Commit c26da265 authored by Takashi Iwai's avatar Takashi Iwai Committed by Jiri Slaby

ALSA: usb-audio: Resume mixer values properly

commit 400362f1 upstream.

Implement reset_resume callback so that the mixer values are properly
restored.  Still no boot quirks are called, so it might not work well
on some devices.
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
Signed-off-by: default avatarJiri Slaby <jslaby@suse.cz>
parent aeb35ac1
...@@ -706,12 +706,12 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) ...@@ -706,12 +706,12 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message)
} }
list_for_each_entry(mixer, &chip->mixer_list, list) list_for_each_entry(mixer, &chip->mixer_list, list)
snd_usb_mixer_inactivate(mixer); snd_usb_mixer_suspend(mixer);
return 0; return 0;
} }
static int usb_audio_resume(struct usb_interface *intf) static int __usb_audio_resume(struct usb_interface *intf, bool reset_resume)
{ {
struct snd_usb_audio *chip = usb_get_intfdata(intf); struct snd_usb_audio *chip = usb_get_intfdata(intf);
struct usb_mixer_interface *mixer; struct usb_mixer_interface *mixer;
...@@ -726,7 +726,7 @@ static int usb_audio_resume(struct usb_interface *intf) ...@@ -726,7 +726,7 @@ static int usb_audio_resume(struct usb_interface *intf)
* we just notify and restart the mixers * we just notify and restart the mixers
*/ */
list_for_each_entry(mixer, &chip->mixer_list, list) { list_for_each_entry(mixer, &chip->mixer_list, list) {
err = snd_usb_mixer_activate(mixer); err = snd_usb_mixer_resume(mixer, reset_resume);
if (err < 0) if (err < 0)
goto err_out; goto err_out;
} }
...@@ -738,9 +738,20 @@ static int usb_audio_resume(struct usb_interface *intf) ...@@ -738,9 +738,20 @@ static int usb_audio_resume(struct usb_interface *intf)
err_out: err_out:
return err; return err;
} }
static int usb_audio_resume(struct usb_interface *intf)
{
return __usb_audio_resume(intf, false);
}
static int usb_audio_reset_resume(struct usb_interface *intf)
{
return __usb_audio_resume(intf, true);
}
#else #else
#define usb_audio_suspend NULL #define usb_audio_suspend NULL
#define usb_audio_resume NULL #define usb_audio_resume NULL
#define usb_audio_reset_resume NULL
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
static struct usb_device_id usb_audio_ids [] = { static struct usb_device_id usb_audio_ids [] = {
...@@ -762,6 +773,7 @@ static struct usb_driver usb_audio_driver = { ...@@ -762,6 +773,7 @@ static struct usb_driver usb_audio_driver = {
.disconnect = usb_audio_disconnect, .disconnect = usb_audio_disconnect,
.suspend = usb_audio_suspend, .suspend = usb_audio_suspend,
.resume = usb_audio_resume, .resume = usb_audio_resume,
.reset_resume = usb_audio_reset_resume,
.id_table = usb_audio_ids, .id_table = usb_audio_ids,
.supports_autosuspend = 1, .supports_autosuspend = 1,
}; };
......
...@@ -2302,26 +2302,6 @@ static void snd_usb_mixer_interrupt(struct urb *urb) ...@@ -2302,26 +2302,6 @@ static void snd_usb_mixer_interrupt(struct urb *urb)
} }
} }
/* stop any bus activity of a mixer */
void snd_usb_mixer_inactivate(struct usb_mixer_interface *mixer)
{
usb_kill_urb(mixer->urb);
usb_kill_urb(mixer->rc_urb);
}
int snd_usb_mixer_activate(struct usb_mixer_interface *mixer)
{
int err;
if (mixer->urb) {
err = usb_submit_urb(mixer->urb, GFP_NOIO);
if (err < 0)
return err;
}
return 0;
}
/* create the handler for the optional status interrupt endpoint */ /* create the handler for the optional status interrupt endpoint */
static int snd_usb_mixer_status_create(struct usb_mixer_interface *mixer) static int snd_usb_mixer_status_create(struct usb_mixer_interface *mixer)
{ {
...@@ -2420,3 +2400,82 @@ void snd_usb_mixer_disconnect(struct list_head *p) ...@@ -2420,3 +2400,82 @@ void snd_usb_mixer_disconnect(struct list_head *p)
usb_kill_urb(mixer->urb); usb_kill_urb(mixer->urb);
usb_kill_urb(mixer->rc_urb); usb_kill_urb(mixer->rc_urb);
} }
#ifdef CONFIG_PM
/* stop any bus activity of a mixer */
static void snd_usb_mixer_inactivate(struct usb_mixer_interface *mixer)
{
usb_kill_urb(mixer->urb);
usb_kill_urb(mixer->rc_urb);
}
static int snd_usb_mixer_activate(struct usb_mixer_interface *mixer)
{
int err;
if (mixer->urb) {
err = usb_submit_urb(mixer->urb, GFP_NOIO);
if (err < 0)
return err;
}
return 0;
}
int snd_usb_mixer_suspend(struct usb_mixer_interface *mixer)
{
snd_usb_mixer_inactivate(mixer);
return 0;
}
static int restore_mixer_value(struct usb_mixer_elem_info *cval)
{
int c, err, idx;
if (cval->cmask) {
idx = 0;
for (c = 0; c < MAX_CHANNELS; c++) {
if (!(cval->cmask & (1 << c)))
continue;
if (cval->cached & (1 << c)) {
err = set_cur_mix_value(cval, c + 1, idx,
cval->cache_val[idx]);
if (err < 0)
return err;
}
idx++;
}
} else {
/* master */
if (cval->cached) {
err = set_cur_mix_value(cval, 0, 0, *cval->cache_val);
if (err < 0)
return err;
}
}
return 0;
}
int snd_usb_mixer_resume(struct usb_mixer_interface *mixer, bool reset_resume)
{
struct usb_mixer_elem_info *cval;
int id, err;
/* FIXME: any mixer quirks? */
if (reset_resume) {
/* restore cached mixer values */
for (id = 0; id < MAX_ID_ELEMS; id++) {
for (cval = mixer->id_elems[id]; cval;
cval = cval->next_id_elem) {
err = restore_mixer_value(cval);
if (err < 0)
return err;
}
}
}
return snd_usb_mixer_activate(mixer);
}
#endif
...@@ -63,8 +63,6 @@ void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, int unitid); ...@@ -63,8 +63,6 @@ void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, int unitid);
int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
int request, int validx, int value_set); int request, int validx, int value_set);
void snd_usb_mixer_inactivate(struct usb_mixer_interface *mixer);
int snd_usb_mixer_activate(struct usb_mixer_interface *mixer);
int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer, int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer,
struct snd_kcontrol *kctl); struct snd_kcontrol *kctl);
...@@ -72,4 +70,9 @@ int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer, ...@@ -72,4 +70,9 @@ int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer,
int snd_usb_mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, int snd_usb_mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
unsigned int size, unsigned int __user *_tlv); unsigned int size, unsigned int __user *_tlv);
#ifdef CONFIG_PM
int snd_usb_mixer_suspend(struct usb_mixer_interface *mixer);
int snd_usb_mixer_resume(struct usb_mixer_interface *mixer, bool reset_resume);
#endif
#endif /* __USBMIXER_H */ #endif /* __USBMIXER_H */
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