Merge tag 'for-usb-next-2012-09-25' of git://git.kernel.org/pub/scm/linux/kernel...
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 25 Sep 2012 22:34:17 +0000 (15:34 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 25 Sep 2012 22:34:17 +0000 (15:34 -0700)
xHCI bug fixes for 3.7

Hi Greg,

Here's three small bug fixes for 3.7.  They fix a NULL pointer deference
and lost USB device unplug events, as well as making sure the xHCI
driver doesn't prevent system suspend.

Sarah Sharp

Documentation/ABI/testing/sysfs-bus-usb
drivers/usb/core/hub.c
drivers/usb/host/ehci-fsl.c
drivers/usb/serial/Kconfig
drivers/usb/serial/Makefile
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio_ids.h
drivers/usb/serial/vizzini.c [deleted file]
drivers/usb/storage/uas.c
include/linux/fsl_devices.h

index 13f3eeee1599a68f4400cdb7f4f81c59924f2782..b6fbe514a869a311bea16c1918061128c8f9d6dc 100644 (file)
@@ -227,27 +227,3 @@ Contact:   Lan Tianyu <tianyu.lan@intel.com>
 Description:
                The /sys/bus/usb/devices/.../(hub interface)/portX
                is usb port device's sysfs directory.
-
-What:          /sys/bus/usb/devices/.../(hub interface)/portX/control
-Date:          August 2012
-Contact:       Lan Tianyu <tianyu.lan@intel.com>
-Description:
-               The /sys/bus/usb/devices/.../(hub interface)/portX/control
-               attribute allows user space to control the power policy on
-               the usb port.
-
-               All ports have one of the following two values for control
-               "on" - port power must be on.
-               "off" - port power must be off.
-
-What:          /sys/bus/usb/devices/.../(hub interface)/portX/state
-Date:          August 2012
-Contact:       Lan Tianyu <tianyu.lan@intel.com>
-Description:
-               The /sys/bus/usb/devices/.../(hub interface)/portX/state
-               attribute allows user space to check hub port's power state.
-
-               All ports have three following states
-               "on"      -    port power on
-               "off"     -    port power off
-               "error"   -    can't get the hub port's power state
index 6dc41c6399de8ec0b8567927a2cfbe608ab54641..673ee46962621e8013b102f2876c918bfa1d56f0 100644 (file)
 #endif
 #endif
 
-enum port_power_policy {
-       USB_PORT_POWER_ON = 0,
-       USB_PORT_POWER_OFF,
-};
-
 struct usb_port {
        struct usb_device *child;
        struct device dev;
        struct dev_state *port_owner;
        enum usb_port_connect_type connect_type;
-       enum port_power_policy port_power_policy;
 };
 
 struct usb_hub {
@@ -99,10 +93,6 @@ struct usb_hub {
        struct usb_port         **ports;
 };
 
-static const char on_string[] = "on";
-static const char off_string[] = "off";
-static const struct attribute_group *port_dev_group[];
-
 static inline int hub_is_superspeed(struct usb_device *hdev)
 {
        return (hdev->descriptor.bDeviceProtocol == USB_HUB_PR_SS);
@@ -855,12 +845,7 @@ static unsigned hub_power_on(struct usb_hub *hub, bool do_delay)
                dev_dbg(hub->intfdev, "trying to enable port power on "
                                "non-switchable hub\n");
        for (port1 = 1; port1 <= hub->descriptor->bNbrPorts; port1++)
-               if (hub->ports[port1 - 1]->port_power_policy
-                               == USB_PORT_POWER_ON)
-                       set_port_feature(hub->hdev, port1, USB_PORT_FEAT_POWER);
-               else
-                       clear_port_feature(hub->hdev, port1,
-                                       USB_PORT_FEAT_POWER);
+               set_port_feature(hub->hdev, port1, USB_PORT_FEAT_POWER);
 
        /* Wait at least 100 msec for power to become stable */
        delay = max(pgood_delay, (unsigned) 100);
@@ -1278,7 +1263,6 @@ static int usb_hub_create_port_device(struct usb_hub *hub,
 
        hub->ports[port1 - 1] = port_dev;
        port_dev->dev.parent = hub->intfdev;
-       port_dev->dev.groups = port_dev_group;
        port_dev->dev.type = &usb_port_device_type;
        dev_set_name(&port_dev->dev, "port%d", port1);
 
@@ -2644,25 +2628,6 @@ static int port_is_power_on(struct usb_hub *hub, unsigned portstatus)
        return ret;
 }
 
-static int usb_get_hub_port_power_state(struct usb_device *hdev, int port1)
-{
-       struct usb_hub *hub = hdev_to_hub(hdev);
-       struct usb_port_status data;
-       u16 portstatus;
-       int ret;
-
-       ret = get_port_status(hub->hdev, port1, &data);
-       if (ret < 4) {
-               dev_err(hub->intfdev,
-                       "%s failed (err = %d)\n", __func__, ret);
-               if (ret >= 0)
-                       ret = -EIO;
-               return ret;
-       } else
-               portstatus = le16_to_cpu(data.wPortStatus);
-       return port_is_power_on(hub, portstatus);
-}
-
 #ifdef CONFIG_PM
 
 /* Check if a port is suspended(USB2.0 port) or in U3 state(USB3.0 port) */
@@ -4669,102 +4634,6 @@ static int hub_thread(void *__unused)
        return 0;
 }
 
-static ssize_t show_port_power_state(struct device *dev,
-       struct device_attribute *attr, char *buf)
-{
-       struct usb_device *udev = to_usb_device(dev->parent->parent);
-       struct usb_interface *intf = to_usb_interface(dev->parent);
-       int port1, power_state;
-       const char *result;
-
-       sscanf(dev_name(dev), "port%d", &port1);
-       usb_autopm_get_interface(intf);
-       power_state = usb_get_hub_port_power_state(udev, port1);
-       usb_autopm_put_interface(intf);
-       if (power_state == 1)
-               result = on_string;
-       else if (!power_state)
-               result = off_string;
-       else
-               result = "error";
-       return sprintf(buf, "%s\n", result);
-}
-static DEVICE_ATTR(state, S_IRUGO, show_port_power_state, NULL);
-
-static ssize_t show_port_power_control(struct device *dev,
-       struct device_attribute *attr, char *buf)
-{
-       struct usb_port *hub_port = to_usb_port(dev);
-       const char *result;
-
-       switch (hub_port->port_power_policy) {
-       case USB_PORT_POWER_ON:
-               result = on_string;
-               break;
-       case USB_PORT_POWER_OFF:
-               result = off_string;
-               break;
-       default:
-               return -EINVAL;
-       }
-       return sprintf(buf, "%s\n", result);
-}
-
-static ssize_t store_port_power_control(struct device *dev,
-               struct device_attribute *attr, const char *buf, size_t count)
-{
-       struct usb_device *hdev = to_usb_device(dev->parent->parent);
-       struct usb_interface *intf = to_usb_interface(dev->parent);
-       struct usb_port *hub_port = to_usb_port(dev);
-       int port1, ret, len = count;
-       char *cp;
-
-       sscanf(dev_name(dev), "port%d", &port1);
-       cp = memchr(buf, '\n', count);
-       if (cp)
-               len = cp - buf;
-       if (len == sizeof(on_string) - 1
-                       && strncmp(buf, on_string, len) == 0) {
-               hub_port->port_power_policy = USB_PORT_POWER_ON;
-               usb_autopm_get_interface(intf);
-               ret = set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
-               usb_autopm_put_interface(intf);
-               if (ret < 0)
-                       return -EIO;
-       } else if (len == sizeof(off_string) - 1
-                       && strncmp(buf, off_string, len) == 0) {
-               struct usb_hub *hub = hdev_to_hub(hdev);
-
-               hub_port->port_power_policy = USB_PORT_POWER_OFF;
-               usb_autopm_get_interface(intf);
-               hub_port_logical_disconnect(hub, port1);
-               ret = clear_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
-               usb_autopm_put_interface(intf);
-               if (ret < 0)
-                       return -EIO;
-       } else
-               return -EINVAL;
-
-       return count;
-}
-static DEVICE_ATTR(control, S_IWUSR | S_IRUGO, show_port_power_control,
-               store_port_power_control);
-
-static struct attribute *port_dev_attrs[] = {
-       &dev_attr_control.attr,
-       &dev_attr_state.attr,
-       NULL,
-};
-
-static struct attribute_group port_dev_attr_grp = {
-       .attrs = port_dev_attrs,
-};
-
-static const struct attribute_group *port_dev_group[] = {
-       &port_dev_attr_grp,
-       NULL,
-};
-
 static const struct usb_device_id hub_id_table[] = {
     { .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS,
       .bDeviceClass = USB_CLASS_HUB},
index 11ff4b4dc7ad0e782ee9b8b0e02add9dd8aecb19..9bfde82078ecabde8236fc504aaf2a1794d25fb3 100644 (file)
@@ -267,8 +267,7 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd,
                break;
        }
 
-       if ((pdata->controller_ver) && ((phy_mode == FSL_USB2_PHY_ULPI) ||
-                       (phy_mode == FSL_USB2_PHY_UTMI))) {
+       if (pdata->controller_ver && (phy_mode == FSL_USB2_PHY_ULPI)) {
                /* check PHY_CLK_VALID to get phy clk valid */
                if (!spin_event_timeout(in_be32(non_ehci + FSL_SOC_USB_CTRL) &
                                PHY_CLK_VALID, FSL_USB_PHY_CLK_TIMEOUT, 0)) {
index a5c144694005b90458676e8b4773f54781964aae..f604f707a05895b3a47419192082b0b078767837 100644 (file)
@@ -182,14 +182,6 @@ config USB_SERIAL_VISOR
          To compile this driver as a module, choose M here: the
          module will be called visor.
 
-config USB_SERIAL_VIZZINI
-       tristate "USB Vizzini Serial Converter Driver"
-       help
-         Say Y here if you have a Vizzini USB to serial device.
-
-         To compile this driver as a module, choose M here: the
-         module will be called vizzini.
-
 config USB_SERIAL_IPAQ
        tristate "USB PocketPC PDA Driver"
        help
index 5fd21a01b009bafa5d7f6f17e82738c7d577b796..45871f9ad1e1c79b99ad34c01f7328a4e57cefe2 100644 (file)
@@ -59,7 +59,6 @@ obj-$(CONFIG_USB_SERIAL_SYMBOL)                       += symbolserial.o
 obj-$(CONFIG_USB_SERIAL_WWAN)                  += usb_wwan.o
 obj-$(CONFIG_USB_SERIAL_TI)                    += ti_usb_3410_5052.o
 obj-$(CONFIG_USB_SERIAL_VISOR)                 += visor.o
-obj-$(CONFIG_USB_SERIAL_VIZZINI)               += vizzini.o
 obj-$(CONFIG_USB_SERIAL_WHITEHEAT)             += whiteheat.o
 obj-$(CONFIG_USB_SERIAL_XIRCOM)                        += keyspan_pda.o
 obj-$(CONFIG_USB_SERIAL_VIVOPAY_SERIAL)                += vivopay-serial.o
index 8742a0ee2091963fff24421a214152bd39c3f46f..9169f51777efbfe3e4438274acbe9bd5ce9dba4f 100644 (file)
@@ -579,6 +579,8 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, FTDI_IBS_PEDO_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_IBS_PROD_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_TAVIR_STK500_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_TIAO_UMPA_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
        /*
         * ELV devices:
         */
index 41fe5826100c0ad27a62d21d16e8d5845dfa25cc..57c12ef6625e3cc940657539cc38cd12c43a030c 100644 (file)
  */
 #define FTDI_TAVIR_STK500_PID  0xFA33  /* STK500 AVR programmer */
 
+/*
+ * TIAO product ids (FTDI_VID)
+ * http://www.tiaowiki.com/w/Main_Page
+ */
+#define FTDI_TIAO_UMPA_PID     0x8a98  /* TIAO/DIYGADGET USB Multi-Protocol Adapter */
 
 
 /********************************/
diff --git a/drivers/usb/serial/vizzini.c b/drivers/usb/serial/vizzini.c
deleted file mode 100644 (file)
index 7f43694..0000000
+++ /dev/null
@@ -1,1354 +0,0 @@
-/*
- * vizzini.c
- *
- * Copyright (c) 2011 Exar Corporation, Inc.
- *
- * ChangeLog:
- *            v0.76- Support for 3.0.0 (Ubuntu 11.10) (Removed all Kernel source
- *                   compiler conditions and now the base is Kernel 3.0. Ravi Reddy)
- *            v0.75- Support for 2.6.38.8 (Ubuntu 11.04) - Added
- *                   .usb_driver = &vizzini_driver.
- *            v0.74- Support for 2.6.35.22 (Ubuntu 10.10) - Added
- *                   #include <linux/slab.h> to fix kmalloc/kfree error.
- *            v0.73- Fixed VZIOC_SET_REG (by Ravi Reddy).
- *            v0.72- Support for 2.6.32.21 (by Ravi Reddy, for Ubuntu 10.04).
- *            v0.71- Support for 2.6.31.
- *            v0.5 - Tentative support for compiling with the CentOS 5.1
- *                   kernel (2.6.18-53).
- *            v0.4 - First version.  Lots of stuff lifted from
- *                   cdc-acm.c (credits due to Armin Fuerst, Pavel Machek,
- *                   Johannes Erdfelt, Vojtech Pavlik, David Kubicek) and
- *                   and sierra.c (credit due to Kevin Lloyd).
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#define DRIVER_VERSION "v.0.76"
-#define DRIVER_AUTHOR "Rob Duncan <rob.duncan@exar.com>"
-#define DRIVER_DESC "USB Driver for Vizzini USB serial port"
-
-#undef VIZZINI_IWA
-
-
-#include <linux/kernel.h>
-#include <linux/jiffies.h>
-#include <linux/errno.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/usb/serial.h>
-#include <linux/serial.h>
-#include <linux/slab.h>
-#include <linux/uaccess.h>
-#include <asm/unaligned.h>
-
-#include <linux/usb/cdc.h>
-#ifndef CDC_DATA_INTERFACE_TYPE
-#define CDC_DATA_INTERFACE_TYPE 0x0a
-#endif
-#ifndef USB_RT_ACM
-#define USB_RT_ACM      (USB_TYPE_CLASS | USB_RECIP_INTERFACE)
-#define ACM_CTRL_DTR            0x01
-#define ACM_CTRL_RTS            0x02
-#define ACM_CTRL_DCD            0x01
-#define ACM_CTRL_DSR            0x02
-#define ACM_CTRL_BRK            0x04
-#define ACM_CTRL_RI             0x08
-#define ACM_CTRL_FRAMING        0x10
-#define ACM_CTRL_PARITY         0x20
-#define ACM_CTRL_OVERRUN        0x40
-#endif
-
-#define XR_SET_REG              0
-#define XR_GETN_REG             1
-
-#define UART_0_REG_BLOCK        0
-#define UART_1_REG_BLOCK        1
-#define UART_2_REG_BLOCK        2
-#define UART_3_REG_BLOCK        3
-#define URM_REG_BLOCK           4
-#define PRM_REG_BLOCK           5
-#define EPMERR_REG_BLOCK        6
-#define RAMCTL_REG_BLOCK        0x64
-#define TWI_ROM_REG_BLOCK       0x65
-#define EPLOCALS_REG_BLOCK      0x66
-
-#define MEM_SHADOW_REG_SIZE_S   5
-#define MEM_SHADOW_REG_SIZE     (1 << MEM_SHADOW_REG_SIZE_S)
-
-#define MEM_EP_LOCALS_SIZE_S    3
-#define MEM_EP_LOCALS_SIZE      (1 << MEM_EP_LOCALS_SIZE_S)
-
-#define EP_WIDE_MODE            0x03
-
-
-#define UART_GPIO_MODE                                     0x01a
-
-#define UART_GPIO_MODE_SEL_M                               0x7
-#define UART_GPIO_MODE_SEL_S                               0
-#define UART_GPIO_MODE_SEL                                 0x007
-
-#define UART_GPIO_MODE_SEL_GPIO                            (0x0 << UART_GPIO_MODE_SEL_S)
-#define UART_GPIO_MODE_SEL_RTS_CTS                         (0x1 << UART_GPIO_MODE_SEL_S)
-#define UART_GPIO_MODE_SEL_DTR_DSR                         (0x2 << UART_GPIO_MODE_SEL_S)
-#define UART_GPIO_MODE_SEL_XCVR_EN_ACT                     (0x3 << UART_GPIO_MODE_SEL_S)
-#define UART_GPIO_MODE_SEL_XCVR_EN_FLOW                    (0x4 << UART_GPIO_MODE_SEL_S)
-
-#define UART_GPIO_MODE_XCVR_EN_POL_M                       0x1
-#define UART_GPIO_MODE_XCVR_EN_POL_S                       3
-#define UART_GPIO_MODE_XCVR_EN_POL                         0x008
-
-#define UART_ENABLE                                        0x003
-#define UART_ENABLE_TX_M                                   0x1
-#define UART_ENABLE_TX_S                                   0
-#define UART_ENABLE_TX                                     0x001
-#define UART_ENABLE_RX_M                                   0x1
-#define UART_ENABLE_RX_S                                   1
-#define UART_ENABLE_RX                                     0x002
-
-#define UART_CLOCK_DIVISOR_0                               0x004
-#define UART_CLOCK_DIVISOR_1                               0x005
-#define UART_CLOCK_DIVISOR_2                               0x006
-
-#define UART_CLOCK_DIVISOR_2_MSB_M                         0x7
-#define UART_CLOCK_DIVISOR_2_MSB_S                         0
-#define UART_CLOCK_DIVISOR_2_MSB                           0x007
-#define UART_CLOCK_DIVISOR_2_DIAGMODE_M                    0x1
-#define UART_CLOCK_DIVISOR_2_DIAGMODE_S                    3
-#define UART_CLOCK_DIVISOR_2_DIAGMODE                      0x008
-
-#define UART_TX_CLOCK_MASK_0                               0x007
-#define UART_TX_CLOCK_MASK_1                               0x008
-
-#define UART_RX_CLOCK_MASK_0                               0x009
-#define UART_RX_CLOCK_MASK_1                               0x00a
-
-#define UART_FORMAT                                        0x00b
-
-#define UART_FORMAT_SIZE_M                                 0xf
-#define UART_FORMAT_SIZE_S                                 0
-#define UART_FORMAT_SIZE                                   0x00f
-
-#define UART_FORMAT_SIZE_7                                 (0x7 << UART_FORMAT_SIZE_S)
-#define UART_FORMAT_SIZE_8                                 (0x8 << UART_FORMAT_SIZE_S)
-#define UART_FORMAT_SIZE_9                                 (0x9 << UART_FORMAT_SIZE_S)
-
-#define UART_FORMAT_PARITY_M                               0x7
-#define UART_FORMAT_PARITY_S                               4
-#define UART_FORMAT_PARITY                                 0x070
-
-#define UART_FORMAT_PARITY_NONE                            (0x0 << UART_FORMAT_PARITY_S)
-#define UART_FORMAT_PARITY_ODD                             (0x1 << UART_FORMAT_PARITY_S)
-#define UART_FORMAT_PARITY_EVEN                            (0x2 << UART_FORMAT_PARITY_S)
-#define UART_FORMAT_PARITY_1                               (0x3 << UART_FORMAT_PARITY_S)
-#define UART_FORMAT_PARITY_0                               (0x4 << UART_FORMAT_PARITY_S)
-
-#define UART_FORMAT_STOP_M                                 0x1
-#define UART_FORMAT_STOP_S                                 7
-#define UART_FORMAT_STOP                                   0x080
-
-#define UART_FORMAT_STOP_1                                 (0x0 << UART_FORMAT_STOP_S)
-#define UART_FORMAT_STOP_2                                 (0x1 << UART_FORMAT_STOP_S)
-
-#define UART_FORMAT_MODE_7N1                               0
-#define UART_FORMAT_MODE_RES1                              1
-#define UART_FORMAT_MODE_RES2                              2
-#define UART_FORMAT_MODE_RES3                              3
-#define UART_FORMAT_MODE_7N2                               4
-#define UART_FORMAT_MODE_7P1                               5
-#define UART_FORMAT_MODE_8N1                               6
-#define UART_FORMAT_MODE_RES7                              7
-#define UART_FORMAT_MODE_7P2                               8
-#define UART_FORMAT_MODE_8N2                               9
-#define UART_FORMAT_MODE_8P1                               10
-#define UART_FORMAT_MODE_9N1                               11
-#define UART_FORMAT_MODE_8P2                               12
-#define UART_FORMAT_MODE_RESD                              13
-#define UART_FORMAT_MODE_RESE                              14
-#define UART_FORMAT_MODE_9N2                               15
-
-#define UART_FLOW                                          0x00c
-
-#define UART_FLOW_MODE_M                                   0x7
-#define UART_FLOW_MODE_S                                   0
-#define UART_FLOW_MODE                                     0x007
-
-#define UART_FLOW_MODE_NONE                                (0x0 << UART_FLOW_MODE_S)
-#define UART_FLOW_MODE_HW                                  (0x1 << UART_FLOW_MODE_S)
-#define UART_FLOW_MODE_SW                                  (0x2 << UART_FLOW_MODE_S)
-#define UART_FLOW_MODE_ADDR_MATCH                          (0x3 << UART_FLOW_MODE_S)
-#define UART_FLOW_MODE_ADDR_MATCH_TX                       (0x4 << UART_FLOW_MODE_S)
-
-#define UART_FLOW_HALF_DUPLEX_M                            0x1
-#define UART_FLOW_HALF_DUPLEX_S                            3
-#define UART_FLOW_HALF_DUPLEX                              0x008
-
-#define UART_LOOPBACK_CTL                                  0x012
-#define UART_LOOPBACK_CTL_ENABLE_M                         0x1
-#define UART_LOOPBACK_CTL_ENABLE_S                         2
-#define UART_LOOPBACK_CTL_ENABLE                           0x004
-#define UART_LOOPBACK_CTL_RX_SOURCE_M                      0x3
-#define UART_LOOPBACK_CTL_RX_SOURCE_S                      0
-#define UART_LOOPBACK_CTL_RX_SOURCE                        0x003
-#define UART_LOOPBACK_CTL_RX_UART0                         (0x0 << UART_LOOPBACK_CTL_RX_SOURCE_S)
-#define UART_LOOPBACK_CTL_RX_UART1                         (0x1 << UART_LOOPBACK_CTL_RX_SOURCE_S)
-#define UART_LOOPBACK_CTL_RX_UART2                         (0x2 << UART_LOOPBACK_CTL_RX_SOURCE_S)
-#define UART_LOOPBACK_CTL_RX_UART3                         (0x3 << UART_LOOPBACK_CTL_RX_SOURCE_S)
-
-#define UART_CHANNEL_NUM                                   0x00d
-
-#define UART_XON_CHAR                                      0x010
-#define UART_XOFF_CHAR                                     0x011
-
-#define UART_GPIO_SET                                      0x01d
-#define UART_GPIO_CLR                                      0x01e
-#define UART_GPIO_STATUS                                   0x01f
-
-#define URM_ENABLE_BASE                                    0x010
-#define URM_ENABLE_0                                       0x010
-#define URM_ENABLE_0_TX_M                                  0x1
-#define URM_ENABLE_0_TX_S                                  0
-#define URM_ENABLE_0_TX                                    0x001
-#define URM_ENABLE_0_RX_M                                  0x1
-#define URM_ENABLE_0_RX_S                                  1
-#define URM_ENABLE_0_RX                                    0x002
-
-#define URM_RX_FIFO_RESET_0                                0x018
-#define URM_RX_FIFO_RESET_1                                0x019
-#define URM_RX_FIFO_RESET_2                                0x01a
-#define URM_RX_FIFO_RESET_3                                0x01b
-#define URM_TX_FIFO_RESET_0                                0x01c
-#define URM_TX_FIFO_RESET_1                                0x01d
-#define URM_TX_FIFO_RESET_2                                0x01e
-#define URM_TX_FIFO_RESET_3                                0x01f
-
-
-#define RAMCTL_REGS_TXFIFO_0_LEVEL                         0x000
-#define RAMCTL_REGS_TXFIFO_1_LEVEL                         0x001
-#define RAMCTL_REGS_TXFIFO_2_LEVEL                         0x002
-#define RAMCTL_REGS_TXFIFO_3_LEVEL                         0x003
-#define RAMCTL_REGS_RXFIFO_0_LEVEL                         0x004
-
-#define RAMCTL_REGS_RXFIFO_0_LEVEL_LEVEL_M                 0x7ff
-#define RAMCTL_REGS_RXFIFO_0_LEVEL_LEVEL_S                 0
-#define RAMCTL_REGS_RXFIFO_0_LEVEL_LEVEL                   0x7ff
-#define RAMCTL_REGS_RXFIFO_0_LEVEL_STALE_M                 0x1
-#define RAMCTL_REGS_RXFIFO_0_LEVEL_STALE_S                 11
-#define RAMCTL_REGS_RXFIFO_0_LEVEL_STALE                   0x800
-
-#define RAMCTL_REGS_RXFIFO_1_LEVEL                         0x005
-#define RAMCTL_REGS_RXFIFO_2_LEVEL                         0x006
-#define RAMCTL_REGS_RXFIFO_3_LEVEL                         0x007
-
-#define RAMCTL_BUFFER_PARITY                               0x1
-#define RAMCTL_BUFFER_BREAK                                0x2
-#define RAMCTL_BUFFER_FRAME                                0x4
-#define RAMCTL_BUFFER_OVERRUN                              0x8
-
-#define N_IN_URB       4
-#define N_OUT_URB      4
-#define IN_BUFLEN      4096
-
-static struct usb_device_id id_table[] = {
-       { USB_DEVICE(0x04e2, 0x1410) },
-       { USB_DEVICE(0x04e2, 0x1412) },
-       { USB_DEVICE(0x04e2, 0x1414) },
-       { }
-};
-MODULE_DEVICE_TABLE(usb, id_table);
-
-struct vizzini_serial_private {
-       struct usb_interface *data_interface;
-};
-
-struct vizzini_port_private {
-       spinlock_t lock;
-       int outstanding_urbs;
-
-       struct urb *in_urbs[N_IN_URB];
-       char *in_buffer[N_IN_URB];
-
-       int ctrlin;
-       int ctrlout;
-       int clocal;
-
-       int block;
-       int preciseflags;       /* USB: wide mode, TTY: flags per character */
-       int trans9;             /* USB: wide mode, serial 9N1 */
-       unsigned int baud_base; /* setserial: used to hack in non-standard baud rates */
-       int have_extra_byte;
-       int extra_byte;
-
-       int bcd_device;
-
-#ifdef VIZZINI_IWA
-       int iwa;
-#endif
-};
-
-
-static int vizzini_rev_a(struct usb_serial_port *port)
-{
-       struct vizzini_port_private *portdata = usb_get_serial_port_data(port);
-       return portdata->bcd_device == 0;
-}
-
-static int acm_ctrl_msg(struct usb_serial_port *port, int request,
-                       int value, void *buf, int len)
-{
-       struct usb_serial *serial = port->serial;
-       int retval = usb_control_msg(serial->dev,
-                                    usb_sndctrlpipe(serial->dev, 0),
-                                    request,
-                                    USB_RT_ACM,
-                                    value,
-                                    serial->interface->cur_altsetting->desc.bInterfaceNumber,
-                                    buf,
-                                    len,
-                                    5000);
-       dev_dbg(&port->dev, "acm_control_msg: rq: 0x%02x val: %#x len: %#x result: %d\n", request, value, len, retval);
-       return retval < 0 ? retval : 0;
-}
-
-#define acm_set_control(port, control)                                 \
-       acm_ctrl_msg(port, USB_CDC_REQ_SET_CONTROL_LINE_STATE, control, NULL, 0)
-#define acm_set_line(port, line)                                       \
-       acm_ctrl_msg(port, USB_CDC_REQ_SET_LINE_CODING, 0, line, sizeof *(line))
-#define acm_send_break(port, ms)                                       \
-       acm_ctrl_msg(port, USB_CDC_REQ_SEND_BREAK, ms, NULL, 0)
-
-static int vizzini_set_reg(struct usb_serial_port *port, int block, int regnum, int value)
-{
-       struct usb_serial *serial = port->serial;
-       int result;
-
-       result = usb_control_msg(serial->dev,                     /* usb device */
-                                usb_sndctrlpipe(serial->dev, 0), /* endpoint pipe */
-                                XR_SET_REG,                      /* request */
-                                USB_DIR_OUT | USB_TYPE_VENDOR,   /* request_type */
-                                value,                           /* request value */
-                                regnum | (block << 8),           /* index */
-                                NULL,                            /* data */
-                                0,                               /* size */
-                                5000);                           /* timeout */
-
-       return result;
-}
-
-static void vizzini_disable(struct usb_serial_port *port)
-{
-       struct vizzini_port_private *portdata = usb_get_serial_port_data(port);
-       int block = portdata->block;
-
-       vizzini_set_reg(port, block, UART_ENABLE, 0);
-       vizzini_set_reg(port, URM_REG_BLOCK, URM_ENABLE_BASE + block, 0);
-}
-
-static void vizzini_enable(struct usb_serial_port *port)
-{
-       struct vizzini_port_private *portdata = usb_get_serial_port_data(port);
-       int block = portdata->block;
-
-       vizzini_set_reg(port, URM_REG_BLOCK, URM_ENABLE_BASE + block, URM_ENABLE_0_TX);
-       vizzini_set_reg(port, block, UART_ENABLE, UART_ENABLE_TX | UART_ENABLE_RX);
-       vizzini_set_reg(port, URM_REG_BLOCK, URM_ENABLE_BASE + block, URM_ENABLE_0_TX | URM_ENABLE_0_RX);
-}
-
-struct vizzini_baud_rate {
-       unsigned int tx;
-       unsigned int rx0;
-       unsigned int rx1;
-};
-
-static struct vizzini_baud_rate vizzini_baud_rates[] = {
-       { 0x000, 0x000, 0x000 },
-       { 0x000, 0x000, 0x000 },
-       { 0x100, 0x000, 0x100 },
-       { 0x020, 0x400, 0x020 },
-       { 0x010, 0x100, 0x010 },
-       { 0x208, 0x040, 0x208 },
-       { 0x104, 0x820, 0x108 },
-       { 0x844, 0x210, 0x884 },
-       { 0x444, 0x110, 0x444 },
-       { 0x122, 0x888, 0x224 },
-       { 0x912, 0x448, 0x924 },
-       { 0x492, 0x248, 0x492 },
-       { 0x252, 0x928, 0x292 },
-       { 0X94A, 0X4A4, 0XA52 },
-       { 0X52A, 0XAA4, 0X54A },
-       { 0XAAA, 0x954, 0X4AA },
-       { 0XAAA, 0x554, 0XAAA },
-       { 0x555, 0XAD4, 0X5AA },
-       { 0XB55, 0XAB4, 0X55A },
-       { 0X6B5, 0X5AC, 0XB56 },
-       { 0X5B5, 0XD6C, 0X6D6 },
-       { 0XB6D, 0XB6A, 0XDB6 },
-       { 0X76D, 0X6DA, 0XBB6 },
-       { 0XEDD, 0XDDA, 0X76E },
-       { 0XDDD, 0XBBA, 0XEEE },
-       { 0X7BB, 0XF7A, 0XDDE },
-       { 0XF7B, 0XEF6, 0X7DE },
-       { 0XDF7, 0XBF6, 0XF7E },
-       { 0X7F7, 0XFEE, 0XEFE },
-       { 0XFDF, 0XFBE, 0X7FE },
-       { 0XF7F, 0XEFE, 0XFFE },
-       { 0XFFF, 0XFFE, 0XFFD },
-};
-
-static int vizzini_set_baud_rate(struct usb_serial_port *port, unsigned int rate)
-{
-       struct vizzini_port_private *portdata = usb_get_serial_port_data(port);
-       int block = portdata->block;
-       unsigned int divisor = 48000000 / rate;
-       unsigned int i = ((32 * 48000000) / rate) & 0x1f;
-       unsigned int tx_mask = vizzini_baud_rates[i].tx;
-       unsigned int rx_mask = (divisor & 1) ? vizzini_baud_rates[i].rx1 : vizzini_baud_rates[i].rx0;
-
-       dev_dbg(&port->dev, "Setting baud rate to %d: i=%u div=%u tx=%03x rx=%03x\n", rate, i, divisor, tx_mask, rx_mask);
-
-       vizzini_set_reg(port, block, UART_CLOCK_DIVISOR_0, (divisor >>  0) & 0xff);
-       vizzini_set_reg(port, block, UART_CLOCK_DIVISOR_1, (divisor >>  8) & 0xff);
-       vizzini_set_reg(port, block, UART_CLOCK_DIVISOR_2, (divisor >> 16) & 0xff);
-       vizzini_set_reg(port, block, UART_TX_CLOCK_MASK_0, (tx_mask >>  0) & 0xff);
-       vizzini_set_reg(port, block, UART_TX_CLOCK_MASK_1, (tx_mask >>  8) & 0xff);
-       vizzini_set_reg(port, block, UART_RX_CLOCK_MASK_0, (rx_mask >>  0) & 0xff);
-       vizzini_set_reg(port, block, UART_RX_CLOCK_MASK_1, (rx_mask >>  8) & 0xff);
-
-       return -EINVAL;
-}
-
-static void vizzini_set_termios(struct tty_struct *tty_param,
-                               struct usb_serial_port *port,
-                               struct ktermios *old_termios)
-{
-       struct vizzini_port_private *portdata = usb_get_serial_port_data(port);
-       unsigned int             cflag, block;
-       speed_t                  rate;
-       unsigned int             format_size, format_parity, format_stop, flow, gpio_mode;
-       struct tty_struct       *tty = port->port.tty;
-
-       cflag = tty->termios->c_cflag;
-
-       portdata->clocal = ((cflag & CLOCAL) != 0);
-
-       block = portdata->block;
-
-       vizzini_disable(port);
-
-       if ((cflag & CSIZE) == CS7) {
-               format_size = UART_FORMAT_SIZE_7;
-       } else if ((cflag & CSIZE) == CS5) {
-               /* Enabling 5-bit mode is really 9-bit mode! */
-               format_size = UART_FORMAT_SIZE_9;
-       } else {
-               format_size = UART_FORMAT_SIZE_8;
-       }
-       portdata->trans9 = (format_size == UART_FORMAT_SIZE_9);
-
-       if (cflag & PARENB) {
-               if (cflag & PARODD) {
-                       if (cflag & CMSPAR)
-                               format_parity = UART_FORMAT_PARITY_1;
-                       else
-                               format_parity = UART_FORMAT_PARITY_ODD;
-               } else {
-                       if (cflag & CMSPAR)
-                               format_parity = UART_FORMAT_PARITY_0;
-                       else
-                               format_parity = UART_FORMAT_PARITY_EVEN;
-               }
-       } else {
-               format_parity = UART_FORMAT_PARITY_NONE;
-       }
-
-       if (cflag & CSTOPB)
-               format_stop = UART_FORMAT_STOP_2;
-       else
-               format_stop = UART_FORMAT_STOP_1;
-
-#ifdef VIZZINI_IWA
-       if (format_size == UART_FORMAT_SIZE_8) {
-               portdata->iwa = format_parity;
-               if (portdata->iwa != UART_FORMAT_PARITY_NONE) {
-                       format_size = UART_FORMAT_SIZE_9;
-                       format_parity = UART_FORMAT_PARITY_NONE;
-               }
-       } else {
-               portdata->iwa = UART_FORMAT_PARITY_NONE;
-       }
-#endif
-       vizzini_set_reg(port, block, UART_FORMAT, format_size | format_parity | format_stop);
-
-       if (cflag & CRTSCTS) {
-               flow      = UART_FLOW_MODE_HW;
-               gpio_mode = UART_GPIO_MODE_SEL_RTS_CTS;
-       } else if (I_IXOFF(tty) || I_IXON(tty)) {
-               unsigned char   start_char = START_CHAR(tty);
-               unsigned char   stop_char  = STOP_CHAR(tty);
-
-               flow      = UART_FLOW_MODE_SW;
-               gpio_mode = UART_GPIO_MODE_SEL_GPIO;
-
-               vizzini_set_reg(port, block, UART_XON_CHAR, start_char);
-               vizzini_set_reg(port, block, UART_XOFF_CHAR, stop_char);
-       } else {
-               flow      = UART_FLOW_MODE_NONE;
-               gpio_mode = UART_GPIO_MODE_SEL_GPIO;
-       }
-
-       vizzini_set_reg(port, block, UART_FLOW, flow);
-       vizzini_set_reg(port, block, UART_GPIO_MODE, gpio_mode);
-
-       if (portdata->trans9) {
-               /* Turn on wide mode if we're 9-bit transparent. */
-               vizzini_set_reg(port, EPLOCALS_REG_BLOCK, (block * MEM_EP_LOCALS_SIZE) + EP_WIDE_MODE, 1);
-#ifdef VIZZINI_IWA
-       } else if (portdata->iwa != UART_FORMAT_PARITY_NONE) {
-               vizzini_set_reg(port, EPLOCALS_REG_BLOCK, (block * MEM_EP_LOCALS_SIZE) + EP_WIDE_MODE, 1);
-#endif
-       } else if (!portdata->preciseflags) {
-               /* Turn off wide mode unless we have precise flags. */
-               vizzini_set_reg(port, EPLOCALS_REG_BLOCK, (block * MEM_EP_LOCALS_SIZE) + EP_WIDE_MODE, 0);
-       }
-
-       rate = tty_get_baud_rate(tty);
-       if (rate)
-               vizzini_set_baud_rate(port, rate);
-
-       vizzini_enable(port);
-}
-
-static void vizzini_break_ctl(struct tty_struct *tty, int break_state)
-{
-       struct usb_serial_port *port = tty->driver_data;
-
-       dev_dbg(&port->dev, "BREAK %d\n", break_state);
-       if (break_state)
-               acm_send_break(port, 0x10);
-       else
-               acm_send_break(port, 0x000);
-}
-
-static int vizzini_tiocmget(struct tty_struct *tty)
-{
-       struct usb_serial_port *port = tty->driver_data;
-       struct vizzini_port_private *portdata = usb_get_serial_port_data(port);
-
-       return (portdata->ctrlout & ACM_CTRL_DTR ? TIOCM_DTR : 0) |
-               (portdata->ctrlout & ACM_CTRL_RTS ? TIOCM_RTS : 0) |
-               (portdata->ctrlin  & ACM_CTRL_DSR ? TIOCM_DSR : 0) |
-               (portdata->ctrlin  & ACM_CTRL_RI  ? TIOCM_RI  : 0) |
-               (portdata->ctrlin  & ACM_CTRL_DCD ? TIOCM_CD  : 0) |
-               TIOCM_CTS;
-}
-
-static int vizzini_tiocmset(struct tty_struct *tty,
-                           unsigned int set, unsigned int clear)
-{
-       struct usb_serial_port *port = tty->driver_data;
-       struct vizzini_port_private *portdata = usb_get_serial_port_data(port);
-       unsigned int newctrl;
-
-       newctrl = portdata->ctrlout;
-       set = (set & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (set & TIOCM_RTS ? ACM_CTRL_RTS : 0);
-       clear = (clear & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (clear & TIOCM_RTS ? ACM_CTRL_RTS : 0);
-
-       newctrl = (newctrl & ~clear) | set;
-
-       if (portdata->ctrlout == newctrl)
-               return 0;
-       return acm_set_control(port, portdata->ctrlout = newctrl);
-}
-
-static int vizzini_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
-{
-       struct usb_serial_port *port = tty->driver_data;
-       struct vizzini_port_private *portdata = usb_get_serial_port_data(port);
-       struct serial_struct ss;
-
-       dev_dbg(&port->dev, "%s %08x\n", __func__, cmd);
-
-       switch (cmd) {
-       case TIOCGSERIAL:
-               if (!arg)
-                       return -EFAULT;
-               memset(&ss, 0, sizeof(ss));
-               ss.baud_base = portdata->baud_base;
-               if (copy_to_user((void __user *)arg, &ss, sizeof(ss)))
-                       return -EFAULT;
-               break;
-
-       case TIOCSSERIAL:
-               if (!arg)
-                       return -EFAULT;
-               if (copy_from_user(&ss, (void __user *)arg, sizeof(ss)))
-                       return -EFAULT;
-               portdata->baud_base = ss.baud_base;
-               dev_dbg(&port->dev, "baud_base=%d\n", portdata->baud_base);
-
-               vizzini_disable(port);
-               if (portdata->baud_base)
-                       vizzini_set_baud_rate(port, portdata->baud_base);
-               vizzini_enable(port);
-               break;
-
-       default:
-               return -ENOIOCTLCMD;
-       }
-
-       return 0;
-}
-
-#ifdef VIZZINI_IWA
-static const int vizzini_parity[] = {
-       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
-       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
-       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
-       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
-       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
-       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
-       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
-       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
-       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
-       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
-       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
-       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
-       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
-       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
-       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
-       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0
-};
-#endif
-
-static void vizzini_out_callback(struct urb *urb)
-{
-       struct usb_serial_port *port = urb->context;
-       struct vizzini_port_private *portdata = usb_get_serial_port_data(port);
-       int status = urb->status;
-       unsigned long flags;
-
-       dev_dbg(&port->dev, "%s - port %d\n", __func__, port->number);
-
-       /* free up the transfer buffer, as usb_free_urb() does not do this */
-       kfree(urb->transfer_buffer);
-
-       if (status)
-               dev_dbg(&port->dev, "%s - nonzero write bulk status received: %d\n", __func__, status);
-
-       spin_lock_irqsave(&portdata->lock, flags);
-       --portdata->outstanding_urbs;
-       spin_unlock_irqrestore(&portdata->lock, flags);
-
-       usb_serial_port_softint(port);
-}
-
-static int vizzini_write_room(struct tty_struct *tty)
-{
-       struct usb_serial_port *port = tty->driver_data;
-       struct vizzini_port_private *portdata = usb_get_serial_port_data(port);
-       unsigned long flags;
-
-       dev_dbg(&port->dev, "%s - port %d\n", __func__, port->number);
-
-       /* try to give a good number back based on if we have any free urbs at
-        * this point in time */
-       spin_lock_irqsave(&portdata->lock, flags);
-       if (portdata->outstanding_urbs > N_OUT_URB * 2 / 3) {
-               spin_unlock_irqrestore(&portdata->lock, flags);
-               dev_dbg(&port->dev, "%s - write limit hit\n", __func__);
-               return 0;
-       }
-       spin_unlock_irqrestore(&portdata->lock, flags);
-
-       return 2048;
-}
-
-static int vizzini_write(struct tty_struct *tty, struct usb_serial_port *port,
-                        const unsigned char *buf, int count)
-{
-       struct vizzini_port_private *portdata = usb_get_serial_port_data(port);
-       struct usb_serial *serial = port->serial;
-       int bufsize = count;
-       unsigned long flags;
-       unsigned char *buffer;
-       struct urb *urb;
-       int status;
-
-       portdata = usb_get_serial_port_data(port);
-
-       dev_dbg(&port->dev, "%s: write (%d chars)\n", __func__, count);
-
-       spin_lock_irqsave(&portdata->lock, flags);
-       if (portdata->outstanding_urbs > N_OUT_URB) {
-               spin_unlock_irqrestore(&portdata->lock, flags);
-               dev_dbg(&port->dev, "%s - write limit hit\n", __func__);
-               return 0;
-       }
-       portdata->outstanding_urbs++;
-       spin_unlock_irqrestore(&portdata->lock, flags);
-
-#ifdef VIZZINI_IWA
-       if (portdata->iwa != UART_FORMAT_PARITY_NONE)
-               bufsize = count * 2;
-#endif
-       buffer = kmalloc(bufsize, GFP_ATOMIC);
-
-       if (!buffer) {
-               dev_err(&port->dev, "out of memory\n");
-               count = -ENOMEM;
-               goto error_no_buffer;
-       }
-
-       urb = usb_alloc_urb(0, GFP_ATOMIC);
-       if (!urb) {
-               dev_err(&port->dev, "no more free urbs\n");
-               count = -ENOMEM;
-               goto error_no_urb;
-       }
-
-#ifdef VIZZINI_IWA
-       if (portdata->iwa != UART_FORMAT_PARITY_NONE) {
-               int i;
-               char *b = buffer;
-               for (i = 0; i < count; ++i) {
-                       int c, p = 0;
-                       c = buf[i];
-                       switch (portdata->iwa) {
-                       case UART_FORMAT_PARITY_ODD:
-                               p = !vizzini_parity[c];
-                               break;
-                       case UART_FORMAT_PARITY_EVEN:
-                               p = vizzini_parity[c];
-                               break;
-                       case UART_FORMAT_PARITY_1:
-                               p = 1;
-                               break;
-                       case UART_FORMAT_PARITY_0:
-                               p = 0;
-                               break;
-                       }
-                       *b++ = c;
-                       *b++ = p;
-               }
-       } else
-#endif
-               memcpy(buffer, buf, count);
-
-       usb_fill_bulk_urb(urb, serial->dev,
-                         usb_sndbulkpipe(serial->dev,
-                                         port->bulk_out_endpointAddress),
-                         buffer, bufsize, vizzini_out_callback, port);
-
-       /* send it down the pipe */
-       status = usb_submit_urb(urb, GFP_ATOMIC);
-       if (status) {
-               dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed with status = %d\n", __func__, status);
-               count = status;
-               goto error;
-       }
-
-       /* we are done with this urb, so let the host driver
-        * really free it when it is finished with it */
-       usb_free_urb(urb);
-
-       return count;
-error:
-       usb_free_urb(urb);
-error_no_urb:
-       kfree(buffer);
-error_no_buffer:
-       spin_lock_irqsave(&portdata->lock, flags);
-       --portdata->outstanding_urbs;
-       spin_unlock_irqrestore(&portdata->lock, flags);
-       return count;
-}
-
-static void vizzini_in_callback(struct urb *urb)
-{
-       int endpoint = usb_pipeendpoint(urb->pipe);
-       struct usb_serial_port *port = urb->context;
-       struct vizzini_port_private *portdata = usb_get_serial_port_data(port);
-       struct tty_struct *tty = port->port.tty;
-       int preciseflags = portdata->preciseflags;
-       char *transfer_buffer = urb->transfer_buffer;
-       int length, room, have_extra_byte;
-       int err;
-
-       if (urb->status) {
-               dev_dbg(&port->dev, "%s: nonzero status: %d on endpoint %02x.\n", __func__, urb->status, endpoint);
-               return;
-       }
-
-#ifdef VIZZINI_IWA
-       if (portdata->iwa != UART_FORMAT_PARITY_NONE)
-               preciseflags = true;
-#endif
-
-       length = urb->actual_length;
-       if (length == 0) {
-               dev_dbg(&port->dev, "%s: empty read urb received\n", __func__);
-               err = usb_submit_urb(urb, GFP_ATOMIC);
-               if (err)
-                       dev_err(&port->dev, "resubmit read urb failed. (%d)\n", err);
-               return;
-       }
-
-       length = length + (portdata->have_extra_byte ? 1 : 0);
-       have_extra_byte = (preciseflags && (length & 1));
-       length = (preciseflags) ? (length / 2) : length;
-
-       room = tty_buffer_request_room(tty, length);
-       if (room != length)
-               dev_dbg(&port->dev, "Not enough room in TTY buf, dropped %d chars.\n", length - room);
-
-       if (room) {
-               if (preciseflags) {
-                       char *dp = transfer_buffer;
-                       int i, ch, ch_flags;
-
-                       for (i = 0; i < room; ++i) {
-                               char tty_flag;
-
-                               if (i == 0) {
-                                       if (portdata->have_extra_byte)
-                                               ch = portdata->extra_byte;
-                                       else
-                                               ch = *dp++;
-                               } else {
-                                       ch = *dp++;
-                               }
-                               ch_flags = *dp++;
-
-#ifdef VIZZINI_IWA
-                               {
-                                       int p;
-                                       switch (portdata->iwa) {
-                                       case UART_FORMAT_PARITY_ODD:
-                                               p = !vizzini_parity[ch];
-                                               break;
-                                       case UART_FORMAT_PARITY_EVEN:
-                                               p = vizzini_parity[ch];
-                                               break;
-                                       case UART_FORMAT_PARITY_1:
-                                               p = 1;
-                                               break;
-                                       case UART_FORMAT_PARITY_0:
-                                               p = 0;
-                                               break;
-                                       default:
-                                               p = 0;
-                                               break;
-                                       }
-                                       ch_flags ^= p;
-                               }
-#endif
-                               if (ch_flags & RAMCTL_BUFFER_PARITY)
-                                       tty_flag = TTY_PARITY;
-                               else if (ch_flags & RAMCTL_BUFFER_BREAK)
-                                       tty_flag = TTY_BREAK;
-                               else if (ch_flags & RAMCTL_BUFFER_FRAME)
-                                       tty_flag = TTY_FRAME;
-                               else if (ch_flags & RAMCTL_BUFFER_OVERRUN)
-                                       tty_flag = TTY_OVERRUN;
-                               else
-                                       tty_flag = TTY_NORMAL;
-
-                               tty_insert_flip_char(tty, ch, tty_flag);
-                       }
-               } else {
-                       tty_insert_flip_string(tty, transfer_buffer, room);
-               }
-
-               tty_flip_buffer_push(tty);
-       }
-
-       portdata->have_extra_byte = have_extra_byte;
-       if (have_extra_byte)
-               portdata->extra_byte = transfer_buffer[urb->actual_length - 1];
-
-       err = usb_submit_urb(urb, GFP_ATOMIC);
-       if (err)
-               dev_err(&port->dev, "resubmit read urb failed. (%d)\n", err);
-}
-
-static void vizzini_int_callback(struct urb *urb)
-{
-       struct usb_serial_port *port = urb->context;
-       struct vizzini_port_private *portdata = usb_get_serial_port_data(port);
-       struct tty_struct *tty = port->port.tty;
-
-       struct usb_cdc_notification *dr = urb->transfer_buffer;
-       unsigned char *data;
-       int newctrl;
-       int status;
-
-       switch (urb->status) {
-       case 0:
-               /* success */
-               break;
-       case -ECONNRESET:
-       case -ENOENT:
-       case -ESHUTDOWN:
-               /* this urb is terminated, clean up */
-               dev_dbg(&port->dev, "urb shutting down with status: %d\n", urb->status);
-               return;
-       default:
-               dev_dbg(&port->dev, "nonzero urb status received: %d\n", urb->status);
-               goto exit;
-       }
-
-       data = (unsigned char *)(dr + 1);
-       switch (dr->bNotificationType) {
-
-       case USB_CDC_NOTIFY_NETWORK_CONNECTION:
-               dev_dbg(&port->dev, "%s network\n", dr->wValue ? "connected to" : "disconnected from");
-               break;
-
-       case USB_CDC_NOTIFY_SERIAL_STATE:
-               newctrl = le16_to_cpu(get_unaligned((__le16 *)data));
-
-               if (!portdata->clocal && (portdata->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
-                       dev_dbg(&port->dev, "calling hangup\n");
-                       tty_hangup(tty);
-               }
-
-               portdata->ctrlin = newctrl;
-
-               dev_dbg(&port->dev, "input control lines: dcd%c dsr%c break%c ring%c framing%c parity%c overrun%c\n",
-                                  portdata->ctrlin & ACM_CTRL_DCD ? '+' : '-',
-                                  portdata->ctrlin & ACM_CTRL_DSR ? '+' : '-',
-                                  portdata->ctrlin & ACM_CTRL_BRK ? '+' : '-',
-                                  portdata->ctrlin & ACM_CTRL_RI  ? '+' : '-',
-                                  portdata->ctrlin & ACM_CTRL_FRAMING ? '+' : '-',
-                                  portdata->ctrlin & ACM_CTRL_PARITY ? '+' : '-',
-                                  portdata->ctrlin & ACM_CTRL_OVERRUN ? '+' : '-');
-               break;
-
-       default:
-               dev_dbg(&port->dev, "unknown notification %d received: index %d len %d data0 %d data1 %d\n",
-                                  dr->bNotificationType, dr->wIndex,
-                                  dr->wLength, data[0], data[1]);
-               break;
-       }
-exit:
-       dev_dbg(&port->dev, "Resubmitting interrupt IN urb %p\n", urb);
-       status = usb_submit_urb(urb, GFP_ATOMIC);
-       if (status)
-               dev_err(&port->dev, "usb_submit_urb failed with result %d", status);
-}
-
-static int vizzini_open(struct tty_struct *tty_param, struct usb_serial_port *port)
-{
-       struct vizzini_port_private *portdata;
-       struct usb_serial *serial = port->serial;
-       struct tty_struct *tty = port->port.tty;
-       int i;
-       struct urb *urb;
-       int result;
-
-       portdata = usb_get_serial_port_data(port);
-
-       acm_set_control(port, portdata->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS);
-
-       /* Reset low level data toggle and start reading from endpoints */
-       for (i = 0; i < N_IN_URB; i++) {
-               dev_dbg(&port->dev, "%s urb %d\n", __func__, i);
-
-               urb = portdata->in_urbs[i];
-               if (!urb)
-                       continue;
-               if (urb->dev != serial->dev) {
-                       dev_dbg(&port->dev, "%s: dev %p != %p\n", __func__,
-                                          urb->dev, serial->dev);
-                       continue;
-               }
-
-               /*
-                * make sure endpoint data toggle is synchronized with the
-                * device
-                */
-               /* dev_dbg(&port->dev, "%s clearing halt on %x\n", __func__, urb->pipe); */
-               /* usb_clear_halt(urb->dev, urb->pipe); */
-
-               dev_dbg(&port->dev, "%s submitting urb %p\n", __func__, urb);
-               result = usb_submit_urb(urb, GFP_KERNEL);
-               if (result) {
-                       dev_err(&port->dev, "submit urb %d failed (%d) %d\n",
-                               i, result, urb->transfer_buffer_length);
-               }
-       }
-
-       tty->low_latency = 1;
-
-       /* start up the interrupt endpoint if we have one */
-       if (port->interrupt_in_urb) {
-               result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
-               if (result)
-                       dev_err(&port->dev, "submit irq_in urb failed %d\n",
-                               result);
-       }
-       return 0;
-}
-
-static void vizzini_close(struct usb_serial_port *port)
-{
-       int                              i;
-       struct usb_serial               *serial = port->serial;
-       struct vizzini_port_private     *portdata;
-       struct tty_struct               *tty    = port->port.tty;
-
-       portdata = usb_get_serial_port_data(port);
-
-       acm_set_control(port, portdata->ctrlout = 0);
-
-       if (serial->dev) {
-               /* Stop reading/writing urbs */
-               for (i = 0; i < N_IN_URB; i++)
-                       usb_kill_urb(portdata->in_urbs[i]);
-       }
-
-       usb_kill_urb(port->interrupt_in_urb);
-
-       tty = NULL; /* FIXME */
-}
-
-static int vizzini_attach(struct usb_serial *serial)
-{
-       struct vizzini_serial_private   *serial_priv       = usb_get_serial_data(serial);
-       struct usb_interface            *interface         = serial_priv->data_interface;
-       struct usb_host_interface       *iface_desc;
-       struct usb_endpoint_descriptor  *endpoint;
-       struct usb_endpoint_descriptor  *bulk_in_endpoint  = NULL;
-       struct usb_endpoint_descriptor  *bulk_out_endpoint = NULL;
-
-       struct usb_serial_port          *port;
-       struct vizzini_port_private     *portdata;
-       struct urb                      *urb;
-       int                              i, j;
-
-       /* Assume that there's exactly one serial port. */
-       port = serial->port[0];
-
-       /* The usb_serial is now fully set up, but we want to make a
-        * couple of modifications.  Namely, it was configured based
-        * upon the control interface and not the data interface, so
-        * it has no notion of the bulk in and out endpoints.  So we
-        * essentially do some of the same allocations and
-        * configurations that the usb-serial core would have done if
-        * it had not made any faulty assumptions about the
-        * endpoints. */
-
-       iface_desc = interface->cur_altsetting;
-       for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
-               endpoint = &iface_desc->endpoint[i].desc;
-
-               if (usb_endpoint_is_bulk_in(endpoint))
-                       bulk_in_endpoint = endpoint;
-
-               if (usb_endpoint_is_bulk_out(endpoint))
-                       bulk_out_endpoint = endpoint;
-       }
-
-       if (!bulk_out_endpoint || !bulk_in_endpoint) {
-               dev_dbg(&port->dev, "Missing endpoint!\n");
-               return -EINVAL;
-       }
-
-       port->bulk_out_endpointAddress = bulk_out_endpoint->bEndpointAddress;
-       port->bulk_in_endpointAddress = bulk_in_endpoint->bEndpointAddress;
-
-       portdata = kzalloc(sizeof(*portdata), GFP_KERNEL);
-       if (!portdata) {
-               dev_dbg(&port->dev, "%s: kmalloc for vizzini_port_private (%d) failed!.\n",
-                                  __func__, i);
-               return -ENOMEM;
-       }
-       spin_lock_init(&portdata->lock);
-       for (j = 0; j < N_IN_URB; j++) {
-               portdata->in_buffer[j] = kmalloc(IN_BUFLEN, GFP_KERNEL);
-               if (!portdata->in_buffer[j]) {
-                       for (--j; j >= 0; j--)
-                               kfree(portdata->in_buffer[j]);
-                       kfree(portdata);
-                       return -ENOMEM;
-               }
-       }
-
-       /* Bulk OUT endpoints 0x1..0x4 map to register blocks 0..3 */
-       portdata->block = port->bulk_out_endpointAddress - 1;
-
-       usb_set_serial_port_data(port, portdata);
-
-       portdata->bcd_device = le16_to_cpu(serial->dev->descriptor.bcdDevice);
-       if (vizzini_rev_a(port))
-               dev_info(&port->dev, "Adapting to revA silicon\n");
-
-       /* initialize the in urbs */
-       for (j = 0; j < N_IN_URB; ++j) {
-               urb = usb_alloc_urb(0, GFP_KERNEL);
-               if (urb == NULL) {
-                       dev_dbg(&port->dev, "%s: alloc for in port failed.\n", __func__);
-                       continue;
-               }
-               /* Fill URB using supplied data. */
-               dev_dbg(&port->dev, "Filling URB %p, EP=%d buf=%p len=%d\n", urb, port->bulk_in_endpointAddress, portdata->in_buffer[j], IN_BUFLEN);
-               usb_fill_bulk_urb(urb, serial->dev,
-                                 usb_rcvbulkpipe(serial->dev,
-                                                 port->bulk_in_endpointAddress),
-                                 portdata->in_buffer[j], IN_BUFLEN,
-                                 vizzini_in_callback, port);
-               portdata->in_urbs[j] = urb;
-       }
-
-       return 0;
-}
-
-static void vizzini_serial_disconnect(struct usb_serial *serial)
-{
-       struct usb_serial_port          *port;
-       struct vizzini_port_private     *portdata;
-       int                              i, j;
-
-       dev_dbg(&serial->dev->dev, "%s %p\n", __func__, serial);
-
-       for (i = 0; i < serial->num_ports; ++i) {
-               port = serial->port[i];
-               if (!port)
-                       continue;
-               portdata = usb_get_serial_port_data(port);
-               if (!portdata)
-                       continue;
-
-               for (j = 0; j < N_IN_URB; j++) {
-                       usb_kill_urb(portdata->in_urbs[j]);
-                       usb_free_urb(portdata->in_urbs[j]);
-               }
-       }
-}
-
-static void vizzini_serial_release(struct usb_serial *serial)
-{
-       struct usb_serial_port          *port;
-       struct vizzini_port_private     *portdata;
-       int                              i, j;
-
-       dev_dbg(&serial->dev->dev, "%s %p\n", __func__, serial);
-
-       for (i = 0; i < serial->num_ports; ++i) {
-               port = serial->port[i];
-               if (!port)
-                       continue;
-               portdata = usb_get_serial_port_data(port);
-               if (!portdata)
-                       continue;
-
-               for (j = 0; j < N_IN_URB; j++)
-                       kfree(portdata->in_buffer[j]);
-
-               kfree(portdata);
-               usb_set_serial_port_data(port, NULL);
-       }
-}
-
-static int vizzini_calc_num_ports(struct usb_serial *serial)
-{
-       return 1;
-}
-
-static int vizzini_probe(struct usb_serial *serial,
-                        const struct usb_device_id *id)
-{
-       struct usb_interface *intf = serial->interface;
-       unsigned char *buffer = intf->altsetting->extra;
-       int buflen = intf->altsetting->extralen;
-       struct usb_device *usb_dev = interface_to_usbdev(intf);
-       struct usb_cdc_union_desc *union_header = NULL;
-       struct usb_cdc_country_functional_desc  *cfd = NULL;
-       int call_interface_num = -1;
-       int data_interface_num;
-       struct usb_interface *control_interface;
-       struct usb_interface *data_interface;
-       struct usb_endpoint_descriptor *epctrl;
-       struct usb_endpoint_descriptor *epread;
-       struct usb_endpoint_descriptor *epwrite;
-       struct vizzini_serial_private *serial_priv;
-
-       if (!buffer) {
-               dev_err(&intf->dev, "Weird descriptor references\n");
-               return -EINVAL;
-       }
-
-       if (!buflen) {
-               if (intf->cur_altsetting->endpoint->extralen && intf->cur_altsetting->endpoint->extra) {
-                       dev_dbg(&intf->dev, "Seeking extra descriptors on endpoint\n");
-                       buflen = intf->cur_altsetting->endpoint->extralen;
-                       buffer = intf->cur_altsetting->endpoint->extra;
-               } else {
-                       dev_err(&intf->dev, "Zero length descriptor references\n");
-                       return -EINVAL;
-               }
-       }
-
-       while (buflen > 0) {
-               if (buffer[1] != USB_DT_CS_INTERFACE) {
-                       dev_err(&intf->dev, "skipping garbage\n");
-                       goto next_desc;
-               }
-
-               switch (buffer[2]) {
-               case USB_CDC_UNION_TYPE: /* we've found it */
-                       if (union_header) {
-                               dev_err(&intf->dev, "More than one union descriptor, skipping ...\n");
-                               goto next_desc;
-                       }
-                       union_header = (struct usb_cdc_union_desc *)buffer;
-                       break;
-               case USB_CDC_COUNTRY_TYPE: /* export through sysfs */
-                       cfd = (struct usb_cdc_country_functional_desc *)buffer;
-                       break;
-               case USB_CDC_HEADER_TYPE: /* maybe check version */
-                       break; /* for now we ignore it */
-               case USB_CDC_CALL_MANAGEMENT_TYPE:
-                       call_interface_num = buffer[4];
-                       break;
-               default:
-                       /* there are LOTS more CDC descriptors that
-                        * could legitimately be found here.
-                        */
-                       dev_dbg(&intf->dev, "Ignoring descriptor: type %02x, length %d\n", buffer[2], buffer[0]);
-                       break;
-               }
-next_desc:
-               buflen -= buffer[0];
-               buffer += buffer[0];
-       }
-
-       if (!union_header) {
-               if (call_interface_num > 0) {
-                       dev_dbg(&intf->dev, "No union descriptor, using call management descriptor\n");
-                       data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num));
-                       control_interface = intf;
-               } else {
-                       dev_dbg(&intf->dev, "No union descriptor, giving up\n");
-                       return -ENODEV;
-               }
-       } else {
-               control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0);
-               data_interface    = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0));
-               if (!control_interface || !data_interface) {
-                       dev_dbg(&intf->dev, "no interfaces\n");
-                       return -ENODEV;
-               }
-       }
-
-       if (data_interface_num != call_interface_num)
-               dev_dbg(&intf->dev, "Separate call control interface. That is not fully supported.\n");
-
-       /* workaround for switched interfaces */
-       if (data_interface->cur_altsetting->desc.bInterfaceClass != CDC_DATA_INTERFACE_TYPE) {
-               if (control_interface->cur_altsetting->desc.bInterfaceClass == CDC_DATA_INTERFACE_TYPE) {
-                       struct usb_interface *t;
-
-                       t = control_interface;
-                       control_interface = data_interface;
-                       data_interface = t;
-               } else {
-                       return -EINVAL;
-               }
-       }
-
-       /* Accept probe requests only for the control interface */
-       if (intf != control_interface)
-               return -ENODEV;
-
-       if (usb_interface_claimed(data_interface)) { /* valid in this context */
-               dev_dbg(&intf->dev, "The data interface isn't available\n");
-               return -EBUSY;
-       }
-
-       if (data_interface->cur_altsetting->desc.bNumEndpoints < 2)
-               return -EINVAL;
-
-       epctrl  = &control_interface->cur_altsetting->endpoint[0].desc;
-       epread  = &data_interface->cur_altsetting->endpoint[0].desc;
-       epwrite = &data_interface->cur_altsetting->endpoint[1].desc;
-       if (!usb_endpoint_dir_in(epread)) {
-               struct usb_endpoint_descriptor *t;
-               t   = epread;
-               epread  = epwrite;
-               epwrite = t;
-       }
-
-       /* The documentation suggests that we allocate private storage
-        * with the attach() entry point, but we can't allow the data
-        * interface to remain unclaimed until then; so we need
-        * somewhere to save the claimed interface now. */
-       serial_priv = kzalloc(sizeof(struct vizzini_serial_private),
-                             GFP_KERNEL);
-       if (!serial_priv)
-               goto alloc_fail;
-       usb_set_serial_data(serial, serial_priv);
-
-       //usb_driver_claim_interface(&vizzini_driver, data_interface, NULL);
-
-       /* Don't set the data interface private data.  When we
-        * disconnect we test this field against NULL to discover
-        * whether we're dealing with the control or data
-        * interface. */
-       serial_priv->data_interface = data_interface;
-
-       return 0;
-
-alloc_fail:
-       return -ENOMEM;
-}
-
-static struct usb_serial_driver vizzini_device = {
-       .driver = {
-               .owner =    THIS_MODULE,
-               .name =     "vizzini",
-       },
-       .description =          "Vizzini USB serial port",
-       .id_table =             id_table,
-       .calc_num_ports =       vizzini_calc_num_ports,
-       .probe =                vizzini_probe,
-       .open =                 vizzini_open,
-       .close =                vizzini_close,
-       .write =                vizzini_write,
-       .write_room =           vizzini_write_room,
-       .ioctl =                vizzini_ioctl,
-       .set_termios =          vizzini_set_termios,
-       .break_ctl =            vizzini_break_ctl,
-       .tiocmget =             vizzini_tiocmget,
-       .tiocmset =             vizzini_tiocmset,
-       .attach =               vizzini_attach,
-       .disconnect =           vizzini_serial_disconnect,
-       .release =              vizzini_serial_release,
-       .read_int_callback =    vizzini_int_callback,
-};
-
-static struct usb_serial_driver * const serial_drivers[] = {
-       &vizzini_device, NULL
-};
-
-module_usb_serial_driver(serial_drivers, id_table);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_VERSION(DRIVER_VERSION);
-MODULE_LICENSE("GPL");
index 638cd64f961014bf59fd75f10542595a651bc9bd..15789097edd6fcdaa1a64609aa11c3d34b9faf5d 100644 (file)
@@ -41,6 +41,7 @@ struct sense_iu_old {
 struct uas_dev_info {
        struct usb_interface *intf;
        struct usb_device *udev;
+       struct usb_anchor cmd_urbs;
        struct usb_anchor sense_urbs;
        struct usb_anchor data_urbs;
        int qdepth, resetting;
@@ -49,6 +50,7 @@ struct uas_dev_info {
        unsigned use_streams:1;
        unsigned uas_sense_old:1;
        struct scsi_cmnd *cmnd;
+       spinlock_t lock;
 };
 
 enum {
@@ -63,13 +65,13 @@ enum {
        DATA_IN_URB_INFLIGHT    = (1 << 9),
        DATA_OUT_URB_INFLIGHT   = (1 << 10),
        COMMAND_COMPLETED       = (1 << 11),
+       COMMAND_ABORTED         = (1 << 12),
 };
 
 /* Overrides scsi_pointer */
 struct uas_cmd_info {
        unsigned int state;
        unsigned int stream;
-       unsigned int aborted;
        struct urb *cmd_urb;
        struct urb *data_in_urb;
        struct urb *data_out_urb;
@@ -90,6 +92,7 @@ static void uas_do_work(struct work_struct *work)
        struct uas_cmd_info *cmdinfo;
        struct uas_cmd_info *temp;
        struct list_head list;
+       unsigned long flags;
        int err;
 
        spin_lock_irq(&uas_work_lock);
@@ -100,7 +103,10 @@ static void uas_do_work(struct work_struct *work)
                struct scsi_pointer *scp = (void *)cmdinfo;
                struct scsi_cmnd *cmnd = container_of(scp,
                                                        struct scsi_cmnd, SCp);
-               err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_NOIO);
+               struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
+               spin_lock_irqsave(&devinfo->lock, flags);
+               err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC);
+               spin_unlock_irqrestore(&devinfo->lock, flags);
                if (err) {
                        list_del(&cmdinfo->list);
                        spin_lock_irq(&uas_work_lock);
@@ -162,7 +168,7 @@ static void uas_log_cmd_state(struct scsi_cmnd *cmnd, const char *caller)
        struct uas_cmd_info *ci = (void *)&cmnd->SCp;
 
        scmd_printk(KERN_INFO, cmnd, "%s %p tag %d, inflight:"
-                   "%s%s%s%s%s%s%s%s%s%s%s\n",
+                   "%s%s%s%s%s%s%s%s%s%s%s%s\n",
                    caller, cmnd, cmnd->request->tag,
                    (ci->state & SUBMIT_STATUS_URB)     ? " s-st"  : "",
                    (ci->state & ALLOC_DATA_IN_URB)     ? " a-in"  : "",
@@ -174,13 +180,16 @@ static void uas_log_cmd_state(struct scsi_cmnd *cmnd, const char *caller)
                    (ci->state & COMMAND_INFLIGHT)      ? " CMD"   : "",
                    (ci->state & DATA_IN_URB_INFLIGHT)  ? " IN"    : "",
                    (ci->state & DATA_OUT_URB_INFLIGHT) ? " OUT"   : "",
-                   (ci->state & COMMAND_COMPLETED)     ? " done"  : "");
+                   (ci->state & COMMAND_COMPLETED)     ? " done"  : "",
+                   (ci->state & COMMAND_ABORTED)       ? " abort" : "");
 }
 
 static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller)
 {
        struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
+       struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
 
+       WARN_ON(!spin_is_locked(&devinfo->lock));
        if (cmdinfo->state & (COMMAND_INFLIGHT |
                              DATA_IN_URB_INFLIGHT |
                              DATA_OUT_URB_INFLIGHT))
@@ -189,6 +198,10 @@ static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller)
        cmdinfo->state |= COMMAND_COMPLETED;
        usb_free_urb(cmdinfo->data_in_urb);
        usb_free_urb(cmdinfo->data_out_urb);
+       if (cmdinfo->state & COMMAND_ABORTED) {
+               scmd_printk(KERN_INFO, cmnd, "abort completed\n");
+               cmnd->result = DID_ABORT << 16;
+       }
        cmnd->scsi_done(cmnd);
        return 0;
 }
@@ -216,6 +229,7 @@ static void uas_stat_cmplt(struct urb *urb)
        struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
        struct scsi_cmnd *cmnd;
        struct uas_cmd_info *cmdinfo;
+       unsigned long flags;
        u16 tag;
 
        if (urb->status) {
@@ -229,6 +243,7 @@ static void uas_stat_cmplt(struct urb *urb)
                return;
        }
 
+       spin_lock_irqsave(&devinfo->lock, flags);
        tag = be16_to_cpup(&iu->tag) - 1;
        if (tag == 0)
                cmnd = devinfo->cmnd;
@@ -237,6 +252,7 @@ static void uas_stat_cmplt(struct urb *urb)
        if (!cmnd) {
                if (iu->iu_id != IU_ID_RESPONSE) {
                        usb_free_urb(urb);
+                       spin_unlock_irqrestore(&devinfo->lock, flags);
                        return;
                }
        } else {
@@ -256,10 +272,16 @@ static void uas_stat_cmplt(struct urb *urb)
                        uas_sense(urb, cmnd);
                if (cmnd->result != 0) {
                        /* cancel data transfers on error */
-                       if (cmdinfo->state & DATA_IN_URB_INFLIGHT)
+                       if (cmdinfo->state & DATA_IN_URB_INFLIGHT) {
+                               spin_unlock_irqrestore(&devinfo->lock, flags);
                                usb_unlink_urb(cmdinfo->data_in_urb);
-                       if (cmdinfo->state & DATA_OUT_URB_INFLIGHT)
+                               spin_lock_irqsave(&devinfo->lock, flags);
+                       }
+                       if (cmdinfo->state & DATA_OUT_URB_INFLIGHT) {
+                               spin_unlock_irqrestore(&devinfo->lock, flags);
                                usb_unlink_urb(cmdinfo->data_out_urb);
+                               spin_lock_irqsave(&devinfo->lock, flags);
+                       }
                }
                cmdinfo->state &= ~COMMAND_INFLIGHT;
                uas_try_complete(cmnd, __func__);
@@ -279,14 +301,18 @@ static void uas_stat_cmplt(struct urb *urb)
                        "Bogus IU (%d) received on status pipe\n", iu->iu_id);
        }
        usb_free_urb(urb);
+       spin_unlock_irqrestore(&devinfo->lock, flags);
 }
 
 static void uas_data_cmplt(struct urb *urb)
 {
        struct scsi_cmnd *cmnd = urb->context;
        struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
+       struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
        struct scsi_data_buffer *sdb = NULL;
+       unsigned long flags;
 
+       spin_lock_irqsave(&devinfo->lock, flags);
        if (cmdinfo->data_in_urb == urb) {
                sdb = scsi_in(cmnd);
                cmdinfo->state &= ~DATA_IN_URB_INFLIGHT;
@@ -301,10 +327,8 @@ static void uas_data_cmplt(struct urb *urb)
        } else {
                sdb->resid = sdb->length - urb->actual_length;
        }
-       if (cmdinfo->aborted) {
-               return;
-       }
        uas_try_complete(cmnd, __func__);
+       spin_unlock_irqrestore(&devinfo->lock, flags);
 }
 
 static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp,
@@ -431,6 +455,7 @@ static int uas_submit_task_urb(struct scsi_cmnd *cmnd, gfp_t gfp,
        err = usb_submit_urb(urb, gfp);
        if (err)
                goto err;
+       usb_anchor_urb(urb, &devinfo->cmd_urbs);
 
        return 0;
 
@@ -470,6 +495,7 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,
        struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
        int err;
 
+       WARN_ON(!spin_is_locked(&devinfo->lock));
        if (cmdinfo->state & SUBMIT_STATUS_URB) {
                err = uas_submit_sense_urb(cmnd->device->host, gfp,
                                           cmdinfo->stream);
@@ -521,18 +547,22 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,
 
        if (cmdinfo->state & ALLOC_CMD_URB) {
                cmdinfo->cmd_urb = uas_alloc_cmd_urb(devinfo, gfp, cmnd,
-                                                       cmdinfo->stream);
+                                                    cmdinfo->stream);
                if (!cmdinfo->cmd_urb)
                        return SCSI_MLQUEUE_DEVICE_BUSY;
                cmdinfo->state &= ~ALLOC_CMD_URB;
        }
 
        if (cmdinfo->state & SUBMIT_CMD_URB) {
+               usb_get_urb(cmdinfo->cmd_urb);
                if (usb_submit_urb(cmdinfo->cmd_urb, gfp)) {
                        scmd_printk(KERN_INFO, cmnd,
                                        "cmd urb submission failure\n");
                        return SCSI_MLQUEUE_DEVICE_BUSY;
                }
+               usb_anchor_urb(cmdinfo->cmd_urb, &devinfo->cmd_urbs);
+               usb_put_urb(cmdinfo->cmd_urb);
+               cmdinfo->cmd_urb = NULL;
                cmdinfo->state &= ~SUBMIT_CMD_URB;
                cmdinfo->state |= COMMAND_INFLIGHT;
        }
@@ -546,12 +576,16 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
        struct scsi_device *sdev = cmnd->device;
        struct uas_dev_info *devinfo = sdev->hostdata;
        struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
+       unsigned long flags;
        int err;
 
        BUILD_BUG_ON(sizeof(struct uas_cmd_info) > sizeof(struct scsi_pointer));
 
-       if (devinfo->cmnd)
+       spin_lock_irqsave(&devinfo->lock, flags);
+       if (devinfo->cmnd) {
+               spin_unlock_irqrestore(&devinfo->lock, flags);
                return SCSI_MLQUEUE_DEVICE_BUSY;
+       }
 
        if (blk_rq_tagged(cmnd->request)) {
                cmdinfo->stream = cmnd->request->tag + 2;
@@ -564,7 +598,6 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
 
        cmdinfo->state = SUBMIT_STATUS_URB |
                        ALLOC_CMD_URB | SUBMIT_CMD_URB;
-       cmdinfo->aborted = 0;
 
        switch (cmnd->sc_data_direction) {
        case DMA_FROM_DEVICE:
@@ -587,6 +620,7 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
        if (err) {
                /* If we did nothing, give up now */
                if (cmdinfo->state & SUBMIT_STATUS_URB) {
+                       spin_unlock_irqrestore(&devinfo->lock, flags);
                        return SCSI_MLQUEUE_DEVICE_BUSY;
                }
                spin_lock(&uas_work_lock);
@@ -595,6 +629,7 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
                schedule_work(&uas_work);
        }
 
+       spin_unlock_irqrestore(&devinfo->lock, flags);
        return 0;
 }
 
@@ -605,22 +640,26 @@ static int uas_eh_task_mgmt(struct scsi_cmnd *cmnd,
 {
        struct Scsi_Host *shost = cmnd->device->host;
        struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
-       u16 tag = 9999; /* FIXME */
+       u16 tag = devinfo->qdepth - 1;
+       unsigned long flags;
 
+       spin_lock_irqsave(&devinfo->lock, flags);
        memset(&devinfo->response, 0, sizeof(devinfo->response));
-       if (uas_submit_sense_urb(shost, GFP_NOIO, tag)) {
+       if (uas_submit_sense_urb(shost, GFP_ATOMIC, tag)) {
                shost_printk(KERN_INFO, shost,
                             "%s: %s: submit sense urb failed\n",
                             __func__, fname);
                return FAILED;
        }
-       if (uas_submit_task_urb(cmnd, GFP_NOIO, function, tag)) {
+       if (uas_submit_task_urb(cmnd, GFP_ATOMIC, function, tag)) {
                shost_printk(KERN_INFO, shost,
                             "%s: %s: submit task mgmt urb failed\n",
                             __func__, fname);
                return FAILED;
        }
-       if (0 == usb_wait_anchor_empty_timeout(&devinfo->sense_urbs, 3000)) {
+       spin_unlock_irqrestore(&devinfo->lock, flags);
+
+       if (usb_wait_anchor_empty_timeout(&devinfo->sense_urbs, 3000) == 0) {
                shost_printk(KERN_INFO, shost,
                             "%s: %s timed out\n", __func__, fname);
                return FAILED;
@@ -643,15 +682,15 @@ static int uas_eh_task_mgmt(struct scsi_cmnd *cmnd,
 static int uas_eh_abort_handler(struct scsi_cmnd *cmnd)
 {
        struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
+       struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
+       unsigned long flags;
        int ret;
 
        uas_log_cmd_state(cmnd, __func__);
-       cmdinfo->aborted = 1;
+       spin_lock_irqsave(&devinfo->lock, flags);
+       cmdinfo->state |= COMMAND_ABORTED;
+       spin_unlock_irqrestore(&devinfo->lock, flags);
        ret = uas_eh_task_mgmt(cmnd, "ABORT TASK", TMF_ABORT_TASK);
-       if (cmdinfo->state & DATA_IN_URB_INFLIGHT)
-               usb_kill_urb(cmdinfo->data_in_urb);
-       if (cmdinfo->state & DATA_OUT_URB_INFLIGHT)
-               usb_kill_urb(cmdinfo->data_out_urb);
        return ret;
 }
 
@@ -670,6 +709,7 @@ static int uas_eh_bus_reset_handler(struct scsi_cmnd *cmnd)
        int err;
 
        devinfo->resetting = 1;
+       usb_kill_anchored_urbs(&devinfo->cmd_urbs);
        usb_kill_anchored_urbs(&devinfo->sense_urbs);
        usb_kill_anchored_urbs(&devinfo->data_urbs);
        err = usb_reset_device(udev);
@@ -694,7 +734,7 @@ static int uas_slave_configure(struct scsi_device *sdev)
 {
        struct uas_dev_info *devinfo = sdev->hostdata;
        scsi_set_tag_type(sdev, MSG_ORDERED_TAG);
-       scsi_activate_tcq(sdev, devinfo->qdepth - 2);
+       scsi_activate_tcq(sdev, devinfo->qdepth - 3);
        return 0;
 }
 
@@ -868,11 +908,13 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id)
        devinfo->intf = intf;
        devinfo->udev = udev;
        devinfo->resetting = 0;
+       init_usb_anchor(&devinfo->cmd_urbs);
        init_usb_anchor(&devinfo->sense_urbs);
        init_usb_anchor(&devinfo->data_urbs);
+       spin_lock_init(&devinfo->lock);
        uas_configure_endpoints(devinfo);
 
-       result = scsi_init_shared_tag_map(shost, devinfo->qdepth - 2);
+       result = scsi_init_shared_tag_map(shost, devinfo->qdepth - 3);
        if (result)
                goto free;
 
@@ -913,6 +955,7 @@ static void uas_disconnect(struct usb_interface *intf)
        struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
 
        scsi_remove_host(shost);
+       usb_kill_anchored_urbs(&devinfo->cmd_urbs);
        usb_kill_anchored_urbs(&devinfo->sense_urbs);
        usb_kill_anchored_urbs(&devinfo->data_urbs);
        uas_free_streams(devinfo);
index 38b5660813ff25f219f1922071a73f21b5738289..a82296af413fbe981d2b6ff7a8453954d6a0e248 100644 (file)
@@ -19,7 +19,7 @@
 
 #define FSL_UTMI_PHY_DLY       10      /*As per P1010RM, delay for UTMI
                                PHY CLK to become stable - 10ms*/
-#define FSL_USB_PHY_CLK_TIMEOUT        1000    /* uSec */
+#define FSL_USB_PHY_CLK_TIMEOUT        10000   /* uSec */
 #define FSL_USB_VER_OLD                0
 #define FSL_USB_VER_1_6                1
 #define FSL_USB_VER_2_2                2