Home | History | Annotate | Download | only in pcm
      1 /*
      2  *  PCM - Params functions
      3  *  Copyright (c) 2000 by Abramo Bagnara <abramo (at) 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 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  */
     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
     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 
     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 
     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 
     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 
    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 
    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 */
    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. */
    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. */
    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. */
    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. */
    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 
    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 
    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 
    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 */
    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 
    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 */
    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 
    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 */
    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 
    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 */
    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 
    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 */
    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 
    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 */
    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 
    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 */
    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 
    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 */
    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  */
    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 
    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 
    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 
    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 
   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 
   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 
   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 */
   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 	err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_PERIOD_TIME, NULL, 0);
   1107 	if (err < 0)
   1108 		return err;
   1109 	err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_PERIOD_SIZE, NULL, 0);
   1110 	if (err < 0)
   1111 		return err;
   1112 	err = snd_pcm_hw_param_set_last(pcm, params, SND_PCM_HW_PARAM_BUFFER_SIZE, NULL, 0);
   1113 	if (err < 0)
   1114 		return err;
   1115 	err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_TICK_TIME, NULL, 0);
   1116 	if (err < 0)
   1117 		return err;
   1118 #ifdef CHOOSE_DEBUG
   1119 	snd_output_printf(log, "choose done\n");
   1120 	snd_pcm_hw_params_dump(params, log);
   1121 	snd_output_close(log);
   1122 #endif
   1123 	return 0;
   1124 }
   1125 
   1126 #if 0
   1127 static unsigned int snd_pcm_hw_param_count(const snd_pcm_hw_params_t *params,
   1128 					   snd_pcm_hw_param_t var)
   1129 {
   1130 	if (hw_is_mask(var)) {
   1131 		const snd_mask_t *mask = hw_param_mask_c(params, var);
   1132 		return snd_mask_count(mask);
   1133 	}
   1134 	if (hw_is_interval(var)) {
   1135 		const snd_interval_t *i = hw_param_interval_c(params, var);
   1136 		return snd_interval_max(i) - snd_interval_min(i) + 1;
   1137 	}
   1138 	assert(0);
   1139 	return 0;
   1140 }
   1141 #endif
   1142 
   1143 int _snd_pcm_hw_param_refine(snd_pcm_hw_params_t *params,
   1144 			     snd_pcm_hw_param_t var,
   1145 			     const snd_pcm_hw_params_t *src)
   1146 {
   1147 	int changed = 0;
   1148 	if (hw_is_mask(var)) {
   1149 		snd_mask_t *d = hw_param_mask(params, var);
   1150 		const snd_mask_t *s = hw_param_mask_c(src, var);
   1151 		changed = snd_mask_refine(d, s);
   1152 	} else if (hw_is_interval(var)) {
   1153 		snd_interval_t *d = hw_param_interval(params, var);
   1154 		const snd_interval_t *s = hw_param_interval_c(src, var);
   1155 		changed = snd_interval_refine(d, s);
   1156 	} else
   1157 		return 0; /* NOP / reserved */
   1158 	if (changed) {
   1159 		params->cmask |= 1 << var;
   1160 		params->rmask |= 1 << var;
   1161 	}
   1162 	return changed;
   1163 }
   1164 
   1165 #if 0
   1166 static void _snd_pcm_hw_param_copy(snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var,
   1167 				   const snd_pcm_hw_params_t *src)
   1168 {
   1169 	if (hw_is_mask(var)) {
   1170 		snd_mask_t *d = hw_param_mask(params, var);
   1171 		const snd_mask_t *s = hw_param_mask_c(src, var);
   1172 		snd_mask_copy(d, s);
   1173 		params->cmask |= 1 << var;
   1174 		params->rmask |= 1 << var;
   1175 		return;
   1176 	}
   1177 	if (hw_is_interval(var)) {
   1178 		snd_interval_t *d = hw_param_interval(params, var);
   1179 		const snd_interval_t *s = hw_param_interval_c(src, var);
   1180 		snd_interval_copy(d, s);
   1181 		params->cmask |= 1 << var;
   1182 		params->rmask |= 1 << var;
   1183 		return;
   1184 	}
   1185 	assert(0);
   1186 }
   1187 #endif
   1188 
   1189 void snd_pcm_hw_param_dump(const snd_pcm_hw_params_t *params,
   1190 			   snd_pcm_hw_param_t var, snd_output_t *out)
   1191 {
   1192 	if (hw_is_mask(var)) {
   1193 		const snd_mask_t *mask = hw_param_mask_c(params, var);
   1194 		if (snd_mask_empty(mask))
   1195 			snd_output_puts(out, " NONE");
   1196 		else if (snd_mask_full(mask))
   1197 			snd_output_puts(out, " ALL");
   1198 		else {
   1199 			unsigned int k;
   1200 			for (k = 0; k <= SND_MASK_MAX; ++k) {
   1201 				if (snd_mask_test(mask, k)) {
   1202 					const char *s;
   1203 					switch (var) {
   1204 					case SND_PCM_HW_PARAM_ACCESS:
   1205 						s = snd_pcm_access_name(k);
   1206 						break;
   1207 					case SND_PCM_HW_PARAM_FORMAT:
   1208 						s = snd_pcm_format_name(k);
   1209 						break;
   1210 					case SND_PCM_HW_PARAM_SUBFORMAT:
   1211 						s = snd_pcm_subformat_name(k);
   1212 						break;
   1213 					default:
   1214 						assert(0);
   1215 						s = NULL;
   1216 					}
   1217 					if (s) {
   1218 						snd_output_putc(out, ' ');
   1219 						snd_output_puts(out, s);
   1220 					}
   1221 				}
   1222 			}
   1223 		}
   1224 		return;
   1225 	}
   1226 	if (hw_is_interval(var)) {
   1227 		snd_interval_print(hw_param_interval_c(params, var), out);
   1228 		return;
   1229 	}
   1230 	assert(0);
   1231 }
   1232 
   1233 #define HW_PARAM(v) [SND_PCM_HW_PARAM_##v] = #v
   1234 
   1235 static const char *const snd_pcm_hw_param_names[] = {
   1236 	HW_PARAM(ACCESS),
   1237 	HW_PARAM(FORMAT),
   1238 	HW_PARAM(SUBFORMAT),
   1239 	HW_PARAM(SAMPLE_BITS),
   1240 	HW_PARAM(FRAME_BITS),
   1241 	HW_PARAM(CHANNELS),
   1242 	HW_PARAM(RATE),
   1243 	HW_PARAM(PERIOD_TIME),
   1244 	HW_PARAM(PERIOD_SIZE),
   1245 	HW_PARAM(PERIOD_BYTES),
   1246 	HW_PARAM(PERIODS),
   1247 	HW_PARAM(BUFFER_TIME),
   1248 	HW_PARAM(BUFFER_SIZE),
   1249 	HW_PARAM(BUFFER_BYTES),
   1250 	HW_PARAM(TICK_TIME),
   1251 };
   1252 
   1253 const char *snd_pcm_hw_param_name(snd_pcm_hw_param_t param)
   1254 {
   1255 	assert(param <= SND_PCM_HW_PARAM_LAST_INTERVAL);
   1256 	return snd_pcm_hw_param_names[param];
   1257 }
   1258 
   1259 #if 0
   1260 /* Strategies */
   1261 
   1262 struct _snd_pcm_hw_strategy {
   1263 	unsigned int badness_min, badness_max;
   1264 	int (*choose_param)(const snd_pcm_hw_params_t *params,
   1265 			    snd_pcm_t *pcm,
   1266 			    const snd_pcm_hw_strategy_t *strategy);
   1267 	int (*next_value)(snd_pcm_hw_params_t *params,
   1268 			  unsigned int param,
   1269 			  int value, int *dir,
   1270 			  snd_pcm_t *pcm,
   1271 			  const snd_pcm_hw_strategy_t *strategy);
   1272 	int (*min_badness)(const snd_pcm_hw_params_t *params,
   1273 			   unsigned int max_badness,
   1274 			   snd_pcm_t *pcm,
   1275 			   const snd_pcm_hw_strategy_t *strategy);
   1276 	void *private_data;
   1277 	void (*free)(snd_pcm_hw_strategy_t *strategy);
   1278 };
   1279 
   1280 /* Independent badness */
   1281 typedef struct _snd_pcm_hw_strategy_simple snd_pcm_hw_strategy_simple_t;
   1282 
   1283 struct _snd_pcm_hw_strategy_simple {
   1284 	int valid;
   1285 	unsigned int order;
   1286 	int (*next_value)(snd_pcm_hw_params_t *params,
   1287 			  unsigned int param,
   1288 			  int value, int *dir,
   1289 			  snd_pcm_t *pcm,
   1290 			  const snd_pcm_hw_strategy_simple_t *par);
   1291 	unsigned int (*min_badness)(const snd_pcm_hw_params_t *params,
   1292 				    unsigned int param,
   1293 				    snd_pcm_t *pcm,
   1294 				    const snd_pcm_hw_strategy_simple_t *par);
   1295 	void *private_data;
   1296 	void (*free)(snd_pcm_hw_strategy_simple_t *strategy);
   1297 };
   1298 
   1299 typedef struct _snd_pcm_hw_strategy_simple_near {
   1300 	int best;
   1301 	unsigned int mul;
   1302 } snd_pcm_hw_strategy_simple_near_t;
   1303 
   1304 typedef struct _snd_pcm_hw_strategy_simple_choices {
   1305 	unsigned int count;
   1306 	/* choices need to be sorted on ascending badness */
   1307 	snd_pcm_hw_strategy_simple_choices_list_t *choices;
   1308 } snd_pcm_hw_strategy_simple_choices_t;
   1309 
   1310 int snd_pcm_hw_params_strategy(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
   1311 			       const snd_pcm_hw_strategy_t *strategy,
   1312 			       unsigned int badness_min,
   1313 			       unsigned int badness_max)
   1314 {
   1315 	snd_pcm_hw_params_t best_params;
   1316 	int var;
   1317 	int value, dir;
   1318 	unsigned int best_badness;
   1319 	int badness = strategy->min_badness(params, badness_max, pcm, strategy);
   1320 	snd_pcm_hw_params_t params1;
   1321 #if 0
   1322 	printf("\nBadness: %d\n", badness);
   1323 	snd_pcm_hw_params_dump(params, stdout);
   1324 #endif
   1325 	if (badness < 0)
   1326 		return badness;
   1327 	if ((unsigned int)badness > badness_min)
   1328 		badness_min = badness_min;
   1329 	var = strategy->choose_param(params, pcm, strategy);
   1330 	if (var < 0)
   1331 		return badness;
   1332 	best_badness = UINT_MAX;
   1333 	value = -1;
   1334 	while (1) {
   1335 		params1 = *params;
   1336 		value = strategy->next_value(&params1, var, value, &dir, pcm, strategy);
   1337 		if (value < 0)
   1338 			break;
   1339 		badness = snd_pcm_hw_params_strategy(pcm, &params1, strategy, badness_min, badness_max);
   1340 		if (badness >= 0) {
   1341 			if ((unsigned int) badness <= badness_min) {
   1342 				*params = params1;
   1343 				return badness;
   1344 			}
   1345 			best_badness = badness;
   1346 			best_params = params1;
   1347 			badness_max = badness - 1;
   1348 		}
   1349 	}
   1350 	if (best_badness == UINT_MAX) {
   1351 		return -EINVAL;
   1352 	}
   1353 	*params = best_params;
   1354 	return best_badness;
   1355 }
   1356 
   1357 void snd_pcm_hw_strategy_simple_free(snd_pcm_hw_strategy_t *strategy)
   1358 {
   1359 	snd_pcm_hw_strategy_simple_t *pars = strategy->private_data;
   1360 	int k;
   1361 	for (k = 0; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; ++k) {
   1362 		if (pars[k].valid && pars[k].free)
   1363 			pars[k].free(&pars[k]);
   1364 	}
   1365 	free(pars);
   1366 }
   1367 
   1368 int snd_pcm_hw_strategy_simple_choose_param(const snd_pcm_hw_params_t *params,
   1369 					 snd_pcm_t *pcm ATTRIBUTE_UNUSED,
   1370 					 const snd_pcm_hw_strategy_t *strategy)
   1371 {
   1372 	snd_pcm_hw_param_t var;
   1373 	int best_var = -1;
   1374 	const snd_pcm_hw_strategy_simple_t *pars = strategy->private_data;
   1375 	unsigned int min_choices = UINT_MAX;
   1376 	unsigned int min_order = UINT_MAX;
   1377 	for (var = 0; var <= SND_PCM_HW_PARAM_LAST_INTERVAL; ++var) {
   1378 		const snd_pcm_hw_strategy_simple_t *p = &pars[var];
   1379 		unsigned int choices;
   1380 		if (!p->valid)
   1381 			continue;
   1382 		choices = snd_pcm_hw_param_count(params, var);
   1383 		if (choices == 1)
   1384 			continue;
   1385 		assert(choices != 0);
   1386 		if (p->order < min_order ||
   1387 		    (p->order == min_order &&
   1388 		     choices < min_choices)) {
   1389 			min_order = p->order;
   1390 			min_choices = choices;
   1391 			best_var = var;
   1392 		}
   1393 	}
   1394 	return best_var;
   1395 }
   1396 
   1397 int snd_pcm_hw_strategy_simple_next_value(snd_pcm_hw_params_t *params,
   1398 					  snd_pcm_hw_param_t var,
   1399 					  int value, int *dir,
   1400 					  snd_pcm_t *pcm,
   1401 					  const snd_pcm_hw_strategy_t *strategy)
   1402 {
   1403 	const snd_pcm_hw_strategy_simple_t *pars = strategy->private_data;
   1404 	assert(pars[var].valid);
   1405 	return pars[var].next_value(params, var, value, dir, pcm, &pars[var]);
   1406 }
   1407 
   1408 
   1409 int snd_pcm_hw_strategy_simple_min_badness(const snd_pcm_hw_params_t *params,
   1410 					unsigned int max_badness,
   1411 					snd_pcm_t *pcm,
   1412 					const snd_pcm_hw_strategy_t *strategy)
   1413 {
   1414 	snd_pcm_hw_param_t var;
   1415 	unsigned int badness = 0;
   1416 	const snd_pcm_hw_strategy_simple_t *pars = strategy->private_data;
   1417 	for (var = 0; var <= SND_PCM_HW_PARAM_LAST_INTERVAL; ++var) {
   1418 		unsigned int b;
   1419 		if (!pars[var].valid)
   1420 			continue;
   1421 		b = pars[var].min_badness(params, var, pcm, &pars[var]);
   1422 		if (b > max_badness || max_badness - b < badness)
   1423 			return -E2BIG;
   1424 		badness += b;
   1425 	}
   1426 	return badness;
   1427 }
   1428 
   1429 
   1430 void snd_pcm_hw_strategy_simple_near_free(snd_pcm_hw_strategy_simple_t *par)
   1431 {
   1432 	snd_pcm_hw_strategy_simple_near_t *p = par->private_data;
   1433 	free(p);
   1434 }
   1435 
   1436 unsigned int snd_pcm_hw_strategy_simple_near_min_badness(const snd_pcm_hw_params_t *params,
   1437 						      snd_pcm_hw_param_t var,
   1438 						      snd_pcm_t *pcm,
   1439 						      const snd_pcm_hw_strategy_simple_t *par)
   1440 {
   1441 	const snd_pcm_hw_strategy_simple_near_t *p = par->private_data;
   1442 	snd_pcm_hw_params_t params1 = *params;
   1443 	int value = snd_pcm_hw_param_set_near(pcm, &params1, var, p->best, 0);
   1444 	int diff;
   1445 	assert(value >= 0);
   1446 	diff = p->best - value;
   1447 	if (diff < 0)
   1448 		diff = -diff;
   1449 	return diff * p->mul;
   1450 }
   1451 
   1452 int snd_pcm_hw_strategy_simple_near_next_value(snd_pcm_hw_params_t *params,
   1453 					       snd_pcm_hw_param_t var,
   1454 					       int value, int *dir,
   1455 					       snd_pcm_t *pcm,
   1456 					       const snd_pcm_hw_strategy_simple_t *par)
   1457 {
   1458 	const snd_pcm_hw_strategy_simple_near_t *p = par->private_data;
   1459 	if (value < 0) {
   1460 		*dir = 0;
   1461 		return snd_pcm_hw_param_set_near(pcm, params, var, p->best, dir);
   1462 	} else
   1463 		return snd_pcm_hw_param_set_next(pcm, params, var, p->best, 0, value, dir);
   1464 }
   1465 
   1466 void snd_pcm_hw_strategy_simple_choices_free(snd_pcm_hw_strategy_simple_t *par)
   1467 {
   1468 	snd_pcm_hw_strategy_simple_choices_t *p = par->private_data;
   1469 //	free(p->choices);
   1470 	free(p);
   1471 }
   1472 
   1473 unsigned int snd_pcm_hw_strategy_simple_choices_min_badness(const snd_pcm_hw_params_t *params,
   1474 							 snd_pcm_hw_param_t var,
   1475 							 snd_pcm_t *pcm,
   1476 							 const snd_pcm_hw_strategy_simple_t *par)
   1477 {
   1478 	const snd_pcm_hw_strategy_simple_choices_t *p = par->private_data;
   1479 	unsigned int k;
   1480 	for (k = 0; k < p->count; ++k) {
   1481 		if (snd_pcm_hw_param_set(pcm, (snd_pcm_hw_params_t *) params, SND_TEST, var, p->choices[k].value, 0))
   1482 			return p->choices[k].badness;
   1483 	}
   1484 	assert(0);
   1485 	return UINT_MAX;
   1486 }
   1487 
   1488 int snd_pcm_hw_strategy_simple_choices_next_value(snd_pcm_hw_params_t *params,
   1489 						  snd_pcm_hw_param_t var,
   1490 						  int value, int *dir,
   1491 						  snd_pcm_t *pcm,
   1492 						  const snd_pcm_hw_strategy_simple_t *par)
   1493 {
   1494 	const snd_pcm_hw_strategy_simple_choices_t *p = par->private_data;
   1495 	unsigned int k = 0;
   1496 	if (value >= 0) {
   1497 		for (; k < p->count; ++k) {
   1498 			if (p->choices[k].value == (unsigned int) value) {
   1499 				k++;
   1500 				break;
   1501 			}
   1502 		}
   1503 	}
   1504 	for (; k < p->count; ++k) {
   1505 		unsigned int v = p->choices[k].value;
   1506 		int err = snd_pcm_hw_param_set(pcm, params, SND_TRY, var, v, 0);
   1507 		if (err < 0)
   1508 			continue;
   1509 		*dir = 0;
   1510 		return v;
   1511 	}
   1512 	return -1;
   1513 }
   1514 
   1515 void snd_pcm_hw_strategy_free(snd_pcm_hw_strategy_t *strategy)
   1516 {
   1517 	if (strategy->free)
   1518 		strategy->free(strategy);
   1519 	free(strategy);
   1520 }
   1521 
   1522 int snd_pcm_hw_strategy_simple(snd_pcm_hw_strategy_t **strategyp,
   1523 			    unsigned int badness_min,
   1524 			    unsigned int badness_max)
   1525 {
   1526 	snd_pcm_hw_strategy_simple_t *data;
   1527 	snd_pcm_hw_strategy_t *s;
   1528 	assert(strategyp);
   1529 	data = calloc(SND_PCM_HW_PARAM_LAST_INTERVAL + 1, sizeof(*data));
   1530 	if (!data)
   1531 		return -ENOMEM;
   1532 	s = calloc(1, sizeof(*s));
   1533 	if (!s) {
   1534 		free(data);
   1535 		return -ENOMEM;
   1536 	}
   1537 	s->choose_param = snd_pcm_hw_strategy_simple_choose_param;
   1538 	s->next_value = snd_pcm_hw_strategy_simple_next_value;
   1539 	s->min_badness = snd_pcm_hw_strategy_simple_min_badness;
   1540 	s->badness_min = badness_min;
   1541 	s->badness_max = badness_max;
   1542 	s->private_data = data;
   1543 	s->free = snd_pcm_hw_strategy_simple_free;
   1544 	*strategyp = s;
   1545 	return 0;
   1546 }
   1547 
   1548 int snd_pcm_hw_strategy_simple_near(snd_pcm_hw_strategy_t *strategy,
   1549 				 int order,
   1550 				 snd_pcm_hw_param_t var,
   1551 				 unsigned int best,
   1552 				 unsigned int mul)
   1553 {
   1554 	snd_pcm_hw_strategy_simple_t *s = strategy->private_data;
   1555 	snd_pcm_hw_strategy_simple_near_t *data;
   1556 	assert(strategy);
   1557 	assert(var <= SND_PCM_HW_PARAM_LAST_INTERVAL);
   1558 	assert(!s->valid);
   1559 	data = calloc(1, sizeof(*data));
   1560 	if (!data)
   1561 		return -ENOMEM;
   1562 	data->best = best;
   1563 	data->mul = mul;
   1564 	s += var;
   1565 	s->order = order;
   1566 	s->valid = 1;
   1567 	s->next_value = snd_pcm_hw_strategy_simple_near_next_value;
   1568 	s->min_badness = snd_pcm_hw_strategy_simple_near_min_badness;
   1569 	s->private_data = data;
   1570 	s->free = snd_pcm_hw_strategy_simple_near_free;
   1571 	return 0;
   1572 }
   1573 
   1574 int snd_pcm_hw_strategy_simple_choices(snd_pcm_hw_strategy_t *strategy,
   1575 				    int order,
   1576 				    snd_pcm_hw_param_t var,
   1577 				    unsigned int count,
   1578 				    snd_pcm_hw_strategy_simple_choices_list_t *choices)
   1579 {
   1580 	snd_pcm_hw_strategy_simple_t *s = strategy->private_data;
   1581 	snd_pcm_hw_strategy_simple_choices_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->count = count;
   1589 	data->choices = choices;
   1590 	s += var;
   1591 	s->valid = 1;
   1592 	s->order = order;
   1593 	s->next_value = snd_pcm_hw_strategy_simple_choices_next_value;
   1594 	s->min_badness = snd_pcm_hw_strategy_simple_choices_min_badness;
   1595 	s->private_data = data;
   1596 	s->free = snd_pcm_hw_strategy_simple_choices_free;
   1597 	return 0;
   1598 }
   1599 
   1600 int snd_pcm_hw_params_try_explain_failure1(snd_pcm_t *pcm,
   1601 					   snd_pcm_hw_params_t *fail,
   1602 					   snd_pcm_hw_params_t *success,
   1603 					   unsigned int depth,
   1604 					   snd_output_t *out)
   1605 {
   1606 	snd_pcm_hw_param_t var;
   1607 	snd_pcm_hw_params_t i;
   1608 	if (depth < 1)
   1609 		return -ENOENT;
   1610 	for (var = 0; var <= SND_PCM_HW_PARAM_LAST_INTERVAL; var++) {
   1611 		int err;
   1612 		i = *success;
   1613 		_snd_pcm_hw_param_copy(&i, var, fail);
   1614 		err = snd_pcm_hw_refine(pcm, &i);
   1615 		if (err == 0 &&
   1616 		    snd_pcm_hw_params_try_explain_failure1(pcm, fail, &i, depth - 1, out) < 0)
   1617 			continue;
   1618 		snd_output_printf(out, "%s: ", snd_pcm_hw_param_name(var));
   1619 		snd_pcm_hw_param_dump(fail, var, out);
   1620 		snd_output_putc(out, '\n');
   1621 		return 0;
   1622 	}
   1623 	return -ENOENT;
   1624 }
   1625 
   1626 int snd_pcm_hw_params_try_explain_failure(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_params_t i, any;
   1633 	int err;
   1634 	snd_pcm_hw_param_t var;
   1635 	int done = 0;
   1636 	assert(pcm && fail);
   1637 	for (var = 0; var <= SND_PCM_HW_PARAM_LAST_INTERVAL; var++) {
   1638 		if (!snd_pcm_hw_param_empty(fail, var))
   1639 			continue;
   1640 		snd_output_printf(out, "%s is empty\n", snd_pcm_hw_param_name(var));
   1641 		done = 1;
   1642 	}
   1643 	if (done)
   1644 		return 0;
   1645 	i = *fail;
   1646 	err = snd_pcm_hw_refine(pcm, &i);
   1647 	if (err == 0) {
   1648 		snd_output_printf(out, "Configuration is virtually correct\n");
   1649 		return 0;
   1650 	}
   1651 	if (!success) {
   1652 		snd_pcm_hw_params_any(pcm, &any);
   1653 		success = &any;
   1654 	}
   1655 	return snd_pcm_hw_params_try_explain_failure1(pcm, fail, success, depth, out);
   1656 }
   1657 
   1658 #endif
   1659 
   1660 typedef struct _snd_pcm_hw_rule snd_pcm_hw_rule_t;
   1661 
   1662 typedef int (*snd_pcm_hw_rule_func_t)(snd_pcm_hw_params_t *params,
   1663 				      const snd_pcm_hw_rule_t *rule);
   1664 
   1665 struct _snd_pcm_hw_rule {
   1666 	int var;
   1667 	snd_pcm_hw_rule_func_t func;
   1668 	int deps[4];
   1669 	void *private_data;
   1670 };
   1671 
   1672 static int snd_pcm_hw_rule_mul(snd_pcm_hw_params_t *params,
   1673 			       const snd_pcm_hw_rule_t *rule)
   1674 {
   1675 	snd_interval_t t;
   1676 	snd_interval_mul(hw_param_interval_c(params, rule->deps[0]),
   1677 		     hw_param_interval_c(params, rule->deps[1]), &t);
   1678 	return snd_interval_refine(hw_param_interval(params, rule->var), &t);
   1679 }
   1680 
   1681 static int snd_pcm_hw_rule_div(snd_pcm_hw_params_t *params,
   1682 			const snd_pcm_hw_rule_t *rule)
   1683 {
   1684 	snd_interval_t t;
   1685 	snd_interval_div(hw_param_interval_c(params, rule->deps[0]),
   1686 		     hw_param_interval_c(params, rule->deps[1]), &t);
   1687 	return snd_interval_refine(hw_param_interval(params, rule->var), &t);
   1688 }
   1689 
   1690 static int snd_pcm_hw_rule_muldivk(snd_pcm_hw_params_t *params,
   1691 				   const snd_pcm_hw_rule_t *rule)
   1692 {
   1693 	snd_interval_t t;
   1694 	snd_interval_muldivk(hw_param_interval_c(params, rule->deps[0]),
   1695 			 hw_param_interval_c(params, rule->deps[1]),
   1696 			 (unsigned long) rule->private_data, &t);
   1697 	return snd_interval_refine(hw_param_interval(params, rule->var), &t);
   1698 }
   1699 
   1700 static int snd_pcm_hw_rule_mulkdiv(snd_pcm_hw_params_t *params,
   1701 				   const snd_pcm_hw_rule_t *rule)
   1702 {
   1703 	snd_interval_t t;
   1704 	snd_interval_mulkdiv(hw_param_interval_c(params, rule->deps[0]),
   1705 			 (unsigned long) rule->private_data,
   1706 			 hw_param_interval_c(params, rule->deps[1]), &t);
   1707 	return snd_interval_refine(hw_param_interval(params, rule->var), &t);
   1708 }
   1709 
   1710 static int snd_pcm_hw_rule_format(snd_pcm_hw_params_t *params,
   1711 				  const snd_pcm_hw_rule_t *rule)
   1712 {
   1713 	int changed = 0;
   1714 	snd_pcm_format_t k;
   1715 	snd_mask_t *mask = hw_param_mask(params, rule->var);
   1716 	snd_interval_t *i = hw_param_interval(params, rule->deps[0]);
   1717 	for (k = 0; k <= SND_PCM_FORMAT_LAST; k++) {
   1718 		int bits;
   1719 		if (!snd_pcm_format_mask_test(mask, k))
   1720 			continue;
   1721 		bits = snd_pcm_format_physical_width(k);
   1722 		if (bits < 0)
   1723 			continue;
   1724 		if (!snd_interval_test(i, (unsigned int) bits)) {
   1725 			snd_pcm_format_mask_reset(mask, k);
   1726 			if (snd_mask_empty(mask))
   1727 				return -EINVAL;
   1728 			changed = 1;
   1729 		}
   1730 	}
   1731 	return changed;
   1732 }
   1733 
   1734 
   1735 static int snd_pcm_hw_rule_sample_bits(snd_pcm_hw_params_t *params,
   1736 				       const snd_pcm_hw_rule_t *rule)
   1737 {
   1738 	unsigned int min, max;
   1739 	snd_pcm_format_t k;
   1740 	snd_interval_t *i = hw_param_interval(params, rule->var);
   1741 	snd_mask_t *mask = hw_param_mask(params, rule->deps[0]);
   1742 	int c, changed = 0;
   1743 	min = UINT_MAX;
   1744 	max = 0;
   1745 	for (k = 0; k <= SND_PCM_FORMAT_LAST; k++) {
   1746 		int bits;
   1747 		if (!snd_pcm_format_mask_test(mask, k))
   1748 			continue;
   1749 		bits = snd_pcm_format_physical_width(k);
   1750 		if (bits < 0)
   1751 			continue;
   1752 		if (min > (unsigned)bits)
   1753 			min = bits;
   1754 		if (max < (unsigned)bits)
   1755 			max = bits;
   1756 	}
   1757 	c = snd_interval_refine_min(i, min, 0);
   1758 	if (c < 0)
   1759 		return c;
   1760 	if (c)
   1761 		changed = 1;
   1762 	c = snd_interval_refine_max(i, max, 0);
   1763 	if (c < 0)
   1764 		return c;
   1765 	if (c)
   1766 		changed = 1;
   1767 	return changed;
   1768 }
   1769 
   1770 static const snd_pcm_hw_rule_t refine_rules[] = {
   1771 	{
   1772 		.var = SND_PCM_HW_PARAM_FORMAT,
   1773 		.func = snd_pcm_hw_rule_format,
   1774 		.deps = { SND_PCM_HW_PARAM_SAMPLE_BITS, -1 },
   1775 		.private_data = 0,
   1776 	},
   1777 	{
   1778 		.var = SND_PCM_HW_PARAM_SAMPLE_BITS,
   1779 		.func = snd_pcm_hw_rule_sample_bits,
   1780 		.deps = { SND_PCM_HW_PARAM_FORMAT,
   1781 			SND_PCM_HW_PARAM_SAMPLE_BITS, -1 },
   1782 		.private_data = 0,
   1783 	},
   1784 	{
   1785 		.var = SND_PCM_HW_PARAM_SAMPLE_BITS,
   1786 		.func = snd_pcm_hw_rule_div,
   1787 		.deps = { SND_PCM_HW_PARAM_FRAME_BITS,
   1788 			SND_PCM_HW_PARAM_CHANNELS, -1 },
   1789 		.private_data = 0,
   1790 	},
   1791 	{
   1792 		.var = SND_PCM_HW_PARAM_FRAME_BITS,
   1793 		.func = snd_pcm_hw_rule_mul,
   1794 		.deps = { SND_PCM_HW_PARAM_SAMPLE_BITS,
   1795 			SND_PCM_HW_PARAM_CHANNELS, -1 },
   1796 		.private_data = 0,
   1797 	},
   1798 	{
   1799 		.var = SND_PCM_HW_PARAM_FRAME_BITS,
   1800 		.func = snd_pcm_hw_rule_mulkdiv,
   1801 		.deps = { SND_PCM_HW_PARAM_PERIOD_BYTES,
   1802 			SND_PCM_HW_PARAM_PERIOD_SIZE, -1 },
   1803 		.private_data = (void*) 8,
   1804 	},
   1805 	{
   1806 		.var = SND_PCM_HW_PARAM_FRAME_BITS,
   1807 		.func = snd_pcm_hw_rule_mulkdiv,
   1808 		.deps = { SND_PCM_HW_PARAM_BUFFER_BYTES,
   1809 			SND_PCM_HW_PARAM_BUFFER_SIZE, -1 },
   1810 		.private_data = (void*) 8,
   1811 	},
   1812 	{
   1813 		.var = SND_PCM_HW_PARAM_CHANNELS,
   1814 		.func = snd_pcm_hw_rule_div,
   1815 		.deps = { SND_PCM_HW_PARAM_FRAME_BITS,
   1816 			SND_PCM_HW_PARAM_SAMPLE_BITS, -1 },
   1817 		.private_data = 0,
   1818 	},
   1819 	{
   1820 		.var = SND_PCM_HW_PARAM_RATE,
   1821 		.func = snd_pcm_hw_rule_mulkdiv,
   1822 		.deps = { SND_PCM_HW_PARAM_PERIOD_SIZE,
   1823 			SND_PCM_HW_PARAM_PERIOD_TIME, -1 },
   1824 		.private_data = (void*) 1000000,
   1825 	},
   1826 	{
   1827 		.var = SND_PCM_HW_PARAM_RATE,
   1828 		.func = snd_pcm_hw_rule_mulkdiv,
   1829 		.deps = { SND_PCM_HW_PARAM_BUFFER_SIZE,
   1830 			SND_PCM_HW_PARAM_BUFFER_TIME, -1 },
   1831 		.private_data = (void*) 1000000,
   1832 	},
   1833 	{
   1834 		.var = SND_PCM_HW_PARAM_PERIODS,
   1835 		.func = snd_pcm_hw_rule_div,
   1836 		.deps = { SND_PCM_HW_PARAM_BUFFER_SIZE,
   1837 			SND_PCM_HW_PARAM_PERIOD_SIZE, -1 },
   1838 		.private_data = 0,
   1839 	},
   1840 	{
   1841 		.var = SND_PCM_HW_PARAM_PERIOD_SIZE,
   1842 		.func = snd_pcm_hw_rule_div,
   1843 		.deps = { SND_PCM_HW_PARAM_BUFFER_SIZE,
   1844 			SND_PCM_HW_PARAM_PERIODS, -1 },
   1845 		.private_data = 0,
   1846 	},
   1847 	{
   1848 		.var = SND_PCM_HW_PARAM_PERIOD_SIZE,
   1849 		.func = snd_pcm_hw_rule_mulkdiv,
   1850 		.deps = { SND_PCM_HW_PARAM_PERIOD_BYTES,
   1851 			SND_PCM_HW_PARAM_FRAME_BITS, -1 },
   1852 		.private_data = (void*) 8,
   1853 	},
   1854 	{
   1855 		.var = SND_PCM_HW_PARAM_PERIOD_SIZE,
   1856 		.func = snd_pcm_hw_rule_muldivk,
   1857 		.deps = { SND_PCM_HW_PARAM_PERIOD_TIME,
   1858 			SND_PCM_HW_PARAM_RATE, -1 },
   1859 		.private_data = (void*) 1000000,
   1860 	},
   1861 	{
   1862 		.var = SND_PCM_HW_PARAM_BUFFER_SIZE,
   1863 		.func = snd_pcm_hw_rule_mul,
   1864 		.deps = { SND_PCM_HW_PARAM_PERIOD_SIZE,
   1865 			SND_PCM_HW_PARAM_PERIODS, -1 },
   1866 		.private_data = 0,
   1867 	},
   1868 	{
   1869 		.var = SND_PCM_HW_PARAM_BUFFER_SIZE,
   1870 		.func = snd_pcm_hw_rule_mulkdiv,
   1871 		.deps = { SND_PCM_HW_PARAM_BUFFER_BYTES,
   1872 			SND_PCM_HW_PARAM_FRAME_BITS, -1 },
   1873 		.private_data = (void*) 8,
   1874 	},
   1875 	{
   1876 		.var = SND_PCM_HW_PARAM_BUFFER_SIZE,
   1877 		.func = snd_pcm_hw_rule_muldivk,
   1878 		.deps = { SND_PCM_HW_PARAM_BUFFER_TIME,
   1879 			SND_PCM_HW_PARAM_RATE, -1 },
   1880 		.private_data = (void*) 1000000,
   1881 	},
   1882 	{
   1883 		.var = SND_PCM_HW_PARAM_PERIOD_BYTES,
   1884 		.func = snd_pcm_hw_rule_muldivk,
   1885 		.deps = { SND_PCM_HW_PARAM_PERIOD_SIZE,
   1886 			SND_PCM_HW_PARAM_FRAME_BITS, -1 },
   1887 		.private_data = (void*) 8,
   1888 	},
   1889 	{
   1890 		.var = SND_PCM_HW_PARAM_BUFFER_BYTES,
   1891 		.func = snd_pcm_hw_rule_muldivk,
   1892 		.deps = { SND_PCM_HW_PARAM_BUFFER_SIZE,
   1893 			SND_PCM_HW_PARAM_FRAME_BITS, -1 },
   1894 		.private_data = (void*) 8,
   1895 	},
   1896 	{
   1897 		.var = SND_PCM_HW_PARAM_PERIOD_TIME,
   1898 		.func = snd_pcm_hw_rule_mulkdiv,
   1899 		.deps = { SND_PCM_HW_PARAM_PERIOD_SIZE,
   1900 			SND_PCM_HW_PARAM_RATE, -1 },
   1901 		.private_data = (void*) 1000000,
   1902 	},
   1903 	{
   1904 		.var = SND_PCM_HW_PARAM_BUFFER_TIME,
   1905 		.func = snd_pcm_hw_rule_mulkdiv,
   1906 		.deps = { SND_PCM_HW_PARAM_BUFFER_SIZE,
   1907 			SND_PCM_HW_PARAM_RATE, -1 },
   1908 		.private_data = (void*) 1000000,
   1909 	},
   1910 };
   1911 
   1912 #define RULES (sizeof(refine_rules) / sizeof(refine_rules[0]))
   1913 
   1914 static const snd_mask_t refine_masks[SND_PCM_HW_PARAM_LAST_MASK - SND_PCM_HW_PARAM_FIRST_MASK + 1] = {
   1915 	[SND_PCM_HW_PARAM_ACCESS - SND_PCM_HW_PARAM_FIRST_MASK] = {
   1916 		.bits = { 0x1f },
   1917 	},
   1918 	[SND_PCM_HW_PARAM_FORMAT - SND_PCM_HW_PARAM_FIRST_MASK] = {
   1919 		.bits = { 0x81ffffff, 0xfff},
   1920 	},
   1921 	[SND_PCM_HW_PARAM_SUBFORMAT - SND_PCM_HW_PARAM_FIRST_MASK] = {
   1922 		.bits = { 0x1 },
   1923 	},
   1924 };
   1925 
   1926 static const snd_interval_t refine_intervals[SND_PCM_HW_PARAM_LAST_INTERVAL - SND_PCM_HW_PARAM_FIRST_INTERVAL + 1] = {
   1927 	[SND_PCM_HW_PARAM_SAMPLE_BITS - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
   1928 		.min = 1, .max = UINT_MAX,
   1929 		.openmin = 0, .openmax = 0, .integer = 1, .empty = 0,
   1930 	},
   1931 	[SND_PCM_HW_PARAM_FRAME_BITS - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
   1932 		.min = 1, .max = UINT_MAX,
   1933 		.openmin = 0, .openmax = 0, .integer = 1, .empty = 0,
   1934 	},
   1935 	[SND_PCM_HW_PARAM_CHANNELS - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
   1936 		.min = 1, .max = UINT_MAX,
   1937 		.openmin = 0, .openmax = 0, .integer = 1, .empty = 0,
   1938 	},
   1939 	[SND_PCM_HW_PARAM_RATE - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
   1940 		.min = 1, .max = UINT_MAX,
   1941 		.openmin = 0, .openmax = 0, .integer = 0, .empty = 0,
   1942 	},
   1943 	[SND_PCM_HW_PARAM_PERIOD_TIME - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
   1944 		.min = 0, .max = UINT_MAX,
   1945 		.openmin = 0, .openmax = 0, .integer = 0, .empty = 0,
   1946 	},
   1947 	[SND_PCM_HW_PARAM_PERIOD_SIZE - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
   1948 		.min = 0, .max = UINT_MAX,
   1949 		.openmin = 0, .openmax = 0, .integer = 0, .empty = 0,
   1950 	},
   1951 	[SND_PCM_HW_PARAM_PERIOD_BYTES - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
   1952 		.min = 0, .max = UINT_MAX,
   1953 		.openmin = 0, .openmax = 0, .integer = 0, .empty = 0,
   1954 	},
   1955 	[SND_PCM_HW_PARAM_PERIODS - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
   1956 		.min = 0, .max = UINT_MAX,
   1957 		.openmin = 0, .openmax = 0, .integer = 0, .empty = 0,
   1958 	},
   1959 	[SND_PCM_HW_PARAM_BUFFER_TIME - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
   1960 		.min = 1, .max = UINT_MAX,
   1961 		.openmin = 0, .openmax = 0, .integer = 0, .empty = 0,
   1962 	},
   1963 	[SND_PCM_HW_PARAM_BUFFER_SIZE - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
   1964 		.min = 1, .max = UINT_MAX,
   1965 		.openmin = 0, .openmax = 0, .integer = 1, .empty = 0,
   1966 	},
   1967 	[SND_PCM_HW_PARAM_BUFFER_BYTES - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
   1968 		.min = 1, .max = UINT_MAX,
   1969 		.openmin = 0, .openmax = 0, .integer = 1, .empty = 0,
   1970 	},
   1971 	[SND_PCM_HW_PARAM_TICK_TIME - SND_PCM_HW_PARAM_FIRST_INTERVAL] = {
   1972 		.min = 0, .max = UINT_MAX,
   1973 		.openmin = 0, .openmax = 0, .integer = 0, .empty = 0,
   1974 	},
   1975 };
   1976 
   1977 #if 0
   1978 #define RULES_DEBUG
   1979 #endif
   1980 
   1981 int snd_pcm_hw_refine_soft(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params)
   1982 {
   1983 	unsigned int k;
   1984 	snd_interval_t *i;
   1985 	unsigned int rstamps[RULES];
   1986 	unsigned int vstamps[SND_PCM_HW_PARAM_LAST_INTERVAL + 1];
   1987 	unsigned int stamp = 2;
   1988 	int changed, again;
   1989 #ifdef RULES_DEBUG
   1990 	snd_output_t *log;
   1991 	snd_output_stdio_attach(&log, stderr, 0);
   1992 	snd_output_printf(log, "refine_soft '%s' (begin)\n", pcm->name);
   1993 	snd_pcm_hw_params_dump(params, log);
   1994 #endif
   1995 
   1996 	for (k = SND_PCM_HW_PARAM_FIRST_MASK; k <= SND_PCM_HW_PARAM_LAST_MASK; k++) {
   1997 		if (!(params->rmask & (1 << k)))
   1998 			continue;
   1999 		changed = snd_mask_refine(hw_param_mask(params, k),
   2000 					  &refine_masks[k - SND_PCM_HW_PARAM_FIRST_MASK]);
   2001 		if (changed)
   2002 			params->cmask |= 1 << k;
   2003 		if (changed < 0)
   2004 			goto _err;
   2005 	}
   2006 
   2007 	for (k = SND_PCM_HW_PARAM_FIRST_INTERVAL; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; k++) {
   2008 		if (!(params->rmask & (1 << k)))
   2009 			continue;
   2010 		changed = snd_interval_refine(hw_param_interval(params, k),
   2011 				      &refine_intervals[k - SND_PCM_HW_PARAM_FIRST_INTERVAL]);
   2012 		if (changed)
   2013 			params->cmask |= 1 << k;
   2014 		if (changed < 0)
   2015 			goto _err;
   2016 	}
   2017 
   2018 	for (k = 0; k < RULES; k++)
   2019 		rstamps[k] = 0;
   2020 	for (k = 0; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; k++)
   2021 		vstamps[k] = (params->rmask & (1 << k)) ? 1 : 0;
   2022 	do {
   2023 		again = 0;
   2024 		for (k = 0; k < RULES; k++) {
   2025 			const snd_pcm_hw_rule_t *r = &refine_rules[k];
   2026 			unsigned int d;
   2027 			int doit = 0;
   2028 			for (d = 0; r->deps[d] >= 0; d++) {
   2029 				if (vstamps[r->deps[d]] > rstamps[k]) {
   2030 					doit = 1;
   2031 					break;
   2032 				}
   2033 			}
   2034 			if (!doit)
   2035 				continue;
   2036 #ifdef RULES_DEBUG
   2037 			snd_output_printf(log, "Rule %d (%p): ", k, r->func);
   2038 			if (r->var >= 0) {
   2039 				snd_output_printf(log, "%s=", snd_pcm_hw_param_name(r->var));
   2040 				snd_pcm_hw_param_dump(params, r->var, log);
   2041 				snd_output_puts(log, " -> ");
   2042 			}
   2043 #endif
   2044 			changed = r->func(params, r);
   2045 #ifdef RULES_DEBUG
   2046 			if (r->var >= 0)
   2047 				snd_pcm_hw_param_dump(params, r->var, log);
   2048 			for (d = 0; r->deps[d] >= 0; d++) {
   2049 				snd_output_printf(log, " %s=", snd_pcm_hw_param_name(r->deps[d]));
   2050 				snd_pcm_hw_param_dump(params, r->deps[d], log);
   2051 			}
   2052 			snd_output_putc(log, '\n');
   2053 #endif
   2054 			rstamps[k] = stamp;
   2055 			if (changed && r->var >= 0) {
   2056 				params->cmask |= 1 << r->var;
   2057 				vstamps[r->var] = stamp;
   2058 				again = 1;
   2059 			}
   2060 			if (changed < 0)
   2061 				goto _err;
   2062 			stamp++;
   2063 		}
   2064 	} while (again);
   2065 	if (!params->msbits) {
   2066 		i = hw_param_interval(params, SND_PCM_HW_PARAM_SAMPLE_BITS);
   2067 		if (snd_interval_single(i))
   2068 			params->msbits = snd_interval_value(i);
   2069 	}
   2070 
   2071 	if (!params->rate_den) {
   2072 		i = hw_param_interval(params, SND_PCM_HW_PARAM_RATE);
   2073 		if (snd_interval_single(i)) {
   2074 			params->rate_num = snd_interval_value(i);
   2075 			params->rate_den = 1;
   2076 		}
   2077 	}
   2078 	params->rmask = 0;
   2079 	return 0;
   2080  _err:
   2081 #ifdef RULES_DEBUG
   2082 	snd_output_printf(log, "refine_soft '%s' (end-%i)\n", pcm->name, changed);
   2083 	snd_pcm_hw_params_dump(params, log);
   2084 	snd_output_close(log);
   2085 #endif
   2086 	return changed;
   2087 }
   2088 
   2089 int _snd_pcm_hw_params_refine(snd_pcm_hw_params_t *params,
   2090 			      unsigned int vars,
   2091 			      const snd_pcm_hw_params_t *src)
   2092 {
   2093 	int changed, err = 0;
   2094 	unsigned int k;
   2095 	for (k = 0; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; ++k) {
   2096 		if (!(vars & (1 << k)))
   2097 			continue;
   2098 		changed = _snd_pcm_hw_param_refine(params, k, src);
   2099 		if (changed < 0)
   2100 			err = changed;
   2101 	}
   2102 	params->info &= src->info;
   2103 	return err;
   2104 }
   2105 
   2106 int snd_pcm_hw_refine_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
   2107 			    int (*cprepare)(snd_pcm_t *pcm,
   2108 					    snd_pcm_hw_params_t *params),
   2109 			    int (*cchange)(snd_pcm_t *pcm,
   2110 					   snd_pcm_hw_params_t *params,
   2111 					   snd_pcm_hw_params_t *sparams),
   2112 			    int (*sprepare)(snd_pcm_t *pcm,
   2113 					    snd_pcm_hw_params_t *params),
   2114 			    int (*schange)(snd_pcm_t *pcm,
   2115 					   snd_pcm_hw_params_t *params,
   2116 					   snd_pcm_hw_params_t *sparams),
   2117 			    int (*srefine)(snd_pcm_t *pcm,
   2118 					   snd_pcm_hw_params_t *sparams))
   2119 
   2120 {
   2121 #ifdef RULES_DEBUG
   2122 	snd_output_t *log;
   2123 #endif
   2124 	snd_pcm_hw_params_t sparams;
   2125 	int err;
   2126 	unsigned int cmask, changed;
   2127 #ifdef RULES_DEBUG
   2128 	snd_output_stdio_attach(&log, stderr, 0);
   2129 #endif
   2130 	err = cprepare(pcm, params);
   2131 	if (err < 0)
   2132 		return err;
   2133 	err = sprepare(pcm, &sparams);
   2134 	if (err < 0) {
   2135 		SNDERR("Slave PCM not usable");
   2136 		return err;
   2137 	}
   2138 #ifdef RULES_DEBUG
   2139 	snd_output_printf(log, "hw_refine_slave - enter '%s'\n", pcm->name);
   2140 #endif
   2141 	do {
   2142 		cmask = params->cmask;
   2143 		params->cmask = 0;
   2144 #ifdef RULES_DEBUG
   2145 		snd_output_printf(log, "schange '%s' (client)\n", pcm->name);
   2146 		snd_pcm_hw_params_dump(params, log);
   2147 		snd_output_printf(log, "schange '%s' (slave)\n", pcm->name);
   2148 		snd_pcm_hw_params_dump(&sparams, log);
   2149 #endif
   2150 		err = schange(pcm, params, &sparams);
   2151 		if (err >= 0) {
   2152 #ifdef RULES_DEBUG
   2153 			snd_output_printf(log, "srefine '%s' (client)\n", pcm->name);
   2154 			snd_pcm_hw_params_dump(params, log);
   2155 			snd_output_printf(log, "srefine '%s' (slave)\n", pcm->name);
   2156 			snd_pcm_hw_params_dump(&sparams, log);
   2157 #endif
   2158 			err = srefine(pcm, &sparams);
   2159 			if (err < 0) {
   2160 #ifdef RULES_DEBUG
   2161 				snd_output_printf(log, "srefine '%s', err < 0 (%i) (client)\n", pcm->name, err);
   2162 				snd_pcm_hw_params_dump(params, log);
   2163 				snd_output_printf(log, "srefine '%s', err < 0 (%i) (slave)\n", pcm->name, err);
   2164 				snd_pcm_hw_params_dump(&sparams, log);
   2165 #endif
   2166 				cchange(pcm, params, &sparams);
   2167 				return err;
   2168 			}
   2169 		} else {
   2170 #ifdef RULES_DEBUG
   2171 			snd_output_printf(log, "schange '%s', err < 0 (%i) (client)\n", pcm->name, err);
   2172 			snd_pcm_hw_params_dump(params, log);
   2173 			snd_output_printf(log, "schange '%s', err < 0 (%i) (slave)\n", pcm->name, err);
   2174 			snd_pcm_hw_params_dump(&sparams, log);
   2175 #endif
   2176 			cchange(pcm, params, &sparams);
   2177 			return err;
   2178 		}
   2179 #ifdef RULES_DEBUG
   2180 		snd_output_printf(log, "cchange '%s'\n", pcm->name);
   2181 #endif
   2182 		err = cchange(pcm, params, &sparams);
   2183 		if (err < 0)
   2184 			return err;
   2185 #ifdef RULES_DEBUG
   2186 		snd_output_printf(log, "refine_soft '%s'\n", pcm->name);
   2187 #endif
   2188 		err = snd_pcm_hw_refine_soft(pcm, params);
   2189 		changed = params->cmask;
   2190 		params->cmask |= cmask;
   2191 		if (err < 0)
   2192 			return err;
   2193 #ifdef RULES_DEBUG
   2194 		snd_output_printf(log, "refine_soft ok '%s'\n", pcm->name);
   2195 #endif
   2196 	} while (changed);
   2197 #ifdef RULES_DEBUG
   2198 	snd_output_printf(log, "refine_slave - leave '%s'\n", pcm->name);
   2199 	snd_output_close(log);
   2200 #endif
   2201 	return 0;
   2202 }
   2203 
   2204 int snd_pcm_hw_params_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
   2205 			    int (*cchange)(snd_pcm_t *pcm,
   2206 					   snd_pcm_hw_params_t *params,
   2207 					   snd_pcm_hw_params_t *sparams),
   2208 			    int (*sprepare)(snd_pcm_t *pcm,
   2209 					    snd_pcm_hw_params_t *params),
   2210 			    int (*schange)(snd_pcm_t *pcm,
   2211 					   snd_pcm_hw_params_t *params,
   2212 					   snd_pcm_hw_params_t *sparams),
   2213 			    int (*sparams)(snd_pcm_t *pcm,
   2214 					   snd_pcm_hw_params_t *sparams))
   2215 
   2216 {
   2217 	snd_pcm_hw_params_t slave_params;
   2218 	int err;
   2219 	err = sprepare(pcm, &slave_params);
   2220 	assert(err >= 0);
   2221 	err = schange(pcm, params, &slave_params);
   2222 	assert(err >= 0);
   2223 	err = sparams(pcm, &slave_params);
   2224 	if (err < 0)
   2225 		cchange(pcm, params, &slave_params);
   2226 	return err;
   2227 }
   2228 
   2229 static int snd_pcm_sw_params_default(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)
   2230 {
   2231 	assert(pcm && params);
   2232 	assert(pcm->setup);
   2233 	params->tstamp_mode = SND_PCM_TSTAMP_NONE;
   2234 	params->period_step = 1;
   2235 	params->sleep_min = 0;
   2236 	params->avail_min = pcm->period_size;
   2237 	params->xfer_align = 1;
   2238 	params->start_threshold = 1;
   2239 	params->stop_threshold = pcm->buffer_size;
   2240 	params->silence_threshold = 0;
   2241 	params->silence_size = 0;
   2242 	params->boundary = pcm->buffer_size;
   2243 	while (params->boundary * 2 <= LONG_MAX - pcm->buffer_size)
   2244 		params->boundary *= 2;
   2245 	return 0;
   2246 }
   2247 
   2248 #if 0
   2249 #define REFINE_DEBUG
   2250 #endif
   2251 
   2252 int snd_pcm_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
   2253 {
   2254 	int res;
   2255 #ifdef REFINE_DEBUG
   2256 	snd_output_t *log;
   2257 	snd_output_stdio_attach(&log, stderr, 0);
   2258 #endif
   2259 	assert(pcm && params);
   2260 #ifdef REFINE_DEBUG
   2261 	snd_output_printf(log, "REFINE called:\n");
   2262 	snd_pcm_hw_params_dump(params, log);
   2263 #endif
   2264 	res = pcm->ops->hw_refine(pcm->op_arg, params);
   2265 #ifdef REFINE_DEBUG
   2266 	snd_output_printf(log, "refine done - result = %i\n", res);
   2267 	snd_pcm_hw_params_dump(params, log);
   2268 	snd_output_close(log);
   2269 #endif
   2270 	return res;
   2271 }
   2272 
   2273 /* Install one of the configurations present in configuration
   2274    space defined by PARAMS.
   2275    The configuration chosen is that obtained fixing in this order:
   2276    first access
   2277    first format
   2278    first subformat
   2279    min channels
   2280    min rate
   2281    min period_size
   2282    max periods
   2283    Return 0 on success otherwise a negative error code
   2284 */
   2285 int _snd_pcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
   2286 {
   2287 	int err;
   2288 	snd_pcm_sw_params_t sw;
   2289 	int fb, min_align;
   2290 	err = snd_pcm_hw_refine(pcm, params);
   2291 	if (err < 0)
   2292 		return err;
   2293 	snd_pcm_hw_params_choose(pcm, params);
   2294 	if (pcm->setup) {
   2295 		err = snd_pcm_hw_free(pcm);
   2296 		if (err < 0)
   2297 			return err;
   2298 	}
   2299 	err = pcm->ops->hw_params(pcm->op_arg, params);
   2300 	if (err < 0)
   2301 		return err;
   2302 
   2303 	pcm->setup = 1;
   2304 	INTERNAL(snd_pcm_hw_params_get_access)(params, &pcm->access);
   2305 	INTERNAL(snd_pcm_hw_params_get_format)(params, &pcm->format);
   2306 	INTERNAL(snd_pcm_hw_params_get_subformat)(params, &pcm->subformat);
   2307 	INTERNAL(snd_pcm_hw_params_get_channels)(params, &pcm->channels);
   2308 	INTERNAL(snd_pcm_hw_params_get_rate)(params, &pcm->rate, 0);
   2309 	INTERNAL(snd_pcm_hw_params_get_period_time)(params, &pcm->period_time, 0);
   2310 	INTERNAL(snd_pcm_hw_params_get_period_size)(params, &pcm->period_size, 0);
   2311 	INTERNAL(snd_pcm_hw_params_get_buffer_size)(params, &pcm->buffer_size);
   2312 	pcm->sample_bits = snd_pcm_format_physical_width(pcm->format);
   2313 	pcm->frame_bits = pcm->sample_bits * pcm->channels;
   2314 	fb = pcm->frame_bits;
   2315 	min_align = 1;
   2316 	while (fb % 8) {
   2317 		fb *= 2;
   2318 		min_align *= 2;
   2319 	}
   2320 	pcm->min_align = min_align;
   2321 
   2322 	pcm->hw_flags = params->flags;
   2323 	pcm->info = params->info;
   2324 	pcm->msbits = params->msbits;
   2325 	pcm->rate_num = params->rate_num;
   2326 	pcm->rate_den = params->rate_den;
   2327 	pcm->fifo_size = params->fifo_size;
   2328 
   2329 	/* Default sw params */
   2330 	memset(&sw, 0, sizeof(sw));
   2331 	snd_pcm_sw_params_default(pcm, &sw);
   2332 	err = snd_pcm_sw_params(pcm, &sw);
   2333 	assert(err >= 0);
   2334 
   2335 	if (pcm->mmap_rw ||
   2336 	    pcm->access == SND_PCM_ACCESS_MMAP_INTERLEAVED ||
   2337 	    pcm->access == SND_PCM_ACCESS_MMAP_NONINTERLEAVED ||
   2338 	    pcm->access == SND_PCM_ACCESS_MMAP_COMPLEX) {
   2339 		err = snd_pcm_mmap(pcm);
   2340 	}
   2341 	if (err < 0)
   2342 		return err;
   2343 	return 0;
   2344 }
   2345 
   2346