• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  PCM - Params functions
3  *  Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
4  *
5  *
6  *   This library is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU Lesser General Public License as
8  *   published by the Free Software Foundation; either version 2.1 of
9  *   the License, or (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU Lesser General Public License for more details.
15  *
16  *   You should have received a copy of the GNU Lesser General Public
17  *   License along with this library; if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21 
22 #include "pcm_local.h"
23 
24 #ifndef NDEBUG
25 /*
26  * dump hw_params when $LIBASOUND_DEBUG is set to >= 1
27  */
dump_hw_params(snd_pcm_hw_params_t * params,const char * type,snd_pcm_hw_param_t var,unsigned int val,int err)28 static void dump_hw_params(snd_pcm_hw_params_t *params, const char *type,
29 			   snd_pcm_hw_param_t var, unsigned int val, int err)
30 {
31 	const char *verbose = getenv("LIBASOUND_DEBUG");
32 	snd_output_t *out;
33 
34 	if (! verbose || ! *verbose || atoi(verbose) < 1)
35 		return;
36 	if (snd_output_stdio_attach(&out, stderr, 0) < 0)
37 		return;
38 	fprintf(stderr, "ALSA ERROR hw_params: %s (%s)\n",
39 		type, snd_pcm_hw_param_name(var));
40 	fprintf(stderr, "           value = ");
41 	switch (var) {
42 	case SND_PCM_HW_PARAM_ACCESS:
43 		fprintf(stderr, "%s", snd_pcm_access_name(val));
44 		break;
45 	case SND_PCM_HW_PARAM_FORMAT:
46 		fprintf(stderr, "%s", snd_pcm_format_name(val));
47 		break;
48 	case SND_PCM_HW_PARAM_SUBFORMAT:
49 		fprintf(stderr, "%s", snd_pcm_subformat_name(val));
50 		break;
51 	default:
52 		fprintf(stderr, "%u", val);
53 	}
54 	fprintf(stderr, " : %s\n", snd_strerror(err));
55 	snd_pcm_hw_params_dump(params, out);
56 	snd_output_close(out);
57 }
58 #else
dump_hw_params(snd_pcm_hw_params_t * params,const char * type,snd_pcm_hw_param_t var,unsigned int val,int err)59 static inline void dump_hw_params(snd_pcm_hw_params_t *params, const char *type,
60 				  snd_pcm_hw_param_t var, unsigned int val, int err)
61 {
62 }
63 #endif
64 
hw_is_mask(snd_pcm_hw_param_t var)65 static inline int hw_is_mask(snd_pcm_hw_param_t var)
66 {
67 #if SND_PCM_HW_PARAM_FIRST_MASK == 0
68 	return var <= SND_PCM_HW_PARAM_LAST_MASK;
69 #else
70 	return var >= SND_PCM_HW_PARAM_FIRST_MASK &&
71 		var <= SND_PCM_HW_PARAM_LAST_MASK;
72 #endif
73 }
74 
hw_is_interval(snd_pcm_hw_param_t var)75 static inline int hw_is_interval(snd_pcm_hw_param_t var)
76 {
77 	return var >= SND_PCM_HW_PARAM_FIRST_INTERVAL &&
78 		var <= SND_PCM_HW_PARAM_LAST_INTERVAL;
79 }
80 
81 #define hw_param_mask(params,var) \
82 	&((params)->masks[(var) - SND_PCM_HW_PARAM_FIRST_MASK])
83 
84 #define hw_param_interval(params,var) \
85 	&((params)->intervals[(var) - SND_PCM_HW_PARAM_FIRST_INTERVAL])
86 
87 #define hw_param_mask_c hw_param_mask
88 #define hw_param_interval_c hw_param_interval
89 
_snd_pcm_hw_param_any(snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var)90 static void _snd_pcm_hw_param_any(snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var)
91 {
92 	if (hw_is_mask(var)) {
93 		snd_mask_any(hw_param_mask(params, var));
94 		params->cmask |= 1 << var;
95 		params->rmask |= 1 << var;
96 		return;
97 	}
98 	if (hw_is_interval(var)) {
99 		snd_interval_any(hw_param_interval(params, var));
100 		params->cmask |= 1 << var;
101 		params->rmask |= 1 << var;
102 		return;
103 	}
104 	assert(0);
105 }
106 
snd_pcm_hw_param_any(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var)107 int snd_pcm_hw_param_any(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
108 			 snd_pcm_hw_param_t var)
109 {
110 	_snd_pcm_hw_param_any(params, var);
111 	return snd_pcm_hw_refine(pcm, params);
112 }
113 
_snd_pcm_hw_params_any(snd_pcm_hw_params_t * params)114 void _snd_pcm_hw_params_any(snd_pcm_hw_params_t *params)
115 {
116 	unsigned int k;
117 	memset(params, 0, sizeof(*params));
118 	for (k = SND_PCM_HW_PARAM_FIRST_MASK; k <= SND_PCM_HW_PARAM_LAST_MASK; k++)
119 		_snd_pcm_hw_param_any(params, k);
120 	for (k = SND_PCM_HW_PARAM_FIRST_INTERVAL; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; k++)
121 		_snd_pcm_hw_param_any(params, k);
122 	params->rmask = ~0U;
123 	params->cmask = 0;
124 	params->info = ~0U;
125 }
126 
127 /* Return the value for field PAR if it's fixed in configuration space
128    defined by PARAMS. Return -EINVAL otherwise
129 */
snd_pcm_hw_param_get(const snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var,unsigned int * val,int * dir)130 int snd_pcm_hw_param_get(const snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var,
131 			 unsigned int *val, int *dir)
132 {
133 	if (hw_is_mask(var)) {
134 		const snd_mask_t *mask = hw_param_mask_c(params, var);
135 		if (snd_mask_empty(mask) || !snd_mask_single(mask))
136 			return -EINVAL;
137 		if (dir)
138 			*dir = 0;
139 		if (val)
140 			*val = snd_mask_value(mask);
141 		return 0;
142 	} else if (hw_is_interval(var)) {
143 		const snd_interval_t *i = hw_param_interval_c(params, var);
144 		if (snd_interval_empty(i) || !snd_interval_single(i))
145 			return -EINVAL;
146 		if (dir)
147 			*dir = i->openmin;
148 		if (val)
149 			*val = snd_interval_value(i);
150 		return 0;
151 	}
152 	assert(0);
153 	return -EINVAL;
154 }
155 
156 /* Return the minimum value for field PAR. */
snd_pcm_hw_param_get_min(const snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var,unsigned int * val,int * dir)157 int snd_pcm_hw_param_get_min(const snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var,
158 			     unsigned int *val, int *dir)
159 {
160 	if (hw_is_mask(var)) {
161 		const snd_mask_t *m = hw_param_mask_c(params, var);
162 		assert(!snd_mask_empty(m));
163 		if (dir)
164 			*dir = 0;
165 		if (val)
166 			*val = snd_mask_min(m);
167 		return 0;
168 	} else if (hw_is_interval(var)) {
169 		const snd_interval_t *i = hw_param_interval_c(params, var);
170 		assert(!snd_interval_empty(i));
171 		if (dir)
172 			*dir = i->openmin;
173 		if (val)
174 			*val = snd_interval_min(i);
175 		return 0;
176 	}
177 	assert(0);
178 	return 0;
179 }
180 
181 /* Return the maximum value for field PAR. */
snd_pcm_hw_param_get_max(const snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var,unsigned int * val,int * dir)182 int snd_pcm_hw_param_get_max(const snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var,
183 			     unsigned int *val, int *dir)
184 {
185 	if (hw_is_mask(var)) {
186 		const snd_mask_t *m = hw_param_mask_c(params, var);
187 		assert(!snd_mask_empty(m));
188 		if (dir)
189 			*dir = 0;
190 		if (val)
191 			*val = snd_mask_max(m);
192 		return 0;
193 	} else if (hw_is_interval(var)) {
194 		const snd_interval_t *i = hw_param_interval_c(params, var);
195 		assert(!snd_interval_empty(i));
196 		if (dir)
197 			*dir = - (int) i->openmax;
198 		if (val)
199 			*val = snd_interval_max(i);
200 		return 0;
201 	}
202 	assert(0);
203 	return 0;
204 }
205 
206 /* Return the mask for field PAR.
207    This function can be called only for SND_PCM_HW_PARAM_ACCESS,
208    SND_PCM_HW_PARAM_FORMAT, SND_PCM_HW_PARAM_SUBFORMAT. */
snd_pcm_hw_param_get_mask(const snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var)209 const snd_mask_t *snd_pcm_hw_param_get_mask(const snd_pcm_hw_params_t *params,
210 					   snd_pcm_hw_param_t var)
211 {
212 	assert(hw_is_mask(var));
213 	return hw_param_mask_c(params, var);
214 }
215 
216 /* Return the interval for field PAR.
217    This function cannot be called for SND_PCM_HW_PARAM_ACCESS,
218    SND_PCM_HW_PARAM_FORMAT, SND_PCM_HW_PARAM_SUBFORMAT. */
snd_pcm_hw_param_get_interval(const snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var)219 const snd_interval_t *snd_pcm_hw_param_get_interval(const snd_pcm_hw_params_t *params,
220 						  snd_pcm_hw_param_t var)
221 {
222 	assert(hw_is_interval(var));
223 	return hw_param_interval_c(params, var);
224 }
225 
226 /* --- Refinement functions --- */
227 
_snd_pcm_hw_param_set_interval(snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var,const snd_interval_t * val)228 int _snd_pcm_hw_param_set_interval(snd_pcm_hw_params_t *params,
229 				   snd_pcm_hw_param_t var,
230 				   const snd_interval_t *val)
231 {
232 	int changed;
233 	assert(hw_is_interval(var));
234 	changed = snd_interval_refine(hw_param_interval(params, var), val);
235 	if (changed) {
236 		params->cmask |= 1 << var;
237 		params->rmask |= 1 << var;
238 	}
239 	return changed;
240 }
241 
_snd_pcm_hw_param_set_empty(snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var)242 void _snd_pcm_hw_param_set_empty(snd_pcm_hw_params_t *params,
243 				 snd_pcm_hw_param_t var)
244 {
245 	if (hw_is_mask(var)) {
246 		snd_mask_none(hw_param_mask(params, var));
247 		params->cmask |= 1 << var;
248 		params->rmask |= 1 << var;
249 	} else if (hw_is_interval(var)) {
250 		snd_interval_none(hw_param_interval(params, var));
251 		params->cmask |= 1 << var;
252 		params->rmask |= 1 << var;
253 	} else {
254 		assert(0);
255 	}
256 }
257 
_snd_pcm_hw_param_set_integer(snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var)258 static int _snd_pcm_hw_param_set_integer(snd_pcm_hw_params_t *params,
259 					 snd_pcm_hw_param_t var)
260 {
261 	int changed;
262 	assert(hw_is_interval(var));
263 	changed = snd_interval_setinteger(hw_param_interval(params, var));
264 	if (changed) {
265 		params->cmask |= 1 << var;
266 		params->rmask |= 1 << var;
267 	}
268 	return changed;
269 }
270 
271 /* Inside configuration space defined by PARAMS remove from PAR all
272    non integer values. Reduce configuration space accordingly.
273    Return -EINVAL if the configuration space is empty
274 */
snd_pcm_hw_param_set_integer(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,snd_set_mode_t mode,snd_pcm_hw_param_t var)275 int snd_pcm_hw_param_set_integer(snd_pcm_t *pcm,
276 				 snd_pcm_hw_params_t *params,
277 				 snd_set_mode_t mode,
278 				 snd_pcm_hw_param_t var)
279 {
280 	snd_pcm_hw_params_t save;
281 	int err;
282 	switch (mode) {
283 	case SND_CHANGE:
284 		break;
285 	case SND_TRY:
286 		save = *params;
287 		break;
288 	case SND_TEST:
289 		save = *params;
290 		params = &save;
291 		break;
292 	default:
293 		assert(0);
294 		return -EINVAL;
295 	}
296 	err = _snd_pcm_hw_param_set_integer(params, var);
297 	if (err < 0)
298 		goto _fail;
299 	if (params->rmask) {
300 		err = snd_pcm_hw_refine(pcm, params);
301 		if (err < 0)
302 			goto _fail;
303 	}
304 	return 0;
305  _fail:
306 	if (mode == SND_TRY)
307 		*params = save;
308 	return err;
309 }
310 
_snd_pcm_hw_param_set_first(snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var)311 static int _snd_pcm_hw_param_set_first(snd_pcm_hw_params_t *params,
312 				       snd_pcm_hw_param_t var)
313 {
314 	int changed;
315 	if (hw_is_mask(var))
316 		changed = snd_mask_refine_first(hw_param_mask(params, var));
317 	else if (hw_is_interval(var))
318 		changed = snd_interval_refine_first(hw_param_interval(params, var));
319 	else {
320 		assert(0);
321 		return -EINVAL;
322 	}
323 	if (changed > 0) {
324 		params->cmask |= 1 << var;
325 		params->rmask |= 1 << var;
326 	}
327 	return changed;
328 }
329 
330 
331 /* Inside configuration space defined by PARAMS remove from PAR all
332    values > minimum. Reduce configuration space accordingly.
333    Return the minimum.
334 */
snd_pcm_hw_param_set_first(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var,unsigned int * rval,int * dir)335 int snd_pcm_hw_param_set_first(snd_pcm_t *pcm,
336 			       snd_pcm_hw_params_t *params,
337 			       snd_pcm_hw_param_t var,
338 			       unsigned int *rval, int *dir)
339 {
340 	int err;
341 
342 	err = _snd_pcm_hw_param_set_first(params, var);
343 	if (err < 0)
344 		return err;
345 	if (params->rmask) {
346 		err = snd_pcm_hw_refine(pcm, params);
347 		if (err < 0)
348 			return err;
349 	}
350 	return snd_pcm_hw_param_get(params, var, rval, dir);
351 }
352 
_snd_pcm_hw_param_set_last(snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var)353 static int _snd_pcm_hw_param_set_last(snd_pcm_hw_params_t *params,
354 				      snd_pcm_hw_param_t var)
355 {
356 	int changed;
357 	if (hw_is_mask(var))
358 		changed = snd_mask_refine_last(hw_param_mask(params, var));
359 	else if (hw_is_interval(var))
360 		changed = snd_interval_refine_last(hw_param_interval(params, var));
361 	else {
362 		assert(0);
363 		return -EINVAL;
364 	}
365 	if (changed > 0) {
366 		params->cmask |= 1 << var;
367 		params->rmask |= 1 << var;
368 	}
369 	return changed;
370 }
371 
372 
373 /* Inside configuration space defined by PARAMS remove from PAR all
374    values < maximum. Reduce configuration space accordingly.
375    Return the maximum.
376 */
snd_pcm_hw_param_set_last(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var,unsigned int * rval,int * dir)377 int snd_pcm_hw_param_set_last(snd_pcm_t *pcm,
378 			      snd_pcm_hw_params_t *params,
379 			      snd_pcm_hw_param_t var,
380 			      unsigned int *rval, int *dir)
381 {
382 	int err;
383 
384 	err = _snd_pcm_hw_param_set_last(params, var);
385 	if (err < 0)
386 		return err;
387 	if (params->rmask) {
388 		err = snd_pcm_hw_refine(pcm, params);
389 		if (err < 0)
390 			return err;
391 	}
392 	return snd_pcm_hw_param_get(params, var, rval, dir);
393 }
394 
_snd_pcm_hw_param_set_min(snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var,unsigned int val,int dir)395 int _snd_pcm_hw_param_set_min(snd_pcm_hw_params_t *params,
396 			      snd_pcm_hw_param_t var, unsigned int val, int dir)
397 {
398 	int changed;
399 	int openmin = 0;
400 	if (dir) {
401 		if (dir > 0) {
402 			openmin = 1;
403 		} else if (dir < 0) {
404 			if (val > 0) {
405 				openmin = 1;
406 				val--;
407 			}
408 		}
409 	}
410 	if (hw_is_mask(var))
411 		changed = snd_mask_refine_min(hw_param_mask(params, var), val + !!openmin);
412 	else if (hw_is_interval(var))
413 		changed = snd_interval_refine_min(hw_param_interval(params, var), val, openmin);
414 	else {
415 		assert(0);
416 		return -EINVAL;
417 	}
418 	if (changed) {
419 		params->cmask |= 1 << var;
420 		params->rmask |= 1 << var;
421 	}
422 	return changed;
423 }
424 
425 /* Inside configuration space defined by PARAMS remove from PAR all
426    values < VAL. Reduce configuration space accordingly.
427    Return new minimum or -EINVAL if the configuration space is empty
428 */
snd_pcm_hw_param_set_min(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,snd_set_mode_t mode,snd_pcm_hw_param_t var,unsigned int * val,int * dir)429 int snd_pcm_hw_param_set_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
430 			     snd_set_mode_t mode,
431 			     snd_pcm_hw_param_t var, unsigned int *val, int *dir)
432 {
433 	snd_pcm_hw_params_t save;
434 	int err;
435 	switch (mode) {
436 	case SND_CHANGE:
437 		break;
438 	case SND_TRY:
439 		save = *params;
440 		break;
441 	case SND_TEST:
442 		save = *params;
443 		params = &save;
444 		break;
445 	default:
446 		assert(0);
447 		return -EINVAL;
448 	}
449 	err = _snd_pcm_hw_param_set_min(params, var, *val, dir ? *dir : 0);
450 	if (err < 0)
451 		goto _fail;
452 	if ((mode != SND_TEST || hw_is_interval(var)) && params->rmask) {
453 		err = snd_pcm_hw_refine(pcm, params);
454 		if (err < 0)
455 			goto _fail;
456 		if (snd_pcm_hw_param_empty(params, var)) {
457 			err = -ENOENT;
458 			goto _fail;
459 		}
460 	}
461 	return snd_pcm_hw_param_get_min(params, var, val, dir);
462  _fail:
463 	if (mode == SND_TRY)
464 		*params = save;
465 	if (err < 0 && mode == SND_TRY)
466 		dump_hw_params(params, "set_min", var, *val, err);
467 	return err;
468 }
469 
_snd_pcm_hw_param_set_max(snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var,unsigned int val,int dir)470 int _snd_pcm_hw_param_set_max(snd_pcm_hw_params_t *params,
471 			      snd_pcm_hw_param_t var, unsigned int val, int dir)
472 {
473 	int changed;
474 	int openmax = 0;
475 	if (dir) {
476 		if (dir < 0) {
477 			openmax = 1;
478 		} else if (dir > 0) {
479 			openmax = 1;
480 			val++;
481 		}
482 	}
483 	if (hw_is_mask(var)) {
484 		if (val == 0 && openmax) {
485 		snd_mask_none(hw_param_mask(params, var));
486 			changed = -EINVAL;
487 		} else
488 			changed = snd_mask_refine_max(hw_param_mask(params, var), val - !!openmax);
489 	} else if (hw_is_interval(var))
490 		changed = snd_interval_refine_max(hw_param_interval(params, var), val, openmax);
491 	else {
492 		assert(0);
493 		return -EINVAL;
494 	}
495 	if (changed) {
496 		params->cmask |= 1 << var;
497 		params->rmask |= 1 << var;
498 	}
499 	return changed;
500 }
501 
502 /* Inside configuration space defined by PARAMS remove from PAR all
503    values >= VAL + 1. Reduce configuration space accordingly.
504    Return new maximum or -EINVAL if the configuration space is empty
505 */
snd_pcm_hw_param_set_max(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,snd_set_mode_t mode,snd_pcm_hw_param_t var,unsigned int * val,int * dir)506 int snd_pcm_hw_param_set_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
507 			     snd_set_mode_t mode,
508 			     snd_pcm_hw_param_t var, unsigned int *val, int *dir)
509 {
510 	snd_pcm_hw_params_t save;
511 	int err;
512 	switch (mode) {
513 	case SND_CHANGE:
514 		break;
515 	case SND_TRY:
516 		save = *params;
517 		break;
518 	case SND_TEST:
519 		save = *params;
520 		params = &save;
521 		break;
522 	default:
523 		assert(0);
524 		return -EINVAL;
525 	}
526 	err = _snd_pcm_hw_param_set_max(params, var, *val, dir ? *dir : 0);
527 	if (err < 0)
528 		goto _fail;
529 	if ((mode != SND_TEST || hw_is_interval(var)) && params->rmask) {
530 		err = snd_pcm_hw_refine(pcm, params);
531 		if (err < 0)
532 			goto _fail;
533 		if (snd_pcm_hw_param_empty(params, var)) {
534 			err = -ENOENT;
535 			goto _fail;
536 		}
537 	}
538 	return snd_pcm_hw_param_get_max(params, var, val, dir);
539  _fail:
540 	if (mode == SND_TRY)
541 		*params = save;
542 	if (err < 0 && mode == SND_TRY)
543 		dump_hw_params(params, "set_max", var, *val, err);
544 	return err;
545 }
546 
_snd_pcm_hw_param_set_minmax(snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var,unsigned int min,int mindir,unsigned int max,int maxdir)547 int _snd_pcm_hw_param_set_minmax(snd_pcm_hw_params_t *params,
548 				 snd_pcm_hw_param_t var,
549 				 unsigned int min, int mindir,
550 				 unsigned int max, int maxdir)
551 {
552 	int changed, c1, c2;
553 	int openmin = 0, openmax = 0;
554 	if (mindir) {
555 		if (mindir > 0) {
556 			openmin = 1;
557 		} else if (mindir < 0) {
558 			if (min > 0) {
559 				openmin = 1;
560 				min--;
561 			}
562 		}
563 	}
564 	if (maxdir) {
565 		if (maxdir < 0) {
566 			openmax = 1;
567 		} else if (maxdir > 0) {
568 			openmax = 1;
569 			max++;
570 		}
571 	}
572 	if (hw_is_mask(var)) {
573 		snd_mask_t *mask = hw_param_mask(params, var);
574 		if (max == 0 && openmax) {
575 			snd_mask_none(mask);
576 			changed = -EINVAL;
577 		} else {
578 			c1 = snd_mask_refine_min(mask, min + !!openmin);
579 			if (c1 < 0)
580 				changed = c1;
581 			else {
582 				c2 = snd_mask_refine_max(mask, max - !!openmax);
583 				if (c2 < 0)
584 					changed = c2;
585 				else
586 					changed = (c1 || c2);
587 			}
588 		}
589 	}
590 	else if (hw_is_interval(var)) {
591 		snd_interval_t *i = hw_param_interval(params, var);
592 		c1 = snd_interval_refine_min(i, min, openmin);
593 		if (c1 < 0)
594 			changed = c1;
595 		else {
596 			c2 = snd_interval_refine_max(i, max, openmax);
597 			if (c2 < 0)
598 				changed = c2;
599 			else
600 				changed = (c1 || c2);
601 		}
602 	} else {
603 		assert(0);
604 		return -EINVAL;
605 	}
606 	if (changed) {
607 		params->cmask |= 1 << var;
608 		params->rmask |= 1 << var;
609 	}
610 	return changed;
611 }
612 
613 /* Inside configuration space defined by PARAMS remove from PAR all
614    values < MIN and all values > MAX. Reduce configuration space accordingly.
615    Return 0 or -EINVAL if the configuration space is empty
616 */
snd_pcm_hw_param_set_minmax(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,snd_set_mode_t mode,snd_pcm_hw_param_t var,unsigned int * min,int * mindir,unsigned int * max,int * maxdir)617 int snd_pcm_hw_param_set_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
618 				snd_set_mode_t mode,
619 				snd_pcm_hw_param_t var,
620 				unsigned int *min, int *mindir,
621 				unsigned int *max, int *maxdir)
622 {
623 	snd_pcm_hw_params_t save;
624 	int err;
625 	switch (mode) {
626 	case SND_CHANGE:
627 		break;
628 	case SND_TRY:
629 		save = *params;
630 		break;
631 	case SND_TEST:
632 		save = *params;
633 		params = &save;
634 		break;
635 	default:
636 		assert(0);
637 		return -EINVAL;
638 	}
639 	err = _snd_pcm_hw_param_set_minmax(params, var,
640 					   *min, mindir ? *mindir : 0,
641 					   *max, maxdir ? *maxdir : 0);
642 	if (err < 0)
643 		goto _fail;
644 	if ((mode != SND_TEST || hw_is_interval(var)) && params->rmask) {
645 		err = snd_pcm_hw_refine(pcm, params);
646 		if (err < 0)
647 			goto _fail;
648 	}
649 	err = snd_pcm_hw_param_get_min(params, var, min, mindir);
650 	if (err < 0)
651 		return err;
652 	return snd_pcm_hw_param_get_max(params, var, max, maxdir);
653  _fail:
654 	if (mode == SND_TRY)
655 		*params = save;
656 	if (err < 0)
657 		dump_hw_params(params, "set_minmax", var, *min, err);
658 	return err;
659 }
660 
_snd_pcm_hw_param_set(snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var,unsigned int val,int dir)661 int _snd_pcm_hw_param_set(snd_pcm_hw_params_t *params,
662 			  snd_pcm_hw_param_t var, unsigned int val, int dir)
663 {
664 	int changed;
665 	if (hw_is_mask(var)) {
666 		snd_mask_t *m = hw_param_mask(params, var);
667 		if (val == 0 && dir < 0) {
668 			changed = -EINVAL;
669 			snd_mask_none(m);
670 		} else {
671 			if (dir > 0)
672 				val++;
673 			else if (dir < 0)
674 				val--;
675 			changed = snd_mask_refine_set(hw_param_mask(params, var), val);
676 		}
677 	} else if (hw_is_interval(var)) {
678 		snd_interval_t *i = hw_param_interval(params, var);
679 		if (val == 0 && dir < 0) {
680 			changed = -EINVAL;
681 			snd_interval_none(i);
682 		} else if (dir == 0)
683 			changed = snd_interval_refine_set(i, val);
684 		else {
685 			snd_interval_t t;
686 			t.openmin = 1;
687 			t.openmax = 1;
688 			t.empty = 0;
689 			t.integer = 0;
690 			if (dir < 0) {
691 				t.min = val - 1;
692 				t.max = val;
693 			} else {
694 				t.min = val;
695 				t.max = val+1;
696 			}
697 			changed = snd_interval_refine(i, &t);
698 		}
699 	} else {
700 		assert(0);
701 		return -EINVAL;
702 	}
703 	if (changed) {
704 		params->cmask |= 1 << var;
705 		params->rmask |= 1 << var;
706 	}
707 	return changed;
708 }
709 
710 /* Inside configuration space defined by PARAMS remove from PAR all
711    values != VAL. Reduce configuration space accordingly.
712    Return -EINVAL if the configuration space is empty
713 */
snd_pcm_hw_param_set(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,snd_set_mode_t mode,snd_pcm_hw_param_t var,unsigned int val,int dir)714 int snd_pcm_hw_param_set(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
715 			 snd_set_mode_t mode,
716 			 snd_pcm_hw_param_t var, unsigned int val, int dir)
717 {
718 	snd_pcm_hw_params_t save;
719 	int err;
720 	switch (mode) {
721 	case SND_CHANGE:
722 		break;
723 	case SND_TRY:
724 		save = *params;
725 		break;
726 	case SND_TEST:
727 		save = *params;
728 		params = &save;
729 		break;
730 	default:
731 		assert(0);
732 		return -EINVAL;
733 	}
734 	err = _snd_pcm_hw_param_set(params, var, val, dir);
735 	if (err < 0)
736 		goto _fail;
737 	if ((mode != SND_TEST || hw_is_interval(var)) && params->rmask) {
738 		err = snd_pcm_hw_refine(pcm, params);
739 		if (err < 0)
740 			goto _fail;
741 	}
742 	return 0;
743  _fail:
744 	if (mode == SND_TRY)
745 		*params = save;
746 	if (err < 0 && mode == SND_TRY)
747 		dump_hw_params(params, "set", var, val, err);
748 	return err;
749 }
750 
_snd_pcm_hw_param_set_mask(snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var,const snd_mask_t * val)751 int _snd_pcm_hw_param_set_mask(snd_pcm_hw_params_t *params,
752 			       snd_pcm_hw_param_t var, const snd_mask_t *val)
753 {
754 	int changed;
755 	assert(hw_is_mask(var));
756 	changed = snd_mask_refine(hw_param_mask(params, var), val);
757 	if (changed) {
758 		params->cmask |= 1 << var;
759 		params->rmask |= 1 << var;
760 	}
761 	return changed;
762 }
763 
764 /* Inside configuration space defined by PARAMS remove from PAR all values
765    not contained in MASK. Reduce configuration space accordingly.
766    This function can be called only for SND_PCM_HW_PARAM_ACCESS,
767    SND_PCM_HW_PARAM_FORMAT, SND_PCM_HW_PARAM_SUBFORMAT.
768    Return 0 on success or -EINVAL
769    if the configuration space is empty
770 */
snd_pcm_hw_param_set_mask(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,snd_set_mode_t mode,snd_pcm_hw_param_t var,const snd_mask_t * val)771 int snd_pcm_hw_param_set_mask(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
772 			      snd_set_mode_t mode,
773 			      snd_pcm_hw_param_t var, const snd_mask_t *val)
774 {
775 	snd_pcm_hw_params_t save;
776 	int err;
777 	switch (mode) {
778 	case SND_CHANGE:
779 		break;
780 	case SND_TRY:
781 		save = *params;
782 		break;
783 	case SND_TEST:
784 		save = *params;
785 		params = &save;
786 		break;
787 	default:
788 		assert(0);
789 		return -EINVAL;
790 	}
791 	err = _snd_pcm_hw_param_set_mask(params, var, val);
792 	if (err < 0)
793 		goto _fail;
794 	if (mode != SND_TEST && params->rmask) {
795 		err = snd_pcm_hw_refine(pcm, params);
796 		if (err < 0)
797 			goto _fail;
798 	}
799 	return 0;
800  _fail:
801 	if (mode == SND_TRY)
802 		*params = save;
803 	return err;
804 }
805 
806 /* Inside configuration space defined by PARAMS set PAR to the available value
807    nearest to VAL. Reduce configuration space accordingly.
808    This function cannot be called for SND_PCM_HW_PARAM_ACCESS,
809    SND_PCM_HW_PARAM_FORMAT, SND_PCM_HW_PARAM_SUBFORMAT.
810    Return the value found.
811  */
snd_pcm_hw_param_set_near(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var,unsigned int * val,int * dir)812 int snd_pcm_hw_param_set_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
813 			      snd_pcm_hw_param_t var,
814 			      unsigned int *val, int *dir)
815 {
816 	snd_pcm_hw_params_t save;
817 	int err;
818 	unsigned int best = *val, saved_min;
819 	int last = 0;
820 	unsigned int min, max;
821 	int mindir, maxdir;
822 	int valdir = dir ? *dir : 0;
823 	snd_interval_t *i;
824 	/* FIXME */
825 	if (best > INT_MAX)
826 		best = INT_MAX;
827 	min = max = best;
828 	mindir = maxdir = valdir;
829 	if (maxdir > 0)
830 		maxdir = 0;
831 	else if (maxdir == 0)
832 		maxdir = -1;
833 	else {
834 		maxdir = 1;
835 		max--;
836 	}
837 	save = *params;
838 	saved_min = min;
839 	err = snd_pcm_hw_param_set_min(pcm, params, SND_CHANGE, var, &min, &mindir);
840 
841 	i = hw_param_interval(params, var);
842 	if (!snd_interval_empty(i) && snd_interval_single(i)) {
843 		err = snd_pcm_hw_param_get_min(params, var, val, dir);
844 		if (err < 0)
845 			dump_hw_params(params, "set_near", var, *val, err);
846 		return err;
847 	}
848 
849 	if (err >= 0) {
850 		snd_pcm_hw_params_t params1;
851 		if (min == saved_min && mindir == valdir)
852 			goto _end;
853 		params1 = save;
854 		err = snd_pcm_hw_param_set_max(pcm, &params1, SND_CHANGE, var, &max, &maxdir);
855 		if (err < 0)
856 			goto _end;
857 		if (boundary_nearer(max, maxdir, best, valdir, min, mindir)) {
858 			*params = params1;
859 			last = 1;
860 		}
861 	} else {
862 		*params = save;
863 		err = snd_pcm_hw_param_set_max(pcm, params, SND_CHANGE, var, &max, &maxdir);
864 		if (err < 0) {
865 			dump_hw_params(params, "set_near", var, *val, err);
866 			return err;
867 		}
868 		last = 1;
869 	}
870  _end:
871 	if (last)
872 		err = snd_pcm_hw_param_set_last(pcm, params, var, val, dir);
873 	else
874 		err = snd_pcm_hw_param_set_first(pcm, params, var, val, dir);
875 	if (err < 0)
876 		dump_hw_params(params, "set_near", var, *val, err);
877 	return err;
878 }
879 
880 #if 0
881 /* Inside configuration space defined by PARAMS set PAR to the available value
882    nearest to BEST after VAL (on equal difference values less than BEST are
883    returned first).
884    Reduce configuration space accordingly.
885    This function cannot be called for SND_PCM_HW_PARAM_ACCESS,
886    SND_PCM_HW_PARAM_FORMAT, SND_PCM_HW_PARAM_SUBFORMAT.
887    Return the value found.
888  */
889 int snd_pcm_hw_param_set_next(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
890 			      snd_pcm_hw_param_t var,
891 			      unsigned int best, int bestdir,
892 			      unsigned int val, int *dir)
893 {
894 	snd_pcm_hw_params_t save;
895 	int v, err;
896 	int last = 0;
897 	int min, max;
898 	int mindir, maxdir;
899 	int diff, diffdir;
900 	int valdir = dir ? *dir : 0;
901 	/* FIXME */
902 	if (best > INT_MAX)
903 		best = INT_MAX;
904 	boundary_sub(val, valdir, best, bestdir, &diff, &diffdir);
905 	if (diff < 0 || (diff == 0 && diffdir < 0)) {
906 		min = best - diff;
907 		mindir = bestdir - diffdir;
908 		max = val;
909 		maxdir = bestdir - 1;
910 	} else {
911 		min = val;
912 		mindir = bestdir + 1;
913 		max = best + diff;
914 		maxdir = bestdir + diffdir + 1;
915 	}
916 	min += mindir / 2;
917 	mindir %= 2;
918 	max += maxdir / 2;
919 	maxdir %= 2;
920 	save = *params;
921 	if (min >= 0 &&
922 	    (err = snd_pcm_hw_param_set_min(pcm, params, SND_CHANGE, var, &min, &mindir)) >= 0) {
923 		snd_pcm_hw_params_t params1;
924 		if (max < 0)
925 			goto _end;
926 		params1 = save;
927 		err = snd_pcm_hw_param_set_max(pcm, &params1, SND_CHANGE, var, &max, &maxdir);
928 		if (err < 0)
929 			goto _end;
930 		if (boundary_nearer(max, maxdir, best, bestdir, min, mindir)) {
931 			*params = params1;
932 			last = 1;
933 		}
934 	} else {
935 		if (max < 0)
936 			return -EINVAL;
937 		*params = save;
938 		err = snd_pcm_hw_param_set_max(pcm, params, SND_CHANGE, var, &max, &maxdir);
939 		if (err < 0)
940 			return max;
941 		last = 1;
942 	}
943  _end:
944 	if (last)
945 		v = snd_pcm_hw_param_set_last(pcm, params, var, dir);
946 	else
947 		v = snd_pcm_hw_param_set_first(pcm, params, var, dir);
948 	assert(v >= 0);
949 	return v;
950 }
951 #endif
952 
snd_pcm_hw_param_set_near_minmax(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var,unsigned int min,int * mindir,unsigned int max,int * maxdir)953 static int snd_pcm_hw_param_set_near_minmax(snd_pcm_t *pcm,
954 					    snd_pcm_hw_params_t *params,
955 					    snd_pcm_hw_param_t var,
956 					    unsigned int min, int *mindir,
957 					    unsigned int max, int *maxdir)
958 {
959 	snd_pcm_hw_params_t tmp;
960 	int err;
961 	if (!boundary_lt(min, *mindir, max, *maxdir))
962 		return snd_pcm_hw_param_set_near(pcm, params, var, &min, mindir);
963 	tmp = *params;
964 	err = snd_pcm_hw_param_set_near(pcm, &tmp, var, &min, mindir);
965 	if (err < 0)
966 		return err;
967 	if (boundary_lt(min, *mindir, max, *maxdir)) {
968 		tmp = *params;
969 		err = snd_pcm_hw_param_set_near(pcm, &tmp, var, &max, maxdir);
970 	} else {
971 		max = min;
972 		*maxdir = *mindir;
973 	}
974 	err = snd_pcm_hw_param_set_minmax(pcm, params, SND_CHANGE, var, &min, mindir,
975 					  &max, maxdir);
976 	if (err < 0)
977 		return err;
978 	return 0;
979 }
980 
snd_pcm_hw_param_refine_near(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var,const snd_pcm_hw_params_t * src)981 int snd_pcm_hw_param_refine_near(snd_pcm_t *pcm,
982 				 snd_pcm_hw_params_t *params,
983 				 snd_pcm_hw_param_t var,
984 				 const snd_pcm_hw_params_t *src)
985 {
986 	unsigned int min, max;
987 	int mindir, maxdir, err;
988 
989 	if ((err = snd_pcm_hw_param_get_min(src, var, &min, &mindir)) < 0)
990 		return err;
991 	if ((err = snd_pcm_hw_param_get_max(src, var, &max, &maxdir)) < 0)
992 		return err;
993 	if ((err = snd_pcm_hw_param_set_near_minmax(pcm, params, var,
994 						    min, &mindir, max, &maxdir)) < 0)
995 		return err;
996 	return 0;
997 }
998 
snd_pcm_hw_param_refine_multiple(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var,const snd_pcm_hw_params_t * src)999 int snd_pcm_hw_param_refine_multiple(snd_pcm_t *pcm,
1000 				     snd_pcm_hw_params_t *params,
1001 				     snd_pcm_hw_param_t var,
1002 				     const snd_pcm_hw_params_t *src)
1003 {
1004 	const snd_interval_t *it = hw_param_interval_c(src, var);
1005 	const snd_interval_t *st = hw_param_interval_c(params, var);
1006 	if (snd_interval_single(it)) {
1007 		unsigned int best = snd_interval_min(it), cur, prev;
1008 		cur = best;
1009 		for (;;) {
1010 			if (st->max < cur || (st->max == cur && st->openmax))
1011 				break;
1012 			if (it->min <= cur && ! (it->min == cur && st->openmin)) {
1013 				if (! snd_pcm_hw_param_set(pcm, params, SND_TRY, var, cur, 0))
1014 					return 0; /* ok */
1015 			}
1016 			prev = cur;
1017 			cur += best;
1018 			if (cur <= prev)
1019 				break;
1020 		}
1021 	}
1022 	return snd_pcm_hw_param_refine_near(pcm, params, var, src);
1023 }
1024 
1025 /* ---- end of refinement functions ---- */
1026 
snd_pcm_hw_param_empty(const snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var)1027 int snd_pcm_hw_param_empty(const snd_pcm_hw_params_t *params,
1028 			   snd_pcm_hw_param_t var)
1029 {
1030 	if (hw_is_mask(var))
1031 		return snd_mask_empty(hw_param_mask_c(params, var));
1032 	if (hw_is_interval(var))
1033 		return snd_interval_empty(hw_param_interval_c(params, var));
1034 	assert(0);
1035 	return -EINVAL;
1036 }
1037 
snd_pcm_hw_param_always_eq(const snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var,const snd_pcm_hw_params_t * params1)1038 int snd_pcm_hw_param_always_eq(const snd_pcm_hw_params_t *params,
1039 			       snd_pcm_hw_param_t var,
1040 			       const snd_pcm_hw_params_t *params1)
1041 {
1042 	if (hw_is_mask(var))
1043 		return snd_mask_always_eq(hw_param_mask_c(params, var),
1044 					  hw_param_mask_c(params1, var));
1045 	if (hw_is_interval(var))
1046 		return snd_interval_always_eq(hw_param_interval_c(params, var),
1047 					      hw_param_interval_c(params1, var));
1048 	assert(0);
1049 	return -EINVAL;
1050 }
1051 
snd_pcm_hw_param_never_eq(const snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var,const snd_pcm_hw_params_t * params1)1052 int snd_pcm_hw_param_never_eq(const snd_pcm_hw_params_t *params,
1053 			      snd_pcm_hw_param_t var,
1054 			      const snd_pcm_hw_params_t *params1)
1055 {
1056 	if (hw_is_mask(var))
1057 		return snd_mask_never_eq(hw_param_mask_c(params, var),
1058 					 hw_param_mask_c(params1, var));
1059 	if (hw_is_interval(var))
1060 		return snd_interval_never_eq(hw_param_interval_c(params, var),
1061 					     hw_param_interval_c(params1, var));
1062 	assert(0);
1063 	return -EINVAL;
1064 }
1065 
1066 #if 0
1067 #define CHOOSE_DEBUG
1068 #endif
1069 
1070 /* Choose one configuration from configuration space defined by PARAMS
1071    The configuration chosen is that obtained fixing in this order:
1072    first access
1073    first format
1074    first subformat
1075    min channels
1076    min rate
1077    min period time
1078    max buffer size
1079    min tick time
1080 */
snd_pcm_hw_params_choose(snd_pcm_t * pcm,snd_pcm_hw_params_t * params)1081 static int snd_pcm_hw_params_choose(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
1082 {
1083 	int err;
1084 #ifdef CHOOSE_DEBUG
1085 	snd_output_t *log;
1086 	snd_output_stdio_attach(&log, stderr, 0);
1087 	snd_output_printf(log, "CHOOSE called:\n");
1088 	snd_pcm_hw_params_dump(params, log);
1089 #endif
1090 
1091 	err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_ACCESS, NULL, 0);
1092 	if (err < 0)
1093 		return err;
1094 	err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_FORMAT, NULL, 0);
1095 	if (err < 0)
1096 		return err;
1097 	err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_SUBFORMAT, NULL, 0);
1098 	if (err < 0)
1099 		return err;
1100 	err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_CHANNELS, NULL, 0);
1101 	if (err < 0)
1102 		return err;
1103 	err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_RATE, NULL, 0);
1104 	if (err < 0)
1105 		return err;
1106 	if (pcm->minperiodtime > 0) {
1107 		unsigned int min, max;
1108 		int dir = 1;
1109 		err = snd_pcm_hw_param_get_min(params, SND_PCM_HW_PARAM_PERIOD_TIME, &min, &dir);
1110 		if (err >= 0)
1111 			err = snd_pcm_hw_param_get_max(params, SND_PCM_HW_PARAM_PERIOD_TIME, &max, &dir);
1112 		if (err >= 0 && (long)min < pcm->minperiodtime &&
1113 			        (long)max > pcm->minperiodtime) {
1114 			min = pcm->minperiodtime; dir = 1;
1115 			snd_pcm_hw_param_set_min(pcm, params, SND_CHANGE, SND_PCM_HW_PARAM_PERIOD_TIME, &min, &dir);
1116 		}
1117 	}
1118 	if (pcm->compat) {
1119 		/* old mode */
1120 		err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_PERIOD_TIME, NULL, 0);
1121 		if (err < 0)
1122 			return err;
1123 		err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_PERIOD_SIZE, NULL, 0);
1124 		if (err < 0)
1125 			return err;
1126 		err = snd_pcm_hw_param_set_last(pcm, params, SND_PCM_HW_PARAM_BUFFER_SIZE, NULL, 0);
1127 		if (err < 0)
1128 			return err;
1129 	} else {
1130 		/* determine buffer size first */
1131 		err = snd_pcm_hw_param_set_last(pcm, params, SND_PCM_HW_PARAM_BUFFER_SIZE, NULL, 0);
1132 		if (err < 0)
1133 			return err;
1134 		err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_PERIOD_SIZE, NULL, 0);
1135 		if (err < 0)
1136 			return err;
1137 		err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_PERIOD_TIME, NULL, 0);
1138 		if (err < 0)
1139 			return err;
1140 	}
1141 	err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_TICK_TIME, NULL, 0);
1142 	if (err < 0)
1143 		return err;
1144 #ifdef CHOOSE_DEBUG
1145 	snd_output_printf(log, "choose done\n");
1146 	snd_pcm_hw_params_dump(params, log);
1147 	snd_output_close(log);
1148 #endif
1149 	return 0;
1150 }
1151 
1152 #if 0
1153 static unsigned int snd_pcm_hw_param_count(const snd_pcm_hw_params_t *params,
1154 					   snd_pcm_hw_param_t var)
1155 {
1156 	if (hw_is_mask(var)) {
1157 		const snd_mask_t *mask = hw_param_mask_c(params, var);
1158 		return snd_mask_count(mask);
1159 	}
1160 	if (hw_is_interval(var)) {
1161 		const snd_interval_t *i = hw_param_interval_c(params, var);
1162 		return snd_interval_max(i) - snd_interval_min(i) + 1;
1163 	}
1164 	assert(0);
1165 	return 0;
1166 }
1167 #endif
1168 
_snd_pcm_hw_param_refine(snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var,const snd_pcm_hw_params_t * src)1169 int _snd_pcm_hw_param_refine(snd_pcm_hw_params_t *params,
1170 			     snd_pcm_hw_param_t var,
1171 			     const snd_pcm_hw_params_t *src)
1172 {
1173 	int changed = 0;
1174 	if (hw_is_mask(var)) {
1175 		snd_mask_t *d = hw_param_mask(params, var);
1176 		const snd_mask_t *s = hw_param_mask_c(src, var);
1177 		changed = snd_mask_refine(d, s);
1178 	} else if (hw_is_interval(var)) {
1179 		snd_interval_t *d = hw_param_interval(params, var);
1180 		const snd_interval_t *s = hw_param_interval_c(src, var);
1181 		changed = snd_interval_refine(d, s);
1182 	} else
1183 		return 0; /* NOP / reserved */
1184 	if (changed) {
1185 		params->cmask |= 1 << var;
1186 		params->rmask |= 1 << var;
1187 	}
1188 	return changed;
1189 }
1190 
1191 #if 0
1192 static void _snd_pcm_hw_param_copy(snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var,
1193 				   const snd_pcm_hw_params_t *src)
1194 {
1195 	if (hw_is_mask(var)) {
1196 		snd_mask_t *d = hw_param_mask(params, var);
1197 		const snd_mask_t *s = hw_param_mask_c(src, var);
1198 		snd_mask_copy(d, s);
1199 		params->cmask |= 1 << var;
1200 		params->rmask |= 1 << var;
1201 		return;
1202 	}
1203 	if (hw_is_interval(var)) {
1204 		snd_interval_t *d = hw_param_interval(params, var);
1205 		const snd_interval_t *s = hw_param_interval_c(src, var);
1206 		snd_interval_copy(d, s);
1207 		params->cmask |= 1 << var;
1208 		params->rmask |= 1 << var;
1209 		return;
1210 	}
1211 	assert(0);
1212 }
1213 #endif
1214 
snd_pcm_hw_param_dump(const snd_pcm_hw_params_t * params,snd_pcm_hw_param_t var,snd_output_t * out)1215 void snd_pcm_hw_param_dump(const snd_pcm_hw_params_t *params,
1216 			   snd_pcm_hw_param_t var, snd_output_t *out)
1217 {
1218 	if (hw_is_mask(var)) {
1219 		const snd_mask_t *mask = hw_param_mask_c(params, var);
1220 		if (snd_mask_empty(mask))
1221 			snd_output_puts(out, " NONE");
1222 		else if (snd_mask_full(mask))
1223 			snd_output_puts(out, " ALL");
1224 		else {
1225 			unsigned int k;
1226 			for (k = 0; k <= SND_MASK_MAX; ++k) {
1227 				if (snd_mask_test(mask, k)) {
1228 					const char *s;
1229 					switch (var) {
1230 					case SND_PCM_HW_PARAM_ACCESS:
1231 						s = snd_pcm_access_name(k);
1232 						break;
1233 					case SND_PCM_HW_PARAM_FORMAT:
1234 						s = snd_pcm_format_name(k);
1235 						break;
1236 					case SND_PCM_HW_PARAM_SUBFORMAT:
1237 						s = snd_pcm_subformat_name(k);
1238 						break;
1239 					default:
1240 						assert(0);
1241 						s = NULL;
1242 					}
1243 					if (s) {
1244 						snd_output_putc(out, ' ');
1245 						snd_output_puts(out, s);
1246 					}
1247 				}
1248 			}
1249 		}
1250 		return;
1251 	}
1252 	if (hw_is_interval(var)) {
1253 		snd_interval_print(hw_param_interval_c(params, var), out);
1254 		return;
1255 	}
1256 	assert(0);
1257 }
1258 
1259 #define HW_PARAM(v) [SND_PCM_HW_PARAM_##v] = #v
1260 
1261 static const char *const snd_pcm_hw_param_names[] = {
1262 	HW_PARAM(ACCESS),
1263 	HW_PARAM(FORMAT),
1264 	HW_PARAM(SUBFORMAT),
1265 	HW_PARAM(SAMPLE_BITS),
1266 	HW_PARAM(FRAME_BITS),
1267 	HW_PARAM(CHANNELS),
1268 	HW_PARAM(RATE),
1269 	HW_PARAM(PERIOD_TIME),
1270 	HW_PARAM(PERIOD_SIZE),
1271 	HW_PARAM(PERIOD_BYTES),
1272 	HW_PARAM(PERIODS),
1273 	HW_PARAM(BUFFER_TIME),
1274 	HW_PARAM(BUFFER_SIZE),
1275 	HW_PARAM(BUFFER_BYTES),
1276 	HW_PARAM(TICK_TIME),
1277 };
1278 
snd_pcm_hw_param_name(snd_pcm_hw_param_t param)1279 const char *snd_pcm_hw_param_name(snd_pcm_hw_param_t param)
1280 {
1281 	assert(param <= SND_PCM_HW_PARAM_LAST_INTERVAL);
1282 	return snd_pcm_hw_param_names[param];
1283 }
1284 
1285 #if 0
1286 /* Strategies */
1287 
1288 struct _snd_pcm_hw_strategy {
1289 	unsigned int badness_min, badness_max;
1290 	int (*choose_param)(const snd_pcm_hw_params_t *params,
1291 			    snd_pcm_t *pcm,
1292 			    const snd_pcm_hw_strategy_t *strategy);
1293 	int (*next_value)(snd_pcm_hw_params_t *params,
1294 			  unsigned int param,
1295 			  int value, int *dir,
1296 			  snd_pcm_t *pcm,
1297 			  const snd_pcm_hw_strategy_t *strategy);
1298 	int (*min_badness)(const snd_pcm_hw_params_t *params,
1299 			   unsigned int max_badness,
1300 			   snd_pcm_t *pcm,
1301 			   const snd_pcm_hw_strategy_t *strategy);
1302 	void *private_data;
1303 	void (*free)(snd_pcm_hw_strategy_t *strategy);
1304 };
1305 
1306 /* Independent badness */
1307 typedef struct _snd_pcm_hw_strategy_simple snd_pcm_hw_strategy_simple_t;
1308 
1309 struct _snd_pcm_hw_strategy_simple {
1310 	int valid;
1311 	unsigned int order;
1312 	int (*next_value)(snd_pcm_hw_params_t *params,
1313 			  unsigned int param,
1314 			  int value, int *dir,
1315 			  snd_pcm_t *pcm,
1316 			  const snd_pcm_hw_strategy_simple_t *par);
1317 	unsigned int (*min_badness)(const snd_pcm_hw_params_t *params,
1318 				    unsigned int param,
1319 				    snd_pcm_t *pcm,
1320 				    const snd_pcm_hw_strategy_simple_t *par);
1321 	void *private_data;
1322 	void (*free)(snd_pcm_hw_strategy_simple_t *strategy);
1323 };
1324 
1325 typedef struct _snd_pcm_hw_strategy_simple_near {
1326 	int best;
1327 	unsigned int mul;
1328 } snd_pcm_hw_strategy_simple_near_t;
1329 
1330 typedef struct _snd_pcm_hw_strategy_simple_choices {
1331 	unsigned int count;
1332 	/* choices need to be sorted on ascending badness */
1333 	snd_pcm_hw_strategy_simple_choices_list_t *choices;
1334 } snd_pcm_hw_strategy_simple_choices_t;
1335 
1336 int snd_pcm_hw_params_strategy(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
1337 			       const snd_pcm_hw_strategy_t *strategy,
1338 			       unsigned int badness_min,
1339 			       unsigned int badness_max)
1340 {
1341 	snd_pcm_hw_params_t best_params;
1342 	int var;
1343 	int value, dir;
1344 	unsigned int best_badness;
1345 	int badness = strategy->min_badness(params, badness_max, pcm, strategy);
1346 	snd_pcm_hw_params_t params1;
1347 #if 0
1348 	printf("\nBadness: %d\n", badness);
1349 	snd_pcm_hw_params_dump(params, stdout);
1350 #endif
1351 	if (badness < 0)
1352 		return badness;
1353 	if ((unsigned int)badness > badness_min)
1354 		badness_min = badness_min;
1355 	var = strategy->choose_param(params, pcm, strategy);
1356 	if (var < 0)
1357 		return badness;
1358 	best_badness = UINT_MAX;
1359 	value = -1;
1360 	while (1) {
1361 		params1 = *params;
1362 		value = strategy->next_value(&params1, var, value, &dir, pcm, strategy);
1363 		if (value < 0)
1364 			break;
1365 		badness = snd_pcm_hw_params_strategy(pcm, &params1, strategy, badness_min, badness_max);
1366 		if (badness >= 0) {
1367 			if ((unsigned int) badness <= badness_min) {
1368 				*params = params1;
1369 				return badness;
1370 			}
1371 			best_badness = badness;
1372 			best_params = params1;
1373 			badness_max = badness - 1;
1374 		}
1375 	}
1376 	if (best_badness == UINT_MAX) {
1377 		return -EINVAL;
1378 	}
1379 	*params = best_params;
1380 	return best_badness;
1381 }
1382 
1383 void snd_pcm_hw_strategy_simple_free(snd_pcm_hw_strategy_t *strategy)
1384 {
1385 	snd_pcm_hw_strategy_simple_t *pars = strategy->private_data;
1386 	int k;
1387 	for (k = 0; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; ++k) {
1388 		if (pars[k].valid && pars[k].free)
1389 			pars[k].free(&pars[k]);
1390 	}
1391 	free(pars);
1392 }
1393 
1394 int snd_pcm_hw_strategy_simple_choose_param(const snd_pcm_hw_params_t *params,
1395 					 snd_pcm_t *pcm ATTRIBUTE_UNUSED,
1396 					 const snd_pcm_hw_strategy_t *strategy)
1397 {
1398 	snd_pcm_hw_param_t var;
1399 	int best_var = -1;
1400 	const snd_pcm_hw_strategy_simple_t *pars = strategy->private_data;
1401 	unsigned int min_choices = UINT_MAX;
1402 	unsigned int min_order = UINT_MAX;
1403 	for (var = 0; var <= SND_PCM_HW_PARAM_LAST_INTERVAL; ++var) {
1404 		const snd_pcm_hw_strategy_simple_t *p = &pars[var];
1405 		unsigned int choices;
1406 		if (!p->valid)
1407 			continue;
1408 		choices = snd_pcm_hw_param_count(params, var);
1409 		if (choices == 1)
1410 			continue;
1411 		assert(choices != 0);
1412 		if (p->order < min_order ||
1413 		    (p->order == min_order &&
1414 		     choices < min_choices)) {
1415 			min_order = p->order;
1416 			min_choices = choices;
1417 			best_var = var;
1418 		}
1419 	}
1420 	return best_var;
1421 }
1422 
1423 int snd_pcm_hw_strategy_simple_next_value(snd_pcm_hw_params_t *params,
1424 					  snd_pcm_hw_param_t var,
1425 					  int value, int *dir,
1426 					  snd_pcm_t *pcm,
1427 					  const snd_pcm_hw_strategy_t *strategy)
1428 {
1429 	const snd_pcm_hw_strategy_simple_t *pars = strategy->private_data;
1430 	assert(pars[var].valid);
1431 	return pars[var].next_value(params, var, value, dir, pcm, &pars[var]);
1432 }
1433 
1434 
1435 int snd_pcm_hw_strategy_simple_min_badness(const snd_pcm_hw_params_t *params,
1436 					unsigned int max_badness,
1437 					snd_pcm_t *pcm,
1438 					const snd_pcm_hw_strategy_t *strategy)
1439 {
1440 	snd_pcm_hw_param_t var;
1441 	unsigned int badness = 0;
1442 	const snd_pcm_hw_strategy_simple_t *pars = strategy->private_data;
1443 	for (var = 0; var <= SND_PCM_HW_PARAM_LAST_INTERVAL; ++var) {
1444 		unsigned int b;
1445 		if (!pars[var].valid)
1446 			continue;
1447 		b = pars[var].min_badness(params, var, pcm, &pars[var]);
1448 		if (b > max_badness || max_badness - b < badness)
1449 			return -E2BIG;
1450 		badness += b;
1451 	}
1452 	return badness;
1453 }
1454 
1455 
1456 void snd_pcm_hw_strategy_simple_near_free(snd_pcm_hw_strategy_simple_t *par)
1457 {
1458 	snd_pcm_hw_strategy_simple_near_t *p = par->private_data;
1459 	free(p);
1460 }
1461 
1462 unsigned int snd_pcm_hw_strategy_simple_near_min_badness(const snd_pcm_hw_params_t *params,
1463 						      snd_pcm_hw_param_t var,
1464 						      snd_pcm_t *pcm,
1465 						      const snd_pcm_hw_strategy_simple_t *par)
1466 {
1467 	const snd_pcm_hw_strategy_simple_near_t *p = par->private_data;
1468 	snd_pcm_hw_params_t params1 = *params;
1469 	int value = snd_pcm_hw_param_set_near(pcm, &params1, var, p->best, 0);
1470 	int diff;
1471 	assert(value >= 0);
1472 	diff = p->best - value;
1473 	if (diff < 0)
1474 		diff = -diff;
1475 	return diff * p->mul;
1476 }
1477 
1478 int snd_pcm_hw_strategy_simple_near_next_value(snd_pcm_hw_params_t *params,
1479 					       snd_pcm_hw_param_t var,
1480 					       int value, int *dir,
1481 					       snd_pcm_t *pcm,
1482 					       const snd_pcm_hw_strategy_simple_t *par)
1483 {
1484 	const snd_pcm_hw_strategy_simple_near_t *p = par->private_data;
1485 	if (value < 0) {
1486 		*dir = 0;
1487 		return snd_pcm_hw_param_set_near(pcm, params, var, p->best, dir);
1488 	} else
1489 		return snd_pcm_hw_param_set_next(pcm, params, var, p->best, 0, value, dir);
1490 }
1491 
1492 void snd_pcm_hw_strategy_simple_choices_free(snd_pcm_hw_strategy_simple_t *par)
1493 {
1494 	snd_pcm_hw_strategy_simple_choices_t *p = par->private_data;
1495 //	free(p->choices);
1496 	free(p);
1497 }
1498 
1499 unsigned int snd_pcm_hw_strategy_simple_choices_min_badness(const snd_pcm_hw_params_t *params,
1500 							 snd_pcm_hw_param_t var,
1501 							 snd_pcm_t *pcm,
1502 							 const snd_pcm_hw_strategy_simple_t *par)
1503 {
1504 	const snd_pcm_hw_strategy_simple_choices_t *p = par->private_data;
1505 	unsigned int k;
1506 	for (k = 0; k < p->count; ++k) {
1507 		if (snd_pcm_hw_param_set(pcm, (snd_pcm_hw_params_t *) params, SND_TEST, var, p->choices[k].value, 0))
1508 			return p->choices[k].badness;
1509 	}
1510 	assert(0);
1511 	return UINT_MAX;
1512 }
1513 
1514 int snd_pcm_hw_strategy_simple_choices_next_value(snd_pcm_hw_params_t *params,
1515 						  snd_pcm_hw_param_t var,
1516 						  int value, int *dir,
1517 						  snd_pcm_t *pcm,
1518 						  const snd_pcm_hw_strategy_simple_t *par)
1519 {
1520 	const snd_pcm_hw_strategy_simple_choices_t *p = par->private_data;
1521 	unsigned int k = 0;
1522 	if (value >= 0) {
1523 		for (; k < p->count; ++k) {
1524 			if (p->choices[k].value == (unsigned int) value) {
1525 				k++;
1526 				break;
1527 			}
1528 		}
1529 	}
1530 	for (; k < p->count; ++k) {
1531 		unsigned int v = p->choices[k].value;
1532 		int err = snd_pcm_hw_param_set(pcm, params, SND_TRY, var, v, 0);
1533 		if (err < 0)
1534 			continue;
1535 		*dir = 0;
1536 		return v;
1537 	}
1538 	return -1;
1539 }
1540 
1541 void snd_pcm_hw_strategy_free(snd_pcm_hw_strategy_t *strategy)
1542 {
1543 	if (strategy->free)
1544 		strategy->free(strategy);
1545 	free(strategy);
1546 }
1547 
1548 int snd_pcm_hw_strategy_simple(snd_pcm_hw_strategy_t **strategyp,
1549 			    unsigned int badness_min,
1550 			    unsigned int badness_max)
1551 {
1552 	snd_pcm_hw_strategy_simple_t *data;
1553 	snd_pcm_hw_strategy_t *s;
1554 	assert(strategyp);
1555 	data = calloc(SND_PCM_HW_PARAM_LAST_INTERVAL + 1, sizeof(*data));
1556 	if (!data)
1557 		return -ENOMEM;
1558 	s = calloc(1, sizeof(*s));
1559 	if (!s) {
1560 		free(data);
1561 		return -ENOMEM;
1562 	}
1563 	s->choose_param = snd_pcm_hw_strategy_simple_choose_param;
1564 	s->next_value = snd_pcm_hw_strategy_simple_next_value;
1565 	s->min_badness = snd_pcm_hw_strategy_simple_min_badness;
1566 	s->badness_min = badness_min;
1567 	s->badness_max = badness_max;
1568 	s->private_data = data;
1569 	s->free = snd_pcm_hw_strategy_simple_free;
1570 	*strategyp = s;
1571 	return 0;
1572 }
1573 
1574 int snd_pcm_hw_strategy_simple_near(snd_pcm_hw_strategy_t *strategy,
1575 				 int order,
1576 				 snd_pcm_hw_param_t var,
1577 				 unsigned int best,
1578 				 unsigned int mul)
1579 {
1580 	snd_pcm_hw_strategy_simple_t *s = strategy->private_data;
1581 	snd_pcm_hw_strategy_simple_near_t *data;
1582 	assert(strategy);
1583 	assert(var <= SND_PCM_HW_PARAM_LAST_INTERVAL);
1584 	assert(!s->valid);
1585 	data = calloc(1, sizeof(*data));
1586 	if (!data)
1587 		return -ENOMEM;
1588 	data->best = best;
1589 	data->mul = mul;
1590 	s += var;
1591 	s->order = order;
1592 	s->valid = 1;
1593 	s->next_value = snd_pcm_hw_strategy_simple_near_next_value;
1594 	s->min_badness = snd_pcm_hw_strategy_simple_near_min_badness;
1595 	s->private_data = data;
1596 	s->free = snd_pcm_hw_strategy_simple_near_free;
1597 	return 0;
1598 }
1599 
1600 int snd_pcm_hw_strategy_simple_choices(snd_pcm_hw_strategy_t *strategy,
1601 				    int order,
1602 				    snd_pcm_hw_param_t var,
1603 				    unsigned int count,
1604 				    snd_pcm_hw_strategy_simple_choices_list_t *choices)
1605 {
1606 	snd_pcm_hw_strategy_simple_t *s = strategy->private_data;
1607 	snd_pcm_hw_strategy_simple_choices_t *data;
1608 	assert(strategy);
1609 	assert(var <= SND_PCM_HW_PARAM_LAST_INTERVAL);
1610 	assert(!s->valid);
1611 	data = calloc(1, sizeof(*data));
1612 	if (!data)
1613 		return -ENOMEM;
1614 	data->count = count;
1615 	data->choices = choices;
1616 	s += var;
1617 	s->valid = 1;
1618 	s->order = order;
1619 	s->next_value = snd_pcm_hw_strategy_simple_choices_next_value;
1620 	s->min_badness = snd_pcm_hw_strategy_simple_choices_min_badness;
1621 	s->private_data = data;
1622 	s->free = snd_pcm_hw_strategy_simple_choices_free;
1623 	return 0;
1624 }
1625 
1626 int snd_pcm_hw_params_try_explain_failure1(snd_pcm_t *pcm,
1627 					   snd_pcm_hw_params_t *fail,
1628 					   snd_pcm_hw_params_t *success,
1629 					   unsigned int depth,
1630 					   snd_output_t *out)
1631 {
1632 	snd_pcm_hw_param_t var;
1633 	snd_pcm_hw_params_t i;
1634 	if (depth < 1)
1635 		return -ENOENT;
1636 	for (var = 0; var <= SND_PCM_HW_PARAM_LAST_INTERVAL; var++) {
1637 		int err;
1638 		i = *success;
1639 		_snd_pcm_hw_param_copy(&i, var, fail);
1640 		err = snd_pcm_hw_refine(pcm, &i);
1641 		if (err == 0 &&
1642 		    snd_pcm_hw_params_try_explain_failure1(pcm, fail, &i, depth - 1, out) < 0)
1643 			continue;
1644 		snd_output_printf(out, "%s: ", snd_pcm_hw_param_name(var));
1645 		snd_pcm_hw_param_dump(fail, var, out);
1646 		snd_output_putc(out, '\n');
1647 		return 0;
1648 	}
1649 	return -ENOENT;
1650 }
1651 
1652 int snd_pcm_hw_params_try_explain_failure(snd_pcm_t *pcm,
1653 					  snd_pcm_hw_params_t *fail,
1654 					  snd_pcm_hw_params_t *success,
1655 					  unsigned int depth,
1656 					  snd_output_t *out)
1657 {
1658 	snd_pcm_hw_params_t i, any;
1659 	int err;
1660 	snd_pcm_hw_param_t var;
1661 	int done = 0;
1662 	assert(pcm && fail);
1663 	for (var = 0; var <= SND_PCM_HW_PARAM_LAST_INTERVAL; var++) {
1664 		if (!snd_pcm_hw_param_empty(fail, var))
1665 			continue;
1666 		snd_output_printf(out, "%s is empty\n", snd_pcm_hw_param_name(var));
1667 		done = 1;
1668 	}
1669 	if (done)
1670 		return 0;
1671 	i = *fail;
1672 	err = snd_pcm_hw_refine(pcm, &i);
1673 	if (err == 0) {
1674 		snd_output_printf(out, "Configuration is virtually correct\n");
1675 		return 0;
1676 	}
1677 	if (!success) {
1678 		snd_pcm_hw_params_any(pcm, &any);
1679 		success = &any;
1680 	}
1681 	return snd_pcm_hw_params_try_explain_failure1(pcm, fail, success, depth, out);
1682 }
1683 
1684 #endif
1685 
1686 typedef struct _snd_pcm_hw_rule snd_pcm_hw_rule_t;
1687 
1688 typedef int (*snd_pcm_hw_rule_func_t)(snd_pcm_hw_params_t *params,
1689 				      const snd_pcm_hw_rule_t *rule);
1690 
1691 struct _snd_pcm_hw_rule {
1692 	int var;
1693 	snd_pcm_hw_rule_func_t func;
1694 	int deps[4];
1695 	void *private_data;
1696 };
1697 
snd_pcm_hw_rule_mul(snd_pcm_hw_params_t * params,const snd_pcm_hw_rule_t * rule)1698 static int snd_pcm_hw_rule_mul(snd_pcm_hw_params_t *params,
1699 			       const snd_pcm_hw_rule_t *rule)
1700 {
1701 	snd_interval_t t;
1702 	snd_interval_mul(hw_param_interval_c(params, rule->deps[0]),
1703 		     hw_param_interval_c(params, rule->deps[1]), &t);
1704 	return snd_interval_refine(hw_param_interval(params, rule->var), &t);
1705 }
1706 
snd_pcm_hw_rule_div(snd_pcm_hw_params_t * params,const snd_pcm_hw_rule_t * rule)1707 static int snd_pcm_hw_rule_div(snd_pcm_hw_params_t *params,
1708 			const snd_pcm_hw_rule_t *rule)
1709 {
1710 	snd_interval_t t;
1711 	snd_interval_div(hw_param_interval_c(params, rule->deps[0]),
1712 		     hw_param_interval_c(params, rule->deps[1]), &t);
1713 	return snd_interval_refine(hw_param_interval(params, rule->var), &t);
1714 }
1715 
snd_pcm_hw_rule_muldivk(snd_pcm_hw_params_t * params,const snd_pcm_hw_rule_t * rule)1716 static int snd_pcm_hw_rule_muldivk(snd_pcm_hw_params_t *params,
1717 				   const snd_pcm_hw_rule_t *rule)
1718 {
1719 	snd_interval_t t;
1720 	snd_interval_muldivk(hw_param_interval_c(params, rule->deps[0]),
1721 			 hw_param_interval_c(params, rule->deps[1]),
1722 			 (unsigned long) rule->private_data, &t);
1723 	return snd_interval_refine(hw_param_interval(params, rule->var), &t);
1724 }
1725 
snd_pcm_hw_rule_mulkdiv(snd_pcm_hw_params_t * params,const snd_pcm_hw_rule_t * rule)1726 static int snd_pcm_hw_rule_mulkdiv(snd_pcm_hw_params_t *params,
1727 				   const snd_pcm_hw_rule_t *rule)
1728 {
1729 	snd_interval_t t;
1730 	snd_interval_mulkdiv(hw_param_interval_c(params, rule->deps[0]),
1731 			 (unsigned long) rule->private_data,
1732 			 hw_param_interval_c(params, rule->deps[1]), &t);
1733 	return snd_interval_refine(hw_param_interval(params, rule->var), &t);
1734 }
1735 
snd_pcm_hw_rule_format(snd_pcm_hw_params_t * params,const snd_pcm_hw_rule_t * rule)1736 static int snd_pcm_hw_rule_format(snd_pcm_hw_params_t *params,
1737 				  const snd_pcm_hw_rule_t *rule)
1738 {
1739 	int changed = 0;
1740 	snd_pcm_format_t k;
1741 	snd_mask_t *mask = hw_param_mask(params, rule->var);
1742 	snd_interval_t *i = hw_param_interval(params, rule->deps[0]);
1743 	for (k = 0; k <= SND_PCM_FORMAT_LAST; k++) {
1744 		int bits;
1745 		if (!snd_pcm_format_mask_test(mask, k))
1746 			continue;
1747 		bits = snd_pcm_format_physical_width(k);
1748 		if (bits < 0)
1749 			continue;
1750 		if (!snd_interval_test(i, (unsigned int) bits)) {
1751 			snd_pcm_format_mask_reset(mask, k);
1752 			if (snd_mask_empty(mask))
1753 				return -EINVAL;
1754 			changed = 1;
1755 		}
1756 	}
1757 	return changed;
1758 }
1759 
1760 
snd_pcm_hw_rule_sample_bits(snd_pcm_hw_params_t * params,const snd_pcm_hw_rule_t * rule)1761 static int snd_pcm_hw_rule_sample_bits(snd_pcm_hw_params_t *params,
1762 				       const snd_pcm_hw_rule_t *rule)
1763 {
1764 	unsigned int min, max;
1765 	snd_pcm_format_t k;
1766 	snd_interval_t *i = hw_param_interval(params, rule->var);
1767 	snd_mask_t *mask = hw_param_mask(params, rule->deps[0]);
1768 	int c, changed = 0;
1769 	min = UINT_MAX;
1770 	max = 0;
1771 	for (k = 0; k <= SND_PCM_FORMAT_LAST; k++) {
1772 		int bits;
1773 		if (!snd_pcm_format_mask_test(mask, k))
1774 			continue;
1775 		bits = snd_pcm_format_physical_width(k);
1776 		if (bits < 0)
1777 			continue;
1778 		if (min > (unsigned)bits)
1779 			min = bits;
1780 		if (max < (unsigned)bits)
1781 			max = bits;
1782 	}
1783 	c = snd_interval_refine_min(i, min, 0);
1784 	if (c < 0)
1785 		return c;
1786 	if (c)
1787 		changed = 1;
1788 	c = snd_interval_refine_max(i, max, 0);
1789 	if (c < 0)
1790 		return c;
1791 	if (c)
1792 		changed = 1;
1793 	return changed;
1794 }
1795 
1796 static const snd_pcm_hw_rule_t refine_rules[] = {
1797 	{
1798 		.var = SND_PCM_HW_PARAM_FORMAT,
1799 		.func = snd_pcm_hw_rule_format,
1800 		.deps = { SND_PCM_HW_PARAM_SAMPLE_BITS, -1 },
1801 		.private_data = 0,
1802 	},
1803 	{
1804 		.var = SND_PCM_HW_PARAM_SAMPLE_BITS,
1805 		.func = snd_pcm_hw_rule_sample_bits,
1806 		.deps = { SND_PCM_HW_PARAM_FORMAT,
1807 			SND_PCM_HW_PARAM_SAMPLE_BITS, -1 },
1808 		.private_data = 0,
1809 	},
1810 	{
1811 		.var = SND_PCM_HW_PARAM_SAMPLE_BITS,
1812 		.func = snd_pcm_hw_rule_div,
1813 		.deps = { SND_PCM_HW_PARAM_FRAME_BITS,
1814 			SND_PCM_HW_PARAM_CHANNELS, -1 },
1815 		.private_data = 0,
1816 	},
1817 	{
1818 		.var = SND_PCM_HW_PARAM_FRAME_BITS,
1819 		.func = snd_pcm_hw_rule_mul,
1820 		.deps = { SND_PCM_HW_PARAM_SAMPLE_BITS,
1821 			SND_PCM_HW_PARAM_CHANNELS, -1 },
1822 		.private_data = 0,
1823 	},
1824 	{
1825 		.var = SND_PCM_HW_PARAM_FRAME_BITS,
1826 		.func = snd_pcm_hw_rule_mulkdiv,
1827 		.deps = { SND_PCM_HW_PARAM_PERIOD_BYTES,
1828 			SND_PCM_HW_PARAM_PERIOD_SIZE, -1 },
1829 		.private_data = (void*) 8,
1830 	},
1831 	{
1832 		.var = SND_PCM_HW_PARAM_FRAME_BITS,
1833 		.func = snd_pcm_hw_rule_mulkdiv,
1834 		.deps = { SND_PCM_HW_PARAM_BUFFER_BYTES,
1835 			SND_PCM_HW_PARAM_BUFFER_SIZE, -1 },
1836 		.private_data = (void*) 8,
1837 	},
1838 	{
1839 		.var = SND_PCM_HW_PARAM_CHANNELS,
1840 		.func = snd_pcm_hw_rule_div,
1841 		.deps = { SND_PCM_HW_PARAM_FRAME_BITS,
1842 			SND_PCM_HW_PARAM_SAMPLE_BITS, -1 },
1843 		.private_data = 0,
1844 	},
1845 	{
1846 		.var = SND_PCM_HW_PARAM_RATE,
1847 		.func = snd_pcm_hw_rule_mulkdiv,
1848 		.deps = { SND_PCM_HW_PARAM_PERIOD_SIZE,
1849 			SND_PCM_HW_PARAM_PERIOD_TIME, -1 },
1850 		.private_data = (void*) 1000000,
1851 	},
1852 	{
1853 		.var = SND_PCM_HW_PARAM_RATE,
1854 		.func = snd_pcm_hw_rule_mulkdiv,
1855 		.deps = { SND_PCM_HW_PARAM_BUFFER_SIZE,
1856 			SND_PCM_HW_PARAM_BUFFER_TIME, -1 },
1857 		.private_data = (void*) 1000000,
1858 	},
1859 	{
1860 		.var = SND_PCM_HW_PARAM_PERIODS,
1861 		.func = snd_pcm_hw_rule_div,
1862 		.deps = { SND_PCM_HW_PARAM_BUFFER_SIZE,
1863 			SND_PCM_HW_PARAM_PERIOD_SIZE, -1 },
1864 		.private_data = 0,
1865 	},
1866 	{
1867 		.var = SND_PCM_HW_PARAM_PERIOD_SIZE,
1868 		.func = snd_pcm_hw_rule_div,
1869 		.deps = { SND_PCM_HW_PARAM_BUFFER_SIZE,
1870 			SND_PCM_HW_PARAM_PERIODS, -1 },
1871 		.private_data = 0,
1872 	},
1873 	{
1874 		.var = SND_PCM_HW_PARAM_PERIOD_SIZE,
1875 		.func = snd_pcm_hw_rule_mulkdiv,
1876 		.deps = { SND_PCM_HW_PARAM_PERIOD_BYTES,
1877 			SND_PCM_HW_PARAM_FRAME_BITS, -1 },
1878 		.private_data = (void*) 8,
1879 	},
1880 	{
1881 		.var = SND_PCM_HW_PARAM_PERIOD_SIZE,
1882 		.func = snd_pcm_hw_rule_muldivk,
1883 		.deps = { SND_PCM_HW_PARAM_PERIOD_TIME,
1884 			SND_PCM_HW_PARAM_RATE, -1 },
1885 		.private_data = (void*) 1000000,
1886 	},
1887 	{
1888 		.var = SND_PCM_HW_PARAM_BUFFER_SIZE,
1889 		.func = snd_pcm_hw_rule_mul,
1890 		.deps = { SND_PCM_HW_PARAM_PERIOD_SIZE,
1891 			SND_PCM_HW_PARAM_PERIODS, -1 },
1892 		.private_data = 0,
1893 	},
1894 	{
1895 		.var = SND_PCM_HW_PARAM_BUFFER_SIZE,
1896 		.func = snd_pcm_hw_rule_mulkdiv,
1897 		.deps = { SND_PCM_HW_PARAM_BUFFER_BYTES,
1898 			SND_PCM_HW_PARAM_FRAME_BITS, -1 },
1899 		.private_data = (void*) 8,
1900 	},
1901 	{
1902 		.var = SND_PCM_HW_PARAM_BUFFER_SIZE,
1903 		.func = snd_pcm_hw_rule_muldivk,
1904 		.deps = { SND_PCM_HW_PARAM_BUFFER_TIME,
1905 			SND_PCM_HW_PARAM_RATE, -1 },
1906 		.private_data = (void*) 1000000,
1907 	},
1908 	{
1909 		.var = SND_PCM_HW_PARAM_PERIOD_BYTES,
1910 		.func = snd_pcm_hw_rule_muldivk,
1911 		.deps = { SND_PCM_HW_PARAM_PERIOD_SIZE,
1912 			SND_PCM_HW_PARAM_FRAME_BITS, -1 },
1913 		.private_data = (void*) 8,
1914 	},
1915 	{
1916 		.var = SND_PCM_HW_PARAM_BUFFER_BYTES,
1917 		.func = snd_pcm_hw_rule_muldivk,
1918 		.deps = { SND_PCM_HW_PARAM_BUFFER_SIZE,
1919 			SND_PCM_HW_PARAM_FRAME_BITS, -1 },
1920 		.private_data = (void*) 8,
1921 	},
1922 	{
1923 		.var = SND_PCM_HW_PARAM_PERIOD_TIME,
1924 		.func = snd_pcm_hw_rule_mulkdiv,
1925 		.deps = { SND_PCM_HW_PARAM_PERIOD_SIZE,
1926 			SND_PCM_HW_PARAM_RATE, -1 },
1927 		.private_data = (void*) 1000000,
1928 	},
1929 	{
1930 		.var = SND_PCM_HW_PARAM_BUFFER_TIME,
1931 		.func = snd_pcm_hw_rule_mulkdiv,
1932 		.deps = { SND_PCM_HW_PARAM_BUFFER_SIZE,
1933 			SND_PCM_HW_PARAM_RATE, -1 },
1934 		.private_data = (void*) 1000000,
1935 	},
1936 };
1937 
1938 #define RULES (sizeof(refine_rules) / sizeof(refine_rules[0]))
1939 #define PCM_BIT(x) \
1940 	(1U << ((x) < 32 ? (x) : ((x) - 32)))
1941 
1942 static const snd_mask_t refine_masks[SND_PCM_HW_PARAM_LAST_MASK - SND_PCM_HW_PARAM_FIRST_MASK + 1] = {
1943 	[SND_PCM_HW_PARAM_ACCESS - SND_PCM_HW_PARAM_FIRST_MASK] = {
1944 		.bits = {
1945 			PCM_BIT(SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) |
1946 			PCM_BIT(SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED) |
1947 			PCM_BIT(SNDRV_PCM_ACCESS_MMAP_COMPLEX) |
1948 			PCM_BIT(SNDRV_PCM_ACCESS_RW_INTERLEAVED) |
1949 			PCM_BIT(SNDRV_PCM_ACCESS_RW_NONINTERLEAVED)
1950 		},
1951 	},
1952 	[SND_PCM_HW_PARAM_FORMAT - SND_PCM_HW_PARAM_FIRST_MASK] = {
1953 		.bits = {
1954 			/* first 32bits */
1955 			PCM_BIT(SNDRV_PCM_FORMAT_S8) |
1956 			PCM_BIT(SNDRV_PCM_FORMAT_U8) |
1957 			PCM_BIT(SNDRV_PCM_FORMAT_S16_LE) |
1958 			PCM_BIT(SNDRV_PCM_FORMAT_S16_BE) |
1959 			PCM_BIT(SNDRV_PCM_FORMAT_U16_LE) |
1960 			PCM_BIT(SNDRV_PCM_FORMAT_U16_BE) |
1961 			PCM_BIT(SNDRV_PCM_FORMAT_S24_LE) |
1962 			PCM_BIT(SNDRV_PCM_FORMAT_S24_BE) |
1963 			PCM_BIT(SNDRV_PCM_FORMAT_U24_LE) |
1964 			PCM_BIT(SNDRV_PCM_FORMAT_U24_BE) |
1965 			PCM_BIT(SNDRV_PCM_FORMAT_S32_LE) |
1966 			PCM_BIT(SNDRV_PCM_FORMAT_S32_BE) |
1967 			PCM_BIT(SNDRV_PCM_FORMAT_U32_LE) |
1968 			PCM_BIT(SNDRV_PCM_FORMAT_U32_BE) |
1969 			PCM_BIT(SNDRV_PCM_FORMAT_FLOAT_LE) |
1970 			PCM_BIT(SNDRV_PCM_FORMAT_FLOAT_BE) |
1971 			PCM_BIT(SNDRV_PCM_FORMAT_FLOAT64_LE) |
1972 			PCM_BIT(SNDRV_PCM_FORMAT_FLOAT64_BE) |
1973 			PCM_BIT(SNDRV_PCM_FORMAT_IEC958_SUBFRAME) |
1974 			PCM_BIT(SNDRV_PCM_FORMAT_IEC958_SUBFRAME) |
1975 			PCM_BIT(SNDRV_PCM_FORMAT_MU_LAW) |
1976 			PCM_BIT(SNDRV_PCM_FORMAT_A_LAW) |
1977 			PCM_BIT(SNDRV_PCM_FORMAT_IMA_ADPCM) |
1978 			PCM_BIT(SNDRV_PCM_FORMAT_MPEG) |
1979 			PCM_BIT(SNDRV_PCM_FORMAT_GSM) |
1980 			PCM_BIT(SNDRV_PCM_FORMAT_S20_LE) |
1981 			PCM_BIT(SNDRV_PCM_FORMAT_S20_BE) |
1982 			PCM_BIT(SNDRV_PCM_FORMAT_U20_LE) |
1983 			PCM_BIT(SNDRV_PCM_FORMAT_U20_BE) |
1984 			PCM_BIT(SNDRV_PCM_FORMAT_SPECIAL),
1985 			/* second 32bits */
1986 			PCM_BIT(SNDRV_PCM_FORMAT_S24_3LE) |
1987 			PCM_BIT(SNDRV_PCM_FORMAT_S24_3BE) |
1988 			PCM_BIT(SNDRV_PCM_FORMAT_U24_3LE) |
1989 			PCM_BIT(SNDRV_PCM_FORMAT_U24_3BE) |
1990 			PCM_BIT(SNDRV_PCM_FORMAT_S20_3LE) |
1991 			PCM_BIT(SNDRV_PCM_FORMAT_S20_3BE) |
1992 			PCM_BIT(SNDRV_PCM_FORMAT_U20_3LE) |
1993 			PCM_BIT(SNDRV_PCM_FORMAT_U20_3BE) |
1994 			PCM_BIT(SNDRV_PCM_FORMAT_S18_3LE) |
1995 			PCM_BIT(SNDRV_PCM_FORMAT_S18_3BE) |
1996 			PCM_BIT(SNDRV_PCM_FORMAT_U18_3LE) |
1997 			PCM_BIT(SNDRV_PCM_FORMAT_U18_3BE) |
1998 			PCM_BIT(SNDRV_PCM_FORMAT_G723_24) |
1999 			PCM_BIT(SNDRV_PCM_FORMAT_G723_24) |
2000 			PCM_BIT(SNDRV_PCM_FORMAT_G723_40) |
2001 			PCM_BIT(SNDRV_PCM_FORMAT_G723_40) |
2002 			PCM_BIT(SNDRV_PCM_FORMAT_DSD_U8) |
2003 			PCM_BIT(SNDRV_PCM_FORMAT_DSD_U16_LE) |
2004 			PCM_BIT(SNDRV_PCM_FORMAT_DSD_U32_LE) |
2005 			PCM_BIT(SNDRV_PCM_FORMAT_DSD_U16_BE) |
2006 			PCM_BIT(SNDRV_PCM_FORMAT_DSD_U32_BE)
2007 		},
2008 	},
2009 	[SND_PCM_HW_PARAM_SUBFORMAT - SND_PCM_HW_PARAM_FIRST_MASK] = {
2010 		.bits = {
2011 			PCM_BIT(SNDRV_PCM_SUBFORMAT_STD)
2012 		},
2013 	},
2014 };
2015 
2016 static const snd_interval_t refine_intervals[SND_PCM_HW_PARAM_LAST_INTERVAL - SND_PCM_HW_PARAM_FIRST_INTERVAL + 1] = {
2017 	[SND_PCM_HW_PARAM_SAMPLE_BITS - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
2018 		.min = 1, .max = UINT_MAX,
2019 		.openmin = 0, .openmax = 0, .integer = 1, .empty = 0,
2020 	},
2021 	[SND_PCM_HW_PARAM_FRAME_BITS - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
2022 		.min = 1, .max = UINT_MAX,
2023 		.openmin = 0, .openmax = 0, .integer = 1, .empty = 0,
2024 	},
2025 	[SND_PCM_HW_PARAM_CHANNELS - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
2026 		.min = 1, .max = UINT_MAX,
2027 		.openmin = 0, .openmax = 0, .integer = 1, .empty = 0,
2028 	},
2029 	[SND_PCM_HW_PARAM_RATE - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
2030 		.min = 1, .max = UINT_MAX,
2031 		.openmin = 0, .openmax = 0, .integer = 0, .empty = 0,
2032 	},
2033 	[SND_PCM_HW_PARAM_PERIOD_TIME - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
2034 		.min = 0, .max = UINT_MAX,
2035 		.openmin = 0, .openmax = 0, .integer = 0, .empty = 0,
2036 	},
2037 	[SND_PCM_HW_PARAM_PERIOD_SIZE - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
2038 		.min = 0, .max = UINT_MAX,
2039 		.openmin = 0, .openmax = 0, .integer = 0, .empty = 0,
2040 	},
2041 	[SND_PCM_HW_PARAM_PERIOD_BYTES - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
2042 		.min = 0, .max = UINT_MAX,
2043 		.openmin = 0, .openmax = 0, .integer = 0, .empty = 0,
2044 	},
2045 	[SND_PCM_HW_PARAM_PERIODS - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
2046 		.min = 0, .max = UINT_MAX,
2047 		.openmin = 0, .openmax = 0, .integer = 0, .empty = 0,
2048 	},
2049 	[SND_PCM_HW_PARAM_BUFFER_TIME - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
2050 		.min = 1, .max = UINT_MAX,
2051 		.openmin = 0, .openmax = 0, .integer = 0, .empty = 0,
2052 	},
2053 	[SND_PCM_HW_PARAM_BUFFER_SIZE - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
2054 		.min = 1, .max = UINT_MAX,
2055 		.openmin = 0, .openmax = 0, .integer = 1, .empty = 0,
2056 	},
2057 	[SND_PCM_HW_PARAM_BUFFER_BYTES - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
2058 		.min = 1, .max = UINT_MAX,
2059 		.openmin = 0, .openmax = 0, .integer = 1, .empty = 0,
2060 	},
2061 	[SND_PCM_HW_PARAM_TICK_TIME - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
2062 		.min = 0, .max = UINT_MAX,
2063 		.openmin = 0, .openmax = 0, .integer = 0, .empty = 0,
2064 	},
2065 };
2066 
2067 #if 0
2068 #define RULES_DEBUG
2069 #endif
2070 
snd_pcm_hw_refine_soft(snd_pcm_t * pcm ATTRIBUTE_UNUSED,snd_pcm_hw_params_t * params)2071 int snd_pcm_hw_refine_soft(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params)
2072 {
2073 	unsigned int k;
2074 	snd_interval_t *i;
2075 	unsigned int rstamps[RULES];
2076 	unsigned int vstamps[SND_PCM_HW_PARAM_LAST_INTERVAL + 1];
2077 	unsigned int stamp = 2;
2078 	int changed, again;
2079 #ifdef RULES_DEBUG
2080 	snd_output_t *log;
2081 	snd_output_stdio_attach(&log, stderr, 0);
2082 	snd_output_printf(log, "refine_soft '%s' (begin)\n", pcm->name);
2083 	snd_pcm_hw_params_dump(params, log);
2084 #endif
2085 
2086 	for (k = SND_PCM_HW_PARAM_FIRST_MASK; k <= SND_PCM_HW_PARAM_LAST_MASK; k++) {
2087 		if (!(params->rmask & (1 << k)))
2088 			continue;
2089 		changed = snd_mask_refine(hw_param_mask(params, k),
2090 					  &refine_masks[k - SND_PCM_HW_PARAM_FIRST_MASK]);
2091 		if (changed)
2092 			params->cmask |= 1 << k;
2093 		if (changed < 0)
2094 			goto _err;
2095 	}
2096 
2097 	for (k = SND_PCM_HW_PARAM_FIRST_INTERVAL; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; k++) {
2098 		if (!(params->rmask & (1 << k)))
2099 			continue;
2100 		changed = snd_interval_refine(hw_param_interval(params, k),
2101 				      &refine_intervals[k - SND_PCM_HW_PARAM_FIRST_INTERVAL]);
2102 		if (changed)
2103 			params->cmask |= 1 << k;
2104 		if (changed < 0)
2105 			goto _err;
2106 	}
2107 
2108 	for (k = 0; k < RULES; k++)
2109 		rstamps[k] = 0;
2110 	for (k = 0; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; k++)
2111 		vstamps[k] = (params->rmask & (1 << k)) ? 1 : 0;
2112 	do {
2113 		again = 0;
2114 		for (k = 0; k < RULES; k++) {
2115 			const snd_pcm_hw_rule_t *r = &refine_rules[k];
2116 			unsigned int d;
2117 			int doit = 0;
2118 			for (d = 0; r->deps[d] >= 0; d++) {
2119 				if (vstamps[r->deps[d]] > rstamps[k]) {
2120 					doit = 1;
2121 					break;
2122 				}
2123 			}
2124 			if (!doit)
2125 				continue;
2126 #ifdef RULES_DEBUG
2127 			snd_output_printf(log, "Rule %d (%p): ", k, r->func);
2128 			if (r->var >= 0) {
2129 				snd_output_printf(log, "%s=", snd_pcm_hw_param_name(r->var));
2130 				snd_pcm_hw_param_dump(params, r->var, log);
2131 				snd_output_puts(log, " -> ");
2132 			}
2133 #endif
2134 			changed = r->func(params, r);
2135 #ifdef RULES_DEBUG
2136 			if (r->var >= 0)
2137 				snd_pcm_hw_param_dump(params, r->var, log);
2138 			for (d = 0; r->deps[d] >= 0; d++) {
2139 				snd_output_printf(log, " %s=", snd_pcm_hw_param_name(r->deps[d]));
2140 				snd_pcm_hw_param_dump(params, r->deps[d], log);
2141 			}
2142 			snd_output_putc(log, '\n');
2143 #endif
2144 			rstamps[k] = stamp;
2145 			if (changed && r->var >= 0) {
2146 				params->cmask |= 1 << r->var;
2147 				vstamps[r->var] = stamp;
2148 				again = 1;
2149 			}
2150 			if (changed < 0)
2151 				goto _err;
2152 			stamp++;
2153 		}
2154 	} while (again);
2155 	if (!params->msbits) {
2156 		i = hw_param_interval(params, SND_PCM_HW_PARAM_SAMPLE_BITS);
2157 		if (snd_interval_single(i))
2158 			params->msbits = snd_interval_value(i);
2159 	}
2160 
2161 	if (!params->rate_den) {
2162 		i = hw_param_interval(params, SND_PCM_HW_PARAM_RATE);
2163 		if (snd_interval_single(i)) {
2164 			params->rate_num = snd_interval_value(i);
2165 			params->rate_den = 1;
2166 		}
2167 	}
2168 	params->rmask = 0;
2169 	return 0;
2170  _err:
2171 #ifdef RULES_DEBUG
2172 	snd_output_printf(log, "refine_soft '%s' (end-%i)\n", pcm->name, changed);
2173 	snd_pcm_hw_params_dump(params, log);
2174 	snd_output_close(log);
2175 #endif
2176 	return changed;
2177 }
2178 
_snd_pcm_hw_params_refine(snd_pcm_hw_params_t * params,unsigned int vars,const snd_pcm_hw_params_t * src)2179 int _snd_pcm_hw_params_refine(snd_pcm_hw_params_t *params,
2180 			      unsigned int vars,
2181 			      const snd_pcm_hw_params_t *src)
2182 {
2183 	int changed, err = 0;
2184 	unsigned int k;
2185 	for (k = 0; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; ++k) {
2186 		if (!(vars & (1 << k)))
2187 			continue;
2188 		changed = _snd_pcm_hw_param_refine(params, k, src);
2189 		if (changed < 0)
2190 			err = changed;
2191 	}
2192 	params->info &= src->info;
2193 	params->flags = src->flags; /* propagate all flags to slave */
2194 	return err;
2195 }
2196 
snd_pcm_hw_refine_slave(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,int (* cprepare)(snd_pcm_t * pcm,snd_pcm_hw_params_t * params),int (* cchange)(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,snd_pcm_hw_params_t * sparams),int (* sprepare)(snd_pcm_t * pcm,snd_pcm_hw_params_t * params),int (* schange)(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,snd_pcm_hw_params_t * sparams),int (* srefine)(snd_pcm_t * pcm,snd_pcm_hw_params_t * sparams))2197 int snd_pcm_hw_refine_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
2198 			    int (*cprepare)(snd_pcm_t *pcm,
2199 					    snd_pcm_hw_params_t *params),
2200 			    int (*cchange)(snd_pcm_t *pcm,
2201 					   snd_pcm_hw_params_t *params,
2202 					   snd_pcm_hw_params_t *sparams),
2203 			    int (*sprepare)(snd_pcm_t *pcm,
2204 					    snd_pcm_hw_params_t *params),
2205 			    int (*schange)(snd_pcm_t *pcm,
2206 					   snd_pcm_hw_params_t *params,
2207 					   snd_pcm_hw_params_t *sparams),
2208 			    int (*srefine)(snd_pcm_t *pcm,
2209 					   snd_pcm_hw_params_t *sparams))
2210 
2211 {
2212 #ifdef RULES_DEBUG
2213 	snd_output_t *log;
2214 #endif
2215 	snd_pcm_hw_params_t sparams;
2216 	int err;
2217 	unsigned int cmask, changed;
2218 #ifdef RULES_DEBUG
2219 	snd_output_stdio_attach(&log, stderr, 0);
2220 #endif
2221 	err = cprepare(pcm, params);
2222 	if (err < 0)
2223 		return err;
2224 	err = sprepare(pcm, &sparams);
2225 	if (err < 0) {
2226 		SNDERR("Slave PCM not usable");
2227 		return err;
2228 	}
2229 #ifdef RULES_DEBUG
2230 	snd_output_printf(log, "hw_refine_slave - enter '%s'\n", pcm->name);
2231 #endif
2232 	do {
2233 		cmask = params->cmask;
2234 		params->cmask = 0;
2235 #ifdef RULES_DEBUG
2236 		snd_output_printf(log, "schange '%s' (client)\n", pcm->name);
2237 		snd_pcm_hw_params_dump(params, log);
2238 		snd_output_printf(log, "schange '%s' (slave)\n", pcm->name);
2239 		snd_pcm_hw_params_dump(&sparams, log);
2240 #endif
2241 		err = schange(pcm, params, &sparams);
2242 		if (err >= 0) {
2243 #ifdef RULES_DEBUG
2244 			snd_output_printf(log, "srefine '%s' (client)\n", pcm->name);
2245 			snd_pcm_hw_params_dump(params, log);
2246 			snd_output_printf(log, "srefine '%s' (slave)\n", pcm->name);
2247 			snd_pcm_hw_params_dump(&sparams, log);
2248 #endif
2249 			err = srefine(pcm, &sparams);
2250 			if (err < 0) {
2251 #ifdef RULES_DEBUG
2252 				snd_output_printf(log, "srefine '%s', err < 0 (%i) (client)\n", pcm->name, err);
2253 				snd_pcm_hw_params_dump(params, log);
2254 				snd_output_printf(log, "srefine '%s', err < 0 (%i) (slave)\n", pcm->name, err);
2255 				snd_pcm_hw_params_dump(&sparams, log);
2256 #endif
2257 				cchange(pcm, params, &sparams);
2258 				return err;
2259 			}
2260 		} else {
2261 #ifdef RULES_DEBUG
2262 			snd_output_printf(log, "schange '%s', err < 0 (%i) (client)\n", pcm->name, err);
2263 			snd_pcm_hw_params_dump(params, log);
2264 			snd_output_printf(log, "schange '%s', err < 0 (%i) (slave)\n", pcm->name, err);
2265 			snd_pcm_hw_params_dump(&sparams, log);
2266 #endif
2267 			cchange(pcm, params, &sparams);
2268 			return err;
2269 		}
2270 #ifdef RULES_DEBUG
2271 		snd_output_printf(log, "cchange '%s'\n", pcm->name);
2272 #endif
2273 		err = cchange(pcm, params, &sparams);
2274 		if (err < 0)
2275 			return err;
2276 #ifdef RULES_DEBUG
2277 		snd_output_printf(log, "refine_soft '%s'\n", pcm->name);
2278 #endif
2279 		err = snd_pcm_hw_refine_soft(pcm, params);
2280 		changed = params->cmask;
2281 		params->cmask |= cmask;
2282 		if (err < 0)
2283 			return err;
2284 #ifdef RULES_DEBUG
2285 		snd_output_printf(log, "refine_soft ok '%s'\n", pcm->name);
2286 #endif
2287 	} while (changed);
2288 #ifdef RULES_DEBUG
2289 	snd_output_printf(log, "refine_slave - leave '%s'\n", pcm->name);
2290 	snd_output_close(log);
2291 #endif
2292 	return 0;
2293 }
2294 
snd_pcm_hw_params_slave(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,int (* cchange)(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,snd_pcm_hw_params_t * sparams),int (* sprepare)(snd_pcm_t * pcm,snd_pcm_hw_params_t * params),int (* schange)(snd_pcm_t * pcm,snd_pcm_hw_params_t * params,snd_pcm_hw_params_t * sparams),int (* sparams)(snd_pcm_t * pcm,snd_pcm_hw_params_t * sparams))2295 int snd_pcm_hw_params_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
2296 			    int (*cchange)(snd_pcm_t *pcm,
2297 					   snd_pcm_hw_params_t *params,
2298 					   snd_pcm_hw_params_t *sparams),
2299 			    int (*sprepare)(snd_pcm_t *pcm,
2300 					    snd_pcm_hw_params_t *params),
2301 			    int (*schange)(snd_pcm_t *pcm,
2302 					   snd_pcm_hw_params_t *params,
2303 					   snd_pcm_hw_params_t *sparams),
2304 			    int (*sparams)(snd_pcm_t *pcm,
2305 					   snd_pcm_hw_params_t *sparams))
2306 
2307 {
2308 	snd_pcm_hw_params_t slave_params;
2309 	int err;
2310 	err = sprepare(pcm, &slave_params);
2311 	if (err < 0)
2312 		return err;
2313 	err = schange(pcm, params, &slave_params);
2314 	if (err < 0)
2315 		return err;
2316 	err = sparams(pcm, &slave_params);
2317 	if (err < 0)
2318 		cchange(pcm, params, &slave_params);
2319 	return err;
2320 }
2321 
snd_pcm_sw_params_default(snd_pcm_t * pcm,snd_pcm_sw_params_t * params)2322 static int snd_pcm_sw_params_default(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)
2323 {
2324 	assert(pcm && params);
2325 	assert(pcm->setup);
2326 	params->proto = SNDRV_PCM_VERSION;
2327 	params->tstamp_mode = SND_PCM_TSTAMP_NONE;
2328 	params->tstamp_type = pcm->tstamp_type;
2329 	params->period_step = 1;
2330 	params->sleep_min = 0;
2331 	params->avail_min = pcm->period_size;
2332 	params->xfer_align = 1;
2333 	params->start_threshold = 1;
2334 	params->stop_threshold = pcm->buffer_size;
2335 	params->silence_threshold = 0;
2336 	params->silence_size = 0;
2337 	params->boundary = pcm->buffer_size;
2338 	while (params->boundary * 2 <= LONG_MAX - pcm->buffer_size)
2339 		params->boundary *= 2;
2340 	return 0;
2341 }
2342 
2343 #if 0
2344 #define REFINE_DEBUG
2345 #endif
2346 
snd_pcm_hw_refine(snd_pcm_t * pcm,snd_pcm_hw_params_t * params)2347 int snd_pcm_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
2348 {
2349 	int res;
2350 #ifdef REFINE_DEBUG
2351 	snd_output_t *log;
2352 	snd_output_stdio_attach(&log, stderr, 0);
2353 #endif
2354 	assert(pcm && params);
2355 #ifdef REFINE_DEBUG
2356 	snd_output_printf(log, "REFINE called:\n");
2357 	snd_pcm_hw_params_dump(params, log);
2358 #endif
2359 	if (pcm->ops->hw_refine)
2360 		res = pcm->ops->hw_refine(pcm->op_arg, params);
2361 	else
2362 		res = -ENOSYS;
2363 #ifdef REFINE_DEBUG
2364 	snd_output_printf(log, "refine done - result = %i\n", res);
2365 	snd_pcm_hw_params_dump(params, log);
2366 	snd_output_close(log);
2367 #endif
2368 	return res;
2369 }
2370 
2371 /* Install one of the configurations present in configuration
2372    space defined by PARAMS.
2373    The configuration chosen is that obtained fixing in this order:
2374    first access
2375    first format
2376    first subformat
2377    min channels
2378    min rate
2379    min period_size
2380    max periods
2381    Return 0 on success otherwise a negative error code
2382 */
_snd_pcm_hw_params_internal(snd_pcm_t * pcm,snd_pcm_hw_params_t * params)2383 int _snd_pcm_hw_params_internal(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
2384 {
2385 	int err;
2386 	snd_pcm_sw_params_t sw;
2387 	int fb, min_align;
2388 	err = snd_pcm_hw_refine(pcm, params);
2389 	if (err < 0)
2390 		return err;
2391 	snd_pcm_hw_params_choose(pcm, params);
2392 	if (pcm->setup) {
2393 		err = snd_pcm_hw_free(pcm);
2394 		if (err < 0)
2395 			return err;
2396 	}
2397 	if (pcm->ops->hw_params)
2398 		err = pcm->ops->hw_params(pcm->op_arg, params);
2399 	else
2400 		err = -ENOSYS;
2401 	if (err < 0)
2402 		return err;
2403 
2404 	pcm->setup = 1;
2405 	INTERNAL(snd_pcm_hw_params_get_access)(params, &pcm->access);
2406 	INTERNAL(snd_pcm_hw_params_get_format)(params, &pcm->format);
2407 	INTERNAL(snd_pcm_hw_params_get_subformat)(params, &pcm->subformat);
2408 	INTERNAL(snd_pcm_hw_params_get_channels)(params, &pcm->channels);
2409 	INTERNAL(snd_pcm_hw_params_get_rate)(params, &pcm->rate, 0);
2410 	INTERNAL(snd_pcm_hw_params_get_period_time)(params, &pcm->period_time, 0);
2411 	INTERNAL(snd_pcm_hw_params_get_period_size)(params, &pcm->period_size, 0);
2412 	INTERNAL(snd_pcm_hw_params_get_buffer_size)(params, &pcm->buffer_size);
2413 	pcm->sample_bits = snd_pcm_format_physical_width(pcm->format);
2414 	pcm->frame_bits = pcm->sample_bits * pcm->channels;
2415 	fb = pcm->frame_bits;
2416 	min_align = 1;
2417 	while (fb % 8) {
2418 		fb *= 2;
2419 		min_align *= 2;
2420 	}
2421 	pcm->min_align = min_align;
2422 
2423 	pcm->hw_flags = params->flags;
2424 	pcm->info = params->info;
2425 	pcm->msbits = params->msbits;
2426 	pcm->rate_num = params->rate_num;
2427 	pcm->rate_den = params->rate_den;
2428 	pcm->fifo_size = params->fifo_size;
2429 
2430 	/* Default sw params */
2431 	memset(&sw, 0, sizeof(sw));
2432 	snd_pcm_sw_params_default(pcm, &sw);
2433 	err = snd_pcm_sw_params(pcm, &sw);
2434 	if (err < 0)
2435 		return err;
2436 
2437 	if (pcm->mmap_rw ||
2438 	    pcm->access == SND_PCM_ACCESS_MMAP_INTERLEAVED ||
2439 	    pcm->access == SND_PCM_ACCESS_MMAP_NONINTERLEAVED ||
2440 	    pcm->access == SND_PCM_ACCESS_MMAP_COMPLEX) {
2441 		err = snd_pcm_mmap(pcm);
2442 	}
2443 	if (err < 0)
2444 		return err;
2445 	return 0;
2446 }
2447 
2448