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