Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/sound/core/pcm_misc.c
10814 views
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 <sound/core.h>
24
#include <sound/pcm.h>
25
#define SND_PCM_FORMAT_UNKNOWN (-1)
26
27
/* NOTE: "signed" prefix must be given below since the default char is
28
* unsigned on some architectures!
29
*/
30
struct pcm_format_data {
31
unsigned char width; /* bit width */
32
unsigned char phys; /* physical bit width */
33
signed char le; /* 0 = big-endian, 1 = little-endian, -1 = others */
34
signed char signd; /* 0 = unsigned, 1 = signed, -1 = others */
35
unsigned char silence[8]; /* silence data to fill */
36
};
37
38
/* we do lots of calculations on snd_pcm_format_t; shut up sparse */
39
#define INT __force int
40
41
static struct pcm_format_data pcm_formats[(INT)SNDRV_PCM_FORMAT_LAST+1] = {
42
[SNDRV_PCM_FORMAT_S8] = {
43
.width = 8, .phys = 8, .le = -1, .signd = 1,
44
.silence = {},
45
},
46
[SNDRV_PCM_FORMAT_U8] = {
47
.width = 8, .phys = 8, .le = -1, .signd = 0,
48
.silence = { 0x80 },
49
},
50
[SNDRV_PCM_FORMAT_S16_LE] = {
51
.width = 16, .phys = 16, .le = 1, .signd = 1,
52
.silence = {},
53
},
54
[SNDRV_PCM_FORMAT_S16_BE] = {
55
.width = 16, .phys = 16, .le = 0, .signd = 1,
56
.silence = {},
57
},
58
[SNDRV_PCM_FORMAT_U16_LE] = {
59
.width = 16, .phys = 16, .le = 1, .signd = 0,
60
.silence = { 0x00, 0x80 },
61
},
62
[SNDRV_PCM_FORMAT_U16_BE] = {
63
.width = 16, .phys = 16, .le = 0, .signd = 0,
64
.silence = { 0x80, 0x00 },
65
},
66
[SNDRV_PCM_FORMAT_S24_LE] = {
67
.width = 24, .phys = 32, .le = 1, .signd = 1,
68
.silence = {},
69
},
70
[SNDRV_PCM_FORMAT_S24_BE] = {
71
.width = 24, .phys = 32, .le = 0, .signd = 1,
72
.silence = {},
73
},
74
[SNDRV_PCM_FORMAT_U24_LE] = {
75
.width = 24, .phys = 32, .le = 1, .signd = 0,
76
.silence = { 0x00, 0x00, 0x80 },
77
},
78
[SNDRV_PCM_FORMAT_U24_BE] = {
79
.width = 24, .phys = 32, .le = 0, .signd = 0,
80
.silence = { 0x00, 0x80, 0x00, 0x00 },
81
},
82
[SNDRV_PCM_FORMAT_S32_LE] = {
83
.width = 32, .phys = 32, .le = 1, .signd = 1,
84
.silence = {},
85
},
86
[SNDRV_PCM_FORMAT_S32_BE] = {
87
.width = 32, .phys = 32, .le = 0, .signd = 1,
88
.silence = {},
89
},
90
[SNDRV_PCM_FORMAT_U32_LE] = {
91
.width = 32, .phys = 32, .le = 1, .signd = 0,
92
.silence = { 0x00, 0x00, 0x00, 0x80 },
93
},
94
[SNDRV_PCM_FORMAT_U32_BE] = {
95
.width = 32, .phys = 32, .le = 0, .signd = 0,
96
.silence = { 0x80, 0x00, 0x00, 0x00 },
97
},
98
[SNDRV_PCM_FORMAT_FLOAT_LE] = {
99
.width = 32, .phys = 32, .le = 1, .signd = -1,
100
.silence = {},
101
},
102
[SNDRV_PCM_FORMAT_FLOAT_BE] = {
103
.width = 32, .phys = 32, .le = 0, .signd = -1,
104
.silence = {},
105
},
106
[SNDRV_PCM_FORMAT_FLOAT64_LE] = {
107
.width = 64, .phys = 64, .le = 1, .signd = -1,
108
.silence = {},
109
},
110
[SNDRV_PCM_FORMAT_FLOAT64_BE] = {
111
.width = 64, .phys = 64, .le = 0, .signd = -1,
112
.silence = {},
113
},
114
[SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE] = {
115
.width = 32, .phys = 32, .le = 1, .signd = -1,
116
.silence = {},
117
},
118
[SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE] = {
119
.width = 32, .phys = 32, .le = 0, .signd = -1,
120
.silence = {},
121
},
122
[SNDRV_PCM_FORMAT_MU_LAW] = {
123
.width = 8, .phys = 8, .le = -1, .signd = -1,
124
.silence = { 0x7f },
125
},
126
[SNDRV_PCM_FORMAT_A_LAW] = {
127
.width = 8, .phys = 8, .le = -1, .signd = -1,
128
.silence = { 0x55 },
129
},
130
[SNDRV_PCM_FORMAT_IMA_ADPCM] = {
131
.width = 4, .phys = 4, .le = -1, .signd = -1,
132
.silence = {},
133
},
134
[SNDRV_PCM_FORMAT_G723_24] = {
135
.width = 3, .phys = 3, .le = -1, .signd = -1,
136
.silence = {},
137
},
138
[SNDRV_PCM_FORMAT_G723_40] = {
139
.width = 5, .phys = 5, .le = -1, .signd = -1,
140
.silence = {},
141
},
142
/* FIXME: the following three formats are not defined properly yet */
143
[SNDRV_PCM_FORMAT_MPEG] = {
144
.le = -1, .signd = -1,
145
},
146
[SNDRV_PCM_FORMAT_GSM] = {
147
.le = -1, .signd = -1,
148
},
149
[SNDRV_PCM_FORMAT_SPECIAL] = {
150
.le = -1, .signd = -1,
151
},
152
[SNDRV_PCM_FORMAT_S24_3LE] = {
153
.width = 24, .phys = 24, .le = 1, .signd = 1,
154
.silence = {},
155
},
156
[SNDRV_PCM_FORMAT_S24_3BE] = {
157
.width = 24, .phys = 24, .le = 0, .signd = 1,
158
.silence = {},
159
},
160
[SNDRV_PCM_FORMAT_U24_3LE] = {
161
.width = 24, .phys = 24, .le = 1, .signd = 0,
162
.silence = { 0x00, 0x00, 0x80 },
163
},
164
[SNDRV_PCM_FORMAT_U24_3BE] = {
165
.width = 24, .phys = 24, .le = 0, .signd = 0,
166
.silence = { 0x80, 0x00, 0x00 },
167
},
168
[SNDRV_PCM_FORMAT_S20_3LE] = {
169
.width = 20, .phys = 24, .le = 1, .signd = 1,
170
.silence = {},
171
},
172
[SNDRV_PCM_FORMAT_S20_3BE] = {
173
.width = 20, .phys = 24, .le = 0, .signd = 1,
174
.silence = {},
175
},
176
[SNDRV_PCM_FORMAT_U20_3LE] = {
177
.width = 20, .phys = 24, .le = 1, .signd = 0,
178
.silence = { 0x00, 0x00, 0x08 },
179
},
180
[SNDRV_PCM_FORMAT_U20_3BE] = {
181
.width = 20, .phys = 24, .le = 0, .signd = 0,
182
.silence = { 0x08, 0x00, 0x00 },
183
},
184
[SNDRV_PCM_FORMAT_S18_3LE] = {
185
.width = 18, .phys = 24, .le = 1, .signd = 1,
186
.silence = {},
187
},
188
[SNDRV_PCM_FORMAT_S18_3BE] = {
189
.width = 18, .phys = 24, .le = 0, .signd = 1,
190
.silence = {},
191
},
192
[SNDRV_PCM_FORMAT_U18_3LE] = {
193
.width = 18, .phys = 24, .le = 1, .signd = 0,
194
.silence = { 0x00, 0x00, 0x02 },
195
},
196
[SNDRV_PCM_FORMAT_U18_3BE] = {
197
.width = 18, .phys = 24, .le = 0, .signd = 0,
198
.silence = { 0x02, 0x00, 0x00 },
199
},
200
[SNDRV_PCM_FORMAT_G723_24_1B] = {
201
.width = 3, .phys = 8, .le = -1, .signd = -1,
202
.silence = {},
203
},
204
[SNDRV_PCM_FORMAT_G723_40_1B] = {
205
.width = 5, .phys = 8, .le = -1, .signd = -1,
206
.silence = {},
207
},
208
};
209
210
211
/**
212
* snd_pcm_format_signed - Check the PCM format is signed linear
213
* @format: the format to check
214
*
215
* Returns 1 if the given PCM format is signed linear, 0 if unsigned
216
* linear, and a negative error code for non-linear formats.
217
*/
218
int snd_pcm_format_signed(snd_pcm_format_t format)
219
{
220
int val;
221
if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST)
222
return -EINVAL;
223
if ((val = pcm_formats[(INT)format].signd) < 0)
224
return -EINVAL;
225
return val;
226
}
227
228
EXPORT_SYMBOL(snd_pcm_format_signed);
229
230
/**
231
* snd_pcm_format_unsigned - Check the PCM format is unsigned linear
232
* @format: the format to check
233
*
234
* Returns 1 if the given PCM format is unsigned linear, 0 if signed
235
* linear, and a negative error code for non-linear formats.
236
*/
237
int snd_pcm_format_unsigned(snd_pcm_format_t format)
238
{
239
int val;
240
241
val = snd_pcm_format_signed(format);
242
if (val < 0)
243
return val;
244
return !val;
245
}
246
247
EXPORT_SYMBOL(snd_pcm_format_unsigned);
248
249
/**
250
* snd_pcm_format_linear - Check the PCM format is linear
251
* @format: the format to check
252
*
253
* Returns 1 if the given PCM format is linear, 0 if not.
254
*/
255
int snd_pcm_format_linear(snd_pcm_format_t format)
256
{
257
return snd_pcm_format_signed(format) >= 0;
258
}
259
260
EXPORT_SYMBOL(snd_pcm_format_linear);
261
262
/**
263
* snd_pcm_format_little_endian - Check the PCM format is little-endian
264
* @format: the format to check
265
*
266
* Returns 1 if the given PCM format is little-endian, 0 if
267
* big-endian, or a negative error code if endian not specified.
268
*/
269
int snd_pcm_format_little_endian(snd_pcm_format_t format)
270
{
271
int val;
272
if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST)
273
return -EINVAL;
274
if ((val = pcm_formats[(INT)format].le) < 0)
275
return -EINVAL;
276
return val;
277
}
278
279
EXPORT_SYMBOL(snd_pcm_format_little_endian);
280
281
/**
282
* snd_pcm_format_big_endian - Check the PCM format is big-endian
283
* @format: the format to check
284
*
285
* Returns 1 if the given PCM format is big-endian, 0 if
286
* little-endian, or a negative error code if endian not specified.
287
*/
288
int snd_pcm_format_big_endian(snd_pcm_format_t format)
289
{
290
int val;
291
292
val = snd_pcm_format_little_endian(format);
293
if (val < 0)
294
return val;
295
return !val;
296
}
297
298
EXPORT_SYMBOL(snd_pcm_format_big_endian);
299
300
/**
301
* snd_pcm_format_width - return the bit-width of the format
302
* @format: the format to check
303
*
304
* Returns the bit-width of the format, or a negative error code
305
* if unknown format.
306
*/
307
int snd_pcm_format_width(snd_pcm_format_t format)
308
{
309
int val;
310
if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST)
311
return -EINVAL;
312
if ((val = pcm_formats[(INT)format].width) == 0)
313
return -EINVAL;
314
return val;
315
}
316
317
EXPORT_SYMBOL(snd_pcm_format_width);
318
319
/**
320
* snd_pcm_format_physical_width - return the physical bit-width of the format
321
* @format: the format to check
322
*
323
* Returns the physical bit-width of the format, or a negative error code
324
* if unknown format.
325
*/
326
int snd_pcm_format_physical_width(snd_pcm_format_t format)
327
{
328
int val;
329
if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST)
330
return -EINVAL;
331
if ((val = pcm_formats[(INT)format].phys) == 0)
332
return -EINVAL;
333
return val;
334
}
335
336
EXPORT_SYMBOL(snd_pcm_format_physical_width);
337
338
/**
339
* snd_pcm_format_size - return the byte size of samples on the given format
340
* @format: the format to check
341
* @samples: sampling rate
342
*
343
* Returns the byte size of the given samples for the format, or a
344
* negative error code if unknown format.
345
*/
346
ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples)
347
{
348
int phys_width = snd_pcm_format_physical_width(format);
349
if (phys_width < 0)
350
return -EINVAL;
351
return samples * phys_width / 8;
352
}
353
354
EXPORT_SYMBOL(snd_pcm_format_size);
355
356
/**
357
* snd_pcm_format_silence_64 - return the silent data in 8 bytes array
358
* @format: the format to check
359
*
360
* Returns the format pattern to fill or NULL if error.
361
*/
362
const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format)
363
{
364
if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST)
365
return NULL;
366
if (! pcm_formats[(INT)format].phys)
367
return NULL;
368
return pcm_formats[(INT)format].silence;
369
}
370
371
EXPORT_SYMBOL(snd_pcm_format_silence_64);
372
373
/**
374
* snd_pcm_format_set_silence - set the silence data on the buffer
375
* @format: the PCM format
376
* @data: the buffer pointer
377
* @samples: the number of samples to set silence
378
*
379
* Sets the silence data on the buffer for the given samples.
380
*
381
* Returns zero if successful, or a negative error code on failure.
382
*/
383
int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int samples)
384
{
385
int width;
386
unsigned char *dst, *pat;
387
388
if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST)
389
return -EINVAL;
390
if (samples == 0)
391
return 0;
392
width = pcm_formats[(INT)format].phys; /* physical width */
393
pat = pcm_formats[(INT)format].silence;
394
if (! width)
395
return -EINVAL;
396
/* signed or 1 byte data */
397
if (pcm_formats[(INT)format].signd == 1 || width <= 8) {
398
unsigned int bytes = samples * width / 8;
399
memset(data, *pat, bytes);
400
return 0;
401
}
402
/* non-zero samples, fill using a loop */
403
width /= 8;
404
dst = data;
405
#if 0
406
while (samples--) {
407
memcpy(dst, pat, width);
408
dst += width;
409
}
410
#else
411
/* a bit optimization for constant width */
412
switch (width) {
413
case 2:
414
while (samples--) {
415
memcpy(dst, pat, 2);
416
dst += 2;
417
}
418
break;
419
case 3:
420
while (samples--) {
421
memcpy(dst, pat, 3);
422
dst += 3;
423
}
424
break;
425
case 4:
426
while (samples--) {
427
memcpy(dst, pat, 4);
428
dst += 4;
429
}
430
break;
431
case 8:
432
while (samples--) {
433
memcpy(dst, pat, 8);
434
dst += 8;
435
}
436
break;
437
}
438
#endif
439
return 0;
440
}
441
442
EXPORT_SYMBOL(snd_pcm_format_set_silence);
443
444
/**
445
* snd_pcm_limit_hw_rates - determine rate_min/rate_max fields
446
* @runtime: the runtime instance
447
*
448
* Determines the rate_min and rate_max fields from the rates bits of
449
* the given runtime->hw.
450
*
451
* Returns zero if successful.
452
*/
453
int snd_pcm_limit_hw_rates(struct snd_pcm_runtime *runtime)
454
{
455
int i;
456
for (i = 0; i < (int)snd_pcm_known_rates.count; i++) {
457
if (runtime->hw.rates & (1 << i)) {
458
runtime->hw.rate_min = snd_pcm_known_rates.list[i];
459
break;
460
}
461
}
462
for (i = (int)snd_pcm_known_rates.count - 1; i >= 0; i--) {
463
if (runtime->hw.rates & (1 << i)) {
464
runtime->hw.rate_max = snd_pcm_known_rates.list[i];
465
break;
466
}
467
}
468
return 0;
469
}
470
471
EXPORT_SYMBOL(snd_pcm_limit_hw_rates);
472
473
/**
474
* snd_pcm_rate_to_rate_bit - converts sample rate to SNDRV_PCM_RATE_xxx bit
475
* @rate: the sample rate to convert
476
*
477
* Returns the SNDRV_PCM_RATE_xxx flag that corresponds to the given rate, or
478
* SNDRV_PCM_RATE_KNOT for an unknown rate.
479
*/
480
unsigned int snd_pcm_rate_to_rate_bit(unsigned int rate)
481
{
482
unsigned int i;
483
484
for (i = 0; i < snd_pcm_known_rates.count; i++)
485
if (snd_pcm_known_rates.list[i] == rate)
486
return 1u << i;
487
return SNDRV_PCM_RATE_KNOT;
488
}
489
EXPORT_SYMBOL(snd_pcm_rate_to_rate_bit);
490
491