1/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. 2 * Use of this source code is governed by a BSD-style license that can be 3 * found in the LICENSE file. 4 */ 5 6#include <alsa/asoundlib.h> 7#include <alsa/use-case.h> 8#include <ctype.h> 9#include <string.h> 10#include <syslog.h> 11 12#include "cras_alsa_ucm.h" 13#include "utlist.h" 14 15static const char jack_var[] = "JackName"; 16static const char jack_type_var[] = "JackType"; 17static const char jack_switch_var[] = "JackSwitch"; 18static const char edid_var[] = "EDIDFile"; 19static const char cap_var[] = "CaptureControl"; 20static const char mic_positions[] = "MicPositions"; 21static const char override_type_name_var[] = "OverrideNodeType"; 22static const char output_dsp_name_var[] = "OutputDspName"; 23static const char input_dsp_name_var[] = "InputDspName"; 24static const char mixer_var[] = "MixerName"; 25static const char swap_mode_suffix[] = "Swap Mode"; 26static const char min_buffer_level_var[] = "MinBufferLevel"; 27static const char dma_period_var[] = "DmaPeriodMicrosecs"; 28static const char disable_software_volume[] = "DisableSoftwareVolume"; 29static const char playback_device_name_var[] = "PlaybackPCM"; 30static const char playback_device_rate_var[] = "PlaybackRate"; 31static const char capture_device_name_var[] = "CapturePCM"; 32static const char capture_device_rate_var[] = "CaptureRate"; 33static const char capture_channel_map_var[] = "CaptureChannelMap"; 34static const char coupled_mixers[] = "CoupledMixers"; 35/* Set this value in a SectionDevice to specify the maximum software gain in dBm 36 * and enable software gain on this node. */ 37static const char max_software_gain[] = "MaxSoftwareGain"; 38/* Set this value in a SectionDevice to specify the default node gain in dBm. */ 39static const char default_node_gain[] = "DefaultNodeGain"; 40static const char hotword_model_prefix[] = "Hotword Model"; 41static const char fully_specified_ucm_var[] = "FullySpecifiedUCM"; 42static const char main_volume_names[] = "MainVolumeNames"; 43static const char enable_htimestamp_var[] = "EnableHtimestamp"; 44 45/* Use case verbs corresponding to CRAS_STREAM_TYPE. */ 46static const char *use_case_verbs[] = { 47 "HiFi", 48 "Multimedia", 49 "Voice Call", 50 "Speech", 51 "Pro Audio", 52}; 53 54/* Represents a list of section names found in UCM. */ 55struct section_name { 56 const char* name; 57 struct section_name *prev, *next; 58}; 59 60struct cras_use_case_mgr { 61 snd_use_case_mgr_t *mgr; 62 const char *name; 63 unsigned int avail_use_cases; 64 enum CRAS_STREAM_TYPE use_case; 65}; 66 67static inline const char *uc_verb(struct cras_use_case_mgr *mgr) 68{ 69 return use_case_verbs[mgr->use_case]; 70} 71 72static int device_enabled(struct cras_use_case_mgr *mgr, const char *dev) 73{ 74 const char **list; 75 unsigned int i; 76 int num_devs; 77 int enabled = 0; 78 79 num_devs = snd_use_case_get_list(mgr->mgr, "_enadevs", &list); 80 if (num_devs <= 0) 81 return 0; 82 83 for (i = 0; i < (unsigned int)num_devs; i++) 84 if (!strcmp(dev, list[i])) { 85 enabled = 1; 86 break; 87 } 88 89 snd_use_case_free_list(list, num_devs); 90 return enabled; 91} 92 93static int modifier_enabled(struct cras_use_case_mgr *mgr, const char *mod) 94{ 95 const char **list; 96 unsigned int mod_idx; 97 int num_mods; 98 99 num_mods = snd_use_case_get_list(mgr->mgr, "_enamods", &list); 100 if (num_mods <= 0) 101 return 0; 102 103 for (mod_idx = 0; mod_idx < (unsigned int)num_mods; mod_idx++) 104 if (!strcmp(mod, list[mod_idx])) 105 break; 106 107 snd_use_case_free_list(list, num_mods); 108 return (mod_idx < (unsigned int)num_mods); 109} 110 111static int get_var(struct cras_use_case_mgr *mgr, const char *var, 112 const char *dev, const char *verb, const char **value) 113{ 114 char *id; 115 int rc; 116 size_t len = strlen(var) + strlen(dev) + strlen(verb) + 4; 117 118 id = (char *)malloc(len); 119 if (!id) 120 return -ENOMEM; 121 snprintf(id, len, "=%s/%s/%s", var, dev, verb); 122 rc = snd_use_case_get(mgr->mgr, id, value); 123 124 free((void *)id); 125 return rc; 126} 127 128static int get_int(struct cras_use_case_mgr *mgr, const char *var, 129 const char *dev, const char *verb, int *value) 130{ 131 const char *str_value; 132 int rc; 133 134 if (!value) 135 return -EINVAL; 136 rc = get_var(mgr, var, dev, verb, &str_value); 137 if (rc != 0) 138 return rc; 139 *value = atoi(str_value); 140 free((void *)str_value); 141 return 0; 142} 143 144static int ucm_set_modifier_enabled(struct cras_use_case_mgr *mgr, 145 const char *mod, int enable) 146{ 147 return snd_use_case_set(mgr->mgr, enable ? "_enamod" : "_dismod", mod); 148} 149 150static int ucm_str_ends_with_suffix(const char *str, const char *suffix) 151{ 152 if (!str || !suffix) 153 return 0; 154 size_t len_str = strlen(str); 155 size_t len_suffix = strlen(suffix); 156 if (len_suffix > len_str) 157 return 0; 158 return strncmp(str + len_str - len_suffix, suffix, len_suffix) == 0; 159} 160 161static int ucm_section_exists_with_name(struct cras_use_case_mgr *mgr, 162 const char *name, const char *identifier) 163{ 164 const char **list; 165 unsigned int i; 166 int num_entries; 167 int exist = 0; 168 169 num_entries = snd_use_case_get_list(mgr->mgr, identifier, &list); 170 if (num_entries <= 0) 171 return 0; 172 173 for (i = 0; i < (unsigned int)num_entries; i+=2) { 174 175 if (!list[i]) 176 continue; 177 178 if (strcmp(list[i], name) == 0) { 179 exist = 1; 180 break; 181 } 182 } 183 snd_use_case_free_list(list, num_entries); 184 return exist; 185} 186 187static int ucm_section_exists_with_suffix(struct cras_use_case_mgr *mgr, 188 const char *suffix, const char *identifier) 189{ 190 const char **list; 191 unsigned int i; 192 int num_entries; 193 int exist = 0; 194 195 num_entries = snd_use_case_get_list(mgr->mgr, identifier, &list); 196 if (num_entries <= 0) 197 return 0; 198 199 for (i = 0; i < (unsigned int)num_entries; i+=2) { 200 201 if (!list[i]) 202 continue; 203 204 if (ucm_str_ends_with_suffix(list[i], suffix)) { 205 exist = 1; 206 break; 207 } 208 } 209 snd_use_case_free_list(list, num_entries); 210 return exist; 211} 212 213static int ucm_mod_exists_with_suffix(struct cras_use_case_mgr *mgr, 214 const char *suffix) 215{ 216 char *identifier; 217 int rc; 218 219 identifier = snd_use_case_identifier("_modifiers/%s", uc_verb(mgr)); 220 rc = ucm_section_exists_with_suffix(mgr, suffix, identifier); 221 free(identifier); 222 return rc; 223} 224 225static int ucm_mod_exists_with_name(struct cras_use_case_mgr *mgr, 226 const char *name) 227{ 228 char *identifier; 229 int rc; 230 231 identifier = snd_use_case_identifier("_modifiers/%s", uc_verb(mgr)); 232 rc = ucm_section_exists_with_name(mgr, name, identifier); 233 free(identifier); 234 return rc; 235} 236 237/* Get a list of section names whose variable is the matched value. */ 238static struct section_name * ucm_get_sections_for_var( 239 struct cras_use_case_mgr *mgr, 240 const char *var, const char *value, 241 const char *identifier, 242 enum CRAS_STREAM_DIRECTION direction) 243{ 244 const char **list; 245 struct section_name *section_names = NULL, *s_name; 246 unsigned int i; 247 int num_entries; 248 int rc; 249 250 num_entries = snd_use_case_get_list(mgr->mgr, identifier, &list); 251 if (num_entries <= 0) 252 return NULL; 253 254 /* snd_use_case_get_list fills list with pairs of device name and 255 * comment, so device names are in even-indexed elements. */ 256 for (i = 0; i < (unsigned int)num_entries; i+=2) { 257 const char *this_value; 258 259 if (!list[i]) 260 continue; 261 262 rc = get_var(mgr, var, list[i], uc_verb(mgr), &this_value); 263 if (rc) 264 continue; 265 266 if (!strcmp(value, this_value)) { 267 s_name = (struct section_name *)malloc( 268 sizeof(struct section_name)); 269 270 if (!s_name) { 271 syslog(LOG_ERR, "Failed to allocate memory"); 272 free((void *)this_value); 273 break; 274 } 275 276 s_name->name = strdup(list[i]); 277 DL_APPEND(section_names, s_name); 278 } 279 free((void *)this_value); 280 } 281 282 snd_use_case_free_list(list, num_entries); 283 return section_names; 284} 285 286static struct section_name *ucm_get_devices_for_var( 287 struct cras_use_case_mgr *mgr, 288 const char *var, const char *value, 289 enum CRAS_STREAM_DIRECTION dir) 290{ 291 char *identifier; 292 struct section_name *section_names; 293 294 identifier = snd_use_case_identifier("_devices/%s", uc_verb(mgr)); 295 section_names = ucm_get_sections_for_var(mgr, var, value, identifier, 296 dir); 297 free(identifier); 298 return section_names; 299} 300 301static const char *ucm_get_playback_device_name_for_dev( 302 struct cras_use_case_mgr *mgr, const char *dev) 303{ 304 const char *name = NULL; 305 int rc; 306 307 rc = get_var(mgr, playback_device_name_var, dev, uc_verb(mgr), &name); 308 if (rc) 309 return NULL; 310 311 return name; 312} 313 314static const char *ucm_get_capture_device_name_for_dev( 315 struct cras_use_case_mgr *mgr, const char *dev) 316{ 317 const char *name = NULL; 318 int rc; 319 320 rc = get_var(mgr, capture_device_name_var, dev, uc_verb(mgr), &name); 321 if (rc) 322 return NULL; 323 324 return name; 325} 326 327/* Get a list of mixer names specified in a UCM variable separated by ",". 328 * E.g. "Left Playback,Right Playback". 329 */ 330static struct mixer_name *ucm_get_mixer_names(struct cras_use_case_mgr *mgr, 331 const char *dev, const char* var, 332 enum CRAS_STREAM_DIRECTION dir, 333 mixer_name_type type) 334{ 335 const char *names_in_string = NULL; 336 int rc; 337 char *tokens, *name, *laststr; 338 struct mixer_name *names = NULL; 339 340 rc = get_var(mgr, var, dev, uc_verb(mgr), &names_in_string); 341 if (rc) 342 return NULL; 343 344 tokens = strdup(names_in_string); 345 name = strtok_r(tokens, ",", &laststr); 346 while (name != NULL) { 347 names = mixer_name_add(names, name, dir, type); 348 name = strtok_r(NULL, ",", &laststr); 349 } 350 free((void*)names_in_string); 351 free(tokens); 352 return names; 353} 354 355/* Exported Interface */ 356 357struct cras_use_case_mgr *ucm_create(const char *name) 358{ 359 struct cras_use_case_mgr *mgr; 360 int rc; 361 const char **list; 362 int num_verbs, i, j; 363 364 if (!name) 365 return NULL; 366 367 mgr = (struct cras_use_case_mgr *)malloc(sizeof(*mgr)); 368 if (!mgr) 369 return NULL; 370 371 rc = snd_use_case_mgr_open(&mgr->mgr, name); 372 if (rc) { 373 syslog(LOG_WARNING, "Can not open ucm for card %s, rc = %d", 374 name, rc); 375 goto cleanup; 376 } 377 378 mgr->name = name; 379 mgr->avail_use_cases = 0; 380 num_verbs = snd_use_case_get_list(mgr->mgr, "_verbs", &list); 381 for (i = 0; i < num_verbs; i += 2) { 382 for (j = 0; j < CRAS_STREAM_NUM_TYPES; ++j) { 383 if (strcmp(list[i], use_case_verbs[j]) == 0) 384 break; 385 } 386 if (j < CRAS_STREAM_NUM_TYPES) 387 mgr->avail_use_cases |= (1 << j); 388 } 389 if (num_verbs > 0) 390 snd_use_case_free_list(list, num_verbs); 391 392 rc = ucm_set_use_case(mgr, CRAS_STREAM_TYPE_DEFAULT); 393 if (rc) 394 goto cleanup_mgr; 395 396 return mgr; 397 398cleanup_mgr: 399 snd_use_case_mgr_close(mgr->mgr); 400cleanup: 401 free(mgr); 402 return NULL; 403} 404 405void ucm_destroy(struct cras_use_case_mgr *mgr) 406{ 407 snd_use_case_mgr_close(mgr->mgr); 408 free(mgr); 409} 410 411int ucm_set_use_case(struct cras_use_case_mgr *mgr, 412 enum CRAS_STREAM_TYPE use_case) 413{ 414 int rc; 415 416 if (mgr->avail_use_cases & (1 << use_case)) { 417 mgr->use_case = use_case; 418 } else { 419 syslog(LOG_ERR, "Unavailable use case %d for card %s", 420 use_case, mgr->name); 421 return -1; 422 } 423 424 rc = snd_use_case_set(mgr->mgr, "_verb", uc_verb(mgr)); 425 if (rc) { 426 syslog(LOG_ERR, "Can not set verb %s for card %s, rc = %d", 427 uc_verb(mgr), mgr->name, rc); 428 return rc; 429 } 430 431 return 0; 432} 433 434int ucm_swap_mode_exists(struct cras_use_case_mgr *mgr) 435{ 436 return ucm_mod_exists_with_suffix(mgr, swap_mode_suffix); 437} 438 439int ucm_enable_swap_mode(struct cras_use_case_mgr *mgr, const char *node_name, 440 int enable) 441{ 442 char *swap_mod = NULL; 443 int rc; 444 size_t len = strlen(node_name) + 1 + strlen(swap_mode_suffix) + 1; 445 swap_mod = (char *)malloc(len); 446 if (!swap_mod) 447 return -ENOMEM; 448 snprintf(swap_mod, len, "%s %s", node_name, swap_mode_suffix); 449 if (!ucm_mod_exists_with_name(mgr, swap_mod)) { 450 syslog(LOG_ERR, "Can not find swap mode modifier %s.", swap_mod); 451 free((void *)swap_mod); 452 return -EPERM; 453 } 454 if (modifier_enabled(mgr, swap_mod) == !!enable) { 455 free((void *)swap_mod); 456 return 0; 457 } 458 rc = ucm_set_modifier_enabled(mgr, swap_mod, enable); 459 free((void *)swap_mod); 460 return rc; 461} 462 463int ucm_set_enabled(struct cras_use_case_mgr *mgr, const char *dev, int enable) 464{ 465 if (device_enabled(mgr, dev) == !!enable) 466 return 0; 467 syslog(LOG_DEBUG, "UCM %s %s", enable ? "enable" : "disable", dev); 468 return snd_use_case_set(mgr->mgr, enable ? "_enadev" : "_disdev", dev); 469} 470 471char *ucm_get_flag(struct cras_use_case_mgr *mgr, const char *flag_name) 472{ 473 char *flag_value = NULL; 474 const char *value; 475 int rc; 476 477 /* Set device to empty string since flag is specified in verb section */ 478 rc = get_var(mgr, flag_name, "", uc_verb(mgr), &value); 479 if (!rc) { 480 flag_value = strdup(value); 481 free((void *)value); 482 } 483 484 return flag_value; 485} 486 487char *ucm_get_cap_control(struct cras_use_case_mgr *mgr, const char *ucm_dev) 488{ 489 char *control_name = NULL; 490 const char *value; 491 int rc; 492 493 rc = get_var(mgr, cap_var, ucm_dev, uc_verb(mgr), &value); 494 if (!rc) { 495 control_name = strdup(value); 496 free((void *)value); 497 } 498 499 return control_name; 500} 501 502char *ucm_get_mic_positions(struct cras_use_case_mgr *mgr) 503{ 504 char *control_name = NULL; 505 const char *value; 506 int rc; 507 508 rc = get_var(mgr, mic_positions, "", uc_verb(mgr), &value); 509 if (!rc) { 510 control_name = strdup(value); 511 free((void *)value); 512 } 513 514 return control_name; 515} 516 517const char *ucm_get_override_type_name(struct cras_use_case_mgr *mgr, 518 const char *dev) 519{ 520 const char *override_type_name; 521 int rc; 522 523 rc = get_var(mgr, override_type_name_var, dev, uc_verb(mgr), 524 &override_type_name); 525 if (rc) 526 return NULL; 527 528 return override_type_name; 529} 530 531char *ucm_get_dev_for_jack(struct cras_use_case_mgr *mgr, const char *jack, 532 enum CRAS_STREAM_DIRECTION direction) 533{ 534 struct section_name *section_names, *c; 535 char *ret = NULL; 536 537 section_names = ucm_get_devices_for_var(mgr, jack_var, jack, direction); 538 539 DL_FOREACH(section_names, c) { 540 if (!strcmp(c->name, "Mic")) { 541 /* Skip mic section for output */ 542 if (direction == CRAS_STREAM_OUTPUT) 543 continue; 544 } else { 545 /* Only check mic for input. */ 546 if (direction == CRAS_STREAM_INPUT) 547 continue; 548 } 549 ret = strdup(c->name); 550 break; 551 } 552 553 DL_FOREACH(section_names, c) { 554 DL_DELETE(section_names, c); 555 free((void*)c->name); 556 free(c); 557 } 558 559 return ret; 560} 561 562char *ucm_get_dev_for_mixer(struct cras_use_case_mgr *mgr, const char *mixer, 563 enum CRAS_STREAM_DIRECTION dir) 564{ 565 struct section_name *section_names, *c; 566 char *ret = NULL; 567 568 section_names = ucm_get_devices_for_var(mgr, mixer_var, mixer, dir); 569 570 if (section_names) 571 ret = strdup(section_names->name); 572 573 DL_FOREACH(section_names, c) { 574 DL_DELETE(section_names, c); 575 free((void*)c->name); 576 free(c); 577 } 578 579 return ret; 580} 581 582const char *ucm_get_edid_file_for_dev(struct cras_use_case_mgr *mgr, 583 const char *dev) 584{ 585 const char *file_name; 586 int rc; 587 588 rc = get_var(mgr, edid_var, dev, uc_verb(mgr), &file_name); 589 if (rc) 590 return NULL; 591 592 return file_name; 593} 594 595const char *ucm_get_dsp_name(struct cras_use_case_mgr *mgr, const char *ucm_dev, 596 int direction) 597{ 598 const char *var = (direction == CRAS_STREAM_OUTPUT) 599 ? output_dsp_name_var 600 : input_dsp_name_var; 601 const char *dsp_name = NULL; 602 int rc; 603 604 rc = get_var(mgr, var, ucm_dev, uc_verb(mgr), &dsp_name); 605 if (rc) 606 return NULL; 607 608 return dsp_name; 609} 610 611const char *ucm_get_dsp_name_default(struct cras_use_case_mgr *mgr, 612 int direction) 613{ 614 return ucm_get_dsp_name(mgr, "", direction); 615} 616 617unsigned int ucm_get_min_buffer_level(struct cras_use_case_mgr *mgr) 618{ 619 int value; 620 int rc; 621 622 rc = get_int(mgr, min_buffer_level_var, "", uc_verb(mgr), &value); 623 if (rc) 624 return 0; 625 626 return value; 627} 628 629unsigned int ucm_get_disable_software_volume(struct cras_use_case_mgr *mgr) 630{ 631 int value; 632 int rc; 633 634 rc = get_int(mgr, disable_software_volume, "", uc_verb(mgr), &value); 635 if (rc) 636 return 0; 637 638 return value; 639} 640 641int ucm_get_max_software_gain(struct cras_use_case_mgr *mgr, const char *dev, 642 long *gain) 643{ 644 int value; 645 int rc; 646 647 rc = get_int(mgr, max_software_gain, dev, uc_verb(mgr), &value); 648 if (rc) 649 return rc; 650 *gain = value; 651 return 0; 652} 653 654int ucm_get_default_node_gain(struct cras_use_case_mgr *mgr, const char *dev, 655 long *gain) 656{ 657 int value; 658 int rc; 659 660 rc = get_int(mgr, default_node_gain, dev, uc_verb(mgr), &value); 661 if (rc) 662 return rc; 663 *gain = value; 664 return 0; 665} 666 667const char *ucm_get_device_name_for_dev( 668 struct cras_use_case_mgr *mgr, const char *dev, 669 enum CRAS_STREAM_DIRECTION direction) 670{ 671 if (direction == CRAS_STREAM_OUTPUT) 672 return ucm_get_playback_device_name_for_dev(mgr, dev); 673 else if (direction == CRAS_STREAM_INPUT) 674 return ucm_get_capture_device_name_for_dev(mgr, dev); 675 return NULL; 676} 677 678int ucm_get_sample_rate_for_dev(struct cras_use_case_mgr *mgr, const char *dev, 679 enum CRAS_STREAM_DIRECTION direction) 680{ 681 int value; 682 int rc; 683 const char *var_name; 684 685 if (direction == CRAS_STREAM_OUTPUT) 686 var_name = playback_device_rate_var; 687 else if (direction == CRAS_STREAM_INPUT) 688 var_name = capture_device_rate_var; 689 else 690 return -EINVAL; 691 692 rc = get_int(mgr, var_name, dev, uc_verb(mgr), &value); 693 if (rc) 694 return rc; 695 696 return value; 697} 698 699int ucm_get_capture_chmap_for_dev(struct cras_use_case_mgr *mgr, 700 const char *dev, 701 int8_t *channel_layout) 702{ 703 const char *var_str; 704 char *tokens, *token; 705 int i, rc; 706 707 rc = get_var(mgr, capture_channel_map_var, dev, uc_verb(mgr), &var_str); 708 if (rc) 709 return rc; 710 711 tokens = strdup(var_str); 712 token = strtok(tokens, " "); 713 for (i = 0; token && (i < CRAS_CH_MAX); i++) { 714 channel_layout[i] = atoi(token); 715 token = strtok(NULL, " "); 716 } 717 718 free((void *)tokens); 719 free((void *)var_str); 720 return (i == CRAS_CH_MAX) ? 0 : -EINVAL; 721} 722 723struct mixer_name *ucm_get_coupled_mixer_names( 724 struct cras_use_case_mgr *mgr, const char *dev) 725{ 726 return ucm_get_mixer_names(mgr, dev, coupled_mixers, 727 CRAS_STREAM_OUTPUT, 728 MIXER_NAME_VOLUME); 729} 730 731static int get_device_index_from_target(const char *target_device_name) 732{ 733 /* Expects a string in the form: hw:card-name,<num> */ 734 const char *pos = target_device_name; 735 if (!pos) 736 return -1; 737 while (*pos && *pos != ',') 738 ++pos; 739 if (*pos == ',') { 740 ++pos; 741 return atoi(pos); 742 } 743 return -1; 744} 745 746struct ucm_section *ucm_get_sections(struct cras_use_case_mgr *mgr) 747{ 748 struct ucm_section *sections = NULL; 749 struct ucm_section *dev_sec; 750 const char **list; 751 int num_devs; 752 int i; 753 char *identifier; 754 755 /* Find the list of all mixers using the control names defined in 756 * the header definintion for this function. */ 757 identifier = snd_use_case_identifier("_devices/%s", uc_verb(mgr)); 758 num_devs = snd_use_case_get_list(mgr->mgr, identifier, &list); 759 free(identifier); 760 761 /* snd_use_case_get_list fills list with pairs of device name and 762 * comment, so device names are in even-indexed elements. */ 763 for (i = 0; i < num_devs; i += 2) { 764 enum CRAS_STREAM_DIRECTION dir = CRAS_STREAM_UNDEFINED; 765 int dev_idx = -1; 766 const char *dev_name = strdup(list[i]); 767 const char *jack_name; 768 const char *jack_type; 769 const char *mixer_name; 770 struct mixer_name *m_name; 771 int rc; 772 const char *target_device_name; 773 774 if (!dev_name) 775 continue; 776 777 target_device_name = 778 ucm_get_playback_device_name_for_dev(mgr, dev_name); 779 if (target_device_name) 780 dir = CRAS_STREAM_OUTPUT; 781 else { 782 target_device_name = 783 ucm_get_capture_device_name_for_dev( 784 mgr, dev_name); 785 if (target_device_name) 786 dir = CRAS_STREAM_INPUT; 787 } 788 if (target_device_name) { 789 dev_idx = get_device_index_from_target( 790 target_device_name); 791 free((void *)target_device_name); 792 } 793 794 if (dir == CRAS_STREAM_UNDEFINED) { 795 syslog(LOG_ERR, 796 "UCM configuration for device '%s' missing" 797 " PlaybackPCM or CapturePCM definition.", 798 dev_name); 799 goto error_cleanup; 800 } 801 802 if (dev_idx == -1) { 803 syslog(LOG_ERR, 804 "PlaybackPCM or CapturePCM for '%s' must be in" 805 " the form 'hw:<card>,<number>'", dev_name); 806 goto error_cleanup; 807 } 808 809 jack_name = ucm_get_jack_name_for_dev(mgr, dev_name); 810 jack_type = ucm_get_jack_type_for_dev(mgr, dev_name); 811 mixer_name = ucm_get_mixer_name_for_dev(mgr, dev_name); 812 813 dev_sec = ucm_section_create(dev_name, dev_idx, dir, 814 jack_name, jack_type); 815 if (jack_name) 816 free((void *)jack_name); 817 if (jack_type) 818 free((void *)jack_type); 819 820 if (!dev_sec) { 821 syslog(LOG_ERR, "Failed to allocate memory."); 822 if (mixer_name) 823 free((void *)mixer_name); 824 goto error_cleanup; 825 } 826 827 dev_sec->jack_switch = 828 ucm_get_jack_switch_for_dev(mgr, dev_name); 829 830 if (mixer_name) { 831 rc = ucm_section_set_mixer_name(dev_sec, mixer_name); 832 free((void *)mixer_name); 833 if (rc) 834 goto error_cleanup; 835 } 836 837 m_name = ucm_get_mixer_names(mgr, dev_name, coupled_mixers, 838 dir, MIXER_NAME_VOLUME); 839 ucm_section_concat_coupled(dev_sec, m_name); 840 841 DL_APPEND(sections, dev_sec); 842 ucm_section_dump(dev_sec); 843 } 844 845 if (num_devs > 0) 846 snd_use_case_free_list(list, num_devs); 847 return sections; 848 849error_cleanup: 850 if (num_devs > 0) 851 snd_use_case_free_list(list, num_devs); 852 ucm_section_free_list(sections); 853 return NULL; 854} 855 856char *ucm_get_hotword_models(struct cras_use_case_mgr *mgr) 857{ 858 const char **list; 859 int i, num_entries; 860 int models_len = 0; 861 char *models = NULL; 862 const char *tmp; 863 char *identifier; 864 865 identifier = snd_use_case_identifier("_modifiers/%s", uc_verb(mgr)); 866 num_entries = snd_use_case_get_list(mgr->mgr, identifier, &list); 867 free(identifier); 868 if (num_entries <= 0) 869 return 0; 870 models = (char *)malloc(num_entries * 8); 871 for (i = 0; i < num_entries; i+=2) { 872 if (!list[i]) 873 continue; 874 if (0 == strncmp(list[i], hotword_model_prefix, 875 strlen(hotword_model_prefix))) { 876 tmp = list[i] + strlen(hotword_model_prefix); 877 while (isspace(*tmp)) 878 tmp++; 879 strcpy(models + models_len, tmp); 880 models_len += strlen(tmp); 881 if (i + 2 >= num_entries) 882 models[models_len] = '\0'; 883 else 884 models[models_len++] = ','; 885 } 886 } 887 snd_use_case_free_list(list, num_entries); 888 889 return models; 890} 891 892int ucm_set_hotword_model(struct cras_use_case_mgr *mgr, const char *model) 893{ 894 const char **list; 895 int num_enmods, mod_idx; 896 char *model_mod = NULL; 897 size_t model_mod_size = strlen(model) + 1 + 898 strlen(hotword_model_prefix) + 1; 899 model_mod = (char *)malloc(model_mod_size); 900 if (!model_mod) 901 return -ENOMEM; 902 snprintf(model_mod, model_mod_size, 903 "%s %s", hotword_model_prefix, model); 904 if (!ucm_mod_exists_with_name(mgr, model_mod)) { 905 free((void *)model_mod); 906 return -EINVAL; 907 } 908 909 /* Disable all currently enabled horword model modifiers. */ 910 num_enmods = snd_use_case_get_list(mgr->mgr, "_enamods", &list); 911 if (num_enmods <= 0) 912 goto enable_mod; 913 914 for (mod_idx = 0; mod_idx < num_enmods; mod_idx++) { 915 if (!strncmp(list[mod_idx], hotword_model_prefix, 916 strlen(hotword_model_prefix))) 917 ucm_set_modifier_enabled(mgr, list[mod_idx], 0); 918 } 919 snd_use_case_free_list(list, num_enmods); 920 921enable_mod: 922 ucm_set_modifier_enabled(mgr, model_mod, 1); 923 924 return 0; 925} 926 927int ucm_has_fully_specified_ucm_flag(struct cras_use_case_mgr *mgr) 928{ 929 char *flag; 930 int ret = 0; 931 flag = ucm_get_flag(mgr, fully_specified_ucm_var); 932 if (!flag) 933 return 0; 934 ret = !strcmp(flag, "1"); 935 free(flag); 936 return ret; 937} 938 939const char *ucm_get_mixer_name_for_dev(struct cras_use_case_mgr *mgr, const char *dev) 940{ 941 const char *name = NULL; 942 int rc; 943 944 rc = get_var(mgr, mixer_var, dev, uc_verb(mgr), &name); 945 if (rc) 946 return NULL; 947 948 return name; 949} 950 951struct mixer_name *ucm_get_main_volume_names(struct cras_use_case_mgr *mgr) 952{ 953 return ucm_get_mixer_names(mgr, "", main_volume_names, 954 CRAS_STREAM_OUTPUT, MIXER_NAME_MAIN_VOLUME); 955} 956 957int ucm_list_section_devices_by_device_name( 958 struct cras_use_case_mgr *mgr, 959 enum CRAS_STREAM_DIRECTION direction, 960 const char *device_name, 961 ucm_list_section_devices_callback cb, 962 void *cb_arg) 963{ 964 int listed= 0; 965 struct section_name *section_names, *c; 966 const char* var; 967 char *identifier; 968 969 if (direction == CRAS_STREAM_OUTPUT) 970 var = playback_device_name_var; 971 else if (direction == CRAS_STREAM_INPUT) 972 var = capture_device_name_var; 973 else 974 return 0; 975 976 identifier = snd_use_case_identifier("_devices/%s", uc_verb(mgr)); 977 section_names = ucm_get_sections_for_var( 978 mgr, var, device_name, identifier, direction); 979 free(identifier); 980 if (!section_names) 981 return 0; 982 983 DL_FOREACH(section_names, c) { 984 cb(c->name, cb_arg); 985 listed++; 986 } 987 988 DL_FOREACH(section_names, c) { 989 DL_DELETE(section_names, c); 990 free((void*)c->name); 991 free(c); 992 } 993 return listed; 994} 995 996const char *ucm_get_jack_name_for_dev(struct cras_use_case_mgr *mgr, 997 const char *dev) 998{ 999 const char *name = NULL; 1000 int rc; 1001 1002 rc = get_var(mgr, jack_var, dev, uc_verb(mgr), &name); 1003 if (rc) 1004 return NULL; 1005 1006 return name; 1007} 1008 1009const char *ucm_get_jack_type_for_dev(struct cras_use_case_mgr *mgr, 1010 const char *dev) 1011{ 1012 const char *name = NULL; 1013 int rc; 1014 1015 rc = get_var(mgr, jack_type_var, dev, uc_verb(mgr), &name); 1016 if (rc) 1017 return NULL; 1018 1019 if (strcmp(name, "hctl") && strcmp(name, "gpio")) { 1020 syslog(LOG_ERR, "Unknown jack type: %s", name); 1021 return NULL; 1022 } 1023 return name; 1024} 1025 1026int ucm_get_jack_switch_for_dev(struct cras_use_case_mgr *mgr, const char *dev) 1027{ 1028 int value; 1029 1030 int rc = get_int(mgr, jack_switch_var, dev, uc_verb(mgr), &value); 1031 if (rc || value < 0) 1032 return -1; 1033 return value; 1034} 1035 1036unsigned int ucm_get_dma_period_for_dev(struct cras_use_case_mgr *mgr, 1037 const char *dev) 1038{ 1039 int value; 1040 1041 int rc = get_int(mgr, dma_period_var, dev, uc_verb(mgr), &value); 1042 if (rc || value < 0) 1043 return 0; 1044 return value; 1045} 1046 1047unsigned int ucm_get_enable_htimestamp_flag(struct cras_use_case_mgr *mgr) 1048{ 1049 char *flag; 1050 int ret = 0; 1051 flag = ucm_get_flag(mgr, enable_htimestamp_var); 1052 if (!flag) 1053 return 0; 1054 ret = !strcmp(flag, "1"); 1055 free(flag); 1056 return ret; 1057} 1058