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