[PATCH 2/2] ALSA: usb-audio: scarlett2: Read mux at init time
Markus
project.m.schroetter at gmail.com
Sun Jun 6 16:33:14 CEST 2021
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 at gmail.com>
> Signed-off-by: Geoffrey D. Bennett <g at b4.vu>
Tested-by: Markus Schroetter <project.m.schroetter at 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;
More information about the Alsa-devel
mailing list