ucm: implement CardIdByName substitution

The syntax is ${CardIdByName:CARDNAME[#INDEX]}.

The CARDNAME is the ALSA's soundcard name (short form).
The INDEX is the instance (0 = first, 1 = second etc.).

Example: ${CardIdByName:HDA Intel PCH}
(which is identical to ${CardIdByName:HDA Intel PCH#0})

Signed-off-by: Jaroslav Kysela <perex@perex.cz>
This commit is contained in:
Jaroslav Kysela 2020-06-03 17:12:19 +02:00
parent f60e0d5fdc
commit eee879d381
6 changed files with 135 additions and 56 deletions

View file

@ -333,6 +333,7 @@ static int execute_sequence(snd_use_case_mgr_t *uc_mgr,
struct sequence_element *s; struct sequence_element *s;
char *cdev = NULL; char *cdev = NULL;
snd_ctl_t *ctl = NULL; snd_ctl_t *ctl = NULL;
struct ctl_list *ctl_list;
int err = 0; int err = 0;
list_for_each(pos, seq) { list_for_each(pos, seq) {
@ -400,11 +401,12 @@ static int execute_sequence(snd_use_case_mgr_t *uc_mgr,
} }
} }
if (ctl == NULL) { if (ctl == NULL) {
err = uc_mgr_open_ctl(uc_mgr, &ctl, cdev); err = uc_mgr_open_ctl(uc_mgr, &ctl_list, cdev, 1);
if (err < 0) { if (err < 0) {
uc_error("unable to open ctl device '%s'", cdev); uc_error("unable to open ctl device '%s'", cdev);
goto __fail; goto __fail;
} }
ctl = ctl_list->ctl;
} }
err = execute_cset(ctl, s->data.cset, s->type); err = execute_cset(ctl, s->data.cset, s->type);
if (err < 0) { if (err < 0) {
@ -516,7 +518,7 @@ static int add_auto_values(snd_use_case_mgr_t *uc_mgr)
char buf[40]; char buf[40];
int err; int err;
ctl_list = uc_mgr_get_one_ctl(uc_mgr); ctl_list = uc_mgr_get_master_ctl(uc_mgr);
if (ctl_list) { if (ctl_list) {
id = snd_ctl_card_info_get_id(ctl_list->ctl_info); id = snd_ctl_card_info_get_id(ctl_list->ctl_info);
snprintf(buf, sizeof(buf), "hw:%s", id); snprintf(buf, sizeof(buf), "hw:%s", id);

View file

@ -1901,25 +1901,16 @@ static int parse_master_file(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
/* get the card info */ /* get the card info */
static int get_card_info(snd_use_case_mgr_t *mgr, static int get_card_info(snd_use_case_mgr_t *mgr,
const char *ctl_name, const char *ctl_name,
snd_ctl_t **_handle, snd_ctl_card_info_t **info)
snd_ctl_card_info_t *info)
{ {
snd_ctl_t *handle; struct ctl_list *ctl_list;
int err; int err;
*_handle = NULL; err = uc_mgr_open_ctl(mgr, &ctl_list, ctl_name, 0);
err = uc_mgr_open_ctl(mgr, &handle, ctl_name);
if (err < 0) if (err < 0)
return err; return err;
err = snd_ctl_card_info(handle, info); *info = ctl_list->ctl_info;
if (err < 0) {
uc_error("control hardware info (%s): %s", ctl_name, snd_strerror(err));
} else {
*_handle = handle;
}
return err; return err;
} }
@ -1927,7 +1918,6 @@ static int get_card_info(snd_use_case_mgr_t *mgr,
static int get_by_card_name(snd_use_case_mgr_t *mgr, const char *card_name) static int get_by_card_name(snd_use_case_mgr_t *mgr, const char *card_name)
{ {
int card, err; int card, err;
snd_ctl_t *ctl;
snd_ctl_card_info_t *info; snd_ctl_card_info_t *info;
const char *_driver, *_name, *_long_name; const char *_driver, *_name, *_long_name;
@ -1942,11 +1932,11 @@ static int get_by_card_name(snd_use_case_mgr_t *mgr, const char *card_name)
while (card >= 0) { while (card >= 0) {
char name[32]; char name[32];
/* mandatory - clear the list, keep the only one CTL device */ /* clear the list, keep the only one CTL device */
uc_mgr_free_ctl_list(mgr); uc_mgr_free_ctl_list(mgr);
sprintf(name, "hw:%d", card); sprintf(name, "hw:%d", card);
err = get_card_info(mgr, name, &ctl, info); err = get_card_info(mgr, name, &info);
if (err == 0) { if (err == 0) {
_driver = snd_ctl_card_info_get_driver(info); _driver = snd_ctl_card_info_get_driver(info);
@ -1972,13 +1962,12 @@ static int get_by_card_name(snd_use_case_mgr_t *mgr, const char *card_name)
/* set the driver name and long name by the card ctl name */ /* set the driver name and long name by the card ctl name */
static int get_by_card(snd_use_case_mgr_t *mgr, const char *ctl_name) static int get_by_card(snd_use_case_mgr_t *mgr, const char *ctl_name)
{ {
snd_ctl_t *ctl;
snd_ctl_card_info_t *info; snd_ctl_card_info_t *info;
int err; int err;
snd_ctl_card_info_alloca(&info); snd_ctl_card_info_alloca(&info);
err = get_card_info(mgr, ctl_name, &ctl, info); err = get_card_info(mgr, ctl_name, &info);
if (err) if (err)
return err; return err;

View file

@ -228,7 +228,7 @@ static int if_eval_control_exists(snd_use_case_mgr_t *uc_mgr, snd_config_t *eval
err = uc_mgr_get_substituted_value(uc_mgr, &s, device); err = uc_mgr_get_substituted_value(uc_mgr, &s, device);
if (err < 0) if (err < 0)
return err; return err;
err = uc_mgr_open_ctl(uc_mgr, &ctl, s); err = uc_mgr_open_ctl(uc_mgr, &ctl, s, 1);
free(s); free(s);
if (err < 0) if (err < 0)
return err; return err;

View file

@ -115,6 +115,7 @@ struct ctl_list {
struct list_head dev_list; struct list_head dev_list;
snd_ctl_t *ctl; snd_ctl_t *ctl;
snd_ctl_card_info_t *ctl_info; snd_ctl_card_info_t *ctl_info;
int slave;
}; };
struct ucm_dev_name { struct ucm_dev_name {
@ -283,10 +284,13 @@ void uc_mgr_free_verb(snd_use_case_mgr_t *uc_mgr);
void uc_mgr_free(snd_use_case_mgr_t *uc_mgr); void uc_mgr_free(snd_use_case_mgr_t *uc_mgr);
int uc_mgr_open_ctl(snd_use_case_mgr_t *uc_mgr, int uc_mgr_open_ctl(snd_use_case_mgr_t *uc_mgr,
snd_ctl_t **ctl, struct ctl_list **ctl_list,
const char *device); const char *device,
int slave);
struct ctl_list *uc_mgr_get_one_ctl(snd_use_case_mgr_t *uc_mgr); struct ctl_list *uc_mgr_get_master_ctl(snd_use_case_mgr_t *uc_mgr);
struct ctl_list *uc_mgr_get_ctl_by_name(snd_use_case_mgr_t *uc_mgr,
const char *name, int idx);
snd_ctl_t *uc_mgr_get_ctl(snd_use_case_mgr_t *uc_mgr); snd_ctl_t *uc_mgr_get_ctl(snd_use_case_mgr_t *uc_mgr);
void uc_mgr_free_ctl_list(snd_use_case_mgr_t *uc_mgr); void uc_mgr_free_ctl_list(snd_use_case_mgr_t *uc_mgr);

View file

@ -73,7 +73,7 @@ static char *rval_card_number(snd_use_case_mgr_t *uc_mgr)
if (uc_mgr->conf_format < 3) if (uc_mgr->conf_format < 3)
return NULL; return NULL;
ctl_list = uc_mgr_get_one_ctl(uc_mgr); ctl_list = uc_mgr_get_master_ctl(uc_mgr);
if (ctl_list == NULL) if (ctl_list == NULL)
return strdup(""); return strdup("");
snprintf(num, sizeof(num), "%i", snd_ctl_card_info_get_card(ctl_list->ctl_info)); snprintf(num, sizeof(num), "%i", snd_ctl_card_info_get_card(ctl_list->ctl_info));
@ -84,7 +84,7 @@ static char *rval_card_id(snd_use_case_mgr_t *uc_mgr)
{ {
struct ctl_list *ctl_list; struct ctl_list *ctl_list;
ctl_list = uc_mgr_get_one_ctl(uc_mgr); ctl_list = uc_mgr_get_master_ctl(uc_mgr);
if (ctl_list == NULL) if (ctl_list == NULL)
return NULL; return NULL;
return strdup(snd_ctl_card_info_get_id(ctl_list->ctl_info)); return strdup(snd_ctl_card_info_get_id(ctl_list->ctl_info));
@ -94,7 +94,7 @@ static char *rval_card_driver(snd_use_case_mgr_t *uc_mgr)
{ {
struct ctl_list *ctl_list; struct ctl_list *ctl_list;
ctl_list = uc_mgr_get_one_ctl(uc_mgr); ctl_list = uc_mgr_get_master_ctl(uc_mgr);
if (ctl_list == NULL) if (ctl_list == NULL)
return NULL; return NULL;
return strdup(snd_ctl_card_info_get_driver(ctl_list->ctl_info)); return strdup(snd_ctl_card_info_get_driver(ctl_list->ctl_info));
@ -104,7 +104,7 @@ static char *rval_card_name(snd_use_case_mgr_t *uc_mgr)
{ {
struct ctl_list *ctl_list; struct ctl_list *ctl_list;
ctl_list = uc_mgr_get_one_ctl(uc_mgr); ctl_list = uc_mgr_get_master_ctl(uc_mgr);
if (ctl_list == NULL) if (ctl_list == NULL)
return NULL; return NULL;
return strdup(snd_ctl_card_info_get_name(ctl_list->ctl_info)); return strdup(snd_ctl_card_info_get_name(ctl_list->ctl_info));
@ -114,7 +114,7 @@ static char *rval_card_longname(snd_use_case_mgr_t *uc_mgr)
{ {
struct ctl_list *ctl_list; struct ctl_list *ctl_list;
ctl_list = uc_mgr_get_one_ctl(uc_mgr); ctl_list = uc_mgr_get_master_ctl(uc_mgr);
if (ctl_list == NULL) if (ctl_list == NULL)
return NULL; return NULL;
return strdup(snd_ctl_card_info_get_longname(ctl_list->ctl_info)); return strdup(snd_ctl_card_info_get_longname(ctl_list->ctl_info));
@ -124,12 +124,37 @@ static char *rval_card_components(snd_use_case_mgr_t *uc_mgr)
{ {
struct ctl_list *ctl_list; struct ctl_list *ctl_list;
ctl_list = uc_mgr_get_one_ctl(uc_mgr); ctl_list = uc_mgr_get_master_ctl(uc_mgr);
if (ctl_list == NULL) if (ctl_list == NULL)
return NULL; return NULL;
return strdup(snd_ctl_card_info_get_components(ctl_list->ctl_info)); return strdup(snd_ctl_card_info_get_components(ctl_list->ctl_info));
} }
static char *rval_card_id_by_name(snd_use_case_mgr_t *uc_mgr, const char *id)
{
struct ctl_list *ctl_list;
char *name, *index;
long idx = 0;
if (uc_mgr->conf_format < 3) {
uc_error("CardIdByName substitution is supported in v3+ syntax");
return NULL;
}
name = alloca(strlen(id) + 1);
strcpy(name, id);
index = strchr(name, '#');
if (index) {
*index = '\0';
if (safe_strtol(index + 1, &idx))
return NULL;
}
ctl_list = uc_mgr_get_ctl_by_name(uc_mgr, name, idx);
if (ctl_list == NULL)
return NULL;
return strdup(snd_ctl_card_info_get_id(ctl_list->ctl_info));
}
static char *rval_env(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED, const char *id) static char *rval_env(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED, const char *id)
{ {
char *e; char *e;
@ -265,6 +290,7 @@ int uc_mgr_get_substituted_value(snd_use_case_mgr_t *uc_mgr,
MATCH_VARIABLE2(value, "${env:", rval_env); MATCH_VARIABLE2(value, "${env:", rval_env);
MATCH_VARIABLE2(value, "${sys:", rval_sysfs); MATCH_VARIABLE2(value, "${sys:", rval_sysfs);
MATCH_VARIABLE2(value, "${var:", rval_var); MATCH_VARIABLE2(value, "${var:", rval_var);
MATCH_VARIABLE2(value, "${CardIdByName:", rval_card_id_by_name);
err = -EINVAL; err = -EINVAL;
tmp = strchr(value, '}'); tmp = strchr(value, '}');
if (tmp) { if (tmp) {

View file

@ -49,26 +49,73 @@ void uc_mgr_stdout(const char *fmt,...)
va_end(va); va_end(va);
} }
struct ctl_list *uc_mgr_get_one_ctl(snd_use_case_mgr_t *uc_mgr) struct ctl_list *uc_mgr_get_master_ctl(snd_use_case_mgr_t *uc_mgr)
{ {
struct list_head *pos; struct list_head *pos;
struct ctl_list *ctl_list = NULL; struct ctl_list *ctl_list = NULL, *ctl_list2;
list_for_each(pos, &uc_mgr->ctl_list) { list_for_each(pos, &uc_mgr->ctl_list) {
ctl_list2 = list_entry(pos, struct ctl_list, list);
if (ctl_list2->slave)
continue;
if (ctl_list) { if (ctl_list) {
uc_error("multiple control device names were found!"); uc_error("multiple control device names were found!");
return NULL; return NULL;
} }
ctl_list = list_entry(pos, struct ctl_list, list); ctl_list = ctl_list2;
} }
return ctl_list; return ctl_list;
} }
struct ctl_list *uc_mgr_get_ctl_by_name(snd_use_case_mgr_t *uc_mgr, const char *name, int idx)
{
struct list_head *pos;
struct ctl_list *ctl_list = NULL;
const char *s;
char cname[32];
int idx2, card, err;
idx2 = idx;
list_for_each(pos, &uc_mgr->ctl_list) {
ctl_list = list_entry(pos, struct ctl_list, list);
s = snd_ctl_card_info_get_name(ctl_list->ctl_info);
if (s == NULL)
continue;
if (strcmp(s, name) == 0) {
if (idx2 == 0)
return ctl_list;
idx2--;
}
}
idx2 = idx;
card = -1;
if (snd_card_next(&card) < 0 || card < 0)
return NULL;
while (card >= 0) {
sprintf(cname, "hw:%d", card);
err = uc_mgr_open_ctl(uc_mgr, &ctl_list, cname, 1);
if (err < 0)
continue; /* really? */
s = snd_ctl_card_info_get_name(ctl_list->ctl_info);
if (s && strcmp(s, name) == 0) {
if (idx2 == 0)
return ctl_list;
idx2--;
}
if (snd_card_next(&card) < 0)
break;
}
return NULL;
}
snd_ctl_t *uc_mgr_get_ctl(snd_use_case_mgr_t *uc_mgr) snd_ctl_t *uc_mgr_get_ctl(snd_use_case_mgr_t *uc_mgr)
{ {
struct ctl_list *ctl_list; struct ctl_list *ctl_list;
ctl_list = uc_mgr_get_one_ctl(uc_mgr); ctl_list = uc_mgr_get_master_ctl(uc_mgr);
if (ctl_list) if (ctl_list)
return ctl_list->ctl; return ctl_list->ctl;
return NULL; return NULL;
@ -127,10 +174,11 @@ static int uc_mgr_ctl_add_dev(struct ctl_list *ctl_list, const char *device)
} }
static int uc_mgr_ctl_add(snd_use_case_mgr_t *uc_mgr, static int uc_mgr_ctl_add(snd_use_case_mgr_t *uc_mgr,
struct ctl_list *ctl_list, struct ctl_list **ctl_list,
snd_ctl_t *ctl, int card, snd_ctl_t *ctl, int card,
snd_ctl_card_info_t *info, snd_ctl_card_info_t *info,
const char *device) const char *device,
int slave)
{ {
struct ctl_list *cl = NULL; struct ctl_list *cl = NULL;
const char *id = snd_ctl_card_info_get_id(info); const char *id = snd_ctl_card_info_get_id(info);
@ -139,7 +187,7 @@ static int uc_mgr_ctl_add(snd_use_case_mgr_t *uc_mgr,
if (id == NULL || id[0] == '\0') if (id == NULL || id[0] == '\0')
return -ENOENT; return -ENOENT;
if (!ctl_list) { if (!(*ctl_list)) {
cl = malloc(sizeof(*cl)); cl = malloc(sizeof(*cl));
if (cl == NULL) if (cl == NULL)
return -ENOMEM; return -ENOMEM;
@ -150,41 +198,49 @@ static int uc_mgr_ctl_add(snd_use_case_mgr_t *uc_mgr,
return -ENOMEM; return -ENOMEM;
} }
snd_ctl_card_info_copy(cl->ctl_info, info); snd_ctl_card_info_copy(cl->ctl_info, info);
ctl_list = cl; cl->slave = slave;
*ctl_list = cl;
} else {
if (!slave)
(*ctl_list)->slave = slave;
} }
if (card >= 0) { if (card >= 0) {
snprintf(dev, sizeof(dev), "hw:%d", card); snprintf(dev, sizeof(dev), "hw:%d", card);
hit |= !!(device && (strcmp(dev, device) == 0)); hit |= !!(device && (strcmp(dev, device) == 0));
err = uc_mgr_ctl_add_dev(ctl_list, dev); err = uc_mgr_ctl_add_dev(*ctl_list, dev);
if (err < 0) if (err < 0)
goto __nomem; goto __nomem;
} }
snprintf(dev, sizeof(dev), "hw:%s", id); snprintf(dev, sizeof(dev), "hw:%s", id);
hit |= !!(device && (strcmp(dev, device) == 0)); hit |= !!(device && (strcmp(dev, device) == 0));
err = uc_mgr_ctl_add_dev(ctl_list, dev); err = uc_mgr_ctl_add_dev(*ctl_list, dev);
if (err < 0) if (err < 0)
goto __nomem; goto __nomem;
/* the UCM name not based on the card name / id */ /* the UCM name not based on the card name / id */
if (!hit && device) { if (!hit && device) {
err = uc_mgr_ctl_add_dev(ctl_list, device); err = uc_mgr_ctl_add_dev(*ctl_list, device);
if (err < 0) if (err < 0)
goto __nomem; goto __nomem;
} }
list_add_tail(&ctl_list->list, &uc_mgr->ctl_list); list_add_tail(&(*ctl_list)->list, &uc_mgr->ctl_list);
return 0; return 0;
__nomem: __nomem:
if (ctl_list == cl) if (*ctl_list == cl) {
uc_mgr_free_ctl(cl); uc_mgr_free_ctl(cl);
*ctl_list = NULL;
}
return -ENOMEM; return -ENOMEM;
} }
int uc_mgr_open_ctl(snd_use_case_mgr_t *uc_mgr, int uc_mgr_open_ctl(snd_use_case_mgr_t *uc_mgr,
snd_ctl_t **ctl, struct ctl_list **ctll,
const char *device) const char *device,
int slave)
{ {
struct list_head *pos1, *pos2; struct list_head *pos1, *pos2;
snd_ctl_t *ctl;
struct ctl_list *ctl_list; struct ctl_list *ctl_list;
struct ctl_dev *ctl_dev; struct ctl_dev *ctl_dev;
snd_ctl_card_info_t *info; snd_ctl_card_info_t *info;
@ -199,24 +255,25 @@ int uc_mgr_open_ctl(snd_use_case_mgr_t *uc_mgr,
list_for_each(pos2, &ctl_list->dev_list) { list_for_each(pos2, &ctl_list->dev_list) {
ctl_dev = list_entry(pos2, struct ctl_dev, list); ctl_dev = list_entry(pos2, struct ctl_dev, list);
if (strcmp(ctl_dev->device, device) == 0) { if (strcmp(ctl_dev->device, device) == 0) {
*ctl = ctl_list->ctl; *ctll = ctl_list;
if (!slave)
ctl_list->slave = 0;
return 0; return 0;
} }
} }
} }
err = snd_ctl_open(ctl, device, 0); err = snd_ctl_open(&ctl, device, 0);
if (err < 0) if (err < 0)
return err; return err;
id = NULL; id = NULL;
err = snd_ctl_card_info(*ctl, info); err = snd_ctl_card_info(ctl, info);
if (err == 0) if (err == 0)
id = snd_ctl_card_info_get_id(info); id = snd_ctl_card_info_get_id(info);
if (err < 0 || id == NULL || id[0] == '\0') { if (err < 0 || id == NULL || id[0] == '\0') {
uc_error("control hardware info (%s): %s", device, snd_strerror(err)); uc_error("control hardware info (%s): %s", device, snd_strerror(err));
snd_ctl_close(*ctl); snd_ctl_close(ctl);
*ctl = NULL;
return err; return err;
} }
@ -225,24 +282,25 @@ int uc_mgr_open_ctl(snd_use_case_mgr_t *uc_mgr,
ctl_list = list_entry(pos1, struct ctl_list, list); ctl_list = list_entry(pos1, struct ctl_list, list);
if (strcmp(id, snd_ctl_card_info_get_id(ctl_list->ctl_info)) == 0) { if (strcmp(id, snd_ctl_card_info_get_id(ctl_list->ctl_info)) == 0) {
card = snd_card_get_index(id); card = snd_card_get_index(id);
err = uc_mgr_ctl_add(uc_mgr, ctl_list, *ctl, card, info, device); err = uc_mgr_ctl_add(uc_mgr, &ctl_list, ctl, card, info, device, slave);
if (err < 0) if (err < 0)
goto __nomem; goto __nomem;
snd_ctl_close(*ctl); snd_ctl_close(ctl);
*ctl = ctl_list->ctl; *ctll = ctl_list;
return 0; return 0;
} }
} }
err = uc_mgr_ctl_add(uc_mgr, NULL, *ctl, -1, info, device); ctl_list = NULL;
err = uc_mgr_ctl_add(uc_mgr, &ctl_list, ctl, -1, info, device, slave);
if (err < 0) if (err < 0)
goto __nomem; goto __nomem;
*ctll = ctl_list;
return 0; return 0;
__nomem: __nomem:
snd_ctl_close(*ctl); snd_ctl_close(ctl);
*ctl = NULL;
return -ENOMEM; return -ENOMEM;
} }