Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit edf7de31 authored by Oliver Neukum's avatar Oliver Neukum Committed by Takashi Iwai
Browse files

ALSA: usbaudio: fix suspend/resume



- ESHUTDOWN must be correctly handled
- the optional interrupt endpoint's URB must be stopped and restarted

Signed-off-by: default avatarOliver Neukum <oneukum@suse.de>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent cc99a086
Loading
Loading
Loading
Loading
+9 −1
Original line number Diff line number Diff line
@@ -586,6 +586,7 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message)
	struct snd_usb_audio *chip = usb_get_intfdata(intf);
	struct list_head *p;
	struct snd_usb_stream *as;
	struct usb_mixer_interface *mixer;

	if (chip == (void *)-1L)
		return 0;
@@ -596,6 +597,10 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message)
			as = list_entry(p, struct snd_usb_stream, list);
			snd_pcm_suspend_all(as->pcm);
		}

		list_for_each_entry(mixer, &chip->mixer_list, list) {
			snd_usb_mixer_inactivate(mixer);
		}
	}

	return 0;
@@ -604,6 +609,7 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message)
static int usb_audio_resume(struct usb_interface *intf)
{
	struct snd_usb_audio *chip = usb_get_intfdata(intf);
	struct usb_mixer_interface *mixer;

	if (chip == (void *)-1L)
		return 0;
@@ -611,8 +617,10 @@ static int usb_audio_resume(struct usb_interface *intf)
		return 0;
	/*
	 * ALSA leaves material resumption to user space
	 * we just notify
	 * we just notify and restart the mixers
	 */
	list_for_each_entry(mixer, &chip->mixer_list, list)
		snd_usb_mixer_activate(mixer);

	snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0);

+23 −2
Original line number Diff line number Diff line
@@ -2075,8 +2075,9 @@ static void snd_usb_mixer_interrupt(struct urb *urb)
{
	struct usb_mixer_interface *mixer = urb->context;
	int len = urb->actual_length;
	int ustatus = urb->status;

	if (urb->status != 0)
	if (ustatus != 0)
		goto requeue;

	if (mixer->protocol == UAC_VERSION_1) {
@@ -2117,12 +2118,32 @@ static void snd_usb_mixer_interrupt(struct urb *urb)
	}

requeue:
	if (urb->status != -ENOENT && urb->status != -ECONNRESET) {
	if (ustatus != -ENOENT && ustatus != -ECONNRESET && ustatus != -ESHUTDOWN) {
		urb->dev = mixer->chip->dev;
		usb_submit_urb(urb, GFP_ATOMIC);
	}
}

/* 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 */
static int snd_usb_mixer_status_create(struct usb_mixer_interface *mixer)
{
+2 −0
Original line number Diff line number Diff line
@@ -52,5 +52,7 @@ 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 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);

#endif /* __USBMIXER_H */