* [PATCH v2 0/2] ALSA: usb-audio: presonus s1810 minor cleanup and document
@ 2026-01-11 21:36 ` fenugrec via B4 Relay
0 siblings, 0 replies; 8+ messages in thread
From: fenugrec @ 2026-01-11 21:36 UTC (permalink / raw)
To: Takashi Iwai
Cc: linux-sound, linux-kernel, roy.vegard.ovesen, mickflemm, fenugrec
patch v2 : apologies, I had missed an __le32 field.
- Use __le32 fields for structures sent/received over USB
Addresses a comment from when this driver was initially merged:
https://lore.kernel.org/all/s5hd0agcjw1.wl-tiwai@suse.de/
- Document constants and protocol details common to the Studio 1810 and
1824c devices
Except for a hypothetical big-endian platform (which I cannot test) where the first
commit would make a difference, both these should have no functional
change.
Signed-off-by: fenugrec <fenugrec@mail.com>
---
Changes in v2:
- fix an overlooked __le32 conversion for .tag and .len fields
- Link to v1: https://lore.kernel.org/r/20260110-preso_clean1-v1-0-ce2dd3ea4506@mail.com
---
fenugrec (2):
ALSA: usb-audio: presonus s18xx uses little-endian
ALSA: usb-audio: clean up presonus s1810 consts
sound/usb/mixer_s1810c.c | 224 ++++++++++++++++++++++++++++-------------------
1 file changed, 134 insertions(+), 90 deletions(-)
---
base-commit: 7d0a66e4bb9081d75c82ec4957c50034cb0ea449
change-id: 20260110-preso_clean1-162b2bd8bdb9
Best regards,
--
fenugrec <fenugrec@mail.com>
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH v2 0/2] ALSA: usb-audio: presonus s1810 minor cleanup and document @ 2026-01-11 21:36 ` fenugrec via B4 Relay 0 siblings, 0 replies; 8+ messages in thread From: fenugrec via B4 Relay @ 2026-01-11 21:36 UTC (permalink / raw) To: Takashi Iwai Cc: linux-sound, linux-kernel, roy.vegard.ovesen, mickflemm, fenugrec patch v2 : apologies, I had missed an __le32 field. - Use __le32 fields for structures sent/received over USB Addresses a comment from when this driver was initially merged: https://lore.kernel.org/all/s5hd0agcjw1.wl-tiwai@suse.de/ - Document constants and protocol details common to the Studio 1810 and 1824c devices Except for a hypothetical big-endian platform (which I cannot test) where the first commit would make a difference, both these should have no functional change. Signed-off-by: fenugrec <fenugrec@mail.com> --- Changes in v2: - fix an overlooked __le32 conversion for .tag and .len fields - Link to v1: https://lore.kernel.org/r/20260110-preso_clean1-v1-0-ce2dd3ea4506@mail.com --- fenugrec (2): ALSA: usb-audio: presonus s18xx uses little-endian ALSA: usb-audio: clean up presonus s1810 consts sound/usb/mixer_s1810c.c | 224 ++++++++++++++++++++++++++++------------------- 1 file changed, 134 insertions(+), 90 deletions(-) --- base-commit: 7d0a66e4bb9081d75c82ec4957c50034cb0ea449 change-id: 20260110-preso_clean1-162b2bd8bdb9 Best regards, -- fenugrec <fenugrec@mail.com> ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 1/2] ALSA: usb-audio: presonus s18xx uses little-endian 2026-01-11 21:36 ` fenugrec via B4 Relay @ 2026-01-11 21:36 ` fenugrec via B4 Relay -1 siblings, 0 replies; 8+ messages in thread From: fenugrec @ 2026-01-11 21:36 UTC (permalink / raw) To: Takashi Iwai Cc: linux-sound, linux-kernel, roy.vegard.ovesen, mickflemm, fenugrec Use __le32 types for USB control transfers Signed-off-by: fenugrec <fenugrec@mail.com> --- sound/usb/mixer_s1810c.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/sound/usb/mixer_s1810c.c b/sound/usb/mixer_s1810c.c index 6e09e074c0e7..93510aa0dc5e 100644 --- a/sound/usb/mixer_s1810c.c +++ b/sound/usb/mixer_s1810c.c @@ -82,13 +82,13 @@ * mixer and output but a different set for device. */ struct s1810c_ctl_packet { - u32 a; - u32 b; - u32 fixed1; - u32 fixed2; - u32 c; - u32 d; - u32 e; + __le32 a; + __le32 b; + __le32 fixed1; + __le32 fixed2; + __le32 c; + __le32 d; + __le32 e; }; #define SC1810C_CTL_LINE_SW 0 @@ -118,7 +118,7 @@ struct s1810c_ctl_packet { * being zero and different f1/f2. */ struct s1810c_state_packet { - u32 fields[63]; + __le32 fields[63]; }; #define SC1810C_STATE_48V_SW 58 @@ -140,14 +140,14 @@ snd_s1810c_send_ctl_packet(struct usb_device *dev, u32 a, struct s1810c_ctl_packet pkt = { 0 }; int ret = 0; - pkt.fixed1 = SC1810C_CMD_F1; - pkt.fixed2 = SC1810C_CMD_F2; + pkt.fixed1 = __cpu_to_le32(SC1810C_CMD_F1); + pkt.fixed2 = __cpu_to_le32(SC1810C_CMD_F2); - pkt.a = a; - pkt.b = b; - pkt.c = c; - pkt.d = d; - pkt.e = e; + pkt.a = __cpu_to_le32(a); + pkt.b = __cpu_to_le32(b); + pkt.c = __cpu_to_le32(c); + pkt.d = __cpu_to_le32(d); + pkt.e = __cpu_to_le32(e); ret = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), SC1810C_CMD_REQ, @@ -176,8 +176,8 @@ snd_sc1810c_get_status_field(struct usb_device *dev, struct s1810c_state_packet pkt_in = { { 0 } }; int ret = 0; - pkt_out.fields[SC1810C_STATE_F1_IDX] = SC1810C_SET_STATE_F1; - pkt_out.fields[SC1810C_STATE_F2_IDX] = SC1810C_SET_STATE_F2; + pkt_out.fields[SC1810C_STATE_F1_IDX] = __cpu_to_le32(SC1810C_SET_STATE_F1); + pkt_out.fields[SC1810C_STATE_F2_IDX] = __cpu_to_le32(SC1810C_SET_STATE_F2); ret = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), SC1810C_SET_STATE_REQ, SC1810C_SET_STATE_REQTYPE, @@ -197,7 +197,7 @@ snd_sc1810c_get_status_field(struct usb_device *dev, return ret; } - (*field) = pkt_in.fields[field_idx]; + (*field) = __le32_to_cpu(pkt_in.fields[field_idx]); (*seqnum)++; return 0; } -- 2.52.0 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v2 1/2] ALSA: usb-audio: presonus s18xx uses little-endian @ 2026-01-11 21:36 ` fenugrec via B4 Relay 0 siblings, 0 replies; 8+ messages in thread From: fenugrec via B4 Relay @ 2026-01-11 21:36 UTC (permalink / raw) To: Takashi Iwai Cc: linux-sound, linux-kernel, roy.vegard.ovesen, mickflemm, fenugrec From: fenugrec <fenugrec@mail.com> Use __le32 types for USB control transfers Signed-off-by: fenugrec <fenugrec@mail.com> --- sound/usb/mixer_s1810c.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/sound/usb/mixer_s1810c.c b/sound/usb/mixer_s1810c.c index 6e09e074c0e7..93510aa0dc5e 100644 --- a/sound/usb/mixer_s1810c.c +++ b/sound/usb/mixer_s1810c.c @@ -82,13 +82,13 @@ * mixer and output but a different set for device. */ struct s1810c_ctl_packet { - u32 a; - u32 b; - u32 fixed1; - u32 fixed2; - u32 c; - u32 d; - u32 e; + __le32 a; + __le32 b; + __le32 fixed1; + __le32 fixed2; + __le32 c; + __le32 d; + __le32 e; }; #define SC1810C_CTL_LINE_SW 0 @@ -118,7 +118,7 @@ struct s1810c_ctl_packet { * being zero and different f1/f2. */ struct s1810c_state_packet { - u32 fields[63]; + __le32 fields[63]; }; #define SC1810C_STATE_48V_SW 58 @@ -140,14 +140,14 @@ snd_s1810c_send_ctl_packet(struct usb_device *dev, u32 a, struct s1810c_ctl_packet pkt = { 0 }; int ret = 0; - pkt.fixed1 = SC1810C_CMD_F1; - pkt.fixed2 = SC1810C_CMD_F2; + pkt.fixed1 = __cpu_to_le32(SC1810C_CMD_F1); + pkt.fixed2 = __cpu_to_le32(SC1810C_CMD_F2); - pkt.a = a; - pkt.b = b; - pkt.c = c; - pkt.d = d; - pkt.e = e; + pkt.a = __cpu_to_le32(a); + pkt.b = __cpu_to_le32(b); + pkt.c = __cpu_to_le32(c); + pkt.d = __cpu_to_le32(d); + pkt.e = __cpu_to_le32(e); ret = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), SC1810C_CMD_REQ, @@ -176,8 +176,8 @@ snd_sc1810c_get_status_field(struct usb_device *dev, struct s1810c_state_packet pkt_in = { { 0 } }; int ret = 0; - pkt_out.fields[SC1810C_STATE_F1_IDX] = SC1810C_SET_STATE_F1; - pkt_out.fields[SC1810C_STATE_F2_IDX] = SC1810C_SET_STATE_F2; + pkt_out.fields[SC1810C_STATE_F1_IDX] = __cpu_to_le32(SC1810C_SET_STATE_F1); + pkt_out.fields[SC1810C_STATE_F2_IDX] = __cpu_to_le32(SC1810C_SET_STATE_F2); ret = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), SC1810C_SET_STATE_REQ, SC1810C_SET_STATE_REQTYPE, @@ -197,7 +197,7 @@ snd_sc1810c_get_status_field(struct usb_device *dev, return ret; } - (*field) = pkt_in.fields[field_idx]; + (*field) = __le32_to_cpu(pkt_in.fields[field_idx]); (*seqnum)++; return 0; } -- 2.52.0 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v2 2/2] ALSA: usb-audio: clean up presonus s1810 consts 2026-01-11 21:36 ` fenugrec via B4 Relay @ 2026-01-11 21:36 ` fenugrec via B4 Relay -1 siblings, 0 replies; 8+ messages in thread From: fenugrec @ 2026-01-11 21:36 UTC (permalink / raw) To: Takashi Iwai Cc: linux-sound, linux-kernel, roy.vegard.ovesen, mickflemm, fenugrec - Reorder some #define blocks - Document mixer/volume levels - Document some Ctl request fields (tag, len) - replace some magic numbers with macros No functional change intended. The information is based on reverse engineering. Signed-off-by: fenugrec <fenugrec@mail.com> --- sound/usb/mixer_s1810c.c | 204 ++++++++++++++++++++++++++++------------------- 1 file changed, 124 insertions(+), 80 deletions(-) diff --git a/sound/usb/mixer_s1810c.c b/sound/usb/mixer_s1810c.c index 93510aa0dc5e..b4ce89afb25b 100644 --- a/sound/usb/mixer_s1810c.c +++ b/sound/usb/mixer_s1810c.c @@ -25,12 +25,6 @@ #include "helper.h" #include "mixer_s1810c.h" -#define SC1810C_CMD_REQ 160 -#define SC1810C_CMD_REQTYPE \ - (USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT) -#define SC1810C_CMD_F1 0x50617269 -#define SC1810C_CMD_F2 0x14 - /* * DISCLAIMER: These are just guesses based on the * dumps I got. @@ -42,9 +36,8 @@ * * b selects an input channel (see below). * * c selects an output channel pair (see below). * * d selects left (0) or right (1) of that pair. - * * e 0-> disconnect, 0x01000000-> connect, - * 0x0109-> used for stereo-linking channels, - * e is also used for setting volume levels + * * e level : see MIXER_LEVEL_* defines below. + * Also used for setting volume levels * in which case b is also set so I guess * this way it is possible to set the volume * level from the specified input to the @@ -75,52 +68,98 @@ * For output (0x65): * * b is the output channel (see above). * * c is zero. - * * e I guess the same as with mixer except 0x0109 - * which I didn't see in my dumps. + * * e I guess the same as with mixer + * + */ +/** struct s1810c_ctl_packet - basic vendor request + * @selector: device/mixer/output + * @b: request-dependant field b + * @tag: fixed value identifying type of request + * @len: sizeof this struct - 8 (excludes first 2 fields) + * i.e. for basic struct s1810c_ctl_packet: len is 5*4=0x14 + * @c: request-dependant field c + * @d: request-dependant field d + * @e: request-dependant field e * - * The two fixed fields have the same values for - * mixer and output but a different set for device. + * See longer description above. This could be combined + * (as a union?) with the longer struct s1810c_state_packet */ struct s1810c_ctl_packet { - __le32 a; + __le32 selector; __le32 b; - __le32 fixed1; - __le32 fixed2; + __le32 tag; + __le32 len; __le32 c; __le32 d; __le32 e; }; +/** selectors for CMD request + */ +#define SC1810C_SEL_DEVICE 0 +#define SC1810C_SEL_MIXER 0x64 +#define SC1810C_SEL_OUTPUT 0x65 + + +/** control ids */ #define SC1810C_CTL_LINE_SW 0 #define SC1810C_CTL_MUTE_SW 1 #define SC1824C_CTL_MONO_SW 2 #define SC1810C_CTL_AB_SW 3 #define SC1810C_CTL_48V_SW 4 +/* USB Control (vendor) requests + */ +#define SC1810C_CMD_REQ 160 +#define SC1810C_CMD_REQTYPE \ + (USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT) +#define SC1810C_CMD_TAG 0x50617269 +#define SC1810C_CMD_LEN 0x14 + #define SC1810C_SET_STATE_REQ 161 #define SC1810C_SET_STATE_REQTYPE SC1810C_CMD_REQTYPE -#define SC1810C_SET_STATE_F1 0x64656D73 -#define SC1810C_SET_STATE_F2 0xF4 +#define SC1810C_SET_STATE_TAG 0x64656D73 +#define SC1810C_SET_STATE_LEN 0xF4 #define SC1810C_GET_STATE_REQ 162 #define SC1810C_GET_STATE_REQTYPE \ (USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN) -#define SC1810C_GET_STATE_F1 SC1810C_SET_STATE_F1 -#define SC1810C_GET_STATE_F2 SC1810C_SET_STATE_F2 - -#define SC1810C_STATE_F1_IDX 2 -#define SC1810C_STATE_F2_IDX 3 +#define SC1810C_GET_STATE_TAG SC1810C_SET_STATE_TAG +#define SC1810C_GET_STATE_LEN SC1810C_SET_STATE_LEN + +/** Mixer levels normally range from 0 (off) to 0x0100 0000 (0 dB). + * raw_level = 2^24 * 10^(db_level / 20), thus + * -3dB = 0xb53bf0 (technically, half-power -3.01...dB would be 0xb504f3) + * -96dB = 0x109 + * -99dB = 0xBC + * PC software sliders cover -96 to +10dB (0x0329 8b08), + * but the value 0 (-inf dB) can be used when e.g. Mixer Bypass is enabled. + * Unclear what the hardware's maximum value is. + * + * Note, when a channel is panned to two channels (stereo), + * the mixer level is set to slider value (by default -96dB) minus 3dB, + * which explains the -99dB value seen in USB captures. + */ +#define MIXER_LEVEL_MUTE 0 +#define MIXER_LEVEL_N99DB 0xbc +#define MIXER_LEVEL_N3DB 0xb53bf0 +#define MIXER_LEVEL_0DB 0x1000000 -/* +/** * This packet includes mixer volumes and * various other fields, it's an extended * version of ctl_packet, with a and b - * being zero and different f1/f2. + * being zero and different tag/length. */ struct s1810c_state_packet { __le32 fields[63]; }; +/** indices into s1810c_state_packet.fields[] + */ +#define SC1810C_STATE_TAG_IDX 2 +#define SC1810C_STATE_LEN_IDX 3 + #define SC1810C_STATE_48V_SW 58 #define SC1810C_STATE_LINE_SW 59 #define SC1810C_STATE_MUTE_SW 60 @@ -134,16 +173,16 @@ struct s1810_mixer_state { }; static int -snd_s1810c_send_ctl_packet(struct usb_device *dev, u32 a, +snd_s1810c_send_ctl_packet(struct usb_device *dev, u32 sel, u32 b, u32 c, u32 d, u32 e) { struct s1810c_ctl_packet pkt = { 0 }; int ret = 0; - pkt.fixed1 = __cpu_to_le32(SC1810C_CMD_F1); - pkt.fixed2 = __cpu_to_le32(SC1810C_CMD_F2); + pkt.tag = __cpu_to_le32(SC1810C_CMD_TAG); + pkt.len = __cpu_to_le32(SC1810C_CMD_LEN); - pkt.a = __cpu_to_le32(a); + pkt.selector = __cpu_to_le32(sel); pkt.b = __cpu_to_le32(b); pkt.c = __cpu_to_le32(c); pkt.d = __cpu_to_le32(d); @@ -176,8 +215,8 @@ snd_sc1810c_get_status_field(struct usb_device *dev, struct s1810c_state_packet pkt_in = { { 0 } }; int ret = 0; - pkt_out.fields[SC1810C_STATE_F1_IDX] = __cpu_to_le32(SC1810C_SET_STATE_F1); - pkt_out.fields[SC1810C_STATE_F2_IDX] = __cpu_to_le32(SC1810C_SET_STATE_F2); + pkt_out.fields[SC1810C_STATE_TAG_IDX] = __cpu_to_le32(SC1810C_SET_STATE_TAG); + pkt_out.fields[SC1810C_STATE_LEN_IDX] = __cpu_to_le32(SC1810C_SET_STATE_LEN); ret = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), SC1810C_SET_STATE_REQ, SC1810C_SET_STATE_REQTYPE, @@ -216,8 +255,8 @@ static int snd_s1810c_init_mixer_maps(struct snd_usb_audio *chip) switch (chip->usb_id) { case USB_ID(0x194f, 0x010c): /* 1810c */ /* Set initial volume levels ? */ - a = 0x64; - e = 0xbc; + a = SC1810C_SEL_MIXER; + e = MIXER_LEVEL_N99DB; for (n = 0; n < 2; n++) { off = n * 18; for (b = off; b < 18 + off; b++) { @@ -234,22 +273,21 @@ static int snd_s1810c_init_mixer_maps(struct snd_usb_audio *chip) * I noticed on UC that DAW channels have different * initial volumes, so this makes sense. */ - e = 0xb53bf0; + e = MIXER_LEVEL_N3DB; } /* Connect analog outputs ? */ - a = 0x65; - e = 0x01000000; + a = SC1810C_SEL_OUTPUT; for (b = 1; b < 3; b++) { - snd_s1810c_send_ctl_packet(dev, a, b, 0, 0, e); - snd_s1810c_send_ctl_packet(dev, a, b, 0, 1, e); + snd_s1810c_send_ctl_packet(dev, a, b, 0, 0, MIXER_LEVEL_0DB); + snd_s1810c_send_ctl_packet(dev, a, b, 0, 1, MIXER_LEVEL_0DB); } - snd_s1810c_send_ctl_packet(dev, a, 0, 0, 0, e); - snd_s1810c_send_ctl_packet(dev, a, 0, 0, 1, e); + snd_s1810c_send_ctl_packet(dev, a, 0, 0, 0, MIXER_LEVEL_0DB); + snd_s1810c_send_ctl_packet(dev, a, 0, 0, 1, MIXER_LEVEL_0DB); /* Set initial volume levels for S/PDIF mappings ? */ - a = 0x64; - e = 0xbc; + a = SC1810C_SEL_MIXER; + e = MIXER_LEVEL_N99DB; c = 3; for (n = 0; n < 2; n++) { off = n * 18; @@ -257,26 +295,23 @@ static int snd_s1810c_init_mixer_maps(struct snd_usb_audio *chip) snd_s1810c_send_ctl_packet(dev, a, b, c, 0, e); snd_s1810c_send_ctl_packet(dev, a, b, c, 1, e); } - e = 0xb53bf0; + e = MIXER_LEVEL_N3DB; } /* Connect S/PDIF output ? */ - a = 0x65; - e = 0x01000000; - snd_s1810c_send_ctl_packet(dev, a, 3, 0, 0, e); - snd_s1810c_send_ctl_packet(dev, a, 3, 0, 1, e); + a = SC1810C_SEL_OUTPUT; + snd_s1810c_send_ctl_packet(dev, a, 3, 0, 0, MIXER_LEVEL_0DB); + snd_s1810c_send_ctl_packet(dev, a, 3, 0, 1, MIXER_LEVEL_0DB); /* Connect all outputs (again) ? */ - a = 0x65; - e = 0x01000000; + a = SC1810C_SEL_OUTPUT; for (b = 0; b < 4; b++) { - snd_s1810c_send_ctl_packet(dev, a, b, 0, 0, e); - snd_s1810c_send_ctl_packet(dev, a, b, 0, 1, e); + snd_s1810c_send_ctl_packet(dev, a, b, 0, 0, MIXER_LEVEL_0DB); + snd_s1810c_send_ctl_packet(dev, a, b, 0, 1, MIXER_LEVEL_0DB); } /* Basic routing to get sound out of the device */ - a = 0x64; - e = 0x01000000; + a = SC1810C_SEL_MIXER; for (c = 0; c < 4; c++) { for (b = 0; b < 36; b++) { if ((c == 0 && b == 18) || /* DAW1/2 -> Main */ @@ -284,23 +319,29 @@ static int snd_s1810c_init_mixer_maps(struct snd_usb_audio *chip) (c == 2 && b == 22) || /* DAW4/5 -> Line5/6 */ (c == 3 && b == 24)) { /* DAW5/6 -> S/PDIF */ /* Left */ - snd_s1810c_send_ctl_packet(dev, a, b, c, 0, e); - snd_s1810c_send_ctl_packet(dev, a, b, c, 1, 0); + snd_s1810c_send_ctl_packet(dev, + a, b, c, 0, MIXER_LEVEL_0DB); + snd_s1810c_send_ctl_packet(dev, + a, b, c, 1, MIXER_LEVEL_MUTE); b++; /* Right */ - snd_s1810c_send_ctl_packet(dev, a, b, c, 0, 0); - snd_s1810c_send_ctl_packet(dev, a, b, c, 1, e); + snd_s1810c_send_ctl_packet(dev, + a, b, c, 0, MIXER_LEVEL_MUTE); + snd_s1810c_send_ctl_packet(dev, + a, b, c, 1, MIXER_LEVEL_0DB); } else { /* Leave the rest disconnected */ - snd_s1810c_send_ctl_packet(dev, a, b, c, 0, 0); - snd_s1810c_send_ctl_packet(dev, a, b, c, 1, 0); + snd_s1810c_send_ctl_packet(dev, + a, b, c, 0, MIXER_LEVEL_MUTE); + snd_s1810c_send_ctl_packet(dev, + a, b, c, 1, MIXER_LEVEL_MUTE); } } } /* Set initial volume levels for S/PDIF (again) ? */ - a = 0x64; - e = 0xbc; + a = SC1810C_SEL_MIXER; + e = MIXER_LEVEL_N99DB; c = 3; for (n = 0; n < 2; n++) { off = n * 18; @@ -308,29 +349,26 @@ static int snd_s1810c_init_mixer_maps(struct snd_usb_audio *chip) snd_s1810c_send_ctl_packet(dev, a, b, c, 0, e); snd_s1810c_send_ctl_packet(dev, a, b, c, 1, e); } - e = 0xb53bf0; + e = MIXER_LEVEL_N3DB; } /* Connect S/PDIF outputs (again) ? */ - a = 0x65; - e = 0x01000000; - snd_s1810c_send_ctl_packet(dev, a, 3, 0, 0, e); - snd_s1810c_send_ctl_packet(dev, a, 3, 0, 1, e); + a = SC1810C_SEL_OUTPUT; + snd_s1810c_send_ctl_packet(dev, a, 3, 0, 0, MIXER_LEVEL_0DB); + snd_s1810c_send_ctl_packet(dev, a, 3, 0, 1, MIXER_LEVEL_0DB); /* Again ? */ - snd_s1810c_send_ctl_packet(dev, a, 3, 0, 0, e); - snd_s1810c_send_ctl_packet(dev, a, 3, 0, 1, e); + snd_s1810c_send_ctl_packet(dev, a, 3, 0, 0, MIXER_LEVEL_0DB); + snd_s1810c_send_ctl_packet(dev, a, 3, 0, 1, MIXER_LEVEL_0DB); break; case USB_ID(0x194f, 0x010d): /* 1824c */ /* Set all output faders to unity gain */ - a = 0x65; + a = SC1810C_SEL_OUTPUT; c = 0x00; - e = 0x01000000; - for (b = 0; b < 9; b++) { - snd_s1810c_send_ctl_packet(dev, a, b, c, 0, e); - snd_s1810c_send_ctl_packet(dev, a, b, c, 1, e); + snd_s1810c_send_ctl_packet(dev, a, b, c, 0, MIXER_LEVEL_0DB); + snd_s1810c_send_ctl_packet(dev, a, b, c, 1, MIXER_LEVEL_0DB); } /* Set @@ -345,7 +383,7 @@ static int snd_s1810c_init_mixer_maps(struct snd_usb_audio *chip) * Daw 17 -> ADAT out 7, (left) Daw 18 -> ADAT out 8 (right) * Everything else muted */ - a = 0x64; + a = SC1810C_SEL_MIXER; /* The first Daw channel is channel 18 */ left = 18; @@ -354,14 +392,20 @@ static int snd_s1810c_init_mixer_maps(struct snd_usb_audio *chip) for (b = 0; b < 36; b++) { if (b == left) { - snd_s1810c_send_ctl_packet(dev, a, b, c, 0, 0x01000000); - snd_s1810c_send_ctl_packet(dev, a, b, c, 1, 0x00); + snd_s1810c_send_ctl_packet(dev, + a, b, c, 0, MIXER_LEVEL_0DB); + snd_s1810c_send_ctl_packet(dev, + a, b, c, 1, MIXER_LEVEL_MUTE); } else if (b == right) { - snd_s1810c_send_ctl_packet(dev, a, b, c, 0, 0x00); - snd_s1810c_send_ctl_packet(dev, a, b, c, 1, 0x01000000); + snd_s1810c_send_ctl_packet(dev, + a, b, c, 0, MIXER_LEVEL_MUTE); + snd_s1810c_send_ctl_packet(dev, + a, b, c, 1, MIXER_LEVEL_0DB); } else { - snd_s1810c_send_ctl_packet(dev, a, b, c, 0, 0x00); - snd_s1810c_send_ctl_packet(dev, a, b, c, 1, 0x00); + snd_s1810c_send_ctl_packet(dev, + a, b, c, 0, MIXER_LEVEL_MUTE); + snd_s1810c_send_ctl_packet(dev, + a, b, c, 1, MIXER_LEVEL_MUTE); } } left += 2; -- 2.52.0 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v2 2/2] ALSA: usb-audio: clean up presonus s1810 consts @ 2026-01-11 21:36 ` fenugrec via B4 Relay 0 siblings, 0 replies; 8+ messages in thread From: fenugrec via B4 Relay @ 2026-01-11 21:36 UTC (permalink / raw) To: Takashi Iwai Cc: linux-sound, linux-kernel, roy.vegard.ovesen, mickflemm, fenugrec From: fenugrec <fenugrec@mail.com> - Reorder some #define blocks - Document mixer/volume levels - Document some Ctl request fields (tag, len) - replace some magic numbers with macros No functional change intended. The information is based on reverse engineering. Signed-off-by: fenugrec <fenugrec@mail.com> --- sound/usb/mixer_s1810c.c | 204 ++++++++++++++++++++++++++++------------------- 1 file changed, 124 insertions(+), 80 deletions(-) diff --git a/sound/usb/mixer_s1810c.c b/sound/usb/mixer_s1810c.c index 93510aa0dc5e..b4ce89afb25b 100644 --- a/sound/usb/mixer_s1810c.c +++ b/sound/usb/mixer_s1810c.c @@ -25,12 +25,6 @@ #include "helper.h" #include "mixer_s1810c.h" -#define SC1810C_CMD_REQ 160 -#define SC1810C_CMD_REQTYPE \ - (USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT) -#define SC1810C_CMD_F1 0x50617269 -#define SC1810C_CMD_F2 0x14 - /* * DISCLAIMER: These are just guesses based on the * dumps I got. @@ -42,9 +36,8 @@ * * b selects an input channel (see below). * * c selects an output channel pair (see below). * * d selects left (0) or right (1) of that pair. - * * e 0-> disconnect, 0x01000000-> connect, - * 0x0109-> used for stereo-linking channels, - * e is also used for setting volume levels + * * e level : see MIXER_LEVEL_* defines below. + * Also used for setting volume levels * in which case b is also set so I guess * this way it is possible to set the volume * level from the specified input to the @@ -75,52 +68,98 @@ * For output (0x65): * * b is the output channel (see above). * * c is zero. - * * e I guess the same as with mixer except 0x0109 - * which I didn't see in my dumps. + * * e I guess the same as with mixer + * + */ +/** struct s1810c_ctl_packet - basic vendor request + * @selector: device/mixer/output + * @b: request-dependant field b + * @tag: fixed value identifying type of request + * @len: sizeof this struct - 8 (excludes first 2 fields) + * i.e. for basic struct s1810c_ctl_packet: len is 5*4=0x14 + * @c: request-dependant field c + * @d: request-dependant field d + * @e: request-dependant field e * - * The two fixed fields have the same values for - * mixer and output but a different set for device. + * See longer description above. This could be combined + * (as a union?) with the longer struct s1810c_state_packet */ struct s1810c_ctl_packet { - __le32 a; + __le32 selector; __le32 b; - __le32 fixed1; - __le32 fixed2; + __le32 tag; + __le32 len; __le32 c; __le32 d; __le32 e; }; +/** selectors for CMD request + */ +#define SC1810C_SEL_DEVICE 0 +#define SC1810C_SEL_MIXER 0x64 +#define SC1810C_SEL_OUTPUT 0x65 + + +/** control ids */ #define SC1810C_CTL_LINE_SW 0 #define SC1810C_CTL_MUTE_SW 1 #define SC1824C_CTL_MONO_SW 2 #define SC1810C_CTL_AB_SW 3 #define SC1810C_CTL_48V_SW 4 +/* USB Control (vendor) requests + */ +#define SC1810C_CMD_REQ 160 +#define SC1810C_CMD_REQTYPE \ + (USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT) +#define SC1810C_CMD_TAG 0x50617269 +#define SC1810C_CMD_LEN 0x14 + #define SC1810C_SET_STATE_REQ 161 #define SC1810C_SET_STATE_REQTYPE SC1810C_CMD_REQTYPE -#define SC1810C_SET_STATE_F1 0x64656D73 -#define SC1810C_SET_STATE_F2 0xF4 +#define SC1810C_SET_STATE_TAG 0x64656D73 +#define SC1810C_SET_STATE_LEN 0xF4 #define SC1810C_GET_STATE_REQ 162 #define SC1810C_GET_STATE_REQTYPE \ (USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN) -#define SC1810C_GET_STATE_F1 SC1810C_SET_STATE_F1 -#define SC1810C_GET_STATE_F2 SC1810C_SET_STATE_F2 - -#define SC1810C_STATE_F1_IDX 2 -#define SC1810C_STATE_F2_IDX 3 +#define SC1810C_GET_STATE_TAG SC1810C_SET_STATE_TAG +#define SC1810C_GET_STATE_LEN SC1810C_SET_STATE_LEN + +/** Mixer levels normally range from 0 (off) to 0x0100 0000 (0 dB). + * raw_level = 2^24 * 10^(db_level / 20), thus + * -3dB = 0xb53bf0 (technically, half-power -3.01...dB would be 0xb504f3) + * -96dB = 0x109 + * -99dB = 0xBC + * PC software sliders cover -96 to +10dB (0x0329 8b08), + * but the value 0 (-inf dB) can be used when e.g. Mixer Bypass is enabled. + * Unclear what the hardware's maximum value is. + * + * Note, when a channel is panned to two channels (stereo), + * the mixer level is set to slider value (by default -96dB) minus 3dB, + * which explains the -99dB value seen in USB captures. + */ +#define MIXER_LEVEL_MUTE 0 +#define MIXER_LEVEL_N99DB 0xbc +#define MIXER_LEVEL_N3DB 0xb53bf0 +#define MIXER_LEVEL_0DB 0x1000000 -/* +/** * This packet includes mixer volumes and * various other fields, it's an extended * version of ctl_packet, with a and b - * being zero and different f1/f2. + * being zero and different tag/length. */ struct s1810c_state_packet { __le32 fields[63]; }; +/** indices into s1810c_state_packet.fields[] + */ +#define SC1810C_STATE_TAG_IDX 2 +#define SC1810C_STATE_LEN_IDX 3 + #define SC1810C_STATE_48V_SW 58 #define SC1810C_STATE_LINE_SW 59 #define SC1810C_STATE_MUTE_SW 60 @@ -134,16 +173,16 @@ struct s1810_mixer_state { }; static int -snd_s1810c_send_ctl_packet(struct usb_device *dev, u32 a, +snd_s1810c_send_ctl_packet(struct usb_device *dev, u32 sel, u32 b, u32 c, u32 d, u32 e) { struct s1810c_ctl_packet pkt = { 0 }; int ret = 0; - pkt.fixed1 = __cpu_to_le32(SC1810C_CMD_F1); - pkt.fixed2 = __cpu_to_le32(SC1810C_CMD_F2); + pkt.tag = __cpu_to_le32(SC1810C_CMD_TAG); + pkt.len = __cpu_to_le32(SC1810C_CMD_LEN); - pkt.a = __cpu_to_le32(a); + pkt.selector = __cpu_to_le32(sel); pkt.b = __cpu_to_le32(b); pkt.c = __cpu_to_le32(c); pkt.d = __cpu_to_le32(d); @@ -176,8 +215,8 @@ snd_sc1810c_get_status_field(struct usb_device *dev, struct s1810c_state_packet pkt_in = { { 0 } }; int ret = 0; - pkt_out.fields[SC1810C_STATE_F1_IDX] = __cpu_to_le32(SC1810C_SET_STATE_F1); - pkt_out.fields[SC1810C_STATE_F2_IDX] = __cpu_to_le32(SC1810C_SET_STATE_F2); + pkt_out.fields[SC1810C_STATE_TAG_IDX] = __cpu_to_le32(SC1810C_SET_STATE_TAG); + pkt_out.fields[SC1810C_STATE_LEN_IDX] = __cpu_to_le32(SC1810C_SET_STATE_LEN); ret = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), SC1810C_SET_STATE_REQ, SC1810C_SET_STATE_REQTYPE, @@ -216,8 +255,8 @@ static int snd_s1810c_init_mixer_maps(struct snd_usb_audio *chip) switch (chip->usb_id) { case USB_ID(0x194f, 0x010c): /* 1810c */ /* Set initial volume levels ? */ - a = 0x64; - e = 0xbc; + a = SC1810C_SEL_MIXER; + e = MIXER_LEVEL_N99DB; for (n = 0; n < 2; n++) { off = n * 18; for (b = off; b < 18 + off; b++) { @@ -234,22 +273,21 @@ static int snd_s1810c_init_mixer_maps(struct snd_usb_audio *chip) * I noticed on UC that DAW channels have different * initial volumes, so this makes sense. */ - e = 0xb53bf0; + e = MIXER_LEVEL_N3DB; } /* Connect analog outputs ? */ - a = 0x65; - e = 0x01000000; + a = SC1810C_SEL_OUTPUT; for (b = 1; b < 3; b++) { - snd_s1810c_send_ctl_packet(dev, a, b, 0, 0, e); - snd_s1810c_send_ctl_packet(dev, a, b, 0, 1, e); + snd_s1810c_send_ctl_packet(dev, a, b, 0, 0, MIXER_LEVEL_0DB); + snd_s1810c_send_ctl_packet(dev, a, b, 0, 1, MIXER_LEVEL_0DB); } - snd_s1810c_send_ctl_packet(dev, a, 0, 0, 0, e); - snd_s1810c_send_ctl_packet(dev, a, 0, 0, 1, e); + snd_s1810c_send_ctl_packet(dev, a, 0, 0, 0, MIXER_LEVEL_0DB); + snd_s1810c_send_ctl_packet(dev, a, 0, 0, 1, MIXER_LEVEL_0DB); /* Set initial volume levels for S/PDIF mappings ? */ - a = 0x64; - e = 0xbc; + a = SC1810C_SEL_MIXER; + e = MIXER_LEVEL_N99DB; c = 3; for (n = 0; n < 2; n++) { off = n * 18; @@ -257,26 +295,23 @@ static int snd_s1810c_init_mixer_maps(struct snd_usb_audio *chip) snd_s1810c_send_ctl_packet(dev, a, b, c, 0, e); snd_s1810c_send_ctl_packet(dev, a, b, c, 1, e); } - e = 0xb53bf0; + e = MIXER_LEVEL_N3DB; } /* Connect S/PDIF output ? */ - a = 0x65; - e = 0x01000000; - snd_s1810c_send_ctl_packet(dev, a, 3, 0, 0, e); - snd_s1810c_send_ctl_packet(dev, a, 3, 0, 1, e); + a = SC1810C_SEL_OUTPUT; + snd_s1810c_send_ctl_packet(dev, a, 3, 0, 0, MIXER_LEVEL_0DB); + snd_s1810c_send_ctl_packet(dev, a, 3, 0, 1, MIXER_LEVEL_0DB); /* Connect all outputs (again) ? */ - a = 0x65; - e = 0x01000000; + a = SC1810C_SEL_OUTPUT; for (b = 0; b < 4; b++) { - snd_s1810c_send_ctl_packet(dev, a, b, 0, 0, e); - snd_s1810c_send_ctl_packet(dev, a, b, 0, 1, e); + snd_s1810c_send_ctl_packet(dev, a, b, 0, 0, MIXER_LEVEL_0DB); + snd_s1810c_send_ctl_packet(dev, a, b, 0, 1, MIXER_LEVEL_0DB); } /* Basic routing to get sound out of the device */ - a = 0x64; - e = 0x01000000; + a = SC1810C_SEL_MIXER; for (c = 0; c < 4; c++) { for (b = 0; b < 36; b++) { if ((c == 0 && b == 18) || /* DAW1/2 -> Main */ @@ -284,23 +319,29 @@ static int snd_s1810c_init_mixer_maps(struct snd_usb_audio *chip) (c == 2 && b == 22) || /* DAW4/5 -> Line5/6 */ (c == 3 && b == 24)) { /* DAW5/6 -> S/PDIF */ /* Left */ - snd_s1810c_send_ctl_packet(dev, a, b, c, 0, e); - snd_s1810c_send_ctl_packet(dev, a, b, c, 1, 0); + snd_s1810c_send_ctl_packet(dev, + a, b, c, 0, MIXER_LEVEL_0DB); + snd_s1810c_send_ctl_packet(dev, + a, b, c, 1, MIXER_LEVEL_MUTE); b++; /* Right */ - snd_s1810c_send_ctl_packet(dev, a, b, c, 0, 0); - snd_s1810c_send_ctl_packet(dev, a, b, c, 1, e); + snd_s1810c_send_ctl_packet(dev, + a, b, c, 0, MIXER_LEVEL_MUTE); + snd_s1810c_send_ctl_packet(dev, + a, b, c, 1, MIXER_LEVEL_0DB); } else { /* Leave the rest disconnected */ - snd_s1810c_send_ctl_packet(dev, a, b, c, 0, 0); - snd_s1810c_send_ctl_packet(dev, a, b, c, 1, 0); + snd_s1810c_send_ctl_packet(dev, + a, b, c, 0, MIXER_LEVEL_MUTE); + snd_s1810c_send_ctl_packet(dev, + a, b, c, 1, MIXER_LEVEL_MUTE); } } } /* Set initial volume levels for S/PDIF (again) ? */ - a = 0x64; - e = 0xbc; + a = SC1810C_SEL_MIXER; + e = MIXER_LEVEL_N99DB; c = 3; for (n = 0; n < 2; n++) { off = n * 18; @@ -308,29 +349,26 @@ static int snd_s1810c_init_mixer_maps(struct snd_usb_audio *chip) snd_s1810c_send_ctl_packet(dev, a, b, c, 0, e); snd_s1810c_send_ctl_packet(dev, a, b, c, 1, e); } - e = 0xb53bf0; + e = MIXER_LEVEL_N3DB; } /* Connect S/PDIF outputs (again) ? */ - a = 0x65; - e = 0x01000000; - snd_s1810c_send_ctl_packet(dev, a, 3, 0, 0, e); - snd_s1810c_send_ctl_packet(dev, a, 3, 0, 1, e); + a = SC1810C_SEL_OUTPUT; + snd_s1810c_send_ctl_packet(dev, a, 3, 0, 0, MIXER_LEVEL_0DB); + snd_s1810c_send_ctl_packet(dev, a, 3, 0, 1, MIXER_LEVEL_0DB); /* Again ? */ - snd_s1810c_send_ctl_packet(dev, a, 3, 0, 0, e); - snd_s1810c_send_ctl_packet(dev, a, 3, 0, 1, e); + snd_s1810c_send_ctl_packet(dev, a, 3, 0, 0, MIXER_LEVEL_0DB); + snd_s1810c_send_ctl_packet(dev, a, 3, 0, 1, MIXER_LEVEL_0DB); break; case USB_ID(0x194f, 0x010d): /* 1824c */ /* Set all output faders to unity gain */ - a = 0x65; + a = SC1810C_SEL_OUTPUT; c = 0x00; - e = 0x01000000; - for (b = 0; b < 9; b++) { - snd_s1810c_send_ctl_packet(dev, a, b, c, 0, e); - snd_s1810c_send_ctl_packet(dev, a, b, c, 1, e); + snd_s1810c_send_ctl_packet(dev, a, b, c, 0, MIXER_LEVEL_0DB); + snd_s1810c_send_ctl_packet(dev, a, b, c, 1, MIXER_LEVEL_0DB); } /* Set @@ -345,7 +383,7 @@ static int snd_s1810c_init_mixer_maps(struct snd_usb_audio *chip) * Daw 17 -> ADAT out 7, (left) Daw 18 -> ADAT out 8 (right) * Everything else muted */ - a = 0x64; + a = SC1810C_SEL_MIXER; /* The first Daw channel is channel 18 */ left = 18; @@ -354,14 +392,20 @@ static int snd_s1810c_init_mixer_maps(struct snd_usb_audio *chip) for (b = 0; b < 36; b++) { if (b == left) { - snd_s1810c_send_ctl_packet(dev, a, b, c, 0, 0x01000000); - snd_s1810c_send_ctl_packet(dev, a, b, c, 1, 0x00); + snd_s1810c_send_ctl_packet(dev, + a, b, c, 0, MIXER_LEVEL_0DB); + snd_s1810c_send_ctl_packet(dev, + a, b, c, 1, MIXER_LEVEL_MUTE); } else if (b == right) { - snd_s1810c_send_ctl_packet(dev, a, b, c, 0, 0x00); - snd_s1810c_send_ctl_packet(dev, a, b, c, 1, 0x01000000); + snd_s1810c_send_ctl_packet(dev, + a, b, c, 0, MIXER_LEVEL_MUTE); + snd_s1810c_send_ctl_packet(dev, + a, b, c, 1, MIXER_LEVEL_0DB); } else { - snd_s1810c_send_ctl_packet(dev, a, b, c, 0, 0x00); - snd_s1810c_send_ctl_packet(dev, a, b, c, 1, 0x00); + snd_s1810c_send_ctl_packet(dev, + a, b, c, 0, MIXER_LEVEL_MUTE); + snd_s1810c_send_ctl_packet(dev, + a, b, c, 1, MIXER_LEVEL_MUTE); } } left += 2; -- 2.52.0 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v2 0/2] ALSA: usb-audio: presonus s1810 minor cleanup and document 2026-01-11 21:36 ` fenugrec via B4 Relay ` (2 preceding siblings ...) (?) @ 2026-01-13 12:22 ` Takashi Iwai 2026-01-13 14:10 ` fenugrec -1 siblings, 1 reply; 8+ messages in thread From: Takashi Iwai @ 2026-01-13 12:22 UTC (permalink / raw) To: fenugrec; +Cc: linux-sound, linux-kernel, roy.vegard.ovesen, mickflemm On Sun, 11 Jan 2026 22:36:39 +0100, fenugrec via B4 Relay wrote: > > patch v2 : apologies, I had missed an __le32 field. > > - Use __le32 fields for structures sent/received over USB > Addresses a comment from when this driver was initially merged: > https://lore.kernel.org/all/s5hd0agcjw1.wl-tiwai@suse.de/ > > - Document constants and protocol details common to the Studio 1810 and > 1824c devices > > Except for a hypothetical big-endian platform (which I cannot test) where the first > commit would make a difference, both these should have no functional > change. > > Signed-off-by: fenugrec <fenugrec@mail.com> > --- > Changes in v2: > - fix an overlooked __le32 conversion for .tag and .len fields > - Link to v1: https://lore.kernel.org/r/20260110-preso_clean1-v1-0-ce2dd3ea4506@mail.com Thanks for the patches. The code changes look OK, so I can take as is. But I wonder about your identity "fenugrec". Is it a real name? The Signed-off-by line needs to be a real name (or a known identity) for legal reasons. thanks, Takashi ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2 0/2] ALSA: usb-audio: presonus s1810 minor cleanup and document 2026-01-13 12:22 ` [PATCH v2 0/2] ALSA: usb-audio: presonus s1810 minor cleanup and document Takashi Iwai @ 2026-01-13 14:10 ` fenugrec 0 siblings, 0 replies; 8+ messages in thread From: fenugrec @ 2026-01-13 14:10 UTC (permalink / raw) To: Takashi Iwai; +Cc: linux-sound, linux-kernel, roy.vegard.ovesen, mickflemm Hi, > The Signed-off-by line needs to be a real name (or a known identity) > for legal reasons. is it acceptable if I've been using this same identity since at least 2009: https://sourceforge.net/p/freediag/gitrepo/ci/9314daac0cecda4e82b5e3e0de4d75fa62cffe93/ I can also PGP-sign (7F91B004A4E206EC) commits or sign-offs if that would be helpful? Thanks ! ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-01-13 14:10 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-01-11 21:36 [PATCH v2 0/2] ALSA: usb-audio: presonus s1810 minor cleanup and document fenugrec 2026-01-11 21:36 ` fenugrec via B4 Relay 2026-01-11 21:36 ` [PATCH v2 1/2] ALSA: usb-audio: presonus s18xx uses little-endian fenugrec 2026-01-11 21:36 ` fenugrec via B4 Relay 2026-01-11 21:36 ` [PATCH v2 2/2] ALSA: usb-audio: clean up presonus s1810 consts fenugrec 2026-01-11 21:36 ` fenugrec via B4 Relay 2026-01-13 12:22 ` [PATCH v2 0/2] ALSA: usb-audio: presonus s1810 minor cleanup and document Takashi Iwai 2026-01-13 14:10 ` fenugrec
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.