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