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 "../control/control_local.h" 35#include <stdbool.h> 36#include <ctype.h> 37#include <stdarg.h> 38#include <pthread.h> 39#include <sys/stat.h> 40#include <sys/wait.h> 41#include <limits.h> 42 43/* 44 * misc 45 */ 46 47static int get_value(snd_use_case_mgr_t *uc_mgr, 48 const char *identifier, 49 char **value, 50 const char *mod_dev_name, 51 const char *verb_name, 52 int exact); 53static int get_value1(snd_use_case_mgr_t *uc_mgr, char **value, 54 struct list_head *value_list, const char *identifier); 55static int get_value3(snd_use_case_mgr_t *uc_mgr, 56 char **value, 57 const char *identifier, 58 struct list_head *value_list1, 59 struct list_head *value_list2, 60 struct list_head *value_list3); 61 62static int execute_sequence(snd_use_case_mgr_t *uc_mgr, 63 struct use_case_verb *verb, 64 struct list_head *seq, 65 struct list_head *value_list1, 66 struct list_head *value_list2, 67 struct list_head *value_list3); 68 69static int execute_component_seq(snd_use_case_mgr_t *uc_mgr, 70 struct component_sequence *cmpt_seq, 71 struct list_head *value_list1, 72 struct list_head *value_list2, 73 struct list_head *value_list3, 74 char *cdev); 75 76static inline struct use_case_device * 77 find_device(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb, 78 const char *device_name, int check_supported); 79 80static int check_identifier(const char *identifier, const char *prefix) 81{ 82 int len; 83 84 len = strlen(prefix); 85 if (strncmp(identifier, prefix, len) != 0) 86 return 0; 87 88 if (identifier[len] == 0 || identifier[len] == '/') 89 return 1; 90 91 return 0; 92} 93 94static int list_count(struct list_head *list) 95{ 96 struct list_head *pos; 97 int count = 0; 98 99 list_for_each(pos, list) { 100 count += 1; 101 } 102 return count; 103} 104 105static int alloc_str_list(struct list_head *list, int mult, char **result[]) 106{ 107 char **res; 108 int cnt; 109 110 cnt = list_count(list) * mult; 111 if (cnt == 0) { 112 *result = NULL; 113 return cnt; 114 } 115 res = calloc(mult, cnt * sizeof(char *)); 116 if (res == NULL) 117 return -ENOMEM; 118 *result = res; 119 return cnt; 120} 121 122/** 123 * \brief Create an identifier 124 * \param fmt Format (sprintf like) 125 * \param ... Optional arguments for sprintf like format 126 * \return Allocated string identifier or NULL on error 127 */ 128char *snd_use_case_identifier(const char *fmt, ...) 129{ 130 char *str, *res; 131 int size = strlen(fmt) + 512; 132 va_list args; 133 134 str = malloc(size); 135 if (str == NULL) 136 return NULL; 137 va_start(args, fmt); 138 vsnprintf(str, size, fmt, args); 139 va_end(args); 140 str[size-1] = '\0'; 141 res = realloc(str, strlen(str) + 1); 142 if (res) 143 return res; 144 return str; 145} 146 147/** 148 * \brief Free a string list 149 * \param list The string list to free 150 * \param items Count of strings 151 * \return Zero if success, otherwise a negative error code 152 */ 153int snd_use_case_free_list(const char *list[], int items) 154{ 155 int i; 156 if (list == NULL) 157 return 0; 158 for (i = 0; i < items; i++) 159 free((void *)list[i]); 160 free(list); 161 return 0; 162} 163 164static int read_tlv_file(unsigned int **res, 165 const char *filepath) 166{ 167 int err = 0; 168 int fd; 169 struct stat64 st; 170 size_t sz; 171 ssize_t sz_read; 172 struct snd_ctl_tlv *tlv; 173 174 fd = open(filepath, O_RDONLY); 175 if (fd < 0) { 176 err = -errno; 177 return err; 178 } 179 if (fstat64(fd, &st) == -1) { 180 err = -errno; 181 goto __fail; 182 } 183 sz = st.st_size; 184 if (sz > 16 * 1024 * 1024 || sz < 8 || sz % 4) { 185 uc_error("File size should be less than 16 MB " 186 "and multiple of 4"); 187 err = -EINVAL; 188 goto __fail; 189 } 190 *res = malloc(sz); 191 if (res == NULL) { 192 err = -ENOMEM; 193 goto __fail; 194 } 195 sz_read = read(fd, *res, sz); 196 if (sz_read < 0 || (size_t)sz_read != sz) { 197 err = -EIO; 198 free(*res); 199 *res = NULL; 200 } 201 /* Check if the tlv file specifies valid size. */ 202 tlv = (struct snd_ctl_tlv *)(*res); 203 if (tlv->length + 2 * sizeof(unsigned int) != sz) { 204 uc_error("Invalid tlv size: %d", tlv->length); 205 err = -EINVAL; 206 free(*res); 207 *res = NULL; 208 } 209 210__fail: 211 close(fd); 212 return err; 213} 214 215static int binary_file_parse(snd_ctl_elem_value_t *dst, 216 snd_ctl_elem_info_t *info, 217 const char *filepath) 218{ 219 int err = 0; 220 int fd; 221 struct stat64 st; 222 size_t sz; 223 ssize_t sz_read; 224 char *res; 225 snd_ctl_elem_type_t type; 226 unsigned int idx, count; 227 228 type = snd_ctl_elem_info_get_type(info); 229 if (type != SND_CTL_ELEM_TYPE_BYTES) { 230 uc_error("only support byte type!"); 231 err = -EINVAL; 232 return err; 233 } 234 fd = open(filepath, O_RDONLY); 235 if (fd < 0) { 236 err = -errno; 237 return err; 238 } 239 if (stat64(filepath, &st) == -1) { 240 err = -errno; 241 goto __fail; 242 } 243 sz = st.st_size; 244 count = snd_ctl_elem_info_get_count(info); 245 if (sz != count || sz > sizeof(dst->value.bytes)) { 246 uc_error("invalid parameter size %d!", sz); 247 err = -EINVAL; 248 goto __fail; 249 } 250 res = malloc(sz); 251 if (res == NULL) { 252 err = -ENOMEM; 253 goto __fail; 254 } 255 sz_read = read(fd, res, sz); 256 if (sz_read < 0 || (size_t)sz_read != sz) { 257 err = -errno; 258 goto __fail_read; 259 } 260 for (idx = 0; idx < sz; idx++) 261 snd_ctl_elem_value_set_byte(dst, idx, *(res + idx)); 262 __fail_read: 263 free(res); 264 __fail: 265 close(fd); 266 return err; 267} 268 269static const char *parse_type(const char *p, const char *prefix, size_t len, 270 snd_ctl_elem_info_t *info) 271{ 272 if (strncasecmp(p, prefix, len)) 273 return p; 274 p += len; 275 if (info->type != SND_CTL_ELEM_TYPE_NONE) 276 return NULL; 277 if (strncasecmp(p, "bool", sizeof("bool") - 1) == 0) 278 info->type = SND_CTL_ELEM_TYPE_BOOLEAN; 279 else if (strncasecmp(p, "integer64", sizeof("integer64") - 1) == 0) 280 info->type = SND_CTL_ELEM_TYPE_INTEGER64; 281 else if (strncasecmp(p, "int64", sizeof("int64") - 1) == 0) 282 info->type = SND_CTL_ELEM_TYPE_INTEGER64; 283 else if (strncasecmp(p, "int", sizeof("int") - 1) == 0) 284 info->type = SND_CTL_ELEM_TYPE_INTEGER; 285 else if (strncasecmp(p, "enum", sizeof("enum") - 1) == 0) 286 info->type = SND_CTL_ELEM_TYPE_ENUMERATED; 287 else if (strncasecmp(p, "bytes", sizeof("bytes") - 1) == 0) 288 info->type = SND_CTL_ELEM_TYPE_BYTES; 289 else 290 return NULL; 291 while (isalpha(*p)) 292 p++; 293 return p; 294} 295 296static const char *parse_uint(const char *p, const char *prefix, size_t len, 297 unsigned int min, unsigned int max, unsigned int *rval) 298{ 299 long v; 300 char *end; 301 302 if (strncasecmp(p, prefix, len)) 303 return p; 304 p += len; 305 v = strtol(p, &end, 0); 306 if (*end != '\0' && *end != ' ' && *end != ',') { 307 uc_error("unable to parse '%s'", prefix); 308 return NULL; 309 } 310 if ((unsigned int)v < min || (unsigned int)v > max) { 311 uc_error("value '%s' out of range %u-%u %(%ld)", min, max, v); 312 return NULL; 313 } 314 *rval = v; 315 return end; 316} 317 318static const char *parse_labels(const char *p, const char *prefix, size_t len, 319 snd_ctl_elem_info_t *info) 320{ 321 const char *s; 322 char *buf, *bp; 323 size_t l; 324 int c; 325 326 if (info->type != SND_CTL_ELEM_TYPE_ENUMERATED) 327 return NULL; 328 if (strncasecmp(p, prefix, len)) 329 return p; 330 p += len; 331 s = p; 332 c = *s; 333 l = 0; 334 if (c == '\'' || c == '\"') { 335 s++; 336 while (*s && *s != c) { 337 s++, l++; 338 } 339 if (*s == c) 340 s++; 341 } else { 342 while (*s && *s != ',') 343 l++; 344 } 345 if (l == 0) 346 return NULL; 347 buf = malloc(l + 1); 348 if (buf == NULL) 349 return NULL; 350 memcpy(buf, p + ((c == '\'' || c == '\"') ? 1 : 0), l); 351 buf[l] = '\0'; 352 info->value.enumerated.items = 1; 353 for (bp = buf; *bp; bp++) { 354 if (*bp == ';') { 355 if (bp == buf || bp[1] == ';') { 356 free(buf); 357 return NULL; 358 } 359 info->value.enumerated.items++; 360 *bp = '\0'; 361 } 362 } 363 info->value.enumerated.names_ptr = (uintptr_t)buf; 364 info->value.enumerated.names_length = l + 1; 365 return s; 366} 367 368static int parse_cset_new_info(snd_ctl_elem_info_t *info, const char *s, const char **pos) 369{ 370 const char *p = s, *op; 371 372 info->count = 1; 373 while (*s) { 374 op = p; 375 p = parse_type(p, "type=", sizeof("type=") - 1, info); 376 if (p != op) 377 goto next; 378 p = parse_uint(p, "elements=", sizeof("elements=") - 1, 1, 128, (unsigned int *)&info->owner); 379 if (p != op) 380 goto next; 381 p = parse_uint(p, "count=", sizeof("count=") - 1, 1, 128, &info->count); 382 if (p != op) 383 goto next; 384 p = parse_labels(p, "labels=", sizeof("labels=") - 1, info); 385next: 386 if (p == NULL) 387 goto er; 388 if (*p == ',') 389 p++; 390 if (isspace(*p)) 391 break; 392 if (op == p) 393 goto er; 394 } 395 *pos = p; 396 return 0; 397er: 398 uc_error("unknown syntax '%s'", p); 399 return -EINVAL; 400} 401 402static int execute_cset(snd_ctl_t *ctl, const char *cset, unsigned int type) 403{ 404 const char *pos; 405 int err; 406 snd_ctl_elem_id_t *id; 407 snd_ctl_elem_value_t *value; 408 snd_ctl_elem_info_t *info, *info2 = NULL; 409 unsigned int *res = NULL; 410 411 snd_ctl_elem_id_malloc(&id); 412 snd_ctl_elem_value_malloc(&value); 413 snd_ctl_elem_info_malloc(&info); 414 415 err = __snd_ctl_ascii_elem_id_parse(id, cset, &pos); 416 if (err < 0) 417 goto __fail; 418 while (*pos && isspace(*pos)) 419 pos++; 420 if (type == SEQUENCE_ELEMENT_TYPE_CSET_NEW) { 421 snd_ctl_elem_info_malloc(&info2); 422 snd_ctl_elem_info_set_id(info2, id); 423 err = parse_cset_new_info(info2, pos, &pos); 424 if (err < 0 || !*pos) { 425 uc_error("undefined or wrong id config for cset-new", cset); 426 err = -EINVAL; 427 goto __fail; 428 } 429 while (*pos && isspace(*pos)) 430 pos++; 431 } 432 if (!*pos) { 433 if (type != SEQUENCE_ELEMENT_TYPE_CTL_REMOVE) { 434 uc_error("undefined value for cset >%s<", cset); 435 err = -EINVAL; 436 goto __fail; 437 } 438 } else if (type == SEQUENCE_ELEMENT_TYPE_CTL_REMOVE) { 439 uc_error("extra value for ctl-remove >%s<", cset); 440 err = -EINVAL; 441 goto __fail; 442 } 443 444 snd_ctl_elem_info_set_id(info, id); 445 err = snd_ctl_elem_info(ctl, info); 446 if (type == SEQUENCE_ELEMENT_TYPE_CSET_NEW || 447 type == SEQUENCE_ELEMENT_TYPE_CTL_REMOVE) { 448 if (err >= 0) { 449 err = snd_ctl_elem_remove(ctl, id); 450 if (err < 0) { 451 uc_error("unable to remove control"); 452 err = -EINVAL; 453 goto __fail; 454 } 455 } 456 if (type == SEQUENCE_ELEMENT_TYPE_CTL_REMOVE) 457 goto __ok; 458 err = __snd_ctl_add_elem_set(ctl, info2, info2->owner, info2->count); 459 if (err < 0) { 460 uc_error("unable to create new control"); 461 goto __fail; 462 } 463 /* new id copy */ 464 snd_ctl_elem_info_get_id(info2, id); 465 snd_ctl_elem_info_set_id(info, id); 466 } else if (err < 0) 467 goto __fail; 468 if (type == SEQUENCE_ELEMENT_TYPE_CSET_TLV) { 469 if (!snd_ctl_elem_info_is_tlv_writable(info)) { 470 err = -EINVAL; 471 goto __fail; 472 } 473 err = read_tlv_file(&res, pos); 474 if (err < 0) 475 goto __fail; 476 err = snd_ctl_elem_tlv_write(ctl, id, res); 477 if (err < 0) 478 goto __fail; 479 } else { 480 snd_ctl_elem_value_set_id(value, id); 481 err = snd_ctl_elem_read(ctl, value); 482 if (err < 0) 483 goto __fail; 484 if (type == SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE) 485 err = binary_file_parse(value, info, pos); 486 else 487 err = snd_ctl_ascii_value_parse(ctl, value, info, pos); 488 if (err < 0) 489 goto __fail; 490 err = snd_ctl_elem_write(ctl, value); 491 if (err < 0) 492 goto __fail; 493 if (type == SEQUENCE_ELEMENT_TYPE_CSET_NEW) { 494 unsigned int idx; 495 for (idx = 1; idx < (unsigned int)info2->owner; idx++) { 496 value->id.numid += 1; 497 err = snd_ctl_elem_write(ctl, value); 498 if (err < 0) 499 goto __fail; 500 } 501 } 502 } 503 __ok: 504 err = 0; 505 __fail: 506 free(id); 507 free(value); 508 if (info2) { 509 if (info2->type == SND_CTL_ELEM_TYPE_ENUMERATED) 510 free((void *)(size_t)info2->value.enumerated.names_ptr); 511 free(info2); 512 } 513 free(info); 514 free(res); 515 516 return err; 517} 518 519static int execute_sysw(const char *sysw) 520{ 521 char path[PATH_MAX]; 522 const char *e; 523 char *s, *value; 524 ssize_t wlen; 525 size_t len; 526 int fd, myerrno; 527 bool ignore_error = false; 528 529 if (sysw == NULL || *sysw == '\0') 530 return 0; 531 532 if (sysw[0] == '-') { 533 ignore_error = true; 534 sysw++; 535 } 536 537 if (sysw[0] == ':') 538 return -EINVAL; 539 540 s = strdup(sysw[0] != '/' ? sysw : sysw + 1); 541 if (s == NULL) 542 return -ENOMEM; 543 544 value = strchr(s, ':'); 545 if (!value) { 546 free(s); 547 return -EINVAL; 548 } 549 *value = '\0'; 550 value++; 551 len = strlen(value); 552 if (len < 1) { 553 free(s); 554 return -EINVAL; 555 } 556 557 e = uc_mgr_sysfs_root(); 558 if (e == NULL) { 559 free(s); 560 return -EINVAL; 561 } 562 snprintf(path, sizeof(path), "%s/%s", e, s); 563 564 fd = open(path, O_WRONLY|O_CLOEXEC); 565 if (fd < 0) { 566 free(s); 567 if (ignore_error) 568 return 0; 569 uc_error("unable to open '%s' for write", path); 570 return -EINVAL; 571 } 572 wlen = write(fd, value, len); 573 myerrno = errno; 574 close(fd); 575 576 if (ignore_error) 577 goto __end; 578 579 if (wlen != (ssize_t)len) { 580 uc_error("unable to write '%s' to '%s': %s", value, path, strerror(myerrno)); 581 free(s); 582 return -EINVAL; 583 } 584 585__end: 586 free(s); 587 return 0; 588} 589 590int _snd_config_save_node_value(snd_config_t *n, snd_output_t *out, unsigned int level); 591 592static int execute_cfgsave(snd_use_case_mgr_t *uc_mgr, const char *filename) 593{ 594 snd_config_t *config = uc_mgr->local_config; 595 char *file, *root; 596 snd_output_t *out; 597 bool with_root = false; 598 int err = 0; 599 600 file = strdup(filename); 601 if (!file) 602 return -ENOMEM; 603 root = strchr(file, ':'); 604 if (config && root) { 605 *root++ = '\0'; 606 if (*root == '+') { 607 with_root = true; 608 root++; 609 } 610 err = snd_config_search(config, root, &config); 611 if (err < 0) { 612 uc_error("Unable to find subtree '%s'", root); 613 goto _err; 614 } 615 } 616 617 err = snd_output_stdio_open(&out, file, "w+"); 618 if (err < 0) { 619 uc_error("unable to open file '%s': %s", file, snd_strerror(err)); 620 goto _err; 621 } 622 if (!config || snd_config_is_empty(config)) { 623 snd_output_close(out); 624 goto _err; 625 } 626 if (with_root) { 627 snd_output_printf(out, "%s ", root); 628 err = _snd_config_save_node_value(config, out, 0); 629 } else { 630 err = snd_config_save(config, out); 631 } 632 snd_output_close(out); 633 if (err < 0) { 634 uc_error("unable to save configuration: %s", snd_strerror(err)); 635 goto _err; 636 } 637_err: 638 free(file); 639 return err; 640} 641 642static int rewrite_device_value(snd_use_case_mgr_t *uc_mgr, const char *name, char **value) 643{ 644 char *sval; 645 size_t l; 646 static const char **s, *_prefix[] = { 647 "PlaybackCTL", 648 "CaptureCTL", 649 "PlaybackMixer", 650 "CaptureMixer", 651 "PlaybackPCM", 652 "CapturePCM", 653 NULL 654 }; 655 656 if (!uc_mgr_has_local_config(uc_mgr)) 657 return 0; 658 for (s = _prefix; *s && *value; s++) { 659 if (strcmp(*s, name) != 0) 660 continue; 661 l = strlen(*value) + 9 + 1; 662 sval = malloc(l); 663 if (sval == NULL) { 664 free(*value); 665 *value = NULL; 666 return -ENOMEM; 667 } 668 snprintf(sval, l, "_ucm%04X.%s", uc_mgr->ucm_card_number, *value); 669 free(*value); 670 *value = sval; 671 break; 672 } 673 return 0; 674} 675 676static int run_device_sequence(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb, 677 const char *name, bool enable) 678{ 679 struct use_case_device *device; 680 681 if (verb == NULL) { 682 uc_error("error: enadev2 / disdev2 must be executed inside the verb context"); 683 return -ENOENT; 684 } 685 686 device = find_device(uc_mgr, verb, name, 0); 687 if (device == NULL) { 688 uc_error("error: unable to find device '%s'\n", name); 689 return -ENOENT; 690 } 691 692 return execute_sequence(uc_mgr, verb, 693 enable ? &device->enable_list : &device->disable_list, 694 &device->value_list, 695 &verb->value_list, 696 &uc_mgr->value_list); 697} 698 699static int run_device_all_sequence(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb) 700{ 701 struct use_case_device *device; 702 struct list_head *pos; 703 int err; 704 705 if (verb == NULL) { 706 uc_error("error: disdevall must be executed inside the verb context"); 707 return -ENOENT; 708 } 709 710 list_for_each(pos, &verb->device_list) { 711 device = list_entry(pos, struct use_case_device, list); 712 713 err = execute_sequence(uc_mgr, verb, 714 &device->disable_list, 715 &device->value_list, 716 &verb->value_list, 717 &uc_mgr->value_list); 718 if (err < 0) 719 return err; 720 } 721 return 0; 722} 723 724/** 725 * \brief Execute the sequence 726 * \param uc_mgr Use case manager 727 * \param seq Sequence 728 * \return zero on success, otherwise a negative error code 729 */ 730static int execute_sequence(snd_use_case_mgr_t *uc_mgr, 731 struct use_case_verb *verb, 732 struct list_head *seq, 733 struct list_head *value_list1, 734 struct list_head *value_list2, 735 struct list_head *value_list3) 736{ 737 struct list_head *pos; 738 struct sequence_element *s; 739 char *cdev = NULL; 740 snd_ctl_t *ctl = NULL; 741 struct ctl_list *ctl_list; 742 bool ignore_error; 743 int err = 0; 744 745 if (uc_mgr->sequence_hops > 100) { 746 uc_error("error: too many inner sequences!"); 747 return -EINVAL; 748 } 749 uc_mgr->sequence_hops++; 750 list_for_each(pos, seq) { 751 s = list_entry(pos, struct sequence_element, list); 752 switch (s->type) { 753 case SEQUENCE_ELEMENT_TYPE_CDEV: 754 cdev = strdup(s->data.cdev); 755 if (cdev == NULL) 756 goto __fail_nomem; 757 if (rewrite_device_value(uc_mgr, "PlaybackCTL", &cdev)) 758 goto __fail_nomem; 759 break; 760 case SEQUENCE_ELEMENT_TYPE_CSET: 761 case SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE: 762 case SEQUENCE_ELEMENT_TYPE_CSET_TLV: 763 case SEQUENCE_ELEMENT_TYPE_CSET_NEW: 764 case SEQUENCE_ELEMENT_TYPE_CTL_REMOVE: 765 if (cdev == NULL && uc_mgr->in_component_domain) { 766 /* For sequence of a component device, use 767 * its parent's cdev stored by ucm manager. 768 */ 769 if (uc_mgr->cdev == NULL) { 770 uc_error("cdev is not defined!"); 771 return err; 772 } 773 774 cdev = strndup(uc_mgr->cdev, PATH_MAX); 775 if (!cdev) 776 return -ENOMEM; 777 } else if (cdev == NULL) { 778 char *playback_ctl = NULL; 779 char *capture_ctl = NULL; 780 781 err = get_value3(uc_mgr, &playback_ctl, "PlaybackCTL", 782 value_list1, 783 value_list2, 784 value_list3); 785 if (err < 0 && err != -ENOENT) { 786 uc_error("cdev is not defined!"); 787 return err; 788 } 789 err = get_value3(uc_mgr, &capture_ctl, "CaptureCTL", 790 value_list1, 791 value_list2, 792 value_list3); 793 if (err < 0 && err != -ENOENT) { 794 free(playback_ctl); 795 uc_error("cdev is not defined!"); 796 return err; 797 } 798 if (playback_ctl == NULL && 799 capture_ctl == NULL) { 800 uc_error("cdev is not defined!"); 801 return -EINVAL; 802 } 803 if (playback_ctl != NULL && 804 capture_ctl != NULL && 805 strcmp(playback_ctl, capture_ctl) != 0) { 806 free(playback_ctl); 807 free(capture_ctl); 808 uc_error("cdev is not equal for playback and capture!"); 809 return -EINVAL; 810 } 811 if (playback_ctl != NULL) { 812 cdev = playback_ctl; 813 free(capture_ctl); 814 } else { 815 cdev = capture_ctl; 816 } 817 } 818 if (ctl == NULL) { 819 err = uc_mgr_open_ctl(uc_mgr, &ctl_list, cdev, 1); 820 if (err < 0) { 821 uc_error("unable to open ctl device '%s'", cdev); 822 goto __fail; 823 } 824 ctl = ctl_list->ctl; 825 } 826 err = execute_cset(ctl, s->data.cset, s->type); 827 if (err < 0) { 828 uc_error("unable to execute cset '%s'", s->data.cset); 829 goto __fail; 830 } 831 break; 832 case SEQUENCE_ELEMENT_TYPE_SYSSET: 833 err = execute_sysw(s->data.sysw); 834 if (err < 0) 835 goto __fail; 836 break; 837 case SEQUENCE_ELEMENT_TYPE_SLEEP: 838 usleep(s->data.sleep); 839 break; 840 case SEQUENCE_ELEMENT_TYPE_EXEC: 841 if (s->data.exec == NULL) 842 break; 843 ignore_error = s->data.exec[0] == '-'; 844 err = uc_mgr_exec(s->data.exec + (ignore_error ? 1 : 0)); 845 if (ignore_error == false && err != 0) { 846 uc_error("exec '%s' failed (exit code %d)", s->data.exec, err); 847 goto __fail; 848 } 849 break; 850 case SEQUENCE_ELEMENT_TYPE_SHELL: 851 if (s->data.exec == NULL) 852 break; 853 ignore_error = s->data.exec[0] == '-'; 854shell_retry: 855 err = system(s->data.exec + (ignore_error ? 1 : 0)); 856 if (WIFSIGNALED(err)) { 857 err = -EINTR; 858 } if (WIFEXITED(err)) { 859 if (ignore_error == false && WEXITSTATUS(err) != 0) { 860 uc_error("command '%s' failed (exit code %d)", s->data.exec, WEXITSTATUS(err)); 861 err = -EINVAL; 862 goto __fail; 863 } 864 } else if (err < 0) { 865 if (errno == EAGAIN) 866 goto shell_retry; 867 err = -errno; 868 goto __fail; 869 } 870 break; 871 case SEQUENCE_ELEMENT_TYPE_CMPT_SEQ: 872 /* Execute enable or disable sequence of a component 873 * device. Pass the cdev defined by the machine device. 874 */ 875 err = execute_component_seq(uc_mgr, 876 &s->data.cmpt_seq, 877 value_list1, 878 value_list2, 879 value_list3, 880 cdev); 881 if (err < 0) 882 goto __fail; 883 break; 884 case SEQUENCE_ELEMENT_TYPE_CFGSAVE: 885 err = execute_cfgsave(uc_mgr, s->data.cfgsave); 886 if (err < 0) 887 goto __fail; 888 break; 889 case SEQUENCE_ELEMENT_TYPE_DEV_ENABLE_SEQ: 890 case SEQUENCE_ELEMENT_TYPE_DEV_DISABLE_SEQ: 891 err = run_device_sequence(uc_mgr, verb, s->data.device, 892 s->type == SEQUENCE_ELEMENT_TYPE_DEV_ENABLE_SEQ); 893 if (err < 0) 894 goto __fail; 895 break; 896 case SEQUENCE_ELEMENT_TYPE_DEV_DISABLE_ALL: 897 err = run_device_all_sequence(uc_mgr, verb); 898 if (err < 0) 899 goto __fail; 900 break; 901 default: 902 uc_error("unknown sequence command %i", s->type); 903 break; 904 } 905 } 906 free(cdev); 907 uc_mgr->sequence_hops--; 908 return 0; 909 __fail_nomem: 910 err = -ENOMEM; 911 __fail: 912 free(cdev); 913 uc_mgr->sequence_hops--; 914 return err; 915 916} 917 918/* Execute enable or disable sequence of a component device. 919 * 920 * For a component device (a codec or embedded DSP), its sequence doesn't 921 * specify the sound card device 'cdev', because a component can be reused 922 * by different sound cards (machines). So when executing its sequence, a 923 * parameter 'cdev' is used to pass cdev defined by the sequence of its 924 * parent, the machine device. UCM manger will store the cdev when entering 925 * the component domain. 926 */ 927static int execute_component_seq(snd_use_case_mgr_t *uc_mgr, 928 struct component_sequence *cmpt_seq, 929 struct list_head *value_list1 ATTRIBUTE_UNUSED, 930 struct list_head *value_list2 ATTRIBUTE_UNUSED, 931 struct list_head *value_list3 ATTRIBUTE_UNUSED, 932 char *cdev) 933{ 934 struct use_case_device *device = cmpt_seq->device; 935 struct list_head *seq; 936 int err; 937 938 /* enter component domain and store cdev for the component */ 939 uc_mgr->in_component_domain = 1; 940 uc_mgr->cdev = cdev; 941 942 /* choose enable or disable sequence of the component device */ 943 if (cmpt_seq->enable) 944 seq = &device->enable_list; 945 else 946 seq = &device->disable_list; 947 948 /* excecute the sequence of the component dev */ 949 err = execute_sequence(uc_mgr, uc_mgr->active_verb, seq, 950 &device->value_list, 951 &uc_mgr->active_verb->value_list, 952 &uc_mgr->value_list); 953 954 /* exit component domain and clear cdev */ 955 uc_mgr->in_component_domain = 0; 956 uc_mgr->cdev = NULL; 957 958 return err; 959} 960 961static int add_auto_value(snd_use_case_mgr_t *uc_mgr, const char *key, char *value) 962{ 963 char *s; 964 int err; 965 966 err = get_value1(uc_mgr, &value, &uc_mgr->value_list, key); 967 if (err == -ENOENT) { 968 s = strdup(value); 969 if (s == NULL) 970 return -ENOMEM; 971 return uc_mgr_add_value(&uc_mgr->value_list, key, s); 972 } else if (err < 0) { 973 return err; 974 } 975 free(value); 976 return 0; 977} 978 979static int add_auto_values(snd_use_case_mgr_t *uc_mgr) 980{ 981 struct ctl_list *ctl_list; 982 const char *id; 983 char buf[40]; 984 int err; 985 986 ctl_list = uc_mgr_get_master_ctl(uc_mgr); 987 if (ctl_list) { 988 id = snd_ctl_card_info_get_id(ctl_list->ctl_info); 989 snprintf(buf, sizeof(buf), "hw:%s", id); 990 err = add_auto_value(uc_mgr, "PlaybackCTL", buf); 991 if (err < 0) 992 return err; 993 err = add_auto_value(uc_mgr, "CaptureCTL", buf); 994 if (err < 0) 995 return err; 996 } 997 return 0; 998} 999 1000/** 1001 * \brief execute default commands 1002 * \param uc_mgr Use case manager 1003 * \param force Force run 1004 * \return zero on success, otherwise a negative error code 1005 */ 1006static int set_defaults(snd_use_case_mgr_t *uc_mgr, bool force) 1007{ 1008 int err; 1009 1010 if (!force && uc_mgr->default_list_executed) 1011 return 0; 1012 err = execute_sequence(uc_mgr, NULL, &uc_mgr->default_list, 1013 &uc_mgr->value_list, NULL, NULL); 1014 if (err < 0) { 1015 uc_error("Unable to execute default sequence"); 1016 return err; 1017 } 1018 uc_mgr->default_list_executed = 1; 1019 return 0; 1020} 1021 1022/** 1023 * \brief Import master config and execute the default sequence 1024 * \param uc_mgr Use case manager 1025 * \return zero on success, otherwise a negative error code 1026 */ 1027static int import_master_config(snd_use_case_mgr_t *uc_mgr) 1028{ 1029 int err; 1030 1031 err = uc_mgr_import_master_config(uc_mgr); 1032 if (err < 0) 1033 return err; 1034 return add_auto_values(uc_mgr); 1035} 1036 1037/** 1038 * \brief Check, if the UCM configuration is empty 1039 * \param uc_mgr Use case Manager 1040 * \return zero on success, otherwise a negative error code 1041 */ 1042static int check_empty_configuration(snd_use_case_mgr_t *uc_mgr) 1043{ 1044 int err; 1045 char *value; 1046 1047 err = get_value(uc_mgr, "Linked", &value, NULL, NULL, 1); 1048 if (err >= 0) { 1049 err = strcasecmp(value, "true") == 0 || 1050 strcmp(value, "1") == 0; 1051 free(value); 1052 if (err) 1053 return 0; 1054 } 1055 if (!list_empty(&uc_mgr->verb_list)) 1056 return 0; 1057 if (!list_empty(&uc_mgr->fixedboot_list)) 1058 return 0; 1059 if (!list_empty(&uc_mgr->boot_list)) 1060 return 0; 1061 return -ENXIO; 1062} 1063 1064/** 1065 * \brief Universal find - string in a list 1066 * \param list List of structures 1067 * \param offset Offset of list structure 1068 * \param soffset Offset of string structure 1069 * \param match String to match 1070 * \return structure on success, otherwise a NULL (not found) 1071 */ 1072static void *find0(struct list_head *list, 1073 unsigned long offset, 1074 unsigned long soffset, 1075 const char *match) 1076{ 1077 struct list_head *pos; 1078 char *ptr, *str; 1079 1080 list_for_each(pos, list) { 1081 ptr = list_entry_offset(pos, char, offset); 1082 str = *((char **)(ptr + soffset)); 1083 if (strcmp(str, match) == 0) 1084 return ptr; 1085 } 1086 return NULL; 1087} 1088 1089#define find(list, type, member, value, match) \ 1090 find0(list, (unsigned long)(&((type *)0)->member), \ 1091 (unsigned long)(&((type *)0)->value), match) 1092 1093/** 1094 * \brief Universal string list 1095 * \param list List of structures 1096 * \param result Result list 1097 * \param offset Offset of list structure 1098 * \param s1offset Offset of string structure 1099 * \return count of items on success, otherwise a negative error code 1100 */ 1101static int get_list0(struct list_head *list, 1102 const char **result[], 1103 unsigned long offset, 1104 unsigned long s1offset) 1105{ 1106 char **res; 1107 int cnt; 1108 struct list_head *pos; 1109 char *ptr, *str1; 1110 1111 cnt = alloc_str_list(list, 1, &res); 1112 if (cnt <= 0) { 1113 *result = NULL; 1114 return cnt; 1115 } 1116 *result = (const char **)res; 1117 list_for_each(pos, list) { 1118 ptr = list_entry_offset(pos, char, offset); 1119 str1 = *((char **)(ptr + s1offset)); 1120 if (str1 != NULL) { 1121 *res = strdup(str1); 1122 if (*res == NULL) 1123 goto __fail; 1124 } else { 1125 *res = NULL; 1126 } 1127 res++; 1128 } 1129 return cnt; 1130 __fail: 1131 snd_use_case_free_list(*result, cnt); 1132 return -ENOMEM; 1133} 1134 1135#define get_list(list, result, type, member, s1) \ 1136 get_list0(list, result, \ 1137 (unsigned long)(&((type *)0)->member), \ 1138 (unsigned long)(&((type *)0)->s1)) 1139 1140/** 1141 * \brief Universal string list - pair of strings 1142 * \param list List of structures 1143 * \param result Result list 1144 * \param offset Offset of list structure 1145 * \param s1offset Offset of string structure 1146 * \param s1offset Offset of string structure 1147 * \return count of items on success, otherwise a negative error code 1148 */ 1149static int get_list20(struct list_head *list, 1150 const char **result[], 1151 unsigned long offset, 1152 unsigned long s1offset, 1153 unsigned long s2offset) 1154{ 1155 char **res; 1156 int cnt; 1157 struct list_head *pos; 1158 char *ptr, *str1, *str2; 1159 1160 cnt = alloc_str_list(list, 2, &res); 1161 if (cnt <= 0) { 1162 *result = NULL; 1163 return cnt; 1164 } 1165 *result = (const char **)res; 1166 list_for_each(pos, list) { 1167 ptr = list_entry_offset(pos, char, offset); 1168 str1 = *((char **)(ptr + s1offset)); 1169 if (str1 != NULL) { 1170 *res = strdup(str1); 1171 if (*res == NULL) 1172 goto __fail; 1173 } else { 1174 *res = NULL; 1175 } 1176 res++; 1177 str2 = *((char **)(ptr + s2offset)); 1178 if (str2 != NULL) { 1179 *res = strdup(str2); 1180 if (*res == NULL) 1181 goto __fail; 1182 } else { 1183 *res = NULL; 1184 } 1185 res++; 1186 } 1187 return cnt; 1188 __fail: 1189 snd_use_case_free_list(*result, cnt); 1190 return -ENOMEM; 1191} 1192 1193#define get_list2(list, result, type, member, s1, s2) \ 1194 get_list20(list, result, \ 1195 (unsigned long)(&((type *)0)->member), \ 1196 (unsigned long)(&((type *)0)->s1), \ 1197 (unsigned long)(&((type *)0)->s2)) 1198 1199/** 1200 * \brief Find verb 1201 * \param uc_mgr Use case manager 1202 * \param verb_name verb to find 1203 * \return structure on success, otherwise a NULL (not found) 1204 */ 1205static inline struct use_case_verb *find_verb(snd_use_case_mgr_t *uc_mgr, 1206 const char *verb_name) 1207{ 1208 return find(&uc_mgr->verb_list, 1209 struct use_case_verb, list, name, 1210 verb_name); 1211} 1212 1213static int is_devlist_supported(snd_use_case_mgr_t *uc_mgr, 1214 struct dev_list *dev_list) 1215{ 1216 struct dev_list_node *device; 1217 struct use_case_device *adev; 1218 struct list_head *pos, *pos1; 1219 int found_ret; 1220 1221 switch (dev_list->type) { 1222 case DEVLIST_NONE: 1223 default: 1224 return 1; 1225 case DEVLIST_SUPPORTED: 1226 found_ret = 1; 1227 break; 1228 case DEVLIST_CONFLICTING: 1229 found_ret = 0; 1230 break; 1231 } 1232 1233 list_for_each(pos, &dev_list->list) { 1234 device = list_entry(pos, struct dev_list_node, list); 1235 1236 list_for_each(pos1, &uc_mgr->active_devices) { 1237 adev = list_entry(pos1, struct use_case_device, 1238 active_list); 1239 if (!strcmp(device->name, adev->name)) 1240 return found_ret; 1241 } 1242 } 1243 return 1 - found_ret; 1244} 1245 1246static inline int is_modifier_supported(snd_use_case_mgr_t *uc_mgr, 1247 struct use_case_modifier *modifier) 1248{ 1249 return is_devlist_supported(uc_mgr, &modifier->dev_list); 1250} 1251 1252static inline int is_device_supported(snd_use_case_mgr_t *uc_mgr, 1253 struct use_case_device *device) 1254{ 1255 return is_devlist_supported(uc_mgr, &device->dev_list); 1256} 1257 1258/** 1259 * \brief Find device 1260 * \param verb Use case verb 1261 * \param device_name device to find 1262 * \return structure on success, otherwise a NULL (not found) 1263 */ 1264static inline struct use_case_device * 1265 find_device(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb, 1266 const char *device_name, int check_supported) 1267{ 1268 struct use_case_device *device; 1269 struct list_head *pos; 1270 1271 list_for_each(pos, &verb->device_list) { 1272 device = list_entry(pos, struct use_case_device, list); 1273 1274 if (strcmp(device_name, device->name)) 1275 continue; 1276 1277 if (check_supported && 1278 !is_device_supported(uc_mgr, device)) 1279 continue; 1280 1281 return device; 1282 } 1283 return NULL; 1284} 1285 1286/** 1287 * \brief Find modifier 1288 * \param verb Use case verb 1289 * \param modifier_name modifier to find 1290 * \return structure on success, otherwise a NULL (not found) 1291 */ 1292static struct use_case_modifier * 1293 find_modifier(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb, 1294 const char *modifier_name, int check_supported) 1295{ 1296 struct use_case_modifier *modifier; 1297 struct list_head *pos; 1298 1299 list_for_each(pos, &verb->modifier_list) { 1300 modifier = list_entry(pos, struct use_case_modifier, list); 1301 1302 if (strcmp(modifier->name, modifier_name)) 1303 continue; 1304 1305 if (check_supported && 1306 !is_modifier_supported(uc_mgr, modifier)) 1307 continue; 1308 1309 return modifier; 1310 } 1311 return NULL; 1312} 1313 1314long device_status(snd_use_case_mgr_t *uc_mgr, 1315 const char *device_name) 1316{ 1317 struct use_case_device *dev; 1318 struct list_head *pos; 1319 1320 list_for_each(pos, &uc_mgr->active_devices) { 1321 dev = list_entry(pos, struct use_case_device, active_list); 1322 if (strcmp(dev->name, device_name) == 0) 1323 return 1; 1324 } 1325 return 0; 1326} 1327 1328long modifier_status(snd_use_case_mgr_t *uc_mgr, 1329 const char *modifier_name) 1330{ 1331 struct use_case_modifier *mod; 1332 struct list_head *pos; 1333 1334 list_for_each(pos, &uc_mgr->active_modifiers) { 1335 mod = list_entry(pos, struct use_case_modifier, active_list); 1336 if (strcmp(mod->name, modifier_name) == 0) 1337 return 1; 1338 } 1339 return 0; 1340} 1341 1342/** 1343 * \brief Set verb 1344 * \param uc_mgr Use case manager 1345 * \param verb verb to set 1346 * \param enable nonzero = enable, zero = disable 1347 * \return zero on success, otherwise a negative error code 1348 */ 1349static int set_verb(snd_use_case_mgr_t *uc_mgr, 1350 struct use_case_verb *verb, 1351 int enable) 1352{ 1353 struct list_head *seq; 1354 int err; 1355 1356 if (enable) { 1357 err = set_defaults(uc_mgr, false); 1358 if (err < 0) 1359 return err; 1360 seq = &verb->enable_list; 1361 } else { 1362 seq = &verb->disable_list; 1363 } 1364 err = execute_sequence(uc_mgr, verb, seq, 1365 &verb->value_list, 1366 &uc_mgr->value_list, 1367 NULL); 1368 if (enable && err >= 0) 1369 uc_mgr->active_verb = verb; 1370 return err; 1371} 1372 1373/** 1374 * \brief Set modifier 1375 * \param uc_mgr Use case manager 1376 * \param modifier modifier to set 1377 * \param enable nonzero = enable, zero = disable 1378 * \return zero on success, otherwise a negative error code 1379 */ 1380static int set_modifier(snd_use_case_mgr_t *uc_mgr, 1381 struct use_case_modifier *modifier, 1382 int enable) 1383{ 1384 struct list_head *seq; 1385 int err; 1386 1387 if (modifier_status(uc_mgr, modifier->name) == enable) 1388 return 0; 1389 1390 if (enable) { 1391 seq = &modifier->enable_list; 1392 } else { 1393 seq = &modifier->disable_list; 1394 } 1395 err = execute_sequence(uc_mgr, uc_mgr->active_verb, seq, 1396 &modifier->value_list, 1397 &uc_mgr->active_verb->value_list, 1398 &uc_mgr->value_list); 1399 if (enable && err >= 0) { 1400 list_add_tail(&modifier->active_list, &uc_mgr->active_modifiers); 1401 } else if (!enable) { 1402 list_del(&modifier->active_list); 1403 } 1404 return err; 1405} 1406 1407/** 1408 * \brief Set device 1409 * \param uc_mgr Use case manager 1410 * \param device device to set 1411 * \param enable nonzero = enable, zero = disable 1412 * \return zero on success, otherwise a negative error code 1413 */ 1414static int set_device(snd_use_case_mgr_t *uc_mgr, 1415 struct use_case_device *device, 1416 int enable) 1417{ 1418 struct list_head *seq; 1419 int err; 1420 1421 if (device_status(uc_mgr, device->name) == enable) 1422 return 0; 1423 1424 if (enable) { 1425 seq = &device->enable_list; 1426 } else { 1427 seq = &device->disable_list; 1428 } 1429 err = execute_sequence(uc_mgr, uc_mgr->active_verb, seq, 1430 &device->value_list, 1431 &uc_mgr->active_verb->value_list, 1432 &uc_mgr->value_list); 1433 if (enable && err >= 0) { 1434 list_add_tail(&device->active_list, &uc_mgr->active_devices); 1435 } else if (!enable) { 1436 list_del(&device->active_list); 1437 } 1438 return err; 1439} 1440 1441/** 1442 * \brief Do the full reset 1443 * \param uc_mgr Use case manager 1444 * \return zero on success, otherwise a negative error code 1445 */ 1446static int do_reset(snd_use_case_mgr_t *uc_mgr) 1447{ 1448 int err; 1449 1450 err = set_defaults(uc_mgr, true); 1451 INIT_LIST_HEAD(&uc_mgr->active_modifiers); 1452 INIT_LIST_HEAD(&uc_mgr->active_devices); 1453 uc_mgr->active_verb = NULL; 1454 return err; 1455} 1456 1457/** 1458 * \brief Parse open arguments 1459 * \param uc_mgr Use case manager 1460 * \param name name of card to open 1461 * \return the rest of the card name to open 1462 */ 1463const char *parse_open_variables(snd_use_case_mgr_t *uc_mgr, const char *name) 1464{ 1465 const char *end, *id; 1466 char *args, *var; 1467 snd_config_t *cfg, *n; 1468 snd_config_iterator_t i, next; 1469 char vname[128]; 1470 size_t l; 1471 int err; 1472 1473 end = strstr(name, ">>>"); 1474 if (end == NULL) 1475 return name; 1476 l = end - name - 3; 1477 args = alloca(l + 1); 1478 strncpy(args, name + 3, l); 1479 args[l] = '\0'; 1480 1481 err = snd_config_load_string(&cfg, args, 0); 1482 if (err < 0) { 1483 uc_error("error: open arguments are not valid (%s)", args); 1484 goto skip; 1485 } 1486 1487 /* set arguments */ 1488 snd_config_for_each(i, next, cfg) { 1489 n = snd_config_iterator_entry(i); 1490 err = snd_config_get_id(n, &id); 1491 if (err < 0) 1492 goto skip; 1493 err = snd_config_get_ascii(n, &var); 1494 if (err < 0) 1495 goto skip; 1496 snprintf(vname, sizeof(vname), "@%s", id); 1497 err = uc_mgr_set_variable(uc_mgr, vname, var); 1498 free(var); 1499 if (err < 0) 1500 goto skip; 1501 } 1502 1503skip: 1504 snd_config_delete(cfg); 1505 return end + 3; 1506} 1507 1508int snd_use_case_mgr_open(snd_use_case_mgr_t **uc_mgr, 1509 const char *card_name) 1510{ 1511 snd_use_case_mgr_t *mgr; 1512 int err; 1513 1514 /* create a new UCM */ 1515 mgr = calloc(1, sizeof(snd_use_case_mgr_t)); 1516 if (mgr == NULL) 1517 return -ENOMEM; 1518 INIT_LIST_HEAD(&mgr->verb_list); 1519 INIT_LIST_HEAD(&mgr->fixedboot_list); 1520 INIT_LIST_HEAD(&mgr->boot_list); 1521 INIT_LIST_HEAD(&mgr->default_list); 1522 INIT_LIST_HEAD(&mgr->value_list); 1523 INIT_LIST_HEAD(&mgr->active_modifiers); 1524 INIT_LIST_HEAD(&mgr->active_devices); 1525 INIT_LIST_HEAD(&mgr->ctl_list); 1526 INIT_LIST_HEAD(&mgr->variable_list); 1527 pthread_mutex_init(&mgr->mutex, NULL); 1528 1529 if (card_name && *card_name == '-') { 1530 card_name++; 1531 mgr->suppress_nodev_errors = 1; 1532 } 1533 1534 if (card_name && card_name[0] == '<' && card_name[1] == '<' && card_name[2] == '<') 1535 card_name = parse_open_variables(mgr, card_name); 1536 1537 err = uc_mgr_card_open(mgr); 1538 if (err < 0) { 1539 uc_mgr_free(mgr); 1540 return err; 1541 } 1542 1543 mgr->card_name = strdup(card_name); 1544 if (mgr->card_name == NULL) { 1545 err = -ENOMEM; 1546 goto _err; 1547 } 1548 1549 /* get info on use_cases and verify against card */ 1550 err = import_master_config(mgr); 1551 if (err < 0) { 1552 if (err == -ENXIO && mgr->suppress_nodev_errors) 1553 goto _err; 1554 uc_error("error: failed to import %s use case configuration %d", 1555 card_name, err); 1556 goto _err; 1557 } 1558 1559 err = check_empty_configuration(mgr); 1560 if (err < 0) { 1561 uc_error("error: failed to import %s (empty configuration)", card_name); 1562 goto _err; 1563 } 1564 1565 *uc_mgr = mgr; 1566 return 0; 1567 1568_err: 1569 uc_mgr_card_close(mgr); 1570 uc_mgr_free(mgr); 1571 return err; 1572} 1573 1574int snd_use_case_mgr_reload(snd_use_case_mgr_t *uc_mgr) 1575{ 1576 int err; 1577 1578 pthread_mutex_lock(&uc_mgr->mutex); 1579 1580 do_reset(uc_mgr); 1581 1582 uc_mgr_free_verb(uc_mgr); 1583 1584 uc_mgr->default_list_executed = 0; 1585 1586 /* reload all use cases */ 1587 err = import_master_config(uc_mgr); 1588 if (err < 0) { 1589 uc_error("error: failed to reload use cases"); 1590 pthread_mutex_unlock(&uc_mgr->mutex); 1591 return -EINVAL; 1592 } 1593 1594 pthread_mutex_unlock(&uc_mgr->mutex); 1595 return err; 1596} 1597 1598int snd_use_case_mgr_close(snd_use_case_mgr_t *uc_mgr) 1599{ 1600 uc_mgr_card_close(uc_mgr); 1601 uc_mgr_free(uc_mgr); 1602 1603 return 0; 1604} 1605 1606/* 1607 * Tear down current use case verb, device and modifier. 1608 */ 1609static int dismantle_use_case(snd_use_case_mgr_t *uc_mgr) 1610{ 1611 struct list_head *pos, *npos; 1612 struct use_case_modifier *modifier; 1613 struct use_case_device *device; 1614 int err; 1615 1616 list_for_each_safe(pos, npos, &uc_mgr->active_modifiers) { 1617 modifier = list_entry(pos, struct use_case_modifier, 1618 active_list); 1619 err = set_modifier(uc_mgr, modifier, 0); 1620 if (err < 0) 1621 uc_error("Unable to disable modifier %s", modifier->name); 1622 } 1623 INIT_LIST_HEAD(&uc_mgr->active_modifiers); 1624 1625 list_for_each_safe(pos, npos, &uc_mgr->active_devices) { 1626 device = list_entry(pos, struct use_case_device, 1627 active_list); 1628 err = set_device(uc_mgr, device, 0); 1629 if (err < 0) 1630 uc_error("Unable to disable device %s", device->name); 1631 } 1632 INIT_LIST_HEAD(&uc_mgr->active_devices); 1633 1634 err = set_verb(uc_mgr, uc_mgr->active_verb, 0); 1635 if (err < 0) { 1636 uc_error("Unable to disable verb %s", uc_mgr->active_verb->name); 1637 return err; 1638 } 1639 uc_mgr->active_verb = NULL; 1640 1641 err = set_defaults(uc_mgr, true); 1642 1643 return err; 1644} 1645 1646int snd_use_case_mgr_reset(snd_use_case_mgr_t *uc_mgr) 1647{ 1648 int err; 1649 1650 pthread_mutex_lock(&uc_mgr->mutex); 1651 err = do_reset(uc_mgr); 1652 pthread_mutex_unlock(&uc_mgr->mutex); 1653 return err; 1654} 1655 1656/** 1657 * \brief Get list of verbs in pair verbname+comment 1658 * \param list Returned list 1659 * \return Number of list entries if success, otherwise a negative error code 1660 */ 1661static int get_verb_list(snd_use_case_mgr_t *uc_mgr, const char **list[]) 1662{ 1663 return get_list2(&uc_mgr->verb_list, list, 1664 struct use_case_verb, list, 1665 name, comment); 1666} 1667 1668/** 1669 * \brief Get list of devices in pair devicename+comment 1670 * \param list Returned list 1671 * \param verbname For verb (NULL = current) 1672 * \return Number of list entries if success, otherwise a negative error code 1673 */ 1674static int get_device_list(snd_use_case_mgr_t *uc_mgr, const char **list[], 1675 char *verbname) 1676{ 1677 struct use_case_verb *verb; 1678 1679 if (verbname) { 1680 verb = find_verb(uc_mgr, verbname); 1681 } else { 1682 verb = uc_mgr->active_verb; 1683 } 1684 if (verb == NULL) 1685 return -ENOENT; 1686 return get_list2(&verb->device_list, list, 1687 struct use_case_device, list, 1688 name, comment); 1689} 1690 1691/** 1692 * \brief Get list of modifiers in pair devicename+comment 1693 * \param list Returned list 1694 * \param verbname For verb (NULL = current) 1695 * \return Number of list entries if success, otherwise a negative error code 1696 */ 1697static int get_modifier_list(snd_use_case_mgr_t *uc_mgr, const char **list[], 1698 char *verbname) 1699{ 1700 struct use_case_verb *verb; 1701 if (verbname) { 1702 verb = find_verb(uc_mgr, verbname); 1703 } else { 1704 verb = uc_mgr->active_verb; 1705 } 1706 if (verb == NULL) 1707 return -ENOENT; 1708 return get_list2(&verb->modifier_list, list, 1709 struct use_case_modifier, list, 1710 name, comment); 1711} 1712 1713/** 1714 * \brief Get list of supported/conflicting devices 1715 * \param list Returned list 1716 * \param name Name of modifier or verb to query 1717 * \param type Type of device list entries to return 1718 * \return Number of list entries if success, otherwise a negative error code 1719 */ 1720static int get_supcon_device_list(snd_use_case_mgr_t *uc_mgr, 1721 const char **list[], char *name, 1722 enum dev_list_type type) 1723{ 1724 char *str; 1725 struct use_case_verb *verb; 1726 struct use_case_modifier *modifier; 1727 struct use_case_device *device; 1728 1729 if (!name) 1730 return -ENOENT; 1731 1732 str = strchr(name, '/'); 1733 if (str) { 1734 *str = '\0'; 1735 verb = find_verb(uc_mgr, str + 1); 1736 } 1737 else { 1738 verb = uc_mgr->active_verb; 1739 } 1740 if (!verb) 1741 return -ENOENT; 1742 1743 modifier = find_modifier(uc_mgr, verb, name, 0); 1744 if (modifier) { 1745 if (modifier->dev_list.type != type) { 1746 *list = NULL; 1747 return 0; 1748 } 1749 return get_list(&modifier->dev_list.list, list, 1750 struct dev_list_node, list, 1751 name); 1752 } 1753 1754 device = find_device(uc_mgr, verb, name, 0); 1755 if (device) { 1756 if (device->dev_list.type != type) { 1757 *list = NULL; 1758 return 0; 1759 } 1760 return get_list(&device->dev_list.list, list, 1761 struct dev_list_node, list, 1762 name); 1763 } 1764 1765 return -ENOENT; 1766} 1767 1768/** 1769 * \brief Get list of supported devices 1770 * \param list Returned list 1771 * \param name Name of verb or modifier to query 1772 * \return Number of list entries if success, otherwise a negative error code 1773 */ 1774static int get_supported_device_list(snd_use_case_mgr_t *uc_mgr, 1775 const char **list[], char *name) 1776{ 1777 return get_supcon_device_list(uc_mgr, list, name, DEVLIST_SUPPORTED); 1778} 1779 1780/** 1781 * \brief Get list of conflicting devices 1782 * \param list Returned list 1783 * \param name Name of verb or modifier to query 1784 * \return Number of list entries if success, otherwise a negative error code 1785 */ 1786static int get_conflicting_device_list(snd_use_case_mgr_t *uc_mgr, 1787 const char **list[], char *name) 1788{ 1789 return get_supcon_device_list(uc_mgr, list, name, DEVLIST_CONFLICTING); 1790} 1791 1792#ifndef DOC_HIDDEN 1793struct myvalue { 1794 struct list_head list; 1795 const char *text; 1796}; 1797#endif 1798 1799/** 1800 * \brief Convert myvalue list string list 1801 * \param list myvalue list 1802 * \param res string list 1803 * \retval Number of list entries if success, otherwise a negativer error code 1804 */ 1805static int myvalue_to_str_list(struct list_head *list, char ***res) 1806{ 1807 struct list_head *pos; 1808 struct myvalue *value; 1809 char **p; 1810 int cnt; 1811 1812 cnt = alloc_str_list(list, 1, res); 1813 if (cnt < 0) 1814 return cnt; 1815 p = *res; 1816 list_for_each(pos, list) { 1817 value = list_entry(pos, struct myvalue, list); 1818 *p = strdup(value->text); 1819 if (*p == NULL) { 1820 snd_use_case_free_list((const char **)p, cnt); 1821 return -ENOMEM; 1822 } 1823 p++; 1824 } 1825 return cnt; 1826} 1827 1828/** 1829 * \brief Free myvalue list 1830 * \param list myvalue list 1831 */ 1832static void myvalue_list_free(struct list_head *list) 1833{ 1834 struct list_head *pos, *npos; 1835 struct myvalue *value; 1836 1837 list_for_each_safe(pos, npos, list) { 1838 value = list_entry(pos, struct myvalue, list); 1839 list_del(&value->list); 1840 free(value); 1841 } 1842} 1843 1844/** 1845 * \brief Merge one value to the myvalue list 1846 * \param list The list with values 1847 * \param value The value to be merged (without duplicates) 1848 * \return 1 if dup, 0 if success, otherwise a negative error code 1849 */ 1850static int merge_value(struct list_head *list, const char *text) 1851{ 1852 struct list_head *pos; 1853 struct myvalue *value; 1854 1855 list_for_each(pos, list) { 1856 value = list_entry(pos, struct myvalue, list); 1857 if (strcmp(value->text, text) == 0) 1858 return 1; 1859 } 1860 value = malloc(sizeof(*value)); 1861 if (value == NULL) 1862 return -ENOMEM; 1863 value->text = text; 1864 list_add_tail(&value->list, list); 1865 return 0; 1866} 1867 1868/** 1869 * \brief Find all values for given identifier 1870 * \param list Returned list 1871 * \param source Source list with ucm_value structures 1872 * \return Zero if success, otherwise a negative error code 1873 */ 1874static int add_identifiers(struct list_head *list, 1875 struct list_head *source) 1876{ 1877 struct ucm_value *v; 1878 struct list_head *pos; 1879 int err; 1880 1881 list_for_each(pos, source) { 1882 v = list_entry(pos, struct ucm_value, list); 1883 err = merge_value(list, v->name); 1884 if (err < 0) 1885 return err; 1886 } 1887 return 0; 1888} 1889 1890/** 1891 * \brief Find all values for given identifier 1892 * \param list Returned list 1893 * \param identifier Identifier 1894 * \param source Source list with ucm_value structures 1895 */ 1896static int add_values(struct list_head *list, 1897 const char *identifier, 1898 struct list_head *source) 1899{ 1900 struct ucm_value *v; 1901 struct list_head *pos; 1902 int err; 1903 1904 list_for_each(pos, source) { 1905 v = list_entry(pos, struct ucm_value, list); 1906 if (check_identifier(identifier, v->name)) { 1907 err = merge_value(list, v->data); 1908 if (err < 0) 1909 return err; 1910 } 1911 } 1912 return 0; 1913} 1914 1915/** 1916 * \brief compare two identifiers 1917 */ 1918static int identifier_cmp(const void *_a, const void *_b) 1919{ 1920 const char * const *a = _a; 1921 const char * const *b = _b; 1922 return strcmp(*a, *b); 1923} 1924 1925/** 1926 * \brief Get list of available identifiers 1927 * \param list Returned list 1928 * \param name Name of verb or modifier to query 1929 * \return Number of list entries if success, otherwise a negative error code 1930 */ 1931static int get_identifiers_list(snd_use_case_mgr_t *uc_mgr, 1932 const char **list[], char *name) 1933{ 1934 struct use_case_verb *verb; 1935 struct use_case_modifier *modifier; 1936 struct use_case_device *device; 1937 struct list_head mylist; 1938 struct list_head *value_list; 1939 char *str, **res; 1940 int err; 1941 1942 if (!name) 1943 return -ENOENT; 1944 1945 str = strchr(name, '/'); 1946 if (str) { 1947 *str = '\0'; 1948 verb = find_verb(uc_mgr, str + 1); 1949 } 1950 else { 1951 verb = uc_mgr->active_verb; 1952 } 1953 if (!verb) 1954 return -ENOENT; 1955 1956 value_list = NULL; 1957 modifier = find_modifier(uc_mgr, verb, name, 0); 1958 if (modifier) { 1959 value_list = &modifier->value_list; 1960 } else { 1961 device = find_device(uc_mgr, verb, name, 0); 1962 if (device) 1963 value_list = &device->value_list; 1964 } 1965 if (value_list == NULL) 1966 return -ENOENT; 1967 1968 INIT_LIST_HEAD(&mylist); 1969 err = add_identifiers(&mylist, &uc_mgr->value_list); 1970 if (err < 0) 1971 goto __fail; 1972 err = add_identifiers(&mylist, &verb->value_list); 1973 if (err < 0) 1974 goto __fail; 1975 err = add_identifiers(&mylist, value_list); 1976 if (err < 0) 1977 goto __fail; 1978 err = myvalue_to_str_list(&mylist, &res); 1979 if (err > 0) 1980 *list = (const char **)res; 1981 else if (err == 0) 1982 *list = NULL; 1983__fail: 1984 myvalue_list_free(&mylist); 1985 if (err <= 0) 1986 return err; 1987 qsort(*list, err, sizeof(char *), identifier_cmp); 1988 return err; 1989} 1990 1991/** 1992 * \brief Get list of values 1993 * \param list Returned list 1994 * \param verbname For verb (NULL = current) 1995 * \return Number of list entries if success, otherwise a negative error code 1996 */ 1997static int get_value_list(snd_use_case_mgr_t *uc_mgr, 1998 const char *identifier, 1999 const char **list[], 2000 char *verbname) 2001{ 2002 struct list_head mylist, *pos; 2003 struct use_case_verb *verb; 2004 struct use_case_device *dev; 2005 struct use_case_modifier *mod; 2006 char **res; 2007 int err; 2008 2009 if (verbname) { 2010 verb = find_verb(uc_mgr, verbname); 2011 } else { 2012 verb = uc_mgr->active_verb; 2013 } 2014 if (verb == NULL) 2015 return -ENOENT; 2016 INIT_LIST_HEAD(&mylist); 2017 err = add_values(&mylist, identifier, &uc_mgr->value_list); 2018 if (err < 0) 2019 goto __fail; 2020 err = add_values(&mylist, identifier, &verb->value_list); 2021 if (err < 0) 2022 goto __fail; 2023 list_for_each(pos, &verb->device_list) { 2024 dev = list_entry(pos, struct use_case_device, list); 2025 err = add_values(&mylist, identifier, &dev->value_list); 2026 if (err < 0) 2027 goto __fail; 2028 } 2029 list_for_each(pos, &verb->modifier_list) { 2030 mod = list_entry(pos, struct use_case_modifier, list); 2031 err = add_values(&mylist, identifier, &mod->value_list); 2032 if (err < 0) 2033 goto __fail; 2034 } 2035 err = myvalue_to_str_list(&mylist, &res); 2036 if (err > 0) 2037 *list = (const char **)res; 2038 else if (err == 0) 2039 *list = NULL; 2040 __fail: 2041 myvalue_list_free(&mylist); 2042 return err; 2043} 2044 2045/** 2046 * \brief Get list of enabled devices 2047 * \param list Returned list 2048 * \param verbname For verb (NULL = current) 2049 * \return Number of list entries if success, otherwise a negative error code 2050 */ 2051static int get_enabled_device_list(snd_use_case_mgr_t *uc_mgr, 2052 const char **list[]) 2053{ 2054 if (uc_mgr->active_verb == NULL) 2055 return -EINVAL; 2056 return get_list(&uc_mgr->active_devices, list, 2057 struct use_case_device, active_list, 2058 name); 2059} 2060 2061/** 2062 * \brief Get list of enabled modifiers 2063 * \param list Returned list 2064 * \param verbname For verb (NULL = current) 2065 * \return Number of list entries if success, otherwise a negative error code 2066 */ 2067static int get_enabled_modifier_list(snd_use_case_mgr_t *uc_mgr, 2068 const char **list[]) 2069{ 2070 if (uc_mgr->active_verb == NULL) 2071 return -EINVAL; 2072 return get_list(&uc_mgr->active_modifiers, list, 2073 struct use_case_modifier, active_list, 2074 name); 2075} 2076 2077int snd_use_case_get_list(snd_use_case_mgr_t *uc_mgr, 2078 const char *identifier, 2079 const char **list[]) 2080{ 2081 char *str, *str1; 2082 int err; 2083 2084 if (uc_mgr == NULL || identifier == NULL) 2085 return uc_mgr_scan_master_configs(list); 2086 pthread_mutex_lock(&uc_mgr->mutex); 2087 if (strcmp(identifier, "_verbs") == 0) 2088 err = get_verb_list(uc_mgr, list); 2089 else if (strcmp(identifier, "_enadevs") == 0) 2090 err = get_enabled_device_list(uc_mgr, list); 2091 else if (strcmp(identifier, "_enamods") == 0) 2092 err = get_enabled_modifier_list(uc_mgr, list); 2093 else { 2094 str1 = strchr(identifier, '/'); 2095 if (str1) { 2096 str = strdup(str1 + 1); 2097 if (str == NULL) { 2098 err = -ENOMEM; 2099 goto __end; 2100 } 2101 } else { 2102 str = NULL; 2103 } 2104 if (check_identifier(identifier, "_devices")) 2105 err = get_device_list(uc_mgr, list, str); 2106 else if (check_identifier(identifier, "_modifiers")) 2107 err = get_modifier_list(uc_mgr, list, str); 2108 else if (check_identifier(identifier, "_identifiers")) 2109 err = get_identifiers_list(uc_mgr, list, str); 2110 else if (check_identifier(identifier, "_supporteddevs")) 2111 err = get_supported_device_list(uc_mgr, list, str); 2112 else if (check_identifier(identifier, "_conflictingdevs")) 2113 err = get_conflicting_device_list(uc_mgr, list, str); 2114 else if (identifier[0] == '_') 2115 err = -ENOENT; 2116 else 2117 err = get_value_list(uc_mgr, identifier, list, str); 2118 if (str) 2119 free(str); 2120 } 2121 __end: 2122 pthread_mutex_unlock(&uc_mgr->mutex); 2123 return err; 2124} 2125 2126static int get_value1(snd_use_case_mgr_t *uc_mgr, char **value, 2127 struct list_head *value_list, const char *identifier) 2128{ 2129 struct ucm_value *val; 2130 struct list_head *pos; 2131 int err; 2132 2133 if (!value_list) 2134 return -ENOENT; 2135 2136 list_for_each(pos, value_list) { 2137 val = list_entry(pos, struct ucm_value, list); 2138 if (check_identifier(identifier, val->name)) { 2139 if (uc_mgr->conf_format < 2) { 2140 *value = strdup(val->data); 2141 if (*value == NULL) 2142 return -ENOMEM; 2143 return 0; 2144 } 2145 err = uc_mgr_get_substituted_value(uc_mgr, value, val->data); 2146 if (err < 0) 2147 return err; 2148 return rewrite_device_value(uc_mgr, val->name, value); 2149 } 2150 } 2151 return -ENOENT; 2152} 2153 2154static int get_value3(snd_use_case_mgr_t *uc_mgr, 2155 char **value, 2156 const char *identifier, 2157 struct list_head *value_list1, 2158 struct list_head *value_list2, 2159 struct list_head *value_list3) 2160{ 2161 int err; 2162 2163 err = get_value1(uc_mgr, value, value_list1, identifier); 2164 if (err >= 0 || err != -ENOENT) 2165 return err; 2166 err = get_value1(uc_mgr, value, value_list2, identifier); 2167 if (err >= 0 || err != -ENOENT) 2168 return err; 2169 err = get_value1(uc_mgr, value, value_list3, identifier); 2170 if (err >= 0 || err != -ENOENT) 2171 return err; 2172 return -ENOENT; 2173} 2174 2175/** 2176 * \brief Get value 2177 * \param uc_mgr Use case manager 2178 * \param identifier Value identifier (string) 2179 * \param value Returned value string 2180 * \param item Modifier or Device name (string) 2181 * \return Zero on success (value is filled), otherwise a negative error code 2182 */ 2183static int get_value(snd_use_case_mgr_t *uc_mgr, 2184 const char *identifier, 2185 char **value, 2186 const char *mod_dev_name, 2187 const char *verb_name, 2188 int exact) 2189{ 2190 struct use_case_verb *verb; 2191 struct use_case_modifier *mod; 2192 struct use_case_device *dev; 2193 int err; 2194 2195 if (mod_dev_name || verb_name || !exact) { 2196 if (verb_name && strlen(verb_name)) { 2197 verb = find_verb(uc_mgr, verb_name); 2198 } else { 2199 verb = uc_mgr->active_verb; 2200 } 2201 if (verb) { 2202 if (mod_dev_name) { 2203 mod = find_modifier(uc_mgr, verb, 2204 mod_dev_name, 0); 2205 if (mod) { 2206 err = get_value1(uc_mgr, value, 2207 &mod->value_list, 2208 identifier); 2209 if (err >= 0 || err != -ENOENT) 2210 return err; 2211 } 2212 2213 dev = find_device(uc_mgr, verb, 2214 mod_dev_name, 0); 2215 if (dev) { 2216 err = get_value1(uc_mgr, value, 2217 &dev->value_list, 2218 identifier); 2219 if (err >= 0 || err != -ENOENT) 2220 return err; 2221 } 2222 2223 if (exact) 2224 return -ENOENT; 2225 } 2226 2227 err = get_value1(uc_mgr, value, &verb->value_list, identifier); 2228 if (err >= 0 || err != -ENOENT) 2229 return err; 2230 } 2231 2232 if (exact) 2233 return -ENOENT; 2234 } 2235 2236 err = get_value1(uc_mgr, value, &uc_mgr->value_list, identifier); 2237 if (err >= 0 || err != -ENOENT) 2238 return err; 2239 2240 return -ENOENT; 2241} 2242 2243/** 2244 * \brief Get private alsa-lib configuration (ASCII) 2245 * \param uc_mgr Use case manager 2246 * \param str Returned value string 2247 * \return Zero on success (value is filled), otherwise a negative error code 2248 */ 2249static int get_alibcfg(snd_use_case_mgr_t *uc_mgr, char **str) 2250{ 2251 snd_output_t *out; 2252 size_t size; 2253 int err; 2254 2255 err = snd_output_buffer_open(&out); 2256 if (err < 0) 2257 return err; 2258 err = snd_config_save(uc_mgr->local_config, out); 2259 if (err >= 0) { 2260 size = snd_output_buffer_steal(out, str); 2261 if (*str) 2262 (*str)[size] = '\0'; 2263 } 2264 snd_output_close(out); 2265 return 0; 2266} 2267 2268/** 2269 * \brief Get device prefix for private alsa-lib configuration 2270 * \param uc_mgr Use case manager 2271 * \param str Returned value string 2272 * \return Zero on success (value is filled), otherwise a negative error code 2273 */ 2274static int get_alibpref(snd_use_case_mgr_t *uc_mgr, char **str) 2275{ 2276 const size_t l = 10; 2277 char *s; 2278 2279 s = malloc(l); 2280 if (s == NULL) 2281 return -ENOMEM; 2282 snprintf(s, l, "_ucm%04X.", uc_mgr->ucm_card_number); 2283 *str = s; 2284 return 0; 2285} 2286 2287int snd_use_case_get(snd_use_case_mgr_t *uc_mgr, 2288 const char *identifier, 2289 const char **value) 2290{ 2291 const char *slash1, *slash2, *mod_dev_after; 2292 const char *ident, *mod_dev, *verb; 2293 int exact = 0; 2294 int err; 2295 2296 pthread_mutex_lock(&uc_mgr->mutex); 2297 if (identifier == NULL) { 2298 *value = strdup(uc_mgr->card_name); 2299 if (*value == NULL) { 2300 err = -ENOMEM; 2301 goto __end; 2302 } 2303 err = 0; 2304 } else if (strcmp(identifier, "_verb") == 0) { 2305 if (uc_mgr->active_verb == NULL) { 2306 err = -ENOENT; 2307 goto __end; 2308 } 2309 *value = strdup(uc_mgr->active_verb->name); 2310 if (*value == NULL) { 2311 err = -ENOMEM; 2312 goto __end; 2313 } 2314 err = 0; 2315 } else if (strcmp(identifier, "_file") == 0) { 2316 /* get the conf file name of the opened card */ 2317 if ((uc_mgr->card_name == NULL) || 2318 (uc_mgr->conf_file_name == NULL) || 2319 (uc_mgr->conf_file_name[0] == '\0')) { 2320 err = -ENOENT; 2321 goto __end; 2322 } 2323 *value = strdup(uc_mgr->conf_file_name); 2324 if (*value == NULL) { 2325 err = -ENOMEM; 2326 goto __end; 2327 } 2328 err = 0; 2329 2330 } else if (strcmp(identifier, "_alibcfg") == 0) { 2331 err = get_alibcfg(uc_mgr, (char **)value); 2332 } else if (strcmp(identifier, "_alibpref") == 0) { 2333 err = get_alibpref(uc_mgr, (char **)value); 2334 } else if (identifier[0] == '_') { 2335 err = -ENOENT; 2336 } else { 2337 if (identifier[0] == '=') { 2338 exact = 1; 2339 identifier++; 2340 } 2341 2342 slash1 = strchr(identifier, '/'); 2343 if (slash1) { 2344 ident = strndup(identifier, slash1 - identifier); 2345 2346 slash2 = strchr(slash1 + 1, '/'); 2347 if (slash2) { 2348 mod_dev_after = slash2; 2349 verb = slash2 + 1; 2350 } 2351 else { 2352 mod_dev_after = slash1 + strlen(slash1); 2353 verb = NULL; 2354 } 2355 2356 if (mod_dev_after == slash1 + 1) 2357 mod_dev = NULL; 2358 else 2359 mod_dev = strndup(slash1 + 1, 2360 mod_dev_after - (slash1 + 1)); 2361 } 2362 else { 2363 ident = identifier; 2364 mod_dev = NULL; 2365 verb = NULL; 2366 } 2367 2368 err = get_value(uc_mgr, ident, (char **)value, mod_dev, verb, 2369 exact); 2370 if (ident != identifier) 2371 free((void *)ident); 2372 if (mod_dev) 2373 free((void *)mod_dev); 2374 } 2375 __end: 2376 pthread_mutex_unlock(&uc_mgr->mutex); 2377 return err; 2378} 2379 2380/* 2381 * a helper macro to obtain status and existence 2382 */ 2383#define geti(uc_mgr, status, ifind, str, value) ({ \ 2384 long val = -EINVAL; \ 2385 if (str) { \ 2386 val = (status)((uc_mgr), (str)); \ 2387 if (val >= 0) { \ 2388 if ((ifind)((uc_mgr), (uc_mgr)->active_verb, (str), 0)) { \ 2389 *(value) = val; \ 2390 val = 0; \ 2391 } else { \ 2392 val = -ENOENT; \ 2393 } \ 2394 } \ 2395 } \ 2396 ; val; /* return value */ \ 2397}) 2398 2399int snd_use_case_geti(snd_use_case_mgr_t *uc_mgr, 2400 const char *identifier, 2401 long *value) 2402{ 2403 char *str, *str1; 2404 int err; 2405 2406 pthread_mutex_lock(&uc_mgr->mutex); 2407 if (0) { 2408 /* nothing here - prepared for fixed identifiers */ 2409 } else { 2410 str1 = strchr(identifier, '/'); 2411 if (str1) { 2412 str = strdup(str1 + 1); 2413 if (str == NULL) { 2414 err = -ENOMEM; 2415 goto __end; 2416 } 2417 } else { 2418 str = NULL; 2419 } 2420 if (check_identifier(identifier, "_devstatus")) { 2421 err = geti(uc_mgr, device_status, find_device, str, value); 2422 } else if (check_identifier(identifier, "_modstatus")) { 2423 err = geti(uc_mgr, modifier_status, find_modifier, str, value); 2424#if 0 2425 /* 2426 * enable this block if the else clause below is expanded to query 2427 * user-supplied values 2428 */ 2429 } else if (identifier[0] == '_') { 2430 err = -ENOENT; 2431#endif 2432 } else 2433 err = -ENOENT; 2434 if (str) 2435 free(str); 2436 } 2437 __end: 2438 pthread_mutex_unlock(&uc_mgr->mutex); 2439 return err; 2440} 2441 2442static int set_fixedboot_user(snd_use_case_mgr_t *uc_mgr, 2443 const char *value) 2444{ 2445 int err; 2446 2447 if (value != NULL && *value) { 2448 uc_error("error: wrong value for _fboot (%s)", value); 2449 return -EINVAL; 2450 } 2451 if (list_empty(&uc_mgr->fixedboot_list)) 2452 return -ENOENT; 2453 err = execute_sequence(uc_mgr, NULL, &uc_mgr->fixedboot_list, 2454 &uc_mgr->value_list, NULL, NULL); 2455 if (err < 0) { 2456 uc_error("Unable to execute force boot sequence"); 2457 return err; 2458 } 2459 return err; 2460} 2461 2462static int set_boot_user(snd_use_case_mgr_t *uc_mgr, 2463 const char *value) 2464{ 2465 int err; 2466 2467 if (value != NULL && *value) { 2468 uc_error("error: wrong value for _boot (%s)", value); 2469 return -EINVAL; 2470 } 2471 if (list_empty(&uc_mgr->boot_list)) 2472 return -ENOENT; 2473 err = execute_sequence(uc_mgr, NULL, &uc_mgr->boot_list, 2474 &uc_mgr->value_list, NULL, NULL); 2475 if (err < 0) { 2476 uc_error("Unable to execute boot sequence"); 2477 return err; 2478 } 2479 return err; 2480} 2481 2482static int set_defaults_user(snd_use_case_mgr_t *uc_mgr, 2483 const char *value) 2484{ 2485 if (value != NULL && *value) { 2486 uc_error("error: wrong value for _defaults (%s)", value); 2487 return -EINVAL; 2488 } 2489 return set_defaults(uc_mgr, false); 2490} 2491 2492static int handle_transition_verb(snd_use_case_mgr_t *uc_mgr, 2493 struct use_case_verb *new_verb) 2494{ 2495 struct list_head *pos; 2496 struct transition_sequence *trans; 2497 int err; 2498 2499 list_for_each(pos, &uc_mgr->active_verb->transition_list) { 2500 trans = list_entry(pos, struct transition_sequence, list); 2501 if (strcmp(trans->name, new_verb->name) == 0) { 2502 err = execute_sequence(uc_mgr, uc_mgr->active_verb, 2503 &trans->transition_list, 2504 &uc_mgr->active_verb->value_list, 2505 &uc_mgr->value_list, 2506 NULL); 2507 if (err >= 0) 2508 return 1; 2509 return err; 2510 } 2511 } 2512 return 0; 2513} 2514 2515static int set_verb_user(snd_use_case_mgr_t *uc_mgr, 2516 const char *verb_name) 2517{ 2518 struct use_case_verb *verb; 2519 int err = 0; 2520 2521 if (uc_mgr->active_verb && 2522 strcmp(uc_mgr->active_verb->name, verb_name) == 0) 2523 return 0; 2524 if (strcmp(verb_name, SND_USE_CASE_VERB_INACTIVE) != 0) { 2525 verb = find_verb(uc_mgr, verb_name); 2526 if (verb == NULL) 2527 return -ENOENT; 2528 } else { 2529 verb = NULL; 2530 } 2531 if (uc_mgr->active_verb) { 2532 err = handle_transition_verb(uc_mgr, verb); 2533 if (err == 0) { 2534 err = dismantle_use_case(uc_mgr); 2535 if (err < 0) 2536 return err; 2537 } else if (err == 1) { 2538 uc_mgr->active_verb = verb; 2539 verb = NULL; 2540 } else { 2541 verb = NULL; /* show error */ 2542 } 2543 } 2544 if (verb) { 2545 err = set_verb(uc_mgr, verb, 1); 2546 if (err < 0) 2547 uc_error("error: failed to initialize new use case: %s", 2548 verb_name); 2549 } 2550 return err; 2551} 2552 2553 2554static int set_device_user(snd_use_case_mgr_t *uc_mgr, 2555 const char *device_name, 2556 int enable) 2557{ 2558 struct use_case_device *device; 2559 2560 if (uc_mgr->active_verb == NULL) 2561 return -ENOENT; 2562 device = find_device(uc_mgr, uc_mgr->active_verb, device_name, 1); 2563 if (device == NULL) 2564 return -ENOENT; 2565 return set_device(uc_mgr, device, enable); 2566} 2567 2568static int set_modifier_user(snd_use_case_mgr_t *uc_mgr, 2569 const char *modifier_name, 2570 int enable) 2571{ 2572 struct use_case_modifier *modifier; 2573 2574 if (uc_mgr->active_verb == NULL) 2575 return -ENOENT; 2576 2577 modifier = find_modifier(uc_mgr, uc_mgr->active_verb, modifier_name, 1); 2578 if (modifier == NULL) 2579 return -ENOENT; 2580 return set_modifier(uc_mgr, modifier, enable); 2581} 2582 2583static int switch_device(snd_use_case_mgr_t *uc_mgr, 2584 const char *old_device, 2585 const char *new_device) 2586{ 2587 struct use_case_device *xold, *xnew; 2588 struct transition_sequence *trans; 2589 struct list_head *pos; 2590 int err, seq_found = 0; 2591 2592 if (uc_mgr->active_verb == NULL) 2593 return -ENOENT; 2594 if (device_status(uc_mgr, old_device) == 0) { 2595 uc_error("error: device %s not enabled", old_device); 2596 return -EINVAL; 2597 } 2598 if (device_status(uc_mgr, new_device) != 0) { 2599 uc_error("error: device %s already enabled", new_device); 2600 return -EINVAL; 2601 } 2602 xold = find_device(uc_mgr, uc_mgr->active_verb, old_device, 1); 2603 if (xold == NULL) 2604 return -ENOENT; 2605 list_del(&xold->active_list); 2606 xnew = find_device(uc_mgr, uc_mgr->active_verb, new_device, 1); 2607 list_add_tail(&xold->active_list, &uc_mgr->active_devices); 2608 if (xnew == NULL) 2609 return -ENOENT; 2610 err = 0; 2611 list_for_each(pos, &xold->transition_list) { 2612 trans = list_entry(pos, struct transition_sequence, list); 2613 if (strcmp(trans->name, new_device) == 0) { 2614 err = execute_sequence(uc_mgr, uc_mgr->active_verb, 2615 &trans->transition_list, 2616 &xold->value_list, 2617 &uc_mgr->active_verb->value_list, 2618 &uc_mgr->value_list); 2619 if (err >= 0) { 2620 list_del(&xold->active_list); 2621 list_add_tail(&xnew->active_list, &uc_mgr->active_devices); 2622 } 2623 seq_found = 1; 2624 break; 2625 } 2626 } 2627 if (!seq_found) { 2628 err = set_device(uc_mgr, xold, 0); 2629 if (err < 0) 2630 return err; 2631 err = set_device(uc_mgr, xnew, 1); 2632 if (err < 0) 2633 return err; 2634 } 2635 return err; 2636} 2637 2638static int switch_modifier(snd_use_case_mgr_t *uc_mgr, 2639 const char *old_modifier, 2640 const char *new_modifier) 2641{ 2642 struct use_case_modifier *xold, *xnew; 2643 struct transition_sequence *trans; 2644 struct list_head *pos; 2645 int err, seq_found = 0; 2646 2647 if (uc_mgr->active_verb == NULL) 2648 return -ENOENT; 2649 if (modifier_status(uc_mgr, old_modifier) == 0) { 2650 uc_error("error: modifier %s not enabled", old_modifier); 2651 return -EINVAL; 2652 } 2653 if (modifier_status(uc_mgr, new_modifier) != 0) { 2654 uc_error("error: modifier %s already enabled", new_modifier); 2655 return -EINVAL; 2656 } 2657 xold = find_modifier(uc_mgr, uc_mgr->active_verb, old_modifier, 1); 2658 if (xold == NULL) 2659 return -ENOENT; 2660 xnew = find_modifier(uc_mgr, uc_mgr->active_verb, new_modifier, 1); 2661 if (xnew == NULL) 2662 return -ENOENT; 2663 err = 0; 2664 list_for_each(pos, &xold->transition_list) { 2665 trans = list_entry(pos, struct transition_sequence, list); 2666 if (strcmp(trans->name, new_modifier) == 0) { 2667 err = execute_sequence(uc_mgr, uc_mgr->active_verb, 2668 &trans->transition_list, 2669 &xold->value_list, 2670 &uc_mgr->active_verb->value_list, 2671 &uc_mgr->value_list); 2672 if (err >= 0) { 2673 list_del(&xold->active_list); 2674 list_add_tail(&xnew->active_list, &uc_mgr->active_modifiers); 2675 } 2676 seq_found = 1; 2677 break; 2678 } 2679 } 2680 if (!seq_found) { 2681 err = set_modifier(uc_mgr, xold, 0); 2682 if (err < 0) 2683 return err; 2684 err = set_modifier(uc_mgr, xnew, 1); 2685 if (err < 0) 2686 return err; 2687 } 2688 return err; 2689} 2690 2691int snd_use_case_set(snd_use_case_mgr_t *uc_mgr, 2692 const char *identifier, 2693 const char *value) 2694{ 2695 char *str, *str1; 2696 int err = 0; 2697 2698 pthread_mutex_lock(&uc_mgr->mutex); 2699 if (strcmp(identifier, "_fboot") == 0) 2700 err = set_fixedboot_user(uc_mgr, value); 2701 else if (strcmp(identifier, "_boot") == 0) 2702 err = set_boot_user(uc_mgr, value); 2703 else if (strcmp(identifier, "_defaults") == 0) 2704 err = set_defaults_user(uc_mgr, value); 2705 else if (strcmp(identifier, "_verb") == 0) 2706 err = set_verb_user(uc_mgr, value); 2707 else if (strcmp(identifier, "_enadev") == 0) 2708 err = set_device_user(uc_mgr, value, 1); 2709 else if (strcmp(identifier, "_disdev") == 0) 2710 err = set_device_user(uc_mgr, value, 0); 2711 else if (strcmp(identifier, "_enamod") == 0) 2712 err = set_modifier_user(uc_mgr, value, 1); 2713 else if (strcmp(identifier, "_dismod") == 0) 2714 err = set_modifier_user(uc_mgr, value, 0); 2715 else { 2716 str1 = strchr(identifier, '/'); 2717 if (str1) { 2718 str = strdup(str1 + 1); 2719 if (str == NULL) { 2720 err = -ENOMEM; 2721 goto __end; 2722 } 2723 } else { 2724 err = -EINVAL; 2725 goto __end; 2726 } 2727 if (check_identifier(identifier, "_swdev")) 2728 err = switch_device(uc_mgr, str, value); 2729 else if (check_identifier(identifier, "_swmod")) 2730 err = switch_modifier(uc_mgr, str, value); 2731 else 2732 err = -EINVAL; 2733 if (str) 2734 free(str); 2735 } 2736 __end: 2737 pthread_mutex_unlock(&uc_mgr->mutex); 2738 return err; 2739} 2740 2741/** 2742 * \brief Parse control element identifier 2743 * \param dst Element identifier 2744 * \param ucm_id Use case identifier 2745 * \param value String value to be parsed 2746 * \return Zero if success, otherwise a negative error code 2747 */ 2748int snd_use_case_parse_ctl_elem_id(snd_ctl_elem_id_t *dst, 2749 const char *ucm_id, 2750 const char *value) 2751{ 2752 snd_ctl_elem_iface_t iface; 2753 int jack_control; 2754 2755 jack_control = strcmp(ucm_id, "JackControl") == 0; 2756 if (!jack_control && 2757 strcmp(ucm_id, "PlaybackVolume") && 2758 strcmp(ucm_id, "PlaybackSwitch") && 2759 strcmp(ucm_id, "CaptureVolume") && 2760 strcmp(ucm_id, "CaptureSwitch")) 2761 return -EINVAL; 2762 snd_ctl_elem_id_clear(dst); 2763 if (strcasestr(value, "name=")) 2764 return __snd_ctl_ascii_elem_id_parse(dst, value, NULL); 2765 iface = SND_CTL_ELEM_IFACE_MIXER; 2766 if (jack_control) 2767 iface = SND_CTL_ELEM_IFACE_CARD; 2768 snd_ctl_elem_id_set_interface(dst, iface); 2769 snd_ctl_elem_id_set_name(dst, value); 2770 return 0; 2771} 2772 2773/** 2774 * \brief Parse mixer element identifier 2775 * \param dst Simple mixer element identifier 2776 * \param ucm_id Use case identifier 2777 * \param value String value to be parsed 2778 * \return Zero if success, otherwise a negative error code 2779 */ 2780int snd_use_case_parse_selem_id(snd_mixer_selem_id_t *dst, 2781 const char *ucm_id, 2782 const char *value) 2783{ 2784#ifdef BUILD_MIXER 2785 if (strcmp(ucm_id, "PlaybackMixerId") == 0 || 2786 strcmp(ucm_id, "CaptureMixerId") == 0) 2787 return snd_mixer_selem_id_parse(dst, value); 2788#endif 2789 return -EINVAL; 2790} 2791