diff options
-rw-r--r-- | Documentation/ABI/testing/sysfs-bus-usb | 24 | ||||
-rw-r--r-- | drivers/usb/core/hub.c | 133 | ||||
-rw-r--r-- | drivers/usb/host/ehci-fsl.c | 3 | ||||
-rw-r--r-- | drivers/usb/serial/Kconfig | 8 | ||||
-rw-r--r-- | drivers/usb/serial/Makefile | 1 | ||||
-rw-r--r-- | drivers/usb/serial/ftdi_sio.c | 2 | ||||
-rw-r--r-- | drivers/usb/serial/ftdi_sio_ids.h | 5 | ||||
-rw-r--r-- | drivers/usb/serial/vizzini.c | 1354 | ||||
-rw-r--r-- | drivers/usb/storage/uas.c | 89 | ||||
-rw-r--r-- | include/linux/fsl_devices.h | 2 |
10 files changed, 76 insertions, 1545 deletions
diff --git a/Documentation/ABI/testing/sysfs-bus-usb b/Documentation/ABI/testing/sysfs-bus-usb index 13f3eeee1599..b6fbe514a869 100644 --- a/Documentation/ABI/testing/sysfs-bus-usb +++ b/Documentation/ABI/testing/sysfs-bus-usb @@ -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 diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 6dc41c6399de..673ee4696262 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -39,17 +39,11 @@ #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}, diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index 11ff4b4dc7ad..9bfde82078ec 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -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)) { diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index a5c144694005..f604f707a058 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -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 diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile index 5fd21a01b009..45871f9ad1e1 100644 --- a/drivers/usb/serial/Makefile +++ b/drivers/usb/serial/Makefile @@ -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 diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 8742a0ee2091..9169f51777ef 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -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: */ diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 41fe5826100c..57c12ef6625e 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -517,6 +517,11 @@ */ #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 index 7f436949dd99..000000000000 --- a/drivers/usb/serial/vizzini.c +++ /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"); diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index 638cd64f9610..15789097edd6 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c @@ -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); diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h index 38b5660813ff..a82296af413f 100644 --- a/include/linux/fsl_devices.h +++ b/include/linux/fsl_devices.h @@ -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 |