|
@@ -1159,6 +1159,32 @@ out:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+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)
|
|
|
{
|
|
@@ -1172,6 +1198,16 @@ static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
|
|
|
|
|
|
spin_lock_irqsave(&dwc->lock, flags);
|
|
|
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);
|
|
|
+
|
|
|
spin_unlock_irqrestore(&dwc->lock, flags);
|
|
|
|
|
|
return ret;
|
|
@@ -2744,6 +2780,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;
|
|
@@ -2785,16 +2827,19 @@ 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;
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
+err5:
|
|
|
+ kfree(dwc->zlp_buf);
|
|
|
+
|
|
|
err4:
|
|
|
dwc3_gadget_free_endpoints(dwc);
|
|
|
dma_free_coherent(dwc->dev, DWC3_EP0_BOUNCE_SIZE,
|
|
@@ -2827,6 +2872,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),
|
|
|
dwc->ep0_trb, dwc->ep0_trb_addr);
|