diff options
-rw-r--r-- | drivers/usb/serial/Kconfig | 8 | ||||
-rw-r--r-- | drivers/usb/serial/Makefile | 1 | ||||
-rw-r--r-- | drivers/usb/serial/vizzini.c | 1354 |
3 files changed, 0 insertions, 1363 deletions
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/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"); |