Merge tag 'usb-3.3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Linus Torvalds [Tue, 20 Mar 2012 18:26:30 +0000 (11:26 -0700)]
Pull USB merge for 3.4-rc1 from Greg KH:
 "Here's the big USB merge for the 3.4-rc1 merge window.

  Lots of gadget driver reworks here, driver updates, xhci changes, some
  new drivers added, usb-serial core reworking to fix some bugs, and
  other various minor things.

  There are some patches touching arch code, but they have all been
acked by the various arch maintainers."

* tag 'usb-3.3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (302 commits)
  net: qmi_wwan: add support for ZTE MF820D
  USB: option: add ZTE MF820D
  usb: gadget: f_fs: Remove lock is held before freeing checks
  USB: option: make interface blacklist work again
  usb/ub: deprecate & schedule for removal the "Low Performance USB Block" driver
  USB: ohci-pxa27x: add clk_prepare/clk_unprepare calls
  USB: use generic platform driver on ath79
  USB: EHCI: Add a generic platform device driver
  USB: OHCI: Add a generic platform device driver
  USB: ftdi_sio: new PID: LUMEL PD12
  USB: ftdi_sio: add support for FT-X series devices
  USB: serial: mos7840: Fixed MCS7820 device attach problem
  usb: Don't make USB_ARCH_HAS_{XHCI,OHCI,EHCI} depend on USB_SUPPORT.
  usb gadget: fix a section mismatch when compiling g_ffs with CONFIG_USB_FUNCTIONFS_ETH
  USB: ohci-nxp: Remove i2c_write(), use smbus
  USB: ohci-nxp: Support for LPC32xx
  USB: ohci-nxp: Rename symbols from pnx4008 to nxp
  USB: OHCI-HCD: Rename ohci-pnx4008 to ohci-nxp
  usb: gadget: Kconfig: fix typo for 'different'
  usb: dwc3: pci: fix another failure path in dwc3_pci_probe()
  ...

269 files changed:
Documentation/ABI/testing/sysfs-bus-usb
Documentation/feature-removal-schedule.txt
Documentation/i2c/instantiating-devices
arch/arm/mach-imx/mx31moboard-devboard.c
arch/arm/mach-imx/mx31moboard-marxbot.c
arch/arm/mach-pxa/pxa3xx-ulpi.c
arch/arm/mach-tegra/include/mach/usb_phy.h
arch/arm/mach-tegra/usb_phy.c
arch/arm/plat-mxc/include/mach/mxc_ehci.h
arch/arm/plat-mxc/include/mach/ulpi.h
arch/arm/plat-mxc/ulpi.c
arch/mips/ath79/dev-usb.c
drivers/block/Kconfig
drivers/block/ub.c
drivers/net/usb/Kconfig
drivers/net/usb/Makefile
drivers/net/usb/qmi_wwan.c [new file with mode: 0644]
drivers/power/isp1704_charger.c
drivers/power/pda_power.c
drivers/power/twl4030_charger.c
drivers/scsi/scsi_scan.c
drivers/scsi/sd.c
drivers/staging/keucr/transport.h
drivers/staging/quatech_usb2/quatech_usb2.c
drivers/staging/serqt_usb2/serqt_usb2.c
drivers/usb/Kconfig
drivers/usb/class/cdc-acm.c
drivers/usb/class/cdc-wdm.c
drivers/usb/core/driver.c
drivers/usb/core/hcd-pci.c
drivers/usb/core/hcd.c
drivers/usb/core/hub.c
drivers/usb/core/sysfs.c
drivers/usb/core/urb.c
drivers/usb/core/usb.c
drivers/usb/core/usb.h
drivers/usb/dwc3/Makefile
drivers/usb/dwc3/core.c
drivers/usb/dwc3/core.h
drivers/usb/dwc3/debugfs.c
drivers/usb/dwc3/dwc3-exynos.c [new file with mode: 0644]
drivers/usb/dwc3/dwc3-omap.c
drivers/usb/dwc3/dwc3-pci.c
drivers/usb/dwc3/ep0.c
drivers/usb/dwc3/gadget.c
drivers/usb/dwc3/gadget.h
drivers/usb/dwc3/host.c
drivers/usb/gadget/Kconfig
drivers/usb/gadget/amd5536udc.c
drivers/usb/gadget/at91_udc.c
drivers/usb/gadget/atmel_usba_udc.c
drivers/usb/gadget/audio.c
drivers/usb/gadget/ci13xxx_msm.c
drivers/usb/gadget/ci13xxx_udc.c
drivers/usb/gadget/ci13xxx_udc.h
drivers/usb/gadget/dummy_hcd.c
drivers/usb/gadget/epautoconf.c
drivers/usb/gadget/f_acm.c
drivers/usb/gadget/f_ecm.c
drivers/usb/gadget/f_fs.c
drivers/usb/gadget/f_mass_storage.c
drivers/usb/gadget/f_midi.c
drivers/usb/gadget/f_rndis.c
drivers/usb/gadget/f_serial.c
drivers/usb/gadget/f_subset.c
drivers/usb/gadget/f_uac1.c [moved from drivers/usb/gadget/f_audio.c with 97% similarity]
drivers/usb/gadget/f_uac2.c [new file with mode: 0644]
drivers/usb/gadget/file_storage.c
drivers/usb/gadget/fsl_qe_udc.c
drivers/usb/gadget/fsl_udc_core.c
drivers/usb/gadget/fsl_usb2_udc.h
drivers/usb/gadget/g_ffs.c
drivers/usb/gadget/goku_udc.c
drivers/usb/gadget/hid.c
drivers/usb/gadget/inode.c
drivers/usb/gadget/langwell_udc.c
drivers/usb/gadget/langwell_udc.h
drivers/usb/gadget/mass_storage.c
drivers/usb/gadget/multi.c
drivers/usb/gadget/mv_udc.h
drivers/usb/gadget/mv_udc_core.c
drivers/usb/gadget/net2272.c
drivers/usb/gadget/net2280.c
drivers/usb/gadget/omap_udc.c
drivers/usb/gadget/omap_udc.h
drivers/usb/gadget/pch_udc.c
drivers/usb/gadget/pxa25x_udc.c
drivers/usb/gadget/pxa25x_udc.h
drivers/usb/gadget/pxa27x_udc.c
drivers/usb/gadget/pxa27x_udc.h
drivers/usb/gadget/r8a66597-udc.c
drivers/usb/gadget/s3c-hsudc.c
drivers/usb/gadget/s3c2410_udc.c
drivers/usb/gadget/serial.c
drivers/usb/gadget/storage_common.c
drivers/usb/gadget/u_uac1.c [moved from drivers/usb/gadget/u_audio.c with 99% similarity]
drivers/usb/gadget/u_uac1.h [moved from drivers/usb/gadget/u_audio.h with 94% similarity]
drivers/usb/gadget/udc-core.c
drivers/usb/host/Kconfig
drivers/usb/host/Makefile
drivers/usb/host/ehci-ath79.c [deleted file]
drivers/usb/host/ehci-dbg.c
drivers/usb/host/ehci-fsl.c
drivers/usb/host/ehci-fsl.h
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-hub.c
drivers/usb/host/ehci-ls1x.c [new file with mode: 0644]
drivers/usb/host/ehci-msm.c
drivers/usb/host/ehci-mv.c
drivers/usb/host/ehci-mxc.c
drivers/usb/host/ehci-platform.c [new file with mode: 0644]
drivers/usb/host/ehci-pxa168.c [deleted file]
drivers/usb/host/ehci-s5p.c
drivers/usb/host/ehci-spear.c
drivers/usb/host/ehci-tegra.c
drivers/usb/host/ehci.h
drivers/usb/host/fsl-mph-dr-of.c
drivers/usb/host/imx21-dbg.c
drivers/usb/host/isp116x-hcd.c
drivers/usb/host/isp1362-hcd.c
drivers/usb/host/ohci-ath79.c [deleted file]
drivers/usb/host/ohci-exynos.c
drivers/usb/host/ohci-hcd.c
drivers/usb/host/ohci-nxp.c [moved from drivers/usb/host/ohci-pnx4008.c with 57% similarity]
drivers/usb/host/ohci-omap.c
drivers/usb/host/ohci-platform.c [new file with mode: 0644]
drivers/usb/host/ohci-pxa27x.c
drivers/usb/host/ohci.h
drivers/usb/host/r8a66597-hcd.c
drivers/usb/host/sl811-hcd.c
drivers/usb/host/uhci-hcd.c
drivers/usb/host/xhci-hub.c
drivers/usb/host/xhci-mem.c
drivers/usb/host/xhci-plat.c [new file with mode: 0644]
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.c
drivers/usb/host/xhci.h
drivers/usb/musb/am35x.c
drivers/usb/musb/blackfin.c
drivers/usb/musb/da8xx.c
drivers/usb/musb/davinci.c
drivers/usb/musb/musb_core.c
drivers/usb/musb/musb_core.h
drivers/usb/musb/musb_debugfs.c
drivers/usb/musb/musb_gadget.c
drivers/usb/musb/musb_virthub.c
drivers/usb/musb/omap2430.c
drivers/usb/musb/tusb6010.c
drivers/usb/musb/ux500.c
drivers/usb/otg/Kconfig
drivers/usb/otg/ab8500-usb.c
drivers/usb/otg/fsl_otg.c
drivers/usb/otg/fsl_otg.h
drivers/usb/otg/gpio_vbus.c
drivers/usb/otg/isp1301_omap.c
drivers/usb/otg/msm_otg.c
drivers/usb/otg/mv_otg.c
drivers/usb/otg/mv_otg.h
drivers/usb/otg/nop-usb-xceiv.c
drivers/usb/otg/otg.c
drivers/usb/otg/otg_fsm.c
drivers/usb/otg/otg_fsm.h
drivers/usb/otg/twl4030-usb.c
drivers/usb/otg/twl6030-usb.c
drivers/usb/otg/ulpi.c
drivers/usb/otg/ulpi_viewport.c
drivers/usb/renesas_usbhs/common.c
drivers/usb/renesas_usbhs/common.h
drivers/usb/renesas_usbhs/fifo.c
drivers/usb/renesas_usbhs/fifo.h
drivers/usb/renesas_usbhs/mod.c
drivers/usb/renesas_usbhs/mod_gadget.c
drivers/usb/serial/Kconfig
drivers/usb/serial/Makefile
drivers/usb/serial/aircable.c
drivers/usb/serial/ark3116.c
drivers/usb/serial/belkin_sa.c
drivers/usb/serial/ch341.c
drivers/usb/serial/cp210x.c
drivers/usb/serial/cyberjack.c
drivers/usb/serial/cypress_m8.c
drivers/usb/serial/digi_acceleport.c
drivers/usb/serial/empeg.c
drivers/usb/serial/f81232.c [new file with mode: 0644]
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio.h
drivers/usb/serial/ftdi_sio_ids.h
drivers/usb/serial/funsoft.c
drivers/usb/serial/garmin_gps.c
drivers/usb/serial/generic.c
drivers/usb/serial/hp4x.c
drivers/usb/serial/io_edgeport.c
drivers/usb/serial/io_tables.h
drivers/usb/serial/io_ti.c
drivers/usb/serial/ipaq.c
drivers/usb/serial/ipw.c
drivers/usb/serial/ir-usb.c
drivers/usb/serial/iuu_phoenix.c
drivers/usb/serial/keyspan.c
drivers/usb/serial/keyspan.h
drivers/usb/serial/keyspan_pda.c
drivers/usb/serial/kl5kusb105.c
drivers/usb/serial/kobil_sct.c
drivers/usb/serial/mct_u232.c
drivers/usb/serial/metro-usb.c [new file with mode: 0644]
drivers/usb/serial/mos7720.c
drivers/usb/serial/mos7840.c
drivers/usb/serial/moto_modem.c
drivers/usb/serial/navman.c
drivers/usb/serial/omninet.c
drivers/usb/serial/opticon.c
drivers/usb/serial/option.c
drivers/usb/serial/oti6858.c
drivers/usb/serial/pl2303.c
drivers/usb/serial/qcaux.c
drivers/usb/serial/qcserial.c
drivers/usb/serial/safe_serial.c
drivers/usb/serial/siemens_mpi.c
drivers/usb/serial/sierra.c
drivers/usb/serial/spcp8x5.c
drivers/usb/serial/ssu100.c
drivers/usb/serial/symbolserial.c
drivers/usb/serial/ti_usb_3410_5052.c
drivers/usb/serial/usb-serial.c
drivers/usb/serial/usb_debug.c
drivers/usb/serial/visor.c
drivers/usb/serial/vivopay-serial.c
drivers/usb/serial/whiteheat.c
drivers/usb/serial/zio.c
drivers/usb/storage/alauda.c
drivers/usb/storage/cypress_atacb.c
drivers/usb/storage/datafab.c
drivers/usb/storage/ene_ub6250.c
drivers/usb/storage/freecom.c
drivers/usb/storage/isd200.c
drivers/usb/storage/jumpshot.c
drivers/usb/storage/karma.c
drivers/usb/storage/onetouch.c
drivers/usb/storage/realtek_cr.c
drivers/usb/storage/scsiglue.c
drivers/usb/storage/sddr09.c
drivers/usb/storage/sddr55.c
drivers/usb/storage/shuttle_usbat.c
drivers/usb/storage/transport.c
drivers/usb/storage/transport.h
drivers/usb/storage/uas.c
drivers/usb/storage/usb.c
include/linux/device.h
include/linux/platform_data/dwc3-exynos.h [new file with mode: 0644]
include/linux/usb.h
include/linux/usb/audio-v2.h
include/linux/usb/cdc-wdm.h [new file with mode: 0644]
include/linux/usb/ch11.h
include/linux/usb/ch9.h
include/linux/usb/ehci_pdriver.h [new file with mode: 0644]
include/linux/usb/gadget.h
include/linux/usb/hcd.h
include/linux/usb/intel_mid_otg.h
include/linux/usb/msm_hsusb.h
include/linux/usb/ohci_pdriver.h [new file with mode: 0644]
include/linux/usb/otg.h
include/linux/usb/renesas_usbhs.h
include/linux/usb/serial.h
include/linux/usb/storage.h
include/linux/usb/uas.h [new file with mode: 0644]
include/linux/usb/ulpi.h
include/scsi/scsi_device.h
tools/usb/ffs-test.c
tools/usb/testusb.c

index b4f5487..7c22a53 100644 (file)
@@ -182,3 +182,14 @@ Description:
                USB2 hardware LPM is enabled for the device. Developer can
                write y/Y/1 or n/N/0 to the file to enable/disable the
                feature.
+
+What:          /sys/bus/usb/devices/.../removable
+Date:          February 2012
+Contact:       Matthew Garrett <mjg@redhat.com>
+Description:
+               Some information about whether a given USB device is
+               physically fixed to the platform can be inferred from a
+               combination of hub decriptor bits and platform-specific data
+               such as ACPI. This file will read either "removable" or
+               "fixed" if the information is available, and "unknown"
+               otherwise.
\ No newline at end of file
index a0ffac0..d5dc80f 100644 (file)
@@ -524,3 +524,14 @@ Files:     arch/arm/mach-at91/at91cap9.c
 Why:   The code is not actively maintained and platforms are now hard to find.
 Who:   Nicolas Ferre <nicolas.ferre@atmel.com>
        Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+
+----------------------------
+
+What:  Low Performance USB Block driver ("CONFIG_BLK_DEV_UB")
+When:  3.6
+Why:   This driver provides support for USB storage devices like "USB
+       sticks". As of now, it is deactivated in Debian, Fedora and
+        Ubuntu. All current users can switch over to usb-storage
+        (CONFIG_USB_STORAGE) which only drawback is the additional SCSI
+        stack.
+Who:   Sebastian Andrzej Siewior <sebastian@breakpoint.cc>
index 9edb75d..abf6361 100644 (file)
@@ -87,11 +87,11 @@ it may have different addresses from one board to the next (manufacturer
 changing its design without notice). In this case, you can call
 i2c_new_probed_device() instead of i2c_new_device().
 
-Example (from the pnx4008 OHCI driver):
+Example (from the nxp OHCI driver):
 
 static const unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
 
-static int __devinit usb_hcd_pnx4008_probe(struct platform_device *pdev)
+static int __devinit usb_hcd_nxp_probe(struct platform_device *pdev)
 {
        (...)
        struct i2c_adapter *i2c_adap;
@@ -100,7 +100,7 @@ static int __devinit usb_hcd_pnx4008_probe(struct platform_device *pdev)
        (...)
        i2c_adap = i2c_get_adapter(2);
        memset(&i2c_info, 0, sizeof(struct i2c_board_info));
-       strlcpy(i2c_info.type, "isp1301_pnx", I2C_NAME_SIZE);
+       strlcpy(i2c_info.type, "isp1301_nxp", I2C_NAME_SIZE);
        isp1301_i2c_client = i2c_new_probed_device(i2c_adap, &i2c_info,
                                                   normal_i2c, NULL);
        i2c_put_adapter(i2c_adap);
index 0aa2536..cc285e5 100644 (file)
@@ -158,7 +158,7 @@ static int devboard_usbh1_hw_init(struct platform_device *pdev)
 #define USBH1_VBUSEN_B IOMUX_TO_GPIO(MX31_PIN_NFRE_B)
 #define USBH1_MODE     IOMUX_TO_GPIO(MX31_PIN_NFALE)
 
-static int devboard_isp1105_init(struct otg_transceiver *otg)
+static int devboard_isp1105_init(struct usb_phy *otg)
 {
        int ret = gpio_request(USBH1_MODE, "usbh1-mode");
        if (ret)
@@ -177,7 +177,7 @@ static int devboard_isp1105_init(struct otg_transceiver *otg)
 }
 
 
-static int devboard_isp1105_set_vbus(struct otg_transceiver *otg, bool on)
+static int devboard_isp1105_set_vbus(struct usb_otg *otg, bool on)
 {
        if (on)
                gpio_set_value(USBH1_VBUSEN_B, 0);
@@ -194,18 +194,24 @@ static struct mxc_usbh_platform_data usbh1_pdata __initdata = {
 
 static int __init devboard_usbh1_init(void)
 {
-       struct otg_transceiver *otg;
+       struct usb_phy *phy;
        struct platform_device *pdev;
 
-       otg = kzalloc(sizeof(*otg), GFP_KERNEL);
-       if (!otg)
+       phy = kzalloc(sizeof(*phy), GFP_KERNEL);
+       if (!phy)
                return -ENOMEM;
 
-       otg->label      = "ISP1105";
-       otg->init       = devboard_isp1105_init;
-       otg->set_vbus   = devboard_isp1105_set_vbus;
+       phy->otg = kzalloc(sizeof(struct usb_otg), GFP_KERNEL);
+       if (!phy->otg) {
+               kfree(phy);
+               return -ENOMEM;
+       }
+
+       phy->label      = "ISP1105";
+       phy->init       = devboard_isp1105_init;
+       phy->otg->set_vbus      = devboard_isp1105_set_vbus;
 
-       usbh1_pdata.otg = otg;
+       usbh1_pdata.otg = phy;
 
        pdev = imx31_add_mxc_ehci_hs(1, &usbh1_pdata);
        if (IS_ERR(pdev))
index bb639cb..135c90e 100644 (file)
@@ -272,7 +272,7 @@ static int marxbot_usbh1_hw_init(struct platform_device *pdev)
 #define USBH1_VBUSEN_B IOMUX_TO_GPIO(MX31_PIN_NFRE_B)
 #define USBH1_MODE     IOMUX_TO_GPIO(MX31_PIN_NFALE)
 
-static int marxbot_isp1105_init(struct otg_transceiver *otg)
+static int marxbot_isp1105_init(struct usb_phy *otg)
 {
        int ret = gpio_request(USBH1_MODE, "usbh1-mode");
        if (ret)
@@ -291,7 +291,7 @@ static int marxbot_isp1105_init(struct otg_transceiver *otg)
 }
 
 
-static int marxbot_isp1105_set_vbus(struct otg_transceiver *otg, bool on)
+static int marxbot_isp1105_set_vbus(struct usb_otg *otg, bool on)
 {
        if (on)
                gpio_set_value(USBH1_VBUSEN_B, 0);
@@ -308,18 +308,24 @@ static struct mxc_usbh_platform_data usbh1_pdata __initdata = {
 
 static int __init marxbot_usbh1_init(void)
 {
-       struct otg_transceiver *otg;
+       struct usb_phy *phy;
        struct platform_device *pdev;
 
-       otg = kzalloc(sizeof(*otg), GFP_KERNEL);
-       if (!otg)
+       phy = kzalloc(sizeof(*phy), GFP_KERNEL);
+       if (!phy)
                return -ENOMEM;
 
-       otg->label      = "ISP1105";
-       otg->init       = marxbot_isp1105_init;
-       otg->set_vbus   = marxbot_isp1105_set_vbus;
+       phy->otg = kzalloc(sizeof(struct usb_otg), GFP_KERNEL);
+       if (!phy->otg) {
+               kfree(phy);
+               return -ENOMEM;
+       }
+
+       phy->label      = "ISP1105";
+       phy->init       = marxbot_isp1105_init;
+       phy->otg->set_vbus      = marxbot_isp1105_set_vbus;
 
-       usbh1_pdata.otg = otg;
+       usbh1_pdata.otg = phy;
 
        pdev = imx31_add_mxc_ehci_hs(1, &usbh1_pdata);
        if (IS_ERR(pdev))
index e28dfb8..5ead6d4 100644 (file)
@@ -33,7 +33,7 @@ struct pxa3xx_u2d_ulpi {
        struct clk              *clk;
        void __iomem            *mmio_base;
 
-       struct otg_transceiver  *otg;
+       struct usb_phy          *otg;
        unsigned int            ulpi_mode;
 };
 
@@ -79,7 +79,7 @@ static int pxa310_ulpi_poll(void)
        return -ETIMEDOUT;
 }
 
-static int pxa310_ulpi_read(struct otg_transceiver *otg, u32 reg)
+static int pxa310_ulpi_read(struct usb_phy *otg, u32 reg)
 {
        int err;
 
@@ -98,7 +98,7 @@ static int pxa310_ulpi_read(struct otg_transceiver *otg, u32 reg)
        return u2d_readl(U2DOTGUCR) & U2DOTGUCR_RDATA;
 }
 
-static int pxa310_ulpi_write(struct otg_transceiver *otg, u32 val, u32 reg)
+static int pxa310_ulpi_write(struct usb_phy *otg, u32 val, u32 reg)
 {
        if (pxa310_ulpi_get_phymode() != SYNCH) {
                pr_warning("%s: PHY is not in SYNCH mode!\n", __func__);
@@ -111,7 +111,7 @@ static int pxa310_ulpi_write(struct otg_transceiver *otg, u32 val, u32 reg)
        return pxa310_ulpi_poll();
 }
 
-struct otg_io_access_ops pxa310_ulpi_access_ops = {
+struct usb_phy_io_ops pxa310_ulpi_access_ops = {
        .read   = pxa310_ulpi_read,
        .write  = pxa310_ulpi_write,
 };
@@ -139,19 +139,19 @@ static int pxa310_start_otg_host_transcvr(struct usb_bus *host)
 
        pxa310_otg_transceiver_rtsm();
 
-       err = otg_init(u2d->otg);
+       err = usb_phy_init(u2d->otg);
        if (err) {
                pr_err("OTG transceiver init failed");
                return err;
        }
 
-       err = otg_set_vbus(u2d->otg, 1);
+       err = otg_set_vbus(u2d->otg->otg, 1);
        if (err) {
                pr_err("OTG transceiver VBUS set failed");
                return err;
        }
 
-       err = otg_set_host(u2d->otg, host);
+       err = otg_set_host(u2d->otg->otg, host);
        if (err)
                pr_err("OTG transceiver Host mode set failed");
 
@@ -189,9 +189,9 @@ static void pxa310_stop_otg_hc(void)
 {
        pxa310_otg_transceiver_rtsm();
 
-       otg_set_host(u2d->otg, NULL);
-       otg_set_vbus(u2d->otg, 0);
-       otg_shutdown(u2d->otg);
+       otg_set_host(u2d->otg->otg, NULL);
+       otg_set_vbus(u2d->otg->otg, 0);
+       usb_phy_shutdown(u2d->otg);
 }
 
 static void pxa310_u2d_setup_otg_hc(void)
index d4b8f9e..de1a0f6 100644 (file)
@@ -58,7 +58,7 @@ struct tegra_usb_phy {
        struct clk *pad_clk;
        enum tegra_usb_phy_mode mode;
        void *config;
-       struct otg_transceiver *ulpi;
+       struct usb_phy *ulpi;
 };
 
 struct tegra_usb_phy *tegra_usb_phy_open(int instance, void __iomem *regs,
index 37576a7..ad321f9 100644 (file)
@@ -608,13 +608,13 @@ static int ulpi_phy_power_on(struct tegra_usb_phy *phy)
        writel(val, base + ULPI_TIMING_CTRL_1);
 
        /* Fix VbusInvalid due to floating VBUS */
-       ret = otg_io_write(phy->ulpi, 0x40, 0x08);
+       ret = usb_phy_io_write(phy->ulpi, 0x40, 0x08);
        if (ret) {
                pr_err("%s: ulpi write failed\n", __func__);
                return ret;
        }
 
-       ret = otg_io_write(phy->ulpi, 0x80, 0x0B);
+       ret = usb_phy_io_write(phy->ulpi, 0x80, 0x0B);
        if (ret) {
                pr_err("%s: ulpi write failed\n", __func__);
                return ret;
index 2c159dc..9ffd1bb 100644 (file)
@@ -44,7 +44,7 @@ struct mxc_usbh_platform_data {
        int (*exit)(struct platform_device *pdev);
 
        unsigned int             portsc;
-       struct otg_transceiver  *otg;
+       struct usb_phy          *otg;
 };
 
 int mx51_initialize_usb_hw(int port, unsigned int flags);
index f9161c9..42bdaca 100644 (file)
@@ -2,15 +2,15 @@
 #define __MACH_ULPI_H
 
 #ifdef CONFIG_USB_ULPI
-struct otg_transceiver *imx_otg_ulpi_create(unsigned int flags);
+struct usb_phy *imx_otg_ulpi_create(unsigned int flags);
 #else
-static inline struct otg_transceiver *imx_otg_ulpi_create(unsigned int flags)
+static inline struct usb_phy *imx_otg_ulpi_create(unsigned int flags)
 {
        return NULL;
 }
 #endif
 
-extern struct otg_io_access_ops mxc_ulpi_access_ops;
+extern struct usb_phy_io_ops mxc_ulpi_access_ops;
 
 #endif /* __MACH_ULPI_H */
 
index 477e45b..d296342 100644 (file)
@@ -58,7 +58,7 @@ static int ulpi_poll(void __iomem *view, u32 bit)
        return -ETIMEDOUT;
 }
 
-static int ulpi_read(struct otg_transceiver *otg, u32 reg)
+static int ulpi_read(struct usb_phy *otg, u32 reg)
 {
        int ret;
        void __iomem *view = otg->io_priv;
@@ -84,7 +84,7 @@ static int ulpi_read(struct otg_transceiver *otg, u32 reg)
        return (__raw_readl(view) >> ULPIVW_RDATA_SHIFT) & ULPIVW_RDATA_MASK;
 }
 
-static int ulpi_write(struct otg_transceiver *otg, u32 val, u32 reg)
+static int ulpi_write(struct usb_phy *otg, u32 val, u32 reg)
 {
        int ret;
        void __iomem *view = otg->io_priv;
@@ -106,13 +106,13 @@ static int ulpi_write(struct otg_transceiver *otg, u32 val, u32 reg)
        return ulpi_poll(view, ULPIVW_RUN);
 }
 
-struct otg_io_access_ops mxc_ulpi_access_ops = {
+struct usb_phy_io_ops mxc_ulpi_access_ops = {
        .read   = ulpi_read,
        .write  = ulpi_write,
 };
 EXPORT_SYMBOL_GPL(mxc_ulpi_access_ops);
 
-struct otg_transceiver *imx_otg_ulpi_create(unsigned int flags)
+struct usb_phy *imx_otg_ulpi_create(unsigned int flags)
 {
        return otg_ulpi_create(&mxc_ulpi_access_ops, flags);
 }
index 002d6d2..36e9570 100644 (file)
@@ -17,6 +17,8 @@
 #include <linux/irq.h>
 #include <linux/dma-mapping.h>
 #include <linux/platform_device.h>
+#include <linux/usb/ehci_pdriver.h>
+#include <linux/usb/ohci_pdriver.h>
 
 #include <asm/mach-ath79/ath79.h>
 #include <asm/mach-ath79/ar71xx_regs.h>
@@ -36,14 +38,19 @@ static struct resource ath79_ohci_resources[] = {
 };
 
 static u64 ath79_ohci_dmamask = DMA_BIT_MASK(32);
+
+static struct usb_ohci_pdata ath79_ohci_pdata = {
+};
+
 static struct platform_device ath79_ohci_device = {
-       .name           = "ath79-ohci",
+       .name           = "ohci-platform",
        .id             = -1,
        .resource       = ath79_ohci_resources,
        .num_resources  = ARRAY_SIZE(ath79_ohci_resources),
        .dev = {
                .dma_mask               = &ath79_ohci_dmamask,
                .coherent_dma_mask      = DMA_BIT_MASK(32),
+               .platform_data          = &ath79_ohci_pdata,
        },
 };
 
@@ -60,8 +67,20 @@ static struct resource ath79_ehci_resources[] = {
 };
 
 static u64 ath79_ehci_dmamask = DMA_BIT_MASK(32);
+
+static struct usb_ehci_pdata ath79_ehci_pdata_v1 = {
+       .has_synopsys_hc_bug    = 1,
+       .port_power_off         = 1,
+};
+
+static struct usb_ehci_pdata ath79_ehci_pdata_v2 = {
+       .caps_offset            = 0x100,
+       .has_tt                 = 1,
+       .port_power_off         = 1,
+};
+
 static struct platform_device ath79_ehci_device = {
-       .name           = "ath79-ehci",
+       .name           = "ehci-platform",
        .id             = -1,
        .resource       = ath79_ehci_resources,
        .num_resources  = ARRAY_SIZE(ath79_ehci_resources),
@@ -101,7 +120,7 @@ static void __init ath79_usb_setup(void)
 
        ath79_ehci_resources[0].start = AR71XX_EHCI_BASE;
        ath79_ehci_resources[0].end = AR71XX_EHCI_BASE + AR71XX_EHCI_SIZE - 1;
-       ath79_ehci_device.name = "ar71xx-ehci";
+       ath79_ehci_device.dev.platform_data = &ath79_ehci_pdata_v1;
        platform_device_register(&ath79_ehci_device);
 }
 
@@ -142,7 +161,7 @@ static void __init ar724x_usb_setup(void)
 
        ath79_ehci_resources[0].start = AR724X_EHCI_BASE;
        ath79_ehci_resources[0].end = AR724X_EHCI_BASE + AR724X_EHCI_SIZE - 1;
-       ath79_ehci_device.name = "ar724x-ehci";
+       ath79_ehci_device.dev.platform_data = &ath79_ehci_pdata_v2;
        platform_device_register(&ath79_ehci_device);
 }
 
@@ -159,7 +178,7 @@ static void __init ar913x_usb_setup(void)
 
        ath79_ehci_resources[0].start = AR913X_EHCI_BASE;
        ath79_ehci_resources[0].end = AR913X_EHCI_BASE + AR913X_EHCI_SIZE - 1;
-       ath79_ehci_device.name = "ar913x-ehci";
+       ath79_ehci_device.dev.platform_data = &ath79_ehci_pdata_v2;
        platform_device_register(&ath79_ehci_device);
 }
 
@@ -176,7 +195,7 @@ static void __init ar933x_usb_setup(void)
 
        ath79_ehci_resources[0].start = AR933X_EHCI_BASE;
        ath79_ehci_resources[0].end = AR933X_EHCI_BASE + AR933X_EHCI_SIZE - 1;
-       ath79_ehci_device.name = "ar933x-ehci";
+       ath79_ehci_device.dev.platform_data = &ath79_ehci_pdata_v2;
        platform_device_register(&ath79_ehci_device);
 }
 
index 4e4c8a4..a796407 100644 (file)
@@ -354,7 +354,7 @@ config BLK_DEV_SX8
          Use devices /dev/sx8/$N and /dev/sx8/$Np$M.
 
 config BLK_DEV_UB
-       tristate "Low Performance USB Block driver"
+       tristate "Low Performance USB Block driver (deprecated)"
        depends on USB
        help
          This driver supports certain USB attached storage devices
index 7333b9e..fcec022 100644 (file)
 
 /*
  */
-
-/* command block wrapper */
-struct bulk_cb_wrap {
-       __le32  Signature;              /* contains 'USBC' */
-       u32     Tag;                    /* unique per command id */
-       __le32  DataTransferLength;     /* size of data */
-       u8      Flags;                  /* direction in bit 0 */
-       u8      Lun;                    /* LUN */
-       u8      Length;                 /* of of the CDB */
-       u8      CDB[UB_MAX_CDB_SIZE];   /* max command */
-};
-
-#define US_BULK_CB_WRAP_LEN    31
-#define US_BULK_CB_SIGN                0x43425355      /*spells out USBC */
-#define US_BULK_FLAG_IN                1
-#define US_BULK_FLAG_OUT       0
-
-/* command status wrapper */
-struct bulk_cs_wrap {
-       __le32  Signature;              /* should = 'USBS' */
-       u32     Tag;                    /* same as original command */
-       __le32  Residue;                /* amount not transferred */
-       u8      Status;                 /* see below */
-};
-
-#define US_BULK_CS_WRAP_LEN    13
-#define US_BULK_CS_SIGN                0x53425355      /* spells out 'USBS' */
-#define US_BULK_STAT_OK                0
-#define US_BULK_STAT_FAIL      1
-#define US_BULK_STAT_PHASE     2
-
-/* bulk-only class specific requests */
-#define US_BULK_RESET_REQUEST  0xff
-#define US_BULK_GET_MAX_LUN    0xfe
-
-/*
- */
 struct ub_dev;
 
 #define UB_MAX_REQ_SG  9       /* cdrecord requires 32KB and maybe a header */
@@ -2477,6 +2440,8 @@ static int __init ub_init(void)
        int rc;
        int i;
 
+       pr_info("'Low Performance USB Block' driver is deprecated. "
+                       "Please switch to usb-storage\n");
        for (i = 0; i < UB_QLOCK_NUM; i++)
                spin_lock_init(&ub_qlockv[i]);
 
index 2335761..4bad899 100644 (file)
@@ -398,6 +398,27 @@ config USB_NET_KALMIA
          To compile this driver as a module, choose M here: the
          module will be called kalmia.
 
+config USB_NET_QMI_WWAN
+       tristate "QMI WWAN driver for Qualcomm MSM based 3G and LTE modems"
+       depends on USB_USBNET
+       help
+         Support WWAN LTE/3G devices based on Qualcomm Mobile Data Modem
+         (MDM) chipsets.  Examples of such devices are
+           * Huawei E392/E398
+
+         This driver will only drive the ethernet part of the chips.
+         The devices require additional configuration to be usable.
+         Multiple management interfaces with linux drivers are
+         available:
+
+           * option: AT commands on /dev/ttyUSBx
+           * cdc-wdm: Qualcomm MSM Interface (QMI) protocol on /dev/cdc-wdmx
+
+         A modem manager with support for QMI is recommended.
+
+         To compile this driver as a module, choose M here: the
+         module will be called qmi_wwan.
+
 config USB_HSO
        tristate "Option USB High Speed Mobile Devices"
        depends on USB && RFKILL
@@ -461,4 +482,5 @@ config USB_VL600
 
          http://ubuntuforums.org/showpost.php?p=10589647&postcount=17
 
+
 endmenu
index c203fa2..a2e2d72 100644 (file)
@@ -29,4 +29,5 @@ obj-$(CONFIG_USB_SIERRA_NET)  += sierra_net.o
 obj-$(CONFIG_USB_NET_CX82310_ETH)      += cx82310_eth.o
 obj-$(CONFIG_USB_NET_CDC_NCM)  += cdc_ncm.o
 obj-$(CONFIG_USB_VL600)                += lg-vl600.o
+obj-$(CONFIG_USB_NET_QMI_WWAN) += qmi_wwan.o
 
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
new file mode 100644 (file)
index 0000000..aac68f5
--- /dev/null
@@ -0,0 +1,478 @@
+/*
+ * Copyright (c) 2012  Bjørn Mork <bjorn@mork.no>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/usb.h>
+#include <linux/usb/cdc.h>
+#include <linux/usb/usbnet.h>
+#include <linux/usb/cdc-wdm.h>
+
+/* The name of the CDC Device Management driver */
+#define DM_DRIVER "cdc_wdm"
+
+/*
+ * This driver supports wwan (3G/LTE/?) devices using a vendor
+ * specific management protocol called Qualcomm MSM Interface (QMI) -
+ * in addition to the more common AT commands over serial interface
+ * management
+ *
+ * QMI is wrapped in CDC, using CDC encapsulated commands on the
+ * control ("master") interface of a two-interface CDC Union
+ * resembling standard CDC ECM.  The devices do not use the control
+ * interface for any other CDC messages.  Most likely because the
+ * management protocol is used in place of the standard CDC
+ * notifications NOTIFY_NETWORK_CONNECTION and NOTIFY_SPEED_CHANGE
+ *
+ * Handling a protocol like QMI is out of the scope for any driver.
+ * It can be exported as a character device using the cdc-wdm driver,
+ * which will enable userspace applications ("modem managers") to
+ * handle it.  This may be required to use the network interface
+ * provided by the driver.
+ *
+ * These devices may alternatively/additionally be configured using AT
+ * commands on any of the serial interfaces driven by the option driver
+ *
+ * This driver binds only to the data ("slave") interface to enable
+ * the cdc-wdm driver to bind to the control interface.  It still
+ * parses the CDC functional descriptors on the control interface to
+ *  a) verify that this is indeed a handled interface (CDC Union
+ *     header lists it as slave)
+ *  b) get MAC address and other ethernet config from the CDC Ethernet
+ *     header
+ *  c) enable user bind requests against the control interface, which
+ *     is the common way to bind to CDC Ethernet Control Model type
+ *     interfaces
+ *  d) provide a hint to the user about which interface is the
+ *     corresponding management interface
+ */
+
+static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+       int status = -1;
+       struct usb_interface *control = NULL;
+       u8 *buf = intf->cur_altsetting->extra;
+       int len = intf->cur_altsetting->extralen;
+       struct usb_interface_descriptor *desc = &intf->cur_altsetting->desc;
+       struct usb_cdc_union_desc *cdc_union = NULL;
+       struct usb_cdc_ether_desc *cdc_ether = NULL;
+       u32 required = 1 << USB_CDC_HEADER_TYPE | 1 << USB_CDC_UNION_TYPE;
+       u32 found = 0;
+       atomic_t *pmcount = (void *)&dev->data[1];
+
+       atomic_set(pmcount, 0);
+
+       /*
+        * assume a data interface has no additional descriptors and
+        * that the control and data interface are numbered
+        * consecutively - this holds for the Huawei device at least
+        */
+       if (len == 0 && desc->bInterfaceNumber > 0) {
+               control = usb_ifnum_to_if(dev->udev, desc->bInterfaceNumber - 1);
+               if (!control)
+                       goto err;
+
+               buf = control->cur_altsetting->extra;
+               len = control->cur_altsetting->extralen;
+               dev_dbg(&intf->dev, "guessing \"control\" => %s, \"data\" => this\n",
+                       dev_name(&control->dev));
+       }
+
+       while (len > 3) {
+               struct usb_descriptor_header *h = (void *)buf;
+
+               /* ignore any misplaced descriptors */
+               if (h->bDescriptorType != USB_DT_CS_INTERFACE)
+                       goto next_desc;
+
+               /* buf[2] is CDC descriptor subtype */
+               switch (buf[2]) {
+               case USB_CDC_HEADER_TYPE:
+                       if (found & 1 << USB_CDC_HEADER_TYPE) {
+                               dev_dbg(&intf->dev, "extra CDC header\n");
+                               goto err;
+                       }
+                       if (h->bLength != sizeof(struct usb_cdc_header_desc)) {
+                               dev_dbg(&intf->dev, "CDC header len %u\n", h->bLength);
+                               goto err;
+                       }
+                       break;
+               case USB_CDC_UNION_TYPE:
+                       if (found & 1 << USB_CDC_UNION_TYPE) {
+                               dev_dbg(&intf->dev, "extra CDC union\n");
+                               goto err;
+                       }
+                       if (h->bLength != sizeof(struct usb_cdc_union_desc)) {
+                               dev_dbg(&intf->dev, "CDC union len %u\n", h->bLength);
+                               goto err;
+                       }
+                       cdc_union = (struct usb_cdc_union_desc *)buf;
+                       break;
+               case USB_CDC_ETHERNET_TYPE:
+                       if (found & 1 << USB_CDC_ETHERNET_TYPE) {
+                               dev_dbg(&intf->dev, "extra CDC ether\n");
+                               goto err;
+                       }
+                       if (h->bLength != sizeof(struct usb_cdc_ether_desc)) {
+                               dev_dbg(&intf->dev, "CDC ether len %u\n",  h->bLength);
+                               goto err;
+                       }
+                       cdc_ether = (struct usb_cdc_ether_desc *)buf;
+                       break;
+               }
+
+               /*
+                * Remember which CDC functional descriptors we've seen.  Works
+                * for all types we care about, of which USB_CDC_ETHERNET_TYPE
+                * (0x0f) is the highest numbered
+                */
+               if (buf[2] < 32)
+                       found |= 1 << buf[2];
+
+next_desc:
+               len -= h->bLength;
+               buf += h->bLength;
+       }
+
+       /* did we find all the required ones? */
+       if ((found & required) != required) {
+               dev_err(&intf->dev, "CDC functional descriptors missing\n");
+               goto err;
+       }
+
+       /* give the user a helpful hint if trying to bind to the wrong interface */
+       if (cdc_union && desc->bInterfaceNumber == cdc_union->bMasterInterface0) {
+               dev_err(&intf->dev, "leaving \"control\" interface for " DM_DRIVER " - try binding to %s instead!\n",
+                       dev_name(&usb_ifnum_to_if(dev->udev, cdc_union->bSlaveInterface0)->dev));
+               goto err;
+       }
+
+       /* errors aren't fatal - we can live with the dynamic address */
+       if (cdc_ether) {
+               dev->hard_mtu = le16_to_cpu(cdc_ether->wMaxSegmentSize);
+               usbnet_get_ethernet_addr(dev, cdc_ether->iMACAddress);
+       }
+
+       /* success! point the user to the management interface */
+       if (control)
+               dev_info(&intf->dev, "Use \"" DM_DRIVER "\" for QMI interface %s\n",
+                       dev_name(&control->dev));
+
+       /* XXX: add a sysfs symlink somewhere to help management applications find it? */
+
+       /* collect bulk endpoints now that we know intf == "data" interface */
+       status = usbnet_get_endpoints(dev, intf);
+
+err:
+       return status;
+}
+
+/* using a counter to merge subdriver requests with our own into a combined state */
+static int qmi_wwan_manage_power(struct usbnet *dev, int on)
+{
+       atomic_t *pmcount = (void *)&dev->data[1];
+       int rv = 0;
+
+       dev_dbg(&dev->intf->dev, "%s() pmcount=%d, on=%d\n", __func__, atomic_read(pmcount), on);
+
+       if ((on && atomic_add_return(1, pmcount) == 1) || (!on && atomic_dec_and_test(pmcount))) {
+               /* need autopm_get/put here to ensure the usbcore sees the new value */
+               rv = usb_autopm_get_interface(dev->intf);
+               if (rv < 0)
+                       goto err;
+               dev->intf->needs_remote_wakeup = on;
+               usb_autopm_put_interface(dev->intf);
+       }
+err:
+       return rv;
+}
+
+static int qmi_wwan_cdc_wdm_manage_power(struct usb_interface *intf, int on)
+{
+       struct usbnet *dev = usb_get_intfdata(intf);
+       return qmi_wwan_manage_power(dev, on);
+}
+
+/* Some devices combine the "control" and "data" functions into a
+ * single interface with all three endpoints: interrupt + bulk in and
+ * out
+ *
+ * Setting up cdc-wdm as a subdriver owning the interrupt endpoint
+ * will let it provide userspace access to the encapsulated QMI
+ * protocol without interfering with the usbnet operations.
+  */
+static int qmi_wwan_bind_shared(struct usbnet *dev, struct usb_interface *intf)
+{
+       int rv;
+       struct usb_driver *subdriver = NULL;
+       atomic_t *pmcount = (void *)&dev->data[1];
+
+       /* ZTE makes devices where the interface descriptors and endpoint
+        * configurations of two or more interfaces are identical, even
+        * though the functions are completely different.  If set, then
+        * driver_info->data is a bitmap of acceptable interface numbers
+        * allowing us to bind to one such interface without binding to
+        * all of them
+        */
+       if (dev->driver_info->data &&
+           !test_bit(intf->cur_altsetting->desc.bInterfaceNumber, &dev->driver_info->data)) {
+               dev_info(&intf->dev, "not on our whitelist - ignored");
+               rv = -ENODEV;
+               goto err;
+       }
+
+       atomic_set(pmcount, 0);
+
+       /* collect all three endpoints */
+       rv = usbnet_get_endpoints(dev, intf);
+       if (rv < 0)
+               goto err;
+
+       /* require interrupt endpoint for subdriver */
+       if (!dev->status) {
+               rv = -EINVAL;
+               goto err;
+       }
+
+       subdriver = usb_cdc_wdm_register(intf, &dev->status->desc, 512, &qmi_wwan_cdc_wdm_manage_power);
+       if (IS_ERR(subdriver)) {
+               rv = PTR_ERR(subdriver);
+               goto err;
+       }
+
+       /* can't let usbnet use the interrupt endpoint */
+       dev->status = NULL;
+
+       /* save subdriver struct for suspend/resume wrappers */
+       dev->data[0] = (unsigned long)subdriver;
+
+err:
+       return rv;
+}
+
+/* Gobi devices uses identical class/protocol codes for all interfaces regardless
+ * of function. Some of these are CDC ACM like and have the exact same endpoints
+ * we are looking for. This leaves two possible strategies for identifying the
+ * correct interface:
+ *   a) hardcoding interface number, or
+ *   b) use the fact that the wwan interface is the only one lacking additional
+ *      (CDC functional) descriptors
+ *
+ * Let's see if we can get away with the generic b) solution.
+ */
+static int qmi_wwan_bind_gobi(struct usbnet *dev, struct usb_interface *intf)
+{
+       int rv = -EINVAL;
+
+       /* ignore any interface with additional descriptors */
+       if (intf->cur_altsetting->extralen)
+               goto err;
+
+       rv = qmi_wwan_bind_shared(dev, intf);
+err:
+       return rv;
+}
+
+static void qmi_wwan_unbind_shared(struct usbnet *dev, struct usb_interface *intf)
+{
+       struct usb_driver *subdriver = (void *)dev->data[0];
+
+       if (subdriver && subdriver->disconnect)
+               subdriver->disconnect(intf);
+
+       dev->data[0] = (unsigned long)NULL;
+}
+
+/* suspend/resume wrappers calling both usbnet and the cdc-wdm
+ * subdriver if present.
+ *
+ * NOTE: cdc-wdm also supports pre/post_reset, but we cannot provide
+ * wrappers for those without adding usbnet reset support first.
+ */
+static int qmi_wwan_suspend(struct usb_interface *intf, pm_message_t message)
+{
+       struct usbnet *dev = usb_get_intfdata(intf);
+       struct usb_driver *subdriver = (void *)dev->data[0];
+       int ret;
+
+       ret = usbnet_suspend(intf, message);
+       if (ret < 0)
+               goto err;
+
+       if (subdriver && subdriver->suspend)
+               ret = subdriver->suspend(intf, message);
+       if (ret < 0)
+               usbnet_resume(intf);
+err:
+       return ret;
+}
+
+static int qmi_wwan_resume(struct usb_interface *intf)
+{
+       struct usbnet *dev = usb_get_intfdata(intf);
+       struct usb_driver *subdriver = (void *)dev->data[0];
+       int ret = 0;
+
+       if (subdriver && subdriver->resume)
+               ret = subdriver->resume(intf);
+       if (ret < 0)
+               goto err;
+       ret = usbnet_resume(intf);
+       if (ret < 0 && subdriver && subdriver->resume && subdriver->suspend)
+               subdriver->suspend(intf, PMSG_SUSPEND);
+err:
+       return ret;
+}
+
+
+static const struct driver_info        qmi_wwan_info = {
+       .description    = "QMI speaking wwan device",
+       .flags          = FLAG_WWAN,
+       .bind           = qmi_wwan_bind,
+       .manage_power   = qmi_wwan_manage_power,
+};
+
+static const struct driver_info        qmi_wwan_shared = {
+       .description    = "QMI speaking wwan device with combined interface",
+       .flags          = FLAG_WWAN,
+       .bind           = qmi_wwan_bind_shared,
+       .unbind         = qmi_wwan_unbind_shared,
+       .manage_power   = qmi_wwan_manage_power,
+};
+
+static const struct driver_info        qmi_wwan_gobi = {
+       .description    = "Qualcomm Gobi wwan/QMI device",
+       .flags          = FLAG_WWAN,
+       .bind           = qmi_wwan_bind_gobi,
+       .unbind         = qmi_wwan_unbind_shared,
+       .manage_power   = qmi_wwan_manage_power,
+};
+
+/* ZTE suck at making USB descriptors */
+static const struct driver_info        qmi_wwan_force_int4 = {
+       .description    = "Qualcomm Gobi wwan/QMI device",
+       .flags          = FLAG_WWAN,
+       .bind           = qmi_wwan_bind_gobi,
+       .unbind         = qmi_wwan_unbind_shared,
+       .manage_power   = qmi_wwan_manage_power,
+       .data           = BIT(4), /* interface whitelist bitmap */
+};
+
+
+#define HUAWEI_VENDOR_ID       0x12D1
+#define QMI_GOBI_DEVICE(vend, prod) \
+       USB_DEVICE(vend, prod), \
+       .driver_info = (unsigned long)&qmi_wwan_gobi
+
+static const struct usb_device_id products[] = {
+       {       /* Huawei E392, E398 and possibly others sharing both device id and more... */
+               .match_flags        = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO,
+               .idVendor           = HUAWEI_VENDOR_ID,
+               .bInterfaceClass    = USB_CLASS_VENDOR_SPEC,
+               .bInterfaceSubClass = 1,
+               .bInterfaceProtocol = 8, /* NOTE: This is the *slave* interface of the CDC Union! */
+               .driver_info        = (unsigned long)&qmi_wwan_info,
+       },
+       {       /* Huawei E392, E398 and possibly others in "Windows mode"
+                * using a combined control and data interface without any CDC
+                * functional descriptors
+                */
+               .match_flags        = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO,
+               .idVendor           = HUAWEI_VENDOR_ID,
+               .bInterfaceClass    = USB_CLASS_VENDOR_SPEC,
+               .bInterfaceSubClass = 1,
+               .bInterfaceProtocol = 17,
+               .driver_info        = (unsigned long)&qmi_wwan_shared,
+       },
+       {       /* Pantech UML290 */
+               .match_flags        = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
+               .idVendor           = 0x106c,
+               .idProduct          = 0x3718,
+               .bInterfaceClass    = 0xff,
+               .bInterfaceSubClass = 0xf0,
+               .bInterfaceProtocol = 0xff,
+               .driver_info        = (unsigned long)&qmi_wwan_shared,
+       },
+       {       /* ZTE MF820D */
+               .match_flags        = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
+               .idVendor           = 0x19d2,
+               .idProduct          = 0x0167,
+               .bInterfaceClass    = 0xff,
+               .bInterfaceSubClass = 0xff,
+               .bInterfaceProtocol = 0xff,
+               .driver_info        = (unsigned long)&qmi_wwan_force_int4,
+       },
+       {QMI_GOBI_DEVICE(0x05c6, 0x9212)},      /* Acer Gobi Modem Device */
+       {QMI_GOBI_DEVICE(0x03f0, 0x1f1d)},      /* HP un2400 Gobi Modem Device */
+       {QMI_GOBI_DEVICE(0x03f0, 0x371d)},      /* HP un2430 Mobile Broadband Module */
+       {QMI_GOBI_DEVICE(0x04da, 0x250d)},      /* Panasonic Gobi Modem device */
+       {QMI_GOBI_DEVICE(0x413c, 0x8172)},      /* Dell Gobi Modem device */
+       {QMI_GOBI_DEVICE(0x1410, 0xa001)},      /* Novatel Gobi Modem device */
+       {QMI_GOBI_DEVICE(0x0b05, 0x1776)},      /* Asus Gobi Modem device */
+       {QMI_GOBI_DEVICE(0x19d2, 0xfff3)},      /* ONDA Gobi Modem device */
+       {QMI_GOBI_DEVICE(0x05c6, 0x9001)},      /* Generic Gobi Modem device */
+       {QMI_GOBI_DEVICE(0x05c6, 0x9002)},      /* Generic Gobi Modem device */
+       {QMI_GOBI_DEVICE(0x05c6, 0x9202)},      /* Generic Gobi Modem device */
+       {QMI_GOBI_DEVICE(0x05c6, 0x9203)},      /* Generic Gobi Modem device */
+       {QMI_GOBI_DEVICE(0x05c6, 0x9222)},      /* Generic Gobi Modem device */
+       {QMI_GOBI_DEVICE(0x05c6, 0x9009)},      /* Generic Gobi Modem device */
+       {QMI_GOBI_DEVICE(0x413c, 0x8186)},      /* Dell Gobi 2000 Modem device (N0218, VU936) */
+       {QMI_GOBI_DEVICE(0x05c6, 0x920b)},      /* Generic Gobi 2000 Modem device */
+       {QMI_GOBI_DEVICE(0x05c6, 0x9225)},      /* Sony Gobi 2000 Modem device (N0279, VU730) */
+       {QMI_GOBI_DEVICE(0x05c6, 0x9245)},      /* Samsung Gobi 2000 Modem device (VL176) */
+       {QMI_GOBI_DEVICE(0x03f0, 0x251d)},      /* HP Gobi 2000 Modem device (VP412) */
+       {QMI_GOBI_DEVICE(0x05c6, 0x9215)},      /* Acer Gobi 2000 Modem device (VP413) */
+       {QMI_GOBI_DEVICE(0x05c6, 0x9265)},      /* Asus Gobi 2000 Modem device (VR305) */
+       {QMI_GOBI_DEVICE(0x05c6, 0x9235)},      /* Top Global Gobi 2000 Modem device (VR306) */
+       {QMI_GOBI_DEVICE(0x05c6, 0x9275)},      /* iRex Technologies Gobi 2000 Modem device (VR307) */
+       {QMI_GOBI_DEVICE(0x1199, 0x9001)},      /* Sierra Wireless Gobi 2000 Modem device (VT773) */
+       {QMI_GOBI_DEVICE(0x1199, 0x9002)},      /* Sierra Wireless Gobi 2000 Modem device (VT773) */
+       {QMI_GOBI_DEVICE(0x1199, 0x9003)},      /* Sierra Wireless Gobi 2000 Modem device (VT773) */
+       {QMI_GOBI_DEVICE(0x1199, 0x9004)},      /* Sierra Wireless Gobi 2000 Modem device (VT773) */
+       {QMI_GOBI_DEVICE(0x1199, 0x9005)},      /* Sierra Wireless Gobi 2000 Modem device (VT773) */
+       {QMI_GOBI_DEVICE(0x1199, 0x9006)},      /* Sierra Wireless Gobi 2000 Modem device (VT773) */
+       {QMI_GOBI_DEVICE(0x1199, 0x9007)},      /* Sierra Wireless Gobi 2000 Modem device (VT773) */
+       {QMI_GOBI_DEVICE(0x1199, 0x9008)},      /* Sierra Wireless Gobi 2000 Modem device (VT773) */
+       {QMI_GOBI_DEVICE(0x1199, 0x9009)},      /* Sierra Wireless Gobi 2000 Modem device (VT773) */
+       {QMI_GOBI_DEVICE(0x1199, 0x900a)},      /* Sierra Wireless Gobi 2000 Modem device (VT773) */
+       {QMI_GOBI_DEVICE(0x1199, 0x9011)},      /* Sierra Wireless Gobi 2000 Modem device (MC8305) */
+       {QMI_GOBI_DEVICE(0x16d8, 0x8002)},      /* CMDTech Gobi 2000 Modem device (VU922) */
+       {QMI_GOBI_DEVICE(0x05c6, 0x9205)},      /* Gobi 2000 Modem device */
+       {QMI_GOBI_DEVICE(0x1199, 0x9013)},      /* Sierra Wireless Gobi 3000 Modem device (MC8355) */
+       { }                                     /* END */
+};
+MODULE_DEVICE_TABLE(usb, products);
+
+static struct usb_driver qmi_wwan_driver = {
+       .name                 = "qmi_wwan",
+       .id_table             = products,
+       .probe                = usbnet_probe,
+       .disconnect           = usbnet_disconnect,
+       .suspend              = qmi_wwan_suspend,
+       .resume               = qmi_wwan_resume,
+       .reset_resume         = qmi_wwan_resume,
+       .supports_autosuspend = 1,
+};
+
+static int __init qmi_wwan_init(void)
+{
+       return usb_register(&qmi_wwan_driver);
+}
+module_init(qmi_wwan_init);
+
+static void __exit qmi_wwan_exit(void)
+{
+       usb_deregister(&qmi_wwan_driver);
+}
+module_exit(qmi_wwan_exit);
+
+MODULE_AUTHOR("Bjørn Mork <bjorn@mork.no>");
+MODULE_DESCRIPTION("Qualcomm MSM Interface (QMI) WWAN driver");
+MODULE_LICENSE("GPL");
index b806667..1289a5f 100644 (file)
@@ -56,7 +56,7 @@ static u16 isp170x_id[] = {
 struct isp1704_charger {
        struct device           *dev;
        struct power_supply     psy;
-       struct otg_transceiver  *otg;
+       struct usb_phy          *phy;
        struct notifier_block   nb;
        struct work_struct      work;
 
@@ -71,6 +71,16 @@ struct isp1704_charger {
        unsigned                max_power;
 };
 
+static inline int isp1704_read(struct isp1704_charger *isp, u32 reg)
+{
+       return usb_phy_io_read(isp->phy, reg);
+}
+
+static inline int isp1704_write(struct isp1704_charger *isp, u32 val, u32 reg)
+{
+       return usb_phy_io_write(isp->phy, val, reg);
+}
+
 /*
  * Disable/enable the power from the isp1704 if a function for it
  * has been provided with platform data.
@@ -97,31 +107,31 @@ static inline int isp1704_charger_type(struct isp1704_charger *isp)
        u8 otg_ctrl;
        int type = POWER_SUPPLY_TYPE_USB_DCP;
 
-       func_ctrl = otg_io_read(isp->otg, ULPI_FUNC_CTRL);
-       otg_ctrl = otg_io_read(isp->otg, ULPI_OTG_CTRL);
+       func_ctrl = isp1704_read(isp, ULPI_FUNC_CTRL);
+       otg_ctrl = isp1704_read(isp, ULPI_OTG_CTRL);
 
        /* disable pulldowns */
        reg = ULPI_OTG_CTRL_DM_PULLDOWN | ULPI_OTG_CTRL_DP_PULLDOWN;
-       otg_io_write(isp->otg, ULPI_CLR(ULPI_OTG_CTRL), reg);
+       isp1704_write(isp, ULPI_CLR(ULPI_OTG_CTRL), reg);
 
        /* full speed */
-       otg_io_write(isp->otg, ULPI_CLR(ULPI_FUNC_CTRL),
+       isp1704_write(isp, ULPI_CLR(ULPI_FUNC_CTRL),
                        ULPI_FUNC_CTRL_XCVRSEL_MASK);
-       otg_io_write(isp->otg, ULPI_SET(ULPI_FUNC_CTRL),
+       isp1704_write(isp, ULPI_SET(ULPI_FUNC_CTRL),
                        ULPI_FUNC_CTRL_FULL_SPEED);
 
        /* Enable strong pull-up on DP (1.5K) and reset */
        reg = ULPI_FUNC_CTRL_TERMSELECT | ULPI_FUNC_CTRL_RESET;
-       otg_io_write(isp->otg, ULPI_SET(ULPI_FUNC_CTRL), reg);
+       isp1704_write(isp, ULPI_SET(ULPI_FUNC_CTRL), reg);
        usleep_range(1000, 2000);
 
-       reg = otg_io_read(isp->otg, ULPI_DEBUG);
+       reg = isp1704_read(isp, ULPI_DEBUG);
        if ((reg & 3) != 3)
                type = POWER_SUPPLY_TYPE_USB_CDP;
 
        /* recover original state */
-       otg_io_write(isp->otg, ULPI_FUNC_CTRL, func_ctrl);
-       otg_io_write(isp->otg, ULPI_OTG_CTRL, otg_ctrl);
+       isp1704_write(isp, ULPI_FUNC_CTRL, func_ctrl);
+       isp1704_write(isp, ULPI_OTG_CTRL, otg_ctrl);
 
        return type;
 }
@@ -136,28 +146,28 @@ static inline int isp1704_charger_verify(struct isp1704_charger *isp)
        u8      r;
 
        /* Reset the transceiver */
-       r = otg_io_read(isp->otg, ULPI_FUNC_CTRL);
+       r = isp1704_read(isp, ULPI_FUNC_CTRL);
        r |= ULPI_FUNC_CTRL_RESET;
-       otg_io_write(isp->otg, ULPI_FUNC_CTRL, r);
+       isp1704_write(isp, ULPI_FUNC_CTRL, r);
        usleep_range(1000, 2000);
 
        /* Set normal mode */
        r &= ~(ULPI_FUNC_CTRL_RESET | ULPI_FUNC_CTRL_OPMODE_MASK);
-       otg_io_write(isp->otg, ULPI_FUNC_CTRL, r);
+       isp1704_write(isp, ULPI_FUNC_CTRL, r);
 
        /* Clear the DP and DM pull-down bits */
        r = ULPI_OTG_CTRL_DP_PULLDOWN | ULPI_OTG_CTRL_DM_PULLDOWN;
-       otg_io_write(isp->otg, ULPI_CLR(ULPI_OTG_CTRL), r);
+       isp1704_write(isp, ULPI_CLR(ULPI_OTG_CTRL), r);
 
        /* Enable strong pull-up on DP (1.5K) and reset */
        r = ULPI_FUNC_CTRL_TERMSELECT | ULPI_FUNC_CTRL_RESET;
-       otg_io_write(isp->otg, ULPI_SET(ULPI_FUNC_CTRL), r);
+       isp1704_write(isp, ULPI_SET(ULPI_FUNC_CTRL), r);
        usleep_range(1000, 2000);
 
        /* Read the line state */
-       if (!otg_io_read(isp->otg, ULPI_DEBUG)) {
+       if (!isp1704_read(isp, ULPI_DEBUG)) {
                /* Disable strong pull-up on DP (1.5K) */
-               otg_io_write(isp->otg, ULPI_CLR(ULPI_FUNC_CTRL),
+               isp1704_write(isp, ULPI_CLR(ULPI_FUNC_CTRL),
                                ULPI_FUNC_CTRL_TERMSELECT);
                return 1;
        }
@@ -165,23 +175,23 @@ static inline int isp1704_charger_verify(struct isp1704_charger *isp)
        /* Is it a charger or PS/2 connection */
 
        /* Enable weak pull-up resistor on DP */
-       otg_io_write(isp->otg, ULPI_SET(ISP1704_PWR_CTRL),
+       isp1704_write(isp, ULPI_SET(ISP1704_PWR_CTRL),
                        ISP1704_PWR_CTRL_DP_WKPU_EN);
 
        /* Disable strong pull-up on DP (1.5K) */
-       otg_io_write(isp->otg, ULPI_CLR(ULPI_FUNC_CTRL),
+       isp1704_write(isp, ULPI_CLR(ULPI_FUNC_CTRL),
                        ULPI_FUNC_CTRL_TERMSELECT);
 
        /* Enable weak pull-down resistor on DM */
-       otg_io_write(isp->otg, ULPI_SET(ULPI_OTG_CTRL),
+       isp1704_write(isp, ULPI_SET(ULPI_OTG_CTRL),
                        ULPI_OTG_CTRL_DM_PULLDOWN);
 
        /* It's a charger if the line states are clear */
-       if (!(otg_io_read(isp->otg, ULPI_DEBUG)))
+       if (!(isp1704_read(isp, ULPI_DEBUG)))
                ret = 1;
 
        /* Disable weak pull-up resistor on DP */
-       otg_io_write(isp->otg, ULPI_CLR(ISP1704_PWR_CTRL),
+       isp1704_write(isp, ULPI_CLR(ISP1704_PWR_CTRL),
                        ISP1704_PWR_CTRL_DP_WKPU_EN);
 
        return ret;
@@ -193,14 +203,14 @@ static inline int isp1704_charger_detect(struct isp1704_charger *isp)
        u8              pwr_ctrl;
        int             ret = 0;
 
-       pwr_ctrl = otg_io_read(isp->otg, ISP1704_PWR_CTRL);
+       pwr_ctrl = isp1704_read(isp, ISP1704_PWR_CTRL);
 
        /* set SW control bit in PWR_CTRL register */
-       otg_io_write(isp->otg, ISP1704_PWR_CTRL,
+       isp1704_write(isp, ISP1704_PWR_CTRL,
                        ISP1704_PWR_CTRL_SWCTRL);
 
        /* enable manual charger detection */
-       otg_io_write(isp->otg, ULPI_SET(ISP1704_PWR_CTRL),
+       isp1704_write(isp, ULPI_SET(ISP1704_PWR_CTRL),
                        ISP1704_PWR_CTRL_SWCTRL
                        | ISP1704_PWR_CTRL_DPVSRC_EN);
        usleep_range(1000, 2000);
@@ -208,7 +218,7 @@ static inline int isp1704_charger_detect(struct isp1704_charger *isp)
        timeout = jiffies + msecs_to_jiffies(300);
        do {
                /* Check if there is a charger */
-               if (otg_io_read(isp->otg, ISP1704_PWR_CTRL)
+               if (isp1704_read(isp, ISP1704_PWR_CTRL)
                                & ISP1704_PWR_CTRL_VDAT_DET) {
                        ret = isp1704_charger_verify(isp);
                        break;
@@ -216,7 +226,7 @@ static inline int isp1704_charger_detect(struct isp1704_charger *isp)
        } while (!time_after(jiffies, timeout) && isp->online);
 
        /* recover original state */
-       otg_io_write(isp->otg, ISP1704_PWR_CTRL, pwr_ctrl);
+       isp1704_write(isp, ISP1704_PWR_CTRL, pwr_ctrl);
 
        return ret;
 }
@@ -264,8 +274,8 @@ static void isp1704_charger_work(struct work_struct *data)
                case POWER_SUPPLY_TYPE_USB:
                default:
                        /* enable data pullups */
-                       if (isp->otg->gadget)
-                               usb_gadget_connect(isp->otg->gadget);
+                       if (isp->phy->otg->gadget)
+                               usb_gadget_connect(isp->phy->otg->gadget);
                }
                break;
        case USB_EVENT_NONE:
@@ -283,8 +293,8 @@ static void isp1704_charger_work(struct work_struct *data)
                 * chargers. The pullups may be enabled elsewhere, so this can
                 * not be the final solution.
                 */
-               if (isp->otg->gadget)
-                       usb_gadget_disconnect(isp->otg->gadget);
+               if (isp->phy->otg->gadget)
+                       usb_gadget_disconnect(isp->phy->otg->gadget);
 
                isp1704_charger_set_power(isp, 0);
                break;
@@ -364,11 +374,11 @@ static inline int isp1704_test_ulpi(struct isp1704_charger *isp)
        int ret = -ENODEV;
 
        /* Test ULPI interface */
-       ret = otg_io_write(isp->otg, ULPI_SCRATCH, 0xaa);
+       ret = isp1704_write(isp, ULPI_SCRATCH, 0xaa);
        if (ret < 0)
                return ret;
 
-       ret = otg_io_read(isp->otg, ULPI_SCRATCH);
+       ret = isp1704_read(isp, ULPI_SCRATCH);
        if (ret < 0)
                return ret;
 
@@ -376,13 +386,13 @@ static inline int isp1704_test_ulpi(struct isp1704_charger *isp)
                return -ENODEV;
 
        /* Verify the product and vendor id matches */
-       vendor = otg_io_read(isp->otg, ULPI_VENDOR_ID_LOW);
-       vendor |= otg_io_read(isp->otg, ULPI_VENDOR_ID_HIGH) << 8;
+       vendor = isp1704_read(isp, ULPI_VENDOR_ID_LOW);
+       vendor |= isp1704_read(isp, ULPI_VENDOR_ID_HIGH) << 8;
        if (vendor != NXP_VENDOR_ID)
                return -ENODEV;
 
-       product = otg_io_read(isp->otg, ULPI_PRODUCT_ID_LOW);
-       product |= otg_io_read(isp->otg, ULPI_PRODUCT_ID_HIGH) << 8;
+       product = isp1704_read(isp, ULPI_PRODUCT_ID_LOW);
+       product |= isp1704_read(isp, ULPI_PRODUCT_ID_HIGH) << 8;
 
        for (i = 0; i < ARRAY_SIZE(isp170x_id); i++) {
                if (product == isp170x_id[i]) {
@@ -405,8 +415,8 @@ static int __devinit isp1704_charger_probe(struct platform_device *pdev)
        if (!isp)
                return -ENOMEM;
 
-       isp->otg = otg_get_transceiver();
-       if (!isp->otg)
+       isp->phy = usb_get_transceiver();
+       if (!isp->phy)
                goto fail0;
 
        isp->dev = &pdev->dev;
@@ -429,14 +439,14 @@ static int __devinit isp1704_charger_probe(struct platform_device *pdev)
                goto fail1;
 
        /*
-        * REVISIT: using work in order to allow the otg notifications to be
+        * REVISIT: using work in order to allow the usb notifications to be
         * made atomically in the future.
         */
        INIT_WORK(&isp->work, isp1704_charger_work);
 
        isp->nb.notifier_call = isp1704_notifier_call;
 
-       ret = otg_register_notifier(isp->otg, &isp->nb);
+       ret = usb_register_notifier(isp->phy, &isp->nb);
        if (ret)
                goto fail2;
 
@@ -449,13 +459,13 @@ static int __devinit isp1704_charger_probe(struct platform_device *pdev)
         * enumerated. The charger driver should be always loaded before any
         * gadget is loaded.
         */
-       if (isp->otg->gadget)
-               usb_gadget_disconnect(isp->otg->gadget);
+       if (isp->phy->otg->gadget)
+               usb_gadget_disconnect(isp->phy->otg->gadget);
 
        /* Detect charger if VBUS is valid (the cable was already plugged). */
-       ret = otg_io_read(isp->otg, ULPI_USB_INT_STS);
+       ret = isp1704_read(isp, ULPI_USB_INT_STS);
        isp1704_charger_set_power(isp, 0);
-       if ((ret & ULPI_INT_VBUS_VALID) && !isp->otg->default_a) {
+       if ((ret & ULPI_INT_VBUS_VALID) && !isp->phy->otg->default_a) {
                isp->event = USB_EVENT_VBUS;
                schedule_work(&isp->work);
        }
@@ -464,7 +474,7 @@ static int __devinit isp1704_charger_probe(struct platform_device *pdev)
 fail2:
        power_supply_unregister(&isp->psy);
 fail1:
-       otg_put_transceiver(isp->otg);
+       usb_put_transceiver(isp->phy);
 fail0:
        kfree(isp);
 
@@ -477,9 +487,9 @@ static int __devexit isp1704_charger_remove(struct platform_device *pdev)
 {
        struct isp1704_charger *isp = platform_get_drvdata(pdev);
 
-       otg_unregister_notifier(isp->otg, &isp->nb);
+       usb_unregister_notifier(isp->phy, &isp->nb);
        power_supply_unregister(&isp->psy);
-       otg_put_transceiver(isp->otg);
+       usb_put_transceiver(isp->phy);
        isp1704_charger_set_power(isp, 0);
        kfree(isp);
 
index fd49689..214468f 100644 (file)
@@ -40,7 +40,7 @@ static struct timer_list polling_timer;
 static int polling;
 
 #ifdef CONFIG_USB_OTG_UTILS
-static struct otg_transceiver *transceiver;
+static struct usb_phy *transceiver;
 static struct notifier_block otg_nb;
 #endif
 
@@ -321,7 +321,7 @@ static int pda_power_probe(struct platform_device *pdev)
        }
 
 #ifdef CONFIG_USB_OTG_UTILS
-       transceiver = otg_get_transceiver();
+       transceiver = usb_get_transceiver();
        if (transceiver && !pdata->is_usb_online) {
                pdata->is_usb_online = otg_is_usb_online;
        }
@@ -375,7 +375,7 @@ static int pda_power_probe(struct platform_device *pdev)
 #ifdef CONFIG_USB_OTG_UTILS
        if (transceiver && pdata->use_otg_notifier) {
                otg_nb.notifier_call = otg_handle_notification;
-               ret = otg_register_notifier(transceiver, &otg_nb);
+               ret = usb_register_notifier(transceiver, &otg_nb);
                if (ret) {
                        dev_err(dev, "failure to register otg notifier\n");
                        goto otg_reg_notifier_failed;
@@ -409,7 +409,7 @@ usb_supply_failed:
                free_irq(ac_irq->start, &pda_psy_ac);
 #ifdef CONFIG_USB_OTG_UTILS
        if (transceiver)
-               otg_put_transceiver(transceiver);
+               usb_put_transceiver(transceiver);
 #endif
 ac_irq_failed:
        if (pdata->is_ac_online)
@@ -444,7 +444,7 @@ static int pda_power_remove(struct platform_device *pdev)
                power_supply_unregister(&pda_psy_ac);
 #ifdef CONFIG_USB_OTG_UTILS
        if (transceiver)
-               otg_put_transceiver(transceiver);
+               usb_put_transceiver(transceiver);
 #endif
        if (ac_draw) {
                regulator_put(ac_draw);
index 54b9198..fdad850 100644 (file)
@@ -69,8 +69,8 @@ struct twl4030_bci {
        struct device           *dev;
        struct power_supply     ac;
        struct power_supply     usb;
-       struct otg_transceiver  *transceiver;
-       struct notifier_block   otg_nb;
+       struct usb_phy          *transceiver;
+       struct notifier_block   usb_nb;
        struct work_struct      work;
        int                     irq_chg;
        int                     irq_bci;
@@ -279,7 +279,7 @@ static void twl4030_bci_usb_work(struct work_struct *data)
 static int twl4030_bci_usb_ncb(struct notifier_block *nb, unsigned long val,
                               void *priv)
 {
-       struct twl4030_bci *bci = container_of(nb, struct twl4030_bci, otg_nb);
+       struct twl4030_bci *bci = container_of(nb, struct twl4030_bci, usb_nb);
 
        dev_dbg(bci->dev, "OTG notify %lu\n", val);
 
@@ -479,10 +479,10 @@ static int __init twl4030_bci_probe(struct platform_device *pdev)
 
        INIT_WORK(&bci->work, twl4030_bci_usb_work);
 
-       bci->transceiver = otg_get_transceiver();
+       bci->transceiver = usb_get_transceiver();
        if (bci->transceiver != NULL) {
-               bci->otg_nb.notifier_call = twl4030_bci_usb_ncb;
-               otg_register_notifier(bci->transceiver, &bci->otg_nb);
+               bci->usb_nb.notifier_call = twl4030_bci_usb_ncb;
+               usb_register_notifier(bci->transceiver, &bci->usb_nb);
        }
 
        /* Enable interrupts now. */
@@ -508,8 +508,8 @@ static int __init twl4030_bci_probe(struct platform_device *pdev)
 
 fail_unmask_interrupts:
        if (bci->transceiver != NULL) {
-               otg_unregister_notifier(bci->transceiver, &bci->otg_nb);
-               otg_put_transceiver(bci->transceiver);
+               usb_unregister_notifier(bci->transceiver, &bci->usb_nb);
+               usb_put_transceiver(bci->transceiver);
        }
        free_irq(bci->irq_bci, bci);
 fail_bci_irq:
@@ -539,8 +539,8 @@ static int __exit twl4030_bci_remove(struct platform_device *pdev)
                         TWL4030_INTERRUPTS_BCIIMR2A);
 
        if (bci->transceiver != NULL) {
-               otg_unregister_notifier(bci->transceiver, &bci->otg_nb);
-               otg_put_transceiver(bci->transceiver);
+               usb_unregister_notifier(bci->transceiver, &bci->usb_nb);
+               usb_put_transceiver(bci->transceiver);
        }
        free_irq(bci->irq_bci, bci);
        free_irq(bci->irq_chg, bci);
index 29c4c04..01b0374 100644 (file)
@@ -1295,6 +1295,7 @@ EXPORT_SYMBOL(int_to_scsilun);
  *   LUNs even if it's older than SCSI-3.
  *   If BLIST_NOREPORTLUN is set, return 1 always.
  *   If BLIST_NOLUN is set, return 0 always.
+ *   If starget->no_report_luns is set, return 1 always.
  *
  * Return:
  *     0: scan completed (or no memory, so further scanning is futile)
@@ -1321,6 +1322,7 @@ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags,
         * Only support SCSI-3 and up devices if BLIST_NOREPORTLUN is not set.
         * Also allow SCSI-2 if BLIST_REPORTLUN2 is set and host adapter does
         * support more than 8 LUNs.
+        * Don't attempt if the target doesn't support REPORT LUNS.
         */
        if (bflags & BLIST_NOREPORTLUN)
                return 1;
@@ -1332,6 +1334,8 @@ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags,
                return 1;
        if (bflags & BLIST_NOLUN)
                return 0;
+       if (starget->no_report_luns)
+               return 1;
 
        if (!(sdev = scsi_device_lookup_by_target(starget, 0))) {
                sdev = scsi_alloc_sdev(starget, 0, NULL);
index c691fb5..d173b90 100644 (file)
@@ -2349,7 +2349,7 @@ static int sd_try_extended_inquiry(struct scsi_device *sdp)
         * some USB ones crash on receiving them, and the pages
         * we currently ask for are for SPC-3 and beyond
         */
-       if (sdp->scsi_level > SCSI_SPC_2)
+       if (sdp->scsi_level > SCSI_SPC_2 && !sdp->skip_vpd_pages)
                return 1;
        return 0;
 }
index 4ae57d0..2a11a98 100644 (file)
@@ -3,43 +3,6 @@
 
 #include <linux/blkdev.h>
 
-/* Bulk only data structures */
-
-/* command block wrapper */
-struct bulk_cb_wrap {
-       __le32  Signature;                      /* contains 'USBC' */
-       __u32   Tag;                            /* unique per command id */
-       __le32  DataTransferLength;     /* size of data */
-       __u8    Flags;                          /* direction in bit 0 */
-       __u8    Lun;                                    /* LUN normally 0 */
-       __u8    Length;                         /* of of the CDB */
-       __u8    CDB[16];                                /* max command */
-};
-
-#define US_BULK_CB_WRAP_LEN    31
-#define US_BULK_CB_SIGN                0x43425355      /*spells out USBC */
-#define US_BULK_FLAG_IN                1
-#define US_BULK_FLAG_OUT       0
-
-/* command status wrapper */
-struct bulk_cs_wrap {
-       __le32  Signature;              /* should = 'USBS' */
-       __u32           Tag;                    /* same as original command */
-       __le32  Residue;                /* amount not transferred */
-       __u8            Status;         /* see below */
-       __u8            Filler[18];
-};
-
-#define US_BULK_CS_WRAP_LEN    13
-#define US_BULK_CS_SIGN                0x53425355      /* spells out 'USBS' */
-#define US_BULK_STAT_OK                0
-#define US_BULK_STAT_FAIL      1
-#define US_BULK_STAT_PHASE     2
-
-/* bulk-only class specific requests */
-#define US_BULK_RESET_REQUEST  0xff
-#define US_BULK_GET_MAX_LUN    0xfe
-
 /* usb_stor_bulk_transfer_xxx() return codes, in order of severity */
 #define USB_STOR_XFER_GOOD     0       /* good transfer                 */
 #define USB_STOR_XFER_SHORT    1       /* transferred less than expected */
index 897a3a9..bb977e0 100644 (file)
@@ -135,7 +135,6 @@ static struct usb_driver quausb2_usb_driver = {
        .probe = usb_serial_probe,
        .disconnect = usb_serial_disconnect,
        .id_table = quausb2_id_table,
-       .no_dynamic_id = 1,
 };
 
 /**
@@ -1942,7 +1941,6 @@ static struct usb_serial_driver quatech2_device = {
                .name = "quatech_usb2",
        },
        .description = DRIVER_DESC,
-       .usb_driver = &quausb2_usb_driver,
        .id_table = quausb2_id_table,
        .num_ports = 8,
        .open = qt2_open,
@@ -1964,41 +1962,11 @@ static struct usb_serial_driver quatech2_device = {
        .write_bulk_callback = qt2_write_bulk_callback,
 };
 
-static int __init quausb2_usb_init(void)
-{
-       int retval;
-
-       dbg("%s\n", __func__);
-
-       /* register with usb-serial */
-       retval = usb_serial_register(&quatech2_device);
-
-       if (retval)
-               goto failed_usb_serial_register;
-
-       printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-                       DRIVER_DESC "\n");
-
-       /* register with usb */
-
-       retval = usb_register(&quausb2_usb_driver);
-       if (retval == 0)
-               return 0;
-
-       /* if we're here, usb_register() failed */
-       usb_serial_deregister(&quatech2_device);
-failed_usb_serial_register:
-               return retval;
-}
-
-static void __exit quausb2_usb_exit(void)
-{
-       usb_deregister(&quausb2_usb_driver);
-       usb_serial_deregister(&quatech2_device);
-}
+static struct usb_serial_driver * const serial_drivers[] = {
+       &quatech2_device, NULL
+};
 
-module_init(quausb2_usb_init);
-module_exit(quausb2_usb_exit);
+module_usb_serial_driver(quausb2_usb_driver, serial_drivers);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
index 1c5780f..ae1d815 100644 (file)
@@ -200,7 +200,6 @@ static struct usb_driver serqt_usb_driver = {
        .probe = usb_serial_probe,
        .disconnect = usb_serial_disconnect,
        .id_table = serqt_id_table,
-       .no_dynamic_id = 1,
 };
 
 static int port_paranoia_check(struct usb_serial_port *port,
@@ -1590,7 +1589,6 @@ static struct usb_serial_driver quatech_device = {
                   .name = "serqt",
                   },
        .description = DRIVER_DESC,
-       .usb_driver = &serqt_usb_driver,
        .id_table = serqt_id_table,
        .num_ports = 8,
        .open = qt_open,
@@ -1610,41 +1608,11 @@ static struct usb_serial_driver quatech_device = {
        .release = qt_release,
 };
 
-static int __init serqt_usb_init(void)
-{
-       int retval;
-
-       dbg("%s\n", __func__);
-
-       /* register with usb-serial */
-       retval = usb_serial_register(&quatech_device);
-
-       if (retval)
-               goto failed_usb_serial_register;
-
-       printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-              DRIVER_DESC "\n");
-
-       /* register with usb */
-
-       retval = usb_register(&serqt_usb_driver);
-       if (retval == 0)
-               return 0;
-
-       /* if we're here, usb_register() failed */
-       usb_serial_deregister(&quatech_device);
-failed_usb_serial_register:
-       return retval;
-}
-
-static void __exit serqt_usb_exit(void)
-{
-       usb_deregister(&serqt_usb_driver);
-       usb_serial_deregister(&quatech_device);
-}
+static struct usb_serial_driver * const serial_drivers[] = {
+       &quatech_device, NULL
+};
 
-module_init(serqt_usb_init);
-module_exit(serqt_usb_exit);
+module_usb_serial_driver(serqt_usb_driver, serial_drivers);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
index 75823a1..e4405e0 100644 (file)
@@ -10,27 +10,6 @@ menuconfig USB_SUPPORT
          This option adds core support for Universal Serial Bus (USB).
          You will also need drivers from the following menu to make use of it.
 
-if USB_SUPPORT
-
-config USB_COMMON
-       tristate
-       default y
-       depends on USB || USB_GADGET
-
-# Host-side USB depends on having a host controller
-# NOTE:  dummy_hcd is always an option, but it's ignored here ...
-# NOTE:  SL-811 option should be board-specific ...
-config USB_ARCH_HAS_HCD
-       boolean
-       default y if USB_ARCH_HAS_OHCI
-       default y if USB_ARCH_HAS_EHCI
-       default y if USB_ARCH_HAS_XHCI
-       default y if PCMCIA && !M32R                    # sl811_cs
-       default y if ARM                                # SL-811
-       default y if BLACKFIN                           # SL-811
-       default y if SUPERH                             # r8a66597-hcd
-       default PCI
-
 # many non-PCI SOC chips embed OHCI
 config USB_ARCH_HAS_OHCI
        boolean
@@ -76,6 +55,7 @@ config USB_ARCH_HAS_EHCI
        default y if MICROBLAZE
        default y if SPARC_LEON
        default y if ARCH_MMP
+       default y if MACH_LOONGSON1
        default PCI
 
 # some non-PCI HCDs implement xHCI
@@ -83,6 +63,27 @@ config USB_ARCH_HAS_XHCI
        boolean
        default PCI
 
+if USB_SUPPORT
+
+config USB_COMMON
+       tristate
+       default y
+       depends on USB || USB_GADGET
+
+# Host-side USB depends on having a host controller
+# NOTE:  dummy_hcd is always an option, but it's ignored here ...
+# NOTE:  SL-811 option should be board-specific ...
+config USB_ARCH_HAS_HCD
+       boolean
+       default y if USB_ARCH_HAS_OHCI
+       default y if USB_ARCH_HAS_EHCI
+       default y if USB_ARCH_HAS_XHCI
+       default y if PCMCIA && !M32R                    # sl811_cs
+       default y if ARM                                # SL-811
+       default y if BLACKFIN                           # SL-811
+       default y if SUPERH                             # r8a66597-hcd
+       default PCI
+
 # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
 config USB
        tristate "Support for Host-side USB"
index 6bb8472..b32ccb4 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/serial.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
+#include <linux/serial.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/uaccess.h>
@@ -768,10 +769,37 @@ static int acm_tty_tiocmset(struct tty_struct *tty,
        return acm_set_control(acm, acm->ctrlout = newctrl);
 }
 
+static int get_serial_info(struct acm *acm, struct serial_struct __user *info)
+{
+       struct serial_struct tmp;
+
+       if (!info)
+               return -EINVAL;
+
+       memset(&tmp, 0, sizeof(tmp));
+       tmp.flags = ASYNC_LOW_LATENCY;
+       tmp.xmit_fifo_size = acm->writesize;
+       tmp.baud_base = le32_to_cpu(acm->line.dwDTERate);
+
+       if (copy_to_user(info, &tmp, sizeof(tmp)))
+               return -EFAULT;
+       else
+               return 0;
+}
+
 static int acm_tty_ioctl(struct tty_struct *tty,
                                        unsigned int cmd, unsigned long arg)
 {
-       return -ENOIOCTLCMD;
+       struct acm *acm = tty->driver_data;
+       int rv = -ENOIOCTLCMD;
+
+       switch (cmd) {
+       case TIOCGSERIAL: /* gets serial port data */
+               rv = get_serial_info(acm, (struct serial_struct __user *) arg);
+               break;
+       }
+
+       return rv;
 }
 
 static const __u32 acm_tty_speed[] = {
index d2b3cff..c6f6560 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/usb/cdc.h>
 #include <asm/byteorder.h>
 #include <asm/unaligned.h>
+#include <linux/usb/cdc-wdm.h>
 
 /*
  * Version Information
@@ -31,6 +32,8 @@
 #define DRIVER_AUTHOR "Oliver Neukum"
 #define DRIVER_DESC "USB Abstract Control Model driver for USB WCM Device Management"
 
+#define HUAWEI_VENDOR_ID       0x12D1
+
 static const struct usb_device_id wdm_ids[] = {
        {
                .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS |
@@ -38,6 +41,20 @@ static const struct usb_device_id wdm_ids[] = {
                .bInterfaceClass = USB_CLASS_COMM,
                .bInterfaceSubClass = USB_CDC_SUBCLASS_DMM
        },
+       {
+               /* 
+                * Huawei E392, E398 and possibly other Qualcomm based modems
+                * embed the Qualcomm QMI protocol inside CDC on CDC ECM like
+                * control interfaces.  Userspace access to this is required
+                * to configure the accompanying data interface
+                */
+               .match_flags        = USB_DEVICE_ID_MATCH_VENDOR |
+                                       USB_DEVICE_ID_MATCH_INT_INFO,
+               .idVendor           = HUAWEI_VENDOR_ID,
+               .bInterfaceClass    = USB_CLASS_VENDOR_SPEC,
+               .bInterfaceSubClass = 1,
+               .bInterfaceProtocol = 9, /* NOTE: CDC ECM control interface! */
+       },
        { }
 };
 
@@ -54,6 +71,7 @@ MODULE_DEVICE_TABLE (usb, wdm_ids);
 #define WDM_POLL_RUNNING       6
 #define WDM_RESPONDING         7
 #define WDM_SUSPENDING         8
+#define WDM_RESETTING          9
 
 #define WDM_MAX                        16
 
@@ -61,6 +79,8 @@ MODULE_DEVICE_TABLE (usb, wdm_ids);
 #define WDM_DEFAULT_BUFSIZE    256
 
 static DEFINE_MUTEX(wdm_mutex);
+static DEFINE_SPINLOCK(wdm_device_list_lock);
+static LIST_HEAD(wdm_device_list);
 
 /* --- method tables --- */
 
@@ -82,7 +102,6 @@ struct wdm_device {
        u16                     bufsize;
        u16                     wMaxCommand;
        u16                     wMaxPacketSize;
-       u16                     bMaxPacketSize0;
        __le16                  inum;
        int                     reslength;
        int                     length;
@@ -96,10 +115,40 @@ struct wdm_device {
        struct work_struct      rxwork;
        int                     werr;
        int                     rerr;
+
+       struct list_head        device_list;
+       int                     (*manage_power)(struct usb_interface *, int);
 };
 
 static struct usb_driver wdm_driver;
 
+/* return intfdata if we own the interface, else look up intf in the list */
+static struct wdm_device *wdm_find_device(struct usb_interface *intf)
+{
+       struct wdm_device *desc = NULL;
+
+       spin_lock(&wdm_device_list_lock);
+       list_for_each_entry(desc, &wdm_device_list, device_list)
+               if (desc->intf == intf)
+                       break;
+       spin_unlock(&wdm_device_list_lock);
+
+       return desc;
+}
+
+static struct wdm_device *wdm_find_device_by_minor(int minor)
+{
+       struct wdm_device *desc = NULL;
+
+       spin_lock(&wdm_device_list_lock);
+       list_for_each_entry(desc, &wdm_device_list, device_list)
+               if (desc->intf->minor == minor)
+                       break;
+       spin_unlock(&wdm_device_list_lock);
+
+       return desc;
+}
+
 /* --- callbacks --- */
 static void wdm_out_callback(struct urb *urb)
 {
@@ -162,11 +211,9 @@ static void wdm_int_callback(struct urb *urb)
        int rv = 0;
        int status = urb->status;
        struct wdm_device *desc;
-       struct usb_ctrlrequest *req;
        struct usb_cdc_notification *dr;
 
        desc = urb->context;
-       req = desc->irq;
        dr = (struct usb_cdc_notification *)desc->sbuf;
 
        if (status) {
@@ -213,24 +260,6 @@ static void wdm_int_callback(struct urb *urb)
                goto exit;
        }
 
-       req->bRequestType = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE);
-       req->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE;
-       req->wValue = 0;
-       req->wIndex = desc->inum;
-       req->wLength = cpu_to_le16(desc->wMaxCommand);
-
-       usb_fill_control_urb(
-               desc->response,
-               interface_to_usbdev(desc->intf),
-               /* using common endpoint 0 */
-               usb_rcvctrlpipe(interface_to_usbdev(desc->intf), 0),
-               (unsigned char *)req,
-               desc->inbuf,
-               desc->wMaxCommand,
-               wdm_in_callback,
-               desc
-       );
-       desc->response->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
        spin_lock(&desc->iuspin);
        clear_bit(WDM_READ, &desc->flags);
        set_bit(WDM_RESPONDING, &desc->flags);
@@ -279,14 +308,11 @@ static void free_urbs(struct wdm_device *desc)
 
 static void cleanup(struct wdm_device *desc)
 {
-       usb_free_coherent(interface_to_usbdev(desc->intf),
-                         desc->wMaxPacketSize,
-                         desc->sbuf,
-                         desc->validity->transfer_dma);
-       usb_free_coherent(interface_to_usbdev(desc->intf),
-                         desc->bMaxPacketSize0,
-                         desc->inbuf,
-                         desc->response->transfer_dma);
+       spin_lock(&wdm_device_list_lock);
+       list_del(&desc->device_list);
+       spin_unlock(&wdm_device_list_lock);
+       kfree(desc->sbuf);
+       kfree(desc->inbuf);
        kfree(desc->orq);
        kfree(desc->irq);
        kfree(desc->ubuf);
@@ -351,6 +377,10 @@ static ssize_t wdm_write
        else
                if (test_bit(WDM_IN_USE, &desc->flags))
                        r = -EAGAIN;
+
+       if (test_bit(WDM_RESETTING, &desc->flags))
+               r = -EIO;
+
        if (r < 0) {
                kfree(buf);
                goto out;
@@ -397,7 +427,7 @@ outnl:
 static ssize_t wdm_read
 (struct file *file, char __user *buffer, size_t count, loff_t *ppos)
 {
-       int rv, cntr = 0;
+       int rv, cntr;
        int i = 0;
        struct wdm_device *desc = file->private_data;
 
@@ -406,7 +436,8 @@ static ssize_t wdm_read
        if (rv < 0)
                return -ERESTARTSYS;
 
-       if (desc->length == 0) {
+       cntr = ACCESS_ONCE(desc->length);
+       if (cntr == 0) {
                desc->read = 0;
 retry:
                if (test_bit(WDM_DISCONNECTING, &desc->flags)) {
@@ -430,6 +461,10 @@ retry:
                        rv = -ENODEV;
                        goto err;
                }
+               if (test_bit(WDM_RESETTING, &desc->flags)) {
+                       rv = -EIO;
+                       goto err;
+               }
                usb_mark_last_busy(interface_to_usbdev(desc->intf));
                if (rv < 0) {
                        rv = -ERESTARTSYS;
@@ -456,26 +491,30 @@ retry:
                        spin_unlock_irq(&desc->iuspin);
                        goto retry;
                }
-               clear_bit(WDM_READ, &desc->flags);
+               cntr = desc->length;
                spin_unlock_irq(&desc->iuspin);
        }
 
-       cntr = count > desc->length ? desc->length : count;
+       if (cntr > count)
+               cntr = count;
        rv = copy_to_user(buffer, desc->ubuf, cntr);
        if (rv > 0) {
                rv = -EFAULT;
                goto err;
        }
 
+       spin_lock_irq(&desc->iuspin);
+
        for (i = 0; i < desc->length - cntr; i++)
                desc->ubuf[i] = desc->ubuf[i + cntr];
 
-       spin_lock_irq(&desc->iuspin);
        desc->length -= cntr;
-       spin_unlock_irq(&desc->iuspin);
        /* in case we had outstanding data */
        if (!desc->length)
                clear_bit(WDM_READ, &desc->flags);
+
+       spin_unlock_irq(&desc->iuspin);
+
        rv = cntr;
 
 err:
@@ -529,11 +568,11 @@ static int wdm_open(struct inode *inode, struct file *file)
        struct wdm_device *desc;
 
        mutex_lock(&wdm_mutex);
-       intf = usb_find_interface(&wdm_driver, minor);
-       if (!intf)
+       desc = wdm_find_device_by_minor(minor);
+       if (!desc)
                goto out;
 
-       desc = usb_get_intfdata(intf);
+       intf = desc->intf;
        if (test_bit(WDM_DISCONNECTING, &desc->flags))
                goto out;
        file->private_data = desc;
@@ -543,7 +582,6 @@ static int wdm_open(struct inode *inode, struct file *file)
                dev_err(&desc->intf->dev, "Error autopm - %d\n", rv);
                goto out;
        }
-       intf->needs_remote_wakeup = 1;
 
        /* using write lock to protect desc->count */
        mutex_lock(&desc->wlock);
@@ -560,6 +598,8 @@ static int wdm_open(struct inode *inode, struct file *file)
                rv = 0;
        }
        mutex_unlock(&desc->wlock);
+       if (desc->count == 1)
+               desc->manage_power(intf, 1);
        usb_autopm_put_interface(desc->intf);
 out:
        mutex_unlock(&wdm_mutex);
@@ -581,7 +621,7 @@ static int wdm_release(struct inode *inode, struct file *file)
                dev_dbg(&desc->intf->dev, "wdm_release: cleanup");
                kill_urbs(desc);
                if (!test_bit(WDM_DISCONNECTING, &desc->flags))
-                       desc->intf->needs_remote_wakeup = 0;
+                       desc->manage_power(desc->intf, 0);
        }
        mutex_unlock(&wdm_mutex);
        return 0;
@@ -628,71 +668,31 @@ static void wdm_rxwork(struct work_struct *work)
 
 /* --- hotplug --- */
 
-static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id)
+static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor *ep,
+               u16 bufsize, int (*manage_power)(struct usb_interface *, int))
 {
-       int rv = -EINVAL;
-       struct usb_device *udev = interface_to_usbdev(intf);
+       int rv = -ENOMEM;
        struct wdm_device *desc;
-       struct usb_host_interface *iface;
-       struct usb_endpoint_descriptor *ep;
-       struct usb_cdc_dmm_desc *dmhd;
-       u8 *buffer = intf->altsetting->extra;
-       int buflen = intf->altsetting->extralen;
-       u16 maxcom = WDM_DEFAULT_BUFSIZE;
-
-       if (!buffer)
-               goto out;
 
-       while (buflen > 2) {
-               if (buffer [1] != USB_DT_CS_INTERFACE) {
-                       dev_err(&intf->dev, "skipping garbage\n");
-                       goto next_desc;
-               }
-
-               switch (buffer [2]) {
-               case USB_CDC_HEADER_TYPE:
-                       break;
-               case USB_CDC_DMM_TYPE:
-                       dmhd = (struct usb_cdc_dmm_desc *)buffer;
-                       maxcom = le16_to_cpu(dmhd->wMaxCommand);
-                       dev_dbg(&intf->dev,
-                               "Finding maximum buffer length: %d", maxcom);
-                       break;
-               default:
-                       dev_err(&intf->dev,
-                               "Ignoring extra header, type %d, length %d\n",
-                               buffer[2], buffer[0]);
-                       break;
-               }
-next_desc:
-               buflen -= buffer[0];
-               buffer += buffer[0];
-       }
-
-       rv = -ENOMEM;
        desc = kzalloc(sizeof(struct wdm_device), GFP_KERNEL);
        if (!desc)
                goto out;
+       INIT_LIST_HEAD(&desc->device_list);
        mutex_init(&desc->rlock);
        mutex_init(&desc->wlock);
        spin_lock_init(&desc->iuspin);
        init_waitqueue_head(&desc->wait);
-       desc->wMaxCommand = maxcom;
+       desc->wMaxCommand = bufsize;
        /* this will be expanded and needed in hardware endianness */
        desc->inum = cpu_to_le16((u16)intf->cur_altsetting->desc.bInterfaceNumber);
        desc->intf = intf;
        INIT_WORK(&desc->rxwork, wdm_rxwork);
 
        rv = -EINVAL;
-       iface = intf->cur_altsetting;
-       if (iface->desc.bNumEndpoints != 1)
-               goto err;
-       ep = &iface->endpoint[0].desc;
-       if (!ep || !usb_endpoint_is_int_in(ep))
+       if (!usb_endpoint_is_int_in(ep))
                goto err;
 
        desc->wMaxPacketSize = usb_endpoint_maxp(ep);
-       desc->bMaxPacketSize0 = udev->descriptor.bMaxPacketSize0;
 
        desc->orq = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
        if (!desc->orq)
@@ -717,19 +717,13 @@ next_desc:
        if (!desc->ubuf)
                goto err;
 
-       desc->sbuf = usb_alloc_coherent(interface_to_usbdev(intf),
-                                       desc->wMaxPacketSize,
-                                       GFP_KERNEL,
-                                       &desc->validity->transfer_dma);
+       desc->sbuf = kmalloc(desc->wMaxPacketSize, GFP_KERNEL);
        if (!desc->sbuf)
                goto err;
 
-       desc->inbuf = usb_alloc_coherent(interface_to_usbdev(intf),
-                                        desc->wMaxCommand,
-                                        GFP_KERNEL,
-                                        &desc->response->transfer_dma);
+       desc->inbuf = kmalloc(desc->wMaxCommand, GFP_KERNEL);
        if (!desc->inbuf)
-               goto err2;
+               goto err;
 
        usb_fill_int_urb(
                desc->validity,
@@ -741,45 +735,149 @@ next_desc:
                desc,
                ep->bInterval
        );
-       desc->validity->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 
-       usb_set_intfdata(intf, desc);
+       desc->irq->bRequestType = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE);
+       desc->irq->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE;
+       desc->irq->wValue = 0;
+       desc->irq->wIndex = desc->inum;
+       desc->irq->wLength = cpu_to_le16(desc->wMaxCommand);
+
+       usb_fill_control_urb(
+               desc->response,
+               interface_to_usbdev(intf),
+               /* using common endpoint 0 */
+               usb_rcvctrlpipe(interface_to_usbdev(desc->intf), 0),
+               (unsigned char *)desc->irq,
+               desc->inbuf,
+               desc->wMaxCommand,
+               wdm_in_callback,
+               desc
+       );
+
+       desc->manage_power = manage_power;
+
+       spin_lock(&wdm_device_list_lock);
+       list_add(&desc->device_list, &wdm_device_list);
+       spin_unlock(&wdm_device_list_lock);
+
        rv = usb_register_dev(intf, &wdm_class);
        if (rv < 0)
-               goto err3;
+               goto err;
        else
-               dev_info(&intf->dev, "cdc-wdm%d: USB WDM device\n",
-                       intf->minor - WDM_MINOR_BASE);
+               dev_info(&intf->dev, "%s: USB WDM device\n", dev_name(intf->usb_dev));
 out:
        return rv;
-err3:
-       usb_set_intfdata(intf, NULL);
-       usb_free_coherent(interface_to_usbdev(desc->intf),
-                         desc->bMaxPacketSize0,
-                       desc->inbuf,
-                       desc->response->transfer_dma);
-err2:
-       usb_free_coherent(interface_to_usbdev(desc->intf),
-                         desc->wMaxPacketSize,
-                         desc->sbuf,
-                         desc->validity->transfer_dma);
 err:
-       free_urbs(desc);
-       kfree(desc->ubuf);
-       kfree(desc->orq);
-       kfree(desc->irq);
-       kfree(desc);
+       cleanup(desc);
+       return rv;
+}
+
+static int wdm_manage_power(struct usb_interface *intf, int on)
+{
+       /* need autopm_get/put here to ensure the usbcore sees the new value */
+       int rv = usb_autopm_get_interface(intf);
+       if (rv < 0)
+               goto err;
+
+       intf->needs_remote_wakeup = on;
+       usb_autopm_put_interface(intf);
+err:
+       return rv;
+}
+
+static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+       int rv = -EINVAL;
+       struct usb_host_interface *iface;
+       struct usb_endpoint_descriptor *ep;
+       struct usb_cdc_dmm_desc *dmhd;
+       u8 *buffer = intf->altsetting->extra;
+       int buflen = intf->altsetting->extralen;
+       u16 maxcom = WDM_DEFAULT_BUFSIZE;
+
+       if (!buffer)
+               goto err;
+       while (buflen > 2) {
+               if (buffer[1] != USB_DT_CS_INTERFACE) {
+                       dev_err(&intf->dev, "skipping garbage\n");
+                       goto next_desc;
+               }
+
+               switch (buffer[2]) {
+               case USB_CDC_HEADER_TYPE:
+                       break;
+               case USB_CDC_DMM_TYPE:
+                       dmhd = (struct usb_cdc_dmm_desc *)buffer;
+                       maxcom = le16_to_cpu(dmhd->wMaxCommand);
+                       dev_dbg(&intf->dev,
+                               "Finding maximum buffer length: %d", maxcom);
+                       break;
+               default:
+                       dev_err(&intf->dev,
+                               "Ignoring extra header, type %d, length %d\n",
+                               buffer[2], buffer[0]);
+                       break;
+               }
+next_desc:
+               buflen -= buffer[0];
+               buffer += buffer[0];
+       }
+
+       iface = intf->cur_altsetting;
+       if (iface->desc.bNumEndpoints != 1)
+               goto err;
+       ep = &iface->endpoint[0].desc;
+
+       rv = wdm_create(intf, ep, maxcom, &wdm_manage_power);
+
+err:
        return rv;
 }
 
+/**
+ * usb_cdc_wdm_register - register a WDM subdriver
+ * @intf: usb interface the subdriver will associate with
+ * @ep: interrupt endpoint to monitor for notifications
+ * @bufsize: maximum message size to support for read/write
+ *
+ * Create WDM usb class character device and associate it with intf
+ * without binding, allowing another driver to manage the interface.
+ *
+ * The subdriver will manage the given interrupt endpoint exclusively
+ * and will issue control requests referring to the given intf. It
+ * will otherwise avoid interferring, and in particular not do
+ * usb_set_intfdata/usb_get_intfdata on intf.
+ *
+ * The return value is a pointer to the subdriver's struct usb_driver.
+ * The registering driver is responsible for calling this subdriver's
+ * disconnect, suspend, resume, pre_reset and post_reset methods from
+ * its own.
+ */
+struct usb_driver *usb_cdc_wdm_register(struct usb_interface *intf,
+                                       struct usb_endpoint_descriptor *ep,
+                                       int bufsize,
+                                       int (*manage_power)(struct usb_interface *, int))
+{
+       int rv = -EINVAL;
+
+       rv = wdm_create(intf, ep, bufsize, manage_power);
+       if (rv < 0)
+               goto err;
+
+       return &wdm_driver;
+err:
+       return ERR_PTR(rv);
+}
+EXPORT_SYMBOL(usb_cdc_wdm_register);
+
 static void wdm_disconnect(struct usb_interface *intf)
 {
        struct wdm_device *desc;
        unsigned long flags;
 
        usb_deregister_dev(intf, &wdm_class);
+       desc = wdm_find_device(intf);
        mutex_lock(&wdm_mutex);
-       desc = usb_get_intfdata(intf);
 
        /* the spinlock makes sure no new urbs are generated in the callbacks */
        spin_lock_irqsave(&desc->iuspin, flags);
@@ -803,7 +901,7 @@ static void wdm_disconnect(struct usb_interface *intf)
 #ifdef CONFIG_PM
 static int wdm_suspend(struct usb_interface *intf, pm_message_t message)
 {
-       struct wdm_device *desc = usb_get_intfdata(intf);
+       struct wdm_device *desc = wdm_find_device(intf);
        int rv = 0;
 
        dev_dbg(&desc->intf->dev, "wdm%d_suspend\n", intf->minor);
@@ -853,7 +951,7 @@ static int recover_from_urb_loss(struct wdm_device *desc)
 #ifdef CONFIG_PM
 static int wdm_resume(struct usb_interface *intf)
 {
-       struct wdm_device *desc = usb_get_intfdata(intf);
+       struct wdm_device *desc = wdm_find_device(intf);
        int rv;
 
        dev_dbg(&desc->intf->dev, "wdm%d_resume\n", intf->minor);
@@ -867,11 +965,7 @@ static int wdm_resume(struct usb_interface *intf)
 
 static int wdm_pre_reset(struct usb_interface *intf)
 {
-       struct wdm_device *desc = usb_get_intfdata(intf);
-
-       mutex_lock(&desc->rlock);
-       mutex_lock(&desc->wlock);
-       kill_urbs(desc);
+       struct wdm_device *desc = wdm_find_device(intf);
 
        /*
         * we notify everybody using poll of
@@ -880,17 +974,25 @@ static int wdm_pre_reset(struct usb_interface *intf)
         * message from the device is lost
         */
        spin_lock_irq(&desc->iuspin);
+       set_bit(WDM_RESETTING, &desc->flags);   /* inform read/write */
+       set_bit(WDM_READ, &desc->flags);        /* unblock read */
+       clear_bit(WDM_IN_USE, &desc->flags);    /* unblock write */
        desc->rerr = -EINTR;
        spin_unlock_irq(&desc->iuspin);
        wake_up_all(&desc->wait);
+       mutex_lock(&desc->rlock);
+       mutex_lock(&desc->wlock);
+       kill_urbs(desc);
+       cancel_work_sync(&desc->rxwork);
        return 0;
 }
 
 static int wdm_post_reset(struct usb_interface *intf)
 {
-       struct wdm_device *desc = usb_get_intfdata(intf);
+       struct wdm_device *desc = wdm_find_device(intf);
        int rv;
 
+       clear_bit(WDM_RESETTING, &desc->flags);
        rv = recover_from_urb_loss(desc);
        mutex_unlock(&desc->wlock);
        mutex_unlock(&desc->rlock);
index 4fee024..f8e2d6d 100644 (file)
@@ -934,13 +934,8 @@ void usb_rebind_intf(struct usb_interface *intf)
        int rc;
 
        /* Delayed unbind of an existing driver */
-       if (intf->dev.driver) {
-               struct usb_driver *driver =
-                               to_usb_driver(intf->dev.driver);
-
-               dev_dbg(&intf->dev, "forced unbind\n");
-               usb_driver_release_interface(driver, intf);
-       }
+       if (intf->dev.driver)
+               usb_forced_unbind_intf(intf);
 
        /* Try to rebind the interface */
        if (!intf->dev.power.is_prepared) {
@@ -953,15 +948,13 @@ void usb_rebind_intf(struct usb_interface *intf)
 
 #ifdef CONFIG_PM
 
-#define DO_UNBIND      0
-#define DO_REBIND      1
-
-/* Unbind drivers for @udev's interfaces that don't support suspend/resume,
- * or rebind interfaces that have been unbound, according to @action.
+/* Unbind drivers for @udev's interfaces that don't support suspend/resume
+ * There is no check for reset_resume here because it can be determined
+ * only during resume whether reset_resume is needed.
  *
  * The caller must hold @udev's device lock.
  */
-static void do_unbind_rebind(struct usb_device *udev, int action)
+static void unbind_no_pm_drivers_interfaces(struct usb_device *udev)
 {
        struct usb_host_config  *config;
        int                     i;
@@ -972,23 +965,53 @@ static void do_unbind_rebind(struct usb_device *udev, int action)
        if (config) {
                for (i = 0; i < config->desc.bNumInterfaces; ++i) {
                        intf = config->interface[i];
-                       switch (action) {
-                       case DO_UNBIND:
-                               if (intf->dev.driver) {
-                                       drv = to_usb_driver(intf->dev.driver);
-                                       if (!drv->suspend || !drv->resume)
-                                               usb_forced_unbind_intf(intf);
-                               }
-                               break;
-                       case DO_REBIND:
-                               if (intf->needs_binding)
-                                       usb_rebind_intf(intf);
-                               break;
+
+                       if (intf->dev.driver) {
+                               drv = to_usb_driver(intf->dev.driver);
+                               if (!drv->suspend || !drv->resume)
+                                       usb_forced_unbind_intf(intf);
                        }
                }
        }
 }
 
+/* Unbind drivers for @udev's interfaces that failed to support reset-resume.
+ * These interfaces have the needs_binding flag set by usb_resume_interface().
+ *
+ * The caller must hold @udev's device lock.
+ */
+static void unbind_no_reset_resume_drivers_interfaces(struct usb_device *udev)
+{
+       struct usb_host_config  *config;
+       int                     i;
+       struct usb_interface    *intf;
+
+       config = udev->actconfig;
+       if (config) {
+               for (i = 0; i < config->desc.bNumInterfaces; ++i) {
+                       intf = config->interface[i];
+                       if (intf->dev.driver && intf->needs_binding)
+                               usb_forced_unbind_intf(intf);
+               }
+       }
+}
+
+static void do_rebind_interfaces(struct usb_device *udev)
+{
+       struct usb_host_config  *config;
+       int                     i;
+       struct usb_interface    *intf;
+
+       config = udev->actconfig;
+       if (config) {
+               for (i = 0; i < config->desc.bNumInterfaces; ++i) {
+                       intf = config->interface[i];
+                       if (intf->needs_binding)
+                               usb_rebind_intf(intf);
+               }
+       }
+}
+
 static int usb_suspend_device(struct usb_device *udev, pm_message_t msg)
 {
        struct usb_device_driver        *udriver;
@@ -1278,35 +1301,48 @@ int usb_suspend(struct device *dev, pm_message_t msg)
 {
        struct usb_device       *udev = to_usb_device(dev);
 
-       do_unbind_rebind(udev, DO_UNBIND);
+       unbind_no_pm_drivers_interfaces(udev);
+
+       /* From now on we are sure all drivers support suspend/resume
+        * but not necessarily reset_resume()
+        * so we may still need to unbind and rebind upon resume
+        */
        choose_wakeup(udev, msg);
        return usb_suspend_both(udev, msg);
 }
 
 /* The device lock is held by the PM core */
+int usb_resume_complete(struct device *dev)
+{
+       struct usb_device *udev = to_usb_device(dev);
+
+       /* For PM complete calls, all we do is rebind interfaces
+        * whose needs_binding flag is set
+        */
+       if (udev->state != USB_STATE_NOTATTACHED)
+               do_rebind_interfaces(udev);
+       return 0;
+}
+
+/* The device lock is held by the PM core */
 int usb_resume(struct device *dev, pm_message_t msg)
 {
        struct usb_device       *udev = to_usb_device(dev);
        int                     status;
 
-       /* For PM complete calls, all we do is rebind interfaces */
-       if (msg.event == PM_EVENT_ON) {
-               if (udev->state != USB_STATE_NOTATTACHED)
-                       do_unbind_rebind(udev, DO_REBIND);
-               status = 0;
-
-       /* For all other calls, take the device back to full power and
+       /* For all calls, take the device back to full power and
         * tell the PM core in case it was autosuspended previously.
-        * Unbind the interfaces that will need rebinding later.
+        * Unbind the interfaces that will need rebinding later,
+        * because they fail to support reset_resume.
+        * (This can't be done in usb_resume_interface()
+        * above because it doesn't own the right set of locks.)
         */
-       } else {
-               status = usb_resume_both(udev, msg);
-               if (status == 0) {
-                       pm_runtime_disable(dev);
-                       pm_runtime_set_active(dev);
-                       pm_runtime_enable(dev);
-                       do_unbind_rebind(udev, DO_REBIND);
-               }
+       status = usb_resume_both(udev, msg);
+       if (status == 0) {
+               pm_runtime_disable(dev);
+               pm_runtime_set_active(dev);
+               pm_runtime_enable(dev);
+               unbind_no_reset_resume_drivers_interfaces(udev);
        }
 
        /* Avoid PM error messages for devices disconnected while suspended
index 81e2c0d..622b4a4 100644 (file)
@@ -380,6 +380,7 @@ static int check_root_hub_suspended(struct device *dev)
        return 0;
 }
 
+#if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM_RUNTIME)
 static int suspend_common(struct device *dev, bool do_wakeup)
 {
        struct pci_dev          *pci_dev = to_pci_dev(dev);
@@ -471,6 +472,7 @@ static int resume_common(struct device *dev, int event)
        }
        return retval;
 }
+#endif /* SLEEP || RUNTIME */
 
 #ifdef CONFIG_PM_SLEEP
 
index e128232..9d7fc9a 100644 (file)
@@ -2352,7 +2352,7 @@ static int usb_hcd_request_irqs(struct usb_hcd *hcd,
                                        "io mem" : "io base",
                                        (unsigned long long)hcd->rsrc_start);
        } else {
-               hcd->irq = -1;
+               hcd->irq = 0;
                if (hcd->rsrc_start)
                        dev_info(hcd->self.controller, "%s 0x%08llx\n",
                                        (hcd->driver->flags & HCD_MEMORY) ?
@@ -2508,7 +2508,7 @@ err_register_root_hub:
        clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
        del_timer_sync(&hcd->rh_timer);
 err_hcd_driver_start:
-       if (usb_hcd_is_primary_hcd(hcd) && hcd->irq >= 0)
+       if (usb_hcd_is_primary_hcd(hcd) && hcd->irq > 0)
                free_irq(irqnum, hcd);
 err_request_irq:
 err_hcd_driver_setup:
@@ -2573,7 +2573,7 @@ void usb_remove_hcd(struct usb_hcd *hcd)
        del_timer_sync(&hcd->rh_timer);
 
        if (usb_hcd_is_primary_hcd(hcd)) {
-               if (hcd->irq >= 0)
+               if (hcd->irq > 0)
                        free_irq(hcd->irq, hcd);
        }
 
index 265c2f6..28664eb 100644 (file)
@@ -62,6 +62,8 @@ struct usb_hub {
                                                        resumed */
        unsigned long           removed_bits[1]; /* ports with a "removed"
                                                        device present */
+       unsigned long           wakeup_bits[1]; /* ports that have signaled
+                                                       remote wakeup */
 #if USB_MAXCHILDREN > 31 /* 8*sizeof(unsigned long) - 1 */
 #error event_bits[] is too short!
 #endif
@@ -411,6 +413,29 @@ void usb_kick_khubd(struct usb_device *hdev)
                kick_khubd(hub);
 }
 
+/*
+ * Let the USB core know that a USB 3.0 device has sent a Function Wake Device
+ * Notification, which indicates it had initiated remote wakeup.
+ *
+ * USB 3.0 hubs do not report the port link state change from U3 to U0 when the
+ * device initiates resume, so the USB core will not receive notice of the
+ * resume through the normal hub interrupt URB.
+ */
+void usb_wakeup_notification(struct usb_device *hdev,
+               unsigned int portnum)
+{
+       struct usb_hub *hub;
+
+       if (!hdev)
+               return;
+
+       hub = hdev_to_hub(hdev);
+       if (hub) {
+               set_bit(portnum, hub->wakeup_bits);
+               kick_khubd(hub);
+       }
+}
+EXPORT_SYMBOL_GPL(usb_wakeup_notification);
 
 /* completion function, fires on port status changes and various faults */
 static void hub_irq(struct urb *urb)
@@ -823,12 +848,6 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
                        clear_port_feature(hub->hdev, port1,
                                        USB_PORT_FEAT_C_ENABLE);
                }
-               if (portchange & USB_PORT_STAT_C_LINK_STATE) {
-                       need_debounce_delay = true;
-                       clear_port_feature(hub->hdev, port1,
-                                       USB_PORT_FEAT_C_PORT_LINK_STATE);
-               }
-
                if ((portchange & USB_PORT_STAT_C_BH_RESET) &&
                                hub_is_superspeed(hub->hdev)) {
                        need_debounce_delay = true;
@@ -850,12 +869,19 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
                                set_bit(port1, hub->change_bits);
 
                } else if (portstatus & USB_PORT_STAT_ENABLE) {
+                       bool port_resumed = (portstatus &
+                                       USB_PORT_STAT_LINK_STATE) ==
+                               USB_SS_PORT_LS_U0;
                        /* The power session apparently survived the resume.
                         * If there was an overcurrent or suspend change
                         * (i.e., remote wakeup request), have khubd
-                        * take care of it.
+                        * take care of it.  Look at the port link state
+                        * for USB 3.0 hubs, since they don't have a suspend
+                        * change bit, and they don't set the port link change
+                        * bit on device-initiated resume.
                         */
-                       if (portchange)
+                       if (portchange || (hub_is_superspeed(hub->hdev) &&
+                                               port_resumed))
                                set_bit(port1, hub->change_bits);
 
                } else if (udev->persist_enabled) {
@@ -1021,8 +1047,10 @@ static int hub_configure(struct usb_hub *hub,
        dev_info (hub_dev, "%d port%s detected\n", hdev->maxchild,
                (hdev->maxchild == 1) ? "" : "s");
 
+       hdev->children = kzalloc(hdev->maxchild *
+                               sizeof(struct usb_device *), GFP_KERNEL);
        hub->port_owners = kzalloc(hdev->maxchild * sizeof(void *), GFP_KERNEL);
-       if (!hub->port_owners) {
+       if (!hdev->children || !hub->port_owners) {
                ret = -ENOMEM;
                goto fail;
        }
@@ -1253,7 +1281,8 @@ static unsigned highspeed_hubs;
 
 static void hub_disconnect(struct usb_interface *intf)
 {
-       struct usb_hub *hub = usb_get_intfdata (intf);
+       struct usb_hub *hub = usb_get_intfdata(intf);
+       struct usb_device *hdev = interface_to_usbdev(intf);
 
        /* Take the hub off the event list and don't let it be added again */
        spin_lock_irq(&hub_event_lock);
@@ -1275,6 +1304,7 @@ static void hub_disconnect(struct usb_interface *intf)
                highspeed_hubs--;
 
        usb_free_urb(hub->urb);
+       kfree(hdev->children);
        kfree(hub->port_owners);
        kfree(hub->descriptor);
        kfree(hub->status);
@@ -1293,14 +1323,8 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
        desc = intf->cur_altsetting;
        hdev = interface_to_usbdev(intf);
 
-       /* Hubs have proper suspend/resume support.  USB 3.0 device suspend is
-        * different from USB 2.0/1.1 device suspend, and unfortunately we
-        * don't support it yet.  So leave autosuspend disabled for USB 3.0
-        * external hubs for now.  Enable autosuspend for USB 3.0 roothubs,
-        * since that isn't a "real" hub.
-        */
-       if (!hub_is_superspeed(hdev) || !hdev->parent)
-               usb_enable_autosuspend(hdev);
+       /* Hubs have proper suspend/resume support. */
+       usb_enable_autosuspend(hdev);
 
        if (hdev->level == MAX_TOPO_LEVEL) {
                dev_err(&intf->dev,
@@ -1656,7 +1680,7 @@ void usb_disconnect(struct usb_device **pdev)
        usb_lock_device(udev);
 
        /* Free up all the children before we remove this device */
-       for (i = 0; i < USB_MAXCHILDREN; i++) {
+       for (i = 0; i < udev->maxchild; i++) {
                if (udev->children[i])
                        usb_disconnect(&udev->children[i]);
        }
@@ -1842,6 +1866,37 @@ fail:
        return err;
 }
 
+static void set_usb_port_removable(struct usb_device *udev)
+{
+       struct usb_device *hdev = udev->parent;
+       struct usb_hub *hub;
+       u8 port = udev->portnum;
+       u16 wHubCharacteristics;
+       bool removable = true;
+
+       if (!hdev)
+               return;
+
+       hub = hdev_to_hub(udev->parent);
+
+       wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
+
+       if (!(wHubCharacteristics & HUB_CHAR_COMPOUND))
+               return;
+
+       if (hub_is_superspeed(hdev)) {
+               if (hub->descriptor->u.ss.DeviceRemovable & (1 << port))
+                       removable = false;
+       } else {
+               if (hub->descriptor->u.hs.DeviceRemovable[port / 8] & (1 << (port % 8)))
+                       removable = false;
+       }
+
+       if (removable)
+               udev->removable = USB_DEVICE_REMOVABLE;
+       else
+               udev->removable = USB_DEVICE_FIXED;
+}
 
 /**
  * usb_new_device - perform initial device setup (usbcore-internal)
@@ -1900,6 +1955,15 @@ int usb_new_device(struct usb_device *udev)
        announce_device(udev);
 
        device_enable_async_suspend(&udev->dev);
+
+       /*
+        * check whether the hub marks this port as non-removable. Do it
+        * now so that platform-specific data can override it in
+        * device_add()
+        */
+       if (udev->parent)
+               set_usb_port_removable(udev);
+
        /* Register the device.  The device driver is responsible
         * for configuring the device and invoking the add-device
         * notifier chain (used by usbfs and possibly others).
@@ -2385,11 +2449,27 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
         * we don't explicitly enable it here.
         */
        if (udev->do_remote_wakeup) {
-               status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
-                               USB_REQ_SET_FEATURE, USB_RECIP_DEVICE,
-                               USB_DEVICE_REMOTE_WAKEUP, 0,
-                               NULL, 0,
-                               USB_CTRL_SET_TIMEOUT);
+               if (!hub_is_superspeed(hub->hdev)) {
+                       status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+                                       USB_REQ_SET_FEATURE, USB_RECIP_DEVICE,
+                                       USB_DEVICE_REMOTE_WAKEUP, 0,
+                                       NULL, 0,
+                                       USB_CTRL_SET_TIMEOUT);
+               } else {
+                       /* Assume there's only one function on the USB 3.0
+                        * device and enable remote wake for the first
+                        * interface. FIXME if the interface association
+                        * descriptor shows there's more than one function.
+                        */
+                       status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+                                       USB_REQ_SET_FEATURE,
+                                       USB_RECIP_INTERFACE,
+                                       USB_INTRF_FUNC_SUSPEND,
+                                       USB_INTRF_FUNC_SUSPEND_RW |
+                                       USB_INTRF_FUNC_SUSPEND_LP,
+                                       NULL, 0,
+                                       USB_CTRL_SET_TIMEOUT);
+               }
                if (status) {
                        dev_dbg(&udev->dev, "won't remote wakeup, status %d\n",
                                        status);
@@ -2679,6 +2759,7 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
        struct usb_hub          *hub = usb_get_intfdata (intf);
        struct usb_device       *hdev = hub->hdev;
        unsigned                port1;
+       int                     status;
 
        /* Warn if children aren't already suspended */
        for (port1 = 1; port1 <= hdev->maxchild; port1++) {
@@ -2691,6 +2772,17 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
                                return -EBUSY;
                }
        }
+       if (hub_is_superspeed(hdev) && hdev->do_remote_wakeup) {
+               /* Enable hub to send remote wakeup for all ports. */
+               for (port1 = 1; port1 <= hdev->maxchild; port1++) {
+                       status = set_port_feature(hdev,
+                                       port1 |
+                                       USB_PORT_FEAT_REMOTE_WAKE_CONNECT |
+                                       USB_PORT_FEAT_REMOTE_WAKE_DISCONNECT |
+                                       USB_PORT_FEAT_REMOTE_WAKE_OVER_CURRENT,
+                                       USB_PORT_FEAT_REMOTE_WAKE_MASK);
+               }
+       }
 
        dev_dbg(&intf->dev, "%s\n", __func__);
 
@@ -3424,6 +3516,46 @@ done:
                hcd->driver->relinquish_port(hcd, port1);
 }
 
+/* Returns 1 if there was a remote wakeup and a connect status change. */
+static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port,
+               u16 portstatus, u16 portchange)
+{
+       struct usb_device *hdev;
+       struct usb_device *udev;
+       int connect_change = 0;
+       int ret;
+
+       hdev = hub->hdev;
+       udev = hdev->children[port-1];
+       if (!hub_is_superspeed(hdev)) {
+               if (!(portchange & USB_PORT_STAT_C_SUSPEND))
+                       return 0;
+               clear_port_feature(hdev, port, USB_PORT_FEAT_C_SUSPEND);
+       } else {
+               if (!udev || udev->state != USB_STATE_SUSPENDED ||
+                                (portstatus & USB_PORT_STAT_LINK_STATE) !=
+                                USB_SS_PORT_LS_U0)
+                       return 0;
+       }
+
+       if (udev) {
+               /* TRSMRCY = 10 msec */
+               msleep(10);
+
+               usb_lock_device(udev);
+               ret = usb_remote_wakeup(udev);
+               usb_unlock_device(udev);
+               if (ret < 0)
+                       connect_change = 1;
+       } else {
+               ret = -ENODEV;
+               hub_port_disable(hub, port, 1);
+       }
+       dev_dbg(hub->intfdev, "resume on port %d, status %d\n",
+                       port, ret);
+       return connect_change;
+}
+
 static void hub_events(void)
 {
        struct list_head *tmp;
@@ -3436,7 +3568,7 @@ static void hub_events(void)
        u16 portstatus;
        u16 portchange;
        int i, ret;
-       int connect_change;
+       int connect_change, wakeup_change;
 
        /*
         *  We restart the list every time to avoid a deadlock with
@@ -3515,8 +3647,9 @@ static void hub_events(void)
                        if (test_bit(i, hub->busy_bits))
                                continue;
                        connect_change = test_bit(i, hub->change_bits);
+                       wakeup_change = test_and_clear_bit(i, hub->wakeup_bits);
                        if (!test_and_clear_bit(i, hub->event_bits) &&
-                                       !connect_change)
+                                       !connect_change && !wakeup_change)
                                continue;
 
                        ret = hub_port_status(hub, i,
@@ -3557,31 +3690,10 @@ static void hub_events(void)
                                }
                        }
 
-                       if (portchange & USB_PORT_STAT_C_SUSPEND) {
-                               struct usb_device *udev;
+                       if (hub_handle_remote_wakeup(hub, i,
+                                               portstatus, portchange))
+                               connect_change = 1;
 
-                               clear_port_feature(hdev, i,
-                                       USB_PORT_FEAT_C_SUSPEND);
-                               udev = hdev->children[i-1];
-                               if (udev) {
-                                       /* TRSMRCY = 10 msec */
-                                       msleep(10);
-
-                                       usb_lock_device(udev);
-                                       ret = usb_remote_wakeup(hdev->
-                                                       children[i-1]);
-                                       usb_unlock_device(udev);
-                                       if (ret < 0)
-                                               connect_change = 1;
-                               } else {
-                                       ret = -ENODEV;
-                                       hub_port_disable(hub, i, 1);
-                               }
-                               dev_dbg (hub_dev,
-                                       "resume on port %d, status %d\n",
-                                       i, ret);
-                       }
-                       
                        if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
                                u16 status = 0;
                                u16 unused;
index 9e491ca..566d9f9 100644 (file)
@@ -230,6 +230,28 @@ show_urbnum(struct device *dev, struct device_attribute *attr, char *buf)
 }
 static DEVICE_ATTR(urbnum, S_IRUGO, show_urbnum, NULL);
 
+static ssize_t
+show_removable(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct usb_device *udev;
+       char *state;
+
+       udev = to_usb_device(dev);
+
+       switch (udev->removable) {
+       case USB_DEVICE_REMOVABLE:
+               state = "removable";
+               break;
+       case USB_DEVICE_FIXED:
+               state = "fixed";
+               break;
+       default:
+               state = "unknown";
+       }
+
+       return sprintf(buf, "%s\n", state);
+}
+static DEVICE_ATTR(removable, S_IRUGO, show_removable, NULL);
 
 #ifdef CONFIG_PM
 
@@ -626,6 +648,7 @@ static struct attribute *dev_attrs[] = {
        &dev_attr_avoid_reset_quirk.attr,
        &dev_attr_authorized.attr,
        &dev_attr_remove.attr,
+       &dev_attr_removable.attr,
        NULL,
 };
 static struct attribute_group dev_attr_grp = {
index 909625b..7239a73 100644 (file)
@@ -403,20 +403,17 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
         * cause problems in HCDs if they get it wrong.
         */
        {
-       unsigned int    orig_flags = urb->transfer_flags;
        unsigned int    allowed;
        static int pipetypes[4] = {
                PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT
        };
 
        /* Check that the pipe's type matches the endpoint's type */
-       if (usb_pipetype(urb->pipe) != pipetypes[xfertype]) {
-               dev_err(&dev->dev, "BOGUS urb xfer, pipe %x != type %x\n",
+       if (usb_pipetype(urb->pipe) != pipetypes[xfertype])
+               dev_WARN(&dev->dev, "BOGUS urb xfer, pipe %x != type %x\n",
                        usb_pipetype(urb->pipe), pipetypes[xfertype]);
-               return -EPIPE;          /* The most suitable error code :-) */
-       }
 
-       /* enforce simple/standard policy */
+       /* Check against a simple/standard policy */
        allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT | URB_DIR_MASK |
                        URB_FREE_BUFFER);
        switch (xfertype) {
@@ -435,14 +432,12 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
                allowed |= URB_ISO_ASAP;
                break;
        }
-       urb->transfer_flags &= allowed;
+       allowed &= urb->transfer_flags;
 
-       /* fail if submitter gave bogus flags */
-       if (urb->transfer_flags != orig_flags) {
-               dev_err(&dev->dev, "BOGUS urb flags, %x --> %x\n",
-                       orig_flags, urb->transfer_flags);
-               return -EINVAL;
-       }
+       /* warn if submitter gave bogus flags */
+       if (allowed != urb->transfer_flags)
+               dev_WARN(&dev->dev, "BOGUS urb flags, %x --> %x\n",
+                       urb->transfer_flags, allowed);
        }
 #endif
        /*
@@ -532,10 +527,13 @@ EXPORT_SYMBOL_GPL(usb_submit_urb);
  * a driver's I/O routines to insure that all URB-related activity has
  * completed before it returns.
  *
- * This request is always asynchronous.  Success is indicated by
- * returning -EINPROGRESS, at which time the URB will probably not yet
- * have been given back to the device driver.  When it is eventually
- * called, the completion function will see @urb->status == -ECONNRESET.
+ * This request is asynchronous, however the HCD might call the ->complete()
+ * callback during unlink. Therefore when drivers call usb_unlink_urb(), they
+ * must not hold any locks that may be taken by the completion function.
+ * Success is indicated by returning -EINPROGRESS, at which time the URB will
+ * probably not yet have been given back to the device driver. When it is
+ * eventually called, the completion function will see @urb->status ==
+ * -ECONNRESET.
  * Failure is indicated by usb_unlink_urb() returning any other value.
  * Unlinking will fail when @urb is not currently "linked" (i.e., it was
  * never submitted, or it was unlinked before, or the hardware is already
index 8ca9f99..c74ba7b 100644 (file)
@@ -274,7 +274,7 @@ static int usb_dev_prepare(struct device *dev)
 static void usb_dev_complete(struct device *dev)
 {
        /* Currently used only for rebinding interfaces */
-       usb_resume(dev, PMSG_ON);       /* FIXME: change to PMSG_COMPLETE */
+       usb_resume_complete(dev);
 }
 
 static int usb_dev_suspend(struct device *dev)
index 45e8479..71648dc 100644 (file)
@@ -56,6 +56,7 @@ extern void usb_major_cleanup(void);
 
 extern int usb_suspend(struct device *dev, pm_message_t msg);
 extern int usb_resume(struct device *dev, pm_message_t msg);
+extern int usb_resume_complete(struct device *dev);
 
 extern int usb_port_suspend(struct usb_device *dev, pm_message_t msg);
 extern int usb_port_resume(struct usb_device *dev, pm_message_t msg);
index 900ae74..d441fe4 100644 (file)
@@ -28,6 +28,19 @@ endif
 
 obj-$(CONFIG_USB_DWC3)         += dwc3-omap.o
 
+##
+# REVISIT Samsung Exynos platform needs the clk API which isn't
+# defined on all architectures. If we allow dwc3-exynos.c compile
+# always we will fail the linking phase on those architectures
+# which don't provide clk api implementation and that's unnaceptable.
+#
+# When Samsung's platform start supporting pm_runtime, this check
+# for HAVE_CLK should be removed.
+##
+ifneq ($(CONFIG_HAVE_CLK),)
+       obj-$(CONFIG_USB_DWC3)          += dwc3-exynos.o
+endif
+
 ifneq ($(CONFIG_PCI),)
        obj-$(CONFIG_USB_DWC3)          += dwc3-pci.o
 endif
index 7c9df63..7bd815a 100644 (file)
 #include <linux/list.h>
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
+#include <linux/of.h>
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
-#include <linux/module.h>
 
 #include "core.h"
 #include "gadget.h"
@@ -86,7 +86,7 @@ again:
                id = -ENOMEM;
        }
 
-       return 0;
+       return id;
 }
 EXPORT_SYMBOL_GPL(dwc3_get_device_id);
 
@@ -167,11 +167,11 @@ static void dwc3_free_one_event_buffer(struct dwc3 *dwc,
 }
 
 /**
- * dwc3_alloc_one_event_buffer - Allocated one event buffer structure
+ * dwc3_alloc_one_event_buffer - Allocates one event buffer structure
  * @dwc: Pointer to our controller context structure
  * @length: size of the event buffer
  *
- * Returns a pointer to the allocated event buffer structure on succes
+ * Returns a pointer to the allocated event buffer structure on success
  * otherwise ERR_PTR(errno).
  */
 static struct dwc3_event_buffer *__devinit
@@ -215,10 +215,10 @@ static void dwc3_free_event_buffers(struct dwc3 *dwc)
 
 /**
  * dwc3_alloc_event_buffers - Allocates @num event buffers of size @length
- * @dwc: Pointer to out controller context structure
+ * @dwc: pointer to our controller context structure
  * @length: size of event buffer
  *
- * Returns 0 on success otherwise negative errno. In error the case, dwc
+ * Returns 0 on success otherwise negative errno. In the error case, dwc
  * may contain some buffers allocated but not all which were requested.
  */
 static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
@@ -251,7 +251,7 @@ static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
 
 /**
  * dwc3_event_buffers_setup - setup our allocated event buffers
- * @dwc: Pointer to out controller context structure
+ * @dwc: pointer to our controller context structure
  *
  * Returns 0 on success otherwise negative errno.
  */
@@ -350,7 +350,7 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc)
        dwc3_cache_hwparams(dwc);
 
        reg = dwc3_readl(dwc->regs, DWC3_GCTL);
-       reg &= ~DWC3_GCTL_SCALEDOWN(3);
+       reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
        reg &= ~DWC3_GCTL_DISSCRAMBLE;
 
        switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) {
@@ -363,9 +363,9 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc)
 
        /*
         * WORKAROUND: DWC3 revisions <1.90a have a bug
-        * when The device fails to connect at SuperSpeed
+        * where the device can fail to connect at SuperSpeed
         * and falls back to high-speed mode which causes
-        * the device to enter in a Connect/Disconnect loop
+        * the device to enter a Connect/Disconnect loop
         */
        if (dwc->revision < DWC3_REVISION_190A)
                reg |= DWC3_GCTL_U2RSTECN;
@@ -404,8 +404,10 @@ static void dwc3_core_exit(struct dwc3 *dwc)
 
 static int __devinit dwc3_probe(struct platform_device *pdev)
 {
+       struct device_node      *node = pdev->dev.of_node;
        struct resource         *res;
        struct dwc3             *dwc;
+       struct device           *dev = &pdev->dev;
 
        int                     ret = -ENOMEM;
        int                     irq;
@@ -415,39 +417,39 @@ static int __devinit dwc3_probe(struct platform_device *pdev)
 
        u8                      mode;
 
-       mem = kzalloc(sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
+       mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
        if (!mem) {
-               dev_err(&pdev->dev, "not enough memory\n");
-               goto err0;
+               dev_err(dev, "not enough memory\n");
+               return -ENOMEM;
        }
        dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1);
        dwc->mem = mem;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res) {
-               dev_err(&pdev->dev, "missing resource\n");
-               goto err1;
+               dev_err(dev, "missing resource\n");
+               return -ENODEV;
        }
 
        dwc->res = res;
 
-       res = request_mem_region(res->start, resource_size(res),
-                       dev_name(&pdev->dev));
+       res = devm_request_mem_region(dev, res->start, resource_size(res),
+                       dev_name(dev));
        if (!res) {
-               dev_err(&pdev->dev, "can't request mem region\n");
-               goto err1;
+               dev_err(dev, "can't request mem region\n");
+               return -ENOMEM;
        }
 
-       regs = ioremap(res->start, resource_size(res));
+       regs = devm_ioremap(dev, res->start, resource_size(res));
        if (!regs) {
-               dev_err(&pdev->dev, "ioremap failed\n");
-               goto err2;
+               dev_err(dev, "ioremap failed\n");
+               return -ENOMEM;
        }
 
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
-               dev_err(&pdev->dev, "missing IRQ\n");
-               goto err3;
+               dev_err(dev, "missing IRQ\n");
+               return -ENODEV;
        }
 
        spin_lock_init(&dwc->lock);
@@ -455,7 +457,7 @@ static int __devinit dwc3_probe(struct platform_device *pdev)
 
        dwc->regs       = regs;
        dwc->regs_size  = resource_size(res);
-       dwc->dev        = &pdev->dev;
+       dwc->dev        = dev;
        dwc->irq        = irq;
 
        if (!strncmp("super", maximum_speed, 5))
@@ -469,14 +471,17 @@ static int __devinit dwc3_probe(struct platform_device *pdev)
        else
                dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;
 
-       pm_runtime_enable(&pdev->dev);
-       pm_runtime_get_sync(&pdev->dev);
-       pm_runtime_forbid(&pdev->dev);
+       if (of_get_property(node, "tx-fifo-resize", NULL))
+               dwc->needs_fifo_resize = true;
+
+       pm_runtime_enable(dev);
+       pm_runtime_get_sync(dev);
+       pm_runtime_forbid(dev);
 
        ret = dwc3_core_init(dwc);
        if (ret) {
-               dev_err(&pdev->dev, "failed to initialize core\n");
-               goto err3;
+               dev_err(dev, "failed to initialize core\n");
+               return ret;
        }
 
        mode = DWC3_MODE(dwc->hwparams.hwparams0);
@@ -486,49 +491,49 @@ static int __devinit dwc3_probe(struct platform_device *pdev)
                dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
                ret = dwc3_gadget_init(dwc);
                if (ret) {
-                       dev_err(&pdev->dev, "failed to initialize gadget\n");
-                       goto err4;
+                       dev_err(dev, "failed to initialize gadget\n");
+                       goto err1;
                }
                break;
        case DWC3_MODE_HOST:
                dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
                ret = dwc3_host_init(dwc);
                if (ret) {
-                       dev_err(&pdev->dev, "failed to initialize host\n");
-                       goto err4;
+                       dev_err(dev, "failed to initialize host\n");
+                       goto err1;
                }
                break;
        case DWC3_MODE_DRD:
                dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
                ret = dwc3_host_init(dwc);
                if (ret) {
-                       dev_err(&pdev->dev, "failed to initialize host\n");
-                       goto err4;
+                       dev_err(dev, "failed to initialize host\n");
+                       goto err1;
                }
 
                ret = dwc3_gadget_init(dwc);
                if (ret) {
-                       dev_err(&pdev->dev, "failed to initialize gadget\n");
-                       goto err4;
+                       dev_err(dev, "failed to initialize gadget\n");
+                       goto err1;
                }
                break;
        default:
-               dev_err(&pdev->dev, "Unsupported mode of operation %d\n", mode);
-               goto err4;
+               dev_err(dev, "Unsupported mode of operation %d\n", mode);
+               goto err1;
        }
        dwc->mode = mode;
 
        ret = dwc3_debugfs_init(dwc);
        if (ret) {
-               dev_err(&pdev->dev, "failed to initialize debugfs\n");
-               goto err5;
+               dev_err(dev, "failed to initialize debugfs\n");
+               goto err2;
        }
 
-       pm_runtime_allow(&pdev->dev);
+       pm_runtime_allow(dev);
 
        return 0;
 
-err5:
+err2:
        switch (mode) {
        case DWC3_MODE_DEVICE:
                dwc3_gadget_exit(dwc);
@@ -545,19 +550,9 @@ err5:
                break;
        }
 
-err4:
-       dwc3_core_exit(dwc);
-
-err3:
-       iounmap(regs);
-
-err2:
-       release_mem_region(res->start, resource_size(res));
-
 err1:
-       kfree(dwc->mem);
+       dwc3_core_exit(dwc);
 
-err0:
        return ret;
 }
 
@@ -590,9 +585,6 @@ static int __devexit dwc3_remove(struct platform_device *pdev)
        }
 
        dwc3_core_exit(dwc);
-       release_mem_region(res->start, resource_size(res));
-       iounmap(dwc->regs);
-       kfree(dwc->mem);
 
        return 0;
 }
@@ -605,19 +597,9 @@ static struct platform_driver dwc3_driver = {
        },
 };
 
+module_platform_driver(dwc3_driver);
+
 MODULE_ALIAS("platform:dwc3");
 MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver");
-
-static int __devinit dwc3_init(void)
-{
-       return platform_driver_register(&dwc3_driver);
-}
-module_init(dwc3_init);
-
-static void __exit dwc3_exit(void)
-{
-       platform_driver_unregister(&dwc3_driver);
-}
-module_exit(dwc3_exit);
index 9e57f8e..6c7945b 100644 (file)
 /* Bit fields */
 
 /* Global Configuration Register */
-#define DWC3_GCTL_PWRDNSCALE(n)        (n << 19)
+#define DWC3_GCTL_PWRDNSCALE(n)        ((n) << 19)
 #define DWC3_GCTL_U2RSTECN     (1 << 16)
-#define DWC3_GCTL_RAMCLKSEL(x) ((x & DWC3_GCTL_CLK_MASK) << 6)
+#define DWC3_GCTL_RAMCLKSEL(x) (((x) & DWC3_GCTL_CLK_MASK) << 6)
 #define DWC3_GCTL_CLK_BUS      (0)
 #define DWC3_GCTL_CLK_PIPE     (1)
 #define DWC3_GCTL_CLK_PIPEHALF (2)
 #define DWC3_GCTL_CLK_MASK     (3)
 
 #define DWC3_GCTL_PRTCAP(n)    (((n) & (3 << 12)) >> 12)
-#define DWC3_GCTL_PRTCAPDIR(n) (n << 12)
+#define DWC3_GCTL_PRTCAPDIR(n) ((n) << 12)
 #define DWC3_GCTL_PRTCAP_HOST  1
 #define DWC3_GCTL_PRTCAP_DEVICE        2
 #define DWC3_GCTL_PRTCAP_OTG   3
 
 #define DWC3_GCTL_CORESOFTRESET        (1 << 11)
-#define DWC3_GCTL_SCALEDOWN(n) (n << 4)
+#define DWC3_GCTL_SCALEDOWN(n) ((n) << 4)
+#define DWC3_GCTL_SCALEDOWN_MASK DWC3_GCTL_SCALEDOWN(3)
 #define DWC3_GCTL_DISSCRAMBLE  (1 << 3)
 #define DWC3_GCTL_DSBLCLKGTNG  (1 << 0)
 
 #define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31)
 #define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17)
 
+/* Global TX Fifo Size Register */
+#define DWC3_GTXFIFOSIZ_TXFDEF(n) ((n) & 0xffff)
+#define DWC3_GTXFIFOSIZ_TXFSTADDR(n) ((n) & 0xffff0000)
+
 /* Global HWPARAMS1 Register */
-#define DWC3_GHWPARAMS1_EN_PWROPT(n)   ((n & (3 << 24)) >> 24)
+#define DWC3_GHWPARAMS1_EN_PWROPT(n)   (((n) & (3 << 24)) >> 24)
 #define DWC3_GHWPARAMS1_EN_PWROPT_NO   0
 #define DWC3_GHWPARAMS1_EN_PWROPT_CLK  1
 
 
 #define DWC3_DCTL_APPL1RES     (1 << 23)
 
+#define DWC3_DCTL_TRGTULST_MASK        (0x0f << 17)
+#define DWC3_DCTL_TRGTULST(n)  ((n) << 17)
+
+#define DWC3_DCTL_TRGTULST_U2  (DWC3_DCTL_TRGTULST(2))
+#define DWC3_DCTL_TRGTULST_U3  (DWC3_DCTL_TRGTULST(3))
+#define DWC3_DCTL_TRGTULST_SS_DIS (DWC3_DCTL_TRGTULST(4))
+#define DWC3_DCTL_TRGTULST_RX_DET (DWC3_DCTL_TRGTULST(5))
+#define DWC3_DCTL_TRGTULST_SS_INACT (DWC3_DCTL_TRGTULST(6))
+
 #define DWC3_DCTL_INITU2ENA    (1 << 12)
 #define DWC3_DCTL_ACCEPTU2ENA  (1 << 11)
 #define DWC3_DCTL_INITU1ENA    (1 << 10)
 
 /* Device Endpoint Command Register */
 #define DWC3_DEPCMD_PARAM_SHIFT                16
-#define DWC3_DEPCMD_PARAM(x)           (x << DWC3_DEPCMD_PARAM_SHIFT)
-#define DWC3_DEPCMD_GET_RSC_IDX(x)     ((x >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f)
+#define DWC3_DEPCMD_PARAM(x)           ((x) << DWC3_DEPCMD_PARAM_SHIFT)
+#define DWC3_DEPCMD_GET_RSC_IDX(x)     (((x) >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f)
 #define DWC3_DEPCMD_STATUS_MASK                (0x0f << 12)
-#define DWC3_DEPCMD_STATUS(x)          ((x & DWC3_DEPCMD_STATUS_MASK) >> 12)
+#define DWC3_DEPCMD_STATUS(x)          (((x) & DWC3_DEPCMD_STATUS_MASK) >> 12)
 #define DWC3_DEPCMD_HIPRI_FORCERM      (1 << 11)
 #define DWC3_DEPCMD_CMDACT             (1 << 10)
 #define DWC3_DEPCMD_CMDIOC             (1 << 8)
 
 /* Structures */
 
-struct dwc3_trb_hw;
+struct dwc3_trb;
 
 /**
  * struct dwc3_event_buffer - Software event buffer representation
@@ -343,7 +357,7 @@ struct dwc3_ep {
        struct list_head        request_list;
        struct list_head        req_queued;
 
-       struct dwc3_trb_hw      *trb_pool;
+       struct dwc3_trb         *trb_pool;
        dma_addr_t              trb_pool_dma;
        u32                     free_slot;
        u32                     busy_slot;
@@ -418,102 +432,49 @@ enum dwc3_device_state {
        DWC3_CONFIGURED_STATE,
 };
 
-/**
- * struct dwc3_trb - transfer request block
- * @bpl: lower 32bit of the buffer
- * @bph: higher 32bit of the buffer
- * @length: buffer size (up to 16mb - 1)
- * @pcm1: packet count m1
- * @trbsts: trb status
- *     0 = ok
- *     1 = missed isoc
- *     2 = setup pending
- * @hwo: hardware owner of descriptor
- * @lst: last trb
- * @chn: chain buffers
- * @csp: continue on short packets (only supported on isoc eps)
- * @trbctl: trb control
- *     1 = normal
- *     2 = control-setup
- *     3 = control-status-2
- *     4 = control-status-3
- *     5 = control-data (first trb of data stage)
- *     6 = isochronous-first (first trb of service interval)
- *     7 = isochronous
- *     8 = link trb
- *     others = reserved
- * @isp_imi: interrupt on short packet / interrupt on missed isoc
- * @ioc: interrupt on complete
- * @sid_sofn: Stream ID / SOF Number
- */
-struct dwc3_trb {
-       u64             bplh;
-
-       union {
-               struct {
-                       u32             length:24;
-                       u32             pcm1:2;
-                       u32             reserved27_26:2;
-                       u32             trbsts:4;
-#define DWC3_TRB_STS_OKAY                       0
-#define DWC3_TRB_STS_MISSED_ISOC                1
-#define DWC3_TRB_STS_SETUP_PENDING              2
-               };
-               u32 len_pcm;
-       };
-
-       union {
-               struct {
-                       u32             hwo:1;
-                       u32             lst:1;
-                       u32             chn:1;
-                       u32             csp:1;
-                       u32             trbctl:6;
-                       u32             isp_imi:1;
-                       u32             ioc:1;
-                       u32             reserved13_12:2;
-                       u32             sid_sofn:16;
-                       u32             reserved31_30:2;
-               };
-               u32 control;
-       };
-} __packed;
+/* TRB Length, PCM and Status */
+#define DWC3_TRB_SIZE_MASK     (0x00ffffff)
+#define DWC3_TRB_SIZE_LENGTH(n)        ((n) & DWC3_TRB_SIZE_MASK)
+#define DWC3_TRB_SIZE_PCM1(n)  (((n) & 0x03) << 24)
+#define DWC3_TRB_SIZE_TRBSTS(n)        (((n) & (0x0f << 28) >> 28))
+
+#define DWC3_TRBSTS_OK                 0
+#define DWC3_TRBSTS_MISSED_ISOC                1
+#define DWC3_TRBSTS_SETUP_PENDING      2
+
+/* TRB Control */
+#define DWC3_TRB_CTRL_HWO              (1 << 0)
+#define DWC3_TRB_CTRL_LST              (1 << 1)
+#define DWC3_TRB_CTRL_CHN              (1 << 2)
+#define DWC3_TRB_CTRL_CSP              (1 << 3)
+#define DWC3_TRB_CTRL_TRBCTL(n)                (((n) & 0x3f) << 4)
+#define DWC3_TRB_CTRL_ISP_IMI          (1 << 10)
+#define DWC3_TRB_CTRL_IOC              (1 << 11)
+#define DWC3_TRB_CTRL_SID_SOFN(n)      (((n) & 0xffff) << 14)
+
+#define DWC3_TRBCTL_NORMAL             DWC3_TRB_CTRL_TRBCTL(1)
+#define DWC3_TRBCTL_CONTROL_SETUP      DWC3_TRB_CTRL_TRBCTL(2)
+#define DWC3_TRBCTL_CONTROL_STATUS2    DWC3_TRB_CTRL_TRBCTL(3)
+#define DWC3_TRBCTL_CONTROL_STATUS3    DWC3_TRB_CTRL_TRBCTL(4)
+#define DWC3_TRBCTL_CONTROL_DATA       DWC3_TRB_CTRL_TRBCTL(5)
+#define DWC3_TRBCTL_ISOCHRONOUS_FIRST  DWC3_TRB_CTRL_TRBCTL(6)
+#define DWC3_TRBCTL_ISOCHRONOUS                DWC3_TRB_CTRL_TRBCTL(7)
+#define DWC3_TRBCTL_LINK_TRB           DWC3_TRB_CTRL_TRBCTL(8)
 
 /**
- * struct dwc3_trb_hw - transfer request block (hw format)
+ * struct dwc3_trb - transfer request block (hw format)
  * @bpl: DW0-3
  * @bph: DW4-7
  * @size: DW8-B
  * @trl: DWC-F
  */
-struct dwc3_trb_hw {
-       __le32          bpl;
-       __le32          bph;
-       __le32          size;
-       __le32          ctrl;
+struct dwc3_trb {
+       u32             bpl;
+       u32             bph;
+       u32             size;
+       u32             ctrl;
 } __packed;
 
-static inline void dwc3_trb_to_hw(struct dwc3_trb *nat, struct dwc3_trb_hw *hw)
-{
-       hw->bpl = cpu_to_le32(lower_32_bits(nat->bplh));
-       hw->bph = cpu_to_le32(upper_32_bits(nat->bplh));
-       hw->size = cpu_to_le32p(&nat->len_pcm);
-       /* HWO is written last */
-       hw->ctrl = cpu_to_le32p(&nat->control);
-}
-
-static inline void dwc3_trb_to_nat(struct dwc3_trb_hw *hw, struct dwc3_trb *nat)
-{
-       u64 bplh;
-
-       bplh = le32_to_cpup(&hw->bpl);
-       bplh |= (u64) le32_to_cpup(&hw->bph) << 32;
-       nat->bplh = bplh;
-
-       nat->len_pcm = le32_to_cpup(&hw->size);
-       nat->control = le32_to_cpup(&hw->ctrl);
-}
-
 /**
  * dwc3_hwparams - copy of HWPARAMS registers
  * @hwparams0 - GHWPARAMS0
@@ -546,8 +507,13 @@ struct dwc3_hwparams {
 #define DWC3_MODE_DRD          2
 #define DWC3_MODE_HUB          3
 
+#define DWC3_MDWIDTH(n)                (((n) & 0xff00) >> 8)
+
 /* HWPARAMS1 */
-#define DWC3_NUM_INT(n)        (((n) & (0x3f << 15)) >> 15)
+#define DWC3_NUM_INT(n)                (((n) & (0x3f << 15)) >> 15)
+
+/* HWPARAMS7 */
+#define DWC3_RAM1_DEPTH(n)     ((n) & 0xffff)
 
 struct dwc3_request {
        struct usb_request      request;
@@ -555,7 +521,7 @@ struct dwc3_request {
        struct dwc3_ep          *dep;
 
        u8                      epnum;
-       struct dwc3_trb_hw      *trb;
+       struct dwc3_trb         *trb;
        dma_addr_t              trb_dma;
 
        unsigned                direction:1;
@@ -572,7 +538,6 @@ struct dwc3_request {
  * @ctrl_req_addr: dma address of ctrl_req
  * @ep0_trb: dma address of ep0_trb
  * @ep0_usb_req: dummy req used while handling STD USB requests
- * @setup_buf_addr: dma address of setup_buf
  * @ep0_bounce_addr: dma address of ep0_bounce
  * @lock: for synchronizing
  * @dev: pointer to our struct device
@@ -594,6 +559,8 @@ struct dwc3_request {
  * @ep0_expect_in: true when we expect a DATA IN transfer
  * @start_config_issued: true when StartConfig command has been issued
  * @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround
+ * @needs_fifo_resize: not all users might want fifo resizing, flag it
+ * @resize_fifos: tells us it's ok to reconfigure our TxFIFO sizes.
  * @ep0_next_event: hold the next expected event
  * @ep0state: state of endpoint zero
  * @link_state: link state
@@ -604,12 +571,11 @@ struct dwc3_request {
  */
 struct dwc3 {
        struct usb_ctrlrequest  *ctrl_req;
-       struct dwc3_trb_hw      *ep0_trb;
+       struct dwc3_trb         *ep0_trb;
        void                    *ep0_bounce;
        u8                      *setup_buf;
        dma_addr_t              ctrl_req_addr;
        dma_addr_t              ep0_trb_addr;
-       dma_addr_t              setup_buf_addr;
        dma_addr_t              ep0_bounce_addr;
        struct dwc3_request     ep0_usb_req;
        /* device lock */
@@ -651,6 +617,8 @@ struct dwc3 {
        unsigned                start_config_issued:1;
        unsigned                setup_packet_pending:1;
        unsigned                delayed_status:1;
+       unsigned                needs_fifo_resize:1;
+       unsigned                resize_fifos:1;
 
        enum dwc3_ep0_next      ep0_next_event;
        enum dwc3_ep0_state     ep0state;
@@ -662,23 +630,13 @@ struct dwc3 {
 
        struct dwc3_hwparams    hwparams;
        struct dentry           *root;
+
+       u8                      test_mode;
+       u8                      test_mode_nr;
 };
 
 /* -------------------------------------------------------------------------- */
 
-#define DWC3_TRBSTS_OK                 0
-#define DWC3_TRBSTS_MISSED_ISOC                1
-#define DWC3_TRBSTS_SETUP_PENDING      2
-
-#define DWC3_TRBCTL_NORMAL             1
-#define DWC3_TRBCTL_CONTROL_SETUP      2
-#define DWC3_TRBCTL_CONTROL_STATUS2    3
-#define DWC3_TRBCTL_CONTROL_STATUS3    4
-#define DWC3_TRBCTL_CONTROL_DATA       5
-#define DWC3_TRBCTL_ISOCHRONOUS_FIRST  6
-#define DWC3_TRBCTL_ISOCHRONOUS                7
-#define DWC3_TRBCTL_LINK_TRB           8
-
 /* -------------------------------------------------------------------------- */
 
 struct dwc3_event_type {
@@ -719,9 +677,14 @@ struct dwc3_event_depevt {
        u32     endpoint_event:4;
        u32     reserved11_10:2;
        u32     status:4;
-#define DEPEVT_STATUS_BUSERR    (1 << 0)
-#define DEPEVT_STATUS_SHORT     (1 << 1)
-#define DEPEVT_STATUS_IOC       (1 << 2)
+
+/* Within XferNotReady */
+#define DEPEVT_STATUS_TRANSFER_ACTIVE  (1 << 3)
+
+/* Within XferComplete */
+#define DEPEVT_STATUS_BUSERR   (1 << 0)
+#define DEPEVT_STATUS_SHORT    (1 << 1)
+#define DEPEVT_STATUS_IOC      (1 << 2)
 #define DEPEVT_STATUS_LST      (1 << 3)
 
 /* Stream event only */
@@ -807,6 +770,7 @@ union dwc3_event {
 
 /* prototypes */
 void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
+int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc);
 
 int dwc3_host_init(struct dwc3 *dwc);
 void dwc3_host_exit(struct dwc3 *dwc);
index 433c97c..d4a30f1 100644 (file)
@@ -46,6 +46,8 @@
 #include <linux/delay.h>
 #include <linux/uaccess.h>
 
+#include <linux/usb/ch9.h>
+
 #include "core.h"
 #include "gadget.h"
 #include "io.h"
@@ -464,6 +466,192 @@ static const struct file_operations dwc3_mode_fops = {
        .release                = single_release,
 };
 
+static int dwc3_testmode_show(struct seq_file *s, void *unused)
+{
+       struct dwc3             *dwc = s->private;
+       unsigned long           flags;
+       u32                     reg;
+
+       spin_lock_irqsave(&dwc->lock, flags);
+       reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+       reg &= DWC3_DCTL_TSTCTRL_MASK;
+       reg >>= 1;
+       spin_unlock_irqrestore(&dwc->lock, flags);
+
+       switch (reg) {
+       case 0:
+               seq_printf(s, "no test\n");
+               break;
+       case TEST_J:
+               seq_printf(s, "test_j\n");
+               break;
+       case TEST_K:
+               seq_printf(s, "test_k\n");
+               break;
+       case TEST_SE0_NAK:
+               seq_printf(s, "test_se0_nak\n");
+               break;
+       case TEST_PACKET:
+               seq_printf(s, "test_packet\n");
+               break;
+       case TEST_FORCE_EN:
+               seq_printf(s, "test_force_enable\n");
+               break;
+       default:
+               seq_printf(s, "UNKNOWN %d\n", reg);
+       }
+
+       return 0;
+}
+
+static int dwc3_testmode_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, dwc3_testmode_show, inode->i_private);
+}
+
+static ssize_t dwc3_testmode_write(struct file *file,
+               const char __user *ubuf, size_t count, loff_t *ppos)
+{
+       struct seq_file         *s = file->private_data;
+       struct dwc3             *dwc = s->private;
+       unsigned long           flags;
+       u32                     testmode = 0;
+       char                    buf[32];
+
+       if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+               return -EFAULT;
+
+       if (!strncmp(buf, "test_j", 6))
+               testmode = TEST_J;
+       else if (!strncmp(buf, "test_k", 6))
+               testmode = TEST_K;
+       else if (!strncmp(buf, "test_se0_nak", 12))
+               testmode = TEST_SE0_NAK;
+       else if (!strncmp(buf, "test_packet", 11))
+               testmode = TEST_PACKET;
+       else if (!strncmp(buf, "test_force_enable", 17))
+               testmode = TEST_FORCE_EN;
+       else
+               testmode = 0;
+
+       spin_lock_irqsave(&dwc->lock, flags);
+       dwc3_gadget_set_test_mode(dwc, testmode);
+       spin_unlock_irqrestore(&dwc->lock, flags);
+
+       return count;
+}
+
+static const struct file_operations dwc3_testmode_fops = {
+       .open                   = dwc3_testmode_open,
+       .write                  = dwc3_testmode_write,
+       .read                   = seq_read,
+       .llseek                 = seq_lseek,
+       .release                = single_release,
+};
+
+static int dwc3_link_state_show(struct seq_file *s, void *unused)
+{
+       struct dwc3             *dwc = s->private;
+       unsigned long           flags;
+       enum dwc3_link_state    state;
+       u32                     reg;
+
+       spin_lock_irqsave(&dwc->lock, flags);
+       reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+       state = DWC3_DSTS_USBLNKST(reg);
+       spin_unlock_irqrestore(&dwc->lock, flags);
+
+       switch (state) {
+       case DWC3_LINK_STATE_U0:
+               seq_printf(s, "U0\n");
+               break;
+       case DWC3_LINK_STATE_U1:
+               seq_printf(s, "U1\n");
+               break;
+       case DWC3_LINK_STATE_U2:
+               seq_printf(s, "U2\n");
+               break;
+       case DWC3_LINK_STATE_U3:
+               seq_printf(s, "U3\n");
+               break;
+       case DWC3_LINK_STATE_SS_DIS:
+               seq_printf(s, "SS.Disabled\n");
+               break;
+       case DWC3_LINK_STATE_RX_DET:
+               seq_printf(s, "Rx.Detect\n");
+               break;
+       case DWC3_LINK_STATE_SS_INACT:
+               seq_printf(s, "SS.Inactive\n");
+               break;
+       case DWC3_LINK_STATE_POLL:
+               seq_printf(s, "Poll\n");
+               break;
+       case DWC3_LINK_STATE_RECOV:
+               seq_printf(s, "Recovery\n");
+               break;
+       case DWC3_LINK_STATE_HRESET:
+               seq_printf(s, "HRESET\n");
+               break;
+       case DWC3_LINK_STATE_CMPLY:
+               seq_printf(s, "Compliance\n");
+               break;
+       case DWC3_LINK_STATE_LPBK:
+               seq_printf(s, "Loopback\n");
+               break;
+       default:
+               seq_printf(s, "UNKNOWN %d\n", reg);
+       }
+
+       return 0;
+}
+
+static int dwc3_link_state_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, dwc3_link_state_show, inode->i_private);
+}
+
+static ssize_t dwc3_link_state_write(struct file *file,
+               const char __user *ubuf, size_t count, loff_t *ppos)
+{
+       struct seq_file         *s = file->private_data;
+       struct dwc3             *dwc = s->private;
+       unsigned long           flags;
+       enum dwc3_link_state    state = 0;
+       char                    buf[32];
+
+       if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+               return -EFAULT;
+
+       if (!strncmp(buf, "SS.Disabled", 11))
+               state = DWC3_LINK_STATE_SS_DIS;
+       else if (!strncmp(buf, "Rx.Detect", 9))
+               state = DWC3_LINK_STATE_RX_DET;
+       else if (!strncmp(buf, "SS.Inactive", 11))
+               state = DWC3_LINK_STATE_SS_INACT;
+       else if (!strncmp(buf, "Recovery", 8))
+               state = DWC3_LINK_STATE_RECOV;
+       else if (!strncmp(buf, "Compliance", 10))
+               state = DWC3_LINK_STATE_CMPLY;
+       else if (!strncmp(buf, "Loopback", 8))
+               state = DWC3_LINK_STATE_LPBK;
+       else
+               return -EINVAL;
+
+       spin_lock_irqsave(&dwc->lock, flags);
+       dwc3_gadget_set_link_state(dwc, state);
+       spin_unlock_irqrestore(&dwc->lock, flags);
+
+       return count;
+}
+
+static const struct file_operations dwc3_link_state_fops = {
+       .open                   = dwc3_link_state_open,
+       .write                  = dwc3_link_state_write,
+       .read                   = seq_read,
+       .llseek                 = seq_lseek,
+       .release                = single_release,
+};
+
 int __devinit dwc3_debugfs_init(struct dwc3 *dwc)
 {
        struct dentry           *root;
@@ -471,8 +659,8 @@ int __devinit dwc3_debugfs_init(struct dwc3 *dwc)
        int                     ret;
 
        root = debugfs_create_dir(dev_name(dwc->dev), NULL);
-       if (IS_ERR(root)) {
-               ret = PTR_ERR(root);
+       if (!root) {
+               ret = -ENOMEM;
                goto err0;
        }
 
@@ -480,15 +668,29 @@ int __devinit dwc3_debugfs_init(struct dwc3 *dwc)
 
        file = debugfs_create_file("regdump", S_IRUGO, root, dwc,
                        &dwc3_regdump_fops);
-       if (IS_ERR(file)) {
-               ret = PTR_ERR(file);
+       if (!file) {
+               ret = -ENOMEM;
                goto err1;
        }
 
        file = debugfs_create_file("mode", S_IRUGO | S_IWUSR, root,
                        dwc, &dwc3_mode_fops);
-       if (IS_ERR(file)) {
-               ret = PTR_ERR(file);
+       if (!file) {
+               ret = -ENOMEM;
+               goto err1;
+       }
+
+       file = debugfs_create_file("testmode", S_IRUGO | S_IWUSR, root,
+                       dwc, &dwc3_testmode_fops);
+       if (!file) {
+               ret = -ENOMEM;
+               goto err1;
+       }
+
+       file = debugfs_create_file("link_state", S_IRUGO | S_IWUSR, root,
+                       dwc, &dwc3_link_state_fops);
+       if (!file) {
+               ret = -ENOMEM;
                goto err1;
        }
 
diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c
new file mode 100644 (file)
index 0000000..d190301
--- /dev/null
@@ -0,0 +1,151 @@
+/**
+ * dwc3-exynos.c - Samsung EXYNOS DWC3 Specific Glue layer
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Author: Anton Tikhomirov <av.tikhomirov@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/dwc3-exynos.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+
+#include "core.h"
+
+struct dwc3_exynos {
+       struct platform_device  *dwc3;
+       struct device           *dev;
+
+       struct clk              *clk;
+};
+
+static int __devinit dwc3_exynos_probe(struct platform_device *pdev)
+{
+       struct dwc3_exynos_data *pdata = pdev->dev.platform_data;
+       struct platform_device  *dwc3;
+       struct dwc3_exynos      *exynos;
+       struct clk              *clk;
+
+       int                     devid;
+       int                     ret = -ENOMEM;
+
+       exynos = kzalloc(sizeof(*exynos), GFP_KERNEL);
+       if (!exynos) {
+               dev_err(&pdev->dev, "not enough memory\n");
+               goto err0;
+       }
+
+       platform_set_drvdata(pdev, exynos);
+
+       devid = dwc3_get_device_id();
+       if (devid < 0)
+               goto err1;
+
+       dwc3 = platform_device_alloc("dwc3", devid);
+       if (!dwc3) {
+               dev_err(&pdev->dev, "couldn't allocate dwc3 device\n");
+               goto err2;
+       }
+
+       clk = clk_get(&pdev->dev, "usbdrd30");
+       if (IS_ERR(clk)) {
+               dev_err(&pdev->dev, "couldn't get clock\n");
+               ret = -EINVAL;
+               goto err3;
+       }
+
+       dma_set_coherent_mask(&dwc3->dev, pdev->dev.coherent_dma_mask);
+
+       dwc3->dev.parent = &pdev->dev;
+       dwc3->dev.dma_mask = pdev->dev.dma_mask;
+       dwc3->dev.dma_parms = pdev->dev.dma_parms;
+       exynos->dwc3    = dwc3;
+       exynos->dev     = &pdev->dev;
+       exynos->clk     = clk;
+
+       clk_enable(exynos->clk);
+
+       /* PHY initialization */
+       if (!pdata) {
+               dev_dbg(&pdev->dev, "missing platform data\n");
+       } else {
+               if (pdata->phy_init)
+                       pdata->phy_init(pdev, pdata->phy_type);
+       }
+
+       ret = platform_device_add_resources(dwc3, pdev->resource,
+                       pdev->num_resources);
+       if (ret) {
+               dev_err(&pdev->dev, "couldn't add resources to dwc3 device\n");
+               goto err4;
+       }
+
+       ret = platform_device_add(dwc3);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to register dwc3 device\n");
+               goto err4;
+       }
+
+       return 0;
+
+err4:
+       if (pdata && pdata->phy_exit)
+               pdata->phy_exit(pdev, pdata->phy_type);
+
+       clk_disable(clk);
+       clk_put(clk);
+err3:
+       platform_device_put(dwc3);
+err2:
+       dwc3_put_device_id(devid);
+err1:
+       kfree(exynos);
+err0:
+       return ret;
+}
+
+static int __devexit dwc3_exynos_remove(struct platform_device *pdev)
+{
+       struct dwc3_exynos      *exynos = platform_get_drvdata(pdev);
+       struct dwc3_exynos_data *pdata = pdev->dev.platform_data;
+
+       platform_device_unregister(exynos->dwc3);
+
+       dwc3_put_device_id(exynos->dwc3->id);
+
+       if (pdata && pdata->phy_exit)
+               pdata->phy_exit(pdev, pdata->phy_type);
+
+       clk_disable(exynos->clk);
+       clk_put(exynos->clk);
+
+       kfree(exynos);
+
+       return 0;
+}
+
+static struct platform_driver dwc3_exynos_driver = {
+       .probe          = dwc3_exynos_probe,
+       .remove         = __devexit_p(dwc3_exynos_remove),
+       .driver         = {
+               .name   = "exynos-dwc3",
+       },
+};
+
+module_platform_driver(dwc3_exynos_driver);
+
+MODULE_ALIAS("platform:exynos-dwc3");
+MODULE_AUTHOR("Anton Tikhomirov <av.tikhomirov@samsung.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("DesignWare USB3 EXYNOS Glue Layer");
index 3274ac8..d7d9c0e 100644 (file)
@@ -46,7 +46,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/ioport.h>
 #include <linux/io.h>
-#include <linux/module.h>
+#include <linux/of.h>
 
 #include "core.h"
 #include "io.h"
@@ -197,91 +197,99 @@ static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
 static int __devinit dwc3_omap_probe(struct platform_device *pdev)
 {
        struct dwc3_omap_data   *pdata = pdev->dev.platform_data;
+       struct device_node      *node = pdev->dev.of_node;
+
        struct platform_device  *dwc3;
        struct dwc3_omap        *omap;
        struct resource         *res;
+       struct device           *dev = &pdev->dev;
 
        int                     devid;
+       int                     size;
        int                     ret = -ENOMEM;
        int                     irq;
 
+       const u32               *utmi_mode;
        u32                     reg;
 
        void __iomem            *base;
        void                    *context;
 
-       omap = kzalloc(sizeof(*omap), GFP_KERNEL);
+       omap = devm_kzalloc(dev, sizeof(*omap), GFP_KERNEL);
        if (!omap) {
-               dev_err(&pdev->dev, "not enough memory\n");
-               goto err0;
+               dev_err(dev, "not enough memory\n");
+               return -ENOMEM;
        }
 
        platform_set_drvdata(pdev, omap);
 
        irq = platform_get_irq(pdev, 1);
        if (irq < 0) {
-               dev_err(&pdev->dev, "missing IRQ resource\n");
-               ret = -EINVAL;
-               goto err1;
+               dev_err(dev, "missing IRQ resource\n");
+               return -EINVAL;
        }
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
        if (!res) {
-               dev_err(&pdev->dev, "missing memory base resource\n");
-               ret = -EINVAL;
-               goto err1;
+               dev_err(dev, "missing memory base resource\n");
+               return -EINVAL;
        }
 
-       base = ioremap_nocache(res->start, resource_size(res));
+       base = devm_ioremap_nocache(dev, res->start, resource_size(res));
        if (!base) {
-               dev_err(&pdev->dev, "ioremap failed\n");
-               goto err1;
+               dev_err(dev, "ioremap failed\n");
+               return -ENOMEM;
        }
 
        devid = dwc3_get_device_id();
        if (devid < 0)
-               goto err2;
+               return -ENODEV;
 
        dwc3 = platform_device_alloc("dwc3", devid);
        if (!dwc3) {
-               dev_err(&pdev->dev, "couldn't allocate dwc3 device\n");
-               goto err3;
+               dev_err(dev, "couldn't allocate dwc3 device\n");
+               goto err1;
        }
 
-       context = kzalloc(resource_size(res), GFP_KERNEL);
+       context = devm_kzalloc(dev, resource_size(res), GFP_KERNEL);
        if (!context) {
-               dev_err(&pdev->dev, "couldn't allocate dwc3 context memory\n");
-               goto err4;
+               dev_err(dev, "couldn't allocate dwc3 context memory\n");
+               goto err2;
        }
 
        spin_lock_init(&omap->lock);
-       dma_set_coherent_mask(&dwc3->dev, pdev->dev.coherent_dma_mask);
+       dma_set_coherent_mask(&dwc3->dev, dev->coherent_dma_mask);
 
-       dwc3->dev.parent = &pdev->dev;
-       dwc3->dev.dma_mask = pdev->dev.dma_mask;
-       dwc3->dev.dma_parms = pdev->dev.dma_parms;
+       dwc3->dev.parent = dev;
+       dwc3->dev.dma_mask = dev->dma_mask;
+       dwc3->dev.dma_parms = dev->dma_parms;
        omap->resource_size = resource_size(res);
        omap->context   = context;
-       omap->dev       = &pdev->dev;
+       omap->dev       = dev;
        omap->irq       = irq;
        omap->base      = base;
        omap->dwc3      = dwc3;
 
        reg = dwc3_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS);
 
-       if (!pdata) {
-               dev_dbg(&pdev->dev, "missing platform data\n");
+       utmi_mode = of_get_property(node, "utmi-mode", &size);
+       if (utmi_mode && size == sizeof(*utmi_mode)) {
+               reg |= *utmi_mode;
        } else {
-               switch (pdata->utmi_mode) {
-               case DWC3_OMAP_UTMI_MODE_SW:
-                       reg |= USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
-                       break;
-               case DWC3_OMAP_UTMI_MODE_HW:
-                       reg &= ~USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
-                       break;
-               default:
-                       dev_dbg(&pdev->dev, "UNKNOWN utmi mode %d\n",
-                                       pdata->utmi_mode);
+               if (!pdata) {
+                       dev_dbg(dev, "missing platform data\n");
+               } else {
+                       switch (pdata->utmi_mode) {
+                       case DWC3_OMAP_UTMI_MODE_SW:
+                               reg |= USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
+                               break;
+                       case DWC3_OMAP_UTMI_MODE_HW:
+                               reg &= ~USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
+                               break;
+                       default:
+                               dev_dbg(dev, "UNKNOWN utmi mode %d\n",
+                                               pdata->utmi_mode);
+                       }
                }
        }
 
@@ -300,12 +308,12 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev)
 
        dwc3_writel(omap->base, USBOTGSS_SYSCONFIG, reg);
 
-       ret = request_irq(omap->irq, dwc3_omap_interrupt, 0,
+       ret = devm_request_irq(dev, omap->irq, dwc3_omap_interrupt, 0,
                        "dwc3-omap", omap);
        if (ret) {
-               dev_err(&pdev->dev, "failed to request IRQ #%d --> %d\n",
+               dev_err(dev, "failed to request IRQ #%d --> %d\n",
                                omap->irq, ret);
-               goto err5;
+               goto err2;
        }
 
        /* enable all IRQs */
@@ -327,37 +335,24 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev)
        ret = platform_device_add_resources(dwc3, pdev->resource,
                        pdev->num_resources);
        if (ret) {
-               dev_err(&pdev->dev, "couldn't add resources to dwc3 device\n");
-               goto err6;
+               dev_err(dev, "couldn't add resources to dwc3 device\n");
+               goto err2;
        }
 
        ret = platform_device_add(dwc3);
        if (ret) {
-               dev_err(&pdev->dev, "failed to register dwc3 device\n");
-               goto err6;
+               dev_err(dev, "failed to register dwc3 device\n");
+               goto err2;
        }
 
        return 0;
 
-err6:
-       free_irq(omap->irq, omap);
-
-err5:
-       kfree(omap->context);
-
-err4:
-       platform_device_put(dwc3);
-
-err3:
-       dwc3_put_device_id(devid);
-
 err2:
-       iounmap(base);
+       platform_device_put(dwc3);
 
 err1:
-       kfree(omap);
+       dwc3_put_device_id(devid);
 
-err0:
        return ret;
 }
 
@@ -368,11 +363,6 @@ static int __devexit dwc3_omap_remove(struct platform_device *pdev)
        platform_device_unregister(omap->dwc3);
 
        dwc3_put_device_id(omap->dwc3->id);
-       free_irq(omap->irq, omap);
-       iounmap(omap->base);
-
-       kfree(omap->context);
-       kfree(omap);
 
        return 0;
 }
index c68e427..a9ca9ad 100644 (file)
@@ -61,32 +61,36 @@ static int __devinit dwc3_pci_probe(struct pci_dev *pci,
        struct dwc3_pci         *glue;
        int                     ret = -ENOMEM;
        int                     devid;
+       struct device           *dev = &pci->dev;
 
-       glue = kzalloc(sizeof(*glue), GFP_KERNEL);
+       glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL);
        if (!glue) {
-               dev_err(&pci->dev, "not enough memory\n");
-               goto err0;
+               dev_err(dev, "not enough memory\n");
+               return -ENOMEM;
        }
 
-       glue->dev       = &pci->dev;
+       glue->dev = dev;
 
        ret = pci_enable_device(pci);
        if (ret) {
-               dev_err(&pci->dev, "failed to enable pci device\n");
-               goto err1;
+               dev_err(dev, "failed to enable pci device\n");
+               return -ENODEV;
        }
 
        pci_set_power_state(pci, PCI_D0);
        pci_set_master(pci);
 
        devid = dwc3_get_device_id();
-       if (devid < 0)
-               goto err2;
+       if (devid < 0) {
+               ret = -ENOMEM;
+               goto err1;
+       }
 
        dwc3 = platform_device_alloc("dwc3", devid);
        if (!dwc3) {
-               dev_err(&pci->dev, "couldn't allocate dwc3 device\n");
-               goto err3;
+               dev_err(dev, "couldn't allocate dwc3 device\n");
+               ret = -ENOMEM;
+               goto err1;
        }
 
        memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res));
@@ -102,41 +106,37 @@ static int __devinit dwc3_pci_probe(struct pci_dev *pci,
 
        ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res));
        if (ret) {
-               dev_err(&pci->dev, "couldn't add resources to dwc3 device\n");
-               goto err4;
+               dev_err(dev, "couldn't add resources to dwc3 device\n");
+               goto err2;
        }
 
        pci_set_drvdata(pci, glue);
 
-       dma_set_coherent_mask(&dwc3->dev, pci->dev.coherent_dma_mask);
+       dma_set_coherent_mask(&dwc3->dev, dev->coherent_dma_mask);
 
-       dwc3->dev.dma_mask = pci->dev.dma_mask;
-       dwc3->dev.dma_parms = pci->dev.dma_parms;
-       dwc3->dev.parent = &pci->dev;
-       glue->dwc3      = dwc3;
+       dwc3->dev.dma_mask = dev->dma_mask;
+       dwc3->dev.dma_parms = dev->dma_parms;
+       dwc3->dev.parent = dev;
+       glue->dwc3 = dwc3;
 
        ret = platform_device_add(dwc3);
        if (ret) {
-               dev_err(&pci->dev, "failed to register dwc3 device\n");
-               goto err4;
+               dev_err(dev, "failed to register dwc3 device\n");
+               goto err3;
        }
 
        return 0;
 
-err4:
+err3:
        pci_set_drvdata(pci, NULL);
        platform_device_put(dwc3);
 
-err3:
-       dwc3_put_device_id(devid);
-
 err2:
-       pci_disable_device(pci);
+       dwc3_put_device_id(devid);
 
 err1:
-       kfree(glue);
+       pci_disable_device(pci);
 
-err0:
        return ret;
 }
 
@@ -148,7 +148,6 @@ static void __devexit dwc3_pci_remove(struct pci_dev *pci)
        platform_device_unregister(glue->dwc3);
        pci_set_drvdata(pci, NULL);
        pci_disable_device(pci);
-       kfree(glue);
 }
 
 static DEFINE_PCI_DEVICE_TABLE(dwc3_pci_id_table) = {
index c8df1dd..25910e2 100644 (file)
@@ -76,8 +76,7 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,
                u32 len, u32 type)
 {
        struct dwc3_gadget_ep_cmd_params params;
-       struct dwc3_trb_hw              *trb_hw;
-       struct dwc3_trb                 trb;
+       struct dwc3_trb                 *trb;
        struct dwc3_ep                  *dep;
 
        int                             ret;
@@ -88,19 +87,17 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,
                return 0;
        }
 
-       trb_hw = dwc->ep0_trb;
-       memset(&trb, 0, sizeof(trb));
+       trb = dwc->ep0_trb;
 
-       trb.trbctl = type;
-       trb.bplh = buf_dma;
-       trb.length = len;
+       trb->bpl = lower_32_bits(buf_dma);
+       trb->bph = upper_32_bits(buf_dma);
+       trb->size = len;
+       trb->ctrl = type;
 
-       trb.hwo = 1;
-       trb.lst = 1;
-       trb.ioc = 1;
-       trb.isp_imi = 1;
-
-       dwc3_trb_to_hw(&trb, trb_hw);
+       trb->ctrl |= (DWC3_TRB_CTRL_HWO
+                       | DWC3_TRB_CTRL_LST
+                       | DWC3_TRB_CTRL_IOC
+                       | DWC3_TRB_CTRL_ISP_IMI);
 
        memset(&params, 0, sizeof(params));
        params.param0 = upper_32_bits(dwc->ep0_trb_addr);
@@ -302,7 +299,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc,
        dep = dwc->eps[0];
        dwc->ep0_usb_req.dep = dep;
        dwc->ep0_usb_req.request.length = sizeof(*response_pkt);
-       dwc->ep0_usb_req.request.dma = dwc->setup_buf_addr;
+       dwc->ep0_usb_req.request.buf = dwc->setup_buf;
        dwc->ep0_usb_req.request.complete = dwc3_ep0_status_cmpl;
 
        return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req);
@@ -315,9 +312,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
        u32                     recip;
        u32                     wValue;
        u32                     wIndex;
-       u32                     reg;
        int                     ret;
-       u32                     mode;
 
        wValue = le16_to_cpu(ctrl->wValue);
        wIndex = le16_to_cpu(ctrl->wIndex);
@@ -356,25 +351,8 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
                        if (!set)
                                return -EINVAL;
 
-                       mode = wIndex >> 8;
-                       reg = dwc3_readl(dwc->regs, DWC3_DCTL);
-                       reg &= ~DWC3_DCTL_TSTCTRL_MASK;
-
-                       switch (mode) {
-                       case TEST_J:
-                       case TEST_K:
-                       case TEST_SE0_NAK:
-                       case TEST_PACKET:
-                       case TEST_FORCE_EN:
-                               reg |= mode << 1;
-                               break;
-                       default:
-                               return -EINVAL;
-                       }
-                       dwc3_writel(dwc->regs, DWC3_DCTL, reg);
-                       break;
-               default:
-                       return -EINVAL;
+                       dwc->test_mode_nr = wIndex >> 8;
+                       dwc->test_mode = true;
                }
                break;
 
@@ -396,7 +374,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
        case USB_RECIP_ENDPOINT:
                switch (wValue) {
                case USB_ENDPOINT_HALT:
-                       dep =  dwc3_wIndex_to_dep(dwc, wIndex);
+                       dep = dwc3_wIndex_to_dep(dwc, wIndex);
                        if (!dep)
                                return -EINVAL;
                        ret = __dwc3_gadget_ep_set_halt(dep, set);
@@ -470,8 +448,11 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
        case DWC3_ADDRESS_STATE:
                ret = dwc3_ep0_delegate_req(dwc, ctrl);
                /* if the cfg matches and the cfg is non zero */
-               if (!ret && cfg)
+               if (cfg && (!ret || (ret == USB_GADGET_DELAYED_STATUS))) {
                        dwc->dev_state = DWC3_CONFIGURED_STATE;
+                       dwc->resize_fifos = true;
+                       dev_dbg(dwc->dev, "resize fifos flag SET\n");
+               }
                break;
 
        case DWC3_CONFIGURED_STATE:
@@ -560,9 +541,10 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
 {
        struct dwc3_request     *r = NULL;
        struct usb_request      *ur;
-       struct dwc3_trb         trb;
+       struct dwc3_trb         *trb;
        struct dwc3_ep          *ep0;
        u32                     transferred;
+       u32                     length;
        u8                      epnum;
 
        epnum = event->endpoint_number;
@@ -573,16 +555,16 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
        r = next_request(&ep0->request_list);
        ur = &r->request;
 
-       dwc3_trb_to_nat(dwc->ep0_trb, &trb);
+       trb = dwc->ep0_trb;
+       length = trb->size & DWC3_TRB_SIZE_MASK;
 
        if (dwc->ep0_bounced) {
-
                transferred = min_t(u32, ur->length,
-                               ep0->endpoint.maxpacket - trb.length);
+                               ep0->endpoint.maxpacket - length);
                memcpy(ur->buf, dwc->ep0_bounce, transferred);
                dwc->ep0_bounced = false;
        } else {
-               transferred = ur->length - trb.length;
+               transferred = ur->length - length;
                ur->actual += transferred;
        }
 
@@ -614,6 +596,17 @@ static void dwc3_ep0_complete_req(struct dwc3 *dwc,
                dwc3_gadget_giveback(dep, r, 0);
        }
 
+       if (dwc->test_mode) {
+               int ret;
+
+               ret = dwc3_gadget_set_test_mode(dwc, dwc->test_mode_nr);
+               if (ret < 0) {
+                       dev_dbg(dwc->dev, "Invalid Test #%d\n",
+                                       dwc->test_mode_nr);
+                       dwc3_ep0_stall_and_restart(dwc);
+               }
+       }
+
        dwc->ep0state = EP0_SETUP_PHASE;
        dwc3_ep0_out_start(dwc);
 }
@@ -624,6 +617,7 @@ static void dwc3_ep0_xfer_complete(struct dwc3 *dwc,
        struct dwc3_ep          *dep = dwc->eps[event->endpoint_number];
 
        dep->flags &= ~DWC3_EP_BUSY;
+       dep->res_trans_idx = 0;
        dwc->setup_packet_pending = false;
 
        switch (dwc->ep0state) {
@@ -679,7 +673,12 @@ static void dwc3_ep0_do_control_data(struct dwc3 *dwc,
                                DWC3_TRBCTL_CONTROL_DATA);
        } else if ((req->request.length % dep->endpoint.maxpacket)
                        && (event->endpoint_number == 0)) {
-               dwc3_map_buffer_to_dma(req);
+               ret = usb_gadget_map_request(&dwc->gadget, &req->request,
+                               event->endpoint_number);
+               if (ret) {
+                       dev_dbg(dwc->dev, "failed to map request\n");
+                       return;
+               }
 
                WARN_ON(req->request.length > dep->endpoint.maxpacket);
 
@@ -694,7 +693,12 @@ static void dwc3_ep0_do_control_data(struct dwc3 *dwc,
                                dwc->ep0_bounce_addr, dep->endpoint.maxpacket,
                                DWC3_TRBCTL_CONTROL_DATA);
        } else {
-               dwc3_map_buffer_to_dma(req);
+               ret = usb_gadget_map_request(&dwc->gadget, &req->request,
+                               event->endpoint_number);
+               if (ret) {
+                       dev_dbg(dwc->dev, "failed to map request\n");
+                       return;
+               }
 
                ret = dwc3_ep0_start_trans(dwc, event->endpoint_number,
                                req->request.dma, req->request.length,
@@ -720,6 +724,12 @@ static void dwc3_ep0_do_control_status(struct dwc3 *dwc, u32 epnum)
 {
        struct dwc3_ep          *dep = dwc->eps[epnum];
 
+       if (dwc->resize_fifos) {
+               dev_dbg(dwc->dev, "starting to resize fifos\n");
+               dwc3_gadget_resize_tx_fifos(dwc);
+               dwc->resize_fifos = 0;
+       }
+
        WARN_ON(dwc3_ep0_start_control_status(dep));
 }
 
index 064b6e2..5255fe9 100644 (file)
 #include "gadget.h"
 #include "io.h"
 
-#define        DMA_ADDR_INVALID        (~(dma_addr_t)0)
-
-void dwc3_map_buffer_to_dma(struct dwc3_request *req)
+/**
+ * dwc3_gadget_set_test_mode - Enables USB2 Test Modes
+ * @dwc: pointer to our context structure
+ * @mode: the mode to set (J, K SE0 NAK, Force Enable)
+ *
+ * Caller should take care of locking. This function will
+ * return 0 on success or -EINVAL if wrong Test Selector
+ * is passed
+ */
+int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode)
 {
-       struct dwc3                     *dwc = req->dep->dwc;
+       u32             reg;
 
-       if (req->request.length == 0) {
-               /* req->request.dma = dwc->setup_buf_addr; */
-               return;
+       reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+       reg &= ~DWC3_DCTL_TSTCTRL_MASK;
+
+       switch (mode) {
+       case TEST_J:
+       case TEST_K:
+       case TEST_SE0_NAK:
+       case TEST_PACKET:
+       case TEST_FORCE_EN:
+               reg |= mode << 1;
+               break;
+       default:
+               return -EINVAL;
        }
 
-       if (req->request.num_sgs) {
-               int     mapped;
+       dwc3_writel(dwc->regs, DWC3_DCTL, reg);
 
-               mapped = dma_map_sg(dwc->dev, req->request.sg,
-                               req->request.num_sgs,
-                               req->direction ? DMA_TO_DEVICE
-                               : DMA_FROM_DEVICE);
-               if (mapped < 0) {
-                       dev_err(dwc->dev, "failed to map SGs\n");
-                       return;
-               }
+       return 0;
+}
 
-               req->request.num_mapped_sgs = mapped;
-               return;
-       }
+/**
+ * dwc3_gadget_set_link_state - Sets USB Link to a particular State
+ * @dwc: pointer to our context structure
+ * @state: the state to put link into
+ *
+ * Caller should take care of locking. This function will
+ * return 0 on success or -ETIMEDOUT.
+ */
+int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)
+{
+       int             retries = 10000;
+       u32             reg;
+
+       reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+       reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK;
 
-       if (req->request.dma == DMA_ADDR_INVALID) {
-               req->request.dma = dma_map_single(dwc->dev, req->request.buf,
-                               req->request.length, req->direction
-                               ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
-               req->mapped = true;
+       /* set requested state */
+       reg |= DWC3_DCTL_ULSTCHNGREQ(state);
+       dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+       /* wait for a change in DSTS */
+       while (--retries) {
+               reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+
+               if (DWC3_DSTS_USBLNKST(reg) == state)
+                       return 0;
+
+               udelay(5);
        }
+
+       dev_vdbg(dwc->dev, "link state change request timed out\n");
+
+       return -ETIMEDOUT;
 }
 
-void dwc3_unmap_buffer_from_dma(struct dwc3_request *req)
+/**
+ * dwc3_gadget_resize_tx_fifos - reallocate fifo spaces for current use-case
+ * @dwc: pointer to our context structure
+ *
+ * This function will a best effort FIFO allocation in order
+ * to improve FIFO usage and throughput, while still allowing
+ * us to enable as many endpoints as possible.
+ *
+ * Keep in mind that this operation will be highly dependent
+ * on the configured size for RAM1 - which contains TxFifo -,
+ * the amount of endpoints enabled on coreConsultant tool, and
+ * the width of the Master Bus.
+ *
+ * In the ideal world, we would always be able to satisfy the
+ * following equation:
+ *
+ * ((512 + 2 * MDWIDTH-Bytes) + (Number of IN Endpoints - 1) * \
+ * (3 * (1024 + MDWIDTH-Bytes) + MDWIDTH-Bytes)) / MDWIDTH-Bytes
+ *
+ * Unfortunately, due to many variables that's not always the case.
+ */
+int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc)
 {
-       struct dwc3                     *dwc = req->dep->dwc;
+       int             last_fifo_depth = 0;
+       int             ram1_depth;
+       int             fifo_size;
+       int             mdwidth;
+       int             num;
 
-       if (req->request.length == 0) {
-               req->request.dma = DMA_ADDR_INVALID;
-               return;
-       }
+       if (!dwc->needs_fifo_resize)
+               return 0;
 
-       if (req->request.num_mapped_sgs) {
-               req->request.dma = DMA_ADDR_INVALID;
-               dma_unmap_sg(dwc->dev, req->request.sg,
-                               req->request.num_mapped_sgs,
-                               req->direction ? DMA_TO_DEVICE
-                               : DMA_FROM_DEVICE);
+       ram1_depth = DWC3_RAM1_DEPTH(dwc->hwparams.hwparams7);
+       mdwidth = DWC3_MDWIDTH(dwc->hwparams.hwparams0);
 
-               req->request.num_mapped_sgs = 0;
-               return;
-       }
+       /* MDWIDTH is represented in bits, we need it in bytes */
+       mdwidth >>= 3;
+
+       /*
+        * FIXME For now we will only allocate 1 wMaxPacketSize space
+        * for each enabled endpoint, later patches will come to
+        * improve this algorithm so that we better use the internal
+        * FIFO space
+        */
+       for (num = 0; num < DWC3_ENDPOINTS_NUM; num++) {
+               struct dwc3_ep  *dep = dwc->eps[num];
+               int             fifo_number = dep->number >> 1;
+               int             mult = 1;
+               int             tmp;
+
+               if (!(dep->number & 1))
+                       continue;
+
+               if (!(dep->flags & DWC3_EP_ENABLED))
+                       continue;
+
+               if (usb_endpoint_xfer_bulk(dep->desc)
+                               || usb_endpoint_xfer_isoc(dep->desc))
+                       mult = 3;
+
+               /*
+                * REVISIT: the following assumes we will always have enough
+                * space available on the FIFO RAM for all possible use cases.
+                * Make sure that's true somehow and change FIFO allocation
+                * accordingly.
+                *
+                * If we have Bulk or Isochronous endpoints, we want
+                * them to be able to be very, very fast. So we're giving
+                * those endpoints a fifo_size which is enough for 3 full
+                * packets
+                */
+               tmp = mult * (dep->endpoint.maxpacket + mdwidth);
+               tmp += mdwidth;
+
+               fifo_size = DIV_ROUND_UP(tmp, mdwidth);
+
+               fifo_size |= (last_fifo_depth << 16);
+
+               dev_vdbg(dwc->dev, "%s: Fifo Addr %04x Size %d\n",
+                               dep->name, last_fifo_depth, fifo_size & 0xffff);
+
+               dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(fifo_number),
+                               fifo_size);
 
-       if (req->mapped) {
-               dma_unmap_single(dwc->dev, req->request.dma,
-                               req->request.length, req->direction
-                               ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
-               req->mapped = 0;
-               req->request.dma = DMA_ADDR_INVALID;
+               last_fifo_depth += (fifo_size & 0xffff);
        }
+
+       return 0;
 }
 
 void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
@@ -144,14 +238,15 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
        if (req->request.status == -EINPROGRESS)
                req->request.status = status;
 
-       dwc3_unmap_buffer_from_dma(req);
+       usb_gadget_unmap_request(&dwc->gadget, &req->request,
+                       req->direction);
 
        dev_dbg(dwc->dev, "request %p from %s completed %d/%d ===> %d\n",
                        req, dep->name, req->request.actual,
                        req->request.length, status);
 
        spin_unlock(&dwc->lock);
-       req->request.complete(&req->dep->endpoint, &req->request);
+       req->request.complete(&dep->endpoint, &req->request);
        spin_lock(&dwc->lock);
 }
 
@@ -219,7 +314,7 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
 }
 
 static dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
-               struct dwc3_trb_hw *trb)
+               struct dwc3_trb *trb)
 {
        u32             offset = (char *) trb - (char *) dep->trb_pool;
 
@@ -368,9 +463,8 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
                return ret;
 
        if (!(dep->flags & DWC3_EP_ENABLED)) {
-               struct dwc3_trb_hw      *trb_st_hw;
-               struct dwc3_trb_hw      *trb_link_hw;
-               struct dwc3_trb         trb_link;
+               struct dwc3_trb *trb_st_hw;
+               struct dwc3_trb *trb_link;
 
                ret = dwc3_gadget_set_xfer_resource(dwc, dep);
                if (ret)
@@ -390,15 +484,15 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
 
                memset(&trb_link, 0, sizeof(trb_link));
 
-               /* Link TRB for ISOC. The HWO but is never reset */
+               /* Link TRB for ISOC. The HWO bit is never reset */
                trb_st_hw = &dep->trb_pool[0];
 
-               trb_link.bplh = dwc3_trb_dma_offset(dep, trb_st_hw);
-               trb_link.trbctl = DWC3_TRBCTL_LINK_TRB;
-               trb_link.hwo = true;
+               trb_link = &dep->trb_pool[DWC3_TRB_NUM - 1];
 
-               trb_link_hw = &dep->trb_pool[DWC3_TRB_NUM - 1];
-               dwc3_trb_to_hw(&trb_link, trb_link_hw);
+               trb_link->bpl = lower_32_bits(dwc3_trb_dma_offset(dep, trb_st_hw));
+               trb_link->bph = upper_32_bits(dwc3_trb_dma_offset(dep, trb_st_hw));
+               trb_link->ctrl |= DWC3_TRBCTL_LINK_TRB;
+               trb_link->ctrl |= DWC3_TRB_CTRL_HWO;
        }
 
        return 0;
@@ -440,6 +534,7 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
 
        dep->stream_capable = false;
        dep->desc = NULL;
+       dep->endpoint.desc = NULL;
        dep->comp_desc = NULL;
        dep->type = 0;
        dep->flags = 0;
@@ -485,16 +580,16 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep,
 
        switch (usb_endpoint_type(desc)) {
        case USB_ENDPOINT_XFER_CONTROL:
-               strncat(dep->name, "-control", sizeof(dep->name));
+               strlcat(dep->name, "-control", sizeof(dep->name));
                break;
        case USB_ENDPOINT_XFER_ISOC:
-               strncat(dep->name, "-isoc", sizeof(dep->name));
+               strlcat(dep->name, "-isoc", sizeof(dep->name));
                break;
        case USB_ENDPOINT_XFER_BULK:
-               strncat(dep->name, "-bulk", sizeof(dep->name));
+               strlcat(dep->name, "-bulk", sizeof(dep->name));
                break;
        case USB_ENDPOINT_XFER_INT:
-               strncat(dep->name, "-int", sizeof(dep->name));
+               strlcat(dep->name, "-int", sizeof(dep->name));
                break;
        default:
                dev_err(dwc->dev, "invalid endpoint transfer type\n");
@@ -562,7 +657,6 @@ static struct usb_request *dwc3_gadget_ep_alloc_request(struct usb_ep *ep,
 
        req->epnum      = dep->number;
        req->dep        = dep;
-       req->request.dma = DMA_ADDR_INVALID;
 
        return &req->request;
 }
@@ -585,8 +679,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
                unsigned length, unsigned last, unsigned chain)
 {
        struct dwc3             *dwc = dep->dwc;
-       struct dwc3_trb_hw      *trb_hw;
-       struct dwc3_trb         trb;
+       struct dwc3_trb         *trb;
 
        unsigned int            cur_slot;
 
@@ -595,7 +688,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
                        length, last ? " last" : "",
                        chain ? " chain" : "");
 
-       trb_hw = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
+       trb = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
        cur_slot = dep->free_slot;
        dep->free_slot++;
 
@@ -604,40 +697,32 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
                        usb_endpoint_xfer_isoc(dep->desc))
                return;
 
-       memset(&trb, 0, sizeof(trb));
        if (!req->trb) {
                dwc3_gadget_move_request_queued(req);
-               req->trb = trb_hw;
-               req->trb_dma = dwc3_trb_dma_offset(dep, trb_hw);
+               req->trb = trb;
+               req->trb_dma = dwc3_trb_dma_offset(dep, trb);
        }
 
-       if (usb_endpoint_xfer_isoc(dep->desc)) {
-               trb.isp_imi = true;
-               trb.csp = true;
-       } else {
-               trb.chn = chain;
-               trb.lst = last;
-       }
-
-       if (usb_endpoint_xfer_bulk(dep->desc) && dep->stream_capable)
-               trb.sid_sofn = req->request.stream_id;
+       trb->size = DWC3_TRB_SIZE_LENGTH(length);
+       trb->bpl = lower_32_bits(dma);
+       trb->bph = upper_32_bits(dma);
 
        switch (usb_endpoint_type(dep->desc)) {
        case USB_ENDPOINT_XFER_CONTROL:
-               trb.trbctl = DWC3_TRBCTL_CONTROL_SETUP;
+               trb->ctrl = DWC3_TRBCTL_CONTROL_SETUP;
                break;
 
        case USB_ENDPOINT_XFER_ISOC:
-               trb.trbctl = DWC3_TRBCTL_ISOCHRONOUS_FIRST;
+               trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS_FIRST;
 
                /* IOC every DWC3_TRB_NUM / 4 so we can refill */
                if (!(cur_slot % (DWC3_TRB_NUM / 4)))
-                       trb.ioc = last;
+                       trb->ctrl |= DWC3_TRB_CTRL_IOC;
                break;
 
        case USB_ENDPOINT_XFER_BULK:
        case USB_ENDPOINT_XFER_INT:
-               trb.trbctl = DWC3_TRBCTL_NORMAL;
+               trb->ctrl = DWC3_TRBCTL_NORMAL;
                break;
        default:
                /*
@@ -647,11 +732,21 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
                BUG();
        }
 
-       trb.length      = length;
-       trb.bplh        = dma;
-       trb.hwo         = true;
+       if (usb_endpoint_xfer_isoc(dep->desc)) {
+               trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI;
+               trb->ctrl |= DWC3_TRB_CTRL_CSP;
+       } else {
+               if (chain)
+                       trb->ctrl |= DWC3_TRB_CTRL_CHN;
+
+               if (last)
+                       trb->ctrl |= DWC3_TRB_CTRL_LST;
+       }
 
-       dwc3_trb_to_hw(&trb, trb_hw);
+       if (usb_endpoint_xfer_bulk(dep->desc) && dep->stream_capable)
+               trb->ctrl |= DWC3_TRB_CTRL_SID_SOFN(req->request.stream_id);
+
+       trb->ctrl |= DWC3_TRB_CTRL_HWO;
 }
 
 /*
@@ -659,14 +754,15 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
  * @dep: endpoint for which requests are being prepared
  * @starting: true if the endpoint is idle and no requests are queued.
  *
- * The functions goes through the requests list and setups TRBs for the
- * transfers. The functions returns once there are not more TRBs available or
- * it run out of requests.
+ * The function goes through the requests list and sets up TRBs for the
+ * transfers. The function returns once there are no more TRBs available or
+ * it runs out of requests.
  */
 static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
 {
        struct dwc3_request     *req, *n;
        u32                     trbs_left;
+       u32                     max;
        unsigned int            last_one = 0;
 
        BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM);
@@ -674,9 +770,16 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
        /* the first request must not be queued */
        trbs_left = (dep->busy_slot - dep->free_slot) & DWC3_TRB_MASK;
 
+       /* Can't wrap around on a non-isoc EP since there's no link TRB */
+       if (!usb_endpoint_xfer_isoc(dep->desc)) {
+               max = DWC3_TRB_NUM - (dep->free_slot & DWC3_TRB_MASK);
+               if (trbs_left > max)
+                       trbs_left = max;
+       }
+
        /*
-        * if busy & slot are equal than it is either full or empty. If we are
-        * starting to proceed requests then we are empty. Otherwise we ar
+        * If busy & slot are equal than it is either full or empty. If we are
+        * starting to process requests then we are empty. Otherwise we are
         * full and don't do anything
         */
        if (!trbs_left) {
@@ -687,7 +790,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
                 * In case we start from scratch, we queue the ISOC requests
                 * starting from slot 1. This is done because we use ring
                 * buffer and have no LST bit to stop us. Instead, we place
-                * IOC bit TRB_NUM/4. We try to avoid to having an interrupt
+                * IOC bit every TRB_NUM/4. We try to avoid having an interrupt
                 * after the first request so we start at slot 1 and have
                 * 7 requests proceed before we hit the first IOC.
                 * Other transfer types don't use the ring buffer and are
@@ -723,8 +826,8 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
                                length = sg_dma_len(s);
                                dma = sg_dma_address(s);
 
-                               if (i == (request->num_mapped_sgs - 1)
-                                               || sg_is_last(s)) {
+                               if (i == (request->num_mapped_sgs - 1) ||
+                                               sg_is_last(s)) {
                                        last_one = true;
                                        chain = false;
                                }
@@ -792,8 +895,7 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
                dwc3_prepare_trbs(dep, start_new);
 
                /*
-                * req points to the first request where HWO changed
-                * from 0 to 1
+                * req points to the first request where HWO changed from 0 to 1
                 */
                req = next_request(&dep->req_queued);
        }
@@ -819,9 +921,10 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
                /*
                 * FIXME we need to iterate over the list of requests
                 * here and stop, unmap, free and del each of the linked
-                * requests instead of we do now.
+                * requests instead of what we do now.
                 */
-               dwc3_unmap_buffer_from_dma(req);
+               usb_gadget_unmap_request(&dwc->gadget, &req->request,
+                               req->direction);
                list_del(&req->list);
                return ret;
        }
@@ -837,6 +940,9 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
 
 static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
 {
+       struct dwc3             *dwc = dep->dwc;
+       int                     ret;
+
        req->request.actual     = 0;
        req->request.status     = -EINPROGRESS;
        req->direction          = dep->direction;
@@ -852,9 +958,13 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
         * particular token from the Host side.
         *
         * This will also avoid Host cancelling URBs due to too
-        * many NACKs.
+        * many NAKs.
         */
-       dwc3_map_buffer_to_dma(req);
+       ret = usb_gadget_map_request(&dwc->gadget, &req->request,
+                       dep->direction);
+       if (ret)
+               return ret;
+
        list_add_tail(&req->list, &dep->request_list);
 
        /*
@@ -874,11 +984,11 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
                int start_trans;
 
                start_trans = 1;
-               if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
-                               dep->flags & DWC3_EP_BUSY)
+               if (usb_endpoint_xfer_isoc(dep->desc) &&
+                               (dep->flags & DWC3_EP_BUSY))
                        start_trans = 0;
 
-               ret =  __dwc3_gadget_kick_transfer(dep, 0, start_trans);
+               ret = __dwc3_gadget_kick_transfer(dep, 0, start_trans);
                if (ret && ret != -EBUSY) {
                        struct dwc3     *dwc = dep->dwc;
 
@@ -1031,8 +1141,12 @@ out:
 static int dwc3_gadget_ep_set_wedge(struct usb_ep *ep)
 {
        struct dwc3_ep                  *dep = to_dwc3_ep(ep);
+       struct dwc3                     *dwc = dep->dwc;
+       unsigned long                   flags;
 
+       spin_lock_irqsave(&dwc->lock, flags);
        dep->flags |= DWC3_EP_WEDGE;
+       spin_unlock_irqrestore(&dwc->lock, flags);
 
        return dwc3_gadget_ep_set_halt(ep, 1);
 }
@@ -1122,26 +1236,20 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g)
                goto out;
        }
 
-       reg = dwc3_readl(dwc->regs, DWC3_DCTL);
-
-       /*
-        * Switch link state to Recovery. In HS/FS/LS this means
-        * RemoteWakeup Request
-        */
-       reg |= DWC3_DCTL_ULSTCHNG_RECOVERY;
-       dwc3_writel(dwc->regs, DWC3_DCTL, reg);
-
-       /* wait for at least 2000us */
-       usleep_range(2000, 2500);
+       ret = dwc3_gadget_set_link_state(dwc, DWC3_LINK_STATE_RECOV);
+       if (ret < 0) {
+               dev_err(dwc->dev, "failed to put link in Recovery\n");
+               goto out;
+       }
 
        /* write zeroes to Link Change Request */
        reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK;
        dwc3_writel(dwc->regs, DWC3_DCTL, reg);
 
-       /* pool until Link State change to ON */
+       /* poll until Link State changes to ON */
        timeout = jiffies + msecs_to_jiffies(100);
 
-       while (!(time_after(jiffies, timeout))) {
+       while (!time_after(jiffies, timeout)) {
                reg = dwc3_readl(dwc->regs, DWC3_DSTS);
 
                /* in HS, means ON */
@@ -1164,8 +1272,11 @@ static int dwc3_gadget_set_selfpowered(struct usb_gadget *g,
                int is_selfpowered)
 {
        struct dwc3             *dwc = gadget_to_dwc(g);
+       unsigned long           flags;
 
+       spin_lock_irqsave(&dwc->lock, flags);
        dwc->is_selfpowered = !!is_selfpowered;
+       spin_unlock_irqrestore(&dwc->lock, flags);
 
        return 0;
 }
@@ -1176,10 +1287,13 @@ static void dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)
        u32                     timeout = 500;
 
        reg = dwc3_readl(dwc->regs, DWC3_DCTL);
-       if (is_on)
-               reg |= DWC3_DCTL_RUN_STOP;
-       else
+       if (is_on) {
+               reg &= ~DWC3_DCTL_TRGTULST_MASK;
+               reg |= (DWC3_DCTL_RUN_STOP
+                               | DWC3_DCTL_TRGTULST_RX_DET);
+       } else {
                reg &= ~DWC3_DCTL_RUN_STOP;
+       }
 
        dwc3_writel(dwc->regs, DWC3_DCTL, reg);
 
@@ -1386,7 +1500,7 @@ 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_trb         trb;
+       struct dwc3_trb         *trb;
        unsigned int            count;
        unsigned int            s_pkt = 0;
 
@@ -1397,20 +1511,20 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
                        return 1;
                }
 
-               dwc3_trb_to_nat(req->trb, &trb);
+               trb = req->trb;
 
-               if (trb.hwo && status != -ESHUTDOWN)
+               if ((trb->ctrl & DWC3_TRB_CTRL_HWO) && status != -ESHUTDOWN)
                        /*
                         * We continue despite the error. There is not much we
-                        * can do. If we don't clean in up we loop for ever. If
-                        * we skip the TRB than it gets overwritten reused after
-                        * a while since we use them in a ring buffer. a BUG()
-                        * would help. Lets hope that if this occures, someone
+                        * can do. If we don't clean it up we loop forever. If
+                        * we skip the TRB then it gets overwritten after a
+                        * while since we use them in a ring buffer. A BUG()
+                        * would help. Lets hope that if this occurs, someone
                         * fixes the root cause instead of looking away :)
                         */
                        dev_err(dwc->dev, "%s's TRB (%p) still owned by HW\n",
                                        dep->name, req->trb);
-               count = trb.length;
+               count = trb->size & DWC3_TRB_SIZE_MASK;
 
                if (dep->direction) {
                        if (count) {
@@ -1434,13 +1548,16 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
                dwc3_gadget_giveback(dep, req, status);
                if (s_pkt)
                        break;
-               if ((event->status & DEPEVT_STATUS_LST) && trb.lst)
+               if ((event->status & DEPEVT_STATUS_LST) &&
+                               (trb->ctrl & DWC3_TRB_CTRL_LST))
                        break;
-               if ((event->status & DEPEVT_STATUS_IOC) && trb.ioc)
+               if ((event->status & DEPEVT_STATUS_IOC) &&
+                               (trb->ctrl & DWC3_TRB_CTRL_IOC))
                        break;
        } while (1);
 
-       if ((event->status & DEPEVT_STATUS_IOC) && trb.ioc)
+       if ((event->status & DEPEVT_STATUS_IOC) &&
+                       (trb->ctrl & DWC3_TRB_CTRL_IOC))
                return 0;
        return 1;
 }
@@ -1455,11 +1572,9 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,
        if (event->status & DEPEVT_STATUS_BUSERR)
                status = -ECONNRESET;
 
-       clean_busy =  dwc3_cleanup_done_reqs(dwc, dep, event, status);
-       if (clean_busy) {
+       clean_busy = dwc3_cleanup_done_reqs(dwc, dep, event, status);
+       if (clean_busy)
                dep->flags &= ~DWC3_EP_BUSY;
-               dep->res_trans_idx = 0;
-       }
 
        /*
         * WORKAROUND: This is the 2nd half of U1/U2 -> U0 workaround.
@@ -1490,7 +1605,7 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,
 static void dwc3_gadget_start_isoc(struct dwc3 *dwc,
                struct dwc3_ep *dep, const struct dwc3_event_depevt *event)
 {
-       u32 uf;
+       u32 uf, mask;
 
        if (list_empty(&dep->request_list)) {
                dev_vdbg(dwc->dev, "ISOC ep %s run out for requests.\n",
@@ -1498,16 +1613,10 @@ static void dwc3_gadget_start_isoc(struct dwc3 *dwc,
                return;
        }
 
-       if (event->parameters) {
-               u32 mask;
-
-               mask = ~(dep->interval - 1);
-               uf = event->parameters & mask;
-               /* 4 micro frames in the future */
-               uf += dep->interval * 4;
-       } else {
-               uf = 0;
-       }
+       mask = ~(dep->interval - 1);
+       uf = event->parameters & mask;
+       /* 4 micro frames in the future */
+       uf += dep->interval * 4;
 
        __dwc3_gadget_kick_transfer(dep, uf, 1);
 }
@@ -1519,8 +1628,8 @@ static void dwc3_process_ep_cmd_complete(struct dwc3_ep *dep,
        struct dwc3_event_depevt mod_ev = *event;
 
        /*
-        * We were asked to remove one requests. It is possible that this
-        * request and a few other were started together and have the same
+        * We were asked to remove one request. It is possible that this
+        * request and a few others were started together and have the same
         * transfer index. Since we stopped the complete endpoint we don't
         * know how many requests were already completed (and not yet)
         * reported and how could be done (later). We purge them all until
@@ -1529,7 +1638,7 @@ static void dwc3_process_ep_cmd_complete(struct dwc3_ep *dep,
        mod_ev.status = DEPEVT_STATUS_LST;
        dwc3_cleanup_done_reqs(dwc, dep, &mod_ev, -ESHUTDOWN);
        dep->flags &= ~DWC3_EP_BUSY;
-       /* pending requets are ignored and are queued on XferNotReady */
+       /* pending requests are ignored and are queued on XferNotReady */
 }
 
 static void dwc3_ep_cmd_compl(struct dwc3_ep *dep,
@@ -1570,6 +1679,8 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
 
        switch (event->endpoint_event) {
        case DWC3_DEPEVT_XFERCOMPLETE:
+               dep->res_trans_idx = 0;
+
                if (usb_endpoint_xfer_isoc(dep->desc)) {
                        dev_dbg(dwc->dev, "%s is an Isochronous endpoint\n",
                                        dep->name);
@@ -1594,7 +1705,8 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
                        int ret;
 
                        dev_vdbg(dwc->dev, "%s: reason %s\n",
-                                       dep->name, event->status
+                                       dep->name, event->status &
+                                       DEPEVT_STATUS_TRANSFER_ACTIVE
                                        ? "Transfer Active"
                                        : "Transfer Not Active");
 
@@ -1805,6 +1917,7 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
        reg = dwc3_readl(dwc->regs, DWC3_DCTL);
        reg &= ~DWC3_DCTL_TSTCTRL_MASK;
        dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+       dwc->test_mode = false;
 
        dwc3_stop_active_transfers(dwc);
        dwc3_clear_stall_all_ep(dwc);
@@ -2082,7 +2195,8 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
        while (left > 0) {
                union dwc3_event event;
 
-               memcpy(&event.raw, (evt->buf + evt->lpos), sizeof(event.raw));
+               event.raw = *(u32 *) (evt->buf + evt->lpos);
+
                dwc3_process_event_entry(dwc, &event);
                /*
                 * XXX we wrap around correctly to the next entry as almost all
@@ -2123,7 +2237,7 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
 
 /**
  * dwc3_gadget_init - Initializes gadget related registers
- * @dwc: Pointer to out controller context structure
+ * @dwc: pointer to our controller context structure
  *
  * Returns 0 on success otherwise negative errno.
  */
@@ -2149,9 +2263,8 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc)
                goto err1;
        }
 
-       dwc->setup_buf = dma_alloc_coherent(dwc->dev,
-                       sizeof(*dwc->setup_buf) * 2,
-                       &dwc->setup_buf_addr, GFP_KERNEL);
+       dwc->setup_buf = kzalloc(sizeof(*dwc->setup_buf) * 2,
+                       GFP_KERNEL);
        if (!dwc->setup_buf) {
                dev_err(dwc->dev, "failed to allocate setup buffer\n");
                ret = -ENOMEM;
@@ -2242,8 +2355,7 @@ err4:
                        dwc->ep0_bounce_addr);
 
 err3:
-       dma_free_coherent(dwc->dev, sizeof(*dwc->setup_buf) * 2,
-                       dwc->setup_buf, dwc->setup_buf_addr);
+       kfree(dwc->setup_buf);
 
 err2:
        dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb),
@@ -2272,8 +2384,7 @@ void dwc3_gadget_exit(struct dwc3 *dwc)
        dma_free_coherent(dwc->dev, 512, dwc->ep0_bounce,
                        dwc->ep0_bounce_addr);
 
-       dma_free_coherent(dwc->dev, sizeof(*dwc->setup_buf) * 2,
-                       dwc->setup_buf, dwc->setup_buf_addr);
+       kfree(dwc->setup_buf);
 
        dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb),
                        dwc->ep0_trb, dwc->ep0_trb_addr);
index d97f467..a860008 100644 (file)
@@ -100,6 +100,9 @@ static inline void dwc3_gadget_move_request_queued(struct dwc3_request *req)
 void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
                int status);
 
+int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode);
+int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state);
+
 void dwc3_ep0_interrupt(struct dwc3 *dwc,
                const struct dwc3_event_depevt *event);
 void dwc3_ep0_out_start(struct dwc3 *dwc);
@@ -108,8 +111,6 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
 int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value);
 int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
                unsigned cmd, struct dwc3_gadget_ep_cmd_params *params);
-void dwc3_map_buffer_to_dma(struct dwc3_request *req);
-void dwc3_unmap_buffer_from_dma(struct dwc3_request *req);
 
 /**
  * dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW
index 7cfe211..b108d18 100644 (file)
@@ -53,7 +53,7 @@ int dwc3_host_init(struct dwc3 *dwc)
        struct platform_device  *xhci;
        int                     ret;
 
-       xhci = platform_device_alloc("xhci", -1);
+       xhci = platform_device_alloc("xhci-hcd", -1);
        if (!xhci) {
                dev_err(dwc->dev, "couldn't allocate xHCI device\n");
                ret = -ENOMEM;
index 7ecb68a..c14a397 100644 (file)
@@ -599,16 +599,29 @@ config USB_AUDIO
        depends on SND
        select SND_PCM
        help
-         Gadget Audio is compatible with USB Audio Class specification 1.0.
-         It will include at least one AudioControl interface, zero or more
-         AudioStream interface and zero or more MIDIStream interface.
-
-         Gadget Audio will use on-board ALSA (CONFIG_SND) audio card to
-         playback or capture audio stream.
+         This Gadget Audio driver is compatible with USB Audio Class
+         specification 2.0. It implements 1 AudioControl interface,
+         1 AudioStreaming Interface each for USB-OUT and USB-IN.
+         Number of channels, sample rate and sample size can be
+         specified as module parameters.
+         This driver doesn't expect any real Audio codec to be present
+         on the device - the audio streams are simply sinked to and
+         sourced from a virtual ALSA sound card created. The user-space
+         application may choose to do whatever it wants with the data
+         received from the USB Host and choose to provide whatever it
+         wants as audio data to the USB Host.
 
          Say "y" to link the driver statically, or "m" to build a
          dynamically linked module called "g_audio".
 
+config GADGET_UAC1
+       bool "UAC 1.0 (Legacy)"
+       depends on USB_AUDIO
+       help
+         If you instead want older UAC Spec-1.0 driver that also has audio
+         paths hardwired to the Audio codec chip on-board and doesn't work
+         without one.
+
 config USB_ETH
        tristate "Ethernet Gadget (with CDC Ethernet support)"
        depends on NET
@@ -685,7 +698,7 @@ config USB_G_NCM
        help
          This driver implements USB CDC NCM subclass standard. NCM is
          an advanced protocol for Ethernet encapsulation, allows grouping
-         of several ethernet frames into one USB transfer and diffferent
+         of several ethernet frames into one USB transfer and different
          alignment possibilities.
 
          Say "y" to link the driver statically, or "m" to build a
index c16ff55..2204a4c 100644 (file)
@@ -29,7 +29,7 @@
 
 /* Driver strings */
 #define UDC_MOD_DESCRIPTION            "AMD 5536 UDC - USB Device Controller"
-#define UDC_DRIVER_VERSION_STRING      "01.00.0206 - $Revision: #3 $"
+#define UDC_DRIVER_VERSION_STRING      "01.00.0206"
 
 /* system */
 #include <linux/module.h>
@@ -140,7 +140,7 @@ static DECLARE_TASKLET(disconnect_tasklet, udc_tasklet_disconnect,
 
 /* endpoint names used for print */
 static const char ep0_string[] = "ep0in";
-static const char *ep_string[] = {
+static const char *const ep_string[] = {
        ep0_string,
        "ep1in-int", "ep2in-bulk", "ep3in-bulk", "ep4in-bulk", "ep5in-bulk",
        "ep6in-bulk", "ep7in-bulk", "ep8in-bulk", "ep9in-bulk", "ep10in-bulk",
@@ -204,9 +204,8 @@ static void print_regs(struct udc *dev)
                DBG(dev, "DMA mode       = BF (buffer fill mode)\n");
                dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "BF");
        }
-       if (!use_dma) {
+       if (!use_dma)
                dev_info(&dev->pdev->dev, "FIFO mode\n");
-       }
        DBG(dev, "-------------------------------------------------------\n");
 }
 
@@ -445,6 +444,7 @@ static void ep_init(struct udc_regs __iomem *regs, struct udc_ep *ep)
 
        VDBG(ep->dev, "ep-%d reset\n", ep->num);
        ep->desc = NULL;
+       ep->ep.desc = NULL;
        ep->ep.ops = &udc_ep_ops;
        INIT_LIST_HEAD(&ep->queue);
 
@@ -569,9 +569,8 @@ udc_free_request(struct usb_ep *usbep, struct usb_request *usbreq)
                VDBG(ep->dev, "req->td_data=%p\n", req->td_data);
 
                /* free dma chain if created */
-               if (req->chain_len > 1) {
+               if (req->chain_len > 1)
                        udc_free_dma_chain(ep->dev, req);
-               }
 
                pci_pool_free(ep->dev->data_requests, req->td_data,
                                                        req->td_phys);
@@ -639,9 +638,8 @@ udc_txfifo_write(struct udc_ep *ep, struct usb_request *req)
                bytes = remaining;
 
        /* dwords first */
-       for (i = 0; i < bytes / UDC_DWORD_BYTES; i++) {
+       for (i = 0; i < bytes / UDC_DWORD_BYTES; i++)
                writel(*(buf + i), ep->txfifo);
-       }
 
        /* remaining bytes must be written by byte access */
        for (j = 0; j < bytes % UDC_DWORD_BYTES; j++) {
@@ -660,9 +658,8 @@ static int udc_rxfifo_read_dwords(struct udc *dev, u32 *buf, int dwords)
 
        VDBG(dev, "udc_read_dwords(): %d dwords\n", dwords);
 
-       for (i = 0; i < dwords; i++) {
+       for (i = 0; i < dwords; i++)
                *(buf + i) = readl(dev->rxfifo);
-       }
        return 0;
 }
 
@@ -675,9 +672,8 @@ static int udc_rxfifo_read_bytes(struct udc *dev, u8 *buf, int bytes)
        VDBG(dev, "udc_read_bytes(): %d bytes\n", bytes);
 
        /* dwords first */
-       for (i = 0; i < bytes / UDC_DWORD_BYTES; i++) {
+       for (i = 0; i < bytes / UDC_DWORD_BYTES; i++)
                *((u32 *)(buf + (i<<2))) = readl(dev->rxfifo);
-       }
 
        /* remaining bytes must be read by byte access */
        if (bytes % UDC_DWORD_BYTES) {
@@ -831,20 +827,8 @@ __acquires(ep->dev->lock)
 
        dev = ep->dev;
        /* unmap DMA */
-       if (req->dma_mapping) {
-               if (ep->in)
-                       pci_unmap_single(dev->pdev,
-                                       req->req.dma,
-                                       req->req.length,
-                                       PCI_DMA_TODEVICE);
-               else
-                       pci_unmap_single(dev->pdev,
-                                       req->req.dma,
-                                       req->req.length,
-                                       PCI_DMA_FROMDEVICE);
-               req->dma_mapping = 0;
-               req->req.dma = DMA_DONT_USE;
-       }
+       if (ep->dma)
+               usb_gadget_unmap_request(&dev->gadget, &req->req, ep->in);
 
        halted = ep->halted;
        ep->halted = 1;
@@ -897,9 +881,8 @@ static struct udc_data_dma *udc_get_last_dma_desc(struct udc_request *req)
        struct udc_data_dma     *td;
 
        td = req->td_data;
-       while (td && !(td->status & AMD_BIT(UDC_DMA_IN_STS_L))) {
+       while (td && !(td->status & AMD_BIT(UDC_DMA_IN_STS_L)))
                td = phys_to_virt(td->next);
-       }
 
        return td;
 
@@ -949,21 +932,18 @@ static int udc_create_dma_chain(
        dma_addr = DMA_DONT_USE;
 
        /* unset L bit in first desc for OUT */
-       if (!ep->in) {
+       if (!ep->in)
                req->td_data->status &= AMD_CLEAR_BIT(UDC_DMA_IN_STS_L);
-       }
 
        /* alloc only new desc's if not already available */
        len = req->req.length / ep->ep.maxpacket;
-       if (req->req.length % ep->ep.maxpacket) {
+       if (req->req.length % ep->ep.maxpacket)
                len++;
-       }
 
        if (len > req->chain_len) {
                /* shorter chain already allocated before */
-               if (req->chain_len > 1) {
+               if (req->chain_len > 1)
                        udc_free_dma_chain(ep->dev, req);
-               }
                req->chain_len = len;
                create_new_chain = 1;
        }
@@ -1006,11 +986,12 @@ static int udc_create_dma_chain(
 
                /* link td and assign tx bytes */
                if (i == buf_len) {
-                       if (create_new_chain) {
+                       if (create_new_chain)
                                req->td_data->next = dma_addr;
-                       } else {
-                               /* req->td_data->next = virt_to_phys(td); */
-                       }
+                       /*
+                       else
+                               req->td_data->next = virt_to_phys(td);
+                       */
                        /* write tx bytes */
                        if (ep->in) {
                                /* first desc */
@@ -1024,11 +1005,12 @@ static int udc_create_dma_chain(
                                                        UDC_DMA_IN_STS_TXBYTES);
                        }
                } else {
-                       if (create_new_chain) {
+                       if (create_new_chain)
                                last->next = dma_addr;
-                       } else {
-                               /* last->next = virt_to_phys(td); */
-                       }
+                       /*
+                       else
+                               last->next = virt_to_phys(td);
+                       */
                        if (ep->in) {
                                /* write tx bytes */
                                td->status = AMD_ADDBITS(td->status,
@@ -1095,20 +1077,11 @@ udc_queue(struct usb_ep *usbep, struct usb_request *usbreq, gfp_t gfp)
                return -ESHUTDOWN;
 
        /* map dma (usually done before) */
-       if (ep->dma && usbreq->length != 0
-                       && (usbreq->dma == DMA_DONT_USE || usbreq->dma == 0)) {
+       if (ep->dma) {
                VDBG(dev, "DMA map req %p\n", req);
-               if (ep->in)
-                       usbreq->dma = pci_map_single(dev->pdev,
-                                               usbreq->buf,
-                                               usbreq->length,
-                                               PCI_DMA_TODEVICE);
-               else
-                       usbreq->dma = pci_map_single(dev->pdev,
-                                               usbreq->buf,
-                                               usbreq->length,
-                                               PCI_DMA_FROMDEVICE);
-               req->dma_mapping = 1;
+               retval = usb_gadget_map_request(&udc->gadget, usbreq, ep->in);
+               if (retval)
+                       return retval;
        }
 
        VDBG(dev, "%s queue req %p, len %d req->td_data=%p buf %p\n",
@@ -1479,11 +1452,10 @@ static int startup_registers(struct udc *dev)
 
        /* program speed */
        tmp = readl(&dev->regs->cfg);
-       if (use_fullspeed) {
+       if (use_fullspeed)
                tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_FS, UDC_DEVCFG_SPD);
-       } else {
+       else
                tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_HS, UDC_DEVCFG_SPD);
-       }
        writel(tmp, &dev->regs->cfg);
 
        return 0;
@@ -1504,9 +1476,8 @@ static void udc_basic_init(struct udc *dev)
                mod_timer(&udc_timer, jiffies - 1);
        }
        /* stop poll stall timer */
-       if (timer_pending(&udc_pollstall_timer)) {
+       if (timer_pending(&udc_pollstall_timer))
                mod_timer(&udc_pollstall_timer, jiffies - 1);
-       }
        /* disable DMA */
        tmp = readl(&dev->regs->ctl);
        tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_RDE);
@@ -1540,11 +1511,10 @@ static void udc_setup_endpoints(struct udc *dev)
        /* read enum speed */
        tmp = readl(&dev->regs->sts);
        tmp = AMD_GETBITS(tmp, UDC_DEVSTS_ENUM_SPEED);
-       if (tmp == UDC_DEVSTS_ENUM_SPEED_HIGH) {
+       if (tmp == UDC_DEVSTS_ENUM_SPEED_HIGH)
                dev->gadget.speed = USB_SPEED_HIGH;
-       } else if (tmp == UDC_DEVSTS_ENUM_SPEED_FULL) {
+       else if (tmp == UDC_DEVSTS_ENUM_SPEED_FULL)
                dev->gadget.speed = USB_SPEED_FULL;
-       }
 
        /* set basic ep parameters */
        for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
@@ -1570,9 +1540,8 @@ static void udc_setup_endpoints(struct udc *dev)
                 * disabling ep interrupts when ENUM interrupt occurs but ep is
                 * not enabled by gadget driver
                 */
-               if (!ep->desc) {
+               if (!ep->desc)
                        ep_init(dev->regs, ep);
-               }
 
                if (use_dma) {
                        /*
@@ -1670,9 +1639,8 @@ static void udc_tasklet_disconnect(unsigned long par)
                spin_lock(&dev->lock);
 
                /* empty queues */
-               for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
+               for (tmp = 0; tmp < UDC_EP_NUM; tmp++)