Skip to content

Commit 3787a6a

Browse files
Rongronggg9tiwai
authored andcommitted
ALSA: usb-audio: Add QUIRK_FLAG_MIXER_{PLAYBACK,CAPTURE}_LINEAR_VOL
Some quirky devices tune their volume by linearly tuning the voltage level (linear volume). In other words, such devices has a linear TLV mapping of DECLARE_TLV_DB_LINEAR(scale, TLV_DB_GAIN_MUTE, 0). Add quirk flags MIXER_PLAYBACK_LINEAR_VOL and MIXER_CAPTURE_LINEAR_VOL to represent this case respectively for playback and capture mixers. No functional change intended. Signed-off-by: Rong Zhang <i@rong.moe> Signed-off-by: Takashi Iwai <tiwai@suse.de> Link: https://patch.msgid.link/20260303194805.266158-7-i@rong.moe
1 parent b13031c commit 3787a6a

4 files changed

Lines changed: 55 additions & 0 deletions

File tree

Documentation/sound/alsa-configuration.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2376,6 +2376,13 @@ quirk_flags
23762376
Skip the probe-time interface setup (usb_set_interface,
23772377
init_pitch, init_sample_rate); redundant with
23782378
snd_usb_endpoint_prepare() at stream-open time
2379+
* bit 27: ``mixer_playback_linear_vol``
2380+
Set linear volume mapping for devices where the playback volume
2381+
control value is mapped to voltage (instead of dB) level linearly.
2382+
In short: ``x(raw) = (raw - raw_min) / (raw_max - raw_min)``;
2383+
``V(x) = k * x``; ``dB(x) = 20 * log10(x)``. Overrides bit 24
2384+
* bit 28: ``mixer_capture_linear_vol``
2385+
Similar to bit 27 but for capture streams. Overrides bit 25
23792386

23802387
This module supports multiple devices, autoprobe and hotplugging.
23812388

sound/usb/mixer_quirks.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4634,6 +4634,25 @@ static void snd_fix_plt_name(struct snd_usb_audio *chip,
46344634
usb_audio_dbg(chip, "something wrong in kctl name %s\n", id->name);
46354635
}
46364636

4637+
static void snd_usb_mixer_fu_quirk_linear_scale(struct usb_mixer_interface *mixer,
4638+
struct usb_mixer_elem_info *cval,
4639+
struct snd_kcontrol *kctl)
4640+
{
4641+
static const DECLARE_TLV_DB_LINEAR(scale, TLV_DB_GAIN_MUTE, 0);
4642+
4643+
if (cval->min_mute) {
4644+
/*
4645+
* We are clearing SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK,
4646+
* resulting in min_mute being a no-op.
4647+
*/
4648+
usb_audio_warn(mixer->chip, "LINEAR_VOL overrides MIN_MUTE\n");
4649+
}
4650+
4651+
kctl->tlv.p = scale;
4652+
kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
4653+
kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
4654+
}
4655+
46374656
void snd_usb_mixer_fu_apply_quirk(struct usb_mixer_interface *mixer,
46384657
struct usb_mixer_elem_info *cval, int unitid,
46394658
struct snd_kcontrol *kctl)
@@ -4660,6 +4679,21 @@ void snd_usb_mixer_fu_apply_quirk(struct usb_mixer_interface *mixer,
46604679
"applying capture min mute quirk\n");
46614680
cval->min_mute = 1;
46624681
}
4682+
4683+
if (mixer->chip->quirk_flags & QUIRK_FLAG_MIXER_PLAYBACK_LINEAR_VOL)
4684+
if (cval->control == UAC_FU_VOLUME && strstr(kctl->id.name, "Playback")) {
4685+
usb_audio_info(mixer->chip,
4686+
"applying playback linear volume quirk\n");
4687+
snd_usb_mixer_fu_quirk_linear_scale(mixer, cval, kctl);
4688+
}
4689+
4690+
if (mixer->chip->quirk_flags & QUIRK_FLAG_MIXER_CAPTURE_LINEAR_VOL)
4691+
if (cval->control == UAC_FU_VOLUME && strstr(kctl->id.name, "Capture")) {
4692+
usb_audio_info(mixer->chip,
4693+
"applying capture linear volume quirk\n");
4694+
snd_usb_mixer_fu_quirk_linear_scale(mixer, cval, kctl);
4695+
}
4696+
46634697
/* ALSA-ify some Plantronics headset control names */
46644698
if (USB_ID_VENDOR(mixer->chip->usb_id) == 0x047f &&
46654699
(cval->control == UAC_FU_MUTE || cval->control == UAC_FU_VOLUME))

sound/usb/quirks.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2543,6 +2543,8 @@ static const char *const snd_usb_audio_quirk_flag_names[] = {
25432543
QUIRK_STRING_ENTRY(MIXER_PLAYBACK_MIN_MUTE),
25442544
QUIRK_STRING_ENTRY(MIXER_CAPTURE_MIN_MUTE),
25452545
QUIRK_STRING_ENTRY(SKIP_IFACE_SETUP),
2546+
QUIRK_STRING_ENTRY(MIXER_PLAYBACK_LINEAR_VOL),
2547+
QUIRK_STRING_ENTRY(MIXER_CAPTURE_LINEAR_VOL),
25462548
NULL
25472549
};
25482550

sound/usb/usbaudio.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,14 @@ extern bool snd_usb_skip_validation;
228228
* Skip the probe-time interface setup (usb_set_interface,
229229
* init_pitch, init_sample_rate); redundant with
230230
* snd_usb_endpoint_prepare() at stream-open time
231+
* QUIRK_FLAG_MIXER_PLAYBACK_LINEAR_VOL
232+
* Set linear volume mapping for devices where the playback volume control
233+
* value is mapped to voltage (instead of dB) level linearly. In short:
234+
* x(raw) = (raw - raw_min) / (raw_max - raw_min); V(x) = k * x;
235+
* dB(x) = 20 * log10(x). Overrides QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE
236+
* QUIRK_FLAG_MIXER_CAPTURE_LINEAR_VOL
237+
* Similar to QUIRK_FLAG_MIXER_PLAYBACK_LINEAR_VOL, but for capture streams.
238+
* Overrides QUIRK_FLAG_MIXER_CAPTURE_MIN_MUTE
231239
*/
232240

233241
enum {
@@ -258,6 +266,8 @@ enum {
258266
QUIRK_TYPE_MIXER_PLAYBACK_MIN_MUTE = 24,
259267
QUIRK_TYPE_MIXER_CAPTURE_MIN_MUTE = 25,
260268
QUIRK_TYPE_SKIP_IFACE_SETUP = 26,
269+
QUIRK_TYPE_MIXER_PLAYBACK_LINEAR_VOL = 27,
270+
QUIRK_TYPE_MIXER_CAPTURE_LINEAR_VOL = 28,
261271
/* Please also edit snd_usb_audio_quirk_flag_names */
262272
};
263273

@@ -290,5 +300,7 @@ enum {
290300
#define QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE QUIRK_FLAG(MIXER_PLAYBACK_MIN_MUTE)
291301
#define QUIRK_FLAG_MIXER_CAPTURE_MIN_MUTE QUIRK_FLAG(MIXER_CAPTURE_MIN_MUTE)
292302
#define QUIRK_FLAG_SKIP_IFACE_SETUP QUIRK_FLAG(SKIP_IFACE_SETUP)
303+
#define QUIRK_FLAG_MIXER_PLAYBACK_LINEAR_VOL QUIRK_FLAG(MIXER_PLAYBACK_LINEAR_VOL)
304+
#define QUIRK_FLAG_MIXER_CAPTURE_LINEAR_VOL QUIRK_FLAG(MIXER_CAPTURE_LINEAR_VOL)
293305

294306
#endif /* __USBAUDIO_H */

0 commit comments

Comments
 (0)