All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/31] Refactor Scarlett Gen 2 support and add Scarlett Gen 3 support
@ 2021-06-21 18:09 Geoffrey D. Bennett
  2021-06-21 18:09 ` [PATCH 01/31] ALSA: usb-audio: scarlett2: Add usb_tx/rx functions Geoffrey D. Bennett
                   ` (30 more replies)
  0 siblings, 31 replies; 43+ messages in thread
From: Geoffrey D. Bennett @ 2021-06-21 18:09 UTC (permalink / raw)
  To: alsa-devel, Takashi Iwai; +Cc: Hin-Tak Leung, Vladimir Sadovnikov

This patch set broadly:
- Refactors the Scarlett Gen 2 support to make the Gen 3 mixer support
  trivial to add
- Fixes a couple of minor issues with the Gen 2 support (low priority
  for stable; the issues were not reported by any user)
- Adds support for Gen 3 devices with and without a mixer
- Adds support for the major features new with the Gen 3 devices

Geoffrey D. Bennett (31):
  ALSA: usb-audio: scarlett2: Add usb_tx/rx functions
  ALSA: usb-audio: scarlett2: Update initialisation sequence
  ALSA: usb-audio: scarlett2: Fix 6i6 Gen 2 line out descriptions
  ALSA: usb-audio: scarlett2: Always enable interrupt polling
  ALSA: usb-audio: scarlett2: Add "Sync Status" control
  ALSA: usb-audio: scarlett2: Merge common line in capture strings
  ALSA: usb-audio: scarlett2: Reformat scarlett2_config_items[]
  ALSA: usb-audio: scarlett2: Improve device info lookup
  ALSA: usb-audio: scarlett2: Move info lookup out of init function
  ALSA: usb-audio: scarlett2: Remove repeated device info comments
  ALSA: usb-audio: scarlett2: Add scarlett2_vol_ctl_write() helper
  ALSA: usb-audio: scarlett2: Add mute support
  ALSA: usb-audio: scarlett2: Allow arbitrary ordering of mux entries
  ALSA: usb-audio: scarlett2: Split struct scarlett2_ports
  ALSA: usb-audio: scarlett2: Fix Level Meter control
  ALSA: usb-audio: scarlett2: Add Gen 3 mixer support
  ALSA: usb-audio: scarlett2: Add support for "input-other" notify
  ALSA: usb-audio: scarlett2: Add Gen 3 MSD mode switch
  ALSA: usb-audio: scarlett2: Move get config above set config
  ALSA: usb-audio: scarlett2: Allow bit-level access to config
  ALSA: usb-audio: scarlett2: Add support for Solo and 2i2 Gen 3
  ALSA: usb-audio: scarlett2: Add "air" switch support
  ALSA: usb-audio: scarlett2: Add phantom power switch support
  ALSA: usb-audio: scarlett2: Add direct monitor support
  ALSA: usb-audio: scarlett2: Label 18i8 Gen 3 line outputs correctly
  ALSA: usb-audio: scarlett2: Split up sw_hw_enum_ctl_put()
  ALSA: usb-audio: scarlett2: Add sw_hw_ctls and mux_ctls
  ALSA: usb-audio: scarlett2: Update mux controls to allow updates
  ALSA: usb-audio: scarlett2: Add speaker switching support
  ALSA: usb-audio: scarlett2: Update get_config to do endian conversion
  ALSA: usb-audio: scarlett2: Add support for the talkback feature

 sound/usb/mixer.c               |    2 +-
 sound/usb/mixer_quirks.c        |    6 +
 sound/usb/mixer_scarlett_gen2.c | 2725 +++++++++++++++++++++++++------
 3 files changed, 2239 insertions(+), 494 deletions(-)


base-commit: 6c0a2078134aba6a77291554035304df9e16b85c
-- 
2.31.1


^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH 01/31] ALSA: usb-audio: scarlett2: Add usb_tx/rx functions
  2021-06-21 18:09 [PATCH 00/31] Refactor Scarlett Gen 2 support and add Scarlett Gen 3 support Geoffrey D. Bennett
@ 2021-06-21 18:09 ` Geoffrey D. Bennett
  2021-06-21 18:09 ` [PATCH 02/31] ALSA: usb-audio: scarlett2: Update initialisation sequence Geoffrey D. Bennett
                   ` (29 subsequent siblings)
  30 siblings, 0 replies; 43+ messages in thread
From: Geoffrey D. Bennett @ 2021-06-21 18:09 UTC (permalink / raw)
  To: alsa-devel, Takashi Iwai; +Cc: Hin-Tak Leung, Vladimir Sadovnikov

Pull out snd_usb_ctl_msg() calls from scarlett2_usb() and put into
scarlett2_usb_tx() and scarlett2_usb_rx() functions.

Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
---
 sound/usb/mixer_scarlett_gen2.c | 44 +++++++++++++++++++--------------
 1 file changed, 26 insertions(+), 18 deletions(-)

diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c
index 2e1937b072ee..6b77582d8e3d 100644
--- a/sound/usb/mixer_scarlett_gen2.c
+++ b/sound/usb/mixer_scarlett_gen2.c
@@ -453,8 +453,8 @@ static int scarlett2_get_port_start_num(const struct scarlett2_ports *ports,
 #define SCARLETT2_USB_NOTIFY_MONITOR  0x00400000
 
 /* Commands for sending/receiving requests/responses */
-#define SCARLETT2_USB_VENDOR_SPECIFIC_CMD_REQ  2
-#define SCARLETT2_USB_VENDOR_SPECIFIC_CMD_RESP 3
+#define SCARLETT2_USB_CMD_REQ  2
+#define SCARLETT2_USB_CMD_RESP 3
 
 #define SCARLETT2_USB_INIT_SEQ  0x00000000
 #define SCARLETT2_USB_GET_METER 0x00001001
@@ -576,12 +576,31 @@ static void scarlett2_fill_request_header(struct scarlett2_data *private,
 	req->pad = 0;
 }
 
+static int scarlett2_usb_tx(struct usb_device *dev, int interface,
+			    void *buf, u16 size)
+{
+	return snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
+			SCARLETT2_USB_CMD_REQ,
+			USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
+			0, interface, buf, size);
+}
+
+static int scarlett2_usb_rx(struct usb_device *dev, int interface,
+			    u32 usb_req, void *buf, u16 size)
+{
+	return snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0),
+			usb_req,
+			USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+			0, interface, buf, size);
+}
+
 /* Send a proprietary format request to the Scarlett interface */
 static int scarlett2_usb(
 	struct usb_mixer_interface *mixer, u32 cmd,
 	void *req_data, u16 req_size, void *resp_data, u16 resp_size)
 {
 	struct scarlett2_data *private = mixer->private_data;
+	struct usb_device *dev = mixer->chip->dev;
 	u16 req_buf_size = sizeof(struct scarlett2_usb_packet) + req_size;
 	u16 resp_buf_size = sizeof(struct scarlett2_usb_packet) + resp_size;
 	struct scarlett2_usb_packet *req, *resp = NULL;
@@ -608,14 +627,8 @@ static int scarlett2_usb(
 	if (req_size)
 		memcpy(req->data, req_data, req_size);
 
-	err = snd_usb_ctl_msg(mixer->chip->dev,
-			usb_sndctrlpipe(mixer->chip->dev, 0),
-			SCARLETT2_USB_VENDOR_SPECIFIC_CMD_REQ,
-			USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-			0,
-			private->bInterfaceNumber,
-			req,
-			req_buf_size);
+	err = scarlett2_usb_tx(dev, private->bInterfaceNumber,
+			       req, req_buf_size);
 
 	if (err != req_buf_size) {
 		usb_audio_err(
@@ -628,14 +641,9 @@ static int scarlett2_usb(
 
 	/* send a second message to get the response */
 
-	err = snd_usb_ctl_msg(mixer->chip->dev,
-			usb_rcvctrlpipe(mixer->chip->dev, 0),
-			SCARLETT2_USB_VENDOR_SPECIFIC_CMD_RESP,
-			USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-			0,
-			private->bInterfaceNumber,
-			resp,
-			resp_buf_size);
+	err = scarlett2_usb_rx(dev, private->bInterfaceNumber,
+			       SCARLETT2_USB_CMD_RESP,
+			       resp, resp_buf_size);
 
 	/* validate the response */
 
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 02/31] ALSA: usb-audio: scarlett2: Update initialisation sequence
  2021-06-21 18:09 [PATCH 00/31] Refactor Scarlett Gen 2 support and add Scarlett Gen 3 support Geoffrey D. Bennett
  2021-06-21 18:09 ` [PATCH 01/31] ALSA: usb-audio: scarlett2: Add usb_tx/rx functions Geoffrey D. Bennett
@ 2021-06-21 18:09 ` Geoffrey D. Bennett
  2021-06-21 18:09 ` [PATCH 03/31] ALSA: usb-audio: scarlett2: Fix 6i6 Gen 2 line out descriptions Geoffrey D. Bennett
                   ` (28 subsequent siblings)
  30 siblings, 0 replies; 43+ messages in thread
From: Geoffrey D. Bennett @ 2021-06-21 18:09 UTC (permalink / raw)
  To: alsa-devel, Takashi Iwai; +Cc: Hin-Tak Leung, Vladimir Sadovnikov

The old initialisation code only works with Gen 2 devices. Replace it
with an initialisation sequence that works on both Gen 2 and Gen 3
devices.

Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
---
 sound/usb/mixer_scarlett_gen2.c | 56 ++++++++++++++++++++++++++-------
 1 file changed, 45 insertions(+), 11 deletions(-)

diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c
index 6b77582d8e3d..ed89e28548c8 100644
--- a/sound/usb/mixer_scarlett_gen2.c
+++ b/sound/usb/mixer_scarlett_gen2.c
@@ -453,10 +453,12 @@ static int scarlett2_get_port_start_num(const struct scarlett2_ports *ports,
 #define SCARLETT2_USB_NOTIFY_MONITOR  0x00400000
 
 /* Commands for sending/receiving requests/responses */
+#define SCARLETT2_USB_CMD_INIT 0
 #define SCARLETT2_USB_CMD_REQ  2
 #define SCARLETT2_USB_CMD_RESP 3
 
-#define SCARLETT2_USB_INIT_SEQ  0x00000000
+#define SCARLETT2_USB_INIT_1    0x00000000
+#define SCARLETT2_USB_INIT_2    0x00000002
 #define SCARLETT2_USB_GET_METER 0x00001001
 #define SCARLETT2_USB_GET_MIX   0x00002001
 #define SCARLETT2_USB_SET_MIX   0x00002002
@@ -650,14 +652,19 @@ static int scarlett2_usb(
 	if (err != resp_buf_size) {
 		usb_audio_err(
 			mixer->chip,
-			"Scarlett Gen 2 USB response result cmd %x was %d\n",
-			cmd, err);
+			"Scarlett Gen 2 USB response result cmd %x was %d "
+			"expected %d\n",
+			cmd, err, resp_buf_size);
 		err = -EINVAL;
 		goto unlock;
 	}
 
+	/* cmd/seq/size should match except when initialising
+	 * seq sent = 1, response = 0
+	 */
 	if (resp->cmd != req->cmd ||
-	    resp->seq != req->seq ||
+	    (resp->seq != req->seq &&
+		(le16_to_cpu(req->seq) != 1 || resp->seq != 0)) ||
 	    resp_size != le16_to_cpu(resp->size) ||
 	    resp->error ||
 	    resp->pad) {
@@ -675,7 +682,7 @@ static int scarlett2_usb(
 		goto unlock;
 	}
 
-	if (resp_size > 0)
+	if (resp_data && resp_size > 0)
 		memcpy(resp_data, resp->data, resp_size);
 
 unlock:
@@ -1924,13 +1931,12 @@ static int scarlett2_find_fc_interface(struct usb_device *dev,
 	return -EINVAL;
 }
 
-/* Initialise private data, sequence number, and get the USB data */
+/* Initialise private data */
 static int scarlett2_init_private(struct usb_mixer_interface *mixer,
 				  const struct scarlett2_device_info *info)
 {
 	struct scarlett2_data *private =
 		kzalloc(sizeof(struct scarlett2_data), GFP_KERNEL);
-	int err;
 
 	if (!private)
 		return -ENOMEM;
@@ -1948,12 +1954,35 @@ static int scarlett2_init_private(struct usb_mixer_interface *mixer,
 	private->scarlett2_seq = 0;
 	private->mixer = mixer;
 
-	err = scarlett2_find_fc_interface(mixer->chip->dev, private);
+	return scarlett2_find_fc_interface(mixer->chip->dev, private);
+}
+
+/* Cargo cult proprietary initialisation sequence */
+static int scarlett2_usb_init(struct usb_mixer_interface *mixer)
+{
+	struct usb_device *dev = mixer->chip->dev;
+	struct scarlett2_data *private = mixer->private_data;
+	u8 buf[24];
+	int err;
+
+	if (usb_pipe_type_check(dev, usb_sndctrlpipe(dev, 0)))
+		return -EINVAL;
+
+	/* step 0 */
+	err = scarlett2_usb_rx(dev, private->bInterfaceNumber,
+			       SCARLETT2_USB_CMD_INIT, buf, sizeof(buf));
 	if (err < 0)
 		return err;
 
-	/* Initialise the sequence number used for the proprietary commands */
-	return scarlett2_usb(mixer, SCARLETT2_USB_INIT_SEQ, NULL, 0, NULL, 0);
+	/* step 1 */
+	private->scarlett2_seq = 1;
+	err = scarlett2_usb(mixer, SCARLETT2_USB_INIT_1, NULL, 0, NULL, 0);
+	if (err < 0)
+		return err;
+
+	/* step 2 */
+	private->scarlett2_seq = 1;
+	return scarlett2_usb(mixer, SCARLETT2_USB_INIT_2, NULL, 0, NULL, 84);
 }
 
 /* Read configuration from the interface on start */
@@ -2128,11 +2157,16 @@ static int snd_scarlett_gen2_controls_create(struct usb_mixer_interface *mixer,
 {
 	int err;
 
-	/* Initialise private data, sequence number, and get the USB data */
+	/* Initialise private data */
 	err = scarlett2_init_private(mixer, info);
 	if (err < 0)
 		return err;
 
+	/* Send proprietary USB initialisation sequence */
+	err = scarlett2_usb_init(mixer);
+	if (err < 0)
+		return err;
+
 	/* Read volume levels and controls from the interface */
 	err = scarlett2_read_configs(mixer);
 	if (err < 0)
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 03/31] ALSA: usb-audio: scarlett2: Fix 6i6 Gen 2 line out descriptions
  2021-06-21 18:09 [PATCH 00/31] Refactor Scarlett Gen 2 support and add Scarlett Gen 3 support Geoffrey D. Bennett
  2021-06-21 18:09 ` [PATCH 01/31] ALSA: usb-audio: scarlett2: Add usb_tx/rx functions Geoffrey D. Bennett
  2021-06-21 18:09 ` [PATCH 02/31] ALSA: usb-audio: scarlett2: Update initialisation sequence Geoffrey D. Bennett
@ 2021-06-21 18:09 ` Geoffrey D. Bennett
  2021-06-21 18:09 ` [PATCH 04/31] ALSA: usb-audio: scarlett2: Always enable interrupt polling Geoffrey D. Bennett
                   ` (27 subsequent siblings)
  30 siblings, 0 replies; 43+ messages in thread
From: Geoffrey D. Bennett @ 2021-06-21 18:09 UTC (permalink / raw)
  To: alsa-devel, Takashi Iwai; +Cc: Hin-Tak Leung, Vladimir Sadovnikov

There are two headphone outputs, and they map to the four analogue
outputs.

Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
---
 sound/usb/mixer_scarlett_gen2.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c
index ed89e28548c8..0b1967d93486 100644
--- a/sound/usb/mixer_scarlett_gen2.c
+++ b/sound/usb/mixer_scarlett_gen2.c
@@ -263,10 +263,10 @@ static const struct scarlett2_device_info s6i6_gen2_info = {
 	.pad_input_count = 2,
 
 	.line_out_descrs = {
-		"Monitor L",
-		"Monitor R",
-		"Headphones L",
-		"Headphones R",
+		"Headphones 1 L",
+		"Headphones 1 R",
+		"Headphones 2 L",
+		"Headphones 2 R",
 	},
 
 	.ports = {
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 04/31] ALSA: usb-audio: scarlett2: Always enable interrupt polling
  2021-06-21 18:09 [PATCH 00/31] Refactor Scarlett Gen 2 support and add Scarlett Gen 3 support Geoffrey D. Bennett
                   ` (2 preceding siblings ...)
  2021-06-21 18:09 ` [PATCH 03/31] ALSA: usb-audio: scarlett2: Fix 6i6 Gen 2 line out descriptions Geoffrey D. Bennett
@ 2021-06-21 18:09 ` Geoffrey D. Bennett
  2021-06-21 18:09 ` [PATCH 05/31] ALSA: usb-audio: scarlett2: Add "Sync Status" control Geoffrey D. Bennett
                   ` (26 subsequent siblings)
  30 siblings, 0 replies; 43+ messages in thread
From: Geoffrey D. Bennett @ 2021-06-21 18:09 UTC (permalink / raw)
  To: alsa-devel, Takashi Iwai; +Cc: Hin-Tak Leung, Vladimir Sadovnikov

Always enable interrupt polling as every model has some sort of
status to report.

Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
---
 sound/usb/mixer_scarlett_gen2.c | 17 ++++++++++-------
 1 file changed, 10 insertions(+), 7 deletions(-)

diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c
index 0b1967d93486..620f1e814f0d 100644
--- a/sound/usb/mixer_scarlett_gen2.c
+++ b/sound/usb/mixer_scarlett_gen2.c
@@ -2059,11 +2059,16 @@ static void scarlett2_notify_monitor(
 	struct usb_mixer_interface *mixer)
 {
 	struct scarlett2_data *private = mixer->private_data;
-	const struct scarlett2_ports *ports = private->info->ports;
+	const struct scarlett2_device_info *info = private->info;
+	const struct scarlett2_ports *ports = info->ports;
 	int num_line_out =
 		ports[SCARLETT2_PORT_TYPE_ANALOGUE].num[SCARLETT2_PORT_OUT];
 	int i;
 
+	/* if line_out_hw_vol is 0, there are no controls to update */
+	if (!info->line_out_hw_vol)
+		return;
+
 	private->vol_updated = 1;
 
 	snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
@@ -2197,12 +2202,10 @@ static int snd_scarlett_gen2_controls_create(struct usb_mixer_interface *mixer,
 	if (err < 0)
 		return err;
 
-	/* Set up the interrupt polling if there are hardware buttons */
-	if (info->line_out_hw_vol) {
-		err = scarlett2_init_notify(mixer);
-		if (err < 0)
-			return err;
-	}
+	/* Set up the interrupt polling */
+	err = scarlett2_init_notify(mixer);
+	if (err < 0)
+		return err;
 
 	return 0;
 }
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 05/31] ALSA: usb-audio: scarlett2: Add "Sync Status" control
  2021-06-21 18:09 [PATCH 00/31] Refactor Scarlett Gen 2 support and add Scarlett Gen 3 support Geoffrey D. Bennett
                   ` (3 preceding siblings ...)
  2021-06-21 18:09 ` [PATCH 04/31] ALSA: usb-audio: scarlett2: Always enable interrupt polling Geoffrey D. Bennett
@ 2021-06-21 18:09 ` Geoffrey D. Bennett
  2021-06-21 18:09 ` [PATCH 06/31] ALSA: usb-audio: scarlett2: Merge common line in capture strings Geoffrey D. Bennett
                   ` (25 subsequent siblings)
  30 siblings, 0 replies; 43+ messages in thread
From: Geoffrey D. Bennett @ 2021-06-21 18:09 UTC (permalink / raw)
  To: alsa-devel, Takashi Iwai; +Cc: Hin-Tak Leung, Vladimir Sadovnikov

Add "Sync Status" control to display the sync locked/unlocked status.

Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
---
 sound/usb/mixer_scarlett_gen2.c | 101 +++++++++++++++++++++++++++++++-
 1 file changed, 100 insertions(+), 1 deletion(-)

diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c
index 620f1e814f0d..4c2ae81f94a8 100644
--- a/sound/usb/mixer_scarlett_gen2.c
+++ b/sound/usb/mixer_scarlett_gen2.c
@@ -237,13 +237,16 @@ struct scarlett2_data {
 	int num_mux_srcs;
 	int num_mux_dsts;
 	u16 scarlett2_seq;
+	u8 sync_updated;
 	u8 vol_updated;
+	u8 sync;
 	u8 master_vol;
 	u8 vol[SCARLETT2_ANALOGUE_MAX];
 	u8 vol_sw_hw_switch[SCARLETT2_ANALOGUE_MAX];
 	u8 level_switch[SCARLETT2_LEVEL_SWITCH_MAX];
 	u8 pad_switch[SCARLETT2_PAD_SWITCH_MAX];
 	u8 dim_mute[SCARLETT2_DIM_MUTE_COUNT];
+	struct snd_kcontrol *sync_ctl;
 	struct snd_kcontrol *master_vol_ctl;
 	struct snd_kcontrol *vol_ctls[SCARLETT2_ANALOGUE_MAX];
 	struct snd_kcontrol *dim_mute_ctls[SCARLETT2_DIM_MUTE_COUNT];
@@ -448,7 +451,8 @@ static int scarlett2_get_port_start_num(const struct scarlett2_ports *ports,
 
 /*** USB Interactions ***/
 
-/* Interrupt flags for dim/mute button and monitor changes */
+/* Notifications from the interface */
+#define SCARLETT2_USB_NOTIFY_SYNC     0x00000008
 #define SCARLETT2_USB_NOTIFY_DIM_MUTE 0x00200000
 #define SCARLETT2_USB_NOTIFY_MONITOR  0x00400000
 
@@ -464,6 +468,7 @@ static int scarlett2_get_port_start_num(const struct scarlett2_ports *ports,
 #define SCARLETT2_USB_SET_MIX   0x00002002
 #define SCARLETT2_USB_GET_MUX   0x00003001
 #define SCARLETT2_USB_SET_MUX   0x00003002
+#define SCARLETT2_USB_GET_SYNC  0x00006004
 #define SCARLETT2_USB_GET_DATA  0x00800000
 #define SCARLETT2_USB_SET_DATA  0x00800001
 #define SCARLETT2_USB_DATA_CMD  0x00800002
@@ -784,6 +789,23 @@ static int scarlett2_usb_get_config(
 	return scarlett2_usb_get(mixer, config_item->offset, buf, size);
 }
 
+/* Send a USB message to get sync status; result placed in *sync */
+static int scarlett2_usb_get_sync_status(
+	struct usb_mixer_interface *mixer,
+	u8 *sync)
+{
+	__le32 data;
+	int err;
+
+	err = scarlett2_usb(mixer, SCARLETT2_USB_GET_SYNC,
+			    NULL, 0, &data, sizeof(data));
+	if (err < 0)
+		return err;
+
+	*sync = !!data;
+	return 0;
+}
+
 /* Send a USB message to get volume status; result placed in *buf */
 static int scarlett2_usb_get_volume_status(
 	struct usb_mixer_interface *mixer,
@@ -1109,6 +1131,60 @@ static int scarlett2_add_new_ctl(struct usb_mixer_interface *mixer,
 	return 0;
 }
 
+/*** Sync Control ***/
+
+/* Update sync control after receiving notification that the status
+ * has changed
+ */
+static int scarlett2_update_sync(struct usb_mixer_interface *mixer)
+{
+	struct scarlett2_data *private = mixer->private_data;
+
+	private->sync_updated = 0;
+	return scarlett2_usb_get_sync_status(mixer, &private->sync);
+}
+
+static int scarlett2_sync_ctl_info(struct snd_kcontrol *kctl,
+				   struct snd_ctl_elem_info *uinfo)
+{
+	static const char *texts[2] = {
+		"Unlocked", "Locked"
+	};
+	return snd_ctl_enum_info(uinfo, 1, 2, texts);
+}
+
+static int scarlett2_sync_ctl_get(struct snd_kcontrol *kctl,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct usb_mixer_elem_info *elem = kctl->private_data;
+	struct usb_mixer_interface *mixer = elem->head.mixer;
+	struct scarlett2_data *private = mixer->private_data;
+
+	mutex_lock(&private->data_mutex);
+	if (private->sync_updated)
+		scarlett2_update_sync(mixer);
+	ucontrol->value.enumerated.item[0] = private->sync;
+	mutex_unlock(&private->data_mutex);
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new scarlett2_sync_ctl = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.access = SNDRV_CTL_ELEM_ACCESS_READ,
+	.name = "",
+	.info = scarlett2_sync_ctl_info,
+	.get  = scarlett2_sync_ctl_get
+};
+
+static int scarlett2_add_sync_ctl(struct usb_mixer_interface *mixer)
+{
+	struct scarlett2_data *private = mixer->private_data;
+
+	return scarlett2_add_new_ctl(mixer, &scarlett2_sync_ctl,
+				     0, 1, "Sync Status", &private->sync_ctl);
+}
+
 /*** Analogue Line Out Volume Controls ***/
 
 /* Update hardware volume controls after receiving notification that
@@ -2018,6 +2094,10 @@ static int scarlett2_read_configs(struct usb_mixer_interface *mixer)
 			return err;
 	}
 
+	err = scarlett2_update_sync(mixer);
+	if (err < 0)
+		return err;
+
 	err = scarlett2_usb_get_volume_status(mixer, &volume_status);
 	if (err < 0)
 		return err;
@@ -2054,6 +2134,18 @@ static int scarlett2_read_configs(struct usb_mixer_interface *mixer)
 	return scarlett2_usb_get_mux(mixer);
 }
 
+/* Notify on sync change */
+static void scarlett2_notify_sync(
+	struct usb_mixer_interface *mixer)
+{
+	struct scarlett2_data *private = mixer->private_data;
+
+	private->sync_updated = 1;
+
+	snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
+		       &private->sync_ctl->id);
+}
+
 /* Notify on monitor change */
 static void scarlett2_notify_monitor(
 	struct usb_mixer_interface *mixer)
@@ -2112,6 +2204,8 @@ static void scarlett2_notify(struct urb *urb)
 		goto requeue;
 
 	data = le32_to_cpu(*(__le32 *)urb->transfer_buffer);
+	if (data & SCARLETT2_USB_NOTIFY_SYNC)
+		scarlett2_notify_sync(mixer);
 	if (data & SCARLETT2_USB_NOTIFY_MONITOR)
 		scarlett2_notify_monitor(mixer);
 	if (data & SCARLETT2_USB_NOTIFY_DIM_MUTE)
@@ -2202,6 +2296,11 @@ static int snd_scarlett_gen2_controls_create(struct usb_mixer_interface *mixer,
 	if (err < 0)
 		return err;
 
+	/* Create the sync control */
+	err = scarlett2_add_sync_ctl(mixer);
+	if (err < 0)
+		return err;
+
 	/* Set up the interrupt polling */
 	err = scarlett2_init_notify(mixer);
 	if (err < 0)
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 06/31] ALSA: usb-audio: scarlett2: Merge common line in capture strings
  2021-06-21 18:09 [PATCH 00/31] Refactor Scarlett Gen 2 support and add Scarlett Gen 3 support Geoffrey D. Bennett
                   ` (4 preceding siblings ...)
  2021-06-21 18:09 ` [PATCH 05/31] ALSA: usb-audio: scarlett2: Add "Sync Status" control Geoffrey D. Bennett
@ 2021-06-21 18:09 ` Geoffrey D. Bennett
  2021-06-21 18:09 ` [PATCH 07/31] ALSA: usb-audio: scarlett2: Reformat scarlett2_config_items[] Geoffrey D. Bennett
                   ` (24 subsequent siblings)
  30 siblings, 0 replies; 43+ messages in thread
From: Geoffrey D. Bennett @ 2021-06-21 18:09 UTC (permalink / raw)
  To: alsa-devel, Takashi Iwai; +Cc: Hin-Tak Leung, Vladimir Sadovnikov

Use a common sprintf() format for the mixer element names generated in
scarlett2_add_line_in_ctls() in preparation for more of them.

Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
---
 sound/usb/mixer_scarlett_gen2.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c
index 4c2ae81f94a8..c401b7d56408 100644
--- a/sound/usb/mixer_scarlett_gen2.c
+++ b/sound/usb/mixer_scarlett_gen2.c
@@ -1660,10 +1660,11 @@ static int scarlett2_add_line_in_ctls(struct usb_mixer_interface *mixer)
 	const struct scarlett2_device_info *info = private->info;
 	int err, i;
 	char s[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+	const char *fmt = "Line In %d %s Capture %s";
 
 	/* Add input level (line/inst) controls */
 	for (i = 0; i < info->level_input_count; i++) {
-		snprintf(s, sizeof(s), "Line In %d Level Capture Enum", i + 1);
+		snprintf(s, sizeof(s), fmt, i + 1, "Level", "Enum");
 		err = scarlett2_add_new_ctl(mixer, &scarlett2_level_enum_ctl,
 					    i, 1, s, NULL);
 		if (err < 0)
@@ -1672,7 +1673,7 @@ static int scarlett2_add_line_in_ctls(struct usb_mixer_interface *mixer)
 
 	/* Add input pad controls */
 	for (i = 0; i < info->pad_input_count; i++) {
-		snprintf(s, sizeof(s), "Line In %d Pad Capture Switch", i + 1);
+		snprintf(s, sizeof(s), fmt, i + 1, "Pad", "Switch");
 		err = scarlett2_add_new_ctl(mixer, &scarlett2_pad_ctl,
 					    i, 1, s, NULL);
 		if (err < 0)
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 07/31] ALSA: usb-audio: scarlett2: Reformat scarlett2_config_items[]
  2021-06-21 18:09 [PATCH 00/31] Refactor Scarlett Gen 2 support and add Scarlett Gen 3 support Geoffrey D. Bennett
                   ` (5 preceding siblings ...)
  2021-06-21 18:09 ` [PATCH 06/31] ALSA: usb-audio: scarlett2: Merge common line in capture strings Geoffrey D. Bennett
@ 2021-06-21 18:09 ` Geoffrey D. Bennett
  2021-06-21 18:09 ` [PATCH 08/31] ALSA: usb-audio: scarlett2: Improve device info lookup Geoffrey D. Bennett
                   ` (23 subsequent siblings)
  30 siblings, 0 replies; 43+ messages in thread
From: Geoffrey D. Bennett @ 2021-06-21 18:09 UTC (permalink / raw)
  To: alsa-devel, Takashi Iwai; +Cc: Hin-Tak Leung, Vladimir Sadovnikov

Use designated initializers and merge lines in preparation for more
configuration items coming soon.

Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
---
 sound/usb/mixer_scarlett_gen2.c | 40 +++++++++------------------------
 1 file changed, 10 insertions(+), 30 deletions(-)

diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c
index c401b7d56408..4a36181e61ab 100644
--- a/sound/usb/mixer_scarlett_gen2.c
+++ b/sound/usb/mixer_scarlett_gen2.c
@@ -523,40 +523,20 @@ struct scarlett2_config {
 
 static const struct scarlett2_config
 		scarlett2_config_items[SCARLETT2_CONFIG_COUNT] = {
-	/* Dim/Mute Buttons */
-	{
-		.offset = 0x31,
-		.size = 1,
-		.activate = 2
-	},
+	[SCARLETT2_CONFIG_DIM_MUTE] = {
+		.offset = 0x31, .size = 1, .activate = 2 },
 
-	/* Line Out Volume */
-	{
-		.offset = 0x34,
-		.size = 2,
-		.activate = 1
-	},
+	[SCARLETT2_CONFIG_LINE_OUT_VOLUME] = {
+		.offset = 0x34, .size = 2, .activate = 1 },
 
-	/* SW/HW Volume Switch */
-	{
-		.offset = 0x66,
-		.size = 1,
-		.activate = 3
-	},
+	[SCARLETT2_CONFIG_SW_HW_SWITCH] = {
+		.offset = 0x66, .size = 1, .activate = 3 },
 
-	/* Level Switch */
-	{
-		.offset = 0x7c,
-		.size = 1,
-		.activate = 7
-	},
+	[SCARLETT2_CONFIG_LEVEL_SWITCH] = {
+		.offset = 0x7c, .size = 1, .activate = 7 },
 
-	/* Pad Switch */
-	{
-		.offset = 0x84,
-		.size = 1,
-		.activate = 8
-	}
+	[SCARLETT2_CONFIG_PAD_SWITCH] = {
+		.offset = 0x84, .size = 1, .activate = 8 },
 };
 
 /* proprietary request/response format */
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 08/31] ALSA: usb-audio: scarlett2: Improve device info lookup
  2021-06-21 18:09 [PATCH 00/31] Refactor Scarlett Gen 2 support and add Scarlett Gen 3 support Geoffrey D. Bennett
                   ` (6 preceding siblings ...)
  2021-06-21 18:09 ` [PATCH 07/31] ALSA: usb-audio: scarlett2: Reformat scarlett2_config_items[] Geoffrey D. Bennett
@ 2021-06-21 18:09 ` Geoffrey D. Bennett
  2021-06-21 18:09 ` [PATCH 09/31] ALSA: usb-audio: scarlett2: Move info lookup out of init function Geoffrey D. Bennett
                   ` (22 subsequent siblings)
  30 siblings, 0 replies; 43+ messages in thread
From: Geoffrey D. Bennett @ 2021-06-21 18:09 UTC (permalink / raw)
  To: alsa-devel, Takashi Iwai; +Cc: Hin-Tak Leung, Vladimir Sadovnikov

Add the USB device ID to the scarlett2_device_info struct so that the
switch statement which finds the appropriate struct can be replaced
with a loop that looks through an array of pointers to those structs.

Suggested-by: Vladimir Sadovnikov <sadko4u@gmail.com>
Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
---
 sound/usb/mixer_scarlett_gen2.c | 37 ++++++++++++++++++++-------------
 1 file changed, 23 insertions(+), 14 deletions(-)

diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c
index 4a36181e61ab..481ebdd1a0df 100644
--- a/sound/usb/mixer_scarlett_gen2.c
+++ b/sound/usb/mixer_scarlett_gen2.c
@@ -217,6 +217,7 @@ struct scarlett2_ports {
 };
 
 struct scarlett2_device_info {
+	u32 usb_id; /* USB device identifier */
 	u8 line_out_hw_vol; /* line out hw volume is sw controlled */
 	u8 level_input_count; /* inputs with level selectable */
 	u8 pad_input_count; /* inputs with pad selectable */
@@ -257,6 +258,8 @@ struct scarlett2_data {
 /*** Model-specific data ***/
 
 static const struct scarlett2_device_info s6i6_gen2_info = {
+	.usb_id = USB_ID(0x1235, 0x8203),
+
 	/* The first two analogue inputs can be switched between line
 	 * and instrument levels.
 	 */
@@ -310,6 +313,8 @@ static const struct scarlett2_device_info s6i6_gen2_info = {
 };
 
 static const struct scarlett2_device_info s18i8_gen2_info = {
+	.usb_id = USB_ID(0x1235, 0x8204),
+
 	/* The first two analogue inputs can be switched between line
 	 * and instrument levels.
 	 */
@@ -371,6 +376,8 @@ static const struct scarlett2_device_info s18i8_gen2_info = {
 };
 
 static const struct scarlett2_device_info s18i20_gen2_info = {
+	.usb_id = USB_ID(0x1235, 0x8201),
+
 	/* The analogue line outputs on the 18i20 can be switched
 	 * between software and hardware volume control
 	 */
@@ -437,6 +444,16 @@ static const struct scarlett2_device_info s18i20_gen2_info = {
 	},
 };
 
+static const struct scarlett2_device_info *scarlett2_devices[] = {
+	/* Supported Gen 2 devices */
+	&s6i6_gen2_info,
+	&s18i8_gen2_info,
+	&s18i20_gen2_info,
+
+	/* End of list */
+	NULL
+};
+
 /* get the starting port index number for a given port type/direction */
 static int scarlett2_get_port_start_num(const struct scarlett2_ports *ports,
 					int direction, int port_type)
@@ -2293,26 +2310,18 @@ static int snd_scarlett_gen2_controls_create(struct usb_mixer_interface *mixer,
 int snd_scarlett_gen2_init(struct usb_mixer_interface *mixer)
 {
 	struct snd_usb_audio *chip = mixer->chip;
-	const struct scarlett2_device_info *info;
+	const struct scarlett2_device_info **info = scarlett2_devices;
 	int err;
 
 	/* only use UAC_VERSION_2 */
 	if (!mixer->protocol)
 		return 0;
 
-	switch (chip->usb_id) {
-	case USB_ID(0x1235, 0x8203):
-		info = &s6i6_gen2_info;
-		break;
-	case USB_ID(0x1235, 0x8204):
-		info = &s18i8_gen2_info;
-		break;
-	case USB_ID(0x1235, 0x8201):
-		info = &s18i20_gen2_info;
-		break;
-	default: /* device not (yet) supported */
+	/* find device in scarlett2_devices */
+	while (*info && (*info)->usb_id != chip->usb_id)
+		info++;
+	if (!*info)
 		return -EINVAL;
-	}
 
 	if (!(chip->setup & SCARLETT2_ENABLE)) {
 		usb_audio_info(chip,
@@ -2329,7 +2338,7 @@ int snd_scarlett_gen2_init(struct usb_mixer_interface *mixer)
 		"Focusrite Scarlett Gen 2 Mixer Driver enabled pid=0x%04x",
 		USB_ID_PRODUCT(chip->usb_id));
 
-	err = snd_scarlett_gen2_controls_create(mixer, info);
+	err = snd_scarlett_gen2_controls_create(mixer, *info);
 	if (err < 0)
 		usb_audio_err(mixer->chip,
 			      "Error initialising Scarlett Mixer Driver: %d",
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 09/31] ALSA: usb-audio: scarlett2: Move info lookup out of init function
  2021-06-21 18:09 [PATCH 00/31] Refactor Scarlett Gen 2 support and add Scarlett Gen 3 support Geoffrey D. Bennett
                   ` (7 preceding siblings ...)
  2021-06-21 18:09 ` [PATCH 08/31] ALSA: usb-audio: scarlett2: Improve device info lookup Geoffrey D. Bennett
@ 2021-06-21 18:09 ` Geoffrey D. Bennett
  2021-06-21 18:09 ` [PATCH 10/31] ALSA: usb-audio: scarlett2: Remove repeated device info comments Geoffrey D. Bennett
                   ` (21 subsequent siblings)
  30 siblings, 0 replies; 43+ messages in thread
From: Geoffrey D. Bennett @ 2021-06-21 18:09 UTC (permalink / raw)
  To: alsa-devel, Takashi Iwai; +Cc: Hin-Tak Leung, Vladimir Sadovnikov

The info variable is not used by snd_scarlett_gen2_init() except to
pass it to snd_scarlett_gen2_controls_create(), so move the lookup
into that function.

Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
---
 sound/usb/mixer_scarlett_gen2.c | 21 ++++++++++-----------
 1 file changed, 10 insertions(+), 11 deletions(-)

diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c
index 481ebdd1a0df..5cc4296944f5 100644
--- a/sound/usb/mixer_scarlett_gen2.c
+++ b/sound/usb/mixer_scarlett_gen2.c
@@ -2249,13 +2249,19 @@ static int scarlett2_init_notify(struct usb_mixer_interface *mixer)
 	return usb_submit_urb(mixer->urb, GFP_KERNEL);
 }
 
-static int snd_scarlett_gen2_controls_create(struct usb_mixer_interface *mixer,
-					     const struct scarlett2_device_info *info)
+static int snd_scarlett_gen2_controls_create(struct usb_mixer_interface *mixer)
 {
+	const struct scarlett2_device_info **info = scarlett2_devices;
 	int err;
 
+	/* Find device in scarlett2_devices */
+	while (*info && (*info)->usb_id != mixer->chip->usb_id)
+		info++;
+	if (!*info)
+		return -EINVAL;
+
 	/* Initialise private data */
-	err = scarlett2_init_private(mixer, info);
+	err = scarlett2_init_private(mixer, *info);
 	if (err < 0)
 		return err;
 
@@ -2310,19 +2316,12 @@ static int snd_scarlett_gen2_controls_create(struct usb_mixer_interface *mixer,
 int snd_scarlett_gen2_init(struct usb_mixer_interface *mixer)
 {
 	struct snd_usb_audio *chip = mixer->chip;
-	const struct scarlett2_device_info **info = scarlett2_devices;
 	int err;
 
 	/* only use UAC_VERSION_2 */
 	if (!mixer->protocol)
 		return 0;
 
-	/* find device in scarlett2_devices */
-	while (*info && (*info)->usb_id != chip->usb_id)
-		info++;
-	if (!*info)
-		return -EINVAL;
-
 	if (!(chip->setup & SCARLETT2_ENABLE)) {
 		usb_audio_info(chip,
 			"Focusrite Scarlett Gen 2 Mixer Driver disabled; "
@@ -2338,7 +2337,7 @@ int snd_scarlett_gen2_init(struct usb_mixer_interface *mixer)
 		"Focusrite Scarlett Gen 2 Mixer Driver enabled pid=0x%04x",
 		USB_ID_PRODUCT(chip->usb_id));
 
-	err = snd_scarlett_gen2_controls_create(mixer, *info);
+	err = snd_scarlett_gen2_controls_create(mixer);
 	if (err < 0)
 		usb_audio_err(mixer->chip,
 			      "Error initialising Scarlett Mixer Driver: %d",
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 10/31] ALSA: usb-audio: scarlett2: Remove repeated device info comments
  2021-06-21 18:09 [PATCH 00/31] Refactor Scarlett Gen 2 support and add Scarlett Gen 3 support Geoffrey D. Bennett
                   ` (8 preceding siblings ...)
  2021-06-21 18:09 ` [PATCH 09/31] ALSA: usb-audio: scarlett2: Move info lookup out of init function Geoffrey D. Bennett
@ 2021-06-21 18:09 ` Geoffrey D. Bennett
  2021-06-21 18:09 ` [PATCH 11/31] ALSA: usb-audio: scarlett2: Add scarlett2_vol_ctl_write() helper Geoffrey D. Bennett
                   ` (20 subsequent siblings)
  30 siblings, 0 replies; 43+ messages in thread
From: Geoffrey D. Bennett @ 2021-06-21 18:09 UTC (permalink / raw)
  To: alsa-devel, Takashi Iwai; +Cc: Hin-Tak Leung, Vladimir Sadovnikov

Document the fields of struct scarlett2_device_info in the definition
of the struct, not in each instantiation.

Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
---
 sound/usb/mixer_scarlett_gen2.c | 33 +++++++++++++++++----------------
 1 file changed, 17 insertions(+), 16 deletions(-)

diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c
index 5cc4296944f5..ded99baa92de 100644
--- a/sound/usb/mixer_scarlett_gen2.c
+++ b/sound/usb/mixer_scarlett_gen2.c
@@ -218,10 +218,24 @@ struct scarlett2_ports {
 
 struct scarlett2_device_info {
 	u32 usb_id; /* USB device identifier */
-	u8 line_out_hw_vol; /* line out hw volume is sw controlled */
-	u8 level_input_count; /* inputs with level selectable */
-	u8 pad_input_count; /* inputs with pad selectable */
+
+	/* line out hw volume is sw controlled */
+	u8 line_out_hw_vol;
+
+	/* the number of analogue inputs with a software switchable
+	 * level control that can be set to line or instrument
+	 */
+	u8 level_input_count;
+
+	/* the number of analogue inputs with a software switchable
+	 * 10dB pad control
+	 */
+	u8 pad_input_count;
+
+	/* additional description for the line out volume controls */
 	const char * const line_out_descrs[SCARLETT2_ANALOGUE_MAX];
+
+	/* port count and type data */
 	struct scarlett2_ports ports[SCARLETT2_PORT_TYPE_COUNT];
 };
 
@@ -260,12 +274,7 @@ struct scarlett2_data {
 static const struct scarlett2_device_info s6i6_gen2_info = {
 	.usb_id = USB_ID(0x1235, 0x8203),
 
-	/* The first two analogue inputs can be switched between line
-	 * and instrument levels.
-	 */
 	.level_input_count = 2,
-
-	/* The first two analogue inputs have an optional pad. */
 	.pad_input_count = 2,
 
 	.line_out_descrs = {
@@ -315,12 +324,7 @@ static const struct scarlett2_device_info s6i6_gen2_info = {
 static const struct scarlett2_device_info s18i8_gen2_info = {
 	.usb_id = USB_ID(0x1235, 0x8204),
 
-	/* The first two analogue inputs can be switched between line
-	 * and instrument levels.
-	 */
 	.level_input_count = 2,
-
-	/* The first four analogue inputs have an optional pad. */
 	.pad_input_count = 4,
 
 	.line_out_descrs = {
@@ -378,9 +382,6 @@ static const struct scarlett2_device_info s18i8_gen2_info = {
 static const struct scarlett2_device_info s18i20_gen2_info = {
 	.usb_id = USB_ID(0x1235, 0x8201),
 
-	/* The analogue line outputs on the 18i20 can be switched
-	 * between software and hardware volume control
-	 */
 	.line_out_hw_vol = 1,
 
 	.line_out_descrs = {
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 11/31] ALSA: usb-audio: scarlett2: Add scarlett2_vol_ctl_write() helper
  2021-06-21 18:09 [PATCH 00/31] Refactor Scarlett Gen 2 support and add Scarlett Gen 3 support Geoffrey D. Bennett
                   ` (9 preceding siblings ...)
  2021-06-21 18:09 ` [PATCH 10/31] ALSA: usb-audio: scarlett2: Remove repeated device info comments Geoffrey D. Bennett
@ 2021-06-21 18:09 ` Geoffrey D. Bennett
  2021-06-21 18:09 ` [PATCH 12/31] ALSA: usb-audio: scarlett2: Add mute support Geoffrey D. Bennett
                   ` (19 subsequent siblings)
  30 siblings, 0 replies; 43+ messages in thread
From: Geoffrey D. Bennett @ 2021-06-21 18:09 UTC (permalink / raw)
  To: alsa-devel, Takashi Iwai; +Cc: Hin-Tak Leung, Vladimir Sadovnikov

Add helper function for setting the read/write status of a volume
control. This will simplify the upcoming mute control support.

Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
---
 sound/usb/mixer_scarlett_gen2.c | 32 ++++++++++++++++++++------------
 1 file changed, 20 insertions(+), 12 deletions(-)

diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c
index ded99baa92de..e156119a21e8 100644
--- a/sound/usb/mixer_scarlett_gen2.c
+++ b/sound/usb/mixer_scarlett_gen2.c
@@ -1344,6 +1344,24 @@ static int scarlett2_sw_hw_enum_ctl_get(struct snd_kcontrol *kctl,
 	return 0;
 }
 
+static void scarlett2_vol_ctl_set_writable(struct usb_mixer_interface *mixer,
+					   int index, int value)
+{
+	struct scarlett2_data *private = mixer->private_data;
+
+	/* Set/Clear write bit */
+	if (value)
+		private->vol_ctls[index]->vd[0].access |=
+			SNDRV_CTL_ELEM_ACCESS_WRITE;
+	else
+		private->vol_ctls[index]->vd[0].access &=
+			~SNDRV_CTL_ELEM_ACCESS_WRITE;
+
+	/* Notify of write bit change */
+	snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_INFO,
+		       &private->vol_ctls[index]->id);
+}
+
 static int scarlett2_sw_hw_enum_ctl_put(struct snd_kcontrol *kctl,
 					struct snd_ctl_elem_value *ucontrol)
 {
@@ -1367,12 +1385,7 @@ static int scarlett2_sw_hw_enum_ctl_put(struct snd_kcontrol *kctl,
 	/* Change access mode to RO (hardware controlled volume)
 	 * or RW (software controlled volume)
 	 */
-	if (val)
-		private->vol_ctls[index]->vd[0].access &=
-			~SNDRV_CTL_ELEM_ACCESS_WRITE;
-	else
-		private->vol_ctls[index]->vd[0].access |=
-			SNDRV_CTL_ELEM_ACCESS_WRITE;
+	scarlett2_vol_ctl_set_writable(mixer, index, !val);
 
 	/* Reset volume to master volume */
 	private->vol[index] = private->master_vol;
@@ -1384,10 +1397,6 @@ static int scarlett2_sw_hw_enum_ctl_put(struct snd_kcontrol *kctl,
 	if (err < 0)
 		goto unlock;
 
-	/* Notify of RO/RW change */
-	snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_INFO,
-		       &private->vol_ctls[index]->id);
-
 	/* Send SW/HW switch change to the device */
 	err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_SW_HW_SWITCH,
 				       index, val);
@@ -1620,8 +1629,7 @@ static int scarlett2_add_line_out_ctls(struct usb_mixer_interface *mixer)
 
 		/* Make the fader read-only if the SW/HW switch is set to HW */
 		if (private->vol_sw_hw_switch[i])
-			private->vol_ctls[i]->vd[0].access &=
-				~SNDRV_CTL_ELEM_ACCESS_WRITE;
+			scarlett2_vol_ctl_set_writable(mixer, i, 0);
 
 		/* SW/HW Switch */
 		if (info->line_out_hw_vol) {
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 12/31] ALSA: usb-audio: scarlett2: Add mute support
  2021-06-21 18:09 [PATCH 00/31] Refactor Scarlett Gen 2 support and add Scarlett Gen 3 support Geoffrey D. Bennett
                   ` (10 preceding siblings ...)
  2021-06-21 18:09 ` [PATCH 11/31] ALSA: usb-audio: scarlett2: Add scarlett2_vol_ctl_write() helper Geoffrey D. Bennett
@ 2021-06-21 18:09 ` Geoffrey D. Bennett
  2021-06-21 18:09 ` [PATCH 13/31] ALSA: usb-audio: scarlett2: Allow arbitrary ordering of mux entries Geoffrey D. Bennett
                   ` (18 subsequent siblings)
  30 siblings, 0 replies; 43+ messages in thread
From: Geoffrey D. Bennett @ 2021-06-21 18:09 UTC (permalink / raw)
  To: alsa-devel, Takashi Iwai; +Cc: Hin-Tak Leung, Vladimir Sadovnikov

For each analogue output, in addition to the output volume (gain)
control, the hardware also has a mute control. Add ALSA mute controls
for each analogue output.

If the device has the line_out_hw_vol feature, then the mute control
is disabled along with the output volume control when the switch is
set to HW.

Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
---
 sound/usb/mixer_scarlett_gen2.c | 170 +++++++++++++++++++++++++++-----
 1 file changed, 145 insertions(+), 25 deletions(-)

diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c
index e156119a21e8..d30f15d580b5 100644
--- a/sound/usb/mixer_scarlett_gen2.c
+++ b/sound/usb/mixer_scarlett_gen2.c
@@ -39,7 +39,7 @@
  * This ALSA mixer gives access to:
  *  - input, output, mixer-matrix muxes
  *  - 18x10 mixer-matrix gain stages
- *  - gain/volume controls
+ *  - gain/volume/mute controls
  *  - level meters
  *  - line/inst level and pad controls
  *
@@ -195,7 +195,11 @@ enum {
 };
 
 /* Dim/Mute buttons on the 18i20 */
-#define SCARLETT2_DIM_MUTE_COUNT 2
+enum {
+	SCARLETT2_BUTTON_MUTE    = 0,
+	SCARLETT2_BUTTON_DIM     = 1,
+	SCARLETT2_DIM_MUTE_COUNT = 2,
+};
 
 static const char *const scarlett2_dim_mute_names[SCARLETT2_DIM_MUTE_COUNT] = {
 	"Mute", "Dim"
@@ -258,12 +262,14 @@ struct scarlett2_data {
 	u8 master_vol;
 	u8 vol[SCARLETT2_ANALOGUE_MAX];
 	u8 vol_sw_hw_switch[SCARLETT2_ANALOGUE_MAX];
+	u8 mute_switch[SCARLETT2_ANALOGUE_MAX];
 	u8 level_switch[SCARLETT2_LEVEL_SWITCH_MAX];
 	u8 pad_switch[SCARLETT2_PAD_SWITCH_MAX];
 	u8 dim_mute[SCARLETT2_DIM_MUTE_COUNT];
 	struct snd_kcontrol *sync_ctl;
 	struct snd_kcontrol *master_vol_ctl;
 	struct snd_kcontrol *vol_ctls[SCARLETT2_ANALOGUE_MAX];
+	struct snd_kcontrol *mute_ctls[SCARLETT2_ANALOGUE_MAX];
 	struct snd_kcontrol *dim_mute_ctls[SCARLETT2_DIM_MUTE_COUNT];
 	u8 mux[SCARLETT2_MUX_MAX];
 	u8 mix[SCARLETT2_INPUT_MIX_MAX * SCARLETT2_OUTPUT_MIX_MAX];
@@ -509,7 +515,8 @@ struct scarlett2_usb_volume_status {
 	/* actual volume of output inc. dim (-18dB) */
 	s16 hw_vol[SCARLETT2_ANALOGUE_MAX];
 
-	u8 pad2[SCARLETT2_ANALOGUE_MAX];
+	/* internal mute buttons */
+	u8 mute_switch[SCARLETT2_ANALOGUE_MAX];
 
 	/* sw (0) or hw (1) controlled */
 	u8 sw_hw_switch[SCARLETT2_ANALOGUE_MAX];
@@ -524,10 +531,11 @@ struct scarlett2_usb_volume_status {
 enum {
 	SCARLETT2_CONFIG_DIM_MUTE = 0,
 	SCARLETT2_CONFIG_LINE_OUT_VOLUME = 1,
-	SCARLETT2_CONFIG_SW_HW_SWITCH = 2,
-	SCARLETT2_CONFIG_LEVEL_SWITCH = 3,
-	SCARLETT2_CONFIG_PAD_SWITCH = 4,
-	SCARLETT2_CONFIG_COUNT = 5
+	SCARLETT2_CONFIG_MUTE_SWITCH = 2,
+	SCARLETT2_CONFIG_SW_HW_SWITCH = 3,
+	SCARLETT2_CONFIG_LEVEL_SWITCH = 4,
+	SCARLETT2_CONFIG_PAD_SWITCH = 5,
+	SCARLETT2_CONFIG_COUNT = 6
 };
 
 /* Location, size, and activation command number for the configuration
@@ -547,6 +555,9 @@ static const struct scarlett2_config
 	[SCARLETT2_CONFIG_LINE_OUT_VOLUME] = {
 		.offset = 0x34, .size = 2, .activate = 1 },
 
+	[SCARLETT2_CONFIG_MUTE_SWITCH] = {
+		.offset = 0x5c, .size = 1, .activate = 1 },
+
 	[SCARLETT2_CONFIG_SW_HW_SWITCH] = {
 		.offset = 0x66, .size = 1, .activate = 3 },
 
@@ -1197,6 +1208,7 @@ static int scarlett2_update_volumes(struct usb_mixer_interface *mixer)
 	int num_line_out =
 		ports[SCARLETT2_PORT_TYPE_ANALOGUE].num[SCARLETT2_PORT_OUT];
 	int err, i;
+	int mute;
 
 	private->vol_updated = 0;
 
@@ -1208,15 +1220,18 @@ static int scarlett2_update_volumes(struct usb_mixer_interface *mixer)
 		volume_status.master_vol + SCARLETT2_VOLUME_BIAS,
 		0, SCARLETT2_VOLUME_BIAS);
 
-	for (i = 0; i < num_line_out; i++) {
-		if (private->vol_sw_hw_switch[i])
-			private->vol[i] = private->master_vol;
-	}
-
 	if (info->line_out_hw_vol)
 		for (i = 0; i < SCARLETT2_DIM_MUTE_COUNT; i++)
 			private->dim_mute[i] = !!volume_status.dim_mute[i];
 
+	mute = private->dim_mute[SCARLETT2_BUTTON_MUTE];
+
+	for (i = 0; i < num_line_out; i++)
+		if (private->vol_sw_hw_switch[i]) {
+			private->vol[i] = private->master_vol;
+			private->mute_switch[i] = mute;
+		}
+
 	return 0;
 }
 
@@ -1321,6 +1336,55 @@ static const struct snd_kcontrol_new scarlett2_line_out_volume_ctl = {
 	.tlv = { .p = db_scale_scarlett2_gain }
 };
 
+/*** Mute Switch Controls ***/
+
+static int scarlett2_mute_ctl_get(struct snd_kcontrol *kctl,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct usb_mixer_elem_info *elem = kctl->private_data;
+	struct scarlett2_data *private = elem->head.mixer->private_data;
+	int index = elem->control;
+
+	ucontrol->value.integer.value[0] = private->mute_switch[index];
+	return 0;
+}
+
+static int scarlett2_mute_ctl_put(struct snd_kcontrol *kctl,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct usb_mixer_elem_info *elem = kctl->private_data;
+	struct usb_mixer_interface *mixer = elem->head.mixer;
+	struct scarlett2_data *private = mixer->private_data;
+	int index = elem->control;
+	int oval, val, err = 0;
+
+	mutex_lock(&private->data_mutex);
+
+	oval = private->mute_switch[index];
+	val = !!ucontrol->value.integer.value[0];
+
+	if (oval == val)
+		goto unlock;
+
+	private->mute_switch[index] = val;
+
+	/* Send mute change to the device */
+	err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_MUTE_SWITCH,
+				       index, val);
+
+unlock:
+	mutex_unlock(&private->data_mutex);
+	return err;
+}
+
+static const struct snd_kcontrol_new scarlett2_mute_ctl = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "",
+	.info = snd_ctl_boolean_mono_info,
+	.get  = scarlett2_mute_ctl_get,
+	.put  = scarlett2_mute_ctl_put,
+};
+
 /*** HW/SW Volume Switch Controls ***/
 
 static int scarlett2_sw_hw_enum_ctl_info(struct snd_kcontrol *kctl,
@@ -1348,18 +1412,26 @@ static void scarlett2_vol_ctl_set_writable(struct usb_mixer_interface *mixer,
 					   int index, int value)
 {
 	struct scarlett2_data *private = mixer->private_data;
+	struct snd_card *card = mixer->chip->card;
 
-	/* Set/Clear write bit */
-	if (value)
+	/* Set/Clear write bits */
+	if (value) {
 		private->vol_ctls[index]->vd[0].access |=
 			SNDRV_CTL_ELEM_ACCESS_WRITE;
-	else
+		private->mute_ctls[index]->vd[0].access |=
+			SNDRV_CTL_ELEM_ACCESS_WRITE;
+	} else {
 		private->vol_ctls[index]->vd[0].access &=
 			~SNDRV_CTL_ELEM_ACCESS_WRITE;
+		private->mute_ctls[index]->vd[0].access &=
+			~SNDRV_CTL_ELEM_ACCESS_WRITE;
+	}
 
 	/* Notify of write bit change */
-	snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_INFO,
+	snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO,
 		       &private->vol_ctls[index]->id);
+	snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO,
+		       &private->mute_ctls[index]->id);
 }
 
 static int scarlett2_sw_hw_enum_ctl_put(struct snd_kcontrol *kctl,
@@ -1387,8 +1459,9 @@ static int scarlett2_sw_hw_enum_ctl_put(struct snd_kcontrol *kctl,
 	 */
 	scarlett2_vol_ctl_set_writable(mixer, index, !val);
 
-	/* Reset volume to master volume */
+	/* Reset volume/mute to master volume/mute */
 	private->vol[index] = private->master_vol;
+	private->mute_switch[index] = private->dim_mute[SCARLETT2_BUTTON_MUTE];
 
 	/* Set SW volume to current HW volume */
 	err = scarlett2_usb_set_config(
@@ -1397,6 +1470,13 @@ static int scarlett2_sw_hw_enum_ctl_put(struct snd_kcontrol *kctl,
 	if (err < 0)
 		goto unlock;
 
+	/* Set SW mute to current HW mute */
+	err = scarlett2_usb_set_config(
+		mixer, SCARLETT2_CONFIG_MUTE_SWITCH,
+		index, private->dim_mute[SCARLETT2_BUTTON_MUTE]);
+	if (err < 0)
+		goto unlock;
+
 	/* Send SW/HW switch change to the device */
 	err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_SW_HW_SWITCH,
 				       index, val);
@@ -1554,9 +1634,13 @@ static int scarlett2_dim_mute_ctl_put(struct snd_kcontrol *kctl,
 	struct usb_mixer_elem_info *elem = kctl->private_data;
 	struct usb_mixer_interface *mixer = elem->head.mixer;
 	struct scarlett2_data *private = mixer->private_data;
+	const struct scarlett2_device_info *info = private->info;
+	const struct scarlett2_ports *ports = info->ports;
+	int num_line_out =
+		ports[SCARLETT2_PORT_TYPE_ANALOGUE].num[SCARLETT2_PORT_OUT];
 
 	int index = elem->control;
-	int oval, val, err = 0;
+	int oval, val, err = 0, i;
 
 	mutex_lock(&private->data_mutex);
 
@@ -1574,6 +1658,15 @@ static int scarlett2_dim_mute_ctl_put(struct snd_kcontrol *kctl,
 	if (err == 0)
 		err = 1;
 
+	if (index == SCARLETT2_BUTTON_MUTE)
+		for (i = 0; i < num_line_out; i++)
+			if (private->vol_sw_hw_switch[i]) {
+				private->mute_switch[i] = val;
+				snd_ctl_notify(mixer->chip->card,
+					       SNDRV_CTL_EVENT_MASK_INFO,
+					       &private->mute_ctls[i]->id);
+			}
+
 unlock:
 	mutex_unlock(&private->data_mutex);
 	return err;
@@ -1627,7 +1720,20 @@ static int scarlett2_add_line_out_ctls(struct usb_mixer_interface *mixer)
 		if (err < 0)
 			return err;
 
-		/* Make the fader read-only if the SW/HW switch is set to HW */
+		/* Mute Switch */
+		snprintf(s, sizeof(s),
+			 "Line %02d Mute Playback Switch",
+			 i + 1);
+		err = scarlett2_add_new_ctl(mixer,
+					    &scarlett2_mute_ctl,
+					    i, 1, s,
+					    &private->mute_ctls[i]);
+		if (err < 0)
+			return err;
+
+		/* Make the fader and mute controls read-only if the
+		 * SW/HW switch is set to HW
+		 */
 		if (private->vol_sw_hw_switch[i])
 			scarlett2_vol_ctl_set_writable(mixer, i, 0);
 
@@ -2109,12 +2215,16 @@ static int scarlett2_read_configs(struct usb_mixer_interface *mixer)
 	if (err < 0)
 		return err;
 
+	if (info->line_out_hw_vol)
+		for (i = 0; i < SCARLETT2_DIM_MUTE_COUNT; i++)
+			private->dim_mute[i] = !!volume_status.dim_mute[i];
+
 	private->master_vol = clamp(
 		volume_status.master_vol + SCARLETT2_VOLUME_BIAS,
 		0, SCARLETT2_VOLUME_BIAS);
 
 	for (i = 0; i < num_line_out; i++) {
-		int volume;
+		int volume, mute;
 
 		private->vol_sw_hw_switch[i] =
 			info->line_out_hw_vol
@@ -2126,11 +2236,12 @@ static int scarlett2_read_configs(struct usb_mixer_interface *mixer)
 		volume = clamp(volume + SCARLETT2_VOLUME_BIAS,
 			       0, SCARLETT2_VOLUME_BIAS);
 		private->vol[i] = volume;
-	}
 
-	if (info->line_out_hw_vol)
-		for (i = 0; i < SCARLETT2_DIM_MUTE_COUNT; i++)
-			private->dim_mute[i] = !!volume_status.dim_mute[i];
+		mute = private->vol_sw_hw_switch[i]
+			 ? private->dim_mute[SCARLETT2_BUTTON_MUTE]
+			 : volume_status.mute_switch[i];
+		private->mute_switch[i] = mute;
+	}
 
 	for (i = 0; i < num_mixer_out; i++) {
 		err = scarlett2_usb_get_mix(mixer, i);
@@ -2185,8 +2296,12 @@ static void scarlett2_notify_monitor(
 static void scarlett2_notify_dim_mute(
 	struct usb_mixer_interface *mixer)
 {
+	struct snd_card *card = mixer->chip->card;
 	struct scarlett2_data *private = mixer->private_data;
 	const struct scarlett2_device_info *info = private->info;
+	const struct scarlett2_ports *ports = info->ports;
+	int num_line_out =
+		ports[SCARLETT2_PORT_TYPE_ANALOGUE].num[SCARLETT2_PORT_OUT];
 	int i;
 
 	private->vol_updated = 1;
@@ -2195,8 +2310,13 @@ static void scarlett2_notify_dim_mute(
 		return;
 
 	for (i = 0; i < SCARLETT2_DIM_MUTE_COUNT; i++)
-		snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
+		snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
 			       &private->dim_mute_ctls[i]->id);
+
+	for (i = 0; i < num_line_out; i++)
+		if (private->vol_sw_hw_switch[i])
+			snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+				       &private->mute_ctls[i]->id);
 }
 
 /* Interrupt callback */
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 13/31] ALSA: usb-audio: scarlett2: Allow arbitrary ordering of mux entries
  2021-06-21 18:09 [PATCH 00/31] Refactor Scarlett Gen 2 support and add Scarlett Gen 3 support Geoffrey D. Bennett
                   ` (11 preceding siblings ...)
  2021-06-21 18:09 ` [PATCH 12/31] ALSA: usb-audio: scarlett2: Add mute support Geoffrey D. Bennett
@ 2021-06-21 18:09 ` Geoffrey D. Bennett
  2021-06-21 18:09 ` [PATCH 14/31] ALSA: usb-audio: scarlett2: Split struct scarlett2_ports Geoffrey D. Bennett
                   ` (17 subsequent siblings)
  30 siblings, 0 replies; 43+ messages in thread
From: Geoffrey D. Bennett @ 2021-06-21 18:09 UTC (permalink / raw)
  To: alsa-devel, Takashi Iwai; +Cc: Hin-Tak Leung, Vladimir Sadovnikov

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 --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;
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 14/31] ALSA: usb-audio: scarlett2: Split struct scarlett2_ports
  2021-06-21 18:09 [PATCH 00/31] Refactor Scarlett Gen 2 support and add Scarlett Gen 3 support Geoffrey D. Bennett
                   ` (12 preceding siblings ...)
  2021-06-21 18:09 ` [PATCH 13/31] ALSA: usb-audio: scarlett2: Allow arbitrary ordering of mux entries Geoffrey D. Bennett
@ 2021-06-21 18:09 ` Geoffrey D. Bennett
  2021-06-21 18:09 ` [PATCH 15/31] ALSA: usb-audio: scarlett2: Fix Level Meter control Geoffrey D. Bennett
                   ` (16 subsequent siblings)
  30 siblings, 0 replies; 43+ messages in thread
From: Geoffrey D. Bennett @ 2021-06-21 18:09 UTC (permalink / raw)
  To: alsa-devel, Takashi Iwai; +Cc: Hin-Tak Leung, Vladimir Sadovnikov

The scarlett2_ports struct contains both generic (hardware IDs and
descriptions) and model-specific (port count) data. Remove the generic
data from the scarlett2_device_info struct so it is not repeated for
every model.

Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
---
 sound/usb/mixer_scarlett_gen2.c | 303 +++++++++++++-------------------
 1 file changed, 124 insertions(+), 179 deletions(-)

diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c
index b874c0c922d3..7647b3428093 100644
--- a/sound/usb/mixer_scarlett_gen2.c
+++ b/sound/usb/mixer_scarlett_gen2.c
@@ -203,20 +203,55 @@ static const char *const scarlett2_dim_mute_names[SCARLETT2_DIM_MUTE_COUNT] = {
 };
 
 /* Description of each hardware port type:
- * - id: hardware ID for this port type
- * - num: number of sources/destinations of this port type
+ * - id: hardware ID of this port type
  * - src_descr: printf format string for mux input selections
  * - src_num_offset: added to channel number for the fprintf
  * - dst_descr: printf format string for mixer controls
  */
-struct scarlett2_ports {
+struct scarlett2_port {
 	u16 id;
-	int num[SCARLETT2_PORT_DIRNS];
 	const char * const src_descr;
 	int src_num_offset;
 	const char * const dst_descr;
 };
 
+static const struct scarlett2_port scarlett2_ports[SCARLETT2_PORT_TYPE_COUNT] = {
+	[SCARLETT2_PORT_TYPE_NONE] = {
+		.id = 0x000,
+		.src_descr = "Off"
+	},
+	[SCARLETT2_PORT_TYPE_ANALOGUE] = {
+		.id = 0x080,
+		.src_descr = "Analogue %d",
+		.src_num_offset = 1,
+		.dst_descr = "Analogue Output %02d Playback"
+	},
+	[SCARLETT2_PORT_TYPE_SPDIF] = {
+		.id = 0x180,
+		.src_descr = "S/PDIF %d",
+		.src_num_offset = 1,
+		.dst_descr = "S/PDIF Output %d Playback"
+	},
+	[SCARLETT2_PORT_TYPE_ADAT] = {
+		.id = 0x200,
+		.src_descr = "ADAT %d",
+		.src_num_offset = 1,
+		.dst_descr = "ADAT Output %d Playback"
+	},
+	[SCARLETT2_PORT_TYPE_MIX] = {
+		.id = 0x300,
+		.src_descr = "Mix %c",
+		.src_num_offset = 'A',
+		.dst_descr = "Mixer Input %02d Capture"
+	},
+	[SCARLETT2_PORT_TYPE_PCM] = {
+		.id = 0x600,
+		.src_descr = "PCM %d",
+		.src_num_offset = 1,
+		.dst_descr = "PCM %02d Capture"
+	},
+};
+
 /* Number of mux tables: one for each band of sample rates
  * (44.1/48kHz, 88.2/96kHz, and 176.4/176kHz)
  */
@@ -254,8 +289,8 @@ struct scarlett2_device_info {
 	/* additional description for the line out volume controls */
 	const char * const line_out_descrs[SCARLETT2_ANALOGUE_MAX];
 
-	/* port count and type data */
-	struct scarlett2_ports ports[SCARLETT2_PORT_TYPE_COUNT];
+	/* number of sources/destinations of each port type */
+	const int port_count[SCARLETT2_PORT_TYPE_COUNT][SCARLETT2_PORT_DIRNS];
 
 	/* layout/order of the entries in the set_mux message */
 	struct scarlett2_mux_entry mux_assignment[SCARLETT2_MUX_TABLES]
@@ -309,40 +344,12 @@ static const struct scarlett2_device_info s6i6_gen2_info = {
 		"Headphones 2 R",
 	},
 
-	.ports = {
-		[SCARLETT2_PORT_TYPE_NONE] = {
-			.id = 0x000,
-			.num = { 1, 0 },
-			.src_descr = "Off",
-		},
-		[SCARLETT2_PORT_TYPE_ANALOGUE] = {
-			.id = 0x080,
-			.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 },
-			.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 },
-			.src_descr = "Mix %c",
-			.src_num_offset = 65,
-			.dst_descr = "Mixer Input %02d Capture"
-		},
-		[SCARLETT2_PORT_TYPE_PCM] = {
-			.id = 0x600,
-			.num = { 6, 6 },
-			.src_descr = "PCM %d",
-			.src_num_offset = 1,
-			.dst_descr = "PCM %02d Capture"
-		},
+	.port_count = {
+		[SCARLETT2_PORT_TYPE_NONE]     = {  1,  0 },
+		[SCARLETT2_PORT_TYPE_ANALOGUE] = {  4,  4 },
+		[SCARLETT2_PORT_TYPE_SPDIF]    = {  2,  2 },
+		[SCARLETT2_PORT_TYPE_MIX]      = { 10, 18 },
+		[SCARLETT2_PORT_TYPE_PCM]      = {  6,  6 },
 	},
 
 	.mux_assignment = { {
@@ -384,46 +391,13 @@ static const struct scarlett2_device_info s18i8_gen2_info = {
 		"Headphones 2 R",
 	},
 
-	.ports = {
-		[SCARLETT2_PORT_TYPE_NONE] = {
-			.id = 0x000,
-			.num = { 1, 0 },
-			.src_descr = "Off",
-		},
-		[SCARLETT2_PORT_TYPE_ANALOGUE] = {
-			.id = 0x080,
-			.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 },
-			.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 },
-			.src_descr = "ADAT %d",
-			.src_num_offset = 1,
-		},
-		[SCARLETT2_PORT_TYPE_MIX] = {
-			.id = 0x300,
-			.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 },
-			.src_descr = "PCM %d",
-			.src_num_offset = 1,
-			.dst_descr = "PCM %02d Capture"
-		},
+	.port_count = {
+		[SCARLETT2_PORT_TYPE_NONE]     = {  1,  0 },
+		[SCARLETT2_PORT_TYPE_ANALOGUE] = {  8,  6 },
+		[SCARLETT2_PORT_TYPE_SPDIF]    = {  2,  2 },
+		[SCARLETT2_PORT_TYPE_ADAT]     = {  8,  0 },
+		[SCARLETT2_PORT_TYPE_MIX]      = { 10, 18 },
+		[SCARLETT2_PORT_TYPE_PCM]      = {  8, 18 },
 	},
 
 	.mux_assignment = { {
@@ -468,51 +442,13 @@ static const struct scarlett2_device_info s18i20_gen2_info = {
 		"Headphones 2 R",
 	},
 
-	.ports = {
-		[SCARLETT2_PORT_TYPE_NONE] = {
-			.id = 0x000,
-			.num = { 1, 0 },
-			.src_descr = "Off",
-		},
-		[SCARLETT2_PORT_TYPE_ANALOGUE] = {
-			.id = 0x080,
-			.num = { 8, 10 },
-			.src_descr = "Analogue %d",
-			.src_num_offset = 1,
-			.dst_descr = "Analogue Output %02d Playback"
-		},
-		[SCARLETT2_PORT_TYPE_SPDIF] = {
-			/* S/PDIF outputs aren't available at 192kHz
-			 * but are included in the USB mux I/O
-			 * assignment message anyway
-			 */
-			.id = 0x180,
-			.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 },
-			.src_descr = "ADAT %d",
-			.src_num_offset = 1,
-			.dst_descr = "ADAT Output %d Playback"
-		},
-		[SCARLETT2_PORT_TYPE_MIX] = {
-			.id = 0x300,
-			.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 },
-			.src_descr = "PCM %d",
-			.src_num_offset = 1,
-			.dst_descr = "PCM %02d Capture"
-		},
+	.port_count = {
+		[SCARLETT2_PORT_TYPE_NONE]     = {  1,  0 },
+		[SCARLETT2_PORT_TYPE_ANALOGUE] = {  8, 10 },
+		[SCARLETT2_PORT_TYPE_SPDIF]    = {  2,  2 },
+		[SCARLETT2_PORT_TYPE_ADAT]     = {  8,  8 },
+		[SCARLETT2_PORT_TYPE_MIX]      = { 10, 18 },
+		[SCARLETT2_PORT_TYPE_PCM]      = { 20, 18 },
 	},
 
 	.mux_assignment = { {
@@ -552,13 +488,14 @@ static const struct scarlett2_device_info *scarlett2_devices[] = {
 };
 
 /* get the starting port index number for a given port type/direction */
-static int scarlett2_get_port_start_num(const struct scarlett2_ports *ports,
-					int direction, int port_type)
+static int scarlett2_get_port_start_num(
+	const int port_count[][SCARLETT2_PORT_DIRNS],
+	int direction, int port_type)
 {
 	int i, num = 0;
 
 	for (i = 0; i < port_type; i++)
-		num += ports[i].num[direction];
+		num += port_count[i][direction];
 
 	return num;
 }
@@ -924,7 +861,7 @@ static int scarlett2_usb_get_mix(struct usb_mixer_interface *mixer,
 	const struct scarlett2_device_info *info = private->info;
 
 	int num_mixer_in =
-		info->ports[SCARLETT2_PORT_TYPE_MIX].num[SCARLETT2_PORT_OUT];
+		info->port_count[SCARLETT2_PORT_TYPE_MIX][SCARLETT2_PORT_OUT];
 	int err, i, j, k;
 
 	struct {
@@ -973,7 +910,7 @@ static int scarlett2_usb_set_mix(struct usb_mixer_interface *mixer,
 
 	int i, j;
 	int num_mixer_in =
-		info->ports[SCARLETT2_PORT_TYPE_MIX].num[SCARLETT2_PORT_OUT];
+		info->port_count[SCARLETT2_PORT_TYPE_MIX][SCARLETT2_PORT_OUT];
 
 	req.mix_num = cpu_to_le16(mix_num);
 
@@ -987,18 +924,18 @@ static int scarlett2_usb_set_mix(struct usb_mixer_interface *mixer,
 			     NULL, 0);
 }
 
-/* Convert a port number index (per info->ports) to a hardware ID */
-static u32 scarlett2_mux_src_num_to_id(const struct scarlett2_ports *ports,
-				       int num)
+/* Convert a port number index (per info->port_count) to a hardware ID */
+static u32 scarlett2_mux_src_num_to_id(
+	const int port_count[][SCARLETT2_PORT_DIRNS], int num)
 {
 	int port_type;
 
 	for (port_type = 0;
 	     port_type < SCARLETT2_PORT_TYPE_COUNT;
 	     port_type++) {
-		if (num < ports[port_type].num[SCARLETT2_PORT_IN])
-			return ports[port_type].id | num;
-		num -= ports[port_type].num[SCARLETT2_PORT_IN];
+		if (num < port_count[port_type][SCARLETT2_PORT_IN])
+			return scarlett2_ports[port_type].id | num;
+		num -= port_count[port_type][SCARLETT2_PORT_IN];
 	}
 
 	/* Oops */
@@ -1006,9 +943,8 @@ static u32 scarlett2_mux_src_num_to_id(const struct scarlett2_ports *ports,
 }
 
 /* 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)
+static u32 scarlett2_mux_id_to_num(
+	const int port_count[][SCARLETT2_PORT_DIRNS], int direction, u32 id)
 {
 	int port_type;
 	int port_num = 0;
@@ -1016,11 +952,11 @@ static u32 scarlett2_mux_id_to_num(const struct scarlett2_ports *ports,
 	for (port_type = 0;
 	     port_type < SCARLETT2_PORT_TYPE_COUNT;
 	     port_type++) {
-		struct scarlett2_ports port = ports[port_type];
-		int count = port.num[direction];
+		int base = scarlett2_ports[port_type].id;
+		int count = port_count[port_type][direction];
 
-		if (id >= port.id && id < port.id + count)
-			return port_num + id - port.id;
+		if (id >= base && id < base + count)
+			return port_num + id - base;
 		port_num += count;
 	}
 
@@ -1033,11 +969,11 @@ static void scarlett2_usb_populate_mux(struct scarlett2_data *private,
 				       u32 mux_entry)
 {
 	const struct scarlett2_device_info *info = private->info;
-	const struct scarlett2_ports *ports = info->ports;
+	const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count;
 
 	int dst_idx, src_idx;
 
-	dst_idx = scarlett2_mux_id_to_num(ports, SCARLETT2_PORT_OUT,
+	dst_idx = scarlett2_mux_id_to_num(port_count, SCARLETT2_PORT_OUT,
 					  mux_entry & 0xFFF);
 	if (dst_idx < 0)
 		return;
@@ -1049,7 +985,7 @@ static void scarlett2_usb_populate_mux(struct scarlett2_data *private,
 		return;
 	}
 
-	src_idx = scarlett2_mux_id_to_num(ports, SCARLETT2_PORT_IN,
+	src_idx = scarlett2_mux_id_to_num(port_count, SCARLETT2_PORT_IN,
 					  mux_entry >> 12);
 	if (src_idx < 0)
 		return;
@@ -1098,7 +1034,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;
+	const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count;
 	int table;
 
 	struct {
@@ -1125,9 +1061,9 @@ static int scarlett2_usb_set_mux(struct usb_mixer_interface *mixer)
 			int j;
 			int port_type = entry->port_type;
 			int port_idx = entry->start;
-			int mux_idx = scarlett2_get_port_start_num(ports,
+			int mux_idx = scarlett2_get_port_start_num(port_count,
 				SCARLETT2_PORT_OUT, port_type) + port_idx;
-			int dst_id = ports[port_type].id + port_idx;
+			int dst_id = scarlett2_ports[port_type].id + port_idx;
 
 			/* Empty slots */
 			if (!dst_id) {
@@ -1142,7 +1078,7 @@ static int scarlett2_usb_set_mux(struct usb_mixer_interface *mixer)
 			 */
 			for (j = 0; j < entry->count; j++) {
 				int src_id = scarlett2_mux_src_num_to_id(
-					ports, private->mux[mux_idx++]);
+					port_count, private->mux[mux_idx++]);
 				req.data[i++] = cpu_to_le32(dst_id |
 							    src_id << 12);
 				dst_id++;
@@ -1289,10 +1225,10 @@ static int scarlett2_update_volumes(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;
+	const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count;
 	struct scarlett2_usb_volume_status volume_status;
 	int num_line_out =
-		ports[SCARLETT2_PORT_TYPE_ANALOGUE].num[SCARLETT2_PORT_OUT];
+		port_count[SCARLETT2_PORT_TYPE_ANALOGUE][SCARLETT2_PORT_OUT];
 	int err, i;
 	int mute;
 
@@ -1721,9 +1657,9 @@ static int scarlett2_dim_mute_ctl_put(struct snd_kcontrol *kctl,
 	struct usb_mixer_interface *mixer = elem->head.mixer;
 	struct scarlett2_data *private = mixer->private_data;
 	const struct scarlett2_device_info *info = private->info;
-	const struct scarlett2_ports *ports = info->ports;
+	const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count;
 	int num_line_out =
-		ports[SCARLETT2_PORT_TYPE_ANALOGUE].num[SCARLETT2_PORT_OUT];
+		port_count[SCARLETT2_PORT_TYPE_ANALOGUE][SCARLETT2_PORT_OUT];
 
 	int index = elem->control;
 	int oval, val, err = 0, i;
@@ -1772,9 +1708,9 @@ static int scarlett2_add_line_out_ctls(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;
+	const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count;
 	int num_line_out =
-		ports[SCARLETT2_PORT_TYPE_ANALOGUE].num[SCARLETT2_PORT_OUT];
+		port_count[SCARLETT2_PORT_TYPE_ANALOGUE][SCARLETT2_PORT_OUT];
 	int err, i;
 	char s[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
 
@@ -1913,7 +1849,7 @@ static int scarlett2_mixer_ctl_put(struct snd_kcontrol *kctl,
 	struct usb_mixer_interface *mixer = elem->head.mixer;
 	struct scarlett2_data *private = mixer->private_data;
 	const struct scarlett2_device_info *info = private->info;
-	const struct scarlett2_ports *ports = info->ports;
+	const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count;
 	int oval, val, num_mixer_in, mix_num, err = 0;
 	int index = elem->control;
 
@@ -1921,7 +1857,7 @@ static int scarlett2_mixer_ctl_put(struct snd_kcontrol *kctl,
 
 	oval = private->mix[index];
 	val = ucontrol->value.integer.value[0];
-	num_mixer_in = ports[SCARLETT2_PORT_TYPE_MIX].num[SCARLETT2_PORT_OUT];
+	num_mixer_in = port_count[SCARLETT2_PORT_TYPE_MIX][SCARLETT2_PORT_OUT];
 	mix_num = index / num_mixer_in;
 
 	if (oval == val)
@@ -1958,13 +1894,16 @@ static const struct snd_kcontrol_new scarlett2_mixer_ctl = {
 static int scarlett2_add_mixer_ctls(struct usb_mixer_interface *mixer)
 {
 	struct scarlett2_data *private = mixer->private_data;
-	const struct scarlett2_ports *ports = private->info->ports;
+	const struct scarlett2_device_info *info = private->info;
+	const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count;
 	int err, i, j;
 	int index;
 	char s[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
 
-	int num_inputs = ports[SCARLETT2_PORT_TYPE_MIX].num[SCARLETT2_PORT_OUT];
-	int num_outputs = ports[SCARLETT2_PORT_TYPE_MIX].num[SCARLETT2_PORT_IN];
+	int num_inputs =
+		port_count[SCARLETT2_PORT_TYPE_MIX][SCARLETT2_PORT_OUT];
+	int num_outputs =
+		port_count[SCARLETT2_PORT_TYPE_MIX][SCARLETT2_PORT_IN];
 
 	for (i = 0, index = 0; i < num_outputs; i++)
 		for (j = 0; j < num_inputs; j++, index++) {
@@ -1987,7 +1926,8 @@ static int scarlett2_mux_src_enum_ctl_info(struct snd_kcontrol *kctl,
 {
 	struct usb_mixer_elem_info *elem = kctl->private_data;
 	struct scarlett2_data *private = elem->head.mixer->private_data;
-	const struct scarlett2_ports *ports = private->info->ports;
+	const struct scarlett2_device_info *info = private->info;
+	const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count;
 	unsigned int item = uinfo->value.enumerated.item;
 	int items = private->num_mux_srcs;
 	int port_type;
@@ -2002,13 +1942,15 @@ static int scarlett2_mux_src_enum_ctl_info(struct snd_kcontrol *kctl,
 	for (port_type = 0;
 	     port_type < SCARLETT2_PORT_TYPE_COUNT;
 	     port_type++) {
-		if (item < ports[port_type].num[SCARLETT2_PORT_IN]) {
+		if (item < port_count[port_type][SCARLETT2_PORT_IN]) {
+			const struct scarlett2_port *port =
+				&scarlett2_ports[port_type];
+
 			sprintf(uinfo->value.enumerated.name,
-				ports[port_type].src_descr,
-				item + ports[port_type].src_num_offset);
+				port->src_descr, item + port->src_num_offset);
 			return 0;
 		}
-		item -= ports[port_type].num[SCARLETT2_PORT_IN];
+		item -= port_count[port_type][SCARLETT2_PORT_IN];
 	}
 
 	return -EINVAL;
@@ -2063,18 +2005,20 @@ static const struct snd_kcontrol_new scarlett2_mux_src_enum_ctl = {
 static int scarlett2_add_mux_enums(struct usb_mixer_interface *mixer)
 {
 	struct scarlett2_data *private = mixer->private_data;
-	const struct scarlett2_ports *ports = private->info->ports;
+	const struct scarlett2_device_info *info = private->info;
+	const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count;
 	int port_type, channel, i;
 
 	for (i = 0, port_type = 0;
 	     port_type < SCARLETT2_PORT_TYPE_COUNT;
 	     port_type++) {
 		for (channel = 0;
-		     channel < ports[port_type].num[SCARLETT2_PORT_OUT];
+		     channel < port_count[port_type][SCARLETT2_PORT_OUT];
 		     channel++, i++) {
 			int err;
 			char s[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
-			const char *const descr = ports[port_type].dst_descr;
+			const char *const descr =
+				scarlett2_ports[port_type].dst_descr;
 
 			snprintf(s, sizeof(s) - 5, descr, channel + 1);
 			strcat(s, " Enum");
@@ -2160,14 +2104,15 @@ static void scarlett2_private_suspend(struct usb_mixer_interface *mixer)
 
 static void scarlett2_count_mux_io(struct scarlett2_data *private)
 {
-	const struct scarlett2_ports *ports = private->info->ports;
+	const struct scarlett2_device_info *info = private->info;
+	const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count;
 	int port_type, srcs = 0, dsts = 0;
 
 	for (port_type = 0;
 	     port_type < SCARLETT2_PORT_TYPE_COUNT;
 	     port_type++) {
-		srcs += ports[port_type].num[SCARLETT2_PORT_IN];
-		dsts += ports[port_type].num[SCARLETT2_PORT_OUT];
+		srcs += port_count[port_type][SCARLETT2_PORT_IN];
+		dsts += port_count[port_type][SCARLETT2_PORT_OUT];
 	}
 
 	private->num_mux_srcs = srcs;
@@ -2265,11 +2210,11 @@ static int scarlett2_read_configs(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;
+	const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count;
 	int num_line_out =
-		ports[SCARLETT2_PORT_TYPE_ANALOGUE].num[SCARLETT2_PORT_OUT];
+		port_count[SCARLETT2_PORT_TYPE_ANALOGUE][SCARLETT2_PORT_OUT];
 	int num_mixer_out =
-		ports[SCARLETT2_PORT_TYPE_MIX].num[SCARLETT2_PORT_IN];
+		port_count[SCARLETT2_PORT_TYPE_MIX][SCARLETT2_PORT_IN];
 	struct scarlett2_usb_volume_status volume_status;
 	int err, i;
 
@@ -2356,9 +2301,9 @@ static void scarlett2_notify_monitor(
 {
 	struct scarlett2_data *private = mixer->private_data;
 	const struct scarlett2_device_info *info = private->info;
-	const struct scarlett2_ports *ports = info->ports;
+	const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count;
 	int num_line_out =
-		ports[SCARLETT2_PORT_TYPE_ANALOGUE].num[SCARLETT2_PORT_OUT];
+		port_count[SCARLETT2_PORT_TYPE_ANALOGUE][SCARLETT2_PORT_OUT];
 	int i;
 
 	/* if line_out_hw_vol is 0, there are no controls to update */
@@ -2385,9 +2330,9 @@ static void scarlett2_notify_dim_mute(
 	struct snd_card *card = mixer->chip->card;
 	struct scarlett2_data *private = mixer->private_data;
 	const struct scarlett2_device_info *info = private->info;
-	const struct scarlett2_ports *ports = info->ports;
+	const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count;
 	int num_line_out =
-		ports[SCARLETT2_PORT_TYPE_ANALOGUE].num[SCARLETT2_PORT_OUT];
+		port_count[SCARLETT2_PORT_TYPE_ANALOGUE][SCARLETT2_PORT_OUT];
 	int i;
 
 	private->vol_updated = 1;
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 15/31] ALSA: usb-audio: scarlett2: Fix Level Meter control
  2021-06-21 18:09 [PATCH 00/31] Refactor Scarlett Gen 2 support and add Scarlett Gen 3 support Geoffrey D. Bennett
                   ` (13 preceding siblings ...)
  2021-06-21 18:09 ` [PATCH 14/31] ALSA: usb-audio: scarlett2: Split struct scarlett2_ports Geoffrey D. Bennett
@ 2021-06-21 18:09 ` Geoffrey D. Bennett
  2021-06-21 18:09 ` [PATCH 16/31] ALSA: usb-audio: scarlett2: Add Gen 3 mixer support Geoffrey D. Bennett
                   ` (15 subsequent siblings)
  30 siblings, 0 replies; 43+ messages in thread
From: Geoffrey D. Bennett @ 2021-06-21 18:09 UTC (permalink / raw)
  To: alsa-devel, Takashi Iwai; +Cc: Hin-Tak Leung, Vladimir Sadovnikov

The Level Meter control had a fixed number of channels and therefore
only worked with the 18i20 Gen 2. Fix the control to contain the
correct number of channels.

Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
---
 sound/usb/mixer_scarlett_gen2.c | 25 +++++++++++++------------
 1 file changed, 13 insertions(+), 12 deletions(-)

diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c
index 7647b3428093..dde008ea21d7 100644
--- a/sound/usb/mixer_scarlett_gen2.c
+++ b/sound/usb/mixer_scarlett_gen2.c
@@ -161,10 +161,8 @@ static const u16 scarlett2_mixer_values[SCARLETT2_MIXER_VALUE_COUNT] = {
  */
 #define SCARLETT2_MUX_MAX 64
 
-/* Number of meters:
- * 18 inputs, 20 outputs, 18 matrix inputs
- */
-#define SCARLETT2_NUM_METERS 56
+/* Maximum number of meters (sum of output port counts) */
+#define SCARLETT2_MAX_METERS 56
 
 /* Hardware port types:
  * - None (no input to mux)
@@ -1097,26 +1095,26 @@ static int scarlett2_usb_set_mux(struct usb_mixer_interface *mixer)
 
 /* Send USB message to get meter levels */
 static int scarlett2_usb_get_meter_levels(struct usb_mixer_interface *mixer,
-					  u16 *levels)
+					  u16 num_meters, u16 *levels)
 {
 	struct {
 		__le16 pad;
 		__le16 num_meters;
 		__le32 magic;
 	} __packed req;
-	u32 resp[SCARLETT2_NUM_METERS];
+	u32 resp[SCARLETT2_MAX_METERS];
 	int i, err;
 
 	req.pad = 0;
-	req.num_meters = cpu_to_le16(SCARLETT2_NUM_METERS);
+	req.num_meters = cpu_to_le16(num_meters);
 	req.magic = cpu_to_le32(SCARLETT2_USB_METER_LEVELS_GET_MAGIC);
 	err = scarlett2_usb(mixer, SCARLETT2_USB_GET_METER,
-			    &req, sizeof(req), resp, sizeof(resp));
+			    &req, sizeof(req), resp, num_meters * sizeof(u32));
 	if (err < 0)
 		return err;
 
 	/* copy, convert to u16 */
-	for (i = 0; i < SCARLETT2_NUM_METERS; i++)
+	for (i = 0; i < num_meters; i++)
 		levels[i] = resp[i];
 
 	return 0;
@@ -2053,10 +2051,11 @@ static int scarlett2_meter_ctl_get(struct snd_kcontrol *kctl,
 				   struct snd_ctl_elem_value *ucontrol)
 {
 	struct usb_mixer_elem_info *elem = kctl->private_data;
-	u16 meter_levels[SCARLETT2_NUM_METERS];
+	u16 meter_levels[SCARLETT2_MAX_METERS];
 	int i, err;
 
-	err = scarlett2_usb_get_meter_levels(elem->head.mixer, meter_levels);
+	err = scarlett2_usb_get_meter_levels(elem->head.mixer, elem->channels,
+					     meter_levels);
 	if (err < 0)
 		return err;
 
@@ -2076,8 +2075,10 @@ static const struct snd_kcontrol_new scarlett2_meter_ctl = {
 
 static int scarlett2_add_meter_ctl(struct usb_mixer_interface *mixer)
 {
+	struct scarlett2_data *private = mixer->private_data;
+
 	return scarlett2_add_new_ctl(mixer, &scarlett2_meter_ctl,
-				     0, SCARLETT2_NUM_METERS,
+				     0, private->num_mux_dsts,
 				     "Level Meter", NULL);
 }
 
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 16/31] ALSA: usb-audio: scarlett2: Add Gen 3 mixer support
  2021-06-21 18:09 [PATCH 00/31] Refactor Scarlett Gen 2 support and add Scarlett Gen 3 support Geoffrey D. Bennett
                   ` (14 preceding siblings ...)
  2021-06-21 18:09 ` [PATCH 15/31] ALSA: usb-audio: scarlett2: Fix Level Meter control Geoffrey D. Bennett
@ 2021-06-21 18:09 ` Geoffrey D. Bennett
  2021-06-22  7:00   ` Takashi Iwai
  2021-06-21 18:09 ` [PATCH 17/31] ALSA: usb-audio: scarlett2: Add support for "input-other" notify Geoffrey D. Bennett
                   ` (14 subsequent siblings)
  30 siblings, 1 reply; 43+ messages in thread
From: Geoffrey D. Bennett @ 2021-06-21 18:09 UTC (permalink / raw)
  To: alsa-devel, Takashi Iwai; +Cc: Hin-Tak Leung, Vladimir Sadovnikov

Add mixer support for the Focusrite Scarlett 4i4, 8i6, 18i8, and 18i20
Gen 3 devices.

Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
---
 sound/usb/mixer.c               |   2 +-
 sound/usb/mixer_quirks.c        |   4 +
 sound/usb/mixer_scarlett_gen2.c | 260 +++++++++++++++++++++++++++++---
 3 files changed, 246 insertions(+), 20 deletions(-)

diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 428d581f988f..ba4aa1eacb04 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -50,7 +50,7 @@
 #include "mixer_quirks.h"
 #include "power.h"
 
-#define MAX_ID_ELEMS	256
+#define MAX_ID_ELEMS	512
 
 struct usb_audio_term {
 	int id;
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index 37ad77524c0b..df7492594e91 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -3060,6 +3060,10 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
 	case USB_ID(0x1235, 0x8203): /* Focusrite Scarlett 6i6 2nd Gen */
 	case USB_ID(0x1235, 0x8204): /* Focusrite Scarlett 18i8 2nd Gen */
 	case USB_ID(0x1235, 0x8201): /* Focusrite Scarlett 18i20 2nd Gen */
+	case USB_ID(0x1235, 0x8212): /* Focusrite Scarlett 4i4 3rd Gen */
+	case USB_ID(0x1235, 0x8213): /* Focusrite Scarlett 8i6 3rd Gen */
+	case USB_ID(0x1235, 0x8214): /* Focusrite Scarlett 18i8 3rd Gen */
+	case USB_ID(0x1235, 0x8215): /* Focusrite Scarlett 18i20 3rd Gen */
 		err = snd_scarlett_gen2_init(mixer);
 		break;
 
diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c
index dde008ea21d7..c4bcccb5aecd 100644
--- a/sound/usb/mixer_scarlett_gen2.c
+++ b/sound/usb/mixer_scarlett_gen2.c
@@ -1,8 +1,12 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- *   Focusrite Scarlett 6i6/18i8/18i20 Gen 2 Driver for ALSA
+ *   Focusrite Scarlett Gen 2/3 Driver for ALSA
  *
- *   Copyright (c) 2018-2019 by Geoffrey D. Bennett <g at b4.vu>
+ *   Supported models:
+ *   - 6i6/18i8/18i20 Gen 2
+ *   - 4i4/8i6/18i8/18i20 Gen 3
+ *
+ *   Copyright (c) 2018-2021 by Geoffrey D. Bennett <g at b4.vu>
  *
  *   Based on the Scarlett (Gen 1) Driver for ALSA:
  *
@@ -19,10 +23,6 @@
  *   David Henningsson <david.henningsson at canonical.com>
  */
 
-/* Mixer Interface for the Focusrite Scarlett 6i6/18i8/18i20 Gen 2 audio
- * interface. Based on the Gen 1 driver and rewritten.
- */
-
 /* The protocol was reverse engineered by looking at the communication
  * between Focusrite Control 2.3.4 and the Focusrite(R) Scarlett 18i20
  * (firmware 1083) using usbmon in July-August 2018.
@@ -32,13 +32,21 @@
  * Scarlett 6i6 support added in June 2019 (thanks to Martin Wittmann
  * for providing usbmon output and testing).
  *
+ * Scarlett 4i4/8i6 Gen 3 support added in May 2020 (thanks to Laurent
+ * Debricon for donating a 4i4 and to Fredrik Unger for providing 8i6
+ * usbmon output and testing).
+ *
+ * Scarlett 18i8/18i20 Gen 3 support added in June 2020 (thanks to
+ * Darren Jaeckel, Alex Sedlack, and Clovis Lunel for providing usbmon
+ * output, protocol traces 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
+ *  - mixer-matrix gain stages
  *  - gain/volume/mute controls
  *  - level meters
  *  - line/inst level and pad controls
@@ -148,21 +156,21 @@ static const u16 scarlett2_mixer_values[SCARLETT2_MIXER_VALUE_COUNT] = {
 
 /* Maximum number of level and pad switches */
 #define SCARLETT2_LEVEL_SWITCH_MAX 2
-#define SCARLETT2_PAD_SWITCH_MAX 4
+#define SCARLETT2_PAD_SWITCH_MAX 8
 
 /* Maximum number of inputs to the mixer */
-#define SCARLETT2_INPUT_MIX_MAX 18
+#define SCARLETT2_INPUT_MIX_MAX 25
 
 /* Maximum number of outputs from the mixer */
-#define SCARLETT2_OUTPUT_MIX_MAX 10
+#define SCARLETT2_OUTPUT_MIX_MAX 12
 
 /* Maximum size of the data in the USB mux assignment message:
- * 18 inputs, 20 outputs, 18 matrix inputs, 8 spare
+ * 20 inputs, 20 outputs, 25 matrix inputs, 12 spare
  */
-#define SCARLETT2_MUX_MAX 64
+#define SCARLETT2_MUX_MAX 77
 
 /* Maximum number of meters (sum of output port counts) */
-#define SCARLETT2_MAX_METERS 56
+#define SCARLETT2_MAX_METERS 65
 
 /* Hardware port types:
  * - None (no input to mux)
@@ -256,7 +264,7 @@ static const struct scarlett2_port scarlett2_ports[SCARLETT2_PORT_TYPE_COUNT] =
 #define SCARLETT2_MUX_TABLES 3
 
 /* Maximum number of entries in a mux table */
-#define SCARLETT2_MAX_MUX_ENTRIES 7
+#define SCARLETT2_MAX_MUX_ENTRIES 10
 
 /* 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
@@ -475,12 +483,226 @@ static const struct scarlett2_device_info s18i20_gen2_info = {
 	} },
 };
 
+static const struct scarlett2_device_info s4i4_gen3_info = {
+	.usb_id = USB_ID(0x1235, 0x8212),
+
+	.level_input_count = 2,
+	.pad_input_count = 2,
+
+	.line_out_descrs = {
+		"Monitor L",
+		"Monitor R",
+		"Headphones L",
+		"Headphones R",
+	},
+
+	.port_count = {
+		[SCARLETT2_PORT_TYPE_NONE]     = { 1, 0 },
+		[SCARLETT2_PORT_TYPE_ANALOGUE] = { 4, 4 },
+		[SCARLETT2_PORT_TYPE_MIX]      = { 6, 8 },
+		[SCARLETT2_PORT_TYPE_PCM]      = { 4, 6 },
+	},
+
+	.mux_assignment = { {
+		{ SCARLETT2_PORT_TYPE_PCM,      0,  6 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE, 0,  4 },
+		{ SCARLETT2_PORT_TYPE_MIX,      0,  8 },
+		{ SCARLETT2_PORT_TYPE_NONE,     0, 16 },
+		{ 0,                            0,  0 },
+	}, {
+		{ SCARLETT2_PORT_TYPE_PCM,      0,  6 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE, 0,  4 },
+		{ SCARLETT2_PORT_TYPE_MIX,      0,  8 },
+		{ SCARLETT2_PORT_TYPE_NONE,     0, 16 },
+		{ 0,                            0,  0 },
+	}, {
+		{ SCARLETT2_PORT_TYPE_PCM,      0,  6 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE, 0,  4 },
+		{ SCARLETT2_PORT_TYPE_MIX,      0,  8 },
+		{ SCARLETT2_PORT_TYPE_NONE,     0, 16 },
+		{ 0,                            0,  0 },
+	} },
+};
+
+static const struct scarlett2_device_info s8i6_gen3_info = {
+	.usb_id = USB_ID(0x1235, 0x8213),
+
+	.level_input_count = 2,
+	.pad_input_count = 2,
+
+	.line_out_descrs = {
+		"Headphones 1 L",
+		"Headphones 1 R",
+		"Headphones 2 L",
+		"Headphones 2 R",
+	},
+
+	.port_count = {
+		[SCARLETT2_PORT_TYPE_NONE]     = { 1,  0 },
+		[SCARLETT2_PORT_TYPE_ANALOGUE] = { 6,  4 },
+		[SCARLETT2_PORT_TYPE_SPDIF]    = { 2,  2 },
+		[SCARLETT2_PORT_TYPE_MIX]      = { 8,  8 },
+		[SCARLETT2_PORT_TYPE_PCM]      = { 6, 10 },
+	},
+
+	.mux_assignment = { {
+		{ SCARLETT2_PORT_TYPE_PCM,      0,  8 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE, 0,  4 },
+		{ SCARLETT2_PORT_TYPE_SPDIF,    0,  2 },
+		{ SCARLETT2_PORT_TYPE_PCM,      8,  2 },
+		{ SCARLETT2_PORT_TYPE_MIX,      0,  8 },
+		{ SCARLETT2_PORT_TYPE_NONE,     0, 18 },
+		{ 0,                            0,  0 },
+	}, {
+		{ SCARLETT2_PORT_TYPE_PCM,      0,  8 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE, 0,  4 },
+		{ SCARLETT2_PORT_TYPE_SPDIF,    0,  2 },
+		{ SCARLETT2_PORT_TYPE_PCM,      8,  2 },
+		{ SCARLETT2_PORT_TYPE_MIX,      0,  8 },
+		{ SCARLETT2_PORT_TYPE_NONE,     0, 18 },
+		{ 0,                            0,  0 },
+	}, {
+		{ SCARLETT2_PORT_TYPE_PCM,      0,  8 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE, 0,  4 },
+		{ SCARLETT2_PORT_TYPE_SPDIF,    0,  2 },
+		{ SCARLETT2_PORT_TYPE_PCM,      8,  2 },
+		{ SCARLETT2_PORT_TYPE_MIX,      0,  8 },
+		{ SCARLETT2_PORT_TYPE_NONE,     0, 18 },
+		{ 0,                            0,  0 },
+	} },
+};
+
+static const struct scarlett2_device_info s18i8_gen3_info = {
+	.usb_id = USB_ID(0x1235, 0x8214),
+
+	.line_out_hw_vol = 1,
+	.level_input_count = 2,
+	.pad_input_count = 2,
+
+	.line_out_descrs = {
+		"Monitor L",
+		"Monitor R",
+		"Headphones 1 L",
+		"Headphones 1 R",
+		"Headphones 2 L",
+		"Headphones 2 R",
+		"Alt Monitor L",
+		"Alt Monitor R",
+	},
+
+	.port_count = {
+		[SCARLETT2_PORT_TYPE_NONE]     = {  1,  0 },
+		[SCARLETT2_PORT_TYPE_ANALOGUE] = {  8,  8 },
+		[SCARLETT2_PORT_TYPE_SPDIF]    = {  2,  2 },
+		[SCARLETT2_PORT_TYPE_ADAT]     = {  8,  0 },
+		[SCARLETT2_PORT_TYPE_MIX]      = { 10, 20 },
+		[SCARLETT2_PORT_TYPE_PCM]      = {  8, 20 },
+	},
+
+	.mux_assignment = { {
+		{ SCARLETT2_PORT_TYPE_PCM,       0, 10 },
+		{ SCARLETT2_PORT_TYPE_PCM,      12,  8 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE,  0,  2 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE,  6,  2 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE,  2,  4 },
+		{ SCARLETT2_PORT_TYPE_SPDIF,     0,  2 },
+		{ SCARLETT2_PORT_TYPE_PCM,      10,  2 },
+		{ SCARLETT2_PORT_TYPE_MIX,       0, 20 },
+		{ SCARLETT2_PORT_TYPE_NONE,      0, 10 },
+		{ 0,                             0,  0 },
+	}, {
+		{ SCARLETT2_PORT_TYPE_PCM,       0, 10 },
+		{ SCARLETT2_PORT_TYPE_PCM,      12,  4 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE,  0,  2 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE,  6,  2 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE,  2,  4 },
+		{ SCARLETT2_PORT_TYPE_SPDIF,     0,  2 },
+		{ SCARLETT2_PORT_TYPE_PCM,      10,  2 },
+		{ SCARLETT2_PORT_TYPE_MIX,       0, 20 },
+		{ SCARLETT2_PORT_TYPE_NONE,      0, 10 },
+		{ 0,                             0,  0 },
+	}, {
+		{ SCARLETT2_PORT_TYPE_PCM,       0, 10 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE,  0,  2 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE,  6,  2 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE,  2,  4 },
+		{ SCARLETT2_PORT_TYPE_SPDIF,     0,  2 },
+		{ SCARLETT2_PORT_TYPE_MIX,       0, 20 },
+		{ SCARLETT2_PORT_TYPE_NONE,      0, 10 },
+		{ 0,                             0,  0 },
+	} },
+};
+
+static const struct scarlett2_device_info s18i20_gen3_info = {
+	.usb_id = USB_ID(0x1235, 0x8215),
+
+	.line_out_hw_vol = 1,
+	.level_input_count = 2,
+	.pad_input_count = 8,
+
+	.line_out_descrs = {
+		"Monitor 1 L",
+		"Monitor 1 R",
+		"Monitor 2 L",
+		"Monitor 2 R",
+		NULL,
+		NULL,
+		"Headphones 1 L",
+		"Headphones 1 R",
+		"Headphones 2 L",
+		"Headphones 2 R",
+	},
+
+	.port_count = {
+		[SCARLETT2_PORT_TYPE_NONE]     = {  1,  0 },
+		[SCARLETT2_PORT_TYPE_ANALOGUE] = {  9, 10 },
+		[SCARLETT2_PORT_TYPE_SPDIF]    = {  2,  2 },
+		[SCARLETT2_PORT_TYPE_ADAT]     = {  8,  8 },
+		[SCARLETT2_PORT_TYPE_MIX]      = { 12, 25 },
+		[SCARLETT2_PORT_TYPE_PCM]      = { 20, 20 },
+	},
+
+	.mux_assignment = { {
+		{ SCARLETT2_PORT_TYPE_PCM,       0,  8 },
+		{ SCARLETT2_PORT_TYPE_PCM,      10, 10 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE,  0, 10 },
+		{ SCARLETT2_PORT_TYPE_SPDIF,     0,  2 },
+		{ SCARLETT2_PORT_TYPE_ADAT,      0,  8 },
+		{ SCARLETT2_PORT_TYPE_PCM,       8,  2 },
+		{ SCARLETT2_PORT_TYPE_MIX,       0, 25 },
+		{ SCARLETT2_PORT_TYPE_NONE,      0, 12 },
+		{ 0,                             0,  0 },
+	}, {
+		{ SCARLETT2_PORT_TYPE_PCM,       0,  8 },
+		{ SCARLETT2_PORT_TYPE_PCM,      10,  8 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE,  0, 10 },
+		{ SCARLETT2_PORT_TYPE_SPDIF,     0,  2 },
+		{ SCARLETT2_PORT_TYPE_ADAT,      0,  8 },
+		{ SCARLETT2_PORT_TYPE_PCM,       8,  2 },
+		{ SCARLETT2_PORT_TYPE_MIX,       0, 25 },
+		{ SCARLETT2_PORT_TYPE_NONE,      0, 10 },
+		{ 0,                             0,  0 },
+	}, {
+		{ SCARLETT2_PORT_TYPE_PCM,       0, 10 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE,  0, 10 },
+		{ SCARLETT2_PORT_TYPE_SPDIF,     0,  2 },
+		{ SCARLETT2_PORT_TYPE_NONE,      0, 24 },
+		{ 0,                             0,  0 },
+	} },
+};
+
 static const struct scarlett2_device_info *scarlett2_devices[] = {
 	/* Supported Gen 2 devices */
 	&s6i6_gen2_info,
 	&s18i8_gen2_info,
 	&s18i20_gen2_info,
 
+	/* Supported Gen 3 devices */
+	&s4i4_gen3_info,
+	&s8i6_gen3_info,
+	&s18i8_gen3_info,
+	&s18i20_gen3_info,
+
 	/* End of list */
 	NULL
 };
@@ -674,7 +896,7 @@ static int scarlett2_usb(
 	if (err != req_buf_size) {
 		usb_audio_err(
 			mixer->chip,
-			"Scarlett Gen 2 USB request result cmd %x was %d\n",
+			"Scarlett Gen 2/3 USB request result cmd %x was %d\n",
 			cmd, err);
 		err = -EINVAL;
 		goto unlock;
@@ -691,7 +913,7 @@ static int scarlett2_usb(
 	if (err != resp_buf_size) {
 		usb_audio_err(
 			mixer->chip,
-			"Scarlett Gen 2 USB response result cmd %x was %d "
+			"Scarlett Gen 2/3 USB response result cmd %x was %d "
 			"expected %d\n",
 			cmd, err, resp_buf_size);
 		err = -EINVAL;
@@ -709,7 +931,7 @@ static int scarlett2_usb(
 	    resp->pad) {
 		usb_audio_err(
 			mixer->chip,
-			"Scarlett Gen 2 USB invalid response; "
+			"Scarlett Gen 2/3 USB invalid response; "
 			   "cmd tx/rx %d/%d seq %d/%d size %d/%d "
 			   "error %d pad %d\n",
 			le32_to_cpu(req->cmd), le32_to_cpu(resp->cmd),
@@ -2485,7 +2707,7 @@ int snd_scarlett_gen2_init(struct usb_mixer_interface *mixer)
 
 	if (!(chip->setup & SCARLETT2_ENABLE)) {
 		usb_audio_info(chip,
-			"Focusrite Scarlett Gen 2 Mixer Driver disabled; "
+			"Focusrite Scarlett Gen 2/3 Mixer Driver disabled; "
 			"use options snd_usb_audio vid=0x%04x pid=0x%04x "
 			"device_setup=1 to enable and report any issues "
 			"to g@b4.vu",
@@ -2495,7 +2717,7 @@ int snd_scarlett_gen2_init(struct usb_mixer_interface *mixer)
 	}
 
 	usb_audio_info(chip,
-		"Focusrite Scarlett Gen 2 Mixer Driver enabled pid=0x%04x",
+		"Focusrite Scarlett Gen 2/3 Mixer Driver enabled pid=0x%04x",
 		USB_ID_PRODUCT(chip->usb_id));
 
 	err = snd_scarlett_gen2_controls_create(mixer);
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 17/31] ALSA: usb-audio: scarlett2: Add support for "input-other" notify
  2021-06-21 18:09 [PATCH 00/31] Refactor Scarlett Gen 2 support and add Scarlett Gen 3 support Geoffrey D. Bennett
                   ` (15 preceding siblings ...)
  2021-06-21 18:09 ` [PATCH 16/31] ALSA: usb-audio: scarlett2: Add Gen 3 mixer support Geoffrey D. Bennett
@ 2021-06-21 18:09 ` Geoffrey D. Bennett
  2021-06-21 18:09 ` [PATCH 18/31] ALSA: usb-audio: scarlett2: Add Gen 3 MSD mode switch Geoffrey D. Bennett
                   ` (13 subsequent siblings)
  30 siblings, 0 replies; 43+ messages in thread
From: Geoffrey D. Bennett @ 2021-06-21 18:09 UTC (permalink / raw)
  To: alsa-devel, Takashi Iwai; +Cc: Hin-Tak Leung, Vladimir Sadovnikov

Some models allow the level and pad settings to be controlled from the
front-panel of the device. For these, the device will send an
"input-other" notification to prompt the driver to re-read the status
of those settings.

Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
---
 sound/usb/mixer_scarlett_gen2.c | 99 ++++++++++++++++++++++++---------
 1 file changed, 73 insertions(+), 26 deletions(-)

diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c
index c4bcccb5aecd..a4f92291b74f 100644
--- a/sound/usb/mixer_scarlett_gen2.c
+++ b/sound/usb/mixer_scarlett_gen2.c
@@ -318,6 +318,7 @@ struct scarlett2_data {
 	u16 scarlett2_seq;
 	u8 sync_updated;
 	u8 vol_updated;
+	u8 input_other_updated;
 	u8 sync;
 	u8 master_vol;
 	u8 vol[SCARLETT2_ANALOGUE_MAX];
@@ -331,6 +332,8 @@ struct scarlett2_data {
 	struct snd_kcontrol *vol_ctls[SCARLETT2_ANALOGUE_MAX];
 	struct snd_kcontrol *mute_ctls[SCARLETT2_ANALOGUE_MAX];
 	struct snd_kcontrol *dim_mute_ctls[SCARLETT2_DIM_MUTE_COUNT];
+	struct snd_kcontrol *level_ctls[SCARLETT2_LEVEL_SWITCH_MAX];
+	struct snd_kcontrol *pad_ctls[SCARLETT2_PAD_SWITCH_MAX];
 	u8 mux[SCARLETT2_MUX_MAX];
 	u8 mix[SCARLETT2_INPUT_MIX_MAX * SCARLETT2_OUTPUT_MIX_MAX];
 };
@@ -723,9 +726,10 @@ static int scarlett2_get_port_start_num(
 /*** USB Interactions ***/
 
 /* Notifications from the interface */
-#define SCARLETT2_USB_NOTIFY_SYNC     0x00000008
-#define SCARLETT2_USB_NOTIFY_DIM_MUTE 0x00200000
-#define SCARLETT2_USB_NOTIFY_MONITOR  0x00400000
+#define SCARLETT2_USB_NOTIFY_SYNC        0x00000008
+#define SCARLETT2_USB_NOTIFY_DIM_MUTE    0x00200000
+#define SCARLETT2_USB_NOTIFY_MONITOR     0x00400000
+#define SCARLETT2_USB_NOTIFY_INPUT_OTHER 0x00800000
 
 /* Commands for sending/receiving requests/responses */
 #define SCARLETT2_USB_CMD_INIT 0
@@ -1740,6 +1744,32 @@ static const struct snd_kcontrol_new scarlett2_sw_hw_enum_ctl = {
 
 /*** Line Level/Instrument Level Switch Controls ***/
 
+static int scarlett2_update_input_other(struct usb_mixer_interface *mixer)
+{
+	struct scarlett2_data *private = mixer->private_data;
+	const struct scarlett2_device_info *info = private->info;
+
+	private->input_other_updated = 0;
+
+	if (info->level_input_count) {
+		int err = scarlett2_usb_get_config(
+			mixer, SCARLETT2_CONFIG_LEVEL_SWITCH,
+			info->level_input_count, private->level_switch);
+		if (err < 0)
+			return err;
+	}
+
+	if (info->pad_input_count) {
+		int err = scarlett2_usb_get_config(
+			mixer, SCARLETT2_CONFIG_PAD_SWITCH,
+			info->pad_input_count, private->pad_switch);
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+
 static int scarlett2_level_enum_ctl_info(struct snd_kcontrol *kctl,
 					 struct snd_ctl_elem_info *uinfo)
 {
@@ -1754,10 +1784,16 @@ static int scarlett2_level_enum_ctl_get(struct snd_kcontrol *kctl,
 					struct snd_ctl_elem_value *ucontrol)
 {
 	struct usb_mixer_elem_info *elem = kctl->private_data;
-	struct scarlett2_data *private = elem->head.mixer->private_data;
+	struct usb_mixer_interface *mixer = elem->head.mixer;
+	struct scarlett2_data *private = mixer->private_data;
 
+	mutex_lock(&private->data_mutex);
+	if (private->input_other_updated)
+		scarlett2_update_input_other(mixer);
 	ucontrol->value.enumerated.item[0] =
 		private->level_switch[elem->control];
+	mutex_unlock(&private->data_mutex);
+
 	return 0;
 }
 
@@ -1806,10 +1842,16 @@ static int scarlett2_pad_ctl_get(struct snd_kcontrol *kctl,
 				 struct snd_ctl_elem_value *ucontrol)
 {
 	struct usb_mixer_elem_info *elem = kctl->private_data;
-	struct scarlett2_data *private = elem->head.mixer->private_data;
+	struct usb_mixer_interface *mixer = elem->head.mixer;
+	struct scarlett2_data *private = mixer->private_data;
 
+	mutex_lock(&private->data_mutex);
+	if (private->input_other_updated)
+		scarlett2_update_input_other(mixer);
 	ucontrol->value.integer.value[0] =
 		private->pad_switch[elem->control];
+	mutex_unlock(&private->data_mutex);
+
 	return 0;
 }
 
@@ -2020,7 +2062,7 @@ static int scarlett2_add_line_in_ctls(struct usb_mixer_interface *mixer)
 	for (i = 0; i < info->level_input_count; i++) {
 		snprintf(s, sizeof(s), fmt, i + 1, "Level", "Enum");
 		err = scarlett2_add_new_ctl(mixer, &scarlett2_level_enum_ctl,
-					    i, 1, s, NULL);
+					    i, 1, s, &private->level_ctls[i]);
 		if (err < 0)
 			return err;
 	}
@@ -2029,7 +2071,7 @@ static int scarlett2_add_line_in_ctls(struct usb_mixer_interface *mixer)
 	for (i = 0; i < info->pad_input_count; i++) {
 		snprintf(s, sizeof(s), fmt, i + 1, "Pad", "Switch");
 		err = scarlett2_add_new_ctl(mixer, &scarlett2_pad_ctl,
-					    i, 1, s, NULL);
+					    i, 1, s, &private->pad_ctls[i]);
 		if (err < 0)
 			return err;
 	}
@@ -2441,25 +2483,9 @@ static int scarlett2_read_configs(struct usb_mixer_interface *mixer)
 	struct scarlett2_usb_volume_status volume_status;
 	int err, i;
 
-	if (info->level_input_count) {
-		err = scarlett2_usb_get_config(
-			mixer,
-			SCARLETT2_CONFIG_LEVEL_SWITCH,
-			info->level_input_count,
-			private->level_switch);
-		if (err < 0)
-			return err;
-	}
-
-	if (info->pad_input_count) {
-		err = scarlett2_usb_get_config(
-			mixer,
-			SCARLETT2_CONFIG_PAD_SWITCH,
-			info->pad_input_count,
-			private->pad_switch);
-		if (err < 0)
-			return err;
-	}
+	err = scarlett2_update_input_other(mixer);
+	if (err < 0)
+		return err;
 
 	err = scarlett2_update_sync(mixer);
 	if (err < 0)
@@ -2573,6 +2599,25 @@ static void scarlett2_notify_dim_mute(
 				       &private->mute_ctls[i]->id);
 }
 
+/* Notify on "input other" change (level/pad) */
+static void scarlett2_notify_input_other(
+	struct usb_mixer_interface *mixer)
+{
+	struct snd_card *card = mixer->chip->card;
+	struct scarlett2_data *private = mixer->private_data;
+	const struct scarlett2_device_info *info = private->info;
+	int i;
+
+	private->input_other_updated = 1;
+
+	for (i = 0; i < info->level_input_count; i++)
+		snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+			       &private->level_ctls[i]->id);
+	for (i = 0; i < info->pad_input_count; i++)
+		snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+			       &private->pad_ctls[i]->id);
+}
+
 /* Interrupt callback */
 static void scarlett2_notify(struct urb *urb)
 {
@@ -2591,6 +2636,8 @@ static void scarlett2_notify(struct urb *urb)
 		scarlett2_notify_monitor(mixer);
 	if (data & SCARLETT2_USB_NOTIFY_DIM_MUTE)
 		scarlett2_notify_dim_mute(mixer);
+	if (data & SCARLETT2_USB_NOTIFY_INPUT_OTHER)
+		scarlett2_notify_input_other(mixer);
 
 requeue:
 	if (ustatus != -ENOENT &&
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 18/31] ALSA: usb-audio: scarlett2: Add Gen 3 MSD mode switch
  2021-06-21 18:09 [PATCH 00/31] Refactor Scarlett Gen 2 support and add Scarlett Gen 3 support Geoffrey D. Bennett
                   ` (16 preceding siblings ...)
  2021-06-21 18:09 ` [PATCH 17/31] ALSA: usb-audio: scarlett2: Add support for "input-other" notify Geoffrey D. Bennett
@ 2021-06-21 18:09 ` Geoffrey D. Bennett
  2021-06-21 18:09 ` [PATCH 19/31] ALSA: usb-audio: scarlett2: Move get config above set config Geoffrey D. Bennett
                   ` (12 subsequent siblings)
  30 siblings, 0 replies; 43+ messages in thread
From: Geoffrey D. Bennett @ 2021-06-21 18:09 UTC (permalink / raw)
  To: alsa-devel, Takashi Iwai; +Cc: Hin-Tak Leung, Vladimir Sadovnikov

Add a control to disable the Gen 3 MSD mode so that the full
functionality of the device is available. Don't create the other
controls until MSD mode is disabled.

Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
---
 sound/usb/mixer_scarlett_gen2.c | 120 +++++++++++++++++++++++++++++++-
 1 file changed, 117 insertions(+), 3 deletions(-)

diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c
index a4f92291b74f..6995d692c6b2 100644
--- a/sound/usb/mixer_scarlett_gen2.c
+++ b/sound/usb/mixer_scarlett_gen2.c
@@ -44,12 +44,13 @@
  * 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 (model-dependent):
  *  - input, output, mixer-matrix muxes
  *  - mixer-matrix gain stages
  *  - gain/volume/mute controls
  *  - level meters
  *  - line/inst level and pad controls
+ *  - disable/enable MSD mode
  *
  * <ditaa>
  *    /--------------\    18chn            20chn     /--------------\
@@ -102,6 +103,14 @@
  *  \--------------/
  * </ditaa>
  *
+ * Gen 3 devices have a Mass Storage Device (MSD) mode where a small
+ * disk with registration and driver download information is presented
+ * to the host. To access the full functionality of the device without
+ * proprietary software, MSD mode can be disabled by:
+ * - holding down the 48V button for five seconds while powering on
+ *   the device, or
+ * - using this driver and alsamixer to change the "MSD Mode" setting
+ *   to Off and power-cycling the device
  */
 
 #include <linux/slab.h>
@@ -120,6 +129,9 @@
 /* device_setup value to enable */
 #define SCARLETT2_ENABLE 0x01
 
+/* device_setup value to allow turning MSD mode back on */
+#define SCARLETT2_MSD_ENABLE 0x02
+
 /* some gui mixers can't handle negative ctl values */
 #define SCARLETT2_VOLUME_BIAS 127
 
@@ -279,6 +291,12 @@ struct scarlett2_mux_entry {
 struct scarlett2_device_info {
 	u32 usb_id; /* USB device identifier */
 
+	/* Gen 3 devices have an internal MSD mode switch that needs
+	 * to be disabled in order to access the full functionality of
+	 * the device.
+	 */
+	u8 has_msd_mode;
+
 	/* line out hw volume is sw controlled */
 	u8 line_out_hw_vol;
 
@@ -327,6 +345,7 @@ struct scarlett2_data {
 	u8 level_switch[SCARLETT2_LEVEL_SWITCH_MAX];
 	u8 pad_switch[SCARLETT2_PAD_SWITCH_MAX];
 	u8 dim_mute[SCARLETT2_DIM_MUTE_COUNT];
+	u8 msd_switch;
 	struct snd_kcontrol *sync_ctl;
 	struct snd_kcontrol *master_vol_ctl;
 	struct snd_kcontrol *vol_ctls[SCARLETT2_ANALOGUE_MAX];
@@ -489,6 +508,7 @@ static const struct scarlett2_device_info s18i20_gen2_info = {
 static const struct scarlett2_device_info s4i4_gen3_info = {
 	.usb_id = USB_ID(0x1235, 0x8212),
 
+	.has_msd_mode = 1,
 	.level_input_count = 2,
 	.pad_input_count = 2,
 
@@ -530,6 +550,7 @@ static const struct scarlett2_device_info s4i4_gen3_info = {
 static const struct scarlett2_device_info s8i6_gen3_info = {
 	.usb_id = USB_ID(0x1235, 0x8213),
 
+	.has_msd_mode = 1,
 	.level_input_count = 2,
 	.pad_input_count = 2,
 
@@ -578,6 +599,7 @@ static const struct scarlett2_device_info s8i6_gen3_info = {
 static const struct scarlett2_device_info s18i8_gen3_info = {
 	.usb_id = USB_ID(0x1235, 0x8214),
 
+	.has_msd_mode = 1,
 	.line_out_hw_vol = 1,
 	.level_input_count = 2,
 	.pad_input_count = 2,
@@ -639,6 +661,7 @@ static const struct scarlett2_device_info s18i8_gen3_info = {
 static const struct scarlett2_device_info s18i20_gen3_info = {
 	.usb_id = USB_ID(0x1235, 0x8215),
 
+	.has_msd_mode = 1,
 	.line_out_hw_vol = 1,
 	.level_input_count = 2,
 	.pad_input_count = 8,
@@ -786,7 +809,8 @@ enum {
 	SCARLETT2_CONFIG_SW_HW_SWITCH = 3,
 	SCARLETT2_CONFIG_LEVEL_SWITCH = 4,
 	SCARLETT2_CONFIG_PAD_SWITCH = 5,
-	SCARLETT2_CONFIG_COUNT = 6
+	SCARLETT2_CONFIG_MSD_SWITCH = 6,
+	SCARLETT2_CONFIG_COUNT = 7
 };
 
 /* Location, size, and activation command number for the configuration
@@ -817,6 +841,9 @@ static const struct scarlett2_config
 
 	[SCARLETT2_CONFIG_PAD_SWITCH] = {
 		.offset = 0x84, .size = 1, .activate = 8 },
+
+	[SCARLETT2_CONFIG_MSD_SWITCH] = {
+		.offset = 0x9d, .size = 1, .activate = 6 },
 };
 
 /* proprietary request/response format */
@@ -1016,7 +1043,8 @@ static int scarlett2_usb_set_config(
 		return err;
 
 	/* Schedule the change to be written to NVRAM */
-	schedule_delayed_work(&private->work, msecs_to_jiffies(2000));
+	if (config_item->activate != SCARLETT2_USB_CONFIG_SAVE)
+		schedule_delayed_work(&private->work, msecs_to_jiffies(2000));
 
 	return 0;
 }
@@ -2346,6 +2374,71 @@ static int scarlett2_add_meter_ctl(struct usb_mixer_interface *mixer)
 				     "Level Meter", NULL);
 }
 
+/*** MSD Controls ***/
+
+static int scarlett2_msd_ctl_get(struct snd_kcontrol *kctl,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct usb_mixer_elem_info *elem = kctl->private_data;
+	struct scarlett2_data *private = elem->head.mixer->private_data;
+
+	ucontrol->value.integer.value[0] = private->msd_switch;
+	return 0;
+}
+
+static int scarlett2_msd_ctl_put(struct snd_kcontrol *kctl,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct usb_mixer_elem_info *elem = kctl->private_data;
+	struct usb_mixer_interface *mixer = elem->head.mixer;
+	struct scarlett2_data *private = mixer->private_data;
+
+	int oval, val, err = 0;
+
+	mutex_lock(&private->data_mutex);
+
+	oval = private->msd_switch;
+	val = !!ucontrol->value.integer.value[0];
+
+	if (oval == val)
+		goto unlock;
+
+	private->msd_switch = val;
+
+	/* Send switch change to the device */
+	err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_MSD_SWITCH,
+				       0, val);
+
+unlock:
+	mutex_unlock(&private->data_mutex);
+	return err;
+}
+
+static const struct snd_kcontrol_new scarlett2_msd_ctl = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "",
+	.info = snd_ctl_boolean_mono_info,
+	.get  = scarlett2_msd_ctl_get,
+	.put  = scarlett2_msd_ctl_put,
+};
+
+static int scarlett2_add_msd_ctl(struct usb_mixer_interface *mixer)
+{
+	struct scarlett2_data *private = mixer->private_data;
+	const struct scarlett2_device_info *info = private->info;
+
+	if (!info->has_msd_mode)
+		return 0;
+
+	/* If MSD mode is off, hide the switch by default */
+	if (!private->msd_switch && !(mixer->chip->setup & SCARLETT2_MSD_ENABLE))
+		return 0;
+
+	/* Add MSD control */
+	return scarlett2_add_new_ctl(mixer, &scarlett2_msd_ctl,
+				     0, 1, "MSD Mode", NULL);
+}
+
 /*** Cleanup/Suspend Callbacks ***/
 
 static void scarlett2_private_free(struct usb_mixer_interface *mixer)
@@ -2483,6 +2576,18 @@ static int scarlett2_read_configs(struct usb_mixer_interface *mixer)
 	struct scarlett2_usb_volume_status volume_status;
 	int err, i;
 
+	if (info->has_msd_mode) {
+		err = scarlett2_usb_get_config(
+			mixer, SCARLETT2_CONFIG_MSD_SWITCH,
+			1, &private->msd_switch);
+		if (err < 0)
+			return err;
+
+		/* no other controls are created if MSD mode is on */
+		if (private->msd_switch)
+			return 0;
+	}
+
 	err = scarlett2_update_input_other(mixer);
 	if (err < 0)
 		return err;
@@ -2705,6 +2810,15 @@ static int snd_scarlett_gen2_controls_create(struct usb_mixer_interface *mixer)
 	if (err < 0)
 		return err;
 
+	/* Create the MSD control */
+	err = scarlett2_add_msd_ctl(mixer);
+	if (err < 0)
+		return err;
+
+	/* If MSD mode is enabled, don't create any other controls */
+	if (((struct scarlett2_data *)mixer->private_data)->msd_switch)
+		return 0;
+
 	/* Create the analogue output controls */
 	err = scarlett2_add_line_out_ctls(mixer);
 	if (err < 0)
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 19/31] ALSA: usb-audio: scarlett2: Move get config above set config
  2021-06-21 18:09 [PATCH 00/31] Refactor Scarlett Gen 2 support and add Scarlett Gen 3 support Geoffrey D. Bennett
                   ` (17 preceding siblings ...)
  2021-06-21 18:09 ` [PATCH 18/31] ALSA: usb-audio: scarlett2: Add Gen 3 MSD mode switch Geoffrey D. Bennett
@ 2021-06-21 18:09 ` Geoffrey D. Bennett
  2021-06-21 18:09 ` [PATCH 20/31] ALSA: usb-audio: scarlett2: Allow bit-level access to config Geoffrey D. Bennett
                   ` (11 subsequent siblings)
  30 siblings, 0 replies; 43+ messages in thread
From: Geoffrey D. Bennett @ 2021-06-21 18:09 UTC (permalink / raw)
  To: alsa-devel, Takashi Iwai; +Cc: Hin-Tak Leung, Vladimir Sadovnikov

Move scarlett2_usb_get() and scarlett2_usb_get_config() above the
functions relating to updating the configuration so that
scarlett2_usb_set_config() can call scarlett2_usb_get() in a
subsequent patch.

Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
---
 sound/usb/mixer_scarlett_gen2.c | 56 ++++++++++++++++-----------------
 1 file changed, 28 insertions(+), 28 deletions(-)

diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c
index 6995d692c6b2..87a90cafb175 100644
--- a/sound/usb/mixer_scarlett_gen2.c
+++ b/sound/usb/mixer_scarlett_gen2.c
@@ -985,6 +985,34 @@ static int scarlett2_usb(
 	return err;
 }
 
+/* Send a USB message to get data; result placed in *buf */
+static int scarlett2_usb_get(
+	struct usb_mixer_interface *mixer,
+	int offset, void *buf, int size)
+{
+	struct {
+		__le32 offset;
+		__le32 size;
+	} __packed req;
+
+	req.offset = cpu_to_le32(offset);
+	req.size = cpu_to_le32(size);
+	return scarlett2_usb(mixer, SCARLETT2_USB_GET_DATA,
+			     &req, sizeof(req), buf, size);
+}
+
+/* Send a USB message to get configuration parameters; result placed in *buf */
+static int scarlett2_usb_get_config(
+	struct usb_mixer_interface *mixer,
+	int config_item_num, int count, void *buf)
+{
+	const struct scarlett2_config *config_item =
+		&scarlett2_config_items[config_item_num];
+	int size = config_item->size * count;
+
+	return scarlett2_usb_get(mixer, config_item->offset, buf, size);
+}
+
 /* Send SCARLETT2_USB_DATA_CMD SCARLETT2_USB_CONFIG_SAVE */
 static void scarlett2_config_save(struct usb_mixer_interface *mixer)
 {
@@ -1049,34 +1077,6 @@ static int scarlett2_usb_set_config(
 	return 0;
 }
 
-/* Send a USB message to get data; result placed in *buf */
-static int scarlett2_usb_get(
-	struct usb_mixer_interface *mixer,
-	int offset, void *buf, int size)
-{
-	struct {
-		__le32 offset;
-		__le32 size;
-	} __packed req;
-
-	req.offset = cpu_to_le32(offset);
-	req.size = cpu_to_le32(size);
-	return scarlett2_usb(mixer, SCARLETT2_USB_GET_DATA,
-			     &req, sizeof(req), buf, size);
-}
-
-/* Send a USB message to get configuration parameters; result placed in *buf */
-static int scarlett2_usb_get_config(
-	struct usb_mixer_interface *mixer,
-	int config_item_num, int count, void *buf)
-{
-	const struct scarlett2_config *config_item =
-		&scarlett2_config_items[config_item_num];
-	int size = config_item->size * count;
-
-	return scarlett2_usb_get(mixer, config_item->offset, buf, size);
-}
-
 /* Send a USB message to get sync status; result placed in *sync */
 static int scarlett2_usb_get_sync_status(
 	struct usb_mixer_interface *mixer,
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 20/31] ALSA: usb-audio: scarlett2: Allow bit-level access to config
  2021-06-21 18:09 [PATCH 00/31] Refactor Scarlett Gen 2 support and add Scarlett Gen 3 support Geoffrey D. Bennett
                   ` (18 preceding siblings ...)
  2021-06-21 18:09 ` [PATCH 19/31] ALSA: usb-audio: scarlett2: Move get config above set config Geoffrey D. Bennett
@ 2021-06-21 18:09 ` Geoffrey D. Bennett
  2021-06-21 18:09 ` [PATCH 21/31] ALSA: usb-audio: scarlett2: Add support for Solo and 2i2 Gen 3 Geoffrey D. Bennett
                   ` (10 subsequent siblings)
  30 siblings, 0 replies; 43+ messages in thread
From: Geoffrey D. Bennett @ 2021-06-21 18:09 UTC (permalink / raw)
  To: alsa-devel, Takashi Iwai; +Cc: Hin-Tak Leung, Vladimir Sadovnikov

Add support for accessing configuration values when multiple values
are stored in one byte. Needed by the upcoming Solo and 2i2 Gen 3
support.

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

diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c
index 87a90cafb175..45b28585dacb 100644
--- a/sound/usb/mixer_scarlett_gen2.c
+++ b/sound/usb/mixer_scarlett_gen2.c
@@ -814,7 +814,7 @@ enum {
 };
 
 /* Location, size, and activation command number for the configuration
- * parameters
+ * parameters. Size is in bits and may be 1, 8, or 16.
  */
 struct scarlett2_config {
 	u8 offset;
@@ -825,25 +825,25 @@ struct scarlett2_config {
 static const struct scarlett2_config
 		scarlett2_config_items[SCARLETT2_CONFIG_COUNT] = {
 	[SCARLETT2_CONFIG_DIM_MUTE] = {
-		.offset = 0x31, .size = 1, .activate = 2 },
+		.offset = 0x31, .size = 8, .activate = 2 },
 
 	[SCARLETT2_CONFIG_LINE_OUT_VOLUME] = {
-		.offset = 0x34, .size = 2, .activate = 1 },
+		.offset = 0x34, .size = 16, .activate = 1 },
 
 	[SCARLETT2_CONFIG_MUTE_SWITCH] = {
-		.offset = 0x5c, .size = 1, .activate = 1 },
+		.offset = 0x5c, .size = 8, .activate = 1 },
 
 	[SCARLETT2_CONFIG_SW_HW_SWITCH] = {
-		.offset = 0x66, .size = 1, .activate = 3 },
+		.offset = 0x66, .size = 8, .activate = 3 },
 
 	[SCARLETT2_CONFIG_LEVEL_SWITCH] = {
-		.offset = 0x7c, .size = 1, .activate = 7 },
+		.offset = 0x7c, .size = 8, .activate = 7 },
 
 	[SCARLETT2_CONFIG_PAD_SWITCH] = {
-		.offset = 0x84, .size = 1, .activate = 8 },
+		.offset = 0x84, .size = 8, .activate = 8 },
 
 	[SCARLETT2_CONFIG_MSD_SWITCH] = {
-		.offset = 0x9d, .size = 1, .activate = 6 },
+		.offset = 0x9d, .size = 8, .activate = 6 },
 };
 
 /* proprietary request/response format */
@@ -1008,9 +1008,25 @@ static int scarlett2_usb_get_config(
 {
 	const struct scarlett2_config *config_item =
 		&scarlett2_config_items[config_item_num];
-	int size = config_item->size * count;
+	int size, err, i;
+	u8 value;
 
-	return scarlett2_usb_get(mixer, config_item->offset, buf, size);
+	/* For byte-sized parameters, retrieve directly into buf */
+	if (config_item->size >= 8) {
+		size = config_item->size / 8 * count;
+		return scarlett2_usb_get(mixer, config_item->offset, buf, size);
+	}
+
+	/* For bit-sized parameters, retrieve into value */
+	err = scarlett2_usb_get(mixer, config_item->offset, &value, 1);
+	if (err < 0)
+		return err;
+
+	/* then unpack from value into buf[] */
+	for (i = 0; i < 8 && i < count; i++, value >>= 1)
+		*(u8 *)buf++ = value & 1;
+
+	return 0;
 }
 
 /* Send SCARLETT2_USB_DATA_CMD SCARLETT2_USB_CONFIG_SAVE */
@@ -1047,18 +1063,44 @@ static int scarlett2_usb_set_config(
 		__le32 value;
 	} __packed req;
 	__le32 req2;
+	int offset, size;
 	int err;
 	struct scarlett2_data *private = mixer->private_data;
 
 	/* Cancel any pending NVRAM save */
 	cancel_delayed_work_sync(&private->work);
 
+	/* Convert config_item->size in bits to size in bytes and
+	 * calculate offset
+	 */
+	if (config_item->size >= 8) {
+		size = config_item->size / 8;
+		offset = config_item->offset + index * size;
+
+	/* If updating a bit, retrieve the old value, set/clear the
+	 * bit as needed, and update value
+	 */
+	} else {
+		u8 tmp;
+
+		size = 1;
+		offset = config_item->offset;
+
+		scarlett2_usb_get(mixer, offset, &tmp, 1);
+		if (value)
+			tmp |= (1 << index);
+		else
+			tmp &= ~(1 << index);
+
+		value = tmp;
+	}
+
 	/* Send the configuration parameter data */
-	req.offset = cpu_to_le32(config_item->offset + index * config_item->size);
-	req.bytes = cpu_to_le32(config_item->size);
+	req.offset = cpu_to_le32(offset);
+	req.bytes = cpu_to_le32(size);
 	req.value = cpu_to_le32(value);
 	err = scarlett2_usb(mixer, SCARLETT2_USB_SET_DATA,
-			    &req, sizeof(u32) * 2 + config_item->size,
+			    &req, sizeof(u32) * 2 + size,
 			    NULL, 0);
 	if (err < 0)
 		return err;
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 21/31] ALSA: usb-audio: scarlett2: Add support for Solo and 2i2 Gen 3
  2021-06-21 18:09 [PATCH 00/31] Refactor Scarlett Gen 2 support and add Scarlett Gen 3 support Geoffrey D. Bennett
                   ` (19 preceding siblings ...)
  2021-06-21 18:09 ` [PATCH 20/31] ALSA: usb-audio: scarlett2: Allow bit-level access to config Geoffrey D. Bennett
@ 2021-06-21 18:09 ` Geoffrey D. Bennett
  2021-06-21 18:10 ` [PATCH 22/31] ALSA: usb-audio: scarlett2: Add "air" switch support Geoffrey D. Bennett
                   ` (9 subsequent siblings)
  30 siblings, 0 replies; 43+ messages in thread
From: Geoffrey D. Bennett @ 2021-06-21 18:09 UTC (permalink / raw)
  To: alsa-devel, Takashi Iwai; +Cc: Hin-Tak Leung, Vladimir Sadovnikov

Add initial support for the Focusrite Scarlett Solo and 2i2 devices:
- They have no mixer
- They don't support reporting sync status or levels
- The configuration space is laid out differently to the other models
- There is no level (line/inst) switch on input 1 of the Solo

Co-developed-by: Vladimir Sadovnikov <sadko4u@gmail.com>
Signed-off-by: Vladimir Sadovnikov <sadko4u@gmail.com>
Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
---
 sound/usb/mixer_quirks.c        |  2 +
 sound/usb/mixer_scarlett_gen2.c | 94 ++++++++++++++++++++++++++++-----
 2 files changed, 84 insertions(+), 12 deletions(-)

diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index df7492594e91..0a3cb8fd7d00 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -3060,6 +3060,8 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
 	case USB_ID(0x1235, 0x8203): /* Focusrite Scarlett 6i6 2nd Gen */
 	case USB_ID(0x1235, 0x8204): /* Focusrite Scarlett 18i8 2nd Gen */
 	case USB_ID(0x1235, 0x8201): /* Focusrite Scarlett 18i20 2nd Gen */
+	case USB_ID(0x1235, 0x8211): /* Focusrite Scarlett Solo 3rd Gen */
+	case USB_ID(0x1235, 0x8210): /* Focusrite Scarlett 2i2 3rd Gen */
 	case USB_ID(0x1235, 0x8212): /* Focusrite Scarlett 4i4 3rd Gen */
 	case USB_ID(0x1235, 0x8213): /* Focusrite Scarlett 8i6 3rd Gen */
 	case USB_ID(0x1235, 0x8214): /* Focusrite Scarlett 18i8 3rd Gen */
diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c
index 45b28585dacb..50a90693482f 100644
--- a/sound/usb/mixer_scarlett_gen2.c
+++ b/sound/usb/mixer_scarlett_gen2.c
@@ -4,9 +4,10 @@
  *
  *   Supported models:
  *   - 6i6/18i8/18i20 Gen 2
- *   - 4i4/8i6/18i8/18i20 Gen 3
+ *   - Solo/2i2/4i4/8i6/18i8/18i20 Gen 3
  *
  *   Copyright (c) 2018-2021 by Geoffrey D. Bennett <g at b4.vu>
+ *   Copyright (c) 2020-2021 by Vladimir Sadovnikov <sadko4u@gmail.com>
  *
  *   Based on the Scarlett (Gen 1) Driver for ALSA:
  *
@@ -44,6 +45,9 @@
  * interface during driver initialisation added in May 2021 (thanks to
  * Vladimir Sadovnikov for figuring out how).
  *
+ * Support for Solo/2i2 Gen 3 added in May 2021 (thanks to Alexander
+ * Vorona for 2i2 protocol traces).
+ *
  * This ALSA mixer gives access to (model-dependent):
  *  - input, output, mixer-matrix muxes
  *  - mixer-matrix gain stages
@@ -297,6 +301,11 @@ struct scarlett2_device_info {
 	 */
 	u8 has_msd_mode;
 
+	/* Gen 3 devices without a mixer have a different
+	 * configuration set
+	 */
+	u8 has_mixer;
+
 	/* line out hw volume is sw controlled */
 	u8 line_out_hw_vol;
 
@@ -305,6 +314,9 @@ struct scarlett2_device_info {
 	 */
 	u8 level_input_count;
 
+	/* the first input with a level control (0-based) */
+	u8 level_input_first;
+
 	/* the number of analogue inputs with a software switchable
 	 * 10dB pad control
 	 */
@@ -362,6 +374,7 @@ struct scarlett2_data {
 static const struct scarlett2_device_info s6i6_gen2_info = {
 	.usb_id = USB_ID(0x1235, 0x8203),
 
+	.has_mixer = 1,
 	.level_input_count = 2,
 	.pad_input_count = 2,
 
@@ -407,6 +420,7 @@ static const struct scarlett2_device_info s6i6_gen2_info = {
 static const struct scarlett2_device_info s18i8_gen2_info = {
 	.usb_id = USB_ID(0x1235, 0x8204),
 
+	.has_mixer = 1,
 	.level_input_count = 2,
 	.pad_input_count = 4,
 
@@ -455,6 +469,7 @@ static const struct scarlett2_device_info s18i8_gen2_info = {
 static const struct scarlett2_device_info s18i20_gen2_info = {
 	.usb_id = USB_ID(0x1235, 0x8201),
 
+	.has_mixer = 1,
 	.line_out_hw_vol = 1,
 
 	.line_out_descrs = {
@@ -505,10 +520,26 @@ static const struct scarlett2_device_info s18i20_gen2_info = {
 	} },
 };
 
+static const struct scarlett2_device_info solo_gen3_info = {
+	.usb_id = USB_ID(0x1235, 0x8211),
+
+	.has_msd_mode = 1,
+	.level_input_count = 1,
+	.level_input_first = 1,
+};
+
+static const struct scarlett2_device_info s2i2_gen3_info = {
+	.usb_id = USB_ID(0x1235, 0x8210),
+
+	.has_msd_mode = 1,
+	.level_input_count = 2,
+};
+
 static const struct scarlett2_device_info s4i4_gen3_info = {
 	.usb_id = USB_ID(0x1235, 0x8212),
 
 	.has_msd_mode = 1,
+	.has_mixer = 1,
 	.level_input_count = 2,
 	.pad_input_count = 2,
 
@@ -551,6 +582,7 @@ static const struct scarlett2_device_info s8i6_gen3_info = {
 	.usb_id = USB_ID(0x1235, 0x8213),
 
 	.has_msd_mode = 1,
+	.has_mixer = 1,
 	.level_input_count = 2,
 	.pad_input_count = 2,
 
@@ -600,6 +632,7 @@ static const struct scarlett2_device_info s18i8_gen3_info = {
 	.usb_id = USB_ID(0x1235, 0x8214),
 
 	.has_msd_mode = 1,
+	.has_mixer = 1,
 	.line_out_hw_vol = 1,
 	.level_input_count = 2,
 	.pad_input_count = 2,
@@ -662,6 +695,7 @@ static const struct scarlett2_device_info s18i20_gen3_info = {
 	.usb_id = USB_ID(0x1235, 0x8215),
 
 	.has_msd_mode = 1,
+	.has_mixer = 1,
 	.line_out_hw_vol = 1,
 	.level_input_count = 2,
 	.pad_input_count = 8,
@@ -724,6 +758,8 @@ static const struct scarlett2_device_info *scarlett2_devices[] = {
 	&s18i20_gen2_info,
 
 	/* Supported Gen 3 devices */
+	&solo_gen3_info,
+	&s2i2_gen3_info,
 	&s4i4_gen3_info,
 	&s8i6_gen3_info,
 	&s18i8_gen3_info,
@@ -776,7 +812,7 @@ static int scarlett2_get_port_start_num(
 #define SCARLETT2_USB_VOLUME_STATUS_OFFSET 0x31
 #define SCARLETT2_USB_METER_LEVELS_GET_MAGIC 1
 
-/* volume status is read together (matches scarlett2_config_items[]) */
+/* volume status is read together (matches scarlett2_config_items[1]) */
 struct scarlett2_usb_volume_status {
 	/* dim/mute buttons */
 	u8 dim_mute[SCARLETT2_DIM_MUTE_COUNT];
@@ -822,8 +858,22 @@ struct scarlett2_config {
 	u8 activate;
 };
 
+/* scarlett2_config_items[0] is for devices without a mixer
+ * scarlett2_config_items[1] is for devices with a mixer
+ */
 static const struct scarlett2_config
-		scarlett2_config_items[SCARLETT2_CONFIG_COUNT] = {
+	scarlett2_config_items[2][SCARLETT2_CONFIG_COUNT] =
+
+/* Devices without a mixer (Solo and 2i2 Gen 3) */
+{ {
+	[SCARLETT2_CONFIG_MSD_SWITCH] = {
+		.offset = 0x04, .size = 8, .activate = 6 },
+
+	[SCARLETT2_CONFIG_LEVEL_SWITCH] = {
+		.offset = 0x08, .size = 1, .activate = 7 },
+
+/* Devices with a mixer (Gen 2 and all other Gen 3) */
+}, {
 	[SCARLETT2_CONFIG_DIM_MUTE] = {
 		.offset = 0x31, .size = 8, .activate = 2 },
 
@@ -844,7 +894,7 @@ static const struct scarlett2_config
 
 	[SCARLETT2_CONFIG_MSD_SWITCH] = {
 		.offset = 0x9d, .size = 8, .activate = 6 },
-};
+} };
 
 /* proprietary request/response format */
 struct scarlett2_usb_packet {
@@ -1006,8 +1056,10 @@ static int scarlett2_usb_get_config(
 	struct usb_mixer_interface *mixer,
 	int config_item_num, int count, void *buf)
 {
+	struct scarlett2_data *private = mixer->private_data;
+	const struct scarlett2_device_info *info = private->info;
 	const struct scarlett2_config *config_item =
-		&scarlett2_config_items[config_item_num];
+		&scarlett2_config_items[info->has_mixer][config_item_num];
 	int size, err, i;
 	u8 value;
 
@@ -1055,8 +1107,10 @@ static int scarlett2_usb_set_config(
 	struct usb_mixer_interface *mixer,
 	int config_item_num, int index, int value)
 {
+	struct scarlett2_data *private = mixer->private_data;
+	const struct scarlett2_device_info *info = private->info;
 	const struct scarlett2_config *config_item =
-	       &scarlett2_config_items[config_item_num];
+	       &scarlett2_config_items[info->has_mixer][config_item_num];
 	struct {
 		__le32 offset;
 		__le32 bytes;
@@ -1065,7 +1119,6 @@ static int scarlett2_usb_set_config(
 	__le32 req2;
 	int offset, size;
 	int err;
-	struct scarlett2_data *private = mixer->private_data;
 
 	/* Cancel any pending NVRAM save */
 	cancel_delayed_work_sync(&private->work);
@@ -1506,6 +1559,10 @@ static int scarlett2_add_sync_ctl(struct usb_mixer_interface *mixer)
 {
 	struct scarlett2_data *private = mixer->private_data;
 
+	/* devices without a mixer also don't support reporting sync status */
+	if (!private->info->has_mixer)
+		return 0;
+
 	return scarlett2_add_new_ctl(mixer, &scarlett2_sync_ctl,
 				     0, 1, "Sync Status", &private->sync_ctl);
 }
@@ -1824,7 +1881,8 @@ static int scarlett2_update_input_other(struct usb_mixer_interface *mixer)
 	if (info->level_input_count) {
 		int err = scarlett2_usb_get_config(
 			mixer, SCARLETT2_CONFIG_LEVEL_SWITCH,
-			info->level_input_count, private->level_switch);
+			info->level_input_count + info->level_input_first,
+			private->level_switch);
 		if (err < 0)
 			return err;
 	}
@@ -1856,12 +1914,14 @@ static int scarlett2_level_enum_ctl_get(struct snd_kcontrol *kctl,
 	struct usb_mixer_elem_info *elem = kctl->private_data;
 	struct usb_mixer_interface *mixer = elem->head.mixer;
 	struct scarlett2_data *private = mixer->private_data;
+	const struct scarlett2_device_info *info = private->info;
+
+	int index = elem->control + info->level_input_first;
 
 	mutex_lock(&private->data_mutex);
 	if (private->input_other_updated)
 		scarlett2_update_input_other(mixer);
-	ucontrol->value.enumerated.item[0] =
-		private->level_switch[elem->control];
+	ucontrol->value.enumerated.item[0] = private->level_switch[index];
 	mutex_unlock(&private->data_mutex);
 
 	return 0;
@@ -1873,8 +1933,9 @@ static int scarlett2_level_enum_ctl_put(struct snd_kcontrol *kctl,
 	struct usb_mixer_elem_info *elem = kctl->private_data;
 	struct usb_mixer_interface *mixer = elem->head.mixer;
 	struct scarlett2_data *private = mixer->private_data;
+	const struct scarlett2_device_info *info = private->info;
 
-	int index = elem->control;
+	int index = elem->control + info->level_input_first;
 	int oval, val, err = 0;
 
 	mutex_lock(&private->data_mutex);
@@ -2130,7 +2191,8 @@ static int scarlett2_add_line_in_ctls(struct usb_mixer_interface *mixer)
 
 	/* Add input level (line/inst) controls */
 	for (i = 0; i < info->level_input_count; i++) {
-		snprintf(s, sizeof(s), fmt, i + 1, "Level", "Enum");
+		snprintf(s, sizeof(s), fmt, i + 1 + info->level_input_first,
+			 "Level", "Enum");
 		err = scarlett2_add_new_ctl(mixer, &scarlett2_level_enum_ctl,
 					    i, 1, s, &private->level_ctls[i]);
 		if (err < 0)
@@ -2411,6 +2473,10 @@ static int scarlett2_add_meter_ctl(struct usb_mixer_interface *mixer)
 {
 	struct scarlett2_data *private = mixer->private_data;
 
+	/* devices without a mixer also don't support reporting levels */
+	if (!private->info->has_mixer)
+		return 0;
+
 	return scarlett2_add_new_ctl(mixer, &scarlett2_meter_ctl,
 				     0, private->num_mux_dsts,
 				     "Level Meter", NULL);
@@ -2634,6 +2700,10 @@ static int scarlett2_read_configs(struct usb_mixer_interface *mixer)
 	if (err < 0)
 		return err;
 
+	/* the rest of the configuration is for devices with a mixer */
+	if (!info->has_mixer)
+		return 0;
+
 	err = scarlett2_update_sync(mixer);
 	if (err < 0)
 		return err;
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 22/31] ALSA: usb-audio: scarlett2: Add "air" switch support
  2021-06-21 18:09 [PATCH 00/31] Refactor Scarlett Gen 2 support and add Scarlett Gen 3 support Geoffrey D. Bennett
                   ` (20 preceding siblings ...)
  2021-06-21 18:09 ` [PATCH 21/31] ALSA: usb-audio: scarlett2: Add support for Solo and 2i2 Gen 3 Geoffrey D. Bennett
@ 2021-06-21 18:10 ` Geoffrey D. Bennett
  2021-06-21 18:10 ` [PATCH 23/31] ALSA: usb-audio: scarlett2: Add phantom power " Geoffrey D. Bennett
                   ` (8 subsequent siblings)
  30 siblings, 0 replies; 43+ messages in thread
From: Geoffrey D. Bennett @ 2021-06-21 18:10 UTC (permalink / raw)
  To: alsa-devel, Takashi Iwai; +Cc: Hin-Tak Leung, Vladimir Sadovnikov

Some inputs on Gen 3 models have an "air" feature which can be enabled
from the driver or (model-dependent) from the front panel. Add support
for getting and setting the state of those switches.

Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
---
 sound/usb/mixer_scarlett_gen2.c | 106 ++++++++++++++++++++++++++++++--
 1 file changed, 100 insertions(+), 6 deletions(-)

diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c
index 50a90693482f..a8c5a28f21c9 100644
--- a/sound/usb/mixer_scarlett_gen2.c
+++ b/sound/usb/mixer_scarlett_gen2.c
@@ -53,7 +53,7 @@
  *  - mixer-matrix gain stages
  *  - gain/volume/mute controls
  *  - level meters
- *  - line/inst level and pad controls
+ *  - line/inst level, pad, and air controls
  *  - disable/enable MSD mode
  *
  * <ditaa>
@@ -173,6 +173,7 @@ static const u16 scarlett2_mixer_values[SCARLETT2_MIXER_VALUE_COUNT] = {
 /* Maximum number of level and pad switches */
 #define SCARLETT2_LEVEL_SWITCH_MAX 2
 #define SCARLETT2_PAD_SWITCH_MAX 8
+#define SCARLETT2_AIR_SWITCH_MAX 8
 
 /* Maximum number of inputs to the mixer */
 #define SCARLETT2_INPUT_MIX_MAX 25
@@ -322,6 +323,11 @@ struct scarlett2_device_info {
 	 */
 	u8 pad_input_count;
 
+	/* the number of analogue inputs with a software switchable
+	 * "air" control
+	 */
+	u8 air_input_count;
+
 	/* additional description for the line out volume controls */
 	const char * const line_out_descrs[SCARLETT2_ANALOGUE_MAX];
 
@@ -357,6 +363,7 @@ struct scarlett2_data {
 	u8 level_switch[SCARLETT2_LEVEL_SWITCH_MAX];
 	u8 pad_switch[SCARLETT2_PAD_SWITCH_MAX];
 	u8 dim_mute[SCARLETT2_DIM_MUTE_COUNT];
+	u8 air_switch[SCARLETT2_AIR_SWITCH_MAX];
 	u8 msd_switch;
 	struct snd_kcontrol *sync_ctl;
 	struct snd_kcontrol *master_vol_ctl;
@@ -365,6 +372,7 @@ struct scarlett2_data {
 	struct snd_kcontrol *dim_mute_ctls[SCARLETT2_DIM_MUTE_COUNT];
 	struct snd_kcontrol *level_ctls[SCARLETT2_LEVEL_SWITCH_MAX];
 	struct snd_kcontrol *pad_ctls[SCARLETT2_PAD_SWITCH_MAX];
+	struct snd_kcontrol *air_ctls[SCARLETT2_AIR_SWITCH_MAX];
 	u8 mux[SCARLETT2_MUX_MAX];
 	u8 mix[SCARLETT2_INPUT_MIX_MAX * SCARLETT2_OUTPUT_MIX_MAX];
 };
@@ -526,6 +534,7 @@ static const struct scarlett2_device_info solo_gen3_info = {
 	.has_msd_mode = 1,
 	.level_input_count = 1,
 	.level_input_first = 1,
+	.air_input_count = 1,
 };
 
 static const struct scarlett2_device_info s2i2_gen3_info = {
@@ -533,6 +542,7 @@ static const struct scarlett2_device_info s2i2_gen3_info = {
 
 	.has_msd_mode = 1,
 	.level_input_count = 2,
+	.air_input_count = 2,
 };
 
 static const struct scarlett2_device_info s4i4_gen3_info = {
@@ -542,6 +552,7 @@ static const struct scarlett2_device_info s4i4_gen3_info = {
 	.has_mixer = 1,
 	.level_input_count = 2,
 	.pad_input_count = 2,
+	.air_input_count = 2,
 
 	.line_out_descrs = {
 		"Monitor L",
@@ -585,6 +596,7 @@ static const struct scarlett2_device_info s8i6_gen3_info = {
 	.has_mixer = 1,
 	.level_input_count = 2,
 	.pad_input_count = 2,
+	.air_input_count = 2,
 
 	.line_out_descrs = {
 		"Headphones 1 L",
@@ -636,6 +648,7 @@ static const struct scarlett2_device_info s18i8_gen3_info = {
 	.line_out_hw_vol = 1,
 	.level_input_count = 2,
 	.pad_input_count = 2,
+	.air_input_count = 4,
 
 	.line_out_descrs = {
 		"Monitor L",
@@ -699,6 +712,7 @@ static const struct scarlett2_device_info s18i20_gen3_info = {
 	.line_out_hw_vol = 1,
 	.level_input_count = 2,
 	.pad_input_count = 8,
+	.air_input_count = 8,
 
 	.line_out_descrs = {
 		"Monitor 1 L",
@@ -846,7 +860,8 @@ enum {
 	SCARLETT2_CONFIG_LEVEL_SWITCH = 4,
 	SCARLETT2_CONFIG_PAD_SWITCH = 5,
 	SCARLETT2_CONFIG_MSD_SWITCH = 6,
-	SCARLETT2_CONFIG_COUNT = 7
+	SCARLETT2_CONFIG_AIR_SWITCH = 7,
+	SCARLETT2_CONFIG_COUNT = 8
 };
 
 /* Location, size, and activation command number for the configuration
@@ -872,6 +887,9 @@ static const struct scarlett2_config
 	[SCARLETT2_CONFIG_LEVEL_SWITCH] = {
 		.offset = 0x08, .size = 1, .activate = 7 },
 
+	[SCARLETT2_CONFIG_AIR_SWITCH] = {
+		.offset = 0x09, .size = 1, .activate = 8 },
+
 /* Devices with a mixer (Gen 2 and all other Gen 3) */
 }, {
 	[SCARLETT2_CONFIG_DIM_MUTE] = {
@@ -892,6 +910,9 @@ static const struct scarlett2_config
 	[SCARLETT2_CONFIG_PAD_SWITCH] = {
 		.offset = 0x84, .size = 8, .activate = 8 },
 
+	[SCARLETT2_CONFIG_AIR_SWITCH] = {
+		.offset = 0x8c, .size = 8, .activate = 8 },
+
 	[SCARLETT2_CONFIG_MSD_SWITCH] = {
 		.offset = 0x9d, .size = 8, .activate = 6 },
 } };
@@ -1100,9 +1121,7 @@ static void scarlett2_config_save_work(struct work_struct *work)
 	scarlett2_config_save(private->mixer);
 }
 
-/* Send a USB message to set a configuration parameter (volume level,
- * sw/hw volume switch, line/inst level switch, or pad switch)
- */
+/* Send a USB message to set a SCARLETT2_CONFIG_* parameter */
 static int scarlett2_usb_set_config(
 	struct usb_mixer_interface *mixer,
 	int config_item_num, int index, int value)
@@ -1895,6 +1914,14 @@ static int scarlett2_update_input_other(struct usb_mixer_interface *mixer)
 			return err;
 	}
 
+	if (info->air_input_count) {
+		int err = scarlett2_usb_get_config(
+			mixer, SCARLETT2_CONFIG_AIR_SWITCH,
+			info->air_input_count, private->air_switch);
+		if (err < 0)
+			return err;
+	}
+
 	return 0;
 }
 
@@ -2025,6 +2052,61 @@ static const struct snd_kcontrol_new scarlett2_pad_ctl = {
 	.put  = scarlett2_pad_ctl_put,
 };
 
+/*** Air Switch Controls ***/
+
+static int scarlett2_air_ctl_get(struct snd_kcontrol *kctl,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct usb_mixer_elem_info *elem = kctl->private_data;
+	struct usb_mixer_interface *mixer = elem->head.mixer;
+	struct scarlett2_data *private = mixer->private_data;
+
+	mutex_lock(&private->data_mutex);
+	if (private->input_other_updated)
+		scarlett2_update_input_other(mixer);
+	ucontrol->value.integer.value[0] = private->air_switch[elem->control];
+	mutex_unlock(&private->data_mutex);
+
+	return 0;
+}
+
+static int scarlett2_air_ctl_put(struct snd_kcontrol *kctl,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct usb_mixer_elem_info *elem = kctl->private_data;
+	struct usb_mixer_interface *mixer = elem->head.mixer;
+	struct scarlett2_data *private = mixer->private_data;
+
+	int index = elem->control;
+	int oval, val, err = 0;
+
+	mutex_lock(&private->data_mutex);
+
+	oval = private->air_switch[index];
+	val = !!ucontrol->value.integer.value[0];
+
+	if (oval == val)
+		goto unlock;
+
+	private->air_switch[index] = val;
+
+	/* Send switch change to the device */
+	err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_AIR_SWITCH,
+				       index, val);
+
+unlock:
+	mutex_unlock(&private->data_mutex);
+	return err;
+}
+
+static const struct snd_kcontrol_new scarlett2_air_ctl = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "",
+	.info = snd_ctl_boolean_mono_info,
+	.get  = scarlett2_air_ctl_get,
+	.put  = scarlett2_air_ctl_put,
+};
+
 /*** Dim/Mute Controls ***/
 
 static int scarlett2_dim_mute_ctl_get(struct snd_kcontrol *kctl,
@@ -2208,6 +2290,15 @@ static int scarlett2_add_line_in_ctls(struct usb_mixer_interface *mixer)
 			return err;
 	}
 
+	/* Add input air controls */
+	for (i = 0; i < info->air_input_count; i++) {
+		snprintf(s, sizeof(s), fmt, i + 1, "Air", "Switch");
+		err = scarlett2_add_new_ctl(mixer, &scarlett2_air_ctl,
+					    i, 1, s, &private->air_ctls[i]);
+		if (err < 0)
+			return err;
+	}
+
 	return 0;
 }
 
@@ -2816,7 +2907,7 @@ static void scarlett2_notify_dim_mute(
 				       &private->mute_ctls[i]->id);
 }
 
-/* Notify on "input other" change (level/pad) */
+/* Notify on "input other" change (level/pad/air) */
 static void scarlett2_notify_input_other(
 	struct usb_mixer_interface *mixer)
 {
@@ -2833,6 +2924,9 @@ static void scarlett2_notify_input_other(
 	for (i = 0; i < info->pad_input_count; i++)
 		snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
 			       &private->pad_ctls[i]->id);
+	for (i = 0; i < info->air_input_count; i++)
+		snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+			       &private->air_ctls[i]->id);
 }
 
 /* Interrupt callback */
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 23/31] ALSA: usb-audio: scarlett2: Add phantom power switch support
  2021-06-21 18:09 [PATCH 00/31] Refactor Scarlett Gen 2 support and add Scarlett Gen 3 support Geoffrey D. Bennett
                   ` (21 preceding siblings ...)
  2021-06-21 18:10 ` [PATCH 22/31] ALSA: usb-audio: scarlett2: Add "air" switch support Geoffrey D. Bennett
@ 2021-06-21 18:10 ` Geoffrey D. Bennett
  2021-06-21 18:10 ` [PATCH 24/31] ALSA: usb-audio: scarlett2: Add direct monitor support Geoffrey D. Bennett
                   ` (7 subsequent siblings)
  30 siblings, 0 replies; 43+ messages in thread
From: Geoffrey D. Bennett @ 2021-06-21 18:10 UTC (permalink / raw)
  To: alsa-devel, Takashi Iwai; +Cc: Hin-Tak Leung, Vladimir Sadovnikov

Some inputs on Gen 3 models support software-selectable phantom power.
Add support for getting and setting the state of those switches and
the "Phantom Power Persistence" switch.

Co-developed-by: Vladimir Sadovnikov <sadko4u@gmail.com>
Signed-off-by: Vladimir Sadovnikov <sadko4u@gmail.com>
Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
---
 sound/usb/mixer_scarlett_gen2.c | 197 +++++++++++++++++++++++++++++++-
 1 file changed, 196 insertions(+), 1 deletion(-)

diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c
index a8c5a28f21c9..87672e6b4505 100644
--- a/sound/usb/mixer_scarlett_gen2.c
+++ b/sound/usb/mixer_scarlett_gen2.c
@@ -48,12 +48,15 @@
  * Support for Solo/2i2 Gen 3 added in May 2021 (thanks to Alexander
  * Vorona for 2i2 protocol traces).
  *
+ * Support for phantom power added in May 2021.
+ *
  * This ALSA mixer gives access to (model-dependent):
  *  - input, output, mixer-matrix muxes
  *  - mixer-matrix gain stages
  *  - gain/volume/mute controls
  *  - level meters
  *  - line/inst level, pad, and air controls
+ *  - phantom power controls
  *  - disable/enable MSD mode
  *
  * <ditaa>
@@ -174,6 +177,7 @@ static const u16 scarlett2_mixer_values[SCARLETT2_MIXER_VALUE_COUNT] = {
 #define SCARLETT2_LEVEL_SWITCH_MAX 2
 #define SCARLETT2_PAD_SWITCH_MAX 8
 #define SCARLETT2_AIR_SWITCH_MAX 8
+#define SCARLETT2_PHANTOM_SWITCH_MAX 2
 
 /* Maximum number of inputs to the mixer */
 #define SCARLETT2_INPUT_MIX_MAX 25
@@ -328,6 +332,12 @@ struct scarlett2_device_info {
 	 */
 	u8 air_input_count;
 
+	/* the number of phantom (48V) software switchable controls */
+	u8 phantom_count;
+
+	/* the number of inputs each phantom switch controls */
+	u8 inputs_per_phantom;
+
 	/* additional description for the line out volume controls */
 	const char * const line_out_descrs[SCARLETT2_ANALOGUE_MAX];
 
@@ -364,6 +374,8 @@ struct scarlett2_data {
 	u8 pad_switch[SCARLETT2_PAD_SWITCH_MAX];
 	u8 dim_mute[SCARLETT2_DIM_MUTE_COUNT];
 	u8 air_switch[SCARLETT2_AIR_SWITCH_MAX];
+	u8 phantom_switch[SCARLETT2_PHANTOM_SWITCH_MAX];
+	u8 phantom_persistence;
 	u8 msd_switch;
 	struct snd_kcontrol *sync_ctl;
 	struct snd_kcontrol *master_vol_ctl;
@@ -373,6 +385,7 @@ struct scarlett2_data {
 	struct snd_kcontrol *level_ctls[SCARLETT2_LEVEL_SWITCH_MAX];
 	struct snd_kcontrol *pad_ctls[SCARLETT2_PAD_SWITCH_MAX];
 	struct snd_kcontrol *air_ctls[SCARLETT2_AIR_SWITCH_MAX];
+	struct snd_kcontrol *phantom_ctls[SCARLETT2_PHANTOM_SWITCH_MAX];
 	u8 mux[SCARLETT2_MUX_MAX];
 	u8 mix[SCARLETT2_INPUT_MIX_MAX * SCARLETT2_OUTPUT_MIX_MAX];
 };
@@ -535,6 +548,8 @@ static const struct scarlett2_device_info solo_gen3_info = {
 	.level_input_count = 1,
 	.level_input_first = 1,
 	.air_input_count = 1,
+	.phantom_count = 1,
+	.inputs_per_phantom = 1,
 };
 
 static const struct scarlett2_device_info s2i2_gen3_info = {
@@ -543,6 +558,8 @@ static const struct scarlett2_device_info s2i2_gen3_info = {
 	.has_msd_mode = 1,
 	.level_input_count = 2,
 	.air_input_count = 2,
+	.phantom_count = 1,
+	.inputs_per_phantom = 2,
 };
 
 static const struct scarlett2_device_info s4i4_gen3_info = {
@@ -553,6 +570,8 @@ static const struct scarlett2_device_info s4i4_gen3_info = {
 	.level_input_count = 2,
 	.pad_input_count = 2,
 	.air_input_count = 2,
+	.phantom_count = 1,
+	.inputs_per_phantom = 2,
 
 	.line_out_descrs = {
 		"Monitor L",
@@ -597,6 +616,8 @@ static const struct scarlett2_device_info s8i6_gen3_info = {
 	.level_input_count = 2,
 	.pad_input_count = 2,
 	.air_input_count = 2,
+	.phantom_count = 1,
+	.inputs_per_phantom = 2,
 
 	.line_out_descrs = {
 		"Headphones 1 L",
@@ -649,6 +670,8 @@ static const struct scarlett2_device_info s18i8_gen3_info = {
 	.level_input_count = 2,
 	.pad_input_count = 2,
 	.air_input_count = 4,
+	.phantom_count = 2,
+	.inputs_per_phantom = 2,
 
 	.line_out_descrs = {
 		"Monitor L",
@@ -713,6 +736,8 @@ static const struct scarlett2_device_info s18i20_gen3_info = {
 	.level_input_count = 2,
 	.pad_input_count = 8,
 	.air_input_count = 8,
+	.phantom_count = 2,
+	.inputs_per_phantom = 4,
 
 	.line_out_descrs = {
 		"Monitor 1 L",
@@ -861,7 +886,9 @@ enum {
 	SCARLETT2_CONFIG_PAD_SWITCH = 5,
 	SCARLETT2_CONFIG_MSD_SWITCH = 6,
 	SCARLETT2_CONFIG_AIR_SWITCH = 7,
-	SCARLETT2_CONFIG_COUNT = 8
+	SCARLETT2_CONFIG_PHANTOM_SWITCH = 8,
+	SCARLETT2_CONFIG_PHANTOM_PERSISTENCE = 9,
+	SCARLETT2_CONFIG_COUNT = 10
 };
 
 /* Location, size, and activation command number for the configuration
@@ -884,6 +911,12 @@ static const struct scarlett2_config
 	[SCARLETT2_CONFIG_MSD_SWITCH] = {
 		.offset = 0x04, .size = 8, .activate = 6 },
 
+	[SCARLETT2_CONFIG_PHANTOM_PERSISTENCE] = {
+		.offset = 0x05, .size = 8, .activate = 6 },
+
+	[SCARLETT2_CONFIG_PHANTOM_SWITCH] = {
+		.offset = 0x06, .size = 8, .activate = 3 },
+
 	[SCARLETT2_CONFIG_LEVEL_SWITCH] = {
 		.offset = 0x08, .size = 1, .activate = 7 },
 
@@ -913,8 +946,14 @@ static const struct scarlett2_config
 	[SCARLETT2_CONFIG_AIR_SWITCH] = {
 		.offset = 0x8c, .size = 8, .activate = 8 },
 
+	[SCARLETT2_CONFIG_PHANTOM_SWITCH] = {
+		.offset = 0x9c, .size = 1, .activate = 8 },
+
 	[SCARLETT2_CONFIG_MSD_SWITCH] = {
 		.offset = 0x9d, .size = 8, .activate = 6 },
+
+	[SCARLETT2_CONFIG_PHANTOM_PERSISTENCE] = {
+		.offset = 0x9e, .size = 8, .activate = 6 },
 } };
 
 /* proprietary request/response format */
@@ -1922,6 +1961,20 @@ static int scarlett2_update_input_other(struct usb_mixer_interface *mixer)
 			return err;
 	}
 
+	if (info->phantom_count) {
+		int err = scarlett2_usb_get_config(
+			mixer, SCARLETT2_CONFIG_PHANTOM_SWITCH,
+			info->phantom_count, private->phantom_switch);
+		if (err < 0)
+			return err;
+
+		err = scarlett2_usb_get_config(
+			mixer, SCARLETT2_CONFIG_PHANTOM_PERSISTENCE,
+			1, &private->phantom_persistence);
+		if (err < 0)
+			return err;
+	}
+
 	return 0;
 }
 
@@ -2107,6 +2160,111 @@ static const struct snd_kcontrol_new scarlett2_air_ctl = {
 	.put  = scarlett2_air_ctl_put,
 };
 
+/*** Phantom Switch Controls ***/
+
+static int scarlett2_phantom_ctl_get(struct snd_kcontrol *kctl,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct usb_mixer_elem_info *elem = kctl->private_data;
+	struct usb_mixer_interface *mixer = elem->head.mixer;
+	struct scarlett2_data *private = mixer->private_data;
+
+	mutex_lock(&private->data_mutex);
+	if (private->input_other_updated)
+		scarlett2_update_input_other(mixer);
+	ucontrol->value.integer.value[0] =
+		private->phantom_switch[elem->control];
+	mutex_unlock(&private->data_mutex);
+
+	return 0;
+}
+
+static int scarlett2_phantom_ctl_put(struct snd_kcontrol *kctl,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	struct usb_mixer_elem_info *elem = kctl->private_data;
+	struct usb_mixer_interface *mixer = elem->head.mixer;
+	struct scarlett2_data *private = mixer->private_data;
+
+	int index = elem->control;
+	int oval, val, err = 0;
+
+	mutex_lock(&private->data_mutex);
+
+	oval = private->phantom_switch[index];
+	val = !!ucontrol->value.integer.value[0];
+
+	if (oval == val)
+		goto unlock;
+
+	private->phantom_switch[index] = val;
+
+	/* Send switch change to the device */
+	err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_PHANTOM_SWITCH,
+				       index, val);
+
+unlock:
+	mutex_unlock(&private->data_mutex);
+	return err;
+}
+
+static const struct snd_kcontrol_new scarlett2_phantom_ctl = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "",
+	.info = snd_ctl_boolean_mono_info,
+	.get  = scarlett2_phantom_ctl_get,
+	.put  = scarlett2_phantom_ctl_put,
+};
+
+/*** Phantom Persistence Control ***/
+
+static int scarlett2_phantom_persistence_ctl_get(
+	struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol)
+{
+	struct usb_mixer_elem_info *elem = kctl->private_data;
+	struct scarlett2_data *private = elem->head.mixer->private_data;
+
+	ucontrol->value.integer.value[0] = private->phantom_persistence;
+	return 0;
+}
+
+static int scarlett2_phantom_persistence_ctl_put(
+	struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol)
+{
+	struct usb_mixer_elem_info *elem = kctl->private_data;
+	struct usb_mixer_interface *mixer = elem->head.mixer;
+	struct scarlett2_data *private = mixer->private_data;
+
+	int index = elem->control;
+	int oval, val, err = 0;
+
+	mutex_lock(&private->data_mutex);
+
+	oval = private->phantom_persistence;
+	val = !!ucontrol->value.integer.value[0];
+
+	if (oval == val)
+		goto unlock;
+
+	private->phantom_persistence = val;
+
+	/* Send switch change to the device */
+	err = scarlett2_usb_set_config(
+		mixer, SCARLETT2_CONFIG_PHANTOM_PERSISTENCE, index, val);
+
+unlock:
+	mutex_unlock(&private->data_mutex);
+	return err;
+}
+
+static const struct snd_kcontrol_new scarlett2_phantom_persistence_ctl = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "",
+	.info = snd_ctl_boolean_mono_info,
+	.get  = scarlett2_phantom_persistence_ctl_get,
+	.put  = scarlett2_phantom_persistence_ctl_put,
+};
+
 /*** Dim/Mute Controls ***/
 
 static int scarlett2_dim_mute_ctl_get(struct snd_kcontrol *kctl,
@@ -2270,6 +2428,7 @@ static int scarlett2_add_line_in_ctls(struct usb_mixer_interface *mixer)
 	int err, i;
 	char s[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
 	const char *fmt = "Line In %d %s Capture %s";
+	const char *fmt2 = "Line In %d-%d %s Capture %s";
 
 	/* Add input level (line/inst) controls */
 	for (i = 0; i < info->level_input_count; i++) {
@@ -2299,6 +2458,39 @@ static int scarlett2_add_line_in_ctls(struct usb_mixer_interface *mixer)
 			return err;
 	}
 
+	/* Add input phantom controls */
+	if (info->inputs_per_phantom == 1) {
+		for (i = 0; i < info->phantom_count; i++) {
+			snprintf(s, sizeof(s), fmt, i + 1,
+				 "Phantom Power", "Switch");
+			err = scarlett2_add_new_ctl(
+				mixer, &scarlett2_phantom_ctl,
+				i, 1, s, &private->phantom_ctls[i]);
+			if (err < 0)
+				return err;
+		}
+	} else if (info->inputs_per_phantom > 1) {
+		for (i = 0; i < info->phantom_count; i++) {
+			int from = i * info->inputs_per_phantom + 1;
+			int to = (i + 1) * info->inputs_per_phantom;
+
+			snprintf(s, sizeof(s), fmt2, from, to,
+				 "Phantom Power", "Switch");
+			err = scarlett2_add_new_ctl(
+				mixer, &scarlett2_phantom_ctl,
+				i, 1, s, &private->phantom_ctls[i]);
+			if (err < 0)
+				return err;
+		}
+	}
+	if (info->phantom_count) {
+		err = scarlett2_add_new_ctl(
+			mixer, &scarlett2_phantom_persistence_ctl, 0, 1,
+			"Phantom Power Persistence Capture Switch", NULL);
+		if (err < 0)
+			return err;
+	}
+
 	return 0;
 }
 
@@ -2927,6 +3119,9 @@ static void scarlett2_notify_input_other(
 	for (i = 0; i < info->air_input_count; i++)
 		snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
 			       &private->air_ctls[i]->id);
+	for (i = 0; i < info->phantom_count; i++)
+		snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+			       &private->phantom_ctls[i]->id);
 }
 
 /* Interrupt callback */
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 24/31] ALSA: usb-audio: scarlett2: Add direct monitor support
  2021-06-21 18:09 [PATCH 00/31] Refactor Scarlett Gen 2 support and add Scarlett Gen 3 support Geoffrey D. Bennett
                   ` (22 preceding siblings ...)
  2021-06-21 18:10 ` [PATCH 23/31] ALSA: usb-audio: scarlett2: Add phantom power " Geoffrey D. Bennett
@ 2021-06-21 18:10 ` Geoffrey D. Bennett
  2021-06-21 18:10 ` [PATCH 25/31] ALSA: usb-audio: scarlett2: Label 18i8 Gen 3 line outputs correctly Geoffrey D. Bennett
                   ` (6 subsequent siblings)
  30 siblings, 0 replies; 43+ messages in thread
From: Geoffrey D. Bennett @ 2021-06-21 18:10 UTC (permalink / raw)
  To: alsa-devel, Takashi Iwai; +Cc: Hin-Tak Leung, Vladimir Sadovnikov

The Solo and 2i2 devices don't have a mixer but they do have a "direct
monitor" switch. Add support for getting and setting the state of this
switch.

Co-developed-by: Vladimir Sadovnikov <sadko4u@gmail.com>
Signed-off-by: Vladimir Sadovnikov <sadko4u@gmail.com>
Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
---
 sound/usb/mixer_scarlett_gen2.c | 161 ++++++++++++++++++++++++++++++--
 1 file changed, 154 insertions(+), 7 deletions(-)

diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c
index 87672e6b4505..94de63847169 100644
--- a/sound/usb/mixer_scarlett_gen2.c
+++ b/sound/usb/mixer_scarlett_gen2.c
@@ -48,7 +48,8 @@
  * Support for Solo/2i2 Gen 3 added in May 2021 (thanks to Alexander
  * Vorona for 2i2 protocol traces).
  *
- * Support for phantom power added in May 2021.
+ * Support for phantom power and direct monitoring added in May-June
+ * 2021.
  *
  * This ALSA mixer gives access to (model-dependent):
  *  - input, output, mixer-matrix muxes
@@ -56,7 +57,7 @@
  *  - gain/volume/mute controls
  *  - level meters
  *  - line/inst level, pad, and air controls
- *  - phantom power controls
+ *  - phantom power and direct monitor controls
  *  - disable/enable MSD mode
  *
  * <ditaa>
@@ -338,6 +339,11 @@ struct scarlett2_device_info {
 	/* the number of inputs each phantom switch controls */
 	u8 inputs_per_phantom;
 
+	/* the number of direct monitor options
+	 * (0 = none, 1 = mono only, 2 = mono/stereo)
+	 */
+	u8 direct_monitor;
+
 	/* additional description for the line out volume controls */
 	const char * const line_out_descrs[SCARLETT2_ANALOGUE_MAX];
 
@@ -365,6 +371,7 @@ struct scarlett2_data {
 	u8 sync_updated;
 	u8 vol_updated;
 	u8 input_other_updated;
+	u8 monitor_other_updated;
 	u8 sync;
 	u8 master_vol;
 	u8 vol[SCARLETT2_ANALOGUE_MAX];
@@ -376,6 +383,7 @@ struct scarlett2_data {
 	u8 air_switch[SCARLETT2_AIR_SWITCH_MAX];
 	u8 phantom_switch[SCARLETT2_PHANTOM_SWITCH_MAX];
 	u8 phantom_persistence;
+	u8 direct_monitor_switch;
 	u8 msd_switch;
 	struct snd_kcontrol *sync_ctl;
 	struct snd_kcontrol *master_vol_ctl;
@@ -386,6 +394,7 @@ struct scarlett2_data {
 	struct snd_kcontrol *pad_ctls[SCARLETT2_PAD_SWITCH_MAX];
 	struct snd_kcontrol *air_ctls[SCARLETT2_AIR_SWITCH_MAX];
 	struct snd_kcontrol *phantom_ctls[SCARLETT2_PHANTOM_SWITCH_MAX];
+	struct snd_kcontrol *direct_monitor_ctl;
 	u8 mux[SCARLETT2_MUX_MAX];
 	u8 mix[SCARLETT2_INPUT_MIX_MAX * SCARLETT2_OUTPUT_MIX_MAX];
 };
@@ -550,6 +559,7 @@ static const struct scarlett2_device_info solo_gen3_info = {
 	.air_input_count = 1,
 	.phantom_count = 1,
 	.inputs_per_phantom = 1,
+	.direct_monitor = 1,
 };
 
 static const struct scarlett2_device_info s2i2_gen3_info = {
@@ -560,6 +570,7 @@ static const struct scarlett2_device_info s2i2_gen3_info = {
 	.air_input_count = 2,
 	.phantom_count = 1,
 	.inputs_per_phantom = 2,
+	.direct_monitor = 2,
 };
 
 static const struct scarlett2_device_info s4i4_gen3_info = {
@@ -824,10 +835,11 @@ static int scarlett2_get_port_start_num(
 /*** USB Interactions ***/
 
 /* Notifications from the interface */
-#define SCARLETT2_USB_NOTIFY_SYNC        0x00000008
-#define SCARLETT2_USB_NOTIFY_DIM_MUTE    0x00200000
-#define SCARLETT2_USB_NOTIFY_MONITOR     0x00400000
-#define SCARLETT2_USB_NOTIFY_INPUT_OTHER 0x00800000
+#define SCARLETT2_USB_NOTIFY_SYNC          0x00000008
+#define SCARLETT2_USB_NOTIFY_DIM_MUTE      0x00200000
+#define SCARLETT2_USB_NOTIFY_MONITOR       0x00400000
+#define SCARLETT2_USB_NOTIFY_INPUT_OTHER   0x00800000
+#define SCARLETT2_USB_NOTIFY_MONITOR_OTHER 0x01000000
 
 /* Commands for sending/receiving requests/responses */
 #define SCARLETT2_USB_CMD_INIT 0
@@ -888,7 +900,8 @@ enum {
 	SCARLETT2_CONFIG_AIR_SWITCH = 7,
 	SCARLETT2_CONFIG_PHANTOM_SWITCH = 8,
 	SCARLETT2_CONFIG_PHANTOM_PERSISTENCE = 9,
-	SCARLETT2_CONFIG_COUNT = 10
+	SCARLETT2_CONFIG_DIRECT_MONITOR = 10,
+	SCARLETT2_CONFIG_COUNT = 11
 };
 
 /* Location, size, and activation command number for the configuration
@@ -917,6 +930,9 @@ static const struct scarlett2_config
 	[SCARLETT2_CONFIG_PHANTOM_SWITCH] = {
 		.offset = 0x06, .size = 8, .activate = 3 },
 
+	[SCARLETT2_CONFIG_DIRECT_MONITOR] = {
+		.offset = 0x07, .size = 8, .activate = 4 },
+
 	[SCARLETT2_CONFIG_LEVEL_SWITCH] = {
 		.offset = 0x08, .size = 1, .activate = 7 },
 
@@ -2265,6 +2281,112 @@ static const struct snd_kcontrol_new scarlett2_phantom_persistence_ctl = {
 	.put  = scarlett2_phantom_persistence_ctl_put,
 };
 
+/*** Direct Monitor Control ***/
+
+static int scarlett2_update_monitor_other(struct usb_mixer_interface *mixer)
+{
+	struct scarlett2_data *private = mixer->private_data;
+	const struct scarlett2_device_info *info = private->info;
+
+	private->monitor_other_updated = 0;
+
+	if (info->direct_monitor)
+		return scarlett2_usb_get_config(
+			mixer, SCARLETT2_CONFIG_DIRECT_MONITOR,
+			1, &private->direct_monitor_switch);
+
+	return 0;
+}
+
+static int scarlett2_direct_monitor_ctl_get(
+	struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol)
+{
+	struct usb_mixer_elem_info *elem = kctl->private_data;
+	struct usb_mixer_interface *mixer = elem->head.mixer;
+	struct scarlett2_data *private = elem->head.mixer->private_data;
+
+	mutex_lock(&private->data_mutex);
+	if (private->monitor_other_updated)
+		scarlett2_update_monitor_other(mixer);
+	ucontrol->value.enumerated.item[0] = private->direct_monitor_switch;
+	mutex_unlock(&private->data_mutex);
+
+	return 0;
+}
+
+static int scarlett2_direct_monitor_ctl_put(
+	struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol)
+{
+	struct usb_mixer_elem_info *elem = kctl->private_data;
+	struct usb_mixer_interface *mixer = elem->head.mixer;
+	struct scarlett2_data *private = mixer->private_data;
+
+	int index = elem->control;
+	int oval, val, err = 0;
+
+	mutex_lock(&private->data_mutex);
+
+	oval = private->direct_monitor_switch;
+	val = min(ucontrol->value.enumerated.item[0], 2U);
+
+	if (oval == val)
+		goto unlock;
+
+	private->direct_monitor_switch = val;
+
+	/* Send switch change to the device */
+	err = scarlett2_usb_set_config(
+		mixer, SCARLETT2_CONFIG_DIRECT_MONITOR, index, val);
+
+unlock:
+	mutex_unlock(&private->data_mutex);
+	return err;
+}
+
+static int scarlett2_direct_monitor_stereo_enum_ctl_info(
+	struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo)
+{
+	static const char *const values[3] = {
+		"Off", "Mono", "Stereo"
+	};
+
+	return snd_ctl_enum_info(uinfo, 1, 3, values);
+}
+
+/* Direct Monitor for Solo is mono-only and only needs a boolean control
+ * Direct Monitor for 2i2 is selectable between Off/Mono/Stereo
+ */
+static const struct snd_kcontrol_new scarlett2_direct_monitor_ctl[2] = {
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "",
+		.info = snd_ctl_boolean_mono_info,
+		.get  = scarlett2_direct_monitor_ctl_get,
+		.put  = scarlett2_direct_monitor_ctl_put,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "",
+		.info = scarlett2_direct_monitor_stereo_enum_ctl_info,
+		.get  = scarlett2_direct_monitor_ctl_get,
+		.put  = scarlett2_direct_monitor_ctl_put,
+	}
+};
+
+static int scarlett2_add_direct_monitor_ctl(struct usb_mixer_interface *mixer)
+{
+	struct scarlett2_data *private = mixer->private_data;
+	const struct scarlett2_device_info *info = private->info;
+
+	if (!info->direct_monitor)
+		return 0;
+
+	return scarlett2_add_new_ctl(
+		mixer, &scarlett2_direct_monitor_ctl[info->direct_monitor - 1],
+		0, 1, "Direct Monitor Playback Switch",
+		&private->direct_monitor_ctl);
+}
+
 /*** Dim/Mute Controls ***/
 
 static int scarlett2_dim_mute_ctl_get(struct snd_kcontrol *kctl,
@@ -2983,6 +3105,10 @@ static int scarlett2_read_configs(struct usb_mixer_interface *mixer)
 	if (err < 0)
 		return err;
 
+	err = scarlett2_update_monitor_other(mixer);
+	if (err < 0)
+		return err;
+
 	/* the rest of the configuration is for devices with a mixer */
 	if (!info->has_mixer)
 		return 0;
@@ -3124,6 +3250,20 @@ static void scarlett2_notify_input_other(
 			       &private->phantom_ctls[i]->id);
 }
 
+/* Notify on "monitor other" change (direct monitor) */
+static void scarlett2_notify_monitor_other(
+	struct usb_mixer_interface *mixer)
+{
+	struct scarlett2_data *private = mixer->private_data;
+	struct snd_card *card = mixer->chip->card;
+
+	private->monitor_other_updated = 1;
+
+	if (private->info->direct_monitor)
+		snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+			       &private->direct_monitor_ctl->id);
+}
+
 /* Interrupt callback */
 static void scarlett2_notify(struct urb *urb)
 {
@@ -3144,6 +3284,8 @@ static void scarlett2_notify(struct urb *urb)
 		scarlett2_notify_dim_mute(mixer);
 	if (data & SCARLETT2_USB_NOTIFY_INPUT_OTHER)
 		scarlett2_notify_input_other(mixer);
+	if (data & SCARLETT2_USB_NOTIFY_MONITOR_OTHER)
+		scarlett2_notify_monitor_other(mixer);
 
 requeue:
 	if (ustatus != -ENOENT &&
@@ -3250,6 +3392,11 @@ static int snd_scarlett_gen2_controls_create(struct usb_mixer_interface *mixer)
 	if (err < 0)
 		return err;
 
+	/* Create the direct monitor control */
+	err = scarlett2_add_direct_monitor_ctl(mixer);
+	if (err < 0)
+		return err;
+
 	/* Set up the interrupt polling */
 	err = scarlett2_init_notify(mixer);
 	if (err < 0)
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 25/31] ALSA: usb-audio: scarlett2: Label 18i8 Gen 3 line outputs correctly
  2021-06-21 18:09 [PATCH 00/31] Refactor Scarlett Gen 2 support and add Scarlett Gen 3 support Geoffrey D. Bennett
                   ` (23 preceding siblings ...)
  2021-06-21 18:10 ` [PATCH 24/31] ALSA: usb-audio: scarlett2: Add direct monitor support Geoffrey D. Bennett
@ 2021-06-21 18:10 ` Geoffrey D. Bennett
  2021-06-21 18:10 ` [PATCH 26/31] ALSA: usb-audio: scarlett2: Split up sw_hw_enum_ctl_put() Geoffrey D. Bennett
                   ` (5 subsequent siblings)
  30 siblings, 0 replies; 43+ messages in thread
From: Geoffrey D. Bennett @ 2021-06-21 18:10 UTC (permalink / raw)
  To: alsa-devel, Takashi Iwai; +Cc: Hin-Tak Leung, Vladimir Sadovnikov

The 18i8 Gen 3 analogue 7/8 outputs are identified as line 3/4 on the
rear of the unit. Add support for remapping the channel numbers to
match the labelling.

Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
---
 sound/usb/mixer_scarlett_gen2.c | 82 ++++++++++++++++++++++++---------
 1 file changed, 59 insertions(+), 23 deletions(-)

diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c
index 94de63847169..03decb35d25e 100644
--- a/sound/usb/mixer_scarlett_gen2.c
+++ b/sound/usb/mixer_scarlett_gen2.c
@@ -344,6 +344,12 @@ struct scarlett2_device_info {
 	 */
 	u8 direct_monitor;
 
+	/* remap analogue outputs; 18i8 Gen 3 has "line 3/4" connected
+	 * internally to the analogue 7/8 outputs
+	 */
+	u8 line_out_remap_enable;
+	u8 line_out_remap[SCARLETT2_ANALOGUE_MAX];
+
 	/* additional description for the line out volume controls */
 	const char * const line_out_descrs[SCARLETT2_ANALOGUE_MAX];
 
@@ -684,15 +690,18 @@ static const struct scarlett2_device_info s18i8_gen3_info = {
 	.phantom_count = 2,
 	.inputs_per_phantom = 2,
 
+	.line_out_remap_enable = 1,
+	.line_out_remap = { 0, 1, 6, 7, 2, 3, 4, 5 },
+
 	.line_out_descrs = {
 		"Monitor L",
 		"Monitor R",
+		"Alt Monitor L",
+		"Alt Monitor R",
 		"Headphones 1 L",
 		"Headphones 1 R",
 		"Headphones 2 L",
 		"Headphones 2 R",
-		"Alt Monitor L",
-		"Alt Monitor R",
 	},
 
 	.port_count = {
@@ -1711,13 +1720,22 @@ static int scarlett2_master_volume_ctl_get(struct snd_kcontrol *kctl,
 	return 0;
 }
 
+static int line_out_remap(struct scarlett2_data *private, int index)
+{
+	const struct scarlett2_device_info *info = private->info;
+
+	if (!info->line_out_remap_enable)
+		return index;
+	return info->line_out_remap[index];
+}
+
 static int scarlett2_volume_ctl_get(struct snd_kcontrol *kctl,
 				    struct snd_ctl_elem_value *ucontrol)
 {
 	struct usb_mixer_elem_info *elem = kctl->private_data;
 	struct usb_mixer_interface *mixer = elem->head.mixer;
 	struct scarlett2_data *private = mixer->private_data;
-	int index = elem->control;
+	int index = line_out_remap(private, elem->control);
 
 	mutex_lock(&private->data_mutex);
 	if (private->vol_updated)
@@ -1734,7 +1752,7 @@ static int scarlett2_volume_ctl_put(struct snd_kcontrol *kctl,
 	struct usb_mixer_elem_info *elem = kctl->private_data;
 	struct usb_mixer_interface *mixer = elem->head.mixer;
 	struct scarlett2_data *private = mixer->private_data;
-	int index = elem->control;
+	int index = line_out_remap(private, elem->control);
 	int oval, val, err = 0;
 
 	mutex_lock(&private->data_mutex);
@@ -1790,7 +1808,7 @@ static int scarlett2_mute_ctl_get(struct snd_kcontrol *kctl,
 {
 	struct usb_mixer_elem_info *elem = kctl->private_data;
 	struct scarlett2_data *private = elem->head.mixer->private_data;
-	int index = elem->control;
+	int index = line_out_remap(private, elem->control);
 
 	ucontrol->value.integer.value[0] = private->mute_switch[index];
 	return 0;
@@ -1802,7 +1820,7 @@ static int scarlett2_mute_ctl_put(struct snd_kcontrol *kctl,
 	struct usb_mixer_elem_info *elem = kctl->private_data;
 	struct usb_mixer_interface *mixer = elem->head.mixer;
 	struct scarlett2_data *private = mixer->private_data;
-	int index = elem->control;
+	int index = line_out_remap(private, elem->control);
 	int oval, val, err = 0;
 
 	mutex_lock(&private->data_mutex);
@@ -1849,9 +1867,9 @@ static int scarlett2_sw_hw_enum_ctl_get(struct snd_kcontrol *kctl,
 {
 	struct usb_mixer_elem_info *elem = kctl->private_data;
 	struct scarlett2_data *private = elem->head.mixer->private_data;
+	int index = line_out_remap(private, elem->control);
 
-	ucontrol->value.enumerated.item[0] =
-		private->vol_sw_hw_switch[elem->control];
+	ucontrol->value.enumerated.item[0] = private->vol_sw_hw_switch[index];
 	return 0;
 }
 
@@ -1887,8 +1905,8 @@ static int scarlett2_sw_hw_enum_ctl_put(struct snd_kcontrol *kctl,
 	struct usb_mixer_elem_info *elem = kctl->private_data;
 	struct usb_mixer_interface *mixer = elem->head.mixer;
 	struct scarlett2_data *private = mixer->private_data;
-
-	int index = elem->control;
+	int ctl_index = elem->control;
+	int index = line_out_remap(private, ctl_index);
 	int oval, val, err = 0;
 
 	mutex_lock(&private->data_mutex);
@@ -1904,7 +1922,7 @@ static int scarlett2_sw_hw_enum_ctl_put(struct snd_kcontrol *kctl,
 	/* Change access mode to RO (hardware controlled volume)
 	 * or RW (software controlled volume)
 	 */
-	scarlett2_vol_ctl_set_writable(mixer, index, !val);
+	scarlett2_vol_ctl_set_writable(mixer, ctl_index, !val);
 
 	/* Reset volume/mute to master volume/mute */
 	private->vol[index] = private->master_vol;
@@ -2436,13 +2454,16 @@ static int scarlett2_dim_mute_ctl_put(struct snd_kcontrol *kctl,
 		err = 1;
 
 	if (index == SCARLETT2_BUTTON_MUTE)
-		for (i = 0; i < num_line_out; i++)
-			if (private->vol_sw_hw_switch[i]) {
-				private->mute_switch[i] = val;
+		for (i = 0; i < num_line_out; i++) {
+			int line_index = line_out_remap(private, i);
+
+			if (private->vol_sw_hw_switch[line_index]) {
+				private->mute_switch[line_index] = val;
 				snd_ctl_notify(mixer->chip->card,
 					       SNDRV_CTL_EVENT_MASK_INFO,
 					       &private->mute_ctls[i]->id);
 			}
+		}
 
 unlock:
 	mutex_unlock(&private->data_mutex);
@@ -2481,6 +2502,7 @@ static int scarlett2_add_line_out_ctls(struct usb_mixer_interface *mixer)
 
 	/* Add volume controls */
 	for (i = 0; i < num_line_out; i++) {
+		int index = line_out_remap(private, i);
 
 		/* Fader */
 		if (info->line_out_descrs[i])
@@ -2511,7 +2533,7 @@ static int scarlett2_add_line_out_ctls(struct usb_mixer_interface *mixer)
 		/* Make the fader and mute controls read-only if the
 		 * SW/HW switch is set to HW
 		 */
-		if (private->vol_sw_hw_switch[i])
+		if (private->vol_sw_hw_switch[index])
 			scarlett2_vol_ctl_set_writable(mixer, i, 0);
 
 		/* SW/HW Switch */
@@ -2760,8 +2782,16 @@ static int scarlett2_mux_src_enum_ctl_get(struct snd_kcontrol *kctl,
 {
 	struct usb_mixer_elem_info *elem = kctl->private_data;
 	struct scarlett2_data *private = elem->head.mixer->private_data;
+	const struct scarlett2_device_info *info = private->info;
+	const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count;
+	int line_out_count =
+		port_count[SCARLETT2_PORT_TYPE_ANALOGUE][SCARLETT2_PORT_OUT];
+	int index = elem->control;
+
+	if (index < line_out_count)
+		index = line_out_remap(private, index);
 
-	ucontrol->value.enumerated.item[0] = private->mux[elem->control];
+	ucontrol->value.enumerated.item[0] = private->mux[index];
 	return 0;
 }
 
@@ -2771,9 +2801,16 @@ static int scarlett2_mux_src_enum_ctl_put(struct snd_kcontrol *kctl,
 	struct usb_mixer_elem_info *elem = kctl->private_data;
 	struct usb_mixer_interface *mixer = elem->head.mixer;
 	struct scarlett2_data *private = mixer->private_data;
+	const struct scarlett2_device_info *info = private->info;
+	const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count;
+	int line_out_count =
+		port_count[SCARLETT2_PORT_TYPE_ANALOGUE][SCARLETT2_PORT_OUT];
 	int index = elem->control;
 	int oval, val, err = 0;
 
+	if (index < line_out_count)
+		index = line_out_remap(private, index);
+
 	mutex_lock(&private->data_mutex);
 
 	oval = private->mux[index];
@@ -3174,6 +3211,7 @@ static void scarlett2_notify_sync(
 static void scarlett2_notify_monitor(
 	struct usb_mixer_interface *mixer)
 {
+	struct snd_card *card = mixer->chip->card;
 	struct scarlett2_data *private = mixer->private_data;
 	const struct scarlett2_device_info *info = private->info;
 	const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count;
@@ -3190,12 +3228,10 @@ static void scarlett2_notify_monitor(
 	snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
 		       &private->master_vol_ctl->id);
 
-	for (i = 0; i < num_line_out; i++) {
-		if (!private->vol_sw_hw_switch[i])
-			continue;
-		snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
-			       &private->vol_ctls[i]->id);
-	}
+	for (i = 0; i < num_line_out; i++)
+		if (private->vol_sw_hw_switch[line_out_remap(private, i)])
+			snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+				       &private->vol_ctls[i]->id);
 }
 
 /* Notify on dim/mute change */
@@ -3220,7 +3256,7 @@ static void scarlett2_notify_dim_mute(
 			       &private->dim_mute_ctls[i]->id);
 
 	for (i = 0; i < num_line_out; i++)
-		if (private->vol_sw_hw_switch[i])
+		if (private->vol_sw_hw_switch[line_out_remap(private, i)])
 			snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
 				       &private->mute_ctls[i]->id);
 }
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 26/31] ALSA: usb-audio: scarlett2: Split up sw_hw_enum_ctl_put()
  2021-06-21 18:09 [PATCH 00/31] Refactor Scarlett Gen 2 support and add Scarlett Gen 3 support Geoffrey D. Bennett
                   ` (24 preceding siblings ...)
  2021-06-21 18:10 ` [PATCH 25/31] ALSA: usb-audio: scarlett2: Label 18i8 Gen 3 line outputs correctly Geoffrey D. Bennett
@ 2021-06-21 18:10 ` Geoffrey D. Bennett
  2021-06-21 18:10 ` [PATCH 27/31] ALSA: usb-audio: scarlett2: Add sw_hw_ctls and mux_ctls Geoffrey D. Bennett
                   ` (4 subsequent siblings)
  30 siblings, 0 replies; 43+ messages in thread
From: Geoffrey D. Bennett @ 2021-06-21 18:10 UTC (permalink / raw)
  To: alsa-devel, Takashi Iwai; +Cc: Hin-Tak Leung, Vladimir Sadovnikov

Split part of scarlett2_sw_hw_enum_ctl_put() out into
scarlett2_sw_hw_change() so that the code which actually makes the
change is available in its own function. This will be used by the
speaker switching support which needs to set the SW/HW switch to HW
when speaker switching is enabled.

Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
---
 sound/usb/mixer_scarlett_gen2.c | 46 ++++++++++++++++++++-------------
 1 file changed, 28 insertions(+), 18 deletions(-)

diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c
index 03decb35d25e..1b398a06d4b2 100644
--- a/sound/usb/mixer_scarlett_gen2.c
+++ b/sound/usb/mixer_scarlett_gen2.c
@@ -1899,23 +1899,12 @@ static void scarlett2_vol_ctl_set_writable(struct usb_mixer_interface *mixer,
 		       &private->mute_ctls[index]->id);
 }
 
-static int scarlett2_sw_hw_enum_ctl_put(struct snd_kcontrol *kctl,
-					struct snd_ctl_elem_value *ucontrol)
+static int scarlett2_sw_hw_change(struct usb_mixer_interface *mixer,
+				  int ctl_index, int val)
 {
-	struct usb_mixer_elem_info *elem = kctl->private_data;
-	struct usb_mixer_interface *mixer = elem->head.mixer;
 	struct scarlett2_data *private = mixer->private_data;
-	int ctl_index = elem->control;
 	int index = line_out_remap(private, ctl_index);
-	int oval, val, err = 0;
-
-	mutex_lock(&private->data_mutex);
-
-	oval = private->vol_sw_hw_switch[index];
-	val = !!ucontrol->value.enumerated.item[0];
-
-	if (oval == val)
-		goto unlock;
+	int err;
 
 	private->vol_sw_hw_switch[index] = val;
 
@@ -1933,18 +1922,39 @@ static int scarlett2_sw_hw_enum_ctl_put(struct snd_kcontrol *kctl,
 		mixer, SCARLETT2_CONFIG_LINE_OUT_VOLUME,
 		index, private->master_vol - SCARLETT2_VOLUME_BIAS);
 	if (err < 0)
-		goto unlock;
+		return err;
 
 	/* Set SW mute to current HW mute */
 	err = scarlett2_usb_set_config(
 		mixer, SCARLETT2_CONFIG_MUTE_SWITCH,
 		index, private->dim_mute[SCARLETT2_BUTTON_MUTE]);
 	if (err < 0)
-		goto unlock;
+		return err;
 
 	/* Send SW/HW switch change to the device */
-	err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_SW_HW_SWITCH,
-				       index, val);
+	return scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_SW_HW_SWITCH,
+					index, val);
+}
+
+static int scarlett2_sw_hw_enum_ctl_put(struct snd_kcontrol *kctl,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct usb_mixer_elem_info *elem = kctl->private_data;
+	struct usb_mixer_interface *mixer = elem->head.mixer;
+	struct scarlett2_data *private = mixer->private_data;
+	int ctl_index = elem->control;
+	int index = line_out_remap(private, ctl_index);
+	int oval, val, err = 0;
+
+	mutex_lock(&private->data_mutex);
+
+	oval = private->vol_sw_hw_switch[index];
+	val = !!ucontrol->value.enumerated.item[0];
+
+	if (oval == val)
+		goto unlock;
+
+	err = scarlett2_sw_hw_change(mixer, ctl_index, val);
 	if (err == 0)
 		err = 1;
 
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 27/31] ALSA: usb-audio: scarlett2: Add sw_hw_ctls and mux_ctls
  2021-06-21 18:09 [PATCH 00/31] Refactor Scarlett Gen 2 support and add Scarlett Gen 3 support Geoffrey D. Bennett
                   ` (25 preceding siblings ...)
  2021-06-21 18:10 ` [PATCH 26/31] ALSA: usb-audio: scarlett2: Split up sw_hw_enum_ctl_put() Geoffrey D. Bennett
@ 2021-06-21 18:10 ` Geoffrey D. Bennett
  2021-06-21 18:10 ` [PATCH 28/31] ALSA: usb-audio: scarlett2: Update mux controls to allow updates Geoffrey D. Bennett
                   ` (3 subsequent siblings)
  30 siblings, 0 replies; 43+ messages in thread
From: Geoffrey D. Bennett @ 2021-06-21 18:10 UTC (permalink / raw)
  To: alsa-devel, Takashi Iwai; +Cc: Hin-Tak Leung, Vladimir Sadovnikov

Save the struct snd_kcontrol pointers for the sw_hw and mux controls.
This is in preparation for speaker switching support which needs to be
able to update those controls.

Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
---
 sound/usb/mixer_scarlett_gen2.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c
index 1b398a06d4b2..efa65bdb48c8 100644
--- a/sound/usb/mixer_scarlett_gen2.c
+++ b/sound/usb/mixer_scarlett_gen2.c
@@ -394,12 +394,14 @@ struct scarlett2_data {
 	struct snd_kcontrol *sync_ctl;
 	struct snd_kcontrol *master_vol_ctl;
 	struct snd_kcontrol *vol_ctls[SCARLETT2_ANALOGUE_MAX];
+	struct snd_kcontrol *sw_hw_ctls[SCARLETT2_ANALOGUE_MAX];
 	struct snd_kcontrol *mute_ctls[SCARLETT2_ANALOGUE_MAX];
 	struct snd_kcontrol *dim_mute_ctls[SCARLETT2_DIM_MUTE_COUNT];
 	struct snd_kcontrol *level_ctls[SCARLETT2_LEVEL_SWITCH_MAX];
 	struct snd_kcontrol *pad_ctls[SCARLETT2_PAD_SWITCH_MAX];
 	struct snd_kcontrol *air_ctls[SCARLETT2_AIR_SWITCH_MAX];
 	struct snd_kcontrol *phantom_ctls[SCARLETT2_PHANTOM_SWITCH_MAX];
+	struct snd_kcontrol *mux_ctls[SCARLETT2_MUX_MAX];
 	struct snd_kcontrol *direct_monitor_ctl;
 	u8 mux[SCARLETT2_MUX_MAX];
 	u8 mix[SCARLETT2_INPUT_MIX_MAX * SCARLETT2_OUTPUT_MIX_MAX];
@@ -2553,7 +2555,8 @@ static int scarlett2_add_line_out_ctls(struct usb_mixer_interface *mixer)
 				 i + 1);
 			err = scarlett2_add_new_ctl(mixer,
 						    &scarlett2_sw_hw_enum_ctl,
-						    i, 1, s, NULL);
+						    i, 1, s,
+						    &private->sw_hw_ctls[i]);
 			if (err < 0)
 				return err;
 		}
@@ -2871,7 +2874,8 @@ static int scarlett2_add_mux_enums(struct usb_mixer_interface *mixer)
 
 			err = scarlett2_add_new_ctl(mixer,
 						    &scarlett2_mux_src_enum_ctl,
-						    i, 1, s, NULL);
+						    i, 1, s,
+						    &private->mux_ctls[i]);
 			if (err < 0)
 				return err;
 		}
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 28/31] ALSA: usb-audio: scarlett2: Update mux controls to allow updates
  2021-06-21 18:09 [PATCH 00/31] Refactor Scarlett Gen 2 support and add Scarlett Gen 3 support Geoffrey D. Bennett
                   ` (26 preceding siblings ...)
  2021-06-21 18:10 ` [PATCH 27/31] ALSA: usb-audio: scarlett2: Add sw_hw_ctls and mux_ctls Geoffrey D. Bennett
@ 2021-06-21 18:10 ` Geoffrey D. Bennett
  2021-06-21 18:10 ` [PATCH 29/31] ALSA: usb-audio: scarlett2: Add speaker switching support Geoffrey D. Bennett
                   ` (2 subsequent siblings)
  30 siblings, 0 replies; 43+ messages in thread
From: Geoffrey D. Bennett @ 2021-06-21 18:10 UTC (permalink / raw)
  To: alsa-devel, Takashi Iwai; +Cc: Hin-Tak Leung, Vladimir Sadovnikov

Enabling/disabling speaker switching will update the mux
configuration. To prepare for this, add a private->mux_updated flag
and update the scarlett2_mux_src_enum_ctl_get() callback to check it.

Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
---
 sound/usb/mixer_scarlett_gen2.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c
index efa65bdb48c8..dce40d2e0ba6 100644
--- a/sound/usb/mixer_scarlett_gen2.c
+++ b/sound/usb/mixer_scarlett_gen2.c
@@ -378,6 +378,7 @@ struct scarlett2_data {
 	u8 vol_updated;
 	u8 input_other_updated;
 	u8 monitor_other_updated;
+	u8 mux_updated;
 	u8 sync;
 	u8 master_vol;
 	u8 vol[SCARLETT2_ANALOGUE_MAX];
@@ -1446,6 +1447,8 @@ static int scarlett2_usb_get_mux(struct usb_mixer_interface *mixer)
 
 	__le32 data[SCARLETT2_MUX_MAX];
 
+	private->mux_updated = 0;
+
 	req.num = 0;
 	req.count = cpu_to_le16(count);
 
@@ -2794,7 +2797,8 @@ static int scarlett2_mux_src_enum_ctl_get(struct snd_kcontrol *kctl,
 					  struct snd_ctl_elem_value *ucontrol)
 {
 	struct usb_mixer_elem_info *elem = kctl->private_data;
-	struct scarlett2_data *private = elem->head.mixer->private_data;
+	struct usb_mixer_interface *mixer = elem->head.mixer;
+	struct scarlett2_data *private = mixer->private_data;
 	const struct scarlett2_device_info *info = private->info;
 	const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count;
 	int line_out_count =
@@ -2804,7 +2808,12 @@ static int scarlett2_mux_src_enum_ctl_get(struct snd_kcontrol *kctl,
 	if (index < line_out_count)
 		index = line_out_remap(private, index);
 
+	mutex_lock(&private->data_mutex);
+	if (private->mux_updated)
+		scarlett2_usb_get_mux(mixer);
 	ucontrol->value.enumerated.item[0] = private->mux[index];
+	mutex_unlock(&private->data_mutex);
+
 	return 0;
 }
 
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 29/31] ALSA: usb-audio: scarlett2: Add speaker switching support
  2021-06-21 18:09 [PATCH 00/31] Refactor Scarlett Gen 2 support and add Scarlett Gen 3 support Geoffrey D. Bennett
                   ` (27 preceding siblings ...)
  2021-06-21 18:10 ` [PATCH 28/31] ALSA: usb-audio: scarlett2: Update mux controls to allow updates Geoffrey D. Bennett
@ 2021-06-21 18:10 ` Geoffrey D. Bennett
  2021-06-21 18:10 ` [PATCH 30/31] ALSA: usb-audio: scarlett2: Update get_config to do endian conversion Geoffrey D. Bennett
  2021-06-21 18:10 ` [PATCH 31/31] ALSA: usb-audio: scarlett2: Add support for the talkback feature Geoffrey D. Bennett
  30 siblings, 0 replies; 43+ messages in thread
From: Geoffrey D. Bennett @ 2021-06-21 18:10 UTC (permalink / raw)
  To: alsa-devel, Takashi Iwai; +Cc: Hin-Tak Leung, Vladimir Sadovnikov

The 18i8 and 18i20 Gen 3 support "speaker switching". Add a Speaker
Switch control which can be set to Off/Main/Alt.

When speaker switching is enabled or disabled, the interface may
change the state of the Analog Outputs 3 and 4 routing and the global
mute button, so use a flag private->speaker_switching_switched to note
that those should be checked when the next "monitor other"
notification is received.

Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
---
 sound/usb/mixer_scarlett_gen2.c | 248 +++++++++++++++++++++++++++++++-
 1 file changed, 241 insertions(+), 7 deletions(-)

diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c
index dce40d2e0ba6..dc5fd045b2dc 100644
--- a/sound/usb/mixer_scarlett_gen2.c
+++ b/sound/usb/mixer_scarlett_gen2.c
@@ -48,8 +48,8 @@
  * Support for Solo/2i2 Gen 3 added in May 2021 (thanks to Alexander
  * Vorona for 2i2 protocol traces).
  *
- * Support for phantom power and direct monitoring added in May-June
- * 2021.
+ * Support for phantom power, direct monitoring, and speaker switching
+ * added in May-June 2021.
  *
  * This ALSA mixer gives access to (model-dependent):
  *  - input, output, mixer-matrix muxes
@@ -57,7 +57,7 @@
  *  - gain/volume/mute controls
  *  - level meters
  *  - line/inst level, pad, and air controls
- *  - phantom power and direct monitor controls
+ *  - phantom power, direct monitor, and speaker switching controls
  *  - disable/enable MSD mode
  *
  * <ditaa>
@@ -315,6 +315,9 @@ struct scarlett2_device_info {
 	/* line out hw volume is sw controlled */
 	u8 line_out_hw_vol;
 
+	/* support for main/alt speaker switching */
+	u8 has_speaker_switching;
+
 	/* the number of analogue inputs with a software switchable
 	 * level control that can be set to line or instrument
 	 */
@@ -379,6 +382,7 @@ struct scarlett2_data {
 	u8 input_other_updated;
 	u8 monitor_other_updated;
 	u8 mux_updated;
+	u8 speaker_switching_switched;
 	u8 sync;
 	u8 master_vol;
 	u8 vol[SCARLETT2_ANALOGUE_MAX];
@@ -391,6 +395,7 @@ struct scarlett2_data {
 	u8 phantom_switch[SCARLETT2_PHANTOM_SWITCH_MAX];
 	u8 phantom_persistence;
 	u8 direct_monitor_switch;
+	u8 speaker_switching_switch;
 	u8 msd_switch;
 	struct snd_kcontrol *sync_ctl;
 	struct snd_kcontrol *master_vol_ctl;
@@ -404,6 +409,7 @@ struct scarlett2_data {
 	struct snd_kcontrol *phantom_ctls[SCARLETT2_PHANTOM_SWITCH_MAX];
 	struct snd_kcontrol *mux_ctls[SCARLETT2_MUX_MAX];
 	struct snd_kcontrol *direct_monitor_ctl;
+	struct snd_kcontrol *speaker_switching_ctl;
 	u8 mux[SCARLETT2_MUX_MAX];
 	u8 mix[SCARLETT2_INPUT_MIX_MAX * SCARLETT2_OUTPUT_MIX_MAX];
 };
@@ -687,6 +693,7 @@ static const struct scarlett2_device_info s18i8_gen3_info = {
 	.has_msd_mode = 1,
 	.has_mixer = 1,
 	.line_out_hw_vol = 1,
+	.has_speaker_switching = 1,
 	.level_input_count = 2,
 	.pad_input_count = 2,
 	.air_input_count = 4,
@@ -756,6 +763,7 @@ static const struct scarlett2_device_info s18i20_gen3_info = {
 	.has_msd_mode = 1,
 	.has_mixer = 1,
 	.line_out_hw_vol = 1,
+	.has_speaker_switching = 1,
 	.level_input_count = 2,
 	.pad_input_count = 8,
 	.air_input_count = 8,
@@ -913,7 +921,9 @@ enum {
 	SCARLETT2_CONFIG_PHANTOM_SWITCH = 8,
 	SCARLETT2_CONFIG_PHANTOM_PERSISTENCE = 9,
 	SCARLETT2_CONFIG_DIRECT_MONITOR = 10,
-	SCARLETT2_CONFIG_COUNT = 11
+	SCARLETT2_CONFIG_MONITOR_OTHER_SWITCH = 11,
+	SCARLETT2_CONFIG_MONITOR_OTHER_ENABLE = 12,
+	SCARLETT2_CONFIG_COUNT = 13
 };
 
 /* Location, size, and activation command number for the configuration
@@ -982,6 +992,12 @@ static const struct scarlett2_config
 
 	[SCARLETT2_CONFIG_PHANTOM_PERSISTENCE] = {
 		.offset = 0x9e, .size = 8, .activate = 6 },
+
+	[SCARLETT2_CONFIG_MONITOR_OTHER_SWITCH] = {
+		.offset = 0x9f, .size = 1, .activate = 10 },
+
+	[SCARLETT2_CONFIG_MONITOR_OTHER_ENABLE] = {
+		.offset = 0xa0, .size = 1, .activate = 10 },
 } };
 
 /* proprietary request/response format */
@@ -1857,6 +1873,18 @@ static const struct snd_kcontrol_new scarlett2_mute_ctl = {
 
 /*** HW/SW Volume Switch Controls ***/
 
+static void scarlett2_sw_hw_ctl_ro(struct scarlett2_data *private, int index)
+{
+	private->sw_hw_ctls[index]->vd[0].access &=
+		~SNDRV_CTL_ELEM_ACCESS_WRITE;
+}
+
+static void scarlett2_sw_hw_ctl_rw(struct scarlett2_data *private, int index)
+{
+	private->sw_hw_ctls[index]->vd[0].access |=
+		SNDRV_CTL_ELEM_ACCESS_WRITE;
+}
+
 static int scarlett2_sw_hw_enum_ctl_info(struct snd_kcontrol *kctl,
 					 struct snd_ctl_elem_info *uinfo)
 {
@@ -2320,6 +2348,13 @@ static int scarlett2_update_monitor_other(struct usb_mixer_interface *mixer)
 {
 	struct scarlett2_data *private = mixer->private_data;
 	const struct scarlett2_device_info *info = private->info;
+	int err;
+
+	/* monitor_other_enable[0] enables speaker switching */
+	u8 monitor_other_enable[2];
+
+	/* monitor_other_switch[0] activates the alternate speakers */
+	u8 monitor_other_switch[2];
 
 	private->monitor_other_updated = 0;
 
@@ -2328,6 +2363,26 @@ static int scarlett2_update_monitor_other(struct usb_mixer_interface *mixer)
 			mixer, SCARLETT2_CONFIG_DIRECT_MONITOR,
 			1, &private->direct_monitor_switch);
 
+	if (!info->has_speaker_switching)
+		return 0;
+
+	err = scarlett2_usb_get_config(
+		mixer, SCARLETT2_CONFIG_MONITOR_OTHER_ENABLE,
+		2, monitor_other_enable);
+	if (err < 0)
+		return err;
+
+	err = scarlett2_usb_get_config(
+		mixer, SCARLETT2_CONFIG_MONITOR_OTHER_SWITCH,
+		2, monitor_other_switch);
+	if (err < 0)
+		return err;
+
+	if (!monitor_other_enable[0])
+		private->speaker_switching_switch = 0;
+	else
+		private->speaker_switching_switch = monitor_other_switch[0] + 1;
+
 	return 0;
 }
 
@@ -2420,6 +2475,151 @@ static int scarlett2_add_direct_monitor_ctl(struct usb_mixer_interface *mixer)
 		&private->direct_monitor_ctl);
 }
 
+/*** Speaker Switching Control ***/
+
+static int scarlett2_speaker_switch_enum_ctl_info(
+	struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo)
+{
+	static const char *const values[3] = {
+		"Off", "Main", "Alt"
+	};
+
+	return snd_ctl_enum_info(uinfo, 1, 3, values);
+}
+
+static int scarlett2_speaker_switch_enum_ctl_get(
+	struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol)
+{
+	struct usb_mixer_elem_info *elem = kctl->private_data;
+	struct usb_mixer_interface *mixer = elem->head.mixer;
+	struct scarlett2_data *private = mixer->private_data;
+
+	mutex_lock(&private->data_mutex);
+	if (private->monitor_other_updated)
+		scarlett2_update_monitor_other(mixer);
+	ucontrol->value.enumerated.item[0] = private->speaker_switching_switch;
+	mutex_unlock(&private->data_mutex);
+
+	return 0;
+}
+
+/* when speaker switching gets enabled, switch the main/alt speakers
+ * to HW volume and disable those controls
+ */
+static void scarlett2_speaker_switch_enable(struct usb_mixer_interface *mixer)
+{
+	struct snd_card *card = mixer->chip->card;
+	struct scarlett2_data *private = mixer->private_data;
+	int i;
+
+	for (i = 0; i < 4; i++) {
+		int index = line_out_remap(private, i);
+
+		/* switch the main/alt speakers to HW volume */
+		if (!private->vol_sw_hw_switch[index])
+			scarlett2_sw_hw_change(private->mixer, i, 1);
+
+		/* disable the line out SW/HW switch */
+		scarlett2_sw_hw_ctl_ro(private, i);
+		snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO,
+			       &private->sw_hw_ctls[i]->id);
+	}
+
+	/* when the next monitor-other notify comes in, update the mux
+	 * configuration
+	 */
+	private->speaker_switching_switched = 1;
+}
+
+/* when speaker switching gets disabled, reenable the hw/sw controls
+ * and invalidate the routing
+ */
+static void scarlett2_speaker_switch_disable(struct usb_mixer_interface *mixer)
+{
+	struct snd_card *card = mixer->chip->card;
+	struct scarlett2_data *private = mixer->private_data;
+	int i;
+
+	/* enable the line out SW/HW switch */
+	for (i = 0; i < 4; i++) {
+		scarlett2_sw_hw_ctl_rw(private, i);
+		snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO,
+			       &private->sw_hw_ctls[i]->id);
+	}
+
+	/* when the next monitor-other notify comes in, update the mux
+	 * configuration
+	 */
+	private->speaker_switching_switched = 1;
+}
+
+static int scarlett2_speaker_switch_enum_ctl_put(
+	struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol)
+{
+	struct usb_mixer_elem_info *elem = kctl->private_data;
+	struct usb_mixer_interface *mixer = elem->head.mixer;
+	struct scarlett2_data *private = mixer->private_data;
+
+	int oval, val, err = 0;
+
+	mutex_lock(&private->data_mutex);
+
+	oval = private->speaker_switching_switch;
+	val = min(ucontrol->value.enumerated.item[0], 2U);
+
+	if (oval == val)
+		goto unlock;
+
+	private->speaker_switching_switch = val;
+
+	/* enable/disable speaker switching */
+	err = scarlett2_usb_set_config(
+		mixer, SCARLETT2_CONFIG_MONITOR_OTHER_ENABLE,
+		0, !!val);
+	if (err < 0)
+		goto unlock;
+
+	/* if speaker switching is enabled, select main or alt */
+	err = scarlett2_usb_set_config(
+		mixer, SCARLETT2_CONFIG_MONITOR_OTHER_SWITCH,
+		0, val == 2);
+	if (err < 0)
+		goto unlock;
+
+	/* update controls if speaker switching gets enabled or disabled */
+	if (!oval && val)
+		scarlett2_speaker_switch_enable(mixer);
+	else if (oval && !val)
+		scarlett2_speaker_switch_disable(mixer);
+
+unlock:
+	mutex_unlock(&private->data_mutex);
+	return err;
+}
+
+static const struct snd_kcontrol_new scarlett2_speaker_switch_enum_ctl = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "",
+	.info = scarlett2_speaker_switch_enum_ctl_info,
+	.get  = scarlett2_speaker_switch_enum_ctl_get,
+	.put  = scarlett2_speaker_switch_enum_ctl_put,
+};
+
+static int scarlett2_add_speaker_switch_ctl(
+	struct usb_mixer_interface *mixer)
+{
+	struct scarlett2_data *private = mixer->private_data;
+	const struct scarlett2_device_info *info = private->info;
+
+	if (!info->has_speaker_switching)
+		return 0;
+
+	return scarlett2_add_new_ctl(
+		mixer, &scarlett2_speaker_switch_enum_ctl,
+		0, 1, "Speaker Switching Playback Enum",
+		&private->speaker_switching_ctl);
+}
+
 /*** Dim/Mute Controls ***/
 
 static int scarlett2_dim_mute_ctl_get(struct snd_kcontrol *kctl,
@@ -2562,6 +2762,12 @@ static int scarlett2_add_line_out_ctls(struct usb_mixer_interface *mixer)
 						    &private->sw_hw_ctls[i]);
 			if (err < 0)
 				return err;
+
+			/* Make the switch read-only if the line is
+			 * involved in speaker switching
+			 */
+			if (private->speaker_switching_switch && i < 4)
+				scarlett2_sw_hw_ctl_ro(private, i);
 		}
 	}
 
@@ -3309,18 +3515,41 @@ static void scarlett2_notify_input_other(
 			       &private->phantom_ctls[i]->id);
 }
 
-/* Notify on "monitor other" change (direct monitor) */
+/* Notify on "monitor other" change (direct monitor, speaker switching) */
 static void scarlett2_notify_monitor_other(
 	struct usb_mixer_interface *mixer)
 {
-	struct scarlett2_data *private = mixer->private_data;
 	struct snd_card *card = mixer->chip->card;
+	struct scarlett2_data *private = mixer->private_data;
+	const struct scarlett2_device_info *info = private->info;
 
 	private->monitor_other_updated = 1;
 
-	if (private->info->direct_monitor)
+	if (info->direct_monitor) {
 		snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
 			       &private->direct_monitor_ctl->id);
+		return;
+	}
+
+	if (info->has_speaker_switching)
+		snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+			       &private->speaker_switching_ctl->id);
+
+	/* if speaker switching was recently enabled or disabled,
+	 * invalidate the dim/mute and mux enum controls
+	 */
+	if (private->speaker_switching_switched) {
+		int i;
+
+		scarlett2_notify_dim_mute(mixer);
+
+		private->speaker_switching_switched = 0;
+		private->mux_updated = 1;
+
+		for (i = 0; i < private->num_mux_dsts; i++)
+			snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+				       &private->mux_ctls[i]->id);
+	}
 }
 
 /* Interrupt callback */
@@ -3456,6 +3685,11 @@ static int snd_scarlett_gen2_controls_create(struct usb_mixer_interface *mixer)
 	if (err < 0)
 		return err;
 
+	/* Create the speaker switching control */
+	err = scarlett2_add_speaker_switch_ctl(mixer);
+	if (err < 0)
+		return err;
+
 	/* Set up the interrupt polling */
 	err = scarlett2_init_notify(mixer);
 	if (err < 0)
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 30/31] ALSA: usb-audio: scarlett2: Update get_config to do endian conversion
  2021-06-21 18:09 [PATCH 00/31] Refactor Scarlett Gen 2 support and add Scarlett Gen 3 support Geoffrey D. Bennett
                   ` (28 preceding siblings ...)
  2021-06-21 18:10 ` [PATCH 29/31] ALSA: usb-audio: scarlett2: Add speaker switching support Geoffrey D. Bennett
@ 2021-06-21 18:10 ` Geoffrey D. Bennett
  2021-06-21 18:10 ` [PATCH 31/31] ALSA: usb-audio: scarlett2: Add support for the talkback feature Geoffrey D. Bennett
  30 siblings, 0 replies; 43+ messages in thread
From: Geoffrey D. Bennett @ 2021-06-21 18:10 UTC (permalink / raw)
  To: alsa-devel, Takashi Iwai; +Cc: Hin-Tak Leung, Vladimir Sadovnikov

For configuration items with a size of 16, scarlett2_usb_get_config()
was filling *buf with little-endian data. Update it to convert to CPU
endian. This function is not currently used so affects nothing yet;
will be used by the upcoming talkback feature.

Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
---
 sound/usb/mixer_scarlett_gen2.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c
index dc5fd045b2dc..8fd850f6aa6e 100644
--- a/sound/usb/mixer_scarlett_gen2.c
+++ b/sound/usb/mixer_scarlett_gen2.c
@@ -1170,7 +1170,13 @@ static int scarlett2_usb_get_config(
 	/* For byte-sized parameters, retrieve directly into buf */
 	if (config_item->size >= 8) {
 		size = config_item->size / 8 * count;
-		return scarlett2_usb_get(mixer, config_item->offset, buf, size);
+		err = scarlett2_usb_get(mixer, config_item->offset, buf, size);
+		if (err < 0)
+			return err;
+		if (size == 2)
+			for (i = 0; i < count; i++, (u16 *)buf++)
+				*(u16 *)buf = le16_to_cpu(*(__le16 *)buf);
+		return 0;
 	}
 
 	/* For bit-sized parameters, retrieve into value */
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 31/31] ALSA: usb-audio: scarlett2: Add support for the talkback feature
  2021-06-21 18:09 [PATCH 00/31] Refactor Scarlett Gen 2 support and add Scarlett Gen 3 support Geoffrey D. Bennett
                   ` (29 preceding siblings ...)
  2021-06-21 18:10 ` [PATCH 30/31] ALSA: usb-audio: scarlett2: Update get_config to do endian conversion Geoffrey D. Bennett
@ 2021-06-21 18:10 ` Geoffrey D. Bennett
  30 siblings, 0 replies; 43+ messages in thread
From: Geoffrey D. Bennett @ 2021-06-21 18:10 UTC (permalink / raw)
  To: alsa-devel, Takashi Iwai; +Cc: Hin-Tak Leung, Vladimir Sadovnikov

Add support for the talkback feature of the 18i20 Gen 3.

Co-developed-by: Vladimir Sadovnikov <sadko4u@gmail.com>
Signed-off-by: Vladimir Sadovnikov <sadko4u@gmail.com>
Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
---
 sound/usb/mixer_scarlett_gen2.c | 229 +++++++++++++++++++++++++++++++-
 1 file changed, 222 insertions(+), 7 deletions(-)

diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c
index 8fd850f6aa6e..fcf78b06a519 100644
--- a/sound/usb/mixer_scarlett_gen2.c
+++ b/sound/usb/mixer_scarlett_gen2.c
@@ -48,8 +48,8 @@
  * Support for Solo/2i2 Gen 3 added in May 2021 (thanks to Alexander
  * Vorona for 2i2 protocol traces).
  *
- * Support for phantom power, direct monitoring, and speaker switching
- * added in May-June 2021.
+ * Support for phantom power, direct monitoring, speaker switching,
+ * and talkback added in May-June 2021.
  *
  * This ALSA mixer gives access to (model-dependent):
  *  - input, output, mixer-matrix muxes
@@ -57,7 +57,8 @@
  *  - gain/volume/mute controls
  *  - level meters
  *  - line/inst level, pad, and air controls
- *  - phantom power, direct monitor, and speaker switching controls
+ *  - phantom power, direct monitor, speaker switching, and talkback
+ *    controls
  *  - disable/enable MSD mode
  *
  * <ditaa>
@@ -318,6 +319,9 @@ struct scarlett2_device_info {
 	/* support for main/alt speaker switching */
 	u8 has_speaker_switching;
 
+	/* support for talkback microphone */
+	u8 has_talkback;
+
 	/* the number of analogue inputs with a software switchable
 	 * level control that can be set to line or instrument
 	 */
@@ -396,6 +400,8 @@ struct scarlett2_data {
 	u8 phantom_persistence;
 	u8 direct_monitor_switch;
 	u8 speaker_switching_switch;
+	u8 talkback_switch;
+	u8 talkback_map[SCARLETT2_OUTPUT_MIX_MAX];
 	u8 msd_switch;
 	struct snd_kcontrol *sync_ctl;
 	struct snd_kcontrol *master_vol_ctl;
@@ -410,6 +416,7 @@ struct scarlett2_data {
 	struct snd_kcontrol *mux_ctls[SCARLETT2_MUX_MAX];
 	struct snd_kcontrol *direct_monitor_ctl;
 	struct snd_kcontrol *speaker_switching_ctl;
+	struct snd_kcontrol *talkback_ctl;
 	u8 mux[SCARLETT2_MUX_MAX];
 	u8 mix[SCARLETT2_INPUT_MIX_MAX * SCARLETT2_OUTPUT_MIX_MAX];
 };
@@ -764,6 +771,7 @@ static const struct scarlett2_device_info s18i20_gen3_info = {
 	.has_mixer = 1,
 	.line_out_hw_vol = 1,
 	.has_speaker_switching = 1,
+	.has_talkback = 1,
 	.level_input_count = 2,
 	.pad_input_count = 8,
 	.air_input_count = 8,
@@ -923,7 +931,8 @@ enum {
 	SCARLETT2_CONFIG_DIRECT_MONITOR = 10,
 	SCARLETT2_CONFIG_MONITOR_OTHER_SWITCH = 11,
 	SCARLETT2_CONFIG_MONITOR_OTHER_ENABLE = 12,
-	SCARLETT2_CONFIG_COUNT = 13
+	SCARLETT2_CONFIG_TALKBACK_MAP = 13,
+	SCARLETT2_CONFIG_COUNT = 14
 };
 
 /* Location, size, and activation command number for the configuration
@@ -998,6 +1007,9 @@ static const struct scarlett2_config
 
 	[SCARLETT2_CONFIG_MONITOR_OTHER_ENABLE] = {
 		.offset = 0xa0, .size = 1, .activate = 10 },
+
+	[SCARLETT2_CONFIG_TALKBACK_MAP] = {
+		.offset = 0xb0, .size = 16, .activate = 10 },
 } };
 
 /* proprietary request/response format */
@@ -2356,10 +2368,14 @@ static int scarlett2_update_monitor_other(struct usb_mixer_interface *mixer)
 	const struct scarlett2_device_info *info = private->info;
 	int err;
 
-	/* monitor_other_enable[0] enables speaker switching */
+	/* monitor_other_enable[0] enables speaker switching
+	 * monitor_other_enable[1] enables talkback
+	 */
 	u8 monitor_other_enable[2];
 
-	/* monitor_other_switch[0] activates the alternate speakers */
+	/* monitor_other_switch[0] activates the alternate speakers
+	 * monitor_other_switch[1] activates talkback
+	 */
 	u8 monitor_other_switch[2];
 
 	private->monitor_other_updated = 0;
@@ -2369,6 +2385,9 @@ static int scarlett2_update_monitor_other(struct usb_mixer_interface *mixer)
 			mixer, SCARLETT2_CONFIG_DIRECT_MONITOR,
 			1, &private->direct_monitor_switch);
 
+	/* if it doesn't do speaker switching then it also doesn't do
+	 * talkback
+	 */
 	if (!info->has_speaker_switching)
 		return 0;
 
@@ -2389,6 +2408,26 @@ static int scarlett2_update_monitor_other(struct usb_mixer_interface *mixer)
 	else
 		private->speaker_switching_switch = monitor_other_switch[0] + 1;
 
+	if (info->has_talkback) {
+		const int (*port_count)[SCARLETT2_PORT_DIRNS] =
+			info->port_count;
+		int num_mixes =
+			port_count[SCARLETT2_PORT_TYPE_MIX][SCARLETT2_PORT_IN];
+		u16 bitmap;
+		int i;
+
+		if (!monitor_other_enable[1])
+			private->talkback_switch = 0;
+		else
+			private->talkback_switch = monitor_other_switch[1] + 1;
+
+		err = scarlett2_usb_get_config(mixer,
+					       SCARLETT2_CONFIG_TALKBACK_MAP,
+					       1, &bitmap);
+		for (i = 0; i < num_mixes; i++, bitmap >>= 1)
+			private->talkback_map[i] = bitmap & 1;
+	}
+
 	return 0;
 }
 
@@ -2626,6 +2665,171 @@ static int scarlett2_add_speaker_switch_ctl(
 		&private->speaker_switching_ctl);
 }
 
+/*** Talkback and Talkback Map Controls ***/
+
+static int scarlett2_talkback_enum_ctl_info(
+	struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo)
+{
+	static const char *const values[3] = {
+		"Disabled", "Off", "On"
+	};
+
+	return snd_ctl_enum_info(uinfo, 1, 3, values);
+}
+
+static int scarlett2_talkback_enum_ctl_get(
+	struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol)
+{
+	struct usb_mixer_elem_info *elem = kctl->private_data;
+	struct usb_mixer_interface *mixer = elem->head.mixer;
+	struct scarlett2_data *private = mixer->private_data;
+
+	mutex_lock(&private->data_mutex);
+	if (private->monitor_other_updated)
+		scarlett2_update_monitor_other(mixer);
+	ucontrol->value.enumerated.item[0] = private->talkback_switch;
+	mutex_unlock(&private->data_mutex);
+
+	return 0;
+}
+
+static int scarlett2_talkback_enum_ctl_put(
+	struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol)
+{
+	struct usb_mixer_elem_info *elem = kctl->private_data;
+	struct usb_mixer_interface *mixer = elem->head.mixer;
+	struct scarlett2_data *private = mixer->private_data;
+
+	int oval, val, err = 0;
+
+	mutex_lock(&private->data_mutex);
+
+	oval = private->talkback_switch;
+	val = min(ucontrol->value.enumerated.item[0], 2U);
+
+	if (oval == val)
+		goto unlock;
+
+	private->talkback_switch = val;
+
+	/* enable/disable talkback */
+	err = scarlett2_usb_set_config(
+		mixer, SCARLETT2_CONFIG_MONITOR_OTHER_ENABLE,
+		1, !!val);
+	if (err < 0)
+		goto unlock;
+
+	/* if talkback is enabled, select main or alt */
+	err = scarlett2_usb_set_config(
+		mixer, SCARLETT2_CONFIG_MONITOR_OTHER_SWITCH,
+		1, val == 2);
+	if (err < 0)
+		goto unlock;
+
+unlock:
+	mutex_unlock(&private->data_mutex);
+	return err;
+}
+
+static const struct snd_kcontrol_new scarlett2_talkback_enum_ctl = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "",
+	.info = scarlett2_talkback_enum_ctl_info,
+	.get  = scarlett2_talkback_enum_ctl_get,
+	.put  = scarlett2_talkback_enum_ctl_put,
+};
+
+static int scarlett2_talkback_map_ctl_get(
+	struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol)
+{
+	struct usb_mixer_elem_info *elem = kctl->private_data;
+	struct usb_mixer_interface *mixer = elem->head.mixer;
+	struct scarlett2_data *private = mixer->private_data;
+	int index = elem->control;
+
+	ucontrol->value.integer.value[0] = private->talkback_map[index];
+
+	return 0;
+}
+
+static int scarlett2_talkback_map_ctl_put(
+	struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol)
+{
+	struct usb_mixer_elem_info *elem = kctl->private_data;
+	struct usb_mixer_interface *mixer = elem->head.mixer;
+	struct scarlett2_data *private = mixer->private_data;
+	const int (*port_count)[SCARLETT2_PORT_DIRNS] =
+		private->info->port_count;
+	int num_mixes = port_count[SCARLETT2_PORT_TYPE_MIX][SCARLETT2_PORT_IN];
+
+	int index = elem->control;
+	int oval, val, err = 0, i;
+	u16 bitmap = 0;
+
+	mutex_lock(&private->data_mutex);
+
+	oval = private->talkback_map[index];
+	val = !!ucontrol->value.integer.value[0];
+
+	if (oval == val)
+		goto unlock;
+
+	private->talkback_map[index] = val;
+
+	for (i = 0; i < num_mixes; i++)
+		bitmap |= private->talkback_map[i] << i;
+
+	/* Send updated bitmap to the device */
+	err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_TALKBACK_MAP,
+				       0, bitmap);
+	if (err < 0)
+		goto unlock;
+
+unlock:
+	mutex_unlock(&private->data_mutex);
+	return err;
+}
+
+static const struct snd_kcontrol_new scarlett2_talkback_map_ctl = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "",
+	.info = snd_ctl_boolean_mono_info,
+	.get  = scarlett2_talkback_map_ctl_get,
+	.put  = scarlett2_talkback_map_ctl_put,
+};
+
+static int scarlett2_add_talkback_ctls(
+	struct usb_mixer_interface *mixer)
+{
+	struct scarlett2_data *private = mixer->private_data;
+	const struct scarlett2_device_info *info = private->info;
+	const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count;
+	int num_mixes = port_count[SCARLETT2_PORT_TYPE_MIX][SCARLETT2_PORT_IN];
+	int err, i;
+	char s[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+
+	if (!info->has_talkback)
+		return 0;
+
+	err = scarlett2_add_new_ctl(
+		mixer, &scarlett2_talkback_enum_ctl,
+		0, 1, "Talkback Playback Enum",
+		&private->talkback_ctl);
+	if (err < 0)
+		return err;
+
+	for (i = 0; i < num_mixes; i++) {
+		snprintf(s, sizeof(s),
+			 "Talkback Mix %c Playback Switch", i + 'A');
+		err = scarlett2_add_new_ctl(mixer, &scarlett2_talkback_map_ctl,
+					    i, 1, s, NULL);
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+
 /*** Dim/Mute Controls ***/
 
 static int scarlett2_dim_mute_ctl_get(struct snd_kcontrol *kctl,
@@ -3521,7 +3725,9 @@ static void scarlett2_notify_input_other(
 			       &private->phantom_ctls[i]->id);
 }
 
-/* Notify on "monitor other" change (direct monitor, speaker switching) */
+/* Notify on "monitor other" change (direct monitor, speaker
+ * switching, talkback)
+ */
 static void scarlett2_notify_monitor_other(
 	struct usb_mixer_interface *mixer)
 {
@@ -3541,6 +3747,10 @@ static void scarlett2_notify_monitor_other(
 		snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
 			       &private->speaker_switching_ctl->id);
 
+	if (info->has_talkback)
+		snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+			       &private->talkback_ctl->id);
+
 	/* if speaker switching was recently enabled or disabled,
 	 * invalidate the dim/mute and mux enum controls
 	 */
@@ -3696,6 +3906,11 @@ static int snd_scarlett_gen2_controls_create(struct usb_mixer_interface *mixer)
 	if (err < 0)
 		return err;
 
+	/* Create the talkback controls */
+	err = scarlett2_add_talkback_ctls(mixer);
+	if (err < 0)
+		return err;
+
 	/* Set up the interrupt polling */
 	err = scarlett2_init_notify(mixer);
 	if (err < 0)
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* Re: [PATCH 16/31] ALSA: usb-audio: scarlett2: Add Gen 3 mixer support
  2021-06-21 18:09 ` [PATCH 16/31] ALSA: usb-audio: scarlett2: Add Gen 3 mixer support Geoffrey D. Bennett
@ 2021-06-22  7:00   ` Takashi Iwai
  2021-06-22  7:07     ` Vladimir Sadovnikov
  2021-06-22  7:24     ` Geoffrey D. Bennett
  0 siblings, 2 replies; 43+ messages in thread
From: Takashi Iwai @ 2021-06-22  7:00 UTC (permalink / raw)
  To: Geoffrey D. Bennett; +Cc: Hin-Tak Leung, alsa-devel, Vladimir Sadovnikov

On Mon, 21 Jun 2021 20:09:48 +0200,
Geoffrey D. Bennett wrote:
> 
> Add mixer support for the Focusrite Scarlett 4i4, 8i6, 18i8, and 18i20
> Gen 3 devices.
> 
> Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
> ---
>  sound/usb/mixer.c               |   2 +-
>  sound/usb/mixer_quirks.c        |   4 +
>  sound/usb/mixer_scarlett_gen2.c | 260 +++++++++++++++++++++++++++++---
>  3 files changed, 246 insertions(+), 20 deletions(-)
> 
> diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
> index 428d581f988f..ba4aa1eacb04 100644
> --- a/sound/usb/mixer.c
> +++ b/sound/usb/mixer.c
> @@ -50,7 +50,7 @@
>  #include "mixer_quirks.h"
>  #include "power.h"
>  
> -#define MAX_ID_ELEMS	256
> +#define MAX_ID_ELEMS	512

This change requires the explanation.
Usually the unit id is a byte per definition, so it can't be over
256.


thanks,

Takashi

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 16/31] ALSA: usb-audio: scarlett2: Add Gen 3 mixer support
  2021-06-22  7:00   ` Takashi Iwai
@ 2021-06-22  7:07     ` Vladimir Sadovnikov
  2021-06-22  7:25       ` [PATCH v2 " Geoffrey D. Bennett
  2021-06-22  7:34       ` [PATCH " Takashi Iwai
  2021-06-22  7:24     ` Geoffrey D. Bennett
  1 sibling, 2 replies; 43+ messages in thread
From: Vladimir Sadovnikov @ 2021-06-22  7:07 UTC (permalink / raw)
  To: Takashi Iwai, Geoffrey D. Bennett; +Cc: Hin-Tak Leung, alsa-devel

Hello Takashi!

Since Focusrite devices are too advanced in settings, the overall amount of 256 
controls is not enough for these devices (like 18i20).
I would like also to extend this constant up to 1024 or even more since adding 
support of software configuration of the device also
can exceed the amount of 512 control elements.

Let's assume we have a mute switch for each mixer gain setting. For the 18i20 
device this will give:
12 inputs * 25 outputs = 300 mute switches.

So I think this constant should be increased rapidly up to 1024 or even to 2048.

Best,
Vladimir

22.06.2021 10:00, Takashi Iwai пишет:
> On Mon, 21 Jun 2021 20:09:48 +0200,
> Geoffrey D. Bennett wrote:
>> Add mixer support for the Focusrite Scarlett 4i4, 8i6, 18i8, and 18i20
>> Gen 3 devices.
>>
>> Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
>> ---
>>   sound/usb/mixer.c               |   2 +-
>>   sound/usb/mixer_quirks.c        |   4 +
>>   sound/usb/mixer_scarlett_gen2.c | 260 +++++++++++++++++++++++++++++---
>>   3 files changed, 246 insertions(+), 20 deletions(-)
>>
>> diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
>> index 428d581f988f..ba4aa1eacb04 100644
>> --- a/sound/usb/mixer.c
>> +++ b/sound/usb/mixer.c
>> @@ -50,7 +50,7 @@
>>   #include "mixer_quirks.h"
>>   #include "power.h"
>>   
>> -#define MAX_ID_ELEMS	256
>> +#define MAX_ID_ELEMS	512
> This change requires the explanation.
> Usually the unit id is a byte per definition, so it can't be over
> 256.
>
>
> thanks,
>
> Takashi



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 16/31] ALSA: usb-audio: scarlett2: Add Gen 3 mixer support
  2021-06-22  7:00   ` Takashi Iwai
  2021-06-22  7:07     ` Vladimir Sadovnikov
@ 2021-06-22  7:24     ` Geoffrey D. Bennett
  1 sibling, 0 replies; 43+ messages in thread
From: Geoffrey D. Bennett @ 2021-06-22  7:24 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: Hin-Tak Leung, alsa-devel, Vladimir Sadovnikov

On Tue, Jun 22, 2021 at 09:00:19AM +0200, Takashi Iwai wrote:
> On Mon, 21 Jun 2021 20:09:48 +0200,
> Geoffrey D. Bennett wrote:
> > 
> > Add mixer support for the Focusrite Scarlett 4i4, 8i6, 18i8, and 18i20
> > Gen 3 devices.
> > 
> > Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
> > ---
> >  sound/usb/mixer.c               |   2 +-
> >  sound/usb/mixer_quirks.c        |   4 +
> >  sound/usb/mixer_scarlett_gen2.c | 260 +++++++++++++++++++++++++++++---
> >  3 files changed, 246 insertions(+), 20 deletions(-)
> > 
> > diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
> > index 428d581f988f..ba4aa1eacb04 100644
> > --- a/sound/usb/mixer.c
> > +++ b/sound/usb/mixer.c
> > @@ -50,7 +50,7 @@
> >  #include "mixer_quirks.h"
> >  #include "power.h"
> >  
> > -#define MAX_ID_ELEMS	256
> > +#define MAX_ID_ELEMS	512
> 
> This change requires the explanation.
> Usually the unit id is a byte per definition, so it can't be over
> 256.

Before making this change we were getting a buffer overflow in
mixer->id_elems[] (snd_usb_mixer_add_list()) because more than 256
controls were being added for the 18i20 Gen 3 device. I will send a
replacement patch with an updated comment.

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH v2 16/31] ALSA: usb-audio: scarlett2: Add Gen 3 mixer support
  2021-06-22  7:07     ` Vladimir Sadovnikov
@ 2021-06-22  7:25       ` Geoffrey D. Bennett
  2021-06-22  7:34       ` [PATCH " Takashi Iwai
  1 sibling, 0 replies; 43+ messages in thread
From: Geoffrey D. Bennett @ 2021-06-22  7:25 UTC (permalink / raw)
  To: alsa-devel, Takashi Iwai; +Cc: Hin-Tak Leung, Vladimir Sadovnikov

Add mixer support for the Focusrite Scarlett 4i4, 8i6, 18i8, and 18i20
Gen 3 devices.

Change mixer.c MAX_ID_ELEMS from 256 to 512 as there are now more than
256 controls needed by the 18i20 Gen 3. The majority of these are the
gain controls for the mixer matrix which has 25 inputs and 12 outputs,
so 300 controls.

Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
---
 sound/usb/mixer.c               |   2 +-
 sound/usb/mixer_quirks.c        |   4 +
 sound/usb/mixer_scarlett_gen2.c | 260 +++++++++++++++++++++++++++++---
 3 files changed, 246 insertions(+), 20 deletions(-)

diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 428d581f988f..ba4aa1eacb04 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -50,7 +50,7 @@
 #include "mixer_quirks.h"
 #include "power.h"
 
-#define MAX_ID_ELEMS	256
+#define MAX_ID_ELEMS	512
 
 struct usb_audio_term {
 	int id;
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index 37ad77524c0b..df7492594e91 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -3060,6 +3060,10 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
 	case USB_ID(0x1235, 0x8203): /* Focusrite Scarlett 6i6 2nd Gen */
 	case USB_ID(0x1235, 0x8204): /* Focusrite Scarlett 18i8 2nd Gen */
 	case USB_ID(0x1235, 0x8201): /* Focusrite Scarlett 18i20 2nd Gen */
+	case USB_ID(0x1235, 0x8212): /* Focusrite Scarlett 4i4 3rd Gen */
+	case USB_ID(0x1235, 0x8213): /* Focusrite Scarlett 8i6 3rd Gen */
+	case USB_ID(0x1235, 0x8214): /* Focusrite Scarlett 18i8 3rd Gen */
+	case USB_ID(0x1235, 0x8215): /* Focusrite Scarlett 18i20 3rd Gen */
 		err = snd_scarlett_gen2_init(mixer);
 		break;
 
diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c
index dde008ea21d7..c4bcccb5aecd 100644
--- a/sound/usb/mixer_scarlett_gen2.c
+++ b/sound/usb/mixer_scarlett_gen2.c
@@ -1,8 +1,12 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- *   Focusrite Scarlett 6i6/18i8/18i20 Gen 2 Driver for ALSA
+ *   Focusrite Scarlett Gen 2/3 Driver for ALSA
  *
- *   Copyright (c) 2018-2019 by Geoffrey D. Bennett <g at b4.vu>
+ *   Supported models:
+ *   - 6i6/18i8/18i20 Gen 2
+ *   - 4i4/8i6/18i8/18i20 Gen 3
+ *
+ *   Copyright (c) 2018-2021 by Geoffrey D. Bennett <g at b4.vu>
  *
  *   Based on the Scarlett (Gen 1) Driver for ALSA:
  *
@@ -19,10 +23,6 @@
  *   David Henningsson <david.henningsson at canonical.com>
  */
 
-/* Mixer Interface for the Focusrite Scarlett 6i6/18i8/18i20 Gen 2 audio
- * interface. Based on the Gen 1 driver and rewritten.
- */
-
 /* The protocol was reverse engineered by looking at the communication
  * between Focusrite Control 2.3.4 and the Focusrite(R) Scarlett 18i20
  * (firmware 1083) using usbmon in July-August 2018.
@@ -32,13 +32,21 @@
  * Scarlett 6i6 support added in June 2019 (thanks to Martin Wittmann
  * for providing usbmon output and testing).
  *
+ * Scarlett 4i4/8i6 Gen 3 support added in May 2020 (thanks to Laurent
+ * Debricon for donating a 4i4 and to Fredrik Unger for providing 8i6
+ * usbmon output and testing).
+ *
+ * Scarlett 18i8/18i20 Gen 3 support added in June 2020 (thanks to
+ * Darren Jaeckel, Alex Sedlack, and Clovis Lunel for providing usbmon
+ * output, protocol traces 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
+ *  - mixer-matrix gain stages
  *  - gain/volume/mute controls
  *  - level meters
  *  - line/inst level and pad controls
@@ -148,21 +156,21 @@ static const u16 scarlett2_mixer_values[SCARLETT2_MIXER_VALUE_COUNT] = {
 
 /* Maximum number of level and pad switches */
 #define SCARLETT2_LEVEL_SWITCH_MAX 2
-#define SCARLETT2_PAD_SWITCH_MAX 4
+#define SCARLETT2_PAD_SWITCH_MAX 8
 
 /* Maximum number of inputs to the mixer */
-#define SCARLETT2_INPUT_MIX_MAX 18
+#define SCARLETT2_INPUT_MIX_MAX 25
 
 /* Maximum number of outputs from the mixer */
-#define SCARLETT2_OUTPUT_MIX_MAX 10
+#define SCARLETT2_OUTPUT_MIX_MAX 12
 
 /* Maximum size of the data in the USB mux assignment message:
- * 18 inputs, 20 outputs, 18 matrix inputs, 8 spare
+ * 20 inputs, 20 outputs, 25 matrix inputs, 12 spare
  */
-#define SCARLETT2_MUX_MAX 64
+#define SCARLETT2_MUX_MAX 77
 
 /* Maximum number of meters (sum of output port counts) */
-#define SCARLETT2_MAX_METERS 56
+#define SCARLETT2_MAX_METERS 65
 
 /* Hardware port types:
  * - None (no input to mux)
@@ -256,7 +264,7 @@ static const struct scarlett2_port scarlett2_ports[SCARLETT2_PORT_TYPE_COUNT] =
 #define SCARLETT2_MUX_TABLES 3
 
 /* Maximum number of entries in a mux table */
-#define SCARLETT2_MAX_MUX_ENTRIES 7
+#define SCARLETT2_MAX_MUX_ENTRIES 10
 
 /* 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
@@ -475,12 +483,226 @@ static const struct scarlett2_device_info s18i20_gen2_info = {
 	} },
 };
 
+static const struct scarlett2_device_info s4i4_gen3_info = {
+	.usb_id = USB_ID(0x1235, 0x8212),
+
+	.level_input_count = 2,
+	.pad_input_count = 2,
+
+	.line_out_descrs = {
+		"Monitor L",
+		"Monitor R",
+		"Headphones L",
+		"Headphones R",
+	},
+
+	.port_count = {
+		[SCARLETT2_PORT_TYPE_NONE]     = { 1, 0 },
+		[SCARLETT2_PORT_TYPE_ANALOGUE] = { 4, 4 },
+		[SCARLETT2_PORT_TYPE_MIX]      = { 6, 8 },
+		[SCARLETT2_PORT_TYPE_PCM]      = { 4, 6 },
+	},
+
+	.mux_assignment = { {
+		{ SCARLETT2_PORT_TYPE_PCM,      0,  6 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE, 0,  4 },
+		{ SCARLETT2_PORT_TYPE_MIX,      0,  8 },
+		{ SCARLETT2_PORT_TYPE_NONE,     0, 16 },
+		{ 0,                            0,  0 },
+	}, {
+		{ SCARLETT2_PORT_TYPE_PCM,      0,  6 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE, 0,  4 },
+		{ SCARLETT2_PORT_TYPE_MIX,      0,  8 },
+		{ SCARLETT2_PORT_TYPE_NONE,     0, 16 },
+		{ 0,                            0,  0 },
+	}, {
+		{ SCARLETT2_PORT_TYPE_PCM,      0,  6 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE, 0,  4 },
+		{ SCARLETT2_PORT_TYPE_MIX,      0,  8 },
+		{ SCARLETT2_PORT_TYPE_NONE,     0, 16 },
+		{ 0,                            0,  0 },
+	} },
+};
+
+static const struct scarlett2_device_info s8i6_gen3_info = {
+	.usb_id = USB_ID(0x1235, 0x8213),
+
+	.level_input_count = 2,
+	.pad_input_count = 2,
+
+	.line_out_descrs = {
+		"Headphones 1 L",
+		"Headphones 1 R",
+		"Headphones 2 L",
+		"Headphones 2 R",
+	},
+
+	.port_count = {
+		[SCARLETT2_PORT_TYPE_NONE]     = { 1,  0 },
+		[SCARLETT2_PORT_TYPE_ANALOGUE] = { 6,  4 },
+		[SCARLETT2_PORT_TYPE_SPDIF]    = { 2,  2 },
+		[SCARLETT2_PORT_TYPE_MIX]      = { 8,  8 },
+		[SCARLETT2_PORT_TYPE_PCM]      = { 6, 10 },
+	},
+
+	.mux_assignment = { {
+		{ SCARLETT2_PORT_TYPE_PCM,      0,  8 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE, 0,  4 },
+		{ SCARLETT2_PORT_TYPE_SPDIF,    0,  2 },
+		{ SCARLETT2_PORT_TYPE_PCM,      8,  2 },
+		{ SCARLETT2_PORT_TYPE_MIX,      0,  8 },
+		{ SCARLETT2_PORT_TYPE_NONE,     0, 18 },
+		{ 0,                            0,  0 },
+	}, {
+		{ SCARLETT2_PORT_TYPE_PCM,      0,  8 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE, 0,  4 },
+		{ SCARLETT2_PORT_TYPE_SPDIF,    0,  2 },
+		{ SCARLETT2_PORT_TYPE_PCM,      8,  2 },
+		{ SCARLETT2_PORT_TYPE_MIX,      0,  8 },
+		{ SCARLETT2_PORT_TYPE_NONE,     0, 18 },
+		{ 0,                            0,  0 },
+	}, {
+		{ SCARLETT2_PORT_TYPE_PCM,      0,  8 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE, 0,  4 },
+		{ SCARLETT2_PORT_TYPE_SPDIF,    0,  2 },
+		{ SCARLETT2_PORT_TYPE_PCM,      8,  2 },
+		{ SCARLETT2_PORT_TYPE_MIX,      0,  8 },
+		{ SCARLETT2_PORT_TYPE_NONE,     0, 18 },
+		{ 0,                            0,  0 },
+	} },
+};
+
+static const struct scarlett2_device_info s18i8_gen3_info = {
+	.usb_id = USB_ID(0x1235, 0x8214),
+
+	.line_out_hw_vol = 1,
+	.level_input_count = 2,
+	.pad_input_count = 2,
+
+	.line_out_descrs = {
+		"Monitor L",
+		"Monitor R",
+		"Headphones 1 L",
+		"Headphones 1 R",
+		"Headphones 2 L",
+		"Headphones 2 R",
+		"Alt Monitor L",
+		"Alt Monitor R",
+	},
+
+	.port_count = {
+		[SCARLETT2_PORT_TYPE_NONE]     = {  1,  0 },
+		[SCARLETT2_PORT_TYPE_ANALOGUE] = {  8,  8 },
+		[SCARLETT2_PORT_TYPE_SPDIF]    = {  2,  2 },
+		[SCARLETT2_PORT_TYPE_ADAT]     = {  8,  0 },
+		[SCARLETT2_PORT_TYPE_MIX]      = { 10, 20 },
+		[SCARLETT2_PORT_TYPE_PCM]      = {  8, 20 },
+	},
+
+	.mux_assignment = { {
+		{ SCARLETT2_PORT_TYPE_PCM,       0, 10 },
+		{ SCARLETT2_PORT_TYPE_PCM,      12,  8 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE,  0,  2 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE,  6,  2 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE,  2,  4 },
+		{ SCARLETT2_PORT_TYPE_SPDIF,     0,  2 },
+		{ SCARLETT2_PORT_TYPE_PCM,      10,  2 },
+		{ SCARLETT2_PORT_TYPE_MIX,       0, 20 },
+		{ SCARLETT2_PORT_TYPE_NONE,      0, 10 },
+		{ 0,                             0,  0 },
+	}, {
+		{ SCARLETT2_PORT_TYPE_PCM,       0, 10 },
+		{ SCARLETT2_PORT_TYPE_PCM,      12,  4 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE,  0,  2 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE,  6,  2 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE,  2,  4 },
+		{ SCARLETT2_PORT_TYPE_SPDIF,     0,  2 },
+		{ SCARLETT2_PORT_TYPE_PCM,      10,  2 },
+		{ SCARLETT2_PORT_TYPE_MIX,       0, 20 },
+		{ SCARLETT2_PORT_TYPE_NONE,      0, 10 },
+		{ 0,                             0,  0 },
+	}, {
+		{ SCARLETT2_PORT_TYPE_PCM,       0, 10 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE,  0,  2 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE,  6,  2 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE,  2,  4 },
+		{ SCARLETT2_PORT_TYPE_SPDIF,     0,  2 },
+		{ SCARLETT2_PORT_TYPE_MIX,       0, 20 },
+		{ SCARLETT2_PORT_TYPE_NONE,      0, 10 },
+		{ 0,                             0,  0 },
+	} },
+};
+
+static const struct scarlett2_device_info s18i20_gen3_info = {
+	.usb_id = USB_ID(0x1235, 0x8215),
+
+	.line_out_hw_vol = 1,
+	.level_input_count = 2,
+	.pad_input_count = 8,
+
+	.line_out_descrs = {
+		"Monitor 1 L",
+		"Monitor 1 R",
+		"Monitor 2 L",
+		"Monitor 2 R",
+		NULL,
+		NULL,
+		"Headphones 1 L",
+		"Headphones 1 R",
+		"Headphones 2 L",
+		"Headphones 2 R",
+	},
+
+	.port_count = {
+		[SCARLETT2_PORT_TYPE_NONE]     = {  1,  0 },
+		[SCARLETT2_PORT_TYPE_ANALOGUE] = {  9, 10 },
+		[SCARLETT2_PORT_TYPE_SPDIF]    = {  2,  2 },
+		[SCARLETT2_PORT_TYPE_ADAT]     = {  8,  8 },
+		[SCARLETT2_PORT_TYPE_MIX]      = { 12, 25 },
+		[SCARLETT2_PORT_TYPE_PCM]      = { 20, 20 },
+	},
+
+	.mux_assignment = { {
+		{ SCARLETT2_PORT_TYPE_PCM,       0,  8 },
+		{ SCARLETT2_PORT_TYPE_PCM,      10, 10 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE,  0, 10 },
+		{ SCARLETT2_PORT_TYPE_SPDIF,     0,  2 },
+		{ SCARLETT2_PORT_TYPE_ADAT,      0,  8 },
+		{ SCARLETT2_PORT_TYPE_PCM,       8,  2 },
+		{ SCARLETT2_PORT_TYPE_MIX,       0, 25 },
+		{ SCARLETT2_PORT_TYPE_NONE,      0, 12 },
+		{ 0,                             0,  0 },
+	}, {
+		{ SCARLETT2_PORT_TYPE_PCM,       0,  8 },
+		{ SCARLETT2_PORT_TYPE_PCM,      10,  8 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE,  0, 10 },
+		{ SCARLETT2_PORT_TYPE_SPDIF,     0,  2 },
+		{ SCARLETT2_PORT_TYPE_ADAT,      0,  8 },
+		{ SCARLETT2_PORT_TYPE_PCM,       8,  2 },
+		{ SCARLETT2_PORT_TYPE_MIX,       0, 25 },
+		{ SCARLETT2_PORT_TYPE_NONE,      0, 10 },
+		{ 0,                             0,  0 },
+	}, {
+		{ SCARLETT2_PORT_TYPE_PCM,       0, 10 },
+		{ SCARLETT2_PORT_TYPE_ANALOGUE,  0, 10 },
+		{ SCARLETT2_PORT_TYPE_SPDIF,     0,  2 },
+		{ SCARLETT2_PORT_TYPE_NONE,      0, 24 },
+		{ 0,                             0,  0 },
+	} },
+};
+
 static const struct scarlett2_device_info *scarlett2_devices[] = {
 	/* Supported Gen 2 devices */
 	&s6i6_gen2_info,
 	&s18i8_gen2_info,
 	&s18i20_gen2_info,
 
+	/* Supported Gen 3 devices */
+	&s4i4_gen3_info,
+	&s8i6_gen3_info,
+	&s18i8_gen3_info,
+	&s18i20_gen3_info,
+
 	/* End of list */
 	NULL
 };
@@ -674,7 +896,7 @@ static int scarlett2_usb(
 	if (err != req_buf_size) {
 		usb_audio_err(
 			mixer->chip,
-			"Scarlett Gen 2 USB request result cmd %x was %d\n",
+			"Scarlett Gen 2/3 USB request result cmd %x was %d\n",
 			cmd, err);
 		err = -EINVAL;
 		goto unlock;
@@ -691,7 +913,7 @@ static int scarlett2_usb(
 	if (err != resp_buf_size) {
 		usb_audio_err(
 			mixer->chip,
-			"Scarlett Gen 2 USB response result cmd %x was %d "
+			"Scarlett Gen 2/3 USB response result cmd %x was %d "
 			"expected %d\n",
 			cmd, err, resp_buf_size);
 		err = -EINVAL;
@@ -709,7 +931,7 @@ static int scarlett2_usb(
 	    resp->pad) {
 		usb_audio_err(
 			mixer->chip,
-			"Scarlett Gen 2 USB invalid response; "
+			"Scarlett Gen 2/3 USB invalid response; "
 			   "cmd tx/rx %d/%d seq %d/%d size %d/%d "
 			   "error %d pad %d\n",
 			le32_to_cpu(req->cmd), le32_to_cpu(resp->cmd),
@@ -2485,7 +2707,7 @@ int snd_scarlett_gen2_init(struct usb_mixer_interface *mixer)
 
 	if (!(chip->setup & SCARLETT2_ENABLE)) {
 		usb_audio_info(chip,
-			"Focusrite Scarlett Gen 2 Mixer Driver disabled; "
+			"Focusrite Scarlett Gen 2/3 Mixer Driver disabled; "
 			"use options snd_usb_audio vid=0x%04x pid=0x%04x "
 			"device_setup=1 to enable and report any issues "
 			"to g@b4.vu",
@@ -2495,7 +2717,7 @@ int snd_scarlett_gen2_init(struct usb_mixer_interface *mixer)
 	}
 
 	usb_audio_info(chip,
-		"Focusrite Scarlett Gen 2 Mixer Driver enabled pid=0x%04x",
+		"Focusrite Scarlett Gen 2/3 Mixer Driver enabled pid=0x%04x",
 		USB_ID_PRODUCT(chip->usb_id));
 
 	err = snd_scarlett_gen2_controls_create(mixer);
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* Re: [PATCH 16/31] ALSA: usb-audio: scarlett2: Add Gen 3 mixer support
  2021-06-22  7:07     ` Vladimir Sadovnikov
  2021-06-22  7:25       ` [PATCH v2 " Geoffrey D. Bennett
@ 2021-06-22  7:34       ` Takashi Iwai
  2021-06-22  7:44         ` Geoffrey D. Bennett
  1 sibling, 1 reply; 43+ messages in thread
From: Takashi Iwai @ 2021-06-22  7:34 UTC (permalink / raw)
  To: Vladimir Sadovnikov; +Cc: Hin-Tak Leung, alsa-devel, Geoffrey D. Bennett

On Tue, 22 Jun 2021 09:07:20 +0200,
Vladimir Sadovnikov wrote:
> 
> Hello Takashi!
> 
> Since Focusrite devices are too advanced in settings, the overall
> amount of 256 controls is not enough for these devices (like 18i20).
> I would like also to extend this constant up to 1024 or even more
> since adding support of software configuration of the device also
> can exceed the amount of 512 control elements.

This define isn't for the total number of mixer elements.  Instead,
it's just a size of the bitmap table that contains the head of the
linked list for each unit id (in the sense of USB mixer spec).
So the number of mixer elements is unlimited.


Takashi

> 
> Let's assume we have a mute switch for each mixer gain setting. For
> the 18i20 device this will give:
> 12 inputs * 25 outputs = 300 mute switches.
> 
> So I think this constant should be increased rapidly up to 1024 or even to 2048.
> 
> Best,
> Vladimir
> 
> 22.06.2021 10:00, Takashi Iwai пишет:
> > On Mon, 21 Jun 2021 20:09:48 +0200,
> > Geoffrey D. Bennett wrote:
> >> Add mixer support for the Focusrite Scarlett 4i4, 8i6, 18i8, and 18i20
> >> Gen 3 devices.
> >>
> >> Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
> >> ---
> >>   sound/usb/mixer.c               |   2 +-
> >>   sound/usb/mixer_quirks.c        |   4 +
> >>   sound/usb/mixer_scarlett_gen2.c | 260 +++++++++++++++++++++++++++++---
> >>   3 files changed, 246 insertions(+), 20 deletions(-)
> >>
> >> diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
> >> index 428d581f988f..ba4aa1eacb04 100644
> >> --- a/sound/usb/mixer.c
> >> +++ b/sound/usb/mixer.c
> >> @@ -50,7 +50,7 @@
> >>   #include "mixer_quirks.h"
> >>   #include "power.h"
> >>   -#define MAX_ID_ELEMS	256
> >> +#define MAX_ID_ELEMS	512
> > This change requires the explanation.
> > Usually the unit id is a byte per definition, so it can't be over
> > 256.
> >
> >
> > thanks,
> >
> > Takashi
> 
> 

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 16/31] ALSA: usb-audio: scarlett2: Add Gen 3 mixer support
  2021-06-22  7:34       ` [PATCH " Takashi Iwai
@ 2021-06-22  7:44         ` Geoffrey D. Bennett
  2021-06-22  7:58           ` Takashi Iwai
  0 siblings, 1 reply; 43+ messages in thread
From: Geoffrey D. Bennett @ 2021-06-22  7:44 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: Hin-Tak Leung, alsa-devel, Vladimir Sadovnikov

On Tue, Jun 22, 2021 at 09:34:25AM +0200, Takashi Iwai wrote:
> On Tue, 22 Jun 2021 09:07:20 +0200,
> Vladimir Sadovnikov wrote:
> > 
> > Hello Takashi!
> > 
> > Since Focusrite devices are too advanced in settings, the overall
> > amount of 256 controls is not enough for these devices (like 18i20).
> > I would like also to extend this constant up to 1024 or even more
> > since adding support of software configuration of the device also
> > can exceed the amount of 512 control elements.
> 
> This define isn't for the total number of mixer elements.  Instead,
> it's just a size of the bitmap table that contains the head of the
> linked list for each unit id (in the sense of USB mixer spec).
> So the number of mixer elements is unlimited.

Sorry I don't understand what's going on then. Am I calling
snd_usb_mixer_add_control() wrong? Because when I called it more than
MAX_ID_ELEMS times I got a buffer overflow in mixer->id_elems[] (from
memory, I can confirm tonight).

snd_usb_create_mixer() has:

        mixer->id_elems = kcalloc(MAX_ID_ELEMS, sizeof(*mixer->id_elems),
                                  GFP_KERNEL);

snd_usb_mixer_add_control() called from mixer_scarlett_gen2.c ends up
at snd_usb_mixer_add_list() which does:

        list->next_id_elem = mixer->id_elems[list->id];
        mixer->id_elems[list->id] = list;

And list->id was going over MAX_ID_ELEMS.

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 16/31] ALSA: usb-audio: scarlett2: Add Gen 3 mixer support
  2021-06-22  7:44         ` Geoffrey D. Bennett
@ 2021-06-22  7:58           ` Takashi Iwai
  2021-06-22  8:12             ` Takashi Iwai
  2021-06-22  8:18             ` Geoffrey D. Bennett
  0 siblings, 2 replies; 43+ messages in thread
From: Takashi Iwai @ 2021-06-22  7:58 UTC (permalink / raw)
  To: Geoffrey D. Bennett; +Cc: Hin-Tak Leung, alsa-devel, Vladimir Sadovnikov

On Tue, 22 Jun 2021 09:44:54 +0200,
Geoffrey D. Bennett wrote:
> 
> On Tue, Jun 22, 2021 at 09:34:25AM +0200, Takashi Iwai wrote:
> > On Tue, 22 Jun 2021 09:07:20 +0200,
> > Vladimir Sadovnikov wrote:
> > > 
> > > Hello Takashi!
> > > 
> > > Since Focusrite devices are too advanced in settings, the overall
> > > amount of 256 controls is not enough for these devices (like 18i20).
> > > I would like also to extend this constant up to 1024 or even more
> > > since adding support of software configuration of the device also
> > > can exceed the amount of 512 control elements.
> > 
> > This define isn't for the total number of mixer elements.  Instead,
> > it's just a size of the bitmap table that contains the head of the
> > linked list for each unit id (in the sense of USB mixer spec).
> > So the number of mixer elements is unlimited.
> 
> Sorry I don't understand what's going on then. Am I calling
> snd_usb_mixer_add_control() wrong? Because when I called it more than
> MAX_ID_ELEMS times I got a buffer overflow in mixer->id_elems[] (from
> memory, I can confirm tonight).
> 
> snd_usb_create_mixer() has:
> 
>         mixer->id_elems = kcalloc(MAX_ID_ELEMS, sizeof(*mixer->id_elems),
>                                   GFP_KERNEL);
> 
> snd_usb_mixer_add_control() called from mixer_scarlett_gen2.c ends up
> at snd_usb_mixer_add_list() which does:
> 
>         list->next_id_elem = mixer->id_elems[list->id];
>         mixer->id_elems[list->id] = list;
> 
> And list->id was going over MAX_ID_ELEMS.

Here, list->id is the *USB* mixer unit id, not the ALSA control id or
whatever the internal index.  The former should be a byte, hence it
can't be over 256.

That said, the scarlett2 code calls the function in a wrong way.  It
has worked casually, so far, just because the core code doesn't use
the unit id number for significant roles.

So, as a quick workaround, simply pass 0 or any fixed number under 256
to list->id (i.e. elem->head.id in scarlett2_add_new_ctl()).  That's
all, and the elements are chained in the linked list.


Takashi

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 16/31] ALSA: usb-audio: scarlett2: Add Gen 3 mixer support
  2021-06-22  7:58           ` Takashi Iwai
@ 2021-06-22  8:12             ` Takashi Iwai
  2021-06-22  8:18             ` Geoffrey D. Bennett
  1 sibling, 0 replies; 43+ messages in thread
From: Takashi Iwai @ 2021-06-22  8:12 UTC (permalink / raw)
  To: Geoffrey D. Bennett; +Cc: Hin-Tak Leung, alsa-devel, Vladimir Sadovnikov

On Tue, 22 Jun 2021 09:58:27 +0200,
Takashi Iwai wrote:
> 
> On Tue, 22 Jun 2021 09:44:54 +0200,
> Geoffrey D. Bennett wrote:
> > 
> > On Tue, Jun 22, 2021 at 09:34:25AM +0200, Takashi Iwai wrote:
> > > On Tue, 22 Jun 2021 09:07:20 +0200,
> > > Vladimir Sadovnikov wrote:
> > > > 
> > > > Hello Takashi!
> > > > 
> > > > Since Focusrite devices are too advanced in settings, the overall
> > > > amount of 256 controls is not enough for these devices (like 18i20).
> > > > I would like also to extend this constant up to 1024 or even more
> > > > since adding support of software configuration of the device also
> > > > can exceed the amount of 512 control elements.
> > > 
> > > This define isn't for the total number of mixer elements.  Instead,
> > > it's just a size of the bitmap table that contains the head of the
> > > linked list for each unit id (in the sense of USB mixer spec).
> > > So the number of mixer elements is unlimited.
> > 
> > Sorry I don't understand what's going on then. Am I calling
> > snd_usb_mixer_add_control() wrong? Because when I called it more than
> > MAX_ID_ELEMS times I got a buffer overflow in mixer->id_elems[] (from
> > memory, I can confirm tonight).
> > 
> > snd_usb_create_mixer() has:
> > 
> >         mixer->id_elems = kcalloc(MAX_ID_ELEMS, sizeof(*mixer->id_elems),
> >                                   GFP_KERNEL);
> > 
> > snd_usb_mixer_add_control() called from mixer_scarlett_gen2.c ends up
> > at snd_usb_mixer_add_list() which does:
> > 
> >         list->next_id_elem = mixer->id_elems[list->id];
> >         mixer->id_elems[list->id] = list;
> > 
> > And list->id was going over MAX_ID_ELEMS.
> 
> Here, list->id is the *USB* mixer unit id, not the ALSA control id or
> whatever the internal index.  The former should be a byte, hence it
> can't be over 256.
> 
> That said, the scarlett2 code calls the function in a wrong way.  It
> has worked casually, so far, just because the core code doesn't use
> the unit id number for significant roles.

... and looking again at the code, actually it does matter.
The USB audio mixer code calls the resume for each mixer element, and
the default resume code (default_mixer_resume()) is applied for a
control with usb_mixer_elem_info.val_type == USB_MIXER_BOOLEAN and
channels == 1.  It seems that scarlett2 has some of them, and the
resume procedure is applied wrongly with an invalid unit id.

We need to define a special mixer value type (e.g. USB_MIXER_VENDOR),
and use this for the all scarlett2 mixer elements, in addition to the
below:

> So, as a quick workaround, simply pass 0 or any fixed number under 256
> to list->id (i.e. elem->head.id in scarlett2_add_new_ctl()).  That's
> all, and the elements are chained in the linked list.


Takashi

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 16/31] ALSA: usb-audio: scarlett2: Add Gen 3 mixer support
  2021-06-22  7:58           ` Takashi Iwai
  2021-06-22  8:12             ` Takashi Iwai
@ 2021-06-22  8:18             ` Geoffrey D. Bennett
  2021-06-22  8:34               ` Takashi Iwai
  1 sibling, 1 reply; 43+ messages in thread
From: Geoffrey D. Bennett @ 2021-06-22  8:18 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: Hin-Tak Leung, alsa-devel, Vladimir Sadovnikov

On Tue, Jun 22, 2021 at 09:58:27AM +0200, Takashi Iwai wrote:
> On Tue, 22 Jun 2021 09:44:54 +0200,
> Geoffrey D. Bennett wrote:
> > 
> > On Tue, Jun 22, 2021 at 09:34:25AM +0200, Takashi Iwai wrote:
> > > On Tue, 22 Jun 2021 09:07:20 +0200,
> > > Vladimir Sadovnikov wrote:
> > > > 
> > > > Hello Takashi!
> > > > 
> > > > Since Focusrite devices are too advanced in settings, the overall
> > > > amount of 256 controls is not enough for these devices (like 18i20).
> > > > I would like also to extend this constant up to 1024 or even more
> > > > since adding support of software configuration of the device also
> > > > can exceed the amount of 512 control elements.
> > > 
> > > This define isn't for the total number of mixer elements.  Instead,
> > > it's just a size of the bitmap table that contains the head of the
> > > linked list for each unit id (in the sense of USB mixer spec).
> > > So the number of mixer elements is unlimited.
> > 
> > Sorry I don't understand what's going on then. Am I calling
> > snd_usb_mixer_add_control() wrong? Because when I called it more than
> > MAX_ID_ELEMS times I got a buffer overflow in mixer->id_elems[] (from
> > memory, I can confirm tonight).
> > 
> > snd_usb_create_mixer() has:
> > 
> >         mixer->id_elems = kcalloc(MAX_ID_ELEMS, sizeof(*mixer->id_elems),
> >                                   GFP_KERNEL);
> > 
> > snd_usb_mixer_add_control() called from mixer_scarlett_gen2.c ends up
> > at snd_usb_mixer_add_list() which does:
> > 
> >         list->next_id_elem = mixer->id_elems[list->id];
> >         mixer->id_elems[list->id] = list;
> > 
> > And list->id was going over MAX_ID_ELEMS.
> 
> Here, list->id is the *USB* mixer unit id, not the ALSA control id or
> whatever the internal index.  The former should be a byte, hence it
> can't be over 256.
> 
> That said, the scarlett2 code calls the function in a wrong way.  It
> has worked casually, so far, just because the core code doesn't use
> the unit id number for significant roles.
> 
> So, as a quick workaround, simply pass 0 or any fixed number under 256
> to list->id (i.e. elem->head.id in scarlett2_add_new_ctl()).  That's
> all, and the elements are chained in the linked list.

Okay, I will fix that tonight.

Were patches 1-15 of this set of 31 acceptable? If so, I will send a
new set with this fix and the remainder of the patches.

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 16/31] ALSA: usb-audio: scarlett2: Add Gen 3 mixer support
  2021-06-22  8:18             ` Geoffrey D. Bennett
@ 2021-06-22  8:34               ` Takashi Iwai
  2021-06-22  9:01                 ` Takashi Iwai
  0 siblings, 1 reply; 43+ messages in thread
From: Takashi Iwai @ 2021-06-22  8:34 UTC (permalink / raw)
  To: Geoffrey D. Bennett; +Cc: Hin-Tak Leung, alsa-devel, Vladimir Sadovnikov

On Tue, 22 Jun 2021 10:18:39 +0200,
Geoffrey D. Bennett wrote:
> 
> On Tue, Jun 22, 2021 at 09:58:27AM +0200, Takashi Iwai wrote:
> > On Tue, 22 Jun 2021 09:44:54 +0200,
> > Geoffrey D. Bennett wrote:
> > > 
> > > On Tue, Jun 22, 2021 at 09:34:25AM +0200, Takashi Iwai wrote:
> > > > On Tue, 22 Jun 2021 09:07:20 +0200,
> > > > Vladimir Sadovnikov wrote:
> > > > > 
> > > > > Hello Takashi!
> > > > > 
> > > > > Since Focusrite devices are too advanced in settings, the overall
> > > > > amount of 256 controls is not enough for these devices (like 18i20).
> > > > > I would like also to extend this constant up to 1024 or even more
> > > > > since adding support of software configuration of the device also
> > > > > can exceed the amount of 512 control elements.
> > > > 
> > > > This define isn't for the total number of mixer elements.  Instead,
> > > > it's just a size of the bitmap table that contains the head of the
> > > > linked list for each unit id (in the sense of USB mixer spec).
> > > > So the number of mixer elements is unlimited.
> > > 
> > > Sorry I don't understand what's going on then. Am I calling
> > > snd_usb_mixer_add_control() wrong? Because when I called it more than
> > > MAX_ID_ELEMS times I got a buffer overflow in mixer->id_elems[] (from
> > > memory, I can confirm tonight).
> > > 
> > > snd_usb_create_mixer() has:
> > > 
> > >         mixer->id_elems = kcalloc(MAX_ID_ELEMS, sizeof(*mixer->id_elems),
> > >                                   GFP_KERNEL);
> > > 
> > > snd_usb_mixer_add_control() called from mixer_scarlett_gen2.c ends up
> > > at snd_usb_mixer_add_list() which does:
> > > 
> > >         list->next_id_elem = mixer->id_elems[list->id];
> > >         mixer->id_elems[list->id] = list;
> > > 
> > > And list->id was going over MAX_ID_ELEMS.
> > 
> > Here, list->id is the *USB* mixer unit id, not the ALSA control id or
> > whatever the internal index.  The former should be a byte, hence it
> > can't be over 256.
> > 
> > That said, the scarlett2 code calls the function in a wrong way.  It
> > has worked casually, so far, just because the core code doesn't use
> > the unit id number for significant roles.
> > 
> > So, as a quick workaround, simply pass 0 or any fixed number under 256
> > to list->id (i.e. elem->head.id in scarlett2_add_new_ctl()).  That's
> > all, and the elements are chained in the linked list.
> 
> Okay, I will fix that tonight.
> 
> Were patches 1-15 of this set of 31 acceptable? If so, I will send a
> new set with this fix and the remainder of the patches.

I don't see other issues through a quick glance.

And, the additional fix is below.
If this works, please include this at first.


Takashi

-- 8< --
From: Takashi Iwai <tiwai@suse.de>
Subject: [PATCH] ALSA: usb-audio: scarlett2: Fix wrong resume call

The current way of the scarlett2 mixer code managing the
usb_mixer_elem_info object is wrong in two ways: it passes its
internal index to the head.id field, and the val_type field is
uninitialized.  This ended up with the wrong execution at the resume
because a bogus unit id is passed wrongly.  Also, in the later code
extensions, we'll have more mixer elements, and passing the index will
overflow the unit id size (of 256).

This patch corrects those issues.  It introduces a new value type,
USB_MIXER_BESPOKEN, which indicates a non-standard mixer element, and
use this type for all scarlett2 mixer elements, as well as
initializing the fixed unit id 0 for avoiding the overflow.

Cc: <stable@vger.kernel.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 sound/usb/mixer.h               | 1 +
 sound/usb/mixer_scarlett_gen2.c | 7 ++++++-
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h
index e5a01f17bf3c..ea41e7a1f7bf 100644
--- a/sound/usb/mixer.h
+++ b/sound/usb/mixer.h
@@ -55,6 +55,7 @@ enum {
 	USB_MIXER_U16,
 	USB_MIXER_S32,
 	USB_MIXER_U32,
+	USB_MIXER_BESPOKEN,	/* non-standard type */
 };
 
 typedef void (*usb_mixer_elem_dump_func_t)(struct snd_info_buffer *buffer,
diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c
index 2e1937b072ee..ed2f16a5fc87 100644
--- a/sound/usb/mixer_scarlett_gen2.c
+++ b/sound/usb/mixer_scarlett_gen2.c
@@ -1070,10 +1070,15 @@ static int scarlett2_add_new_ctl(struct usb_mixer_interface *mixer,
 	if (!elem)
 		return -ENOMEM;
 
+	/* We set USB_MIXER_BESPOKEN type, so that the core USB mixer code
+	 * ignores them for resume and other operations.
+	 * Also, the head.id field is set to 0, as we don't use this field.
+	 */
 	elem->head.mixer = mixer;
 	elem->control = index;
-	elem->head.id = index;
+	elem->head.id = 0;
 	elem->channels = channels;
+	elem->val_type = USB_MIXER_BESPOKEN;
 
 	kctl = snd_ctl_new1(ncontrol, elem);
 	if (!kctl) {
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* Re: [PATCH 16/31] ALSA: usb-audio: scarlett2: Add Gen 3 mixer support
  2021-06-22  8:34               ` Takashi Iwai
@ 2021-06-22  9:01                 ` Takashi Iwai
  0 siblings, 0 replies; 43+ messages in thread
From: Takashi Iwai @ 2021-06-22  9:01 UTC (permalink / raw)
  To: Geoffrey D. Bennett; +Cc: Hin-Tak Leung, alsa-devel, Vladimir Sadovnikov

On Tue, 22 Jun 2021 10:34:54 +0200,
Takashi Iwai wrote:
> 
> On Tue, 22 Jun 2021 10:18:39 +0200,
> Geoffrey D. Bennett wrote:
> > 
> > On Tue, Jun 22, 2021 at 09:58:27AM +0200, Takashi Iwai wrote:
> > > On Tue, 22 Jun 2021 09:44:54 +0200,
> > > Geoffrey D. Bennett wrote:
> > > > 
> > > > On Tue, Jun 22, 2021 at 09:34:25AM +0200, Takashi Iwai wrote:
> > > > > On Tue, 22 Jun 2021 09:07:20 +0200,
> > > > > Vladimir Sadovnikov wrote:
> > > > > > 
> > > > > > Hello Takashi!
> > > > > > 
> > > > > > Since Focusrite devices are too advanced in settings, the overall
> > > > > > amount of 256 controls is not enough for these devices (like 18i20).
> > > > > > I would like also to extend this constant up to 1024 or even more
> > > > > > since adding support of software configuration of the device also
> > > > > > can exceed the amount of 512 control elements.
> > > > > 
> > > > > This define isn't for the total number of mixer elements.  Instead,
> > > > > it's just a size of the bitmap table that contains the head of the
> > > > > linked list for each unit id (in the sense of USB mixer spec).
> > > > > So the number of mixer elements is unlimited.
> > > > 
> > > > Sorry I don't understand what's going on then. Am I calling
> > > > snd_usb_mixer_add_control() wrong? Because when I called it more than
> > > > MAX_ID_ELEMS times I got a buffer overflow in mixer->id_elems[] (from
> > > > memory, I can confirm tonight).
> > > > 
> > > > snd_usb_create_mixer() has:
> > > > 
> > > >         mixer->id_elems = kcalloc(MAX_ID_ELEMS, sizeof(*mixer->id_elems),
> > > >                                   GFP_KERNEL);
> > > > 
> > > > snd_usb_mixer_add_control() called from mixer_scarlett_gen2.c ends up
> > > > at snd_usb_mixer_add_list() which does:
> > > > 
> > > >         list->next_id_elem = mixer->id_elems[list->id];
> > > >         mixer->id_elems[list->id] = list;
> > > > 
> > > > And list->id was going over MAX_ID_ELEMS.
> > > 
> > > Here, list->id is the *USB* mixer unit id, not the ALSA control id or
> > > whatever the internal index.  The former should be a byte, hence it
> > > can't be over 256.
> > > 
> > > That said, the scarlett2 code calls the function in a wrong way.  It
> > > has worked casually, so far, just because the core code doesn't use
> > > the unit id number for significant roles.
> > > 
> > > So, as a quick workaround, simply pass 0 or any fixed number under 256
> > > to list->id (i.e. elem->head.id in scarlett2_add_new_ctl()).  That's
> > > all, and the elements are chained in the linked list.
> > 
> > Okay, I will fix that tonight.
> > 
> > Were patches 1-15 of this set of 31 acceptable? If so, I will send a
> > new set with this fix and the remainder of the patches.
> 
> I don't see other issues through a quick glance.
> 
> And, the additional fix is below.
> If this works, please include this at first.

It was missing one piece.  The revised patch is below.


Takashi

-- 8< --
From: Takashi Iwai <tiwai@suse.de>
Subject: [PATCH v2] ALSA: usb-audio: scarlett2: Fix wrong resume call

The current way of the scarlett2 mixer code managing the
usb_mixer_elem_info object is wrong in two ways: it passes its
internal index to the head.id field, and the val_type field is
uninitialized.  This ended up with the wrong execution at the resume
because a bogus unit id is passed wrongly.  Also, in the later code
extensions, we'll have more mixer elements, and passing the index will
overflow the unit id size (of 256).

This patch corrects those issues.  It introduces a new value type,
USB_MIXER_BESPOKEN, which indicates a non-standard mixer element, and
use this type for all scarlett2 mixer elements, as well as
initializing the fixed unit id 0 for avoiding the overflow.

Cc: <stable@vger.kernel.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 sound/usb/mixer.c               | 3 +++
 sound/usb/mixer.h               | 1 +
 sound/usb/mixer_scarlett_gen2.c | 7 ++++++-
 3 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 428d581f988f..0f578dabd094 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -3605,6 +3605,9 @@ static int restore_mixer_value(struct usb_mixer_elem_list *list)
 	struct usb_mixer_elem_info *cval = mixer_elem_list_to_info(list);
 	int c, err, idx;
 
+	if (cval->val_type == USB_MIXER_BESPOKEN)
+		return 0;
+
 	if (cval->cmask) {
 		idx = 0;
 		for (c = 0; c < MAX_CHANNELS; c++) {
diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h
index e5a01f17bf3c..ea41e7a1f7bf 100644
--- a/sound/usb/mixer.h
+++ b/sound/usb/mixer.h
@@ -55,6 +55,7 @@ enum {
 	USB_MIXER_U16,
 	USB_MIXER_S32,
 	USB_MIXER_U32,
+	USB_MIXER_BESPOKEN,	/* non-standard type */
 };
 
 typedef void (*usb_mixer_elem_dump_func_t)(struct snd_info_buffer *buffer,
diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c
index 2e1937b072ee..ed2f16a5fc87 100644
--- a/sound/usb/mixer_scarlett_gen2.c
+++ b/sound/usb/mixer_scarlett_gen2.c
@@ -1070,10 +1070,15 @@ static int scarlett2_add_new_ctl(struct usb_mixer_interface *mixer,
 	if (!elem)
 		return -ENOMEM;
 
+	/* We set USB_MIXER_BESPOKEN type, so that the core USB mixer code
+	 * ignores them for resume and other operations.
+	 * Also, the head.id field is set to 0, as we don't use this field.
+	 */
 	elem->head.mixer = mixer;
 	elem->control = index;
-	elem->head.id = index;
+	elem->head.id = 0;
 	elem->channels = channels;
+	elem->val_type = USB_MIXER_BESPOKEN;
 
 	kctl = snd_ctl_new1(ncontrol, elem);
 	if (!kctl) {
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 43+ messages in thread

end of thread, other threads:[~2021-06-23  9:18 UTC | newest]

Thread overview: 43+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-21 18:09 [PATCH 00/31] Refactor Scarlett Gen 2 support and add Scarlett Gen 3 support Geoffrey D. Bennett
2021-06-21 18:09 ` [PATCH 01/31] ALSA: usb-audio: scarlett2: Add usb_tx/rx functions Geoffrey D. Bennett
2021-06-21 18:09 ` [PATCH 02/31] ALSA: usb-audio: scarlett2: Update initialisation sequence Geoffrey D. Bennett
2021-06-21 18:09 ` [PATCH 03/31] ALSA: usb-audio: scarlett2: Fix 6i6 Gen 2 line out descriptions Geoffrey D. Bennett
2021-06-21 18:09 ` [PATCH 04/31] ALSA: usb-audio: scarlett2: Always enable interrupt polling Geoffrey D. Bennett
2021-06-21 18:09 ` [PATCH 05/31] ALSA: usb-audio: scarlett2: Add "Sync Status" control Geoffrey D. Bennett
2021-06-21 18:09 ` [PATCH 06/31] ALSA: usb-audio: scarlett2: Merge common line in capture strings Geoffrey D. Bennett
2021-06-21 18:09 ` [PATCH 07/31] ALSA: usb-audio: scarlett2: Reformat scarlett2_config_items[] Geoffrey D. Bennett
2021-06-21 18:09 ` [PATCH 08/31] ALSA: usb-audio: scarlett2: Improve device info lookup Geoffrey D. Bennett
2021-06-21 18:09 ` [PATCH 09/31] ALSA: usb-audio: scarlett2: Move info lookup out of init function Geoffrey D. Bennett
2021-06-21 18:09 ` [PATCH 10/31] ALSA: usb-audio: scarlett2: Remove repeated device info comments Geoffrey D. Bennett
2021-06-21 18:09 ` [PATCH 11/31] ALSA: usb-audio: scarlett2: Add scarlett2_vol_ctl_write() helper Geoffrey D. Bennett
2021-06-21 18:09 ` [PATCH 12/31] ALSA: usb-audio: scarlett2: Add mute support Geoffrey D. Bennett
2021-06-21 18:09 ` [PATCH 13/31] ALSA: usb-audio: scarlett2: Allow arbitrary ordering of mux entries Geoffrey D. Bennett
2021-06-21 18:09 ` [PATCH 14/31] ALSA: usb-audio: scarlett2: Split struct scarlett2_ports Geoffrey D. Bennett
2021-06-21 18:09 ` [PATCH 15/31] ALSA: usb-audio: scarlett2: Fix Level Meter control Geoffrey D. Bennett
2021-06-21 18:09 ` [PATCH 16/31] ALSA: usb-audio: scarlett2: Add Gen 3 mixer support Geoffrey D. Bennett
2021-06-22  7:00   ` Takashi Iwai
2021-06-22  7:07     ` Vladimir Sadovnikov
2021-06-22  7:25       ` [PATCH v2 " Geoffrey D. Bennett
2021-06-22  7:34       ` [PATCH " Takashi Iwai
2021-06-22  7:44         ` Geoffrey D. Bennett
2021-06-22  7:58           ` Takashi Iwai
2021-06-22  8:12             ` Takashi Iwai
2021-06-22  8:18             ` Geoffrey D. Bennett
2021-06-22  8:34               ` Takashi Iwai
2021-06-22  9:01                 ` Takashi Iwai
2021-06-22  7:24     ` Geoffrey D. Bennett
2021-06-21 18:09 ` [PATCH 17/31] ALSA: usb-audio: scarlett2: Add support for "input-other" notify Geoffrey D. Bennett
2021-06-21 18:09 ` [PATCH 18/31] ALSA: usb-audio: scarlett2: Add Gen 3 MSD mode switch Geoffrey D. Bennett
2021-06-21 18:09 ` [PATCH 19/31] ALSA: usb-audio: scarlett2: Move get config above set config Geoffrey D. Bennett
2021-06-21 18:09 ` [PATCH 20/31] ALSA: usb-audio: scarlett2: Allow bit-level access to config Geoffrey D. Bennett
2021-06-21 18:09 ` [PATCH 21/31] ALSA: usb-audio: scarlett2: Add support for Solo and 2i2 Gen 3 Geoffrey D. Bennett
2021-06-21 18:10 ` [PATCH 22/31] ALSA: usb-audio: scarlett2: Add "air" switch support Geoffrey D. Bennett
2021-06-21 18:10 ` [PATCH 23/31] ALSA: usb-audio: scarlett2: Add phantom power " Geoffrey D. Bennett
2021-06-21 18:10 ` [PATCH 24/31] ALSA: usb-audio: scarlett2: Add direct monitor support Geoffrey D. Bennett
2021-06-21 18:10 ` [PATCH 25/31] ALSA: usb-audio: scarlett2: Label 18i8 Gen 3 line outputs correctly Geoffrey D. Bennett
2021-06-21 18:10 ` [PATCH 26/31] ALSA: usb-audio: scarlett2: Split up sw_hw_enum_ctl_put() Geoffrey D. Bennett
2021-06-21 18:10 ` [PATCH 27/31] ALSA: usb-audio: scarlett2: Add sw_hw_ctls and mux_ctls Geoffrey D. Bennett
2021-06-21 18:10 ` [PATCH 28/31] ALSA: usb-audio: scarlett2: Update mux controls to allow updates Geoffrey D. Bennett
2021-06-21 18:10 ` [PATCH 29/31] ALSA: usb-audio: scarlett2: Add speaker switching support Geoffrey D. Bennett
2021-06-21 18:10 ` [PATCH 30/31] ALSA: usb-audio: scarlett2: Update get_config to do endian conversion Geoffrey D. Bennett
2021-06-21 18:10 ` [PATCH 31/31] ALSA: usb-audio: scarlett2: Add support for the talkback feature Geoffrey D. Bennett

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.