summaryrefslogtreecommitdiff
path: root/sound/usb
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2021-10-14 15:06:36 +0200
committerTakashi Iwai <tiwai@suse.de>2021-10-14 16:51:56 +0200
commitb96681bd58276e1c7ca4ca37bbaab9f8f1738d61 (patch)
tree179f9e7e79dccf1f67b4c7711167304fc0cb2232 /sound/usb
parent509975c7789f84b4d98e06fe2db51ee4ec02eef5 (diff)
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')
-rw-r--r--sound/usb/mixer.c34
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;
}