From c79f09e1f5e8b559b58dacdb00708d995b2e3aa5 Mon Sep 17 00:00:00 2001 From: paulhsia Date: Sat, 30 Nov 2019 03:35:30 +0800 Subject: [PATCH 01/10] ucm: Use strncmp to avoid access-out-of-boundary If the length of the identifier is less than the length of the prefix, access-out-of-boundary will occur in memcmp(). Signed-off-by: paulhsia Signed-off-by: Jaroslav Kysela --- src/ucm/main.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/ucm/main.c b/src/ucm/main.c index b0b6ffb3..252e50d9 100644 --- a/src/ucm/main.c +++ b/src/ucm/main.c @@ -61,11 +61,13 @@ 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] == '/') + if (strncmp(identifier, prefix, len) != 0) + return 0; + + if (identifier[len] == 0 || identifier[len] == '/') return 1; + return 0; } -- 2.20.1 From 9baf64da2f26844434ecea4825052937a3abe06c Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Fri, 29 Nov 2019 22:28:26 +0100 Subject: [PATCH 02/10] ucm: return always at least NULL if no list is available in snd_use_case_get_list() Signed-off-by: Jaroslav Kysela --- src/ucm/main.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/ucm/main.c b/src/ucm/main.c index 252e50d9..b80db65f 100644 --- a/src/ucm/main.c +++ b/src/ucm/main.c @@ -1160,8 +1160,10 @@ static int get_supcon_device_list(snd_use_case_mgr_t *uc_mgr, modifier = find_modifier(uc_mgr, verb, name, 0); if (modifier) { - if (modifier->dev_list.type != type) + if (modifier->dev_list.type != type) { + *list = NULL; return 0; + } return get_list(&modifier->dev_list.list, list, struct dev_list_node, list, name); @@ -1169,8 +1171,10 @@ static int get_supcon_device_list(snd_use_case_mgr_t *uc_mgr, device = find_device(uc_mgr, verb, name, 0); if (device) { - if (device->dev_list.type != type) + if (device->dev_list.type != type) { + *list = NULL; return 0; + } return get_list(&device->dev_list.list, list, struct dev_list_node, list, name); -- 2.20.1 From ebdd2b6cdb8119cf75f0dd0a3b283d271b3a547e Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Sat, 30 Nov 2019 20:31:55 +0100 Subject: [PATCH 03/10] ucm: add _identifiers list Signed-off-by: Jaroslav Kysela --- 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 8e7e838c..85c58ac0 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 b80db65f..d2078a23 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.20.1 From 5ee5ef31b5ff3fb7c904054cb9cac7478a727f7c Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Sun, 1 Dec 2019 14:26:40 +0100 Subject: [PATCH 04/10] namehint: correct the @args check BugLink: https://github.com/alsa-project/alsa-plugins/issues/3 Signed-off-by: Jaroslav Kysela --- src/control/namehint.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/control/namehint.c b/src/control/namehint.c index 808df6b5..4927ef97 100644 --- a/src/control/namehint.c +++ b/src/control/namehint.c @@ -348,6 +348,12 @@ static int try_config(snd_config_t *config, goto __cleanup; if (snd_config_search(res, "@args", &cfg) >= 0) { snd_config_for_each(i, next, cfg) { + /* skip the argument list */ + snd_config_get_id(snd_config_iterator_entry(i), &str); + while (*str && *str >= '0' && *str <= '9') str++; + if (*str == '\0') + continue; + /* the argument definition must have the default */ if (snd_config_search(snd_config_iterator_entry(i), "default", NULL) < 0) { err = -EINVAL; -- 2.20.1 From 6055f8a584296abfc0cec0439ceb708f0eddcc9d Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Sun, 1 Dec 2019 14:30:54 +0100 Subject: [PATCH 05/10] namehint: improve the previous patch (check the returned value) Signed-off-by: Jaroslav Kysela --- src/control/namehint.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/control/namehint.c b/src/control/namehint.c index 4927ef97..60c48ae3 100644 --- a/src/control/namehint.c +++ b/src/control/namehint.c @@ -349,7 +349,8 @@ static int try_config(snd_config_t *config, if (snd_config_search(res, "@args", &cfg) >= 0) { snd_config_for_each(i, next, cfg) { /* skip the argument list */ - snd_config_get_id(snd_config_iterator_entry(i), &str); + if (snd_config_get_id(snd_config_iterator_entry(i), &str) < 0) + continue; while (*str && *str >= '0' && *str <= '9') str++; if (*str == '\0') continue; -- 2.20.1 From 4dddcf733d56a13f4d042fefa1fb6230c09f1f65 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 2 Dec 2019 11:56:30 +0100 Subject: [PATCH 06/10] ucm: docs - allow spaces in device names for JackHWMute Signed-off-by: Jaroslav Kysela --- include/use-case.h | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/include/use-case.h b/include/use-case.h index 85c58ac0..e1f58027 100644 --- a/include/use-case.h +++ b/include/use-case.h @@ -326,7 +326,7 @@ int snd_use_case_get_list(snd_use_case_mgr_t *uc_mgr, * - Valid values: "soft" (software attenuation) * - EDIDFile * - Path to EDID file for HDMI devices - * - JackControl, JackDev, JackHWMute + * - JackControl, JackDev * - Jack information for a device. The jack status can be reported via * a kcontrol and/or via an input device. **JackControl** is the * kcontrol name of the jack, and **JackDev** is the input device id of @@ -334,17 +334,18 @@ int snd_use_case_get_list(snd_use_case_mgr_t *uc_mgr, * JackDev value should be "foo"). UCM configuration files should * contain both JackControl and JackDev when possible, because * applications are likely to support only one or the other. - * - * If **JackHWMute** is set, it indicates that when the jack is plugged - * in, the hardware automatically mutes some other device(s). The - * JackHWMute value is a space-separated list of device names (this - * isn't compatible with device names with spaces in them, so don't use - * such device names!). Note that JackHWMute should be used only when - * the hardware enforces the automatic muting. If the hardware doesn't - * enforce any muting, it may still be tempting to set JackHWMute to - * trick upper software layers to e.g. automatically mute speakers when - * headphones are plugged in, but that's application policy - * configuration that doesn't belong to UCM configuration files. + * - JackHWMute + * If this value is set, it indicates that when the jack is plugged + * in, the hardware automatically mutes some other device(s). The + * value is a space-separated list of device names. If the device + * name contains space, it must be enclosed to ' or ", e.g.: + * JackHWMute "'Dock Headphone' Headphone" + * Note that JackHWMute should be used only when the hardware enforces + * the automatic muting. If the hardware doesn't enforce any muting, it + * may still be tempting to set JackHWMute to trick upper software layers + * to e.g. automatically mute speakers when headphones are plugged in, + * but that's application policy configuration that doesn't belong + * to UCM configuration files. * - MinBufferLevel * - This is used on platform where reported buffer level is not accurate. * E.g. "512", which holds 512 samples in device buffer. Note: this will -- 2.20.1 From 2a286ca9a8415571181ce58027686ec332a834e9 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 2 Dec 2019 11:57:18 +0100 Subject: [PATCH 07/10] use-case: docs - add PlaybackMixerCopy and CaptureMixerCopy Signed-off-by: Jaroslav Kysela --- include/use-case.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/include/use-case.h b/include/use-case.h index e1f58027..71fcc949 100644 --- a/include/use-case.h +++ b/include/use-case.h @@ -309,8 +309,14 @@ int snd_use_case_get_list(snd_use_case_mgr_t *uc_mgr, * - PlaybackMixerElem * - mixer element playback identifier * - can be parsed using snd_use_case_parse_selem_id() + * - PlaybackMixerCopy + * - additional mixer element playback identifier + * - can be parsed using snd_use_case_parse_selem_id() + * - those elements should copy the volume and switch settings + * - element identifiers are separated using the | character * - PlaybackMasterElem * - mixer element playback identifier for the master control + * - can be parsed using snd_use_case_parse_selem_id() * - PlaybackMasterType * - type of the master volume control * - Valid values: "soft" (software attenuation) @@ -319,8 +325,14 @@ int snd_use_case_get_list(snd_use_case_mgr_t *uc_mgr, * - CaptureMixerElem * - mixer element capture identifier * - can be parsed using snd_use_case_parse_selem_id() + * - CaptureMixerCopy + * - additional mixer element capture identifier + * - can be parsed using snd_use_case_parse_selem_id() + * - those elements should copy the volume and switch settings + * - element identifiers are separated using the | character * - CaptureMasterElem * - mixer element playback identifier for the master control + * - can be parsed using snd_use_case_parse_selem_id() * - CaptureMasterType * - type of the master volume control * - Valid values: "soft" (software attenuation) -- 2.20.1 From a0fc4447bb7c7f9a850a0a85f3a5a32c1509caf4 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 3 Dec 2019 15:01:04 +0100 Subject: [PATCH 08/10] ucm: docs - add JackCTL, rearrange JackControl and JackDev Signed-off-by: Jaroslav Kysela --- include/use-case.h | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/include/use-case.h b/include/use-case.h index 71fcc949..25998cb9 100644 --- a/include/use-case.h +++ b/include/use-case.h @@ -338,14 +338,20 @@ int snd_use_case_get_list(snd_use_case_mgr_t *uc_mgr, * - Valid values: "soft" (software attenuation) * - EDIDFile * - Path to EDID file for HDMI devices - * - JackControl, JackDev - * - Jack information for a device. The jack status can be reported via - * a kcontrol and/or via an input device. **JackControl** is the - * kcontrol name of the jack, and **JackDev** is the input device id of - * the jack (if the full input device path is /dev/input/by-id/foo, the - * JackDev value should be "foo"). UCM configuration files should - * contain both JackControl and JackDev when possible, because - * applications are likely to support only one or the other. + * - JackCTL + * - jack control device name + * - JackControl + * - jack control identificator + * - can be parsed using snd_use_case_parse_ctl_elem_id() + * - UCM configuration files should contain both JackControl and JackDev + * when possible, because applications are likely to support only one + * or the other + * - JackDev + * - the input device id of the jack (if the full input device path is + * /dev/input/by-id/foo, the JackDev value should be "foo") + * - UCM configuration files should contain both JackControl and JackDev + * when possible, because applications are likely to support only one + * or the other * - JackHWMute * If this value is set, it indicates that when the jack is plugged * in, the hardware automatically mutes some other device(s). The -- 2.20.1 From e59034a0bec257cc7422a1e9436d936be8696a6f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 3 Dec 2019 18:27:39 +0100 Subject: [PATCH 09/10] ucm: Do not fail to parse configs on cards with an empty CardComponents lists Since the UCM profiles for all Bay- and Cherry-Trail SST cards have been moved over to UCM2, parsing them fails with: ALSA lib ucm_subs.c:220:(uc_mgr_get_substituted_value) variable '${CardComponents}' is not defined in this context! This completely breaks audio support on all Bay- and Cherry-Trail devices. This is caused by these non-SOF ASoC using cards having an empty CardComponents list. Which in itself is fine, but is rejected by the ucm_subs.c code. This commit changes the ucm_subs code to accept an empty string as a valid value for CardComponents restoring audio functionality on these boards. Signed-off-by: Hans de Goede Signed-off-by: Jaroslav Kysela --- src/ucm/ucm_subs.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/ucm/ucm_subs.c b/src/ucm/ucm_subs.c index 00afa9e3..90e395f0 100644 --- a/src/ucm/ucm_subs.c +++ b/src/ucm/ucm_subs.c @@ -25,6 +25,7 @@ */ #include "ucm_local.h" +#include #include #include @@ -145,10 +146,11 @@ static char *rval_sysfs(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED, const char return strdup(path); } -#define MATCH_VARIABLE(name, id, fcn) \ +#define MATCH_VARIABLE(name, id, fcn, empty_ok) \ if (strncmp((name), (id), sizeof(id) - 1) == 0) { \ rval = fcn(uc_mgr); \ idsize = sizeof(id) - 1; \ + allow_empty = (empty_ok); \ goto __rval; \ } @@ -189,12 +191,14 @@ int uc_mgr_get_substituted_value(snd_use_case_mgr_t *uc_mgr, while (*value) { if (*value == '$' && *(value+1) == '{') { - MATCH_VARIABLE(value, "${ConfName}", rval_conf_name); - MATCH_VARIABLE(value, "${CardId}", rval_card_id); - MATCH_VARIABLE(value, "${CardDriver}", rval_card_driver); - MATCH_VARIABLE(value, "${CardName}", rval_card_name); - MATCH_VARIABLE(value, "${CardLongName}", rval_card_longname); - MATCH_VARIABLE(value, "${CardComponents}", rval_card_components); + bool allow_empty = false; + + MATCH_VARIABLE(value, "${ConfName}", rval_conf_name, false); + MATCH_VARIABLE(value, "${CardId}", rval_card_id, false); + MATCH_VARIABLE(value, "${CardDriver}", rval_card_driver, false); + MATCH_VARIABLE(value, "${CardName}", rval_card_name, false); + MATCH_VARIABLE(value, "${CardLongName}", rval_card_longname, false); + MATCH_VARIABLE(value, "${CardComponents}", rval_card_components, true); MATCH_VARIABLE2(value, "${env:", rval_env); MATCH_VARIABLE2(value, "${sys:", rval_sysfs); err = -EINVAL; @@ -208,7 +212,7 @@ int uc_mgr_get_substituted_value(snd_use_case_mgr_t *uc_mgr, } goto __error; __rval: - if (rval == NULL || rval[0] == '\0') { + if (rval == NULL || (!allow_empty && rval[0] == '\0')) { free(rval); strncpy(r, value, idsize); r[idsize] = '\0'; -- 2.20.1 From 8e2c70add782f997f7c269ed3f722888e56ff024 Mon Sep 17 00:00:00 2001 From: Fabrice Fontaine Date: Tue, 3 Dec 2019 18:56:40 +0100 Subject: [PATCH 10/10] src/ucm/main.c: fix build without mixer Commit 4ce38a5ff466d18039b2606938f866ea3a6c9f3c breaks the build without mixer on: CCLD libasound.la /home/buildroot/autobuild/instance-1/output-1/host/lib/gcc/xtensa-buildroot-linux-uclibc/8.3.0/../../../../xtensa-buildroot-linux-uclibc/bin/ld: ucm/.libs/libucm.a(main.o): in function `snd_use_case_set': main.c:(.text+0x185c): undefined reference to `snd_mixer_selem_id_parse' Fixes: http://autobuild.buildroot.org/results/4d91c9f82a2a61c50c457a851073b85cc09ea345 Signed-off-by: Fabrice Fontaine Signed-off-by: Jaroslav Kysela --- src/ucm/main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ucm/main.c b/src/ucm/main.c index d2078a23..61922f10 100644 --- a/src/ucm/main.c +++ b/src/ucm/main.c @@ -2115,8 +2115,10 @@ int snd_use_case_parse_selem_id(snd_mixer_selem_id_t *dst, const char *ucm_id, const char *value) { +#ifdef BUILD_MIXER if (strcmp(ucm_id, "PlaybackMixerId") == 0 || strcmp(ucm_id, "CaptureMixerId") == 0) return snd_mixer_selem_id_parse(dst, value); +#endif return -EINVAL; } -- 2.20.1