return 0;
}
+/*
+ * Determine priority for a device.
+ * Priority order:
+ * 1. If 'Priority' value exists, use it as the sort key
+ * 2. If 'PlaybackPriority' value exists, use it as the sort key
+ * 3. If 'CapturePriority' value exists, use it as the sort key
+ * 4. Fallback: LONG_MIN (no priority)
+ */
+static long verb_device_get_priority(struct use_case_device *device)
+{
+ struct list_head *pos;
+ struct ucm_value *val;
+ const char *priority_str = NULL;
+ long priority = LONG_MIN;
+ int err;
+
+ list_for_each(pos, &device->value_list) {
+ val = list_entry(pos, struct ucm_value, list);
+ if (strcmp(val->name, "Priority") == 0) {
+ priority_str = val->data;
+ break;
+ }
+ }
+
+ if (!priority_str) {
+ list_for_each(pos, &device->value_list) {
+ val = list_entry(pos, struct ucm_value, list);
+ if (strcmp(val->name, "PlaybackPriority") == 0) {
+ priority_str = val->data;
+ break;
+ }
+ }
+ }
+
+ if (!priority_str) {
+ list_for_each(pos, &device->value_list) {
+ val = list_entry(pos, struct ucm_value, list);
+ if (strcmp(val->name, "CapturePriority") == 0) {
+ priority_str = val->data;
+ break;
+ }
+ }
+ }
+
+ if (priority_str) {
+ err = safe_strtol(priority_str, &priority);
+ if (err < 0)
+ priority = LONG_MIN;
+ }
+
+ return priority;
+}
+
+/*
+ * Sort devices based on priority values.
+ * Priority order:
+ * 1. If 'Priority' value exists, use it as the sort key
+ * 2. If 'PlaybackPriority' value exists, use it as the sort key
+ * 3. If 'CapturePriority' value exists, use it as the sort key
+ * 4. Fallback: use device->name (original) as the sort key
+ * Higher priority values are placed first in the list.
+ */
+static int verb_sort_devices(struct use_case_verb *verb)
+{
+ struct list_head sorted_list;
+ struct list_head *pos, *npos;
+ struct use_case_device *device, *insert_dev;
+
+ INIT_LIST_HEAD(&sorted_list);
+
+ /* First pass: determine and cache priority for all devices */
+ list_for_each(pos, &verb->device_list) {
+ device = list_entry(pos, struct use_case_device, list);
+ device->sort_priority = verb_device_get_priority(device);
+ }
+
+ /* Move devices from verb->device_list to sorted_list in sorted order */
+ list_for_each_safe(pos, npos, &verb->device_list) {
+ device = list_entry(pos, struct use_case_device, list);
+
+ /* Remove device from original list */
+ list_del(&device->list);
+
+ /* Find the insertion point in sorted_list */
+ /* Devices are sorted in descending order of priority (higher priority first) */
+ /* If priorities are equal or not defined, use device name as key */
+ if (list_empty(&sorted_list)) {
+ list_add_tail(&device->list, &sorted_list);
+ } else {
+ struct list_head *pos2, *insert_pos = &sorted_list;
+ list_for_each(pos2, &sorted_list) {
+ insert_dev = list_entry(pos2, struct use_case_device, list);
+
+ if (device->sort_priority > insert_dev->sort_priority) {
+ insert_pos = pos2;
+ break;
+ } else if (device->sort_priority == insert_dev->sort_priority) {
+ if (strcmp(device->name, insert_dev->name) < 0) {
+ insert_pos = pos2;
+ break;
+ }
+ }
+ }
+
+ list_add_tail(&device->list, insert_pos);
+ }
+ }
+
+ /* Move sorted list back to verb->device_list */
+ list_splice_init(&sorted_list, &verb->device_list);
+
+ return 0;
+}
+
static int verb_device_management(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb)
{
struct list_head *pos;
uc_mgr_free_dev_name_list(&verb->rename_list);
uc_mgr_free_dev_name_list(&verb->remove_list);
+ /* strip index from single device names */
+ if (uc_mgr->conf_format >= 8) {
+ /* sort devices by priority */
+ err = verb_sort_devices(verb);
+ if (err < 0)
+ return err;
+ }
+
/* normalize device names to remove spaces per use-case.h specification */
err = verb_normalize_device_names(uc_mgr, verb);
if (err < 0)
err = verb_strip_single_device_index(verb);
if (err < 0)
return err;
+
}
/* handle conflicting/supported lists */
The preference of the devices is determined by the priority value (higher value = higher priority).
+#### Device ordering (Syntax 8+)
+
+Starting with **Syntax 8**, devices are automatically sorted based on their priority values.
+The sorting is performed at the end of device management processing, after device renaming
+and index assignment.
+
+The priority key selection order is:
+1. **Priority** - If this value exists, use it as the sorting key
+2. **PlaybackPriority** - If Priority doesn't exist but PlaybackPriority exists, use it
+3. **CapturePriority** - If neither Priority nor PlaybackPriority exist, use CapturePriority
+4. **Fallback** - If no priority value is defined, use the device name for alphabetical sorting
+
+Devices are sorted in **descending order** of priority (higher priority values appear first
+in the device list). When two devices have the same priority value, they are sorted
+alphabetically by device name.
+
+Example - Device priority ordering:
+
+~~~{.html}
+SectionDevice."Speaker" {
+ Comment "Internal speaker"
+ EnableSequence [
+ cset "name='Speaker Switch' on"
+ ]
+ Value {
+ PlaybackPriority 100
+ PlaybackPCM "hw:${CardId},0"
+ }
+}
+
+SectionDevice."Headphones" {
+ Comment "Headphone jack"
+ EnableSequence [
+ cset "name='Headphone Switch' on"
+ ]
+ Value {
+ PlaybackPriority 200
+ PlaybackPCM "hw:${CardId},1"
+ }
+}
+
+SectionDevice."HDMI" {
+ Comment "HDMI output"
+ EnableSequence [
+ cset "name='HDMI Switch' on"
+ ]
+ Value {
+ PlaybackPriority 150
+ PlaybackPCM "hw:${CardId},3"
+ }
+}
+~~~
+
+In this example, the device list will be ordered as: Headphones (200), HDMI (150), Speaker (100).
+
See the SND_USE_CASE_MOD constants like #SND_USE_CASE_MOD_ECHO_REF for the full list of known modifiers.
### Boot (alsactl)