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