]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge v3.9-rc5 into usb-next
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 1 Apr 2013 19:14:26 +0000 (12:14 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 1 Apr 2013 19:14:26 +0000 (12:14 -0700)
We want the fixes here as well.

Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
110 files changed:
Documentation/ABI/testing/sysfs-bus-usb
Documentation/devicetree/bindings/usb/ci13xxx-imx.txt
Documentation/devicetree/bindings/usb/ehci-omap.txt [new file with mode: 0644]
Documentation/devicetree/bindings/usb/ohci-omap3.txt [new file with mode: 0644]
Documentation/ioctl/ioctl-number.txt
Documentation/usb/power-management.txt
drivers/hid/usbhid/hid-core.c
drivers/net/usb/cdc_mbim.c
drivers/net/usb/qmi_wwan.c
drivers/net/usb/smsc75xx.c
drivers/net/usb/smsc95xx.c
drivers/staging/Kconfig
drivers/staging/Makefile
drivers/usb/chipidea/Makefile
drivers/usb/chipidea/ci.h
drivers/usb/chipidea/ci13xxx_imx.c
drivers/usb/chipidea/ci13xxx_imx.h
drivers/usb/chipidea/ci13xxx_pci.c
drivers/usb/chipidea/core.c
drivers/usb/chipidea/debug.c
drivers/usb/chipidea/debug.h
drivers/usb/chipidea/udc.c
drivers/usb/chipidea/usbmisc_imx.c [new file with mode: 0644]
drivers/usb/chipidea/usbmisc_imx6q.c [deleted file]
drivers/usb/class/cdc-acm.c
drivers/usb/class/cdc-wdm.c
drivers/usb/core/Kconfig
drivers/usb/core/driver.c
drivers/usb/core/generic.c
drivers/usb/core/hcd-pci.c
drivers/usb/core/hcd.c
drivers/usb/core/hub.c
drivers/usb/core/port.c
drivers/usb/core/quirks.c
drivers/usb/core/sysfs.c
drivers/usb/core/urb.c
drivers/usb/core/usb.c
drivers/usb/core/usb.h
drivers/usb/host/Kconfig
drivers/usb/host/Makefile
drivers/usb/host/ehci-dbg.c
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-hub.c
drivers/usb/host/ehci-mv.c
drivers/usb/host/ehci-mxc.c
drivers/usb/host/ehci-omap.c
drivers/usb/host/ehci-orion.c
drivers/usb/host/ehci-pci.c
drivers/usb/host/ehci-platform.c
drivers/usb/host/ehci-q.c
drivers/usb/host/ehci-s5p.c
drivers/usb/host/ehci-sched.c
drivers/usb/host/ehci-sh.c
drivers/usb/host/ehci-spear.c
drivers/usb/host/ehci-timer.c
drivers/usb/host/ehci-vt8500.c [deleted file]
drivers/usb/host/ehci.h
drivers/usb/host/ohci-hub.c
drivers/usb/host/ohci-omap3.c
drivers/usb/host/sl811-hcd.c
drivers/usb/host/u132-hcd.c
drivers/usb/host/xhci-hub.c
drivers/usb/host/xhci.c
drivers/usb/misc/sisusbvga/sisusb.c
drivers/usb/misc/usb3503.c
drivers/usb/otg/isp1301_omap.c
drivers/usb/otg/twl4030-usb.c
drivers/usb/otg/twl6030-usb.c
drivers/usb/phy/mv_u3d_phy.c
drivers/usb/serial/ark3116.c
drivers/usb/serial/bus.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/f81232.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/garmin_gps.c
drivers/usb/serial/generic.c
drivers/usb/serial/io_edgeport.c
drivers/usb/serial/io_tables.h
drivers/usb/serial/io_ti.c
drivers/usb/serial/iuu_phoenix.c
drivers/usb/serial/keyspan.c
drivers/usb/serial/keyspan_pda.c
drivers/usb/serial/kl5kusb105.c
drivers/usb/serial/mct_u232.c
drivers/usb/serial/metro-usb.c
drivers/usb/serial/mos7720.c
drivers/usb/serial/mos7840.c
drivers/usb/serial/opticon.c
drivers/usb/serial/oti6858.c
drivers/usb/serial/pl2303.c
drivers/usb/serial/quatech2.c
drivers/usb/serial/sierra.c
drivers/usb/serial/spcp8x5.c
drivers/usb/serial/ssu100.c
drivers/usb/serial/ti_usb_3410_5052.c
drivers/usb/serial/usb-serial.c
drivers/usb/serial/usb_wwan.c
drivers/usb/serial/visor.c
drivers/usb/storage/isd200.c
drivers/usb/storage/onetouch.c
drivers/usb/usb-skeleton.c
include/linux/usb.h
include/linux/usb/cdc-wdm.h
include/linux/usb/hcd.h
include/linux/usb/serial.h
include/uapi/linux/usb/cdc-wdm.h [new file with mode: 0644]

index c8baaf53594a862fb8be7fadd880cb534de8acea..f093e59cbe5f017531b74ce45dcc3d130ddfd44d 100644 (file)
@@ -32,7 +32,7 @@ Date:         January 2008
 KernelVersion: 2.6.25
 Contact:       Sarah Sharp <sarah.a.sharp@intel.com>
 Description:
-               If CONFIG_PM and CONFIG_USB_SUSPEND are enabled, then this file
+               If CONFIG_PM_RUNTIME is enabled then this file
                is present.  When read, it returns the total time (in msec)
                that the USB device has been connected to the machine.  This
                file is read-only.
@@ -45,7 +45,7 @@ Date:         January 2008
 KernelVersion: 2.6.25
 Contact:       Sarah Sharp <sarah.a.sharp@intel.com>
 Description:
-               If CONFIG_PM and CONFIG_USB_SUSPEND are enabled, then this file
+               If CONFIG_PM_RUNTIME is enabled then this file
                is present.  When read, it returns the total time (in msec)
                that the USB device has been active, i.e. not in a suspended
                state.  This file is read-only.
@@ -187,7 +187,7 @@ What:               /sys/bus/usb/devices/.../power/usb2_hardware_lpm
 Date:          September 2011
 Contact:       Andiry Xu <andiry.xu@amd.com>
 Description:
-               If CONFIG_USB_SUSPEND is set and a USB 2.0 lpm-capable device
+               If CONFIG_PM_RUNTIME is set and a USB 2.0 lpm-capable device
                is plugged in to a xHCI host which support link PM, it will
                perform a LPM test; if the test is passed and host supports
                USB2 hardware LPM (xHCI 1.0 feature), USB2 hardware LPM will
index 5778b9c83bd845692a4eda281ec842eb1864ac6e..1c04a4c9515f981e570fe778b748bfeb3d5b3e92 100644 (file)
@@ -11,6 +11,7 @@ Optional properties:
   that indicate usb controller index
 - vbus-supply: regulator for vbus
 - disable-over-current: disable over current detect
+- external-vbus-divider: enables off-chip resistor divider for Vbus
 
 Examples:
 usb@02184000 { /* USB OTG */
@@ -20,4 +21,5 @@ usb@02184000 { /* USB OTG */
        fsl,usbphy = <&usbphy1>;
        fsl,usbmisc = <&usbmisc 0>;
        disable-over-current;
+       external-vbus-divider;
 };
diff --git a/Documentation/devicetree/bindings/usb/ehci-omap.txt b/Documentation/devicetree/bindings/usb/ehci-omap.txt
new file mode 100644 (file)
index 0000000..485a9a1
--- /dev/null
@@ -0,0 +1,32 @@
+OMAP HS USB EHCI controller
+
+This device is usually the child of the omap-usb-host
+Documentation/devicetree/bindings/mfd/omap-usb-host.txt
+
+Required properties:
+
+- compatible: should be "ti,ehci-omap"
+- reg: should contain one register range i.e. start and length
+- interrupts: description of the interrupt line
+
+Optional properties:
+
+- phys: list of phandles to PHY nodes.
+  This property is required if at least one of the ports are in
+  PHY mode i.e. OMAP_EHCI_PORT_MODE_PHY
+
+To specify the port mode, see
+Documentation/devicetree/bindings/mfd/omap-usb-host.txt
+
+Example for OMAP4:
+
+usbhsehci: ehci@4a064c00 {
+       compatible = "ti,ehci-omap", "usb-ehci";
+       reg = <0x4a064c00 0x400>;
+       interrupts = <0 77 0x4>;
+};
+
+&usbhsehci {
+       phys = <&hsusb1_phy 0 &hsusb3_phy>;
+};
+
diff --git a/Documentation/devicetree/bindings/usb/ohci-omap3.txt b/Documentation/devicetree/bindings/usb/ohci-omap3.txt
new file mode 100644 (file)
index 0000000..14ab428
--- /dev/null
@@ -0,0 +1,15 @@
+OMAP HS USB OHCI controller (OMAP3 and later)
+
+Required properties:
+
+- compatible: should be "ti,ohci-omap3"
+- reg: should contain one register range i.e. start and length
+- interrupts: description of the interrupt line
+
+Example for OMAP4:
+
+usbhsohci: ohci@4a064800 {
+       compatible = "ti,ohci-omap3", "usb-ohci";
+       reg = <0x4a064800 0x400>;
+       interrupts = <0 76 0x4>;
+};
index 3210540f8bd355d3e8dd8171f6c71d932abc6df4..237acab169dd723b5a3f9ec3e40c79d55246f48a 100644 (file)
@@ -131,6 +131,7 @@ Code  Seq#(hex)     Include File            Comments
 'H'    40-4F   sound/hdspm.h           conflict!
 'H'    40-4F   sound/hdsp.h            conflict!
 'H'    90      sound/usb/usx2y/usb_stream.h
+'H'    A0      uapi/linux/usb/cdc-wdm.h
 'H'    C0-F0   net/bluetooth/hci.h     conflict!
 'H'    C0-DF   net/bluetooth/hidp/hidp.h       conflict!
 'H'    C0-DF   net/bluetooth/cmtp/cmtp.h       conflict!
index 4204eb01fd3839187da2d20654a39f1f9a134b7e..1392b61d6ebe59c87bbe616cc4a9796cba9a160f 100644 (file)
@@ -33,6 +33,10 @@ built with CONFIG_USB_SUSPEND enabled (which depends on
 CONFIG_PM_RUNTIME).  System PM support is present only if the kernel
 was built with CONFIG_SUSPEND or CONFIG_HIBERNATION enabled.
 
+(Starting with the 3.10 kernel release, dynamic PM support for USB is
+present whenever the kernel was built with CONFIG_PM_RUNTIME enabled.
+The CONFIG_USB_SUSPEND option has been eliminated.)
+
 
        What is Remote Wakeup?
        ----------------------
@@ -206,10 +210,8 @@ initialized to 5.  (The idle-delay values for already existing devices
 will not be affected.)
 
 Setting the initial default idle-delay to -1 will prevent any
-autosuspend of any USB device.  This is a simple alternative to
-disabling CONFIG_USB_SUSPEND and rebuilding the kernel, and it has the
-added benefit of allowing you to enable autosuspend for selected
-devices.
+autosuspend of any USB device.  This has the benefit of allowing you
+then to enable autosuspend for selected devices.
 
 
        Warnings
index 8e0c4bf94ebc44b8a3cf214bfd82b9000a7b874a..1f9e56bfeaa0499ee9522aa0813e5da43f36164a 100644 (file)
@@ -1493,7 +1493,7 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message)
 {
        struct hid_device *hid = usb_get_intfdata(intf);
        struct usbhid_device *usbhid = hid->driver_data;
-       int status;
+       int status = 0;
        bool driver_suspended = false;
 
        if (PMSG_IS_AUTO(message)) {
@@ -1520,19 +1520,15 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message)
                }
 
        } else {
-               if (hid->driver && hid->driver->suspend) {
+               /* TODO: resume() might need to handle suspend failure */
+               if (hid->driver && hid->driver->suspend)
                        status = hid->driver->suspend(hid, message);
-                       if (status < 0)
-                               return status;
-               }
                driver_suspended = true;
                spin_lock_irq(&usbhid->lock);
                set_bit(HID_SUSPENDED, &usbhid->iofl);
                spin_unlock_irq(&usbhid->lock);
-               if (usbhid_wait_io(hid) < 0) {
+               if (usbhid_wait_io(hid) < 0)
                        status = -EIO;
-                       goto failed;
-               }
        }
 
        hid_cancel_delayed_stuff(usbhid);
@@ -1544,7 +1540,7 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message)
                goto failed;
        }
        dev_dbg(&intf->dev, "suspend\n");
-       return 0;
+       return status;
 
  failed:
        hid_resume_common(hid, driver_suspended);
index 16c842997291483eb12306d9ccf0a638772f18f0..673e3624713e926256348d31a3b96778f7106a20 100644 (file)
@@ -323,6 +323,11 @@ static int cdc_mbim_suspend(struct usb_interface *intf, pm_message_t message)
                goto error;
        }
 
+       /*
+        * Both usbnet_suspend() and subdriver->suspend() MUST return 0
+        * in system sleep context, otherwise, the resume callback has
+        * to recover device from previous suspend failure.
+        */
        ret = usbnet_suspend(intf, message);
        if (ret < 0)
                goto error;
index 968d5d50751dc120b406f54fffca49b46eafa230..bdceb7411de3b2fb45e3a2f937e158f412deea5e 100644 (file)
@@ -271,6 +271,11 @@ static int qmi_wwan_suspend(struct usb_interface *intf, pm_message_t message)
        struct qmi_wwan_state *info = (void *)&dev->data;
        int ret;
 
+       /*
+        * Both usbnet_suspend() and subdriver->suspend() MUST return 0
+        * in system sleep context, otherwise, the resume callback has
+        * to recover device from previous suspend failure.
+        */
        ret = usbnet_suspend(intf, message);
        if (ret < 0)
                goto err;
index 9abe51710f229377cb9f405ffedb198eab580738..21b607ab86f2fa87855378c3e79b84475f8e07d8 100644 (file)
@@ -2011,7 +2011,11 @@ static int smsc75xx_suspend(struct usb_interface *intf, pm_message_t message)
        ret = smsc75xx_enter_suspend0(dev);
 
 done:
-       if (ret)
+       /*
+        * TODO: resume() might need to handle the suspend failure
+        * in system sleep
+        */
+       if (ret && PMSG_IS_AUTO(message))
                usbnet_resume(intf);
        return ret;
 }
index e6d2dea1373ce29fcd5275c2d84547c561ba20d0..3f38ba868f6182152093e8efad0a864439c5cef0 100644 (file)
@@ -1660,7 +1660,11 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
        ret = smsc95xx_enter_suspend0(dev);
 
 done:
-       if (ret)
+       /*
+        * TODO: resume() might need to handle the suspend failure
+        * in system sleep
+        */
+       if (ret && PMSG_IS_AUTO(message))
                usbnet_resume(intf);
        return ret;
 }
index 093f10c88ccef5cefb5905a4a7aa4a8aa1acde40..659855cecda5766cc7e2e7d384e91814f1313556 100644 (file)
@@ -116,8 +116,6 @@ source "drivers/staging/android/Kconfig"
 
 source "drivers/staging/ozwpan/Kconfig"
 
-source "drivers/staging/ccg/Kconfig"
-
 source "drivers/staging/gdm72xx/Kconfig"
 
 source "drivers/staging/csr/Kconfig"
index fa41b04cf4cb7e49a38af98dfa9fd0c519c5d940..b367ea876854b17d16c86e25f2a4a1a52310afaa 100644 (file)
@@ -50,7 +50,6 @@ obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4)  += ste_rmi4/
 obj-$(CONFIG_MFD_NVEC)         += nvec/
 obj-$(CONFIG_ANDROID)          += android/
 obj-$(CONFIG_USB_WPAN_HCD)     += ozwpan/
-obj-$(CONFIG_USB_G_CCG)                += ccg/
 obj-$(CONFIG_WIMAX_GDM72XX)    += gdm72xx/
 obj-$(CONFIG_CSR_WIFI)         += csr/
 obj-$(CONFIG_OMAP_BANDGAP)     += omap-thermal/
index d92ca325b104f9ccd6b7a27cf2b7177b443190c4..4ab83e98219b7b9c15ebcc78ca2716b650653574 100644 (file)
@@ -17,5 +17,5 @@ ifneq ($(CONFIG_PCI),)
 endif
 
 ifneq ($(CONFIG_OF_DEVICE),)
-       obj-$(CONFIG_USB_CHIPIDEA)      += ci13xxx_imx.o usbmisc_imx6q.o
+       obj-$(CONFIG_USB_CHIPIDEA)      += ci13xxx_imx.o usbmisc_imx.o
 endif
index e25d1263da13edd9cc8737030982cc9f81402105..b0a6bce064ca9a4f6ed7e4b19657165c48821686 100644 (file)
@@ -21,6 +21,7 @@
 /******************************************************************************
  * DEFINE
  *****************************************************************************/
+#define TD_PAGE_COUNT      5
 #define CI13XXX_PAGE_SIZE  4096ul /* page size for TD's */
 #define ENDPT_MAX          32
 
@@ -129,6 +130,7 @@ struct hw_bank {
  * @vbus_active: is VBUS active
  * @transceiver: pointer to USB PHY, if any
  * @hcd: pointer to usb_hcd for ehci host driver
+ * @debugfs: root dentry for this controller in debugfs
  */
 struct ci13xxx {
        struct device                   *dev;
@@ -139,7 +141,6 @@ struct ci13xxx {
        enum ci_role                    role;
        bool                            is_otg;
        struct work_struct              work;
-       struct work_struct              vbus_work;
        struct workqueue_struct         *wq;
 
        struct dma_pool                 *qh_pool;
@@ -165,6 +166,7 @@ struct ci13xxx {
        bool                            global_phy;
        struct usb_phy                  *transceiver;
        struct usb_hcd                  *hcd;
+       struct dentry                   *debugfs;
 };
 
 static inline struct ci_role_driver *ci_role(struct ci13xxx *ci)
@@ -233,19 +235,6 @@ enum ci13xxx_regs {
        OP_LAST = OP_ENDPTCTRL + ENDPT_MAX / 2,
 };
 
-/**
- * ffs_nr: find first (least significant) bit set
- * @x: the word to search
- *
- * This function returns bit number (instead of position)
- */
-static inline int ffs_nr(u32 x)
-{
-       int n = ffs(x);
-
-       return n ? n-1 : 32;
-}
-
 /**
  * hw_read: reads from a hw register
  * @reg:  register index
@@ -304,7 +293,7 @@ static inline u32 hw_test_and_write(struct ci13xxx *ci, enum ci13xxx_regs reg,
        u32 val = hw_read(ci, reg, ~0);
 
        hw_write(ci, reg, mask, data);
-       return (val & mask) >> ffs_nr(mask);
+       return (val & mask) >> __ffs(mask);
 }
 
 int hw_device_reset(struct ci13xxx *ci, u32 mode);
index 8c291220be7f9ffd1117eb0fe0bd0cc7b6df4a5b..8faec9dbbb84326d436ffc568451b322eb95a1a3 100644 (file)
@@ -79,6 +79,9 @@ int usbmisc_get_init_data(struct device *dev, struct usbmisc_usb_device *usbdev)
        if (of_find_property(np, "disable-over-current", NULL))
                usbdev->disable_oc = 1;
 
+       if (of_find_property(np, "external-vbus-divider", NULL))
+               usbdev->evdo = 1;
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(usbmisc_get_init_data);
@@ -202,6 +205,15 @@ static int ci13xxx_imx_probe(struct platform_device *pdev)
                goto err;
        }
 
+       if (usbmisc_ops && usbmisc_ops->post) {
+               ret = usbmisc_ops->post(&pdev->dev);
+               if (ret) {
+                       dev_err(&pdev->dev,
+                               "usbmisc post failed, ret=%d\n", ret);
+                       goto put_np;
+               }
+       }
+
        data->ci_pdev = plat_ci;
        platform_set_drvdata(pdev, data);
 
index 9cd2e910b1ca3ae03ecd5a1fa81f5204698d45bf..550bfa4576202c6f6f8f9c3f73ab8921971fd234 100644 (file)
@@ -13,6 +13,8 @@
 struct usbmisc_ops {
        /* It's called once when probe a usb device */
        int (*init)(struct device *dev);
+       /* It's called once after adding a usb device */
+       int (*post)(struct device *dev);
 };
 
 struct usbmisc_usb_device {
@@ -20,6 +22,7 @@ struct usbmisc_usb_device {
        int index;
 
        unsigned int disable_oc:1; /* over current detect disabled */
+       unsigned int evdo:1; /* set external vbus divider option */
 };
 
 int usbmisc_set_ops(const struct usbmisc_ops *ops);
index 9b227e39299af9bd4e51887c974c276eecb9fb30..4e1fc61b9d95201c5bfd119cd8be8f6e9b8db6ba 100644 (file)
 /******************************************************************************
  * PCI block
  *****************************************************************************/
-struct ci13xxx_platform_data pci_platdata = {
+static struct ci13xxx_platform_data pci_platdata = {
        .name           = UDC_DRIVER_NAME,
        .capoffset      = DEF_CAPOFFSET,
 };
 
-struct ci13xxx_platform_data langwell_pci_platdata = {
+static struct ci13xxx_platform_data langwell_pci_platdata = {
        .name           = UDC_DRIVER_NAME,
        .capoffset      = 0,
 };
 
-struct ci13xxx_platform_data penwell_pci_platdata = {
+static struct ci13xxx_platform_data penwell_pci_platdata = {
        .name           = UDC_DRIVER_NAME,
        .capoffset      = 0,
        .power_budget   = 200,
index 57cae1f897b21b7b4797e2ea54f7cfe51042618b..450107e5f657a32a3b7d5b0fd1e310a99e77ec66 100644 (file)
  */
 #include <linux/delay.h>
 #include <linux/device.h>
-#include <linux/dmapool.h>
 #include <linux/dma-mapping.h>
-#include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/module.h>
 #include <linux/idr.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
-#include <linux/irq.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/pm_runtime.h>
@@ -158,7 +155,7 @@ int hw_port_test_set(struct ci13xxx *ci, u8 mode)
        if (mode > TEST_MODE_MAX)
                return -EINVAL;
 
-       hw_write(ci, OP_PORTSC, PORTSC_PTC, mode << ffs_nr(PORTSC_PTC));
+       hw_write(ci, OP_PORTSC, PORTSC_PTC, mode << __ffs(PORTSC_PTC));
        return 0;
 }
 
@@ -169,7 +166,7 @@ int hw_port_test_set(struct ci13xxx *ci, u8 mode)
  */
 u8 hw_port_test_get(struct ci13xxx *ci)
 {
-       return hw_read(ci, OP_PORTSC, PORTSC_PTC) >> ffs_nr(PORTSC_PTC);
+       return hw_read(ci, OP_PORTSC, PORTSC_PTC) >> __ffs(PORTSC_PTC);
 }
 
 static int hw_device_init(struct ci13xxx *ci, void __iomem *base)
@@ -181,11 +178,11 @@ static int hw_device_init(struct ci13xxx *ci, void __iomem *base)
 
        ci->hw_bank.cap = ci->hw_bank.abs;
        ci->hw_bank.cap += ci->platdata->capoffset;
-       ci->hw_bank.op = ci->hw_bank.cap + ioread8(ci->hw_bank.cap);
+       ci->hw_bank.op = ci->hw_bank.cap + (ioread32(ci->hw_bank.cap) & 0xff);
 
        hw_alloc_regmap(ci, false);
        reg = hw_read(ci, CAP_HCCPARAMS, HCCPARAMS_LEN) >>
-               ffs_nr(HCCPARAMS_LEN);
+               __ffs(HCCPARAMS_LEN);
        ci->hw_bank.lpm  = reg;
        hw_alloc_regmap(ci, !!reg);
        ci->hw_bank.size = ci->hw_bank.op - ci->hw_bank.abs;
@@ -193,7 +190,7 @@ static int hw_device_init(struct ci13xxx *ci, void __iomem *base)
        ci->hw_bank.size /= sizeof(u32);
 
        reg = hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_DEN) >>
-               ffs_nr(DCCPARAMS_DEN);
+               __ffs(DCCPARAMS_DEN);
        ci->hw_ep_max = reg * 2;   /* cache hw ENDPT_MAX */
 
        if (ci->hw_ep_max > ENDPT_MAX)
@@ -283,38 +280,6 @@ static void ci_role_work(struct work_struct *work)
        }
 }
 
-static ssize_t show_role(struct device *dev, struct device_attribute *attr,
-                        char *buf)
-{
-       struct ci13xxx *ci = dev_get_drvdata(dev);
-
-       return sprintf(buf, "%s\n", ci_role(ci)->name);
-}
-
-static ssize_t store_role(struct device *dev, struct device_attribute *attr,
-                         const char *buf, size_t count)
-{
-       struct ci13xxx *ci = dev_get_drvdata(dev);
-       enum ci_role role;
-       int ret;
-
-       for (role = CI_ROLE_HOST; role < CI_ROLE_END; role++)
-               if (ci->roles[role] && !strcmp(buf, ci->roles[role]->name))
-                       break;
-
-       if (role == CI_ROLE_END || role == ci->role)
-               return -EINVAL;
-
-       ci_role_stop(ci);
-       ret = ci_role_start(ci, role);
-       if (ret)
-               return ret;
-
-       return count;
-}
-
-static DEVICE_ATTR(role, S_IRUSR | S_IWUSR, show_role, store_role);
-
 static irqreturn_t ci_irq(int irq, void *data)
 {
        struct ci13xxx *ci = data;
@@ -410,11 +375,9 @@ static int ci_hdrc_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       base = devm_request_and_ioremap(dev, res);
-       if (!base) {
-               dev_err(dev, "can't request and ioremap resource\n");
-               return -ENOMEM;
-       }
+       base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
 
        ci = devm_kzalloc(dev, sizeof(*ci), GFP_KERNEL);
        if (!ci) {
@@ -489,17 +452,14 @@ static int ci_hdrc_probe(struct platform_device *pdev)
        if (ret)
                goto stop;
 
-       ret = device_create_file(dev, &dev_attr_role);
-       if (ret)
-               goto rm_attr;
-
        if (ci->is_otg)
                hw_write(ci, OP_OTGSC, OTGSC_IDIE, OTGSC_IDIE);
 
-       return ret;
+       ret = dbg_create_files(ci);
+       if (!ret)
+               return 0;
 
-rm_attr:
-       device_remove_file(dev, &dev_attr_role);
+       free_irq(ci->irq, ci);
 stop:
        ci_role_stop(ci);
 rm_wq:
@@ -513,9 +473,9 @@ static int ci_hdrc_remove(struct platform_device *pdev)
 {
        struct ci13xxx *ci = platform_get_drvdata(pdev);
 
+       dbg_remove_files(ci);
        flush_workqueue(ci->wq);
        destroy_workqueue(ci->wq);
-       device_remove_file(ci->dev, &dev_attr_role);
        free_irq(ci->irq, ci);
        ci_role_stop(ci);
 
index a62c4a47d52c6685787ff01e174f67040241502f..36a7063a6cba04f55e1b25ea062f2896f9524dda 100644 (file)
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/dmapool.h>
-#include <linux/dma-mapping.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/irq.h>
 #include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/pm_runtime.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/uaccess.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
-#include <linux/usb/otg.h>
-#include <linux/usb/chipidea.h>
 
 #include "ci.h"
 #include "udc.h"
 #include "bits.h"
 #include "debug.h"
 
-/* Interrupt statistics */
-#define ISR_MASK   0x1F
-static struct isr_statistics {
-       u32 test;
-       u32 ui;
-       u32 uei;
-       u32 pci;
-       u32 uri;
-       u32 sli;
-       u32 none;
-       struct {
-               u32 cnt;
-               u32 buf[ISR_MASK+1];
-               u32 idx;
-       } hndl;
-} isr_statistics;
-
-void dbg_interrupt(u32 intmask)
-{
-       if (!intmask) {
-               isr_statistics.none++;
-               return;
-       }
-
-       isr_statistics.hndl.buf[isr_statistics.hndl.idx++] = intmask;
-       isr_statistics.hndl.idx &= ISR_MASK;
-       isr_statistics.hndl.cnt++;
-
-       if (USBi_URI & intmask)
-               isr_statistics.uri++;
-       if (USBi_PCI & intmask)
-               isr_statistics.pci++;
-       if (USBi_UEI & intmask)
-               isr_statistics.uei++;
-       if (USBi_UI  & intmask)
-               isr_statistics.ui++;
-       if (USBi_SLI & intmask)
-               isr_statistics.sli++;
-}
-
 /**
- * hw_register_read: reads all device registers (execute without interruption)
- * @buf:  destination buffer
- * @size: buffer size
- *
- * This function returns number of registers read
+ * ci_device_show: prints information about device capabilities and status
  */
-static size_t hw_register_read(struct ci13xxx *ci, u32 *buf, size_t size)
+static int ci_device_show(struct seq_file *s, void *data)
 {
-       unsigned i;
-
-       if (size > ci->hw_bank.size)
-               size = ci->hw_bank.size;
-
-       for (i = 0; i < size; i++)
-               buf[i] = hw_read(ci, i * sizeof(u32), ~0);
-
-       return size;
-}
-
-/**
- * hw_register_write: writes to register
- * @addr: register address
- * @data: register value
- *
- * This function returns an error code
- */
-static int hw_register_write(struct ci13xxx *ci, u16 addr, u32 data)
-{
-       /* align */
-       addr /= sizeof(u32);
-
-       if (addr >= ci->hw_bank.size)
-               return -EINVAL;
-
-       /* align */
-       addr *= sizeof(u32);
-
-       hw_write(ci, addr, ~0, data);
-       return 0;
-}
-
-/**
- * hw_intr_clear: disables interrupt & clears interrupt status (execute without
- *                interruption)
- * @n: interrupt bit
- *
- * This function returns an error code
- */
-static int hw_intr_clear(struct ci13xxx *ci, int n)
-{
-       if (n >= REG_BITS)
-               return -EINVAL;
-
-       hw_write(ci, OP_USBINTR, BIT(n), 0);
-       hw_write(ci, OP_USBSTS,  BIT(n), BIT(n));
-       return 0;
-}
-
-/**
- * hw_intr_force: enables interrupt & forces interrupt status (execute without
- *                interruption)
- * @n: interrupt bit
- *
- * This function returns an error code
- */
-static int hw_intr_force(struct ci13xxx *ci, int n)
-{
-       if (n >= REG_BITS)
-               return -EINVAL;
-
-       hw_write(ci, CAP_TESTMODE, TESTMODE_FORCE, TESTMODE_FORCE);
-       hw_write(ci, OP_USBINTR,  BIT(n), BIT(n));
-       hw_write(ci, OP_USBSTS,   BIT(n), BIT(n));
-       hw_write(ci, CAP_TESTMODE, TESTMODE_FORCE, 0);
-       return 0;
-}
-
-/**
- * show_device: prints information about device capabilities and status
- *
- * Check "device.h" for details
- */
-static ssize_t show_device(struct device *dev, struct device_attribute *attr,
-                          char *buf)
-{
-       struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
+       struct ci13xxx *ci = s->private;
        struct usb_gadget *gadget = &ci->gadget;
-       int n = 0;
 
-       if (attr == NULL || buf == NULL) {
-               dev_err(ci->dev, "[%s] EINVAL\n", __func__);
+       seq_printf(s, "speed             = %d\n", gadget->speed);
+       seq_printf(s, "max_speed         = %d\n", gadget->max_speed);
+       seq_printf(s, "is_otg            = %d\n", gadget->is_otg);
+       seq_printf(s, "is_a_peripheral   = %d\n", gadget->is_a_peripheral);
+       seq_printf(s, "b_hnp_enable      = %d\n", gadget->b_hnp_enable);
+       seq_printf(s, "a_hnp_support     = %d\n", gadget->a_hnp_support);
+       seq_printf(s, "a_alt_hnp_support = %d\n", gadget->a_alt_hnp_support);
+       seq_printf(s, "name              = %s\n",
+                  (gadget->name ? gadget->name : ""));
+
+       if (!ci->driver)
                return 0;
-       }
-
-       n += scnprintf(buf + n, PAGE_SIZE - n, "speed             = %d\n",
-                      gadget->speed);
-       n += scnprintf(buf + n, PAGE_SIZE - n, "max_speed         = %d\n",
-                      gadget->max_speed);
-       n += scnprintf(buf + n, PAGE_SIZE - n, "is_otg            = %d\n",
-                      gadget->is_otg);
-       n += scnprintf(buf + n, PAGE_SIZE - n, "is_a_peripheral   = %d\n",
-                      gadget->is_a_peripheral);
-       n += scnprintf(buf + n, PAGE_SIZE - n, "b_hnp_enable      = %d\n",
-                      gadget->b_hnp_enable);
-       n += scnprintf(buf + n, PAGE_SIZE - n, "a_hnp_support     = %d\n",
-                      gadget->a_hnp_support);
-       n += scnprintf(buf + n, PAGE_SIZE - n, "a_alt_hnp_support = %d\n",
-                      gadget->a_alt_hnp_support);
-       n += scnprintf(buf + n, PAGE_SIZE - n, "name              = %s\n",
-                      (gadget->name ? gadget->name : ""));
-
-       return n;
-}
-static DEVICE_ATTR(device, S_IRUSR, show_device, NULL);
-
-/**
- * show_driver: prints information about attached gadget (if any)
- *
- * Check "device.h" for details
- */
-static ssize_t show_driver(struct device *dev, struct device_attribute *attr,
-                          char *buf)
-{
-       struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
-       struct usb_gadget_driver *driver = ci->driver;
-       int n = 0;
-
-       if (attr == NULL || buf == NULL) {
-               dev_err(dev, "[%s] EINVAL\n", __func__);
-               return 0;
-       }
-
-       if (driver == NULL)
-               return scnprintf(buf, PAGE_SIZE,
-                                "There is no gadget attached!\n");
 
-       n += scnprintf(buf + n, PAGE_SIZE - n, "function  = %s\n",
-                      (driver->function ? driver->function : ""));
-       n += scnprintf(buf + n, PAGE_SIZE - n, "max speed = %d\n",
-                      driver->max_speed);
+       seq_printf(s, "gadget function   = %s\n",
+                      (ci->driver->function ? ci->driver->function : ""));
+       seq_printf(s, "gadget max speed  = %d\n", ci->driver->max_speed);
 
-       return n;
-}
-static DEVICE_ATTR(driver, S_IRUSR, show_driver, NULL);
-
-/* Maximum event message length */
-#define DBG_DATA_MSG   64UL
-
-/* Maximum event messages */
-#define DBG_DATA_MAX   128UL
-
-/* Event buffer descriptor */
-static struct {
-       char     (buf[DBG_DATA_MAX])[DBG_DATA_MSG];   /* buffer */
-       unsigned idx;   /* index */
-       unsigned tty;   /* print to console? */
-       rwlock_t lck;   /* lock */
-} dbg_data = {
-       .idx = 0,
-       .tty = 0,
-       .lck = __RW_LOCK_UNLOCKED(dbg_data.lck)
-};
-
-/**
- * dbg_dec: decrements debug event index
- * @idx: buffer index
- */
-static void dbg_dec(unsigned *idx)
-{
-       *idx = (*idx - 1) & (DBG_DATA_MAX-1);
-}
-
-/**
- * dbg_inc: increments debug event index
- * @idx: buffer index
- */
-static void dbg_inc(unsigned *idx)
-{
-       *idx = (*idx + 1) & (DBG_DATA_MAX-1);
-}
-
-/**
- * dbg_print:  prints the common part of the event
- * @addr:   endpoint address
- * @name:   event name
- * @status: status
- * @extra:  extra information
- */
-static void dbg_print(u8 addr, const char *name, int status, const char *extra)
-{
-       struct timeval tval;
-       unsigned int stamp;
-       unsigned long flags;
-
-       write_lock_irqsave(&dbg_data.lck, flags);
-
-       do_gettimeofday(&tval);
-       stamp = tval.tv_sec & 0xFFFF;   /* 2^32 = 4294967296. Limit to 4096s */
-       stamp = stamp * 1000000 + tval.tv_usec;
-
-       scnprintf(dbg_data.buf[dbg_data.idx], DBG_DATA_MSG,
-                 "%04X\t? %02X %-7.7s %4i ?\t%s\n",
-                 stamp, addr, name, status, extra);
-
-       dbg_inc(&dbg_data.idx);
-
-       write_unlock_irqrestore(&dbg_data.lck, flags);
-
-       if (dbg_data.tty != 0)
-               pr_notice("%04X\t? %02X %-7.7s %4i ?\t%s\n",
-                         stamp, addr, name, status, extra);
-}
-
-/**
- * dbg_done: prints a DONE event
- * @addr:   endpoint address
- * @td:     transfer descriptor
- * @status: status
- */
-void dbg_done(u8 addr, const u32 token, int status)
-{
-       char msg[DBG_DATA_MSG];
-
-       scnprintf(msg, sizeof(msg), "%d %02X",
-                 (int)(token & TD_TOTAL_BYTES) >> ffs_nr(TD_TOTAL_BYTES),
-                 (int)(token & TD_STATUS)      >> ffs_nr(TD_STATUS));
-       dbg_print(addr, "DONE", status, msg);
-}
-
-/**
- * dbg_event: prints a generic event
- * @addr:   endpoint address
- * @name:   event name
- * @status: status
- */
-void dbg_event(u8 addr, const char *name, int status)
-{
-       if (name != NULL)
-               dbg_print(addr, name, status, "");
-}
-
-/*
- * dbg_queue: prints a QUEUE event
- * @addr:   endpoint address
- * @req:    USB request
- * @status: status
- */
-void dbg_queue(u8 addr, const struct usb_request *req, int status)
-{
-       char msg[DBG_DATA_MSG];
-
-       if (req != NULL) {
-               scnprintf(msg, sizeof(msg),
-                         "%d %d", !req->no_interrupt, req->length);
-               dbg_print(addr, "QUEUE", status, msg);
-       }
-}
-
-/**
- * dbg_setup: prints a SETUP event
- * @addr: endpoint address
- * @req:  setup request
- */
-void dbg_setup(u8 addr, const struct usb_ctrlrequest *req)
-{
-       char msg[DBG_DATA_MSG];
-
-       if (req != NULL) {
-               scnprintf(msg, sizeof(msg),
-                         "%02X %02X %04X %04X %d", req->bRequestType,
-                         req->bRequest, le16_to_cpu(req->wValue),
-                         le16_to_cpu(req->wIndex), le16_to_cpu(req->wLength));
-               dbg_print(addr, "SETUP", 0, msg);
-       }
+       return 0;
 }
 
-/**
- * show_events: displays the event buffer
- *
- * Check "device.h" for details
- */
-static ssize_t show_events(struct device *dev, struct device_attribute *attr,
-                          char *buf)
+static int ci_device_open(struct inode *inode, struct file *file)
 {
-       unsigned long flags;
-       unsigned i, j, n = 0;
-
-       if (attr == NULL || buf == NULL) {
-               dev_err(dev->parent, "[%s] EINVAL\n", __func__);
-               return 0;
-       }
-
-       read_lock_irqsave(&dbg_data.lck, flags);
-
-       i = dbg_data.idx;
-       for (dbg_dec(&i); i != dbg_data.idx; dbg_dec(&i)) {
-               n += strlen(dbg_data.buf[i]);
-               if (n >= PAGE_SIZE) {
-                       n -= strlen(dbg_data.buf[i]);
-                       break;
-               }
-       }
-       for (j = 0, dbg_inc(&i); j < n; dbg_inc(&i))
-               j += scnprintf(buf + j, PAGE_SIZE - j,
-                              "%s", dbg_data.buf[i]);
-
-       read_unlock_irqrestore(&dbg_data.lck, flags);
-
-       return n;
+       return single_open(file, ci_device_show, inode->i_private);
 }
 
-/**
- * store_events: configure if events are going to be also printed to console
- *
- * Check "device.h" for details
- */
-static ssize_t store_events(struct device *dev, struct device_attribute *attr,
-                           const char *buf, size_t count)
-{
-       unsigned tty;
-
-       if (attr == NULL || buf == NULL) {
-               dev_err(dev, "[%s] EINVAL\n", __func__);
-               goto done;
-       }
-
-       if (sscanf(buf, "%u", &tty) != 1 || tty > 1) {
-               dev_err(dev, "<1|0>: enable|disable console log\n");
-               goto done;
-       }
-
-       dbg_data.tty = tty;
-       dev_info(dev, "tty = %u", dbg_data.tty);
-
- done:
-       return count;
-}
-static DEVICE_ATTR(events, S_IRUSR | S_IWUSR, show_events, store_events);
+static const struct file_operations ci_device_fops = {
+       .open           = ci_device_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
 
 /**
- * show_inters: interrupt status, enable status and historic
- *
- * Check "device.h" for details
+ * ci_port_test_show: reads port test mode
  */
-static ssize_t show_inters(struct device *dev, struct device_attribute *attr,
-                          char *buf)
+static int ci_port_test_show(struct seq_file *s, void *data)
 {
-       struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
+       struct ci13xxx *ci = s->private;
        unsigned long flags;
-       u32 intr;
-       unsigned i, j, n = 0;
-
-       if (attr == NULL || buf == NULL) {
-               dev_err(ci->dev, "[%s] EINVAL\n", __func__);
-               return 0;
-       }
+       unsigned mode;
 
        spin_lock_irqsave(&ci->lock, flags);
-
-       /*n += scnprintf(buf + n, PAGE_SIZE - n,
-                      "status = %08x\n", hw_read_intr_status(ci));
-       n += scnprintf(buf + n, PAGE_SIZE - n,
-       "enable = %08x\n", hw_read_intr_enable(ci));*/
-
-       n += scnprintf(buf + n, PAGE_SIZE - n, "*test = %d\n",
-                      isr_statistics.test);
-       n += scnprintf(buf + n, PAGE_SIZE - n, "? ui  = %d\n",
-                      isr_statistics.ui);
-       n += scnprintf(buf + n, PAGE_SIZE - n, "? uei = %d\n",
-                      isr_statistics.uei);
-       n += scnprintf(buf + n, PAGE_SIZE - n, "? pci = %d\n",
-                      isr_statistics.pci);
-       n += scnprintf(buf + n, PAGE_SIZE - n, "? uri = %d\n",
-                      isr_statistics.uri);
-       n += scnprintf(buf + n, PAGE_SIZE - n, "? sli = %d\n",
-                      isr_statistics.sli);
-       n += scnprintf(buf + n, PAGE_SIZE - n, "*none = %d\n",
-                      isr_statistics.none);
-       n += scnprintf(buf + n, PAGE_SIZE - n, "*hndl = %d\n",
-                      isr_statistics.hndl.cnt);
-
-       for (i = isr_statistics.hndl.idx, j = 0; j <= ISR_MASK; j++, i++) {
-               i   &= ISR_MASK;
-               intr = isr_statistics.hndl.buf[i];
-
-               if (USBi_UI  & intr)
-                       n += scnprintf(buf + n, PAGE_SIZE - n, "ui  ");
-               intr &= ~USBi_UI;
-               if (USBi_UEI & intr)
-                       n += scnprintf(buf + n, PAGE_SIZE - n, "uei ");
-               intr &= ~USBi_UEI;
-               if (USBi_PCI & intr)
-                       n += scnprintf(buf + n, PAGE_SIZE - n, "pci ");
-               intr &= ~USBi_PCI;
-               if (USBi_URI & intr)
-                       n += scnprintf(buf + n, PAGE_SIZE - n, "uri ");
-               intr &= ~USBi_URI;
-               if (USBi_SLI & intr)
-                       n += scnprintf(buf + n, PAGE_SIZE - n, "sli ");
-               intr &= ~USBi_SLI;
-               if (intr)
-                       n += scnprintf(buf + n, PAGE_SIZE - n, "??? ");
-               if (isr_statistics.hndl.buf[i])
-                       n += scnprintf(buf + n, PAGE_SIZE - n, "\n");
-       }
-
+       mode = hw_port_test_get(ci);
        spin_unlock_irqrestore(&ci->lock, flags);
 
-       return n;
-}
-
-/**
- * store_inters: enable & force or disable an individual interrutps
- *                   (to be used for test purposes only)
- *
- * Check "device.h" for details
- */
-static ssize_t store_inters(struct device *dev, struct device_attribute *attr,
-                           const char *buf, size_t count)
-{
-       struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
-       unsigned long flags;
-       unsigned en, bit;
-
-       if (attr == NULL || buf == NULL) {
-               dev_err(ci->dev, "EINVAL\n");
-               goto done;
-       }
+       seq_printf(s, "mode = %u\n", mode);
 
-       if (sscanf(buf, "%u %u", &en, &bit) != 2 || en > 1) {
-               dev_err(ci->dev, "<1|0> <bit>: enable|disable interrupt\n");
-               goto done;
-       }
-
-       spin_lock_irqsave(&ci->lock, flags);
-       if (en) {
-               if (hw_intr_force(ci, bit))
-                       dev_err(dev, "invalid bit number\n");
-               else
-                       isr_statistics.test++;
-       } else {
-               if (hw_intr_clear(ci, bit))
-                       dev_err(dev, "invalid bit number\n");
-       }
-       spin_unlock_irqrestore(&ci->lock, flags);
-
- done:
-       return count;
+       return 0;
 }
-static DEVICE_ATTR(inters, S_IRUSR | S_IWUSR, show_inters, store_inters);
 
 /**
- * show_port_test: reads port test mode
- *
- * Check "device.h" for details
+ * ci_port_test_write: writes port test mode
  */
-static ssize_t show_port_test(struct device *dev,
-                             struct device_attribute *attr, char *buf)
+static ssize_t ci_port_test_write(struct file *file, const char __user *ubuf,
+                                 size_t count, loff_t *ppos)
 {
-       struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
+       struct seq_file *s = file->private_data;
+       struct ci13xxx *ci = s->private;
        unsigned long flags;
        unsigned mode;
+       char buf[32];
+       int ret;
 
-       if (attr == NULL || buf == NULL) {
-               dev_err(ci->dev, "EINVAL\n");
-               return 0;
-       }
+       if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+               return -EFAULT;
+
+       if (sscanf(buf, "%u", &mode) != 1)
+               return -EINVAL;
 
        spin_lock_irqsave(&ci->lock, flags);
-       mode = hw_port_test_get(ci);
+       ret = hw_port_test_set(ci, mode);
        spin_unlock_irqrestore(&ci->lock, flags);
 
-       return scnprintf(buf, PAGE_SIZE, "mode = %u\n", mode);
+       return ret ? ret : count;
 }
 
-/**
- * store_port_test: writes port test mode
- *
- * Check "device.h" for details
- */
-static ssize_t store_port_test(struct device *dev,
-                              struct device_attribute *attr,
-                              const char *buf, size_t count)
+static int ci_port_test_open(struct inode *inode, struct file *file)
 {
-       struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
-       unsigned long flags;
-       unsigned mode;
-
-       if (attr == NULL || buf == NULL) {
-               dev_err(ci->dev, "[%s] EINVAL\n", __func__);
-               goto done;
-       }
-
-       if (sscanf(buf, "%u", &mode) != 1) {
-               dev_err(ci->dev, "<mode>: set port test mode");
-               goto done;
-       }
-
-       spin_lock_irqsave(&ci->lock, flags);
-       if (hw_port_test_set(ci, mode))
-               dev_err(ci->dev, "invalid mode\n");
-       spin_unlock_irqrestore(&ci->lock, flags);
-
- done:
-       return count;
+       return single_open(file, ci_port_test_show, inode->i_private);
 }
-static DEVICE_ATTR(port_test, S_IRUSR | S_IWUSR,
-                  show_port_test, store_port_test);
+
+static const struct file_operations ci_port_test_fops = {
+       .open           = ci_port_test_open,
+       .write          = ci_port_test_write,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
 
 /**
- * show_qheads: DMA contents of all queue heads
- *
- * Check "device.h" for details
+ * ci_qheads_show: DMA contents of all queue heads
  */
-static ssize_t show_qheads(struct device *dev, struct device_attribute *attr,
-                          char *buf)
+static int ci_qheads_show(struct seq_file *s, void *data)
 {
-       struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
+       struct ci13xxx *ci = s->private;
        unsigned long flags;
-       unsigned i, j, n = 0;
+       unsigned i, j;
 
-       if (attr == NULL || buf == NULL) {
-               dev_err(ci->dev, "[%s] EINVAL\n", __func__);
+       if (ci->role != CI_ROLE_GADGET) {
+               seq_printf(s, "not in gadget mode\n");
                return 0;
        }
 
@@ -593,209 +129,173 @@ static ssize_t show_qheads(struct device *dev, struct device_attribute *attr,
                struct ci13xxx_ep *mEpRx = &ci->ci13xxx_ep[i];
                struct ci13xxx_ep *mEpTx =
                        &ci->ci13xxx_ep[i + ci->hw_ep_max/2];
-               n += scnprintf(buf + n, PAGE_SIZE - n,
-                              "EP=%02i: RX=%08X TX=%08X\n",
-                              i, (u32)mEpRx->qh.dma, (u32)mEpTx->qh.dma);
-               for (j = 0; j < (sizeof(struct ci13xxx_qh)/sizeof(u32)); j++) {
-                       n += scnprintf(buf + n, PAGE_SIZE - n,
-                                      " %04X:    %08X    %08X\n", j,
-                                      *((u32 *)mEpRx->qh.ptr + j),
-                                      *((u32 *)mEpTx->qh.ptr + j));
-               }
+               seq_printf(s, "EP=%02i: RX=%08X TX=%08X\n",
+                          i, (u32)mEpRx->qh.dma, (u32)mEpTx->qh.dma);
+               for (j = 0; j < (sizeof(struct ci13xxx_qh)/sizeof(u32)); j++)
+                       seq_printf(s, " %04X:    %08X    %08X\n", j,
+                                  *((u32 *)mEpRx->qh.ptr + j),
+                                  *((u32 *)mEpTx->qh.ptr + j));
        }
        spin_unlock_irqrestore(&ci->lock, flags);
 
-       return n;
+       return 0;
+}
+
+static int ci_qheads_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, ci_qheads_show, inode->i_private);
 }
-static DEVICE_ATTR(qheads, S_IRUSR, show_qheads, NULL);
+
+static const struct file_operations ci_qheads_fops = {
+       .open           = ci_qheads_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
 
 /**
- * show_registers: dumps all registers
- *
- * Check "device.h" for details
+ * ci_requests_show: DMA contents of all requests currently queued (all endpts)
  */
-#define DUMP_ENTRIES   512
-static ssize_t show_registers(struct device *dev,
-                             struct device_attribute *attr, char *buf)
+static int ci_requests_show(struct seq_file *s, void *data)
 {
-       struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
+       struct ci13xxx *ci = s->private;
        unsigned long flags;
-       u32 *dump;
-       unsigned i, k, n = 0;
-
-       if (attr == NULL || buf == NULL) {
-               dev_err(ci->dev, "[%s] EINVAL\n", __func__);
-               return 0;
-       }
+       struct list_head   *ptr = NULL;
+       struct ci13xxx_req *req = NULL;
+       unsigned i, j, qsize = sizeof(struct ci13xxx_td)/sizeof(u32);
 
-       dump = kmalloc(sizeof(u32) * DUMP_ENTRIES, GFP_KERNEL);
-       if (!dump) {
-               dev_err(ci->dev, "%s: out of memory\n", __func__);
+       if (ci->role != CI_ROLE_GADGET) {
+               seq_printf(s, "not in gadget mode\n");
                return 0;
        }
 
        spin_lock_irqsave(&ci->lock, flags);
-       k = hw_register_read(ci, dump, DUMP_ENTRIES);
-       spin_unlock_irqrestore(&ci->lock, flags);
+       for (i = 0; i < ci->hw_ep_max; i++)
+               list_for_each(ptr, &ci->ci13xxx_ep[i].qh.queue) {
+                       req = list_entry(ptr, struct ci13xxx_req, queue);
 
-       for (i = 0; i < k; i++) {
-               n += scnprintf(buf + n, PAGE_SIZE - n,
-                              "reg[0x%04X] = 0x%08X\n",
-                              i * (unsigned)sizeof(u32), dump[i]);
-       }
-       kfree(dump);
+                       seq_printf(s, "EP=%02i: TD=%08X %s\n",
+                                  i % (ci->hw_ep_max / 2), (u32)req->dma,
+                                  ((i < ci->hw_ep_max/2) ? "RX" : "TX"));
+
+                       for (j = 0; j < qsize; j++)
+                               seq_printf(s, " %04X:    %08X\n", j,
+                                          *((u32 *)req->ptr + j));
+               }
+       spin_unlock_irqrestore(&ci->lock, flags);
 
-       return n;
+       return 0;
 }
 
-/**
- * store_registers: writes value to register address
- *
- * Check "device.h" for details
- */
-static ssize_t store_registers(struct device *dev,
-                              struct device_attribute *attr,
-                              const char *buf, size_t count)
+static int ci_requests_open(struct inode *inode, struct file *file)
 {
-       struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
-       unsigned long addr, data, flags;
+       return single_open(file, ci_requests_show, inode->i_private);
+}
 
-       if (attr == NULL || buf == NULL) {
-               dev_err(ci->dev, "[%s] EINVAL\n", __func__);
-               goto done;
-       }
+static const struct file_operations ci_requests_fops = {
+       .open           = ci_requests_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
 
-       if (sscanf(buf, "%li %li", &addr, &data) != 2) {
-               dev_err(ci->dev,
-                       "<addr> <data>: write data to register address\n");
-               goto done;
-       }
+static int ci_role_show(struct seq_file *s, void *data)
+{
+       struct ci13xxx *ci = s->private;
 
-       spin_lock_irqsave(&ci->lock, flags);
-       if (hw_register_write(ci, addr, data))
-               dev_err(ci->dev, "invalid address range\n");
-       spin_unlock_irqrestore(&ci->lock, flags);
+       seq_printf(s, "%s\n", ci_role(ci)->name);
 
- done:
-       return count;
+       return 0;
 }
-static DEVICE_ATTR(registers, S_IRUSR | S_IWUSR,
-                  show_registers, store_registers);
 
-/**
- * show_requests: DMA contents of all requests currently queued (all endpts)
- *
- * Check "device.h" for details
- */
-static ssize_t show_requests(struct device *dev, struct device_attribute *attr,
-                            char *buf)
+static ssize_t ci_role_write(struct file *file, const char __user *ubuf,
+                            size_t count, loff_t *ppos)
 {
-       struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
-       unsigned long flags;
-       struct list_head   *ptr = NULL;
-       struct ci13xxx_req *req = NULL;
-       unsigned i, j, n = 0, qSize = sizeof(struct ci13xxx_td)/sizeof(u32);
-
-       if (attr == NULL || buf == NULL) {
-               dev_err(ci->dev, "[%s] EINVAL\n", __func__);
-               return 0;
-       }
+       struct seq_file *s = file->private_data;
+       struct ci13xxx *ci = s->private;
+       enum ci_role role;
+       char buf[8];
+       int ret;
+
+       if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+               return -EFAULT;
+
+       for (role = CI_ROLE_HOST; role < CI_ROLE_END; role++)
+               if (ci->roles[role] &&
+                   !strncmp(buf, ci->roles[role]->name,
+                            strlen(ci->roles[role]->name)))
+                       break;
 
-       spin_lock_irqsave(&ci->lock, flags);
-       for (i = 0; i < ci->hw_ep_max; i++)
-               list_for_each(ptr, &ci->ci13xxx_ep[i].qh.queue)
-               {
-                       req = list_entry(ptr, struct ci13xxx_req, queue);
+       if (role == CI_ROLE_END || role == ci->role)
+               return -EINVAL;
 
-                       n += scnprintf(buf + n, PAGE_SIZE - n,
-                                       "EP=%02i: TD=%08X %s\n",
-                                       i % ci->hw_ep_max/2, (u32)req->dma,
-                                       ((i < ci->hw_ep_max/2) ? "RX" : "TX"));
+       ci_role_stop(ci);
+       ret = ci_role_start(ci, role);
 
-                       for (j = 0; j < qSize; j++)
-                               n += scnprintf(buf + n, PAGE_SIZE - n,
-                                               " %04X:    %08X\n", j,
-                                               *((u32 *)req->ptr + j));
-               }
-       spin_unlock_irqrestore(&ci->lock, flags);
+       return ret ? ret : count;
+}
 
-       return n;
+static int ci_role_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, ci_role_show, inode->i_private);
 }
-static DEVICE_ATTR(requests, S_IRUSR, show_requests, NULL);
+
+static const struct file_operations ci_role_fops = {
+       .open           = ci_role_open,
+       .write          = ci_role_write,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
 
 /**
  * dbg_create_files: initializes the attribute interface
- * @dev: device
+ * @ci: device
  *
  * This function returns an error code
  */
-int dbg_create_files(struct device *dev)
+int dbg_create_files(struct ci13xxx *ci)
 {
-       int retval = 0;
-
-       if (dev == NULL)
-               return -EINVAL;
-       retval = device_create_file(dev, &dev_attr_device);
-       if (retval)
-               goto done;
-       retval = device_create_file(dev, &dev_attr_driver);
-       if (retval)
-               goto rm_device;
-       retval = device_create_file(dev, &dev_attr_events);
-       if (retval)
-               goto rm_driver;
-       retval = device_create_file(dev, &dev_attr_inters);
-       if (retval)
-               goto rm_events;
-       retval = device_create_file(dev, &dev_attr_port_test);
-       if (retval)
-               goto rm_inters;
-       retval = device_create_file(dev, &dev_attr_qheads);
-       if (retval)
-               goto rm_port_test;
-       retval = device_create_file(dev, &dev_attr_registers);
-       if (retval)
-               goto rm_qheads;
-       retval = device_create_file(dev, &dev_attr_requests);
-       if (retval)
-               goto rm_registers;
-       return 0;
-
- rm_registers:
-       device_remove_file(dev, &dev_attr_registers);
- rm_qheads:
-       device_remove_file(dev, &dev_attr_qheads);
- rm_port_test:
-       device_remove_file(dev, &dev_attr_port_test);
- rm_inters:
-       device_remove_file(dev, &dev_attr_inters);
- rm_events:
-       device_remove_file(dev, &dev_attr_events);
- rm_driver:
-       device_remove_file(dev, &dev_attr_driver);
- rm_device:
-       device_remove_file(dev, &dev_attr_device);
- done:
-       return retval;
+       struct dentry *dent;
+
+       ci->debugfs = debugfs_create_dir(dev_name(ci->dev), NULL);
+       if (!ci->debugfs)
+               return -ENOMEM;
+
+       dent = debugfs_create_file("device", S_IRUGO, ci->debugfs, ci,
+                                  &ci_device_fops);
+       if (!dent)
+               goto err;
+
+       dent = debugfs_create_file("port_test", S_IRUGO | S_IWUSR, ci->debugfs,
+                                  ci, &ci_port_test_fops);
+       if (!dent)
+               goto err;
+
+       dent = debugfs_create_file("qheads", S_IRUGO, ci->debugfs, ci,
+                                  &ci_qheads_fops);
+       if (!dent)
+               goto err;
+
+       dent = debugfs_create_file("requests", S_IRUGO, ci->debugfs, ci,
+                                  &ci_requests_fops);
+       if (!dent)
+               goto err;
+
+       dent = debugfs_create_file("role", S_IRUGO | S_IWUSR, ci->debugfs, ci,
+                                  &ci_role_fops);
+       if (dent)
+               return 0;
+err:
+       debugfs_remove_recursive(ci->debugfs);
+       return -ENOMEM;
 }
 
 /**
  * dbg_remove_files: destroys the attribute interface
- * @dev: device
- *
- * This function returns an error code
+ * @ci: device
  */
-int dbg_remove_files(struct device *dev)
+void dbg_remove_files(struct ci13xxx *ci)
 {
-       if (dev == NULL)
-               return -EINVAL;
-       device_remove_file(dev, &dev_attr_requests);
-       device_remove_file(dev, &dev_attr_registers);
-       device_remove_file(dev, &dev_attr_qheads);
-       device_remove_file(dev, &dev_attr_port_test);
-       device_remove_file(dev, &dev_attr_inters);
-       device_remove_file(dev, &dev_attr_events);
-       device_remove_file(dev, &dev_attr_driver);
-       device_remove_file(dev, &dev_attr_device);
-       return 0;
+       debugfs_remove_recursive(ci->debugfs);
 }
index 80d96865775c6e3b3bb28be933baa12e610e11eb..7ca6ca0a24a5056726c1c9af68baa3c34410c744 100644 (file)
 #define __DRIVERS_USB_CHIPIDEA_DEBUG_H
 
 #ifdef CONFIG_USB_CHIPIDEA_DEBUG
-void dbg_interrupt(u32 intmask);
-void dbg_done(u8 addr, const u32 token, int status);
-void dbg_event(u8 addr, const char *name, int status);
-void dbg_queue(u8 addr, const struct usb_request *req, int status);
-void dbg_setup(u8 addr, const struct usb_ctrlrequest *req);
-int dbg_create_files(struct device *dev);
-int dbg_remove_files(struct device *dev);
+int dbg_create_files(struct ci13xxx *ci);
+void dbg_remove_files(struct ci13xxx *ci);
 #else
-static inline void dbg_interrupt(u32 intmask)
-{
-}
-
-static inline void dbg_done(u8 addr, const u32 token, int status)
-{
-}
-
-static inline void dbg_event(u8 addr, const char *name, int status)
-{
-}
-
-static inline void dbg_queue(u8 addr, const struct usb_request *req, int status)
-{
-}
-
-static inline void dbg_setup(u8 addr, const struct usb_ctrlrequest *req)
-{
-}
-
-static inline int dbg_create_files(struct device *dev)
+static inline int dbg_create_files(struct ci13xxx *ci)
 {
        return 0;
 }
 
-static inline int dbg_remove_files(struct device *dev)
+static inline void dbg_remove_files(struct ci13xxx *ci)
 {
-       return 0;
 }
 #endif
 
index f64fbea1cf20aa689452ea50198ea9f8f70701b3..e502e4807812f86e0073b047a10eb78ce34bcabf 100644 (file)
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/dmapool.h>
-#include <linux/dma-mapping.h>
 #include <linux/err.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/irq.h>
+#include <linux/irqreturn.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/pm_runtime.h>
@@ -146,7 +140,7 @@ static int hw_ep_enable(struct ci13xxx *ci, int num, int dir, int type)
 
        if (dir) {
                mask  = ENDPTCTRL_TXT;  /* type    */
-               data  = type << ffs_nr(mask);
+               data  = type << __ffs(mask);
 
                mask |= ENDPTCTRL_TXS;  /* unstall */
                mask |= ENDPTCTRL_TXR;  /* reset data toggle */
@@ -155,7 +149,7 @@ static int hw_ep_enable(struct ci13xxx *ci, int num, int dir, int type)
                data |= ENDPTCTRL_TXE;
        } else {
                mask  = ENDPTCTRL_RXT;  /* type    */
-               data  = type << ffs_nr(mask);
+               data  = type << __ffs(mask);
 
                mask |= ENDPTCTRL_RXS;  /* unstall */
                mask |= ENDPTCTRL_RXR;  /* reset data toggle */
@@ -305,18 +299,6 @@ static u32 hw_test_and_clear_intr_active(struct ci13xxx *ci)
        return reg;
 }
 
-static void hw_enable_vbus_intr(struct ci13xxx *ci)
-{
-       hw_write(ci, OP_OTGSC, OTGSC_AVVIS, OTGSC_AVVIS);
-       hw_write(ci, OP_OTGSC, OTGSC_AVVIE, OTGSC_AVVIE);
-       queue_work(ci->wq, &ci->vbus_work);
-}
-
-static void hw_disable_vbus_intr(struct ci13xxx *ci)
-{
-       hw_write(ci, OP_OTGSC, OTGSC_AVVIE, 0);
-}
-
 /**
  * hw_test_and_clear_setup_guard: test & clear setup guard (execute without
  *                                interruption)
@@ -349,7 +331,7 @@ static int hw_test_and_set_setup_guard(struct ci13xxx *ci)
 static void hw_usb_set_address(struct ci13xxx *ci, u8 value)
 {
        hw_write(ci, OP_DEVICEADDR, DEVICEADDR_USBADR,
-                value << ffs_nr(DEVICEADDR_USBADR));
+                value << __ffs(DEVICEADDR_USBADR));
 }
 
 /**
@@ -383,16 +365,6 @@ static int hw_usb_reset(struct ci13xxx *ci)
        return 0;
 }
 
-static void vbus_work(struct work_struct *work)
-{
-       struct ci13xxx *ci = container_of(work, struct ci13xxx, vbus_work);
-
-       if (hw_read(ci, OP_OTGSC, OTGSC_AVV))
-               usb_gadget_vbus_connect(&ci->gadget);
-       else
-               usb_gadget_vbus_disconnect(&ci->gadget);
-}
-
 /******************************************************************************
  * UTIL block
  *****************************************************************************/
@@ -432,10 +404,10 @@ static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
                        return -ENOMEM;
 
                memset(mReq->zptr, 0, sizeof(*mReq->zptr));
-               mReq->zptr->next    = TD_TERMINATE;
-               mReq->zptr->token   = TD_STATUS_ACTIVE;
+               mReq->zptr->next    = cpu_to_le32(TD_TERMINATE);
+               mReq->zptr->token   = cpu_to_le32(TD_STATUS_ACTIVE);
                if (!mReq->req.no_interrupt)
-                       mReq->zptr->token   |= TD_IOC;
+                       mReq->zptr->token   |= cpu_to_le32(TD_IOC);
        }
        ret = usb_gadget_map_request(&ci->gadget, &mReq->req, mEp->dir);
        if (ret)
@@ -446,32 +418,35 @@ static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
         * TODO - handle requests which spawns into several TDs
         */
        memset(mReq->ptr, 0, sizeof(*mReq->ptr));
-       mReq->ptr->token    = length << ffs_nr(TD_TOTAL_BYTES);
-       mReq->ptr->token   &= TD_TOTAL_BYTES;
-       mReq->ptr->token   |= TD_STATUS_ACTIVE;
+       mReq->ptr->token    = cpu_to_le32(length << __ffs(TD_TOTAL_BYTES));
+       mReq->ptr->token   &= cpu_to_le32(TD_TOTAL_BYTES);
+       mReq->ptr->token   |= cpu_to_le32(TD_STATUS_ACTIVE);
        if (mReq->zptr) {
-               mReq->ptr->next    = mReq->zdma;
+               mReq->ptr->next    = cpu_to_le32(mReq->zdma);
        } else {
-               mReq->ptr->next    = TD_TERMINATE;
+               mReq->ptr->next    = cpu_to_le32(TD_TERMINATE);
                if (!mReq->req.no_interrupt)
-                       mReq->ptr->token  |= TD_IOC;
+                       mReq->ptr->token  |= cpu_to_le32(TD_IOC);
+       }
+       mReq->ptr->page[0]  = cpu_to_le32(mReq->req.dma);
+       for (i = 1; i < TD_PAGE_COUNT; i++) {
+               u32 page = mReq->req.dma + i * CI13XXX_PAGE_SIZE;
+               page &= ~TD_RESERVED_MASK;
+               mReq->ptr->page[i] = cpu_to_le32(page);
        }
-       mReq->ptr->page[0]  = mReq->req.dma;
-       for (i = 1; i < 5; i++)
-               mReq->ptr->page[i] =
-                       (mReq->req.dma + i * CI13XXX_PAGE_SIZE) & ~TD_RESERVED_MASK;
 
        if (!list_empty(&mEp->qh.queue)) {
                struct ci13xxx_req *mReqPrev;
                int n = hw_ep_bit(mEp->num, mEp->dir);
                int tmp_stat;
+               u32 next = mReq->dma & TD_ADDR_MASK;
 
                mReqPrev = list_entry(mEp->qh.queue.prev,
                                struct ci13xxx_req, queue);
                if (mReqPrev->zptr)
-                       mReqPrev->zptr->next = mReq->dma & TD_ADDR_MASK;
+                       mReqPrev->zptr->next = cpu_to_le32(next);
                else
-                       mReqPrev->ptr->next = mReq->dma & TD_ADDR_MASK;
+                       mReqPrev->ptr->next = cpu_to_le32(next);
                wmb();
                if (hw_read(ci, OP_ENDPTPRIME, BIT(n)))
                        goto done;
@@ -485,9 +460,9 @@ static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
        }
 
        /*  QH configuration */
-       mEp->qh.ptr->td.next   = mReq->dma;    /* TERMINATE = 0 */
-       mEp->qh.ptr->td.token &= ~TD_STATUS;   /* clear status */
-       mEp->qh.ptr->cap |=  QH_ZLT;
+       mEp->qh.ptr->td.next   = cpu_to_le32(mReq->dma);    /* TERMINATE = 0 */
+       mEp->qh.ptr->td.token &=
+               cpu_to_le32(~(TD_STATUS_HALTED|TD_STATUS_ACTIVE));
 
        wmb();   /* synchronize before ep prime */
 
@@ -506,14 +481,16 @@ done:
  */
 static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
 {
+       u32 tmptoken = le32_to_cpu(mReq->ptr->token);
+
        if (mReq->req.status != -EALREADY)
                return -EINVAL;
 
-       if ((TD_STATUS_ACTIVE & mReq->ptr->token) != 0)
+       if ((TD_STATUS_ACTIVE & tmptoken) != 0)
                return -EBUSY;
 
        if (mReq->zptr) {
-               if ((TD_STATUS_ACTIVE & mReq->zptr->token) != 0)
+               if ((cpu_to_le32(TD_STATUS_ACTIVE) & mReq->zptr->token) != 0)
                        return -EBUSY;
                dma_pool_free(mEp->td_pool, mReq->zptr, mReq->zdma);
                mReq->zptr = NULL;
@@ -523,7 +500,7 @@ static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
 
        usb_gadget_unmap_request(&mEp->ci->gadget, &mReq->req, mEp->dir);
 
-       mReq->req.status = mReq->ptr->token & TD_STATUS;
+       mReq->req.status = tmptoken & TD_STATUS;
        if ((TD_STATUS_HALTED & mReq->req.status) != 0)
                mReq->req.status = -1;
        else if ((TD_STATUS_DT_ERR & mReq->req.status) != 0)
@@ -531,8 +508,8 @@ static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
        else if ((TD_STATUS_TR_ERR & mReq->req.status) != 0)
                mReq->req.status = -1;
 
-       mReq->req.actual   = mReq->ptr->token & TD_TOTAL_BYTES;
-       mReq->req.actual >>= ffs_nr(TD_TOTAL_BYTES);
+       mReq->req.actual   = tmptoken & TD_TOTAL_BYTES;
+       mReq->req.actual >>= __ffs(TD_TOTAL_BYTES);
        mReq->req.actual   = mReq->req.length - mReq->req.actual;
        mReq->req.actual   = mReq->req.status ? 0 : mReq->req.actual;
 
@@ -629,8 +606,6 @@ __acquires(ci->lock)
 {
        int retval;
 
-       dbg_event(0xFF, "BUS RST", 0);
-
        spin_unlock(&ci->lock);
        retval = _gadget_stop_activity(&ci->gadget);
        if (retval)
@@ -667,6 +642,59 @@ static void isr_get_status_complete(struct usb_ep *ep, struct usb_request *req)
        usb_ep_free_request(ep, req);
 }
 
+/**
+ * _ep_queue: queues (submits) an I/O request to an endpoint
+ *
+ * Caller must hold lock
+ */
+static int _ep_queue(struct usb_ep *ep, struct usb_request *req,
+                   gfp_t __maybe_unused gfp_flags)
+{
+       struct ci13xxx_ep  *mEp  = container_of(ep,  struct ci13xxx_ep, ep);
+       struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
+       struct ci13xxx *ci = mEp->ci;
+       int retval = 0;
+
+       if (ep == NULL || req == NULL || mEp->ep.desc == NULL)
+               return -EINVAL;
+
+       if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
+               if (req->length)
+                       mEp = (ci->ep0_dir == RX) ?
+                              ci->ep0out : ci->ep0in;
+               if (!list_empty(&mEp->qh.queue)) {
+                       _ep_nuke(mEp);
+                       retval = -EOVERFLOW;
+                       dev_warn(mEp->ci->dev, "endpoint ctrl %X nuked\n",
+                                _usb_addr(mEp));
+               }
+       }
+
+       /* first nuke then test link, e.g. previous status has not sent */
+       if (!list_empty(&mReq->queue)) {
+               dev_err(mEp->ci->dev, "request already in queue\n");
+               return -EBUSY;
+       }
+
+       if (req->length > (TD_PAGE_COUNT - 1) * CI13XXX_PAGE_SIZE) {
+               dev_err(mEp->ci->dev, "request bigger than one td\n");
+               return -EMSGSIZE;
+       }
+
+       /* push request */
+       mReq->req.status = -EINPROGRESS;
+       mReq->req.actual = 0;
+
+       retval = _hardware_enqueue(mEp, mReq);
+
+       if (retval == -EALREADY)
+               retval = 0;
+       if (!retval)
+               list_add_tail(&mReq->queue, &mEp->qh.queue);
+
+       return retval;
+}
+
 /**
  * isr_get_status_response: get_status request response
  * @ci: ci struct
@@ -714,9 +742,7 @@ __acquires(mEp->lock)
        }
        /* else do nothing; reserved for future use */
 
-       spin_unlock(mEp->lock);
-       retval = usb_ep_queue(&mEp->ep, req, gfp_flags);
-       spin_lock(mEp->lock);
+       retval = _ep_queue(&mEp->ep, req, gfp_flags);
        if (retval)
                goto err_free_buf;
 
@@ -763,8 +789,6 @@ isr_setup_status_complete(struct usb_ep *ep, struct usb_request *req)
  * This function returns an error code
  */
 static int isr_setup_status_phase(struct ci13xxx *ci)
-__releases(mEp->lock)
-__acquires(mEp->lock)
 {
        int retval;
        struct ci13xxx_ep *mEp;
@@ -773,9 +797,7 @@ __acquires(mEp->lock)
        ci->status->context = ci;
        ci->status->complete = isr_setup_status_complete;
 
-       spin_unlock(mEp->lock);
-       retval = usb_ep_queue(&mEp->ep, ci->status, GFP_ATOMIC);
-       spin_lock(mEp->lock);
+       retval = _ep_queue(&mEp->ep, ci->status, GFP_ATOMIC);
 
        return retval;
 }
@@ -801,7 +823,6 @@ __acquires(mEp->lock)
                if (retval < 0)
                        break;
                list_del_init(&mReq->queue);
-               dbg_done(_usb_addr(mEp), mReq->ptr->token, retval);
                if (mReq->req.complete != NULL) {
                        spin_unlock(mEp->lock);
                        if ((mEp->type == USB_ENDPOINT_XFER_CONTROL) &&
@@ -814,8 +835,6 @@ __acquires(mEp->lock)
 
        if (retval == -EBUSY)
                retval = 0;
-       if (retval < 0)
-               dbg_event(_usb_addr(mEp), "DONE", retval);
 
        return retval;
 }
@@ -847,8 +866,6 @@ __acquires(ci->lock)
                                if (err > 0)   /* needs status phase */
                                        err = isr_setup_status_phase(ci);
                                if (err < 0) {
-                                       dbg_event(_usb_addr(mEp),
-                                                 "ERROR", err);
                                        spin_unlock(&ci->lock);
                                        if (usb_ep_set_halt(&mEp->ep))
                                                dev_err(ci->dev,
@@ -884,8 +901,6 @@ __acquires(ci->lock)
 
                ci->ep0_dir = (type & USB_DIR_IN) ? TX : RX;
 
-               dbg_setup(_usb_addr(mEp), &req);
-
                switch (req.bRequest) {
                case USB_REQ_CLEAR_FEATURE:
                        if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) &&
@@ -997,8 +1012,6 @@ delegate:
                }
 
                if (err < 0) {
-                       dbg_event(_usb_addr(mEp), "ERROR", err);
-
                        spin_unlock(&ci->lock);
                        if (usb_ep_set_halt(&mEp->ep))
                                dev_err(ci->dev, "error: ep_set_halt\n");
@@ -1021,6 +1034,7 @@ static int ep_enable(struct usb_ep *ep,
        struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
        int retval = 0;
        unsigned long flags;
+       u32 cap = 0;
 
        if (ep == NULL || desc == NULL)
                return -EINVAL;
@@ -1040,20 +1054,15 @@ static int ep_enable(struct usb_ep *ep,
 
        mEp->ep.maxpacket = usb_endpoint_maxp(desc);
 
-       dbg_event(_usb_addr(mEp), "ENABLE", 0);
-
-       mEp->qh.ptr->cap = 0;
-
        if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
-               mEp->qh.ptr->cap |=  QH_IOS;
-       else if (mEp->type == USB_ENDPOINT_XFER_ISOC)
-               mEp->qh.ptr->cap &= ~QH_MULT;
-       else
-               mEp->qh.ptr->cap &= ~QH_ZLT;
+               cap |= QH_IOS;
+       if (mEp->num)
+               cap |= QH_ZLT;
+       cap |= (mEp->ep.maxpacket << __ffs(QH_MAX_PKT)) & QH_MAX_PKT;
+
+       mEp->qh.ptr->cap = cpu_to_le32(cap);
 
-       mEp->qh.ptr->cap |=
-               (mEp->ep.maxpacket << ffs_nr(QH_MAX_PKT)) & QH_MAX_PKT;
-       mEp->qh.ptr->td.next |= TD_TERMINATE;   /* needed? */
+       mEp->qh.ptr->td.next |= cpu_to_le32(TD_TERMINATE);   /* needed? */
 
        /*
         * Enable endpoints in the HW other than ep0 as ep0
@@ -1088,8 +1097,6 @@ static int ep_disable(struct usb_ep *ep)
 
        direction = mEp->dir;
        do {
-               dbg_event(_usb_addr(mEp), "DISABLE", 0);
-
                retval |= _ep_nuke(mEp);
                retval |= hw_ep_disable(mEp->ci, mEp->num, mEp->dir);
 
@@ -1129,8 +1136,6 @@ static struct usb_request *ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
                }
        }
 
-       dbg_event(_usb_addr(mEp), "ALLOC", mReq == NULL);
-
        return (mReq == NULL) ? NULL : &mReq->req;
 }
 
@@ -1158,8 +1163,6 @@ static void ep_free_request(struct usb_ep *ep, struct usb_request *req)
                dma_pool_free(mEp->td_pool, mReq->ptr, mReq->dma);
        kfree(mReq);
 
-       dbg_event(_usb_addr(mEp), "FREE", 0);
-
        spin_unlock_irqrestore(mEp->lock, flags);
 }
 
@@ -1172,8 +1175,6 @@ static int ep_queue(struct usb_ep *ep, struct usb_request *req,
                    gfp_t __maybe_unused gfp_flags)
 {
        struct ci13xxx_ep  *mEp  = container_of(ep,  struct ci13xxx_ep, ep);
-       struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
-       struct ci13xxx *ci = mEp->ci;
        int retval = 0;
        unsigned long flags;
 
@@ -1181,48 +1182,7 @@ static int ep_queue(struct usb_ep *ep, struct usb_request *req,
                return -EINVAL;
 
        spin_lock_irqsave(mEp->lock, flags);
-
-       if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
-               if (req->length)
-                       mEp = (ci->ep0_dir == RX) ?
-                              ci->ep0out : ci->ep0in;
-               if (!list_empty(&mEp->qh.queue)) {
-                       _ep_nuke(mEp);
-                       retval = -EOVERFLOW;
-                       dev_warn(mEp->ci->dev, "endpoint ctrl %X nuked\n",
-                                _usb_addr(mEp));
-               }
-       }
-
-       /* first nuke then test link, e.g. previous status has not sent */
-       if (!list_empty(&mReq->queue)) {
-               retval = -EBUSY;
-               dev_err(mEp->ci->dev, "request already in queue\n");
-               goto done;
-       }
-
-       if (req->length > 4 * CI13XXX_PAGE_SIZE) {
-               req->length = 4 * CI13XXX_PAGE_SIZE;
-               retval = -EMSGSIZE;
-               dev_warn(mEp->ci->dev, "request length truncated\n");
-       }
-
-       dbg_queue(_usb_addr(mEp), req, retval);
-
-       /* push request */
-       mReq->req.status = -EINPROGRESS;
-       mReq->req.actual = 0;
-
-       retval = _hardware_enqueue(mEp, mReq);
-
-       if (retval == -EALREADY) {
-               dbg_event(_usb_addr(mEp), "QUEUE", retval);
-               retval = 0;
-       }
-       if (!retval)
-               list_add_tail(&mReq->queue, &mEp->qh.queue);
-
- done:
+       retval = _ep_queue(ep, req, gfp_flags);
        spin_unlock_irqrestore(mEp->lock, flags);
        return retval;
 }
@@ -1245,8 +1205,6 @@ static int ep_dequeue(struct usb_ep *ep, struct usb_request *req)
 
        spin_lock_irqsave(mEp->lock, flags);
 
-       dbg_event(_usb_addr(mEp), "DEQUEUE", 0);
-
        hw_ep_flush(mEp->ci, mEp->num, mEp->dir);
 
        /* pop request */
@@ -1293,7 +1251,6 @@ static int ep_set_halt(struct usb_ep *ep, int value)
 
        direction = mEp->dir;
        do {
-               dbg_event(_usb_addr(mEp), "HALT", value);
                retval |= hw_ep_set_halt(mEp->ci, mEp->num, mEp->dir, value);
 
                if (!value)
@@ -1322,10 +1279,7 @@ static int ep_set_wedge(struct usb_ep *ep)
                return -EINVAL;
 
        spin_lock_irqsave(mEp->lock, flags);
-
-       dbg_event(_usb_addr(mEp), "WEDGE", 0);
        mEp->wedge = 1;
-
        spin_unlock_irqrestore(mEp->lock, flags);
 
        return usb_ep_set_halt(ep);
@@ -1348,7 +1302,6 @@ static void ep_fifo_flush(struct usb_ep *ep)
 
        spin_lock_irqsave(mEp->lock, flags);
 
-       dbg_event(_usb_addr(mEp), "FFLUSH", 0);
        hw_ep_flush(mEp->ci, mEp->num, mEp->dir);
 
        spin_unlock_irqrestore(mEp->lock, flags);
@@ -1392,7 +1345,6 @@ static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active)
                if (is_active) {
                        pm_runtime_get_sync(&_gadget->dev);
                        hw_device_reset(ci, USBMODE_CM_DC);
-                       hw_enable_vbus_intr(ci);
                        hw_device_state(ci, ci->ep0out->qh.dma);
                } else {
                        hw_device_state(ci, 0);
@@ -1567,10 +1519,8 @@ static int ci13xxx_start(struct usb_gadget *gadget,
        pm_runtime_get_sync(&ci->gadget.dev);
        if (ci->platdata->flags & CI13XXX_PULLUP_ON_VBUS) {
                if (ci->vbus_active) {
-                       if (ci->platdata->flags & CI13XXX_REGS_SHARED) {
+                       if (ci->platdata->flags & CI13XXX_REGS_SHARED)
                                hw_device_reset(ci, USBMODE_CM_DC);
-                               hw_enable_vbus_intr(ci);
-                       }
                } else {
                        pm_runtime_put_sync(&ci->gadget.dev);
                        goto done;
@@ -1642,7 +1592,6 @@ static irqreturn_t udc_irq(struct ci13xxx *ci)
                }
        }
        intr = hw_test_and_clear_intr_active(ci);
-       dbg_interrupt(intr);
 
        if (intr) {
                /* order defines priority - do NOT change it */
@@ -1676,13 +1625,6 @@ static irqreturn_t udc_irq(struct ci13xxx *ci)
        } else {
                retval = IRQ_NONE;
        }
-
-       intr = hw_read(ci, OP_OTGSC, ~0);
-       hw_write(ci, OP_OTGSC, ~0, intr);
-
-       if (intr & (OTGSC_AVVIE & OTGSC_AVVIS))
-               queue_work(ci->wq, &ci->vbus_work);
-
        spin_unlock(&ci->lock);
 
        return retval;
@@ -1758,7 +1700,6 @@ static int udc_start(struct ci13xxx *ci)
                retval = hw_device_reset(ci, USBMODE_CM_DC);
                if (retval)
                        goto put_transceiver;
-               hw_enable_vbus_intr(ci);
        }
 
        retval = device_register(&ci->gadget.dev);
@@ -1767,15 +1708,11 @@ static int udc_start(struct ci13xxx *ci)
                goto put_transceiver;
        }
 
-       retval = dbg_create_files(ci->dev);
-       if (retval)
-               goto unreg_device;
-
        if (!IS_ERR_OR_NULL(ci->transceiver)) {
                retval = otg_set_peripheral(ci->transceiver->otg,
                                                &ci->gadget);
                if (retval)
-                       goto remove_dbg;
+                       goto unreg_device;
        }
 
        retval = usb_add_gadget_udc(dev, &ci->gadget);
@@ -1795,8 +1732,6 @@ remove_trans:
        }
 
        dev_err(dev, "error = %i\n", retval);
-remove_dbg:
-       dbg_remove_files(ci->dev);
 unreg_device:
        device_unregister(&ci->gadget.dev);
 put_transceiver:
@@ -1821,9 +1756,6 @@ static void udc_stop(struct ci13xxx *ci)
        if (ci == NULL)
                return;
 
-       hw_disable_vbus_intr(ci);
-       cancel_work_sync(&ci->vbus_work);
-
        usb_del_gadget_udc(&ci->gadget);
 
        destroy_eps(ci);
@@ -1836,7 +1768,6 @@ static void udc_stop(struct ci13xxx *ci)
                if (ci->global_phy)
                        usb_put_phy(ci->transceiver);
        }
-       dbg_remove_files(ci->dev);
        device_unregister(&ci->gadget.dev);
        /* my kobject is dynamic, I swear! */
        memset(&ci->gadget, 0, sizeof(ci->gadget));
@@ -1864,7 +1795,6 @@ int ci_hdrc_gadget_init(struct ci13xxx *ci)
        rdrv->irq       = udc_irq;
        rdrv->name      = "gadget";
        ci->roles[CI_ROLE_GADGET] = rdrv;
-       INIT_WORK(&ci->vbus_work, vbus_work);
 
        return 0;
 }
diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c
new file mode 100644 (file)
index 0000000..714a6bd
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+
+#include "ci13xxx_imx.h"
+
+#define USB_DEV_MAX 4
+
+#define MX25_USB_PHY_CTRL_OFFSET       0x08
+#define MX25_BM_EXTERNAL_VBUS_DIVIDER  BIT(23)
+
+#define MX53_USB_OTG_PHY_CTRL_0_OFFSET 0x08
+#define MX53_USB_UH2_CTRL_OFFSET       0x14
+#define MX53_USB_UH3_CTRL_OFFSET       0x18
+#define MX53_BM_OVER_CUR_DIS_H1                BIT(5)
+#define MX53_BM_OVER_CUR_DIS_OTG       BIT(8)
+#define MX53_BM_OVER_CUR_DIS_UHx       BIT(30)
+
+#define MX6_BM_OVER_CUR_DIS            BIT(7)
+
+struct imx_usbmisc {
+       void __iomem *base;
+       spinlock_t lock;
+       struct clk *clk;
+       struct usbmisc_usb_device usbdev[USB_DEV_MAX];
+       const struct usbmisc_ops *ops;
+};
+
+static struct imx_usbmisc *usbmisc;
+
+static struct usbmisc_usb_device *get_usbdev(struct device *dev)
+{
+       int i, ret;
+
+       for (i = 0; i < USB_DEV_MAX; i++) {
+               if (usbmisc->usbdev[i].dev == dev)
+                       return &usbmisc->usbdev[i];
+               else if (!usbmisc->usbdev[i].dev)
+                       break;
+       }
+
+       if (i >= USB_DEV_MAX)
+               return ERR_PTR(-EBUSY);
+
+       ret = usbmisc_get_init_data(dev, &usbmisc->usbdev[i]);
+       if (ret)
+               return ERR_PTR(ret);
+
+       return &usbmisc->usbdev[i];
+}
+
+static int usbmisc_imx25_post(struct device *dev)
+{
+       struct usbmisc_usb_device *usbdev;
+       void __iomem *reg;
+       unsigned long flags;
+       u32 val;
+
+       usbdev = get_usbdev(dev);
+       if (IS_ERR(usbdev))
+               return PTR_ERR(usbdev);
+
+       reg = usbmisc->base + MX25_USB_PHY_CTRL_OFFSET;
+
+       if (usbdev->evdo) {
+               spin_lock_irqsave(&usbmisc->lock, flags);
+               val = readl(reg);
+               writel(val | MX25_BM_EXTERNAL_VBUS_DIVIDER, reg);
+               spin_unlock_irqrestore(&usbmisc->lock, flags);
+               usleep_range(5000, 10000); /* needed to stabilize voltage */
+       }
+
+       return 0;
+}
+
+static int usbmisc_imx53_init(struct device *dev)
+{
+       struct usbmisc_usb_device *usbdev;
+       void __iomem *reg = NULL;
+       unsigned long flags;
+       u32 val = 0;
+
+       usbdev = get_usbdev(dev);
+       if (IS_ERR(usbdev))
+               return PTR_ERR(usbdev);
+
+       if (usbdev->disable_oc) {
+               spin_lock_irqsave(&usbmisc->lock, flags);
+               switch (usbdev->index) {
+               case 0:
+                       reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET;
+                       val = readl(reg) | MX53_BM_OVER_CUR_DIS_OTG;
+                       break;
+               case 1:
+                       reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET;
+                       val = readl(reg) | MX53_BM_OVER_CUR_DIS_H1;
+                       break;
+               case 2:
+                       reg = usbmisc->base + MX53_USB_UH2_CTRL_OFFSET;
+                       val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx;
+                       break;
+               case 3:
+                       reg = usbmisc->base + MX53_USB_UH3_CTRL_OFFSET;
+                       val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx;
+                       break;
+               }
+               if (reg && val)
+                       writel(val, reg);
+               spin_unlock_irqrestore(&usbmisc->lock, flags);
+       }
+
+       return 0;
+}
+
+static int usbmisc_imx6q_init(struct device *dev)
+{
+
+       struct usbmisc_usb_device *usbdev;
+       unsigned long flags;
+       u32 reg;
+
+       usbdev = get_usbdev(dev);
+       if (IS_ERR(usbdev))
+               return PTR_ERR(usbdev);
+
+       if (usbdev->disable_oc) {
+               spin_lock_irqsave(&usbmisc->lock, flags);
+               reg = readl(usbmisc->base + usbdev->index * 4);
+               writel(reg | MX6_BM_OVER_CUR_DIS,
+                       usbmisc->base + usbdev->index * 4);
+               spin_unlock_irqrestore(&usbmisc->lock, flags);
+       }
+
+       return 0;
+}
+
+static const struct usbmisc_ops imx25_usbmisc_ops = {
+       .post = usbmisc_imx25_post,
+};
+
+static const struct usbmisc_ops imx53_usbmisc_ops = {
+       .init = usbmisc_imx53_init,
+};
+
+static const struct usbmisc_ops imx6q_usbmisc_ops = {
+       .init = usbmisc_imx6q_init,
+};
+
+static const struct of_device_id usbmisc_imx_dt_ids[] = {
+       {
+               .compatible = "fsl,imx25-usbmisc",
+               .data = &imx25_usbmisc_ops,
+       },
+       {
+               .compatible = "fsl,imx53-usbmisc",
+               .data = &imx53_usbmisc_ops,
+       },
+       {
+               .compatible = "fsl,imx6q-usbmisc",
+               .data = &imx6q_usbmisc_ops,
+       },
+       { /* sentinel */ }
+};
+
+static int usbmisc_imx_probe(struct platform_device *pdev)
+{
+       struct resource *res;
+       struct imx_usbmisc *data;
+       int ret;
+       struct of_device_id *tmp_dev;
+
+       if (usbmisc)
+               return -EBUSY;
+
+       data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       spin_lock_init(&data->lock);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       data->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(data->base))
+               return PTR_ERR(data->base);
+
+       data->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(data->clk)) {
+               dev_err(&pdev->dev,
+                       "failed to get clock, err=%ld\n", PTR_ERR(data->clk));
+               return PTR_ERR(data->clk);
+       }
+
+       ret = clk_prepare_enable(data->clk);
+       if (ret) {
+               dev_err(&pdev->dev,
+                       "clk_prepare_enable failed, err=%d\n", ret);
+               return ret;
+       }
+
+       tmp_dev = (struct of_device_id *)
+               of_match_device(usbmisc_imx_dt_ids, &pdev->dev);
+       data->ops = (const struct usbmisc_ops *)tmp_dev->data;
+       usbmisc = data;
+       ret = usbmisc_set_ops(data->ops);
+       if (ret) {
+               usbmisc = NULL;
+               clk_disable_unprepare(data->clk);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int usbmisc_imx_remove(struct platform_device *pdev)
+{
+       usbmisc_unset_ops(usbmisc->ops);
+       clk_disable_unprepare(usbmisc->clk);
+       usbmisc = NULL;
+       return 0;
+}
+
+static struct platform_driver usbmisc_imx_driver = {
+       .probe = usbmisc_imx_probe,
+       .remove = usbmisc_imx_remove,
+       .driver = {
+               .name = "usbmisc_imx",
+               .owner = THIS_MODULE,
+               .of_match_table = usbmisc_imx_dt_ids,
+        },
+};
+
+int usbmisc_imx_drv_init(void)
+{
+       return platform_driver_register(&usbmisc_imx_driver);
+}
+subsys_initcall(usbmisc_imx_drv_init);
+
+void usbmisc_imx_drv_exit(void)
+{
+       platform_driver_unregister(&usbmisc_imx_driver);
+}
+module_exit(usbmisc_imx_drv_exit);
+
+MODULE_ALIAS("platform:usbmisc-imx");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("driver for imx usb non-core registers");
+MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>");
diff --git a/drivers/usb/chipidea/usbmisc_imx6q.c b/drivers/usb/chipidea/usbmisc_imx6q.c
deleted file mode 100644 (file)
index a1bce39..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright 2012 Freescale Semiconductor, Inc.
- *
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-
-#include <linux/module.h>
-#include <linux/of_platform.h>
-#include <linux/clk.h>
-#include <linux/err.h>
-#include <linux/io.h>
-
-#include "ci13xxx_imx.h"
-
-#define USB_DEV_MAX 4
-
-#define BM_OVER_CUR_DIS                BIT(7)
-
-struct imx6q_usbmisc {
-       void __iomem *base;
-       spinlock_t lock;
-       struct clk *clk;
-       struct usbmisc_usb_device usbdev[USB_DEV_MAX];
-};
-
-static struct imx6q_usbmisc *usbmisc;
-
-static struct usbmisc_usb_device *get_usbdev(struct device *dev)
-{
-       int i, ret;
-
-       for (i = 0; i < USB_DEV_MAX; i++) {
-               if (usbmisc->usbdev[i].dev == dev)
-                       return &usbmisc->usbdev[i];
-               else if (!usbmisc->usbdev[i].dev)
-                       break;
-       }
-
-       if (i >= USB_DEV_MAX)
-               return ERR_PTR(-EBUSY);
-
-       ret = usbmisc_get_init_data(dev, &usbmisc->usbdev[i]);
-       if (ret)
-               return ERR_PTR(ret);
-
-       return &usbmisc->usbdev[i];
-}
-
-static int usbmisc_imx6q_init(struct device *dev)
-{
-
-       struct usbmisc_usb_device *usbdev;
-       unsigned long flags;
-       u32 reg;
-
-       usbdev = get_usbdev(dev);
-       if (IS_ERR(usbdev))
-               return PTR_ERR(usbdev);
-
-       if (usbdev->disable_oc) {
-               spin_lock_irqsave(&usbmisc->lock, flags);
-               reg = readl(usbmisc->base + usbdev->index * 4);
-               writel(reg | BM_OVER_CUR_DIS,
-                       usbmisc->base + usbdev->index * 4);
-               spin_unlock_irqrestore(&usbmisc->lock, flags);
-       }
-
-       return 0;
-}
-
-static const struct usbmisc_ops imx6q_usbmisc_ops = {
-       .init = usbmisc_imx6q_init,
-};
-
-static const struct of_device_id usbmisc_imx6q_dt_ids[] = {
-       { .compatible = "fsl,imx6q-usbmisc"},
-       { /* sentinel */ }
-};
-
-static int usbmisc_imx6q_probe(struct platform_device *pdev)
-{
-       struct resource *res;
-       struct imx6q_usbmisc *data;
-       int ret;
-
-       if (usbmisc)
-               return -EBUSY;
-
-       data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
-       if (!data)
-               return -ENOMEM;
-
-       spin_lock_init(&data->lock);
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       data->base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(data->base))
-               return PTR_ERR(data->base);
-
-       data->clk = devm_clk_get(&pdev->dev, NULL);
-       if (IS_ERR(data->clk)) {
-               dev_err(&pdev->dev,
-                       "failed to get clock, err=%ld\n", PTR_ERR(data->clk));
-               return PTR_ERR(data->clk);
-       }
-
-       ret = clk_prepare_enable(data->clk);
-       if (ret) {
-               dev_err(&pdev->dev,
-                       "clk_prepare_enable failed, err=%d\n", ret);
-               return ret;
-       }
-
-       ret = usbmisc_set_ops(&imx6q_usbmisc_ops);
-       if (ret) {
-               clk_disable_unprepare(data->clk);
-               return ret;
-       }
-
-       usbmisc = data;
-
-       return 0;
-}
-
-static int usbmisc_imx6q_remove(struct platform_device *pdev)
-{
-       usbmisc_unset_ops(&imx6q_usbmisc_ops);
-       clk_disable_unprepare(usbmisc->clk);
-       return 0;
-}
-
-static struct platform_driver usbmisc_imx6q_driver = {
-       .probe = usbmisc_imx6q_probe,
-       .remove = usbmisc_imx6q_remove,
-       .driver = {
-               .name = "usbmisc_imx6q",
-               .owner = THIS_MODULE,
-               .of_match_table = usbmisc_imx6q_dt_ids,
-        },
-};
-
-int __init usbmisc_imx6q_drv_init(void)
-{
-       return platform_driver_register(&usbmisc_imx6q_driver);
-}
-subsys_initcall(usbmisc_imx6q_drv_init);
-
-void __exit usbmisc_imx6q_drv_exit(void)
-{
-       platform_driver_unregister(&usbmisc_imx6q_driver);
-}
-module_exit(usbmisc_imx6q_drv_exit);
-
-MODULE_ALIAS("platform:usbmisc-imx6q");
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("driver for imx6q usb non-core registers");
-MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>");
index 387dc6c8ad25b0d43a7d954ce71d877618fcb63d..6d4e0b96f89d57f9c020c7d510c42899e9772262 100644 (file)
@@ -839,14 +839,6 @@ static int acm_tty_ioctl(struct tty_struct *tty,
        return rv;
 }
 
-static const __u32 acm_tty_speed[] = {
-       0, 50, 75, 110, 134, 150, 200, 300, 600,
-       1200, 1800, 2400, 4800, 9600, 19200, 38400,
-       57600, 115200, 230400, 460800, 500000, 576000,
-       921600, 1000000, 1152000, 1500000, 2000000,
-       2500000, 3000000, 3500000, 4000000
-};
-
 static void acm_tty_set_termios(struct tty_struct *tty,
                                                struct ktermios *termios_old)
 {
index 122d056d96d570c2d59762fda22e0e973ac081b5..8a230f0ef77c77b9acef90b86ab902e9cd4999eb 100644 (file)
@@ -13,6 +13,7 @@
  */
 #include <linux/kernel.h>
 #include <linux/errno.h>
+#include <linux/ioctl.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
@@ -644,6 +645,22 @@ static int wdm_release(struct inode *inode, struct file *file)
        return 0;
 }
 
+static long wdm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       struct wdm_device *desc = file->private_data;
+       int rv = 0;
+
+       switch (cmd) {
+       case IOCTL_WDM_MAX_COMMAND:
+               if (copy_to_user((void __user *)arg, &desc->wMaxCommand, sizeof(desc->wMaxCommand)))
+                       rv = -EFAULT;
+               break;
+       default:
+               rv = -ENOTTY;
+       }
+       return rv;
+}
+
 static const struct file_operations wdm_fops = {
        .owner =        THIS_MODULE,
        .read =         wdm_read,
@@ -652,6 +669,8 @@ static const struct file_operations wdm_fops = {
        .flush =        wdm_flush,
        .release =      wdm_release,
        .poll =         wdm_poll,
+       .unlocked_ioctl = wdm_ioctl,
+       .compat_ioctl = wdm_ioctl,
        .llseek =       noop_llseek,
 };
 
index f70c1a1694ade4237e7ec7fee06f6c1342e46af1..7b7305e3abc8d19a934f51364abfe53e8c837430 100644 (file)
@@ -27,6 +27,22 @@ config USB_ANNOUNCE_NEW_DEVICES
 comment "Miscellaneous USB options"
        depends on USB
 
+config USB_DEFAULT_PERSIST
+       bool "Enable USB persist by default"
+       depends on USB
+       default y
+       help
+         Say N here if you don't want USB power session persistance
+         enabled by default.  If you say N it will make suspended USB
+         devices that lose power get reenumerated as if they had been
+         unplugged, causing any mounted filesystems to be lost.  The
+         persist feature can still be enabled for individual devices
+         through the power/persist sysfs node. See
+         Documentation/usb/persist.txt for more info.
+
+         If you have any questions about this, say Y here, only say N
+         if you know exactly what you are doing.
+
 config USB_DYNAMIC_MINORS
        bool "Dynamic USB minor allocation"
        depends on USB
@@ -38,22 +54,6 @@ config USB_DYNAMIC_MINORS
 
          If you are unsure about this, say N here.
 
-config USB_SUSPEND
-       bool "USB runtime power management (autosuspend) and wakeup"
-       depends on USB && PM_RUNTIME
-       help
-         If you say Y here, you can use driver calls or the sysfs
-         "power/control" file to enable or disable autosuspend for
-         individual USB peripherals (see
-         Documentation/usb/power-management.txt for more details).
-
-         Also, USB "remote wakeup" signaling is supported, whereby some
-         USB devices (like keyboards and network adapters) can wake up
-         their parent hub.  That wakeup cascades up the USB tree, and
-         could wake the system from states like suspend-to-RAM.
-
-         If you are unsure about this, say N here.
-
 config USB_OTG
        bool "OTG support"
        depends on USB
index d938b2b99e31fcee332a2f83ae46e4998907190a..84d2b05858102c926fd93f98aa7d8347927f3c09 100644 (file)
@@ -1196,9 +1196,14 @@ done:
  *
  * This is the central routine for suspending USB devices.  It calls the
  * suspend methods for all the interface drivers in @udev and then calls
- * the suspend method for @udev itself.  If an error occurs at any stage,
- * all the interfaces which were suspended are resumed so that they remain
- * in the same state as the device.
+ * the suspend method for @udev itself.  When the routine is called in
+ * autosuspend, if an error occurs at any stage, all the interfaces
+ * which were suspended are resumed so that they remain in the same
+ * state as the device, but when called from system sleep, all error
+ * from suspend methods of interfaces and the non-root-hub device itself
+ * are simply ignored, so all suspended interfaces are only resumed
+ * to the device's state when @udev is root-hub and its suspend method
+ * returns failure.
  *
  * Autosuspend requests originating from a child device or an interface
  * driver may be made without the protection of @udev's device lock, but
@@ -1407,7 +1412,7 @@ int usb_resume(struct device *dev, pm_message_t msg)
 
 #endif /* CONFIG_PM */
 
-#ifdef CONFIG_USB_SUSPEND
+#ifdef CONFIG_PM_RUNTIME
 
 /**
  * usb_enable_autosuspend - allow a USB device to be autosuspended
@@ -1775,7 +1780,7 @@ int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable)
        return ret;
 }
 
-#endif /* CONFIG_USB_SUSPEND */
+#endif /* CONFIG_PM_RUNTIME */
 
 struct bus_type usb_bus_type = {
        .name =         "usb",
index 271e761f563ee42e54f59eb175e23e06e4d19c5b..acbfeb0a011903289a0d6a17fddcab275792fc72 100644 (file)
@@ -169,7 +169,7 @@ static int generic_probe(struct usb_device *udev)
                c = usb_choose_configuration(udev);
                if (c >= 0) {
                        err = usb_set_configuration(udev, c);
-                       if (err) {
+                       if (err && err != -ENODEV) {
                                dev_err(&udev->dev, "can't set config #%d, error %d\n",
                                        c, err);
                                /* This need not be fatal.  The user can try to
index 2b487d4797bd74057a9ad88148af199360d9de1d..caeb8d6d39fbb8b2e93cb4a0e1cf9d5bd54c2a67 100644 (file)
 
 /* PCI-based HCs are common, but plenty of non-PCI HCs are used too */
 
-#ifdef CONFIG_PM_SLEEP
-
-/* Coordinate handoffs between EHCI and companion controllers
- * during system resume
+/*
+ * Coordinate handoffs between EHCI and companion controllers
+ * during EHCI probing and system resume.
  */
 
-static DEFINE_MUTEX(companions_mutex);
+static DECLARE_RWSEM(companions_rwsem);
 
 #define CL_UHCI                PCI_CLASS_SERIAL_USB_UHCI
 #define CL_OHCI                PCI_CLASS_SERIAL_USB_OHCI
 #define CL_EHCI                PCI_CLASS_SERIAL_USB_EHCI
 
-enum companion_action {
-       SET_HS_COMPANION, CLEAR_HS_COMPANION, WAIT_FOR_COMPANIONS
-};
+static inline int is_ohci_or_uhci(struct pci_dev *pdev)
+{
+       return pdev->class == CL_OHCI || pdev->class == CL_UHCI;
+}
+
+typedef void (*companion_fn)(struct pci_dev *pdev, struct usb_hcd *hcd,
+               struct pci_dev *companion, struct usb_hcd *companion_hcd);
 
-static void companion_common(struct pci_dev *pdev, struct usb_hcd *hcd,
-               enum companion_action action)
+/* Iterate over PCI devices in the same slot as pdev and call fn for each */
+static void for_each_companion(struct pci_dev *pdev, struct usb_hcd *hcd,
+               companion_fn fn)
 {
        struct pci_dev          *companion;
        struct usb_hcd          *companion_hcd;
        unsigned int            slot = PCI_SLOT(pdev->devfn);
 
-       /* Iterate through other PCI functions in the same slot.
-        * If pdev is OHCI or UHCI then we are looking for EHCI, and
-        * vice versa.
+       /*
+        * Iterate through other PCI functions in the same slot.
+        * If the function's drvdata isn't set then it isn't bound to
+        * a USB host controller driver, so skip it.
         */
        companion = NULL;
        for_each_pci_dev(companion) {
                if (companion->bus != pdev->bus ||
                                PCI_SLOT(companion->devfn) != slot)
                        continue;
-
                companion_hcd = pci_get_drvdata(companion);
                if (!companion_hcd)
                        continue;
-
-               /* For SET_HS_COMPANION, store a pointer to the EHCI bus in
-                * the OHCI/UHCI companion bus structure.
-                * For CLEAR_HS_COMPANION, clear the pointer to the EHCI bus
-                * in the OHCI/UHCI companion bus structure.
-                * For WAIT_FOR_COMPANIONS, wait until the OHCI/UHCI
-                * companion controllers have fully resumed.
-                */
-
-               if ((pdev->class == CL_OHCI || pdev->class == CL_UHCI) &&
-                               companion->class == CL_EHCI) {
-                       /* action must be SET_HS_COMPANION */
-                       dev_dbg(&companion->dev, "HS companion for %s\n",
-                                       dev_name(&pdev->dev));
-                       hcd->self.hs_companion = &companion_hcd->self;
-
-               } else if (pdev->class == CL_EHCI &&
-                               (companion->class == CL_OHCI ||
-                               companion->class == CL_UHCI)) {
-                       switch (action) {
-                       case SET_HS_COMPANION:
-                               dev_dbg(&pdev->dev, "HS companion for %s\n",
-                                               dev_name(&companion->dev));
-                               companion_hcd->self.hs_companion = &hcd->self;
-                               break;
-                       case CLEAR_HS_COMPANION:
-                               companion_hcd->self.hs_companion = NULL;
-                               break;
-                       case WAIT_FOR_COMPANIONS:
-                               device_pm_wait_for_dev(&pdev->dev,
-                                               &companion->dev);
-                               break;
-                       }
-               }
+               fn(pdev, hcd, companion, companion_hcd);
        }
 }
 
-static void set_hs_companion(struct pci_dev *pdev, struct usb_hcd *hcd)
+/*
+ * We're about to add an EHCI controller, which will unceremoniously grab
+ * all the port connections away from its companions.  To prevent annoying
+ * error messages, lock the companion's root hub and gracefully unconfigure
+ * it beforehand.  Leave it locked until the EHCI controller is all set.
+ */
+static void ehci_pre_add(struct pci_dev *pdev, struct usb_hcd *hcd,
+               struct pci_dev *companion, struct usb_hcd *companion_hcd)
 {
-       mutex_lock(&companions_mutex);
-       dev_set_drvdata(&pdev->dev, hcd);
-       companion_common(pdev, hcd, SET_HS_COMPANION);
-       mutex_unlock(&companions_mutex);
+       struct usb_device *udev;
+
+       if (is_ohci_or_uhci(companion)) {
+               udev = companion_hcd->self.root_hub;
+               usb_lock_device(udev);
+               usb_set_configuration(udev, 0);
+       }
 }
 
-static void clear_hs_companion(struct pci_dev *pdev, struct usb_hcd *hcd)
+/*
+ * Adding the EHCI controller has either succeeded or failed.  Set the
+ * companion pointer accordingly, and in either case, reconfigure and
+ * unlock the root hub.
+ */
+static void ehci_post_add(struct pci_dev *pdev, struct usb_hcd *hcd,
+               struct pci_dev *companion, struct usb_hcd *companion_hcd)
 {
-       mutex_lock(&companions_mutex);
-       dev_set_drvdata(&pdev->dev, NULL);
+       struct usb_device *udev;
 
-       /* If pdev is OHCI or UHCI, just clear its hs_companion pointer */
-       if (pdev->class == CL_OHCI || pdev->class == CL_UHCI)
-               hcd->self.hs_companion = NULL;
+       if (is_ohci_or_uhci(companion)) {
+               if (dev_get_drvdata(&pdev->dev)) {      /* Succeeded */
+                       dev_dbg(&pdev->dev, "HS companion for %s\n",
+                                       dev_name(&companion->dev));
+                       companion_hcd->self.hs_companion = &hcd->self;
+               }
+               udev = companion_hcd->self.root_hub;
+               usb_set_configuration(udev, 1);
+               usb_unlock_device(udev);
+       }
+}
 
-       /* Otherwise search for companion buses and clear their pointers */
-       else
-               companion_common(pdev, hcd, CLEAR_HS_COMPANION);
-       mutex_unlock(&companions_mutex);
+/*
+ * We just added a non-EHCI controller.  Find the EHCI controller to
+ * which it is a companion, and store a pointer to the bus structure.
+ */
+static void non_ehci_add(struct pci_dev *pdev, struct usb_hcd *hcd,
+               struct pci_dev *companion, struct usb_hcd *companion_hcd)
+{
+       if (is_ohci_or_uhci(pdev) && companion->class == CL_EHCI) {
+               dev_dbg(&pdev->dev, "FS/LS companion for %s\n",
+                               dev_name(&companion->dev));
+               hcd->self.hs_companion = &companion_hcd->self;
+       }
 }
 
-static void wait_for_companions(struct pci_dev *pdev, struct usb_hcd *hcd)
+/* We are removing an EHCI controller.  Clear the companions' pointers. */
+static void ehci_remove(struct pci_dev *pdev, struct usb_hcd *hcd,
+               struct pci_dev *companion, struct usb_hcd *companion_hcd)
 {
-       /* Only EHCI controllers need to wait.
-        * No locking is needed because a controller cannot be resumed
-        * while one of its companions is getting unbound.
-        */
-       if (pdev->class == CL_EHCI)
-               companion_common(pdev, hcd, WAIT_FOR_COMPANIONS);
+       if (is_ohci_or_uhci(companion))
+               companion_hcd->self.hs_companion = NULL;
 }
 
-#else /* !CONFIG_PM_SLEEP */
+#ifdef CONFIG_PM
 
-static inline void set_hs_companion(struct pci_dev *d, struct usb_hcd *h) {}
-static inline void clear_hs_companion(struct pci_dev *d, struct usb_hcd *h) {}
-static inline void wait_for_companions(struct pci_dev *d, struct usb_hcd *h) {}
+/* An EHCI controller must wait for its companions before resuming. */
+static void ehci_wait_for_companions(struct pci_dev *pdev, struct usb_hcd *hcd,
+               struct pci_dev *companion, struct usb_hcd *companion_hcd)
+{
+       if (is_ohci_or_uhci(companion))
+               device_pm_wait_for_dev(&pdev->dev, &companion->dev);
+}
 
-#endif /* !CONFIG_PM_SLEEP */
+#endif /* CONFIG_PM */
 
 /*-------------------------------------------------------------------------*/
 
@@ -217,7 +221,7 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
                                driver->description)) {
                        dev_dbg(&dev->dev, "controller already in use\n");
                        retval = -EBUSY;
-                       goto clear_companion;
+                       goto put_hcd;
                }
                hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
                if (hcd->regs == NULL) {
@@ -244,16 +248,35 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
                if (region == PCI_ROM_RESOURCE) {
                        dev_dbg(&dev->dev, "no i/o regions available\n");
                        retval = -EBUSY;
-                       goto clear_companion;
+                       goto put_hcd;
                }
        }
 
        pci_set_master(dev);
 
-       retval = usb_add_hcd(hcd, hcd_irq, IRQF_SHARED);
+       /* Note: dev_set_drvdata must be called while holding the rwsem */
+       if (dev->class == CL_EHCI) {
+               down_write(&companions_rwsem);
+               dev_set_drvdata(&dev->dev, hcd);
+               for_each_companion(dev, hcd, ehci_pre_add);
+               retval = usb_add_hcd(hcd, hcd_irq, IRQF_SHARED);
+               if (retval != 0)
+                       dev_set_drvdata(&dev->dev, NULL);
+               for_each_companion(dev, hcd, ehci_post_add);
+               up_write(&companions_rwsem);
+       } else {
+               down_read(&companions_rwsem);
+               dev_set_drvdata(&dev->dev, hcd);
+               retval = usb_add_hcd(hcd, hcd_irq, IRQF_SHARED);
+               if (retval != 0)
+                       dev_set_drvdata(&dev->dev, NULL);
+               else
+                       for_each_companion(dev, hcd, non_ehci_add);
+               up_read(&companions_rwsem);
+       }
+
        if (retval != 0)
                goto unmap_registers;
-       set_hs_companion(dev, hcd);
 
        if (pci_dev_run_wake(dev))
                pm_runtime_put_noidle(&dev->dev);
@@ -266,8 +289,7 @@ release_mem_region:
                release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
        } else
                release_region(hcd->rsrc_start, hcd->rsrc_len);
-clear_companion:
-       clear_hs_companion(dev, hcd);
+put_hcd:
        usb_put_hcd(hcd);
 disable_pci:
        pci_disable_device(dev);
@@ -310,14 +332,29 @@ void usb_hcd_pci_remove(struct pci_dev *dev)
        usb_hcd_irq(0, hcd);
        local_irq_enable();
 
-       usb_remove_hcd(hcd);
+       /* Note: dev_set_drvdata must be called while holding the rwsem */
+       if (dev->class == CL_EHCI) {
+               down_write(&companions_rwsem);
+               for_each_companion(dev, hcd, ehci_remove);
+               usb_remove_hcd(hcd);
+               dev_set_drvdata(&dev->dev, NULL);
+               up_write(&companions_rwsem);
+       } else {
+               /* Not EHCI; just clear the companion pointer */
+               down_read(&companions_rwsem);
+               hcd->self.hs_companion = NULL;
+               usb_remove_hcd(hcd);
+               dev_set_drvdata(&dev->dev, NULL);
+               up_read(&companions_rwsem);
+       }
+
        if (hcd->driver->flags & HCD_MEMORY) {
                iounmap(hcd->regs);
                release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
        } else {
                release_region(hcd->rsrc_start, hcd->rsrc_len);
        }
-       clear_hs_companion(dev, hcd);
+
        usb_put_hcd(hcd);
        pci_disable_device(dev);
 }
@@ -463,8 +500,15 @@ static int resume_common(struct device *dev, int event)
        pci_set_master(pci_dev);
 
        if (hcd->driver->pci_resume && !HCD_DEAD(hcd)) {
-               if (event != PM_EVENT_AUTO_RESUME)
-                       wait_for_companions(pci_dev, hcd);
+
+               /*
+                * Only EHCI controllers have to wait for their companions.
+                * No locking is needed because PCI controller drivers do not
+                * get unbound during system resume.
+                */
+               if (pci_dev->class == CL_EHCI && event != PM_EVENT_AUTO_RESUME)
+                       for_each_companion(pci_dev, hcd,
+                                       ehci_wait_for_companions);
 
                retval = hcd->driver->pci_resume(hcd,
                                event == PM_EVENT_RESTORE);
index f9ec44cbb82fb1ff6fa8e620367de8a9daec2c70..d53547d2e4c744c92b43ce55883351aa241f8fb4 100644 (file)
@@ -2125,7 +2125,7 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg)
 
 #endif /* CONFIG_PM */
 
-#ifdef CONFIG_USB_SUSPEND
+#ifdef CONFIG_PM_RUNTIME
 
 /* Workqueue routine for root-hub remote wakeup */
 static void hcd_resume_work(struct work_struct *work)
@@ -2160,7 +2160,7 @@ void usb_hcd_resume_root_hub (struct usb_hcd *hcd)
 }
 EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub);
 
-#endif /* CONFIG_USB_SUSPEND */
+#endif /* CONFIG_PM_RUNTIME */
 
 /*-------------------------------------------------------------------------*/
 
@@ -2336,7 +2336,7 @@ struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,
        init_timer(&hcd->rh_timer);
        hcd->rh_timer.function = rh_timer_func;
        hcd->rh_timer.data = (unsigned long) hcd;
-#ifdef CONFIG_USB_SUSPEND
+#ifdef CONFIG_PM_RUNTIME
        INIT_WORK(&hcd->wakeup_work, hcd_resume_work);
 #endif
 
@@ -2590,7 +2590,7 @@ error_create_attr_group:
        hcd->rh_registered = 0;
        spin_unlock_irq(&hcd_root_hub_lock);
 
-#ifdef CONFIG_USB_SUSPEND
+#ifdef CONFIG_PM_RUNTIME
        cancel_work_sync(&hcd->wakeup_work);
 #endif
        mutex_lock(&usb_bus_list_lock);
@@ -2645,7 +2645,7 @@ void usb_remove_hcd(struct usb_hcd *hcd)
        hcd->rh_registered = 0;
        spin_unlock_irq (&hcd_root_hub_lock);
 
-#ifdef CONFIG_USB_SUSPEND
+#ifdef CONFIG_PM_RUNTIME
        cancel_work_sync(&hcd->wakeup_work);
 #endif
 
index 5480352f984dc2df418902a430979c828cb5df52..feef9351463d99845a379ee3cdd1cb32b6772a4c 100644 (file)
@@ -555,8 +555,9 @@ static int hub_port_status(struct usb_hub *hub, int port1,
        mutex_lock(&hub->status_mutex);
        ret = get_port_status(hub->hdev, port1, &hub->status->port);
        if (ret < 4) {
-               dev_err(hub->intfdev,
-                       "%s failed (err = %d)\n", __func__, ret);
+               if (ret != -ENODEV)
+                       dev_err(hub->intfdev,
+                               "%s failed (err = %d)\n", __func__, ret);
                if (ret >= 0)
                        ret = -EIO;
        } else {
@@ -699,7 +700,7 @@ static void hub_tt_work(struct work_struct *work)
                /* drop lock so HCD can concurrently report other TT errors */
                spin_unlock_irqrestore (&hub->tt.lock, flags);
                status = hub_clear_tt_buffer (hdev, clear->devinfo, clear->tt);
-               if (status)
+               if (status && status != -ENODEV)
                        dev_err (&hdev->dev,
                                "clear tt %d (%04x) error %d\n",
                                clear->tt, clear->devinfo, status);
@@ -837,10 +838,11 @@ static int hub_hub_status(struct usb_hub *hub,
 
        mutex_lock(&hub->status_mutex);
        ret = get_hub_status(hub->hdev, &hub->status->hub);
-       if (ret < 0)
-               dev_err (hub->intfdev,
-                       "%s failed (err = %d)\n", __func__, ret);
-       else {
+       if (ret < 0) {
+               if (ret != -ENODEV)
+                       dev_err(hub->intfdev,
+                               "%s failed (err = %d)\n", __func__, ret);
+       } else {
                *status = le16_to_cpu(hub->status->hub.wHubStatus);
                *change = le16_to_cpu(hub->status->hub.wHubChange); 
                ret = 0;
@@ -877,11 +879,8 @@ static int hub_usb3_port_disable(struct usb_hub *hub, int port1)
                return -EINVAL;
 
        ret = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_SS_DISABLED);
-       if (ret) {
-               dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n",
-                               port1, ret);
+       if (ret)
                return ret;
-       }
 
        /* Wait for the link to enter the disabled state. */
        for (total_time = 0; ; total_time += HUB_DEBOUNCE_STEP) {
@@ -918,7 +917,7 @@ static int hub_port_disable(struct usb_hub *hub, int port1, int set_state)
                        ret = usb_clear_port_feature(hdev, port1,
                                        USB_PORT_FEAT_ENABLE);
        }
-       if (ret)
+       if (ret && ret != -ENODEV)
                dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n",
                                port1, ret);
        return ret;
@@ -1317,6 +1316,10 @@ static int hub_configure(struct usb_hub *hub,
                message = "hub has too many ports!";
                ret = -ENODEV;
                goto fail;
+       } else if (hub->descriptor->bNbrPorts == 0) {
+               message = "hub doesn't have any ports!";
+               ret = -ENODEV;
+               goto fail;
        }
 
        hdev->maxchild = hub->descriptor->bNbrPorts;
@@ -2192,8 +2195,9 @@ static int usb_enumerate_device(struct usb_device *udev)
        if (udev->config == NULL) {
                err = usb_get_configuration(udev);
                if (err < 0) {
-                       dev_err(&udev->dev, "can't read configurations, error %d\n",
-                               err);
+                       if (err != -ENODEV)
+                               dev_err(&udev->dev, "can't read configurations, error %d\n",
+                                               err);
                        return err;
                }
        }
@@ -2640,14 +2644,16 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
                status = set_port_feature(hub->hdev, port1, (warm ?
                                        USB_PORT_FEAT_BH_PORT_RESET :
                                        USB_PORT_FEAT_RESET));
-               if (status) {
+               if (status == -ENODEV) {
+                       ;       /* The hub is gone */
+               } else if (status) {
                        dev_err(hub->intfdev,
                                        "cannot %sreset port %d (err = %d)\n",
                                        warm ? "warm " : "", port1, status);
                } else {
                        status = hub_port_wait_reset(hub, port1, udev, delay,
                                                                warm);
-                       if (status && status != -ENOTCONN)
+                       if (status && status != -ENOTCONN && status != -ENODEV)
                                dev_dbg(hub->intfdev,
                                                "port_wait_reset: err = %d\n",
                                                status);
@@ -2821,7 +2827,7 @@ void usb_enable_ltm(struct usb_device *udev)
 }
 EXPORT_SYMBOL_GPL(usb_enable_ltm);
 
-#ifdef CONFIG_USB_SUSPEND
+#ifdef CONFIG_PM
 /*
  * usb_disable_function_remotewakeup - disable usb3.0
  * device's function remote wakeup
@@ -2880,9 +2886,11 @@ static int usb_disable_function_remotewakeup(struct usb_device *udev)
  * Linux (2.6) currently has NO mechanisms to initiate that:  no khubd
  * timer, no SRP, no requests through sysfs.
  *
- * If CONFIG_USB_SUSPEND isn't enabled, devices only really suspend when
- * the root hub for their bus goes into global suspend ... so we don't
- * (falsely) update the device power state to say it suspended.
+ * If Runtime PM isn't enabled or used, non-SuperSpeed devices really get
+ * suspended only when their bus goes into global suspend (i.e., the root
+ * hub is suspended).  Nevertheless, we change @udev->state to
+ * USB_STATE_SUSPENDED as this is the device's "logical" state.  The actual
+ * upstream port setting is stored in @udev->port_is_suspended.
  *
  * Returns 0 on success, else negative errno.
  */
@@ -2893,6 +2901,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
        enum pm_qos_flags_status pm_qos_stat;
        int             port1 = udev->portnum;
        int             status;
+       bool            really_suspend = true;
 
        /* enable remote wakeup when appropriate; this lets the device
         * wake up the upstream hub (including maybe the root hub).
@@ -2949,9 +2958,19 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
        /* see 7.1.7.6 */
        if (hub_is_superspeed(hub->hdev))
                status = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_U3);
-       else
+       else if (PMSG_IS_AUTO(msg))
                status = set_port_feature(hub->hdev, port1,
                                                USB_PORT_FEAT_SUSPEND);
+       /*
+        * For system suspend, we do not need to enable the suspend feature
+        * on individual USB-2 ports.  The devices will automatically go
+        * into suspend a few ms after the root hub stops sending packets.
+        * The USB 2.0 spec calls this "global suspend".
+        */
+       else {
+               really_suspend = false;
+               status = 0;
+       }
        if (status) {
                dev_dbg(hub->intfdev, "can't suspend port %d, status %d\n",
                                port1, status);
@@ -2987,8 +3006,10 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
                                (PMSG_IS_AUTO(msg) ? "auto-" : ""),
                                udev->do_remote_wakeup);
                usb_set_device_state(udev, USB_STATE_SUSPENDED);
-               udev->port_is_suspended = 1;
-               msleep(10);
+               if (really_suspend) {
+                       udev->port_is_suspended = 1;
+                       msleep(10);
+               }
        }
 
        /*
@@ -3226,6 +3247,10 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
        return status;
 }
 
+#endif /* CONFIG_PM */
+
+#ifdef CONFIG_PM_RUNTIME
+
 /* caller has locked udev */
 int usb_remote_wakeup(struct usb_device *udev)
 {
@@ -3242,38 +3267,6 @@ int usb_remote_wakeup(struct usb_device *udev)
        return status;
 }
 
-#else  /* CONFIG_USB_SUSPEND */
-
-/* When CONFIG_USB_SUSPEND isn't set, we never suspend or resume any ports. */
-
-int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
-{
-       return 0;
-}
-
-/* However we may need to do a reset-resume */
-
-int usb_port_resume(struct usb_device *udev, pm_message_t msg)
-{
-       struct usb_hub  *hub = usb_hub_to_struct_hub(udev->parent);
-       int             port1 = udev->portnum;
-       int             status;
-       u16             portchange, portstatus;
-
-       status = hub_port_status(hub, port1, &portstatus, &portchange);
-       status = check_port_resume_type(udev,
-                       hub, port1, status, portchange, portstatus);
-
-       if (status) {
-               dev_dbg(&udev->dev, "can't resume, status %d\n", status);
-               hub_port_logical_disconnect(hub, port1);
-       } else if (udev->reset_resume) {
-               dev_dbg(&udev->dev, "reset-resume\n");
-               status = usb_reset_and_verify_device(udev);
-       }
-       return status;
-}
-
 #endif
 
 static int check_ports_changed(struct usb_hub *hub)
@@ -4090,9 +4083,9 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
                                goto fail;
                        }
                        if (r) {
-                               dev_err(&udev->dev,
-                                       "device descriptor read/64, error %d\n",
-                                       r);
+                               if (r != -ENODEV)
+                                       dev_err(&udev->dev, "device descriptor read/64, error %d\n",
+                                                       r);
                                retval = -EMSGSIZE;
                                continue;
                        }
@@ -4112,9 +4105,9 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
                                msleep(200);
                        }
                        if (retval < 0) {
-                               dev_err(&udev->dev,
-                                       "device not accepting address %d, error %d\n",
-                                       devnum, retval);
+                               if (retval != -ENODEV)
+                                       dev_err(&udev->dev, "device not accepting address %d, error %d\n",
+                                                       devnum, retval);
                                goto fail;
                        }
                        if (udev->speed == USB_SPEED_SUPER) {
@@ -4136,7 +4129,8 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
 
                retval = usb_get_device_descriptor(udev, 8);
                if (retval < 8) {
-                       dev_err(&udev->dev,
+                       if (retval != -ENODEV)
+                               dev_err(&udev->dev,
                                        "device descriptor read/8, error %d\n",
                                        retval);
                        if (retval >= 0)
@@ -4190,8 +4184,9 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
   
        retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE);
        if (retval < (signed)sizeof(udev->descriptor)) {
-               dev_err(&udev->dev, "device descriptor read/all, error %d\n",
-                       retval);
+               if (retval != -ENODEV)
+                       dev_err(&udev->dev, "device descriptor read/all, error %d\n",
+                                       retval);
                if (retval >= 0)
                        retval = -ENOMSG;
                goto fail;
@@ -4333,7 +4328,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
                if (portstatus & USB_PORT_STAT_ENABLE) {
                        status = 0;             /* Nothing to do */
 
-#ifdef CONFIG_USB_SUSPEND
+#ifdef CONFIG_PM_RUNTIME
                } else if (udev->state == USB_STATE_SUSPENDED &&
                                udev->persist_enabled) {
                        /* For a suspended device, treat this as a
@@ -4373,7 +4368,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
                                USB_PORT_STAT_C_ENABLE)) {
                status = hub_port_debounce_be_stable(hub, port1);
                if (status < 0) {
-                       if (printk_ratelimit())
+                       if (status != -ENODEV && printk_ratelimit())
                                dev_err(hub_dev, "connect-debounce failed, "
                                                "port %d disabled\n", port1);
                        portstatus &= ~USB_PORT_STAT_CONNECTION;
@@ -4402,6 +4397,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
        else
                unit_load = 100;
 
+       status = 0;
        for (i = 0; i < SET_CONFIG_TRIES; i++) {
 
                /* reallocate for each attempt, since references
@@ -4526,9 +4522,11 @@ loop:
        }
        if (hub->hdev->parent ||
                        !hcd->driver->port_handed_over ||
-                       !(hcd->driver->port_handed_over)(hcd, port1))
-               dev_err(hub_dev, "unable to enumerate USB device on port %d\n",
-                               port1);
+                       !(hcd->driver->port_handed_over)(hcd, port1)) {
+               if (status != -ENOTCONN && status != -ENODEV)
+                       dev_err(hub_dev, "unable to enumerate USB device on port %d\n",
+                                       port1);
+       }
  
 done:
        hub_port_disable(hub, port1, 1);
index 797f9d51473298582d166858b30e5e464ee2b18c..06c4894bf181bddb3e6d2c86a48dc90fa584917a 100644 (file)
@@ -71,7 +71,7 @@ static void usb_port_device_release(struct device *dev)
        kfree(port_dev);
 }
 
-#ifdef CONFIG_USB_SUSPEND
+#ifdef CONFIG_PM_RUNTIME
 static int usb_port_runtime_resume(struct device *dev)
 {
        struct usb_port *port_dev = to_usb_port(dev);
@@ -139,7 +139,7 @@ static int usb_port_runtime_suspend(struct device *dev)
 #endif
 
 static const struct dev_pm_ops usb_port_pm_ops = {
-#ifdef CONFIG_USB_SUSPEND
+#ifdef CONFIG_PM_RUNTIME
        .runtime_suspend =      usb_port_runtime_suspend,
        .runtime_resume =       usb_port_runtime_resume,
        .runtime_idle =         pm_generic_runtime_idle,
index 3113c1d71442953d3f9659afff042064bca8a9b9..ab5638d9c707c0524eb37a58fc1ce3e95d1a7ae9 100644 (file)
@@ -201,20 +201,14 @@ void usb_detect_quirks(struct usb_device *udev)
                dev_dbg(&udev->dev, "USB quirks for this device: %x\n",
                        udev->quirks);
 
-       /* For the present, all devices default to USB-PERSIST enabled */
-#if 0          /* was: #ifdef CONFIG_PM */
-       /* Hubs are automatically enabled for USB-PERSIST */
-       if (udev->descriptor.bDeviceClass == USB_CLASS_HUB)
+#ifdef CONFIG_USB_DEFAULT_PERSIST
+       if (!(udev->quirks & USB_QUIRK_RESET))
                udev->persist_enabled = 1;
-
 #else
-       /* In the absence of PM, we can safely enable USB-PERSIST
-        * for all devices.  It will affect things like hub resets
-        * and EMF-related port disables.
-        */
-       if (!(udev->quirks & USB_QUIRK_RESET))
+       /* Hubs are automatically enabled for USB-PERSIST */
+       if (udev->descriptor.bDeviceClass == USB_CLASS_HUB)
                udev->persist_enabled = 1;
-#endif /* CONFIG_PM */
+#endif /* CONFIG_USB_DEFAULT_PERSIST */
 }
 
 void usb_detect_interface_quirks(struct usb_device *udev)
index 3f81a3dc6867638a17ab4b0e2850aa1d79ec33c3..aa38db44818a99ab9331c11d2c670669d014498f 100644 (file)
@@ -338,7 +338,7 @@ static void remove_persist_attributes(struct device *dev)
 
 #endif /* CONFIG_PM */
 
-#ifdef CONFIG_USB_SUSPEND
+#ifdef CONFIG_PM_RUNTIME
 
 static ssize_t
 show_connected_duration(struct device *dev, struct device_attribute *attr,
@@ -544,7 +544,7 @@ static void remove_power_attributes(struct device *dev)
 #define add_power_attributes(dev)      0
 #define remove_power_attributes(dev)   do {} while (0)
 
-#endif /* CONFIG_USB_SUSPEND */
+#endif /* CONFIG_PM_RUNTIME */
 
 
 /* Descriptor fields */
index e0d9d948218c665ce09730c00730757a5c33986e..16927fa88fbd61d2e81d02a42b6d1dfefac1fa65 100644 (file)
@@ -683,10 +683,13 @@ EXPORT_SYMBOL_GPL(usb_kill_urb);
 void usb_poison_urb(struct urb *urb)
 {
        might_sleep();
-       if (!(urb && urb->dev && urb->ep))
+       if (!urb)
                return;
        atomic_inc(&urb->reject);
 
+       if (!urb->dev || !urb->ep)
+               return;
+
        usb_hcd_unlink_urb(urb, -ENOENT);
        wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0);
 }
index f81b92572735449b53e5c464ca12d38b314e1029..03eb7ae8fc1a3401e580d78af7a2fee1c4fe9a93 100644 (file)
@@ -49,7 +49,7 @@ const char *usbcore_name = "usbcore";
 
 static bool nousb;     /* Disable USB when built into kernel image */
 
-#ifdef CONFIG_USB_SUSPEND
+#ifdef CONFIG_PM_RUNTIME
 static int usb_autosuspend_delay = 2;          /* Default delay value,
                                                 * in seconds */
 module_param_named(autosuspend, usb_autosuspend_delay, int, 0644);
@@ -307,7 +307,7 @@ static const struct dev_pm_ops usb_device_pm_ops = {
        .thaw =         usb_dev_thaw,
        .poweroff =     usb_dev_poweroff,
        .restore =      usb_dev_restore,
-#ifdef CONFIG_USB_SUSPEND
+#ifdef CONFIG_PM_RUNTIME
        .runtime_suspend =      usb_runtime_suspend,
        .runtime_resume =       usb_runtime_resume,
        .runtime_idle =         usb_runtime_idle,
index a7f20bde0e5e2a18d202a346b1e4024af28fd796..823857767a16f3384730dcf1f90c42f8eedc3588 100644 (file)
@@ -93,7 +93,7 @@ static inline int usb_port_resume(struct usb_device *udev, pm_message_t msg)
 
 #endif
 
-#ifdef CONFIG_USB_SUSPEND
+#ifdef CONFIG_PM_RUNTIME
 
 extern void usb_autosuspend_device(struct usb_device *udev);
 extern int usb_autoresume_device(struct usb_device *udev);
index c59a1126926f3210dd47d524d6ae5d184a5d535c..2f682219e25774935ef5bb78820c601369f7aec9 100644 (file)
@@ -155,8 +155,9 @@ config USB_EHCI_MXC
          Variation of ARC USB block used in some Freescale chips.
 
 config USB_EHCI_HCD_OMAP
-       bool "EHCI support for OMAP3 and later chips"
+       tristate "EHCI support for OMAP3 and later chips"
        depends on USB_EHCI_HCD && ARCH_OMAP
+       select NOP_USB_XCEIV
        default y
        ---help---
          Enables support for the on-chip EHCI controller on
index 001fbff2fdefedbb346f71db705f8e687201e454..56de4106c8b3607bdd62a9ae01a46daafb1e52e4 100644 (file)
@@ -27,6 +27,7 @@ obj-$(CONFIG_USB_EHCI_HCD)    += ehci-hcd.o
 obj-$(CONFIG_USB_EHCI_PCI)     += ehci-pci.o
 obj-$(CONFIG_USB_EHCI_HCD_PLATFORM)    += ehci-platform.o
 obj-$(CONFIG_USB_EHCI_MXC)     += ehci-mxc.o
+obj-$(CONFIG_USB_EHCI_HCD_OMAP)        += ehci-omap.o
 
 obj-$(CONFIG_USB_OXU210HP_HCD) += oxu210hp-hcd.o
 obj-$(CONFIG_USB_ISP116X_HCD)  += isp116x-hcd.o
index 70b496dc18a008c0bbfc261f5005bdd5ca50d204..5429d2645bbc943eb616b1438af21027aa49f124 100644 (file)
@@ -510,14 +510,16 @@ static ssize_t fill_async_buffer(struct debug_buffer *buf)
        spin_lock_irqsave (&ehci->lock, flags);
        for (qh = ehci->async->qh_next.qh; size > 0 && qh; qh = qh->qh_next.qh)
                qh_lines (ehci, qh, &next, &size);
-       if (ehci->async_unlink && size > 0) {
+       if (!list_empty(&ehci->async_unlink) && size > 0) {
                temp = scnprintf(next, size, "\nunlink =\n");
                size -= temp;
                next += temp;
 
-               for (qh = ehci->async_unlink; size > 0 && qh;
-                               qh = qh->unlink_next)
-                       qh_lines (ehci, qh, &next, &size);
+               list_for_each_entry(qh, &ehci->async_unlink, unlink_node) {
+                       if (size <= 0)
+                               break;
+                       qh_lines(ehci, qh, &next, &size);
+               }
        }
        spin_unlock_irqrestore (&ehci->lock, flags);
 
@@ -814,9 +816,10 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
                }
        }
 
-       if (ehci->async_unlink) {
+       if (!list_empty(&ehci->async_unlink)) {
                temp = scnprintf(next, size, "async unlink qh %p\n",
-                               ehci->async_unlink);
+                               list_first_entry(&ehci->async_unlink,
+                                               struct ehci_qh, unlink_node));
                size -= temp;
                next += temp;
        }
index 416a6dce5e11c8adeeed2eef487b93c93dd5d728..b12b97d2ccafd628db4c0e744c1b4d3202a295cf 100644 (file)
@@ -482,6 +482,9 @@ static int ehci_init(struct usb_hcd *hcd)
         * periodic_size can shrink by USBCMD update if hcc_params allows.
         */
        ehci->periodic_size = DEFAULT_I_TDPS;
+       INIT_LIST_HEAD(&ehci->async_unlink);
+       INIT_LIST_HEAD(&ehci->async_idle);
+       INIT_LIST_HEAD(&ehci->intr_unlink);
        INIT_LIST_HEAD(&ehci->intr_qh_list);
        INIT_LIST_HEAD(&ehci->cached_itd_list);
        INIT_LIST_HEAD(&ehci->cached_sitd_list);
@@ -749,7 +752,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
                /* guard against (alleged) silicon errata */
                if (cmd & CMD_IAAD)
                        ehci_dbg(ehci, "IAA with IAAD still set?\n");
-               if (ehci->async_iaa)
+               if (ehci->iaa_in_progress)
                        COUNT(ehci->stats.iaa);
                end_unlink_async(ehci);
        }
@@ -757,7 +760,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
        /* remote wakeup [4.3.1] */
        if (status & STS_PCD) {
                unsigned        i = HCS_N_PORTS (ehci->hcs_params);
-               u32             ppcd = 0;
+               u32             ppcd = ~0;
 
                /* kick root hub later */
                pcd_status = status;
@@ -774,7 +777,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
                        int pstatus;
 
                        /* leverage per-port change bits feature */
-                       if (ehci->has_ppcd && !(ppcd & (1 << i)))
+                       if (!(ppcd & (1 << i)))
                                continue;
                        pstatus = ehci_readl(ehci,
                                         &ehci->regs->port_status[i]);
@@ -896,17 +899,24 @@ static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
        if (rc)
                goto done;
 
-       switch (usb_pipetype (urb->pipe)) {
-       // case PIPE_CONTROL:
-       // case PIPE_BULK:
-       default:
+       if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+               /*
+                * We don't expedite dequeue for isochronous URBs.
+                * Just wait until they complete normally or their
+                * time slot expires.
+                */
+       } else {
                qh = (struct ehci_qh *) urb->hcpriv;
-               if (!qh)
-                       break;
+               qh->exception = 1;
                switch (qh->qh_state) {
                case QH_STATE_LINKED:
+                       if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)
+                               start_unlink_intr(ehci, qh);
+                       else
+                               start_unlink_async(ehci, qh);
+                       break;
                case QH_STATE_COMPLETING:
-                       start_unlink_async(ehci, qh);
+                       qh->dequeue_during_giveback = 1;
                        break;
                case QH_STATE_UNLINK:
                case QH_STATE_UNLINK_WAIT:
@@ -917,33 +927,6 @@ static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
                        qh_completions(ehci, qh);
                        break;
                }
-               break;
-
-       case PIPE_INTERRUPT:
-               qh = (struct ehci_qh *) urb->hcpriv;
-               if (!qh)
-                       break;
-               switch (qh->qh_state) {
-               case QH_STATE_LINKED:
-               case QH_STATE_COMPLETING:
-                       start_unlink_intr(ehci, qh);
-                       break;
-               case QH_STATE_IDLE:
-                       qh_completions (ehci, qh);
-                       break;
-               default:
-                       ehci_dbg (ehci, "bogus qh %p state %d\n",
-                                       qh, qh->qh_state);
-                       goto done;
-               }
-               break;
-
-       case PIPE_ISOCHRONOUS:
-               // itd or sitd ...
-
-               // wait till next completion, do it then.
-               // completion irqs can wait up to 1024 msec,
-               break;
        }
 done:
        spin_unlock_irqrestore (&ehci->lock, flags);
@@ -984,6 +967,7 @@ rescan:
                goto done;
        }
 
+       qh->exception = 1;
        if (ehci->rh_state < EHCI_RH_RUNNING)
                qh->qh_state = QH_STATE_IDLE;
        switch (qh->qh_state) {
@@ -1052,13 +1036,12 @@ ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
                usb_settoggle(qh->dev, epnum, is_out, 0);
                if (!list_empty(&qh->qtd_list)) {
                        WARN_ONCE(1, "clear_halt for a busy endpoint\n");
-               } else if (qh->qh_state == QH_STATE_LINKED ||
-                               qh->qh_state == QH_STATE_COMPLETING) {
-
+               } else {
                        /* The toggle value in the QH can't be updated
                         * while the QH is active.  Unlink it now;
                         * re-linking will call qh_refresh().
                         */
+                       qh->exception = 1;
                        if (eptype == USB_ENDPOINT_XFER_BULK)
                                start_unlink_async(ehci, qh);
                        else
@@ -1251,11 +1234,6 @@ MODULE_LICENSE ("GPL");
 #define PLATFORM_DRIVER                ehci_hcd_sh_driver
 #endif
 
-#ifdef CONFIG_USB_EHCI_HCD_OMAP
-#include "ehci-omap.c"
-#define        PLATFORM_DRIVER         ehci_hcd_omap_driver
-#endif
-
 #ifdef CONFIG_PPC_PS3
 #include "ehci-ps3.c"
 #define        PS3_SYSTEM_BUS_DRIVER   ps3_ehci_driver
@@ -1291,11 +1269,6 @@ MODULE_LICENSE ("GPL");
 #define PLATFORM_DRIVER                ehci_octeon_driver
 #endif
 
-#ifdef CONFIG_ARCH_VT8500
-#include "ehci-vt8500.c"
-#define        PLATFORM_DRIVER         vt8500_ehci_driver
-#endif
-
 #ifdef CONFIG_PLAT_SPEAR
 #include "ehci-spear.c"
 #define PLATFORM_DRIVER                spear_ehci_hcd_driver
@@ -1345,6 +1318,7 @@ MODULE_LICENSE ("GPL");
        !IS_ENABLED(CONFIG_USB_EHCI_HCD_PLATFORM) && \
        !IS_ENABLED(CONFIG_USB_CHIPIDEA_HOST) && \
        !IS_ENABLED(CONFIG_USB_EHCI_MXC) && \
+       !IS_ENABLED(CONFIG_USB_EHCI_HCD_OMAP) && \
        !defined(PLATFORM_DRIVER) && \
        !defined(PS3_SYSTEM_BUS_DRIVER) && \
        !defined(OF_PLATFORM_DRIVER) && \
index 7d06e77f6c4fa0116ea69ad239753ea4dffe20fd..7b04ca96b58598dbac7dec332af8061ba3ebba35 100644 (file)
@@ -464,7 +464,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
        while (i--) {
                temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
                if (test_bit(i, &resume_needed)) {
-                       temp &= ~(PORT_RWC_BITS | PORT_RESUME);
+                       temp &= ~(PORT_RWC_BITS | PORT_SUSPEND | PORT_RESUME);
                        ehci_writel(ehci, temp, &ehci->regs->port_status [i]);
                        ehci_vdbg (ehci, "resumed port %d\n", i + 1);
                }
@@ -590,7 +590,7 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
        u32             mask;
        int             ports, i, retval = 1;
        unsigned long   flags;
-       u32             ppcd = 0;
+       u32             ppcd = ~0;
 
        /* init status to no-changes */
        buf [0] = 0;
@@ -628,9 +628,10 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
 
        for (i = 0; i < ports; i++) {
                /* leverage per-port change bits feature */
-               if (ehci->has_ppcd && !(ppcd & (1 << i)))
-                       continue;
-               temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
+               if (ppcd & (1 << i))
+                       temp = ehci_readl(ehci, &ehci->regs->port_status[i]);
+               else
+                       temp = 0;
 
                /*
                 * Return status information even for ports with OWNER set.
@@ -870,10 +871,9 @@ static int ehci_hub_control (
                                usb_hcd_end_port_resume(&hcd->self, wIndex);
 
                                /* stop resume signaling */
-                               temp = ehci_readl(ehci, status_reg);
-                               ehci_writel(ehci,
-                                       temp & ~(PORT_RWC_BITS | PORT_RESUME),
-                                       status_reg);
+                               temp &= ~(PORT_RWC_BITS |
+                                               PORT_SUSPEND | PORT_RESUME);
+                               ehci_writel(ehci, temp, status_reg);
                                clear_bit(wIndex, &ehci->resuming_ports);
                                retval = handshake(ehci, status_reg,
                                           PORT_RESUME, 0, 2000 /* 2msec */);
@@ -883,7 +883,7 @@ static int ehci_hub_control (
                                                wIndex + 1, retval);
                                        goto error;
                                }
-                               temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
+                               temp = ehci_readl(ehci, status_reg);
                        }
                }
 
index 3065809546b159c1966b87f5fe4cdc6c333bc3da..5cd9f96ed92df495147b9791d3cb5c44bc792548 100644 (file)
@@ -225,7 +225,7 @@ static int mv_ehci_probe(struct platform_device *pdev)
                (void __iomem *) ((unsigned long) ehci_mv->cap_regs + offset);
 
        hcd->rsrc_start = r->start;
-       hcd->rsrc_len = r->end - r->start + 1;
+       hcd->rsrc_len = resource_size(r);
        hcd->regs = ehci_mv->op_regs;
 
        hcd->irq = platform_get_irq(pdev, 0);
index e9301fb97eaa328337dc2ef0a4dd1329457575d3..a38c8c8e5b0d9fdc6d25c61f4f79322bddfdf02d 100644 (file)
 #include <linux/slab.h>
 #include <linux/usb.h>
 #include <linux/usb/hcd.h>
-
 #include <linux/platform_data/usb-ehci-mxc.h>
-
-#include <asm/mach-types.h>
-
 #include "ehci.h"
 
 #define DRIVER_DESC "Freescale On-Chip EHCI Host driver"
@@ -61,8 +57,6 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct ehci_hcd *ehci;
 
-       dev_info(&pdev->dev, "initializing i.MX USB Controller\n");
-
        if (!pdata) {
                dev_err(dev, "No platform data given, bailing out.\n");
                return -EINVAL;
@@ -178,7 +172,7 @@ err_alloc:
        return ret;
 }
 
-static int __exit ehci_mxc_drv_remove(struct platform_device *pdev)
+static int ehci_mxc_drv_remove(struct platform_device *pdev)
 {
        struct mxc_usbh_platform_data *pdata = pdev->dev.platform_data;
        struct usb_hcd *hcd = platform_get_drvdata(pdev);
index 0555ee42d7cb1882cf284a2f8019ce8a091be961..5de3e43ded50775bf5f2173e564e410b7ba433cd 100644 (file)
@@ -4,10 +4,11 @@
  * Bus Glue for the EHCI controllers in OMAP3/4
  * Tested on several OMAP3 boards, and OMAP4 Pandaboard
  *
- * Copyright (C) 2007-2011 Texas Instruments, Inc.
+ * Copyright (C) 2007-2013 Texas Instruments, Inc.
  *     Author: Vikram Pandita <vikram.pandita@ti.com>
  *     Author: Anand Gadiyar <gadiyar@ti.com>
  *     Author: Keshava Munegowda <keshava_mgowda@ti.com>
+ *     Author: Roger Quadros <rogerq@ti.com>
  *
  * Copyright (C) 2009 Nokia Corporation
  *     Contact: Felipe Balbi <felipe.balbi@nokia.com>
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  *
- * TODO (last updated Feb 27, 2010):
- *     - add kernel-doc
- *     - enable AUTOIDLE
- *     - add suspend/resume
- *     - add HSIC and TLL support
- *     - convert to use hwmod and runtime PM
  */
 
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/usb/ulpi.h>
-#include <linux/regulator/consumer.h>
 #include <linux/pm_runtime.h>
 #include <linux/gpio.h>
 #include <linux/clk.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+#include <linux/of.h>
+#include <linux/dma-mapping.h>
+
+#include "ehci.h"
 
 #include <linux/platform_data/usb-omap.h>
 
 #define        EHCI_INSNREG05_ULPI_EXTREGADD_SHIFT             8
 #define        EHCI_INSNREG05_ULPI_WRDATA_SHIFT                0
 
-/*-------------------------------------------------------------------------*/
+#define DRIVER_DESC "OMAP-EHCI Host Controller driver"
+
+static const char hcd_name[] = "ehci-omap";
 
-static const struct hc_driver ehci_omap_hc_driver;
+/*-------------------------------------------------------------------------*/
 
+struct omap_hcd {
+       struct usb_phy *phy[OMAP3_HS_USB_PORTS]; /* one PHY for each port */
+       int nports;
+};
 
 static inline void ehci_write(void __iomem *base, u32 reg, u32 val)
 {
@@ -72,99 +81,16 @@ static inline u32 ehci_read(void __iomem *base, u32 reg)
        return __raw_readl(base + reg);
 }
 
+/* configure so an HC device and id are always provided */
+/* always called with process context; sleeping is OK */
 
-static void omap_ehci_soft_phy_reset(struct usb_hcd *hcd, u8 port)
-{
-       unsigned long timeout = jiffies + msecs_to_jiffies(1000);
-       unsigned reg = 0;
-
-       reg = ULPI_FUNC_CTRL_RESET
-               /* FUNCTION_CTRL_SET register */
-               | (ULPI_SET(ULPI_FUNC_CTRL) << EHCI_INSNREG05_ULPI_REGADD_SHIFT)
-               /* Write */
-               | (2 << EHCI_INSNREG05_ULPI_OPSEL_SHIFT)
-               /* PORTn */
-               | ((port + 1) << EHCI_INSNREG05_ULPI_PORTSEL_SHIFT)
-               /* start ULPI access*/
-               | (1 << EHCI_INSNREG05_ULPI_CONTROL_SHIFT);
-
-       ehci_write(hcd->regs, EHCI_INSNREG05_ULPI, reg);
-
-       /* Wait for ULPI access completion */
-       while ((ehci_read(hcd->regs, EHCI_INSNREG05_ULPI)
-                       & (1 << EHCI_INSNREG05_ULPI_CONTROL_SHIFT))) {
-               cpu_relax();
-
-               if (time_after(jiffies, timeout)) {
-                       dev_dbg(hcd->self.controller,
-                                       "phy reset operation timed out\n");
-                       break;
-               }
-       }
-}
-
-static int omap_ehci_init(struct usb_hcd *hcd)
-{
-       struct ehci_hcd         *ehci = hcd_to_ehci(hcd);
-       int                     rc;
-       struct usbhs_omap_platform_data *pdata;
-
-       pdata = hcd->self.controller->platform_data;
-
-       /* Hold PHYs in reset while initializing EHCI controller */
-       if (pdata->phy_reset) {
-               if (gpio_is_valid(pdata->reset_gpio_port[0]))
-                       gpio_set_value_cansleep(pdata->reset_gpio_port[0], 0);
-
-               if (gpio_is_valid(pdata->reset_gpio_port[1]))
-                       gpio_set_value_cansleep(pdata->reset_gpio_port[1], 0);
-
-               /* Hold the PHY in RESET for enough time till DIR is high */
-               udelay(10);
-       }
-
-       /* Soft reset the PHY using PHY reset command over ULPI */
-       if (pdata->port_mode[0] == OMAP_EHCI_PORT_MODE_PHY)
-               omap_ehci_soft_phy_reset(hcd, 0);
-       if (pdata->port_mode[1] == OMAP_EHCI_PORT_MODE_PHY)
-               omap_ehci_soft_phy_reset(hcd, 1);
-
-       /* we know this is the memory we want, no need to ioremap again */
-       ehci->caps = hcd->regs;
-
-       rc = ehci_setup(hcd);
-
-       if (pdata->phy_reset) {
-               /* Hold the PHY in RESET for enough time till
-                * PHY is settled and ready
-                */
-               udelay(10);
-
-               if (gpio_is_valid(pdata->reset_gpio_port[0]))
-                       gpio_set_value_cansleep(pdata->reset_gpio_port[0], 1);
-
-               if (gpio_is_valid(pdata->reset_gpio_port[1]))
-                       gpio_set_value_cansleep(pdata->reset_gpio_port[1], 1);
-       }
-
-       return rc;
-}
+static struct hc_driver __read_mostly ehci_omap_hc_driver;
 
-static void disable_put_regulator(
-               struct usbhs_omap_platform_data *pdata)
-{
-       int i;
-
-       for (i = 0 ; i < OMAP3_HS_USB_PORTS ; i++) {
-               if (pdata->regulator[i]) {
-                       regulator_disable(pdata->regulator[i]);
-                       regulator_put(pdata->regulator[i]);
-               }
-       }
-}
+static const struct ehci_driver_overrides ehci_omap_overrides __initdata = {
+       .extra_priv_size = sizeof(struct omap_hcd),
+};
 
-/* configure so an HC device and id are always provided */
-/* always called with process context; sleeping is OK */
+static u64 omap_ehci_dma_mask = DMA_BIT_MASK(32);
 
 /**
  * ehci_hcd_omap_probe - initialize TI-based HCDs
@@ -175,15 +101,15 @@ static void disable_put_regulator(
  */
 static int ehci_hcd_omap_probe(struct platform_device *pdev)
 {
-       struct device                           *dev = &pdev->dev;
-       struct usbhs_omap_platform_data         *pdata = dev->platform_data;
-       struct resource                         *res;
-       struct usb_hcd                          *hcd;
-       void __iomem                            *regs;
-       int                                     ret = -ENODEV;
-       int                                     irq;
-       int                                     i;
-       char                                    supply[7];
+       struct device *dev = &pdev->dev;
+       struct usbhs_omap_platform_data *pdata = dev->platform_data;
+       struct resource *res;
+       struct usb_hcd  *hcd;
+       void __iomem *regs;
+       int ret = -ENODEV;
+       int irq;
+       int i;
+       struct omap_hcd *omap;
 
        if (usb_disabled())
                return -ENODEV;
@@ -193,52 +119,74 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       irq = platform_get_irq_byname(pdev, "ehci-irq");
-       if (irq < 0) {
-               dev_err(dev, "EHCI irq failed\n");
-               return -ENODEV;
+       /* For DT boot, get platform data from parent. i.e. usbhshost */
+       if (dev->of_node) {
+               pdata = dev->parent->platform_data;
+               dev->platform_data = pdata;
        }
 
-       res =  platform_get_resource_byname(pdev,
-                               IORESOURCE_MEM, "ehci");
-       if (!res) {
-               dev_err(dev, "UHH EHCI get resource failed\n");
+       if (!pdata) {
+               dev_err(dev, "Missing platform data\n");
                return -ENODEV;
        }
 
-       regs = ioremap(res->start, resource_size(res));
-       if (!regs) {
-               dev_err(dev, "UHH EHCI ioremap failed\n");
-               return -ENOMEM;
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(dev, "EHCI irq failed\n");
+               return -ENODEV;
        }
 
+       res =  platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       regs = devm_ioremap_resource(dev, res);
+       if (IS_ERR(regs))
+               return PTR_ERR(regs);
+
+       /*
+        * Right now device-tree probed devices don't get dma_mask set.
+        * Since shared usb code relies on it, set it here for now.
+        * Once we have dma capability bindings this can go away.
+        */
+       if (!pdev->dev.dma_mask)
+               pdev->dev.dma_mask = &omap_ehci_dma_mask;
+
        hcd = usb_create_hcd(&ehci_omap_hc_driver, dev,
                        dev_name(dev));
        if (!hcd) {
-               dev_err(dev, "failed to create hcd with err %d\n", ret);
-               ret = -ENOMEM;
-               goto err_io;
+               dev_err(dev, "Failed to create HCD\n");
+               return -ENOMEM;
        }
 
        hcd->rsrc_start = res->start;
        hcd->rsrc_len = resource_size(res);
        hcd->regs = regs;
-
-       /* get ehci regulator and enable */
-       for (i = 0 ; i < OMAP3_HS_USB_PORTS ; i++) {
-               if (pdata->port_mode[i] != OMAP_EHCI_PORT_MODE_PHY) {
-                       pdata->regulator[i] = NULL;
-                       continue;
-               }
-               snprintf(supply, sizeof(supply), "hsusb%d", i);
-               pdata->regulator[i] = regulator_get(dev, supply);
-               if (IS_ERR(pdata->regulator[i])) {
-                       pdata->regulator[i] = NULL;
-                       dev_dbg(dev,
-                       "failed to get ehci port%d regulator\n", i);
-               } else {
-                       regulator_enable(pdata->regulator[i]);
+       hcd_to_ehci(hcd)->caps = regs;
+
+       omap = (struct omap_hcd *)hcd_to_ehci(hcd)->priv;
+       omap->nports = pdata->nports;
+
+       platform_set_drvdata(pdev, hcd);
+
+       /* get the PHY devices if needed */
+       for (i = 0 ; i < omap->nports ; i++) {
+               struct usb_phy *phy;
+
+               /* get the PHY device */
+               if (dev->of_node)
+                       phy = devm_usb_get_phy_by_phandle(dev, "phys", i);
+               else
+                       phy = devm_usb_get_phy_dev(dev, i);
+               if (IS_ERR(phy) || !phy) {
+                       /* Don't bail out if PHY is not absolutely necessary */
+                       if (pdata->port_mode[i] != OMAP_EHCI_PORT_MODE_PHY)
+                               continue;
+
+                       ret = IS_ERR(phy) ? PTR_ERR(phy) : -ENODEV;
+                       dev_err(dev, "Can't get PHY device for port %d: %d\n",
+                                       i, ret);
+                       goto err_phy;
                }
+
+               omap->phy[i] = phy;
        }
 
        pm_runtime_enable(dev);
@@ -262,16 +210,34 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
                goto err_pm_runtime;
        }
 
+       /*
+        * Bring PHYs out of reset.
+        * Even though HSIC mode is a PHY-less mode, the reset
+        * line exists between the chips and can be modelled
+        * as a PHY device for reset control.
+        */
+       for (i = 0; i < omap->nports; i++) {
+               if (!omap->phy[i])
+                       continue;
+
+               usb_phy_init(omap->phy[i]);
+               /* bring PHY out of suspend */
+               usb_phy_set_suspend(omap->phy[i], 0);
+       }
 
        return 0;
 
 err_pm_runtime:
-       disable_put_regulator(pdata);
        pm_runtime_put_sync(dev);
+
+err_phy:
+       for (i = 0; i < omap->nports; i++) {
+               if (omap->phy[i])
+                       usb_phy_shutdown(omap->phy[i]);
+       }
+
        usb_put_hcd(hcd);
 
-err_io:
-       iounmap(regs);
        return ret;
 }
 
@@ -286,14 +252,19 @@ err_io:
  */
 static int ehci_hcd_omap_remove(struct platform_device *pdev)
 {
-       struct device *dev                              = &pdev->dev;
-       struct usb_hcd *hcd                             = dev_get_drvdata(dev);
+       struct device *dev = &pdev->dev;
+       struct usb_hcd *hcd = dev_get_drvdata(dev);
+       struct omap_hcd *omap = (struct omap_hcd *)hcd_to_ehci(hcd)->priv;
+       int i;
 
        usb_remove_hcd(hcd);
-       disable_put_regulator(dev->platform_data);
-       iounmap(hcd->regs);
-       usb_put_hcd(hcd);
 
+       for (i = 0; i < omap->nports; i++) {
+               if (omap->phy[i])
+                       usb_phy_shutdown(omap->phy[i]);
+       }
+
+       usb_put_hcd(hcd);
        pm_runtime_put_sync(dev);
        pm_runtime_disable(dev);
 
@@ -308,6 +279,13 @@ static void ehci_hcd_omap_shutdown(struct platform_device *pdev)
                hcd->driver->shutdown(hcd);
 }
 
+static const struct of_device_id omap_ehci_dt_ids[] = {
+       { .compatible = "ti,ehci-omap" },
+       { }
+};
+
+MODULE_DEVICE_TABLE(of, omap_ehci_dt_ids);
+
 static struct platform_driver ehci_hcd_omap_driver = {
        .probe                  = ehci_hcd_omap_probe,
        .remove                 = ehci_hcd_omap_remove,
@@ -315,56 +293,35 @@ static struct platform_driver ehci_hcd_omap_driver = {
        /*.suspend              = ehci_hcd_omap_suspend, */
        /*.resume               = ehci_hcd_omap_resume, */
        .driver = {
-               .name           = "ehci-omap",
+               .name           = hcd_name,
+               .of_match_table = of_match_ptr(omap_ehci_dt_ids),
        }
 };
 
 /*-------------------------------------------------------------------------*/
 
-static const struct hc_driver ehci_omap_hc_driver = {
-       .description            = hcd_name,
-       .product_desc           = "OMAP-EHCI Host Controller",
-       .hcd_priv_size          = sizeof(struct ehci_hcd),
-
-       /*
-        * generic hardware linkage
-        */
-       .irq                    = ehci_irq,
-       .flags                  = HCD_MEMORY | HCD_USB2,
-
-       /*
-        * basic lifecycle operations
-        */
-       .reset                  = omap_ehci_init,
-       .start                  = ehci_run,
-       .stop                   = ehci_stop,
-       .shutdown               = ehci_shutdown,
-
-       /*
-        * managing i/o requests and associated device resources
-        */
-       .urb_enqueue            = ehci_urb_enqueue,
-       .urb_dequeue            = ehci_urb_dequeue,
-       .endpoint_disable       = ehci_endpoint_disable,
-       .endpoint_reset         = ehci_endpoint_reset,
+static int __init ehci_omap_init(void)
+{
+       if (usb_disabled())
+               return -ENODEV;
 
-       /*
-        * scheduling support
-        */
-       .get_frame_number       = ehci_get_frame,
+       pr_info("%s: " DRIVER_DESC "\n", hcd_name);
 
-       /*
-        * root hub support
-        */
-       .hub_status_data        = ehci_hub_status_data,
-       .hub_control            = ehci_hub_control,
-       .bus_suspend            = ehci_bus_suspend,
-       .bus_resume             = ehci_bus_resume,
+       ehci_init_driver(&ehci_omap_hc_driver, &ehci_omap_overrides);
+       return platform_driver_register(&ehci_hcd_omap_driver);
+}
+module_init(ehci_omap_init);
 
-       .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
-};
+static void __exit ehci_omap_cleanup(void)
+{
+       platform_driver_unregister(&ehci_hcd_omap_driver);
+}
+module_exit(ehci_omap_cleanup);
 
 MODULE_ALIAS("platform:ehci-omap");
 MODULE_AUTHOR("Texas Instruments, Inc.");
 MODULE_AUTHOR("Felipe Balbi <felipe.balbi@nokia.com>");
+MODULE_AUTHOR("Roger Quadros <rogerq@ti.com>");
 
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
index 914a3ecfb5d361501a9a9e939d82388e34b795bc..38c45fb3357eed576e195905768d6316d16d6dce 100644 (file)
@@ -305,7 +305,7 @@ err1:
        return err;
 }
 
-static int __exit ehci_orion_drv_remove(struct platform_device *pdev)
+static int ehci_orion_drv_remove(struct platform_device *pdev)
 {
        struct usb_hcd *hcd = platform_get_drvdata(pdev);
        struct clk *clk;
@@ -333,7 +333,7 @@ MODULE_DEVICE_TABLE(of, ehci_orion_dt_ids);
 
 static struct platform_driver ehci_orion_driver = {
        .probe          = ehci_orion_drv_probe,
-       .remove         = __exit_p(ehci_orion_drv_remove),
+       .remove         = ehci_orion_drv_remove,
        .shutdown       = usb_hcd_platform_shutdown,
        .driver = {
                .name   = "orion-ehci",
index 170b9399e09f34b42ec798b8e02985c5b0f71190..a573d5ff9adcf213dad7014cc24e434df22a3346 100644 (file)
@@ -292,17 +292,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
                }
        }
 
-#ifdef CONFIG_USB_SUSPEND
-       /* REVISIT: the controller works fine for wakeup iff the root hub
-        * itself is "globally" suspended, but usbcore currently doesn't
-        * understand such things.
-        *
-        * System suspend currently expects to be able to suspend the entire
-        * device tree, device-at-a-time.  If we failed selective suspend
-        * reports, system suspend would fail; so the root hub code must claim
-        * success.  That's lying to usbcore, and it matters for runtime
-        * PM scenarios with selective suspend and remote wakeup...
-        */
+#ifdef CONFIG_PM_RUNTIME
        if (ehci->no_selective_suspend && device_can_wakeup(&pdev->dev))
                ehci_warn(ehci, "selective suspend/wakeup unavailable\n");
 #endif
index ca7506390542bf0e5c75232724477e4832f68f1c..cda0fa9613e7c633c7f4382ddb0b5b3ee5c71ca9 100644 (file)
  *
  * Licensed under the GNU/GPL. See COPYING for details.
  */
+#include <linux/dma-mapping.h>
 #include <linux/err.h>
 #include <linux/kernel.h>
 #include <linux/hrtimer.h>
 #include <linux/io.h>
 #include <linux/module.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/usb.h>
 #include <linux/usb/hcd.h>
@@ -62,22 +64,32 @@ static const struct ehci_driver_overrides platform_overrides __initdata = {
        .reset =        ehci_platform_reset,
 };
 
+static struct usb_ehci_pdata ehci_platform_defaults;
+
 static int ehci_platform_probe(struct platform_device *dev)
 {
        struct usb_hcd *hcd;
        struct resource *res_mem;
-       struct usb_ehci_pdata *pdata = dev->dev.platform_data;
+       struct usb_ehci_pdata *pdata;
        int irq;
        int err = -ENOMEM;
 
-       if (!pdata) {
-               WARN_ON(1);
-               return -ENODEV;
-       }
-
        if (usb_disabled())
                return -ENODEV;
 
+       /*
+        * use reasonable defaults so platforms don't have to provide these.
+        * with DT probing on ARM, none of these are set.
+        */
+       if (!dev->dev.platform_data)
+               dev->dev.platform_data = &ehci_platform_defaults;
+       if (!dev->dev.dma_mask)
+               dev->dev.dma_mask = &dev->dev.coherent_dma_mask;
+       if (!dev->dev.coherent_dma_mask)
+               dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+
+       pdata = dev->dev.platform_data;
+
        irq = platform_get_irq(dev, 0);
        if (irq < 0) {
                dev_err(&dev->dev, "no irq provided");
@@ -139,6 +151,9 @@ static int ehci_platform_remove(struct platform_device *dev)
        if (pdata->power_off)
                pdata->power_off(dev);
 
+       if (pdata == &ehci_platform_defaults)
+               dev->dev.platform_data = NULL;
+
        return 0;
 }
 
@@ -183,6 +198,12 @@ static int ehci_platform_resume(struct device *dev)
 #define ehci_platform_resume   NULL
 #endif /* CONFIG_PM */
 
+static const struct of_device_id vt8500_ehci_ids[] = {
+       { .compatible = "via,vt8500-ehci", },
+       { .compatible = "wm,prizm-ehci", },
+       {}
+};
+
 static const struct platform_device_id ehci_platform_table[] = {
        { "ehci-platform", 0 },
        { }
@@ -203,6 +224,7 @@ static struct platform_driver ehci_platform_driver = {
                .owner  = THIS_MODULE,
                .name   = "ehci-platform",
                .pm     = &ehci_platform_pm_ops,
+               .of_match_table = of_match_ptr(vt8500_ehci_ids),
        }
 };
 
index 23d13690428591b3c71d6c10bc9b29a4ffd0c973..d34b399b78e2c30665792857a34615b6c9a0c227 100644 (file)
@@ -90,7 +90,7 @@ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd)
        struct ehci_qh_hw *hw = qh->hw;
 
        /* writes to an active overlay are unsafe */
-       BUG_ON(qh->qh_state != QH_STATE_IDLE);
+       WARN_ON(qh->qh_state != QH_STATE_IDLE);
 
        hw->hw_qtd_next = QTD_NEXT(ehci, qtd->qtd_dma);
        hw->hw_alt_next = EHCI_LIST_END(ehci);
@@ -123,26 +123,19 @@ qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh)
 {
        struct ehci_qtd *qtd;
 
-       if (list_empty (&qh->qtd_list))
-               qtd = qh->dummy;
-       else {
-               qtd = list_entry (qh->qtd_list.next,
-                               struct ehci_qtd, qtd_list);
-               /*
-                * first qtd may already be partially processed.
-                * If we come here during unlink, the QH overlay region
-                * might have reference to the just unlinked qtd. The
-                * qtd is updated in qh_completions(). Update the QH
-                * overlay here.
-                */
-               if (qh->hw->hw_token & ACTIVE_BIT(ehci)) {
-                       qh->hw->hw_qtd_next = qtd->hw_next;
-                       qtd = NULL;
-               }
-       }
+       qtd = list_entry(qh->qtd_list.next, struct ehci_qtd, qtd_list);
 
-       if (qtd)
-               qh_update (ehci, qh, qtd);
+       /*
+        * first qtd may already be partially processed.
+        * If we come here during unlink, the QH overlay region
+        * might have reference to the just unlinked qtd. The
+        * qtd is updated in qh_completions(). Update the QH
+        * overlay here.
+        */
+       if (qh->hw->hw_token & ACTIVE_BIT(ehci))
+               qh->hw->hw_qtd_next = qtd->hw_next;
+       else
+               qh_update(ehci, qh, qtd);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -299,8 +292,8 @@ static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh);
 
 /*
  * Process and free completed qtds for a qh, returning URBs to drivers.
- * Chases up to qh->hw_current.  Returns number of completions called,
- * indicating how much "real" work we did.
+ * Chases up to qh->hw_current.  Returns nonzero if the caller should
+ * unlink qh.
  */
 static unsigned
 qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
@@ -309,13 +302,9 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
        struct list_head        *entry, *tmp;
        int                     last_status;
        int                     stopped;
-       unsigned                count = 0;
        u8                      state;
        struct ehci_qh_hw       *hw = qh->hw;
 
-       if (unlikely (list_empty (&qh->qtd_list)))
-               return count;
-
        /* completions (or tasks on other cpus) must never clobber HALT
         * till we've gone through and cleaned everything up, even when
         * they add urbs to this qh's queue or mark them for unlinking.
@@ -333,7 +322,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
  rescan:
        last = NULL;
        last_status = -EINPROGRESS;
-       qh->needs_rescan = 0;
+       qh->dequeue_during_giveback = 0;
 
        /* remove de-activated QTDs from front of queue.
         * after faults (including short reads), cleanup this urb
@@ -352,7 +341,6 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
                if (last) {
                        if (likely (last->urb != urb)) {
                                ehci_urb_done(ehci, last->urb, last_status);
-                               count++;
                                last_status = -EINPROGRESS;
                        }
                        ehci_qtd_free (ehci, last);
@@ -526,23 +514,16 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
        /* last urb's completion might still need calling */
        if (likely (last != NULL)) {
                ehci_urb_done(ehci, last->urb, last_status);
-               count++;
                ehci_qtd_free (ehci, last);
        }
 
        /* Do we need to rescan for URBs dequeued during a giveback? */
-       if (unlikely(qh->needs_rescan)) {
+       if (unlikely(qh->dequeue_during_giveback)) {
                /* If the QH is already unlinked, do the rescan now. */
                if (state == QH_STATE_IDLE)
                        goto rescan;
 
-               /* Otherwise we have to wait until the QH is fully unlinked.
-                * Our caller will start an unlink if qh->needs_rescan is
-                * set.  But if an unlink has already started, nothing needs
-                * to be done.
-                */
-               if (state != QH_STATE_LINKED)
-                       qh->needs_rescan = 0;
+               /* Otherwise the caller must unlink the QH. */
        }
 
        /* restore original state; caller must unlink or relink */
@@ -551,33 +532,23 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
        /* be sure the hardware's done with the qh before refreshing
         * it after fault cleanup, or recovering from silicon wrongly
         * overlaying the dummy qtd (which reduces DMA chatter).
+        *
+        * We won't refresh a QH that's linked (after the HC
+        * stopped the queue).  That avoids a race:
+        *  - HC reads first part of QH;
+        *  - CPU updates that first part and the token;
+        *  - HC reads rest of that QH, including token
+        * Result:  HC gets an inconsistent image, and then
+        * DMAs to/from the wrong memory (corrupting it).
+        *
+        * That should be rare for interrupt transfers,
+        * except maybe high bandwidth ...
         */
-       if (stopped != 0 || hw->hw_qtd_next == EHCI_LIST_END(ehci)) {
-               switch (state) {
-               case QH_STATE_IDLE:
-                       qh_refresh(ehci, qh);
-                       break;
-               case QH_STATE_LINKED:
-                       /* We won't refresh a QH that's linked (after the HC
-                        * stopped the queue).  That avoids a race:
-                        *  - HC reads first part of QH;
-                        *  - CPU updates that first part and the token;
-                        *  - HC reads rest of that QH, including token
-                        * Result:  HC gets an inconsistent image, and then
-                        * DMAs to/from the wrong memory (corrupting it).
-                        *
-                        * That should be rare for interrupt transfers,
-                        * except maybe high bandwidth ...
-                        */
+       if (stopped != 0 || hw->hw_qtd_next == EHCI_LIST_END(ehci))
+               qh->exception = 1;
 
-                       /* Tell the caller to start an unlink */
-                       qh->needs_rescan = 1;
-                       break;
-               /* otherwise, unlink already started */
-               }
-       }
-
-       return count;
+       /* Let the caller know if the QH needs to be unlinked. */
+       return qh->exception;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -957,14 +928,13 @@ done:
 
        /* NOTE:  if (PIPE_INTERRUPT) { scheduler sets s-mask } */
 
-       /* init as live, toggle clear, advance to dummy */
+       /* init as live, toggle clear */
        qh->qh_state = QH_STATE_IDLE;
        hw = qh->hw;
        hw->hw_info1 = cpu_to_hc32(ehci, info1);
        hw->hw_info2 = cpu_to_hc32(ehci, info2);
        qh->is_out = !is_input;
        usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1);
-       qh_refresh (ehci, qh);
        return qh;
 }
 
@@ -988,8 +958,9 @@ static void disable_async(struct ehci_hcd *ehci)
        if (--ehci->async_count)
                return;
 
-       /* The async schedule and async_unlink list are supposed to be empty */
-       WARN_ON(ehci->async->qh_next.qh || ehci->async_unlink);
+       /* The async schedule and unlink lists are supposed to be empty */
+       WARN_ON(ehci->async->qh_next.qh || !list_empty(&ehci->async_unlink) ||
+                       !list_empty(&ehci->async_idle));
 
        /* Don't turn off the schedule until ASS is 1 */
        ehci_poll_ASS(ehci);
@@ -1020,8 +991,9 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
        head->qh_next.qh = qh;
        head->hw->hw_next = dma;
 
-       qh->xacterrs = 0;
        qh->qh_state = QH_STATE_LINKED;
+       qh->xacterrs = 0;
+       qh->exception = 0;
        /* qtd completions reported later by interrupt */
 
        enable_async(ehci);
@@ -1179,11 +1151,7 @@ static void single_unlink_async(struct ehci_hcd *ehci, struct ehci_qh *qh)
 
        /* Add to the end of the list of QHs waiting for the next IAAD */
        qh->qh_state = QH_STATE_UNLINK_WAIT;
-       if (ehci->async_unlink)
-               ehci->async_unlink_last->unlink_next = qh;
-       else
-               ehci->async_unlink = qh;
-       ehci->async_unlink_last = qh;
+       list_add_tail(&qh->unlink_node, &ehci->async_unlink);
 
        /* Unlink it from the schedule */
        prev = ehci->async;
@@ -1196,44 +1164,19 @@ static void single_unlink_async(struct ehci_hcd *ehci, struct ehci_qh *qh)
                ehci->qh_scan_next = qh->qh_next.qh;
 }
 
-static void start_iaa_cycle(struct ehci_hcd *ehci, bool nested)
+static void start_iaa_cycle(struct ehci_hcd *ehci)
 {
-       /*
-        * Do nothing if an IAA cycle is already running or
-        * if one will be started shortly.
-        */
-       if (ehci->async_iaa || ehci->async_unlinking)
+       /* Do nothing if an IAA cycle is already running */
+       if (ehci->iaa_in_progress)
                return;
+       ehci->iaa_in_progress = true;
 
        /* If the controller isn't running, we don't have to wait for it */
        if (unlikely(ehci->rh_state < EHCI_RH_RUNNING)) {
-
-               /* Do all the waiting QHs */
-               ehci->async_iaa = ehci->async_unlink;
-               ehci->async_unlink = NULL;
-
-               if (!nested)            /* Avoid recursion */
-                       end_unlink_async(ehci);
+               end_unlink_async(ehci);
 
        /* Otherwise start a new IAA cycle */
        } else if (likely(ehci->rh_state == EHCI_RH_RUNNING)) {
-               struct ehci_qh          *qh;
-
-               /* Do only the first waiting QH (nVidia bug?) */
-               qh = ehci->async_unlink;
-
-               /*
-                * Intel (?) bug: The HC can write back the overlay region
-                * even after the IAA interrupt occurs.  In self-defense,
-                * always go through two IAA cycles for each QH.
-                */
-               if (qh->qh_state == QH_STATE_UNLINK_WAIT) {
-                       qh->qh_state = QH_STATE_UNLINK;
-               } else {
-                       ehci->async_iaa = qh;
-                       ehci->async_unlink = qh->unlink_next;
-                       qh->unlink_next = NULL;
-               }
 
                /* Make sure the unlinks are all visible to the hardware */
                wmb();
@@ -1250,36 +1193,73 @@ static void start_iaa_cycle(struct ehci_hcd *ehci, bool nested)
 static void end_unlink_async(struct ehci_hcd *ehci)
 {
        struct ehci_qh          *qh;
+       bool                    early_exit;
 
        if (ehci->has_synopsys_hc_bug)
                ehci_writel(ehci, (u32) ehci->async->qh_dma,
                            &ehci->regs->async_next);
 
+       /* The current IAA cycle has ended */
+       ehci->iaa_in_progress = false;
+
+       if (list_empty(&ehci->async_unlink))
+               return;
+       qh = list_first_entry(&ehci->async_unlink, struct ehci_qh,
+                       unlink_node);   /* QH whose IAA cycle just ended */
+
+       /*
+        * If async_unlinking is set then this routine is already running,
+        * either on the stack or on another CPU.
+        */
+       early_exit = ehci->async_unlinking;
+
+       /* If the controller isn't running, process all the waiting QHs */
+       if (ehci->rh_state < EHCI_RH_RUNNING)
+               list_splice_tail_init(&ehci->async_unlink, &ehci->async_idle);
+
+       /*
+        * Intel (?) bug: The HC can write back the overlay region even
+        * after the IAA interrupt occurs.  In self-defense, always go
+        * through two IAA cycles for each QH.
+        */
+       else if (qh->qh_state == QH_STATE_UNLINK_WAIT) {
+               qh->qh_state = QH_STATE_UNLINK;
+               early_exit = true;
+       }
+
+       /* Otherwise process only the first waiting QH (NVIDIA bug?) */
+       else
+               list_move_tail(&qh->unlink_node, &ehci->async_idle);
+
+       /* Start a new IAA cycle if any QHs are waiting for it */
+       if (!list_empty(&ehci->async_unlink))
+               start_iaa_cycle(ehci);
+
+       /*
+        * Don't allow nesting or concurrent calls,
+        * or wait for the second IAA cycle for the next QH.
+        */
+       if (early_exit)
+               return;
+
        /* Process the idle QHs */
- restart:
        ehci->async_unlinking = true;
-       while (ehci->async_iaa) {
-               qh = ehci->async_iaa;
-               ehci->async_iaa = qh->unlink_next;
-               qh->unlink_next = NULL;
+       while (!list_empty(&ehci->async_idle)) {
+               qh = list_first_entry(&ehci->async_idle, struct ehci_qh,
+                               unlink_node);
+               list_del(&qh->unlink_node);
 
                qh->qh_state = QH_STATE_IDLE;
                qh->qh_next.qh = NULL;
 
-               qh_completions(ehci, qh);
+               if (!list_empty(&qh->qtd_list))
+                       qh_completions(ehci, qh);
                if (!list_empty(&qh->qtd_list) &&
                                ehci->rh_state == EHCI_RH_RUNNING)
                        qh_link_async(ehci, qh);
                disable_async(ehci);
        }
        ehci->async_unlinking = false;
-
-       /* Start a new IAA cycle if any QHs are waiting for it */
-       if (ehci->async_unlink) {
-               start_iaa_cycle(ehci, true);
-               if (unlikely(ehci->rh_state < EHCI_RH_RUNNING))
-                       goto restart;
-       }
 }
 
 static void start_unlink_async(struct ehci_hcd *ehci, struct ehci_qh *qh);
@@ -1288,7 +1268,6 @@ static void unlink_empty_async(struct ehci_hcd *ehci)
 {
        struct ehci_qh          *qh;
        struct ehci_qh          *qh_to_unlink = NULL;
-       bool                    check_unlinks_later = false;
        int                     count = 0;
 
        /* Find the last async QH which has been empty for a timer cycle */
@@ -1296,15 +1275,13 @@ static void unlink_empty_async(struct ehci_hcd *ehci)
                if (list_empty(&qh->qtd_list) &&
                                qh->qh_state == QH_STATE_LINKED) {
                        ++count;
-                       if (qh->unlink_cycle == ehci->async_unlink_cycle)
-                               check_unlinks_later = true;
-                       else
+                       if (qh->unlink_cycle != ehci->async_unlink_cycle)
                                qh_to_unlink = qh;
                }
        }
 
        /* If nothing else is being unlinked, unlink the last empty QH */
-       if (!ehci->async_iaa && !ehci->async_unlink && qh_to_unlink) {
+       if (list_empty(&ehci->async_unlink) && qh_to_unlink) {
                start_unlink_async(ehci, qh_to_unlink);
                --count;
        }
@@ -1317,7 +1294,7 @@ static void unlink_empty_async(struct ehci_hcd *ehci)
 }
 
 /* The root hub is suspended; unlink all the async QHs */
-static void unlink_empty_async_suspended(struct ehci_hcd *ehci)
+static void __maybe_unused unlink_empty_async_suspended(struct ehci_hcd *ehci)
 {
        struct ehci_qh          *qh;
 
@@ -1326,7 +1303,7 @@ static void unlink_empty_async_suspended(struct ehci_hcd *ehci)
                WARN_ON(!list_empty(&qh->qtd_list));
                single_unlink_async(ehci, qh);
        }
-       start_iaa_cycle(ehci, false);
+       start_iaa_cycle(ehci);
 }
 
 /* makes sure the async qh will become idle */
@@ -1334,19 +1311,12 @@ static void unlink_empty_async_suspended(struct ehci_hcd *ehci)
 
 static void start_unlink_async(struct ehci_hcd *ehci, struct ehci_qh *qh)
 {
-       /*
-        * If the QH isn't linked then there's nothing we can do
-        * unless we were called during a giveback, in which case
-        * qh_completions() has to deal with it.
-        */
-       if (qh->qh_state != QH_STATE_LINKED) {
-               if (qh->qh_state == QH_STATE_COMPLETING)
-                       qh->needs_rescan = 1;
+       /* If the QH isn't linked then there's nothing we can do. */
+       if (qh->qh_state != QH_STATE_LINKED)
                return;
-       }
 
        single_unlink_async(ehci, qh);
-       start_iaa_cycle(ehci, false);
+       start_iaa_cycle(ehci);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -1360,7 +1330,7 @@ static void scan_async (struct ehci_hcd *ehci)
        while (ehci->qh_scan_next) {
                qh = ehci->qh_scan_next;
                ehci->qh_scan_next = qh->qh_next.qh;
- rescan:
+
                /* clean any finished work for this qh */
                if (!list_empty(&qh->qtd_list)) {
                        int temp;
@@ -1373,14 +1343,13 @@ static void scan_async (struct ehci_hcd *ehci)
                         * in single_unlink_async().
                         */
                        temp = qh_completions(ehci, qh);
-                       if (qh->needs_rescan) {
+                       if (unlikely(temp)) {
                                start_unlink_async(ehci, qh);
                        } else if (list_empty(&qh->qtd_list)
                                        && qh->qh_state == QH_STATE_LINKED) {
                                qh->unlink_cycle = ehci->async_unlink_cycle;
                                check_unlinks_later = true;
-                       } else if (temp != 0)
-                               goto rescan;
+                       }
                }
        }
 
index 20ebf6a8b7f4736c9cd448a9653de41b9d88c48a..738490e6d4298f9046bc4296d231b2f9bfbfd45d 100644 (file)
@@ -92,20 +92,21 @@ static void s5p_ehci_phy_disable(struct s5p_ehci_hcd *s5p_ehci)
 
 static void s5p_setup_vbus_gpio(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        int err;
        int gpio;
 
-       if (!pdev->dev.of_node)
+       if (!dev->of_node)
                return;
 
-       gpio = of_get_named_gpio(pdev->dev.of_node,
-                       "samsung,vbus-gpio", 0);
+       gpio = of_get_named_gpio(dev->of_node, "samsung,vbus-gpio", 0);
        if (!gpio_is_valid(gpio))
                return;
 
-       err = gpio_request_one(gpio, GPIOF_OUT_INIT_HIGH, "ehci_vbus_gpio");
+       err = devm_gpio_request_one(dev, gpio, GPIOF_OUT_INIT_HIGH,
+                                   "ehci_vbus_gpio");
        if (err)
-               dev_err(&pdev->dev, "can't request ehci vbus gpio %d", gpio);
+               dev_err(dev, "can't request ehci vbus gpio %d", gpio);
 }
 
 static u64 ehci_s5p_dma_mask = DMA_BIT_MASK(32);
index 010f686d8881fc9796fd3bbee1c1f5c3aa71e878..acff5b8f6e89dd89edf37d30377c2b1b86307c68 100644 (file)
@@ -539,6 +539,7 @@ static void qh_link_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)
        }
        qh->qh_state = QH_STATE_LINKED;
        qh->xacterrs = 0;
+       qh->exception = 0;
 
        /* update per-qh bandwidth for usbfs */
        ehci_to_hcd(ehci)->self.bandwidth_allocated += qh->period
@@ -602,15 +603,9 @@ static void qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)
 
 static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)
 {
-       /* If the QH isn't linked then there's nothing we can do
-        * unless we were called during a giveback, in which case
-        * qh_completions() has to deal with it.
-        */
-       if (qh->qh_state != QH_STATE_LINKED) {
-               if (qh->qh_state == QH_STATE_COMPLETING)
-                       qh->needs_rescan = 1;
+       /* If the QH isn't linked then there's nothing we can do. */
+       if (qh->qh_state != QH_STATE_LINKED)
                return;
-       }
 
        qh_unlink_periodic (ehci, qh);
 
@@ -625,17 +620,13 @@ static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)
        qh->unlink_cycle = ehci->intr_unlink_cycle;
 
        /* New entries go at the end of the intr_unlink list */
-       if (ehci->intr_unlink)
-               ehci->intr_unlink_last->unlink_next = qh;
-       else
-               ehci->intr_unlink = qh;
-       ehci->intr_unlink_last = qh;
+       list_add_tail(&qh->unlink_node, &ehci->intr_unlink);
 
        if (ehci->intr_unlinking)
                ;       /* Avoid recursive calls */
        else if (ehci->rh_state < EHCI_RH_RUNNING)
                ehci_handle_intr_unlinks(ehci);
-       else if (ehci->intr_unlink == qh) {
+       else if (ehci->intr_unlink.next == &qh->unlink_node) {
                ehci_enable_event(ehci, EHCI_HRTIMER_UNLINK_INTR, true);
                ++ehci->intr_unlink_cycle;
        }
@@ -649,7 +640,8 @@ static void end_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)
        qh->qh_state = QH_STATE_IDLE;
        hw->hw_next = EHCI_LIST_END(ehci);
 
-       qh_completions(ehci, qh);
+       if (!list_empty(&qh->qtd_list))
+               qh_completions(ehci, qh);
 
        /* reschedule QH iff another request is queued */
        if (!list_empty(&qh->qtd_list) && ehci->rh_state == EHCI_RH_RUNNING) {
@@ -792,7 +784,6 @@ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh)
        unsigned        frame;          /* 0..(qh->period - 1), or NO_FRAME */
        struct ehci_qh_hw       *hw = qh->hw;
 
-       qh_refresh(ehci, qh);
        hw->hw_next = EHCI_LIST_END(ehci);
        frame = qh->start;
 
@@ -844,8 +835,6 @@ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh)
        } else
                ehci_dbg (ehci, "reused qh %p schedule\n", qh);
 
-       /* stuff into the periodic schedule */
-       qh_link_periodic(ehci, qh);
 done:
        return status;
 }
@@ -891,6 +880,12 @@ static int intr_submit (
        qh = qh_append_tds(ehci, urb, qtd_list, epnum, &urb->ep->hcpriv);
        BUG_ON (qh == NULL);
 
+       /* stuff into the periodic schedule */
+       if (qh->qh_state == QH_STATE_IDLE) {
+               qh_refresh(ehci, qh);
+               qh_link_periodic(ehci, qh);
+       }
+
        /* ... update usbfs periodic stats */
        ehci_to_hcd(ehci)->self.bandwidth_int_reqs++;
 
@@ -911,7 +906,7 @@ static void scan_intr(struct ehci_hcd *ehci)
 
        list_for_each_entry_safe(qh, ehci->qh_scan_next, &ehci->intr_qh_list,
                        intr_node) {
- rescan:
+
                /* clean any finished work for this qh */
                if (!list_empty(&qh->qtd_list)) {
                        int temp;
@@ -924,12 +919,9 @@ static void scan_intr(struct ehci_hcd *ehci)
                         * in qh_unlink_periodic().
                         */
                        temp = qh_completions(ehci, qh);
-                       if (unlikely(qh->needs_rescan ||
-                                       (list_empty(&qh->qtd_list) &&
-                                               qh->qh_state == QH_STATE_LINKED)))
+                       if (unlikely(temp || (list_empty(&qh->qtd_list) &&
+                                       qh->qh_state == QH_STATE_LINKED)))
                                start_unlink_intr(ehci, qh);
-                       else if (temp != 0)
-                               goto rescan;
                }
        }
 }
index 3565a300f401347315b968b0c09131df294e317f..b44d716ddc825e1b5905e0f4cbf481f3e176e83a 100644 (file)
@@ -77,7 +77,6 @@ static const struct hc_driver ehci_sh_hc_driver = {
 
 static int ehci_hcd_sh_probe(struct platform_device *pdev)
 {
-       const struct hc_driver *driver = &ehci_sh_hc_driver;
        struct resource *res;
        struct ehci_sh_priv *priv;
        struct ehci_sh_platdata *pdata;
@@ -170,7 +169,7 @@ fail_create_hcd:
        return ret;
 }
 
-static int __exit ehci_hcd_sh_remove(struct platform_device *pdev)
+static int ehci_hcd_sh_remove(struct platform_device *pdev)
 {
        struct ehci_sh_priv *priv = platform_get_drvdata(pdev);
        struct usb_hcd *hcd = priv->hcd;
@@ -196,7 +195,7 @@ static void ehci_hcd_sh_shutdown(struct platform_device *pdev)
 
 static struct platform_driver ehci_hcd_sh_driver = {
        .probe          = ehci_hcd_sh_probe,
-       .remove         = __exit_p(ehci_hcd_sh_remove),
+       .remove         = ehci_hcd_sh_remove,
        .shutdown       = ehci_hcd_sh_shutdown,
        .driver         = {
                .name   = "sh_ehci",
index 466c1bb5b96728c6514ef45e7348a747868398f9..210bb676f22f4f953e3407419dc07d2c3bc91c11 100644 (file)
@@ -78,7 +78,7 @@ static const struct hc_driver ehci_spear_hc_driver = {
        .clear_tt_buffer_complete       = ehci_clear_tt_buffer_complete,
 };
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int ehci_spear_drv_suspend(struct device *dev)
 {
        struct usb_hcd *hcd = dev_get_drvdata(dev);
@@ -94,7 +94,7 @@ static int ehci_spear_drv_resume(struct device *dev)
        ehci_resume(hcd, false);
        return 0;
 }
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static SIMPLE_DEV_PM_OPS(ehci_spear_pm_ops, ehci_spear_drv_suspend,
                ehci_spear_drv_resume);
index c3fa1305f830bf53070a6553446428368553691d..11e5b32f73e943824ca262f3bb61462dacb82b15 100644 (file)
@@ -113,8 +113,8 @@ static void ehci_poll_ASS(struct ehci_hcd *ehci)
 
        if (want != actual) {
 
-               /* Poll again later, but give up after about 20 ms */
-               if (ehci->ASS_poll_count++ < 20) {
+               /* Poll again later, but give up after about 2-4 ms */
+               if (ehci->ASS_poll_count++ < 2) {
                        ehci_enable_event(ehci, EHCI_HRTIMER_POLL_ASS, true);
                        return;
                }
@@ -159,8 +159,8 @@ static void ehci_poll_PSS(struct ehci_hcd *ehci)
 
        if (want != actual) {
 
-               /* Poll again later, but give up after about 20 ms */
-               if (ehci->PSS_poll_count++ < 20) {
+               /* Poll again later, but give up after about 2-4 ms */
+               if (ehci->PSS_poll_count++ < 2) {
                        ehci_enable_event(ehci, EHCI_HRTIMER_POLL_PSS, true);
                        return;
                }
@@ -229,18 +229,19 @@ static void ehci_handle_intr_unlinks(struct ehci_hcd *ehci)
         * process all the QHs on the list.
         */
        ehci->intr_unlinking = true;
-       while (ehci->intr_unlink) {
-               struct ehci_qh  *qh = ehci->intr_unlink;
+       while (!list_empty(&ehci->intr_unlink)) {
+               struct ehci_qh  *qh;
 
+               qh = list_first_entry(&ehci->intr_unlink, struct ehci_qh,
+                               unlink_node);
                if (!stopped && qh->unlink_cycle == ehci->intr_unlink_cycle)
                        break;
-               ehci->intr_unlink = qh->unlink_next;
-               qh->unlink_next = NULL;
+               list_del(&qh->unlink_node);
                end_unlink_intr(ehci, qh);
        }
 
        /* Handle remaining entries later */
-       if (ehci->intr_unlink) {
+       if (!list_empty(&ehci->intr_unlink)) {
                ehci_enable_event(ehci, EHCI_HRTIMER_UNLINK_INTR, true);
                ++ehci->intr_unlink_cycle;
        }
@@ -295,8 +296,7 @@ static void end_free_itds(struct ehci_hcd *ehci)
 /* Handle lost (or very late) IAA interrupts */
 static void ehci_iaa_watchdog(struct ehci_hcd *ehci)
 {
-       if (ehci->rh_state != EHCI_RH_RUNNING)
-               return;
+       u32 cmd, status;
 
        /*
         * Lost IAA irqs wedge things badly; seen first with a vt8235.
@@ -304,34 +304,32 @@ static void ehci_iaa_watchdog(struct ehci_hcd *ehci)
         * (a) SMP races against real IAA firing and retriggering, and
         * (b) clean HC shutdown, when IAA watchdog was pending.
         */
-       if (1) {
-               u32 cmd, status;
-
-               /* If we get here, IAA is *REALLY* late.  It's barely
-                * conceivable that the system is so busy that CMD_IAAD
-                * is still legitimately set, so let's be sure it's
-                * clear before we read STS_IAA.  (The HC should clear
-                * CMD_IAAD when it sets STS_IAA.)
-                */
-               cmd = ehci_readl(ehci, &ehci->regs->command);
-
-               /*
-                * If IAA is set here it either legitimately triggered
-                * after the watchdog timer expired (_way_ late, so we'll
-                * still count it as lost) ... or a silicon erratum:
-                * - VIA seems to set IAA without triggering the IRQ;
-                * - IAAD potentially cleared without setting IAA.
-                */
-               status = ehci_readl(ehci, &ehci->regs->status);
-               if ((status & STS_IAA) || !(cmd & CMD_IAAD)) {
-                       COUNT(ehci->stats.lost_iaa);
-                       ehci_writel(ehci, STS_IAA, &ehci->regs->status);
-               }
+       if (!ehci->iaa_in_progress || ehci->rh_state != EHCI_RH_RUNNING)
+               return;
+
+       /* If we get here, IAA is *REALLY* late.  It's barely
+        * conceivable that the system is so busy that CMD_IAAD
+        * is still legitimately set, so let's be sure it's
+        * clear before we read STS_IAA.  (The HC should clear
+        * CMD_IAAD when it sets STS_IAA.)
+        */
+       cmd = ehci_readl(ehci, &ehci->regs->command);
 
-               ehci_vdbg(ehci, "IAA watchdog: status %x cmd %x\n",
-                               status, cmd);
-               end_unlink_async(ehci);
+       /*
+        * If IAA is set here it either legitimately triggered
+        * after the watchdog timer expired (_way_ late, so we'll
+        * still count it as lost) ... or a silicon erratum:
+        * - VIA seems to set IAA without triggering the IRQ;
+        * - IAAD potentially cleared without setting IAA.
+        */
+       status = ehci_readl(ehci, &ehci->regs->status);
+       if ((status & STS_IAA) || !(cmd & CMD_IAAD)) {
+               COUNT(ehci->stats.lost_iaa);
+               ehci_writel(ehci, STS_IAA, &ehci->regs->status);
        }
+
+       ehci_dbg(ehci, "IAA watchdog: status %x cmd %x\n", status, cmd);
+       end_unlink_async(ehci);
 }
 
 
diff --git a/drivers/usb/host/ehci-vt8500.c b/drivers/usb/host/ehci-vt8500.c
deleted file mode 100644 (file)
index 7ecf709..0000000
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * drivers/usb/host/ehci-vt8500.c
- *
- * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
- *
- * Based on ehci-au1xxx.c
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/err.h>
-#include <linux/of.h>
-#include <linux/platform_device.h>
-
-static const struct hc_driver vt8500_ehci_hc_driver = {
-       .description            = hcd_name,
-       .product_desc           = "VT8500 EHCI",
-       .hcd_priv_size          = sizeof(struct ehci_hcd),
-
-       /*
-        * generic hardware linkage
-        */
-       .irq                    = ehci_irq,
-       .flags                  = HCD_MEMORY | HCD_USB2,
-
-       /*
-        * basic lifecycle operations
-        */
-       .reset                  = ehci_setup,
-       .start                  = ehci_run,
-       .stop                   = ehci_stop,
-       .shutdown               = ehci_shutdown,
-
-       /*
-        * managing i/o requests and associated device resources
-        */
-       .urb_enqueue            = ehci_urb_enqueue,
-       .urb_dequeue            = ehci_urb_dequeue,
-       .endpoint_disable       = ehci_endpoint_disable,
-       .endpoint_reset         = ehci_endpoint_reset,
-
-       /*
-        * scheduling support
-        */
-       .get_frame_number       = ehci_get_frame,
-
-       /*
-        * root hub support
-        */
-       .hub_status_data        = ehci_hub_status_data,
-       .hub_control            = ehci_hub_control,
-       .bus_suspend            = ehci_bus_suspend,
-       .bus_resume             = ehci_bus_resume,
-       .relinquish_port        = ehci_relinquish_port,
-       .port_handed_over       = ehci_port_handed_over,
-
-       .clear_tt_buffer_complete       = ehci_clear_tt_buffer_complete,
-};
-
-static u64 vt8500_ehci_dma_mask = DMA_BIT_MASK(32);
-
-static int vt8500_ehci_drv_probe(struct platform_device *pdev)
-{
-       struct usb_hcd *hcd;
-       struct ehci_hcd *ehci;
-       struct resource *res;
-       int ret;
-
-       if (usb_disabled())
-               return -ENODEV;
-
-       /*
-        * Right now device-tree probed devices don't get dma_mask set.
-        * Since shared usb code relies on it, set it here for now.
-        * Once we have dma capability bindings this can go away.
-        */
-       if (!pdev->dev.dma_mask)
-               pdev->dev.dma_mask = &vt8500_ehci_dma_mask;
-
-       if (pdev->resource[1].flags != IORESOURCE_IRQ) {
-               pr_debug("resource[1] is not IORESOURCE_IRQ");
-               return -ENOMEM;
-       }
-       hcd = usb_create_hcd(&vt8500_ehci_hc_driver, &pdev->dev, "VT8500");
-       if (!hcd)
-               return -ENOMEM;
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       hcd->rsrc_start = res->start;
-       hcd->rsrc_len = resource_size(res);
-
-       hcd->regs = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(hcd->regs)) {
-               ret = PTR_ERR(hcd->regs);
-               goto err1;
-       }
-
-       ehci = hcd_to_ehci(hcd);
-       ehci->caps = hcd->regs;
-
-       ret = usb_add_hcd(hcd, pdev->resource[1].start,
-                         IRQF_SHARED);
-       if (ret == 0) {
-               platform_set_drvdata(pdev, hcd);
-               return ret;
-       }
-
-err1:
-       usb_put_hcd(hcd);
-       return ret;
-}
-
-static int vt8500_ehci_drv_remove(struct platform_device *pdev)
-{
-       struct usb_hcd *hcd = platform_get_drvdata(pdev);
-
-       usb_remove_hcd(hcd);
-       usb_put_hcd(hcd);
-       platform_set_drvdata(pdev, NULL);
-
-       return 0;
-}
-
-static const struct of_device_id vt8500_ehci_ids[] = {
-       { .compatible = "via,vt8500-ehci", },
-       { .compatible = "wm,prizm-ehci", },
-       {}
-};
-
-static struct platform_driver vt8500_ehci_driver = {
-       .probe          = vt8500_ehci_drv_probe,
-       .remove         = vt8500_ehci_drv_remove,
-       .shutdown       = usb_hcd_platform_shutdown,
-       .driver = {
-               .name   = "vt8500-ehci",
-               .owner  = THIS_MODULE,
-               .of_match_table = of_match_ptr(vt8500_ehci_ids),
-       }
-};
-
-MODULE_ALIAS("platform:vt8500-ehci");
-MODULE_DEVICE_TABLE(of, vt8500_ehci_ids);
index 36c3a82105953ba2433d12845e7e02a293fa6d35..e66699950997b7c11d5b2cbde4c379a46dff1c63 100644 (file)
@@ -121,6 +121,7 @@ struct ehci_hcd {                   /* one per controller */
        bool                    scanning:1;
        bool                    need_rescan:1;
        bool                    intr_unlinking:1;
+       bool                    iaa_in_progress:1;
        bool                    async_unlinking:1;
        bool                    shutdown:1;
        struct ehci_qh          *qh_scan_next;
@@ -128,9 +129,8 @@ struct ehci_hcd {                   /* one per controller */
        /* async schedule support */
        struct ehci_qh          *async;
        struct ehci_qh          *dummy;         /* For AMD quirk use */
-       struct ehci_qh          *async_unlink;
-       struct ehci_qh          *async_unlink_last;
-       struct ehci_qh          *async_iaa;
+       struct list_head        async_unlink;
+       struct list_head        async_idle;
        unsigned                async_unlink_cycle;
        unsigned                async_count;    /* async activity count */
 
@@ -143,8 +143,7 @@ struct ehci_hcd {                   /* one per controller */
        unsigned                i_thresh;       /* uframes HC might cache */
 
        union ehci_shadow       *pshadow;       /* mirror hw periodic table */
-       struct ehci_qh          *intr_unlink;
-       struct ehci_qh          *intr_unlink_last;
+       struct list_head        intr_unlink;
        unsigned                intr_unlink_cycle;
        unsigned                now_frame;      /* frame from HC hardware */
        unsigned                last_iso_frame; /* last frame scanned for iso */
@@ -380,11 +379,10 @@ struct ehci_qh {
        struct list_head        qtd_list;       /* sw qtd list */
        struct list_head        intr_node;      /* list of intr QHs */
        struct ehci_qtd         *dummy;
-       struct ehci_qh          *unlink_next;   /* next on unlink list */
+       struct list_head        unlink_node;
 
        unsigned                unlink_cycle;
 
-       u8                      needs_rescan;   /* Dequeue during giveback */
        u8                      qh_state;
 #define        QH_STATE_LINKED         1               /* HC sees this */
 #define        QH_STATE_UNLINK         2               /* HC may still see this */
@@ -407,6 +405,9 @@ struct ehci_qh {
        struct usb_device       *dev;           /* access to TT */
        unsigned                is_out:1;       /* bulk or intr OUT */
        unsigned                clearing_tt:1;  /* Clear-TT-Buf in progress */
+       unsigned                dequeue_during_giveback:1;
+       unsigned                exception:1;    /* got a fault, or an unlink
+                                                  was requested */
 };
 
 /*-------------------------------------------------------------------------*/
index db09dae7b557a18063d424a3ffc58c1edb8ccca8..60ff4220e8b4fbe771857f5b1316e02663eccf68 100644 (file)
@@ -580,14 +580,8 @@ static int ohci_start_port_reset (struct usb_hcd *hcd, unsigned port)
 
 /* See usb 7.1.7.5:  root hubs must issue at least 50 msec reset signaling,
  * not necessarily continuous ... to guard against resume signaling.
- * The short timeout is safe for non-root hubs, and is backward-compatible
- * with earlier Linux hosts.
  */
-#ifdef CONFIG_USB_SUSPEND
 #define        PORT_RESET_MSEC         50
-#else
-#define        PORT_RESET_MSEC         10
-#endif
 
 /* this timer value might be vendor-specific ... */
 #define        PORT_RESET_HW_MSEC      10
index eb35d96302373c7e9e2fa3345f7d81008aa802f9..ddfc31427bc09e1fc95c63ea40f006ad00631e66 100644 (file)
@@ -31,6 +31,8 @@
 
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/dma-mapping.h>
 
 /*-------------------------------------------------------------------------*/
 
@@ -112,6 +114,8 @@ static const struct hc_driver ohci_omap3_hc_driver = {
 
 /*-------------------------------------------------------------------------*/
 
+static u64 omap_ohci_dma_mask = DMA_BIT_MASK(32);
+
 /*
  * configure so an HC device and id are always provided
  * always called with process context; sleeping is OK
@@ -141,14 +145,13 @@ static int ohci_hcd_omap3_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       irq = platform_get_irq_byname(pdev, "ohci-irq");
+       irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
                dev_err(dev, "OHCI irq failed\n");
                return -ENODEV;
        }
 
-       res = platform_get_resource_byname(pdev,
-                               IORESOURCE_MEM, "ohci");
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res) {
                dev_err(dev, "UHH OHCI get resource failed\n");
                return -ENOMEM;
@@ -160,6 +163,13 @@ static int ohci_hcd_omap3_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
+       /*
+        * Right now device-tree probed devices don't get dma_mask set.
+        * Since shared usb code relies on it, set it here for now.
+        * Once we have dma capability bindings this can go away.
+        */
+       if (!pdev->dev.dma_mask)
+               pdev->dev.dma_mask = &omap_ohci_dma_mask;
 
        hcd = usb_create_hcd(&ohci_omap3_hc_driver, dev,
                        dev_name(dev));
@@ -229,12 +239,20 @@ static void ohci_hcd_omap3_shutdown(struct platform_device *pdev)
                hcd->driver->shutdown(hcd);
 }
 
+static const struct of_device_id omap_ohci_dt_ids[] = {
+       { .compatible = "ti,ohci-omap3" },
+       { }
+};
+
+MODULE_DEVICE_TABLE(of, omap_ohci_dt_ids);
+
 static struct platform_driver ohci_hcd_omap3_driver = {
        .probe          = ohci_hcd_omap3_probe,
        .remove         = ohci_hcd_omap3_remove,
        .shutdown       = ohci_hcd_omap3_shutdown,
        .driver         = {
                .name   = "ohci-omap3",
+               .of_match_table = of_match_ptr(omap_ohci_dt_ids),
        },
 };
 
index d62f0404baaa636d82e3b409edf4581c7e92ab03..15ed7e8d887f6897781715ca42a0b12018e0e99a 100644 (file)
@@ -1755,7 +1755,7 @@ sl811h_probe(struct platform_device *dev)
 
 /* for this device there's no useful distinction between the controller
  * and its root hub, except that the root hub only gets direct PM calls
- * when CONFIG_USB_SUSPEND is enabled.
+ * when CONFIG_PM_RUNTIME is enabled.
  */
 
 static int
index 5efdffe3236572e4f7b3141a6a8ab5f4fb95d721..5c124bf5d01869c727543b34240deace3d27d1cd 100644 (file)
@@ -3141,10 +3141,11 @@ static int u132_probe(struct platform_device *pdev)
 
 
 #ifdef CONFIG_PM
-/* for this device there's no useful distinction between the controller
-* and its root hub, except that the root hub only gets direct PM calls
-* when CONFIG_USB_SUSPEND is enabled.
-*/
+/*
+ * for this device there's no useful distinction between the controller
+ * and its root hub, except that the root hub only gets direct PM calls
+ * when CONFIG_PM_RUNTIME is enabled.
+ */
 static int u132_suspend(struct platform_device *pdev, pm_message_t state)
 {
        struct usb_hcd *hcd = platform_get_drvdata(pdev);
index 68914429482f30ff4afed47180aae563d07c5784..187a3ec1069ace87d28b888823e4c4e38053f80b 100644 (file)
@@ -1075,7 +1075,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
                        set_bit(port_index, &bus_state->bus_suspended);
                }
                /* USB core sets remote wake mask for USB 3.0 hubs,
-                * including the USB 3.0 roothub, but only if CONFIG_USB_SUSPEND
+                * including the USB 3.0 roothub, but only if CONFIG_PM_RUNTIME
                 * is enabled, so also enable remote wake here.
                 */
                if (hcd->self.root_hub->do_remote_wakeup) {
index 53b8f89a0b1c7e6199c95672c85d3d27fb3e0b90..5156b720a53a5f5d63a66b0ce7b287eff3deaada 100644 (file)
@@ -3801,7 +3801,7 @@ int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1)
        return raw_port;
 }
 
-#ifdef CONFIG_USB_SUSPEND
+#ifdef CONFIG_PM_RUNTIME
 
 /* BESL to HIRD Encoding array for USB2 LPM */
 static int xhci_besl_encoding[16] = {125, 150, 200, 300, 400, 500, 1000, 2000,
@@ -4051,7 +4051,7 @@ int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev)
        return 0;
 }
 
-#endif /* CONFIG_USB_SUSPEND */
+#endif /* CONFIG_PM_RUNTIME */
 
 /*---------------------- USB 3.0 Link PM functions ------------------------*/
 
index dd573abd2d1edf9b32b0a97aa9def3d1abd9d967..c21386ec5d35d142b7d0d84abe2e3f3cb5be7125 100644 (file)
@@ -3084,7 +3084,7 @@ static int sisusb_probe(struct usb_interface *intf,
 
        /* Allocate memory for our private */
        if (!(sisusb = kzalloc(sizeof(*sisusb), GFP_KERNEL))) {
-               dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for private data\n");
+               dev_err(&dev->dev, "Failed to allocate memory for private data\n");
                return -ENOMEM;
        }
        kref_init(&sisusb->kref);
index f713f6aeb6e5508dc79302d067474e59c3eadade..d3a1cce1bf9c511710993002d83391f8f6a6fb35 100644 (file)
@@ -307,18 +307,7 @@ static struct i2c_driver usb3503_driver = {
        .id_table       = usb3503_id,
 };
 
-static int __init usb3503_init(void)
-{
-       return i2c_add_driver(&usb3503_driver);
-}
-
-static void __exit usb3503_exit(void)
-{
-       i2c_del_driver(&usb3503_driver);
-}
-
-module_init(usb3503_init);
-module_exit(usb3503_exit);
+module_i2c_driver(usb3503_driver);
 
 MODULE_AUTHOR("Dongjin Kim <tobetter@gmail.com>");
 MODULE_DESCRIPTION("USB3503 USB HUB driver");
index af9cb11626b229a417b49189ff932c40f3587c13..8b9de95813197cc8edd254b7c260ed10a73c72df 100644 (file)
@@ -1212,7 +1212,7 @@ static void isp1301_release(struct device *dev)
 
 static struct isp1301 *the_transceiver;
 
-static int __exit isp1301_remove(struct i2c_client *i2c)
+static int isp1301_remove(struct i2c_client *i2c)
 {
        struct isp1301  *isp;
 
@@ -1634,7 +1634,7 @@ static struct i2c_driver isp1301_driver = {
                .name   = "isp1301_omap",
        },
        .probe          = isp1301_probe,
-       .remove         = __exit_p(isp1301_remove),
+       .remove         = isp1301_remove,
        .id_table       = isp1301_id,
 };
 
index a994715a3101978a916bea3f4d3d1e1c38d72f7d..24d573a134b1ceccbd5af25fdff74595bd8fe09c 100644 (file)
@@ -658,7 +658,7 @@ static int twl4030_usb_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __exit twl4030_usb_remove(struct platform_device *pdev)
+static int twl4030_usb_remove(struct platform_device *pdev)
 {
        struct twl4030_usb *twl = platform_get_drvdata(pdev);
        int val;
@@ -702,7 +702,7 @@ MODULE_DEVICE_TABLE(of, twl4030_usb_id_table);
 
 static struct platform_driver twl4030_usb_driver = {
        .probe          = twl4030_usb_probe,
-       .remove         = __exit_p(twl4030_usb_remove),
+       .remove         = twl4030_usb_remove,
        .driver         = {
                .name   = "twl4030_usb",
                .owner  = THIS_MODULE,
index 8cd6cf49bdbd12c987f871193e58be3f3df77853..7f3c5b0e3f66a3a24014bf56e0b8774735fc753b 100644 (file)
@@ -393,7 +393,7 @@ static int twl6030_usb_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __exit twl6030_usb_remove(struct platform_device *pdev)
+static int twl6030_usb_remove(struct platform_device *pdev)
 {
        struct twl6030_usb *twl = platform_get_drvdata(pdev);
 
@@ -420,7 +420,7 @@ MODULE_DEVICE_TABLE(of, twl6030_usb_id_table);
 
 static struct platform_driver twl6030_usb_driver = {
        .probe          = twl6030_usb_probe,
-       .remove         = __exit_p(twl6030_usb_remove),
+       .remove         = twl6030_usb_remove,
        .driver         = {
                .name   = "twl6030_usb",
                .owner  = THIS_MODULE,
index 9d8599122aa9abb424d469747fb50c28d9893dbd..bafd67f1f13491dee8c12cc2be2b8da48377d169 100644 (file)
@@ -313,7 +313,7 @@ err:
        return ret;
 }
 
-static int __exit mv_u3d_phy_remove(struct platform_device *pdev)
+static int mv_u3d_phy_remove(struct platform_device *pdev)
 {
        struct mv_u3d_phy *mv_u3d_phy = platform_get_drvdata(pdev);
 
index 4775f8209e5502b7f893d0a00a8f51622746a138..3b16118cbf62d7d8be032f6a243a39fd5965a5be 100644 (file)
@@ -62,7 +62,6 @@ static int is_irda(struct usb_serial *serial)
 }
 
 struct ark3116_private {
-       struct async_icount     icount;
        int                     irda;   /* 1 for irda device */
 
        /* protects hw register updates */
@@ -341,18 +340,15 @@ static void ark3116_close(struct usb_serial_port *port)
 {
        struct usb_serial *serial = port->serial;
 
-       if (serial->dev) {
-               /* disable DMA */
-               ark3116_write_reg(serial, UART_FCR, 0);
-
-               /* deactivate interrupts */
-               ark3116_write_reg(serial, UART_IER, 0);
+       /* disable DMA */
+       ark3116_write_reg(serial, UART_FCR, 0);
 
-               usb_serial_generic_close(port);
-               if (serial->num_interrupt_in)
-                       usb_kill_urb(port->interrupt_in_urb);
-       }
+       /* deactivate interrupts */
+       ark3116_write_reg(serial, UART_IER, 0);
 
+       usb_serial_generic_close(port);
+       if (serial->num_interrupt_in)
+               usb_kill_urb(port->interrupt_in_urb);
 }
 
 static int ark3116_open(struct tty_struct *tty, struct usb_serial_port *port)
@@ -405,31 +401,10 @@ err_out:
        return result;
 }
 
-static int ark3116_get_icount(struct tty_struct *tty,
-                                       struct serial_icounter_struct *icount)
-{
-       struct usb_serial_port *port = tty->driver_data;
-       struct ark3116_private *priv = usb_get_serial_port_data(port);
-       struct async_icount cnow = priv->icount;
-       icount->cts = cnow.cts;
-       icount->dsr = cnow.dsr;
-       icount->rng = cnow.rng;
-       icount->dcd = cnow.dcd;
-       icount->rx = cnow.rx;
-       icount->tx = cnow.tx;
-       icount->frame = cnow.frame;
-       icount->overrun = cnow.overrun;
-       icount->parity = cnow.parity;
-       icount->brk = cnow.brk;
-       icount->buf_overrun = cnow.buf_overrun;
-       return 0;
-}
-
 static int ark3116_ioctl(struct tty_struct *tty,
                         unsigned int cmd, unsigned long arg)
 {
        struct usb_serial_port *port = tty->driver_data;
-       struct ark3116_private *priv = usb_get_serial_port_data(port);
        struct serial_struct serstruct;
        void __user *user_arg = (void __user *)arg;
 
@@ -451,33 +426,6 @@ static int ark3116_ioctl(struct tty_struct *tty,
                if (copy_from_user(&serstruct, user_arg, sizeof(serstruct)))
                        return -EFAULT;
                return 0;
-       case TIOCMIWAIT:
-               for (;;) {
-                       struct async_icount prev = priv->icount;
-                       interruptible_sleep_on(&port->delta_msr_wait);
-                       /* see if a signal did it */
-                       if (signal_pending(current))
-                               return -ERESTARTSYS;
-
-                       if (port->serial->disconnected)
-                               return -EIO;
-
-                       if ((prev.rng == priv->icount.rng) &&
-                           (prev.dsr == priv->icount.dsr) &&
-                           (prev.dcd == priv->icount.dcd) &&
-                           (prev.cts == priv->icount.cts))
-                               return -EIO;
-                       if ((arg & TIOCM_RNG &&
-                            (prev.rng != priv->icount.rng)) ||
-                           (arg & TIOCM_DSR &&
-                            (prev.dsr != priv->icount.dsr)) ||
-                           (arg & TIOCM_CD  &&
-                            (prev.dcd != priv->icount.dcd)) ||
-                           (arg & TIOCM_CTS &&
-                            (prev.cts != priv->icount.cts)))
-                               return 0;
-               }
-               break;
        }
 
        return -ENOIOCTLCMD;
@@ -575,14 +523,14 @@ static void ark3116_update_msr(struct usb_serial_port *port, __u8 msr)
        if (msr & UART_MSR_ANY_DELTA) {
                /* update input line counters */
                if (msr & UART_MSR_DCTS)
-                       priv->icount.cts++;
+                       port->icount.cts++;
                if (msr & UART_MSR_DDSR)
-                       priv->icount.dsr++;
+                       port->icount.dsr++;
                if (msr & UART_MSR_DDCD)
-                       priv->icount.dcd++;
+                       port->icount.dcd++;
                if (msr & UART_MSR_TERI)
-                       priv->icount.rng++;
-               wake_up_interruptible(&port->delta_msr_wait);
+                       port->icount.rng++;
+               wake_up_interruptible(&port->port.delta_msr_wait);
        }
 }
 
@@ -598,13 +546,13 @@ static void ark3116_update_lsr(struct usb_serial_port *port, __u8 lsr)
 
        if (lsr&UART_LSR_BRK_ERROR_BITS) {
                if (lsr & UART_LSR_BI)
-                       priv->icount.brk++;
+                       port->icount.brk++;
                if (lsr & UART_LSR_FE)
-                       priv->icount.frame++;
+                       port->icount.frame++;
                if (lsr & UART_LSR_PE)
-                       priv->icount.parity++;
+                       port->icount.parity++;
                if (lsr & UART_LSR_OE)
-                       priv->icount.overrun++;
+                       port->icount.overrun++;
        }
 }
 
@@ -722,7 +670,8 @@ static struct usb_serial_driver ark3116_device = {
        .ioctl =                ark3116_ioctl,
        .tiocmget =             ark3116_tiocmget,
        .tiocmset =             ark3116_tiocmset,
-       .get_icount =           ark3116_get_icount,
+       .tiocmiwait =           usb_serial_generic_tiocmiwait,
+       .get_icount =           usb_serial_generic_get_icount,
        .open =                 ark3116_open,
        .close =                ark3116_close,
        .break_ctl =            ark3116_break_ctl,
index 37decb13d7eb82a2f4486f3d17ca56fec73dc6f3..3c4db6d196c630257611883e9f8f7ec46f5c20b6 100644 (file)
@@ -106,14 +106,15 @@ static int usb_serial_device_remove(struct device *dev)
        /* make sure suspend/resume doesn't race against port_remove */
        usb_autopm_get_interface(port->serial->interface);
 
+       minor = port->number;
+       tty_unregister_device(usb_serial_tty_driver, minor);
+
        device_remove_file(&port->dev, &dev_attr_port_number);
 
        driver = port->serial->type;
        if (driver->port_remove)
                retval = driver->port_remove(port);
 
-       minor = port->number;
-       tty_unregister_device(usb_serial_tty_driver, minor);
        dev_info(dev, "%s converter now disconnected from ttyUSB%d\n",
                 driver->description, minor);
 
index 07d4650a32abe2d89149ef8fc2a22bc17bebe8b2..c2a4171ab9cb7f962ca32b07a85e8d2f37630d10 100644 (file)
@@ -296,7 +296,6 @@ static void ch341_dtr_rts(struct usb_serial_port *port, int on)
                priv->line_control &= ~(CH341_BIT_RTS | CH341_BIT_DTR);
        spin_unlock_irqrestore(&priv->lock, flags);
        ch341_set_handshake(port->serial->dev, priv->line_control);
-       wake_up_interruptible(&port->delta_msr_wait);
 }
 
 static void ch341_close(struct usb_serial_port *port)
@@ -489,7 +488,7 @@ static void ch341_read_int_callback(struct urb *urb)
                        tty_kref_put(tty);
                }
 
-               wake_up_interruptible(&port->delta_msr_wait);
+               wake_up_interruptible(&port->port.delta_msr_wait);
        }
 
 exit:
@@ -500,8 +499,9 @@ exit:
                        __func__, status);
 }
 
-static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
+static int ch341_tiocmiwait(struct tty_struct *tty, unsigned long arg)
 {
+       struct usb_serial_port *port = tty->driver_data;
        struct ch341_private *priv = usb_get_serial_port_data(port);
        unsigned long flags;
        u8 prevstatus;
@@ -515,7 +515,7 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
        spin_unlock_irqrestore(&priv->lock, flags);
 
        while (!multi_change) {
-               interruptible_sleep_on(&port->delta_msr_wait);
+               interruptible_sleep_on(&port->port.delta_msr_wait);
                /* see if a signal did it */
                if (signal_pending(current))
                        return -ERESTARTSYS;
@@ -542,26 +542,6 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
        return 0;
 }
 
-static int ch341_ioctl(struct tty_struct *tty,
-                       unsigned int cmd, unsigned long arg)
-{
-       struct usb_serial_port *port = tty->driver_data;
-
-       dev_dbg(&port->dev, "%s (%d) cmd = 0x%04x\n", __func__, port->number, cmd);
-
-       switch (cmd) {
-       case TIOCMIWAIT:
-               dev_dbg(&port->dev, "%s (%d) TIOCMIWAIT\n", __func__,  port->number);
-               return wait_modem_info(port, arg);
-
-       default:
-               dev_dbg(&port->dev, "%s not supported = 0x%04x\n", __func__, cmd);
-               break;
-       }
-
-       return -ENOIOCTLCMD;
-}
-
 static int ch341_tiocmget(struct tty_struct *tty)
 {
        struct usb_serial_port *port = tty->driver_data;
@@ -611,11 +591,11 @@ static struct usb_serial_driver ch341_device = {
        .dtr_rts           = ch341_dtr_rts,
        .carrier_raised    = ch341_carrier_raised,
        .close             = ch341_close,
-       .ioctl             = ch341_ioctl,
        .set_termios       = ch341_set_termios,
        .break_ctl         = ch341_break_ctl,
        .tiocmget          = ch341_tiocmget,
        .tiocmset          = ch341_tiocmset,
+       .tiocmiwait        = ch341_tiocmiwait,
        .read_int_callback = ch341_read_int_callback,
        .port_probe        = ch341_port_probe,
        .port_remove       = ch341_port_remove,
index 4747d1c328ffbdc13e1ca4337dc11a6c557711f5..2c659553c07c01df5dc1a65be8341809939fc6f4 100644 (file)
@@ -462,11 +462,7 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port)
 static void cp210x_close(struct usb_serial_port *port)
 {
        usb_serial_generic_close(port);
-
-       mutex_lock(&port->serial->disc_mutex);
-       if (!port->serial->disconnected)
-               cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_DISABLE);
-       mutex_unlock(&port->serial->disc_mutex);
+       cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_DISABLE);
 }
 
 /*
index 629bd2894506344e2177d4191d1b9e4a19a8b6f4..781426230d695a3f34544ab4b0a589a500a0063e 100644 (file)
@@ -51,7 +51,6 @@
 #define CYBERJACK_PRODUCT_ID   0x0100
 
 /* Function prototypes */
-static void cyberjack_disconnect(struct usb_serial *serial);
 static int cyberjack_port_probe(struct usb_serial_port *port);
 static int cyberjack_port_remove(struct usb_serial_port *port);
 static int  cyberjack_open(struct tty_struct *tty,
@@ -79,7 +78,6 @@ static struct usb_serial_driver cyberjack_device = {
        .description =          "Reiner SCT Cyberjack USB card reader",
        .id_table =             id_table,
        .num_ports =            1,
-       .disconnect =           cyberjack_disconnect,
        .port_probe =           cyberjack_port_probe,
        .port_remove =          cyberjack_port_remove,
        .open =                 cyberjack_open,
@@ -130,20 +128,14 @@ static int cyberjack_port_remove(struct usb_serial_port *port)
 {
        struct cyberjack_private *priv;
 
+       usb_kill_urb(port->interrupt_in_urb);
+
        priv = usb_get_serial_port_data(port);
        kfree(priv);
 
        return 0;
 }
 
-static void cyberjack_disconnect(struct usb_serial *serial)
-{
-       int i;
-
-       for (i = 0; i < serial->num_ports; ++i)
-               usb_kill_urb(serial->port[i]->interrupt_in_urb);
-}
-
 static int  cyberjack_open(struct tty_struct *tty,
                                        struct usb_serial_port *port)
 {
@@ -166,11 +158,8 @@ static int  cyberjack_open(struct tty_struct *tty,
 
 static void cyberjack_close(struct usb_serial_port *port)
 {
-       if (port->serial->dev) {
-               /* shutdown any bulk reads that might be going on */
-               usb_kill_urb(port->write_urb);
-               usb_kill_urb(port->read_urb);
-       }
+       usb_kill_urb(port->write_urb);
+       usb_kill_urb(port->read_urb);
 }
 
 static int cyberjack_write(struct tty_struct *tty,
index ba7352e4187efbd1ef73a09297d1cbb1825a4b08..d341555d37d8bbe85f719d782049806522d2a066 100644 (file)
@@ -129,13 +129,12 @@ static int  cypress_write(struct tty_struct *tty, struct usb_serial_port *port,
                        const unsigned char *buf, int count);
 static void cypress_send(struct usb_serial_port *port);
 static int  cypress_write_room(struct tty_struct *tty);
-static int  cypress_ioctl(struct tty_struct *tty,
-                       unsigned int cmd, unsigned long arg);
 static void cypress_set_termios(struct tty_struct *tty,
                        struct usb_serial_port *port, struct ktermios *old);
 static int  cypress_tiocmget(struct tty_struct *tty);
 static int  cypress_tiocmset(struct tty_struct *tty,
                        unsigned int set, unsigned int clear);
+static int  cypress_tiocmiwait(struct tty_struct *tty, unsigned long arg);
 static int  cypress_chars_in_buffer(struct tty_struct *tty);
 static void cypress_throttle(struct tty_struct *tty);
 static void cypress_unthrottle(struct tty_struct *tty);
@@ -158,10 +157,10 @@ static struct usb_serial_driver cypress_earthmate_device = {
        .dtr_rts =                      cypress_dtr_rts,
        .write =                        cypress_write,
        .write_room =                   cypress_write_room,
-       .ioctl =                        cypress_ioctl,
        .set_termios =                  cypress_set_termios,
        .tiocmget =                     cypress_tiocmget,
        .tiocmset =                     cypress_tiocmset,
+       .tiocmiwait =                   cypress_tiocmiwait,
        .chars_in_buffer =              cypress_chars_in_buffer,
        .throttle =                     cypress_throttle,
        .unthrottle =                   cypress_unthrottle,
@@ -184,10 +183,10 @@ static struct usb_serial_driver cypress_hidcom_device = {
        .dtr_rts =                      cypress_dtr_rts,
        .write =                        cypress_write,
        .write_room =                   cypress_write_room,
-       .ioctl =                        cypress_ioctl,
        .set_termios =                  cypress_set_termios,
        .tiocmget =                     cypress_tiocmget,
        .tiocmset =                     cypress_tiocmset,
+       .tiocmiwait =                   cypress_tiocmiwait,
        .chars_in_buffer =              cypress_chars_in_buffer,
        .throttle =                     cypress_throttle,
        .unthrottle =                   cypress_unthrottle,
@@ -210,10 +209,10 @@ static struct usb_serial_driver cypress_ca42v2_device = {
        .dtr_rts =                      cypress_dtr_rts,
        .write =                        cypress_write,
        .write_room =                   cypress_write_room,
-       .ioctl =                        cypress_ioctl,
        .set_termios =                  cypress_set_termios,
        .tiocmget =                     cypress_tiocmget,
        .tiocmset =                     cypress_tiocmset,
+       .tiocmiwait =                   cypress_tiocmiwait,
        .chars_in_buffer =              cypress_chars_in_buffer,
        .throttle =                     cypress_throttle,
        .unthrottle =                   cypress_unthrottle,
@@ -633,12 +632,6 @@ static void cypress_close(struct usb_serial_port *port)
        struct cypress_private *priv = usb_get_serial_port_data(port);
        unsigned long flags;
 
-       /* writing is potentially harmful, lock must be taken */
-       mutex_lock(&port->serial->disc_mutex);
-       if (port->serial->disconnected) {
-               mutex_unlock(&port->serial->disc_mutex);
-               return;
-       }
        spin_lock_irqsave(&priv->lock, flags);
        kfifo_reset_out(&priv->write_fifo);
        spin_unlock_irqrestore(&priv->lock, flags);
@@ -650,7 +643,6 @@ static void cypress_close(struct usb_serial_port *port)
        if (stats)
                dev_info(&port->dev, "Statistics: %d Bytes In | %d Bytes Out | %d Commands Issued\n",
                        priv->bytes_in, priv->bytes_out, priv->cmd_count);
-       mutex_unlock(&port->serial->disc_mutex);
 } /* cypress_close */
 
 
@@ -855,55 +847,43 @@ static int cypress_tiocmset(struct tty_struct *tty,
 }
 
 
-static int cypress_ioctl(struct tty_struct *tty,
-                                       unsigned int cmd, unsigned long arg)
+static int cypress_tiocmiwait(struct tty_struct *tty, unsigned long arg)
 {
        struct usb_serial_port *port = tty->driver_data;
        struct cypress_private *priv = usb_get_serial_port_data(port);
-
-       dev_dbg(&port->dev, "%s - port %d, cmd 0x%.4x\n", __func__, port->number, cmd);
-
-       switch (cmd) {
-       /* This code comes from drivers/char/serial.c and ftdi_sio.c */
-       case TIOCMIWAIT:
-               for (;;) {
-                       interruptible_sleep_on(&port->delta_msr_wait);
-                       /* see if a signal did it */
-                       if (signal_pending(current))
-                               return -ERESTARTSYS;
-
-                       if (port->serial->disconnected)
-                               return -EIO;
-
-                       {
-                               char diff = priv->diff_status;
-                               if (diff == 0)
-                                       return -EIO; /* no change => error */
-
-                               /* consume all events */
-                               priv->diff_status = 0;
-
-                               /* return 0 if caller wanted to know about
-                                  these bits */
-                               if (((arg & TIOCM_RNG) && (diff & UART_RI)) ||
-                                   ((arg & TIOCM_DSR) && (diff & UART_DSR)) ||
-                                   ((arg & TIOCM_CD) && (diff & UART_CD)) ||
-                                   ((arg & TIOCM_CTS) && (diff & UART_CTS)))
-                                       return 0;
-                               /* otherwise caller can't care less about what
-                                * happened, and so we continue to wait for
-                                * more events.
-                                */
-                       }
-               }
-               return 0;
-       default:
-               break;
+       char diff;
+
+       for (;;) {
+               interruptible_sleep_on(&port->port.delta_msr_wait);
+               /* see if a signal did it */
+               if (signal_pending(current))
+                       return -ERESTARTSYS;
+
+               if (port->serial->disconnected)
+                       return -EIO;
+
+               diff = priv->diff_status;
+               if (diff == 0)
+                       return -EIO; /* no change => error */
+
+               /* consume all events */
+               priv->diff_status = 0;
+
+               /* return 0 if caller wanted to know about
+                  these bits */
+               if (((arg & TIOCM_RNG) && (diff & UART_RI))  ||
+                       ((arg & TIOCM_DSR) && (diff & UART_DSR)) ||
+                       ((arg & TIOCM_CD)  && (diff & UART_CD))  ||
+                       ((arg & TIOCM_CTS) && (diff & UART_CTS)))
+                       return 0;
+               /* otherwise caller can't care less about what
+                * happened, and so we continue to wait for
+                * more events.
+                */
        }
-       dev_dbg(&port->dev, "%s - arg not supported - it was 0x%04x - check include/asm/ioctls.h\n", __func__, cmd);
-       return -ENOIOCTLCMD;
-} /* cypress_ioctl */
 
+       return 0;
+}
 
 static void cypress_set_termios(struct tty_struct *tty,
        struct usb_serial_port *port, struct ktermios *old_termios)
@@ -1189,7 +1169,7 @@ static void cypress_read_int_callback(struct urb *urb)
        if (priv->current_status != priv->prev_status) {
                priv->diff_status |= priv->current_status ^
                        priv->prev_status;
-               wake_up_interruptible(&port->delta_msr_wait);
+               wake_up_interruptible(&port->port.delta_msr_wait);
                priv->prev_status = priv->current_status;
        }
        spin_unlock_irqrestore(&priv->lock, flags);
index ebe45fa0ed50a3722ed7feae0750558ffea7fdad..32873b4064025b124960e45b1309ef5a47d24346 100644 (file)
@@ -196,7 +196,6 @@ struct digi_port {
        unsigned char dp_out_buf[DIGI_OUT_BUF_SIZE];
        int dp_write_urb_in_use;
        unsigned int dp_modem_signals;
-       wait_queue_head_t dp_modem_change_wait;
        int dp_transmit_idle;
        wait_queue_head_t dp_transmit_idle_wait;
        int dp_throttled;
@@ -1149,53 +1148,51 @@ static void digi_close(struct usb_serial_port *port)
        if (port->serial->disconnected)
                goto exit;
 
-       if (port->serial->dev) {
-               /* FIXME: Transmit idle belongs in the wait_unti_sent path */
-               digi_transmit_idle(port, DIGI_CLOSE_TIMEOUT);
-
-               /* disable input flow control */
-               buf[0] = DIGI_CMD_SET_INPUT_FLOW_CONTROL;
-               buf[1] = priv->dp_port_num;
-               buf[2] = DIGI_DISABLE;
-               buf[3] = 0;
-
-               /* disable output flow control */
-               buf[4] = DIGI_CMD_SET_OUTPUT_FLOW_CONTROL;
-               buf[5] = priv->dp_port_num;
-               buf[6] = DIGI_DISABLE;
-               buf[7] = 0;
-
-               /* disable reading modem signals automatically */
-               buf[8] = DIGI_CMD_READ_INPUT_SIGNALS;
-               buf[9] = priv->dp_port_num;
-               buf[10] = DIGI_DISABLE;
-               buf[11] = 0;
-
-               /* disable receive */
-               buf[12] = DIGI_CMD_RECEIVE_ENABLE;
-               buf[13] = priv->dp_port_num;
-               buf[14] = DIGI_DISABLE;
-               buf[15] = 0;
-
-               /* flush fifos */
-               buf[16] = DIGI_CMD_IFLUSH_FIFO;
-               buf[17] = priv->dp_port_num;
-               buf[18] = DIGI_FLUSH_TX | DIGI_FLUSH_RX;
-               buf[19] = 0;
-
-               ret = digi_write_oob_command(port, buf, 20, 0);
-               if (ret != 0)
-                       dev_dbg(&port->dev, "digi_close: write oob failed, ret=%d\n", ret);
-
-               /* wait for final commands on oob port to complete */
-               prepare_to_wait(&priv->dp_flush_wait, &wait,
-                                                       TASK_INTERRUPTIBLE);
-               schedule_timeout(DIGI_CLOSE_TIMEOUT);
-               finish_wait(&priv->dp_flush_wait, &wait);
-
-               /* shutdown any outstanding bulk writes */
-               usb_kill_urb(port->write_urb);
-       }
+       /* FIXME: Transmit idle belongs in the wait_unti_sent path */
+       digi_transmit_idle(port, DIGI_CLOSE_TIMEOUT);
+
+       /* disable input flow control */
+       buf[0] = DIGI_CMD_SET_INPUT_FLOW_CONTROL;
+       buf[1] = priv->dp_port_num;
+       buf[2] = DIGI_DISABLE;
+       buf[3] = 0;
+
+       /* disable output flow control */
+       buf[4] = DIGI_CMD_SET_OUTPUT_FLOW_CONTROL;
+       buf[5] = priv->dp_port_num;
+       buf[6] = DIGI_DISABLE;
+       buf[7] = 0;
+
+       /* disable reading modem signals automatically */
+       buf[8] = DIGI_CMD_READ_INPUT_SIGNALS;
+       buf[9] = priv->dp_port_num;
+       buf[10] = DIGI_DISABLE;
+       buf[11] = 0;
+
+       /* disable receive */
+       buf[12] = DIGI_CMD_RECEIVE_ENABLE;
+       buf[13] = priv->dp_port_num;
+       buf[14] = DIGI_DISABLE;
+       buf[15] = 0;
+
+       /* flush fifos */
+       buf[16] = DIGI_CMD_IFLUSH_FIFO;
+       buf[17] = priv->dp_port_num;
+       buf[18] = DIGI_FLUSH_TX | DIGI_FLUSH_RX;
+       buf[19] = 0;
+
+       ret = digi_write_oob_command(port, buf, 20, 0);
+       if (ret != 0)
+               dev_dbg(&port->dev, "digi_close: write oob failed, ret=%d\n",
+                                                                       ret);
+       /* wait for final commands on oob port to complete */
+       prepare_to_wait(&priv->dp_flush_wait, &wait,
+                       TASK_INTERRUPTIBLE);
+       schedule_timeout(DIGI_CLOSE_TIMEOUT);
+       finish_wait(&priv->dp_flush_wait, &wait);
+
+       /* shutdown any outstanding bulk writes */
+       usb_kill_urb(port->write_urb);
 exit:
        spin_lock_irq(&priv->dp_port_lock);
        priv->dp_write_urb_in_use = 0;
@@ -1252,7 +1249,6 @@ static int digi_port_init(struct usb_serial_port *port, unsigned port_num)
 
        spin_lock_init(&priv->dp_port_lock);
        priv->dp_port_num = port_num;
-       init_waitqueue_head(&priv->dp_modem_change_wait);
        init_waitqueue_head(&priv->dp_transmit_idle_wait);
        init_waitqueue_head(&priv->dp_flush_wait);
        init_waitqueue_head(&priv->dp_close_wait);
@@ -1543,7 +1539,6 @@ static int digi_read_oob_callback(struct urb *urb)
                        else
                                priv->dp_modem_signals &= ~TIOCM_CD;
 
-                       wake_up_interruptible(&priv->dp_modem_change_wait);
                        spin_unlock(&priv->dp_port_lock);
                } else if (opcode == DIGI_CMD_TRANSMIT_IDLE) {
                        spin_lock(&priv->dp_port_lock);
index a172ad5c5ce80c1c00983960a04339ac3c13fb24..090b411d893f8b957d816eb6b45bd599948ea055 100644 (file)
@@ -110,7 +110,7 @@ static void f81232_process_read_urb(struct urb *urb)
        line_status = priv->line_status;
        priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
        spin_unlock_irqrestore(&priv->lock, flags);
-       wake_up_interruptible(&port->delta_msr_wait);
+       wake_up_interruptible(&port->port.delta_msr_wait);
 
        if (!urb->actual_length)
                return;
@@ -242,8 +242,9 @@ static int f81232_carrier_raised(struct usb_serial_port *port)
        return 0;
 }
 
-static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
+static int f81232_tiocmiwait(struct tty_struct *tty, unsigned long arg)
 {
+       struct usb_serial_port *port = tty->driver_data;
        struct f81232_private *priv = usb_get_serial_port_data(port);
        unsigned long flags;
        unsigned int prevstatus;
@@ -255,7 +256,7 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
        spin_unlock_irqrestore(&priv->lock, flags);
 
        while (1) {
-               interruptible_sleep_on(&port->delta_msr_wait);
+               interruptible_sleep_on(&port->port.delta_msr_wait);
                /* see if a signal did it */
                if (signal_pending(current))
                        return -ERESTARTSYS;
@@ -302,11 +303,6 @@ static int f81232_ioctl(struct tty_struct *tty,
                        return -EFAULT;
 
                return 0;
-
-       case TIOCMIWAIT:
-               dev_dbg(&port->dev, "%s (%d) TIOCMIWAIT\n", __func__,
-                       port->number);
-               return wait_modem_info(port, arg);
        default:
                dev_dbg(&port->dev, "%s not supported = 0x%04x\n",
                        __func__, cmd);
@@ -358,6 +354,7 @@ static struct usb_serial_driver f81232_device = {
        .set_termios =          f81232_set_termios,
        .tiocmget =             f81232_tiocmget,
        .tiocmset =             f81232_tiocmset,
+       .tiocmiwait =           f81232_tiocmiwait,
        .process_read_urb =     f81232_process_read_urb,
        .read_int_callback =    f81232_read_int_callback,
        .port_probe =           f81232_port_probe,
index 9886180e45f1b5d73ddc1903f2e13eecb6297013..778c54dd3dff146e92da96cd10b9ea5ecfdbc353 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * USB FTDI SIO driver
  *
- *     Copyright (C) 2009 - 2010
+ *     Copyright (C) 2009 - 2013
  *         Johan Hovold (jhovold@gmail.com)
  *     Copyright (C) 1999 - 2001
  *         Greg Kroah-Hartman (greg@kroah.com)
@@ -55,7 +55,6 @@ static __u16 vendor = FTDI_VID;
 static __u16 product;
 
 struct ftdi_private {
-       struct kref kref;
        enum ftdi_chip_type chip_type;
                                /* type of device, either SIO or FT8U232AM */
        int baud_base;          /* baud base clock for divisor setting */
@@ -68,7 +67,6 @@ struct ftdi_private {
                                 */
        int flags;              /* some ASYNC_xxxx flags are supported */
        unsigned long last_dtr_rts;     /* saved modem control outputs */
-       struct async_icount     icount;
        char prev_status;        /* Used for TIOCMIWAIT */
        char transmit_empty;    /* If transmitter is empty or not */
        __u16 interface;        /* FT2232C, FT2232H or FT4232H port interface
@@ -911,7 +909,6 @@ static int  ftdi_sio_probe(struct usb_serial *serial,
 static int  ftdi_sio_port_probe(struct usb_serial_port *port);
 static int  ftdi_sio_port_remove(struct usb_serial_port *port);
 static int  ftdi_open(struct tty_struct *tty, struct usb_serial_port *port);
-static void ftdi_close(struct usb_serial_port *port);
 static void ftdi_dtr_rts(struct usb_serial_port *port, int on);
 static void ftdi_process_read_urb(struct urb *urb);
 static int ftdi_prepare_write_buffer(struct usb_serial_port *port,
@@ -921,8 +918,6 @@ static void ftdi_set_termios(struct tty_struct *tty,
 static int  ftdi_tiocmget(struct tty_struct *tty);
 static int  ftdi_tiocmset(struct tty_struct *tty,
                        unsigned int set, unsigned int clear);
-static int ftdi_get_icount(struct tty_struct *tty,
-                          struct serial_icounter_struct *icount);
 static int  ftdi_ioctl(struct tty_struct *tty,
                        unsigned int cmd, unsigned long arg);
 static void ftdi_break_ctl(struct tty_struct *tty, int break_state);
@@ -951,7 +946,6 @@ static struct usb_serial_driver ftdi_sio_device = {
        .port_probe =           ftdi_sio_port_probe,
        .port_remove =          ftdi_sio_port_remove,
        .open =                 ftdi_open,
-       .close =                ftdi_close,
        .dtr_rts =              ftdi_dtr_rts,
        .throttle =             usb_serial_generic_throttle,
        .unthrottle =           usb_serial_generic_unthrottle,
@@ -959,7 +953,8 @@ static struct usb_serial_driver ftdi_sio_device = {
        .prepare_write_buffer = ftdi_prepare_write_buffer,
        .tiocmget =             ftdi_tiocmget,
        .tiocmset =             ftdi_tiocmset,
-       .get_icount =           ftdi_get_icount,
+       .tiocmiwait =           usb_serial_generic_tiocmiwait,
+       .get_icount =           usb_serial_generic_get_icount,
        .ioctl =                ftdi_ioctl,
        .set_termios =          ftdi_set_termios,
        .break_ctl =            ftdi_break_ctl,
@@ -1688,7 +1683,6 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
                return -ENOMEM;
        }
 
-       kref_init(&priv->kref);
        mutex_init(&priv->cfg_lock);
 
        priv->flags = ASYNC_LOW_LATENCY;
@@ -1826,22 +1820,13 @@ static int ftdi_mtxorb_hack_setup(struct usb_serial *serial)
        return 0;
 }
 
-static void ftdi_sio_priv_release(struct kref *k)
-{
-       struct ftdi_private *priv = container_of(k, struct ftdi_private, kref);
-
-       kfree(priv);
-}
-
 static int ftdi_sio_port_remove(struct usb_serial_port *port)
 {
        struct ftdi_private *priv = usb_get_serial_port_data(port);
 
-       wake_up_interruptible(&port->delta_msr_wait);
-
        remove_sysfs_attrs(port);
 
-       kref_put(&priv->kref, ftdi_sio_priv_release);
+       kfree(priv);
 
        return 0;
 }
@@ -1851,7 +1836,6 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)
        struct ktermios dummy;
        struct usb_device *dev = port->serial->dev;
        struct ftdi_private *priv = usb_get_serial_port_data(port);
-       int result;
 
        /* No error checking for this (will get errors later anyway) */
        /* See ftdi_sio.h for description of what is reset */
@@ -1870,12 +1854,7 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)
                ftdi_set_termios(tty, port, &dummy);
        }
 
-       /* Start reading from the device */
-       result = usb_serial_generic_open(tty, port);
-       if (!result)
-               kref_get(&priv->kref);
-
-       return result;
+       return usb_serial_generic_open(tty, port);
 }
 
 static void ftdi_dtr_rts(struct usb_serial_port *port, int on)
@@ -1900,19 +1879,6 @@ static void ftdi_dtr_rts(struct usb_serial_port *port, int on)
                clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
 }
 
-/*
- * usbserial:__serial_close  only calls ftdi_close if the point is open
- *
- *   This only gets called when it is the last close
- */
-static void ftdi_close(struct usb_serial_port *port)
-{
-       struct ftdi_private *priv = usb_get_serial_port_data(port);
-
-       usb_serial_generic_close(port);
-       kref_put(&priv->kref, ftdi_sio_priv_release);
-}
-
 /* The SIO requires the first byte to have:
  *  B0 1
  *  B1 0
@@ -1940,7 +1906,7 @@ static int ftdi_prepare_write_buffer(struct usb_serial_port *port,
                        c = kfifo_out(&port->write_fifo, &buffer[i + 1], len);
                        if (!c)
                                break;
-                       priv->icount.tx += c;
+                       port->icount.tx += c;
                        buffer[i] = (c << 2) + 1;
                        count += c + 1;
                }
@@ -1948,7 +1914,7 @@ static int ftdi_prepare_write_buffer(struct usb_serial_port *port,
        } else {
                count = kfifo_out_locked(&port->write_fifo, dest, size,
                                                                &port->lock);
-               priv->icount.tx += count;
+               port->icount.tx += count;
        }
 
        return count;
@@ -1977,15 +1943,15 @@ static int ftdi_process_packet(struct usb_serial_port *port,
                char diff_status = status ^ priv->prev_status;
 
                if (diff_status & FTDI_RS0_CTS)
-                       priv->icount.cts++;
+                       port->icount.cts++;
                if (diff_status & FTDI_RS0_DSR)
-                       priv->icount.dsr++;
+                       port->icount.dsr++;
                if (diff_status & FTDI_RS0_RI)
-                       priv->icount.rng++;
+                       port->icount.rng++;
                if (diff_status & FTDI_RS0_RLSD)
-                       priv->icount.dcd++;
+                       port->icount.dcd++;
 
-               wake_up_interruptible(&port->delta_msr_wait);
+               wake_up_interruptible(&port->port.delta_msr_wait);
                priv->prev_status = status;
        }
 
@@ -1995,18 +1961,18 @@ static int ftdi_process_packet(struct usb_serial_port *port,
                 * over framing errors */
                if (packet[1] & FTDI_RS_BI) {
                        flag = TTY_BREAK;
-                       priv->icount.brk++;
+                       port->icount.brk++;
                        usb_serial_handle_break(port);
                } else if (packet[1] & FTDI_RS_PE) {
                        flag = TTY_PARITY;
-                       priv->icount.parity++;
+                       port->icount.parity++;
                } else if (packet[1] & FTDI_RS_FE) {
                        flag = TTY_FRAME;
-                       priv->icount.frame++;
+                       port->icount.frame++;
                }
                /* Overrun is special, not associated with a char */
                if (packet[1] & FTDI_RS_OE) {
-                       priv->icount.overrun++;
+                       port->icount.overrun++;
                        tty_insert_flip_char(&port->port, 0, TTY_OVERRUN);
                }
        }
@@ -2020,7 +1986,7 @@ static int ftdi_process_packet(struct usb_serial_port *port,
        len -= 2;
        if (!len)
                return 0;       /* status only */
-       priv->icount.rx += len;
+       port->icount.rx += len;
        ch = packet + 2;
 
        if (port->port.console && port->sysrq) {
@@ -2384,34 +2350,10 @@ static int ftdi_tiocmset(struct tty_struct *tty,
        return update_mctrl(port, set, clear);
 }
 
-static int ftdi_get_icount(struct tty_struct *tty,
-                               struct serial_icounter_struct *icount)
-{
-       struct usb_serial_port *port = tty->driver_data;
-       struct ftdi_private *priv = usb_get_serial_port_data(port);
-       struct async_icount *ic = &priv->icount;
-
-       icount->cts = ic->cts;
-       icount->dsr = ic->dsr;
-       icount->rng = ic->rng;
-       icount->dcd = ic->dcd;
-       icount->tx = ic->tx;
-       icount->rx = ic->rx;
-       icount->frame = ic->frame;
-       icount->parity = ic->parity;
-       icount->overrun = ic->overrun;
-       icount->brk = ic->brk;
-       icount->buf_overrun = ic->buf_overrun;
-       return 0;
-}
-
 static int ftdi_ioctl(struct tty_struct *tty,
                                        unsigned int cmd, unsigned long arg)
 {
        struct usb_serial_port *port = tty->driver_data;
-       struct ftdi_private *priv = usb_get_serial_port_data(port);
-       struct async_icount cnow;
-       struct async_icount cprev;
 
        dev_dbg(&port->dev, "%s cmd 0x%04x\n", __func__, cmd);
 
@@ -2425,35 +2367,6 @@ static int ftdi_ioctl(struct tty_struct *tty,
        case TIOCSSERIAL: /* sets serial port data */
                return set_serial_info(tty, port,
                                        (struct serial_struct __user *) arg);
-
-       /*
-        * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
-        * - mask passed in arg for lines of interest
-        *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
-        * Caller should use TIOCGICOUNT to see which one it was.
-        *
-        * This code is borrowed from linux/drivers/char/serial.c
-        */
-       case TIOCMIWAIT:
-               cprev = priv->icount;
-               for (;;) {
-                       interruptible_sleep_on(&port->delta_msr_wait);
-                       /* see if a signal did it */
-                       if (signal_pending(current))
-                               return -ERESTARTSYS;
-
-                       if (port->serial->disconnected)
-                               return -EIO;
-
-                       cnow = priv->icount;
-                       if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
-                           ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
-                           ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
-                           ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
-                               return 0;
-                       }
-                       cprev = cnow;
-               }
        case TIOCSERGETLSR:
                return get_lsr_info(port, (struct serial_struct __user *)arg);
                break;
index 81caf5623ee295d609acce00a1e06a20ef34c20f..b110c573ea85319490922d8f3c538d507913c060 100644 (file)
@@ -946,16 +946,12 @@ static int garmin_open(struct tty_struct *tty, struct usb_serial_port *port)
 
 static void garmin_close(struct usb_serial_port *port)
 {
-       struct usb_serial *serial = port->serial;
        struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);
 
        dev_dbg(&port->dev, "%s - port %d - mode=%d state=%d flags=0x%X\n",
                __func__, port->number, garmin_data_p->mode,
                garmin_data_p->state, garmin_data_p->flags);
 
-       if (!serial)
-               return;
-
        garmin_clear(garmin_data_p);
 
        /* shutdown our urbs */
@@ -1185,17 +1181,11 @@ static void garmin_read_bulk_callback(struct urb *urb)
 {
        unsigned long flags;
        struct usb_serial_port *port = urb->context;
-       struct usb_serial *serial =  port->serial;
        struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);
        unsigned char *data = urb->transfer_buffer;
        int status = urb->status;
        int retval;
 
-       if (!serial) {
-               dev_dbg(&urb->dev->dev, "%s - bad serial pointer, exiting\n", __func__);
-               return;
-       }
-
        if (status) {
                dev_dbg(&urb->dev->dev, "%s - nonzero read bulk status received: %d\n",
                        __func__, status);
index 4c5c23f1cae5db8a5ff157cbe0277dfb4bc42e5d..297665fdd16d31993a5e95cddd313626453be6c7 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * USB Serial Converter Generic functions
  *
- * Copyright (C) 2010 - 2011 Johan Hovold (jhovold@gmail.com)
+ * Copyright (C) 2010 - 2013 Johan Hovold (jhovold@gmail.com)
  * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com)
  *
  *     This program is free software; you can redistribute it and/or
@@ -45,8 +45,6 @@ struct usb_serial_driver usb_serial_generic_device = {
        },
        .id_table =             generic_device_ids,
        .num_ports =            1,
-       .disconnect =           usb_serial_generic_disconnect,
-       .release =              usb_serial_generic_release,
        .throttle =             usb_serial_generic_throttle,
        .unthrottle =           usb_serial_generic_unthrottle,
        .resume =               usb_serial_generic_resume,
@@ -102,32 +100,23 @@ int usb_serial_generic_open(struct tty_struct *tty, struct usb_serial_port *port
 }
 EXPORT_SYMBOL_GPL(usb_serial_generic_open);
 
-static void generic_cleanup(struct usb_serial_port *port)
+void usb_serial_generic_close(struct usb_serial_port *port)
 {
-       struct usb_serial *serial = port->serial;
        unsigned long flags;
        int i;
 
-       if (serial->dev) {
-               /* shutdown any bulk transfers that might be going on */
-               if (port->bulk_out_size) {
-                       for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i)
-                               usb_kill_urb(port->write_urbs[i]);
+       if (port->bulk_out_size) {
+               for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i)
+                       usb_kill_urb(port->write_urbs[i]);
 
-                       spin_lock_irqsave(&port->lock, flags);
-                       kfifo_reset_out(&port->write_fifo);
-                       spin_unlock_irqrestore(&port->lock, flags);
-               }
-               if (port->bulk_in_size) {
-                       for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i)
-                               usb_kill_urb(port->read_urbs[i]);
-               }
+               spin_lock_irqsave(&port->lock, flags);
+               kfifo_reset_out(&port->write_fifo);
+               spin_unlock_irqrestore(&port->lock, flags);
+       }
+       if (port->bulk_in_size) {
+               for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i)
+                       usb_kill_urb(port->read_urbs[i]);
        }
-}
-
-void usb_serial_generic_close(struct usb_serial_port *port)
-{
-       generic_cleanup(port);
 }
 EXPORT_SYMBOL_GPL(usb_serial_generic_close);
 
@@ -272,8 +261,7 @@ static int usb_serial_generic_submit_read_urb(struct usb_serial_port *port,
        if (!test_and_clear_bit(index, &port->read_urbs_free))
                return 0;
 
-       dev_dbg(&port->dev, "%s - port %d, urb %d\n", __func__,
-               port->number, index);
+       dev_dbg(&port->dev, "%s - urb %d\n", __func__, index);
 
        res = usb_submit_urb(port->read_urbs[index], mem_flags);
        if (res) {
@@ -347,8 +335,8 @@ void usb_serial_generic_read_bulk_callback(struct urb *urb)
        }
        set_bit(i, &port->read_urbs_free);
 
-       dev_dbg(&port->dev, "%s - port %d, urb %d, len %d\n",
-               __func__, port->number, i, urb->actual_length);
+       dev_dbg(&port->dev, "%s - urb %d, len %d\n", __func__, i,
+                                                       urb->actual_length);
 
        if (urb->status) {
                dev_dbg(&port->dev, "%s - non-zero urb status: %d\n",
@@ -430,6 +418,91 @@ void usb_serial_generic_unthrottle(struct tty_struct *tty)
 }
 EXPORT_SYMBOL_GPL(usb_serial_generic_unthrottle);
 
+static bool usb_serial_generic_msr_changed(struct tty_struct *tty,
+                               unsigned long arg, struct async_icount *cprev)
+{
+       struct usb_serial_port *port = tty->driver_data;
+       struct async_icount cnow;
+       unsigned long flags;
+       bool ret;
+
+       /*
+        * Use tty-port initialised flag to detect all hangups including the
+        * one generated at USB-device disconnect.
+        *
+        * FIXME: Remove hupping check once tty_port_hangup calls shutdown
+        *        (which clears the initialised flag) before wake up.
+        */
+       if (test_bit(TTY_HUPPING, &tty->flags))
+               return true;
+       if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags))
+               return true;
+
+       spin_lock_irqsave(&port->lock, flags);
+       cnow = port->icount;                            /* atomic copy*/
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       ret =   ((arg & TIOCM_RNG) && (cnow.rng != cprev->rng)) ||
+               ((arg & TIOCM_DSR) && (cnow.dsr != cprev->dsr)) ||
+               ((arg & TIOCM_CD)  && (cnow.dcd != cprev->dcd)) ||
+               ((arg & TIOCM_CTS) && (cnow.cts != cprev->cts));
+
+       *cprev = cnow;
+
+       return ret;
+}
+
+int usb_serial_generic_tiocmiwait(struct tty_struct *tty, unsigned long arg)
+{
+       struct usb_serial_port *port = tty->driver_data;
+       struct async_icount cnow;
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&port->lock, flags);
+       cnow = port->icount;                            /* atomic copy */
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       ret = wait_event_interruptible(port->port.delta_msr_wait,
+                       usb_serial_generic_msr_changed(tty, arg, &cnow));
+       if (!ret) {
+               if (test_bit(TTY_HUPPING, &tty->flags))
+                       ret = -EIO;
+               if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags))
+                       ret = -EIO;
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(usb_serial_generic_tiocmiwait);
+
+int usb_serial_generic_get_icount(struct tty_struct *tty,
+                                       struct serial_icounter_struct *icount)
+{
+       struct usb_serial_port *port = tty->driver_data;
+       struct async_icount cnow;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       cnow = port->icount;                            /* atomic copy */
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       icount->cts = cnow.cts;
+       icount->dsr = cnow.dsr;
+       icount->rng = cnow.rng;
+       icount->dcd = cnow.dcd;
+       icount->tx = cnow.tx;
+       icount->rx = cnow.rx;
+       icount->frame = cnow.frame;
+       icount->parity = cnow.parity;
+       icount->overrun = cnow.overrun;
+       icount->brk = cnow.brk;
+       icount->buf_overrun = cnow.buf_overrun;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(usb_serial_generic_get_icount);
+
 #ifdef CONFIG_MAGIC_SYSRQ
 int usb_serial_handle_sysrq_char(struct usb_serial_port *port, unsigned int ch)
 {
@@ -473,8 +546,7 @@ void usb_serial_handle_dcd_change(struct usb_serial_port *usb_port,
 {
        struct tty_port *port = &usb_port->port;
 
-       dev_dbg(&usb_port->dev, "%s - port %d, status %d\n", __func__,
-               usb_port->number, status);
+       dev_dbg(&usb_port->dev, "%s - status %d\n", __func__, status);
 
        if (status)
                wake_up_interruptible(&port->open_wait);
@@ -510,17 +582,3 @@ int usb_serial_generic_resume(struct usb_serial *serial)
        return c ? -EIO : 0;
 }
 EXPORT_SYMBOL_GPL(usb_serial_generic_resume);
-
-void usb_serial_generic_disconnect(struct usb_serial *serial)
-{
-       int i;
-
-       /* stop reads and writes on all ports */
-       for (i = 0; i < serial->num_ports; ++i)
-               generic_cleanup(serial->port[i]);
-}
-EXPORT_SYMBOL_GPL(usb_serial_generic_disconnect);
-
-void usb_serial_generic_release(struct usb_serial *serial)
-{
-}
index efd8b978128c1d86412322f0c37e9da32b00610a..ff9a6ef8477f26b8c65da0366664debc38dea0fd 100644 (file)
@@ -111,7 +111,6 @@ struct edgeport_port {
        wait_queue_head_t       wait_open;              /* for handling sleeping while waiting for open to finish */
        wait_queue_head_t       wait_command;           /* for handling sleeping while waiting for command to finish */
 
-       struct async_icount     icount;
        struct usb_serial_port  *port;                  /* loop back to the owner of this object */
 };
 
@@ -215,8 +214,6 @@ static void edge_break(struct tty_struct *tty, int break_state);
 static int  edge_tiocmget(struct tty_struct *tty);
 static int  edge_tiocmset(struct tty_struct *tty,
                                        unsigned int set, unsigned int clear);
-static int  edge_get_icount(struct tty_struct *tty,
-                               struct serial_icounter_struct *icount);
 static int  edge_startup(struct usb_serial *serial);
 static void edge_disconnect(struct usb_serial *serial);
 static void edge_release(struct usb_serial *serial);
@@ -885,9 +882,6 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port)
        init_waitqueue_head(&edge_port->wait_chase);
        init_waitqueue_head(&edge_port->wait_command);
 
-       /* initialize our icount structure */
-       memset(&(edge_port->icount), 0x00, sizeof(edge_port->icount));
-
        /* initialize our port settings */
        edge_port->txCredits = 0;       /* Can't send any data yet */
        /* Must always set this bit to enable ints! */
@@ -1314,7 +1308,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial,
 
        /* decrement the number of credits we have by the number we just sent */
        edge_port->txCredits -= count;
-       edge_port->icount.tx += count;
+       edge_port->port->icount.tx += count;
 
        status = usb_submit_urb(urb, GFP_ATOMIC);
        if (status) {
@@ -1326,7 +1320,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial,
 
                /* revert the credits as something bad happened. */
                edge_port->txCredits += count;
-               edge_port->icount.tx -= count;
+               edge_port->port->icount.tx -= count;
        }
        dev_dbg(dev, "%s wrote %d byte(s) TxCredit %d, Fifo %d\n",
                __func__, count, edge_port->txCredits, fifo->count);
@@ -1588,31 +1582,6 @@ static int edge_tiocmget(struct tty_struct *tty)
        return result;
 }
 
-static int edge_get_icount(struct tty_struct *tty,
-                               struct serial_icounter_struct *icount)
-{
-       struct usb_serial_port *port = tty->driver_data;
-       struct edgeport_port *edge_port = usb_get_serial_port_data(port);
-       struct async_icount cnow;
-       cnow = edge_port->icount;
-
-       icount->cts = cnow.cts;
-       icount->dsr = cnow.dsr;
-       icount->rng = cnow.rng;
-       icount->dcd = cnow.dcd;
-       icount->rx = cnow.rx;
-       icount->tx = cnow.tx;
-       icount->frame = cnow.frame;
-       icount->overrun = cnow.overrun;
-       icount->parity = cnow.parity;
-       icount->brk = cnow.brk;
-       icount->buf_overrun = cnow.buf_overrun;
-
-       dev_dbg(&port->dev, "%s (%d) TIOCGICOUNT RX=%d, TX=%d\n", __func__,
-               port->number, icount->rx, icount->tx);
-       return 0;
-}
-
 static int get_serial_info(struct edgeport_port *edge_port,
                                struct serial_struct __user *retinfo)
 {
@@ -1649,8 +1618,6 @@ static int edge_ioctl(struct tty_struct *tty,
        struct usb_serial_port *port = tty->driver_data;
        DEFINE_WAIT(wait);
        struct edgeport_port *edge_port = usb_get_serial_port_data(port);
-       struct async_icount cnow;
-       struct async_icount cprev;
 
        dev_dbg(&port->dev, "%s - port %d, cmd = 0x%x\n", __func__, port->number, cmd);
 
@@ -1662,37 +1629,6 @@ static int edge_ioctl(struct tty_struct *tty,
        case TIOCGSERIAL:
                dev_dbg(&port->dev, "%s (%d) TIOCGSERIAL\n", __func__,  port->number);
                return get_serial_info(edge_port, (struct serial_struct __user *) arg);
-
-       case TIOCMIWAIT:
-               dev_dbg(&port->dev, "%s (%d) TIOCMIWAIT\n", __func__,  port->number);
-               cprev = edge_port->icount;
-               while (1) {
-                       prepare_to_wait(&port->delta_msr_wait,
-                                               &wait, TASK_INTERRUPTIBLE);
-                       schedule();
-                       finish_wait(&port->delta_msr_wait, &wait);
-                       /* see if a signal did it */
-                       if (signal_pending(current))
-                               return -ERESTARTSYS;
-
-                       if (port->serial->disconnected)
-                               return -EIO;
-
-                       cnow = edge_port->icount;
-                       if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
-                           cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
-                               return -EIO; /* no change => error */
-                       if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
-                           ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
-                           ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
-                           ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
-                               return 0;
-                       }
-                       cprev = cnow;
-               }
-               /* NOTREACHED */
-               break;
-
        }
        return -ENOIOCTLCMD;
 }
@@ -1866,7 +1802,7 @@ static void process_rcvd_data(struct edgeport_serial *edge_serial,
                                                edge_serial->rxPort);
                                        edge_tty_recv(edge_port->port, buffer,
                                                        rxLen);
-                                       edge_port->icount.rx += rxLen;
+                                       edge_port->port->icount.rx += rxLen;
                                }
                                buffer += rxLen;
                        }
@@ -2042,7 +1978,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 newMsr)
 
        if (newMsr & (EDGEPORT_MSR_DELTA_CTS | EDGEPORT_MSR_DELTA_DSR |
                        EDGEPORT_MSR_DELTA_RI | EDGEPORT_MSR_DELTA_CD)) {
-               icount = &edge_port->icount;
+               icount = &edge_port->port->icount;
 
                /* update input line counters */
                if (newMsr & EDGEPORT_MSR_DELTA_CTS)
@@ -2053,7 +1989,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 newMsr)
                        icount->dcd++;
                if (newMsr & EDGEPORT_MSR_DELTA_RI)
                        icount->rng++;
-               wake_up_interruptible(&edge_port->port->delta_msr_wait);
+               wake_up_interruptible(&edge_port->port->port.delta_msr_wait);
        }
 
        /* Save the new modem status */
@@ -2088,7 +2024,7 @@ static void handle_new_lsr(struct edgeport_port *edge_port, __u8 lsrData,
                edge_tty_recv(edge_port->port, &data, 1);
 
        /* update input line counters */
-       icount = &edge_port->icount;
+       icount = &edge_port->port->icount;
        if (newLsr & LSR_BREAK)
                icount->brk++;
        if (newLsr & LSR_OVER_ERR)
index 1511dd0ad3242650e6da605d316b2d7165b1fb2d..ae5fac5656c90f7d8e15d820c643c954de415242 100644 (file)
@@ -116,7 +116,8 @@ static struct usb_serial_driver edgeport_2port_device = {
        .set_termios            = edge_set_termios,
        .tiocmget               = edge_tiocmget,
        .tiocmset               = edge_tiocmset,
-       .get_icount             = edge_get_icount,
+       .tiocmiwait             = usb_serial_generic_tiocmiwait,
+       .get_icount             = usb_serial_generic_get_icount,
        .write                  = edge_write,
        .write_room             = edge_write_room,
        .chars_in_buffer        = edge_chars_in_buffer,
@@ -147,7 +148,8 @@ static struct usb_serial_driver edgeport_4port_device = {
        .set_termios            = edge_set_termios,
        .tiocmget               = edge_tiocmget,
        .tiocmset               = edge_tiocmset,
-       .get_icount             = edge_get_icount,
+       .tiocmiwait             = usb_serial_generic_tiocmiwait,
+       .get_icount             = usb_serial_generic_get_icount,
        .write                  = edge_write,
        .write_room             = edge_write_room,
        .chars_in_buffer        = edge_chars_in_buffer,
@@ -178,7 +180,8 @@ static struct usb_serial_driver edgeport_8port_device = {
        .set_termios            = edge_set_termios,
        .tiocmget               = edge_tiocmget,
        .tiocmset               = edge_tiocmset,
-       .get_icount             = edge_get_icount,
+       .tiocmiwait             = usb_serial_generic_tiocmiwait,
+       .get_icount             = usb_serial_generic_get_icount,
        .write                  = edge_write,
        .write_room             = edge_write_room,
        .chars_in_buffer        = edge_chars_in_buffer,
@@ -209,7 +212,8 @@ static struct usb_serial_driver epic_device = {
        .set_termios            = edge_set_termios,
        .tiocmget               = edge_tiocmget,
        .tiocmset               = edge_tiocmset,
-       .get_icount             = edge_get_icount,
+       .tiocmiwait             = usb_serial_generic_tiocmiwait,
+       .get_icount             = usb_serial_generic_get_icount,
        .write                  = edge_write,
        .write_room             = edge_write_room,
        .chars_in_buffer        = edge_chars_in_buffer,
index 7777172206de1b42a971acb0747d97180230d670..0ccc4225d593cab86b79a1894dd1b99bddcc4118 100644 (file)
@@ -86,7 +86,7 @@ struct edgeport_port {
        int baud_rate;
        int close_pending;
        int lsr_event;
-       struct async_icount     icount;
+
        struct edgeport_serial  *edge_serial;
        struct usb_serial_port  *port;
        __u8 bUartMode;         /* Port type, 0: RS232, etc. */
@@ -1445,7 +1445,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr)
 
        if (msr & (EDGEPORT_MSR_DELTA_CTS | EDGEPORT_MSR_DELTA_DSR |
                        EDGEPORT_MSR_DELTA_RI | EDGEPORT_MSR_DELTA_CD)) {
-               icount = &edge_port->icount;
+               icount = &edge_port->port->icount;
 
                /* update input line counters */
                if (msr & EDGEPORT_MSR_DELTA_CTS)
@@ -1456,7 +1456,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr)
                        icount->dcd++;
                if (msr & EDGEPORT_MSR_DELTA_RI)
                        icount->rng++;
-               wake_up_interruptible(&edge_port->port->delta_msr_wait);
+               wake_up_interruptible(&edge_port->port->port.delta_msr_wait);
        }
 
        /* Save the new modem status */
@@ -1498,7 +1498,7 @@ static void handle_new_lsr(struct edgeport_port *edge_port, int lsr_data,
                edge_tty_recv(edge_port->port, &data, 1);
 
        /* update input line counters */
-       icount = &edge_port->icount;
+       icount = &edge_port->port->icount;
        if (new_lsr & LSR_BREAK)
                icount->brk++;
        if (new_lsr & LSR_OVER_ERR)
@@ -1657,7 +1657,7 @@ static void edge_bulk_in_callback(struct urb *urb)
                else
                        edge_tty_recv(edge_port->port, data,
                                        urb->actual_length);
-               edge_port->icount.rx += urb->actual_length;
+               edge_port->port->icount.rx += urb->actual_length;
        }
 
 exit:
@@ -1750,8 +1750,6 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port)
 
        dev = port->serial->dev;
 
-       memset(&(edge_port->icount), 0x00, sizeof(edge_port->icount));
-
        /* turn off loopback */
        status = ti_do_config(edge_port, UMPC_SET_CLR_LOOPBACK, 0);
        if (status) {
@@ -1909,21 +1907,10 @@ static void edge_close(struct usb_serial_port *port)
        kfifo_reset_out(&edge_port->write_fifo);
        spin_unlock_irqrestore(&edge_port->ep_lock, flags);
 
-       /* assuming we can still talk to the device,
-        * send a close port command to it */
        dev_dbg(&port->dev, "%s - send umpc_close_port\n", __func__);
        port_number = port->number - port->serial->minor;
-
-       mutex_lock(&serial->disc_mutex);
-       if (!serial->disconnected) {
-               send_cmd(serial->dev,
-                                    UMPC_CLOSE_PORT,
-                                    (__u8)(UMPM_UART1_PORT + port_number),
-                                    0,
-                                    NULL,
-                                    0);
-       }
-       mutex_unlock(&serial->disc_mutex);
+       send_cmd(serial->dev, UMPC_CLOSE_PORT,
+                    (__u8)(UMPM_UART1_PORT + port_number), 0, NULL, 0);
 
        mutex_lock(&edge_serial->es_lock);
        --edge_port->edge_serial->num_ports_open;
@@ -1999,7 +1986,7 @@ static void edge_send(struct tty_struct *tty)
                edge_port->ep_write_urb_in_use = 0;
                /* TODO: reschedule edge_send */
        } else
-               edge_port->icount.tx += count;
+               edge_port->port->icount.tx += count;
 
        /* wakeup any process waiting for writes to complete */
        /* there is now more room in the buffer for new writes */
@@ -2360,27 +2347,6 @@ static int edge_tiocmget(struct tty_struct *tty)
        return result;
 }
 
-static int edge_get_icount(struct tty_struct *tty,
-                               struct serial_icounter_struct *icount)
-{
-       struct usb_serial_port *port = tty->driver_data;
-       struct edgeport_port *edge_port = usb_get_serial_port_data(port);
-       struct async_icount *ic = &edge_port->icount;
-
-       icount->cts = ic->cts;
-       icount->dsr = ic->dsr;
-       icount->rng = ic->rng;
-       icount->dcd = ic->dcd;
-       icount->tx = ic->tx;
-        icount->rx = ic->rx;
-        icount->frame = ic->frame;
-        icount->parity = ic->parity;
-        icount->overrun = ic->overrun;
-        icount->brk = ic->brk;
-        icount->buf_overrun = ic->buf_overrun;
-       return 0;
-}
-
 static int get_serial_info(struct edgeport_port *edge_port,
                                struct serial_struct __user *retinfo)
 {
@@ -2416,8 +2382,6 @@ static int edge_ioctl(struct tty_struct *tty,
 {
        struct usb_serial_port *port = tty->driver_data;
        struct edgeport_port *edge_port = usb_get_serial_port_data(port);
-       struct async_icount cnow;
-       struct async_icount cprev;
 
        dev_dbg(&port->dev, "%s - port %d, cmd = 0x%x\n", __func__, port->number, cmd);
 
@@ -2426,32 +2390,6 @@ static int edge_ioctl(struct tty_struct *tty,
                dev_dbg(&port->dev, "%s - TIOCGSERIAL\n", __func__);
                return get_serial_info(edge_port,
                                (struct serial_struct __user *) arg);
-       case TIOCMIWAIT:
-               dev_dbg(&port->dev, "%s - TIOCMIWAIT\n", __func__);
-               cprev = edge_port->icount;
-               while (1) {
-                       interruptible_sleep_on(&port->delta_msr_wait);
-                       /* see if a signal did it */
-                       if (signal_pending(current))
-                               return -ERESTARTSYS;
-
-                       if (port->serial->disconnected)
-                               return -EIO;
-
-                       cnow = edge_port->icount;
-                       if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
-                           cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
-                               return -EIO; /* no change => error */
-                       if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
-                           ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
-                           ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
-                           ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
-                               return 0;
-                       }
-                       cprev = cnow;
-               }
-               /* not reached */
-               break;
        }
        return -ENOIOCTLCMD;
 }
@@ -2546,7 +2484,6 @@ static int edge_port_remove(struct usb_serial_port *port)
        struct edgeport_port *edge_port;
 
        edge_port = usb_get_serial_port_data(port);
-
        edge_remove_sysfs_attrs(port);
        kfifo_free(&edge_port->write_fifo);
        kfree(edge_port);
@@ -2618,7 +2555,8 @@ static struct usb_serial_driver edgeport_1port_device = {
        .set_termios            = edge_set_termios,
        .tiocmget               = edge_tiocmget,
        .tiocmset               = edge_tiocmset,
-       .get_icount             = edge_get_icount,
+       .tiocmiwait             = usb_serial_generic_tiocmiwait,
+       .get_icount             = usb_serial_generic_get_icount,
        .write                  = edge_write,
        .write_room             = edge_write_room,
        .chars_in_buffer        = edge_chars_in_buffer,
@@ -2649,7 +2587,8 @@ static struct usb_serial_driver edgeport_2port_device = {
        .set_termios            = edge_set_termios,
        .tiocmget               = edge_tiocmget,
        .tiocmset               = edge_tiocmset,
-       .get_icount             = edge_get_icount,
+       .tiocmiwait             = usb_serial_generic_tiocmiwait,
+       .get_icount             = usb_serial_generic_get_icount,
        .write                  = edge_write,
        .write_room             = edge_write_room,
        .chars_in_buffer        = edge_chars_in_buffer,
index ff77027160aab7eca0ac78e4f78ae1c8e7f01877..9d74c278b7b58d5f9ce6878d35d5ff66d869a5cf 100644 (file)
@@ -55,7 +55,6 @@ static void read_rxcmd_callback(struct urb *urb);
 
 struct iuu_private {
        spinlock_t lock;        /* store irq state */
-       wait_queue_head_t delta_msr_wait;
        u8 line_status;
        int tiostatus;          /* store IUART SIGNAL for tiocmget call */
        u8 reset;               /* if 1 reset is needed */
@@ -94,7 +93,6 @@ static int iuu_port_probe(struct usb_serial_port *port)
 
        priv->vcc = vcc_default;
        spin_lock_init(&priv->lock);
-       init_waitqueue_head(&priv->delta_msr_wait);
 
        usb_set_serial_port_data(port, priv);
 
@@ -944,22 +942,13 @@ static void iuu_set_termios(struct tty_struct *tty,
 static void iuu_close(struct usb_serial_port *port)
 {
        /* iuu_led (port,255,0,0,0); */
-       struct usb_serial *serial;
-
-       serial = port->serial;
-       if (!serial)
-               return;
 
        iuu_uart_off(port);
-       if (serial->dev) {
-               /* free writebuf */
-               /* shutdown our urbs */
-               dev_dbg(&port->dev, "%s - shutting down urbs\n", __func__);
-               usb_kill_urb(port->write_urb);
-               usb_kill_urb(port->read_urb);
-               usb_kill_urb(port->interrupt_in_urb);
-               iuu_led(port, 0, 0, 0xF000, 0xFF);
-       }
+
+       usb_kill_urb(port->write_urb);
+       usb_kill_urb(port->read_urb);
+
+       iuu_led(port, 0, 0, 0xF000, 0xFF);
 }
 
 static void iuu_init_termios(struct tty_struct *tty)
index 1fd1935c8316f525e5795c22fa0dada0093b6be9..6abe8a4fee0ee2baf569e51b5c98ee7a86e711e4 100644 (file)
@@ -1115,7 +1115,6 @@ static void keyspan_dtr_rts(struct usb_serial_port *port, int on)
 static void keyspan_close(struct usb_serial_port *port)
 {
        int                     i;
-       struct usb_serial       *serial = port->serial;
        struct keyspan_port_private     *p_priv;
 
        p_priv = usb_get_serial_port_data(port);
@@ -1123,28 +1122,17 @@ static void keyspan_close(struct usb_serial_port *port)
        p_priv->rts_state = 0;
        p_priv->dtr_state = 0;
 
-       if (serial->dev) {
-               keyspan_send_setup(port, 2);
-               /* pilot-xfer seems to work best with this delay */
-               mdelay(100);
-               /* keyspan_set_termios(port, NULL); */
-       }
-
-       /*while (p_priv->outcont_urb->status == -EINPROGRESS) {
-               dev_dbg(&port->dev, "%s - urb in progress\n", __func__);
-       }*/
+       keyspan_send_setup(port, 2);
+       /* pilot-xfer seems to work best with this delay */
+       mdelay(100);
 
        p_priv->out_flip = 0;
        p_priv->in_flip = 0;
 
-       if (serial->dev) {
-               /* Stop reading/writing urbs */
-               stop_urb(p_priv->inack_urb);
-               /* stop_urb(p_priv->outcont_urb); */
-               for (i = 0; i < 2; i++) {
-                       stop_urb(p_priv->in_urbs[i]);
-                       stop_urb(p_priv->out_urbs[i]);
-               }
+       stop_urb(p_priv->inack_urb);
+       for (i = 0; i < 2; i++) {
+               stop_urb(p_priv->in_urbs[i]);
+               stop_urb(p_priv->out_urbs[i]);
        }
 }
 
index 3b17d5d13dc86aa8fa9ebe8b6a290572c57a6323..da3b29eb605ca2c8fc249b799b8e23d3d0473592 100644 (file)
@@ -595,12 +595,10 @@ static void keyspan_pda_dtr_rts(struct usb_serial_port *port, int on)
 {
        struct usb_serial *serial = port->serial;
 
-       if (serial->dev) {
-               if (on)
-                       keyspan_pda_set_modem_info(serial, (1<<7) | (1<< 2));
-               else
-                       keyspan_pda_set_modem_info(serial, 0);
-       }
+       if (on)
+               keyspan_pda_set_modem_info(serial, (1 << 7) | (1 << 2));
+       else
+               keyspan_pda_set_modem_info(serial, 0);
 }
 
 
@@ -651,13 +649,8 @@ error:
 }
 static void keyspan_pda_close(struct usb_serial_port *port)
 {
-       struct usb_serial *serial = port->serial;
-
-       if (serial->dev) {
-               /* shutdown our bulk reads and writes */
-               usb_kill_urb(port->write_urb);
-               usb_kill_urb(port->interrupt_in_urb);
-       }
+       usb_kill_urb(port->write_urb);
+       usb_kill_urb(port->interrupt_in_urb);
 }
 
 
index 769d910ae0a5d789cf933659867fee715fc6be8a..1b4054fe52a5fccf85d4be4cbe4cbb3b30ff03b7 100644 (file)
@@ -341,28 +341,20 @@ static void klsi_105_close(struct usb_serial_port *port)
 {
        int rc;
 
-       mutex_lock(&port->serial->disc_mutex);
-       if (!port->serial->disconnected) {
-               /* send READ_OFF */
-               rc = usb_control_msg(port->serial->dev,
-                                    usb_sndctrlpipe(port->serial->dev, 0),
-                                    KL5KUSB105A_SIO_CONFIGURE,
-                                    USB_TYPE_VENDOR | USB_DIR_OUT,
-                                    KL5KUSB105A_SIO_CONFIGURE_READ_OFF,
-                                    0, /* index */
-                                    NULL, 0,
-                                    KLSI_TIMEOUT);
-               if (rc < 0)
-                       dev_err(&port->dev,
-                               "Disabling read failed (error = %d)\n", rc);
-       }
-       mutex_unlock(&port->serial->disc_mutex);
+       /* send READ_OFF */
+       rc = usb_control_msg(port->serial->dev,
+                            usb_sndctrlpipe(port->serial->dev, 0),
+                            KL5KUSB105A_SIO_CONFIGURE,
+                            USB_TYPE_VENDOR | USB_DIR_OUT,
+                            KL5KUSB105A_SIO_CONFIGURE_READ_OFF,
+                            0, /* index */
+                            NULL, 0,
+                            KLSI_TIMEOUT);
+       if (rc < 0)
+               dev_err(&port->dev, "failed to disable read: %d\n", rc);
 
        /* shutdown our bulk reads and writes */
        usb_serial_generic_close(port);
-
-       /* wgg - do I need this? I think so. */
-       usb_kill_urb(port->interrupt_in_urb);
 }
 
 /* We need to write a complete 64-byte data block and encode the
index 06d5a60be2c4cb87279744372edef4a41864b74b..3353c9ed7721a7b2fb49bc3b5ff7595cc6107a15 100644 (file)
@@ -35,7 +35,6 @@
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
 #include <linux/serial.h>
-#include <linux/ioctl.h>
 #include "mct_u232.h"
 
 #define DRIVER_AUTHOR "Wolfgang Grandegger <wolfgang@ces.ch>"
@@ -57,10 +56,6 @@ static void mct_u232_break_ctl(struct tty_struct *tty, int break_state);
 static int  mct_u232_tiocmget(struct tty_struct *tty);
 static int  mct_u232_tiocmset(struct tty_struct *tty,
                        unsigned int set, unsigned int clear);
-static int  mct_u232_ioctl(struct tty_struct *tty,
-                       unsigned int cmd, unsigned long arg);
-static int  mct_u232_get_icount(struct tty_struct *tty,
-                       struct serial_icounter_struct *icount);
 static void mct_u232_throttle(struct tty_struct *tty);
 static void mct_u232_unthrottle(struct tty_struct *tty);
 
@@ -95,11 +90,11 @@ static struct usb_serial_driver mct_u232_device = {
        .break_ctl =         mct_u232_break_ctl,
        .tiocmget =          mct_u232_tiocmget,
        .tiocmset =          mct_u232_tiocmset,
+       .tiocmiwait =        usb_serial_generic_tiocmiwait,
        .attach =            mct_u232_startup,
        .port_probe =        mct_u232_port_probe,
        .port_remove =       mct_u232_port_remove,
-       .ioctl =             mct_u232_ioctl,
-       .get_icount =        mct_u232_get_icount,
+       .get_icount =        usb_serial_generic_get_icount,
 };
 
 static struct usb_serial_driver * const serial_drivers[] = {
@@ -113,7 +108,6 @@ struct mct_u232_private {
        unsigned char        last_lsr;      /* Line Status Register */
        unsigned char        last_msr;      /* Modem Status Register */
        unsigned int         rx_flags;      /* Throttling flags */
-       struct async_icount  icount;
 };
 
 #define THROTTLED              0x01
@@ -570,7 +564,7 @@ static void mct_u232_read_int_callback(struct urb *urb)
        /* Record Control Line states */
        mct_u232_msr_to_state(port, &priv->control_state, priv->last_msr);
 
-       mct_u232_msr_to_icount(&priv->icount, priv->last_msr);
+       mct_u232_msr_to_icount(&port->icount, priv->last_msr);
 
 #if 0
        /* Not yet handled. See belkin_sa.c for further information */
@@ -598,7 +592,7 @@ static void mct_u232_read_int_callback(struct urb *urb)
                tty_kref_put(tty);
        }
 #endif
-       wake_up_interruptible(&port->delta_msr_wait);
+       wake_up_interruptible(&port->port.delta_msr_wait);
        spin_unlock_irqrestore(&priv->lock, flags);
 exit:
        retval = usb_submit_urb(urb, GFP_ATOMIC);
@@ -786,86 +780,6 @@ static void mct_u232_unthrottle(struct tty_struct *tty)
        }
 }
 
-static int  mct_u232_ioctl(struct tty_struct *tty,
-                       unsigned int cmd, unsigned long arg)
-{
-       DEFINE_WAIT(wait);
-       struct usb_serial_port *port = tty->driver_data;
-       struct mct_u232_private *mct_u232_port = usb_get_serial_port_data(port);
-       struct async_icount cnow, cprev;
-       unsigned long flags;
-
-       dev_dbg(&port->dev, "%s - cmd = 0x%x\n", __func__, cmd);
-
-       switch (cmd) {
-
-       case TIOCMIWAIT:
-
-               dev_dbg(&port->dev, "%s TIOCMIWAIT", __func__);
-
-               spin_lock_irqsave(&mct_u232_port->lock, flags);
-               cprev = mct_u232_port->icount;
-               spin_unlock_irqrestore(&mct_u232_port->lock, flags);
-               for ( ; ; ) {
-                       prepare_to_wait(&port->delta_msr_wait,
-                                       &wait, TASK_INTERRUPTIBLE);
-                       schedule();
-                       finish_wait(&port->delta_msr_wait, &wait);
-                       /* see if a signal did it */
-                       if (signal_pending(current))
-                               return -ERESTARTSYS;
-
-                       if (port->serial->disconnected)
-                               return -EIO;
-
-                       spin_lock_irqsave(&mct_u232_port->lock, flags);
-                       cnow = mct_u232_port->icount;
-                       spin_unlock_irqrestore(&mct_u232_port->lock, flags);
-                       if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
-                           cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
-                               return -EIO; /* no change => error */
-                       if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
-                           ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
-                           ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
-                           ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
-                               return 0;
-                       }
-                       cprev = cnow;
-               }
-
-       }
-       return -ENOIOCTLCMD;
-}
-
-static int  mct_u232_get_icount(struct tty_struct *tty,
-                       struct serial_icounter_struct *icount)
-{
-       struct usb_serial_port *port = tty->driver_data;
-       struct mct_u232_private *mct_u232_port = usb_get_serial_port_data(port);
-       struct async_icount *ic = &mct_u232_port->icount;
-       unsigned long flags;
-
-       spin_lock_irqsave(&mct_u232_port->lock, flags);
-
-       icount->cts = ic->cts;
-       icount->dsr = ic->dsr;
-       icount->rng = ic->rng;
-       icount->dcd = ic->dcd;
-       icount->rx = ic->rx;
-       icount->tx = ic->tx;
-       icount->frame = ic->frame;
-       icount->overrun = ic->overrun;
-       icount->parity = ic->parity;
-       icount->brk = ic->brk;
-       icount->buf_overrun = ic->buf_overrun;
-
-       spin_unlock_irqrestore(&mct_u232_port->lock, flags);
-
-       dev_dbg(&port->dev, "%s TIOCGICOUNT RX=%d, TX=%d\n",
-               __func__,  icount->rx, icount->tx);
-       return 0;
-}
-
 module_usb_serial_driver(serial_drivers, id_table);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
index bf3c7a23553efbe73d1c12b4e7b910d506fed474..47e247759eb0ed975ddcca6482b34080525397d3 100644 (file)
@@ -177,10 +177,7 @@ static void metrousb_cleanup(struct usb_serial_port *port)
        usb_unlink_urb(port->interrupt_in_urb);
        usb_kill_urb(port->interrupt_in_urb);
 
-       mutex_lock(&port->serial->disc_mutex);
-       if (!port->serial->disconnected)
-               metrousb_send_unidirectional_cmd(UNI_CMD_CLOSE, port);
-       mutex_unlock(&port->serial->disc_mutex);
+       metrousb_send_unidirectional_cmd(UNI_CMD_CLOSE, port);
 }
 
 static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port)
index e0ebec3b5d6ae077aa4ac0347e8a33470f8dc6c3..fc506bb71315d97a2273c81324d48d57c549a629 100644 (file)
@@ -62,7 +62,6 @@ struct moschip_port {
        __u8    shadowMCR;              /* last MCR value received */
        __u8    shadowMSR;              /* last MSR value received */
        char                    open;
-       struct async_icount     icount;
        struct usb_serial_port  *port;  /* loop back to the owner */
        struct urb              *write_urb_pool[NUM_URBS];
 };
@@ -1075,9 +1074,6 @@ static int mos7720_open(struct tty_struct *tty, struct usb_serial_port *port)
                dev_err(&port->dev, "%s - Error %d submitting read urb\n",
                                                        __func__, response);
 
-       /* initialize our icount structure */
-       memset(&(mos7720_port->icount), 0x00, sizeof(mos7720_port->icount));
-
        /* initialize our port settings */
        mos7720_port->shadowMCR = UART_MCR_OUT2; /* Must set to enable ints! */
 
@@ -1144,16 +1140,9 @@ static void mos7720_close(struct usb_serial_port *port)
        usb_kill_urb(port->write_urb);
        usb_kill_urb(port->read_urb);
 
-       mutex_lock(&serial->disc_mutex);
-       /* these commands must not be issued if the device has
-        * been disconnected */
-       if (!serial->disconnected) {
-               write_mos_reg(serial, port->number - port->serial->minor,
-                             MCR, 0x00);
-               write_mos_reg(serial, port->number - port->serial->minor,
-                             IER, 0x00);
-       }
-       mutex_unlock(&serial->disc_mutex);
+       write_mos_reg(serial, port->number - port->serial->minor, MCR, 0x00);
+       write_mos_reg(serial, port->number - port->serial->minor, IER, 0x00);
+
        mos7720_port->open = 0;
 }
 
@@ -1803,33 +1792,6 @@ static int mos7720_tiocmset(struct tty_struct *tty,
        return 0;
 }
 
-static int mos7720_get_icount(struct tty_struct *tty,
-                               struct serial_icounter_struct *icount)
-{
-       struct usb_serial_port *port = tty->driver_data;
-       struct moschip_port *mos7720_port;
-       struct async_icount cnow;
-
-       mos7720_port = usb_get_serial_port_data(port);
-       cnow = mos7720_port->icount;
-
-       icount->cts = cnow.cts;
-       icount->dsr = cnow.dsr;
-       icount->rng = cnow.rng;
-       icount->dcd = cnow.dcd;
-       icount->rx = cnow.rx;
-       icount->tx = cnow.tx;
-       icount->frame = cnow.frame;
-       icount->overrun = cnow.overrun;
-       icount->parity = cnow.parity;
-       icount->brk = cnow.brk;
-       icount->buf_overrun = cnow.buf_overrun;
-
-       dev_dbg(&port->dev, "%s TIOCGICOUNT RX=%d, TX=%d\n", __func__,
-               icount->rx, icount->tx);
-       return 0;
-}
-
 static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd,
                          unsigned int __user *value)
 {
@@ -1905,8 +1867,6 @@ static int mos7720_ioctl(struct tty_struct *tty,
 {
        struct usb_serial_port *port = tty->driver_data;
        struct moschip_port *mos7720_port;
-       struct async_icount cnow;
-       struct async_icount cprev;
 
        mos7720_port = usb_get_serial_port_data(port);
        if (mos7720_port == NULL)
@@ -1931,27 +1891,6 @@ static int mos7720_ioctl(struct tty_struct *tty,
                dev_dbg(&port->dev, "%s TIOCGSERIAL\n", __func__);
                return get_serial_info(mos7720_port,
                                       (struct serial_struct __user *)arg);
-
-       case TIOCMIWAIT:
-               dev_dbg(&port->dev, "%s TIOCMIWAIT\n", __func__);
-               cprev = mos7720_port->icount;
-               while (1) {
-                       if (signal_pending(current))
-                               return -ERESTARTSYS;
-                       cnow = mos7720_port->icount;
-                       if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
-                           cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
-                               return -EIO; /* no change => error */
-                       if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
-                           ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
-                           ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
-                           ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
-                               return 0;
-                       }
-                       cprev = cnow;
-               }
-               /* NOTREACHED */
-               break;
        }
 
        return -ENOIOCTLCMD;
@@ -2107,7 +2046,6 @@ static struct usb_serial_driver moschip7720_2port_driver = {
        .ioctl                  = mos7720_ioctl,
        .tiocmget               = mos7720_tiocmget,
        .tiocmset               = mos7720_tiocmset,
-       .get_icount             = mos7720_get_icount,
        .set_termios            = mos7720_set_termios,
        .write                  = mos7720_write,
        .write_room             = mos7720_write_room,
index b8051fa61911a54a23de8f9a1662518181b6c084..f0b4e5c01e13ab4b1914499971266b6d0f110fed 100644 (file)
@@ -219,8 +219,6 @@ struct moschip_port {
        char open;
        char open_ports;
        wait_queue_head_t wait_chase;   /* for handling sleeping while waiting for chase to finish */
-       int delta_msr_cond;
-       struct async_icount icount;
        struct usb_serial_port *port;   /* loop back to the owner of this object */
 
        /* Offsets */
@@ -399,32 +397,22 @@ static void mos7840_handle_new_msr(struct moschip_port *port, __u8 new_msr)
        struct moschip_port *mos7840_port;
        struct async_icount *icount;
        mos7840_port = port;
-       icount = &mos7840_port->icount;
        if (new_msr &
            (MOS_MSR_DELTA_CTS | MOS_MSR_DELTA_DSR | MOS_MSR_DELTA_RI |
             MOS_MSR_DELTA_CD)) {
-               icount = &mos7840_port->icount;
+               icount = &mos7840_port->port->icount;
 
                /* update input line counters */
-               if (new_msr & MOS_MSR_DELTA_CTS) {
+               if (new_msr & MOS_MSR_DELTA_CTS)
                        icount->cts++;
-                       smp_wmb();
-               }
-               if (new_msr & MOS_MSR_DELTA_DSR) {
+               if (new_msr & MOS_MSR_DELTA_DSR)
                        icount->dsr++;
-                       smp_wmb();
-               }
-               if (new_msr & MOS_MSR_DELTA_CD) {
+               if (new_msr & MOS_MSR_DELTA_CD)
                        icount->dcd++;
-                       smp_wmb();
-               }
-               if (new_msr & MOS_MSR_DELTA_RI) {
+               if (new_msr & MOS_MSR_DELTA_RI)
                        icount->rng++;
-                       smp_wmb();
-               }
 
-               mos7840_port->delta_msr_cond = 1;
-               wake_up_interruptible(&port->port->delta_msr_wait);
+               wake_up_interruptible(&port->port->port.delta_msr_wait);
        }
 }
 
@@ -442,23 +430,15 @@ static void mos7840_handle_new_lsr(struct moschip_port *port, __u8 new_lsr)
        }
 
        /* update input line counters */
-       icount = &port->icount;
-       if (new_lsr & SERIAL_LSR_BI) {
+       icount = &port->port->icount;
+       if (new_lsr & SERIAL_LSR_BI)
                icount->brk++;
-               smp_wmb();
-       }
-       if (new_lsr & SERIAL_LSR_OE) {
+       if (new_lsr & SERIAL_LSR_OE)
                icount->overrun++;
-               smp_wmb();
-       }
-       if (new_lsr & SERIAL_LSR_PE) {
+       if (new_lsr & SERIAL_LSR_PE)
                icount->parity++;
-               smp_wmb();
-       }
-       if (new_lsr & SERIAL_LSR_FE) {
+       if (new_lsr & SERIAL_LSR_FE)
                icount->frame++;
-               smp_wmb();
-       }
 }
 
 /************************************************************************/
@@ -777,9 +757,8 @@ static void mos7840_bulk_in_callback(struct urb *urb)
                struct tty_port *tport = &mos7840_port->port->port;
                tty_insert_flip_string(tport, data, urb->actual_length);
                tty_flip_buffer_push(tport);
-               mos7840_port->icount.rx += urb->actual_length;
-               smp_wmb();
-               dev_dbg(&port->dev, "mos7840_port->icount.rx is %d:\n", mos7840_port->icount.rx);
+               port->icount.rx += urb->actual_length;
+               dev_dbg(&port->dev, "icount.rx is %d:\n", port->icount.rx);
        }
 
        if (!mos7840_port->read_urb) {
@@ -1130,17 +1109,12 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)
        /* initialize our wait queues */
        init_waitqueue_head(&mos7840_port->wait_chase);
 
-       /* initialize our icount structure */
-       memset(&(mos7840_port->icount), 0x00, sizeof(mos7840_port->icount));
-
        /* initialize our port settings */
        /* Must set to enable ints! */
        mos7840_port->shadowMCR = MCR_MASTER_IE;
        /* send a open port command */
        mos7840_port->open = 1;
        /* mos7840_change_port_settings(mos7840_port,old_termios); */
-       mos7840_port->icount.tx = 0;
-       mos7840_port->icount.rx = 0;
 
        return 0;
 }
@@ -1223,25 +1197,10 @@ static void mos7840_close(struct usb_serial_port *port)
                }
        }
 
-       /* While closing port, shutdown all bulk read, write  *
-        * and interrupt read if they exists                  */
-       if (serial->dev) {
-               if (mos7840_port->write_urb) {
-                       dev_dbg(&port->dev, "%s", "Shutdown bulk write\n");
-                       usb_kill_urb(mos7840_port->write_urb);
-               }
-               if (mos7840_port->read_urb) {
-                       dev_dbg(&port->dev, "%s", "Shutdown bulk read\n");
-                       usb_kill_urb(mos7840_port->read_urb);
-                       mos7840_port->read_urb_busy = false;
-               }
-               if ((&mos7840_port->control_urb)) {
-                       dev_dbg(&port->dev, "%s", "Shutdown control read\n");
-                       /*/      usb_kill_urb (mos7840_port->control_urb); */
-               }
-       }
-/*      if(mos7840_port->ctrl_buf != NULL) */
-/*              kfree(mos7840_port->ctrl_buf); */
+       usb_kill_urb(mos7840_port->write_urb);
+       usb_kill_urb(mos7840_port->read_urb);
+       mos7840_port->read_urb_busy = false;
+
        port0->open_ports--;
        dev_dbg(&port->dev, "%s in close%d:in port%d\n", __func__, port0->open_ports, port->number);
        if (port0->open_ports == 0) {
@@ -1253,8 +1212,7 @@ static void mos7840_close(struct usb_serial_port *port)
 
        if (mos7840_port->write_urb) {
                /* if this urb had a transfer buffer already (old tx) free it */
-               if (mos7840_port->write_urb->transfer_buffer != NULL)
-                       kfree(mos7840_port->write_urb->transfer_buffer);
+               kfree(mos7840_port->write_urb->transfer_buffer);
                usb_free_urb(mos7840_port->write_urb);
        }
 
@@ -1331,9 +1289,8 @@ static void mos7840_break(struct tty_struct *tty, int break_state)
        if (mos7840_port == NULL)
                return;
 
-       if (serial->dev)
-               /* flush and block until tx is empty */
-               mos7840_block_until_chase_response(tty, mos7840_port);
+       /* flush and block until tx is empty */
+       mos7840_block_until_chase_response(tty, mos7840_port);
 
        if (break_state == -1)
                data = mos7840_port->shadowLCR | LCR_SET_BREAK;
@@ -1523,9 +1480,8 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port,
                goto exit;
        }
        bytes_sent = transfer_size;
-       mos7840_port->icount.tx += transfer_size;
-       smp_wmb();
-       dev_dbg(&port->dev, "mos7840_port->icount.tx is %d:\n", mos7840_port->icount.tx);
+       port->icount.tx += transfer_size;
+       dev_dbg(&port->dev, "icount.tx is %d:\n", port->icount.tx);
 exit:
        return bytes_sent;
 
@@ -2144,34 +2100,6 @@ static int mos7840_get_serial_info(struct moschip_port *mos7840_port,
        return 0;
 }
 
-static int mos7840_get_icount(struct tty_struct *tty,
-                       struct serial_icounter_struct *icount)
-{
-       struct usb_serial_port *port = tty->driver_data;
-       struct moschip_port *mos7840_port;
-       struct async_icount cnow;
-
-       mos7840_port = mos7840_get_port_private(port);
-       cnow = mos7840_port->icount;
-
-       smp_rmb();
-       icount->cts = cnow.cts;
-       icount->dsr = cnow.dsr;
-       icount->rng = cnow.rng;
-       icount->dcd = cnow.dcd;
-       icount->rx = cnow.rx;
-       icount->tx = cnow.tx;
-       icount->frame = cnow.frame;
-       icount->overrun = cnow.overrun;
-       icount->parity = cnow.parity;
-       icount->brk = cnow.brk;
-       icount->buf_overrun = cnow.buf_overrun;
-
-       dev_dbg(&port->dev, "%s TIOCGICOUNT RX=%d, TX=%d\n", __func__,
-               icount->rx, icount->tx);
-       return 0;
-}
-
 /*****************************************************************************
  * SerialIoctl
  *     this function handles any ioctl calls to the driver
@@ -2184,9 +2112,6 @@ static int mos7840_ioctl(struct tty_struct *tty,
        void __user *argp = (void __user *)arg;
        struct moschip_port *mos7840_port;
 
-       struct async_icount cnow;
-       struct async_icount cprev;
-
        if (mos7840_port_paranoia_check(port, __func__))
                return -1;
 
@@ -2211,41 +2136,6 @@ static int mos7840_ioctl(struct tty_struct *tty,
        case TIOCSSERIAL:
                dev_dbg(&port->dev, "%s TIOCSSERIAL\n", __func__);
                break;
-
-       case TIOCMIWAIT:
-               dev_dbg(&port->dev, "%s  TIOCMIWAIT\n", __func__);
-               cprev = mos7840_port->icount;
-               while (1) {
-                       /* interruptible_sleep_on(&mos7840_port->delta_msr_wait); */
-                       mos7840_port->delta_msr_cond = 0;
-                       wait_event_interruptible(port->delta_msr_wait,
-                                                (port->serial->disconnected ||
-                                                 mos7840_port->
-                                                 delta_msr_cond == 1));
-
-                       /* see if a signal did it */
-                       if (signal_pending(current))
-                               return -ERESTARTSYS;
-
-                       if (port->serial->disconnected)
-                               return -EIO;
-
-                       cnow = mos7840_port->icount;
-                       smp_rmb();
-                       if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
-                           cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
-                               return -EIO;    /* no change => error */
-                       if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
-                           ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
-                           ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
-                           ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
-                               return 0;
-                       }
-                       cprev = cnow;
-               }
-               /* NOTREACHED */
-               break;
-
        default:
                break;
        }
@@ -2592,7 +2482,8 @@ static struct usb_serial_driver moschip7840_4port_device = {
        .break_ctl = mos7840_break,
        .tiocmget = mos7840_tiocmget,
        .tiocmset = mos7840_tiocmset,
-       .get_icount = mos7840_get_icount,
+       .tiocmiwait = usb_serial_generic_tiocmiwait,
+       .get_icount = usb_serial_generic_get_icount,
        .port_probe = mos7840_port_probe,
        .port_remove = mos7840_port_remove,
        .read_bulk_callback = mos7840_bulk_in_callback,
index e13e1a4d3e1e0901d09195280ae6f7fd4cf386fc..5f4b0cd0f6e9734193dac84ba23373f13e301d65 100644 (file)
@@ -120,7 +120,10 @@ static int send_control_msg(struct usb_serial_port *port, u8 requesttype,
                                0, 0, buffer, 1, 0);
        kfree(buffer);
 
-       return retval;
+       if (retval < 0)
+               return retval;
+
+       return 0;
 }
 
 static int opticon_open(struct tty_struct *tty, struct usb_serial_port *port)
@@ -306,7 +309,6 @@ static int opticon_tiocmset(struct tty_struct *tty,
                           unsigned int set, unsigned int clear)
 {
        struct usb_serial_port *port = tty->driver_data;
-       struct usb_serial *serial = port->serial;
        struct opticon_private *priv = usb_get_serial_port_data(port);
        unsigned long flags;
        bool rts;
@@ -327,15 +329,11 @@ static int opticon_tiocmset(struct tty_struct *tty,
        if (!changed)
                return 0;
 
-       /* Send the new RTS state to the connected device */
-       mutex_lock(&serial->disc_mutex);
-       if (!serial->disconnected)
-               ret = send_control_msg(port, CONTROL_RTS, !rts);
-       else
-               ret = -ENODEV;
-       mutex_unlock(&serial->disc_mutex);
+       ret = send_control_msg(port, CONTROL_RTS, !rts);
+       if (ret)
+               return usb_translate_errors(ret);
 
-       return ret;
+       return 0;
 }
 
 static int get_serial_info(struct usb_serial_port *port,
index 87c71ccfee87bfd06d41034a52a6e5dc27a21c7f..7e3e0782e51fe48ccb91e3e9e28eb42a380a0932 100644 (file)
@@ -124,8 +124,6 @@ static void oti6858_close(struct usb_serial_port *port);
 static void oti6858_set_termios(struct tty_struct *tty,
                        struct usb_serial_port *port, struct ktermios *old);
 static void oti6858_init_termios(struct tty_struct *tty);
-static int oti6858_ioctl(struct tty_struct *tty,
-                       unsigned int cmd, unsigned long arg);
 static void oti6858_read_int_callback(struct urb *urb);
 static void oti6858_read_bulk_callback(struct urb *urb);
 static void oti6858_write_bulk_callback(struct urb *urb);
@@ -136,6 +134,7 @@ static int oti6858_chars_in_buffer(struct tty_struct *tty);
 static int oti6858_tiocmget(struct tty_struct *tty);
 static int oti6858_tiocmset(struct tty_struct *tty,
                                unsigned int set, unsigned int clear);
+static int oti6858_tiocmiwait(struct tty_struct *tty, unsigned long arg);
 static int oti6858_port_probe(struct usb_serial_port *port);
 static int oti6858_port_remove(struct usb_serial_port *port);
 
@@ -150,11 +149,11 @@ static struct usb_serial_driver oti6858_device = {
        .open =                 oti6858_open,
        .close =                oti6858_close,
        .write =                oti6858_write,
-       .ioctl =                oti6858_ioctl,
        .set_termios =          oti6858_set_termios,
        .init_termios =         oti6858_init_termios,
        .tiocmget =             oti6858_tiocmget,
        .tiocmset =             oti6858_tiocmset,
+       .tiocmiwait =           oti6858_tiocmiwait,
        .read_bulk_callback =   oti6858_read_bulk_callback,
        .read_int_callback =    oti6858_read_int_callback,
        .write_bulk_callback =  oti6858_write_bulk_callback,
@@ -650,8 +649,9 @@ static int oti6858_tiocmget(struct tty_struct *tty)
        return result;
 }
 
-static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
+static int oti6858_tiocmiwait(struct tty_struct *tty, unsigned long arg)
 {
+       struct usb_serial_port *port = tty->driver_data;
        struct oti6858_private *priv = usb_get_serial_port_data(port);
        unsigned long flags;
        unsigned int prev, status;
@@ -662,7 +662,7 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
        spin_unlock_irqrestore(&priv->lock, flags);
 
        while (1) {
-               wait_event_interruptible(port->delta_msr_wait,
+               wait_event_interruptible(port->port.delta_msr_wait,
                                        port->serial->disconnected ||
                                        priv->status.pin_state != prev);
                if (signal_pending(current))
@@ -689,24 +689,6 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
        return 0;
 }
 
-static int oti6858_ioctl(struct tty_struct *tty,
-                       unsigned int cmd, unsigned long arg)
-{
-       struct usb_serial_port *port = tty->driver_data;
-
-       dev_dbg(&port->dev, "%s(cmd = 0x%04x, arg = 0x%08lx)\n", __func__, cmd, arg);
-
-       switch (cmd) {
-       case TIOCMIWAIT:
-               dev_dbg(&port->dev, "%s(): TIOCMIWAIT\n", __func__);
-               return wait_modem_info(port, arg);
-       default:
-               dev_dbg(&port->dev, "%s(): 0x%04x not supported\n", __func__, cmd);
-               break;
-       }
-       return -ENOIOCTLCMD;
-}
-
 static void oti6858_read_int_callback(struct urb *urb)
 {
        struct usb_serial_port *port =  urb->context;
@@ -765,7 +747,7 @@ static void oti6858_read_int_callback(struct urb *urb)
 
                if (!priv->transient) {
                        if (xs->pin_state != priv->status.pin_state)
-                               wake_up_interruptible(&port->delta_msr_wait);
+                               wake_up_interruptible(&port->port.delta_msr_wait);
                        memcpy(&priv->status, xs, OTI6858_CTRL_PKT_SIZE);
                }
 
index 3b10018d89a34e44e03b5ffb5562c34c7e4e6b85..7151659367a0898cec3124e8ee328bf17f57d6bd 100644 (file)
@@ -149,7 +149,7 @@ static int pl2303_vendor_read(__u16 value, __u16 index,
        int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
                        VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,
                        value, index, buf, 1, 100);
-       dev_dbg(&serial->dev->dev, "0x%x:0x%x:0x%x:0x%x  %d - %x\n",
+       dev_dbg(&serial->interface->dev, "0x%x:0x%x:0x%x:0x%x  %d - %x\n",
                VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, value, index,
                res, buf[0]);
        return res;
@@ -161,7 +161,7 @@ static int pl2303_vendor_write(__u16 value, __u16 index,
        int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
                        VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
                        value, index, NULL, 0, 100);
-       dev_dbg(&serial->dev->dev, "0x%x:0x%x:0x%x:0x%x  %d\n",
+       dev_dbg(&serial->interface->dev, "0x%x:0x%x:0x%x:0x%x  %d\n",
                VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, value, index,
                res);
        return res;
@@ -248,14 +248,15 @@ static int pl2303_port_remove(struct usb_serial_port *port)
        return 0;
 }
 
-static int set_control_lines(struct usb_device *dev, u8 value)
+static int pl2303_set_control_lines(struct usb_serial_port *port, u8 value)
 {
+       struct usb_device *dev = port->serial->dev;
        int retval;
 
        retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
                                 SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
                                 value, 0, NULL, 0, 100);
-       dev_dbg(&dev->dev, "%s - value = %d, retval = %d\n", __func__,
+       dev_dbg(&port->dev, "%s - value = %d, retval = %d\n", __func__,
                value, retval);
        return retval;
 }
@@ -437,7 +438,7 @@ static void pl2303_set_termios(struct tty_struct *tty,
        if (control != priv->line_control) {
                control = priv->line_control;
                spin_unlock_irqrestore(&priv->lock, flags);
-               set_control_lines(serial->dev, control);
+               pl2303_set_control_lines(port, control);
        } else {
                spin_unlock_irqrestore(&priv->lock, flags);
        }
@@ -480,7 +481,7 @@ static void pl2303_dtr_rts(struct usb_serial_port *port, int on)
                priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
        control = priv->line_control;
        spin_unlock_irqrestore(&priv->lock, flags);
-       set_control_lines(port->serial->dev, control);
+       pl2303_set_control_lines(port, control);
 }
 
 static void pl2303_close(struct usb_serial_port *port)
@@ -530,7 +531,6 @@ static int pl2303_tiocmset(struct tty_struct *tty,
                           unsigned int set, unsigned int clear)
 {
        struct usb_serial_port *port = tty->driver_data;
-       struct usb_serial *serial = port->serial;
        struct pl2303_private *priv = usb_get_serial_port_data(port);
        unsigned long flags;
        u8 control;
@@ -548,14 +548,11 @@ static int pl2303_tiocmset(struct tty_struct *tty,
        control = priv->line_control;
        spin_unlock_irqrestore(&priv->lock, flags);
 
-       mutex_lock(&serial->disc_mutex);
-       if (!serial->disconnected)
-               ret = set_control_lines(serial->dev, control);
-       else
-               ret = -ENODEV;
-       mutex_unlock(&serial->disc_mutex);
+       ret = pl2303_set_control_lines(port, control);
+       if (ret)
+               return usb_translate_errors(ret);
 
-       return ret;
+       return 0;
 }
 
 static int pl2303_tiocmget(struct tty_struct *tty)
@@ -592,8 +589,9 @@ static int pl2303_carrier_raised(struct usb_serial_port *port)
        return 0;
 }
 
-static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
+static int pl2303_tiocmiwait(struct tty_struct *tty, unsigned long arg)
 {
+       struct usb_serial_port *port = tty->driver_data;
        struct pl2303_private *priv = usb_get_serial_port_data(port);
        unsigned long flags;
        unsigned int prevstatus;
@@ -605,7 +603,7 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
        spin_unlock_irqrestore(&priv->lock, flags);
 
        while (1) {
-               interruptible_sleep_on(&port->delta_msr_wait);
+               interruptible_sleep_on(&port->port.delta_msr_wait);
                /* see if a signal did it */
                if (signal_pending(current))
                        return -ERESTARTSYS;
@@ -651,10 +649,6 @@ static int pl2303_ioctl(struct tty_struct *tty,
                        return -EFAULT;
 
                return 0;
-
-       case TIOCMIWAIT:
-               dev_dbg(&port->dev, "%s TIOCMIWAIT\n", __func__);
-               return wait_modem_info(port, arg);
        default:
                dev_dbg(&port->dev, "%s not supported = 0x%04x\n", __func__, cmd);
                break;
@@ -720,7 +714,7 @@ static void pl2303_update_line_status(struct usb_serial_port *port,
        spin_unlock_irqrestore(&priv->lock, flags);
        if (priv->line_status & UART_BREAK_ERROR)
                usb_serial_handle_break(port);
-       wake_up_interruptible(&port->delta_msr_wait);
+       wake_up_interruptible(&port->port.delta_msr_wait);
 
        tty = tty_port_tty_get(&port->port);
        if (!tty)
@@ -784,7 +778,7 @@ static void pl2303_process_read_urb(struct urb *urb)
        line_status = priv->line_status;
        priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
        spin_unlock_irqrestore(&priv->lock, flags);
-       wake_up_interruptible(&port->delta_msr_wait);
+       wake_up_interruptible(&port->port.delta_msr_wait);
 
        if (!urb->actual_length)
                return;
@@ -835,6 +829,7 @@ static struct usb_serial_driver pl2303_device = {
        .set_termios =          pl2303_set_termios,
        .tiocmget =             pl2303_tiocmget,
        .tiocmset =             pl2303_tiocmset,
+       .tiocmiwait =           pl2303_tiocmiwait,
        .process_read_urb =     pl2303_process_read_urb,
        .read_int_callback =    pl2303_read_int_callback,
        .attach =               pl2303_startup,
index 75f125ddb0c94136da28ebf5fa5d4e4200a0b410..3c278521f7e2179a7886537c7118da6e32490d2b 100644 (file)
@@ -128,8 +128,6 @@ struct qt2_port_private {
        u8          shadowLSR;
        u8          shadowMSR;
 
-       struct async_icount icount;
-
        struct usb_serial_port *port;
 };
 
@@ -424,12 +422,6 @@ static void qt2_close(struct usb_serial_port *port)
        port_priv->urb_in_use = false;
        spin_unlock_irqrestore(&port_priv->urb_lock, flags);
 
-       mutex_lock(&port->serial->disc_mutex);
-       if (port->serial->disconnected) {
-               mutex_unlock(&port->serial->disc_mutex);
-               return;
-       }
-
        /* flush the port transmit buffer */
        i = usb_control_msg(serial->dev,
                            usb_rcvctrlpipe(serial->dev, 0),
@@ -460,8 +452,6 @@ static void qt2_close(struct usb_serial_port *port)
        if (i < 0)
                dev_err(&port->dev, "%s - close port failed %i\n",
                        __func__, i);
-
-       mutex_unlock(&port->serial->disc_mutex);
 }
 
 static void qt2_disconnect(struct usb_serial *serial)
@@ -494,71 +484,6 @@ static int get_serial_info(struct usb_serial_port *port,
        return 0;
 }
 
-static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
-{
-       struct qt2_port_private *priv = usb_get_serial_port_data(port);
-       struct async_icount prev, cur;
-       unsigned long flags;
-
-       spin_lock_irqsave(&priv->lock, flags);
-       prev = priv->icount;
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       while (1) {
-               wait_event_interruptible(port->delta_msr_wait,
-                                        (port->serial->disconnected ||
-                                         (priv->icount.rng != prev.rng) ||
-                                         (priv->icount.dsr != prev.dsr) ||
-                                         (priv->icount.dcd != prev.dcd) ||
-                                         (priv->icount.cts != prev.cts)));
-
-               if (signal_pending(current))
-                       return -ERESTARTSYS;
-
-               if (port->serial->disconnected)
-                       return -EIO;
-
-               spin_lock_irqsave(&priv->lock, flags);
-               cur = priv->icount;
-               spin_unlock_irqrestore(&priv->lock, flags);
-
-               if ((prev.rng == cur.rng) &&
-                   (prev.dsr == cur.dsr) &&
-                   (prev.dcd == cur.dcd) &&
-                   (prev.cts == cur.cts))
-                       return -EIO;
-
-               if ((arg & TIOCM_RNG && (prev.rng != cur.rng)) ||
-                   (arg & TIOCM_DSR && (prev.dsr != cur.dsr)) ||
-                   (arg & TIOCM_CD && (prev.dcd != cur.dcd)) ||
-                   (arg & TIOCM_CTS && (prev.cts != cur.cts)))
-                       return 0;
-       }
-       return 0;
-}
-
-static int qt2_get_icount(struct tty_struct *tty,
-                         struct serial_icounter_struct *icount)
-{
-       struct usb_serial_port *port = tty->driver_data;
-       struct qt2_port_private *priv = usb_get_serial_port_data(port);
-       struct async_icount cnow = priv->icount;
-
-       icount->cts = cnow.cts;
-       icount->dsr = cnow.dsr;
-       icount->rng = cnow.rng;
-       icount->dcd = cnow.dcd;
-       icount->rx = cnow.rx;
-       icount->tx = cnow.tx;
-       icount->frame = cnow.frame;
-       icount->overrun = cnow.overrun;
-       icount->parity = cnow.parity;
-       icount->brk = cnow.brk;
-       icount->buf_overrun = cnow.buf_overrun;
-
-       return 0;
-}
-
 static int qt2_ioctl(struct tty_struct *tty,
                     unsigned int cmd, unsigned long arg)
 {
@@ -568,10 +493,6 @@ static int qt2_ioctl(struct tty_struct *tty,
        case TIOCGSERIAL:
                return get_serial_info(port,
                                       (struct serial_struct __user *)arg);
-
-       case TIOCMIWAIT:
-               return wait_modem_info(port, arg);
-
        default:
                break;
        }
@@ -664,9 +585,7 @@ void qt2_process_read_urb(struct urb *urb)
                                                 __func__);
                                        break;
                                }
-
-                               if (port_priv->is_open)
-                                       tty_flip_buffer_push(&port->port);
+                               tty_flip_buffer_push(&port->port);
 
                                newport = *(ch + 3);
 
@@ -709,8 +628,7 @@ void qt2_process_read_urb(struct urb *urb)
                tty_insert_flip_string(&port->port, ch, 1);
        }
 
-       if (port_priv->is_open)
-               tty_flip_buffer_push(&port->port);
+       tty_flip_buffer_push(&port->port);
 }
 
 static void qt2_write_bulk_callback(struct urb *urb)
@@ -961,18 +879,15 @@ static void qt2_update_msr(struct usb_serial_port *port, unsigned char *ch)
        if (newMSR & UART_MSR_ANY_DELTA) {
                /* update input line counters */
                if (newMSR & UART_MSR_DCTS)
-                       port_priv->icount.cts++;
-
+                       port->icount.cts++;
                if (newMSR & UART_MSR_DDSR)
-                       port_priv->icount.dsr++;
-
+                       port->icount.dsr++;
                if (newMSR & UART_MSR_DDCD)
-                       port_priv->icount.dcd++;
-
+                       port->icount.dcd++;
                if (newMSR & UART_MSR_TERI)
-                       port_priv->icount.rng++;
+                       port->icount.rng++;
 
-               wake_up_interruptible(&port->delta_msr_wait);
+               wake_up_interruptible(&port->port.delta_msr_wait);
        }
 }
 
@@ -992,7 +907,7 @@ static void qt2_update_lsr(struct usb_serial_port *port, unsigned char *ch)
        port_priv->shadowLSR = newLSR;
        spin_unlock_irqrestore(&port_priv->lock, flags);
 
-       icount = &port_priv->icount;
+       icount = &port->icount;
 
        if (newLSR & UART_LSR_BRK_ERROR_BITS) {
 
@@ -1102,7 +1017,8 @@ static struct usb_serial_driver qt2_device = {
        .break_ctl           = qt2_break_ctl,
        .tiocmget            = qt2_tiocmget,
        .tiocmset            = qt2_tiocmset,
-       .get_icount          = qt2_get_icount,
+       .tiocmiwait          = usb_serial_generic_tiocmiwait,
+       .get_icount          = usb_serial_generic_get_icount,
        .ioctl               = qt2_ioctl,
        .set_termios         = qt2_set_termios,
 };
index c13f6e747748b31d16c0d087fa4f8b1953826285..2b06481dc85ceb2a5829d14cd24c01970fa3439e 100644 (file)
@@ -778,30 +778,25 @@ static void sierra_close(struct usb_serial_port *port)
        portdata->rts_state = 0;
        portdata->dtr_state = 0;
 
-       if (serial->dev) {
-               mutex_lock(&serial->disc_mutex);
-               if (!serial->disconnected) {
-                       serial->interface->needs_remote_wakeup = 0;
-                       /* odd error handling due to pm counters */
-                       if (!usb_autopm_get_interface(serial->interface))
-                               sierra_send_setup(port);
-                       else
-                               usb_autopm_get_interface_no_resume(serial->interface);
-                               
-               }
-               mutex_unlock(&serial->disc_mutex);
-               spin_lock_irq(&intfdata->susp_lock);
-               portdata->opened = 0;
-               spin_unlock_irq(&intfdata->susp_lock);
+       mutex_lock(&serial->disc_mutex);
+       if (!serial->disconnected) {
+               serial->interface->needs_remote_wakeup = 0;
+               /* odd error handling due to pm counters */
+               if (!usb_autopm_get_interface(serial->interface))
+                       sierra_send_setup(port);
+               else
+                       usb_autopm_get_interface_no_resume(serial->interface);
 
+       }
+       mutex_unlock(&serial->disc_mutex);
+       spin_lock_irq(&intfdata->susp_lock);
+       portdata->opened = 0;
+       spin_unlock_irq(&intfdata->susp_lock);
 
-               /* Stop reading urbs */
-               sierra_stop_rx_urbs(port);
-               /* .. and release them */
-               for (i = 0; i < portdata->num_in_urbs; i++) {
-                       sierra_release_urb(portdata->in_urbs[i]);
-                       portdata->in_urbs[i] = NULL;
-               }
+       sierra_stop_rx_urbs(port);
+       for (i = 0; i < portdata->num_in_urbs; i++) {
+               sierra_release_urb(portdata->in_urbs[i]);
+               portdata->in_urbs[i] = NULL;
        }
 }
 
index 549ef68ff5fa2ea156fa31ea65f3b823353b1cfa..cf3df793c2b7a1a7781e908e0a5d2385e7056f5b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * spcp8x5 USB to serial adaptor driver
  *
- * Copyright (C) 2010 Johan Hovold (jhovold@gmail.com)
+ * Copyright (C) 2010-2013 Johan Hovold (jhovold@gmail.com)
  * Copyright (C) 2006 Linxb (xubin.lin@worldplus.com.cn)
  * Copyright (C) 2006 S1 Corp.
  *
@@ -13,8 +13,6 @@
  *     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/kernel.h>
 #include <linux/errno.h>
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
 
-#define DRIVER_DESC    "SPCP8x5 USB to serial adaptor driver"
+#define DRIVER_DESC    "SPCP8x5 USB to serial adaptor driver"
+
+#define SPCP825_QUIRK_NO_UART_STATUS   0x01
+#define SPCP825_QUIRK_NO_WORK_MODE     0x02
 
 #define SPCP8x5_007_VID                0x04FC
 #define SPCP8x5_007_PID                0x0201
@@ -46,13 +47,15 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(SPCP8x5_INTERMATIC_VID, SPCP8x5_INTERMATIC_PID)},
        { USB_DEVICE(SPCP8x5_835_VID, SPCP8x5_835_PID)},
        { USB_DEVICE(SPCP8x5_008_VID, SPCP8x5_008_PID)},
-       { USB_DEVICE(SPCP8x5_007_VID, SPCP8x5_007_PID)},
+       { USB_DEVICE(SPCP8x5_007_VID, SPCP8x5_007_PID),
+         .driver_info = SPCP825_QUIRK_NO_UART_STATUS |
+                               SPCP825_QUIRK_NO_WORK_MODE },
        { }                                     /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, id_table);
 
 struct spcp8x5_usb_ctrl_arg {
-       u8      type;
+       u8      type;
        u8      cmd;
        u8      cmd_type;
        u16     value;
@@ -138,49 +141,33 @@ struct spcp8x5_usb_ctrl_arg {
 #define UART_OVERRUN_ERROR             0x40
 #define UART_CTS                       0x80
 
-enum spcp8x5_type {
-       SPCP825_007_TYPE,
-       SPCP825_008_TYPE,
-       SPCP825_PHILIP_TYPE,
-       SPCP825_INTERMATIC_TYPE,
-       SPCP835_TYPE,
-};
-
 struct spcp8x5_private {
-       spinlock_t      lock;
-       enum spcp8x5_type       type;
-       u8                      line_control;
-       u8                      line_status;
+       unsigned                quirks;
+       spinlock_t              lock;
+       u8                      line_control;
 };
 
+static int spcp8x5_probe(struct usb_serial *serial,
+                                               const struct usb_device_id *id)
+{
+       usb_set_serial_data(serial, (void *)id);
+
+       return 0;
+}
+
 static int spcp8x5_port_probe(struct usb_serial_port *port)
 {
-       struct usb_serial *serial = port->serial;
+       const struct usb_device_id *id = usb_get_serial_data(port->serial);
        struct spcp8x5_private *priv;
-       enum spcp8x5_type type = SPCP825_007_TYPE;
-       u16 product = le16_to_cpu(serial->dev->descriptor.idProduct);
-
-       if (product == 0x0201)
-               type = SPCP825_007_TYPE;
-       else if (product == 0x0231)
-               type = SPCP835_TYPE;
-       else if (product == 0x0235)
-               type = SPCP825_008_TYPE;
-       else if (product == 0x0204)
-               type = SPCP825_INTERMATIC_TYPE;
-       else if (product == 0x0471 &&
-                serial->dev->descriptor.idVendor == cpu_to_le16(0x081e))
-               type = SPCP825_PHILIP_TYPE;
-       dev_dbg(&serial->dev->dev, "device type = %d\n", (int)type);
 
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
 
        spin_lock_init(&priv->lock);
-       priv->type = type;
+       priv->quirks = id->driver_info;
 
-       usb_set_serial_port_data(port , priv);
+       usb_set_serial_port_data(port, priv);
 
        return 0;
 }
@@ -195,86 +182,79 @@ static int spcp8x5_port_remove(struct usb_serial_port *port)
        return 0;
 }
 
-/* set the modem control line of the device.
- * NOTE spcp825-007 not supported this */
-static int spcp8x5_set_ctrlLine(struct usb_device *dev, u8 value,
-                               enum spcp8x5_type type)
+static int spcp8x5_set_ctrl_line(struct usb_serial_port *port, u8 mcr)
 {
+       struct spcp8x5_private *priv = usb_get_serial_port_data(port);
+       struct usb_device *dev = port->serial->dev;
        int retval;
-       u8 mcr = 0 ;
 
-       if (type == SPCP825_007_TYPE)
+       if (priv->quirks & SPCP825_QUIRK_NO_UART_STATUS)
                return -EPERM;
 
-       mcr = (unsigned short)value;
        retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
                                 SET_UART_STATUS_TYPE, SET_UART_STATUS,
                                 mcr, 0x04, NULL, 0, 100);
-       if (retval != 0)
-               dev_dbg(&dev->dev, "usb_control_msg return %#x\n", retval);
+       if (retval != 0) {
+               dev_err(&port->dev, "failed to set control lines: %d\n",
+                                                               retval);
+       }
        return retval;
 }
 
-/* get the modem status register of the device
- * NOTE spcp825-007 not supported this */
-static int spcp8x5_get_msr(struct usb_device *dev, u8 *status,
-                          enum spcp8x5_type type)
+static int spcp8x5_get_msr(struct usb_serial_port *port, u8 *status)
 {
-       u8 *status_buffer;
+       struct spcp8x5_private *priv = usb_get_serial_port_data(port);
+       struct usb_device *dev = port->serial->dev;
+       u8 *buf;
        int ret;
 
-       /* I return Permited not support here but seem inval device
-        * is more fix */
-       if (type == SPCP825_007_TYPE)
+       if (priv->quirks & SPCP825_QUIRK_NO_UART_STATUS)
                return -EPERM;
-       if (status == NULL)
-               return -EINVAL;
 
-       status_buffer = kmalloc(1, GFP_KERNEL);
-       if (!status_buffer)
+       buf = kzalloc(1, GFP_KERNEL);
+       if (!buf)
                return -ENOMEM;
-       status_buffer[0] = status[0];
 
        ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
                              GET_UART_STATUS, GET_UART_STATUS_TYPE,
-                             0, GET_UART_STATUS_MSR, status_buffer, 1, 100);
+                             0, GET_UART_STATUS_MSR, buf, 1, 100);
        if (ret < 0)
-               dev_dbg(&dev->dev, "Get MSR = 0x%p failed (error = %d)",
-                       status_buffer, ret);
+               dev_err(&port->dev, "failed to get modem status: %d", ret);
 
-       dev_dbg(&dev->dev, "0xc0:0x22:0:6  %d - 0x%p ", ret, status_buffer);
-       status[0] = status_buffer[0];
-       kfree(status_buffer);
+       dev_dbg(&port->dev, "0xc0:0x22:0:6  %d - 0x02%x", ret, *buf);
+       *status = *buf;
+       kfree(buf);
 
        return ret;
 }
 
-/* select the work mode.
- * NOTE this function not supported by spcp825-007 */
-static void spcp8x5_set_workMode(struct usb_device *dev, u16 value,
-                                u16 index, enum spcp8x5_type type)
+static void spcp8x5_set_work_mode(struct usb_serial_port *port, u16 value,
+                                                                u16 index)
 {
+       struct spcp8x5_private *priv = usb_get_serial_port_data(port);
+       struct usb_device *dev = port->serial->dev;
        int ret;
 
-       /* I return Permited not support here but seem inval device
-        * is more fix */
-       if (type == SPCP825_007_TYPE)
+       if (priv->quirks & SPCP825_QUIRK_NO_WORK_MODE)
                return;
 
        ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
                              SET_WORKING_MODE_TYPE, SET_WORKING_MODE,
                              value, index, NULL, 0, 100);
-       dev_dbg(&dev->dev, "value = %#x , index = %#x\n", value, index);
+       dev_dbg(&port->dev, "value = %#x , index = %#x\n", value, index);
        if (ret < 0)
-               dev_dbg(&dev->dev,
-                       "RTSCTS usb_control_msg(enable flowctrl) = %d\n", ret);
+               dev_err(&port->dev, "failed to set work mode: %d\n", ret);
 }
 
 static int spcp8x5_carrier_raised(struct usb_serial_port *port)
 {
-       struct spcp8x5_private *priv = usb_get_serial_port_data(port);
-       if (priv->line_status & MSR_STATUS_LINE_DCD)
+       u8 msr;
+       int ret;
+
+       ret = spcp8x5_get_msr(port, &msr);
+       if (ret || msr & MSR_STATUS_LINE_DCD)
                return 1;
+
        return 0;
 }
 
@@ -293,20 +273,17 @@ static void spcp8x5_dtr_rts(struct usb_serial_port *port, int on)
                                                | MCR_CONTROL_LINE_RTS);
        control = priv->line_control;
        spin_unlock_irqrestore(&priv->lock, flags);
-       spcp8x5_set_ctrlLine(port->serial->dev, control , priv->type);
+       spcp8x5_set_ctrl_line(port, control);
 }
 
 static void spcp8x5_init_termios(struct tty_struct *tty)
 {
-       /* for the 1st time call this function */
        tty->termios = tty_std_termios;
        tty->termios.c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL;
        tty->termios.c_ispeed = 115200;
        tty->termios.c_ospeed = 115200;
 }
 
-/* set the serial param for transfer. we should check if we really need to
- * transfer. if we set flow control we should do this too. */
 static void spcp8x5_set_termios(struct tty_struct *tty,
                struct usb_serial_port *port, struct ktermios *old_termios)
 {
@@ -321,7 +298,6 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
        int i;
        u8 control;
 
-
        /* check that they really want us to change something */
        if (!tty_termios_hw_change(&tty->termios, old_termios))
                return;
@@ -337,7 +313,7 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
        if (control != priv->line_control) {
                control = priv->line_control;
                spin_unlock_irqrestore(&priv->lock, flags);
-               spcp8x5_set_ctrlLine(serial->dev, control , priv->type);
+               spcp8x5_set_ctrl_line(port, control);
        } else {
                spin_unlock_irqrestore(&priv->lock, flags);
        }
@@ -397,9 +373,9 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
        if (cflag & PARENB) {
                buf[1] |= (cflag & PARODD) ?
                SET_UART_FORMAT_PAR_ODD : SET_UART_FORMAT_PAR_EVEN ;
-       } else
+       } else {
                buf[1] |= SET_UART_FORMAT_PAR_NONE;
-
+       }
        uartdata = buf[0] | buf[1]<<8;
 
        i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
@@ -412,22 +388,16 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
 
        if (cflag & CRTSCTS) {
                /* enable hardware flow control */
-               spcp8x5_set_workMode(serial->dev, 0x000a,
-                                    SET_WORKING_MODE_U2C, priv->type);
+               spcp8x5_set_work_mode(port, 0x000a, SET_WORKING_MODE_U2C);
        }
 }
 
-/* open the serial port. do some usb system call. set termios and get the line
- * status of the device. */
 static int spcp8x5_open(struct tty_struct *tty, struct usb_serial_port *port)
 {
        struct ktermios tmp_termios;
        struct usb_serial *serial = port->serial;
        struct spcp8x5_private *priv = usb_get_serial_port_data(port);
        int ret;
-       unsigned long flags;
-       u8 status = 0x30;
-       /* status 0x30 means DSR and CTS = 1 other CDC RI and delta = 0 */
 
        usb_clear_halt(serial->dev, port->write_urb->pipe);
        usb_clear_halt(serial->dev, port->read_urb->pipe);
@@ -438,142 +408,16 @@ static int spcp8x5_open(struct tty_struct *tty, struct usb_serial_port *port)
        if (ret)
                return ret;
 
-       spcp8x5_set_ctrlLine(serial->dev, priv->line_control , priv->type);
+       spcp8x5_set_ctrl_line(port, priv->line_control);
 
-       /* Setup termios */
        if (tty)
                spcp8x5_set_termios(tty, port, &tmp_termios);
 
-       spcp8x5_get_msr(serial->dev, &status, priv->type);
-
-       /* may be we should update uart status here but now we did not do */
-       spin_lock_irqsave(&priv->lock, flags);
-       priv->line_status = status & 0xf0 ;
-       spin_unlock_irqrestore(&priv->lock, flags);
-
        port->port.drain_delay = 256;
 
        return usb_serial_generic_open(tty, port);
 }
 
-static void spcp8x5_process_read_urb(struct urb *urb)
-{
-       struct usb_serial_port *port = urb->context;
-       struct spcp8x5_private *priv = usb_get_serial_port_data(port);
-       unsigned char *data = urb->transfer_buffer;
-       unsigned long flags;
-       u8 status;
-       char tty_flag;
-
-       /* get tty_flag from status */
-       tty_flag = TTY_NORMAL;
-
-       spin_lock_irqsave(&priv->lock, flags);
-       status = priv->line_status;
-       priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
-       spin_unlock_irqrestore(&priv->lock, flags);
-       /* wake up the wait for termios */
-       wake_up_interruptible(&port->delta_msr_wait);
-
-       if (!urb->actual_length)
-               return;
-
-
-       if (status & UART_STATE_TRANSIENT_MASK) {
-               /* break takes precedence over parity, which takes precedence
-                * over framing errors */
-               if (status & UART_BREAK_ERROR)
-                       tty_flag = TTY_BREAK;
-               else if (status & UART_PARITY_ERROR)
-                       tty_flag = TTY_PARITY;
-               else if (status & UART_FRAME_ERROR)
-                       tty_flag = TTY_FRAME;
-               dev_dbg(&port->dev, "tty_flag = %d\n", tty_flag);
-
-               /* overrun is special, not associated with a char */
-               if (status & UART_OVERRUN_ERROR)
-                       tty_insert_flip_char(&port->port, 0, TTY_OVERRUN);
-
-               if (status & UART_DCD) {
-                       struct tty_struct *tty = tty_port_tty_get(&port->port);
-                       if (tty) {
-                               usb_serial_handle_dcd_change(port, tty,
-                                      priv->line_status & MSR_STATUS_LINE_DCD);
-                               tty_kref_put(tty);
-                       }
-               }
-       }
-
-       tty_insert_flip_string_fixed_flag(&port->port, data, tty_flag,
-                                                       urb->actual_length);
-       tty_flip_buffer_push(&port->port);
-}
-
-static int spcp8x5_wait_modem_info(struct usb_serial_port *port,
-                                  unsigned int arg)
-{
-       struct spcp8x5_private *priv = usb_get_serial_port_data(port);
-       unsigned long flags;
-       unsigned int prevstatus;
-       unsigned int status;
-       unsigned int changed;
-
-       spin_lock_irqsave(&priv->lock, flags);
-       prevstatus = priv->line_status;
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       while (1) {
-               /* wake up in bulk read */
-               interruptible_sleep_on(&port->delta_msr_wait);
-
-               /* see if a signal did it */
-               if (signal_pending(current))
-                       return -ERESTARTSYS;
-
-               if (port->serial->disconnected)
-                       return -EIO;
-
-               spin_lock_irqsave(&priv->lock, flags);
-               status = priv->line_status;
-               spin_unlock_irqrestore(&priv->lock, flags);
-
-               changed = prevstatus^status;
-
-               if (((arg & TIOCM_RNG) && (changed & MSR_STATUS_LINE_RI)) ||
-                   ((arg & TIOCM_DSR) && (changed & MSR_STATUS_LINE_DSR)) ||
-                   ((arg & TIOCM_CD)  && (changed & MSR_STATUS_LINE_DCD)) ||
-                   ((arg & TIOCM_CTS) && (changed & MSR_STATUS_LINE_CTS)))
-                       return 0;
-
-               prevstatus = status;
-       }
-       /* NOTREACHED */
-       return 0;
-}
-
-static int spcp8x5_ioctl(struct tty_struct *tty,
-                        unsigned int cmd, unsigned long arg)
-{
-       struct usb_serial_port *port = tty->driver_data;
-
-       dev_dbg(&port->dev, "%s (%d) cmd = 0x%04x\n", __func__,
-               port->number, cmd);
-
-       switch (cmd) {
-       case TIOCMIWAIT:
-               dev_dbg(&port->dev, "%s (%d) TIOCMIWAIT\n", __func__,
-                       port->number);
-               return spcp8x5_wait_modem_info(port, arg);
-
-       default:
-               dev_dbg(&port->dev, "%s not supported = 0x%04x", __func__,
-                       cmd);
-               break;
-       }
-
-       return -ENOIOCTLCMD;
-}
-
 static int spcp8x5_tiocmset(struct tty_struct *tty,
                            unsigned int set, unsigned int clear)
 {
@@ -594,7 +438,7 @@ static int spcp8x5_tiocmset(struct tty_struct *tty,
        control = priv->line_control;
        spin_unlock_irqrestore(&priv->lock, flags);
 
-       return spcp8x5_set_ctrlLine(port->serial->dev, control , priv->type);
+       return spcp8x5_set_ctrl_line(port, control);
 }
 
 static int spcp8x5_tiocmget(struct tty_struct *tty)
@@ -603,12 +447,15 @@ static int spcp8x5_tiocmget(struct tty_struct *tty)
        struct spcp8x5_private *priv = usb_get_serial_port_data(port);
        unsigned long flags;
        unsigned int mcr;
-       unsigned int status;
+       u8 status;
        unsigned int result;
 
+       result = spcp8x5_get_msr(port, &status);
+       if (result)
+               return result;
+
        spin_lock_irqsave(&priv->lock, flags);
        mcr = priv->line_control;
-       status = priv->line_status;
        spin_unlock_irqrestore(&priv->lock, flags);
 
        result = ((mcr & MCR_DTR)                       ? TIOCM_DTR : 0)
@@ -621,7 +468,6 @@ static int spcp8x5_tiocmget(struct tty_struct *tty)
        return result;
 }
 
-/* All of the device info needed for the spcp8x5 SIO serial converter */
 static struct usb_serial_driver spcp8x5_device = {
        .driver = {
                .owner =        THIS_MODULE,
@@ -629,17 +475,16 @@ static struct usb_serial_driver spcp8x5_device = {
        },
        .id_table               = id_table,
        .num_ports              = 1,
-       .open                   = spcp8x5_open,
+       .open                   = spcp8x5_open,
        .dtr_rts                = spcp8x5_dtr_rts,
        .carrier_raised         = spcp8x5_carrier_raised,
-       .set_termios            = spcp8x5_set_termios,
+       .set_termios            = spcp8x5_set_termios,
        .init_termios           = spcp8x5_init_termios,
-       .ioctl                  = spcp8x5_ioctl,
-       .tiocmget               = spcp8x5_tiocmget,
-       .tiocmset               = spcp8x5_tiocmset,
+       .tiocmget               = spcp8x5_tiocmget,
+       .tiocmset               = spcp8x5_tiocmset,
+       .probe                  = spcp8x5_probe,
        .port_probe             = spcp8x5_port_probe,
        .port_remove            = spcp8x5_port_remove,
-       .process_read_urb       = spcp8x5_process_read_urb,
 };
 
 static struct usb_serial_driver * const serial_drivers[] = {
index 4b2a19757b4d531baa8dfb48c8009517d2d21cb5..5b62dbbdf996b53bcb4f82ea6966dae7c2fa5801 100644 (file)
@@ -61,7 +61,6 @@ struct ssu100_port_private {
        spinlock_t status_lock;
        u8 shadowLSR;
        u8 shadowMSR;
-       struct async_icount icount;
 };
 
 static inline int ssu100_control_msg(struct usb_device *dev,
@@ -315,11 +314,6 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port)
        return usb_serial_generic_open(tty, port);
 }
 
-static void ssu100_close(struct usb_serial_port *port)
-{
-       usb_serial_generic_close(port);
-}
-
 static int get_serial_info(struct usb_serial_port *port,
                           struct serial_struct __user *retinfo)
 {
@@ -343,73 +337,6 @@ static int get_serial_info(struct usb_serial_port *port,
        return 0;
 }
 
-static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
-{
-       struct ssu100_port_private *priv = usb_get_serial_port_data(port);
-       struct async_icount prev, cur;
-       unsigned long flags;
-
-       spin_lock_irqsave(&priv->status_lock, flags);
-       prev = priv->icount;
-       spin_unlock_irqrestore(&priv->status_lock, flags);
-
-       while (1) {
-               wait_event_interruptible(port->delta_msr_wait,
-                                        (port->serial->disconnected ||
-                                         (priv->icount.rng != prev.rng) ||
-                                         (priv->icount.dsr != prev.dsr) ||
-                                         (priv->icount.dcd != prev.dcd) ||
-                                         (priv->icount.cts != prev.cts)));
-
-               if (signal_pending(current))
-                       return -ERESTARTSYS;
-
-               if (port->serial->disconnected)
-                       return -EIO;
-
-               spin_lock_irqsave(&priv->status_lock, flags);
-               cur = priv->icount;
-               spin_unlock_irqrestore(&priv->status_lock, flags);
-
-               if ((prev.rng == cur.rng) &&
-                   (prev.dsr == cur.dsr) &&
-                   (prev.dcd == cur.dcd) &&
-                   (prev.cts == cur.cts))
-                       return -EIO;
-
-               if ((arg & TIOCM_RNG && (prev.rng != cur.rng)) ||
-                   (arg & TIOCM_DSR && (prev.dsr != cur.dsr)) ||
-                   (arg & TIOCM_CD  && (prev.dcd != cur.dcd)) ||
-                   (arg & TIOCM_CTS && (prev.cts != cur.cts)))
-                       return 0;
-       }
-       return 0;
-}
-
-static int ssu100_get_icount(struct tty_struct *tty,
-                       struct serial_icounter_struct *icount)
-{
-       struct usb_serial_port *port = tty->driver_data;
-       struct ssu100_port_private *priv = usb_get_serial_port_data(port);
-       struct async_icount cnow = priv->icount;
-
-       icount->cts = cnow.cts;
-       icount->dsr = cnow.dsr;
-       icount->rng = cnow.rng;
-       icount->dcd = cnow.dcd;
-       icount->rx = cnow.rx;
-       icount->tx = cnow.tx;
-       icount->frame = cnow.frame;
-       icount->overrun = cnow.overrun;
-       icount->parity = cnow.parity;
-       icount->brk = cnow.brk;
-       icount->buf_overrun = cnow.buf_overrun;
-
-       return 0;
-}
-
-
-
 static int ssu100_ioctl(struct tty_struct *tty,
                    unsigned int cmd, unsigned long arg)
 {
@@ -421,10 +348,6 @@ static int ssu100_ioctl(struct tty_struct *tty,
        case TIOCGSERIAL:
                return get_serial_info(port,
                                       (struct serial_struct __user *) arg);
-
-       case TIOCMIWAIT:
-               return wait_modem_info(port, arg);
-
        default:
                break;
        }
@@ -532,14 +455,14 @@ static void ssu100_update_msr(struct usb_serial_port *port, u8 msr)
        if (msr & UART_MSR_ANY_DELTA) {
                /* update input line counters */
                if (msr & UART_MSR_DCTS)
-                       priv->icount.cts++;
+                       port->icount.cts++;
                if (msr & UART_MSR_DDSR)
-                       priv->icount.dsr++;
+                       port->icount.dsr++;
                if (msr & UART_MSR_DDCD)
-                       priv->icount.dcd++;
+                       port->icount.dcd++;
                if (msr & UART_MSR_TERI)
-                       priv->icount.rng++;
-               wake_up_interruptible(&port->delta_msr_wait);
+                       port->icount.rng++;
+               wake_up_interruptible(&port->port.delta_msr_wait);
        }
 }
 
@@ -558,22 +481,22 @@ static void ssu100_update_lsr(struct usb_serial_port *port, u8 lsr,
                /* we always want to update icount, but we only want to
                 * update tty_flag for one case */
                if (lsr & UART_LSR_BI) {
-                       priv->icount.brk++;
+                       port->icount.brk++;
                        *tty_flag = TTY_BREAK;
                        usb_serial_handle_break(port);
                }
                if (lsr & UART_LSR_PE) {
-                       priv->icount.parity++;
+                       port->icount.parity++;
                        if (*tty_flag == TTY_NORMAL)
                                *tty_flag = TTY_PARITY;
                }
                if (lsr & UART_LSR_FE) {
-                       priv->icount.frame++;
+                       port->icount.frame++;
                        if (*tty_flag == TTY_NORMAL)
                                *tty_flag = TTY_FRAME;
                }
                if (lsr & UART_LSR_OE){
-                       priv->icount.overrun++;
+                       port->icount.overrun++;
                        if (*tty_flag == TTY_NORMAL)
                                *tty_flag = TTY_OVERRUN;
                }
@@ -630,7 +553,6 @@ static struct usb_serial_driver ssu100_device = {
        .id_table            = id_table,
        .num_ports           = 1,
        .open                = ssu100_open,
-       .close               = ssu100_close,
        .attach              = ssu100_attach,
        .port_probe          = ssu100_port_probe,
        .port_remove         = ssu100_port_remove,
@@ -638,10 +560,10 @@ static struct usb_serial_driver ssu100_device = {
        .process_read_urb    = ssu100_process_read_urb,
        .tiocmget            = ssu100_tiocmget,
        .tiocmset            = ssu100_tiocmset,
-       .get_icount          = ssu100_get_icount,
+       .tiocmiwait          = usb_serial_generic_tiocmiwait,
+       .get_icount          = usb_serial_generic_get_icount,
        .ioctl               = ssu100_ioctl,
        .set_termios         = ssu100_set_termios,
-       .disconnect          = usb_serial_generic_disconnect,
 };
 
 static struct usb_serial_driver * const serial_drivers[] = {
index 73deb029fc05d3d9c9b728f1fae1616a8efee6e4..07268591b0d1fa7d958736a9fda4d2efa7586cf0 100644 (file)
@@ -73,7 +73,6 @@ struct ti_port {
        unsigned int            tp_uart_base_addr;
        int                     tp_flags;
        int                     tp_closing_wait;/* in .01 secs */
-       struct async_icount     tp_icount;
        wait_queue_head_t       tp_write_wait;
        struct ti_device        *tp_tdev;
        struct usb_serial_port  *tp_port;
@@ -108,8 +107,6 @@ static void ti_throttle(struct tty_struct *tty);
 static void ti_unthrottle(struct tty_struct *tty);
 static int ti_ioctl(struct tty_struct *tty,
                unsigned int cmd, unsigned long arg);
-static int ti_get_icount(struct tty_struct *tty,
-               struct serial_icounter_struct *icount);
 static void ti_set_termios(struct tty_struct *tty,
                struct usb_serial_port *port, struct ktermios *old_termios);
 static int ti_tiocmget(struct tty_struct *tty);
@@ -235,7 +232,8 @@ static struct usb_serial_driver ti_1port_device = {
        .set_termios            = ti_set_termios,
        .tiocmget               = ti_tiocmget,
        .tiocmset               = ti_tiocmset,
-       .get_icount             = ti_get_icount,
+       .tiocmiwait             = usb_serial_generic_tiocmiwait,
+       .get_icount             = usb_serial_generic_get_icount,
        .break_ctl              = ti_break,
        .read_int_callback      = ti_interrupt_callback,
        .read_bulk_callback     = ti_bulk_in_callback,
@@ -265,7 +263,8 @@ static struct usb_serial_driver ti_2port_device = {
        .set_termios            = ti_set_termios,
        .tiocmget               = ti_tiocmget,
        .tiocmset               = ti_tiocmset,
-       .get_icount             = ti_get_icount,
+       .tiocmiwait             = usb_serial_generic_tiocmiwait,
+       .get_icount             = usb_serial_generic_get_icount,
        .break_ctl              = ti_break,
        .read_int_callback      = ti_interrupt_callback,
        .read_bulk_callback     = ti_bulk_in_callback,
@@ -480,8 +479,6 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port)
 
        port_number = port->number - port->serial->minor;
 
-       memset(&(tport->tp_icount), 0x00, sizeof(tport->tp_icount));
-
        tport->tp_msr = 0;
        tport->tp_shadow_mcr |= (TI_MCR_RTS | TI_MCR_DTR);
 
@@ -731,38 +728,11 @@ static void ti_unthrottle(struct tty_struct *tty)
        }
 }
 
-static int ti_get_icount(struct tty_struct *tty,
-               struct serial_icounter_struct *icount)
-{
-       struct usb_serial_port *port = tty->driver_data;
-       struct ti_port *tport = usb_get_serial_port_data(port);
-       struct async_icount cnow = tport->tp_icount;
-
-       dev_dbg(&port->dev, "%s - TIOCGICOUNT RX=%d, TX=%d\n", __func__,
-               cnow.rx, cnow.tx);
-
-       icount->cts = cnow.cts;
-       icount->dsr = cnow.dsr;
-       icount->rng = cnow.rng;
-       icount->dcd = cnow.dcd;
-       icount->rx = cnow.rx;
-       icount->tx = cnow.tx;
-       icount->frame = cnow.frame;
-       icount->overrun = cnow.overrun;
-       icount->parity = cnow.parity;
-       icount->brk = cnow.brk;
-       icount->buf_overrun = cnow.buf_overrun;
-
-       return 0;
-}
-
 static int ti_ioctl(struct tty_struct *tty,
        unsigned int cmd, unsigned long arg)
 {
        struct usb_serial_port *port = tty->driver_data;
        struct ti_port *tport = usb_get_serial_port_data(port);
-       struct async_icount cnow;
-       struct async_icount cprev;
 
        dev_dbg(&port->dev, "%s - cmd = 0x%04X\n", __func__, cmd);
 
@@ -778,29 +748,6 @@ static int ti_ioctl(struct tty_struct *tty,
                dev_dbg(&port->dev, "%s - TIOCSSERIAL\n", __func__);
                return ti_set_serial_info(tty, tport,
                                (struct serial_struct __user *)arg);
-       case TIOCMIWAIT:
-               dev_dbg(&port->dev, "%s - TIOCMIWAIT\n", __func__);
-               cprev = tport->tp_icount;
-               while (1) {
-                       interruptible_sleep_on(&port->delta_msr_wait);
-                       if (signal_pending(current))
-                               return -ERESTARTSYS;
-
-                       if (port->serial->disconnected)
-                               return -EIO;
-
-                       cnow = tport->tp_icount;
-                       if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
-                           cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
-                               return -EIO; /* no change => error */
-                       if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
-                           ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
-                           ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
-                           ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)))
-                               return 0;
-                       cprev = cnow;
-               }
-               break;
        }
        return -ENOIOCTLCMD;
 }
@@ -1156,7 +1103,7 @@ static void ti_bulk_in_callback(struct urb *urb)
                else
                        ti_recv(port, urb->transfer_buffer, urb->actual_length);
                spin_lock(&tport->tp_lock);
-               tport->tp_icount.rx += urb->actual_length;
+               port->icount.rx += urb->actual_length;
                spin_unlock(&tport->tp_lock);
        }
 
@@ -1265,7 +1212,7 @@ static void ti_send(struct ti_port *tport)
                /* TODO: reschedule ti_send */
        } else {
                spin_lock_irqsave(&tport->tp_lock, flags);
-               tport->tp_icount.tx += count;
+               port->icount.tx += count;
                spin_unlock_irqrestore(&tport->tp_lock, flags);
        }
 
@@ -1385,7 +1332,7 @@ static void ti_handle_new_msr(struct ti_port *tport, __u8 msr)
 
        if (msr & TI_MSR_DELTA_MASK) {
                spin_lock_irqsave(&tport->tp_lock, flags);
-               icount = &tport->tp_icount;
+               icount = &tport->tp_port->icount;
                if (msr & TI_MSR_DELTA_CTS)
                        icount->cts++;
                if (msr & TI_MSR_DELTA_DSR)
@@ -1394,7 +1341,7 @@ static void ti_handle_new_msr(struct ti_port *tport, __u8 msr)
                        icount->dcd++;
                if (msr & TI_MSR_DELTA_RI)
                        icount->rng++;
-               wake_up_interruptible(&tport->tp_port->delta_msr_wait);
+               wake_up_interruptible(&tport->tp_port->port.delta_msr_wait);
                spin_unlock_irqrestore(&tport->tp_lock, flags);
        }
 
index 5d9b178484fdf805bfd9a6e264732d5082216088..5eb96df8de05bdcd659974e587ca3121092f30fb 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * USB Serial Converter driver
  *
+ * Copyright (C) 2009 - 2013 Johan Hovold (jhovold@gmail.com)
  * Copyright (C) 1999 - 2012 Greg Kroah-Hartman (greg@kroah.com)
  * Copyright (C) 2000 Peter Berger (pberger@brimson.com)
  * Copyright (C) 2000 Al Borchers (borchers@steinerpoint.com)
@@ -14,7 +15,6 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this
  * driver
- *
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -49,7 +49,6 @@
    drivers depend on it.
 */
 
-/* initially all NULL */
 static struct usb_serial *serial_table[SERIAL_TTY_MINORS];
 static DEFINE_MUTEX(table_lock);
 static LIST_HEAD(usb_serial_driver_list);
@@ -139,7 +138,7 @@ static void destroy_serial(struct kref *kref)
        if (serial->minor != SERIAL_TTY_NO_MINOR)
                return_serial(serial);
 
-       if (serial->attached)
+       if (serial->attached && serial->type->release)
                serial->type->release(serial);
 
        /* Now that nothing is using the ports, they can be freed */
@@ -225,7 +224,7 @@ static int serial_install(struct tty_driver *driver, struct tty_struct *tty)
        return retval;
 }
 
-static int serial_activate(struct tty_port *tport, struct tty_struct *tty)
+static int serial_port_activate(struct tty_port *tport, struct tty_struct *tty)
 {
        struct usb_serial_port *port =
                container_of(tport, struct usb_serial_port, port);
@@ -249,30 +248,27 @@ static int serial_open(struct tty_struct *tty, struct file *filp)
 {
        struct usb_serial_port *port = tty->driver_data;
 
-       dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+       dev_dbg(tty->dev, "%s\n", __func__);
+
        return tty_port_open(&port->port, tty, filp);
 }
 
 /**
- * serial_down - shut down hardware
+ * serial_port_shutdown - shut down hardware
  * @tport: tty port to shut down
  *
- * Shut down a USB serial port unless it is the console.  We never
- * shut down the console hardware as it will always be in use. Serialized
- * against activate by the tport mutex and kept to matching open/close pairs
+ * Shut down a USB serial port. Serialized against activate by the
+ * tport mutex and kept to matching open/close pairs
  * of calls by the ASYNCB_INITIALIZED flag.
+ *
+ * Not called if tty is console.
  */
-static void serial_down(struct tty_port *tport)
+static void serial_port_shutdown(struct tty_port *tport)
 {
        struct usb_serial_port *port =
                container_of(tport, struct usb_serial_port, port);
        struct usb_serial_driver *drv = port->serial->type;
-       /*
-        * The console is magical.  Do not hang up the console hardware
-        * or there will be tears.
-        */
-       if (port->port.console)
-               return;
+
        if (drv->close)
                drv->close(port);
 }
@@ -281,7 +277,8 @@ static void serial_hangup(struct tty_struct *tty)
 {
        struct usb_serial_port *port = tty->driver_data;
 
-       dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+       dev_dbg(tty->dev, "%s\n", __func__);
+
        tty_port_hangup(&port->port);
 }
 
@@ -289,7 +286,8 @@ static void serial_close(struct tty_struct *tty, struct file *filp)
 {
        struct usb_serial_port *port = tty->driver_data;
 
-       dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+       dev_dbg(tty->dev, "%s\n", __func__);
+
        tty_port_close(&port->port, tty, filp);
 }
 
@@ -308,14 +306,14 @@ static void serial_cleanup(struct tty_struct *tty)
        struct usb_serial *serial;
        struct module *owner;
 
+       dev_dbg(tty->dev, "%s\n", __func__);
+
        /* The console is magical.  Do not hang up the console hardware
         * or there will be tears.
         */
        if (port->port.console)
                return;
 
-       dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
-
        tty->driver_data = NULL;
 
        serial = port->serial;
@@ -339,10 +337,8 @@ static int serial_write(struct tty_struct *tty, const unsigned char *buf,
        if (port->serial->dev->state == USB_STATE_NOTATTACHED)
                goto exit;
 
-       dev_dbg(tty->dev, "%s - port %d, %d byte(s)\n", __func__,
-               port->number, count);
+       dev_dbg(tty->dev, "%s - %d byte(s)\n", __func__, count);
 
-       /* pass on to the driver specific version of this function */
        retval = port->serial->type->write(tty, port, buf, count);
        if (retval < 0)
                retval = usb_translate_errors(retval);
@@ -354,8 +350,8 @@ static int serial_write_room(struct tty_struct *tty)
 {
        struct usb_serial_port *port = tty->driver_data;
 
-       dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
-       /* pass on to the driver specific version of this function */
+       dev_dbg(tty->dev, "%s\n", __func__);
+
        return port->serial->type->write_room(tty);
 }
 
@@ -365,7 +361,7 @@ static int serial_chars_in_buffer(struct tty_struct *tty)
        struct usb_serial *serial = port->serial;
        int count = 0;
 
-       dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+       dev_dbg(tty->dev, "%s\n", __func__);
 
        mutex_lock(&serial->disc_mutex);
        /* if the device was unplugged then any remaining characters
@@ -383,9 +379,8 @@ static void serial_throttle(struct tty_struct *tty)
 {
        struct usb_serial_port *port = tty->driver_data;
 
-       dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+       dev_dbg(tty->dev, "%s\n", __func__);
 
-       /* pass on to the driver specific version of this function */
        if (port->serial->type->throttle)
                port->serial->type->throttle(tty);
 }
@@ -394,9 +389,8 @@ static void serial_unthrottle(struct tty_struct *tty)
 {
        struct usb_serial_port *port = tty->driver_data;
 
-       dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+       dev_dbg(tty->dev, "%s\n", __func__);
 
-       /* pass on to the driver specific version of this function */
        if (port->serial->type->unthrottle)
                port->serial->type->unthrottle(tty);
 }
@@ -407,15 +401,20 @@ static int serial_ioctl(struct tty_struct *tty,
        struct usb_serial_port *port = tty->driver_data;
        int retval = -ENODEV;
 
-       dev_dbg(tty->dev, "%s - port %d, cmd 0x%.4x\n", __func__,
-               port->number, cmd);
+       dev_dbg(tty->dev, "%s - cmd 0x%.4x\n", __func__, cmd);
+
+       switch (cmd) {
+       case TIOCMIWAIT:
+               if (port->serial->type->tiocmiwait)
+                       retval = port->serial->type->tiocmiwait(tty, arg);
+               break;
+       default:
+               if (port->serial->type->ioctl)
+                       retval = port->serial->type->ioctl(tty, cmd, arg);
+               else
+                       retval = -ENOIOCTLCMD;
+       }
 
-       /* pass on to the driver specific version of this function
-          if it is available */
-       if (port->serial->type->ioctl) {
-               retval = port->serial->type->ioctl(tty, cmd, arg);
-       } else
-               retval = -ENOIOCTLCMD;
        return retval;
 }
 
@@ -423,10 +422,8 @@ static void serial_set_termios(struct tty_struct *tty, struct ktermios *old)
 {
        struct usb_serial_port *port = tty->driver_data;
 
-       dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+       dev_dbg(tty->dev, "%s\n", __func__);
 
-       /* pass on to the driver specific version of this function
-          if it is available */
        if (port->serial->type->set_termios)
                port->serial->type->set_termios(tty, port, old);
        else
@@ -437,12 +434,11 @@ static int serial_break(struct tty_struct *tty, int break_state)
 {
        struct usb_serial_port *port = tty->driver_data;
 
-       dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+       dev_dbg(tty->dev, "%s\n", __func__);
 
-       /* pass on to the driver specific version of this function
-          if it is available */
        if (port->serial->type->break_ctl)
                port->serial->type->break_ctl(tty, break_state);
+
        return 0;
 }
 
@@ -496,7 +492,7 @@ static int serial_tiocmget(struct tty_struct *tty)
 {
        struct usb_serial_port *port = tty->driver_data;
 
-       dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+       dev_dbg(tty->dev, "%s\n", __func__);
 
        if (port->serial->type->tiocmget)
                return port->serial->type->tiocmget(tty);
@@ -508,7 +504,7 @@ static int serial_tiocmset(struct tty_struct *tty,
 {
        struct usb_serial_port *port = tty->driver_data;
 
-       dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+       dev_dbg(tty->dev, "%s\n", __func__);
 
        if (port->serial->type->tiocmset)
                return port->serial->type->tiocmset(tty, set, clear);
@@ -520,7 +516,7 @@ static int serial_get_icount(struct tty_struct *tty,
 {
        struct usb_serial_port *port = tty->driver_data;
 
-       dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+       dev_dbg(tty->dev, "%s\n", __func__);
 
        if (port->serial->type->get_icount)
                return port->serial->type->get_icount(tty, icount);
@@ -548,49 +544,45 @@ static void usb_serial_port_work(struct work_struct *work)
        if (!tty)
                return;
 
-       dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+       dev_dbg(tty->dev, "%s\n", __func__);
 
        tty_wakeup(tty);
        tty_kref_put(tty);
 }
 
-static void kill_traffic(struct usb_serial_port *port)
+static void usb_serial_port_poison_urbs(struct usb_serial_port *port)
 {
        int i;
 
        for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i)
-               usb_kill_urb(port->read_urbs[i]);
+               usb_poison_urb(port->read_urbs[i]);
        for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i)
-               usb_kill_urb(port->write_urbs[i]);
-       /*
-        * This is tricky.
-        * Some drivers submit the read_urb in the
-        * handler for the write_urb or vice versa
-        * this order determines the order in which
-        * usb_kill_urb() must be used to reliably
-        * kill the URBs. As it is unknown here,
-        * both orders must be used in turn.
-        * The call below is not redundant.
-        */
-       usb_kill_urb(port->read_urb);
-       usb_kill_urb(port->interrupt_in_urb);
-       usb_kill_urb(port->interrupt_out_urb);
+               usb_poison_urb(port->write_urbs[i]);
+
+       usb_poison_urb(port->interrupt_in_urb);
+       usb_poison_urb(port->interrupt_out_urb);
+}
+
+static void usb_serial_port_unpoison_urbs(struct usb_serial_port *port)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i)
+               usb_unpoison_urb(port->read_urbs[i]);
+       for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i)
+               usb_unpoison_urb(port->write_urbs[i]);
+
+       usb_unpoison_urb(port->interrupt_in_urb);
+       usb_unpoison_urb(port->interrupt_out_urb);
 }
 
-static void port_release(struct device *dev)
+static void usb_serial_port_release(struct device *dev)
 {
        struct usb_serial_port *port = to_usb_serial_port(dev);
        int i;
 
        dev_dbg(dev, "%s\n", __func__);
 
-       /*
-        * Stop all the traffic before cancelling the work, so that
-        * nobody will restart it by calling usb_serial_port_softint.
-        */
-       kill_traffic(port);
-       cancel_work_sync(&port->work);
-
        usb_free_urb(port->interrupt_in_urb);
        usb_free_urb(port->interrupt_out_urb);
        for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) {
@@ -615,10 +607,8 @@ static struct usb_serial *create_serial(struct usb_device *dev,
        struct usb_serial *serial;
 
        serial = kzalloc(sizeof(*serial), GFP_KERNEL);
-       if (!serial) {
-               dev_err(&dev->dev, "%s - out of memory\n", __func__);
+       if (!serial)
                return NULL;
-       }
        serial->dev = usb_get_dev(dev);
        serial->type = driver;
        serial->interface = usb_get_intf(interface);
@@ -681,7 +671,7 @@ static struct usb_serial_driver *search_serial_device(
        return NULL;
 }
 
-static int serial_carrier_raised(struct tty_port *port)
+static int serial_port_carrier_raised(struct tty_port *port)
 {
        struct usb_serial_port *p = container_of(port, struct usb_serial_port, port);
        struct usb_serial_driver *drv = p->serial->type;
@@ -692,7 +682,7 @@ static int serial_carrier_raised(struct tty_port *port)
        return 1;
 }
 
-static void serial_dtr_rts(struct tty_port *port, int on)
+static void serial_port_dtr_rts(struct tty_port *port, int on)
 {
        struct usb_serial_port *p = container_of(port, struct usb_serial_port, port);
        struct usb_serial *serial = p->serial;
@@ -712,10 +702,10 @@ static void serial_dtr_rts(struct tty_port *port, int on)
 }
 
 static const struct tty_port_operations serial_port_ops = {
-       .carrier_raised = serial_carrier_raised,
-       .dtr_rts = serial_dtr_rts,
-       .activate = serial_activate,
-       .shutdown = serial_down,
+       .carrier_raised         = serial_port_carrier_raised,
+       .dtr_rts                = serial_port_dtr_rts,
+       .activate               = serial_port_activate,
+       .shutdown               = serial_port_shutdown,
 };
 
 static int usb_serial_probe(struct usb_interface *interface,
@@ -762,7 +752,6 @@ static int usb_serial_probe(struct usb_interface *interface,
        serial = create_serial(dev, interface, type);
        if (!serial) {
                module_put(type->driver.owner);
-               dev_err(ddev, "%s - out of memory\n", __func__);
                return -ENOMEM;
        }
 
@@ -903,7 +892,6 @@ static int usb_serial_probe(struct usb_interface *interface,
                port->port.ops = &serial_port_ops;
                port->serial = serial;
                spin_lock_init(&port->lock);
-               init_waitqueue_head(&port->delta_msr_wait);
                /* Keep this for private driver use for the moment but
                   should probably go away */
                INIT_WORK(&port->work, usb_serial_port_work);
@@ -911,7 +899,7 @@ static int usb_serial_probe(struct usb_interface *interface,
                port->dev.parent = &interface->dev;
                port->dev.driver = NULL;
                port->dev.bus = &usb_serial_bus_type;
-               port->dev.release = &port_release;
+               port->dev.release = &usb_serial_port_release;
                device_initialize(&port->dev);
        }
 
@@ -927,16 +915,12 @@ static int usb_serial_probe(struct usb_interface *interface,
                for (j = 0; j < ARRAY_SIZE(port->read_urbs); ++j) {
                        set_bit(j, &port->read_urbs_free);
                        port->read_urbs[j] = usb_alloc_urb(0, GFP_KERNEL);
-                       if (!port->read_urbs[j]) {
-                               dev_err(ddev, "No free urbs available\n");
+                       if (!port->read_urbs[j])
                                goto probe_error;
-                       }
                        port->bulk_in_buffers[j] = kmalloc(buffer_size,
                                                                GFP_KERNEL);
-                       if (!port->bulk_in_buffers[j]) {
-                               dev_err(ddev, "Couldn't allocate bulk_in_buffer\n");
+                       if (!port->bulk_in_buffers[j])
                                goto probe_error;
-                       }
                        usb_fill_bulk_urb(port->read_urbs[j], dev,
                                        usb_rcvbulkpipe(dev,
                                                endpoint->bEndpointAddress),
@@ -963,16 +947,12 @@ static int usb_serial_probe(struct usb_interface *interface,
                for (j = 0; j < ARRAY_SIZE(port->write_urbs); ++j) {
                        set_bit(j, &port->write_urbs_free);
                        port->write_urbs[j] = usb_alloc_urb(0, GFP_KERNEL);
-                       if (!port->write_urbs[j]) {
-                               dev_err(ddev, "No free urbs available\n");
+                       if (!port->write_urbs[j])
                                goto probe_error;
-                       }
                        port->bulk_out_buffers[j] = kmalloc(buffer_size,
                                                                GFP_KERNEL);
-                       if (!port->bulk_out_buffers[j]) {
-                               dev_err(ddev, "Couldn't allocate bulk_out_buffer\n");
+                       if (!port->bulk_out_buffers[j])
                                goto probe_error;
-                       }
                        usb_fill_bulk_urb(port->write_urbs[j], dev,
                                        usb_sndbulkpipe(dev,
                                                endpoint->bEndpointAddress),
@@ -990,19 +970,15 @@ static int usb_serial_probe(struct usb_interface *interface,
                        endpoint = interrupt_in_endpoint[i];
                        port = serial->port[i];
                        port->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);
-                       if (!port->interrupt_in_urb) {
-                               dev_err(ddev, "No free urbs available\n");
+                       if (!port->interrupt_in_urb)
                                goto probe_error;
-                       }
                        buffer_size = usb_endpoint_maxp(endpoint);
                        port->interrupt_in_endpointAddress =
                                                endpoint->bEndpointAddress;
                        port->interrupt_in_buffer = kmalloc(buffer_size,
                                                                GFP_KERNEL);
-                       if (!port->interrupt_in_buffer) {
-                               dev_err(ddev, "Couldn't allocate interrupt_in_buffer\n");
+                       if (!port->interrupt_in_buffer)
                                goto probe_error;
-                       }
                        usb_fill_int_urb(port->interrupt_in_urb, dev,
                                usb_rcvintpipe(dev,
                                                endpoint->bEndpointAddress),
@@ -1019,20 +995,16 @@ static int usb_serial_probe(struct usb_interface *interface,
                        endpoint = interrupt_out_endpoint[i];
                        port = serial->port[i];
                        port->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL);
-                       if (!port->interrupt_out_urb) {
-                               dev_err(ddev, "No free urbs available\n");
+                       if (!port->interrupt_out_urb)
                                goto probe_error;
-                       }
                        buffer_size = usb_endpoint_maxp(endpoint);
                        port->interrupt_out_size = buffer_size;
                        port->interrupt_out_endpointAddress =
                                                endpoint->bEndpointAddress;
                        port->interrupt_out_buffer = kmalloc(buffer_size,
                                                                GFP_KERNEL);
-                       if (!port->interrupt_out_buffer) {
-                               dev_err(ddev, "Couldn't allocate interrupt_out_buffer\n");
+                       if (!port->interrupt_out_buffer)
                                goto probe_error;
-                       }
                        usb_fill_int_urb(port->interrupt_out_urb, dev,
                                usb_sndintpipe(dev,
                                                  endpoint->bEndpointAddress),
@@ -1121,13 +1093,15 @@ static void usb_serial_disconnect(struct usb_interface *interface)
                                tty_vhangup(tty);
                                tty_kref_put(tty);
                        }
-                       kill_traffic(port);
+                       usb_serial_port_poison_urbs(port);
+                       wake_up_interruptible(&port->port.delta_msr_wait);
                        cancel_work_sync(&port->work);
                        if (device_is_registered(&port->dev))
                                device_del(&port->dev);
                }
        }
-       serial->type->disconnect(serial);
+       if (serial->type->disconnect)
+               serial->type->disconnect(serial);
 
        /* let the last holder of this object cause it to be cleaned up */
        usb_serial_put(serial);
@@ -1142,6 +1116,11 @@ int usb_serial_suspend(struct usb_interface *intf, pm_message_t message)
 
        serial->suspending = 1;
 
+       /*
+        * serial->type->suspend() MUST return 0 in system sleep context,
+        * otherwise, the resume callback has to recover device from
+        * previous suspend failure.
+        */
        if (serial->type->suspend) {
                r = serial->type->suspend(serial, message);
                if (r < 0) {
@@ -1153,7 +1132,7 @@ int usb_serial_suspend(struct usb_interface *intf, pm_message_t message)
        for (i = 0; i < serial->num_ports; ++i) {
                port = serial->port[i];
                if (port)
-                       kill_traffic(port);
+                       usb_serial_port_poison_urbs(port);
        }
 
 err_out:
@@ -1161,11 +1140,25 @@ err_out:
 }
 EXPORT_SYMBOL(usb_serial_suspend);
 
+static void usb_serial_unpoison_port_urbs(struct usb_serial *serial)
+{
+       struct usb_serial_port *port;
+       int i;
+
+       for (i = 0; i < serial->num_ports; ++i) {
+               port = serial->port[i];
+               if (port)
+                       usb_serial_port_unpoison_urbs(port);
+       }
+}
+
 int usb_serial_resume(struct usb_interface *intf)
 {
        struct usb_serial *serial = usb_get_intfdata(intf);
        int rv;
 
+       usb_serial_unpoison_port_urbs(serial);
+
        serial->suspending = 0;
        if (serial->type->resume)
                rv = serial->type->resume(serial);
@@ -1181,6 +1174,8 @@ static int usb_serial_reset_resume(struct usb_interface *intf)
        struct usb_serial *serial = usb_get_intfdata(intf);
        int rv;
 
+       usb_serial_unpoison_port_urbs(serial);
+
        serial->suspending = 0;
        if (serial->type->reset_resume)
                rv = serial->type->reset_resume(serial);
@@ -1317,12 +1312,12 @@ module_exit(usb_serial_exit);
        do {                                                            \
                if (!type->function) {                                  \
                        type->function = usb_serial_generic_##function; \
-                       pr_debug("Had to override the " #function       \
-                               " usb serial operation with the generic one.");\
-                       }                                               \
+                       pr_debug("%s: using generic " #function "\n",   \
+                                               type->driver.name);     \
+               }                                                       \
        } while (0)
 
-static void fixup_generic(struct usb_serial_driver *device)
+static void usb_serial_operations_init(struct usb_serial_driver *device)
 {
        set_to_generic_if_null(device, open);
        set_to_generic_if_null(device, write);
@@ -1331,8 +1326,6 @@ static void fixup_generic(struct usb_serial_driver *device)
        set_to_generic_if_null(device, chars_in_buffer);
        set_to_generic_if_null(device, read_bulk_callback);
        set_to_generic_if_null(device, write_bulk_callback);
-       set_to_generic_if_null(device, disconnect);
-       set_to_generic_if_null(device, release);
        set_to_generic_if_null(device, process_read_urb);
        set_to_generic_if_null(device, prepare_write_buffer);
 }
@@ -1344,8 +1337,6 @@ static int usb_serial_register(struct usb_serial_driver *driver)
        if (usb_disabled())
                return -ENODEV;
 
-       fixup_generic(driver);
-
        if (!driver->description)
                driver->description = driver->driver.name;
        if (!driver->usb_driver) {
@@ -1354,6 +1345,8 @@ static int usb_serial_register(struct usb_serial_driver *driver)
                return -EINVAL;
        }
 
+       usb_serial_operations_init(driver);
+
        /* Add this device to our list of devices */
        mutex_lock(&table_lock);
        list_add(&driver->driver_list, &usb_serial_driver_list);
@@ -1471,7 +1464,6 @@ void usb_serial_deregister_drivers(struct usb_serial_driver *const serial_driver
 }
 EXPORT_SYMBOL_GPL(usb_serial_deregister_drivers);
 
-/* Module information */
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
index 571965aa1cc015257eaf4bde8316ce10045a82a0..ece326ef63a0b64c831e5f541b7171b95a9761f6 100644 (file)
@@ -421,20 +421,19 @@ void usb_wwan_close(struct usb_serial_port *port)
 
        portdata = usb_get_serial_port_data(port);
 
-       if (serial->dev) {
-               /* Stop reading/writing urbs */
-               spin_lock_irq(&intfdata->susp_lock);
-               portdata->opened = 0;
-               spin_unlock_irq(&intfdata->susp_lock);
+       /* Stop reading/writing urbs */
+       spin_lock_irq(&intfdata->susp_lock);
+       portdata->opened = 0;
+       spin_unlock_irq(&intfdata->susp_lock);
 
-               for (i = 0; i < N_IN_URB; i++)
-                       usb_kill_urb(portdata->in_urbs[i]);
-               for (i = 0; i < N_OUT_URB; i++)
-                       usb_kill_urb(portdata->out_urbs[i]);
-               /* balancing - important as an error cannot be handled*/
-               usb_autopm_get_interface_no_resume(serial->interface);
-               serial->interface->needs_remote_wakeup = 0;
-       }
+       for (i = 0; i < N_IN_URB; i++)
+               usb_kill_urb(portdata->in_urbs[i]);
+       for (i = 0; i < N_OUT_URB; i++)
+               usb_kill_urb(portdata->out_urbs[i]);
+
+       /* balancing - important as an error cannot be handled*/
+       usb_autopm_get_interface_no_resume(serial->interface);
+       serial->interface->needs_remote_wakeup = 0;
 }
 EXPORT_SYMBOL(usb_wwan_close);
 
index 1129aa73c23e93643ab273f578533ce85e04dc2c..7573ec8a084f3f55c1f2597c2f2b699e58790351 100644 (file)
@@ -257,24 +257,18 @@ static void visor_close(struct usb_serial_port *port)
 {
        unsigned char *transfer_buffer;
 
-       /* shutdown our urbs */
        usb_serial_generic_close(port);
        usb_kill_urb(port->interrupt_in_urb);
 
-       mutex_lock(&port->serial->disc_mutex);
-       if (!port->serial->disconnected) {
-               /* Try to send shutdown message, unless the device is gone */
-               transfer_buffer =  kmalloc(0x12, GFP_KERNEL);
-               if (transfer_buffer) {
-                       usb_control_msg(port->serial->dev,
+       transfer_buffer = kmalloc(0x12, GFP_KERNEL);
+       if (!transfer_buffer)
+               return;
+       usb_control_msg(port->serial->dev,
                                         usb_rcvctrlpipe(port->serial->dev, 0),
                                         VISOR_CLOSE_NOTIFICATION, 0xc2,
                                         0x0000, 0x0000,
                                         transfer_buffer, 0x12, 300);
-                       kfree(transfer_buffer);
-               }
-       }
-       mutex_unlock(&port->serial->disc_mutex);
+       kfree(transfer_buffer);
 }
 
 static void visor_read_int_callback(struct urb *urb)
index ecea4787736463ccda4d1a498749eed74c2c9136..06a3d22db685da2913b64070c397227840bf9ff8 100644 (file)
@@ -1457,8 +1457,7 @@ static int isd200_init_info(struct us_data *us)
                retStatus = ISD200_ERROR;
        else {
                info->id = kzalloc(ATA_ID_WORDS * 2, GFP_KERNEL);
-               info->RegsBuf = (unsigned char *)
-                               kmalloc(sizeof(info->ATARegs), GFP_KERNEL);
+               info->RegsBuf = kmalloc(sizeof(info->ATARegs), GFP_KERNEL);
                info->srb.sense_buffer =
                                kmalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL);
                if (!info->id || !info->RegsBuf || !info->srb.sense_buffer) {
index cb79de61f4c837e191e1e8de0616e9b06d33d5fe..26964895c88b50ea0ce9bbc51a63e62bfda8f37c 100644 (file)
@@ -195,6 +195,7 @@ static int onetouch_connect_input(struct us_data *ss)
 
        pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
        maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
+       maxp = min(maxp, ONETOUCH_PKT_LEN);
 
        onetouch = kzalloc(sizeof(struct usb_onetouch), GFP_KERNEL);
        input_dev = input_allocate_device();
@@ -245,8 +246,7 @@ static int onetouch_connect_input(struct us_data *ss)
        input_dev->open = usb_onetouch_open;
        input_dev->close = usb_onetouch_close;
 
-       usb_fill_int_urb(onetouch->irq, udev, pipe, onetouch->data,
-                        (maxp > 8 ? 8 : maxp),
+       usb_fill_int_urb(onetouch->irq, udev, pipe, onetouch->data, maxp,
                         usb_onetouch_irq, onetouch, endpoint->bInterval);
        onetouch->irq->transfer_dma = onetouch->data_dma;
        onetouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
index ce310170829fdc66442a8c7b629fc028152c96af..7ed3b039dbe878a8a7c7db038e6150c3395e5bec 100644 (file)
@@ -61,11 +61,10 @@ struct usb_skel {
        __u8                    bulk_out_endpointAddr;  /* the address of the bulk out endpoint */
        int                     errors;                 /* the last request tanked */
        bool                    ongoing_read;           /* a read is going on */
-       bool                    processed_urb;          /* indicates we haven't processed the urb */
        spinlock_t              err_lock;               /* lock for errors */
        struct kref             kref;
        struct mutex            io_mutex;               /* synchronize I/O with disconnect */
-       struct completion       bulk_in_completion;     /* to wait for an ongoing read */
+       wait_queue_head_t       bulk_in_wait;           /* to wait for an ongoing read */
 };
 #define to_skel_dev(d) container_of(d, struct usb_skel, kref)
 
@@ -185,7 +184,7 @@ static void skel_read_bulk_callback(struct urb *urb)
        dev->ongoing_read = 0;
        spin_unlock(&dev->err_lock);
 
-       complete(&dev->bulk_in_completion);
+       wake_up_interruptible(&dev->bulk_in_wait);
 }
 
 static int skel_do_read_io(struct usb_skel *dev, size_t count)
@@ -206,13 +205,16 @@ static int skel_do_read_io(struct usb_skel *dev, size_t count)
        dev->ongoing_read = 1;
        spin_unlock_irq(&dev->err_lock);
 
+       /* submit bulk in urb, which means no data to deliver */
+       dev->bulk_in_filled = 0;
+       dev->bulk_in_copied = 0;
+
        /* do it */
        rv = usb_submit_urb(dev->bulk_in_urb, GFP_KERNEL);
        if (rv < 0) {
                dev_err(&dev->interface->dev,
                        "%s - failed submitting read urb, error %d\n",
                        __func__, rv);
-               dev->bulk_in_filled = 0;
                rv = (rv == -ENOMEM) ? rv : -EIO;
                spin_lock_irq(&dev->err_lock);
                dev->ongoing_read = 0;
@@ -261,25 +263,9 @@ retry:
                 * IO may take forever
                 * hence wait in an interruptible state
                 */
-               rv = wait_for_completion_interruptible(&dev->bulk_in_completion);
+               rv = wait_event_interruptible(dev->bulk_in_wait, (!dev->ongoing_read));
                if (rv < 0)
                        goto exit;
-               /*
-                * by waiting we also semiprocessed the urb
-                * we must finish now
-                */
-               dev->bulk_in_copied = 0;
-               dev->processed_urb = 1;
-       }
-
-       if (!dev->processed_urb) {
-               /*
-                * the URB hasn't been processed
-                * do it now
-                */
-               wait_for_completion(&dev->bulk_in_completion);
-               dev->bulk_in_copied = 0;
-               dev->processed_urb = 1;
        }
 
        /* errors must be reported */
@@ -289,8 +275,6 @@ retry:
                dev->errors = 0;
                /* to preserve notifications about reset */
                rv = (rv == -EPIPE) ? rv : -EIO;
-               /* no data to deliver */
-               dev->bulk_in_filled = 0;
                /* report it */
                goto exit;
        }
@@ -526,7 +510,7 @@ static int skel_probe(struct usb_interface *interface,
        mutex_init(&dev->io_mutex);
        spin_lock_init(&dev->err_lock);
        init_usb_anchor(&dev->submitted);
-       init_completion(&dev->bulk_in_completion);
+       init_waitqueue_head(&dev->bulk_in_wait);
 
        dev->udev = usb_get_dev(interface_to_usbdev(interface));
        dev->interface = interface;
index 4d22d0f6167aa49b653c8d942c2e00d61be689b8..a0bee5a28d1a578a27829edd231968e1ff11ce1d 100644 (file)
@@ -469,14 +469,12 @@ struct usb3_lpm_parameters {
  * @lpm_capable: device supports LPM
  * @usb2_hw_lpm_capable: device can perform USB2 hardware LPM
  * @usb2_hw_lpm_enabled: USB2 hardware LPM enabled
+ * @usb3_lpm_enabled: USB3 hardware LPM enabled
  * @string_langid: language ID for strings
  * @product: iProduct string, if present (static)
  * @manufacturer: iManufacturer string, if present (static)
  * @serial: iSerialNumber string, if present (static)
  * @filelist: usbfs files that are open to this device
- * @usb_classdev: USB class device that was created for usbfs device
- *     access from userspace
- * @usbfs_dentry: usbfs dentry entry for the device
  * @maxchild: number of ports if hub
  * @quirks: quirks of the whole device
  * @urbnum: number of URBs submitted for the whole device
@@ -619,7 +617,7 @@ static inline bool usb_acpi_power_manageable(struct usb_device *hdev, int index)
 #endif
 
 /* USB autosuspend and autoresume */
-#ifdef CONFIG_USB_SUSPEND
+#ifdef CONFIG_PM_RUNTIME
 extern void usb_enable_autosuspend(struct usb_device *udev);
 extern void usb_disable_autosuspend(struct usb_device *udev);
 
@@ -978,7 +976,12 @@ struct usbdrv_wrap {
  *     the "usbfs" filesystem.  This lets devices provide ways to
  *     expose information to user space regardless of where they
  *     do (or don't) show up otherwise in the filesystem.
- * @suspend: Called when the device is going to be suspended by the system.
+ * @suspend: Called when the device is going to be suspended by the
+ *     system either from system sleep or runtime suspend context. The
+ *     return value will be ignored in system sleep context, so do NOT
+ *     try to continue using the device if suspend fails in this case.
+ *     Instead, let the resume or reset-resume routine recover from
+ *     the failure.
  * @resume: Called when the device is being resumed by the system.
  * @reset_resume: Called when the suspended device has been reset instead
  *     of being resumed.
index 719c332620fa7688bfa440c0cc1fc3472ffd40d9..0b3f4295c0254ae4ecc0b4ae999a5fe363731875 100644 (file)
@@ -11,6 +11,8 @@
 #ifndef __LINUX_USB_CDC_WDM_H
 #define __LINUX_USB_CDC_WDM_H
 
+#include <uapi/linux/usb/cdc-wdm.h>
+
 extern struct usb_driver *usb_cdc_wdm_register(struct usb_interface *intf,
                                        struct usb_endpoint_descriptor *ep,
                                        int bufsize,
index 59694b5e5e906821a873d52a1a33b9c5d67af5d4..f5f5c7dfda90ebe2656176c058672b75854c3176 100644 (file)
@@ -84,7 +84,7 @@ struct usb_hcd {
 
        struct timer_list       rh_timer;       /* drives root-hub polling */
        struct urb              *status_urb;    /* the current status urb */
-#ifdef CONFIG_USB_SUSPEND
+#ifdef CONFIG_PM_RUNTIME
        struct work_struct      wakeup_work;    /* for remote wakeup */
 #endif
 
@@ -593,14 +593,14 @@ extern int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg);
 extern int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg);
 #endif /* CONFIG_PM */
 
-#ifdef CONFIG_USB_SUSPEND
+#ifdef CONFIG_PM_RUNTIME
 extern void usb_hcd_resume_root_hub(struct usb_hcd *hcd);
 #else
 static inline void usb_hcd_resume_root_hub(struct usb_hcd *hcd)
 {
        return;
 }
-#endif /* CONFIG_USB_SUSPEND */
+#endif /* CONFIG_PM_RUNTIME */
 
 /*-------------------------------------------------------------------------*/
 
index 1819b59aab2a697aa573cbf8fe4e1081292dc713..b9b0f7b4e43b81c4829802b5f0eea0cd0713974d 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <linux/kref.h>
 #include <linux/mutex.h>
+#include <linux/serial.h>
 #include <linux/sysrq.h>
 #include <linux/kfifo.h>
 
  * @bulk_out_buffers: pointers to the bulk out buffers for this port
  * @write_urbs: pointers to the bulk out urbs for this port
  * @write_urbs_free: status bitmap the for bulk out urbs
+ * @icount: interrupt counters
  * @tx_bytes: number of bytes currently in host stack queues
  * @bulk_out_endpointAddress: endpoint address for the bulk out pipe for this
  *     port.
  * @flags: usb serial port flags
  * @write_wait: a wait_queue_head_t used by the port.
- * @delta_msr_wait: modem-status-change wait queue
  * @work: work queue entry for the line discipline waking up.
  * @throttled: nonzero if the read urb is inactive to throttle the device
  * @throttle_req: nonzero if the tty wants to throttle us
@@ -109,11 +110,11 @@ struct usb_serial_port {
        unsigned long           write_urbs_free;
        __u8                    bulk_out_endpointAddress;
 
+       struct async_icount     icount;
        int                     tx_bytes;
 
        unsigned long           flags;
        wait_queue_head_t       write_wait;
-       wait_queue_head_t       delta_msr_wait;
        struct work_struct      work;
        char                    throttled;
        char                    throttle_req;
@@ -272,6 +273,7 @@ struct usb_serial_driver {
        int  (*tiocmget)(struct tty_struct *tty);
        int  (*tiocmset)(struct tty_struct *tty,
                         unsigned int set, unsigned int clear);
+       int  (*tiocmiwait)(struct tty_struct *tty, unsigned long arg);
        int  (*get_icount)(struct tty_struct *tty,
                        struct serial_icounter_struct *icount);
        /* Called by the tty layer for port level work. There may or may not
@@ -329,8 +331,10 @@ extern void usb_serial_generic_read_bulk_callback(struct urb *urb);
 extern void usb_serial_generic_write_bulk_callback(struct urb *urb);
 extern void usb_serial_generic_throttle(struct tty_struct *tty);
 extern void usb_serial_generic_unthrottle(struct tty_struct *tty);
-extern void usb_serial_generic_disconnect(struct usb_serial *serial);
-extern void usb_serial_generic_release(struct usb_serial *serial);
+extern int usb_serial_generic_tiocmiwait(struct tty_struct *tty,
+                                                       unsigned long arg);
+extern int usb_serial_generic_get_icount(struct tty_struct *tty,
+                                       struct serial_icounter_struct *icount);
 extern int usb_serial_generic_register(void);
 extern void usb_serial_generic_deregister(void);
 extern int usb_serial_generic_submit_read_urbs(struct usb_serial_port *port,
diff --git a/include/uapi/linux/usb/cdc-wdm.h b/include/uapi/linux/usb/cdc-wdm.h
new file mode 100644 (file)
index 0000000..f03134f
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * USB CDC Device Management userspace API definitions
+ *
+ * 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.
+ */
+
+#ifndef _UAPI__LINUX_USB_CDC_WDM_H
+#define _UAPI__LINUX_USB_CDC_WDM_H
+
+/*
+ * This IOCTL is used to retrieve the wMaxCommand for the device,
+ * defining the message limit for both reading and writing.
+ *
+ * For CDC WDM functions this will be the wMaxCommand field of the
+ * Device Management Functional Descriptor.
+ */
+#define IOCTL_WDM_MAX_COMMAND _IOR('H', 0xA0, __u16)
+
+#endif /* _UAPI__LINUX_USB_CDC_WDM_H */