OSDN Git Service

ucm: Introduce "Value {}" section, more implementation work
authorJaroslav Kysela <perex@perex.cz>
Wed, 22 Sep 2010 12:31:15 +0000 (14:31 +0200)
committerJaroslav Kysela <perex@perex.cz>
Wed, 22 Sep 2010 12:31:15 +0000 (14:31 +0200)
- new "Value {}" section is introduced for read-only values
  describing the PCM and control/mixer IDs (or any other
  things)
- more complete implementation for API functions

Signed-off-by: Jaroslav Kysela <perex@perex.cz>
include/use-case.h
src/ucm/main.c
src/ucm/parser.c
src/ucm/ucm_local.h
src/ucm/utils.c

index 6b9b645..fdbcaca 100644 (file)
@@ -179,9 +179,10 @@ char *snd_use_case_identifier(const char *fmt, ...);
 /**
  * \brief Free a string list
  * \param list The string list to free
+ * \param items Count of strings
  * \return Zero if success, otherwise a negative error code
  */
-int snd_use_case_free_list(const char *list[]);
+int snd_use_case_free_list(const char *list[], int items);
 
 /**
  * \brief Obtain a list of entries
@@ -192,14 +193,14 @@ int snd_use_case_free_list(const char *list[]);
  *
  * Defined identifiers:
  *   NULL              - get card list
- *                       (in pair verb+comment)
+ *                       (in pair cardname+comment)
  *   _verbs            - get verb list
  *                       (in pair verb+comment)
  *   _devices[/<verb>] - get list of supported devices
  *                       (in pair device+comment)
  *   _modifiers[/<verb>]- get list of supported modifiers
  *                       (in pair modifier+comment)
- *   _tqs[/<verb>]     - get list of QoS identifiers
+ *   TQ[/<verb>]       - get list of TQ identifiers
  *   _enadevs          - get list of enabled devices
  *   _enamods          - get list of enabled modifiers
  *
@@ -222,20 +223,19 @@ 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
- *   _ctl_/_pctlvol[/<modifier>]       - playback control volume ID string
- *   _ctl_/_pctlsw[/<modifier>]                - playback control switch ID string
- *   _ctl_/_cctl[/<modifier>]          - capture control device name
- *   _ctl_/_cctlvol[/<modifier>]       - capture control volume ID string
- *   _ctl_/_cctlsw[/<modifier>]                - capture control switch ID string
- *   _mixer_/_pname[/<modifier>]       - name of playback mixer
- *   _mixer_/_pid[/<modifier>]         - mixer playback ID
- *   _mixer_/_cname[/<modifier>]       - name of capture mixer
- *   _mixer_/_cid[/<modifier>]         - mixer capture ID
+ *   TQ[/<modifier>]                   - Tone Quality [for given modifier]
+ *   PlaybackPCM[/<modifier>]          - full PCM playback device name
+ *   CapturePCM[/<modifier>]           - full PCM capture device name
+ *   PlaybackCTL[/<modifier>]          - playback control device name
+ *   PlaybackVolume[/<modifier>]       - playback control volume ID string
+ *   PlaybackSwitch[/<modifier>]       - playback control switch ID string
+ *   CaptureCTL[/<modifier>]           - capture control device name
+ *   CaptureVolume[/<modifier>]                - capture control volume ID string
+ *   CaptureSwitch[/<modifier>]                - capture control switch ID string
+ *   PlaybackMixer[/<modifier>]                - name of playback mixer
+ *   PlaybackMixerID[/<modifier>]      - mixer playback ID
+ *   CaptureMixer[/<modifier>]         - name of capture mixer
+ *   CaptureMixerID[/<modifier>]       - mixer capture ID
  */
 int snd_use_case_get(snd_use_case_mgr_t *uc_mgr,
                      const char *identifier,
@@ -251,8 +251,8 @@ int snd_use_case_get(snd_use_case_mgr_t *uc_mgr,
  *   _devstatus/<device>       - return status for given device
  *   _modstatus/<modifier>     - return status for given modifier
  */
-int snd_use_case_geti(snd_use_case_mgr_t *uc_mgr,
-                      const char *identifier);
+long snd_use_case_geti(snd_use_case_mgr_t *uc_mgr,
+                       const char *identifier);
 
 /**
  * \brief Set new
@@ -311,13 +311,6 @@ int snd_use_case_mgr_close(snd_use_case_mgr_t *uc_mgr);
 int snd_use_case_mgr_reset(snd_use_case_mgr_t *uc_mgr);
 
 /**
- * \brief Dump current sound card use case control settings
- * \param card_name Sound card name
- * \return zero if success, otherwise a negative error code
- */
-int snd_use_case_dump(const char *card_name);
-
-/**
  *  \}
  */
 
index a8df44c..e036c4d 100644 (file)
  */
 
 #include "ucm_local.h"
+#include <stdarg.h>
 #include <pthread.h>
 
+/*
+ * misc
+ */
+
+static int check_identifier(const char *identifier, const char *prefix)
+{
+       int len;
+
+       if (strcmp(identifier, prefix) == 0)
+               return 1;
+       len = strlen(prefix);
+       if (memcmp(identifier, prefix, len) == 0 && identifier[len] == '/')
+               return 1;
+       return 0;
+}
+
+static int list_count(struct list_head *list)
+{
+        struct list_head *pos;
+        int count = 0;
+        
+        list_for_each(pos, list) {
+                count += 1;
+        }
+        return count;
+}
+
+static int alloc_str_list(struct list_head *list, int mult, char **result[])
+{
+        char **res;
+        int cnt;
+        
+        cnt = list_count(list) * mult;
+        if (cnt == 0)
+                return cnt;
+        res = calloc(mult, cnt * sizeof(char *));
+        if (res == NULL)
+                return -ENOMEM;
+        *result = res;
+        return cnt;
+}
+
+/**
+ * \brief Create an identifier
+ * \param fmt Format (sprintf like)
+ * \param ... Optional arguments for sprintf like format
+ * \return Allocated string identifier or NULL on error
+ */
+char *snd_use_case_identifier(const char *fmt, ...)
+{
+       char *str, *res;
+       int size = strlen(fmt) + 512;
+       va_list args;
+
+       str = malloc(size);
+       if (str == NULL)
+               return NULL;
+       va_start(args, fmt);
+       vsnprintf(str, size, fmt, args);
+       va_end(args);
+       str[size-1] = '\0';
+       res = realloc(str, strlen(str) + 1);
+       if (res)
+               return res;
+       return str;
+}
+
+/**
+ * \brief Free a string list
+ * \param list The string list to free
+ * \param items Count of strings
+ * \return Zero if success, otherwise a negative error code
+ */
+int snd_use_case_free_list(const char *list[], int items)
+{
+        int i;
+       if (list == NULL)
+               return 0;
+        for (i = 0; i < items; i++)
+               free((void *)list[i]);
+        free(list);
+       return 0;
+}
+
 /**
  * \brief Execute the sequence
  * \param uc_mgr Use case manager
@@ -85,15 +170,13 @@ static int import_master_config(snd_use_case_mgr_t *uc_mgr)
 
 /**
  * \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,
+static void *find0(struct list_head *list,
                   unsigned long offset,
                   unsigned long soffset,
                   const char *match)
@@ -110,10 +193,111 @@ static void *find0(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED,
        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)
+#define find(list, type, member, value, match) \
+       find0(list, (unsigned long)(&((type *)0)->member), \
+                   (unsigned long)(&((type *)0)->value), match)
+
+/**
+ * \brief Universal string list
+ * \param list List of structures
+ * \param result Result list
+ * \param offset Offset of list structure
+ * \param s1offset Offset of string structure
+ * \return count of items on success, otherwise a negative error code
+ */
+static int get_list0(struct list_head *list,
+                     const char **result[],
+                     unsigned long offset,
+                     unsigned long s1offset)
+{
+        char **res;
+        int cnt;
+       struct list_head *pos;
+       char *ptr, *str1;
+
+       cnt = alloc_str_list(list, 1, &res);
+       if (cnt <= 0)
+               return cnt;
+       *result = (const char **)res;
+       list_for_each(pos, list) {
+               ptr = list_entry_offset(pos, char, offset);
+               str1 = *((char **)(ptr + s1offset));
+               if (str1 != NULL) {
+                       *res = strdup(str1);
+                       if (*res == NULL)
+                               goto __fail;
+                } else {
+                        *res = NULL;
+                }
+                res++;
+       }
+       return cnt;
+      __fail:
+        snd_use_case_free_list((const char **)res, cnt);
+        return -ENOMEM;
+}
+
+#define get_list(list, result, type, member, s1) \
+       get_list0(list, result, \
+                   (unsigned long)(&((type *)0)->member), \
+                   (unsigned long)(&((type *)0)->s1))
+
+/**
+ * \brief Universal string list - pair of strings
+ * \param list List of structures
+ * \param result Result list
+ * \param offset Offset of list structure
+ * \param s1offset Offset of string structure
+ * \param s1offset Offset of string structure
+ * \return count of items on success, otherwise a negative error code
+ */
+static int get_list20(struct list_head *list,
+                      const char **result[],
+                      unsigned long offset,
+                      unsigned long s1offset,
+                      unsigned long s2offset)
+{
+        char **res;
+        int cnt;
+       struct list_head *pos;
+       char *ptr, *str1, *str2;
+
+       cnt = alloc_str_list(list, 2, &res);
+       if (cnt <= 0)
+               return cnt;
+        *result = (const char **)res;
+       list_for_each(pos, list) {
+               ptr = list_entry_offset(pos, char, offset);
+               str1 = *((char **)(ptr + s1offset));
+               if (str1 != NULL) {
+                       *res = strdup(str1);
+                       if (*res == NULL)
+                               goto __fail;
+                } else {
+                        *res = NULL;
+                }
+                res++;
+               str2 = *((char **)(ptr + s2offset));
+               if (str2 != NULL) {
+                       *res = strdup(str2);
+                       if (*res == NULL)
+                               goto __fail;
+                } else {
+                        *res = NULL;
+                }
+                res++;
+       }
+       return cnt;
+      __fail:
+        snd_use_case_free_list((const char **)res, cnt);
+        return -ENOMEM;
+}
+
+#define get_list2(list, result, type, member, s1, s2) \
+       get_list20(list, result, \
+                   (unsigned long)(&((type *)0)->member), \
+                   (unsigned long)(&((type *)0)->s1), \
+                   (unsigned long)(&((type *)0)->s2))
 
 /**
  * \brief Find verb
@@ -122,17 +306,33 @@ static void *find0(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED,
  * \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)
+                                             const char *verb_name)
 {
-       return find(uc_mgr, &uc_mgr->verb_list,
+       return find(&uc_mgr->verb_list,
                    struct use_case_verb, list, name,
-                   _name);
+                   verb_name);
+}
+
+/**
+ * \brief Find modifier
+ * \param verb Use case verb
+ * \param modifier_name modifier to find
+ * \return structure on success, otherwise a NULL (not found)
+ */
+static inline struct use_case_modifier *
+        find_modifier(struct use_case_verb *verb,
+                      const char *modifier_name)
+{
+       return find(&verb->modifier_list,
+                   struct use_case_modifier, list, name,
+                   modifier_name);
 }
 
 /**
  * \brief Set verb
  * \param uc_mgr Use case manager
  * \param verb verb to set
+ * \param enable nonzero = enable, zero = disable
  * \return zero on success, otherwise a negative error code
  */
 static int set_verb(snd_use_case_mgr_t *uc_mgr,
@@ -154,6 +354,62 @@ static int set_verb(snd_use_case_mgr_t *uc_mgr,
 }
 
 /**
+ * \brief Set modifier
+ * \param uc_mgr Use case manager
+ * \param modifier modifier to set
+ * \param enable nonzero = enable, zero = disable
+ * \return zero on success, otherwise a negative error code
+ */
+static int set_modifier(snd_use_case_mgr_t *uc_mgr,
+                       struct use_case_modifier *modifier,
+                       int enable)
+{
+       struct list_head *seq;
+       int err;
+
+       if (enable) {
+               seq = &modifier->enable_list;
+       } else {
+               seq = &modifier->disable_list;
+       }
+       err = execute_sequence(uc_mgr, seq);
+       if (enable && err >= 0) {
+               list_add_tail(&modifier->active_list, &uc_mgr->active_modifiers);
+       } else if (!enable) {
+               list_del(&modifier->active_list);
+       }
+       return err;
+}
+
+/**
+ * \brief Set device
+ * \param uc_mgr Use case manager
+ * \param device device to set
+ * \param enable nonzero = enable, zero = disable
+ * \return zero on success, otherwise a negative error code
+ */
+static int set_device(snd_use_case_mgr_t *uc_mgr,
+                     struct use_case_device *device,
+                     int enable)
+{
+       struct list_head *seq;
+       int err;
+
+       if (enable) {
+               seq = &device->enable_list;
+       } else {
+               seq = &device->disable_list;
+       }
+       err = execute_sequence(uc_mgr, seq);
+       if (enable && err >= 0) {
+               list_add_tail(&device->active_list, &uc_mgr->active_devices);
+       } else if (!enable) {
+               list_del(&device->active_list);
+       }
+       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
@@ -249,7 +505,7 @@ int snd_use_case_mgr_reset(snd_use_case_mgr_t *uc_mgr)
        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);
+               err = set_modifier(uc_mgr, modifier, 0);
                if (err < 0)
                        uc_error("Unable to disable modifier %s", modifier->name);
        }
@@ -258,13 +514,13 @@ int snd_use_case_mgr_reset(snd_use_case_mgr_t *uc_mgr)
        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);
+               err = set_device(uc_mgr, device, 0);
                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);
+       err = set_verb(uc_mgr, uc_mgr->active_verb, 0);
        if (err < 0) {
                uc_error("Unable to disable verb %s", uc_mgr->active_verb->name);
                return err;
@@ -277,1172 +533,469 @@ int snd_use_case_mgr_reset(snd_use_case_mgr_t *uc_mgr)
        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
+ * \brief Get list of cards in pair cardname+comment
+ * \param list Returned list
+ * \return Number of list entries 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)
+static int get_card_list(const char **list[])
 {
-       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;
+       return -ENXIO;  /* Not Yet Implemented */
 }
 
 /**
- * \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
+ * \brief Get list of verbs in pair verbname+comment
+ * \param list Returned list
+ * \param verbname For verb (NULL = current)
+ * \return Number of list entries if success, otherwise a negative error code
  */
-int snd_use_case_set_verb(snd_use_case_mgr_t *uc_mgr,
-               const char *verb_name)
+static int get_verb_list(snd_use_case_mgr_t *uc_mgr, const char **list[])
 {
-       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;
+        return get_list2(&uc_mgr->verb_list, list,
+                         struct use_case_verb, list,
+                         name, comment);
 }
 
 /**
- * \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 Get list of devices in pair devicename+comment
+ * \param list Returned list
+ * \param verbname For verb (NULL = current)
+ * \return Number of list entries if success, otherwise a negative error code
+ */
+static int get_device_list(snd_use_case_mgr_t *uc_mgr, const char **list[],
+                           char *verbname)
+{
+        struct use_case_verb *verb;
+        
+        if (verbname) {
+                verb = find_verb(uc_mgr, verbname);
+        } else {
+                verb = uc_mgr->active_verb;
+        }
+        if (verb == NULL)
+                return -ENOENT;
+        return get_list2(&verb->device_list, list,
+                         struct use_case_device, list,
+                         name, comment);
+        return 0;
 }
 
 /**
- * \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 Get list of modifiers in pair devicename+comment
+ * \param list Returned list
+ * \param verbname For verb (NULL = current)
+ * \return Number of list entries if success, otherwise a negative error code
+ */
+static int get_modifier_list(snd_use_case_mgr_t *uc_mgr, const char **list[],
+                             char *verbname)
+{
+        struct use_case_verb *verb;
+        
+        if (verbname) {
+                verb = find_verb(uc_mgr, verbname);
+        } else {
+                verb = uc_mgr->active_verb;
+        }
+        if (verb == NULL)
+                return -ENOENT;
+        return get_list2(&verb->modifier_list, list,
+                         struct use_case_modifier, list,
+                         name, comment);
+        return 0;
+}
+
+struct myvalue {
+        struct list_head list;
+        char *value;
+};
+
+static int add_values(struct list_head *list,
+                      const char *identifier,
+                      struct list_head *source)
+{
+        struct ucm_value *v;
+        struct myvalue *val;
+        struct list_head *pos, *pos1;
+        int match;
+        
+        list_for_each(pos, source) {
+                v = list_entry(pos, struct ucm_value, list);
+                if (check_identifier(identifier, v->name)) {
+                        match = 0;
+                        list_for_each(pos1, list) {
+                                val = list_entry(pos1, struct myvalue, list);
+                                if (strcmp(val->value, v->data) == 0) {
+                                        match = 1;
+                                        break;
+                                }
+                        }
+                        if (!match) {
+                                val = malloc(sizeof(struct myvalue));
+                                if (val == NULL)
+                                        return -ENOMEM;
+                                list_add_tail(&val->list, list);
+                        }
+                }
+        }
+        return 0;
 }
 
 /**
- * \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 Get list of values
+ * \param list Returned list
+ * \param verbname For verb (NULL = current)
+ * \return Number of list entries if success, otherwise a negative error code
+ */
+static int get_value_list(snd_use_case_mgr_t *uc_mgr,
+                          const char *identifier,
+                          const char **list[],
+                          char *verbname)
+{
+        struct list_head mylist, *pos, *npos;
+        struct myvalue *val;
+        struct use_case_verb *verb;
+        struct use_case_device *dev;
+        struct use_case_modifier *mod;
+        char **res;
+        int err;
+        
+        if (verbname) {
+                verb = find_verb(uc_mgr, verbname);
+        } else {
+                verb = uc_mgr->active_verb;
+        }
+        if (verb == NULL)
+                return -ENOENT;
+        INIT_LIST_HEAD(&mylist);
+        err = add_values(&mylist, identifier, &verb->value_list);
+        if (err < 0)
+                goto __fail;
+        list_for_each(pos, &verb->device_list) {
+                dev = list_entry(pos, struct use_case_device, list);
+                err = add_values(&mylist, identifier, &dev->value_list);
+                if (err < 0)
+                        goto __fail;
+        }
+        list_for_each(pos, &verb->modifier_list) {
+                mod = list_entry(pos, struct use_case_modifier, list);
+                err = add_values(&mylist, identifier, &mod->value_list);
+                if (err < 0)
+                        goto __fail;
+        }
+        err = alloc_str_list(&mylist, 1, &res);
+        *list = (const char **)res;
+        if (err >= 0) {
+                list_for_each(pos, &mylist) {
+                        val = list_entry(pos, struct myvalue, list);
+                        *res = strdup(val->value);
+                        if (*res == NULL) {
+                                snd_use_case_free_list((const char **)res, err);
+                                err = -ENOMEM;
+                                goto __fail;
+                        }
+                        res++;
+                }
+        }
+      __fail:
+        list_for_each_safe(pos, npos, &mylist) {
+                val = list_entry(pos, struct myvalue, list);
+                list_del(&val->list);
+                free(val);
+        }
+        return err;
 }
 
 /**
- * \brief Enable use case modifier
- * \param uc_mgr Use case manager
- * \param modifier the modifier to be enabled
- * \return 0 = successful negative = error
+ * \brief Get list of enabled devices
+ * \param list Returned list
+ * \param verbname For verb (NULL = current)
+ * \return Number of list entries if success, otherwise a negative error code
  */
-int snd_use_case_enable_modifier(snd_use_case_mgr_t *uc_mgr,
-               const char *modifier)
+static int get_enabled_device_list(snd_use_case_mgr_t *uc_mgr,
+                                   const char **list[])
 {
-       return config_use_case_mod(uc_mgr, modifier, 1);
+        if (uc_mgr->active_verb == NULL)
+                return -EINVAL;
+        return get_list(&uc_mgr->active_devices, list,
+                        struct use_case_device, active_list,
+                        name);
 }
 
 /**
- * \brief Disable use case modifier
- * \param uc_mgr Use case manager
- * \param modifier the modifier to be disabled
- * \return 0 = successful negative = error
+ * \brief Get list of enabled modifiers
+ * \param list Returned list
+ * \param verbname For verb (NULL = current)
+ * \return Number of list entries if success, otherwise a negative error code
  */
-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)
+static int get_enabled_modifier_list(snd_use_case_mgr_t *uc_mgr,
+                                     const char **list[])
 {
-       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;
+        if (uc_mgr->active_verb == NULL)
+                return -EINVAL;
+        return get_list(&uc_mgr->active_modifiers, list,
+                        struct use_case_modifier, active_list,
+                        name);
 }
 
 /**
- * \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
+ * \brief Obtain a list of entries
+ * \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
  */
-int snd_use_case_switch_modifier(snd_use_case_mgr_t *uc_mgr,
-                       const char *old, const char *new)
+int snd_use_case_get_list(snd_use_case_mgr_t *uc_mgr,
+                         const char *identifier,
+                         const char **list[])
 {
-       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);
+       char *str, *str1;
+       int err;
 
+       if (uc_mgr == NULL || identifier == NULL)
+               return get_card_list(list);
        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:
+       if (strcmp(identifier, "_verbs") == 0)
+               err = get_verb_list(uc_mgr, list);
+        else if (strcmp(identifier, "_enadevs"))
+               err = get_enabled_device_list(uc_mgr, list);
+        else if (strcmp(identifier, "_enamods"))
+                err = get_enabled_modifier_list(uc_mgr, list);
+        else {
+                str1 = strchr(identifier, '/');
+                if (str1) {
+                        str = strdup(str1 + 1);
+                       if (str == NULL) {
+                               err = -ENOMEM;
+                               goto __end;
+                        }
+                } else {
+                        str = NULL;
+                }
+               if (check_identifier(identifier, "_devices"))
+                       err = get_device_list(uc_mgr, list, str);
+                else if (check_identifier(identifier, "_modifiers"))
+                        err = get_modifier_list(uc_mgr, list, str);
+                else
+                        err = get_value_list(uc_mgr, identifier, list, str);
+               if (str)
+                       free(str);
+        }
+      __end:
        pthread_mutex_unlock(&uc_mgr->mutex);
-       return ret;
+       return err;
 }
 
-/**
- * \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)
+static int get_value1(const char **value, struct list_head *value_list,
+                      const char *identifier)
 {
-       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;
+        struct ucm_value *val;
+        struct list_head *pos;
+        
+        list_for_each(pos, value_list) {
+              val = list_entry(pos, struct ucm_value, list);
+              if (check_identifier(identifier, val->name)) {
+                      *value = strdup(val->data);
+                      if (*value == NULL)
+                              return -ENOMEM;
+                      return 0;
+              }
+        }
+        return 0;
 }
 
 /**
- * \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
+ * \brief Get value
+ * \param list Returned list
+ * \param verbname For verb (NULL = current)
+ * \return Number of list entries if success, otherwise a negative error code
  */
-int snd_use_case_get_device_status(snd_use_case_mgr_t *uc_mgr,
-               const char *device_name)
+static int get_value(snd_use_case_mgr_t *uc_mgr,
+                     const char *identifier,
+                     const char **value,
+                     const char *modifier)
 {
-       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);
+        struct use_case_modifier *mod;
 
-       return ret;
+        if (uc_mgr->active_verb == NULL)
+                return -ENOENT;
+        if (modifier == NULL)
+                return get_value1(value, &uc_mgr->active_verb->value_list,
+                                  identifier);
+        mod = find_modifier(uc_mgr->active_verb, modifier);
+        if (mod == NULL)
+                return -EINVAL;
+        return get_value1(value, &mod->value_list, identifier);
 }
 
 /**
- * \brief Get modifier status for current use case verb
+ * \brief Get current - string
  * \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)
+ * \param identifier 
+ * \param value Value pointer
+ * \return Zero if success, otherwise a negative error code
+ *
+ * Note: String is dynamically allocated, use free() to
+ * deallocate this string.
+ */      
+int snd_use_case_get(snd_use_case_mgr_t *uc_mgr,
+                    const char *identifier,
+                    const char **value)
 {
-       struct use_case_verb *verb;
-       int ret = -EINVAL;
+        char *str, *str1;
+        int err;
 
        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;
-       }
-
+       if (identifier == NULL) {
+               *value = strdup(uc_mgr->card_name);
+               if (*value == NULL) {
+                       err = -ENOMEM;
+                       goto __end;
+                }
+                err = 0;
+        } else if (strcmp(identifier, "_verb") == 0) {
+                if (uc_mgr->active_verb == NULL)
+                        return -ENOENT;
+                *value = strdup(uc_mgr->active_verb->name);
+                if (*value == NULL) {
+                        err = -ENOMEM;
+                        goto __end;
+                }
+               err = 0;
+        } else {
+                str1 = strchr(identifier, '/');
+                if (str1) {
+                        str = strdup(str1 + 1);
+                       if (str == NULL) {
+                               err = -ENOMEM;
+                               goto __end;
+                        }
+                } else {
+                        str = NULL;
+                }
+                err = get_value(uc_mgr, identifier, value, str);
+                if (str)
+                        free(str);
+        }
+      __end:
        pthread_mutex_unlock(&uc_mgr->mutex);
-
-       return ret;
+        return err;
 }
 
-/**
- * \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)
+long device_status(snd_use_case_mgr_t *uc_mgr,
+                   const char *device_name)
 {
-       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;
+        struct use_case_device *dev;
+        struct list_head *pos;
+        
+        list_for_each(pos, &uc_mgr->active_devices) {
+                dev = list_entry(pos, struct use_case_device, active_list);
+                if (strcmp(dev->name, device_name) == 0)
+                        return 1;
+        }
+        return 0;
 }
 
-/**
- * \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)
+long modifier_status(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;
+        struct use_case_modifier *mod;
+        struct list_head *pos;
+        
+        list_for_each(pos, &uc_mgr->active_modifiers) {
+                mod = list_entry(pos, struct use_case_modifier, active_list);
+                if (strcmp(mod->name, modifier_name) == 0)
+                        return 1;
+        }
+        return 0;
 }
 
-/**
- * \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.
+ * \brief Get current - integer
+ * \param uc_mgr Use case manager
+ * \param identifier 
+ * \return Value if success, otherwise a negative error code 
  */
-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)
+long snd_use_case_geti(snd_use_case_mgr_t *uc_mgr,
+                       const char *identifier)
 {
-       struct use_case_device *device;
-       const char *kcontrol_name = NULL;
+        char *str, *str1;
+        long err;
 
        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:
+        if (0) {
+                /* nothing here - prepared for fixed identifiers */
+        } else {
+                str1 = strchr(identifier, '/');
+                if (str1) {
+                        str = strdup(str1 + 1);
+                       if (str == NULL) {
+                               err = -ENOMEM;
+                               goto __end;
+                        }
+                } else {
+                        str = NULL;
+                }
+                if (check_identifier(identifier, "_devstatus"))
+                        err = device_status(uc_mgr, str);
+                else if (check_identifier(identifier, "_modstatus"))
+                        err = modifier_status(uc_mgr, str);
+                else
+                        err = -EINVAL;
+                if (str)
+                        free(str);
+        }
+      __end:
        pthread_mutex_unlock(&uc_mgr->mutex);
-
-       return kcontrol_name;
+        return err;
 }
 
 /**
- * \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.
+ * \brief Set new
+ * \param uc_mgr Use case manager
+ * \param identifier
+ * \param value Value
+ * \return Zero if success, otherwise a negative error code
  */
-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)
+int snd_use_case_set(snd_use_case_mgr_t *uc_mgr,
+                     const char *identifier,
+                     const char *value)
 {
-       struct use_case_modifier *modifier;
-       const char *kcontrol_name = NULL;
+        char *str, *str1;
+        int err;
 
        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:
+       if (strcmp(identifier, "_verb") == 0)
+               err = set_verb_user(uc_mgr, value);
+        else if (strcmp(identifier, "_enadev") == 0)
+                err = set_device_user(uc_mgr, value, 1);
+        else if (strcmp(identifier, "_disdev") == 0)
+                err = set_device_user(uc_mgr, value, 0);
+        else if (strcmp(identifier, "_enamod") == 0)
+                err = set_modifier_user(uc_mgr, value, 1);
+        else if (strcmp(identifier, "_dismod") == 0)
+                err = set_modifier_user(uc_mgr, value, 0);
+        else {
+                str1 = strchr(identifier, '/');
+                if (str1) {
+                        str = strdup(str1 + 1);
+                       if (str == NULL) {
+                               err = -ENOMEM;
+                               goto __end;
+                        }
+                } else {
+                        str = NULL;
+                }
+                if (check_identifier(identifier, "_swdev"))
+                        err = switch_device(uc_mgr, str, value);
+                else if (check_identifier(identifier, "_swmod"))
+                        err = switch_modifier(uc_mgr, str, value);
+                else
+                        err = -EINVAL;
+                if (str)
+                        free(str);
+        }
+      __end:
        pthread_mutex_unlock(&uc_mgr->mutex);
-
-       return kcontrol_name;
+        return err;
 }
-#endif
index bb04751..e540c20 100644 (file)
@@ -220,6 +220,88 @@ static int parse_sequence(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED,
 }
 
 /*
+ * Parse values.
+ *
+ * Parse values describing PCM, control/mixer settings and stream parameters.
+ *
+ * Value {
+ *   TQ Voice
+ *   CapturePCM "hw:1"
+ *   PlaybackVolume "name='Master Playback Volume',index=2"
+ *   PlaybackSwitch "name='Master Playback Switch',index=2"
+ * }
+ */
+static int parse_value(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED,
+                         struct list_head *base,
+                         snd_config_t *cfg)
+{
+       struct ucm_value *curr;
+       snd_config_iterator_t i, next, j, next2;
+       snd_config_t *n, *n2;
+       long l;
+       long long ll;
+       double d;
+       snd_config_type_t type;
+       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 value */
+                       curr = calloc(1, sizeof(struct ucm_value));
+                       if (curr == NULL)
+                               return -ENOMEM;
+                       list_add_tail(&curr->list, base);
+                       curr->name = strdup(id);
+                       if (curr->name == NULL)
+                               return -ENOMEM;
+                       type = snd_config_get_type(n2);
+                       switch (type) {
+                       case SND_CONFIG_TYPE_INTEGER:
+                               curr->data = malloc(16);
+                               if (curr->data == NULL)
+                                       return -ENOMEM;
+                               snd_config_get_integer(n2, &l);
+                               sprintf(curr->data, "%li", l);
+                               break;
+                       case SND_CONFIG_TYPE_INTEGER64:
+                               curr->data = malloc(32);
+                               if (curr->data == NULL)
+                                       return -ENOMEM;
+                               snd_config_get_integer64(n2, &ll);
+                               sprintf(curr->data, "%lli", ll);
+                               break;
+                       case SND_CONFIG_TYPE_REAL:
+                               curr->data = malloc(64);
+                               if (curr->data == NULL)
+                                       return -ENOMEM;
+                               snd_config_get_real(n2, &d);
+                               sprintf(curr->data, "%-16g", d);
+                               break;
+                       case SND_CONFIG_TYPE_STRING:
+                               err = parse_string(n2, &curr->data);
+                               if (err < 0) {
+                                       uc_error("error: unable to parse a string for id '%s'!", id);
+                                       return err;
+                               }
+                               break;
+                       default:
+                               uc_error("error: invalid type %i in Value compound", type);
+                               return -EINVAL;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+/*
  * Parse Modifier Use cases
  *
  *     # Each modifier is described in new section. N modifier are allowed
@@ -240,10 +322,12 @@ static int parse_sequence(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED,
  *             ]
  *
  *             # Optional TQ and ALSA PCMs
- *             TQ Voice
- *             CapturePCM "hw:1"
- *             MasterPlaybackVolume "name='Master Playback Volume',index=2"
- *             MasterPlaybackSwitch "name='Master Playback Switch',index=2"
+ *             Value {
+ *                     TQ Voice
+ *                     CapturePCM "hw:1"
+ *                     PlaybackVolume "name='Master Playback Volume',index=2"
+ *                     PlaybackSwitch "name='Master Playback Switch',index=2"
+ *             }
  *
  *      }
  */
@@ -267,6 +351,7 @@ static int parse_modifier(snd_use_case_mgr_t *uc_mgr,
        INIT_LIST_HEAD(&modifier->disable_list);
        INIT_LIST_HEAD(&modifier->transition_list);
        INIT_LIST_HEAD(&modifier->dev_list);
+       INIT_LIST_HEAD(&modifier->value_list);
        list_add_tail(&modifier->list, &verb->modifier_list);
        err = snd_config_get_id(cfg, &id);
        if (err < 0)
@@ -335,64 +420,10 @@ static int parse_modifier(snd_use_case_mgr_t *uc_mgr,
                        continue;
                }
 
-               if (strcmp(id, "TQ") == 0) {
-                       err = parse_string(n, &modifier->tq);
+               if (strcmp(id, "Value") == 0) {
+                       err = parse_value(uc_mgr, &modifier->value_list, n);
                        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");
+                               uc_error("error: failed to parse Value");
                                return err;
                        }
                        continue;
@@ -422,9 +453,10 @@ static int parse_modifier(snd_use_case_mgr_t *uc_mgr,
  *             ...
  *     ]
  *
- *     MasterPlaybackVolume "name='Master Playback Volume',index=2"
- *     MasterPlaybackSwitch "name='Master Playback Switch',index=2"
- *
+ *     Value {
+ *             PlaybackVolume "name='Master Playback Volume',index=2"
+ *             PlaybackSwitch "name='Master Playback Switch',index=2"
+ *     }
  * }
  */
 static int parse_device_index(snd_use_case_mgr_t *uc_mgr,
@@ -446,17 +478,16 @@ static int parse_device_index(snd_use_case_mgr_t *uc_mgr,
        INIT_LIST_HEAD(&device->enable_list);
        INIT_LIST_HEAD(&device->disable_list);
        INIT_LIST_HEAD(&device->transition_list);
+       INIT_LIST_HEAD(&device->value_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;
-       }
+       device->name = malloc(strlen(name) + strlen(id) + 2);
+       if (device->name == NULL)
+               return -ENOMEM;
+       strcpy(device->name, name);
+       strcat(device->name, ".");
+       strcat(device->name, id);
 
        snd_config_for_each(i, next, cfg) {
                const char *id;
@@ -506,37 +537,10 @@ static int parse_device_index(snd_use_case_mgr_t *uc_mgr,
                        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 (strcmp(id, "Value") == 0) {
+                       err = parse_value(uc_mgr, &device->value_list, n);
                        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");
+                               uc_error("error: failed to parse Value");
                                return err;
                        }
                        continue;
@@ -577,7 +581,7 @@ static int parse_device(snd_use_case_mgr_t *uc_mgr,
  *     # 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"
+ *             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"
@@ -592,10 +596,11 @@ static int parse_device(snd_use_case_mgr_t *uc_mgr,
  *     ]
  *
  *     # Optional TQ and ALSA PCMs
- *     TQ HiFi
- *     CapturePCM 0
- *     PlaybackPCM 0
- *
+ *     Value {
+ *             TQ HiFi
+ *             CapturePCM 0
+ *             PlaybackPCM 0
+ *     }
  * }
  */
 static int parse_verb(snd_use_case_mgr_t *uc_mgr,
@@ -643,25 +648,9 @@ static int parse_verb(snd_use_case_mgr_t *uc_mgr,
                        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 (strcmp(id, "Value") == 0) {
+                       uc_dbg("Parse Value");
+                       err = parse_value(uc_mgr, &verb->value_list, n);
                        if (err < 0)
                                return err;
                        continue;
@@ -703,6 +692,7 @@ static int parse_verb_file(snd_use_case_mgr_t *uc_mgr,
        INIT_LIST_HEAD(&verb->transition_list);
        INIT_LIST_HEAD(&verb->device_list);
        INIT_LIST_HEAD(&verb->modifier_list);
+       INIT_LIST_HEAD(&verb->value_list);
        list_add_tail(&verb->list, &uc_mgr->verb_list);
        verb->name = strdup(use_case_name);
        if (verb->name == NULL)
index ffef8f0..a3c1dcb 100644 (file)
 #define SEQUENCE_ELEMENT_TYPE_SLEEP    2
 #define SEQUENCE_ELEMENT_TYPE_EXEC     3
 
+struct ucm_value {
+        struct list_head list;
+        char *name;
+        char *data;
+};
+
 struct sequence_element {
        struct list_head list;
        unsigned int type;
@@ -99,20 +105,8 @@ struct use_case_modifier {
        /* 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;
+       /* values */
+       struct list_head value_list;
 };
 
 /*
@@ -127,7 +121,6 @@ struct use_case_device {
 
        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;
@@ -136,13 +129,8 @@ struct use_case_device {
        /* 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;
+       /* value list */
+       struct list_head value_list;
 };
 
 /*
@@ -164,16 +152,14 @@ struct use_case_verb {
        /* 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;
+
+       /* value list */
+       struct list_head value_list;
 };
 
 /*
index 98e3cf6..83926da 100644 (file)
@@ -80,6 +80,19 @@ int uc_mgr_config_load(const char *file, snd_config_t **cfg)
        return 0;
 }
 
+void uc_mgr_free_value(struct list_head *base)
+{
+       struct list_head *pos, *npos;
+       struct ucm_value *val;
+       
+       list_for_each_safe(pos, npos, base) {
+               val = list_entry(pos, struct ucm_value, list);
+               free(val->name);
+               free(val->data);
+               list_del(pos);
+       }
+}
+
 void uc_mgr_free_dev_list(struct list_head *base)
 {
        struct list_head *pos, *npos;
@@ -147,15 +160,7 @@ void uc_mgr_free_modifier(struct list_head *base)
                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);
+               uc_mgr_free_value(&mod->value_list);
                free(mod);
                list_del(pos);
        }
@@ -173,12 +178,7 @@ void uc_mgr_free_device(struct list_head *base)
                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);
+               uc_mgr_free_value(&dev->value_list);
                free(dev);
                list_del(pos);
        }
@@ -196,9 +196,7 @@ void uc_mgr_free_verb(snd_use_case_mgr_t *uc_mgr)
                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_value(&verb->value_list);
                uc_mgr_free_device(&verb->device_list);
                uc_mgr_free_modifier(&verb->modifier_list);
                free(verb);