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