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