summaryrefslogtreecommitdiff
path: root/include/sound/pcm_params.h
blob: ba184f49f7e18cfcb25863392cad654fe7b99561 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
/* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef __SOUND_PCM_PARAMS_H
#define __SOUND_PCM_PARAMS_H

/*
 *  PCM params helpers
 *  Copyright (c) by Abramo Bagnara <abramo@alsa-project.org>
 */

#include <sound/pcm.h>

int snd_pcm_hw_param_first(struct snd_pcm_substream *pcm, 
			   struct snd_pcm_hw_params *params,
			   snd_pcm_hw_param_t var, int *dir);
int snd_pcm_hw_param_last(struct snd_pcm_substream *pcm, 
			  struct snd_pcm_hw_params *params,
			  snd_pcm_hw_param_t var, int *dir);
int snd_pcm_hw_param_value(const struct snd_pcm_hw_params *params,
			   snd_pcm_hw_param_t var, int *dir);

#define SNDRV_MASK_BITS	64	/* we use so far 64bits only */
#define SNDRV_MASK_SIZE	(SNDRV_MASK_BITS / 32)
#define MASK_OFS(i)	((i) >> 5)
#define MASK_BIT(i)	(1U << ((i) & 31))

static inline void snd_mask_none(struct snd_mask *mask)
{
	memset(mask, 0, sizeof(*mask));
}

static inline void snd_mask_any(struct snd_mask *mask)
{
	memset(mask, 0xff, SNDRV_MASK_SIZE * sizeof(u_int32_t));
}

static inline int snd_mask_empty(const struct snd_mask *mask)
{
	int i;
	for (i = 0; i < SNDRV_MASK_SIZE; i++)
		if (mask->bits[i])
			return 0;
	return 1;
}

static inline unsigned int snd_mask_min(const struct snd_mask *mask)
{
	int i;
	for (i = 0; i < SNDRV_MASK_SIZE; i++) {
		if (mask->bits[i])
			return __ffs(mask->bits[i]) + (i << 5);
	}
	return 0;
}

static inline unsigned int snd_mask_max(const struct snd_mask *mask)
{
	int i;
	for (i = SNDRV_MASK_SIZE - 1; i >= 0; i--) {
		if (mask->bits[i])
			return __fls(mask->bits[i]) + (i << 5);
	}
	return 0;
}

static inline void snd_mask_set(struct snd_mask *mask, unsigned int val)
{
	mask->bits[MASK_OFS(val)] |= MASK_BIT(val);
}

/* Most of drivers need only this one */
static inline void snd_mask_set_format(struct snd_mask *mask,
				       snd_pcm_format_t format)
{
	snd_mask_set(mask, (__force unsigned int)format);
}

static inline void snd_mask_reset(struct snd_mask *mask, unsigned int val)
{
	mask->bits[MASK_OFS(val)] &= ~MASK_BIT(val);
}

static inline void snd_mask_set_range(struct snd_mask *mask,
				      unsigned int from, unsigned int to)
{
	unsigned int i;
	for (i = from; i <= to; i++)
		mask->bits[MASK_OFS(i)] |= MASK_BIT(i);
}

static inline void snd_mask_reset_range(struct snd_mask *mask,
					unsigned int from, unsigned int to)
{
	unsigned int i;
	for (i = from; i <= to; i++)
		mask->bits[MASK_OFS(i)] &= ~MASK_BIT(i);
}

static inline void snd_mask_leave(struct snd_mask *mask, unsigned int val)
{
	unsigned int v;
	v = mask->bits[MASK_OFS(val)] & MASK_BIT(val);
	snd_mask_none(mask);
	mask->bits[MASK_OFS(val)] = v;
}

static inline void snd_mask_intersect(struct snd_mask *mask,
				      const struct snd_mask *v)
{
	int i;
	for (i = 0; i < SNDRV_MASK_SIZE; i++)
		mask->bits[i] &= v->bits[i];
}

static inline int snd_mask_eq(const struct snd_mask *mask,
			      const struct snd_mask *v)
{
	return ! memcmp(mask, v, SNDRV_MASK_SIZE * sizeof(u_int32_t));
}

static inline void snd_mask_copy(struct snd_mask *mask,
				 const struct snd_mask *v)
{
	*mask = *v;
}

static inline int snd_mask_test(const struct snd_mask *mask, unsigned int val)
{
	return mask->bits[MASK_OFS(val)] & MASK_BIT(val);
}

/* Most of drivers need only this one */
static inline int snd_mask_test_format(const struct snd_mask *mask,
				       snd_pcm_format_t format)
{
	return snd_mask_test(mask, (__force unsigned int)format);
}

static inline int snd_mask_single(const struct snd_mask *mask)
{
	int i, c = 0;
	for (i = 0; i < SNDRV_MASK_SIZE; i++) {
		if (! mask->bits[i])
			continue;
		if (mask->bits[i] & (mask->bits[i] - 1))
			return 0;
		if (c)
			return 0;
		c++;
	}
	return 1;
}

static inline int snd_mask_refine(struct snd_mask *mask,
				  const struct snd_mask *v)
{
	struct snd_mask old;
	snd_mask_copy(&old, mask);
	snd_mask_intersect(mask, v);
	if (snd_mask_empty(mask))
		return -EINVAL;
	return !snd_mask_eq(mask, &old);
}

static inline int snd_mask_refine_first(struct snd_mask *mask)
{
	if (snd_mask_single(mask))
		return 0;
	snd_mask_leave(mask, snd_mask_min(mask));
	return 1;
}

static inline int snd_mask_refine_last(struct snd_mask *mask)
{
	if (snd_mask_single(mask))
		return 0;
	snd_mask_leave(mask, snd_mask_max(mask));
	return 1;
}

static inline int snd_mask_refine_min(struct snd_mask *mask, unsigned int val)
{
	if (snd_mask_min(mask) >= val)
		return 0;
	snd_mask_reset_range(mask, 0, val - 1);
	if (snd_mask_empty(mask))
		return -EINVAL;
	return 1;
}

static inline int snd_mask_refine_max(struct snd_mask *mask, unsigned int val)
{
	if (snd_mask_max(mask) <= val)
		return 0;
	snd_mask_reset_range(mask, val + 1, SNDRV_MASK_BITS);
	if (snd_mask_empty(mask))
		return -EINVAL;
	return 1;
}

static inline int snd_mask_refine_set(struct snd_mask *mask, unsigned int val)
{
	int changed;
	changed = !snd_mask_single(mask);
	snd_mask_leave(mask, val);
	if (snd_mask_empty(mask))
		return -EINVAL;
	return changed;
}

static inline int snd_mask_value(const struct snd_mask *mask)
{
	return snd_mask_min(mask);
}

static inline void snd_interval_any(struct snd_interval *i)
{
	i->min = 0;
	i->openmin = 0;
	i->max = UINT_MAX;
	i->openmax = 0;
	i->integer = 0;
	i->empty = 0;
}

static inline void snd_interval_none(struct snd_interval *i)
{
	i->empty = 1;
}

static inline int snd_interval_checkempty(const struct snd_interval *i)
{
	return (i->min > i->max ||
		(i->min == i->max && (i->openmin || i->openmax)));
}

static inline int snd_interval_empty(const struct snd_interval *i)
{
	return i->empty;
}

static inline int snd_interval_single(const struct snd_interval *i)
{
	return (i->min == i->max || 
		(i->min + 1 == i->max && (i->openmin || i->openmax)));
}

static inline int snd_interval_value(const struct snd_interval *i)
{
	if (i->openmin && !i->openmax)
		return i->max;
	return i->min;
}

static inline int snd_interval_min(const struct snd_interval *i)
{
	return i->min;
}

static inline int snd_interval_max(const struct snd_interval *i)
{
	unsigned int v;
	v = i->max;
	if (i->openmax)
		v--;
	return v;
}

static inline int snd_interval_test(const struct snd_interval *i, unsigned int val)
{
	return !((i->min > val || (i->min == val && i->openmin) ||
		  i->max < val || (i->max == val && i->openmax)));
}

static inline void snd_interval_copy(struct snd_interval *d, const struct snd_interval *s)
{
	*d = *s;
}

static inline int snd_interval_setinteger(struct snd_interval *i)
{
	if (i->integer)
		return 0;
	if (i->openmin && i->openmax && i->min == i->max)
		return -EINVAL;
	i->integer = 1;
	return 1;
}

static inline int snd_interval_eq(const struct snd_interval *i1, const struct snd_interval *i2)
{
	if (i1->empty)
		return i2->empty;
	if (i2->empty)
		return i1->empty;
	return i1->min == i2->min && i1->openmin == i2->openmin &&
		i1->max == i2->max && i1->openmax == i2->openmax;
}

/**
 * params_access - get the access type from the hw params
 * @p: hw params
 */
static inline snd_pcm_access_t params_access(const struct snd_pcm_hw_params *p)
{
	return (__force snd_pcm_access_t)snd_mask_min(hw_param_mask_c(p,
		SNDRV_PCM_HW_PARAM_ACCESS));
}

/**
 * params_format - get the sample format from the hw params
 * @p: hw params
 */
static inline snd_pcm_format_t params_format(const struct snd_pcm_hw_params *p)
{
	return (__force snd_pcm_format_t)snd_mask_min(hw_param_mask_c(p,
		SNDRV_PCM_HW_PARAM_FORMAT));
}

/**
 * params_subformat - get the sample subformat from the hw params
 * @p: hw params
 */
static inline snd_pcm_subformat_t
params_subformat(const struct snd_pcm_hw_params *p)
{
	return (__force snd_pcm_subformat_t)snd_mask_min(hw_param_mask_c(p,
		SNDRV_PCM_HW_PARAM_SUBFORMAT));
}

/**
 * params_period_bytes - get the period size (in bytes) from the hw params
 * @p: hw params
 */
static inline unsigned int
params_period_bytes(const struct snd_pcm_hw_params *p)
{
	return hw_param_interval_c(p, SNDRV_PCM_HW_PARAM_PERIOD_BYTES)->min;
}

/**
 * params_width - get the number of bits of the sample format from the hw params
 * @p: hw params
 *
 * This function returns the number of bits per sample that the selected sample
 * format of the hw params has.
 */
static inline int params_width(const struct snd_pcm_hw_params *p)
{
	return snd_pcm_format_width(params_format(p));
}

/*
 * params_physical_width - get the storage size of the sample format from the hw params
 * @p: hw params
 *
 * This functions returns the number of bits per sample that the selected sample
 * format of the hw params takes up in memory. This will be equal or larger than
 * params_width().
 */
static inline int params_physical_width(const struct snd_pcm_hw_params *p)
{
	return snd_pcm_format_physical_width(params_format(p));
}

static inline void
params_set_format(struct snd_pcm_hw_params *p, snd_pcm_format_t fmt)
{
	snd_mask_set_format(hw_param_mask(p, SNDRV_PCM_HW_PARAM_FORMAT), fmt);
}

#endif /* __SOUND_PCM_PARAMS_H */