11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * PCM Interface - misc routines 3c1017a4cSJaroslav Kysela * Copyright (c) 1998 by Jaroslav Kysela <perex@perex.cz> 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * This library is free software; you can redistribute it and/or modify 71da177e4SLinus Torvalds * it under the terms of the GNU Library General Public License as 81da177e4SLinus Torvalds * published by the Free Software Foundation; either version 2 of 91da177e4SLinus Torvalds * the License, or (at your option) any later version. 101da177e4SLinus Torvalds * 111da177e4SLinus Torvalds * This program is distributed in the hope that it will be useful, 121da177e4SLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 131da177e4SLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 141da177e4SLinus Torvalds * GNU Library General Public License for more details. 151da177e4SLinus Torvalds * 161da177e4SLinus Torvalds * You should have received a copy of the GNU Library General Public 171da177e4SLinus Torvalds * License along with this library; if not, write to the Free Software 181da177e4SLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 191da177e4SLinus Torvalds * 201da177e4SLinus Torvalds */ 211da177e4SLinus Torvalds 221da177e4SLinus Torvalds #include <linux/time.h> 23d81a6d71SPaul Gortmaker #include <linux/export.h> 241da177e4SLinus Torvalds #include <sound/core.h> 251da177e4SLinus Torvalds #include <sound/pcm.h> 261da177e4SLinus Torvalds #define SND_PCM_FORMAT_UNKNOWN (-1) 271da177e4SLinus Torvalds 281da177e4SLinus Torvalds /* NOTE: "signed" prefix must be given below since the default char is 291da177e4SLinus Torvalds * unsigned on some architectures! 301da177e4SLinus Torvalds */ 311da177e4SLinus Torvalds struct pcm_format_data { 321da177e4SLinus Torvalds unsigned char width; /* bit width */ 331da177e4SLinus Torvalds unsigned char phys; /* physical bit width */ 341da177e4SLinus Torvalds signed char le; /* 0 = big-endian, 1 = little-endian, -1 = others */ 351da177e4SLinus Torvalds signed char signd; /* 0 = unsigned, 1 = signed, -1 = others */ 361da177e4SLinus Torvalds unsigned char silence[8]; /* silence data to fill */ 371da177e4SLinus Torvalds }; 381da177e4SLinus Torvalds 39fea952e5SClemens Ladisch /* we do lots of calculations on snd_pcm_format_t; shut up sparse */ 40fea952e5SClemens Ladisch #define INT __force int 41fea952e5SClemens Ladisch 42fea952e5SClemens Ladisch static struct pcm_format_data pcm_formats[(INT)SNDRV_PCM_FORMAT_LAST+1] = { 431da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_S8] = { 441da177e4SLinus Torvalds .width = 8, .phys = 8, .le = -1, .signd = 1, 451da177e4SLinus Torvalds .silence = {}, 461da177e4SLinus Torvalds }, 471da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_U8] = { 481da177e4SLinus Torvalds .width = 8, .phys = 8, .le = -1, .signd = 0, 491da177e4SLinus Torvalds .silence = { 0x80 }, 501da177e4SLinus Torvalds }, 511da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_S16_LE] = { 521da177e4SLinus Torvalds .width = 16, .phys = 16, .le = 1, .signd = 1, 531da177e4SLinus Torvalds .silence = {}, 541da177e4SLinus Torvalds }, 551da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_S16_BE] = { 561da177e4SLinus Torvalds .width = 16, .phys = 16, .le = 0, .signd = 1, 571da177e4SLinus Torvalds .silence = {}, 581da177e4SLinus Torvalds }, 591da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_U16_LE] = { 601da177e4SLinus Torvalds .width = 16, .phys = 16, .le = 1, .signd = 0, 611da177e4SLinus Torvalds .silence = { 0x00, 0x80 }, 621da177e4SLinus Torvalds }, 631da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_U16_BE] = { 641da177e4SLinus Torvalds .width = 16, .phys = 16, .le = 0, .signd = 0, 651da177e4SLinus Torvalds .silence = { 0x80, 0x00 }, 661da177e4SLinus Torvalds }, 671da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_S24_LE] = { 681da177e4SLinus Torvalds .width = 24, .phys = 32, .le = 1, .signd = 1, 691da177e4SLinus Torvalds .silence = {}, 701da177e4SLinus Torvalds }, 711da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_S24_BE] = { 721da177e4SLinus Torvalds .width = 24, .phys = 32, .le = 0, .signd = 1, 731da177e4SLinus Torvalds .silence = {}, 741da177e4SLinus Torvalds }, 751da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_U24_LE] = { 761da177e4SLinus Torvalds .width = 24, .phys = 32, .le = 1, .signd = 0, 771da177e4SLinus Torvalds .silence = { 0x00, 0x00, 0x80 }, 781da177e4SLinus Torvalds }, 791da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_U24_BE] = { 801da177e4SLinus Torvalds .width = 24, .phys = 32, .le = 0, .signd = 0, 8167a7be7eSJaroslav Kysela .silence = { 0x00, 0x80, 0x00, 0x00 }, 821da177e4SLinus Torvalds }, 831da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_S32_LE] = { 841da177e4SLinus Torvalds .width = 32, .phys = 32, .le = 1, .signd = 1, 851da177e4SLinus Torvalds .silence = {}, 861da177e4SLinus Torvalds }, 871da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_S32_BE] = { 881da177e4SLinus Torvalds .width = 32, .phys = 32, .le = 0, .signd = 1, 891da177e4SLinus Torvalds .silence = {}, 901da177e4SLinus Torvalds }, 911da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_U32_LE] = { 921da177e4SLinus Torvalds .width = 32, .phys = 32, .le = 1, .signd = 0, 931da177e4SLinus Torvalds .silence = { 0x00, 0x00, 0x00, 0x80 }, 941da177e4SLinus Torvalds }, 951da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_U32_BE] = { 961da177e4SLinus Torvalds .width = 32, .phys = 32, .le = 0, .signd = 0, 971da177e4SLinus Torvalds .silence = { 0x80, 0x00, 0x00, 0x00 }, 981da177e4SLinus Torvalds }, 991da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_FLOAT_LE] = { 1001da177e4SLinus Torvalds .width = 32, .phys = 32, .le = 1, .signd = -1, 1011da177e4SLinus Torvalds .silence = {}, 1021da177e4SLinus Torvalds }, 1031da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_FLOAT_BE] = { 1041da177e4SLinus Torvalds .width = 32, .phys = 32, .le = 0, .signd = -1, 1051da177e4SLinus Torvalds .silence = {}, 1061da177e4SLinus Torvalds }, 1071da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_FLOAT64_LE] = { 1081da177e4SLinus Torvalds .width = 64, .phys = 64, .le = 1, .signd = -1, 1091da177e4SLinus Torvalds .silence = {}, 1101da177e4SLinus Torvalds }, 1111da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_FLOAT64_BE] = { 1121da177e4SLinus Torvalds .width = 64, .phys = 64, .le = 0, .signd = -1, 1131da177e4SLinus Torvalds .silence = {}, 1141da177e4SLinus Torvalds }, 1151da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE] = { 1161da177e4SLinus Torvalds .width = 32, .phys = 32, .le = 1, .signd = -1, 1171da177e4SLinus Torvalds .silence = {}, 1181da177e4SLinus Torvalds }, 1191da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE] = { 1201da177e4SLinus Torvalds .width = 32, .phys = 32, .le = 0, .signd = -1, 1211da177e4SLinus Torvalds .silence = {}, 1221da177e4SLinus Torvalds }, 1231da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_MU_LAW] = { 1241da177e4SLinus Torvalds .width = 8, .phys = 8, .le = -1, .signd = -1, 1251da177e4SLinus Torvalds .silence = { 0x7f }, 1261da177e4SLinus Torvalds }, 1271da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_A_LAW] = { 1281da177e4SLinus Torvalds .width = 8, .phys = 8, .le = -1, .signd = -1, 1291da177e4SLinus Torvalds .silence = { 0x55 }, 1301da177e4SLinus Torvalds }, 1311da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_IMA_ADPCM] = { 1321da177e4SLinus Torvalds .width = 4, .phys = 4, .le = -1, .signd = -1, 1331da177e4SLinus Torvalds .silence = {}, 1341da177e4SLinus Torvalds }, 13515c0cee6SBen Collins [SNDRV_PCM_FORMAT_G723_24] = { 13615c0cee6SBen Collins .width = 3, .phys = 3, .le = -1, .signd = -1, 13715c0cee6SBen Collins .silence = {}, 13815c0cee6SBen Collins }, 13915c0cee6SBen Collins [SNDRV_PCM_FORMAT_G723_40] = { 14015c0cee6SBen Collins .width = 5, .phys = 5, .le = -1, .signd = -1, 14115c0cee6SBen Collins .silence = {}, 14215c0cee6SBen Collins }, 1431da177e4SLinus Torvalds /* FIXME: the following three formats are not defined properly yet */ 1441da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_MPEG] = { 1451da177e4SLinus Torvalds .le = -1, .signd = -1, 1461da177e4SLinus Torvalds }, 1471da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_GSM] = { 1481da177e4SLinus Torvalds .le = -1, .signd = -1, 1491da177e4SLinus Torvalds }, 1501da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_SPECIAL] = { 1511da177e4SLinus Torvalds .le = -1, .signd = -1, 1521da177e4SLinus Torvalds }, 1531da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_S24_3LE] = { 1541da177e4SLinus Torvalds .width = 24, .phys = 24, .le = 1, .signd = 1, 1551da177e4SLinus Torvalds .silence = {}, 1561da177e4SLinus Torvalds }, 1571da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_S24_3BE] = { 1581da177e4SLinus Torvalds .width = 24, .phys = 24, .le = 0, .signd = 1, 1591da177e4SLinus Torvalds .silence = {}, 1601da177e4SLinus Torvalds }, 1611da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_U24_3LE] = { 1621da177e4SLinus Torvalds .width = 24, .phys = 24, .le = 1, .signd = 0, 1631da177e4SLinus Torvalds .silence = { 0x00, 0x00, 0x80 }, 1641da177e4SLinus Torvalds }, 1651da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_U24_3BE] = { 1661da177e4SLinus Torvalds .width = 24, .phys = 24, .le = 0, .signd = 0, 1671da177e4SLinus Torvalds .silence = { 0x80, 0x00, 0x00 }, 1681da177e4SLinus Torvalds }, 1691da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_S20_3LE] = { 1701da177e4SLinus Torvalds .width = 20, .phys = 24, .le = 1, .signd = 1, 1711da177e4SLinus Torvalds .silence = {}, 1721da177e4SLinus Torvalds }, 1731da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_S20_3BE] = { 1741da177e4SLinus Torvalds .width = 20, .phys = 24, .le = 0, .signd = 1, 1751da177e4SLinus Torvalds .silence = {}, 1761da177e4SLinus Torvalds }, 1771da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_U20_3LE] = { 1781da177e4SLinus Torvalds .width = 20, .phys = 24, .le = 1, .signd = 0, 1791da177e4SLinus Torvalds .silence = { 0x00, 0x00, 0x08 }, 1801da177e4SLinus Torvalds }, 1811da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_U20_3BE] = { 1821da177e4SLinus Torvalds .width = 20, .phys = 24, .le = 0, .signd = 0, 1831da177e4SLinus Torvalds .silence = { 0x08, 0x00, 0x00 }, 1841da177e4SLinus Torvalds }, 1851da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_S18_3LE] = { 1861da177e4SLinus Torvalds .width = 18, .phys = 24, .le = 1, .signd = 1, 1871da177e4SLinus Torvalds .silence = {}, 1881da177e4SLinus Torvalds }, 1891da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_S18_3BE] = { 1901da177e4SLinus Torvalds .width = 18, .phys = 24, .le = 0, .signd = 1, 1911da177e4SLinus Torvalds .silence = {}, 1921da177e4SLinus Torvalds }, 1931da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_U18_3LE] = { 1941da177e4SLinus Torvalds .width = 18, .phys = 24, .le = 1, .signd = 0, 1951da177e4SLinus Torvalds .silence = { 0x00, 0x00, 0x02 }, 1961da177e4SLinus Torvalds }, 1971da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_U18_3BE] = { 1981da177e4SLinus Torvalds .width = 18, .phys = 24, .le = 0, .signd = 0, 1991da177e4SLinus Torvalds .silence = { 0x02, 0x00, 0x00 }, 2001da177e4SLinus Torvalds }, 20115c0cee6SBen Collins [SNDRV_PCM_FORMAT_G723_24_1B] = { 20215c0cee6SBen Collins .width = 3, .phys = 8, .le = -1, .signd = -1, 20315c0cee6SBen Collins .silence = {}, 20415c0cee6SBen Collins }, 20515c0cee6SBen Collins [SNDRV_PCM_FORMAT_G723_40_1B] = { 20615c0cee6SBen Collins .width = 5, .phys = 8, .le = -1, .signd = -1, 20715c0cee6SBen Collins .silence = {}, 20815c0cee6SBen Collins }, 2091da177e4SLinus Torvalds }; 2101da177e4SLinus Torvalds 2111da177e4SLinus Torvalds 2121da177e4SLinus Torvalds /** 2131da177e4SLinus Torvalds * snd_pcm_format_signed - Check the PCM format is signed linear 2141da177e4SLinus Torvalds * @format: the format to check 2151da177e4SLinus Torvalds * 216*eb7c06e8SYacine Belkadi * Return: 1 if the given PCM format is signed linear, 0 if unsigned 2171da177e4SLinus Torvalds * linear, and a negative error code for non-linear formats. 2181da177e4SLinus Torvalds */ 2191da177e4SLinus Torvalds int snd_pcm_format_signed(snd_pcm_format_t format) 2201da177e4SLinus Torvalds { 2211da177e4SLinus Torvalds int val; 222fea952e5SClemens Ladisch if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST) 2231da177e4SLinus Torvalds return -EINVAL; 224fea952e5SClemens Ladisch if ((val = pcm_formats[(INT)format].signd) < 0) 2251da177e4SLinus Torvalds return -EINVAL; 2261da177e4SLinus Torvalds return val; 2271da177e4SLinus Torvalds } 2281da177e4SLinus Torvalds 229e88e8ae6STakashi Iwai EXPORT_SYMBOL(snd_pcm_format_signed); 230e88e8ae6STakashi Iwai 2311da177e4SLinus Torvalds /** 2321da177e4SLinus Torvalds * snd_pcm_format_unsigned - Check the PCM format is unsigned linear 2331da177e4SLinus Torvalds * @format: the format to check 2341da177e4SLinus Torvalds * 235*eb7c06e8SYacine Belkadi * Return: 1 if the given PCM format is unsigned linear, 0 if signed 2361da177e4SLinus Torvalds * linear, and a negative error code for non-linear formats. 2371da177e4SLinus Torvalds */ 2381da177e4SLinus Torvalds int snd_pcm_format_unsigned(snd_pcm_format_t format) 2391da177e4SLinus Torvalds { 2401da177e4SLinus Torvalds int val; 2411da177e4SLinus Torvalds 2421da177e4SLinus Torvalds val = snd_pcm_format_signed(format); 2431da177e4SLinus Torvalds if (val < 0) 2441da177e4SLinus Torvalds return val; 2451da177e4SLinus Torvalds return !val; 2461da177e4SLinus Torvalds } 2471da177e4SLinus Torvalds 248e88e8ae6STakashi Iwai EXPORT_SYMBOL(snd_pcm_format_unsigned); 249e88e8ae6STakashi Iwai 2501da177e4SLinus Torvalds /** 2511da177e4SLinus Torvalds * snd_pcm_format_linear - Check the PCM format is linear 2521da177e4SLinus Torvalds * @format: the format to check 2531da177e4SLinus Torvalds * 254*eb7c06e8SYacine Belkadi * Return: 1 if the given PCM format is linear, 0 if not. 2551da177e4SLinus Torvalds */ 2561da177e4SLinus Torvalds int snd_pcm_format_linear(snd_pcm_format_t format) 2571da177e4SLinus Torvalds { 2581da177e4SLinus Torvalds return snd_pcm_format_signed(format) >= 0; 2591da177e4SLinus Torvalds } 2601da177e4SLinus Torvalds 261e88e8ae6STakashi Iwai EXPORT_SYMBOL(snd_pcm_format_linear); 262e88e8ae6STakashi Iwai 2631da177e4SLinus Torvalds /** 2641da177e4SLinus Torvalds * snd_pcm_format_little_endian - Check the PCM format is little-endian 2651da177e4SLinus Torvalds * @format: the format to check 2661da177e4SLinus Torvalds * 267*eb7c06e8SYacine Belkadi * Return: 1 if the given PCM format is little-endian, 0 if 2681da177e4SLinus Torvalds * big-endian, or a negative error code if endian not specified. 2691da177e4SLinus Torvalds */ 2701da177e4SLinus Torvalds int snd_pcm_format_little_endian(snd_pcm_format_t format) 2711da177e4SLinus Torvalds { 2721da177e4SLinus Torvalds int val; 273fea952e5SClemens Ladisch if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST) 2741da177e4SLinus Torvalds return -EINVAL; 275fea952e5SClemens Ladisch if ((val = pcm_formats[(INT)format].le) < 0) 2761da177e4SLinus Torvalds return -EINVAL; 2771da177e4SLinus Torvalds return val; 2781da177e4SLinus Torvalds } 2791da177e4SLinus Torvalds 280e88e8ae6STakashi Iwai EXPORT_SYMBOL(snd_pcm_format_little_endian); 281e88e8ae6STakashi Iwai 2821da177e4SLinus Torvalds /** 2831da177e4SLinus Torvalds * snd_pcm_format_big_endian - Check the PCM format is big-endian 2841da177e4SLinus Torvalds * @format: the format to check 2851da177e4SLinus Torvalds * 286*eb7c06e8SYacine Belkadi * Return: 1 if the given PCM format is big-endian, 0 if 2871da177e4SLinus Torvalds * little-endian, or a negative error code if endian not specified. 2881da177e4SLinus Torvalds */ 2891da177e4SLinus Torvalds int snd_pcm_format_big_endian(snd_pcm_format_t format) 2901da177e4SLinus Torvalds { 2911da177e4SLinus Torvalds int val; 2921da177e4SLinus Torvalds 2931da177e4SLinus Torvalds val = snd_pcm_format_little_endian(format); 2941da177e4SLinus Torvalds if (val < 0) 2951da177e4SLinus Torvalds return val; 2961da177e4SLinus Torvalds return !val; 2971da177e4SLinus Torvalds } 2981da177e4SLinus Torvalds 299e88e8ae6STakashi Iwai EXPORT_SYMBOL(snd_pcm_format_big_endian); 300e88e8ae6STakashi Iwai 3011da177e4SLinus Torvalds /** 3021da177e4SLinus Torvalds * snd_pcm_format_width - return the bit-width of the format 3031da177e4SLinus Torvalds * @format: the format to check 3041da177e4SLinus Torvalds * 305*eb7c06e8SYacine Belkadi * Return: The bit-width of the format, or a negative error code 3061da177e4SLinus Torvalds * if unknown format. 3071da177e4SLinus Torvalds */ 3081da177e4SLinus Torvalds int snd_pcm_format_width(snd_pcm_format_t format) 3091da177e4SLinus Torvalds { 3101da177e4SLinus Torvalds int val; 311fea952e5SClemens Ladisch if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST) 3121da177e4SLinus Torvalds return -EINVAL; 313fea952e5SClemens Ladisch if ((val = pcm_formats[(INT)format].width) == 0) 3141da177e4SLinus Torvalds return -EINVAL; 3151da177e4SLinus Torvalds return val; 3161da177e4SLinus Torvalds } 3171da177e4SLinus Torvalds 318e88e8ae6STakashi Iwai EXPORT_SYMBOL(snd_pcm_format_width); 319e88e8ae6STakashi Iwai 3201da177e4SLinus Torvalds /** 3211da177e4SLinus Torvalds * snd_pcm_format_physical_width - return the physical bit-width of the format 3221da177e4SLinus Torvalds * @format: the format to check 3231da177e4SLinus Torvalds * 324*eb7c06e8SYacine Belkadi * Return: The physical bit-width of the format, or a negative error code 3251da177e4SLinus Torvalds * if unknown format. 3261da177e4SLinus Torvalds */ 3271da177e4SLinus Torvalds int snd_pcm_format_physical_width(snd_pcm_format_t format) 3281da177e4SLinus Torvalds { 3291da177e4SLinus Torvalds int val; 330fea952e5SClemens Ladisch if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST) 3311da177e4SLinus Torvalds return -EINVAL; 332fea952e5SClemens Ladisch if ((val = pcm_formats[(INT)format].phys) == 0) 3331da177e4SLinus Torvalds return -EINVAL; 3341da177e4SLinus Torvalds return val; 3351da177e4SLinus Torvalds } 3361da177e4SLinus Torvalds 337e88e8ae6STakashi Iwai EXPORT_SYMBOL(snd_pcm_format_physical_width); 338e88e8ae6STakashi Iwai 3391da177e4SLinus Torvalds /** 3401da177e4SLinus Torvalds * snd_pcm_format_size - return the byte size of samples on the given format 3411da177e4SLinus Torvalds * @format: the format to check 342a66547f3SRandy Dunlap * @samples: sampling rate 3431da177e4SLinus Torvalds * 344*eb7c06e8SYacine Belkadi * Return: The byte size of the given samples for the format, or a 3451da177e4SLinus Torvalds * negative error code if unknown format. 3461da177e4SLinus Torvalds */ 3471da177e4SLinus Torvalds ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples) 3481da177e4SLinus Torvalds { 3491da177e4SLinus Torvalds int phys_width = snd_pcm_format_physical_width(format); 3501da177e4SLinus Torvalds if (phys_width < 0) 3511da177e4SLinus Torvalds return -EINVAL; 3521da177e4SLinus Torvalds return samples * phys_width / 8; 3531da177e4SLinus Torvalds } 3541da177e4SLinus Torvalds 355e88e8ae6STakashi Iwai EXPORT_SYMBOL(snd_pcm_format_size); 356e88e8ae6STakashi Iwai 3571da177e4SLinus Torvalds /** 3581da177e4SLinus Torvalds * snd_pcm_format_silence_64 - return the silent data in 8 bytes array 3591da177e4SLinus Torvalds * @format: the format to check 3601da177e4SLinus Torvalds * 361*eb7c06e8SYacine Belkadi * Return: The format pattern to fill or %NULL if error. 3621da177e4SLinus Torvalds */ 3631da177e4SLinus Torvalds const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format) 3641da177e4SLinus Torvalds { 365fea952e5SClemens Ladisch if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST) 3661da177e4SLinus Torvalds return NULL; 367fea952e5SClemens Ladisch if (! pcm_formats[(INT)format].phys) 3681da177e4SLinus Torvalds return NULL; 369fea952e5SClemens Ladisch return pcm_formats[(INT)format].silence; 3701da177e4SLinus Torvalds } 3711da177e4SLinus Torvalds 372e88e8ae6STakashi Iwai EXPORT_SYMBOL(snd_pcm_format_silence_64); 373e88e8ae6STakashi Iwai 3741da177e4SLinus Torvalds /** 3751da177e4SLinus Torvalds * snd_pcm_format_set_silence - set the silence data on the buffer 3761da177e4SLinus Torvalds * @format: the PCM format 3771da177e4SLinus Torvalds * @data: the buffer pointer 3781da177e4SLinus Torvalds * @samples: the number of samples to set silence 3791da177e4SLinus Torvalds * 3801da177e4SLinus Torvalds * Sets the silence data on the buffer for the given samples. 3811da177e4SLinus Torvalds * 382*eb7c06e8SYacine Belkadi * Return: Zero if successful, or a negative error code on failure. 3831da177e4SLinus Torvalds */ 3841da177e4SLinus Torvalds int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int samples) 3851da177e4SLinus Torvalds { 3861da177e4SLinus Torvalds int width; 3871da177e4SLinus Torvalds unsigned char *dst, *pat; 3881da177e4SLinus Torvalds 389fea952e5SClemens Ladisch if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST) 3901da177e4SLinus Torvalds return -EINVAL; 3911da177e4SLinus Torvalds if (samples == 0) 3921da177e4SLinus Torvalds return 0; 393fea952e5SClemens Ladisch width = pcm_formats[(INT)format].phys; /* physical width */ 394fea952e5SClemens Ladisch pat = pcm_formats[(INT)format].silence; 3951da177e4SLinus Torvalds if (! width) 3961da177e4SLinus Torvalds return -EINVAL; 3971da177e4SLinus Torvalds /* signed or 1 byte data */ 398fea952e5SClemens Ladisch if (pcm_formats[(INT)format].signd == 1 || width <= 8) { 3991da177e4SLinus Torvalds unsigned int bytes = samples * width / 8; 4001da177e4SLinus Torvalds memset(data, *pat, bytes); 4011da177e4SLinus Torvalds return 0; 4021da177e4SLinus Torvalds } 4031da177e4SLinus Torvalds /* non-zero samples, fill using a loop */ 4041da177e4SLinus Torvalds width /= 8; 4051da177e4SLinus Torvalds dst = data; 4061da177e4SLinus Torvalds #if 0 4071da177e4SLinus Torvalds while (samples--) { 4081da177e4SLinus Torvalds memcpy(dst, pat, width); 4091da177e4SLinus Torvalds dst += width; 4101da177e4SLinus Torvalds } 4111da177e4SLinus Torvalds #else 4121da177e4SLinus Torvalds /* a bit optimization for constant width */ 4131da177e4SLinus Torvalds switch (width) { 4141da177e4SLinus Torvalds case 2: 4151da177e4SLinus Torvalds while (samples--) { 4161da177e4SLinus Torvalds memcpy(dst, pat, 2); 4171da177e4SLinus Torvalds dst += 2; 4181da177e4SLinus Torvalds } 4191da177e4SLinus Torvalds break; 4201da177e4SLinus Torvalds case 3: 4211da177e4SLinus Torvalds while (samples--) { 4221da177e4SLinus Torvalds memcpy(dst, pat, 3); 4231da177e4SLinus Torvalds dst += 3; 4241da177e4SLinus Torvalds } 4251da177e4SLinus Torvalds break; 4261da177e4SLinus Torvalds case 4: 4271da177e4SLinus Torvalds while (samples--) { 4281da177e4SLinus Torvalds memcpy(dst, pat, 4); 4291da177e4SLinus Torvalds dst += 4; 4301da177e4SLinus Torvalds } 4311da177e4SLinus Torvalds break; 4321da177e4SLinus Torvalds case 8: 4331da177e4SLinus Torvalds while (samples--) { 4341da177e4SLinus Torvalds memcpy(dst, pat, 8); 4351da177e4SLinus Torvalds dst += 8; 4361da177e4SLinus Torvalds } 4371da177e4SLinus Torvalds break; 4381da177e4SLinus Torvalds } 4391da177e4SLinus Torvalds #endif 4401da177e4SLinus Torvalds return 0; 4411da177e4SLinus Torvalds } 4421da177e4SLinus Torvalds 443e88e8ae6STakashi Iwai EXPORT_SYMBOL(snd_pcm_format_set_silence); 444e88e8ae6STakashi Iwai 4451da177e4SLinus Torvalds /** 4461da177e4SLinus Torvalds * snd_pcm_limit_hw_rates - determine rate_min/rate_max fields 4471da177e4SLinus Torvalds * @runtime: the runtime instance 4481da177e4SLinus Torvalds * 4491da177e4SLinus Torvalds * Determines the rate_min and rate_max fields from the rates bits of 4501da177e4SLinus Torvalds * the given runtime->hw. 4511da177e4SLinus Torvalds * 452*eb7c06e8SYacine Belkadi * Return: Zero if successful. 4531da177e4SLinus Torvalds */ 454877211f5STakashi Iwai int snd_pcm_limit_hw_rates(struct snd_pcm_runtime *runtime) 4551da177e4SLinus Torvalds { 4561da177e4SLinus Torvalds int i; 4577653d557SClemens Ladisch for (i = 0; i < (int)snd_pcm_known_rates.count; i++) { 4581da177e4SLinus Torvalds if (runtime->hw.rates & (1 << i)) { 4597653d557SClemens Ladisch runtime->hw.rate_min = snd_pcm_known_rates.list[i]; 4601da177e4SLinus Torvalds break; 4611da177e4SLinus Torvalds } 4621da177e4SLinus Torvalds } 4637653d557SClemens Ladisch for (i = (int)snd_pcm_known_rates.count - 1; i >= 0; i--) { 4641da177e4SLinus Torvalds if (runtime->hw.rates & (1 << i)) { 4657653d557SClemens Ladisch runtime->hw.rate_max = snd_pcm_known_rates.list[i]; 4661da177e4SLinus Torvalds break; 4671da177e4SLinus Torvalds } 4681da177e4SLinus Torvalds } 4691da177e4SLinus Torvalds return 0; 4701da177e4SLinus Torvalds } 471e88e8ae6STakashi Iwai 472e88e8ae6STakashi Iwai EXPORT_SYMBOL(snd_pcm_limit_hw_rates); 473918f3a0eSClemens Ladisch 474918f3a0eSClemens Ladisch /** 475918f3a0eSClemens Ladisch * snd_pcm_rate_to_rate_bit - converts sample rate to SNDRV_PCM_RATE_xxx bit 476918f3a0eSClemens Ladisch * @rate: the sample rate to convert 477918f3a0eSClemens Ladisch * 478*eb7c06e8SYacine Belkadi * Return: The SNDRV_PCM_RATE_xxx flag that corresponds to the given rate, or 479918f3a0eSClemens Ladisch * SNDRV_PCM_RATE_KNOT for an unknown rate. 480918f3a0eSClemens Ladisch */ 481918f3a0eSClemens Ladisch unsigned int snd_pcm_rate_to_rate_bit(unsigned int rate) 482918f3a0eSClemens Ladisch { 483918f3a0eSClemens Ladisch unsigned int i; 484918f3a0eSClemens Ladisch 485918f3a0eSClemens Ladisch for (i = 0; i < snd_pcm_known_rates.count; i++) 486918f3a0eSClemens Ladisch if (snd_pcm_known_rates.list[i] == rate) 487918f3a0eSClemens Ladisch return 1u << i; 488918f3a0eSClemens Ladisch return SNDRV_PCM_RATE_KNOT; 489918f3a0eSClemens Ladisch } 490918f3a0eSClemens Ladisch EXPORT_SYMBOL(snd_pcm_rate_to_rate_bit); 4914be77a53SDimitris Papastamos 4924be77a53SDimitris Papastamos /** 4934be77a53SDimitris Papastamos * snd_pcm_rate_bit_to_rate - converts SNDRV_PCM_RATE_xxx bit to sample rate 4944be77a53SDimitris Papastamos * @rate_bit: the rate bit to convert 4954be77a53SDimitris Papastamos * 496*eb7c06e8SYacine Belkadi * Return: The sample rate that corresponds to the given SNDRV_PCM_RATE_xxx flag 497*eb7c06e8SYacine Belkadi * or 0 for an unknown rate bit. 4984be77a53SDimitris Papastamos */ 4994be77a53SDimitris Papastamos unsigned int snd_pcm_rate_bit_to_rate(unsigned int rate_bit) 5004be77a53SDimitris Papastamos { 5014be77a53SDimitris Papastamos unsigned int i; 5024be77a53SDimitris Papastamos 5034be77a53SDimitris Papastamos for (i = 0; i < snd_pcm_known_rates.count; i++) 5044be77a53SDimitris Papastamos if ((1u << i) == rate_bit) 5054be77a53SDimitris Papastamos return snd_pcm_known_rates.list[i]; 5064be77a53SDimitris Papastamos return 0; 5074be77a53SDimitris Papastamos } 5084be77a53SDimitris Papastamos EXPORT_SYMBOL(snd_pcm_rate_bit_to_rate); 509