aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/dwc3
diff options
context:
space:
mode:
authorFelipe Balbi <balbi@ti.com>2011-08-27 22:18:09 +0300
committerFelipe Balbi <balbi@ti.com>2011-09-09 13:02:05 +0300
commita6829706ce0bae7e4623ea987a639d91a721eee2 (patch)
tree094bcdbe1c8588c85d45cadfec91782f884614c6 /drivers/usb/dwc3
parentusb: dwc3: add a bounce buffer for control endpoints (diff)
downloadlinux-dev-a6829706ce0bae7e4623ea987a639d91a721eee2.tar.xz
linux-dev-a6829706ce0bae7e4623ea987a639d91a721eee2.zip
usb: dwc3: ep0: add handling for unaligned OUT transfers
In case we have transfers which aren't aligned to wMaxPacketSize, we need to be careful with how we start the transfer with the HW. OUT transfers _must_ be aligned with wMaxPacketSize and in order to guarantee that, we use a bounce buffer. Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/dwc3')
-rw-r--r--drivers/usb/dwc3/ep0.c37
1 files changed, 32 insertions, 5 deletions
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index a6fc5c316743..f1e0a5eb0544 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -185,10 +185,29 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,
req->epnum = dep->number;
list_add_tail(&req->list, &dep->request_list);
- dwc3_map_buffer_to_dma(req);
+ if (req->request.length == 0) {
+ ret = dwc3_ep0_start_trans(dwc, dep->number,
+ dwc->ctrl_req_addr, 0);
+ } else if ((req->request.length % dep->endpoint.maxpacket)
+ && (dep->number == 0)) {
+ dwc->ep0_bounced = true;
+
+ WARN_ON(req->request.length > dep->endpoint.maxpacket);
+
+ /*
+ * REVISIT in case request length is bigger than EP0
+ * wMaxPacketSize, we will need two chained TRBs to handle
+ * the transfer.
+ */
+ ret = dwc3_ep0_start_trans(dwc, dep->number,
+ dwc->ep0_bounce_addr, dep->endpoint.maxpacket);
+ } else {
+ dwc3_map_buffer_to_dma(req);
+
+ ret = dwc3_ep0_start_trans(dwc, dep->number,
+ req->request.dma, req->request.length);
+ }
- ret = dwc3_ep0_start_trans(dwc, dep->number, req->request.dma,
- req->request.length);
if (ret < 0) {
list_del(&req->list);
dwc3_unmap_buffer_from_dma(req);
@@ -655,8 +674,16 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
dwc3_trb_to_nat(dwc->ep0_trb, &trb);
- transferred = ur->length - trb.length;
- ur->actual += transferred;
+ if (dwc->ep0_bounced) {
+ struct dwc3_ep *ep0 = dwc->eps[0];
+
+ transferred = min(ur->length, dep->endpoint.maxpacket - trb.length);
+ memcpy(ur->buf, dwc->ep0_bounce, transferred);
+ dwc->ep0_bounced = false;
+ } else {
+ transferred = ur->length - trb.length;
+ ur->actual += transferred;
+ }
if ((epnum & 1) && ur->actual < ur->length) {
/* for some reason we did not get everything out */