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