OSDN Git Service

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