diff options
Diffstat (limited to 'drivers/usb/dwc3/ep0.c')
-rw-r--r-- | drivers/usb/dwc3/ep0.c | 35 |
1 files changed, 35 insertions, 0 deletions
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 24b447e40bc..36482f45b3b 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -733,6 +733,41 @@ static void dwc3_ep0_do_control_status(struct dwc3 *dwc, static void dwc3_ep0_xfernotready(struct dwc3 *dwc, const struct dwc3_event_depevt *event) { + /* + * This part is very tricky: If we has just handled + * XferNotReady(Setup) and we're now expecting a + * XferComplete but, instead, we receive another + * XferNotReady(Setup), we should STALL and restart + * the state machine. + * + * In all other cases, we just continue waiting + * for the XferComplete event. + * + * We are a little bit unsafe here because we're + * not trying to ensure that last event was, indeed, + * XferNotReady(Setup). + * + * Still, we don't expect any condition where that + * should happen and, even if it does, it would be + * another error condition. + */ + if (dwc->ep0_next_event == DWC3_EP0_COMPLETE) { + switch (event->status) { + case DEPEVT_STATUS_CONTROL_SETUP: + dev_vdbg(dwc->dev, "Unexpected XferNotReady(Setup)\n"); + dwc3_ep0_stall_and_restart(dwc); + break; + case DEPEVT_STATUS_CONTROL_DATA: + /* FALLTHROUGH */ + case DEPEVT_STATUS_CONTROL_STATUS: + /* FALLTHROUGH */ + default: + dev_vdbg(dwc->dev, "waiting for XferComplete\n"); + } + + return; + } + switch (event->status) { case DEPEVT_STATUS_CONTROL_SETUP: dev_vdbg(dwc->dev, "Control Setup\n"); |