Merge commit '3ff195b011d7decf501a4d55aeed312731094796' into for-linus
[pandora-kernel.git] / sound / usb / midi.c
index c6ee4a1..8b1e4b1 100644 (file)
@@ -987,6 +987,8 @@ static void snd_usbmidi_output_drain(struct snd_rawmidi_substream *substream)
        DEFINE_WAIT(wait);
        long timeout = msecs_to_jiffies(50);
 
+       if (ep->umidi->disconnected)
+               return;
        /*
         * The substream buffer is empty, but some data might still be in the
         * currently active URBs, so we have to wait for those to complete.
@@ -1046,8 +1048,8 @@ static struct snd_rawmidi_ops snd_usbmidi_input_ops = {
 static void free_urb_and_buffer(struct snd_usb_midi *umidi, struct urb *urb,
                                unsigned int buffer_length)
 {
-       usb_buffer_free(umidi->dev, buffer_length,
-                       urb->transfer_buffer, urb->transfer_dma);
+       usb_free_coherent(umidi->dev, buffer_length,
+                         urb->transfer_buffer, urb->transfer_dma);
        usb_free_urb(urb);
 }
 
@@ -1098,8 +1100,8 @@ static int snd_usbmidi_in_endpoint_create(struct snd_usb_midi* umidi,
                pipe = usb_rcvbulkpipe(umidi->dev, ep_info->in_ep);
        length = usb_maxpacket(umidi->dev, pipe, 0);
        for (i = 0; i < INPUT_URBS; ++i) {
-               buffer = usb_buffer_alloc(umidi->dev, length, GFP_KERNEL,
-                                         &ep->urbs[i]->transfer_dma);
+               buffer = usb_alloc_coherent(umidi->dev, length, GFP_KERNEL,
+                                           &ep->urbs[i]->transfer_dma);
                if (!buffer) {
                        snd_usbmidi_in_endpoint_delete(ep);
                        return -ENOMEM;
@@ -1124,14 +1126,21 @@ static int snd_usbmidi_in_endpoint_create(struct snd_usb_midi* umidi,
  * Frees an output endpoint.
  * May be called when ep hasn't been initialized completely.
  */
-static void snd_usbmidi_out_endpoint_delete(struct snd_usb_midi_out_endpoint* ep)
+static void snd_usbmidi_out_endpoint_clear(struct snd_usb_midi_out_endpoint *ep)
 {
        unsigned int i;
 
        for (i = 0; i < OUTPUT_URBS; ++i)
-               if (ep->urbs[i].urb)
+               if (ep->urbs[i].urb) {
                        free_urb_and_buffer(ep->umidi, ep->urbs[i].urb,
                                            ep->max_transfer);
+                       ep->urbs[i].urb = NULL;
+               }
+}
+
+static void snd_usbmidi_out_endpoint_delete(struct snd_usb_midi_out_endpoint *ep)
+{
+       snd_usbmidi_out_endpoint_clear(ep);
        kfree(ep);
 }
 
@@ -1182,9 +1191,9 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi* umidi,
                break;
        }
        for (i = 0; i < OUTPUT_URBS; ++i) {
-               buffer = usb_buffer_alloc(umidi->dev,
-                                         ep->max_transfer, GFP_KERNEL,
-                                         &ep->urbs[i].urb->transfer_dma);
+               buffer = usb_alloc_coherent(umidi->dev,
+                                           ep->max_transfer, GFP_KERNEL,
+                                           &ep->urbs[i].urb->transfer_dma);
                if (!buffer) {
                        snd_usbmidi_out_endpoint_delete(ep);
                        return -ENOMEM;
@@ -1263,15 +1272,18 @@ void snd_usbmidi_disconnect(struct list_head* p)
                                usb_kill_urb(ep->out->urbs[j].urb);
                        if (umidi->usb_protocol_ops->finish_out_endpoint)
                                umidi->usb_protocol_ops->finish_out_endpoint(ep->out);
+                       ep->out->active_urbs = 0;
+                       if (ep->out->drain_urbs) {
+                               ep->out->drain_urbs = 0;
+                               wake_up(&ep->out->drain_wait);
+                       }
                }
                if (ep->in)
                        for (j = 0; j < INPUT_URBS; ++j)
                                usb_kill_urb(ep->in->urbs[j]);
                /* free endpoints here; later call can result in Oops */
-               if (ep->out) {
-                       snd_usbmidi_out_endpoint_delete(ep->out);
-                       ep->out = NULL;
-               }
+               if (ep->out)
+                       snd_usbmidi_out_endpoint_clear(ep->out);
                if (ep->in) {
                        snd_usbmidi_in_endpoint_delete(ep->in);
                        ep->in = NULL;