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"
44 static int get_value(snd_use_case_mgr_t *uc_mgr,
45 const char *identifier,
47 const char *mod_dev_name,
48 const char *verb_name,
50 static int get_value1(snd_use_case_mgr_t *uc_mgr, char **value,
51 struct list_head *value_list, const char *identifier);
52 static int get_value3(snd_use_case_mgr_t *uc_mgr,
54 const char *identifier,
55 struct list_head *value_list1,
56 struct list_head *value_list2,
57 struct list_head *value_list3);
59 static int execute_component_seq(snd_use_case_mgr_t *uc_mgr,
60 struct component_sequence *cmpt_seq,
61 struct list_head *value_list1,
62 struct list_head *value_list2,
63 struct list_head *value_list3,
66 static int check_identifier(const char *identifier, const char *prefix)
71 if (strncmp(identifier, prefix, len) != 0)
74 if (identifier[len] == 0 || identifier[len] == '/')
80 static int list_count(struct list_head *list)
82 struct list_head *pos;
85 list_for_each(pos, list) {
91 static int alloc_str_list(struct list_head *list, int mult, char **result[])
96 cnt = list_count(list) * mult;
101 res = calloc(mult, cnt * sizeof(char *));
109 * \brief Create an identifier
110 * \param fmt Format (sprintf like)
111 * \param ... Optional arguments for sprintf like format
112 * \return Allocated string identifier or NULL on error
114 char *snd_use_case_identifier(const char *fmt, ...)
117 int size = strlen(fmt) + 512;
124 vsnprintf(str, size, fmt, args);
127 res = realloc(str, strlen(str) + 1);
134 * \brief Free a string list
135 * \param list The string list to free
136 * \param items Count of strings
137 * \return Zero if success, otherwise a negative error code
139 int snd_use_case_free_list(const char *list[], int items)
144 for (i = 0; i < items; i++)
145 free((void *)list[i]);
150 static int read_tlv_file(unsigned int **res,
151 const char *filepath)
158 struct snd_ctl_tlv *tlv;
160 fd = open(filepath, O_RDONLY);
165 if (fstat(fd, &st) == -1) {
170 if (sz > 16 * 1024 * 1024 || sz < 8 || sz % 4) {
171 uc_error("File size should be less than 16 MB "
172 "and multiple of 4");
181 sz_read = read(fd, *res, sz);
182 if (sz_read < 0 || (size_t)sz_read != sz) {
187 /* Check if the tlv file specifies valid size. */
188 tlv = (struct snd_ctl_tlv *)(*res);
189 if (tlv->length + 2 * sizeof(unsigned int) != sz) {
190 uc_error("Invalid tlv size: %d", tlv->length);
201 static int binary_file_parse(snd_ctl_elem_value_t *dst,
202 snd_ctl_elem_info_t *info,
203 const char *filepath)
211 snd_ctl_elem_type_t type;
212 unsigned int idx, count;
214 type = snd_ctl_elem_info_get_type(info);
215 if (type != SND_CTL_ELEM_TYPE_BYTES) {
216 uc_error("only support byte type!");
220 fd = open(filepath, O_RDONLY);
225 if (stat(filepath, &st) == -1) {
230 count = snd_ctl_elem_info_get_count(info);
231 if (sz != count || sz > sizeof(dst->value.bytes)) {
232 uc_error("invalid parameter size %d!", sz);
241 sz_read = read(fd, res, sz);
242 if (sz_read < 0 || (size_t)sz_read != sz) {
246 for (idx = 0; idx < sz; idx++)
247 snd_ctl_elem_value_set_byte(dst, idx, *(res + idx));
255 extern int __snd_ctl_ascii_elem_id_parse(snd_ctl_elem_id_t *dst,
257 const char **ret_ptr);
259 static int execute_cset(snd_ctl_t *ctl, const char *cset, unsigned int type)
263 snd_ctl_elem_id_t *id;
264 snd_ctl_elem_value_t *value;
265 snd_ctl_elem_info_t *info;
266 unsigned int *res = NULL;
268 snd_ctl_elem_id_malloc(&id);
269 snd_ctl_elem_value_malloc(&value);
270 snd_ctl_elem_info_malloc(&info);
272 err = __snd_ctl_ascii_elem_id_parse(id, cset, &pos);
275 while (*pos && isspace(*pos))
278 uc_error("undefined value for cset >%s<", cset);
282 snd_ctl_elem_info_set_id(info, id);
283 err = snd_ctl_elem_info(ctl, info);
286 if (type == SEQUENCE_ELEMENT_TYPE_CSET_TLV) {
287 if (!snd_ctl_elem_info_is_tlv_writable(info)) {
291 err = read_tlv_file(&res, pos);
294 err = snd_ctl_elem_tlv_write(ctl, id, res);
298 snd_ctl_elem_value_set_id(value, id);
299 err = snd_ctl_elem_read(ctl, value);
302 if (type == SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE)
303 err = binary_file_parse(value, info, pos);
305 err = snd_ctl_ascii_value_parse(ctl, value, info, pos);
308 err = snd_ctl_elem_write(ctl, value);
327 * \brief Execute the sequence
328 * \param uc_mgr Use case manager
329 * \param seq Sequence
330 * \return zero on success, otherwise a negative error code
332 static int execute_sequence(snd_use_case_mgr_t *uc_mgr,
333 struct list_head *seq,
334 struct list_head *value_list1,
335 struct list_head *value_list2,
336 struct list_head *value_list3)
338 struct list_head *pos;
339 struct sequence_element *s;
341 snd_ctl_t *ctl = NULL;
342 struct ctl_list *ctl_list;
345 list_for_each(pos, seq) {
346 s = list_entry(pos, struct sequence_element, list);
348 case SEQUENCE_ELEMENT_TYPE_CDEV:
349 cdev = strdup(s->data.cdev);
353 case SEQUENCE_ELEMENT_TYPE_CSET:
354 case SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE:
355 case SEQUENCE_ELEMENT_TYPE_CSET_TLV:
356 if (cdev == NULL && uc_mgr->in_component_domain) {
357 /* For sequence of a component device, use
358 * its parent's cdev stored by ucm manager.
360 if (uc_mgr->cdev == NULL) {
361 uc_error("cdev is not defined!");
365 cdev = strndup(uc_mgr->cdev, PATH_MAX);
368 } else if (cdev == NULL) {
369 char *playback_ctl = NULL;
370 char *capture_ctl = NULL;
372 err = get_value3(uc_mgr, &playback_ctl, "PlaybackCTL",
376 if (err < 0 && err != -ENOENT) {
377 uc_error("cdev is not defined!");
380 err = get_value3(uc_mgr, &capture_ctl, "CaptureCTL",
384 if (err < 0 && err != -ENOENT) {
386 uc_error("cdev is not defined!");
389 if (playback_ctl == NULL &&
390 capture_ctl == NULL) {
391 uc_error("cdev is not defined!");
394 if (playback_ctl != NULL &&
395 capture_ctl != NULL &&
396 strcmp(playback_ctl, capture_ctl) != 0) {
399 uc_error("cdev is not equal for playback and capture!");
402 if (playback_ctl != NULL) {
410 err = uc_mgr_open_ctl(uc_mgr, &ctl_list, cdev, 1);
412 uc_error("unable to open ctl device '%s'", cdev);
417 err = execute_cset(ctl, s->data.cset, s->type);
419 uc_error("unable to execute cset '%s'", s->data.cset);
423 case SEQUENCE_ELEMENT_TYPE_SLEEP:
424 usleep(s->data.sleep);
426 case SEQUENCE_ELEMENT_TYPE_EXEC:
427 err = system(s->data.exec);
431 case SEQUENCE_ELEMENT_TYPE_CMPT_SEQ:
432 /* Execute enable or disable sequence of a component
433 * device. Pass the cdev defined by the machine device.
435 err = execute_component_seq(uc_mgr,
445 uc_error("unknown sequence command %i", s->type);
459 /* Execute enable or disable sequence of a component device.
461 * For a component device (a codec or embedded DSP), its sequence doesn't
462 * specify the sound card device 'cdev', because a component can be reused
463 * by different sound cards (machines). So when executing its sequence, a
464 * parameter 'cdev' is used to pass cdev defined by the sequence of its
465 * parent, the machine device. UCM manger will store the cdev when entering
466 * the component domain.
468 static int execute_component_seq(snd_use_case_mgr_t *uc_mgr,
469 struct component_sequence *cmpt_seq,
470 struct list_head *value_list1 ATTRIBUTE_UNUSED,
471 struct list_head *value_list2 ATTRIBUTE_UNUSED,
472 struct list_head *value_list3 ATTRIBUTE_UNUSED,
475 struct use_case_device *device = cmpt_seq->device;
476 struct list_head *seq;
479 /* enter component domain and store cdev for the component */
480 uc_mgr->in_component_domain = 1;
483 /* choose enable or disable sequence of the component device */
484 if (cmpt_seq->enable)
485 seq = &device->enable_list;
487 seq = &device->disable_list;
489 /* excecute the sequence of the component dev */
490 err = execute_sequence(uc_mgr, seq,
492 &uc_mgr->active_verb->value_list,
493 &uc_mgr->value_list);
495 /* exit component domain and clear cdev */
496 uc_mgr->in_component_domain = 0;
502 static int add_auto_value(snd_use_case_mgr_t *uc_mgr, const char *key, char *value)
507 err = get_value1(uc_mgr, &value, &uc_mgr->value_list, key);
508 if (err == -ENOENT) {
512 return uc_mgr_add_value(&uc_mgr->value_list, key, s);
513 } else if (err < 0) {
520 static int add_auto_values(snd_use_case_mgr_t *uc_mgr)
522 struct ctl_list *ctl_list;
527 ctl_list = uc_mgr_get_master_ctl(uc_mgr);
529 id = snd_ctl_card_info_get_id(ctl_list->ctl_info);
530 snprintf(buf, sizeof(buf), "hw:%s", id);
531 err = add_auto_value(uc_mgr, "PlaybackCTL", buf);
534 err = add_auto_value(uc_mgr, "CaptureCTL", buf);
542 * \brief execute default commands
543 * \param uc_mgr Use case manager
544 * \return zero on success, otherwise a negative error code
546 static int set_defaults(snd_use_case_mgr_t *uc_mgr)
550 if (uc_mgr->default_list_executed)
552 err = execute_sequence(uc_mgr, &uc_mgr->default_list,
553 &uc_mgr->value_list, NULL, NULL);
555 uc_error("Unable to execute default sequence");
558 uc_mgr->default_list_executed = 1;
563 * \brief Import master config and execute the default sequence
564 * \param uc_mgr Use case manager
565 * \return zero on success, otherwise a negative error code
567 static int import_master_config(snd_use_case_mgr_t *uc_mgr)
571 err = uc_mgr_import_master_config(uc_mgr);
574 return add_auto_values(uc_mgr);
578 * \brief Check, if the UCM configuration is empty
579 * \param uc_mgr Use case Manager
580 * \return zero on success, otherwise a negative error code
582 static int check_empty_configuration(snd_use_case_mgr_t *uc_mgr)
587 err = get_value(uc_mgr, "Linked", &value, NULL, NULL, 1);
589 err = strcasecmp(value, "true") == 0 ||
590 strcmp(value, "1") == 0;
595 if (!list_empty(&uc_mgr->verb_list))
597 if (!list_empty(&uc_mgr->boot_list))
603 * \brief Universal find - string in a list
604 * \param list List of structures
605 * \param offset Offset of list structure
606 * \param soffset Offset of string structure
607 * \param match String to match
608 * \return structure on success, otherwise a NULL (not found)
610 static void *find0(struct list_head *list,
611 unsigned long offset,
612 unsigned long soffset,
615 struct list_head *pos;
618 list_for_each(pos, list) {
619 ptr = list_entry_offset(pos, char, offset);
620 str = *((char **)(ptr + soffset));
621 if (strcmp(str, match) == 0)
627 #define find(list, type, member, value, match) \
628 find0(list, (unsigned long)(&((type *)0)->member), \
629 (unsigned long)(&((type *)0)->value), match)
632 * \brief Universal string list
633 * \param list List of structures
634 * \param result Result list
635 * \param offset Offset of list structure
636 * \param s1offset Offset of string structure
637 * \return count of items on success, otherwise a negative error code
639 static int get_list0(struct list_head *list,
640 const char **result[],
641 unsigned long offset,
642 unsigned long s1offset)
646 struct list_head *pos;
649 cnt = alloc_str_list(list, 1, &res);
654 *result = (const char **)res;
655 list_for_each(pos, list) {
656 ptr = list_entry_offset(pos, char, offset);
657 str1 = *((char **)(ptr + s1offset));
669 snd_use_case_free_list(*result, cnt);
673 #define get_list(list, result, type, member, s1) \
674 get_list0(list, result, \
675 (unsigned long)(&((type *)0)->member), \
676 (unsigned long)(&((type *)0)->s1))
679 * \brief Universal string list - pair of strings
680 * \param list List of structures
681 * \param result Result list
682 * \param offset Offset of list structure
683 * \param s1offset Offset of string structure
684 * \param s1offset Offset of string structure
685 * \return count of items on success, otherwise a negative error code
687 static int get_list20(struct list_head *list,
688 const char **result[],
689 unsigned long offset,
690 unsigned long s1offset,
691 unsigned long s2offset)
695 struct list_head *pos;
696 char *ptr, *str1, *str2;
698 cnt = alloc_str_list(list, 2, &res);
703 *result = (const char **)res;
704 list_for_each(pos, list) {
705 ptr = list_entry_offset(pos, char, offset);
706 str1 = *((char **)(ptr + s1offset));
715 str2 = *((char **)(ptr + s2offset));
727 snd_use_case_free_list(*result, cnt);
731 #define get_list2(list, result, type, member, s1, s2) \
732 get_list20(list, result, \
733 (unsigned long)(&((type *)0)->member), \
734 (unsigned long)(&((type *)0)->s1), \
735 (unsigned long)(&((type *)0)->s2))
739 * \param uc_mgr Use case manager
740 * \param verb_name verb to find
741 * \return structure on success, otherwise a NULL (not found)
743 static inline struct use_case_verb *find_verb(snd_use_case_mgr_t *uc_mgr,
744 const char *verb_name)
746 return find(&uc_mgr->verb_list,
747 struct use_case_verb, list, name,
751 static int is_devlist_supported(snd_use_case_mgr_t *uc_mgr,
752 struct dev_list *dev_list)
754 struct dev_list_node *device;
755 struct use_case_device *adev;
756 struct list_head *pos, *pos1;
759 switch (dev_list->type) {
763 case DEVLIST_SUPPORTED:
766 case DEVLIST_CONFLICTING:
771 list_for_each(pos, &dev_list->list) {
772 device = list_entry(pos, struct dev_list_node, list);
774 list_for_each(pos1, &uc_mgr->active_devices) {
775 adev = list_entry(pos1, struct use_case_device,
777 if (!strcmp(device->name, adev->name))
781 return 1 - found_ret;
784 static inline int is_modifier_supported(snd_use_case_mgr_t *uc_mgr,
785 struct use_case_modifier *modifier)
787 return is_devlist_supported(uc_mgr, &modifier->dev_list);
790 static inline int is_device_supported(snd_use_case_mgr_t *uc_mgr,
791 struct use_case_device *device)
793 return is_devlist_supported(uc_mgr, &device->dev_list);
798 * \param verb Use case verb
799 * \param device_name device to find
800 * \return structure on success, otherwise a NULL (not found)
802 static inline struct use_case_device *
803 find_device(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb,
804 const char *device_name, int check_supported)
806 struct use_case_device *device;
807 struct list_head *pos;
809 list_for_each(pos, &verb->device_list) {
810 device = list_entry(pos, struct use_case_device, list);
812 if (strcmp(device_name, device->name))
815 if (check_supported &&
816 !is_device_supported(uc_mgr, device))
825 * \brief Find modifier
826 * \param verb Use case verb
827 * \param modifier_name modifier to find
828 * \return structure on success, otherwise a NULL (not found)
830 static struct use_case_modifier *
831 find_modifier(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb,
832 const char *modifier_name, int check_supported)
834 struct use_case_modifier *modifier;
835 struct list_head *pos;
837 list_for_each(pos, &verb->modifier_list) {
838 modifier = list_entry(pos, struct use_case_modifier, list);
840 if (strcmp(modifier->name, modifier_name))
843 if (check_supported &&
844 !is_modifier_supported(uc_mgr, modifier))
852 long device_status(snd_use_case_mgr_t *uc_mgr,
853 const char *device_name)
855 struct use_case_device *dev;
856 struct list_head *pos;
858 list_for_each(pos, &uc_mgr->active_devices) {
859 dev = list_entry(pos, struct use_case_device, active_list);
860 if (strcmp(dev->name, device_name) == 0)
866 long modifier_status(snd_use_case_mgr_t *uc_mgr,
867 const char *modifier_name)
869 struct use_case_modifier *mod;
870 struct list_head *pos;
872 list_for_each(pos, &uc_mgr->active_modifiers) {
873 mod = list_entry(pos, struct use_case_modifier, active_list);
874 if (strcmp(mod->name, modifier_name) == 0)
882 * \param uc_mgr Use case manager
883 * \param verb verb to set
884 * \param enable nonzero = enable, zero = disable
885 * \return zero on success, otherwise a negative error code
887 static int set_verb(snd_use_case_mgr_t *uc_mgr,
888 struct use_case_verb *verb,
891 struct list_head *seq;
895 err = set_defaults(uc_mgr);
898 seq = &verb->enable_list;
900 seq = &verb->disable_list;
902 err = execute_sequence(uc_mgr, seq,
906 if (enable && err >= 0)
907 uc_mgr->active_verb = verb;
912 * \brief Set modifier
913 * \param uc_mgr Use case manager
914 * \param modifier modifier to set
915 * \param enable nonzero = enable, zero = disable
916 * \return zero on success, otherwise a negative error code
918 static int set_modifier(snd_use_case_mgr_t *uc_mgr,
919 struct use_case_modifier *modifier,
922 struct list_head *seq;
925 if (modifier_status(uc_mgr, modifier->name) == enable)
929 seq = &modifier->enable_list;
931 seq = &modifier->disable_list;
933 err = execute_sequence(uc_mgr, seq,
934 &modifier->value_list,
935 &uc_mgr->active_verb->value_list,
936 &uc_mgr->value_list);
937 if (enable && err >= 0) {
938 list_add_tail(&modifier->active_list, &uc_mgr->active_modifiers);
939 } else if (!enable) {
940 list_del(&modifier->active_list);
947 * \param uc_mgr Use case manager
948 * \param device device to set
949 * \param enable nonzero = enable, zero = disable
950 * \return zero on success, otherwise a negative error code
952 static int set_device(snd_use_case_mgr_t *uc_mgr,
953 struct use_case_device *device,
956 struct list_head *seq;
959 if (device_status(uc_mgr, device->name) == enable)
963 seq = &device->enable_list;
965 seq = &device->disable_list;
967 err = execute_sequence(uc_mgr, seq,
969 &uc_mgr->active_verb->value_list,
970 &uc_mgr->value_list);
971 if (enable && err >= 0) {
972 list_add_tail(&device->active_list, &uc_mgr->active_devices);
973 } else if (!enable) {
974 list_del(&device->active_list);
980 * \brief Init sound card use case manager.
981 * \param uc_mgr Returned use case manager pointer
982 * \param card_name name of card to open
983 * \return zero on success, otherwise a negative error code
985 int snd_use_case_mgr_open(snd_use_case_mgr_t **uc_mgr,
986 const char *card_name)
988 snd_use_case_mgr_t *mgr;
991 /* create a new UCM */
992 mgr = calloc(1, sizeof(snd_use_case_mgr_t));
995 INIT_LIST_HEAD(&mgr->verb_list);
996 INIT_LIST_HEAD(&mgr->boot_list);
997 INIT_LIST_HEAD(&mgr->default_list);
998 INIT_LIST_HEAD(&mgr->value_list);
999 INIT_LIST_HEAD(&mgr->active_modifiers);
1000 INIT_LIST_HEAD(&mgr->active_devices);
1001 INIT_LIST_HEAD(&mgr->ctl_list);
1002 INIT_LIST_HEAD(&mgr->variable_list);
1003 pthread_mutex_init(&mgr->mutex, NULL);
1005 mgr->card_name = strdup(card_name);
1006 if (mgr->card_name == NULL) {
1011 /* get info on use_cases and verify against card */
1012 err = import_master_config(mgr);
1014 uc_error("error: failed to import %s use case configuration %d",
1019 err = check_empty_configuration(mgr);
1021 uc_error("error: failed to import %s (empty configuration)", card_name);
1034 * \brief Reload and reparse all use case files.
1035 * \param uc_mgr Use case manager
1036 * \return zero on success, otherwise a negative error code
1038 int snd_use_case_mgr_reload(snd_use_case_mgr_t *uc_mgr)
1042 pthread_mutex_lock(&uc_mgr->mutex);
1044 uc_mgr_free_verb(uc_mgr);
1046 uc_mgr->default_list_executed = 0;
1048 /* reload all use cases */
1049 err = import_master_config(uc_mgr);
1051 uc_error("error: failed to reload use cases");
1052 pthread_mutex_unlock(&uc_mgr->mutex);
1056 pthread_mutex_unlock(&uc_mgr->mutex);
1061 * \brief Close use case manager.
1062 * \param uc_mgr Use case manager
1063 * \return zero on success, otherwise a negative error code
1065 int snd_use_case_mgr_close(snd_use_case_mgr_t *uc_mgr)
1067 uc_mgr_free(uc_mgr);
1073 * Tear down current use case verb, device and modifier.
1075 static int dismantle_use_case(snd_use_case_mgr_t *uc_mgr)
1077 struct list_head *pos, *npos;
1078 struct use_case_modifier *modifier;
1079 struct use_case_device *device;
1082 list_for_each_safe(pos, npos, &uc_mgr->active_modifiers) {
1083 modifier = list_entry(pos, struct use_case_modifier,
1085 err = set_modifier(uc_mgr, modifier, 0);
1087 uc_error("Unable to disable modifier %s", modifier->name);
1089 INIT_LIST_HEAD(&uc_mgr->active_modifiers);
1091 list_for_each_safe(pos, npos, &uc_mgr->active_devices) {
1092 device = list_entry(pos, struct use_case_device,
1094 err = set_device(uc_mgr, device, 0);
1096 uc_error("Unable to disable device %s", device->name);
1098 INIT_LIST_HEAD(&uc_mgr->active_devices);
1100 err = set_verb(uc_mgr, uc_mgr->active_verb, 0);
1102 uc_error("Unable to disable verb %s", uc_mgr->active_verb->name);
1105 uc_mgr->active_verb = NULL;
1107 err = execute_sequence(uc_mgr, &uc_mgr->default_list,
1108 &uc_mgr->value_list, NULL, NULL);
1114 * \brief Reset sound card controls to default values.
1115 * \param uc_mgr Use case manager
1116 * \return zero on success, otherwise a negative error code
1118 int snd_use_case_mgr_reset(snd_use_case_mgr_t *uc_mgr)
1122 pthread_mutex_lock(&uc_mgr->mutex);
1123 err = execute_sequence(uc_mgr, &uc_mgr->default_list,
1124 &uc_mgr->value_list, NULL, NULL);
1125 INIT_LIST_HEAD(&uc_mgr->active_modifiers);
1126 INIT_LIST_HEAD(&uc_mgr->active_devices);
1127 uc_mgr->active_verb = NULL;
1128 pthread_mutex_unlock(&uc_mgr->mutex);
1133 * \brief Get list of verbs in pair verbname+comment
1134 * \param list Returned list
1135 * \return Number of list entries if success, otherwise a negative error code
1137 static int get_verb_list(snd_use_case_mgr_t *uc_mgr, const char **list[])
1139 return get_list2(&uc_mgr->verb_list, list,
1140 struct use_case_verb, list,
1145 * \brief Get list of devices in pair devicename+comment
1146 * \param list Returned list
1147 * \param verbname For verb (NULL = current)
1148 * \return Number of list entries if success, otherwise a negative error code
1150 static int get_device_list(snd_use_case_mgr_t *uc_mgr, const char **list[],
1153 struct use_case_verb *verb;
1156 verb = find_verb(uc_mgr, verbname);
1158 verb = uc_mgr->active_verb;
1162 return get_list2(&verb->device_list, list,
1163 struct use_case_device, list,
1168 * \brief Get list of modifiers in pair devicename+comment
1169 * \param list Returned list
1170 * \param verbname For verb (NULL = current)
1171 * \return Number of list entries if success, otherwise a negative error code
1173 static int get_modifier_list(snd_use_case_mgr_t *uc_mgr, const char **list[],
1176 struct use_case_verb *verb;
1179 verb = find_verb(uc_mgr, verbname);
1181 verb = uc_mgr->active_verb;
1185 return get_list2(&verb->modifier_list, list,
1186 struct use_case_modifier, list,
1191 * \brief Get list of supported/conflicting devices
1192 * \param list Returned list
1193 * \param name Name of modifier or verb to query
1194 * \param type Type of device list entries to return
1195 * \return Number of list entries if success, otherwise a negative error code
1197 static int get_supcon_device_list(snd_use_case_mgr_t *uc_mgr,
1198 const char **list[], char *name,
1199 enum dev_list_type type)
1202 struct use_case_verb *verb;
1203 struct use_case_modifier *modifier;
1204 struct use_case_device *device;
1209 str = strchr(name, '/');
1212 verb = find_verb(uc_mgr, str + 1);
1215 verb = uc_mgr->active_verb;
1220 modifier = find_modifier(uc_mgr, verb, name, 0);
1222 if (modifier->dev_list.type != type) {
1226 return get_list(&modifier->dev_list.list, list,
1227 struct dev_list_node, list,
1231 device = find_device(uc_mgr, verb, name, 0);
1233 if (device->dev_list.type != type) {
1237 return get_list(&device->dev_list.list, list,
1238 struct dev_list_node, list,
1246 * \brief Get list of supported devices
1247 * \param list Returned list
1248 * \param name Name of verb or modifier to query
1249 * \return Number of list entries if success, otherwise a negative error code
1251 static int get_supported_device_list(snd_use_case_mgr_t *uc_mgr,
1252 const char **list[], char *name)
1254 return get_supcon_device_list(uc_mgr, list, name, DEVLIST_SUPPORTED);
1258 * \brief Get list of conflicting devices
1259 * \param list Returned list
1260 * \param name Name of verb or modifier to query
1261 * \return Number of list entries if success, otherwise a negative error code
1263 static int get_conflicting_device_list(snd_use_case_mgr_t *uc_mgr,
1264 const char **list[], char *name)
1266 return get_supcon_device_list(uc_mgr, list, name, DEVLIST_CONFLICTING);
1271 struct list_head list;
1277 * \brief Convert myvalue list string list
1278 * \param list myvalue list
1279 * \param res string list
1280 * \retval Number of list entries if success, otherwise a negativer error code
1282 static int myvalue_to_str_list(struct list_head *list, char ***res)
1284 struct list_head *pos;
1285 struct myvalue *value;
1289 cnt = alloc_str_list(list, 1, res);
1293 list_for_each(pos, list) {
1294 value = list_entry(pos, struct myvalue, list);
1295 *p = strdup(value->text);
1297 snd_use_case_free_list((const char **)p, cnt);
1306 * \brief Free myvalue list
1307 * \param list myvalue list
1309 static void myvalue_list_free(struct list_head *list)
1311 struct list_head *pos, *npos;
1312 struct myvalue *value;
1314 list_for_each_safe(pos, npos, list) {
1315 value = list_entry(pos, struct myvalue, list);
1316 list_del(&value->list);
1322 * \brief Merge one value to the myvalue list
1323 * \param list The list with values
1324 * \param value The value to be merged (without duplicates)
1325 * \return 1 if dup, 0 if success, otherwise a negative error code
1327 static int merge_value(struct list_head *list, const char *text)
1329 struct list_head *pos;
1330 struct myvalue *value;
1332 list_for_each(pos, list) {
1333 value = list_entry(pos, struct myvalue, list);
1334 if (strcmp(value->text, text) == 0)
1337 value = malloc(sizeof(*value));
1341 list_add_tail(&value->list, list);
1346 * \brief Find all values for given identifier
1347 * \param list Returned list
1348 * \param source Source list with ucm_value structures
1349 * \return Zero if success, otherwise a negative error code
1351 static int add_identifiers(struct list_head *list,
1352 struct list_head *source)
1354 struct ucm_value *v;
1355 struct list_head *pos;
1358 list_for_each(pos, source) {
1359 v = list_entry(pos, struct ucm_value, list);
1360 err = merge_value(list, v->name);
1368 * \brief Find all values for given identifier
1369 * \param list Returned list
1370 * \param identifier Identifier
1371 * \param source Source list with ucm_value structures
1373 static int add_values(struct list_head *list,
1374 const char *identifier,
1375 struct list_head *source)
1377 struct ucm_value *v;
1378 struct list_head *pos;
1381 list_for_each(pos, source) {
1382 v = list_entry(pos, struct ucm_value, list);
1383 if (check_identifier(identifier, v->name)) {
1384 err = merge_value(list, v->data);
1393 * \brief compare two identifiers
1395 static int identifier_cmp(const void *_a, const void *_b)
1397 const char * const *a = _a;
1398 const char * const *b = _b;
1399 return strcmp(*a, *b);
1403 * \brief Get list of available identifiers
1404 * \param list Returned list
1405 * \param name Name of verb or modifier to query
1406 * \return Number of list entries if success, otherwise a negative error code
1408 static int get_identifiers_list(snd_use_case_mgr_t *uc_mgr,
1409 const char **list[], char *name)
1411 struct use_case_verb *verb;
1412 struct use_case_modifier *modifier;
1413 struct use_case_device *device;
1414 struct list_head mylist;
1415 struct list_head *value_list;
1422 str = strchr(name, '/');
1425 verb = find_verb(uc_mgr, str + 1);
1428 verb = uc_mgr->active_verb;
1434 modifier = find_modifier(uc_mgr, verb, name, 0);
1436 value_list = &modifier->value_list;
1438 device = find_device(uc_mgr, verb, name, 0);
1440 value_list = &device->value_list;
1442 if (value_list == NULL)
1445 INIT_LIST_HEAD(&mylist);
1446 err = add_identifiers(&mylist, &uc_mgr->value_list);
1449 err = add_identifiers(&mylist, &verb->value_list);
1452 err = add_identifiers(&mylist, value_list);
1455 err = myvalue_to_str_list(&mylist, &res);
1457 *list = (const char **)res;
1461 myvalue_list_free(&mylist);
1464 qsort(*list, err, sizeof(char *), identifier_cmp);
1469 * \brief Get list of values
1470 * \param list Returned list
1471 * \param verbname For verb (NULL = current)
1472 * \return Number of list entries if success, otherwise a negative error code
1474 static int get_value_list(snd_use_case_mgr_t *uc_mgr,
1475 const char *identifier,
1476 const char **list[],
1479 struct list_head mylist, *pos;
1480 struct use_case_verb *verb;
1481 struct use_case_device *dev;
1482 struct use_case_modifier *mod;
1487 verb = find_verb(uc_mgr, verbname);
1489 verb = uc_mgr->active_verb;
1493 INIT_LIST_HEAD(&mylist);
1494 err = add_values(&mylist, identifier, &uc_mgr->value_list);
1497 err = add_values(&mylist, identifier, &verb->value_list);
1500 list_for_each(pos, &verb->device_list) {
1501 dev = list_entry(pos, struct use_case_device, list);
1502 err = add_values(&mylist, identifier, &dev->value_list);
1506 list_for_each(pos, &verb->modifier_list) {
1507 mod = list_entry(pos, struct use_case_modifier, list);
1508 err = add_values(&mylist, identifier, &mod->value_list);
1512 err = myvalue_to_str_list(&mylist, &res);
1514 *list = (const char **)res;
1518 myvalue_list_free(&mylist);
1523 * \brief Get list of enabled devices
1524 * \param list Returned list
1525 * \param verbname For verb (NULL = current)
1526 * \return Number of list entries if success, otherwise a negative error code
1528 static int get_enabled_device_list(snd_use_case_mgr_t *uc_mgr,
1529 const char **list[])
1531 if (uc_mgr->active_verb == NULL)
1533 return get_list(&uc_mgr->active_devices, list,
1534 struct use_case_device, active_list,
1539 * \brief Get list of enabled modifiers
1540 * \param list Returned list
1541 * \param verbname For verb (NULL = current)
1542 * \return Number of list entries if success, otherwise a negative error code
1544 static int get_enabled_modifier_list(snd_use_case_mgr_t *uc_mgr,
1545 const char **list[])
1547 if (uc_mgr->active_verb == NULL)
1549 return get_list(&uc_mgr->active_modifiers, list,
1550 struct use_case_modifier, active_list,
1555 * \brief Obtain a list of entries
1556 * \param uc_mgr Use case manager (may be NULL - card list)
1557 * \param identifier (may be NULL - card list)
1558 * \param list Returned allocated list
1559 * \return Number of list entries if success, otherwise a negative error code
1561 int snd_use_case_get_list(snd_use_case_mgr_t *uc_mgr,
1562 const char *identifier,
1563 const char **list[])
1568 if (uc_mgr == NULL || identifier == NULL)
1569 return uc_mgr_scan_master_configs(list);
1570 pthread_mutex_lock(&uc_mgr->mutex);
1571 if (strcmp(identifier, "_verbs") == 0)
1572 err = get_verb_list(uc_mgr, list);
1573 else if (strcmp(identifier, "_enadevs") == 0)
1574 err = get_enabled_device_list(uc_mgr, list);
1575 else if (strcmp(identifier, "_enamods") == 0)
1576 err = get_enabled_modifier_list(uc_mgr, list);
1578 str1 = strchr(identifier, '/');
1580 str = strdup(str1 + 1);
1588 if (check_identifier(identifier, "_devices"))
1589 err = get_device_list(uc_mgr, list, str);
1590 else if (check_identifier(identifier, "_modifiers"))
1591 err = get_modifier_list(uc_mgr, list, str);
1592 else if (check_identifier(identifier, "_identifiers"))
1593 err = get_identifiers_list(uc_mgr, list, str);
1594 else if (check_identifier(identifier, "_supporteddevs"))
1595 err = get_supported_device_list(uc_mgr, list, str);
1596 else if (check_identifier(identifier, "_conflictingdevs"))
1597 err = get_conflicting_device_list(uc_mgr, list, str);
1598 else if (identifier[0] == '_')
1601 err = get_value_list(uc_mgr, identifier, list, str);
1606 pthread_mutex_unlock(&uc_mgr->mutex);
1610 static int get_value1(snd_use_case_mgr_t *uc_mgr, char **value,
1611 struct list_head *value_list, const char *identifier)
1613 struct ucm_value *val;
1614 struct list_head *pos;
1619 list_for_each(pos, value_list) {
1620 val = list_entry(pos, struct ucm_value, list);
1621 if (check_identifier(identifier, val->name)) {
1622 if (uc_mgr->conf_format < 2) {
1623 *value = strdup(val->data);
1628 return uc_mgr_get_substituted_value(uc_mgr, value, val->data);
1634 static int get_value3(snd_use_case_mgr_t *uc_mgr,
1636 const char *identifier,
1637 struct list_head *value_list1,
1638 struct list_head *value_list2,
1639 struct list_head *value_list3)
1643 err = get_value1(uc_mgr, value, value_list1, identifier);
1644 if (err >= 0 || err != -ENOENT)
1646 err = get_value1(uc_mgr, value, value_list2, identifier);
1647 if (err >= 0 || err != -ENOENT)
1649 err = get_value1(uc_mgr, value, value_list3, identifier);
1650 if (err >= 0 || err != -ENOENT)
1657 * \param uc_mgr Use case manager
1658 * \param identifier Value identifier (string)
1659 * \param value Returned value string
1660 * \param item Modifier or Device name (string)
1661 * \return Zero on success (value is filled), otherwise a negative error code
1663 static int get_value(snd_use_case_mgr_t *uc_mgr,
1664 const char *identifier,
1666 const char *mod_dev_name,
1667 const char *verb_name,
1670 struct use_case_verb *verb;
1671 struct use_case_modifier *mod;
1672 struct use_case_device *dev;
1675 if (mod_dev_name || verb_name || !exact) {
1676 if (verb_name && strlen(verb_name)) {
1677 verb = find_verb(uc_mgr, verb_name);
1679 verb = uc_mgr->active_verb;
1683 mod = find_modifier(uc_mgr, verb,
1686 err = get_value1(uc_mgr, value,
1689 if (err >= 0 || err != -ENOENT)
1693 dev = find_device(uc_mgr, verb,
1696 err = get_value1(uc_mgr, value,
1699 if (err >= 0 || err != -ENOENT)
1707 err = get_value1(uc_mgr, value, &verb->value_list, identifier);
1708 if (err >= 0 || err != -ENOENT)
1716 err = get_value1(uc_mgr, value, &uc_mgr->value_list, identifier);
1717 if (err >= 0 || err != -ENOENT)
1724 * \brief Get current - string
1725 * \param uc_mgr Use case manager
1727 * \param value Value pointer
1728 * \return Zero if success, otherwise a negative error code
1730 * Note: String is dynamically allocated, use free() to
1731 * deallocate this string.
1733 int snd_use_case_get(snd_use_case_mgr_t *uc_mgr,
1734 const char *identifier,
1737 const char *slash1, *slash2, *mod_dev_after;
1738 const char *ident, *mod_dev, *verb;
1742 pthread_mutex_lock(&uc_mgr->mutex);
1743 if (identifier == NULL) {
1744 *value = strdup(uc_mgr->card_name);
1745 if (*value == NULL) {
1750 } else if (strcmp(identifier, "_verb") == 0) {
1751 if (uc_mgr->active_verb == NULL) {
1755 *value = strdup(uc_mgr->active_verb->name);
1756 if (*value == NULL) {
1761 } else if (strcmp(identifier, "_file") == 0) {
1762 /* get the conf file name of the opened card */
1763 if ((uc_mgr->card_name == NULL) ||
1764 (uc_mgr->conf_file_name == NULL) ||
1765 (uc_mgr->conf_file_name[0] == '\0')) {
1769 *value = strdup(uc_mgr->conf_file_name);
1770 if (*value == NULL) {
1776 } else if (identifier[0] == '_') {
1780 if (identifier[0] == '=') {
1785 slash1 = strchr(identifier, '/');
1787 ident = strndup(identifier, slash1 - identifier);
1789 slash2 = strchr(slash1 + 1, '/');
1791 mod_dev_after = slash2;
1795 mod_dev_after = slash1 + strlen(slash1);
1799 if (mod_dev_after == slash1 + 1)
1802 mod_dev = strndup(slash1 + 1,
1803 mod_dev_after - (slash1 + 1));
1811 err = get_value(uc_mgr, ident, (char **)value, mod_dev, verb,
1813 if (ident != identifier)
1814 free((void *)ident);
1816 free((void *)mod_dev);
1819 pthread_mutex_unlock(&uc_mgr->mutex);
1825 * \brief Get current - integer
1826 * \param uc_mgr Use case manager
1828 * \return Value if success, otherwise a negative error code
1830 int snd_use_case_geti(snd_use_case_mgr_t *uc_mgr,
1831 const char *identifier,
1837 pthread_mutex_lock(&uc_mgr->mutex);
1839 /* nothing here - prepared for fixed identifiers */
1841 str1 = strchr(identifier, '/');
1843 str = strdup(str1 + 1);
1851 if (check_identifier(identifier, "_devstatus")) {
1856 err = device_status(uc_mgr, str);
1861 } else if (check_identifier(identifier, "_modstatus")) {
1866 err = modifier_status(uc_mgr, str);
1873 * enable this block if the else clause below is expanded to query
1874 * user-supplied values
1876 } else if (identifier[0] == '_')
1885 pthread_mutex_unlock(&uc_mgr->mutex);
1889 static int set_boot_user(snd_use_case_mgr_t *uc_mgr,
1894 if (value != NULL && *value) {
1895 uc_error("error: wrong value for _boot (%s)", value);
1898 err = execute_sequence(uc_mgr, &uc_mgr->boot_list,
1899 &uc_mgr->value_list, NULL, NULL);
1901 uc_error("Unable to execute boot sequence");
1907 static int set_defaults_user(snd_use_case_mgr_t *uc_mgr,
1910 if (value != NULL && *value) {
1911 uc_error("error: wrong value for _defaults (%s)", value);
1914 return set_defaults(uc_mgr);
1917 static int handle_transition_verb(snd_use_case_mgr_t *uc_mgr,
1918 struct use_case_verb *new_verb)
1920 struct list_head *pos;
1921 struct transition_sequence *trans;
1924 list_for_each(pos, &uc_mgr->active_verb->transition_list) {
1925 trans = list_entry(pos, struct transition_sequence, list);
1926 if (strcmp(trans->name, new_verb->name) == 0) {
1927 err = execute_sequence(uc_mgr, &trans->transition_list,
1928 &uc_mgr->active_verb->value_list,
1929 &uc_mgr->value_list,
1939 static int set_verb_user(snd_use_case_mgr_t *uc_mgr,
1940 const char *verb_name)
1942 struct use_case_verb *verb;
1945 if (uc_mgr->active_verb &&
1946 strcmp(uc_mgr->active_verb->name, verb_name) == 0)
1948 if (strcmp(verb_name, SND_USE_CASE_VERB_INACTIVE) != 0) {
1949 verb = find_verb(uc_mgr, verb_name);
1955 if (uc_mgr->active_verb) {
1956 err = handle_transition_verb(uc_mgr, verb);
1958 err = dismantle_use_case(uc_mgr);
1961 } else if (err == 1) {
1962 uc_mgr->active_verb = verb;
1965 verb = NULL; /* show error */
1969 err = set_verb(uc_mgr, verb, 1);
1971 uc_error("error: failed to initialize new use case: %s",
1978 static int set_device_user(snd_use_case_mgr_t *uc_mgr,
1979 const char *device_name,
1982 struct use_case_device *device;
1984 if (uc_mgr->active_verb == NULL)
1986 device = find_device(uc_mgr, uc_mgr->active_verb, device_name, 1);
1989 return set_device(uc_mgr, device, enable);
1992 static int set_modifier_user(snd_use_case_mgr_t *uc_mgr,
1993 const char *modifier_name,
1996 struct use_case_modifier *modifier;
1998 if (uc_mgr->active_verb == NULL)
2001 modifier = find_modifier(uc_mgr, uc_mgr->active_verb, modifier_name, 1);
2002 if (modifier == NULL)
2004 return set_modifier(uc_mgr, modifier, enable);
2007 static int switch_device(snd_use_case_mgr_t *uc_mgr,
2008 const char *old_device,
2009 const char *new_device)
2011 struct use_case_device *xold, *xnew;
2012 struct transition_sequence *trans;
2013 struct list_head *pos;
2014 int err, seq_found = 0;
2016 if (uc_mgr->active_verb == NULL)
2018 if (device_status(uc_mgr, old_device) == 0) {
2019 uc_error("error: device %s not enabled", old_device);
2022 if (device_status(uc_mgr, new_device) != 0) {
2023 uc_error("error: device %s already enabled", new_device);
2026 xold = find_device(uc_mgr, uc_mgr->active_verb, old_device, 1);
2029 list_del(&xold->active_list);
2030 xnew = find_device(uc_mgr, uc_mgr->active_verb, new_device, 1);
2031 list_add_tail(&xold->active_list, &uc_mgr->active_devices);
2035 list_for_each(pos, &xold->transition_list) {
2036 trans = list_entry(pos, struct transition_sequence, list);
2037 if (strcmp(trans->name, new_device) == 0) {
2038 err = execute_sequence(uc_mgr, &trans->transition_list,
2040 &uc_mgr->active_verb->value_list,
2041 &uc_mgr->value_list);
2043 list_del(&xold->active_list);
2044 list_add_tail(&xnew->active_list, &uc_mgr->active_devices);
2051 err = set_device(uc_mgr, xold, 0);
2054 err = set_device(uc_mgr, xnew, 1);
2061 static int switch_modifier(snd_use_case_mgr_t *uc_mgr,
2062 const char *old_modifier,
2063 const char *new_modifier)
2065 struct use_case_modifier *xold, *xnew;
2066 struct transition_sequence *trans;
2067 struct list_head *pos;
2068 int err, seq_found = 0;
2070 if (uc_mgr->active_verb == NULL)
2072 if (modifier_status(uc_mgr, old_modifier) == 0) {
2073 uc_error("error: modifier %s not enabled", old_modifier);
2076 if (modifier_status(uc_mgr, new_modifier) != 0) {
2077 uc_error("error: modifier %s already enabled", new_modifier);
2080 xold = find_modifier(uc_mgr, uc_mgr->active_verb, old_modifier, 1);
2083 xnew = find_modifier(uc_mgr, uc_mgr->active_verb, new_modifier, 1);
2087 list_for_each(pos, &xold->transition_list) {
2088 trans = list_entry(pos, struct transition_sequence, list);
2089 if (strcmp(trans->name, new_modifier) == 0) {
2090 err = execute_sequence(uc_mgr, &trans->transition_list,
2092 &uc_mgr->active_verb->value_list,
2093 &uc_mgr->value_list);
2095 list_del(&xold->active_list);
2096 list_add_tail(&xnew->active_list, &uc_mgr->active_modifiers);
2103 err = set_modifier(uc_mgr, xold, 0);
2106 err = set_modifier(uc_mgr, xnew, 1);
2115 * \param uc_mgr Use case manager
2117 * \param value Value
2118 * \return Zero if success, otherwise a negative error code
2120 int snd_use_case_set(snd_use_case_mgr_t *uc_mgr,
2121 const char *identifier,
2127 pthread_mutex_lock(&uc_mgr->mutex);
2128 if (strcmp(identifier, "_boot") == 0)
2129 err = set_boot_user(uc_mgr, value);
2130 else if (strcmp(identifier, "_defaults") == 0)
2131 err = set_defaults_user(uc_mgr, value);
2132 else if (strcmp(identifier, "_verb") == 0)
2133 err = set_verb_user(uc_mgr, value);
2134 else if (strcmp(identifier, "_enadev") == 0)
2135 err = set_device_user(uc_mgr, value, 1);
2136 else if (strcmp(identifier, "_disdev") == 0)
2137 err = set_device_user(uc_mgr, value, 0);
2138 else if (strcmp(identifier, "_enamod") == 0)
2139 err = set_modifier_user(uc_mgr, value, 1);
2140 else if (strcmp(identifier, "_dismod") == 0)
2141 err = set_modifier_user(uc_mgr, value, 0);
2143 str1 = strchr(identifier, '/');
2145 str = strdup(str1 + 1);
2154 if (check_identifier(identifier, "_swdev"))
2155 err = switch_device(uc_mgr, str, value);
2156 else if (check_identifier(identifier, "_swmod"))
2157 err = switch_modifier(uc_mgr, str, value);
2164 pthread_mutex_unlock(&uc_mgr->mutex);
2169 * \brief Parse control element identifier
2170 * \param elem_id Element identifier
2171 * \param ucm_id Use case identifier
2172 * \param value String value to be parsed
2173 * \return Zero if success, otherwise a negative error code
2175 int snd_use_case_parse_ctl_elem_id(snd_ctl_elem_id_t *dst,
2179 snd_ctl_elem_iface_t iface;
2182 jack_control = strcmp(ucm_id, "JackControl") == 0;
2183 if (!jack_control &&
2184 strcmp(ucm_id, "PlaybackVolume") &&
2185 strcmp(ucm_id, "PlaybackSwitch") &&
2186 strcmp(ucm_id, "CaptureVolume") &&
2187 strcmp(ucm_id, "CaptureSwitch"))
2189 snd_ctl_elem_id_clear(dst);
2190 if (strcasestr(ucm_id, "name="))
2191 return __snd_ctl_ascii_elem_id_parse(dst, value, NULL);
2192 iface = SND_CTL_ELEM_IFACE_MIXER;
2194 iface = SND_CTL_ELEM_IFACE_CARD;
2195 snd_ctl_elem_id_set_interface(dst, iface);
2196 snd_ctl_elem_id_set_name(dst, value);
2201 * \brief Parse mixer element identifier
2202 * \param dst Simple mixer element identifier
2203 * \param ucm_id Use case identifier
2204 * \param value String value to be parsed
2205 * \return Zero if success, otherwise a negative error code
2207 int snd_use_case_parse_selem_id(snd_mixer_selem_id_t *dst,
2212 if (strcmp(ucm_id, "PlaybackMixerId") == 0 ||
2213 strcmp(ucm_id, "CaptureMixerId") == 0)
2214 return snd_mixer_selem_id_parse(dst, value);