[PATCH 9/9] USB:s3c-hsotg: Cable disconnection recovery code

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

 



This code allows Samsung SoC's to recover its state when
device is disconnected and connected during transfer.

It is necessary, in such a scenario, to reinitialize the USB core
to assure correct initial state of the driver.

A simple mechanism with jiffies has been used to perform core reset
only once.

Tested with:
- DFU gadget (various size of the sent data - also packet = MPS)
- Ethernet gadget (CDC and RNDIS)
- Multi Function Gadget (g_multi)

HW:
- Samsung's C210 Universal rev.0

Signed-off-by: Lukasz Majewski <l.majewski@xxxxxxxxxxx>
Signed-off-by: Kyungmin Park <kyungmin.park@xxxxxxxxxxx>
---
 drivers/usb/gadget/s3c-hsotg.c |   30 +++++++++++++++++++-----------
 1 files changed, 19 insertions(+), 11 deletions(-)

diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c
index 02a3142..ad2ecce 100644
--- a/drivers/usb/gadget/s3c-hsotg.c
+++ b/drivers/usb/gadget/s3c-hsotg.c
@@ -144,7 +144,8 @@ struct s3c_hsotg_ep {
  * @ep0_buff: Buffer for EP0 reply data, if needed.
  * @ctrl_buff: Buffer for EP0 control requests.
  * @ctrl_req: Request for EP0 control packets.
- * @setup: NAK management for EP0 SETUP 
+ * @setup: NAK management for EP0 SETUP
+ * @last_rst: Time of last reset
  * @eps: The endpoints being supplied to the gadget framework
  */
 struct s3c_hsotg {
@@ -175,6 +176,7 @@ struct s3c_hsotg {
 
 	struct usb_gadget	gadget;
 	unsigned int		setup;
+	unsigned long           last_rst;
 	struct s3c_hsotg_ep	eps[];
 };
 
@@ -2391,23 +2393,26 @@ irq_retry:
 	}
 
 	if (gintsts & S3C_GINTSTS_USBRst) {
+
+		u32 usb_status = readl(hsotg->regs + S3C_GOTGCTL);
+
 		dev_info(hsotg->dev, "%s: USBRst\n", __func__);
 		dev_dbg(hsotg->dev, "GNPTXSTS=%08x\n",
 			readl(hsotg->regs + S3C_GNPTXSTS));
 
 		writel(S3C_GINTSTS_USBRst, hsotg->regs + S3C_GINTSTS);
 
-		kill_all_requests(hsotg, &hsotg->eps[0], -ECONNRESET, true);
+		if (usb_status & S3C_GOTGCTL_BSESVLD) {
+			if (time_after(jiffies, hsotg->last_rst +
+				       msecs_to_jiffies(200))) {
 
-		/* it seems after a reset we can end up with a situation
-		 * where the TXFIFO still has data in it... the docs
-		 * suggest resetting all the fifos, so use the init_fifo
-		 * code to relayout and flush the fifos.
-		 */
+				kill_all_requests(hsotg, &hsotg->eps[0],
+							  -ECONNRESET, true);
 
-		s3c_hsotg_init_fifo(hsotg);
-
-		s3c_hsotg_enqueue_setup(hsotg);
+				s3c_hsotg_core_init(hsotg);
+				hsotg->last_rst = jiffies;
+			}
+		}
 	}
 
 	/* check both FIFOs */
@@ -2450,6 +2455,7 @@ irq_retry:
 		writel(S3C_GINTSTS_USBSusp, hsotg->regs + S3C_GINTSTS);
 
 		call_gadget(hsotg, suspend);
+		s3c_hsotg_disconnect(hsotg);
 	}
 
 	if (gintsts & S3C_GINTSTS_WkUpInt) {
@@ -2462,6 +2468,8 @@ irq_retry:
 	if (gintsts & S3C_GINTSTS_ErlySusp) {
 		dev_dbg(hsotg->dev, "S3C_GINTSTS_ErlySusp\n");
 		writel(S3C_GINTSTS_ErlySusp, hsotg->regs + S3C_GINTSTS);
+
+		s3c_hsotg_disconnect(hsotg);
 	}
 
 	/* these next two seem to crop-up occasionally causing the core
@@ -2804,7 +2812,7 @@ static int s3c_hsotg_start(struct usb_gadget_driver *driver,
 	}
 
 	s3c_hsotg_core_init(hsotg);
-
+	hsotg->last_rst = jiffies;
 	dev_info(hsotg->dev, "bound driver %s\n", driver->driver.name);
 	return 0;
 
-- 
1.7.2.3

--
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