[PATCH] usb: dwc3: ep0: Handle variable-length Data Stage

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



In accordance with specification, when sent data length is
an exact multiple of wMaxPacketSize for the pipe and less
than requested by host, the function shall return a zero-length
packet (ZLP) to indicate the end of the Data stage to a USB host.

Signed-off-by: Anton Tikhomirov <av.tikhomirov@xxxxxxxxxxx>
---
 drivers/usb/dwc3/core.h   |    2 ++
 drivers/usb/dwc3/ep0.c    |   27 ++++++++++++++++++++-------
 drivers/usb/dwc3/gadget.c |    3 +++
 3 files changed, 25 insertions(+), 7 deletions(-)

diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index f8af8d4..fefbf2d 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -619,6 +619,7 @@ struct dwc3_scratchpad_array {
  * @three_stage_setup: set if we perform a three phase setup
  * @ep0_bounced: true when we used bounce buffer
  * @ep0_expect_in: true when we expect a DATA IN transfer
+ * @ep0_zlp_sent: true when ZLP was sent
  * @start_config_issued: true when StartConfig command has been issued
  * @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround
  * @needs_fifo_resize: not all users might want fifo resizing, flag it
@@ -700,6 +701,7 @@ struct dwc3 {
 	unsigned		three_stage_setup:1;
 	unsigned		ep0_bounced:1;
 	unsigned		ep0_expect_in:1;
+	unsigned		ep0_zlp_sent:1;
 	unsigned		start_config_issued:1;
 	unsigned		setup_packet_pending:1;
 	unsigned		delayed_status:1;
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index 21a3520..cf72561 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -782,6 +782,9 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
 		return;
 	}
 
+	if (dwc->ep0_zlp_sent)
+		goto finish_zlp;
+
 	length = trb->size & DWC3_TRB_SIZE_MASK;
 
 	if (dwc->ep0_bounced) {
@@ -802,14 +805,24 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
 		/* for some reason we did not get everything out */
 
 		dwc3_ep0_stall_and_restart(dwc);
-	} else {
-		/*
-		 * handle the case where we have to send a zero packet. This
-		 * seems to be case when req.length > maxpacket. Could it be?
-		 */
-		if (r)
-			dwc3_gadget_giveback(ep0, r, 0);
+		return;
 	}
+
+	/* handle the case where we have to send a zero packet */
+	if ((epnum & 1) && ur->zero &&
+	    (ur->length % ep0->endpoint.maxpacket == 0)) {
+		int ret;
+
+		ret = dwc3_ep0_start_trans(dwc, epnum, dwc->ctrl_req_addr, 0,
+				DWC3_TRBCTL_CONTROL_DATA);
+		WARN_ON(ret < 0);
+		dwc->ep0_zlp_sent = 1;
+		return;
+	}
+
+finish_zlp:
+	if (r)
+		dwc3_gadget_giveback(ep0, r, 0);
 }
 
 static void dwc3_ep0_complete_status(struct dwc3 *dwc,
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 02e44fc..59ecd1e 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -251,6 +251,9 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
 		usb_gadget_unmap_request(&dwc->gadget, &req->request,
 				req->direction);
 
+	if (dwc->ep0_zlp_sent && dep->number == 0)
+		dwc->ep0_zlp_sent = 0;
+
 	dev_dbg(dwc->dev, "request %p from %s completed %d/%d ===> %d\n",
 			req, dep->name, req->request.actual,
 			req->request.length, status);
-- 
1.7.9.5


--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux