1*1da177e4SLinus Torvalds /* 2*1da177e4SLinus Torvalds * PCM Interface - misc routines 3*1da177e4SLinus Torvalds * Copyright (c) 1998 by Jaroslav Kysela <perex@suse.cz> 4*1da177e4SLinus Torvalds * 5*1da177e4SLinus Torvalds * 6*1da177e4SLinus Torvalds * This library is free software; you can redistribute it and/or modify 7*1da177e4SLinus Torvalds * it under the terms of the GNU Library General Public License as 8*1da177e4SLinus Torvalds * published by the Free Software Foundation; either version 2 of 9*1da177e4SLinus Torvalds * the License, or (at your option) any later version. 10*1da177e4SLinus Torvalds * 11*1da177e4SLinus Torvalds * This program is distributed in the hope that it will be useful, 12*1da177e4SLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 13*1da177e4SLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14*1da177e4SLinus Torvalds * GNU Library General Public License for more details. 15*1da177e4SLinus Torvalds * 16*1da177e4SLinus Torvalds * You should have received a copy of the GNU Library General Public 17*1da177e4SLinus Torvalds * License along with this library; if not, write to the Free Software 18*1da177e4SLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19*1da177e4SLinus Torvalds * 20*1da177e4SLinus Torvalds */ 21*1da177e4SLinus Torvalds 22*1da177e4SLinus Torvalds #include <sound/driver.h> 23*1da177e4SLinus Torvalds #include <linux/time.h> 24*1da177e4SLinus Torvalds #include <sound/core.h> 25*1da177e4SLinus Torvalds #include <sound/pcm.h> 26*1da177e4SLinus Torvalds #define SND_PCM_FORMAT_UNKNOWN (-1) 27*1da177e4SLinus Torvalds 28*1da177e4SLinus Torvalds /* NOTE: "signed" prefix must be given below since the default char is 29*1da177e4SLinus Torvalds * unsigned on some architectures! 30*1da177e4SLinus Torvalds */ 31*1da177e4SLinus Torvalds struct pcm_format_data { 32*1da177e4SLinus Torvalds unsigned char width; /* bit width */ 33*1da177e4SLinus Torvalds unsigned char phys; /* physical bit width */ 34*1da177e4SLinus Torvalds signed char le; /* 0 = big-endian, 1 = little-endian, -1 = others */ 35*1da177e4SLinus Torvalds signed char signd; /* 0 = unsigned, 1 = signed, -1 = others */ 36*1da177e4SLinus Torvalds unsigned char silence[8]; /* silence data to fill */ 37*1da177e4SLinus Torvalds }; 38*1da177e4SLinus Torvalds 39*1da177e4SLinus Torvalds static struct pcm_format_data pcm_formats[SNDRV_PCM_FORMAT_LAST+1] = { 40*1da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_S8] = { 41*1da177e4SLinus Torvalds .width = 8, .phys = 8, .le = -1, .signd = 1, 42*1da177e4SLinus Torvalds .silence = {}, 43*1da177e4SLinus Torvalds }, 44*1da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_U8] = { 45*1da177e4SLinus Torvalds .width = 8, .phys = 8, .le = -1, .signd = 0, 46*1da177e4SLinus Torvalds .silence = { 0x80 }, 47*1da177e4SLinus Torvalds }, 48*1da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_S16_LE] = { 49*1da177e4SLinus Torvalds .width = 16, .phys = 16, .le = 1, .signd = 1, 50*1da177e4SLinus Torvalds .silence = {}, 51*1da177e4SLinus Torvalds }, 52*1da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_S16_BE] = { 53*1da177e4SLinus Torvalds .width = 16, .phys = 16, .le = 0, .signd = 1, 54*1da177e4SLinus Torvalds .silence = {}, 55*1da177e4SLinus Torvalds }, 56*1da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_U16_LE] = { 57*1da177e4SLinus Torvalds .width = 16, .phys = 16, .le = 1, .signd = 0, 58*1da177e4SLinus Torvalds .silence = { 0x00, 0x80 }, 59*1da177e4SLinus Torvalds }, 60*1da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_U16_BE] = { 61*1da177e4SLinus Torvalds .width = 16, .phys = 16, .le = 0, .signd = 0, 62*1da177e4SLinus Torvalds .silence = { 0x80, 0x00 }, 63*1da177e4SLinus Torvalds }, 64*1da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_S24_LE] = { 65*1da177e4SLinus Torvalds .width = 24, .phys = 32, .le = 1, .signd = 1, 66*1da177e4SLinus Torvalds .silence = {}, 67*1da177e4SLinus Torvalds }, 68*1da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_S24_BE] = { 69*1da177e4SLinus Torvalds .width = 24, .phys = 32, .le = 0, .signd = 1, 70*1da177e4SLinus Torvalds .silence = {}, 71*1da177e4SLinus Torvalds }, 72*1da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_U24_LE] = { 73*1da177e4SLinus Torvalds .width = 24, .phys = 32, .le = 1, .signd = 0, 74*1da177e4SLinus Torvalds .silence = { 0x00, 0x00, 0x80 }, 75*1da177e4SLinus Torvalds }, 76*1da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_U24_BE] = { 77*1da177e4SLinus Torvalds .width = 24, .phys = 32, .le = 0, .signd = 0, 78*1da177e4SLinus Torvalds .silence = { 0x80, 0x00, 0x00 }, 79*1da177e4SLinus Torvalds }, 80*1da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_S32_LE] = { 81*1da177e4SLinus Torvalds .width = 32, .phys = 32, .le = 1, .signd = 1, 82*1da177e4SLinus Torvalds .silence = {}, 83*1da177e4SLinus Torvalds }, 84*1da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_S32_BE] = { 85*1da177e4SLinus Torvalds .width = 32, .phys = 32, .le = 0, .signd = 1, 86*1da177e4SLinus Torvalds .silence = {}, 87*1da177e4SLinus Torvalds }, 88*1da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_U32_LE] = { 89*1da177e4SLinus Torvalds .width = 32, .phys = 32, .le = 1, .signd = 0, 90*1da177e4SLinus Torvalds .silence = { 0x00, 0x00, 0x00, 0x80 }, 91*1da177e4SLinus Torvalds }, 92*1da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_U32_BE] = { 93*1da177e4SLinus Torvalds .width = 32, .phys = 32, .le = 0, .signd = 0, 94*1da177e4SLinus Torvalds .silence = { 0x80, 0x00, 0x00, 0x00 }, 95*1da177e4SLinus Torvalds }, 96*1da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_FLOAT_LE] = { 97*1da177e4SLinus Torvalds .width = 32, .phys = 32, .le = 1, .signd = -1, 98*1da177e4SLinus Torvalds .silence = {}, 99*1da177e4SLinus Torvalds }, 100*1da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_FLOAT_BE] = { 101*1da177e4SLinus Torvalds .width = 32, .phys = 32, .le = 0, .signd = -1, 102*1da177e4SLinus Torvalds .silence = {}, 103*1da177e4SLinus Torvalds }, 104*1da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_FLOAT64_LE] = { 105*1da177e4SLinus Torvalds .width = 64, .phys = 64, .le = 1, .signd = -1, 106*1da177e4SLinus Torvalds .silence = {}, 107*1da177e4SLinus Torvalds }, 108*1da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_FLOAT64_BE] = { 109*1da177e4SLinus Torvalds .width = 64, .phys = 64, .le = 0, .signd = -1, 110*1da177e4SLinus Torvalds .silence = {}, 111*1da177e4SLinus Torvalds }, 112*1da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE] = { 113*1da177e4SLinus Torvalds .width = 32, .phys = 32, .le = 1, .signd = -1, 114*1da177e4SLinus Torvalds .silence = {}, 115*1da177e4SLinus Torvalds }, 116*1da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE] = { 117*1da177e4SLinus Torvalds .width = 32, .phys = 32, .le = 0, .signd = -1, 118*1da177e4SLinus Torvalds .silence = {}, 119*1da177e4SLinus Torvalds }, 120*1da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_MU_LAW] = { 121*1da177e4SLinus Torvalds .width = 8, .phys = 8, .le = -1, .signd = -1, 122*1da177e4SLinus Torvalds .silence = { 0x7f }, 123*1da177e4SLinus Torvalds }, 124*1da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_A_LAW] = { 125*1da177e4SLinus Torvalds .width = 8, .phys = 8, .le = -1, .signd = -1, 126*1da177e4SLinus Torvalds .silence = { 0x55 }, 127*1da177e4SLinus Torvalds }, 128*1da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_IMA_ADPCM] = { 129*1da177e4SLinus Torvalds .width = 4, .phys = 4, .le = -1, .signd = -1, 130*1da177e4SLinus Torvalds .silence = {}, 131*1da177e4SLinus Torvalds }, 132*1da177e4SLinus Torvalds /* FIXME: the following three formats are not defined properly yet */ 133*1da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_MPEG] = { 134*1da177e4SLinus Torvalds .le = -1, .signd = -1, 135*1da177e4SLinus Torvalds }, 136*1da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_GSM] = { 137*1da177e4SLinus Torvalds .le = -1, .signd = -1, 138*1da177e4SLinus Torvalds }, 139*1da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_SPECIAL] = { 140*1da177e4SLinus Torvalds .le = -1, .signd = -1, 141*1da177e4SLinus Torvalds }, 142*1da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_S24_3LE] = { 143*1da177e4SLinus Torvalds .width = 24, .phys = 24, .le = 1, .signd = 1, 144*1da177e4SLinus Torvalds .silence = {}, 145*1da177e4SLinus Torvalds }, 146*1da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_S24_3BE] = { 147*1da177e4SLinus Torvalds .width = 24, .phys = 24, .le = 0, .signd = 1, 148*1da177e4SLinus Torvalds .silence = {}, 149*1da177e4SLinus Torvalds }, 150*1da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_U24_3LE] = { 151*1da177e4SLinus Torvalds .width = 24, .phys = 24, .le = 1, .signd = 0, 152*1da177e4SLinus Torvalds .silence = { 0x00, 0x00, 0x80 }, 153*1da177e4SLinus Torvalds }, 154*1da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_U24_3BE] = { 155*1da177e4SLinus Torvalds .width = 24, .phys = 24, .le = 0, .signd = 0, 156*1da177e4SLinus Torvalds .silence = { 0x80, 0x00, 0x00 }, 157*1da177e4SLinus Torvalds }, 158*1da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_S20_3LE] = { 159*1da177e4SLinus Torvalds .width = 20, .phys = 24, .le = 1, .signd = 1, 160*1da177e4SLinus Torvalds .silence = {}, 161*1da177e4SLinus Torvalds }, 162*1da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_S20_3BE] = { 163*1da177e4SLinus Torvalds .width = 20, .phys = 24, .le = 0, .signd = 1, 164*1da177e4SLinus Torvalds .silence = {}, 165*1da177e4SLinus Torvalds }, 166*1da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_U20_3LE] = { 167*1da177e4SLinus Torvalds .width = 20, .phys = 24, .le = 1, .signd = 0, 168*1da177e4SLinus Torvalds .silence = { 0x00, 0x00, 0x08 }, 169*1da177e4SLinus Torvalds }, 170*1da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_U20_3BE] = { 171*1da177e4SLinus Torvalds .width = 20, .phys = 24, .le = 0, .signd = 0, 172*1da177e4SLinus Torvalds .silence = { 0x08, 0x00, 0x00 }, 173*1da177e4SLinus Torvalds }, 174*1da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_S18_3LE] = { 175*1da177e4SLinus Torvalds .width = 18, .phys = 24, .le = 1, .signd = 1, 176*1da177e4SLinus Torvalds .silence = {}, 177*1da177e4SLinus Torvalds }, 178*1da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_S18_3BE] = { 179*1da177e4SLinus Torvalds .width = 18, .phys = 24, .le = 0, .signd = 1, 180*1da177e4SLinus Torvalds .silence = {}, 181*1da177e4SLinus Torvalds }, 182*1da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_U18_3LE] = { 183*1da177e4SLinus Torvalds .width = 18, .phys = 24, .le = 1, .signd = 0, 184*1da177e4SLinus Torvalds .silence = { 0x00, 0x00, 0x02 }, 185*1da177e4SLinus Torvalds }, 186*1da177e4SLinus Torvalds [SNDRV_PCM_FORMAT_U18_3BE] = { 187*1da177e4SLinus Torvalds .width = 18, .phys = 24, .le = 0, .signd = 0, 188*1da177e4SLinus Torvalds .silence = { 0x02, 0x00, 0x00 }, 189*1da177e4SLinus Torvalds }, 190*1da177e4SLinus Torvalds }; 191*1da177e4SLinus Torvalds 192*1da177e4SLinus Torvalds 193*1da177e4SLinus Torvalds /** 194*1da177e4SLinus Torvalds * snd_pcm_format_signed - Check the PCM format is signed linear 195*1da177e4SLinus Torvalds * @format: the format to check 196*1da177e4SLinus Torvalds * 197*1da177e4SLinus Torvalds * Returns 1 if the given PCM format is signed linear, 0 if unsigned 198*1da177e4SLinus Torvalds * linear, and a negative error code for non-linear formats. 199*1da177e4SLinus Torvalds */ 200*1da177e4SLinus Torvalds int snd_pcm_format_signed(snd_pcm_format_t format) 201*1da177e4SLinus Torvalds { 202*1da177e4SLinus Torvalds int val; 203*1da177e4SLinus Torvalds if (format < 0 || format > SNDRV_PCM_FORMAT_LAST) 204*1da177e4SLinus Torvalds return -EINVAL; 205*1da177e4SLinus Torvalds if ((val = pcm_formats[format].signd) < 0) 206*1da177e4SLinus Torvalds return -EINVAL; 207*1da177e4SLinus Torvalds return val; 208*1da177e4SLinus Torvalds } 209*1da177e4SLinus Torvalds 210*1da177e4SLinus Torvalds /** 211*1da177e4SLinus Torvalds * snd_pcm_format_unsigned - Check the PCM format is unsigned linear 212*1da177e4SLinus Torvalds * @format: the format to check 213*1da177e4SLinus Torvalds * 214*1da177e4SLinus Torvalds * Returns 1 if the given PCM format is unsigned linear, 0 if signed 215*1da177e4SLinus Torvalds * linear, and a negative error code for non-linear formats. 216*1da177e4SLinus Torvalds */ 217*1da177e4SLinus Torvalds int snd_pcm_format_unsigned(snd_pcm_format_t format) 218*1da177e4SLinus Torvalds { 219*1da177e4SLinus Torvalds int val; 220*1da177e4SLinus Torvalds 221*1da177e4SLinus Torvalds val = snd_pcm_format_signed(format); 222*1da177e4SLinus Torvalds if (val < 0) 223*1da177e4SLinus Torvalds return val; 224*1da177e4SLinus Torvalds return !val; 225*1da177e4SLinus Torvalds } 226*1da177e4SLinus Torvalds 227*1da177e4SLinus Torvalds /** 228*1da177e4SLinus Torvalds * snd_pcm_format_linear - Check the PCM format is linear 229*1da177e4SLinus Torvalds * @format: the format to check 230*1da177e4SLinus Torvalds * 231*1da177e4SLinus Torvalds * Returns 1 if the given PCM format is linear, 0 if not. 232*1da177e4SLinus Torvalds */ 233*1da177e4SLinus Torvalds int snd_pcm_format_linear(snd_pcm_format_t format) 234*1da177e4SLinus Torvalds { 235*1da177e4SLinus Torvalds return snd_pcm_format_signed(format) >= 0; 236*1da177e4SLinus Torvalds } 237*1da177e4SLinus Torvalds 238*1da177e4SLinus Torvalds /** 239*1da177e4SLinus Torvalds * snd_pcm_format_little_endian - Check the PCM format is little-endian 240*1da177e4SLinus Torvalds * @format: the format to check 241*1da177e4SLinus Torvalds * 242*1da177e4SLinus Torvalds * Returns 1 if the given PCM format is little-endian, 0 if 243*1da177e4SLinus Torvalds * big-endian, or a negative error code if endian not specified. 244*1da177e4SLinus Torvalds */ 245*1da177e4SLinus Torvalds int snd_pcm_format_little_endian(snd_pcm_format_t format) 246*1da177e4SLinus Torvalds { 247*1da177e4SLinus Torvalds int val; 248*1da177e4SLinus Torvalds if (format < 0 || format > SNDRV_PCM_FORMAT_LAST) 249*1da177e4SLinus Torvalds return -EINVAL; 250*1da177e4SLinus Torvalds if ((val = pcm_formats[format].le) < 0) 251*1da177e4SLinus Torvalds return -EINVAL; 252*1da177e4SLinus Torvalds return val; 253*1da177e4SLinus Torvalds } 254*1da177e4SLinus Torvalds 255*1da177e4SLinus Torvalds /** 256*1da177e4SLinus Torvalds * snd_pcm_format_big_endian - Check the PCM format is big-endian 257*1da177e4SLinus Torvalds * @format: the format to check 258*1da177e4SLinus Torvalds * 259*1da177e4SLinus Torvalds * Returns 1 if the given PCM format is big-endian, 0 if 260*1da177e4SLinus Torvalds * little-endian, or a negative error code if endian not specified. 261*1da177e4SLinus Torvalds */ 262*1da177e4SLinus Torvalds int snd_pcm_format_big_endian(snd_pcm_format_t format) 263*1da177e4SLinus Torvalds { 264*1da177e4SLinus Torvalds int val; 265*1da177e4SLinus Torvalds 266*1da177e4SLinus Torvalds val = snd_pcm_format_little_endian(format); 267*1da177e4SLinus Torvalds if (val < 0) 268*1da177e4SLinus Torvalds return val; 269*1da177e4SLinus Torvalds return !val; 270*1da177e4SLinus Torvalds } 271*1da177e4SLinus Torvalds 272*1da177e4SLinus Torvalds /** 273*1da177e4SLinus Torvalds * snd_pcm_format_cpu_endian - Check the PCM format is CPU-endian 274*1da177e4SLinus Torvalds * @format: the format to check 275*1da177e4SLinus Torvalds * 276*1da177e4SLinus Torvalds * Returns 1 if the given PCM format is CPU-endian, 0 if 277*1da177e4SLinus Torvalds * opposite, or a negative error code if endian not specified. 278*1da177e4SLinus Torvalds */ 279*1da177e4SLinus Torvalds int snd_pcm_format_cpu_endian(snd_pcm_format_t format) 280*1da177e4SLinus Torvalds { 281*1da177e4SLinus Torvalds #ifdef SNDRV_LITTLE_ENDIAN 282*1da177e4SLinus Torvalds return snd_pcm_format_little_endian(format); 283*1da177e4SLinus Torvalds #else 284*1da177e4SLinus Torvalds return snd_pcm_format_big_endian(format); 285*1da177e4SLinus Torvalds #endif 286*1da177e4SLinus Torvalds } 287*1da177e4SLinus Torvalds 288*1da177e4SLinus Torvalds /** 289*1da177e4SLinus Torvalds * snd_pcm_format_width - return the bit-width of the format 290*1da177e4SLinus Torvalds * @format: the format to check 291*1da177e4SLinus Torvalds * 292*1da177e4SLinus Torvalds * Returns the bit-width of the format, or a negative error code 293*1da177e4SLinus Torvalds * if unknown format. 294*1da177e4SLinus Torvalds */ 295*1da177e4SLinus Torvalds int snd_pcm_format_width(snd_pcm_format_t format) 296*1da177e4SLinus Torvalds { 297*1da177e4SLinus Torvalds int val; 298*1da177e4SLinus Torvalds if (format < 0 || format > SNDRV_PCM_FORMAT_LAST) 299*1da177e4SLinus Torvalds return -EINVAL; 300*1da177e4SLinus Torvalds if ((val = pcm_formats[format].width) == 0) 301*1da177e4SLinus Torvalds return -EINVAL; 302*1da177e4SLinus Torvalds return val; 303*1da177e4SLinus Torvalds } 304*1da177e4SLinus Torvalds 305*1da177e4SLinus Torvalds /** 306*1da177e4SLinus Torvalds * snd_pcm_format_physical_width - return the physical bit-width of the format 307*1da177e4SLinus Torvalds * @format: the format to check 308*1da177e4SLinus Torvalds * 309*1da177e4SLinus Torvalds * Returns the physical bit-width of the format, or a negative error code 310*1da177e4SLinus Torvalds * if unknown format. 311*1da177e4SLinus Torvalds */ 312*1da177e4SLinus Torvalds int snd_pcm_format_physical_width(snd_pcm_format_t format) 313*1da177e4SLinus Torvalds { 314*1da177e4SLinus Torvalds int val; 315*1da177e4SLinus Torvalds if (format < 0 || format > SNDRV_PCM_FORMAT_LAST) 316*1da177e4SLinus Torvalds return -EINVAL; 317*1da177e4SLinus Torvalds if ((val = pcm_formats[format].phys) == 0) 318*1da177e4SLinus Torvalds return -EINVAL; 319*1da177e4SLinus Torvalds return val; 320*1da177e4SLinus Torvalds } 321*1da177e4SLinus Torvalds 322*1da177e4SLinus Torvalds /** 323*1da177e4SLinus Torvalds * snd_pcm_format_size - return the byte size of samples on the given format 324*1da177e4SLinus Torvalds * @format: the format to check 325*1da177e4SLinus Torvalds * 326*1da177e4SLinus Torvalds * Returns the byte size of the given samples for the format, or a 327*1da177e4SLinus Torvalds * negative error code if unknown format. 328*1da177e4SLinus Torvalds */ 329*1da177e4SLinus Torvalds ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples) 330*1da177e4SLinus Torvalds { 331*1da177e4SLinus Torvalds int phys_width = snd_pcm_format_physical_width(format); 332*1da177e4SLinus Torvalds if (phys_width < 0) 333*1da177e4SLinus Torvalds return -EINVAL; 334*1da177e4SLinus Torvalds return samples * phys_width / 8; 335*1da177e4SLinus Torvalds } 336*1da177e4SLinus Torvalds 337*1da177e4SLinus Torvalds /** 338*1da177e4SLinus Torvalds * snd_pcm_format_silence_64 - return the silent data in 8 bytes array 339*1da177e4SLinus Torvalds * @format: the format to check 340*1da177e4SLinus Torvalds * 341*1da177e4SLinus Torvalds * Returns the format pattern to fill or NULL if error. 342*1da177e4SLinus Torvalds */ 343*1da177e4SLinus Torvalds const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format) 344*1da177e4SLinus Torvalds { 345*1da177e4SLinus Torvalds if (format < 0 || format > SNDRV_PCM_FORMAT_LAST) 346*1da177e4SLinus Torvalds return NULL; 347*1da177e4SLinus Torvalds if (! pcm_formats[format].phys) 348*1da177e4SLinus Torvalds return NULL; 349*1da177e4SLinus Torvalds return pcm_formats[format].silence; 350*1da177e4SLinus Torvalds } 351*1da177e4SLinus Torvalds 352*1da177e4SLinus Torvalds /** 353*1da177e4SLinus Torvalds * snd_pcm_format_set_silence - set the silence data on the buffer 354*1da177e4SLinus Torvalds * @format: the PCM format 355*1da177e4SLinus Torvalds * @data: the buffer pointer 356*1da177e4SLinus Torvalds * @samples: the number of samples to set silence 357*1da177e4SLinus Torvalds * 358*1da177e4SLinus Torvalds * Sets the silence data on the buffer for the given samples. 359*1da177e4SLinus Torvalds * 360*1da177e4SLinus Torvalds * Returns zero if successful, or a negative error code on failure. 361*1da177e4SLinus Torvalds */ 362*1da177e4SLinus Torvalds int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int samples) 363*1da177e4SLinus Torvalds { 364*1da177e4SLinus Torvalds int width; 365*1da177e4SLinus Torvalds unsigned char *dst, *pat; 366*1da177e4SLinus Torvalds 367*1da177e4SLinus Torvalds if (format < 0 || format > SNDRV_PCM_FORMAT_LAST) 368*1da177e4SLinus Torvalds return -EINVAL; 369*1da177e4SLinus Torvalds if (samples == 0) 370*1da177e4SLinus Torvalds return 0; 371*1da177e4SLinus Torvalds width = pcm_formats[format].phys; /* physical width */ 372*1da177e4SLinus Torvalds pat = pcm_formats[format].silence; 373*1da177e4SLinus Torvalds if (! width) 374*1da177e4SLinus Torvalds return -EINVAL; 375*1da177e4SLinus Torvalds /* signed or 1 byte data */ 376*1da177e4SLinus Torvalds if (pcm_formats[format].signd == 1 || width <= 8) { 377*1da177e4SLinus Torvalds unsigned int bytes = samples * width / 8; 378*1da177e4SLinus Torvalds memset(data, *pat, bytes); 379*1da177e4SLinus Torvalds return 0; 380*1da177e4SLinus Torvalds } 381*1da177e4SLinus Torvalds /* non-zero samples, fill using a loop */ 382*1da177e4SLinus Torvalds width /= 8; 383*1da177e4SLinus Torvalds dst = data; 384*1da177e4SLinus Torvalds #if 0 385*1da177e4SLinus Torvalds while (samples--) { 386*1da177e4SLinus Torvalds memcpy(dst, pat, width); 387*1da177e4SLinus Torvalds dst += width; 388*1da177e4SLinus Torvalds } 389*1da177e4SLinus Torvalds #else 390*1da177e4SLinus Torvalds /* a bit optimization for constant width */ 391*1da177e4SLinus Torvalds switch (width) { 392*1da177e4SLinus Torvalds case 2: 393*1da177e4SLinus Torvalds while (samples--) { 394*1da177e4SLinus Torvalds memcpy(dst, pat, 2); 395*1da177e4SLinus Torvalds dst += 2; 396*1da177e4SLinus Torvalds } 397*1da177e4SLinus Torvalds break; 398*1da177e4SLinus Torvalds case 3: 399*1da177e4SLinus Torvalds while (samples--) { 400*1da177e4SLinus Torvalds memcpy(dst, pat, 3); 401*1da177e4SLinus Torvalds dst += 3; 402*1da177e4SLinus Torvalds } 403*1da177e4SLinus Torvalds break; 404*1da177e4SLinus Torvalds case 4: 405*1da177e4SLinus Torvalds while (samples--) { 406*1da177e4SLinus Torvalds memcpy(dst, pat, 4); 407*1da177e4SLinus Torvalds dst += 4; 408*1da177e4SLinus Torvalds } 409*1da177e4SLinus Torvalds break; 410*1da177e4SLinus Torvalds case 8: 411*1da177e4SLinus Torvalds while (samples--) { 412*1da177e4SLinus Torvalds memcpy(dst, pat, 8); 413*1da177e4SLinus Torvalds dst += 8; 414*1da177e4SLinus Torvalds } 415*1da177e4SLinus Torvalds break; 416*1da177e4SLinus Torvalds } 417*1da177e4SLinus Torvalds #endif 418*1da177e4SLinus Torvalds return 0; 419*1da177e4SLinus Torvalds } 420*1da177e4SLinus Torvalds 421*1da177e4SLinus Torvalds /* [width][unsigned][bigendian] */ 422*1da177e4SLinus Torvalds static int linear_formats[4][2][2] = { 423*1da177e4SLinus Torvalds {{ SNDRV_PCM_FORMAT_S8, SNDRV_PCM_FORMAT_S8}, 424*1da177e4SLinus Torvalds { SNDRV_PCM_FORMAT_U8, SNDRV_PCM_FORMAT_U8}}, 425*1da177e4SLinus Torvalds {{SNDRV_PCM_FORMAT_S16_LE, SNDRV_PCM_FORMAT_S16_BE}, 426*1da177e4SLinus Torvalds {SNDRV_PCM_FORMAT_U16_LE, SNDRV_PCM_FORMAT_U16_BE}}, 427*1da177e4SLinus Torvalds {{SNDRV_PCM_FORMAT_S24_LE, SNDRV_PCM_FORMAT_S24_BE}, 428*1da177e4SLinus Torvalds {SNDRV_PCM_FORMAT_U24_LE, SNDRV_PCM_FORMAT_U24_BE}}, 429*1da177e4SLinus Torvalds {{SNDRV_PCM_FORMAT_S32_LE, SNDRV_PCM_FORMAT_S32_BE}, 430*1da177e4SLinus Torvalds {SNDRV_PCM_FORMAT_U32_LE, SNDRV_PCM_FORMAT_U32_BE}} 431*1da177e4SLinus Torvalds }; 432*1da177e4SLinus Torvalds 433*1da177e4SLinus Torvalds /** 434*1da177e4SLinus Torvalds * snd_pcm_build_linear_format - return the suitable linear format for the given condition 435*1da177e4SLinus Torvalds * @width: the bit-width 436*1da177e4SLinus Torvalds * @unsignd: 1 if unsigned, 0 if signed. 437*1da177e4SLinus Torvalds * @big_endian: 1 if big-endian, 0 if little-endian 438*1da177e4SLinus Torvalds * 439*1da177e4SLinus Torvalds * Returns the suitable linear format for the given condition. 440*1da177e4SLinus Torvalds */ 441*1da177e4SLinus Torvalds snd_pcm_format_t snd_pcm_build_linear_format(int width, int unsignd, int big_endian) 442*1da177e4SLinus Torvalds { 443*1da177e4SLinus Torvalds if (width & 7) 444*1da177e4SLinus Torvalds return SND_PCM_FORMAT_UNKNOWN; 445*1da177e4SLinus Torvalds width = (width / 8) - 1; 446*1da177e4SLinus Torvalds if (width < 0 || width >= 4) 447*1da177e4SLinus Torvalds return SND_PCM_FORMAT_UNKNOWN; 448*1da177e4SLinus Torvalds return linear_formats[width][!!unsignd][!!big_endian]; 449*1da177e4SLinus Torvalds } 450*1da177e4SLinus Torvalds 451*1da177e4SLinus Torvalds /** 452*1da177e4SLinus Torvalds * snd_pcm_limit_hw_rates - determine rate_min/rate_max fields 453*1da177e4SLinus Torvalds * @runtime: the runtime instance 454*1da177e4SLinus Torvalds * 455*1da177e4SLinus Torvalds * Determines the rate_min and rate_max fields from the rates bits of 456*1da177e4SLinus Torvalds * the given runtime->hw. 457*1da177e4SLinus Torvalds * 458*1da177e4SLinus Torvalds * Returns zero if successful. 459*1da177e4SLinus Torvalds */ 460*1da177e4SLinus Torvalds int snd_pcm_limit_hw_rates(snd_pcm_runtime_t *runtime) 461*1da177e4SLinus Torvalds { 462*1da177e4SLinus Torvalds static unsigned rates[] = { 463*1da177e4SLinus Torvalds /* ATTENTION: these values depend on the definition in pcm.h! */ 464*1da177e4SLinus Torvalds 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, 465*1da177e4SLinus Torvalds 64000, 88200, 96000, 176400, 192000 466*1da177e4SLinus Torvalds }; 467*1da177e4SLinus Torvalds int i; 468*1da177e4SLinus Torvalds for (i = 0; i < (int)ARRAY_SIZE(rates); i++) { 469*1da177e4SLinus Torvalds if (runtime->hw.rates & (1 << i)) { 470*1da177e4SLinus Torvalds runtime->hw.rate_min = rates[i]; 471*1da177e4SLinus Torvalds break; 472*1da177e4SLinus Torvalds } 473*1da177e4SLinus Torvalds } 474*1da177e4SLinus Torvalds for (i = (int)ARRAY_SIZE(rates) - 1; i >= 0; i--) { 475*1da177e4SLinus Torvalds if (runtime->hw.rates & (1 << i)) { 476*1da177e4SLinus Torvalds runtime->hw.rate_max = rates[i]; 477*1da177e4SLinus Torvalds break; 478*1da177e4SLinus Torvalds } 479*1da177e4SLinus Torvalds } 480*1da177e4SLinus Torvalds return 0; 481*1da177e4SLinus Torvalds } 482