Commit b96681bd authored by Takashi Iwai's avatar Takashi Iwai

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: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Link: https://lore.kernel.org/r/20211014130636.17860-4-tiwai@suse.deSigned-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 509975c7
...@@ -1199,12 +1199,32 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval, ...@@ -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 * retrieve the minimum and maximum values for the specified control
*/ */
static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval, static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval,
int default_min, struct snd_kcontrol *kctl) int default_min, struct snd_kcontrol *kctl)
{ {
int i, idx;
/* for failsafe */ /* for failsafe */
cval->min = default_min; cval->min = default_min;
cval->max = cval->min + 1; cval->max = cval->min + 1;
...@@ -1217,7 +1237,6 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval, ...@@ -1217,7 +1237,6 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval,
} else { } else {
int minchn = 0; int minchn = 0;
if (cval->cmask) { if (cval->cmask) {
int i;
for (i = 0; i < MAX_CHANNELS; i++) for (i = 0; i < MAX_CHANNELS; i++)
if (cval->cmask & (1 << i)) { if (cval->cmask & (1 << i)) {
minchn = i + 1; minchn = i + 1;
...@@ -1318,6 +1337,19 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval, ...@@ -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; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment