usb: dwc3: ep0: fix SetFeature(TEST)
authorGerard Cauvy <g-cauvy1@ti.com>
Fri, 10 Feb 2012 10:21:18 +0000 (12:21 +0200)
committerFelipe Balbi <balbi@ti.com>
Fri, 10 Feb 2012 11:11:46 +0000 (13:11 +0200)
When host requests us to enter a test mode,
we cannot directly enter the test mode before
Status Phase is completed, otherwise the core
will never be able to deliver the Status ZLP
to host, because it has already entered the
requested Test Mode.

In order to fix the error, we move the actual
start of Test Mode right after we receive
Transfer Complete event of the status phase.

Signed-off-by: Gerard Cauvy <g-cauvy1@ti.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
drivers/usb/dwc3/core.h
drivers/usb/dwc3/ep0.c
drivers/usb/dwc3/gadget.c

index 71d958af2393b6c25e297cabe1ef3b1033fe8f2c..4dac9828577e9c877eb3f5fc324b6c33c1ca3d18 100644 (file)
@@ -684,6 +684,9 @@ struct dwc3 {
 
        struct dwc3_hwparams    hwparams;
        struct dentry           *root;
+
+       u8                      test_mode;
+       u8                      test_mode_nr;
 };
 
 /* -------------------------------------------------------------------------- */
index 5104dbf46680de50e5ac48e9f4cc20303eae2781..c20e30c8b69545f9ecbb661a96e63d420e1e436a 100644 (file)
@@ -316,7 +316,6 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
        u32                     wValue;
        u32                     wIndex;
        int                     ret;
-       u32                     mode;
 
        wValue = le16_to_cpu(ctrl->wValue);
        wIndex = le16_to_cpu(ctrl->wIndex);
@@ -355,13 +354,8 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
                        if (!set)
                                return -EINVAL;
 
-                       mode = wIndex >> 8;
-                       ret = dwc3_gadget_set_test_mode(dwc, mode);
-                       if (ret < 0) {
-                               dev_dbg(dwc->dev, "Invalid Test #%d\n",
-                                               mode);
-                               return ret;
-                       }
+                       dwc->test_mode_nr = wIndex >> 8;
+                       dwc->test_mode = true;
                }
                break;
 
@@ -604,6 +598,17 @@ static void dwc3_ep0_complete_req(struct dwc3 *dwc,
                dwc3_gadget_giveback(dep, r, 0);
        }
 
+       if (dwc->test_mode) {
+               int ret;
+
+               ret = dwc3_gadget_set_test_mode(dwc, dwc->test_mode_nr);
+               if (ret < 0) {
+                       dev_dbg(dwc->dev, "Invalid Test #%d\n",
+                                       dwc->test_mode_nr);
+                       dwc3_ep0_stall_and_restart(dwc);
+               }
+       }
+
        dwc->ep0state = EP0_SETUP_PHASE;
        dwc3_ep0_out_start(dwc);
 }
index c30ab6da3d0e0e84ca199991dbb393f6849ddc23..76327005d54c637ff3eaf156b10e6b51786fb0c1 100644 (file)
@@ -1962,6 +1962,7 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
        reg = dwc3_readl(dwc->regs, DWC3_DCTL);
        reg &= ~DWC3_DCTL_TSTCTRL_MASK;
        dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+       dwc->test_mode = false;
 
        dwc3_stop_active_transfers(dwc);
        dwc3_clear_stall_all_ep(dwc);