• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  This library is free software; you can redistribute it and/or
3  *  modify it under the terms of the GNU Lesser General Public
4  *  License as published by the Free Software Foundation; either
5  *  version 2 of the License, or (at your option) any later version.
6  *
7  *  This library is distributed in the hope that it will be useful,
8  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
10  *  Lesser General Public License for more details.
11  *
12  *  You should have received a copy of the GNU Lesser General Public
13  *  License along with this library; if not, write to the Free Software
14  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
15  *
16  *  Support for the verb/device/modifier core logic and API,
17  *  command line tool and file parser was kindly sponsored by
18  *  Texas Instruments Inc.
19  *  Support for multiple active modifiers and devices,
20  *  transition sequences, multiple client access and user defined use
21  *  cases was kindly sponsored by Wolfson Microelectronics PLC.
22  *
23  *  Copyright (C) 2008-2010 SlimLogic Ltd
24  *  Copyright (C) 2010 Wolfson Microelectronics PLC
25  *  Copyright (C) 2010 Texas Instruments Inc.
26  *  Copyright (C) 2010 Red Hat Inc.
27  *  Authors: Liam Girdwood <lrg@slimlogic.co.uk>
28  *	         Stefan Schmidt <stefan@slimlogic.co.uk>
29  *	         Justin Xu <justinx@slimlogic.co.uk>
30  *               Jaroslav Kysela <perex@perex.cz>
31  */
32 
33 #include "ucm_local.h"
34 #include "../control/control_local.h"
35 #include <stdbool.h>
36 #include <ctype.h>
37 #include <stdarg.h>
38 #include <pthread.h>
39 #include <sys/stat.h>
40 #include <sys/wait.h>
41 #include <limits.h>
42 
43 /*
44  * misc
45  */
46 
47 static int get_value(snd_use_case_mgr_t *uc_mgr,
48 			const char *identifier,
49 			char **value,
50 			const char *mod_dev_name,
51 			const char *verb_name,
52 			int exact);
53 static int get_value1(snd_use_case_mgr_t *uc_mgr, char **value,
54 		      struct list_head *value_list, const char *identifier);
55 static int get_value3(snd_use_case_mgr_t *uc_mgr,
56 		      char **value,
57 		      const char *identifier,
58 		      struct list_head *value_list1,
59 		      struct list_head *value_list2,
60 		      struct list_head *value_list3);
61 
62 static int execute_component_seq(snd_use_case_mgr_t *uc_mgr,
63 				 struct component_sequence *cmpt_seq,
64 				 struct list_head *value_list1,
65 				 struct list_head *value_list2,
66 				 struct list_head *value_list3,
67 				 char *cdev);
68 
check_identifier(const char * identifier,const char * prefix)69 static int check_identifier(const char *identifier, const char *prefix)
70 {
71 	int len;
72 
73 	len = strlen(prefix);
74 	if (strncmp(identifier, prefix, len) != 0)
75 		return 0;
76 
77 	if (identifier[len] == 0 || identifier[len] == '/')
78 		return 1;
79 
80 	return 0;
81 }
82 
list_count(struct list_head * list)83 static int list_count(struct list_head *list)
84 {
85 	struct list_head *pos;
86 	int count = 0;
87 
88 	list_for_each(pos, list) {
89 		count += 1;
90 	}
91 	return count;
92 }
93 
alloc_str_list(struct list_head * list,int mult,char ** result[])94 static int alloc_str_list(struct list_head *list, int mult, char **result[])
95 {
96 	char **res;
97 	int cnt;
98 
99 	cnt = list_count(list) * mult;
100 	if (cnt == 0) {
101 		*result = NULL;
102 		return cnt;
103 	}
104 	res = calloc(mult, cnt * sizeof(char *));
105 	if (res == NULL)
106 		return -ENOMEM;
107 	*result = res;
108 	return cnt;
109 }
110 
111 /**
112  * \brief Create an identifier
113  * \param fmt Format (sprintf like)
114  * \param ... Optional arguments for sprintf like format
115  * \return Allocated string identifier or NULL on error
116  */
snd_use_case_identifier(const char * fmt,...)117 char *snd_use_case_identifier(const char *fmt, ...)
118 {
119 	char *str, *res;
120 	int size = strlen(fmt) + 512;
121 	va_list args;
122 
123 	str = malloc(size);
124 	if (str == NULL)
125 		return NULL;
126 	va_start(args, fmt);
127 	vsnprintf(str, size, fmt, args);
128 	va_end(args);
129 	str[size-1] = '\0';
130 	res = realloc(str, strlen(str) + 1);
131 	if (res)
132 		return res;
133 	return str;
134 }
135 
136 /**
137  * \brief Free a string list
138  * \param list The string list to free
139  * \param items Count of strings
140  * \return Zero if success, otherwise a negative error code
141  */
snd_use_case_free_list(const char * list[],int items)142 int snd_use_case_free_list(const char *list[], int items)
143 {
144 	int i;
145 	if (list == NULL)
146 		return 0;
147 	for (i = 0; i < items; i++)
148 		free((void *)list[i]);
149 	free(list);
150 	return 0;
151 }
152 
read_tlv_file(unsigned int ** res,const char * filepath)153 static int read_tlv_file(unsigned int **res,
154 			 const char *filepath)
155 {
156 	int err = 0;
157 	int fd;
158 	struct stat st;
159 	size_t sz;
160 	ssize_t sz_read;
161 	struct snd_ctl_tlv *tlv;
162 
163 	fd = open(filepath, O_RDONLY);
164 	if (fd < 0) {
165 		err = -errno;
166 		return err;
167 	}
168 	if (fstat(fd, &st) == -1) {
169 		err = -errno;
170 		goto __fail;
171 	}
172 	sz = st.st_size;
173 	if (sz > 16 * 1024 * 1024 || sz < 8 || sz % 4) {
174 		uc_error("File size should be less than 16 MB "
175 			 "and multiple of 4");
176 		err = -EINVAL;
177 		goto __fail;
178 	}
179 	*res = malloc(sz);
180 	if (res == NULL) {
181 		err = -ENOMEM;
182 		goto __fail;
183 	}
184 	sz_read = read(fd, *res, sz);
185 	if (sz_read < 0 || (size_t)sz_read != sz) {
186 		err = -EIO;
187 		free(*res);
188 		*res = NULL;
189 	}
190 	/* Check if the tlv file specifies valid size. */
191 	tlv = (struct snd_ctl_tlv *)(*res);
192 	if (tlv->length + 2 * sizeof(unsigned int) != sz) {
193 		uc_error("Invalid tlv size: %d", tlv->length);
194 		err = -EINVAL;
195 		free(*res);
196 		*res = NULL;
197 	}
198 
199 __fail:
200 	close(fd);
201 	return err;
202 }
203 
binary_file_parse(snd_ctl_elem_value_t * dst,snd_ctl_elem_info_t * info,const char * filepath)204 static int binary_file_parse(snd_ctl_elem_value_t *dst,
205 			      snd_ctl_elem_info_t *info,
206 			      const char *filepath)
207 {
208 	int err = 0;
209 	int fd;
210 	struct stat st;
211 	size_t sz;
212 	ssize_t sz_read;
213 	char *res;
214 	snd_ctl_elem_type_t type;
215 	unsigned int idx, count;
216 
217 	type = snd_ctl_elem_info_get_type(info);
218 	if (type != SND_CTL_ELEM_TYPE_BYTES) {
219 		uc_error("only support byte type!");
220 		err = -EINVAL;
221 		return err;
222 	}
223 	fd = open(filepath, O_RDONLY);
224 	if (fd < 0) {
225 		err = -errno;
226 		return err;
227 	}
228 	if (stat(filepath, &st) == -1) {
229 		err = -errno;
230 		goto __fail;
231 	}
232 	sz = st.st_size;
233 	count = snd_ctl_elem_info_get_count(info);
234 	if (sz != count || sz > sizeof(dst->value.bytes)) {
235 		uc_error("invalid parameter size %d!", sz);
236 		err = -EINVAL;
237 		goto __fail;
238 	}
239 	res = malloc(sz);
240 	if (res == NULL) {
241 		err = -ENOMEM;
242 		goto __fail;
243 	}
244 	sz_read = read(fd, res, sz);
245 	if (sz_read < 0 || (size_t)sz_read != sz) {
246 		err = -errno;
247 		goto __fail_read;
248 	}
249 	for (idx = 0; idx < sz; idx++)
250 		snd_ctl_elem_value_set_byte(dst, idx, *(res + idx));
251       __fail_read:
252 	free(res);
253       __fail:
254 	close(fd);
255 	return err;
256 }
257 
parse_type(const char * p,const char * prefix,size_t len,snd_ctl_elem_info_t * info)258 static const char *parse_type(const char *p, const char *prefix, size_t len,
259 			      snd_ctl_elem_info_t *info)
260 {
261 	if (strncasecmp(p, prefix, len))
262 		return p;
263 	p += len;
264 	if (info->type != SND_CTL_ELEM_TYPE_NONE)
265 		return NULL;
266 	if (strncasecmp(p, "bool", sizeof("bool") - 1) == 0)
267 		info->type = SND_CTL_ELEM_TYPE_BOOLEAN;
268 	else if (strncasecmp(p, "integer64", sizeof("integer64") - 1) == 0)
269 		info->type = SND_CTL_ELEM_TYPE_INTEGER64;
270 	else if (strncasecmp(p, "int64", sizeof("int64") - 1) == 0)
271 		info->type = SND_CTL_ELEM_TYPE_INTEGER64;
272 	else if (strncasecmp(p, "int", sizeof("int") - 1) == 0)
273 		info->type = SND_CTL_ELEM_TYPE_INTEGER;
274 	else if (strncasecmp(p, "enum", sizeof("enum") - 1) == 0)
275 		info->type = SND_CTL_ELEM_TYPE_ENUMERATED;
276 	else if (strncasecmp(p, "bytes", sizeof("bytes") - 1) == 0)
277 		info->type = SND_CTL_ELEM_TYPE_BYTES;
278 	else
279 		return NULL;
280 	while (isalpha(*p))
281 		p++;
282 	return p;
283 }
284 
parse_uint(const char * p,const char * prefix,size_t len,unsigned int min,unsigned int max,unsigned int * rval)285 static const char *parse_uint(const char *p, const char *prefix, size_t len,
286 			      unsigned int min, unsigned int max, unsigned int *rval)
287 {
288 	long v;
289 	char *end;
290 
291 	if (strncasecmp(p, prefix, len))
292 		return p;
293 	p += len;
294 	v = strtol(p, &end, 0);
295 	if (*end != '\0' && *end != ' ' && *end != ',') {
296 		uc_error("unable to parse '%s'", prefix);
297 		return NULL;
298 	}
299 	if (v < min || v > max) {
300 		uc_error("value '%s' out of range %u-%u %(%ld)", min, max, v);
301 		return NULL;
302 	}
303 	*rval = v;
304 	return end;
305 }
306 
parse_labels(const char * p,const char * prefix,size_t len,snd_ctl_elem_info_t * info)307 static const char *parse_labels(const char *p, const char *prefix, size_t len,
308 				snd_ctl_elem_info_t *info)
309 {
310 	const char *s;
311 	char *buf, *bp;
312 	size_t l;
313 	int c;
314 
315 	if (info->type != SND_CTL_ELEM_TYPE_ENUMERATED)
316 		return NULL;
317 	if (strncasecmp(p, prefix, len))
318 		return p;
319 	p += len;
320 	s = p;
321 	c = *s;
322 	l = 0;
323 	if (c == '\'' || c == '\"') {
324 		s++;
325 		while (*s && *s != c) {
326 			s++, l++;
327 		}
328 		if (*s == c)
329 			s++;
330 	} else {
331 		while (*s && *s != ',')
332 			l++;
333 	}
334 	if (l == 0)
335 		return NULL;
336 	buf = malloc(l + 1);
337 	if (buf == NULL)
338 		return NULL;
339 	memcpy(buf, p + ((c == '\'' || c == '\"') ? 1 : 0), l);
340 	buf[l] = '\0';
341 	info->value.enumerated.items = 1;
342 	for (bp = buf; *bp; bp++) {
343 		if (*bp == ';') {
344 			if (bp == buf || bp[1] == ';') {
345 				free(buf);
346 				return NULL;
347 			}
348 			info->value.enumerated.items++;
349 			*bp = '\0';
350 		}
351 	}
352 	info->value.enumerated.names_ptr = (uintptr_t)buf;
353 	info->value.enumerated.names_length = l + 1;
354 	return s;
355 }
356 
parse_cset_new_info(snd_ctl_elem_info_t * info,const char * s,const char ** pos)357 static int parse_cset_new_info(snd_ctl_elem_info_t *info, const char *s, const char **pos)
358 {
359 	const char *p = s, *op;
360 
361 	info->count = 1;
362 	while (*s) {
363 		op = p;
364 		p = parse_type(p, "type=", sizeof("type=") - 1, info);
365 		if (p != op)
366 			goto next;
367 		p = parse_uint(p, "elements=", sizeof("elements=") - 1, 1, 128, (unsigned int *)&info->owner);
368 		if (p != op)
369 			goto next;
370 		p = parse_uint(p, "count=", sizeof("count=") - 1, 1, 128, &info->count);
371 		if (p != op)
372 			goto next;
373 		p = parse_labels(p, "labels=", sizeof("labels=") - 1, info);
374 next:
375 		if (p == NULL)
376 			goto er;
377 		if (*p == ',')
378 			p++;
379 		if (isspace(*p))
380 			break;
381 		if (op == p)
382 			goto er;
383 	}
384 	*pos = p;
385 	return 0;
386 er:
387 	uc_error("unknown syntax '%s'", p);
388 	return -EINVAL;
389 }
390 
execute_cset(snd_ctl_t * ctl,const char * cset,unsigned int type)391 static int execute_cset(snd_ctl_t *ctl, const char *cset, unsigned int type)
392 {
393 	const char *pos;
394 	int err;
395 	snd_ctl_elem_id_t *id;
396 	snd_ctl_elem_value_t *value;
397 	snd_ctl_elem_info_t *info, *info2 = NULL;
398 	unsigned int *res = NULL;
399 
400 	snd_ctl_elem_id_malloc(&id);
401 	snd_ctl_elem_value_malloc(&value);
402 	snd_ctl_elem_info_malloc(&info);
403 
404 	err = __snd_ctl_ascii_elem_id_parse(id, cset, &pos);
405 	if (err < 0)
406 		goto __fail;
407 	while (*pos && isspace(*pos))
408 		pos++;
409 	if (type == SEQUENCE_ELEMENT_TYPE_CSET_NEW) {
410 		snd_ctl_elem_info_malloc(&info2);
411 		snd_ctl_elem_info_set_id(info2, id);
412 		err = parse_cset_new_info(info2, pos, &pos);
413 		if (err < 0 || !*pos) {
414 			uc_error("undefined or wrong id config for cset-new", cset);
415 			err = -EINVAL;
416 			goto __fail;
417 		}
418 		while (*pos && isspace(*pos))
419 			pos++;
420 	}
421 	if (!*pos) {
422 		if (type != SEQUENCE_ELEMENT_TYPE_CTL_REMOVE) {
423 			uc_error("undefined value for cset >%s<", cset);
424 			err = -EINVAL;
425 			goto __fail;
426 		}
427 	} else if (type == SEQUENCE_ELEMENT_TYPE_CTL_REMOVE) {
428 		uc_error("extra value for ctl-remove >%s<", cset);
429 		err = -EINVAL;
430 		goto __fail;
431 	}
432 
433 	snd_ctl_elem_info_set_id(info, id);
434 	err = snd_ctl_elem_info(ctl, info);
435 	if (type == SEQUENCE_ELEMENT_TYPE_CSET_NEW ||
436 	    type == SEQUENCE_ELEMENT_TYPE_CTL_REMOVE) {
437 		if (err >= 0) {
438 			err = snd_ctl_elem_remove(ctl, id);
439 			if (err < 0) {
440 				uc_error("unable to remove control");
441 				err = -EINVAL;
442 				goto __fail;
443 			}
444 		}
445 		if (type == SEQUENCE_ELEMENT_TYPE_CTL_REMOVE)
446 			goto __ok;
447 		err = __snd_ctl_add_elem_set(ctl, info2, info2->owner, info2->count);
448 		if (err < 0) {
449 			uc_error("unable to create new control");
450 			goto __fail;
451 		}
452 		/* new id copy */
453 		snd_ctl_elem_info_get_id(info2, id);
454 		snd_ctl_elem_info_set_id(info, id);
455 	} else if (err < 0)
456 		goto __fail;
457 	if (type == SEQUENCE_ELEMENT_TYPE_CSET_TLV) {
458 		if (!snd_ctl_elem_info_is_tlv_writable(info)) {
459 			err = -EINVAL;
460 			goto __fail;
461 		}
462 		err = read_tlv_file(&res, pos);
463 		if (err < 0)
464 			goto __fail;
465 		err = snd_ctl_elem_tlv_write(ctl, id, res);
466 		if (err < 0)
467 			goto __fail;
468 	} else {
469 		snd_ctl_elem_value_set_id(value, id);
470 		err = snd_ctl_elem_read(ctl, value);
471 		if (err < 0)
472 			goto __fail;
473 		if (type == SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE)
474 			err = binary_file_parse(value, info, pos);
475 		else
476 			err = snd_ctl_ascii_value_parse(ctl, value, info, pos);
477 		if (err < 0)
478 			goto __fail;
479 		err = snd_ctl_elem_write(ctl, value);
480 		if (err < 0)
481 			goto __fail;
482 		if (type == SEQUENCE_ELEMENT_TYPE_CSET_NEW) {
483 			unsigned int idx;
484 			for (idx = 1; idx < (unsigned int)info2->owner; idx++) {
485 				value->id.numid += 1;
486 				err = snd_ctl_elem_write(ctl, value);
487 				if (err < 0)
488 					goto __fail;
489 			}
490 		}
491 	}
492       __ok:
493 	err = 0;
494       __fail:
495 	free(id);
496 	free(value);
497 	if (info2) {
498 		if (info2->type == SND_CTL_ELEM_TYPE_ENUMERATED)
499 			free((void *)info2->value.enumerated.names_ptr);
500 		free(info2);
501 	}
502 	free(info);
503 	free(res);
504 
505 	return err;
506 }
507 
execute_sysw(const char * sysw)508 static int execute_sysw(const char *sysw)
509 {
510 	char path[PATH_MAX];
511 	const char *e;
512 	char *s, *value;
513 	ssize_t wlen;
514 	size_t len;
515 	int fd, myerrno;
516 	bool ignore_error = false;
517 
518 	if (sysw == NULL || *sysw == '\0')
519 		return 0;
520 
521 	if (sysw[0] == '-') {
522 		ignore_error = true;
523 		sysw++;
524 	}
525 
526 	if (sysw[0] == ':')
527 		return -EINVAL;
528 
529 	s = strdup(sysw[0] != '/' ? sysw : sysw + 1);
530 	if (s == NULL)
531 		return -ENOMEM;
532 
533 	value = strchr(s, ':');
534 	if (!value) {
535 		free(s);
536 		return -EINVAL;
537 	}
538 	*value = '\0';
539 	value++;
540 	len = strlen(value);
541 	if (len < 1) {
542 		free(s);
543 		return -EINVAL;
544 	}
545 
546 	e = uc_mgr_sysfs_root();
547 	if (e == NULL) {
548 		free(s);
549 		return -EINVAL;
550 	}
551 	snprintf(path, sizeof(path), "%s/%s", e, s);
552 
553 	fd = open(path, O_WRONLY|O_CLOEXEC);
554 	if (fd < 0) {
555 		free(s);
556 		if (ignore_error)
557 			return 0;
558 		uc_error("unable to open '%s' for write", path);
559 		return -EINVAL;
560 	}
561 	wlen = write(fd, value, len);
562 	myerrno = errno;
563 	close(fd);
564 	free(s);
565 
566 	if (ignore_error)
567 		return 0;
568 
569 	if (wlen != (ssize_t)len) {
570 		uc_error("unable to write '%s' to '%s': %s", value, path, strerror(myerrno));
571 		return -EINVAL;
572 	}
573 
574 	return 0;
575 }
576 
577 int _snd_config_save_node_value(snd_config_t *n, snd_output_t *out, unsigned int level);
578 
execute_cfgsave(snd_use_case_mgr_t * uc_mgr,const char * filename)579 static int execute_cfgsave(snd_use_case_mgr_t *uc_mgr, const char *filename)
580 {
581 	snd_config_t *config = uc_mgr->local_config;
582 	char *file, *root;
583 	snd_output_t *out;
584 	bool with_root = false;
585 	int err = 0;
586 
587 	file = strdup(filename);
588 	if (!file)
589 		return -ENOMEM;
590 	root = strchr(file, ':');
591 	if (config && root) {
592 		*root++ = '\0';
593 		if (*root == '+') {
594 			with_root = true;
595 			root++;
596 		}
597 		err = snd_config_search(config, root, &config);
598 		if (err < 0) {
599 			uc_error("Unable to find subtree '%s'", root);
600 			goto _err;
601 		}
602 	}
603 
604 	err = snd_output_stdio_open(&out, file, "w+");
605 	if (err < 0) {
606 		uc_error("unable to open file '%s': %s", file, snd_strerror(err));
607 		goto _err;
608 	}
609 	if (!config || snd_config_is_empty(config)) {
610 		snd_output_close(out);
611 		goto _err;
612 	}
613 	if (with_root) {
614 		snd_output_printf(out, "%s ", root);
615 		err = _snd_config_save_node_value(config, out, 0);
616 	} else {
617 		err = snd_config_save(config, out);
618 	}
619 	snd_output_close(out);
620 	if (err < 0) {
621 		uc_error("unable to save configuration: %s", snd_strerror(err));
622 		goto _err;
623 	}
624 _err:
625 	free(file);
626 	return err;
627 }
628 
rewrite_device_value(snd_use_case_mgr_t * uc_mgr,const char * name,char ** value)629 static int rewrite_device_value(snd_use_case_mgr_t *uc_mgr, const char *name, char **value)
630 {
631 	char *sval;
632 	size_t l;
633 	static const char **s, *_prefix[] = {
634 		"PlaybackCTL",
635 		"CaptureCTL",
636 		"PlaybackMixer",
637 		"CaptureMixer",
638 		"PlaybackPCM",
639 		"CapturePCM",
640 		NULL
641 	};
642 
643 	if (!uc_mgr_has_local_config(uc_mgr))
644 		return 0;
645 	for (s = _prefix; *s && *value; s++) {
646 		if (strcmp(*s, name) != 0)
647 			continue;
648 		l = strlen(*value) + 9 + 1;
649 		sval = malloc(l);
650 		if (sval == NULL) {
651 			free(*value);
652 			*value = NULL;
653 			return -ENOMEM;
654 		}
655 		snprintf(sval, l, "_ucm%04X.%s", uc_mgr->ucm_card_number, *value);
656 		free(*value);
657 		*value = sval;
658 		break;
659 	}
660 	return 0;
661 }
662 
663 /**
664  * \brief Execute the sequence
665  * \param uc_mgr Use case manager
666  * \param seq Sequence
667  * \return zero on success, otherwise a negative error code
668  */
execute_sequence(snd_use_case_mgr_t * uc_mgr,struct list_head * seq,struct list_head * value_list1,struct list_head * value_list2,struct list_head * value_list3)669 static int execute_sequence(snd_use_case_mgr_t *uc_mgr,
670 			    struct list_head *seq,
671 			    struct list_head *value_list1,
672 			    struct list_head *value_list2,
673 			    struct list_head *value_list3)
674 {
675 	struct list_head *pos;
676 	struct sequence_element *s;
677 	char *cdev = NULL;
678 	snd_ctl_t *ctl = NULL;
679 	struct ctl_list *ctl_list;
680 	bool ignore_error;
681 	int err = 0;
682 
683 	list_for_each(pos, seq) {
684 		s = list_entry(pos, struct sequence_element, list);
685 		switch (s->type) {
686 		case SEQUENCE_ELEMENT_TYPE_CDEV:
687 			cdev = strdup(s->data.cdev);
688 			if (cdev == NULL)
689 				goto __fail_nomem;
690 			if (rewrite_device_value(uc_mgr, "PlaybackCTL", &cdev))
691 				goto __fail_nomem;
692 			break;
693 		case SEQUENCE_ELEMENT_TYPE_CSET:
694 		case SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE:
695 		case SEQUENCE_ELEMENT_TYPE_CSET_TLV:
696 		case SEQUENCE_ELEMENT_TYPE_CSET_NEW:
697 		case SEQUENCE_ELEMENT_TYPE_CTL_REMOVE:
698 			if (cdev == NULL && uc_mgr->in_component_domain) {
699 				/* For sequence of a component device, use
700 				 * its parent's cdev stored by ucm manager.
701 				 */
702 				if (uc_mgr->cdev == NULL) {
703 					uc_error("cdev is not defined!");
704 					return err;
705 				}
706 
707 				cdev = strndup(uc_mgr->cdev, PATH_MAX);
708 				if (!cdev)
709 					return -ENOMEM;
710 			} else if (cdev == NULL) {
711 				char *playback_ctl = NULL;
712 				char *capture_ctl = NULL;
713 
714 				err = get_value3(uc_mgr, &playback_ctl, "PlaybackCTL",
715 						 value_list1,
716 						 value_list2,
717 						 value_list3);
718 				if (err < 0 && err != -ENOENT) {
719 					uc_error("cdev is not defined!");
720 					return err;
721 				}
722 				err = get_value3(uc_mgr, &capture_ctl, "CaptureCTL",
723 						 value_list1,
724 						 value_list2,
725 						 value_list3);
726 				if (err < 0 && err != -ENOENT) {
727 					free(playback_ctl);
728 					uc_error("cdev is not defined!");
729 					return err;
730 				}
731 				if (playback_ctl == NULL &&
732 				    capture_ctl == NULL) {
733 					uc_error("cdev is not defined!");
734 					return -EINVAL;
735 				}
736 				if (playback_ctl != NULL &&
737 				    capture_ctl != NULL &&
738 				    strcmp(playback_ctl, capture_ctl) != 0) {
739 					free(playback_ctl);
740 					free(capture_ctl);
741 					uc_error("cdev is not equal for playback and capture!");
742 					return -EINVAL;
743 				}
744 				if (playback_ctl != NULL) {
745 					cdev = playback_ctl;
746 					free(capture_ctl);
747 				} else {
748 					cdev = capture_ctl;
749 				}
750 			}
751 			if (ctl == NULL) {
752 				err = uc_mgr_open_ctl(uc_mgr, &ctl_list, cdev, 1);
753 				if (err < 0) {
754 					uc_error("unable to open ctl device '%s'", cdev);
755 					goto __fail;
756 				}
757 				ctl = ctl_list->ctl;
758 			}
759 			err = execute_cset(ctl, s->data.cset, s->type);
760 			if (err < 0) {
761 				uc_error("unable to execute cset '%s'", s->data.cset);
762 				goto __fail;
763 			}
764 			break;
765 		case SEQUENCE_ELEMENT_TYPE_SYSSET:
766 			err = execute_sysw(s->data.sysw);
767 			if (err < 0)
768 				goto __fail;
769 			break;
770 		case SEQUENCE_ELEMENT_TYPE_SLEEP:
771 			usleep(s->data.sleep);
772 			break;
773 		case SEQUENCE_ELEMENT_TYPE_EXEC:
774 			if (s->data.exec == NULL)
775 				break;
776 			ignore_error = s->data.exec[0] == '-';
777 			err = uc_mgr_exec(s->data.exec + (ignore_error ? 1 : 0));
778 			if (ignore_error == false && err != 0) {
779 				uc_error("exec '%s' failed (exit code %d)", s->data.exec, err);
780 				goto __fail;
781 			}
782 			break;
783 		case SEQUENCE_ELEMENT_TYPE_SHELL:
784 			if (s->data.exec == NULL)
785 				break;
786 			ignore_error = s->data.exec[0] == '-';
787 shell_retry:
788 			err = system(s->data.exec + (ignore_error ? 1 : 0));
789 			if (WIFSIGNALED(err)) {
790 				err = -EINTR;
791 			} if (WIFEXITED(err)) {
792 				if (ignore_error == false && WEXITSTATUS(err) != 0) {
793 					uc_error("command '%s' failed (exit code %d)", s->data.exec, WEXITSTATUS(err));
794 					err = -EINVAL;
795 					goto __fail;
796 				}
797 			} else if (err < 0) {
798 				if (errno == EAGAIN)
799 					goto shell_retry;
800 				err = -errno;
801 				goto __fail;
802 			}
803 			break;
804 		case SEQUENCE_ELEMENT_TYPE_CMPT_SEQ:
805 			/* Execute enable or disable sequence of a component
806 			 * device. Pass the cdev defined by the machine device.
807 			 */
808 			err = execute_component_seq(uc_mgr,
809 						    &s->data.cmpt_seq,
810 						    value_list1,
811 						    value_list2,
812 						    value_list3,
813 						    cdev);
814 			if (err < 0)
815 				goto __fail;
816 			break;
817 		case SEQUENCE_ELEMENT_TYPE_CFGSAVE:
818 			err = execute_cfgsave(uc_mgr, s->data.cfgsave);
819 			if (err < 0)
820 				goto __fail;
821 			break;
822 		default:
823 			uc_error("unknown sequence command %i", s->type);
824 			break;
825 		}
826 	}
827 	free(cdev);
828 	return 0;
829       __fail_nomem:
830 	err = -ENOMEM;
831       __fail:
832 	free(cdev);
833 	return err;
834 
835 }
836 
837 /* Execute enable or disable sequence of a component device.
838  *
839  * For a component device (a codec or embedded DSP), its sequence doesn't
840  * specify the sound card device 'cdev', because a component can be reused
841  * by different sound cards (machines). So when executing its sequence, a
842  * parameter 'cdev' is used to pass cdev defined by the sequence of its
843  * parent, the machine device. UCM manger will store the cdev when entering
844  * the component domain.
845  */
execute_component_seq(snd_use_case_mgr_t * uc_mgr,struct component_sequence * cmpt_seq,struct list_head * value_list1 ATTRIBUTE_UNUSED,struct list_head * value_list2 ATTRIBUTE_UNUSED,struct list_head * value_list3 ATTRIBUTE_UNUSED,char * cdev)846 static int execute_component_seq(snd_use_case_mgr_t *uc_mgr,
847 				 struct component_sequence *cmpt_seq,
848 				 struct list_head *value_list1 ATTRIBUTE_UNUSED,
849 				 struct list_head *value_list2 ATTRIBUTE_UNUSED,
850 				 struct list_head *value_list3 ATTRIBUTE_UNUSED,
851 				 char *cdev)
852 {
853 	struct use_case_device *device = cmpt_seq->device;
854 	struct list_head *seq;
855 	int err;
856 
857 	/* enter component domain and store cdev for the component */
858 	uc_mgr->in_component_domain = 1;
859 	uc_mgr->cdev = cdev;
860 
861 	/* choose enable or disable sequence of the component device */
862 	if (cmpt_seq->enable)
863 		seq = &device->enable_list;
864 	else
865 		seq = &device->disable_list;
866 
867 	/* excecute the sequence of the component dev */
868 	err = execute_sequence(uc_mgr, seq,
869 			       &device->value_list,
870 			       &uc_mgr->active_verb->value_list,
871 			       &uc_mgr->value_list);
872 
873 	/* exit component domain and clear cdev */
874 	uc_mgr->in_component_domain = 0;
875 	uc_mgr->cdev = NULL;
876 
877 	return err;
878 }
879 
add_auto_value(snd_use_case_mgr_t * uc_mgr,const char * key,char * value)880 static int add_auto_value(snd_use_case_mgr_t *uc_mgr, const char *key, char *value)
881 {
882 	char *s;
883 	int err;
884 
885 	err = get_value1(uc_mgr, &value, &uc_mgr->value_list, key);
886 	if (err == -ENOENT) {
887 		s = strdup(value);
888 		if (s == NULL)
889 			return -ENOMEM;
890 		return uc_mgr_add_value(&uc_mgr->value_list, key, s);
891 	} else if (err < 0) {
892 		return err;
893 	}
894 	free(value);
895 	return 0;
896 }
897 
add_auto_values(snd_use_case_mgr_t * uc_mgr)898 static int add_auto_values(snd_use_case_mgr_t *uc_mgr)
899 {
900 	struct ctl_list *ctl_list;
901 	const char *id;
902 	char buf[40];
903 	int err;
904 
905 	ctl_list = uc_mgr_get_master_ctl(uc_mgr);
906 	if (ctl_list) {
907 		id = snd_ctl_card_info_get_id(ctl_list->ctl_info);
908 		snprintf(buf, sizeof(buf), "hw:%s", id);
909 		err = add_auto_value(uc_mgr, "PlaybackCTL", buf);
910 		if (err < 0)
911 			return err;
912 		err = add_auto_value(uc_mgr, "CaptureCTL", buf);
913 		if (err < 0)
914 			return err;
915 	}
916 	return 0;
917 }
918 
919 /**
920  * \brief execute default commands
921  * \param uc_mgr Use case manager
922  * \return zero on success, otherwise a negative error code
923  */
set_defaults(snd_use_case_mgr_t * uc_mgr)924 static int set_defaults(snd_use_case_mgr_t *uc_mgr)
925 {
926 	int err;
927 
928 	if (uc_mgr->default_list_executed)
929 		return 0;
930 	err = execute_sequence(uc_mgr, &uc_mgr->default_list,
931 			       &uc_mgr->value_list, NULL, NULL);
932 	if (err < 0) {
933 		uc_error("Unable to execute default sequence");
934 		return err;
935 	}
936 	uc_mgr->default_list_executed = 1;
937 	return 0;
938 }
939 
940 /**
941  * \brief Import master config and execute the default sequence
942  * \param uc_mgr Use case manager
943  * \return zero on success, otherwise a negative error code
944  */
import_master_config(snd_use_case_mgr_t * uc_mgr)945 static int import_master_config(snd_use_case_mgr_t *uc_mgr)
946 {
947 	int err;
948 
949 	err = uc_mgr_import_master_config(uc_mgr);
950 	if (err < 0)
951 		return err;
952 	return add_auto_values(uc_mgr);
953 }
954 
955 /**
956  * \brief Check, if the UCM configuration is empty
957  * \param uc_mgr Use case Manager
958  * \return zero on success, otherwise a negative error code
959  */
check_empty_configuration(snd_use_case_mgr_t * uc_mgr)960 static int check_empty_configuration(snd_use_case_mgr_t *uc_mgr)
961 {
962 	int err;
963 	char *value;
964 
965 	err = get_value(uc_mgr, "Linked", &value, NULL, NULL, 1);
966 	if (err >= 0) {
967 		err = strcasecmp(value, "true") == 0 ||
968 		      strcmp(value, "1") == 0;
969 		free(value);
970 		if (err)
971 			return 0;
972 	}
973 	if (!list_empty(&uc_mgr->verb_list))
974 		return 0;
975 	if (!list_empty(&uc_mgr->fixedboot_list))
976 		return 0;
977 	if (!list_empty(&uc_mgr->boot_list))
978 		return 0;
979 	return -ENXIO;
980 }
981 
982 /**
983  * \brief Universal find - string in a list
984  * \param list List of structures
985  * \param offset Offset of list structure
986  * \param soffset Offset of string structure
987  * \param match String to match
988  * \return structure on success, otherwise a NULL (not found)
989  */
find0(struct list_head * list,unsigned long offset,unsigned long soffset,const char * match)990 static void *find0(struct list_head *list,
991 		   unsigned long offset,
992 		   unsigned long soffset,
993 		   const char *match)
994 {
995 	struct list_head *pos;
996 	char *ptr, *str;
997 
998 	list_for_each(pos, list) {
999 		ptr = list_entry_offset(pos, char, offset);
1000 		str = *((char **)(ptr + soffset));
1001 		if (strcmp(str, match) == 0)
1002 			return ptr;
1003 	}
1004 	return NULL;
1005 }
1006 
1007 #define find(list, type, member, value, match) \
1008 	find0(list, (unsigned long)(&((type *)0)->member), \
1009 		    (unsigned long)(&((type *)0)->value), match)
1010 
1011 /**
1012  * \brief Universal string list
1013  * \param list List of structures
1014  * \param result Result list
1015  * \param offset Offset of list structure
1016  * \param s1offset Offset of string structure
1017  * \return count of items on success, otherwise a negative error code
1018  */
get_list0(struct list_head * list,const char ** result[],unsigned long offset,unsigned long s1offset)1019 static int get_list0(struct list_head *list,
1020 		     const char **result[],
1021 		     unsigned long offset,
1022 		     unsigned long s1offset)
1023 {
1024 	char **res;
1025 	int cnt;
1026 	struct list_head *pos;
1027 	char *ptr, *str1;
1028 
1029 	cnt = alloc_str_list(list, 1, &res);
1030 	if (cnt <= 0) {
1031 		*result = NULL;
1032 		return cnt;
1033 	}
1034 	*result = (const char **)res;
1035 	list_for_each(pos, list) {
1036 		ptr = list_entry_offset(pos, char, offset);
1037 		str1 = *((char **)(ptr + s1offset));
1038 		if (str1 != NULL) {
1039 			*res = strdup(str1);
1040 			if (*res == NULL)
1041 				goto __fail;
1042 		} else {
1043 			*res = NULL;
1044 		}
1045 		res++;
1046 	}
1047 	return cnt;
1048       __fail:
1049 	snd_use_case_free_list(*result, cnt);
1050 	return -ENOMEM;
1051 }
1052 
1053 #define get_list(list, result, type, member, s1) \
1054 	get_list0(list, result, \
1055 		    (unsigned long)(&((type *)0)->member), \
1056 		    (unsigned long)(&((type *)0)->s1))
1057 
1058 /**
1059  * \brief Universal string list - pair of strings
1060  * \param list List of structures
1061  * \param result Result list
1062  * \param offset Offset of list structure
1063  * \param s1offset Offset of string structure
1064  * \param s1offset Offset of string structure
1065  * \return count of items on success, otherwise a negative error code
1066  */
get_list20(struct list_head * list,const char ** result[],unsigned long offset,unsigned long s1offset,unsigned long s2offset)1067 static int get_list20(struct list_head *list,
1068 		      const char **result[],
1069 		      unsigned long offset,
1070 		      unsigned long s1offset,
1071 		      unsigned long s2offset)
1072 {
1073 	char **res;
1074 	int cnt;
1075 	struct list_head *pos;
1076 	char *ptr, *str1, *str2;
1077 
1078 	cnt = alloc_str_list(list, 2, &res);
1079 	if (cnt <= 0) {
1080 		*result = NULL;
1081 		return cnt;
1082 	}
1083 	*result = (const char **)res;
1084 	list_for_each(pos, list) {
1085 		ptr = list_entry_offset(pos, char, offset);
1086 		str1 = *((char **)(ptr + s1offset));
1087 		if (str1 != NULL) {
1088 			*res = strdup(str1);
1089 			if (*res == NULL)
1090 				goto __fail;
1091 		} else {
1092 			*res = NULL;
1093 		}
1094 		res++;
1095 		str2 = *((char **)(ptr + s2offset));
1096 		if (str2 != NULL) {
1097 			*res = strdup(str2);
1098 			if (*res == NULL)
1099 				goto __fail;
1100 		} else {
1101 			*res = NULL;
1102 		}
1103 		res++;
1104 	}
1105 	return cnt;
1106       __fail:
1107 	snd_use_case_free_list(*result, cnt);
1108 	return -ENOMEM;
1109 }
1110 
1111 #define get_list2(list, result, type, member, s1, s2) \
1112 	get_list20(list, result, \
1113 		    (unsigned long)(&((type *)0)->member), \
1114 		    (unsigned long)(&((type *)0)->s1), \
1115 		    (unsigned long)(&((type *)0)->s2))
1116 
1117 /**
1118  * \brief Find verb
1119  * \param uc_mgr Use case manager
1120  * \param verb_name verb to find
1121  * \return structure on success, otherwise a NULL (not found)
1122  */
find_verb(snd_use_case_mgr_t * uc_mgr,const char * verb_name)1123 static inline struct use_case_verb *find_verb(snd_use_case_mgr_t *uc_mgr,
1124 					      const char *verb_name)
1125 {
1126 	return find(&uc_mgr->verb_list,
1127 		    struct use_case_verb, list, name,
1128 		    verb_name);
1129 }
1130 
is_devlist_supported(snd_use_case_mgr_t * uc_mgr,struct dev_list * dev_list)1131 static int is_devlist_supported(snd_use_case_mgr_t *uc_mgr,
1132 	struct dev_list *dev_list)
1133 {
1134 	struct dev_list_node *device;
1135 	struct use_case_device *adev;
1136 	struct list_head *pos, *pos1;
1137 	int found_ret;
1138 
1139 	switch (dev_list->type) {
1140 	case DEVLIST_NONE:
1141 	default:
1142 		return 1;
1143 	case DEVLIST_SUPPORTED:
1144 		found_ret = 1;
1145 		break;
1146 	case DEVLIST_CONFLICTING:
1147 		found_ret = 0;
1148 		break;
1149 	}
1150 
1151 	list_for_each(pos, &dev_list->list) {
1152 		device = list_entry(pos, struct dev_list_node, list);
1153 
1154 		list_for_each(pos1, &uc_mgr->active_devices) {
1155 			adev = list_entry(pos1, struct use_case_device,
1156 					    active_list);
1157 			if (!strcmp(device->name, adev->name))
1158 				return found_ret;
1159 		}
1160 	}
1161 	return 1 - found_ret;
1162 }
1163 
is_modifier_supported(snd_use_case_mgr_t * uc_mgr,struct use_case_modifier * modifier)1164 static inline int is_modifier_supported(snd_use_case_mgr_t *uc_mgr,
1165 	struct use_case_modifier *modifier)
1166 {
1167 	return is_devlist_supported(uc_mgr, &modifier->dev_list);
1168 }
1169 
is_device_supported(snd_use_case_mgr_t * uc_mgr,struct use_case_device * device)1170 static inline int is_device_supported(snd_use_case_mgr_t *uc_mgr,
1171 	struct use_case_device *device)
1172 {
1173 	return is_devlist_supported(uc_mgr, &device->dev_list);
1174 }
1175 
1176 /**
1177  * \brief Find device
1178  * \param verb Use case verb
1179  * \param device_name device to find
1180  * \return structure on success, otherwise a NULL (not found)
1181  */
1182 static inline struct use_case_device *
find_device(snd_use_case_mgr_t * uc_mgr,struct use_case_verb * verb,const char * device_name,int check_supported)1183 	find_device(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb,
1184 		    const char *device_name, int check_supported)
1185 {
1186 	struct use_case_device *device;
1187 	struct list_head *pos;
1188 
1189 	list_for_each(pos, &verb->device_list) {
1190 		device = list_entry(pos, struct use_case_device, list);
1191 
1192 		if (strcmp(device_name, device->name))
1193 			continue;
1194 
1195 		if (check_supported &&
1196 		    !is_device_supported(uc_mgr, device))
1197 			continue;
1198 
1199 		return device;
1200 	}
1201 	return NULL;
1202 }
1203 
1204 /**
1205  * \brief Find modifier
1206  * \param verb Use case verb
1207  * \param modifier_name modifier to find
1208  * \return structure on success, otherwise a NULL (not found)
1209  */
1210 static struct use_case_modifier *
find_modifier(snd_use_case_mgr_t * uc_mgr,struct use_case_verb * verb,const char * modifier_name,int check_supported)1211 	find_modifier(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb,
1212 		      const char *modifier_name, int check_supported)
1213 {
1214 	struct use_case_modifier *modifier;
1215 	struct list_head *pos;
1216 
1217 	list_for_each(pos, &verb->modifier_list) {
1218 		modifier = list_entry(pos, struct use_case_modifier, list);
1219 
1220 		if (strcmp(modifier->name, modifier_name))
1221 			continue;
1222 
1223 		if (check_supported &&
1224 		    !is_modifier_supported(uc_mgr, modifier))
1225 			continue;
1226 
1227 		return modifier;
1228 	}
1229 	return NULL;
1230 }
1231 
device_status(snd_use_case_mgr_t * uc_mgr,const char * device_name)1232 long device_status(snd_use_case_mgr_t *uc_mgr,
1233 		   const char *device_name)
1234 {
1235 	struct use_case_device *dev;
1236 	struct list_head *pos;
1237 
1238 	list_for_each(pos, &uc_mgr->active_devices) {
1239 		dev = list_entry(pos, struct use_case_device, active_list);
1240 		if (strcmp(dev->name, device_name) == 0)
1241 			return 1;
1242 	}
1243 	return 0;
1244 }
1245 
modifier_status(snd_use_case_mgr_t * uc_mgr,const char * modifier_name)1246 long modifier_status(snd_use_case_mgr_t *uc_mgr,
1247 		     const char *modifier_name)
1248 {
1249 	struct use_case_modifier *mod;
1250 	struct list_head *pos;
1251 
1252 	list_for_each(pos, &uc_mgr->active_modifiers) {
1253 		mod = list_entry(pos, struct use_case_modifier, active_list);
1254 		if (strcmp(mod->name, modifier_name) == 0)
1255 			return 1;
1256 	}
1257 	return 0;
1258 }
1259 
1260 /**
1261  * \brief Set verb
1262  * \param uc_mgr Use case manager
1263  * \param verb verb to set
1264  * \param enable nonzero = enable, zero = disable
1265  * \return zero on success, otherwise a negative error code
1266  */
set_verb(snd_use_case_mgr_t * uc_mgr,struct use_case_verb * verb,int enable)1267 static int set_verb(snd_use_case_mgr_t *uc_mgr,
1268 		    struct use_case_verb *verb,
1269 		    int enable)
1270 {
1271 	struct list_head *seq;
1272 	int err;
1273 
1274 	if (enable) {
1275 		err = set_defaults(uc_mgr);
1276 		if (err < 0)
1277 			return err;
1278 		seq = &verb->enable_list;
1279 	} else {
1280 		seq = &verb->disable_list;
1281 	}
1282 	err = execute_sequence(uc_mgr, seq,
1283 			       &verb->value_list,
1284 			       &uc_mgr->value_list,
1285 			       NULL);
1286 	if (enable && err >= 0)
1287 		uc_mgr->active_verb = verb;
1288 	return err;
1289 }
1290 
1291 /**
1292  * \brief Set modifier
1293  * \param uc_mgr Use case manager
1294  * \param modifier modifier to set
1295  * \param enable nonzero = enable, zero = disable
1296  * \return zero on success, otherwise a negative error code
1297  */
set_modifier(snd_use_case_mgr_t * uc_mgr,struct use_case_modifier * modifier,int enable)1298 static int set_modifier(snd_use_case_mgr_t *uc_mgr,
1299 			struct use_case_modifier *modifier,
1300 			int enable)
1301 {
1302 	struct list_head *seq;
1303 	int err;
1304 
1305 	if (modifier_status(uc_mgr, modifier->name) == enable)
1306 		return 0;
1307 
1308 	if (enable) {
1309 		seq = &modifier->enable_list;
1310 	} else {
1311 		seq = &modifier->disable_list;
1312 	}
1313 	err = execute_sequence(uc_mgr, seq,
1314 			       &modifier->value_list,
1315 			       &uc_mgr->active_verb->value_list,
1316 			       &uc_mgr->value_list);
1317 	if (enable && err >= 0) {
1318 		list_add_tail(&modifier->active_list, &uc_mgr->active_modifiers);
1319 	} else if (!enable) {
1320 		list_del(&modifier->active_list);
1321 	}
1322 	return err;
1323 }
1324 
1325 /**
1326  * \brief Set device
1327  * \param uc_mgr Use case manager
1328  * \param device device to set
1329  * \param enable nonzero = enable, zero = disable
1330  * \return zero on success, otherwise a negative error code
1331  */
set_device(snd_use_case_mgr_t * uc_mgr,struct use_case_device * device,int enable)1332 static int set_device(snd_use_case_mgr_t *uc_mgr,
1333 		      struct use_case_device *device,
1334 		      int enable)
1335 {
1336 	struct list_head *seq;
1337 	int err;
1338 
1339 	if (device_status(uc_mgr, device->name) == enable)
1340 		return 0;
1341 
1342 	if (enable) {
1343 		seq = &device->enable_list;
1344 	} else {
1345 		seq = &device->disable_list;
1346 	}
1347 	err = execute_sequence(uc_mgr, seq,
1348 			       &device->value_list,
1349 			       &uc_mgr->active_verb->value_list,
1350 			       &uc_mgr->value_list);
1351 	if (enable && err >= 0) {
1352 		list_add_tail(&device->active_list, &uc_mgr->active_devices);
1353 	} else if (!enable) {
1354 		list_del(&device->active_list);
1355 	}
1356 	return err;
1357 }
1358 
1359 /**
1360  * \brief Init sound card use case manager.
1361  * \param uc_mgr Returned use case manager pointer
1362  * \param card_name name of card to open
1363  * \return zero on success, otherwise a negative error code
1364  */
snd_use_case_mgr_open(snd_use_case_mgr_t ** uc_mgr,const char * card_name)1365 int snd_use_case_mgr_open(snd_use_case_mgr_t **uc_mgr,
1366 			  const char *card_name)
1367 {
1368 	snd_use_case_mgr_t *mgr;
1369 	int err;
1370 
1371 	/* create a new UCM */
1372 	mgr = calloc(1, sizeof(snd_use_case_mgr_t));
1373 	if (mgr == NULL)
1374 		return -ENOMEM;
1375 	INIT_LIST_HEAD(&mgr->verb_list);
1376 	INIT_LIST_HEAD(&mgr->fixedboot_list);
1377 	INIT_LIST_HEAD(&mgr->boot_list);
1378 	INIT_LIST_HEAD(&mgr->default_list);
1379 	INIT_LIST_HEAD(&mgr->value_list);
1380 	INIT_LIST_HEAD(&mgr->active_modifiers);
1381 	INIT_LIST_HEAD(&mgr->active_devices);
1382 	INIT_LIST_HEAD(&mgr->ctl_list);
1383 	INIT_LIST_HEAD(&mgr->variable_list);
1384 	pthread_mutex_init(&mgr->mutex, NULL);
1385 
1386 	if (card_name && *card_name == '-') {
1387 		card_name++;
1388 		mgr->suppress_nodev_errors = 1;
1389 	}
1390 
1391 	err = uc_mgr_card_open(mgr);
1392 	if (err < 0) {
1393 		uc_mgr_free(mgr);
1394 		return err;
1395 	}
1396 
1397 	err = snd_config_top(&mgr->local_config);
1398 	if (err < 0)
1399 		goto _err;
1400 
1401 	mgr->card_name = strdup(card_name);
1402 	if (mgr->card_name == NULL) {
1403 		err = -ENOMEM;
1404 		goto _err;
1405 	}
1406 
1407 	/* get info on use_cases and verify against card */
1408 	err = import_master_config(mgr);
1409 	if (err < 0) {
1410 		if (err == -ENXIO && mgr->suppress_nodev_errors)
1411 			goto _err;
1412 		uc_error("error: failed to import %s use case configuration %d",
1413 			 card_name, err);
1414 		goto _err;
1415 	}
1416 
1417 	err = check_empty_configuration(mgr);
1418 	if (err < 0) {
1419 		uc_error("error: failed to import %s (empty configuration)", card_name);
1420 		goto _err;
1421 	}
1422 
1423 	*uc_mgr = mgr;
1424 	return 0;
1425 
1426 _err:
1427 	uc_mgr_card_close(mgr);
1428 	uc_mgr_free(mgr);
1429 	return err;
1430 }
1431 
1432 /**
1433  * \brief Reload and reparse all use case files.
1434  * \param uc_mgr Use case manager
1435  * \return zero on success, otherwise a negative error code
1436  */
snd_use_case_mgr_reload(snd_use_case_mgr_t * uc_mgr)1437 int snd_use_case_mgr_reload(snd_use_case_mgr_t *uc_mgr)
1438 {
1439 	int err;
1440 
1441 	pthread_mutex_lock(&uc_mgr->mutex);
1442 
1443 	uc_mgr_free_verb(uc_mgr);
1444 
1445 	uc_mgr->default_list_executed = 0;
1446 
1447 	/* reload all use cases */
1448 	err = import_master_config(uc_mgr);
1449 	if (err < 0) {
1450 		uc_error("error: failed to reload use cases");
1451 		pthread_mutex_unlock(&uc_mgr->mutex);
1452 		return -EINVAL;
1453 	}
1454 
1455 	pthread_mutex_unlock(&uc_mgr->mutex);
1456 	return err;
1457 }
1458 
1459 /**
1460  * \brief Close use case manager.
1461  * \param uc_mgr Use case manager
1462  * \return zero on success, otherwise a negative error code
1463  */
snd_use_case_mgr_close(snd_use_case_mgr_t * uc_mgr)1464 int snd_use_case_mgr_close(snd_use_case_mgr_t *uc_mgr)
1465 {
1466 	uc_mgr_card_close(uc_mgr);
1467 	uc_mgr_free(uc_mgr);
1468 
1469 	return 0;
1470 }
1471 
1472 /*
1473  * Tear down current use case verb, device and modifier.
1474  */
dismantle_use_case(snd_use_case_mgr_t * uc_mgr)1475 static int dismantle_use_case(snd_use_case_mgr_t *uc_mgr)
1476 {
1477 	struct list_head *pos, *npos;
1478 	struct use_case_modifier *modifier;
1479 	struct use_case_device *device;
1480 	int err;
1481 
1482 	list_for_each_safe(pos, npos, &uc_mgr->active_modifiers) {
1483 		modifier = list_entry(pos, struct use_case_modifier,
1484 				      active_list);
1485 		err = set_modifier(uc_mgr, modifier, 0);
1486 		if (err < 0)
1487 			uc_error("Unable to disable modifier %s", modifier->name);
1488 	}
1489 	INIT_LIST_HEAD(&uc_mgr->active_modifiers);
1490 
1491 	list_for_each_safe(pos, npos, &uc_mgr->active_devices) {
1492 		device = list_entry(pos, struct use_case_device,
1493 				    active_list);
1494 		err = set_device(uc_mgr, device, 0);
1495 		if (err < 0)
1496 			uc_error("Unable to disable device %s", device->name);
1497 	}
1498 	INIT_LIST_HEAD(&uc_mgr->active_devices);
1499 
1500 	err = set_verb(uc_mgr, uc_mgr->active_verb, 0);
1501 	if (err < 0) {
1502 		uc_error("Unable to disable verb %s", uc_mgr->active_verb->name);
1503 		return err;
1504 	}
1505 	uc_mgr->active_verb = NULL;
1506 
1507 	err = execute_sequence(uc_mgr, &uc_mgr->default_list,
1508 			       &uc_mgr->value_list, NULL, NULL);
1509 
1510 	return err;
1511 }
1512 
1513 /**
1514  * \brief Reset sound card controls to default values.
1515  * \param uc_mgr Use case manager
1516  * \return zero on success, otherwise a negative error code
1517  */
snd_use_case_mgr_reset(snd_use_case_mgr_t * uc_mgr)1518 int snd_use_case_mgr_reset(snd_use_case_mgr_t *uc_mgr)
1519 {
1520 	int err;
1521 
1522 	pthread_mutex_lock(&uc_mgr->mutex);
1523 	err = execute_sequence(uc_mgr, &uc_mgr->default_list,
1524 			       &uc_mgr->value_list, NULL, NULL);
1525 	INIT_LIST_HEAD(&uc_mgr->active_modifiers);
1526 	INIT_LIST_HEAD(&uc_mgr->active_devices);
1527 	uc_mgr->active_verb = NULL;
1528 	pthread_mutex_unlock(&uc_mgr->mutex);
1529 	return err;
1530 }
1531 
1532 /**
1533  * \brief Get list of verbs in pair verbname+comment
1534  * \param list Returned list
1535  * \return Number of list entries if success, otherwise a negative error code
1536  */
get_verb_list(snd_use_case_mgr_t * uc_mgr,const char ** list[])1537 static int get_verb_list(snd_use_case_mgr_t *uc_mgr, const char **list[])
1538 {
1539 	return get_list2(&uc_mgr->verb_list, list,
1540 			 struct use_case_verb, list,
1541 			 name, comment);
1542 }
1543 
1544 /**
1545  * \brief Get list of devices in pair devicename+comment
1546  * \param list Returned list
1547  * \param verbname For verb (NULL = current)
1548  * \return Number of list entries if success, otherwise a negative error code
1549  */
get_device_list(snd_use_case_mgr_t * uc_mgr,const char ** list[],char * verbname)1550 static int get_device_list(snd_use_case_mgr_t *uc_mgr, const char **list[],
1551 			   char *verbname)
1552 {
1553 	struct use_case_verb *verb;
1554 
1555 	if (verbname) {
1556 		verb = find_verb(uc_mgr, verbname);
1557 	} else {
1558 		verb = uc_mgr->active_verb;
1559 	}
1560 	if (verb == NULL)
1561 		return -ENOENT;
1562 	return get_list2(&verb->device_list, list,
1563 			 struct use_case_device, list,
1564 			 name, comment);
1565 }
1566 
1567 /**
1568  * \brief Get list of modifiers in pair devicename+comment
1569  * \param list Returned list
1570  * \param verbname For verb (NULL = current)
1571  * \return Number of list entries if success, otherwise a negative error code
1572  */
get_modifier_list(snd_use_case_mgr_t * uc_mgr,const char ** list[],char * verbname)1573 static int get_modifier_list(snd_use_case_mgr_t *uc_mgr, const char **list[],
1574 			     char *verbname)
1575 {
1576 	struct use_case_verb *verb;
1577 	if (verbname) {
1578 		verb = find_verb(uc_mgr, verbname);
1579 	} else {
1580 		verb = uc_mgr->active_verb;
1581 	}
1582 	if (verb == NULL)
1583 		return -ENOENT;
1584 	return get_list2(&verb->modifier_list, list,
1585 			 struct use_case_modifier, list,
1586 			 name, comment);
1587 }
1588 
1589 /**
1590  * \brief Get list of supported/conflicting devices
1591  * \param list Returned list
1592  * \param name Name of modifier or verb to query
1593  * \param type Type of device list entries to return
1594  * \return Number of list entries if success, otherwise a negative error code
1595  */
get_supcon_device_list(snd_use_case_mgr_t * uc_mgr,const char ** list[],char * name,enum dev_list_type type)1596 static int get_supcon_device_list(snd_use_case_mgr_t *uc_mgr,
1597 				  const char **list[], char *name,
1598 				  enum dev_list_type type)
1599 {
1600 	char *str;
1601 	struct use_case_verb *verb;
1602 	struct use_case_modifier *modifier;
1603 	struct use_case_device *device;
1604 
1605 	if (!name)
1606 		return -ENOENT;
1607 
1608 	str = strchr(name, '/');
1609 	if (str) {
1610 		*str = '\0';
1611 		verb = find_verb(uc_mgr, str + 1);
1612 	}
1613 	else {
1614 		verb = uc_mgr->active_verb;
1615 	}
1616 	if (!verb)
1617 		return -ENOENT;
1618 
1619 	modifier = find_modifier(uc_mgr, verb, name, 0);
1620 	if (modifier) {
1621 		if (modifier->dev_list.type != type) {
1622 			*list = NULL;
1623 			return 0;
1624 		}
1625 		return get_list(&modifier->dev_list.list, list,
1626 				struct dev_list_node, list,
1627 				name);
1628 	}
1629 
1630 	device = find_device(uc_mgr, verb, name, 0);
1631 	if (device) {
1632 		if (device->dev_list.type != type) {
1633 			*list = NULL;
1634 			return 0;
1635 		}
1636 		return get_list(&device->dev_list.list, list,
1637 				struct dev_list_node, list,
1638 				name);
1639 	}
1640 
1641 	return -ENOENT;
1642 }
1643 
1644 /**
1645  * \brief Get list of supported devices
1646  * \param list Returned list
1647  * \param name Name of verb or modifier to query
1648  * \return Number of list entries if success, otherwise a negative error code
1649  */
get_supported_device_list(snd_use_case_mgr_t * uc_mgr,const char ** list[],char * name)1650 static int get_supported_device_list(snd_use_case_mgr_t *uc_mgr,
1651 				     const char **list[], char *name)
1652 {
1653 	return get_supcon_device_list(uc_mgr, list, name, DEVLIST_SUPPORTED);
1654 }
1655 
1656 /**
1657  * \brief Get list of conflicting devices
1658  * \param list Returned list
1659  * \param name Name of verb or modifier to query
1660  * \return Number of list entries if success, otherwise a negative error code
1661  */
get_conflicting_device_list(snd_use_case_mgr_t * uc_mgr,const char ** list[],char * name)1662 static int get_conflicting_device_list(snd_use_case_mgr_t *uc_mgr,
1663 				       const char **list[], char *name)
1664 {
1665 	return get_supcon_device_list(uc_mgr, list, name, DEVLIST_CONFLICTING);
1666 }
1667 
1668 #ifndef DOC_HIDDEN
1669 struct myvalue {
1670 	struct list_head list;
1671 	const char *text;
1672 };
1673 #endif
1674 
1675 /**
1676  * \brief Convert myvalue list string list
1677  * \param list myvalue list
1678  * \param res string list
1679  * \retval Number of list entries if success, otherwise a negativer error code
1680  */
myvalue_to_str_list(struct list_head * list,char *** res)1681 static int myvalue_to_str_list(struct list_head *list, char ***res)
1682 {
1683 	struct list_head *pos;
1684 	struct myvalue *value;
1685 	char **p;
1686 	int cnt;
1687 
1688 	cnt = alloc_str_list(list, 1, res);
1689 	if (cnt < 0)
1690 		return cnt;
1691 	p = *res;
1692 	list_for_each(pos, list) {
1693 		value = list_entry(pos, struct myvalue, list);
1694 		*p = strdup(value->text);
1695 		if (*p == NULL) {
1696 			snd_use_case_free_list((const char **)p, cnt);
1697 			return -ENOMEM;
1698 		}
1699 		p++;
1700 	}
1701 	return cnt;
1702 }
1703 
1704 /**
1705  * \brief Free myvalue list
1706  * \param list myvalue list
1707  */
myvalue_list_free(struct list_head * list)1708 static void myvalue_list_free(struct list_head *list)
1709 {
1710 	struct list_head *pos, *npos;
1711 	struct myvalue *value;
1712 
1713 	list_for_each_safe(pos, npos, list) {
1714 		value = list_entry(pos, struct myvalue, list);
1715 		list_del(&value->list);
1716 		free(value);
1717 	}
1718 }
1719 
1720 /**
1721  * \brief Merge one value to the myvalue list
1722  * \param list The list with values
1723  * \param value The value to be merged (without duplicates)
1724  * \return 1 if dup, 0 if success, otherwise a negative error code
1725  */
merge_value(struct list_head * list,const char * text)1726 static int merge_value(struct list_head *list, const char *text)
1727 {
1728 	struct list_head *pos;
1729 	struct myvalue *value;
1730 
1731 	list_for_each(pos, list) {
1732 		value = list_entry(pos, struct myvalue, list);
1733 		if (strcmp(value->text, text) == 0)
1734 			return 1;
1735 	}
1736 	value = malloc(sizeof(*value));
1737 	if (value == NULL)
1738 		return -ENOMEM;
1739 	value->text = text;
1740 	list_add_tail(&value->list, list);
1741 	return 0;
1742 }
1743 
1744 /**
1745  * \brief Find all values for given identifier
1746  * \param list Returned list
1747  * \param source Source list with ucm_value structures
1748  * \return Zero if success, otherwise a negative error code
1749  */
add_identifiers(struct list_head * list,struct list_head * source)1750 static int add_identifiers(struct list_head *list,
1751 			   struct list_head *source)
1752 {
1753 	struct ucm_value *v;
1754 	struct list_head *pos;
1755 	int err;
1756 
1757 	list_for_each(pos, source) {
1758 		v = list_entry(pos, struct ucm_value, list);
1759 		err = merge_value(list, v->name);
1760 		if (err < 0)
1761 			return err;
1762 	}
1763 	return 0;
1764 }
1765 
1766 /**
1767  * \brief Find all values for given identifier
1768  * \param list Returned list
1769  * \param identifier Identifier
1770  * \param source Source list with ucm_value structures
1771  */
add_values(struct list_head * list,const char * identifier,struct list_head * source)1772 static int add_values(struct list_head *list,
1773 		      const char *identifier,
1774 		      struct list_head *source)
1775 {
1776 	struct ucm_value *v;
1777 	struct list_head *pos;
1778 	int err;
1779 
1780 	list_for_each(pos, source) {
1781 		v = list_entry(pos, struct ucm_value, list);
1782 		if (check_identifier(identifier, v->name)) {
1783 			err = merge_value(list, v->data);
1784 			if (err < 0)
1785 				return err;
1786 		}
1787 	}
1788 	return 0;
1789 }
1790 
1791 /**
1792  * \brief compare two identifiers
1793  */
identifier_cmp(const void * _a,const void * _b)1794 static int identifier_cmp(const void *_a, const void *_b)
1795 {
1796 	const char * const *a = _a;
1797 	const char * const *b = _b;
1798 	return strcmp(*a, *b);
1799 }
1800 
1801 /**
1802  * \brief Get list of available identifiers
1803  * \param list Returned list
1804  * \param name Name of verb or modifier to query
1805  * \return Number of list entries if success, otherwise a negative error code
1806  */
get_identifiers_list(snd_use_case_mgr_t * uc_mgr,const char ** list[],char * name)1807 static int get_identifiers_list(snd_use_case_mgr_t *uc_mgr,
1808 				const char **list[], char *name)
1809 {
1810 	struct use_case_verb *verb;
1811 	struct use_case_modifier *modifier;
1812 	struct use_case_device *device;
1813 	struct list_head mylist;
1814 	struct list_head *value_list;
1815 	char *str, **res;
1816 	int err;
1817 
1818 	if (!name)
1819 		return -ENOENT;
1820 
1821 	str = strchr(name, '/');
1822 	if (str) {
1823 		*str = '\0';
1824 		verb = find_verb(uc_mgr, str + 1);
1825 	}
1826 	else {
1827 		verb = uc_mgr->active_verb;
1828 	}
1829 	if (!verb)
1830 		return -ENOENT;
1831 
1832 	value_list = NULL;
1833 	modifier = find_modifier(uc_mgr, verb, name, 0);
1834 	if (modifier) {
1835 		value_list = &modifier->value_list;
1836 	} else {
1837 		device = find_device(uc_mgr, verb, name, 0);
1838 		if (device)
1839 			value_list = &device->value_list;
1840 	}
1841 	if (value_list == NULL)
1842 		return -ENOENT;
1843 
1844 	INIT_LIST_HEAD(&mylist);
1845 	err = add_identifiers(&mylist, &uc_mgr->value_list);
1846 	if (err < 0)
1847 		goto __fail;
1848 	err = add_identifiers(&mylist, &verb->value_list);
1849 	if (err < 0)
1850 		goto __fail;
1851 	err = add_identifiers(&mylist, value_list);
1852 	if (err < 0)
1853 		goto __fail;
1854 	err = myvalue_to_str_list(&mylist, &res);
1855 	if (err > 0)
1856 		*list = (const char **)res;
1857 	else if (err == 0)
1858 		*list = NULL;
1859 __fail:
1860 	myvalue_list_free(&mylist);
1861 	if (err <= 0)
1862 		return err;
1863 	qsort(*list, err, sizeof(char *), identifier_cmp);
1864 	return err;
1865 }
1866 
1867 /**
1868  * \brief Get list of values
1869  * \param list Returned list
1870  * \param verbname For verb (NULL = current)
1871  * \return Number of list entries if success, otherwise a negative error code
1872  */
get_value_list(snd_use_case_mgr_t * uc_mgr,const char * identifier,const char ** list[],char * verbname)1873 static int get_value_list(snd_use_case_mgr_t *uc_mgr,
1874 			  const char *identifier,
1875 			  const char **list[],
1876 			  char *verbname)
1877 {
1878 	struct list_head mylist, *pos;
1879 	struct use_case_verb *verb;
1880 	struct use_case_device *dev;
1881 	struct use_case_modifier *mod;
1882 	char **res;
1883 	int err;
1884 
1885 	if (verbname) {
1886 		verb = find_verb(uc_mgr, verbname);
1887 	} else {
1888 		verb = uc_mgr->active_verb;
1889 	}
1890 	if (verb == NULL)
1891 		return -ENOENT;
1892 	INIT_LIST_HEAD(&mylist);
1893 	err = add_values(&mylist, identifier, &uc_mgr->value_list);
1894 	if (err < 0)
1895 		goto __fail;
1896 	err = add_values(&mylist, identifier, &verb->value_list);
1897 	if (err < 0)
1898 		goto __fail;
1899 	list_for_each(pos, &verb->device_list) {
1900 		dev = list_entry(pos, struct use_case_device, list);
1901 		err = add_values(&mylist, identifier, &dev->value_list);
1902 		if (err < 0)
1903 			goto __fail;
1904 	}
1905 	list_for_each(pos, &verb->modifier_list) {
1906 		mod = list_entry(pos, struct use_case_modifier, list);
1907 		err = add_values(&mylist, identifier, &mod->value_list);
1908 		if (err < 0)
1909 			goto __fail;
1910 	}
1911 	err = myvalue_to_str_list(&mylist, &res);
1912 	if (err > 0)
1913 		*list = (const char **)res;
1914 	else if (err == 0)
1915 		*list = NULL;
1916       __fail:
1917 	myvalue_list_free(&mylist);
1918 	return err;
1919 }
1920 
1921 /**
1922  * \brief Get list of enabled devices
1923  * \param list Returned list
1924  * \param verbname For verb (NULL = current)
1925  * \return Number of list entries if success, otherwise a negative error code
1926  */
get_enabled_device_list(snd_use_case_mgr_t * uc_mgr,const char ** list[])1927 static int get_enabled_device_list(snd_use_case_mgr_t *uc_mgr,
1928 				   const char **list[])
1929 {
1930 	if (uc_mgr->active_verb == NULL)
1931 		return -EINVAL;
1932 	return get_list(&uc_mgr->active_devices, list,
1933 			struct use_case_device, active_list,
1934 			name);
1935 }
1936 
1937 /**
1938  * \brief Get list of enabled modifiers
1939  * \param list Returned list
1940  * \param verbname For verb (NULL = current)
1941  * \return Number of list entries if success, otherwise a negative error code
1942  */
get_enabled_modifier_list(snd_use_case_mgr_t * uc_mgr,const char ** list[])1943 static int get_enabled_modifier_list(snd_use_case_mgr_t *uc_mgr,
1944 				     const char **list[])
1945 {
1946 	if (uc_mgr->active_verb == NULL)
1947 		return -EINVAL;
1948 	return get_list(&uc_mgr->active_modifiers, list,
1949 			struct use_case_modifier, active_list,
1950 			name);
1951 }
1952 
1953 /**
1954  * \brief Obtain a list of entries
1955  * \param uc_mgr Use case manager (may be NULL - card list)
1956  * \param identifier (may be NULL - card list)
1957  * \param list Returned allocated list
1958  * \return Number of list entries if success, otherwise a negative error code
1959  */
snd_use_case_get_list(snd_use_case_mgr_t * uc_mgr,const char * identifier,const char ** list[])1960 int snd_use_case_get_list(snd_use_case_mgr_t *uc_mgr,
1961 			  const char *identifier,
1962 			  const char **list[])
1963 {
1964 	char *str, *str1;
1965 	int err;
1966 
1967 	if (uc_mgr == NULL || identifier == NULL)
1968 		return uc_mgr_scan_master_configs(list);
1969 	pthread_mutex_lock(&uc_mgr->mutex);
1970 	if (strcmp(identifier, "_verbs") == 0)
1971 		err = get_verb_list(uc_mgr, list);
1972 	else if (strcmp(identifier, "_enadevs") == 0)
1973 		err = get_enabled_device_list(uc_mgr, list);
1974 	else if (strcmp(identifier, "_enamods") == 0)
1975 		err = get_enabled_modifier_list(uc_mgr, list);
1976 	else {
1977 		str1 = strchr(identifier, '/');
1978 		if (str1) {
1979 			str = strdup(str1 + 1);
1980 			if (str == NULL) {
1981 				err = -ENOMEM;
1982 				goto __end;
1983 			}
1984 		} else {
1985 			str = NULL;
1986 		}
1987 		if (check_identifier(identifier, "_devices"))
1988 			err = get_device_list(uc_mgr, list, str);
1989 		else if (check_identifier(identifier, "_modifiers"))
1990 			err = get_modifier_list(uc_mgr, list, str);
1991 		else if (check_identifier(identifier, "_identifiers"))
1992 			err = get_identifiers_list(uc_mgr, list, str);
1993 		else if (check_identifier(identifier, "_supporteddevs"))
1994 			err = get_supported_device_list(uc_mgr, list, str);
1995 		else if (check_identifier(identifier, "_conflictingdevs"))
1996 			err = get_conflicting_device_list(uc_mgr, list, str);
1997 		else if (identifier[0] == '_')
1998 			err = -ENOENT;
1999 		else
2000 			err = get_value_list(uc_mgr, identifier, list, str);
2001 		if (str)
2002 			free(str);
2003 	}
2004       __end:
2005 	pthread_mutex_unlock(&uc_mgr->mutex);
2006 	return err;
2007 }
2008 
get_value1(snd_use_case_mgr_t * uc_mgr,char ** value,struct list_head * value_list,const char * identifier)2009 static int get_value1(snd_use_case_mgr_t *uc_mgr, char **value,
2010 		      struct list_head *value_list, const char *identifier)
2011 {
2012 	struct ucm_value *val;
2013 	struct list_head *pos;
2014 	int err;
2015 
2016 	if (!value_list)
2017 		return -ENOENT;
2018 
2019 	list_for_each(pos, value_list) {
2020 		val = list_entry(pos, struct ucm_value, list);
2021 		if (check_identifier(identifier, val->name)) {
2022 			if (uc_mgr->conf_format < 2) {
2023 				*value = strdup(val->data);
2024 				if (*value == NULL)
2025 					return -ENOMEM;
2026 				return 0;
2027 			}
2028 			err = uc_mgr_get_substituted_value(uc_mgr, value, val->data);
2029 			if (err < 0)
2030 				return err;
2031 			return rewrite_device_value(uc_mgr, val->name, value);
2032 		}
2033 	}
2034 	return -ENOENT;
2035 }
2036 
get_value3(snd_use_case_mgr_t * uc_mgr,char ** value,const char * identifier,struct list_head * value_list1,struct list_head * value_list2,struct list_head * value_list3)2037 static int get_value3(snd_use_case_mgr_t *uc_mgr,
2038 		      char **value,
2039 		      const char *identifier,
2040 		      struct list_head *value_list1,
2041 		      struct list_head *value_list2,
2042 		      struct list_head *value_list3)
2043 {
2044 	int err;
2045 
2046 	err = get_value1(uc_mgr, value, value_list1, identifier);
2047 	if (err >= 0 || err != -ENOENT)
2048 		return err;
2049 	err = get_value1(uc_mgr, value, value_list2, identifier);
2050 	if (err >= 0 || err != -ENOENT)
2051 		return err;
2052 	err = get_value1(uc_mgr, value, value_list3, identifier);
2053 	if (err >= 0 || err != -ENOENT)
2054 		return err;
2055 	return -ENOENT;
2056 }
2057 
2058 /**
2059  * \brief Get value
2060  * \param uc_mgr Use case manager
2061  * \param identifier Value identifier (string)
2062  * \param value Returned value string
2063  * \param item Modifier or Device name (string)
2064  * \return Zero on success (value is filled), otherwise a negative error code
2065  */
get_value(snd_use_case_mgr_t * uc_mgr,const char * identifier,char ** value,const char * mod_dev_name,const char * verb_name,int exact)2066 static int get_value(snd_use_case_mgr_t *uc_mgr,
2067 			const char *identifier,
2068 			char **value,
2069 			const char *mod_dev_name,
2070 			const char *verb_name,
2071 			int exact)
2072 {
2073 	struct use_case_verb *verb;
2074 	struct use_case_modifier *mod;
2075 	struct use_case_device *dev;
2076 	int err;
2077 
2078 	if (mod_dev_name || verb_name || !exact) {
2079 		if (verb_name && strlen(verb_name)) {
2080 			verb = find_verb(uc_mgr, verb_name);
2081 		} else {
2082 			verb = uc_mgr->active_verb;
2083 		}
2084 		if (verb) {
2085 			if (mod_dev_name) {
2086 				mod = find_modifier(uc_mgr, verb,
2087 						    mod_dev_name, 0);
2088 				if (mod) {
2089 					err = get_value1(uc_mgr, value,
2090 							 &mod->value_list,
2091 							 identifier);
2092 					if (err >= 0 || err != -ENOENT)
2093 						return err;
2094 				}
2095 
2096 				dev = find_device(uc_mgr, verb,
2097 						  mod_dev_name, 0);
2098 				if (dev) {
2099 					err = get_value1(uc_mgr, value,
2100 							 &dev->value_list,
2101 							 identifier);
2102 					if (err >= 0 || err != -ENOENT)
2103 						return err;
2104 				}
2105 
2106 				if (exact)
2107 					return -ENOENT;
2108 			}
2109 
2110 			err = get_value1(uc_mgr, value, &verb->value_list, identifier);
2111 			if (err >= 0 || err != -ENOENT)
2112 				return err;
2113 		}
2114 
2115 		if (exact)
2116 			return -ENOENT;
2117 	}
2118 
2119 	err = get_value1(uc_mgr, value, &uc_mgr->value_list, identifier);
2120 	if (err >= 0 || err != -ENOENT)
2121 		return err;
2122 
2123 	return -ENOENT;
2124 }
2125 
2126 /**
2127  * \brief Get private alsa-lib configuration (ASCII)
2128  * \param uc_mgr Use case manager
2129  * \param str Returned value string
2130  * \return Zero on success (value is filled), otherwise a negative error code
2131  */
get_alibcfg(snd_use_case_mgr_t * uc_mgr,char ** str)2132 static int get_alibcfg(snd_use_case_mgr_t *uc_mgr, char **str)
2133 {
2134 	snd_output_t *out;
2135 	size_t size;
2136 	int err;
2137 
2138 	err = snd_output_buffer_open(&out);
2139 	if (err < 0)
2140 		return err;
2141 	err = snd_config_save(uc_mgr->local_config, out);
2142 	if (err >= 0) {
2143 		size = snd_output_buffer_steal(out, str);
2144 		if (*str)
2145 			(*str)[size] = '\0';
2146 	}
2147 	snd_output_close(out);
2148 	return 0;
2149 }
2150 
2151 /**
2152  * \brief Get device prefix for private alsa-lib configuration
2153  * \param uc_mgr Use case manager
2154  * \param str Returned value string
2155  * \return Zero on success (value is filled), otherwise a negative error code
2156  */
get_alibpref(snd_use_case_mgr_t * uc_mgr,char ** str)2157 static int get_alibpref(snd_use_case_mgr_t *uc_mgr, char **str)
2158 {
2159 	const size_t l = 10;
2160 	char *s;
2161 
2162 	s = malloc(l);
2163 	if (s == NULL)
2164 		return -ENOMEM;
2165 	snprintf(s, l, "_ucm%04X.", uc_mgr->ucm_card_number);
2166 	*str = s;
2167 	return 0;
2168 }
2169 
2170 /**
2171  * \brief Get current - string
2172  * \param uc_mgr Use case manager
2173  * \param identifier
2174  * \param value Value pointer
2175  * \return Zero if success, otherwise a negative error code
2176  *
2177  * Note: String is dynamically allocated, use free() to
2178  * deallocate this string.
2179  */
snd_use_case_get(snd_use_case_mgr_t * uc_mgr,const char * identifier,const char ** value)2180 int snd_use_case_get(snd_use_case_mgr_t *uc_mgr,
2181 		     const char *identifier,
2182 		     const char **value)
2183 {
2184 	const char *slash1, *slash2, *mod_dev_after;
2185 	const char *ident, *mod_dev, *verb;
2186 	int exact = 0;
2187 	int err;
2188 
2189 	pthread_mutex_lock(&uc_mgr->mutex);
2190 	if (identifier == NULL) {
2191 		*value = strdup(uc_mgr->card_name);
2192 		if (*value == NULL) {
2193 			err = -ENOMEM;
2194 			goto __end;
2195 		}
2196 		err = 0;
2197 	} else if (strcmp(identifier, "_verb") == 0) {
2198 		if (uc_mgr->active_verb == NULL) {
2199 			err = -ENOENT;
2200 			goto __end;
2201 		}
2202 		*value = strdup(uc_mgr->active_verb->name);
2203 		if (*value == NULL) {
2204 			err = -ENOMEM;
2205 			goto __end;
2206 		}
2207 		err = 0;
2208 	} else if (strcmp(identifier, "_file") == 0) {
2209 		/* get the conf file name of the opened card */
2210 		if ((uc_mgr->card_name == NULL) ||
2211 		    (uc_mgr->conf_file_name == NULL) ||
2212 		    (uc_mgr->conf_file_name[0] == '\0')) {
2213 			err = -ENOENT;
2214 			goto __end;
2215 		}
2216 		*value = strdup(uc_mgr->conf_file_name);
2217 		if (*value == NULL) {
2218 			err = -ENOMEM;
2219 			goto __end;
2220 		}
2221 		err = 0;
2222 
2223 	} else if (strcmp(identifier, "_alibcfg") == 0) {
2224 		err = get_alibcfg(uc_mgr, (char **)value);
2225 	} else if (strcmp(identifier, "_alibpref") == 0) {
2226 		err = get_alibpref(uc_mgr, (char **)value);
2227 	} else if (identifier[0] == '_') {
2228 		err = -ENOENT;
2229 	} else {
2230 		if (identifier[0] == '=') {
2231 			exact = 1;
2232 			identifier++;
2233 		}
2234 
2235 		slash1 = strchr(identifier, '/');
2236 		if (slash1) {
2237 			ident = strndup(identifier, slash1 - identifier);
2238 
2239 			slash2 = strchr(slash1 + 1, '/');
2240 			if (slash2) {
2241 				mod_dev_after = slash2;
2242 				verb = slash2 + 1;
2243 			}
2244 			else {
2245 				mod_dev_after = slash1 + strlen(slash1);
2246 				verb = NULL;
2247 			}
2248 
2249 			if (mod_dev_after == slash1 + 1)
2250 				mod_dev = NULL;
2251 			else
2252 				mod_dev = strndup(slash1 + 1,
2253 						  mod_dev_after - (slash1 + 1));
2254 		}
2255 		else {
2256 			ident = identifier;
2257 			mod_dev = NULL;
2258 			verb = NULL;
2259 		}
2260 
2261 		err = get_value(uc_mgr, ident, (char **)value, mod_dev, verb,
2262 				exact);
2263 		if (ident != identifier)
2264 			free((void *)ident);
2265 		if (mod_dev)
2266 			free((void *)mod_dev);
2267 	}
2268       __end:
2269 	pthread_mutex_unlock(&uc_mgr->mutex);
2270 	return err;
2271 }
2272 
2273 
2274 /**
2275  * \brief Get current - integer
2276  * \param uc_mgr Use case manager
2277  * \param identifier
2278  * \return Value if success, otherwise a negative error code
2279  */
snd_use_case_geti(snd_use_case_mgr_t * uc_mgr,const char * identifier,long * value)2280 int snd_use_case_geti(snd_use_case_mgr_t *uc_mgr,
2281 		      const char *identifier,
2282 		      long *value)
2283 {
2284 	char *str, *str1;
2285 	long err;
2286 
2287 	pthread_mutex_lock(&uc_mgr->mutex);
2288 	if (0) {
2289 		/* nothing here - prepared for fixed identifiers */
2290 	} else {
2291 		str1 = strchr(identifier, '/');
2292 		if (str1) {
2293 			str = strdup(str1 + 1);
2294 			if (str == NULL) {
2295 				err = -ENOMEM;
2296 				goto __end;
2297 			}
2298 		} else {
2299 			str = NULL;
2300 		}
2301 		if (check_identifier(identifier, "_devstatus")) {
2302 			if (!str) {
2303 				err = -EINVAL;
2304 				goto __end;
2305 			}
2306 			err = device_status(uc_mgr, str);
2307 			if (err >= 0) {
2308 				*value = err;
2309 				err = 0;
2310 			}
2311 		} else if (check_identifier(identifier, "_modstatus")) {
2312 			if (!str) {
2313 				err = -EINVAL;
2314 				goto __end;
2315 			}
2316 			err = modifier_status(uc_mgr, str);
2317 			if (err >= 0) {
2318 				*value = err;
2319 				err = 0;
2320 			}
2321 #if 0
2322 		/*
2323 		 * enable this block if the else clause below is expanded to query
2324 		 * user-supplied values
2325 		 */
2326 		} else if (identifier[0] == '_')
2327 			err = -ENOENT;
2328 #endif
2329 		} else
2330 			err = -ENOENT;
2331 		if (str)
2332 			free(str);
2333 	}
2334       __end:
2335 	pthread_mutex_unlock(&uc_mgr->mutex);
2336 	return err;
2337 }
2338 
set_fixedboot_user(snd_use_case_mgr_t * uc_mgr,const char * value)2339 static int set_fixedboot_user(snd_use_case_mgr_t *uc_mgr,
2340 			      const char *value)
2341 {
2342 	int err;
2343 
2344 	if (value != NULL && *value) {
2345 		uc_error("error: wrong value for _fboot (%s)", value);
2346 		return -EINVAL;
2347 	}
2348 	if (list_empty(&uc_mgr->fixedboot_list))
2349 		return -ENOENT;
2350 	err = execute_sequence(uc_mgr, &uc_mgr->fixedboot_list,
2351 			       &uc_mgr->value_list, NULL, NULL);
2352 	if (err < 0) {
2353 		uc_error("Unable to execute force boot sequence");
2354 		return err;
2355 	}
2356 	return err;
2357 }
2358 
set_boot_user(snd_use_case_mgr_t * uc_mgr,const char * value)2359 static int set_boot_user(snd_use_case_mgr_t *uc_mgr,
2360 			 const char *value)
2361 {
2362 	int err;
2363 
2364 	if (value != NULL && *value) {
2365 		uc_error("error: wrong value for _boot (%s)", value);
2366 		return -EINVAL;
2367 	}
2368 	if (list_empty(&uc_mgr->boot_list))
2369 		return -ENOENT;
2370 	err = execute_sequence(uc_mgr, &uc_mgr->boot_list,
2371 			       &uc_mgr->value_list, NULL, NULL);
2372 	if (err < 0) {
2373 		uc_error("Unable to execute boot sequence");
2374 		return err;
2375 	}
2376 	return err;
2377 }
2378 
set_defaults_user(snd_use_case_mgr_t * uc_mgr,const char * value)2379 static int set_defaults_user(snd_use_case_mgr_t *uc_mgr,
2380 			     const char *value)
2381 {
2382 	if (value != NULL && *value) {
2383 		uc_error("error: wrong value for _defaults (%s)", value);
2384 		return -EINVAL;
2385 	}
2386 	return set_defaults(uc_mgr);
2387 }
2388 
handle_transition_verb(snd_use_case_mgr_t * uc_mgr,struct use_case_verb * new_verb)2389 static int handle_transition_verb(snd_use_case_mgr_t *uc_mgr,
2390 				  struct use_case_verb *new_verb)
2391 {
2392 	struct list_head *pos;
2393 	struct transition_sequence *trans;
2394 	int err;
2395 
2396 	list_for_each(pos, &uc_mgr->active_verb->transition_list) {
2397 		trans = list_entry(pos, struct transition_sequence, list);
2398 		if (strcmp(trans->name, new_verb->name) == 0) {
2399 			err = execute_sequence(uc_mgr, &trans->transition_list,
2400 					       &uc_mgr->active_verb->value_list,
2401 					       &uc_mgr->value_list,
2402 					       NULL);
2403 			if (err >= 0)
2404 				return 1;
2405 			return err;
2406 		}
2407 	}
2408 	return 0;
2409 }
2410 
set_verb_user(snd_use_case_mgr_t * uc_mgr,const char * verb_name)2411 static int set_verb_user(snd_use_case_mgr_t *uc_mgr,
2412 			 const char *verb_name)
2413 {
2414 	struct use_case_verb *verb;
2415 	int err = 0;
2416 
2417 	if (uc_mgr->active_verb &&
2418 	    strcmp(uc_mgr->active_verb->name, verb_name) == 0)
2419 		return 0;
2420 	if (strcmp(verb_name, SND_USE_CASE_VERB_INACTIVE) != 0) {
2421 		verb = find_verb(uc_mgr, verb_name);
2422 		if (verb == NULL)
2423 			return -ENOENT;
2424 	} else {
2425 		verb = NULL;
2426 	}
2427 	if (uc_mgr->active_verb) {
2428 		err = handle_transition_verb(uc_mgr, verb);
2429 		if (err == 0) {
2430 			err = dismantle_use_case(uc_mgr);
2431 			if (err < 0)
2432 				return err;
2433 		} else if (err == 1) {
2434 			uc_mgr->active_verb = verb;
2435 			verb = NULL;
2436 		} else {
2437 			verb = NULL; /* show error */
2438 		}
2439 	}
2440 	if (verb) {
2441 		err = set_verb(uc_mgr, verb, 1);
2442 		if (err < 0)
2443 			uc_error("error: failed to initialize new use case: %s",
2444 				 verb_name);
2445 	}
2446 	return err;
2447 }
2448 
2449 
set_device_user(snd_use_case_mgr_t * uc_mgr,const char * device_name,int enable)2450 static int set_device_user(snd_use_case_mgr_t *uc_mgr,
2451 			   const char *device_name,
2452 			   int enable)
2453 {
2454 	struct use_case_device *device;
2455 
2456 	if (uc_mgr->active_verb == NULL)
2457 		return -ENOENT;
2458 	device = find_device(uc_mgr, uc_mgr->active_verb, device_name, 1);
2459 	if (device == NULL)
2460 		return -ENOENT;
2461 	return set_device(uc_mgr, device, enable);
2462 }
2463 
set_modifier_user(snd_use_case_mgr_t * uc_mgr,const char * modifier_name,int enable)2464 static int set_modifier_user(snd_use_case_mgr_t *uc_mgr,
2465 			     const char *modifier_name,
2466 			     int enable)
2467 {
2468 	struct use_case_modifier *modifier;
2469 
2470 	if (uc_mgr->active_verb == NULL)
2471 		return -ENOENT;
2472 
2473 	modifier = find_modifier(uc_mgr, uc_mgr->active_verb, modifier_name, 1);
2474 	if (modifier == NULL)
2475 		return -ENOENT;
2476 	return set_modifier(uc_mgr, modifier, enable);
2477 }
2478 
switch_device(snd_use_case_mgr_t * uc_mgr,const char * old_device,const char * new_device)2479 static int switch_device(snd_use_case_mgr_t *uc_mgr,
2480 			 const char *old_device,
2481 			 const char *new_device)
2482 {
2483 	struct use_case_device *xold, *xnew;
2484 	struct transition_sequence *trans;
2485 	struct list_head *pos;
2486 	int err, seq_found = 0;
2487 
2488 	if (uc_mgr->active_verb == NULL)
2489 		return -ENOENT;
2490 	if (device_status(uc_mgr, old_device) == 0) {
2491 		uc_error("error: device %s not enabled", old_device);
2492 		return -EINVAL;
2493 	}
2494 	if (device_status(uc_mgr, new_device) != 0) {
2495 		uc_error("error: device %s already enabled", new_device);
2496 		return -EINVAL;
2497 	}
2498 	xold = find_device(uc_mgr, uc_mgr->active_verb, old_device, 1);
2499 	if (xold == NULL)
2500 		return -ENOENT;
2501 	list_del(&xold->active_list);
2502 	xnew = find_device(uc_mgr, uc_mgr->active_verb, new_device, 1);
2503 	list_add_tail(&xold->active_list, &uc_mgr->active_devices);
2504 	if (xnew == NULL)
2505 		return -ENOENT;
2506 	err = 0;
2507 	list_for_each(pos, &xold->transition_list) {
2508 		trans = list_entry(pos, struct transition_sequence, list);
2509 		if (strcmp(trans->name, new_device) == 0) {
2510 			err = execute_sequence(uc_mgr, &trans->transition_list,
2511 					       &xold->value_list,
2512 					       &uc_mgr->active_verb->value_list,
2513 					       &uc_mgr->value_list);
2514 			if (err >= 0) {
2515 				list_del(&xold->active_list);
2516 				list_add_tail(&xnew->active_list, &uc_mgr->active_devices);
2517 			}
2518 			seq_found = 1;
2519 			break;
2520 		}
2521 	}
2522 	if (!seq_found) {
2523 		err = set_device(uc_mgr, xold, 0);
2524 		if (err < 0)
2525 			return err;
2526 		err = set_device(uc_mgr, xnew, 1);
2527 		if (err < 0)
2528 			return err;
2529 	}
2530 	return err;
2531 }
2532 
switch_modifier(snd_use_case_mgr_t * uc_mgr,const char * old_modifier,const char * new_modifier)2533 static int switch_modifier(snd_use_case_mgr_t *uc_mgr,
2534 			   const char *old_modifier,
2535 			   const char *new_modifier)
2536 {
2537 	struct use_case_modifier *xold, *xnew;
2538 	struct transition_sequence *trans;
2539 	struct list_head *pos;
2540 	int err, seq_found = 0;
2541 
2542 	if (uc_mgr->active_verb == NULL)
2543 		return -ENOENT;
2544 	if (modifier_status(uc_mgr, old_modifier) == 0) {
2545 		uc_error("error: modifier %s not enabled", old_modifier);
2546 		return -EINVAL;
2547 	}
2548 	if (modifier_status(uc_mgr, new_modifier) != 0) {
2549 		uc_error("error: modifier %s already enabled", new_modifier);
2550 		return -EINVAL;
2551 	}
2552 	xold = find_modifier(uc_mgr, uc_mgr->active_verb, old_modifier, 1);
2553 	if (xold == NULL)
2554 		return -ENOENT;
2555 	xnew = find_modifier(uc_mgr, uc_mgr->active_verb, new_modifier, 1);
2556 	if (xnew == NULL)
2557 		return -ENOENT;
2558 	err = 0;
2559 	list_for_each(pos, &xold->transition_list) {
2560 		trans = list_entry(pos, struct transition_sequence, list);
2561 		if (strcmp(trans->name, new_modifier) == 0) {
2562 			err = execute_sequence(uc_mgr, &trans->transition_list,
2563 					       &xold->value_list,
2564 					       &uc_mgr->active_verb->value_list,
2565 					       &uc_mgr->value_list);
2566 			if (err >= 0) {
2567 				list_del(&xold->active_list);
2568 				list_add_tail(&xnew->active_list, &uc_mgr->active_modifiers);
2569 			}
2570 			seq_found = 1;
2571 			break;
2572 		}
2573 	}
2574 	if (!seq_found) {
2575 		err = set_modifier(uc_mgr, xold, 0);
2576 		if (err < 0)
2577 			return err;
2578 		err = set_modifier(uc_mgr, xnew, 1);
2579 		if (err < 0)
2580 			return err;
2581 	}
2582 	return err;
2583 }
2584 
2585 /**
2586  * \brief Set new
2587  * \param uc_mgr Use case manager
2588  * \param identifier
2589  * \param value Value
2590  * \return Zero if success, otherwise a negative error code
2591  */
snd_use_case_set(snd_use_case_mgr_t * uc_mgr,const char * identifier,const char * value)2592 int snd_use_case_set(snd_use_case_mgr_t *uc_mgr,
2593 		     const char *identifier,
2594 		     const char *value)
2595 {
2596 	char *str, *str1;
2597 	int err = 0;
2598 
2599 	pthread_mutex_lock(&uc_mgr->mutex);
2600 	if (strcmp(identifier, "_fboot") == 0)
2601 		err = set_fixedboot_user(uc_mgr, value);
2602 	else if (strcmp(identifier, "_boot") == 0)
2603 		err = set_boot_user(uc_mgr, value);
2604 	else if (strcmp(identifier, "_defaults") == 0)
2605 		err = set_defaults_user(uc_mgr, value);
2606 	else if (strcmp(identifier, "_verb") == 0)
2607 		err = set_verb_user(uc_mgr, value);
2608 	else if (strcmp(identifier, "_enadev") == 0)
2609 		err = set_device_user(uc_mgr, value, 1);
2610 	else if (strcmp(identifier, "_disdev") == 0)
2611 		err = set_device_user(uc_mgr, value, 0);
2612 	else if (strcmp(identifier, "_enamod") == 0)
2613 		err = set_modifier_user(uc_mgr, value, 1);
2614 	else if (strcmp(identifier, "_dismod") == 0)
2615 		err = set_modifier_user(uc_mgr, value, 0);
2616 	else {
2617 		str1 = strchr(identifier, '/');
2618 		if (str1) {
2619 			str = strdup(str1 + 1);
2620 			if (str == NULL) {
2621 				err = -ENOMEM;
2622 				goto __end;
2623 			}
2624 		} else {
2625 			err = -EINVAL;
2626 			goto __end;
2627 		}
2628 		if (check_identifier(identifier, "_swdev"))
2629 			err = switch_device(uc_mgr, str, value);
2630 		else if (check_identifier(identifier, "_swmod"))
2631 			err = switch_modifier(uc_mgr, str, value);
2632 		else
2633 			err = -EINVAL;
2634 		if (str)
2635 			free(str);
2636 	}
2637       __end:
2638 	pthread_mutex_unlock(&uc_mgr->mutex);
2639 	return err;
2640 }
2641 
2642 /**
2643  * \brief Parse control element identifier
2644  * \param elem_id Element identifier
2645  * \param ucm_id Use case identifier
2646  * \param value String value to be parsed
2647  * \return Zero if success, otherwise a negative error code
2648  */
snd_use_case_parse_ctl_elem_id(snd_ctl_elem_id_t * dst,const char * ucm_id,const char * value)2649 int snd_use_case_parse_ctl_elem_id(snd_ctl_elem_id_t *dst,
2650 				   const char *ucm_id,
2651 				   const char *value)
2652 {
2653 	snd_ctl_elem_iface_t iface;
2654 	int jack_control;
2655 
2656 	jack_control = strcmp(ucm_id, "JackControl") == 0;
2657 	if (!jack_control &&
2658 	    strcmp(ucm_id, "PlaybackVolume") &&
2659 	    strcmp(ucm_id, "PlaybackSwitch") &&
2660 	    strcmp(ucm_id, "CaptureVolume") &&
2661 	    strcmp(ucm_id, "CaptureSwitch"))
2662 		return -EINVAL;
2663 	snd_ctl_elem_id_clear(dst);
2664 	if (strcasestr(ucm_id, "name="))
2665 		return __snd_ctl_ascii_elem_id_parse(dst, value, NULL);
2666 	iface = SND_CTL_ELEM_IFACE_MIXER;
2667 	if (jack_control)
2668 		iface = SND_CTL_ELEM_IFACE_CARD;
2669 	snd_ctl_elem_id_set_interface(dst, iface);
2670 	snd_ctl_elem_id_set_name(dst, value);
2671 	return 0;
2672 }
2673 
2674 /**
2675  * \brief Parse mixer element identifier
2676  * \param dst Simple mixer element identifier
2677  * \param ucm_id Use case identifier
2678  * \param value String value to be parsed
2679  * \return Zero if success, otherwise a negative error code
2680  */
snd_use_case_parse_selem_id(snd_mixer_selem_id_t * dst,const char * ucm_id,const char * value)2681 int snd_use_case_parse_selem_id(snd_mixer_selem_id_t *dst,
2682 				const char *ucm_id,
2683 				const char *value)
2684 {
2685 #ifdef BUILD_MIXER
2686 	if (strcmp(ucm_id, "PlaybackMixerId") == 0 ||
2687 	    strcmp(ucm_id, "CaptureMixerId") == 0)
2688 		return snd_mixer_selem_id_parse(dst, value);
2689 #endif
2690 	return -EINVAL;
2691 }
2692