diff mbox series

[3/3] ALSA: usb-audio: Initialize every feature unit once at probe time

Message ID 20211014130636.17860-4-tiwai@suse.de (mailing list archive)
State New, archived
Headers show
Series ALSA: usb-audio: Small improvements in mixer handling | expand

Commit Message

Takashi Iwai Oct. 14, 2021, 1:06 p.m. UTC
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.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 sound/usb/mixer.c | 34 +++++++++++++++++++++++++++++++++-
 1 file changed, 33 insertions(+), 1 deletion(-)
diff mbox series

Patch

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 @@  static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval,
 		}
 	}
 
+	/* 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;
 }