diff mbox series

[06/17] ALSA: usb-audio: scarlett2: Allow bit-level access to config

Message ID 4e54e9e106ec7029c1a668c51b4fc769a7eb4ed0.1624379707.git.g@b4.vu
State Superseded
Headers show
Series Add Scarlett Gen 3 support | expand

Commit Message

Geoffrey D. Bennett June 22, 2021, 5:02 p.m. UTC
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 mbox series

Patch

diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c
index 7a5346c68603..08e7b687484e 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;