| From 42e3121d90f42e57f6dbd6083dff2f57b3ec7daa Mon Sep 17 00:00:00 2001 |
| From: Anssi Hannula <anssi.hannula@iki.fi> |
| Date: Sun, 13 Dec 2015 20:49:58 +0200 |
| Subject: ALSA: usb-audio: Add a more accurate volume quirk for AudioQuest DragonFly |
| |
| From: Anssi Hannula <anssi.hannula@iki.fi> |
| |
| commit 42e3121d90f42e57f6dbd6083dff2f57b3ec7daa upstream. |
| |
| AudioQuest DragonFly DAC reports a volume control range of 0..50 |
| (0x0000..0x0032) which in USB Audio means a range of 0 .. 0.2dB, which |
| is obviously incorrect and would cause software using the dB information |
| in e.g. volume sliders to have a massive volume difference in 100..102% |
| range. |
| |
| Commit 2d1cb7f658fb ("ALSA: usb-audio: add dB range mapping for some |
| devices") added a dB range mapping for it with range 0..50 dB. |
| |
| However, the actual volume mapping seems to be neither linear volume nor |
| linear dB scale, but instead quite close to the cubic mapping e.g. |
| alsamixer uses, with a range of approx. -53...0 dB. |
| |
| Replace the previous quirk with a custom dB mapping based on some basic |
| output measurements, using a 10-item range TLV (which will still fit in |
| alsa-lib MAX_TLV_RANGE_SIZE). |
| |
| Tested on AudioQuest DragonFly HW v1.2. The quirk is only applied if the |
| range is 0..50, so if this gets fixed/changed in later HW revisions it |
| will no longer be applied. |
| |
| v2: incorporated Takashi Iwai's suggestion for the quirk application |
| method |
| |
| Signed-off-by: Anssi Hannula <anssi.hannula@iki.fi> |
| Signed-off-by: Takashi Iwai <tiwai@suse.de> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| sound/usb/mixer.c | 2 ++ |
| sound/usb/mixer_maps.c | 12 ------------ |
| sound/usb/mixer_quirks.c | 37 +++++++++++++++++++++++++++++++++++++ |
| sound/usb/mixer_quirks.h | 4 ++++ |
| 4 files changed, 43 insertions(+), 12 deletions(-) |
| |
| --- a/sound/usb/mixer.c |
| +++ b/sound/usb/mixer.c |
| @@ -1354,6 +1354,8 @@ static void build_feature_ctl(struct mix |
| } |
| } |
| |
| + snd_usb_mixer_fu_apply_quirk(state->mixer, cval, unitid, kctl); |
| + |
| range = (cval->max - cval->min) / cval->res; |
| /* |
| * Are there devices with volume range more than 255? I use a bit more |
| --- a/sound/usb/mixer_maps.c |
| +++ b/sound/usb/mixer_maps.c |
| @@ -348,13 +348,6 @@ static struct usbmix_name_map bose_compa |
| { 0 } /* terminator */ |
| }; |
| |
| -/* Dragonfly DAC 1.2, the dB conversion factor is 1 instead of 256 */ |
| -static struct usbmix_dB_map dragonfly_1_2_dB = {0, 5000}; |
| -static struct usbmix_name_map dragonfly_1_2_map[] = { |
| - { 7, NULL, .dB = &dragonfly_1_2_dB }, |
| - { 0 } /* terminator */ |
| -}; |
| - |
| /* |
| * Control map entries |
| */ |
| @@ -470,11 +463,6 @@ static struct usbmix_ctl_map usbmix_ctl_ |
| .id = USB_ID(0x05a7, 0x1020), |
| .map = bose_companion5_map, |
| }, |
| - { |
| - /* Dragonfly DAC 1.2 */ |
| - .id = USB_ID(0x21b4, 0x0081), |
| - .map = dragonfly_1_2_map, |
| - }, |
| { 0 } /* terminator */ |
| }; |
| |
| --- a/sound/usb/mixer_quirks.c |
| +++ b/sound/usb/mixer_quirks.c |
| @@ -37,6 +37,7 @@ |
| #include <sound/control.h> |
| #include <sound/hwdep.h> |
| #include <sound/info.h> |
| +#include <sound/tlv.h> |
| |
| #include "usbaudio.h" |
| #include "mixer.h" |
| @@ -1824,4 +1825,40 @@ void snd_usb_mixer_rc_memory_change(stru |
| break; |
| } |
| } |
| + |
| +static void snd_dragonfly_quirk_db_scale(struct usb_mixer_interface *mixer, |
| + struct snd_kcontrol *kctl) |
| +{ |
| + /* Approximation using 10 ranges based on output measurement on hw v1.2. |
| + * This seems close to the cubic mapping e.g. alsamixer uses. */ |
| + static const DECLARE_TLV_DB_RANGE(scale, |
| + 0, 1, TLV_DB_MINMAX_ITEM(-5300, -4970), |
| + 2, 5, TLV_DB_MINMAX_ITEM(-4710, -4160), |
| + 6, 7, TLV_DB_MINMAX_ITEM(-3884, -3710), |
| + 8, 14, TLV_DB_MINMAX_ITEM(-3443, -2560), |
| + 15, 16, TLV_DB_MINMAX_ITEM(-2475, -2324), |
| + 17, 19, TLV_DB_MINMAX_ITEM(-2228, -2031), |
| + 20, 26, TLV_DB_MINMAX_ITEM(-1910, -1393), |
| + 27, 31, TLV_DB_MINMAX_ITEM(-1322, -1032), |
| + 32, 40, TLV_DB_MINMAX_ITEM(-968, -490), |
| + 41, 50, TLV_DB_MINMAX_ITEM(-441, 0), |
| + ); |
| + |
| + usb_audio_info(mixer->chip, "applying DragonFly dB scale quirk\n"); |
| + kctl->tlv.p = scale; |
| + kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; |
| + kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; |
| +} |
| + |
| +void snd_usb_mixer_fu_apply_quirk(struct usb_mixer_interface *mixer, |
| + struct usb_mixer_elem_info *cval, int unitid, |
| + struct snd_kcontrol *kctl) |
| +{ |
| + switch (mixer->chip->usb_id) { |
| + case USB_ID(0x21b4, 0x0081): /* AudioQuest DragonFly */ |
| + if (unitid == 7 && cval->min == 0 && cval->max == 50) |
| + snd_dragonfly_quirk_db_scale(mixer, kctl); |
| + break; |
| + } |
| +} |
| |
| --- a/sound/usb/mixer_quirks.h |
| +++ b/sound/usb/mixer_quirks.h |
| @@ -9,5 +9,9 @@ void snd_emuusb_set_samplerate(struct sn |
| void snd_usb_mixer_rc_memory_change(struct usb_mixer_interface *mixer, |
| int unitid); |
| |
| +void snd_usb_mixer_fu_apply_quirk(struct usb_mixer_interface *mixer, |
| + struct usb_mixer_elem_info *cval, int unitid, |
| + struct snd_kcontrol *kctl); |
| + |
| #endif /* SND_USB_MIXER_QUIRKS_H */ |
| |