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