diff options
-rw-r--r-- | drivers/usb/host/ehci-hcd.c | 2 | ||||
-rw-r--r-- | drivers/usb/host/ehci-q.c | 32 |
2 files changed, 29 insertions, 5 deletions
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 2a3265087ef..5859522d6ed 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c | |||
@@ -605,6 +605,8 @@ static int ehci_init(struct usb_hcd *hcd) | |||
605 | } | 605 | } |
606 | ehci->command = temp; | 606 | ehci->command = temp; |
607 | 607 | ||
608 | /* Accept arbitrarily long scatter-gather lists */ | ||
609 | hcd->self.sg_tablesize = ~0; | ||
608 | return 0; | 610 | return 0; |
609 | } | 611 | } |
610 | 612 | ||
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 139a2cc3f64..a427d3b0063 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c | |||
@@ -616,9 +616,11 @@ qh_urb_transaction ( | |||
616 | ) { | 616 | ) { |
617 | struct ehci_qtd *qtd, *qtd_prev; | 617 | struct ehci_qtd *qtd, *qtd_prev; |
618 | dma_addr_t buf; | 618 | dma_addr_t buf; |
619 | int len, maxpacket; | 619 | int len, this_sg_len, maxpacket; |
620 | int is_input; | 620 | int is_input; |
621 | u32 token; | 621 | u32 token; |
622 | int i; | ||
623 | struct scatterlist *sg; | ||
622 | 624 | ||
623 | /* | 625 | /* |
624 | * URBs map to sequences of QTDs: one logical transaction | 626 | * URBs map to sequences of QTDs: one logical transaction |
@@ -659,7 +661,20 @@ qh_urb_transaction ( | |||
659 | /* | 661 | /* |
660 | * data transfer stage: buffer setup | 662 | * data transfer stage: buffer setup |
661 | */ | 663 | */ |
662 | buf = urb->transfer_dma; | 664 | i = urb->num_sgs; |
665 | if (len > 0 && i > 0) { | ||
666 | sg = urb->sg->sg; | ||
667 | buf = sg_dma_address(sg); | ||
668 | |||
669 | /* urb->transfer_buffer_length may be smaller than the | ||
670 | * size of the scatterlist (or vice versa) | ||
671 | */ | ||
672 | this_sg_len = min_t(int, sg_dma_len(sg), len); | ||
673 | } else { | ||
674 | sg = NULL; | ||
675 | buf = urb->transfer_dma; | ||
676 | this_sg_len = len; | ||
677 | } | ||
663 | 678 | ||
664 | if (is_input) | 679 | if (is_input) |
665 | token |= (1 /* "in" */ << 8); | 680 | token |= (1 /* "in" */ << 8); |
@@ -675,7 +690,9 @@ qh_urb_transaction ( | |||
675 | for (;;) { | 690 | for (;;) { |
676 | int this_qtd_len; | 691 | int this_qtd_len; |
677 | 692 | ||
678 | this_qtd_len = qtd_fill(ehci, qtd, buf, len, token, maxpacket); | 693 | this_qtd_len = qtd_fill(ehci, qtd, buf, this_sg_len, token, |
694 | maxpacket); | ||
695 | this_sg_len -= this_qtd_len; | ||
679 | len -= this_qtd_len; | 696 | len -= this_qtd_len; |
680 | buf += this_qtd_len; | 697 | buf += this_qtd_len; |
681 | 698 | ||
@@ -691,8 +708,13 @@ qh_urb_transaction ( | |||
691 | if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0) | 708 | if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0) |
692 | token ^= QTD_TOGGLE; | 709 | token ^= QTD_TOGGLE; |
693 | 710 | ||
694 | if (likely (len <= 0)) | 711 | if (likely(this_sg_len <= 0)) { |
695 | break; | 712 | if (--i <= 0 || len <= 0) |
713 | break; | ||
714 | sg = sg_next(sg); | ||
715 | buf = sg_dma_address(sg); | ||
716 | this_sg_len = min_t(int, sg_dma_len(sg), len); | ||
717 | } | ||
696 | 718 | ||
697 | qtd_prev = qtd; | 719 | qtd_prev = qtd; |
698 | qtd = ehci_qtd_alloc (ehci, flags); | 720 | qtd = ehci_qtd_alloc (ehci, flags); |