diff mbox series

[13/31] ALSA: usb-audio: scarlett2: Allow arbitrary ordering of mux entries

Message ID 08e8d784d78262cb57496d28ef1ad7b6213a90ab.1624294591.git.g@b4.vu
State Accepted
Commit 6522c36419af1cc3e9613d4c5342cbdc740a359a
Headers show
Series Refactor Scarlett Gen 2 support and add Scarlett Gen 3 support | expand

Commit Message

Geoffrey D. Bennett June 21, 2021, 6:09 p.m. UTC
Some Gen 3 devices do not put all of the mux entries for the same port
types together in order in the "set mux" message data. To prepare for
this, replace the struct scarlett2_ports num[] array and the
assignment_order[] array with mux_assignment[], a list of port types
and ranges that is defined in the struct scarlett2_device_info.

Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
---
 sound/usb/mixer_scarlett_gen2.c | 222 ++++++++++++++++++++++----------
 1 file changed, 154 insertions(+), 68 deletions(-)
diff mbox series

Patch

diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c
index d30f15d580b5..b874c0c922d3 100644
--- a/sound/usb/mixer_scarlett_gen2.c
+++ b/sound/usb/mixer_scarlett_gen2.c
@@ -184,14 +184,11 @@  enum {
 	SCARLETT2_PORT_TYPE_COUNT    = 6,
 };
 
-/* Count of total I/O and number available at each sample rate */
+/* I/O count of each port type kept in struct scarlett2_ports */
 enum {
-	SCARLETT2_PORT_IN      = 0,
-	SCARLETT2_PORT_OUT     = 1,
-	SCARLETT2_PORT_OUT_44  = 2,
-	SCARLETT2_PORT_OUT_88  = 3,
-	SCARLETT2_PORT_OUT_176 = 4,
-	SCARLETT2_PORT_DIRNS   = 5,
+	SCARLETT2_PORT_IN    = 0,
+	SCARLETT2_PORT_OUT   = 1,
+	SCARLETT2_PORT_DIRNS = 2,
 };
 
 /* Dim/Mute buttons on the 18i20 */
@@ -220,6 +217,24 @@  struct scarlett2_ports {
 	const char * const dst_descr;
 };
 
+/* Number of mux tables: one for each band of sample rates
+ * (44.1/48kHz, 88.2/96kHz, and 176.4/176kHz)
+ */
+#define SCARLETT2_MUX_TABLES 3
+
+/* Maximum number of entries in a mux table */
+#define SCARLETT2_MAX_MUX_ENTRIES 7
+
+/* One entry within mux_assignment defines the port type and range of
+ * ports to add to the set_mux message. The end of the list is marked
+ * with count == 0.
+ */
+struct scarlett2_mux_entry {
+	u8 port_type;
+	u8 start;
+	u8 count;
+};
+
 struct scarlett2_device_info {
 	u32 usb_id; /* USB device identifier */
 
@@ -241,6 +256,10 @@  struct scarlett2_device_info {
 
 	/* port count and type data */
 	struct scarlett2_ports ports[SCARLETT2_PORT_TYPE_COUNT];
+
+	/* layout/order of the entries in the set_mux message */
+	struct scarlett2_mux_entry mux_assignment[SCARLETT2_MUX_TABLES]
+						 [SCARLETT2_MAX_MUX_ENTRIES];
 };
 
 struct scarlett2_data {
@@ -293,38 +312,61 @@  static const struct scarlett2_device_info s6i6_gen2_info = {
 	.ports = {
 		[SCARLETT2_PORT_TYPE_NONE] = {
 			.id = 0x000,
-			.num = { 1, 0, 8, 8, 8 },
+			.num = { 1, 0 },
 			.src_descr = "Off",
 		},
 		[SCARLETT2_PORT_TYPE_ANALOGUE] = {
 			.id = 0x080,
-			.num = { 4, 4, 4, 4, 4 },
+			.num = { 4, 4 },
 			.src_descr = "Analogue %d",
 			.src_num_offset = 1,
 			.dst_descr = "Analogue Output %02d Playback"
 		},
 		[SCARLETT2_PORT_TYPE_SPDIF] = {
 			.id = 0x180,
-			.num = { 2, 2, 2, 2, 2 },
+			.num = { 2, 2 },
 			.src_descr = "S/PDIF %d",
 			.src_num_offset = 1,
 			.dst_descr = "S/PDIF Output %d Playback"
 		},
 		[SCARLETT2_PORT_TYPE_MIX] = {
 			.id = 0x300,
-			.num = { 10, 18, 18, 18, 18 },
+			.num = { 10, 18 },
 			.src_descr = "Mix %c",
 			.src_num_offset = 65,
 			.dst_descr = "Mixer Input %02d Capture"
 		},
 		[SCARLETT2_PORT_TYPE_PCM] = {
 			.id = 0x600,
-			.num = { 6, 6, 6, 6, 6 },
+			.num = { 6, 6 },
 			.src_descr = "PCM %d",
 			.src_num_offset = 1,
 			.dst_descr = "PCM %02d Capture"
 		},
 	},
+
+	.mux_assignment = { {
+		{ SCARLETT2_PORT_TYPE_PCM,      0,  6 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE, 0,  4 },
+		{ SCARLETT2_PORT_TYPE_SPDIF,    0,  2 },
+		{ SCARLETT2_PORT_TYPE_MIX,      0, 18 },
+		{ SCARLETT2_PORT_TYPE_NONE,     0,  8 },
+		{ 0,                            0,  0 },
+	}, {
+		{ SCARLETT2_PORT_TYPE_PCM,      0,  6 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE, 0,  4 },
+		{ SCARLETT2_PORT_TYPE_SPDIF,    0,  2 },
+		{ SCARLETT2_PORT_TYPE_MIX,      0, 18 },
+		{ SCARLETT2_PORT_TYPE_NONE,     0,  8 },
+		{ 0,                            0,  0 },
+	}, {
+		{ SCARLETT2_PORT_TYPE_PCM,      0,  6 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE, 0,  4 },
+		{ SCARLETT2_PORT_TYPE_SPDIF,    0,  2 },
+		{ SCARLETT2_PORT_TYPE_MIX,      0, 18 },
+		{ SCARLETT2_PORT_TYPE_NONE,     0,  8 },
+		{ 0,                            0,  0 },
+	} },
 };
 
 static const struct scarlett2_device_info s18i8_gen2_info = {
@@ -345,44 +387,67 @@  static const struct scarlett2_device_info s18i8_gen2_info = {
 	.ports = {
 		[SCARLETT2_PORT_TYPE_NONE] = {
 			.id = 0x000,
-			.num = { 1, 0, 8, 8, 4 },
+			.num = { 1, 0 },
 			.src_descr = "Off",
 		},
 		[SCARLETT2_PORT_TYPE_ANALOGUE] = {
 			.id = 0x080,
-			.num = { 8, 6, 6, 6, 6 },
+			.num = { 8, 6 },
 			.src_descr = "Analogue %d",
 			.src_num_offset = 1,
 			.dst_descr = "Analogue Output %02d Playback"
 		},
 		[SCARLETT2_PORT_TYPE_SPDIF] = {
 			.id = 0x180,
-			.num = { 2, 2, 2, 2, 2 },
+			.num = { 2, 2 },
 			.src_descr = "S/PDIF %d",
 			.src_num_offset = 1,
 			.dst_descr = "S/PDIF Output %d Playback"
 		},
 		[SCARLETT2_PORT_TYPE_ADAT] = {
 			.id = 0x200,
-			.num = { 8, 0, 0, 0, 0 },
+			.num = { 8, 0 },
 			.src_descr = "ADAT %d",
 			.src_num_offset = 1,
 		},
 		[SCARLETT2_PORT_TYPE_MIX] = {
 			.id = 0x300,
-			.num = { 10, 18, 18, 18, 18 },
+			.num = { 10, 18 },
 			.src_descr = "Mix %c",
 			.src_num_offset = 65,
 			.dst_descr = "Mixer Input %02d Capture"
 		},
 		[SCARLETT2_PORT_TYPE_PCM] = {
 			.id = 0x600,
-			.num = { 8, 18, 18, 14, 10 },
+			.num = { 8, 18 },
 			.src_descr = "PCM %d",
 			.src_num_offset = 1,
 			.dst_descr = "PCM %02d Capture"
 		},
 	},
+
+	.mux_assignment = { {
+		{ SCARLETT2_PORT_TYPE_PCM,      0, 18 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE, 0,  6 },
+		{ SCARLETT2_PORT_TYPE_SPDIF,    0,  2 },
+		{ SCARLETT2_PORT_TYPE_MIX,      0, 18 },
+		{ SCARLETT2_PORT_TYPE_NONE,     0,  8 },
+		{ 0,                            0,  0 },
+	}, {
+		{ SCARLETT2_PORT_TYPE_PCM,      0, 14 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE, 0,  6 },
+		{ SCARLETT2_PORT_TYPE_SPDIF,    0,  2 },
+		{ SCARLETT2_PORT_TYPE_MIX,      0, 18 },
+		{ SCARLETT2_PORT_TYPE_NONE,     0,  8 },
+		{ 0,                            0,  0 },
+	}, {
+		{ SCARLETT2_PORT_TYPE_PCM,      0, 10 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE, 0,  6 },
+		{ SCARLETT2_PORT_TYPE_SPDIF,    0,  2 },
+		{ SCARLETT2_PORT_TYPE_MIX,      0, 18 },
+		{ SCARLETT2_PORT_TYPE_NONE,     0,  4 },
+		{ 0,                            0,  0 },
+	} },
 };
 
 static const struct scarlett2_device_info s18i20_gen2_info = {
@@ -406,12 +471,12 @@  static const struct scarlett2_device_info s18i20_gen2_info = {
 	.ports = {
 		[SCARLETT2_PORT_TYPE_NONE] = {
 			.id = 0x000,
-			.num = { 1, 0, 8, 8, 6 },
+			.num = { 1, 0 },
 			.src_descr = "Off",
 		},
 		[SCARLETT2_PORT_TYPE_ANALOGUE] = {
 			.id = 0x080,
-			.num = { 8, 10, 10, 10, 10 },
+			.num = { 8, 10 },
 			.src_descr = "Analogue %d",
 			.src_num_offset = 1,
 			.dst_descr = "Analogue Output %02d Playback"
@@ -422,33 +487,58 @@  static const struct scarlett2_device_info s18i20_gen2_info = {
 			 * assignment message anyway
 			 */
 			.id = 0x180,
-			.num = { 2, 2, 2, 2, 2 },
+			.num = { 2, 2 },
 			.src_descr = "S/PDIF %d",
 			.src_num_offset = 1,
 			.dst_descr = "S/PDIF Output %d Playback"
 		},
 		[SCARLETT2_PORT_TYPE_ADAT] = {
 			.id = 0x200,
-			.num = { 8, 8, 8, 4, 0 },
+			.num = { 8, 8 },
 			.src_descr = "ADAT %d",
 			.src_num_offset = 1,
 			.dst_descr = "ADAT Output %d Playback"
 		},
 		[SCARLETT2_PORT_TYPE_MIX] = {
 			.id = 0x300,
-			.num = { 10, 18, 18, 18, 18 },
+			.num = { 10, 18 },
 			.src_descr = "Mix %c",
 			.src_num_offset = 65,
 			.dst_descr = "Mixer Input %02d Capture"
 		},
 		[SCARLETT2_PORT_TYPE_PCM] = {
 			.id = 0x600,
-			.num = { 20, 18, 18, 14, 10 },
+			.num = { 20, 18 },
 			.src_descr = "PCM %d",
 			.src_num_offset = 1,
 			.dst_descr = "PCM %02d Capture"
 		},
 	},
+
+	.mux_assignment = { {
+		{ SCARLETT2_PORT_TYPE_PCM,      0, 18 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE, 0, 10 },
+		{ SCARLETT2_PORT_TYPE_SPDIF,    0,  2 },
+		{ SCARLETT2_PORT_TYPE_ADAT,     0,  8 },
+		{ SCARLETT2_PORT_TYPE_MIX,      0, 18 },
+		{ SCARLETT2_PORT_TYPE_NONE,     0,  8 },
+		{ 0,                            0,  0 },
+	}, {
+		{ SCARLETT2_PORT_TYPE_PCM,      0, 14 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE, 0, 10 },
+		{ SCARLETT2_PORT_TYPE_SPDIF,    0,  2 },
+		{ SCARLETT2_PORT_TYPE_ADAT,     0,  4 },
+		{ SCARLETT2_PORT_TYPE_MIX,      0, 18 },
+		{ SCARLETT2_PORT_TYPE_NONE,     0,  8 },
+		{ 0,                            0,  0 },
+	}, {
+		{ SCARLETT2_PORT_TYPE_PCM,      0, 10 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE, 0, 10 },
+		{ SCARLETT2_PORT_TYPE_SPDIF,    0,  2 },
+		{ SCARLETT2_PORT_TYPE_MIX,      0, 18 },
+		{ SCARLETT2_PORT_TYPE_NONE,     0,  6 },
+		{ 0,                            0,  0 },
+	} },
 };
 
 static const struct scarlett2_device_info *scarlett2_devices[] = {
@@ -1009,16 +1099,7 @@  static int scarlett2_usb_set_mux(struct usb_mixer_interface *mixer)
 	struct scarlett2_data *private = mixer->private_data;
 	const struct scarlett2_device_info *info = private->info;
 	const struct scarlett2_ports *ports = info->ports;
-	int rate, port_dir_rate;
-
-	static const int assignment_order[SCARLETT2_PORT_TYPE_COUNT] = {
-		SCARLETT2_PORT_TYPE_PCM,
-		SCARLETT2_PORT_TYPE_ANALOGUE,
-		SCARLETT2_PORT_TYPE_SPDIF,
-		SCARLETT2_PORT_TYPE_ADAT,
-		SCARLETT2_PORT_TYPE_MIX,
-		SCARLETT2_PORT_TYPE_NONE,
-	};
+	int table;
 
 	struct {
 		__le16 pad;
@@ -1028,39 +1109,44 @@  static int scarlett2_usb_set_mux(struct usb_mixer_interface *mixer)
 
 	req.pad = 0;
 
-	/* mux settings for each rate */
-	for (rate = 0, port_dir_rate = SCARLETT2_PORT_OUT_44;
-	     port_dir_rate <= SCARLETT2_PORT_OUT_176;
-	     rate++, port_dir_rate++) {
-		int order_num, i, err;
-
-		req.num = cpu_to_le16(rate);
-
-		for (order_num = 0, i = 0;
-		     order_num < SCARLETT2_PORT_TYPE_COUNT;
-		     order_num++) {
-			int port_type = assignment_order[order_num];
-			int j = scarlett2_get_port_start_num(ports,
-							     SCARLETT2_PORT_OUT,
-							     port_type);
-			int port_id = ports[port_type].id;
-			int channel;
-
-			for (channel = 0;
-			     channel < ports[port_type].num[port_dir_rate];
-			     channel++, i++, j++)
-				/* lower 12 bits for the destination and
-				 * next 12 bits for the source
-				 */
-				req.data[i] = !port_id
-					? 0
-					: cpu_to_le32(
-						port_id |
-						channel |
-						scarlett2_mux_src_num_to_id(
-							ports, private->mux[j]
-						) << 12
-					  );
+	/* set mux settings for each rate */
+	for (table = 0; table < SCARLETT2_MUX_TABLES; table++) {
+		const struct scarlett2_mux_entry *entry;
+
+		/* i counts over the output array */
+		int i = 0, err;
+
+		req.num = cpu_to_le16(table);
+
+		/* loop through each entry */
+		for (entry = info->mux_assignment[table];
+		     entry->count;
+		     entry++) {
+			int j;
+			int port_type = entry->port_type;
+			int port_idx = entry->start;
+			int mux_idx = scarlett2_get_port_start_num(ports,
+				SCARLETT2_PORT_OUT, port_type) + port_idx;
+			int dst_id = ports[port_type].id + port_idx;
+
+			/* Empty slots */
+			if (!dst_id) {
+				for (j = 0; j < entry->count; j++)
+					req.data[i++] = 0;
+				continue;
+			}
+
+			/* Non-empty mux slots use the lower 12 bits
+			 * for the destination and next 12 bits for
+			 * the source
+			 */
+			for (j = 0; j < entry->count; j++) {
+				int src_id = scarlett2_mux_src_num_to_id(
+					ports, private->mux[mux_idx++]);
+				req.data[i++] = cpu_to_le32(dst_id |
+							    src_id << 12);
+				dst_id++;
+			}
 		}
 
 		err = scarlett2_usb(mixer, SCARLETT2_USB_SET_MUX,
@@ -2081,7 +2167,7 @@  static void scarlett2_count_mux_io(struct scarlett2_data *private)
 	     port_type < SCARLETT2_PORT_TYPE_COUNT;
 	     port_type++) {
 		srcs += ports[port_type].num[SCARLETT2_PORT_IN];
-		dsts += ports[port_type].num[SCARLETT2_PORT_OUT_44];
+		dsts += ports[port_type].num[SCARLETT2_PORT_OUT];
 	}
 
 	private->num_mux_srcs = srcs;