0494728271210ab13dffe4d2f87af0b8a664de5c
[platform/upstream/alsa-lib.git] / src / ucm / main.c
1 /*
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.
6  *
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.
11  *
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
15  *
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.
22  *
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>
31  */
32
33 #include "ucm_local.h"
34 #include <ctype.h>
35 #include <stdarg.h>
36 #include <pthread.h>
37
38 /*
39  * misc
40  */
41
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);
49
50 static int check_identifier(const char *identifier, const char *prefix)
51 {
52         int len;
53
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;
60 }
61
62 static int list_count(struct list_head *list)
63 {
64         struct list_head *pos;
65         int count = 0;
66         
67         list_for_each(pos, list) {
68                 count += 1;
69         }
70         return count;
71 }
72
73 static int alloc_str_list(struct list_head *list, int mult, char **result[])
74 {
75         char **res;
76         int cnt;
77         
78         cnt = list_count(list) * mult;
79         if (cnt == 0) {
80                 *result = NULL;
81                 return cnt;
82         }
83         res = calloc(mult, cnt * sizeof(char *));
84         if (res == NULL)
85                 return -ENOMEM;
86         *result = res;
87         return cnt;
88 }
89
90 /**
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
95  */
96 char *snd_use_case_identifier(const char *fmt, ...)
97 {
98         char *str, *res;
99         int size = strlen(fmt) + 512;
100         va_list args;
101
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;
113 }
114
115 /**
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
120  */
121 int snd_use_case_free_list(const char *list[], int items)
122 {
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;
130 }
131
132 static int open_ctl(snd_use_case_mgr_t *uc_mgr,
133                     snd_ctl_t **ctl,
134                     const char *ctl_dev)
135 {
136         int err;
137
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;
143         }
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);
148                 uc_mgr->ctl = NULL;
149         
150         }
151         err = snd_ctl_open(ctl, ctl_dev, 0);
152         if (err < 0)
153                 return err;
154         uc_mgr->ctl_dev = strdup(ctl_dev);
155         if (uc_mgr->ctl_dev == NULL) {
156                 snd_ctl_close(*ctl);
157                 return -ENOMEM;
158         }
159         uc_mgr->ctl = *ctl;
160         return 0;
161 }
162
163 extern int __snd_ctl_ascii_elem_id_parse(snd_ctl_elem_id_t *dst,
164                                          const char *str,
165                                          const char **ret_ptr);
166
167 static int execute_cset(snd_ctl_t *ctl, const char *cset)
168 {
169         const char *pos;
170         int err;
171         snd_ctl_elem_id_t *id;
172         snd_ctl_elem_value_t *value;
173         snd_ctl_elem_info_t *info;
174
175         snd_ctl_elem_id_malloc(&id);
176         snd_ctl_elem_value_malloc(&value);
177         snd_ctl_elem_info_malloc(&info);
178
179         err = __snd_ctl_ascii_elem_id_parse(id, cset, &pos);
180         if (err < 0)
181                 goto __fail;
182         while (*pos && isspace(*pos))
183                 pos++;
184         if (!*pos) {
185                 uc_error("undefined value for cset >%s<", cset);
186                 err = -EINVAL;
187                 goto __fail;
188         }
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);
192         if (err < 0)
193                 goto __fail;
194         err = snd_ctl_elem_info(ctl, info);
195         if (err < 0)
196                 goto __fail;
197         err = snd_ctl_ascii_value_parse(ctl, value, info, pos);
198         if (err < 0)
199                 goto __fail;
200         err = snd_ctl_elem_write(ctl, value);
201         if (err < 0)
202                 goto __fail;
203         err = 0;
204       __fail:
205         if (id != NULL)
206                 free(id);
207         if (value != NULL)
208                 free(value);
209         if (info != NULL)
210                 free(info);
211
212         return err;
213 }
214
215 /**
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
220  */
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)
226 {
227         struct list_head *pos;
228         struct sequence_element *s;
229         char *cdev = NULL;
230         snd_ctl_t *ctl = NULL;
231         int err = 0;
232
233         list_for_each(pos, seq) {
234                 s = list_entry(pos, struct sequence_element, list);
235                 switch (s->type) {
236                 case SEQUENCE_ELEMENT_TYPE_CDEV:
237                         cdev = strdup(s->data.cdev);
238                         if (cdev == NULL)
239                                 goto __fail_nomem;
240                         break;
241                 case SEQUENCE_ELEMENT_TYPE_CSET:
242                         if (cdev == NULL) {
243                                 const char *cdev1 = NULL, *cdev2 = NULL;
244                                 err = get_value3(&cdev1, "PlaybackCTL",
245                                                  value_list1,
246                                                  value_list2,
247                                                  value_list3);
248                                 if (err < 0 && err != ENOENT) {
249                                         uc_error("cdev is not defined!");
250                                         return err;
251                                 }
252                                 err = get_value3(&cdev1, "CaptureCTL",
253                                                  value_list1,
254                                                  value_list2,
255                                                  value_list3);
256                                 if (err < 0 && err != ENOENT) {
257                                         free((char *)cdev1);
258                                         uc_error("cdev is not defined!");
259                                         return err;
260                                 }
261                                 if (cdev1 == NULL || cdev2 == NULL ||
262                                     strcmp(cdev1, cdev2) == 0) {
263                                         cdev = (char *)cdev1;
264                                         free((char *)cdev2);
265                                 } else {
266                                         free((char *)cdev1);
267                                         free((char *)cdev2);
268                                 }
269                         }
270                         if (ctl == NULL) {
271                                 err = open_ctl(uc_mgr, &ctl, cdev);
272                                 if (err < 0) {
273                                         uc_error("unable to open ctl device '%s'", cdev);
274                                         goto __fail;
275                                 }
276                         }
277                         err = execute_cset(ctl, s->data.cset);
278                         if (err < 0) {
279                                 uc_error("unable to execute cset '%s'\n", s->data.cset);
280                                 goto __fail;
281                         }
282                         break;
283                 case SEQUENCE_ELEMENT_TYPE_SLEEP:
284                         usleep(s->data.sleep);
285                         break;
286                 case SEQUENCE_ELEMENT_TYPE_EXEC:
287                         err = system(s->data.exec);
288                         if (err < 0)
289                                 goto __fail;
290                         break;
291                 default:
292                         uc_error("unknown sequence command %i", s->type);
293                         break;
294                 }
295         }
296         free(cdev);
297         return 0;
298       __fail_nomem:
299         err = -ENOMEM;
300       __fail:
301         free(cdev);
302         return err;
303
304 }
305
306 /**
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
310  */
311 static int import_master_config(snd_use_case_mgr_t *uc_mgr)
312 {
313         int err;
314         
315         err = uc_mgr_import_master_config(uc_mgr);
316         if (err < 0)
317                 return err;
318         err = execute_sequence(uc_mgr, &uc_mgr->default_list,
319                                &uc_mgr->value_list, NULL, NULL);
320         if (err < 0)
321                 uc_error("Unable to execute default sequence");
322         return err;
323 }
324
325 /**
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)
332  */
333 static void *find0(struct list_head *list,
334                    unsigned long offset,
335                    unsigned long soffset,
336                    const char *match)
337 {
338         struct list_head *pos;
339         char *ptr, *str;
340
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)
345                         return ptr;
346         }
347         return NULL;
348 }
349
350 #define find(list, type, member, value, match) \
351         find0(list, (unsigned long)(&((type *)0)->member), \
352                     (unsigned long)(&((type *)0)->value), match)
353
354 /**
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
361  */
362 static int get_list0(struct list_head *list,
363                      const char **result[],
364                      unsigned long offset,
365                      unsigned long s1offset)
366 {
367         char **res;
368         int cnt;
369         struct list_head *pos;
370         char *ptr, *str1;
371
372         cnt = alloc_str_list(list, 1, &res);
373         if (cnt <= 0) {
374                 *result = NULL;
375                 return cnt;
376         }
377         *result = (const char **)res;
378         list_for_each(pos, list) {
379                 ptr = list_entry_offset(pos, char, offset);
380                 str1 = *((char **)(ptr + s1offset));
381                 if (str1 != NULL) {
382                         *res = strdup(str1);
383                         if (*res == NULL)
384                                 goto __fail;
385                 } else {
386                         *res = NULL;
387                 }
388                 res++;
389         }
390         return cnt;
391       __fail:
392         snd_use_case_free_list((const char **)res, cnt);
393         return -ENOMEM;
394 }
395
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))
400
401 /**
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
409  */
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)
415 {
416         char **res;
417         int cnt;
418         struct list_head *pos;
419         char *ptr, *str1, *str2;
420
421         cnt = alloc_str_list(list, 2, &res);
422         if (cnt <= 0) {
423                 *result = NULL;
424                 return cnt;
425         }
426         *result = (const char **)res;
427         list_for_each(pos, list) {
428                 ptr = list_entry_offset(pos, char, offset);
429                 str1 = *((char **)(ptr + s1offset));
430                 if (str1 != NULL) {
431                         *res = strdup(str1);
432                         if (*res == NULL)
433                                 goto __fail;
434                 } else {
435                         *res = NULL;
436                 }
437                 res++;
438                 str2 = *((char **)(ptr + s2offset));
439                 if (str2 != NULL) {
440                         *res = strdup(str2);
441                         if (*res == NULL)
442                                 goto __fail;
443                 } else {
444                         *res = NULL;
445                 }
446                 res++;
447         }
448         return cnt;
449       __fail:
450         snd_use_case_free_list((const char **)res, cnt);
451         return -ENOMEM;
452 }
453
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))
459
460 /**
461  * \brief Find verb
462  * \param uc_mgr Use case manager
463  * \param verb_name verb to find
464  * \return structure on success, otherwise a NULL (not found)
465  */
466 static inline struct use_case_verb *find_verb(snd_use_case_mgr_t *uc_mgr,
467                                               const char *verb_name)
468 {
469         return find(&uc_mgr->verb_list,
470                     struct use_case_verb, list, name,
471                     verb_name);
472 }
473
474 static int is_devlist_supported(snd_use_case_mgr_t *uc_mgr, 
475         struct dev_list *dev_list)
476 {
477         struct dev_list_node *device;
478         struct use_case_device *adev;
479         struct list_head *pos, *pos1;
480         int found_ret;
481
482         switch (dev_list->type) {
483         case DEVLIST_NONE:
484         default:
485                 return 1;
486         case DEVLIST_SUPPORTED:
487                 found_ret = 1;
488                 break;
489         case DEVLIST_CONFLICTING:
490                 found_ret = 0;
491                 break;
492         }
493
494         list_for_each(pos, &dev_list->list) {
495                 device = list_entry(pos, struct dev_list_node, list);
496
497                 list_for_each(pos1, &uc_mgr->active_devices) {
498                         adev = list_entry(pos1, struct use_case_device,
499                                             active_list);
500                         if (!strcmp(device->name, adev->name))
501                                 return found_ret;
502                 }
503         }
504         return 1 - found_ret;
505 }
506
507 static inline int is_modifier_supported(snd_use_case_mgr_t *uc_mgr, 
508         struct use_case_modifier *modifier)
509 {
510         return is_devlist_supported(uc_mgr, &modifier->dev_list);
511 }
512
513 static inline int is_device_supported(snd_use_case_mgr_t *uc_mgr, 
514         struct use_case_device *device)
515 {
516         return is_devlist_supported(uc_mgr, &device->dev_list);
517 }
518
519 /**
520  * \brief Find device
521  * \param verb Use case verb
522  * \param device_name device to find
523  * \return structure on success, otherwise a NULL (not found)
524  */
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)
528 {
529         struct use_case_device *device;
530         struct list_head *pos;
531
532         list_for_each(pos, &verb->device_list) {
533                 device = list_entry(pos, struct use_case_device, list);
534
535                 if (strcmp(device_name, device->name))
536                         continue;
537
538                 if (check_supported &&
539                     !is_device_supported(uc_mgr, device))
540                         continue;
541
542                 return device;
543         }
544         return NULL;
545 }
546
547 /**
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)
552  */
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)
556 {
557         struct use_case_modifier *modifier;
558         struct list_head *pos;
559
560         list_for_each(pos, &verb->modifier_list) {
561                 modifier = list_entry(pos, struct use_case_modifier, list);
562
563                 if (strcmp(modifier->name, modifier_name))
564                         continue;
565
566                 if (check_supported &&
567                     !is_modifier_supported(uc_mgr, modifier))
568                         continue;
569
570                 return modifier;
571         }
572         return NULL;
573 }
574
575 long device_status(snd_use_case_mgr_t *uc_mgr,
576                    const char *device_name)
577 {
578         struct use_case_device *dev;
579         struct list_head *pos;
580
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)
584                         return 1;
585         }
586         return 0;
587 }
588
589 long modifier_status(snd_use_case_mgr_t *uc_mgr,
590                      const char *modifier_name)
591 {
592         struct use_case_modifier *mod;
593         struct list_head *pos;
594
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)
598                         return 1;
599         }
600         return 0;
601 }
602
603 /**
604  * \brief Set verb
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
609  */
610 static int set_verb(snd_use_case_mgr_t *uc_mgr,
611                     struct use_case_verb *verb,
612                     int enable)
613 {
614         struct list_head *seq;
615         int err;
616
617         if (enable) {
618                 seq = &verb->enable_list;
619         } else {
620                 seq = &verb->disable_list;
621         }
622         err = execute_sequence(uc_mgr, seq,
623                                &verb->value_list,
624                                &uc_mgr->value_list,
625                                NULL);
626         if (enable && err >= 0)
627                 uc_mgr->active_verb = verb;
628         return err;
629 }
630
631 /**
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
637  */
638 static int set_modifier(snd_use_case_mgr_t *uc_mgr,
639                         struct use_case_modifier *modifier,
640                         int enable)
641 {
642         struct list_head *seq;
643         int err;
644
645         if (modifier_status(uc_mgr, modifier->name) == enable)
646                 return 0;
647
648         if (enable) {
649                 seq = &modifier->enable_list;
650         } else {
651                 seq = &modifier->disable_list;
652         }
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);
661         }
662         return err;
663 }
664
665 /**
666  * \brief Set device
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
671  */
672 static int set_device(snd_use_case_mgr_t *uc_mgr,
673                       struct use_case_device *device,
674                       int enable)
675 {
676         struct list_head *seq;
677         int err;
678
679         if (device_status(uc_mgr, device->name) == enable)
680                 return 0;
681
682         if (enable) {
683                 seq = &device->enable_list;
684         } else {
685                 seq = &device->disable_list;
686         }
687         err = execute_sequence(uc_mgr, seq,
688                                &device->value_list,
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);
695         }
696         return err;
697 }
698
699 /**
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
704  */
705 int snd_use_case_mgr_open(snd_use_case_mgr_t **uc_mgr,
706                           const char *card_name)
707 {
708         snd_use_case_mgr_t *mgr;
709         int err;
710
711         /* create a new UCM */
712         mgr = calloc(1, sizeof(snd_use_case_mgr_t));
713         if (mgr == NULL)
714                 return -ENOMEM;
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);
721
722         mgr->card_name = strdup(card_name);
723         if (mgr->card_name == NULL) {
724                 free(mgr);
725                 return -ENOMEM;
726         }
727
728         /* get info on use_cases and verify against card */
729         err = import_master_config(mgr);
730         if (err < 0) {
731                 uc_error("error: failed to import %s use case configuration %d",
732                         card_name, err);
733                 goto err;
734         }
735
736         *uc_mgr = mgr;
737         return 0;
738
739 err:
740         uc_mgr_free(mgr);
741         return err;
742 }
743
744 /**
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
748  */
749 int snd_use_case_mgr_reload(snd_use_case_mgr_t *uc_mgr)
750 {
751         int err;
752
753         pthread_mutex_lock(&uc_mgr->mutex);
754
755         uc_mgr_free_verb(uc_mgr);
756
757         /* reload all use cases */
758         err = import_master_config(uc_mgr);
759         if (err < 0) {
760                 uc_error("error: failed to reload use cases\n");
761                 pthread_mutex_unlock(&uc_mgr->mutex);
762                 return -EINVAL;
763         }
764
765         pthread_mutex_unlock(&uc_mgr->mutex);
766         return err;
767 }
768
769 /**
770  * \brief Close use case manager.
771  * \param uc_mgr Use case manager
772  * \return zero on success, otherwise a negative error code
773  */
774 int snd_use_case_mgr_close(snd_use_case_mgr_t *uc_mgr)
775 {
776         uc_mgr_free(uc_mgr);
777
778         return 0;
779 }
780
781 /*
782  * Tear down current use case verb, device and modifier.
783  */
784 static int dismantle_use_case(snd_use_case_mgr_t *uc_mgr)
785 {
786         struct list_head *pos, *npos;
787         struct use_case_modifier *modifier;
788         struct use_case_device *device;
789         int err;
790
791         list_for_each_safe(pos, npos, &uc_mgr->active_modifiers) {
792                 modifier = list_entry(pos, struct use_case_modifier,
793                                       active_list);
794                 err = set_modifier(uc_mgr, modifier, 0);
795                 if (err < 0)
796                         uc_error("Unable to disable modifier %s", modifier->name);
797         }
798         INIT_LIST_HEAD(&uc_mgr->active_modifiers);
799
800         list_for_each_safe(pos, npos, &uc_mgr->active_devices) {
801                 device = list_entry(pos, struct use_case_device,
802                                     active_list);
803                 err = set_device(uc_mgr, device, 0);
804                 if (err < 0)
805                         uc_error("Unable to disable device %s", device->name);
806         }
807         INIT_LIST_HEAD(&uc_mgr->active_devices);
808
809         err = set_verb(uc_mgr, uc_mgr->active_verb, 0);
810         if (err < 0) {
811                 uc_error("Unable to disable verb %s", uc_mgr->active_verb->name);
812                 return err;
813         }
814         uc_mgr->active_verb = NULL;
815
816         err = execute_sequence(uc_mgr, &uc_mgr->default_list,
817                                &uc_mgr->value_list, NULL, NULL);
818         
819         return err;
820 }
821
822 /**
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
826  */
827 int snd_use_case_mgr_reset(snd_use_case_mgr_t *uc_mgr)
828 {
829         int err;
830
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);
838         return err;
839 }
840
841 /**
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
846  */
847 static int get_verb_list(snd_use_case_mgr_t *uc_mgr, const char **list[])
848 {
849         return get_list2(&uc_mgr->verb_list, list,
850                          struct use_case_verb, list,
851                          name, comment);
852 }
853
854 /**
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
859  */
860 static int get_device_list(snd_use_case_mgr_t *uc_mgr, const char **list[],
861                            char *verbname)
862 {
863         struct use_case_verb *verb;
864         
865         if (verbname) {
866                 verb = find_verb(uc_mgr, verbname);
867         } else {
868                 verb = uc_mgr->active_verb;
869         }
870         if (verb == NULL)
871                 return -ENOENT;
872         return get_list2(&verb->device_list, list,
873                          struct use_case_device, list,
874                          name, comment);
875 }
876
877 /**
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
882  */
883 static int get_modifier_list(snd_use_case_mgr_t *uc_mgr, const char **list[],
884                              char *verbname)
885 {
886         struct use_case_verb *verb;
887         
888         if (verbname) {
889                 verb = find_verb(uc_mgr, verbname);
890         } else {
891                 verb = uc_mgr->active_verb;
892         }
893         if (verb == NULL)
894                 return -ENOENT;
895         return get_list2(&verb->modifier_list, list,
896                          struct use_case_modifier, list,
897                          name, comment);
898 }
899
900 /**
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
906  */
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)
910 {
911         char *str;
912         struct use_case_verb *verb;
913         struct use_case_modifier *modifier;
914         struct use_case_device *device;
915
916         if (!name)
917                 return -ENOENT;
918
919         str = strchr(name, '/');
920         if (str) {
921                 *str = '\0';
922                 verb = find_verb(uc_mgr, str + 1);
923         }
924         else {
925                 verb = uc_mgr->active_verb;
926         }
927         if (!verb)
928                 return -ENOENT;
929
930         modifier = find_modifier(uc_mgr, verb, name, 0);
931         if (modifier) {
932                 if (modifier->dev_list.type != type)
933                         return 0;
934                 return get_list(&modifier->dev_list.list, list,
935                                 struct dev_list_node, list,
936                                 name);
937         }
938
939         device = find_device(uc_mgr, verb, name, 0);
940         if (device) {
941                 if (device->dev_list.type != type)
942                         return 0;
943                 return get_list(&device->dev_list.list, list,
944                                 struct dev_list_node, list,
945                                 name);
946         }
947
948         return -ENOENT;
949
950 }
951
952 /**
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
957  */
958 static int get_supported_device_list(snd_use_case_mgr_t *uc_mgr,
959                                      const char **list[], char *name)
960 {
961         return get_supcon_device_list(uc_mgr, list, name, DEVLIST_SUPPORTED);
962 }
963
964 /**
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
969  */
970 static int get_conflicting_device_list(snd_use_case_mgr_t *uc_mgr,
971                                        const char **list[], char *name)
972 {
973         return get_supcon_device_list(uc_mgr, list, name, DEVLIST_CONFLICTING);
974 }
975
976 #ifndef DOC_HIDDEN
977 struct myvalue {
978         struct list_head list;
979         char *value;
980 };
981 #endif
982
983 static int add_values(struct list_head *list,
984                       const char *identifier,
985                       struct list_head *source)
986 {
987         struct ucm_value *v;
988         struct myvalue *val;
989         struct list_head *pos, *pos1;
990         int match;
991         
992         list_for_each(pos, source) {
993                 v = list_entry(pos, struct ucm_value, list);
994                 if (check_identifier(identifier, v->name)) {
995                         match = 0;
996                         list_for_each(pos1, list) {
997                                 val = list_entry(pos1, struct myvalue, list);
998                                 if (strcmp(val->value, v->data) == 0) {
999                                         match = 1;
1000                                         break;
1001                                 }
1002                         }
1003                         if (!match) {
1004                                 val = malloc(sizeof(struct myvalue));
1005                                 if (val == NULL)
1006                                         return -ENOMEM;
1007                                 val->value = v->data;
1008                                 list_add_tail(&val->list, list);
1009                         }
1010                 }
1011         }
1012         return 0;
1013 }
1014
1015 /**
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
1020  */
1021 static int get_value_list(snd_use_case_mgr_t *uc_mgr,
1022                           const char *identifier,
1023                           const char **list[],
1024                           char *verbname)
1025 {
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;
1031         char **res;
1032         int err;
1033         
1034         if (verbname) {
1035                 verb = find_verb(uc_mgr, verbname);
1036         } else {
1037                 verb = uc_mgr->active_verb;
1038         }
1039         if (verb == NULL)
1040                 return -ENOENT;
1041         INIT_LIST_HEAD(&mylist);
1042         err = add_values(&mylist, identifier, &uc_mgr->value_list);
1043         if (err < 0)
1044                 goto __fail;
1045         err = add_values(&mylist, identifier, &verb->value_list);
1046         if (err < 0)
1047                 goto __fail;
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);
1051                 if (err < 0)
1052                         goto __fail;
1053         }
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);
1057                 if (err < 0)
1058                         goto __fail;
1059         }
1060         err = alloc_str_list(&mylist, 1, &res);
1061         if (err >= 0) {
1062                 *list = (const char **)res;
1063                 list_for_each(pos, &mylist) {
1064                         val = list_entry(pos, struct myvalue, list);
1065                         *res = strdup(val->value);
1066                         if (*res == NULL) {
1067                                 snd_use_case_free_list((const char **)res, err);
1068                                 err = -ENOMEM;
1069                                 goto __fail;
1070                         }
1071                         res++;
1072                 }
1073         }
1074       __fail:
1075         list_for_each_safe(pos, npos, &mylist) {
1076                 val = list_entry(pos, struct myvalue, list);
1077                 list_del(&val->list);
1078                 free(val);
1079         }
1080         return err;
1081 }
1082
1083 /**
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
1088  */
1089 static int get_enabled_device_list(snd_use_case_mgr_t *uc_mgr,
1090                                    const char **list[])
1091 {
1092         if (uc_mgr->active_verb == NULL)
1093                 return -EINVAL;
1094         return get_list(&uc_mgr->active_devices, list,
1095                         struct use_case_device, active_list,
1096                         name);
1097 }
1098
1099 /**
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
1104  */
1105 static int get_enabled_modifier_list(snd_use_case_mgr_t *uc_mgr,
1106                                      const char **list[])
1107 {
1108         if (uc_mgr->active_verb == NULL)
1109                 return -EINVAL;
1110         return get_list(&uc_mgr->active_modifiers, list,
1111                         struct use_case_modifier, active_list,
1112                         name);
1113 }
1114
1115 /**
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
1121  */
1122 int snd_use_case_get_list(snd_use_case_mgr_t *uc_mgr,
1123                           const char *identifier,
1124                           const char **list[])
1125 {
1126         char *str, *str1;
1127         int err;
1128
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);
1138         else {
1139                 str1 = strchr(identifier, '/');
1140                 if (str1) {
1141                         str = strdup(str1 + 1);
1142                         if (str == NULL) {
1143                                 err = -ENOMEM;
1144                                 goto __end;
1145                         }
1146                 } else {
1147                         str = NULL;
1148                 }
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] == '_')
1158                         err = -ENOENT;
1159                 else
1160                         err = get_value_list(uc_mgr, identifier, list, str);
1161                 if (str)
1162                         free(str);
1163         }
1164       __end:
1165         pthread_mutex_unlock(&uc_mgr->mutex);
1166         return err;
1167 }
1168
1169 static int get_value1(const char **value, struct list_head *value_list,
1170                       const char *identifier)
1171 {
1172         struct ucm_value *val;
1173         struct list_head *pos;
1174         
1175         if (!value_list)
1176                 return -ENOENT;
1177
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);
1182                       if (*value == NULL)
1183                               return -ENOMEM;
1184                       return 0;
1185               }
1186         }
1187         return -ENOENT;
1188 }
1189
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)
1195 {
1196         int err;
1197
1198         err = get_value1(value, value_list1, identifier);
1199         if (err >= 0 || err != -ENOENT)
1200                 return err;
1201         err = get_value1(value, value_list2, identifier);
1202         if (err >= 0 || err != -ENOENT)
1203                 return err;
1204         err = get_value1(value, value_list3, identifier);
1205         if (err >= 0 || err != -ENOENT)
1206                 return err;
1207         return -ENOENT;
1208 }
1209
1210 /**
1211  * \brief Get value
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
1217  */
1218 static int get_value(snd_use_case_mgr_t *uc_mgr,
1219                         const char *identifier,
1220                         const char **value,
1221                         const char *mod_dev_name,
1222                         const char *verb_name,
1223                         int exact)
1224 {
1225         struct use_case_verb *verb;
1226         struct use_case_modifier *mod;
1227         struct use_case_device *dev;
1228         int err;
1229
1230         if (mod_dev_name || verb_name || !exact) {
1231                 if (verb_name && strlen(verb_name)) {
1232                         verb = find_verb(uc_mgr, verb_name);
1233                 } else {
1234                         verb = uc_mgr->active_verb;
1235                 }
1236                 if (verb) {
1237                         if (mod_dev_name) {
1238                                 mod = find_modifier(uc_mgr, verb,
1239                                                     mod_dev_name, 0);
1240                                 if (mod) {
1241                                         err = get_value1(value,
1242                                                          &mod->value_list,
1243                                                          identifier);
1244                                         if (err >= 0 || err != -ENOENT)
1245                                                 return err;
1246                                 }
1247
1248                                 dev = find_device(uc_mgr, verb,
1249                                                   mod_dev_name, 0);
1250                                 if (dev) {
1251                                         err = get_value1(value,
1252                                                          &dev->value_list,
1253                                                          identifier);
1254                                         if (err >= 0 || err != -ENOENT)
1255                                                 return err;
1256                                 }
1257
1258                                 if (exact)
1259                                         return -ENOENT;
1260                         }
1261
1262                         err = get_value1(value, &verb->value_list, identifier);
1263                         if (err >= 0 || err != -ENOENT)
1264                                 return err;
1265                 }
1266
1267                 if (exact)
1268                         return -ENOENT;
1269         }
1270
1271         err = get_value1(value, &uc_mgr->value_list, identifier);
1272         if (err >= 0 || err != -ENOENT)
1273                 return err;
1274
1275         return -ENOENT;
1276 }
1277
1278 /**
1279  * \brief Get current - string
1280  * \param uc_mgr Use case manager
1281  * \param identifier 
1282  * \param value Value pointer
1283  * \return Zero if success, otherwise a negative error code
1284  *
1285  * Note: String is dynamically allocated, use free() to
1286  * deallocate this string.
1287  */      
1288 int snd_use_case_get(snd_use_case_mgr_t *uc_mgr,
1289                      const char *identifier,
1290                      const char **value)
1291 {
1292         const char *slash1, *slash2, *mod_dev_after;
1293         const char *ident, *mod_dev, *verb;
1294         int exact = 0;
1295         int err;
1296
1297         pthread_mutex_lock(&uc_mgr->mutex);
1298         if (identifier == NULL) {
1299                 *value = strdup(uc_mgr->card_name);
1300                 if (*value == NULL) {
1301                         err = -ENOMEM;
1302                         goto __end;
1303                 }
1304                 err = 0;
1305         } else if (strcmp(identifier, "_verb") == 0) {
1306                 if (uc_mgr->active_verb == NULL) {
1307                         err = -ENOENT;
1308                         goto __end;
1309                 }
1310                 *value = strdup(uc_mgr->active_verb->name);
1311                 if (*value == NULL) {
1312                         err = -ENOMEM;
1313                         goto __end;
1314                 }
1315                 err = 0;
1316         } else if (identifier[0] == '_') {
1317                 err = -ENOENT;
1318                 goto __end;
1319         } else {
1320                 if (identifier[0] == '=') {
1321                         exact = 1;
1322                         identifier++;
1323                 }
1324
1325                 slash1 = strchr(identifier, '/');
1326                 if (slash1) {
1327                         ident = strndup(identifier, slash1 - identifier);
1328
1329                         slash2 = strchr(slash1 + 1, '/');
1330                         if (slash2) {
1331                                 mod_dev_after = slash2;
1332                                 verb = slash2 + 1;
1333                         }
1334                         else {
1335                                 mod_dev_after = slash1 + strlen(slash1);
1336                                 verb = NULL;
1337                         }
1338
1339                         if (mod_dev_after == slash1 + 1)
1340                                 mod_dev = NULL;
1341                         else
1342                                 mod_dev = strndup(slash1 + 1,
1343                                                   mod_dev_after - (slash1 + 1));
1344                 }
1345                 else {
1346                         ident = identifier;
1347                         mod_dev = NULL;
1348                         verb = NULL;
1349                 }
1350
1351                 err = get_value(uc_mgr, ident, value, mod_dev, verb, exact);
1352                 if (ident != identifier)
1353                         free((void *)ident);
1354                 if (mod_dev)
1355                         free((void *)mod_dev);
1356         }
1357       __end:
1358         pthread_mutex_unlock(&uc_mgr->mutex);
1359         return err;
1360 }
1361
1362
1363 /**
1364  * \brief Get current - integer
1365  * \param uc_mgr Use case manager
1366  * \param identifier 
1367  * \return Value if success, otherwise a negative error code 
1368  */
1369 int snd_use_case_geti(snd_use_case_mgr_t *uc_mgr,
1370                       const char *identifier,
1371                       long *value)
1372 {
1373         char *str, *str1;
1374         long err;
1375
1376         pthread_mutex_lock(&uc_mgr->mutex);
1377         if (0) {
1378                 /* nothing here - prepared for fixed identifiers */
1379         } else {
1380                 str1 = strchr(identifier, '/');
1381                 if (str1) {
1382                         str = strdup(str1 + 1);
1383                         if (str == NULL) {
1384                                 err = -ENOMEM;
1385                                 goto __end;
1386                         }
1387                 } else {
1388                         str = NULL;
1389                 }
1390                 if (check_identifier(identifier, "_devstatus")) {
1391                         err = device_status(uc_mgr, str);
1392                         if (err >= 0) {
1393                                 *value = err;
1394                                 err = 0;
1395                         }
1396                 } else if (check_identifier(identifier, "_modstatus")) {
1397                         err = modifier_status(uc_mgr, str);
1398                         if (err >= 0) {
1399                                 *value = err;
1400                                 err = 0;
1401                         }
1402 #if 0
1403                 /*
1404                  * enable this block if the else clause below is expanded to query
1405                  * user-supplied values
1406                  */
1407                 } else if (identifier[0] == '_')
1408                         err = -ENOENT;
1409 #endif
1410                 } else
1411                         err = -ENOENT;
1412                 if (str)
1413                         free(str);
1414         }
1415       __end:
1416         pthread_mutex_unlock(&uc_mgr->mutex);
1417         return err;
1418 }
1419
1420 static int handle_transition_verb(snd_use_case_mgr_t *uc_mgr,
1421                                   struct use_case_verb *new_verb)
1422 {
1423         struct list_head *pos;
1424         struct transition_sequence *trans;
1425         int err;
1426
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,
1433                                                NULL);
1434                         if (err >= 0)
1435                                 return 1;
1436                         return err;
1437                 }
1438         }
1439         return 0;
1440 }
1441
1442 static int set_verb_user(snd_use_case_mgr_t *uc_mgr,
1443                          const char *verb_name)
1444 {
1445         struct use_case_verb *verb;
1446         int err;
1447
1448         if (uc_mgr->active_verb &&
1449             strcmp(uc_mgr->active_verb->name, verb_name) == 0)
1450                 return 0;
1451         if (strcmp(verb_name, SND_USE_CASE_VERB_INACTIVE) != 0) {
1452                 verb = find_verb(uc_mgr, verb_name);
1453                 if (verb == NULL)
1454                         return -ENOENT;
1455         } else {
1456                 verb = NULL;
1457         }
1458         if (uc_mgr->active_verb) {
1459                 err = handle_transition_verb(uc_mgr, verb);
1460                 if (err == 0) {
1461                         err = dismantle_use_case(uc_mgr);
1462                         if (err < 0)
1463                                 return err;
1464                 } else if (err == 1) {
1465                         uc_mgr->active_verb = verb;
1466                         verb = NULL;
1467                 } else {
1468                         verb = NULL; /* show error */
1469                 }
1470         }
1471         if (verb) {
1472                 err = set_verb(uc_mgr, verb, 1);
1473                 if (err < 0)
1474                         uc_error("error: failed to initialize new use case: %s",
1475                                  verb_name);
1476         }
1477         return err;
1478 }
1479
1480
1481 static int set_device_user(snd_use_case_mgr_t *uc_mgr,
1482                            const char *device_name,
1483                            int enable)
1484 {
1485         struct use_case_device *device;
1486
1487         if (uc_mgr->active_verb == NULL)
1488                 return -ENOENT;
1489         device = find_device(uc_mgr, uc_mgr->active_verb, device_name, 1);
1490         if (device == NULL)
1491                 return -ENOENT;
1492         return set_device(uc_mgr, device, enable);
1493 }
1494
1495 static int set_modifier_user(snd_use_case_mgr_t *uc_mgr,
1496                              const char *modifier_name,
1497                              int enable)
1498 {
1499         struct use_case_modifier *modifier;
1500
1501         if (uc_mgr->active_verb == NULL)
1502                 return -ENOENT;
1503
1504         modifier = find_modifier(uc_mgr, uc_mgr->active_verb, modifier_name, 1);
1505         if (modifier == NULL)
1506                 return -ENOENT;
1507         return set_modifier(uc_mgr, modifier, enable);
1508 }
1509
1510 static int switch_device(snd_use_case_mgr_t *uc_mgr,
1511                          const char *old_device,
1512                          const char *new_device)
1513 {
1514         struct use_case_device *xold, *xnew;
1515         struct transition_sequence *trans;
1516         struct list_head *pos;
1517         int err, seq_found = 0;
1518         
1519         if (uc_mgr->active_verb == NULL)
1520                 return -ENOENT;
1521         if (device_status(uc_mgr, old_device) == 0) {
1522                 uc_error("error: device %s not enabled", old_device);
1523                 return -EINVAL;
1524         }
1525         if (device_status(uc_mgr, new_device) != 0) {
1526                 uc_error("error: device %s already enabled", new_device);
1527                 return -EINVAL;
1528         }
1529         xold = find_device(uc_mgr, uc_mgr->active_verb, old_device, 1);
1530         if (xold == NULL)
1531                 return -ENOENT;
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);
1535         if (xnew == NULL)
1536                 return -ENOENT;
1537         err = 0;
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,
1542                                                &xold->value_list,
1543                                                &uc_mgr->active_verb->value_list,
1544                                                &uc_mgr->value_list);
1545                         if (err >= 0) {
1546                                 list_del(&xold->active_list);
1547                                 list_add_tail(&xnew->active_list, &uc_mgr->active_devices);
1548                         }
1549                         seq_found = 1;
1550                         break;
1551                 }
1552         }
1553         if (!seq_found) {
1554                 err = set_device(uc_mgr, xold, 0);
1555                 if (err < 0)
1556                         return err;
1557                 err = set_device(uc_mgr, xnew, 1);
1558                 if (err < 0)
1559                         return err;
1560         }
1561         return err;
1562 }
1563
1564 static int switch_modifier(snd_use_case_mgr_t *uc_mgr,
1565                            const char *old_modifier,
1566                            const char *new_modifier)
1567 {
1568         struct use_case_modifier *xold, *xnew;
1569         struct transition_sequence *trans;
1570         struct list_head *pos;
1571         int err, seq_found = 0;
1572         
1573         if (uc_mgr->active_verb == NULL)
1574                 return -ENOENT;
1575         if (modifier_status(uc_mgr, old_modifier) == 0) {
1576                 uc_error("error: modifier %s not enabled", old_modifier);
1577                 return -EINVAL;
1578         }
1579         if (modifier_status(uc_mgr, new_modifier) != 0) {
1580                 uc_error("error: modifier %s already enabled", new_modifier);
1581                 return -EINVAL;
1582         }
1583         xold = find_modifier(uc_mgr, uc_mgr->active_verb, old_modifier, 1);
1584         if (xold == NULL)
1585                 return -ENOENT;
1586         xnew = find_modifier(uc_mgr, uc_mgr->active_verb, new_modifier, 1);
1587         if (xnew == NULL)
1588                 return -ENOENT;
1589         err = 0;
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,
1594                                                &xold->value_list,
1595                                                &uc_mgr->active_verb->value_list,
1596                                                &uc_mgr->value_list);
1597                         if (err >= 0) {
1598                                 list_del(&xold->active_list);
1599                                 list_add_tail(&xnew->active_list, &uc_mgr->active_modifiers);
1600                         }
1601                         seq_found = 1;
1602                         break;
1603                 }
1604         }
1605         if (!seq_found) {
1606                 err = set_modifier(uc_mgr, xold, 0);
1607                 if (err < 0)
1608                         return err;
1609                 err = set_modifier(uc_mgr, xnew, 1);
1610                 if (err < 0)
1611                         return err;
1612         }
1613         return err;        
1614 }
1615
1616 /**
1617  * \brief Set new
1618  * \param uc_mgr Use case manager
1619  * \param identifier
1620  * \param value Value
1621  * \return Zero if success, otherwise a negative error code
1622  */
1623 int snd_use_case_set(snd_use_case_mgr_t *uc_mgr,
1624                      const char *identifier,
1625                      const char *value)
1626 {
1627         char *str, *str1;
1628         int err;
1629
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);
1641         else {
1642                 str1 = strchr(identifier, '/');
1643                 if (str1) {
1644                         str = strdup(str1 + 1);
1645                         if (str == NULL) {
1646                                 err = -ENOMEM;
1647                                 goto __end;
1648                         }
1649                 } else {
1650                         err = -EINVAL;
1651                         goto __end;
1652                 }
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);
1657                 else
1658                         err = -EINVAL;
1659                 if (str)
1660                         free(str);
1661         }
1662       __end:
1663         pthread_mutex_unlock(&uc_mgr->mutex);
1664         return err;
1665 }