xref: /third_party/alsa-lib/src/pcm/pcm_params.c (revision d5ac70f0)
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 */
28static 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
59static 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
65static 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
75static 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
90static 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
107int 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
114void _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*/
130int 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. */
157int 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. */
182int 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. */
209const 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. */
219const 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
228int _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
242void _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
258static 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*/
275int 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
311static 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*/
335int 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
353static 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*/
377int 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
395int _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*/
429int 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
470int _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*/
506int 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
547int _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*/
617int 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
661int _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*/
714int 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
751int _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*/
771int 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 */
812int 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 */
889int 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
953static 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
981int 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
999int 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
1027int 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
1038int 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
1052int 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*/
1081static 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
1153static 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
1169int _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
1192static 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
1215void 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
1261static 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
1279const 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
1288struct _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 */
1307typedef struct _snd_pcm_hw_strategy_simple snd_pcm_hw_strategy_simple_t;
1308
1309struct _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
1325typedef struct _snd_pcm_hw_strategy_simple_near {
1326	int best;
1327	unsigned int mul;
1328} snd_pcm_hw_strategy_simple_near_t;
1329
1330typedef 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
1336int 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
1383void 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
1394int 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
1423int 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
1435int 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
1456void 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
1462unsigned 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
1478int 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
1492void 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
1499unsigned 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
1514int 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
1541void 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
1548int 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
1574int 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
1600int 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
1626int 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
1652int 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
1686typedef struct _snd_pcm_hw_rule snd_pcm_hw_rule_t;
1687
1688typedef int (*snd_pcm_hw_rule_func_t)(snd_pcm_hw_params_t *params,
1689				      const snd_pcm_hw_rule_t *rule);
1690
1691struct _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
1698static 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
1707static 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
1716static 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
1726static 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
1736static 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
1761static 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
1796static 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
1942static 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			PCM_BIT(SNDRV_PCM_SUBFORMAT_MSBITS_MAX) |
2013			PCM_BIT(SNDRV_PCM_SUBFORMAT_MSBITS_20) |
2014			PCM_BIT(SNDRV_PCM_SUBFORMAT_MSBITS_24),
2015		},
2016	},
2017};
2018
2019static const snd_interval_t refine_intervals[SND_PCM_HW_PARAM_LAST_INTERVAL - SND_PCM_HW_PARAM_FIRST_INTERVAL + 1] = {
2020	[SND_PCM_HW_PARAM_SAMPLE_BITS - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
2021		.min = 1, .max = UINT_MAX,
2022		.openmin = 0, .openmax = 0, .integer = 1, .empty = 0,
2023	},
2024	[SND_PCM_HW_PARAM_FRAME_BITS - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
2025		.min = 1, .max = UINT_MAX,
2026		.openmin = 0, .openmax = 0, .integer = 1, .empty = 0,
2027	},
2028	[SND_PCM_HW_PARAM_CHANNELS - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
2029		.min = 1, .max = UINT_MAX,
2030		.openmin = 0, .openmax = 0, .integer = 1, .empty = 0,
2031	},
2032	[SND_PCM_HW_PARAM_RATE - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
2033		.min = 1, .max = UINT_MAX,
2034		.openmin = 0, .openmax = 0, .integer = 0, .empty = 0,
2035	},
2036	[SND_PCM_HW_PARAM_PERIOD_TIME - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
2037		.min = 0, .max = UINT_MAX,
2038		.openmin = 0, .openmax = 0, .integer = 0, .empty = 0,
2039	},
2040	[SND_PCM_HW_PARAM_PERIOD_SIZE - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
2041		.min = 0, .max = UINT_MAX,
2042		.openmin = 0, .openmax = 0, .integer = 0, .empty = 0,
2043	},
2044	[SND_PCM_HW_PARAM_PERIOD_BYTES - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
2045		.min = 0, .max = UINT_MAX,
2046		.openmin = 0, .openmax = 0, .integer = 0, .empty = 0,
2047	},
2048	[SND_PCM_HW_PARAM_PERIODS - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
2049		.min = 0, .max = UINT_MAX,
2050		.openmin = 0, .openmax = 0, .integer = 0, .empty = 0,
2051	},
2052	[SND_PCM_HW_PARAM_BUFFER_TIME - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
2053		.min = 1, .max = UINT_MAX,
2054		.openmin = 0, .openmax = 0, .integer = 0, .empty = 0,
2055	},
2056	[SND_PCM_HW_PARAM_BUFFER_SIZE - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
2057		.min = 1, .max = UINT_MAX,
2058		.openmin = 0, .openmax = 0, .integer = 1, .empty = 0,
2059	},
2060	[SND_PCM_HW_PARAM_BUFFER_BYTES - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
2061		.min = 1, .max = UINT_MAX,
2062		.openmin = 0, .openmax = 0, .integer = 1, .empty = 0,
2063	},
2064	[SND_PCM_HW_PARAM_TICK_TIME - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
2065		.min = 0, .max = UINT_MAX,
2066		.openmin = 0, .openmax = 0, .integer = 0, .empty = 0,
2067	},
2068};
2069
2070#if 0
2071#define RULES_DEBUG
2072#endif
2073
2074int snd_pcm_hw_refine_soft(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params)
2075{
2076	unsigned int k;
2077	snd_interval_t *i;
2078	snd_mask_t *m;
2079	unsigned int rstamps[RULES];
2080	unsigned int vstamps[SND_PCM_HW_PARAM_LAST_INTERVAL + 1];
2081	unsigned int stamp = 2;
2082	int changed, again;
2083#ifdef RULES_DEBUG
2084	snd_output_t *log;
2085	snd_output_stdio_attach(&log, stderr, 0);
2086	snd_output_printf(log, "refine_soft '%s' (begin)\n", pcm->name);
2087	snd_pcm_hw_params_dump(params, log);
2088#endif
2089
2090	for (k = SND_PCM_HW_PARAM_FIRST_MASK; k <= SND_PCM_HW_PARAM_LAST_MASK; k++) {
2091		if (!(params->rmask & (1 << k)))
2092			continue;
2093		changed = snd_mask_refine(hw_param_mask(params, k),
2094					  &refine_masks[k - SND_PCM_HW_PARAM_FIRST_MASK]);
2095		if (changed)
2096			params->cmask |= 1 << k;
2097		if (changed < 0)
2098			goto _err;
2099	}
2100
2101	for (k = SND_PCM_HW_PARAM_FIRST_INTERVAL; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; k++) {
2102		if (!(params->rmask & (1 << k)))
2103			continue;
2104		changed = snd_interval_refine(hw_param_interval(params, k),
2105				      &refine_intervals[k - SND_PCM_HW_PARAM_FIRST_INTERVAL]);
2106		if (changed)
2107			params->cmask |= 1 << k;
2108		if (changed < 0)
2109			goto _err;
2110	}
2111
2112	for (k = 0; k < RULES; k++)
2113		rstamps[k] = 0;
2114	for (k = 0; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; k++)
2115		vstamps[k] = (params->rmask & (1 << k)) ? 1 : 0;
2116	do {
2117		again = 0;
2118		for (k = 0; k < RULES; k++) {
2119			const snd_pcm_hw_rule_t *r = &refine_rules[k];
2120			unsigned int d;
2121			int doit = 0;
2122			for (d = 0; r->deps[d] >= 0; d++) {
2123				if (vstamps[r->deps[d]] > rstamps[k]) {
2124					doit = 1;
2125					break;
2126				}
2127			}
2128			if (!doit)
2129				continue;
2130#ifdef RULES_DEBUG
2131			snd_output_printf(log, "Rule %d (%p): ", k, r->func);
2132			if (r->var >= 0) {
2133				snd_output_printf(log, "%s=", snd_pcm_hw_param_name(r->var));
2134				snd_pcm_hw_param_dump(params, r->var, log);
2135				snd_output_puts(log, " -> ");
2136			}
2137#endif
2138			changed = r->func(params, r);
2139#ifdef RULES_DEBUG
2140			if (r->var >= 0)
2141				snd_pcm_hw_param_dump(params, r->var, log);
2142			for (d = 0; r->deps[d] >= 0; d++) {
2143				snd_output_printf(log, " %s=", snd_pcm_hw_param_name(r->deps[d]));
2144				snd_pcm_hw_param_dump(params, r->deps[d], log);
2145			}
2146			snd_output_putc(log, '\n');
2147#endif
2148			rstamps[k] = stamp;
2149			if (changed && r->var >= 0) {
2150				params->cmask |= 1 << r->var;
2151				vstamps[r->var] = stamp;
2152				again = 1;
2153			}
2154			if (changed < 0)
2155				goto _err;
2156			stamp++;
2157		}
2158	} while (again);
2159	if (!params->msbits) {
2160		i = hw_param_interval(params, SND_PCM_HW_PARAM_SAMPLE_BITS);
2161		if (snd_interval_single(i))
2162			params->msbits = snd_interval_value(i);
2163		m = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT);
2164		if (snd_mask_single(m)) {
2165			snd_pcm_format_t format = snd_mask_min(m);
2166			params->msbits = snd_pcm_format_width(format);
2167		}
2168	}
2169
2170	if (!params->rate_den) {
2171		i = hw_param_interval(params, SND_PCM_HW_PARAM_RATE);
2172		if (snd_interval_single(i)) {
2173			params->rate_num = snd_interval_value(i);
2174			params->rate_den = 1;
2175		}
2176	}
2177	params->rmask = 0;
2178	return 0;
2179 _err:
2180#ifdef RULES_DEBUG
2181	snd_output_printf(log, "refine_soft '%s' (end-%i)\n", pcm->name, changed);
2182	snd_pcm_hw_params_dump(params, log);
2183	snd_output_close(log);
2184#endif
2185	return changed;
2186}
2187
2188int _snd_pcm_hw_params_refine(snd_pcm_hw_params_t *params,
2189			      unsigned int vars,
2190			      const snd_pcm_hw_params_t *src)
2191{
2192	int changed, err = 0;
2193	unsigned int k;
2194	for (k = 0; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; ++k) {
2195		if (!(vars & (1 << k)))
2196			continue;
2197		changed = _snd_pcm_hw_param_refine(params, k, src);
2198		if (changed < 0)
2199			err = changed;
2200	}
2201	params->info &= src->info;
2202	params->flags = src->flags; /* propagate all flags to slave */
2203	return err;
2204}
2205
2206int snd_pcm_hw_refine_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
2207			    int (*cprepare)(snd_pcm_t *pcm,
2208					    snd_pcm_hw_params_t *params),
2209			    int (*cchange)(snd_pcm_t *pcm,
2210					   snd_pcm_hw_params_t *params,
2211					   snd_pcm_hw_params_t *sparams),
2212			    int (*sprepare)(snd_pcm_t *pcm,
2213					    snd_pcm_hw_params_t *params),
2214			    int (*schange)(snd_pcm_t *pcm,
2215					   snd_pcm_hw_params_t *params,
2216					   snd_pcm_hw_params_t *sparams),
2217			    int (*srefine)(snd_pcm_t *pcm,
2218					   snd_pcm_hw_params_t *sparams))
2219
2220{
2221#ifdef RULES_DEBUG
2222	snd_output_t *log;
2223#endif
2224	snd_pcm_hw_params_t sparams;
2225	int err;
2226	unsigned int cmask, changed;
2227#ifdef RULES_DEBUG
2228	snd_output_stdio_attach(&log, stderr, 0);
2229#endif
2230	err = cprepare(pcm, params);
2231	if (err < 0)
2232		return err;
2233	err = sprepare(pcm, &sparams);
2234	if (err < 0) {
2235		SNDERR("Slave PCM not usable");
2236		return err;
2237	}
2238#ifdef RULES_DEBUG
2239	snd_output_printf(log, "hw_refine_slave - enter '%s'\n", pcm->name);
2240#endif
2241	do {
2242		cmask = params->cmask;
2243		params->cmask = 0;
2244#ifdef RULES_DEBUG
2245		snd_output_printf(log, "schange '%s' (client)\n", pcm->name);
2246		snd_pcm_hw_params_dump(params, log);
2247		snd_output_printf(log, "schange '%s' (slave)\n", pcm->name);
2248		snd_pcm_hw_params_dump(&sparams, log);
2249#endif
2250		err = schange(pcm, params, &sparams);
2251		if (err >= 0) {
2252#ifdef RULES_DEBUG
2253			snd_output_printf(log, "srefine '%s' (client)\n", pcm->name);
2254			snd_pcm_hw_params_dump(params, log);
2255			snd_output_printf(log, "srefine '%s' (slave)\n", pcm->name);
2256			snd_pcm_hw_params_dump(&sparams, log);
2257#endif
2258			err = srefine(pcm, &sparams);
2259			if (err < 0) {
2260#ifdef RULES_DEBUG
2261				snd_output_printf(log, "srefine '%s', err < 0 (%i) (client)\n", pcm->name, err);
2262				snd_pcm_hw_params_dump(params, log);
2263				snd_output_printf(log, "srefine '%s', err < 0 (%i) (slave)\n", pcm->name, err);
2264				snd_pcm_hw_params_dump(&sparams, log);
2265#endif
2266				cchange(pcm, params, &sparams);
2267				return err;
2268			}
2269		} else {
2270#ifdef RULES_DEBUG
2271			snd_output_printf(log, "schange '%s', err < 0 (%i) (client)\n", pcm->name, err);
2272			snd_pcm_hw_params_dump(params, log);
2273			snd_output_printf(log, "schange '%s', err < 0 (%i) (slave)\n", pcm->name, err);
2274			snd_pcm_hw_params_dump(&sparams, log);
2275#endif
2276			cchange(pcm, params, &sparams);
2277			return err;
2278		}
2279#ifdef RULES_DEBUG
2280		snd_output_printf(log, "cchange '%s'\n", pcm->name);
2281#endif
2282		err = cchange(pcm, params, &sparams);
2283		if (err < 0)
2284			return err;
2285#ifdef RULES_DEBUG
2286		snd_output_printf(log, "refine_soft '%s'\n", pcm->name);
2287#endif
2288		err = snd_pcm_hw_refine_soft(pcm, params);
2289		changed = params->cmask;
2290		params->cmask |= cmask;
2291		if (err < 0)
2292			return err;
2293#ifdef RULES_DEBUG
2294		snd_output_printf(log, "refine_soft ok '%s'\n", pcm->name);
2295#endif
2296	} while (changed);
2297#ifdef RULES_DEBUG
2298	snd_output_printf(log, "refine_slave - leave '%s'\n", pcm->name);
2299	snd_output_close(log);
2300#endif
2301	return 0;
2302}
2303
2304int snd_pcm_hw_params_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
2305			    int (*cchange)(snd_pcm_t *pcm,
2306					   snd_pcm_hw_params_t *params,
2307					   snd_pcm_hw_params_t *sparams),
2308			    int (*sprepare)(snd_pcm_t *pcm,
2309					    snd_pcm_hw_params_t *params),
2310			    int (*schange)(snd_pcm_t *pcm,
2311					   snd_pcm_hw_params_t *params,
2312					   snd_pcm_hw_params_t *sparams),
2313			    int (*sparams)(snd_pcm_t *pcm,
2314					   snd_pcm_hw_params_t *sparams))
2315
2316{
2317	snd_pcm_hw_params_t slave_params;
2318	int err;
2319	err = sprepare(pcm, &slave_params);
2320	if (err < 0)
2321		return err;
2322	err = schange(pcm, params, &slave_params);
2323	if (err < 0)
2324		return err;
2325	err = sparams(pcm, &slave_params);
2326	if (err < 0)
2327		cchange(pcm, params, &slave_params);
2328	return err;
2329}
2330
2331static int snd_pcm_sw_params_default(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)
2332{
2333	assert(pcm && params);
2334	assert(pcm->setup);
2335	params->proto = SNDRV_PCM_VERSION;
2336	params->tstamp_mode = SND_PCM_TSTAMP_NONE;
2337	params->tstamp_type = pcm->tstamp_type;
2338	params->period_step = 1;
2339	params->sleep_min = 0;
2340	params->avail_min = pcm->period_size;
2341	params->xfer_align = 1;
2342	params->start_threshold = 1;
2343	params->stop_threshold = pcm->buffer_size;
2344	params->silence_threshold = 0;
2345	params->silence_size = 0;
2346	params->boundary = pcm->buffer_size;
2347	/* this should not happen (bad child?) */
2348	if (params->boundary == 0)
2349		return -EINVAL;
2350	while (params->boundary * 2 <= LONG_MAX - pcm->buffer_size)
2351		params->boundary *= 2;
2352	return 0;
2353}
2354
2355#if 0
2356#define REFINE_DEBUG
2357#endif
2358
2359int snd_pcm_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
2360{
2361	int res;
2362#ifdef REFINE_DEBUG
2363	snd_output_t *log;
2364	snd_output_stdio_attach(&log, stderr, 0);
2365#endif
2366	assert(pcm && params);
2367#ifdef REFINE_DEBUG
2368	snd_output_printf(log, "REFINE called:\n");
2369	snd_pcm_hw_params_dump(params, log);
2370#endif
2371	if (pcm->ops->hw_refine)
2372		res = pcm->ops->hw_refine(pcm->op_arg, params);
2373	else
2374		res = -ENOSYS;
2375#ifdef REFINE_DEBUG
2376	snd_output_printf(log, "refine done - result = %i\n", res);
2377	snd_pcm_hw_params_dump(params, log);
2378	snd_output_close(log);
2379#endif
2380	return res;
2381}
2382
2383/* Install one of the configurations present in configuration
2384   space defined by PARAMS.
2385   The configuration chosen is that obtained fixing in this order:
2386   first access
2387   first format
2388   first subformat
2389   min channels
2390   min rate
2391   min period_size
2392   max periods
2393   Return 0 on success otherwise a negative error code
2394*/
2395int _snd_pcm_hw_params_internal(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
2396{
2397	int err;
2398	snd_pcm_sw_params_t sw;
2399	int fb, min_align;
2400	err = snd_pcm_hw_refine(pcm, params);
2401	if (err < 0)
2402		return err;
2403	snd_pcm_hw_params_choose(pcm, params);
2404	if (pcm->setup) {
2405		err = snd_pcm_hw_free(pcm);
2406		if (err < 0)
2407			return err;
2408	}
2409	if (pcm->ops->hw_params)
2410		err = pcm->ops->hw_params(pcm->op_arg, params);
2411	else
2412		err = -ENOSYS;
2413	if (err < 0)
2414		return err;
2415
2416	pcm->setup = 1;
2417	INTERNAL(snd_pcm_hw_params_get_access)(params, &pcm->access);
2418	INTERNAL(snd_pcm_hw_params_get_format)(params, &pcm->format);
2419	INTERNAL(snd_pcm_hw_params_get_subformat)(params, &pcm->subformat);
2420	INTERNAL(snd_pcm_hw_params_get_channels)(params, &pcm->channels);
2421	INTERNAL(snd_pcm_hw_params_get_rate)(params, &pcm->rate, 0);
2422	snd_interval_copy(&pcm->periods, &params->intervals[SND_PCM_HW_PARAM_PERIODS - SND_PCM_HW_PARAM_FIRST_INTERVAL]);
2423	snd_interval_copy(&pcm->buffer_time, &params->intervals[SND_PCM_HW_PARAM_BUFFER_TIME - SND_PCM_HW_PARAM_FIRST_INTERVAL]);
2424	INTERNAL(snd_pcm_hw_params_get_period_time)(params, &pcm->period_time, 0);
2425	INTERNAL(snd_pcm_hw_params_get_period_size)(params, &pcm->period_size, 0);
2426	INTERNAL(snd_pcm_hw_params_get_buffer_size)(params, &pcm->buffer_size);
2427	pcm->sample_bits = snd_pcm_format_physical_width(pcm->format);
2428	pcm->frame_bits = pcm->sample_bits * pcm->channels;
2429	fb = pcm->frame_bits;
2430	min_align = 1;
2431	while (fb % 8) {
2432		fb *= 2;
2433		min_align *= 2;
2434	}
2435	pcm->min_align = min_align;
2436
2437	pcm->hw_flags = params->flags;
2438	pcm->info = params->info;
2439	pcm->msbits = params->msbits;
2440	pcm->rate_num = params->rate_num;
2441	pcm->rate_den = params->rate_den;
2442	pcm->fifo_size = params->fifo_size;
2443
2444	/* Default sw params */
2445	memset(&sw, 0, sizeof(sw));
2446	err = snd_pcm_sw_params_default(pcm, &sw);
2447	if (err < 0)
2448		return err;
2449	err = snd_pcm_sw_params(pcm, &sw);
2450	if (err < 0)
2451		return err;
2452
2453	if (pcm->mmap_rw ||
2454	    pcm->access == SND_PCM_ACCESS_MMAP_INTERLEAVED ||
2455	    pcm->access == SND_PCM_ACCESS_MMAP_NONINTERLEAVED ||
2456	    pcm->access == SND_PCM_ACCESS_MMAP_COMPLEX) {
2457		err = snd_pcm_mmap(pcm);
2458	}
2459	if (err < 0)
2460		return err;
2461	return 0;
2462}
2463
2464