xref: /OK3568_Linux_fs/kernel/sound/core/pcm_misc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  *  PCM Interface - misc routines
3*4882a593Smuzhiyun  *  Copyright (c) 1998 by Jaroslav Kysela <perex@perex.cz>
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  *   This library is free software; you can redistribute it and/or modify
7*4882a593Smuzhiyun  *   it under the terms of the GNU Library General Public License as
8*4882a593Smuzhiyun  *   published by the Free Software Foundation; either version 2 of
9*4882a593Smuzhiyun  *   the License, or (at your option) any later version.
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  *   This program is distributed in the hope that it will be useful,
12*4882a593Smuzhiyun  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13*4882a593Smuzhiyun  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14*4882a593Smuzhiyun  *   GNU Library General Public License for more details.
15*4882a593Smuzhiyun  *
16*4882a593Smuzhiyun  *   You should have received a copy of the GNU Library General Public
17*4882a593Smuzhiyun  *   License along with this library; if not, write to the Free Software
18*4882a593Smuzhiyun  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19*4882a593Smuzhiyun  *
20*4882a593Smuzhiyun  */
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #include <linux/time.h>
23*4882a593Smuzhiyun #include <linux/export.h>
24*4882a593Smuzhiyun #include <sound/core.h>
25*4882a593Smuzhiyun #include <sound/pcm.h>
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun #include "pcm_local.h"
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun #define SND_PCM_FORMAT_UNKNOWN (-1)
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun /* NOTE: "signed" prefix must be given below since the default char is
32*4882a593Smuzhiyun  *       unsigned on some architectures!
33*4882a593Smuzhiyun  */
34*4882a593Smuzhiyun struct pcm_format_data {
35*4882a593Smuzhiyun 	unsigned char width;	/* bit width */
36*4882a593Smuzhiyun 	unsigned char phys;	/* physical bit width */
37*4882a593Smuzhiyun 	signed char le;	/* 0 = big-endian, 1 = little-endian, -1 = others */
38*4882a593Smuzhiyun 	signed char signd;	/* 0 = unsigned, 1 = signed, -1 = others */
39*4882a593Smuzhiyun 	unsigned char silence[8];	/* silence data to fill */
40*4882a593Smuzhiyun };
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun /* we do lots of calculations on snd_pcm_format_t; shut up sparse */
43*4882a593Smuzhiyun #define INT	__force int
44*4882a593Smuzhiyun 
valid_format(snd_pcm_format_t format)45*4882a593Smuzhiyun static bool valid_format(snd_pcm_format_t format)
46*4882a593Smuzhiyun {
47*4882a593Smuzhiyun 	return (INT)format >= 0 && (INT)format <= (INT)SNDRV_PCM_FORMAT_LAST;
48*4882a593Smuzhiyun }
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun static const struct pcm_format_data pcm_formats[(INT)SNDRV_PCM_FORMAT_LAST+1] = {
51*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_S8] = {
52*4882a593Smuzhiyun 		.width = 8, .phys = 8, .le = -1, .signd = 1,
53*4882a593Smuzhiyun 		.silence = {},
54*4882a593Smuzhiyun 	},
55*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_U8] = {
56*4882a593Smuzhiyun 		.width = 8, .phys = 8, .le = -1, .signd = 0,
57*4882a593Smuzhiyun 		.silence = { 0x80 },
58*4882a593Smuzhiyun 	},
59*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_S16_LE] = {
60*4882a593Smuzhiyun 		.width = 16, .phys = 16, .le = 1, .signd = 1,
61*4882a593Smuzhiyun 		.silence = {},
62*4882a593Smuzhiyun 	},
63*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_S16_BE] = {
64*4882a593Smuzhiyun 		.width = 16, .phys = 16, .le = 0, .signd = 1,
65*4882a593Smuzhiyun 		.silence = {},
66*4882a593Smuzhiyun 	},
67*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_U16_LE] = {
68*4882a593Smuzhiyun 		.width = 16, .phys = 16, .le = 1, .signd = 0,
69*4882a593Smuzhiyun 		.silence = { 0x00, 0x80 },
70*4882a593Smuzhiyun 	},
71*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_U16_BE] = {
72*4882a593Smuzhiyun 		.width = 16, .phys = 16, .le = 0, .signd = 0,
73*4882a593Smuzhiyun 		.silence = { 0x80, 0x00 },
74*4882a593Smuzhiyun 	},
75*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_S24_LE] = {
76*4882a593Smuzhiyun 		.width = 24, .phys = 32, .le = 1, .signd = 1,
77*4882a593Smuzhiyun 		.silence = {},
78*4882a593Smuzhiyun 	},
79*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_S24_BE] = {
80*4882a593Smuzhiyun 		.width = 24, .phys = 32, .le = 0, .signd = 1,
81*4882a593Smuzhiyun 		.silence = {},
82*4882a593Smuzhiyun 	},
83*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_U24_LE] = {
84*4882a593Smuzhiyun 		.width = 24, .phys = 32, .le = 1, .signd = 0,
85*4882a593Smuzhiyun 		.silence = { 0x00, 0x00, 0x80 },
86*4882a593Smuzhiyun 	},
87*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_U24_BE] = {
88*4882a593Smuzhiyun 		.width = 24, .phys = 32, .le = 0, .signd = 0,
89*4882a593Smuzhiyun 		.silence = { 0x00, 0x80, 0x00, 0x00 },
90*4882a593Smuzhiyun 	},
91*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_S32_LE] = {
92*4882a593Smuzhiyun 		.width = 32, .phys = 32, .le = 1, .signd = 1,
93*4882a593Smuzhiyun 		.silence = {},
94*4882a593Smuzhiyun 	},
95*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_S32_BE] = {
96*4882a593Smuzhiyun 		.width = 32, .phys = 32, .le = 0, .signd = 1,
97*4882a593Smuzhiyun 		.silence = {},
98*4882a593Smuzhiyun 	},
99*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_U32_LE] = {
100*4882a593Smuzhiyun 		.width = 32, .phys = 32, .le = 1, .signd = 0,
101*4882a593Smuzhiyun 		.silence = { 0x00, 0x00, 0x00, 0x80 },
102*4882a593Smuzhiyun 	},
103*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_U32_BE] = {
104*4882a593Smuzhiyun 		.width = 32, .phys = 32, .le = 0, .signd = 0,
105*4882a593Smuzhiyun 		.silence = { 0x80, 0x00, 0x00, 0x00 },
106*4882a593Smuzhiyun 	},
107*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_FLOAT_LE] = {
108*4882a593Smuzhiyun 		.width = 32, .phys = 32, .le = 1, .signd = -1,
109*4882a593Smuzhiyun 		.silence = {},
110*4882a593Smuzhiyun 	},
111*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_FLOAT_BE] = {
112*4882a593Smuzhiyun 		.width = 32, .phys = 32, .le = 0, .signd = -1,
113*4882a593Smuzhiyun 		.silence = {},
114*4882a593Smuzhiyun 	},
115*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_FLOAT64_LE] = {
116*4882a593Smuzhiyun 		.width = 64, .phys = 64, .le = 1, .signd = -1,
117*4882a593Smuzhiyun 		.silence = {},
118*4882a593Smuzhiyun 	},
119*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_FLOAT64_BE] = {
120*4882a593Smuzhiyun 		.width = 64, .phys = 64, .le = 0, .signd = -1,
121*4882a593Smuzhiyun 		.silence = {},
122*4882a593Smuzhiyun 	},
123*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE] = {
124*4882a593Smuzhiyun 		.width = 32, .phys = 32, .le = 1, .signd = -1,
125*4882a593Smuzhiyun 		.silence = {},
126*4882a593Smuzhiyun 	},
127*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE] = {
128*4882a593Smuzhiyun 		.width = 32, .phys = 32, .le = 0, .signd = -1,
129*4882a593Smuzhiyun 		.silence = {},
130*4882a593Smuzhiyun 	},
131*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_MU_LAW] = {
132*4882a593Smuzhiyun 		.width = 8, .phys = 8, .le = -1, .signd = -1,
133*4882a593Smuzhiyun 		.silence = { 0x7f },
134*4882a593Smuzhiyun 	},
135*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_A_LAW] = {
136*4882a593Smuzhiyun 		.width = 8, .phys = 8, .le = -1, .signd = -1,
137*4882a593Smuzhiyun 		.silence = { 0x55 },
138*4882a593Smuzhiyun 	},
139*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_IMA_ADPCM] = {
140*4882a593Smuzhiyun 		.width = 4, .phys = 4, .le = -1, .signd = -1,
141*4882a593Smuzhiyun 		.silence = {},
142*4882a593Smuzhiyun 	},
143*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_G723_24] = {
144*4882a593Smuzhiyun 		.width = 3, .phys = 3, .le = -1, .signd = -1,
145*4882a593Smuzhiyun 		.silence = {},
146*4882a593Smuzhiyun 	},
147*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_G723_40] = {
148*4882a593Smuzhiyun 		.width = 5, .phys = 5, .le = -1, .signd = -1,
149*4882a593Smuzhiyun 		.silence = {},
150*4882a593Smuzhiyun 	},
151*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_DSD_U8] = {
152*4882a593Smuzhiyun 		.width = 8, .phys = 8, .le = 1, .signd = 0,
153*4882a593Smuzhiyun 		.silence = { 0x69 },
154*4882a593Smuzhiyun 	},
155*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_DSD_U16_LE] = {
156*4882a593Smuzhiyun 		.width = 16, .phys = 16, .le = 1, .signd = 0,
157*4882a593Smuzhiyun 		.silence = { 0x69, 0x69 },
158*4882a593Smuzhiyun 	},
159*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_DSD_U32_LE] = {
160*4882a593Smuzhiyun 		.width = 32, .phys = 32, .le = 1, .signd = 0,
161*4882a593Smuzhiyun 		.silence = { 0x69, 0x69, 0x69, 0x69 },
162*4882a593Smuzhiyun 	},
163*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_DSD_U16_BE] = {
164*4882a593Smuzhiyun 		.width = 16, .phys = 16, .le = 0, .signd = 0,
165*4882a593Smuzhiyun 		.silence = { 0x69, 0x69 },
166*4882a593Smuzhiyun 	},
167*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_DSD_U32_BE] = {
168*4882a593Smuzhiyun 		.width = 32, .phys = 32, .le = 0, .signd = 0,
169*4882a593Smuzhiyun 		.silence = { 0x69, 0x69, 0x69, 0x69 },
170*4882a593Smuzhiyun 	},
171*4882a593Smuzhiyun 	/* FIXME: the following two formats are not defined properly yet */
172*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_MPEG] = {
173*4882a593Smuzhiyun 		.le = -1, .signd = -1,
174*4882a593Smuzhiyun 	},
175*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_GSM] = {
176*4882a593Smuzhiyun 		.le = -1, .signd = -1,
177*4882a593Smuzhiyun 	},
178*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_S20_LE] = {
179*4882a593Smuzhiyun 		.width = 20, .phys = 32, .le = 1, .signd = 1,
180*4882a593Smuzhiyun 		.silence = {},
181*4882a593Smuzhiyun 	},
182*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_S20_BE] = {
183*4882a593Smuzhiyun 		.width = 20, .phys = 32, .le = 0, .signd = 1,
184*4882a593Smuzhiyun 		.silence = {},
185*4882a593Smuzhiyun 	},
186*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_U20_LE] = {
187*4882a593Smuzhiyun 		.width = 20, .phys = 32, .le = 1, .signd = 0,
188*4882a593Smuzhiyun 		.silence = { 0x00, 0x00, 0x08, 0x00 },
189*4882a593Smuzhiyun 	},
190*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_U20_BE] = {
191*4882a593Smuzhiyun 		.width = 20, .phys = 32, .le = 0, .signd = 0,
192*4882a593Smuzhiyun 		.silence = { 0x00, 0x08, 0x00, 0x00 },
193*4882a593Smuzhiyun 	},
194*4882a593Smuzhiyun 	/* FIXME: the following format is not defined properly yet */
195*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_SPECIAL] = {
196*4882a593Smuzhiyun 		.le = -1, .signd = -1,
197*4882a593Smuzhiyun 	},
198*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_S24_3LE] = {
199*4882a593Smuzhiyun 		.width = 24, .phys = 24, .le = 1, .signd = 1,
200*4882a593Smuzhiyun 		.silence = {},
201*4882a593Smuzhiyun 	},
202*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_S24_3BE] = {
203*4882a593Smuzhiyun 		.width = 24, .phys = 24, .le = 0, .signd = 1,
204*4882a593Smuzhiyun 		.silence = {},
205*4882a593Smuzhiyun 	},
206*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_U24_3LE] = {
207*4882a593Smuzhiyun 		.width = 24, .phys = 24, .le = 1, .signd = 0,
208*4882a593Smuzhiyun 		.silence = { 0x00, 0x00, 0x80 },
209*4882a593Smuzhiyun 	},
210*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_U24_3BE] = {
211*4882a593Smuzhiyun 		.width = 24, .phys = 24, .le = 0, .signd = 0,
212*4882a593Smuzhiyun 		.silence = { 0x80, 0x00, 0x00 },
213*4882a593Smuzhiyun 	},
214*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_S20_3LE] = {
215*4882a593Smuzhiyun 		.width = 20, .phys = 24, .le = 1, .signd = 1,
216*4882a593Smuzhiyun 		.silence = {},
217*4882a593Smuzhiyun 	},
218*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_S20_3BE] = {
219*4882a593Smuzhiyun 		.width = 20, .phys = 24, .le = 0, .signd = 1,
220*4882a593Smuzhiyun 		.silence = {},
221*4882a593Smuzhiyun 	},
222*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_U20_3LE] = {
223*4882a593Smuzhiyun 		.width = 20, .phys = 24, .le = 1, .signd = 0,
224*4882a593Smuzhiyun 		.silence = { 0x00, 0x00, 0x08 },
225*4882a593Smuzhiyun 	},
226*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_U20_3BE] = {
227*4882a593Smuzhiyun 		.width = 20, .phys = 24, .le = 0, .signd = 0,
228*4882a593Smuzhiyun 		.silence = { 0x08, 0x00, 0x00 },
229*4882a593Smuzhiyun 	},
230*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_S18_3LE] = {
231*4882a593Smuzhiyun 		.width = 18, .phys = 24, .le = 1, .signd = 1,
232*4882a593Smuzhiyun 		.silence = {},
233*4882a593Smuzhiyun 	},
234*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_S18_3BE] = {
235*4882a593Smuzhiyun 		.width = 18, .phys = 24, .le = 0, .signd = 1,
236*4882a593Smuzhiyun 		.silence = {},
237*4882a593Smuzhiyun 	},
238*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_U18_3LE] = {
239*4882a593Smuzhiyun 		.width = 18, .phys = 24, .le = 1, .signd = 0,
240*4882a593Smuzhiyun 		.silence = { 0x00, 0x00, 0x02 },
241*4882a593Smuzhiyun 	},
242*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_U18_3BE] = {
243*4882a593Smuzhiyun 		.width = 18, .phys = 24, .le = 0, .signd = 0,
244*4882a593Smuzhiyun 		.silence = { 0x02, 0x00, 0x00 },
245*4882a593Smuzhiyun 	},
246*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_G723_24_1B] = {
247*4882a593Smuzhiyun 		.width = 3, .phys = 8, .le = -1, .signd = -1,
248*4882a593Smuzhiyun 		.silence = {},
249*4882a593Smuzhiyun 	},
250*4882a593Smuzhiyun 	[SNDRV_PCM_FORMAT_G723_40_1B] = {
251*4882a593Smuzhiyun 		.width = 5, .phys = 8, .le = -1, .signd = -1,
252*4882a593Smuzhiyun 		.silence = {},
253*4882a593Smuzhiyun 	},
254*4882a593Smuzhiyun };
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun /**
258*4882a593Smuzhiyun  * snd_pcm_format_signed - Check the PCM format is signed linear
259*4882a593Smuzhiyun  * @format: the format to check
260*4882a593Smuzhiyun  *
261*4882a593Smuzhiyun  * Return: 1 if the given PCM format is signed linear, 0 if unsigned
262*4882a593Smuzhiyun  * linear, and a negative error code for non-linear formats.
263*4882a593Smuzhiyun  */
snd_pcm_format_signed(snd_pcm_format_t format)264*4882a593Smuzhiyun int snd_pcm_format_signed(snd_pcm_format_t format)
265*4882a593Smuzhiyun {
266*4882a593Smuzhiyun 	int val;
267*4882a593Smuzhiyun 	if (!valid_format(format))
268*4882a593Smuzhiyun 		return -EINVAL;
269*4882a593Smuzhiyun 	if ((val = pcm_formats[(INT)format].signd) < 0)
270*4882a593Smuzhiyun 		return -EINVAL;
271*4882a593Smuzhiyun 	return val;
272*4882a593Smuzhiyun }
273*4882a593Smuzhiyun EXPORT_SYMBOL(snd_pcm_format_signed);
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun /**
276*4882a593Smuzhiyun  * snd_pcm_format_unsigned - Check the PCM format is unsigned linear
277*4882a593Smuzhiyun  * @format: the format to check
278*4882a593Smuzhiyun  *
279*4882a593Smuzhiyun  * Return: 1 if the given PCM format is unsigned linear, 0 if signed
280*4882a593Smuzhiyun  * linear, and a negative error code for non-linear formats.
281*4882a593Smuzhiyun  */
snd_pcm_format_unsigned(snd_pcm_format_t format)282*4882a593Smuzhiyun int snd_pcm_format_unsigned(snd_pcm_format_t format)
283*4882a593Smuzhiyun {
284*4882a593Smuzhiyun 	int val;
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 	val = snd_pcm_format_signed(format);
287*4882a593Smuzhiyun 	if (val < 0)
288*4882a593Smuzhiyun 		return val;
289*4882a593Smuzhiyun 	return !val;
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun EXPORT_SYMBOL(snd_pcm_format_unsigned);
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun /**
294*4882a593Smuzhiyun  * snd_pcm_format_linear - Check the PCM format is linear
295*4882a593Smuzhiyun  * @format: the format to check
296*4882a593Smuzhiyun  *
297*4882a593Smuzhiyun  * Return: 1 if the given PCM format is linear, 0 if not.
298*4882a593Smuzhiyun  */
snd_pcm_format_linear(snd_pcm_format_t format)299*4882a593Smuzhiyun int snd_pcm_format_linear(snd_pcm_format_t format)
300*4882a593Smuzhiyun {
301*4882a593Smuzhiyun 	return snd_pcm_format_signed(format) >= 0;
302*4882a593Smuzhiyun }
303*4882a593Smuzhiyun EXPORT_SYMBOL(snd_pcm_format_linear);
304*4882a593Smuzhiyun 
305*4882a593Smuzhiyun /**
306*4882a593Smuzhiyun  * snd_pcm_format_little_endian - Check the PCM format is little-endian
307*4882a593Smuzhiyun  * @format: the format to check
308*4882a593Smuzhiyun  *
309*4882a593Smuzhiyun  * Return: 1 if the given PCM format is little-endian, 0 if
310*4882a593Smuzhiyun  * big-endian, or a negative error code if endian not specified.
311*4882a593Smuzhiyun  */
snd_pcm_format_little_endian(snd_pcm_format_t format)312*4882a593Smuzhiyun int snd_pcm_format_little_endian(snd_pcm_format_t format)
313*4882a593Smuzhiyun {
314*4882a593Smuzhiyun 	int val;
315*4882a593Smuzhiyun 	if (!valid_format(format))
316*4882a593Smuzhiyun 		return -EINVAL;
317*4882a593Smuzhiyun 	if ((val = pcm_formats[(INT)format].le) < 0)
318*4882a593Smuzhiyun 		return -EINVAL;
319*4882a593Smuzhiyun 	return val;
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun EXPORT_SYMBOL(snd_pcm_format_little_endian);
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun /**
324*4882a593Smuzhiyun  * snd_pcm_format_big_endian - Check the PCM format is big-endian
325*4882a593Smuzhiyun  * @format: the format to check
326*4882a593Smuzhiyun  *
327*4882a593Smuzhiyun  * Return: 1 if the given PCM format is big-endian, 0 if
328*4882a593Smuzhiyun  * little-endian, or a negative error code if endian not specified.
329*4882a593Smuzhiyun  */
snd_pcm_format_big_endian(snd_pcm_format_t format)330*4882a593Smuzhiyun int snd_pcm_format_big_endian(snd_pcm_format_t format)
331*4882a593Smuzhiyun {
332*4882a593Smuzhiyun 	int val;
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun 	val = snd_pcm_format_little_endian(format);
335*4882a593Smuzhiyun 	if (val < 0)
336*4882a593Smuzhiyun 		return val;
337*4882a593Smuzhiyun 	return !val;
338*4882a593Smuzhiyun }
339*4882a593Smuzhiyun EXPORT_SYMBOL(snd_pcm_format_big_endian);
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun /**
342*4882a593Smuzhiyun  * snd_pcm_format_width - return the bit-width of the format
343*4882a593Smuzhiyun  * @format: the format to check
344*4882a593Smuzhiyun  *
345*4882a593Smuzhiyun  * Return: The bit-width of the format, or a negative error code
346*4882a593Smuzhiyun  * if unknown format.
347*4882a593Smuzhiyun  */
snd_pcm_format_width(snd_pcm_format_t format)348*4882a593Smuzhiyun int snd_pcm_format_width(snd_pcm_format_t format)
349*4882a593Smuzhiyun {
350*4882a593Smuzhiyun 	int val;
351*4882a593Smuzhiyun 	if (!valid_format(format))
352*4882a593Smuzhiyun 		return -EINVAL;
353*4882a593Smuzhiyun 	if ((val = pcm_formats[(INT)format].width) == 0)
354*4882a593Smuzhiyun 		return -EINVAL;
355*4882a593Smuzhiyun 	return val;
356*4882a593Smuzhiyun }
357*4882a593Smuzhiyun EXPORT_SYMBOL(snd_pcm_format_width);
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun /**
360*4882a593Smuzhiyun  * snd_pcm_format_physical_width - return the physical bit-width of the format
361*4882a593Smuzhiyun  * @format: the format to check
362*4882a593Smuzhiyun  *
363*4882a593Smuzhiyun  * Return: The physical bit-width of the format, or a negative error code
364*4882a593Smuzhiyun  * if unknown format.
365*4882a593Smuzhiyun  */
snd_pcm_format_physical_width(snd_pcm_format_t format)366*4882a593Smuzhiyun int snd_pcm_format_physical_width(snd_pcm_format_t format)
367*4882a593Smuzhiyun {
368*4882a593Smuzhiyun 	int val;
369*4882a593Smuzhiyun 	if (!valid_format(format))
370*4882a593Smuzhiyun 		return -EINVAL;
371*4882a593Smuzhiyun 	if ((val = pcm_formats[(INT)format].phys) == 0)
372*4882a593Smuzhiyun 		return -EINVAL;
373*4882a593Smuzhiyun 	return val;
374*4882a593Smuzhiyun }
375*4882a593Smuzhiyun EXPORT_SYMBOL(snd_pcm_format_physical_width);
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun /**
378*4882a593Smuzhiyun  * snd_pcm_format_size - return the byte size of samples on the given format
379*4882a593Smuzhiyun  * @format: the format to check
380*4882a593Smuzhiyun  * @samples: sampling rate
381*4882a593Smuzhiyun  *
382*4882a593Smuzhiyun  * Return: The byte size of the given samples for the format, or a
383*4882a593Smuzhiyun  * negative error code if unknown format.
384*4882a593Smuzhiyun  */
snd_pcm_format_size(snd_pcm_format_t format,size_t samples)385*4882a593Smuzhiyun ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples)
386*4882a593Smuzhiyun {
387*4882a593Smuzhiyun 	int phys_width = snd_pcm_format_physical_width(format);
388*4882a593Smuzhiyun 	if (phys_width < 0)
389*4882a593Smuzhiyun 		return -EINVAL;
390*4882a593Smuzhiyun 	return samples * phys_width / 8;
391*4882a593Smuzhiyun }
392*4882a593Smuzhiyun EXPORT_SYMBOL(snd_pcm_format_size);
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun /**
395*4882a593Smuzhiyun  * snd_pcm_format_silence_64 - return the silent data in 8 bytes array
396*4882a593Smuzhiyun  * @format: the format to check
397*4882a593Smuzhiyun  *
398*4882a593Smuzhiyun  * Return: The format pattern to fill or %NULL if error.
399*4882a593Smuzhiyun  */
snd_pcm_format_silence_64(snd_pcm_format_t format)400*4882a593Smuzhiyun const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format)
401*4882a593Smuzhiyun {
402*4882a593Smuzhiyun 	if (!valid_format(format))
403*4882a593Smuzhiyun 		return NULL;
404*4882a593Smuzhiyun 	if (! pcm_formats[(INT)format].phys)
405*4882a593Smuzhiyun 		return NULL;
406*4882a593Smuzhiyun 	return pcm_formats[(INT)format].silence;
407*4882a593Smuzhiyun }
408*4882a593Smuzhiyun EXPORT_SYMBOL(snd_pcm_format_silence_64);
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun /**
411*4882a593Smuzhiyun  * snd_pcm_format_set_silence - set the silence data on the buffer
412*4882a593Smuzhiyun  * @format: the PCM format
413*4882a593Smuzhiyun  * @data: the buffer pointer
414*4882a593Smuzhiyun  * @samples: the number of samples to set silence
415*4882a593Smuzhiyun  *
416*4882a593Smuzhiyun  * Sets the silence data on the buffer for the given samples.
417*4882a593Smuzhiyun  *
418*4882a593Smuzhiyun  * Return: Zero if successful, or a negative error code on failure.
419*4882a593Smuzhiyun  */
snd_pcm_format_set_silence(snd_pcm_format_t format,void * data,unsigned int samples)420*4882a593Smuzhiyun int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int samples)
421*4882a593Smuzhiyun {
422*4882a593Smuzhiyun 	int width;
423*4882a593Smuzhiyun 	unsigned char *dst;
424*4882a593Smuzhiyun 	const unsigned char *pat;
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun 	if (!valid_format(format))
427*4882a593Smuzhiyun 		return -EINVAL;
428*4882a593Smuzhiyun 	if (samples == 0)
429*4882a593Smuzhiyun 		return 0;
430*4882a593Smuzhiyun 	width = pcm_formats[(INT)format].phys; /* physical width */
431*4882a593Smuzhiyun 	pat = pcm_formats[(INT)format].silence;
432*4882a593Smuzhiyun 	if (!width || !pat)
433*4882a593Smuzhiyun 		return -EINVAL;
434*4882a593Smuzhiyun 	/* signed or 1 byte data */
435*4882a593Smuzhiyun 	if (pcm_formats[(INT)format].signd == 1 || width <= 8) {
436*4882a593Smuzhiyun 		unsigned int bytes = samples * width / 8;
437*4882a593Smuzhiyun 		memset(data, *pat, bytes);
438*4882a593Smuzhiyun 		return 0;
439*4882a593Smuzhiyun 	}
440*4882a593Smuzhiyun 	/* non-zero samples, fill using a loop */
441*4882a593Smuzhiyun 	width /= 8;
442*4882a593Smuzhiyun 	dst = data;
443*4882a593Smuzhiyun #if 0
444*4882a593Smuzhiyun 	while (samples--) {
445*4882a593Smuzhiyun 		memcpy(dst, pat, width);
446*4882a593Smuzhiyun 		dst += width;
447*4882a593Smuzhiyun 	}
448*4882a593Smuzhiyun #else
449*4882a593Smuzhiyun 	/* a bit optimization for constant width */
450*4882a593Smuzhiyun 	switch (width) {
451*4882a593Smuzhiyun 	case 2:
452*4882a593Smuzhiyun 		while (samples--) {
453*4882a593Smuzhiyun 			memcpy(dst, pat, 2);
454*4882a593Smuzhiyun 			dst += 2;
455*4882a593Smuzhiyun 		}
456*4882a593Smuzhiyun 		break;
457*4882a593Smuzhiyun 	case 3:
458*4882a593Smuzhiyun 		while (samples--) {
459*4882a593Smuzhiyun 			memcpy(dst, pat, 3);
460*4882a593Smuzhiyun 			dst += 3;
461*4882a593Smuzhiyun 		}
462*4882a593Smuzhiyun 		break;
463*4882a593Smuzhiyun 	case 4:
464*4882a593Smuzhiyun 		while (samples--) {
465*4882a593Smuzhiyun 			memcpy(dst, pat, 4);
466*4882a593Smuzhiyun 			dst += 4;
467*4882a593Smuzhiyun 		}
468*4882a593Smuzhiyun 		break;
469*4882a593Smuzhiyun 	case 8:
470*4882a593Smuzhiyun 		while (samples--) {
471*4882a593Smuzhiyun 			memcpy(dst, pat, 8);
472*4882a593Smuzhiyun 			dst += 8;
473*4882a593Smuzhiyun 		}
474*4882a593Smuzhiyun 		break;
475*4882a593Smuzhiyun 	}
476*4882a593Smuzhiyun #endif
477*4882a593Smuzhiyun 	return 0;
478*4882a593Smuzhiyun }
479*4882a593Smuzhiyun EXPORT_SYMBOL(snd_pcm_format_set_silence);
480*4882a593Smuzhiyun 
481*4882a593Smuzhiyun /**
482*4882a593Smuzhiyun  * snd_pcm_hw_limit_rates - determine rate_min/rate_max fields
483*4882a593Smuzhiyun  * @hw: the pcm hw instance
484*4882a593Smuzhiyun  *
485*4882a593Smuzhiyun  * Determines the rate_min and rate_max fields from the rates bits of
486*4882a593Smuzhiyun  * the given hw.
487*4882a593Smuzhiyun  *
488*4882a593Smuzhiyun  * Return: Zero if successful.
489*4882a593Smuzhiyun  */
snd_pcm_hw_limit_rates(struct snd_pcm_hardware * hw)490*4882a593Smuzhiyun int snd_pcm_hw_limit_rates(struct snd_pcm_hardware *hw)
491*4882a593Smuzhiyun {
492*4882a593Smuzhiyun 	int i;
493*4882a593Smuzhiyun 	for (i = 0; i < (int)snd_pcm_known_rates.count; i++) {
494*4882a593Smuzhiyun 		if (hw->rates & (1 << i)) {
495*4882a593Smuzhiyun 			hw->rate_min = snd_pcm_known_rates.list[i];
496*4882a593Smuzhiyun 			break;
497*4882a593Smuzhiyun 		}
498*4882a593Smuzhiyun 	}
499*4882a593Smuzhiyun 	for (i = (int)snd_pcm_known_rates.count - 1; i >= 0; i--) {
500*4882a593Smuzhiyun 		if (hw->rates & (1 << i)) {
501*4882a593Smuzhiyun 			hw->rate_max = snd_pcm_known_rates.list[i];
502*4882a593Smuzhiyun 			break;
503*4882a593Smuzhiyun 		}
504*4882a593Smuzhiyun 	}
505*4882a593Smuzhiyun 	return 0;
506*4882a593Smuzhiyun }
507*4882a593Smuzhiyun EXPORT_SYMBOL(snd_pcm_hw_limit_rates);
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun /**
510*4882a593Smuzhiyun  * snd_pcm_rate_to_rate_bit - converts sample rate to SNDRV_PCM_RATE_xxx bit
511*4882a593Smuzhiyun  * @rate: the sample rate to convert
512*4882a593Smuzhiyun  *
513*4882a593Smuzhiyun  * Return: The SNDRV_PCM_RATE_xxx flag that corresponds to the given rate, or
514*4882a593Smuzhiyun  * SNDRV_PCM_RATE_KNOT for an unknown rate.
515*4882a593Smuzhiyun  */
snd_pcm_rate_to_rate_bit(unsigned int rate)516*4882a593Smuzhiyun unsigned int snd_pcm_rate_to_rate_bit(unsigned int rate)
517*4882a593Smuzhiyun {
518*4882a593Smuzhiyun 	unsigned int i;
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun 	for (i = 0; i < snd_pcm_known_rates.count; i++)
521*4882a593Smuzhiyun 		if (snd_pcm_known_rates.list[i] == rate)
522*4882a593Smuzhiyun 			return 1u << i;
523*4882a593Smuzhiyun 	return SNDRV_PCM_RATE_KNOT;
524*4882a593Smuzhiyun }
525*4882a593Smuzhiyun EXPORT_SYMBOL(snd_pcm_rate_to_rate_bit);
526*4882a593Smuzhiyun 
527*4882a593Smuzhiyun /**
528*4882a593Smuzhiyun  * snd_pcm_rate_bit_to_rate - converts SNDRV_PCM_RATE_xxx bit to sample rate
529*4882a593Smuzhiyun  * @rate_bit: the rate bit to convert
530*4882a593Smuzhiyun  *
531*4882a593Smuzhiyun  * Return: The sample rate that corresponds to the given SNDRV_PCM_RATE_xxx flag
532*4882a593Smuzhiyun  * or 0 for an unknown rate bit.
533*4882a593Smuzhiyun  */
snd_pcm_rate_bit_to_rate(unsigned int rate_bit)534*4882a593Smuzhiyun unsigned int snd_pcm_rate_bit_to_rate(unsigned int rate_bit)
535*4882a593Smuzhiyun {
536*4882a593Smuzhiyun 	unsigned int i;
537*4882a593Smuzhiyun 
538*4882a593Smuzhiyun 	for (i = 0; i < snd_pcm_known_rates.count; i++)
539*4882a593Smuzhiyun 		if ((1u << i) == rate_bit)
540*4882a593Smuzhiyun 			return snd_pcm_known_rates.list[i];
541*4882a593Smuzhiyun 	return 0;
542*4882a593Smuzhiyun }
543*4882a593Smuzhiyun EXPORT_SYMBOL(snd_pcm_rate_bit_to_rate);
544*4882a593Smuzhiyun 
snd_pcm_rate_mask_sanitize(unsigned int rates)545*4882a593Smuzhiyun static unsigned int snd_pcm_rate_mask_sanitize(unsigned int rates)
546*4882a593Smuzhiyun {
547*4882a593Smuzhiyun 	if (rates & SNDRV_PCM_RATE_CONTINUOUS)
548*4882a593Smuzhiyun 		return SNDRV_PCM_RATE_CONTINUOUS;
549*4882a593Smuzhiyun 	else if (rates & SNDRV_PCM_RATE_KNOT)
550*4882a593Smuzhiyun 		return SNDRV_PCM_RATE_KNOT;
551*4882a593Smuzhiyun 	return rates;
552*4882a593Smuzhiyun }
553*4882a593Smuzhiyun 
554*4882a593Smuzhiyun /**
555*4882a593Smuzhiyun  * snd_pcm_rate_mask_intersect - computes the intersection between two rate masks
556*4882a593Smuzhiyun  * @rates_a: The first rate mask
557*4882a593Smuzhiyun  * @rates_b: The second rate mask
558*4882a593Smuzhiyun  *
559*4882a593Smuzhiyun  * This function computes the rates that are supported by both rate masks passed
560*4882a593Smuzhiyun  * to the function. It will take care of the special handling of
561*4882a593Smuzhiyun  * SNDRV_PCM_RATE_CONTINUOUS and SNDRV_PCM_RATE_KNOT.
562*4882a593Smuzhiyun  *
563*4882a593Smuzhiyun  * Return: A rate mask containing the rates that are supported by both rates_a
564*4882a593Smuzhiyun  * and rates_b.
565*4882a593Smuzhiyun  */
snd_pcm_rate_mask_intersect(unsigned int rates_a,unsigned int rates_b)566*4882a593Smuzhiyun unsigned int snd_pcm_rate_mask_intersect(unsigned int rates_a,
567*4882a593Smuzhiyun 	unsigned int rates_b)
568*4882a593Smuzhiyun {
569*4882a593Smuzhiyun 	rates_a = snd_pcm_rate_mask_sanitize(rates_a);
570*4882a593Smuzhiyun 	rates_b = snd_pcm_rate_mask_sanitize(rates_b);
571*4882a593Smuzhiyun 
572*4882a593Smuzhiyun 	if (rates_a & SNDRV_PCM_RATE_CONTINUOUS)
573*4882a593Smuzhiyun 		return rates_b;
574*4882a593Smuzhiyun 	else if (rates_b & SNDRV_PCM_RATE_CONTINUOUS)
575*4882a593Smuzhiyun 		return rates_a;
576*4882a593Smuzhiyun 	else if (rates_a & SNDRV_PCM_RATE_KNOT)
577*4882a593Smuzhiyun 		return rates_b;
578*4882a593Smuzhiyun 	else if (rates_b & SNDRV_PCM_RATE_KNOT)
579*4882a593Smuzhiyun 		return rates_a;
580*4882a593Smuzhiyun 	return rates_a & rates_b;
581*4882a593Smuzhiyun }
582*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(snd_pcm_rate_mask_intersect);
583*4882a593Smuzhiyun 
584*4882a593Smuzhiyun /**
585*4882a593Smuzhiyun  * snd_pcm_rate_range_to_bits - converts rate range to SNDRV_PCM_RATE_xxx bit
586*4882a593Smuzhiyun  * @rate_min: the minimum sample rate
587*4882a593Smuzhiyun  * @rate_max: the maximum sample rate
588*4882a593Smuzhiyun  *
589*4882a593Smuzhiyun  * This function has an implicit assumption: the rates in the given range have
590*4882a593Smuzhiyun  * only the pre-defined rates like 44100 or 16000.
591*4882a593Smuzhiyun  *
592*4882a593Smuzhiyun  * Return: The SNDRV_PCM_RATE_xxx flag that corresponds to the given rate range,
593*4882a593Smuzhiyun  * or SNDRV_PCM_RATE_KNOT for an unknown range.
594*4882a593Smuzhiyun  */
snd_pcm_rate_range_to_bits(unsigned int rate_min,unsigned int rate_max)595*4882a593Smuzhiyun unsigned int snd_pcm_rate_range_to_bits(unsigned int rate_min,
596*4882a593Smuzhiyun 	unsigned int rate_max)
597*4882a593Smuzhiyun {
598*4882a593Smuzhiyun 	unsigned int rates = 0;
599*4882a593Smuzhiyun 	int i;
600*4882a593Smuzhiyun 
601*4882a593Smuzhiyun 	for (i = 0; i < snd_pcm_known_rates.count; i++) {
602*4882a593Smuzhiyun 		if (snd_pcm_known_rates.list[i] >= rate_min
603*4882a593Smuzhiyun 			&& snd_pcm_known_rates.list[i] <= rate_max)
604*4882a593Smuzhiyun 			rates |= 1 << i;
605*4882a593Smuzhiyun 	}
606*4882a593Smuzhiyun 
607*4882a593Smuzhiyun 	if (!rates)
608*4882a593Smuzhiyun 		rates = SNDRV_PCM_RATE_KNOT;
609*4882a593Smuzhiyun 
610*4882a593Smuzhiyun 	return rates;
611*4882a593Smuzhiyun }
612*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(snd_pcm_rate_range_to_bits);
613