Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pcm_misc.c
Go to the documentation of this file.
1 /*
2  * PCM Interface - misc routines
3  * Copyright (c) 1998 by Jaroslav Kysela <[email protected]>
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 <linux/time.h>
23 #include <linux/export.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  */
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 /* we do lots of calculations on snd_pcm_format_t; shut up sparse */
40 #define INT __force int
41 
42 static struct pcm_format_data pcm_formats[(INT)SNDRV_PCM_FORMAT_LAST+1] = {
44  .width = 8, .phys = 8, .le = -1, .signd = 1,
45  .silence = {},
46  },
48  .width = 8, .phys = 8, .le = -1, .signd = 0,
49  .silence = { 0x80 },
50  },
52  .width = 16, .phys = 16, .le = 1, .signd = 1,
53  .silence = {},
54  },
56  .width = 16, .phys = 16, .le = 0, .signd = 1,
57  .silence = {},
58  },
60  .width = 16, .phys = 16, .le = 1, .signd = 0,
61  .silence = { 0x00, 0x80 },
62  },
64  .width = 16, .phys = 16, .le = 0, .signd = 0,
65  .silence = { 0x80, 0x00 },
66  },
68  .width = 24, .phys = 32, .le = 1, .signd = 1,
69  .silence = {},
70  },
72  .width = 24, .phys = 32, .le = 0, .signd = 1,
73  .silence = {},
74  },
76  .width = 24, .phys = 32, .le = 1, .signd = 0,
77  .silence = { 0x00, 0x00, 0x80 },
78  },
80  .width = 24, .phys = 32, .le = 0, .signd = 0,
81  .silence = { 0x00, 0x80, 0x00, 0x00 },
82  },
84  .width = 32, .phys = 32, .le = 1, .signd = 1,
85  .silence = {},
86  },
88  .width = 32, .phys = 32, .le = 0, .signd = 1,
89  .silence = {},
90  },
92  .width = 32, .phys = 32, .le = 1, .signd = 0,
93  .silence = { 0x00, 0x00, 0x00, 0x80 },
94  },
96  .width = 32, .phys = 32, .le = 0, .signd = 0,
97  .silence = { 0x80, 0x00, 0x00, 0x00 },
98  },
100  .width = 32, .phys = 32, .le = 1, .signd = -1,
101  .silence = {},
102  },
104  .width = 32, .phys = 32, .le = 0, .signd = -1,
105  .silence = {},
106  },
108  .width = 64, .phys = 64, .le = 1, .signd = -1,
109  .silence = {},
110  },
112  .width = 64, .phys = 64, .le = 0, .signd = -1,
113  .silence = {},
114  },
116  .width = 32, .phys = 32, .le = 1, .signd = -1,
117  .silence = {},
118  },
120  .width = 32, .phys = 32, .le = 0, .signd = -1,
121  .silence = {},
122  },
124  .width = 8, .phys = 8, .le = -1, .signd = -1,
125  .silence = { 0x7f },
126  },
128  .width = 8, .phys = 8, .le = -1, .signd = -1,
129  .silence = { 0x55 },
130  },
132  .width = 4, .phys = 4, .le = -1, .signd = -1,
133  .silence = {},
134  },
136  .width = 3, .phys = 3, .le = -1, .signd = -1,
137  .silence = {},
138  },
140  .width = 5, .phys = 5, .le = -1, .signd = -1,
141  .silence = {},
142  },
143  /* FIXME: the following three formats are not defined properly yet */
145  .le = -1, .signd = -1,
146  },
148  .le = -1, .signd = -1,
149  },
151  .le = -1, .signd = -1,
152  },
154  .width = 24, .phys = 24, .le = 1, .signd = 1,
155  .silence = {},
156  },
158  .width = 24, .phys = 24, .le = 0, .signd = 1,
159  .silence = {},
160  },
162  .width = 24, .phys = 24, .le = 1, .signd = 0,
163  .silence = { 0x00, 0x00, 0x80 },
164  },
166  .width = 24, .phys = 24, .le = 0, .signd = 0,
167  .silence = { 0x80, 0x00, 0x00 },
168  },
170  .width = 20, .phys = 24, .le = 1, .signd = 1,
171  .silence = {},
172  },
174  .width = 20, .phys = 24, .le = 0, .signd = 1,
175  .silence = {},
176  },
178  .width = 20, .phys = 24, .le = 1, .signd = 0,
179  .silence = { 0x00, 0x00, 0x08 },
180  },
182  .width = 20, .phys = 24, .le = 0, .signd = 0,
183  .silence = { 0x08, 0x00, 0x00 },
184  },
186  .width = 18, .phys = 24, .le = 1, .signd = 1,
187  .silence = {},
188  },
190  .width = 18, .phys = 24, .le = 0, .signd = 1,
191  .silence = {},
192  },
194  .width = 18, .phys = 24, .le = 1, .signd = 0,
195  .silence = { 0x00, 0x00, 0x02 },
196  },
198  .width = 18, .phys = 24, .le = 0, .signd = 0,
199  .silence = { 0x02, 0x00, 0x00 },
200  },
202  .width = 3, .phys = 8, .le = -1, .signd = -1,
203  .silence = {},
204  },
206  .width = 5, .phys = 8, .le = -1, .signd = -1,
207  .silence = {},
208  },
209 };
210 
211 
220 {
221  int val;
222  if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST)
223  return -EINVAL;
224  if ((val = pcm_formats[(INT)format].signd) < 0)
225  return -EINVAL;
226  return val;
227 }
228 
230 
239 {
240  int val;
241 
242  val = snd_pcm_format_signed(format);
243  if (val < 0)
244  return val;
245  return !val;
246 }
247 
249 
257 {
258  return snd_pcm_format_signed(format) >= 0;
259 }
260 
262 
271 {
272  int val;
273  if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST)
274  return -EINVAL;
275  if ((val = pcm_formats[(INT)format].le) < 0)
276  return -EINVAL;
277  return val;
278 }
279 
281 
290 {
291  int val;
292 
293  val = snd_pcm_format_little_endian(format);
294  if (val < 0)
295  return val;
296  return !val;
297 }
298 
300 
309 {
310  int val;
311  if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST)
312  return -EINVAL;
313  if ((val = pcm_formats[(INT)format].width) == 0)
314  return -EINVAL;
315  return val;
316 }
317 
319 
328 {
329  int val;
330  if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST)
331  return -EINVAL;
332  if ((val = pcm_formats[(INT)format].phys) == 0)
333  return -EINVAL;
334  return val;
335 }
336 
338 
348 {
350  if (phys_width < 0)
351  return -EINVAL;
352  return samples * phys_width / 8;
353 }
354 
356 
364 {
365  if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST)
366  return NULL;
367  if (! pcm_formats[(INT)format].phys)
368  return NULL;
369  return pcm_formats[(INT)format].silence;
370 }
371 
373 
384 int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int samples)
385 {
386  int width;
387  unsigned char *dst, *pat;
388 
389  if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST)
390  return -EINVAL;
391  if (samples == 0)
392  return 0;
393  width = pcm_formats[(INT)format].phys; /* physical width */
394  pat = pcm_formats[(INT)format].silence;
395  if (! width)
396  return -EINVAL;
397  /* signed or 1 byte data */
398  if (pcm_formats[(INT)format].signd == 1 || width <= 8) {
399  unsigned int bytes = samples * width / 8;
400  memset(data, *pat, bytes);
401  return 0;
402  }
403  /* non-zero samples, fill using a loop */
404  width /= 8;
405  dst = data;
406 #if 0
407  while (samples--) {
408  memcpy(dst, pat, width);
409  dst += width;
410  }
411 #else
412  /* a bit optimization for constant width */
413  switch (width) {
414  case 2:
415  while (samples--) {
416  memcpy(dst, pat, 2);
417  dst += 2;
418  }
419  break;
420  case 3:
421  while (samples--) {
422  memcpy(dst, pat, 3);
423  dst += 3;
424  }
425  break;
426  case 4:
427  while (samples--) {
428  memcpy(dst, pat, 4);
429  dst += 4;
430  }
431  break;
432  case 8:
433  while (samples--) {
434  memcpy(dst, pat, 8);
435  dst += 8;
436  }
437  break;
438  }
439 #endif
440  return 0;
441 }
442 
444 
455 {
456  int i;
457  for (i = 0; i < (int)snd_pcm_known_rates.count; i++) {
458  if (runtime->hw.rates & (1 << i)) {
459  runtime->hw.rate_min = snd_pcm_known_rates.list[i];
460  break;
461  }
462  }
463  for (i = (int)snd_pcm_known_rates.count - 1; i >= 0; i--) {
464  if (runtime->hw.rates & (1 << i)) {
465  runtime->hw.rate_max = snd_pcm_known_rates.list[i];
466  break;
467  }
468  }
469  return 0;
470 }
471 
473 
481 unsigned int snd_pcm_rate_to_rate_bit(unsigned int rate)
482 {
483  unsigned int i;
484 
485  for (i = 0; i < snd_pcm_known_rates.count; i++)
486  if (snd_pcm_known_rates.list[i] == rate)
487  return 1u << i;
488  return SNDRV_PCM_RATE_KNOT;
489 }
491 
499 unsigned int snd_pcm_rate_bit_to_rate(unsigned int rate_bit)
500 {
501  unsigned int i;
502 
503  for (i = 0; i < snd_pcm_known_rates.count; i++)
504  if ((1u << i) == rate_bit)
505  return snd_pcm_known_rates.list[i];
506  return 0;
507 }