summaryrefslogtreecommitdiffstats
path: root/sound/usb/mixer.c
diff options
context:
space:
mode:
authorKai-Heng Feng <kai.heng.feng@canonical.com>2021-03-25 17:59:13 +0100
committerTakashi Iwai <tiwai@suse.de>2021-03-26 09:10:33 +0100
commit44609fc01f280d6b4067262ecbb00e3128d718ae (patch)
tree7bca7809ed4ff63c53706b5bc8059ba85d6bbcf4 /sound/usb/mixer.c
parentALSA: usb-audio: Carve out connector value checking into a helper (diff)
downloadlinux-44609fc01f280d6b4067262ecbb00e3128d718ae.tar.xz
linux-44609fc01f280d6b4067262ecbb00e3128d718ae.zip
ALSA: usb-audio: Check connector value on resume
Rear Mic on Lenovo P620 cannot record after S3, despite that there's no error and the other two functions of the USB audio, Line In and Line Out, work just fine. The mic starts to work again after running userspace app like "alsactl store". Following the lead, the evidence shows that as soon as connector status is queried, the mic can work again. So also check connector value on resume to "wake up" the USB audio to make it functional. This can be device specific, however I think this generic approach may benefit more than one device. Now the resume callback checks connector, and a new callback, reset_resume, to also restore switches and volumes. Suggested-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com> Link: https://lore.kernel.org/r/20210325165918.22593-2-kai.heng.feng@canonical.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/usb/mixer.c')
-rw-r--r--sound/usb/mixer.c44
1 files changed, 34 insertions, 10 deletions
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 5a2d9a768f70..2faf5767c7f8 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -3631,20 +3631,43 @@ static int restore_mixer_value(struct usb_mixer_elem_list *list)
return 0;
}
+static int default_mixer_resume(struct usb_mixer_elem_list *list)
+{
+ struct usb_mixer_elem_info *cval = mixer_elem_list_to_info(list);
+
+ /* get connector value to "wake up" the USB audio */
+ if (cval->val_type == USB_MIXER_BOOLEAN && cval->channels == 1)
+ get_connector_value(cval, NULL, NULL);
+
+ return 0;
+}
+
+static int default_mixer_reset_resume(struct usb_mixer_elem_list *list)
+{
+ int err = default_mixer_resume(list);
+
+ if (err < 0)
+ return err;
+ return restore_mixer_value(list);
+}
+
int snd_usb_mixer_resume(struct usb_mixer_interface *mixer, bool reset_resume)
{
struct usb_mixer_elem_list *list;
+ usb_mixer_elem_resume_func_t f;
int id, err;
- if (reset_resume) {
- /* restore cached mixer values */
- for (id = 0; id < MAX_ID_ELEMS; id++) {
- for_each_mixer_elem(list, mixer, id) {
- if (list->resume) {
- err = list->resume(list);
- if (err < 0)
- return err;
- }
+ /* restore cached mixer values */
+ for (id = 0; id < MAX_ID_ELEMS; id++) {
+ for_each_mixer_elem(list, mixer, id) {
+ if (reset_resume)
+ f = list->reset_resume;
+ else
+ f = list->resume;
+ if (f) {
+ err = f(list);
+ if (err < 0)
+ return err;
}
}
}
@@ -3663,6 +3686,7 @@ void snd_usb_mixer_elem_init_std(struct usb_mixer_elem_list *list,
list->id = unitid;
list->dump = snd_usb_mixer_dump_cval;
#ifdef CONFIG_PM
- list->resume = restore_mixer_value;
+ list->resume = default_mixer_resume;
+ list->reset_resume = default_mixer_reset_resume;
#endif
}