* [PATCH 0/2] ALSA: usb-audio: Support for Feaulle Rainbow
@ 2026-04-08 18:33 Rong Zhang
2026-04-08 18:33 ` [PATCH 1/2] ALSA: usb-audio: Add quirk flags " Rong Zhang
2026-04-08 18:33 ` [PATCH 2/2] ALSA: usb-audio: Do not expose sticky volume control mixers Rong Zhang
0 siblings, 2 replies; 8+ messages in thread
From: Rong Zhang @ 2026-04-08 18:33 UTC (permalink / raw)
To: Jaroslav Kysela, Takashi Iwai
Cc: linux-sound, linux-kernel, Icenowy Zheng, Rong Zhang
Feaulle Rainbow is a wired USB-C dynamic in-ear monitor (IEM) featuring
active noise cancellation (ANC).
The supported sample rates are 48000Hz and 96000Hz at 16bit or 24bit,
but it does not support reading the current sample rate and results in
an error message printed to kmsg. Set QUIRK_FLAG_GET_SAMPLE_RATE to skip
the sample rate check.
Its playback mixer reports val = -15360/0/128. Setting -15360 (-60dB)
mutes the playback, so QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE is needed.
Its Mic Capture Volume mixer is sticky (accepts SET_CUR but do
absolutely nothing). Registering it confuses userspace and results in
ineffective volume control.
Patch 1 adds a quirk table entry matching VID/PID=0x0e0b/0xfa01 and
applying the mentioned quirk flags, so that it can work properly.
Patch 2 checks if a volume control mixer is sticky by setting the volume
to the maximum or minimum value, and prevent the mixer from being
registered accordingly.
Quirky device sample:
usb 7-1: New USB device found, idVendor=0e0b, idProduct=fa01, bcdDevice= 1.00
usb 7-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
usb 7-1: Product: Feaulle Rainbow
usb 7-1: Manufacturer: Generic
usb 7-1: SerialNumber: 20210726905926
Signed-off-by: Rong Zhang <i@rong.moe>
---
Rong Zhang (2):
ALSA: usb-audio: Add quirk flags for Feaulle Rainbow
ALSA: usb-audio: Do not expose sticky volume control mixers
sound/usb/mixer.c | 37 +++++++++++++++++++++++++++++++++++--
sound/usb/quirks.c | 2 ++
2 files changed, 37 insertions(+), 2 deletions(-)
---
base-commit: 292286b2d229fb732421429b027d38ac3f969383
change-id: 20260403-feaulle-rainbow-fb6e2db837a4
Thanks,
Rong
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 1/2] ALSA: usb-audio: Add quirk flags for Feaulle Rainbow
2026-04-08 18:33 [PATCH 0/2] ALSA: usb-audio: Support for Feaulle Rainbow Rong Zhang
@ 2026-04-08 18:33 ` Rong Zhang
2026-04-09 14:38 ` Takashi Iwai
2026-04-08 18:33 ` [PATCH 2/2] ALSA: usb-audio: Do not expose sticky volume control mixers Rong Zhang
1 sibling, 1 reply; 8+ messages in thread
From: Rong Zhang @ 2026-04-08 18:33 UTC (permalink / raw)
To: Jaroslav Kysela, Takashi Iwai
Cc: linux-sound, linux-kernel, Icenowy Zheng, Rong Zhang
Feaulle Rainbow is a wired USB-C dynamic in-ear monitor (IEM) featuring
active noise cancellation (ANC).
The supported sample rates are 48000Hz and 96000Hz at 16bit or 24bit,
but it does not support reading the current sample rate and results in
an error message printed to kmsg. Set QUIRK_FLAG_GET_SAMPLE_RATE to skip
the sample rate check.
Its playback mixer reports val = -15360/0/128. Setting -15360 (-60dB)
mutes the playback, so QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE is needed.
Add a quirk table entry matching VID/PID=0x0e0b/0xfa01 and applying
the mentioned quirk flags, so that it can work properly.
Quirky device sample:
usb 7-1: New USB device found, idVendor=0e0b, idProduct=fa01, bcdDevice= 1.00
usb 7-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
usb 7-1: Product: Feaulle Rainbow
usb 7-1: Manufacturer: Generic
usb 7-1: SerialNumber: 20210726905926
Signed-off-by: Rong Zhang <i@rong.moe>
---
sound/usb/quirks.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 48acd8dac689..f73d5d01726e 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -2337,6 +2337,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE),
DEVICE_FLG(0x0d8c, 0x0014, /* C-Media */
QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE),
+ DEVICE_FLG(0x0e0b, 0xfa01, /* Feaulle Rainbow */
+ QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE),
DEVICE_FLG(0x0ecb, 0x205c, /* JBL Quantum610 Wireless */
QUIRK_FLAG_FIXED_RATE),
DEVICE_FLG(0x0ecb, 0x2069, /* JBL Quantum810 Wireless */
--
2.53.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 2/2] ALSA: usb-audio: Do not expose sticky volume control mixers
2026-04-08 18:33 [PATCH 0/2] ALSA: usb-audio: Support for Feaulle Rainbow Rong Zhang
2026-04-08 18:33 ` [PATCH 1/2] ALSA: usb-audio: Add quirk flags " Rong Zhang
@ 2026-04-08 18:33 ` Rong Zhang
2026-04-09 7:08 ` Takashi Iwai
1 sibling, 1 reply; 8+ messages in thread
From: Rong Zhang @ 2026-04-08 18:33 UTC (permalink / raw)
To: Jaroslav Kysela, Takashi Iwai
Cc: linux-sound, linux-kernel, Icenowy Zheng, Rong Zhang
Some devices expose sticky mixers that accept SET_CUR but do absolutely
nothing. Registering mixers for them confuses userspace and results in
ineffective volume control.
Check if the volume control is sticky by setting the volume to the
maximum or minimum value, and prevent the mixer from being registered
accordingly.
Quirky device sample:
usb 7-1: New USB device found, idVendor=0e0b, idProduct=fa01, bcdDevice= 1.00
usb 7-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
usb 7-1: Product: Feaulle Rainbow
usb 7-1: Manufacturer: Generic
usb 7-1: SerialNumber: 20210726905926
(Mic Capture Volume)
Signed-off-by: Rong Zhang <i@rong.moe>
---
sound/usb/mixer.c | 37 +++++++++++++++++++++++++++++++++++--
1 file changed, 35 insertions(+), 2 deletions(-)
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index a25e8145af67..9f0aed36e27d 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -27,6 +27,7 @@
* - parse available sample rates again when clock sources changed
*/
+#include <linux/array_size.h>
#include <linux/bitops.h>
#include <linux/init.h>
#include <linux/list.h>
@@ -1287,17 +1288,49 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval,
if (cval->res == 0)
cval->res = 1;
- /* Additional checks for the proper resolution
+ /* Additional checks
+ *
+ * Some devices expose sticky mixers that accept SET_CUR
+ * but do absolutely nothing.
*
* Some devices report smaller resolutions than actually
* reacting. They don't return errors but simply clip
* to the lower aligned value.
*/
- if (cval->min + cval->res < cval->max) {
+ if (cval->min < cval->max) {
+ int sticky_test_values[] = { cval->min, cval->max };
int last_valid_res = cval->res;
int saved, test, check;
+ bool effective = false;
+
if (get_cur_mix_raw(cval, minchn, &saved) < 0)
goto no_res_check;
+
+ for (i = 0; i < ARRAY_SIZE(sticky_test_values); i++) {
+ test = sticky_test_values[i];
+ if (test == saved)
+ continue;
+ /* Assume non-sticky on failure. */
+ if (snd_usb_set_cur_mix_value(cval, minchn, 0, test) ||
+ get_cur_mix_raw(cval, minchn, &check) ||
+ check != saved) { /* SET_CUR effective, non-sticky. */
+ effective = true;
+ break;
+ }
+ }
+ if (!effective) {
+ usb_audio_warn(cval->head.mixer->chip,
+ "%d:%d: sticky mixer values (%d/%d/%d => %d), disabling\n",
+ cval->head.id, mixer_ctrl_intf(cval->head.mixer),
+ cval->min, cval->max, cval->res, saved);
+
+ cval->initialized = 1;
+ cval->min = cval->max = cval->res = 0;
+ return -ENODEV;
+ }
+
+ if (cval->min + cval->res >= cval->max)
+ goto no_res_check;
for (;;) {
test = saved;
if (test < cval->max)
--
2.53.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 2/2] ALSA: usb-audio: Do not expose sticky volume control mixers
2026-04-08 18:33 ` [PATCH 2/2] ALSA: usb-audio: Do not expose sticky volume control mixers Rong Zhang
@ 2026-04-09 7:08 ` Takashi Iwai
2026-04-09 14:20 ` Rong Zhang
0 siblings, 1 reply; 8+ messages in thread
From: Takashi Iwai @ 2026-04-09 7:08 UTC (permalink / raw)
To: Rong Zhang
Cc: Jaroslav Kysela, Takashi Iwai, linux-sound, linux-kernel,
Icenowy Zheng
On Wed, 08 Apr 2026 20:33:06 +0200,
Rong Zhang wrote:
>
> Some devices expose sticky mixers that accept SET_CUR but do absolutely
> nothing. Registering mixers for them confuses userspace and results in
> ineffective volume control.
>
> Check if the volume control is sticky by setting the volume to the
> maximum or minimum value, and prevent the mixer from being registered
> accordingly.
>
> Quirky device sample:
>
> usb 7-1: New USB device found, idVendor=0e0b, idProduct=fa01, bcdDevice= 1.00
> usb 7-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
> usb 7-1: Product: Feaulle Rainbow
> usb 7-1: Manufacturer: Generic
> usb 7-1: SerialNumber: 20210726905926
> (Mic Capture Volume)
>
> Signed-off-by: Rong Zhang <i@rong.moe>
> ---
> sound/usb/mixer.c | 37 +++++++++++++++++++++++++++++++++++--
> 1 file changed, 35 insertions(+), 2 deletions(-)
>
> diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
> index a25e8145af67..9f0aed36e27d 100644
> --- a/sound/usb/mixer.c
> +++ b/sound/usb/mixer.c
> @@ -27,6 +27,7 @@
> * - parse available sample rates again when clock sources changed
> */
>
> +#include <linux/array_size.h>
It's only for ARRAY_SIZE()? Then no need for extra inclusion. It's
already included by others.
> #include <linux/bitops.h>
> #include <linux/init.h>
> #include <linux/list.h>
> @@ -1287,17 +1288,49 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval,
> if (cval->res == 0)
> cval->res = 1;
>
> - /* Additional checks for the proper resolution
> + /* Additional checks
> + *
> + * Some devices expose sticky mixers that accept SET_CUR
> + * but do absolutely nothing.
> *
> * Some devices report smaller resolutions than actually
> * reacting. They don't return errors but simply clip
> * to the lower aligned value.
> */
> - if (cval->min + cval->res < cval->max) {
> + if (cval->min < cval->max) {
> + int sticky_test_values[] = { cval->min, cval->max };
> int last_valid_res = cval->res;
> int saved, test, check;
> + bool effective = false;
> +
> if (get_cur_mix_raw(cval, minchn, &saved) < 0)
> goto no_res_check;
> +
> + for (i = 0; i < ARRAY_SIZE(sticky_test_values); i++) {
> + test = sticky_test_values[i];
> + if (test == saved)
> + continue;
> + /* Assume non-sticky on failure. */
> + if (snd_usb_set_cur_mix_value(cval, minchn, 0, test) ||
> + get_cur_mix_raw(cval, minchn, &check) ||
> + check != saved) { /* SET_CUR effective, non-sticky. */
> + effective = true;
> + break;
> + }
> + }
> + if (!effective) {
> + usb_audio_warn(cval->head.mixer->chip,
> + "%d:%d: sticky mixer values (%d/%d/%d => %d), disabling\n",
> + cval->head.id, mixer_ctrl_intf(cval->head.mixer),
> + cval->min, cval->max, cval->res, saved);
> +
> + cval->initialized = 1;
> + cval->min = cval->max = cval->res = 0;
> + return -ENODEV;
> + }
> +
> + if (cval->min + cval->res >= cval->max)
> + goto no_res_check;
Hm, it's quite lots of changes, and I'd like this to be factored out
as a function instead. Maybe the resolution check code could be moved
into a function, too; get_min_max_with_quirks() is too lengthy.
Also, note that currently there is no error check for get_min_max*().
Your code works just because you set cval->min = cval->max, and there
is an additional check at a later point of this.
Ideally speaking, we should have an error check to explicitly handle a
case like this. But the current code allows the error at init, at
least, we tolerate the errors at reading UAC_GET_MIN and _MAX. So, if
any, the error check would need to evaluate the error number and
ignore -EINVAL or such...
thanks,
Takashi
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/2] ALSA: usb-audio: Do not expose sticky volume control mixers
2026-04-09 7:08 ` Takashi Iwai
@ 2026-04-09 14:20 ` Rong Zhang
2026-04-09 14:36 ` Takashi Iwai
0 siblings, 1 reply; 8+ messages in thread
From: Rong Zhang @ 2026-04-09 14:20 UTC (permalink / raw)
To: Takashi Iwai
Cc: Jaroslav Kysela, Takashi Iwai, linux-sound, linux-kernel,
Icenowy Zheng
Hi Takashi,
Thanks for your review.
On Thu, 2026-04-09 at 09:08 +0200, Takashi Iwai wrote:
> On Wed, 08 Apr 2026 20:33:06 +0200,
> Rong Zhang wrote:
> >
> > Some devices expose sticky mixers that accept SET_CUR but do absolutely
> > nothing. Registering mixers for them confuses userspace and results in
> > ineffective volume control.
> >
> > Check if the volume control is sticky by setting the volume to the
> > maximum or minimum value, and prevent the mixer from being registered
> > accordingly.
> >
> > Quirky device sample:
> >
> > usb 7-1: New USB device found, idVendor=0e0b, idProduct=fa01, bcdDevice= 1.00
> > usb 7-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
> > usb 7-1: Product: Feaulle Rainbow
> > usb 7-1: Manufacturer: Generic
> > usb 7-1: SerialNumber: 20210726905926
> > (Mic Capture Volume)
> >
> > Signed-off-by: Rong Zhang <i@rong.moe>
> > ---
> > sound/usb/mixer.c | 37 +++++++++++++++++++++++++++++++++++--
> > 1 file changed, 35 insertions(+), 2 deletions(-)
> >
> > diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
> > index a25e8145af67..9f0aed36e27d 100644
> > --- a/sound/usb/mixer.c
> > +++ b/sound/usb/mixer.c
> > @@ -27,6 +27,7 @@
> > * - parse available sample rates again when clock sources changed
> > */
> >
> > +#include <linux/array_size.h>
>
> It's only for ARRAY_SIZE()? Then no need for extra inclusion. It's
> already included by others.
>
> > #include <linux/bitops.h>
> > #include <linux/init.h>
> > #include <linux/list.h>
> > @@ -1287,17 +1288,49 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval,
> > if (cval->res == 0)
> > cval->res = 1;
> >
> > - /* Additional checks for the proper resolution
> > + /* Additional checks
> > + *
> > + * Some devices expose sticky mixers that accept SET_CUR
> > + * but do absolutely nothing.
> > *
> > * Some devices report smaller resolutions than actually
> > * reacting. They don't return errors but simply clip
> > * to the lower aligned value.
> > */
> > - if (cval->min + cval->res < cval->max) {
> > + if (cval->min < cval->max) {
> > + int sticky_test_values[] = { cval->min, cval->max };
> > int last_valid_res = cval->res;
> > int saved, test, check;
> > + bool effective = false;
> > +
> > if (get_cur_mix_raw(cval, minchn, &saved) < 0)
> > goto no_res_check;
> > +
> > + for (i = 0; i < ARRAY_SIZE(sticky_test_values); i++) {
> > + test = sticky_test_values[i];
> > + if (test == saved)
> > + continue;
> > + /* Assume non-sticky on failure. */
> > + if (snd_usb_set_cur_mix_value(cval, minchn, 0, test) ||
> > + get_cur_mix_raw(cval, minchn, &check) ||
> > + check != saved) { /* SET_CUR effective, non-sticky. */
> > + effective = true;
> > + break;
> > + }
> > + }
> > + if (!effective) {
> > + usb_audio_warn(cval->head.mixer->chip,
> > + "%d:%d: sticky mixer values (%d/%d/%d => %d), disabling\n",
> > + cval->head.id, mixer_ctrl_intf(cval->head.mixer),
> > + cval->min, cval->max, cval->res, saved);
> > +
> > + cval->initialized = 1;
> > + cval->min = cval->max = cval->res = 0;
> > + return -ENODEV;
> > + }
> > +
> > + if (cval->min + cval->res >= cval->max)
> > + goto no_res_check;
>
> Hm, it's quite lots of changes, and I'd like this to be factored out
> as a function instead. Maybe the resolution check code could be moved
> into a function, too; get_min_max_with_quirks() is too lengthy.
Sure, I will refactor the current code path beforehand when I resubmit
this.
Hmm, does patch 1 make sense to you? If so, I would be grateful if you
could you apply it separately so that I can send a new series solely
focusing on refactoring and adding the sticky mixer check.
>
> Also, note that currently there is no error check for get_min_max*().
> Your code works just because you set cval->min = cval->max, and there
> is an additional check at a later point of this.
>
> Ideally speaking, we should have an error check to explicitly handle a
> case like this. But the current code allows the error at init, at
> least, we tolerate the errors at reading UAC_GET_MIN and _MAX. So, if
> any, the error check would need to evaluate the error number and
> ignore -EINVAL or such...
Makes sense, I will address it beforehand when I resubmit this.
BTW, how about checking against -ENODEV instead? It can be considered to
be an indication that the caller should not register the mixer and is
much more readable. I don't have a strong preference for this though,
and ignoring -EINVAL also makes sense to me.
Thanks,
Rong
>
>
> thanks,
>
> Takashi
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/2] ALSA: usb-audio: Do not expose sticky volume control mixers
2026-04-09 14:20 ` Rong Zhang
@ 2026-04-09 14:36 ` Takashi Iwai
2026-04-09 15:07 ` Rong Zhang
0 siblings, 1 reply; 8+ messages in thread
From: Takashi Iwai @ 2026-04-09 14:36 UTC (permalink / raw)
To: Rong Zhang
Cc: Takashi Iwai, Jaroslav Kysela, Takashi Iwai, linux-sound,
linux-kernel, Icenowy Zheng
On Thu, 09 Apr 2026 16:20:30 +0200,
Rong Zhang wrote:
>
> Hi Takashi,
>
> Thanks for your review.
>
> On Thu, 2026-04-09 at 09:08 +0200, Takashi Iwai wrote:
> > On Wed, 08 Apr 2026 20:33:06 +0200,
> > Rong Zhang wrote:
> > >
> > > Some devices expose sticky mixers that accept SET_CUR but do absolutely
> > > nothing. Registering mixers for them confuses userspace and results in
> > > ineffective volume control.
> > >
> > > Check if the volume control is sticky by setting the volume to the
> > > maximum or minimum value, and prevent the mixer from being registered
> > > accordingly.
> > >
> > > Quirky device sample:
> > >
> > > usb 7-1: New USB device found, idVendor=0e0b, idProduct=fa01, bcdDevice= 1.00
> > > usb 7-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
> > > usb 7-1: Product: Feaulle Rainbow
> > > usb 7-1: Manufacturer: Generic
> > > usb 7-1: SerialNumber: 20210726905926
> > > (Mic Capture Volume)
> > >
> > > Signed-off-by: Rong Zhang <i@rong.moe>
> > > ---
> > > sound/usb/mixer.c | 37 +++++++++++++++++++++++++++++++++++--
> > > 1 file changed, 35 insertions(+), 2 deletions(-)
> > >
> > > diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
> > > index a25e8145af67..9f0aed36e27d 100644
> > > --- a/sound/usb/mixer.c
> > > +++ b/sound/usb/mixer.c
> > > @@ -27,6 +27,7 @@
> > > * - parse available sample rates again when clock sources changed
> > > */
> > >
> > > +#include <linux/array_size.h>
> >
> > It's only for ARRAY_SIZE()? Then no need for extra inclusion. It's
> > already included by others.
> >
> > > #include <linux/bitops.h>
> > > #include <linux/init.h>
> > > #include <linux/list.h>
> > > @@ -1287,17 +1288,49 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval,
> > > if (cval->res == 0)
> > > cval->res = 1;
> > >
> > > - /* Additional checks for the proper resolution
> > > + /* Additional checks
> > > + *
> > > + * Some devices expose sticky mixers that accept SET_CUR
> > > + * but do absolutely nothing.
> > > *
> > > * Some devices report smaller resolutions than actually
> > > * reacting. They don't return errors but simply clip
> > > * to the lower aligned value.
> > > */
> > > - if (cval->min + cval->res < cval->max) {
> > > + if (cval->min < cval->max) {
> > > + int sticky_test_values[] = { cval->min, cval->max };
> > > int last_valid_res = cval->res;
> > > int saved, test, check;
> > > + bool effective = false;
> > > +
> > > if (get_cur_mix_raw(cval, minchn, &saved) < 0)
> > > goto no_res_check;
> > > +
> > > + for (i = 0; i < ARRAY_SIZE(sticky_test_values); i++) {
> > > + test = sticky_test_values[i];
> > > + if (test == saved)
> > > + continue;
> > > + /* Assume non-sticky on failure. */
> > > + if (snd_usb_set_cur_mix_value(cval, minchn, 0, test) ||
> > > + get_cur_mix_raw(cval, minchn, &check) ||
> > > + check != saved) { /* SET_CUR effective, non-sticky. */
> > > + effective = true;
> > > + break;
> > > + }
> > > + }
> > > + if (!effective) {
> > > + usb_audio_warn(cval->head.mixer->chip,
> > > + "%d:%d: sticky mixer values (%d/%d/%d => %d), disabling\n",
> > > + cval->head.id, mixer_ctrl_intf(cval->head.mixer),
> > > + cval->min, cval->max, cval->res, saved);
> > > +
> > > + cval->initialized = 1;
> > > + cval->min = cval->max = cval->res = 0;
> > > + return -ENODEV;
> > > + }
> > > +
> > > + if (cval->min + cval->res >= cval->max)
> > > + goto no_res_check;
> >
> > Hm, it's quite lots of changes, and I'd like this to be factored out
> > as a function instead. Maybe the resolution check code could be moved
> > into a function, too; get_min_max_with_quirks() is too lengthy.
>
> Sure, I will refactor the current code path beforehand when I resubmit
> this.
>
> Hmm, does patch 1 make sense to you? If so, I would be grateful if you
> could you apply it separately so that I can send a new series solely
> focusing on refactoring and adding the sticky mixer check.
OK, I'm going to apply only the first patch now.
> >
> > Also, note that currently there is no error check for get_min_max*().
> > Your code works just because you set cval->min = cval->max, and there
> > is an additional check at a later point of this.
> >
> > Ideally speaking, we should have an error check to explicitly handle a
> > case like this. But the current code allows the error at init, at
> > least, we tolerate the errors at reading UAC_GET_MIN and _MAX. So, if
> > any, the error check would need to evaluate the error number and
> > ignore -EINVAL or such...
>
> Makes sense, I will address it beforehand when I resubmit this.
>
> BTW, how about checking against -ENODEV instead? It can be considered to
> be an indication that the caller should not register the mixer and is
> much more readable. I don't have a strong preference for this though,
> and ignoring -EINVAL also makes sense to me.
The -EINVAL could be a temporary error at the probe time, and there
were cases where the later read works. I meant the code:
if (get_ctl_value(cval, UAC_GET_MAX, (cval->control << 8) | minchn, &cval->max) < 0 ||
get_ctl_value(cval, UAC_GET_MIN, (cval->control << 8) | minchn, &cval->min) < 0) {
usb_audio_err(cval->head.mixer->chip,
"%d:%d: cannot get min/max values for control %d (id %d)\n",
cval->head.id, mixer_ctrl_intf(cval->head.mixer),
cval->control, cval->head.id);
return -EINVAL;
}
... and maybe -EINVAL isn't really a good sign, but better to replace
with -EAGAIN. Then continuing after -EAGAIN in the caller side would
become more logical.
thanks,
Takashi
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 1/2] ALSA: usb-audio: Add quirk flags for Feaulle Rainbow
2026-04-08 18:33 ` [PATCH 1/2] ALSA: usb-audio: Add quirk flags " Rong Zhang
@ 2026-04-09 14:38 ` Takashi Iwai
0 siblings, 0 replies; 8+ messages in thread
From: Takashi Iwai @ 2026-04-09 14:38 UTC (permalink / raw)
To: Rong Zhang
Cc: Jaroslav Kysela, Takashi Iwai, linux-sound, linux-kernel,
Icenowy Zheng
On Wed, 08 Apr 2026 20:33:05 +0200,
Rong Zhang wrote:
>
> Feaulle Rainbow is a wired USB-C dynamic in-ear monitor (IEM) featuring
> active noise cancellation (ANC).
>
> The supported sample rates are 48000Hz and 96000Hz at 16bit or 24bit,
> but it does not support reading the current sample rate and results in
> an error message printed to kmsg. Set QUIRK_FLAG_GET_SAMPLE_RATE to skip
> the sample rate check.
>
> Its playback mixer reports val = -15360/0/128. Setting -15360 (-60dB)
> mutes the playback, so QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE is needed.
>
> Add a quirk table entry matching VID/PID=0x0e0b/0xfa01 and applying
> the mentioned quirk flags, so that it can work properly.
>
> Quirky device sample:
>
> usb 7-1: New USB device found, idVendor=0e0b, idProduct=fa01, bcdDevice= 1.00
> usb 7-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
> usb 7-1: Product: Feaulle Rainbow
> usb 7-1: Manufacturer: Generic
> usb 7-1: SerialNumber: 20210726905926
>
> Signed-off-by: Rong Zhang <i@rong.moe>
Now applied only this one to for-next branch.
thanks,
Takashi
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/2] ALSA: usb-audio: Do not expose sticky volume control mixers
2026-04-09 14:36 ` Takashi Iwai
@ 2026-04-09 15:07 ` Rong Zhang
0 siblings, 0 replies; 8+ messages in thread
From: Rong Zhang @ 2026-04-09 15:07 UTC (permalink / raw)
To: Takashi Iwai
Cc: Jaroslav Kysela, Takashi Iwai, linux-sound, linux-kernel,
Icenowy Zheng
Hi Takashi,
On Thu, 2026-04-09 at 16:36 +0200, Takashi Iwai wrote:
> On Thu, 09 Apr 2026 16:20:30 +0200,
> Rong Zhang wrote:
> >
> > Hi Takashi,
> >
> > Thanks for your review.
> >
> > On Thu, 2026-04-09 at 09:08 +0200, Takashi Iwai wrote:
> > > On Wed, 08 Apr 2026 20:33:06 +0200,
> > > Rong Zhang wrote:
> > > >
> > > > Some devices expose sticky mixers that accept SET_CUR but do absolutely
> > > > nothing. Registering mixers for them confuses userspace and results in
> > > > ineffective volume control.
> > > >
> > > > Check if the volume control is sticky by setting the volume to the
> > > > maximum or minimum value, and prevent the mixer from being registered
> > > > accordingly.
> > > >
> > > > Quirky device sample:
> > > >
> > > > usb 7-1: New USB device found, idVendor=0e0b, idProduct=fa01, bcdDevice= 1.00
> > > > usb 7-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
> > > > usb 7-1: Product: Feaulle Rainbow
> > > > usb 7-1: Manufacturer: Generic
> > > > usb 7-1: SerialNumber: 20210726905926
> > > > (Mic Capture Volume)
> > > >
> > > > Signed-off-by: Rong Zhang <i@rong.moe>
> > > > ---
> > > > sound/usb/mixer.c | 37 +++++++++++++++++++++++++++++++++++--
> > > > 1 file changed, 35 insertions(+), 2 deletions(-)
> > > >
> > > > diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
> > > > index a25e8145af67..9f0aed36e27d 100644
> > > > --- a/sound/usb/mixer.c
> > > > +++ b/sound/usb/mixer.c
> > > > @@ -27,6 +27,7 @@
> > > > * - parse available sample rates again when clock sources changed
> > > > */
> > > >
> > > > +#include <linux/array_size.h>
> > >
> > > It's only for ARRAY_SIZE()? Then no need for extra inclusion. It's
> > > already included by others.
> > >
> > > > #include <linux/bitops.h>
> > > > #include <linux/init.h>
> > > > #include <linux/list.h>
> > > > @@ -1287,17 +1288,49 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval,
> > > > if (cval->res == 0)
> > > > cval->res = 1;
> > > >
> > > > - /* Additional checks for the proper resolution
> > > > + /* Additional checks
> > > > + *
> > > > + * Some devices expose sticky mixers that accept SET_CUR
> > > > + * but do absolutely nothing.
> > > > *
> > > > * Some devices report smaller resolutions than actually
> > > > * reacting. They don't return errors but simply clip
> > > > * to the lower aligned value.
> > > > */
> > > > - if (cval->min + cval->res < cval->max) {
> > > > + if (cval->min < cval->max) {
> > > > + int sticky_test_values[] = { cval->min, cval->max };
> > > > int last_valid_res = cval->res;
> > > > int saved, test, check;
> > > > + bool effective = false;
> > > > +
> > > > if (get_cur_mix_raw(cval, minchn, &saved) < 0)
> > > > goto no_res_check;
> > > > +
> > > > + for (i = 0; i < ARRAY_SIZE(sticky_test_values); i++) {
> > > > + test = sticky_test_values[i];
> > > > + if (test == saved)
> > > > + continue;
> > > > + /* Assume non-sticky on failure. */
> > > > + if (snd_usb_set_cur_mix_value(cval, minchn, 0, test) ||
> > > > + get_cur_mix_raw(cval, minchn, &check) ||
> > > > + check != saved) { /* SET_CUR effective, non-sticky. */
> > > > + effective = true;
> > > > + break;
> > > > + }
> > > > + }
> > > > + if (!effective) {
> > > > + usb_audio_warn(cval->head.mixer->chip,
> > > > + "%d:%d: sticky mixer values (%d/%d/%d => %d), disabling\n",
> > > > + cval->head.id, mixer_ctrl_intf(cval->head.mixer),
> > > > + cval->min, cval->max, cval->res, saved);
> > > > +
> > > > + cval->initialized = 1;
> > > > + cval->min = cval->max = cval->res = 0;
> > > > + return -ENODEV;
> > > > + }
> > > > +
> > > > + if (cval->min + cval->res >= cval->max)
> > > > + goto no_res_check;
> > >
> > > Hm, it's quite lots of changes, and I'd like this to be factored out
> > > as a function instead. Maybe the resolution check code could be moved
> > > into a function, too; get_min_max_with_quirks() is too lengthy.
> >
> > Sure, I will refactor the current code path beforehand when I resubmit
> > this.
> >
> > Hmm, does patch 1 make sense to you? If so, I would be grateful if you
> > could you apply it separately so that I can send a new series solely
> > focusing on refactoring and adding the sticky mixer check.
>
> OK, I'm going to apply only the first patch now.
Thanks a lot!
>
> > >
> > > Also, note that currently there is no error check for get_min_max*().
> > > Your code works just because you set cval->min = cval->max, and there
> > > is an additional check at a later point of this.
> > >
> > > Ideally speaking, we should have an error check to explicitly handle a
> > > case like this. But the current code allows the error at init, at
> > > least, we tolerate the errors at reading UAC_GET_MIN and _MAX. So, if
> > > any, the error check would need to evaluate the error number and
> > > ignore -EINVAL or such...
> >
> > Makes sense, I will address it beforehand when I resubmit this.
> >
> > BTW, how about checking against -ENODEV instead? It can be considered to
> > be an indication that the caller should not register the mixer and is
> > much more readable. I don't have a strong preference for this though,
> > and ignoring -EINVAL also makes sense to me.
>
> The -EINVAL could be a temporary error at the probe time, and there
> were cases where the later read works. I meant the code:
>
> if (get_ctl_value(cval, UAC_GET_MAX, (cval->control << 8) | minchn, &cval->max) < 0 ||
> get_ctl_value(cval, UAC_GET_MIN, (cval->control << 8) | minchn, &cval->min) < 0) {
> usb_audio_err(cval->head.mixer->chip,
> "%d:%d: cannot get min/max values for control %d (id %d)\n",
> cval->head.id, mixer_ctrl_intf(cval->head.mixer),
> cval->control, cval->head.id);
> return -EINVAL;
> }
>
> ... and maybe -EINVAL isn't really a good sign, but better to replace
> with -EAGAIN. Then continuing after -EAGAIN in the caller side would
> become more logical.
Thanks for your detailed explanation. It makes sense. I will refactor
the code path to return -EAGAIN and make callers ignore it when I
resubmit this.
Thanks,
Rong
>
>
> thanks,
>
> Takashi
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-04-09 15:13 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-08 18:33 [PATCH 0/2] ALSA: usb-audio: Support for Feaulle Rainbow Rong Zhang
2026-04-08 18:33 ` [PATCH 1/2] ALSA: usb-audio: Add quirk flags " Rong Zhang
2026-04-09 14:38 ` Takashi Iwai
2026-04-08 18:33 ` [PATCH 2/2] ALSA: usb-audio: Do not expose sticky volume control mixers Rong Zhang
2026-04-09 7:08 ` Takashi Iwai
2026-04-09 14:20 ` Rong Zhang
2026-04-09 14:36 ` Takashi Iwai
2026-04-09 15:07 ` Rong Zhang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox