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"
42 static int get_value1(const char **value, struct list_head *value_list,
43 const char *identifier);
44 static int get_value3(const char **value,
45 const char *identifier,
46 struct list_head *value_list1,
47 struct list_head *value_list2,
48 struct list_head *value_list3);
50 static int check_identifier(const char *identifier, const char *prefix)
54 if (strcmp(identifier, prefix) == 0)
57 if (memcmp(identifier, prefix, len) == 0 && identifier[len] == '/')
62 static int list_count(struct list_head *list)
64 struct list_head *pos;
67 list_for_each(pos, list) {
73 static int alloc_str_list(struct list_head *list, int mult, char **result[])
78 cnt = list_count(list) * mult;
83 res = calloc(mult, cnt * sizeof(char *));
91 * \brief Create an identifier
92 * \param fmt Format (sprintf like)
93 * \param ... Optional arguments for sprintf like format
94 * \return Allocated string identifier or NULL on error
96 char *snd_use_case_identifier(const char *fmt, ...)
99 int size = strlen(fmt) + 512;
106 vsnprintf(str, size, fmt, args);
109 res = realloc(str, strlen(str) + 1);
116 * \brief Free a string list
117 * \param list The string list to free
118 * \param items Count of strings
119 * \return Zero if success, otherwise a negative error code
121 int snd_use_case_free_list(const char *list[], int items)
126 for (i = 0; i < items; i++)
127 free((void *)list[i]);
132 static int open_ctl(snd_use_case_mgr_t *uc_mgr,
138 /* FIXME: add a list of ctl devices to uc_mgr structure and
139 cache accesses for multiple opened ctl devices */
140 if (uc_mgr->ctl_dev != NULL && strcmp(ctl_dev, uc_mgr->ctl_dev) == 0) {
144 if (uc_mgr->ctl_dev) {
145 free(uc_mgr->ctl_dev);
146 uc_mgr->ctl_dev = NULL;
147 snd_ctl_close(uc_mgr->ctl);
151 err = snd_ctl_open(ctl, ctl_dev, 0);
154 uc_mgr->ctl_dev = strdup(ctl_dev);
155 if (uc_mgr->ctl_dev == NULL) {
163 extern int __snd_ctl_ascii_elem_id_parse(snd_ctl_elem_id_t *dst,
165 const char **ret_ptr);
167 static int execute_cset(snd_ctl_t *ctl, const char *cset)
171 snd_ctl_elem_id_t *id;
172 snd_ctl_elem_value_t *value;
173 snd_ctl_elem_info_t *info;
175 snd_ctl_elem_id_malloc(&id);
176 snd_ctl_elem_value_malloc(&value);
177 snd_ctl_elem_info_malloc(&info);
179 err = __snd_ctl_ascii_elem_id_parse(id, cset, &pos);
182 while (*pos && isspace(*pos))
185 uc_error("undefined value for cset >%s<", cset);
189 snd_ctl_elem_value_set_id(value, id);
190 snd_ctl_elem_info_set_id(info, id);
191 err = snd_ctl_elem_read(ctl, value);
194 err = snd_ctl_elem_info(ctl, info);
197 err = snd_ctl_ascii_value_parse(ctl, value, info, pos);
200 err = snd_ctl_elem_write(ctl, value);
216 * \brief Execute the sequence
217 * \param uc_mgr Use case manager
218 * \param seq Sequence
219 * \return zero on success, otherwise a negative error code
221 static int execute_sequence(snd_use_case_mgr_t *uc_mgr,
222 struct list_head *seq,
223 struct list_head *value_list1,
224 struct list_head *value_list2,
225 struct list_head *value_list3)
227 struct list_head *pos;
228 struct sequence_element *s;
230 snd_ctl_t *ctl = NULL;
233 list_for_each(pos, seq) {
234 s = list_entry(pos, struct sequence_element, list);
236 case SEQUENCE_ELEMENT_TYPE_CDEV:
237 cdev = strdup(s->data.cdev);
241 case SEQUENCE_ELEMENT_TYPE_CSET:
243 const char *cdev1 = NULL, *cdev2 = NULL;
244 err = get_value3(&cdev1, "PlaybackCTL",
248 if (err < 0 && err != ENOENT) {
249 uc_error("cdev is not defined!");
252 err = get_value3(&cdev1, "CaptureCTL",
256 if (err < 0 && err != ENOENT) {
258 uc_error("cdev is not defined!");
261 if (cdev1 == NULL || cdev2 == NULL ||
262 strcmp(cdev1, cdev2) == 0) {
263 cdev = (char *)cdev1;
271 err = open_ctl(uc_mgr, &ctl, cdev);
273 uc_error("unable to open ctl device '%s'", cdev);
277 err = execute_cset(ctl, s->data.cset);
279 uc_error("unable to execute cset '%s'\n", s->data.cset);
283 case SEQUENCE_ELEMENT_TYPE_SLEEP:
284 usleep(s->data.sleep);
286 case SEQUENCE_ELEMENT_TYPE_EXEC:
287 err = system(s->data.exec);
292 uc_error("unknown sequence command %i", s->type);
307 * \brief Import master config and execute the default sequence
308 * \param uc_mgr Use case manager
309 * \return zero on success, otherwise a negative error code
311 static int import_master_config(snd_use_case_mgr_t *uc_mgr)
315 err = uc_mgr_import_master_config(uc_mgr);
318 err = execute_sequence(uc_mgr, &uc_mgr->default_list,
319 &uc_mgr->value_list, NULL, NULL);
321 uc_error("Unable to execute default sequence");
326 * \brief Universal find - string in a list
327 * \param list List of structures
328 * \param offset Offset of list structure
329 * \param soffset Offset of string structure
330 * \param match String to match
331 * \return structure on success, otherwise a NULL (not found)
333 static void *find0(struct list_head *list,
334 unsigned long offset,
335 unsigned long soffset,
338 struct list_head *pos;
341 list_for_each(pos, list) {
342 ptr = list_entry_offset(pos, char, offset);
343 str = *((char **)(ptr + soffset));
344 if (strcmp(str, match) == 0)
350 #define find(list, type, member, value, match) \
351 find0(list, (unsigned long)(&((type *)0)->member), \
352 (unsigned long)(&((type *)0)->value), match)
355 * \brief Universal string list
356 * \param list List of structures
357 * \param result Result list
358 * \param offset Offset of list structure
359 * \param s1offset Offset of string structure
360 * \return count of items on success, otherwise a negative error code
362 static int get_list0(struct list_head *list,
363 const char **result[],
364 unsigned long offset,
365 unsigned long s1offset)
369 struct list_head *pos;
372 cnt = alloc_str_list(list, 1, &res);
377 *result = (const char **)res;
378 list_for_each(pos, list) {
379 ptr = list_entry_offset(pos, char, offset);
380 str1 = *((char **)(ptr + s1offset));
392 snd_use_case_free_list((const char **)res, cnt);
396 #define get_list(list, result, type, member, s1) \
397 get_list0(list, result, \
398 (unsigned long)(&((type *)0)->member), \
399 (unsigned long)(&((type *)0)->s1))
402 * \brief Universal string list - pair of strings
403 * \param list List of structures
404 * \param result Result list
405 * \param offset Offset of list structure
406 * \param s1offset Offset of string structure
407 * \param s1offset Offset of string structure
408 * \return count of items on success, otherwise a negative error code
410 static int get_list20(struct list_head *list,
411 const char **result[],
412 unsigned long offset,
413 unsigned long s1offset,
414 unsigned long s2offset)
418 struct list_head *pos;
419 char *ptr, *str1, *str2;
421 cnt = alloc_str_list(list, 2, &res);
426 *result = (const char **)res;
427 list_for_each(pos, list) {
428 ptr = list_entry_offset(pos, char, offset);
429 str1 = *((char **)(ptr + s1offset));
438 str2 = *((char **)(ptr + s2offset));
450 snd_use_case_free_list((const char **)res, cnt);
454 #define get_list2(list, result, type, member, s1, s2) \
455 get_list20(list, result, \
456 (unsigned long)(&((type *)0)->member), \
457 (unsigned long)(&((type *)0)->s1), \
458 (unsigned long)(&((type *)0)->s2))
462 * \param uc_mgr Use case manager
463 * \param verb_name verb to find
464 * \return structure on success, otherwise a NULL (not found)
466 static inline struct use_case_verb *find_verb(snd_use_case_mgr_t *uc_mgr,
467 const char *verb_name)
469 return find(&uc_mgr->verb_list,
470 struct use_case_verb, list, name,
474 static int is_devlist_supported(snd_use_case_mgr_t *uc_mgr,
475 struct dev_list *dev_list)
477 struct dev_list_node *device;
478 struct use_case_device *adev;
479 struct list_head *pos, *pos1;
482 switch (dev_list->type) {
486 case DEVLIST_SUPPORTED:
489 case DEVLIST_CONFLICTING:
494 list_for_each(pos, &dev_list->list) {
495 device = list_entry(pos, struct dev_list_node, list);
497 list_for_each(pos1, &uc_mgr->active_devices) {
498 adev = list_entry(pos1, struct use_case_device,
500 if (!strcmp(device->name, adev->name))
504 return 1 - found_ret;
507 static inline int is_modifier_supported(snd_use_case_mgr_t *uc_mgr,
508 struct use_case_modifier *modifier)
510 return is_devlist_supported(uc_mgr, &modifier->dev_list);
513 static inline int is_device_supported(snd_use_case_mgr_t *uc_mgr,
514 struct use_case_device *device)
516 return is_devlist_supported(uc_mgr, &device->dev_list);
521 * \param verb Use case verb
522 * \param device_name device to find
523 * \return structure on success, otherwise a NULL (not found)
525 static inline struct use_case_device *
526 find_device(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb,
527 const char *device_name, int check_supported)
529 struct use_case_device *device;
530 struct list_head *pos;
532 list_for_each(pos, &verb->device_list) {
533 device = list_entry(pos, struct use_case_device, list);
535 if (strcmp(device_name, device->name))
538 if (check_supported &&
539 !is_device_supported(uc_mgr, device))
548 * \brief Find modifier
549 * \param verb Use case verb
550 * \param modifier_name modifier to find
551 * \return structure on success, otherwise a NULL (not found)
553 static struct use_case_modifier *
554 find_modifier(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb,
555 const char *modifier_name, int check_supported)
557 struct use_case_modifier *modifier;
558 struct list_head *pos;
560 list_for_each(pos, &verb->modifier_list) {
561 modifier = list_entry(pos, struct use_case_modifier, list);
563 if (strcmp(modifier->name, modifier_name))
566 if (check_supported &&
567 !is_modifier_supported(uc_mgr, modifier))
575 long device_status(snd_use_case_mgr_t *uc_mgr,
576 const char *device_name)
578 struct use_case_device *dev;
579 struct list_head *pos;
581 list_for_each(pos, &uc_mgr->active_devices) {
582 dev = list_entry(pos, struct use_case_device, active_list);
583 if (strcmp(dev->name, device_name) == 0)
589 long modifier_status(snd_use_case_mgr_t *uc_mgr,
590 const char *modifier_name)
592 struct use_case_modifier *mod;
593 struct list_head *pos;
595 list_for_each(pos, &uc_mgr->active_modifiers) {
596 mod = list_entry(pos, struct use_case_modifier, active_list);
597 if (strcmp(mod->name, modifier_name) == 0)
605 * \param uc_mgr Use case manager
606 * \param verb verb to set
607 * \param enable nonzero = enable, zero = disable
608 * \return zero on success, otherwise a negative error code
610 static int set_verb(snd_use_case_mgr_t *uc_mgr,
611 struct use_case_verb *verb,
614 struct list_head *seq;
618 seq = &verb->enable_list;
620 seq = &verb->disable_list;
622 err = execute_sequence(uc_mgr, seq,
626 if (enable && err >= 0)
627 uc_mgr->active_verb = verb;
632 * \brief Set modifier
633 * \param uc_mgr Use case manager
634 * \param modifier modifier to set
635 * \param enable nonzero = enable, zero = disable
636 * \return zero on success, otherwise a negative error code
638 static int set_modifier(snd_use_case_mgr_t *uc_mgr,
639 struct use_case_modifier *modifier,
642 struct list_head *seq;
645 if (modifier_status(uc_mgr, modifier->name) == enable)
649 seq = &modifier->enable_list;
651 seq = &modifier->disable_list;
653 err = execute_sequence(uc_mgr, seq,
654 &modifier->value_list,
655 &uc_mgr->active_verb->value_list,
656 &uc_mgr->value_list);
657 if (enable && err >= 0) {
658 list_add_tail(&modifier->active_list, &uc_mgr->active_modifiers);
659 } else if (!enable) {
660 list_del(&modifier->active_list);
667 * \param uc_mgr Use case manager
668 * \param device device to set
669 * \param enable nonzero = enable, zero = disable
670 * \return zero on success, otherwise a negative error code
672 static int set_device(snd_use_case_mgr_t *uc_mgr,
673 struct use_case_device *device,
676 struct list_head *seq;
679 if (device_status(uc_mgr, device->name) == enable)
683 seq = &device->enable_list;
685 seq = &device->disable_list;
687 err = execute_sequence(uc_mgr, seq,
689 &uc_mgr->active_verb->value_list,
690 &uc_mgr->value_list);
691 if (enable && err >= 0) {
692 list_add_tail(&device->active_list, &uc_mgr->active_devices);
693 } else if (!enable) {
694 list_del(&device->active_list);
700 * \brief Init sound card use case manager.
701 * \param uc_mgr Returned use case manager pointer
702 * \param card_name name of card to open
703 * \return zero on success, otherwise a negative error code
705 int snd_use_case_mgr_open(snd_use_case_mgr_t **uc_mgr,
706 const char *card_name)
708 snd_use_case_mgr_t *mgr;
711 /* create a new UCM */
712 mgr = calloc(1, sizeof(snd_use_case_mgr_t));
715 INIT_LIST_HEAD(&mgr->verb_list);
716 INIT_LIST_HEAD(&mgr->default_list);
717 INIT_LIST_HEAD(&mgr->value_list);
718 INIT_LIST_HEAD(&mgr->active_modifiers);
719 INIT_LIST_HEAD(&mgr->active_devices);
720 pthread_mutex_init(&mgr->mutex, NULL);
722 mgr->card_name = strdup(card_name);
723 if (mgr->card_name == NULL) {
728 /* get info on use_cases and verify against card */
729 err = import_master_config(mgr);
731 uc_error("error: failed to import %s use case configuration %d",
745 * \brief Reload and reparse all use case files.
746 * \param uc_mgr Use case manager
747 * \return zero on success, otherwise a negative error code
749 int snd_use_case_mgr_reload(snd_use_case_mgr_t *uc_mgr)
753 pthread_mutex_lock(&uc_mgr->mutex);
755 uc_mgr_free_verb(uc_mgr);
757 /* reload all use cases */
758 err = import_master_config(uc_mgr);
760 uc_error("error: failed to reload use cases\n");
761 pthread_mutex_unlock(&uc_mgr->mutex);
765 pthread_mutex_unlock(&uc_mgr->mutex);
770 * \brief Close use case manager.
771 * \param uc_mgr Use case manager
772 * \return zero on success, otherwise a negative error code
774 int snd_use_case_mgr_close(snd_use_case_mgr_t *uc_mgr)
782 * Tear down current use case verb, device and modifier.
784 static int dismantle_use_case(snd_use_case_mgr_t *uc_mgr)
786 struct list_head *pos, *npos;
787 struct use_case_modifier *modifier;
788 struct use_case_device *device;
791 list_for_each_safe(pos, npos, &uc_mgr->active_modifiers) {
792 modifier = list_entry(pos, struct use_case_modifier,
794 err = set_modifier(uc_mgr, modifier, 0);
796 uc_error("Unable to disable modifier %s", modifier->name);
798 INIT_LIST_HEAD(&uc_mgr->active_modifiers);
800 list_for_each_safe(pos, npos, &uc_mgr->active_devices) {
801 device = list_entry(pos, struct use_case_device,
803 err = set_device(uc_mgr, device, 0);
805 uc_error("Unable to disable device %s", device->name);
807 INIT_LIST_HEAD(&uc_mgr->active_devices);
809 err = set_verb(uc_mgr, uc_mgr->active_verb, 0);
811 uc_error("Unable to disable verb %s", uc_mgr->active_verb->name);
814 uc_mgr->active_verb = NULL;
816 err = execute_sequence(uc_mgr, &uc_mgr->default_list,
817 &uc_mgr->value_list, NULL, NULL);
823 * \brief Reset sound card controls to default values.
824 * \param uc_mgr Use case manager
825 * \return zero on success, otherwise a negative error code
827 int snd_use_case_mgr_reset(snd_use_case_mgr_t *uc_mgr)
831 pthread_mutex_lock(&uc_mgr->mutex);
832 err = execute_sequence(uc_mgr, &uc_mgr->default_list,
833 &uc_mgr->value_list, NULL, NULL);
834 INIT_LIST_HEAD(&uc_mgr->active_modifiers);
835 INIT_LIST_HEAD(&uc_mgr->active_devices);
836 uc_mgr->active_verb = NULL;
837 pthread_mutex_unlock(&uc_mgr->mutex);
842 * \brief Get list of verbs in pair verbname+comment
843 * \param list Returned list
844 * \param verbname For verb (NULL = current)
845 * \return Number of list entries if success, otherwise a negative error code
847 static int get_verb_list(snd_use_case_mgr_t *uc_mgr, const char **list[])
849 return get_list2(&uc_mgr->verb_list, list,
850 struct use_case_verb, list,
855 * \brief Get list of devices in pair devicename+comment
856 * \param list Returned list
857 * \param verbname For verb (NULL = current)
858 * \return Number of list entries if success, otherwise a negative error code
860 static int get_device_list(snd_use_case_mgr_t *uc_mgr, const char **list[],
863 struct use_case_verb *verb;
866 verb = find_verb(uc_mgr, verbname);
868 verb = uc_mgr->active_verb;
872 return get_list2(&verb->device_list, list,
873 struct use_case_device, list,
878 * \brief Get list of modifiers in pair devicename+comment
879 * \param list Returned list
880 * \param verbname For verb (NULL = current)
881 * \return Number of list entries if success, otherwise a negative error code
883 static int get_modifier_list(snd_use_case_mgr_t *uc_mgr, const char **list[],
886 struct use_case_verb *verb;
889 verb = find_verb(uc_mgr, verbname);
891 verb = uc_mgr->active_verb;
895 return get_list2(&verb->modifier_list, list,
896 struct use_case_modifier, list,
901 * \brief Get list of supported/conflicting devices
902 * \param list Returned list
903 * \param name Name of modifier or verb to query
904 * \param type Type of device list entries to return
905 * \return Number of list entries if success, otherwise a negative error code
907 static int get_supcon_device_list(snd_use_case_mgr_t *uc_mgr,
908 const char **list[], char *name,
909 enum dev_list_type type)
912 struct use_case_verb *verb;
913 struct use_case_modifier *modifier;
914 struct use_case_device *device;
919 str = strchr(name, '/');
922 verb = find_verb(uc_mgr, str + 1);
925 verb = uc_mgr->active_verb;
930 modifier = find_modifier(uc_mgr, verb, name, 0);
932 if (modifier->dev_list.type != type)
934 return get_list(&modifier->dev_list.list, list,
935 struct dev_list_node, list,
939 device = find_device(uc_mgr, verb, name, 0);
941 if (device->dev_list.type != type)
943 return get_list(&device->dev_list.list, list,
944 struct dev_list_node, list,
953 * \brief Get list of supported devices
954 * \param list Returned list
955 * \param name Name of verb or modifier to query
956 * \return Number of list entries if success, otherwise a negative error code
958 static int get_supported_device_list(snd_use_case_mgr_t *uc_mgr,
959 const char **list[], char *name)
961 return get_supcon_device_list(uc_mgr, list, name, DEVLIST_SUPPORTED);
965 * \brief Get list of conflicting devices
966 * \param list Returned list
967 * \param name Name of verb or modifier to query
968 * \return Number of list entries if success, otherwise a negative error code
970 static int get_conflicting_device_list(snd_use_case_mgr_t *uc_mgr,
971 const char **list[], char *name)
973 return get_supcon_device_list(uc_mgr, list, name, DEVLIST_CONFLICTING);
978 struct list_head list;
983 static int add_values(struct list_head *list,
984 const char *identifier,
985 struct list_head *source)
989 struct list_head *pos, *pos1;
992 list_for_each(pos, source) {
993 v = list_entry(pos, struct ucm_value, list);
994 if (check_identifier(identifier, v->name)) {
996 list_for_each(pos1, list) {
997 val = list_entry(pos1, struct myvalue, list);
998 if (strcmp(val->value, v->data) == 0) {
1004 val = malloc(sizeof(struct myvalue));
1007 val->value = v->data;
1008 list_add_tail(&val->list, list);
1016 * \brief Get list of values
1017 * \param list Returned list
1018 * \param verbname For verb (NULL = current)
1019 * \return Number of list entries if success, otherwise a negative error code
1021 static int get_value_list(snd_use_case_mgr_t *uc_mgr,
1022 const char *identifier,
1023 const char **list[],
1026 struct list_head mylist, *pos, *npos;
1027 struct myvalue *val;
1028 struct use_case_verb *verb;
1029 struct use_case_device *dev;
1030 struct use_case_modifier *mod;
1035 verb = find_verb(uc_mgr, verbname);
1037 verb = uc_mgr->active_verb;
1041 INIT_LIST_HEAD(&mylist);
1042 err = add_values(&mylist, identifier, &uc_mgr->value_list);
1045 err = add_values(&mylist, identifier, &verb->value_list);
1048 list_for_each(pos, &verb->device_list) {
1049 dev = list_entry(pos, struct use_case_device, list);
1050 err = add_values(&mylist, identifier, &dev->value_list);
1054 list_for_each(pos, &verb->modifier_list) {
1055 mod = list_entry(pos, struct use_case_modifier, list);
1056 err = add_values(&mylist, identifier, &mod->value_list);
1060 err = alloc_str_list(&mylist, 1, &res);
1062 *list = (const char **)res;
1063 list_for_each(pos, &mylist) {
1064 val = list_entry(pos, struct myvalue, list);
1065 *res = strdup(val->value);
1067 snd_use_case_free_list((const char **)res, err);
1075 list_for_each_safe(pos, npos, &mylist) {
1076 val = list_entry(pos, struct myvalue, list);
1077 list_del(&val->list);
1084 * \brief Get list of enabled devices
1085 * \param list Returned list
1086 * \param verbname For verb (NULL = current)
1087 * \return Number of list entries if success, otherwise a negative error code
1089 static int get_enabled_device_list(snd_use_case_mgr_t *uc_mgr,
1090 const char **list[])
1092 if (uc_mgr->active_verb == NULL)
1094 return get_list(&uc_mgr->active_devices, list,
1095 struct use_case_device, active_list,
1100 * \brief Get list of enabled modifiers
1101 * \param list Returned list
1102 * \param verbname For verb (NULL = current)
1103 * \return Number of list entries if success, otherwise a negative error code
1105 static int get_enabled_modifier_list(snd_use_case_mgr_t *uc_mgr,
1106 const char **list[])
1108 if (uc_mgr->active_verb == NULL)
1110 return get_list(&uc_mgr->active_modifiers, list,
1111 struct use_case_modifier, active_list,
1116 * \brief Obtain a list of entries
1117 * \param uc_mgr Use case manager (may be NULL - card list)
1118 * \param identifier (may be NULL - card list)
1119 * \param list Returned allocated list
1120 * \return Number of list entries if success, otherwise a negative error code
1122 int snd_use_case_get_list(snd_use_case_mgr_t *uc_mgr,
1123 const char *identifier,
1124 const char **list[])
1129 if (uc_mgr == NULL || identifier == NULL)
1130 return uc_mgr_scan_master_configs(list);
1131 pthread_mutex_lock(&uc_mgr->mutex);
1132 if (strcmp(identifier, "_verbs") == 0)
1133 err = get_verb_list(uc_mgr, list);
1134 else if (strcmp(identifier, "_enadevs") == 0)
1135 err = get_enabled_device_list(uc_mgr, list);
1136 else if (strcmp(identifier, "_enamods") == 0)
1137 err = get_enabled_modifier_list(uc_mgr, list);
1139 str1 = strchr(identifier, '/');
1141 str = strdup(str1 + 1);
1149 if (check_identifier(identifier, "_devices"))
1150 err = get_device_list(uc_mgr, list, str);
1151 else if (check_identifier(identifier, "_modifiers"))
1152 err = get_modifier_list(uc_mgr, list, str);
1153 else if (check_identifier(identifier, "_supporteddevs"))
1154 err = get_supported_device_list(uc_mgr, list, str);
1155 else if (check_identifier(identifier, "_conflictingdevs"))
1156 err = get_conflicting_device_list(uc_mgr, list, str);
1157 else if (identifier[0] == '_')
1160 err = get_value_list(uc_mgr, identifier, list, str);
1165 pthread_mutex_unlock(&uc_mgr->mutex);
1169 static int get_value1(const char **value, struct list_head *value_list,
1170 const char *identifier)
1172 struct ucm_value *val;
1173 struct list_head *pos;
1178 list_for_each(pos, value_list) {
1179 val = list_entry(pos, struct ucm_value, list);
1180 if (check_identifier(identifier, val->name)) {
1181 *value = strdup(val->data);
1190 static int get_value3(const char **value,
1191 const char *identifier,
1192 struct list_head *value_list1,
1193 struct list_head *value_list2,
1194 struct list_head *value_list3)
1198 err = get_value1(value, value_list1, identifier);
1199 if (err >= 0 || err != -ENOENT)
1201 err = get_value1(value, value_list2, identifier);
1202 if (err >= 0 || err != -ENOENT)
1204 err = get_value1(value, value_list3, identifier);
1205 if (err >= 0 || err != -ENOENT)
1212 * \param uc_mgr Use case manager
1213 * \param identifier Value identifier (string)
1214 * \param value Returned value string
1215 * \param item Modifier or Device name (string)
1216 * \return Zero on success (value is filled), otherwise a negative error code
1218 static int get_value(snd_use_case_mgr_t *uc_mgr,
1219 const char *identifier,
1221 const char *mod_dev_name,
1222 const char *verb_name,
1225 struct use_case_verb *verb;
1226 struct use_case_modifier *mod;
1227 struct use_case_device *dev;
1230 if (mod_dev_name || verb_name || !exact) {
1231 if (verb_name && strlen(verb_name)) {
1232 verb = find_verb(uc_mgr, verb_name);
1234 verb = uc_mgr->active_verb;
1238 mod = find_modifier(uc_mgr, verb,
1241 err = get_value1(value,
1244 if (err >= 0 || err != -ENOENT)
1248 dev = find_device(uc_mgr, verb,
1251 err = get_value1(value,
1254 if (err >= 0 || err != -ENOENT)
1262 err = get_value1(value, &verb->value_list, identifier);
1263 if (err >= 0 || err != -ENOENT)
1271 err = get_value1(value, &uc_mgr->value_list, identifier);
1272 if (err >= 0 || err != -ENOENT)
1279 * \brief Get current - string
1280 * \param uc_mgr Use case manager
1282 * \param value Value pointer
1283 * \return Zero if success, otherwise a negative error code
1285 * Note: String is dynamically allocated, use free() to
1286 * deallocate this string.
1288 int snd_use_case_get(snd_use_case_mgr_t *uc_mgr,
1289 const char *identifier,
1292 const char *slash1, *slash2, *mod_dev_after;
1293 const char *ident, *mod_dev, *verb;
1297 pthread_mutex_lock(&uc_mgr->mutex);
1298 if (identifier == NULL) {
1299 *value = strdup(uc_mgr->card_name);
1300 if (*value == NULL) {
1305 } else if (strcmp(identifier, "_verb") == 0) {
1306 if (uc_mgr->active_verb == NULL) {
1310 *value = strdup(uc_mgr->active_verb->name);
1311 if (*value == NULL) {
1316 } else if (identifier[0] == '_') {
1320 if (identifier[0] == '=') {
1325 slash1 = strchr(identifier, '/');
1327 ident = strndup(identifier, slash1 - identifier);
1329 slash2 = strchr(slash1 + 1, '/');
1331 mod_dev_after = slash2;
1335 mod_dev_after = slash1 + strlen(slash1);
1339 if (mod_dev_after == slash1 + 1)
1342 mod_dev = strndup(slash1 + 1,
1343 mod_dev_after - (slash1 + 1));
1351 err = get_value(uc_mgr, ident, value, mod_dev, verb, exact);
1352 if (ident != identifier)
1353 free((void *)ident);
1355 free((void *)mod_dev);
1358 pthread_mutex_unlock(&uc_mgr->mutex);
1364 * \brief Get current - integer
1365 * \param uc_mgr Use case manager
1367 * \return Value if success, otherwise a negative error code
1369 int snd_use_case_geti(snd_use_case_mgr_t *uc_mgr,
1370 const char *identifier,
1376 pthread_mutex_lock(&uc_mgr->mutex);
1378 /* nothing here - prepared for fixed identifiers */
1380 str1 = strchr(identifier, '/');
1382 str = strdup(str1 + 1);
1390 if (check_identifier(identifier, "_devstatus")) {
1391 err = device_status(uc_mgr, str);
1396 } else if (check_identifier(identifier, "_modstatus")) {
1397 err = modifier_status(uc_mgr, str);
1404 * enable this block if the else clause below is expanded to query
1405 * user-supplied values
1407 } else if (identifier[0] == '_')
1416 pthread_mutex_unlock(&uc_mgr->mutex);
1420 static int handle_transition_verb(snd_use_case_mgr_t *uc_mgr,
1421 struct use_case_verb *new_verb)
1423 struct list_head *pos;
1424 struct transition_sequence *trans;
1427 list_for_each(pos, &uc_mgr->active_verb->transition_list) {
1428 trans = list_entry(pos, struct transition_sequence, list);
1429 if (strcmp(trans->name, new_verb->name) == 0) {
1430 err = execute_sequence(uc_mgr, &trans->transition_list,
1431 &uc_mgr->active_verb->value_list,
1432 &uc_mgr->value_list,
1442 static int set_verb_user(snd_use_case_mgr_t *uc_mgr,
1443 const char *verb_name)
1445 struct use_case_verb *verb;
1448 if (uc_mgr->active_verb &&
1449 strcmp(uc_mgr->active_verb->name, verb_name) == 0)
1451 if (strcmp(verb_name, SND_USE_CASE_VERB_INACTIVE) != 0) {
1452 verb = find_verb(uc_mgr, verb_name);
1458 if (uc_mgr->active_verb) {
1459 err = handle_transition_verb(uc_mgr, verb);
1461 err = dismantle_use_case(uc_mgr);
1464 } else if (err == 1) {
1465 uc_mgr->active_verb = verb;
1468 verb = NULL; /* show error */
1472 err = set_verb(uc_mgr, verb, 1);
1474 uc_error("error: failed to initialize new use case: %s",
1481 static int set_device_user(snd_use_case_mgr_t *uc_mgr,
1482 const char *device_name,
1485 struct use_case_device *device;
1487 if (uc_mgr->active_verb == NULL)
1489 device = find_device(uc_mgr, uc_mgr->active_verb, device_name, 1);
1492 return set_device(uc_mgr, device, enable);
1495 static int set_modifier_user(snd_use_case_mgr_t *uc_mgr,
1496 const char *modifier_name,
1499 struct use_case_modifier *modifier;
1501 if (uc_mgr->active_verb == NULL)
1504 modifier = find_modifier(uc_mgr, uc_mgr->active_verb, modifier_name, 1);
1505 if (modifier == NULL)
1507 return set_modifier(uc_mgr, modifier, enable);
1510 static int switch_device(snd_use_case_mgr_t *uc_mgr,
1511 const char *old_device,
1512 const char *new_device)
1514 struct use_case_device *xold, *xnew;
1515 struct transition_sequence *trans;
1516 struct list_head *pos;
1517 int err, seq_found = 0;
1519 if (uc_mgr->active_verb == NULL)
1521 if (device_status(uc_mgr, old_device) == 0) {
1522 uc_error("error: device %s not enabled", old_device);
1525 if (device_status(uc_mgr, new_device) != 0) {
1526 uc_error("error: device %s already enabled", new_device);
1529 xold = find_device(uc_mgr, uc_mgr->active_verb, old_device, 1);
1532 list_del(&xold->active_list);
1533 xnew = find_device(uc_mgr, uc_mgr->active_verb, new_device, 1);
1534 list_add_tail(&xold->active_list, &uc_mgr->active_devices);
1538 list_for_each(pos, &xold->transition_list) {
1539 trans = list_entry(pos, struct transition_sequence, list);
1540 if (strcmp(trans->name, new_device) == 0) {
1541 err = execute_sequence(uc_mgr, &trans->transition_list,
1543 &uc_mgr->active_verb->value_list,
1544 &uc_mgr->value_list);
1546 list_del(&xold->active_list);
1547 list_add_tail(&xnew->active_list, &uc_mgr->active_devices);
1554 err = set_device(uc_mgr, xold, 0);
1557 err = set_device(uc_mgr, xnew, 1);
1564 static int switch_modifier(snd_use_case_mgr_t *uc_mgr,
1565 const char *old_modifier,
1566 const char *new_modifier)
1568 struct use_case_modifier *xold, *xnew;
1569 struct transition_sequence *trans;
1570 struct list_head *pos;
1571 int err, seq_found = 0;
1573 if (uc_mgr->active_verb == NULL)
1575 if (modifier_status(uc_mgr, old_modifier) == 0) {
1576 uc_error("error: modifier %s not enabled", old_modifier);
1579 if (modifier_status(uc_mgr, new_modifier) != 0) {
1580 uc_error("error: modifier %s already enabled", new_modifier);
1583 xold = find_modifier(uc_mgr, uc_mgr->active_verb, old_modifier, 1);
1586 xnew = find_modifier(uc_mgr, uc_mgr->active_verb, new_modifier, 1);
1590 list_for_each(pos, &xold->transition_list) {
1591 trans = list_entry(pos, struct transition_sequence, list);
1592 if (strcmp(trans->name, new_modifier) == 0) {
1593 err = execute_sequence(uc_mgr, &trans->transition_list,
1595 &uc_mgr->active_verb->value_list,
1596 &uc_mgr->value_list);
1598 list_del(&xold->active_list);
1599 list_add_tail(&xnew->active_list, &uc_mgr->active_modifiers);
1606 err = set_modifier(uc_mgr, xold, 0);
1609 err = set_modifier(uc_mgr, xnew, 1);
1618 * \param uc_mgr Use case manager
1620 * \param value Value
1621 * \return Zero if success, otherwise a negative error code
1623 int snd_use_case_set(snd_use_case_mgr_t *uc_mgr,
1624 const char *identifier,
1630 pthread_mutex_lock(&uc_mgr->mutex);
1631 if (strcmp(identifier, "_verb") == 0)
1632 err = set_verb_user(uc_mgr, value);
1633 else if (strcmp(identifier, "_enadev") == 0)
1634 err = set_device_user(uc_mgr, value, 1);
1635 else if (strcmp(identifier, "_disdev") == 0)
1636 err = set_device_user(uc_mgr, value, 0);
1637 else if (strcmp(identifier, "_enamod") == 0)
1638 err = set_modifier_user(uc_mgr, value, 1);
1639 else if (strcmp(identifier, "_dismod") == 0)
1640 err = set_modifier_user(uc_mgr, value, 0);
1642 str1 = strchr(identifier, '/');
1644 str = strdup(str1 + 1);
1653 if (check_identifier(identifier, "_swdev"))
1654 err = switch_device(uc_mgr, str, value);
1655 else if (check_identifier(identifier, "_swmod"))
1656 err = switch_modifier(uc_mgr, str, value);
1663 pthread_mutex_unlock(&uc_mgr->mutex);