ucm: strip device index when the device type is present only one time

Signed-off-by: Jaroslav Kysela <perex@perex.cz>
This commit is contained in:
Jaroslav Kysela 2025-11-18 13:35:06 +01:00
parent 48c477569d
commit e83fd7806f

View file

@ -1891,6 +1891,52 @@ static int is_device_name_used(struct use_case_verb *verb, const char *name, str
return 0; return 0;
} }
/*
* Update all references to a device name in modifiers and other devices.
* This helper function is used when renaming devices to ensure all
* dev_list references are updated accordingly.
*/
static int verb_update_device_references(struct use_case_verb *verb,
const char *old_name,
const char *new_name)
{
struct list_head *pos, *pos2;
struct use_case_device *device;
struct use_case_modifier *modifier;
struct dev_list_node *dlist;
char *name_copy;
list_for_each(pos, &verb->modifier_list) {
modifier = list_entry(pos, struct use_case_modifier, list);
list_for_each(pos2, &modifier->dev_list.list) {
dlist = list_entry(pos2, struct dev_list_node, list);
if (strcmp(dlist->name, old_name) == 0) {
name_copy = strdup(new_name);
if (name_copy == NULL)
return -ENOMEM;
free(dlist->name);
dlist->name = name_copy;
}
}
}
list_for_each(pos, &verb->device_list) {
device = list_entry(pos, struct use_case_device, list);
list_for_each(pos2, &device->dev_list.list) {
dlist = list_entry(pos2, struct dev_list_node, list);
if (strcmp(dlist->name, old_name) == 0) {
name_copy = strdup(new_name);
if (name_copy == NULL)
return -ENOMEM;
free(dlist->name);
dlist->name = name_copy;
}
}
}
return 0;
}
/* /*
* Normalize device names according to use-case.h specification. * Normalize device names according to use-case.h specification.
* Device names like "HDMI 1" or "Line 1" should be normalized to "HDMI1" and "Line1". * Device names like "HDMI 1" or "Line 1" should be normalized to "HDMI1" and "Line1".
@ -1900,10 +1946,8 @@ static int is_device_name_used(struct use_case_verb *verb, const char *name, str
*/ */
static int verb_normalize_device_names(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb) static int verb_normalize_device_names(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb)
{ {
struct list_head *pos, *pos2, *pos3; struct list_head *pos;
struct use_case_device *device, *device2; struct use_case_device *device;
struct use_case_modifier *modifier;
struct dev_list_node *dlist;
char *orig_name, *norm_name, *colon; char *orig_name, *norm_name, *colon;
char temp[80]; char temp[80];
int err, index; int err, index;
@ -1963,35 +2007,10 @@ __no_colon:
goto __error; goto __error;
} }
list_for_each(pos2, &verb->modifier_list) { /* Update all references to the old device name */
modifier = list_entry(pos2, struct use_case_modifier, list); err = verb_update_device_references(verb, orig_name, device->name);
list_for_each(pos3, &modifier->dev_list.list) { if (err < 0)
dlist = list_entry(pos3, struct dev_list_node, list); goto __error;
if (strcmp(dlist->name, orig_name) == 0) {
free(dlist->name);
dlist->name = strdup(device->name);
if (dlist->name == NULL) {
err = -ENOMEM;
goto __error;
}
}
}
}
list_for_each(pos2, &verb->device_list) {
device2 = list_entry(pos2, struct use_case_device, list);
list_for_each(pos3, &device2->dev_list.list) {
dlist = list_entry(pos3, struct dev_list_node, list);
if (strcmp(dlist->name, orig_name) == 0) {
free(dlist->name);
dlist->name = strdup(device->name);
if (dlist->name == NULL) {
err = -ENOMEM;
goto __error;
}
}
}
}
free(orig_name); free(orig_name);
free(norm_name); free(norm_name);
@ -2005,6 +2024,75 @@ __error:
return err; return err;
} }
/*
* Strip index from single device names.
* According to use-case.h specification, if there is only one device
* with a given base name (e.g., only "HDMI1" and no "HDMI2"), the index
* should be stripped to produce the final name (e.g., "HDMI").
*/
static int verb_strip_single_device_index(struct use_case_verb *verb)
{
struct list_head *pos, *pos2;
struct use_case_device *device, *device2;
char *base_name, *test_base;
char *orig_name;
int count, index, test_index, err;
list_for_each(pos, &verb->device_list) {
device = list_entry(pos, struct use_case_device, list);
base_name = strdup(device->name);
if (base_name == NULL)
return -ENOMEM;
err = parse_device_index(&base_name, &index);
if (err < 0) {
free(base_name);
continue;
}
if (index <= 0) {
free(base_name);
continue;
}
/* Count how many devices have the same base name */
count = 0;
list_for_each(pos2, &verb->device_list) {
device2 = list_entry(pos2, struct use_case_device, list);
test_base = strdup(device2->name);
if (test_base == NULL) {
free(base_name);
return -ENOMEM;
}
err = parse_device_index(&test_base, &test_index);
if (err >= 0 && strcmp(test_base, base_name) == 0)
count++;
free(test_base);
}
if (count == 1) {
orig_name = device->name;
device->name = base_name;
err = verb_update_device_references(verb, orig_name, device->name);
if (err < 0) {
device->name = orig_name;
free(base_name);
return err;
}
free(orig_name);
} else {
free(base_name);
}
}
return 0;
}
static int verb_device_management(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb) static int verb_device_management(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb)
{ {
struct list_head *pos; struct list_head *pos;
@ -2040,6 +2128,13 @@ static int verb_device_management(snd_use_case_mgr_t *uc_mgr, struct use_case_ve
if (err < 0) if (err < 0)
return err; return err;
/* strip index from single device names */
if (uc_mgr->conf_format >= 8) {
err = verb_strip_single_device_index(verb);
if (err < 0)
return err;
}
/* handle conflicting/supported lists */ /* handle conflicting/supported lists */
return verb_dev_list_check(verb); return verb_dev_list_check(verb);
} }