diff options
author | Takashi Iwai <tiwai@suse.de> | 2021-10-14 15:06:36 +0200 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2021-10-14 16:51:56 +0200 |
commit | b96681bd58276e1c7ca4ca37bbaab9f8f1738d61 (patch) | |
tree | 179f9e7e79dccf1f67b4c7711167304fc0cb2232 /sound/usb/mixer.c | |
parent | ALSA: usb-audio: Drop superfluous error message after disconnection (diff) | |
download | linux-b96681bd58276e1c7ca4ca37bbaab9f8f1738d61.tar.xz linux-b96681bd58276e1c7ca4ca37bbaab9f8f1738d61.zip |
ALSA: usb-audio: Initialize every feature unit once at probe time
So far we used to read the current value of the mixer element
dynamically at the first access, and the error from a GET_CUR message
is treated as a fatal error (unless QUIRK_IGNORE_CTL_ERROR is set).
It's rather inconvenient, as most of GET_CUR errors are no fatal, and
we can continue operation with assumption of some fixed value.
This patch makes the USB-audio driver to change the behavior at probe
time; now it tries to initialize the current value of each mixer
element that is built from a feature unit (those for typically for
mixer volumes and switches). When a read failure happens, it tries to
set the known minimum value. After that point, a cached value is used
always, hence we won't hit GET_CUR message error any longer.
The error from GET_CUR message is still shown as a warning normally,
but only once at the probe time, and it'll keep operating. If the
message is confirmed to be harmless, it can be shut up by
QUIRK_IGNORE_CTL_ERROR quirk flag, too.
Tested-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Link: https://lore.kernel.org/r/20211014130636.17860-4-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/usb/mixer.c')
-rw-r--r-- | sound/usb/mixer.c | 34 |
1 files changed, 33 insertions, 1 deletions
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 60d394361a43..4555de9830c5 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -1199,12 +1199,32 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval, } } +/* forcibly initialize the current mixer value; if GET_CUR fails, set to + * the minimum as default + */ +static void init_cur_mix_raw(struct usb_mixer_elem_info *cval, int ch, int idx) +{ + int val, err; + + err = snd_usb_get_cur_mix_value(cval, ch, idx, &val); + if (!err) + return; + if (!cval->head.mixer->ignore_ctl_error) + usb_audio_warn(cval->head.mixer->chip, + "%d:%d: failed to get current value for ch %d (%d)\n", + cval->head.id, mixer_ctrl_intf(cval->head.mixer), + ch, err); + snd_usb_set_cur_mix_value(cval, ch, idx, cval->min); +} + /* * retrieve the minimum and maximum values for the specified control */ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval, int default_min, struct snd_kcontrol *kctl) { + int i, idx; + /* for failsafe */ cval->min = default_min; cval->max = cval->min + 1; @@ -1217,7 +1237,6 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval, } else { int minchn = 0; if (cval->cmask) { - int i; for (i = 0; i < MAX_CHANNELS; i++) if (cval->cmask & (1 << i)) { minchn = i + 1; @@ -1318,6 +1337,19 @@ no_res_check: } } + /* initialize all elements */ + if (!cval->cmask) { + init_cur_mix_raw(cval, 0, 0); + } else { + idx = 0; + for (i = 0; i < MAX_CHANNELS; i++) { + if (cval->cmask & (1 << i)) { + init_cur_mix_raw(cval, i + 1, idx); + idx++; + } + } + } + return 0; } |