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