From e83fd7806fc1eec383e09c3aa1d7f78e5e7b7a20 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 18 Nov 2025 13:35:06 +0100 Subject: [PATCH] ucm: strip device index when the device type is present only one time Signed-off-by: Jaroslav Kysela --- src/ucm/parser.c | 161 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 128 insertions(+), 33 deletions(-) diff --git a/src/ucm/parser.c b/src/ucm/parser.c index 64ff5fe7..2c0d2678 100644 --- a/src/ucm/parser.c +++ b/src/ucm/parser.c @@ -1891,6 +1891,52 @@ static int is_device_name_used(struct use_case_verb *verb, const char *name, str 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. * 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) { - struct list_head *pos, *pos2, *pos3; - struct use_case_device *device, *device2; - struct use_case_modifier *modifier; - struct dev_list_node *dlist; + struct list_head *pos; + struct use_case_device *device; char *orig_name, *norm_name, *colon; char temp[80]; int err, index; @@ -1963,35 +2007,10 @@ __no_colon: goto __error; } - list_for_each(pos2, &verb->modifier_list) { - modifier = list_entry(pos2, struct use_case_modifier, list); - list_for_each(pos3, &modifier->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; - } - } - } - } - - 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; - } - } - } - } + /* Update all references to the old device name */ + err = verb_update_device_references(verb, orig_name, device->name); + if (err < 0) + goto __error; free(orig_name); free(norm_name); @@ -2005,6 +2024,75 @@ __error: 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) { 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) 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 */ return verb_dev_list_check(verb); } -- 2.47.3