1/* 2 * This library is free software; you can redistribute it and/or 3 * modify it under the terms of the GNU Lesser General Public 4 * License as published by the Free Software Foundation; either 5 * version 2 of the License, or (at your option) any later version. 6 * 7 * This library is distributed in the hope that it will be useful, 8 * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 * Lesser General Public License for more details. 11 * 12 * You should have received a copy of the GNU Lesser General Public 13 * License along with this library; if not, write to the Free Software 14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 15 * 16 * Support for the verb/device/modifier core logic and API, 17 * command line tool and file parser was kindly sponsored by 18 * Texas Instruments Inc. 19 * Support for multiple active modifiers and devices, 20 * transition sequences, multiple client access and user defined use 21 * cases was kindly sponsored by Wolfson Microelectronics PLC. 22 * 23 * Copyright (C) 2008-2010 SlimLogic Ltd 24 * Copyright (C) 2010 Wolfson Microelectronics PLC 25 * Copyright (C) 2010 Texas Instruments Inc. 26 * Copyright (C) 2010 Red Hat Inc. 27 * Authors: Liam Girdwood <lrg@slimlogic.co.uk> 28 * Stefan Schmidt <stefan@slimlogic.co.uk> 29 * Justin Xu <justinx@slimlogic.co.uk> 30 * Jaroslav Kysela <perex@perex.cz> 31 */ 32 33#include "ucm_local.h" 34#include <sys/stat.h> 35#include <stdbool.h> 36#include <dirent.h> 37#include <limits.h> 38 39static int filename_filter(const struct dirent64 *dirent); 40 41static int parse_sequence(snd_use_case_mgr_t *uc_mgr, 42 struct list_head *base, 43 snd_config_t *cfg); 44 45/* 46 * compose the absolute ucm filename 47 */ 48static void ucm_filename(char *fn, size_t fn_len, long version, 49 const char *dir, const char *file) 50{ 51 const char *env = getenv(version > 1 ? ALSA_CONFIG_UCM2_VAR : ALSA_CONFIG_UCM_VAR); 52 53 if (file[0] == '/') 54 file++; 55 if (env == NULL) 56 snprintf(fn, fn_len, "%s/%s/%s%s%s", 57 snd_config_topdir(), version > 1 ? "ucm2" : "ucm", 58 dir ?: "", dir ? "/" : "", file); 59 else 60 snprintf(fn, fn_len, "%s/%s%s%s", 61 env, dir ?: "", dir ? "/" : "", file); 62} 63 64/* 65 * 66 */ 67int uc_mgr_config_load_file(snd_use_case_mgr_t *uc_mgr, 68 const char *file, snd_config_t **cfg) 69{ 70 char filename[PATH_MAX]; 71 int err; 72 73 ucm_filename(filename, sizeof(filename), uc_mgr->conf_format, 74 file[0] == '/' ? NULL : uc_mgr->conf_dir_name, 75 file); 76 err = uc_mgr_config_load(uc_mgr->conf_format, filename, cfg); 77 if (err < 0) { 78 uc_error("error: failed to open file %s: %d", filename, err); 79 return err; 80 } 81 return 0; 82} 83 84/* 85 * Replace mallocated string 86 */ 87static char *replace_string(char **dst, const char *value) 88{ 89 free(*dst); 90 *dst = value ? strdup(value) : NULL; 91 return *dst; 92} 93 94/* 95 * Parse string 96 */ 97static int parse_string(snd_config_t *n, char **res) 98{ 99 int err; 100 101 err = snd_config_get_string(n, (const char **)res); 102 if (err < 0) 103 return err; 104 *res = strdup(*res); 105 if (*res == NULL) 106 return -ENOMEM; 107 return 0; 108} 109 110/* 111 * Parse string and substitute 112 */ 113static int parse_string_substitute(snd_use_case_mgr_t *uc_mgr, 114 snd_config_t *n, char **res) 115{ 116 const char *str; 117 char *s; 118 int err; 119 120 err = snd_config_get_string(n, &str); 121 if (err < 0) 122 return err; 123 err = uc_mgr_get_substituted_value(uc_mgr, &s, str); 124 if (err >= 0) 125 *res = s; 126 return err; 127} 128 129/* 130 * Parse string and substitute 131 */ 132static int parse_string_substitute3(snd_use_case_mgr_t *uc_mgr, 133 snd_config_t *n, char **res) 134{ 135 if (uc_mgr->conf_format < 3) 136 return parse_string(n, res); 137 return parse_string_substitute(uc_mgr, n, res); 138} 139 140/* 141 * Parse integer with substitution 142 */ 143static int parse_integer_substitute(snd_use_case_mgr_t *uc_mgr, 144 snd_config_t *n, long *res) 145{ 146 char *s1, *s2; 147 int err; 148 149 err = snd_config_get_ascii(n, &s1); 150 if (err < 0) 151 return err; 152 err = uc_mgr_get_substituted_value(uc_mgr, &s2, s1); 153 if (err >= 0) 154 err = safe_strtol(s2, res); 155 free(s2); 156 free(s1); 157 return err; 158} 159 160/* 161 * Parse integer with substitution 162 */ 163static int parse_integer_substitute3(snd_use_case_mgr_t *uc_mgr, 164 snd_config_t *n, long *res) 165{ 166 char *s1, *s2; 167 int err; 168 169 err = snd_config_get_ascii(n, &s1); 170 if (err < 0) 171 return err; 172 if (uc_mgr->conf_format < 3) 173 s2 = s1; 174 else 175 err = uc_mgr_get_substituted_value(uc_mgr, &s2, s1); 176 if (err >= 0) 177 err = safe_strtol(s2, res); 178 if (s1 != s2) 179 free(s2); 180 free(s1); 181 return err; 182} 183 184/* 185 * Parse safe ID 186 */ 187static int parse_is_name_safe(const char *name) 188{ 189 if (strchr(name, '.')) { 190 uc_error("char '.' not allowed in '%s'", name); 191 return 0; 192 } 193 return 1; 194} 195 196static int get_string3(snd_use_case_mgr_t *uc_mgr, const char *s1, char **s) 197{ 198 if (uc_mgr->conf_format < 3) { 199 *s = strdup(s1); 200 if (*s == NULL) 201 return -ENOMEM; 202 return 0; 203 } 204 return uc_mgr_get_substituted_value(uc_mgr, s, s1); 205} 206 207static int parse_get_safe_name(snd_use_case_mgr_t *uc_mgr, snd_config_t *n, 208 const char *alt, char **name) 209{ 210 const char *id; 211 int err; 212 213 if (alt) { 214 id = alt; 215 } else { 216 err = snd_config_get_id(n, &id); 217 if (err < 0) 218 return err; 219 } 220 err = get_string3(uc_mgr, id, name); 221 if (err < 0) 222 return err; 223 if (!parse_is_name_safe(*name)) { 224 free(*name); 225 return -EINVAL; 226 } 227 return 0; 228} 229 230/* 231 * Handle 'Error' configuration node. 232 */ 233static int error_node(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg) 234{ 235 int err; 236 char *s; 237 238 err = parse_string_substitute3(uc_mgr, cfg, &s); 239 if (err < 0) { 240 uc_error("error: failed to get Error string"); 241 return err; 242 } 243 if (!uc_mgr->suppress_nodev_errors) 244 uc_error("%s", s); 245 free(s); 246 return -ENXIO; 247} 248 249/* 250 * 251 */ 252static int parse_syntax_field(snd_use_case_mgr_t *uc_mgr, 253 snd_config_t *cfg, const char *filename) 254{ 255 snd_config_t *n; 256 long l; 257 int err; 258 259 err = snd_config_search(cfg, "Syntax", &n); 260 if (err < 0) { 261 uc_error("Syntax field not found in %s", filename); 262 return -EINVAL; 263 } 264 err = snd_config_get_integer(n, &l); 265 if (err < 0) { 266 uc_error("Syntax field is invalid in %s", filename); 267 return err; 268 } 269 if (l < 2 || l > SYNTAX_VERSION_MAX) { 270 uc_error("Incompatible syntax %ld in %s", l, filename); 271 return -EINVAL; 272 } 273 /* delete this field to optimize strcmp() call in the parsing loop */ 274 snd_config_delete(n); 275 uc_mgr->conf_format = l; 276 return l; 277} 278 279/* 280 * Evaluate variable regex definitions (in-place delete) 281 */ 282static int evaluate_regex(snd_use_case_mgr_t *uc_mgr, 283 snd_config_t *cfg) 284{ 285 snd_config_iterator_t i, next; 286 snd_config_t *d, *n; 287 const char *id; 288 int err; 289 290 err = snd_config_search(cfg, "DefineRegex", &d); 291 if (err == -ENOENT) 292 return 1; 293 if (err < 0) 294 return err; 295 296 if (snd_config_get_type(d) != SND_CONFIG_TYPE_COMPOUND) { 297 uc_error("compound type expected for DefineRegex"); 298 return -EINVAL; 299 } 300 301 if (uc_mgr->conf_format < 3) { 302 uc_error("DefineRegex is supported in v3+ syntax"); 303 return -EINVAL; 304 } 305 306 snd_config_for_each(i, next, d) { 307 n = snd_config_iterator_entry(i); 308 err = snd_config_get_id(n, &id); 309 if (err < 0) 310 return err; 311 if (id[0] == '@') { 312 uc_error("error: value names starting with '@' are reserved for application variables"); 313 return -EINVAL; 314 } 315 err = uc_mgr_define_regex(uc_mgr, id, n); 316 if (err < 0) 317 return err; 318 } 319 320 snd_config_delete(d); 321 return 0; 322} 323 324/* 325 * Evaluate variable definitions (in-place delete) 326 */ 327static int evaluate_define(snd_use_case_mgr_t *uc_mgr, 328 snd_config_t *cfg) 329{ 330 snd_config_iterator_t i, next; 331 snd_config_t *d, *n; 332 const char *id; 333 char *var, *s; 334 int err; 335 336 err = snd_config_search(cfg, "Define", &d); 337 if (err == -ENOENT) 338 return evaluate_regex(uc_mgr, cfg); 339 if (err < 0) 340 return err; 341 342 if (snd_config_get_type(d) != SND_CONFIG_TYPE_COMPOUND) { 343 uc_error("compound type expected for Define"); 344 return -EINVAL; 345 } 346 347 if (uc_mgr->conf_format < 3) { 348 uc_error("Define is supported in v3+ syntax"); 349 return -EINVAL; 350 } 351 352 snd_config_for_each(i, next, d) { 353 n = snd_config_iterator_entry(i); 354 err = snd_config_get_id(n, &id); 355 if (err < 0) 356 return err; 357 err = snd_config_get_ascii(n, &var); 358 if (err < 0) 359 return err; 360 err = uc_mgr_get_substituted_value(uc_mgr, &s, var); 361 free(var); 362 if (err < 0) 363 return err; 364 if (id[0] == '@') { 365 free(s); 366 uc_error("error: value names starting with '@' are reserved for application variables"); 367 return -EINVAL; 368 } 369 err = uc_mgr_set_variable(uc_mgr, id, s); 370 free(s); 371 if (err < 0) 372 return err; 373 } 374 375 snd_config_delete(d); 376 377 return evaluate_regex(uc_mgr, cfg); 378} 379 380/* 381 * Evaluate macro definitions (in-place delete) 382 */ 383static int evaluate_define_macro(snd_use_case_mgr_t *uc_mgr, 384 snd_config_t *cfg) 385{ 386 snd_config_t *d; 387 int err; 388 389 err = snd_config_search(cfg, "DefineMacro", &d); 390 if (err == -ENOENT) 391 return 1; 392 if (err < 0) 393 return err; 394 395 if (snd_config_get_type(d) != SND_CONFIG_TYPE_COMPOUND) { 396 uc_error("compound type expected for DefineMacro"); 397 return -EINVAL; 398 } 399 400 if (uc_mgr->conf_format < 6) { 401 uc_error("DefineMacro is supported in v6+ syntax"); 402 return -EINVAL; 403 } 404 405 err = snd_config_merge(uc_mgr->macros, d, 0); 406 if (err < 0) 407 return err; 408 return 0; 409} 410 411static int evaluate_macro1(snd_use_case_mgr_t *uc_mgr, 412 snd_config_t *dst, 413 snd_config_t *args) 414{ 415 snd_config_iterator_t i, next; 416 snd_config_t *m, *mc, *a, *n; 417 const char *mid, *id; 418 char name[128], *var; 419 const char *s; 420 int err; 421 422 err = snd_config_get_id(args, &mid); 423 if (err < 0) 424 return err; 425 err = snd_config_search(uc_mgr->macros, mid, &m); 426 if (err < 0) { 427 uc_error("Macro '%s' is not defined", mid); 428 return err; 429 } 430 431 a = args; 432 if (snd_config_get_type(args) == SND_CONFIG_TYPE_STRING) { 433 err = snd_config_get_string(args, &s); 434 if (err < 0) 435 return err; 436 err = snd_config_load_string(&a, s, 0); 437 if (err < 0) 438 return err; 439 } else if (snd_config_get_type(args) != SND_CONFIG_TYPE_COMPOUND) { 440 return -EINVAL; 441 } 442 443 /* set arguments */ 444 snd_config_for_each(i, next, a) { 445 n = snd_config_iterator_entry(i); 446 err = snd_config_get_id(n, &id); 447 if (err < 0) 448 goto __err_path; 449 err = snd_config_get_ascii(n, &var); 450 if (err < 0) 451 goto __err_path; 452 snprintf(name, sizeof(name), "__%s", id); 453 err = uc_mgr_set_variable(uc_mgr, name, var); 454 free(var); 455 if (err < 0) 456 goto __err_path; 457 } 458 459 /* merge + substitute variables */ 460 err = snd_config_copy(&mc, m); 461 if (err < 0) 462 goto __err_path; 463 err = uc_mgr_evaluate_inplace(uc_mgr, mc); 464 if (err < 0) { 465 snd_config_delete(mc); 466 goto __err_path; 467 } 468 err = uc_mgr_config_tree_merge(uc_mgr, dst, mc, NULL, NULL); 469 snd_config_delete(mc); 470 471 /* delete arguments */ 472 snd_config_for_each(i, next, a) { 473 n = snd_config_iterator_entry(i); 474 err = snd_config_get_id(n, &id); 475 if (err < 0) 476 goto __err_path; 477 snprintf(name, sizeof(name), "__%s", id); 478 err = uc_mgr_delete_variable(uc_mgr, name); 479 if (err < 0) 480 goto __err_path; 481 } 482 483__err_path: 484 if (a != args) 485 snd_config_delete(a); 486 return err; 487} 488 489/* 490 * Evaluate macro definitions and instances (in-place delete) 491 */ 492static int evaluate_macro(snd_use_case_mgr_t *uc_mgr, 493 snd_config_t *cfg) 494{ 495 snd_config_iterator_t i, i2, next, next2; 496 snd_config_t *d, *n, *n2; 497 int err, ret; 498 499 ret = evaluate_define_macro(uc_mgr, cfg); 500 if (ret < 0) 501 return ret; 502 503 err = snd_config_search(cfg, "Macro", &d); 504 if (err == -ENOENT) 505 return ret; 506 if (err < 0) 507 return err; 508 509 if (snd_config_get_type(d) != SND_CONFIG_TYPE_COMPOUND) { 510 uc_error("compound type expected for DefineMacro"); 511 return -EINVAL; 512 } 513 514 if (uc_mgr->conf_format < 6) { 515 uc_error("Macro is supported in v6+ syntax"); 516 return -EINVAL; 517 } 518 519 snd_config_for_each(i, next, d) { 520 n = snd_config_iterator_entry(i); 521 if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) { 522 const char *id; 523 if (snd_config_get_id(n, &id)) 524 id = ""; 525 uc_error("compound type expected for Macro.%s", id); 526 return -EINVAL; 527 } 528 snd_config_for_each(i2, next2, n) { 529 n2 = snd_config_iterator_entry(i2); 530 err = evaluate_macro1(uc_mgr, cfg, n2); 531 if (err < 0) 532 return err; 533 } 534 } 535 536 snd_config_delete(d); 537 538 return 0; 539} 540 541/* 542 * Evaluate include (in-place) 543 */ 544static int evaluate_include(snd_use_case_mgr_t *uc_mgr, 545 snd_config_t *cfg) 546{ 547 snd_config_t *n; 548 int err; 549 550 err = snd_config_search(cfg, "Include", &n); 551 if (err == -ENOENT) 552 return 1; 553 if (err < 0) 554 return err; 555 556 err = uc_mgr_evaluate_include(uc_mgr, cfg, n); 557 snd_config_delete(n); 558 return err; 559} 560 561/* 562 * Evaluate condition (in-place) 563 */ 564static int evaluate_condition(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg) 565{ 566 snd_config_t *n; 567 int err; 568 569 err = snd_config_search(cfg, "If", &n); 570 if (err == -ENOENT) 571 return 1; 572 if (err < 0) 573 return err; 574 575 err = uc_mgr_evaluate_condition(uc_mgr, cfg, n); 576 snd_config_delete(n); 577 return err; 578} 579 580/* 581 * Evaluate variant (in-place) 582 */ 583static int evaluate_variant(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg) 584{ 585 snd_config_iterator_t i, next; 586 snd_config_t *n, *c; 587 const char *id; 588 int err; 589 590 err = snd_config_search(cfg, "Variant", &c); 591 if (err == -ENOENT) 592 return 1; 593 if (err < 0) 594 return err; 595 596 if (uc_mgr->conf_format < 6) { 597 uc_error("Variant is supported in v6+ syntax"); 598 return -EINVAL; 599 } 600 601 if (uc_mgr->parse_master_section) 602 return 1; 603 604 if (uc_mgr->parse_variant == NULL) 605 goto __ret; 606 607 snd_config_for_each(i, next, c) { 608 n = snd_config_iterator_entry(i); 609 610 if (snd_config_get_id(n, &id) < 0) 611 return -EINVAL; 612 613 if (strcmp(id, uc_mgr->parse_variant)) 614 continue; 615 616 err = uc_mgr_evaluate_inplace(uc_mgr, n); 617 if (err < 0) 618 return err; 619 620 err = uc_mgr_config_tree_merge(uc_mgr, cfg, n, NULL, NULL); 621 if (err < 0) 622 return err; 623 snd_config_delete(c); 624 return 0; 625 } 626 627__ret: 628 snd_config_delete(c); 629 return 1; 630} 631 632/* 633 * In-place evaluate 634 */ 635int uc_mgr_evaluate_inplace(snd_use_case_mgr_t *uc_mgr, 636 snd_config_t *cfg) 637{ 638 long iterations = 10000; 639 int err1 = 0, err2 = 0, err3 = 0, err4 = 0, err5 = 0; 640 641 while (err1 == 0 || err2 == 0 || err3 == 0 || err4 == 0 || err5 == 0) { 642 if (iterations == 0) { 643 uc_error("Maximal inplace evaluation iterations number reached (recursive references?)"); 644 return -EINVAL; 645 } 646 iterations--; 647 /* variables at first */ 648 err1 = evaluate_define(uc_mgr, cfg); 649 if (err1 < 0) 650 return err1; 651 /* include at second */ 652 err2 = evaluate_include(uc_mgr, cfg); 653 if (err2 < 0) 654 return err2; 655 /* include or macro may define another variables */ 656 /* conditions may depend on them */ 657 if (err2 == 0) 658 continue; 659 err3 = evaluate_variant(uc_mgr, cfg); 660 if (err3 < 0) 661 return err3; 662 if (err3 == 0) 663 continue; 664 uc_mgr->macro_hops++; 665 if (uc_mgr->macro_hops > 100) { 666 uc_error("Maximal macro hops reached!"); 667 return -EINVAL; 668 } 669 err4 = evaluate_macro(uc_mgr, cfg); 670 uc_mgr->macro_hops--; 671 if (err4 < 0) 672 return err4; 673 if (err4 == 0) 674 continue; 675 err5 = evaluate_condition(uc_mgr, cfg); 676 if (err5 < 0) 677 return err5; 678 } 679 return 0; 680} 681 682/* 683 * Parse one item for alsa-lib config 684 */ 685static int parse_libconfig1(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg) 686{ 687 snd_config_iterator_t i, next; 688 snd_config_t *n, *config = NULL; 689 const char *id, *file = NULL; 690 bool substfile = false, substconfig = false; 691 int err; 692 693 if (snd_config_get_id(cfg, &id) < 0) 694 return -EINVAL; 695 696 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { 697 uc_error("compound type expected for %s", id); 698 return -EINVAL; 699 } 700 701 snd_config_for_each(i, next, cfg) { 702 n = snd_config_iterator_entry(i); 703 704 if (snd_config_get_id(n, &id) < 0) 705 return -EINVAL; 706 707 if (strcmp(id, "File") == 0 || 708 strcmp(id, "SubstiFile") == 0) { 709 substfile = id[0] == 'S'; 710 err = snd_config_get_string(n, &file); 711 if (err < 0) 712 return err; 713 continue; 714 } 715 716 if (strcmp(id, "Config") == 0 || 717 strcmp(id, "SubstiConfig") == 0) { 718 substconfig = id[0] == 'S'; 719 if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) 720 return -EINVAL; 721 config = n; 722 continue; 723 } 724 725 uc_error("unknown field %s", id); 726 return -EINVAL; 727 } 728 729 if (file) { 730 if (substfile) { 731 snd_config_t *cfg; 732 err = uc_mgr_config_load(uc_mgr->conf_format, file, &cfg); 733 if (err < 0) 734 return err; 735 err = uc_mgr_substitute_tree(uc_mgr, cfg); 736 if (err < 0) { 737 snd_config_delete(cfg); 738 return err; 739 } 740 err = snd_config_merge(uc_mgr->local_config, cfg, 0); 741 if (err < 0) { 742 snd_config_delete(cfg); 743 return err; 744 } 745 } else { 746 char filename[PATH_MAX]; 747 748 ucm_filename(filename, sizeof(filename), uc_mgr->conf_format, 749 file[0] == '/' ? NULL : uc_mgr->conf_dir_name, 750 file); 751 err = uc_mgr_config_load_into(uc_mgr->conf_format, filename, uc_mgr->local_config); 752 if (err < 0) 753 return err; 754 } 755 } 756 757 if (config) { 758 if (substconfig) { 759 err = uc_mgr_substitute_tree(uc_mgr, config); 760 if (err < 0) 761 return err; 762 } 763 err = snd_config_merge(uc_mgr->local_config, config, 0); 764 if (err < 0) 765 return err; 766 } 767 768 return 0; 769} 770 771/* 772 * Parse alsa-lib config 773 */ 774static int parse_libconfig(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg) 775{ 776 snd_config_iterator_t i, next; 777 snd_config_t *n; 778 const char *id; 779 int err; 780 781 if (snd_config_get_id(cfg, &id) < 0) 782 return -EINVAL; 783 784 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { 785 uc_error("compound type expected for %s", id); 786 return -EINVAL; 787 } 788 789 snd_config_for_each(i, next, cfg) { 790 n = snd_config_iterator_entry(i); 791 792 err = parse_libconfig1(uc_mgr, n); 793 if (err < 0) 794 return err; 795 } 796 797 return 0; 798} 799 800/* 801 * Parse transition 802 */ 803static int parse_transition(snd_use_case_mgr_t *uc_mgr, 804 struct list_head *tlist, 805 snd_config_t *cfg) 806{ 807 struct transition_sequence *tseq; 808 const char *id; 809 snd_config_iterator_t i, next; 810 snd_config_t *n; 811 int err; 812 813 if (snd_config_get_id(cfg, &id) < 0) 814 return -EINVAL; 815 816 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { 817 uc_error("compound type expected for %s", id); 818 return -EINVAL; 819 } 820 821 snd_config_for_each(i, next, cfg) { 822 n = snd_config_iterator_entry(i); 823 824 if (snd_config_get_id(n, &id) < 0) 825 return -EINVAL; 826 827 tseq = calloc(1, sizeof(*tseq)); 828 if (tseq == NULL) 829 return -ENOMEM; 830 INIT_LIST_HEAD(&tseq->transition_list); 831 832 err = get_string3(uc_mgr, id, &tseq->name); 833 if (err < 0) { 834 free(tseq); 835 return err; 836 } 837 838 err = parse_sequence(uc_mgr, &tseq->transition_list, n); 839 if (err < 0) { 840 uc_mgr_free_transition_element(tseq); 841 return err; 842 } 843 844 list_add(&tseq->list, tlist); 845 } 846 return 0; 847} 848 849/* 850 * Parse compound 851 */ 852static int parse_compound(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg, 853 int (*fcn)(snd_use_case_mgr_t *, snd_config_t *, void *, void *), 854 void *data1, void *data2) 855{ 856 const char *id; 857 snd_config_iterator_t i, next; 858 snd_config_t *n; 859 int err; 860 861 if (snd_config_get_id(cfg, &id) < 0) 862 return -EINVAL; 863 864 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { 865 uc_error("compound type expected for %s", id); 866 return -EINVAL; 867 } 868 /* parse compound */ 869 snd_config_for_each(i, next, cfg) { 870 n = snd_config_iterator_entry(i); 871 872 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { 873 uc_error("compound type expected for %s, is %d", id, snd_config_get_type(cfg)); 874 return -EINVAL; 875 } 876 877 err = fcn(uc_mgr, n, data1, data2); 878 if (err < 0) 879 return err; 880 } 881 882 return 0; 883} 884 885static int strip_legacy_dev_index(char *name) 886{ 887 char *dot = strchr(name, '.'); 888 if (!dot) 889 return 0; 890 if (dot[1] != '0' || dot[2] != '\0') { 891 uc_error("device name %s contains a '.'," 892 " and is not legacy foo.0 format", name); 893 return -EINVAL; 894 } 895 *dot = '\0'; 896 return 0; 897} 898 899/* 900 * Parse device list 901 */ 902static int parse_device_list(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED, 903 struct dev_list *dev_list, 904 enum dev_list_type type, 905 snd_config_t *cfg) 906{ 907 struct dev_list_node *sdev; 908 const char *id; 909 snd_config_iterator_t i, next; 910 snd_config_t *n; 911 int err; 912 913 if (dev_list->type != DEVLIST_NONE) { 914 uc_error("error: multiple supported or" 915 " conflicting device lists"); 916 return -EEXIST; 917 } 918 919 if (snd_config_get_id(cfg, &id) < 0) 920 return -EINVAL; 921 922 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { 923 uc_error("compound type expected for %s", id); 924 return -EINVAL; 925 } 926 927 snd_config_for_each(i, next, cfg) { 928 n = snd_config_iterator_entry(i); 929 930 if (snd_config_get_id(n, &id) < 0) 931 return -EINVAL; 932 933 sdev = calloc(1, sizeof(struct dev_list_node)); 934 if (sdev == NULL) 935 return -ENOMEM; 936 err = parse_string_substitute3(uc_mgr, n, &sdev->name); 937 if (err < 0) { 938 free(sdev); 939 return err; 940 } 941 err = strip_legacy_dev_index(sdev->name); 942 if (err < 0) { 943 free(sdev->name); 944 free(sdev); 945 return err; 946 } 947 list_add(&sdev->list, &dev_list->list); 948 } 949 950 dev_list->type = type; 951 952 return 0; 953} 954 955/* Find a component device by its name, and remove it from machine device 956 * list. 957 * 958 * Component devices are defined by machine components (usually off-soc 959 * codes or DSP embeded in SoC). Since alsaconf imports their configuration 960 * files automatically, we don't know which devices are component devices 961 * until they are referenced by a machine device sequence. So here when we 962 * find a referenced device, we move it from the machine device list to the 963 * component device list. Component devices will not be exposed to applications 964 * by the original API to list devices for backward compatibility. So sound 965 * servers can only see the machine devices. 966 */ 967struct use_case_device *find_component_dev(snd_use_case_mgr_t *uc_mgr, 968 const char *name) 969{ 970 struct list_head *pos, *posdev, *_posdev; 971 struct use_case_verb *verb; 972 struct use_case_device *dev; 973 974 list_for_each(pos, &uc_mgr->verb_list) { 975 verb = list_entry(pos, struct use_case_verb, list); 976 977 /* search in the component device list */ 978 list_for_each(posdev, &verb->cmpt_device_list) { 979 dev = list_entry(posdev, struct use_case_device, list); 980 if (!strcmp(dev->name, name)) 981 return dev; 982 } 983 984 /* search the machine device list */ 985 list_for_each_safe(posdev, _posdev, &verb->device_list) { 986 dev = list_entry(posdev, struct use_case_device, list); 987 if (!strcmp(dev->name, name)) { 988 /* find the component device, move it from the 989 * machine device list to the component device 990 * list. 991 */ 992 list_del(&dev->list); 993 list_add_tail(&dev->list, 994 &verb->cmpt_device_list); 995 return dev; 996 } 997 } 998 } 999 1000 return NULL; 1001} 1002 1003/* parse sequence of a component device 1004 * 1005 * This function will find the component device and mark if its enable or 1006 * disable sequence is needed by its parenet device. 1007 */ 1008static int parse_component_seq(snd_use_case_mgr_t *uc_mgr, 1009 snd_config_t *n, int enable, 1010 struct component_sequence *cmpt_seq) 1011{ 1012 char *val; 1013 int err; 1014 1015 err = parse_string_substitute3(uc_mgr, n, &val); 1016 if (err < 0) 1017 return err; 1018 1019 cmpt_seq->device = find_component_dev(uc_mgr, val); 1020 if (!cmpt_seq->device) { 1021 uc_error("error: Cannot find component device %s", val); 1022 free(val); 1023 return -EINVAL; 1024 } 1025 free(val); 1026 1027 /* Parent needs its enable or disable sequence */ 1028 cmpt_seq->enable = enable; 1029 1030 return 0; 1031} 1032 1033/* 1034 * Parse sequences. 1035 * 1036 * Sequence controls elements are in the following form:- 1037 * 1038 * cdev "hw:0" 1039 * cset "element_id_syntax value_syntax" 1040 * usleep time 1041 * exec "any unix command with arguments" 1042 * enadev "component device name" 1043 * disdev "component device name" 1044 * 1045 * e.g. 1046 * cset "name='Master Playback Switch' 0,0" 1047 * cset "iface=PCM,name='Disable HDMI',index=1 0" 1048 * enadev "rt286:Headphones" 1049 * disdev "rt286:Speaker" 1050 */ 1051static int parse_sequence(snd_use_case_mgr_t *uc_mgr, 1052 struct list_head *base, 1053 snd_config_t *cfg) 1054{ 1055 struct sequence_element *curr; 1056 snd_config_iterator_t i, next; 1057 snd_config_t *n; 1058 int err, idx = 0; 1059 const char *cmd = NULL; 1060 1061 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { 1062 uc_error("error: compound is expected for sequence definition"); 1063 return -EINVAL; 1064 } 1065 1066 snd_config_for_each(i, next, cfg) { 1067 const char *id; 1068 idx ^= 1; 1069 n = snd_config_iterator_entry(i); 1070 err = snd_config_get_id(n, &id); 1071 if (err < 0) 1072 continue; 1073 if (idx == 1) { 1074 if (snd_config_get_type(n) != SND_CONFIG_TYPE_STRING) { 1075 uc_error("error: string type is expected for sequence command"); 1076 return -EINVAL; 1077 } 1078 snd_config_get_string(n, &cmd); 1079 continue; 1080 } 1081 1082 /* alloc new sequence element */ 1083 curr = calloc(1, sizeof(struct sequence_element)); 1084 if (curr == NULL) 1085 return -ENOMEM; 1086 list_add_tail(&curr->list, base); 1087 1088 if (strcmp(cmd, "cdev") == 0) { 1089 curr->type = SEQUENCE_ELEMENT_TYPE_CDEV; 1090 err = parse_string_substitute3(uc_mgr, n, &curr->data.cdev); 1091 if (err < 0) { 1092 uc_error("error: cdev requires a string!"); 1093 return err; 1094 } 1095 continue; 1096 } 1097 1098 if (strcmp(cmd, "cset") == 0) { 1099 curr->type = SEQUENCE_ELEMENT_TYPE_CSET; 1100cset: 1101 err = parse_string_substitute3(uc_mgr, n, &curr->data.cset); 1102 if (err < 0) { 1103 uc_error("error: %s requires a string!", cmd); 1104 return err; 1105 } 1106 continue; 1107 } 1108 1109 if (strcmp(cmd, "enadev") == 0 || 1110 strcmp(cmd, "disdev") == 0) { 1111 /* need to enable or disable a component device */ 1112 curr->type = SEQUENCE_ELEMENT_TYPE_CMPT_SEQ; 1113 err = parse_component_seq(uc_mgr, n, 1114 strcmp(cmd, "enadev") == 0, 1115 &curr->data.cmpt_seq); 1116 if (err < 0) { 1117 uc_error("error: %s requires a valid device!", cmd); 1118 return err; 1119 } 1120 continue; 1121 } 1122 1123 if (strcmp(cmd, "enadev2") == 0) { 1124 curr->type = SEQUENCE_ELEMENT_TYPE_DEV_ENABLE_SEQ; 1125 goto device; 1126 } 1127 1128 if (strcmp(cmd, "disdev2") == 0) { 1129 curr->type = SEQUENCE_ELEMENT_TYPE_DEV_DISABLE_SEQ; 1130device: 1131 err = parse_string_substitute3(uc_mgr, n, &curr->data.device); 1132 if (err < 0) { 1133 uc_error("error: %s requires a valid device!", cmd); 1134 return err; 1135 } 1136 continue; 1137 } 1138 1139 if (strcmp(cmd, "disdevall") == 0) { 1140 curr->type = SEQUENCE_ELEMENT_TYPE_DEV_DISABLE_ALL; 1141 continue; 1142 } 1143 1144 if (strcmp(cmd, "cset-bin-file") == 0) { 1145 curr->type = SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE; 1146 goto cset; 1147 } 1148 1149 if (strcmp(cmd, "cset-tlv") == 0) { 1150 curr->type = SEQUENCE_ELEMENT_TYPE_CSET_TLV; 1151 goto cset; 1152 } 1153 1154 if (strcmp(cmd, "cset-new") == 0) { 1155 curr->type = SEQUENCE_ELEMENT_TYPE_CSET_NEW; 1156 goto cset; 1157 } 1158 1159 if (strcmp(cmd, "ctl-remove") == 0) { 1160 curr->type = SEQUENCE_ELEMENT_TYPE_CTL_REMOVE; 1161 goto cset; 1162 } 1163 1164 if (strcmp(cmd, "sysw") == 0) { 1165 curr->type = SEQUENCE_ELEMENT_TYPE_SYSSET; 1166 err = parse_string_substitute3(uc_mgr, n, &curr->data.sysw); 1167 if (err < 0) { 1168 uc_error("error: sysw requires a string!"); 1169 return err; 1170 } 1171 continue; 1172 } 1173 1174 if (strcmp(cmd, "usleep") == 0) { 1175 curr->type = SEQUENCE_ELEMENT_TYPE_SLEEP; 1176 err = parse_integer_substitute3(uc_mgr, n, &curr->data.sleep); 1177 if (err < 0) { 1178 uc_error("error: usleep requires integer!"); 1179 return err; 1180 } 1181 continue; 1182 } 1183 1184 if (strcmp(cmd, "msleep") == 0) { 1185 curr->type = SEQUENCE_ELEMENT_TYPE_SLEEP; 1186 err = parse_integer_substitute3(uc_mgr, n, &curr->data.sleep); 1187 if (err < 0) { 1188 uc_error("error: msleep requires integer!"); 1189 return err; 1190 } 1191 curr->data.sleep *= 1000L; 1192 continue; 1193 } 1194 1195 if (strcmp(cmd, "exec") == 0) { 1196 curr->type = SEQUENCE_ELEMENT_TYPE_EXEC; 1197exec: 1198 err = parse_string_substitute3(uc_mgr, n, &curr->data.exec); 1199 if (err < 0) { 1200 uc_error("error: exec requires a string!"); 1201 return err; 1202 } 1203 continue; 1204 } 1205 1206 if (strcmp(cmd, "shell") == 0) { 1207 curr->type = SEQUENCE_ELEMENT_TYPE_SHELL; 1208 goto exec; 1209 } 1210 1211 if (strcmp(cmd, "cfg-save") == 0) { 1212 curr->type = SEQUENCE_ELEMENT_TYPE_CFGSAVE; 1213 err = parse_string_substitute3(uc_mgr, n, &curr->data.cfgsave); 1214 if (err < 0) { 1215 uc_error("error: sysw requires a string!"); 1216 return err; 1217 } 1218 continue; 1219 } 1220 1221 if (strcmp(cmd, "comment") == 0) 1222 goto skip; 1223 1224 uc_error("error: sequence command '%s' is ignored", cmd); 1225 1226skip: 1227 list_del(&curr->list); 1228 uc_mgr_free_sequence_element(curr); 1229 } 1230 1231 return 0; 1232} 1233 1234/* 1235 * 1236 */ 1237int uc_mgr_add_value(struct list_head *base, const char *key, char *val) 1238{ 1239 struct ucm_value *curr; 1240 1241 curr = calloc(1, sizeof(struct ucm_value)); 1242 if (curr == NULL) 1243 return -ENOMEM; 1244 curr->name = strdup(key); 1245 if (curr->name == NULL) { 1246 free(curr); 1247 return -ENOMEM; 1248 } 1249 list_add_tail(&curr->list, base); 1250 curr->data = val; 1251 return 0; 1252} 1253 1254/* 1255 * Parse values. 1256 * 1257 * Parse values describing PCM, control/mixer settings and stream parameters. 1258 * 1259 * Value { 1260 * TQ Voice 1261 * CapturePCM "hw:1" 1262 * PlaybackVolume "name='Master Playback Volume',index=2" 1263 * PlaybackSwitch "name='Master Playback Switch',index=2" 1264 * } 1265 */ 1266static int parse_value(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED, 1267 struct list_head *base, 1268 snd_config_t *cfg) 1269{ 1270 snd_config_iterator_t i, next; 1271 snd_config_t *n; 1272 char *s; 1273 snd_config_type_t type; 1274 int err; 1275 1276 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { 1277 uc_error("error: compound is expected for value definition"); 1278 return -EINVAL; 1279 } 1280 1281 /* in-place evaluation */ 1282 err = uc_mgr_evaluate_inplace(uc_mgr, cfg); 1283 if (err < 0) 1284 return err; 1285 1286 snd_config_for_each(i, next, cfg) { 1287 const char *id; 1288 n = snd_config_iterator_entry(i); 1289 err = snd_config_get_id(n, &id); 1290 if (err < 0) 1291 continue; 1292 1293 type = snd_config_get_type(n); 1294 switch (type) { 1295 case SND_CONFIG_TYPE_INTEGER: 1296 case SND_CONFIG_TYPE_INTEGER64: 1297 case SND_CONFIG_TYPE_REAL: 1298 err = snd_config_get_ascii(n, &s); 1299 if (err < 0) { 1300 uc_error("error: unable to parse value for id '%s': %s!", id, snd_strerror(err)); 1301 return err; 1302 } 1303 break; 1304 case SND_CONFIG_TYPE_STRING: 1305 err = parse_string_substitute(uc_mgr, n, &s); 1306 if (err < 0) { 1307 uc_error("error: unable to parse a string for id '%s'!", id); 1308 return err; 1309 } 1310 break; 1311 default: 1312 uc_error("error: invalid type %i in Value compound '%s'", type, id); 1313 return -EINVAL; 1314 } 1315 err = uc_mgr_add_value(base, id, s); 1316 if (err < 0) { 1317 free(s); 1318 return err; 1319 } 1320 } 1321 1322 return 0; 1323} 1324 1325/* 1326 * Parse Modifier Use cases 1327 * 1328 * # Each modifier is described in new section. N modifiers are allowed 1329 * SectionModifier."Capture Voice" { 1330 * 1331 * Comment "Record voice call" 1332 * 1333 * SupportedDevice [ 1334 * "x" 1335 * "y" 1336 * ] 1337 * 1338 * ConflictingDevice [ 1339 * "x" 1340 * "y" 1341 * ] 1342 * 1343 * EnableSequence [ 1344 * .... 1345 * ] 1346 * 1347 * DisableSequence [ 1348 * ... 1349 * ] 1350 * 1351 * TransitionSequence."ToModifierName" [ 1352 * ... 1353 * ] 1354 * 1355 * # Optional TQ and ALSA PCMs 1356 * Value { 1357 * TQ Voice 1358 * CapturePCM "hw:1" 1359 * PlaybackVolume "name='Master Playback Volume',index=2" 1360 * PlaybackSwitch "name='Master Playback Switch',index=2" 1361 * } 1362 * } 1363 * 1364 * SupportedDevice and ConflictingDevice cannot be specified together. 1365 * Both are optional. 1366 */ 1367static int parse_modifier(snd_use_case_mgr_t *uc_mgr, 1368 snd_config_t *cfg, 1369 void *data1, void *data2) 1370{ 1371 struct use_case_verb *verb = data1; 1372 struct use_case_modifier *modifier; 1373 char *name; 1374 snd_config_iterator_t i, next; 1375 snd_config_t *n; 1376 int err; 1377 1378 if (parse_get_safe_name(uc_mgr, cfg, data2, &name) < 0) 1379 return -EINVAL; 1380 1381 /* allocate modifier */ 1382 modifier = calloc(1, sizeof(*modifier)); 1383 if (modifier == NULL) { 1384 free(name); 1385 return -ENOMEM; 1386 } 1387 INIT_LIST_HEAD(&modifier->enable_list); 1388 INIT_LIST_HEAD(&modifier->disable_list); 1389 INIT_LIST_HEAD(&modifier->transition_list); 1390 INIT_LIST_HEAD(&modifier->dev_list.list); 1391 INIT_LIST_HEAD(&modifier->value_list); 1392 list_add_tail(&modifier->list, &verb->modifier_list); 1393 modifier->name = name; 1394 1395 /* in-place evaluation */ 1396 err = uc_mgr_evaluate_inplace(uc_mgr, cfg); 1397 if (err < 0) 1398 return err; 1399 1400 snd_config_for_each(i, next, cfg) { 1401 const char *id; 1402 n = snd_config_iterator_entry(i); 1403 if (snd_config_get_id(n, &id) < 0) 1404 continue; 1405 1406 if (strcmp(id, "Comment") == 0) { 1407 err = parse_string_substitute3(uc_mgr, n, &modifier->comment); 1408 if (err < 0) { 1409 uc_error("error: failed to get modifier comment"); 1410 return err; 1411 } 1412 continue; 1413 } 1414 1415 if (strcmp(id, "SupportedDevice") == 0) { 1416 err = parse_device_list(uc_mgr, &modifier->dev_list, 1417 DEVLIST_SUPPORTED, n); 1418 if (err < 0) { 1419 uc_error("error: failed to parse supported" 1420 " device list"); 1421 return err; 1422 } 1423 } 1424 1425 if (strcmp(id, "ConflictingDevice") == 0) { 1426 err = parse_device_list(uc_mgr, &modifier->dev_list, 1427 DEVLIST_CONFLICTING, n); 1428 if (err < 0) { 1429 uc_error("error: failed to parse conflicting" 1430 " device list"); 1431 return err; 1432 } 1433 } 1434 1435 if (strcmp(id, "EnableSequence") == 0) { 1436 err = parse_sequence(uc_mgr, &modifier->enable_list, n); 1437 if (err < 0) { 1438 uc_error("error: failed to parse modifier" 1439 " enable sequence"); 1440 return err; 1441 } 1442 continue; 1443 } 1444 1445 if (strcmp(id, "DisableSequence") == 0) { 1446 err = parse_sequence(uc_mgr, &modifier->disable_list, n); 1447 if (err < 0) { 1448 uc_error("error: failed to parse modifier" 1449 " disable sequence"); 1450 return err; 1451 } 1452 continue; 1453 } 1454 1455 if (strcmp(id, "TransitionSequence") == 0) { 1456 err = parse_transition(uc_mgr, &modifier->transition_list, n); 1457 if (err < 0) { 1458 uc_error("error: failed to parse transition" 1459 " modifier"); 1460 return err; 1461 } 1462 continue; 1463 } 1464 1465 if (strcmp(id, "Value") == 0) { 1466 err = parse_value(uc_mgr, &modifier->value_list, n); 1467 if (err < 0) { 1468 uc_error("error: failed to parse Value"); 1469 return err; 1470 } 1471 continue; 1472 } 1473 } 1474 1475 return 0; 1476} 1477 1478/* 1479 * Parse Device Use Cases 1480 * 1481 * # Each device is described in new section. N devices are allowed 1482 * SectionDevice."Headphones" { 1483 * Comment "Headphones connected to 3.5mm jack" 1484 * 1485 * SupportedDevice [ 1486 * "x" 1487 * "y" 1488 * ] 1489 * 1490 * ConflictingDevice [ 1491 * "x" 1492 * "y" 1493 * ] 1494 * 1495 * EnableSequence [ 1496 * .... 1497 * ] 1498 * 1499 * DisableSequence [ 1500 * ... 1501 * ] 1502 * 1503 * TransitionSequence."ToDevice" [ 1504 * ... 1505 * ] 1506 * 1507 * Value { 1508 * PlaybackVolume "name='Master Playback Volume',index=2" 1509 * PlaybackSwitch "name='Master Playback Switch',index=2" 1510 * } 1511 * } 1512 */ 1513static int parse_device(snd_use_case_mgr_t *uc_mgr, 1514 snd_config_t *cfg, 1515 void *data1, void *data2) 1516{ 1517 struct use_case_verb *verb = data1; 1518 char *name; 1519 struct use_case_device *device; 1520 snd_config_iterator_t i, next; 1521 snd_config_t *n; 1522 int err; 1523 1524 if (parse_get_safe_name(uc_mgr, cfg, data2, &name) < 0) 1525 return -EINVAL; 1526 1527 device = calloc(1, sizeof(*device)); 1528 if (device == NULL) { 1529 free(name); 1530 return -ENOMEM; 1531 } 1532 INIT_LIST_HEAD(&device->enable_list); 1533 INIT_LIST_HEAD(&device->disable_list); 1534 INIT_LIST_HEAD(&device->transition_list); 1535 INIT_LIST_HEAD(&device->dev_list.list); 1536 INIT_LIST_HEAD(&device->value_list); 1537 list_add_tail(&device->list, &verb->device_list); 1538 device->name = name; 1539 1540 /* in-place evaluation */ 1541 err = uc_mgr_evaluate_inplace(uc_mgr, cfg); 1542 if (err < 0) 1543 return err; 1544 1545 snd_config_for_each(i, next, cfg) { 1546 const char *id; 1547 n = snd_config_iterator_entry(i); 1548 if (snd_config_get_id(n, &id) < 0) 1549 continue; 1550 1551 if (strcmp(id, "Comment") == 0) { 1552 err = parse_string_substitute3(uc_mgr, n, &device->comment); 1553 if (err < 0) { 1554 uc_error("error: failed to get device comment"); 1555 return err; 1556 } 1557 continue; 1558 } 1559 1560 if (strcmp(id, "SupportedDevice") == 0) { 1561 err = parse_device_list(uc_mgr, &device->dev_list, 1562 DEVLIST_SUPPORTED, n); 1563 if (err < 0) { 1564 uc_error("error: failed to parse supported" 1565 " device list"); 1566 return err; 1567 } 1568 } 1569 1570 if (strcmp(id, "ConflictingDevice") == 0) { 1571 err = parse_device_list(uc_mgr, &device->dev_list, 1572 DEVLIST_CONFLICTING, n); 1573 if (err < 0) { 1574 uc_error("error: failed to parse conflicting" 1575 " device list"); 1576 return err; 1577 } 1578 } 1579 1580 if (strcmp(id, "EnableSequence") == 0) { 1581 uc_dbg("EnableSequence"); 1582 err = parse_sequence(uc_mgr, &device->enable_list, n); 1583 if (err < 0) { 1584 uc_error("error: failed to parse device enable" 1585 " sequence"); 1586 return err; 1587 } 1588 continue; 1589 } 1590 1591 if (strcmp(id, "DisableSequence") == 0) { 1592 uc_dbg("DisableSequence"); 1593 err = parse_sequence(uc_mgr, &device->disable_list, n); 1594 if (err < 0) { 1595 uc_error("error: failed to parse device disable" 1596 " sequence"); 1597 return err; 1598 } 1599 continue; 1600 } 1601 1602 if (strcmp(id, "TransitionSequence") == 0) { 1603 uc_dbg("TransitionSequence"); 1604 err = parse_transition(uc_mgr, &device->transition_list, n); 1605 if (err < 0) { 1606 uc_error("error: failed to parse transition" 1607 " device"); 1608 return err; 1609 } 1610 continue; 1611 } 1612 1613 if (strcmp(id, "Value") == 0) { 1614 err = parse_value(uc_mgr, &device->value_list, n); 1615 if (err < 0) { 1616 uc_error("error: failed to parse Value"); 1617 return err; 1618 } 1619 continue; 1620 } 1621 } 1622 return 0; 1623} 1624 1625/* 1626 * Parse Device Rename/Delete Command 1627 * 1628 * # The devices might be renamed to allow the better conditional runtime 1629 * # evaluation. Bellow example renames Speaker1 device to Speaker and 1630 * # removes Speaker2 device. 1631 * RenameDevice."Speaker1" "Speaker" 1632 * RemoveDevice."Speaker2" "Speaker2" 1633 */ 1634static int parse_dev_name_list(snd_use_case_mgr_t *uc_mgr, 1635 snd_config_t *cfg, 1636 struct list_head *list) 1637{ 1638 snd_config_t *n; 1639 snd_config_iterator_t i, next; 1640 const char *id, *name1; 1641 char *name1s, *name2; 1642 struct ucm_dev_name *dev; 1643 snd_config_iterator_t pos; 1644 int err; 1645 1646 if (snd_config_get_id(cfg, &id) < 0) 1647 return -EINVAL; 1648 1649 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { 1650 uc_error("compound type expected for %s", id); 1651 return -EINVAL; 1652 } 1653 1654 snd_config_for_each(i, next, cfg) { 1655 n = snd_config_iterator_entry(i); 1656 1657 if (snd_config_get_id(n, &name1) < 0) 1658 return -EINVAL; 1659 1660 err = get_string3(uc_mgr, name1, &name1s); 1661 if (err < 0) 1662 return err; 1663 1664 err = parse_string_substitute3(uc_mgr, n, &name2); 1665 if (err < 0) { 1666 free(name1s); 1667 uc_error("error: failed to get target device name for '%s'", name1); 1668 return err; 1669 } 1670 1671 /* skip duplicates */ 1672 list_for_each(pos, list) { 1673 dev = list_entry(pos, struct ucm_dev_name, list); 1674 if (strcmp(dev->name1, name1s) == 0) { 1675 free(name2); 1676 free(name1s); 1677 return 0; 1678 } 1679 } 1680 1681 free(name1s); 1682 1683 dev = calloc(1, sizeof(*dev)); 1684 if (dev == NULL) { 1685 free(name2); 1686 return -ENOMEM; 1687 } 1688 dev->name1 = strdup(name1); 1689 if (dev->name1 == NULL) { 1690 free(dev); 1691 free(name2); 1692 return -ENOMEM; 1693 } 1694 dev->name2 = name2; 1695 list_add_tail(&dev->list, list); 1696 } 1697 1698 return 0; 1699} 1700 1701static int parse_compound_check_legacy(snd_use_case_mgr_t *uc_mgr, 1702 snd_config_t *cfg, 1703 int (*fcn)(snd_use_case_mgr_t *, snd_config_t *, void *, void *), 1704 void *data1) 1705{ 1706 const char *id, *idchild; 1707 int child_ctr = 0, legacy_format = 1; 1708 snd_config_iterator_t i, next; 1709 snd_config_t *child; 1710 int err; 1711 1712 err = snd_config_get_id(cfg, &id); 1713 if (err < 0) 1714 return err; 1715 1716 snd_config_for_each(i, next, cfg) { 1717 child_ctr++; 1718 if (child_ctr > 1) { 1719 break; 1720 } 1721 1722 child = snd_config_iterator_entry(i); 1723 1724 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { 1725 legacy_format = 0; 1726 break; 1727 } 1728 1729 if (snd_config_get_id(child, &idchild) < 0) 1730 return -EINVAL; 1731 1732 if (strcmp(idchild, "0")) { 1733 legacy_format = 0; 1734 break; 1735 } 1736 } 1737 if (child_ctr != 1) { 1738 legacy_format = 0; 1739 } 1740 1741 if (legacy_format) 1742 return parse_compound(uc_mgr, cfg, fcn, data1, (void *)id); 1743 else 1744 return fcn(uc_mgr, cfg, data1, NULL); 1745} 1746 1747static int parse_device_name(snd_use_case_mgr_t *uc_mgr, 1748 snd_config_t *cfg, 1749 void *data1, 1750 void *data2 ATTRIBUTE_UNUSED) 1751{ 1752 return parse_compound_check_legacy(uc_mgr, cfg, parse_device, data1); 1753} 1754 1755static int parse_modifier_name(snd_use_case_mgr_t *uc_mgr, 1756 snd_config_t *cfg, 1757 void *data1, 1758 void *data2 ATTRIBUTE_UNUSED) 1759{ 1760 return parse_compound_check_legacy(uc_mgr, cfg, parse_modifier, data1); 1761} 1762 1763static int verb_dev_list_add(struct use_case_verb *verb, 1764 enum dev_list_type dst_type, 1765 const char *dst, 1766 const char *src) 1767{ 1768 struct use_case_device *device; 1769 struct list_head *pos; 1770 1771 list_for_each(pos, &verb->device_list) { 1772 device = list_entry(pos, struct use_case_device, list); 1773 if (strcmp(device->name, dst) != 0) 1774 continue; 1775 if (device->dev_list.type != dst_type) { 1776 if (list_empty(&device->dev_list.list)) { 1777 device->dev_list.type = dst_type; 1778 } else { 1779 uc_error("error: incompatible device list type ('%s', '%s')", 1780 device->name, src); 1781 return -EINVAL; 1782 } 1783 } 1784 return uc_mgr_put_to_dev_list(&device->dev_list, src); 1785 } 1786 uc_error("error: unable to find device '%s'", dst); 1787 return -ENOENT; 1788} 1789 1790static int verb_dev_list_check(struct use_case_verb *verb) 1791{ 1792 struct list_head *pos, *pos2; 1793 struct use_case_device *device; 1794 struct dev_list_node *dlist; 1795 int err; 1796 1797 list_for_each(pos, &verb->device_list) { 1798 device = list_entry(pos, struct use_case_device, list); 1799 list_for_each(pos2, &device->dev_list.list) { 1800 dlist = list_entry(pos2, struct dev_list_node, list); 1801 err = verb_dev_list_add(verb, device->dev_list.type, 1802 dlist->name, device->name); 1803 if (err < 0) 1804 return err; 1805 } 1806 } 1807 return 0; 1808} 1809 1810static int verb_device_management(struct use_case_verb *verb) 1811{ 1812 struct list_head *pos; 1813 struct ucm_dev_name *dev; 1814 int err; 1815 1816 /* rename devices */ 1817 list_for_each(pos, &verb->rename_list) { 1818 dev = list_entry(pos, struct ucm_dev_name, list); 1819 err = uc_mgr_rename_device(verb, dev->name1, dev->name2); 1820 if (err < 0) { 1821 uc_error("error: cannot rename device '%s' to '%s'", dev->name1, dev->name2); 1822 return err; 1823 } 1824 } 1825 1826 /* remove devices */ 1827 list_for_each(pos, &verb->remove_list) { 1828 dev = list_entry(pos, struct ucm_dev_name, list); 1829 err = uc_mgr_remove_device(verb, dev->name2); 1830 if (err < 0) { 1831 uc_error("error: cannot remove device '%s'", dev->name2); 1832 return err; 1833 } 1834 } 1835 1836 /* those lists are no longer used */ 1837 uc_mgr_free_dev_name_list(&verb->rename_list); 1838 uc_mgr_free_dev_name_list(&verb->remove_list); 1839 1840 /* handle conflicting/supported lists */ 1841 return verb_dev_list_check(verb); 1842} 1843 1844/* 1845 * Parse Verb Section 1846 * 1847 * # Example Use case verb section for Voice call blah 1848 * # By Joe Blogs <joe@blogs.com> 1849 * 1850 * SectionVerb { 1851 * # enable and disable sequences are compulsory 1852 * EnableSequence [ 1853 * cset "name='Master Playback Switch',index=2 0,0" 1854 * cset "name='Master Playback Volume',index=2 25,25" 1855 * msleep 50 1856 * cset "name='Master Playback Switch',index=2 1,1" 1857 * cset "name='Master Playback Volume',index=2 50,50" 1858 * ] 1859 * 1860 * DisableSequence [ 1861 * cset "name='Master Playback Switch',index=2 0,0" 1862 * cset "name='Master Playback Volume',index=2 25,25" 1863 * msleep 50 1864 * cset "name='Master Playback Switch',index=2 1,1" 1865 * cset "name='Master Playback Volume',index=2 50,50" 1866 * ] 1867 * 1868 * # Optional transition verb 1869 * TransitionSequence."ToCaseName" [ 1870 * msleep 1 1871 * ] 1872 * 1873 * # Optional TQ and ALSA PCMs 1874 * Value { 1875 * TQ HiFi 1876 * CapturePCM "hw:0" 1877 * PlaybackPCM "hw:0" 1878 * } 1879 * } 1880 */ 1881static int parse_verb(snd_use_case_mgr_t *uc_mgr, 1882 struct use_case_verb *verb, 1883 snd_config_t *cfg) 1884{ 1885 snd_config_iterator_t i, next; 1886 snd_config_t *n; 1887 int err; 1888 1889 /* in-place evaluation */ 1890 err = uc_mgr_evaluate_inplace(uc_mgr, cfg); 1891 if (err < 0) 1892 return err; 1893 1894 /* parse verb section */ 1895 snd_config_for_each(i, next, cfg) { 1896 const char *id; 1897 n = snd_config_iterator_entry(i); 1898 if (snd_config_get_id(n, &id) < 0) 1899 continue; 1900 1901 if (strcmp(id, "EnableSequence") == 0) { 1902 uc_dbg("Parse EnableSequence"); 1903 err = parse_sequence(uc_mgr, &verb->enable_list, n); 1904 if (err < 0) { 1905 uc_error("error: failed to parse verb enable sequence"); 1906 return err; 1907 } 1908 continue; 1909 } 1910 1911 if (strcmp(id, "DisableSequence") == 0) { 1912 uc_dbg("Parse DisableSequence"); 1913 err = parse_sequence(uc_mgr, &verb->disable_list, n); 1914 if (err < 0) { 1915 uc_error("error: failed to parse verb disable sequence"); 1916 return err; 1917 } 1918 continue; 1919 } 1920 1921 if (strcmp(id, "TransitionSequence") == 0) { 1922 uc_dbg("Parse TransitionSequence"); 1923 err = parse_transition(uc_mgr, &verb->transition_list, n); 1924 if (err < 0) { 1925 uc_error("error: failed to parse transition sequence"); 1926 return err; 1927 } 1928 continue; 1929 } 1930 1931 if (strcmp(id, "Value") == 0) { 1932 uc_dbg("Parse Value"); 1933 err = parse_value(uc_mgr, &verb->value_list, n); 1934 if (err < 0) 1935 return err; 1936 continue; 1937 } 1938 } 1939 1940 return 0; 1941} 1942 1943/* 1944 * Parse a Use case verb file. 1945 * 1946 * This file contains the following :- 1947 * o Verb enable and disable sequences. 1948 * o Supported Device enable and disable sequences for verb. 1949 * o Supported Modifier enable and disable sequences for verb 1950 * o Optional QoS for the verb and modifiers. 1951 * o Optional PCM device ID for verb and modifiers 1952 * o Alias kcontrols IDs for master and volumes and mutes. 1953 */ 1954static int parse_verb_file(snd_use_case_mgr_t *uc_mgr, 1955 const char *use_case_name, 1956 const char *comment, 1957 const char *file) 1958{ 1959 snd_config_iterator_t i, next; 1960 snd_config_t *n; 1961 struct use_case_verb *verb; 1962 snd_config_t *cfg; 1963 int err; 1964 1965 /* allocate verb */ 1966 verb = calloc(1, sizeof(struct use_case_verb)); 1967 if (verb == NULL) 1968 return -ENOMEM; 1969 INIT_LIST_HEAD(&verb->enable_list); 1970 INIT_LIST_HEAD(&verb->disable_list); 1971 INIT_LIST_HEAD(&verb->transition_list); 1972 INIT_LIST_HEAD(&verb->device_list); 1973 INIT_LIST_HEAD(&verb->cmpt_device_list); 1974 INIT_LIST_HEAD(&verb->modifier_list); 1975 INIT_LIST_HEAD(&verb->value_list); 1976 INIT_LIST_HEAD(&verb->rename_list); 1977 INIT_LIST_HEAD(&verb->remove_list); 1978 list_add_tail(&verb->list, &uc_mgr->verb_list); 1979 if (use_case_name == NULL) 1980 return -EINVAL; 1981 verb->name = strdup(use_case_name); 1982 if (verb->name == NULL) 1983 return -ENOMEM; 1984 1985 if (comment != NULL) { 1986 verb->comment = strdup(comment); 1987 if (verb->comment == NULL) 1988 return -ENOMEM; 1989 } 1990 1991 /* open Verb file for reading */ 1992 err = uc_mgr_config_load_file(uc_mgr, file, &cfg); 1993 if (err < 0) 1994 return err; 1995 1996 /* in-place evaluation */ 1997 err = uc_mgr_evaluate_inplace(uc_mgr, cfg); 1998 if (err < 0) 1999 goto _err; 2000 2001 /* parse master config sections */ 2002 snd_config_for_each(i, next, cfg) { 2003 const char *id; 2004 n = snd_config_iterator_entry(i); 2005 if (snd_config_get_id(n, &id) < 0) 2006 continue; 2007 2008 /* find verb section and parse it */ 2009 if (strcmp(id, "SectionVerb") == 0) { 2010 err = parse_verb(uc_mgr, verb, n); 2011 if (err < 0) { 2012 uc_error("error: %s failed to parse verb", 2013 file); 2014 goto _err; 2015 } 2016 continue; 2017 } 2018 2019 /* find device sections and parse them */ 2020 if (strcmp(id, "SectionDevice") == 0) { 2021 err = parse_compound(uc_mgr, n, 2022 parse_device_name, verb, NULL); 2023 if (err < 0) { 2024 uc_error("error: %s failed to parse device", 2025 file); 2026 goto _err; 2027 } 2028 continue; 2029 } 2030 2031 /* find modifier sections and parse them */ 2032 if (strcmp(id, "SectionModifier") == 0) { 2033 err = parse_compound(uc_mgr, n, 2034 parse_modifier_name, verb, NULL); 2035 if (err < 0) { 2036 uc_error("error: %s failed to parse modifier", 2037 file); 2038 goto _err; 2039 } 2040 continue; 2041 } 2042 2043 /* device renames */ 2044 if (strcmp(id, "RenameDevice") == 0) { 2045 err = parse_dev_name_list(uc_mgr, n, &verb->rename_list); 2046 if (err < 0) { 2047 uc_error("error: %s failed to parse device rename", 2048 file); 2049 goto _err; 2050 } 2051 continue; 2052 } 2053 2054 /* device remove */ 2055 if (strcmp(id, "RemoveDevice") == 0) { 2056 err = parse_dev_name_list(uc_mgr, n, &verb->remove_list); 2057 if (err < 0) { 2058 uc_error("error: %s failed to parse device remove", 2059 file); 2060 goto _err; 2061 } 2062 continue; 2063 } 2064 2065 /* alsa-lib configuration */ 2066 if (uc_mgr->conf_format > 3 && strcmp(id, "LibraryConfig") == 0) { 2067 err = parse_libconfig(uc_mgr, n); 2068 if (err < 0) { 2069 uc_error("error: failed to parse LibConfig"); 2070 goto _err; 2071 } 2072 continue; 2073 } 2074 } 2075 2076 snd_config_delete(cfg); 2077 2078 /* use case verb must have at least 1 device */ 2079 if (list_empty(&verb->device_list)) { 2080 uc_error("error: no use case device defined", file); 2081 return -EINVAL; 2082 } 2083 2084 /* do device rename and delete */ 2085 err = verb_device_management(verb); 2086 if (err < 0) { 2087 uc_error("error: device management error in verb '%s'", verb->name); 2088 return err; 2089 } 2090 2091 return 0; 2092 2093 _err: 2094 snd_config_delete(cfg); 2095 return err; 2096} 2097 2098/* 2099 * Parse variant information 2100 */ 2101static int parse_variant(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg, 2102 char **_vfile, char **_vcomment) 2103{ 2104 snd_config_iterator_t i, next; 2105 snd_config_t *n; 2106 char *file = NULL, *comment = NULL; 2107 int err; 2108 2109 /* parse master config sections */ 2110 snd_config_for_each(i, next, cfg) { 2111 const char *id; 2112 n = snd_config_iterator_entry(i); 2113 if (snd_config_get_id(n, &id) < 0) 2114 continue; 2115 2116 /* get use case verb file name */ 2117 if (strcmp(id, "File") == 0) { 2118 if (_vfile) { 2119 err = parse_string_substitute3(uc_mgr, n, &file); 2120 if (err < 0) { 2121 uc_error("failed to get File"); 2122 goto __error; 2123 } 2124 } 2125 continue; 2126 } 2127 2128 /* get optional use case comment */ 2129 if (strncmp(id, "Comment", 7) == 0) { 2130 if (_vcomment) { 2131 err = parse_string_substitute3(uc_mgr, n, &comment); 2132 if (err < 0) { 2133 uc_error("error: failed to get Comment"); 2134 goto __error; 2135 } 2136 } 2137 continue; 2138 } 2139 2140 uc_error("unknown field '%s' in Variant section", id); 2141 err = -EINVAL; 2142 goto __error; 2143 } 2144 2145 if (_vfile) 2146 *_vfile = file; 2147 if (_vcomment) 2148 *_vcomment = comment; 2149 return 0; 2150 2151__error: 2152 free(file); 2153 free(comment); 2154 return err; 2155} 2156 2157/* 2158 * Parse master section for "Use Case" and "File" tags. 2159 */ 2160static int parse_master_section(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg, 2161 void *data1 ATTRIBUTE_UNUSED, 2162 void *data2 ATTRIBUTE_UNUSED) 2163{ 2164 snd_config_iterator_t i, next; 2165 snd_config_t *n, *variant = NULL; 2166 char *use_case_name, *file = NULL, *comment = NULL; 2167 bool variant_ok = false; 2168 int err; 2169 2170 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { 2171 uc_error("compound type expected for use case section"); 2172 return -EINVAL; 2173 } 2174 2175 err = parse_get_safe_name(uc_mgr, cfg, NULL, &use_case_name); 2176 if (err < 0) { 2177 uc_error("unable to get name for use case section"); 2178 return err; 2179 } 2180 2181 /* in-place evaluation */ 2182 uc_mgr->parse_master_section = 1; 2183 err = uc_mgr_evaluate_inplace(uc_mgr, cfg); 2184 uc_mgr->parse_master_section = 0; 2185 if (err < 0) 2186 goto __error; 2187 2188 /* parse master config sections */ 2189 snd_config_for_each(i, next, cfg) { 2190 const char *id; 2191 n = snd_config_iterator_entry(i); 2192 if (snd_config_get_id(n, &id) < 0) 2193 continue; 2194 2195 /* get use case verb file name */ 2196 if (strcmp(id, "File") == 0) { 2197 err = parse_string_substitute3(uc_mgr, n, &file); 2198 if (err < 0) { 2199 uc_error("failed to get File"); 2200 goto __error; 2201 } 2202 continue; 2203 } 2204 2205 /* get optional use case comment */ 2206 if (strncmp(id, "Comment", 7) == 0) { 2207 err = parse_string_substitute3(uc_mgr, n, &comment); 2208 if (err < 0) { 2209 uc_error("error: failed to get Comment"); 2210 goto __error; 2211 } 2212 continue; 2213 } 2214 2215 if (uc_mgr->conf_format >= 6 && strcmp(id, "Variant") == 0) { 2216 snd_config_iterator_t i2, next2; 2217 variant = n; 2218 snd_config_for_each(i2, next2, n) { 2219 const char *id2; 2220 snd_config_t *n2; 2221 n2 = snd_config_iterator_entry(i2); 2222 if (snd_config_get_id(n2, &id2) < 0) 2223 continue; 2224 err = uc_mgr_evaluate_inplace(uc_mgr, n2); 2225 if (err < 0) 2226 goto __error; 2227 if (strcmp(use_case_name, id2) == 0) 2228 variant_ok = true; 2229 } 2230 continue; 2231 } 2232 2233 uc_error("unknown field '%s' in SectionUseCase", id); 2234 } 2235 2236 if (variant && !variant_ok) { 2237 uc_error("error: undefined variant '%s'", use_case_name); 2238 err = -EINVAL; 2239 goto __error; 2240 } 2241 2242 if (!variant) { 2243 uc_dbg("use_case_name %s file '%s'", use_case_name, file); 2244 2245 /* do we have both use case name and file ? */ 2246 if (!file) { 2247 uc_error("error: use case missing file"); 2248 err = -EINVAL; 2249 goto __error; 2250 } 2251 2252 /* parse verb file */ 2253 err = parse_verb_file(uc_mgr, use_case_name, comment, file); 2254 } else { 2255 /* parse variants */ 2256 snd_config_for_each(i, next, variant) { 2257 char *vfile, *vcomment; 2258 const char *id; 2259 n = snd_config_iterator_entry(i); 2260 if (snd_config_get_id(n, &id) < 0) 2261 continue; 2262 if (!parse_is_name_safe(id)) { 2263 err = -EINVAL; 2264 goto __error; 2265 } 2266 err = parse_variant(uc_mgr, n, &vfile, &vcomment); 2267 if (err < 0) 2268 break; 2269 uc_mgr->parse_variant = id; 2270 err = parse_verb_file(uc_mgr, id, 2271 vcomment ? vcomment : comment, 2272 vfile ? vfile : file); 2273 uc_mgr->parse_variant = NULL; 2274 free(vfile); 2275 free(vcomment); 2276 } 2277 } 2278 2279__error: 2280 free(use_case_name); 2281 free(file); 2282 free(comment); 2283 return err; 2284} 2285 2286/* 2287 * parse controls which should be run only at initial boot (forcefully) 2288 */ 2289static int parse_controls_fixedboot(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg) 2290{ 2291 int err; 2292 2293 if (!list_empty(&uc_mgr->fixedboot_list)) { 2294 uc_error("FixedBoot list is not empty"); 2295 return -EINVAL; 2296 } 2297 err = parse_sequence(uc_mgr, &uc_mgr->fixedboot_list, cfg); 2298 if (err < 0) { 2299 uc_error("Unable to parse FixedBootSequence"); 2300 return err; 2301 } 2302 2303 return 0; 2304} 2305 2306/* 2307 * parse controls which should be run only at initial boot 2308 */ 2309static int parse_controls_boot(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg) 2310{ 2311 int err; 2312 2313 if (!list_empty(&uc_mgr->boot_list)) { 2314 uc_error("Boot list is not empty"); 2315 return -EINVAL; 2316 } 2317 err = parse_sequence(uc_mgr, &uc_mgr->boot_list, cfg); 2318 if (err < 0) { 2319 uc_error("Unable to parse BootSequence"); 2320 return err; 2321 } 2322 2323 return 0; 2324} 2325 2326/* 2327 * parse controls 2328 */ 2329static int parse_controls(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg) 2330{ 2331 int err; 2332 2333 if (!list_empty(&uc_mgr->default_list)) { 2334 uc_error("Default list is not empty"); 2335 return -EINVAL; 2336 } 2337 err = parse_sequence(uc_mgr, &uc_mgr->default_list, cfg); 2338 if (err < 0) { 2339 uc_error("Unable to parse SectionDefaults"); 2340 return err; 2341 } 2342 2343 return 0; 2344} 2345 2346/* 2347 * Each sound card has a master sound card file that lists all the supported 2348 * use case verbs for that sound card. i.e. 2349 * 2350 * #Example master file for blah sound card 2351 * #By Joe Blogs <joe@bloggs.org> 2352 * 2353 * Comment "Nice Abstracted Soundcard" 2354 * 2355 * # The file is divided into Use case sections. One section per use case verb. 2356 * 2357 * SectionUseCase."Voice Call" { 2358 * File "voice_call_blah" 2359 * Comment "Make a voice phone call." 2360 * } 2361 * 2362 * SectionUseCase."HiFi" { 2363 * File "hifi_blah" 2364 * Comment "Play and record HiFi quality Music." 2365 * } 2366 * 2367 * # Define Value defaults 2368 * 2369 * ValueDefaults { 2370 * PlaybackCTL "hw:CARD=0" 2371 * CaptureCTL "hw:CARD=0" 2372 * } 2373 * 2374 * # The initial boot (run once) configuration. 2375 * 2376 * BootSequence [ 2377 * cset "name='Master Playback Switch',index=2 1,1" 2378 * cset "name='Master Playback Volume',index=2 25,25" 2379 * ] 2380 * 2381 * # This file also stores the default sound card state. 2382 * 2383 * SectionDefaults [ 2384 * cset "name='Master Mono Playback',index=1 0" 2385 * cset "name='Master Mono Playback Volume',index=1 0" 2386 * cset "name='PCM Switch',index=2 1,1" 2387 * exec "some binary here" 2388 * msleep 50 2389 * ........ 2390 * ] 2391 * 2392 * # End of example file. 2393 */ 2394static int parse_master_file(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg) 2395{ 2396 snd_config_iterator_t i, next; 2397 snd_config_t *n; 2398 const char *id; 2399 int err; 2400 2401 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { 2402 uc_error("compound type expected for master file"); 2403 return -EINVAL; 2404 } 2405 2406 if (uc_mgr->conf_format >= 2) { 2407 err = parse_syntax_field(uc_mgr, cfg, uc_mgr->conf_file_name); 2408 if (err < 0) 2409 return err; 2410 } 2411 2412 /* in-place evaluation */ 2413 err = uc_mgr_evaluate_inplace(uc_mgr, cfg); 2414 if (err < 0) 2415 return err; 2416 2417 /* parse master config sections */ 2418 snd_config_for_each(i, next, cfg) { 2419 2420 n = snd_config_iterator_entry(i); 2421 if (snd_config_get_id(n, &id) < 0) 2422 continue; 2423 2424 if (strcmp(id, "Comment") == 0) { 2425 err = parse_string_substitute3(uc_mgr, n, &uc_mgr->comment); 2426 if (err < 0) { 2427 uc_error("error: failed to get master comment"); 2428 return err; 2429 } 2430 continue; 2431 } 2432 2433 /* find use case section and parse it */ 2434 if (strcmp(id, "SectionUseCase") == 0) { 2435 err = parse_compound(uc_mgr, n, 2436 parse_master_section, 2437 NULL, NULL); 2438 if (err < 0) 2439 return err; 2440 continue; 2441 } 2442 2443 /* find default control values section (force boot sequence only) */ 2444 if (strcmp(id, "FixedBootSequence") == 0) { 2445 err = parse_controls_fixedboot(uc_mgr, n); 2446 if (err < 0) 2447 return err; 2448 continue; 2449 } 2450 2451 /* find default control values section (first boot only) */ 2452 if (strcmp(id, "BootSequence") == 0) { 2453 err = parse_controls_boot(uc_mgr, n); 2454 if (err < 0) 2455 return err; 2456 continue; 2457 } 2458 2459 /* find default control values section and parse it */ 2460 if (strcmp(id, "SectionDefaults") == 0) { 2461 err = parse_controls(uc_mgr, n); 2462 if (err < 0) 2463 return err; 2464 continue; 2465 } 2466 2467 /* get the default values */ 2468 if (strcmp(id, "ValueDefaults") == 0) { 2469 err = parse_value(uc_mgr, &uc_mgr->value_list, n); 2470 if (err < 0) { 2471 uc_error("error: failed to parse ValueDefaults"); 2472 return err; 2473 } 2474 continue; 2475 } 2476 2477 /* alsa-lib configuration */ 2478 if (uc_mgr->conf_format > 3 && strcmp(id, "LibraryConfig") == 0) { 2479 err = parse_libconfig(uc_mgr, n); 2480 if (err < 0) { 2481 uc_error("error: failed to parse LibraryConfig"); 2482 return err; 2483 } 2484 continue; 2485 } 2486 2487 /* error */ 2488 if (strcmp(id, "Error") == 0) 2489 return error_node(uc_mgr, n); 2490 2491 /* skip further Syntax value updates (Include) */ 2492 if (strcmp(id, "Syntax") == 0) 2493 continue; 2494 2495 uc_error("unknown master file field %s", id); 2496 } 2497 return 0; 2498} 2499 2500/* get the card info */ 2501static int get_card_info(snd_use_case_mgr_t *mgr, 2502 const char *ctl_name, 2503 snd_ctl_card_info_t **info) 2504{ 2505 struct ctl_list *ctl_list; 2506 int err; 2507 2508 err = uc_mgr_open_ctl(mgr, &ctl_list, ctl_name, 0); 2509 if (err < 0) 2510 return err; 2511 2512 if (info) 2513 *info = ctl_list->ctl_info; 2514 return err; 2515} 2516 2517/* find the card in the local machine */ 2518static int get_by_card_name(snd_use_case_mgr_t *mgr, const char *card_name) 2519{ 2520 int card, err; 2521 snd_ctl_card_info_t *info; 2522 const char *_driver, *_name, *_long_name; 2523 2524 snd_ctl_card_info_alloca(&info); 2525 2526 card = -1; 2527 if (snd_card_next(&card) < 0 || card < 0) { 2528 uc_error("no soundcards found..."); 2529 return -1; 2530 } 2531 2532 while (card >= 0) { 2533 char name[32]; 2534 2535 /* clear the list, keep the only one CTL device */ 2536 uc_mgr_free_ctl_list(mgr); 2537 2538 sprintf(name, "hw:%d", card); 2539 err = get_card_info(mgr, name, &info); 2540 2541 if (err == 0) { 2542 _driver = snd_ctl_card_info_get_driver(info); 2543 _name = snd_ctl_card_info_get_name(info); 2544 _long_name = snd_ctl_card_info_get_longname(info); 2545 if (!strcmp(card_name, _driver) || 2546 !strcmp(card_name, _name) || 2547 !strcmp(card_name, _long_name)) 2548 return 0; 2549 } 2550 2551 if (snd_card_next(&card) < 0) { 2552 uc_error("snd_card_next"); 2553 break; 2554 } 2555 } 2556 2557 uc_mgr_free_ctl_list(mgr); 2558 2559 return -1; 2560} 2561 2562/* set the driver name and long name by the card ctl name */ 2563static inline int get_by_card(snd_use_case_mgr_t *mgr, const char *ctl_name) 2564{ 2565 return get_card_info(mgr, ctl_name, NULL); 2566} 2567 2568static int parse_toplevel_path(snd_use_case_mgr_t *uc_mgr, 2569 char *filename, 2570 snd_config_t *cfg) 2571{ 2572 snd_config_iterator_t i, next, i2, next2; 2573 snd_config_t *n, *n2; 2574 const char *id; 2575 char *dir = NULL, *file = NULL, fn[PATH_MAX]; 2576 struct stat64 st; 2577 long version; 2578 int err; 2579 2580 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { 2581 uc_error("compound type expected for UseCasePath node"); 2582 return -EINVAL; 2583 } 2584 2585 /* parse use case path config sections */ 2586 snd_config_for_each(i, next, cfg) { 2587 n = snd_config_iterator_entry(i); 2588 2589 if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) { 2590 uc_error("compound type expected for UseCasePath.something node"); 2591 return -EINVAL; 2592 } 2593 2594 if (snd_config_get_id(n, &id) < 0) 2595 continue; 2596 2597 version = 2; 2598 2599 /* parse use case path config sections */ 2600 snd_config_for_each(i2, next2, n) { 2601 2602 n2 = snd_config_iterator_entry(i2); 2603 if (snd_config_get_id(n2, &id) < 0) 2604 continue; 2605 2606 if (strcmp(id, "Version") == 0) { 2607 err = parse_integer_substitute(uc_mgr, n2, &version); 2608 if (err < 0) { 2609 uc_error("unable to parse UcmDirectory"); 2610 goto __error; 2611 } 2612 if (version < 1 || version > 2) { 2613 uc_error("Version must be 1 or 2"); 2614 err = -EINVAL; 2615 goto __error; 2616 } 2617 continue; 2618 } 2619 2620 if (strcmp(id, "Directory") == 0) { 2621 err = parse_string_substitute(uc_mgr, n2, &dir); 2622 if (err < 0) { 2623 uc_error("unable to parse Directory"); 2624 goto __error; 2625 } 2626 continue; 2627 } 2628 2629 if (strcmp(id, "File") == 0) { 2630 err = parse_string_substitute(uc_mgr, n2, &file); 2631 if (err < 0) { 2632 uc_error("unable to parse File"); 2633 goto __error; 2634 } 2635 continue; 2636 } 2637 2638 uc_error("unknown UseCasePath field %s", id); 2639 } 2640 2641 if (dir == NULL) { 2642 uc_error("Directory is not defined in %s!", filename); 2643 goto __next; 2644 } 2645 if (file == NULL) { 2646 uc_error("File is not defined in %s!", filename); 2647 goto __next; 2648 } 2649 2650 ucm_filename(fn, sizeof(fn), version, dir, file); 2651 if (access(fn, R_OK) == 0 && lstat64(fn, &st) == 0) { 2652 if (S_ISLNK(st.st_mode)) { 2653 ssize_t r; 2654 char *link, *dir2, *p; 2655 2656 link = malloc(PATH_MAX); 2657 if (link == NULL) 2658 goto __enomem; 2659 r = readlink(fn, link, PATH_MAX - 1); 2660 if (r <= 0) { 2661 free(link); 2662 goto __next; 2663 } 2664 link[r] = '\0'; 2665 p = strrchr(link, '/'); 2666 if (p) { 2667 *p = '\0'; 2668 dir2 = malloc(PATH_MAX); 2669 if (dir2 == NULL) { 2670 free(link); 2671 goto __enomem; 2672 } 2673 strncpy(dir2, dir, PATH_MAX - 1); 2674 strncat(dir2, "/", PATH_MAX - 1); 2675 strncat(dir2, link, PATH_MAX - 1); 2676 fn[PATH_MAX - 1] = '\0'; 2677 free(dir); 2678 dir = dir2; 2679 } 2680 free(link); 2681 } 2682 if (replace_string(&uc_mgr->conf_dir_name, dir) == NULL) 2683 goto __enomem; 2684 if (replace_string(&uc_mgr->conf_file_name, file) == NULL) 2685 goto __enomem; 2686 strncpy(filename, fn, PATH_MAX); 2687 filename[PATH_MAX - 1] = '\0'; 2688 uc_mgr->conf_format = version; 2689 goto __ok; 2690 } 2691 2692__next: 2693 free(file); 2694 if (dir != fn) 2695 free(dir); 2696 dir = NULL; 2697 file = NULL; 2698 } 2699 2700 err = -ENOENT; 2701 goto __error; 2702 2703__enomem: 2704 err = -ENOMEM; 2705 goto __error; 2706 2707__ok: 2708 err = 0; 2709__error: 2710 free(file); 2711 if (dir != fn) 2712 free(dir); 2713 return err; 2714} 2715 2716static int parse_toplevel_config(snd_use_case_mgr_t *uc_mgr, 2717 char *filename, 2718 snd_config_t *cfg) 2719{ 2720 snd_config_iterator_t i, next; 2721 snd_config_t *n; 2722 const char *id; 2723 int err; 2724 2725 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { 2726 uc_error("compound type expected for toplevel file"); 2727 return -EINVAL; 2728 } 2729 2730 err = parse_syntax_field(uc_mgr, cfg, filename); 2731 if (err < 0) 2732 return err; 2733 2734 /* in-place evaluation */ 2735 err = uc_mgr_evaluate_inplace(uc_mgr, cfg); 2736 if (err < 0) 2737 return err; 2738 2739 /* parse toplevel config sections */ 2740 snd_config_for_each(i, next, cfg) { 2741 2742 n = snd_config_iterator_entry(i); 2743 if (snd_config_get_id(n, &id) < 0) 2744 continue; 2745 2746 if (strcmp(id, "UseCasePath") == 0) { 2747 err = parse_toplevel_path(uc_mgr, filename, n); 2748 if (err == 0) 2749 return err; 2750 continue; 2751 } 2752 2753 /* alsa-lib configuration */ 2754 if (uc_mgr->conf_format > 3 && strcmp(id, "LibraryConfig") == 0) { 2755 err = parse_libconfig(uc_mgr, n); 2756 if (err < 0) { 2757 uc_error("error: failed to parse LibConfig"); 2758 return err; 2759 } 2760 continue; 2761 } 2762 2763 /* skip further Syntax value updates (Include) */ 2764 if (strcmp(id, "Syntax") == 0) 2765 continue; 2766 2767 uc_error("unknown toplevel field %s", id); 2768 } 2769 2770 return -ENOENT; 2771} 2772 2773static int load_toplevel_config(snd_use_case_mgr_t *uc_mgr, 2774 snd_config_t **cfg) 2775{ 2776 char filename[PATH_MAX]; 2777 snd_config_t *tcfg; 2778 int err; 2779 2780 ucm_filename(filename, sizeof(filename), 2, NULL, "ucm.conf"); 2781 2782 if (access(filename, R_OK) != 0) { 2783 uc_error("Unable to find the top-level configuration file '%s'.", filename); 2784 return -ENOENT; 2785 } 2786 2787 err = uc_mgr_config_load(2, filename, &tcfg); 2788 if (err < 0) 2789 goto __error; 2790 2791 /* filename is shared for function input and output! */ 2792 err = parse_toplevel_config(uc_mgr, filename, tcfg); 2793 snd_config_delete(tcfg); 2794 if (err < 0) 2795 goto __error; 2796 2797 err = uc_mgr_config_load(uc_mgr->conf_format, filename, cfg); 2798 if (err < 0) { 2799 uc_error("error: could not parse configuration for card %s", 2800 uc_mgr->card_name); 2801 goto __error; 2802 } 2803 2804 return 0; 2805 2806__error: 2807 return err; 2808} 2809 2810/* load master use case file for sound card based on rules in ucm2/ucm.conf 2811 */ 2812int uc_mgr_import_master_config(snd_use_case_mgr_t *uc_mgr) 2813{ 2814 snd_config_t *cfg; 2815 const char *name; 2816 int err; 2817 2818 err = snd_config_top(&uc_mgr->local_config); 2819 if (err < 0) 2820 return err; 2821 2822 err = snd_config_top(&uc_mgr->macros); 2823 if (err < 0) 2824 return err; 2825 2826 name = uc_mgr->card_name; 2827 if (strncmp(name, "hw:", 3) == 0) { 2828 err = get_by_card(uc_mgr, name); 2829 if (err < 0) { 2830 uc_error("card '%s' is not valid", name); 2831 goto __error; 2832 } 2833 } else if (strncmp(name, "strict:", 7)) { 2834 /* do not handle the error here */ 2835 /* we can refer the virtual UCM config */ 2836 get_by_card_name(uc_mgr, name); 2837 } 2838 2839 err = load_toplevel_config(uc_mgr, &cfg); 2840 if (err < 0) 2841 goto __error; 2842 2843 err = parse_master_file(uc_mgr, cfg); 2844 if (uc_mgr->macros) { 2845 snd_config_delete(uc_mgr->macros); 2846 uc_mgr->macros = NULL; 2847 } 2848 snd_config_delete(cfg); 2849 if (err < 0) { 2850 uc_mgr_free_ctl_list(uc_mgr); 2851 uc_mgr_free_verb(uc_mgr); 2852 } 2853 2854 return err; 2855 2856__error: 2857 uc_mgr_free_ctl_list(uc_mgr); 2858 replace_string(&uc_mgr->conf_dir_name, NULL); 2859 return err; 2860} 2861 2862static int filename_filter(const struct dirent64 *dirent) 2863{ 2864 if (dirent == NULL) 2865 return 0; 2866 if (dirent->d_type == DT_DIR) { 2867 if (dirent->d_name[0] == '.') { 2868 if (dirent->d_name[1] == '\0') 2869 return 0; 2870 if (dirent->d_name[1] == '.' && 2871 dirent->d_name[2] == '\0') 2872 return 0; 2873 } 2874 return 1; 2875 } 2876 return 0; 2877} 2878 2879/* scan all cards and comments 2880 * 2881 * Cards are defined by machines. Each card/machine installs its UCM 2882 * configuration files in a subdirectory with the same name as the sound 2883 * card under /usr/share/alsa/ucm2. This function will scan all the card 2884 * directories and skip the component directories defined in the array 2885 * component_dir. 2886 */ 2887int uc_mgr_scan_master_configs(const char **_list[]) 2888{ 2889 char filename[PATH_MAX], dfl[PATH_MAX], fn[FILENAME_MAX]; 2890 char *env = getenv(ALSA_CONFIG_UCM2_VAR); 2891 snd_use_case_mgr_t *uc_mgr; 2892 const char **list, *d_name; 2893 char *s; 2894 snd_config_t *cfg, *c; 2895 int i, j, cnt, err, cards; 2896 long l; 2897 ssize_t ss; 2898 struct dirent64 **namelist; 2899 2900 i = -1; 2901 cards = 0; 2902 while (1) { 2903 err = snd_card_next(&i); 2904 if (err < 0) 2905 return err; 2906 if (i < 0) 2907 break; 2908 cards++; 2909 } 2910 cards += 4; /* plug-and-play */ 2911 2912 if (env) 2913 snprintf(filename, sizeof(filename), "%s/conf.virt.d", env); 2914 else 2915 snprintf(filename, sizeof(filename), "%s/ucm2/conf.virt.d", 2916 snd_config_topdir()); 2917 2918#if defined(_GNU_SOURCE) && !defined(__NetBSD__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__) && !defined(__sun) && !defined(__ANDROID__) 2919#define SORTFUNC versionsort64 2920#else 2921#define SORTFUNC alphasort64 2922#endif 2923 err = scandir64(filename, &namelist, filename_filter, SORTFUNC); 2924 if (err < 0) { 2925 err = -errno; 2926 uc_error("error: could not scan directory %s: %s", 2927 filename, strerror(-err)); 2928 return err; 2929 } 2930 cnt = err; 2931 2932 dfl[0] = '\0'; 2933 if (strlen(filename) + 8 < sizeof(filename)) { 2934 strcat(filename, "/default"); 2935 ss = readlink(filename, dfl, sizeof(dfl)-1); 2936 if (ss >= 0) { 2937 dfl[ss] = '\0'; 2938 dfl[sizeof(dfl)-1] = '\0'; 2939 if (dfl[0] && dfl[strlen(dfl)-1] == '/') 2940 dfl[strlen(dfl)-1] = '\0'; 2941 } else { 2942 dfl[0] = '\0'; 2943 } 2944 } 2945 2946 j = 0; 2947 list = calloc(1, (cards + cnt) * 2 * sizeof(char *)); 2948 if (list == NULL) { 2949 err = -ENOMEM; 2950 goto __err; 2951 } 2952 2953 i = -1; 2954 while (j / 2 < cards) { 2955 err = snd_card_next(&i); 2956 if (err < 0) 2957 goto __err; 2958 if (i < 0) 2959 break; 2960 snprintf(fn, sizeof(fn), "-hw:%d", i); 2961 err = snd_use_case_mgr_open(&uc_mgr, fn); 2962 if (err == -ENOENT || err == -ENXIO) 2963 continue; 2964 if (err < 0) { 2965 uc_error("Unable to open '%s': %s", fn, snd_strerror(err)); 2966 goto __err; 2967 } 2968 err = snd_use_case_get(uc_mgr, "comment", (const char **)&s); 2969 if (err < 0) { 2970 err = snd_card_get_longname(i, &s); 2971 if (err < 0) 2972 goto __err; 2973 } 2974 snd_use_case_mgr_close(uc_mgr); 2975 list[j] = strdup(fn + 1); 2976 if (list[j] == NULL) { 2977 free(s); 2978 err = -ENOMEM; 2979 goto __err; 2980 } 2981 list[j + 1] = s; 2982 j += 2; 2983 } 2984 2985 for (i = 0; i < cnt; i++) { 2986 2987 d_name = namelist[i]->d_name; 2988 2989 snprintf(fn, sizeof(fn), "%s.conf", d_name); 2990 ucm_filename(filename, sizeof(filename), 2, d_name, fn); 2991#ifdef HAVE_EACCESS 2992 if (eaccess(filename, R_OK)) 2993#else 2994 if (access(filename, R_OK)) 2995#endif 2996 continue; 2997 2998 err = uc_mgr_config_load(2, filename, &cfg); 2999 if (err < 0) 3000 goto __err; 3001 err = snd_config_search(cfg, "Syntax", &c); 3002 if (err < 0) { 3003 uc_error("Syntax field not found in %s", d_name); 3004 snd_config_delete(cfg); 3005 continue; 3006 } 3007 err = snd_config_get_integer(c, &l); 3008 if (err < 0) { 3009 uc_error("Syntax field is invalid in %s", d_name); 3010 snd_config_delete(cfg); 3011 goto __err; 3012 } 3013 if (l < 2 || l > SYNTAX_VERSION_MAX) { 3014 uc_error("Incompatible syntax %d in %s", l, d_name); 3015 snd_config_delete(cfg); 3016 goto __err; 3017 } 3018 err = snd_config_search(cfg, "Comment", &c); 3019 if (err >= 0) { 3020 err = parse_string(c, (char **)&list[j+1]); 3021 if (err < 0) { 3022 snd_config_delete(cfg); 3023 goto __err; 3024 } 3025 } 3026 snd_config_delete(cfg); 3027 list[j] = strdup(d_name); 3028 if (list[j] == NULL) { 3029 err = -ENOMEM; 3030 goto __err; 3031 } 3032 if (strcmp(dfl, list[j]) == 0) { 3033 /* default to top */ 3034 const char *save1 = list[j]; 3035 const char *save2 = list[j + 1]; 3036 memmove(list + 2, list, j * sizeof(char *)); 3037 list[0] = save1; 3038 list[1] = save2; 3039 } 3040 j += 2; 3041 } 3042 err = 0; 3043 3044 __err: 3045 for (i = 0; i < cnt; i++) 3046 free(namelist[i]); 3047 free(namelist); 3048 if (err < 0) { 3049 for (i = 0; i < j; i++) { 3050 free((void *)list[i * 2]); 3051 free((void *)list[i * 2 + 1]); 3052 } 3053 free(list); 3054 return err; 3055 } 3056 3057 *_list = list; 3058 return j; 3059} 3060