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, ¶ms1, 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, ¶ms1, 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(¶ms1, var, value, &dir, pcm, strategy); 1363 if (value < 0) 1364 break; 1365 badness = snd_pcm_hw_params_strategy(pcm, ¶ms1, 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, ¶ms1, 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, ¶ms->intervals[SND_PCM_HW_PARAM_PERIODS - SND_PCM_HW_PARAM_FIRST_INTERVAL]); 2423 snd_interval_copy(&pcm->buffer_time, ¶ms->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