* @ctrl_buff: Buffer for EP0 control requests.
* @ctrl_req: Request for EP0 control packets.
* @ep0_state: EP0 control transfers state
+ * @delayed_status: true when gadget driver asks for delayed status
* @test_mode: USB test mode requested by the host
* @remote_wakeup_allowed: True if device is allowed to wake-up host by
* remote-wakeup signalling
void *ep0_buff;
void *ctrl_buff;
enum dwc2_ep0_state ep0_state;
+ unsigned delayed_status : 1;
u8 test_mode;
dma_addr_t setup_desc_dma[2];
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/usb/phy.h>
+#include <linux/usb/composite.h>
+
#include "core.h"
#include "hw.h"
return 0;
}
+ /* Change EP direction if status phase request is after data out */
+ if (!hs_ep->index && !req->length && !hs_ep->dir_in &&
+ hs->ep0_state == DWC2_EP0_DATA_OUT)
+ hs_ep->dir_in = 1;
+
if (first) {
if (!hs_ep->isochronous) {
dwc2_hsotg_start_req(hs, hs_ep, hs_req, false);
dev_dbg(hsotg->dev, "driver->setup() ret %d\n", ret);
}
+ hsotg->delayed_status = false;
+ if (ret == USB_GADGET_DELAYED_STATUS)
+ hsotg->delayed_status = true;
+
/*
* the request is either unhandlable, or is not formatted correctly
* so respond with a STALL for the status stage to indicate failure.
if (!using_desc_dma(hsotg) && epnum == 0 &&
hsotg->ep0_state == DWC2_EP0_DATA_OUT) {
/* Move to STATUS IN */
- dwc2_hsotg_ep0_zlp(hsotg, true);
- return;
+ if (!hsotg->delayed_status)
+ dwc2_hsotg_ep0_zlp(hsotg, true);
}
/*
/* Safety check EP0 state when STSPHSERCVD asserted */
if (hsotg->ep0_state == DWC2_EP0_DATA_OUT) {
/* Move to STATUS IN for DDMA */
- if (using_desc_dma(hsotg))
- dwc2_hsotg_ep0_zlp(hsotg, true);
+ if (using_desc_dma(hsotg)) {
+ if (!hsotg->delayed_status)
+ dwc2_hsotg_ep0_zlp(hsotg, true);
+ else
+ /* In case of 3 stage Control Write with delayed
+ * status, when Status IN transfer started
+ * before STSPHSERCVD asserted, NAKSTS bit not
+ * cleared by CNAK in dwc2_hsotg_start_req()
+ * function. Clear now NAKSTS to allow complete
+ * transfer.
+ */
+ dwc2_set_bit(hsotg, DIEPCTL(0),
+ DXEPCTL_CNAK);
+ }
}
}