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.
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.
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
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.
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>
33 #include "ucm_local.h"
39 static int filename_filter(const struct dirent64 *dirent);
41 static int parse_sequence(snd_use_case_mgr_t *uc_mgr,
42 struct list_head *base,
46 * compose the absolute ucm filename
48 static void ucm_filename(char *fn, size_t fn_len, long version,
49 const char *dir, const char *file)
51 const char *env = getenv(version > 1 ? ALSA_CONFIG_UCM2_VAR : ALSA_CONFIG_UCM_VAR);
56 snprintf(fn, fn_len, "%s/%s/%s%s%s",
57 snd_config_topdir(), version > 1 ? "ucm2" : "ucm",
58 dir ?: "", dir ? "/" : "", file);
60 snprintf(fn, fn_len, "%s/%s%s%s",
61 env, dir ?: "", dir ? "/" : "", file);
67 int uc_mgr_config_load_file(snd_use_case_mgr_t *uc_mgr,
68 const char *file, snd_config_t **cfg)
70 char filename[PATH_MAX];
73 ucm_filename(filename, sizeof(filename), uc_mgr->conf_format,
74 file[0] == '/' ? NULL : uc_mgr->conf_dir_name,
76 err = uc_mgr_config_load(uc_mgr->conf_format, filename, cfg);
78 snd_error(UCM, "failed to open file %s: %d", filename, err);
85 * Replace mallocated string
87 static char *replace_string(char **dst, const char *value)
90 *dst = value ? strdup(value) : NULL;
97 static int parse_string(snd_config_t *n, char **res)
101 err = snd_config_get_string(n, (const char **)res);
111 * Parse string and substitute
113 static int parse_string_substitute(snd_use_case_mgr_t *uc_mgr,
114 snd_config_t *n, char **res)
120 err = snd_config_get_string(n, &str);
123 err = uc_mgr_get_substituted_value(uc_mgr, &s, str);
130 * Parse string and substitute
132 static int parse_string_substitute3(snd_use_case_mgr_t *uc_mgr,
133 snd_config_t *n, char **res)
135 if (uc_mgr->conf_format < 3)
136 return parse_string(n, res);
137 return parse_string_substitute(uc_mgr, n, res);
141 * Parse integer with substitution
143 static int parse_integer_substitute(snd_use_case_mgr_t *uc_mgr,
144 snd_config_t *n, long *res)
149 err = snd_config_get_ascii(n, &s1);
152 err = uc_mgr_get_substituted_value(uc_mgr, &s2, s1);
154 err = safe_strtol(s2, res);
161 * Parse integer with substitution
163 static int parse_integer_substitute3(snd_use_case_mgr_t *uc_mgr,
164 snd_config_t *n, long *res)
169 err = snd_config_get_ascii(n, &s1);
172 if (uc_mgr->conf_format < 3)
175 err = uc_mgr_get_substituted_value(uc_mgr, &s2, s1);
177 err = safe_strtol(s2, res);
187 static int parse_is_name_safe(const char *name)
189 if (strchr(name, '.')) {
190 snd_error(UCM, "char '.' not allowed in '%s'", name);
196 static int get_string3(snd_use_case_mgr_t *uc_mgr, const char *s1, char **s)
198 if (uc_mgr->conf_format < 3) {
204 return uc_mgr_get_substituted_value(uc_mgr, s, s1);
207 static int parse_get_safe_name(snd_use_case_mgr_t *uc_mgr, snd_config_t *n,
208 const char *alt, char **name)
216 err = snd_config_get_id(n, &id);
220 err = get_string3(uc_mgr, id, name);
223 if (!parse_is_name_safe(*name)) {
231 * Handle 'Error' configuration node.
233 static int error_node(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
238 err = parse_string_substitute3(uc_mgr, cfg, &s);
240 snd_error(UCM, "failed to get Error string");
243 if (!uc_mgr->suppress_nodev_errors)
244 snd_error(UCM, "%s", s);
252 static int parse_syntax_field(snd_use_case_mgr_t *uc_mgr,
253 snd_config_t *cfg, const char *filename)
259 err = snd_config_search(cfg, "Syntax", &n);
261 snd_error(UCM, "Syntax field not found in %s", filename);
264 err = snd_config_get_integer(n, &l);
266 snd_error(UCM, "Syntax field is invalid in %s", filename);
269 if (l < 2 || l > SYNTAX_VERSION_MAX) {
270 snd_error(UCM, "Incompatible syntax %ld in %s", l, filename);
273 /* delete this field to optimize strcmp() call in the parsing loop */
274 snd_config_delete(n);
275 uc_mgr->conf_format = l;
280 * Evaluate variable regex definitions (in-place delete)
282 static int evaluate_regex(snd_use_case_mgr_t *uc_mgr,
285 snd_config_iterator_t i, next;
290 err = snd_config_search(cfg, "DefineRegex", &d);
296 if (snd_config_get_type(d) != SND_CONFIG_TYPE_COMPOUND) {
297 snd_error(UCM, "compound type expected for DefineRegex");
301 if (uc_mgr->conf_format < 3) {
302 snd_error(UCM, "DefineRegex is supported in v3+ syntax");
306 snd_config_for_each(i, next, d) {
307 n = snd_config_iterator_entry(i);
308 err = snd_config_get_id(n, &id);
312 snd_error(UCM, "value names starting with '@' are reserved for application variables");
315 err = uc_mgr_define_regex(uc_mgr, id, n);
320 snd_config_delete(d);
325 * Evaluate variable definitions (in-place delete)
327 static int evaluate_define(snd_use_case_mgr_t *uc_mgr,
330 snd_config_iterator_t i, next;
336 err = snd_config_search(cfg, "Define", &d);
338 return evaluate_regex(uc_mgr, cfg);
342 if (snd_config_get_type(d) != SND_CONFIG_TYPE_COMPOUND) {
343 snd_error(UCM, "compound type expected for Define");
347 if (uc_mgr->conf_format < 3) {
348 snd_error(UCM, "Define is supported in v3+ syntax");
352 snd_config_for_each(i, next, d) {
353 n = snd_config_iterator_entry(i);
354 err = snd_config_get_id(n, &id);
357 err = snd_config_get_ascii(n, &var);
360 err = uc_mgr_get_substituted_value(uc_mgr, &s, var);
366 snd_error(UCM, "value names starting with '@' are reserved for application variables");
369 err = uc_mgr_set_variable(uc_mgr, id, s);
375 snd_config_delete(d);
377 return evaluate_regex(uc_mgr, cfg);
381 * Evaluate macro definitions (in-place delete)
383 static int evaluate_define_macro(snd_use_case_mgr_t *uc_mgr,
389 err = snd_config_search(cfg, "DefineMacro", &d);
395 if (snd_config_get_type(d) != SND_CONFIG_TYPE_COMPOUND) {
396 snd_error(UCM, "compound type expected for DefineMacro");
400 if (uc_mgr->conf_format < 6) {
401 snd_error(UCM, "DefineMacro is supported in v6+ syntax");
405 err = snd_config_merge(uc_mgr->macros, d, 0);
411 static int evaluate_macro1(snd_use_case_mgr_t *uc_mgr,
415 snd_config_iterator_t i, next;
416 snd_config_t *m, *mc, *a, *n;
417 const char *mid, *id;
418 char name[128], *var, *var2;
422 err = snd_config_get_id(args, &mid);
425 err = snd_config_search(uc_mgr->macros, mid, &m);
427 snd_error(UCM, "Macro '%s' is not defined", mid);
432 if (snd_config_get_type(args) == SND_CONFIG_TYPE_STRING) {
433 err = snd_config_get_string(args, &s);
436 err = snd_config_load_string(&a, s, 0);
439 } else if (snd_config_get_type(args) != SND_CONFIG_TYPE_COMPOUND) {
444 snd_config_for_each(i, next, a) {
445 n = snd_config_iterator_entry(i);
446 err = snd_config_get_id(n, &id);
449 snprintf(name, sizeof(name), "__%s", id);
450 if (uc_mgr_get_variable(uc_mgr, name)) {
451 snd_error(UCM, "Macro argument '%s' is already defined", name);
454 err = snd_config_get_ascii(n, &var);
457 if (uc_mgr->conf_format < 7) {
458 err = uc_mgr_set_variable(uc_mgr, name, var);
461 err = uc_mgr_get_substituted_value(uc_mgr, &var2, var);
464 err = uc_mgr_set_variable(uc_mgr, name, var2);
472 /* merge + substitute variables */
473 err = snd_config_copy(&mc, m);
476 err = uc_mgr_evaluate_inplace(uc_mgr, mc);
478 snd_config_delete(mc);
481 err = uc_mgr_config_tree_merge(uc_mgr, dst, mc, NULL, NULL);
482 snd_config_delete(mc);
484 /* delete arguments */
485 snd_config_for_each(i, next, a) {
486 n = snd_config_iterator_entry(i);
487 err = snd_config_get_id(n, &id);
490 snprintf(name, sizeof(name), "__%s", id);
491 err = uc_mgr_delete_variable(uc_mgr, name);
498 snd_config_delete(a);
503 * Evaluate macro definitions and instances (in-place delete)
505 static int evaluate_macro(snd_use_case_mgr_t *uc_mgr,
508 snd_config_iterator_t i, i2, next, next2;
509 snd_config_t *d, *n, *n2;
512 ret = evaluate_define_macro(uc_mgr, cfg);
516 err = snd_config_search(cfg, "Macro", &d);
522 if (snd_config_get_type(d) != SND_CONFIG_TYPE_COMPOUND) {
523 snd_error(UCM, "compound type expected for DefineMacro");
527 if (uc_mgr->conf_format < 6) {
528 snd_error(UCM, "Macro is supported in v6+ syntax");
532 snd_config_for_each(i, next, d) {
533 n = snd_config_iterator_entry(i);
534 if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
536 if (snd_config_get_id(n, &id))
538 snd_error(UCM, "compound type expected for Macro.%s", id);
541 snd_config_for_each(i2, next2, n) {
542 n2 = snd_config_iterator_entry(i2);
543 err = evaluate_macro1(uc_mgr, cfg, n2);
549 snd_config_delete(d);
555 * Evaluate include (in-place)
557 static int evaluate_include(snd_use_case_mgr_t *uc_mgr,
563 err = snd_config_search(cfg, "Include", &n);
569 err = uc_mgr_evaluate_include(uc_mgr, cfg, n);
570 snd_config_delete(n);
575 * Evaluate condition (in-place)
577 static int evaluate_condition(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
582 err = snd_config_search(cfg, "If", &n);
588 err = uc_mgr_evaluate_condition(uc_mgr, cfg, n);
589 snd_config_delete(n);
594 * Evaluate variant (in-place)
596 static int evaluate_variant(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
598 snd_config_iterator_t i, next;
603 err = snd_config_search(cfg, "Variant", &c);
609 if (uc_mgr->conf_format < 6) {
610 snd_error(UCM, "Variant is supported in v6+ syntax");
614 if (uc_mgr->parse_master_section)
617 if (uc_mgr->parse_variant == NULL)
620 snd_config_for_each(i, next, c) {
621 n = snd_config_iterator_entry(i);
623 if (snd_config_get_id(n, &id) < 0)
626 if (strcmp(id, uc_mgr->parse_variant))
629 err = uc_mgr_evaluate_inplace(uc_mgr, n);
633 err = uc_mgr_config_tree_merge(uc_mgr, cfg, n, NULL, NULL);
636 snd_config_delete(c);
641 snd_config_delete(c);
648 int uc_mgr_evaluate_inplace(snd_use_case_mgr_t *uc_mgr,
651 long iterations = 10000;
652 int err1 = 0, err2 = 0, err3 = 0, err4 = 0, err5 = 0;
654 while (err1 == 0 || err2 == 0 || err3 == 0 || err4 == 0 || err5 == 0) {
655 if (iterations == 0) {
656 snd_error(UCM, "Maximal inplace evaluation iterations number reached (recursive references?)");
660 /* variables at first */
661 err1 = evaluate_define(uc_mgr, cfg);
664 /* include at second */
665 err2 = evaluate_include(uc_mgr, cfg);
668 /* include or macro may define another variables */
669 /* conditions may depend on them */
672 err3 = evaluate_variant(uc_mgr, cfg);
677 uc_mgr->macro_hops++;
678 if (uc_mgr->macro_hops > 100) {
679 snd_error(UCM, "Maximal macro hops reached!");
682 err4 = evaluate_macro(uc_mgr, cfg);
683 uc_mgr->macro_hops--;
688 err5 = evaluate_condition(uc_mgr, cfg);
696 * Parse one item for alsa-lib config
698 static int parse_libconfig1(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
700 snd_config_iterator_t i, next;
701 snd_config_t *n, *config = NULL;
702 const char *id, *file = NULL;
703 bool substfile = false, substconfig = false;
706 if (snd_config_get_id(cfg, &id) < 0)
709 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
710 snd_error(UCM, "compound type expected for %s", id);
714 snd_config_for_each(i, next, cfg) {
715 n = snd_config_iterator_entry(i);
717 if (snd_config_get_id(n, &id) < 0)
720 if (strcmp(id, "File") == 0 ||
721 strcmp(id, "SubstiFile") == 0) {
722 substfile = id[0] == 'S';
723 err = snd_config_get_string(n, &file);
729 if (strcmp(id, "Config") == 0 ||
730 strcmp(id, "SubstiConfig") == 0) {
731 substconfig = id[0] == 'S';
732 if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND)
738 snd_error(UCM, "unknown field %s", id);
745 err = uc_mgr_config_load(uc_mgr->conf_format, file, &cfg);
748 err = uc_mgr_substitute_tree(uc_mgr, cfg);
750 snd_config_delete(cfg);
753 err = snd_config_merge(uc_mgr->local_config, cfg, 0);
755 snd_config_delete(cfg);
759 char filename[PATH_MAX];
761 ucm_filename(filename, sizeof(filename), uc_mgr->conf_format,
762 file[0] == '/' ? NULL : uc_mgr->conf_dir_name,
764 err = uc_mgr_config_load_into(uc_mgr->conf_format, filename, uc_mgr->local_config);
772 err = uc_mgr_substitute_tree(uc_mgr, config);
776 err = snd_config_merge(uc_mgr->local_config, config, 0);
785 * Parse alsa-lib config
787 static int parse_libconfig(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
789 snd_config_iterator_t i, next;
794 if (snd_config_get_id(cfg, &id) < 0)
797 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
798 snd_error(UCM, "compound type expected for %s", id);
802 snd_config_for_each(i, next, cfg) {
803 n = snd_config_iterator_entry(i);
805 err = parse_libconfig1(uc_mgr, n);
816 static int parse_transition(snd_use_case_mgr_t *uc_mgr,
817 struct list_head *tlist,
820 struct transition_sequence *tseq;
822 snd_config_iterator_t i, next;
826 if (snd_config_get_id(cfg, &id) < 0)
829 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
830 snd_error(UCM, "compound type expected for %s", id);
834 snd_config_for_each(i, next, cfg) {
835 n = snd_config_iterator_entry(i);
837 if (snd_config_get_id(n, &id) < 0)
840 tseq = calloc(1, sizeof(*tseq));
843 INIT_LIST_HEAD(&tseq->transition_list);
845 err = get_string3(uc_mgr, id, &tseq->name);
851 err = parse_sequence(uc_mgr, &tseq->transition_list, n);
853 uc_mgr_free_transition_element(tseq);
857 list_add(&tseq->list, tlist);
865 static int parse_compound(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg,
866 int (*fcn)(snd_use_case_mgr_t *, snd_config_t *, void *, void *),
867 void *data1, void *data2)
870 snd_config_iterator_t i, next;
874 if (snd_config_get_id(cfg, &id) < 0)
877 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
878 snd_error(UCM, "compound type expected for %s", id);
882 snd_config_for_each(i, next, cfg) {
883 n = snd_config_iterator_entry(i);
885 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
886 snd_error(UCM, "compound type expected for %s, is %d", id, snd_config_get_type(cfg));
890 err = fcn(uc_mgr, n, data1, data2);
898 static int strip_legacy_dev_index(char *name)
900 char *dot = strchr(name, '.');
903 if (dot[1] != '0' || dot[2] != '\0') {
904 snd_error(UCM, "device name %s contains a '.',"
905 " and is not legacy foo.0 format", name);
916 static int parse_device_list(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED,
917 struct dev_list *dev_list,
918 enum dev_list_type type,
921 struct dev_list_node *sdev;
923 snd_config_iterator_t i, next;
927 if (dev_list->type != DEVLIST_NONE) {
928 snd_error(UCM, "multiple supported or conflicting device lists");
933 if (snd_config_get_id(cfg, &id) < 0)
936 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
937 snd_error(UCM, "compound type expected for %s", id);
941 snd_config_for_each(i, next, cfg) {
942 n = snd_config_iterator_entry(i);
944 if (snd_config_get_id(n, &id) < 0)
947 sdev = calloc(1, sizeof(struct dev_list_node));
950 err = parse_string_substitute3(uc_mgr, n, &sdev->name);
955 err = strip_legacy_dev_index(sdev->name);
961 list_add(&sdev->list, &dev_list->list);
964 dev_list->type = type;
969 /* Find a component device by its name, and remove it from machine device
972 * Component devices are defined by machine components (usually off-soc
973 * codes or DSP embeded in SoC). Since alsaconf imports their configuration
974 * files automatically, we don't know which devices are component devices
975 * until they are referenced by a machine device sequence. So here when we
976 * find a referenced device, we move it from the machine device list to the
977 * component device list. Component devices will not be exposed to applications
978 * by the original API to list devices for backward compatibility. So sound
979 * servers can only see the machine devices.
981 struct use_case_device *find_component_dev(snd_use_case_mgr_t *uc_mgr,
984 struct list_head *pos, *posdev, *_posdev;
985 struct use_case_verb *verb;
986 struct use_case_device *dev;
988 list_for_each(pos, &uc_mgr->verb_list) {
989 verb = list_entry(pos, struct use_case_verb, list);
991 /* search in the component device list */
992 list_for_each(posdev, &verb->cmpt_device_list) {
993 dev = list_entry(posdev, struct use_case_device, list);
994 if (!strcmp(dev->name, name))
998 /* search the machine device list */
999 list_for_each_safe(posdev, _posdev, &verb->device_list) {
1000 dev = list_entry(posdev, struct use_case_device, list);
1001 if (!strcmp(dev->name, name)) {
1002 /* find the component device, move it from the
1003 * machine device list to the component device
1006 list_del(&dev->list);
1007 list_add_tail(&dev->list,
1008 &verb->cmpt_device_list);
1017 /* parse sequence of a component device
1019 * This function will find the component device and mark if its enable or
1020 * disable sequence is needed by its parenet device.
1022 static int parse_component_seq(snd_use_case_mgr_t *uc_mgr,
1023 snd_config_t *n, int enable,
1024 struct component_sequence *cmpt_seq)
1029 err = parse_string_substitute3(uc_mgr, n, &val);
1033 cmpt_seq->device = find_component_dev(uc_mgr, val);
1034 if (!cmpt_seq->device) {
1035 snd_error(UCM, "Cannot find component device %s", val);
1041 /* Parent needs its enable or disable sequence */
1042 cmpt_seq->enable = enable;
1050 * Sequence controls elements are in the following form:-
1053 * cset "element_id_syntax value_syntax"
1055 * exec "any unix command with arguments"
1056 * enadev "component device name"
1057 * disdev "component device name"
1060 * cset "name='Master Playback Switch' 0,0"
1061 * cset "iface=PCM,name='Disable HDMI',index=1 0"
1062 * enadev "rt286:Headphones"
1063 * disdev "rt286:Speaker"
1065 static int parse_sequence(snd_use_case_mgr_t *uc_mgr,
1066 struct list_head *base,
1069 struct sequence_element *curr;
1070 snd_config_iterator_t i, next;
1073 const char *cmd = NULL;
1075 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
1076 snd_error(UCM, "compound is expected for sequence definition");
1080 snd_config_for_each(i, next, cfg) {
1083 n = snd_config_iterator_entry(i);
1084 err = snd_config_get_id(n, &id);
1088 if (snd_config_get_type(n) != SND_CONFIG_TYPE_STRING) {
1089 snd_error(UCM, "string type is expected for sequence command");
1092 err = snd_config_get_string(n, &cmd);
1098 /* alloc new sequence element */
1099 curr = calloc(1, sizeof(struct sequence_element));
1102 list_add_tail(&curr->list, base);
1104 if (strcmp(cmd, "cdev") == 0) {
1105 curr->type = SEQUENCE_ELEMENT_TYPE_CDEV;
1106 err = parse_string_substitute3(uc_mgr, n, &curr->data.cdev);
1108 snd_error(UCM, "cdev requires a string!");
1114 if (strcmp(cmd, "cset") == 0) {
1115 curr->type = SEQUENCE_ELEMENT_TYPE_CSET;
1117 err = parse_string_substitute3(uc_mgr, n, &curr->data.cset);
1119 snd_error(UCM, "%s requires a string!", cmd);
1125 if (strcmp(cmd, "enadev") == 0 ||
1126 strcmp(cmd, "disdev") == 0) {
1127 /* need to enable or disable a component device */
1128 curr->type = SEQUENCE_ELEMENT_TYPE_CMPT_SEQ;
1129 err = parse_component_seq(uc_mgr, n,
1130 strcmp(cmd, "enadev") == 0,
1131 &curr->data.cmpt_seq);
1133 snd_error(UCM, "%s requires a valid device!", cmd);
1139 if (strcmp(cmd, "enadev2") == 0) {
1140 curr->type = SEQUENCE_ELEMENT_TYPE_DEV_ENABLE_SEQ;
1144 if (strcmp(cmd, "disdev2") == 0) {
1145 curr->type = SEQUENCE_ELEMENT_TYPE_DEV_DISABLE_SEQ;
1147 err = parse_string_substitute3(uc_mgr, n, &curr->data.device);
1149 snd_error(UCM, "%s requires a valid device!", cmd);
1155 if (strcmp(cmd, "disdevall") == 0) {
1156 curr->type = SEQUENCE_ELEMENT_TYPE_DEV_DISABLE_ALL;
1160 if (strcmp(cmd, "cset-bin-file") == 0) {
1161 curr->type = SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE;
1165 if (strcmp(cmd, "cset-tlv") == 0) {
1166 curr->type = SEQUENCE_ELEMENT_TYPE_CSET_TLV;
1170 if (strcmp(cmd, "cset-new") == 0) {
1171 curr->type = SEQUENCE_ELEMENT_TYPE_CSET_NEW;
1175 if (strcmp(cmd, "ctl-remove") == 0) {
1176 curr->type = SEQUENCE_ELEMENT_TYPE_CTL_REMOVE;
1180 if (strcmp(cmd, "sysw") == 0) {
1181 curr->type = SEQUENCE_ELEMENT_TYPE_SYSSET;
1182 err = parse_string_substitute3(uc_mgr, n, &curr->data.sysw);
1184 snd_error(UCM, "sysw requires a string!");
1190 if (strcmp(cmd, "usleep") == 0) {
1191 curr->type = SEQUENCE_ELEMENT_TYPE_SLEEP;
1192 err = parse_integer_substitute3(uc_mgr, n, &curr->data.sleep);
1194 snd_error(UCM, "usleep requires integer!");
1200 if (strcmp(cmd, "msleep") == 0) {
1201 curr->type = SEQUENCE_ELEMENT_TYPE_SLEEP;
1202 err = parse_integer_substitute3(uc_mgr, n, &curr->data.sleep);
1204 snd_error(UCM, "msleep requires integer!");
1207 curr->data.sleep *= 1000L;
1211 if (strcmp(cmd, "exec") == 0) {
1212 curr->type = SEQUENCE_ELEMENT_TYPE_EXEC;
1214 err = parse_string_substitute3(uc_mgr, n, &curr->data.exec);
1216 snd_error(UCM, "exec requires a string!");
1222 if (strcmp(cmd, "shell") == 0) {
1223 curr->type = SEQUENCE_ELEMENT_TYPE_SHELL;
1227 if (strcmp(cmd, "cfg-save") == 0) {
1228 curr->type = SEQUENCE_ELEMENT_TYPE_CFGSAVE;
1229 err = parse_string_substitute3(uc_mgr, n, &curr->data.cfgsave);
1231 snd_error(UCM, "sysw requires a string!");
1237 if (strcmp(cmd, "comment") == 0)
1240 snd_error(UCM, "sequence command '%s' is ignored", cmd);
1243 list_del(&curr->list);
1244 uc_mgr_free_sequence_element(curr);
1253 int uc_mgr_add_value(struct list_head *base, const char *key, char *val)
1255 struct ucm_value *curr;
1257 curr = calloc(1, sizeof(struct ucm_value));
1260 curr->name = strdup(key);
1261 if (curr->name == NULL) {
1265 list_add_tail(&curr->list, base);
1273 * Parse values describing PCM, control/mixer settings and stream parameters.
1278 * PlaybackVolume "name='Master Playback Volume',index=2"
1279 * PlaybackSwitch "name='Master Playback Switch',index=2"
1282 static int parse_value(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED,
1283 struct list_head *base,
1286 snd_config_iterator_t i, next;
1289 snd_config_type_t type;
1292 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
1293 snd_error(UCM, "compound is expected for value definition");
1297 /* in-place evaluation */
1298 err = uc_mgr_evaluate_inplace(uc_mgr, cfg);
1302 snd_config_for_each(i, next, cfg) {
1304 n = snd_config_iterator_entry(i);
1305 err = snd_config_get_id(n, &id);
1309 type = snd_config_get_type(n);
1311 case SND_CONFIG_TYPE_INTEGER:
1312 case SND_CONFIG_TYPE_INTEGER64:
1313 case SND_CONFIG_TYPE_REAL:
1314 err = snd_config_get_ascii(n, &s);
1316 snd_error(UCM, "unable to parse value for id '%s': %s!", id, snd_strerror(err));
1320 case SND_CONFIG_TYPE_STRING:
1321 err = parse_string_substitute(uc_mgr, n, &s);
1323 snd_error(UCM, "unable to parse a string for id '%s'!", id);
1328 snd_error(UCM, "invalid type %i in Value compound '%s'", type, id);
1331 err = uc_mgr_add_value(base, id, s);
1342 * Parse Modifier Use cases
1344 * # Each modifier is described in new section. N modifiers are allowed
1345 * SectionModifier."Capture Voice" {
1347 * Comment "Record voice call"
1354 * ConflictingDevice [
1367 * TransitionSequence."ToModifierName" [
1371 * # Optional TQ and ALSA PCMs
1375 * PlaybackVolume "name='Master Playback Volume',index=2"
1376 * PlaybackSwitch "name='Master Playback Switch',index=2"
1380 * SupportedDevice and ConflictingDevice cannot be specified together.
1381 * Both are optional.
1383 static int parse_modifier(snd_use_case_mgr_t *uc_mgr,
1385 void *data1, void *data2)
1387 struct use_case_verb *verb = data1;
1388 struct use_case_modifier *modifier;
1390 snd_config_iterator_t i, next;
1394 if (parse_get_safe_name(uc_mgr, cfg, data2, &name) < 0)
1397 /* allocate modifier */
1398 modifier = calloc(1, sizeof(*modifier));
1399 if (modifier == NULL) {
1403 INIT_LIST_HEAD(&modifier->enable_list);
1404 INIT_LIST_HEAD(&modifier->disable_list);
1405 INIT_LIST_HEAD(&modifier->transition_list);
1406 INIT_LIST_HEAD(&modifier->dev_list.list);
1407 INIT_LIST_HEAD(&modifier->value_list);
1408 list_add_tail(&modifier->list, &verb->modifier_list);
1409 modifier->name = name;
1411 /* in-place evaluation */
1412 err = uc_mgr_evaluate_inplace(uc_mgr, cfg);
1416 snd_config_for_each(i, next, cfg) {
1418 n = snd_config_iterator_entry(i);
1419 if (snd_config_get_id(n, &id) < 0)
1422 if (strcmp(id, "Comment") == 0) {
1423 err = parse_string_substitute3(uc_mgr, n, &modifier->comment);
1425 snd_error(UCM, "failed to get modifier comment");
1431 if (strcmp(id, "SupportedDevice") == 0) {
1432 err = parse_device_list(uc_mgr, &modifier->dev_list,
1433 DEVLIST_SUPPORTED, n);
1435 snd_error(UCM, "failed to parse supported device list");
1440 if (strcmp(id, "ConflictingDevice") == 0) {
1441 err = parse_device_list(uc_mgr, &modifier->dev_list,
1442 DEVLIST_CONFLICTING, n);
1444 snd_error(UCM, "failed to parse conflicting device list");
1449 if (strcmp(id, "EnableSequence") == 0) {
1450 err = parse_sequence(uc_mgr, &modifier->enable_list, n);
1452 snd_error(UCM, "failed to parse modifier enable sequence");
1458 if (strcmp(id, "DisableSequence") == 0) {
1459 err = parse_sequence(uc_mgr, &modifier->disable_list, n);
1461 snd_error(UCM, "failed to parse modifier disable sequence");
1467 if (strcmp(id, "TransitionSequence") == 0) {
1468 err = parse_transition(uc_mgr, &modifier->transition_list, n);
1470 snd_error(UCM, "failed to parse transition modifier");
1476 if (strcmp(id, "Value") == 0) {
1477 err = parse_value(uc_mgr, &modifier->value_list, n);
1479 snd_error(UCM, "failed to parse Value");
1490 * Parse Device Use Cases
1492 * # Each device is described in new section. N devices are allowed
1493 * SectionDevice."Headphones" {
1494 * Comment "Headphones connected to 3.5mm jack"
1501 * ConflictingDevice [
1514 * TransitionSequence."ToDevice" [
1519 * PlaybackVolume "name='Master Playback Volume',index=2"
1520 * PlaybackSwitch "name='Master Playback Switch',index=2"
1524 static int parse_device(snd_use_case_mgr_t *uc_mgr,
1526 void *data1, void *data2)
1528 struct use_case_verb *verb = data1;
1530 struct use_case_device *device;
1531 snd_config_iterator_t i, next;
1535 if (parse_get_safe_name(uc_mgr, cfg, data2, &name) < 0)
1538 device = calloc(1, sizeof(*device));
1539 if (device == NULL) {
1543 INIT_LIST_HEAD(&device->enable_list);
1544 INIT_LIST_HEAD(&device->disable_list);
1545 INIT_LIST_HEAD(&device->transition_list);
1546 INIT_LIST_HEAD(&device->dev_list.list);
1547 INIT_LIST_HEAD(&device->value_list);
1548 list_add_tail(&device->list, &verb->device_list);
1549 device->name = name;
1551 /* in-place evaluation */
1552 err = uc_mgr_evaluate_inplace(uc_mgr, cfg);
1556 snd_config_for_each(i, next, cfg) {
1558 n = snd_config_iterator_entry(i);
1559 if (snd_config_get_id(n, &id) < 0)
1562 if (strcmp(id, "Comment") == 0) {
1563 err = parse_string_substitute3(uc_mgr, n, &device->comment);
1565 snd_error(UCM, "failed to get device comment");
1571 if (strcmp(id, "SupportedDevice") == 0) {
1572 err = parse_device_list(uc_mgr, &device->dev_list,
1573 DEVLIST_SUPPORTED, n);
1575 snd_error(UCM, "failed to parse supported device list");
1581 if (strcmp(id, "ConflictingDevice") == 0) {
1582 err = parse_device_list(uc_mgr, &device->dev_list,
1583 DEVLIST_CONFLICTING, n);
1585 snd_error(UCM, "failed to parse conflicting device list");
1591 if (strcmp(id, "EnableSequence") == 0) {
1592 err = parse_sequence(uc_mgr, &device->enable_list, n);
1594 snd_error(UCM, "failed to parse device enable sequence");
1601 if (strcmp(id, "DisableSequence") == 0) {
1602 err = parse_sequence(uc_mgr, &device->disable_list, n);
1604 snd_error(UCM, "failed to parse device disable sequence");
1611 if (strcmp(id, "TransitionSequence") == 0) {
1612 err = parse_transition(uc_mgr, &device->transition_list, n);
1614 snd_error(UCM, "failed to parse transition device");
1621 if (strcmp(id, "Value") == 0) {
1622 err = parse_value(uc_mgr, &device->value_list, n);
1624 snd_error(UCM, "failed to parse Value");
1634 * Parse Device Rename/Delete Command
1636 * # The devices might be renamed to allow the better conditional runtime
1637 * # evaluation. Bellow example renames Speaker1 device to Speaker and
1638 * # removes Speaker2 device.
1639 * RenameDevice."Speaker1" "Speaker"
1640 * RemoveDevice."Speaker2" "Speaker2"
1642 static int parse_dev_name_list(snd_use_case_mgr_t *uc_mgr,
1644 struct list_head *list)
1647 snd_config_iterator_t i, next;
1648 const char *id, *name1;
1649 char *name1s, *name2;
1650 struct ucm_dev_name *dev;
1651 snd_config_iterator_t pos;
1654 if (snd_config_get_id(cfg, &id) < 0)
1657 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
1658 snd_error(UCM, "compound type expected for %s", id);
1662 snd_config_for_each(i, next, cfg) {
1663 n = snd_config_iterator_entry(i);
1665 if (snd_config_get_id(n, &name1) < 0)
1668 err = get_string3(uc_mgr, name1, &name1s);
1672 err = parse_string_substitute3(uc_mgr, n, &name2);
1675 snd_error(UCM, "failed to get target device name for '%s'", name1);
1679 /* skip duplicates */
1680 list_for_each(pos, list) {
1681 dev = list_entry(pos, struct ucm_dev_name, list);
1682 if (strcmp(dev->name1, name1s) == 0) {
1691 dev = calloc(1, sizeof(*dev));
1696 dev->name1 = strdup(name1);
1697 if (dev->name1 == NULL) {
1703 list_add_tail(&dev->list, list);
1709 static int parse_compound_check_legacy(snd_use_case_mgr_t *uc_mgr,
1711 int (*fcn)(snd_use_case_mgr_t *, snd_config_t *, void *, void *),
1714 const char *id, *idchild;
1715 int child_ctr = 0, legacy_format = 1;
1716 snd_config_iterator_t i, next;
1717 snd_config_t *child;
1720 err = snd_config_get_id(cfg, &id);
1724 snd_config_for_each(i, next, cfg) {
1726 if (child_ctr > 1) {
1730 child = snd_config_iterator_entry(i);
1732 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
1737 if (snd_config_get_id(child, &idchild) < 0)
1740 if (strcmp(idchild, "0")) {
1745 if (child_ctr != 1) {
1750 return parse_compound(uc_mgr, cfg, fcn, data1, (void *)id);
1752 return fcn(uc_mgr, cfg, data1, NULL);
1755 static int parse_device_name(snd_use_case_mgr_t *uc_mgr,
1758 void *data2 ATTRIBUTE_UNUSED)
1760 return parse_compound_check_legacy(uc_mgr, cfg, parse_device, data1);
1763 static int parse_modifier_name(snd_use_case_mgr_t *uc_mgr,
1766 void *data2 ATTRIBUTE_UNUSED)
1768 return parse_compound_check_legacy(uc_mgr, cfg, parse_modifier, data1);
1771 static int verb_dev_list_add(struct use_case_verb *verb,
1772 enum dev_list_type dst_type,
1776 struct use_case_device *device;
1777 struct list_head *pos;
1779 list_for_each(pos, &verb->device_list) {
1780 device = list_entry(pos, struct use_case_device, list);
1781 if (strcmp(device->name, dst) != 0)
1783 if (device->dev_list.type != dst_type) {
1784 if (list_empty(&device->dev_list.list)) {
1785 device->dev_list.type = dst_type;
1787 snd_error(UCM, "incompatible device list type ('%s', '%s')", device->name, src);
1791 return uc_mgr_put_to_dev_list(&device->dev_list, src);
1793 snd_error(UCM, "unable to find device '%s'", dst);
1797 static int verb_dev_list_check(struct use_case_verb *verb)
1799 struct list_head *pos, *pos2;
1800 struct use_case_device *device;
1801 struct dev_list_node *dlist;
1804 list_for_each(pos, &verb->device_list) {
1805 device = list_entry(pos, struct use_case_device, list);
1806 list_for_each(pos2, &device->dev_list.list) {
1807 dlist = list_entry(pos2, struct dev_list_node, list);
1808 err = verb_dev_list_add(verb, device->dev_list.type,
1809 dlist->name, device->name);
1817 static int verb_device_management(struct use_case_verb *verb)
1819 struct list_head *pos;
1820 struct ucm_dev_name *dev;
1823 /* rename devices */
1824 list_for_each(pos, &verb->rename_list) {
1825 dev = list_entry(pos, struct ucm_dev_name, list);
1826 err = uc_mgr_rename_device(verb, dev->name1, dev->name2);
1828 snd_error(UCM, "cannot rename device '%s' to '%s'", dev->name1, dev->name2);
1833 /* remove devices */
1834 list_for_each(pos, &verb->remove_list) {
1835 dev = list_entry(pos, struct ucm_dev_name, list);
1836 err = uc_mgr_remove_device(verb, dev->name2);
1838 snd_error(UCM, "cannot remove device '%s'", dev->name2);
1843 /* those lists are no longer used */
1844 uc_mgr_free_dev_name_list(&verb->rename_list);
1845 uc_mgr_free_dev_name_list(&verb->remove_list);
1847 /* handle conflicting/supported lists */
1848 return verb_dev_list_check(verb);
1852 * Parse Verb Section
1854 * # Example Use case verb section for Voice call blah
1855 * # By Joe Blogs <joe@blogs.com>
1858 * # enable and disable sequences are compulsory
1860 * cset "name='Master Playback Switch',index=2 0,0"
1861 * cset "name='Master Playback Volume',index=2 25,25"
1863 * cset "name='Master Playback Switch',index=2 1,1"
1864 * cset "name='Master Playback Volume',index=2 50,50"
1868 * cset "name='Master Playback Switch',index=2 0,0"
1869 * cset "name='Master Playback Volume',index=2 25,25"
1871 * cset "name='Master Playback Switch',index=2 1,1"
1872 * cset "name='Master Playback Volume',index=2 50,50"
1875 * # Optional transition verb
1876 * TransitionSequence."ToCaseName" [
1880 * # Optional TQ and ALSA PCMs
1884 * PlaybackPCM "hw:0"
1888 static int parse_verb(snd_use_case_mgr_t *uc_mgr,
1889 struct use_case_verb *verb,
1892 snd_config_iterator_t i, next;
1896 /* in-place evaluation */
1897 err = uc_mgr_evaluate_inplace(uc_mgr, cfg);
1901 /* parse verb section */
1902 snd_config_for_each(i, next, cfg) {
1904 n = snd_config_iterator_entry(i);
1905 if (snd_config_get_id(n, &id) < 0)
1908 if (strcmp(id, "EnableSequence") == 0) {
1909 err = parse_sequence(uc_mgr, &verb->enable_list, n);
1911 snd_error(UCM, "failed to parse verb enable sequence");
1917 if (strcmp(id, "DisableSequence") == 0) {
1918 err = parse_sequence(uc_mgr, &verb->disable_list, n);
1920 snd_error(UCM, "failed to parse verb disable sequence");
1926 if (strcmp(id, "TransitionSequence") == 0) {
1927 snd_debug(UCM, "Parse TransitionSequence");
1928 err = parse_transition(uc_mgr, &verb->transition_list, n);
1930 snd_error(UCM, "failed to parse transition sequence");
1936 if (strcmp(id, "Value") == 0) {
1937 err = parse_value(uc_mgr, &verb->value_list, n);
1948 * Parse a Use case verb file.
1950 * This file contains the following :-
1951 * o Verb enable and disable sequences.
1952 * o Supported Device enable and disable sequences for verb.
1953 * o Supported Modifier enable and disable sequences for verb
1954 * o Optional QoS for the verb and modifiers.
1955 * o Optional PCM device ID for verb and modifiers
1956 * o Alias kcontrols IDs for master and volumes and mutes.
1958 static int parse_verb_file(snd_use_case_mgr_t *uc_mgr,
1959 const char *use_case_name,
1960 const char *comment,
1963 snd_config_iterator_t i, next;
1965 struct use_case_verb *verb;
1970 verb = calloc(1, sizeof(struct use_case_verb));
1973 INIT_LIST_HEAD(&verb->enable_list);
1974 INIT_LIST_HEAD(&verb->disable_list);
1975 INIT_LIST_HEAD(&verb->transition_list);
1976 INIT_LIST_HEAD(&verb->device_list);
1977 INIT_LIST_HEAD(&verb->cmpt_device_list);
1978 INIT_LIST_HEAD(&verb->modifier_list);
1979 INIT_LIST_HEAD(&verb->value_list);
1980 INIT_LIST_HEAD(&verb->rename_list);
1981 INIT_LIST_HEAD(&verb->remove_list);
1982 list_add_tail(&verb->list, &uc_mgr->verb_list);
1983 if (use_case_name == NULL)
1985 verb->name = strdup(use_case_name);
1986 if (verb->name == NULL)
1989 if (comment != NULL) {
1990 verb->comment = strdup(comment);
1991 if (verb->comment == NULL)
1995 /* open Verb file for reading */
1996 err = uc_mgr_config_load_file(uc_mgr, file, &cfg);
2000 /* in-place evaluation */
2001 err = uc_mgr_evaluate_inplace(uc_mgr, cfg);
2005 /* parse master config sections */
2006 snd_config_for_each(i, next, cfg) {
2008 n = snd_config_iterator_entry(i);
2009 if (snd_config_get_id(n, &id) < 0)
2012 /* find verb section and parse it */
2013 if (strcmp(id, "SectionVerb") == 0) {
2014 err = parse_verb(uc_mgr, verb, n);
2016 snd_error(UCM, "%s failed to parse verb", file);
2022 /* find device sections and parse them */
2023 if (strcmp(id, "SectionDevice") == 0) {
2024 err = parse_compound(uc_mgr, n,
2025 parse_device_name, verb, NULL);
2027 snd_error(UCM, "%s failed to parse device", file);
2033 /* find modifier sections and parse them */
2034 if (strcmp(id, "SectionModifier") == 0) {
2035 err = parse_compound(uc_mgr, n,
2036 parse_modifier_name, verb, NULL);
2038 snd_error(UCM, "%s failed to parse modifier", file);
2044 /* device renames */
2045 if (strcmp(id, "RenameDevice") == 0) {
2046 err = parse_dev_name_list(uc_mgr, n, &verb->rename_list);
2048 snd_error(UCM, " %s failed to parse device rename", file);
2055 if (strcmp(id, "RemoveDevice") == 0) {
2056 err = parse_dev_name_list(uc_mgr, n, &verb->remove_list);
2058 snd_error(UCM, "%s failed to parse device remove", file);
2064 /* alsa-lib configuration */
2065 if (uc_mgr->conf_format > 3 && strcmp(id, "LibraryConfig") == 0) {
2066 err = parse_libconfig(uc_mgr, n);
2068 snd_error(UCM, "failed to parse LibConfig");
2075 snd_config_delete(cfg);
2077 /* use case verb must have at least 1 device */
2078 if (list_empty(&verb->device_list)) {
2079 snd_error(UCM, "no use case device defined", file);
2083 /* do device rename and delete */
2084 err = verb_device_management(verb);
2086 snd_error(UCM, "device management error in verb '%s'", verb->name);
2093 snd_config_delete(cfg);
2098 * Parse variant information
2100 static int parse_variant(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg,
2101 char **_vfile, char **_vcomment)
2103 snd_config_iterator_t i, next;
2105 char *file = NULL, *comment = NULL;
2108 /* parse master config sections */
2109 snd_config_for_each(i, next, cfg) {
2111 n = snd_config_iterator_entry(i);
2112 if (snd_config_get_id(n, &id) < 0)
2115 /* get use case verb file name */
2116 if (strcmp(id, "File") == 0) {
2118 err = parse_string_substitute3(uc_mgr, n, &file);
2120 snd_error(UCM, "failed to get File");
2127 /* get optional use case comment */
2128 if (strncmp(id, "Comment", 7) == 0) {
2130 err = parse_string_substitute3(uc_mgr, n, &comment);
2132 snd_error(UCM, "failed to get Comment");
2139 snd_error(UCM, "unknown field '%s' in Variant section", id);
2147 *_vcomment = comment;
2157 * Parse master section for "Use Case" and "File" tags.
2159 static int parse_master_section(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg,
2160 void *data1 ATTRIBUTE_UNUSED,
2161 void *data2 ATTRIBUTE_UNUSED)
2163 snd_config_iterator_t i, next;
2164 snd_config_t *n, *variant = NULL;
2165 char *use_case_name, *file = NULL, *comment = NULL;
2166 bool variant_ok = false;
2169 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
2170 snd_error(UCM, "compound type expected for use case section");
2174 err = parse_get_safe_name(uc_mgr, cfg, NULL, &use_case_name);
2176 snd_error(UCM, "unable to get name for use case section");
2180 /* in-place evaluation */
2181 uc_mgr->parse_master_section = 1;
2182 err = uc_mgr_evaluate_inplace(uc_mgr, cfg);
2183 uc_mgr->parse_master_section = 0;
2187 /* parse master config sections */
2188 snd_config_for_each(i, next, cfg) {
2190 n = snd_config_iterator_entry(i);
2191 if (snd_config_get_id(n, &id) < 0)
2194 /* get use case verb file name */
2195 if (strcmp(id, "File") == 0) {
2196 err = parse_string_substitute3(uc_mgr, n, &file);
2198 snd_error(UCM, "failed to get File");
2204 /* get optional use case comment */
2205 if (strncmp(id, "Comment", 7) == 0) {
2206 err = parse_string_substitute3(uc_mgr, n, &comment);
2208 snd_error(UCM, "failed to get Comment");
2214 if (uc_mgr->conf_format >= 6 && strcmp(id, "Variant") == 0) {
2215 snd_config_iterator_t i2, next2;
2217 snd_config_for_each(i2, next2, n) {
2220 n2 = snd_config_iterator_entry(i2);
2221 if (snd_config_get_id(n2, &id2) < 0)
2223 err = uc_mgr_evaluate_inplace(uc_mgr, n2);
2226 if (strcmp(use_case_name, id2) == 0)
2232 snd_error(UCM, "unknown field '%s' in SectionUseCase", id);
2235 if (variant && !variant_ok) {
2236 snd_error(UCM, "undefined variant '%s'", use_case_name);
2242 snd_debug(UCM, "use_case_name %s file '%s'", use_case_name, file);
2244 /* do we have both use case name and file ? */
2246 snd_error(UCM, "use case missing file");
2251 /* parse verb file */
2252 err = parse_verb_file(uc_mgr, use_case_name, comment, file);
2254 /* parse variants */
2255 struct list_head orig_variable_list;
2256 snd_config_t *orig_macros = NULL;
2257 int first_iteration = 1;
2259 /* save original variable list */
2260 err = uc_mgr_duplicate_variables(&orig_variable_list, &uc_mgr->variable_list);
2264 /* save original macros */
2265 if (uc_mgr->macros) {
2266 err = snd_config_copy(&orig_macros, uc_mgr->macros);
2268 goto __variant_error;
2271 snd_config_for_each(i, next, variant) {
2272 char *vfile, *vcomment;
2275 /* restore variables and macros for second and later iterations */
2276 if (!first_iteration) {
2277 uc_mgr_free_value(&uc_mgr->variable_list);
2279 err = uc_mgr_duplicate_variables(&uc_mgr->variable_list, &orig_variable_list);
2281 goto __variant_error;
2283 if (uc_mgr->macros) {
2284 snd_config_delete(uc_mgr->macros);
2285 uc_mgr->macros = NULL;
2288 err = snd_config_copy(&uc_mgr->macros, orig_macros);
2290 goto __variant_error;
2293 first_iteration = 0;
2295 n = snd_config_iterator_entry(i);
2296 if (snd_config_get_id(n, &id) < 0)
2298 if (!parse_is_name_safe(id)) {
2300 goto __variant_error;
2302 err = parse_variant(uc_mgr, n, &vfile, &vcomment);
2305 uc_mgr->parse_variant = id;
2306 err = parse_verb_file(uc_mgr, id,
2307 vcomment ? vcomment : comment,
2308 vfile ? vfile : file);
2309 uc_mgr->parse_variant = NULL;
2317 uc_mgr_free_value(&orig_variable_list);
2319 snd_config_delete(orig_macros);
2323 free(use_case_name);
2330 * parse controls which should be run only at initial boot (forcefully)
2332 static int parse_controls_fixedboot(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
2336 if (!list_empty(&uc_mgr->fixedboot_list)) {
2337 snd_error(UCM, "FixedBoot list is not empty");
2340 err = parse_sequence(uc_mgr, &uc_mgr->fixedboot_list, cfg);
2342 snd_error(UCM, "Unable to parse FixedBootSequence");
2350 * parse controls which should be run only at initial boot
2352 static int parse_controls_boot(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
2356 if (!list_empty(&uc_mgr->boot_list)) {
2357 snd_error(UCM, "Boot list is not empty");
2360 err = parse_sequence(uc_mgr, &uc_mgr->boot_list, cfg);
2362 snd_error(UCM, "Unable to parse BootSequence");
2372 static int parse_controls(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
2376 if (!list_empty(&uc_mgr->default_list)) {
2377 snd_error(UCM, "Default list is not empty");
2380 err = parse_sequence(uc_mgr, &uc_mgr->default_list, cfg);
2382 snd_error(UCM, "Unable to parse SectionDefaults");
2390 * Each sound card has a master sound card file that lists all the supported
2391 * use case verbs for that sound card. i.e.
2393 * #Example master file for blah sound card
2394 * #By Joe Blogs <joe@bloggs.org>
2396 * Comment "Nice Abstracted Soundcard"
2398 * # The file is divided into Use case sections. One section per use case verb.
2400 * SectionUseCase."Voice Call" {
2401 * File "voice_call_blah"
2402 * Comment "Make a voice phone call."
2405 * SectionUseCase."HiFi" {
2407 * Comment "Play and record HiFi quality Music."
2410 * # Define Value defaults
2413 * PlaybackCTL "hw:CARD=0"
2414 * CaptureCTL "hw:CARD=0"
2417 * # The initial boot (run once) configuration.
2420 * cset "name='Master Playback Switch',index=2 1,1"
2421 * cset "name='Master Playback Volume',index=2 25,25"
2424 * # This file also stores the default sound card state.
2427 * cset "name='Master Mono Playback',index=1 0"
2428 * cset "name='Master Mono Playback Volume',index=1 0"
2429 * cset "name='PCM Switch',index=2 1,1"
2430 * exec "some binary here"
2435 * # End of example file.
2437 static int parse_master_file(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
2439 snd_config_iterator_t i, next;
2444 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
2445 snd_error(UCM, "compound type expected for master file");
2449 if (uc_mgr->conf_format >= 2) {
2450 err = parse_syntax_field(uc_mgr, cfg, uc_mgr->conf_file_name);
2455 /* in-place evaluation */
2456 err = uc_mgr_evaluate_inplace(uc_mgr, cfg);
2460 /* parse master config sections */
2461 snd_config_for_each(i, next, cfg) {
2463 n = snd_config_iterator_entry(i);
2464 if (snd_config_get_id(n, &id) < 0)
2467 if (strcmp(id, "Comment") == 0) {
2468 err = parse_string_substitute3(uc_mgr, n, &uc_mgr->comment);
2470 snd_error(UCM, "failed to get master comment");
2476 /* find use case section and parse it */
2477 if (strcmp(id, "SectionUseCase") == 0) {
2478 err = parse_compound(uc_mgr, n,
2479 parse_master_section,
2486 /* find default control values section (force boot sequence only) */
2487 if (strcmp(id, "FixedBootSequence") == 0) {
2488 err = parse_controls_fixedboot(uc_mgr, n);
2494 /* find default control values section (first boot only) */
2495 if (strcmp(id, "BootSequence") == 0) {
2496 err = parse_controls_boot(uc_mgr, n);
2502 /* find default control values section and parse it */
2503 if (strcmp(id, "SectionDefaults") == 0) {
2504 err = parse_controls(uc_mgr, n);
2510 /* get the default values */
2511 if (strcmp(id, "ValueDefaults") == 0) {
2512 err = parse_value(uc_mgr, &uc_mgr->value_list, n);
2514 snd_error(UCM, "failed to parse ValueDefaults");
2520 /* alsa-lib configuration */
2521 if (uc_mgr->conf_format > 3 && strcmp(id, "LibraryConfig") == 0) {
2522 err = parse_libconfig(uc_mgr, n);
2524 snd_error(UCM, "failed to parse LibraryConfig");
2531 if (strcmp(id, "Error") == 0)
2532 return error_node(uc_mgr, n);
2534 /* skip further Syntax value updates (Include) */
2535 if (strcmp(id, "Syntax") == 0)
2538 snd_error(UCM, "unknown master file field %s", id);
2543 /* get the card info */
2544 static int get_card_info(snd_use_case_mgr_t *mgr,
2545 const char *ctl_name,
2546 snd_ctl_card_info_t **info)
2548 struct ctl_list *ctl_list;
2551 err = uc_mgr_open_ctl(mgr, &ctl_list, ctl_name, 0);
2556 *info = ctl_list->ctl_info;
2560 /* find the card in the local machine */
2561 static int get_by_card_name(snd_use_case_mgr_t *mgr, const char *card_name)
2564 snd_ctl_card_info_t *info;
2565 const char *_driver, *_name, *_long_name;
2567 snd_ctl_card_info_alloca(&info);
2570 if (snd_card_next(&card) < 0 || card < 0) {
2571 snd_error(UCM, "no soundcards found...");
2578 /* clear the list, keep the only one CTL device */
2579 uc_mgr_free_ctl_list(mgr);
2581 sprintf(name, "hw:%d", card);
2582 err = get_card_info(mgr, name, &info);
2585 _driver = snd_ctl_card_info_get_driver(info);
2586 _name = snd_ctl_card_info_get_name(info);
2587 _long_name = snd_ctl_card_info_get_longname(info);
2588 if (!strcmp(card_name, _driver) ||
2589 !strcmp(card_name, _name) ||
2590 !strcmp(card_name, _long_name))
2594 if (snd_card_next(&card) < 0) {
2595 snd_error(UCM, "snd_card_next");
2600 uc_mgr_free_ctl_list(mgr);
2605 /* set the driver name and long name by the card ctl name */
2606 static inline int get_by_card(snd_use_case_mgr_t *mgr, const char *ctl_name)
2608 return get_card_info(mgr, ctl_name, NULL);
2611 static int parse_toplevel_path(snd_use_case_mgr_t *uc_mgr,
2615 snd_config_iterator_t i, next, i2, next2;
2616 snd_config_t *n, *n2;
2618 char *dir = NULL, *file = NULL, fn[PATH_MAX];
2623 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
2624 snd_error(UCM, "compound type expected for UseCasePath node");
2628 /* parse use case path config sections */
2629 snd_config_for_each(i, next, cfg) {
2630 n = snd_config_iterator_entry(i);
2632 if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
2633 snd_error(UCM, "compound type expected for UseCasePath.something node");
2637 if (snd_config_get_id(n, &id) < 0)
2642 /* parse use case path config sections */
2643 snd_config_for_each(i2, next2, n) {
2645 n2 = snd_config_iterator_entry(i2);
2646 if (snd_config_get_id(n2, &id) < 0)
2649 if (strcmp(id, "Version") == 0) {
2650 err = parse_integer_substitute(uc_mgr, n2, &version);
2652 snd_error(UCM, "unable to parse UcmDirectory");
2655 if (version < 1 || version > 2) {
2656 snd_error(UCM, "Version must be 1 or 2");
2663 if (strcmp(id, "Directory") == 0) {
2664 err = parse_string_substitute(uc_mgr, n2, &dir);
2666 snd_error(UCM, "unable to parse Directory");
2672 if (strcmp(id, "File") == 0) {
2673 err = parse_string_substitute(uc_mgr, n2, &file);
2675 snd_error(UCM, "unable to parse File");
2681 snd_error(UCM, "unknown UseCasePath field %s", id);
2685 snd_error(UCM, "Directory is not defined in %s!", filename);
2689 snd_error(UCM, "File is not defined in %s!", filename);
2693 ucm_filename(fn, sizeof(fn), version, dir, file);
2694 if (access(fn, R_OK) == 0 && lstat64(fn, &st) == 0) {
2695 if (S_ISLNK(st.st_mode)) {
2697 char *link, *dir2, *p;
2699 link = malloc(PATH_MAX);
2702 r = readlink(fn, link, PATH_MAX - 1);
2708 p = strrchr(link, '/');
2711 dir2 = malloc(PATH_MAX);
2716 strncpy(dir2, dir, PATH_MAX - 1);
2717 strncat(dir2, "/", PATH_MAX - 1);
2718 strncat(dir2, link, PATH_MAX - 1);
2719 fn[PATH_MAX - 1] = '\0';
2725 if (replace_string(&uc_mgr->conf_dir_name, dir) == NULL)
2727 if (replace_string(&uc_mgr->conf_file_name, file) == NULL)
2729 strncpy(filename, fn, PATH_MAX);
2730 filename[PATH_MAX - 1] = '\0';
2731 uc_mgr->conf_format = version;
2759 static int parse_toplevel_config(snd_use_case_mgr_t *uc_mgr,
2763 snd_config_iterator_t i, next;
2768 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
2769 snd_error(UCM, "compound type expected for toplevel file");
2773 err = parse_syntax_field(uc_mgr, cfg, filename);
2777 /* in-place evaluation */
2778 err = uc_mgr_evaluate_inplace(uc_mgr, cfg);
2782 /* parse toplevel config sections */
2783 snd_config_for_each(i, next, cfg) {
2785 n = snd_config_iterator_entry(i);
2786 if (snd_config_get_id(n, &id) < 0)
2789 if (strcmp(id, "UseCasePath") == 0) {
2790 err = parse_toplevel_path(uc_mgr, filename, n);
2796 /* alsa-lib configuration */
2797 if (uc_mgr->conf_format > 3 && strcmp(id, "LibraryConfig") == 0) {
2798 err = parse_libconfig(uc_mgr, n);
2800 snd_error(UCM, "failed to parse LibConfig");
2806 /* skip further Syntax value updates (Include) */
2807 if (strcmp(id, "Syntax") == 0)
2810 snd_error(UCM, "unknown toplevel field %s", id);
2816 static int load_toplevel_config(snd_use_case_mgr_t *uc_mgr,
2819 char filename[PATH_MAX];
2823 ucm_filename(filename, sizeof(filename), 2, NULL, "ucm.conf");
2825 if (access(filename, R_OK) != 0) {
2826 snd_error(UCM, "Unable to find the top-level configuration file '%s'.", filename);
2830 err = uc_mgr_config_load(2, filename, &tcfg);
2834 /* filename is shared for function input and output! */
2835 err = parse_toplevel_config(uc_mgr, filename, tcfg);
2836 snd_config_delete(tcfg);
2840 err = uc_mgr_config_load(uc_mgr->conf_format, filename, cfg);
2842 snd_error(UCM, "could not parse configuration for card %s", uc_mgr->card_name);
2852 /* load master use case file for sound card based on rules in ucm2/ucm.conf
2854 int uc_mgr_import_master_config(snd_use_case_mgr_t *uc_mgr)
2860 err = snd_config_top(&uc_mgr->local_config);
2864 err = snd_config_top(&uc_mgr->macros);
2868 name = uc_mgr->card_name;
2869 if (strncmp(name, "hw:", 3) == 0) {
2870 err = get_by_card(uc_mgr, name);
2872 snd_error(UCM, "card '%s' is not valid", name);
2875 } else if (strncmp(name, "strict:", 7)) {
2876 /* do not handle the error here */
2877 /* we can refer the virtual UCM config */
2878 get_by_card_name(uc_mgr, name);
2881 err = load_toplevel_config(uc_mgr, &cfg);
2885 err = parse_master_file(uc_mgr, cfg);
2886 if (uc_mgr->macros) {
2887 snd_config_delete(uc_mgr->macros);
2888 uc_mgr->macros = NULL;
2890 snd_config_delete(cfg);
2892 uc_mgr_free_ctl_list(uc_mgr);
2893 uc_mgr_free_verb(uc_mgr);
2899 uc_mgr_free_ctl_list(uc_mgr);
2900 replace_string(&uc_mgr->conf_dir_name, NULL);
2904 static int filename_filter(const struct dirent64 *dirent)
2908 if (dirent->d_type == DT_DIR) {
2909 if (dirent->d_name[0] == '.') {
2910 if (dirent->d_name[1] == '\0')
2912 if (dirent->d_name[1] == '.' &&
2913 dirent->d_name[2] == '\0')
2921 /* scan all cards and comments
2923 * Cards are defined by machines. Each card/machine installs its UCM
2924 * configuration files in a subdirectory with the same name as the sound
2925 * card under /usr/share/alsa/ucm2. This function will scan all the card
2926 * directories and skip the component directories defined in the array
2929 int uc_mgr_scan_master_configs(const char **_list[])
2931 char filename[PATH_MAX], dfl[PATH_MAX], fn[FILENAME_MAX];
2932 char *env = getenv(ALSA_CONFIG_UCM2_VAR);
2933 snd_use_case_mgr_t *uc_mgr;
2934 const char **list, *d_name;
2936 snd_config_t *cfg, *c;
2937 int i, j, cnt, err, cards;
2940 struct dirent64 **namelist;
2945 err = snd_card_next(&i);
2952 cards += 4; /* plug-and-play */
2955 snprintf(filename, sizeof(filename), "%s/conf.virt.d", env);
2957 snprintf(filename, sizeof(filename), "%s/ucm2/conf.virt.d",
2958 snd_config_topdir());
2960 #if defined(_GNU_SOURCE) && \
2961 !defined(__NetBSD__) && \
2962 !defined(__FreeBSD__) && \
2963 !defined(__OpenBSD__) && \
2964 !defined(__DragonFly__) && \
2965 !defined(__sun) && \
2966 !defined(__ANDROID__) && \
2968 #define SORTFUNC versionsort64
2970 #define SORTFUNC alphasort64
2972 err = scandir64(filename, &namelist, filename_filter, SORTFUNC);
2975 snd_error(UCM, "could not scan directory %s: %s", filename, strerror(-err));
2981 if (strlen(filename) + 8 < sizeof(filename)) {
2982 strcat(filename, "/default");
2983 ss = readlink(filename, dfl, sizeof(dfl)-1);
2986 dfl[sizeof(dfl)-1] = '\0';
2987 if (dfl[0] && dfl[strlen(dfl)-1] == '/')
2988 dfl[strlen(dfl)-1] = '\0';
2995 list = calloc(1, (cards + cnt) * 2 * sizeof(char *));
3002 while (j / 2 < cards) {
3003 err = snd_card_next(&i);
3008 snprintf(fn, sizeof(fn), "-hw:%d", i);
3009 err = snd_use_case_mgr_open(&uc_mgr, fn);
3010 if (err == -ENOENT || err == -ENXIO)
3013 snd_error(UCM, "Unable to open '%s': %s", fn, snd_strerror(err));
3016 err = snd_use_case_get(uc_mgr, "comment", (const char **)&s);
3018 err = snd_card_get_longname(i, &s);
3022 snd_use_case_mgr_close(uc_mgr);
3023 list[j] = strdup(fn + 1);
3024 if (list[j] == NULL) {
3033 for (i = 0; i < cnt; i++) {
3035 d_name = namelist[i]->d_name;
3037 snprintf(fn, sizeof(fn), "%s.conf", d_name);
3038 ucm_filename(filename, sizeof(filename), 2, d_name, fn);
3040 if (eaccess(filename, R_OK))
3042 if (access(filename, R_OK))
3046 err = uc_mgr_config_load(2, filename, &cfg);
3049 err = snd_config_search(cfg, "Syntax", &c);
3051 snd_error(UCM, "Syntax field not found in %s", d_name);
3052 snd_config_delete(cfg);
3055 err = snd_config_get_integer(c, &l);
3057 snd_error(UCM, "Syntax field is invalid in %s", d_name);
3058 snd_config_delete(cfg);
3061 if (l < 2 || l > SYNTAX_VERSION_MAX) {
3062 snd_error(UCM, "Incompatible syntax %d in %s", l, d_name);
3063 snd_config_delete(cfg);
3066 err = snd_config_search(cfg, "Comment", &c);
3068 err = parse_string(c, (char **)&list[j+1]);
3070 snd_config_delete(cfg);
3074 snd_config_delete(cfg);
3075 list[j] = strdup(d_name);
3076 if (list[j] == NULL) {
3080 if (strcmp(dfl, list[j]) == 0) {
3081 /* default to top */
3082 const char *save1 = list[j];
3083 const char *save2 = list[j + 1];
3084 memmove(list + 2, list, j * sizeof(char *));
3093 for (i = 0; i < cnt; i++)
3097 for (i = 0; i < j; i++) {
3098 free((void *)list[i * 2]);
3099 free((void *)list[i * 2 + 1]);