diff options
author | Ingo Molnar <mingo@elte.hu> | 2010-10-25 19:38:43 +0200 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2010-10-25 19:38:52 +0200 |
commit | 7d7a48b76012eeee25871e1d69104dec4b6d740f (patch) | |
tree | c27e3d8bb2e80ad93c7b4a5c850e1ffbc090bcd2 /drivers/usb/host/uhci-q.c | |
parent | e4072a9a9d186fe86293effe8828faa4be75b4a4 (diff) | |
parent | 229aebb873e29726b91e076161649cf45154b0bf (diff) |
Merge branch 'linus' into x86/urgent
Merge reason: We want to queue up a dependent fix.
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'drivers/usb/host/uhci-q.c')
-rw-r--r-- | drivers/usb/host/uhci-q.c | 33 |
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 |