]> git.alsa-project.org Git - alsa-lib.git/commitdiff
ucm: Moved ucm to src/ucm subdirectory
authorJaroslav Kysela <perex@perex.cz>
Tue, 7 Sep 2010 13:35:14 +0000 (15:35 +0200)
committerJaroslav Kysela <perex@perex.cz>
Wed, 15 Sep 2010 06:09:31 +0000 (08:09 +0200)
- separate code to more files
- use standard lists to represent structures
- use alsa-lib configuration parser

Signed-off-by: Jaroslav Kysela <perex@perex.cz>
configure.in
doc/doxygen.cfg.in
include/list.h
include/use-case.h
src/Makefile.am
src/ucm/Makefile.am [new file with mode: 0644]
src/ucm/main.c [new file with mode: 0644]
src/ucm/parser.c [new file with mode: 0644]
src/ucm/ucm_local.h [new file with mode: 0644]
src/ucm/utils.c [new file with mode: 0644]
src/use-case.c [deleted file]

index abc4687ef0160742478cff37fdb4dd107562353a..0a65cc1559db4c002fa626dd399f34bf8729e1d8 100644 (file)
@@ -373,6 +373,9 @@ AC_ARG_ENABLE(hwdep,
 AC_ARG_ENABLE(seq,
   AS_HELP_STRING([--disable-seq], [disable the sequencer component]),
   [build_seq="$enableval"], [build_seq="yes"])
+AC_ARG_ENABLE(ucm,
+  AS_HELP_STRING([--disable-ucm], [disable the use-case-manager component]),
+  [build_ucm="$enableval"], [build_ucm="yes"])
 AC_ARG_ENABLE(alisp,
   AS_HELP_STRING([--disable-alisp], [disable the alisp component]),
   [build_alisp="$enableval"], [build_alisp="yes"])
@@ -414,6 +417,7 @@ AM_CONDITIONAL(BUILD_PCM, test x$build_pcm = xyes)
 AM_CONDITIONAL(BUILD_RAWMIDI, test x$build_rawmidi = xyes)
 AM_CONDITIONAL(BUILD_HWDEP, test x$build_hwdep = xyes)
 AM_CONDITIONAL(BUILD_SEQ, test x$build_seq = xyes)
+AM_CONDITIONAL(BUILD_UCM, test x$build_ucm = xyes)
 AM_CONDITIONAL(BUILD_ALISP, test x$build_alisp = xyes)
 AM_CONDITIONAL(BUILD_PYTHON, test x$build_python = xyes)
 
@@ -598,7 +602,7 @@ AC_OUTPUT(Makefile doc/Makefile doc/pictures/Makefile doc/doxygen.cfg \
           src/control/Makefile src/mixer/Makefile \
          src/pcm/Makefile src/pcm/scopes/Makefile \
          src/rawmidi/Makefile src/timer/Makefile \
-          src/hwdep/Makefile src/seq/Makefile \
+          src/hwdep/Makefile src/seq/Makefile src/ucm/Makefile \
           src/compat/Makefile src/alisp/Makefile src/conf/Makefile \
          src/conf/cards/Makefile \
          src/conf/pcm/Makefile \
index 39297722134bbbccab53bf843a397a1384353b67..f4499d61029054150e313f32f52493dc4253af81 100644 (file)
@@ -77,7 +77,8 @@ INPUT            = @top_srcdir@/doc/index.doxygen \
                   @top_srcdir@/src/rawmidi \
                   @top_srcdir@/src/timer \
                   @top_srcdir@/src/hwdep \
-                  @top_srcdir@/src/seq
+                  @top_srcdir@/src/seq \
+                  @top_srcdir@/src/ucm
 EXCLUDE                 = @top_srcdir@/src/control/control_local.h \
                   @top_srcdir@/src/pcm/atomic.h \
                   @top_srcdir@/src/pcm/interval.h \
@@ -92,7 +93,8 @@ EXCLUDE                = @top_srcdir@/src/control/control_local.h \
                   @top_srcdir@/src/hwdep/hwdep_local.h \
                   @top_srcdir@/src/mixer/mixer_local.h \
                   @top_srcdir@/src/rawmidi/rawmidi_local.h \
-                  @top_srcdir@/src/seq/seq_local.h
+                  @top_srcdir@/src/seq/seq_local.h \
+                  @top_srcdir@/src/seq/ucm_local.h
 RECURSIVE       = YES
 FILE_PATTERNS    = *.c *.h
 EXAMPLE_PATH     = @top_srcdir@/test
index 5b3f1bf0a63c95cf9e5ee25d39c5aff90b76b1e9..4d9895feba052447a77a3413342fbee54f5725f1 100644 (file)
@@ -162,5 +162,13 @@ static __inline__ void list_splice(struct list_head *list, struct list_head *hea
 #define list_entry(ptr, type, member) \
        ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
 
+/**
+ * list_entry - get the struct for this entry
+ * @ptr:       the &struct list_head pointer.
+ * @type:      the type of the struct this is embedded in.
+ * @offset:    offset of entry inside a struct
+ */
+#define list_entry_offset(ptr, type, offset) \
+       ((type *)((char *)(ptr)-(offset)))
 
 #endif /* _LIST_H */
index 33d480f66d000fa7c86367c68b98bdaad9217a74..6b9b6455fe23a6ef2c5e633bfc856b5af7a4fdd5 100644 (file)
@@ -176,11 +176,18 @@ typedef struct snd_use_case_mgr snd_use_case_mgr_t;
  */
 char *snd_use_case_identifier(const char *fmt, ...);
 
+/**
+ * \brief Free a string list
+ * \param list The string list to free
+ * \return Zero if success, otherwise a negative error code
+ */
+int snd_use_case_free_list(const char *list[]);
+
 /**
  * \brief Obtain a list of entries
- * \param uc_mgr Use case manager
- * \param identifier (may be NULL)
- * \param list Returned list
+ * \param uc_mgr Use case manager (may be NULL - card list)
+ * \param identifier (may be NULL - card list)
+ * \param list Returned allocated list
  * \return Number of list entries if success, otherwise a negative error code
  *
  * Defined identifiers:
@@ -215,6 +222,8 @@ int snd_use_case_get_list(snd_use_case_mgr_t *uc_mgr,
  * Known identifiers:
  *   NULL                              - return current card
  *   _verb                             - return current verb
+ *   _tq                               - return current Tone Quality
+ *   _tq/<modifier>                    - return Tone Quality for given modifier
  *   _pcm_/_pdevice[/<modifier>]       - full PCM playback device name
  *   _pcm_/_cdevice[/<modifier>]       - full PCM capture device name
  *   _ctl_/_pctl_[/<modifier>]         - playback control device name
@@ -241,8 +250,6 @@ int snd_use_case_get(snd_use_case_mgr_t *uc_mgr,
  * Known identifiers:
  *   _devstatus/<device>       - return status for given device
  *   _modstatus/<modifier>     - return status for given modifier
- *   _tq                       - return current Tone Quality
- *   _tq/<modifier>            - return Tone Quality for given modifier
  */
 int snd_use_case_geti(snd_use_case_mgr_t *uc_mgr,
                       const char *identifier);
@@ -275,10 +282,11 @@ int snd_use_case_set(snd_use_case_mgr_t *uc_mgr,
 
 /**
  * \brief Open and initialise use case core for sound card
+ * \param uc_mgr Returned use case manager pointer
  * \param card_name Sound card name.
- * \return Use case handle if success, otherwise NULL
+ * \return zero if success, otherwise a negative error code
  */
-snd_use_case_mgr_t *snd_use_case_mgr_open(const char *card_name);
+int snd_use_case_mgr_open(snd_use_case_mgr_t **uc_mgr, const char *card_name);
 
 
 /**
index 7206dbdbbbc9ae0231ca81e173beb57ffc8d6e85..9a00dca33c985b0105548b4ef3fce908b553380c 100644 (file)
@@ -14,7 +14,7 @@ SYMFUNCS =
 endif
 
 lib_LTLIBRARIES = libasound.la
-libasound_la_SOURCES = conf.c confmisc.c input.c output.c async.c error.c dlmisc.c socket.c shmarea.c userfile.c names.c use-case.c
+libasound_la_SOURCES = conf.c confmisc.c input.c output.c async.c error.c dlmisc.c socket.c shmarea.c userfile.c names.c
 
 SUBDIRS=control
 libasound_la_LIBADD = control/libcontrol.la
@@ -38,6 +38,10 @@ if BUILD_SEQ
 SUBDIRS += seq
 libasound_la_LIBADD += seq/libseq.la
 endif
+if BUILD_UCM
+SUBDIRS += ucm
+libasound_la_LIBADD += ucm/libucm.la
+endif
 if BUILD_ALISP
 SUBDIRS += alisp
 libasound_la_LIBADD += alisp/libalisp.la
diff --git a/src/ucm/Makefile.am b/src/ucm/Makefile.am
new file mode 100644 (file)
index 0000000..7435d90
--- /dev/null
@@ -0,0 +1,10 @@
+EXTRA_LTLIBRARIES = libucm.la
+
+libucm_la_SOURCES = utils.c parser.c main.c
+
+noinst_HEADERS = ucm_local.h
+
+all: libucm.la
+
+
+INCLUDES=-I$(top_srcdir)/include
diff --git a/src/ucm/main.c b/src/ucm/main.c
new file mode 100644 (file)
index 0000000..a8df44c
--- /dev/null
@@ -0,0 +1,1448 @@
+/*
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *  Support for the verb/device/modifier core logic and API,
+ *  command line tool and file parser was kindly sponsored by
+ *  Texas Instruments Inc.
+ *  Support for multiple active modifiers and devices,
+ *  transition sequences, multiple client access and user defined use
+ *  cases was kindly sponsored by Wolfson Microelectronics PLC.
+ *
+ *  Copyright (C) 2008-2010 SlimLogic Ltd
+ *  Copyright (C) 2010 Wolfson Microelectronics PLC
+ *  Copyright (C) 2010 Texas Instruments Inc.
+ *  Copyright (C) 2010 Red Hat Inc.
+ *  Authors: Liam Girdwood <lrg@slimlogic.co.uk>
+ *              Stefan Schmidt <stefan@slimlogic.co.uk>
+ *              Justin Xu <justinx@slimlogic.co.uk>
+ *               Jaroslav Kysela <perex@perex.cz>
+ */
+
+#include "ucm_local.h"
+#include <pthread.h>
+
+/**
+ * \brief Execute the sequence
+ * \param uc_mgr Use case manager
+ * \param seq Sequence
+ * \return zero on success, otherwise a negative error code
+ */
+static int execute_sequence(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED,
+                           struct list_head *seq)
+{
+       struct list_head *pos;
+       struct sequence_element *s;
+
+       list_for_each(pos, seq) {
+               s = list_entry(pos, struct sequence_element, list);
+               switch (s->type) {
+               case SEQUENCE_ELEMENT_TYPE_CSET:
+                       uc_error("cset not yet implemented: '%s'", s->data.cset);
+                       break;
+               case SEQUENCE_ELEMENT_TYPE_SLEEP:
+                       usleep(s->data.sleep);
+                       break;
+               case SEQUENCE_ELEMENT_TYPE_EXEC:
+                       uc_error("exec not yet implemented: '%s'", s->data.exec);
+                       break;
+               default:
+                       uc_error("unknown sequence command %i", s->type);
+                       break;
+               }
+       }
+       return 0;
+}
+
+/**
+ * \brief Import master config and execute the default sequence
+ * \param uc_mgr Use case manager
+ * \return zero on success, otherwise a negative error code
+ */
+static int import_master_config(snd_use_case_mgr_t *uc_mgr)
+{
+       int err;
+       
+       err = uc_mgr_import_master_config(uc_mgr);
+       if (err < 0)
+               return err;
+       err = execute_sequence(uc_mgr, &uc_mgr->default_list);
+       if (err < 0)
+               uc_error("Unable to execute default sequence");
+       return err;
+}
+
+/**
+ * \brief Universal find - string in a list
+ * \param uc_mgr Use case manager
+ * \param list List of structures
+ * \param offset Offset of list structure
+ * \param soffset Offset of string structure
+ * \param match String to match
+ * \return structure on success, otherwise a NULL (not found)
+ */
+static void *find0(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED,
+                  struct list_head *list,
+                  unsigned long offset,
+                  unsigned long soffset,
+                  const char *match)
+{
+       struct list_head *pos;
+       char *ptr, *str;
+
+       list_for_each(pos, list) {
+               ptr = list_entry_offset(pos, char, offset);
+               str = *((char **)(ptr + soffset));
+               if (strcmp(str, match) == 0)
+                       return ptr;
+       }
+       return NULL;
+}
+
+#define find(uc_mgr, list, type, member, value, match) \
+       find0(uc_mgr, list, \
+                    (unsigned long)(&((type *)0)->member), \
+                    (unsigned long)(&((type *)0)->value), match)
+
+/**
+ * \brief Find verb
+ * \param uc_mgr Use case manager
+ * \param verb_name verb to find
+ * \return structure on success, otherwise a NULL (not found)
+ */
+static inline struct use_case_verb *find_verb(snd_use_case_mgr_t *uc_mgr,
+                                             const char *_name)
+{
+       return find(uc_mgr, &uc_mgr->verb_list,
+                   struct use_case_verb, list, name,
+                   _name);
+}
+
+/**
+ * \brief Set verb
+ * \param uc_mgr Use case manager
+ * \param verb verb to set
+ * \return zero on success, otherwise a negative error code
+ */
+static int set_verb(snd_use_case_mgr_t *uc_mgr,
+                   struct use_case_verb *verb,
+                   int enable)
+{
+       struct list_head *seq;
+       int err;
+
+       if (enable) {
+               seq = &verb->enable_list;
+       } else {
+               seq = &verb->disable_list;
+       }
+       err = execute_sequence(uc_mgr, seq);
+       if (enable && err >= 0)
+               uc_mgr->active_verb = verb;
+       return err;
+}
+
+/**
+ * \brief Init sound card use case manager.
+ * \param uc_mgr Returned use case manager pointer
+ * \param card_name name of card to open
+ * \return zero on success, otherwise a negative error code
+ */
+int snd_use_case_mgr_open(snd_use_case_mgr_t **mgr,
+                         const char *card_name)
+{
+       snd_use_case_mgr_t *uc_mgr;
+       int err;
+
+       /* create a new UCM */
+       uc_mgr = calloc(1, sizeof(snd_use_case_mgr_t));
+       if (uc_mgr == NULL)
+               return -ENOMEM;
+       INIT_LIST_HEAD(&uc_mgr->verb_list);
+       INIT_LIST_HEAD(&uc_mgr->default_list);
+       pthread_mutex_init(&uc_mgr->mutex, NULL);
+
+       uc_mgr->card_name = strdup(card_name);
+       if (uc_mgr->card_name == NULL) {
+               free(uc_mgr);
+               return -ENOMEM;
+       }
+
+       /* get info on use_cases and verify against card */
+       err = import_master_config(uc_mgr);
+       if (err < 0) {
+               uc_error("error: failed to import %s use case configuration %d",
+                       card_name, err);
+               goto err;
+       }
+
+       *mgr = uc_mgr;
+       return 0;
+
+err:
+       uc_mgr_free(uc_mgr);
+       return err;
+}
+
+/**
+ * \brief Reload and reparse all use case files.
+ * \param uc_mgr Use case manager
+ * \return zero on success, otherwise a negative error code
+ */
+int snd_use_case_mgr_reload(snd_use_case_mgr_t *uc_mgr)
+{
+       int err;
+
+       pthread_mutex_lock(&uc_mgr->mutex);
+
+       uc_mgr_free_verb(uc_mgr);
+
+       /* reload all use cases */
+       err = import_master_config(uc_mgr);
+       if (err < 0) {
+               uc_error("error: failed to reload use cases\n");
+               pthread_mutex_unlock(&uc_mgr->mutex);
+               return -EINVAL;
+       }
+
+       pthread_mutex_unlock(&uc_mgr->mutex);
+       return err;
+}
+
+/**
+ * \brief Close use case manager.
+ * \param uc_mgr Use case manager
+ * \return zero on success, otherwise a negative error code
+ */
+int snd_use_case_mgr_close(snd_use_case_mgr_t *uc_mgr)
+{
+       uc_mgr_free(uc_mgr);
+
+       return 0;
+}
+
+/**
+ * \brief Reset sound card controls to default values.
+ * \param uc_mgr Use case manager
+ * \return zero on success, otherwise a negative error code
+ */
+int snd_use_case_mgr_reset(snd_use_case_mgr_t *uc_mgr)
+{
+       struct list_head *pos, *npos;
+       struct use_case_modifier *modifier;
+       struct use_case_device *device;
+       int err;
+
+       pthread_mutex_lock(&uc_mgr->mutex);
+
+       list_for_each_safe(pos, npos, &uc_mgr->active_modifiers) {
+               modifier = list_entry(pos, struct use_case_modifier,
+                                     active_list);
+               err = disable_modifier(uc_mgr, modifier);
+               if (err < 0)
+                       uc_error("Unable to disable modifier %s", modifier->name);
+       }
+       INIT_LIST_HEAD(&uc_mgr->active_modifiers);
+
+       list_for_each_safe(pos, npos, &uc_mgr->active_devices) {
+               device = list_entry(pos, struct use_case_device,
+                                   active_list);
+               err = disable_device(uc_mgr, device);
+               if (err < 0)
+                       uc_error("Unable to disable device %s", device->name);
+       }
+       INIT_LIST_HEAD(&uc_mgr->active_devices);
+
+       err = disable_verb(uc_mgr, uc_mgr->active_verb);
+       if (err < 0) {
+               uc_error("Unable to disable verb %s", uc_mgr->active_verb->name);
+               return err;
+       }
+       uc_mgr->active_verb = NULL;
+
+       err = execute_sequence(uc_mgr, &uc_mgr->default_list);
+       
+       pthread_mutex_unlock(&uc_mgr->mutex);
+       return err;
+}
+
+#if 0
+static int enable_use_case_verb(snd_use_case_mgr_t *uc_mgr, int verb_id,
+               snd_ctl_elem_list_t *list, snd_ctl_t *handle)
+{
+       struct use_case_verb *verb;
+       int ret;
+
+       if (verb_id >= uc_mgr->num_verbs) {
+               uc_error("error: invalid verb id %d", verb_id);
+               return -EINVAL;
+       }
+       verb = &uc_mgr->verb[verb_id];
+
+       uc_dbg("verb %s", verb->name);
+       ret = exec_sequence(verb->enable, uc_mgr, list, handle);
+       if (ret < 0) {
+               uc_error("error: could not enable verb %s", verb->name);
+               return ret;
+       }
+       uc_mgr->card.current_verb = verb_id;
+
+       return 0;
+}
+
+static int disable_use_case_verb(snd_use_case_mgr_t *uc_mgr, int verb_id,
+               snd_ctl_elem_list_t *list, snd_ctl_t *handle)
+{
+       struct use_case_verb *verb;
+       int ret;
+
+       if (verb_id >= uc_mgr->num_verbs) {
+               uc_error("error: invalid verb id %d", verb_id);
+               return -EINVAL;
+       }
+       verb = &uc_mgr->verb[verb_id];
+
+       /* we set the invalid verb at open() but we should still
+        * check that this succeeded */
+       if (verb == NULL)
+               return 0;
+
+       uc_dbg("verb %s", verb->name);
+       ret = exec_sequence(verb->disable, uc_mgr, list, handle);
+       if (ret < 0) {
+               uc_error("error: could not disable verb %s", verb->name);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int enable_use_case_device(snd_use_case_mgr_t *uc_mgr,
+               int device_id, snd_ctl_elem_list_t *list, snd_ctl_t *handle)
+{
+       struct use_case_verb *verb = &uc_mgr->verb[uc_mgr->card.current_verb];
+       struct use_case_device *device = &verb->device[device_id];
+       int ret;
+
+       if (uc_mgr->card.current_verb == VERB_NOT_INITIALISED)
+               return -EINVAL;
+
+       uc_dbg("device %s", device->name);
+       ret = exec_sequence(device->enable, uc_mgr, list, handle);
+       if (ret < 0) {
+               uc_error("error: could not enable device %s", device->name);
+               return ret;
+       }
+
+       set_device_status(uc_mgr, device_id, 1);
+       return 0;
+}
+
+static int disable_use_case_device(snd_use_case_mgr_t *uc_mgr,
+               int device_id, snd_ctl_elem_list_t *list, snd_ctl_t *handle)
+{
+       struct use_case_verb *verb = &uc_mgr->verb[uc_mgr->card.current_verb];
+       struct use_case_device *device = &verb->device[device_id];
+       int ret;
+
+       if (uc_mgr->card.current_verb == VERB_NOT_INITIALISED)
+               return -EINVAL;
+
+       uc_dbg("device %s", device->name);
+       ret = exec_sequence(device->disable, uc_mgr, list, handle);
+       if (ret < 0) {
+               uc_error("error: could not disable device %s", device->name);
+               return ret;
+       }
+
+       set_device_status(uc_mgr, device_id, 0);
+       return 0;
+}
+
+static int enable_use_case_modifier(snd_use_case_mgr_t *uc_mgr,
+               int modifier_id, snd_ctl_elem_list_t *list, snd_ctl_t *handle)
+{
+       struct use_case_verb *verb = &uc_mgr->verb[uc_mgr->card.current_verb];
+       struct use_case_modifier *modifier = &verb->modifier[modifier_id];
+       int ret;
+
+       if (uc_mgr->card.current_verb == VERB_NOT_INITIALISED)
+               return -EINVAL;
+
+       uc_dbg("modifier %s", modifier->name);
+       ret = exec_sequence(modifier->enable, uc_mgr, list, handle);
+       if (ret < 0) {
+               uc_error("error: could not enable modifier %s", modifier->name);
+               return ret;
+       }
+
+       set_modifier_status(uc_mgr, modifier_id, 1);
+       return 0;
+}
+
+static int disable_use_case_modifier(snd_use_case_mgr_t *uc_mgr,
+               int modifier_id, snd_ctl_elem_list_t *list, snd_ctl_t *handle)
+{
+       struct use_case_verb *verb = &uc_mgr->verb[uc_mgr->card.current_verb];
+       struct use_case_modifier *modifier = &verb->modifier[modifier_id];
+       int ret;
+
+       if (uc_mgr->card.current_verb == VERB_NOT_INITIALISED)
+               return -EINVAL;
+
+       uc_dbg("modifier %s", modifier->name);
+       ret = exec_sequence(modifier->disable, uc_mgr, list, handle);
+       if (ret < 0) {
+               uc_error("error: could not disable modifier %s", modifier->name);
+               return ret;
+       }
+
+       set_modifier_status(uc_mgr, modifier_id, 0);
+       return 0;
+}
+
+/*
+ * Tear down current use case verb, device and modifier.
+ */
+static int dismantle_use_case(snd_use_case_mgr_t *uc_mgr,
+               snd_ctl_elem_list_t *list, snd_ctl_t *handle)
+{
+       struct use_case_verb *verb = &uc_mgr->verb[uc_mgr->card.current_verb];
+       int ret, i;
+
+       /* No active verb */
+       if (uc_mgr->card.current_verb == VERB_NOT_INITIALISED)
+               return 0;
+
+       /* disable all modifiers that are active */
+       for (i = 0; i < verb->num_modifiers; i++) {
+               if (get_modifier_status(uc_mgr,i)) {
+                       ret = disable_use_case_modifier(uc_mgr, i, list, handle);
+                       if (ret < 0)
+                               return ret;
+               }
+       }
+
+       /* disable all devices that are active */
+       for (i = 0; i < verb->num_devices; i++) {
+               if (get_device_status(uc_mgr,i)) {
+                       ret = disable_use_case_device(uc_mgr, i, list, handle);
+                       if (ret < 0)
+                               return ret;
+               }
+       }
+
+       /* disable verb */
+       ret = disable_use_case_verb(uc_mgr, uc_mgr->card.current_verb, list, handle);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+ /**
+ * \brief Dump sound card controls in format required for sequencer.
+ * \param card_name The name of the sound card to be dumped
+ * \return zero on success, otherwise a negative error code
+ */
+int snd_use_case_dump(const char *card_name)
+{
+       snd_ctl_t *handle;
+       snd_ctl_card_info_t *info;
+       snd_ctl_elem_list_t *list;
+       int ret, i, count, idx;
+       char ctl_name[8];
+
+       snd_ctl_card_info_alloca(&info);
+       snd_ctl_elem_list_alloca(&list);
+
+       idx = snd_card_get_index(card_name);
+       if (idx < 0)
+               return idx;
+       sprintf(ctl_name, "hw:%d", idx);
+
+       /* open and load snd card */
+       ret = snd_ctl_open(&handle, ctl_name, SND_CTL_READONLY);
+       if (ret < 0) {
+               uc_error("error: could not open controls for  %s: %s",
+                       card_name, snd_strerror(ret));
+               return ret;
+       }
+
+       ret = snd_ctl_card_info(handle, info);
+       if (ret < 0) {
+               uc_error("error: could not get control info for %s:%s",
+                       card_name, snd_strerror(ret));
+               goto close;
+       }
+
+       ret = snd_ctl_elem_list(handle, list);
+       if (ret < 0) {
+               uc_error("error: cannot determine controls for  %s: %s",
+                       card_name, snd_strerror(ret));
+               goto close;
+       }
+
+       count = snd_ctl_elem_list_get_count(list);
+       if (count < 0) {
+               ret = 0;
+               goto close;
+       }
+
+       snd_ctl_elem_list_set_offset(list, 0);
+       if (snd_ctl_elem_list_alloc_space(list, count) < 0) {
+               uc_error("error: not enough memory for control elements");
+               ret =  -ENOMEM;
+               goto close;
+       }
+       if ((ret = snd_ctl_elem_list(handle, list)) < 0) {
+               uc_error("error: cannot determine controls: %s",
+                       snd_strerror(ret));
+               goto free;
+       }
+
+       /* iterate through each kcontrol and add to use
+        * case manager control list */
+       for (i = 0; i < count; ++i) {
+               snd_ctl_elem_id_t *id;
+               snd_ctl_elem_id_alloca(&id);
+               snd_ctl_elem_list_get_id(list, i, id);
+
+               /* dump to stdout in friendly format */
+               ret = dump_control(handle, id);
+               if (ret < 0) {
+                       uc_error("error: control dump failed: %s",
+                               snd_strerror(ret));
+                       goto free;
+               }
+       }
+free:
+       snd_ctl_elem_list_free_space(list);
+close:
+       snd_ctl_close(handle);
+       return ret;
+}
+
+/**
+ * \brief List supported use case verbs for given soundcard
+ * \param uc_mgr use case manager
+ * \param verb returned list of supported use case verb id and names
+ * \return number of use case verbs if success, otherwise a negative error code
+ */
+int snd_use_case_get_verb_list(snd_use_case_mgr_t *uc_mgr,
+               const char **verb[])
+{
+       int ret;
+
+       pthread_mutex_lock(&uc_mgr->mutex);
+
+       *verb = uc_mgr->verb_list;
+       ret = uc_mgr->num_verbs;
+
+       pthread_mutex_unlock(&uc_mgr->mutex);
+       return ret;
+}
+
+/**
+ * \brief List supported use case devices for given verb
+ * \param uc_mgr use case manager
+ * \param verb verb id.
+ * \param device returned list of supported use case device id and names
+ * \return number of use case devices if success, otherwise a negative error code
+ */
+int snd_use_case_get_device_list(snd_use_case_mgr_t *uc_mgr,
+               const char *verb_name, const char **device[])
+{
+       struct use_case_verb *verb = NULL;
+       int i, ret = -EINVAL;
+
+       pthread_mutex_lock(&uc_mgr->mutex);
+
+       /* find verb name */
+       for (i = 0; i < uc_mgr->num_verbs; i++) {
+               verb = &uc_mgr->verb[i];
+               if (!strcmp(uc_mgr->verb[i].name, verb_name))
+                       goto found;
+       }
+
+       uc_error("error: use case verb %s not found", verb_name);
+       goto out;
+
+found:
+       *device = verb->device_list;
+       ret = verb->num_devices;
+out:
+       pthread_mutex_unlock(&uc_mgr->mutex);
+       return ret;
+}
+
+/**
+ * \brief List supported use case verb modifiers for given verb
+ * \param uc_mgr use case manager
+ * \param verb verb id.
+ * \param mod returned list of supported use case modifier id and names
+ * \return number of use case modifiers if success, otherwise a negative error code
+ */
+int snd_use_case_get_mod_list(snd_use_case_mgr_t *uc_mgr,
+               const char *verb_name, const char **mod[])
+{
+       struct use_case_verb *verb = NULL;
+       int i, ret = -EINVAL;
+
+       pthread_mutex_lock(&uc_mgr->mutex);
+
+       /* find verb name */
+       for (i = 0; i <uc_mgr->num_verbs; i++) {
+               verb = &uc_mgr->verb[i];
+               if (!strcmp(uc_mgr->verb[i].name, verb_name))
+                       goto found;
+       }
+
+       uc_error("error: use case verb %s not found", verb_name);
+       goto out;
+
+found:
+       *mod = verb->modifier_list;
+       ret = verb->num_modifiers;
+out:
+       pthread_mutex_unlock(&uc_mgr->mutex);
+       return ret;
+}
+
+static struct sequence_element *get_transition_sequence(
+               struct transition_sequence *trans_list, const char *name)
+{
+       struct transition_sequence *trans = trans_list;
+
+       while (trans) {
+               if (trans->name && !strcmp(trans->name, name))
+                       return trans->transition;
+
+               trans =  trans->next;
+       }
+
+       return NULL;
+}
+
+static int exec_transition_sequence(snd_use_case_mgr_t *uc_mgr,
+                       struct sequence_element *trans_sequence)
+{
+       int ret;
+
+       ret = exec_sequence(trans_sequence, uc_mgr, uc_mgr->list,
+                       uc_mgr->handle);
+       if (ret < 0)
+               uc_error("error: could not exec transition sequence");
+
+       return ret;
+}
+
+static int handle_transition_verb(snd_use_case_mgr_t *uc_mgr,
+               int new_verb_id)
+{
+       struct use_case_verb *old_verb = &uc_mgr->verb[uc_mgr->card.current_verb];
+       struct use_case_verb *new_verb;
+       static struct sequence_element *trans_sequence;
+
+       if (uc_mgr->card.current_verb == VERB_NOT_INITIALISED)
+               return -EINVAL;
+
+       if (new_verb_id >= uc_mgr->num_verbs) {
+               uc_error("error: invalid new_verb id %d", new_verb_id);
+               return -EINVAL;
+       }
+
+       new_verb = &uc_mgr->verb[new_verb_id];
+
+       uc_dbg("new verb %s", new_verb->name);
+
+       trans_sequence = get_transition_sequence(old_verb->transition_list,
+                                                       new_verb->name);
+       if (trans_sequence != NULL) {
+               int ret, i;
+
+               uc_dbg("find transition sequence %s->%s",
+                               old_verb->name, new_verb->name);
+
+               /* disable all modifiers that are active */
+               for (i = 0; i < old_verb->num_modifiers; i++) {
+                       if (get_modifier_status(uc_mgr,i)) {
+                               ret = disable_use_case_modifier(uc_mgr, i,
+                                       uc_mgr->list, uc_mgr->handle);
+                               if (ret < 0)
+                                       return ret;
+                       }
+               }
+
+               /* disable all devices that are active */
+               for (i = 0; i < old_verb->num_devices; i++) {
+                       if (get_device_status(uc_mgr,i)) {
+                               ret = disable_use_case_device(uc_mgr, i,
+                                       uc_mgr->list, uc_mgr->handle);
+                               if (ret < 0)
+                                       return ret;
+                       }
+               }
+
+               ret = exec_transition_sequence(uc_mgr, trans_sequence);
+               if (ret)
+                       return ret;
+
+               uc_mgr->card.current_verb = new_verb_id;
+
+               return 0;
+       }
+
+       return-EINVAL;
+}
+
+/**
+ * \brief Set new use case verb for sound card
+ * \param uc_mgr use case manager
+ * \param verb verb id
+ * \return zero if success, otherwise a negative error code
+ */
+int snd_use_case_set_verb(snd_use_case_mgr_t *uc_mgr,
+               const char *verb_name)
+{
+       int i = 0, ret = -EINVAL, inactive = 0;
+
+       pthread_mutex_lock(&uc_mgr->mutex);
+
+       uc_dbg("uc_mgr %p, verb_name %s", uc_mgr, verb_name);
+
+       /* check for "Inactive" */
+       if (!strcmp(verb_name, SND_USE_CASE_VERB_INACTIVE)) {
+               inactive = 1;
+               goto found;
+       }
+
+       /* find verb name */
+       for (i = 0; i <uc_mgr->num_verbs; i++) {
+               if (!strcmp(uc_mgr->verb[i].name, verb_name))
+                       goto found;
+       }
+
+       uc_error("error: use case verb %s not found", verb_name);
+       goto out;
+found:
+       /* use case verb found - check that we actually changing the verb */
+       if (i == uc_mgr->card.current_verb) {
+               uc_dbg("current verb ID %d", i);
+               ret = 0;
+               goto out;
+       }
+
+       if (handle_transition_verb(uc_mgr, i) == 0)
+               goto out;
+
+       /*
+        * Dismantle the old use cases by running it's verb, device and modifier
+        * disable sequences
+        */
+       ret = dismantle_use_case(uc_mgr, uc_mgr->list, uc_mgr->handle);
+       if (ret < 0) {
+               uc_error("error: failed to dismantle current use case: %s",
+                       uc_mgr->verb[i].name);
+               goto out;
+       }
+
+       /* we don't need to initialise new verb if inactive */
+       if (inactive)
+               goto out;
+
+       /* Initialise the new use case verb */
+       ret = enable_use_case_verb(uc_mgr, i, uc_mgr->list, uc_mgr->handle);
+       if (ret < 0)
+               uc_error("error: failed to initialise new use case: %s",
+                               verb_name);
+out:
+       pthread_mutex_unlock(&uc_mgr->mutex);
+
+       return ret;
+}
+
+static int config_use_case_device(snd_use_case_mgr_t *uc_mgr,
+               const char *device_name, int enable)
+{
+       struct use_case_verb *verb;
+       int ret, i;
+
+       pthread_mutex_lock(&uc_mgr->mutex);
+
+       if (uc_mgr->card.current_verb == VERB_NOT_INITIALISED) {
+               uc_error("error: no valid use case verb set\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       verb = &uc_mgr->verb[uc_mgr->card.current_verb];
+
+       uc_dbg("current verb %s", verb->name);
+       uc_dbg("uc_mgr %p device_name %s", uc_mgr, device_name);
+
+       /* find device name and index */
+       for (i = 0; i <verb->num_devices; i++) {
+               uc_dbg("verb->num_devices %s", verb->device[i].name);
+               if (!strcmp(verb->device[i].name, device_name))
+                       goto found;
+       }
+
+       uc_error("error: use case device %s not found", device_name);
+       ret = -EINVAL;
+       goto out;
+
+found:
+       if (enable) {
+               /* Initialise the new use case device */
+               ret = enable_use_case_device(uc_mgr, i, uc_mgr->list,
+                       uc_mgr->handle);
+               if (ret < 0)
+                       goto out;
+       } else {
+               /* disable the old device */
+               ret = disable_use_case_device(uc_mgr, i, uc_mgr->list,
+                       uc_mgr->handle);
+               if (ret < 0)
+                       goto out;
+       }
+
+out:
+       pthread_mutex_unlock(&uc_mgr->mutex);
+       return ret;
+}
+
+/**
+ * \brief Enable use case device
+ * \param uc_mgr Use case manager
+ * \param device the device to be enabled
+ * \return 0 = successful negative = error
+ */
+int snd_use_case_enable_device(snd_use_case_mgr_t *uc_mgr,
+               const char *device)
+{
+       return config_use_case_device(uc_mgr, device, 1);
+}
+
+/**
+ * \brief Disable use case device
+ * \param uc_mgr Use case manager
+ * \param device the device to be disabled
+ * \return 0 = successful negative = error
+ */
+int snd_use_case_disable_device(snd_use_case_mgr_t *uc_mgr,
+               const char *device)
+{
+       return config_use_case_device(uc_mgr, device, 0);
+}
+
+static struct use_case_device *get_device(snd_use_case_mgr_t *uc_mgr,
+                                                       const char *name, int *id)
+{
+       struct use_case_verb *verb;
+       int i;
+
+       if (uc_mgr->card.current_verb == VERB_NOT_INITIALISED)
+               return NULL;
+
+       verb = &uc_mgr->verb[uc_mgr->card.current_verb];
+
+       uc_dbg("current verb %s", verb->name);
+
+       for (i = 0; i < verb->num_devices; i++) {
+               uc_dbg("device %s", verb->device[i].name);
+
+               if (!strcmp(verb->device[i].name, name)) {
+                       if (id)
+                               *id = i;
+                       return &verb->device[i];
+               }
+       }
+
+       return NULL;
+}
+
+/**
+ * \brief Disable old_device and then enable new_device.
+ *        If from_device is not enabled just return.
+ *        Check transition sequence firstly.
+ * \param uc_mgr Use case manager
+ * \param old the device to be closed
+ * \param new the device to be opened
+ * \return 0 = successful negative = error
+ */
+int snd_use_case_switch_device(snd_use_case_mgr_t *uc_mgr,
+                       const char *old, const char *new)
+{
+       static struct sequence_element *trans_sequence;
+       struct use_case_device *old_device;
+       struct use_case_device *new_device;
+       int ret = 0, old_id, new_id;
+
+       uc_dbg("old %s, new %s", old, new);
+
+       pthread_mutex_lock(&uc_mgr->mutex);
+
+       old_device = get_device(uc_mgr, old, &old_id);
+       if (!old_device) {
+               uc_error("error: device %s not found", old);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (!get_device_status(uc_mgr, old_id)) {
+               uc_error("error: device %s not enabled", old);
+               goto out;
+       }
+
+       new_device = get_device(uc_mgr, new, &new_id);
+       if (!new_device) {
+               uc_error("error: device %s not found", new);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       trans_sequence = get_transition_sequence(old_device->transition_list, new);
+       if (trans_sequence != NULL) {
+
+               uc_dbg("find transition sequece %s->%s", old, new);
+
+               ret = exec_transition_sequence(uc_mgr, trans_sequence);
+               if (ret)
+                       goto out;
+
+               set_device_status(uc_mgr, old_id, 0);
+               set_device_status(uc_mgr, new_id, 1);
+       } else {
+               /* use lock in config_use_case_device */
+               pthread_mutex_unlock(&uc_mgr->mutex);
+
+               config_use_case_device(uc_mgr, old, 0);
+               config_use_case_device(uc_mgr, new, 1);
+
+               return 0;
+       }
+out:
+       pthread_mutex_unlock(&uc_mgr->mutex);
+       return ret;
+}
+
+/*
+ * Check to make sure that the modifier actually supports any of the
+ * active devices.
+ */
+static int is_modifier_valid(snd_use_case_mgr_t *uc_mgr,
+       struct use_case_verb *verb, struct use_case_modifier *modifier)
+{
+       struct dev_list *dev_list;
+       int dev;
+
+       /* check modifier list against each enabled device */
+       for (dev = 0; dev < verb->num_devices; dev++) {
+               if (!get_device_status(uc_mgr, dev))
+                       continue;
+
+               dev_list = modifier->dev_list;
+               uc_dbg("checking device %s for %s", verb->device[dev].name,
+                       dev_list->name ? dev_list->name : "");
+
+               while (dev_list) {
+                       uc_dbg("device supports %s", dev_list->name);
+                       if (!strcmp(dev_list->name, verb->device[dev].name))
+                                       return 1;
+                       dev_list = dev_list->next;
+               }
+       }
+       return 0;
+}
+
+static int config_use_case_mod(snd_use_case_mgr_t *uc_mgr,
+               const char *modifier_name, int enable)
+{
+       struct use_case_verb *verb;
+       int ret, i;
+
+       pthread_mutex_lock(&uc_mgr->mutex);
+
+       if (uc_mgr->card.current_verb == VERB_NOT_INITIALISED) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       verb = &uc_mgr->verb[uc_mgr->card.current_verb];
+
+       uc_dbg("current verb %s", verb->name);
+       uc_dbg("uc_mgr %p modifier_name %s", uc_mgr, modifier_name);
+
+       /* find modifier name */
+       for (i = 0; i <verb->num_modifiers; i++) {
+               uc_dbg("verb->num_modifiers %d %s", i, verb->modifier[i].name);
+               if (!strcmp(verb->modifier[i].name, modifier_name) &&
+                       is_modifier_valid(uc_mgr, verb, &verb->modifier[i]))
+                       goto found;
+       }
+
+       uc_error("error: use case modifier %s not found or invalid",
+               modifier_name);
+       ret = -EINVAL;
+       goto out;
+
+found:
+       if (enable) {
+               /* Initialise the new use case device */
+               ret = enable_use_case_modifier(uc_mgr, i, uc_mgr->list,
+                       uc_mgr->handle);
+               if (ret < 0)
+                       goto out;
+       } else {
+               /* disable the old device */
+               ret = disable_use_case_modifier(uc_mgr, i, uc_mgr->list,
+                       uc_mgr->handle);
+               if (ret < 0)
+                       goto out;
+       }
+
+out:
+       pthread_mutex_unlock(&uc_mgr->mutex);
+       return ret;
+}
+
+/**
+ * \brief Enable use case modifier
+ * \param uc_mgr Use case manager
+ * \param modifier the modifier to be enabled
+ * \return 0 = successful negative = error
+ */
+int snd_use_case_enable_modifier(snd_use_case_mgr_t *uc_mgr,
+               const char *modifier)
+{
+       return config_use_case_mod(uc_mgr, modifier, 1);
+}
+
+/**
+ * \brief Disable use case modifier
+ * \param uc_mgr Use case manager
+ * \param modifier the modifier to be disabled
+ * \return 0 = successful negative = error
+ */
+int snd_use_case_disable_modifier(snd_use_case_mgr_t *uc_mgr,
+               const char *modifier)
+{
+       return config_use_case_mod(uc_mgr, modifier, 0);
+}
+
+static struct use_case_modifier *get_modifier(snd_use_case_mgr_t *uc_mgr,
+                                                       const char *name, int *mod_id)
+{
+       struct use_case_verb *verb;
+       int i;
+
+       if (uc_mgr->card.current_verb == VERB_NOT_INITIALISED)
+               return NULL;
+
+       verb = &uc_mgr->verb[uc_mgr->card.current_verb];
+
+       uc_dbg("current verb %s", verb->name);
+
+       uc_dbg("uc_mgr %p modifier_name %s", uc_mgr, name);
+
+       for (i = 0; i < verb->num_modifiers; i++) {
+               uc_dbg("verb->num_devices %s", verb->modifier[i].name);
+
+               if (!strcmp(verb->modifier[i].name, name)) {
+                       if (mod_id)
+                               *mod_id = i;
+                       return &verb->modifier[i];
+               }
+       }
+
+       return NULL;
+}
+
+/**
+ * \brief Disable old_modifier and then enable new_modifier.
+ *        If old_modifier is not enabled just return.
+ *        Check transition sequence firstly.
+ * \param uc_mgr Use case manager
+ * \param old the modifier to be closed
+ * \param new the modifier to be opened
+ * \return 0 = successful negative = error
+ */
+int snd_use_case_switch_modifier(snd_use_case_mgr_t *uc_mgr,
+                       const char *old, const char *new)
+{
+       struct use_case_modifier *old_modifier;
+       struct use_case_modifier *new_modifier;
+       static struct sequence_element *trans_sequence;
+       int ret = 0, old_id, new_id
+
+       uc_dbg("old %s, new %s", old, new);
+
+       pthread_mutex_lock(&uc_mgr->mutex);
+
+       old_modifier = get_modifier(uc_mgr, old, &old_id);
+       if (!old_modifier) {
+               uc_error("error: modifier %s not found", old);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (!get_modifier_status(uc_mgr, old_id)) {
+               uc_error("error: modifier %s not enabled", old);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       new_modifier = get_modifier(uc_mgr, new, &new_id);
+       if (!new_modifier) {
+               uc_error("error: modifier %s not found", new);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       trans_sequence = get_transition_sequence(
+                               old_modifier->transition_list, new);
+       if (trans_sequence != NULL) {
+               uc_dbg("find transition sequence %s->%s", old, new);
+
+               ret = exec_transition_sequence(uc_mgr, trans_sequence);
+               if (ret)
+                       goto out;
+
+               set_device_status(uc_mgr, old_id, 0);
+               set_device_status(uc_mgr, new_id, 1);
+       } else {
+               /* use lock in config_use_case_mod*/
+               pthread_mutex_unlock(&uc_mgr->mutex);
+
+               config_use_case_mod(uc_mgr, old, 0);
+               config_use_case_mod(uc_mgr, new, 1);
+
+               return 0;
+       }
+out:
+       pthread_mutex_unlock(&uc_mgr->mutex);
+       return ret;
+}
+
+/**
+ * \brief Get current use case verb from sound card
+ * \param uc_mgr use case manager
+ * \return Verb Name if success, otherwise NULL
+ */
+const char *snd_use_case_get_verb(snd_use_case_mgr_t *uc_mgr)
+{
+       const char *ret = NULL;
+
+       pthread_mutex_lock(&uc_mgr->mutex);
+
+       if (uc_mgr->card.current_verb != VERB_NOT_INITIALISED)
+               ret = uc_mgr->verb_list[uc_mgr->card.current_verb];
+
+       pthread_mutex_unlock(&uc_mgr->mutex);
+
+       return ret;
+}
+
+/**
+ * \brief Get device status for current use case verb
+ * \param uc_mgr Use case manager
+ * \param device_name The device we are interested in.
+ * \return - 1 = enabled, 0 = disabled, negative = error
+ */
+int snd_use_case_get_device_status(snd_use_case_mgr_t *uc_mgr,
+               const char *device_name)
+{
+       struct use_case_device *device;
+       int ret = -EINVAL, dev_id;
+
+       pthread_mutex_lock(&uc_mgr->mutex);
+
+       device = get_device(uc_mgr, device_name, &dev_id);
+       if (device == NULL) {
+               uc_error("error: use case device %s not found", device_name);
+               goto out;
+       }
+
+       ret = get_device_status(uc_mgr, dev_id);
+out:
+       pthread_mutex_unlock(&uc_mgr->mutex);
+
+       return ret;
+}
+
+/**
+ * \brief Get modifier status for current use case verb
+ * \param uc_mgr Use case manager
+ * \param device_name The device we are interested in.
+ * \return - 1 = enabled, 0 = disabled, negative = error
+ */
+int snd_use_case_get_modifier_status(snd_use_case_mgr_t *uc_mgr,
+               const char *modifier_name)
+{
+       struct use_case_modifier *modifier;
+       int ret = -EINVAL, mod_id;
+
+       pthread_mutex_lock(&uc_mgr->mutex);
+
+       modifier = get_modifier(uc_mgr, modifier_name, &mod_id);
+       if (modifier == NULL) {
+               uc_error("error: use case modifier %s not found", modifier_name);
+               goto out;
+       }
+
+       ret = get_modifier_status(uc_mgr, mod_id);
+out:
+       pthread_mutex_unlock(&uc_mgr->mutex);
+
+       return ret;
+}
+
+/**
+ * \brief Get current use case verb QoS
+ * \param uc_mgr use case manager
+ * \return QoS level
+ */
+enum snd_use_case_qos
+       snd_use_case_get_verb_qos(snd_use_case_mgr_t *uc_mgr)
+{
+       struct use_case_verb *verb;
+       enum snd_use_case_qos ret = SND_USE_CASE_QOS_UNKNOWN;
+
+       pthread_mutex_lock(&uc_mgr->mutex);
+
+       if (uc_mgr->card.current_verb != VERB_NOT_INITIALISED) {
+               verb = &uc_mgr->verb[uc_mgr->card.current_verb];
+               ret = verb->qos;
+       }
+
+       pthread_mutex_unlock(&uc_mgr->mutex);
+
+       return ret;
+}
+
+/**
+ * \brief Get current use case modifier QoS
+ * \param uc_mgr use case manager
+ * \return QoS level
+ */
+enum snd_use_case_qos
+       snd_use_case_get_mod_qos(snd_use_case_mgr_t *uc_mgr,
+                                       const char *modifier_name)
+{
+       struct use_case_modifier *modifier;
+       enum snd_use_case_qos ret = SND_USE_CASE_QOS_UNKNOWN;
+
+       pthread_mutex_lock(&uc_mgr->mutex);
+
+       modifier = get_modifier(uc_mgr, modifier_name, NULL);
+       if (modifier != NULL)
+               ret = modifier->qos;
+       else
+               uc_error("error: use case modifier %s not found", modifier_name);
+       pthread_mutex_unlock(&uc_mgr->mutex);
+
+       return ret;
+}
+
+/**
+ * \brief Get current use case verb playback PCM
+ * \param uc_mgr use case manager
+ * \return PCM number if success, otherwise negative
+ */
+int snd_use_case_get_verb_playback_pcm(snd_use_case_mgr_t *uc_mgr)
+{
+       struct use_case_verb *verb;
+       int ret = -EINVAL;
+
+       pthread_mutex_lock(&uc_mgr->mutex);
+
+       if (uc_mgr->card.current_verb != VERB_NOT_INITIALISED) {
+               verb = &uc_mgr->verb[uc_mgr->card.current_verb];
+               ret = verb->playback_pcm;
+       }
+
+       pthread_mutex_unlock(&uc_mgr->mutex);
+
+       return ret;
+}
+
+/**
+ * \brief Get current use case verb playback PCM
+ * \param uc_mgr use case manager
+ * \return PCM number if success, otherwise negative
+ */
+int snd_use_case_get_verb_capture_pcm(snd_use_case_mgr_t *uc_mgr)
+{
+       struct use_case_verb *verb;
+       int ret = -EINVAL;
+
+       pthread_mutex_lock(&uc_mgr->mutex);
+
+       if (uc_mgr->card.current_verb != VERB_NOT_INITIALISED) {
+               verb = &uc_mgr->verb[uc_mgr->card.current_verb];
+               ret = verb->capture_pcm;
+       }
+
+       pthread_mutex_unlock(&uc_mgr->mutex);
+
+       return ret;
+}
+
+/**
+ * \brief Get current use case modifier playback PCM
+ * \param uc_mgr use case manager
+ * \return PCM number if success, otherwise negative
+ */
+int snd_use_case_get_mod_playback_pcm(snd_use_case_mgr_t *uc_mgr,
+                                       const char *modifier_name)
+{
+       struct use_case_modifier *modifier;
+       int ret = -EINVAL;
+
+       pthread_mutex_lock(&uc_mgr->mutex);
+
+       modifier = get_modifier(uc_mgr, modifier_name, NULL);
+       if (modifier == NULL)
+               uc_error("error: use case modifier %s not found",
+                                               modifier_name);
+       else
+               ret = modifier->playback_pcm;
+
+       pthread_mutex_unlock(&uc_mgr->mutex);
+
+       return ret;
+}
+
+/**
+ * \brief Get current use case modifier playback PCM
+ * \param uc_mgr use case manager
+ * \return PCM number if success, otherwise negative
+ */
+int snd_use_case_get_mod_capture_pcm(snd_use_case_mgr_t *uc_mgr,
+       const char *modifier_name)
+{
+       struct use_case_modifier *modifier;
+       int ret = -EINVAL;
+
+       pthread_mutex_lock(&uc_mgr->mutex);
+
+       modifier = get_modifier(uc_mgr, modifier_name, NULL);
+       if (modifier == NULL)
+               uc_error("error: use case modifier %s not found",
+                                               modifier_name);
+       else
+               ret = modifier->capture_pcm;
+
+       pthread_mutex_unlock(&uc_mgr->mutex);
+
+       return ret;
+}
+
+/**
+ * \brief Get volume/mute control name depending on use case device.
+ * \param uc_mgr use case manager
+ * \param type the control type we are looking for
+ * \param device_name The use case device we are interested in.
+ * \return control name if success, otherwise NULL
+ *
+ * Get the control id for common volume and mute controls that are aliased
+ * in the named use case device.
+ */
+const char *snd_use_case_get_device_ctl_elem_name(snd_use_case_mgr_t *uc_mgr,
+               enum snd_use_case_control_alias type, const char *device_name)
+{
+       struct use_case_device *device;
+       const char *kcontrol_name = NULL;
+
+       pthread_mutex_lock(&uc_mgr->mutex);
+
+       device = get_device(uc_mgr, device_name, NULL);
+       if (!device) {
+               uc_error("error: device %s not found", device_name);
+               goto out;
+       }
+
+       switch (type) {
+       case SND_USE_CASE_ALIAS_PLAYBACK_VOLUME:
+               kcontrol_name = device->playback_volume_id;
+               break;
+       case SND_USE_CASE_ALIAS_CAPTURE_VOLUME:
+               kcontrol_name = device->capture_volume_id;
+               break;
+       case SND_USE_CASE_ALIAS_PLAYBACK_SWITCH:
+               kcontrol_name = device->playback_switch_id;
+               break;
+       case SND_USE_CASE_ALIAS_CAPTURE_SWITCH:
+               kcontrol_name = device->capture_switch_id;
+               break;
+       default:
+               uc_error("error: invalid control alias %d", type);
+               break;
+       }
+
+out:
+       pthread_mutex_unlock(&uc_mgr->mutex);
+
+       return kcontrol_name;
+}
+
+/**
+ * \brief Get volume/mute control IDs depending on use case modifier.
+ * \param uc_mgr use case manager
+ * \param type the control type we are looking for
+ * \param modifier_name The use case modifier we are interested in.
+ * \return ID if success, otherwise a negative error code
+ *
+ * Get the control id for common volume and mute controls that are aliased
+ * in the named use case device.
+ */
+const char *snd_use_case_get_modifier_ctl_elem_name(snd_use_case_mgr_t *uc_mgr,
+               enum snd_use_case_control_alias type, const char *modifier_name)
+{
+       struct use_case_modifier *modifier;
+       const char *kcontrol_name = NULL;
+
+       pthread_mutex_lock(&uc_mgr->mutex);
+
+       modifier = get_modifier(uc_mgr, modifier_name, NULL);
+       if (!modifier) {
+               uc_error("error: modifier %s not found", modifier_name);
+               goto out;
+       }
+
+       switch (type) {
+       case SND_USE_CASE_ALIAS_PLAYBACK_VOLUME:
+               kcontrol_name = modifier->playback_volume_id;
+               break;
+       case SND_USE_CASE_ALIAS_CAPTURE_VOLUME:
+               kcontrol_name = modifier->capture_volume_id;
+               break;
+       case SND_USE_CASE_ALIAS_PLAYBACK_SWITCH:
+               kcontrol_name = modifier->playback_switch_id;
+               break;
+       case SND_USE_CASE_ALIAS_CAPTURE_SWITCH:
+               kcontrol_name = modifier->capture_switch_id;
+               break;
+       default:
+               uc_error("error: invalid control alias %d", type);
+               break;
+       }
+
+out:
+       pthread_mutex_unlock(&uc_mgr->mutex);
+
+       return kcontrol_name;
+}
+#endif
diff --git a/src/ucm/parser.c b/src/ucm/parser.c
new file mode 100644 (file)
index 0000000..bb04751
--- /dev/null
@@ -0,0 +1,956 @@
+/*
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *  Support for the verb/device/modifier core logic and API,
+ *  command line tool and file parser was kindly sponsored by
+ *  Texas Instruments Inc.
+ *  Support for multiple active modifiers and devices,
+ *  transition sequences, multiple client access and user defined use
+ *  cases was kindly sponsored by Wolfson Microelectronics PLC.
+ *
+ *  Copyright (C) 2008-2010 SlimLogic Ltd
+ *  Copyright (C) 2010 Wolfson Microelectronics PLC
+ *  Copyright (C) 2010 Texas Instruments Inc.
+ *  Copyright (C) 2010 Red Hat Inc.
+ *  Authors: Liam Girdwood <lrg@slimlogic.co.uk>
+ *              Stefan Schmidt <stefan@slimlogic.co.uk>
+ *              Justin Xu <justinx@slimlogic.co.uk>
+ *               Jaroslav Kysela <perex@perex.cz>
+ */
+
+#include "ucm_local.h"
+
+static int parse_sequence(snd_use_case_mgr_t *uc_mgr,
+                         struct list_head *base,
+                         snd_config_t *cfg);
+
+/*
+ * Parse string
+ */
+int parse_string(snd_config_t *n, char **res)
+{
+       int err;
+
+       err = snd_config_get_string(n, (const char **)res);
+       if (err < 0)
+               return err;
+       *res = strdup(*res);
+       if (*res == NULL)
+               return -ENOMEM;
+       return 0;
+}
+
+
+/*
+ * Parse transition
+ */
+static int parse_transition(snd_use_case_mgr_t *uc_mgr,
+                           struct list_head *tlist,
+                           snd_config_t *cfg)
+{
+       struct transition_sequence *tseq;
+       const char *id;
+       snd_config_iterator_t i, next;
+       snd_config_t *n;
+       int err;
+
+       if (snd_config_get_id(cfg, &id) < 0)
+               return -EINVAL;
+
+       tseq = calloc(1, sizeof(*tseq));
+       if (tseq == NULL)
+               return -ENOMEM;
+       INIT_LIST_HEAD(&tseq->transition_list);
+
+       tseq->name = strdup(id);
+       if (tseq->name == NULL) {
+               free(tseq);
+               return -ENOMEM;
+       }
+       
+       if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
+               uc_error("compound type expected for %s", id);
+               err = -EINVAL;
+               goto __err;
+       }
+       /* parse master config sections */
+       snd_config_for_each(i, next, cfg) {
+               n = snd_config_iterator_entry(i);
+
+               if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
+                       uc_error("compound type expected for %s", id);
+                       err = -EINVAL;
+                       goto __err;
+               }
+               
+               err = parse_sequence(uc_mgr, &tseq->transition_list, n);
+               if (err < 0)
+                       return err;
+       }
+
+       list_add(&tseq->list, tlist);
+       return 0;
+      __err:
+       free(tseq->name);
+       free(tseq);
+       return err;
+}
+
+/*
+ * Parse compound
+ */
+static int parse_compound(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg,
+         int (*fcn)(snd_use_case_mgr_t *, snd_config_t *, void *, void *),
+         void *data1, void *data2)
+{
+       const char *id;
+       snd_config_iterator_t i, next;
+       snd_config_t *n;
+       int err;
+
+       if (snd_config_get_id(cfg, &id) < 0)
+               return -EINVAL;
+       
+       if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
+               uc_error("compound type expected for %s", id);
+               return -EINVAL;
+       }
+       /* parse master config sections */
+       snd_config_for_each(i, next, cfg) {
+               n = snd_config_iterator_entry(i);
+
+               if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
+                       uc_error("compound type expected for %s", id);
+                       return -EINVAL;
+               }
+               
+               err = fcn(uc_mgr, n, data1, data2);
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
+/*
+ * Parse sequences.
+ *
+ * Sequence controls elements  are in the following form:-
+ *
+ * cset "element_id_syntax value_syntax"
+ * usleep time
+ * exec "any unix command with arguments"
+ *
+ * e.g.
+ *     cset "name='Master Playback Switch' 0,0"
+ *      cset "iface=PCM,name='Disable HDMI',index=1 0"
+ */
+static int parse_sequence(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED,
+                         struct list_head *base,
+                         snd_config_t *cfg)
+{
+       struct sequence_element *curr;
+       snd_config_iterator_t i, next, j, next2;
+       snd_config_t *n, *n2;
+       int err;
+
+       snd_config_for_each(i, next, cfg) {
+               n = snd_config_iterator_entry(i);
+               snd_config_for_each(j, next2, n) {
+                       const char *id;
+                       n2 = snd_config_iterator_entry(i);
+                       err = snd_config_get_id(n2, &id);
+                       if (err < 0)
+                               continue;
+
+                       /* alloc new sequence element */
+                       curr = calloc(1, sizeof(struct sequence_element));
+                       if (curr == NULL)
+                               return -ENOMEM;
+                       list_add_tail(&curr->list, base);
+
+                       if (strcmp(id, "cset") == 0) {
+                               curr->type = SEQUENCE_ELEMENT_TYPE_CSET;
+                               err = parse_string(n2, &curr->data.cset);
+                               if (err < 0) {
+                                       uc_error("error: cset requires a string!");
+                                       return err;
+                               }
+                               continue;
+                       }
+
+                       if (strcmp(id, "usleep") == 0) {
+                               curr->type = SEQUENCE_ELEMENT_TYPE_SLEEP;
+                               err = snd_config_get_integer(n2, &curr->data.sleep);
+                               if (err < 0) {
+                                       uc_error("error: usleep requires integer!");
+                                       return err;
+                               }
+                               continue;
+                       }
+
+                       if (strcmp(id, "exec") == 0) {
+                               curr->type = SEQUENCE_ELEMENT_TYPE_EXEC;
+                               err = parse_string(n2, &curr->data.exec);
+                               if (err < 0) {
+                                       uc_error("error: exec requires a string!");
+                                       return err;
+                               }
+                               continue;
+                       }
+                       
+                       list_del(&curr->list);
+                       uc_mgr_free_sequence_element(curr);
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * Parse Modifier Use cases
+ *
+ *     # Each modifier is described in new section. N modifier are allowed
+ *     SectionModifier."Capture Voice" {
+ *
+ *             Comment "Record voice call"
+ *             SupportedDevice [
+ *                     "x"
+ *                     "y"
+ *             ]
+ *
+ *             EnableSequence [
+ *                     ....
+ *             ]
+ *
+ *             DisableSequence [
+ *                     ...
+ *             ]
+ *
+ *             # Optional TQ and ALSA PCMs
+ *             TQ Voice
+ *             CapturePCM "hw:1"
+ *             MasterPlaybackVolume "name='Master Playback Volume',index=2"
+ *             MasterPlaybackSwitch "name='Master Playback Switch',index=2"
+ *
+ *      }
+ */
+static int parse_modifier(snd_use_case_mgr_t *uc_mgr,
+               snd_config_t *cfg,
+               void *data1,
+               void *data2 ATTRIBUTE_UNUSED)
+{
+       struct use_case_verb *verb = data1;
+       struct use_case_modifier *modifier;
+       const char *id;
+       snd_config_iterator_t i, next;
+       snd_config_t *n;
+       int err;
+
+       /* allocate modifier */
+       modifier = calloc(1, sizeof(*modifier));
+       if (modifier == NULL)
+               return -ENOMEM;
+       INIT_LIST_HEAD(&modifier->enable_list);
+       INIT_LIST_HEAD(&modifier->disable_list);
+       INIT_LIST_HEAD(&modifier->transition_list);
+       INIT_LIST_HEAD(&modifier->dev_list);
+       list_add_tail(&modifier->list, &verb->modifier_list);
+       err = snd_config_get_id(cfg, &id);
+       if (err < 0)
+               return err;
+       modifier->name = strdup(id);
+       if (modifier->name == NULL)
+               return -EINVAL;
+
+       snd_config_for_each(i, next, cfg) {
+               const char *id;
+               n = snd_config_iterator_entry(i);
+               if (snd_config_get_id(n, &id) < 0)
+                       continue;
+
+               if (strcmp(id, "Comment") == 0) {
+                       err = parse_string(n, &modifier->comment);
+                       if (err < 0) {
+                               uc_error("error: failed to get modifier comment");
+                               return err;
+                       }
+                       continue;
+               }
+
+               if (strcmp(id, "SupportedDevice") == 0) {
+                       struct dev_list *sdev;
+                       
+                       sdev = calloc(1, sizeof(struct dev_list));
+                       if (sdev == NULL)
+                               return -ENOMEM;
+                       err = parse_string(n, &sdev->name);
+                       if (err < 0) {
+                               free(sdev);
+                               return err;
+                       }
+                       list_add(&sdev->list, &modifier->dev_list);
+                       continue;
+               }
+
+               if (strcmp(id, "EnableSequence") == 0) {
+                       err = parse_sequence(uc_mgr, &modifier->enable_list, n);
+                       if (err < 0) {
+                               uc_error("error: failed to parse modifier"
+                                       " enable sequence");
+                               return err;
+                       }
+                       continue;
+               }
+
+               if (strcmp(id, "DisableSequence") == 0) {
+                       err = parse_sequence(uc_mgr, &modifier->disable_list, n);
+                       if (err < 0) {
+                               uc_error("error: failed to parse modifier"
+                                       " disable sequence");
+                               return err;
+                       }
+                       continue;
+               }
+
+               if (strcmp(id, "TransitionModifier") == 0) {
+                       err = parse_transition(uc_mgr, &modifier->transition_list, n);
+                       if (err < 0) {
+                               uc_error("error: failed to parse transition"
+                                       " modifier");
+                               return err;
+                       }
+                       continue;
+               }
+
+               if (strcmp(id, "TQ") == 0) {
+                       err = parse_string(n, &modifier->tq);
+                       if (err < 0) {
+                               uc_error("error: failed to parse TQ");
+                               return err;
+                       }
+                       continue;
+               }
+
+               if (strcmp(id, "CapturePCM") == 0) {
+                       err = parse_string(n, &modifier->capture_pcm);
+                       if (err < 0) {
+                               uc_error("error: failed to get Capture PCM ID");
+                               return err;
+                       }
+                       continue;
+               }
+
+               if (strcmp(id, "PlaybackPCM") == 0) {
+                       err = parse_string(n, &modifier->playback_pcm);
+                       if (err < 0) {
+                               uc_error("error: failed to get Playback PCM ID");
+                               return err;
+                       }
+                       continue;
+               }
+
+               if (strcmp(id, "MasterPlaybackVolume") == 0) {
+                       err = parse_string(n, &modifier->playback_volume_id);
+                       if (err < 0) {
+                               uc_error("error: failed to get MasterPlaybackVolume");
+                               return err;
+                       }
+                       continue;
+               }
+
+               if (strcmp(id, "MasterPlaybackSwitch") == 0) {
+                       err = parse_string(n, &modifier->playback_switch_id);
+                       if (err < 0) {
+                               uc_error("error: failed to get MasterPlaybackSwitch");
+                               return err;
+                       }
+                       continue;
+               }
+
+               if (strcmp(id, "MasterCaptureVolume") == 0) {
+                       err = parse_string(n, &modifier->capture_volume_id);
+                       if (err < 0) {
+                               uc_error("error: failed to get MasterCaptureVolume");
+                               return err;
+                       }
+                       continue;
+               }
+
+               if (strcmp(id, "MasterCaptureSwitch") == 0) {
+                       err = parse_string(n, &modifier->capture_switch_id);
+                       if (err < 0) {
+                               uc_error("error: failed to get MasterCaptureSwitch");
+                               return err;
+                       }
+                       continue;
+               }
+       }
+
+       if (list_empty(&modifier->dev_list)) {
+               uc_error("error: %s: modifier missing supported device sequence");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/*
+ * Parse Device Use Cases
+ *
+ *# Each device is described in new section. N devices are allowed
+ *SectionDevice."Headphones".0 {
+ *     Comment "Headphones connected to 3.5mm jack"
+ *
+ *     EnableSequence [
+ *             ....
+ *     ]
+ *
+ *     DisableSequence [
+ *             ...
+ *     ]
+ *
+ *     MasterPlaybackVolume "name='Master Playback Volume',index=2"
+ *     MasterPlaybackSwitch "name='Master Playback Switch',index=2"
+ *
+ * }
+ */
+static int parse_device_index(snd_use_case_mgr_t *uc_mgr,
+                             snd_config_t *cfg,
+                             void *data1,
+                             void *data2)
+{
+       struct use_case_verb *verb = data1;
+       char *name = data2;
+       struct use_case_device *device;
+       const char *id;
+       snd_config_iterator_t i, next;
+       snd_config_t *n;
+       int err;
+       
+       device = calloc(1, sizeof(*device));
+       if (device == NULL)
+               return -ENOMEM;
+       INIT_LIST_HEAD(&device->enable_list);
+       INIT_LIST_HEAD(&device->disable_list);
+       INIT_LIST_HEAD(&device->transition_list);
+       list_add_tail(&device->list, &verb->device_list);
+       device->name = strdup(name);
+       if (device->name == NULL)
+               return -ENOMEM;
+       if (snd_config_get_id(cfg, &id) < 0)
+               return -EINVAL;
+       err = safe_strtol(id, &device->idx);
+       if (err < 0) {
+               uc_error("Invalid device index '%s'", id);
+               return -EINVAL;
+       }
+
+       snd_config_for_each(i, next, cfg) {
+               const char *id;
+               n = snd_config_iterator_entry(i);
+               if (snd_config_get_id(n, &id) < 0)
+                       continue;
+
+               if (strcmp(id, "Comment") == 0) {
+                       err = parse_string(n, &device->comment);
+                       if (err < 0) {
+                               uc_error("error: failed to get device comment");
+                               return err;
+                       }
+                       continue;
+               }
+
+               if (strcmp(id, "EnableSequence") == 0) {
+                       uc_dbg("EnableSequence");
+                       err = parse_sequence(uc_mgr, &device->enable_list, n);
+                       if (err < 0) {
+                               uc_error("error: failed to parse device enable"
+                                        " sequence");
+                               return err;
+                       }
+                       continue;
+               }
+
+               if (strcmp(id, "DisableSequence") == 0) {
+                       uc_dbg("DisableSequence");
+                       err = parse_sequence(uc_mgr, &device->disable_list, n);
+                       if (err < 0) {
+                               uc_error("error: failed to parse device disable"
+                                        " sequence");
+                               return err;
+                       }
+                       continue;
+               }
+
+               if (strcmp(id, "TransitionDevice") == 0) {
+                       uc_dbg("TransitionDevice");
+                       err = parse_transition(uc_mgr, &device->transition_list, n);
+                       if (err < 0) {
+                               uc_error("error: failed to parse transition"
+                                       " device");
+                               return err;
+                       }
+                       continue;
+               }
+
+               if (strcmp(id, "MasterPlaybackVolume") == 0) {
+                       err = parse_string(n, &device->playback_volume_id);
+                       if (err < 0) {
+                               uc_error("error: failed to get MasterPlaybackVolume");
+                               return err;
+                       }
+                       continue;
+               }
+
+               if (strcmp(id, "MasterPlaybackSwitch") == 0) {
+                       err = parse_string(n, &device->playback_switch_id);
+                       if (err < 0) {
+                               uc_error("error: failed to get MasterPlaybackSwitch");
+                               return err;
+                       }
+                       continue;
+               }
+
+               if (strcmp(id, "MasterCaptureVolume") == 0) {
+                       err = parse_string(n, &device->capture_volume_id);
+                       if (err < 0) {
+                               uc_error("error: failed to get MasterCaptureVolume");
+                               return err;
+                       }
+                       continue;
+               }
+
+               if (strcmp(id, "MasterCaptureSwitch") == 0) {
+                       err = parse_string(n, &device->capture_switch_id);
+                       if (err < 0) {
+                               uc_error("error: failed to get MasterCaptureSwitch");
+                               return err;
+                       }
+                       continue;
+               }
+       }
+       return 0;
+}
+
+static int parse_device_name(snd_use_case_mgr_t *uc_mgr,
+                            snd_config_t *cfg,
+                            void *data1,
+                            void *data2 ATTRIBUTE_UNUSED)
+{
+       const char *id;
+       int err;
+
+       err = snd_config_get_id(cfg, &id);
+       if (err < 0)
+               return err;
+       return parse_compound(uc_mgr, cfg, parse_device_index,
+                             data1, (void *)id);
+}
+
+static int parse_device(snd_use_case_mgr_t *uc_mgr,
+                       struct use_case_verb *verb,
+                       snd_config_t *cfg)
+{
+       return parse_compound(uc_mgr, cfg, parse_device_name, verb, NULL);
+}
+
+/*
+ * Parse Verb Section
+ *
+ * # Example Use case verb section for Voice call blah
+ * # By Joe Blogs <joe@blogs.com>
+ *
+ * SectionVerb {
+ *     # enable and disable sequences are compulsory
+ *     EnableSequence [
+ *             cset "name='Master Playback Switch',index=2 0,0"
+ *             cset "name='Master Playback Volume':index=2 25,25"
+ *             msleep 50
+ *             cset "name='Master Playback Switch',index=2 1,1"
+ *             cset "name='Master Playback Volume',index=2 50,50"
+ *     ]
+ *
+ *     DisableSequence [
+ *             cset "name='Master Playback Switch',index=2 0,0"
+ *             cset "name='Master Playback Volume',index=2 25,25"
+ *             msleep 50
+ *             cset "name='Master Playback Switch',index=2 1,1"
+ *             cset "name='Master Playback Volume',index=2 50,50"
+ *     ]
+ *
+ *     # Optional TQ and ALSA PCMs
+ *     TQ HiFi
+ *     CapturePCM 0
+ *     PlaybackPCM 0
+ *
+ * }
+ */
+static int parse_verb(snd_use_case_mgr_t *uc_mgr,
+                     struct use_case_verb *verb,
+                     snd_config_t *cfg)
+{
+       snd_config_iterator_t i, next;
+       snd_config_t *n;
+       int err;
+       
+       /* parse verb section */
+       snd_config_for_each(i, next, cfg) {
+               const char *id;
+               n = snd_config_iterator_entry(i);
+               if (snd_config_get_id(n, &id) < 0)
+                       continue;
+
+               if (strcmp(id, "EnableSequence") == 0) {
+                       uc_dbg("Parse EnableSequence");
+                       err = parse_sequence(uc_mgr, &verb->enable_list, cfg);
+                       if (err < 0) {
+                               uc_error("error: failed to parse verb enable sequence");
+                               return err;
+                       }
+                       continue;
+               }
+
+               if (strcmp(id, "DisableSequence") == 0) {
+                       uc_dbg("Parse DisableSequence");
+                       err = parse_sequence(uc_mgr, &verb->disable_list, cfg);
+                       if (err < 0) {
+                               uc_error("error: failed to parse verb disable sequence");
+                               return err;
+                       }
+                       continue;
+               }
+
+               if (strcmp(id, "TransitionVerb") == 0) {
+                       uc_dbg("Parse TransitionVerb");
+                       err = parse_transition(uc_mgr, &verb->transition_list, n);
+                       if (err < 0) {
+                               uc_error("error: failed to parse transition verb");
+                               return err;
+                       }
+                       continue;
+               }
+
+               if (strcmp(id, "TQ") == 0) {
+                       uc_dbg("Parse TQ");
+                       err = parse_string(n, &verb->tq);
+                       if (err < 0)
+                               return err;
+                       continue;
+               }
+
+               if (strcmp(id, "CapturePCM") == 0) {
+                       uc_dbg("Parse CapturePCM");
+                       err = parse_string(n, &verb->capture_pcm);
+                       if (err < 0)
+                               return err;
+                       continue;
+               }
+
+               if (strcmp(id, "PlaybackPCM") == 0) {
+                       uc_dbg("Parse PlaybackPCM");
+                       err = parse_string(n, &verb->playback_pcm);
+                       if (err < 0)
+                               return err;
+                       continue;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * Parse a Use case verb file.
+ *
+ * This file contains the following :-
+ *  o Verb enable and disable sequences.
+ *  o Supported Device enable and disable sequences for verb.
+ *  o Supported Modifier enable and disable sequences for verb
+ *  o Optional QoS for the verb and modifiers.
+ *  o Optional PCM device ID for verb and modifiers
+ *  o Alias kcontrols IDs for master and volumes and mutes.
+ */
+static int parse_verb_file(snd_use_case_mgr_t *uc_mgr,
+                          const char *use_case_name,
+                          const char *comment,
+                          const char *file)
+{
+       snd_config_iterator_t i, next;
+       snd_config_t *n;
+       struct use_case_verb *verb;
+       snd_config_t *cfg;
+       char filename[MAX_FILE];
+       int err;
+
+       /* allocate verb */
+       verb = calloc(1, sizeof(struct use_case_verb));
+       if (verb == NULL)
+               return -ENOMEM;
+       INIT_LIST_HEAD(&verb->enable_list);
+       INIT_LIST_HEAD(&verb->disable_list);
+       INIT_LIST_HEAD(&verb->transition_list);
+       INIT_LIST_HEAD(&verb->device_list);
+       INIT_LIST_HEAD(&verb->modifier_list);
+       list_add_tail(&verb->list, &uc_mgr->verb_list);
+       verb->name = strdup(use_case_name);
+       if (verb->name == NULL)
+               return -ENOMEM;
+       verb->comment = strdup(comment);
+       if (verb->comment == NULL)
+               return -ENOMEM;
+
+       /* open Verb file for reading */
+       snprintf(filename, sizeof(filename), "%s/%s/%s", ALSA_USE_CASE_DIR,
+               uc_mgr->card_name, file);
+       filename[sizeof(filename)-1] = '\0';
+       
+       err = uc_mgr_config_load(filename, &cfg);
+       if (err < 0) {
+               uc_error("error: failed to open verb file %s : %d",
+                       filename, -errno);
+               return err;
+       }
+
+       /* parse master config sections */
+       snd_config_for_each(i, next, cfg) {
+               const char *id;
+               n = snd_config_iterator_entry(i);
+               if (snd_config_get_id(n, &id) < 0)
+                       continue;
+
+               /* find verb section and parse it */
+               if (strcmp(id, "SectionVerb") == 0) {
+                       err = parse_verb(uc_mgr, verb, n);
+                       if (err < 0) {
+                               uc_error("error: %s failed to parse verb",
+                                               file);
+                               return err;
+                       }
+                       continue;
+               }
+
+               /* find device sections and parse them */
+               if (strcmp(id, "SectionDevice") == 0) {
+                       err = parse_device(uc_mgr, verb, n);
+                       if (err < 0) {
+                               uc_error("error: %s failed to parse device",
+                                               file);
+                               return err;
+                       }
+                       continue;
+               }
+
+               /* find modifier sections and parse them */
+               if (strcmp(id, "SectionModifier") == 0) {
+                       err = parse_compound(uc_mgr, n,
+                                            parse_modifier, verb, NULL);
+                       if (err < 0) {
+                               uc_error("error: %s failed to parse modifier",
+                                               file);
+                               return err;
+                       }
+                       continue;
+               }
+       }
+
+       /* use case verb must have at least 1 device */
+       if (list_empty(&verb->device_list)) {
+               uc_error("error: no use case device defined", file);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/*
+ * Parse master section for "Use Case" and "File" tags.
+ */
+static int parse_master_section(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg,
+                               void *data1 ATTRIBUTE_UNUSED,
+                               void *data2 ATTRIBUTE_UNUSED)
+{
+       snd_config_iterator_t i, next;
+       snd_config_t *n;
+       const char *use_case_name, *file = NULL, *comment = NULL;
+       int err;
+
+       if (snd_config_get_id(cfg, &use_case_name) < 0) {
+               uc_error("unable to get name for use case section");
+               return -EINVAL;
+       }
+
+       if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
+               uc_error("compound type expected for use case section");
+               return -EINVAL;
+       }
+       /* parse master config sections */
+       snd_config_for_each(i, next, cfg) {
+               const char *id;
+               n = snd_config_iterator_entry(i);
+               if (snd_config_get_id(n, &id) < 0)
+                       continue;
+
+               /* get use case verb file name */
+               if (strcmp(id, "File") == 0) {
+                       err = snd_config_get_string(n, &file);
+                       if (err < 0) {
+                               uc_error("failed to get File");
+                               return err;
+                       }
+                       continue;
+               }
+
+               /* get optional use case comment */
+               if (strncmp(id, "Comment", 7) == 0) {
+                       err = snd_config_get_string(n, &comment);
+                       if (err < 0) {
+                               uc_error("error: failed to get Comment");
+                               return err;
+                       }
+                       continue;
+               }
+
+               uc_error("unknown field %s in master section");
+       }
+
+       uc_dbg("use_case_name %s file %s end %d", use_case_name, file, end);
+
+       /* do we have both use case name and file ? */
+       if (!file) {
+               uc_error("error: use case missing file");
+               return -EINVAL;
+       }
+
+       /* parse verb file */
+       return parse_verb_file(uc_mgr, use_case_name, comment, file);
+}
+
+/*
+ * parse and execute controls
+ */
+static int parse_controls(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
+{
+       struct list_head list;
+       int err;
+       
+       INIT_LIST_HEAD(&list);
+       err = parse_sequence(uc_mgr, &list, cfg);
+       if (err < 0) {
+               uc_error("Unable to parse SectionDefaults");
+               return err;
+       }
+       printf("parse_controls - not yet implemented\n");
+       return 0;
+}
+
+/*
+ * Each sound card has a master sound card file that lists all the supported
+ * use case verbs for that sound card. i.e.
+ *
+ * #Example master file for blah sound card
+ * #By Joe Blogs <joe@bloggs.org>
+ *
+ * # The file is divided into Use case sections. One section per use case verb.
+ *
+ * SectionUseCase."Voice Call" {
+ *             File "voice_call_blah"
+ *             Comment "Make a voice phone call."
+ * }
+ *
+ * SectionUseCase."HiFi" {
+ *             File "hifi_blah"
+ *             Comment "Play and record HiFi quality Music."
+ * }
+ *
+ * # This file also stores the default sound card state.
+ *
+ * SectionDefaults [
+ *             cset "name='Master Playback Switch',index=2 1,1"
+ *             cset "name='Master Playback Volume',index=2 25,25"
+ *             cset "name='Master Mono Playback',index=1 0"
+ *             cset "name='Master Mono Playback Volume',index=1 0"
+ *             cset "name='PCM Switch',index=2 1,1"
+ *              exec "some binary here"
+ *              msleep 50
+ *             ........
+ * ]
+ *
+ * # End of example file.
+ */
+static int parse_master_file(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
+{
+       snd_config_iterator_t i, next;
+       snd_config_t *n;
+       int ret;
+
+       if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
+               uc_error("compound type expected for master file");
+               return -EINVAL;
+       }
+
+       /* parse master config sections */
+       snd_config_for_each(i, next, cfg) {
+               const char *id;
+               n = snd_config_iterator_entry(i);
+               if (snd_config_get_id(n, &id) < 0)
+                       continue;
+
+               /* find use case section and parse it */
+               if (strcmp(id, "SectionUseCase") == 0) {
+                       ret = parse_compound(uc_mgr, n,
+                                            parse_master_section,
+                                            NULL, NULL);
+                       if (ret < 0)
+                               return ret;
+                       continue;
+               }
+
+               /* find default control values section and parse it */
+               if (strcmp(id, "SectionDefaults") == 0) {
+                       ret = parse_controls(uc_mgr, n);
+                       if (ret < 0)
+                               return ret;
+                       continue;
+               }
+               uc_error("uknown master file field %s", id);
+       }
+       return 0;
+}
+
+/* load master use case file for sound card */
+int uc_mgr_import_master_config(snd_use_case_mgr_t *uc_mgr)
+{
+       char filename[MAX_FILE];
+       snd_config_t *cfg;
+       int err;
+
+       snprintf(filename, sizeof(filename)-1,
+               "%s/%s/%s.conf", ALSA_USE_CASE_DIR,
+               uc_mgr->card_name, uc_mgr->card_name);
+       filename[MAX_FILE-1] = '\0';
+
+       err = uc_mgr_config_load(filename, &cfg);
+       if (err < 0) {
+               uc_error("error: could not parse configuration for card %s",
+                               uc_mgr->card_name);
+               return err;
+       }
+
+       err = parse_master_file(uc_mgr, cfg);
+       snd_config_delete(cfg);
+       if (err < 0)
+               uc_mgr_free_verb(uc_mgr);
+
+       return err;
+}
diff --git a/src/ucm/ucm_local.h b/src/ucm/ucm_local.h
new file mode 100644 (file)
index 0000000..ffef8f0
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *  Support for the verb/device/modifier core logic and API,
+ *  command line tool and file parser was kindly sponsored by
+ *  Texas Instruments Inc.
+ *  Support for multiple active modifiers and devices,
+ *  transition sequences, multiple client access and user defined use
+ *  cases was kindly sponsored by Wolfson Microelectronics PLC.
+ *
+ *  Copyright (C) 2008-2010 SlimLogic Ltd
+ *  Copyright (C) 2010 Wolfson Microelectronics PLC
+ *  Copyright (C) 2010 Texas Instruments Inc.
+ *  Copyright (C) 2010 Red Hat Inc.
+ *  Authors: Liam Girdwood <lrg@slimlogic.co.uk>
+ *              Stefan Schmidt <stefan@slimlogic.co.uk>
+ *              Justin Xu <justinx@slimlogic.co.uk>
+ *               Jaroslav Kysela <perex@perex.cz>
+ */
+
+
+
+#if 0
+#define UC_MGR_DEBUG
+#endif
+
+#include "local.h"
+#include "use-case.h"
+
+#define PRE_SEQ                        0
+#define POST_SEQ               1
+#define MAX_FILE               256
+#define ALSA_USE_CASE_DIR      ALSA_CONFIG_DIR "/ucm"
+#define ARRAY_SIZE(x)          (sizeof(x)/sizeof(x[0]))
+#define VERB_NOT_INITIALISED   -1
+
+#define SEQUENCE_ELEMENT_TYPE_CSET     1
+#define SEQUENCE_ELEMENT_TYPE_SLEEP    2
+#define SEQUENCE_ELEMENT_TYPE_EXEC     3
+
+struct sequence_element {
+       struct list_head list;
+       unsigned int type;
+       union {
+               long sleep; /* Sleep time in msecs if sleep element, else 0 */
+               char *cset;
+               char *exec;
+       } data;
+};
+
+/*
+ * Transition sequences. i.e. transition between one verb, device, mod to another
+ */
+struct transition_sequence {
+       struct list_head list;
+       char *name;
+       struct list_head transition_list;
+};
+
+/*
+ * Modifier Supported Devices.
+ */
+struct dev_list {
+       struct list_head list;
+       char *name;
+};
+
+
+/*
+ * Describes a Use Case Modifier and it's enable and disable sequences.
+ * A use case verb can have N modifiers.
+ */
+struct use_case_modifier {
+       struct list_head list;
+       struct list_head active_list;
+
+       char *name;
+       char *comment;
+
+       /* modifier enable and disable sequences */
+       struct list_head enable_list;
+       struct list_head disable_list;
+
+       /* modifier transition list */
+       struct list_head transition_list;
+
+       /* list of supported devices per modifier */
+       struct list_head dev_list;
+
+       /* ALSA PCM devices associated with any modifier PCM streams */
+       char *capture_pcm;
+       char *playback_pcm;
+
+       /* Any modifier stream TQ */
+       char *tq;
+
+       /* aliased controls */
+       char *playback_ctl;
+       char *playback_volume_id;
+       char *playback_switch_id;
+       char *capture_ctl;
+       char *capture_volume_id;
+       char *capture_switch_id;
+};
+
+/*
+ * Describes a Use Case Device and it's enable and disable sequences.
+ * A use case verb can have N devices.
+ */
+struct use_case_device {
+       struct list_head list;
+       struct list_head active_list;
+
+       unsigned int active: 1;
+
+       char *name;
+       char *comment;
+       long idx; /* index for similar devices i.e. 2 headphone jacks */
+
+       /* device enable and disable sequences */
+       struct list_head enable_list;
+       struct list_head disable_list;
+
+       /* device transition list */
+       struct list_head transition_list;
+
+       /* aliased controls */
+       char *playback_ctl;
+       char *playback_volume_id;
+       char *playback_switch_id;
+       char *capture_ctl;
+       char *capture_volume_id;
+       char *capture_switch_id;
+};
+
+/*
+ * Describes a Use Case Verb and it's enable and disable sequences.
+ * A use case verb can have N devices and N modifiers.
+ */
+struct use_case_verb {
+       struct list_head list;
+
+       unsigned int active: 1;
+
+       char *name;
+       char *comment;
+
+       /* verb enable and disable sequences */
+       struct list_head enable_list;
+       struct list_head disable_list;
+
+       /* verb transition list */
+       struct list_head transition_list;
+
+       /* verb PCMs and TQ */
+       char *tq;
+       char *capture_pcm;
+       char *playback_pcm;
+
+       /* hardware devices that can be used with this use case */
+       struct list_head device_list;
+
+       /* modifiers that can be used with this use case */
+       struct list_head modifier_list;
+};
+
+/*
+ *  Manages a sound card and all its use cases.
+ */
+struct snd_use_case_mgr {
+       char *card_name;
+       char *comment;
+
+       /* use case verb, devices and modifier configs parsed from files */
+       struct list_head verb_list;
+
+       /* default settings - sequence */
+       struct list_head default_list;
+
+       /* current status */
+       struct use_case_verb *active_verb;
+       struct list_head active_devices;
+       struct list_head active_modifiers;
+
+       /* locking */
+       pthread_mutex_t mutex;
+};
+
+#define uc_error SNDERR
+
+#ifdef UC_MGR_DEBUG
+#define uc_dbg SNDERR
+#else
+#define uc_dbg(fmt, arg...)
+#endif
+
+void uc_mgr_error(const char *fmt, ...);
+void uc_mgr_stdout(const char *fmt, ...);
+
+int uc_mgr_config_load(const char *file, snd_config_t **cfg);
+int uc_mgr_import_master_config(snd_use_case_mgr_t *uc_mgr);
+
+void uc_mgr_free_sequence_element(struct sequence_element *seq);
+void uc_mgr_free_verb(snd_use_case_mgr_t *uc_mgr);
+void uc_mgr_free(snd_use_case_mgr_t *uc_mgr);
diff --git a/src/ucm/utils.c b/src/ucm/utils.c
new file mode 100644 (file)
index 0000000..98e3cf6
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *  Support for the verb/device/modifier core logic and API,
+ *  command line tool and file parser was kindly sponsored by
+ *  Texas Instruments Inc.
+ *  Support for multiple active modifiers and devices,
+ *  transition sequences, multiple client access and user defined use
+ *  cases was kindly sponsored by Wolfson Microelectronics PLC.
+ *
+ *  Copyright (C) 2008-2010 SlimLogic Ltd
+ *  Copyright (C) 2010 Wolfson Microelectronics PLC
+ *  Copyright (C) 2010 Texas Instruments Inc.
+ *  Copyright (C) 2010 Red Hat Inc.
+ *  Authors: Liam Girdwood <lrg@slimlogic.co.uk>
+ *              Stefan Schmidt <stefan@slimlogic.co.uk>
+ *              Justin Xu <justinx@slimlogic.co.uk>
+ *               Jaroslav Kysela <perex@perex.cz>
+ */
+
+#include "ucm_local.h"
+
+void uc_mgr_error(const char *fmt,...)
+{
+       va_list va;
+       va_start(va, fmt);
+       fprintf(stderr, "ucm: ");
+       vfprintf(stderr, fmt, va);
+       va_end(va);
+}
+
+void uc_mgr_stdout(const char *fmt,...)
+{
+       va_list va;
+       va_start(va, fmt);
+       vfprintf(stdout, fmt, va);
+       va_end(va);
+}
+
+int uc_mgr_config_load(const char *file, snd_config_t **cfg)
+{
+       FILE *fp;
+       snd_input_t *in;
+       snd_config_t *top;
+       int err;
+
+       fp = fopen(file, "r");
+       err = snd_input_stdio_attach(&in, fp, 1);
+       if (err < 0) {
+               uc_error("could not open configuration file %s", file);
+               return err;
+       }
+       err = snd_config_top(&top);
+       if (err < 0)
+               return err;
+       err = snd_config_load(top, in);
+       if (err < 0) {
+               uc_error("could not load configuration file %s", file);
+               snd_config_delete(top);
+               return err;
+       }
+       err = snd_input_close(in);
+       if (err < 0) {
+               snd_config_delete(top);
+               return err;
+       }
+       *cfg = top;
+       return 0;
+}
+
+void uc_mgr_free_dev_list(struct list_head *base)
+{
+       struct list_head *pos, *npos;
+       struct dev_list *dlist;
+       
+       list_for_each_safe(pos, npos, base) {
+               dlist = list_entry(pos, struct dev_list, list);
+               free(dlist->name);
+               free(dlist);
+               list_del(pos);
+       }
+}
+
+void uc_mgr_free_sequence_element(struct sequence_element *seq)
+{
+       if (seq == NULL)
+               return;
+       switch (seq->type) {
+       case SEQUENCE_ELEMENT_TYPE_CSET:
+       case SEQUENCE_ELEMENT_TYPE_EXEC:
+               free(seq->data.exec);
+               break;
+       default:
+               break;
+       }
+       free(seq);
+}
+
+void uc_mgr_free_sequence(struct list_head *base)
+{
+       struct list_head *pos, *npos;
+       struct sequence_element *seq;
+       
+       list_for_each_safe(pos, npos, base) {
+               seq = list_entry(pos, struct sequence_element, list);
+               uc_mgr_free_sequence_element(seq);
+               list_del(pos);
+       }
+}
+
+void uc_mgr_free_transition(struct list_head *base)
+{
+       struct list_head *pos, *npos;
+       struct transition_sequence *tseq;
+       
+       list_for_each_safe(pos, npos, base) {
+               tseq = list_entry(pos, struct transition_sequence, list);
+               free(tseq->name);
+               uc_mgr_free_sequence(&tseq->transition_list);
+               free(tseq);
+               list_del(pos);
+       }
+}
+
+void uc_mgr_free_modifier(struct list_head *base)
+{
+       struct list_head *pos, *npos;
+       struct use_case_modifier *mod;
+       
+       list_for_each_safe(pos, npos, base) {
+               mod = list_entry(pos, struct use_case_modifier, list);
+               free(mod->name);
+               free(mod->comment);
+               uc_mgr_free_sequence(&mod->enable_list);
+               uc_mgr_free_sequence(&mod->disable_list);
+               uc_mgr_free_transition(&mod->transition_list);
+               uc_mgr_free_dev_list(&mod->dev_list);
+               free(mod->capture_pcm);
+               free(mod->playback_pcm);
+               free(mod->tq);
+               free(mod->playback_ctl);
+               free(mod->playback_volume_id);
+               free(mod->playback_switch_id);
+               free(mod->capture_ctl);
+               free(mod->capture_volume_id);
+               free(mod->capture_switch_id);
+               free(mod);
+               list_del(pos);
+       }
+}
+
+void uc_mgr_free_device(struct list_head *base)
+{
+       struct list_head *pos, *npos;
+       struct use_case_device *dev;
+       
+       list_for_each_safe(pos, npos, base) {
+               dev = list_entry(pos, struct use_case_device, list);
+               free(dev->name);
+               free(dev->comment);
+               uc_mgr_free_sequence(&dev->enable_list);
+               uc_mgr_free_sequence(&dev->disable_list);
+               uc_mgr_free_transition(&dev->transition_list);
+               free(dev->playback_ctl);
+               free(dev->playback_volume_id);
+               free(dev->playback_switch_id);
+               free(dev->capture_ctl);
+               free(dev->capture_volume_id);
+               free(dev->capture_switch_id);
+               free(dev);
+               list_del(pos);
+       }
+}
+
+void uc_mgr_free_verb(snd_use_case_mgr_t *uc_mgr)
+{
+       struct list_head *pos, *npos;
+       struct use_case_verb *verb;
+
+       list_for_each_safe(pos, npos, &uc_mgr->verb_list) {
+               verb = list_entry(pos, struct use_case_verb, list);
+               free(verb->name);
+               free(verb->comment);
+               uc_mgr_free_sequence(&verb->enable_list);
+               uc_mgr_free_sequence(&verb->disable_list);
+               uc_mgr_free_transition(&verb->transition_list);
+               free(verb->tq);
+               free(verb->capture_pcm);
+               free(verb->playback_pcm);
+               uc_mgr_free_device(&verb->device_list);
+               uc_mgr_free_modifier(&verb->modifier_list);
+               free(verb);
+               list_del(pos);
+       }
+       uc_mgr_free_sequence(&uc_mgr->default_list);
+       free(uc_mgr->comment);
+       uc_mgr->comment = NULL;
+       uc_mgr->active_verb = NULL;
+       INIT_LIST_HEAD(&uc_mgr->active_devices);
+       INIT_LIST_HEAD(&uc_mgr->active_modifiers);
+}
+
+void uc_mgr_free(snd_use_case_mgr_t *uc_mgr)
+{
+       uc_mgr_free_verb(uc_mgr);
+       free(uc_mgr->card_name);
+       free(uc_mgr);
+}
diff --git a/src/use-case.c b/src/use-case.c
deleted file mode 100644 (file)
index b45fe1f..0000000
+++ /dev/null
@@ -1,3515 +0,0 @@
-/*
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- *  Support for the verb/device/modifier core logic and API,
- *  command line tool and file parser was kindly sponsored by
- *  Texas Instruments Inc.
- *  Support for multiple active modifiers and devices,
- *  transition sequences, multiple client access and user defined use
- *  cases was kindly sponsored by Wolfson Microelectronics PLC.
- *
- *  Copyright (C) 2008-2010 SlimLogic Ltd
- *  Copyright (C) 2010 Wolfson Microelectronics PLC
- *  Copyright (C) 2010 Texas Instruments Inc.
- *  Authors: Liam Girdwood <lrg@slimlogic.co.uk>
- *              Stefan Schmidt <stefan@slimlogic.co.uk>
- *              Justin Xu <justinx@slimlogic.co.uk>
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <alsa/asoundlib.h>
-#include <pthread.h>
-
-#include "../include/use-case.h"
-#include "../include/iatomic.h"
-
-#define PRE_SEQ                0
-#define POST_SEQ               1
-#define MAX_VERB               32
-#define MAX_DEVICE             64
-#define MAX_MODIFIER           64
-#define MAX_NAME               64
-#define MAX_FILE               256
-#define MAX_BUF                256
-#define ALSA_USE_CASE_DIR      "/usr/share/alsa/ucm"
-#define ARRAY_SIZE(x)          (sizeof(x)/sizeof(x[0]))
-#define VERB_NOT_INITIALISED   -1
-
-/*
- * Stores all use case settings for 1 kcontrol. Hence we have a
- * control_settings for each kcontrol in card.
- */
-struct control_settings {
-       char name[MAX_NAME];
-       unsigned int id;
-       snd_ctl_elem_type_t type;
-       short count; /* 1 = mono, 2 = stereo, etc */
-       unsigned short *value;
-};
-
-/*
- * If sleep is 0 the element contains the settings in control. Else sleep
- * contains the sleep time in micro seconds.
- */
-struct sequence_element {
-       unsigned int sleep; /* Sleep time in msecs if sleep element, else 0 */
-       struct control_settings *control;
-       struct sequence_element *next; /* Pointer to next list element */
-};
-
-/*
- * Transition sequences. i.e. transition between one verb, device, mod to another
- */
-struct transition_sequence {
-       char *name;
-       struct sequence_element *transition;
-       struct transition_sequence *next;
-};
-
-/*
- * Modifier Supported Devicees.
- */
-struct dev_list {
-       char *name;
-       struct dev_list *next;
-};
-
-
-/*
- * Describes a Use Case Modifier and it's enable and disable sequences.
- * A use case verb can have N modifiers.
- */
-struct use_case_modifier {
-       char *name;
-       char *comment;
-
-       /* modifier enable and disable sequences */
-       struct sequence_element *enable;
-       struct sequence_element *disable;
-
-       /* modifier transition list */
-       struct transition_sequence *transition_list;
-
-       /* list of supported devices per modifier */
-       struct dev_list *dev_list;
-
-       /* ALSA PCM devices associated with any modifier PCM streams */
-       int capture_pcm;
-       int playback_pcm;
-
-       /* Any modifier stream QoS */
-       enum snd_use_case_qos qos;
-
-       /* aliased controls */
-       char *playback_volume_id;
-       char *playback_switch_id;
-       char *capture_volume_id;
-       char *capture_switch_id;
-};
-
-/*
- * Describes a Use Case Device and it's enable and disable sequences.
- * A use case verb can have N devices.
- */
-struct use_case_device {
-       char *name;
-       char *comment;
-       int idx; /* index for similar devices i.e. 2 headphone jacks */
-
-       /* device enable and disable sequences */
-       struct sequence_element *enable;
-       struct sequence_element *disable;
-
-       /* device transition list */
-       struct transition_sequence *transition_list;
-
-       /* aliased controls */
-       char *playback_volume_id;
-       char *playback_switch_id;
-       char *capture_volume_id;
-       char *capture_switch_id;
-};
-
-/*
- * Describes a Use Case Verb and it's enable and disable sequences.
- * A use case verb can have N devices and N modifiers.
- */
-struct use_case_verb {
-       char *name;
-       char *comment;
-
-       /* verb enable and disable sequences */
-       struct sequence_element *enable;
-       struct sequence_element *disable;
-
-       /* verb transition list */
-       struct transition_sequence *transition_list;
-
-       /* verb PCMs and QoS */
-       enum snd_use_case_qos qos;
-       int capture_pcm;
-       int playback_pcm;
-
-       /* hardware devices that can be used with this use case */
-       int num_devices;
-       struct use_case_device *device;
-       /*
-        * device_list[i] shares string with device[i].name,
-        * so device_list don't need not be freed
-        */
-       const char *device_list[MAX_DEVICE];
-
-       /* modifiers that can be used with this use case */
-       int num_modifiers;
-       struct use_case_modifier *modifier;
-       /*
-        * modifier_list[i] shares string with modifier[i].name,
-        * so modifier_list don't need not be freed
-        */
-       const char *modifier_list[MAX_MODIFIER];
-};
-
-struct ucm_card {
-       int current_verb;
-       int current_device[MAX_DEVICE];
-       int current_modifier[MAX_MODIFIER];
-};
-
-/*
- *  Manages a sound card and all its use cases.
- */
-struct snd_use_case_mgr {
-       pthread_mutex_t mutex;
-       char *card_name;
-       char *ctl_name;
-       struct ucm_card card;
-
-       /* use case verb, devices and modifier configs parsed from files */
-       int num_verbs; /* number of supported use case verbs */
-       struct use_case_verb *verb; /* var len array of use case info */
-       /*
-        * verb_list[i] shares string with verb[i].name,
-        * so verb_list don't need not be freed
-        */
-       const char *verb_list[MAX_VERB];
-
-       /* sound card ALSA kcontrol read from sound card device */
-       struct control_settings *control; /* var len array of controls */
-
-       /* snd ctl */
-       int count;
-       snd_ctl_t *handle;
-       snd_ctl_card_info_t *info;
-       snd_ctl_elem_list_t *list;
-       snd_ctl_elem_id_t *id;
-};
-
-static void uc_mgr_error(const char *fmt,...)
-{
-       va_list va;
-       va_start(va, fmt);
-       fprintf(stderr, "ucm: ");
-       vfprintf(stderr, fmt, va);
-       va_end(va);
-}
-
-#define uc_error(fmt, arg...) do { \
-        uc_mgr_error("%s() - " fmt "\n", __FUNCTION__ , ## arg); \
-} while (0)
-
-static void uc_mgr_stdout(const char *fmt,...)
-{
-       va_list va;
-       va_start(va, fmt);
-       vfprintf(stdout, fmt, va);
-       va_end(va);
-}
-
-#undef UC_MGR_DEBUG
-
-#ifdef UC_MGR_DEBUG
-#define uc_dbg(fmt, arg...) do { \
-        uc_mgr_stdout("%s() - " fmt "\n", __FUNCTION__ , ## arg); \
-} while (0)
-#else
-#define uc_dbg(fmt, arg...)
-#endif
-
-static int set_control(snd_ctl_t *handle, snd_ctl_elem_id_t *id,
-       snd_use_case_mgr_t *uc_mgr, unsigned short value[]);
-
-static inline void set_value(struct control_settings *control,
-               int count, unsigned short val)
-{
-       uc_dbg("value %d, count %d", val, count);
-       control->value[count] = val;
-}
-
-static inline unsigned short get_value(struct control_settings *control,
-               int count)
-{
-       return control->value[count];
-}
-
-static inline void set_device_status(struct snd_use_case_mgr *uc_mgr,
-       int device_id, int status)
-{
-       struct use_case_verb *verb;
-
-       verb = &uc_mgr->verb[uc_mgr->card.current_verb];
-       uc_mgr->card.current_device[device_id] = status;
-}
-
-static inline void set_modifier_status(struct snd_use_case_mgr *uc_mgr,
-       int modifier_id, int status)
-{
-       struct use_case_verb *verb;
-
-       verb = &uc_mgr->verb[uc_mgr->card.current_verb];
-       uc_mgr->card.current_modifier[modifier_id] = status;
-}
-
-static inline int get_device_status(struct snd_use_case_mgr *uc_mgr,
-       int device_id)
-{
-       struct use_case_verb *verb;
-
-       verb = &uc_mgr->verb[uc_mgr->card.current_verb];
-       return uc_mgr->card.current_device[device_id];
-}
-
-static inline int get_modifier_status(struct snd_use_case_mgr *uc_mgr,
-       int modifier_id)
-{
-       struct use_case_verb *verb;
-
-       verb = &uc_mgr->verb[uc_mgr->card.current_verb];
-       return uc_mgr->card.current_modifier[modifier_id];
-}
-
-static int dump_control(snd_ctl_t *handle, snd_ctl_elem_id_t *id)
-{
-       int err, count, i;
-       snd_ctl_elem_info_t *info;
-       snd_ctl_elem_type_t type;
-       snd_ctl_elem_value_t *control;
-
-       snd_ctl_elem_info_alloca(&info);
-       snd_ctl_elem_value_alloca(&control);
-
-       snd_ctl_elem_info_set_id(info, id);
-       err = snd_ctl_elem_info(handle, info);
-       if (err < 0) {
-               uc_error("error: failed to get ctl info: %s\n",
-                       snd_strerror(err));
-               return err;
-       }
-
-       snd_ctl_elem_value_set_id(control, id);
-       snd_ctl_elem_read(handle, control);
-
-       type = snd_ctl_elem_info_get_type(info);
-       count = snd_ctl_elem_info_get_count(info);
-       if (count == 0)
-               return 0;
-
-       uc_mgr_stdout("'%s':%d:",
-              snd_ctl_elem_id_get_name(id), count);
-
-       switch (type) {
-       case SND_CTL_ELEM_TYPE_BOOLEAN:
-               for (i = 0; i < count - 1; i++)
-                       uc_mgr_stdout("%d,",
-                               snd_ctl_elem_value_get_boolean(control, i));
-               uc_mgr_stdout("%d",
-                       snd_ctl_elem_value_get_boolean(control, i));
-               break;
-       case SND_CTL_ELEM_TYPE_INTEGER:
-               for (i = 0; i < count - 1; i++)
-                       uc_mgr_stdout("%d,",
-                               snd_ctl_elem_value_get_integer(control, i));
-               uc_mgr_stdout("%d",
-                       snd_ctl_elem_value_get_integer(control, i));
-               break;
-       case SND_CTL_ELEM_TYPE_INTEGER64:
-               for (i = 0; i < count - 1; i++)
-                       uc_mgr_stdout("%ld,",
-                               snd_ctl_elem_value_get_integer64(control, i));
-               uc_mgr_stdout("%ld",
-                               snd_ctl_elem_value_get_integer64(control, i));
-               break;
-       case SND_CTL_ELEM_TYPE_ENUMERATED:
-               for (i = 0; i < count - 1; i++)
-                       uc_mgr_stdout("%d,",
-                               snd_ctl_elem_value_get_enumerated(control, i));
-               uc_mgr_stdout("%d",
-                               snd_ctl_elem_value_get_enumerated(control, i));
-               break;
-       case SND_CTL_ELEM_TYPE_BYTES:
-               for (i = 0; i < count - 1; i++)
-                       uc_mgr_stdout("%2.2x,",
-                               snd_ctl_elem_value_get_byte(control, i));
-               uc_mgr_stdout("%2.2x",
-                       snd_ctl_elem_value_get_byte(control, i));
-               break;
-       default:
-               break;
-       }
-       uc_mgr_stdout("\n");
-       return 0;
-}
-
-/*
- * Add new kcontrol from sound card into memory database.
- */
-static int add_control(snd_ctl_t *handle, snd_ctl_elem_id_t *id,
-       struct control_settings *control_settings)
-{
-       int err;
-       snd_ctl_elem_info_t *info;
-       snd_ctl_elem_value_t *control;
-
-       snd_ctl_elem_info_alloca(&info);
-       snd_ctl_elem_value_alloca(&control);
-
-       snd_ctl_elem_info_set_id(info, id);
-       err = snd_ctl_elem_info(handle, info);
-       if (err < 0) {
-               uc_error("error: failed to get ctl info: %s\n",
-                       snd_strerror(err));
-               return err;
-       }
-
-       snd_ctl_elem_value_set_id(control, id);
-       snd_ctl_elem_read(handle, control);
-
-       strncpy(control_settings->name, snd_ctl_elem_id_get_name(id),
-               MAX_NAME);
-
-       control_settings->name[MAX_NAME - 1] = 0;
-       control_settings->count = snd_ctl_elem_info_get_count(info);
-       control_settings->type = snd_ctl_elem_info_get_type(info);
-       control_settings->id = snd_ctl_elem_id_get_numid(id);
-       uc_dbg("control name %s", control_settings->name);
-       uc_dbg("control count %d", control_settings->count);
-       uc_dbg("control type %d", control_settings->type);
-       uc_dbg("control id %d", control_settings->id);
-       return 0;
-}
-
-static int set_control_default(snd_use_case_mgr_t *uc_mgr,
-       struct control_settings *control)
-{
-       snd_ctl_elem_id_t *id;
-       int i, ret = -ENODEV;
-       unsigned int numid;
-
-       snd_ctl_elem_id_alloca(&id);
-
-       /* Where is id lookup from numid if you need it? */
-       for (i = 0; i < uc_mgr->count; ++i) {
-               snd_ctl_elem_list_get_id(uc_mgr->list, i, id);
-               numid = snd_ctl_elem_id_get_numid(id);
-               if (numid == control->id) {
-                       ret = set_control(uc_mgr->handle, id, uc_mgr,
-                               control->value);
-                       goto out;
-               }
-       }
-       uc_error("error: could not find control ID %s : %d",
-               control->name, control->id);
-out:
-       return ret;
-}
-
-static int get_control_id(snd_use_case_mgr_t *uc_mgr,
-                       struct control_settings *control)
-{
-       int i = 0;
-       struct control_settings *card_control;
-
-       uc_dbg("name %s count %d",
-                       control->name, control->count);
-
-       for (i = 0; i < uc_mgr->count; i++) {
-               card_control = &uc_mgr->control[i];
-               if (!strcmp(card_control->name, control->name)) {
-                       control->id = uc_mgr->control[i].id;
-                       uc_dbg("Get id %d", control->id);
-                       return 0;
-               }
-       }
-
-       uc_error("error: control name %s is not available", control->name);
-
-       return -EINVAL;
-}
-
-static char *get_control_name(char *buf, int line, char *file)
-{
-       char name[MAX_NAME];
-       char *name_start, *name_end, *tbuf = buf;
-
-       /* get name start */
-       while (*tbuf != 0 && *tbuf != '\'')
-               tbuf++;
-       if (*tbuf == 0)
-               return NULL;
-       name_start = ++tbuf;
-
-       /* get name end */
-       while (*tbuf != 0 && *tbuf != '\'')
-               tbuf++;
-       if (*tbuf == 0)
-               return NULL;
-       name_end = tbuf++;
-
-       /* copy name */
-       if ((name_end - name_start) > MAX_NAME) {
-               uc_error("error: %s:%d name too big at %d chars",
-                               file, line, name_end - name_start);
-               return NULL;
-       }
-       strncpy(name, name_start, name_end - name_start);
-       name[name_end - name_start] = 0;
-       return strdup(name);
-}
-
-/*
- * Parse a single control from file.
- *
- * Controls are in the following form:-
- *
- * 'name':channels:value0,value1,...,valueN
- *
- * e.g.
- *     'Master Playback Switch':2:0,0
- */
-static int parse_control(snd_use_case_mgr_t *uc_mgr,
-                       struct control_settings *control, char *buf,
-                       int line, char *file)
-{
-       char name[MAX_NAME];
-       int count, i;
-       char *name_start, *name_end, *tbuf;
-
-       uc_dbg("%s", buf);
-
-       tbuf = buf;
-
-       /* get name start */
-       while (*tbuf != 0 && *tbuf != '\'')
-               tbuf++;
-       if (*tbuf == 0)
-               return -EINVAL;
-       name_start = ++tbuf;
-
-       /* get name end */
-       while (*tbuf != 0 && *tbuf != '\'')
-               tbuf++;
-       if (*tbuf == 0)
-               return -EINVAL;
-       name_end = tbuf++;
-
-       /* copy name */
-       if ((name_end - name_start) > MAX_NAME) {
-               uc_error("error: %s:%d name too big at %d chars",
-                               file, line, name_end - name_start);
-               return -EINVAL;
-       }
-       strncpy(name, name_start, name_end - name_start);
-       name[name_end - name_start] = 0;
-       strncpy(control->name, name, name_end - name_start +1);
-
-       /* get count */
-       uc_dbg("%s", tbuf);
-       tbuf++;
-       count = atoi(tbuf);
-       if (count == 0) {
-               uc_error("error: %s:%d count == 0 on line %d", file, line);
-               return -EINVAL;
-       }
-       control->count = count;
-
-       /* get vals */
-       control->value = calloc(count, sizeof(unsigned short));
-       if (control->value == NULL)
-               return -ENOMEM;
-
-       while (*tbuf != 0 && *tbuf != ':')
-               tbuf++;
-       if (*tbuf == 0)
-               return -EINVAL;
-       tbuf++;
-
-       for (i = 0; i < count; i++) {
-               set_value(control, i, atoi(tbuf));
-               while (*tbuf != 0 && *tbuf != ',')
-                       tbuf++;
-
-               if (*tbuf++ == 0 && i < (count - 1))
-                       return -EINVAL;
-       }
-
-       return get_control_id(uc_mgr, control);
-}
-
-static int parse_controls(snd_use_case_mgr_t *uc_mgr, FILE *f, int *line_,
-               char *file)
-{
-       struct control_settings *control = NULL;
-       char buf[MAX_BUF], name[MAX_NAME];
-       int count, i, ret = 0, line = *line_;
-       char *name_start, *name_end, *tbuf;
-
-       while (fgets(buf, MAX_BUF, f) != NULL) {
-
-               uc_dbg("%s: get line %d\n%s", file, line, buf);
-
-               tbuf = buf;
-               while (isblank(*tbuf))
-               tbuf++;
-               line ++;
-
-               /* end of section ?*/
-               if (strncmp(tbuf, "EndSectionDefaults", 18) == 0)
-                       return 0;
-
-               /* get name start */
-               while (*tbuf != 0 && *tbuf != '\'')
-                       tbuf++;
-               if (*tbuf == 0)
-                       return -EINVAL;
-               name_start = ++tbuf;
-
-               /* get name end */
-               while (*tbuf != 0 && *tbuf != '\'')
-                       tbuf++;
-               if (*tbuf == 0)
-                       return -EINVAL;
-               name_end = tbuf++;
-
-               /* copy name */
-               if ((name_end - name_start) > MAX_NAME) {
-                       uc_error("error: %s:%d name too big at %d chars",
-                                       file, line, name_end - name_start);
-                       return -EINVAL;
-               }
-               strncpy(name, name_start, name_end - name_start);
-               name[name_end - name_start] = 0;
-
-               for (i = 0; i < uc_mgr->count; i++) {
-                       struct control_settings *card_control =
-                                                       &uc_mgr->control[i];
-                       if (!strcmp(card_control->name, name))
-                               control = &uc_mgr->control[i];
-               }
-
-               uc_dbg("control id %d", control->id);
-
-               /* get count */
-               tbuf++;
-               count = atoi(tbuf);
-               if (count == 0) {
-                       uc_error("error: %s:%d count == 0", file, line);
-                       return -EINVAL;
-               }
-               if (count != control->count) {
-                       uc_error("error: %s:%d count %d does not match card count"
-                               " %d", file, line, count, control->count);
-                       return -EINVAL;
-               }
-
-               /* get vals */
-               control->value = malloc(control->count *uc_mgr->num_verbs *
-                       sizeof(unsigned short));
-               if (control->value == NULL)
-                       return -ENOMEM;
-
-               while (*tbuf != 0 && *tbuf != ':')
-                       tbuf++;
-               if (*tbuf == 0)
-                       return -EINVAL;
-               tbuf++;
-
-               for (i = 0; i < count; i++) {
-                       set_value(control, i, atoi(tbuf));
-                       while (*tbuf != 0 && *tbuf != ',')
-                               tbuf++;
-
-                       if (*tbuf++ == 0 && i < (count - 1))
-                               return -EINVAL;
-               }
-       }
-
-       *line_ = line;
-       return ret;
-}
-
-static char *get_string (char *buf)
-{
-       char *str, *end;
-
-       uc_dbg("%s", buf);
-
-       while (isblank(*buf))
-               buf++;
-
-       /* find leading '"' */
-       if (*buf == 0 || *buf != '"') {
-               uc_error("error: missing start '\"'");
-               return NULL;
-       }
-       str = ++buf;
-
-       /* get value */
-       while (*buf != 0 && *buf != '"')
-               buf++;
-       end = buf;
-
-       /* find '"' terminator */
-       if (*buf == 0 || *buf != '"') {
-               uc_error("error: missing terminator '\"' %s", buf);
-               return NULL;
-       }
-
-       *end = 0;
-       return strdup(str);
-}
-
-static enum snd_use_case_qos get_enum (char *buf)
-{
-       while (isblank(*buf))
-               buf++;
-
-       if (!strncmp(buf, "Music", 5))
-               return SND_USE_CASE_QOS_MUSIC;
-       if (!strncmp(buf, "Voice", 5))
-               return SND_USE_CASE_QOS_VOICE;
-       if (!strncmp(buf, "Tones", 5))
-               return SND_USE_CASE_QOS_TONES;
-
-       return SND_USE_CASE_QOS_MUSIC;
-}
-
-static void seq_list_append(struct sequence_element **base,
-                       struct sequence_element *curr)
-{
-       struct sequence_element *last, *tmp;
-
-       if (!*base)
-               *base = curr;
-       else {
-               tmp = *base;
-               while (tmp) {
-                       last = tmp;
-                       tmp = tmp->next;
-               }
-               last->next = curr;
-               curr->next = NULL;
-       }
-}
-/*
- * Parse sequences.
- *
- * Sequence controls elements  are in the following form:-
- *
- * 'name':value0,value1,...,valueN
- *
- * e.g.
- *     'Master Playback Switch':0,0
- */
-static int parse_sequence(snd_use_case_mgr_t *uc_mgr,
-                       struct sequence_element **base, FILE *f,
-                       int *line_, char *file)
-{
-       char buf[MAX_BUF], *tbuf;
-       int ret, line = *line_;
-       struct sequence_element *curr;
-
-       /* read line by line */
-       while (fgets(buf, MAX_BUF, f) != NULL) {
-
-               uc_dbg("%s", buf);
-               line++;
-
-               /* Check for lines with comments and ignore */
-               if (buf[0] == '#')
-                       continue;
-
-               /* Parse current line and skip blanks */
-               tbuf = buf;
-               while (isblank(*tbuf))
-                       tbuf++;
-
-               /* end of sequence ? */
-               if (strncmp(tbuf, "EndSequence", 11) == 0)
-                       goto out;
-
-               if (strncmp(tbuf, "EndTransition", 13) == 0)
-                       goto out;
-
-               /* alloc new sequence element */
-               curr = calloc(1, sizeof(struct sequence_element));
-               if (curr == NULL)
-                       return -ENOMEM;
-
-               /* is element a sleep ? */
-               if (strncmp(tbuf, "msleep", 6) == 0) {
-                       curr->sleep = atoi(tbuf + 6);
-                       uc_dbg("msleep %d", curr->sleep);
-                       seq_list_append(base, curr);
-                       continue;
-               }
-
-               /* alloc new sequence control */
-               curr->control = calloc(1, sizeof(struct control_settings));
-               if (curr->control == NULL)
-                       return -ENOMEM;
-
-               ret = parse_control(uc_mgr, curr->control, tbuf, line, file);
-               if (ret < 0) {
-                       uc_error("error: %s:%d failed to get parse sequence"
-                               " controls", file, line);
-                               goto err;
-               }
-
-               uc_dbg("name %s, id %d, count %d", curr->control->name,
-                       curr->control->id, curr->control->count);
-               seq_list_append(base, curr);
-       }
-
-out:
-       *line_ = line;
-       return 0;
-
-err:
-       free(curr);
-       return ret;
-}
-
-static void prepend_transition(
-                               struct transition_sequence **transition_list,
-                               struct transition_sequence *trans_seq)
-{
-       if (*transition_list == NULL)
-               *transition_list = trans_seq;
-       else {
-               trans_seq->next = *transition_list;
-               *transition_list = trans_seq;
-       }
-
-}
-
-static void prepend_dev(struct dev_list **dev_list,
-                               struct dev_list *sdev)
-{
-       if (*dev_list == NULL)
-               *dev_list = sdev;
-       else {
-               sdev->next = *dev_list;
-               *dev_list = sdev;
-       }
-
-}
-
-/*
- * Parse Modifier Use cases
- *
- *     # Each modifier is described in new section. N modifier are allowed
- *     SectionModifier
- *
- *             Name "Capture Voice"
- *             Comment "Record voice call"
- *             SupportedDevice "x"
- *             SupportedDevice "y"
- *
- *             EnableSequence
- *                     ....
- *             EndSequence
- *
- *             DisableSequence
- *                     ...
- *             EndSequence
- *
- *             # Optional QoS and ALSA PCMs
- *             QoS Voice
- *             CapturePCM 1
- *             MasterPlaybackVolume  'Device Master Playback Volume'
- *             MasterPlaybackSwitch  'Device Master Playback Switch'
- *
- *      EndSection
- */
-static int parse_modifier(snd_use_case_mgr_t *uc_mgr,
-               struct use_case_verb *verb, FILE *f, int *line_, char *file)
-{
-       struct use_case_modifier *modifier;
-       int line = *line_, end = 0, en_seq = 0, dis_seq = 0;
-       int id = 0, dev = 0, ret;
-       char buf[MAX_BUF], *tbuf;
-       char *name = NULL, *comment = NULL;
-
-       /* allocate modifier  */
-       verb->modifier = realloc(verb->modifier,
-               (verb->num_modifiers + 1) * sizeof(struct use_case_modifier));
-       if (verb->modifier == NULL)
-               return -ENOMEM;
-       modifier = verb->modifier + verb->num_modifiers;
-       bzero(modifier, sizeof(struct use_case_modifier));
-
-       /* read line by line */
-       while(fgets(buf, MAX_BUF, f) != NULL) {
-
-               line++;
-
-               /* skip comments */
-               if (buf[0] == '#')
-                       continue;
-
-               tbuf = buf;
-               /* skip spaces */
-               while (isblank(*tbuf))
-                       tbuf++;
-
-               /* get use case modifier name */
-               if (strncmp(tbuf, "Name", 4) == 0) {
-                       name = get_string(tbuf + 4);
-                       if (name == NULL) {
-                               uc_error("error: %s:%d failed to get modifier name",
-                                               file, line);
-                               goto err;
-                       }
-                       modifier->name = name;
-                       id = 1;
-                       continue;
-               }
-
-               if (strncmp(tbuf, "Comment", 8) == 0) {
-                       name = get_string(tbuf + 8);
-                       if (name == NULL) {
-                               uc_error("error: %s:%d failed to get modifier comment",
-                                               file, line);
-                               goto err;
-                       }
-                       modifier->comment = comment;
-                       continue;
-               }
-
-               if (strncmp(tbuf, "SupportedDevice", 15) == 0) {
-                       struct dev_list *sdev;
-                       name = get_string(tbuf + 15);
-                       if (name == NULL) {
-                               uc_error("error: %s:%d failed to get modifier"
-                                       " supported device", file, line);
-                               goto err;
-                       }
-
-                       sdev = calloc(1, sizeof(struct dev_list));
-                       if (sdev == NULL)
-                               goto err;
-
-                       dev = 1;
-                       sdev->name = name;
-                       prepend_dev(&modifier->dev_list, sdev);
-                       continue;
-               }
-
-               if (strncmp(tbuf, "EnableSequence", 14) == 0) {
-                       ret = parse_sequence(uc_mgr, &modifier->enable, f,
-                               &line, file);
-                       if (ret < 0) {
-                               uc_error("error: %s:%d failed to parse modifier"
-                                       " enable sequence", file, line);
-                               goto err;
-                       }
-                       en_seq = 1;
-                       continue;
-               }
-
-               if (strncmp(tbuf, "DisableSequence", 15) == 0) {
-                       ret = parse_sequence(uc_mgr, &modifier->disable, f,
-                               &line, file);
-                       if (ret < 0) {
-                               uc_error("error: %s:%d failed to parse modifier"
-                                       " disable sequence", file, line);
-                               goto err;
-                       }
-                       dis_seq = 1;
-                       continue;
-               }
-
-               if (strncmp(tbuf, "TransitionModifier", 16) == 0) {
-                       struct transition_sequence *trans_seq;
-
-                       name = get_string(tbuf + 16);
-                       if (name == NULL)
-                               continue;
-
-                       trans_seq = calloc(1, sizeof(struct transition_sequence));
-                       if (trans_seq == NULL)
-                               return -ENOMEM;
-
-                       trans_seq->name = name;
-
-                       ret = parse_sequence(uc_mgr, &trans_seq->transition, f,
-                               &line, file);
-                       if (ret < 0) {
-                               uc_error("error: %s:%d failed to parse transition"
-                                       " modifier", file, line);
-                               goto err;
-                       }
-
-                       prepend_transition(&modifier->transition_list, trans_seq);
-                       continue;
-               }
-
-               if (strncmp(tbuf, "QoS", 3) == 0) {
-                       modifier->qos = get_enum(tbuf + 3);
-                       continue;
-               }
-
-               if (strncmp(tbuf, "CapturePCM", 3) == 0) {
-                       modifier->capture_pcm = atoi(tbuf + 3);
-                       if (modifier->capture_pcm < 0) {
-                               uc_error("error: %s:%d failed to get Capture PCM ID",
-                                               file, line);
-                               goto err;
-                       }
-                       continue;
-               }
-
-               if (strncmp(tbuf, "PlaybackPCM", 3) == 0) {
-                       modifier->playback_pcm = atoi(tbuf + 3);
-                       if (modifier->playback_pcm < 0) {
-                               uc_error("error: %s:%d failed to get Playback PCM ID",
-                                               file, line);
-                               goto err;
-                       }
-                       continue;
-               }
-
-               if (strncmp(tbuf, "MasterPlaybackVolume", 20) == 0) {
-                       modifier->playback_volume_id =
-                               get_control_name(tbuf + 20, line, file);
-                       if (modifier->playback_volume_id == NULL) {
-                               uc_error("error: %s:%d failed to get MasterPlaybackVolume",
-                                               file, line);
-                               goto err;
-                       }
-                       continue;
-               }
-
-               if (strncmp(tbuf, "MasterPlaybackSwitch", 20) == 0) {
-                       modifier->playback_switch_id =
-                               get_control_name(tbuf + 20, line, file);
-                       if (modifier->playback_switch_id == NULL) {
-                               uc_error("error: %s:%d failed to get MasterPlaybackSwitch",
-                                               file, line);
-                               goto err;
-                       }
-                       continue;
-               }
-
-               if (strncmp(tbuf, "MasterCaptureVolume", 19) == 0) {
-                       modifier->capture_volume_id =
-                               get_control_name(tbuf + 19, line, file);
-                       if (modifier->capture_volume_id == NULL) {
-                               uc_error("error: %s:%d failed to get MasterCaptureVolume",
-                                               file, line);
-                               goto err;
-                       }
-                       continue;
-               }
-
-               if (strncmp(tbuf, "MasterCaptureSwitch", 19) == 0) {
-                       modifier->capture_switch_id =
-                               get_control_name(tbuf + 19, line, file);
-                       if (modifier->capture_switch_id == NULL) {
-                               uc_error("error: %s:%d failed to get MasterCaptureSwitch",
-                                               file, line);
-                               goto err;
-                       }
-                       continue;
-               }
-
-               /* end of section ?*/
-               if (strncmp(tbuf, "EndSection", 10) == 0) {
-                       end = 1;
-                       break;
-               }
-       }
-
-       /* do we have the modifier basics ? */
-       if (!en_seq || !dis_seq || !end || !dev) {
-               uc_error("error: invalid modifier");
-               if (!en_seq)
-                       uc_error("error: %s: modifier missing enable sequence",
-                                       file);
-               if (!dis_seq)
-                       uc_error("error: %s: modifier missing disable sequence",
-                                       file);
-               if (!dev)
-                       uc_error("error: %s: modifier missing supported device"
-                                       " sequence", file);
-               if (!end)
-                       uc_error("error: %s: modifier missing end", file);
-               return -EINVAL;
-       }
-
-       verb->modifier_list[verb->num_modifiers++] = modifier->name;
-       *line_ = line;
-       return 0;
-
-err:
-       if (ferror(f)) {
-               uc_error("error: %s: failed to read modifier master section",
-                       file);
-               return ferror(f);
-       }
-       return -ENOMEM;
-}
-
-/*
- * Parse Device Use Cases
- *
- *# Each device is described in new section. N devices are allowed
- *SectionDevice
- *
- *     Name "Headphones"
- *     Comment "Headphones connected to 3.5mm jack"
- *     Index 0
- *
- *     EnableSequence
- *             ....
- *     EndSequence
- *
- *     DisableSequence
- *             ...
- *     EndSequence
- *
- *     #Optional control aliases
- *     MasterPlaybackVolume  'Device Master Playback Volume'
- *     MasterPlaybackSwitch  'Device Master Playback Switch'
- *
- * EndSection
- */
-static int parse_device(snd_use_case_mgr_t *uc_mgr,
-               struct use_case_verb *verb, FILE *f, int *line_, char *file)
-{
-       struct use_case_device *device;
-       int line = *line_, end = 0, en_seq = 0, dis_seq = 0, id = 0, ret;
-       char buf[MAX_BUF], *tbuf;
-       char *name = NULL, *comment;
-
-       /* allocate device  */
-       verb->device = realloc(verb->device,
-               (verb->num_devices + 1) * sizeof(struct use_case_device));
-       if (verb->device == NULL)
-               return -ENOMEM;
-       device = verb->device + verb->num_devices;
-       bzero(device, sizeof(struct use_case_device));
-
-       /* read line by line */
-       while(fgets(buf, MAX_BUF, f) != NULL) {
-
-               line++;
-
-               /* skip comments */
-               if (buf[0] == '#')
-                       continue;
-
-               tbuf = buf;
-               /* skip spaces */
-               while (isblank(*tbuf))
-                       tbuf++;
-
-               /* get use case device name */
-               if (strncmp(tbuf, "Name", 4) == 0) {
-                       name = get_string(tbuf + 4);
-                       if (name == NULL) {
-                               uc_error("error: %s:%d failed to get device name",
-                                               file, line);
-                               goto err;
-                       }
-                       device->name = name;
-                       id = 1;
-                       continue;
-               }
-
-               if (strncmp(tbuf, "Comment", 8) == 0) {
-                       comment = get_string(tbuf + 8);
-                       if (name == NULL) {
-                               uc_error("error: %s: %d failed to get device comment",
-                                               file, line);
-                               goto err;
-                       }
-
-                       device->comment = comment;
-                       continue;
-               }
-
-               if (strncmp(tbuf, "Index", 5) == 0) {
-                       device->idx = atoi(tbuf + 5);
-                       if (device->idx < 0) {
-                               uc_error("error: %s:%d failed to get device index",
-                                               file, line);
-                               goto err;
-                       }
-                       continue;
-               }
-
-               if (strncmp(tbuf, "EnableSequence", 14) == 0) {
-                       ret = parse_sequence(uc_mgr, &device->enable, f,
-                                       &line, file);
-                       if (ret < 0) {
-                               uc_error("error: %s:%d failed to parse device enable"
-                                       " sequence", file, line);
-                               goto err;
-                       }
-                       en_seq = 1;
-                       continue;
-               }
-
-               if (strncmp(tbuf, "DisableSequence", 15) == 0) {
-                       uc_dbg("DisableSequence");
-                       ret = parse_sequence(uc_mgr, &device->disable, f,
-                                       &line, file);
-                       if (ret < 0) {
-                               uc_error("error: %s:%d failed to parse device disable sequence",
-                                               file, line);
-                               goto err;
-                       }
-                       dis_seq = 1;
-                       continue;
-               }
-
-               if (strncmp(tbuf, "TransitionDevice", 14) == 0) {
-                       struct transition_sequence *trans_seq;
-
-                       name = get_string(tbuf + 14);
-                       if (name == NULL)
-                               continue;
-
-                       uc_dbg("TransitionDevice %s", name);
-
-                       trans_seq = calloc(1, sizeof(struct transition_sequence));
-                       if (trans_seq == NULL)
-                               return -ENOMEM;
-
-                       trans_seq->name = name;
-
-                       ret = parse_sequence(uc_mgr, &trans_seq->transition, f,
-                                       &line, file);
-                       if (ret < 0) {
-                               uc_error("error: %s:%d failed to parse transition"
-                                       " device", file, line);
-                               goto err;
-                       }
-
-                       prepend_transition(&device->transition_list, trans_seq);
-                       continue;
-               }
-
-               if (strncmp(tbuf, "MasterPlaybackVolume", 20) == 0) {
-                       device->playback_volume_id =
-                               get_control_name(tbuf + 20, line, file);
-                       if (device->playback_volume_id == NULL) {
-                               uc_error("error: %s:%d failed to get MasterPlaybackVolume",
-                                               file, line);
-                               goto err;
-                       }
-                       continue;
-               }
-
-               if (strncmp(tbuf, "MasterPlaybackSwitch", 20) == 0) {
-                       device->playback_switch_id =
-                               get_control_name(tbuf + 20, line, file);
-                       if (device->playback_switch_id == NULL) {
-                               uc_error("error: %s:%d failed to get MasterPlaybackSwitch",
-                                               file, line);
-                               goto err;
-                       }
-                       continue;
-               }
-
-               if (strncmp(tbuf, "MasterCaptureVolume", 19) == 0) {
-                       device->capture_volume_id =
-                               get_control_name(tbuf + 19, line, file);
-                       if (device->capture_volume_id == NULL) {
-                               uc_error("error: %s:%d failed to get MasterCaptureVolume%d",
-                                               file, line);
-                               goto err;
-                       }
-                       continue;
-               }
-
-               if (strncmp(tbuf, "MasterCaptureSwitch", 19) == 0) {
-                       device->capture_switch_id =
-                               get_control_name(tbuf + 19, line, file);
-                       if (device->capture_switch_id == NULL) {
-                               uc_error("error: %s:%d failed to get MasterCaptureSwitch",
-                                               file, line);
-                               goto err;
-                       }
-                       continue;
-               }
-
-               /* end of section ?*/
-               if (strncmp(tbuf, "EndSection", 10) == 0) {
-                       end = 1;
-                       break;
-               }
-       }
-
-       /* do we have the basics for this device ? */
-       if (!en_seq || !dis_seq || !end || !id) {
-               uc_error("error: invalid device");
-               if (!en_seq)
-                       uc_error("error: %s: device missing enable sequence", file);
-               if (!dis_seq)
-                       uc_error("error: %s: device missing disable sequence", file);
-               if (!end)
-                       uc_error("error: %s: device missing end", file);
-               return -EINVAL;
-       }
-
-       verb->device_list[verb->num_devices++] = device->name;
-       *line_ = line;
-       return 0;
-
-err:
-       if (ferror(f)) {
-               uc_error("%s: failed to read device section", file);
-               return ferror(f);
-       }
-       return -ENOMEM;
-}
-
-/*
- * Parse Verb Section
- *
- * # Example Use case verb section for Voice call blah
- * # By Joe Blogs <joe@blogs.com>
- *
- * SectionVerb
- *     # enable and disable sequences are compulsory
- *     EnableSequence
- *             'Master Playback Switch':2:0,0
- *             'Master Playback Volume':2:25,25
- *             msleep 50
- *             'Master Playback Switch':2:1,1
- *             'Master Playback Volume':2:50,50
- *     EndSequence
- *
- *     DisableSequence
- *             'Master Playback Switch':2:0,0
- *             'Master Playback Volume':2:25,25
- *             msleep 50
- *             'Master Playback Switch':2:1,1
- *             'Master Playback Volume':2:50,50
- *     EndSequence
- *
- *     # Optional QoS and ALSA PCMs
- *     QoS HiFi
- *     CapturePCM 0
- *     PlaybackPCM 0
- *
- * EndSection
- */
-static int parse_verb(snd_use_case_mgr_t *uc_mgr,
-               struct use_case_verb *verb, FILE *f, int *line_, char *file)
-{
-       int line = *line_, end = 0, en_seq = 0, dis_seq = 0, ret;
-       char buf[MAX_BUF], *tbuf;
-
-       /* read line by line */
-       while(fgets(buf, MAX_BUF, f) != NULL) {
-
-               line++;
-
-               /* skip comments */
-               if (buf[0] == '#')
-                       continue;
-
-               tbuf = buf;
-               /* skip spaces */
-               while (isblank(*tbuf))
-                       tbuf++;
-
-               if (strncmp(tbuf, "EnableSequence", 14) == 0) {
-                       uc_dbg("Parse EnableSequence");
-                       ret = parse_sequence(uc_mgr, &verb->enable, f, &line, file);
-                       if (ret < 0) {
-                               uc_error("error: %s:%d failed to parse verb enable sequence",
-                                               file, line);
-                               goto err;
-                       }
-                       en_seq = 1;
-                       continue;
-               }
-
-               if (strncmp(tbuf, "DisableSequence", 15) == 0) {
-                       uc_dbg("Parse DisableSequence");
-                       ret = parse_sequence(uc_mgr, &verb->disable, f, &line, file);
-                       if (ret < 0) {
-                               uc_error("error: %s:%d failed to parse verb disable sequence",
-                                               file, line);
-                               goto err;
-                       }
-                       dis_seq = 1;
-                       continue;
-               }
-
-               if (strncmp(tbuf, "TransitionVerb", 12) == 0) {
-                       struct transition_sequence *trans_seq;
-                       char *name;
-
-                       name = get_string(tbuf + 12);
-                       if (name == NULL)
-                               continue;
-
-                       uc_dbg("TransitionVerb %s", name);
-
-                       trans_seq = calloc(1, sizeof(struct transition_sequence));
-                       if (trans_seq == NULL)
-                               return -ENOMEM;
-
-                       trans_seq->name = name;
-
-                       ret = parse_sequence(uc_mgr, &trans_seq->transition, f,
-                               &line, file);
-                       if (ret < 0) {
-                               uc_error("error: %s:%d failed to parse transition verb",
-                                               file, line);
-                               goto err;
-                       }
-
-                       prepend_transition(&verb->transition_list, trans_seq);
-                       continue;
-               }
-
-               if (strncmp(tbuf, "QoS", 3) == 0) {
-                       uc_dbg("Parse Qos");
-                       verb->qos = get_enum(tbuf + 3);
-                       continue;
-               }
-
-               if (strncmp(tbuf, "CapturePCM", 3) == 0) {
-                       uc_dbg("Parse CapTurePCM");
-                       verb->capture_pcm = atoi(tbuf + 3);
-                       if (verb->capture_pcm < 0) {
-                               uc_error("error: %s:%d failed to get Capture PCM ID",
-                                               file, line);
-                               goto err;
-                       }
-                       continue;
-               }
-
-               if (strncmp(tbuf, "PlaybackPCM", 3) == 0) {
-                       uc_dbg("Parse PlaybackPCM");
-                       verb->playback_pcm = atoi(tbuf + 3);
-                       if (verb->playback_pcm < 0) {
-                               uc_error("error: %s: %d failed to get Playback PCM ID",
-                                               file, line);
-                               goto err;
-                       }
-                       continue;
-               }
-
-               /* end of section ?*/
-               if (strncmp(tbuf, "EndSection", 10) == 0) {
-                       end = 1;
-                       break;
-               }
-       }
-
-       /* do we have both use case name and file ? */
-       if (!en_seq || !dis_seq || !end) {
-                       uc_error("error: invalid verb");
-               if (!en_seq)
-                       uc_error("error: %s: verb missing enable sequence", file);
-               if (!dis_seq)
-                       uc_error("error: %s: verb missing disable sequence", file);
-               if (!end)
-                       uc_error("error: %s: verb missing end", file);
-               return -EINVAL;
-       }
-
-       *line_ = line;
-       return 0;
-
-err:
-       if (ferror(f)) {
-               uc_error("error: failed to read verb master section");
-               return ferror(f);
-       }
-       return -ENOMEM;
-}
-
-/*
- * Parse a Use case verb file.
- *
- * This file contains the following :-
- *  o Verb enable and disable sequences.
- *  o Supported Device enable and disable sequences for verb.
- *  o Supported Modifier enable and disable sequences for verb
- *  o Optional QoS for the verb and modifiers.
- *  o Optional PCM device ID for verb and modifiers
- *  o Alias kcontrols IDs for master and volumes and mutes.
- */
-static int parse_verb_file(snd_use_case_mgr_t *uc_mgr,
-                       char *use_case_name, char *file)
-{
-       struct use_case_verb *verb;
-       FILE *f;
-       int line = 0, ret = 0, dev_idx = 0, verb_idx = 0, mod_idx = 0;
-       char buf[MAX_BUF], *tbuf;
-       char filename[MAX_FILE];
-
-       /* allocate verb */
-       uc_mgr->verb = realloc(uc_mgr->verb,
-               (uc_mgr->num_verbs + 1) * sizeof(struct use_case_verb));
-       if (uc_mgr->verb == NULL)
-               return -ENOMEM;
-       verb = uc_mgr->verb +uc_mgr->num_verbs;
-       bzero(verb, sizeof(struct use_case_verb));
-
-       /* open Verb file for reading */
-       sprintf(filename, "%s/%s/%s", ALSA_USE_CASE_DIR,
-               uc_mgr->card_name, file);
-
-       f = fopen(filename, "r");
-       if (f == NULL) {
-               uc_error("error: failed to open verb file %s : %d",
-                       filename, -errno);
-               return -errno;
-       }
-
-       /* read line by line */
-       while(fgets(buf, MAX_BUF, f) != NULL) {
-
-               line++;
-
-               /* skip comments */
-               if (buf[0] == '#')
-                       continue;
-
-               /* skip leading spaces */
-               tbuf = buf;
-               while (isblank(*tbuf))
-                       tbuf++;
-
-               /* find verb section and parse it */
-               if (strncmp(tbuf, "SectionVerb", 11) == 0) {
-                       ret = parse_verb(uc_mgr, verb, f, &line, file);
-                       if (ret < 0) {
-                               uc_error("error: %s:%d failed to parse verb %s",
-                                       file, line, use_case_name);
-                               goto err;
-                       }
-                       verb_idx++;
-                       continue;
-               }
-
-               /* find device sections and parse them */
-               if (strncmp(tbuf, "SectionDevice", 13) == 0) {
-
-                       if (verb->num_devices >= MAX_DEVICE) {
-                               uc_error("error: %s:%d verb number of devices %d"
-                                       "exceeds max %d", file, line,
-                                       verb->num_devices, MAX_DEVICE);
-                               goto err;
-                       }
-                       ret = parse_device(uc_mgr, verb, f, &line, file);
-                       if (ret < 0) {
-                               uc_error("error: %s:%d failed to parse device",
-                                               file, line);
-                               goto err;
-                       }
-                       dev_idx++;
-                       continue;
-               }
-
-               /* find modifier sections and parse them */
-               if (strncmp(tbuf, "SectionModifier", 15) == 0) {
-                       if (verb->num_modifiers >= MAX_MODIFIER) {
-                               uc_error("error: %s:%d verb number of modifiers %d"
-                                       " exceeds max %d", file, line,
-                                       verb->num_modifiers, MAX_MODIFIER);
-                               goto err;
-                       }
-
-                       ret = parse_modifier(uc_mgr, verb, f, &line, file);
-                       if (ret < 0) {
-                               uc_error("error: %s:%d failed to parse modifier",
-                                               file, line);
-                               goto err;
-                       }
-                       mod_idx++;
-                       continue;
-               }
-       }
-
-       /* use case verb must have at least verb and 1 device */
-       if (verb_idx && dev_idx) {
-               uc_mgr->verb_list[uc_mgr->num_verbs++] = use_case_name;
-               verb->name = use_case_name;
-       }
-       else {
-               uc_error("error: failed to parse use case %s", file);
-               if (verb_idx == 0)
-                       uc_error("error: no use case verb defined", file);
-               if (dev_idx == 0)
-                       uc_error("error: no use case device defined", file);
-               ret = -EINVAL;
-       }
-
-err:
-       fclose(f);
-       return ret;
-}
-
-/*
- * Parse master section for "Use Case" and "File" tags.
- */
-static int parse_master_section(snd_use_case_mgr_t *uc_mgr, FILE *f,
-                       int *line_)
-{
-       int line = *line_ - 1, end = 0;
-       char buf[MAX_BUF], *tbuf;
-       char *file = NULL, *use_case_name = NULL, *comment;
-
-       /* read line by line */
-       while(fgets(buf, MAX_BUF, f) != NULL) {
-
-               line++;
-
-               /* skip comments */
-               if (buf[0] == '#')
-                       continue;
-
-               uc_dbg("%s", buf);
-
-               /* skip leading spaces */
-               tbuf = buf;
-               while (isblank(*tbuf))
-                       tbuf++;
-
-               /* get use case name */
-               if (strncmp(tbuf, "Use Case", 8) == 0) {
-                       use_case_name = get_string(tbuf + 8);
-                       if (use_case_name == NULL) {
-                               uc_error("error: failed to get Use Case at line %d",
-                                               line);
-                               goto err;
-                       }
-
-                       if (uc_mgr->num_verbs >= MAX_VERB) {
-                               uc_error("error: verb number exceed max %d",
-                                                               uc_mgr->num_verbs, MAX_VERB);
-                               goto err;
-                       }
-                       continue;
-               }
-
-               /* get use case verb file name */
-               if (strncmp(tbuf, "File", 4) == 0) {
-                       file = get_string(tbuf + 4);
-                       if (file == NULL) {
-                               uc_error("error: failed to get File at line %d", line);
-                               goto err;
-                       }
-                       continue;
-               }
-
-               /* get optional use case comment */
-               if (strncmp(tbuf, "Comment", 7) == 0) {
-                       comment = get_string(tbuf + 7);
-                       if (comment == NULL) {
-                               uc_error("error: failed to get Comment at line %d",
-                                               line);
-                               goto err;
-                       }
-                       continue;
-               }
-
-               /* end of section ?*/
-               if (strncmp(tbuf, "EndSectionUseCase", 10) == 0) {
-                       end = 1;
-                       break;
-               }
-       }
-
-       uc_dbg("use_case_name %s file %s end %d", use_case_name, file, end);
-
-       /* do we have both use case name and file ? */
-       if (!use_case_name || !file || !end) {
-               uc_error("error: failed to find use case\n");
-               if (!use_case_name)
-                       uc_error("error: use case missing name");
-               if (!file)
-                       uc_error("error: use case missing file");
-               if (!end)
-                       uc_error("error: use case missing end");
-               return -EINVAL;
-       }
-
-       *line_ = line;
-
-       /* parse verb file */
-       return parse_verb_file(uc_mgr, use_case_name, file);
-
-err:
-       if (ferror(f)) {
-               uc_error("error: failed to read use case master section");
-               return ferror(f);
-       }
-       return -ENOMEM;
-}
-
-/*
- * Each sound card has a master sound card file that lists all the supported
- * use case verbs for that sound card. i.e.
- *
- * #Example master file for blah sound card
- * #By Joe Blogs <joe@bloggs.org>
- *
- * # The file is divided into Use case sections. One section per use case verb.
- *
- * SectionUseCase
- *             Use Case "Voice Call"
- *             File "voice_call_blah"
- *             Comment "Make a voice phone call."
- * EndSectionUseCase
- *
- * SectionUseCase
- *             Use Case "HiFi"
- *             File "hifi_blah"
- *             Comment "Play and record HiFi quality Music."
- * EndSectionUseCase
- *
- * # This file also stores the default sound card state.
- *
- * SectionDefaults
- *             'Master Playback Switch':2:1,1
- *             'Master Playback Volume':2:25,25
- *             'Master Mono Playback Switch':1:0
- *             'Master Mono Playback Volume':1:0
- *             'PCM Switch':2:1,1
- *             ........
- * EndSectionDefaults
- *
- * # End of example file.
- */
-static int parse_master_file(snd_use_case_mgr_t *uc_mgr, FILE *f,
-               char *file)
-{
-       int line = 0, ret = 0;
-       char buf[MAX_BUF], *tbuf;
-
-       /* parse master config sections */
-       while(fgets(buf, MAX_BUF, f) != NULL) {
-
-               line++;
-
-               /* ignore comments */
-               if (buf[0] == '#') {
-                       line++;
-                       continue;
-               }
-
-               /* find use case section and parse it */
-               if (strncmp(buf, "SectionUseCase", 14) == 0) {
-                       tbuf = buf + 14;
-                       while (isblank(*tbuf))
-                               tbuf++;
-                       ret = parse_master_section(uc_mgr, f, &line);
-                       if (ret < 0)
-                               goto err;
-               }
-
-               /* find default control values section and parse it */
-               if (strncmp(buf, "SectionDefaults", 15) == 0) {
-                       tbuf = buf + 15;
-                       while (isblank(*tbuf))
-                               tbuf++;
-                       ret = parse_controls(uc_mgr, f, &line, file);
-                       if (ret < 0)
-                               goto err;
-               }
-       }
-
-err:
-       if (ferror(f)) {
-               uc_error("error: %s: failed to read master file", file);
-               return ferror(f);
-       }
-       return ret;
-}
-
-/* load master use case file for sound card */
-static int import_master_config(snd_use_case_mgr_t *uc_mgr)
-{
-       int ret;
-       FILE *f;
-       char filename[MAX_FILE];
-
-       sprintf(filename, "%s/%s/%s.conf", ALSA_USE_CASE_DIR,
-               uc_mgr->card_name, uc_mgr->card_name);
-
-       uc_dbg("master config file %s", filename);
-
-       f = fopen(filename, "r");
-       if (f == NULL) {
-               uc_error("error: couldn't open %s configuration file %s",
-                               uc_mgr->card_name, filename);
-               return -errno;
-       }
-
-       ret = parse_master_file(uc_mgr, f, uc_mgr->card_name);
-       fclose(f);
-       return ret;
-}
-
-static int parse_card_controls(snd_use_case_mgr_t *uc_mgr)
-{
-       struct control_settings *control;
-       int i, ret = 0;
-       snd_ctl_elem_id_t *id;
-
-       /* allocate memory for controls */
-       uc_mgr->control = calloc(uc_mgr->count,
-               sizeof(struct control_settings));
-       if (uc_mgr->control == NULL) {
-               uc_error("error: not enough memory to store controls.\n");
-               return -ENOMEM;
-       }
-       control = uc_mgr->control;
-       snd_ctl_elem_id_alloca(&id);
-
-       /* iterate through each kcontrol and add to manager */
-       for (i = 0; i < uc_mgr->count; ++i) {
-
-               snd_ctl_elem_list_get_id(uc_mgr->list, i, id);
-               ret = add_control(uc_mgr->handle, id, control++);
-               if (ret < 0) {
-                       uc_error("error: failed to add control error %s\n",
-                               __func__, snd_strerror(ret));
-                       break;
-               }
-       }
-
-       return ret;
-}
-
-static int import_use_case_files(snd_use_case_mgr_t *uc_mgr)
-{
-       int ret;
-
-       /* import the master file and default kcontrol settings */
-       ret = import_master_config(uc_mgr);
-       if (ret < 0) {
-               uc_error("error: failed to parse master use case config %s\n",
-                               uc_mgr->card_name);
-               return ret;
-       }
-
-       return 0;
-}
-
-
-static void free_sequence(struct sequence_element *sequence)
-{
-       struct sequence_element *element = sequence;
-
-       while (element) {
-               struct sequence_element *pre_element;
-
-               if (element->control) {
-                       free(element->control->value);
-                       free(element->control);
-               }
-               pre_element = element;
-               element = element->next;
-               free(pre_element);
-       }
-}
-
-static void free_transition_sequence_element(struct transition_sequence *trans)
-{
-       free(trans->name);
-       free_sequence(trans->transition);
-       free(trans);
-}
-
-static void free_transition_sequence(struct transition_sequence *transition_list)
-{
-       struct transition_sequence *last, *trans_sequence = transition_list;
-
-       while (trans_sequence) {
-               last = trans_sequence;
-               trans_sequence =  trans_sequence->next;
-               free_transition_sequence_element(last);
-       }
-}
-
-static void free_modifier(struct use_case_modifier *modifier)
-{
-       if (!modifier)
-               return;
-
-       free(modifier->name);
-       free(modifier->comment);
-       free(modifier->playback_volume_id);
-       free(modifier->playback_switch_id);
-       free(modifier->capture_volume_id);
-       free(modifier->capture_switch_id);
-
-       free_sequence(modifier->enable);
-       free_sequence(modifier->disable);
-       free_transition_sequence(modifier->transition_list);
-}
-
-static void free_device(struct use_case_device *device)
-{
-       if (!device)
-               return;
-
-       free(device->name);
-       free(device->comment);
-       free(device->playback_volume_id);
-       free(device->playback_switch_id);
-       free(device->capture_volume_id);
-       free(device->capture_switch_id);
-
-       free_sequence(device->enable);
-       free_sequence(device->disable);
-       free_transition_sequence(device->transition_list);
-}
-
-static void free_devices(struct use_case_device *devices, int num_devices)
-{
-       int i;
-
-       if (!devices)
-               return;
-
-       for (i = 0; i< num_devices; i++)
-               free_device(devices + i);
-
-       free(devices);
-}
-
-static void free_modifiers(struct use_case_modifier *modifiers,
-                                               int num_modifiers)
-{
-       int i;
-
-       if (!modifiers)
-               return;
-
-       for (i = 0; i < num_modifiers; i++)
-               free_modifier(modifiers + i);
-
-       free(modifiers);
-}
-
-static void free_verb(struct use_case_verb *verb)
-{
-       if (!verb)
-               return;
-
-       free(verb->name);
-       free(verb->comment);
-
-       free_sequence(verb->enable);
-       free_sequence(verb->disable);
-       free_transition_sequence(verb->transition_list);
-
-       free_devices(verb->device, verb->num_devices);
-       free_modifiers(verb->modifier, verb->num_modifiers);
-}
-
-static void free_verbs(struct use_case_verb *verbs, int num_verbs)
-{
-       int i;
-
-       if (!verbs)
-               return;
-
-       for (i = 0; i < num_verbs; i++)
-               free_verb(verbs + i);
-
-       free(verbs);
-}
-
-static void free_controls(struct control_settings *controls, int num_controls)
-{
-       int i = 0;
-
-       if (!controls)
-               return;
-
-       for(i = 0; i < num_controls; i++){
-               struct control_settings *control = controls + i;
-               free(control->value);
-       }
-       free(controls);
-}
-
-/*
- * Free all use case manager resources.
- * Callers holds locks.
- */
-static void free_uc_mgr(snd_use_case_mgr_t *uc_mgr)
-{
-       if (uc_mgr == NULL)
-               return;
-
-       if (uc_mgr->info)
-               snd_ctl_card_info_free(uc_mgr->info);
-       if (uc_mgr->list)
-               snd_ctl_elem_list_free(uc_mgr->list);
-       if (uc_mgr->id)
-               snd_ctl_elem_id_free(uc_mgr->id);
-
-       if (uc_mgr->handle)
-               snd_ctl_close(uc_mgr->handle);
-
-       free(uc_mgr->card_name);
-       free(uc_mgr->ctl_name);
-
-       free_verbs(uc_mgr->verb, uc_mgr->num_verbs);
-
-       free_controls(uc_mgr->control, uc_mgr->count);
-
-       pthread_mutex_destroy(&uc_mgr->mutex);
-
-       free(uc_mgr);
-}
-
- /**
- * \brief Init sound card use case manager.
- * \param uc_mgr Use case manager
- * \return zero on success, otherwise a negative error code
- */
-snd_use_case_mgr_t *snd_use_case_mgr_open(const char *card_name)
-{
-       snd_use_case_mgr_t *uc_mgr;
-       char ctl_name[8];
-       int err, idx;
-
-       idx = snd_card_get_index(card_name);
-       if (idx < 0) {
-               uc_error("error: can't get sound card %s: %s",
-                               card_name, snd_strerror(idx));
-               return NULL;
-       }
-
-       /* create a new UCM */
-       uc_mgr = calloc(1, sizeof(snd_use_case_mgr_t));
-       if (uc_mgr == NULL)
-               return NULL;
-
-       uc_mgr->card_name = strdup(card_name);
-       if (uc_mgr->card_name == NULL) {
-               free(uc_mgr);
-               return NULL;
-       }
-       sprintf(ctl_name, "hw:%d", idx);
-       uc_mgr->ctl_name = strdup(ctl_name);
-       if (uc_mgr->ctl_name == NULL) {
-               free_uc_mgr(uc_mgr);
-               return NULL;
-       }
-       if (snd_ctl_card_info_malloc(&uc_mgr->info) < 0) {
-               free_uc_mgr(uc_mgr);
-               return NULL;
-       }
-       if (snd_ctl_elem_list_malloc(&uc_mgr->list) < 0) {
-               free_uc_mgr(uc_mgr);
-               return NULL;
-       }
-       if (snd_ctl_elem_id_malloc(&uc_mgr->id) < 0) {
-               free_uc_mgr(uc_mgr);
-               return NULL;
-       }
-
-       /* open and init CTLs */
-       err = snd_ctl_open(&uc_mgr->handle, uc_mgr->ctl_name, 0);
-       if (err) {
-               uc_error("error: can't open sound card %s: %s",
-                       uc_mgr->card_name, snd_strerror(err));
-               goto err;
-       }
-
-       err = snd_ctl_card_info(uc_mgr->handle, uc_mgr->info);
-       if (err < 0) {
-               uc_error("error: can't get sound card %s control info: %s",
-                       uc_mgr->card_name, snd_strerror(err));
-               goto err;
-       }
-
-       err = snd_ctl_elem_list(uc_mgr->handle, uc_mgr->list);
-       if (err < 0) {
-               uc_error("error: can't get sound card %s elements: %s",
-                       uc_mgr->card_name, snd_strerror(err));
-               goto err;
-       }
-
-       uc_mgr->count = snd_ctl_elem_list_get_count(uc_mgr->list);
-       if (uc_mgr->count < 0) {
-               uc_error("error: can't get sound card %s controls %s:",
-                               uc_mgr->card_name, snd_strerror(err));
-               goto err;
-       }
-
-       snd_ctl_elem_list_set_offset(uc_mgr->list, 0);
-       if (snd_ctl_elem_list_alloc_space(uc_mgr->list, uc_mgr->count) < 0) {
-               uc_error("error: could not allocate elements for %s",
-                       uc_mgr->card_name);
-               goto err;
-       }
-
-       err = snd_ctl_elem_list(uc_mgr->handle, uc_mgr->list);
-       if (err < 0) {
-               uc_error("error: could not get elements for %s : %s",
-                       uc_mgr->card_name, snd_strerror(err));
-               goto err;
-       }
-
-       /* get info about sound card */
-       err = parse_card_controls(uc_mgr);
-       if (err < 0) {
-               uc_error("error: failed to parse sound device %s controls %d",
-                       card_name, err);
-               goto err;
-       }
-
-       /* get info on use_cases and verify against card */
-       err = import_use_case_files(uc_mgr);
-       if (err < 0) {
-               uc_error("error: failed to import %s use case configuration %d",
-                       card_name, err);
-               goto err;
-       }
-
-       pthread_mutex_init(&uc_mgr->mutex, NULL);
-       uc_mgr->card.current_verb = VERB_NOT_INITIALISED;
-
-       return uc_mgr;
-
-err:
-       free_uc_mgr(uc_mgr);
-       return NULL;
-}
-
- /**
- * \brief Reload and reparse all use case files.
- * \param uc_mgr Use case manager
- * \return zero on success, otherwise a negative error code
- */
-int snd_use_case_mgr_reload(snd_use_case_mgr_t *uc_mgr)
-{
-       int ret;
-
-       pthread_mutex_lock(&uc_mgr->mutex);
-
-       free_verbs(uc_mgr->verb, uc_mgr->num_verbs);
-       free_controls(uc_mgr->control, uc_mgr->count);
-
-       /* reload all sound card controls */
-       ret = parse_card_controls(uc_mgr);
-       if (ret <= 0) {
-               uc_error("error: failed to reload sound card controls %d\n",
-                       ret);
-               free_uc_mgr(uc_mgr);
-               return -EINVAL;
-       }
-
-       /* reload all use cases */
-       uc_mgr->num_verbs = import_use_case_files(uc_mgr);
-       if (uc_mgr->num_verbs <= 0) {
-               uc_error("error: failed to reload use cases\n");
-               return -EINVAL;
-       }
-
-       pthread_mutex_unlock(&uc_mgr->mutex);
-       return ret;
-}
-
- /**
- * \brief Close use case manager.
- * \param uc_mgr Use case manager
- * \return zero on success, otherwise a negative error code
- */
-int snd_use_case_mgr_close(snd_use_case_mgr_t *uc_mgr)
-{
-       free_uc_mgr(uc_mgr);
-
-       return 0;
-}
-
- /**
- * \brief Reset sound card controls to default values.
- * \param uc_mgr Use case manager
- * \return zero on success, otherwise a negative error code
- */
-int snd_use_case_mgr_reset(snd_use_case_mgr_t *uc_mgr)
-{
-       int ret = 0, i;
-       struct control_settings *control;
-
-       pthread_mutex_lock(&uc_mgr->mutex);
-
-       for (i = 0; i < uc_mgr->count; i++) {
-               control = &uc_mgr->control[i];
-
-               /* Only set default value specified in master config file */
-               if (control->value == NULL)
-                       continue;
-
-               ret = set_control_default(uc_mgr, control);
-               if (ret < 0)
-                       goto out;
-       }
-       uc_mgr->card.current_verb = VERB_NOT_INITIALISED;
-out:
-       pthread_mutex_unlock(&uc_mgr->mutex);
-       return ret;
-}
-
-
-/*
- * Change a sound card control to a new value.
- */
-static int set_control(snd_ctl_t *handle, snd_ctl_elem_id_t *id,
-       snd_use_case_mgr_t *uc_mgr, unsigned short value[])
-{
-       struct control_settings *setting;
-       int ret, count, i;
-       unsigned int idnum;
-       snd_ctl_elem_info_t *info;
-       snd_ctl_elem_type_t type;
-       snd_ctl_elem_value_t *control;
-
-       snd_ctl_elem_info_alloca(&info);
-       snd_ctl_elem_value_alloca(&control);
-
-       snd_ctl_elem_info_set_id(info, id);
-       ret = snd_ctl_elem_info(handle, info);
-       if (ret < 0) {
-               uc_error("error: failed to get ctl elem info %d: ",
-                       snd_strerror(ret));
-               return ret;
-       }
-
-       snd_ctl_elem_value_set_id(control, id);
-       snd_ctl_elem_read(handle, control);
-
-       idnum = snd_ctl_elem_id_get_numid(id);
-       for (i = 0; i < uc_mgr->count; i++) {
-               setting = &uc_mgr->control[i];
-               if (setting->id == idnum)
-                       goto set_val;
-       }
-       uc_error("error: failed to find control at id %d", idnum);
-       return 0;
-
-set_val:
-       uc_dbg("set control %s id %d count %d", setting->name, setting->id,
-                       setting->count);
-
-       type = snd_ctl_elem_info_get_type(info);
-       count = snd_ctl_elem_info_get_count(info);
-       if (count == 0)
-               return 0;
-
-       uc_dbg("type %d count %d", type, count);
-
-       switch (type) {
-       case SND_CTL_ELEM_TYPE_BOOLEAN:
-               for (i = 0; i < count; i++) {
-                       uc_dbg("count %d value %u", i, *(value + i));
-                       snd_ctl_elem_value_set_boolean(control, i, value[i]);
-               }
-               break;
-       case SND_CTL_ELEM_TYPE_INTEGER:
-               uc_dbg("int");
-               for (i = 0; i < count; i++) {
-                       uc_dbg("count %d value %u", i, value[i]);
-                       snd_ctl_elem_value_set_integer(control, i, value[i]);
-               }
-               break;
-       case SND_CTL_ELEM_TYPE_INTEGER64:
-               uc_dbg("int64");
-               for (i = 0; i < count; i++) {
-                       uc_dbg("count %d value %u", i, value[i]);
-                       snd_ctl_elem_value_set_integer64(control, i, value[i]);
-               }
-
-               break;
-       case SND_CTL_ELEM_TYPE_ENUMERATED:
-               uc_dbg("enumerated");
-               for (i = 0; i < count; i++) {
-                       uc_dbg("count %d value %u", i, value[i]);
-                       snd_ctl_elem_value_set_enumerated(control, i, value[i]);
-               }
-               break;
-       case SND_CTL_ELEM_TYPE_BYTES:
-               uc_dbg("bytes");
-               for (i = 0; i < count; i++) {
-                       uc_dbg("count %d value %u", i, value[i]);
-                       snd_ctl_elem_value_set_byte(control, i, value[i]);
-               }
-               break;
-       default:
-               break;
-       }
-
-       ret = snd_ctl_elem_write(handle, control);
-       if (ret < 0) {
-               uc_error("error: failed to set control %s: %s",
-                        setting->name, snd_strerror(ret));
-               uc_error("error: count %d type: %d",
-                       count, type);
-               for (i = 0; i < count; i++)
-                       fprintf(stderr, "%d ", get_value(setting, i));
-               return ret;
-       }
-       return 0;
-}
-
-/*
- * Execute a sequence of control writes.
- */
-static int exec_sequence(struct sequence_element *seq, snd_use_case_mgr_t
-                       *uc_mgr, snd_ctl_elem_list_t *list, snd_ctl_t *handle)
-{
-       int count = snd_ctl_elem_list_get_count(list);
-       int ret, i;
-
-       uc_dbg("");
-
-       /* keep going until end of sequence */
-       while (seq) {
-               /* do we need to sleep */
-               if (seq->sleep) {
-                       uc_dbg("msleep %d", seq->sleep);
-                       usleep(seq->sleep);
-               } else {
-                       uc_dbg("control name %s, id %d, count %d, vale[1] %u",
-                               seq->control->name, seq->control->id,
-                               seq->control->count, seq->control->value[0]);
-
-                       /* control write */
-                       snd_ctl_elem_id_t *id;
-                       snd_ctl_elem_id_alloca(&id);
-                       unsigned int numid;
-
-                       /* Where is id lookup from numid if you need it? */
-                       for (i = 0; i < count; ++i) {
-
-                               snd_ctl_elem_list_get_id(list, i, id);
-                               numid = snd_ctl_elem_id_get_numid(id);
-
-                               if (numid == seq->control->id) {
-                                       ret = set_control(handle, id, uc_mgr, seq->control->value);
-                                       if (ret < 0) {
-                                               uc_error("error: failed to set control %s",
-                                                       __func__, uc_mgr->card_name);
-                                               return ret;
-                                       }
-                                       break;
-                               }
-                       }
-               }
-               seq = seq->next;
-       }
-       return 0;
-}
-
-static int enable_use_case_verb(snd_use_case_mgr_t *uc_mgr, int verb_id,
-               snd_ctl_elem_list_t *list, snd_ctl_t *handle)
-{
-       struct use_case_verb *verb;
-       int ret;
-
-       if (verb_id >= uc_mgr->num_verbs) {
-               uc_error("error: invalid verb id %d", verb_id);
-               return -EINVAL;
-       }
-       verb = &uc_mgr->verb[verb_id];
-
-       uc_dbg("verb %s", verb->name);
-       ret = exec_sequence(verb->enable, uc_mgr, list, handle);
-       if (ret < 0) {
-               uc_error("error: could not enable verb %s", verb->name);
-               return ret;
-       }
-       uc_mgr->card.current_verb = verb_id;
-
-       return 0;
-}
-
-static int disable_use_case_verb(snd_use_case_mgr_t *uc_mgr, int verb_id,
-               snd_ctl_elem_list_t *list, snd_ctl_t *handle)
-{
-       struct use_case_verb *verb;
-       int ret;
-
-       if (verb_id >= uc_mgr->num_verbs) {
-               uc_error("error: invalid verb id %d", verb_id);
-               return -EINVAL;
-       }
-       verb = &uc_mgr->verb[verb_id];
-
-       /* we set the invalid verb at open() but we should still
-        * check that this succeeded */
-       if (verb == NULL)
-               return 0;
-
-       uc_dbg("verb %s", verb->name);
-       ret = exec_sequence(verb->disable, uc_mgr, list, handle);
-       if (ret < 0) {
-               uc_error("error: could not disable verb %s", verb->name);
-               return ret;
-       }
-
-       return 0;
-}
-
-static int enable_use_case_device(snd_use_case_mgr_t *uc_mgr,
-               int device_id, snd_ctl_elem_list_t *list, snd_ctl_t *handle)
-{
-       struct use_case_verb *verb = &uc_mgr->verb[uc_mgr->card.current_verb];
-       struct use_case_device *device = &verb->device[device_id];
-       int ret;
-
-       if (uc_mgr->card.current_verb == VERB_NOT_INITIALISED)
-               return -EINVAL;
-
-       uc_dbg("device %s", device->name);
-       ret = exec_sequence(device->enable, uc_mgr, list, handle);
-       if (ret < 0) {
-               uc_error("error: could not enable device %s", device->name);
-               return ret;
-       }
-
-       set_device_status(uc_mgr, device_id, 1);
-       return 0;
-}
-
-static int disable_use_case_device(snd_use_case_mgr_t *uc_mgr,
-               int device_id, snd_ctl_elem_list_t *list, snd_ctl_t *handle)
-{
-       struct use_case_verb *verb = &uc_mgr->verb[uc_mgr->card.current_verb];
-       struct use_case_device *device = &verb->device[device_id];
-       int ret;
-
-       if (uc_mgr->card.current_verb == VERB_NOT_INITIALISED)
-               return -EINVAL;
-
-       uc_dbg("device %s", device->name);
-       ret = exec_sequence(device->disable, uc_mgr, list, handle);
-       if (ret < 0) {
-               uc_error("error: could not disable device %s", device->name);
-               return ret;
-       }
-
-       set_device_status(uc_mgr, device_id, 0);
-       return 0;
-}
-
-static int enable_use_case_modifier(snd_use_case_mgr_t *uc_mgr,
-               int modifier_id, snd_ctl_elem_list_t *list, snd_ctl_t *handle)
-{
-       struct use_case_verb *verb = &uc_mgr->verb[uc_mgr->card.current_verb];
-       struct use_case_modifier *modifier = &verb->modifier[modifier_id];
-       int ret;
-
-       if (uc_mgr->card.current_verb == VERB_NOT_INITIALISED)
-               return -EINVAL;
-
-       uc_dbg("modifier %s", modifier->name);
-       ret = exec_sequence(modifier->enable, uc_mgr, list, handle);
-       if (ret < 0) {
-               uc_error("error: could not enable modifier %s", modifier->name);
-               return ret;
-       }
-
-       set_modifier_status(uc_mgr, modifier_id, 1);
-       return 0;
-}
-
-static int disable_use_case_modifier(snd_use_case_mgr_t *uc_mgr,
-               int modifier_id, snd_ctl_elem_list_t *list, snd_ctl_t *handle)
-{
-       struct use_case_verb *verb = &uc_mgr->verb[uc_mgr->card.current_verb];
-       struct use_case_modifier *modifier = &verb->modifier[modifier_id];
-       int ret;
-
-       if (uc_mgr->card.current_verb == VERB_NOT_INITIALISED)
-               return -EINVAL;
-
-       uc_dbg("modifier %s", modifier->name);
-       ret = exec_sequence(modifier->disable, uc_mgr, list, handle);
-       if (ret < 0) {
-               uc_error("error: could not disable modifier %s", modifier->name);
-               return ret;
-       }
-
-       set_modifier_status(uc_mgr, modifier_id, 0);
-       return 0;
-}
-
-/*
- * Tear down current use case verb, device and modifier.
- */
-static int dismantle_use_case(snd_use_case_mgr_t *uc_mgr,
-               snd_ctl_elem_list_t *list, snd_ctl_t *handle)
-{
-       struct use_case_verb *verb = &uc_mgr->verb[uc_mgr->card.current_verb];
-       int ret, i;
-
-       /* No active verb */
-       if (uc_mgr->card.current_verb == VERB_NOT_INITIALISED)
-               return 0;
-
-       /* disable all modifiers that are active */
-       for (i = 0; i < verb->num_modifiers; i++) {
-               if (get_modifier_status(uc_mgr,i)) {
-                       ret = disable_use_case_modifier(uc_mgr, i, list, handle);
-                       if (ret < 0)
-                               return ret;
-               }
-       }
-
-       /* disable all devices that are active */
-       for (i = 0; i < verb->num_devices; i++) {
-               if (get_device_status(uc_mgr,i)) {
-                       ret = disable_use_case_device(uc_mgr, i, list, handle);
-                       if (ret < 0)
-                               return ret;
-               }
-       }
-
-       /* disable verb */
-       ret = disable_use_case_verb(uc_mgr, uc_mgr->card.current_verb, list, handle);
-       if (ret < 0)
-               return ret;
-
-       return 0;
-}
-
- /**
- * \brief Dump sound card controls in format required for sequencer.
- * \param card_name The name of the sound card to be dumped
- * \return zero on success, otherwise a negative error code
- */
-int snd_use_case_dump(const char *card_name)
-{
-       snd_ctl_t *handle;
-       snd_ctl_card_info_t *info;
-       snd_ctl_elem_list_t *list;
-       int ret, i, count, idx;
-       char ctl_name[8];
-
-       snd_ctl_card_info_alloca(&info);
-       snd_ctl_elem_list_alloca(&list);
-
-       idx = snd_card_get_index(card_name);
-       if (idx < 0)
-               return idx;
-       sprintf(ctl_name, "hw:%d", idx);
-
-       /* open and load snd card */
-       ret = snd_ctl_open(&handle, ctl_name, SND_CTL_READONLY);
-       if (ret < 0) {
-               uc_error("error: could not open controls for  %s: %s",
-                       card_name, snd_strerror(ret));
-               return ret;
-       }
-
-       ret = snd_ctl_card_info(handle, info);
-       if (ret < 0) {
-               uc_error("error: could not get control info for %s:%s",
-                       card_name, snd_strerror(ret));
-               goto close;
-       }
-
-       ret = snd_ctl_elem_list(handle, list);
-       if (ret < 0) {
-               uc_error("error: cannot determine controls for  %s: %s",
-                       card_name, snd_strerror(ret));
-               goto close;
-       }
-
-       count = snd_ctl_elem_list_get_count(list);
-       if (count < 0) {
-               ret = 0;
-               goto close;
-       }
-
-       snd_ctl_elem_list_set_offset(list, 0);
-       if (snd_ctl_elem_list_alloc_space(list, count) < 0) {
-               uc_error("error: not enough memory for control elements");
-               ret =  -ENOMEM;
-               goto close;
-       }
-       if ((ret = snd_ctl_elem_list(handle, list)) < 0) {
-               uc_error("error: cannot determine controls: %s",
-                       snd_strerror(ret));
-               goto free;
-       }
-
-       /* iterate through each kcontrol and add to use
-        * case manager control list */
-       for (i = 0; i < count; ++i) {
-               snd_ctl_elem_id_t *id;
-               snd_ctl_elem_id_alloca(&id);
-               snd_ctl_elem_list_get_id(list, i, id);
-
-               /* dump to stdout in friendly format */
-               ret = dump_control(handle, id);
-               if (ret < 0) {
-                       uc_error("error: control dump failed: %s",
-                               snd_strerror(ret));
-                       goto free;
-               }
-       }
-free:
-       snd_ctl_elem_list_free_space(list);
-close:
-       snd_ctl_close(handle);
-       return ret;
-}
-
-/**
- * \brief List supported use case verbs for given soundcard
- * \param uc_mgr use case manager
- * \param verb returned list of supported use case verb id and names
- * \return number of use case verbs if success, otherwise a negative error code
- */
-int snd_use_case_get_verb_list(snd_use_case_mgr_t *uc_mgr,
-               const char **verb[])
-{
-       int ret;
-
-       pthread_mutex_lock(&uc_mgr->mutex);
-
-       *verb = uc_mgr->verb_list;
-       ret = uc_mgr->num_verbs;
-
-       pthread_mutex_unlock(&uc_mgr->mutex);
-       return ret;
-}
-
-/**
- * \brief List supported use case devices for given verb
- * \param uc_mgr use case manager
- * \param verb verb id.
- * \param device returned list of supported use case device id and names
- * \return number of use case devices if success, otherwise a negative error code
- */
-int snd_use_case_get_device_list(snd_use_case_mgr_t *uc_mgr,
-               const char *verb_name, const char **device[])
-{
-       struct use_case_verb *verb = NULL;
-       int i, ret = -EINVAL;
-
-       pthread_mutex_lock(&uc_mgr->mutex);
-
-       /* find verb name */
-       for (i = 0; i < uc_mgr->num_verbs; i++) {
-               verb = &uc_mgr->verb[i];
-               if (!strcmp(uc_mgr->verb[i].name, verb_name))
-                       goto found;
-       }
-
-       uc_error("error: use case verb %s not found", verb_name);
-       goto out;
-
-found:
-       *device = verb->device_list;
-       ret = verb->num_devices;
-out:
-       pthread_mutex_unlock(&uc_mgr->mutex);
-       return ret;
-}
-
-/**
- * \brief List supported use case verb modifiers for given verb
- * \param uc_mgr use case manager
- * \param verb verb id.
- * \param mod returned list of supported use case modifier id and names
- * \return number of use case modifiers if success, otherwise a negative error code
- */
-int snd_use_case_get_mod_list(snd_use_case_mgr_t *uc_mgr,
-               const char *verb_name, const char **mod[])
-{
-       struct use_case_verb *verb = NULL;
-       int i, ret = -EINVAL;
-
-       pthread_mutex_lock(&uc_mgr->mutex);
-
-       /* find verb name */
-       for (i = 0; i <uc_mgr->num_verbs; i++) {
-               verb = &uc_mgr->verb[i];
-               if (!strcmp(uc_mgr->verb[i].name, verb_name))
-                       goto found;
-       }
-
-       uc_error("error: use case verb %s not found", verb_name);
-       goto out;
-
-found:
-       *mod = verb->modifier_list;
-       ret = verb->num_modifiers;
-out:
-       pthread_mutex_unlock(&uc_mgr->mutex);
-       return ret;
-}
-
-static struct sequence_element *get_transition_sequence(
-               struct transition_sequence *trans_list, const char *name)
-{
-       struct transition_sequence *trans = trans_list;
-
-       while (trans) {
-               if (trans->name && !strcmp(trans->name, name))
-                       return trans->transition;
-
-               trans =  trans->next;
-       }
-
-       return NULL;
-}
-
-static int exec_transition_sequence(snd_use_case_mgr_t *uc_mgr,
-                       struct sequence_element *trans_sequence)
-{
-       int ret;
-
-       ret = exec_sequence(trans_sequence, uc_mgr, uc_mgr->list,
-                       uc_mgr->handle);
-       if (ret < 0)
-               uc_error("error: could not exec transition sequence");
-
-       return ret;
-}
-
-static int handle_transition_verb(snd_use_case_mgr_t *uc_mgr,
-               int new_verb_id)
-{
-       struct use_case_verb *old_verb = &uc_mgr->verb[uc_mgr->card.current_verb];
-       struct use_case_verb *new_verb;
-       static struct sequence_element *trans_sequence;
-
-       if (uc_mgr->card.current_verb == VERB_NOT_INITIALISED)
-               return -EINVAL;
-
-       if (new_verb_id >= uc_mgr->num_verbs) {
-               uc_error("error: invalid new_verb id %d", new_verb_id);
-               return -EINVAL;
-       }
-
-       new_verb = &uc_mgr->verb[new_verb_id];
-
-       uc_dbg("new verb %s", new_verb->name);
-
-       trans_sequence = get_transition_sequence(old_verb->transition_list,
-                                                       new_verb->name);
-       if (trans_sequence != NULL) {
-               int ret, i;
-
-               uc_dbg("find transition sequence %s->%s",
-                               old_verb->name, new_verb->name);
-
-               /* disable all modifiers that are active */
-               for (i = 0; i < old_verb->num_modifiers; i++) {
-                       if (get_modifier_status(uc_mgr,i)) {
-                               ret = disable_use_case_modifier(uc_mgr, i,
-                                       uc_mgr->list, uc_mgr->handle);
-                               if (ret < 0)
-                                       return ret;
-                       }
-               }
-
-               /* disable all devices that are active */
-               for (i = 0; i < old_verb->num_devices; i++) {
-                       if (get_device_status(uc_mgr,i)) {
-                               ret = disable_use_case_device(uc_mgr, i,
-                                       uc_mgr->list, uc_mgr->handle);
-                               if (ret < 0)
-                                       return ret;
-                       }
-               }
-
-               ret = exec_transition_sequence(uc_mgr, trans_sequence);
-               if (ret)
-                       return ret;
-
-               uc_mgr->card.current_verb = new_verb_id;
-
-               return 0;
-       }
-
-       return-EINVAL;
-}
-
-/**
- * \brief Set new use case verb for sound card
- * \param uc_mgr use case manager
- * \param verb verb id
- * \return zero if success, otherwise a negative error code
- */
-int snd_use_case_set_verb(snd_use_case_mgr_t *uc_mgr,
-               const char *verb_name)
-{
-       int i = 0, ret = -EINVAL, inactive = 0;
-
-       pthread_mutex_lock(&uc_mgr->mutex);
-
-       uc_dbg("uc_mgr %p, verb_name %s", uc_mgr, verb_name);
-
-       /* check for "Inactive" */
-       if (!strcmp(verb_name, SND_USE_CASE_VERB_INACTIVE)) {
-               inactive = 1;
-               goto found;
-       }
-
-       /* find verb name */
-       for (i = 0; i <uc_mgr->num_verbs; i++) {
-               if (!strcmp(uc_mgr->verb[i].name, verb_name))
-                       goto found;
-       }
-
-       uc_error("error: use case verb %s not found", verb_name);
-       goto out;
-found:
-       /* use case verb found - check that we actually changing the verb */
-       if (i == uc_mgr->card.current_verb) {
-               uc_dbg("current verb ID %d", i);
-               ret = 0;
-               goto out;
-       }
-
-       if (handle_transition_verb(uc_mgr, i) == 0)
-               goto out;
-
-       /*
-        * Dismantle the old use cases by running it's verb, device and modifier
-        * disable sequences
-        */
-       ret = dismantle_use_case(uc_mgr, uc_mgr->list, uc_mgr->handle);
-       if (ret < 0) {
-               uc_error("error: failed to dismantle current use case: %s",
-                       uc_mgr->verb[i].name);
-               goto out;
-       }
-
-       /* we don't need to initialise new verb if inactive */
-       if (inactive)
-               goto out;
-
-       /* Initialise the new use case verb */
-       ret = enable_use_case_verb(uc_mgr, i, uc_mgr->list, uc_mgr->handle);
-       if (ret < 0)
-               uc_error("error: failed to initialise new use case: %s",
-                               verb_name);
-out:
-       pthread_mutex_unlock(&uc_mgr->mutex);
-
-       return ret;
-}
-
-static int config_use_case_device(snd_use_case_mgr_t *uc_mgr,
-               const char *device_name, int enable)
-{
-       struct use_case_verb *verb;
-       int ret, i;
-
-       pthread_mutex_lock(&uc_mgr->mutex);
-
-       if (uc_mgr->card.current_verb == VERB_NOT_INITIALISED) {
-               uc_error("error: no valid use case verb set\n");
-               ret = -EINVAL;
-               goto out;
-       }
-
-       verb = &uc_mgr->verb[uc_mgr->card.current_verb];
-
-       uc_dbg("current verb %s", verb->name);
-       uc_dbg("uc_mgr %p device_name %s", uc_mgr, device_name);
-
-       /* find device name and index */
-       for (i = 0; i <verb->num_devices; i++) {
-               uc_dbg("verb->num_devices %s", verb->device[i].name);
-               if (!strcmp(verb->device[i].name, device_name))
-                       goto found;
-       }
-
-       uc_error("error: use case device %s not found", device_name);
-       ret = -EINVAL;
-       goto out;
-
-found:
-       if (enable) {
-               /* Initialise the new use case device */
-               ret = enable_use_case_device(uc_mgr, i, uc_mgr->list,
-                       uc_mgr->handle);
-               if (ret < 0)
-                       goto out;
-       } else {
-               /* disable the old device */
-               ret = disable_use_case_device(uc_mgr, i, uc_mgr->list,
-                       uc_mgr->handle);
-               if (ret < 0)
-                       goto out;
-       }
-
-out:
-       pthread_mutex_unlock(&uc_mgr->mutex);
-       return ret;
-}
-
-/**
- * \brief Enable use case device
- * \param uc_mgr Use case manager
- * \param device the device to be enabled
- * \return 0 = successful negative = error
- */
-int snd_use_case_enable_device(snd_use_case_mgr_t *uc_mgr,
-               const char *device)
-{
-       return config_use_case_device(uc_mgr, device, 1);
-}
-
-/**
- * \brief Disable use case device
- * \param uc_mgr Use case manager
- * \param device the device to be disabled
- * \return 0 = successful negative = error
- */
-int snd_use_case_disable_device(snd_use_case_mgr_t *uc_mgr,
-               const char *device)
-{
-       return config_use_case_device(uc_mgr, device, 0);
-}
-
-static struct use_case_device *get_device(snd_use_case_mgr_t *uc_mgr,
-                                                       const char *name, int *id)
-{
-       struct use_case_verb *verb;
-       int i;
-
-       if (uc_mgr->card.current_verb == VERB_NOT_INITIALISED)
-               return NULL;
-
-       verb = &uc_mgr->verb[uc_mgr->card.current_verb];
-
-       uc_dbg("current verb %s", verb->name);
-
-       for (i = 0; i < verb->num_devices; i++) {
-               uc_dbg("device %s", verb->device[i].name);
-
-               if (!strcmp(verb->device[i].name, name)) {
-                       if (id)
-                               *id = i;
-                       return &verb->device[i];
-               }
-       }
-
-       return NULL;
-}
-
-/**
- * \brief Disable old_device and then enable new_device.
- *        If from_device is not enabled just return.
- *        Check transition sequence firstly.
- * \param uc_mgr Use case manager
- * \param old the device to be closed
- * \param new the device to be opened
- * \return 0 = successful negative = error
- */
-int snd_use_case_switch_device(snd_use_case_mgr_t *uc_mgr,
-                       const char *old, const char *new)
-{
-       static struct sequence_element *trans_sequence;
-       struct use_case_device *old_device;
-       struct use_case_device *new_device;
-       int ret = 0, old_id, new_id;
-
-       uc_dbg("old %s, new %s", old, new);
-
-       pthread_mutex_lock(&uc_mgr->mutex);
-
-       old_device = get_device(uc_mgr, old, &old_id);
-       if (!old_device) {
-               uc_error("error: device %s not found", old);
-               ret = -EINVAL;
-               goto out;
-       }
-
-       if (!get_device_status(uc_mgr, old_id)) {
-               uc_error("error: device %s not enabled", old);
-               goto out;
-       }
-
-       new_device = get_device(uc_mgr, new, &new_id);
-       if (!new_device) {
-               uc_error("error: device %s not found", new);
-               ret = -EINVAL;
-               goto out;
-       }
-
-       trans_sequence = get_transition_sequence(old_device->transition_list, new);
-       if (trans_sequence != NULL) {
-
-               uc_dbg("find transition sequece %s->%s", old, new);
-
-               ret = exec_transition_sequence(uc_mgr, trans_sequence);
-               if (ret)
-                       goto out;
-
-               set_device_status(uc_mgr, old_id, 0);
-               set_device_status(uc_mgr, new_id, 1);
-       } else {
-               /* use lock in config_use_case_device */
-               pthread_mutex_unlock(&uc_mgr->mutex);
-
-               config_use_case_device(uc_mgr, old, 0);
-               config_use_case_device(uc_mgr, new, 1);
-
-               return 0;
-       }
-out:
-       pthread_mutex_unlock(&uc_mgr->mutex);
-       return ret;
-}
-
-/*
- * Check to make sure that the modifier actually supports any of the
- * active devices.
- */
-static int is_modifier_valid(snd_use_case_mgr_t *uc_mgr,
-       struct use_case_verb *verb, struct use_case_modifier *modifier)
-{
-       struct dev_list *dev_list;
-       int dev;
-
-       /* check modifier list against each enabled device */
-       for (dev = 0; dev < verb->num_devices; dev++) {
-               if (!get_device_status(uc_mgr, dev))
-                       continue;
-
-               dev_list = modifier->dev_list;
-               uc_dbg("checking device %s for %s", verb->device[dev].name,
-                       dev_list->name ? dev_list->name : "");
-
-               while (dev_list) {
-                       uc_dbg("device supports %s", dev_list->name);
-                       if (!strcmp(dev_list->name, verb->device[dev].name))
-                                       return 1;
-                       dev_list = dev_list->next;
-               }
-       }
-       return 0;
-}
-
-static int config_use_case_mod(snd_use_case_mgr_t *uc_mgr,
-               const char *modifier_name, int enable)
-{
-       struct use_case_verb *verb;
-       int ret, i;
-
-       pthread_mutex_lock(&uc_mgr->mutex);
-
-       if (uc_mgr->card.current_verb == VERB_NOT_INITIALISED) {
-               ret = -EINVAL;
-               goto out;
-       }
-
-       verb = &uc_mgr->verb[uc_mgr->card.current_verb];
-
-       uc_dbg("current verb %s", verb->name);
-       uc_dbg("uc_mgr %p modifier_name %s", uc_mgr, modifier_name);
-
-       /* find modifier name */
-       for (i = 0; i <verb->num_modifiers; i++) {
-               uc_dbg("verb->num_modifiers %d %s", i, verb->modifier[i].name);
-               if (!strcmp(verb->modifier[i].name, modifier_name) &&
-                       is_modifier_valid(uc_mgr, verb, &verb->modifier[i]))
-                       goto found;
-       }
-
-       uc_error("error: use case modifier %s not found or invalid",
-               modifier_name);
-       ret = -EINVAL;
-       goto out;
-
-found:
-       if (enable) {
-               /* Initialise the new use case device */
-               ret = enable_use_case_modifier(uc_mgr, i, uc_mgr->list,
-                       uc_mgr->handle);
-               if (ret < 0)
-                       goto out;
-       } else {
-               /* disable the old device */
-               ret = disable_use_case_modifier(uc_mgr, i, uc_mgr->list,
-                       uc_mgr->handle);
-               if (ret < 0)
-                       goto out;
-       }
-
-out:
-       pthread_mutex_unlock(&uc_mgr->mutex);
-       return ret;
-}
-
-/**
- * \brief Enable use case modifier
- * \param uc_mgr Use case manager
- * \param modifier the modifier to be enabled
- * \return 0 = successful negative = error
- */
-int snd_use_case_enable_modifier(snd_use_case_mgr_t *uc_mgr,
-               const char *modifier)
-{
-       return config_use_case_mod(uc_mgr, modifier, 1);
-}
-
-/**
- * \brief Disable use case modifier
- * \param uc_mgr Use case manager
- * \param modifier the modifier to be disabled
- * \return 0 = successful negative = error
- */
-int snd_use_case_disable_modifier(snd_use_case_mgr_t *uc_mgr,
-               const char *modifier)
-{
-       return config_use_case_mod(uc_mgr, modifier, 0);
-}
-
-static struct use_case_modifier *get_modifier(snd_use_case_mgr_t *uc_mgr,
-                                                       const char *name, int *mod_id)
-{
-       struct use_case_verb *verb;
-       int i;
-
-       if (uc_mgr->card.current_verb == VERB_NOT_INITIALISED)
-               return NULL;
-
-       verb = &uc_mgr->verb[uc_mgr->card.current_verb];
-
-       uc_dbg("current verb %s", verb->name);
-
-       uc_dbg("uc_mgr %p modifier_name %s", uc_mgr, name);
-
-       for (i = 0; i < verb->num_modifiers; i++) {
-               uc_dbg("verb->num_devices %s", verb->modifier[i].name);
-
-               if (!strcmp(verb->modifier[i].name, name)) {
-                       if (mod_id)
-                               *mod_id = i;
-                       return &verb->modifier[i];
-               }
-       }
-
-       return NULL;
-}
-
-/**
- * \brief Disable old_modifier and then enable new_modifier.
- *        If old_modifier is not enabled just return.
- *        Check transition sequence firstly.
- * \param uc_mgr Use case manager
- * \param old the modifier to be closed
- * \param new the modifier to be opened
- * \return 0 = successful negative = error
- */
-int snd_use_case_switch_modifier(snd_use_case_mgr_t *uc_mgr,
-                       const char *old, const char *new)
-{
-       struct use_case_modifier *old_modifier;
-       struct use_case_modifier *new_modifier;
-       static struct sequence_element *trans_sequence;
-       int ret = 0, old_id, new_id
-
-       uc_dbg("old %s, new %s", old, new);
-
-       pthread_mutex_lock(&uc_mgr->mutex);
-
-       old_modifier = get_modifier(uc_mgr, old, &old_id);
-       if (!old_modifier) {
-               uc_error("error: modifier %s not found", old);
-               ret = -EINVAL;
-               goto out;
-       }
-
-       if (!get_modifier_status(uc_mgr, old_id)) {
-               uc_error("error: modifier %s not enabled", old);
-               ret = -EINVAL;
-               goto out;
-       }
-
-       new_modifier = get_modifier(uc_mgr, new, &new_id);
-       if (!new_modifier) {
-               uc_error("error: modifier %s not found", new);
-               ret = -EINVAL;
-               goto out;
-       }
-
-       trans_sequence = get_transition_sequence(
-                               old_modifier->transition_list, new);
-       if (trans_sequence != NULL) {
-               uc_dbg("find transition sequence %s->%s", old, new);
-
-               ret = exec_transition_sequence(uc_mgr, trans_sequence);
-               if (ret)
-                       goto out;
-
-               set_device_status(uc_mgr, old_id, 0);
-               set_device_status(uc_mgr, new_id, 1);
-       } else {
-               /* use lock in config_use_case_mod*/
-               pthread_mutex_unlock(&uc_mgr->mutex);
-
-               config_use_case_mod(uc_mgr, old, 0);
-               config_use_case_mod(uc_mgr, new, 1);
-
-               return 0;
-       }
-out:
-       pthread_mutex_unlock(&uc_mgr->mutex);
-       return ret;
-}
-
-/**
- * \brief Get current use case verb from sound card
- * \param uc_mgr use case manager
- * \return Verb Name if success, otherwise NULL
- */
-const char *snd_use_case_get_verb(snd_use_case_mgr_t *uc_mgr)
-{
-       const char *ret = NULL;
-
-       pthread_mutex_lock(&uc_mgr->mutex);
-
-       if (uc_mgr->card.current_verb != VERB_NOT_INITIALISED)
-               ret = uc_mgr->verb_list[uc_mgr->card.current_verb];
-
-       pthread_mutex_unlock(&uc_mgr->mutex);
-
-       return ret;
-}
-
-/**
- * \brief Get device status for current use case verb
- * \param uc_mgr Use case manager
- * \param device_name The device we are interested in.
- * \return - 1 = enabled, 0 = disabled, negative = error
- */
-int snd_use_case_get_device_status(snd_use_case_mgr_t *uc_mgr,
-               const char *device_name)
-{
-       struct use_case_device *device;
-       int ret = -EINVAL, dev_id;
-
-       pthread_mutex_lock(&uc_mgr->mutex);
-
-       device = get_device(uc_mgr, device_name, &dev_id);
-       if (device == NULL) {
-               uc_error("error: use case device %s not found", device_name);
-               goto out;
-       }
-
-       ret = get_device_status(uc_mgr, dev_id);
-out:
-       pthread_mutex_unlock(&uc_mgr->mutex);
-
-       return ret;
-}
-
-/**
- * \brief Get modifier status for current use case verb
- * \param uc_mgr Use case manager
- * \param device_name The device we are interested in.
- * \return - 1 = enabled, 0 = disabled, negative = error
- */
-int snd_use_case_get_modifier_status(snd_use_case_mgr_t *uc_mgr,
-               const char *modifier_name)
-{
-       struct use_case_modifier *modifier;
-       int ret = -EINVAL, mod_id;
-
-       pthread_mutex_lock(&uc_mgr->mutex);
-
-       modifier = get_modifier(uc_mgr, modifier_name, &mod_id);
-       if (modifier == NULL) {
-               uc_error("error: use case modifier %s not found", modifier_name);
-               goto out;
-       }
-
-       ret = get_modifier_status(uc_mgr, mod_id);
-out:
-       pthread_mutex_unlock(&uc_mgr->mutex);
-
-       return ret;
-}
-
-/**
- * \brief Get current use case verb QoS
- * \param uc_mgr use case manager
- * \return QoS level
- */
-enum snd_use_case_qos
-       snd_use_case_get_verb_qos(snd_use_case_mgr_t *uc_mgr)
-{
-       struct use_case_verb *verb;
-       enum snd_use_case_qos ret = SND_USE_CASE_QOS_UNKNOWN;
-
-       pthread_mutex_lock(&uc_mgr->mutex);
-
-       if (uc_mgr->card.current_verb != VERB_NOT_INITIALISED) {
-               verb = &uc_mgr->verb[uc_mgr->card.current_verb];
-               ret = verb->qos;
-       }
-
-       pthread_mutex_unlock(&uc_mgr->mutex);
-
-       return ret;
-}
-
-/**
- * \brief Get current use case modifier QoS
- * \param uc_mgr use case manager
- * \return QoS level
- */
-enum snd_use_case_qos
-       snd_use_case_get_mod_qos(snd_use_case_mgr_t *uc_mgr,
-                                       const char *modifier_name)
-{
-       struct use_case_modifier *modifier;
-       enum snd_use_case_qos ret = SND_USE_CASE_QOS_UNKNOWN;
-
-       pthread_mutex_lock(&uc_mgr->mutex);
-
-       modifier = get_modifier(uc_mgr, modifier_name, NULL);
-       if (modifier != NULL)
-               ret = modifier->qos;
-       else
-               uc_error("error: use case modifier %s not found", modifier_name);
-       pthread_mutex_unlock(&uc_mgr->mutex);
-
-       return ret;
-}
-
-/**
- * \brief Get current use case verb playback PCM
- * \param uc_mgr use case manager
- * \return PCM number if success, otherwise negative
- */
-int snd_use_case_get_verb_playback_pcm(snd_use_case_mgr_t *uc_mgr)
-{
-       struct use_case_verb *verb;
-       int ret = -EINVAL;
-
-       pthread_mutex_lock(&uc_mgr->mutex);
-
-       if (uc_mgr->card.current_verb != VERB_NOT_INITIALISED) {
-               verb = &uc_mgr->verb[uc_mgr->card.current_verb];
-               ret = verb->playback_pcm;
-       }
-
-       pthread_mutex_unlock(&uc_mgr->mutex);
-
-       return ret;
-}
-
-/**
- * \brief Get current use case verb playback PCM
- * \param uc_mgr use case manager
- * \return PCM number if success, otherwise negative
- */
-int snd_use_case_get_verb_capture_pcm(snd_use_case_mgr_t *uc_mgr)
-{
-       struct use_case_verb *verb;
-       int ret = -EINVAL;
-
-       pthread_mutex_lock(&uc_mgr->mutex);
-
-       if (uc_mgr->card.current_verb != VERB_NOT_INITIALISED) {
-               verb = &uc_mgr->verb[uc_mgr->card.current_verb];
-               ret = verb->capture_pcm;
-       }
-
-       pthread_mutex_unlock(&uc_mgr->mutex);
-
-       return ret;
-}
-
-/**
- * \brief Get current use case modifier playback PCM
- * \param uc_mgr use case manager
- * \return PCM number if success, otherwise negative
- */
-int snd_use_case_get_mod_playback_pcm(snd_use_case_mgr_t *uc_mgr,
-                                       const char *modifier_name)
-{
-       struct use_case_modifier *modifier;
-       int ret = -EINVAL;
-
-       pthread_mutex_lock(&uc_mgr->mutex);
-
-       modifier = get_modifier(uc_mgr, modifier_name, NULL);
-       if (modifier == NULL)
-               uc_error("error: use case modifier %s not found",
-                                               modifier_name);
-       else
-               ret = modifier->playback_pcm;
-
-       pthread_mutex_unlock(&uc_mgr->mutex);
-
-       return ret;
-}
-
-/**
- * \brief Get current use case modifier playback PCM
- * \param uc_mgr use case manager
- * \return PCM number if success, otherwise negative
- */
-int snd_use_case_get_mod_capture_pcm(snd_use_case_mgr_t *uc_mgr,
-       const char *modifier_name)
-{
-       struct use_case_modifier *modifier;
-       int ret = -EINVAL;
-
-       pthread_mutex_lock(&uc_mgr->mutex);
-
-       modifier = get_modifier(uc_mgr, modifier_name, NULL);
-       if (modifier == NULL)
-               uc_error("error: use case modifier %s not found",
-                                               modifier_name);
-       else
-               ret = modifier->capture_pcm;
-
-       pthread_mutex_unlock(&uc_mgr->mutex);
-
-       return ret;
-}
-
-/**
- * \brief Get volume/mute control name depending on use case device.
- * \param uc_mgr use case manager
- * \param type the control type we are looking for
- * \param device_name The use case device we are interested in.
- * \return control name if success, otherwise NULL
- *
- * Get the control id for common volume and mute controls that are aliased
- * in the named use case device.
- */
-const char *snd_use_case_get_device_ctl_elem_name(snd_use_case_mgr_t *uc_mgr,
-               enum snd_use_case_control_alias type, const char *device_name)
-{
-       struct use_case_device *device;
-       const char *kcontrol_name = NULL;
-
-       pthread_mutex_lock(&uc_mgr->mutex);
-
-       device = get_device(uc_mgr, device_name, NULL);
-       if (!device) {
-               uc_error("error: device %s not found", device_name);
-               goto out;
-       }
-
-       switch (type) {
-       case SND_USE_CASE_ALIAS_PLAYBACK_VOLUME:
-               kcontrol_name = device->playback_volume_id;
-               break;
-       case SND_USE_CASE_ALIAS_CAPTURE_VOLUME:
-               kcontrol_name = device->capture_volume_id;
-               break;
-       case SND_USE_CASE_ALIAS_PLAYBACK_SWITCH:
-               kcontrol_name = device->playback_switch_id;
-               break;
-       case SND_USE_CASE_ALIAS_CAPTURE_SWITCH:
-               kcontrol_name = device->capture_switch_id;
-               break;
-       default:
-               uc_error("error: invalid control alias %d", type);
-               break;
-       }
-
-out:
-       pthread_mutex_unlock(&uc_mgr->mutex);
-
-       return kcontrol_name;
-}
-
-/**
- * \brief Get volume/mute control IDs depending on use case modifier.
- * \param uc_mgr use case manager
- * \param type the control type we are looking for
- * \param modifier_name The use case modifier we are interested in.
- * \return ID if success, otherwise a negative error code
- *
- * Get the control id for common volume and mute controls that are aliased
- * in the named use case device.
- */
-const char *snd_use_case_get_modifier_ctl_elem_name(snd_use_case_mgr_t *uc_mgr,
-               enum snd_use_case_control_alias type, const char *modifier_name)
-{
-       struct use_case_modifier *modifier;
-       const char *kcontrol_name = NULL;
-
-       pthread_mutex_lock(&uc_mgr->mutex);
-
-       modifier = get_modifier(uc_mgr, modifier_name, NULL);
-       if (!modifier) {
-               uc_error("error: modifier %s not found", modifier_name);
-               goto out;
-       }
-
-       switch (type) {
-       case SND_USE_CASE_ALIAS_PLAYBACK_VOLUME:
-               kcontrol_name = modifier->playback_volume_id;
-               break;
-       case SND_USE_CASE_ALIAS_CAPTURE_VOLUME:
-               kcontrol_name = modifier->capture_volume_id;
-               break;
-       case SND_USE_CASE_ALIAS_PLAYBACK_SWITCH:
-               kcontrol_name = modifier->playback_switch_id;
-               break;
-       case SND_USE_CASE_ALIAS_CAPTURE_SWITCH:
-               kcontrol_name = modifier->capture_switch_id;
-               break;
-       default:
-               uc_error("error: invalid control alias %d", type);
-               break;
-       }
-
-out:
-       pthread_mutex_unlock(&uc_mgr->mutex);
-
-       return kcontrol_name;
-}