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); 490