Commit 44609fc0 authored by Kai-Heng Feng's avatar Kai-Heng Feng Committed by Takashi Iwai

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: default avatarTakashi Iwai <tiwai@suse.de>
Signed-off-by: default avatarKai-Heng Feng <kai.heng.feng@canonical.com>
Link: https://lore.kernel.org/r/20210325165918.22593-2-kai.heng.feng@canonical.comSigned-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 69644fca
...@@ -3631,20 +3631,43 @@ static int restore_mixer_value(struct usb_mixer_elem_list *list) ...@@ -3631,20 +3631,43 @@ static int restore_mixer_value(struct usb_mixer_elem_list *list)
return 0; 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) int snd_usb_mixer_resume(struct usb_mixer_interface *mixer, bool reset_resume)
{ {
struct usb_mixer_elem_list *list; struct usb_mixer_elem_list *list;
usb_mixer_elem_resume_func_t f;
int id, err; int id, err;
if (reset_resume) { /* restore cached mixer values */
/* restore cached mixer values */ for (id = 0; id < MAX_ID_ELEMS; id++) {
for (id = 0; id < MAX_ID_ELEMS; id++) { for_each_mixer_elem(list, mixer, id) {
for_each_mixer_elem(list, mixer, id) { if (reset_resume)
if (list->resume) { f = list->reset_resume;
err = list->resume(list); else
if (err < 0) f = list->resume;
return err; 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, ...@@ -3663,6 +3686,7 @@ void snd_usb_mixer_elem_init_std(struct usb_mixer_elem_list *list,
list->id = unitid; list->id = unitid;
list->dump = snd_usb_mixer_dump_cval; list->dump = snd_usb_mixer_dump_cval;
#ifdef CONFIG_PM #ifdef CONFIG_PM
list->resume = restore_mixer_value; list->resume = default_mixer_resume;
list->reset_resume = default_mixer_reset_resume;
#endif #endif
} }
...@@ -69,6 +69,7 @@ struct usb_mixer_elem_list { ...@@ -69,6 +69,7 @@ struct usb_mixer_elem_list {
bool is_std_info; bool is_std_info;
usb_mixer_elem_dump_func_t dump; usb_mixer_elem_dump_func_t dump;
usb_mixer_elem_resume_func_t resume; usb_mixer_elem_resume_func_t resume;
usb_mixer_elem_resume_func_t reset_resume;
}; };
/* iterate over mixer element list of the given unit id */ /* iterate over mixer element list of the given unit id */
......
...@@ -151,7 +151,7 @@ static int add_single_ctl_with_resume(struct usb_mixer_interface *mixer, ...@@ -151,7 +151,7 @@ static int add_single_ctl_with_resume(struct usb_mixer_interface *mixer,
*listp = list; *listp = list;
list->mixer = mixer; list->mixer = mixer;
list->id = id; list->id = id;
list->resume = resume; list->reset_resume = resume;
kctl = snd_ctl_new1(knew, list); kctl = snd_ctl_new1(knew, list);
if (!kctl) { if (!kctl) {
kfree(list); kfree(list);
......
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