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