aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/host/uhci-q.c
diff options
context:
space:
mode:
authorDavid Woodhouse <David.Woodhouse@intel.com>2010-10-30 12:35:11 +0100
committerDavid Woodhouse <David.Woodhouse@intel.com>2010-10-30 12:35:11 +0100
commit67577927e8d7a1f4b09b4992df640eadc6aacb36 (patch)
tree2e9efe6b5745965faf0dcc084d4613d9356263f9 /drivers/usb/host/uhci-q.c
parent6fe4c590313133ebd5dadb769031489ff178ece1 (diff)
parent51f00a471ce8f359627dd99aeac322947a0e491b (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
Conflicts: drivers/mtd/mtd_blkdevs.c Merge Grant's device-tree bits so that we can apply the subsequent fixes. Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/usb/host/uhci-q.c')
-rw-r--r--drivers/usb/host/uhci-q.c33
1 files changed, 29 insertions, 4 deletions
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index d3ade401848..2090b45eb60 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -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