0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022 #include <linux/time.h>
0023 #include <linux/export.h>
0024 #include <sound/core.h>
0025 #include <sound/pcm.h>
0026
0027 #include "pcm_local.h"
0028
0029 #define SND_PCM_FORMAT_UNKNOWN (-1)
0030
0031
0032
0033
0034 struct pcm_format_data {
0035 unsigned char width;
0036 unsigned char phys;
0037 signed char le;
0038 signed char signd;
0039 unsigned char silence[8];
0040 };
0041
0042
0043 #define INT __force int
0044
0045 static bool valid_format(snd_pcm_format_t format)
0046 {
0047 return (INT)format >= 0 && (INT)format <= (INT)SNDRV_PCM_FORMAT_LAST;
0048 }
0049
0050 static const struct pcm_format_data pcm_formats[(INT)SNDRV_PCM_FORMAT_LAST+1] = {
0051 [SNDRV_PCM_FORMAT_S8] = {
0052 .width = 8, .phys = 8, .le = -1, .signd = 1,
0053 .silence = {},
0054 },
0055 [SNDRV_PCM_FORMAT_U8] = {
0056 .width = 8, .phys = 8, .le = -1, .signd = 0,
0057 .silence = { 0x80 },
0058 },
0059 [SNDRV_PCM_FORMAT_S16_LE] = {
0060 .width = 16, .phys = 16, .le = 1, .signd = 1,
0061 .silence = {},
0062 },
0063 [SNDRV_PCM_FORMAT_S16_BE] = {
0064 .width = 16, .phys = 16, .le = 0, .signd = 1,
0065 .silence = {},
0066 },
0067 [SNDRV_PCM_FORMAT_U16_LE] = {
0068 .width = 16, .phys = 16, .le = 1, .signd = 0,
0069 .silence = { 0x00, 0x80 },
0070 },
0071 [SNDRV_PCM_FORMAT_U16_BE] = {
0072 .width = 16, .phys = 16, .le = 0, .signd = 0,
0073 .silence = { 0x80, 0x00 },
0074 },
0075 [SNDRV_PCM_FORMAT_S24_LE] = {
0076 .width = 24, .phys = 32, .le = 1, .signd = 1,
0077 .silence = {},
0078 },
0079 [SNDRV_PCM_FORMAT_S24_BE] = {
0080 .width = 24, .phys = 32, .le = 0, .signd = 1,
0081 .silence = {},
0082 },
0083 [SNDRV_PCM_FORMAT_U24_LE] = {
0084 .width = 24, .phys = 32, .le = 1, .signd = 0,
0085 .silence = { 0x00, 0x00, 0x80 },
0086 },
0087 [SNDRV_PCM_FORMAT_U24_BE] = {
0088 .width = 24, .phys = 32, .le = 0, .signd = 0,
0089 .silence = { 0x00, 0x80, 0x00, 0x00 },
0090 },
0091 [SNDRV_PCM_FORMAT_S32_LE] = {
0092 .width = 32, .phys = 32, .le = 1, .signd = 1,
0093 .silence = {},
0094 },
0095 [SNDRV_PCM_FORMAT_S32_BE] = {
0096 .width = 32, .phys = 32, .le = 0, .signd = 1,
0097 .silence = {},
0098 },
0099 [SNDRV_PCM_FORMAT_U32_LE] = {
0100 .width = 32, .phys = 32, .le = 1, .signd = 0,
0101 .silence = { 0x00, 0x00, 0x00, 0x80 },
0102 },
0103 [SNDRV_PCM_FORMAT_U32_BE] = {
0104 .width = 32, .phys = 32, .le = 0, .signd = 0,
0105 .silence = { 0x80, 0x00, 0x00, 0x00 },
0106 },
0107 [SNDRV_PCM_FORMAT_FLOAT_LE] = {
0108 .width = 32, .phys = 32, .le = 1, .signd = -1,
0109 .silence = {},
0110 },
0111 [SNDRV_PCM_FORMAT_FLOAT_BE] = {
0112 .width = 32, .phys = 32, .le = 0, .signd = -1,
0113 .silence = {},
0114 },
0115 [SNDRV_PCM_FORMAT_FLOAT64_LE] = {
0116 .width = 64, .phys = 64, .le = 1, .signd = -1,
0117 .silence = {},
0118 },
0119 [SNDRV_PCM_FORMAT_FLOAT64_BE] = {
0120 .width = 64, .phys = 64, .le = 0, .signd = -1,
0121 .silence = {},
0122 },
0123 [SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE] = {
0124 .width = 32, .phys = 32, .le = 1, .signd = -1,
0125 .silence = {},
0126 },
0127 [SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE] = {
0128 .width = 32, .phys = 32, .le = 0, .signd = -1,
0129 .silence = {},
0130 },
0131 [SNDRV_PCM_FORMAT_MU_LAW] = {
0132 .width = 8, .phys = 8, .le = -1, .signd = -1,
0133 .silence = { 0x7f },
0134 },
0135 [SNDRV_PCM_FORMAT_A_LAW] = {
0136 .width = 8, .phys = 8, .le = -1, .signd = -1,
0137 .silence = { 0x55 },
0138 },
0139 [SNDRV_PCM_FORMAT_IMA_ADPCM] = {
0140 .width = 4, .phys = 4, .le = -1, .signd = -1,
0141 .silence = {},
0142 },
0143 [SNDRV_PCM_FORMAT_G723_24] = {
0144 .width = 3, .phys = 3, .le = -1, .signd = -1,
0145 .silence = {},
0146 },
0147 [SNDRV_PCM_FORMAT_G723_40] = {
0148 .width = 5, .phys = 5, .le = -1, .signd = -1,
0149 .silence = {},
0150 },
0151 [SNDRV_PCM_FORMAT_DSD_U8] = {
0152 .width = 8, .phys = 8, .le = 1, .signd = 0,
0153 .silence = { 0x69 },
0154 },
0155 [SNDRV_PCM_FORMAT_DSD_U16_LE] = {
0156 .width = 16, .phys = 16, .le = 1, .signd = 0,
0157 .silence = { 0x69, 0x69 },
0158 },
0159 [SNDRV_PCM_FORMAT_DSD_U32_LE] = {
0160 .width = 32, .phys = 32, .le = 1, .signd = 0,
0161 .silence = { 0x69, 0x69, 0x69, 0x69 },
0162 },
0163 [SNDRV_PCM_FORMAT_DSD_U16_BE] = {
0164 .width = 16, .phys = 16, .le = 0, .signd = 0,
0165 .silence = { 0x69, 0x69 },
0166 },
0167 [SNDRV_PCM_FORMAT_DSD_U32_BE] = {
0168 .width = 32, .phys = 32, .le = 0, .signd = 0,
0169 .silence = { 0x69, 0x69, 0x69, 0x69 },
0170 },
0171
0172 [SNDRV_PCM_FORMAT_MPEG] = {
0173 .le = -1, .signd = -1,
0174 },
0175 [SNDRV_PCM_FORMAT_GSM] = {
0176 .le = -1, .signd = -1,
0177 },
0178 [SNDRV_PCM_FORMAT_S20_LE] = {
0179 .width = 20, .phys = 32, .le = 1, .signd = 1,
0180 .silence = {},
0181 },
0182 [SNDRV_PCM_FORMAT_S20_BE] = {
0183 .width = 20, .phys = 32, .le = 0, .signd = 1,
0184 .silence = {},
0185 },
0186 [SNDRV_PCM_FORMAT_U20_LE] = {
0187 .width = 20, .phys = 32, .le = 1, .signd = 0,
0188 .silence = { 0x00, 0x00, 0x08, 0x00 },
0189 },
0190 [SNDRV_PCM_FORMAT_U20_BE] = {
0191 .width = 20, .phys = 32, .le = 0, .signd = 0,
0192 .silence = { 0x00, 0x08, 0x00, 0x00 },
0193 },
0194
0195 [SNDRV_PCM_FORMAT_SPECIAL] = {
0196 .le = -1, .signd = -1,
0197 },
0198 [SNDRV_PCM_FORMAT_S24_3LE] = {
0199 .width = 24, .phys = 24, .le = 1, .signd = 1,
0200 .silence = {},
0201 },
0202 [SNDRV_PCM_FORMAT_S24_3BE] = {
0203 .width = 24, .phys = 24, .le = 0, .signd = 1,
0204 .silence = {},
0205 },
0206 [SNDRV_PCM_FORMAT_U24_3LE] = {
0207 .width = 24, .phys = 24, .le = 1, .signd = 0,
0208 .silence = { 0x00, 0x00, 0x80 },
0209 },
0210 [SNDRV_PCM_FORMAT_U24_3BE] = {
0211 .width = 24, .phys = 24, .le = 0, .signd = 0,
0212 .silence = { 0x80, 0x00, 0x00 },
0213 },
0214 [SNDRV_PCM_FORMAT_S20_3LE] = {
0215 .width = 20, .phys = 24, .le = 1, .signd = 1,
0216 .silence = {},
0217 },
0218 [SNDRV_PCM_FORMAT_S20_3BE] = {
0219 .width = 20, .phys = 24, .le = 0, .signd = 1,
0220 .silence = {},
0221 },
0222 [SNDRV_PCM_FORMAT_U20_3LE] = {
0223 .width = 20, .phys = 24, .le = 1, .signd = 0,
0224 .silence = { 0x00, 0x00, 0x08 },
0225 },
0226 [SNDRV_PCM_FORMAT_U20_3BE] = {
0227 .width = 20, .phys = 24, .le = 0, .signd = 0,
0228 .silence = { 0x08, 0x00, 0x00 },
0229 },
0230 [SNDRV_PCM_FORMAT_S18_3LE] = {
0231 .width = 18, .phys = 24, .le = 1, .signd = 1,
0232 .silence = {},
0233 },
0234 [SNDRV_PCM_FORMAT_S18_3BE] = {
0235 .width = 18, .phys = 24, .le = 0, .signd = 1,
0236 .silence = {},
0237 },
0238 [SNDRV_PCM_FORMAT_U18_3LE] = {
0239 .width = 18, .phys = 24, .le = 1, .signd = 0,
0240 .silence = { 0x00, 0x00, 0x02 },
0241 },
0242 [SNDRV_PCM_FORMAT_U18_3BE] = {
0243 .width = 18, .phys = 24, .le = 0, .signd = 0,
0244 .silence = { 0x02, 0x00, 0x00 },
0245 },
0246 [SNDRV_PCM_FORMAT_G723_24_1B] = {
0247 .width = 3, .phys = 8, .le = -1, .signd = -1,
0248 .silence = {},
0249 },
0250 [SNDRV_PCM_FORMAT_G723_40_1B] = {
0251 .width = 5, .phys = 8, .le = -1, .signd = -1,
0252 .silence = {},
0253 },
0254 };
0255
0256
0257
0258
0259
0260
0261
0262
0263
0264 int snd_pcm_format_signed(snd_pcm_format_t format)
0265 {
0266 int val;
0267 if (!valid_format(format))
0268 return -EINVAL;
0269 val = pcm_formats[(INT)format].signd;
0270 if (val < 0)
0271 return -EINVAL;
0272 return val;
0273 }
0274 EXPORT_SYMBOL(snd_pcm_format_signed);
0275
0276
0277
0278
0279
0280
0281
0282
0283 int snd_pcm_format_unsigned(snd_pcm_format_t format)
0284 {
0285 int val;
0286
0287 val = snd_pcm_format_signed(format);
0288 if (val < 0)
0289 return val;
0290 return !val;
0291 }
0292 EXPORT_SYMBOL(snd_pcm_format_unsigned);
0293
0294
0295
0296
0297
0298
0299
0300 int snd_pcm_format_linear(snd_pcm_format_t format)
0301 {
0302 return snd_pcm_format_signed(format) >= 0;
0303 }
0304 EXPORT_SYMBOL(snd_pcm_format_linear);
0305
0306
0307
0308
0309
0310
0311
0312
0313 int snd_pcm_format_little_endian(snd_pcm_format_t format)
0314 {
0315 int val;
0316 if (!valid_format(format))
0317 return -EINVAL;
0318 val = pcm_formats[(INT)format].le;
0319 if (val < 0)
0320 return -EINVAL;
0321 return val;
0322 }
0323 EXPORT_SYMBOL(snd_pcm_format_little_endian);
0324
0325
0326
0327
0328
0329
0330
0331
0332 int snd_pcm_format_big_endian(snd_pcm_format_t format)
0333 {
0334 int val;
0335
0336 val = snd_pcm_format_little_endian(format);
0337 if (val < 0)
0338 return val;
0339 return !val;
0340 }
0341 EXPORT_SYMBOL(snd_pcm_format_big_endian);
0342
0343
0344
0345
0346
0347
0348
0349
0350 int snd_pcm_format_width(snd_pcm_format_t format)
0351 {
0352 int val;
0353 if (!valid_format(format))
0354 return -EINVAL;
0355 val = pcm_formats[(INT)format].width;
0356 if (!val)
0357 return -EINVAL;
0358 return val;
0359 }
0360 EXPORT_SYMBOL(snd_pcm_format_width);
0361
0362
0363
0364
0365
0366
0367
0368
0369 int snd_pcm_format_physical_width(snd_pcm_format_t format)
0370 {
0371 int val;
0372 if (!valid_format(format))
0373 return -EINVAL;
0374 val = pcm_formats[(INT)format].phys;
0375 if (!val)
0376 return -EINVAL;
0377 return val;
0378 }
0379 EXPORT_SYMBOL(snd_pcm_format_physical_width);
0380
0381
0382
0383
0384
0385
0386
0387
0388
0389 ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples)
0390 {
0391 int phys_width = snd_pcm_format_physical_width(format);
0392 if (phys_width < 0)
0393 return -EINVAL;
0394 return samples * phys_width / 8;
0395 }
0396 EXPORT_SYMBOL(snd_pcm_format_size);
0397
0398
0399
0400
0401
0402
0403
0404 const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format)
0405 {
0406 if (!valid_format(format))
0407 return NULL;
0408 if (! pcm_formats[(INT)format].phys)
0409 return NULL;
0410 return pcm_formats[(INT)format].silence;
0411 }
0412 EXPORT_SYMBOL(snd_pcm_format_silence_64);
0413
0414
0415
0416
0417
0418
0419
0420
0421
0422
0423
0424 int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int samples)
0425 {
0426 int width;
0427 unsigned char *dst;
0428 const unsigned char *pat;
0429
0430 if (!valid_format(format))
0431 return -EINVAL;
0432 if (samples == 0)
0433 return 0;
0434 width = pcm_formats[(INT)format].phys;
0435 pat = pcm_formats[(INT)format].silence;
0436 if (!width || !pat)
0437 return -EINVAL;
0438
0439 if (pcm_formats[(INT)format].signd == 1 || width <= 8) {
0440 unsigned int bytes = samples * width / 8;
0441 memset(data, *pat, bytes);
0442 return 0;
0443 }
0444
0445 width /= 8;
0446 dst = data;
0447 #if 0
0448 while (samples--) {
0449 memcpy(dst, pat, width);
0450 dst += width;
0451 }
0452 #else
0453
0454 switch (width) {
0455 case 2:
0456 while (samples--) {
0457 memcpy(dst, pat, 2);
0458 dst += 2;
0459 }
0460 break;
0461 case 3:
0462 while (samples--) {
0463 memcpy(dst, pat, 3);
0464 dst += 3;
0465 }
0466 break;
0467 case 4:
0468 while (samples--) {
0469 memcpy(dst, pat, 4);
0470 dst += 4;
0471 }
0472 break;
0473 case 8:
0474 while (samples--) {
0475 memcpy(dst, pat, 8);
0476 dst += 8;
0477 }
0478 break;
0479 }
0480 #endif
0481 return 0;
0482 }
0483 EXPORT_SYMBOL(snd_pcm_format_set_silence);
0484
0485
0486
0487
0488
0489
0490
0491
0492
0493
0494 int snd_pcm_hw_limit_rates(struct snd_pcm_hardware *hw)
0495 {
0496 int i;
0497 for (i = 0; i < (int)snd_pcm_known_rates.count; i++) {
0498 if (hw->rates & (1 << i)) {
0499 hw->rate_min = snd_pcm_known_rates.list[i];
0500 break;
0501 }
0502 }
0503 for (i = (int)snd_pcm_known_rates.count - 1; i >= 0; i--) {
0504 if (hw->rates & (1 << i)) {
0505 hw->rate_max = snd_pcm_known_rates.list[i];
0506 break;
0507 }
0508 }
0509 return 0;
0510 }
0511 EXPORT_SYMBOL(snd_pcm_hw_limit_rates);
0512
0513
0514
0515
0516
0517
0518
0519
0520 unsigned int snd_pcm_rate_to_rate_bit(unsigned int rate)
0521 {
0522 unsigned int i;
0523
0524 for (i = 0; i < snd_pcm_known_rates.count; i++)
0525 if (snd_pcm_known_rates.list[i] == rate)
0526 return 1u << i;
0527 return SNDRV_PCM_RATE_KNOT;
0528 }
0529 EXPORT_SYMBOL(snd_pcm_rate_to_rate_bit);
0530
0531
0532
0533
0534
0535
0536
0537
0538 unsigned int snd_pcm_rate_bit_to_rate(unsigned int rate_bit)
0539 {
0540 unsigned int i;
0541
0542 for (i = 0; i < snd_pcm_known_rates.count; i++)
0543 if ((1u << i) == rate_bit)
0544 return snd_pcm_known_rates.list[i];
0545 return 0;
0546 }
0547 EXPORT_SYMBOL(snd_pcm_rate_bit_to_rate);
0548
0549 static unsigned int snd_pcm_rate_mask_sanitize(unsigned int rates)
0550 {
0551 if (rates & SNDRV_PCM_RATE_CONTINUOUS)
0552 return SNDRV_PCM_RATE_CONTINUOUS;
0553 else if (rates & SNDRV_PCM_RATE_KNOT)
0554 return SNDRV_PCM_RATE_KNOT;
0555 return rates;
0556 }
0557
0558
0559
0560
0561
0562
0563
0564
0565
0566
0567
0568
0569
0570 unsigned int snd_pcm_rate_mask_intersect(unsigned int rates_a,
0571 unsigned int rates_b)
0572 {
0573 rates_a = snd_pcm_rate_mask_sanitize(rates_a);
0574 rates_b = snd_pcm_rate_mask_sanitize(rates_b);
0575
0576 if (rates_a & SNDRV_PCM_RATE_CONTINUOUS)
0577 return rates_b;
0578 else if (rates_b & SNDRV_PCM_RATE_CONTINUOUS)
0579 return rates_a;
0580 else if (rates_a & SNDRV_PCM_RATE_KNOT)
0581 return rates_b;
0582 else if (rates_b & SNDRV_PCM_RATE_KNOT)
0583 return rates_a;
0584 return rates_a & rates_b;
0585 }
0586 EXPORT_SYMBOL_GPL(snd_pcm_rate_mask_intersect);
0587
0588
0589
0590
0591
0592
0593
0594
0595
0596
0597
0598
0599 unsigned int snd_pcm_rate_range_to_bits(unsigned int rate_min,
0600 unsigned int rate_max)
0601 {
0602 unsigned int rates = 0;
0603 int i;
0604
0605 for (i = 0; i < snd_pcm_known_rates.count; i++) {
0606 if (snd_pcm_known_rates.list[i] >= rate_min
0607 && snd_pcm_known_rates.list[i] <= rate_max)
0608 rates |= 1 << i;
0609 }
0610
0611 if (!rates)
0612 rates = SNDRV_PCM_RATE_KNOT;
0613
0614 return rates;
0615 }
0616 EXPORT_SYMBOL_GPL(snd_pcm_rate_range_to_bits);