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 /** 211 * snd_pcm_format_unsigned - Check the PCM format is unsigned linear 212 * @format: the format to check 213 * 214 * Returns 1 if the given PCM format is unsigned linear, 0 if signed 215 * linear, and a negative error code for non-linear formats. 216 */ 217 int snd_pcm_format_unsigned(snd_pcm_format_t format) 218 { 219 int val; 220 221 val = snd_pcm_format_signed(format); 222 if (val < 0) 223 return val; 224 return !val; 225 } 226 227 /** 228 * snd_pcm_format_linear - Check the PCM format is linear 229 * @format: the format to check 230 * 231 * Returns 1 if the given PCM format is linear, 0 if not. 232 */ 233 int snd_pcm_format_linear(snd_pcm_format_t format) 234 { 235 return snd_pcm_format_signed(format) >= 0; 236 } 237 238 /** 239 * snd_pcm_format_little_endian - Check the PCM format is little-endian 240 * @format: the format to check 241 * 242 * Returns 1 if the given PCM format is little-endian, 0 if 243 * big-endian, or a negative error code if endian not specified. 244 */ 245 int snd_pcm_format_little_endian(snd_pcm_format_t format) 246 { 247 int val; 248 if (format < 0 || format > SNDRV_PCM_FORMAT_LAST) 249 return -EINVAL; 250 if ((val = pcm_formats[format].le) < 0) 251 return -EINVAL; 252 return val; 253 } 254 255 /** 256 * snd_pcm_format_big_endian - Check the PCM format is big-endian 257 * @format: the format to check 258 * 259 * Returns 1 if the given PCM format is big-endian, 0 if 260 * little-endian, or a negative error code if endian not specified. 261 */ 262 int snd_pcm_format_big_endian(snd_pcm_format_t format) 263 { 264 int val; 265 266 val = snd_pcm_format_little_endian(format); 267 if (val < 0) 268 return val; 269 return !val; 270 } 271 272 /** 273 * snd_pcm_format_cpu_endian - Check the PCM format is CPU-endian 274 * @format: the format to check 275 * 276 * Returns 1 if the given PCM format is CPU-endian, 0 if 277 * opposite, or a negative error code if endian not specified. 278 */ 279 int snd_pcm_format_cpu_endian(snd_pcm_format_t format) 280 { 281 #ifdef SNDRV_LITTLE_ENDIAN 282 return snd_pcm_format_little_endian(format); 283 #else 284 return snd_pcm_format_big_endian(format); 285 #endif 286 } 287 288 /** 289 * snd_pcm_format_width - return the bit-width of the format 290 * @format: the format to check 291 * 292 * Returns the bit-width of the format, or a negative error code 293 * if unknown format. 294 */ 295 int snd_pcm_format_width(snd_pcm_format_t format) 296 { 297 int val; 298 if (format < 0 || format > SNDRV_PCM_FORMAT_LAST) 299 return -EINVAL; 300 if ((val = pcm_formats[format].width) == 0) 301 return -EINVAL; 302 return val; 303 } 304 305 /** 306 * snd_pcm_format_physical_width - return the physical bit-width of the format 307 * @format: the format to check 308 * 309 * Returns the physical bit-width of the format, or a negative error code 310 * if unknown format. 311 */ 312 int snd_pcm_format_physical_width(snd_pcm_format_t format) 313 { 314 int val; 315 if (format < 0 || format > SNDRV_PCM_FORMAT_LAST) 316 return -EINVAL; 317 if ((val = pcm_formats[format].phys) == 0) 318 return -EINVAL; 319 return val; 320 } 321 322 /** 323 * snd_pcm_format_size - return the byte size of samples on the given format 324 * @format: the format to check 325 * 326 * Returns the byte size of the given samples for the format, or a 327 * negative error code if unknown format. 328 */ 329 ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples) 330 { 331 int phys_width = snd_pcm_format_physical_width(format); 332 if (phys_width < 0) 333 return -EINVAL; 334 return samples * phys_width / 8; 335 } 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 /** 353 * snd_pcm_format_set_silence - set the silence data on the buffer 354 * @format: the PCM format 355 * @data: the buffer pointer 356 * @samples: the number of samples to set silence 357 * 358 * Sets the silence data on the buffer for the given samples. 359 * 360 * Returns zero if successful, or a negative error code on failure. 361 */ 362 int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int samples) 363 { 364 int width; 365 unsigned char *dst, *pat; 366 367 if (format < 0 || format > SNDRV_PCM_FORMAT_LAST) 368 return -EINVAL; 369 if (samples == 0) 370 return 0; 371 width = pcm_formats[format].phys; /* physical width */ 372 pat = pcm_formats[format].silence; 373 if (! width) 374 return -EINVAL; 375 /* signed or 1 byte data */ 376 if (pcm_formats[format].signd == 1 || width <= 8) { 377 unsigned int bytes = samples * width / 8; 378 memset(data, *pat, bytes); 379 return 0; 380 } 381 /* non-zero samples, fill using a loop */ 382 width /= 8; 383 dst = data; 384 #if 0 385 while (samples--) { 386 memcpy(dst, pat, width); 387 dst += width; 388 } 389 #else 390 /* a bit optimization for constant width */ 391 switch (width) { 392 case 2: 393 while (samples--) { 394 memcpy(dst, pat, 2); 395 dst += 2; 396 } 397 break; 398 case 3: 399 while (samples--) { 400 memcpy(dst, pat, 3); 401 dst += 3; 402 } 403 break; 404 case 4: 405 while (samples--) { 406 memcpy(dst, pat, 4); 407 dst += 4; 408 } 409 break; 410 case 8: 411 while (samples--) { 412 memcpy(dst, pat, 8); 413 dst += 8; 414 } 415 break; 416 } 417 #endif 418 return 0; 419 } 420 421 /* [width][unsigned][bigendian] */ 422 static int linear_formats[4][2][2] = { 423 {{ SNDRV_PCM_FORMAT_S8, SNDRV_PCM_FORMAT_S8}, 424 { SNDRV_PCM_FORMAT_U8, SNDRV_PCM_FORMAT_U8}}, 425 {{SNDRV_PCM_FORMAT_S16_LE, SNDRV_PCM_FORMAT_S16_BE}, 426 {SNDRV_PCM_FORMAT_U16_LE, SNDRV_PCM_FORMAT_U16_BE}}, 427 {{SNDRV_PCM_FORMAT_S24_LE, SNDRV_PCM_FORMAT_S24_BE}, 428 {SNDRV_PCM_FORMAT_U24_LE, SNDRV_PCM_FORMAT_U24_BE}}, 429 {{SNDRV_PCM_FORMAT_S32_LE, SNDRV_PCM_FORMAT_S32_BE}, 430 {SNDRV_PCM_FORMAT_U32_LE, SNDRV_PCM_FORMAT_U32_BE}} 431 }; 432 433 /** 434 * snd_pcm_build_linear_format - return the suitable linear format for the given condition 435 * @width: the bit-width 436 * @unsignd: 1 if unsigned, 0 if signed. 437 * @big_endian: 1 if big-endian, 0 if little-endian 438 * 439 * Returns the suitable linear format for the given condition. 440 */ 441 snd_pcm_format_t snd_pcm_build_linear_format(int width, int unsignd, int big_endian) 442 { 443 if (width & 7) 444 return SND_PCM_FORMAT_UNKNOWN; 445 width = (width / 8) - 1; 446 if (width < 0 || width >= 4) 447 return SND_PCM_FORMAT_UNKNOWN; 448 return linear_formats[width][!!unsignd][!!big_endian]; 449 } 450 451 /** 452 * snd_pcm_limit_hw_rates - determine rate_min/rate_max fields 453 * @runtime: the runtime instance 454 * 455 * Determines the rate_min and rate_max fields from the rates bits of 456 * the given runtime->hw. 457 * 458 * Returns zero if successful. 459 */ 460 int snd_pcm_limit_hw_rates(snd_pcm_runtime_t *runtime) 461 { 462 static unsigned rates[] = { 463 /* ATTENTION: these values depend on the definition in pcm.h! */ 464 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, 465 64000, 88200, 96000, 176400, 192000 466 }; 467 int i; 468 for (i = 0; i < (int)ARRAY_SIZE(rates); i++) { 469 if (runtime->hw.rates & (1 << i)) { 470 runtime->hw.rate_min = rates[i]; 471 break; 472 } 473 } 474 for (i = (int)ARRAY_SIZE(rates) - 1; i >= 0; i--) { 475 if (runtime->hw.rates & (1 << i)) { 476 runtime->hw.rate_max = rates[i]; 477 break; 478 } 479 } 480 return 0; 481 } 482