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