Commit 6522c364 authored by Geoffrey D. Bennett's avatar Geoffrey D. Bennett Committed by Takashi Iwai

ALSA: usb-audio: scarlett2: Allow arbitrary ordering of mux entries

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: default avatarGeoffrey D. Bennett <g@b4.vu>
Link: https://lore.kernel.org/r/08e8d784d78262cb57496d28ef1ad7b6213a90ab.1624294591.git.g@b4.vuSigned-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 0c88f9db
...@@ -184,14 +184,11 @@ enum { ...@@ -184,14 +184,11 @@ enum {
SCARLETT2_PORT_TYPE_COUNT = 6, 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 { enum {
SCARLETT2_PORT_IN = 0, SCARLETT2_PORT_IN = 0,
SCARLETT2_PORT_OUT = 1, SCARLETT2_PORT_OUT = 1,
SCARLETT2_PORT_OUT_44 = 2, SCARLETT2_PORT_DIRNS = 2,
SCARLETT2_PORT_OUT_88 = 3,
SCARLETT2_PORT_OUT_176 = 4,
SCARLETT2_PORT_DIRNS = 5,
}; };
/* Dim/Mute buttons on the 18i20 */ /* Dim/Mute buttons on the 18i20 */
...@@ -220,6 +217,24 @@ struct scarlett2_ports { ...@@ -220,6 +217,24 @@ struct scarlett2_ports {
const char * const dst_descr; 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 { struct scarlett2_device_info {
u32 usb_id; /* USB device identifier */ u32 usb_id; /* USB device identifier */
...@@ -241,6 +256,10 @@ struct scarlett2_device_info { ...@@ -241,6 +256,10 @@ struct scarlett2_device_info {
/* port count and type data */ /* port count and type data */
struct scarlett2_ports ports[SCARLETT2_PORT_TYPE_COUNT]; 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 { struct scarlett2_data {
...@@ -293,38 +312,61 @@ static const struct scarlett2_device_info s6i6_gen2_info = { ...@@ -293,38 +312,61 @@ static const struct scarlett2_device_info s6i6_gen2_info = {
.ports = { .ports = {
[SCARLETT2_PORT_TYPE_NONE] = { [SCARLETT2_PORT_TYPE_NONE] = {
.id = 0x000, .id = 0x000,
.num = { 1, 0, 8, 8, 8 }, .num = { 1, 0 },
.src_descr = "Off", .src_descr = "Off",
}, },
[SCARLETT2_PORT_TYPE_ANALOGUE] = { [SCARLETT2_PORT_TYPE_ANALOGUE] = {
.id = 0x080, .id = 0x080,
.num = { 4, 4, 4, 4, 4 }, .num = { 4, 4 },
.src_descr = "Analogue %d", .src_descr = "Analogue %d",
.src_num_offset = 1, .src_num_offset = 1,
.dst_descr = "Analogue Output %02d Playback" .dst_descr = "Analogue Output %02d Playback"
}, },
[SCARLETT2_PORT_TYPE_SPDIF] = { [SCARLETT2_PORT_TYPE_SPDIF] = {
.id = 0x180, .id = 0x180,
.num = { 2, 2, 2, 2, 2 }, .num = { 2, 2 },
.src_descr = "S/PDIF %d", .src_descr = "S/PDIF %d",
.src_num_offset = 1, .src_num_offset = 1,
.dst_descr = "S/PDIF Output %d Playback" .dst_descr = "S/PDIF Output %d Playback"
}, },
[SCARLETT2_PORT_TYPE_MIX] = { [SCARLETT2_PORT_TYPE_MIX] = {
.id = 0x300, .id = 0x300,
.num = { 10, 18, 18, 18, 18 }, .num = { 10, 18 },
.src_descr = "Mix %c", .src_descr = "Mix %c",
.src_num_offset = 65, .src_num_offset = 65,
.dst_descr = "Mixer Input %02d Capture" .dst_descr = "Mixer Input %02d Capture"
}, },
[SCARLETT2_PORT_TYPE_PCM] = { [SCARLETT2_PORT_TYPE_PCM] = {
.id = 0x600, .id = 0x600,
.num = { 6, 6, 6, 6, 6 }, .num = { 6, 6 },
.src_descr = "PCM %d", .src_descr = "PCM %d",
.src_num_offset = 1, .src_num_offset = 1,
.dst_descr = "PCM %02d Capture" .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 = { static const struct scarlett2_device_info s18i8_gen2_info = {
...@@ -345,44 +387,67 @@ static const struct scarlett2_device_info s18i8_gen2_info = { ...@@ -345,44 +387,67 @@ static const struct scarlett2_device_info s18i8_gen2_info = {
.ports = { .ports = {
[SCARLETT2_PORT_TYPE_NONE] = { [SCARLETT2_PORT_TYPE_NONE] = {
.id = 0x000, .id = 0x000,
.num = { 1, 0, 8, 8, 4 }, .num = { 1, 0 },
.src_descr = "Off", .src_descr = "Off",
}, },
[SCARLETT2_PORT_TYPE_ANALOGUE] = { [SCARLETT2_PORT_TYPE_ANALOGUE] = {
.id = 0x080, .id = 0x080,
.num = { 8, 6, 6, 6, 6 }, .num = { 8, 6 },
.src_descr = "Analogue %d", .src_descr = "Analogue %d",
.src_num_offset = 1, .src_num_offset = 1,
.dst_descr = "Analogue Output %02d Playback" .dst_descr = "Analogue Output %02d Playback"
}, },
[SCARLETT2_PORT_TYPE_SPDIF] = { [SCARLETT2_PORT_TYPE_SPDIF] = {
.id = 0x180, .id = 0x180,
.num = { 2, 2, 2, 2, 2 }, .num = { 2, 2 },
.src_descr = "S/PDIF %d", .src_descr = "S/PDIF %d",
.src_num_offset = 1, .src_num_offset = 1,
.dst_descr = "S/PDIF Output %d Playback" .dst_descr = "S/PDIF Output %d Playback"
}, },
[SCARLETT2_PORT_TYPE_ADAT] = { [SCARLETT2_PORT_TYPE_ADAT] = {
.id = 0x200, .id = 0x200,
.num = { 8, 0, 0, 0, 0 }, .num = { 8, 0 },
.src_descr = "ADAT %d", .src_descr = "ADAT %d",
.src_num_offset = 1, .src_num_offset = 1,
}, },
[SCARLETT2_PORT_TYPE_MIX] = { [SCARLETT2_PORT_TYPE_MIX] = {
.id = 0x300, .id = 0x300,
.num = { 10, 18, 18, 18, 18 }, .num = { 10, 18 },
.src_descr = "Mix %c", .src_descr = "Mix %c",
.src_num_offset = 65, .src_num_offset = 65,
.dst_descr = "Mixer Input %02d Capture" .dst_descr = "Mixer Input %02d Capture"
}, },
[SCARLETT2_PORT_TYPE_PCM] = { [SCARLETT2_PORT_TYPE_PCM] = {
.id = 0x600, .id = 0x600,
.num = { 8, 18, 18, 14, 10 }, .num = { 8, 18 },
.src_descr = "PCM %d", .src_descr = "PCM %d",
.src_num_offset = 1, .src_num_offset = 1,
.dst_descr = "PCM %02d Capture" .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 = { static const struct scarlett2_device_info s18i20_gen2_info = {
...@@ -406,12 +471,12 @@ static const struct scarlett2_device_info s18i20_gen2_info = { ...@@ -406,12 +471,12 @@ static const struct scarlett2_device_info s18i20_gen2_info = {
.ports = { .ports = {
[SCARLETT2_PORT_TYPE_NONE] = { [SCARLETT2_PORT_TYPE_NONE] = {
.id = 0x000, .id = 0x000,
.num = { 1, 0, 8, 8, 6 }, .num = { 1, 0 },
.src_descr = "Off", .src_descr = "Off",
}, },
[SCARLETT2_PORT_TYPE_ANALOGUE] = { [SCARLETT2_PORT_TYPE_ANALOGUE] = {
.id = 0x080, .id = 0x080,
.num = { 8, 10, 10, 10, 10 }, .num = { 8, 10 },
.src_descr = "Analogue %d", .src_descr = "Analogue %d",
.src_num_offset = 1, .src_num_offset = 1,
.dst_descr = "Analogue Output %02d Playback" .dst_descr = "Analogue Output %02d Playback"
...@@ -422,33 +487,58 @@ static const struct scarlett2_device_info s18i20_gen2_info = { ...@@ -422,33 +487,58 @@ static const struct scarlett2_device_info s18i20_gen2_info = {
* assignment message anyway * assignment message anyway
*/ */
.id = 0x180, .id = 0x180,
.num = { 2, 2, 2, 2, 2 }, .num = { 2, 2 },
.src_descr = "S/PDIF %d", .src_descr = "S/PDIF %d",
.src_num_offset = 1, .src_num_offset = 1,
.dst_descr = "S/PDIF Output %d Playback" .dst_descr = "S/PDIF Output %d Playback"
}, },
[SCARLETT2_PORT_TYPE_ADAT] = { [SCARLETT2_PORT_TYPE_ADAT] = {
.id = 0x200, .id = 0x200,
.num = { 8, 8, 8, 4, 0 }, .num = { 8, 8 },
.src_descr = "ADAT %d", .src_descr = "ADAT %d",
.src_num_offset = 1, .src_num_offset = 1,
.dst_descr = "ADAT Output %d Playback" .dst_descr = "ADAT Output %d Playback"
}, },
[SCARLETT2_PORT_TYPE_MIX] = { [SCARLETT2_PORT_TYPE_MIX] = {
.id = 0x300, .id = 0x300,
.num = { 10, 18, 18, 18, 18 }, .num = { 10, 18 },
.src_descr = "Mix %c", .src_descr = "Mix %c",
.src_num_offset = 65, .src_num_offset = 65,
.dst_descr = "Mixer Input %02d Capture" .dst_descr = "Mixer Input %02d Capture"
}, },
[SCARLETT2_PORT_TYPE_PCM] = { [SCARLETT2_PORT_TYPE_PCM] = {
.id = 0x600, .id = 0x600,
.num = { 20, 18, 18, 14, 10 }, .num = { 20, 18 },
.src_descr = "PCM %d", .src_descr = "PCM %d",
.src_num_offset = 1, .src_num_offset = 1,
.dst_descr = "PCM %02d Capture" .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[] = { static const struct scarlett2_device_info *scarlett2_devices[] = {
...@@ -1009,16 +1099,7 @@ static int scarlett2_usb_set_mux(struct usb_mixer_interface *mixer) ...@@ -1009,16 +1099,7 @@ static int scarlett2_usb_set_mux(struct usb_mixer_interface *mixer)
struct scarlett2_data *private = mixer->private_data; struct scarlett2_data *private = mixer->private_data;
const struct scarlett2_device_info *info = private->info; const struct scarlett2_device_info *info = private->info;
const struct scarlett2_ports *ports = info->ports; const struct scarlett2_ports *ports = info->ports;
int rate, port_dir_rate; int table;
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,
};
struct { struct {
__le16 pad; __le16 pad;
...@@ -1028,39 +1109,44 @@ static int scarlett2_usb_set_mux(struct usb_mixer_interface *mixer) ...@@ -1028,39 +1109,44 @@ static int scarlett2_usb_set_mux(struct usb_mixer_interface *mixer)
req.pad = 0; req.pad = 0;
/* mux settings for each rate */ /* set mux settings for each rate */
for (rate = 0, port_dir_rate = SCARLETT2_PORT_OUT_44; for (table = 0; table < SCARLETT2_MUX_TABLES; table++) {
port_dir_rate <= SCARLETT2_PORT_OUT_176; const struct scarlett2_mux_entry *entry;
rate++, port_dir_rate++) {
int order_num, i, err; /* i counts over the output array */
int i = 0, err;
req.num = cpu_to_le16(rate);
req.num = cpu_to_le16(table);
for (order_num = 0, i = 0;
order_num < SCARLETT2_PORT_TYPE_COUNT; /* loop through each entry */
order_num++) { for (entry = info->mux_assignment[table];
int port_type = assignment_order[order_num]; entry->count;
int j = scarlett2_get_port_start_num(ports, entry++) {
SCARLETT2_PORT_OUT, int j;
port_type); int port_type = entry->port_type;
int port_id = ports[port_type].id; int port_idx = entry->start;
int channel; int mux_idx = scarlett2_get_port_start_num(ports,
SCARLETT2_PORT_OUT, port_type) + port_idx;
for (channel = 0; int dst_id = ports[port_type].id + port_idx;
channel < ports[port_type].num[port_dir_rate];
channel++, i++, j++) /* Empty slots */
/* lower 12 bits for the destination and if (!dst_id) {
* next 12 bits for the source for (j = 0; j < entry->count; j++)
*/ req.data[i++] = 0;
req.data[i] = !port_id continue;
? 0 }
: cpu_to_le32(
port_id | /* Non-empty mux slots use the lower 12 bits
channel | * for the destination and next 12 bits for
scarlett2_mux_src_num_to_id( * the source
ports, private->mux[j] */
) << 12 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, err = scarlett2_usb(mixer, SCARLETT2_USB_SET_MUX,
...@@ -2081,7 +2167,7 @@ static void scarlett2_count_mux_io(struct scarlett2_data *private) ...@@ -2081,7 +2167,7 @@ static void scarlett2_count_mux_io(struct scarlett2_data *private)
port_type < SCARLETT2_PORT_TYPE_COUNT; port_type < SCARLETT2_PORT_TYPE_COUNT;
port_type++) { port_type++) {
srcs += ports[port_type].num[SCARLETT2_PORT_IN]; 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; private->num_mux_srcs = srcs;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment