Re: [PATCH] USB Audio Class 2 Mixer unit support for GET_CUR, SET_CUR and RANGE

From: Zipdox

Date: Mon Oct 05 2026 - 09:55:33 EST


On 9/28/26 12:59 PM, Takashi Iwai wrote:
I thought of it, too. OTOH, it'll be a bit tricky, because the range
isn't usually covering -32767 but only a part. So -32768 won't be
reached continuously.

I'm inclined to have a simple mute switch in addition.


thanks,

Takashi

Actually I think this seems to work. We might have to do something with
dBmin and dBmax as well though, I don't fully understand their function.

---
sound/usb/mixer.c | 26 +++++++++++++++++++++-----
sound/usb/mixer.h | 2 +-
2 files changed, 22 insertions(+), 6 deletions(-)

diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 91d4c7373871..1653bb47ed6c 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -358,7 +358,7 @@ static int request_ctl_v2(struct usb_mixer_elem_info *cval, u8 request,
return -EIO;
/* correct wValue for UAC2 mixer control with MCN */
- if (cval->v2_mixer)
+ if (cval->mixer_unit == 2)
validx = (UAC2_MU_MIXER << 8) | to_mcn(cval, validx);
memset(buf, 0, size);
@@ -400,9 +400,14 @@ static int get_cur_ctl_value(struct usb_mixer_elem_info *cval,
{
validx += cval->idx_off;
- return (cval->head.mixer->protocol == UAC_VERSION_1) ?
+ int value = (cval->head.mixer->protocol == UAC_VERSION_1) ?
request_ctl_v1(cval, UAC_GET_CUR, validx, value_ret) :
get_ctl_value_v2(cval, validx, value_ret);
+
+ /* Map -32768 (mute in mixer unit spec) to minimum */
+ if(cval->mixer_unit && value == -32768) value = cval->min;
+
+ return value;
}
/* channel = 0: master, 1 = first channel */
@@ -539,11 +544,16 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
request = UAC2_CS_CUR;
- /* correct wValue for UAC2 mixer control with MCN */
- if (cval->v2_mixer)
+ /* correct wValue for UAC2 mixer unit control with MCN */
+ if (cval->mixer_unit == 2)
validx = (UAC2_MU_MIXER << 8) | to_mcn(cval, validx);
}
+ /* Remap the lowest value to -32768 (mute per the spec for mixer units) */
+ if(cval->mixer_unit && value_set < (cval->min + cval->res)){
+ value_set = -32768;
+ }
+
value_set = convert_bytes_value(cval, value_set);
buf[0] = value_set & 0xff;
buf[1] = (value_set >> 8) & 0xff;
@@ -2390,7 +2400,11 @@ static void build_mixer_unit_ctl(struct mixer_build *state,
cval->control = in_ch + 1; /* based on 1 */
if (state->mixer->protocol == UAC_VERSION_2 ||
state->mixer->protocol == UAC_VERSION_3)
- cval->v2_mixer = true;
+ {
+ cval->mixer_unit = 2;
+ }else{
+ cval->mixer_unit = 1;
+ }
cval->num_outputs = num_outs;
cval->val_type = USB_MIXER_S16;
for (i = 0; i < num_outs; i++) {
@@ -2408,6 +2422,8 @@ static void build_mixer_unit_ctl(struct mixer_build *state,
usb_mixer_elem_info_free(cval);
return;
}
+ /* We will map the lowest setting to mute (-32768 per the spec) */
+ cval->min -= cval->res;
kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval);
if (!kctl) {
diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h
index cf45c39cbccc..2ace9b95da0a 100644
--- a/sound/usb/mixer.h
+++ b/sound/usb/mixer.h
@@ -98,7 +98,7 @@ struct usb_mixer_elem_info {
u8 min_mute;
u8 get_cur_broken;
u8 num_outputs;
- bool v2_mixer;
+ int mixer_unit;
void *private_data;
};
--
2.47.3