18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * PCM Interface - misc routines 38c2ecf20Sopenharmony_ci * Copyright (c) 1998 by Jaroslav Kysela <perex@perex.cz> 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This library is free software; you can redistribute it and/or modify 78c2ecf20Sopenharmony_ci * it under the terms of the GNU Library General Public License as 88c2ecf20Sopenharmony_ci * published by the Free Software Foundation; either version 2 of 98c2ecf20Sopenharmony_ci * the License, or (at your option) any later version. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful, 128c2ecf20Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 138c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 148c2ecf20Sopenharmony_ci * GNU Library General Public License for more details. 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * You should have received a copy of the GNU Library General Public 178c2ecf20Sopenharmony_ci * License along with this library; if not, write to the Free Software 188c2ecf20Sopenharmony_ci * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci */ 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include <linux/time.h> 238c2ecf20Sopenharmony_ci#include <linux/export.h> 248c2ecf20Sopenharmony_ci#include <sound/core.h> 258c2ecf20Sopenharmony_ci#include <sound/pcm.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#include "pcm_local.h" 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define SND_PCM_FORMAT_UNKNOWN (-1) 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/* NOTE: "signed" prefix must be given below since the default char is 328c2ecf20Sopenharmony_ci * unsigned on some architectures! 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_cistruct pcm_format_data { 358c2ecf20Sopenharmony_ci unsigned char width; /* bit width */ 368c2ecf20Sopenharmony_ci unsigned char phys; /* physical bit width */ 378c2ecf20Sopenharmony_ci signed char le; /* 0 = big-endian, 1 = little-endian, -1 = others */ 388c2ecf20Sopenharmony_ci signed char signd; /* 0 = unsigned, 1 = signed, -1 = others */ 398c2ecf20Sopenharmony_ci unsigned char silence[8]; /* silence data to fill */ 408c2ecf20Sopenharmony_ci}; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* we do lots of calculations on snd_pcm_format_t; shut up sparse */ 438c2ecf20Sopenharmony_ci#define INT __force int 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic bool valid_format(snd_pcm_format_t format) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci return (INT)format >= 0 && (INT)format <= (INT)SNDRV_PCM_FORMAT_LAST; 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic const struct pcm_format_data pcm_formats[(INT)SNDRV_PCM_FORMAT_LAST+1] = { 518c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_S8] = { 528c2ecf20Sopenharmony_ci .width = 8, .phys = 8, .le = -1, .signd = 1, 538c2ecf20Sopenharmony_ci .silence = {}, 548c2ecf20Sopenharmony_ci }, 558c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_U8] = { 568c2ecf20Sopenharmony_ci .width = 8, .phys = 8, .le = -1, .signd = 0, 578c2ecf20Sopenharmony_ci .silence = { 0x80 }, 588c2ecf20Sopenharmony_ci }, 598c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_S16_LE] = { 608c2ecf20Sopenharmony_ci .width = 16, .phys = 16, .le = 1, .signd = 1, 618c2ecf20Sopenharmony_ci .silence = {}, 628c2ecf20Sopenharmony_ci }, 638c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_S16_BE] = { 648c2ecf20Sopenharmony_ci .width = 16, .phys = 16, .le = 0, .signd = 1, 658c2ecf20Sopenharmony_ci .silence = {}, 668c2ecf20Sopenharmony_ci }, 678c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_U16_LE] = { 688c2ecf20Sopenharmony_ci .width = 16, .phys = 16, .le = 1, .signd = 0, 698c2ecf20Sopenharmony_ci .silence = { 0x00, 0x80 }, 708c2ecf20Sopenharmony_ci }, 718c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_U16_BE] = { 728c2ecf20Sopenharmony_ci .width = 16, .phys = 16, .le = 0, .signd = 0, 738c2ecf20Sopenharmony_ci .silence = { 0x80, 0x00 }, 748c2ecf20Sopenharmony_ci }, 758c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_S24_LE] = { 768c2ecf20Sopenharmony_ci .width = 24, .phys = 32, .le = 1, .signd = 1, 778c2ecf20Sopenharmony_ci .silence = {}, 788c2ecf20Sopenharmony_ci }, 798c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_S24_BE] = { 808c2ecf20Sopenharmony_ci .width = 24, .phys = 32, .le = 0, .signd = 1, 818c2ecf20Sopenharmony_ci .silence = {}, 828c2ecf20Sopenharmony_ci }, 838c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_U24_LE] = { 848c2ecf20Sopenharmony_ci .width = 24, .phys = 32, .le = 1, .signd = 0, 858c2ecf20Sopenharmony_ci .silence = { 0x00, 0x00, 0x80 }, 868c2ecf20Sopenharmony_ci }, 878c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_U24_BE] = { 888c2ecf20Sopenharmony_ci .width = 24, .phys = 32, .le = 0, .signd = 0, 898c2ecf20Sopenharmony_ci .silence = { 0x00, 0x80, 0x00, 0x00 }, 908c2ecf20Sopenharmony_ci }, 918c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_S32_LE] = { 928c2ecf20Sopenharmony_ci .width = 32, .phys = 32, .le = 1, .signd = 1, 938c2ecf20Sopenharmony_ci .silence = {}, 948c2ecf20Sopenharmony_ci }, 958c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_S32_BE] = { 968c2ecf20Sopenharmony_ci .width = 32, .phys = 32, .le = 0, .signd = 1, 978c2ecf20Sopenharmony_ci .silence = {}, 988c2ecf20Sopenharmony_ci }, 998c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_U32_LE] = { 1008c2ecf20Sopenharmony_ci .width = 32, .phys = 32, .le = 1, .signd = 0, 1018c2ecf20Sopenharmony_ci .silence = { 0x00, 0x00, 0x00, 0x80 }, 1028c2ecf20Sopenharmony_ci }, 1038c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_U32_BE] = { 1048c2ecf20Sopenharmony_ci .width = 32, .phys = 32, .le = 0, .signd = 0, 1058c2ecf20Sopenharmony_ci .silence = { 0x80, 0x00, 0x00, 0x00 }, 1068c2ecf20Sopenharmony_ci }, 1078c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_FLOAT_LE] = { 1088c2ecf20Sopenharmony_ci .width = 32, .phys = 32, .le = 1, .signd = -1, 1098c2ecf20Sopenharmony_ci .silence = {}, 1108c2ecf20Sopenharmony_ci }, 1118c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_FLOAT_BE] = { 1128c2ecf20Sopenharmony_ci .width = 32, .phys = 32, .le = 0, .signd = -1, 1138c2ecf20Sopenharmony_ci .silence = {}, 1148c2ecf20Sopenharmony_ci }, 1158c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_FLOAT64_LE] = { 1168c2ecf20Sopenharmony_ci .width = 64, .phys = 64, .le = 1, .signd = -1, 1178c2ecf20Sopenharmony_ci .silence = {}, 1188c2ecf20Sopenharmony_ci }, 1198c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_FLOAT64_BE] = { 1208c2ecf20Sopenharmony_ci .width = 64, .phys = 64, .le = 0, .signd = -1, 1218c2ecf20Sopenharmony_ci .silence = {}, 1228c2ecf20Sopenharmony_ci }, 1238c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE] = { 1248c2ecf20Sopenharmony_ci .width = 32, .phys = 32, .le = 1, .signd = -1, 1258c2ecf20Sopenharmony_ci .silence = {}, 1268c2ecf20Sopenharmony_ci }, 1278c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE] = { 1288c2ecf20Sopenharmony_ci .width = 32, .phys = 32, .le = 0, .signd = -1, 1298c2ecf20Sopenharmony_ci .silence = {}, 1308c2ecf20Sopenharmony_ci }, 1318c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_MU_LAW] = { 1328c2ecf20Sopenharmony_ci .width = 8, .phys = 8, .le = -1, .signd = -1, 1338c2ecf20Sopenharmony_ci .silence = { 0x7f }, 1348c2ecf20Sopenharmony_ci }, 1358c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_A_LAW] = { 1368c2ecf20Sopenharmony_ci .width = 8, .phys = 8, .le = -1, .signd = -1, 1378c2ecf20Sopenharmony_ci .silence = { 0x55 }, 1388c2ecf20Sopenharmony_ci }, 1398c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_IMA_ADPCM] = { 1408c2ecf20Sopenharmony_ci .width = 4, .phys = 4, .le = -1, .signd = -1, 1418c2ecf20Sopenharmony_ci .silence = {}, 1428c2ecf20Sopenharmony_ci }, 1438c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_G723_24] = { 1448c2ecf20Sopenharmony_ci .width = 3, .phys = 3, .le = -1, .signd = -1, 1458c2ecf20Sopenharmony_ci .silence = {}, 1468c2ecf20Sopenharmony_ci }, 1478c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_G723_40] = { 1488c2ecf20Sopenharmony_ci .width = 5, .phys = 5, .le = -1, .signd = -1, 1498c2ecf20Sopenharmony_ci .silence = {}, 1508c2ecf20Sopenharmony_ci }, 1518c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_DSD_U8] = { 1528c2ecf20Sopenharmony_ci .width = 8, .phys = 8, .le = 1, .signd = 0, 1538c2ecf20Sopenharmony_ci .silence = { 0x69 }, 1548c2ecf20Sopenharmony_ci }, 1558c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_DSD_U16_LE] = { 1568c2ecf20Sopenharmony_ci .width = 16, .phys = 16, .le = 1, .signd = 0, 1578c2ecf20Sopenharmony_ci .silence = { 0x69, 0x69 }, 1588c2ecf20Sopenharmony_ci }, 1598c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_DSD_U32_LE] = { 1608c2ecf20Sopenharmony_ci .width = 32, .phys = 32, .le = 1, .signd = 0, 1618c2ecf20Sopenharmony_ci .silence = { 0x69, 0x69, 0x69, 0x69 }, 1628c2ecf20Sopenharmony_ci }, 1638c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_DSD_U16_BE] = { 1648c2ecf20Sopenharmony_ci .width = 16, .phys = 16, .le = 0, .signd = 0, 1658c2ecf20Sopenharmony_ci .silence = { 0x69, 0x69 }, 1668c2ecf20Sopenharmony_ci }, 1678c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_DSD_U32_BE] = { 1688c2ecf20Sopenharmony_ci .width = 32, .phys = 32, .le = 0, .signd = 0, 1698c2ecf20Sopenharmony_ci .silence = { 0x69, 0x69, 0x69, 0x69 }, 1708c2ecf20Sopenharmony_ci }, 1718c2ecf20Sopenharmony_ci /* FIXME: the following two formats are not defined properly yet */ 1728c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_MPEG] = { 1738c2ecf20Sopenharmony_ci .le = -1, .signd = -1, 1748c2ecf20Sopenharmony_ci }, 1758c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_GSM] = { 1768c2ecf20Sopenharmony_ci .le = -1, .signd = -1, 1778c2ecf20Sopenharmony_ci }, 1788c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_S20_LE] = { 1798c2ecf20Sopenharmony_ci .width = 20, .phys = 32, .le = 1, .signd = 1, 1808c2ecf20Sopenharmony_ci .silence = {}, 1818c2ecf20Sopenharmony_ci }, 1828c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_S20_BE] = { 1838c2ecf20Sopenharmony_ci .width = 20, .phys = 32, .le = 0, .signd = 1, 1848c2ecf20Sopenharmony_ci .silence = {}, 1858c2ecf20Sopenharmony_ci }, 1868c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_U20_LE] = { 1878c2ecf20Sopenharmony_ci .width = 20, .phys = 32, .le = 1, .signd = 0, 1888c2ecf20Sopenharmony_ci .silence = { 0x00, 0x00, 0x08, 0x00 }, 1898c2ecf20Sopenharmony_ci }, 1908c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_U20_BE] = { 1918c2ecf20Sopenharmony_ci .width = 20, .phys = 32, .le = 0, .signd = 0, 1928c2ecf20Sopenharmony_ci .silence = { 0x00, 0x08, 0x00, 0x00 }, 1938c2ecf20Sopenharmony_ci }, 1948c2ecf20Sopenharmony_ci /* FIXME: the following format is not defined properly yet */ 1958c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_SPECIAL] = { 1968c2ecf20Sopenharmony_ci .le = -1, .signd = -1, 1978c2ecf20Sopenharmony_ci }, 1988c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_S24_3LE] = { 1998c2ecf20Sopenharmony_ci .width = 24, .phys = 24, .le = 1, .signd = 1, 2008c2ecf20Sopenharmony_ci .silence = {}, 2018c2ecf20Sopenharmony_ci }, 2028c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_S24_3BE] = { 2038c2ecf20Sopenharmony_ci .width = 24, .phys = 24, .le = 0, .signd = 1, 2048c2ecf20Sopenharmony_ci .silence = {}, 2058c2ecf20Sopenharmony_ci }, 2068c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_U24_3LE] = { 2078c2ecf20Sopenharmony_ci .width = 24, .phys = 24, .le = 1, .signd = 0, 2088c2ecf20Sopenharmony_ci .silence = { 0x00, 0x00, 0x80 }, 2098c2ecf20Sopenharmony_ci }, 2108c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_U24_3BE] = { 2118c2ecf20Sopenharmony_ci .width = 24, .phys = 24, .le = 0, .signd = 0, 2128c2ecf20Sopenharmony_ci .silence = { 0x80, 0x00, 0x00 }, 2138c2ecf20Sopenharmony_ci }, 2148c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_S20_3LE] = { 2158c2ecf20Sopenharmony_ci .width = 20, .phys = 24, .le = 1, .signd = 1, 2168c2ecf20Sopenharmony_ci .silence = {}, 2178c2ecf20Sopenharmony_ci }, 2188c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_S20_3BE] = { 2198c2ecf20Sopenharmony_ci .width = 20, .phys = 24, .le = 0, .signd = 1, 2208c2ecf20Sopenharmony_ci .silence = {}, 2218c2ecf20Sopenharmony_ci }, 2228c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_U20_3LE] = { 2238c2ecf20Sopenharmony_ci .width = 20, .phys = 24, .le = 1, .signd = 0, 2248c2ecf20Sopenharmony_ci .silence = { 0x00, 0x00, 0x08 }, 2258c2ecf20Sopenharmony_ci }, 2268c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_U20_3BE] = { 2278c2ecf20Sopenharmony_ci .width = 20, .phys = 24, .le = 0, .signd = 0, 2288c2ecf20Sopenharmony_ci .silence = { 0x08, 0x00, 0x00 }, 2298c2ecf20Sopenharmony_ci }, 2308c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_S18_3LE] = { 2318c2ecf20Sopenharmony_ci .width = 18, .phys = 24, .le = 1, .signd = 1, 2328c2ecf20Sopenharmony_ci .silence = {}, 2338c2ecf20Sopenharmony_ci }, 2348c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_S18_3BE] = { 2358c2ecf20Sopenharmony_ci .width = 18, .phys = 24, .le = 0, .signd = 1, 2368c2ecf20Sopenharmony_ci .silence = {}, 2378c2ecf20Sopenharmony_ci }, 2388c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_U18_3LE] = { 2398c2ecf20Sopenharmony_ci .width = 18, .phys = 24, .le = 1, .signd = 0, 2408c2ecf20Sopenharmony_ci .silence = { 0x00, 0x00, 0x02 }, 2418c2ecf20Sopenharmony_ci }, 2428c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_U18_3BE] = { 2438c2ecf20Sopenharmony_ci .width = 18, .phys = 24, .le = 0, .signd = 0, 2448c2ecf20Sopenharmony_ci .silence = { 0x02, 0x00, 0x00 }, 2458c2ecf20Sopenharmony_ci }, 2468c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_G723_24_1B] = { 2478c2ecf20Sopenharmony_ci .width = 3, .phys = 8, .le = -1, .signd = -1, 2488c2ecf20Sopenharmony_ci .silence = {}, 2498c2ecf20Sopenharmony_ci }, 2508c2ecf20Sopenharmony_ci [SNDRV_PCM_FORMAT_G723_40_1B] = { 2518c2ecf20Sopenharmony_ci .width = 5, .phys = 8, .le = -1, .signd = -1, 2528c2ecf20Sopenharmony_ci .silence = {}, 2538c2ecf20Sopenharmony_ci }, 2548c2ecf20Sopenharmony_ci}; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci/** 2588c2ecf20Sopenharmony_ci * snd_pcm_format_signed - Check the PCM format is signed linear 2598c2ecf20Sopenharmony_ci * @format: the format to check 2608c2ecf20Sopenharmony_ci * 2618c2ecf20Sopenharmony_ci * Return: 1 if the given PCM format is signed linear, 0 if unsigned 2628c2ecf20Sopenharmony_ci * linear, and a negative error code for non-linear formats. 2638c2ecf20Sopenharmony_ci */ 2648c2ecf20Sopenharmony_ciint snd_pcm_format_signed(snd_pcm_format_t format) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci int val; 2678c2ecf20Sopenharmony_ci if (!valid_format(format)) 2688c2ecf20Sopenharmony_ci return -EINVAL; 2698c2ecf20Sopenharmony_ci if ((val = pcm_formats[(INT)format].signd) < 0) 2708c2ecf20Sopenharmony_ci return -EINVAL; 2718c2ecf20Sopenharmony_ci return val; 2728c2ecf20Sopenharmony_ci} 2738c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_pcm_format_signed); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci/** 2768c2ecf20Sopenharmony_ci * snd_pcm_format_unsigned - Check the PCM format is unsigned linear 2778c2ecf20Sopenharmony_ci * @format: the format to check 2788c2ecf20Sopenharmony_ci * 2798c2ecf20Sopenharmony_ci * Return: 1 if the given PCM format is unsigned linear, 0 if signed 2808c2ecf20Sopenharmony_ci * linear, and a negative error code for non-linear formats. 2818c2ecf20Sopenharmony_ci */ 2828c2ecf20Sopenharmony_ciint snd_pcm_format_unsigned(snd_pcm_format_t format) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci int val; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci val = snd_pcm_format_signed(format); 2878c2ecf20Sopenharmony_ci if (val < 0) 2888c2ecf20Sopenharmony_ci return val; 2898c2ecf20Sopenharmony_ci return !val; 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_pcm_format_unsigned); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci/** 2948c2ecf20Sopenharmony_ci * snd_pcm_format_linear - Check the PCM format is linear 2958c2ecf20Sopenharmony_ci * @format: the format to check 2968c2ecf20Sopenharmony_ci * 2978c2ecf20Sopenharmony_ci * Return: 1 if the given PCM format is linear, 0 if not. 2988c2ecf20Sopenharmony_ci */ 2998c2ecf20Sopenharmony_ciint snd_pcm_format_linear(snd_pcm_format_t format) 3008c2ecf20Sopenharmony_ci{ 3018c2ecf20Sopenharmony_ci return snd_pcm_format_signed(format) >= 0; 3028c2ecf20Sopenharmony_ci} 3038c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_pcm_format_linear); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci/** 3068c2ecf20Sopenharmony_ci * snd_pcm_format_little_endian - Check the PCM format is little-endian 3078c2ecf20Sopenharmony_ci * @format: the format to check 3088c2ecf20Sopenharmony_ci * 3098c2ecf20Sopenharmony_ci * Return: 1 if the given PCM format is little-endian, 0 if 3108c2ecf20Sopenharmony_ci * big-endian, or a negative error code if endian not specified. 3118c2ecf20Sopenharmony_ci */ 3128c2ecf20Sopenharmony_ciint snd_pcm_format_little_endian(snd_pcm_format_t format) 3138c2ecf20Sopenharmony_ci{ 3148c2ecf20Sopenharmony_ci int val; 3158c2ecf20Sopenharmony_ci if (!valid_format(format)) 3168c2ecf20Sopenharmony_ci return -EINVAL; 3178c2ecf20Sopenharmony_ci if ((val = pcm_formats[(INT)format].le) < 0) 3188c2ecf20Sopenharmony_ci return -EINVAL; 3198c2ecf20Sopenharmony_ci return val; 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_pcm_format_little_endian); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci/** 3248c2ecf20Sopenharmony_ci * snd_pcm_format_big_endian - Check the PCM format is big-endian 3258c2ecf20Sopenharmony_ci * @format: the format to check 3268c2ecf20Sopenharmony_ci * 3278c2ecf20Sopenharmony_ci * Return: 1 if the given PCM format is big-endian, 0 if 3288c2ecf20Sopenharmony_ci * little-endian, or a negative error code if endian not specified. 3298c2ecf20Sopenharmony_ci */ 3308c2ecf20Sopenharmony_ciint snd_pcm_format_big_endian(snd_pcm_format_t format) 3318c2ecf20Sopenharmony_ci{ 3328c2ecf20Sopenharmony_ci int val; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci val = snd_pcm_format_little_endian(format); 3358c2ecf20Sopenharmony_ci if (val < 0) 3368c2ecf20Sopenharmony_ci return val; 3378c2ecf20Sopenharmony_ci return !val; 3388c2ecf20Sopenharmony_ci} 3398c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_pcm_format_big_endian); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci/** 3428c2ecf20Sopenharmony_ci * snd_pcm_format_width - return the bit-width of the format 3438c2ecf20Sopenharmony_ci * @format: the format to check 3448c2ecf20Sopenharmony_ci * 3458c2ecf20Sopenharmony_ci * Return: The bit-width of the format, or a negative error code 3468c2ecf20Sopenharmony_ci * if unknown format. 3478c2ecf20Sopenharmony_ci */ 3488c2ecf20Sopenharmony_ciint snd_pcm_format_width(snd_pcm_format_t format) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci int val; 3518c2ecf20Sopenharmony_ci if (!valid_format(format)) 3528c2ecf20Sopenharmony_ci return -EINVAL; 3538c2ecf20Sopenharmony_ci if ((val = pcm_formats[(INT)format].width) == 0) 3548c2ecf20Sopenharmony_ci return -EINVAL; 3558c2ecf20Sopenharmony_ci return val; 3568c2ecf20Sopenharmony_ci} 3578c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_pcm_format_width); 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci/** 3608c2ecf20Sopenharmony_ci * snd_pcm_format_physical_width - return the physical bit-width of the format 3618c2ecf20Sopenharmony_ci * @format: the format to check 3628c2ecf20Sopenharmony_ci * 3638c2ecf20Sopenharmony_ci * Return: The physical bit-width of the format, or a negative error code 3648c2ecf20Sopenharmony_ci * if unknown format. 3658c2ecf20Sopenharmony_ci */ 3668c2ecf20Sopenharmony_ciint snd_pcm_format_physical_width(snd_pcm_format_t format) 3678c2ecf20Sopenharmony_ci{ 3688c2ecf20Sopenharmony_ci int val; 3698c2ecf20Sopenharmony_ci if (!valid_format(format)) 3708c2ecf20Sopenharmony_ci return -EINVAL; 3718c2ecf20Sopenharmony_ci if ((val = pcm_formats[(INT)format].phys) == 0) 3728c2ecf20Sopenharmony_ci return -EINVAL; 3738c2ecf20Sopenharmony_ci return val; 3748c2ecf20Sopenharmony_ci} 3758c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_pcm_format_physical_width); 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci/** 3788c2ecf20Sopenharmony_ci * snd_pcm_format_size - return the byte size of samples on the given format 3798c2ecf20Sopenharmony_ci * @format: the format to check 3808c2ecf20Sopenharmony_ci * @samples: sampling rate 3818c2ecf20Sopenharmony_ci * 3828c2ecf20Sopenharmony_ci * Return: The byte size of the given samples for the format, or a 3838c2ecf20Sopenharmony_ci * negative error code if unknown format. 3848c2ecf20Sopenharmony_ci */ 3858c2ecf20Sopenharmony_cissize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples) 3868c2ecf20Sopenharmony_ci{ 3878c2ecf20Sopenharmony_ci int phys_width = snd_pcm_format_physical_width(format); 3888c2ecf20Sopenharmony_ci if (phys_width < 0) 3898c2ecf20Sopenharmony_ci return -EINVAL; 3908c2ecf20Sopenharmony_ci return samples * phys_width / 8; 3918c2ecf20Sopenharmony_ci} 3928c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_pcm_format_size); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci/** 3958c2ecf20Sopenharmony_ci * snd_pcm_format_silence_64 - return the silent data in 8 bytes array 3968c2ecf20Sopenharmony_ci * @format: the format to check 3978c2ecf20Sopenharmony_ci * 3988c2ecf20Sopenharmony_ci * Return: The format pattern to fill or %NULL if error. 3998c2ecf20Sopenharmony_ci */ 4008c2ecf20Sopenharmony_ciconst unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format) 4018c2ecf20Sopenharmony_ci{ 4028c2ecf20Sopenharmony_ci if (!valid_format(format)) 4038c2ecf20Sopenharmony_ci return NULL; 4048c2ecf20Sopenharmony_ci if (! pcm_formats[(INT)format].phys) 4058c2ecf20Sopenharmony_ci return NULL; 4068c2ecf20Sopenharmony_ci return pcm_formats[(INT)format].silence; 4078c2ecf20Sopenharmony_ci} 4088c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_pcm_format_silence_64); 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci/** 4118c2ecf20Sopenharmony_ci * snd_pcm_format_set_silence - set the silence data on the buffer 4128c2ecf20Sopenharmony_ci * @format: the PCM format 4138c2ecf20Sopenharmony_ci * @data: the buffer pointer 4148c2ecf20Sopenharmony_ci * @samples: the number of samples to set silence 4158c2ecf20Sopenharmony_ci * 4168c2ecf20Sopenharmony_ci * Sets the silence data on the buffer for the given samples. 4178c2ecf20Sopenharmony_ci * 4188c2ecf20Sopenharmony_ci * Return: Zero if successful, or a negative error code on failure. 4198c2ecf20Sopenharmony_ci */ 4208c2ecf20Sopenharmony_ciint snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int samples) 4218c2ecf20Sopenharmony_ci{ 4228c2ecf20Sopenharmony_ci int width; 4238c2ecf20Sopenharmony_ci unsigned char *dst; 4248c2ecf20Sopenharmony_ci const unsigned char *pat; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci if (!valid_format(format)) 4278c2ecf20Sopenharmony_ci return -EINVAL; 4288c2ecf20Sopenharmony_ci if (samples == 0) 4298c2ecf20Sopenharmony_ci return 0; 4308c2ecf20Sopenharmony_ci width = pcm_formats[(INT)format].phys; /* physical width */ 4318c2ecf20Sopenharmony_ci pat = pcm_formats[(INT)format].silence; 4328c2ecf20Sopenharmony_ci if (!width || !pat) 4338c2ecf20Sopenharmony_ci return -EINVAL; 4348c2ecf20Sopenharmony_ci /* signed or 1 byte data */ 4358c2ecf20Sopenharmony_ci if (pcm_formats[(INT)format].signd == 1 || width <= 8) { 4368c2ecf20Sopenharmony_ci unsigned int bytes = samples * width / 8; 4378c2ecf20Sopenharmony_ci memset(data, *pat, bytes); 4388c2ecf20Sopenharmony_ci return 0; 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci /* non-zero samples, fill using a loop */ 4418c2ecf20Sopenharmony_ci width /= 8; 4428c2ecf20Sopenharmony_ci dst = data; 4438c2ecf20Sopenharmony_ci#if 0 4448c2ecf20Sopenharmony_ci while (samples--) { 4458c2ecf20Sopenharmony_ci memcpy(dst, pat, width); 4468c2ecf20Sopenharmony_ci dst += width; 4478c2ecf20Sopenharmony_ci } 4488c2ecf20Sopenharmony_ci#else 4498c2ecf20Sopenharmony_ci /* a bit optimization for constant width */ 4508c2ecf20Sopenharmony_ci switch (width) { 4518c2ecf20Sopenharmony_ci case 2: 4528c2ecf20Sopenharmony_ci while (samples--) { 4538c2ecf20Sopenharmony_ci memcpy(dst, pat, 2); 4548c2ecf20Sopenharmony_ci dst += 2; 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci break; 4578c2ecf20Sopenharmony_ci case 3: 4588c2ecf20Sopenharmony_ci while (samples--) { 4598c2ecf20Sopenharmony_ci memcpy(dst, pat, 3); 4608c2ecf20Sopenharmony_ci dst += 3; 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci break; 4638c2ecf20Sopenharmony_ci case 4: 4648c2ecf20Sopenharmony_ci while (samples--) { 4658c2ecf20Sopenharmony_ci memcpy(dst, pat, 4); 4668c2ecf20Sopenharmony_ci dst += 4; 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci break; 4698c2ecf20Sopenharmony_ci case 8: 4708c2ecf20Sopenharmony_ci while (samples--) { 4718c2ecf20Sopenharmony_ci memcpy(dst, pat, 8); 4728c2ecf20Sopenharmony_ci dst += 8; 4738c2ecf20Sopenharmony_ci } 4748c2ecf20Sopenharmony_ci break; 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci#endif 4778c2ecf20Sopenharmony_ci return 0; 4788c2ecf20Sopenharmony_ci} 4798c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_pcm_format_set_silence); 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci/** 4828c2ecf20Sopenharmony_ci * snd_pcm_hw_limit_rates - determine rate_min/rate_max fields 4838c2ecf20Sopenharmony_ci * @hw: the pcm hw instance 4848c2ecf20Sopenharmony_ci * 4858c2ecf20Sopenharmony_ci * Determines the rate_min and rate_max fields from the rates bits of 4868c2ecf20Sopenharmony_ci * the given hw. 4878c2ecf20Sopenharmony_ci * 4888c2ecf20Sopenharmony_ci * Return: Zero if successful. 4898c2ecf20Sopenharmony_ci */ 4908c2ecf20Sopenharmony_ciint snd_pcm_hw_limit_rates(struct snd_pcm_hardware *hw) 4918c2ecf20Sopenharmony_ci{ 4928c2ecf20Sopenharmony_ci int i; 4938c2ecf20Sopenharmony_ci for (i = 0; i < (int)snd_pcm_known_rates.count; i++) { 4948c2ecf20Sopenharmony_ci if (hw->rates & (1 << i)) { 4958c2ecf20Sopenharmony_ci hw->rate_min = snd_pcm_known_rates.list[i]; 4968c2ecf20Sopenharmony_ci break; 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ci } 4998c2ecf20Sopenharmony_ci for (i = (int)snd_pcm_known_rates.count - 1; i >= 0; i--) { 5008c2ecf20Sopenharmony_ci if (hw->rates & (1 << i)) { 5018c2ecf20Sopenharmony_ci hw->rate_max = snd_pcm_known_rates.list[i]; 5028c2ecf20Sopenharmony_ci break; 5038c2ecf20Sopenharmony_ci } 5048c2ecf20Sopenharmony_ci } 5058c2ecf20Sopenharmony_ci return 0; 5068c2ecf20Sopenharmony_ci} 5078c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_pcm_hw_limit_rates); 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci/** 5108c2ecf20Sopenharmony_ci * snd_pcm_rate_to_rate_bit - converts sample rate to SNDRV_PCM_RATE_xxx bit 5118c2ecf20Sopenharmony_ci * @rate: the sample rate to convert 5128c2ecf20Sopenharmony_ci * 5138c2ecf20Sopenharmony_ci * Return: The SNDRV_PCM_RATE_xxx flag that corresponds to the given rate, or 5148c2ecf20Sopenharmony_ci * SNDRV_PCM_RATE_KNOT for an unknown rate. 5158c2ecf20Sopenharmony_ci */ 5168c2ecf20Sopenharmony_ciunsigned int snd_pcm_rate_to_rate_bit(unsigned int rate) 5178c2ecf20Sopenharmony_ci{ 5188c2ecf20Sopenharmony_ci unsigned int i; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci for (i = 0; i < snd_pcm_known_rates.count; i++) 5218c2ecf20Sopenharmony_ci if (snd_pcm_known_rates.list[i] == rate) 5228c2ecf20Sopenharmony_ci return 1u << i; 5238c2ecf20Sopenharmony_ci return SNDRV_PCM_RATE_KNOT; 5248c2ecf20Sopenharmony_ci} 5258c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_pcm_rate_to_rate_bit); 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci/** 5288c2ecf20Sopenharmony_ci * snd_pcm_rate_bit_to_rate - converts SNDRV_PCM_RATE_xxx bit to sample rate 5298c2ecf20Sopenharmony_ci * @rate_bit: the rate bit to convert 5308c2ecf20Sopenharmony_ci * 5318c2ecf20Sopenharmony_ci * Return: The sample rate that corresponds to the given SNDRV_PCM_RATE_xxx flag 5328c2ecf20Sopenharmony_ci * or 0 for an unknown rate bit. 5338c2ecf20Sopenharmony_ci */ 5348c2ecf20Sopenharmony_ciunsigned int snd_pcm_rate_bit_to_rate(unsigned int rate_bit) 5358c2ecf20Sopenharmony_ci{ 5368c2ecf20Sopenharmony_ci unsigned int i; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci for (i = 0; i < snd_pcm_known_rates.count; i++) 5398c2ecf20Sopenharmony_ci if ((1u << i) == rate_bit) 5408c2ecf20Sopenharmony_ci return snd_pcm_known_rates.list[i]; 5418c2ecf20Sopenharmony_ci return 0; 5428c2ecf20Sopenharmony_ci} 5438c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_pcm_rate_bit_to_rate); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_cistatic unsigned int snd_pcm_rate_mask_sanitize(unsigned int rates) 5468c2ecf20Sopenharmony_ci{ 5478c2ecf20Sopenharmony_ci if (rates & SNDRV_PCM_RATE_CONTINUOUS) 5488c2ecf20Sopenharmony_ci return SNDRV_PCM_RATE_CONTINUOUS; 5498c2ecf20Sopenharmony_ci else if (rates & SNDRV_PCM_RATE_KNOT) 5508c2ecf20Sopenharmony_ci return SNDRV_PCM_RATE_KNOT; 5518c2ecf20Sopenharmony_ci return rates; 5528c2ecf20Sopenharmony_ci} 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci/** 5558c2ecf20Sopenharmony_ci * snd_pcm_rate_mask_intersect - computes the intersection between two rate masks 5568c2ecf20Sopenharmony_ci * @rates_a: The first rate mask 5578c2ecf20Sopenharmony_ci * @rates_b: The second rate mask 5588c2ecf20Sopenharmony_ci * 5598c2ecf20Sopenharmony_ci * This function computes the rates that are supported by both rate masks passed 5608c2ecf20Sopenharmony_ci * to the function. It will take care of the special handling of 5618c2ecf20Sopenharmony_ci * SNDRV_PCM_RATE_CONTINUOUS and SNDRV_PCM_RATE_KNOT. 5628c2ecf20Sopenharmony_ci * 5638c2ecf20Sopenharmony_ci * Return: A rate mask containing the rates that are supported by both rates_a 5648c2ecf20Sopenharmony_ci * and rates_b. 5658c2ecf20Sopenharmony_ci */ 5668c2ecf20Sopenharmony_ciunsigned int snd_pcm_rate_mask_intersect(unsigned int rates_a, 5678c2ecf20Sopenharmony_ci unsigned int rates_b) 5688c2ecf20Sopenharmony_ci{ 5698c2ecf20Sopenharmony_ci rates_a = snd_pcm_rate_mask_sanitize(rates_a); 5708c2ecf20Sopenharmony_ci rates_b = snd_pcm_rate_mask_sanitize(rates_b); 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci if (rates_a & SNDRV_PCM_RATE_CONTINUOUS) 5738c2ecf20Sopenharmony_ci return rates_b; 5748c2ecf20Sopenharmony_ci else if (rates_b & SNDRV_PCM_RATE_CONTINUOUS) 5758c2ecf20Sopenharmony_ci return rates_a; 5768c2ecf20Sopenharmony_ci else if (rates_a & SNDRV_PCM_RATE_KNOT) 5778c2ecf20Sopenharmony_ci return rates_b; 5788c2ecf20Sopenharmony_ci else if (rates_b & SNDRV_PCM_RATE_KNOT) 5798c2ecf20Sopenharmony_ci return rates_a; 5808c2ecf20Sopenharmony_ci return rates_a & rates_b; 5818c2ecf20Sopenharmony_ci} 5828c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_pcm_rate_mask_intersect); 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci/** 5858c2ecf20Sopenharmony_ci * snd_pcm_rate_range_to_bits - converts rate range to SNDRV_PCM_RATE_xxx bit 5868c2ecf20Sopenharmony_ci * @rate_min: the minimum sample rate 5878c2ecf20Sopenharmony_ci * @rate_max: the maximum sample rate 5888c2ecf20Sopenharmony_ci * 5898c2ecf20Sopenharmony_ci * This function has an implicit assumption: the rates in the given range have 5908c2ecf20Sopenharmony_ci * only the pre-defined rates like 44100 or 16000. 5918c2ecf20Sopenharmony_ci * 5928c2ecf20Sopenharmony_ci * Return: The SNDRV_PCM_RATE_xxx flag that corresponds to the given rate range, 5938c2ecf20Sopenharmony_ci * or SNDRV_PCM_RATE_KNOT for an unknown range. 5948c2ecf20Sopenharmony_ci */ 5958c2ecf20Sopenharmony_ciunsigned int snd_pcm_rate_range_to_bits(unsigned int rate_min, 5968c2ecf20Sopenharmony_ci unsigned int rate_max) 5978c2ecf20Sopenharmony_ci{ 5988c2ecf20Sopenharmony_ci unsigned int rates = 0; 5998c2ecf20Sopenharmony_ci int i; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci for (i = 0; i < snd_pcm_known_rates.count; i++) { 6028c2ecf20Sopenharmony_ci if (snd_pcm_known_rates.list[i] >= rate_min 6038c2ecf20Sopenharmony_ci && snd_pcm_known_rates.list[i] <= rate_max) 6048c2ecf20Sopenharmony_ci rates |= 1 << i; 6058c2ecf20Sopenharmony_ci } 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci if (!rates) 6088c2ecf20Sopenharmony_ci rates = SNDRV_PCM_RATE_KNOT; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci return rates; 6118c2ecf20Sopenharmony_ci} 6128c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_pcm_rate_range_to_bits); 613