Skip to content

Commit ad2c7d2

Browse files
Rongronggg9tiwai
authored andcommitted
ALSA: usb-audio: Add QUIRK_FLAG_MIXER_GET_CUR_BROKEN
Since commit 86aa1ea ("ALSA: usb-audio: Do not expose sticky mixers"), the UAC mixer core utilizes volume SET_CUR and GET_CUR to identify devices with sticky mixers. Unfortunately, even though most devices with sticky GET_CUR also have corresponding sticky SET_CUR, which I actually met more since the commit had been merged, there is also a rare case that some devices may have volume mixers that responds to SET_CUR properly but with its GET_CUR stubbed. This cause the sticky check to consider the mixer to be sticky and unnecessarily disable it. As the sticky check can't distinguish between sticky mixers and working SET_CUR but broken GET_CUR, add QUIRK_FLAG_MIXER_GET_CUR_BROKEN to tell that the device should fall into the second category when GET_CUR returns a constant value. In this case, the sticky check becomes non-fatal and only disables GET_CUR instead of the whole mixer. The current volume will then be provided by the internal cache that stores the last set volume. An info message prompting users to check MIXER_GET_CUR_BROKEN for potential sticky mixers is also added, so that users can learn how to do some experiments to determine what's going on. If the mixer surprisingly turns out to be non-sticky, they can submit a patch for a new quirk table entry. Signed-off-by: Rong Zhang <i@rong.moe> Signed-off-by: Takashi Iwai <tiwai@suse.de> Link: https://patch.msgid.link/20260531-uac-quirk-get-cur-vol-v4-1-ede643dca151@rong.moe
1 parent f52b1b0 commit ad2c7d2

5 files changed

Lines changed: 77 additions & 10 deletions

File tree

Documentation/sound/alsa-configuration.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2389,6 +2389,18 @@ quirk_flags
23892389
from snd_usb_handle_sync_urb. Instead fall through and enqueue a
23902390
packet_info containing only size-0 packets, so the OUT ring keeps
23912391
moving (emits silence). Needed by Behringer Flow 8 (1397:050c).
2392+
* bit 30: ``mixer_get_cur_broken``
2393+
Some mixers are sticky, which means that setting their current volume
2394+
is a no-op, and reading the current volume returns a constant value.
2395+
The sticky check disables these mixers to prevent confusing userspace.
2396+
However, some devices do have a tunable volume despite the reported
2397+
current volume being constant. As the sticky check can't distinguish
2398+
between the two categories, setting this flag tells that the device
2399+
should fall into the second category when GET_CUR returns a constant
2400+
value, resulting in the sticky check being non-fatal and only
2401+
disabling GET_CUR instead of the whole mixer. The current volume will
2402+
then be provided by the internal cache that stores the last set
2403+
volume
23922404

23932405
This module supports multiple devices, autoprobe and hotplugging.
23942406

sound/usb/mixer.c

Lines changed: 50 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,11 @@ int snd_usb_get_cur_mix_value(struct usb_mixer_elem_info *cval,
434434
*value = cval->cache_val[index];
435435
return 0;
436436
}
437+
438+
/* The current value is always provided by the cache after initialization. */
439+
if (cval->get_cur_broken)
440+
return -ENXIO;
441+
437442
err = get_cur_mix_raw(cval, channel, value);
438443
if (err < 0) {
439444
if (!cval->head.mixer->ignore_ctl_error)
@@ -1223,7 +1228,7 @@ static void init_cur_mix_raw(struct usb_mixer_elem_info *cval, int ch, int idx)
12231228
err = snd_usb_get_cur_mix_value(cval, ch, idx, &val);
12241229
if (!err)
12251230
return;
1226-
if (!cval->head.mixer->ignore_ctl_error)
1231+
if (!cval->head.mixer->ignore_ctl_error && !cval->get_cur_broken)
12271232
usb_audio_warn(cval->head.mixer->chip,
12281233
"%d:%d: failed to get current value for ch %d (%d)\n",
12291234
cval->head.id, mixer_ctrl_intf(cval->head.mixer),
@@ -1237,8 +1242,16 @@ static void init_cur_mix_raw(struct usb_mixer_elem_info *cval, int ch, int idx)
12371242
* Some devices' volume control mixers are sticky, which accept SET_CUR but
12381243
* do absolutely nothing.
12391244
*
1240-
* Prevent sticky mixers from being registered, otherwise they confuses
1241-
* userspace and results in ineffective volume control.
1245+
* Check the return values of GET_CUR with different SET_CUR values. Consider
1246+
* the mixer as sticky if GET_CUR always returns a constant value.
1247+
*
1248+
* Some devices have effective SET_CUR despite GET_CUR being constant. Do not
1249+
* consider the mixer as sticky if a quirk flag indicates that.
1250+
*
1251+
* Gate the registration of sticky mixers to prevent confusing userspace, so
1252+
* that they won't cause ineffective volume control. However, for mixers with
1253+
* effective SET_CUR but broken GET_CUR, the registration can continue normally
1254+
* but further GET_CUR requests will be gated.
12421255
*/
12431256
static int check_sticky_volume_control(struct usb_mixer_elem_info *cval,
12441257
int channel, int saved)
@@ -1258,10 +1271,22 @@ static int check_sticky_volume_control(struct usb_mixer_elem_info *cval,
12581271
return 0;
12591272
}
12601273

1274+
if (cval->head.mixer->chip->quirk_flags & QUIRK_FLAG_MIXER_GET_CUR_BROKEN) {
1275+
usb_audio_info(cval->head.mixer->chip,
1276+
"%d:%d: broken mixer GET_CUR (%d/%d/%d => %d)\n",
1277+
cval->head.id, mixer_ctrl_intf(cval->head.mixer),
1278+
cval->min, cval->max, cval->res, saved);
1279+
1280+
cval->get_cur_broken = 1;
1281+
return -ENXIO;
1282+
}
1283+
12611284
usb_audio_err(cval->head.mixer->chip,
12621285
"%d:%d: sticky mixer values (%d/%d/%d => %d), disabling\n",
12631286
cval->head.id, mixer_ctrl_intf(cval->head.mixer),
12641287
cval->min, cval->max, cval->res, saved);
1288+
usb_audio_info(cval->head.mixer->chip,
1289+
"check MIXER_GET_CUR_BROKEN if you believe the mixer is non-sticky");
12651290

12661291
return -ENODEV;
12671292
}
@@ -1304,7 +1329,7 @@ static void check_volume_control_res(struct usb_mixer_elem_info *cval,
13041329
static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval,
13051330
int default_min, struct snd_kcontrol *kctl)
13061331
{
1307-
int i, idx, ret;
1332+
int i, idx, ret = 0;
13081333

13091334
/* for failsafe */
13101335
cval->min = default_min;
@@ -1360,8 +1385,10 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval,
13601385
goto no_checks;
13611386

13621387
ret = check_sticky_volume_control(cval, minchn, saved);
1363-
if (ret < 0)
1388+
if (ret == -ENODEV)
13641389
goto sticky;
1390+
if (ret)
1391+
goto no_checks;
13651392

13661393
if (cval->min + cval->res < cval->max)
13671394
check_volume_control_res(cval, minchn, saved);
@@ -1370,6 +1397,16 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval,
13701397
}
13711398

13721399
no_checks:
1400+
/*
1401+
* Got a non-fatal failure during sanity checks.
1402+
*
1403+
* Do not propagate mixer values written by sanity checks.
1404+
* Instead, rely on init_cur_mix_raw() to initialize the mixer
1405+
* properly.
1406+
*/
1407+
if (ret)
1408+
cval->cached = 0;
1409+
13731410
cval->initialized = 1;
13741411
}
13751412

@@ -3538,7 +3575,8 @@ void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, int unitid)
35383575
continue;
35393576
info = mixer_elem_list_to_info(list);
35403577
/* invalidate cache, so the value is read from the device */
3541-
info->cached = 0;
3578+
if (!info->get_cur_broken)
3579+
info->cached = 0;
35423580
snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
35433581
&list->kctl->id);
35443582
}
@@ -3635,10 +3673,12 @@ static void snd_usb_mixer_interrupt_v2(struct usb_mixer_interface *mixer,
36353673
switch (attribute) {
36363674
case UAC2_CS_CUR:
36373675
/* invalidate cache, so the value is read from the device */
3638-
if (channel)
3639-
info->cached &= ~BIT(channel);
3640-
else /* master channel */
3641-
info->cached = 0;
3676+
if (!info->get_cur_broken) {
3677+
if (channel)
3678+
info->cached &= ~BIT(channel);
3679+
else /* master channel */
3680+
info->cached = 0;
3681+
}
36423682

36433683
snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
36443684
&info->head.kctl->id);

sound/usb/mixer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ struct usb_mixer_elem_info {
9494
int cache_val[MAX_CHANNELS];
9595
u8 initialized;
9696
u8 min_mute;
97+
u8 get_cur_broken;
9798
void *private_data;
9899
};
99100

sound/usb/quirks.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2607,6 +2607,7 @@ static const char *const snd_usb_audio_quirk_flag_names[] = {
26072607
QUIRK_STRING_ENTRY(MIXER_PLAYBACK_LINEAR_VOL),
26082608
QUIRK_STRING_ENTRY(MIXER_CAPTURE_LINEAR_VOL),
26092609
QUIRK_STRING_ENTRY(IFB_SILENCE_ON_EMPTY),
2610+
QUIRK_STRING_ENTRY(MIXER_GET_CUR_BROKEN),
26102611
NULL
26112612
};
26122613

sound/usb/usbaudio.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,17 @@ extern bool snd_usb_skip_validation;
242242
* from snd_usb_handle_sync_urb. Instead fall through and enqueue a
243243
* packet_info containing only size-0 packets, so the OUT ring keeps
244244
* moving (emits silence). Needed by Behringer Flow 8 (1397:050c).
245+
* QUIRK_FLAG_MIXER_GET_CUR_BROKEN
246+
* Some mixers are sticky, which means that setting their current volume is a
247+
* no-op, and reading the current volume returns a constant value. The sticky
248+
* check disables these mixers to prevent confusing userspace. However, some
249+
* devices do have a tunable volume despite the reported current volume being
250+
* constant. As the sticky check can't distinguish between the two categories,
251+
* setting this flag tells that the device should fall into the second
252+
* category when GET_CUR returns a constant value, resulting in the sticky
253+
* check being non-fatal and only disabling GET_CUR instead of the whole mixer.
254+
* The current volume will then be provided by the internal cache that stores
255+
* the last set volume
245256
*/
246257

247258
enum {
@@ -275,6 +286,7 @@ enum {
275286
QUIRK_TYPE_MIXER_PLAYBACK_LINEAR_VOL = 27,
276287
QUIRK_TYPE_MIXER_CAPTURE_LINEAR_VOL = 28,
277288
QUIRK_TYPE_IFB_SILENCE_ON_EMPTY = 29,
289+
QUIRK_TYPE_MIXER_GET_CUR_BROKEN = 30,
278290
/* Please also edit snd_usb_audio_quirk_flag_names */
279291
};
280292

@@ -310,5 +322,6 @@ enum {
310322
#define QUIRK_FLAG_MIXER_PLAYBACK_LINEAR_VOL QUIRK_FLAG(MIXER_PLAYBACK_LINEAR_VOL)
311323
#define QUIRK_FLAG_MIXER_CAPTURE_LINEAR_VOL QUIRK_FLAG(MIXER_CAPTURE_LINEAR_VOL)
312324
#define QUIRK_FLAG_IFB_SILENCE_ON_EMPTY QUIRK_FLAG(IFB_SILENCE_ON_EMPTY)
325+
#define QUIRK_FLAG_MIXER_GET_CUR_BROKEN QUIRK_FLAG(MIXER_GET_CUR_BROKEN)
313326

314327
#endif /* __USBAUDIO_H */

0 commit comments

Comments
 (0)