usb: dwc3: gadget: Submit endxfer command if delayed during disconnect
authorWesley Cheng <quic_wcheng@quicinc.com>
Thu, 1 Sep 2022 19:36:25 +0000 (12:36 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 7 Sep 2022 14:26:45 +0000 (16:26 +0200)
During a cable disconnect sequence, if ep0state is not in the SETUP phase,
then nothing will trigger any pending end transfer commands.  Force
stopping of any pending SETUP transaction, and move back to the SETUP
phase.

Reviewed-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
Signed-off-by: Wesley Cheng <quic_wcheng@quicinc.com>
Link: https://lore.kernel.org/r/20220901193625.8727-6-quic_wcheng@quicinc.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/dwc3/gadget.c

index 0149c9106752c1d40e56be1179bafbb15985171c..b75e1b8b3f054c4709b27b8f8b998b3585320433 100644 (file)
@@ -3778,13 +3778,24 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
        reg &= ~DWC3_DCTL_INITU2ENA;
        dwc3_gadget_dctl_write_safe(dwc, reg);
 
+       dwc->connected = false;
+
        dwc3_disconnect_gadget(dwc);
 
        dwc->gadget->speed = USB_SPEED_UNKNOWN;
        dwc->setup_packet_pending = false;
        usb_gadget_set_state(dwc->gadget, USB_STATE_NOTATTACHED);
 
-       dwc->connected = false;
+       if (dwc->ep0state != EP0_SETUP_PHASE) {
+               unsigned int    dir;
+
+               dir = !!dwc->ep0_expect_in;
+               if (dwc->ep0state == EP0_DATA_PHASE)
+                       dwc3_ep0_end_control_data(dwc, dwc->eps[dir]);
+               else
+                       dwc3_ep0_end_control_data(dwc, dwc->eps[!dir]);
+               dwc3_ep0_stall_and_restart(dwc);
+       }
 }
 
 static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)