]> git.alsa-project.org Git - alsa-lib.git/blob - src/ucm/parser.c
fdd39902a1e39aa14f1c2171add0566029291210
[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 <ctype.h>
38 #include <limits.h>
39
40 static int filename_filter(const struct dirent64 *dirent);
41
42 static int parse_sequence(snd_use_case_mgr_t *uc_mgr,
43                           struct list_head *base,
44                           snd_config_t *cfg);
45
46 /*
47  * compose the absolute ucm filename
48  */
49 static int ucm_filename(char *fn, size_t fn_len, long version,
50                          const char *dir, const char *file)
51 {
52         const char *env = getenv(version > 1 ? ALSA_CONFIG_UCM2_VAR : ALSA_CONFIG_UCM_VAR);
53
54         if (file[0] == '/')
55                 file++;
56         if (snd_relative_path_check(file) < 0 ||
57             (dir && snd_relative_path_check(dir) < 0)) {
58                 snd_error(UCM, "config file path '%s%s%s' escapes the configuration directory",
59                           dir ?: "", dir ? "/" : "", file);
60                 return -EINVAL;
61         }
62         if (env == NULL)
63                 snprintf(fn, fn_len, "%s/%s/%s%s%s",
64                          snd_config_topdir(), version > 1 ? "ucm2" : "ucm",
65                          dir ?: "", dir ? "/" : "", file);
66         else
67                 snprintf(fn, fn_len, "%s/%s%s%s",
68                          env, dir ?: "", dir ? "/" : "", file);
69         return 0;
70 }
71
72 /*
73  *
74  */
75 int uc_mgr_config_load_file(snd_use_case_mgr_t *uc_mgr,
76                              const char *file, snd_config_t **cfg, bool optional)
77 {
78         char filename[PATH_MAX];
79         int err;
80
81         err = ucm_filename(filename, sizeof(filename), uc_mgr->conf_format,
82                            file[0] == '/' ? NULL : uc_mgr->conf_dir_name,
83                            file);
84         if (err < 0)
85                 return err;
86         err = uc_mgr_config_load(uc_mgr->conf_format, filename, cfg, optional);
87         if (err < 0) {
88                 if (!optional || (err != -ENOENT && err != -EACCES))
89                         snd_error(UCM, "failed to open file %s: %d", filename, err);
90                 return err;
91         }
92         return 0;
93 }
94
95 /*
96  * Replace mallocated string
97  */
98 static char *replace_string(char **dst, const char *value)
99 {
100         free(*dst);
101         *dst = value ? strdup(value) : NULL;
102         return *dst;
103 }
104
105 /*
106  * Parse string
107  */
108 static int parse_string(snd_config_t *n, char **res)
109 {
110         int err;
111
112         err = snd_config_get_string(n, (const char **)res);
113         if (err < 0)
114                 return err;
115         *res = strdup(*res);
116         if (*res == NULL)
117                 return -ENOMEM;
118         return 0;
119 }
120
121 /*
122  * Parse string and substitute
123  */
124 static int parse_string_substitute(snd_use_case_mgr_t *uc_mgr,
125                             snd_config_t *n, char **res)
126 {
127         const char *str;
128         char *s;
129         int err;
130
131         err = snd_config_get_string(n, &str);
132         if (err < 0)
133                 return err;
134         err = uc_mgr_get_substituted_value(uc_mgr, &s, str);
135         if (err >= 0)
136                 *res = s;
137         return err;
138 }
139
140 /*
141  * Parse string and substitute
142  */
143 static int parse_string_substitute3(snd_use_case_mgr_t *uc_mgr,
144                              snd_config_t *n, char **res)
145 {
146         if (uc_mgr->conf_format < 3)
147                 return parse_string(n, res);
148         return parse_string_substitute(uc_mgr, n, res);
149 }
150
151 /*
152  * Parse integer with substitution
153  */
154 static int parse_integer_substitute(snd_use_case_mgr_t *uc_mgr,
155                              snd_config_t *n, long *res)
156 {
157         char *s1, *s2;
158         int err;
159
160         err = snd_config_get_ascii(n, &s1);
161         if (err < 0)
162                 return err;
163         err = uc_mgr_get_substituted_value(uc_mgr, &s2, s1);
164         if (err >= 0)
165                 err = safe_strtol(s2, res);
166         free(s2);
167         free(s1);
168         return err;
169 }
170
171 /*
172  * Parse integer with substitution
173  */
174 static int parse_integer_substitute3(snd_use_case_mgr_t *uc_mgr,
175                               snd_config_t *n, long *res)
176 {
177         char *s1, *s2;
178         int err;
179
180         err = snd_config_get_ascii(n, &s1);
181         if (err < 0)
182                 return err;
183         if (uc_mgr->conf_format < 3)
184                 s2 = s1;
185         else
186                 err = uc_mgr_get_substituted_value(uc_mgr, &s2, s1);
187         if (err >= 0)
188                 err = safe_strtol(s2, res);
189         if (s1 != s2)
190                 free(s2);
191         free(s1);
192         return err;
193 }
194
195 /*
196  * Parse safe ID
197  */
198 static int parse_is_name_safe(const char *name)
199 {
200         if (strchr(name, '.')) {
201                 snd_error(UCM, "char '.' not allowed in '%s'", name);
202                 return 0;
203         }
204         return 1;
205 }
206
207 static int get_string3(snd_use_case_mgr_t *uc_mgr, const char *s1, char **s)
208 {
209         if (uc_mgr->conf_format < 3) {
210                 *s = strdup(s1);
211                 if (*s == NULL)
212                         return -ENOMEM;
213                 return 0;
214         }
215         return uc_mgr_get_substituted_value(uc_mgr, s, s1);
216 }
217
218 static int parse_get_safe_name(snd_use_case_mgr_t *uc_mgr, snd_config_t *n,
219                         const char *alt, char **name)
220 {
221         const char *id;
222         int err;
223
224         if (alt) {
225                 id = alt;
226         } else {
227                 err = snd_config_get_id(n, &id);
228                 if (err < 0)
229                         return err;
230         }
231         err = get_string3(uc_mgr, id, name);
232         if (err < 0)
233                 return err;
234         if (!parse_is_name_safe(*name)) {
235                 free(*name);
236                 return -EINVAL;
237         }
238         return 0;
239 }
240
241 /*
242  * Parse device index from device name
243  * According to use-case.h specification, device names can have numeric suffixes
244  * like HDMI1, HDMI2, or "Line 1", "Line 2".
245  * This function extracts the index and modifies the name to contain only the base.
246  */
247 static int parse_device_index(char **name, int *index)
248 {
249         char *p, *num_start;
250         long idx;
251         size_t len;
252         int err;
253
254         if (!name || !*name || !index)
255                 return -EINVAL;
256
257         len = strlen(*name);
258         if (len == 0)
259                 return -EINVAL;
260
261         /* Start from the end and find where digits begin */
262         p = *name + len - 1;
263
264         /* Skip trailing digits */
265         while (p > *name && isdigit(*p))
266                 p--;
267
268         /* If no digits found at the end, index is 0 (no index) */
269         if (p == *name + len - 1) {
270                 *index = 0;
271                 return 0;
272         }
273
274         /* Move to first digit */
275         p++;
276
277         /* Check if there's an optional space before the number */
278         if (p > *name && *(p - 1) == ' ')
279                 p--;
280
281         /* Parse the index */
282         num_start = *p == ' ' ? p + 1 : p;
283         err = safe_strtol(num_start, &idx);
284         if (err < 0) {
285                 /* No valid number found */
286                 *index = 0;
287                 return 0;
288         }
289
290         *index = (int)idx;
291
292         /* Truncate the name to remove the index part */
293         if (*p == ' ')
294                 *p = '\0';  /* Remove space and number */
295         else if (p > *name)
296                 *p = '\0';  /* Remove number only */
297
298         return 0;
299 }
300
301 /*
302  * Handle 'Error' configuration node.
303  */
304 static int error_node(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
305 {
306         int err;
307         char *s;
308
309         err = parse_string_substitute3(uc_mgr, cfg, &s);
310         if (err < 0) {
311                 snd_error(UCM, "failed to get Error string");
312                 return err;
313         }
314         if (!uc_mgr->suppress_nodev_errors)
315                 snd_error(UCM, "%s", s);
316         free(s);
317         return -ENXIO;
318 }
319
320 /*
321  *
322  */
323 static int parse_syntax_field(snd_use_case_mgr_t *uc_mgr,
324                               snd_config_t *cfg, const char *filename)
325 {
326         snd_config_t *n;
327         long l;
328         int err;
329
330         err = snd_config_search(cfg, "Syntax", &n);
331         if (err < 0) {
332                 snd_error(UCM, "Syntax field not found in %s", filename);
333                 return -EINVAL;
334         }
335         err = snd_config_get_integer(n, &l);
336         if (err < 0) {
337                 snd_error(UCM, "Syntax field is invalid in %s", filename);
338                 return err;
339         }
340         if (l < 2 || l > SYNTAX_VERSION_MAX) {
341                 snd_error(UCM, "Incompatible syntax %ld in %s", l, filename);
342                 return -EINVAL;
343         }
344         /* delete this field to optimize strcmp() call in the parsing loop */
345         snd_config_delete(n);
346         uc_mgr->conf_format = l;
347         return l;
348 }
349
350 /*
351  * Evaluate variable regex definitions (in-place delete)
352  */
353 static int evaluate_regex(snd_use_case_mgr_t *uc_mgr,
354                           snd_config_t *cfg)
355 {
356         snd_config_iterator_t i, next;
357         snd_config_t *d, *n;
358         const char *id;
359         int err;
360
361         err = snd_config_search(cfg, "DefineRegex", &d);
362         if (err == -ENOENT)
363                 return 1;
364         if (err < 0)
365                 return err;
366
367         if (snd_config_get_type(d) != SND_CONFIG_TYPE_COMPOUND) {
368                 snd_error(UCM, "compound type expected for DefineRegex");
369                 return -EINVAL;
370         }
371
372         if (uc_mgr->conf_format < 3) {
373                 snd_error(UCM, "DefineRegex is supported in v3+ syntax");
374                 return -EINVAL;
375         }
376
377         snd_config_for_each(i, next, d) {
378                 n = snd_config_iterator_entry(i);
379                 err = snd_config_get_id(n, &id);
380                 if (err < 0)
381                         return err;
382                 if (id[0] == '@') {
383                         snd_error(UCM, "value names starting with '@' are reserved for application variables");
384                         return -EINVAL;
385                 }
386                 err = uc_mgr_define_regex(uc_mgr, id, n);
387                 if (err < 0)
388                         return err;
389         }
390
391         snd_config_delete(d);
392         return 0;
393 }
394
395 /*
396  * Evaluate variable definitions (in-place delete)
397  */
398 static int evaluate_define(snd_use_case_mgr_t *uc_mgr,
399                            snd_config_t *cfg)
400 {
401         snd_config_iterator_t i, next;
402         snd_config_t *d, *n;
403         const char *id;
404         char *var, *s, *sid;
405         int err;
406
407         err = snd_config_search(cfg, "Define", &d);
408         if (err == -ENOENT)
409                 return evaluate_regex(uc_mgr, cfg);
410         if (err < 0)
411                 return err;
412
413         if (snd_config_get_type(d) != SND_CONFIG_TYPE_COMPOUND) {
414                 snd_error(UCM, "compound type expected for Define");
415                 return -EINVAL;
416         }
417
418         if (uc_mgr->conf_format < 3) {
419                 snd_error(UCM, "Define is supported in v3+ syntax");
420                 return -EINVAL;
421         }
422
423         snd_config_for_each(i, next, d) {
424                 n = snd_config_iterator_entry(i);
425                 err = snd_config_get_id(n, &id);
426                 if (err < 0)
427                         return err;
428                 err = snd_config_get_ascii(n, &var);
429                 if (err < 0)
430                         return err;
431                 err = uc_mgr_get_substituted_value(uc_mgr, &s, var);
432                 free(var);
433                 if (err < 0)
434                         return err;
435                 if (id[0] == '@') {
436                         free(s);
437                         snd_error(UCM, "value names starting with '@' are reserved for application variables");
438                         return -EINVAL;
439                 }
440                 sid = (char *)id;
441                 if (uc_mgr->conf_format >= 9) {
442                         err = uc_mgr_get_substituted_value(uc_mgr, &sid, id);
443                         if (err < 0) {
444                                 free(s);
445                                 return err;
446                         }
447                 }
448                 err = uc_mgr_set_variable(uc_mgr, sid, s);
449                 free(s);
450                 if (id != sid)
451                         free(sid);
452                 if (err < 0)
453                         return err;
454         }
455
456         snd_config_delete(d);
457
458         return evaluate_regex(uc_mgr, cfg);
459 }
460
461 /*
462  * Evaluate macro definitions (in-place delete)
463  */
464 static int evaluate_define_macro(snd_use_case_mgr_t *uc_mgr,
465                                  snd_config_t *cfg)
466 {
467         snd_config_t *d;
468         int err;
469
470         err = snd_config_search(cfg, "DefineMacro", &d);
471         if (err == -ENOENT)
472                 return 1;
473         if (err < 0)
474                 return err;
475
476         if (snd_config_get_type(d) != SND_CONFIG_TYPE_COMPOUND) {
477                 snd_error(UCM, "compound type expected for DefineMacro");
478                 return -EINVAL;
479         }
480
481         if (uc_mgr->conf_format < 6) {
482                 snd_error(UCM, "DefineMacro is supported in v6+ syntax");
483                 return -EINVAL;
484         }
485
486         err = snd_config_merge(uc_mgr->macros, d, 0);
487         if (err < 0)
488                 return err;
489
490         return 0;
491 }
492
493 static int evaluate_macro1(snd_use_case_mgr_t *uc_mgr,
494                            snd_config_t *dst,
495                            snd_config_t *args)
496 {
497         snd_config_iterator_t i, next;
498         snd_config_t *m, *mc, *a, *n;
499         const char *mid, *id;
500         char name[128], *var, *var2;
501         const char *s;
502         int err;
503
504         err = snd_config_get_id(args, &mid);
505         if (err < 0)
506                 return err;
507         err = snd_config_search(uc_mgr->macros, mid, &m);
508         if (err < 0) {
509                 snd_error(UCM, "Macro '%s' is not defined", mid);
510                 return err;
511         }
512
513         a = args;
514         if (snd_config_get_type(args) == SND_CONFIG_TYPE_STRING) {
515                 err = snd_config_get_string(args, &s);
516                 if (err < 0)
517                         return err;
518                 if (uc_mgr->conf_format < 9) {
519                         err = snd_config_load_string(&a, s, 0);
520                 } else {
521                         err = uc_mgr_get_substituted_value(uc_mgr, &var2, s);
522                         if (err >= 0) {
523                                 err = snd_config_load_string(&a, var2, 0);
524                                 free(var2);
525                         }
526                 }
527                 if (err < 0)
528                         return err;
529         } else if (snd_config_get_type(args) != SND_CONFIG_TYPE_COMPOUND) {
530                 return -EINVAL;
531         }
532
533         /* set arguments */
534         snd_config_for_each(i, next, a) {
535                 n = snd_config_iterator_entry(i);
536                 err = snd_config_get_id(n, &id);
537                 if (err < 0)
538                         goto __err_path;
539                 snprintf(name, sizeof(name), "__%s", id);
540                 if (uc_mgr_get_variable(uc_mgr, name, false)) {
541                         snd_error(UCM, "Macro argument '%s' is already defined", name);
542                         goto __err_path;
543                 }
544                 err = snd_config_get_ascii(n, &var);
545                 if (err < 0)
546                         goto __err_path;
547                 if (uc_mgr->conf_format < 7) {
548                         err = uc_mgr_set_variable(uc_mgr, name, var);
549                         free(var);
550                 } else {
551                         err = uc_mgr_get_substituted_value(uc_mgr, &var2, var);
552                         free(var);
553                         if (err >= 0) {
554                                 err = uc_mgr_set_variable(uc_mgr, name, var2);
555                                 free(var2);
556                         }
557                 }
558                 if (err < 0)
559                         goto __err_path;
560         }
561
562         /* merge + substitute variables */
563         err = snd_config_copy(&mc, m);
564         if (err < 0)
565                 goto __err_path;
566         err = uc_mgr_evaluate_inplace(uc_mgr, mc);
567         if (err < 0) {
568                 snd_config_delete(mc);
569                 goto __err_path;
570         }
571         err = uc_mgr_config_tree_merge(uc_mgr, dst, mc, NULL, NULL);
572         snd_config_delete(mc);
573
574         /* delete arguments */
575         snd_config_for_each(i, next, a) {
576                 n = snd_config_iterator_entry(i);
577                 err = snd_config_get_id(n, &id);
578                 if (err < 0)
579                         goto __err_path;
580                 snprintf(name, sizeof(name), "__%s", id);
581                 err = uc_mgr_delete_variable(uc_mgr, name);
582                 if (err < 0)
583                         goto __err_path;
584         }
585
586 __err_path:
587         if (a != args)
588                 snd_config_delete(a);
589         return err;
590 }
591
592 /*
593  * Evaluate macro definitions and instances (in-place delete)
594  */
595 static int evaluate_macro(snd_use_case_mgr_t *uc_mgr,
596                           snd_config_t *cfg)
597 {
598         snd_config_iterator_t i, i2, next, next2;
599         snd_config_t *d, *n, *n2;
600         int err, ret;
601
602         ret = evaluate_define_macro(uc_mgr, cfg);
603         if (ret < 0)
604                 return ret;
605
606         err = snd_config_search(cfg, "Macro", &d);
607         if (err == -ENOENT)
608                 return ret;
609         if (err < 0)
610                 return err;
611
612         if (snd_config_get_type(d) != SND_CONFIG_TYPE_COMPOUND) {
613                 snd_error(UCM, "compound type expected for DefineMacro");
614                 return -EINVAL;
615         }
616
617         if (uc_mgr->conf_format < 6) {
618                 snd_error(UCM, "Macro is supported in v6+ syntax");
619                 return -EINVAL;
620         }
621
622         snd_config_for_each(i, next, d) {
623                 n = snd_config_iterator_entry(i);
624                 if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
625                         const char *id;
626                         if (snd_config_get_id(n, &id))
627                                 id = "";
628                         snd_error(UCM, "compound type expected for Macro.%s", id);
629                         return -EINVAL;
630                 }
631                 snd_config_for_each(i2, next2, n) {
632                         n2 = snd_config_iterator_entry(i2);
633                         err = evaluate_macro1(uc_mgr, cfg, n2);
634                         if (err < 0)
635                                 return err;
636                 }
637         }
638
639         snd_config_delete(d);
640
641         return 0;
642 }
643
644 /*
645  * Evaluate include (in-place)
646  */
647 static int evaluate_include(snd_use_case_mgr_t *uc_mgr,
648                             snd_config_t *cfg)
649 {
650         snd_config_t *n;
651         int err;
652
653         err = snd_config_search(cfg, "Include", &n);
654         if (err == -ENOENT)
655                 return 1;
656         if (err < 0)
657                 return err;
658
659         err = uc_mgr_evaluate_include(uc_mgr, cfg, n);
660         snd_config_delete(n);
661         return err;
662 }
663
664 /*
665  * Evaluate condition (in-place)
666  */
667 static int evaluate_condition(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
668 {
669         snd_config_t *n;
670         int err;
671
672         err = snd_config_search(cfg, "If", &n);
673         if (err == -ENOENT)
674                 return 1;
675         if (err < 0)
676                 return err;
677
678         err = uc_mgr_evaluate_condition(uc_mgr, cfg, n);
679         snd_config_delete(n);
680         return err;
681 }
682
683 /*
684  * Evaluate variant (in-place)
685  */
686 static int evaluate_variant(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
687 {
688         snd_config_iterator_t i, next;
689         snd_config_t *n, *c;
690         const char *id;
691         int err;
692
693         err = snd_config_search(cfg, "Variant", &c);
694         if (err == -ENOENT)
695                 return 1;
696         if (err < 0)
697                 return err;
698
699         if (uc_mgr->conf_format < 6) {
700                 snd_error(UCM, "Variant is supported in v6+ syntax");
701                 return -EINVAL;
702         }
703
704         if (uc_mgr->parse_master_section)
705                 return 1;
706
707         if (uc_mgr->parse_variant == NULL)
708                 goto __ret;
709
710         snd_config_for_each(i, next, c) {
711                 n = snd_config_iterator_entry(i);
712
713                 if (snd_config_get_id(n, &id) < 0)
714                         return -EINVAL;
715
716                 if (strcmp(id, uc_mgr->parse_variant))
717                         continue;
718
719                 err = uc_mgr_evaluate_inplace(uc_mgr, n);
720                 if (err < 0)
721                         return err;
722
723                 err = uc_mgr_config_tree_merge(uc_mgr, cfg, n, NULL, NULL);
724                 if (err < 0)
725                         return err;
726                 snd_config_delete(c);
727                 return 0;
728         }
729
730 __ret:
731         snd_config_delete(c);
732         return 1;
733 }
734
735 /*
736  * In-place evaluate
737  */
738 int uc_mgr_evaluate_inplace(snd_use_case_mgr_t *uc_mgr,
739                             snd_config_t *cfg)
740 {
741         long iterations = 10000;
742         int err1 = 0, err2 = 0, err3 = 0, err4 = 0, err5 = 0, err6 = 0;
743
744         while (err1 == 0 || err2 == 0 || err3 == 0 || err4 == 0 || err5 == 0 || err6 == 0) {
745                 if (iterations == 0) {
746                         snd_error(UCM, "Maximal inplace evaluation iterations number reached (recursive references?)");
747                         return -EINVAL;
748                 }
749                 iterations--;
750                 /* variables at first */
751                 err1 = evaluate_define(uc_mgr, cfg);
752                 if (err1 < 0)
753                         return err1;
754                 /* include at second */
755                 err2 = evaluate_include(uc_mgr, cfg);
756                 if (err2 < 0)
757                         return err2;
758                 /* include or macro may define another variables */
759                 /* conditions may depend on them */
760                 if (err2 == 0)
761                         continue;
762                 err3 = evaluate_variant(uc_mgr, cfg);
763                 if (err3 < 0)
764                         return err3;
765                 if (err3 == 0)
766                         continue;
767                 uc_mgr->macro_hops++;
768                 if (uc_mgr->macro_hops > 100) {
769                         snd_error(UCM, "Maximal macro hops reached!");
770                         return -EINVAL;
771                 }
772                 err4 = evaluate_macro(uc_mgr, cfg);
773                 uc_mgr->macro_hops--;
774                 if (err4 < 0)
775                         return err4;
776                 if (err4 == 0)
777                         continue;
778                 err5 = uc_mgr_evaluate_repeat(uc_mgr, cfg);
779                 if (err5 < 0)
780                         return err5;
781                 err6 = evaluate_condition(uc_mgr, cfg);
782                 if (err6 < 0)
783                         return err6;
784         }
785         return 0;
786 }
787
788 /*
789  * Parse one item for alsa-lib config
790  */
791 static int parse_libconfig1(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
792 {
793         snd_config_iterator_t i, next;
794         snd_config_t *n, *config = NULL;
795         const char *id, *file = NULL;
796         bool substfile = false, substconfig = false;
797         int err;
798
799         if (snd_config_get_id(cfg, &id) < 0)
800                 return -EINVAL;
801
802         if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
803                 snd_error(UCM, "compound type expected for %s", id);
804                 return -EINVAL;
805         }
806
807         snd_config_for_each(i, next, cfg) {
808                 n = snd_config_iterator_entry(i);
809
810                 if (snd_config_get_id(n, &id) < 0)
811                         return -EINVAL;
812
813                 if (strcmp(id, "File") == 0 ||
814                     strcmp(id, "SubstiFile") == 0) {
815                         substfile = id[0] == 'S';
816                         err = snd_config_get_string(n, &file);
817                         if (err < 0)
818                                 return err;
819                         continue;
820                 }
821
822                 if (strcmp(id, "Config") == 0 ||
823                     strcmp(id, "SubstiConfig") == 0) {
824                         substconfig = id[0] == 'S';
825                         if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND)
826                                 return -EINVAL;
827                         config = n;
828                         continue;
829                 }
830
831                 snd_error(UCM, "unknown field %s", id);
832                 return -EINVAL;
833         }
834
835         if (file) {
836                 if (substfile) {
837                         snd_config_t *cfg;
838                         err = uc_mgr_config_load_file(uc_mgr, file, &cfg, false);
839                         if (err < 0)
840                                 return err;
841                         err = uc_mgr_substitute_tree(uc_mgr, cfg);
842                         if (err < 0) {
843                                 snd_config_delete(cfg);
844                                 return err;
845                         }
846                         err = snd_config_merge(uc_mgr->local_config, cfg, 0);
847                         if (err < 0) {
848                                 snd_config_delete(cfg);
849                                 return err;
850                         }
851                 } else {
852                         char filename[PATH_MAX];
853
854                         err = ucm_filename(filename, sizeof(filename), uc_mgr->conf_format,
855                                            file[0] == '/' ? NULL : uc_mgr->conf_dir_name,
856                                            file);
857                         if (err < 0)
858                                 return err;
859                         err = uc_mgr_config_load_into(uc_mgr->conf_format, filename, uc_mgr->local_config, false);
860                         if (err < 0)
861                                 return err;
862                 }
863         }
864
865         if (config) {
866                 if (substconfig) {
867                         err = uc_mgr_substitute_tree(uc_mgr, config);
868                         if (err < 0)
869                                 return err;
870                 }
871                 err = snd_config_merge(uc_mgr->local_config, config, 0);
872                 if (err < 0)
873                         return err;
874         }
875
876         return 0;
877 }
878
879 /*
880  * Parse alsa-lib config
881  */
882 static int parse_libconfig(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
883 {
884         snd_config_iterator_t i, next;
885         snd_config_t *n;
886         const char *id;
887         int err;
888
889         if (snd_config_get_id(cfg, &id) < 0)
890                 return -EINVAL;
891
892         if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
893                 snd_error(UCM, "compound type expected for %s", id);
894                 return -EINVAL;
895         }
896
897         snd_config_for_each(i, next, cfg) {
898                 n = snd_config_iterator_entry(i);
899
900                 err = parse_libconfig1(uc_mgr, n);
901                 if (err < 0)
902                         return err;
903         }
904
905         return 0;
906 }
907
908 /*
909  * Parse transition
910  */
911 static int parse_transition(snd_use_case_mgr_t *uc_mgr,
912                             struct list_head *tlist,
913                             snd_config_t *cfg)
914 {
915         struct transition_sequence *tseq;
916         const char *id;
917         snd_config_iterator_t i, next;
918         snd_config_t *n;
919         int err;
920
921         if (snd_config_get_id(cfg, &id) < 0)
922                 return -EINVAL;
923
924         if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
925                 snd_error(UCM, "compound type expected for %s", id);
926                 return -EINVAL;
927         }
928
929         snd_config_for_each(i, next, cfg) {
930                 n = snd_config_iterator_entry(i);
931
932                 if (snd_config_get_id(n, &id) < 0)
933                         return -EINVAL;
934
935                 tseq = calloc(1, sizeof(*tseq));
936                 if (tseq == NULL)
937                         return -ENOMEM;
938                 INIT_LIST_HEAD(&tseq->transition_list);
939
940                 err = get_string3(uc_mgr, id, &tseq->name);
941                 if (err < 0) {
942                         free(tseq);
943                         return err;
944                 }
945
946                 err = parse_sequence(uc_mgr, &tseq->transition_list, n);
947                 if (err < 0) {
948                         uc_mgr_free_transition_element(tseq);
949                         return err;
950                 }
951
952                 list_add(&tseq->list, tlist);
953         }
954         return 0;
955 }
956
957 /*
958  * Parse compound
959  */
960 static int parse_compound(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg,
961           int (*fcn)(snd_use_case_mgr_t *, snd_config_t *, void *, void *),
962           void *data1, void *data2)
963 {
964         const char *id;
965         snd_config_iterator_t i, next;
966         snd_config_t *n;
967         int err;
968
969         if (snd_config_get_id(cfg, &id) < 0)
970                 return -EINVAL;
971
972         if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
973                 snd_error(UCM, "compound type expected for %s", id);
974                 return -EINVAL;
975         }
976         /* parse compound */
977         snd_config_for_each(i, next, cfg) {
978                 n = snd_config_iterator_entry(i);
979
980                 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
981                         snd_error(UCM, "compound type expected for %s, is %d", id, snd_config_get_type(cfg));
982                         return -EINVAL;
983                 }
984
985                 err = fcn(uc_mgr, n, data1, data2);
986                 if (err < 0)
987                         return err;
988         }
989
990         return 0;
991 }
992
993 static int strip_legacy_dev_index(char *name)
994 {
995         char *dot = strchr(name, '.');
996         if (!dot)
997                 return 0;
998         if (dot[1] != '0' || dot[2] != '\0') {
999                 snd_error(UCM, "device name %s contains a '.',"
1000                                " and is not legacy foo.0 format", name);
1001
1002                 return -EINVAL;
1003         }
1004         *dot = '\0';
1005         return 0;
1006 }
1007
1008 /*
1009  * Parse device list
1010  */
1011 static int parse_device_list(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED,
1012                              struct dev_list *dev_list,
1013                              enum dev_list_type type,
1014                              snd_config_t *cfg)
1015 {
1016         struct dev_list_node *sdev;
1017         const char *id;
1018         snd_config_iterator_t i, next;
1019         snd_config_t *n;
1020         int err;
1021
1022         if (dev_list->type != DEVLIST_NONE) {
1023                 snd_error(UCM, "multiple supported or conflicting device lists");
1024
1025                 return -EEXIST;
1026         }
1027
1028         if (snd_config_get_id(cfg, &id) < 0)
1029                 return -EINVAL;
1030
1031         if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
1032                 snd_error(UCM, "compound type expected for %s", id);
1033                 return -EINVAL;
1034         }
1035
1036         snd_config_for_each(i, next, cfg) {
1037                 n = snd_config_iterator_entry(i);
1038
1039                 if (snd_config_get_id(n, &id) < 0)
1040                         return -EINVAL;
1041
1042                 sdev = calloc(1, sizeof(struct dev_list_node));
1043                 if (sdev == NULL)
1044                         return -ENOMEM;
1045                 err = parse_string_substitute3(uc_mgr, n, &sdev->name);
1046                 if (err < 0) {
1047                         free(sdev);
1048                         return err;
1049                 }
1050                 err = strip_legacy_dev_index(sdev->name);
1051                 if (err < 0) {
1052                         free(sdev->name);
1053                         free(sdev);
1054                         return err;
1055                 }
1056                 list_add(&sdev->list, &dev_list->list);
1057         }
1058
1059         dev_list->type = type;
1060
1061         return 0;
1062 }
1063
1064 /* Find a component device by its name, and remove it from machine device
1065  * list.
1066  *
1067  * Component devices are defined by machine components (usually off-soc
1068  * codes or DSP embeded in SoC). Since alsaconf imports their configuration
1069  * files automatically, we don't know which devices are component devices
1070  * until they are referenced by a machine device sequence. So here when we
1071  * find a referenced device, we move it from the machine device list to the
1072  * component device list. Component devices will not be exposed to applications
1073  * by the original API to list devices for backward compatibility. So sound
1074  * servers can only see the machine devices.
1075  */
1076 struct use_case_device *find_component_dev(snd_use_case_mgr_t *uc_mgr,
1077         const char *name)
1078 {
1079         struct list_head *pos, *posdev, *_posdev;
1080         struct use_case_verb *verb;
1081         struct use_case_device *dev;
1082
1083         list_for_each(pos, &uc_mgr->verb_list) {
1084                 verb = list_entry(pos, struct use_case_verb, list);
1085
1086                 /* search in the component device list */
1087                 list_for_each(posdev, &verb->cmpt_device_list) {
1088                         dev = list_entry(posdev, struct use_case_device, list);
1089                         if (!strcmp(dev->name, name))
1090                                 return dev;
1091                 }
1092
1093                 /* search the machine device list */
1094                 list_for_each_safe(posdev, _posdev, &verb->device_list) {
1095                         dev = list_entry(posdev, struct use_case_device, list);
1096                         if (!strcmp(dev->name, name)) {
1097                                 /* find the component device, move it from the
1098                                  * machine device list to the component device
1099                                  * list.
1100                                  */
1101                                 list_del(&dev->list);
1102                                 list_add_tail(&dev->list,
1103                                               &verb->cmpt_device_list);
1104                                 return dev;
1105                         }
1106                 }
1107         }
1108
1109         return NULL;
1110 }
1111
1112 /* parse sequence of a component device
1113  *
1114  * This function will find the component device and mark if its enable or
1115  * disable sequence is needed by its parenet device.
1116  */
1117 static int parse_component_seq(snd_use_case_mgr_t *uc_mgr,
1118                                snd_config_t *n, int enable,
1119                                struct component_sequence *cmpt_seq)
1120 {
1121         char *val;
1122         int err;
1123
1124         err = parse_string_substitute3(uc_mgr, n, &val);
1125         if (err < 0)
1126                 return err;
1127
1128         cmpt_seq->device = find_component_dev(uc_mgr, val);
1129         if (!cmpt_seq->device) {
1130                 snd_error(UCM, "Cannot find component device %s", val);
1131                 free(val);
1132                 return -EINVAL;
1133         }
1134         free(val);
1135
1136         /* Parent needs its enable or disable sequence */
1137         cmpt_seq->enable = enable;
1138
1139         return 0;
1140 }
1141
1142 /*
1143  * Parse sequences.
1144  *
1145  * Sequence controls elements  are in the following form:-
1146  *
1147  * cdev "hw:0"
1148  * cset "element_id_syntax value_syntax"
1149  * usleep time
1150  * exec "any unix command with arguments"
1151  * enadev "component device name"
1152  * disdev "component device name"
1153  *
1154  * e.g.
1155  *      cset "name='Master Playback Switch' 0,0"
1156  *      cset "iface=PCM,name='Disable HDMI',index=1 0"
1157  *      enadev "rt286:Headphones"
1158  *      disdev "rt286:Speaker"
1159  */
1160 static int parse_sequence(snd_use_case_mgr_t *uc_mgr,
1161                           struct list_head *base,
1162                           snd_config_t *cfg)
1163 {
1164         struct sequence_element *curr;
1165         snd_config_iterator_t i, next;
1166         snd_config_t *n;
1167         int err, idx = 0;
1168         const char *cmd = NULL;
1169
1170         if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
1171                 snd_error(UCM, "compound is expected for sequence definition");
1172                 return -EINVAL;
1173         }
1174
1175         snd_config_for_each(i, next, cfg) {
1176                 const char *id;
1177                 idx ^= 1;
1178                 n = snd_config_iterator_entry(i);
1179                 err = snd_config_get_id(n, &id);
1180                 if (err < 0)
1181                         continue;
1182                 if (idx == 1) {
1183                         if (snd_config_get_type(n) != SND_CONFIG_TYPE_STRING) {
1184                                 snd_error(UCM, "string type is expected for sequence command");
1185                                 return -EINVAL;
1186                         }
1187                         err = snd_config_get_string(n, &cmd);
1188                         if (err < 0)
1189                                 return err;
1190                         continue;
1191                 }
1192
1193                 /* alloc new sequence element */
1194                 curr = calloc(1, sizeof(struct sequence_element));
1195                 if (curr == NULL)
1196                         return -ENOMEM;
1197                 list_add_tail(&curr->list, base);
1198
1199                 if (strcmp(cmd, "cdev") == 0) {
1200                         curr->type = SEQUENCE_ELEMENT_TYPE_CDEV;
1201                         err = parse_string_substitute3(uc_mgr, n, &curr->data.cdev);
1202                         if (err < 0) {
1203                                 snd_error(UCM, "cdev requires a string!");
1204                                 return err;
1205                         }
1206                         continue;
1207                 }
1208
1209                 if (strcmp(cmd, "cset") == 0) {
1210                         curr->type = SEQUENCE_ELEMENT_TYPE_CSET;
1211 cset:
1212                         err = parse_string_substitute3(uc_mgr, n, &curr->data.cset);
1213                         if (err < 0) {
1214                                 snd_error(UCM, "%s requires a string!", cmd);
1215                                 return err;
1216                         }
1217                         continue;
1218                 }
1219
1220                 if (strcmp(cmd, "enadev") == 0 ||
1221                     strcmp(cmd, "disdev") == 0) {
1222                         /* need to enable or disable a component device */
1223                         curr->type = SEQUENCE_ELEMENT_TYPE_CMPT_SEQ;
1224                         err = parse_component_seq(uc_mgr, n,
1225                                                 strcmp(cmd, "enadev") == 0,
1226                                                 &curr->data.cmpt_seq);
1227                         if (err < 0) {
1228                                 snd_error(UCM, "%s requires a valid device!", cmd);
1229                                 return err;
1230                         }
1231                         continue;
1232                 }
1233
1234                 if (strcmp(cmd, "enadev2") == 0) {
1235                         curr->type = SEQUENCE_ELEMENT_TYPE_DEV_ENABLE_SEQ;
1236                         goto device;
1237                 }
1238
1239                 if (strcmp(cmd, "disdev2") == 0) {
1240                         curr->type = SEQUENCE_ELEMENT_TYPE_DEV_DISABLE_SEQ;
1241 device:
1242                         err = parse_string_substitute3(uc_mgr, n, &curr->data.device);
1243                         if (err < 0) {
1244                                 snd_error(UCM, "%s requires a valid device!", cmd);
1245                                 return err;
1246                         }
1247                         continue;
1248                 }
1249
1250                 if (strcmp(cmd, "disdevall") == 0) {
1251                         curr->type = SEQUENCE_ELEMENT_TYPE_DEV_DISABLE_ALL;
1252                         continue;
1253                 }
1254
1255                 if (strcmp(cmd, "cset-bin-file") == 0) {
1256                         curr->type = SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE;
1257                         goto cset;
1258                 }
1259
1260                 if (strcmp(cmd, "cset-tlv") == 0) {
1261                         curr->type = SEQUENCE_ELEMENT_TYPE_CSET_TLV;
1262                         goto cset;
1263                 }
1264
1265                 if (strcmp(cmd, "cset-new") == 0) {
1266                         curr->type = SEQUENCE_ELEMENT_TYPE_CSET_NEW;
1267                         goto cset;
1268                 }
1269
1270                 if (strcmp(cmd, "ctl-remove") == 0) {
1271                         curr->type = SEQUENCE_ELEMENT_TYPE_CTL_REMOVE;
1272                         goto cset;
1273                 }
1274
1275                 if (strcmp(cmd, "sysw") == 0) {
1276                         curr->type = SEQUENCE_ELEMENT_TYPE_SYSSET;
1277                         err = parse_string_substitute3(uc_mgr, n, &curr->data.sysw);
1278                         if (err < 0) {
1279                                 snd_error(UCM, "sysw requires a string!");
1280                                 return err;
1281                         }
1282                         continue;
1283                 }
1284
1285                 if (strcmp(cmd, "usleep") == 0) {
1286                         curr->type = SEQUENCE_ELEMENT_TYPE_SLEEP;
1287                         err = parse_integer_substitute3(uc_mgr, n, &curr->data.sleep);
1288                         if (err < 0) {
1289                                 snd_error(UCM, "usleep requires integer!");
1290                                 return err;
1291                         }
1292                         continue;
1293                 }
1294
1295                 if (strcmp(cmd, "msleep") == 0) {
1296                         curr->type = SEQUENCE_ELEMENT_TYPE_SLEEP;
1297                         err = parse_integer_substitute3(uc_mgr, n, &curr->data.sleep);
1298                         if (err < 0) {
1299                                 snd_error(UCM, "msleep requires integer!");
1300                                 return err;
1301                         }
1302                         curr->data.sleep *= 1000L;
1303                         continue;
1304                 }
1305
1306                 if (strcmp(cmd, "exec") == 0) {
1307                         curr->type = SEQUENCE_ELEMENT_TYPE_EXEC;
1308 exec:
1309                         err = parse_string_substitute3(uc_mgr, n, &curr->data.exec);
1310                         if (err < 0) {
1311                                 snd_error(UCM, "exec requires a string!");
1312                                 return err;
1313                         }
1314                         continue;
1315                 }
1316
1317                 if (strcmp(cmd, "shell") == 0) {
1318                         curr->type = SEQUENCE_ELEMENT_TYPE_SHELL;
1319                         goto exec;
1320                 }
1321
1322                 if (strcmp(cmd, "cfg-save") == 0) {
1323                         curr->type = SEQUENCE_ELEMENT_TYPE_CFGSAVE;
1324                         err = parse_string_substitute3(uc_mgr, n, &curr->data.cfgsave);
1325                         if (err < 0) {
1326                                 snd_error(UCM, "sysw requires a string!");
1327                                 return err;
1328                         }
1329                         continue;
1330                 }
1331
1332                 if (strcmp(cmd, "comment") == 0)
1333                         goto skip;
1334
1335                 snd_error(UCM, "sequence command '%s' is ignored", cmd);
1336
1337 skip:
1338                 list_del(&curr->list);
1339                 uc_mgr_free_sequence_element(curr);
1340         }
1341
1342         return 0;
1343 }
1344
1345 /*
1346  *
1347  */
1348 int uc_mgr_add_value(struct list_head *base, const char *key, char *val)
1349 {
1350         struct ucm_value *curr;
1351
1352         curr = calloc(1, sizeof(struct ucm_value));
1353         if (curr == NULL)
1354                 return -ENOMEM;
1355         curr->name = strdup(key);
1356         if (curr->name == NULL) {
1357                 free(curr);
1358                 return -ENOMEM;
1359         }
1360         list_add_tail(&curr->list, base);
1361         curr->data = val;
1362         return 0;
1363 }
1364
1365 /*
1366  * Parse values.
1367  *
1368  * Parse values describing PCM, control/mixer settings and stream parameters.
1369  *
1370  * Value {
1371  *   TQ Voice
1372  *   CapturePCM "hw:1"
1373  *   PlaybackVolume "name='Master Playback Volume',index=2"
1374  *   PlaybackSwitch "name='Master Playback Switch',index=2"
1375  * }
1376  */
1377 static int parse_value(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED,
1378                           struct list_head *base,
1379                           snd_config_t *cfg)
1380 {
1381         snd_config_iterator_t i, next;
1382         snd_config_t *n;
1383         char *s;
1384         snd_config_type_t type;
1385         int err;
1386
1387         if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
1388                 snd_error(UCM, "compound is expected for value definition");
1389                 return -EINVAL;
1390         }
1391
1392         /* in-place evaluation */
1393         err = uc_mgr_evaluate_inplace(uc_mgr, cfg);
1394         if (err < 0)
1395                 return err;
1396
1397         snd_config_for_each(i, next, cfg) {
1398                 const char *id;
1399                 n = snd_config_iterator_entry(i);
1400                 err = snd_config_get_id(n, &id);
1401                 if (err < 0)
1402                         continue;
1403
1404                 type = snd_config_get_type(n);
1405                 switch (type) {
1406                 case SND_CONFIG_TYPE_INTEGER:
1407                 case SND_CONFIG_TYPE_INTEGER64:
1408                 case SND_CONFIG_TYPE_REAL:
1409                         err = snd_config_get_ascii(n, &s);
1410                         if (err < 0) {
1411                                 snd_error(UCM, "unable to parse value for id '%s': %s!", id, snd_strerror(err));
1412                                 return err;
1413                         }
1414                         break;
1415                 case SND_CONFIG_TYPE_STRING:
1416                         err = parse_string_substitute(uc_mgr, n, &s);
1417                         if (err < 0) {
1418                                 snd_error(UCM, "unable to parse a string for id '%s'!", id);
1419                                 return err;
1420                         }
1421                         break;
1422                 default:
1423                         snd_error(UCM, "invalid type %i in Value compound '%s'", type, id);
1424                         return -EINVAL;
1425                 }
1426                 err = uc_mgr_add_value(base, id, s);
1427                 if (err < 0) {
1428                         free(s);
1429                         return err;
1430                 }
1431         }
1432
1433         return 0;
1434 }
1435
1436 /*
1437  * Parse Modifier Use cases
1438  *
1439  * # Each modifier is described in new section. N modifiers are allowed
1440  * SectionModifier."Capture Voice" {
1441  *
1442  *      Comment "Record voice call"
1443  *
1444  *      SupportedDevice [
1445  *              "x"
1446  *              "y"
1447  *      ]
1448  *
1449  *      ConflictingDevice [
1450  *              "x"
1451  *              "y"
1452  *      ]
1453  *
1454  *      EnableSequence [
1455  *              ....
1456  *      ]
1457  *
1458  *      DisableSequence [
1459  *              ...
1460  *      ]
1461  *
1462  *      TransitionSequence."ToModifierName" [
1463  *              ...
1464  *      ]
1465  *
1466  *      # Optional TQ and ALSA PCMs
1467  *      Value {
1468  *              TQ Voice
1469  *              CapturePCM "hw:1"
1470  *              PlaybackVolume "name='Master Playback Volume',index=2"
1471  *              PlaybackSwitch "name='Master Playback Switch',index=2"
1472  *      }
1473  * }
1474  *
1475  * SupportedDevice and ConflictingDevice cannot be specified together.
1476  * Both are optional.
1477  */
1478 static int parse_modifier(snd_use_case_mgr_t *uc_mgr,
1479                           snd_config_t *cfg,
1480                           void *data1, void *data2)
1481 {
1482         struct use_case_verb *verb = data1;
1483         struct use_case_modifier *modifier;
1484         char *name;
1485         snd_config_iterator_t i, next;
1486         snd_config_t *n;
1487         int err;
1488
1489         if (parse_get_safe_name(uc_mgr, cfg, data2, &name) < 0)
1490                 return -EINVAL;
1491
1492         /* allocate modifier */
1493         modifier = calloc(1, sizeof(*modifier));
1494         if (modifier == NULL) {
1495                 free(name);
1496                 return -ENOMEM;
1497         }
1498         INIT_LIST_HEAD(&modifier->enable_list);
1499         INIT_LIST_HEAD(&modifier->disable_list);
1500         INIT_LIST_HEAD(&modifier->transition_list);
1501         INIT_LIST_HEAD(&modifier->dev_list.list);
1502         INIT_LIST_HEAD(&modifier->value_list);
1503         list_add_tail(&modifier->list, &verb->modifier_list);
1504         modifier->name = name;
1505
1506         /* in-place evaluation */
1507         err = uc_mgr_evaluate_inplace(uc_mgr, cfg);
1508         if (err < 0)
1509                 return err;
1510
1511         snd_config_for_each(i, next, cfg) {
1512                 const char *id;
1513                 n = snd_config_iterator_entry(i);
1514                 if (snd_config_get_id(n, &id) < 0)
1515                         continue;
1516
1517                 if (strcmp(id, "Comment") == 0) {
1518                         err = parse_string_substitute3(uc_mgr, n, &modifier->comment);
1519                         if (err < 0) {
1520                                 snd_error(UCM, "failed to get modifier comment");
1521                                 return err;
1522                         }
1523                         continue;
1524                 }
1525
1526                 if (strcmp(id, "SupportedDevice") == 0) {
1527                         err = parse_device_list(uc_mgr, &modifier->dev_list,
1528                                                 DEVLIST_SUPPORTED, n);
1529                         if (err < 0) {
1530                                 snd_error(UCM, "failed to parse supported device list");
1531                                 return err;
1532                         }
1533                 }
1534
1535                 if (strcmp(id, "ConflictingDevice") == 0) {
1536                         err = parse_device_list(uc_mgr, &modifier->dev_list,
1537                                                 DEVLIST_CONFLICTING, n);
1538                         if (err < 0) {
1539                                 snd_error(UCM, "failed to parse conflicting device list");
1540                                 return err;
1541                         }
1542                 }
1543
1544                 if (strcmp(id, "EnableSequence") == 0) {
1545                         err = parse_sequence(uc_mgr, &modifier->enable_list, n);
1546                         if (err < 0) {
1547                                 snd_error(UCM, "failed to parse modifier enable sequence");
1548                                 return err;
1549                         }
1550                         continue;
1551                 }
1552
1553                 if (strcmp(id, "DisableSequence") == 0) {
1554                         err = parse_sequence(uc_mgr, &modifier->disable_list, n);
1555                         if (err < 0) {
1556                                 snd_error(UCM, "failed to parse modifier disable sequence");
1557                                 return err;
1558                         }
1559                         continue;
1560                 }
1561
1562                 if (strcmp(id, "TransitionSequence") == 0) {
1563                         err = parse_transition(uc_mgr, &modifier->transition_list, n);
1564                         if (err < 0) {
1565                                 snd_error(UCM, "failed to parse transition modifier");
1566                                 return err;
1567                         }
1568                         continue;
1569                 }
1570
1571                 if (strcmp(id, "Value") == 0) {
1572                         err = parse_value(uc_mgr, &modifier->value_list, n);
1573                         if (err < 0) {
1574                                 snd_error(UCM, "failed to parse Value");
1575                                 return err;
1576                         }
1577                         continue;
1578                 }
1579         }
1580
1581         return 0;
1582 }
1583
1584 /*
1585  * Parse device configuration fields
1586  */
1587 static int parse_device_fields(snd_use_case_mgr_t *uc_mgr,
1588                                snd_config_t *cfg,
1589                                struct use_case_device *device)
1590 {
1591         snd_config_iterator_t i, next;
1592         snd_config_t *n;
1593         int err;
1594
1595         snd_config_for_each(i, next, cfg) {
1596                 const char *id;
1597                 n = snd_config_iterator_entry(i);
1598                 if (snd_config_get_id(n, &id) < 0)
1599                         continue;
1600
1601                 if (strcmp(id, "Comment") == 0) {
1602                         err = parse_string_substitute3(uc_mgr, n, &device->comment);
1603                         if (err < 0) {
1604                                 snd_error(UCM, "failed to get device comment");
1605                                 return err;
1606                         }
1607                         continue;
1608                 }
1609
1610                 if (strcmp(id, "SupportedDevice") == 0) {
1611                         err = parse_device_list(uc_mgr, &device->dev_list,
1612                                                 DEVLIST_SUPPORTED, n);
1613                         if (err < 0) {
1614                                 snd_error(UCM, "failed to parse supported device list");
1615
1616                                 return err;
1617                         }
1618                 }
1619
1620                 if (strcmp(id, "ConflictingDevice") == 0) {
1621                         err = parse_device_list(uc_mgr, &device->dev_list,
1622                                                 DEVLIST_CONFLICTING, n);
1623                         if (err < 0) {
1624                                 snd_error(UCM, "failed to parse conflicting device list");
1625
1626                                 return err;
1627                         }
1628                 }
1629
1630                 if (strcmp(id, "EnableSequence") == 0) {
1631                         err = parse_sequence(uc_mgr, &device->enable_list, n);
1632                         if (err < 0) {
1633                                 snd_error(UCM, "failed to parse device enable sequence");
1634
1635                                 return err;
1636                         }
1637                         continue;
1638                 }
1639
1640                 if (strcmp(id, "DisableSequence") == 0) {
1641                         err = parse_sequence(uc_mgr, &device->disable_list, n);
1642                         if (err < 0) {
1643                                 snd_error(UCM, "failed to parse device disable sequence");
1644
1645                                 return err;
1646                         }
1647                         continue;
1648                 }
1649
1650                 if (strcmp(id, "TransitionSequence") == 0) {
1651                         err = parse_transition(uc_mgr, &device->transition_list, n);
1652                         if (err < 0) {
1653                                 snd_error(UCM, "failed to parse transition device");
1654
1655                                 return err;
1656                         }
1657                         continue;
1658                 }
1659
1660                 if (strcmp(id, "Value") == 0) {
1661                         err = parse_value(uc_mgr, &device->value_list, n);
1662                         if (err < 0) {
1663                                 snd_error(UCM, "failed to parse Value");
1664                                 return err;
1665                         }
1666                         continue;
1667                 }
1668         }
1669         return 0;
1670 }
1671
1672 /*
1673  * Helper function to copy, evaluate and optionally merge configuration trees.
1674  */
1675 static int uc_mgr_config_copy_eval_merge(snd_use_case_mgr_t *uc_mgr,
1676                                          snd_config_t **dst,
1677                                          snd_config_t *src,
1678                                          snd_config_t *merge_from)
1679 {
1680         snd_config_t *tmp = NULL;
1681         int err;
1682
1683         err = snd_config_copy(&tmp, src);
1684         if (err < 0)
1685                 return err;
1686
1687         err = uc_mgr_evaluate_inplace(uc_mgr, tmp);
1688         if (err < 0) {
1689                 snd_config_delete(tmp);
1690                 return err;
1691         }
1692
1693         if (merge_from) {
1694                 err = uc_mgr_config_tree_merge(uc_mgr, tmp, merge_from, NULL, NULL);
1695                 if (err < 0) {
1696                         snd_config_delete(tmp);
1697                         return err;
1698                 }
1699         }
1700
1701         *dst = tmp;
1702         return 0;
1703 }
1704
1705 /*
1706  * Parse Device Use Cases
1707  *
1708  * # Each device is described in new section. N devices are allowed
1709  * SectionDevice."Headphones" {
1710  *      Comment "Headphones connected to 3.5mm jack"
1711  *
1712  *      SupportedDevice [
1713  *              "x"
1714  *              "y"
1715  *      ]
1716  *
1717  *      ConflictingDevice [
1718  *              "x"
1719  *              "y"
1720  *      ]
1721  *
1722  *      EnableSequence [
1723  *              ....
1724  *      ]
1725  *
1726  *      DisableSequence [
1727  *              ...
1728  *      ]
1729  *
1730  *      TransitionSequence."ToDevice" [
1731  *              ...
1732  *      ]
1733  *
1734  *      Value {
1735  *              PlaybackVolume "name='Master Playback Volume',index=2"
1736  *              PlaybackSwitch "name='Master Playback Switch',index=2"
1737  *      }
1738  * }
1739  */
1740
1741 static int parse_device_by_name(snd_use_case_mgr_t *uc_mgr,
1742                                 snd_config_t *cfg,
1743                                 struct use_case_verb *verb,
1744                                 const char *name,
1745                                 struct use_case_device **ret_device)
1746 {
1747         struct use_case_device *device;
1748         int err;
1749
1750         device = calloc(1, sizeof(*device));
1751         if (device == NULL)
1752                 return -ENOMEM;
1753
1754         INIT_LIST_HEAD(&device->enable_list);
1755         INIT_LIST_HEAD(&device->disable_list);
1756         INIT_LIST_HEAD(&device->transition_list);
1757         INIT_LIST_HEAD(&device->dev_list.list);
1758         INIT_LIST_HEAD(&device->value_list);
1759         INIT_LIST_HEAD(&device->variants);
1760         INIT_LIST_HEAD(&device->variant_list);
1761         list_add_tail(&device->list, &verb->device_list);
1762         device->name = strdup(name);
1763         if (device->name == NULL) {
1764                 free(device);
1765                 return -ENOMEM;
1766         }
1767         device->orig_name = strdup(name);
1768         if (device->orig_name == NULL)
1769                 return -ENOMEM;
1770
1771         err = parse_device_fields(uc_mgr, cfg, device);
1772         if (err < 0)
1773                 return err;
1774
1775         if (ret_device)
1776                 *ret_device = device;
1777
1778         return 0;
1779 }
1780
1781 static int parse_device(snd_use_case_mgr_t *uc_mgr,
1782                         snd_config_t *cfg,
1783                         void *data1, void *data2)
1784 {
1785         struct use_case_verb *verb = data1;
1786         char *name, *colon;
1787         const char *variant_label = NULL;
1788         struct use_case_device *device = NULL;
1789         snd_config_t *primary_cfg_copy = NULL;
1790         snd_config_t *device_variant = NULL;
1791         snd_config_t *merged_cfg = NULL;
1792         snd_config_iterator_t i, next;
1793         snd_config_t *n;
1794         int err;
1795
1796         if (parse_get_safe_name(uc_mgr, cfg, data2, &name) < 0)
1797                 return -EINVAL;
1798
1799         if (uc_mgr->conf_format >= 8 && (colon = strchr(name, ':'))) {
1800                 variant_label = colon + 1;
1801
1802                 err = snd_config_search(cfg, "DeviceVariant", &device_variant);
1803                 if (err == 0) {
1804                         snd_config_t *variant_cfg = NULL;
1805
1806                         /* Save a copy of the primary config for creating variant devices */
1807                         err = snd_config_copy(&primary_cfg_copy, cfg);
1808                         if (err < 0) {
1809                                 free(name);
1810                                 return err;
1811                         }
1812
1813                         err = snd_config_search(device_variant, variant_label, &variant_cfg);
1814                         if (err == 0) {
1815                                 err = uc_mgr_config_copy_eval_merge(uc_mgr, &merged_cfg, cfg, variant_cfg);
1816                                 if (err < 0) {
1817                                         free(name);
1818                                         return err;
1819                                 }
1820                                 cfg = merged_cfg;
1821                         }
1822                 }
1823         }
1824
1825         /* in-place evaluation */
1826         if (cfg != merged_cfg) {
1827                 err = uc_mgr_evaluate_inplace(uc_mgr, cfg);
1828                 if (err < 0) {
1829                         free(name);
1830                         goto __error;
1831                 }
1832         }
1833
1834         err = parse_device_by_name(uc_mgr, cfg, verb, name, &device);
1835         free(name);
1836         if (err < 0)
1837                 goto __error;
1838
1839         if (merged_cfg) {
1840                 snd_config_delete(merged_cfg);
1841                 merged_cfg = NULL;
1842         }
1843
1844         if (device_variant == NULL)
1845                 goto __end;
1846
1847         if (device->dev_list.type == DEVLIST_SUPPORTED) {
1848                 snd_error(UCM, "DeviceVariant cannot be used with SupportedDevice");
1849                 err = -EINVAL;
1850                 goto __error;
1851         }
1852
1853         if (snd_config_get_type(device_variant) != SND_CONFIG_TYPE_COMPOUND) {
1854                 snd_error(UCM, "compound type expected for DeviceVariant");
1855                 err = -EINVAL;
1856                 goto __error;
1857         }
1858
1859         colon = strchr(device->name, ':');
1860         if (!colon) {
1861                 snd_error(UCM, "DeviceVariant requires ':' in device name");
1862                 err = -EINVAL;
1863                 goto __error;
1864         }
1865
1866         snd_config_for_each(i, next, device_variant) {
1867                 const char *variant_name;
1868                 char variant_device_name[128];
1869                 struct use_case_device *variant = NULL;
1870
1871                 n = snd_config_iterator_entry(i);
1872
1873                 if (snd_config_get_id(n, &variant_name) < 0)
1874                         continue;
1875
1876                 /* Create variant device name: base:variant_name */
1877                 snprintf(variant_device_name, sizeof(variant_device_name),
1878                          "%.*s:%s", (int)(colon - device->name),
1879                          device->name, variant_name);
1880
1881                 err = uc_mgr_config_copy_eval_merge(uc_mgr, &merged_cfg, primary_cfg_copy, n);
1882                 if (err < 0)
1883                         goto __error;
1884
1885                 err = parse_device_by_name(uc_mgr, merged_cfg, verb,
1886                                            variant_device_name, &variant);
1887                 snd_config_delete(merged_cfg);
1888                 merged_cfg = NULL;
1889                 if (err < 0)
1890                         goto __error;
1891
1892                 /* Link variant to primary device */
1893                 list_add(&variant->variant_list, &device->variants);
1894
1895                 err = uc_mgr_put_to_dev_list(&device->dev_list, variant->name);
1896                 if (err < 0)
1897                         goto __error;
1898                 if (device->dev_list.type == DEVLIST_NONE)
1899                         device->dev_list.type = DEVLIST_CONFLICTING;
1900         }
1901
1902 __end:
1903         err = 0;
1904 __error:
1905         if (merged_cfg)
1906                 snd_config_delete(merged_cfg);
1907         if (primary_cfg_copy)
1908                 snd_config_delete(primary_cfg_copy);
1909         return err;
1910 }
1911
1912 /*
1913  * Parse Device Rename/Delete Command
1914  *
1915  * # The devices might be renamed to allow the better conditional runtime
1916  * # evaluation. Bellow example renames Speaker1 device to Speaker and
1917  * # removes Speaker2 device.
1918  * RenameDevice."Speaker1" "Speaker"
1919  * RemoveDevice."Speaker2" "Speaker2"
1920  */
1921 static int parse_dev_name_list(snd_use_case_mgr_t *uc_mgr,
1922                                snd_config_t *cfg,
1923                                struct list_head *list)
1924 {
1925         snd_config_t *n;
1926         snd_config_iterator_t i, next;
1927         const char *id, *name1;
1928         char *name1s, *name2;
1929         struct ucm_dev_name *dev;
1930         snd_config_iterator_t pos;
1931         int err;
1932
1933         if (snd_config_get_id(cfg, &id) < 0)
1934                 return -EINVAL;
1935
1936         if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
1937                 snd_error(UCM, "compound type expected for %s", id);
1938                 return -EINVAL;
1939         }
1940
1941         snd_config_for_each(i, next, cfg) {
1942                 n = snd_config_iterator_entry(i);
1943
1944                 if (snd_config_get_id(n, &name1) < 0)
1945                         return -EINVAL;
1946
1947                 err = get_string3(uc_mgr, name1, &name1s);
1948                 if (err < 0)
1949                         return err;
1950
1951                 err = parse_string_substitute3(uc_mgr, n, &name2);
1952                 if (err < 0) {
1953                         free(name1s);
1954                         snd_error(UCM, "failed to get target device name for '%s'", name1);
1955                         return err;
1956                 }
1957
1958                 /* skip duplicates */
1959                 list_for_each(pos, list) {
1960                         dev = list_entry(pos, struct ucm_dev_name, list);
1961                         if (strcmp(dev->name1, name1s) == 0) {
1962                                 free(name2);
1963                                 free(name1s);
1964                                 return 0;
1965                         }
1966                 }
1967
1968                 free(name1s);
1969
1970                 dev = calloc(1, sizeof(*dev));
1971                 if (dev == NULL) {
1972                         free(name2);
1973                         return -ENOMEM;
1974                 }
1975                 dev->name1 = strdup(name1);
1976                 if (dev->name1 == NULL) {
1977                         free(dev);
1978                         free(name2);
1979                         return -ENOMEM;
1980                 }
1981                 dev->name2 = name2;
1982                 list_add_tail(&dev->list, list);
1983         }
1984
1985         return 0;
1986 }
1987
1988 static int parse_compound_check_legacy(snd_use_case_mgr_t *uc_mgr,
1989           snd_config_t *cfg,
1990           int (*fcn)(snd_use_case_mgr_t *, snd_config_t *, void *, void *),
1991           void *data1)
1992 {
1993         const char *id, *idchild;
1994         int child_ctr = 0, legacy_format = 1;
1995         snd_config_iterator_t i, next;
1996         snd_config_t *child;
1997         int err;
1998
1999         err = snd_config_get_id(cfg, &id);
2000         if (err < 0)
2001                 return err;
2002
2003         snd_config_for_each(i, next, cfg) {
2004                 child_ctr++;
2005                 if (child_ctr > 1) {
2006                         break;
2007                 }
2008
2009                 child = snd_config_iterator_entry(i);
2010
2011                 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
2012                         legacy_format = 0;
2013                         break;
2014                 }
2015
2016                 if (snd_config_get_id(child, &idchild) < 0)
2017                         return -EINVAL;
2018
2019                 if (strcmp(idchild, "0")) {
2020                         legacy_format = 0;
2021                         break;
2022                 }
2023         }
2024         if (child_ctr != 1) {
2025                 legacy_format = 0;
2026         }
2027
2028         if (legacy_format)
2029                 return parse_compound(uc_mgr, cfg, fcn, data1, (void *)id);
2030         else
2031                 return fcn(uc_mgr, cfg, data1, NULL);
2032 }
2033
2034 static int parse_device_name(snd_use_case_mgr_t *uc_mgr,
2035                              snd_config_t *cfg,
2036                              void *data1,
2037                              void *data2 ATTRIBUTE_UNUSED)
2038 {
2039         return parse_compound_check_legacy(uc_mgr, cfg, parse_device, data1);
2040 }
2041
2042 static int parse_modifier_name(snd_use_case_mgr_t *uc_mgr,
2043                              snd_config_t *cfg,
2044                              void *data1,
2045                              void *data2 ATTRIBUTE_UNUSED)
2046 {
2047         return parse_compound_check_legacy(uc_mgr, cfg, parse_modifier, data1);
2048 }
2049
2050 static int verb_dev_list_add(struct use_case_verb *verb,
2051                              enum dev_list_type dst_type,
2052                              const char *dst,
2053                              const char *src)
2054 {
2055         struct use_case_device *device;
2056         struct list_head *pos;
2057
2058         list_for_each(pos, &verb->device_list) {
2059                 device = list_entry(pos, struct use_case_device, list);
2060
2061                 if (strcmp(device->name, dst) != 0)
2062                         continue;
2063                 if (device->dev_list.type != dst_type) {
2064                         if (list_empty(&device->dev_list.list)) {
2065                                 device->dev_list.type = dst_type;
2066                         } else {
2067                                 snd_error(UCM, "incompatible device list type ('%s', '%s')", device->orig_name, src);
2068                                 return -EINVAL;
2069                         }
2070                 }
2071                 return uc_mgr_put_to_dev_list(&device->dev_list, src);
2072         }
2073         snd_error(UCM, "unable to find device '%s'", dst);
2074         return -ENOENT;
2075 }
2076
2077 static int verb_dev_list_check(struct use_case_verb *verb)
2078 {
2079         struct list_head *pos, *pos2, *pos3;
2080         struct use_case_device *device, *target_dev;
2081         struct dev_list_node *dlist, *dlist2;
2082         int err, iteration;
2083         int max_iterations = 100; /* safety limit to prevent infinite loops */
2084         bool added_something;
2085
2086         /* First pass: ensure bidirectional relationships */
2087         list_for_each(pos, &verb->device_list) {
2088                 device = list_entry(pos, struct use_case_device, list);
2089                 list_for_each(pos2, &device->dev_list.list) {
2090                         dlist = list_entry(pos2, struct dev_list_node, list);
2091                         err = verb_dev_list_add(verb, device->dev_list.type,
2092                                                 dlist->name, device->name);
2093                         if (err < 0)
2094                                 return err;
2095                 }
2096         }
2097
2098         /* Second pass: complete other relationships for devices in group.
2099          * For n devices, at most n-1 iterations are needed.
2100          */
2101         for (iteration = 0; iteration < max_iterations; iteration++) {
2102                 added_something = false;
2103
2104                 list_for_each(pos, &verb->device_list) {
2105                         device = list_entry(pos, struct use_case_device, list);
2106
2107                         if (device->dev_list.type == DEVLIST_NONE)
2108                                 continue;
2109
2110                         list_for_each(pos2, &device->dev_list.list) {
2111                                 dlist = list_entry(pos2, struct dev_list_node, list);
2112
2113                                 target_dev = NULL;
2114                                 list_for_each(pos3, &verb->device_list) {
2115                                         struct use_case_device *tmp_dev;
2116                                         tmp_dev = list_entry(pos3, struct use_case_device, list);
2117                                         if (strcmp(tmp_dev->name, dlist->name) == 0) {
2118                                                 target_dev = tmp_dev;
2119                                                 break;
2120                                         }
2121                                 }
2122
2123                                 if (!target_dev)
2124                                         continue;
2125
2126                                 list_for_each(pos3, &device->dev_list.list) {
2127                                         dlist2 = list_entry(pos3, struct dev_list_node, list);
2128
2129                                         if (strcmp(dlist2->name, target_dev->name) == 0)
2130                                                 continue;
2131
2132                                         /* verb_dev_list_add returns 1 if device was added, 0 if already exists */
2133                                         err = verb_dev_list_add(verb, device->dev_list.type,
2134                                                                 target_dev->name, dlist2->name);
2135                                         if (err < 0)
2136                                                 return err;
2137                                         if (err > 0)
2138                                                 added_something = true;
2139                                 }
2140                         }
2141                 }
2142
2143                 /* If nothing was added in this iteration, we're done */
2144                 if (!added_something)
2145                         break;
2146         }
2147
2148         if (iteration >= max_iterations) {
2149                 snd_error(UCM, "too many device list iterations for verb '%s'", verb->name);
2150                 return -EINVAL;
2151         }
2152
2153         return 0;
2154 }
2155
2156 /*
2157  * Check if a device name is already in use
2158  */
2159 static int is_device_name_used(struct use_case_verb *verb, const char *name, struct use_case_device *current)
2160 {
2161         struct list_head *pos;
2162         struct use_case_device *device;
2163
2164         list_for_each(pos, &verb->device_list) {
2165                 device = list_entry(pos, struct use_case_device, list);
2166                 if (device != current && strcmp(device->name, name) == 0)
2167                         return 1;
2168         }
2169         return 0;
2170 }
2171
2172 /*
2173  * Update all references to a device name in modifiers and other devices.
2174  * This helper function is used when renaming devices to ensure all
2175  * dev_list references are updated accordingly.
2176  */
2177 static int verb_update_device_references(struct use_case_verb *verb,
2178                                           const char *old_name,
2179                                           const char *new_name)
2180 {
2181         struct list_head *pos, *pos2;
2182         struct use_case_device *device;
2183         struct use_case_modifier *modifier;
2184         struct dev_list_node *dlist;
2185         char *name_copy;
2186
2187         list_for_each(pos, &verb->modifier_list) {
2188                 modifier = list_entry(pos, struct use_case_modifier, list);
2189                 list_for_each(pos2, &modifier->dev_list.list) {
2190                         dlist = list_entry(pos2, struct dev_list_node, list);
2191                         if (strcmp(dlist->name, old_name) == 0) {
2192                                 name_copy = strdup(new_name);
2193                                 if (name_copy == NULL)
2194                                         return -ENOMEM;
2195                                 free(dlist->name);
2196                                 dlist->name = name_copy;
2197                         }
2198                 }
2199         }
2200
2201         list_for_each(pos, &verb->device_list) {
2202                 device = list_entry(pos, struct use_case_device, list);
2203                 list_for_each(pos2, &device->dev_list.list) {
2204                         dlist = list_entry(pos2, struct dev_list_node, list);
2205                         if (strcmp(dlist->name, old_name) == 0) {
2206                                 name_copy = strdup(new_name);
2207                                 if (name_copy == NULL)
2208                                         return -ENOMEM;
2209                                 free(dlist->name);
2210                                 dlist->name = name_copy;
2211                         }
2212                 }
2213         }
2214
2215         return 0;
2216 }
2217
2218 /*
2219  * Normalize device names according to use-case.h specification.
2220  * Device names like "HDMI 1" or "Line 1" should be normalized to "HDMI1" and "Line1".
2221  * When device name contains ':', add index and remove everything after ':' (including).
2222  * If final name is already used, retry with higher index.
2223  * Also updates dev_list members in modifiers and devices to reference the normalized names.
2224  */
2225 static int verb_normalize_device_names(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb)
2226 {
2227         struct list_head *pos;
2228         struct use_case_device *device;
2229         char *orig_name, *norm_name, *colon;
2230         char temp[80];
2231         int err, index;
2232
2233         list_for_each(pos, &verb->device_list) {
2234                 device = list_entry(pos, struct use_case_device, list);
2235
2236                 orig_name = strdup(device->name);
2237                 if (orig_name == NULL)
2238                         return -ENOMEM;
2239
2240                 norm_name = strdup(device->name);
2241                 if (norm_name == NULL) {
2242                         err = -ENOMEM;
2243                         goto __error;
2244                 }
2245
2246                 if (uc_mgr->conf_format < 8)
2247                         goto __no_colon;
2248
2249                 colon = strchr(norm_name, ':');
2250                 if (colon) {
2251                         if (colon[1] == '\0' || strchr(colon + 1, ' ')) {
2252                                 snd_error(UCM, "device descriptor cannot be empty or contain spaces '%s'", orig_name);
2253                                 err = -EINVAL;
2254                                 goto __error;
2255                         }
2256                         *colon = '\0';
2257                         index = 1;
2258                         do {
2259                                 snprintf(temp, sizeof(temp), "%s%d", norm_name, index);
2260                                 if (!is_device_name_used(verb, temp, device))
2261                                         break;
2262                                 index++;
2263                         } while (index < 100); /* Safety limit */
2264                         if (index >= 100) {
2265                                 snd_error(UCM, "too many device name conflicts for '%s'", orig_name);
2266                                 err = -EINVAL;
2267                                 goto __error;
2268                         }
2269
2270                 } else {
2271 __no_colon:
2272                         err = parse_device_index(&norm_name, &index);
2273                         if (err < 0) {
2274                                 snd_error(UCM, "cannot parse device name '%s'", orig_name);
2275                                 goto __error;
2276                         }
2277
2278                         if (index <= 0) {
2279                                 free(orig_name);
2280                                 free(norm_name);
2281                                 continue;
2282                         }
2283                         snprintf(temp, sizeof(temp), "%s%d", norm_name, index);
2284                 }
2285
2286                 free(device->name);
2287                 device->name = strdup(temp);
2288                 if (device->name == NULL) {
2289                         err = -ENOMEM;
2290                         goto __error;
2291                 }
2292
2293                 /* Update all references to the old device name */
2294                 err = verb_update_device_references(verb, orig_name, device->name);
2295                 if (err < 0)
2296                         goto __error;
2297
2298                 free(orig_name);
2299                 free(norm_name);
2300         }
2301
2302         return 0;
2303
2304 __error:
2305         free(orig_name);
2306         free(norm_name);
2307         return err;
2308 }
2309
2310 /*
2311  * Strip index from single device names.
2312  * According to use-case.h specification, if there is only one device
2313  * with a given base name (e.g., only "HDMI1" and no "HDMI2"), the index
2314  * should be stripped to produce the final name (e.g., "HDMI").
2315  */
2316 static int verb_strip_single_device_index(struct use_case_verb *verb)
2317 {
2318         struct list_head *pos, *pos2;
2319         struct use_case_device *device, *device2;
2320         char *base_name, *test_base;
2321         char *orig_name;
2322         int count, index, test_index, err;
2323
2324         list_for_each(pos, &verb->device_list) {
2325                 device = list_entry(pos, struct use_case_device, list);
2326
2327                 base_name = strdup(device->name);
2328                 if (base_name == NULL)
2329                         return -ENOMEM;
2330
2331                 err = parse_device_index(&base_name, &index);
2332                 if (err < 0) {
2333                         free(base_name);
2334                         continue;
2335                 }
2336
2337                 if (index <= 0) {
2338                         free(base_name);
2339                         continue;
2340                 }
2341
2342                 /* Count how many devices have the same base name */
2343                 count = 0;
2344                 list_for_each(pos2, &verb->device_list) {
2345                         device2 = list_entry(pos2, struct use_case_device, list);
2346                         test_base = strdup(device2->name);
2347                         if (test_base == NULL) {
2348                                 free(base_name);
2349                                 return -ENOMEM;
2350                         }
2351
2352                         err = parse_device_index(&test_base, &test_index);
2353                         if (err >= 0 && strcmp(test_base, base_name) == 0)
2354                                 count++;
2355
2356                         free(test_base);
2357                 }
2358
2359                 if (count == 1) {
2360                         orig_name = device->name;
2361                         device->name = base_name;
2362
2363                         err = verb_update_device_references(verb, orig_name, device->name);
2364                         if (err < 0) {
2365                                 device->name = orig_name;
2366                                 free(base_name);
2367                                 return err;
2368                         }
2369
2370                         free(orig_name);
2371                 } else {
2372                         free(base_name);
2373                 }
2374         }
2375
2376         return 0;
2377 }
2378
2379 /*
2380  * Determine priority for a device.
2381  * Priority order:
2382  *   1. If 'Priority' value exists, use it as the sort key
2383  *   2. If 'PlaybackPriority' value exists, use it as the sort key
2384  *   3. If 'CapturePriority' value exists, use it as the sort key
2385  *   4. Fallback: LONG_MIN (no priority)
2386  */
2387 static long verb_device_get_priority(struct use_case_device *device)
2388 {
2389         struct list_head *pos;
2390         struct ucm_value *val;
2391         const char *priority_str = NULL;
2392         long priority = LONG_MIN;
2393         int err;
2394
2395         list_for_each(pos, &device->value_list) {
2396                 val = list_entry(pos, struct ucm_value, list);
2397                 if (strcmp(val->name, "Priority") == 0) {
2398                         priority_str = val->data;
2399                         break;
2400                 }
2401         }
2402
2403         if (!priority_str) {
2404                 list_for_each(pos, &device->value_list) {
2405                         val = list_entry(pos, struct ucm_value, list);
2406                         if (strcmp(val->name, "PlaybackPriority") == 0) {
2407                                 priority_str = val->data;
2408                                 break;
2409                         }
2410                 }
2411         }
2412
2413         if (!priority_str) {
2414                 list_for_each(pos, &device->value_list) {
2415                         val = list_entry(pos, struct ucm_value, list);
2416                         if (strcmp(val->name, "CapturePriority") == 0) {
2417                                 priority_str = val->data;
2418                                 break;
2419                         }
2420                 }
2421         }
2422
2423         if (priority_str) {
2424                 err = safe_strtol(priority_str, &priority);
2425                 if (err < 0)
2426                         priority = LONG_MIN;
2427         }
2428
2429         return priority;
2430 }
2431
2432 /*
2433  * Sort devices based on priority values.
2434  * Priority order:
2435  *   1. If 'Priority' value exists, use it as the sort key
2436  *   2. If 'PlaybackPriority' value exists, use it as the sort key
2437  *   3. If 'CapturePriority' value exists, use it as the sort key
2438  *   4. Fallback: use device->name (original) as the sort key
2439  * Higher priority values are placed first in the list.
2440  */
2441 static int verb_sort_devices(struct use_case_verb *verb)
2442 {
2443         struct list_head sorted_list;
2444         struct list_head *pos, *npos;
2445         struct use_case_device *device, *insert_dev;
2446
2447         INIT_LIST_HEAD(&sorted_list);
2448
2449         /* First pass: determine and cache priority for all devices */
2450         list_for_each(pos, &verb->device_list) {
2451                 device = list_entry(pos, struct use_case_device, list);
2452                 device->sort_priority = verb_device_get_priority(device);
2453         }
2454
2455         /* Move devices from verb->device_list to sorted_list in sorted order */
2456         list_for_each_safe(pos, npos, &verb->device_list) {
2457                 device = list_entry(pos, struct use_case_device, list);
2458
2459                 /* Remove device from original list */
2460                 list_del(&device->list);
2461
2462                 /* Find the insertion point in sorted_list */
2463                 /* Devices are sorted in descending order of priority (higher priority first) */
2464                 /* If priorities are equal or not defined, use device name as key */
2465                 if (list_empty(&sorted_list)) {
2466                         list_add_tail(&device->list, &sorted_list);
2467                 } else {
2468                         struct list_head *pos2, *insert_pos = &sorted_list;
2469                         list_for_each(pos2, &sorted_list) {
2470                                 insert_dev = list_entry(pos2, struct use_case_device, list);
2471
2472                                 if (device->sort_priority > insert_dev->sort_priority) {
2473                                         insert_pos = pos2;
2474                                         break;
2475                                 } else if (device->sort_priority == insert_dev->sort_priority) {
2476                                         if (strcmp(device->name, insert_dev->name) < 0) {
2477                                                 insert_pos = pos2;
2478                                                 break;
2479                                         }
2480                                 }
2481                         }
2482
2483                         list_add_tail(&device->list, insert_pos);
2484                 }
2485         }
2486
2487         /* Move sorted list back to verb->device_list */
2488         list_splice_init(&sorted_list, &verb->device_list);
2489
2490         return 0;
2491 }
2492
2493 static int verb_device_management(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb)
2494 {
2495         struct list_head *pos;
2496         struct ucm_dev_name *dev;
2497         int err;
2498
2499         /* rename devices */
2500         list_for_each(pos, &verb->rename_list) {
2501                 dev = list_entry(pos, struct ucm_dev_name, list);
2502                 err = uc_mgr_rename_device(verb, dev->name1, dev->name2);
2503                 if (err < 0) {
2504                         snd_error(UCM, "cannot rename device '%s' to '%s'", dev->name1, dev->name2);
2505                         return err;
2506                 }
2507         }
2508
2509         /* remove devices */
2510         list_for_each(pos, &verb->remove_list) {
2511                 dev = list_entry(pos, struct ucm_dev_name, list);
2512                 err = uc_mgr_remove_device(verb, dev->name2);
2513                 if (err < 0) {
2514                         snd_error(UCM, "cannot remove device '%s'", dev->name2);
2515                         return err;
2516                 }
2517         }
2518
2519         /* those lists are no longer used */
2520         uc_mgr_free_dev_name_list(&verb->rename_list);
2521         uc_mgr_free_dev_name_list(&verb->remove_list);
2522
2523         /* strip index from single device names */
2524         if (uc_mgr->conf_format >= 8) {
2525                 /* sort devices by priority */
2526                 err = verb_sort_devices(verb);
2527                 if (err < 0)
2528                         return err;
2529         }
2530
2531         /* normalize device names to remove spaces per use-case.h specification */
2532         err = verb_normalize_device_names(uc_mgr, verb);
2533         if (err < 0)
2534                 return err;
2535
2536         /* strip index from single device names */
2537         if (uc_mgr->conf_format >= 8) {
2538                 err = verb_strip_single_device_index(verb);
2539                 if (err < 0)
2540                         return err;
2541
2542         }
2543
2544         /* handle conflicting/supported lists */
2545         return verb_dev_list_check(verb);
2546 }
2547
2548 /*
2549  * Parse Verb Section
2550  *
2551  * # Example Use case verb section for Voice call blah
2552  * # By Joe Blogs <joe@blogs.com>
2553  *
2554  * SectionVerb {
2555  *      # enable and disable sequences are compulsory
2556  *      EnableSequence [
2557  *              cset "name='Master Playback Switch',index=2 0,0"
2558  *              cset "name='Master Playback Volume',index=2 25,25"
2559  *              msleep 50
2560  *              cset "name='Master Playback Switch',index=2 1,1"
2561  *              cset "name='Master Playback Volume',index=2 50,50"
2562  *      ]
2563  *
2564  *      DisableSequence [
2565  *              cset "name='Master Playback Switch',index=2 0,0"
2566  *              cset "name='Master Playback Volume',index=2 25,25"
2567  *              msleep 50
2568  *              cset "name='Master Playback Switch',index=2 1,1"
2569  *              cset "name='Master Playback Volume',index=2 50,50"
2570  *      ]
2571  *
2572  *      # Optional transition verb
2573  *      TransitionSequence."ToCaseName" [
2574  *              msleep 1
2575  *      ]
2576  *
2577  *      # Optional TQ and ALSA PCMs
2578  *      Value {
2579  *              TQ HiFi
2580  *              CapturePCM "hw:0"
2581  *              PlaybackPCM "hw:0"
2582  *      }
2583  * }
2584  */
2585 static int parse_verb(snd_use_case_mgr_t *uc_mgr,
2586                       struct use_case_verb *verb,
2587                       snd_config_t *cfg)
2588 {
2589         snd_config_iterator_t i, next;
2590         snd_config_t *n;
2591         int err;
2592
2593         /* in-place evaluation */
2594         err = uc_mgr_evaluate_inplace(uc_mgr, cfg);
2595         if (err < 0)
2596                 return err;
2597
2598         /* parse verb section */
2599         snd_config_for_each(i, next, cfg) {
2600                 const char *id;
2601                 n = snd_config_iterator_entry(i);
2602                 if (snd_config_get_id(n, &id) < 0)
2603                         continue;
2604
2605                 if (strcmp(id, "EnableSequence") == 0) {
2606                         err = parse_sequence(uc_mgr, &verb->enable_list, n);
2607                         if (err < 0) {
2608                                 snd_error(UCM, "failed to parse verb enable sequence");
2609                                 return err;
2610                         }
2611                         continue;
2612                 }
2613
2614                 if (strcmp(id, "DisableSequence") == 0) {
2615                         err = parse_sequence(uc_mgr, &verb->disable_list, n);
2616                         if (err < 0) {
2617                                 snd_error(UCM, "failed to parse verb disable sequence");
2618                                 return err;
2619                         }
2620                         continue;
2621                 }
2622
2623                 if (strcmp(id, "TransitionSequence") == 0) {
2624                         snd_debug(UCM, "Parse TransitionSequence");
2625                         err = parse_transition(uc_mgr, &verb->transition_list, n);
2626                         if (err < 0) {
2627                                 snd_error(UCM, "failed to parse transition sequence");
2628                                 return err;
2629                         }
2630                         continue;
2631                 }
2632
2633                 if (strcmp(id, "Value") == 0) {
2634                         err = parse_value(uc_mgr, &verb->value_list, n);
2635                         if (err < 0)
2636                                 return err;
2637                         continue;
2638                 }
2639         }
2640
2641         return 0;
2642 }
2643
2644 /*
2645  * Parse a Use case verb configuration.
2646  *
2647  * This configuration contains the following :-
2648  *  o Verb enable and disable sequences.
2649  *  o Supported Device enable and disable sequences for verb.
2650  *  o Supported Modifier enable and disable sequences for verb
2651  *  o Optional QoS for the verb and modifiers.
2652  *  o Optional PCM device ID for verb and modifiers
2653  *  o Alias kcontrols IDs for master and volumes and mutes.
2654  */
2655 static int parse_verb_config(snd_use_case_mgr_t *uc_mgr,
2656                              const char *use_case_name,
2657                              const char *comment,
2658                              snd_config_t *cfg,
2659                              const char *what)
2660 {
2661         snd_config_iterator_t i, next;
2662         snd_config_t *n;
2663         struct use_case_verb *verb;
2664         int err;
2665
2666         /* allocate verb */
2667         verb = calloc(1, sizeof(struct use_case_verb));
2668         if (verb == NULL)
2669                 return -ENOMEM;
2670         INIT_LIST_HEAD(&verb->enable_list);
2671         INIT_LIST_HEAD(&verb->disable_list);
2672         INIT_LIST_HEAD(&verb->transition_list);
2673         INIT_LIST_HEAD(&verb->device_list);
2674         INIT_LIST_HEAD(&verb->cmpt_device_list);
2675         INIT_LIST_HEAD(&verb->modifier_list);
2676         INIT_LIST_HEAD(&verb->value_list);
2677         INIT_LIST_HEAD(&verb->rename_list);
2678         INIT_LIST_HEAD(&verb->remove_list);
2679         list_add_tail(&verb->list, &uc_mgr->verb_list);
2680         if (use_case_name == NULL)
2681                 return -EINVAL;
2682         verb->name = strdup(use_case_name);
2683         if (verb->name == NULL)
2684                 return -ENOMEM;
2685
2686         if (comment != NULL) {
2687                 verb->comment = strdup(comment);
2688                 if (verb->comment == NULL)
2689                         return -ENOMEM;
2690         }
2691
2692         /* in-place evaluation */
2693         err = uc_mgr_evaluate_inplace(uc_mgr, cfg);
2694         if (err < 0)
2695                 return err;
2696
2697         /* parse master config sections */
2698         snd_config_for_each(i, next, cfg) {
2699                 const char *id;
2700                 n = snd_config_iterator_entry(i);
2701                 if (snd_config_get_id(n, &id) < 0)
2702                         continue;
2703
2704                 /* find verb section and parse it */
2705                 if (strcmp(id, "SectionVerb") == 0) {
2706                         err = parse_verb(uc_mgr, verb, n);
2707                         if (err < 0) {
2708                                 snd_error(UCM, "%s failed to parse verb", what);
2709                                 return err;
2710                         }
2711                         continue;
2712                 }
2713
2714                 /* find device sections and parse them */
2715                 if (strcmp(id, "SectionDevice") == 0) {
2716                         err = parse_compound(uc_mgr, n,
2717                                                 parse_device_name, verb, NULL);
2718                         if (err < 0) {
2719                                 snd_error(UCM, "%s failed to parse device", what);
2720                                 return err;
2721                         }
2722                         continue;
2723                 }
2724
2725                 /* find modifier sections and parse them */
2726                 if (strcmp(id, "SectionModifier") == 0) {
2727                         err = parse_compound(uc_mgr, n,
2728                                              parse_modifier_name, verb, NULL);
2729                         if (err < 0) {
2730                                 snd_error(UCM, "%s failed to parse modifier", what);
2731                                 return err;
2732                         }
2733                         continue;
2734                 }
2735
2736                 /* device renames */
2737                 if (strcmp(id, "RenameDevice") == 0) {
2738                         err = parse_dev_name_list(uc_mgr, n, &verb->rename_list);
2739                         if (err < 0) {
2740                                 snd_error(UCM, "%s failed to parse device rename", what);
2741                                 return err;
2742                         }
2743                         continue;
2744                 }
2745
2746                 /* device remove */
2747                 if (strcmp(id, "RemoveDevice") == 0) {
2748                         err = parse_dev_name_list(uc_mgr, n, &verb->remove_list);
2749                         if (err < 0) {
2750                                 snd_error(UCM, "%s failed to parse device remove", what);
2751                                 return err;
2752                         }
2753                         continue;
2754                 }
2755
2756                 /* alsa-lib configuration */
2757                 if (uc_mgr->conf_format > 3 && strcmp(id, "LibraryConfig") == 0) {
2758                         err = parse_libconfig(uc_mgr, n);
2759                         if (err < 0) {
2760                                 snd_error(UCM, "%s failed to parse LibConfig", what);
2761                                 return err;
2762                         }
2763                         continue;
2764                 }
2765         }
2766
2767         /* use case verb must have at least 1 device */
2768         if (list_empty(&verb->device_list)) {
2769                 snd_error(UCM, "no use case device defined");
2770                 return -EINVAL;
2771         }
2772
2773         /* do device rename and delete */
2774         err = verb_device_management(uc_mgr, verb);
2775         if (err < 0) {
2776                 snd_error(UCM, "device management error in verb '%s'", verb->name);
2777                 return err;
2778         }
2779
2780         return 0;
2781 }
2782
2783 /*
2784  * Parse variant information
2785  */
2786 static int parse_variant(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg,
2787                          char **_vfile, char **_vcomment)
2788 {
2789         snd_config_iterator_t i, next;
2790         snd_config_t *n;
2791         char *file = NULL, *comment = NULL;
2792         int err;
2793
2794         /* parse master config sections */
2795         snd_config_for_each(i, next, cfg) {
2796                 const char *id;
2797                 n = snd_config_iterator_entry(i);
2798                 if (snd_config_get_id(n, &id) < 0)
2799                         continue;
2800
2801                 /* get use case verb file name */
2802                 if (strcmp(id, "File") == 0) {
2803                         if (_vfile) {
2804                                 err = parse_string_substitute3(uc_mgr, n, &file);
2805                                 if (err < 0) {
2806                                         snd_error(UCM, "failed to get File");
2807                                         goto __error;
2808                                 }
2809                         }
2810                         continue;
2811                 }
2812
2813                 /* get optional use case comment */
2814                 if (strncmp(id, "Comment", 7) == 0) {
2815                         if (_vcomment) {
2816                                 err = parse_string_substitute3(uc_mgr, n, &comment);
2817                                 if (err < 0) {
2818                                         snd_error(UCM, "failed to get Comment");
2819                                         goto __error;
2820                                 }
2821                         }
2822                         continue;
2823                 }
2824
2825                 snd_error(UCM, "unknown field '%s' in Variant section", id);
2826                 err = -EINVAL;
2827                 goto __error;
2828         }
2829
2830         if (_vfile)
2831                 *_vfile = file;
2832         if (_vcomment)
2833                 *_vcomment = comment;
2834         return 0;
2835
2836 __error:
2837         free(file);
2838         free(comment);
2839         return err;
2840 }
2841
2842 /*
2843  * Parse master section for "Use Case" and "File" tags.
2844  */
2845 static int parse_master_section(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg,
2846                                 void *data1 ATTRIBUTE_UNUSED,
2847                                 void *data2 ATTRIBUTE_UNUSED)
2848 {
2849         snd_config_iterator_t i, next;
2850         snd_config_t *n, *variant = NULL, *config = NULL;
2851         char *use_case_name, *file = NULL, *comment = NULL;
2852         bool variant_ok = false;
2853         int err;
2854
2855         if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
2856                 snd_error(UCM, "compound type expected for use case section");
2857                 return -EINVAL;
2858         }
2859
2860         err = parse_get_safe_name(uc_mgr, cfg, NULL, &use_case_name);
2861         if (err < 0) {
2862                 snd_error(UCM, "unable to get name for use case section");
2863                 return err;
2864         }
2865
2866         /* in-place evaluation */
2867         uc_mgr->parse_master_section = 1;
2868         err = uc_mgr_evaluate_inplace(uc_mgr, cfg);
2869         uc_mgr->parse_master_section = 0;
2870         if (err < 0)
2871                 goto __error;
2872
2873         /* parse master config sections */
2874         snd_config_for_each(i, next, cfg) {
2875                 const char *id;
2876                 n = snd_config_iterator_entry(i);
2877                 if (snd_config_get_id(n, &id) < 0)
2878                         continue;
2879
2880                 /* get use case verb file name */
2881                 if (strcmp(id, "File") == 0) {
2882                         err = parse_string_substitute3(uc_mgr, n, &file);
2883                         if (err < 0) {
2884                                 snd_error(UCM, "failed to get File");
2885                                 goto __error;
2886                         }
2887                         continue;
2888                 }
2889
2890                 /* get use case verb configuration block (syntax version 8+) */
2891                 if (strcmp(id, "Config") == 0) {
2892                         if (uc_mgr->conf_format < 8) {
2893                                 snd_error(UCM, "Config is supported in v8+ syntax");
2894                                 err = -EINVAL;
2895                                 goto __error;
2896                         }
2897                         if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
2898                                 snd_error(UCM, "compound type expected for Config");
2899                                 err = -EINVAL;
2900                                 goto __error;
2901                         }
2902                         config = n;
2903                         continue;
2904                 }
2905
2906                 /* get optional use case comment */
2907                 if (strncmp(id, "Comment", 7) == 0) {
2908                         err = parse_string_substitute3(uc_mgr, n, &comment);
2909                         if (err < 0) {
2910                                 snd_error(UCM, "failed to get Comment");
2911                                 goto __error;
2912                         }
2913                         continue;
2914                 }
2915
2916                 if (uc_mgr->conf_format >= 6 && strcmp(id, "Variant") == 0) {
2917                         snd_config_iterator_t i2, next2;
2918                         variant = n;
2919                         snd_config_for_each(i2, next2, n) {
2920                                 const char *id2;
2921                                 snd_config_t *n2;
2922                                 n2 = snd_config_iterator_entry(i2);
2923                                 if (snd_config_get_id(n2, &id2) < 0)
2924                                         continue;
2925                                 err = uc_mgr_evaluate_inplace(uc_mgr, n2);
2926                                 if (err < 0)
2927                                         goto __error;
2928                                 if (strcmp(use_case_name, id2) == 0)
2929                                         variant_ok = true;
2930                         }
2931                         continue;
2932                 }
2933
2934                 snd_error(UCM, "unknown field '%s' in SectionUseCase", id);
2935         }
2936
2937         if (variant && !variant_ok) {
2938                 snd_error(UCM, "undefined variant '%s'", use_case_name);
2939                 err = -EINVAL;
2940                 goto __error;
2941         }
2942
2943         /* check mutual exclusivity of File and Config */
2944         if (file && config) {
2945                 snd_error(UCM, "both File and Config specified in SectionUseCase");
2946                 err = -EINVAL;
2947                 goto __error;
2948         }
2949
2950         if (!variant) {
2951                 snd_debug(UCM, "use_case_name %s file '%s'", use_case_name, file);
2952
2953                 /* do we have both use case name and (file or config) ? */
2954                 if (!file && !config) {
2955                         snd_error(UCM, "use case missing file or config");
2956                         err = -EINVAL;
2957                         goto __error;
2958                 }
2959
2960                 /* parse verb from file or config */
2961                 if (file) {
2962                         snd_config_t *cfg;
2963                         /* load config from file */
2964                         err = uc_mgr_config_load_file(uc_mgr, file, &cfg, false);
2965                         if (err < 0)
2966                                 goto __error;
2967                         /* parse the config */
2968                         err = parse_verb_config(uc_mgr, use_case_name, comment, cfg, file);
2969                         snd_config_delete(cfg);
2970                 } else {
2971                         /* inline config - parse directly */
2972                         err = parse_verb_config(uc_mgr, use_case_name, comment, config,
2973                                                 comment ? comment : use_case_name);
2974                 }
2975         } else {
2976                 /* parse variants */
2977                 struct list_head orig_variable_list;
2978                 snd_config_t *orig_macros = NULL;
2979                 int first_iteration = 1;
2980
2981                 /* save original variable list */
2982                 err = uc_mgr_duplicate_variables(&orig_variable_list, &uc_mgr->variable_list);
2983                 if (err < 0)
2984                         goto __error;
2985
2986                 /* save original macros */
2987                 if (uc_mgr->macros) {
2988                         err = snd_config_copy(&orig_macros, uc_mgr->macros);
2989                         if (err < 0)
2990                                 goto __variant_error;
2991                 }
2992
2993                 snd_config_for_each(i, next, variant) {
2994                         char *vfile, *vcomment;
2995                         const char *id;
2996
2997                         /* restore variables and macros for second and later iterations */
2998                         if (!first_iteration) {
2999                                 uc_mgr_free_value(&uc_mgr->variable_list);
3000
3001                                 err = uc_mgr_duplicate_variables(&uc_mgr->variable_list, &orig_variable_list);
3002                                 if (err < 0)
3003                                         goto __variant_error;
3004
3005                                 if (uc_mgr->macros) {
3006                                         snd_config_delete(uc_mgr->macros);
3007                                         uc_mgr->macros = NULL;
3008                                 }
3009                                 if (orig_macros) {
3010                                         err = snd_config_copy(&uc_mgr->macros, orig_macros);
3011                                         if (err < 0)
3012                                                 goto __variant_error;
3013                                 }
3014                         }
3015                         first_iteration = 0;
3016
3017                         n = snd_config_iterator_entry(i);
3018                         if (snd_config_get_id(n, &id) < 0)
3019                                 continue;
3020                         if (!parse_is_name_safe(id)) {
3021                                 err = -EINVAL;
3022                                 goto __variant_error;
3023                         }
3024                         err = parse_variant(uc_mgr, n, &vfile, &vcomment);
3025                         if (err < 0)
3026                                 break;
3027                         uc_mgr->parse_variant = id;
3028                         if (vfile || file) {
3029                                 snd_config_t *cfg;
3030                                 const char *fname = vfile ? vfile : file;
3031                                 /* load config from file */
3032                                 err = uc_mgr_config_load_file(uc_mgr, fname, &cfg, false);
3033                                 if (err >= 0) {
3034                                         err = parse_verb_config(uc_mgr, id,
3035                                                                 vcomment ? vcomment : comment,
3036                                                                 cfg, fname);
3037                                         snd_config_delete(cfg);
3038                                 }
3039                         } else {
3040                                 /* inline config from variant */
3041                                 err = parse_verb_config(uc_mgr, id,
3042                                                         vcomment ? vcomment : comment,
3043                                                         config,
3044                                                         vcomment ? vcomment : (comment ? comment : id));
3045                         }
3046                         uc_mgr->parse_variant = NULL;
3047                         free(vfile);
3048                         free(vcomment);
3049                         if (err < 0)
3050                                 break;
3051                 }
3052
3053 __variant_error:
3054                 uc_mgr_free_value(&orig_variable_list);
3055                 if (orig_macros)
3056                         snd_config_delete(orig_macros);
3057         }
3058
3059 __error:
3060         free(use_case_name);
3061         free(file);
3062         free(comment);
3063         return err;
3064 }
3065
3066 /*
3067  * parse controls which should be run only at initial boot (forcefully)
3068  */
3069 static int parse_controls_fixedboot(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
3070 {
3071         int err;
3072
3073         if (!list_empty(&uc_mgr->fixedboot_list)) {
3074                 snd_error(UCM, "FixedBoot list is not empty");
3075                 return -EINVAL;
3076         }
3077         err = parse_sequence(uc_mgr, &uc_mgr->fixedboot_list, cfg);
3078         if (err < 0) {
3079                 snd_error(UCM, "Unable to parse FixedBootSequence");
3080                 return err;
3081         }
3082
3083         return 0;
3084 }
3085
3086 /*
3087  * parse controls which should be run only at initial boot
3088  */
3089 static int parse_controls_boot(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
3090 {
3091         int err;
3092
3093         if (!list_empty(&uc_mgr->boot_list)) {
3094                 snd_error(UCM, "Boot list is not empty");
3095                 return -EINVAL;
3096         }
3097         err = parse_sequence(uc_mgr, &uc_mgr->boot_list, cfg);
3098         if (err < 0) {
3099                 snd_error(UCM, "Unable to parse BootSequence");
3100                 return err;
3101         }
3102
3103         return 0;
3104 }
3105
3106 /*
3107  * parse controls
3108  */
3109 static int parse_controls(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
3110 {
3111         int err;
3112
3113         if (!list_empty(&uc_mgr->default_list)) {
3114                 snd_error(UCM, "Default list is not empty");
3115                 return -EINVAL;
3116         }
3117         err = parse_sequence(uc_mgr, &uc_mgr->default_list, cfg);
3118         if (err < 0) {
3119                 snd_error(UCM, "Unable to parse SectionDefaults");
3120                 return err;
3121         }
3122
3123         return 0;
3124 }
3125
3126 /*
3127  * Each sound card has a master sound card file that lists all the supported
3128  * use case verbs for that sound card. i.e.
3129  *
3130  * #Example master file for blah sound card
3131  * #By Joe Blogs <joe@bloggs.org>
3132  *
3133  * Comment "Nice Abstracted Soundcard"
3134  *
3135  * # The file is divided into Use case sections. One section per use case verb.
3136  *
3137  * SectionUseCase."Voice Call" {
3138  *      File "voice_call_blah"
3139  *      Comment "Make a voice phone call."
3140  * }
3141  *
3142  * SectionUseCase."HiFi" {
3143  *      File "hifi_blah"
3144  *      Comment "Play and record HiFi quality Music."
3145  * }
3146  *
3147  * # Define Value defaults
3148  *
3149  * ValueDefaults {
3150  *      PlaybackCTL "hw:CARD=0"
3151  *      CaptureCTL "hw:CARD=0"
3152  * }
3153  *
3154  * # The initial boot (run once) configuration.
3155  *
3156  * BootSequence [
3157  *      cset "name='Master Playback Switch',index=2 1,1"
3158  *      cset "name='Master Playback Volume',index=2 25,25"
3159  * ]
3160  *
3161  * # This file also stores the default sound card state.
3162  *
3163  * SectionDefaults [
3164  *      cset "name='Master Mono Playback',index=1 0"
3165  *      cset "name='Master Mono Playback Volume',index=1 0"
3166  *      cset "name='PCM Switch',index=2 1,1"
3167  *      exec "some binary here"
3168  *      msleep 50
3169  *      ........
3170  * ]
3171  *
3172  * # End of example file.
3173  */
3174 static int parse_master_file(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
3175 {
3176         snd_config_iterator_t i, next;
3177         snd_config_t *n;
3178         const char *id;
3179         int err;
3180
3181         if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
3182                 snd_error(UCM, "compound type expected for master file");
3183                 return -EINVAL;
3184         }
3185
3186         if (uc_mgr->conf_format >= 2) {
3187                 err = parse_syntax_field(uc_mgr, cfg, uc_mgr->conf_file_name);
3188                 if (err < 0)
3189                         return err;
3190         }
3191
3192         /* in-place evaluation */
3193         err = uc_mgr_evaluate_inplace(uc_mgr, cfg);
3194         if (err < 0)
3195                 return err;
3196
3197         /* parse ValueGlobals first */
3198         err = snd_config_search(cfg, "ValueGlobals", &n);
3199         if (err == 0) {
3200                 err = parse_value(uc_mgr, &uc_mgr->global_value_list, n);
3201                 if (err < 0) {
3202                         snd_error(UCM, "failed to parse ValueGlobals");
3203                         return err;
3204                 }
3205         }
3206
3207         err = uc_mgr_check_value(&uc_mgr->global_value_list, "BootCardGroup");
3208         if (err == 0) {
3209                 uc_mgr->card_group = true;
3210                 /* if we are in boot, skip the main parsing loop */
3211                 if (uc_mgr->in_boot)
3212                         return 0;
3213         }
3214
3215         /* parse master config sections */
3216         snd_config_for_each(i, next, cfg) {
3217
3218                 n = snd_config_iterator_entry(i);
3219                 if (snd_config_get_id(n, &id) < 0)
3220                         continue;
3221
3222                 if (strcmp(id, "Comment") == 0) {
3223                         err = parse_string_substitute3(uc_mgr, n, &uc_mgr->comment);
3224                         if (err < 0) {
3225                                 snd_error(UCM, "failed to get master comment");
3226                                 return err;
3227                         }
3228                         continue;
3229                 }
3230
3231                 /* find use case section and parse it */
3232                 if (strcmp(id, "SectionUseCase") == 0) {
3233                         err = parse_compound(uc_mgr, n,
3234                                              parse_master_section,
3235                                              NULL, NULL);
3236                         if (err < 0)
3237                                 return err;
3238                         continue;
3239                 }
3240
3241                 /* find default control values section (force boot sequence only) */
3242                 if (strcmp(id, "FixedBootSequence") == 0) {
3243                         err = parse_controls_fixedboot(uc_mgr, n);
3244                         if (err < 0)
3245                                 return err;
3246                         continue;
3247                 }
3248
3249                 /* find default control values section (first boot only) */
3250                 if (strcmp(id, "BootSequence") == 0) {
3251                         err = parse_controls_boot(uc_mgr, n);
3252                         if (err < 0)
3253                                 return err;
3254                         continue;
3255                 }
3256
3257                 /* find default control values section and parse it */
3258                 if (strcmp(id, "SectionDefaults") == 0) {
3259                         err = parse_controls(uc_mgr, n);
3260                         if (err < 0)
3261                                 return err;
3262                         continue;
3263                 }
3264
3265                 /* ValueDefaults is now parsed at the top of this function */
3266                 if (strcmp(id, "ValueDefaults") == 0) {
3267                         err = parse_value(uc_mgr, &uc_mgr->value_list, n);
3268                         if (err < 0) {
3269                                 snd_error(UCM, "failed to parse ValueDefaults");
3270                                 return err;
3271                         }
3272                         continue;
3273                 }
3274
3275                 /* ValueGlobals is parsed at the top of this function */
3276                 if (strcmp(id, "ValueGlobals") == 0)
3277                         continue;
3278
3279                 /* alsa-lib configuration */
3280                 if (uc_mgr->conf_format > 3 && strcmp(id, "LibraryConfig") == 0) {
3281                         err = parse_libconfig(uc_mgr, n);
3282                         if (err < 0) {
3283                                 snd_error(UCM, "failed to parse LibraryConfig");
3284                                 return err;
3285                         }
3286                         continue;
3287                 }
3288
3289                 /* error */
3290                 if (strcmp(id, "Error") == 0)
3291                         return error_node(uc_mgr, n);
3292
3293                 /* skip further Syntax value updates (Include) */
3294                 if (strcmp(id, "Syntax") == 0)
3295                         continue;
3296
3297                 snd_error(UCM, "unknown master file field %s", id);
3298         }
3299         return 0;
3300 }
3301
3302 /* get the card info */
3303 static int get_card_info(snd_use_case_mgr_t *mgr,
3304                          const char *ctl_name,
3305                          snd_ctl_card_info_t **info)
3306 {
3307         struct ctl_list *ctl_list;
3308         int err;
3309
3310         err = uc_mgr_open_ctl(mgr, &ctl_list, ctl_name, 0);
3311         if (err < 0)
3312                 return err;
3313
3314         if (info)
3315                 *info = ctl_list->ctl_info;
3316         return err;
3317 }
3318
3319 /* find the card in the local machine */
3320 static int get_by_card_name(snd_use_case_mgr_t *mgr, const char *card_name)
3321 {
3322         int card, err;
3323         snd_ctl_card_info_t *info;
3324         const char *_driver, *_name, *_long_name;
3325
3326         snd_ctl_card_info_alloca(&info);
3327
3328         card = -1;
3329         if (snd_card_next(&card) < 0 || card < 0) {
3330                 snd_error(UCM, "no soundcards found...");
3331                 return -1;
3332         }
3333
3334         while (card >= 0) {
3335                 char name[32];
3336
3337                 /* clear the list, keep the only one CTL device */
3338                 uc_mgr_free_ctl_list(mgr);
3339
3340                 sprintf(name, "hw:%d", card);
3341                 err = get_card_info(mgr, name, &info);
3342
3343                 if (err == 0) {
3344                         _driver = snd_ctl_card_info_get_driver(info);
3345                         _name = snd_ctl_card_info_get_name(info);
3346                         _long_name = snd_ctl_card_info_get_longname(info);
3347                         if (!strcmp(card_name, _driver) ||
3348                             !strcmp(card_name, _name) ||
3349                             !strcmp(card_name, _long_name))
3350                                 return 0;
3351                 }
3352
3353                 if (snd_card_next(&card) < 0) {
3354                         snd_error(UCM, "snd_card_next");
3355                         break;
3356                 }
3357         }
3358
3359         uc_mgr_free_ctl_list(mgr);
3360
3361         return -1;
3362 }
3363
3364 /* set the driver name and long name by the card ctl name */
3365 static inline int get_by_card(snd_use_case_mgr_t *mgr, const char *ctl_name)
3366 {
3367         return get_card_info(mgr, ctl_name, NULL);
3368 }
3369
3370 static int parse_toplevel_path(snd_use_case_mgr_t *uc_mgr,
3371                                char *filename,
3372                                snd_config_t *cfg)
3373 {
3374         snd_config_iterator_t i, next, i2, next2;
3375         snd_config_t *n, *n2;
3376         const char *id;
3377         char *dir = NULL, *file = NULL, fn[PATH_MAX];
3378         struct stat64 st;
3379         long version;
3380         int err;
3381
3382         if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
3383                 snd_error(UCM, "compound type expected for UseCasePath node");
3384                 return -EINVAL;
3385         }
3386
3387         /* parse use case path config sections */
3388         snd_config_for_each(i, next, cfg) {
3389                 n = snd_config_iterator_entry(i);
3390
3391                 if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
3392                         snd_error(UCM, "compound type expected for UseCasePath.something node");
3393                         return -EINVAL;
3394                 }
3395
3396                         if (snd_config_get_id(n, &id) < 0)
3397                                 continue;
3398
3399                 version = 2;
3400
3401                 /* parse use case path config sections */
3402                 snd_config_for_each(i2, next2, n) {
3403
3404                         n2 = snd_config_iterator_entry(i2);
3405                         if (snd_config_get_id(n2, &id) < 0)
3406                                 continue;
3407
3408                         if (strcmp(id, "Version") == 0) {
3409                                 err = parse_integer_substitute(uc_mgr, n2, &version);
3410                                 if (err < 0) {
3411                                         snd_error(UCM, "unable to parse UcmDirectory");
3412                                         goto __error;
3413                                 }
3414                                 if (version < 1 || version > 2) {
3415                                         snd_error(UCM, "Version must be 1 or 2");
3416                                         err = -EINVAL;
3417                                         goto __error;
3418                                 }
3419                                 continue;
3420                         }
3421
3422                         if (strcmp(id, "Directory") == 0) {
3423                                 err = parse_string_substitute(uc_mgr, n2, &dir);
3424                                 if (err < 0) {
3425                                         snd_error(UCM, "unable to parse Directory");
3426                                         goto __error;
3427                                 }
3428                                 continue;
3429                         }
3430
3431                         if (strcmp(id, "File") == 0) {
3432                                 err = parse_string_substitute(uc_mgr, n2, &file);
3433                                 if (err < 0) {
3434                                         snd_error(UCM, "unable to parse File");
3435                                         goto __error;
3436                                 }
3437                                 continue;
3438                         }
3439
3440                         snd_error(UCM, "unknown UseCasePath field %s", id);
3441                 }
3442
3443                 if (dir == NULL) {
3444                         snd_error(UCM, "Directory is not defined in %s!", filename);
3445                         goto __next;
3446                 }
3447                 if (file == NULL) {
3448                         snd_error(UCM, "File is not defined in %s!", filename);
3449                         goto __next;
3450                 }
3451
3452                 if (ucm_filename(fn, sizeof(fn), version, dir, file) < 0)
3453                         goto __next;
3454                 snd_trace(UCM, "probing configuration file '%s'", fn);
3455                 if (access(fn, R_OK) == 0 && lstat64(fn, &st) == 0) {
3456                         if (S_ISLNK(st.st_mode)) {
3457                                 ssize_t r;
3458                                 char *link, *dir2, *p;
3459
3460                                 link = malloc(PATH_MAX);
3461                                 if (link == NULL)
3462                                         goto __enomem;
3463                                 r = readlink(fn, link, PATH_MAX - 1);
3464                                 if (r <= 0) {
3465                                         free(link);
3466                                         goto __next;
3467                                 }
3468                                 link[r] = '\0';
3469                                 p = strrchr(link, '/');
3470                                 if (p) {
3471                                         *p = '\0';
3472                                         dir2 = malloc(PATH_MAX);
3473                                         if (dir2 == NULL) {
3474                                                 free(link);
3475                                                 goto __enomem;
3476                                         }
3477                                         strncpy(dir2, dir, PATH_MAX - 1);
3478                                         strncat(dir2, "/", PATH_MAX - 1);
3479                                         strncat(dir2, link, PATH_MAX - 1);
3480                                         fn[PATH_MAX - 1] = '\0';
3481                                         free(dir);
3482                                         dir = dir2;
3483                                 }
3484                                 free(link);
3485                         }
3486                         snd_trace(UCM, "using directory '%s' and file '%s'", dir, file);
3487                         if (replace_string(&uc_mgr->conf_dir_name, dir) == NULL)
3488                                 goto __enomem;
3489                         if (replace_string(&uc_mgr->conf_file_name, file) == NULL)
3490                                 goto __enomem;
3491                         strncpy(filename, fn, PATH_MAX);
3492                         filename[PATH_MAX - 1] = '\0';
3493                         uc_mgr->conf_format = version;
3494                         goto __ok;
3495                 }
3496
3497 __next:
3498                 free(file);
3499                 if (dir != fn)
3500                         free(dir);
3501                 dir = NULL;
3502                 file = NULL;
3503         }
3504
3505         err = -ENOENT;
3506         goto __error;
3507
3508 __enomem:
3509         err = -ENOMEM;
3510         goto __error;
3511
3512 __ok:
3513         err = 0;
3514 __error:
3515         free(file);
3516         if (dir != fn)
3517                 free(dir);
3518         return err;
3519 }
3520
3521 static int parse_toplevel_config(snd_use_case_mgr_t *uc_mgr,
3522                                  char *filename,
3523                                  snd_config_t *cfg)
3524 {
3525         snd_config_iterator_t i, next;
3526         snd_config_t *n;
3527         const char *id;
3528         int err;
3529
3530         if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
3531                 snd_error(UCM, "compound type expected for toplevel file");
3532                 return -EINVAL;
3533         }
3534
3535         err = parse_syntax_field(uc_mgr, cfg, filename);
3536         if (err < 0)
3537                 return err;
3538
3539         /* in-place evaluation */
3540         err = uc_mgr_evaluate_inplace(uc_mgr, cfg);
3541         if (err < 0)
3542                 return err;
3543
3544         /* parse toplevel config sections */
3545         snd_config_for_each(i, next, cfg) {
3546
3547                 n = snd_config_iterator_entry(i);
3548                 if (snd_config_get_id(n, &id) < 0)
3549                         continue;
3550
3551                 if (strcmp(id, "UseCasePath") == 0) {
3552                         err = parse_toplevel_path(uc_mgr, filename, n);
3553                         if (err == 0)
3554                                 return err;
3555                         continue;
3556                 }
3557
3558                 /* alsa-lib configuration */
3559                 if (uc_mgr->conf_format > 3 && strcmp(id, "LibraryConfig") == 0) {
3560                         err = parse_libconfig(uc_mgr, n);
3561                         if (err < 0) {
3562                                 snd_error(UCM, "failed to parse LibConfig");
3563                                 return err;
3564                         }
3565                         continue;
3566                 }
3567
3568                 /* skip further Syntax value updates (Include) */
3569                 if (strcmp(id, "Syntax") == 0)
3570                         continue;
3571
3572                 snd_error(UCM, "unknown toplevel field %s", id);
3573         }
3574
3575         return -ENOENT;
3576 }
3577
3578 static int load_toplevel_config(snd_use_case_mgr_t *uc_mgr,
3579                                 snd_config_t **cfg)
3580 {
3581         char filename[PATH_MAX];
3582         snd_config_t *tcfg;
3583         int err;
3584
3585         ucm_filename(filename, sizeof(filename), 2, NULL, "ucm.conf");
3586
3587         if (access(filename, R_OK) != 0) {
3588                 snd_error(UCM, "Unable to find the top-level configuration file '%s'.", filename);
3589                 return -ENOENT;
3590         }
3591
3592         err = uc_mgr_config_load(2, filename, &tcfg, false);
3593         if (err < 0)
3594                 goto __error;
3595
3596         /* filename is shared for function input and output! */
3597         err = parse_toplevel_config(uc_mgr, filename, tcfg);
3598         snd_config_delete(tcfg);
3599         if (err < 0)
3600                 goto __error;
3601
3602         err = uc_mgr_config_load(uc_mgr->conf_format, filename, cfg, false);
3603         if (err < 0) {
3604                 snd_error(UCM, "could not parse configuration for card %s", uc_mgr->card_name);
3605                 goto __error;
3606         }
3607
3608         return 0;
3609
3610 __error:
3611         return err;
3612 }
3613
3614 /* load master use case file for sound card based on rules in ucm2/ucm.conf
3615  */
3616 int uc_mgr_import_master_config(snd_use_case_mgr_t *uc_mgr)
3617 {
3618         snd_config_t *cfg;
3619         const char *name;
3620         int err;
3621
3622         err = snd_config_top(&uc_mgr->local_config);
3623         if (err < 0)
3624                 return err;
3625
3626         err = snd_config_top(&uc_mgr->macros);
3627         if (err < 0)
3628                 return err;
3629
3630         name = uc_mgr->card_name;
3631         if (strncmp(name, "hw:", 3) == 0) {
3632                 err = get_by_card(uc_mgr, name);
3633                 if (err < 0) {
3634                         snd_error(UCM, "card '%s' is not valid", name);
3635                         goto __error;
3636                 }
3637         } else if (strncmp(name, "strict:", 7)) {
3638                 /* do not handle the error here */
3639                 /* we can refer the virtual UCM config */
3640                 get_by_card_name(uc_mgr, name);
3641         }
3642
3643         err = load_toplevel_config(uc_mgr, &cfg);
3644         if (err < 0)
3645                 goto __error;
3646
3647         err = parse_master_file(uc_mgr, cfg);
3648         if (uc_mgr->macros) {
3649                 snd_config_delete(uc_mgr->macros);
3650                 uc_mgr->macros = NULL;
3651         }
3652         snd_config_delete(cfg);
3653         if (err < 0) {
3654                 uc_mgr_free_ctl_list(uc_mgr);
3655                 uc_mgr_free_verb(uc_mgr);
3656         }
3657
3658         return err;
3659
3660 __error:
3661         uc_mgr_free_ctl_list(uc_mgr);
3662         replace_string(&uc_mgr->conf_dir_name, NULL);
3663         return err;
3664 }
3665
3666 static int filename_filter(const struct dirent64 *dirent)
3667 {
3668         if (dirent == NULL)
3669                 return 0;
3670         if (dirent->d_type == DT_DIR) {
3671                 if (dirent->d_name[0] == '.') {
3672                         if (dirent->d_name[1] == '\0')
3673                                 return 0;
3674                         if (dirent->d_name[1] == '.' &&
3675                             dirent->d_name[2] == '\0')
3676                                 return 0;
3677                 }
3678                 return 1;
3679         }
3680         return 0;
3681 }
3682
3683 /* scan all cards and comments
3684  *
3685  * Cards are defined by machines. Each card/machine installs its UCM
3686  * configuration files in a subdirectory with the same name as the sound
3687  * card under /usr/share/alsa/ucm2. This function will scan all the card
3688  * directories and skip the component directories defined in the array
3689  * component_dir.
3690  */
3691 int uc_mgr_scan_master_configs(const char **_list[])
3692 {
3693         char filename[PATH_MAX], dfl[PATH_MAX], fn[FILENAME_MAX];
3694         char *env = getenv(ALSA_CONFIG_UCM2_VAR);
3695         snd_use_case_mgr_t *uc_mgr;
3696         const char **list, *d_name;
3697         char *s;
3698         snd_config_t *cfg, *c;
3699         int i, j, cnt, err, cards;
3700         long l;
3701         ssize_t ss;
3702         struct dirent64 **namelist;
3703
3704         i = -1;
3705         cards = 0;
3706         while (1) {
3707                 err = snd_card_next(&i);
3708                 if (err < 0)
3709                         return err;
3710                 if (i < 0)
3711                         break;
3712                 cards++;
3713         }
3714         cards += 4;     /* plug-and-play */
3715
3716         if (env)
3717                 snprintf(filename, sizeof(filename), "%s/conf.virt.d", env);
3718         else
3719                 snprintf(filename, sizeof(filename), "%s/ucm2/conf.virt.d",
3720                          snd_config_topdir());
3721
3722 #if defined(_GNU_SOURCE) && \
3723     !defined(__NetBSD__) && \
3724     !defined(__FreeBSD__) && \
3725     !defined(__OpenBSD__) && \
3726     !defined(__DragonFly__) && \
3727     !defined(__sun) && \
3728     !defined(__ANDROID__) && \
3729     !defined(__OHOS__)
3730 #define SORTFUNC        versionsort64
3731 #else
3732 #define SORTFUNC        alphasort64
3733 #endif
3734         err = scandir64(filename, &namelist, filename_filter, SORTFUNC);
3735         if (err < 0) {
3736                 err = -errno;
3737                 snd_error(UCM, "could not scan directory %s: %s", filename, strerror(-err));
3738                 return err;
3739         }
3740         cnt = err;
3741
3742         dfl[0] = '\0';
3743         if (strlen(filename) + 8 < sizeof(filename)) {
3744                 strcat(filename, "/default");
3745                 ss = readlink(filename, dfl, sizeof(dfl)-1);
3746                 if (ss >= 0) {
3747                         dfl[ss] = '\0';
3748                         dfl[sizeof(dfl)-1] = '\0';
3749                         if (dfl[0] && dfl[strlen(dfl)-1] == '/')
3750                                 dfl[strlen(dfl)-1] = '\0';
3751                 } else {
3752                         dfl[0] = '\0';
3753                 }
3754         }
3755
3756         j = 0;
3757         list = calloc(1, (cards + cnt) * 2 * sizeof(char *));
3758         if (list == NULL) {
3759                 err = -ENOMEM;
3760                 goto __err;
3761         }
3762
3763         i = -1;
3764         while (j / 2 < cards) {
3765                 err = snd_card_next(&i);
3766                 if (err < 0)
3767                         goto __err;
3768                 if (i < 0)
3769                         break;
3770                 snprintf(fn, sizeof(fn), "-hw:%d", i);
3771                 err = snd_use_case_mgr_open(&uc_mgr, fn);
3772                 if (err == -ENOENT || err == -ENXIO)
3773                         continue;
3774                 if (err < 0) {
3775                         snd_error(UCM, "Unable to open '%s': %s", fn, snd_strerror(err));
3776                         goto __err;
3777                 }
3778                 err = snd_use_case_get(uc_mgr, "comment", (const char **)&s);
3779                 if (err < 0) {
3780                         err = snd_card_get_longname(i, &s);
3781                         if (err < 0)
3782                                 goto __err;
3783                 }
3784                 snd_use_case_mgr_close(uc_mgr);
3785                 list[j] = strdup(fn + 1);
3786                 if (list[j] == NULL) {
3787                         free(s);
3788                         err = -ENOMEM;
3789                         goto __err;
3790                 }
3791                 list[j + 1] = s;
3792                 j += 2;
3793         }
3794
3795         for (i = 0; i < cnt; i++) {
3796
3797                 d_name = namelist[i]->d_name;
3798
3799                 snprintf(fn, sizeof(fn), "%s.conf", d_name);
3800                 if (ucm_filename(filename, sizeof(filename), 2, d_name, fn) < 0)
3801                         continue;
3802 #ifdef HAVE_EACCESS
3803                 if (eaccess(filename, R_OK))
3804 #else
3805                 if (access(filename, R_OK))
3806 #endif
3807                         continue;
3808
3809                 err = uc_mgr_config_load(2, filename, &cfg, false);
3810                 if (err < 0)
3811                         goto __err;
3812                 err = snd_config_search(cfg, "Syntax", &c);
3813                 if (err < 0) {
3814                         snd_error(UCM, "Syntax field not found in %s", d_name);
3815                         snd_config_delete(cfg);
3816                         continue;
3817                 }
3818                 err = snd_config_get_integer(c, &l);
3819                 if (err < 0) {
3820                         snd_error(UCM, "Syntax field is invalid in %s", d_name);
3821                         snd_config_delete(cfg);
3822                         goto __err;
3823                 }
3824                 if (l < 2 || l > SYNTAX_VERSION_MAX) {
3825                         snd_error(UCM, "Incompatible syntax %d in %s", l, d_name);
3826                         snd_config_delete(cfg);
3827                         goto __err;
3828                 }
3829                 err = snd_config_search(cfg, "Comment", &c);
3830                 if (err >= 0) {
3831                         err = parse_string(c, (char **)&list[j+1]);
3832                         if (err < 0) {
3833                                 snd_config_delete(cfg);
3834                                 goto __err;
3835                         }
3836                 }
3837                 snd_config_delete(cfg);
3838                 list[j] = strdup(d_name);
3839                 if (list[j] == NULL) {
3840                         err = -ENOMEM;
3841                         goto __err;
3842                 }
3843                 if (strcmp(dfl, list[j]) == 0) {
3844                         /* default to top */
3845                         const char *save1 = list[j];
3846                         const char *save2 = list[j + 1];
3847                         memmove(list + 2, list, j * sizeof(char *));
3848                         list[0] = save1;
3849                         list[1] = save2;
3850                 }
3851                 j += 2;
3852         }
3853         err = 0;
3854
3855       __err:
3856         for (i = 0; i < cnt; i++)
3857                 free(namelist[i]);
3858         free(namelist);
3859         if (err < 0) {
3860                 for (i = 0; i < j; i++) {
3861                         free((void *)list[i * 2]);
3862                         free((void *)list[i * 2 + 1]);
3863                 }
3864                 free(list);
3865                 return err;
3866         }
3867
3868         *_list = list;
3869         return j;
3870 }