diff options
author | Ming Lei <tom.leiming@gmail.com> | 2010-09-30 08:32:44 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-10-22 13:22:00 -0400 |
commit | 689d6eacd1b7c3677bfe6ee367766f21c3c80e26 (patch) | |
tree | 2524c96c3e6dbd6244292a2a4d0ba769564d5ecf /drivers/usb/host | |
parent | 00be545e49d83485d49a598d3b7e090088934be8 (diff) |
USB: UHCI: add native scatter-gather support(v1)
This patch adds native scatter-gather support to uhci-hcd.
Reviewed-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Ming Lei <tom.leiming@gmail.com>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host')
-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 d3ade4018487..2090b45eb606 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, | |||
917 | unsigned long destination, status; | 917 | unsigned long destination, status; |
918 | int maxsze = le16_to_cpu(qh->hep->desc.wMaxPacketSize); | 918 | int maxsze = le16_to_cpu(qh->hep->desc.wMaxPacketSize); |
919 | int len = urb->transfer_buffer_length; | 919 | int len = urb->transfer_buffer_length; |
920 | dma_addr_t data = urb->transfer_dma; | 920 | int this_sg_len; |
921 | dma_addr_t data; | ||
921 | __le32 *plink; | 922 | __le32 *plink; |
922 | struct urb_priv *urbp = urb->hcpriv; | 923 | struct urb_priv *urbp = urb->hcpriv; |
923 | unsigned int toggle; | 924 | unsigned int toggle; |
925 | struct scatterlist *sg; | ||
926 | int i; | ||
924 | 927 | ||
925 | if (len < 0) | 928 | if (len < 0) |
926 | return -EINVAL; | 929 | return -EINVAL; |
@@ -937,12 +940,26 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, | |||
937 | if (usb_pipein(urb->pipe)) | 940 | if (usb_pipein(urb->pipe)) |
938 | status |= TD_CTRL_SPD; | 941 | status |= TD_CTRL_SPD; |
939 | 942 | ||
943 | i = urb->num_sgs; | ||
944 | if (len > 0 && i > 0) { | ||
945 | sg = urb->sg; | ||
946 | data = sg_dma_address(sg); | ||
947 | |||
948 | /* urb->transfer_buffer_length may be smaller than the | ||
949 | * size of the scatterlist (or vice versa) | ||
950 | */ | ||
951 | this_sg_len = min_t(int, sg_dma_len(sg), len); | ||
952 | } else { | ||
953 | sg = NULL; | ||
954 | data = urb->transfer_dma; | ||
955 | this_sg_len = len; | ||
956 | } | ||
940 | /* | 957 | /* |
941 | * Build the DATA TDs | 958 | * Build the DATA TDs |
942 | */ | 959 | */ |
943 | plink = NULL; | 960 | plink = NULL; |
944 | td = qh->dummy_td; | 961 | td = qh->dummy_td; |
945 | do { /* Allow zero length packets */ | 962 | for (;;) { /* Allow zero length packets */ |
946 | int pktsze = maxsze; | 963 | int pktsze = maxsze; |
947 | 964 | ||
948 | if (len <= pktsze) { /* The last packet */ | 965 | if (len <= pktsze) { /* The last packet */ |
@@ -965,10 +982,18 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, | |||
965 | plink = &td->link; | 982 | plink = &td->link; |
966 | status |= TD_CTRL_ACTIVE; | 983 | status |= TD_CTRL_ACTIVE; |
967 | 984 | ||
985 | toggle ^= 1; | ||
968 | data += pktsze; | 986 | data += pktsze; |
987 | this_sg_len -= pktsze; | ||
969 | len -= maxsze; | 988 | len -= maxsze; |
970 | toggle ^= 1; | 989 | if (this_sg_len <= 0) { |
971 | } while (len > 0); | 990 | if (--i <= 0 || len <= 0) |
991 | break; | ||
992 | sg = sg_next(sg); | ||
993 | data = sg_dma_address(sg); | ||
994 | this_sg_len = min_t(int, sg_dma_len(sg), len); | ||
995 | } | ||
996 | } | ||
972 | 997 | ||
973 | /* | 998 | /* |
974 | * URB_ZERO_PACKET means adding a 0-length packet, if direction | 999 | * URB_ZERO_PACKET means adding a 0-length packet, if direction |