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 <sys/stat.h>
35d5ac70f0Sopenharmony_ci#include <stdbool.h>
36d5ac70f0Sopenharmony_ci#include <dirent.h>
37d5ac70f0Sopenharmony_ci#include <limits.h>
38d5ac70f0Sopenharmony_ci
39d5ac70f0Sopenharmony_cistatic int filename_filter(const struct dirent64 *dirent);
40d5ac70f0Sopenharmony_ci
41d5ac70f0Sopenharmony_cistatic int parse_sequence(snd_use_case_mgr_t *uc_mgr,
42d5ac70f0Sopenharmony_ci			  struct list_head *base,
43d5ac70f0Sopenharmony_ci			  snd_config_t *cfg);
44d5ac70f0Sopenharmony_ci
45d5ac70f0Sopenharmony_ci/*
46d5ac70f0Sopenharmony_ci * compose the absolute ucm filename
47d5ac70f0Sopenharmony_ci */
48d5ac70f0Sopenharmony_cistatic void ucm_filename(char *fn, size_t fn_len, long version,
49d5ac70f0Sopenharmony_ci			  const char *dir, const char *file)
50d5ac70f0Sopenharmony_ci{
51d5ac70f0Sopenharmony_ci	const char *env = getenv(version > 1 ? ALSA_CONFIG_UCM2_VAR : ALSA_CONFIG_UCM_VAR);
52d5ac70f0Sopenharmony_ci
53d5ac70f0Sopenharmony_ci	if (file[0] == '/')
54d5ac70f0Sopenharmony_ci		file++;
55d5ac70f0Sopenharmony_ci	if (env == NULL)
56d5ac70f0Sopenharmony_ci		snprintf(fn, fn_len, "%s/%s/%s%s%s",
57d5ac70f0Sopenharmony_ci			 snd_config_topdir(), version > 1 ? "ucm2" : "ucm",
58d5ac70f0Sopenharmony_ci			 dir ?: "", dir ? "/" : "", file);
59d5ac70f0Sopenharmony_ci	else
60d5ac70f0Sopenharmony_ci		snprintf(fn, fn_len, "%s/%s%s%s",
61d5ac70f0Sopenharmony_ci			 env, dir ?: "", dir ? "/" : "", file);
62d5ac70f0Sopenharmony_ci}
63d5ac70f0Sopenharmony_ci
64d5ac70f0Sopenharmony_ci/*
65d5ac70f0Sopenharmony_ci *
66d5ac70f0Sopenharmony_ci */
67d5ac70f0Sopenharmony_ciint uc_mgr_config_load_file(snd_use_case_mgr_t *uc_mgr,
68d5ac70f0Sopenharmony_ci			     const char *file, snd_config_t **cfg)
69d5ac70f0Sopenharmony_ci{
70d5ac70f0Sopenharmony_ci	char filename[PATH_MAX];
71d5ac70f0Sopenharmony_ci	int err;
72d5ac70f0Sopenharmony_ci
73d5ac70f0Sopenharmony_ci	ucm_filename(filename, sizeof(filename), uc_mgr->conf_format,
74d5ac70f0Sopenharmony_ci		     file[0] == '/' ? NULL : uc_mgr->conf_dir_name,
75d5ac70f0Sopenharmony_ci		     file);
76d5ac70f0Sopenharmony_ci	err = uc_mgr_config_load(uc_mgr->conf_format, filename, cfg);
77d5ac70f0Sopenharmony_ci	if (err < 0) {
78d5ac70f0Sopenharmony_ci		uc_error("error: failed to open file %s: %d", filename, err);
79d5ac70f0Sopenharmony_ci		return err;
80d5ac70f0Sopenharmony_ci	}
81d5ac70f0Sopenharmony_ci	return 0;
82d5ac70f0Sopenharmony_ci}
83d5ac70f0Sopenharmony_ci
84d5ac70f0Sopenharmony_ci/*
85d5ac70f0Sopenharmony_ci * Replace mallocated string
86d5ac70f0Sopenharmony_ci */
87d5ac70f0Sopenharmony_cistatic char *replace_string(char **dst, const char *value)
88d5ac70f0Sopenharmony_ci{
89d5ac70f0Sopenharmony_ci	free(*dst);
90d5ac70f0Sopenharmony_ci	*dst = value ? strdup(value) : NULL;
91d5ac70f0Sopenharmony_ci	return *dst;
92d5ac70f0Sopenharmony_ci}
93d5ac70f0Sopenharmony_ci
94d5ac70f0Sopenharmony_ci/*
95d5ac70f0Sopenharmony_ci * Parse string
96d5ac70f0Sopenharmony_ci */
97d5ac70f0Sopenharmony_cistatic int parse_string(snd_config_t *n, char **res)
98d5ac70f0Sopenharmony_ci{
99d5ac70f0Sopenharmony_ci	int err;
100d5ac70f0Sopenharmony_ci
101d5ac70f0Sopenharmony_ci	err = snd_config_get_string(n, (const char **)res);
102d5ac70f0Sopenharmony_ci	if (err < 0)
103d5ac70f0Sopenharmony_ci		return err;
104d5ac70f0Sopenharmony_ci	*res = strdup(*res);
105d5ac70f0Sopenharmony_ci	if (*res == NULL)
106d5ac70f0Sopenharmony_ci		return -ENOMEM;
107d5ac70f0Sopenharmony_ci	return 0;
108d5ac70f0Sopenharmony_ci}
109d5ac70f0Sopenharmony_ci
110d5ac70f0Sopenharmony_ci/*
111d5ac70f0Sopenharmony_ci * Parse string and substitute
112d5ac70f0Sopenharmony_ci */
113d5ac70f0Sopenharmony_cistatic int parse_string_substitute(snd_use_case_mgr_t *uc_mgr,
114d5ac70f0Sopenharmony_ci			    snd_config_t *n, char **res)
115d5ac70f0Sopenharmony_ci{
116d5ac70f0Sopenharmony_ci	const char *str;
117d5ac70f0Sopenharmony_ci	char *s;
118d5ac70f0Sopenharmony_ci	int err;
119d5ac70f0Sopenharmony_ci
120d5ac70f0Sopenharmony_ci	err = snd_config_get_string(n, &str);
121d5ac70f0Sopenharmony_ci	if (err < 0)
122d5ac70f0Sopenharmony_ci		return err;
123d5ac70f0Sopenharmony_ci	err = uc_mgr_get_substituted_value(uc_mgr, &s, str);
124d5ac70f0Sopenharmony_ci	if (err >= 0)
125d5ac70f0Sopenharmony_ci		*res = s;
126d5ac70f0Sopenharmony_ci	return err;
127d5ac70f0Sopenharmony_ci}
128d5ac70f0Sopenharmony_ci
129d5ac70f0Sopenharmony_ci/*
130d5ac70f0Sopenharmony_ci * Parse string and substitute
131d5ac70f0Sopenharmony_ci */
132d5ac70f0Sopenharmony_cistatic int parse_string_substitute3(snd_use_case_mgr_t *uc_mgr,
133d5ac70f0Sopenharmony_ci			     snd_config_t *n, char **res)
134d5ac70f0Sopenharmony_ci{
135d5ac70f0Sopenharmony_ci	if (uc_mgr->conf_format < 3)
136d5ac70f0Sopenharmony_ci		return parse_string(n, res);
137d5ac70f0Sopenharmony_ci	return parse_string_substitute(uc_mgr, n, res);
138d5ac70f0Sopenharmony_ci}
139d5ac70f0Sopenharmony_ci
140d5ac70f0Sopenharmony_ci/*
141d5ac70f0Sopenharmony_ci * Parse integer with substitution
142d5ac70f0Sopenharmony_ci */
143d5ac70f0Sopenharmony_cistatic int parse_integer_substitute(snd_use_case_mgr_t *uc_mgr,
144d5ac70f0Sopenharmony_ci			     snd_config_t *n, long *res)
145d5ac70f0Sopenharmony_ci{
146d5ac70f0Sopenharmony_ci	char *s1, *s2;
147d5ac70f0Sopenharmony_ci	int err;
148d5ac70f0Sopenharmony_ci
149d5ac70f0Sopenharmony_ci	err = snd_config_get_ascii(n, &s1);
150d5ac70f0Sopenharmony_ci	if (err < 0)
151d5ac70f0Sopenharmony_ci		return err;
152d5ac70f0Sopenharmony_ci	err = uc_mgr_get_substituted_value(uc_mgr, &s2, s1);
153d5ac70f0Sopenharmony_ci	if (err >= 0)
154d5ac70f0Sopenharmony_ci		err = safe_strtol(s2, res);
155d5ac70f0Sopenharmony_ci	free(s2);
156d5ac70f0Sopenharmony_ci	free(s1);
157d5ac70f0Sopenharmony_ci	return err;
158d5ac70f0Sopenharmony_ci}
159d5ac70f0Sopenharmony_ci
160d5ac70f0Sopenharmony_ci/*
161d5ac70f0Sopenharmony_ci * Parse integer with substitution
162d5ac70f0Sopenharmony_ci */
163d5ac70f0Sopenharmony_cistatic int parse_integer_substitute3(snd_use_case_mgr_t *uc_mgr,
164d5ac70f0Sopenharmony_ci			      snd_config_t *n, long *res)
165d5ac70f0Sopenharmony_ci{
166d5ac70f0Sopenharmony_ci	char *s1, *s2;
167d5ac70f0Sopenharmony_ci	int err;
168d5ac70f0Sopenharmony_ci
169d5ac70f0Sopenharmony_ci	err = snd_config_get_ascii(n, &s1);
170d5ac70f0Sopenharmony_ci	if (err < 0)
171d5ac70f0Sopenharmony_ci		return err;
172d5ac70f0Sopenharmony_ci	if (uc_mgr->conf_format < 3)
173d5ac70f0Sopenharmony_ci		s2 = s1;
174d5ac70f0Sopenharmony_ci	else
175d5ac70f0Sopenharmony_ci		err = uc_mgr_get_substituted_value(uc_mgr, &s2, s1);
176d5ac70f0Sopenharmony_ci	if (err >= 0)
177d5ac70f0Sopenharmony_ci		err = safe_strtol(s2, res);
178d5ac70f0Sopenharmony_ci	if (s1 != s2)
179d5ac70f0Sopenharmony_ci		free(s2);
180d5ac70f0Sopenharmony_ci	free(s1);
181d5ac70f0Sopenharmony_ci	return err;
182d5ac70f0Sopenharmony_ci}
183d5ac70f0Sopenharmony_ci
184d5ac70f0Sopenharmony_ci/*
185d5ac70f0Sopenharmony_ci * Parse safe ID
186d5ac70f0Sopenharmony_ci */
187d5ac70f0Sopenharmony_cistatic int parse_is_name_safe(const char *name)
188d5ac70f0Sopenharmony_ci{
189d5ac70f0Sopenharmony_ci	if (strchr(name, '.')) {
190d5ac70f0Sopenharmony_ci		uc_error("char '.' not allowed in '%s'", name);
191d5ac70f0Sopenharmony_ci		return 0;
192d5ac70f0Sopenharmony_ci	}
193d5ac70f0Sopenharmony_ci	return 1;
194d5ac70f0Sopenharmony_ci}
195d5ac70f0Sopenharmony_ci
196d5ac70f0Sopenharmony_cistatic int get_string3(snd_use_case_mgr_t *uc_mgr, const char *s1, char **s)
197d5ac70f0Sopenharmony_ci{
198d5ac70f0Sopenharmony_ci	if (uc_mgr->conf_format < 3) {
199d5ac70f0Sopenharmony_ci		*s = strdup(s1);
200d5ac70f0Sopenharmony_ci		if (*s == NULL)
201d5ac70f0Sopenharmony_ci			return -ENOMEM;
202d5ac70f0Sopenharmony_ci		return 0;
203d5ac70f0Sopenharmony_ci	}
204d5ac70f0Sopenharmony_ci	return uc_mgr_get_substituted_value(uc_mgr, s, s1);
205d5ac70f0Sopenharmony_ci}
206d5ac70f0Sopenharmony_ci
207d5ac70f0Sopenharmony_cistatic int parse_get_safe_name(snd_use_case_mgr_t *uc_mgr, snd_config_t *n,
208d5ac70f0Sopenharmony_ci			const char *alt, char **name)
209d5ac70f0Sopenharmony_ci{
210d5ac70f0Sopenharmony_ci	const char *id;
211d5ac70f0Sopenharmony_ci	int err;
212d5ac70f0Sopenharmony_ci
213d5ac70f0Sopenharmony_ci	if (alt) {
214d5ac70f0Sopenharmony_ci		id = alt;
215d5ac70f0Sopenharmony_ci	} else {
216d5ac70f0Sopenharmony_ci		err = snd_config_get_id(n, &id);
217d5ac70f0Sopenharmony_ci		if (err < 0)
218d5ac70f0Sopenharmony_ci			return err;
219d5ac70f0Sopenharmony_ci	}
220d5ac70f0Sopenharmony_ci	err = get_string3(uc_mgr, id, name);
221d5ac70f0Sopenharmony_ci	if (err < 0)
222d5ac70f0Sopenharmony_ci		return err;
223d5ac70f0Sopenharmony_ci	if (!parse_is_name_safe(*name)) {
224d5ac70f0Sopenharmony_ci		free(*name);
225d5ac70f0Sopenharmony_ci		return -EINVAL;
226d5ac70f0Sopenharmony_ci	}
227d5ac70f0Sopenharmony_ci	return 0;
228d5ac70f0Sopenharmony_ci}
229d5ac70f0Sopenharmony_ci
230d5ac70f0Sopenharmony_ci/*
231d5ac70f0Sopenharmony_ci * Handle 'Error' configuration node.
232d5ac70f0Sopenharmony_ci */
233d5ac70f0Sopenharmony_cistatic int error_node(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
234d5ac70f0Sopenharmony_ci{
235d5ac70f0Sopenharmony_ci	int err;
236d5ac70f0Sopenharmony_ci	char *s;
237d5ac70f0Sopenharmony_ci
238d5ac70f0Sopenharmony_ci	err = parse_string_substitute3(uc_mgr, cfg, &s);
239d5ac70f0Sopenharmony_ci	if (err < 0) {
240d5ac70f0Sopenharmony_ci		uc_error("error: failed to get Error string");
241d5ac70f0Sopenharmony_ci		return err;
242d5ac70f0Sopenharmony_ci	}
243d5ac70f0Sopenharmony_ci	if (!uc_mgr->suppress_nodev_errors)
244d5ac70f0Sopenharmony_ci		uc_error("%s", s);
245d5ac70f0Sopenharmony_ci	free(s);
246d5ac70f0Sopenharmony_ci	return -ENXIO;
247d5ac70f0Sopenharmony_ci}
248d5ac70f0Sopenharmony_ci
249d5ac70f0Sopenharmony_ci/*
250d5ac70f0Sopenharmony_ci *
251d5ac70f0Sopenharmony_ci */
252d5ac70f0Sopenharmony_cistatic int parse_syntax_field(snd_use_case_mgr_t *uc_mgr,
253d5ac70f0Sopenharmony_ci			      snd_config_t *cfg, const char *filename)
254d5ac70f0Sopenharmony_ci{
255d5ac70f0Sopenharmony_ci	snd_config_t *n;
256d5ac70f0Sopenharmony_ci	long l;
257d5ac70f0Sopenharmony_ci	int err;
258d5ac70f0Sopenharmony_ci
259d5ac70f0Sopenharmony_ci	err = snd_config_search(cfg, "Syntax", &n);
260d5ac70f0Sopenharmony_ci	if (err < 0) {
261d5ac70f0Sopenharmony_ci		uc_error("Syntax field not found in %s", filename);
262d5ac70f0Sopenharmony_ci		return -EINVAL;
263d5ac70f0Sopenharmony_ci	}
264d5ac70f0Sopenharmony_ci	err = snd_config_get_integer(n, &l);
265d5ac70f0Sopenharmony_ci	if (err < 0) {
266d5ac70f0Sopenharmony_ci		uc_error("Syntax field is invalid in %s", filename);
267d5ac70f0Sopenharmony_ci		return err;
268d5ac70f0Sopenharmony_ci	}
269d5ac70f0Sopenharmony_ci	if (l < 2 || l > SYNTAX_VERSION_MAX) {
270d5ac70f0Sopenharmony_ci		uc_error("Incompatible syntax %ld in %s", l, filename);
271d5ac70f0Sopenharmony_ci		return -EINVAL;
272d5ac70f0Sopenharmony_ci	}
273d5ac70f0Sopenharmony_ci	/* delete this field to optimize strcmp() call in the parsing loop */
274d5ac70f0Sopenharmony_ci	snd_config_delete(n);
275d5ac70f0Sopenharmony_ci	uc_mgr->conf_format = l;
276d5ac70f0Sopenharmony_ci	return l;
277d5ac70f0Sopenharmony_ci}
278d5ac70f0Sopenharmony_ci
279d5ac70f0Sopenharmony_ci/*
280d5ac70f0Sopenharmony_ci * Evaluate variable regex definitions (in-place delete)
281d5ac70f0Sopenharmony_ci */
282d5ac70f0Sopenharmony_cistatic int evaluate_regex(snd_use_case_mgr_t *uc_mgr,
283d5ac70f0Sopenharmony_ci			  snd_config_t *cfg)
284d5ac70f0Sopenharmony_ci{
285d5ac70f0Sopenharmony_ci	snd_config_iterator_t i, next;
286d5ac70f0Sopenharmony_ci	snd_config_t *d, *n;
287d5ac70f0Sopenharmony_ci	const char *id;
288d5ac70f0Sopenharmony_ci	int err;
289d5ac70f0Sopenharmony_ci
290d5ac70f0Sopenharmony_ci	err = snd_config_search(cfg, "DefineRegex", &d);
291d5ac70f0Sopenharmony_ci	if (err == -ENOENT)
292d5ac70f0Sopenharmony_ci		return 1;
293d5ac70f0Sopenharmony_ci	if (err < 0)
294d5ac70f0Sopenharmony_ci		return err;
295d5ac70f0Sopenharmony_ci
296d5ac70f0Sopenharmony_ci	if (snd_config_get_type(d) != SND_CONFIG_TYPE_COMPOUND) {
297d5ac70f0Sopenharmony_ci		uc_error("compound type expected for DefineRegex");
298d5ac70f0Sopenharmony_ci		return -EINVAL;
299d5ac70f0Sopenharmony_ci	}
300d5ac70f0Sopenharmony_ci
301d5ac70f0Sopenharmony_ci	if (uc_mgr->conf_format < 3) {
302d5ac70f0Sopenharmony_ci		uc_error("DefineRegex is supported in v3+ syntax");
303d5ac70f0Sopenharmony_ci		return -EINVAL;
304d5ac70f0Sopenharmony_ci	}
305d5ac70f0Sopenharmony_ci
306d5ac70f0Sopenharmony_ci	snd_config_for_each(i, next, d) {
307d5ac70f0Sopenharmony_ci		n = snd_config_iterator_entry(i);
308d5ac70f0Sopenharmony_ci		err = snd_config_get_id(n, &id);
309d5ac70f0Sopenharmony_ci		if (err < 0)
310d5ac70f0Sopenharmony_ci			return err;
311d5ac70f0Sopenharmony_ci		if (id[0] == '@') {
312d5ac70f0Sopenharmony_ci			uc_error("error: value names starting with '@' are reserved for application variables");
313d5ac70f0Sopenharmony_ci			return -EINVAL;
314d5ac70f0Sopenharmony_ci		}
315d5ac70f0Sopenharmony_ci		err = uc_mgr_define_regex(uc_mgr, id, n);
316d5ac70f0Sopenharmony_ci		if (err < 0)
317d5ac70f0Sopenharmony_ci			return err;
318d5ac70f0Sopenharmony_ci	}
319d5ac70f0Sopenharmony_ci
320d5ac70f0Sopenharmony_ci	snd_config_delete(d);
321d5ac70f0Sopenharmony_ci	return 0;
322d5ac70f0Sopenharmony_ci}
323d5ac70f0Sopenharmony_ci
324d5ac70f0Sopenharmony_ci/*
325d5ac70f0Sopenharmony_ci * Evaluate variable definitions (in-place delete)
326d5ac70f0Sopenharmony_ci */
327d5ac70f0Sopenharmony_cistatic int evaluate_define(snd_use_case_mgr_t *uc_mgr,
328d5ac70f0Sopenharmony_ci			   snd_config_t *cfg)
329d5ac70f0Sopenharmony_ci{
330d5ac70f0Sopenharmony_ci	snd_config_iterator_t i, next;
331d5ac70f0Sopenharmony_ci	snd_config_t *d, *n;
332d5ac70f0Sopenharmony_ci	const char *id;
333d5ac70f0Sopenharmony_ci	char *var, *s;
334d5ac70f0Sopenharmony_ci	int err;
335d5ac70f0Sopenharmony_ci
336d5ac70f0Sopenharmony_ci	err = snd_config_search(cfg, "Define", &d);
337d5ac70f0Sopenharmony_ci	if (err == -ENOENT)
338d5ac70f0Sopenharmony_ci		return evaluate_regex(uc_mgr, cfg);
339d5ac70f0Sopenharmony_ci	if (err < 0)
340d5ac70f0Sopenharmony_ci		return err;
341d5ac70f0Sopenharmony_ci
342d5ac70f0Sopenharmony_ci	if (snd_config_get_type(d) != SND_CONFIG_TYPE_COMPOUND) {
343d5ac70f0Sopenharmony_ci		uc_error("compound type expected for Define");
344d5ac70f0Sopenharmony_ci		return -EINVAL;
345d5ac70f0Sopenharmony_ci	}
346d5ac70f0Sopenharmony_ci
347d5ac70f0Sopenharmony_ci	if (uc_mgr->conf_format < 3) {
348d5ac70f0Sopenharmony_ci		uc_error("Define is supported in v3+ syntax");
349d5ac70f0Sopenharmony_ci		return -EINVAL;
350d5ac70f0Sopenharmony_ci	}
351d5ac70f0Sopenharmony_ci
352d5ac70f0Sopenharmony_ci	snd_config_for_each(i, next, d) {
353d5ac70f0Sopenharmony_ci		n = snd_config_iterator_entry(i);
354d5ac70f0Sopenharmony_ci		err = snd_config_get_id(n, &id);
355d5ac70f0Sopenharmony_ci		if (err < 0)
356d5ac70f0Sopenharmony_ci			return err;
357d5ac70f0Sopenharmony_ci		err = snd_config_get_ascii(n, &var);
358d5ac70f0Sopenharmony_ci		if (err < 0)
359d5ac70f0Sopenharmony_ci			return err;
360d5ac70f0Sopenharmony_ci		err = uc_mgr_get_substituted_value(uc_mgr, &s, var);
361d5ac70f0Sopenharmony_ci		free(var);
362d5ac70f0Sopenharmony_ci		if (err < 0)
363d5ac70f0Sopenharmony_ci			return err;
364d5ac70f0Sopenharmony_ci		if (id[0] == '@') {
365d5ac70f0Sopenharmony_ci			free(s);
366d5ac70f0Sopenharmony_ci			uc_error("error: value names starting with '@' are reserved for application variables");
367d5ac70f0Sopenharmony_ci			return -EINVAL;
368d5ac70f0Sopenharmony_ci		}
369d5ac70f0Sopenharmony_ci		err = uc_mgr_set_variable(uc_mgr, id, s);
370d5ac70f0Sopenharmony_ci		free(s);
371d5ac70f0Sopenharmony_ci		if (err < 0)
372d5ac70f0Sopenharmony_ci			return err;
373d5ac70f0Sopenharmony_ci	}
374d5ac70f0Sopenharmony_ci
375d5ac70f0Sopenharmony_ci	snd_config_delete(d);
376d5ac70f0Sopenharmony_ci
377d5ac70f0Sopenharmony_ci	return evaluate_regex(uc_mgr, cfg);
378d5ac70f0Sopenharmony_ci}
379d5ac70f0Sopenharmony_ci
380d5ac70f0Sopenharmony_ci/*
381d5ac70f0Sopenharmony_ci * Evaluate macro definitions (in-place delete)
382d5ac70f0Sopenharmony_ci */
383d5ac70f0Sopenharmony_cistatic int evaluate_define_macro(snd_use_case_mgr_t *uc_mgr,
384d5ac70f0Sopenharmony_ci				 snd_config_t *cfg)
385d5ac70f0Sopenharmony_ci{
386d5ac70f0Sopenharmony_ci	snd_config_t *d;
387d5ac70f0Sopenharmony_ci	int err;
388d5ac70f0Sopenharmony_ci
389d5ac70f0Sopenharmony_ci	err = snd_config_search(cfg, "DefineMacro", &d);
390d5ac70f0Sopenharmony_ci	if (err == -ENOENT)
391d5ac70f0Sopenharmony_ci		return 1;
392d5ac70f0Sopenharmony_ci	if (err < 0)
393d5ac70f0Sopenharmony_ci		return err;
394d5ac70f0Sopenharmony_ci
395d5ac70f0Sopenharmony_ci	if (snd_config_get_type(d) != SND_CONFIG_TYPE_COMPOUND) {
396d5ac70f0Sopenharmony_ci		uc_error("compound type expected for DefineMacro");
397d5ac70f0Sopenharmony_ci		return -EINVAL;
398d5ac70f0Sopenharmony_ci	}
399d5ac70f0Sopenharmony_ci
400d5ac70f0Sopenharmony_ci	if (uc_mgr->conf_format < 6) {
401d5ac70f0Sopenharmony_ci		uc_error("DefineMacro is supported in v6+ syntax");
402d5ac70f0Sopenharmony_ci		return -EINVAL;
403d5ac70f0Sopenharmony_ci	}
404d5ac70f0Sopenharmony_ci
405d5ac70f0Sopenharmony_ci	err = snd_config_merge(uc_mgr->macros, d, 0);
406d5ac70f0Sopenharmony_ci	if (err < 0)
407d5ac70f0Sopenharmony_ci		return err;
408d5ac70f0Sopenharmony_ci	return 0;
409d5ac70f0Sopenharmony_ci}
410d5ac70f0Sopenharmony_ci
411d5ac70f0Sopenharmony_cistatic int evaluate_macro1(snd_use_case_mgr_t *uc_mgr,
412d5ac70f0Sopenharmony_ci			   snd_config_t *dst,
413d5ac70f0Sopenharmony_ci			   snd_config_t *args)
414d5ac70f0Sopenharmony_ci{
415d5ac70f0Sopenharmony_ci	snd_config_iterator_t i, next;
416d5ac70f0Sopenharmony_ci	snd_config_t *m, *mc, *a, *n;
417d5ac70f0Sopenharmony_ci	const char *mid, *id;
418d5ac70f0Sopenharmony_ci	char name[128], *var;
419d5ac70f0Sopenharmony_ci	const char *s;
420d5ac70f0Sopenharmony_ci	int err;
421d5ac70f0Sopenharmony_ci
422d5ac70f0Sopenharmony_ci	err = snd_config_get_id(args, &mid);
423d5ac70f0Sopenharmony_ci	if (err < 0)
424d5ac70f0Sopenharmony_ci		return err;
425d5ac70f0Sopenharmony_ci	err = snd_config_search(uc_mgr->macros, mid, &m);
426d5ac70f0Sopenharmony_ci	if (err < 0) {
427d5ac70f0Sopenharmony_ci		uc_error("Macro '%s' is not defined", mid);
428d5ac70f0Sopenharmony_ci		return err;
429d5ac70f0Sopenharmony_ci	}
430d5ac70f0Sopenharmony_ci
431d5ac70f0Sopenharmony_ci	a = args;
432d5ac70f0Sopenharmony_ci	if (snd_config_get_type(args) == SND_CONFIG_TYPE_STRING) {
433d5ac70f0Sopenharmony_ci		err = snd_config_get_string(args, &s);
434d5ac70f0Sopenharmony_ci		if (err < 0)
435d5ac70f0Sopenharmony_ci			return err;
436d5ac70f0Sopenharmony_ci		err = snd_config_load_string(&a, s, 0);
437d5ac70f0Sopenharmony_ci		if (err < 0)
438d5ac70f0Sopenharmony_ci			return err;
439d5ac70f0Sopenharmony_ci	} else if (snd_config_get_type(args) != SND_CONFIG_TYPE_COMPOUND) {
440d5ac70f0Sopenharmony_ci		return -EINVAL;
441d5ac70f0Sopenharmony_ci	}
442d5ac70f0Sopenharmony_ci
443d5ac70f0Sopenharmony_ci	/* set arguments */
444d5ac70f0Sopenharmony_ci	snd_config_for_each(i, next, a) {
445d5ac70f0Sopenharmony_ci		n = snd_config_iterator_entry(i);
446d5ac70f0Sopenharmony_ci		err = snd_config_get_id(n, &id);
447d5ac70f0Sopenharmony_ci		if (err < 0)
448d5ac70f0Sopenharmony_ci			goto __err_path;
449d5ac70f0Sopenharmony_ci		err = snd_config_get_ascii(n, &var);
450d5ac70f0Sopenharmony_ci		if (err < 0)
451d5ac70f0Sopenharmony_ci			goto __err_path;
452d5ac70f0Sopenharmony_ci		snprintf(name, sizeof(name), "__%s", id);
453d5ac70f0Sopenharmony_ci		err = uc_mgr_set_variable(uc_mgr, name, var);
454d5ac70f0Sopenharmony_ci		free(var);
455d5ac70f0Sopenharmony_ci		if (err < 0)
456d5ac70f0Sopenharmony_ci			goto __err_path;
457d5ac70f0Sopenharmony_ci	}
458d5ac70f0Sopenharmony_ci
459d5ac70f0Sopenharmony_ci	/* merge + substitute variables */
460d5ac70f0Sopenharmony_ci	err = snd_config_copy(&mc, m);
461d5ac70f0Sopenharmony_ci	if (err < 0)
462d5ac70f0Sopenharmony_ci		goto __err_path;
463d5ac70f0Sopenharmony_ci	err = uc_mgr_evaluate_inplace(uc_mgr, mc);
464d5ac70f0Sopenharmony_ci	if (err < 0) {
465d5ac70f0Sopenharmony_ci		snd_config_delete(mc);
466d5ac70f0Sopenharmony_ci		goto __err_path;
467d5ac70f0Sopenharmony_ci	}
468d5ac70f0Sopenharmony_ci	err = uc_mgr_config_tree_merge(uc_mgr, dst, mc, NULL, NULL);
469d5ac70f0Sopenharmony_ci	snd_config_delete(mc);
470d5ac70f0Sopenharmony_ci
471d5ac70f0Sopenharmony_ci	/* delete arguments */
472d5ac70f0Sopenharmony_ci	snd_config_for_each(i, next, a) {
473d5ac70f0Sopenharmony_ci		n = snd_config_iterator_entry(i);
474d5ac70f0Sopenharmony_ci		err = snd_config_get_id(n, &id);
475d5ac70f0Sopenharmony_ci		if (err < 0)
476d5ac70f0Sopenharmony_ci			goto __err_path;
477d5ac70f0Sopenharmony_ci		snprintf(name, sizeof(name), "__%s", id);
478d5ac70f0Sopenharmony_ci		err = uc_mgr_delete_variable(uc_mgr, name);
479d5ac70f0Sopenharmony_ci		if (err < 0)
480d5ac70f0Sopenharmony_ci			goto __err_path;
481d5ac70f0Sopenharmony_ci	}
482d5ac70f0Sopenharmony_ci
483d5ac70f0Sopenharmony_ci__err_path:
484d5ac70f0Sopenharmony_ci	if (a != args)
485d5ac70f0Sopenharmony_ci		snd_config_delete(a);
486d5ac70f0Sopenharmony_ci	return err;
487d5ac70f0Sopenharmony_ci}
488d5ac70f0Sopenharmony_ci
489d5ac70f0Sopenharmony_ci/*
490d5ac70f0Sopenharmony_ci * Evaluate macro definitions and instances (in-place delete)
491d5ac70f0Sopenharmony_ci */
492d5ac70f0Sopenharmony_cistatic int evaluate_macro(snd_use_case_mgr_t *uc_mgr,
493d5ac70f0Sopenharmony_ci			  snd_config_t *cfg)
494d5ac70f0Sopenharmony_ci{
495d5ac70f0Sopenharmony_ci	snd_config_iterator_t i, i2, next, next2;
496d5ac70f0Sopenharmony_ci	snd_config_t *d, *n, *n2;
497d5ac70f0Sopenharmony_ci	int err, ret;
498d5ac70f0Sopenharmony_ci
499d5ac70f0Sopenharmony_ci	ret = evaluate_define_macro(uc_mgr, cfg);
500d5ac70f0Sopenharmony_ci	if (ret < 0)
501d5ac70f0Sopenharmony_ci		return ret;
502d5ac70f0Sopenharmony_ci
503d5ac70f0Sopenharmony_ci	err = snd_config_search(cfg, "Macro", &d);
504d5ac70f0Sopenharmony_ci	if (err == -ENOENT)
505d5ac70f0Sopenharmony_ci		return ret;
506d5ac70f0Sopenharmony_ci	if (err < 0)
507d5ac70f0Sopenharmony_ci		return err;
508d5ac70f0Sopenharmony_ci
509d5ac70f0Sopenharmony_ci	if (snd_config_get_type(d) != SND_CONFIG_TYPE_COMPOUND) {
510d5ac70f0Sopenharmony_ci		uc_error("compound type expected for DefineMacro");
511d5ac70f0Sopenharmony_ci		return -EINVAL;
512d5ac70f0Sopenharmony_ci	}
513d5ac70f0Sopenharmony_ci
514d5ac70f0Sopenharmony_ci	if (uc_mgr->conf_format < 6) {
515d5ac70f0Sopenharmony_ci		uc_error("Macro is supported in v6+ syntax");
516d5ac70f0Sopenharmony_ci		return -EINVAL;
517d5ac70f0Sopenharmony_ci	}
518d5ac70f0Sopenharmony_ci
519d5ac70f0Sopenharmony_ci	snd_config_for_each(i, next, d) {
520d5ac70f0Sopenharmony_ci		n = snd_config_iterator_entry(i);
521d5ac70f0Sopenharmony_ci		if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
522d5ac70f0Sopenharmony_ci			const char *id;
523d5ac70f0Sopenharmony_ci			if (snd_config_get_id(n, &id))
524d5ac70f0Sopenharmony_ci				id = "";
525d5ac70f0Sopenharmony_ci			uc_error("compound type expected for Macro.%s", id);
526d5ac70f0Sopenharmony_ci			return -EINVAL;
527d5ac70f0Sopenharmony_ci		}
528d5ac70f0Sopenharmony_ci		snd_config_for_each(i2, next2, n) {
529d5ac70f0Sopenharmony_ci			n2 = snd_config_iterator_entry(i2);
530d5ac70f0Sopenharmony_ci			err = evaluate_macro1(uc_mgr, cfg, n2);
531d5ac70f0Sopenharmony_ci			if (err < 0)
532d5ac70f0Sopenharmony_ci				return err;
533d5ac70f0Sopenharmony_ci		}
534d5ac70f0Sopenharmony_ci	}
535d5ac70f0Sopenharmony_ci
536d5ac70f0Sopenharmony_ci	snd_config_delete(d);
537d5ac70f0Sopenharmony_ci
538d5ac70f0Sopenharmony_ci	return 0;
539d5ac70f0Sopenharmony_ci}
540d5ac70f0Sopenharmony_ci
541d5ac70f0Sopenharmony_ci/*
542d5ac70f0Sopenharmony_ci * Evaluate include (in-place)
543d5ac70f0Sopenharmony_ci */
544d5ac70f0Sopenharmony_cistatic int evaluate_include(snd_use_case_mgr_t *uc_mgr,
545d5ac70f0Sopenharmony_ci			    snd_config_t *cfg)
546d5ac70f0Sopenharmony_ci{
547d5ac70f0Sopenharmony_ci	snd_config_t *n;
548d5ac70f0Sopenharmony_ci	int err;
549d5ac70f0Sopenharmony_ci
550d5ac70f0Sopenharmony_ci	err = snd_config_search(cfg, "Include", &n);
551d5ac70f0Sopenharmony_ci	if (err == -ENOENT)
552d5ac70f0Sopenharmony_ci		return 1;
553d5ac70f0Sopenharmony_ci	if (err < 0)
554d5ac70f0Sopenharmony_ci		return err;
555d5ac70f0Sopenharmony_ci
556d5ac70f0Sopenharmony_ci	err = uc_mgr_evaluate_include(uc_mgr, cfg, n);
557d5ac70f0Sopenharmony_ci	snd_config_delete(n);
558d5ac70f0Sopenharmony_ci	return err;
559d5ac70f0Sopenharmony_ci}
560d5ac70f0Sopenharmony_ci
561d5ac70f0Sopenharmony_ci/*
562d5ac70f0Sopenharmony_ci * Evaluate condition (in-place)
563d5ac70f0Sopenharmony_ci */
564d5ac70f0Sopenharmony_cistatic int evaluate_condition(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
565d5ac70f0Sopenharmony_ci{
566d5ac70f0Sopenharmony_ci	snd_config_t *n;
567d5ac70f0Sopenharmony_ci	int err;
568d5ac70f0Sopenharmony_ci
569d5ac70f0Sopenharmony_ci	err = snd_config_search(cfg, "If", &n);
570d5ac70f0Sopenharmony_ci	if (err == -ENOENT)
571d5ac70f0Sopenharmony_ci		return 1;
572d5ac70f0Sopenharmony_ci	if (err < 0)
573d5ac70f0Sopenharmony_ci		return err;
574d5ac70f0Sopenharmony_ci
575d5ac70f0Sopenharmony_ci	err = uc_mgr_evaluate_condition(uc_mgr, cfg, n);
576d5ac70f0Sopenharmony_ci	snd_config_delete(n);
577d5ac70f0Sopenharmony_ci	return err;
578d5ac70f0Sopenharmony_ci}
579d5ac70f0Sopenharmony_ci
580d5ac70f0Sopenharmony_ci/*
581d5ac70f0Sopenharmony_ci * Evaluate variant (in-place)
582d5ac70f0Sopenharmony_ci */
583d5ac70f0Sopenharmony_cistatic int evaluate_variant(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
584d5ac70f0Sopenharmony_ci{
585d5ac70f0Sopenharmony_ci	snd_config_iterator_t i, next;
586d5ac70f0Sopenharmony_ci	snd_config_t *n, *c;
587d5ac70f0Sopenharmony_ci	const char *id;
588d5ac70f0Sopenharmony_ci	int err;
589d5ac70f0Sopenharmony_ci
590d5ac70f0Sopenharmony_ci	err = snd_config_search(cfg, "Variant", &c);
591d5ac70f0Sopenharmony_ci	if (err == -ENOENT)
592d5ac70f0Sopenharmony_ci		return 1;
593d5ac70f0Sopenharmony_ci	if (err < 0)
594d5ac70f0Sopenharmony_ci		return err;
595d5ac70f0Sopenharmony_ci
596d5ac70f0Sopenharmony_ci	if (uc_mgr->conf_format < 6) {
597d5ac70f0Sopenharmony_ci		uc_error("Variant is supported in v6+ syntax");
598d5ac70f0Sopenharmony_ci		return -EINVAL;
599d5ac70f0Sopenharmony_ci	}
600d5ac70f0Sopenharmony_ci
601d5ac70f0Sopenharmony_ci	if (uc_mgr->parse_master_section)
602d5ac70f0Sopenharmony_ci		return 1;
603d5ac70f0Sopenharmony_ci
604d5ac70f0Sopenharmony_ci	if (uc_mgr->parse_variant == NULL)
605d5ac70f0Sopenharmony_ci		goto __ret;
606d5ac70f0Sopenharmony_ci
607d5ac70f0Sopenharmony_ci	snd_config_for_each(i, next, c) {
608d5ac70f0Sopenharmony_ci		n = snd_config_iterator_entry(i);
609d5ac70f0Sopenharmony_ci
610d5ac70f0Sopenharmony_ci		if (snd_config_get_id(n, &id) < 0)
611d5ac70f0Sopenharmony_ci			return -EINVAL;
612d5ac70f0Sopenharmony_ci
613d5ac70f0Sopenharmony_ci		if (strcmp(id, uc_mgr->parse_variant))
614d5ac70f0Sopenharmony_ci			continue;
615d5ac70f0Sopenharmony_ci
616d5ac70f0Sopenharmony_ci		err = uc_mgr_evaluate_inplace(uc_mgr, n);
617d5ac70f0Sopenharmony_ci		if (err < 0)
618d5ac70f0Sopenharmony_ci			return err;
619d5ac70f0Sopenharmony_ci
620d5ac70f0Sopenharmony_ci		err = uc_mgr_config_tree_merge(uc_mgr, cfg, n, NULL, NULL);
621d5ac70f0Sopenharmony_ci		if (err < 0)
622d5ac70f0Sopenharmony_ci			return err;
623d5ac70f0Sopenharmony_ci		snd_config_delete(c);
624d5ac70f0Sopenharmony_ci		return 0;
625d5ac70f0Sopenharmony_ci	}
626d5ac70f0Sopenharmony_ci
627d5ac70f0Sopenharmony_ci__ret:
628d5ac70f0Sopenharmony_ci	snd_config_delete(c);
629d5ac70f0Sopenharmony_ci	return 1;
630d5ac70f0Sopenharmony_ci}
631d5ac70f0Sopenharmony_ci
632d5ac70f0Sopenharmony_ci/*
633d5ac70f0Sopenharmony_ci * In-place evaluate
634d5ac70f0Sopenharmony_ci */
635d5ac70f0Sopenharmony_ciint uc_mgr_evaluate_inplace(snd_use_case_mgr_t *uc_mgr,
636d5ac70f0Sopenharmony_ci			    snd_config_t *cfg)
637d5ac70f0Sopenharmony_ci{
638d5ac70f0Sopenharmony_ci	long iterations = 10000;
639d5ac70f0Sopenharmony_ci	int err1 = 0, err2 = 0, err3 = 0, err4 = 0, err5 = 0;
640d5ac70f0Sopenharmony_ci
641d5ac70f0Sopenharmony_ci	while (err1 == 0 || err2 == 0 || err3 == 0 || err4 == 0 || err5 == 0) {
642d5ac70f0Sopenharmony_ci		if (iterations == 0) {
643d5ac70f0Sopenharmony_ci			uc_error("Maximal inplace evaluation iterations number reached (recursive references?)");
644d5ac70f0Sopenharmony_ci			return -EINVAL;
645d5ac70f0Sopenharmony_ci		}
646d5ac70f0Sopenharmony_ci		iterations--;
647d5ac70f0Sopenharmony_ci		/* variables at first */
648d5ac70f0Sopenharmony_ci		err1 = evaluate_define(uc_mgr, cfg);
649d5ac70f0Sopenharmony_ci		if (err1 < 0)
650d5ac70f0Sopenharmony_ci			return err1;
651d5ac70f0Sopenharmony_ci		/* include at second */
652d5ac70f0Sopenharmony_ci		err2 = evaluate_include(uc_mgr, cfg);
653d5ac70f0Sopenharmony_ci		if (err2 < 0)
654d5ac70f0Sopenharmony_ci			return err2;
655d5ac70f0Sopenharmony_ci		/* include or macro may define another variables */
656d5ac70f0Sopenharmony_ci		/* conditions may depend on them */
657d5ac70f0Sopenharmony_ci		if (err2 == 0)
658d5ac70f0Sopenharmony_ci			continue;
659d5ac70f0Sopenharmony_ci		err3 = evaluate_variant(uc_mgr, cfg);
660d5ac70f0Sopenharmony_ci		if (err3 < 0)
661d5ac70f0Sopenharmony_ci			return err3;
662d5ac70f0Sopenharmony_ci		if (err3 == 0)
663d5ac70f0Sopenharmony_ci			continue;
664d5ac70f0Sopenharmony_ci		uc_mgr->macro_hops++;
665d5ac70f0Sopenharmony_ci		if (uc_mgr->macro_hops > 100) {
666d5ac70f0Sopenharmony_ci			uc_error("Maximal macro hops reached!");
667d5ac70f0Sopenharmony_ci			return -EINVAL;
668d5ac70f0Sopenharmony_ci		}
669d5ac70f0Sopenharmony_ci		err4 = evaluate_macro(uc_mgr, cfg);
670d5ac70f0Sopenharmony_ci		uc_mgr->macro_hops--;
671d5ac70f0Sopenharmony_ci		if (err4 < 0)
672d5ac70f0Sopenharmony_ci			return err4;
673d5ac70f0Sopenharmony_ci		if (err4 == 0)
674d5ac70f0Sopenharmony_ci			continue;
675d5ac70f0Sopenharmony_ci		err5 = evaluate_condition(uc_mgr, cfg);
676d5ac70f0Sopenharmony_ci		if (err5 < 0)
677d5ac70f0Sopenharmony_ci			return err5;
678d5ac70f0Sopenharmony_ci	}
679d5ac70f0Sopenharmony_ci	return 0;
680d5ac70f0Sopenharmony_ci}
681d5ac70f0Sopenharmony_ci
682d5ac70f0Sopenharmony_ci/*
683d5ac70f0Sopenharmony_ci * Parse one item for alsa-lib config
684d5ac70f0Sopenharmony_ci */
685d5ac70f0Sopenharmony_cistatic int parse_libconfig1(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
686d5ac70f0Sopenharmony_ci{
687d5ac70f0Sopenharmony_ci	snd_config_iterator_t i, next;
688d5ac70f0Sopenharmony_ci	snd_config_t *n, *config = NULL;
689d5ac70f0Sopenharmony_ci	const char *id, *file = NULL;
690d5ac70f0Sopenharmony_ci	bool substfile = false, substconfig = false;
691d5ac70f0Sopenharmony_ci	int err;
692d5ac70f0Sopenharmony_ci
693d5ac70f0Sopenharmony_ci	if (snd_config_get_id(cfg, &id) < 0)
694d5ac70f0Sopenharmony_ci		return -EINVAL;
695d5ac70f0Sopenharmony_ci
696d5ac70f0Sopenharmony_ci	if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
697d5ac70f0Sopenharmony_ci		uc_error("compound type expected for %s", id);
698d5ac70f0Sopenharmony_ci		return -EINVAL;
699d5ac70f0Sopenharmony_ci	}
700d5ac70f0Sopenharmony_ci
701d5ac70f0Sopenharmony_ci	snd_config_for_each(i, next, cfg) {
702d5ac70f0Sopenharmony_ci		n = snd_config_iterator_entry(i);
703d5ac70f0Sopenharmony_ci
704d5ac70f0Sopenharmony_ci		if (snd_config_get_id(n, &id) < 0)
705d5ac70f0Sopenharmony_ci			return -EINVAL;
706d5ac70f0Sopenharmony_ci
707d5ac70f0Sopenharmony_ci		if (strcmp(id, "File") == 0 ||
708d5ac70f0Sopenharmony_ci		    strcmp(id, "SubstiFile") == 0) {
709d5ac70f0Sopenharmony_ci			substfile = id[0] == 'S';
710d5ac70f0Sopenharmony_ci			err = snd_config_get_string(n, &file);
711d5ac70f0Sopenharmony_ci			if (err < 0)
712d5ac70f0Sopenharmony_ci				return err;
713d5ac70f0Sopenharmony_ci			continue;
714d5ac70f0Sopenharmony_ci		}
715d5ac70f0Sopenharmony_ci
716d5ac70f0Sopenharmony_ci		if (strcmp(id, "Config") == 0 ||
717d5ac70f0Sopenharmony_ci		    strcmp(id, "SubstiConfig") == 0) {
718d5ac70f0Sopenharmony_ci			substconfig = id[0] == 'S';
719d5ac70f0Sopenharmony_ci			if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND)
720d5ac70f0Sopenharmony_ci				return -EINVAL;
721d5ac70f0Sopenharmony_ci			config = n;
722d5ac70f0Sopenharmony_ci			continue;
723d5ac70f0Sopenharmony_ci		}
724d5ac70f0Sopenharmony_ci
725d5ac70f0Sopenharmony_ci		uc_error("unknown field %s", id);
726d5ac70f0Sopenharmony_ci		return -EINVAL;
727d5ac70f0Sopenharmony_ci	}
728d5ac70f0Sopenharmony_ci
729d5ac70f0Sopenharmony_ci	if (file) {
730d5ac70f0Sopenharmony_ci		if (substfile) {
731d5ac70f0Sopenharmony_ci			snd_config_t *cfg;
732d5ac70f0Sopenharmony_ci			err = uc_mgr_config_load(uc_mgr->conf_format, file, &cfg);
733d5ac70f0Sopenharmony_ci			if (err < 0)
734d5ac70f0Sopenharmony_ci				return err;
735d5ac70f0Sopenharmony_ci			err = uc_mgr_substitute_tree(uc_mgr, cfg);
736d5ac70f0Sopenharmony_ci			if (err < 0) {
737d5ac70f0Sopenharmony_ci				snd_config_delete(cfg);
738d5ac70f0Sopenharmony_ci				return err;
739d5ac70f0Sopenharmony_ci			}
740d5ac70f0Sopenharmony_ci			err = snd_config_merge(uc_mgr->local_config, cfg, 0);
741d5ac70f0Sopenharmony_ci			if (err < 0) {
742d5ac70f0Sopenharmony_ci				snd_config_delete(cfg);
743d5ac70f0Sopenharmony_ci				return err;
744d5ac70f0Sopenharmony_ci			}
745d5ac70f0Sopenharmony_ci		} else {
746d5ac70f0Sopenharmony_ci			char filename[PATH_MAX];
747d5ac70f0Sopenharmony_ci
748d5ac70f0Sopenharmony_ci			ucm_filename(filename, sizeof(filename), uc_mgr->conf_format,
749d5ac70f0Sopenharmony_ci				     file[0] == '/' ? NULL : uc_mgr->conf_dir_name,
750d5ac70f0Sopenharmony_ci				     file);
751d5ac70f0Sopenharmony_ci			err = uc_mgr_config_load_into(uc_mgr->conf_format, filename, uc_mgr->local_config);
752d5ac70f0Sopenharmony_ci			if (err < 0)
753d5ac70f0Sopenharmony_ci				return err;
754d5ac70f0Sopenharmony_ci		}
755d5ac70f0Sopenharmony_ci	}
756d5ac70f0Sopenharmony_ci
757d5ac70f0Sopenharmony_ci	if (config) {
758d5ac70f0Sopenharmony_ci		if (substconfig) {
759d5ac70f0Sopenharmony_ci			err = uc_mgr_substitute_tree(uc_mgr, config);
760d5ac70f0Sopenharmony_ci			if (err < 0)
761d5ac70f0Sopenharmony_ci				return err;
762d5ac70f0Sopenharmony_ci		}
763d5ac70f0Sopenharmony_ci		err = snd_config_merge(uc_mgr->local_config, config, 0);
764d5ac70f0Sopenharmony_ci		if (err < 0)
765d5ac70f0Sopenharmony_ci			return err;
766d5ac70f0Sopenharmony_ci	}
767d5ac70f0Sopenharmony_ci
768d5ac70f0Sopenharmony_ci	return 0;
769d5ac70f0Sopenharmony_ci}
770d5ac70f0Sopenharmony_ci
771d5ac70f0Sopenharmony_ci/*
772d5ac70f0Sopenharmony_ci * Parse alsa-lib config
773d5ac70f0Sopenharmony_ci */
774d5ac70f0Sopenharmony_cistatic int parse_libconfig(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
775d5ac70f0Sopenharmony_ci{
776d5ac70f0Sopenharmony_ci	snd_config_iterator_t i, next;
777d5ac70f0Sopenharmony_ci	snd_config_t *n;
778d5ac70f0Sopenharmony_ci	const char *id;
779d5ac70f0Sopenharmony_ci	int err;
780d5ac70f0Sopenharmony_ci
781d5ac70f0Sopenharmony_ci	if (snd_config_get_id(cfg, &id) < 0)
782d5ac70f0Sopenharmony_ci		return -EINVAL;
783d5ac70f0Sopenharmony_ci
784d5ac70f0Sopenharmony_ci	if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
785d5ac70f0Sopenharmony_ci		uc_error("compound type expected for %s", id);
786d5ac70f0Sopenharmony_ci		return -EINVAL;
787d5ac70f0Sopenharmony_ci	}
788d5ac70f0Sopenharmony_ci
789d5ac70f0Sopenharmony_ci	snd_config_for_each(i, next, cfg) {
790d5ac70f0Sopenharmony_ci		n = snd_config_iterator_entry(i);
791d5ac70f0Sopenharmony_ci
792d5ac70f0Sopenharmony_ci		err = parse_libconfig1(uc_mgr, n);
793d5ac70f0Sopenharmony_ci		if (err < 0)
794d5ac70f0Sopenharmony_ci			return err;
795d5ac70f0Sopenharmony_ci	}
796d5ac70f0Sopenharmony_ci
797d5ac70f0Sopenharmony_ci	return 0;
798d5ac70f0Sopenharmony_ci}
799d5ac70f0Sopenharmony_ci
800d5ac70f0Sopenharmony_ci/*
801d5ac70f0Sopenharmony_ci * Parse transition
802d5ac70f0Sopenharmony_ci */
803d5ac70f0Sopenharmony_cistatic int parse_transition(snd_use_case_mgr_t *uc_mgr,
804d5ac70f0Sopenharmony_ci			    struct list_head *tlist,
805d5ac70f0Sopenharmony_ci			    snd_config_t *cfg)
806d5ac70f0Sopenharmony_ci{
807d5ac70f0Sopenharmony_ci	struct transition_sequence *tseq;
808d5ac70f0Sopenharmony_ci	const char *id;
809d5ac70f0Sopenharmony_ci	snd_config_iterator_t i, next;
810d5ac70f0Sopenharmony_ci	snd_config_t *n;
811d5ac70f0Sopenharmony_ci	int err;
812d5ac70f0Sopenharmony_ci
813d5ac70f0Sopenharmony_ci	if (snd_config_get_id(cfg, &id) < 0)
814d5ac70f0Sopenharmony_ci		return -EINVAL;
815d5ac70f0Sopenharmony_ci
816d5ac70f0Sopenharmony_ci	if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
817d5ac70f0Sopenharmony_ci		uc_error("compound type expected for %s", id);
818d5ac70f0Sopenharmony_ci		return -EINVAL;
819d5ac70f0Sopenharmony_ci	}
820d5ac70f0Sopenharmony_ci
821d5ac70f0Sopenharmony_ci	snd_config_for_each(i, next, cfg) {
822d5ac70f0Sopenharmony_ci		n = snd_config_iterator_entry(i);
823d5ac70f0Sopenharmony_ci
824d5ac70f0Sopenharmony_ci		if (snd_config_get_id(n, &id) < 0)
825d5ac70f0Sopenharmony_ci			return -EINVAL;
826d5ac70f0Sopenharmony_ci
827d5ac70f0Sopenharmony_ci		tseq = calloc(1, sizeof(*tseq));
828d5ac70f0Sopenharmony_ci		if (tseq == NULL)
829d5ac70f0Sopenharmony_ci			return -ENOMEM;
830d5ac70f0Sopenharmony_ci		INIT_LIST_HEAD(&tseq->transition_list);
831d5ac70f0Sopenharmony_ci
832d5ac70f0Sopenharmony_ci		err = get_string3(uc_mgr, id, &tseq->name);
833d5ac70f0Sopenharmony_ci		if (err < 0) {
834d5ac70f0Sopenharmony_ci			free(tseq);
835d5ac70f0Sopenharmony_ci			return err;
836d5ac70f0Sopenharmony_ci		}
837d5ac70f0Sopenharmony_ci
838d5ac70f0Sopenharmony_ci		err = parse_sequence(uc_mgr, &tseq->transition_list, n);
839d5ac70f0Sopenharmony_ci		if (err < 0) {
840d5ac70f0Sopenharmony_ci			uc_mgr_free_transition_element(tseq);
841d5ac70f0Sopenharmony_ci			return err;
842d5ac70f0Sopenharmony_ci		}
843d5ac70f0Sopenharmony_ci
844d5ac70f0Sopenharmony_ci		list_add(&tseq->list, tlist);
845d5ac70f0Sopenharmony_ci	}
846d5ac70f0Sopenharmony_ci	return 0;
847d5ac70f0Sopenharmony_ci}
848d5ac70f0Sopenharmony_ci
849d5ac70f0Sopenharmony_ci/*
850d5ac70f0Sopenharmony_ci * Parse compound
851d5ac70f0Sopenharmony_ci */
852d5ac70f0Sopenharmony_cistatic int parse_compound(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg,
853d5ac70f0Sopenharmony_ci	  int (*fcn)(snd_use_case_mgr_t *, snd_config_t *, void *, void *),
854d5ac70f0Sopenharmony_ci	  void *data1, void *data2)
855d5ac70f0Sopenharmony_ci{
856d5ac70f0Sopenharmony_ci	const char *id;
857d5ac70f0Sopenharmony_ci	snd_config_iterator_t i, next;
858d5ac70f0Sopenharmony_ci	snd_config_t *n;
859d5ac70f0Sopenharmony_ci	int err;
860d5ac70f0Sopenharmony_ci
861d5ac70f0Sopenharmony_ci	if (snd_config_get_id(cfg, &id) < 0)
862d5ac70f0Sopenharmony_ci		return -EINVAL;
863d5ac70f0Sopenharmony_ci
864d5ac70f0Sopenharmony_ci	if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
865d5ac70f0Sopenharmony_ci		uc_error("compound type expected for %s", id);
866d5ac70f0Sopenharmony_ci		return -EINVAL;
867d5ac70f0Sopenharmony_ci	}
868d5ac70f0Sopenharmony_ci	/* parse compound */
869d5ac70f0Sopenharmony_ci	snd_config_for_each(i, next, cfg) {
870d5ac70f0Sopenharmony_ci		n = snd_config_iterator_entry(i);
871d5ac70f0Sopenharmony_ci
872d5ac70f0Sopenharmony_ci		if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
873d5ac70f0Sopenharmony_ci			uc_error("compound type expected for %s, is %d", id, snd_config_get_type(cfg));
874d5ac70f0Sopenharmony_ci			return -EINVAL;
875d5ac70f0Sopenharmony_ci		}
876d5ac70f0Sopenharmony_ci
877d5ac70f0Sopenharmony_ci		err = fcn(uc_mgr, n, data1, data2);
878d5ac70f0Sopenharmony_ci		if (err < 0)
879d5ac70f0Sopenharmony_ci			return err;
880d5ac70f0Sopenharmony_ci	}
881d5ac70f0Sopenharmony_ci
882d5ac70f0Sopenharmony_ci	return 0;
883d5ac70f0Sopenharmony_ci}
884d5ac70f0Sopenharmony_ci
885d5ac70f0Sopenharmony_cistatic int strip_legacy_dev_index(char *name)
886d5ac70f0Sopenharmony_ci{
887d5ac70f0Sopenharmony_ci	char *dot = strchr(name, '.');
888d5ac70f0Sopenharmony_ci	if (!dot)
889d5ac70f0Sopenharmony_ci		return 0;
890d5ac70f0Sopenharmony_ci	if (dot[1] != '0' || dot[2] != '\0') {
891d5ac70f0Sopenharmony_ci		uc_error("device name %s contains a '.',"
892d5ac70f0Sopenharmony_ci			 " and is not legacy foo.0 format", name);
893d5ac70f0Sopenharmony_ci		return -EINVAL;
894d5ac70f0Sopenharmony_ci	}
895d5ac70f0Sopenharmony_ci	*dot = '\0';
896d5ac70f0Sopenharmony_ci	return 0;
897d5ac70f0Sopenharmony_ci}
898d5ac70f0Sopenharmony_ci
899d5ac70f0Sopenharmony_ci/*
900d5ac70f0Sopenharmony_ci * Parse device list
901d5ac70f0Sopenharmony_ci */
902d5ac70f0Sopenharmony_cistatic int parse_device_list(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED,
903d5ac70f0Sopenharmony_ci			     struct dev_list *dev_list,
904d5ac70f0Sopenharmony_ci			     enum dev_list_type type,
905d5ac70f0Sopenharmony_ci			     snd_config_t *cfg)
906d5ac70f0Sopenharmony_ci{
907d5ac70f0Sopenharmony_ci	struct dev_list_node *sdev;
908d5ac70f0Sopenharmony_ci	const char *id;
909d5ac70f0Sopenharmony_ci	snd_config_iterator_t i, next;
910d5ac70f0Sopenharmony_ci	snd_config_t *n;
911d5ac70f0Sopenharmony_ci	int err;
912d5ac70f0Sopenharmony_ci
913d5ac70f0Sopenharmony_ci	if (dev_list->type != DEVLIST_NONE) {
914d5ac70f0Sopenharmony_ci		uc_error("error: multiple supported or"
915d5ac70f0Sopenharmony_ci			" conflicting device lists");
916d5ac70f0Sopenharmony_ci		return -EEXIST;
917d5ac70f0Sopenharmony_ci	}
918d5ac70f0Sopenharmony_ci
919d5ac70f0Sopenharmony_ci	if (snd_config_get_id(cfg, &id) < 0)
920d5ac70f0Sopenharmony_ci		return -EINVAL;
921d5ac70f0Sopenharmony_ci
922d5ac70f0Sopenharmony_ci	if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
923d5ac70f0Sopenharmony_ci		uc_error("compound type expected for %s", id);
924d5ac70f0Sopenharmony_ci		return -EINVAL;
925d5ac70f0Sopenharmony_ci	}
926d5ac70f0Sopenharmony_ci
927d5ac70f0Sopenharmony_ci	snd_config_for_each(i, next, cfg) {
928d5ac70f0Sopenharmony_ci		n = snd_config_iterator_entry(i);
929d5ac70f0Sopenharmony_ci
930d5ac70f0Sopenharmony_ci		if (snd_config_get_id(n, &id) < 0)
931d5ac70f0Sopenharmony_ci			return -EINVAL;
932d5ac70f0Sopenharmony_ci
933d5ac70f0Sopenharmony_ci		sdev = calloc(1, sizeof(struct dev_list_node));
934d5ac70f0Sopenharmony_ci		if (sdev == NULL)
935d5ac70f0Sopenharmony_ci			return -ENOMEM;
936d5ac70f0Sopenharmony_ci		err = parse_string_substitute3(uc_mgr, n, &sdev->name);
937d5ac70f0Sopenharmony_ci		if (err < 0) {
938d5ac70f0Sopenharmony_ci			free(sdev);
939d5ac70f0Sopenharmony_ci			return err;
940d5ac70f0Sopenharmony_ci		}
941d5ac70f0Sopenharmony_ci		err = strip_legacy_dev_index(sdev->name);
942d5ac70f0Sopenharmony_ci		if (err < 0) {
943d5ac70f0Sopenharmony_ci			free(sdev->name);
944d5ac70f0Sopenharmony_ci			free(sdev);
945d5ac70f0Sopenharmony_ci			return err;
946d5ac70f0Sopenharmony_ci		}
947d5ac70f0Sopenharmony_ci		list_add(&sdev->list, &dev_list->list);
948d5ac70f0Sopenharmony_ci	}
949d5ac70f0Sopenharmony_ci
950d5ac70f0Sopenharmony_ci	dev_list->type = type;
951d5ac70f0Sopenharmony_ci
952d5ac70f0Sopenharmony_ci	return 0;
953d5ac70f0Sopenharmony_ci}
954d5ac70f0Sopenharmony_ci
955d5ac70f0Sopenharmony_ci/* Find a component device by its name, and remove it from machine device
956d5ac70f0Sopenharmony_ci * list.
957d5ac70f0Sopenharmony_ci *
958d5ac70f0Sopenharmony_ci * Component devices are defined by machine components (usually off-soc
959d5ac70f0Sopenharmony_ci * codes or DSP embeded in SoC). Since alsaconf imports their configuration
960d5ac70f0Sopenharmony_ci * files automatically, we don't know which devices are component devices
961d5ac70f0Sopenharmony_ci * until they are referenced by a machine device sequence. So here when we
962d5ac70f0Sopenharmony_ci * find a referenced device, we move it from the machine device list to the
963d5ac70f0Sopenharmony_ci * component device list. Component devices will not be exposed to applications
964d5ac70f0Sopenharmony_ci * by the original API to list devices for backward compatibility. So sound
965d5ac70f0Sopenharmony_ci * servers can only see the machine devices.
966d5ac70f0Sopenharmony_ci */
967d5ac70f0Sopenharmony_cistruct use_case_device *find_component_dev(snd_use_case_mgr_t *uc_mgr,
968d5ac70f0Sopenharmony_ci	const char *name)
969d5ac70f0Sopenharmony_ci{
970d5ac70f0Sopenharmony_ci	struct list_head *pos, *posdev, *_posdev;
971d5ac70f0Sopenharmony_ci	struct use_case_verb *verb;
972d5ac70f0Sopenharmony_ci	struct use_case_device *dev;
973d5ac70f0Sopenharmony_ci
974d5ac70f0Sopenharmony_ci	list_for_each(pos, &uc_mgr->verb_list) {
975d5ac70f0Sopenharmony_ci		verb = list_entry(pos, struct use_case_verb, list);
976d5ac70f0Sopenharmony_ci
977d5ac70f0Sopenharmony_ci		/* search in the component device list */
978d5ac70f0Sopenharmony_ci		list_for_each(posdev, &verb->cmpt_device_list) {
979d5ac70f0Sopenharmony_ci			dev = list_entry(posdev, struct use_case_device, list);
980d5ac70f0Sopenharmony_ci			if (!strcmp(dev->name, name))
981d5ac70f0Sopenharmony_ci				return dev;
982d5ac70f0Sopenharmony_ci		}
983d5ac70f0Sopenharmony_ci
984d5ac70f0Sopenharmony_ci		/* search the machine device list */
985d5ac70f0Sopenharmony_ci		list_for_each_safe(posdev, _posdev, &verb->device_list) {
986d5ac70f0Sopenharmony_ci			dev = list_entry(posdev, struct use_case_device, list);
987d5ac70f0Sopenharmony_ci			if (!strcmp(dev->name, name)) {
988d5ac70f0Sopenharmony_ci				/* find the component device, move it from the
989d5ac70f0Sopenharmony_ci				 * machine device list to the component device
990d5ac70f0Sopenharmony_ci				 * list.
991d5ac70f0Sopenharmony_ci				 */
992d5ac70f0Sopenharmony_ci				list_del(&dev->list);
993d5ac70f0Sopenharmony_ci				list_add_tail(&dev->list,
994d5ac70f0Sopenharmony_ci					      &verb->cmpt_device_list);
995d5ac70f0Sopenharmony_ci				return dev;
996d5ac70f0Sopenharmony_ci			}
997d5ac70f0Sopenharmony_ci		}
998d5ac70f0Sopenharmony_ci	}
999d5ac70f0Sopenharmony_ci
1000d5ac70f0Sopenharmony_ci	return NULL;
1001d5ac70f0Sopenharmony_ci}
1002d5ac70f0Sopenharmony_ci
1003d5ac70f0Sopenharmony_ci/* parse sequence of a component device
1004d5ac70f0Sopenharmony_ci *
1005d5ac70f0Sopenharmony_ci * This function will find the component device and mark if its enable or
1006d5ac70f0Sopenharmony_ci * disable sequence is needed by its parenet device.
1007d5ac70f0Sopenharmony_ci */
1008d5ac70f0Sopenharmony_cistatic int parse_component_seq(snd_use_case_mgr_t *uc_mgr,
1009d5ac70f0Sopenharmony_ci			       snd_config_t *n, int enable,
1010d5ac70f0Sopenharmony_ci			       struct component_sequence *cmpt_seq)
1011d5ac70f0Sopenharmony_ci{
1012d5ac70f0Sopenharmony_ci	char *val;
1013d5ac70f0Sopenharmony_ci	int err;
1014d5ac70f0Sopenharmony_ci
1015d5ac70f0Sopenharmony_ci	err = parse_string_substitute3(uc_mgr, n, &val);
1016d5ac70f0Sopenharmony_ci	if (err < 0)
1017d5ac70f0Sopenharmony_ci		return err;
1018d5ac70f0Sopenharmony_ci
1019d5ac70f0Sopenharmony_ci	cmpt_seq->device = find_component_dev(uc_mgr, val);
1020d5ac70f0Sopenharmony_ci	if (!cmpt_seq->device) {
1021d5ac70f0Sopenharmony_ci		uc_error("error: Cannot find component device %s", val);
1022d5ac70f0Sopenharmony_ci		free(val);
1023d5ac70f0Sopenharmony_ci		return -EINVAL;
1024d5ac70f0Sopenharmony_ci	}
1025d5ac70f0Sopenharmony_ci	free(val);
1026d5ac70f0Sopenharmony_ci
1027d5ac70f0Sopenharmony_ci	/* Parent needs its enable or disable sequence */
1028d5ac70f0Sopenharmony_ci	cmpt_seq->enable = enable;
1029d5ac70f0Sopenharmony_ci
1030d5ac70f0Sopenharmony_ci	return 0;
1031d5ac70f0Sopenharmony_ci}
1032d5ac70f0Sopenharmony_ci
1033d5ac70f0Sopenharmony_ci/*
1034d5ac70f0Sopenharmony_ci * Parse sequences.
1035d5ac70f0Sopenharmony_ci *
1036d5ac70f0Sopenharmony_ci * Sequence controls elements  are in the following form:-
1037d5ac70f0Sopenharmony_ci *
1038d5ac70f0Sopenharmony_ci * cdev "hw:0"
1039d5ac70f0Sopenharmony_ci * cset "element_id_syntax value_syntax"
1040d5ac70f0Sopenharmony_ci * usleep time
1041d5ac70f0Sopenharmony_ci * exec "any unix command with arguments"
1042d5ac70f0Sopenharmony_ci * enadev "component device name"
1043d5ac70f0Sopenharmony_ci * disdev "component device name"
1044d5ac70f0Sopenharmony_ci *
1045d5ac70f0Sopenharmony_ci * e.g.
1046d5ac70f0Sopenharmony_ci *	cset "name='Master Playback Switch' 0,0"
1047d5ac70f0Sopenharmony_ci *      cset "iface=PCM,name='Disable HDMI',index=1 0"
1048d5ac70f0Sopenharmony_ci *	enadev "rt286:Headphones"
1049d5ac70f0Sopenharmony_ci *	disdev "rt286:Speaker"
1050d5ac70f0Sopenharmony_ci */
1051d5ac70f0Sopenharmony_cistatic int parse_sequence(snd_use_case_mgr_t *uc_mgr,
1052d5ac70f0Sopenharmony_ci			  struct list_head *base,
1053d5ac70f0Sopenharmony_ci			  snd_config_t *cfg)
1054d5ac70f0Sopenharmony_ci{
1055d5ac70f0Sopenharmony_ci	struct sequence_element *curr;
1056d5ac70f0Sopenharmony_ci	snd_config_iterator_t i, next;
1057d5ac70f0Sopenharmony_ci	snd_config_t *n;
1058d5ac70f0Sopenharmony_ci	int err, idx = 0;
1059d5ac70f0Sopenharmony_ci	const char *cmd = NULL;
1060d5ac70f0Sopenharmony_ci
1061d5ac70f0Sopenharmony_ci	if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
1062d5ac70f0Sopenharmony_ci		uc_error("error: compound is expected for sequence definition");
1063d5ac70f0Sopenharmony_ci		return -EINVAL;
1064d5ac70f0Sopenharmony_ci	}
1065d5ac70f0Sopenharmony_ci
1066d5ac70f0Sopenharmony_ci	snd_config_for_each(i, next, cfg) {
1067d5ac70f0Sopenharmony_ci		const char *id;
1068d5ac70f0Sopenharmony_ci		idx ^= 1;
1069d5ac70f0Sopenharmony_ci		n = snd_config_iterator_entry(i);
1070d5ac70f0Sopenharmony_ci		err = snd_config_get_id(n, &id);
1071d5ac70f0Sopenharmony_ci		if (err < 0)
1072d5ac70f0Sopenharmony_ci			continue;
1073d5ac70f0Sopenharmony_ci		if (idx == 1) {
1074d5ac70f0Sopenharmony_ci			if (snd_config_get_type(n) != SND_CONFIG_TYPE_STRING) {
1075d5ac70f0Sopenharmony_ci				uc_error("error: string type is expected for sequence command");
1076d5ac70f0Sopenharmony_ci				return -EINVAL;
1077d5ac70f0Sopenharmony_ci			}
1078d5ac70f0Sopenharmony_ci			snd_config_get_string(n, &cmd);
1079d5ac70f0Sopenharmony_ci			continue;
1080d5ac70f0Sopenharmony_ci		}
1081d5ac70f0Sopenharmony_ci
1082d5ac70f0Sopenharmony_ci		/* alloc new sequence element */
1083d5ac70f0Sopenharmony_ci		curr = calloc(1, sizeof(struct sequence_element));
1084d5ac70f0Sopenharmony_ci		if (curr == NULL)
1085d5ac70f0Sopenharmony_ci			return -ENOMEM;
1086d5ac70f0Sopenharmony_ci		list_add_tail(&curr->list, base);
1087d5ac70f0Sopenharmony_ci
1088d5ac70f0Sopenharmony_ci		if (strcmp(cmd, "cdev") == 0) {
1089d5ac70f0Sopenharmony_ci			curr->type = SEQUENCE_ELEMENT_TYPE_CDEV;
1090d5ac70f0Sopenharmony_ci			err = parse_string_substitute3(uc_mgr, n, &curr->data.cdev);
1091d5ac70f0Sopenharmony_ci			if (err < 0) {
1092d5ac70f0Sopenharmony_ci				uc_error("error: cdev requires a string!");
1093d5ac70f0Sopenharmony_ci				return err;
1094d5ac70f0Sopenharmony_ci			}
1095d5ac70f0Sopenharmony_ci			continue;
1096d5ac70f0Sopenharmony_ci		}
1097d5ac70f0Sopenharmony_ci
1098d5ac70f0Sopenharmony_ci		if (strcmp(cmd, "cset") == 0) {
1099d5ac70f0Sopenharmony_ci			curr->type = SEQUENCE_ELEMENT_TYPE_CSET;
1100d5ac70f0Sopenharmony_cicset:
1101d5ac70f0Sopenharmony_ci			err = parse_string_substitute3(uc_mgr, n, &curr->data.cset);
1102d5ac70f0Sopenharmony_ci			if (err < 0) {
1103d5ac70f0Sopenharmony_ci				uc_error("error: %s requires a string!", cmd);
1104d5ac70f0Sopenharmony_ci				return err;
1105d5ac70f0Sopenharmony_ci			}
1106d5ac70f0Sopenharmony_ci			continue;
1107d5ac70f0Sopenharmony_ci		}
1108d5ac70f0Sopenharmony_ci
1109d5ac70f0Sopenharmony_ci		if (strcmp(cmd, "enadev") == 0 ||
1110d5ac70f0Sopenharmony_ci		    strcmp(cmd, "disdev") == 0) {
1111d5ac70f0Sopenharmony_ci			/* need to enable or disable a component device */
1112d5ac70f0Sopenharmony_ci			curr->type = SEQUENCE_ELEMENT_TYPE_CMPT_SEQ;
1113d5ac70f0Sopenharmony_ci			err = parse_component_seq(uc_mgr, n,
1114d5ac70f0Sopenharmony_ci						strcmp(cmd, "enadev") == 0,
1115d5ac70f0Sopenharmony_ci						&curr->data.cmpt_seq);
1116d5ac70f0Sopenharmony_ci			if (err < 0) {
1117d5ac70f0Sopenharmony_ci				uc_error("error: %s requires a valid device!", cmd);
1118d5ac70f0Sopenharmony_ci				return err;
1119d5ac70f0Sopenharmony_ci			}
1120d5ac70f0Sopenharmony_ci			continue;
1121d5ac70f0Sopenharmony_ci		}
1122d5ac70f0Sopenharmony_ci
1123d5ac70f0Sopenharmony_ci		if (strcmp(cmd, "enadev2") == 0) {
1124d5ac70f0Sopenharmony_ci			curr->type = SEQUENCE_ELEMENT_TYPE_DEV_ENABLE_SEQ;
1125d5ac70f0Sopenharmony_ci			goto device;
1126d5ac70f0Sopenharmony_ci		}
1127d5ac70f0Sopenharmony_ci
1128d5ac70f0Sopenharmony_ci		if (strcmp(cmd, "disdev2") == 0) {
1129d5ac70f0Sopenharmony_ci			curr->type = SEQUENCE_ELEMENT_TYPE_DEV_DISABLE_SEQ;
1130d5ac70f0Sopenharmony_cidevice:
1131d5ac70f0Sopenharmony_ci			err = parse_string_substitute3(uc_mgr, n, &curr->data.device);
1132d5ac70f0Sopenharmony_ci			if (err < 0) {
1133d5ac70f0Sopenharmony_ci				uc_error("error: %s requires a valid device!", cmd);
1134d5ac70f0Sopenharmony_ci				return err;
1135d5ac70f0Sopenharmony_ci			}
1136d5ac70f0Sopenharmony_ci			continue;
1137d5ac70f0Sopenharmony_ci		}
1138d5ac70f0Sopenharmony_ci
1139d5ac70f0Sopenharmony_ci		if (strcmp(cmd, "disdevall") == 0) {
1140d5ac70f0Sopenharmony_ci			curr->type = SEQUENCE_ELEMENT_TYPE_DEV_DISABLE_ALL;
1141d5ac70f0Sopenharmony_ci			continue;
1142d5ac70f0Sopenharmony_ci		}
1143d5ac70f0Sopenharmony_ci
1144d5ac70f0Sopenharmony_ci		if (strcmp(cmd, "cset-bin-file") == 0) {
1145d5ac70f0Sopenharmony_ci			curr->type = SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE;
1146d5ac70f0Sopenharmony_ci			goto cset;
1147d5ac70f0Sopenharmony_ci		}
1148d5ac70f0Sopenharmony_ci
1149d5ac70f0Sopenharmony_ci		if (strcmp(cmd, "cset-tlv") == 0) {
1150d5ac70f0Sopenharmony_ci			curr->type = SEQUENCE_ELEMENT_TYPE_CSET_TLV;
1151d5ac70f0Sopenharmony_ci			goto cset;
1152d5ac70f0Sopenharmony_ci		}
1153d5ac70f0Sopenharmony_ci
1154d5ac70f0Sopenharmony_ci		if (strcmp(cmd, "cset-new") == 0) {
1155d5ac70f0Sopenharmony_ci			curr->type = SEQUENCE_ELEMENT_TYPE_CSET_NEW;
1156d5ac70f0Sopenharmony_ci			goto cset;
1157d5ac70f0Sopenharmony_ci		}
1158d5ac70f0Sopenharmony_ci
1159d5ac70f0Sopenharmony_ci		if (strcmp(cmd, "ctl-remove") == 0) {
1160d5ac70f0Sopenharmony_ci			curr->type = SEQUENCE_ELEMENT_TYPE_CTL_REMOVE;
1161d5ac70f0Sopenharmony_ci			goto cset;
1162d5ac70f0Sopenharmony_ci		}
1163d5ac70f0Sopenharmony_ci
1164d5ac70f0Sopenharmony_ci		if (strcmp(cmd, "sysw") == 0) {
1165d5ac70f0Sopenharmony_ci			curr->type = SEQUENCE_ELEMENT_TYPE_SYSSET;
1166d5ac70f0Sopenharmony_ci			err = parse_string_substitute3(uc_mgr, n, &curr->data.sysw);
1167d5ac70f0Sopenharmony_ci			if (err < 0) {
1168d5ac70f0Sopenharmony_ci				uc_error("error: sysw requires a string!");
1169d5ac70f0Sopenharmony_ci				return err;
1170d5ac70f0Sopenharmony_ci			}
1171d5ac70f0Sopenharmony_ci			continue;
1172d5ac70f0Sopenharmony_ci		}
1173d5ac70f0Sopenharmony_ci
1174d5ac70f0Sopenharmony_ci		if (strcmp(cmd, "usleep") == 0) {
1175d5ac70f0Sopenharmony_ci			curr->type = SEQUENCE_ELEMENT_TYPE_SLEEP;
1176d5ac70f0Sopenharmony_ci			err = parse_integer_substitute3(uc_mgr, n, &curr->data.sleep);
1177d5ac70f0Sopenharmony_ci			if (err < 0) {
1178d5ac70f0Sopenharmony_ci				uc_error("error: usleep requires integer!");
1179d5ac70f0Sopenharmony_ci				return err;
1180d5ac70f0Sopenharmony_ci			}
1181d5ac70f0Sopenharmony_ci			continue;
1182d5ac70f0Sopenharmony_ci		}
1183d5ac70f0Sopenharmony_ci
1184d5ac70f0Sopenharmony_ci		if (strcmp(cmd, "msleep") == 0) {
1185d5ac70f0Sopenharmony_ci			curr->type = SEQUENCE_ELEMENT_TYPE_SLEEP;
1186d5ac70f0Sopenharmony_ci			err = parse_integer_substitute3(uc_mgr, n, &curr->data.sleep);
1187d5ac70f0Sopenharmony_ci			if (err < 0) {
1188d5ac70f0Sopenharmony_ci				uc_error("error: msleep requires integer!");
1189d5ac70f0Sopenharmony_ci				return err;
1190d5ac70f0Sopenharmony_ci			}
1191d5ac70f0Sopenharmony_ci			curr->data.sleep *= 1000L;
1192d5ac70f0Sopenharmony_ci			continue;
1193d5ac70f0Sopenharmony_ci		}
1194d5ac70f0Sopenharmony_ci
1195d5ac70f0Sopenharmony_ci		if (strcmp(cmd, "exec") == 0) {
1196d5ac70f0Sopenharmony_ci			curr->type = SEQUENCE_ELEMENT_TYPE_EXEC;
1197d5ac70f0Sopenharmony_ciexec:
1198d5ac70f0Sopenharmony_ci			err = parse_string_substitute3(uc_mgr, n, &curr->data.exec);
1199d5ac70f0Sopenharmony_ci			if (err < 0) {
1200d5ac70f0Sopenharmony_ci				uc_error("error: exec requires a string!");
1201d5ac70f0Sopenharmony_ci				return err;
1202d5ac70f0Sopenharmony_ci			}
1203d5ac70f0Sopenharmony_ci			continue;
1204d5ac70f0Sopenharmony_ci		}
1205d5ac70f0Sopenharmony_ci
1206d5ac70f0Sopenharmony_ci		if (strcmp(cmd, "shell") == 0) {
1207d5ac70f0Sopenharmony_ci			curr->type = SEQUENCE_ELEMENT_TYPE_SHELL;
1208d5ac70f0Sopenharmony_ci			goto exec;
1209d5ac70f0Sopenharmony_ci		}
1210d5ac70f0Sopenharmony_ci
1211d5ac70f0Sopenharmony_ci		if (strcmp(cmd, "cfg-save") == 0) {
1212d5ac70f0Sopenharmony_ci			curr->type = SEQUENCE_ELEMENT_TYPE_CFGSAVE;
1213d5ac70f0Sopenharmony_ci			err = parse_string_substitute3(uc_mgr, n, &curr->data.cfgsave);
1214d5ac70f0Sopenharmony_ci			if (err < 0) {
1215d5ac70f0Sopenharmony_ci				uc_error("error: sysw requires a string!");
1216d5ac70f0Sopenharmony_ci				return err;
1217d5ac70f0Sopenharmony_ci			}
1218d5ac70f0Sopenharmony_ci			continue;
1219d5ac70f0Sopenharmony_ci		}
1220d5ac70f0Sopenharmony_ci
1221d5ac70f0Sopenharmony_ci		if (strcmp(cmd, "comment") == 0)
1222d5ac70f0Sopenharmony_ci			goto skip;
1223d5ac70f0Sopenharmony_ci
1224d5ac70f0Sopenharmony_ci		uc_error("error: sequence command '%s' is ignored", cmd);
1225d5ac70f0Sopenharmony_ci
1226d5ac70f0Sopenharmony_ciskip:
1227d5ac70f0Sopenharmony_ci		list_del(&curr->list);
1228d5ac70f0Sopenharmony_ci		uc_mgr_free_sequence_element(curr);
1229d5ac70f0Sopenharmony_ci	}
1230d5ac70f0Sopenharmony_ci
1231d5ac70f0Sopenharmony_ci	return 0;
1232d5ac70f0Sopenharmony_ci}
1233d5ac70f0Sopenharmony_ci
1234d5ac70f0Sopenharmony_ci/*
1235d5ac70f0Sopenharmony_ci *
1236d5ac70f0Sopenharmony_ci */
1237d5ac70f0Sopenharmony_ciint uc_mgr_add_value(struct list_head *base, const char *key, char *val)
1238d5ac70f0Sopenharmony_ci{
1239d5ac70f0Sopenharmony_ci	struct ucm_value *curr;
1240d5ac70f0Sopenharmony_ci
1241d5ac70f0Sopenharmony_ci	curr = calloc(1, sizeof(struct ucm_value));
1242d5ac70f0Sopenharmony_ci	if (curr == NULL)
1243d5ac70f0Sopenharmony_ci		return -ENOMEM;
1244d5ac70f0Sopenharmony_ci	curr->name = strdup(key);
1245d5ac70f0Sopenharmony_ci	if (curr->name == NULL) {
1246d5ac70f0Sopenharmony_ci		free(curr);
1247d5ac70f0Sopenharmony_ci		return -ENOMEM;
1248d5ac70f0Sopenharmony_ci	}
1249d5ac70f0Sopenharmony_ci	list_add_tail(&curr->list, base);
1250d5ac70f0Sopenharmony_ci	curr->data = val;
1251d5ac70f0Sopenharmony_ci	return 0;
1252d5ac70f0Sopenharmony_ci}
1253d5ac70f0Sopenharmony_ci
1254d5ac70f0Sopenharmony_ci/*
1255d5ac70f0Sopenharmony_ci * Parse values.
1256d5ac70f0Sopenharmony_ci *
1257d5ac70f0Sopenharmony_ci * Parse values describing PCM, control/mixer settings and stream parameters.
1258d5ac70f0Sopenharmony_ci *
1259d5ac70f0Sopenharmony_ci * Value {
1260d5ac70f0Sopenharmony_ci *   TQ Voice
1261d5ac70f0Sopenharmony_ci *   CapturePCM "hw:1"
1262d5ac70f0Sopenharmony_ci *   PlaybackVolume "name='Master Playback Volume',index=2"
1263d5ac70f0Sopenharmony_ci *   PlaybackSwitch "name='Master Playback Switch',index=2"
1264d5ac70f0Sopenharmony_ci * }
1265d5ac70f0Sopenharmony_ci */
1266d5ac70f0Sopenharmony_cistatic int parse_value(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED,
1267d5ac70f0Sopenharmony_ci			  struct list_head *base,
1268d5ac70f0Sopenharmony_ci			  snd_config_t *cfg)
1269d5ac70f0Sopenharmony_ci{
1270d5ac70f0Sopenharmony_ci	snd_config_iterator_t i, next;
1271d5ac70f0Sopenharmony_ci	snd_config_t *n;
1272d5ac70f0Sopenharmony_ci	char *s;
1273d5ac70f0Sopenharmony_ci	snd_config_type_t type;
1274d5ac70f0Sopenharmony_ci	int err;
1275d5ac70f0Sopenharmony_ci
1276d5ac70f0Sopenharmony_ci	if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
1277d5ac70f0Sopenharmony_ci		uc_error("error: compound is expected for value definition");
1278d5ac70f0Sopenharmony_ci		return -EINVAL;
1279d5ac70f0Sopenharmony_ci	}
1280d5ac70f0Sopenharmony_ci
1281d5ac70f0Sopenharmony_ci	/* in-place evaluation */
1282d5ac70f0Sopenharmony_ci	err = uc_mgr_evaluate_inplace(uc_mgr, cfg);
1283d5ac70f0Sopenharmony_ci	if (err < 0)
1284d5ac70f0Sopenharmony_ci		return err;
1285d5ac70f0Sopenharmony_ci
1286d5ac70f0Sopenharmony_ci	snd_config_for_each(i, next, cfg) {
1287d5ac70f0Sopenharmony_ci		const char *id;
1288d5ac70f0Sopenharmony_ci		n = snd_config_iterator_entry(i);
1289d5ac70f0Sopenharmony_ci		err = snd_config_get_id(n, &id);
1290d5ac70f0Sopenharmony_ci		if (err < 0)
1291d5ac70f0Sopenharmony_ci			continue;
1292d5ac70f0Sopenharmony_ci
1293d5ac70f0Sopenharmony_ci		type = snd_config_get_type(n);
1294d5ac70f0Sopenharmony_ci		switch (type) {
1295d5ac70f0Sopenharmony_ci		case SND_CONFIG_TYPE_INTEGER:
1296d5ac70f0Sopenharmony_ci		case SND_CONFIG_TYPE_INTEGER64:
1297d5ac70f0Sopenharmony_ci		case SND_CONFIG_TYPE_REAL:
1298d5ac70f0Sopenharmony_ci			err = snd_config_get_ascii(n, &s);
1299d5ac70f0Sopenharmony_ci			if (err < 0) {
1300d5ac70f0Sopenharmony_ci				uc_error("error: unable to parse value for id '%s': %s!", id, snd_strerror(err));
1301d5ac70f0Sopenharmony_ci				return err;
1302d5ac70f0Sopenharmony_ci			}
1303d5ac70f0Sopenharmony_ci			break;
1304d5ac70f0Sopenharmony_ci		case SND_CONFIG_TYPE_STRING:
1305d5ac70f0Sopenharmony_ci			err = parse_string_substitute(uc_mgr, n, &s);
1306d5ac70f0Sopenharmony_ci			if (err < 0) {
1307d5ac70f0Sopenharmony_ci				uc_error("error: unable to parse a string for id '%s'!", id);
1308d5ac70f0Sopenharmony_ci				return err;
1309d5ac70f0Sopenharmony_ci			}
1310d5ac70f0Sopenharmony_ci			break;
1311d5ac70f0Sopenharmony_ci		default:
1312d5ac70f0Sopenharmony_ci			uc_error("error: invalid type %i in Value compound '%s'", type, id);
1313d5ac70f0Sopenharmony_ci			return -EINVAL;
1314d5ac70f0Sopenharmony_ci		}
1315d5ac70f0Sopenharmony_ci		err = uc_mgr_add_value(base, id, s);
1316d5ac70f0Sopenharmony_ci		if (err < 0) {
1317d5ac70f0Sopenharmony_ci			free(s);
1318d5ac70f0Sopenharmony_ci			return err;
1319d5ac70f0Sopenharmony_ci		}
1320d5ac70f0Sopenharmony_ci	}
1321d5ac70f0Sopenharmony_ci
1322d5ac70f0Sopenharmony_ci	return 0;
1323d5ac70f0Sopenharmony_ci}
1324d5ac70f0Sopenharmony_ci
1325d5ac70f0Sopenharmony_ci/*
1326d5ac70f0Sopenharmony_ci * Parse Modifier Use cases
1327d5ac70f0Sopenharmony_ci *
1328d5ac70f0Sopenharmony_ci * # Each modifier is described in new section. N modifiers are allowed
1329d5ac70f0Sopenharmony_ci * SectionModifier."Capture Voice" {
1330d5ac70f0Sopenharmony_ci *
1331d5ac70f0Sopenharmony_ci *	Comment "Record voice call"
1332d5ac70f0Sopenharmony_ci *
1333d5ac70f0Sopenharmony_ci *	SupportedDevice [
1334d5ac70f0Sopenharmony_ci *		"x"
1335d5ac70f0Sopenharmony_ci *		"y"
1336d5ac70f0Sopenharmony_ci *	]
1337d5ac70f0Sopenharmony_ci *
1338d5ac70f0Sopenharmony_ci *	ConflictingDevice [
1339d5ac70f0Sopenharmony_ci *		"x"
1340d5ac70f0Sopenharmony_ci *		"y"
1341d5ac70f0Sopenharmony_ci *	]
1342d5ac70f0Sopenharmony_ci *
1343d5ac70f0Sopenharmony_ci *	EnableSequence [
1344d5ac70f0Sopenharmony_ci *		....
1345d5ac70f0Sopenharmony_ci *	]
1346d5ac70f0Sopenharmony_ci *
1347d5ac70f0Sopenharmony_ci *	DisableSequence [
1348d5ac70f0Sopenharmony_ci *		...
1349d5ac70f0Sopenharmony_ci *	]
1350d5ac70f0Sopenharmony_ci *
1351d5ac70f0Sopenharmony_ci *      TransitionSequence."ToModifierName" [
1352d5ac70f0Sopenharmony_ci *		...
1353d5ac70f0Sopenharmony_ci *	]
1354d5ac70f0Sopenharmony_ci *
1355d5ac70f0Sopenharmony_ci *	# Optional TQ and ALSA PCMs
1356d5ac70f0Sopenharmony_ci *	Value {
1357d5ac70f0Sopenharmony_ci *		TQ Voice
1358d5ac70f0Sopenharmony_ci *		CapturePCM "hw:1"
1359d5ac70f0Sopenharmony_ci *		PlaybackVolume "name='Master Playback Volume',index=2"
1360d5ac70f0Sopenharmony_ci *		PlaybackSwitch "name='Master Playback Switch',index=2"
1361d5ac70f0Sopenharmony_ci *	}
1362d5ac70f0Sopenharmony_ci * }
1363d5ac70f0Sopenharmony_ci *
1364d5ac70f0Sopenharmony_ci * SupportedDevice and ConflictingDevice cannot be specified together.
1365d5ac70f0Sopenharmony_ci * Both are optional.
1366d5ac70f0Sopenharmony_ci */
1367d5ac70f0Sopenharmony_cistatic int parse_modifier(snd_use_case_mgr_t *uc_mgr,
1368d5ac70f0Sopenharmony_ci			  snd_config_t *cfg,
1369d5ac70f0Sopenharmony_ci			  void *data1, void *data2)
1370d5ac70f0Sopenharmony_ci{
1371d5ac70f0Sopenharmony_ci	struct use_case_verb *verb = data1;
1372d5ac70f0Sopenharmony_ci	struct use_case_modifier *modifier;
1373d5ac70f0Sopenharmony_ci	char *name;
1374d5ac70f0Sopenharmony_ci	snd_config_iterator_t i, next;
1375d5ac70f0Sopenharmony_ci	snd_config_t *n;
1376d5ac70f0Sopenharmony_ci	int err;
1377d5ac70f0Sopenharmony_ci
1378d5ac70f0Sopenharmony_ci	if (parse_get_safe_name(uc_mgr, cfg, data2, &name) < 0)
1379d5ac70f0Sopenharmony_ci		return -EINVAL;
1380d5ac70f0Sopenharmony_ci
1381d5ac70f0Sopenharmony_ci	/* allocate modifier */
1382d5ac70f0Sopenharmony_ci	modifier = calloc(1, sizeof(*modifier));
1383d5ac70f0Sopenharmony_ci	if (modifier == NULL) {
1384d5ac70f0Sopenharmony_ci		free(name);
1385d5ac70f0Sopenharmony_ci		return -ENOMEM;
1386d5ac70f0Sopenharmony_ci	}
1387d5ac70f0Sopenharmony_ci	INIT_LIST_HEAD(&modifier->enable_list);
1388d5ac70f0Sopenharmony_ci	INIT_LIST_HEAD(&modifier->disable_list);
1389d5ac70f0Sopenharmony_ci	INIT_LIST_HEAD(&modifier->transition_list);
1390d5ac70f0Sopenharmony_ci	INIT_LIST_HEAD(&modifier->dev_list.list);
1391d5ac70f0Sopenharmony_ci	INIT_LIST_HEAD(&modifier->value_list);
1392d5ac70f0Sopenharmony_ci	list_add_tail(&modifier->list, &verb->modifier_list);
1393d5ac70f0Sopenharmony_ci	modifier->name = name;
1394d5ac70f0Sopenharmony_ci
1395d5ac70f0Sopenharmony_ci	/* in-place evaluation */
1396d5ac70f0Sopenharmony_ci	err = uc_mgr_evaluate_inplace(uc_mgr, cfg);
1397d5ac70f0Sopenharmony_ci	if (err < 0)
1398d5ac70f0Sopenharmony_ci		return err;
1399d5ac70f0Sopenharmony_ci
1400d5ac70f0Sopenharmony_ci	snd_config_for_each(i, next, cfg) {
1401d5ac70f0Sopenharmony_ci		const char *id;
1402d5ac70f0Sopenharmony_ci		n = snd_config_iterator_entry(i);
1403d5ac70f0Sopenharmony_ci		if (snd_config_get_id(n, &id) < 0)
1404d5ac70f0Sopenharmony_ci			continue;
1405d5ac70f0Sopenharmony_ci
1406d5ac70f0Sopenharmony_ci		if (strcmp(id, "Comment") == 0) {
1407d5ac70f0Sopenharmony_ci			err = parse_string_substitute3(uc_mgr, n, &modifier->comment);
1408d5ac70f0Sopenharmony_ci			if (err < 0) {
1409d5ac70f0Sopenharmony_ci				uc_error("error: failed to get modifier comment");
1410d5ac70f0Sopenharmony_ci				return err;
1411d5ac70f0Sopenharmony_ci			}
1412d5ac70f0Sopenharmony_ci			continue;
1413d5ac70f0Sopenharmony_ci		}
1414d5ac70f0Sopenharmony_ci
1415d5ac70f0Sopenharmony_ci		if (strcmp(id, "SupportedDevice") == 0) {
1416d5ac70f0Sopenharmony_ci			err = parse_device_list(uc_mgr, &modifier->dev_list,
1417d5ac70f0Sopenharmony_ci						DEVLIST_SUPPORTED, n);
1418d5ac70f0Sopenharmony_ci			if (err < 0) {
1419d5ac70f0Sopenharmony_ci				uc_error("error: failed to parse supported"
1420d5ac70f0Sopenharmony_ci					" device list");
1421d5ac70f0Sopenharmony_ci				return err;
1422d5ac70f0Sopenharmony_ci			}
1423d5ac70f0Sopenharmony_ci		}
1424d5ac70f0Sopenharmony_ci
1425d5ac70f0Sopenharmony_ci		if (strcmp(id, "ConflictingDevice") == 0) {
1426d5ac70f0Sopenharmony_ci			err = parse_device_list(uc_mgr, &modifier->dev_list,
1427d5ac70f0Sopenharmony_ci						DEVLIST_CONFLICTING, n);
1428d5ac70f0Sopenharmony_ci			if (err < 0) {
1429d5ac70f0Sopenharmony_ci				uc_error("error: failed to parse conflicting"
1430d5ac70f0Sopenharmony_ci					" device list");
1431d5ac70f0Sopenharmony_ci				return err;
1432d5ac70f0Sopenharmony_ci			}
1433d5ac70f0Sopenharmony_ci		}
1434d5ac70f0Sopenharmony_ci
1435d5ac70f0Sopenharmony_ci		if (strcmp(id, "EnableSequence") == 0) {
1436d5ac70f0Sopenharmony_ci			err = parse_sequence(uc_mgr, &modifier->enable_list, n);
1437d5ac70f0Sopenharmony_ci			if (err < 0) {
1438d5ac70f0Sopenharmony_ci				uc_error("error: failed to parse modifier"
1439d5ac70f0Sopenharmony_ci					" enable sequence");
1440d5ac70f0Sopenharmony_ci				return err;
1441d5ac70f0Sopenharmony_ci			}
1442d5ac70f0Sopenharmony_ci			continue;
1443d5ac70f0Sopenharmony_ci		}
1444d5ac70f0Sopenharmony_ci
1445d5ac70f0Sopenharmony_ci		if (strcmp(id, "DisableSequence") == 0) {
1446d5ac70f0Sopenharmony_ci			err = parse_sequence(uc_mgr, &modifier->disable_list, n);
1447d5ac70f0Sopenharmony_ci			if (err < 0) {
1448d5ac70f0Sopenharmony_ci				uc_error("error: failed to parse modifier"
1449d5ac70f0Sopenharmony_ci					" disable sequence");
1450d5ac70f0Sopenharmony_ci				return err;
1451d5ac70f0Sopenharmony_ci			}
1452d5ac70f0Sopenharmony_ci			continue;
1453d5ac70f0Sopenharmony_ci		}
1454d5ac70f0Sopenharmony_ci
1455d5ac70f0Sopenharmony_ci		if (strcmp(id, "TransitionSequence") == 0) {
1456d5ac70f0Sopenharmony_ci			err = parse_transition(uc_mgr, &modifier->transition_list, n);
1457d5ac70f0Sopenharmony_ci			if (err < 0) {
1458d5ac70f0Sopenharmony_ci				uc_error("error: failed to parse transition"
1459d5ac70f0Sopenharmony_ci					" modifier");
1460d5ac70f0Sopenharmony_ci				return err;
1461d5ac70f0Sopenharmony_ci			}
1462d5ac70f0Sopenharmony_ci			continue;
1463d5ac70f0Sopenharmony_ci		}
1464d5ac70f0Sopenharmony_ci
1465d5ac70f0Sopenharmony_ci		if (strcmp(id, "Value") == 0) {
1466d5ac70f0Sopenharmony_ci			err = parse_value(uc_mgr, &modifier->value_list, n);
1467d5ac70f0Sopenharmony_ci			if (err < 0) {
1468d5ac70f0Sopenharmony_ci				uc_error("error: failed to parse Value");
1469d5ac70f0Sopenharmony_ci				return err;
1470d5ac70f0Sopenharmony_ci			}
1471d5ac70f0Sopenharmony_ci			continue;
1472d5ac70f0Sopenharmony_ci		}
1473d5ac70f0Sopenharmony_ci	}
1474d5ac70f0Sopenharmony_ci
1475d5ac70f0Sopenharmony_ci	return 0;
1476d5ac70f0Sopenharmony_ci}
1477d5ac70f0Sopenharmony_ci
1478d5ac70f0Sopenharmony_ci/*
1479d5ac70f0Sopenharmony_ci * Parse Device Use Cases
1480d5ac70f0Sopenharmony_ci *
1481d5ac70f0Sopenharmony_ci * # Each device is described in new section. N devices are allowed
1482d5ac70f0Sopenharmony_ci * SectionDevice."Headphones" {
1483d5ac70f0Sopenharmony_ci *	Comment "Headphones connected to 3.5mm jack"
1484d5ac70f0Sopenharmony_ci *
1485d5ac70f0Sopenharmony_ci *	SupportedDevice [
1486d5ac70f0Sopenharmony_ci *		"x"
1487d5ac70f0Sopenharmony_ci *		"y"
1488d5ac70f0Sopenharmony_ci *	]
1489d5ac70f0Sopenharmony_ci *
1490d5ac70f0Sopenharmony_ci *	ConflictingDevice [
1491d5ac70f0Sopenharmony_ci *		"x"
1492d5ac70f0Sopenharmony_ci *		"y"
1493d5ac70f0Sopenharmony_ci *	]
1494d5ac70f0Sopenharmony_ci *
1495d5ac70f0Sopenharmony_ci *	EnableSequence [
1496d5ac70f0Sopenharmony_ci *		....
1497d5ac70f0Sopenharmony_ci *	]
1498d5ac70f0Sopenharmony_ci *
1499d5ac70f0Sopenharmony_ci *	DisableSequence [
1500d5ac70f0Sopenharmony_ci *		...
1501d5ac70f0Sopenharmony_ci *	]
1502d5ac70f0Sopenharmony_ci *
1503d5ac70f0Sopenharmony_ci *      TransitionSequence."ToDevice" [
1504d5ac70f0Sopenharmony_ci *		...
1505d5ac70f0Sopenharmony_ci *	]
1506d5ac70f0Sopenharmony_ci *
1507d5ac70f0Sopenharmony_ci *	Value {
1508d5ac70f0Sopenharmony_ci *		PlaybackVolume "name='Master Playback Volume',index=2"
1509d5ac70f0Sopenharmony_ci *		PlaybackSwitch "name='Master Playback Switch',index=2"
1510d5ac70f0Sopenharmony_ci *	}
1511d5ac70f0Sopenharmony_ci * }
1512d5ac70f0Sopenharmony_ci */
1513d5ac70f0Sopenharmony_cistatic int parse_device(snd_use_case_mgr_t *uc_mgr,
1514d5ac70f0Sopenharmony_ci			snd_config_t *cfg,
1515d5ac70f0Sopenharmony_ci			void *data1, void *data2)
1516d5ac70f0Sopenharmony_ci{
1517d5ac70f0Sopenharmony_ci	struct use_case_verb *verb = data1;
1518d5ac70f0Sopenharmony_ci	char *name;
1519d5ac70f0Sopenharmony_ci	struct use_case_device *device;
1520d5ac70f0Sopenharmony_ci	snd_config_iterator_t i, next;
1521d5ac70f0Sopenharmony_ci	snd_config_t *n;
1522d5ac70f0Sopenharmony_ci	int err;
1523d5ac70f0Sopenharmony_ci
1524d5ac70f0Sopenharmony_ci	if (parse_get_safe_name(uc_mgr, cfg, data2, &name) < 0)
1525d5ac70f0Sopenharmony_ci		return -EINVAL;
1526d5ac70f0Sopenharmony_ci
1527d5ac70f0Sopenharmony_ci	device = calloc(1, sizeof(*device));
1528d5ac70f0Sopenharmony_ci	if (device == NULL) {
1529d5ac70f0Sopenharmony_ci		free(name);
1530d5ac70f0Sopenharmony_ci		return -ENOMEM;
1531d5ac70f0Sopenharmony_ci	}
1532d5ac70f0Sopenharmony_ci	INIT_LIST_HEAD(&device->enable_list);
1533d5ac70f0Sopenharmony_ci	INIT_LIST_HEAD(&device->disable_list);
1534d5ac70f0Sopenharmony_ci	INIT_LIST_HEAD(&device->transition_list);
1535d5ac70f0Sopenharmony_ci	INIT_LIST_HEAD(&device->dev_list.list);
1536d5ac70f0Sopenharmony_ci	INIT_LIST_HEAD(&device->value_list);
1537d5ac70f0Sopenharmony_ci	list_add_tail(&device->list, &verb->device_list);
1538d5ac70f0Sopenharmony_ci	device->name = name;
1539d5ac70f0Sopenharmony_ci
1540d5ac70f0Sopenharmony_ci	/* in-place evaluation */
1541d5ac70f0Sopenharmony_ci	err = uc_mgr_evaluate_inplace(uc_mgr, cfg);
1542d5ac70f0Sopenharmony_ci	if (err < 0)
1543d5ac70f0Sopenharmony_ci		return err;
1544d5ac70f0Sopenharmony_ci
1545d5ac70f0Sopenharmony_ci	snd_config_for_each(i, next, cfg) {
1546d5ac70f0Sopenharmony_ci		const char *id;
1547d5ac70f0Sopenharmony_ci		n = snd_config_iterator_entry(i);
1548d5ac70f0Sopenharmony_ci		if (snd_config_get_id(n, &id) < 0)
1549d5ac70f0Sopenharmony_ci			continue;
1550d5ac70f0Sopenharmony_ci
1551d5ac70f0Sopenharmony_ci		if (strcmp(id, "Comment") == 0) {
1552d5ac70f0Sopenharmony_ci			err = parse_string_substitute3(uc_mgr, n, &device->comment);
1553d5ac70f0Sopenharmony_ci			if (err < 0) {
1554d5ac70f0Sopenharmony_ci				uc_error("error: failed to get device comment");
1555d5ac70f0Sopenharmony_ci				return err;
1556d5ac70f0Sopenharmony_ci			}
1557d5ac70f0Sopenharmony_ci			continue;
1558d5ac70f0Sopenharmony_ci		}
1559d5ac70f0Sopenharmony_ci
1560d5ac70f0Sopenharmony_ci		if (strcmp(id, "SupportedDevice") == 0) {
1561d5ac70f0Sopenharmony_ci			err = parse_device_list(uc_mgr, &device->dev_list,
1562d5ac70f0Sopenharmony_ci						DEVLIST_SUPPORTED, n);
1563d5ac70f0Sopenharmony_ci			if (err < 0) {
1564d5ac70f0Sopenharmony_ci				uc_error("error: failed to parse supported"
1565d5ac70f0Sopenharmony_ci					" device list");
1566d5ac70f0Sopenharmony_ci				return err;
1567d5ac70f0Sopenharmony_ci			}
1568d5ac70f0Sopenharmony_ci		}
1569d5ac70f0Sopenharmony_ci
1570d5ac70f0Sopenharmony_ci		if (strcmp(id, "ConflictingDevice") == 0) {
1571d5ac70f0Sopenharmony_ci			err = parse_device_list(uc_mgr, &device->dev_list,
1572d5ac70f0Sopenharmony_ci						DEVLIST_CONFLICTING, n);
1573d5ac70f0Sopenharmony_ci			if (err < 0) {
1574d5ac70f0Sopenharmony_ci				uc_error("error: failed to parse conflicting"
1575d5ac70f0Sopenharmony_ci					" device list");
1576d5ac70f0Sopenharmony_ci				return err;
1577d5ac70f0Sopenharmony_ci			}
1578d5ac70f0Sopenharmony_ci		}
1579d5ac70f0Sopenharmony_ci
1580d5ac70f0Sopenharmony_ci		if (strcmp(id, "EnableSequence") == 0) {
1581d5ac70f0Sopenharmony_ci			uc_dbg("EnableSequence");
1582d5ac70f0Sopenharmony_ci			err = parse_sequence(uc_mgr, &device->enable_list, n);
1583d5ac70f0Sopenharmony_ci			if (err < 0) {
1584d5ac70f0Sopenharmony_ci				uc_error("error: failed to parse device enable"
1585d5ac70f0Sopenharmony_ci					 " sequence");
1586d5ac70f0Sopenharmony_ci				return err;
1587d5ac70f0Sopenharmony_ci			}
1588d5ac70f0Sopenharmony_ci			continue;
1589d5ac70f0Sopenharmony_ci		}
1590d5ac70f0Sopenharmony_ci
1591d5ac70f0Sopenharmony_ci		if (strcmp(id, "DisableSequence") == 0) {
1592d5ac70f0Sopenharmony_ci			uc_dbg("DisableSequence");
1593d5ac70f0Sopenharmony_ci			err = parse_sequence(uc_mgr, &device->disable_list, n);
1594d5ac70f0Sopenharmony_ci			if (err < 0) {
1595d5ac70f0Sopenharmony_ci				uc_error("error: failed to parse device disable"
1596d5ac70f0Sopenharmony_ci					 " sequence");
1597d5ac70f0Sopenharmony_ci				return err;
1598d5ac70f0Sopenharmony_ci			}
1599d5ac70f0Sopenharmony_ci			continue;
1600d5ac70f0Sopenharmony_ci		}
1601d5ac70f0Sopenharmony_ci
1602d5ac70f0Sopenharmony_ci		if (strcmp(id, "TransitionSequence") == 0) {
1603d5ac70f0Sopenharmony_ci			uc_dbg("TransitionSequence");
1604d5ac70f0Sopenharmony_ci			err = parse_transition(uc_mgr, &device->transition_list, n);
1605d5ac70f0Sopenharmony_ci			if (err < 0) {
1606d5ac70f0Sopenharmony_ci				uc_error("error: failed to parse transition"
1607d5ac70f0Sopenharmony_ci					" device");
1608d5ac70f0Sopenharmony_ci				return err;
1609d5ac70f0Sopenharmony_ci			}
1610d5ac70f0Sopenharmony_ci			continue;
1611d5ac70f0Sopenharmony_ci		}
1612d5ac70f0Sopenharmony_ci
1613d5ac70f0Sopenharmony_ci		if (strcmp(id, "Value") == 0) {
1614d5ac70f0Sopenharmony_ci			err = parse_value(uc_mgr, &device->value_list, n);
1615d5ac70f0Sopenharmony_ci			if (err < 0) {
1616d5ac70f0Sopenharmony_ci				uc_error("error: failed to parse Value");
1617d5ac70f0Sopenharmony_ci				return err;
1618d5ac70f0Sopenharmony_ci			}
1619d5ac70f0Sopenharmony_ci			continue;
1620d5ac70f0Sopenharmony_ci		}
1621d5ac70f0Sopenharmony_ci	}
1622d5ac70f0Sopenharmony_ci	return 0;
1623d5ac70f0Sopenharmony_ci}
1624d5ac70f0Sopenharmony_ci
1625d5ac70f0Sopenharmony_ci/*
1626d5ac70f0Sopenharmony_ci * Parse Device Rename/Delete Command
1627d5ac70f0Sopenharmony_ci *
1628d5ac70f0Sopenharmony_ci * # The devices might be renamed to allow the better conditional runtime
1629d5ac70f0Sopenharmony_ci * # evaluation. Bellow example renames Speaker1 device to Speaker and
1630d5ac70f0Sopenharmony_ci * # removes Speaker2 device.
1631d5ac70f0Sopenharmony_ci * RenameDevice."Speaker1" "Speaker"
1632d5ac70f0Sopenharmony_ci * RemoveDevice."Speaker2" "Speaker2"
1633d5ac70f0Sopenharmony_ci */
1634d5ac70f0Sopenharmony_cistatic int parse_dev_name_list(snd_use_case_mgr_t *uc_mgr,
1635d5ac70f0Sopenharmony_ci			       snd_config_t *cfg,
1636d5ac70f0Sopenharmony_ci			       struct list_head *list)
1637d5ac70f0Sopenharmony_ci{
1638d5ac70f0Sopenharmony_ci	snd_config_t *n;
1639d5ac70f0Sopenharmony_ci	snd_config_iterator_t i, next;
1640d5ac70f0Sopenharmony_ci	const char *id, *name1;
1641d5ac70f0Sopenharmony_ci	char *name1s, *name2;
1642d5ac70f0Sopenharmony_ci	struct ucm_dev_name *dev;
1643d5ac70f0Sopenharmony_ci	snd_config_iterator_t pos;
1644d5ac70f0Sopenharmony_ci	int err;
1645d5ac70f0Sopenharmony_ci
1646d5ac70f0Sopenharmony_ci	if (snd_config_get_id(cfg, &id) < 0)
1647d5ac70f0Sopenharmony_ci		return -EINVAL;
1648d5ac70f0Sopenharmony_ci
1649d5ac70f0Sopenharmony_ci	if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
1650d5ac70f0Sopenharmony_ci		uc_error("compound type expected for %s", id);
1651d5ac70f0Sopenharmony_ci		return -EINVAL;
1652d5ac70f0Sopenharmony_ci	}
1653d5ac70f0Sopenharmony_ci
1654d5ac70f0Sopenharmony_ci	snd_config_for_each(i, next, cfg) {
1655d5ac70f0Sopenharmony_ci		n = snd_config_iterator_entry(i);
1656d5ac70f0Sopenharmony_ci
1657d5ac70f0Sopenharmony_ci		if (snd_config_get_id(n, &name1) < 0)
1658d5ac70f0Sopenharmony_ci			return -EINVAL;
1659d5ac70f0Sopenharmony_ci
1660d5ac70f0Sopenharmony_ci		err = get_string3(uc_mgr, name1, &name1s);
1661d5ac70f0Sopenharmony_ci		if (err < 0)
1662d5ac70f0Sopenharmony_ci			return err;
1663d5ac70f0Sopenharmony_ci
1664d5ac70f0Sopenharmony_ci		err = parse_string_substitute3(uc_mgr, n, &name2);
1665d5ac70f0Sopenharmony_ci		if (err < 0) {
1666d5ac70f0Sopenharmony_ci			free(name1s);
1667d5ac70f0Sopenharmony_ci			uc_error("error: failed to get target device name for '%s'", name1);
1668d5ac70f0Sopenharmony_ci			return err;
1669d5ac70f0Sopenharmony_ci		}
1670d5ac70f0Sopenharmony_ci
1671d5ac70f0Sopenharmony_ci		/* skip duplicates */
1672d5ac70f0Sopenharmony_ci		list_for_each(pos, list) {
1673d5ac70f0Sopenharmony_ci			dev = list_entry(pos, struct ucm_dev_name, list);
1674d5ac70f0Sopenharmony_ci			if (strcmp(dev->name1, name1s) == 0) {
1675d5ac70f0Sopenharmony_ci				free(name2);
1676d5ac70f0Sopenharmony_ci				free(name1s);
1677d5ac70f0Sopenharmony_ci				return 0;
1678d5ac70f0Sopenharmony_ci			}
1679d5ac70f0Sopenharmony_ci		}
1680d5ac70f0Sopenharmony_ci
1681d5ac70f0Sopenharmony_ci		free(name1s);
1682d5ac70f0Sopenharmony_ci
1683d5ac70f0Sopenharmony_ci		dev = calloc(1, sizeof(*dev));
1684d5ac70f0Sopenharmony_ci		if (dev == NULL) {
1685d5ac70f0Sopenharmony_ci			free(name2);
1686d5ac70f0Sopenharmony_ci			return -ENOMEM;
1687d5ac70f0Sopenharmony_ci		}
1688d5ac70f0Sopenharmony_ci		dev->name1 = strdup(name1);
1689d5ac70f0Sopenharmony_ci		if (dev->name1 == NULL) {
1690d5ac70f0Sopenharmony_ci			free(dev);
1691d5ac70f0Sopenharmony_ci			free(name2);
1692d5ac70f0Sopenharmony_ci			return -ENOMEM;
1693d5ac70f0Sopenharmony_ci		}
1694d5ac70f0Sopenharmony_ci		dev->name2 = name2;
1695d5ac70f0Sopenharmony_ci		list_add_tail(&dev->list, list);
1696d5ac70f0Sopenharmony_ci	}
1697d5ac70f0Sopenharmony_ci
1698d5ac70f0Sopenharmony_ci	return 0;
1699d5ac70f0Sopenharmony_ci}
1700d5ac70f0Sopenharmony_ci
1701d5ac70f0Sopenharmony_cistatic int parse_compound_check_legacy(snd_use_case_mgr_t *uc_mgr,
1702d5ac70f0Sopenharmony_ci	  snd_config_t *cfg,
1703d5ac70f0Sopenharmony_ci	  int (*fcn)(snd_use_case_mgr_t *, snd_config_t *, void *, void *),
1704d5ac70f0Sopenharmony_ci	  void *data1)
1705d5ac70f0Sopenharmony_ci{
1706d5ac70f0Sopenharmony_ci	const char *id, *idchild;
1707d5ac70f0Sopenharmony_ci	int child_ctr = 0, legacy_format = 1;
1708d5ac70f0Sopenharmony_ci	snd_config_iterator_t i, next;
1709d5ac70f0Sopenharmony_ci	snd_config_t *child;
1710d5ac70f0Sopenharmony_ci	int err;
1711d5ac70f0Sopenharmony_ci
1712d5ac70f0Sopenharmony_ci	err = snd_config_get_id(cfg, &id);
1713d5ac70f0Sopenharmony_ci	if (err < 0)
1714d5ac70f0Sopenharmony_ci		return err;
1715d5ac70f0Sopenharmony_ci
1716d5ac70f0Sopenharmony_ci	snd_config_for_each(i, next, cfg) {
1717d5ac70f0Sopenharmony_ci		child_ctr++;
1718d5ac70f0Sopenharmony_ci		if (child_ctr > 1) {
1719d5ac70f0Sopenharmony_ci			break;
1720d5ac70f0Sopenharmony_ci		}
1721d5ac70f0Sopenharmony_ci
1722d5ac70f0Sopenharmony_ci		child = snd_config_iterator_entry(i);
1723d5ac70f0Sopenharmony_ci
1724d5ac70f0Sopenharmony_ci		if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
1725d5ac70f0Sopenharmony_ci			legacy_format = 0;
1726d5ac70f0Sopenharmony_ci			break;
1727d5ac70f0Sopenharmony_ci		}
1728d5ac70f0Sopenharmony_ci
1729d5ac70f0Sopenharmony_ci		if (snd_config_get_id(child, &idchild) < 0)
1730d5ac70f0Sopenharmony_ci			return -EINVAL;
1731d5ac70f0Sopenharmony_ci
1732d5ac70f0Sopenharmony_ci		if (strcmp(idchild, "0")) {
1733d5ac70f0Sopenharmony_ci			legacy_format = 0;
1734d5ac70f0Sopenharmony_ci			break;
1735d5ac70f0Sopenharmony_ci		}
1736d5ac70f0Sopenharmony_ci	}
1737d5ac70f0Sopenharmony_ci	if (child_ctr != 1) {
1738d5ac70f0Sopenharmony_ci		legacy_format = 0;
1739d5ac70f0Sopenharmony_ci	}
1740d5ac70f0Sopenharmony_ci
1741d5ac70f0Sopenharmony_ci	if (legacy_format)
1742d5ac70f0Sopenharmony_ci		return parse_compound(uc_mgr, cfg, fcn, data1, (void *)id);
1743d5ac70f0Sopenharmony_ci	else
1744d5ac70f0Sopenharmony_ci		return fcn(uc_mgr, cfg, data1, NULL);
1745d5ac70f0Sopenharmony_ci}
1746d5ac70f0Sopenharmony_ci
1747d5ac70f0Sopenharmony_cistatic int parse_device_name(snd_use_case_mgr_t *uc_mgr,
1748d5ac70f0Sopenharmony_ci			     snd_config_t *cfg,
1749d5ac70f0Sopenharmony_ci			     void *data1,
1750d5ac70f0Sopenharmony_ci			     void *data2 ATTRIBUTE_UNUSED)
1751d5ac70f0Sopenharmony_ci{
1752d5ac70f0Sopenharmony_ci	return parse_compound_check_legacy(uc_mgr, cfg, parse_device, data1);
1753d5ac70f0Sopenharmony_ci}
1754d5ac70f0Sopenharmony_ci
1755d5ac70f0Sopenharmony_cistatic int parse_modifier_name(snd_use_case_mgr_t *uc_mgr,
1756d5ac70f0Sopenharmony_ci			     snd_config_t *cfg,
1757d5ac70f0Sopenharmony_ci			     void *data1,
1758d5ac70f0Sopenharmony_ci			     void *data2 ATTRIBUTE_UNUSED)
1759d5ac70f0Sopenharmony_ci{
1760d5ac70f0Sopenharmony_ci	return parse_compound_check_legacy(uc_mgr, cfg, parse_modifier, data1);
1761d5ac70f0Sopenharmony_ci}
1762d5ac70f0Sopenharmony_ci
1763d5ac70f0Sopenharmony_cistatic int verb_dev_list_add(struct use_case_verb *verb,
1764d5ac70f0Sopenharmony_ci			     enum dev_list_type dst_type,
1765d5ac70f0Sopenharmony_ci			     const char *dst,
1766d5ac70f0Sopenharmony_ci			     const char *src)
1767d5ac70f0Sopenharmony_ci{
1768d5ac70f0Sopenharmony_ci	struct use_case_device *device;
1769d5ac70f0Sopenharmony_ci	struct list_head *pos;
1770d5ac70f0Sopenharmony_ci
1771d5ac70f0Sopenharmony_ci	list_for_each(pos, &verb->device_list) {
1772d5ac70f0Sopenharmony_ci		device = list_entry(pos, struct use_case_device, list);
1773d5ac70f0Sopenharmony_ci		if (strcmp(device->name, dst) != 0)
1774d5ac70f0Sopenharmony_ci			continue;
1775d5ac70f0Sopenharmony_ci		if (device->dev_list.type != dst_type) {
1776d5ac70f0Sopenharmony_ci			if (list_empty(&device->dev_list.list)) {
1777d5ac70f0Sopenharmony_ci				device->dev_list.type = dst_type;
1778d5ac70f0Sopenharmony_ci			} else {
1779d5ac70f0Sopenharmony_ci				uc_error("error: incompatible device list type ('%s', '%s')",
1780d5ac70f0Sopenharmony_ci					 device->name, src);
1781d5ac70f0Sopenharmony_ci				return -EINVAL;
1782d5ac70f0Sopenharmony_ci			}
1783d5ac70f0Sopenharmony_ci		}
1784d5ac70f0Sopenharmony_ci		return uc_mgr_put_to_dev_list(&device->dev_list, src);
1785d5ac70f0Sopenharmony_ci	}
1786d5ac70f0Sopenharmony_ci	uc_error("error: unable to find device '%s'", dst);
1787d5ac70f0Sopenharmony_ci	return -ENOENT;
1788d5ac70f0Sopenharmony_ci}
1789d5ac70f0Sopenharmony_ci
1790d5ac70f0Sopenharmony_cistatic int verb_dev_list_check(struct use_case_verb *verb)
1791d5ac70f0Sopenharmony_ci{
1792d5ac70f0Sopenharmony_ci	struct list_head *pos, *pos2;
1793d5ac70f0Sopenharmony_ci	struct use_case_device *device;
1794d5ac70f0Sopenharmony_ci	struct dev_list_node *dlist;
1795d5ac70f0Sopenharmony_ci	int err;
1796d5ac70f0Sopenharmony_ci
1797d5ac70f0Sopenharmony_ci	list_for_each(pos, &verb->device_list) {
1798d5ac70f0Sopenharmony_ci		device = list_entry(pos, struct use_case_device, list);
1799d5ac70f0Sopenharmony_ci		list_for_each(pos2, &device->dev_list.list) {
1800d5ac70f0Sopenharmony_ci			dlist = list_entry(pos2, struct dev_list_node, list);
1801d5ac70f0Sopenharmony_ci			err = verb_dev_list_add(verb, device->dev_list.type,
1802d5ac70f0Sopenharmony_ci						dlist->name, device->name);
1803d5ac70f0Sopenharmony_ci			if (err < 0)
1804d5ac70f0Sopenharmony_ci				return err;
1805d5ac70f0Sopenharmony_ci		}
1806d5ac70f0Sopenharmony_ci	}
1807d5ac70f0Sopenharmony_ci	return 0;
1808d5ac70f0Sopenharmony_ci}
1809d5ac70f0Sopenharmony_ci
1810d5ac70f0Sopenharmony_cistatic int verb_device_management(struct use_case_verb *verb)
1811d5ac70f0Sopenharmony_ci{
1812d5ac70f0Sopenharmony_ci	struct list_head *pos;
1813d5ac70f0Sopenharmony_ci	struct ucm_dev_name *dev;
1814d5ac70f0Sopenharmony_ci	int err;
1815d5ac70f0Sopenharmony_ci
1816d5ac70f0Sopenharmony_ci	/* rename devices */
1817d5ac70f0Sopenharmony_ci	list_for_each(pos, &verb->rename_list) {
1818d5ac70f0Sopenharmony_ci		dev = list_entry(pos, struct ucm_dev_name, list);
1819d5ac70f0Sopenharmony_ci		err = uc_mgr_rename_device(verb, dev->name1, dev->name2);
1820d5ac70f0Sopenharmony_ci		if (err < 0) {
1821d5ac70f0Sopenharmony_ci			uc_error("error: cannot rename device '%s' to '%s'", dev->name1, dev->name2);
1822d5ac70f0Sopenharmony_ci			return err;
1823d5ac70f0Sopenharmony_ci		}
1824d5ac70f0Sopenharmony_ci	}
1825d5ac70f0Sopenharmony_ci
1826d5ac70f0Sopenharmony_ci	/* remove devices */
1827d5ac70f0Sopenharmony_ci	list_for_each(pos, &verb->remove_list) {
1828d5ac70f0Sopenharmony_ci		dev = list_entry(pos, struct ucm_dev_name, list);
1829d5ac70f0Sopenharmony_ci		err = uc_mgr_remove_device(verb, dev->name2);
1830d5ac70f0Sopenharmony_ci		if (err < 0) {
1831d5ac70f0Sopenharmony_ci			uc_error("error: cannot remove device '%s'", dev->name2);
1832d5ac70f0Sopenharmony_ci			return err;
1833d5ac70f0Sopenharmony_ci		}
1834d5ac70f0Sopenharmony_ci	}
1835d5ac70f0Sopenharmony_ci
1836d5ac70f0Sopenharmony_ci	/* those lists are no longer used */
1837d5ac70f0Sopenharmony_ci	uc_mgr_free_dev_name_list(&verb->rename_list);
1838d5ac70f0Sopenharmony_ci	uc_mgr_free_dev_name_list(&verb->remove_list);
1839d5ac70f0Sopenharmony_ci
1840d5ac70f0Sopenharmony_ci	/* handle conflicting/supported lists */
1841d5ac70f0Sopenharmony_ci	return verb_dev_list_check(verb);
1842d5ac70f0Sopenharmony_ci}
1843d5ac70f0Sopenharmony_ci
1844d5ac70f0Sopenharmony_ci/*
1845d5ac70f0Sopenharmony_ci * Parse Verb Section
1846d5ac70f0Sopenharmony_ci *
1847d5ac70f0Sopenharmony_ci * # Example Use case verb section for Voice call blah
1848d5ac70f0Sopenharmony_ci * # By Joe Blogs <joe@blogs.com>
1849d5ac70f0Sopenharmony_ci *
1850d5ac70f0Sopenharmony_ci * SectionVerb {
1851d5ac70f0Sopenharmony_ci *	# enable and disable sequences are compulsory
1852d5ac70f0Sopenharmony_ci *	EnableSequence [
1853d5ac70f0Sopenharmony_ci *		cset "name='Master Playback Switch',index=2 0,0"
1854d5ac70f0Sopenharmony_ci *		cset "name='Master Playback Volume',index=2 25,25"
1855d5ac70f0Sopenharmony_ci *		msleep 50
1856d5ac70f0Sopenharmony_ci *		cset "name='Master Playback Switch',index=2 1,1"
1857d5ac70f0Sopenharmony_ci *		cset "name='Master Playback Volume',index=2 50,50"
1858d5ac70f0Sopenharmony_ci *	]
1859d5ac70f0Sopenharmony_ci *
1860d5ac70f0Sopenharmony_ci *	DisableSequence [
1861d5ac70f0Sopenharmony_ci *		cset "name='Master Playback Switch',index=2 0,0"
1862d5ac70f0Sopenharmony_ci *		cset "name='Master Playback Volume',index=2 25,25"
1863d5ac70f0Sopenharmony_ci *		msleep 50
1864d5ac70f0Sopenharmony_ci *		cset "name='Master Playback Switch',index=2 1,1"
1865d5ac70f0Sopenharmony_ci *		cset "name='Master Playback Volume',index=2 50,50"
1866d5ac70f0Sopenharmony_ci *	]
1867d5ac70f0Sopenharmony_ci *
1868d5ac70f0Sopenharmony_ci *      # Optional transition verb
1869d5ac70f0Sopenharmony_ci *      TransitionSequence."ToCaseName" [
1870d5ac70f0Sopenharmony_ci *		msleep 1
1871d5ac70f0Sopenharmony_ci *      ]
1872d5ac70f0Sopenharmony_ci *
1873d5ac70f0Sopenharmony_ci *	# Optional TQ and ALSA PCMs
1874d5ac70f0Sopenharmony_ci *	Value {
1875d5ac70f0Sopenharmony_ci *		TQ HiFi
1876d5ac70f0Sopenharmony_ci *		CapturePCM "hw:0"
1877d5ac70f0Sopenharmony_ci *		PlaybackPCM "hw:0"
1878d5ac70f0Sopenharmony_ci *	}
1879d5ac70f0Sopenharmony_ci * }
1880d5ac70f0Sopenharmony_ci */
1881d5ac70f0Sopenharmony_cistatic int parse_verb(snd_use_case_mgr_t *uc_mgr,
1882d5ac70f0Sopenharmony_ci		      struct use_case_verb *verb,
1883d5ac70f0Sopenharmony_ci		      snd_config_t *cfg)
1884d5ac70f0Sopenharmony_ci{
1885d5ac70f0Sopenharmony_ci	snd_config_iterator_t i, next;
1886d5ac70f0Sopenharmony_ci	snd_config_t *n;
1887d5ac70f0Sopenharmony_ci	int err;
1888d5ac70f0Sopenharmony_ci
1889d5ac70f0Sopenharmony_ci	/* in-place evaluation */
1890d5ac70f0Sopenharmony_ci	err = uc_mgr_evaluate_inplace(uc_mgr, cfg);
1891d5ac70f0Sopenharmony_ci	if (err < 0)
1892d5ac70f0Sopenharmony_ci		return err;
1893d5ac70f0Sopenharmony_ci
1894d5ac70f0Sopenharmony_ci	/* parse verb section */
1895d5ac70f0Sopenharmony_ci	snd_config_for_each(i, next, cfg) {
1896d5ac70f0Sopenharmony_ci		const char *id;
1897d5ac70f0Sopenharmony_ci		n = snd_config_iterator_entry(i);
1898d5ac70f0Sopenharmony_ci		if (snd_config_get_id(n, &id) < 0)
1899d5ac70f0Sopenharmony_ci			continue;
1900d5ac70f0Sopenharmony_ci
1901d5ac70f0Sopenharmony_ci		if (strcmp(id, "EnableSequence") == 0) {
1902d5ac70f0Sopenharmony_ci			uc_dbg("Parse EnableSequence");
1903d5ac70f0Sopenharmony_ci			err = parse_sequence(uc_mgr, &verb->enable_list, n);
1904d5ac70f0Sopenharmony_ci			if (err < 0) {
1905d5ac70f0Sopenharmony_ci				uc_error("error: failed to parse verb enable sequence");
1906d5ac70f0Sopenharmony_ci				return err;
1907d5ac70f0Sopenharmony_ci			}
1908d5ac70f0Sopenharmony_ci			continue;
1909d5ac70f0Sopenharmony_ci		}
1910d5ac70f0Sopenharmony_ci
1911d5ac70f0Sopenharmony_ci		if (strcmp(id, "DisableSequence") == 0) {
1912d5ac70f0Sopenharmony_ci			uc_dbg("Parse DisableSequence");
1913d5ac70f0Sopenharmony_ci			err = parse_sequence(uc_mgr, &verb->disable_list, n);
1914d5ac70f0Sopenharmony_ci			if (err < 0) {
1915d5ac70f0Sopenharmony_ci				uc_error("error: failed to parse verb disable sequence");
1916d5ac70f0Sopenharmony_ci				return err;
1917d5ac70f0Sopenharmony_ci			}
1918d5ac70f0Sopenharmony_ci			continue;
1919d5ac70f0Sopenharmony_ci		}
1920d5ac70f0Sopenharmony_ci
1921d5ac70f0Sopenharmony_ci		if (strcmp(id, "TransitionSequence") == 0) {
1922d5ac70f0Sopenharmony_ci			uc_dbg("Parse TransitionSequence");
1923d5ac70f0Sopenharmony_ci			err = parse_transition(uc_mgr, &verb->transition_list, n);
1924d5ac70f0Sopenharmony_ci			if (err < 0) {
1925d5ac70f0Sopenharmony_ci				uc_error("error: failed to parse transition sequence");
1926d5ac70f0Sopenharmony_ci				return err;
1927d5ac70f0Sopenharmony_ci			}
1928d5ac70f0Sopenharmony_ci			continue;
1929d5ac70f0Sopenharmony_ci		}
1930d5ac70f0Sopenharmony_ci
1931d5ac70f0Sopenharmony_ci		if (strcmp(id, "Value") == 0) {
1932d5ac70f0Sopenharmony_ci			uc_dbg("Parse Value");
1933d5ac70f0Sopenharmony_ci			err = parse_value(uc_mgr, &verb->value_list, n);
1934d5ac70f0Sopenharmony_ci			if (err < 0)
1935d5ac70f0Sopenharmony_ci				return err;
1936d5ac70f0Sopenharmony_ci			continue;
1937d5ac70f0Sopenharmony_ci		}
1938d5ac70f0Sopenharmony_ci	}
1939d5ac70f0Sopenharmony_ci
1940d5ac70f0Sopenharmony_ci	return 0;
1941d5ac70f0Sopenharmony_ci}
1942d5ac70f0Sopenharmony_ci
1943d5ac70f0Sopenharmony_ci/*
1944d5ac70f0Sopenharmony_ci * Parse a Use case verb file.
1945d5ac70f0Sopenharmony_ci *
1946d5ac70f0Sopenharmony_ci * This file contains the following :-
1947d5ac70f0Sopenharmony_ci *  o Verb enable and disable sequences.
1948d5ac70f0Sopenharmony_ci *  o Supported Device enable and disable sequences for verb.
1949d5ac70f0Sopenharmony_ci *  o Supported Modifier enable and disable sequences for verb
1950d5ac70f0Sopenharmony_ci *  o Optional QoS for the verb and modifiers.
1951d5ac70f0Sopenharmony_ci *  o Optional PCM device ID for verb and modifiers
1952d5ac70f0Sopenharmony_ci *  o Alias kcontrols IDs for master and volumes and mutes.
1953d5ac70f0Sopenharmony_ci */
1954d5ac70f0Sopenharmony_cistatic int parse_verb_file(snd_use_case_mgr_t *uc_mgr,
1955d5ac70f0Sopenharmony_ci			   const char *use_case_name,
1956d5ac70f0Sopenharmony_ci			   const char *comment,
1957d5ac70f0Sopenharmony_ci			   const char *file)
1958d5ac70f0Sopenharmony_ci{
1959d5ac70f0Sopenharmony_ci	snd_config_iterator_t i, next;
1960d5ac70f0Sopenharmony_ci	snd_config_t *n;
1961d5ac70f0Sopenharmony_ci	struct use_case_verb *verb;
1962d5ac70f0Sopenharmony_ci	snd_config_t *cfg;
1963d5ac70f0Sopenharmony_ci	int err;
1964d5ac70f0Sopenharmony_ci
1965d5ac70f0Sopenharmony_ci	/* allocate verb */
1966d5ac70f0Sopenharmony_ci	verb = calloc(1, sizeof(struct use_case_verb));
1967d5ac70f0Sopenharmony_ci	if (verb == NULL)
1968d5ac70f0Sopenharmony_ci		return -ENOMEM;
1969d5ac70f0Sopenharmony_ci	INIT_LIST_HEAD(&verb->enable_list);
1970d5ac70f0Sopenharmony_ci	INIT_LIST_HEAD(&verb->disable_list);
1971d5ac70f0Sopenharmony_ci	INIT_LIST_HEAD(&verb->transition_list);
1972d5ac70f0Sopenharmony_ci	INIT_LIST_HEAD(&verb->device_list);
1973d5ac70f0Sopenharmony_ci	INIT_LIST_HEAD(&verb->cmpt_device_list);
1974d5ac70f0Sopenharmony_ci	INIT_LIST_HEAD(&verb->modifier_list);
1975d5ac70f0Sopenharmony_ci	INIT_LIST_HEAD(&verb->value_list);
1976d5ac70f0Sopenharmony_ci	INIT_LIST_HEAD(&verb->rename_list);
1977d5ac70f0Sopenharmony_ci	INIT_LIST_HEAD(&verb->remove_list);
1978d5ac70f0Sopenharmony_ci	list_add_tail(&verb->list, &uc_mgr->verb_list);
1979d5ac70f0Sopenharmony_ci	if (use_case_name == NULL)
1980d5ac70f0Sopenharmony_ci		return -EINVAL;
1981d5ac70f0Sopenharmony_ci	verb->name = strdup(use_case_name);
1982d5ac70f0Sopenharmony_ci	if (verb->name == NULL)
1983d5ac70f0Sopenharmony_ci		return -ENOMEM;
1984d5ac70f0Sopenharmony_ci
1985d5ac70f0Sopenharmony_ci	if (comment != NULL) {
1986d5ac70f0Sopenharmony_ci		verb->comment = strdup(comment);
1987d5ac70f0Sopenharmony_ci		if (verb->comment == NULL)
1988d5ac70f0Sopenharmony_ci			return -ENOMEM;
1989d5ac70f0Sopenharmony_ci	}
1990d5ac70f0Sopenharmony_ci
1991d5ac70f0Sopenharmony_ci	/* open Verb file for reading */
1992d5ac70f0Sopenharmony_ci	err = uc_mgr_config_load_file(uc_mgr, file, &cfg);
1993d5ac70f0Sopenharmony_ci	if (err < 0)
1994d5ac70f0Sopenharmony_ci		return err;
1995d5ac70f0Sopenharmony_ci
1996d5ac70f0Sopenharmony_ci	/* in-place evaluation */
1997d5ac70f0Sopenharmony_ci	err = uc_mgr_evaluate_inplace(uc_mgr, cfg);
1998d5ac70f0Sopenharmony_ci	if (err < 0)
1999d5ac70f0Sopenharmony_ci		goto _err;
2000d5ac70f0Sopenharmony_ci
2001d5ac70f0Sopenharmony_ci	/* parse master config sections */
2002d5ac70f0Sopenharmony_ci	snd_config_for_each(i, next, cfg) {
2003d5ac70f0Sopenharmony_ci		const char *id;
2004d5ac70f0Sopenharmony_ci		n = snd_config_iterator_entry(i);
2005d5ac70f0Sopenharmony_ci		if (snd_config_get_id(n, &id) < 0)
2006d5ac70f0Sopenharmony_ci			continue;
2007d5ac70f0Sopenharmony_ci
2008d5ac70f0Sopenharmony_ci		/* find verb section and parse it */
2009d5ac70f0Sopenharmony_ci		if (strcmp(id, "SectionVerb") == 0) {
2010d5ac70f0Sopenharmony_ci			err = parse_verb(uc_mgr, verb, n);
2011d5ac70f0Sopenharmony_ci			if (err < 0) {
2012d5ac70f0Sopenharmony_ci				uc_error("error: %s failed to parse verb",
2013d5ac70f0Sopenharmony_ci						file);
2014d5ac70f0Sopenharmony_ci				goto _err;
2015d5ac70f0Sopenharmony_ci			}
2016d5ac70f0Sopenharmony_ci			continue;
2017d5ac70f0Sopenharmony_ci		}
2018d5ac70f0Sopenharmony_ci
2019d5ac70f0Sopenharmony_ci		/* find device sections and parse them */
2020d5ac70f0Sopenharmony_ci		if (strcmp(id, "SectionDevice") == 0) {
2021d5ac70f0Sopenharmony_ci			err = parse_compound(uc_mgr, n,
2022d5ac70f0Sopenharmony_ci						parse_device_name, verb, NULL);
2023d5ac70f0Sopenharmony_ci			if (err < 0) {
2024d5ac70f0Sopenharmony_ci				uc_error("error: %s failed to parse device",
2025d5ac70f0Sopenharmony_ci						file);
2026d5ac70f0Sopenharmony_ci				goto _err;
2027d5ac70f0Sopenharmony_ci			}
2028d5ac70f0Sopenharmony_ci			continue;
2029d5ac70f0Sopenharmony_ci		}
2030d5ac70f0Sopenharmony_ci
2031d5ac70f0Sopenharmony_ci		/* find modifier sections and parse them */
2032d5ac70f0Sopenharmony_ci		if (strcmp(id, "SectionModifier") == 0) {
2033d5ac70f0Sopenharmony_ci			err = parse_compound(uc_mgr, n,
2034d5ac70f0Sopenharmony_ci					     parse_modifier_name, verb, NULL);
2035d5ac70f0Sopenharmony_ci			if (err < 0) {
2036d5ac70f0Sopenharmony_ci				uc_error("error: %s failed to parse modifier",
2037d5ac70f0Sopenharmony_ci						file);
2038d5ac70f0Sopenharmony_ci				goto _err;
2039d5ac70f0Sopenharmony_ci			}
2040d5ac70f0Sopenharmony_ci			continue;
2041d5ac70f0Sopenharmony_ci		}
2042d5ac70f0Sopenharmony_ci
2043d5ac70f0Sopenharmony_ci		/* device renames */
2044d5ac70f0Sopenharmony_ci		if (strcmp(id, "RenameDevice") == 0) {
2045d5ac70f0Sopenharmony_ci			err = parse_dev_name_list(uc_mgr, n, &verb->rename_list);
2046d5ac70f0Sopenharmony_ci			if (err < 0) {
2047d5ac70f0Sopenharmony_ci				uc_error("error: %s failed to parse device rename",
2048d5ac70f0Sopenharmony_ci						file);
2049d5ac70f0Sopenharmony_ci				goto _err;
2050d5ac70f0Sopenharmony_ci			}
2051d5ac70f0Sopenharmony_ci			continue;
2052d5ac70f0Sopenharmony_ci		}
2053d5ac70f0Sopenharmony_ci
2054d5ac70f0Sopenharmony_ci		/* device remove */
2055d5ac70f0Sopenharmony_ci		if (strcmp(id, "RemoveDevice") == 0) {
2056d5ac70f0Sopenharmony_ci			err = parse_dev_name_list(uc_mgr, n, &verb->remove_list);
2057d5ac70f0Sopenharmony_ci			if (err < 0) {
2058d5ac70f0Sopenharmony_ci				uc_error("error: %s failed to parse device remove",
2059d5ac70f0Sopenharmony_ci						file);
2060d5ac70f0Sopenharmony_ci				goto _err;
2061d5ac70f0Sopenharmony_ci			}
2062d5ac70f0Sopenharmony_ci			continue;
2063d5ac70f0Sopenharmony_ci		}
2064d5ac70f0Sopenharmony_ci
2065d5ac70f0Sopenharmony_ci		/* alsa-lib configuration */
2066d5ac70f0Sopenharmony_ci		if (uc_mgr->conf_format > 3 && strcmp(id, "LibraryConfig") == 0) {
2067d5ac70f0Sopenharmony_ci			err = parse_libconfig(uc_mgr, n);
2068d5ac70f0Sopenharmony_ci			if (err < 0) {
2069d5ac70f0Sopenharmony_ci				uc_error("error: failed to parse LibConfig");
2070d5ac70f0Sopenharmony_ci				goto _err;
2071d5ac70f0Sopenharmony_ci			}
2072d5ac70f0Sopenharmony_ci			continue;
2073d5ac70f0Sopenharmony_ci		}
2074d5ac70f0Sopenharmony_ci	}
2075d5ac70f0Sopenharmony_ci
2076d5ac70f0Sopenharmony_ci	snd_config_delete(cfg);
2077d5ac70f0Sopenharmony_ci
2078d5ac70f0Sopenharmony_ci	/* use case verb must have at least 1 device */
2079d5ac70f0Sopenharmony_ci	if (list_empty(&verb->device_list)) {
2080d5ac70f0Sopenharmony_ci		uc_error("error: no use case device defined", file);
2081d5ac70f0Sopenharmony_ci		return -EINVAL;
2082d5ac70f0Sopenharmony_ci	}
2083d5ac70f0Sopenharmony_ci
2084d5ac70f0Sopenharmony_ci	/* do device rename and delete */
2085d5ac70f0Sopenharmony_ci	err = verb_device_management(verb);
2086d5ac70f0Sopenharmony_ci	if (err < 0) {
2087d5ac70f0Sopenharmony_ci		uc_error("error: device management error in verb '%s'", verb->name);
2088d5ac70f0Sopenharmony_ci		return err;
2089d5ac70f0Sopenharmony_ci	}
2090d5ac70f0Sopenharmony_ci
2091d5ac70f0Sopenharmony_ci	return 0;
2092d5ac70f0Sopenharmony_ci
2093d5ac70f0Sopenharmony_ci       _err:
2094d5ac70f0Sopenharmony_ci	snd_config_delete(cfg);
2095d5ac70f0Sopenharmony_ci	return err;
2096d5ac70f0Sopenharmony_ci}
2097d5ac70f0Sopenharmony_ci
2098d5ac70f0Sopenharmony_ci/*
2099d5ac70f0Sopenharmony_ci * Parse variant information
2100d5ac70f0Sopenharmony_ci */
2101d5ac70f0Sopenharmony_cistatic int parse_variant(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg,
2102d5ac70f0Sopenharmony_ci			 char **_vfile, char **_vcomment)
2103d5ac70f0Sopenharmony_ci{
2104d5ac70f0Sopenharmony_ci	snd_config_iterator_t i, next;
2105d5ac70f0Sopenharmony_ci	snd_config_t *n;
2106d5ac70f0Sopenharmony_ci	char *file = NULL, *comment = NULL;
2107d5ac70f0Sopenharmony_ci	int err;
2108d5ac70f0Sopenharmony_ci
2109d5ac70f0Sopenharmony_ci	/* parse master config sections */
2110d5ac70f0Sopenharmony_ci	snd_config_for_each(i, next, cfg) {
2111d5ac70f0Sopenharmony_ci		const char *id;
2112d5ac70f0Sopenharmony_ci		n = snd_config_iterator_entry(i);
2113d5ac70f0Sopenharmony_ci		if (snd_config_get_id(n, &id) < 0)
2114d5ac70f0Sopenharmony_ci			continue;
2115d5ac70f0Sopenharmony_ci
2116d5ac70f0Sopenharmony_ci		/* get use case verb file name */
2117d5ac70f0Sopenharmony_ci		if (strcmp(id, "File") == 0) {
2118d5ac70f0Sopenharmony_ci			if (_vfile) {
2119d5ac70f0Sopenharmony_ci				err = parse_string_substitute3(uc_mgr, n, &file);
2120d5ac70f0Sopenharmony_ci				if (err < 0) {
2121d5ac70f0Sopenharmony_ci					uc_error("failed to get File");
2122d5ac70f0Sopenharmony_ci					goto __error;
2123d5ac70f0Sopenharmony_ci				}
2124d5ac70f0Sopenharmony_ci			}
2125d5ac70f0Sopenharmony_ci			continue;
2126d5ac70f0Sopenharmony_ci		}
2127d5ac70f0Sopenharmony_ci
2128d5ac70f0Sopenharmony_ci		/* get optional use case comment */
2129d5ac70f0Sopenharmony_ci		if (strncmp(id, "Comment", 7) == 0) {
2130d5ac70f0Sopenharmony_ci			if (_vcomment) {
2131d5ac70f0Sopenharmony_ci				err = parse_string_substitute3(uc_mgr, n, &comment);
2132d5ac70f0Sopenharmony_ci				if (err < 0) {
2133d5ac70f0Sopenharmony_ci					uc_error("error: failed to get Comment");
2134d5ac70f0Sopenharmony_ci					goto __error;
2135d5ac70f0Sopenharmony_ci				}
2136d5ac70f0Sopenharmony_ci			}
2137d5ac70f0Sopenharmony_ci			continue;
2138d5ac70f0Sopenharmony_ci		}
2139d5ac70f0Sopenharmony_ci
2140d5ac70f0Sopenharmony_ci		uc_error("unknown field '%s' in Variant section", id);
2141d5ac70f0Sopenharmony_ci		err = -EINVAL;
2142d5ac70f0Sopenharmony_ci		goto __error;
2143d5ac70f0Sopenharmony_ci	}
2144d5ac70f0Sopenharmony_ci
2145d5ac70f0Sopenharmony_ci	if (_vfile)
2146d5ac70f0Sopenharmony_ci		*_vfile = file;
2147d5ac70f0Sopenharmony_ci	if (_vcomment)
2148d5ac70f0Sopenharmony_ci		*_vcomment = comment;
2149d5ac70f0Sopenharmony_ci	return 0;
2150d5ac70f0Sopenharmony_ci
2151d5ac70f0Sopenharmony_ci__error:
2152d5ac70f0Sopenharmony_ci	free(file);
2153d5ac70f0Sopenharmony_ci	free(comment);
2154d5ac70f0Sopenharmony_ci	return err;
2155d5ac70f0Sopenharmony_ci}
2156d5ac70f0Sopenharmony_ci
2157d5ac70f0Sopenharmony_ci/*
2158d5ac70f0Sopenharmony_ci * Parse master section for "Use Case" and "File" tags.
2159d5ac70f0Sopenharmony_ci */
2160d5ac70f0Sopenharmony_cistatic int parse_master_section(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg,
2161d5ac70f0Sopenharmony_ci				void *data1 ATTRIBUTE_UNUSED,
2162d5ac70f0Sopenharmony_ci				void *data2 ATTRIBUTE_UNUSED)
2163d5ac70f0Sopenharmony_ci{
2164d5ac70f0Sopenharmony_ci	snd_config_iterator_t i, next;
2165d5ac70f0Sopenharmony_ci	snd_config_t *n, *variant = NULL;
2166d5ac70f0Sopenharmony_ci	char *use_case_name, *file = NULL, *comment = NULL;
2167d5ac70f0Sopenharmony_ci	bool variant_ok = false;
2168d5ac70f0Sopenharmony_ci	int err;
2169d5ac70f0Sopenharmony_ci
2170d5ac70f0Sopenharmony_ci	if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
2171d5ac70f0Sopenharmony_ci		uc_error("compound type expected for use case section");
2172d5ac70f0Sopenharmony_ci		return -EINVAL;
2173d5ac70f0Sopenharmony_ci	}
2174d5ac70f0Sopenharmony_ci
2175d5ac70f0Sopenharmony_ci	err = parse_get_safe_name(uc_mgr, cfg, NULL, &use_case_name);
2176d5ac70f0Sopenharmony_ci	if (err < 0) {
2177d5ac70f0Sopenharmony_ci		uc_error("unable to get name for use case section");
2178d5ac70f0Sopenharmony_ci		return err;
2179d5ac70f0Sopenharmony_ci	}
2180d5ac70f0Sopenharmony_ci
2181d5ac70f0Sopenharmony_ci	/* in-place evaluation */
2182d5ac70f0Sopenharmony_ci	uc_mgr->parse_master_section = 1;
2183d5ac70f0Sopenharmony_ci	err = uc_mgr_evaluate_inplace(uc_mgr, cfg);
2184d5ac70f0Sopenharmony_ci	uc_mgr->parse_master_section = 0;
2185d5ac70f0Sopenharmony_ci	if (err < 0)
2186d5ac70f0Sopenharmony_ci		goto __error;
2187d5ac70f0Sopenharmony_ci
2188d5ac70f0Sopenharmony_ci	/* parse master config sections */
2189d5ac70f0Sopenharmony_ci	snd_config_for_each(i, next, cfg) {
2190d5ac70f0Sopenharmony_ci		const char *id;
2191d5ac70f0Sopenharmony_ci		n = snd_config_iterator_entry(i);
2192d5ac70f0Sopenharmony_ci		if (snd_config_get_id(n, &id) < 0)
2193d5ac70f0Sopenharmony_ci			continue;
2194d5ac70f0Sopenharmony_ci
2195d5ac70f0Sopenharmony_ci		/* get use case verb file name */
2196d5ac70f0Sopenharmony_ci		if (strcmp(id, "File") == 0) {
2197d5ac70f0Sopenharmony_ci			err = parse_string_substitute3(uc_mgr, n, &file);
2198d5ac70f0Sopenharmony_ci			if (err < 0) {
2199d5ac70f0Sopenharmony_ci				uc_error("failed to get File");
2200d5ac70f0Sopenharmony_ci				goto __error;
2201d5ac70f0Sopenharmony_ci			}
2202d5ac70f0Sopenharmony_ci			continue;
2203d5ac70f0Sopenharmony_ci		}
2204d5ac70f0Sopenharmony_ci
2205d5ac70f0Sopenharmony_ci		/* get optional use case comment */
2206d5ac70f0Sopenharmony_ci		if (strncmp(id, "Comment", 7) == 0) {
2207d5ac70f0Sopenharmony_ci			err = parse_string_substitute3(uc_mgr, n, &comment);
2208d5ac70f0Sopenharmony_ci			if (err < 0) {
2209d5ac70f0Sopenharmony_ci				uc_error("error: failed to get Comment");
2210d5ac70f0Sopenharmony_ci				goto __error;
2211d5ac70f0Sopenharmony_ci			}
2212d5ac70f0Sopenharmony_ci			continue;
2213d5ac70f0Sopenharmony_ci		}
2214d5ac70f0Sopenharmony_ci
2215d5ac70f0Sopenharmony_ci		if (uc_mgr->conf_format >= 6 && strcmp(id, "Variant") == 0) {
2216d5ac70f0Sopenharmony_ci			snd_config_iterator_t i2, next2;
2217d5ac70f0Sopenharmony_ci			variant = n;
2218d5ac70f0Sopenharmony_ci			snd_config_for_each(i2, next2, n) {
2219d5ac70f0Sopenharmony_ci				const char *id2;
2220d5ac70f0Sopenharmony_ci				snd_config_t *n2;
2221d5ac70f0Sopenharmony_ci				n2 = snd_config_iterator_entry(i2);
2222d5ac70f0Sopenharmony_ci				if (snd_config_get_id(n2, &id2) < 0)
2223d5ac70f0Sopenharmony_ci					continue;
2224d5ac70f0Sopenharmony_ci				err = uc_mgr_evaluate_inplace(uc_mgr, n2);
2225d5ac70f0Sopenharmony_ci				if (err < 0)
2226d5ac70f0Sopenharmony_ci					goto __error;
2227d5ac70f0Sopenharmony_ci				if (strcmp(use_case_name, id2) == 0)
2228d5ac70f0Sopenharmony_ci					variant_ok = true;
2229d5ac70f0Sopenharmony_ci			}
2230d5ac70f0Sopenharmony_ci			continue;
2231d5ac70f0Sopenharmony_ci		}
2232d5ac70f0Sopenharmony_ci
2233d5ac70f0Sopenharmony_ci		uc_error("unknown field '%s' in SectionUseCase", id);
2234d5ac70f0Sopenharmony_ci	}
2235d5ac70f0Sopenharmony_ci
2236d5ac70f0Sopenharmony_ci	if (variant && !variant_ok) {
2237d5ac70f0Sopenharmony_ci		uc_error("error: undefined variant '%s'", use_case_name);
2238d5ac70f0Sopenharmony_ci		err = -EINVAL;
2239d5ac70f0Sopenharmony_ci		goto __error;
2240d5ac70f0Sopenharmony_ci	}
2241d5ac70f0Sopenharmony_ci
2242d5ac70f0Sopenharmony_ci	if (!variant) {
2243d5ac70f0Sopenharmony_ci		uc_dbg("use_case_name %s file '%s'", use_case_name, file);
2244d5ac70f0Sopenharmony_ci
2245d5ac70f0Sopenharmony_ci		/* do we have both use case name and file ? */
2246d5ac70f0Sopenharmony_ci		if (!file) {
2247d5ac70f0Sopenharmony_ci			uc_error("error: use case missing file");
2248d5ac70f0Sopenharmony_ci			err = -EINVAL;
2249d5ac70f0Sopenharmony_ci			goto __error;
2250d5ac70f0Sopenharmony_ci		}
2251d5ac70f0Sopenharmony_ci
2252d5ac70f0Sopenharmony_ci		/* parse verb file */
2253d5ac70f0Sopenharmony_ci		err = parse_verb_file(uc_mgr, use_case_name, comment, file);
2254d5ac70f0Sopenharmony_ci	} else {
2255d5ac70f0Sopenharmony_ci		/* parse variants */
2256d5ac70f0Sopenharmony_ci		snd_config_for_each(i, next, variant) {
2257d5ac70f0Sopenharmony_ci			char *vfile, *vcomment;
2258d5ac70f0Sopenharmony_ci			const char *id;
2259d5ac70f0Sopenharmony_ci			n = snd_config_iterator_entry(i);
2260d5ac70f0Sopenharmony_ci			if (snd_config_get_id(n, &id) < 0)
2261d5ac70f0Sopenharmony_ci				continue;
2262d5ac70f0Sopenharmony_ci			if (!parse_is_name_safe(id)) {
2263d5ac70f0Sopenharmony_ci				err = -EINVAL;
2264d5ac70f0Sopenharmony_ci				goto __error;
2265d5ac70f0Sopenharmony_ci			}
2266d5ac70f0Sopenharmony_ci			err = parse_variant(uc_mgr, n, &vfile, &vcomment);
2267d5ac70f0Sopenharmony_ci			if (err < 0)
2268d5ac70f0Sopenharmony_ci				break;
2269d5ac70f0Sopenharmony_ci			uc_mgr->parse_variant = id;
2270d5ac70f0Sopenharmony_ci			err = parse_verb_file(uc_mgr, id,
2271d5ac70f0Sopenharmony_ci						vcomment ? vcomment : comment,
2272d5ac70f0Sopenharmony_ci						vfile ? vfile : file);
2273d5ac70f0Sopenharmony_ci			uc_mgr->parse_variant = NULL;
2274d5ac70f0Sopenharmony_ci			free(vfile);
2275d5ac70f0Sopenharmony_ci			free(vcomment);
2276d5ac70f0Sopenharmony_ci		}
2277d5ac70f0Sopenharmony_ci	}
2278d5ac70f0Sopenharmony_ci
2279d5ac70f0Sopenharmony_ci__error:
2280d5ac70f0Sopenharmony_ci	free(use_case_name);
2281d5ac70f0Sopenharmony_ci	free(file);
2282d5ac70f0Sopenharmony_ci	free(comment);
2283d5ac70f0Sopenharmony_ci	return err;
2284d5ac70f0Sopenharmony_ci}
2285d5ac70f0Sopenharmony_ci
2286d5ac70f0Sopenharmony_ci/*
2287d5ac70f0Sopenharmony_ci * parse controls which should be run only at initial boot (forcefully)
2288d5ac70f0Sopenharmony_ci */
2289d5ac70f0Sopenharmony_cistatic int parse_controls_fixedboot(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
2290d5ac70f0Sopenharmony_ci{
2291d5ac70f0Sopenharmony_ci	int err;
2292d5ac70f0Sopenharmony_ci
2293d5ac70f0Sopenharmony_ci	if (!list_empty(&uc_mgr->fixedboot_list)) {
2294d5ac70f0Sopenharmony_ci		uc_error("FixedBoot list is not empty");
2295d5ac70f0Sopenharmony_ci		return -EINVAL;
2296d5ac70f0Sopenharmony_ci	}
2297d5ac70f0Sopenharmony_ci	err = parse_sequence(uc_mgr, &uc_mgr->fixedboot_list, cfg);
2298d5ac70f0Sopenharmony_ci	if (err < 0) {
2299d5ac70f0Sopenharmony_ci		uc_error("Unable to parse FixedBootSequence");
2300d5ac70f0Sopenharmony_ci		return err;
2301d5ac70f0Sopenharmony_ci	}
2302d5ac70f0Sopenharmony_ci
2303d5ac70f0Sopenharmony_ci	return 0;
2304d5ac70f0Sopenharmony_ci}
2305d5ac70f0Sopenharmony_ci
2306d5ac70f0Sopenharmony_ci/*
2307d5ac70f0Sopenharmony_ci * parse controls which should be run only at initial boot
2308d5ac70f0Sopenharmony_ci */
2309d5ac70f0Sopenharmony_cistatic int parse_controls_boot(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
2310d5ac70f0Sopenharmony_ci{
2311d5ac70f0Sopenharmony_ci	int err;
2312d5ac70f0Sopenharmony_ci
2313d5ac70f0Sopenharmony_ci	if (!list_empty(&uc_mgr->boot_list)) {
2314d5ac70f0Sopenharmony_ci		uc_error("Boot list is not empty");
2315d5ac70f0Sopenharmony_ci		return -EINVAL;
2316d5ac70f0Sopenharmony_ci	}
2317d5ac70f0Sopenharmony_ci	err = parse_sequence(uc_mgr, &uc_mgr->boot_list, cfg);
2318d5ac70f0Sopenharmony_ci	if (err < 0) {
2319d5ac70f0Sopenharmony_ci		uc_error("Unable to parse BootSequence");
2320d5ac70f0Sopenharmony_ci		return err;
2321d5ac70f0Sopenharmony_ci	}
2322d5ac70f0Sopenharmony_ci
2323d5ac70f0Sopenharmony_ci	return 0;
2324d5ac70f0Sopenharmony_ci}
2325d5ac70f0Sopenharmony_ci
2326d5ac70f0Sopenharmony_ci/*
2327d5ac70f0Sopenharmony_ci * parse controls
2328d5ac70f0Sopenharmony_ci */
2329d5ac70f0Sopenharmony_cistatic int parse_controls(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
2330d5ac70f0Sopenharmony_ci{
2331d5ac70f0Sopenharmony_ci	int err;
2332d5ac70f0Sopenharmony_ci
2333d5ac70f0Sopenharmony_ci	if (!list_empty(&uc_mgr->default_list)) {
2334d5ac70f0Sopenharmony_ci		uc_error("Default list is not empty");
2335d5ac70f0Sopenharmony_ci		return -EINVAL;
2336d5ac70f0Sopenharmony_ci	}
2337d5ac70f0Sopenharmony_ci	err = parse_sequence(uc_mgr, &uc_mgr->default_list, cfg);
2338d5ac70f0Sopenharmony_ci	if (err < 0) {
2339d5ac70f0Sopenharmony_ci		uc_error("Unable to parse SectionDefaults");
2340d5ac70f0Sopenharmony_ci		return err;
2341d5ac70f0Sopenharmony_ci	}
2342d5ac70f0Sopenharmony_ci
2343d5ac70f0Sopenharmony_ci	return 0;
2344d5ac70f0Sopenharmony_ci}
2345d5ac70f0Sopenharmony_ci
2346d5ac70f0Sopenharmony_ci/*
2347d5ac70f0Sopenharmony_ci * Each sound card has a master sound card file that lists all the supported
2348d5ac70f0Sopenharmony_ci * use case verbs for that sound card. i.e.
2349d5ac70f0Sopenharmony_ci *
2350d5ac70f0Sopenharmony_ci * #Example master file for blah sound card
2351d5ac70f0Sopenharmony_ci * #By Joe Blogs <joe@bloggs.org>
2352d5ac70f0Sopenharmony_ci *
2353d5ac70f0Sopenharmony_ci * Comment "Nice Abstracted Soundcard"
2354d5ac70f0Sopenharmony_ci *
2355d5ac70f0Sopenharmony_ci * # The file is divided into Use case sections. One section per use case verb.
2356d5ac70f0Sopenharmony_ci *
2357d5ac70f0Sopenharmony_ci * SectionUseCase."Voice Call" {
2358d5ac70f0Sopenharmony_ci *	File "voice_call_blah"
2359d5ac70f0Sopenharmony_ci *	Comment "Make a voice phone call."
2360d5ac70f0Sopenharmony_ci * }
2361d5ac70f0Sopenharmony_ci *
2362d5ac70f0Sopenharmony_ci * SectionUseCase."HiFi" {
2363d5ac70f0Sopenharmony_ci *	File "hifi_blah"
2364d5ac70f0Sopenharmony_ci *	Comment "Play and record HiFi quality Music."
2365d5ac70f0Sopenharmony_ci * }
2366d5ac70f0Sopenharmony_ci *
2367d5ac70f0Sopenharmony_ci * # Define Value defaults
2368d5ac70f0Sopenharmony_ci *
2369d5ac70f0Sopenharmony_ci * ValueDefaults {
2370d5ac70f0Sopenharmony_ci *	PlaybackCTL "hw:CARD=0"
2371d5ac70f0Sopenharmony_ci *	CaptureCTL "hw:CARD=0"
2372d5ac70f0Sopenharmony_ci * }
2373d5ac70f0Sopenharmony_ci *
2374d5ac70f0Sopenharmony_ci * # The initial boot (run once) configuration.
2375d5ac70f0Sopenharmony_ci *
2376d5ac70f0Sopenharmony_ci * BootSequence [
2377d5ac70f0Sopenharmony_ci *      cset "name='Master Playback Switch',index=2 1,1"
2378d5ac70f0Sopenharmony_ci *	cset "name='Master Playback Volume',index=2 25,25"
2379d5ac70f0Sopenharmony_ci * ]
2380d5ac70f0Sopenharmony_ci *
2381d5ac70f0Sopenharmony_ci * # This file also stores the default sound card state.
2382d5ac70f0Sopenharmony_ci *
2383d5ac70f0Sopenharmony_ci * SectionDefaults [
2384d5ac70f0Sopenharmony_ci *	cset "name='Master Mono Playback',index=1 0"
2385d5ac70f0Sopenharmony_ci *	cset "name='Master Mono Playback Volume',index=1 0"
2386d5ac70f0Sopenharmony_ci *	cset "name='PCM Switch',index=2 1,1"
2387d5ac70f0Sopenharmony_ci *      exec "some binary here"
2388d5ac70f0Sopenharmony_ci *      msleep 50
2389d5ac70f0Sopenharmony_ci *	........
2390d5ac70f0Sopenharmony_ci * ]
2391d5ac70f0Sopenharmony_ci *
2392d5ac70f0Sopenharmony_ci * # End of example file.
2393d5ac70f0Sopenharmony_ci */
2394d5ac70f0Sopenharmony_cistatic int parse_master_file(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
2395d5ac70f0Sopenharmony_ci{
2396d5ac70f0Sopenharmony_ci	snd_config_iterator_t i, next;
2397d5ac70f0Sopenharmony_ci	snd_config_t *n;
2398d5ac70f0Sopenharmony_ci	const char *id;
2399d5ac70f0Sopenharmony_ci	int err;
2400d5ac70f0Sopenharmony_ci
2401d5ac70f0Sopenharmony_ci	if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
2402d5ac70f0Sopenharmony_ci		uc_error("compound type expected for master file");
2403d5ac70f0Sopenharmony_ci		return -EINVAL;
2404d5ac70f0Sopenharmony_ci	}
2405d5ac70f0Sopenharmony_ci
2406d5ac70f0Sopenharmony_ci	if (uc_mgr->conf_format >= 2) {
2407d5ac70f0Sopenharmony_ci		err = parse_syntax_field(uc_mgr, cfg, uc_mgr->conf_file_name);
2408d5ac70f0Sopenharmony_ci		if (err < 0)
2409d5ac70f0Sopenharmony_ci			return err;
2410d5ac70f0Sopenharmony_ci	}
2411d5ac70f0Sopenharmony_ci
2412d5ac70f0Sopenharmony_ci	/* in-place evaluation */
2413d5ac70f0Sopenharmony_ci	err = uc_mgr_evaluate_inplace(uc_mgr, cfg);
2414d5ac70f0Sopenharmony_ci	if (err < 0)
2415d5ac70f0Sopenharmony_ci		return err;
2416d5ac70f0Sopenharmony_ci
2417d5ac70f0Sopenharmony_ci	/* parse master config sections */
2418d5ac70f0Sopenharmony_ci	snd_config_for_each(i, next, cfg) {
2419d5ac70f0Sopenharmony_ci
2420d5ac70f0Sopenharmony_ci		n = snd_config_iterator_entry(i);
2421d5ac70f0Sopenharmony_ci		if (snd_config_get_id(n, &id) < 0)
2422d5ac70f0Sopenharmony_ci			continue;
2423d5ac70f0Sopenharmony_ci
2424d5ac70f0Sopenharmony_ci		if (strcmp(id, "Comment") == 0) {
2425d5ac70f0Sopenharmony_ci			err = parse_string_substitute3(uc_mgr, n, &uc_mgr->comment);
2426d5ac70f0Sopenharmony_ci			if (err < 0) {
2427d5ac70f0Sopenharmony_ci				uc_error("error: failed to get master comment");
2428d5ac70f0Sopenharmony_ci				return err;
2429d5ac70f0Sopenharmony_ci			}
2430d5ac70f0Sopenharmony_ci			continue;
2431d5ac70f0Sopenharmony_ci		}
2432d5ac70f0Sopenharmony_ci
2433d5ac70f0Sopenharmony_ci		/* find use case section and parse it */
2434d5ac70f0Sopenharmony_ci		if (strcmp(id, "SectionUseCase") == 0) {
2435d5ac70f0Sopenharmony_ci			err = parse_compound(uc_mgr, n,
2436d5ac70f0Sopenharmony_ci					     parse_master_section,
2437d5ac70f0Sopenharmony_ci					     NULL, NULL);
2438d5ac70f0Sopenharmony_ci			if (err < 0)
2439d5ac70f0Sopenharmony_ci				return err;
2440d5ac70f0Sopenharmony_ci			continue;
2441d5ac70f0Sopenharmony_ci		}
2442d5ac70f0Sopenharmony_ci
2443d5ac70f0Sopenharmony_ci		/* find default control values section (force boot sequence only) */
2444d5ac70f0Sopenharmony_ci		if (strcmp(id, "FixedBootSequence") == 0) {
2445d5ac70f0Sopenharmony_ci			err = parse_controls_fixedboot(uc_mgr, n);
2446d5ac70f0Sopenharmony_ci			if (err < 0)
2447d5ac70f0Sopenharmony_ci				return err;
2448d5ac70f0Sopenharmony_ci			continue;
2449d5ac70f0Sopenharmony_ci		}
2450d5ac70f0Sopenharmony_ci
2451d5ac70f0Sopenharmony_ci		/* find default control values section (first boot only) */
2452d5ac70f0Sopenharmony_ci		if (strcmp(id, "BootSequence") == 0) {
2453d5ac70f0Sopenharmony_ci			err = parse_controls_boot(uc_mgr, n);
2454d5ac70f0Sopenharmony_ci			if (err < 0)
2455d5ac70f0Sopenharmony_ci				return err;
2456d5ac70f0Sopenharmony_ci			continue;
2457d5ac70f0Sopenharmony_ci		}
2458d5ac70f0Sopenharmony_ci
2459d5ac70f0Sopenharmony_ci		/* find default control values section and parse it */
2460d5ac70f0Sopenharmony_ci		if (strcmp(id, "SectionDefaults") == 0) {
2461d5ac70f0Sopenharmony_ci			err = parse_controls(uc_mgr, n);
2462d5ac70f0Sopenharmony_ci			if (err < 0)
2463d5ac70f0Sopenharmony_ci				return err;
2464d5ac70f0Sopenharmony_ci			continue;
2465d5ac70f0Sopenharmony_ci		}
2466d5ac70f0Sopenharmony_ci
2467d5ac70f0Sopenharmony_ci		/* get the default values */
2468d5ac70f0Sopenharmony_ci		if (strcmp(id, "ValueDefaults") == 0) {
2469d5ac70f0Sopenharmony_ci			err = parse_value(uc_mgr, &uc_mgr->value_list, n);
2470d5ac70f0Sopenharmony_ci			if (err < 0) {
2471d5ac70f0Sopenharmony_ci				uc_error("error: failed to parse ValueDefaults");
2472d5ac70f0Sopenharmony_ci				return err;
2473d5ac70f0Sopenharmony_ci			}
2474d5ac70f0Sopenharmony_ci			continue;
2475d5ac70f0Sopenharmony_ci		}
2476d5ac70f0Sopenharmony_ci
2477d5ac70f0Sopenharmony_ci		/* alsa-lib configuration */
2478d5ac70f0Sopenharmony_ci		if (uc_mgr->conf_format > 3 && strcmp(id, "LibraryConfig") == 0) {
2479d5ac70f0Sopenharmony_ci			err = parse_libconfig(uc_mgr, n);
2480d5ac70f0Sopenharmony_ci			if (err < 0) {
2481d5ac70f0Sopenharmony_ci				uc_error("error: failed to parse LibraryConfig");
2482d5ac70f0Sopenharmony_ci				return err;
2483d5ac70f0Sopenharmony_ci			}
2484d5ac70f0Sopenharmony_ci			continue;
2485d5ac70f0Sopenharmony_ci		}
2486d5ac70f0Sopenharmony_ci
2487d5ac70f0Sopenharmony_ci		/* error */
2488d5ac70f0Sopenharmony_ci		if (strcmp(id, "Error") == 0)
2489d5ac70f0Sopenharmony_ci			return error_node(uc_mgr, n);
2490d5ac70f0Sopenharmony_ci
2491d5ac70f0Sopenharmony_ci		/* skip further Syntax value updates (Include) */
2492d5ac70f0Sopenharmony_ci		if (strcmp(id, "Syntax") == 0)
2493d5ac70f0Sopenharmony_ci			continue;
2494d5ac70f0Sopenharmony_ci
2495d5ac70f0Sopenharmony_ci		uc_error("unknown master file field %s", id);
2496d5ac70f0Sopenharmony_ci	}
2497d5ac70f0Sopenharmony_ci	return 0;
2498d5ac70f0Sopenharmony_ci}
2499d5ac70f0Sopenharmony_ci
2500d5ac70f0Sopenharmony_ci/* get the card info */
2501d5ac70f0Sopenharmony_cistatic int get_card_info(snd_use_case_mgr_t *mgr,
2502d5ac70f0Sopenharmony_ci			 const char *ctl_name,
2503d5ac70f0Sopenharmony_ci			 snd_ctl_card_info_t **info)
2504d5ac70f0Sopenharmony_ci{
2505d5ac70f0Sopenharmony_ci	struct ctl_list *ctl_list;
2506d5ac70f0Sopenharmony_ci	int err;
2507d5ac70f0Sopenharmony_ci
2508d5ac70f0Sopenharmony_ci	err = uc_mgr_open_ctl(mgr, &ctl_list, ctl_name, 0);
2509d5ac70f0Sopenharmony_ci	if (err < 0)
2510d5ac70f0Sopenharmony_ci		return err;
2511d5ac70f0Sopenharmony_ci
2512d5ac70f0Sopenharmony_ci	if (info)
2513d5ac70f0Sopenharmony_ci		*info = ctl_list->ctl_info;
2514d5ac70f0Sopenharmony_ci	return err;
2515d5ac70f0Sopenharmony_ci}
2516d5ac70f0Sopenharmony_ci
2517d5ac70f0Sopenharmony_ci/* find the card in the local machine */
2518d5ac70f0Sopenharmony_cistatic int get_by_card_name(snd_use_case_mgr_t *mgr, const char *card_name)
2519d5ac70f0Sopenharmony_ci{
2520d5ac70f0Sopenharmony_ci	int card, err;
2521d5ac70f0Sopenharmony_ci	snd_ctl_card_info_t *info;
2522d5ac70f0Sopenharmony_ci	const char *_driver, *_name, *_long_name;
2523d5ac70f0Sopenharmony_ci
2524d5ac70f0Sopenharmony_ci	snd_ctl_card_info_alloca(&info);
2525d5ac70f0Sopenharmony_ci
2526d5ac70f0Sopenharmony_ci	card = -1;
2527d5ac70f0Sopenharmony_ci	if (snd_card_next(&card) < 0 || card < 0) {
2528d5ac70f0Sopenharmony_ci		uc_error("no soundcards found...");
2529d5ac70f0Sopenharmony_ci		return -1;
2530d5ac70f0Sopenharmony_ci	}
2531d5ac70f0Sopenharmony_ci
2532d5ac70f0Sopenharmony_ci	while (card >= 0) {
2533d5ac70f0Sopenharmony_ci		char name[32];
2534d5ac70f0Sopenharmony_ci
2535d5ac70f0Sopenharmony_ci		/* clear the list, keep the only one CTL device */
2536d5ac70f0Sopenharmony_ci		uc_mgr_free_ctl_list(mgr);
2537d5ac70f0Sopenharmony_ci
2538d5ac70f0Sopenharmony_ci		sprintf(name, "hw:%d", card);
2539d5ac70f0Sopenharmony_ci		err = get_card_info(mgr, name, &info);
2540d5ac70f0Sopenharmony_ci
2541d5ac70f0Sopenharmony_ci		if (err == 0) {
2542d5ac70f0Sopenharmony_ci			_driver = snd_ctl_card_info_get_driver(info);
2543d5ac70f0Sopenharmony_ci			_name = snd_ctl_card_info_get_name(info);
2544d5ac70f0Sopenharmony_ci			_long_name = snd_ctl_card_info_get_longname(info);
2545d5ac70f0Sopenharmony_ci			if (!strcmp(card_name, _driver) ||
2546d5ac70f0Sopenharmony_ci			    !strcmp(card_name, _name) ||
2547d5ac70f0Sopenharmony_ci			    !strcmp(card_name, _long_name))
2548d5ac70f0Sopenharmony_ci				return 0;
2549d5ac70f0Sopenharmony_ci		}
2550d5ac70f0Sopenharmony_ci
2551d5ac70f0Sopenharmony_ci		if (snd_card_next(&card) < 0) {
2552d5ac70f0Sopenharmony_ci			uc_error("snd_card_next");
2553d5ac70f0Sopenharmony_ci			break;
2554d5ac70f0Sopenharmony_ci		}
2555d5ac70f0Sopenharmony_ci	}
2556d5ac70f0Sopenharmony_ci
2557d5ac70f0Sopenharmony_ci	uc_mgr_free_ctl_list(mgr);
2558d5ac70f0Sopenharmony_ci
2559d5ac70f0Sopenharmony_ci	return -1;
2560d5ac70f0Sopenharmony_ci}
2561d5ac70f0Sopenharmony_ci
2562d5ac70f0Sopenharmony_ci/* set the driver name and long name by the card ctl name */
2563d5ac70f0Sopenharmony_cistatic inline int get_by_card(snd_use_case_mgr_t *mgr, const char *ctl_name)
2564d5ac70f0Sopenharmony_ci{
2565d5ac70f0Sopenharmony_ci	return get_card_info(mgr, ctl_name, NULL);
2566d5ac70f0Sopenharmony_ci}
2567d5ac70f0Sopenharmony_ci
2568d5ac70f0Sopenharmony_cistatic int parse_toplevel_path(snd_use_case_mgr_t *uc_mgr,
2569d5ac70f0Sopenharmony_ci			       char *filename,
2570d5ac70f0Sopenharmony_ci			       snd_config_t *cfg)
2571d5ac70f0Sopenharmony_ci{
2572d5ac70f0Sopenharmony_ci	snd_config_iterator_t i, next, i2, next2;
2573d5ac70f0Sopenharmony_ci	snd_config_t *n, *n2;
2574d5ac70f0Sopenharmony_ci	const char *id;
2575d5ac70f0Sopenharmony_ci	char *dir = NULL, *file = NULL, fn[PATH_MAX];
2576d5ac70f0Sopenharmony_ci	struct stat64 st;
2577d5ac70f0Sopenharmony_ci	long version;
2578d5ac70f0Sopenharmony_ci	int err;
2579d5ac70f0Sopenharmony_ci
2580d5ac70f0Sopenharmony_ci	if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
2581d5ac70f0Sopenharmony_ci		uc_error("compound type expected for UseCasePath node");
2582d5ac70f0Sopenharmony_ci		return -EINVAL;
2583d5ac70f0Sopenharmony_ci	}
2584d5ac70f0Sopenharmony_ci
2585d5ac70f0Sopenharmony_ci	/* parse use case path config sections */
2586d5ac70f0Sopenharmony_ci	snd_config_for_each(i, next, cfg) {
2587d5ac70f0Sopenharmony_ci		n = snd_config_iterator_entry(i);
2588d5ac70f0Sopenharmony_ci
2589d5ac70f0Sopenharmony_ci		if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
2590d5ac70f0Sopenharmony_ci			uc_error("compound type expected for UseCasePath.something node");
2591d5ac70f0Sopenharmony_ci			return -EINVAL;
2592d5ac70f0Sopenharmony_ci		}
2593d5ac70f0Sopenharmony_ci
2594d5ac70f0Sopenharmony_ci			if (snd_config_get_id(n, &id) < 0)
2595d5ac70f0Sopenharmony_ci				continue;
2596d5ac70f0Sopenharmony_ci
2597d5ac70f0Sopenharmony_ci		version = 2;
2598d5ac70f0Sopenharmony_ci
2599d5ac70f0Sopenharmony_ci		/* parse use case path config sections */
2600d5ac70f0Sopenharmony_ci		snd_config_for_each(i2, next2, n) {
2601d5ac70f0Sopenharmony_ci
2602d5ac70f0Sopenharmony_ci			n2 = snd_config_iterator_entry(i2);
2603d5ac70f0Sopenharmony_ci			if (snd_config_get_id(n2, &id) < 0)
2604d5ac70f0Sopenharmony_ci				continue;
2605d5ac70f0Sopenharmony_ci
2606d5ac70f0Sopenharmony_ci			if (strcmp(id, "Version") == 0) {
2607d5ac70f0Sopenharmony_ci				err = parse_integer_substitute(uc_mgr, n2, &version);
2608d5ac70f0Sopenharmony_ci				if (err < 0) {
2609d5ac70f0Sopenharmony_ci					uc_error("unable to parse UcmDirectory");
2610d5ac70f0Sopenharmony_ci					goto __error;
2611d5ac70f0Sopenharmony_ci				}
2612d5ac70f0Sopenharmony_ci				if (version < 1 || version > 2) {
2613d5ac70f0Sopenharmony_ci					uc_error("Version must be 1 or 2");
2614d5ac70f0Sopenharmony_ci					err = -EINVAL;
2615d5ac70f0Sopenharmony_ci					goto __error;
2616d5ac70f0Sopenharmony_ci				}
2617d5ac70f0Sopenharmony_ci				continue;
2618d5ac70f0Sopenharmony_ci			}
2619d5ac70f0Sopenharmony_ci
2620d5ac70f0Sopenharmony_ci			if (strcmp(id, "Directory") == 0) {
2621d5ac70f0Sopenharmony_ci				err = parse_string_substitute(uc_mgr, n2, &dir);
2622d5ac70f0Sopenharmony_ci				if (err < 0) {
2623d5ac70f0Sopenharmony_ci					uc_error("unable to parse Directory");
2624d5ac70f0Sopenharmony_ci					goto __error;
2625d5ac70f0Sopenharmony_ci				}
2626d5ac70f0Sopenharmony_ci				continue;
2627d5ac70f0Sopenharmony_ci			}
2628d5ac70f0Sopenharmony_ci
2629d5ac70f0Sopenharmony_ci			if (strcmp(id, "File") == 0) {
2630d5ac70f0Sopenharmony_ci				err = parse_string_substitute(uc_mgr, n2, &file);
2631d5ac70f0Sopenharmony_ci				if (err < 0) {
2632d5ac70f0Sopenharmony_ci					uc_error("unable to parse File");
2633d5ac70f0Sopenharmony_ci					goto __error;
2634d5ac70f0Sopenharmony_ci				}
2635d5ac70f0Sopenharmony_ci				continue;
2636d5ac70f0Sopenharmony_ci			}
2637d5ac70f0Sopenharmony_ci
2638d5ac70f0Sopenharmony_ci			uc_error("unknown UseCasePath field %s", id);
2639d5ac70f0Sopenharmony_ci		}
2640d5ac70f0Sopenharmony_ci
2641d5ac70f0Sopenharmony_ci		if (dir == NULL) {
2642d5ac70f0Sopenharmony_ci			uc_error("Directory is not defined in %s!", filename);
2643d5ac70f0Sopenharmony_ci			goto __next;
2644d5ac70f0Sopenharmony_ci		}
2645d5ac70f0Sopenharmony_ci		if (file == NULL) {
2646d5ac70f0Sopenharmony_ci			uc_error("File is not defined in %s!", filename);
2647d5ac70f0Sopenharmony_ci			goto __next;
2648d5ac70f0Sopenharmony_ci		}
2649d5ac70f0Sopenharmony_ci
2650d5ac70f0Sopenharmony_ci		ucm_filename(fn, sizeof(fn), version, dir, file);
2651d5ac70f0Sopenharmony_ci		if (access(fn, R_OK) == 0 && lstat64(fn, &st) == 0) {
2652d5ac70f0Sopenharmony_ci			if (S_ISLNK(st.st_mode)) {
2653d5ac70f0Sopenharmony_ci				ssize_t r;
2654d5ac70f0Sopenharmony_ci				char *link, *dir2, *p;
2655d5ac70f0Sopenharmony_ci
2656d5ac70f0Sopenharmony_ci				link = malloc(PATH_MAX);
2657d5ac70f0Sopenharmony_ci				if (link == NULL)
2658d5ac70f0Sopenharmony_ci					goto __enomem;
2659d5ac70f0Sopenharmony_ci				r = readlink(fn, link, PATH_MAX - 1);
2660d5ac70f0Sopenharmony_ci				if (r <= 0) {
2661d5ac70f0Sopenharmony_ci					free(link);
2662d5ac70f0Sopenharmony_ci					goto __next;
2663d5ac70f0Sopenharmony_ci				}
2664d5ac70f0Sopenharmony_ci				link[r] = '\0';
2665d5ac70f0Sopenharmony_ci				p = strrchr(link, '/');
2666d5ac70f0Sopenharmony_ci				if (p) {
2667d5ac70f0Sopenharmony_ci					*p = '\0';
2668d5ac70f0Sopenharmony_ci					dir2 = malloc(PATH_MAX);
2669d5ac70f0Sopenharmony_ci					if (dir2 == NULL) {
2670d5ac70f0Sopenharmony_ci						free(link);
2671d5ac70f0Sopenharmony_ci						goto __enomem;
2672d5ac70f0Sopenharmony_ci					}
2673d5ac70f0Sopenharmony_ci					strncpy(dir2, dir, PATH_MAX - 1);
2674d5ac70f0Sopenharmony_ci					strncat(dir2, "/", PATH_MAX - 1);
2675d5ac70f0Sopenharmony_ci					strncat(dir2, link, PATH_MAX - 1);
2676d5ac70f0Sopenharmony_ci					fn[PATH_MAX - 1] = '\0';
2677d5ac70f0Sopenharmony_ci					free(dir);
2678d5ac70f0Sopenharmony_ci					dir = dir2;
2679d5ac70f0Sopenharmony_ci				}
2680d5ac70f0Sopenharmony_ci				free(link);
2681d5ac70f0Sopenharmony_ci			}
2682d5ac70f0Sopenharmony_ci			if (replace_string(&uc_mgr->conf_dir_name, dir) == NULL)
2683d5ac70f0Sopenharmony_ci				goto __enomem;
2684d5ac70f0Sopenharmony_ci			if (replace_string(&uc_mgr->conf_file_name, file) == NULL)
2685d5ac70f0Sopenharmony_ci				goto __enomem;
2686d5ac70f0Sopenharmony_ci			strncpy(filename, fn, PATH_MAX);
2687d5ac70f0Sopenharmony_ci			filename[PATH_MAX - 1] = '\0';
2688d5ac70f0Sopenharmony_ci			uc_mgr->conf_format = version;
2689d5ac70f0Sopenharmony_ci			goto __ok;
2690d5ac70f0Sopenharmony_ci		}
2691d5ac70f0Sopenharmony_ci
2692d5ac70f0Sopenharmony_ci__next:
2693d5ac70f0Sopenharmony_ci		free(file);
2694d5ac70f0Sopenharmony_ci		if (dir != fn)
2695d5ac70f0Sopenharmony_ci			free(dir);
2696d5ac70f0Sopenharmony_ci		dir = NULL;
2697d5ac70f0Sopenharmony_ci		file = NULL;
2698d5ac70f0Sopenharmony_ci	}
2699d5ac70f0Sopenharmony_ci
2700d5ac70f0Sopenharmony_ci	err = -ENOENT;
2701d5ac70f0Sopenharmony_ci	goto __error;
2702d5ac70f0Sopenharmony_ci
2703d5ac70f0Sopenharmony_ci__enomem:
2704d5ac70f0Sopenharmony_ci	err = -ENOMEM;
2705d5ac70f0Sopenharmony_ci	goto __error;
2706d5ac70f0Sopenharmony_ci
2707d5ac70f0Sopenharmony_ci__ok:
2708d5ac70f0Sopenharmony_ci	err = 0;
2709d5ac70f0Sopenharmony_ci__error:
2710d5ac70f0Sopenharmony_ci	free(file);
2711d5ac70f0Sopenharmony_ci	if (dir != fn)
2712d5ac70f0Sopenharmony_ci		free(dir);
2713d5ac70f0Sopenharmony_ci	return err;
2714d5ac70f0Sopenharmony_ci}
2715d5ac70f0Sopenharmony_ci
2716d5ac70f0Sopenharmony_cistatic int parse_toplevel_config(snd_use_case_mgr_t *uc_mgr,
2717d5ac70f0Sopenharmony_ci				 char *filename,
2718d5ac70f0Sopenharmony_ci				 snd_config_t *cfg)
2719d5ac70f0Sopenharmony_ci{
2720d5ac70f0Sopenharmony_ci	snd_config_iterator_t i, next;
2721d5ac70f0Sopenharmony_ci	snd_config_t *n;
2722d5ac70f0Sopenharmony_ci	const char *id;
2723d5ac70f0Sopenharmony_ci	int err;
2724d5ac70f0Sopenharmony_ci
2725d5ac70f0Sopenharmony_ci	if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
2726d5ac70f0Sopenharmony_ci		uc_error("compound type expected for toplevel file");
2727d5ac70f0Sopenharmony_ci		return -EINVAL;
2728d5ac70f0Sopenharmony_ci	}
2729d5ac70f0Sopenharmony_ci
2730d5ac70f0Sopenharmony_ci	err = parse_syntax_field(uc_mgr, cfg, filename);
2731d5ac70f0Sopenharmony_ci	if (err < 0)
2732d5ac70f0Sopenharmony_ci		return err;
2733d5ac70f0Sopenharmony_ci
2734d5ac70f0Sopenharmony_ci	/* in-place evaluation */
2735d5ac70f0Sopenharmony_ci	err = uc_mgr_evaluate_inplace(uc_mgr, cfg);
2736d5ac70f0Sopenharmony_ci	if (err < 0)
2737d5ac70f0Sopenharmony_ci		return err;
2738d5ac70f0Sopenharmony_ci
2739d5ac70f0Sopenharmony_ci	/* parse toplevel config sections */
2740d5ac70f0Sopenharmony_ci	snd_config_for_each(i, next, cfg) {
2741d5ac70f0Sopenharmony_ci
2742d5ac70f0Sopenharmony_ci		n = snd_config_iterator_entry(i);
2743d5ac70f0Sopenharmony_ci		if (snd_config_get_id(n, &id) < 0)
2744d5ac70f0Sopenharmony_ci			continue;
2745d5ac70f0Sopenharmony_ci
2746d5ac70f0Sopenharmony_ci		if (strcmp(id, "UseCasePath") == 0) {
2747d5ac70f0Sopenharmony_ci			err = parse_toplevel_path(uc_mgr, filename, n);
2748d5ac70f0Sopenharmony_ci			if (err == 0)
2749d5ac70f0Sopenharmony_ci				return err;
2750d5ac70f0Sopenharmony_ci			continue;
2751d5ac70f0Sopenharmony_ci		}
2752d5ac70f0Sopenharmony_ci
2753d5ac70f0Sopenharmony_ci		/* alsa-lib configuration */
2754d5ac70f0Sopenharmony_ci		if (uc_mgr->conf_format > 3 && strcmp(id, "LibraryConfig") == 0) {
2755d5ac70f0Sopenharmony_ci			err = parse_libconfig(uc_mgr, n);
2756d5ac70f0Sopenharmony_ci			if (err < 0) {
2757d5ac70f0Sopenharmony_ci				uc_error("error: failed to parse LibConfig");
2758d5ac70f0Sopenharmony_ci				return err;
2759d5ac70f0Sopenharmony_ci			}
2760d5ac70f0Sopenharmony_ci			continue;
2761d5ac70f0Sopenharmony_ci		}
2762d5ac70f0Sopenharmony_ci
2763d5ac70f0Sopenharmony_ci		/* skip further Syntax value updates (Include) */
2764d5ac70f0Sopenharmony_ci		if (strcmp(id, "Syntax") == 0)
2765d5ac70f0Sopenharmony_ci			continue;
2766d5ac70f0Sopenharmony_ci
2767d5ac70f0Sopenharmony_ci		uc_error("unknown toplevel field %s", id);
2768d5ac70f0Sopenharmony_ci	}
2769d5ac70f0Sopenharmony_ci
2770d5ac70f0Sopenharmony_ci	return -ENOENT;
2771d5ac70f0Sopenharmony_ci}
2772d5ac70f0Sopenharmony_ci
2773d5ac70f0Sopenharmony_cistatic int load_toplevel_config(snd_use_case_mgr_t *uc_mgr,
2774d5ac70f0Sopenharmony_ci				snd_config_t **cfg)
2775d5ac70f0Sopenharmony_ci{
2776d5ac70f0Sopenharmony_ci	char filename[PATH_MAX];
2777d5ac70f0Sopenharmony_ci	snd_config_t *tcfg;
2778d5ac70f0Sopenharmony_ci	int err;
2779d5ac70f0Sopenharmony_ci
2780d5ac70f0Sopenharmony_ci	ucm_filename(filename, sizeof(filename), 2, NULL, "ucm.conf");
2781d5ac70f0Sopenharmony_ci
2782d5ac70f0Sopenharmony_ci	if (access(filename, R_OK) != 0) {
2783d5ac70f0Sopenharmony_ci		uc_error("Unable to find the top-level configuration file '%s'.", filename);
2784d5ac70f0Sopenharmony_ci		return -ENOENT;
2785d5ac70f0Sopenharmony_ci	}
2786d5ac70f0Sopenharmony_ci
2787d5ac70f0Sopenharmony_ci	err = uc_mgr_config_load(2, filename, &tcfg);
2788d5ac70f0Sopenharmony_ci	if (err < 0)
2789d5ac70f0Sopenharmony_ci		goto __error;
2790d5ac70f0Sopenharmony_ci
2791d5ac70f0Sopenharmony_ci	/* filename is shared for function input and output! */
2792d5ac70f0Sopenharmony_ci	err = parse_toplevel_config(uc_mgr, filename, tcfg);
2793d5ac70f0Sopenharmony_ci	snd_config_delete(tcfg);
2794d5ac70f0Sopenharmony_ci	if (err < 0)
2795d5ac70f0Sopenharmony_ci		goto __error;
2796d5ac70f0Sopenharmony_ci
2797d5ac70f0Sopenharmony_ci	err = uc_mgr_config_load(uc_mgr->conf_format, filename, cfg);
2798d5ac70f0Sopenharmony_ci	if (err < 0) {
2799d5ac70f0Sopenharmony_ci		uc_error("error: could not parse configuration for card %s",
2800d5ac70f0Sopenharmony_ci				uc_mgr->card_name);
2801d5ac70f0Sopenharmony_ci		goto __error;
2802d5ac70f0Sopenharmony_ci	}
2803d5ac70f0Sopenharmony_ci
2804d5ac70f0Sopenharmony_ci	return 0;
2805d5ac70f0Sopenharmony_ci
2806d5ac70f0Sopenharmony_ci__error:
2807d5ac70f0Sopenharmony_ci	return err;
2808d5ac70f0Sopenharmony_ci}
2809d5ac70f0Sopenharmony_ci
2810d5ac70f0Sopenharmony_ci/* load master use case file for sound card based on rules in ucm2/ucm.conf
2811d5ac70f0Sopenharmony_ci */
2812d5ac70f0Sopenharmony_ciint uc_mgr_import_master_config(snd_use_case_mgr_t *uc_mgr)
2813d5ac70f0Sopenharmony_ci{
2814d5ac70f0Sopenharmony_ci	snd_config_t *cfg;
2815d5ac70f0Sopenharmony_ci	const char *name;
2816d5ac70f0Sopenharmony_ci	int err;
2817d5ac70f0Sopenharmony_ci
2818d5ac70f0Sopenharmony_ci	err = snd_config_top(&uc_mgr->local_config);
2819d5ac70f0Sopenharmony_ci	if (err < 0)
2820d5ac70f0Sopenharmony_ci		return err;
2821d5ac70f0Sopenharmony_ci
2822d5ac70f0Sopenharmony_ci	err = snd_config_top(&uc_mgr->macros);
2823d5ac70f0Sopenharmony_ci	if (err < 0)
2824d5ac70f0Sopenharmony_ci		return err;
2825d5ac70f0Sopenharmony_ci
2826d5ac70f0Sopenharmony_ci	name = uc_mgr->card_name;
2827d5ac70f0Sopenharmony_ci	if (strncmp(name, "hw:", 3) == 0) {
2828d5ac70f0Sopenharmony_ci		err = get_by_card(uc_mgr, name);
2829d5ac70f0Sopenharmony_ci		if (err < 0) {
2830d5ac70f0Sopenharmony_ci			uc_error("card '%s' is not valid", name);
2831d5ac70f0Sopenharmony_ci			goto __error;
2832d5ac70f0Sopenharmony_ci		}
2833d5ac70f0Sopenharmony_ci	} else if (strncmp(name, "strict:", 7)) {
2834d5ac70f0Sopenharmony_ci		/* do not handle the error here */
2835d5ac70f0Sopenharmony_ci		/* we can refer the virtual UCM config */
2836d5ac70f0Sopenharmony_ci		get_by_card_name(uc_mgr, name);
2837d5ac70f0Sopenharmony_ci	}
2838d5ac70f0Sopenharmony_ci
2839d5ac70f0Sopenharmony_ci	err = load_toplevel_config(uc_mgr, &cfg);
2840d5ac70f0Sopenharmony_ci	if (err < 0)
2841d5ac70f0Sopenharmony_ci		goto __error;
2842d5ac70f0Sopenharmony_ci
2843d5ac70f0Sopenharmony_ci	err = parse_master_file(uc_mgr, cfg);
2844d5ac70f0Sopenharmony_ci	if (uc_mgr->macros) {
2845d5ac70f0Sopenharmony_ci		snd_config_delete(uc_mgr->macros);
2846d5ac70f0Sopenharmony_ci		uc_mgr->macros = NULL;
2847d5ac70f0Sopenharmony_ci	}
2848d5ac70f0Sopenharmony_ci	snd_config_delete(cfg);
2849d5ac70f0Sopenharmony_ci	if (err < 0) {
2850d5ac70f0Sopenharmony_ci		uc_mgr_free_ctl_list(uc_mgr);
2851d5ac70f0Sopenharmony_ci		uc_mgr_free_verb(uc_mgr);
2852d5ac70f0Sopenharmony_ci	}
2853d5ac70f0Sopenharmony_ci
2854d5ac70f0Sopenharmony_ci	return err;
2855d5ac70f0Sopenharmony_ci
2856d5ac70f0Sopenharmony_ci__error:
2857d5ac70f0Sopenharmony_ci	uc_mgr_free_ctl_list(uc_mgr);
2858d5ac70f0Sopenharmony_ci	replace_string(&uc_mgr->conf_dir_name, NULL);
2859d5ac70f0Sopenharmony_ci	return err;
2860d5ac70f0Sopenharmony_ci}
2861d5ac70f0Sopenharmony_ci
2862d5ac70f0Sopenharmony_cistatic int filename_filter(const struct dirent64 *dirent)
2863d5ac70f0Sopenharmony_ci{
2864d5ac70f0Sopenharmony_ci	if (dirent == NULL)
2865d5ac70f0Sopenharmony_ci		return 0;
2866d5ac70f0Sopenharmony_ci	if (dirent->d_type == DT_DIR) {
2867d5ac70f0Sopenharmony_ci		if (dirent->d_name[0] == '.') {
2868d5ac70f0Sopenharmony_ci			if (dirent->d_name[1] == '\0')
2869d5ac70f0Sopenharmony_ci				return 0;
2870d5ac70f0Sopenharmony_ci			if (dirent->d_name[1] == '.' &&
2871d5ac70f0Sopenharmony_ci			    dirent->d_name[2] == '\0')
2872d5ac70f0Sopenharmony_ci				return 0;
2873d5ac70f0Sopenharmony_ci		}
2874d5ac70f0Sopenharmony_ci		return 1;
2875d5ac70f0Sopenharmony_ci	}
2876d5ac70f0Sopenharmony_ci	return 0;
2877d5ac70f0Sopenharmony_ci}
2878d5ac70f0Sopenharmony_ci
2879d5ac70f0Sopenharmony_ci/* scan all cards and comments
2880d5ac70f0Sopenharmony_ci *
2881d5ac70f0Sopenharmony_ci * Cards are defined by machines. Each card/machine installs its UCM
2882d5ac70f0Sopenharmony_ci * configuration files in a subdirectory with the same name as the sound
2883d5ac70f0Sopenharmony_ci * card under /usr/share/alsa/ucm2. This function will scan all the card
2884d5ac70f0Sopenharmony_ci * directories and skip the component directories defined in the array
2885d5ac70f0Sopenharmony_ci * component_dir.
2886d5ac70f0Sopenharmony_ci */
2887d5ac70f0Sopenharmony_ciint uc_mgr_scan_master_configs(const char **_list[])
2888d5ac70f0Sopenharmony_ci{
2889d5ac70f0Sopenharmony_ci	char filename[PATH_MAX], dfl[PATH_MAX], fn[FILENAME_MAX];
2890d5ac70f0Sopenharmony_ci	char *env = getenv(ALSA_CONFIG_UCM2_VAR);
2891d5ac70f0Sopenharmony_ci	snd_use_case_mgr_t *uc_mgr;
2892d5ac70f0Sopenharmony_ci	const char **list, *d_name;
2893d5ac70f0Sopenharmony_ci	char *s;
2894d5ac70f0Sopenharmony_ci	snd_config_t *cfg, *c;
2895d5ac70f0Sopenharmony_ci	int i, j, cnt, err, cards;
2896d5ac70f0Sopenharmony_ci	long l;
2897d5ac70f0Sopenharmony_ci	ssize_t ss;
2898d5ac70f0Sopenharmony_ci	struct dirent64 **namelist;
2899d5ac70f0Sopenharmony_ci
2900d5ac70f0Sopenharmony_ci	i = -1;
2901d5ac70f0Sopenharmony_ci	cards = 0;
2902d5ac70f0Sopenharmony_ci	while (1) {
2903d5ac70f0Sopenharmony_ci		err = snd_card_next(&i);
2904d5ac70f0Sopenharmony_ci		if (err < 0)
2905d5ac70f0Sopenharmony_ci			return err;
2906d5ac70f0Sopenharmony_ci		if (i < 0)
2907d5ac70f0Sopenharmony_ci			break;
2908d5ac70f0Sopenharmony_ci		cards++;
2909d5ac70f0Sopenharmony_ci	}
2910d5ac70f0Sopenharmony_ci	cards += 4;	/* plug-and-play */
2911d5ac70f0Sopenharmony_ci
2912d5ac70f0Sopenharmony_ci	if (env)
2913d5ac70f0Sopenharmony_ci		snprintf(filename, sizeof(filename), "%s/conf.virt.d", env);
2914d5ac70f0Sopenharmony_ci	else
2915d5ac70f0Sopenharmony_ci		snprintf(filename, sizeof(filename), "%s/ucm2/conf.virt.d",
2916d5ac70f0Sopenharmony_ci			 snd_config_topdir());
2917d5ac70f0Sopenharmony_ci
2918d5ac70f0Sopenharmony_ci#if defined(_GNU_SOURCE) && !defined(__NetBSD__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__) && !defined(__sun) && !defined(__ANDROID__)
2919d5ac70f0Sopenharmony_ci#define SORTFUNC	versionsort64
2920d5ac70f0Sopenharmony_ci#else
2921d5ac70f0Sopenharmony_ci#define SORTFUNC	alphasort64
2922d5ac70f0Sopenharmony_ci#endif
2923d5ac70f0Sopenharmony_ci	err = scandir64(filename, &namelist, filename_filter, SORTFUNC);
2924d5ac70f0Sopenharmony_ci	if (err < 0) {
2925d5ac70f0Sopenharmony_ci		err = -errno;
2926d5ac70f0Sopenharmony_ci		uc_error("error: could not scan directory %s: %s",
2927d5ac70f0Sopenharmony_ci				filename, strerror(-err));
2928d5ac70f0Sopenharmony_ci		return err;
2929d5ac70f0Sopenharmony_ci	}
2930d5ac70f0Sopenharmony_ci	cnt = err;
2931d5ac70f0Sopenharmony_ci
2932d5ac70f0Sopenharmony_ci	dfl[0] = '\0';
2933d5ac70f0Sopenharmony_ci	if (strlen(filename) + 8 < sizeof(filename)) {
2934d5ac70f0Sopenharmony_ci		strcat(filename, "/default");
2935d5ac70f0Sopenharmony_ci		ss = readlink(filename, dfl, sizeof(dfl)-1);
2936d5ac70f0Sopenharmony_ci		if (ss >= 0) {
2937d5ac70f0Sopenharmony_ci			dfl[ss] = '\0';
2938d5ac70f0Sopenharmony_ci			dfl[sizeof(dfl)-1] = '\0';
2939d5ac70f0Sopenharmony_ci			if (dfl[0] && dfl[strlen(dfl)-1] == '/')
2940d5ac70f0Sopenharmony_ci				dfl[strlen(dfl)-1] = '\0';
2941d5ac70f0Sopenharmony_ci		} else {
2942d5ac70f0Sopenharmony_ci			dfl[0] = '\0';
2943d5ac70f0Sopenharmony_ci		}
2944d5ac70f0Sopenharmony_ci	}
2945d5ac70f0Sopenharmony_ci
2946d5ac70f0Sopenharmony_ci	j = 0;
2947d5ac70f0Sopenharmony_ci	list = calloc(1, (cards + cnt) * 2 * sizeof(char *));
2948d5ac70f0Sopenharmony_ci	if (list == NULL) {
2949d5ac70f0Sopenharmony_ci		err = -ENOMEM;
2950d5ac70f0Sopenharmony_ci		goto __err;
2951d5ac70f0Sopenharmony_ci	}
2952d5ac70f0Sopenharmony_ci
2953d5ac70f0Sopenharmony_ci	i = -1;
2954d5ac70f0Sopenharmony_ci	while (j / 2 < cards) {
2955d5ac70f0Sopenharmony_ci		err = snd_card_next(&i);
2956d5ac70f0Sopenharmony_ci		if (err < 0)
2957d5ac70f0Sopenharmony_ci			goto __err;
2958d5ac70f0Sopenharmony_ci		if (i < 0)
2959d5ac70f0Sopenharmony_ci			break;
2960d5ac70f0Sopenharmony_ci		snprintf(fn, sizeof(fn), "-hw:%d", i);
2961d5ac70f0Sopenharmony_ci		err = snd_use_case_mgr_open(&uc_mgr, fn);
2962d5ac70f0Sopenharmony_ci		if (err == -ENOENT || err == -ENXIO)
2963d5ac70f0Sopenharmony_ci			continue;
2964d5ac70f0Sopenharmony_ci		if (err < 0) {
2965d5ac70f0Sopenharmony_ci			uc_error("Unable to open '%s': %s", fn, snd_strerror(err));
2966d5ac70f0Sopenharmony_ci			goto __err;
2967d5ac70f0Sopenharmony_ci		}
2968d5ac70f0Sopenharmony_ci		err = snd_use_case_get(uc_mgr, "comment", (const char **)&s);
2969d5ac70f0Sopenharmony_ci		if (err < 0) {
2970d5ac70f0Sopenharmony_ci			err = snd_card_get_longname(i, &s);
2971d5ac70f0Sopenharmony_ci			if (err < 0)
2972d5ac70f0Sopenharmony_ci				goto __err;
2973d5ac70f0Sopenharmony_ci		}
2974d5ac70f0Sopenharmony_ci		snd_use_case_mgr_close(uc_mgr);
2975d5ac70f0Sopenharmony_ci		list[j] = strdup(fn + 1);
2976d5ac70f0Sopenharmony_ci		if (list[j] == NULL) {
2977d5ac70f0Sopenharmony_ci			free(s);
2978d5ac70f0Sopenharmony_ci			err = -ENOMEM;
2979d5ac70f0Sopenharmony_ci			goto __err;
2980d5ac70f0Sopenharmony_ci		}
2981d5ac70f0Sopenharmony_ci		list[j + 1] = s;
2982d5ac70f0Sopenharmony_ci		j += 2;
2983d5ac70f0Sopenharmony_ci	}
2984d5ac70f0Sopenharmony_ci
2985d5ac70f0Sopenharmony_ci	for (i = 0; i < cnt; i++) {
2986d5ac70f0Sopenharmony_ci
2987d5ac70f0Sopenharmony_ci		d_name = namelist[i]->d_name;
2988d5ac70f0Sopenharmony_ci
2989d5ac70f0Sopenharmony_ci		snprintf(fn, sizeof(fn), "%s.conf", d_name);
2990d5ac70f0Sopenharmony_ci		ucm_filename(filename, sizeof(filename), 2, d_name, fn);
2991d5ac70f0Sopenharmony_ci#ifdef HAVE_EACCESS
2992d5ac70f0Sopenharmony_ci		if (eaccess(filename, R_OK))
2993d5ac70f0Sopenharmony_ci#else
2994d5ac70f0Sopenharmony_ci		if (access(filename, R_OK))
2995d5ac70f0Sopenharmony_ci#endif
2996d5ac70f0Sopenharmony_ci			continue;
2997d5ac70f0Sopenharmony_ci
2998d5ac70f0Sopenharmony_ci		err = uc_mgr_config_load(2, filename, &cfg);
2999d5ac70f0Sopenharmony_ci		if (err < 0)
3000d5ac70f0Sopenharmony_ci			goto __err;
3001d5ac70f0Sopenharmony_ci		err = snd_config_search(cfg, "Syntax", &c);
3002d5ac70f0Sopenharmony_ci		if (err < 0) {
3003d5ac70f0Sopenharmony_ci			uc_error("Syntax field not found in %s", d_name);
3004d5ac70f0Sopenharmony_ci			snd_config_delete(cfg);
3005d5ac70f0Sopenharmony_ci			continue;
3006d5ac70f0Sopenharmony_ci		}
3007d5ac70f0Sopenharmony_ci		err = snd_config_get_integer(c, &l);
3008d5ac70f0Sopenharmony_ci		if (err < 0) {
3009d5ac70f0Sopenharmony_ci			uc_error("Syntax field is invalid in %s", d_name);
3010d5ac70f0Sopenharmony_ci			snd_config_delete(cfg);
3011d5ac70f0Sopenharmony_ci			goto __err;
3012d5ac70f0Sopenharmony_ci		}
3013d5ac70f0Sopenharmony_ci		if (l < 2 || l > SYNTAX_VERSION_MAX) {
3014d5ac70f0Sopenharmony_ci			uc_error("Incompatible syntax %d in %s", l, d_name);
3015d5ac70f0Sopenharmony_ci			snd_config_delete(cfg);
3016d5ac70f0Sopenharmony_ci			goto __err;
3017d5ac70f0Sopenharmony_ci		}
3018d5ac70f0Sopenharmony_ci		err = snd_config_search(cfg, "Comment", &c);
3019d5ac70f0Sopenharmony_ci		if (err >= 0) {
3020d5ac70f0Sopenharmony_ci			err = parse_string(c, (char **)&list[j+1]);
3021d5ac70f0Sopenharmony_ci			if (err < 0) {
3022d5ac70f0Sopenharmony_ci				snd_config_delete(cfg);
3023d5ac70f0Sopenharmony_ci				goto __err;
3024d5ac70f0Sopenharmony_ci			}
3025d5ac70f0Sopenharmony_ci		}
3026d5ac70f0Sopenharmony_ci		snd_config_delete(cfg);
3027d5ac70f0Sopenharmony_ci		list[j] = strdup(d_name);
3028d5ac70f0Sopenharmony_ci		if (list[j] == NULL) {
3029d5ac70f0Sopenharmony_ci			err = -ENOMEM;
3030d5ac70f0Sopenharmony_ci			goto __err;
3031d5ac70f0Sopenharmony_ci		}
3032d5ac70f0Sopenharmony_ci		if (strcmp(dfl, list[j]) == 0) {
3033d5ac70f0Sopenharmony_ci			/* default to top */
3034d5ac70f0Sopenharmony_ci			const char *save1 = list[j];
3035d5ac70f0Sopenharmony_ci			const char *save2 = list[j + 1];
3036d5ac70f0Sopenharmony_ci			memmove(list + 2, list, j * sizeof(char *));
3037d5ac70f0Sopenharmony_ci			list[0] = save1;
3038d5ac70f0Sopenharmony_ci			list[1] = save2;
3039d5ac70f0Sopenharmony_ci		}
3040d5ac70f0Sopenharmony_ci		j += 2;
3041d5ac70f0Sopenharmony_ci	}
3042d5ac70f0Sopenharmony_ci	err = 0;
3043d5ac70f0Sopenharmony_ci
3044d5ac70f0Sopenharmony_ci      __err:
3045d5ac70f0Sopenharmony_ci	for (i = 0; i < cnt; i++)
3046d5ac70f0Sopenharmony_ci		free(namelist[i]);
3047d5ac70f0Sopenharmony_ci	free(namelist);
3048d5ac70f0Sopenharmony_ci	if (err < 0) {
3049d5ac70f0Sopenharmony_ci		for (i = 0; i < j; i++) {
3050d5ac70f0Sopenharmony_ci			free((void *)list[i * 2]);
3051d5ac70f0Sopenharmony_ci			free((void *)list[i * 2 + 1]);
3052d5ac70f0Sopenharmony_ci		}
3053d5ac70f0Sopenharmony_ci		free(list);
3054d5ac70f0Sopenharmony_ci		return err;
3055d5ac70f0Sopenharmony_ci	}
3056d5ac70f0Sopenharmony_ci
3057d5ac70f0Sopenharmony_ci	*_list = list;
3058d5ac70f0Sopenharmony_ci	return j;
3059d5ac70f0Sopenharmony_ci}
3060