]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/usb/host/uhci-q.c
Merge tag 'v2.6.37' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[mv-sheeva.git] / drivers / usb / host / uhci-q.c
index d3ade4018487187fd986766bce8a5135979a95e8..2090b45eb6067eb14aee9f26f57b6622355fd3e9 100644 (file)
@@ -917,10 +917,13 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
        unsigned long destination, status;
        int maxsze = le16_to_cpu(qh->hep->desc.wMaxPacketSize);
        int len = urb->transfer_buffer_length;
-       dma_addr_t data = urb->transfer_dma;
+       int this_sg_len;
+       dma_addr_t data;
        __le32 *plink;
        struct urb_priv *urbp = urb->hcpriv;
        unsigned int toggle;
+       struct scatterlist  *sg;
+       int i;
 
        if (len < 0)
                return -EINVAL;
@@ -937,12 +940,26 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
        if (usb_pipein(urb->pipe))
                status |= TD_CTRL_SPD;
 
+       i = urb->num_sgs;
+       if (len > 0 && i > 0) {
+               sg = urb->sg;
+               data = sg_dma_address(sg);
+
+               /* urb->transfer_buffer_length may be smaller than the
+                * size of the scatterlist (or vice versa)
+                */
+               this_sg_len = min_t(int, sg_dma_len(sg), len);
+       } else {
+               sg = NULL;
+               data = urb->transfer_dma;
+               this_sg_len = len;
+       }
        /*
         * Build the DATA TDs
         */
        plink = NULL;
        td = qh->dummy_td;
-       do {    /* Allow zero length packets */
+       for (;;) {      /* Allow zero length packets */
                int pktsze = maxsze;
 
                if (len <= pktsze) {            /* The last packet */
@@ -965,10 +982,18 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
                plink = &td->link;
                status |= TD_CTRL_ACTIVE;
 
+               toggle ^= 1;
                data += pktsze;
+               this_sg_len -= pktsze;
                len -= maxsze;
-               toggle ^= 1;
-       } while (len > 0);
+               if (this_sg_len <= 0) {
+                       if (--i <= 0 || len <= 0)
+                               break;
+                       sg = sg_next(sg);
+                       data = sg_dma_address(sg);
+                       this_sg_len = min_t(int, sg_dma_len(sg), len);
+               }
+       }
 
        /*
         * URB_ZERO_PACKET means adding a 0-length packet, if direction