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 /* Remove because security issues */
285 /* err = system(s->data.exec);
288 uc_error("unsupported known sequence command %i", s->type);
291 uc_error("unknown sequence command %i", s->type);
306 * \brief Import master config and execute the default sequence
307 * \param uc_mgr Use case manager
308 * \return zero on success, otherwise a negative error code
310 static int import_master_config(snd_use_case_mgr_t *uc_mgr)
314 err = uc_mgr_import_master_config(uc_mgr);
317 err = execute_sequence(uc_mgr, &uc_mgr->default_list,
318 &uc_mgr->value_list, NULL, NULL);
320 uc_error("Unable to execute default sequence");
325 * \brief Universal find - string in a list
326 * \param list List of structures
327 * \param offset Offset of list structure
328 * \param soffset Offset of string structure
329 * \param match String to match
330 * \return structure on success, otherwise a NULL (not found)
332 static void *find0(struct list_head *list,
333 unsigned long offset,
334 unsigned long soffset,
337 struct list_head *pos;
340 list_for_each(pos, list) {
341 ptr = list_entry_offset(pos, char, offset);
342 str = *((char **)(ptr + soffset));
343 if (strcmp(str, match) == 0)
349 #define find(list, type, member, value, match) \
350 find0(list, (unsigned long)(&((type *)0)->member), \
351 (unsigned long)(&((type *)0)->value), match)
354 * \brief Universal string list
355 * \param list List of structures
356 * \param result Result list
357 * \param offset Offset of list structure
358 * \param s1offset Offset of string structure
359 * \return count of items on success, otherwise a negative error code
361 static int get_list0(struct list_head *list,
362 const char **result[],
363 unsigned long offset,
364 unsigned long s1offset)
368 struct list_head *pos;
371 cnt = alloc_str_list(list, 1, &res);
374 *result = (const char **)res;
375 list_for_each(pos, list) {
376 ptr = list_entry_offset(pos, char, offset);
377 str1 = *((char **)(ptr + s1offset));
389 snd_use_case_free_list((const char **)res, cnt);
393 #define get_list(list, result, type, member, s1) \
394 get_list0(list, result, \
395 (unsigned long)(&((type *)0)->member), \
396 (unsigned long)(&((type *)0)->s1))
399 * \brief Universal string list - pair of strings
400 * \param list List of structures
401 * \param result Result list
402 * \param offset Offset of list structure
403 * \param s1offset Offset of string structure
404 * \param s1offset Offset of string structure
405 * \return count of items on success, otherwise a negative error code
407 static int get_list20(struct list_head *list,
408 const char **result[],
409 unsigned long offset,
410 unsigned long s1offset,
411 unsigned long s2offset)
415 struct list_head *pos;
416 char *ptr, *str1, *str2;
418 cnt = alloc_str_list(list, 2, &res);
421 *result = (const char **)res;
422 list_for_each(pos, list) {
423 ptr = list_entry_offset(pos, char, offset);
424 str1 = *((char **)(ptr + s1offset));
433 str2 = *((char **)(ptr + s2offset));
445 snd_use_case_free_list((const char **)res, cnt);
449 #define get_list2(list, result, type, member, s1, s2) \
450 get_list20(list, result, \
451 (unsigned long)(&((type *)0)->member), \
452 (unsigned long)(&((type *)0)->s1), \
453 (unsigned long)(&((type *)0)->s2))
457 * \param uc_mgr Use case manager
458 * \param verb_name verb to find
459 * \return structure on success, otherwise a NULL (not found)
461 static inline struct use_case_verb *find_verb(snd_use_case_mgr_t *uc_mgr,
462 const char *verb_name)
464 return find(&uc_mgr->verb_list,
465 struct use_case_verb, list, name,
469 static int is_devlist_supported(snd_use_case_mgr_t *uc_mgr,
470 struct dev_list *dev_list)
472 struct dev_list_node *device;
473 struct use_case_device *adev;
474 struct list_head *pos, *pos1;
477 switch (dev_list->type) {
481 case DEVLIST_SUPPORTED:
484 case DEVLIST_CONFLICTING:
489 list_for_each(pos, &dev_list->list) {
490 device = list_entry(pos, struct dev_list_node, list);
492 list_for_each(pos1, &uc_mgr->active_devices) {
493 adev = list_entry(pos1, struct use_case_device,
495 if (!strcmp(device->name, adev->name))
499 return 1 - found_ret;
502 static inline int is_modifier_supported(snd_use_case_mgr_t *uc_mgr,
503 struct use_case_modifier *modifier)
505 return is_devlist_supported(uc_mgr, &modifier->dev_list);
508 static inline int is_device_supported(snd_use_case_mgr_t *uc_mgr,
509 struct use_case_device *device)
511 return is_devlist_supported(uc_mgr, &device->dev_list);
516 * \param verb Use case verb
517 * \param device_name device to find
518 * \return structure on success, otherwise a NULL (not found)
520 static inline struct use_case_device *
521 find_device(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb,
522 const char *device_name, int check_supported)
524 struct use_case_device *device;
525 struct list_head *pos;
527 list_for_each(pos, &verb->device_list) {
528 device = list_entry(pos, struct use_case_device, list);
530 if (strcmp(device_name, device->name))
533 if (check_supported &&
534 !is_device_supported(uc_mgr, device))
543 * \brief Find modifier
544 * \param verb Use case verb
545 * \param modifier_name modifier to find
546 * \return structure on success, otherwise a NULL (not found)
548 static struct use_case_modifier *
549 find_modifier(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb,
550 const char *modifier_name, int check_supported)
552 struct use_case_modifier *modifier;
553 struct list_head *pos;
555 list_for_each(pos, &verb->modifier_list) {
556 modifier = list_entry(pos, struct use_case_modifier, list);
558 if (strcmp(modifier->name, modifier_name))
561 if (check_supported &&
562 !is_modifier_supported(uc_mgr, modifier))
572 * \param uc_mgr Use case manager
573 * \param verb verb to set
574 * \param enable nonzero = enable, zero = disable
575 * \return zero on success, otherwise a negative error code
577 static int set_verb(snd_use_case_mgr_t *uc_mgr,
578 struct use_case_verb *verb,
581 struct list_head *seq;
585 seq = &verb->enable_list;
587 seq = &verb->disable_list;
589 err = execute_sequence(uc_mgr, seq,
593 if (enable && err >= 0)
594 uc_mgr->active_verb = verb;
599 * \brief Set modifier
600 * \param uc_mgr Use case manager
601 * \param modifier modifier to set
602 * \param enable nonzero = enable, zero = disable
603 * \return zero on success, otherwise a negative error code
605 static int set_modifier(snd_use_case_mgr_t *uc_mgr,
606 struct use_case_modifier *modifier,
609 struct list_head *seq;
613 seq = &modifier->enable_list;
615 seq = &modifier->disable_list;
617 err = execute_sequence(uc_mgr, seq,
618 &modifier->value_list,
619 &uc_mgr->active_verb->value_list,
620 &uc_mgr->value_list);
621 if (enable && err >= 0) {
622 list_add_tail(&modifier->active_list, &uc_mgr->active_modifiers);
623 } else if (!enable) {
624 list_del(&modifier->active_list);
631 * \param uc_mgr Use case manager
632 * \param device device to set
633 * \param enable nonzero = enable, zero = disable
634 * \return zero on success, otherwise a negative error code
636 static int set_device(snd_use_case_mgr_t *uc_mgr,
637 struct use_case_device *device,
640 struct list_head *seq;
644 seq = &device->enable_list;
646 seq = &device->disable_list;
648 err = execute_sequence(uc_mgr, seq,
650 &uc_mgr->active_verb->value_list,
651 &uc_mgr->value_list);
652 if (enable && err >= 0) {
653 list_add_tail(&device->active_list, &uc_mgr->active_devices);
654 } else if (!enable) {
655 list_del(&device->active_list);
661 * \brief Init sound card use case manager.
662 * \param uc_mgr Returned use case manager pointer
663 * \param card_name name of card to open
664 * \return zero on success, otherwise a negative error code
666 int snd_use_case_mgr_open(snd_use_case_mgr_t **mgr,
667 const char *card_name)
669 snd_use_case_mgr_t *uc_mgr;
672 /* create a new UCM */
673 uc_mgr = calloc(1, sizeof(snd_use_case_mgr_t));
676 INIT_LIST_HEAD(&uc_mgr->verb_list);
677 INIT_LIST_HEAD(&uc_mgr->default_list);
678 INIT_LIST_HEAD(&uc_mgr->value_list);
679 INIT_LIST_HEAD(&uc_mgr->active_modifiers);
680 INIT_LIST_HEAD(&uc_mgr->active_devices);
681 pthread_mutex_init(&uc_mgr->mutex, NULL);
683 uc_mgr->card_name = strdup(card_name);
684 if (uc_mgr->card_name == NULL) {
689 /* get info on use_cases and verify against card */
690 err = import_master_config(uc_mgr);
692 uc_error("error: failed to import %s use case configuration %d",
706 * \brief Reload and reparse all use case files.
707 * \param uc_mgr Use case manager
708 * \return zero on success, otherwise a negative error code
710 int snd_use_case_mgr_reload(snd_use_case_mgr_t *uc_mgr)
714 pthread_mutex_lock(&uc_mgr->mutex);
716 uc_mgr_free_verb(uc_mgr);
718 /* reload all use cases */
719 err = import_master_config(uc_mgr);
721 uc_error("error: failed to reload use cases\n");
722 pthread_mutex_unlock(&uc_mgr->mutex);
726 pthread_mutex_unlock(&uc_mgr->mutex);
731 * \brief Close use case manager.
732 * \param uc_mgr Use case manager
733 * \return zero on success, otherwise a negative error code
735 int snd_use_case_mgr_close(snd_use_case_mgr_t *uc_mgr)
743 * Tear down current use case verb, device and modifier.
745 static int dismantle_use_case(snd_use_case_mgr_t *uc_mgr)
747 struct list_head *pos, *npos;
748 struct use_case_modifier *modifier;
749 struct use_case_device *device;
752 list_for_each_safe(pos, npos, &uc_mgr->active_modifiers) {
753 modifier = list_entry(pos, struct use_case_modifier,
755 err = set_modifier(uc_mgr, modifier, 0);
757 uc_error("Unable to disable modifier %s", modifier->name);
759 INIT_LIST_HEAD(&uc_mgr->active_modifiers);
761 list_for_each_safe(pos, npos, &uc_mgr->active_devices) {
762 device = list_entry(pos, struct use_case_device,
764 err = set_device(uc_mgr, device, 0);
766 uc_error("Unable to disable device %s", device->name);
768 INIT_LIST_HEAD(&uc_mgr->active_devices);
770 err = set_verb(uc_mgr, uc_mgr->active_verb, 0);
772 uc_error("Unable to disable verb %s", uc_mgr->active_verb->name);
775 uc_mgr->active_verb = NULL;
777 err = execute_sequence(uc_mgr, &uc_mgr->default_list,
778 &uc_mgr->value_list, NULL, NULL);
784 * \brief Reset sound card controls to default values.
785 * \param uc_mgr Use case manager
786 * \return zero on success, otherwise a negative error code
788 int snd_use_case_mgr_reset(snd_use_case_mgr_t *uc_mgr)
792 pthread_mutex_lock(&uc_mgr->mutex);
793 err = execute_sequence(uc_mgr, &uc_mgr->default_list,
794 &uc_mgr->value_list, NULL, NULL);
795 INIT_LIST_HEAD(&uc_mgr->active_modifiers);
796 INIT_LIST_HEAD(&uc_mgr->active_devices);
797 uc_mgr->active_verb = NULL;
798 pthread_mutex_unlock(&uc_mgr->mutex);
803 * \brief Get list of verbs in pair verbname+comment
804 * \param list Returned list
805 * \param verbname For verb (NULL = current)
806 * \return Number of list entries if success, otherwise a negative error code
808 static int get_verb_list(snd_use_case_mgr_t *uc_mgr, const char **list[])
810 return get_list2(&uc_mgr->verb_list, list,
811 struct use_case_verb, list,
816 * \brief Get list of devices in pair devicename+comment
817 * \param list Returned list
818 * \param verbname For verb (NULL = current)
819 * \return Number of list entries if success, otherwise a negative error code
821 static int get_device_list(snd_use_case_mgr_t *uc_mgr, const char **list[],
824 struct use_case_verb *verb;
827 verb = find_verb(uc_mgr, verbname);
829 verb = uc_mgr->active_verb;
833 return get_list2(&verb->device_list, list,
834 struct use_case_device, list,
839 * \brief Get list of modifiers in pair devicename+comment
840 * \param list Returned list
841 * \param verbname For verb (NULL = current)
842 * \return Number of list entries if success, otherwise a negative error code
844 static int get_modifier_list(snd_use_case_mgr_t *uc_mgr, const char **list[],
847 struct use_case_verb *verb;
850 verb = find_verb(uc_mgr, verbname);
852 verb = uc_mgr->active_verb;
856 return get_list2(&verb->modifier_list, list,
857 struct use_case_modifier, list,
862 * \brief Get list of supported/conflicting devices
863 * \param list Returned list
864 * \param name Name of modifier or verb to query
865 * \param type Type of device list entries to return
866 * \return Number of list entries if success, otherwise a negative error code
868 static int get_supcon_device_list(snd_use_case_mgr_t *uc_mgr,
869 const char **list[], char *name,
870 enum dev_list_type type)
873 struct use_case_verb *verb;
874 struct use_case_modifier *modifier;
875 struct use_case_device *device;
880 str = strchr(name, '/');
883 verb = find_verb(uc_mgr, str + 1);
886 verb = uc_mgr->active_verb;
891 modifier = find_modifier(uc_mgr, verb, name, 0);
893 if (modifier->dev_list.type != type)
895 return get_list(&modifier->dev_list.list, list,
896 struct dev_list_node, list,
900 device = find_device(uc_mgr, verb, name, 0);
902 if (device->dev_list.type != type)
904 return get_list(&device->dev_list.list, list,
905 struct dev_list_node, list,
914 * \brief Get list of supported devices
915 * \param list Returned list
916 * \param name Name of verb or modifier to query
917 * \return Number of list entries if success, otherwise a negative error code
919 static int get_supported_device_list(snd_use_case_mgr_t *uc_mgr,
920 const char **list[], char *name)
922 return get_supcon_device_list(uc_mgr, list, name, DEVLIST_SUPPORTED);
926 * \brief Get list of conflicting devices
927 * \param list Returned list
928 * \param name Name of verb or modifier to query
929 * \return Number of list entries if success, otherwise a negative error code
931 static int get_conflicting_device_list(snd_use_case_mgr_t *uc_mgr,
932 const char **list[], char *name)
934 return get_supcon_device_list(uc_mgr, list, name, DEVLIST_CONFLICTING);
938 struct list_head list;
942 static int add_values(struct list_head *list,
943 const char *identifier,
944 struct list_head *source)
948 struct list_head *pos, *pos1;
951 list_for_each(pos, source) {
952 v = list_entry(pos, struct ucm_value, list);
953 if (check_identifier(identifier, v->name)) {
955 list_for_each(pos1, list) {
956 val = list_entry(pos1, struct myvalue, list);
957 if (strcmp(val->value, v->data) == 0) {
963 val = malloc(sizeof(struct myvalue));
966 val->value = v->data;
967 list_add_tail(&val->list, list);
975 * \brief Get list of values
976 * \param list Returned list
977 * \param verbname For verb (NULL = current)
978 * \return Number of list entries if success, otherwise a negative error code
980 static int get_value_list(snd_use_case_mgr_t *uc_mgr,
981 const char *identifier,
985 struct list_head mylist, *pos, *npos;
987 struct use_case_verb *verb;
988 struct use_case_device *dev;
989 struct use_case_modifier *mod;
994 verb = find_verb(uc_mgr, verbname);
996 verb = uc_mgr->active_verb;
1000 INIT_LIST_HEAD(&mylist);
1001 err = add_values(&mylist, identifier, &uc_mgr->value_list);
1004 err = add_values(&mylist, identifier, &verb->value_list);
1007 list_for_each(pos, &verb->device_list) {
1008 dev = list_entry(pos, struct use_case_device, list);
1009 err = add_values(&mylist, identifier, &dev->value_list);
1013 list_for_each(pos, &verb->modifier_list) {
1014 mod = list_entry(pos, struct use_case_modifier, list);
1015 err = add_values(&mylist, identifier, &mod->value_list);
1019 err = alloc_str_list(&mylist, 1, &res);
1021 *list = (const char **)res;
1022 list_for_each(pos, &mylist) {
1023 val = list_entry(pos, struct myvalue, list);
1024 *res = strdup(val->value);
1026 snd_use_case_free_list((const char **)res, err);
1034 list_for_each_safe(pos, npos, &mylist) {
1035 val = list_entry(pos, struct myvalue, list);
1036 list_del(&val->list);
1043 * \brief Get list of enabled devices
1044 * \param list Returned list
1045 * \param verbname For verb (NULL = current)
1046 * \return Number of list entries if success, otherwise a negative error code
1048 static int get_enabled_device_list(snd_use_case_mgr_t *uc_mgr,
1049 const char **list[])
1051 if (uc_mgr->active_verb == NULL)
1053 return get_list(&uc_mgr->active_devices, list,
1054 struct use_case_device, active_list,
1059 * \brief Get list of enabled modifiers
1060 * \param list Returned list
1061 * \param verbname For verb (NULL = current)
1062 * \return Number of list entries if success, otherwise a negative error code
1064 static int get_enabled_modifier_list(snd_use_case_mgr_t *uc_mgr,
1065 const char **list[])
1067 if (uc_mgr->active_verb == NULL)
1069 return get_list(&uc_mgr->active_modifiers, list,
1070 struct use_case_modifier, active_list,
1075 * \brief Obtain a list of entries
1076 * \param uc_mgr Use case manager (may be NULL - card list)
1077 * \param identifier (may be NULL - card list)
1078 * \param list Returned allocated list
1079 * \return Number of list entries if success, otherwise a negative error code
1081 int snd_use_case_get_list(snd_use_case_mgr_t *uc_mgr,
1082 const char *identifier,
1083 const char **list[])
1088 if (uc_mgr == NULL || identifier == NULL)
1089 return uc_mgr_scan_master_configs(list);
1090 pthread_mutex_lock(&uc_mgr->mutex);
1091 if (strcmp(identifier, "_verbs") == 0)
1092 err = get_verb_list(uc_mgr, list);
1093 else if (strcmp(identifier, "_enadevs") == 0)
1094 err = get_enabled_device_list(uc_mgr, list);
1095 else if (strcmp(identifier, "_enamods") == 0)
1096 err = get_enabled_modifier_list(uc_mgr, list);
1098 str1 = strchr(identifier, '/');
1100 str = strdup(str1 + 1);
1108 if (check_identifier(identifier, "_devices"))
1109 err = get_device_list(uc_mgr, list, str);
1110 else if (check_identifier(identifier, "_modifiers"))
1111 err = get_modifier_list(uc_mgr, list, str);
1112 else if (check_identifier(identifier, "_supporteddevs"))
1113 err = get_supported_device_list(uc_mgr, list, str);
1114 else if (check_identifier(identifier, "_conflictingdevs"))
1115 err = get_conflicting_device_list(uc_mgr, list, str);
1116 else if (identifier[0] == '_')
1119 err = get_value_list(uc_mgr, identifier, list, str);
1124 pthread_mutex_unlock(&uc_mgr->mutex);
1128 static int get_value1(const char **value, struct list_head *value_list,
1129 const char *identifier)
1131 struct ucm_value *val;
1132 struct list_head *pos;
1137 list_for_each(pos, value_list) {
1138 val = list_entry(pos, struct ucm_value, list);
1139 if (check_identifier(identifier, val->name)) {
1140 *value = strdup(val->data);
1149 static int get_value3(const char **value,
1150 const char *identifier,
1151 struct list_head *value_list1,
1152 struct list_head *value_list2,
1153 struct list_head *value_list3)
1157 err = get_value1(value, value_list1, identifier);
1158 if (err >= 0 || err != -ENOENT)
1160 err = get_value1(value, value_list2, identifier);
1161 if (err >= 0 || err != -ENOENT)
1163 err = get_value1(value, value_list3, identifier);
1164 if (err >= 0 || err != -ENOENT)
1171 * \param uc_mgr Use case manager
1172 * \param identifier Value identifier (string)
1173 * \param value Returned value string
1174 * \param item Modifier or Device name (string)
1175 * \return Zero on success (value is filled), otherwise a negative error code
1177 static int get_value(snd_use_case_mgr_t *uc_mgr,
1178 const char *identifier,
1180 const char *mod_dev_name,
1181 const char *verb_name,
1184 struct use_case_verb *verb;
1185 struct use_case_modifier *mod;
1186 struct use_case_device *dev;
1189 if (mod_dev_name || verb_name || !exact) {
1190 if (verb_name && strlen(verb_name)) {
1191 verb = find_verb(uc_mgr, verb_name);
1193 verb = uc_mgr->active_verb;
1197 mod = find_modifier(uc_mgr, verb,
1200 err = get_value1(value,
1203 if (err >= 0 || err != -ENOENT)
1207 dev = find_device(uc_mgr, verb,
1210 err = get_value1(value,
1213 if (err >= 0 || err != -ENOENT)
1221 err = get_value1(value, &verb->value_list, identifier);
1222 if (err >= 0 || err != -ENOENT)
1230 err = get_value1(value, &uc_mgr->value_list, identifier);
1231 if (err >= 0 || err != -ENOENT)
1238 * \brief Get current - string
1239 * \param uc_mgr Use case manager
1241 * \param value Value pointer
1242 * \return Zero if success, otherwise a negative error code
1244 * Note: String is dynamically allocated, use free() to
1245 * deallocate this string.
1247 int snd_use_case_get(snd_use_case_mgr_t *uc_mgr,
1248 const char *identifier,
1251 const char *slash1, *slash2, *mod_dev_after;
1252 const char *ident, *mod_dev, *verb;
1256 pthread_mutex_lock(&uc_mgr->mutex);
1257 if (identifier == NULL) {
1258 *value = strdup(uc_mgr->card_name);
1259 if (*value == NULL) {
1264 } else if (strcmp(identifier, "_verb") == 0) {
1265 if (uc_mgr->active_verb == NULL) {
1269 *value = strdup(uc_mgr->active_verb->name);
1270 if (*value == NULL) {
1275 } else if (identifier[0] == '_') {
1279 if (identifier[0] == '=') {
1284 slash1 = strchr(identifier, '/');
1286 ident = strndup(identifier, slash1 - identifier);
1288 slash2 = strchr(slash1 + 1, '/');
1290 mod_dev_after = slash2;
1294 mod_dev_after = slash1 + strlen(slash1);
1298 if (mod_dev_after == slash1 + 1)
1301 mod_dev = strndup(slash1 + 1,
1302 mod_dev_after - (slash1 + 1));
1310 err = get_value(uc_mgr, ident, value, mod_dev, verb, exact);
1311 if (ident != identifier)
1312 free((void *)ident);
1314 free((void *)mod_dev);
1317 pthread_mutex_unlock(&uc_mgr->mutex);
1321 long device_status(snd_use_case_mgr_t *uc_mgr,
1322 const char *device_name)
1324 struct use_case_device *dev;
1325 struct list_head *pos;
1327 list_for_each(pos, &uc_mgr->active_devices) {
1328 dev = list_entry(pos, struct use_case_device, active_list);
1329 if (strcmp(dev->name, device_name) == 0)
1335 long modifier_status(snd_use_case_mgr_t *uc_mgr,
1336 const char *modifier_name)
1338 struct use_case_modifier *mod;
1339 struct list_head *pos;
1341 list_for_each(pos, &uc_mgr->active_modifiers) {
1342 mod = list_entry(pos, struct use_case_modifier, active_list);
1343 if (strcmp(mod->name, modifier_name) == 0)
1351 * \brief Get current - integer
1352 * \param uc_mgr Use case manager
1354 * \return Value if success, otherwise a negative error code
1356 int snd_use_case_geti(snd_use_case_mgr_t *uc_mgr,
1357 const char *identifier,
1363 pthread_mutex_lock(&uc_mgr->mutex);
1365 /* nothing here - prepared for fixed identifiers */
1367 str1 = strchr(identifier, '/');
1369 str = strdup(str1 + 1);
1377 if (check_identifier(identifier, "_devstatus")) {
1378 err = device_status(uc_mgr, str);
1383 } else if (check_identifier(identifier, "_modstatus")) {
1384 err = modifier_status(uc_mgr, str);
1391 * enable this block if the else clause below is expanded to query
1392 * user-supplied values
1394 } else if (identifier[0] == '_')
1403 pthread_mutex_unlock(&uc_mgr->mutex);
1407 static int handle_transition_verb(snd_use_case_mgr_t *uc_mgr,
1408 struct use_case_verb *new_verb)
1410 struct list_head *pos;
1411 struct transition_sequence *trans;
1414 list_for_each(pos, &uc_mgr->active_verb->transition_list) {
1415 trans = list_entry(pos, struct transition_sequence, list);
1416 if (strcmp(trans->name, new_verb->name) == 0) {
1417 err = execute_sequence(uc_mgr, &trans->transition_list,
1418 &uc_mgr->active_verb->value_list,
1419 &uc_mgr->value_list,
1429 static int set_verb_user(snd_use_case_mgr_t *uc_mgr,
1430 const char *verb_name)
1432 struct use_case_verb *verb;
1435 if (uc_mgr->active_verb &&
1436 strcmp(uc_mgr->active_verb->name, verb_name) == 0)
1438 if (strcmp(verb_name, SND_USE_CASE_VERB_INACTIVE) != 0) {
1439 verb = find_verb(uc_mgr, verb_name);
1445 if (uc_mgr->active_verb) {
1446 err = handle_transition_verb(uc_mgr, verb);
1448 err = dismantle_use_case(uc_mgr);
1451 } else if (err == 1) {
1452 uc_mgr->active_verb = verb;
1455 verb = NULL; /* show error */
1459 err = set_verb(uc_mgr, verb, 1);
1461 uc_error("error: failed to initialize new use case: %s",
1468 static int set_device_user(snd_use_case_mgr_t *uc_mgr,
1469 const char *device_name,
1472 struct use_case_device *device;
1474 if (uc_mgr->active_verb == NULL)
1476 device = find_device(uc_mgr, uc_mgr->active_verb, device_name, 1);
1479 return set_device(uc_mgr, device, enable);
1482 static int set_modifier_user(snd_use_case_mgr_t *uc_mgr,
1483 const char *modifier_name,
1486 struct use_case_modifier *modifier;
1488 if (uc_mgr->active_verb == NULL)
1491 modifier = find_modifier(uc_mgr, uc_mgr->active_verb, modifier_name, 1);
1492 if (modifier == NULL)
1494 return set_modifier(uc_mgr, modifier, enable);
1497 static int switch_device(snd_use_case_mgr_t *uc_mgr,
1498 const char *old_device,
1499 const char *new_device)
1501 struct use_case_device *xold, *xnew;
1502 struct transition_sequence *trans;
1503 struct list_head *pos;
1504 int err, seq_found = 0;
1506 if (uc_mgr->active_verb == NULL)
1508 if (device_status(uc_mgr, old_device) == 0) {
1509 uc_error("error: device %s not enabled", old_device);
1512 if (device_status(uc_mgr, new_device) != 0) {
1513 uc_error("error: device %s already enabled", new_device);
1516 xold = find_device(uc_mgr, uc_mgr->active_verb, old_device, 1);
1519 list_del(&xold->active_list);
1520 xnew = find_device(uc_mgr, uc_mgr->active_verb, new_device, 1);
1521 list_add_tail(&xold->active_list, &uc_mgr->active_devices);
1525 list_for_each(pos, &xold->transition_list) {
1526 trans = list_entry(pos, struct transition_sequence, list);
1527 if (strcmp(trans->name, new_device) == 0) {
1528 err = execute_sequence(uc_mgr, &trans->transition_list,
1530 &uc_mgr->active_verb->value_list,
1531 &uc_mgr->value_list);
1533 list_del(&xold->active_list);
1534 list_add_tail(&xnew->active_list, &uc_mgr->active_devices);
1541 err = set_device(uc_mgr, xold, 0);
1544 err = set_device(uc_mgr, xnew, 1);
1551 static int switch_modifier(snd_use_case_mgr_t *uc_mgr,
1552 const char *old_modifier,
1553 const char *new_modifier)
1555 struct use_case_modifier *xold, *xnew;
1556 struct transition_sequence *trans;
1557 struct list_head *pos;
1558 int err, seq_found = 0;
1560 if (uc_mgr->active_verb == NULL)
1562 if (modifier_status(uc_mgr, old_modifier) == 0) {
1563 uc_error("error: modifier %s not enabled", old_modifier);
1566 if (modifier_status(uc_mgr, new_modifier) != 0) {
1567 uc_error("error: modifier %s already enabled", new_modifier);
1570 xold = find_modifier(uc_mgr, uc_mgr->active_verb, old_modifier, 1);
1573 xnew = find_modifier(uc_mgr, uc_mgr->active_verb, new_modifier, 1);
1577 list_for_each(pos, &xold->transition_list) {
1578 trans = list_entry(pos, struct transition_sequence, list);
1579 if (strcmp(trans->name, new_modifier) == 0) {
1580 err = execute_sequence(uc_mgr, &trans->transition_list,
1582 &uc_mgr->active_verb->value_list,
1583 &uc_mgr->value_list);
1585 list_del(&xold->active_list);
1586 list_add_tail(&xnew->active_list, &uc_mgr->active_modifiers);
1593 err = set_modifier(uc_mgr, xold, 0);
1596 err = set_modifier(uc_mgr, xnew, 1);
1605 * \param uc_mgr Use case manager
1607 * \param value Value
1608 * \return Zero if success, otherwise a negative error code
1610 int snd_use_case_set(snd_use_case_mgr_t *uc_mgr,
1611 const char *identifier,
1617 pthread_mutex_lock(&uc_mgr->mutex);
1618 if (strcmp(identifier, "_verb") == 0)
1619 err = set_verb_user(uc_mgr, value);
1620 else if (strcmp(identifier, "_enadev") == 0)
1621 err = set_device_user(uc_mgr, value, 1);
1622 else if (strcmp(identifier, "_disdev") == 0)
1623 err = set_device_user(uc_mgr, value, 0);
1624 else if (strcmp(identifier, "_enamod") == 0)
1625 err = set_modifier_user(uc_mgr, value, 1);
1626 else if (strcmp(identifier, "_dismod") == 0)
1627 err = set_modifier_user(uc_mgr, value, 0);
1629 str1 = strchr(identifier, '/');
1631 str = strdup(str1 + 1);
1639 if (check_identifier(identifier, "_swdev"))
1640 err = switch_device(uc_mgr, str, value);
1641 else if (check_identifier(identifier, "_swmod"))
1642 err = switch_modifier(uc_mgr, str, value);
1649 pthread_mutex_unlock(&uc_mgr->mutex);