354 lines
10 KiB
Diff
354 lines
10 KiB
Diff
|
From ebdd2b6cdb8119cf75f0dd0a3b283d271b3a547e Mon Sep 17 00:00:00 2001
|
||
|
From: Jaroslav Kysela <perex@perex.cz>
|
||
|
Date: Sat, 30 Nov 2019 20:31:55 +0100
|
||
|
Subject: [PATCH 03/30] ucm: add _identifiers list
|
||
|
|
||
|
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
|
||
|
---
|
||
|
include/use-case.h | 1 +
|
||
|
src/ucm/main.c | 268 +++++++++++++++++++++++++++++++++++++++++------------
|
||
|
2 files changed, 208 insertions(+), 61 deletions(-)
|
||
|
|
||
|
diff --git a/include/use-case.h b/include/use-case.h
|
||
|
index 8e7e838c9cb9..85c58ac0614a 100644
|
||
|
--- a/include/use-case.h
|
||
|
+++ b/include/use-case.h
|
||
|
@@ -206,6 +206,7 @@ int snd_use_case_free_list(const char *list[], int items);
|
||
|
* - _enadevs - get list of enabled devices
|
||
|
* - _enamods - get list of enabled modifiers
|
||
|
*
|
||
|
+ * - _identifiers/{modifier}|{device}[/{verb}] - list of value identifiers
|
||
|
* - _supporteddevs/{modifier}|{device}[/{verb}] - list of supported devices
|
||
|
* - _conflictingdevs/{modifier}|{device}[/{verb}] - list of conflicting devices
|
||
|
*
|
||
|
diff --git a/src/ucm/main.c b/src/ucm/main.c
|
||
|
index b80db65fa93b..d2078a2381d3 100644
|
||
|
--- a/src/ucm/main.c
|
||
|
+++ b/src/ucm/main.c
|
||
|
@@ -1072,7 +1072,6 @@ int snd_use_case_mgr_reset(snd_use_case_mgr_t *uc_mgr)
|
||
|
/**
|
||
|
* \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
|
||
|
*/
|
||
|
static int get_verb_list(snd_use_case_mgr_t *uc_mgr, const char **list[])
|
||
|
@@ -1181,7 +1180,6 @@ static int get_supcon_device_list(snd_use_case_mgr_t *uc_mgr,
|
||
|
}
|
||
|
|
||
|
return -ENOENT;
|
||
|
-
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@@ -1210,41 +1208,201 @@ static int get_conflicting_device_list(snd_use_case_mgr_t *uc_mgr,
|
||
|
|
||
|
#ifndef DOC_HIDDEN
|
||
|
struct myvalue {
|
||
|
- struct list_head list;
|
||
|
- char *value;
|
||
|
+ struct list_head list;
|
||
|
+ const char *text;
|
||
|
};
|
||
|
#endif
|
||
|
|
||
|
+/**
|
||
|
+ * \brief Convert myvalue list string list
|
||
|
+ * \param list myvalue list
|
||
|
+ * \param res string list
|
||
|
+ * \retval Number of list entries if success, otherwise a negativer error code
|
||
|
+ */
|
||
|
+static int myvalue_to_str_list(struct list_head *list, char ***res)
|
||
|
+{
|
||
|
+ struct list_head *pos;
|
||
|
+ struct myvalue *value;
|
||
|
+ char **p;
|
||
|
+ int cnt;
|
||
|
+
|
||
|
+ cnt = alloc_str_list(list, 1, res);
|
||
|
+ if (cnt < 0)
|
||
|
+ return cnt;
|
||
|
+ p = *res;
|
||
|
+ list_for_each(pos, list) {
|
||
|
+ value = list_entry(pos, struct myvalue, list);
|
||
|
+ *p = strdup(value->text);
|
||
|
+ if (*p == NULL) {
|
||
|
+ snd_use_case_free_list((const char **)p, cnt);
|
||
|
+ return -ENOMEM;
|
||
|
+ }
|
||
|
+ p++;
|
||
|
+ }
|
||
|
+ return cnt;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * \brief Free myvalue list
|
||
|
+ * \param list myvalue list
|
||
|
+ */
|
||
|
+static void myvalue_list_free(struct list_head *list)
|
||
|
+{
|
||
|
+ struct list_head *pos, *npos;
|
||
|
+ struct myvalue *value;
|
||
|
+
|
||
|
+ list_for_each_safe(pos, npos, list) {
|
||
|
+ value = list_entry(pos, struct myvalue, list);
|
||
|
+ list_del(&value->list);
|
||
|
+ free(value);
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * \brief Merge one value to the myvalue list
|
||
|
+ * \param list The list with values
|
||
|
+ * \param value The value to be merged (without duplicates)
|
||
|
+ * \return 1 if dup, 0 if success, otherwise a negative error code
|
||
|
+ */
|
||
|
+static int merge_value(struct list_head *list, const char *text)
|
||
|
+{
|
||
|
+ struct list_head *pos;
|
||
|
+ struct myvalue *value;
|
||
|
+
|
||
|
+ list_for_each(pos, list) {
|
||
|
+ value = list_entry(pos, struct myvalue, list);
|
||
|
+ if (strcmp(value->text, text) == 0)
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+ value = malloc(sizeof(*value));
|
||
|
+ if (value == NULL)
|
||
|
+ return -ENOMEM;
|
||
|
+ value->text = text;
|
||
|
+ list_add_tail(&value->list, list);
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * \brief Find all values for given identifier
|
||
|
+ * \param list Returned list
|
||
|
+ * \param source Source list with ucm_value structures
|
||
|
+ * \return Zero if success, otherwise a negative error code
|
||
|
+ */
|
||
|
+static int add_identifiers(struct list_head *list,
|
||
|
+ struct list_head *source)
|
||
|
+{
|
||
|
+ struct ucm_value *v;
|
||
|
+ struct list_head *pos;
|
||
|
+ int err;
|
||
|
+
|
||
|
+ list_for_each(pos, source) {
|
||
|
+ v = list_entry(pos, struct ucm_value, list);
|
||
|
+ err = merge_value(list, v->name);
|
||
|
+ if (err < 0)
|
||
|
+ return err;
|
||
|
+ }
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * \brief Find all values for given identifier
|
||
|
+ * \param list Returned list
|
||
|
+ * \param identifier Identifier
|
||
|
+ * \param source Source list with ucm_value structures
|
||
|
+ */
|
||
|
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;
|
||
|
+ struct ucm_value *v;
|
||
|
+ struct list_head *pos;
|
||
|
+ int err;
|
||
|
|
||
|
- 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;
|
||
|
- val->value = v->data;
|
||
|
- list_add_tail(&val->list, list);
|
||
|
- }
|
||
|
- }
|
||
|
- }
|
||
|
- return 0;
|
||
|
+ list_for_each(pos, source) {
|
||
|
+ v = list_entry(pos, struct ucm_value, list);
|
||
|
+ if (check_identifier(identifier, v->name)) {
|
||
|
+ err = merge_value(list, v->data);
|
||
|
+ if (err < 0)
|
||
|
+ return err;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * \brief compare two identifiers
|
||
|
+ */
|
||
|
+static int identifier_cmp(const void *_a, const void *_b)
|
||
|
+{
|
||
|
+ const char * const *a = _a;
|
||
|
+ const char * const *b = _b;
|
||
|
+ return strcmp(*a, *b);
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * \brief Get list of available identifiers
|
||
|
+ * \param list Returned list
|
||
|
+ * \param name Name of verb or modifier to query
|
||
|
+ * \return Number of list entries if success, otherwise a negative error code
|
||
|
+ */
|
||
|
+static int get_identifiers_list(snd_use_case_mgr_t *uc_mgr,
|
||
|
+ const char **list[], char *name)
|
||
|
+{
|
||
|
+ struct use_case_verb *verb;
|
||
|
+ struct use_case_modifier *modifier;
|
||
|
+ struct use_case_device *device;
|
||
|
+ struct list_head mylist;
|
||
|
+ struct list_head *value_list;
|
||
|
+ char *str, **res;
|
||
|
+ int err;
|
||
|
+
|
||
|
+ if (!name)
|
||
|
+ return -ENOENT;
|
||
|
+
|
||
|
+ str = strchr(name, '/');
|
||
|
+ if (str) {
|
||
|
+ *str = '\0';
|
||
|
+ verb = find_verb(uc_mgr, str + 1);
|
||
|
+ }
|
||
|
+ else {
|
||
|
+ verb = uc_mgr->active_verb;
|
||
|
+ }
|
||
|
+ if (!verb)
|
||
|
+ return -ENOENT;
|
||
|
+
|
||
|
+ value_list = NULL;
|
||
|
+ modifier = find_modifier(uc_mgr, verb, name, 0);
|
||
|
+ if (modifier) {
|
||
|
+ value_list = &modifier->value_list;
|
||
|
+ } else {
|
||
|
+ device = find_device(uc_mgr, verb, name, 0);
|
||
|
+ if (device)
|
||
|
+ value_list = &device->value_list;
|
||
|
+ }
|
||
|
+ if (value_list == NULL)
|
||
|
+ return -ENOENT;
|
||
|
+
|
||
|
+ INIT_LIST_HEAD(&mylist);
|
||
|
+ err = add_identifiers(&mylist, &uc_mgr->value_list);
|
||
|
+ if (err < 0)
|
||
|
+ goto __fail;
|
||
|
+ err = add_identifiers(&mylist, &verb->value_list);
|
||
|
+ if (err < 0)
|
||
|
+ goto __fail;
|
||
|
+ err = add_identifiers(&mylist, value_list);
|
||
|
+ if (err < 0)
|
||
|
+ goto __fail;
|
||
|
+ err = myvalue_to_str_list(&mylist, &res);
|
||
|
+ if (err > 0)
|
||
|
+ *list = (const char **)res;
|
||
|
+ else if (err == 0)
|
||
|
+ *list = NULL;
|
||
|
+__fail:
|
||
|
+ myvalue_list_free(&mylist);
|
||
|
+ if (err <= 0)
|
||
|
+ return err;
|
||
|
+ qsort(*list, err, sizeof(char *), identifier_cmp);
|
||
|
+ return err;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@@ -1258,8 +1416,7 @@ static int get_value_list(snd_use_case_mgr_t *uc_mgr,
|
||
|
const char **list[],
|
||
|
char *verbname)
|
||
|
{
|
||
|
- struct list_head mylist, *pos, *npos;
|
||
|
- struct myvalue *val;
|
||
|
+ struct list_head mylist, *pos;
|
||
|
struct use_case_verb *verb;
|
||
|
struct use_case_device *dev;
|
||
|
struct use_case_modifier *mod;
|
||
|
@@ -1292,26 +1449,13 @@ static int get_value_list(snd_use_case_mgr_t *uc_mgr,
|
||
|
if (err < 0)
|
||
|
goto __fail;
|
||
|
}
|
||
|
- err = alloc_str_list(&mylist, 1, &res);
|
||
|
- if (err >= 0) {
|
||
|
+ err = myvalue_to_str_list(&mylist, &res);
|
||
|
+ if (err > 0)
|
||
|
*list = (const char **)res;
|
||
|
- 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++;
|
||
|
- }
|
||
|
- }
|
||
|
+ else if (err == 0)
|
||
|
+ *list = NULL;
|
||
|
__fail:
|
||
|
- list_for_each_safe(pos, npos, &mylist) {
|
||
|
- val = list_entry(pos, struct myvalue, list);
|
||
|
- list_del(&val->list);
|
||
|
- free(val);
|
||
|
- }
|
||
|
+ myvalue_list_free(&mylist);
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
@@ -1381,21 +1525,23 @@ int snd_use_case_get_list(snd_use_case_mgr_t *uc_mgr,
|
||
|
} else {
|
||
|
str = NULL;
|
||
|
}
|
||
|
- if (check_identifier(identifier, "_devices"))
|
||
|
- err = get_device_list(uc_mgr, list, str);
|
||
|
+ 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 if (check_identifier(identifier, "_supporteddevs"))
|
||
|
- err = get_supported_device_list(uc_mgr, list, str);
|
||
|
- else if (check_identifier(identifier, "_conflictingdevs"))
|
||
|
- err = get_conflicting_device_list(uc_mgr, list, str);
|
||
|
+ err = get_modifier_list(uc_mgr, list, str);
|
||
|
+ else if (check_identifier(identifier, "_identifiers"))
|
||
|
+ err = get_identifiers_list(uc_mgr, list, str);
|
||
|
+ else if (check_identifier(identifier, "_supporteddevs"))
|
||
|
+ err = get_supported_device_list(uc_mgr, list, str);
|
||
|
+ else if (check_identifier(identifier, "_conflictingdevs"))
|
||
|
+ err = get_conflicting_device_list(uc_mgr, list, str);
|
||
|
else if (identifier[0] == '_')
|
||
|
err = -ENOENT;
|
||
|
- else
|
||
|
- err = get_value_list(uc_mgr, identifier, list, str);
|
||
|
- if (str)
|
||
|
- free(str);
|
||
|
- }
|
||
|
+ else
|
||
|
+ err = get_value_list(uc_mgr, identifier, list, str);
|
||
|
+ if (str)
|
||
|
+ free(str);
|
||
|
+ }
|
||
|
__end:
|
||
|
pthread_mutex_unlock(&uc_mgr->mutex);
|
||
|
return err;
|
||
|
--
|
||
|
2.16.4
|
||
|
|