diff options
author | Linux Build Service Account <lnxbuild@quicinc.com> | 2017-07-25 00:35:41 -0700 |
---|---|---|
committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2017-07-25 00:35:40 -0700 |
commit | 43a6d43b545084ba97d898ab6f2a4bf0918ac1f3 (patch) | |
tree | 58533990c308ec96d4f35b7e5146801618593d0c /drivers | |
parent | 48f499115ea4db7929dceb50947806c99da77bc2 (diff) | |
parent | 7f2ea4fd0c887de75eef2f9f1df2e779aaf14b49 (diff) |
Merge "usb: dwc3: gadget: handle request->zero"
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/usb/dwc3/core.h | 3 | ||||
-rw-r--r-- | drivers/usb/dwc3/gadget.c | 49 |
2 files changed, 50 insertions, 2 deletions
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 1b4fb562ce4b..927c84ea4921 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -39,6 +39,7 @@ #define DWC3_MSG_MAX 500 /* Global constants */ +#define DWC3_ZLP_BUF_SIZE 1024 /* size of a superspeed bulk */ #define DWC3_EP0_BOUNCE_SIZE 512 #define DWC3_ENDPOINTS_NUM 32 #define DWC3_XHCI_RESOURCES_NUM 2 @@ -748,6 +749,7 @@ struct dwc3_scratchpad_array { * @ctrl_req: usb control request which is used for ep0 * @ep0_trb: trb which is used for the ctrl_req * @ep0_bounce: bounce buffer for ep0 + * @zlp_buf: used when request->zero is set * @setup_buf: used while precessing STD USB requests * @ctrl_req_addr: dma address of ctrl_req * @ep0_trb: dma address of ep0_trb @@ -853,6 +855,7 @@ struct dwc3 { struct usb_ctrlrequest *ctrl_req; struct dwc3_trb *ep0_trb; void *ep0_bounce; + void *zlp_buf; void *scratchbuf; u8 *setup_buf; dma_addr_t ctrl_req_addr; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 658fcca485d8..646b47db88b5 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1340,6 +1340,32 @@ static bool dwc3_gadget_is_suspended(struct dwc3 *dwc) return false; } +static void __dwc3_gadget_ep_zlp_complete(struct usb_ep *ep, + struct usb_request *request) +{ + dwc3_gadget_ep_free_request(ep, request); +} + +static int __dwc3_gadget_ep_queue_zlp(struct dwc3 *dwc, struct dwc3_ep *dep) +{ + struct dwc3_request *req; + struct usb_request *request; + struct usb_ep *ep = &dep->endpoint; + + dwc3_trace(trace_dwc3_gadget, "queueing ZLP\n"); + request = dwc3_gadget_ep_alloc_request(ep, GFP_ATOMIC); + if (!request) + return -ENOMEM; + + request->length = 0; + request->buf = dwc->zlp_buf; + request->complete = __dwc3_gadget_ep_zlp_complete; + + req = to_dwc3_request(request); + + return __dwc3_gadget_ep_queue(dep, req); +} + static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request, gfp_t gfp_flags) { @@ -1387,6 +1413,15 @@ static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request, ret = __dwc3_gadget_ep_queue(dep, req); + /* + * Okay, here's the thing, if gadget driver has requested for a ZLP by + * setting request->zero, instead of doing magic, we will just queue an + * extra usb_request ourselves so that it gets handled the same way as + * any other request. + */ + if (ret == 0 && request->zero && (request->length % ep->maxpacket == 0)) + ret = __dwc3_gadget_ep_queue_zlp(dwc, dep); + out: spin_unlock_irqrestore(&dwc->lock, flags); @@ -3554,6 +3589,12 @@ int dwc3_gadget_init(struct dwc3 *dwc) goto err3; } + dwc->zlp_buf = kzalloc(DWC3_ZLP_BUF_SIZE, GFP_KERNEL); + if (!dwc->zlp_buf) { + ret = -ENOMEM; + goto err4; + } + dwc->gadget.ops = &dwc3_gadget_ops; dwc->gadget.speed = USB_SPEED_UNKNOWN; dwc->gadget.sg_supported = true; @@ -3595,12 +3636,12 @@ int dwc3_gadget_init(struct dwc3 *dwc) ret = dwc3_gadget_init_endpoints(dwc); if (ret) - goto err4; + goto err5; ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget); if (ret) { dev_err(dwc->dev, "failed to register udc\n"); - goto err4; + goto err5; } if (!dwc->is_drd) { @@ -3612,6 +3653,9 @@ int dwc3_gadget_init(struct dwc3 *dwc) return 0; +err5: + kfree(dwc->zlp_buf); + err4: dwc3_gadget_free_endpoints(dwc); dma_free_coherent(dwc->dev, DWC3_EP0_BOUNCE_SIZE, @@ -3649,6 +3693,7 @@ void dwc3_gadget_exit(struct dwc3 *dwc) dwc->ep0_bounce, dwc->ep0_bounce_addr); kfree(dwc->setup_buf); + kfree(dwc->zlp_buf); dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb) * 2, dwc->ep0_trb, dwc->ep0_trb_addr); |