aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/dwc3/gadget.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/dwc3/gadget.c')
-rw-r--r--drivers/usb/dwc3/gadget.c29
1 files changed, 20 insertions, 9 deletions
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index eca945feeec3..3a344ba0b292 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -965,7 +965,7 @@ out:
return 0;
}
-static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep)
+static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep, int status)
{
struct dwc3_request *req;
@@ -975,19 +975,19 @@ static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep)
while (!list_empty(&dep->started_list)) {
req = next_request(&dep->started_list);
- dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
+ dwc3_gadget_giveback(dep, req, status);
}
while (!list_empty(&dep->pending_list)) {
req = next_request(&dep->pending_list);
- dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
+ dwc3_gadget_giveback(dep, req, status);
}
while (!list_empty(&dep->cancelled_list)) {
req = next_request(&dep->cancelled_list);
- dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
+ dwc3_gadget_giveback(dep, req, status);
}
}
@@ -1022,7 +1022,7 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
dep->endpoint.desc = NULL;
}
- dwc3_remove_requests(dwc, dep);
+ dwc3_remove_requests(dwc, dep, -ECONNRESET);
dep->stream_capable = false;
dep->type = 0;
@@ -2340,7 +2340,7 @@ static void dwc3_stop_active_transfers(struct dwc3 *dwc)
if (!dep)
continue;
- dwc3_remove_requests(dwc, dep);
+ dwc3_remove_requests(dwc, dep, -ESHUTDOWN);
}
}
@@ -2501,6 +2501,9 @@ static int dwc3_gadget_soft_disconnect(struct dwc3 *dwc)
if (dwc->ep0state != EP0_SETUP_PHASE) {
int ret;
+ if (dwc->delayed_status)
+ dwc3_ep0_send_delayed_status(dwc);
+
reinit_completion(&dwc->ep0_in_setup);
spin_unlock_irqrestore(&dwc->lock, flags);
@@ -2568,6 +2571,8 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
return 0;
}
+ synchronize_irq(dwc->irq_gadget);
+
if (!is_on) {
ret = dwc3_gadget_soft_disconnect(dwc);
} else {
@@ -2718,6 +2723,7 @@ static int __dwc3_gadget_start(struct dwc3 *dwc)
dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
dep = dwc->eps[0];
+ dep->flags = 0;
ret = __dwc3_gadget_ep_enable(dep, DWC3_DEPCFG_ACTION_INIT);
if (ret) {
dev_err(dwc->dev, "failed to enable %s\n", dep->name);
@@ -2725,6 +2731,7 @@ static int __dwc3_gadget_start(struct dwc3 *dwc)
}
dep = dwc->eps[1];
+ dep->flags = 0;
ret = __dwc3_gadget_ep_enable(dep, DWC3_DEPCFG_ACTION_INIT);
if (ret) {
dev_err(dwc->dev, "failed to enable %s\n", dep->name);
@@ -3596,11 +3603,12 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
dep = dwc->eps[epnum];
if (!(dep->flags & DWC3_EP_ENABLED)) {
- if (!(dep->flags & DWC3_EP_TRANSFER_STARTED))
+ if ((epnum > 1) && !(dep->flags & DWC3_EP_TRANSFER_STARTED))
return;
/* Handle only EPCMDCMPLT when EP disabled */
- if (event->endpoint_event != DWC3_DEPEVT_EPCMDCMPLT)
+ if ((event->endpoint_event != DWC3_DEPEVT_EPCMDCMPLT) &&
+ !(epnum <= 1 && event->endpoint_event == DWC3_DEPEVT_XFERCOMPLETE))
return;
}
@@ -3695,7 +3703,7 @@ void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force,
* timeout. Delay issuing the End Transfer command until the Setup TRB is
* prepared.
*/
- if (dwc->ep0state != EP0_SETUP_PHASE && !dwc->delayed_status) {
+ if (dwc->ep0state != EP0_SETUP_PHASE) {
dep->flags |= DWC3_EP_DELAY_STOP;
return;
}
@@ -3867,6 +3875,9 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
u8 lanes = 1;
u8 speed;
+ if (!dwc->softconnect)
+ return;
+
reg = dwc3_readl(dwc->regs, DWC3_DSTS);
speed = reg & DWC3_DSTS_CONNECTSPD;
dwc->speed = speed;