On 06.06.21 16:17, Geoffrey D. Bennett wrote:
Add support for retrieving the mux configuration from the hardware when the driver is initialising. Previously the ALSA controls were initialised to a default hard-coded state instead of being initialised to match the hardware state.
Fixes: 9e4d5c1be21f ("ALSA: usb-audio: Scarlett Gen 2 mixer interface") Suggested-by: Vladimir Sadovnikov sadko4u@gmail.com Signed-off-by: Geoffrey D. Bennett g@b4.vu
Tested-by: Markus Schroetter project.m.schroetter@gmail.com
sound/usb/mixer_scarlett_gen2.c | 170 ++++++++++++++++++++------------ 1 file changed, 106 insertions(+), 64 deletions(-)
diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c index b0043906c77f..48cf3e1954e0 100644 --- a/sound/usb/mixer_scarlett_gen2.c +++ b/sound/usb/mixer_scarlett_gen2.c @@ -32,6 +32,10 @@
- Scarlett 6i6 support added in June 2019 (thanks to Martin Wittmann
- for providing usbmon output and testing).
- Support for loading mixer volume and mux configuration from the
- interface during driver initialisation added in May 2021 (thanks to
- Vladimir Sadovnikov for figuring out how).
- This ALSA mixer gives access to:
- input, output, mixer-matrix muxes
- 18x10 mixer-matrix gain stages
@@ -228,6 +232,7 @@ struct scarlett2_mixer_data { struct delayed_work work; const struct scarlett2_device_info *info; int num_mux_srcs;
- int num_mux_dsts; u16 scarlett2_seq; u8 vol_updated; u8 master_vol;
@@ -468,6 +473,7 @@ static int scarlett2_get_port_start_num(const struct scarlett2_ports *ports, #define SCARLETT2_USB_GET_METER_LEVELS 0x00001001 #define SCARLETT2_USB_GET_MIX 0x00002001 #define SCARLETT2_USB_SET_MIX 0x00002002 +#define SCARLETT2_USB_GET_MUX 0x00003001 #define SCARLETT2_USB_SET_MUX 0x00003002 #define SCARLETT2_USB_GET_DATA 0x00800000 #define SCARLETT2_USB_SET_DATA 0x00800001 @@ -877,6 +883,94 @@ static u32 scarlett2_mux_src_num_to_id(const struct scarlett2_ports *ports, return 0; }
+/* Convert a hardware ID to a port number index */ +static u32 scarlett2_mux_id_to_num(const struct scarlett2_ports *ports,
int direction,
u32 id)
+{
- int port_type;
- int port_num = 0;
- for (port_type = 0;
port_type < SCARLETT2_PORT_TYPE_COUNT;
port_type++) {
struct scarlett2_ports port = ports[port_type];
int count = port.num[direction];
if (id >= port.id && id < port.id + count)
return port_num + id - port.id;
port_num += count;
- }
- /* Oops */
- return -1;
+}
+/* Convert one mux entry from the interface and load into private->mux[] */ +static void scarlett2_usb_populate_mux(struct scarlett2_mixer_data *private,
u32 mux_entry)
+{
- const struct scarlett2_device_info *info = private->info;
- const struct scarlett2_ports *ports = info->ports;
- int dst_idx, src_idx;
- dst_idx = scarlett2_mux_id_to_num(ports, SCARLETT2_PORT_OUT,
mux_entry & 0xFFF);
- if (dst_idx < 0)
return;
- if (dst_idx >= private->num_mux_dsts) {
usb_audio_err(private->mixer->chip,
"BUG: scarlett2_mux_id_to_num(%06x, OUT): %d >= %d",
mux_entry, dst_idx, private->num_mux_dsts);
return;
- }
- src_idx = scarlett2_mux_id_to_num(ports, SCARLETT2_PORT_IN,
mux_entry >> 12);
- if (src_idx < 0)
return;
- if (src_idx >= private->num_mux_srcs) {
usb_audio_err(private->mixer->chip,
"BUG: scarlett2_mux_id_to_num(%06x, IN): %d >= %d",
mux_entry, src_idx, private->num_mux_srcs);
return;
- }
- private->mux[dst_idx] = src_idx;
+}
+/* Send USB message to get mux inputs and then populate private->mux[] */ +static int scarlett2_usb_get_mux(struct usb_mixer_interface *mixer) +{
- struct scarlett2_mixer_data *private = mixer->private_data;
- int count = private->num_mux_dsts;
- int err, i;
- struct {
__le16 num;
__le16 count;
- } __packed req;
- __le32 data[SCARLETT2_MUX_MAX];
- req.num = 0;
- req.count = cpu_to_le16(count);
- err = scarlett2_usb(mixer, SCARLETT2_USB_GET_MUX,
&req, sizeof(req),
data, count * sizeof(u32));
- if (err < 0)
return err;
- for (i = 0; i < count; i++)
scarlett2_usb_populate_mux(private, le32_to_cpu(data[i]));
- return 0;
+}
/* Send USB messages to set mux inputs */ static int scarlett2_usb_set_mux(struct usb_mixer_interface *mixer) { @@ -1783,72 +1877,23 @@ static void scarlett2_private_suspend(struct usb_mixer_interface *mixer)
/*** Initialisation ***/
-static int scarlett2_count_mux_srcs(const struct scarlett2_ports *ports) +static void scarlett2_count_mux_io(struct scarlett2_mixer_data *private) {
- int port_type, count = 0;
const struct scarlett2_ports *ports = private->info->ports;
int port_type, srcs = 0, dsts = 0;
for (port_type = 0; port_type < SCARLETT2_PORT_TYPE_COUNT;
port_type++)
count += ports[port_type].num[SCARLETT2_PORT_IN];
- return count;
-}
-/* Default routing connects PCM outputs and inputs to Analogue,
- S/PDIF, then ADAT
- */
-static void scarlett2_init_routing(u8 *mux,
const struct scarlett2_ports *ports)
-{
- int i, input_num, input_count, port_type;
- int output_num, output_count, port_type_connect_num;
- static const int connect_order[] = {
SCARLETT2_PORT_TYPE_ANALOGUE,
SCARLETT2_PORT_TYPE_SPDIF,
SCARLETT2_PORT_TYPE_ADAT,
-1
- };
- /* Assign PCM inputs (routing outputs) */
- output_num = scarlett2_get_port_start_num(ports,
SCARLETT2_PORT_OUT,
SCARLETT2_PORT_TYPE_PCM);
- output_count = ports[SCARLETT2_PORT_TYPE_PCM].num[SCARLETT2_PORT_OUT];
- for (port_type = connect_order[port_type_connect_num = 0];
port_type >= 0;
port_type = connect_order[++port_type_connect_num]) {
input_num = scarlett2_get_port_start_num(
ports, SCARLETT2_PORT_IN, port_type);
input_count = ports[port_type].num[SCARLETT2_PORT_IN];
for (i = 0;
i < input_count && output_count;
i++, output_count--)
mux[output_num++] = input_num++;
port_type++) {
srcs += ports[port_type].num[SCARLETT2_PORT_IN];
}dsts += ports[port_type].num[SCARLETT2_PORT_OUT_44];
- /* Assign PCM outputs (routing inputs) */
- input_num = scarlett2_get_port_start_num(ports,
SCARLETT2_PORT_IN,
SCARLETT2_PORT_TYPE_PCM);
- input_count = ports[SCARLETT2_PORT_TYPE_PCM].num[SCARLETT2_PORT_IN];
- for (port_type = connect_order[port_type_connect_num = 0];
port_type >= 0;
port_type = connect_order[++port_type_connect_num]) {
output_num = scarlett2_get_port_start_num(
ports, SCARLETT2_PORT_OUT, port_type);
output_count = ports[port_type].num[SCARLETT2_PORT_OUT];
for (i = 0;
i < output_count && input_count;
i++, input_count--)
mux[output_num++] = input_num++;
- }
- private->num_mux_srcs = srcs;
- private->num_mux_dsts = dsts;
}
-/* Initialise private data, routing, sequence number */ +/* Initialise private data and sequence number */ static int scarlett2_init_private(struct usb_mixer_interface *mixer, const struct scarlett2_device_info *info) { @@ -1862,16 +1907,13 @@ static int scarlett2_init_private(struct usb_mixer_interface *mixer, mutex_init(&private->data_mutex); INIT_DELAYED_WORK(&private->work, scarlett2_config_save_work); private->info = info;
- private->num_mux_srcs = scarlett2_count_mux_srcs(info->ports);
- scarlett2_count_mux_io(private); private->scarlett2_seq = 0; private->mixer = mixer; mixer->private_data = private; mixer->private_free = scarlett2_private_free; mixer->private_suspend = scarlett2_private_suspend;
- /* Setup default routing */
- scarlett2_init_routing(private->mux, info->ports);
- /* Initialise the sequence number used for the proprietary commands */ return scarlett2_usb(mixer, SCARLETT2_USB_INIT_SEQ, NULL, 0, NULL, 0);
} @@ -1947,7 +1989,7 @@ static int scarlett2_read_configs(struct usb_mixer_interface *mixer) return err; }
- return 0;
- return scarlett2_usb_get_mux(mixer);
}
/* Notify on volume change */ @@ -2055,7 +2097,7 @@ static int snd_scarlett_gen2_controls_create(struct usb_mixer_interface *mixer, { int err;
- /* Initialise private data, routing, sequence number */
- /* Initialise private data and sequence number */ err = scarlett2_init_private(mixer, info); if (err < 0) return err;