Merge remote-tracking branch 'usb-gadget/next'
authorStephen Rothwell <sfr@canb.auug.org.au>
Tue, 13 Sep 2016 02:42:48 +0000 (12:42 +1000)
committerStephen Rothwell <sfr@canb.auug.org.au>
Tue, 13 Sep 2016 02:42:48 +0000 (12:42 +1000)
50 files changed:
Documentation/devicetree/bindings/phy/mxs-usb-phy.txt
Documentation/devicetree/bindings/usb/dwc2.txt
Documentation/devicetree/bindings/usb/dwc3.txt
Documentation/devicetree/bindings/usb/generic.txt
Documentation/devicetree/bindings/usb/renesas_usbhs.txt
Documentation/devicetree/bindings/usb/rockchip,dwc3.txt [new file with mode: 0644]
drivers/usb/common/ulpi.c
drivers/usb/dwc2/core.c
drivers/usb/dwc2/core.h
drivers/usb/dwc2/gadget.c
drivers/usb/dwc2/hw.h
drivers/usb/dwc3/core.c
drivers/usb/dwc3/core.h
drivers/usb/dwc3/dwc3-of-simple.c
drivers/usb/dwc3/gadget.c
drivers/usb/dwc3/ulpi.c
drivers/usb/gadget/Kconfig
drivers/usb/gadget/composite.c
drivers/usb/gadget/configfs.c
drivers/usb/gadget/function/f_fs.c
drivers/usb/gadget/function/f_hid.c
drivers/usb/gadget/function/f_loopback.c
drivers/usb/gadget/function/f_mass_storage.c
drivers/usb/gadget/function/f_mass_storage.h
drivers/usb/gadget/function/f_midi.c
drivers/usb/gadget/function/f_ncm.c
drivers/usb/gadget/function/f_printer.c
drivers/usb/gadget/function/f_sourcesink.c
drivers/usb/gadget/function/f_uvc.c
drivers/usb/gadget/function/storage_common.c
drivers/usb/gadget/function/storage_common.h
drivers/usb/gadget/function/u_ether.c
drivers/usb/gadget/function/u_ether.h
drivers/usb/gadget/legacy/gmidi.c
drivers/usb/gadget/u_f.c
drivers/usb/gadget/u_f.h
drivers/usb/gadget/udc/core.c
drivers/usb/gadget/udc/goku_udc.c
drivers/usb/gadget/udc/net2280.c
drivers/usb/gadget/udc/pxa27x_udc.c
drivers/usb/phy/phy-ab8500-usb.c
drivers/usb/phy/phy-generic.c
drivers/usb/phy/phy-mxs-usb.c
drivers/usb/renesas_usbhs/common.c
drivers/usb/renesas_usbhs/mod_gadget.c
include/linux/ulpi/driver.h
include/linux/ulpi/interface.h
include/linux/usb/composite.h
include/linux/usb/gadget.h
include/uapi/linux/usb/functionfs.h

index 379b84a567ccb82442b1275c43cdc9d6d518c075..1d25b04cd05e176a91dd53a75cd10a3020f16120 100644 (file)
@@ -12,6 +12,16 @@ Required properties:
 - interrupts: Should contain phy interrupt
 - fsl,anatop: phandle for anatop register, it is only for imx6 SoC series
 
+Optional properties:
+- fsl,tx-cal-45-dn-ohms: Integer [30-55]. Resistance (in ohms) of switchable
+  high-speed trimming resistor connected in parallel with the 45 ohm resistor
+  that terminates the DN output signal. Default: 45
+- fsl,tx-cal-45-dp-ohms: Integer [30-55]. Resistance (in ohms) of switchable
+  high-speed trimming resistor connected in parallel with the 45 ohm resistor
+  that terminates the DP output signal. Default: 45
+- fsl,tx-d-cal: Integer [79-119]. Current trimming value (as a percentage) of
+  the 17.78mA TX reference current. Default: 100
+
 Example:
 usbphy1: usbphy@020c9000 {
        compatible = "fsl,imx6q-usbphy", "fsl,imx23-usbphy";
index 20a68bf2b4e755fb3d2679c80d77795de695e8de..7d16ebfaa5a1b013436445ffd47203849ab0408b 100644 (file)
@@ -26,7 +26,10 @@ Refer to phy/phy-bindings.txt for generic phy consumer properties
 - g-use-dma: enable dma usage in gadget driver.
 - g-rx-fifo-size: size of rx fifo size in gadget mode.
 - g-np-tx-fifo-size: size of non-periodic tx fifo size in gadget mode.
-- g-tx-fifo-size: size of periodic tx fifo per endpoint (except ep0) in gadget mode.
+
+Deprecated properties:
+- g-tx-fifo-size: size of periodic tx fifo per endpoint (except ep0)
+  in gadget mode.
 
 Example:
 
index 7d7ce089b003dd4d1f67e0c47840cb032f815bed..e3e6983288e31c1f337ea4014fa69a575364560c 100644 (file)
@@ -13,7 +13,8 @@ Optional properties:
    in the array is expected to be a handle to the USB2/HS PHY and
    the second element is expected to be a handle to the USB3/SS PHY
  - phys: from the *Generic PHY* bindings
- - phy-names: from the *Generic PHY* bindings
+ - phy-names: from the *Generic PHY* bindings; supported names are "usb2-phy"
+       or "usb3-phy".
  - snps,usb3_lpm_capable: determines if platform is USB3 LPM capable
  - snps,disable_scramble_quirk: true when SW should disable data scrambling.
        Only really useful for FPGA builds.
@@ -39,6 +40,11 @@ Optional properties:
                        disabling the suspend signal to the PHY.
  - snps,dis_rxdet_inp3_quirk: when set core will disable receiver detection
                        in PHY P3 power state.
+ - snps,dis-u2-freeclk-exists-quirk: when set, clear the u2_freeclk_exists
+                       in GUSB2PHYCFG, specify that USB2 PHY doesn't provide
+                       a free-running PHY clock.
+ - snps,dis-del-phy-power-chg-quirk: when set core will change PHY power
+                       from P0 to P1/P2/P3 without delay.
  - snps,is-utmi-l1-suspend: true when DWC3 asserts output signal
                        utmi_l1_suspend_n, false when asserts utmi_sleep_n
  - snps,hird-threshold: HIRD threshold
index bba825711873f30d47b6cafa1ee941df57d73c7e..bfadeb1c3bab6212993a3efc2a01750409e9a798 100644 (file)
@@ -11,6 +11,11 @@ Optional properties:
                        "peripheral" and "otg". In case this attribute isn't
                        passed via DT, USB DRD controllers should default to
                        OTG.
+ - phy_type: tells USB controllers that we want to configure the core to support
+                       a UTMI+ PHY with an 8- or 16-bit interface if UTMI+ is
+                       selected. Valid arguments are "utmi" and "utmi_wide".
+                       In case this isn't passed via DT, USB controllers should
+                       default to HW capability.
  - otg-rev: tells usb driver the release number of the OTG and EH supplement
                        with which the device and its descriptors are compliant,
                        in binary-coded decimal (i.e. 2.0 is 0200H). This
@@ -34,6 +39,7 @@ dwc3@4a030000 {
        usb-phy = <&usb2_phy>, <&usb3,phy>;
        maximum-speed = "super-speed";
        dr_mode = "otg";
+       phy_type = "utmi_wide";
        otg-rev = <0x0200>;
        adp-disable;
 };
index b6040563e51a36de00900c2b5c0192cdd4b5d540..9e18e000339ebb856a839e27245a91f3c25c9c77 100644 (file)
@@ -9,6 +9,7 @@ Required properties:
        - "renesas,usbhs-r8a7793" for r8a7793 (R-Car M2-N) compatible device
        - "renesas,usbhs-r8a7794" for r8a7794 (R-Car E2) compatible device
        - "renesas,usbhs-r8a7795" for r8a7795 (R-Car H3) compatible device
+       - "renesas,usbhs-r8a7796" for r8a7796 (R-Car M3-W) compatible device
        - "renesas,rcar-gen2-usbhs" for R-Car Gen2 compatible device
        - "renesas,rcar-gen3-usbhs" for R-Car Gen3 compatible device
 
diff --git a/Documentation/devicetree/bindings/usb/rockchip,dwc3.txt b/Documentation/devicetree/bindings/usb/rockchip,dwc3.txt
new file mode 100644 (file)
index 0000000..0536a93
--- /dev/null
@@ -0,0 +1,59 @@
+Rockchip SuperSpeed DWC3 USB SoC controller
+
+Required properties:
+- compatible:  should contain "rockchip,rk3399-dwc3" for rk3399 SoC
+- clocks:      A list of phandle + clock-specifier pairs for the
+               clocks listed in clock-names
+- clock-names: Should contain the following:
+  "ref_clk"    Controller reference clk, have to be 24 MHz
+  "suspend_clk"        Controller suspend clk, have to be 24 MHz or 32 KHz
+  "bus_clk"    Master/Core clock, have to be >= 62.5 MHz for SS
+               operation and >= 30MHz for HS operation
+  "grf_clk"    Controller grf clk
+
+Required child node:
+A child node must exist to represent the core DWC3 IP block. The name of
+the node is not important. The content of the node is defined in dwc3.txt.
+
+Phy documentation is provided in the following places:
+Documentation/devicetree/bindings/phy/rockchip,dwc3-usb-phy.txt
+
+Example device nodes:
+
+       usbdrd3_0: usb@fe800000 {
+               compatible = "rockchip,rk3399-dwc3";
+               clocks = <&cru SCLK_USB3OTG0_REF>, <&cru SCLK_USB3OTG0_SUSPEND>,
+                        <&cru ACLK_USB3OTG0>, <&cru ACLK_USB3_GRF>;
+               clock-names = "ref_clk", "suspend_clk",
+                             "bus_clk", "grf_clk";
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+               status = "disabled";
+               usbdrd_dwc3_0: dwc3@fe800000 {
+                       compatible = "snps,dwc3";
+                       reg = <0x0 0xfe800000 0x0 0x100000>;
+                       interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>;
+                       dr_mode = "otg";
+                       status = "disabled";
+               };
+       };
+
+       usbdrd3_1: usb@fe900000 {
+               compatible = "rockchip,rk3399-dwc3";
+               clocks = <&cru SCLK_USB3OTG1_REF>, <&cru SCLK_USB3OTG1_SUSPEND>,
+                        <&cru ACLK_USB3OTG1>, <&cru ACLK_USB3_GRF>;
+               clock-names = "ref_clk", "suspend_clk",
+                             "bus_clk", "grf_clk";
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+               status = "disabled";
+               usbdrd_dwc3_1: dwc3@fe900000 {
+                       compatible = "snps,dwc3";
+                       reg = <0x0 0xfe900000 0x0 0x100000>;
+                       interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
+                       dr_mode = "otg";
+                       status = "disabled";
+               };
+       };
index e04a34e7a341d64af2262cf0dd436875794ac09a..8b317702d7610d3dae663df4f1fc0feff87c36f6 100644 (file)
 
 int ulpi_read(struct ulpi *ulpi, u8 addr)
 {
-       return ulpi->ops->read(ulpi->ops, addr);
+       return ulpi->ops->read(ulpi->dev.parent, addr);
 }
 EXPORT_SYMBOL_GPL(ulpi_read);
 
 int ulpi_write(struct ulpi *ulpi, u8 addr, u8 val)
 {
-       return ulpi->ops->write(ulpi->ops, addr, val);
+       return ulpi->ops->write(ulpi->dev.parent, addr, val);
 }
 EXPORT_SYMBOL_GPL(ulpi_write);
 
@@ -157,6 +157,8 @@ static int ulpi_register(struct device *dev, struct ulpi *ulpi)
 {
        int ret;
 
+       ulpi->dev.parent = dev; /* needed early for ops */
+
        /* Test the interface */
        ret = ulpi_write(ulpi, ULPI_SCRATCH, 0xaa);
        if (ret < 0)
@@ -175,7 +177,6 @@ static int ulpi_register(struct device *dev, struct ulpi *ulpi)
        ulpi->id.product = ulpi_read(ulpi, ULPI_PRODUCT_ID_LOW);
        ulpi->id.product |= ulpi_read(ulpi, ULPI_PRODUCT_ID_HIGH) << 8;
 
-       ulpi->dev.parent = dev;
        ulpi->dev.bus = &ulpi_bus;
        ulpi->dev.type = &ulpi_dev_type;
        dev_set_name(&ulpi->dev, "%s.ulpi", dev_name(dev));
@@ -202,7 +203,8 @@ static int ulpi_register(struct device *dev, struct ulpi *ulpi)
  * Allocates and registers a ULPI device and an interface for it. Called from
  * the USB controller that provides the ULPI interface.
  */
-struct ulpi *ulpi_register_interface(struct device *dev, struct ulpi_ops *ops)
+struct ulpi *ulpi_register_interface(struct device *dev,
+                                    const struct ulpi_ops *ops)
 {
        struct ulpi *ulpi;
        int ret;
@@ -212,7 +214,6 @@ struct ulpi *ulpi_register_interface(struct device *dev, struct ulpi_ops *ops)
                return ERR_PTR(-ENOMEM);
 
        ulpi->ops = ops;
-       ops->dev = dev;
 
        ret = ulpi_register(dev, ulpi);
        if (ret) {
index 4135a5ff67ca75257583d14ebda6a1737fa5066f..fa9b26b915071ada49ee1b068ff098c09a962ff1 100644 (file)
@@ -238,6 +238,77 @@ int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg)
        return ret;
 }
 
+/**
+ * dwc2_wait_for_mode() - Waits for the controller mode.
+ * @hsotg:     Programming view of the DWC_otg controller.
+ * @host_mode: If true, waits for host mode, otherwise device mode.
+ */
+static void dwc2_wait_for_mode(struct dwc2_hsotg *hsotg,
+                              bool host_mode)
+{
+       ktime_t start;
+       ktime_t end;
+       unsigned int timeout = 110;
+
+       dev_vdbg(hsotg->dev, "Waiting for %s mode\n",
+                host_mode ? "host" : "device");
+
+       start = ktime_get();
+
+       while (1) {
+               s64 ms;
+
+               if (dwc2_is_host_mode(hsotg) == host_mode) {
+                       dev_vdbg(hsotg->dev, "%s mode set\n",
+                                host_mode ? "Host" : "Device");
+                       break;
+               }
+
+               end = ktime_get();
+               ms = ktime_to_ms(ktime_sub(end, start));
+
+               if (ms >= (s64)timeout) {
+                       dev_warn(hsotg->dev, "%s: Couldn't set %s mode\n",
+                                __func__, host_mode ? "host" : "device");
+                       break;
+               }
+
+               usleep_range(1000, 2000);
+       }
+}
+
+/**
+ * dwc2_iddig_filter_enabled() - Returns true if the IDDIG debounce
+ * filter is enabled.
+ */
+static bool dwc2_iddig_filter_enabled(struct dwc2_hsotg *hsotg)
+{
+       u32 gsnpsid;
+       u32 ghwcfg4;
+
+       if (!dwc2_hw_is_otg(hsotg))
+               return false;
+
+       /* Check if core configuration includes the IDDIG filter. */
+       ghwcfg4 = dwc2_readl(hsotg->regs + GHWCFG4);
+       if (!(ghwcfg4 & GHWCFG4_IDDIG_FILT_EN))
+               return false;
+
+       /*
+        * Check if the IDDIG debounce filter is bypassed. Available
+        * in core version >= 3.10a.
+        */
+       gsnpsid = dwc2_readl(hsotg->regs + GSNPSID);
+       if (gsnpsid >= DWC2_CORE_REV_3_10a) {
+               u32 gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
+
+               if (gotgctl & GOTGCTL_DBNCE_FLTR_BYPASS)
+                       return false;
+       }
+
+       return true;
+}
+
 /*
  * Do core a soft reset of the core.  Be careful with this because it
  * resets all the internal state machines of the core.
@@ -246,9 +317,30 @@ int dwc2_core_reset(struct dwc2_hsotg *hsotg)
 {
        u32 greset;
        int count = 0;
+       bool wait_for_host_mode = false;
 
        dev_vdbg(hsotg->dev, "%s()\n", __func__);
 
+       /*
+        * If the current mode is host, either due to the force mode
+        * bit being set (which persists after core reset) or the
+        * connector id pin, a core soft reset will temporarily reset
+        * the mode to device. A delay from the IDDIG debounce filter
+        * will occur before going back to host mode.
+        *
+        * Determine whether we will go back into host mode after a
+        * reset and account for this delay after the reset.
+        */
+       if (dwc2_iddig_filter_enabled(hsotg)) {
+               u32 gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
+               u32 gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
+
+               if (!(gotgctl & GOTGCTL_CONID_B) ||
+                   (gusbcfg & GUSBCFG_FORCEHOSTMODE)) {
+                       wait_for_host_mode = true;
+               }
+       }
+
        /* Core Soft Reset */
        greset = dwc2_readl(hsotg->regs + GRSTCTL);
        greset |= GRSTCTL_CSFTRST;
@@ -277,6 +369,9 @@ int dwc2_core_reset(struct dwc2_hsotg *hsotg)
                }
        } while (!(greset & GRSTCTL_AHBIDLE));
 
+       if (wait_for_host_mode)
+               dwc2_wait_for_mode(hsotg, true);
+
        return 0;
 }
 
@@ -300,9 +395,9 @@ int dwc2_core_reset(struct dwc2_hsotg *hsotg)
  * Checks are done in this function to determine whether doing a force
  * would be valid or not.
  *
- * If a force is done, it requires a 25ms delay to take effect.
- *
- * Returns true if the mode was forced.
+ * If a force is done, it requires a IDDIG debounce filter delay if
+ * the filter is configured and enabled. We poll the current mode of
+ * the controller to account for this delay.
  */
 static bool dwc2_force_mode(struct dwc2_hsotg *hsotg, bool host)
 {
@@ -337,12 +432,18 @@ static bool dwc2_force_mode(struct dwc2_hsotg *hsotg, bool host)
        gusbcfg |= set;
        dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG);
 
-       msleep(25);
+       dwc2_wait_for_mode(hsotg, host);
        return true;
 }
 
-/*
- * Clears the force mode bits.
+/**
+ * dwc2_clear_force_mode() - Clears the force mode bits.
+ *
+ * After clearing the bits, wait up to 100 ms to account for any
+ * potential IDDIG filter delay. We can't know if we expect this delay
+ * or not because the value of the connector ID status is affected by
+ * the force mode. We only need to call this once during probe if
+ * dr_mode == OTG.
  */
 static void dwc2_clear_force_mode(struct dwc2_hsotg *hsotg)
 {
@@ -353,11 +454,8 @@ static void dwc2_clear_force_mode(struct dwc2_hsotg *hsotg)
        gusbcfg &= ~GUSBCFG_FORCEDEVMODE;
        dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG);
 
-       /*
-        * NOTE: This long sleep is _very_ important, otherwise the core will
-        * not stay in host mode after a connector ID change!
-        */
-       msleep(25);
+       if (dwc2_iddig_filter_enabled(hsotg))
+               usleep_range(100000, 110000);
 }
 
 /*
@@ -380,12 +478,6 @@ void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg)
                         __func__, hsotg->dr_mode);
                break;
        }
-
-       /*
-        * NOTE: This is required for some rockchip soc based
-        * platforms.
-        */
-       msleep(50);
 }
 
 /*
index d64551243789a2a1cd2ea045df62d8407a8fbde1..aad4107ef927e26388f302ebbbd7907ad9a295c0 100644 (file)
@@ -259,13 +259,6 @@ enum dwc2_lx_state {
        DWC2_L3,        /* Off state */
 };
 
-/*
- * Gadget periodic tx fifo sizes as used by legacy driver
- * EP0 is not included
- */
-#define DWC2_G_P_LEGACY_TX_FIFO_SIZE {256, 256, 256, 256, 768, 768, 768, \
-                                          768, 0, 0, 0, 0, 0, 0, 0}
-
 /* Gadget ep0 states */
 enum dwc2_ep0_state {
        DWC2_EP0_SETUP,
@@ -890,6 +883,7 @@ struct dwc2_hsotg {
 #define DWC2_CORE_REV_2_92a    0x4f54292a
 #define DWC2_CORE_REV_2_94a    0x4f54294a
 #define DWC2_CORE_REV_3_00a    0x4f54300a
+#define DWC2_CORE_REV_3_10a    0x4f54310a
 
 #if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
        union dwc2_hcd_internal_flags {
index 2ff03ae08e144d8541c6f8bfca5afb6874e87049..4cd6403a75668c35bef6a277f987bf41fc55ed27 100644 (file)
@@ -186,9 +186,10 @@ static void dwc2_hsotg_ctrl_epint(struct dwc2_hsotg *hsotg,
  */
 static void dwc2_hsotg_init_fifo(struct dwc2_hsotg *hsotg)
 {
-       unsigned int ep;
+       unsigned int fifo;
        unsigned int addr;
        int timeout;
+       u32 dptxfsizn;
        u32 val;
 
        /* Reset fifo map if not correctly cleared during previous session */
@@ -216,16 +217,16 @@ static void dwc2_hsotg_init_fifo(struct dwc2_hsotg *hsotg)
         * them to endpoints dynamically according to maxpacket size value of
         * given endpoint.
         */
-       for (ep = 1; ep < MAX_EPS_CHANNELS; ep++) {
-               if (!hsotg->g_tx_fifo_sz[ep])
-                       continue;
-               val = addr;
-               val |= hsotg->g_tx_fifo_sz[ep] << FIFOSIZE_DEPTH_SHIFT;
-               WARN_ONCE(addr + hsotg->g_tx_fifo_sz[ep] > hsotg->fifo_mem,
-                         "insufficient fifo memory");
-               addr += hsotg->g_tx_fifo_sz[ep];
+       for (fifo = 1; fifo < MAX_EPS_CHANNELS; fifo++) {
+               dptxfsizn = dwc2_readl(hsotg->regs + DPTXFSIZN(fifo));
+
+               val = (dptxfsizn & FIFOSIZE_DEPTH_MASK) | addr;
+               addr += dptxfsizn >> FIFOSIZE_DEPTH_SHIFT;
+
+               if (addr > hsotg->fifo_mem)
+                       break;
 
-               dwc2_writel(val, hsotg->regs + DPTXFSIZN(ep));
+               dwc2_writel(val, hsotg->regs + DPTXFSIZN(fifo));
        }
 
        /*
@@ -388,7 +389,8 @@ static int dwc2_hsotg_write_fifo(struct dwc2_hsotg *hsotg,
                        return -ENOSPC;
                }
        } else if (hsotg->dedicated_fifos && hs_ep->index != 0) {
-               can_write = dwc2_readl(hsotg->regs + DTXFSTS(hs_ep->index));
+               can_write = dwc2_readl(hsotg->regs +
+                               DTXFSTS(hs_ep->fifo_index));
 
                can_write &= 0xffff;
                can_write *= 4;
@@ -2432,7 +2434,7 @@ static void kill_all_requests(struct dwc2_hsotg *hsotg,
 
        if (!hsotg->dedicated_fifos)
                return;
-       size = (dwc2_readl(hsotg->regs + DTXFSTS(ep->index)) & 0xffff) * 4;
+       size = (dwc2_readl(hsotg->regs + DTXFSTS(ep->fifo_index)) & 0xffff) * 4;
        if (size < ep->fifo_size)
                dwc2_hsotg_txfifo_flush(hsotg, ep->fifo_index);
 }
@@ -3041,22 +3043,11 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep,
                break;
        }
 
-       /* If fifo is already allocated for this ep */
-       if (hs_ep->fifo_index) {
-               size =  hs_ep->ep.maxpacket * hs_ep->mc;
-               /* If bigger fifo is required deallocate current one */
-               if (size > hs_ep->fifo_size) {
-                       hsotg->fifo_map &= ~(1 << hs_ep->fifo_index);
-                       hs_ep->fifo_index = 0;
-                       hs_ep->fifo_size = 0;
-               }
-       }
-
        /*
         * if the hardware has dedicated fifos, we must give each IN EP
         * a unique tx-fifo even if it is non-periodic.
         */
-       if (dir_in && hsotg->dedicated_fifos && !hs_ep->fifo_index) {
+       if (dir_in && hsotg->dedicated_fifos) {
                u32 fifo_index = 0;
                u32 fifo_size = UINT_MAX;
                size = hs_ep->ep.maxpacket*hs_ep->mc;
@@ -3129,10 +3120,6 @@ static int dwc2_hsotg_ep_disable(struct usb_ep *ep)
 
        spin_lock_irqsave(&hsotg->lock, flags);
 
-       hsotg->fifo_map &= ~(1<<hs_ep->fifo_index);
-       hs_ep->fifo_index = 0;
-       hs_ep->fifo_size = 0;
-
        ctrl = dwc2_readl(hsotg->regs + epctrl_reg);
        ctrl &= ~DXEPCTL_EPENA;
        ctrl &= ~DXEPCTL_USBACTEP;
@@ -3147,6 +3134,10 @@ static int dwc2_hsotg_ep_disable(struct usb_ep *ep)
        /* terminate all requests with shutdown */
        kill_all_requests(hsotg, hs_ep, -ESHUTDOWN);
 
+       hsotg->fifo_map &= ~(1 << hs_ep->fifo_index);
+       hs_ep->fifo_index = 0;
+       hs_ep->fifo_size = 0;
+
        spin_unlock_irqrestore(&hsotg->lock, flags);
        return 0;
 }
@@ -3475,8 +3466,11 @@ static int dwc2_hsotg_udc_start(struct usb_gadget *gadget,
                otg_set_peripheral(hsotg->uphy->otg, &hsotg->gadget);
 
        spin_lock_irqsave(&hsotg->lock, flags);
-       dwc2_hsotg_init(hsotg);
-       dwc2_hsotg_core_init_disconnected(hsotg, false);
+       if (dwc2_hw_is_device(hsotg)) {
+               dwc2_hsotg_init(hsotg);
+               dwc2_hsotg_core_init_disconnected(hsotg, false);
+       }
+
        hsotg->enabled = 0;
        spin_unlock_irqrestore(&hsotg->lock, flags);
 
@@ -3813,36 +3807,10 @@ static void dwc2_hsotg_dump(struct dwc2_hsotg *hsotg)
 static void dwc2_hsotg_of_probe(struct dwc2_hsotg *hsotg)
 {
        struct device_node *np = hsotg->dev->of_node;
-       u32 len = 0;
-       u32 i = 0;
 
        /* Enable dma if requested in device tree */
        hsotg->g_using_dma = of_property_read_bool(np, "g-use-dma");
 
-       /*
-       * Register TX periodic fifo size per endpoint.
-       * EP0 is excluded since it has no fifo configuration.
-       */
-       if (!of_find_property(np, "g-tx-fifo-size", &len))
-               goto rx_fifo;
-
-       len /= sizeof(u32);
-
-       /* Read tx fifo sizes other than ep0 */
-       if (of_property_read_u32_array(np, "g-tx-fifo-size",
-                                               &hsotg->g_tx_fifo_sz[1], len))
-               goto rx_fifo;
-
-       /* Add ep0 */
-       len++;
-
-       /* Make remaining TX fifos unavailable */
-       if (len < MAX_EPS_CHANNELS) {
-               for (i = len; i < MAX_EPS_CHANNELS; i++)
-                       hsotg->g_tx_fifo_sz[i] = 0;
-       }
-
-rx_fifo:
        /* Register RX fifo size */
        of_property_read_u32(np, "g-rx-fifo-size", &hsotg->g_rx_fifo_sz);
 
@@ -3864,13 +3832,10 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq)
        struct device *dev = hsotg->dev;
        int epnum;
        int ret;
-       int i;
-       u32 p_tx_fifo[] = DWC2_G_P_LEGACY_TX_FIFO_SIZE;
 
        /* Initialize to legacy fifo configuration values */
        hsotg->g_rx_fifo_sz = 2048;
        hsotg->g_np_g_tx_fifo_sz = 1024;
-       memcpy(&hsotg->g_tx_fifo_sz[1], p_tx_fifo, sizeof(p_tx_fifo));
        /* Device tree specific probe */
        dwc2_hsotg_of_probe(hsotg);
 
@@ -3888,9 +3853,6 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq)
        dev_dbg(dev, "NonPeriodic TXFIFO size: %d\n",
                                                hsotg->g_np_g_tx_fifo_sz);
        dev_dbg(dev, "RXFIFO size: %d\n", hsotg->g_rx_fifo_sz);
-       for (i = 0; i < MAX_EPS_CHANNELS; i++)
-               dev_dbg(dev, "Periodic TXFIFO%2d size: %d\n", i,
-                                               hsotg->g_tx_fifo_sz[i]);
 
        hsotg->gadget.max_speed = USB_SPEED_HIGH;
        hsotg->gadget.ops = &dwc2_hsotg_gadget_ops;
index efc3bcde2822aa59a9e59350e632c70a0a2f8841..91058441e62abb1f68538aa2145018a097813dda 100644 (file)
@@ -48,6 +48,7 @@
 #define GOTGCTL_ASESVLD                        (1 << 18)
 #define GOTGCTL_DBNC_SHORT             (1 << 17)
 #define GOTGCTL_CONID_B                        (1 << 16)
+#define GOTGCTL_DBNCE_FLTR_BYPASS      (1 << 15)
 #define GOTGCTL_DEVHNPEN               (1 << 11)
 #define GOTGCTL_HSTSETHNPEN            (1 << 10)
 #define GOTGCTL_HNPREQ                 (1 << 9)
index 35d092456bec1da828ea41476e421d47809380a5..7287a763cd0cc4ca5a114ed687e6c34b0bdd643d 100644 (file)
 
 #define DWC3_DEFAULT_AUTOSUSPEND_DELAY 5000 /* ms */
 
+/**
+ * dwc3_get_dr_mode - Validates and sets dr_mode
+ * @dwc: pointer to our context structure
+ */
+static int dwc3_get_dr_mode(struct dwc3 *dwc)
+{
+       enum usb_dr_mode mode;
+       struct device *dev = dwc->dev;
+       unsigned int hw_mode;
+
+       if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
+               dwc->dr_mode = USB_DR_MODE_OTG;
+
+       mode = dwc->dr_mode;
+       hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0);
+
+       switch (hw_mode) {
+       case DWC3_GHWPARAMS0_MODE_GADGET:
+               if (IS_ENABLED(CONFIG_USB_DWC3_HOST)) {
+                       dev_err(dev,
+                               "Controller does not support host mode.\n");
+                       return -EINVAL;
+               }
+               mode = USB_DR_MODE_PERIPHERAL;
+               break;
+       case DWC3_GHWPARAMS0_MODE_HOST:
+               if (IS_ENABLED(CONFIG_USB_DWC3_GADGET)) {
+                       dev_err(dev,
+                               "Controller does not support device mode.\n");
+                       return -EINVAL;
+               }
+               mode = USB_DR_MODE_HOST;
+               break;
+       default:
+               if (IS_ENABLED(CONFIG_USB_DWC3_HOST))
+                       mode = USB_DR_MODE_HOST;
+               else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
+                       mode = USB_DR_MODE_PERIPHERAL;
+       }
+
+       if (mode != dwc->dr_mode) {
+               dev_warn(dev,
+                        "Configuration mismatch. dr_mode forced to %s\n",
+                        mode == USB_DR_MODE_HOST ? "host" : "gadget");
+
+               dwc->dr_mode = mode;
+       }
+
+       return 0;
+}
+
 void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
 {
        u32 reg;
@@ -448,6 +499,9 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
        if (dwc->dis_u3_susphy_quirk)
                reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
 
+       if (dwc->dis_del_phy_power_chg_quirk)
+               reg &= ~DWC3_GUSB3PIPECTL_DEPOCHANGE;
+
        dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
 
        reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
@@ -485,6 +539,23 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
                break;
        }
 
+       switch (dwc->hsphy_mode) {
+       case USBPHY_INTERFACE_MODE_UTMI:
+               reg &= ~(DWC3_GUSB2PHYCFG_PHYIF_MASK |
+                      DWC3_GUSB2PHYCFG_USBTRDTIM_MASK);
+               reg |= DWC3_GUSB2PHYCFG_PHYIF(UTMI_PHYIF_8_BIT) |
+                      DWC3_GUSB2PHYCFG_USBTRDTIM(USBTRDTIM_UTMI_8_BIT);
+               break;
+       case USBPHY_INTERFACE_MODE_UTMIW:
+               reg &= ~(DWC3_GUSB2PHYCFG_PHYIF_MASK |
+                      DWC3_GUSB2PHYCFG_USBTRDTIM_MASK);
+               reg |= DWC3_GUSB2PHYCFG_PHYIF(UTMI_PHYIF_16_BIT) |
+                      DWC3_GUSB2PHYCFG_USBTRDTIM(USBTRDTIM_UTMI_16_BIT);
+               break;
+       default:
+               break;
+       }
+
        /*
         * Above 1.94a, it is recommended to set DWC3_GUSB2PHYCFG_SUSPHY to
         * '0' during coreConsultant configuration. So default value will
@@ -500,6 +571,9 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
        if (dwc->dis_enblslpm_quirk)
                reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM;
 
+       if (dwc->dis_u2_freeclk_exists_quirk)
+               reg &= ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS;
+
        dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
 
        return 0;
@@ -666,6 +740,32 @@ static int dwc3_core_init(struct dwc3 *dwc)
                goto err4;
        }
 
+       switch (dwc->dr_mode) {
+       case USB_DR_MODE_PERIPHERAL:
+               dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
+               break;
+       case USB_DR_MODE_HOST:
+               dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
+               break;
+       case USB_DR_MODE_OTG:
+               dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
+               break;
+       default:
+               dev_warn(dwc->dev, "Unsupported mode %d\n", dwc->dr_mode);
+               break;
+       }
+
+       /*
+        * ENDXFER polling is available on version 3.10a and later of
+        * the DWC_usb3 controller. It is NOT available in the
+        * DWC_usb31 controller.
+        */
+       if (!dwc3_is_usb31(dwc) && dwc->revision >= DWC3_REVISION_310A) {
+               reg = dwc3_readl(dwc->regs, DWC3_GUCTL2);
+               reg |= DWC3_GUCTL2_RST_ACTBITLATER;
+               dwc3_writel(dwc->regs, DWC3_GUCTL2, reg);
+       }
+
        return 0;
 
 err4:
@@ -763,7 +863,6 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
 
        switch (dwc->dr_mode) {
        case USB_DR_MODE_PERIPHERAL:
-               dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
                ret = dwc3_gadget_init(dwc);
                if (ret) {
                        if (ret != -EPROBE_DEFER)
@@ -772,7 +871,6 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
                }
                break;
        case USB_DR_MODE_HOST:
-               dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
                ret = dwc3_host_init(dwc);
                if (ret) {
                        if (ret != -EPROBE_DEFER)
@@ -781,7 +879,6 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
                }
                break;
        case USB_DR_MODE_OTG:
-               dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
                ret = dwc3_host_init(dwc);
                if (ret) {
                        if (ret != -EPROBE_DEFER)
@@ -888,6 +985,7 @@ static int dwc3_probe(struct platform_device *pdev)
 
        dwc->maximum_speed = usb_get_maximum_speed(dev);
        dwc->dr_mode = usb_get_dr_mode(dev);
+       dwc->hsphy_mode = of_usb_get_phy_mode(dev->of_node);
 
        dwc->has_lpm_erratum = device_property_read_bool(dev,
                                "snps,has-lpm-erratum");
@@ -924,6 +1022,10 @@ static int dwc3_probe(struct platform_device *pdev)
                                "snps,dis_enblslpm_quirk");
        dwc->dis_rxdet_inp3_quirk = device_property_read_bool(dev,
                                "snps,dis_rxdet_inp3_quirk");
+       dwc->dis_u2_freeclk_exists_quirk = device_property_read_bool(dev,
+                               "snps,dis-u2-freeclk-exists-quirk");
+       dwc->dis_del_phy_power_chg_quirk = device_property_read_bool(dev,
+                               "snps,dis-del-phy-power-chg-quirk");
 
        dwc->tx_de_emphasis_quirk = device_property_read_bool(dev,
                                "snps,tx_de_emphasis_quirk");
@@ -972,17 +1074,9 @@ static int dwc3_probe(struct platform_device *pdev)
                goto err2;
        }
 
-       if (IS_ENABLED(CONFIG_USB_DWC3_HOST) &&
-                       (dwc->dr_mode == USB_DR_MODE_OTG ||
-                                       dwc->dr_mode == USB_DR_MODE_UNKNOWN))
-               dwc->dr_mode = USB_DR_MODE_HOST;
-       else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET) &&
-                       (dwc->dr_mode == USB_DR_MODE_OTG ||
-                                       dwc->dr_mode == USB_DR_MODE_UNKNOWN))
-               dwc->dr_mode = USB_DR_MODE_PERIPHERAL;
-
-       if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
-               dwc->dr_mode = USB_DR_MODE_OTG;
+       ret = dwc3_get_dr_mode(dwc);
+       if (ret)
+               goto err3;
 
        ret = dwc3_alloc_scratch_buffers(dwc);
        if (ret)
index 45d6de5107c733ff1ba2d9df69e3147b45c9a493..6b60e42626a235e2f8a7197749c9e43c1b2723ea 100644 (file)
 #define DWC3_GPRTBIMAP_HS1     0xc184
 #define DWC3_GPRTBIMAP_FS0     0xc188
 #define DWC3_GPRTBIMAP_FS1     0xc18c
+#define DWC3_GUCTL2            0xc19c
 
 #define DWC3_VER_NUMBER                0xc1a0
 #define DWC3_VER_TYPE          0xc1a4
 
 /* Global USB2 PHY Configuration Register */
 #define DWC3_GUSB2PHYCFG_PHYSOFTRST    (1 << 31)
+#define DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS     (1 << 30)
 #define DWC3_GUSB2PHYCFG_SUSPHY                (1 << 6)
 #define DWC3_GUSB2PHYCFG_ULPI_UTMI     (1 << 4)
 #define DWC3_GUSB2PHYCFG_ENBLSLPM      (1 << 8)
+#define DWC3_GUSB2PHYCFG_PHYIF(n)      (n << 3)
+#define DWC3_GUSB2PHYCFG_PHYIF_MASK    DWC3_GUSB2PHYCFG_PHYIF(1)
+#define DWC3_GUSB2PHYCFG_USBTRDTIM(n)  (n << 10)
+#define DWC3_GUSB2PHYCFG_USBTRDTIM_MASK        DWC3_GUSB2PHYCFG_USBTRDTIM(0xf)
+#define USBTRDTIM_UTMI_8_BIT           9
+#define USBTRDTIM_UTMI_16_BIT          5
+#define UTMI_PHYIF_16_BIT              1
+#define UTMI_PHYIF_8_BIT               0
 
 /* Global USB2 PHY Vendor Control Register */
 #define DWC3_GUSB2PHYACC_NEWREGREQ     (1 << 25)
 #define DWC3_GEVNTSIZ_SIZE(n)          ((n) & 0xffff)
 
 /* Global HWPARAMS0 Register */
-#define DWC3_GHWPARAMS0_USB3_MODE(n)   ((n) & 0x3)
+#define DWC3_GHWPARAMS0_MODE(n)                ((n) & 0x3)
+#define DWC3_GHWPARAMS0_MODE_GADGET    0
+#define DWC3_GHWPARAMS0_MODE_HOST      1
+#define DWC3_GHWPARAMS0_MODE_DRD       2
 #define DWC3_GHWPARAMS0_MBUS_TYPE(n)   (((n) >> 3) & 0x7)
 #define DWC3_GHWPARAMS0_SBUS_TYPE(n)   (((n) >> 6) & 0x3)
 #define DWC3_GHWPARAMS0_MDWIDTH(n)     (((n) >> 8) & 0xff)
 #define DWC3_GFLADJ_30MHZ_SDBND_SEL            (1 << 7)
 #define DWC3_GFLADJ_30MHZ_MASK                 0x3f
 
+/* Global User Control Register 2 */
+#define DWC3_GUCTL2_RST_ACTBITLATER            (1 << 14)
+
 /* Device Configuration Register */
 #define DWC3_DCFG_DEVADDR(addr)        ((addr) << 3)
 #define DWC3_DCFG_DEVADDR_MASK DWC3_DCFG_DEVADDR(0x7f)
@@ -685,6 +701,8 @@ struct dwc3_hwparams {
  * @request: struct usb_request to be transferred
  * @list: a list_head used for request queueing
  * @dep: struct dwc3_ep owning this request
+ * @sg: pointer to first incomplete sg
+ * @num_pending_sgs: counter to pending sgs
  * @first_trb_index: index to first trb used by this request
  * @epnum: endpoint number to which this request refers
  * @trb: pointer to struct dwc3_trb
@@ -697,7 +715,9 @@ struct dwc3_request {
        struct usb_request      request;
        struct list_head        list;
        struct dwc3_ep          *dep;
+       struct scatterlist      *sg;
 
+       unsigned                num_pending_sgs;
        u8                      first_trb_index;
        u8                      epnum;
        struct dwc3_trb         *trb;
@@ -743,6 +763,9 @@ struct dwc3_scratchpad_array {
  * @maximum_speed: maximum speed requested (mainly for testing purposes)
  * @revision: revision register contents
  * @dr_mode: requested mode of operation
+ * @hsphy_mode: UTMI phy mode, one of following:
+ *             - USBPHY_INTERFACE_MODE_UTMI
+ *             - USBPHY_INTERFACE_MODE_UTMIW
  * @usb2_phy: pointer to USB2 PHY
  * @usb3_phy: pointer to USB3 PHY
  * @usb2_generic_phy: pointer to USB2 PHY
@@ -799,6 +822,11 @@ struct dwc3_scratchpad_array {
  * @dis_u2_susphy_quirk: set if we disable usb2 suspend phy
  * @dis_enblslpm_quirk: set if we clear enblslpm in GUSB2PHYCFG,
  *                      disabling the suspend signal to the PHY.
+ * @dis_u2_freeclk_exists_quirk : set if we clear u2_freeclk_exists
+ *                     in GUSB2PHYCFG, specify that USB2 PHY doesn't
+ *                     provide a free-running PHY clock.
+ * @dis_del_phy_power_chg_quirk: set if we disable delay phy power
+ *                     change quirk.
  * @tx_de_emphasis_quirk: set if we enable Tx de-emphasis quirk
  * @tx_de_emphasis: Tx de-emphasis value
  *     0       - -6dB de-emphasis
@@ -845,6 +873,7 @@ struct dwc3 {
        size_t                  regs_size;
 
        enum usb_dr_mode        dr_mode;
+       enum usb_phy_interface  hsphy_mode;
 
        u32                     fladj;
        u32                     irq_gadget;
@@ -880,6 +909,8 @@ struct dwc3 {
 #define DWC3_REVISION_260A     0x5533260a
 #define DWC3_REVISION_270A     0x5533270a
 #define DWC3_REVISION_280A     0x5533280a
+#define DWC3_REVISION_300A     0x5533300a
+#define DWC3_REVISION_310A     0x5533310a
 
 /*
  * NOTICE: we're using bit 31 as a "is usb 3.1" flag. This is really
@@ -942,6 +973,8 @@ struct dwc3 {
        unsigned                dis_u2_susphy_quirk:1;
        unsigned                dis_enblslpm_quirk:1;
        unsigned                dis_rxdet_inp3_quirk:1;
+       unsigned                dis_u2_freeclk_exists_quirk:1;
+       unsigned                dis_del_phy_power_chg_quirk:1;
 
        unsigned                tx_de_emphasis_quirk:1;
        unsigned                tx_de_emphasis:2;
index e56d59b19a0ecacaf632cccdf7680ac5114075b7..283f9980a2604f8b31162d40d2df1d7fba286f31 100644 (file)
@@ -162,6 +162,7 @@ static const struct dev_pm_ops dwc3_of_simple_dev_pm_ops = {
 
 static const struct of_device_id of_dwc3_simple_match[] = {
        { .compatible = "qcom,dwc3" },
+       { .compatible = "rockchip,rk3399-dwc3" },
        { .compatible = "xlnx,zynqmp-dwc3" },
        { /* Sentinel */ }
 };
index 122e64df2f4dc173123ddbfe7ef934d8630851a2..07cc8929f27134e40b1084389fb3efb3c29c58f6 100644 (file)
@@ -174,15 +174,8 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
                int status)
 {
        struct dwc3                     *dwc = dep->dwc;
-       int                             i;
 
-       if (req->started) {
-               i = 0;
-               do {
-                       dwc3_ep_inc_deq(dep);
-               } while(++i < req->request.num_mapped_sgs);
-               req->started = false;
-       }
+       req->started = false;
        list_del(&req->list);
        req->trb = NULL;
 
@@ -348,7 +341,8 @@ static int dwc3_send_clear_stall_ep_cmd(struct dwc3_ep *dep)
         * IN transfers due to a mishandled error condition. Synopsys
         * STAR 9000614252.
         */
-       if (dep->direction && (dwc->revision >= DWC3_REVISION_260A))
+       if (dep->direction && (dwc->revision >= DWC3_REVISION_260A) &&
+           (dwc->gadget.speed >= USB_SPEED_SUPER))
                cmd |= DWC3_DEPCMD_CLEARPENDIN;
 
        memset(&params, 0, sizeof(params));
@@ -490,7 +484,8 @@ static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,
                params.param0 |= DWC3_DEPCFG_ACTION_INIT;
        }
 
-       params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN;
+       if (usb_endpoint_xfer_control(desc))
+               params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN;
 
        if (dep->number <= 1 || usb_endpoint_xfer_isoc(desc))
                params.param1 |= DWC3_DEPCFG_XFER_NOT_READY_EN;
@@ -764,6 +759,8 @@ static void dwc3_gadget_ep_free_request(struct usb_ep *ep,
        kfree(req);
 }
 
+static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep);
+
 /**
  * dwc3_prepare_one_trb - setup one TRB from one request
  * @dep: endpoint for which this request is prepared
@@ -771,15 +768,13 @@ static void dwc3_gadget_ep_free_request(struct usb_ep *ep,
  */
 static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
                struct dwc3_request *req, dma_addr_t dma,
-               unsigned length, unsigned last, unsigned chain, unsigned node)
+               unsigned length, unsigned chain, unsigned node)
 {
        struct dwc3_trb         *trb;
 
-       dwc3_trace(trace_dwc3_gadget, "%s: req %p dma %08llx length %d%s%s",
+       dwc3_trace(trace_dwc3_gadget, "%s: req %p dma %08llx length %d%s",
                        dep->name, req, (unsigned long long) dma,
-                       length, last ? " last" : "",
-                       chain ? " chain" : "");
-
+                       length, chain ? " chain" : "");
 
        trb = &dep->trb_pool[dep->trb_enqueue];
 
@@ -826,12 +821,10 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
        /* always enable Continue on Short Packet */
        trb->ctrl |= DWC3_TRB_CTRL_CSP;
 
-       if (!req->request.no_interrupt && !chain)
+       if ((!req->request.no_interrupt && !chain) ||
+                       (dwc3_calc_trbs_left(dep) == 0))
                trb->ctrl |= DWC3_TRB_CTRL_IOC | DWC3_TRB_CTRL_ISP_IMI;
 
-       if (last && !usb_endpoint_xfer_isoc(dep->endpoint.desc))
-               trb->ctrl |= DWC3_TRB_CTRL_LST;
-
        if (chain)
                trb->ctrl |= DWC3_TRB_CTRL_CHN;
 
@@ -856,12 +849,12 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
  */
 static struct dwc3_trb *dwc3_ep_prev_trb(struct dwc3_ep *dep, u8 index)
 {
-       if (!index)
-               index = DWC3_TRB_NUM - 2;
-       else
-               index = dep->trb_enqueue - 1;
+       u8 tmp = index;
 
-       return &dep->trb_pool[index];
+       if (!tmp)
+               tmp = DWC3_TRB_NUM - 1;
+
+       return &dep->trb_pool[tmp - 1];
 }
 
 static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep)
@@ -894,65 +887,42 @@ static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep)
 }
 
 static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,
-               struct dwc3_request *req, unsigned int trbs_left,
-               unsigned int more_coming)
+               struct dwc3_request *req)
 {
-       struct usb_request *request = &req->request;
-       struct scatterlist *sg = request->sg;
+       struct scatterlist *sg = req->sg;
        struct scatterlist *s;
-       unsigned int    last = false;
        unsigned int    length;
        dma_addr_t      dma;
        int             i;
 
-       for_each_sg(sg, s, request->num_mapped_sgs, i) {
+       for_each_sg(sg, s, req->num_pending_sgs, i) {
                unsigned chain = true;
 
                length = sg_dma_len(s);
                dma = sg_dma_address(s);
 
-               if (sg_is_last(s)) {
-                       if (usb_endpoint_xfer_int(dep->endpoint.desc) ||
-                               !more_coming)
-                               last = true;
-
-                       chain = false;
-               }
-
-               if (!trbs_left--)
-                       last = true;
-
-               if (last)
+               if (sg_is_last(s))
                        chain = false;
 
                dwc3_prepare_one_trb(dep, req, dma, length,
-                               last, chain, i);
+                               chain, i);
 
-               if (last)
+               if (!dwc3_calc_trbs_left(dep))
                        break;
        }
 }
 
 static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep,
-               struct dwc3_request *req, unsigned int trbs_left,
-               unsigned int more_coming)
+               struct dwc3_request *req)
 {
-       unsigned int    last = false;
        unsigned int    length;
        dma_addr_t      dma;
 
        dma = req->request.dma;
        length = req->request.length;
 
-       if (!trbs_left)
-               last = true;
-
-       /* Is this the last request? */
-       if (usb_endpoint_xfer_int(dep->endpoint.desc) || !more_coming)
-               last = true;
-
        dwc3_prepare_one_trb(dep, req, dma, length,
-                       last, false, 0);
+                       false, 0);
 }
 
 /*
@@ -966,26 +936,19 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep,
 static void dwc3_prepare_trbs(struct dwc3_ep *dep)
 {
        struct dwc3_request     *req, *n;
-       unsigned int            more_coming;
-       u32                     trbs_left;
 
        BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM);
 
-       trbs_left = dwc3_calc_trbs_left(dep);
-       if (!trbs_left)
+       if (!dwc3_calc_trbs_left(dep))
                return;
 
-       more_coming = dep->allocated_requests - dep->queued_requests;
-
        list_for_each_entry_safe(req, n, &dep->pending_list, list) {
-               if (req->request.num_mapped_sgs > 0)
-                       dwc3_prepare_one_trb_sg(dep, req, trbs_left--,
-                                       more_coming);
+               if (req->num_pending_sgs > 0)
+                       dwc3_prepare_one_trb_sg(dep, req);
                else
-                       dwc3_prepare_one_trb_linear(dep, req, trbs_left--,
-                                       more_coming);
+                       dwc3_prepare_one_trb_linear(dep, req);
 
-               if (!trbs_left)
+               if (!dwc3_calc_trbs_left(dep))
                        return;
        }
 }
@@ -1101,93 +1064,29 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
 
        trace_dwc3_ep_queue(req);
 
-       /*
-        * We only add to our list of requests now and
-        * start consuming the list once we get XferNotReady
-        * IRQ.
-        *
-        * That way, we avoid doing anything that we don't need
-        * to do now and defer it until the point we receive a
-        * particular token from the Host side.
-        *
-        * This will also avoid Host cancelling URBs due to too
-        * many NAKs.
-        */
        ret = usb_gadget_map_request(&dwc->gadget, &req->request,
                        dep->direction);
        if (ret)
                return ret;
 
-       list_add_tail(&req->list, &dep->pending_list);
-
-       /*
-        * If there are no pending requests and the endpoint isn't already
-        * busy, we will just start the request straight away.
-        *
-        * This will save one IRQ (XFER_NOT_READY) and possibly make it a
-        * little bit faster.
-        */
-       if (!usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
-                       !usb_endpoint_xfer_int(dep->endpoint.desc)) {
-               ret = __dwc3_gadget_kick_transfer(dep, 0);
-               goto out;
-       }
-
-       /*
-        * There are a few special cases:
-        *
-        * 1. XferNotReady with empty list of requests. We need to kick the
-        *    transfer here in that situation, otherwise we will be NAKing
-        *    forever. If we get XferNotReady before gadget driver has a
-        *    chance to queue a request, we will ACK the IRQ but won't be
-        *    able to receive the data until the next request is queued.
-        *    The following code is handling exactly that.
-        *
-        */
-       if (dep->flags & DWC3_EP_PENDING_REQUEST) {
-               /*
-                * If xfernotready is already elapsed and it is a case
-                * of isoc transfer, then issue END TRANSFER, so that
-                * you can receive xfernotready again and can have
-                * notion of current microframe.
-                */
-               if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
-                       if (list_empty(&dep->started_list)) {
-                               dwc3_stop_active_transfer(dwc, dep->number, true);
-                               dep->flags = DWC3_EP_ENABLED;
-                       }
-                       return 0;
-               }
-
-               ret = __dwc3_gadget_kick_transfer(dep, 0);
-               if (!ret)
-                       dep->flags &= ~DWC3_EP_PENDING_REQUEST;
+       req->sg                 = req->request.sg;
+       req->num_pending_sgs    = req->request.num_mapped_sgs;
 
-               goto out;
-       }
+       list_add_tail(&req->list, &dep->pending_list);
 
-       /*
-        * 2. XferInProgress on Isoc EP with an active transfer. We need to
-        *    kick the transfer here after queuing a request, otherwise the
-        *    core may not see the modified TRB(s).
-        */
        if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
-                       (dep->flags & DWC3_EP_BUSY) &&
-                       !(dep->flags & DWC3_EP_MISSED_ISOC)) {
-               WARN_ON_ONCE(!dep->resource_index);
-               ret = __dwc3_gadget_kick_transfer(dep, dep->resource_index);
-               goto out;
+                       dep->flags & DWC3_EP_PENDING_REQUEST) {
+               if (list_empty(&dep->started_list)) {
+                       dwc3_stop_active_transfer(dwc, dep->number, true);
+                       dep->flags = DWC3_EP_ENABLED;
+               }
+               return 0;
        }
 
-       /*
-        * 4. Stream Capable Bulk Endpoints. We need to start the transfer
-        * right away, otherwise host will not know we have streams to be
-        * handled.
-        */
-       if (dep->stream_capable)
-               ret = __dwc3_gadget_kick_transfer(dep, 0);
+       if (!dwc3_calc_trbs_left(dep))
+               return 0;
 
-out:
+       ret = __dwc3_gadget_kick_transfer(dep, 0);
        if (ret && ret != -EBUSY)
                dwc3_trace(trace_dwc3_gadget,
                                "%s: failed to kick transfers",
@@ -1963,6 +1862,7 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep,
        unsigned int            trb_status;
 
        dep->queued_requests--;
+       dwc3_ep_inc_deq(dep);
        trace_dwc3_complete_trb(dep, trb);
 
        /*
@@ -1982,6 +1882,7 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep,
                return 1;
 
        count = trb->size & DWC3_TRB_SIZE_MASK;
+       req->request.actual += count;
 
        if (dep->direction) {
                if (count) {
@@ -2021,48 +1922,51 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep,
 
        if (s_pkt && !chain)
                return 1;
-       if ((event->status & DEPEVT_STATUS_LST) &&
-                       (trb->ctrl & (DWC3_TRB_CTRL_LST |
-                               DWC3_TRB_CTRL_HWO)))
-               return 1;
+
        if ((event->status & DEPEVT_STATUS_IOC) &&
                        (trb->ctrl & DWC3_TRB_CTRL_IOC))
                return 1;
+
        return 0;
 }
 
 static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
                const struct dwc3_event_depevt *event, int status)
 {
-       struct dwc3_request     *req;
+       struct dwc3_request     *req, *n;
        struct dwc3_trb         *trb;
-       unsigned int            slot;
-       unsigned int            i;
-       int                     count = 0;
+       bool                    ioc = false;
        int                     ret;
 
-       do {
+       list_for_each_entry_safe(req, n, &dep->started_list, list) {
+               unsigned length;
+               unsigned actual;
                int chain;
 
-               req = next_request(&dep->started_list);
-               if (WARN_ON_ONCE(!req))
-                       return 1;
-
-               chain = req->request.num_mapped_sgs > 0;
-               i = 0;
-               do {
-                       slot = req->first_trb_index + i;
-                       if (slot == DWC3_TRB_NUM - 1)
-                               slot++;
-                       slot %= DWC3_TRB_NUM;
-                       trb = &dep->trb_pool[slot];
-                       count += trb->size & DWC3_TRB_SIZE_MASK;
+               length = req->request.length;
+               chain = req->num_pending_sgs > 0;
+               if (chain) {
+                       struct scatterlist *sg = req->sg;
+                       struct scatterlist *s;
+                       unsigned int pending = req->num_pending_sgs;
+                       unsigned int i;
 
+                       for_each_sg(sg, s, pending, i) {
+                               trb = &dep->trb_pool[dep->trb_dequeue];
+
+                               req->sg = sg_next(s);
+                               req->num_pending_sgs--;
+
+                               ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb,
+                                               event, status, chain);
+                               if (ret)
+                                       break;
+                       }
+               } else {
+                       trb = &dep->trb_pool[dep->trb_dequeue];
                        ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb,
                                        event, status, chain);
-                       if (ret)
-                               break;
-               } while (++i < req->request.num_mapped_sgs);
+               }
 
                /*
                 * We assume here we will always receive the entire data block
@@ -2071,12 +1975,21 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
                 * should receive and we simply bounce the request back to the
                 * gadget driver for further processing.
                 */
-               req->request.actual += req->request.length - count;
+               actual = length - req->request.actual;
+               req->request.actual = actual;
+
+               if (ret && chain && (actual < length) && req->num_pending_sgs)
+                       return __dwc3_gadget_kick_transfer(dep, 0);
+
                dwc3_gadget_giveback(dep, req, status);
 
-               if (ret)
+               if (ret) {
+                       if ((event->status & DEPEVT_STATUS_IOC) &&
+                           (trb->ctrl & DWC3_TRB_CTRL_IOC))
+                               ioc = true;
                        break;
-       } while (1);
+               }
+       }
 
        /*
         * Our endpoint might get disabled by another thread during
@@ -2103,10 +2016,9 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
                return 1;
        }
 
-       if (usb_endpoint_xfer_isoc(dep->endpoint.desc))
-               if ((event->status & DEPEVT_STATUS_IOC) &&
-                               (trb->ctrl & DWC3_TRB_CTRL_IOC))
-                       return 0;
+       if (usb_endpoint_xfer_isoc(dep->endpoint.desc) && ioc)
+               return 0;
+
        return 1;
 }
 
@@ -2322,6 +2234,18 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force)
         *
         * - Issue EndTransfer WITH CMDIOC bit set
         * - Wait 100us
+        *
+        * As of IP version 3.10a of the DWC_usb3 IP, the controller
+        * supports a mode to work around the above limitation. The
+        * software can poll the CMDACT bit in the DEPCMD register
+        * after issuing a EndTransfer command. This mode is enabled
+        * by writing GUCTL2[14]. This polling is already done in the
+        * dwc3_send_gadget_ep_cmd() function so if the mode is
+        * enabled, the EndTransfer command will have completed upon
+        * returning from this function and we don't need to delay for
+        * 100us.
+        *
+        * This mode is NOT available on the DWC_usb31 IP.
         */
 
        cmd = DWC3_DEPCMD_ENDTRANSFER;
@@ -2333,7 +2257,9 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force)
        WARN_ON_ONCE(ret);
        dep->resource_index = 0;
        dep->flags &= ~DWC3_EP_BUSY;
-       udelay(100);
+
+       if (dwc3_is_usb31(dwc) || dwc->revision < DWC3_REVISION_310A)
+               udelay(100);
 }
 
 static void dwc3_stop_active_transfers(struct dwc3 *dwc)
index ec004c6d76f23a793e60793aeee688afe9a44606..bd86f84f37901da174cc87229504d9d895b2b0e9 100644 (file)
@@ -35,9 +35,9 @@ static int dwc3_ulpi_busyloop(struct dwc3 *dwc)
        return -ETIMEDOUT;
 }
 
-static int dwc3_ulpi_read(struct ulpi_ops *ops, u8 addr)
+static int dwc3_ulpi_read(struct device *dev, u8 addr)
 {
-       struct dwc3 *dwc = dev_get_drvdata(ops->dev);
+       struct dwc3 *dwc = dev_get_drvdata(dev);
        u32 reg;
        int ret;
 
@@ -53,9 +53,9 @@ static int dwc3_ulpi_read(struct ulpi_ops *ops, u8 addr)
        return DWC3_GUSB2PHYACC_DATA(reg);
 }
 
-static int dwc3_ulpi_write(struct ulpi_ops *ops, u8 addr, u8 val)
+static int dwc3_ulpi_write(struct device *dev, u8 addr, u8 val)
 {
-       struct dwc3 *dwc = dev_get_drvdata(ops->dev);
+       struct dwc3 *dwc = dev_get_drvdata(dev);
        u32 reg;
 
        reg = DWC3_GUSB2PHYACC_NEWREGREQ | DWC3_ULPI_ADDR(addr);
@@ -65,7 +65,7 @@ static int dwc3_ulpi_write(struct ulpi_ops *ops, u8 addr, u8 val)
        return dwc3_ulpi_busyloop(dwc);
 }
 
-static struct ulpi_ops dwc3_ulpi_ops = {
+static const struct ulpi_ops dwc3_ulpi_ops = {
        .read = dwc3_ulpi_read,
        .write = dwc3_ulpi_write,
 };
index 3c3f31ceece76b4412362a32b90d86e5e48004ed..2ea3fc3c41b9875bd9e0fdbeaf76bf7d1f370f5e 100644 (file)
@@ -209,25 +209,6 @@ config USB_F_PRINTER
 config USB_F_TCM
        tristate
 
-choice
-       tristate "USB Gadget Drivers"
-       default USB_ETH
-       help
-         A Linux "Gadget Driver" talks to the USB Peripheral Controller
-         driver through the abstract "gadget" API.  Some other operating
-         systems call these "client" drivers, of which "class drivers"
-         are a subset (implementing a USB device class specification).
-         A gadget driver implements one or more USB functions using
-         the peripheral hardware.
-
-         Gadget drivers are hardware-neutral, or "platform independent",
-         except that they sometimes must understand quirks or limitations
-         of the particular controllers they work with.  For example, when
-         a controller doesn't support alternate configurations or provide
-         enough of the right types of endpoints, the gadget driver might
-         not be able work with that controller, or might need to implement
-         a less common variant of a device class protocol.
-
 # this first set of drivers all depend on bulk-capable hardware.
 
 config USB_CONFIGFS
@@ -475,6 +456,25 @@ config USB_CONFIGFS_F_TCM
          Both protocols can work on USB2.0 and USB3.0.
          UAS utilizes the USB 3.0 feature called streams support.
 
+choice
+       tristate "USB Gadget Drivers"
+       default USB_ETH
+       help
+         A Linux "Gadget Driver" talks to the USB Peripheral Controller
+         driver through the abstract "gadget" API.  Some other operating
+         systems call these "client" drivers, of which "class drivers"
+         are a subset (implementing a USB device class specification).
+         A gadget driver implements one or more USB functions using
+         the peripheral hardware.
+
+         Gadget drivers are hardware-neutral, or "platform independent",
+         except that they sometimes must understand quirks or limitations
+         of the particular controllers they work with.  For example, when
+         a controller doesn't support alternate configurations or provide
+         enough of the right types of endpoints, the gadget driver might
+         not be able work with that controller, or might need to implement
+         a less common variant of a device class protocol.
+
 source "drivers/usb/gadget/legacy/Kconfig"
 
 endchoice
index 5ebe6af7976ec4189363651dfe505cf6ec79fb12..32176f779861624578b47be6dd4975a269b7f664 100644 (file)
@@ -1893,17 +1893,21 @@ unknown:
                /* functions always handle their interfaces and endpoints...
                 * punt other recipients (other, WUSB, ...) to the current
                 * configuration code.
-                *
-                * REVISIT it could make sense to let the composite device
-                * take such requests too, if that's ever needed:  to work
-                * in config 0, etc.
                 */
                if (cdev->config) {
                        list_for_each_entry(f, &cdev->config->functions, list)
-                               if (f->req_match && f->req_match(f, ctrl))
+                               if (f->req_match &&
+                                   f->req_match(f, ctrl, false))
                                        goto try_fun_setup;
-                       f = NULL;
+               } else {
+                       struct usb_configuration *c;
+                       list_for_each_entry(c, &cdev->configs, list)
+                               list_for_each_entry(f, &c->functions, list)
+                                       if (f->req_match &&
+                                           f->req_match(f, ctrl, true))
+                                               goto try_fun_setup;
                }
+               f = NULL;
 
                switch (ctrl->bRequestType & USB_RECIP_MASK) {
                case USB_RECIP_INTERFACE:
index f9237fe2be0565857a23c637fd7d878d85fe049a..3984787f8e9720933830864200196b32930e10b4 100644 (file)
@@ -1211,8 +1211,9 @@ static void purge_configs_funcs(struct gadget_info *gi)
 
                        list_move_tail(&f->list, &cfg->func_list);
                        if (f->unbind) {
-                               dev_err(&gi->cdev.gadget->dev, "unbind function"
-                                               " '%s'/%p\n", f->name, f);
+                               dev_dbg(&gi->cdev.gadget->dev,
+                                        "unbind function '%s'/%p\n",
+                                        f->name, f);
                                f->unbind(c, f);
                        }
                }
index 5c8429f23a892782febdb3c650efa8c168705227..0aeed85bb5cbbe76c6a9318db9ef1ee7cdd0ca5d 100644 (file)
@@ -98,6 +98,9 @@ static int ffs_func_set_alt(struct usb_function *, unsigned, unsigned);
 static void ffs_func_disable(struct usb_function *);
 static int ffs_func_setup(struct usb_function *,
                          const struct usb_ctrlrequest *);
+static bool ffs_func_req_match(struct usb_function *,
+                              const struct usb_ctrlrequest *,
+                              bool config0);
 static void ffs_func_suspend(struct usb_function *);
 static void ffs_func_resume(struct usb_function *);
 
@@ -2243,7 +2246,9 @@ static int __ffs_data_got_descs(struct ffs_data *ffs,
                              FUNCTIONFS_HAS_SS_DESC |
                              FUNCTIONFS_HAS_MS_OS_DESC |
                              FUNCTIONFS_VIRTUAL_ADDR |
-                             FUNCTIONFS_EVENTFD)) {
+                             FUNCTIONFS_EVENTFD |
+                             FUNCTIONFS_ALL_CTRL_RECIP |
+                             FUNCTIONFS_CONFIG0_SETUP)) {
                        ret = -ENOSYS;
                        goto error;
                }
@@ -3094,8 +3099,9 @@ static int ffs_func_setup(struct usb_function *f,
         * handle them.  All other either handled by composite or
         * passed to usb_configuration->setup() (if one is set).  No
         * matter, we will handle requests directed to endpoint here
-        * as well (as it's straightforward) but what to do with any
-        * other request?
+        * as well (as it's straightforward).  Other request recipient
+        * types are only handled when the user flag FUNCTIONFS_ALL_CTRL_RECIP
+        * is being used.
         */
        if (ffs->state != FFS_ACTIVE)
                return -ENODEV;
@@ -3116,7 +3122,10 @@ static int ffs_func_setup(struct usb_function *f,
                break;
 
        default:
-               return -EOPNOTSUPP;
+               if (func->ffs->user_flags & FUNCTIONFS_ALL_CTRL_RECIP)
+                       ret = le16_to_cpu(creq->wIndex);
+               else
+                       return -EOPNOTSUPP;
        }
 
        spin_lock_irqsave(&ffs->ev.waitq.lock, flags);
@@ -3128,6 +3137,28 @@ static int ffs_func_setup(struct usb_function *f,
        return 0;
 }
 
+static bool ffs_func_req_match(struct usb_function *f,
+                              const struct usb_ctrlrequest *creq,
+                              bool config0)
+{
+       struct ffs_function *func = ffs_func_from_usb(f);
+
+       if (config0 && !(func->ffs->user_flags & FUNCTIONFS_CONFIG0_SETUP))
+               return false;
+
+       switch (creq->bRequestType & USB_RECIP_MASK) {
+       case USB_RECIP_INTERFACE:
+               return ffs_func_revmap_intf(func,
+                                           le16_to_cpu(creq->wIndex) >= 0);
+       case USB_RECIP_ENDPOINT:
+               return ffs_func_revmap_ep(func,
+                                         le16_to_cpu(creq->wIndex) >= 0);
+       default:
+               return (bool) (func->ffs->user_flags &
+                              FUNCTIONFS_ALL_CTRL_RECIP);
+       }
+}
+
 static void ffs_func_suspend(struct usb_function *f)
 {
        ENTER();
@@ -3378,6 +3409,7 @@ static struct usb_function *ffs_alloc(struct usb_function_instance *fi)
        func->function.set_alt = ffs_func_set_alt;
        func->function.disable = ffs_func_disable;
        func->function.setup   = ffs_func_setup;
+       func->function.req_match = ffs_func_req_match;
        func->function.suspend = ffs_func_suspend;
        func->function.resume  = ffs_func_resume;
        func->function.free_func = ffs_free;
@@ -3470,6 +3502,11 @@ static void _ffs_free_dev(struct ffs_dev *dev)
        list_del(&dev->entry);
        if (dev->name_allocated)
                kfree(dev->name);
+
+       /* Clear the private_data pointer to stop incorrect dev access */
+       if (dev->ffs_data)
+               dev->ffs_data->private_data = NULL;
+
        kfree(dev);
        if (list_empty(&ffs_devices))
                functionfs_cleanup();
index 51980c50546d5b1061eb289b8825604cf8b031bc..e2966f87c860b49e46a7148e51e35a76ca15685c 100644 (file)
@@ -365,7 +365,7 @@ static int f_hidg_open(struct inode *inode, struct file *fd)
 static inline struct usb_request *hidg_alloc_ep_req(struct usb_ep *ep,
                                                    unsigned length)
 {
-       return alloc_ep_req(ep, length, length);
+       return alloc_ep_req(ep, length);
 }
 
 static void hidg_set_report_complete(struct usb_ep *ep, struct usb_request *req)
@@ -617,14 +617,10 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f)
 
        /* preallocate request and buffer */
        status = -ENOMEM;
-       hidg->req = usb_ep_alloc_request(hidg->in_ep, GFP_KERNEL);
+       hidg->req = alloc_ep_req(hidg->in_ep, hidg->report_length);
        if (!hidg->req)
                goto fail;
 
-       hidg->req->buf = kmalloc(hidg->report_length, GFP_KERNEL);
-       if (!hidg->req->buf)
-               goto fail;
-
        /* set descriptor dynamic values */
        hidg_interface_desc.bInterfaceSubClass = hidg->bInterfaceSubClass;
        hidg_interface_desc.bInterfaceProtocol = hidg->bInterfaceProtocol;
@@ -677,11 +673,8 @@ fail_free_descs:
        usb_free_all_descriptors(f);
 fail:
        ERROR(f->config->cdev, "hidg_bind FAILED\n");
-       if (hidg->req != NULL) {
-               kfree(hidg->req->buf);
-               if (hidg->in_ep != NULL)
-                       usb_ep_free_request(hidg->in_ep, hidg->req);
-       }
+       if (hidg->req != NULL)
+               free_ep_req(hidg->in_ep, hidg->req);
 
        return status;
 }
@@ -809,11 +802,21 @@ end:
 
 CONFIGFS_ATTR(f_hid_opts_, report_desc);
 
+static ssize_t f_hid_opts_dev_show(struct config_item *item, char *page)
+{
+       struct f_hid_opts *opts = to_f_hid_opts(item);
+
+       return sprintf(page, "%d:%d\n", major, opts->minor);
+}
+
+CONFIGFS_ATTR_RO(f_hid_opts_, dev);
+
 static struct configfs_attribute *hid_attrs[] = {
        &f_hid_opts_attr_subclass,
        &f_hid_opts_attr_protocol,
        &f_hid_opts_attr_report_length,
        &f_hid_opts_attr_report_desc,
+       &f_hid_opts_attr_dev,
        NULL,
 };
 
@@ -910,8 +913,7 @@ static void hidg_unbind(struct usb_configuration *c, struct usb_function *f)
 
        /* disable/free request and end point */
        usb_ep_disable(hidg->in_ep);
-       kfree(hidg->req->buf);
-       usb_ep_free_request(hidg->in_ep, hidg->req);
+       free_ep_req(hidg->in_ep, hidg->req);
 
        usb_free_all_descriptors(f);
 }
index 3a9f8f9c77bde8d972cdd188b4c6e3cce862471d..e70093835e14a275edbf7c387d89c9f20da488c6 100644 (file)
@@ -308,9 +308,7 @@ static void disable_loopback(struct f_loopback *loop)
 
 static inline struct usb_request *lb_alloc_ep_req(struct usb_ep *ep, int len)
 {
-       struct f_loopback       *loop = ep->driver_data;
-
-       return alloc_ep_req(ep, len, loop->buflen);
+       return alloc_ep_req(ep, len);
 }
 
 static int alloc_requests(struct usb_composite_dev *cdev,
@@ -333,7 +331,7 @@ static int alloc_requests(struct usb_composite_dev *cdev,
                if (!in_req)
                        goto fail;
 
-               out_req = lb_alloc_ep_req(loop->out_ep, 0);
+               out_req = lb_alloc_ep_req(loop->out_ep, loop->buflen);
                if (!out_req)
                        goto fail_in;
 
@@ -593,13 +591,9 @@ DECLARE_USB_FUNCTION(Loopback, loopback_alloc_instance, loopback_alloc);
 
 int __init lb_modinit(void)
 {
-       int ret;
-
-       ret = usb_function_register(&Loopbackusb_func);
-       if (ret)
-               return ret;
-       return ret;
+       return usb_function_register(&Loopbackusb_func);
 }
+
 void __exit lb_modexit(void)
 {
        usb_function_unregister(&Loopbackusb_func);
index 2505117e88e8bad0f1ce98a49498731634ceaf88..8f3659b65f5313303140c7f56100ea4c8cb30b1a 100644 (file)
@@ -311,11 +311,7 @@ struct fsg_common {
        /* Gadget's private data. */
        void                    *private_data;
 
-       /*
-        * Vendor (8 chars), product (16 chars), release (4
-        * hexadecimal digits) and NUL byte
-        */
-       char inquiry_string[8 + 16 + 4 + 1];
+       char inquiry_string[INQUIRY_STRING_LEN];
 
        struct kref             ref;
 };
@@ -1107,7 +1103,12 @@ static int do_inquiry(struct fsg_common *common, struct fsg_buffhd *bh)
        buf[5] = 0;             /* No special options */
        buf[6] = 0;
        buf[7] = 0;
-       memcpy(buf + 8, common->inquiry_string, sizeof common->inquiry_string);
+       if (curlun->inquiry_string[0])
+               memcpy(buf + 8, curlun->inquiry_string,
+                      sizeof(curlun->inquiry_string));
+       else
+               memcpy(buf + 8, common->inquiry_string,
+                      sizeof(common->inquiry_string));
        return 36;
 }
 
@@ -3209,12 +3210,27 @@ static ssize_t fsg_lun_opts_nofua_store(struct config_item *item,
 
 CONFIGFS_ATTR(fsg_lun_opts_, nofua);
 
+static ssize_t fsg_lun_opts_inquiry_string_show(struct config_item *item,
+                                               char *page)
+{
+       return fsg_show_inquiry_string(to_fsg_lun_opts(item)->lun, page);
+}
+
+static ssize_t fsg_lun_opts_inquiry_string_store(struct config_item *item,
+                                                const char *page, size_t len)
+{
+       return fsg_store_inquiry_string(to_fsg_lun_opts(item)->lun, page, len);
+}
+
+CONFIGFS_ATTR(fsg_lun_opts_, inquiry_string);
+
 static struct configfs_attribute *fsg_lun_attrs[] = {
        &fsg_lun_opts_attr_file,
        &fsg_lun_opts_attr_ro,
        &fsg_lun_opts_attr_removable,
        &fsg_lun_opts_attr_cdrom,
        &fsg_lun_opts_attr_nofua,
+       &fsg_lun_opts_attr_inquiry_string,
        NULL,
 };
 
index b6a9918eaefb9306258e2476d351bc95190c0177..d3902313b8ac44dd2a53ba16b346b0d585c3f2e1 100644 (file)
@@ -100,6 +100,7 @@ struct fsg_lun_config {
        char removable;
        char cdrom;
        char nofua;
+       char inquiry_string[INQUIRY_STRING_LEN];
 };
 
 struct fsg_config {
index 58fc199a18ecd735021796ed4c352f7f728d0e22..a5719f271bf0b77e5dfe0cbac1b796ba1fd188b7 100644 (file)
@@ -51,6 +51,19 @@ static const char f_midi_longname[] = "MIDI Gadget";
  */
 #define MAX_PORTS 16
 
+/* MIDI message states */
+enum {
+       STATE_INITIAL = 0,      /* pseudo state */
+       STATE_1PARAM,
+       STATE_2PARAM_1,
+       STATE_2PARAM_2,
+       STATE_SYSEX_0,
+       STATE_SYSEX_1,
+       STATE_SYSEX_2,
+       STATE_REAL_TIME,
+       STATE_FINISHED,         /* pseudo state */
+};
+
 /*
  * This is a gadget, and the IN/OUT naming is from the host's perspective.
  * USB -> OUT endpoint -> rawmidi
@@ -61,13 +74,6 @@ struct gmidi_in_port {
        int active;
        uint8_t cable;
        uint8_t state;
-#define STATE_UNKNOWN  0
-#define STATE_1PARAM   1
-#define STATE_2PARAM_1 2
-#define STATE_2PARAM_2 3
-#define STATE_SYSEX_0  4
-#define STATE_SYSEX_1  5
-#define STATE_SYSEX_2  6
        uint8_t data[2];
 };
 
@@ -205,7 +211,7 @@ static struct usb_gadget_strings *midi_strings[] = {
 static inline struct usb_request *midi_alloc_ep_req(struct usb_ep *ep,
                                                    unsigned length)
 {
-       return alloc_ep_req(ep, length, length);
+       return alloc_ep_req(ep, length);
 }
 
 static const uint8_t f_midi_cin_length[] = {
@@ -299,6 +305,19 @@ f_midi_complete(struct usb_ep *ep, struct usb_request *req)
        }
 }
 
+static void f_midi_drop_out_substreams(struct f_midi *midi)
+{
+       unsigned int i;
+
+       for (i = 0; i < midi->in_ports; i++) {
+               struct gmidi_in_port *port = midi->in_ports_array + i;
+               struct snd_rawmidi_substream *substream = port->substream;
+
+               if (port->active && substream)
+                       snd_rawmidi_drop_output(substream);
+       }
+}
+
 static int f_midi_start_ep(struct f_midi *midi,
                           struct usb_function *f,
                           struct usb_ep *ep)
@@ -360,9 +379,8 @@ static int f_midi_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
        /* allocate a bunch of read buffers and queue them all at once. */
        for (i = 0; i < midi->qlen && err == 0; i++) {
                struct usb_request *req =
-                       midi_alloc_ep_req(midi->out_ep,
-                               max_t(unsigned, midi->buflen,
-                                       bulk_out_desc.wMaxPacketSize));
+                       midi_alloc_ep_req(midi->out_ep, midi->buflen);
+
                if (req == NULL)
                        return -ENOMEM;
 
@@ -397,6 +415,8 @@ static void f_midi_disable(struct usb_function *f)
        /* release IN requests */
        while (kfifo_get(&midi->in_req_fifo, &req))
                free_ep_req(midi->in_ep, req);
+
+       f_midi_drop_out_substreams(midi);
 }
 
 static int f_midi_snd_free(struct snd_device *device)
@@ -404,130 +424,166 @@ static int f_midi_snd_free(struct snd_device *device)
        return 0;
 }
 
-static void f_midi_transmit_packet(struct usb_request *req, uint8_t p0,
-                                       uint8_t p1, uint8_t p2, uint8_t p3)
-{
-       unsigned length = req->length;
-       u8 *buf = (u8 *)req->buf + length;
-
-       buf[0] = p0;
-       buf[1] = p1;
-       buf[2] = p2;
-       buf[3] = p3;
-       req->length = length + 4;
-}
-
 /*
  * Converts MIDI commands to USB MIDI packets.
  */
 static void f_midi_transmit_byte(struct usb_request *req,
                                 struct gmidi_in_port *port, uint8_t b)
 {
-       uint8_t p0 = port->cable << 4;
+       uint8_t p[4] = { port->cable << 4, 0, 0, 0 };
+       uint8_t next_state = STATE_INITIAL;
+
+       switch (b) {
+       case 0xf8 ... 0xff:
+               /* System Real-Time Messages */
+               p[0] |= 0x0f;
+               p[1] = b;
+               next_state = port->state;
+               port->state = STATE_REAL_TIME;
+               break;
 
-       if (b >= 0xf8) {
-               f_midi_transmit_packet(req, p0 | 0x0f, b, 0, 0);
-       } else if (b >= 0xf0) {
+       case 0xf7:
+               /* End of SysEx */
+               switch (port->state) {
+               case STATE_SYSEX_0:
+                       p[0] |= 0x05;
+                       p[1] = 0xf7;
+                       next_state = STATE_FINISHED;
+                       break;
+               case STATE_SYSEX_1:
+                       p[0] |= 0x06;
+                       p[1] = port->data[0];
+                       p[2] = 0xf7;
+                       next_state = STATE_FINISHED;
+                       break;
+               case STATE_SYSEX_2:
+                       p[0] |= 0x07;
+                       p[1] = port->data[0];
+                       p[2] = port->data[1];
+                       p[3] = 0xf7;
+                       next_state = STATE_FINISHED;
+                       break;
+               default:
+                       /* Ignore byte */
+                       next_state = port->state;
+                       port->state = STATE_INITIAL;
+               }
+               break;
+
+       case 0xf0 ... 0xf6:
+               /* System Common Messages */
+               port->data[0] = port->data[1] = 0;
+               port->state = STATE_INITIAL;
                switch (b) {
                case 0xf0:
                        port->data[0] = b;
-                       port->state = STATE_SYSEX_1;
+                       port->data[1] = 0;
+                       next_state = STATE_SYSEX_1;
                        break;
                case 0xf1:
                case 0xf3:
                        port->data[0] = b;
-                       port->state = STATE_1PARAM;
+                       next_state = STATE_1PARAM;
                        break;
                case 0xf2:
                        port->data[0] = b;
-                       port->state = STATE_2PARAM_1;
+                       next_state = STATE_2PARAM_1;
                        break;
                case 0xf4:
                case 0xf5:
-                       port->state = STATE_UNKNOWN;
+                       next_state = STATE_INITIAL;
                        break;
                case 0xf6:
-                       f_midi_transmit_packet(req, p0 | 0x05, 0xf6, 0, 0);
-                       port->state = STATE_UNKNOWN;
-                       break;
-               case 0xf7:
-                       switch (port->state) {
-                       case STATE_SYSEX_0:
-                               f_midi_transmit_packet(req,
-                                       p0 | 0x05, 0xf7, 0, 0);
-                               break;
-                       case STATE_SYSEX_1:
-                               f_midi_transmit_packet(req,
-                                       p0 | 0x06, port->data[0], 0xf7, 0);
-                               break;
-                       case STATE_SYSEX_2:
-                               f_midi_transmit_packet(req,
-                                       p0 | 0x07, port->data[0],
-                                       port->data[1], 0xf7);
-                               break;
-                       }
-                       port->state = STATE_UNKNOWN;
+                       p[0] |= 0x05;
+                       p[1] = 0xf6;
+                       next_state = STATE_FINISHED;
                        break;
                }
-       } else if (b >= 0x80) {
+               break;
+
+       case 0x80 ... 0xef:
+               /*
+                * Channel Voice Messages, Channel Mode Messages
+                * and Control Change Messages.
+                */
                port->data[0] = b;
+               port->data[1] = 0;
+               port->state = STATE_INITIAL;
                if (b >= 0xc0 && b <= 0xdf)
-                       port->state = STATE_1PARAM;
+                       next_state = STATE_1PARAM;
                else
-                       port->state = STATE_2PARAM_1;
-       } else { /* b < 0x80 */
+                       next_state = STATE_2PARAM_1;
+               break;
+
+       case 0x00 ... 0x7f:
+               /* Message parameters */
                switch (port->state) {
                case STATE_1PARAM:
-                       if (port->data[0] < 0xf0) {
-                               p0 |= port->data[0] >> 4;
-                       } else {
-                               p0 |= 0x02;
-                               port->state = STATE_UNKNOWN;
-                       }
-                       f_midi_transmit_packet(req, p0, port->data[0], b, 0);
+                       if (port->data[0] < 0xf0)
+                               p[0] |= port->data[0] >> 4;
+                       else
+                               p[0] |= 0x02;
+
+                       p[1] = port->data[0];
+                       p[2] = b;
+                       /* This is to allow Running State Messages */
+                       next_state = STATE_1PARAM;
                        break;
                case STATE_2PARAM_1:
                        port->data[1] = b;
-                       port->state = STATE_2PARAM_2;
+                       next_state = STATE_2PARAM_2;
                        break;
                case STATE_2PARAM_2:
-                       if (port->data[0] < 0xf0) {
-                               p0 |= port->data[0] >> 4;
-                               port->state = STATE_2PARAM_1;
-                       } else {
-                               p0 |= 0x03;
-                               port->state = STATE_UNKNOWN;
-                       }
-                       f_midi_transmit_packet(req,
-                               p0, port->data[0], port->data[1], b);
+                       if (port->data[0] < 0xf0)
+                               p[0] |= port->data[0] >> 4;
+                       else
+                               p[0] |= 0x03;
+
+                       p[1] = port->data[0];
+                       p[2] = port->data[1];
+                       p[3] = b;
+                       /* This is to allow Running State Messages */
+                       next_state = STATE_2PARAM_1;
                        break;
                case STATE_SYSEX_0:
                        port->data[0] = b;
-                       port->state = STATE_SYSEX_1;
+                       next_state = STATE_SYSEX_1;
                        break;
                case STATE_SYSEX_1:
                        port->data[1] = b;
-                       port->state = STATE_SYSEX_2;
+                       next_state = STATE_SYSEX_2;
                        break;
                case STATE_SYSEX_2:
-                       f_midi_transmit_packet(req,
-                               p0 | 0x04, port->data[0], port->data[1], b);
-                       port->state = STATE_SYSEX_0;
+                       p[0] |= 0x04;
+                       p[1] = port->data[0];
+                       p[2] = port->data[1];
+                       p[3] = b;
+                       next_state = STATE_SYSEX_0;
                        break;
                }
+               break;
        }
-}
 
-static void f_midi_drop_out_substreams(struct f_midi *midi)
-{
-       unsigned int i;
+       /* States where we have to write into the USB request */
+       if (next_state == STATE_FINISHED ||
+           port->state == STATE_SYSEX_2 ||
+           port->state == STATE_1PARAM ||
+           port->state == STATE_2PARAM_2 ||
+           port->state == STATE_REAL_TIME) {
 
-       for (i = 0; i < midi->in_ports; i++) {
-               struct gmidi_in_port *port = midi->in_ports_array + i;
-               struct snd_rawmidi_substream *substream = port->substream;
-               if (port->active && substream)
-                       snd_rawmidi_drop_output(substream);
+               unsigned int length = req->length;
+               u8 *buf = (u8 *)req->buf + length;
+
+               memcpy(buf, p, sizeof(p));
+               req->length = length + sizeof(p);
+
+               if (next_state == STATE_FINISHED) {
+                       next_state = STATE_INITIAL;
+                       port->data[0] = port->data[1] = 0;
+               }
        }
+
+       port->state = next_state;
 }
 
 static int f_midi_do_transmit(struct f_midi *midi, struct usb_ep *ep)
@@ -642,7 +698,7 @@ static int f_midi_in_open(struct snd_rawmidi_substream *substream)
        VDBG(midi, "%s()\n", __func__);
        port = midi->in_ports_array + substream->number;
        port->substream = substream;
-       port->state = STATE_UNKNOWN;
+       port->state = STATE_INITIAL;
        return 0;
 }
 
@@ -1123,7 +1179,7 @@ static struct usb_function_instance *f_midi_alloc_inst(void)
        opts->func_inst.free_func_inst = f_midi_free_inst;
        opts->index = SNDRV_DEFAULT_IDX1;
        opts->id = SNDRV_DEFAULT_STR1;
-       opts->buflen = 256;
+       opts->buflen = 512;
        opts->qlen = 32;
        opts->in_ports = 1;
        opts->out_ports = 1;
index 97f0a9bc84df23bf39fe4b6b1b21a55965907ec1..639603722709648148423d01eb4df85544c9ff49 100644 (file)
@@ -90,7 +90,9 @@ static inline struct f_ncm *func_to_ncm(struct usb_function *f)
 /* peak (theoretical) bulk transfer rate in bits-per-second */
 static inline unsigned ncm_bitrate(struct usb_gadget *g)
 {
-       if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+       if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER)
+               return 13 * 1024 * 8 * 1000 * 8;
+       else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
                return 13 * 512 * 8 * 1000 * 8;
        else
                return 19 *  64 * 1 * 1000 * 8;
@@ -333,6 +335,76 @@ static struct usb_descriptor_header *ncm_hs_function[] = {
        NULL,
 };
 
+
+/* super speed support: */
+
+static struct usb_endpoint_descriptor ss_ncm_notify_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+
+       .bEndpointAddress =     USB_DIR_IN,
+       .bmAttributes =         USB_ENDPOINT_XFER_INT,
+       .wMaxPacketSize =       cpu_to_le16(NCM_STATUS_BYTECOUNT),
+       .bInterval =            USB_MS_TO_HS_INTERVAL(NCM_STATUS_INTERVAL_MS)
+};
+
+static struct usb_ss_ep_comp_descriptor ss_ncm_notify_comp_desc = {
+       .bLength =              sizeof(ss_ncm_notify_comp_desc),
+       .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
+
+       /* the following 3 values can be tweaked if necessary */
+       /* .bMaxBurst =         0, */
+       /* .bmAttributes =      0, */
+       .wBytesPerInterval =    cpu_to_le16(NCM_STATUS_BYTECOUNT),
+};
+
+static struct usb_endpoint_descriptor ss_ncm_in_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+
+       .bEndpointAddress =     USB_DIR_IN,
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+       .wMaxPacketSize =       cpu_to_le16(1024),
+};
+
+static struct usb_endpoint_descriptor ss_ncm_out_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+
+       .bEndpointAddress =     USB_DIR_OUT,
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+       .wMaxPacketSize =       cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor ss_ncm_bulk_comp_desc = {
+       .bLength =              sizeof(ss_ncm_bulk_comp_desc),
+       .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
+
+       /* the following 2 values can be tweaked if necessary */
+       /* .bMaxBurst =         0, */
+       /* .bmAttributes =      0, */
+};
+
+static struct usb_descriptor_header *ncm_ss_function[] = {
+       (struct usb_descriptor_header *) &ncm_iad_desc,
+       /* CDC NCM control descriptors */
+       (struct usb_descriptor_header *) &ncm_control_intf,
+       (struct usb_descriptor_header *) &ncm_header_desc,
+       (struct usb_descriptor_header *) &ncm_union_desc,
+       (struct usb_descriptor_header *) &ecm_desc,
+       (struct usb_descriptor_header *) &ncm_desc,
+       (struct usb_descriptor_header *) &ss_ncm_notify_desc,
+       (struct usb_descriptor_header *) &ss_ncm_notify_comp_desc,
+       /* data interface, altsettings 0 and 1 */
+       (struct usb_descriptor_header *) &ncm_data_nop_intf,
+       (struct usb_descriptor_header *) &ncm_data_intf,
+       (struct usb_descriptor_header *) &ss_ncm_in_desc,
+       (struct usb_descriptor_header *) &ss_ncm_bulk_comp_desc,
+       (struct usb_descriptor_header *) &ss_ncm_out_desc,
+       (struct usb_descriptor_header *) &ss_ncm_bulk_comp_desc,
+       NULL,
+};
+
 /* string descriptors: */
 
 #define STRING_CTRL_IDX        0
@@ -852,6 +924,8 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
                         */
                        ncm->port.is_zlp_ok =
                                gadget_is_zlp_supported(cdev->gadget);
+                       ncm->port.no_skb_reserve =
+                               gadget_avoids_skb_reserve(cdev->gadget);
                        ncm->port.cdc_filter = DEFAULT_FILTER;
                        DBG(cdev, "activate ncm\n");
                        net = gether_connect(&ncm->port);
@@ -1431,8 +1505,13 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f)
        hs_ncm_notify_desc.bEndpointAddress =
                fs_ncm_notify_desc.bEndpointAddress;
 
+       ss_ncm_in_desc.bEndpointAddress = fs_ncm_in_desc.bEndpointAddress;
+       ss_ncm_out_desc.bEndpointAddress = fs_ncm_out_desc.bEndpointAddress;
+       ss_ncm_notify_desc.bEndpointAddress =
+               fs_ncm_notify_desc.bEndpointAddress;
+
        status = usb_assign_descriptors(f, ncm_fs_function, ncm_hs_function,
-                       NULL, NULL);
+                       ncm_ss_function, NULL);
        if (status)
                goto fail;
 
@@ -1450,6 +1529,7 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f)
        ncm->task_timer.function = ncm_tx_timeout;
 
        DBG(cdev, "CDC Network: %s speed IN/%s OUT/%s NOTIFY/%s\n",
+                       gadget_is_superspeed(c->cdev->gadget) ? "super" :
                        gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
                        ncm->port.in_ep->name, ncm->port.out_ep->name,
                        ncm->notify->name);
index 64706a789580dd3bb1641b151d15f0b0831c43ed..0de36cda6e4106156821e4d024c800cf6c4af206 100644 (file)
@@ -889,13 +889,17 @@ static void printer_soft_reset(struct printer_dev *dev)
 /*-------------------------------------------------------------------------*/
 
 static bool gprinter_req_match(struct usb_function *f,
-                              const struct usb_ctrlrequest *ctrl)
+                              const struct usb_ctrlrequest *ctrl,
+                              bool config0)
 {
        struct printer_dev      *dev = func_to_printer(f);
        u16                     w_index = le16_to_cpu(ctrl->wIndex);
        u16                     w_value = le16_to_cpu(ctrl->wValue);
        u16                     w_length = le16_to_cpu(ctrl->wLength);
 
+       if (config0)
+               return false;
+
        if ((ctrl->bRequestType & USB_RECIP_MASK) != USB_RECIP_INTERFACE ||
            (ctrl->bRequestType & USB_TYPE_MASK) != USB_TYPE_CLASS)
                return false;
index df0189ddfdd5fef4248c1528d29835a7b95c5ca0..8784fa12ea2c637b52857a15f01f6dbeb965ec15 100644 (file)
@@ -293,9 +293,7 @@ static struct usb_gadget_strings *sourcesink_strings[] = {
 
 static inline struct usb_request *ss_alloc_ep_req(struct usb_ep *ep, int len)
 {
-       struct f_sourcesink             *ss = ep->driver_data;
-
-       return alloc_ep_req(ep, len, ss->buflen);
+       return alloc_ep_req(ep, len);
 }
 
 static void disable_ep(struct usb_composite_dev *cdev, struct usb_ep *ep)
@@ -606,7 +604,7 @@ static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in,
        } else {
                ep = is_in ? ss->in_ep : ss->out_ep;
                qlen = ss->bulk_qlen;
-               size = 0;
+               size = ss->buflen;
        }
 
        for (i = 0; i < qlen; i++) {
index 29b41b5dee04d2e0e3e87a6dc97d6dde84af49d0..27ed51b5082f66de17c41761f260a4b96dcc0f33 100644 (file)
@@ -258,6 +258,13 @@ uvc_function_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
        memcpy(&uvc_event->req, ctrl, sizeof(uvc_event->req));
        v4l2_event_queue(&uvc->vdev, &v4l2_event);
 
+       /* Pass additional setup data to userspace */
+       if (uvc->event_setup_out && uvc->event_length) {
+               uvc->control_req->length = uvc->event_length;
+               return usb_ep_queue(uvc->func.config->cdev->gadget->ep0,
+                       uvc->control_req, GFP_ATOMIC);
+       }
+
        return 0;
 }
 
index 990df221c6299a2cd9d2ecb9aab54fda5447560e..8fbf6861690d2f6ae20d33d7499003ad887ae835 100644 (file)
@@ -369,6 +369,12 @@ ssize_t fsg_show_removable(struct fsg_lun *curlun, char *buf)
 }
 EXPORT_SYMBOL_GPL(fsg_show_removable);
 
+ssize_t fsg_show_inquiry_string(struct fsg_lun *curlun, char *buf)
+{
+       return sprintf(buf, "%s\n", curlun->inquiry_string);
+}
+EXPORT_SYMBOL_GPL(fsg_show_inquiry_string);
+
 /*
  * The caller must hold fsg->filesem for reading when calling this function.
  */
@@ -499,4 +505,22 @@ ssize_t fsg_store_removable(struct fsg_lun *curlun, const char *buf,
 }
 EXPORT_SYMBOL_GPL(fsg_store_removable);
 
+ssize_t fsg_store_inquiry_string(struct fsg_lun *curlun, const char *buf,
+                                size_t count)
+{
+       const size_t len = min(count, sizeof(curlun->inquiry_string));
+
+       if (len == 0 || buf[0] == '\n') {
+               curlun->inquiry_string[0] = 0;
+       } else {
+               snprintf(curlun->inquiry_string,
+                        sizeof(curlun->inquiry_string), "%-28s", buf);
+               if (curlun->inquiry_string[len-1] == '\n')
+                       curlun->inquiry_string[len-1] = ' ';
+       }
+
+       return count;
+}
+EXPORT_SYMBOL_GPL(fsg_store_inquiry_string);
+
 MODULE_LICENSE("GPL");
index c3544e61da6690f2b377e0a8e2cc8e7f835389ea..e69848994cb46488d1685efbf7565504c5c6947d 100644 (file)
@@ -88,6 +88,12 @@ do {                                                                 \
 #define ASC(x)         ((u8) ((x) >> 8))
 #define ASCQ(x)                ((u8) (x))
 
+/*
+ * Vendor (8 chars), product (16 chars), release (4 hexadecimal digits) and NUL
+ * byte
+ */
+#define INQUIRY_STRING_LEN ((size_t) (8 + 16 + 4 + 1))
+
 struct fsg_lun {
        struct file     *filp;
        loff_t          file_length;
@@ -112,6 +118,7 @@ struct fsg_lun {
        struct device   dev;
        const char      *name;          /* "lun.name" */
        const char      **name_pfx;     /* "function.name" */
+       char            inquiry_string[INQUIRY_STRING_LEN];
 };
 
 static inline bool fsg_lun_is_open(struct fsg_lun *curlun)
@@ -210,6 +217,7 @@ ssize_t fsg_show_ro(struct fsg_lun *curlun, char *buf);
 ssize_t fsg_show_nofua(struct fsg_lun *curlun, char *buf);
 ssize_t fsg_show_file(struct fsg_lun *curlun, struct rw_semaphore *filesem,
                      char *buf);
+ssize_t fsg_show_inquiry_string(struct fsg_lun *curlun, char *buf);
 ssize_t fsg_show_cdrom(struct fsg_lun *curlun, char *buf);
 ssize_t fsg_show_removable(struct fsg_lun *curlun, char *buf);
 ssize_t fsg_store_ro(struct fsg_lun *curlun, struct rw_semaphore *filesem,
@@ -221,5 +229,7 @@ ssize_t fsg_store_cdrom(struct fsg_lun *curlun, struct rw_semaphore *filesem,
                        const char *buf, size_t count);
 ssize_t fsg_store_removable(struct fsg_lun *curlun, const char *buf,
                            size_t count);
+ssize_t fsg_store_inquiry_string(struct fsg_lun *curlun, const char *buf,
+                                size_t count);
 
 #endif /* USB_STORAGE_COMMON_H */
index 5f562c1ec795718900e5e33de6d6e051eb2bb2ae..8cb08033b7c152b388a291d03499f7f180566d4b 100644 (file)
@@ -82,6 +82,7 @@ struct eth_dev {
 #define        WORK_RX_MEMORY          0
 
        bool                    zlp;
+       bool                    no_skb_reserve;
        u8                      host_mac[ETH_ALEN];
        u8                      dev_mac[ETH_ALEN];
 };
@@ -233,7 +234,8 @@ rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags)
         * but on at least one, checksumming fails otherwise.  Note:
         * RNDIS headers involve variable numbers of LE32 values.
         */
-       skb_reserve(skb, NET_IP_ALIGN);
+       if (likely(!dev->no_skb_reserve))
+               skb_reserve(skb, NET_IP_ALIGN);
 
        req->buf = skb->data;
        req->length = size;
@@ -551,14 +553,16 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
                spin_lock_irqsave(&dev->lock, flags);
                if (dev->port_usb)
                        skb = dev->wrap(dev->port_usb, skb);
-               spin_unlock_irqrestore(&dev->lock, flags);
                if (!skb) {
                        /* Multi frame CDC protocols may store the frame for
                         * later which is not a dropped frame.
                         */
                        if (dev->port_usb &&
-                                       dev->port_usb->supports_multi_frame)
+                                       dev->port_usb->supports_multi_frame) {
+                               spin_unlock_irqrestore(&dev->lock, flags);
                                goto multiframe;
+                       }
+                       spin_unlock_irqrestore(&dev->lock, flags);
                        goto drop;
                }
        }
@@ -569,12 +573,14 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
        req->complete = tx_complete;
 
        /* NCM requires no zlp if transfer is dwNtbInMaxSize */
-       if (dev->port_usb->is_fixed &&
+       if (dev->port_usb &&
+           dev->port_usb->is_fixed &&
            length == dev->port_usb->fixed_in_len &&
            (length % in->maxpacket) == 0)
                req->zero = 0;
        else
                req->zero = 1;
+       spin_unlock_irqrestore(&dev->lock, flags);
 
        /* use zlp framing on tx for strict CDC-Ether conformance,
         * though any robust network rx path ignores extra padding.
@@ -1063,6 +1069,7 @@ struct net_device *gether_connect(struct gether *link)
 
        if (result == 0) {
                dev->zlp = link->is_zlp_ok;
+               dev->no_skb_reserve = link->no_skb_reserve;
                DBG(dev, "qlen %d\n", qlen(dev->gadget, dev->qmult));
 
                dev->header_len = link->header_len;
index c77145bd6b5b94f65b8531f2ab061c2770edbae5..81d94a7ae4b4da5d04e17a0ea8e98080c4a62da9 100644 (file)
@@ -64,6 +64,7 @@ struct gether {
        struct usb_ep                   *out_ep;
 
        bool                            is_zlp_ok;
+       bool                            no_skb_reserve;
 
        u16                             cdc_filter;
 
index fc2ac150f5ffc4e15398a6d5a1a8d23f75baea53..0bf39c3ccdb1c22df1533e3dbb76231b4bb51461 100644 (file)
@@ -47,7 +47,7 @@ static char *id = SNDRV_DEFAULT_STR1;
 module_param(id, charp, S_IRUGO);
 MODULE_PARM_DESC(id, "ID string for the USB MIDI Gadget adapter.");
 
-static unsigned int buflen = 256;
+static unsigned int buflen = 512;
 module_param(buflen, uint, S_IRUGO);
 MODULE_PARM_DESC(buflen, "MIDI buffer length");
 
index 4bc7eea8bfc84d0c941b8ba7ec743e1db313db97..18839732c8406d18467bcd9c518fc5fc2db84be5 100644 (file)
  */
 
 #include "u_f.h"
+#include <linux/usb/ch9.h>
 
-struct usb_request *alloc_ep_req(struct usb_ep *ep, int len, int default_len)
+struct usb_request *alloc_ep_req(struct usb_ep *ep, size_t len)
 {
        struct usb_request      *req;
 
        req = usb_ep_alloc_request(ep, GFP_ATOMIC);
        if (req) {
-               req->length = len ?: default_len;
+               req->length = usb_endpoint_dir_out(ep->desc) ?
+                       usb_ep_align(ep, len) : len;
                req->buf = kmalloc(req->length, GFP_ATOMIC);
                if (!req->buf) {
                        usb_ep_free_request(ep, req);
index 4247cc098a8915c49286ff4c57978f77d89f1125..7d53a4773d1af5a303e292234239769b97878d2f 100644 (file)
 struct usb_ep;
 struct usb_request;
 
-/* Requests allocated via alloc_ep_req() must be freed by free_ep_req(). */
-struct usb_request *alloc_ep_req(struct usb_ep *ep, int len, int default_len);
+/**
+ * alloc_ep_req - returns a usb_request allocated by the gadget driver and
+ * allocates the request's buffer.
+ *
+ * @ep: the endpoint to allocate a usb_request
+ * @len: usb_requests's buffer suggested size
+ *
+ * In case @ep direction is OUT, the @len will be aligned to ep's
+ * wMaxPacketSize. In order to avoid memory leaks or drops, *always* use
+ * usb_requests's length (req->length) to refer to the allocated buffer size.
+ * Requests allocated via alloc_ep_req() *must* be freed by free_ep_req().
+ */
+struct usb_request *alloc_ep_req(struct usb_ep *ep, size_t len);
+
+/* Frees a usb_request previously allocated by alloc_ep_req() */
 static inline void free_ep_req(struct usb_ep *ep, struct usb_request *req)
 {
        kfree(req->buf);
index 40c04bb25f2f9f2eee7c4b326e8585e6de3e4fb9..9483489080f66230370db44a2326a152a3f3eb47 100644 (file)
@@ -107,10 +107,8 @@ int usb_ep_enable(struct usb_ep *ep)
                goto out;
 
        ret = ep->ops->enable(ep, ep->desc);
-       if (ret) {
-               ret = ret;
+       if (ret)
                goto out;
-       }
 
        ep->enabled = true;
 
index 1400415fe67ac863a5fafe5f4395e92c5298c710..5107987bd35382b8054d789c44546fc196c40f3d 100644 (file)
@@ -1838,6 +1838,8 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 err:
        if (dev)
                goku_remove (pdev);
+       /* gadget_release is not registered yet, kfree explicitly */
+       kfree(dev);
        return retval;
 }
 
index 614ab951a4ae6e0fca159a17ae9fd9914aedd727..61c938c36d88fd2ce83f2d149910f4086ddce5e1 100644 (file)
@@ -589,7 +589,7 @@ static void net2280_free_request(struct usb_ep *_ep, struct usb_request *_req)
 
        ep = container_of(_ep, struct net2280_ep, ep);
        if (!_ep || !_req) {
-               dev_err(&ep->dev->pdev->dev, "%s: Inavlid ep=%p or req=%p\n",
+               dev_err(&ep->dev->pdev->dev, "%s: Invalid ep=%p or req=%p\n",
                                                        __func__, _ep, _req);
                return;
        }
@@ -1137,8 +1137,10 @@ dma_done(struct net2280_ep *ep,  struct net2280_request *req, u32 dmacount,
        done(ep, req, status);
 }
 
-static void scan_dma_completions(struct net2280_ep *ep)
+static int scan_dma_completions(struct net2280_ep *ep)
 {
+       int num_completed = 0;
+
        /* only look at descriptors that were "naturally" retired,
         * so fifo and list head state won't matter
         */
@@ -1166,6 +1168,7 @@ static void scan_dma_completions(struct net2280_ep *ep)
                                break;
                        /* single transfer mode */
                        dma_done(ep, req, tmp, 0);
+                       num_completed++;
                        break;
                } else if (!ep->is_in &&
                           (req->req.length % ep->ep.maxpacket) &&
@@ -1194,7 +1197,10 @@ static void scan_dma_completions(struct net2280_ep *ep)
                        }
                }
                dma_done(ep, req, tmp, 0);
+               num_completed++;
        }
+
+       return num_completed;
 }
 
 static void restart_dma(struct net2280_ep *ep)
@@ -1567,6 +1573,44 @@ static struct usb_ep *net2280_match_ep(struct usb_gadget *_gadget,
                        return ep;
        }
 
+       /* USB3380: Only first four endpoints have DMA channels. Allocate
+        * slower interrupt endpoints from PIO hw endpoints, to allow bulk/isoc
+        * endpoints use DMA hw endpoints.
+        */
+       if (usb_endpoint_type(desc) == USB_ENDPOINT_XFER_INT &&
+           usb_endpoint_dir_in(desc)) {
+               ep = gadget_find_ep_by_name(_gadget, "ep2in");
+               if (ep && usb_gadget_ep_match_desc(_gadget, ep, desc, ep_comp))
+                       return ep;
+               ep = gadget_find_ep_by_name(_gadget, "ep4in");
+               if (ep && usb_gadget_ep_match_desc(_gadget, ep, desc, ep_comp))
+                       return ep;
+       } else if (usb_endpoint_type(desc) == USB_ENDPOINT_XFER_INT &&
+                  !usb_endpoint_dir_in(desc)) {
+               ep = gadget_find_ep_by_name(_gadget, "ep1out");
+               if (ep && usb_gadget_ep_match_desc(_gadget, ep, desc, ep_comp))
+                       return ep;
+               ep = gadget_find_ep_by_name(_gadget, "ep3out");
+               if (ep && usb_gadget_ep_match_desc(_gadget, ep, desc, ep_comp))
+                       return ep;
+       } else if (usb_endpoint_type(desc) != USB_ENDPOINT_XFER_BULK &&
+                  usb_endpoint_dir_in(desc)) {
+               ep = gadget_find_ep_by_name(_gadget, "ep1in");
+               if (ep && usb_gadget_ep_match_desc(_gadget, ep, desc, ep_comp))
+                       return ep;
+               ep = gadget_find_ep_by_name(_gadget, "ep3in");
+               if (ep && usb_gadget_ep_match_desc(_gadget, ep, desc, ep_comp))
+                       return ep;
+       } else if (usb_endpoint_type(desc) != USB_ENDPOINT_XFER_BULK &&
+                  !usb_endpoint_dir_in(desc)) {
+               ep = gadget_find_ep_by_name(_gadget, "ep2out");
+               if (ep && usb_gadget_ep_match_desc(_gadget, ep, desc, ep_comp))
+                       return ep;
+               ep = gadget_find_ep_by_name(_gadget, "ep4out");
+               if (ep && usb_gadget_ep_match_desc(_gadget, ep, desc, ep_comp))
+                       return ep;
+       }
+
        /* USB3380: use same address for usb and hardware endpoints */
        snprintf(name, sizeof(name), "ep%d%s", usb_endpoint_num(desc),
                        usb_endpoint_dir_in(desc) ? "in" : "out");
@@ -2547,8 +2591,11 @@ static void handle_ep_small(struct net2280_ep *ep)
        /* manual DMA queue advance after short OUT */
        if (likely(ep->dma)) {
                if (t & BIT(SHORT_PACKET_TRANSFERRED_INTERRUPT)) {
-                       u32     count;
+                       struct net2280_request *stuck_req = NULL;
                        int     stopped = ep->stopped;
+                       int     num_completed;
+                       int     stuck = 0;
+                       u32     count;
 
                        /* TRANSFERRED works around OUT_DONE erratum 0112.
                         * we expect (N <= maxpacket) bytes; host wrote M.
@@ -2560,7 +2607,7 @@ static void handle_ep_small(struct net2280_ep *ep)
                                /* any preceding dma transfers must finish.
                                 * dma handles (M >= N), may empty the queue
                                 */
-                               scan_dma_completions(ep);
+                               num_completed = scan_dma_completions(ep);
                                if (unlikely(list_empty(&ep->queue) ||
                                                ep->out_overflow)) {
                                        req = NULL;
@@ -2580,6 +2627,31 @@ static void handle_ep_small(struct net2280_ep *ep)
                                                req = NULL;
                                        break;
                                }
+
+                               /* Escape loop if no dma transfers completed
+                                * after few retries.
+                                */
+                               if (num_completed == 0) {
+                                       if (stuck_req == req &&
+                                           readl(&ep->dma->dmadesc) !=
+                                                 req->td_dma && stuck++ > 5) {
+                                               count = readl(
+                                                       &ep->dma->dmacount);
+                                               count &= DMA_BYTE_COUNT_MASK;
+                                               req = NULL;
+                                               ep_dbg(ep->dev, "%s escape stuck %d, count %u\n",
+                                                       ep->ep.name, stuck,
+                                                       count);
+                                               break;
+                                       } else if (stuck_req != req) {
+                                               stuck_req = req;
+                                               stuck = 0;
+                                       }
+                               } else {
+                                       stuck_req = NULL;
+                                       stuck = 0;
+                               }
+
                                udelay(1);
                        }
 
index ad140aa00132eb73dc9d490c5eb06e1b79190878..7fa60f5b7ae408b39461107954d561bc303926af 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/usb.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
+#include <linux/usb/phy.h>
 
 #include "pxa27x_udc.h"
 
@@ -1655,6 +1656,37 @@ static int pxa_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
        return -EOPNOTSUPP;
 }
 
+/**
+ * pxa_udc_phy_event - Called by phy upon VBus event
+ * @nb: notifier block
+ * @action: phy action, is vbus connect or disconnect
+ * @data: the usb_gadget structure in pxa_udc
+ *
+ * Called by the USB Phy when a cable connect or disconnect is sensed.
+ *
+ * Returns 0
+ */
+static int pxa_udc_phy_event(struct notifier_block *nb, unsigned long action,
+                            void *data)
+{
+       struct usb_gadget *gadget = data;
+
+       switch (action) {
+       case USB_EVENT_VBUS:
+               usb_gadget_vbus_connect(gadget);
+               return NOTIFY_OK;
+       case USB_EVENT_NONE:
+               usb_gadget_vbus_disconnect(gadget);
+               return NOTIFY_OK;
+       default:
+               return NOTIFY_DONE;
+       }
+}
+
+static struct notifier_block pxa27x_udc_phy = {
+       .notifier_call = pxa_udc_phy_event,
+};
+
 static int pxa27x_udc_start(struct usb_gadget *g,
                struct usb_gadget_driver *driver);
 static int pxa27x_udc_stop(struct usb_gadget *g);
@@ -2432,7 +2464,14 @@ static int pxa_udc_probe(struct platform_device *pdev)
                return udc->irq;
 
        udc->dev = &pdev->dev;
-       udc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
+       if (of_have_populated_dt()) {
+               udc->transceiver =
+                       devm_usb_get_phy_by_phandle(udc->dev, "phys", 0);
+               if (IS_ERR(udc->transceiver))
+                       return PTR_ERR(udc->transceiver);
+       } else {
+               udc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
+       }
 
        if (IS_ERR(udc->gpiod)) {
                dev_err(&pdev->dev, "Couldn't find or request D+ gpio : %ld\n",
@@ -2465,14 +2504,20 @@ static int pxa_udc_probe(struct platform_device *pdev)
                goto err;
        }
 
+       if (!IS_ERR_OR_NULL(udc->transceiver))
+               usb_register_notifier(udc->transceiver, &pxa27x_udc_phy);
        retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
        if (retval)
-               goto err;
+               goto err_add_gadget;
 
        pxa_init_debugfs(udc);
        if (should_enable_udc(udc))
                udc_enable(udc);
        return 0;
+
+err_add_gadget:
+       if (!IS_ERR_OR_NULL(udc->transceiver))
+               usb_unregister_notifier(udc->transceiver, &pxa27x_udc_phy);
 err:
        clk_unprepare(udc->clk);
        return retval;
@@ -2489,6 +2534,8 @@ static int pxa_udc_remove(struct platform_device *_dev)
        usb_del_gadget_udc(&udc->gadget);
        pxa_cleanup_debugfs(udc);
 
+       if (!IS_ERR_OR_NULL(udc->transceiver))
+               usb_unregister_notifier(udc->transceiver, &pxa27x_udc_phy);
        usb_put_phy(udc->transceiver);
 
        udc->transceiver = NULL;
index 0c912d3950a5f177b5a0e0900b29b18074ca8fb8..a03caf4b1327c441f086724f42e317f7d7793172 100644 (file)
@@ -1248,7 +1248,7 @@ static void ab8500_usb_set_ab8500_tuning_values(struct ab8500_usb *ab)
        err = abx500_set_register_interruptible(ab->dev,
                        AB8500_DEBUG, AB8500_USB_PHY_TUNE3, 0x78);
        if (err < 0)
-               dev_err(ab->dev, "Failed to set PHY_TUNE3 regester err=%d\n",
+               dev_err(ab->dev, "Failed to set PHY_TUNE3 register err=%d\n",
                                err);
 
        /* Switch to normal mode/disable Bank 0x12 access */
@@ -1290,7 +1290,7 @@ static void ab8500_usb_set_ab8505_tuning_values(struct ab8500_usb *ab)
                        0xFC, 0x80);
 
        if (err < 0)
-               dev_err(ab->dev, "Failed to set PHY_TUNE3 regester err=%d\n",
+               dev_err(ab->dev, "Failed to set PHY_TUNE3 register err=%d\n",
                                err);
 
        /* Switch to normal mode/disable Bank 0x12 access */
@@ -1321,7 +1321,7 @@ static void ab8500_usb_set_ab8540_tuning_values(struct ab8500_usb *ab)
        err = abx500_set_register_interruptible(ab->dev,
                        AB8540_DEBUG, AB8500_USB_PHY_TUNE3, 0x90);
        if (err < 0)
-               dev_err(ab->dev, "Failed to set PHY_TUNE3 regester ret=%d\n",
+               dev_err(ab->dev, "Failed to set PHY_TUNE3 register ret=%d\n",
                                err);
 }
 
@@ -1351,7 +1351,7 @@ static void ab8500_usb_set_ab9540_tuning_values(struct ab8500_usb *ab)
        err = abx500_set_register_interruptible(ab->dev,
                        AB8500_DEBUG, AB8500_USB_PHY_TUNE3, 0x80);
        if (err < 0)
-               dev_err(ab->dev, "Failed to set PHY_TUNE3 regester err=%d\n",
+               dev_err(ab->dev, "Failed to set PHY_TUNE3 register err=%d\n",
                                err);
 
        /* Switch to normal mode/disable Bank 0x12 access */
index 427efb5eebae9b386c2437d0da82477462cd184f..8311ba2968cd1e14f21b6c497b463d4ec4cf9abe 100644 (file)
@@ -118,8 +118,6 @@ static irqreturn_t nop_gpio_vbus_thread(int irq, void *data)
                status = USB_EVENT_VBUS;
                otg->state = OTG_STATE_B_PERIPHERAL;
                nop->phy.last_event = status;
-               if (otg->gadget)
-                       usb_gadget_vbus_connect(otg->gadget);
 
                /* drawing a "unit load" is *always* OK, except for OTG */
                nop_set_vbus_draw(nop, 100);
@@ -129,8 +127,6 @@ static irqreturn_t nop_gpio_vbus_thread(int irq, void *data)
        } else {
                nop_set_vbus_draw(nop, 0);
 
-               if (otg->gadget)
-                       usb_gadget_vbus_disconnect(otg->gadget);
                status = USB_EVENT_NONE;
                otg->state = OTG_STATE_B_IDLE;
                nop->phy.last_event = status;
@@ -191,7 +187,8 @@ static int nop_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget)
 
        otg->gadget = gadget;
        if (otg->state == OTG_STATE_B_PERIPHERAL)
-               usb_gadget_vbus_connect(gadget);
+               atomic_notifier_call_chain(&otg->usb_phy->notifier,
+                                          USB_EVENT_VBUS, otg->gadget);
        else
                otg->state = OTG_STATE_B_IDLE;
        return 0;
@@ -326,6 +323,8 @@ static int usb_phy_generic_probe(struct platform_device *pdev)
                                gpiod_to_irq(nop->gpiod_vbus), err);
                        return err;
                }
+               nop->phy.otg->state = gpiod_get_value(nop->gpiod_vbus) ?
+                       OTG_STATE_B_PERIPHERAL : OTG_STATE_B_IDLE;
        }
 
        nop->phy.init           = usb_gen_phy_init;
index 00bfea01be6501d9b53ccc7975b069c24bc57d7b..0e2f1a36d315dabcb26de84bc97ea752c13c0ba3 100644 (file)
@@ -27,6 +27,7 @@
 #define DRIVER_NAME "mxs_phy"
 
 #define HW_USBPHY_PWD                          0x00
+#define HW_USBPHY_TX                           0x10
 #define HW_USBPHY_CTRL                         0x30
 #define HW_USBPHY_CTRL_SET                     0x34
 #define HW_USBPHY_CTRL_CLR                     0x38
 #define HW_USBPHY_IP_SET                       0x94
 #define HW_USBPHY_IP_CLR                       0x98
 
+#define GM_USBPHY_TX_TXCAL45DP(x)            (((x) & 0xf) << 16)
+#define GM_USBPHY_TX_TXCAL45DN(x)            (((x) & 0xf) << 8)
+#define GM_USBPHY_TX_D_CAL(x)                (((x) & 0xf) << 0)
+
 #define BM_USBPHY_CTRL_SFTRST                  BIT(31)
 #define BM_USBPHY_CTRL_CLKGATE                 BIT(30)
 #define BM_USBPHY_CTRL_OTG_ID_VALUE            BIT(27)
  */
 #define MXS_PHY_NEED_IP_FIX                    BIT(3)
 
+/* Minimum and maximum values for device tree entries */
+#define MXS_PHY_TX_CAL45_MIN                   30
+#define MXS_PHY_TX_CAL45_MAX                   55
+#define MXS_PHY_TX_D_CAL_MIN                   79
+#define MXS_PHY_TX_D_CAL_MAX                   119
+
 struct mxs_phy_data {
        unsigned int flags;
 };
@@ -164,6 +175,8 @@ struct mxs_phy {
        const struct mxs_phy_data *data;
        struct regmap *regmap_anatop;
        int port_id;
+       u32 tx_reg_set;
+       u32 tx_reg_mask;
 };
 
 static inline bool is_imx6q_phy(struct mxs_phy *mxs_phy)
@@ -185,6 +198,20 @@ static void mxs_phy_clock_switch_delay(void)
        usleep_range(300, 400);
 }
 
+static void mxs_phy_tx_init(struct mxs_phy *mxs_phy)
+{
+       void __iomem *base = mxs_phy->phy.io_priv;
+       u32 phytx;
+
+       /* Update TX register if there is anything to write */
+       if (mxs_phy->tx_reg_mask) {
+               phytx = readl(base + HW_USBPHY_TX);
+               phytx &= ~mxs_phy->tx_reg_mask;
+               phytx |= mxs_phy->tx_reg_set;
+               writel(phytx, base + HW_USBPHY_TX);
+       }
+}
+
 static int mxs_phy_hw_init(struct mxs_phy *mxs_phy)
 {
        int ret;
@@ -214,6 +241,8 @@ static int mxs_phy_hw_init(struct mxs_phy *mxs_phy)
        if (mxs_phy->data->flags & MXS_PHY_NEED_IP_FIX)
                writel(BM_USBPHY_IP_FIX, base + HW_USBPHY_IP_SET);
 
+       mxs_phy_tx_init(mxs_phy);
+
        return 0;
 }
 
@@ -459,6 +488,7 @@ static int mxs_phy_probe(struct platform_device *pdev)
        int ret;
        const struct of_device_id *of_id;
        struct device_node *np = pdev->dev.of_node;
+       u32 val;
 
        of_id = of_match_device(mxs_phy_dt_ids, &pdev->dev);
        if (!of_id)
@@ -491,6 +521,37 @@ static int mxs_phy_probe(struct platform_device *pdev)
                }
        }
 
+       /* Precompute which bits of the TX register are to be updated, if any */
+       if (!of_property_read_u32(np, "fsl,tx-cal-45-dn-ohms", &val) &&
+           val >= MXS_PHY_TX_CAL45_MIN && val <= MXS_PHY_TX_CAL45_MAX) {
+               /* Scale to a 4-bit value */
+               val = (MXS_PHY_TX_CAL45_MAX - val) * 0xF
+                       / (MXS_PHY_TX_CAL45_MAX - MXS_PHY_TX_CAL45_MIN);
+               mxs_phy->tx_reg_mask |= GM_USBPHY_TX_TXCAL45DN(~0);
+               mxs_phy->tx_reg_set  |= GM_USBPHY_TX_TXCAL45DN(val);
+       }
+
+       if (!of_property_read_u32(np, "fsl,tx-cal-45-dp-ohms", &val) &&
+           val >= MXS_PHY_TX_CAL45_MIN && val <= MXS_PHY_TX_CAL45_MAX) {
+               /* Scale to a 4-bit value. */
+               val = (MXS_PHY_TX_CAL45_MAX - val) * 0xF
+                       / (MXS_PHY_TX_CAL45_MAX - MXS_PHY_TX_CAL45_MIN);
+               mxs_phy->tx_reg_mask |= GM_USBPHY_TX_TXCAL45DP(~0);
+               mxs_phy->tx_reg_set  |= GM_USBPHY_TX_TXCAL45DP(val);
+       }
+
+       if (!of_property_read_u32(np, "fsl,tx-d-cal", &val) &&
+           val >= MXS_PHY_TX_D_CAL_MIN && val <= MXS_PHY_TX_D_CAL_MAX) {
+               /* Scale to a 4-bit value.  Round up the values and heavily
+                * weight the rounding by adding 2/3 of the denominator.
+                */
+               val = ((MXS_PHY_TX_D_CAL_MAX - val) * 0xF
+                       + (MXS_PHY_TX_D_CAL_MAX - MXS_PHY_TX_D_CAL_MIN) * 2/3)
+                       / (MXS_PHY_TX_D_CAL_MAX - MXS_PHY_TX_D_CAL_MIN);
+               mxs_phy->tx_reg_mask |= GM_USBPHY_TX_D_CAL(~0);
+               mxs_phy->tx_reg_set  |= GM_USBPHY_TX_D_CAL(val);
+       }
+
        ret = of_alias_get_id(np, "usbphy");
        if (ret < 0)
                dev_dbg(&pdev->dev, "failed to get alias id, errno %d\n", ret);
index ac67bab9124cc043e0c858a8858fc4adb7e5878d..012a37aa3e0d4c4dfe132b6b9792ed13b8410f42 100644 (file)
@@ -481,6 +481,10 @@ static const struct of_device_id usbhs_of_match[] = {
                .compatible = "renesas,usbhs-r8a7795",
                .data = (void *)USBHS_TYPE_RCAR_GEN3,
        },
+       {
+               .compatible = "renesas,usbhs-r8a7796",
+               .data = (void *)USBHS_TYPE_RCAR_GEN3,
+       },
        {
                .compatible = "renesas,rcar-gen2-usbhs",
                .data = (void *)USBHS_TYPE_RCAR_GEN2,
index 86b37a8eedd445d9559c35bec1bead959bb22f1f..5bc7a6138855ec7ecf69046ceb71a3c992ccb9fa 100644 (file)
@@ -1102,6 +1102,8 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv)
        gpriv->gadget.name              = "renesas_usbhs_udc";
        gpriv->gadget.ops               = &usbhsg_gadget_ops;
        gpriv->gadget.max_speed         = USB_SPEED_HIGH;
+       gpriv->gadget.quirk_avoids_skb_reserve = usbhs_get_dparam(priv,
+                                                               has_usb_dmac);
 
        INIT_LIST_HEAD(&gpriv->gadget.ep_list);
 
index 80b36ca12e80ec9aec1cff524475e7195526c1a1..a7af21a5524805b47718ef8001eea20e83860647 100644 (file)
@@ -15,7 +15,7 @@ struct ulpi_ops;
  */
 struct ulpi {
        struct ulpi_device_id id;
-       struct ulpi_ops *ops;
+       const struct ulpi_ops *ops;
        struct device dev;
 };
 
index 4de8ab491038382d3f098e00fe6287fa84ec1875..a2011a919eb61f39a1d1be6e01159b29b0e71113 100644 (file)
@@ -4,20 +4,19 @@
 #include <linux/types.h>
 
 struct ulpi;
+struct device;
 
 /**
  * struct ulpi_ops - ULPI register access
- * @dev: the interface provider
  * @read: read operation for ULPI register access
  * @write: write operation for ULPI register access
  */
 struct ulpi_ops {
-       struct device *dev;
-       int (*read)(struct ulpi_ops *ops, u8 addr);
-       int (*write)(struct ulpi_ops *ops, u8 addr, u8 val);
+       int (*read)(struct device *dev, u8 addr);
+       int (*write)(struct device *dev, u8 addr, u8 val);
 };
 
-struct ulpi *ulpi_register_interface(struct device *, struct ulpi_ops *);
+struct ulpi *ulpi_register_interface(struct device *, const struct ulpi_ops *);
 void ulpi_unregister_interface(struct ulpi *);
 
 #endif /* __LINUX_ULPI_INTERFACE_H */
index 2b81b24eb5aa30d852046d7ab8ef39d46145250d..4616a49a1c2e58c61e3bc602fa214e0be40f8820 100644 (file)
@@ -220,7 +220,8 @@ struct usb_function {
        int                     (*setup)(struct usb_function *,
                                        const struct usb_ctrlrequest *);
        bool                    (*req_match)(struct usb_function *,
-                                       const struct usb_ctrlrequest *);
+                                       const struct usb_ctrlrequest *,
+                                       bool config0);
        void                    (*suspend)(struct usb_function *);
        void                    (*resume)(struct usb_function *);
 
index 612dbdfa388ed29db4620149954b7ee46603d393..8e81f9eb95e40134f52cd49bd9c3cf5a948735f7 100644 (file)
@@ -346,6 +346,8 @@ struct usb_gadget_ops {
  *     or B-Peripheral wants to take host role.
  * @quirk_ep_out_aligned_size: epout requires buffer size to be aligned to
  *     MaxPacketSize.
+ * @quirk_avoids_skb_reserve: udc/platform wants to avoid skb_reserve() in
+ *     u_ether.c to improve performance.
  * @is_selfpowered: if the gadget is self-powered.
  * @deactivated: True if gadget is deactivated - in deactivated state it cannot
  *     be connected.
@@ -398,6 +400,7 @@ struct usb_gadget {
        unsigned                        quirk_altset_not_supp:1;
        unsigned                        quirk_stall_not_supp:1;
        unsigned                        quirk_zlp_not_supp:1;
+       unsigned                        quirk_avoids_skb_reserve:1;
        unsigned                        is_selfpowered:1;
        unsigned                        deactivated:1;
        unsigned                        connected:1;
@@ -417,9 +420,21 @@ static inline struct usb_gadget *dev_to_usb_gadget(struct device *dev)
 #define gadget_for_each_ep(tmp, gadget) \
        list_for_each_entry(tmp, &(gadget)->ep_list, ep_list)
 
+/**
+ * usb_ep_align - returns @len aligned to ep's maxpacketsize.
+ * @ep: the endpoint whose maxpacketsize is used to align @len
+ * @len: buffer size's length to align to @ep's maxpacketsize
+ *
+ * This helper is used to align buffer's size to an ep's maxpacketsize.
+ */
+static inline size_t usb_ep_align(struct usb_ep *ep, size_t len)
+{
+       return round_up(len, (size_t)le16_to_cpu(ep->desc->wMaxPacketSize));
+}
+
 /**
  * usb_ep_align_maybe - returns @len aligned to ep's maxpacketsize if gadget
- *     requires quirk_ep_out_aligned_size, otherwise reguens len.
+ *     requires quirk_ep_out_aligned_size, otherwise returns len.
  * @g: controller to check for quirk
  * @ep: the endpoint whose maxpacketsize is used to align @len
  * @len: buffer size's length to align to @ep's maxpacketsize
@@ -430,8 +445,7 @@ static inline struct usb_gadget *dev_to_usb_gadget(struct device *dev)
 static inline size_t
 usb_ep_align_maybe(struct usb_gadget *g, struct usb_ep *ep, size_t len)
 {
-       return !g->quirk_ep_out_aligned_size ? len :
-                       round_up(len, (size_t)ep->desc->wMaxPacketSize);
+       return g->quirk_ep_out_aligned_size ? usb_ep_align(ep, len) : len;
 }
 
 /**
@@ -462,6 +476,16 @@ static inline int gadget_is_zlp_supported(struct usb_gadget *g)
        return !g->quirk_zlp_not_supp;
 }
 
+/**
+ * gadget_avoids_skb_reserve - return true iff the hardware would like to avoid
+ *     skb_reserve to improve performance.
+ * @g: controller to check for quirk
+ */
+static inline int gadget_avoids_skb_reserve(struct usb_gadget *g)
+{
+       return g->quirk_avoids_skb_reserve;
+}
+
 /**
  * gadget_is_dualspeed - return true iff the hardware handles high speed
  * @g: controller that might support both high and full speeds
index 108dd799701449f8e7693f30596b3c3ab9dd030c..acc63697a0cc415357792e922396a9ef296bb01f 100644 (file)
@@ -21,6 +21,8 @@ enum functionfs_flags {
        FUNCTIONFS_HAS_MS_OS_DESC = 8,
        FUNCTIONFS_VIRTUAL_ADDR = 16,
        FUNCTIONFS_EVENTFD = 32,
+       FUNCTIONFS_ALL_CTRL_RECIP = 64,
+       FUNCTIONFS_CONFIG0_SETUP = 128,
 };
 
 /* Descriptor of an non-audio endpoint */
This page took 0.075625 seconds and 5 git commands to generate.