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"
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"
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 */
58 static int filename_filter(const struct dirent *dirent);
59 static int is_component_directory(const char *dir);
61 static int parse_sequence(snd_use_case_mgr_t *uc_mgr,
62 struct list_head *base,
66 * compose the absolute ucm filename
68 static void ucm_filename(char *fn, size_t fn_len, long version,
69 const char *dir, const char *file)
71 const char *env = getenv(version > 1 ? ALSA_CONFIG_UCM2_VAR : ALSA_CONFIG_UCM_VAR);
74 snprintf(fn, fn_len, "%s/%s/%s%s%s",
75 snd_config_topdir(), version > 1 ? "ucm2" : "ucm",
76 dir ?: "", dir ? "/" : "", file);
78 snprintf(fn, fn_len, "%s/%s%s%s",
79 env, dir ?: "", dir ? "/" : "", file);
85 int uc_mgr_config_load_file(snd_use_case_mgr_t *uc_mgr,
86 const char *file, snd_config_t **cfg)
88 char filename[PATH_MAX];
91 ucm_filename(filename, sizeof(filename), uc_mgr->conf_format,
92 file[0] == '/' ? NULL : uc_mgr->conf_dir_name,
94 err = uc_mgr_config_load(uc_mgr->conf_format, filename, cfg);
96 uc_error("error: failed to open file %s: %d", filename, err);
103 * Replace mallocated string
105 static char *replace_string(char **dst, const char *value)
108 *dst = value ? strdup(value) : NULL;
115 int parse_string(snd_config_t *n, char **res)
119 err = snd_config_get_string(n, (const char **)res);
129 * Parse string and substitute
131 int parse_string_substitute(snd_use_case_mgr_t *uc_mgr,
132 snd_config_t *n, char **res)
138 err = snd_config_get_string(n, &str);
141 err = uc_mgr_get_substituted_value(uc_mgr, &s, str);
148 * Parse string and substitute
150 int parse_string_substitute3(snd_use_case_mgr_t *uc_mgr,
151 snd_config_t *n, char **res)
153 if (uc_mgr->conf_format < 3)
154 return parse_string(n, res);
155 return parse_string_substitute(uc_mgr, n, res);
159 * Parse integer with substitution
161 int parse_integer_substitute(snd_use_case_mgr_t *uc_mgr,
162 snd_config_t *n, long *res)
167 err = snd_config_get_ascii(n, &s1);
170 err = uc_mgr_get_substituted_value(uc_mgr, &s2, s1);
172 err = safe_strtol(s2, res);
179 * Parse integer with substitution
181 int parse_integer_substitute3(snd_use_case_mgr_t *uc_mgr,
182 snd_config_t *n, long *res)
187 err = snd_config_get_ascii(n, &s1);
190 if (uc_mgr->conf_format < 3)
193 err = uc_mgr_get_substituted_value(uc_mgr, &s2, s1);
195 err = safe_strtol(s2, res);
205 int parse_is_name_safe(const char *name)
207 if (strchr(name, '.')) {
208 uc_error("char '.' not allowed in '%s'", name);
214 int get_string3(snd_use_case_mgr_t *uc_mgr, const char *s1, char **s)
216 if (uc_mgr->conf_format < 3) {
222 return uc_mgr_get_substituted_value(uc_mgr, s, s1);
225 int parse_get_safe_name(snd_use_case_mgr_t *uc_mgr, snd_config_t *n,
226 const char *alt, char **name)
234 err = snd_config_get_id(n, &id);
238 err = get_string3(uc_mgr, id, name);
241 if (!parse_is_name_safe(*name)) {
249 * Handle 'Error' configuration node.
251 static int error_node(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
256 err = parse_string_substitute3(uc_mgr, cfg, &s);
258 uc_error("error: failed to get Error string");
267 * Evaluate variable regex definitions (in-place delete)
269 static int evaluate_regex(snd_use_case_mgr_t *uc_mgr,
272 snd_config_iterator_t i, next;
277 err = snd_config_search(cfg, "DefineRegex", &d);
283 if (snd_config_get_type(d) != SND_CONFIG_TYPE_COMPOUND) {
284 uc_error("compound type expected for DefineRegex");
288 if (uc_mgr->conf_format < 3) {
289 uc_error("DefineRegex is supported in v3+ syntax");
293 snd_config_for_each(i, next, d) {
294 n = snd_config_iterator_entry(i);
295 err = snd_config_get_id(n, &id);
298 err = uc_mgr_define_regex(uc_mgr, id, n);
303 snd_config_delete(d);
308 * Evaluate variable definitions (in-place delete)
310 static int evaluate_define(snd_use_case_mgr_t *uc_mgr,
313 snd_config_iterator_t i, next;
319 err = snd_config_search(cfg, "Define", &d);
321 return evaluate_regex(uc_mgr, cfg);
325 if (snd_config_get_type(d) != SND_CONFIG_TYPE_COMPOUND) {
326 uc_error("compound type expected for Define");
330 if (uc_mgr->conf_format < 3) {
331 uc_error("Define is supported in v3+ syntax");
335 snd_config_for_each(i, next, d) {
336 n = snd_config_iterator_entry(i);
337 err = snd_config_get_id(n, &id);
340 err = snd_config_get_ascii(n, &var);
343 err = uc_mgr_get_substituted_value(uc_mgr, &s, var);
347 uc_mgr_set_variable(uc_mgr, id, s);
351 snd_config_delete(d);
353 return evaluate_regex(uc_mgr, cfg);
357 * Evaluate include (in-place)
359 static int evaluate_include(snd_use_case_mgr_t *uc_mgr,
365 err = snd_config_search(cfg, "Include", &n);
371 err = uc_mgr_evaluate_include(uc_mgr, cfg, n);
372 snd_config_delete(n);
377 * Evaluate condition (in-place)
379 static int evaluate_condition(snd_use_case_mgr_t *uc_mgr,
385 err = snd_config_search(cfg, "If", &n);
391 err = uc_mgr_evaluate_condition(uc_mgr, cfg, n);
392 snd_config_delete(n);
399 int uc_mgr_evaluate_inplace(snd_use_case_mgr_t *uc_mgr,
402 int err1 = 0, err2 = 0, err3 = 0;
404 while (err1 == 0 || err2 == 0 || err3 == 0) {
405 /* variables at first */
406 err1 = evaluate_define(uc_mgr, cfg);
409 /* include at second */
410 err2 = evaluate_include(uc_mgr, cfg);
413 /* include may define another variables */
414 /* conditions may depend on them */
417 err3 = evaluate_condition(uc_mgr, cfg);
425 * Parse one item for alsa-lib config
427 static int parse_libconfig1(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
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;
435 if (snd_config_get_id(cfg, &id) < 0)
438 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
439 uc_error("compound type expected for %s", id);
443 snd_config_for_each(i, next, cfg) {
444 n = snd_config_iterator_entry(i);
446 if (snd_config_get_id(n, &id) < 0)
449 if (strcmp(id, "File") == 0 ||
450 strcmp(id, "SubstiFile") == 0) {
451 substfile = id[0] == 'S';
452 err = snd_config_get_string(n, &file);
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)
467 uc_error("unknown field %s", id);
474 err = uc_mgr_config_load(uc_mgr->conf_format, file, &cfg);
477 err = uc_mgr_substitute_tree(uc_mgr, cfg);
479 snd_config_delete(config);
482 err = snd_config_merge(uc_mgr->local_config, cfg, 1);
484 snd_config_delete(cfg);
488 char filename[PATH_MAX];
490 ucm_filename(filename, sizeof(filename), uc_mgr->conf_format,
491 file[0] == '/' ? NULL : uc_mgr->conf_dir_name,
493 err = uc_mgr_config_load_into(uc_mgr->conf_format, filename, uc_mgr->local_config);
501 err = uc_mgr_substitute_tree(uc_mgr, config);
503 snd_config_delete(config);
507 err = snd_config_merge(uc_mgr->local_config, config, 1);
509 snd_config_delete(config);
518 * Parse alsa-lib config
520 static int parse_libconfig(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
522 snd_config_iterator_t i, next;
527 if (snd_config_get_id(cfg, &id) < 0)
530 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
531 uc_error("compound type expected for %s", id);
535 snd_config_for_each(i, next, cfg) {
536 n = snd_config_iterator_entry(i);
538 err = parse_libconfig1(uc_mgr, n);
549 static int parse_transition(snd_use_case_mgr_t *uc_mgr,
550 struct list_head *tlist,
553 struct transition_sequence *tseq;
555 snd_config_iterator_t i, next;
559 if (snd_config_get_id(cfg, &id) < 0)
562 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
563 uc_error("compound type expected for %s", id);
567 snd_config_for_each(i, next, cfg) {
568 n = snd_config_iterator_entry(i);
570 if (snd_config_get_id(n, &id) < 0)
573 tseq = calloc(1, sizeof(*tseq));
576 INIT_LIST_HEAD(&tseq->transition_list);
578 err = get_string3(uc_mgr, id, &tseq->name);
584 err = parse_sequence(uc_mgr, &tseq->transition_list, n);
586 uc_mgr_free_transition_element(tseq);
590 list_add(&tseq->list, tlist);
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)
603 snd_config_iterator_t i, next;
607 if (snd_config_get_id(cfg, &id) < 0)
610 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
611 uc_error("compound type expected for %s", id);
615 snd_config_for_each(i, next, cfg) {
616 n = snd_config_iterator_entry(i);
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));
623 err = fcn(uc_mgr, n, data1, data2);
631 static int strip_legacy_dev_index(char *name)
633 char *dot = strchr(name, '.');
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);
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,
653 struct dev_list_node *sdev;
655 snd_config_iterator_t i, next;
659 if (dev_list->type != DEVLIST_NONE) {
660 uc_error("error: multiple supported or"
661 " conflicting device lists");
665 if (snd_config_get_id(cfg, &id) < 0)
668 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
669 uc_error("compound type expected for %s", id);
673 snd_config_for_each(i, next, cfg) {
674 n = snd_config_iterator_entry(i);
676 if (snd_config_get_id(n, &id) < 0)
679 sdev = calloc(1, sizeof(struct dev_list_node));
682 err = parse_string_substitute3(uc_mgr, n, &sdev->name);
687 err = strip_legacy_dev_index(sdev->name);
693 list_add(&sdev->list, &dev_list->list);
696 dev_list->type = type;
701 /* Find a component device by its name, and remove it from machine device
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.
713 struct use_case_device *find_component_dev(snd_use_case_mgr_t *uc_mgr,
716 struct list_head *pos, *posdev, *_posdev;
717 struct use_case_verb *verb;
718 struct use_case_device *dev;
720 list_for_each(pos, &uc_mgr->verb_list) {
721 verb = list_entry(pos, struct use_case_verb, list);
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))
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
738 list_del(&dev->list);
739 list_add_tail(&dev->list,
740 &verb->cmpt_device_list);
749 /* parse sequence of a component device
751 * This function will find the component device and mark if its enable or
752 * disable sequence is needed by its parenet device.
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)
761 err = parse_string_substitute3(uc_mgr, n, &val);
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);
773 /* Parent needs its enable or disable sequence */
774 cmpt_seq->enable = enable;
782 * Sequence controls elements are in the following form:-
785 * cset "element_id_syntax value_syntax"
787 * exec "any unix command with arguments"
788 * enadev "component device name"
789 * disdev "component device name"
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"
797 static int parse_sequence(snd_use_case_mgr_t *uc_mgr,
798 struct list_head *base,
801 struct sequence_element *curr;
802 snd_config_iterator_t i, next;
805 const char *cmd = NULL;
807 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
808 uc_error("error: compound is expected for sequence definition");
812 snd_config_for_each(i, next, cfg) {
815 n = snd_config_iterator_entry(i);
816 err = snd_config_get_id(n, &id);
820 if (snd_config_get_type(n) != SND_CONFIG_TYPE_STRING) {
821 uc_error("error: string type is expected for sequence command");
824 snd_config_get_string(n, &cmd);
828 /* alloc new sequence element */
829 curr = calloc(1, sizeof(struct sequence_element));
832 list_add_tail(&curr->list, base);
834 if (strcmp(cmd, "cdev") == 0) {
835 curr->type = SEQUENCE_ELEMENT_TYPE_CDEV;
836 err = parse_string_substitute3(uc_mgr, n, &curr->data.cdev);
838 uc_error("error: cdev requires a string!");
844 if (strcmp(cmd, "cset") == 0) {
845 curr->type = SEQUENCE_ELEMENT_TYPE_CSET;
847 err = parse_string_substitute3(uc_mgr, n, &curr->data.cset);
849 uc_error("error: %s requires a string!", cmd);
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);
861 uc_error("error: enadev requires a valid device!");
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);
873 uc_error("error: disdev requires a valid device!");
879 if (strcmp(cmd, "cset-bin-file") == 0) {
880 curr->type = SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE;
884 if (strcmp(cmd, "cset-tlv") == 0) {
885 curr->type = SEQUENCE_ELEMENT_TYPE_CSET_TLV;
889 if (strcmp(cmd, "cset-new") == 0) {
890 curr->type = SEQUENCE_ELEMENT_TYPE_CSET_NEW;
894 if (strcmp(cmd, "ctl-remove") == 0) {
895 curr->type = SEQUENCE_ELEMENT_TYPE_CTL_REMOVE;
899 if (strcmp(cmd, "sysw") == 0) {
900 curr->type = SEQUENCE_ELEMENT_TYPE_SYSSET;
901 err = parse_string_substitute3(uc_mgr, n, &curr->data.sysw);
903 uc_error("error: sysw requires a string!");
909 if (strcmp(cmd, "usleep") == 0) {
910 curr->type = SEQUENCE_ELEMENT_TYPE_SLEEP;
911 err = parse_integer_substitute3(uc_mgr, n, &curr->data.sleep);
913 uc_error("error: usleep requires integer!");
919 if (strcmp(cmd, "msleep") == 0) {
920 curr->type = SEQUENCE_ELEMENT_TYPE_SLEEP;
921 err = parse_integer_substitute3(uc_mgr, n, &curr->data.sleep);
923 uc_error("error: msleep requires integer!");
926 curr->data.sleep *= 1000L;
930 if (strcmp(cmd, "exec") == 0) {
931 curr->type = SEQUENCE_ELEMENT_TYPE_EXEC;
932 err = parse_string_substitute3(uc_mgr, n, &curr->data.exec);
934 uc_error("error: exec requires a string!");
940 if (strcmp(cmd, "comment") == 0)
943 uc_error("error: sequence command '%s' is ignored", cmd);
946 list_del(&curr->list);
947 uc_mgr_free_sequence_element(curr);
956 int uc_mgr_add_value(struct list_head *base, const char *key, char *val)
958 struct ucm_value *curr;
960 curr = calloc(1, sizeof(struct ucm_value));
963 curr->name = strdup(key);
964 if (curr->name == NULL) {
968 list_add_tail(&curr->list, base);
976 * Parse values describing PCM, control/mixer settings and stream parameters.
981 * PlaybackVolume "name='Master Playback Volume',index=2"
982 * PlaybackSwitch "name='Master Playback Switch',index=2"
985 static int parse_value(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED,
986 struct list_head *base,
989 snd_config_iterator_t i, next;
992 snd_config_type_t type;
995 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
996 uc_error("error: compound is expected for value definition");
1000 /* in-place evaluation */
1001 err = uc_mgr_evaluate_inplace(uc_mgr, cfg);
1005 snd_config_for_each(i, next, cfg) {
1007 n = snd_config_iterator_entry(i);
1008 err = snd_config_get_id(n, &id);
1012 type = snd_config_get_type(n);
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);
1019 uc_error("error: unable to parse value for id '%s': %s!", id, snd_strerror(err));
1023 case SND_CONFIG_TYPE_STRING:
1024 err = parse_string_substitute(uc_mgr, n, &s);
1026 uc_error("error: unable to parse a string for id '%s'!", id);
1031 uc_error("error: invalid type %i in Value compound '%s'", type, id);
1034 err = uc_mgr_add_value(base, id, s);
1045 * Parse Modifier Use cases
1047 * # Each modifier is described in new section. N modifiers are allowed
1048 * SectionModifier."Capture Voice" {
1050 * Comment "Record voice call"
1057 * ConflictingDevice [
1070 * TransitionSequence."ToModifierName" [
1074 * # Optional TQ and ALSA PCMs
1078 * PlaybackVolume "name='Master Playback Volume',index=2"
1079 * PlaybackSwitch "name='Master Playback Switch',index=2"
1083 * SupportedDevice and ConflictingDevice cannot be specified together.
1084 * Both are optional.
1086 static int parse_modifier(snd_use_case_mgr_t *uc_mgr,
1088 void *data1, void *data2)
1090 struct use_case_verb *verb = data1;
1091 struct use_case_modifier *modifier;
1093 snd_config_iterator_t i, next;
1097 if (parse_get_safe_name(uc_mgr, cfg, data2, &name) < 0)
1100 /* allocate modifier */
1101 modifier = calloc(1, sizeof(*modifier));
1102 if (modifier == NULL) {
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;
1114 /* in-place evaluation */
1115 err = uc_mgr_evaluate_inplace(uc_mgr, cfg);
1119 snd_config_for_each(i, next, cfg) {
1121 n = snd_config_iterator_entry(i);
1122 if (snd_config_get_id(n, &id) < 0)
1125 if (strcmp(id, "Comment") == 0) {
1126 err = parse_string_substitute3(uc_mgr, n, &modifier->comment);
1128 uc_error("error: failed to get modifier comment");
1134 if (strcmp(id, "SupportedDevice") == 0) {
1135 err = parse_device_list(uc_mgr, &modifier->dev_list,
1136 DEVLIST_SUPPORTED, n);
1138 uc_error("error: failed to parse supported"
1144 if (strcmp(id, "ConflictingDevice") == 0) {
1145 err = parse_device_list(uc_mgr, &modifier->dev_list,
1146 DEVLIST_CONFLICTING, n);
1148 uc_error("error: failed to parse conflicting"
1154 if (strcmp(id, "EnableSequence") == 0) {
1155 err = parse_sequence(uc_mgr, &modifier->enable_list, n);
1157 uc_error("error: failed to parse modifier"
1158 " enable sequence");
1164 if (strcmp(id, "DisableSequence") == 0) {
1165 err = parse_sequence(uc_mgr, &modifier->disable_list, n);
1167 uc_error("error: failed to parse modifier"
1168 " disable sequence");
1174 if (strcmp(id, "TransitionSequence") == 0) {
1175 err = parse_transition(uc_mgr, &modifier->transition_list, n);
1177 uc_error("error: failed to parse transition"
1184 if (strcmp(id, "Value") == 0) {
1185 err = parse_value(uc_mgr, &modifier->value_list, n);
1187 uc_error("error: failed to parse Value");
1198 * Parse Device Use Cases
1200 * # Each device is described in new section. N devices are allowed
1201 * SectionDevice."Headphones" {
1202 * Comment "Headphones connected to 3.5mm jack"
1209 * ConflictingDevice [
1222 * TransitionSequence."ToDevice" [
1227 * PlaybackVolume "name='Master Playback Volume',index=2"
1228 * PlaybackSwitch "name='Master Playback Switch',index=2"
1232 static int parse_device(snd_use_case_mgr_t *uc_mgr,
1234 void *data1, void *data2)
1236 struct use_case_verb *verb = data1;
1238 struct use_case_device *device;
1239 snd_config_iterator_t i, next;
1243 if (parse_get_safe_name(uc_mgr, cfg, data2, &name) < 0)
1246 device = calloc(1, sizeof(*device));
1247 if (device == NULL) {
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;
1259 /* in-place evaluation */
1260 err = uc_mgr_evaluate_inplace(uc_mgr, cfg);
1264 snd_config_for_each(i, next, cfg) {
1266 n = snd_config_iterator_entry(i);
1267 if (snd_config_get_id(n, &id) < 0)
1270 if (strcmp(id, "Comment") == 0) {
1271 err = parse_string_substitute3(uc_mgr, n, &device->comment);
1273 uc_error("error: failed to get device comment");
1279 if (strcmp(id, "SupportedDevice") == 0) {
1280 err = parse_device_list(uc_mgr, &device->dev_list,
1281 DEVLIST_SUPPORTED, n);
1283 uc_error("error: failed to parse supported"
1289 if (strcmp(id, "ConflictingDevice") == 0) {
1290 err = parse_device_list(uc_mgr, &device->dev_list,
1291 DEVLIST_CONFLICTING, n);
1293 uc_error("error: failed to parse conflicting"
1299 if (strcmp(id, "EnableSequence") == 0) {
1300 uc_dbg("EnableSequence");
1301 err = parse_sequence(uc_mgr, &device->enable_list, n);
1303 uc_error("error: failed to parse device enable"
1310 if (strcmp(id, "DisableSequence") == 0) {
1311 uc_dbg("DisableSequence");
1312 err = parse_sequence(uc_mgr, &device->disable_list, n);
1314 uc_error("error: failed to parse device disable"
1321 if (strcmp(id, "TransitionSequence") == 0) {
1322 uc_dbg("TransitionSequence");
1323 err = parse_transition(uc_mgr, &device->transition_list, n);
1325 uc_error("error: failed to parse transition"
1332 if (strcmp(id, "Value") == 0) {
1333 err = parse_value(uc_mgr, &device->value_list, n);
1335 uc_error("error: failed to parse Value");
1345 * Parse Device Rename/Delete Command
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"
1353 static int parse_dev_name_list(snd_use_case_mgr_t *uc_mgr,
1355 struct list_head *list)
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;
1365 if (snd_config_get_id(cfg, &id) < 0)
1368 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
1369 uc_error("compound type expected for %s", id);
1373 snd_config_for_each(i, next, cfg) {
1374 n = snd_config_iterator_entry(i);
1376 if (snd_config_get_id(n, &name1) < 0)
1379 err = get_string3(uc_mgr, name1, &name1s);
1383 err = parse_string_substitute3(uc_mgr, n, &name2);
1386 uc_error("error: failed to get target device name for '%s'", name1);
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) {
1402 dev = calloc(1, sizeof(*dev));
1407 dev->name1 = strdup(name1);
1408 if (dev->name1 == NULL) {
1414 list_add_tail(&dev->list, list);
1420 static int parse_compound_check_legacy(snd_use_case_mgr_t *uc_mgr,
1422 int (*fcn)(snd_use_case_mgr_t *, snd_config_t *, void *, void *),
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;
1431 err = snd_config_get_id(cfg, &id);
1435 snd_config_for_each(i, next, cfg) {
1437 if (child_ctr > 1) {
1441 child = snd_config_iterator_entry(i);
1443 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
1448 if (snd_config_get_id(child, &idchild) < 0)
1451 if (strcmp(idchild, "0")) {
1456 if (child_ctr != 1) {
1461 return parse_compound(uc_mgr, cfg, fcn, data1, (void *)id);
1463 return fcn(uc_mgr, cfg, data1, NULL);
1466 static int parse_device_name(snd_use_case_mgr_t *uc_mgr,
1469 void *data2 ATTRIBUTE_UNUSED)
1471 return parse_compound_check_legacy(uc_mgr, cfg, parse_device, data1);
1474 static int parse_modifier_name(snd_use_case_mgr_t *uc_mgr,
1477 void *data2 ATTRIBUTE_UNUSED)
1479 return parse_compound(uc_mgr, cfg, parse_modifier, data1, data2);
1482 static int verb_dev_list_add(struct use_case_verb *verb,
1483 enum dev_list_type dst_type,
1487 struct use_case_device *device;
1488 struct list_head *pos;
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)
1494 if (device->dev_list.type != dst_type) {
1495 if (list_empty(&device->dev_list.list)) {
1496 device->dev_list.type = dst_type;
1498 uc_error("error: incompatible device list type ('%s', '%s')",
1503 return uc_mgr_put_to_dev_list(&device->dev_list, src);
1505 uc_error("error: unable to find device '%s'", dst);
1509 static int verb_dev_list_check(struct use_case_verb *verb)
1511 struct list_head *pos, *pos2;
1512 struct use_case_device *device;
1513 struct dev_list_node *dlist;
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);
1529 static int verb_device_management(struct use_case_verb *verb)
1531 struct list_head *pos;
1532 struct ucm_dev_name *dev;
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);
1540 uc_error("error: cannot rename device '%s' to '%s'", dev->name1, dev->name2);
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);
1550 uc_error("error: cannot remove device '%s'", dev->name2);
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);
1559 /* handle conflicting/supported lists */
1560 return verb_dev_list_check(verb);
1564 * Parse Verb Section
1566 * # Example Use case verb section for Voice call blah
1567 * # By Joe Blogs <joe@blogs.com>
1570 * # enable and disable sequences are compulsory
1572 * cset "name='Master Playback Switch',index=2 0,0"
1573 * cset "name='Master Playback Volume',index=2 25,25"
1575 * cset "name='Master Playback Switch',index=2 1,1"
1576 * cset "name='Master Playback Volume',index=2 50,50"
1580 * cset "name='Master Playback Switch',index=2 0,0"
1581 * cset "name='Master Playback Volume',index=2 25,25"
1583 * cset "name='Master Playback Switch',index=2 1,1"
1584 * cset "name='Master Playback Volume',index=2 50,50"
1587 * # Optional transition verb
1588 * TransitionSequence."ToCaseName" [
1592 * # Optional TQ and ALSA PCMs
1596 * PlaybackPCM "hw:0"
1600 static int parse_verb(snd_use_case_mgr_t *uc_mgr,
1601 struct use_case_verb *verb,
1604 snd_config_iterator_t i, next;
1608 /* in-place evaluation */
1609 err = uc_mgr_evaluate_inplace(uc_mgr, cfg);
1613 /* parse verb section */
1614 snd_config_for_each(i, next, cfg) {
1616 n = snd_config_iterator_entry(i);
1617 if (snd_config_get_id(n, &id) < 0)
1620 if (strcmp(id, "EnableSequence") == 0) {
1621 uc_dbg("Parse EnableSequence");
1622 err = parse_sequence(uc_mgr, &verb->enable_list, n);
1624 uc_error("error: failed to parse verb enable sequence");
1630 if (strcmp(id, "DisableSequence") == 0) {
1631 uc_dbg("Parse DisableSequence");
1632 err = parse_sequence(uc_mgr, &verb->disable_list, n);
1634 uc_error("error: failed to parse verb disable sequence");
1640 if (strcmp(id, "TransitionSequence") == 0) {
1641 uc_dbg("Parse TransitionSequence");
1642 err = parse_transition(uc_mgr, &verb->transition_list, n);
1644 uc_error("error: failed to parse transition sequence");
1650 if (strcmp(id, "Value") == 0) {
1651 uc_dbg("Parse Value");
1652 err = parse_value(uc_mgr, &verb->value_list, n);
1663 * Parse a Use case verb file.
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.
1673 static int parse_verb_file(snd_use_case_mgr_t *uc_mgr,
1674 const char *use_case_name,
1675 const char *comment,
1678 snd_config_iterator_t i, next;
1680 struct use_case_verb *verb;
1685 verb = calloc(1, sizeof(struct use_case_verb));
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)
1700 verb->name = strdup(use_case_name);
1701 if (verb->name == NULL)
1704 if (comment != NULL) {
1705 verb->comment = strdup(comment);
1706 if (verb->comment == NULL)
1710 /* open Verb file for reading */
1711 err = uc_mgr_config_load_file(uc_mgr, file, &cfg);
1715 /* in-place evaluation */
1716 err = uc_mgr_evaluate_inplace(uc_mgr, cfg);
1720 /* parse master config sections */
1721 snd_config_for_each(i, next, cfg) {
1723 n = snd_config_iterator_entry(i);
1724 if (snd_config_get_id(n, &id) < 0)
1727 /* find verb section and parse it */
1728 if (strcmp(id, "SectionVerb") == 0) {
1729 err = parse_verb(uc_mgr, verb, n);
1731 uc_error("error: %s failed to parse verb",
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);
1743 uc_error("error: %s failed to parse device",
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);
1755 uc_error("error: %s failed to parse modifier",
1762 /* device renames */
1763 if (strcmp(id, "RenameDevice") == 0) {
1764 err = parse_dev_name_list(uc_mgr, n, &verb->rename_list);
1766 uc_error("error: %s failed to parse device rename",
1774 if (strcmp(id, "RemoveDevice") == 0) {
1775 err = parse_dev_name_list(uc_mgr, n, &verb->remove_list);
1777 uc_error("error: %s failed to parse device remove",
1784 /* alsa-lib configuration */
1785 if (uc_mgr->conf_format > 3 && strcmp(id, "LibraryConfig") == 0) {
1786 err = parse_libconfig(uc_mgr, n);
1788 uc_error("error: failed to parse LibConfig");
1795 snd_config_delete(cfg);
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);
1803 /* do device rename and delete */
1804 err = verb_device_management(verb);
1806 uc_error("error: device management error in verb '%s'", verb->name);
1813 snd_config_delete(cfg);
1818 * Parse master section for "Use Case" and "File" tags.
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)
1824 snd_config_iterator_t i, next;
1826 char *use_case_name, *file = NULL, *comment = NULL;
1829 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
1830 uc_error("compound type expected for use case section");
1834 err = parse_get_safe_name(uc_mgr, cfg, NULL, &use_case_name);
1836 uc_error("unable to get name for use case section");
1840 /* in-place evaluation */
1841 err = uc_mgr_evaluate_inplace(uc_mgr, cfg);
1845 /* parse master config sections */
1846 snd_config_for_each(i, next, cfg) {
1848 n = snd_config_iterator_entry(i);
1849 if (snd_config_get_id(n, &id) < 0)
1852 /* get use case verb file name */
1853 if (strcmp(id, "File") == 0) {
1854 err = parse_string_substitute3(uc_mgr, n, &file);
1856 uc_error("failed to get File");
1862 /* get optional use case comment */
1863 if (strncmp(id, "Comment", 7) == 0) {
1864 err = parse_string_substitute3(uc_mgr, n, &comment);
1866 uc_error("error: failed to get Comment");
1872 uc_error("unknown field %s in master section");
1875 uc_dbg("use_case_name %s file '%s'", use_case_name, file);
1877 /* do we have both use case name and file ? */
1879 uc_error("error: use case missing file");
1884 /* parse verb file */
1885 err = parse_verb_file(uc_mgr, use_case_name, comment, file);
1888 free(use_case_name);
1895 * parse controls which should be run only at initial boot (forcefully)
1897 static int parse_controls_fixedboot(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
1901 if (!list_empty(&uc_mgr->fixedboot_list)) {
1902 uc_error("FixedBoot list is not empty");
1905 err = parse_sequence(uc_mgr, &uc_mgr->fixedboot_list, cfg);
1907 uc_error("Unable to parse FixedBootSequence");
1915 * parse controls which should be run only at initial boot
1917 static int parse_controls_boot(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
1921 if (!list_empty(&uc_mgr->boot_list)) {
1922 uc_error("Boot list is not empty");
1925 err = parse_sequence(uc_mgr, &uc_mgr->boot_list, cfg);
1927 uc_error("Unable to parse BootSequence");
1937 static int parse_controls(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
1941 if (!list_empty(&uc_mgr->default_list)) {
1942 uc_error("Default list is not empty");
1945 err = parse_sequence(uc_mgr, &uc_mgr->default_list, cfg);
1947 uc_error("Unable to parse SectionDefaults");
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.
1958 * #Example master file for blah sound card
1959 * #By Joe Blogs <joe@bloggs.org>
1961 * Comment "Nice Abstracted Soundcard"
1963 * # The file is divided into Use case sections. One section per use case verb.
1965 * SectionUseCase."Voice Call" {
1966 * File "voice_call_blah"
1967 * Comment "Make a voice phone call."
1970 * SectionUseCase."HiFi" {
1972 * Comment "Play and record HiFi quality Music."
1975 * # Define Value defaults
1978 * PlaybackCTL "hw:CARD=0"
1979 * CaptureCTL "hw:CARD=0"
1982 * # The initial boot (run once) configuration.
1985 * cset "name='Master Playback Switch',index=2 1,1"
1986 * cset "name='Master Playback Volume',index=2 25,25"
1989 * # This file also stores the default sound card state.
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"
2000 * # End of example file.
2002 static int parse_master_file(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
2004 snd_config_iterator_t i, next;
2010 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
2011 uc_error("compound type expected for master file");
2015 if (uc_mgr->conf_format >= 2) {
2016 err = snd_config_search(cfg, "Syntax", &n);
2018 uc_error("Syntax field not found in %s", uc_mgr->conf_file_name);
2021 err = snd_config_get_integer(n, &l);
2023 uc_error("Syntax field is invalid in %s", uc_mgr->conf_file_name);
2026 if (l < 2 || l > SYNTAX_VERSION_MAX) {
2027 uc_error("Incompatible syntax %d in %s", l, uc_mgr->conf_file_name);
2030 /* delete this field to avoid strcmp() call in the loop */
2031 snd_config_delete(n);
2032 uc_mgr->conf_format = l;
2035 /* in-place evaluation */
2036 err = uc_mgr_evaluate_inplace(uc_mgr, cfg);
2040 /* parse master config sections */
2041 snd_config_for_each(i, next, cfg) {
2043 n = snd_config_iterator_entry(i);
2044 if (snd_config_get_id(n, &id) < 0)
2047 if (strcmp(id, "Comment") == 0) {
2048 err = parse_string_substitute3(uc_mgr, n, &uc_mgr->comment);
2050 uc_error("error: failed to get master comment");
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,
2066 /* find default control values section (force boot sequence only) */
2067 if (strcmp(id, "FixedBootSequence") == 0) {
2068 err = parse_controls_fixedboot(uc_mgr, n);
2074 /* find default control values section (first boot only) */
2075 if (strcmp(id, "BootSequence") == 0) {
2076 err = parse_controls_boot(uc_mgr, n);
2082 /* find default control values section and parse it */
2083 if (strcmp(id, "SectionDefaults") == 0) {
2084 err = parse_controls(uc_mgr, n);
2090 /* get the default values */
2091 if (strcmp(id, "ValueDefaults") == 0) {
2092 err = parse_value(uc_mgr, &uc_mgr->value_list, n);
2094 uc_error("error: failed to parse ValueDefaults");
2100 /* alsa-lib configuration */
2101 if (uc_mgr->conf_format > 3 && strcmp(id, "LibraryConfig") == 0) {
2102 err = parse_libconfig(uc_mgr, n);
2104 uc_error("error: failed to parse LibraryConfig");
2111 if (strcmp(id, "Error") == 0)
2112 return error_node(uc_mgr, n);
2114 uc_error("uknown master file field %s", id);
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)
2124 struct ctl_list *ctl_list;
2127 err = uc_mgr_open_ctl(mgr, &ctl_list, ctl_name, 0);
2132 *info = ctl_list->ctl_info;
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)
2140 snd_ctl_card_info_t *info;
2141 const char *_driver, *_name, *_long_name;
2143 snd_ctl_card_info_alloca(&info);
2146 if (snd_card_next(&card) < 0 || card < 0) {
2147 uc_error("no soundcards found...");
2154 /* clear the list, keep the only one CTL device */
2155 uc_mgr_free_ctl_list(mgr);
2157 sprintf(name, "hw:%d", card);
2158 err = get_card_info(mgr, name, &info);
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))
2170 if (snd_card_next(&card) < 0) {
2171 uc_error("snd_card_next");
2176 uc_mgr_free_ctl_list(mgr);
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)
2184 return get_card_info(mgr, ctl_name, NULL);
2187 static int parse_toplevel_path(snd_use_case_mgr_t *uc_mgr,
2191 snd_config_iterator_t i, next, i2, next2;
2192 snd_config_t *n, *n2;
2194 char *dir = NULL, *file = NULL, fn[PATH_MAX];
2198 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
2199 uc_error("compound type expected for UseCasePath node");
2203 /* parse use case path config sections */
2204 snd_config_for_each(i, next, cfg) {
2205 n = snd_config_iterator_entry(i);
2207 if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
2208 uc_error("compound type expected for UseCasePath.something node");
2212 if (snd_config_get_id(n, &id) < 0)
2217 /* parse use case path config sections */
2218 snd_config_for_each(i2, next2, n) {
2220 n2 = snd_config_iterator_entry(i2);
2221 if (snd_config_get_id(n2, &id) < 0)
2224 if (strcmp(id, "Version") == 0) {
2225 err = parse_integer_substitute(uc_mgr, n2, &version);
2227 uc_error("unable to parse UcmDirectory");
2230 if (version < 1 || version > 2) {
2231 uc_error("Version must be 1 or 2");
2238 if (strcmp(id, "Directory") == 0) {
2239 err = parse_string_substitute(uc_mgr, n2, &dir);
2241 uc_error("unable to parse Directory");
2247 if (strcmp(id, "File") == 0) {
2248 err = parse_string_substitute(uc_mgr, n2, &file);
2250 uc_error("unable to parse File");
2256 uc_error("unknown UseCasePath field %s", id);
2260 uc_error("Directory is not defined in %s!", filename);
2264 uc_error("File is not defined in %s!", filename);
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) {
2274 if (replace_string(&uc_mgr->conf_file_name, file) == NULL) {
2278 strncpy(filename, fn, PATH_MAX);
2279 uc_mgr->conf_format = version;
2301 static int parse_toplevel_config(snd_use_case_mgr_t *uc_mgr,
2305 snd_config_iterator_t i, next;
2311 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
2312 uc_error("compound type expected for toplevel file");
2316 err = snd_config_search(cfg, "Syntax", &n);
2318 uc_error("Syntax field not found in %s", filename);
2321 err = snd_config_get_integer(n, &l);
2323 uc_error("Syntax field is invalid in %s", filename);
2326 if (l < 2 || l > SYNTAX_VERSION_MAX) {
2327 uc_error("Incompatible syntax %d in %s", l, filename);
2330 /* delete this field to avoid strcmp() call in the loop */
2331 snd_config_delete(n);
2332 uc_mgr->conf_format = l;
2334 /* in-place evaluation */
2335 err = uc_mgr_evaluate_inplace(uc_mgr, cfg);
2339 /* parse toplevel config sections */
2340 snd_config_for_each(i, next, cfg) {
2342 n = snd_config_iterator_entry(i);
2343 if (snd_config_get_id(n, &id) < 0)
2346 if (strcmp(id, "UseCasePath") == 0) {
2347 err = parse_toplevel_path(uc_mgr, filename, n);
2353 uc_error("uknown toplevel field %s", id);
2359 static int load_toplevel_config(snd_use_case_mgr_t *uc_mgr,
2362 char filename[PATH_MAX];
2366 ucm_filename(filename, sizeof(filename), 2, NULL, "ucm.conf");
2368 if (access(filename, R_OK) != 0) {
2369 uc_error("Unable to find the top-level configuration file '%s'.", filename);
2373 err = uc_mgr_config_load(2, filename, &tcfg);
2377 /* filename is shared for function input and output! */
2378 err = parse_toplevel_config(uc_mgr, filename, tcfg);
2379 snd_config_delete(tcfg);
2383 err = uc_mgr_config_load(uc_mgr->conf_format, filename, cfg);
2385 uc_error("error: could not parse configuration for card %s",
2396 /* load master use case file for sound card based on rules in ucm2/ucm.conf
2398 int uc_mgr_import_master_config(snd_use_case_mgr_t *uc_mgr)
2404 name = uc_mgr->card_name;
2405 if (strncmp(name, "hw:", 3) == 0) {
2406 err = get_by_card(uc_mgr, name);
2408 uc_error("card '%s' is not valid", name);
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);
2417 err = load_toplevel_config(uc_mgr, &cfg);
2421 err = parse_master_file(uc_mgr, cfg);
2422 snd_config_delete(cfg);
2424 uc_mgr_free_ctl_list(uc_mgr);
2425 uc_mgr_free_verb(uc_mgr);
2431 uc_mgr_free_ctl_list(uc_mgr);
2432 replace_string(&uc_mgr->conf_dir_name, NULL);
2436 static int filename_filter(const struct dirent *dirent)
2440 if (dirent->d_type == DT_DIR) {
2441 if (dirent->d_name[0] == '.') {
2442 if (dirent->d_name[1] == '\0')
2444 if (dirent->d_name[1] == '.' &&
2445 dirent->d_name[2] == '\0')
2453 /* whether input dir is a predefined component directory */
2454 static int is_component_directory(const char *dir)
2458 while (component_dir[i]) {
2459 if (!strncmp(dir, component_dir[i], PATH_MAX))
2467 /* scan all cards and comments
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
2475 int uc_mgr_scan_master_configs(const char **_list[])
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;
2484 struct dirent **namelist;
2487 snprintf(filename, sizeof(filename), "%s", env);
2489 snprintf(filename, sizeof(filename), "%s/ucm2",
2490 snd_config_topdir());
2492 #if defined(_GNU_SOURCE) && !defined(__NetBSD__) && !defined(__FreeBSD__) && !defined(__sun) && !defined(ANDROID)
2493 #define SORTFUNC versionsort
2495 #define SORTFUNC alphasort
2497 err = scandir(filename, &namelist, filename_filter, SORTFUNC);
2500 uc_error("error: could not scan directory %s: %s",
2501 filename, strerror(-err));
2507 if (strlen(filename) + 8 < sizeof(filename)) {
2508 strcat(filename, "/default");
2509 ss = readlink(filename, dfl, sizeof(dfl)-1);
2512 dfl[sizeof(dfl)-1] = '\0';
2513 if (dfl[0] && dfl[strlen(dfl)-1] == '/')
2514 dfl[strlen(dfl)-1] = '\0';
2520 list = calloc(1, cnt * 2 * sizeof(char *));
2526 for (i = j = 0; i < cnt; i++) {
2528 d_name = namelist[i]->d_name;
2530 /* Skip the directories for component devices */
2531 if (is_component_directory(d_name))
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))
2539 err = uc_mgr_config_load(2, filename, &cfg);
2542 err = snd_config_search(cfg, "Syntax", &c);
2544 uc_error("Syntax field not found in %s", d_name);
2545 snd_config_delete(cfg);
2548 err = snd_config_get_integer(c, &l);
2550 uc_error("Syntax field is invalid in %s", d_name);
2551 snd_config_delete(cfg);
2554 if (l < 2 || l > SYNTAX_VERSION_MAX) {
2555 uc_error("Incompatible syntax %d in %s", l, d_name);
2556 snd_config_delete(cfg);
2559 err = snd_config_search(cfg, "Comment", &c);
2561 err = parse_string(c, (char **)&list[j+1]);
2563 snd_config_delete(cfg);
2567 snd_config_delete(cfg);
2568 list[j] = strdup(d_name);
2569 if (list[j] == NULL) {
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 *));
2586 for (i = 0; i < cnt; i++) {
2589 free((void *)list[i * 2]);
2590 free((void *)list[i * 2 + 1]);