[PATCH] usb: dwc2: gadget: stall handshakes returned by control pipes in status stage

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

 



From: Jun Chen <jun.chen@xxxxxxxxxx>

According to USB2.0 spec 8.5.3, "If the control sequence
has no Data stage, then it consists of a Setup stage
followed by a Status stage consisting of an IN transaction."

But when doing control read in some HOST (like MS Windows),
after a SETUP transaction with no Data stage, the sequence
stay in the Status stage of an OUT transaction until timeout.

This patch Stall both IN and OUT on ep0 in status stage,
fix the unhandling state when we got an error command
with zero length control read request.

It's also based on the USB2.0 spec 8.5.3.4,
"The protocol STALL condition lasts until the receipt of
the next SETUP transaction, and the function will return
STALL in response to any IN or OUT transaction on the pipe
until the SETUP transaction is received."

Signed-off-by: Jun Chen <jun.chen@xxxxxxxxxx>
---
 drivers/usb/dwc2/gadget.c | 33 ++++++++++++++++++++-------------
 1 file changed, 20 insertions(+), 13 deletions(-)

diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
index 6be10e496..73b5944 100644
--- a/drivers/usb/dwc2/gadget.c
+++ b/drivers/usb/dwc2/gadget.c
@@ -1853,23 +1853,30 @@ static void dwc2_hsotg_stall_ep0(struct dwc2_hsotg *hsotg)
 	struct dwc2_hsotg_ep *ep0 = hsotg->eps_out[0];
 	u32 reg;
 	u32 ctrl;
+	u32 direction;
 
-	dev_dbg(hsotg->dev, "ep0 stall (dir=%d)\n", ep0->dir_in);
-	reg = (ep0->dir_in) ? DIEPCTL0 : DOEPCTL0;
+	direction = ep0->dir_in;
+	do {
+		dev_dbg(hsotg->dev, "ep0 stall (dir=%d)\n", ep0->dir_in);
+		reg = (ep0->dir_in) ? DIEPCTL0 : DOEPCTL0;
 
-	/*
-	 * DxEPCTL_Stall will be cleared by EP once it has
-	 * taken effect, so no need to clear later.
-	 */
+		/*
+		 * DxEPCTL_Stall will be cleared by EP once it has
+		 * taken effect, so no need to clear later.
+		 */
 
-	ctrl = dwc2_readl(hsotg, reg);
-	ctrl |= DXEPCTL_STALL;
-	ctrl |= DXEPCTL_CNAK;
-	dwc2_writel(hsotg, ctrl, reg);
+		ctrl = dwc2_readl(hsotg, reg);
+		ctrl |= DXEPCTL_STALL;
+		ctrl |= DXEPCTL_CNAK;
+		dwc2_writel(hsotg, ctrl, reg);
 
-	dev_dbg(hsotg->dev,
-		"written DXEPCTL=0x%08x to %08x (DXEPCTL=0x%08x)\n",
-		ctrl, reg, dwc2_readl(hsotg, reg));
+		dev_dbg(hsotg->dev,
+			"written DXEPCTL=0x%08x to %08x (DXEPCTL=0x%08x)\n",
+			ctrl, reg, dwc2_readl(hsotg, reg));
+
+		if (hsotg->ep0_state == DWC2_EP0_STATUS_IN)
+			ep0->dir_in = (ep0->dir_in == 1) ? 0 : 1;
+	} while (ep0->dir_in != direction);
 
 	 /*
 	  * complete won't be called, so we enqueue
-- 
1.9.1




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

  Powered by Linux