ALSA: ua101: Fix unlocked snd_pcm_stop() call
[pandora-kernel.git] / sound / usb / misc / ua101.c
index 67bec76..84052cf 100644 (file)
@@ -459,7 +459,8 @@ static void kill_stream_urbs(struct ua101_stream *stream)
        unsigned int i;
 
        for (i = 0; i < stream->queue_length; ++i)
-               usb_kill_urb(&stream->urbs[i]->urb);
+               if (stream->urbs[i])
+                       usb_kill_urb(&stream->urbs[i]->urb);
 }
 
 static int enable_iso_interface(struct ua101 *ua, unsigned int intf_index)
@@ -484,6 +485,9 @@ static void disable_iso_interface(struct ua101 *ua, unsigned int intf_index)
 {
        struct usb_host_interface *alts;
 
+       if (!ua->intf[intf_index])
+               return;
+
        alts = ua->intf[intf_index]->cur_altsetting;
        if (alts->desc.bAlternateSetting != 0) {
                int err = usb_set_interface(ua->dev,
@@ -609,14 +613,24 @@ static int start_usb_playback(struct ua101 *ua)
 
 static void abort_alsa_capture(struct ua101 *ua)
 {
-       if (test_bit(ALSA_CAPTURE_RUNNING, &ua->states))
+       unsigned long flags;
+
+       if (test_bit(ALSA_CAPTURE_RUNNING, &ua->states)) {
+               snd_pcm_stream_lock_irqsave(ua->capture.substream, flags);
                snd_pcm_stop(ua->capture.substream, SNDRV_PCM_STATE_XRUN);
+               snd_pcm_stream_unlock_irqrestore(ua->capture.substream, flags);
+       }
 }
 
 static void abort_alsa_playback(struct ua101 *ua)
 {
-       if (test_bit(ALSA_PLAYBACK_RUNNING, &ua->states))
+       unsigned long flags;
+
+       if (test_bit(ALSA_PLAYBACK_RUNNING, &ua->states)) {
+               snd_pcm_stream_lock_irqsave(ua->playback.substream, flags);
                snd_pcm_stop(ua->playback.substream, SNDRV_PCM_STATE_XRUN);
+               snd_pcm_stream_unlock_irqrestore(ua->playback.substream, flags);
+       }
 }
 
 static int set_stream_hw(struct ua101 *ua, struct snd_pcm_substream *substream,
@@ -1144,27 +1158,37 @@ static void free_stream_urbs(struct ua101_stream *stream)
 {
        unsigned int i;
 
-       for (i = 0; i < stream->queue_length; ++i)
+       for (i = 0; i < stream->queue_length; ++i) {
                kfree(stream->urbs[i]);
+               stream->urbs[i] = NULL;
+       }
 }
 
 static void free_usb_related_resources(struct ua101 *ua,
                                       struct usb_interface *interface)
 {
        unsigned int i;
+       struct usb_interface *intf;
 
+       mutex_lock(&ua->mutex);
        free_stream_urbs(&ua->capture);
        free_stream_urbs(&ua->playback);
+       mutex_unlock(&ua->mutex);
        free_stream_buffers(ua, &ua->capture);
        free_stream_buffers(ua, &ua->playback);
 
-       for (i = 0; i < ARRAY_SIZE(ua->intf); ++i)
-               if (ua->intf[i]) {
-                       usb_set_intfdata(ua->intf[i], NULL);
-                       if (ua->intf[i] != interface)
+       for (i = 0; i < ARRAY_SIZE(ua->intf); ++i) {
+               mutex_lock(&ua->mutex);
+               intf = ua->intf[i];
+               ua->intf[i] = NULL;
+               mutex_unlock(&ua->mutex);
+               if (intf) {
+                       usb_set_intfdata(intf, NULL);
+                       if (intf != interface)
                                usb_driver_release_interface(&ua101_driver,
-                                                            ua->intf[i]);
+                                                            intf);
                }
+       }
 }
 
 static void ua101_card_free(struct snd_card *card)