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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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"
41 static int get_value1(const char **value, struct list_head *value_list,
42 const char *identifier);
43 static int get_value3(const char **value,
44 const char *identifier,
45 struct list_head *value_list1,
46 struct list_head *value_list2,
47 struct list_head *value_list3);
49 static int check_identifier(const char *identifier, const char *prefix)
53 if (strcmp(identifier, prefix) == 0)
56 if (memcmp(identifier, prefix, len) == 0 && identifier[len] == '/')
61 static int list_count(struct list_head *list)
63 struct list_head *pos;
66 list_for_each(pos, list) {
72 static int alloc_str_list(struct list_head *list, int mult, char **result[])
77 cnt = list_count(list) * mult;
82 res = calloc(mult, cnt * sizeof(char *));
90 * \brief Create an identifier
91 * \param fmt Format (sprintf like)
92 * \param ... Optional arguments for sprintf like format
93 * \return Allocated string identifier or NULL on error
95 char *snd_use_case_identifier(const char *fmt, ...)
98 int size = strlen(fmt) + 512;
105 vsnprintf(str, size, fmt, args);
108 res = realloc(str, strlen(str) + 1);
115 * \brief Free a string list
116 * \param list The string list to free
117 * \param items Count of strings
118 * \return Zero if success, otherwise a negative error code
120 int snd_use_case_free_list(const char *list[], int items)
125 for (i = 0; i < items; i++)
126 free((void *)list[i]);
131 static int open_ctl(snd_use_case_mgr_t *uc_mgr,
137 /* FIXME: add a list of ctl devices to uc_mgr structure and
138 cache accesses for multiple opened ctl devices */
139 if (uc_mgr->ctl_dev != NULL && strcmp(ctl_dev, uc_mgr->ctl_dev) == 0) {
143 if (uc_mgr->ctl_dev) {
144 free(uc_mgr->ctl_dev);
145 uc_mgr->ctl_dev = NULL;
146 snd_ctl_close(uc_mgr->ctl);
149 err = snd_ctl_open(ctl, ctl_dev, 0);
152 uc_mgr->ctl_dev = strdup(ctl_dev);
153 if (uc_mgr->ctl_dev == NULL) {
161 static int execute_cset(snd_ctl_t *ctl, char *cset)
165 snd_ctl_elem_id_t *id;
166 snd_ctl_elem_value_t *value;
167 snd_ctl_elem_info_t *info;
169 snd_ctl_elem_id_malloc(&id);
170 snd_ctl_elem_value_malloc(&value);
171 snd_ctl_elem_info_malloc(&info);
173 pos = strrchr(cset, ' ');
175 uc_error("undefined value for cset >%s<", cset);
180 err = snd_ctl_ascii_elem_id_parse(id, cset);
183 snd_ctl_elem_value_set_id(value, id);
184 snd_ctl_elem_info_set_id(info, id);
185 err = snd_ctl_elem_read(ctl, value);
188 err = snd_ctl_elem_info(ctl, info);
191 err = snd_ctl_ascii_value_parse(ctl, value, info, pos + 1);
194 err = snd_ctl_elem_write(ctl, value);
213 * \brief Execute the sequence
214 * \param uc_mgr Use case manager
215 * \param seq Sequence
216 * \return zero on success, otherwise a negative error code
218 static int execute_sequence(snd_use_case_mgr_t *uc_mgr,
219 struct list_head *seq,
220 struct list_head *value_list1,
221 struct list_head *value_list2,
222 struct list_head *value_list3)
224 struct list_head *pos;
225 struct sequence_element *s;
227 snd_ctl_t *ctl = NULL;
230 list_for_each(pos, seq) {
231 s = list_entry(pos, struct sequence_element, list);
233 case SEQUENCE_ELEMENT_TYPE_CDEV:
234 cdev = strdup(s->data.cdev);
238 case SEQUENCE_ELEMENT_TYPE_CSET:
240 const char *cdev1 = NULL, *cdev2 = NULL;
241 err = get_value3(&cdev1, "PlaybackCTL",
245 if (err < 0 && err != ENOENT) {
246 uc_error("cdev is not defined!");
249 err = get_value3(&cdev1, "CaptureCTL",
253 if (err < 0 && err != ENOENT) {
255 uc_error("cdev is not defined!");
258 if (cdev1 == NULL || cdev2 == NULL ||
259 strcmp(cdev1, cdev2) == 0) {
260 cdev = (char *)cdev1;
268 err = open_ctl(uc_mgr, &ctl, cdev);
270 uc_error("unable to open ctl device '%s'", cdev);
274 err = execute_cset(ctl, s->data.cset);
276 uc_error("unable to execute cset '%s'\n", s->data.cset);
280 case SEQUENCE_ELEMENT_TYPE_SLEEP:
281 usleep(s->data.sleep);
283 case SEQUENCE_ELEMENT_TYPE_EXEC:
284 err = system(s->data.exec);
289 uc_error("unknown sequence command %i", s->type);
304 * \brief Import master config and execute the default sequence
305 * \param uc_mgr Use case manager
306 * \return zero on success, otherwise a negative error code
308 static int import_master_config(snd_use_case_mgr_t *uc_mgr)
312 err = uc_mgr_import_master_config(uc_mgr);
315 err = execute_sequence(uc_mgr, &uc_mgr->default_list,
316 &uc_mgr->value_list, NULL, NULL);
318 uc_error("Unable to execute default sequence");
323 * \brief Universal find - string in a list
324 * \param list List of structures
325 * \param offset Offset of list structure
326 * \param soffset Offset of string structure
327 * \param match String to match
328 * \return structure on success, otherwise a NULL (not found)
330 static void *find0(struct list_head *list,
331 unsigned long offset,
332 unsigned long soffset,
335 struct list_head *pos;
338 list_for_each(pos, list) {
339 ptr = list_entry_offset(pos, char, offset);
340 str = *((char **)(ptr + soffset));
341 if (strcmp(str, match) == 0)
347 #define find(list, type, member, value, match) \
348 find0(list, (unsigned long)(&((type *)0)->member), \
349 (unsigned long)(&((type *)0)->value), match)
352 * \brief Universal string list
353 * \param list List of structures
354 * \param result Result list
355 * \param offset Offset of list structure
356 * \param s1offset Offset of string structure
357 * \return count of items on success, otherwise a negative error code
359 static int get_list0(struct list_head *list,
360 const char **result[],
361 unsigned long offset,
362 unsigned long s1offset)
366 struct list_head *pos;
369 cnt = alloc_str_list(list, 1, &res);
372 *result = (const char **)res;
373 list_for_each(pos, list) {
374 ptr = list_entry_offset(pos, char, offset);
375 str1 = *((char **)(ptr + s1offset));
387 snd_use_case_free_list((const char **)res, cnt);
391 #define get_list(list, result, type, member, s1) \
392 get_list0(list, result, \
393 (unsigned long)(&((type *)0)->member), \
394 (unsigned long)(&((type *)0)->s1))
397 * \brief Universal string list - pair of strings
398 * \param list List of structures
399 * \param result Result list
400 * \param offset Offset of list structure
401 * \param s1offset Offset of string structure
402 * \param s1offset Offset of string structure
403 * \return count of items on success, otherwise a negative error code
405 static int get_list20(struct list_head *list,
406 const char **result[],
407 unsigned long offset,
408 unsigned long s1offset,
409 unsigned long s2offset)
413 struct list_head *pos;
414 char *ptr, *str1, *str2;
416 cnt = alloc_str_list(list, 2, &res);
419 *result = (const char **)res;
420 list_for_each(pos, list) {
421 ptr = list_entry_offset(pos, char, offset);
422 str1 = *((char **)(ptr + s1offset));
431 str2 = *((char **)(ptr + s2offset));
443 snd_use_case_free_list((const char **)res, cnt);
447 #define get_list2(list, result, type, member, s1, s2) \
448 get_list20(list, result, \
449 (unsigned long)(&((type *)0)->member), \
450 (unsigned long)(&((type *)0)->s1), \
451 (unsigned long)(&((type *)0)->s2))
455 * \param uc_mgr Use case manager
456 * \param verb_name verb to find
457 * \return structure on success, otherwise a NULL (not found)
459 static inline struct use_case_verb *find_verb(snd_use_case_mgr_t *uc_mgr,
460 const char *verb_name)
462 return find(&uc_mgr->verb_list,
463 struct use_case_verb, list, name,
467 static int is_devlist_supported(snd_use_case_mgr_t *uc_mgr,
468 struct dev_list *dev_list)
470 struct dev_list_node *device;
471 struct use_case_device *adev;
472 struct list_head *pos, *pos1;
475 switch (dev_list->type) {
479 case DEVLIST_SUPPORTED:
482 case DEVLIST_CONFLICTING:
487 list_for_each(pos, &dev_list->list) {
488 device = list_entry(pos, struct dev_list_node, list);
490 list_for_each(pos1, &uc_mgr->active_devices) {
491 adev = list_entry(pos1, struct use_case_device,
493 if (!strcmp(device->name, adev->name))
497 return 1 - found_ret;
500 static inline int is_modifier_supported(snd_use_case_mgr_t *uc_mgr,
501 struct use_case_modifier *modifier)
503 return is_devlist_supported(uc_mgr, &modifier->dev_list);
506 static inline int is_device_supported(snd_use_case_mgr_t *uc_mgr,
507 struct use_case_device *device)
509 return is_devlist_supported(uc_mgr, &device->dev_list);
514 * \param verb Use case verb
515 * \param device_name device to find
516 * \return structure on success, otherwise a NULL (not found)
518 static inline struct use_case_device *
519 find_device(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb,
520 const char *device_name, int check_supported)
522 struct use_case_device *device;
523 struct list_head *pos;
525 list_for_each(pos, &verb->device_list) {
526 device = list_entry(pos, struct use_case_device, list);
528 if (strcmp(device_name, device->name))
531 if (check_supported &&
532 !is_device_supported(uc_mgr, device))
541 * \brief Find modifier
542 * \param verb Use case verb
543 * \param modifier_name modifier to find
544 * \return structure on success, otherwise a NULL (not found)
546 static struct use_case_modifier *
547 find_modifier(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb,
548 const char *modifier_name, int check_supported)
550 struct use_case_modifier *modifier;
551 struct list_head *pos;
553 list_for_each(pos, &verb->modifier_list) {
554 modifier = list_entry(pos, struct use_case_modifier, list);
556 if (strcmp(modifier->name, modifier_name))
559 if (check_supported &&
560 !is_modifier_supported(uc_mgr, modifier))
570 * \param uc_mgr Use case manager
571 * \param verb verb to set
572 * \param enable nonzero = enable, zero = disable
573 * \return zero on success, otherwise a negative error code
575 static int set_verb(snd_use_case_mgr_t *uc_mgr,
576 struct use_case_verb *verb,
579 struct list_head *seq;
583 seq = &verb->enable_list;
585 seq = &verb->disable_list;
587 err = execute_sequence(uc_mgr, seq,
591 if (enable && err >= 0)
592 uc_mgr->active_verb = verb;
597 * \brief Set modifier
598 * \param uc_mgr Use case manager
599 * \param modifier modifier to set
600 * \param enable nonzero = enable, zero = disable
601 * \return zero on success, otherwise a negative error code
603 static int set_modifier(snd_use_case_mgr_t *uc_mgr,
604 struct use_case_modifier *modifier,
607 struct list_head *seq;
611 seq = &modifier->enable_list;
613 seq = &modifier->disable_list;
615 err = execute_sequence(uc_mgr, seq,
616 &modifier->value_list,
617 &uc_mgr->active_verb->value_list,
618 &uc_mgr->value_list);
619 if (enable && err >= 0) {
620 list_add_tail(&modifier->active_list, &uc_mgr->active_modifiers);
621 } else if (!enable) {
622 list_del(&modifier->active_list);
629 * \param uc_mgr Use case manager
630 * \param device device to set
631 * \param enable nonzero = enable, zero = disable
632 * \return zero on success, otherwise a negative error code
634 static int set_device(snd_use_case_mgr_t *uc_mgr,
635 struct use_case_device *device,
638 struct list_head *seq;
642 seq = &device->enable_list;
644 seq = &device->disable_list;
646 err = execute_sequence(uc_mgr, seq,
648 &uc_mgr->active_verb->value_list,
649 &uc_mgr->value_list);
650 if (enable && err >= 0) {
651 list_add_tail(&device->active_list, &uc_mgr->active_devices);
652 } else if (!enable) {
653 list_del(&device->active_list);
659 * \brief Init sound card use case manager.
660 * \param uc_mgr Returned use case manager pointer
661 * \param card_name name of card to open
662 * \return zero on success, otherwise a negative error code
664 int snd_use_case_mgr_open(snd_use_case_mgr_t **mgr,
665 const char *card_name)
667 snd_use_case_mgr_t *uc_mgr;
670 /* create a new UCM */
671 uc_mgr = calloc(1, sizeof(snd_use_case_mgr_t));
674 INIT_LIST_HEAD(&uc_mgr->verb_list);
675 INIT_LIST_HEAD(&uc_mgr->default_list);
676 INIT_LIST_HEAD(&uc_mgr->value_list);
677 INIT_LIST_HEAD(&uc_mgr->active_modifiers);
678 INIT_LIST_HEAD(&uc_mgr->active_devices);
679 pthread_mutex_init(&uc_mgr->mutex, NULL);
681 uc_mgr->card_name = strdup(card_name);
682 if (uc_mgr->card_name == NULL) {
687 /* get info on use_cases and verify against card */
688 err = import_master_config(uc_mgr);
690 uc_error("error: failed to import %s use case configuration %d",
704 * \brief Reload and reparse all use case files.
705 * \param uc_mgr Use case manager
706 * \return zero on success, otherwise a negative error code
708 int snd_use_case_mgr_reload(snd_use_case_mgr_t *uc_mgr)
712 pthread_mutex_lock(&uc_mgr->mutex);
714 uc_mgr_free_verb(uc_mgr);
716 /* reload all use cases */
717 err = import_master_config(uc_mgr);
719 uc_error("error: failed to reload use cases\n");
720 pthread_mutex_unlock(&uc_mgr->mutex);
724 pthread_mutex_unlock(&uc_mgr->mutex);
729 * \brief Close use case manager.
730 * \param uc_mgr Use case manager
731 * \return zero on success, otherwise a negative error code
733 int snd_use_case_mgr_close(snd_use_case_mgr_t *uc_mgr)
741 * Tear down current use case verb, device and modifier.
743 static int dismantle_use_case(snd_use_case_mgr_t *uc_mgr)
745 struct list_head *pos, *npos;
746 struct use_case_modifier *modifier;
747 struct use_case_device *device;
750 list_for_each_safe(pos, npos, &uc_mgr->active_modifiers) {
751 modifier = list_entry(pos, struct use_case_modifier,
753 err = set_modifier(uc_mgr, modifier, 0);
755 uc_error("Unable to disable modifier %s", modifier->name);
757 INIT_LIST_HEAD(&uc_mgr->active_modifiers);
759 list_for_each_safe(pos, npos, &uc_mgr->active_devices) {
760 device = list_entry(pos, struct use_case_device,
762 err = set_device(uc_mgr, device, 0);
764 uc_error("Unable to disable device %s", device->name);
766 INIT_LIST_HEAD(&uc_mgr->active_devices);
768 err = set_verb(uc_mgr, uc_mgr->active_verb, 0);
770 uc_error("Unable to disable verb %s", uc_mgr->active_verb->name);
773 uc_mgr->active_verb = NULL;
775 err = execute_sequence(uc_mgr, &uc_mgr->default_list,
776 &uc_mgr->value_list, NULL, NULL);
782 * \brief Reset sound card controls to default values.
783 * \param uc_mgr Use case manager
784 * \return zero on success, otherwise a negative error code
786 int snd_use_case_mgr_reset(snd_use_case_mgr_t *uc_mgr)
790 pthread_mutex_lock(&uc_mgr->mutex);
791 err = execute_sequence(uc_mgr, &uc_mgr->default_list,
792 &uc_mgr->value_list, NULL, NULL);
793 INIT_LIST_HEAD(&uc_mgr->active_modifiers);
794 INIT_LIST_HEAD(&uc_mgr->active_devices);
795 uc_mgr->active_verb = NULL;
796 pthread_mutex_unlock(&uc_mgr->mutex);
801 * \brief Get list of verbs in pair verbname+comment
802 * \param list Returned list
803 * \param verbname For verb (NULL = current)
804 * \return Number of list entries if success, otherwise a negative error code
806 static int get_verb_list(snd_use_case_mgr_t *uc_mgr, const char **list[])
808 return get_list2(&uc_mgr->verb_list, list,
809 struct use_case_verb, list,
814 * \brief Get list of devices in pair devicename+comment
815 * \param list Returned list
816 * \param verbname For verb (NULL = current)
817 * \return Number of list entries if success, otherwise a negative error code
819 static int get_device_list(snd_use_case_mgr_t *uc_mgr, const char **list[],
822 struct use_case_verb *verb;
825 verb = find_verb(uc_mgr, verbname);
827 verb = uc_mgr->active_verb;
831 return get_list2(&verb->device_list, list,
832 struct use_case_device, list,
837 * \brief Get list of modifiers in pair devicename+comment
838 * \param list Returned list
839 * \param verbname For verb (NULL = current)
840 * \return Number of list entries if success, otherwise a negative error code
842 static int get_modifier_list(snd_use_case_mgr_t *uc_mgr, const char **list[],
845 struct use_case_verb *verb;
848 verb = find_verb(uc_mgr, verbname);
850 verb = uc_mgr->active_verb;
854 return get_list2(&verb->modifier_list, list,
855 struct use_case_modifier, list,
860 * \brief Get list of supported/conflicting devices
861 * \param list Returned list
862 * \param name Name of modifier or verb to query
863 * \param type Type of device list entries to return
864 * \return Number of list entries if success, otherwise a negative error code
866 static int get_supcon_device_list(snd_use_case_mgr_t *uc_mgr,
867 const char **list[], char *name,
868 enum dev_list_type type)
871 struct use_case_verb *verb;
872 struct use_case_modifier *modifier;
873 struct use_case_device *device;
878 str = strchr(name, '/');
881 verb = find_verb(uc_mgr, str + 1);
884 verb = uc_mgr->active_verb;
889 modifier = find_modifier(uc_mgr, verb, name, 0);
891 if (modifier->dev_list.type != type)
893 return get_list(&modifier->dev_list.list, list,
894 struct dev_list_node, list,
898 device = find_device(uc_mgr, verb, name, 0);
900 if (device->dev_list.type != type)
902 return get_list(&device->dev_list.list, list,
903 struct dev_list_node, list,
912 * \brief Get list of supported devices
913 * \param list Returned list
914 * \param name Name of verb or modifier to query
915 * \return Number of list entries if success, otherwise a negative error code
917 static int get_supported_device_list(snd_use_case_mgr_t *uc_mgr,
918 const char **list[], char *name)
920 return get_supcon_device_list(uc_mgr, list, name, DEVLIST_SUPPORTED);
924 * \brief Get list of conflicting devices
925 * \param list Returned list
926 * \param name Name of verb or modifier to query
927 * \return Number of list entries if success, otherwise a negative error code
929 static int get_conflicting_device_list(snd_use_case_mgr_t *uc_mgr,
930 const char **list[], char *name)
932 return get_supcon_device_list(uc_mgr, list, name, DEVLIST_CONFLICTING);
936 struct list_head list;
940 static int add_values(struct list_head *list,
941 const char *identifier,
942 struct list_head *source)
946 struct list_head *pos, *pos1;
949 list_for_each(pos, source) {
950 v = list_entry(pos, struct ucm_value, list);
951 if (check_identifier(identifier, v->name)) {
953 list_for_each(pos1, list) {
954 val = list_entry(pos1, struct myvalue, list);
955 if (strcmp(val->value, v->data) == 0) {
961 val = malloc(sizeof(struct myvalue));
964 val->value = v->data;
965 list_add_tail(&val->list, list);
973 * \brief Get list of values
974 * \param list Returned list
975 * \param verbname For verb (NULL = current)
976 * \return Number of list entries if success, otherwise a negative error code
978 static int get_value_list(snd_use_case_mgr_t *uc_mgr,
979 const char *identifier,
983 struct list_head mylist, *pos, *npos;
985 struct use_case_verb *verb;
986 struct use_case_device *dev;
987 struct use_case_modifier *mod;
992 verb = find_verb(uc_mgr, verbname);
994 verb = uc_mgr->active_verb;
998 INIT_LIST_HEAD(&mylist);
999 err = add_values(&mylist, identifier, &uc_mgr->value_list);
1002 err = add_values(&mylist, identifier, &verb->value_list);
1005 list_for_each(pos, &verb->device_list) {
1006 dev = list_entry(pos, struct use_case_device, list);
1007 err = add_values(&mylist, identifier, &dev->value_list);
1011 list_for_each(pos, &verb->modifier_list) {
1012 mod = list_entry(pos, struct use_case_modifier, list);
1013 err = add_values(&mylist, identifier, &mod->value_list);
1017 err = alloc_str_list(&mylist, 1, &res);
1019 *list = (const char **)res;
1020 list_for_each(pos, &mylist) {
1021 val = list_entry(pos, struct myvalue, list);
1022 *res = strdup(val->value);
1024 snd_use_case_free_list((const char **)res, err);
1032 list_for_each_safe(pos, npos, &mylist) {
1033 val = list_entry(pos, struct myvalue, list);
1034 list_del(&val->list);
1041 * \brief Get list of enabled devices
1042 * \param list Returned list
1043 * \param verbname For verb (NULL = current)
1044 * \return Number of list entries if success, otherwise a negative error code
1046 static int get_enabled_device_list(snd_use_case_mgr_t *uc_mgr,
1047 const char **list[])
1049 if (uc_mgr->active_verb == NULL)
1051 return get_list(&uc_mgr->active_devices, list,
1052 struct use_case_device, active_list,
1057 * \brief Get list of enabled modifiers
1058 * \param list Returned list
1059 * \param verbname For verb (NULL = current)
1060 * \return Number of list entries if success, otherwise a negative error code
1062 static int get_enabled_modifier_list(snd_use_case_mgr_t *uc_mgr,
1063 const char **list[])
1065 if (uc_mgr->active_verb == NULL)
1067 return get_list(&uc_mgr->active_modifiers, list,
1068 struct use_case_modifier, active_list,
1073 * \brief Obtain a list of entries
1074 * \param uc_mgr Use case manager (may be NULL - card list)
1075 * \param identifier (may be NULL - card list)
1076 * \param list Returned allocated list
1077 * \return Number of list entries if success, otherwise a negative error code
1079 int snd_use_case_get_list(snd_use_case_mgr_t *uc_mgr,
1080 const char *identifier,
1081 const char **list[])
1086 if (uc_mgr == NULL || identifier == NULL)
1087 return uc_mgr_scan_master_configs(list);
1088 pthread_mutex_lock(&uc_mgr->mutex);
1089 if (strcmp(identifier, "_verbs") == 0)
1090 err = get_verb_list(uc_mgr, list);
1091 else if (strcmp(identifier, "_enadevs") == 0)
1092 err = get_enabled_device_list(uc_mgr, list);
1093 else if (strcmp(identifier, "_enamods") == 0)
1094 err = get_enabled_modifier_list(uc_mgr, list);
1096 str1 = strchr(identifier, '/');
1098 str = strdup(str1 + 1);
1106 if (check_identifier(identifier, "_devices"))
1107 err = get_device_list(uc_mgr, list, str);
1108 else if (check_identifier(identifier, "_modifiers"))
1109 err = get_modifier_list(uc_mgr, list, str);
1110 else if (check_identifier(identifier, "_supporteddevs"))
1111 err = get_supported_device_list(uc_mgr, list, str);
1112 else if (check_identifier(identifier, "_conflictingdevs"))
1113 err = get_conflicting_device_list(uc_mgr, list, str);
1114 else if (identifier[0] == '_')
1117 err = get_value_list(uc_mgr, identifier, list, str);
1122 pthread_mutex_unlock(&uc_mgr->mutex);
1126 static int get_value1(const char **value, struct list_head *value_list,
1127 const char *identifier)
1129 struct ucm_value *val;
1130 struct list_head *pos;
1135 list_for_each(pos, value_list) {
1136 val = list_entry(pos, struct ucm_value, list);
1137 if (check_identifier(identifier, val->name)) {
1138 *value = strdup(val->data);
1147 static int get_value3(const char **value,
1148 const char *identifier,
1149 struct list_head *value_list1,
1150 struct list_head *value_list2,
1151 struct list_head *value_list3)
1155 err = get_value1(value, value_list1, identifier);
1156 if (err >= 0 || err != -ENOENT)
1158 err = get_value1(value, value_list2, identifier);
1159 if (err >= 0 || err != -ENOENT)
1161 err = get_value1(value, value_list3, identifier);
1162 if (err >= 0 || err != -ENOENT)
1169 * \param uc_mgr Use case manager
1170 * \param identifier Value identifier (string)
1171 * \param value Returned value string
1172 * \param item Modifier or Device name (string)
1173 * \return Zero on success (value is filled), otherwise a negative error code
1175 static int get_value(snd_use_case_mgr_t *uc_mgr,
1176 const char *identifier,
1178 const char *mod_dev_name,
1179 const char *verb_name,
1182 struct use_case_verb *verb;
1183 struct use_case_modifier *mod;
1184 struct use_case_device *dev;
1187 if (mod_dev_name || verb_name || !exact) {
1188 if (verb_name && strlen(verb_name)) {
1189 verb = find_verb(uc_mgr, verb_name);
1191 verb = uc_mgr->active_verb;
1195 mod = find_modifier(uc_mgr, verb,
1198 err = get_value1(value,
1201 if (err >= 0 || err != -ENOENT)
1205 dev = find_device(uc_mgr, verb,
1208 err = get_value1(value,
1211 if (err >= 0 || err != -ENOENT)
1219 err = get_value1(value, &verb->value_list, identifier);
1220 if (err >= 0 || err != -ENOENT)
1228 err = get_value1(value, &uc_mgr->value_list, identifier);
1229 if (err >= 0 || err != -ENOENT)
1236 * \brief Get current - string
1237 * \param uc_mgr Use case manager
1239 * \param value Value pointer
1240 * \return Zero if success, otherwise a negative error code
1242 * Note: String is dynamically allocated, use free() to
1243 * deallocate this string.
1245 int snd_use_case_get(snd_use_case_mgr_t *uc_mgr,
1246 const char *identifier,
1249 const char *slash1, *slash2, *mod_dev_after;
1250 const char *ident, *mod_dev, *verb;
1254 pthread_mutex_lock(&uc_mgr->mutex);
1255 if (identifier == NULL) {
1256 *value = strdup(uc_mgr->card_name);
1257 if (*value == NULL) {
1262 } else if (strcmp(identifier, "_verb") == 0) {
1263 if (uc_mgr->active_verb == NULL) {
1267 *value = strdup(uc_mgr->active_verb->name);
1268 if (*value == NULL) {
1273 } else if (identifier[0] == '_') {
1277 if (identifier[0] == '=') {
1282 slash1 = strchr(identifier, '/');
1284 ident = strndup(identifier, slash1 - identifier);
1286 slash2 = strchr(slash1 + 1, '/');
1288 mod_dev_after = slash2;
1292 mod_dev_after = slash1 + strlen(slash1);
1296 if (mod_dev_after == slash1 + 1)
1299 mod_dev = strndup(slash1 + 1,
1300 mod_dev_after - (slash1 + 1));
1308 err = get_value(uc_mgr, ident, value, mod_dev, verb, exact);
1309 if (ident != identifier)
1310 free((void *)ident);
1312 free((void *)mod_dev);
1315 pthread_mutex_unlock(&uc_mgr->mutex);
1319 long device_status(snd_use_case_mgr_t *uc_mgr,
1320 const char *device_name)
1322 struct use_case_device *dev;
1323 struct list_head *pos;
1325 list_for_each(pos, &uc_mgr->active_devices) {
1326 dev = list_entry(pos, struct use_case_device, active_list);
1327 if (strcmp(dev->name, device_name) == 0)
1333 long modifier_status(snd_use_case_mgr_t *uc_mgr,
1334 const char *modifier_name)
1336 struct use_case_modifier *mod;
1337 struct list_head *pos;
1339 list_for_each(pos, &uc_mgr->active_modifiers) {
1340 mod = list_entry(pos, struct use_case_modifier, active_list);
1341 if (strcmp(mod->name, modifier_name) == 0)
1349 * \brief Get current - integer
1350 * \param uc_mgr Use case manager
1352 * \return Value if success, otherwise a negative error code
1354 int snd_use_case_geti(snd_use_case_mgr_t *uc_mgr,
1355 const char *identifier,
1361 pthread_mutex_lock(&uc_mgr->mutex);
1363 /* nothing here - prepared for fixed identifiers */
1365 str1 = strchr(identifier, '/');
1367 str = strdup(str1 + 1);
1375 if (check_identifier(identifier, "_devstatus")) {
1376 err = device_status(uc_mgr, str);
1381 } else if (check_identifier(identifier, "_modstatus")) {
1382 err = modifier_status(uc_mgr, str);
1389 * enable this block if the else clause below is expanded to query
1390 * user-supplied values
1392 } else if (identifier[0] == '_')
1401 pthread_mutex_unlock(&uc_mgr->mutex);
1405 static int handle_transition_verb(snd_use_case_mgr_t *uc_mgr,
1406 struct use_case_verb *new_verb)
1408 struct list_head *pos;
1409 struct transition_sequence *trans;
1412 list_for_each(pos, &uc_mgr->active_verb->transition_list) {
1413 trans = list_entry(pos, struct transition_sequence, list);
1414 if (strcmp(trans->name, new_verb->name) == 0) {
1415 err = execute_sequence(uc_mgr, &trans->transition_list,
1416 &uc_mgr->active_verb->value_list,
1417 &uc_mgr->value_list,
1427 static int set_verb_user(snd_use_case_mgr_t *uc_mgr,
1428 const char *verb_name)
1430 struct use_case_verb *verb;
1433 if (uc_mgr->active_verb &&
1434 strcmp(uc_mgr->active_verb->name, verb_name) == 0)
1436 if (strcmp(verb_name, SND_USE_CASE_VERB_INACTIVE) != 0) {
1437 verb = find_verb(uc_mgr, verb_name);
1443 if (uc_mgr->active_verb) {
1444 err = handle_transition_verb(uc_mgr, verb);
1446 err = dismantle_use_case(uc_mgr);
1449 } else if (err == 1) {
1450 uc_mgr->active_verb = verb;
1453 verb = NULL; /* show error */
1457 err = set_verb(uc_mgr, verb, 1);
1459 uc_error("error: failed to initialize new use case: %s",
1466 static int set_device_user(snd_use_case_mgr_t *uc_mgr,
1467 const char *device_name,
1470 struct use_case_device *device;
1472 if (uc_mgr->active_verb == NULL)
1474 device = find_device(uc_mgr, uc_mgr->active_verb, device_name, 1);
1477 return set_device(uc_mgr, device, enable);
1480 static int set_modifier_user(snd_use_case_mgr_t *uc_mgr,
1481 const char *modifier_name,
1484 struct use_case_modifier *modifier;
1486 if (uc_mgr->active_verb == NULL)
1489 modifier = find_modifier(uc_mgr, uc_mgr->active_verb, modifier_name, 1);
1490 if (modifier == NULL)
1492 return set_modifier(uc_mgr, modifier, enable);
1495 static int switch_device(snd_use_case_mgr_t *uc_mgr,
1496 const char *old_device,
1497 const char *new_device)
1499 struct use_case_device *xold, *xnew;
1500 struct transition_sequence *trans;
1501 struct list_head *pos;
1502 int err, seq_found = 0;
1504 if (uc_mgr->active_verb == NULL)
1506 if (device_status(uc_mgr, old_device) == 0) {
1507 uc_error("error: device %s not enabled", old_device);
1510 if (device_status(uc_mgr, new_device) != 0) {
1511 uc_error("error: device %s already enabled", new_device);
1514 xold = find_device(uc_mgr, uc_mgr->active_verb, old_device, 1);
1517 list_del(&xold->active_list);
1518 xnew = find_device(uc_mgr, uc_mgr->active_verb, new_device, 1);
1519 list_add_tail(&xold->active_list, &uc_mgr->active_devices);
1523 list_for_each(pos, &xold->transition_list) {
1524 trans = list_entry(pos, struct transition_sequence, list);
1525 if (strcmp(trans->name, new_device) == 0) {
1526 err = execute_sequence(uc_mgr, &trans->transition_list,
1528 &uc_mgr->active_verb->value_list,
1529 &uc_mgr->value_list);
1531 list_del(&xold->active_list);
1532 list_add_tail(&xnew->active_list, &uc_mgr->active_devices);
1539 err = set_device(uc_mgr, xold, 0);
1542 err = set_device(uc_mgr, xnew, 1);
1549 static int switch_modifier(snd_use_case_mgr_t *uc_mgr,
1550 const char *old_modifier,
1551 const char *new_modifier)
1553 struct use_case_modifier *xold, *xnew;
1554 struct transition_sequence *trans;
1555 struct list_head *pos;
1556 int err, seq_found = 0;
1558 if (uc_mgr->active_verb == NULL)
1560 if (modifier_status(uc_mgr, old_modifier) == 0) {
1561 uc_error("error: modifier %s not enabled", old_modifier);
1564 if (modifier_status(uc_mgr, new_modifier) != 0) {
1565 uc_error("error: modifier %s already enabled", new_modifier);
1568 xold = find_modifier(uc_mgr, uc_mgr->active_verb, old_modifier, 1);
1571 xnew = find_modifier(uc_mgr, uc_mgr->active_verb, new_modifier, 1);
1575 list_for_each(pos, &xold->transition_list) {
1576 trans = list_entry(pos, struct transition_sequence, list);
1577 if (strcmp(trans->name, new_modifier) == 0) {
1578 err = execute_sequence(uc_mgr, &trans->transition_list,
1580 &uc_mgr->active_verb->value_list,
1581 &uc_mgr->value_list);
1583 list_del(&xold->active_list);
1584 list_add_tail(&xnew->active_list, &uc_mgr->active_modifiers);
1591 err = set_modifier(uc_mgr, xold, 0);
1594 err = set_modifier(uc_mgr, xnew, 1);
1603 * \param uc_mgr Use case manager
1605 * \param value Value
1606 * \return Zero if success, otherwise a negative error code
1608 int snd_use_case_set(snd_use_case_mgr_t *uc_mgr,
1609 const char *identifier,
1615 pthread_mutex_lock(&uc_mgr->mutex);
1616 if (strcmp(identifier, "_verb") == 0)
1617 err = set_verb_user(uc_mgr, value);
1618 else if (strcmp(identifier, "_enadev") == 0)
1619 err = set_device_user(uc_mgr, value, 1);
1620 else if (strcmp(identifier, "_disdev") == 0)
1621 err = set_device_user(uc_mgr, value, 0);
1622 else if (strcmp(identifier, "_enamod") == 0)
1623 err = set_modifier_user(uc_mgr, value, 1);
1624 else if (strcmp(identifier, "_dismod") == 0)
1625 err = set_modifier_user(uc_mgr, value, 0);
1627 str1 = strchr(identifier, '/');
1629 str = strdup(str1 + 1);
1637 if (check_identifier(identifier, "_swdev"))
1638 err = switch_device(uc_mgr, str, value);
1639 else if (check_identifier(identifier, "_swmod"))
1640 err = switch_modifier(uc_mgr, str, value);
1647 pthread_mutex_unlock(&uc_mgr->mutex);