[POWERPC] spufs: sched.c cleanups
[linux-2.6] / sound / core / pcm_misc.c
1 /*
2  *  PCM Interface - misc routines
3  *  Copyright (c) 1998 by Jaroslav Kysela <perex@suse.cz>
4  *
5  *
6  *   This library is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU Library General Public License as
8  *   published by the Free Software Foundation; either version 2 of
9  *   the License, or (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU Library General Public License for more details.
15  *
16  *   You should have received a copy of the GNU Library General Public
17  *   License along with this library; if not, write to the Free Software
18  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19  *
20  */
21   
22 #include <sound/driver.h>
23 #include <linux/time.h>
24 #include <sound/core.h>
25 #include <sound/pcm.h>
26 #define SND_PCM_FORMAT_UNKNOWN (-1)
27
28 /* NOTE: "signed" prefix must be given below since the default char is
29  *       unsigned on some architectures!
30  */
31 struct pcm_format_data {
32         unsigned char width;    /* bit width */
33         unsigned char phys;     /* physical bit width */
34         signed char le; /* 0 = big-endian, 1 = little-endian, -1 = others */
35         signed char signd;      /* 0 = unsigned, 1 = signed, -1 = others */
36         unsigned char silence[8];       /* silence data to fill */
37 };
38
39 static struct pcm_format_data pcm_formats[SNDRV_PCM_FORMAT_LAST+1] = {
40         [SNDRV_PCM_FORMAT_S8] = {
41                 .width = 8, .phys = 8, .le = -1, .signd = 1,
42                 .silence = {},
43         },
44         [SNDRV_PCM_FORMAT_U8] = {
45                 .width = 8, .phys = 8, .le = -1, .signd = 0,
46                 .silence = { 0x80 },
47         },
48         [SNDRV_PCM_FORMAT_S16_LE] = {
49                 .width = 16, .phys = 16, .le = 1, .signd = 1,
50                 .silence = {},
51         },
52         [SNDRV_PCM_FORMAT_S16_BE] = {
53                 .width = 16, .phys = 16, .le = 0, .signd = 1,
54                 .silence = {},
55         },
56         [SNDRV_PCM_FORMAT_U16_LE] = {
57                 .width = 16, .phys = 16, .le = 1, .signd = 0,
58                 .silence = { 0x00, 0x80 },
59         },
60         [SNDRV_PCM_FORMAT_U16_BE] = {
61                 .width = 16, .phys = 16, .le = 0, .signd = 0,
62                 .silence = { 0x80, 0x00 },
63         },
64         [SNDRV_PCM_FORMAT_S24_LE] = {
65                 .width = 24, .phys = 32, .le = 1, .signd = 1,
66                 .silence = {},
67         },
68         [SNDRV_PCM_FORMAT_S24_BE] = {
69                 .width = 24, .phys = 32, .le = 0, .signd = 1,
70                 .silence = {},
71         },
72         [SNDRV_PCM_FORMAT_U24_LE] = {
73                 .width = 24, .phys = 32, .le = 1, .signd = 0,
74                 .silence = { 0x00, 0x00, 0x80 },
75         },
76         [SNDRV_PCM_FORMAT_U24_BE] = {
77                 .width = 24, .phys = 32, .le = 0, .signd = 0,
78                 .silence = { 0x80, 0x00, 0x00 },
79         },
80         [SNDRV_PCM_FORMAT_S32_LE] = {
81                 .width = 32, .phys = 32, .le = 1, .signd = 1,
82                 .silence = {},
83         },
84         [SNDRV_PCM_FORMAT_S32_BE] = {
85                 .width = 32, .phys = 32, .le = 0, .signd = 1,
86                 .silence = {},
87         },
88         [SNDRV_PCM_FORMAT_U32_LE] = {
89                 .width = 32, .phys = 32, .le = 1, .signd = 0,
90                 .silence = { 0x00, 0x00, 0x00, 0x80 },
91         },
92         [SNDRV_PCM_FORMAT_U32_BE] = {
93                 .width = 32, .phys = 32, .le = 0, .signd = 0,
94                 .silence = { 0x80, 0x00, 0x00, 0x00 },
95         },
96         [SNDRV_PCM_FORMAT_FLOAT_LE] = {
97                 .width = 32, .phys = 32, .le = 1, .signd = -1,
98                 .silence = {},
99         },
100         [SNDRV_PCM_FORMAT_FLOAT_BE] = {
101                 .width = 32, .phys = 32, .le = 0, .signd = -1,
102                 .silence = {},
103         },
104         [SNDRV_PCM_FORMAT_FLOAT64_LE] = {
105                 .width = 64, .phys = 64, .le = 1, .signd = -1,
106                 .silence = {},
107         },
108         [SNDRV_PCM_FORMAT_FLOAT64_BE] = {
109                 .width = 64, .phys = 64, .le = 0, .signd = -1,
110                 .silence = {},
111         },
112         [SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE] = {
113                 .width = 32, .phys = 32, .le = 1, .signd = -1,
114                 .silence = {},
115         },
116         [SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE] = {
117                 .width = 32, .phys = 32, .le = 0, .signd = -1,
118                 .silence = {},
119         },
120         [SNDRV_PCM_FORMAT_MU_LAW] = {
121                 .width = 8, .phys = 8, .le = -1, .signd = -1,
122                 .silence = { 0x7f },
123         },
124         [SNDRV_PCM_FORMAT_A_LAW] = {
125                 .width = 8, .phys = 8, .le = -1, .signd = -1,
126                 .silence = { 0x55 },
127         },
128         [SNDRV_PCM_FORMAT_IMA_ADPCM] = {
129                 .width = 4, .phys = 4, .le = -1, .signd = -1,
130                 .silence = {},
131         },
132         /* FIXME: the following three formats are not defined properly yet */
133         [SNDRV_PCM_FORMAT_MPEG] = {
134                 .le = -1, .signd = -1,
135         },
136         [SNDRV_PCM_FORMAT_GSM] = {
137                 .le = -1, .signd = -1,
138         },
139         [SNDRV_PCM_FORMAT_SPECIAL] = {
140                 .le = -1, .signd = -1,
141         },
142         [SNDRV_PCM_FORMAT_S24_3LE] = {
143                 .width = 24, .phys = 24, .le = 1, .signd = 1,
144                 .silence = {},
145         },
146         [SNDRV_PCM_FORMAT_S24_3BE] = {
147                 .width = 24, .phys = 24, .le = 0, .signd = 1,
148                 .silence = {},
149         },
150         [SNDRV_PCM_FORMAT_U24_3LE] = {
151                 .width = 24, .phys = 24, .le = 1, .signd = 0,
152                 .silence = { 0x00, 0x00, 0x80 },
153         },
154         [SNDRV_PCM_FORMAT_U24_3BE] = {
155                 .width = 24, .phys = 24, .le = 0, .signd = 0,
156                 .silence = { 0x80, 0x00, 0x00 },
157         },
158         [SNDRV_PCM_FORMAT_S20_3LE] = {
159                 .width = 20, .phys = 24, .le = 1, .signd = 1,
160                 .silence = {},
161         },
162         [SNDRV_PCM_FORMAT_S20_3BE] = {
163                 .width = 20, .phys = 24, .le = 0, .signd = 1,
164                 .silence = {},
165         },
166         [SNDRV_PCM_FORMAT_U20_3LE] = {
167                 .width = 20, .phys = 24, .le = 1, .signd = 0,
168                 .silence = { 0x00, 0x00, 0x08 },
169         },
170         [SNDRV_PCM_FORMAT_U20_3BE] = {
171                 .width = 20, .phys = 24, .le = 0, .signd = 0,
172                 .silence = { 0x08, 0x00, 0x00 },
173         },
174         [SNDRV_PCM_FORMAT_S18_3LE] = {
175                 .width = 18, .phys = 24, .le = 1, .signd = 1,
176                 .silence = {},
177         },
178         [SNDRV_PCM_FORMAT_S18_3BE] = {
179                 .width = 18, .phys = 24, .le = 0, .signd = 1,
180                 .silence = {},
181         },
182         [SNDRV_PCM_FORMAT_U18_3LE] = {
183                 .width = 18, .phys = 24, .le = 1, .signd = 0,
184                 .silence = { 0x00, 0x00, 0x02 },
185         },
186         [SNDRV_PCM_FORMAT_U18_3BE] = {
187                 .width = 18, .phys = 24, .le = 0, .signd = 0,
188                 .silence = { 0x02, 0x00, 0x00 },
189         },
190 };
191
192
193 /**
194  * snd_pcm_format_signed - Check the PCM format is signed linear
195  * @format: the format to check
196  *
197  * Returns 1 if the given PCM format is signed linear, 0 if unsigned
198  * linear, and a negative error code for non-linear formats.
199  */
200 int snd_pcm_format_signed(snd_pcm_format_t format)
201 {
202         int val;
203         if (format < 0 || format > SNDRV_PCM_FORMAT_LAST)
204                 return -EINVAL;
205         if ((val = pcm_formats[format].signd) < 0)
206                 return -EINVAL;
207         return val;
208 }
209
210 EXPORT_SYMBOL(snd_pcm_format_signed);
211
212 /**
213  * snd_pcm_format_unsigned - Check the PCM format is unsigned linear
214  * @format: the format to check
215  *
216  * Returns 1 if the given PCM format is unsigned linear, 0 if signed
217  * linear, and a negative error code for non-linear formats.
218  */
219 int snd_pcm_format_unsigned(snd_pcm_format_t format)
220 {
221         int val;
222
223         val = snd_pcm_format_signed(format);
224         if (val < 0)
225                 return val;
226         return !val;
227 }
228
229 EXPORT_SYMBOL(snd_pcm_format_unsigned);
230
231 /**
232  * snd_pcm_format_linear - Check the PCM format is linear
233  * @format: the format to check
234  *
235  * Returns 1 if the given PCM format is linear, 0 if not.
236  */
237 int snd_pcm_format_linear(snd_pcm_format_t format)
238 {
239         return snd_pcm_format_signed(format) >= 0;
240 }
241
242 EXPORT_SYMBOL(snd_pcm_format_linear);
243
244 /**
245  * snd_pcm_format_little_endian - Check the PCM format is little-endian
246  * @format: the format to check
247  *
248  * Returns 1 if the given PCM format is little-endian, 0 if
249  * big-endian, or a negative error code if endian not specified.
250  */
251 int snd_pcm_format_little_endian(snd_pcm_format_t format)
252 {
253         int val;
254         if (format < 0 || format > SNDRV_PCM_FORMAT_LAST)
255                 return -EINVAL;
256         if ((val = pcm_formats[format].le) < 0)
257                 return -EINVAL;
258         return val;
259 }
260
261 EXPORT_SYMBOL(snd_pcm_format_little_endian);
262
263 /**
264  * snd_pcm_format_big_endian - Check the PCM format is big-endian
265  * @format: the format to check
266  *
267  * Returns 1 if the given PCM format is big-endian, 0 if
268  * little-endian, or a negative error code if endian not specified.
269  */
270 int snd_pcm_format_big_endian(snd_pcm_format_t format)
271 {
272         int val;
273
274         val = snd_pcm_format_little_endian(format);
275         if (val < 0)
276                 return val;
277         return !val;
278 }
279
280 EXPORT_SYMBOL(snd_pcm_format_big_endian);
281
282 /**
283  * snd_pcm_format_width - return the bit-width of the format
284  * @format: the format to check
285  *
286  * Returns the bit-width of the format, or a negative error code
287  * if unknown format.
288  */
289 int snd_pcm_format_width(snd_pcm_format_t format)
290 {
291         int val;
292         if (format < 0 || format > SNDRV_PCM_FORMAT_LAST)
293                 return -EINVAL;
294         if ((val = pcm_formats[format].width) == 0)
295                 return -EINVAL;
296         return val;
297 }
298
299 EXPORT_SYMBOL(snd_pcm_format_width);
300
301 /**
302  * snd_pcm_format_physical_width - return the physical bit-width of the format
303  * @format: the format to check
304  *
305  * Returns the physical bit-width of the format, or a negative error code
306  * if unknown format.
307  */
308 int snd_pcm_format_physical_width(snd_pcm_format_t format)
309 {
310         int val;
311         if (format < 0 || format > SNDRV_PCM_FORMAT_LAST)
312                 return -EINVAL;
313         if ((val = pcm_formats[format].phys) == 0)
314                 return -EINVAL;
315         return val;
316 }
317
318 EXPORT_SYMBOL(snd_pcm_format_physical_width);
319
320 /**
321  * snd_pcm_format_size - return the byte size of samples on the given format
322  * @format: the format to check
323  *
324  * Returns the byte size of the given samples for the format, or a
325  * negative error code if unknown format.
326  */
327 ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples)
328 {
329         int phys_width = snd_pcm_format_physical_width(format);
330         if (phys_width < 0)
331                 return -EINVAL;
332         return samples * phys_width / 8;
333 }
334
335 EXPORT_SYMBOL(snd_pcm_format_size);
336
337 /**
338  * snd_pcm_format_silence_64 - return the silent data in 8 bytes array
339  * @format: the format to check
340  *
341  * Returns the format pattern to fill or NULL if error.
342  */
343 const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format)
344 {
345         if (format < 0 || format > SNDRV_PCM_FORMAT_LAST)
346                 return NULL;
347         if (! pcm_formats[format].phys)
348                 return NULL;
349         return pcm_formats[format].silence;
350 }
351
352 EXPORT_SYMBOL(snd_pcm_format_silence_64);
353
354 /**
355  * snd_pcm_format_set_silence - set the silence data on the buffer
356  * @format: the PCM format
357  * @data: the buffer pointer
358  * @samples: the number of samples to set silence
359  *
360  * Sets the silence data on the buffer for the given samples.
361  *
362  * Returns zero if successful, or a negative error code on failure.
363  */
364 int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int samples)
365 {
366         int width;
367         unsigned char *dst, *pat;
368
369         if (format < 0 || format > SNDRV_PCM_FORMAT_LAST)
370                 return -EINVAL;
371         if (samples == 0)
372                 return 0;
373         width = pcm_formats[format].phys; /* physical width */
374         pat = pcm_formats[format].silence;
375         if (! width)
376                 return -EINVAL;
377         /* signed or 1 byte data */
378         if (pcm_formats[format].signd == 1 || width <= 8) {
379                 unsigned int bytes = samples * width / 8;
380                 memset(data, *pat, bytes);
381                 return 0;
382         }
383         /* non-zero samples, fill using a loop */
384         width /= 8;
385         dst = data;
386 #if 0
387         while (samples--) {
388                 memcpy(dst, pat, width);
389                 dst += width;
390         }
391 #else
392         /* a bit optimization for constant width */
393         switch (width) {
394         case 2:
395                 while (samples--) {
396                         memcpy(dst, pat, 2);
397                         dst += 2;
398                 }
399                 break;
400         case 3:
401                 while (samples--) {
402                         memcpy(dst, pat, 3);
403                         dst += 3;
404                 }
405                 break;
406         case 4:
407                 while (samples--) {
408                         memcpy(dst, pat, 4);
409                         dst += 4;
410                 }
411                 break;
412         case 8:
413                 while (samples--) {
414                         memcpy(dst, pat, 8);
415                         dst += 8;
416                 }
417                 break;
418         }
419 #endif
420         return 0;
421 }
422
423 EXPORT_SYMBOL(snd_pcm_format_set_silence);
424
425 /* [width][unsigned][bigendian] */
426 static int linear_formats[4][2][2] = {
427         {{ SNDRV_PCM_FORMAT_S8, SNDRV_PCM_FORMAT_S8},
428          { SNDRV_PCM_FORMAT_U8, SNDRV_PCM_FORMAT_U8}},
429         {{SNDRV_PCM_FORMAT_S16_LE, SNDRV_PCM_FORMAT_S16_BE},
430          {SNDRV_PCM_FORMAT_U16_LE, SNDRV_PCM_FORMAT_U16_BE}},
431         {{SNDRV_PCM_FORMAT_S24_LE, SNDRV_PCM_FORMAT_S24_BE},
432          {SNDRV_PCM_FORMAT_U24_LE, SNDRV_PCM_FORMAT_U24_BE}},
433         {{SNDRV_PCM_FORMAT_S32_LE, SNDRV_PCM_FORMAT_S32_BE},
434          {SNDRV_PCM_FORMAT_U32_LE, SNDRV_PCM_FORMAT_U32_BE}}
435 };
436
437 /**
438  * snd_pcm_build_linear_format - return the suitable linear format for the given condition
439  * @width: the bit-width
440  * @unsignd: 1 if unsigned, 0 if signed.
441  * @big_endian: 1 if big-endian, 0 if little-endian
442  *
443  * Returns the suitable linear format for the given condition.
444  */
445 snd_pcm_format_t snd_pcm_build_linear_format(int width, int unsignd, int big_endian)
446 {
447         if (width & 7)
448                 return SND_PCM_FORMAT_UNKNOWN;
449         width = (width / 8) - 1;
450         if (width < 0 || width >= 4)
451                 return SND_PCM_FORMAT_UNKNOWN;
452         return linear_formats[width][!!unsignd][!!big_endian];
453 }
454
455 EXPORT_SYMBOL(snd_pcm_build_linear_format);
456
457 /**
458  * snd_pcm_limit_hw_rates - determine rate_min/rate_max fields
459  * @runtime: the runtime instance
460  *
461  * Determines the rate_min and rate_max fields from the rates bits of
462  * the given runtime->hw.
463  *
464  * Returns zero if successful.
465  */
466 int snd_pcm_limit_hw_rates(struct snd_pcm_runtime *runtime)
467 {
468         static unsigned rates[] = {
469                 /* ATTENTION: these values depend on the definition in pcm.h! */
470                 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000,
471                 64000, 88200, 96000, 176400, 192000
472         };
473         int i;
474         for (i = 0; i < (int)ARRAY_SIZE(rates); i++) {
475                 if (runtime->hw.rates & (1 << i)) {
476                         runtime->hw.rate_min = rates[i];
477                         break;
478                 }
479         }
480         for (i = (int)ARRAY_SIZE(rates) - 1; i >= 0; i--) {
481                 if (runtime->hw.rates & (1 << i)) {
482                         runtime->hw.rate_max = rates[i];
483                         break;
484                 }
485         }
486         return 0;
487 }
488
489 EXPORT_SYMBOL(snd_pcm_limit_hw_rates);