[v5] usb: dwc2/gadget: rework disconnect event handling

Message ID 1416214782-13911-1-git-send-email-m.szyprowski@samsung.com
State New
Headers show

Commit Message

Marek Szyprowski Nov. 17, 2014, 8:59 a.m.
This patch adds a call to s3c_hsotg_disconnect() from 'end session'
interrupt (GOTGINT_SES_END_DET) to correctly notify gadget subsystem
about unplugged usb cable. DISCONNINT interrupt cannot be used for this
purpose, because it is asserted only in host mode.

To avoid reporting disconnect event more than once, a disconnect call has
been moved from USB_REQ_SET_ADDRESS handling function to SESSREQINT
interrupt. This way driver ensures that disconnect event is reported
either when usb cable is unplugged or every time the host starts a new
session. To handle devices which has been synthesized without
SRP support, connected state is set in ENUMDONE interrupt.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
 drivers/usb/dwc2/core.h   |  1 +
 drivers/usb/dwc2/gadget.c | 16 ++++++++++++++--
 2 files changed, 15 insertions(+), 2 deletions(-)

Comments

Paul Zimmerman Nov. 18, 2014, 8:56 p.m. | #1
> From: Marek Szyprowski [mailto:m.szyprowski@samsung.com]
> Sent: Monday, November 17, 2014 1:00 AM
> 
> This patch adds a call to s3c_hsotg_disconnect() from 'end session'
> interrupt (GOTGINT_SES_END_DET) to correctly notify gadget subsystem
> about unplugged usb cable. DISCONNINT interrupt cannot be used for this
> purpose, because it is asserted only in host mode.
> 
> To avoid reporting disconnect event more than once, a disconnect call has
> been moved from USB_REQ_SET_ADDRESS handling function to SESSREQINT
> interrupt. This way driver ensures that disconnect event is reported
> either when usb cable is unplugged or every time the host starts a new
> session. To handle devices which has been synthesized without
> SRP support, connected state is set in ENUMDONE interrupt.
> 
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> ---
>  drivers/usb/dwc2/core.h   |  1 +
>  drivers/usb/dwc2/gadget.c | 16 ++++++++++++++--
>  2 files changed, 15 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
> index 55c90c53f2d6..e54c3c50cd48 100644
> --- a/drivers/usb/dwc2/core.h
> +++ b/drivers/usb/dwc2/core.h
> @@ -210,6 +210,7 @@ struct s3c_hsotg {
>  	u8                      ctrl_buff[8];
> 
>  	struct usb_gadget       gadget;
> +	unsigned int		connected:1;
>  	unsigned int            setup;
>  	unsigned long           last_rst;
>  	struct s3c_hsotg_ep     *eps;
> diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
> index fcd2bb55ccca..89b1bea50ee3 100644
> --- a/drivers/usb/dwc2/gadget.c
> +++ b/drivers/usb/dwc2/gadget.c
> @@ -1029,7 +1029,6 @@ static int s3c_hsotg_process_req_feature(struct s3c_hsotg *hsotg,
>  }
> 
>  static void s3c_hsotg_enqueue_setup(struct s3c_hsotg *hsotg);
> -static void s3c_hsotg_disconnect(struct s3c_hsotg *hsotg);
> 
>  /**
>   * s3c_hsotg_stall_ep0 - stall ep0
> @@ -1107,7 +1106,6 @@ static void s3c_hsotg_process_control(struct s3c_hsotg *hsotg,
>  	if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
>  		switch (ctrl->bRequest) {
>  		case USB_REQ_SET_ADDRESS:
> -			s3c_hsotg_disconnect(hsotg);
>  			dcfg = readl(hsotg->regs + DCFG);
>  			dcfg &= ~DCFG_DEVADDR_MASK;
>  			dcfg |= (le16_to_cpu(ctrl->wValue) <<
> @@ -2031,6 +2029,10 @@ static void s3c_hsotg_disconnect(struct s3c_hsotg *hsotg)
>  {
>  	unsigned ep;
> 
> +	if (!hsotg->connected)
> +		return;
> +
> +	hsotg->connected = 0;
>  	for (ep = 0; ep < hsotg->num_of_eps; ep++)
>  		kill_all_requests(hsotg, &hsotg->eps[ep], -ESHUTDOWN, true);
> 
> @@ -2290,17 +2292,27 @@ irq_retry:
>  		dev_info(hsotg->dev, "OTGInt: %08x\n", otgint);
> 
>  		writel(otgint, hsotg->regs + GOTGINT);
> +
> +		if (otgint & GOTGINT_SES_END_DET) {
> +			s3c_hsotg_disconnect(hsotg);
> +			hsotg->gadget.speed = USB_SPEED_UNKNOWN;
> +		}
>  	}
> 
>  	if (gintsts & GINTSTS_SESSREQINT) {
>  		dev_dbg(hsotg->dev, "%s: SessReqInt\n", __func__);
>  		writel(GINTSTS_SESSREQINT, hsotg->regs + GINTSTS);
> +		/*
> +		 * Report disconnect if there is any previous session established
> +		 */
> +		s3c_hsotg_disconnect(hsotg);
>  	}
> 
>  	if (gintsts & GINTSTS_ENUMDONE) {
>  		writel(GINTSTS_ENUMDONE, hsotg->regs + GINTSTS);
> 
>  		s3c_hsotg_irq_enumdone(hsotg);
> +		hsotg->connected = 1;
>  	}
> 
>  	if (gintsts & GINTSTS_CONIDSTSCHNG) {

Acked-by: Paul Zimmerman <paulz@synopsys.com>

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Felipe Balbi Nov. 20, 2014, 7:53 p.m. | #2
On Mon, Nov 17, 2014 at 09:59:42AM +0100, Marek Szyprowski wrote:
> This patch adds a call to s3c_hsotg_disconnect() from 'end session'
> interrupt (GOTGINT_SES_END_DET) to correctly notify gadget subsystem
> about unplugged usb cable. DISCONNINT interrupt cannot be used for this
> purpose, because it is asserted only in host mode.
> 
> To avoid reporting disconnect event more than once, a disconnect call has
> been moved from USB_REQ_SET_ADDRESS handling function to SESSREQINT
> interrupt. This way driver ensures that disconnect event is reported
> either when usb cable is unplugged or every time the host starts a new
> session. To handle devices which has been synthesized without
> SRP support, connected state is set in ENUMDONE interrupt.
> 
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>

doesn't apply, please rebase on my testing/next:

checking file drivers/usb/dwc2/core.h
Hunk #1 FAILED at 210.
1 out of 1 hunk FAILED
checking file drivers/usb/dwc2/gadget.c
Hunk #1 FAILED at 1029.
Hunk #2 succeeded at 1108 (offset 1 line).
Hunk #3 succeeded at 2031 (offset 1 line).
Hunk #4 FAILED at 2293.
2 out of 4 hunks FAILED

thanks

Patch

diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
index 55c90c53f2d6..e54c3c50cd48 100644
--- a/drivers/usb/dwc2/core.h
+++ b/drivers/usb/dwc2/core.h
@@ -210,6 +210,7 @@  struct s3c_hsotg {
 	u8                      ctrl_buff[8];
 
 	struct usb_gadget       gadget;
+	unsigned int		connected:1;
 	unsigned int            setup;
 	unsigned long           last_rst;
 	struct s3c_hsotg_ep     *eps;
diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
index fcd2bb55ccca..89b1bea50ee3 100644
--- a/drivers/usb/dwc2/gadget.c
+++ b/drivers/usb/dwc2/gadget.c
@@ -1029,7 +1029,6 @@  static int s3c_hsotg_process_req_feature(struct s3c_hsotg *hsotg,
 }
 
 static void s3c_hsotg_enqueue_setup(struct s3c_hsotg *hsotg);
-static void s3c_hsotg_disconnect(struct s3c_hsotg *hsotg);
 
 /**
  * s3c_hsotg_stall_ep0 - stall ep0
@@ -1107,7 +1106,6 @@  static void s3c_hsotg_process_control(struct s3c_hsotg *hsotg,
 	if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
 		switch (ctrl->bRequest) {
 		case USB_REQ_SET_ADDRESS:
-			s3c_hsotg_disconnect(hsotg);
 			dcfg = readl(hsotg->regs + DCFG);
 			dcfg &= ~DCFG_DEVADDR_MASK;
 			dcfg |= (le16_to_cpu(ctrl->wValue) <<
@@ -2031,6 +2029,10 @@  static void s3c_hsotg_disconnect(struct s3c_hsotg *hsotg)
 {
 	unsigned ep;
 
+	if (!hsotg->connected)
+		return;
+
+	hsotg->connected = 0;
 	for (ep = 0; ep < hsotg->num_of_eps; ep++)
 		kill_all_requests(hsotg, &hsotg->eps[ep], -ESHUTDOWN, true);
 
@@ -2290,17 +2292,27 @@  irq_retry:
 		dev_info(hsotg->dev, "OTGInt: %08x\n", otgint);
 
 		writel(otgint, hsotg->regs + GOTGINT);
+
+		if (otgint & GOTGINT_SES_END_DET) {
+			s3c_hsotg_disconnect(hsotg);
+			hsotg->gadget.speed = USB_SPEED_UNKNOWN;
+		}
 	}
 
 	if (gintsts & GINTSTS_SESSREQINT) {
 		dev_dbg(hsotg->dev, "%s: SessReqInt\n", __func__);
 		writel(GINTSTS_SESSREQINT, hsotg->regs + GINTSTS);
+		/*
+		 * Report disconnect if there is any previous session established
+		 */
+		s3c_hsotg_disconnect(hsotg);
 	}
 
 	if (gintsts & GINTSTS_ENUMDONE) {
 		writel(GINTSTS_ENUMDONE, hsotg->regs + GINTSTS);
 
 		s3c_hsotg_irq_enumdone(hsotg);
+		hsotg->connected = 1;
 	}
 
 	if (gintsts & GINTSTS_CONIDSTSCHNG) {