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