ALSA: usb-audio: Respond to suspend and resume callbacks for MIDI input
authorAdam Goode <agoode@google.com>
Tue, 5 Aug 2014 16:44:50 +0000 (12:44 -0400)
committerTakashi Iwai <tiwai@suse.de>
Tue, 5 Aug 2014 18:08:00 +0000 (20:08 +0200)
sound/usb/card.c registers USB suspend and resume but did not previously
kill the input URBs. This means that USB MIDI devices left open across
suspend/resume had non-functional input (output still usually worked,
but it looks like that is another issue). Before this change, we would
get ESHUTDOWN for each of the input URBs at suspend time, killing input.

Signed-off-by: Adam Goode <agoode@google.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/usb/card.c
sound/usb/midi.c
sound/usb/midi.h

index a09e5f3519e324eeadd28a7a144fdbdb35a44130..7ecd0e8a5c51ba435e590090a52259fe0be35561 100644 (file)
@@ -680,6 +680,7 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message)
        struct snd_usb_audio *chip = usb_get_intfdata(intf);
        struct snd_usb_stream *as;
        struct usb_mixer_interface *mixer;
+       struct list_head *p;
 
        if (chip == (void *)-1L)
                return 0;
@@ -692,6 +693,9 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message)
                                as->substream[0].need_setup_ep =
                                        as->substream[1].need_setup_ep = true;
                        }
+                       list_for_each(p, &chip->midi_list) {
+                               snd_usbmidi_suspend(p);
+                       }
                }
        } else {
                /*
@@ -713,6 +717,7 @@ static int __usb_audio_resume(struct usb_interface *intf, bool reset_resume)
 {
        struct snd_usb_audio *chip = usb_get_intfdata(intf);
        struct usb_mixer_interface *mixer;
+       struct list_head *p;
        int err = 0;
 
        if (chip == (void *)-1L)
@@ -731,6 +736,10 @@ static int __usb_audio_resume(struct usb_interface *intf, bool reset_resume)
                        goto err_out;
        }
 
+       list_for_each(p, &chip->midi_list) {
+               snd_usbmidi_resume(p);
+       }
+
        if (!chip->autosuspended)
                snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0);
        chip->autosuspended = 0;
index 9da74d2e8eeec5f40cfbfc80d892f72e79cc4e04..9a4e82cf4ef9df2974f3f06c3609820d3591cee0 100644 (file)
@@ -2186,6 +2186,34 @@ void snd_usbmidi_input_start(struct list_head* p)
 }
 EXPORT_SYMBOL(snd_usbmidi_input_start);
 
+/*
+ * Prepare for suspend. Typically called from the USB suspend callback.
+ */
+void snd_usbmidi_suspend(struct list_head *p)
+{
+       struct snd_usb_midi *umidi;
+
+       umidi = list_entry(p, struct snd_usb_midi, list);
+       mutex_lock(&umidi->mutex);
+       snd_usbmidi_input_stop(p);
+       mutex_unlock(&umidi->mutex);
+}
+EXPORT_SYMBOL(snd_usbmidi_suspend);
+
+/*
+ * Resume. Typically called from the USB resume callback.
+ */
+void snd_usbmidi_resume(struct list_head *p)
+{
+       struct snd_usb_midi *umidi;
+
+       umidi = list_entry(p, struct snd_usb_midi, list);
+       mutex_lock(&umidi->mutex);
+       snd_usbmidi_input_start(p);
+       mutex_unlock(&umidi->mutex);
+}
+EXPORT_SYMBOL(snd_usbmidi_resume);
+
 /*
  * Creates and registers everything needed for a MIDI streaming interface.
  */
index 2fca80b744c0a5476d191512e3e909fa744f8d77..46e5b65e81e78ea4fea17070dae44820af403411 100644 (file)
@@ -46,5 +46,7 @@ int snd_usbmidi_create(struct snd_card *card,
 void snd_usbmidi_input_stop(struct list_head* p);
 void snd_usbmidi_input_start(struct list_head* p);
 void snd_usbmidi_disconnect(struct list_head *p);
+void snd_usbmidi_suspend(struct list_head *p);
+void snd_usbmidi_resume(struct list_head *p);
 
 #endif /* __USBMIDI_H */