Merge branch 'stable-3.2' into pandora-3.2
[pandora-kernel.git] / drivers / usb / core / devio.c
index 6f34a26..a33e3cb 100644 (file)
@@ -423,6 +423,8 @@ static void async_completed(struct urb *urb)
        if (as->status < 0 && as->bulk_addr && as->status != -ECONNRESET &&
                        as->status != -ENOENT)
                cancel_bulk_urbs(ps, as->bulk_addr);
+
+       wake_up(&ps->wait);
        spin_unlock(&ps->lock);
 
        if (signr) {
@@ -430,8 +432,6 @@ static void async_completed(struct urb *urb)
                put_pid(pid);
                put_cred(cred);
        }
-
-       wake_up(&ps->wait);
 }
 
 static void destroy_async(struct dev_state *ps, struct list_head *list)
@@ -1093,14 +1093,18 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
        unsigned int u, totlen, isofrmlen;
        int ret, ifnum = -1;
        int is_in;
-
-       if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP |
-                               USBDEVFS_URB_SHORT_NOT_OK |
+       unsigned long mask =    USBDEVFS_URB_SHORT_NOT_OK |
                                USBDEVFS_URB_BULK_CONTINUATION |
                                USBDEVFS_URB_NO_FSBR |
                                USBDEVFS_URB_ZERO_PACKET |
-                               USBDEVFS_URB_NO_INTERRUPT))
-               return -EINVAL;
+                               USBDEVFS_URB_NO_INTERRUPT;
+       /* USBDEVFS_URB_ISO_ASAP is a special case */
+       if (uurb->type == USBDEVFS_URB_TYPE_ISO)
+               mask |= USBDEVFS_URB_ISO_ASAP;
+
+       if (uurb->flags & ~mask)
+                       return -EINVAL;
+
        if (uurb->buffer_length > 0 && !uurb->buffer)
                return -EINVAL;
        if (!(uurb->type == USBDEVFS_URB_TYPE_CONTROL &&
@@ -1402,6 +1406,18 @@ static int proc_unlinkurb(struct dev_state *ps, void __user *arg)
        return 0;
 }
 
+static void compute_isochronous_actual_length(struct urb *urb)
+{
+       unsigned int i;
+
+       if (urb->number_of_packets > 0) {
+               urb->actual_length = 0;
+               for (i = 0; i < urb->number_of_packets; i++)
+                       urb->actual_length +=
+                                       urb->iso_frame_desc[i].actual_length;
+       }
+}
+
 static int processcompl(struct async *as, void __user * __user *arg)
 {
        struct urb *urb = as->urb;
@@ -1409,6 +1425,7 @@ static int processcompl(struct async *as, void __user * __user *arg)
        void __user *addr = as->userurb;
        unsigned int i;
 
+       compute_isochronous_actual_length(urb);
        if (as->userbuffer && urb->actual_length) {
                if (urb->number_of_packets > 0)         /* Isochronous */
                        i = urb->transfer_buffer_length;
@@ -1581,6 +1598,7 @@ static int processcompl_compat(struct async *as, void __user * __user *arg)
        void __user *addr = as->userurb;
        unsigned int i;
 
+       compute_isochronous_actual_length(urb);
        if (as->userbuffer && urb->actual_length) {
                if (urb->number_of_packets > 0)         /* Isochronous */
                        i = urb->transfer_buffer_length;