Home | History | Annotate | Download | only in server
      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 
     15 static const char jack_var[] = "JackName";
     16 static const char jack_type_var[] = "JackType";
     17 static const char jack_switch_var[] = "JackSwitch";
     18 static const char edid_var[] = "EDIDFile";
     19 static const char cap_var[] = "CaptureControl";
     20 static const char mic_positions[] = "MicPositions";
     21 static const char override_type_name_var[] = "OverrideNodeType";
     22 static const char output_dsp_name_var[] = "OutputDspName";
     23 static const char input_dsp_name_var[] = "InputDspName";
     24 static const char mixer_var[] = "MixerName";
     25 static const char swap_mode_suffix[] = "Swap Mode";
     26 static const char min_buffer_level_var[] = "MinBufferLevel";
     27 static const char dma_period_var[] = "DmaPeriodMicrosecs";
     28 static const char disable_software_volume[] = "DisableSoftwareVolume";
     29 static const char playback_device_name_var[] = "PlaybackPCM";
     30 static const char playback_device_rate_var[] = "PlaybackRate";
     31 static const char capture_device_name_var[] = "CapturePCM";
     32 static const char capture_device_rate_var[] = "CaptureRate";
     33 static const char capture_channel_map_var[] = "CaptureChannelMap";
     34 static 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. */
     37 static const char max_software_gain[] = "MaxSoftwareGain";
     38 /* Set this value in a SectionDevice to specify the default node gain in dBm. */
     39 static const char default_node_gain[] = "DefaultNodeGain";
     40 static const char hotword_model_prefix[] = "Hotword Model";
     41 static const char fully_specified_ucm_var[] = "FullySpecifiedUCM";
     42 static const char main_volume_names[] = "MainVolumeNames";
     43 static const char enable_htimestamp_var[] = "EnableHtimestamp";
     44 
     45 /* Use case verbs corresponding to CRAS_STREAM_TYPE. */
     46 static 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. */
     55 struct section_name {
     56 	const char* name;
     57 	struct section_name  *prev, *next;
     58 };
     59 
     60 struct 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 
     67 static inline const char *uc_verb(struct cras_use_case_mgr *mgr)
     68 {
     69 	return use_case_verbs[mgr->use_case];
     70 }
     71 
     72 static 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 
     93 static 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 
    111 static 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 
    128 static 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 
    144 static 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 
    150 static 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 
    161 static 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 
    187 static 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 
    213 static 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 
    225 static 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. */
    238 static 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 
    286 static 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 
    301 static 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 
    314 static 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  */
    330 static 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 
    357 struct 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 
    398 cleanup_mgr:
    399 	snd_use_case_mgr_close(mgr->mgr);
    400 cleanup:
    401 	free(mgr);
    402 	return NULL;
    403 }
    404 
    405 void ucm_destroy(struct cras_use_case_mgr *mgr)
    406 {
    407 	snd_use_case_mgr_close(mgr->mgr);
    408 	free(mgr);
    409 }
    410 
    411 int 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 
    434 int ucm_swap_mode_exists(struct cras_use_case_mgr *mgr)
    435 {
    436 	return ucm_mod_exists_with_suffix(mgr, swap_mode_suffix);
    437 }
    438 
    439 int 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 
    463 int 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 
    471 char *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 
    487 char *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 
    502 char *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 
    517 const 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 
    531 char *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 
    562 char *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 
    582 const 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 
    595 const 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 
    611 const 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 
    617 unsigned 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 
    629 unsigned 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 
    641 int 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 
    654 int 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 
    667 const 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 
    678 int 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 
    699 int 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 
    723 struct 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 
    731 static 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 
    746 struct 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 
    849 error_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 
    856 char *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 
    892 int 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 
    921 enable_mod:
    922 	ucm_set_modifier_enabled(mgr, model_mod, 1);
    923 
    924 	return 0;
    925 }
    926 
    927 int 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 
    939 const 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 
    951 struct 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 
    957 int 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 
    996 const 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 
   1009 const 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 
   1026 int 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 
   1036 unsigned 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 
   1047 unsigned 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