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

ALSA: usb-audio: scarlett2: Read mux at init time

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: 9e4d5c1b ("ALSA: usb-audio: Scarlett Gen 2 mixer interface")
Suggested-by: default avatarVladimir Sadovnikov <sadko4u@gmail.com>
Tested-by: default avatarMarkus Schroetter <project.m.schroetter@gmail.com>
Tested-by: default avatarAlex Fellows <alex.fellows@gmail.com>
Tested-by: default avatarDaniel Sales <daniel.sales.z@gmail.com>
Signed-off-by: default avatarGeoffrey D. Bennett <g@b4.vu>
Link: https://lore.kernel.org/r/15b17c60a2bca174bcddcec41c9419b746f21c1d.1623091570.git.g@b4.vuSigned-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 2661f033
...@@ -32,6 +32,10 @@ ...@@ -32,6 +32,10 @@
* Scarlett 6i6 support added in June 2019 (thanks to Martin Wittmann * Scarlett 6i6 support added in June 2019 (thanks to Martin Wittmann
* for providing usbmon output and testing). * 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: * This ALSA mixer gives access to:
* - input, output, mixer-matrix muxes * - input, output, mixer-matrix muxes
* - 18x10 mixer-matrix gain stages * - 18x10 mixer-matrix gain stages
...@@ -228,6 +232,7 @@ struct scarlett2_mixer_data { ...@@ -228,6 +232,7 @@ struct scarlett2_mixer_data {
struct delayed_work work; struct delayed_work work;
const struct scarlett2_device_info *info; const struct scarlett2_device_info *info;
int num_mux_srcs; int num_mux_srcs;
int num_mux_dsts;
u16 scarlett2_seq; u16 scarlett2_seq;
u8 vol_updated; u8 vol_updated;
u8 master_vol; u8 master_vol;
...@@ -468,6 +473,7 @@ static int scarlett2_get_port_start_num(const struct scarlett2_ports *ports, ...@@ -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_METER_LEVELS 0x00001001
#define SCARLETT2_USB_GET_MIX 0x00002001 #define SCARLETT2_USB_GET_MIX 0x00002001
#define SCARLETT2_USB_SET_MIX 0x00002002 #define SCARLETT2_USB_SET_MIX 0x00002002
#define SCARLETT2_USB_GET_MUX 0x00003001
#define SCARLETT2_USB_SET_MUX 0x00003002 #define SCARLETT2_USB_SET_MUX 0x00003002
#define SCARLETT2_USB_GET_DATA 0x00800000 #define SCARLETT2_USB_GET_DATA 0x00800000
#define SCARLETT2_USB_SET_DATA 0x00800001 #define SCARLETT2_USB_SET_DATA 0x00800001
...@@ -877,6 +883,94 @@ static u32 scarlett2_mux_src_num_to_id(const struct scarlett2_ports *ports, ...@@ -877,6 +883,94 @@ static u32 scarlett2_mux_src_num_to_id(const struct scarlett2_ports *ports,
return 0; 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 */ /* Send USB messages to set mux inputs */
static int scarlett2_usb_set_mux(struct usb_mixer_interface *mixer) 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) ...@@ -1783,72 +1877,23 @@ static void scarlett2_private_suspend(struct usb_mixer_interface *mixer)
/*** Initialisation ***/ /*** 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; for (port_type = 0;
port_type < SCARLETT2_PORT_TYPE_COUNT; port_type < SCARLETT2_PORT_TYPE_COUNT;
port_type++) port_type++) {
count += ports[port_type].num[SCARLETT2_PORT_IN]; srcs += ports[port_type].num[SCARLETT2_PORT_IN];
dsts += ports[port_type].num[SCARLETT2_PORT_OUT_44];
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++;
} }
/* Assign PCM outputs (routing inputs) */ private->num_mux_srcs = srcs;
input_num = scarlett2_get_port_start_num(ports, private->num_mux_dsts = dsts;
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++;
}
} }
/* Initialise private data, routing, sequence number */ /* Initialise private data and sequence number */
static int scarlett2_init_private(struct usb_mixer_interface *mixer, static int scarlett2_init_private(struct usb_mixer_interface *mixer,
const struct scarlett2_device_info *info) const struct scarlett2_device_info *info)
{ {
...@@ -1862,16 +1907,13 @@ static int scarlett2_init_private(struct usb_mixer_interface *mixer, ...@@ -1862,16 +1907,13 @@ static int scarlett2_init_private(struct usb_mixer_interface *mixer,
mutex_init(&private->data_mutex); mutex_init(&private->data_mutex);
INIT_DELAYED_WORK(&private->work, scarlett2_config_save_work); INIT_DELAYED_WORK(&private->work, scarlett2_config_save_work);
private->info = info; private->info = info;
private->num_mux_srcs = scarlett2_count_mux_srcs(info->ports); scarlett2_count_mux_io(private);
private->scarlett2_seq = 0; private->scarlett2_seq = 0;
private->mixer = mixer; private->mixer = mixer;
mixer->private_data = private; mixer->private_data = private;
mixer->private_free = scarlett2_private_free; mixer->private_free = scarlett2_private_free;
mixer->private_suspend = scarlett2_private_suspend; 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 */ /* Initialise the sequence number used for the proprietary commands */
return scarlett2_usb(mixer, SCARLETT2_USB_INIT_SEQ, NULL, 0, NULL, 0); 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) ...@@ -1947,7 +1989,7 @@ static int scarlett2_read_configs(struct usb_mixer_interface *mixer)
return err; return err;
} }
return 0; return scarlett2_usb_get_mux(mixer);
} }
/* Notify on volume change */ /* Notify on volume change */
...@@ -2055,7 +2097,7 @@ static int snd_scarlett_gen2_controls_create(struct usb_mixer_interface *mixer, ...@@ -2055,7 +2097,7 @@ static int snd_scarlett_gen2_controls_create(struct usb_mixer_interface *mixer,
{ {
int err; int err;
/* Initialise private data, routing, sequence number */ /* Initialise private data and sequence number */
err = scarlett2_init_private(mixer, info); err = scarlett2_init_private(mixer, info);
if (err < 0) if (err < 0)
return err; return err;
......
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