• Home
  • History
  • Annotate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/ap/gpl/iserver/alsa-lib-1.0.26/src/ucm/

Lines Matching defs:*

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"
34 #include <ctype.h>
35 #include <stdarg.h>
36 #include <pthread.h>
39 * misc
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)
52 int len;
54 if (strcmp(identifier, prefix) == 0)
55 return 1;
56 len = strlen(prefix);
57 if (memcmp(identifier, prefix, len) == 0 && identifier[len] == '/')
58 return 1;
59 return 0;
62 static int list_count(struct list_head *list)
64 struct list_head *pos;
65 int count = 0;
67 list_for_each(pos, list) {
68 count += 1;
70 return count;
73 static int alloc_str_list(struct list_head *list, int mult, char **result[])
75 char **res;
76 int cnt;
78 cnt = list_count(list) * mult;
79 if (cnt == 0) {
80 *result = NULL;
81 return cnt;
83 res = calloc(mult, cnt * sizeof(char *));
84 if (res == NULL)
85 return -ENOMEM;
86 *result = res;
87 return cnt;
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, ...)
98 char *str, *res;
99 int size = strlen(fmt) + 512;
100 va_list args;
102 str = malloc(size);
103 if (str == NULL)
104 return NULL;
105 va_start(args, fmt);
106 vsnprintf(str, size, fmt, args);
107 va_end(args);
108 str[size-1] = '\0';
109 res = realloc(str, strlen(str) + 1);
110 if (res)
111 return res;
112 return str;
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)
123 int i;
124 if (list == NULL)
125 return 0;
126 for (i = 0; i < items; i++)
127 free((void *)list[i]);
128 free(list);
129 return 0;
132 static int open_ctl(snd_use_case_mgr_t *uc_mgr,
133 snd_ctl_t **ctl,
134 const char *ctl_dev)
136 int err;
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) {
141 *ctl = uc_mgr->ctl;
142 return 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);
150 err = snd_ctl_open(ctl, ctl_dev, 0);
151 if (err < 0)
152 return err;
153 uc_mgr->ctl_dev = strdup(ctl_dev);
154 if (uc_mgr->ctl_dev == NULL) {
155 snd_ctl_close(*ctl);
156 return -ENOMEM;
158 uc_mgr->ctl = *ctl;
159 return 0;
162 extern int __snd_ctl_ascii_elem_id_parse(snd_ctl_elem_id_t *dst,
163 const char *str,
164 const char **ret_ptr);
166 static int execute_cset(snd_ctl_t *ctl, const char *cset)
168 const char *pos;
169 int err;
170 snd_ctl_elem_id_t *id;
171 snd_ctl_elem_value_t *value;
172 snd_ctl_elem_info_t *info;
174 snd_ctl_elem_id_malloc(&id);
175 snd_ctl_elem_value_malloc(&value);
176 snd_ctl_elem_info_malloc(&info);
178 err = __snd_ctl_ascii_elem_id_parse(id, cset, &pos);
179 if (err < 0)
180 goto __fail;
181 while (*pos && isspace(*pos))
182 pos++;
183 if (!*pos) {
184 uc_error("undefined value for cset >%s<", cset);
185 err = -EINVAL;
186 goto __fail;
188 snd_ctl_elem_value_set_id(value, id);
189 snd_ctl_elem_info_set_id(info, id);
190 err = snd_ctl_elem_read(ctl, value);
191 if (err < 0)
192 goto __fail;
193 err = snd_ctl_elem_info(ctl, info);
194 if (err < 0)
195 goto __fail;
196 err = snd_ctl_ascii_value_parse(ctl, value, info, pos);
197 if (err < 0)
198 goto __fail;
199 err = snd_ctl_elem_write(ctl, value);
200 if (err < 0)
201 goto __fail;
202 err = 0;
203 __fail:
204 if (id != NULL)
205 free(id);
206 if (value != NULL)
207 free(value);
208 if (info != NULL)
209 free(info);
211 return err;
215 * \brief Execute the sequence
216 * \param uc_mgr Use case manager
217 * \param seq Sequence
218 * \return zero on success, otherwise a negative error code
220 static int execute_sequence(snd_use_case_mgr_t *uc_mgr,
221 struct list_head *seq,
222 struct list_head *value_list1,
223 struct list_head *value_list2,
224 struct list_head *value_list3)
226 struct list_head *pos;
227 struct sequence_element *s;
228 char *cdev = NULL;
229 snd_ctl_t *ctl = NULL;
230 int err = 0;
232 list_for_each(pos, seq) {
233 s = list_entry(pos, struct sequence_element, list);
234 switch (s->type) {
235 case SEQUENCE_ELEMENT_TYPE_CDEV:
236 cdev = strdup(s->data.cdev);
237 if (cdev == NULL)
238 goto __fail_nomem;
239 break;
240 case SEQUENCE_ELEMENT_TYPE_CSET:
241 if (cdev == NULL) {
242 const char *cdev1 = NULL, *cdev2 = NULL;
243 err = get_value3(&cdev1, "PlaybackCTL",
244 value_list1,
245 value_list2,
246 value_list3);
247 if (err < 0 && err != ENOENT) {
248 uc_error("cdev is not defined!");
249 return err;
251 err = get_value3(&cdev1, "CaptureCTL",
252 value_list1,
253 value_list2,
254 value_list3);
255 if (err < 0 && err != ENOENT) {
256 free((char *)cdev1);
257 uc_error("cdev is not defined!");
258 return err;
260 if (cdev1 == NULL || cdev2 == NULL ||
261 strcmp(cdev1, cdev2) == 0) {
262 cdev = (char *)cdev1;
263 free((char *)cdev2);
264 } else {
265 free((char *)cdev1);
266 free((char *)cdev2);
269 if (ctl == NULL) {
270 err = open_ctl(uc_mgr, &ctl, cdev);
271 if (err < 0) {
272 uc_error("unable to open ctl device '%s'", cdev);
273 goto __fail;
276 err = execute_cset(ctl, s->data.cset);
277 if (err < 0) {
278 uc_error("unable to execute cset '%s'\n", s->data.cset);
279 goto __fail;
281 break;
282 case SEQUENCE_ELEMENT_TYPE_SLEEP:
283 usleep(s->data.sleep);
284 break;
285 case SEQUENCE_ELEMENT_TYPE_EXEC:
286 err = system(s->data.exec);
287 if (err < 0)
288 goto __fail;
289 break;
290 default:
291 uc_error("unknown sequence command %i", s->type);
292 break;
295 free(cdev);
296 return 0;
297 __fail_nomem:
298 err = -ENOMEM;
299 __fail:
300 free(cdev);
301 return err;
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)
312 int err;
314 err = uc_mgr_import_master_config(uc_mgr);
315 if (err < 0)
316 return err;
317 err = execute_sequence(uc_mgr, &uc_mgr->default_list,
318 &uc_mgr->value_list, NULL, NULL);
319 if (err < 0)
320 uc_error("Unable to execute default sequence");
321 return err;
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,
335 const char *match)
337 struct list_head *pos;
338 char *ptr, *str;
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)
344 return ptr;
346 return NULL;
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)
366 char **res;
367 int cnt;
368 struct list_head *pos;
369 char *ptr, *str1;
371 cnt = alloc_str_list(list, 1, &res);
372 if (cnt <= 0) {
373 *result = NULL;
374 return cnt;
376 *result = (const char **)res;
377 list_for_each(pos, list) {
378 ptr = list_entry_offset(pos, char, offset);
379 str1 = *((char **)(ptr + s1offset));
380 if (str1 != NULL) {
381 *res = strdup(str1);
382 if (*res == NULL)
383 goto __fail;
384 } else {
385 *res = NULL;
387 res++;
389 return cnt;
390 __fail:
391 snd_use_case_free_list((const char **)res, cnt);
392 return -ENOMEM;
395 #define get_list(list, result, type, member, s1) \
396 get_list0(list, result, \
397 (unsigned long)(&((type *)0)->member), \
398 (unsigned long)(&((type *)0)->s1))
401 * \brief Universal string list - pair of strings
402 * \param list List of structures
403 * \param result Result list
404 * \param offset Offset of list structure
405 * \param s1offset Offset of string structure
406 * \param s1offset Offset of string structure
407 * \return count of items on success, otherwise a negative error code
409 static int get_list20(struct list_head *list,
410 const char **result[],
411 unsigned long offset,
412 unsigned long s1offset,
413 unsigned long s2offset)
415 char **res;
416 int cnt;
417 struct list_head *pos;
418 char *ptr, *str1, *str2;
420 cnt = alloc_str_list(list, 2, &res);
421 if (cnt <= 0) {
422 *result = NULL;
423 return cnt;
425 *result = (const char **)res;
426 list_for_each(pos, list) {
427 ptr = list_entry_offset(pos, char, offset);
428 str1 = *((char **)(ptr + s1offset));
429 if (str1 != NULL) {
430 *res = strdup(str1);
431 if (*res == NULL)
432 goto __fail;
433 } else {
434 *res = NULL;
436 res++;
437 str2 = *((char **)(ptr + s2offset));
438 if (str2 != NULL) {
439 *res = strdup(str2);
440 if (*res == NULL)
441 goto __fail;
442 } else {
443 *res = NULL;
445 res++;
447 return cnt;
448 __fail:
449 snd_use_case_free_list((const char **)res, cnt);
450 return -ENOMEM;
453 #define get_list2(list, result, type, member, s1, s2) \
454 get_list20(list, result, \
455 (unsigned long)(&((type *)0)->member), \
456 (unsigned long)(&((type *)0)->s1), \
457 (unsigned long)(&((type *)0)->s2))
460 * \brief Find verb
461 * \param uc_mgr Use case manager
462 * \param verb_name verb to find
463 * \return structure on success, otherwise a NULL (not found)
465 static inline struct use_case_verb *find_verb(snd_use_case_mgr_t *uc_mgr,
466 const char *verb_name)
468 return find(&uc_mgr->verb_list,
469 struct use_case_verb, list, name,
470 verb_name);
473 static int is_devlist_supported(snd_use_case_mgr_t *uc_mgr,
474 struct dev_list *dev_list)
476 struct dev_list_node *device;
477 struct use_case_device *adev;
478 struct list_head *pos, *pos1;
479 int found_ret;
481 switch (dev_list->type) {
482 case DEVLIST_NONE:
483 default:
484 return 1;
485 case DEVLIST_SUPPORTED:
486 found_ret = 1;
487 break;
488 case DEVLIST_CONFLICTING:
489 found_ret = 0;
490 break;
493 list_for_each(pos, &dev_list->list) {
494 device = list_entry(pos, struct dev_list_node, list);
496 list_for_each(pos1, &uc_mgr->active_devices) {
497 adev = list_entry(pos1, struct use_case_device,
498 active_list);
499 if (!strcmp(device->name, adev->name))
500 return found_ret;
503 return 1 - found_ret;
506 static inline int is_modifier_supported(snd_use_case_mgr_t *uc_mgr,
507 struct use_case_modifier *modifier)
509 return is_devlist_supported(uc_mgr, &modifier->dev_list);
512 static inline int is_device_supported(snd_use_case_mgr_t *uc_mgr,
513 struct use_case_device *device)
515 return is_devlist_supported(uc_mgr, &device->dev_list);
519 * \brief Find device
520 * \param verb Use case verb
521 * \param device_name device to find
522 * \return structure on success, otherwise a NULL (not found)
524 static inline struct use_case_device *
525 find_device(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb,
526 const char *device_name, int check_supported)
528 struct use_case_device *device;
529 struct list_head *pos;
531 list_for_each(pos, &verb->device_list) {
532 device = list_entry(pos, struct use_case_device, list);
534 if (strcmp(device_name, device->name))
535 continue;
537 if (check_supported &&
538 !is_device_supported(uc_mgr, device))
539 continue;
541 return device;
543 return NULL;
547 * \brief Find modifier
548 * \param verb Use case verb
549 * \param modifier_name modifier to find
550 * \return structure on success, otherwise a NULL (not found)
552 static struct use_case_modifier *
553 find_modifier(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb,
554 const char *modifier_name, int check_supported)
556 struct use_case_modifier *modifier;
557 struct list_head *pos;
559 list_for_each(pos, &verb->modifier_list) {
560 modifier = list_entry(pos, struct use_case_modifier, list);
562 if (strcmp(modifier->name, modifier_name))
563 continue;
565 if (check_supported &&
566 !is_modifier_supported(uc_mgr, modifier))
567 continue;
569 return modifier;
571 return NULL;
574 long device_status(snd_use_case_mgr_t *uc_mgr,
575 const char *device_name)
577 struct use_case_device *dev;
578 struct list_head *pos;
580 list_for_each(pos, &uc_mgr->active_devices) {
581 dev = list_entry(pos, struct use_case_device, active_list);
582 if (strcmp(dev->name, device_name) == 0)
583 return 1;
585 return 0;
588 long modifier_status(snd_use_case_mgr_t *uc_mgr,
589 const char *modifier_name)
591 struct use_case_modifier *mod;
592 struct list_head *pos;
594 list_for_each(pos, &uc_mgr->active_modifiers) {
595 mod = list_entry(pos, struct use_case_modifier, active_list);
596 if (strcmp(mod->name, modifier_name) == 0)
597 return 1;
599 return 0;
603 * \brief Set verb
604 * \param uc_mgr Use case manager
605 * \param verb verb to set
606 * \param enable nonzero = enable, zero = disable
607 * \return zero on success, otherwise a negative error code
609 static int set_verb(snd_use_case_mgr_t *uc_mgr,
610 struct use_case_verb *verb,
611 int enable)
613 struct list_head *seq;
614 int err;
616 if (enable) {
617 seq = &verb->enable_list;
618 } else {
619 seq = &verb->disable_list;
621 err = execute_sequence(uc_mgr, seq,
622 &verb->value_list,
623 &uc_mgr->value_list,
624 NULL);
625 if (enable && err >= 0)
626 uc_mgr->active_verb = verb;
627 return err;
631 * \brief Set modifier
632 * \param uc_mgr Use case manager
633 * \param modifier modifier to set
634 * \param enable nonzero = enable, zero = disable
635 * \return zero on success, otherwise a negative error code
637 static int set_modifier(snd_use_case_mgr_t *uc_mgr,
638 struct use_case_modifier *modifier,
639 int enable)
641 struct list_head *seq;
642 int err;
644 if (modifier_status(uc_mgr, modifier->name) == enable)
645 return 0;
647 if (enable) {
648 seq = &modifier->enable_list;
649 } else {
650 seq = &modifier->disable_list;
652 err = execute_sequence(uc_mgr, seq,
653 &modifier->value_list,
654 &uc_mgr->active_verb->value_list,
655 &uc_mgr->value_list);
656 if (enable && err >= 0) {
657 list_add_tail(&modifier->active_list, &uc_mgr->active_modifiers);
658 } else if (!enable) {
659 list_del(&modifier->active_list);
661 return err;
665 * \brief Set device
666 * \param uc_mgr Use case manager
667 * \param device device to set
668 * \param enable nonzero = enable, zero = disable
669 * \return zero on success, otherwise a negative error code
671 static int set_device(snd_use_case_mgr_t *uc_mgr,
672 struct use_case_device *device,
673 int enable)
675 struct list_head *seq;
676 int err;
678 if (device_status(uc_mgr, device->name) == enable)
679 return 0;
681 if (enable) {
682 seq = &device->enable_list;
683 } else {
684 seq = &device->disable_list;
686 err = execute_sequence(uc_mgr, seq,
687 &device->value_list,
688 &uc_mgr->active_verb->value_list,
689 &uc_mgr->value_list);
690 if (enable && err >= 0) {
691 list_add_tail(&device->active_list, &uc_mgr->active_devices);
692 } else if (!enable) {
693 list_del(&device->active_list);
695 return err;
699 * \brief Init sound card use case manager.
700 * \param uc_mgr Returned use case manager pointer
701 * \param card_name name of card to open
702 * \return zero on success, otherwise a negative error code
704 int snd_use_case_mgr_open(snd_use_case_mgr_t **mgr,
705 const char *card_name)
707 snd_use_case_mgr_t *uc_mgr;
708 int err;
710 /* create a new UCM */
711 uc_mgr = calloc(1, sizeof(snd_use_case_mgr_t));
712 if (uc_mgr == NULL)
713 return -ENOMEM;
714 INIT_LIST_HEAD(&uc_mgr->verb_list);
715 INIT_LIST_HEAD(&uc_mgr->default_list);
716 INIT_LIST_HEAD(&uc_mgr->value_list);
717 INIT_LIST_HEAD(&uc_mgr->active_modifiers);
718 INIT_LIST_HEAD(&uc_mgr->active_devices);
719 pthread_mutex_init(&uc_mgr->mutex, NULL);
721 uc_mgr->card_name = strdup(card_name);
722 if (uc_mgr->card_name == NULL) {
723 free(uc_mgr);
724 return -ENOMEM;
727 /* get info on use_cases and verify against card */
728 err = import_master_config(uc_mgr);
729 if (err < 0) {
730 uc_error("error: failed to import %s use case configuration %d",
731 card_name, err);
732 goto err;
735 *mgr = uc_mgr;
736 return 0;
738 err:
739 uc_mgr_free(uc_mgr);
740 return err;
744 * \brief Reload and reparse all use case files.
745 * \param uc_mgr Use case manager
746 * \return zero on success, otherwise a negative error code
748 int snd_use_case_mgr_reload(snd_use_case_mgr_t *uc_mgr)
750 int err;
752 pthread_mutex_lock(&uc_mgr->mutex);
754 uc_mgr_free_verb(uc_mgr);
756 /* reload all use cases */
757 err = import_master_config(uc_mgr);
758 if (err < 0) {
759 uc_error("error: failed to reload use cases\n");
760 pthread_mutex_unlock(&uc_mgr->mutex);
761 return -EINVAL;
764 pthread_mutex_unlock(&uc_mgr->mutex);
765 return err;
769 * \brief Close use case manager.
770 * \param uc_mgr Use case manager
771 * \return zero on success, otherwise a negative error code
773 int snd_use_case_mgr_close(snd_use_case_mgr_t *uc_mgr)
775 uc_mgr_free(uc_mgr);
777 return 0;
781 * Tear down current use case verb, device and modifier.
783 static int dismantle_use_case(snd_use_case_mgr_t *uc_mgr)
785 struct list_head *pos, *npos;
786 struct use_case_modifier *modifier;
787 struct use_case_device *device;
788 int err;
790 list_for_each_safe(pos, npos, &uc_mgr->active_modifiers) {
791 modifier = list_entry(pos, struct use_case_modifier,
792 active_list);
793 err = set_modifier(uc_mgr, modifier, 0);
794 if (err < 0)
795 uc_error("Unable to disable modifier %s", modifier->name);
797 INIT_LIST_HEAD(&uc_mgr->active_modifiers);
799 list_for_each_safe(pos, npos, &uc_mgr->active_devices) {
800 device = list_entry(pos, struct use_case_device,
801 active_list);
802 err = set_device(uc_mgr, device, 0);
803 if (err < 0)
804 uc_error("Unable to disable device %s", device->name);
806 INIT_LIST_HEAD(&uc_mgr->active_devices);
808 err = set_verb(uc_mgr, uc_mgr->active_verb, 0);
809 if (err < 0) {
810 uc_error("Unable to disable verb %s", uc_mgr->active_verb->name);
811 return err;
813 uc_mgr->active_verb = NULL;
815 err = execute_sequence(uc_mgr, &uc_mgr->default_list,
816 &uc_mgr->value_list, NULL, NULL);
818 return err;
822 * \brief Reset sound card controls to default values.
823 * \param uc_mgr Use case manager
824 * \return zero on success, otherwise a negative error code
826 int snd_use_case_mgr_reset(snd_use_case_mgr_t *uc_mgr)
828 int err;
830 pthread_mutex_lock(&uc_mgr->mutex);
831 err = execute_sequence(uc_mgr, &uc_mgr->default_list,
832 &uc_mgr->value_list, NULL, NULL);
833 INIT_LIST_HEAD(&uc_mgr->active_modifiers);
834 INIT_LIST_HEAD(&uc_mgr->active_devices);
835 uc_mgr->active_verb = NULL;
836 pthread_mutex_unlock(&uc_mgr->mutex);
837 return err;
841 * \brief Get list of verbs in pair verbname+comment
842 * \param list Returned list
843 * \param verbname For verb (NULL = current)
844 * \return Number of list entries if success, otherwise a negative error code
846 static int get_verb_list(snd_use_case_mgr_t *uc_mgr, const char **list[])
848 return get_list2(&uc_mgr->verb_list, list,
849 struct use_case_verb, list,
850 name, comment);
854 * \brief Get list of devices in pair devicename+comment
855 * \param list Returned list
856 * \param verbname For verb (NULL = current)
857 * \return Number of list entries if success, otherwise a negative error code
859 static int get_device_list(snd_use_case_mgr_t *uc_mgr, const char **list[],
860 char *verbname)
862 struct use_case_verb *verb;
864 if (verbname) {
865 verb = find_verb(uc_mgr, verbname);
866 } else {
867 verb = uc_mgr->active_verb;
869 if (verb == NULL)
870 return -ENOENT;
871 return get_list2(&verb->device_list, list,
872 struct use_case_device, list,
873 name, comment);
877 * \brief Get list of modifiers in pair devicename+comment
878 * \param list Returned list
879 * \param verbname For verb (NULL = current)
880 * \return Number of list entries if success, otherwise a negative error code
882 static int get_modifier_list(snd_use_case_mgr_t *uc_mgr, const char **list[],
883 char *verbname)
885 struct use_case_verb *verb;
887 if (verbname) {
888 verb = find_verb(uc_mgr, verbname);
889 } else {
890 verb = uc_mgr->active_verb;
892 if (verb == NULL)
893 return -ENOENT;
894 return get_list2(&verb->modifier_list, list,
895 struct use_case_modifier, list,
896 name, comment);
900 * \brief Get list of supported/conflicting devices
901 * \param list Returned list
902 * \param name Name of modifier or verb to query
903 * \param type Type of device list entries to return
904 * \return Number of list entries if success, otherwise a negative error code
906 static int get_supcon_device_list(snd_use_case_mgr_t *uc_mgr,
907 const char **list[], char *name,
908 enum dev_list_type type)
910 char *str;
911 struct use_case_verb *verb;
912 struct use_case_modifier *modifier;
913 struct use_case_device *device;
915 if (!name)
916 return -ENOENT;
918 str = strchr(name, '/');
919 if (str) {
920 *str = '\0';
921 verb = find_verb(uc_mgr, str + 1);
923 else {
924 verb = uc_mgr->active_verb;
926 if (!verb)
927 return -ENOENT;
929 modifier = find_modifier(uc_mgr, verb, name, 0);
930 if (modifier) {
931 if (modifier->dev_list.type != type)
932 return 0;
933 return get_list(&modifier->dev_list.list, list,
934 struct dev_list_node, list,
935 name);
938 device = find_device(uc_mgr, verb, name, 0);
939 if (device) {
940 if (device->dev_list.type != type)
941 return 0;
942 return get_list(&device->dev_list.list, list,
943 struct dev_list_node, list,
944 name);
947 return -ENOENT;
952 * \brief Get list of supported devices
953 * \param list Returned list
954 * \param name Name of verb or modifier to query
955 * \return Number of list entries if success, otherwise a negative error code
957 static int get_supported_device_list(snd_use_case_mgr_t *uc_mgr,
958 const char **list[], char *name)
960 return get_supcon_device_list(uc_mgr, list, name, DEVLIST_SUPPORTED);
964 * \brief Get list of conflicting devices
965 * \param list Returned list
966 * \param name Name of verb or modifier to query
967 * \return Number of list entries if success, otherwise a negative error code
969 static int get_conflicting_device_list(snd_use_case_mgr_t *uc_mgr,
970 const char **list[], char *name)
972 return get_supcon_device_list(uc_mgr, list, name, DEVLIST_CONFLICTING);
975 struct myvalue {
976 struct list_head list;
977 char *value;
980 static int add_values(struct list_head *list,
981 const char *identifier,
982 struct list_head *source)
984 struct ucm_value *v;
985 struct myvalue *val;
986 struct list_head *pos, *pos1;
987 int match;
989 list_for_each(pos, source) {
990 v = list_entry(pos, struct ucm_value, list);
991 if (check_identifier(identifier, v->name)) {
992 match = 0;
993 list_for_each(pos1, list) {
994 val = list_entry(pos1, struct myvalue, list);
995 if (strcmp(val->value, v->data) == 0) {
996 match = 1;
997 break;
1000 if (!match) {
1001 val = malloc(sizeof(struct myvalue));
1002 if (val == NULL)
1003 return -ENOMEM;
1004 val->value = v->data;
1005 list_add_tail(&val->list, list);
1009 return 0;
1013 * \brief Get list of values
1014 * \param list Returned list
1015 * \param verbname For verb (NULL = current)
1016 * \return Number of list entries if success, otherwise a negative error code
1018 static int get_value_list(snd_use_case_mgr_t *uc_mgr,
1019 const char *identifier,
1020 const char **list[],
1021 char *verbname)
1023 struct list_head mylist, *pos, *npos;
1024 struct myvalue *val;
1025 struct use_case_verb *verb;
1026 struct use_case_device *dev;
1027 struct use_case_modifier *mod;
1028 char **res;
1029 int err;
1031 if (verbname) {
1032 verb = find_verb(uc_mgr, verbname);
1033 } else {
1034 verb = uc_mgr->active_verb;
1036 if (verb == NULL)
1037 return -ENOENT;
1038 INIT_LIST_HEAD(&mylist);
1039 err = add_values(&mylist, identifier, &uc_mgr->value_list);
1040 if (err < 0)
1041 goto __fail;
1042 err = add_values(&mylist, identifier, &verb->value_list);
1043 if (err < 0)
1044 goto __fail;
1045 list_for_each(pos, &verb->device_list) {
1046 dev = list_entry(pos, struct use_case_device, list);
1047 err = add_values(&mylist, identifier, &dev->value_list);
1048 if (err < 0)
1049 goto __fail;
1051 list_for_each(pos, &verb->modifier_list) {
1052 mod = list_entry(pos, struct use_case_modifier, list);
1053 err = add_values(&mylist, identifier, &mod->value_list);
1054 if (err < 0)
1055 goto __fail;
1057 err = alloc_str_list(&mylist, 1, &res);
1058 if (err >= 0) {
1059 *list = (const char **)res;
1060 list_for_each(pos, &mylist) {
1061 val = list_entry(pos, struct myvalue, list);
1062 *res = strdup(val->value);
1063 if (*res == NULL) {
1064 snd_use_case_free_list((const char **)res, err);
1065 err = -ENOMEM;
1066 goto __fail;
1068 res++;
1071 __fail:
1072 list_for_each_safe(pos, npos, &mylist) {
1073 val = list_entry(pos, struct myvalue, list);
1074 list_del(&val->list);
1075 free(val);
1077 return err;
1081 * \brief Get list of enabled devices
1082 * \param list Returned list
1083 * \param verbname For verb (NULL = current)
1084 * \return Number of list entries if success, otherwise a negative error code
1086 static int get_enabled_device_list(snd_use_case_mgr_t *uc_mgr,
1087 const char **list[])
1089 if (uc_mgr->active_verb == NULL)
1090 return -EINVAL;
1091 return get_list(&uc_mgr->active_devices, list,
1092 struct use_case_device, active_list,
1093 name);
1097 * \brief Get list of enabled modifiers
1098 * \param list Returned list
1099 * \param verbname For verb (NULL = current)
1100 * \return Number of list entries if success, otherwise a negative error code
1102 static int get_enabled_modifier_list(snd_use_case_mgr_t *uc_mgr,
1103 const char **list[])
1105 if (uc_mgr->active_verb == NULL)
1106 return -EINVAL;
1107 return get_list(&uc_mgr->active_modifiers, list,
1108 struct use_case_modifier, active_list,
1109 name);
1113 * \brief Obtain a list of entries
1114 * \param uc_mgr Use case manager (may be NULL - card list)
1115 * \param identifier (may be NULL - card list)
1116 * \param list Returned allocated list
1117 * \return Number of list entries if success, otherwise a negative error code
1119 int snd_use_case_get_list(snd_use_case_mgr_t *uc_mgr,
1120 const char *identifier,
1121 const char **list[])
1123 char *str, *str1;
1124 int err;
1126 if (uc_mgr == NULL || identifier == NULL)
1127 return uc_mgr_scan_master_configs(list);
1128 pthread_mutex_lock(&uc_mgr->mutex);
1129 if (strcmp(identifier, "_verbs") == 0)
1130 err = get_verb_list(uc_mgr, list);
1131 else if (strcmp(identifier, "_enadevs") == 0)
1132 err = get_enabled_device_list(uc_mgr, list);
1133 else if (strcmp(identifier, "_enamods") == 0)
1134 err = get_enabled_modifier_list(uc_mgr, list);
1135 else {
1136 str1 = strchr(identifier, '/');
1137 if (str1) {
1138 str = strdup(str1 + 1);
1139 if (str == NULL) {
1140 err = -ENOMEM;
1141 goto __end;
1143 } else {
1144 str = NULL;
1146 if (check_identifier(identifier, "_devices"))
1147 err = get_device_list(uc_mgr, list, str);
1148 else if (check_identifier(identifier, "_modifiers"))
1149 err = get_modifier_list(uc_mgr, list, str);
1150 else if (check_identifier(identifier, "_supporteddevs"))
1151 err = get_supported_device_list(uc_mgr, list, str);
1152 else if (check_identifier(identifier, "_conflictingdevs"))
1153 err = get_conflicting_device_list(uc_mgr, list, str);
1154 else if (identifier[0] == '_')
1155 err = -ENOENT;
1156 else
1157 err = get_value_list(uc_mgr, identifier, list, str);
1158 if (str)
1159 free(str);
1161 __end:
1162 pthread_mutex_unlock(&uc_mgr->mutex);
1163 return err;
1166 static int get_value1(const char **value, struct list_head *value_list,
1167 const char *identifier)
1169 struct ucm_value *val;
1170 struct list_head *pos;
1172 if (!value_list)
1173 return -ENOENT;
1175 list_for_each(pos, value_list) {
1176 val = list_entry(pos, struct ucm_value, list);
1177 if (check_identifier(identifier, val->name)) {
1178 *value = strdup(val->data);
1179 if (*value == NULL)
1180 return -ENOMEM;
1181 return 0;
1184 return -ENOENT;
1187 static int get_value3(const char **value,
1188 const char *identifier,
1189 struct list_head *value_list1,
1190 struct list_head *value_list2,
1191 struct list_head *value_list3)
1193 int err;
1195 err = get_value1(value, value_list1, identifier);
1196 if (err >= 0 || err != -ENOENT)
1197 return err;
1198 err = get_value1(value, value_list2, identifier);
1199 if (err >= 0 || err != -ENOENT)
1200 return err;
1201 err = get_value1(value, value_list3, identifier);
1202 if (err >= 0 || err != -ENOENT)
1203 return err;
1204 return -ENOENT;
1208 * \brief Get value
1209 * \param uc_mgr Use case manager
1210 * \param identifier Value identifier (string)
1211 * \param value Returned value string
1212 * \param item Modifier or Device name (string)
1213 * \return Zero on success (value is filled), otherwise a negative error code
1215 static int get_value(snd_use_case_mgr_t *uc_mgr,
1216 const char *identifier,
1217 const char **value,
1218 const char *mod_dev_name,
1219 const char *verb_name,
1220 int exact)
1222 struct use_case_verb *verb;
1223 struct use_case_modifier *mod;
1224 struct use_case_device *dev;
1225 int err;
1227 if (mod_dev_name || verb_name || !exact) {
1228 if (verb_name && strlen(verb_name)) {
1229 verb = find_verb(uc_mgr, verb_name);
1230 } else {
1231 verb = uc_mgr->active_verb;
1233 if (verb) {
1234 if (mod_dev_name) {
1235 mod = find_modifier(uc_mgr, verb,
1236 mod_dev_name, 0);
1237 if (mod) {
1238 err = get_value1(value,
1239 &mod->value_list,
1240 identifier);
1241 if (err >= 0 || err != -ENOENT)
1242 return err;
1245 dev = find_device(uc_mgr, verb,
1246 mod_dev_name, 0);
1247 if (dev) {
1248 err = get_value1(value,
1249 &dev->value_list,
1250 identifier);
1251 if (err >= 0 || err != -ENOENT)
1252 return err;
1255 if (exact)
1256 return -ENOENT;
1259 err = get_value1(value, &verb->value_list, identifier);
1260 if (err >= 0 || err != -ENOENT)
1261 return err;
1264 if (exact)
1265 return -ENOENT;
1268 err = get_value1(value, &uc_mgr->value_list, identifier);
1269 if (err >= 0 || err != -ENOENT)
1270 return err;
1272 return -ENOENT;
1276 * \brief Get current - string
1277 * \param uc_mgr Use case manager
1278 * \param identifier
1279 * \param value Value pointer
1280 * \return Zero if success, otherwise a negative error code
1282 * Note: String is dynamically allocated, use free() to
1283 * deallocate this string.
1285 int snd_use_case_get(snd_use_case_mgr_t *uc_mgr,
1286 const char *identifier,
1287 const char **value)
1289 const char *slash1, *slash2, *mod_dev_after;
1290 const char *ident, *mod_dev, *verb;
1291 int exact = 0;
1292 int err;
1294 pthread_mutex_lock(&uc_mgr->mutex);
1295 if (identifier == NULL) {
1296 *value = strdup(uc_mgr->card_name);
1297 if (*value == NULL) {
1298 err = -ENOMEM;
1299 goto __end;
1301 err = 0;
1302 } else if (strcmp(identifier, "_verb") == 0) {
1303 if (uc_mgr->active_verb == NULL) {
1304 err = -ENOENT;
1305 goto __end;
1307 *value = strdup(uc_mgr->active_verb->name);
1308 if (*value == NULL) {
1309 err = -ENOMEM;
1310 goto __end;
1312 err = 0;
1313 } else if (identifier[0] == '_') {
1314 err = -ENOENT;
1315 goto __end;
1316 } else {
1317 if (identifier[0] == '=') {
1318 exact = 1;
1319 identifier++;
1322 slash1 = strchr(identifier, '/');
1323 if (slash1) {
1324 ident = strndup(identifier, slash1 - identifier);
1326 slash2 = strchr(slash1 + 1, '/');
1327 if (slash2) {
1328 mod_dev_after = slash2;
1329 verb = slash2 + 1;
1331 else {
1332 mod_dev_after = slash1 + strlen(slash1);
1333 verb = NULL;
1336 if (mod_dev_after == slash1 + 1)
1337 mod_dev = NULL;
1338 else
1339 mod_dev = strndup(slash1 + 1,
1340 mod_dev_after - (slash1 + 1));
1342 else {
1343 ident = identifier;
1344 mod_dev = NULL;
1345 verb = NULL;
1348 err = get_value(uc_mgr, ident, value, mod_dev, verb, exact);
1349 if (ident != identifier)
1350 free((void *)ident);
1351 if (mod_dev)
1352 free((void *)mod_dev);
1354 __end:
1355 pthread_mutex_unlock(&uc_mgr->mutex);
1356 return err;
1361 * \brief Get current - integer
1362 * \param uc_mgr Use case manager
1363 * \param identifier
1364 * \return Value if success, otherwise a negative error code
1366 int snd_use_case_geti(snd_use_case_mgr_t *uc_mgr,
1367 const char *identifier,
1368 long *value)
1370 char *str, *str1;
1371 long err;
1373 pthread_mutex_lock(&uc_mgr->mutex);
1374 if (0) {
1375 /* nothing here - prepared for fixed identifiers */
1376 } else {
1377 str1 = strchr(identifier, '/');
1378 if (str1) {
1379 str = strdup(str1 + 1);
1380 if (str == NULL) {
1381 err = -ENOMEM;
1382 goto __end;
1384 } else {
1385 str = NULL;
1387 if (check_identifier(identifier, "_devstatus")) {
1388 err = device_status(uc_mgr, str);
1389 if (err >= 0) {
1390 *value = err;
1391 err = 0;
1393 } else if (check_identifier(identifier, "_modstatus")) {
1394 err = modifier_status(uc_mgr, str);
1395 if (err >= 0) {
1396 *value = err;
1397 err = 0;
1399 #if 0
1401 * enable this block if the else clause below is expanded to query
1402 * user-supplied values
1404 } else if (identifier[0] == '_')
1405 err = -ENOENT;
1406 #endif
1407 } else
1408 err = -ENOENT;
1409 if (str)
1410 free(str);
1412 __end:
1413 pthread_mutex_unlock(&uc_mgr->mutex);
1414 return err;
1417 static int handle_transition_verb(snd_use_case_mgr_t *uc_mgr,
1418 struct use_case_verb *new_verb)
1420 struct list_head *pos;
1421 struct transition_sequence *trans;
1422 int err;
1424 list_for_each(pos, &uc_mgr->active_verb->transition_list) {
1425 trans = list_entry(pos, struct transition_sequence, list);
1426 if (strcmp(trans->name, new_verb->name) == 0) {
1427 err = execute_sequence(uc_mgr, &trans->transition_list,
1428 &uc_mgr->active_verb->value_list,
1429 &uc_mgr->value_list,
1430 NULL);
1431 if (err >= 0)
1432 return 1;
1433 return err;
1436 return 0;
1439 static int set_verb_user(snd_use_case_mgr_t *uc_mgr,
1440 const char *verb_name)
1442 struct use_case_verb *verb;
1443 int err;
1445 if (uc_mgr->active_verb &&
1446 strcmp(uc_mgr->active_verb->name, verb_name) == 0)
1447 return 0;
1448 if (strcmp(verb_name, SND_USE_CASE_VERB_INACTIVE) != 0) {
1449 verb = find_verb(uc_mgr, verb_name);
1450 if (verb == NULL)
1451 return -ENOENT;
1452 } else {
1453 verb = NULL;
1455 if (uc_mgr->active_verb) {
1456 err = handle_transition_verb(uc_mgr, verb);
1457 if (err == 0) {
1458 err = dismantle_use_case(uc_mgr);
1459 if (err < 0)
1460 return err;
1461 } else if (err == 1) {
1462 uc_mgr->active_verb = verb;
1463 verb = NULL;
1464 } else {
1465 verb = NULL; /* show error */
1468 if (verb) {
1469 err = set_verb(uc_mgr, verb, 1);
1470 if (err < 0)
1471 uc_error("error: failed to initialize new use case: %s",
1472 verb_name);
1474 return err;
1478 static int set_device_user(snd_use_case_mgr_t *uc_mgr,
1479 const char *device_name,
1480 int enable)
1482 struct use_case_device *device;
1484 if (uc_mgr->active_verb == NULL)
1485 return -ENOENT;
1486 device = find_device(uc_mgr, uc_mgr->active_verb, device_name, 1);
1487 if (device == NULL)
1488 return -ENOENT;
1489 return set_device(uc_mgr, device, enable);
1492 static int set_modifier_user(snd_use_case_mgr_t *uc_mgr,
1493 const char *modifier_name,
1494 int enable)
1496 struct use_case_modifier *modifier;
1498 if (uc_mgr->active_verb == NULL)
1499 return -ENOENT;
1501 modifier = find_modifier(uc_mgr, uc_mgr->active_verb, modifier_name, 1);
1502 if (modifier == NULL)
1503 return -ENOENT;
1504 return set_modifier(uc_mgr, modifier, enable);
1507 static int switch_device(snd_use_case_mgr_t *uc_mgr,
1508 const char *old_device,
1509 const char *new_device)
1511 struct use_case_device *xold, *xnew;
1512 struct transition_sequence *trans;
1513 struct list_head *pos;
1514 int err, seq_found = 0;
1516 if (uc_mgr->active_verb == NULL)
1517 return -ENOENT;
1518 if (device_status(uc_mgr, old_device) == 0) {
1519 uc_error("error: device %s not enabled", old_device);
1520 return -EINVAL;
1522 if (device_status(uc_mgr, new_device) != 0) {
1523 uc_error("error: device %s already enabled", new_device);
1524 return -EINVAL;
1526 xold = find_device(uc_mgr, uc_mgr->active_verb, old_device, 1);
1527 if (xold == NULL)
1528 return -ENOENT;
1529 list_del(&xold->active_list);
1530 xnew = find_device(uc_mgr, uc_mgr->active_verb, new_device, 1);
1531 list_add_tail(&xold->active_list, &uc_mgr->active_devices);
1532 if (xnew == NULL)
1533 return -ENOENT;
1534 err = 0;
1535 list_for_each(pos, &xold->transition_list) {
1536 trans = list_entry(pos, struct transition_sequence, list);
1537 if (strcmp(trans->name, new_device) == 0) {
1538 err = execute_sequence(uc_mgr, &trans->transition_list,
1539 &xold->value_list,
1540 &uc_mgr->active_verb->value_list,
1541 &uc_mgr->value_list);
1542 if (err >= 0) {
1543 list_del(&xold->active_list);
1544 list_add_tail(&xnew->active_list, &uc_mgr->active_devices);
1546 seq_found = 1;
1547 break;
1550 if (!seq_found) {
1551 err = set_device(uc_mgr, xold, 0);
1552 if (err < 0)
1553 return err;
1554 err = set_device(uc_mgr, xnew, 1);
1555 if (err < 0)
1556 return err;
1558 return err;
1561 static int switch_modifier(snd_use_case_mgr_t *uc_mgr,
1562 const char *old_modifier,
1563 const char *new_modifier)
1565 struct use_case_modifier *xold, *xnew;
1566 struct transition_sequence *trans;
1567 struct list_head *pos;
1568 int err, seq_found = 0;
1570 if (uc_mgr->active_verb == NULL)
1571 return -ENOENT;
1572 if (modifier_status(uc_mgr, old_modifier) == 0) {
1573 uc_error("error: modifier %s not enabled", old_modifier);
1574 return -EINVAL;
1576 if (modifier_status(uc_mgr, new_modifier) != 0) {
1577 uc_error("error: modifier %s already enabled", new_modifier);
1578 return -EINVAL;
1580 xold = find_modifier(uc_mgr, uc_mgr->active_verb, old_modifier, 1);
1581 if (xold == NULL)
1582 return -ENOENT;
1583 xnew = find_modifier(uc_mgr, uc_mgr->active_verb, new_modifier, 1);
1584 if (xnew == NULL)
1585 return -ENOENT;
1586 err = 0;
1587 list_for_each(pos, &xold->transition_list) {
1588 trans = list_entry(pos, struct transition_sequence, list);
1589 if (strcmp(trans->name, new_modifier) == 0) {
1590 err = execute_sequence(uc_mgr, &trans->transition_list,
1591 &xold->value_list,
1592 &uc_mgr->active_verb->value_list,
1593 &uc_mgr->value_list);
1594 if (err >= 0) {
1595 list_del(&xold->active_list);
1596 list_add_tail(&xnew->active_list, &uc_mgr->active_modifiers);
1598 seq_found = 1;
1599 break;
1602 if (!seq_found) {
1603 err = set_modifier(uc_mgr, xold, 0);
1604 if (err < 0)
1605 return err;
1606 err = set_modifier(uc_mgr, xnew, 1);
1607 if (err < 0)
1608 return err;
1610 return err;
1614 * \brief Set new
1615 * \param uc_mgr Use case manager
1616 * \param identifier
1617 * \param value Value
1618 * \return Zero if success, otherwise a negative error code
1620 int snd_use_case_set(snd_use_case_mgr_t *uc_mgr,
1621 const char *identifier,
1622 const char *value)
1624 char *str, *str1;
1625 int err;
1627 pthread_mutex_lock(&uc_mgr->mutex);
1628 if (strcmp(identifier, "_verb") == 0)
1629 err = set_verb_user(uc_mgr, value);
1630 else if (strcmp(identifier, "_enadev") == 0)
1631 err = set_device_user(uc_mgr, value, 1);
1632 else if (strcmp(identifier, "_disdev") == 0)
1633 err = set_device_user(uc_mgr, value, 0);
1634 else if (strcmp(identifier, "_enamod") == 0)
1635 err = set_modifier_user(uc_mgr, value, 1);
1636 else if (strcmp(identifier, "_dismod") == 0)
1637 err = set_modifier_user(uc_mgr, value, 0);
1638 else {
1639 str1 = strchr(identifier, '/');
1640 if (str1) {
1641 str = strdup(str1 + 1);
1642 if (str == NULL) {
1643 err = -ENOMEM;
1644 goto __end;
1646 } else {
1647 str = NULL;
1649 if (check_identifier(identifier, "_swdev"))
1650 err = switch_device(uc_mgr, str, value);
1651 else if (check_identifier(identifier, "_swmod"))
1652 err = switch_modifier(uc_mgr, str, value);
1653 else
1654 err = -EINVAL;
1655 if (str)
1656 free(str);
1658 __end:
1659 pthread_mutex_unlock(&uc_mgr->mutex);
1660 return err;