aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/serial
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/serial')
-rw-r--r--drivers/usb/serial/Kconfig107
-rw-r--r--drivers/usb/serial/Makefile10
-rw-r--r--drivers/usb/serial/aircable.c27
-rw-r--r--drivers/usb/serial/ark3116.c108
-rw-r--r--drivers/usb/serial/belkin_sa.c15
-rw-r--r--drivers/usb/serial/bus.c46
-rw-r--r--drivers/usb/serial/ch341.c160
-rw-r--r--drivers/usb/serial/console.c36
-rw-r--r--drivers/usb/serial/cp210x.c46
-rw-r--r--drivers/usb/serial/cyberjack.c37
-rw-r--r--drivers/usb/serial/cypress_m8.c138
-rw-r--r--drivers/usb/serial/cypress_m8.h34
-rw-r--r--drivers/usb/serial/digi_acceleport.c133
-rw-r--r--drivers/usb/serial/empeg.c1
-rw-r--r--drivers/usb/serial/f81232.c88
-rw-r--r--drivers/usb/serial/ftdi_sio.c448
-rw-r--r--drivers/usb/serial/ftdi_sio_ids.h126
-rw-r--r--drivers/usb/serial/funsoft.c40
-rw-r--r--drivers/usb/serial/garmin_gps.c52
-rw-r--r--drivers/usb/serial/generic.c319
-rw-r--r--drivers/usb/serial/hp4x.c51
-rw-r--r--drivers/usb/serial/io_edgeport.c252
-rw-r--r--drivers/usb/serial/io_tables.h12
-rw-r--r--drivers/usb/serial/io_ti.c427
-rw-r--r--drivers/usb/serial/io_usbvend.h2
-rw-r--r--drivers/usb/serial/ipaq.c3
-rw-r--r--drivers/usb/serial/ipw.c1
-rw-r--r--drivers/usb/serial/ir-usb.c18
-rw-r--r--drivers/usb/serial/iuu_phoenix.c47
-rw-r--r--drivers/usb/serial/keyspan.c392
-rw-r--r--drivers/usb/serial/keyspan_pda.c37
-rw-r--r--drivers/usb/serial/keyspan_usa26msg.h2
-rw-r--r--drivers/usb/serial/kl5kusb105.c61
-rw-r--r--drivers/usb/serial/kobil_sct.c140
-rw-r--r--drivers/usb/serial/mct_u232.c164
-rw-r--r--drivers/usb/serial/metro-usb.c23
-rw-r--r--drivers/usb/serial/mos7720.c217
-rw-r--r--drivers/usb/serial/mos7840.c532
-rw-r--r--drivers/usb/serial/moto_modem.c48
-rw-r--r--drivers/usb/serial/mxuport.c1393
-rw-r--r--drivers/usb/serial/navman.c10
-rw-r--r--drivers/usb/serial/omninet.c86
-rw-r--r--drivers/usb/serial/opticon.c42
-rw-r--r--drivers/usb/serial/option.c522
-rw-r--r--drivers/usb/serial/oti6858.c110
-rw-r--r--drivers/usb/serial/pl2303.c666
-rw-r--r--drivers/usb/serial/pl2303.h5
-rw-r--r--drivers/usb/serial/qcaux.c4
-rw-r--r--drivers/usb/serial/qcserial.c135
-rw-r--r--drivers/usb/serial/quatech2.c207
-rw-r--r--drivers/usb/serial/safe_serial.c69
-rw-r--r--drivers/usb/serial/siemens_mpi.c47
-rw-r--r--drivers/usb/serial/sierra.c261
-rw-r--r--drivers/usb/serial/spcp8x5.c348
-rw-r--r--drivers/usb/serial/ssu100.c155
-rw-r--r--drivers/usb/serial/symbolserial.c142
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.c366
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.h4
-rw-r--r--drivers/usb/serial/usb-serial-simple.c110
-rw-r--r--drivers/usb/serial/usb-serial.c442
-rw-r--r--drivers/usb/serial/usb-wwan.h6
-rw-r--r--drivers/usb/serial/usb_debug.c1
-rw-r--r--drivers/usb/serial/usb_wwan.c315
-rw-r--r--drivers/usb/serial/visor.c44
-rw-r--r--drivers/usb/serial/visor.h2
-rw-r--r--drivers/usb/serial/vivopay-serial.c43
-rw-r--r--drivers/usb/serial/whiteheat.c31
-rw-r--r--drivers/usb/serial/wishbone-serial.c94
-rw-r--r--drivers/usb/serial/xsens_mt.c85
-rw-r--r--drivers/usb/serial/zio.c39
-rw-r--r--drivers/usb/serial/zte_ev.c78
71 files changed, 5322 insertions, 4940 deletions
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index 76f46224173..3ce5c74b29e 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -4,7 +4,7 @@
menuconfig USB_SERIAL
tristate "USB Serial Converter support"
- depends on USB
+ depends on TTY
---help---
Say Y here if you have a USB device that provides normal serial
ports, or acts like a serial device, and you want to connect it to
@@ -51,6 +51,24 @@ config USB_SERIAL_GENERIC
support" be compiled as a module for this driver to be used
properly.
+config USB_SERIAL_SIMPLE
+ tristate "USB Serial Simple Driver"
+ help
+ Say Y here to use the USB serial "simple" driver. This driver
+ handles a wide range of very simple devices, all in one
+ driver. Specifically, it supports:
+ - Suunto ANT+ USB device.
+ - Fundamental Software dongle.
+ - HP4x calculators
+ - a number of Motorola phones
+ - Siemens USB/MPI adapter.
+ - ViVOtech ViVOpay USB device.
+ - Infineon Modem Flashloader USB interface
+ - ZIO Motherboard USB serial interface
+
+ To compile this driver as a module, choose M here: the module
+ will be called usb-serial-simple.
+
config USB_SERIAL_AIRCABLE
tristate "USB AIRcable Bluetooth Dongle Driver"
help
@@ -158,14 +176,6 @@ config USB_SERIAL_FTDI_SIO
To compile this driver as a module, choose M here: the
module will be called ftdi_sio.
-config USB_SERIAL_FUNSOFT
- tristate "USB Fundamental Software Dongle Driver"
- ---help---
- Say Y here if you want to use the Fundamental Software dongle.
-
- To compile this driver as a module, choose M here: the
- module will be called funsoft.
-
config USB_SERIAL_VISOR
tristate "USB Handspring Visor / Palm m50x / Sony Clie Driver"
help
@@ -462,14 +472,34 @@ config USB_SERIAL_MOS7840
To compile this driver as a module, choose M here: the
module will be called mos7840. If unsure, choose N.
-config USB_SERIAL_MOTOROLA
- tristate "USB Motorola Phone modem driver"
+config USB_SERIAL_MXUPORT
+ tristate "USB Moxa UPORT Serial Driver"
---help---
- Say Y here if you want to use a Motorola phone with a USB
- connector as a modem link.
+ Say Y here if you want to use a MOXA UPort Serial hub.
+
+ This driver supports:
+
+ [2 Port]
+ - UPort 1250 : 2 Port RS-232/422/485 USB to Serial Hub
+ - UPort 1250I : 2 Port RS-232/422/485 USB to Serial Hub with
+ Isolation
+
+ [4 Port]
+ - UPort 1410 : 4 Port RS-232 USB to Serial Hub
+ - UPort 1450 : 4 Port RS-232/422/485 USB to Serial Hub
+ - UPort 1450I : 4 Port RS-232/422/485 USB to Serial Hub with
+ Isolation
+
+ [8 Port]
+ - UPort 1610-8 : 8 Port RS-232 USB to Serial Hub
+ - UPort 1650-8 : 8 Port RS-232/422/485 USB to Serial Hub
+
+ [16 Port]
+ - UPort 1610-16 : 16 Port RS-232 USB to Serial Hub
+ - UPort 1650-16 : 16 Port RS-232/422/485 USB to Serial Hub
To compile this driver as a module, choose M here: the
- module will be called moto_modem. If unsure, choose N.
+ module will be called mxuport.
config USB_SERIAL_NAVMAN
tristate "USB Navman GPS device"
@@ -525,14 +555,6 @@ config USB_SERIAL_SPCP8X5
To compile this driver as a module, choose M here: the
module will be called spcp8x5.
-config USB_SERIAL_HP4X
- tristate "USB HP4x Calculators support"
- help
- Say Y here if you want to use an Hewlett-Packard 4x Calculator.
-
- To compile this driver as a module, choose M here: the
- module will be called hp4x.
-
config USB_SERIAL_SAFE
tristate "USB Safe Serial (Encapsulated) Driver"
@@ -540,14 +562,6 @@ config USB_SERIAL_SAFE_PADDED
bool "USB Secure Encapsulated Driver - Padded"
depends on USB_SERIAL_SAFE
-config USB_SERIAL_SIEMENS_MPI
- tristate "USB Siemens MPI driver"
- help
- Say M here if you want to use a Siemens USB/MPI adapter.
-
- To compile this driver as a module, choose M here: the
- module will be called siemens_mpi.
-
config USB_SERIAL_SIERRAWIRELESS
tristate "USB Sierra Wireless Driver"
help
@@ -639,21 +653,34 @@ config USB_SERIAL_OPTICON
To compile this driver as a module, choose M here: the
module will be called opticon.
-config USB_SERIAL_VIVOPAY_SERIAL
- tristate "USB ViVOpay serial interface driver"
- help
- Say Y here if you want to use a ViVOtech ViVOpay USB device.
+config USB_SERIAL_XSENS_MT
+ tristate "Xsens motion tracker serial interface driver"
+ help
+ Say Y here if you want to use Xsens motion trackers.
- To compile this driver as a module, choose M here: the
- module will be called vivopay-serial.
+ This driver supports the new generation of motion trackers
+ by Xsens. Older devices can be accessed using the FTDI_SIO
+ driver.
+
+ To compile this driver as a module, choose M here: the
+ module will be called xsens_mt.
-config USB_SERIAL_ZIO
- tristate "ZIO Motherboard USB serial interface driver"
+config USB_SERIAL_WISHBONE
+ tristate "USB-Wishbone adapter interface driver"
help
- Say Y here if you want to use ZIO Motherboard.
+ Say Y here if you want to use a USB attached Wishbone bus.
+
+ Wishbone is an open hardware SoC bus commonly used in FPGA
+ designs. Bus access can be serialized using the Etherbone
+ protocol <http://www.ohwr.org/projects/etherbone-core>.
+
+ This driver is intended to be used with devices which attach
+ their internal Wishbone bus to a USB serial interface using
+ the Etherbone protocol. A userspace library is required to
+ speak the protocol made available by this driver as ttyUSBx.
To compile this driver as a module, choose M here: the
- module will be called zio.
+ module will be called wishbone-serial.
config USB_SERIAL_ZTE
tristate "ZTE USB serial driver"
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index 3b3e7308d47..bfdafd34944 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -24,9 +24,7 @@ obj-$(CONFIG_USB_SERIAL_EDGEPORT_TI) += io_ti.o
obj-$(CONFIG_USB_SERIAL_EMPEG) += empeg.o
obj-$(CONFIG_USB_SERIAL_F81232) += f81232.o
obj-$(CONFIG_USB_SERIAL_FTDI_SIO) += ftdi_sio.o
-obj-$(CONFIG_USB_SERIAL_FUNSOFT) += funsoft.o
obj-$(CONFIG_USB_SERIAL_GARMIN) += garmin_gps.o
-obj-$(CONFIG_USB_SERIAL_HP4X) += hp4x.o
obj-$(CONFIG_USB_SERIAL_IPAQ) += ipaq.o
obj-$(CONFIG_USB_SERIAL_IPW) += ipw.o
obj-$(CONFIG_USB_SERIAL_IR) += ir-usb.o
@@ -39,7 +37,7 @@ obj-$(CONFIG_USB_SERIAL_MCT_U232) += mct_u232.o
obj-$(CONFIG_USB_SERIAL_METRO) += metro-usb.o
obj-$(CONFIG_USB_SERIAL_MOS7720) += mos7720.o
obj-$(CONFIG_USB_SERIAL_MOS7840) += mos7840.o
-obj-$(CONFIG_USB_SERIAL_MOTOROLA) += moto_modem.o
+obj-$(CONFIG_USB_SERIAL_MXUPORT) += mxuport.o
obj-$(CONFIG_USB_SERIAL_NAVMAN) += navman.o
obj-$(CONFIG_USB_SERIAL_OMNINET) += omninet.o
obj-$(CONFIG_USB_SERIAL_OPTICON) += opticon.o
@@ -50,16 +48,16 @@ obj-$(CONFIG_USB_SERIAL_QCAUX) += qcaux.o
obj-$(CONFIG_USB_SERIAL_QUALCOMM) += qcserial.o
obj-$(CONFIG_USB_SERIAL_QT2) += quatech2.o
obj-$(CONFIG_USB_SERIAL_SAFE) += safe_serial.o
-obj-$(CONFIG_USB_SERIAL_SIEMENS_MPI) += siemens_mpi.o
obj-$(CONFIG_USB_SERIAL_SIERRAWIRELESS) += sierra.o
+obj-$(CONFIG_USB_SERIAL_SIMPLE) += usb-serial-simple.o
obj-$(CONFIG_USB_SERIAL_SPCP8X5) += spcp8x5.o
obj-$(CONFIG_USB_SERIAL_SSU100) += ssu100.o
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_WISHBONE) += wishbone-serial.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
-obj-$(CONFIG_USB_SERIAL_ZIO) += zio.o
+obj-$(CONFIG_USB_SERIAL_XSENS_MT) += xsens_mt.o
obj-$(CONFIG_USB_SERIAL_ZTE) += zte_ev.o
diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c
index 6d110a3bc7e..80a9845cd93 100644
--- a/drivers/usb/serial/aircable.c
+++ b/drivers/usb/serial/aircable.c
@@ -10,9 +10,9 @@
*
* The device works as an standard CDC device, it has 2 interfaces, the first
* one is for firmware access and the second is the serial one.
- * The protocol is very simply, there are two posibilities reading or writing.
+ * The protocol is very simply, there are two possibilities reading or writing.
* When writing the first urb must have a Header that starts with 0x20 0x29 the
- * next two bytes must say how much data will be sended.
+ * next two bytes must say how much data will be sent.
* When reading the process is almost equal except that the header starts with
* 0x00 0x20.
*
@@ -31,15 +31,15 @@
*
* The driver registers himself with the USB-serial core and the USB Core. I had
* to implement a probe function against USB-serial, because other way, the
- * driver was attaching himself to both interfaces. I have tryed with different
+ * driver was attaching himself to both interfaces. I have tried with different
* configurations of usb_serial_driver with out exit, only the probe function
* could handle this correctly.
*
* I have taken some info from a Greg Kroah-Hartman article:
* http://www.linuxjournal.com/article/6573
* And from Linux Device Driver Kit CD, which is a great work, the authors taken
- * the work to recompile lots of information an knowladge in drivers development
- * and made it all avaible inside a cd.
+ * the work to recompile lots of information an knowledge in drivers development
+ * and made it all available inside a cd.
* URL: http://kernel.org/pub/linux/kernel/people/gregkh/ddk/
*
*/
@@ -119,9 +119,8 @@ static int aircable_probe(struct usb_serial *serial,
return 0;
}
-static int aircable_process_packet(struct tty_struct *tty,
- struct usb_serial_port *port, int has_headers,
- char *packet, int len)
+static int aircable_process_packet(struct usb_serial_port *port,
+ int has_headers, char *packet, int len)
{
if (has_headers) {
len -= HCI_HEADER_LENGTH;
@@ -132,7 +131,7 @@ static int aircable_process_packet(struct tty_struct *tty,
return 0;
}
- tty_insert_flip_string(tty, packet, len);
+ tty_insert_flip_string(&port->port, packet, len);
return len;
}
@@ -141,28 +140,22 @@ static void aircable_process_read_urb(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
char *data = (char *)urb->transfer_buffer;
- struct tty_struct *tty;
int has_headers;
int count;
int len;
int i;
- tty = tty_port_tty_get(&port->port);
- if (!tty)
- return;
-
has_headers = (urb->actual_length > 2 && data[0] == RX_HEADER_0);
count = 0;
for (i = 0; i < urb->actual_length; i += HCI_COMPLETE_FRAME) {
len = min_t(int, urb->actual_length - i, HCI_COMPLETE_FRAME);
- count += aircable_process_packet(tty, port, has_headers,
+ count += aircable_process_packet(port, has_headers,
&data[i], len);
}
if (count)
- tty_flip_buffer_push(tty);
- tty_kref_put(tty);
+ tty_flip_buffer_push(&port->port);
}
static struct usb_serial_driver aircable_device = {
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
index a88882c0e23..1532cde8a43 100644
--- a/drivers/usb/serial/ark3116.c
+++ b/drivers/usb/serial/ark3116.c
@@ -23,7 +23,6 @@
*/
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/ioctl.h>
#include <linux/tty.h>
#include <linux/slab.h>
@@ -43,7 +42,7 @@
#define DRIVER_NAME "ark3116"
/* usb timeout of 1 second */
-#define ARK_TIMEOUT (1*HZ)
+#define ARK_TIMEOUT 1000
static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x6547, 0x0232) },
@@ -62,8 +61,6 @@ static int is_irda(struct usb_serial *serial)
}
struct ark3116_private {
- wait_queue_head_t delta_msr_wait;
- struct async_icount icount;
int irda; /* 1 for irda device */
/* protects hw register updates */
@@ -73,7 +70,7 @@ struct ark3116_private {
__u32 lcr; /* line control register value */
__u32 hcr; /* handshake control register (0x8)
* value */
- __u32 mcr; /* modem contol register value */
+ __u32 mcr; /* modem control register value */
/* protects the status values below */
spinlock_t status_lock;
@@ -146,7 +143,6 @@ static int ark3116_port_probe(struct usb_serial_port *port)
if (!priv)
return -ENOMEM;
- init_waitqueue_head(&priv->delta_msr_wait);
mutex_init(&priv->hw_lock);
spin_lock_init(&priv->status_lock);
@@ -343,18 +339,15 @@ static void ark3116_close(struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
- if (serial->dev) {
- /* disable DMA */
- ark3116_write_reg(serial, UART_FCR, 0);
-
- /* deactivate interrupts */
- ark3116_write_reg(serial, UART_IER, 0);
+ /* disable DMA */
+ ark3116_write_reg(serial, UART_FCR, 0);
- usb_serial_generic_close(port);
- if (serial->num_interrupt_in)
- usb_kill_urb(port->interrupt_in_urb);
- }
+ /* deactivate interrupts */
+ ark3116_write_reg(serial, UART_IER, 0);
+ usb_serial_generic_close(port);
+ if (serial->num_interrupt_in)
+ usb_kill_urb(port->interrupt_in_urb);
}
static int ark3116_open(struct tty_struct *tty, struct usb_serial_port *port)
@@ -407,31 +400,10 @@ err_out:
return result;
}
-static int ark3116_get_icount(struct tty_struct *tty,
- struct serial_icounter_struct *icount)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct ark3116_private *priv = usb_get_serial_port_data(port);
- struct async_icount cnow = priv->icount;
- icount->cts = cnow.cts;
- icount->dsr = cnow.dsr;
- icount->rng = cnow.rng;
- icount->dcd = cnow.dcd;
- icount->rx = cnow.rx;
- icount->tx = cnow.tx;
- icount->frame = cnow.frame;
- icount->overrun = cnow.overrun;
- icount->parity = cnow.parity;
- icount->brk = cnow.brk;
- icount->buf_overrun = cnow.buf_overrun;
- return 0;
-}
-
static int ark3116_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
struct usb_serial_port *port = tty->driver_data;
- struct ark3116_private *priv = usb_get_serial_port_data(port);
struct serial_struct serstruct;
void __user *user_arg = (void __user *)arg;
@@ -440,8 +412,8 @@ static int ark3116_ioctl(struct tty_struct *tty,
/* XXX: Some of these values are probably wrong. */
memset(&serstruct, 0, sizeof(serstruct));
serstruct.type = PORT_16654;
- serstruct.line = port->serial->minor;
- serstruct.port = port->number;
+ serstruct.line = port->minor;
+ serstruct.port = port->port_number;
serstruct.custom_divisor = 0;
serstruct.baud_base = 460800;
@@ -453,29 +425,6 @@ static int ark3116_ioctl(struct tty_struct *tty,
if (copy_from_user(&serstruct, user_arg, sizeof(serstruct)))
return -EFAULT;
return 0;
- case TIOCMIWAIT:
- for (;;) {
- struct async_icount prev = priv->icount;
- interruptible_sleep_on(&priv->delta_msr_wait);
- /* see if a signal did it */
- if (signal_pending(current))
- return -ERESTARTSYS;
- if ((prev.rng == priv->icount.rng) &&
- (prev.dsr == priv->icount.dsr) &&
- (prev.dcd == priv->icount.dcd) &&
- (prev.cts == priv->icount.cts))
- return -EIO;
- if ((arg & TIOCM_RNG &&
- (prev.rng != priv->icount.rng)) ||
- (arg & TIOCM_DSR &&
- (prev.dsr != priv->icount.dsr)) ||
- (arg & TIOCM_CD &&
- (prev.dcd != priv->icount.dcd)) ||
- (arg & TIOCM_CTS &&
- (prev.cts != priv->icount.cts)))
- return 0;
- }
- break;
}
return -ENOIOCTLCMD;
@@ -573,14 +522,14 @@ static void ark3116_update_msr(struct usb_serial_port *port, __u8 msr)
if (msr & UART_MSR_ANY_DELTA) {
/* update input line counters */
if (msr & UART_MSR_DCTS)
- priv->icount.cts++;
+ port->icount.cts++;
if (msr & UART_MSR_DDSR)
- priv->icount.dsr++;
+ port->icount.dsr++;
if (msr & UART_MSR_DDCD)
- priv->icount.dcd++;
+ port->icount.dcd++;
if (msr & UART_MSR_TERI)
- priv->icount.rng++;
- wake_up_interruptible(&priv->delta_msr_wait);
+ port->icount.rng++;
+ wake_up_interruptible(&port->port.delta_msr_wait);
}
}
@@ -596,13 +545,13 @@ static void ark3116_update_lsr(struct usb_serial_port *port, __u8 lsr)
if (lsr&UART_LSR_BRK_ERROR_BITS) {
if (lsr & UART_LSR_BI)
- priv->icount.brk++;
+ port->icount.brk++;
if (lsr & UART_LSR_FE)
- priv->icount.frame++;
+ port->icount.frame++;
if (lsr & UART_LSR_PE)
- priv->icount.parity++;
+ port->icount.parity++;
if (lsr & UART_LSR_OE)
- priv->icount.overrun++;
+ port->icount.overrun++;
}
}
@@ -659,7 +608,7 @@ static void ark3116_read_int_callback(struct urb *urb)
}
-/* Data comes in via the bulk (data) URB, erors/interrupts via the int URB.
+/* Data comes in via the bulk (data) URB, errors/interrupts via the int URB.
* This means that we cannot be sure which data byte has an associated error
* condition, so we report an error for all data in the next bulk read.
*
@@ -674,7 +623,6 @@ static void ark3116_process_read_urb(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
struct ark3116_private *priv = usb_get_serial_port_data(port);
- struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
char tty_flag = TTY_NORMAL;
unsigned long flags;
@@ -689,10 +637,6 @@ static void ark3116_process_read_urb(struct urb *urb)
if (!urb->actual_length)
return;
- tty = tty_port_tty_get(&port->port);
- if (!tty)
- return;
-
if (lsr & UART_LSR_BRK_ERROR_BITS) {
if (lsr & UART_LSR_BI)
tty_flag = TTY_BREAK;
@@ -703,12 +647,11 @@ static void ark3116_process_read_urb(struct urb *urb)
/* overrun is special, not associated with a char */
if (lsr & UART_LSR_OE)
- tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+ tty_insert_flip_char(&port->port, 0, TTY_OVERRUN);
}
- tty_insert_flip_string_fixed_flag(tty, data, tty_flag,
+ tty_insert_flip_string_fixed_flag(&port->port, data, tty_flag,
urb->actual_length);
- tty_flip_buffer_push(tty);
- tty_kref_put(tty);
+ tty_flip_buffer_push(&port->port);
}
static struct usb_serial_driver ark3116_device = {
@@ -726,7 +669,8 @@ static struct usb_serial_driver ark3116_device = {
.ioctl = ark3116_ioctl,
.tiocmget = ark3116_tiocmget,
.tiocmset = ark3116_tiocmset,
- .get_icount = ark3116_get_icount,
+ .tiocmiwait = usb_serial_generic_tiocmiwait,
+ .get_icount = usb_serial_generic_get_icount,
.open = ark3116_open,
.close = ark3116_close,
.break_ctl = ark3116_break_ctl,
diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
index b72a4c16670..15bc71853db 100644
--- a/drivers/usb/serial/belkin_sa.c
+++ b/drivers/usb/serial/belkin_sa.c
@@ -18,14 +18,13 @@
* driver
*
* TODO:
- * -- Add true modem contol line query capability. Currently we track the
+ * -- Add true modem control line query capability. Currently we track the
* states reported by the interrupt and the states we request.
* -- Add support for flush commands
*/
#include <linux/kernel.h>
#include <linux/errno.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
@@ -242,7 +241,6 @@ static void belkin_sa_process_read_urb(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
struct belkin_sa_private *priv = usb_get_serial_port_data(port);
- struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
unsigned long flags;
unsigned char status;
@@ -259,10 +257,6 @@ static void belkin_sa_process_read_urb(struct urb *urb)
if (!urb->actual_length)
return;
- tty = tty_port_tty_get(&port->port);
- if (!tty)
- return;
-
if (status & BELKIN_SA_LSR_ERR) {
/* Break takes precedence over parity, which takes precedence
* over framing errors. */
@@ -276,13 +270,12 @@ static void belkin_sa_process_read_urb(struct urb *urb)
/* Overrun is special, not associated with a char. */
if (status & BELKIN_SA_LSR_OE)
- tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+ tty_insert_flip_char(&port->port, 0, TTY_OVERRUN);
}
- tty_insert_flip_string_fixed_flag(tty, data, tty_flag,
+ tty_insert_flip_string_fixed_flag(&port->port, data, tty_flag,
urb->actual_length);
- tty_flip_buffer_push(tty);
- tty_kref_put(tty);
+ tty_flip_buffer_push(&port->port);
}
static void belkin_sa_set_termios(struct tty_struct *tty,
diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c
index 37decb13d7e..9374bd2aba2 100644
--- a/drivers/usb/serial/bus.c
+++ b/drivers/usb/serial/bus.c
@@ -38,15 +38,14 @@ static int usb_serial_device_match(struct device *dev,
return 0;
}
-static ssize_t show_port_number(struct device *dev,
+static ssize_t port_number_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct usb_serial_port *port = to_usb_serial_port(dev);
- return sprintf(buf, "%d\n", port->number - port->serial->minor);
+ return sprintf(buf, "%d\n", port->port_number);
}
-
-static DEVICE_ATTR(port_number, S_IRUGO, show_port_number, NULL);
+static DEVICE_ATTR_RO(port_number);
static int usb_serial_device_probe(struct device *dev)
{
@@ -80,7 +79,7 @@ static int usb_serial_device_probe(struct device *dev)
goto exit_with_autopm;
}
- minor = port->number;
+ minor = port->minor;
tty_register_device(usb_serial_tty_driver, minor, dev);
dev_info(&port->serial->dev->dev,
"%s converter now attached to ttyUSB%d\n",
@@ -98,13 +97,22 @@ static int usb_serial_device_remove(struct device *dev)
struct usb_serial_port *port;
int retval = 0;
int minor;
+ int autopm_err;
port = to_usb_serial_port(dev);
if (!port)
return -ENODEV;
- /* make sure suspend/resume doesn't race against port_remove */
- usb_autopm_get_interface(port->serial->interface);
+ /*
+ * Make sure suspend/resume doesn't race against port_remove.
+ *
+ * Note that no further runtime PM callbacks will be made if
+ * autopm_get fails.
+ */
+ autopm_err = usb_autopm_get_interface(port->serial->interface);
+
+ minor = port->minor;
+ tty_unregister_device(usb_serial_tty_driver, minor);
device_remove_file(&port->dev, &dev_attr_port_number);
@@ -112,39 +120,43 @@ static int usb_serial_device_remove(struct device *dev)
if (driver->port_remove)
retval = driver->port_remove(port);
- minor = port->number;
- tty_unregister_device(usb_serial_tty_driver, minor);
dev_info(dev, "%s converter now disconnected from ttyUSB%d\n",
driver->description, minor);
- usb_autopm_put_interface(port->serial->interface);
+ if (!autopm_err)
+ usb_autopm_put_interface(port->serial->interface);
+
return retval;
}
-static ssize_t store_new_id(struct device_driver *driver,
+static ssize_t new_id_store(struct device_driver *driver,
const char *buf, size_t count)
{
struct usb_serial_driver *usb_drv = to_usb_serial_driver(driver);
- ssize_t retval = usb_store_new_id(&usb_drv->dynids, driver, buf, count);
+ ssize_t retval = usb_store_new_id(&usb_drv->dynids, usb_drv->id_table,
+ driver, buf, count);
if (retval >= 0 && usb_drv->usb_driver != NULL)
retval = usb_store_new_id(&usb_drv->usb_driver->dynids,
+ usb_drv->usb_driver->id_table,
&usb_drv->usb_driver->drvwrap.driver,
buf, count);
return retval;
}
-static ssize_t show_dynids(struct device_driver *driver, char *buf)
+static ssize_t new_id_show(struct device_driver *driver, char *buf)
{
struct usb_serial_driver *usb_drv = to_usb_serial_driver(driver);
return usb_show_dynids(&usb_drv->dynids, buf);
}
+static DRIVER_ATTR_RW(new_id);
-static struct driver_attribute drv_attrs[] = {
- __ATTR(new_id, S_IRUGO | S_IWUSR, show_dynids, store_new_id),
- __ATTR_NULL,
+static struct attribute *usb_serial_drv_attrs[] = {
+ &driver_attr_new_id.attr,
+ NULL,
};
+ATTRIBUTE_GROUPS(usb_serial_drv);
static void free_dynids(struct usb_serial_driver *drv)
{
@@ -163,7 +175,7 @@ struct bus_type usb_serial_bus_type = {
.match = usb_serial_device_match,
.probe = usb_serial_device_probe,
.remove = usb_serial_device_remove,
- .drv_attrs = drv_attrs,
+ .drv_groups = usb_serial_drv_groups,
};
int usb_serial_bus_register(struct usb_serial_driver *driver)
diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c
index d255f66e708..2d72aa3564a 100644
--- a/drivers/usb/serial/ch341.c
+++ b/drivers/usb/serial/ch341.c
@@ -16,7 +16,6 @@
*/
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/tty.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -80,11 +79,9 @@ MODULE_DEVICE_TABLE(usb, id_table);
struct ch341_private {
spinlock_t lock; /* access lock */
- wait_queue_head_t delta_msr_wait; /* wait queue for modem status */
unsigned baud_rate; /* set baud rate */
u8 line_control; /* set line control value RTS/DTR */
u8 line_status; /* active status of modem control inputs */
- u8 multi_status_change; /* status changed multiple since last call */
};
static int ch341_control_out(struct usb_device *dev, u8 request,
@@ -175,7 +172,6 @@ static int ch341_get_status(struct usb_device *dev, struct ch341_private *priv)
r = 0;
spin_lock_irqsave(&priv->lock, flags);
priv->line_status = (~(*buffer)) & CH341_BITS_MODEM_STAT;
- priv->multi_status_change = 0;
spin_unlock_irqrestore(&priv->lock, flags);
} else
r = -EPROTO;
@@ -252,7 +248,6 @@ static int ch341_port_probe(struct usb_serial_port *port)
return -ENOMEM;
spin_lock_init(&priv->lock);
- init_waitqueue_head(&priv->delta_msr_wait);
priv->baud_rate = DEFAULT_BAUD_RATE;
priv->line_control = CH341_BIT_RTS | CH341_BIT_DTR;
@@ -298,7 +293,6 @@ static void ch341_dtr_rts(struct usb_serial_port *port, int on)
priv->line_control &= ~(CH341_BIT_RTS | CH341_BIT_DTR);
spin_unlock_irqrestore(&priv->lock, flags);
ch341_set_handshake(port->serial->dev, priv->line_control);
- wake_up_interruptible(&priv->delta_msr_wait);
}
static void ch341_close(struct usb_serial_port *port)
@@ -329,11 +323,11 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port)
if (r)
goto out;
- dev_dbg(&port->dev, "%s - submitting interrupt urb", __func__);
+ dev_dbg(&port->dev, "%s - submitting interrupt urb\n", __func__);
r = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (r) {
- dev_err(&port->dev, "%s - failed submitting interrupt urb,"
- " error %d\n", __func__, r);
+ dev_err(&port->dev, "%s - failed to submit interrupt urb: %d\n",
+ __func__, r);
ch341_close(port);
goto out;
}
@@ -387,10 +381,8 @@ static void ch341_break_ctl(struct tty_struct *tty, int break_state)
uint8_t *break_reg;
break_reg = kmalloc(2, GFP_KERNEL);
- if (!break_reg) {
- dev_err(&port->dev, "%s - kmalloc failed\n", __func__);
+ if (!break_reg)
return;
- }
r = ch341_control_in(port->serial->dev, CH341_REQ_READ_REG,
ch341_break_reg, 0, break_reg, 2);
@@ -445,11 +437,55 @@ static int ch341_tiocmset(struct tty_struct *tty,
return ch341_set_handshake(port->serial->dev, control);
}
+static void ch341_update_line_status(struct usb_serial_port *port,
+ unsigned char *data, size_t len)
+{
+ struct ch341_private *priv = usb_get_serial_port_data(port);
+ struct tty_struct *tty;
+ unsigned long flags;
+ u8 status;
+ u8 delta;
+
+ if (len < 4)
+ return;
+
+ status = ~data[2] & CH341_BITS_MODEM_STAT;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ delta = status ^ priv->line_status;
+ priv->line_status = status;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (data[1] & CH341_MULT_STAT)
+ dev_dbg(&port->dev, "%s - multiple status change\n", __func__);
+
+ if (!delta)
+ return;
+
+ if (delta & CH341_BIT_CTS)
+ port->icount.cts++;
+ if (delta & CH341_BIT_DSR)
+ port->icount.dsr++;
+ if (delta & CH341_BIT_RI)
+ port->icount.rng++;
+ if (delta & CH341_BIT_DCD) {
+ port->icount.dcd++;
+ tty = tty_port_tty_get(&port->port);
+ if (tty) {
+ usb_serial_handle_dcd_change(port, tty,
+ status & CH341_BIT_DCD);
+ tty_kref_put(tty);
+ }
+ }
+
+ wake_up_interruptible(&port->port.delta_msr_wait);
+}
+
static void ch341_read_int_callback(struct urb *urb)
{
- struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
+ struct usb_serial_port *port = urb->context;
unsigned char *data = urb->transfer_buffer;
- unsigned int actual_length = urb->actual_length;
+ unsigned int len = urb->actual_length;
int status;
switch (urb->status) {
@@ -460,105 +496,23 @@ static void ch341_read_int_callback(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dev_dbg(&urb->dev->dev, "%s - urb shutting down with status: %d\n",
+ dev_dbg(&urb->dev->dev, "%s - urb shutting down: %d\n",
__func__, urb->status);
return;
default:
- dev_dbg(&urb->dev->dev, "%s - nonzero urb status received: %d\n",
+ dev_dbg(&urb->dev->dev, "%s - nonzero urb status: %d\n",
__func__, urb->status);
goto exit;
}
- usb_serial_debug_data(&port->dev, __func__,
- urb->actual_length, urb->transfer_buffer);
-
- if (actual_length >= 4) {
- struct ch341_private *priv = usb_get_serial_port_data(port);
- unsigned long flags;
- u8 prev_line_status = priv->line_status;
-
- spin_lock_irqsave(&priv->lock, flags);
- priv->line_status = (~(data[2])) & CH341_BITS_MODEM_STAT;
- if ((data[1] & CH341_MULT_STAT))
- priv->multi_status_change = 1;
- spin_unlock_irqrestore(&priv->lock, flags);
-
- if ((priv->line_status ^ prev_line_status) & CH341_BIT_DCD) {
- struct tty_struct *tty = tty_port_tty_get(&port->port);
- if (tty)
- usb_serial_handle_dcd_change(port, tty,
- priv->line_status & CH341_BIT_DCD);
- tty_kref_put(tty);
- }
-
- wake_up_interruptible(&priv->delta_msr_wait);
- }
-
+ usb_serial_debug_data(&port->dev, __func__, len, data);
+ ch341_update_line_status(port, data, len);
exit:
status = usb_submit_urb(urb, GFP_ATOMIC);
- if (status)
- dev_err(&urb->dev->dev,
- "%s - usb_submit_urb failed with result %d\n",
+ if (status) {
+ dev_err(&urb->dev->dev, "%s - usb_submit_urb failed: %d\n",
__func__, status);
-}
-
-static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
-{
- struct ch341_private *priv = usb_get_serial_port_data(port);
- unsigned long flags;
- u8 prevstatus;
- u8 status;
- u8 changed;
- u8 multi_change = 0;
-
- spin_lock_irqsave(&priv->lock, flags);
- prevstatus = priv->line_status;
- priv->multi_status_change = 0;
- spin_unlock_irqrestore(&priv->lock, flags);
-
- while (!multi_change) {
- interruptible_sleep_on(&priv->delta_msr_wait);
- /* see if a signal did it */
- if (signal_pending(current))
- return -ERESTARTSYS;
-
- spin_lock_irqsave(&priv->lock, flags);
- status = priv->line_status;
- multi_change = priv->multi_status_change;
- spin_unlock_irqrestore(&priv->lock, flags);
-
- changed = prevstatus ^ status;
-
- if (((arg & TIOCM_RNG) && (changed & CH341_BIT_RI)) ||
- ((arg & TIOCM_DSR) && (changed & CH341_BIT_DSR)) ||
- ((arg & TIOCM_CD) && (changed & CH341_BIT_DCD)) ||
- ((arg & TIOCM_CTS) && (changed & CH341_BIT_CTS))) {
- return 0;
- }
- prevstatus = status;
}
-
- return 0;
-}
-
-static int ch341_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
-{
- struct usb_serial_port *port = tty->driver_data;
-
- dev_dbg(&port->dev, "%s (%d) cmd = 0x%04x\n", __func__, port->number, cmd);
-
- switch (cmd) {
- case TIOCMIWAIT:
- dev_dbg(&port->dev, "%s (%d) TIOCMIWAIT\n", __func__, port->number);
- return wait_modem_info(port, arg);
-
- default:
- dev_dbg(&port->dev, "%s not supported = 0x%04x\n", __func__, cmd);
- break;
- }
-
- return -ENOIOCTLCMD;
}
static int ch341_tiocmget(struct tty_struct *tty)
@@ -610,11 +564,11 @@ static struct usb_serial_driver ch341_device = {
.dtr_rts = ch341_dtr_rts,
.carrier_raised = ch341_carrier_raised,
.close = ch341_close,
- .ioctl = ch341_ioctl,
.set_termios = ch341_set_termios,
.break_ctl = ch341_break_ctl,
.tiocmget = ch341_tiocmget,
.tiocmset = ch341_tiocmset,
+ .tiocmiwait = usb_serial_generic_tiocmiwait,
.read_int_callback = ch341_read_int_callback,
.port_probe = ch341_port_probe,
.port_remove = ch341_port_remove,
diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c
index 5f3bcd31e20..8d7fc48b1f3 100644
--- a/drivers/usb/serial/console.c
+++ b/drivers/usb/serial/console.c
@@ -14,7 +14,6 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/console.h>
@@ -108,18 +107,18 @@ static int usb_console_setup(struct console *co, char *options)
* no need to check the index here: if the index is wrong, console
* code won't call us
*/
- serial = usb_serial_get_by_index(co->index);
- if (serial == NULL) {
+ port = usb_serial_port_get_by_minor(co->index);
+ if (port == NULL) {
/* no device is connected yet, sorry :( */
pr_err("No USB device connected to ttyUSB%i\n", co->index);
return -ENODEV;
}
+ serial = port->serial;
retval = usb_autopm_get_interface(serial->interface);
if (retval)
goto error_get_interface;
- port = serial->port[co->index - serial->minor];
tty_port_tty_set(&port->port, NULL);
info->port = port;
@@ -135,7 +134,6 @@ static int usb_console_setup(struct console *co, char *options)
tty = kzalloc(sizeof(*tty), GFP_KERNEL);
if (!tty) {
retval = -ENOMEM;
- dev_err(&port->dev, "no more memory\n");
goto reset_open_count;
}
kref_init(&tty->kref);
@@ -144,18 +142,13 @@ static int usb_console_setup(struct console *co, char *options)
tty->index = co->index;
if (tty_init_termios(tty)) {
retval = -ENOMEM;
- dev_err(&port->dev, "no more memory\n");
goto free_tty;
}
}
/* only call the device specific open if this
* is the first time the port is opened */
- if (serial->type->open)
- retval = serial->type->open(NULL, port);
- else
- retval = usb_serial_generic_open(NULL, port);
-
+ retval = serial->type->open(NULL, port);
if (retval) {
dev_err(&port->dev, "could not open USB console port\n");
goto fail;
@@ -210,10 +203,10 @@ static void usb_console_write(struct console *co,
if (count == 0)
return;
- pr_debug("%s - port %d, %d byte(s)\n", __func__, port->number, count);
+ dev_dbg(&port->dev, "%s - %d byte(s)\n", __func__, count);
if (!port->port.console) {
- pr_debug("%s - port not opened\n", __func__);
+ dev_dbg(&port->dev, "%s - port not opened\n", __func__);
return;
}
@@ -230,21 +223,14 @@ static void usb_console_write(struct console *co,
}
/* pass on to the driver specific version of this function if
it is available */
- if (serial->type->write)
- retval = serial->type->write(NULL, port, buf, i);
- else
- retval = usb_serial_generic_write(NULL, port, buf, i);
- pr_debug("%s - return value : %d\n", __func__, retval);
+ retval = serial->type->write(NULL, port, buf, i);
+ dev_dbg(&port->dev, "%s - write: %d\n", __func__, retval);
if (lf) {
/* append CR after LF */
unsigned char cr = 13;
- if (serial->type->write)
- retval = serial->type->write(NULL,
- port, &cr, 1);
- else
- retval = usb_serial_generic_write(NULL,
- port, &cr, 1);
- pr_debug("%s - return value : %d\n", __func__, retval);
+ retval = serial->type->write(NULL, port, &cr, 1);
+ dev_dbg(&port->dev, "%s - write cr: %d\n",
+ __func__, retval);
}
buf += i;
count -= i;
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index f14736f647f..330df5ce435 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -53,6 +53,7 @@ static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x0489, 0xE000) }, /* Pirelli Broadband S.p.A, DP-L10 SIP/GSM Mobile */
{ USB_DEVICE(0x0489, 0xE003) }, /* Pirelli Broadband S.p.A, DP-L10 SIP/GSM Mobile */
{ USB_DEVICE(0x0745, 0x1000) }, /* CipherLab USB CCD Barcode Scanner 1000 */
+ { USB_DEVICE(0x0846, 0x1100) }, /* NetGear Managed Switch M4100 series, M5300 series, M7100 series */
{ USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */
{ USB_DEVICE(0x08FD, 0x000A) }, /* Digianswer A/S , ZigBee/802.15.4 MAC Device */
{ USB_DEVICE(0x0BED, 0x1100) }, /* MEI (TM) Cashflow-SC Bill/Voucher Acceptor */
@@ -60,6 +61,7 @@ static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */
{ USB_DEVICE(0x0FCF, 0x1004) }, /* Dynastream ANT2USB */
{ USB_DEVICE(0x0FCF, 0x1006) }, /* Dynastream ANT development board */
+ { USB_DEVICE(0x0FDE, 0xCA05) }, /* OWL Wireless Electricity Monitor CM-160 */
{ USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */
{ USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */
{ USB_DEVICE(0x10B5, 0xAC70) }, /* Nokia CA-42 USB */
@@ -84,6 +86,7 @@ static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x10C4, 0x813F) }, /* Tams Master Easy Control */
{ USB_DEVICE(0x10C4, 0x814A) }, /* West Mountain Radio RIGblaster P&P */
{ USB_DEVICE(0x10C4, 0x814B) }, /* West Mountain Radio RIGtalk */
+ { USB_DEVICE(0x2405, 0x0003) }, /* West Mountain Radio RIGblaster Advantage */
{ USB_DEVICE(0x10C4, 0x8156) }, /* B&G H3000 link cable */
{ USB_DEVICE(0x10C4, 0x815E) }, /* Helicomm IP-Link 1220-DVM */
{ USB_DEVICE(0x10C4, 0x815F) }, /* Timewave HamLinkUSB */
@@ -101,6 +104,7 @@ static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x10C4, 0x8218) }, /* Lipowsky Industrie Elektronik GmbH, HARP-1 */
{ USB_DEVICE(0x10C4, 0x822B) }, /* Modem EDGE(GSM) Comander 2 */
{ USB_DEVICE(0x10C4, 0x826B) }, /* Cygnal Integrated Products, Inc., Fasttrax GPS demonstration module */
+ { USB_DEVICE(0x10C4, 0x8281) }, /* Nanotec Plug & Drive */
{ USB_DEVICE(0x10C4, 0x8293) }, /* Telegesis ETRX2USB */
{ USB_DEVICE(0x10C4, 0x82F9) }, /* Procyon AVS */
{ USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */
@@ -116,6 +120,8 @@ static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x10C4, 0x85F8) }, /* Virtenio Preon32 */
{ USB_DEVICE(0x10C4, 0x8664) }, /* AC-Services CAN-IF */
{ USB_DEVICE(0x10C4, 0x8665) }, /* AC-Services OBD-IF */
+ { USB_DEVICE(0x10C4, 0x88A4) }, /* MMB Networks ZigBee USB Device */
+ { USB_DEVICE(0x10C4, 0x88A5) }, /* Planet Innovation Ingeni ZigBee USB Device */
{ USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */
{ USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */
{ USB_DEVICE(0x10C4, 0xEA70) }, /* Silicon Labs factory default */
@@ -146,9 +152,30 @@ static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x17F4, 0xAAAA) }, /* Wavesense Jazz blood glucose meter */
{ USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */
{ USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */
+ { USB_DEVICE(0x1ADB, 0x0001) }, /* Schweitzer Engineering C662 Cable */
+ { USB_DEVICE(0x1B1C, 0x1C00) }, /* Corsair USB Dongle */
{ USB_DEVICE(0x1BE3, 0x07A6) }, /* WAGO 750-923 USB Service Cable */
{ USB_DEVICE(0x1E29, 0x0102) }, /* Festo CPX-USB */
{ USB_DEVICE(0x1E29, 0x0501) }, /* Festo CMSP */
+ { USB_DEVICE(0x1FB9, 0x0100) }, /* Lake Shore Model 121 Current Source */
+ { USB_DEVICE(0x1FB9, 0x0200) }, /* Lake Shore Model 218A Temperature Monitor */
+ { USB_DEVICE(0x1FB9, 0x0201) }, /* Lake Shore Model 219 Temperature Monitor */
+ { USB_DEVICE(0x1FB9, 0x0202) }, /* Lake Shore Model 233 Temperature Transmitter */
+ { USB_DEVICE(0x1FB9, 0x0203) }, /* Lake Shore Model 235 Temperature Transmitter */
+ { USB_DEVICE(0x1FB9, 0x0300) }, /* Lake Shore Model 335 Temperature Controller */
+ { USB_DEVICE(0x1FB9, 0x0301) }, /* Lake Shore Model 336 Temperature Controller */
+ { USB_DEVICE(0x1FB9, 0x0302) }, /* Lake Shore Model 350 Temperature Controller */
+ { USB_DEVICE(0x1FB9, 0x0303) }, /* Lake Shore Model 371 AC Bridge */
+ { USB_DEVICE(0x1FB9, 0x0400) }, /* Lake Shore Model 411 Handheld Gaussmeter */
+ { USB_DEVICE(0x1FB9, 0x0401) }, /* Lake Shore Model 425 Gaussmeter */
+ { USB_DEVICE(0x1FB9, 0x0402) }, /* Lake Shore Model 455A Gaussmeter */
+ { USB_DEVICE(0x1FB9, 0x0403) }, /* Lake Shore Model 475A Gaussmeter */
+ { USB_DEVICE(0x1FB9, 0x0404) }, /* Lake Shore Model 465 Three Axis Gaussmeter */
+ { USB_DEVICE(0x1FB9, 0x0600) }, /* Lake Shore Model 625A Superconducting MPS */
+ { USB_DEVICE(0x1FB9, 0x0601) }, /* Lake Shore Model 642A Magnet Power Supply */
+ { USB_DEVICE(0x1FB9, 0x0602) }, /* Lake Shore Model 648 Magnet Power Supply */
+ { USB_DEVICE(0x1FB9, 0x0700) }, /* Lake Shore Model 737 VSM Controller */
+ { USB_DEVICE(0x1FB9, 0x0701) }, /* Lake Shore Model 776 Hall Matrix */
{ USB_DEVICE(0x3195, 0xF190) }, /* Link Instruments MSO-19 */
{ USB_DEVICE(0x3195, 0xF280) }, /* Link Instruments MSO-28 */
{ USB_DEVICE(0x3195, 0xF281) }, /* Link Instruments MSO-28 */
@@ -280,10 +307,8 @@ static int cp210x_get_config(struct usb_serial_port *port, u8 request,
length = (((size - 1) | 3) + 1) / 4;
buf = kcalloc(length, sizeof(__le32), GFP_KERNEL);
- if (!buf) {
- dev_err(&port->dev, "%s - out of memory.\n", __func__);
+ if (!buf)
return -ENOMEM;
- }
/* Issue the request, attempting to read 'size' bytes */
result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
@@ -327,10 +352,8 @@ static int cp210x_set_config(struct usb_serial_port *port, u8 request,
length = (((size - 1) | 3) + 1) / 4;
buf = kmalloc(length * sizeof(__le32), GFP_KERNEL);
- if (!buf) {
- dev_err(&port->dev, "%s - out of memory.\n", __func__);
+ if (!buf)
return -ENOMEM;
- }
/* Array of integers into bytes */
for (i = 0; i < length; i++)
@@ -441,11 +464,7 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port)
static void cp210x_close(struct usb_serial_port *port)
{
usb_serial_generic_close(port);
-
- mutex_lock(&port->serial->disc_mutex);
- if (!port->serial->disconnected)
- cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_DISABLE);
- mutex_unlock(&port->serial->disc_mutex);
+ cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_DISABLE);
}
/*
@@ -649,11 +668,6 @@ static void cp210x_set_termios(struct tty_struct *tty,
unsigned int bits;
unsigned int modem_ctl[4];
- dev_dbg(dev, "%s - port %d\n", __func__, port->number);
-
- if (!tty)
- return;
-
cflag = tty->termios.c_cflag;
old_cflag = old_termios->c_cflag;
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
index 69a4fa1cee2..2916dea3ede 100644
--- a/drivers/usb/serial/cyberjack.c
+++ b/drivers/usb/serial/cyberjack.c
@@ -30,7 +30,6 @@
#include <linux/kernel.h>
#include <linux/errno.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
@@ -51,7 +50,6 @@
#define CYBERJACK_PRODUCT_ID 0x0100
/* Function prototypes */
-static void cyberjack_disconnect(struct usb_serial *serial);
static int cyberjack_port_probe(struct usb_serial_port *port);
static int cyberjack_port_remove(struct usb_serial_port *port);
static int cyberjack_open(struct tty_struct *tty,
@@ -79,7 +77,6 @@ static struct usb_serial_driver cyberjack_device = {
.description = "Reiner SCT Cyberjack USB card reader",
.id_table = id_table,
.num_ports = 1,
- .disconnect = cyberjack_disconnect,
.port_probe = cyberjack_port_probe,
.port_remove = cyberjack_port_remove,
.open = cyberjack_open,
@@ -130,20 +127,14 @@ static int cyberjack_port_remove(struct usb_serial_port *port)
{
struct cyberjack_private *priv;
+ usb_kill_urb(port->interrupt_in_urb);
+
priv = usb_get_serial_port_data(port);
kfree(priv);
return 0;
}
-static void cyberjack_disconnect(struct usb_serial *serial)
-{
- int i;
-
- for (i = 0; i < serial->num_ports; ++i)
- usb_kill_urb(serial->port[i]->interrupt_in_urb);
-}
-
static int cyberjack_open(struct tty_struct *tty,
struct usb_serial_port *port)
{
@@ -166,11 +157,8 @@ static int cyberjack_open(struct tty_struct *tty,
static void cyberjack_close(struct usb_serial_port *port)
{
- if (port->serial->dev) {
- /* shutdown any bulk reads that might be going on */
- usb_kill_urb(port->write_urb);
- usb_kill_urb(port->read_urb);
- }
+ usb_kill_urb(port->write_urb);
+ usb_kill_urb(port->read_urb);
}
static int cyberjack_write(struct tty_struct *tty,
@@ -232,7 +220,7 @@ static int cyberjack_write(struct tty_struct *tty,
result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
if (result) {
dev_err(&port->dev,
- "%s - failed submitting write urb, error %d",
+ "%s - failed submitting write urb, error %d\n",
__func__, result);
/* Throw away data. No better idea what to do with it. */
priv->wrfilled = 0;
@@ -290,13 +278,13 @@ static void cyberjack_read_int_callback(struct urb *urb)
old_rdtodo = priv->rdtodo;
- if (old_rdtodo + size < old_rdtodo) {
+ if (old_rdtodo > SHRT_MAX - size) {
dev_dbg(dev, "To many bulk_in urbs to do.\n");
spin_unlock(&priv->lock);
goto resubmit;
}
- /* "+=" is probably more fault tollerant than "=" */
+ /* "+=" is probably more fault tolerant than "=" */
priv->rdtodo += size;
dev_dbg(dev, "%s - rdtodo: %d\n", __func__, priv->rdtodo);
@@ -324,7 +312,6 @@ static void cyberjack_read_bulk_callback(struct urb *urb)
struct usb_serial_port *port = urb->context;
struct cyberjack_private *priv = usb_get_serial_port_data(port);
struct device *dev = &port->dev;
- struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
short todo;
int result;
@@ -337,16 +324,10 @@ static void cyberjack_read_bulk_callback(struct urb *urb)
return;
}
- tty = tty_port_tty_get(&port->port);
- if (!tty) {
- dev_dbg(dev, "%s - ignoring since device not open\n", __func__);
- return;
- }
if (urb->actual_length) {
- tty_insert_flip_string(tty, data, urb->actual_length);
- tty_flip_buffer_push(tty);
+ tty_insert_flip_string(&port->port, data, urb->actual_length);
+ tty_flip_buffer_push(&port->port);
}
- tty_kref_put(tty);
spin_lock(&priv->lock);
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index fd8c35fd452..01bf5339281 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -27,7 +27,6 @@
#include <linux/kernel.h>
#include <linux/errno.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
@@ -65,6 +64,7 @@ static const struct usb_device_id id_table_earthmate[] = {
static const struct usb_device_id id_table_cyphidcomrs232[] = {
{ USB_DEVICE(VENDOR_ID_CYPRESS, PRODUCT_ID_CYPHIDCOM) },
{ USB_DEVICE(VENDOR_ID_POWERCOM, PRODUCT_ID_UPS) },
+ { USB_DEVICE(VENDOR_ID_FRWD, PRODUCT_ID_CYPHIDCOM_FRWD) },
{ } /* Terminating entry */
};
@@ -78,6 +78,7 @@ static const struct usb_device_id id_table_combined[] = {
{ USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB_LT20) },
{ USB_DEVICE(VENDOR_ID_CYPRESS, PRODUCT_ID_CYPHIDCOM) },
{ USB_DEVICE(VENDOR_ID_POWERCOM, PRODUCT_ID_UPS) },
+ { USB_DEVICE(VENDOR_ID_FRWD, PRODUCT_ID_CYPHIDCOM_FRWD) },
{ USB_DEVICE(VENDOR_ID_DAZZLE, PRODUCT_ID_CA42) },
{ } /* Terminating entry */
};
@@ -111,8 +112,7 @@ struct cypress_private {
int baud_rate; /* stores current baud rate in
integer form */
int isthrottled; /* if throttled, discard reads */
- wait_queue_head_t delta_msr_wait; /* used for TIOCMIWAIT */
- char prev_status, diff_status; /* used for TIOCMIWAIT */
+ char prev_status; /* used for TIOCMIWAIT */
/* we pass a pointer to this as the argument sent to
cypress_set_termios old_termios */
struct ktermios tmp_termios; /* stores the old termios settings */
@@ -130,8 +130,6 @@ static int cypress_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count);
static void cypress_send(struct usb_serial_port *port);
static int cypress_write_room(struct tty_struct *tty);
-static int cypress_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg);
static void cypress_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old);
static int cypress_tiocmget(struct tty_struct *tty);
@@ -159,10 +157,10 @@ static struct usb_serial_driver cypress_earthmate_device = {
.dtr_rts = cypress_dtr_rts,
.write = cypress_write,
.write_room = cypress_write_room,
- .ioctl = cypress_ioctl,
.set_termios = cypress_set_termios,
.tiocmget = cypress_tiocmget,
.tiocmset = cypress_tiocmset,
+ .tiocmiwait = usb_serial_generic_tiocmiwait,
.chars_in_buffer = cypress_chars_in_buffer,
.throttle = cypress_throttle,
.unthrottle = cypress_unthrottle,
@@ -185,10 +183,10 @@ static struct usb_serial_driver cypress_hidcom_device = {
.dtr_rts = cypress_dtr_rts,
.write = cypress_write,
.write_room = cypress_write_room,
- .ioctl = cypress_ioctl,
.set_termios = cypress_set_termios,
.tiocmget = cypress_tiocmget,
.tiocmset = cypress_tiocmset,
+ .tiocmiwait = usb_serial_generic_tiocmiwait,
.chars_in_buffer = cypress_chars_in_buffer,
.throttle = cypress_throttle,
.unthrottle = cypress_unthrottle,
@@ -211,10 +209,10 @@ static struct usb_serial_driver cypress_ca42v2_device = {
.dtr_rts = cypress_dtr_rts,
.write = cypress_write,
.write_room = cypress_write_room,
- .ioctl = cypress_ioctl,
.set_termios = cypress_set_termios,
.tiocmget = cypress_tiocmget,
.tiocmset = cypress_tiocmset,
+ .tiocmiwait = usb_serial_generic_tiocmiwait,
.chars_in_buffer = cypress_chars_in_buffer,
.throttle = cypress_throttle,
.unthrottle = cypress_unthrottle,
@@ -231,6 +229,12 @@ static struct usb_serial_driver * const serial_drivers[] = {
* Cypress serial helper functions
*****************************************************************************/
+/* FRWD Dongle hidcom needs to skip reset and speed checks */
+static inline bool is_frwd(struct usb_device *dev)
+{
+ return ((le16_to_cpu(dev->descriptor.idVendor) == VENDOR_ID_FRWD) &&
+ (le16_to_cpu(dev->descriptor.idProduct) == PRODUCT_ID_CYPHIDCOM_FRWD));
+}
static int analyze_baud_rate(struct usb_serial_port *port, speed_t new_rate)
{
@@ -240,6 +244,10 @@ static int analyze_baud_rate(struct usb_serial_port *port, speed_t new_rate)
if (unstable_bauds)
return new_rate;
+ /* FRWD Dongle uses 115200 bps */
+ if (is_frwd(port->serial->dev))
+ return new_rate;
+
/*
* The general purpose firmware for the Cypress M8 allows for
* a maximum speed of 57600bps (I have no idea whether DeLorme
@@ -271,7 +279,7 @@ static int analyze_baud_rate(struct usb_serial_port *port, speed_t new_rate)
* the generic firmware, but are not used with
* NMEA and SiRF protocols */
dev_dbg(&port->dev,
- "%s - failed setting baud rate, unsupported speed of %d on Earthmate GPS",
+ "%s - failed setting baud rate, unsupported speed of %d on Earthmate GPS\n",
__func__, new_rate);
return -1;
}
@@ -425,7 +433,7 @@ static void cypress_set_dead(struct usb_serial_port *port)
spin_unlock_irqrestore(&priv->lock, flags);
dev_err(&port->dev, "cypress_m8 suspending failing port %d - "
- "interval might be too short\n", port->number);
+ "interval might be too short\n", port->port_number);
}
@@ -449,9 +457,12 @@ static int cypress_generic_port_probe(struct usb_serial_port *port)
kfree(priv);
return -ENOMEM;
}
- init_waitqueue_head(&priv->delta_msr_wait);
- usb_reset_configuration(serial->dev);
+ /* Skip reset for FRWD device. It is a workaound:
+ device hangs if it receives SET_CONFIGURE in Configured
+ state. */
+ if (!is_frwd(serial->dev))
+ usb_reset_configuration(serial->dev);
priv->cmd_ctrl = 0;
priv->line_control = 0;
@@ -482,6 +493,8 @@ static int cypress_generic_port_probe(struct usb_serial_port *port)
}
usb_set_serial_port_data(port, priv);
+ port->port.drain_delay = 256;
+
return 0;
}
@@ -612,7 +625,7 @@ static int cypress_open(struct tty_struct *tty, struct usb_serial_port *port)
__func__, result);
cypress_set_dead(port);
}
- port->port.drain_delay = 256;
+
return result;
} /* cypress_open */
@@ -635,12 +648,6 @@ static void cypress_close(struct usb_serial_port *port)
struct cypress_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
- /* writing is potentially harmful, lock must be taken */
- mutex_lock(&port->serial->disc_mutex);
- if (port->serial->disconnected) {
- mutex_unlock(&port->serial->disc_mutex);
- return;
- }
spin_lock_irqsave(&priv->lock, flags);
kfifo_reset_out(&priv->write_fifo);
spin_unlock_irqrestore(&priv->lock, flags);
@@ -652,7 +659,6 @@ static void cypress_close(struct usb_serial_port *port)
if (stats)
dev_info(&port->dev, "Statistics: %d Bytes In | %d Bytes Out | %d Commands Issued\n",
priv->bytes_in, priv->bytes_out, priv->cmd_count);
- mutex_unlock(&port->serial->disc_mutex);
} /* cypress_close */
@@ -661,7 +667,7 @@ static int cypress_write(struct tty_struct *tty, struct usb_serial_port *port,
{
struct cypress_private *priv = usb_get_serial_port_data(port);
- dev_dbg(&port->dev, "%s - port %d, %d bytes\n", __func__, port->number, count);
+ dev_dbg(&port->dev, "%s - %d bytes\n", __func__, count);
/* line control commands, which need to be executed immediately,
are not put into the buffer for obvious reasons.
@@ -856,53 +862,6 @@ static int cypress_tiocmset(struct tty_struct *tty,
return cypress_write(tty, port, NULL, 0);
}
-
-static int cypress_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct cypress_private *priv = usb_get_serial_port_data(port);
-
- dev_dbg(&port->dev, "%s - port %d, cmd 0x%.4x\n", __func__, port->number, cmd);
-
- switch (cmd) {
- /* This code comes from drivers/char/serial.c and ftdi_sio.c */
- case TIOCMIWAIT:
- while (priv != NULL) {
- interruptible_sleep_on(&priv->delta_msr_wait);
- /* see if a signal did it */
- if (signal_pending(current))
- return -ERESTARTSYS;
- else {
- char diff = priv->diff_status;
- if (diff == 0)
- return -EIO; /* no change => error */
-
- /* consume all events */
- priv->diff_status = 0;
-
- /* return 0 if caller wanted to know about
- these bits */
- if (((arg & TIOCM_RNG) && (diff & UART_RI)) ||
- ((arg & TIOCM_DSR) && (diff & UART_DSR)) ||
- ((arg & TIOCM_CD) && (diff & UART_CD)) ||
- ((arg & TIOCM_CTS) && (diff & UART_CTS)))
- return 0;
- /* otherwise caller can't care less about what
- * happened, and so we continue to wait for
- * more events.
- */
- }
- }
- return 0;
- default:
- break;
- }
- dev_dbg(&port->dev, "%s - arg not supported - it was 0x%04x - check include/asm/ioctls.h\n", __func__, cmd);
- return -ENOIOCTLCMD;
-} /* cypress_ioctl */
-
-
static void cypress_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios)
{
@@ -1185,9 +1144,21 @@ static void cypress_read_int_callback(struct urb *urb)
spin_lock_irqsave(&priv->lock, flags);
/* check to see if status has changed */
if (priv->current_status != priv->prev_status) {
- priv->diff_status |= priv->current_status ^
- priv->prev_status;
- wake_up_interruptible(&priv->delta_msr_wait);
+ u8 delta = priv->current_status ^ priv->prev_status;
+
+ if (delta & UART_MSR_MASK) {
+ if (delta & UART_CTS)
+ port->icount.cts++;
+ if (delta & UART_DSR)
+ port->icount.dsr++;
+ if (delta & UART_RI)
+ port->icount.rng++;
+ if (delta & UART_CD)
+ port->icount.dcd++;
+
+ wake_up_interruptible(&port->port.delta_msr_wait);
+ }
+
priv->prev_status = priv->current_status;
}
spin_unlock_irqrestore(&priv->lock, flags);
@@ -1214,10 +1185,10 @@ static void cypress_read_int_callback(struct urb *urb)
spin_unlock_irqrestore(&priv->lock, flags);
/* process read if there is data other than line status */
- if (tty && bytes > i) {
- tty_insert_flip_string_fixed_flag(tty, data + i,
+ if (bytes > i) {
+ tty_insert_flip_string_fixed_flag(&port->port, data + i,
tty_flag, bytes - i);
- tty_flip_buffer_push(tty);
+ tty_flip_buffer_push(&port->port);
}
spin_lock_irqsave(&priv->lock, flags);
@@ -1253,7 +1224,6 @@ static void cypress_write_int_callback(struct urb *urb)
struct usb_serial_port *port = urb->context;
struct cypress_private *priv = usb_get_serial_port_data(port);
struct device *dev = &urb->dev->dev;
- int result;
int status = urb->status;
switch (status) {
@@ -1268,21 +1238,9 @@ static void cypress_write_int_callback(struct urb *urb)
__func__, status);
priv->write_urb_in_use = 0;
return;
- case -EPIPE: /* no break needed; clear halt and resubmit */
- if (!priv->comm_is_ok)
- break;
- usb_clear_halt(port->serial->dev, 0x02);
- /* error in the urb, so we have to resubmit it */
- dev_dbg(dev, "%s - nonzero write bulk status received: %d\n",
- __func__, status);
- port->interrupt_out_urb->transfer_buffer_length = 1;
- result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC);
- if (!result)
- return;
- dev_err(dev, "%s - failed resubmitting write urb, error %d\n",
- __func__, result);
- cypress_set_dead(port);
- break;
+ case -EPIPE:
+ /* Cannot call usb_clear_halt while in_interrupt */
+ /* FALLTHROUGH */
default:
dev_err(dev, "%s - unexpected nonzero write status received: %d\n",
__func__, status);
diff --git a/drivers/usb/serial/cypress_m8.h b/drivers/usb/serial/cypress_m8.h
index 67cf6082688..119d2e17077 100644
--- a/drivers/usb/serial/cypress_m8.h
+++ b/drivers/usb/serial/cypress_m8.h
@@ -24,6 +24,10 @@
#define VENDOR_ID_CYPRESS 0x04b4
#define PRODUCT_ID_CYPHIDCOM 0x5500
+/* FRWD Dongle - a GPS sports watch */
+#define VENDOR_ID_FRWD 0x6737
+#define PRODUCT_ID_CYPHIDCOM_FRWD 0x0001
+
/* Powercom UPS, chip CY7C63723 */
#define VENDOR_ID_POWERCOM 0x0d9f
#define PRODUCT_ID_UPS 0x0002
@@ -51,19 +55,23 @@
#define CT_GENERIC 0x0F
/* End of chiptype definitions */
-/* RS-232 serial data communication protocol definitions */
-/* these are sent / read at byte 0 of the input/output hid reports */
-/* You can find these values defined in the CY4601 USB to Serial design notes */
-
-#define CONTROL_DTR 0x20 /* data terminal ready - flow control - host to device */
-#define UART_DSR 0x20 /* data set ready - flow control - device to host */
-#define CONTROL_RTS 0x10 /* request to send - flow control - host to device */
-#define UART_CTS 0x10 /* clear to send - flow control - device to host */
-#define UART_RI 0x10 /* ring indicator - modem - device to host */
-#define UART_CD 0x40 /* carrier detect - modem - device to host */
-#define CYP_ERROR 0x08 /* received from input report - device to host */
-/* Note - the below has nothing to do with the "feature report" reset */
-#define CONTROL_RESET 0x08 /* sent with output report - host to device */
+/*
+ * RS-232 serial data communication protocol definitions.
+ *
+ * These are sent / read at byte 0 of the input/output hid reports.
+ * You can find these values defined in the CY4601 USB to Serial design notes.
+ */
+
+#define CONTROL_DTR 0x20 /* data terminal ready */
+#define CONTROL_RTS 0x10 /* request to send */
+#define CONTROL_RESET 0x08 /* sent with output report */
+
+#define UART_MSR_MASK 0xf0
+#define UART_RI 0x80 /* ring indicator */
+#define UART_CD 0x40 /* carrier detect */
+#define UART_DSR 0x20 /* data set ready */
+#define UART_CTS 0x10 /* clear to send */
+#define CYP_ERROR 0x08 /* received from input report */
/* End of RS-232 protocol definitions */
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index 45d4af62967..8a23c53b946 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -17,7 +17,6 @@
#include <linux/kernel.h>
#include <linux/errno.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
@@ -196,7 +195,6 @@ struct digi_port {
unsigned char dp_out_buf[DIGI_OUT_BUF_SIZE];
int dp_write_urb_in_use;
unsigned int dp_modem_signals;
- wait_queue_head_t dp_modem_change_wait;
int dp_transmit_idle;
wait_queue_head_t dp_transmit_idle_wait;
int dp_throttled;
@@ -210,7 +208,6 @@ struct digi_port {
/* Local Function Declarations */
-static void digi_wakeup_write(struct usb_serial_port *port);
static void digi_wakeup_write_lock(struct work_struct *work);
static int digi_write_oob_command(struct usb_serial_port *port,
unsigned char *buf, int count, int interruptible);
@@ -374,20 +371,10 @@ static void digi_wakeup_write_lock(struct work_struct *work)
unsigned long flags;
spin_lock_irqsave(&priv->dp_port_lock, flags);
- digi_wakeup_write(port);
+ tty_port_tty_wakeup(&port->port);
spin_unlock_irqrestore(&priv->dp_port_lock, flags);
}
-static void digi_wakeup_write(struct usb_serial_port *port)
-{
- struct tty_struct *tty = tty_port_tty_get(&port->port);
- if (tty) {
- tty_wakeup(tty);
- tty_kref_put(tty);
- }
-}
-
-
/*
* Digi Write OOB Command
*
@@ -1044,7 +1031,7 @@ static void digi_write_bulk_callback(struct urb *urb)
}
}
/* wake up processes sleeping on writes immediately */
- digi_wakeup_write(port);
+ tty_port_tty_wakeup(&port->port);
/* also queue up a wakeup at scheduler time, in case we */
/* lost the race in write_chan(). */
schedule_work(&priv->dp_wakeup_work);
@@ -1149,53 +1136,51 @@ static void digi_close(struct usb_serial_port *port)
if (port->serial->disconnected)
goto exit;
- if (port->serial->dev) {
- /* FIXME: Transmit idle belongs in the wait_unti_sent path */
- digi_transmit_idle(port, DIGI_CLOSE_TIMEOUT);
-
- /* disable input flow control */
- buf[0] = DIGI_CMD_SET_INPUT_FLOW_CONTROL;
- buf[1] = priv->dp_port_num;
- buf[2] = DIGI_DISABLE;
- buf[3] = 0;
-
- /* disable output flow control */
- buf[4] = DIGI_CMD_SET_OUTPUT_FLOW_CONTROL;
- buf[5] = priv->dp_port_num;
- buf[6] = DIGI_DISABLE;
- buf[7] = 0;
-
- /* disable reading modem signals automatically */
- buf[8] = DIGI_CMD_READ_INPUT_SIGNALS;
- buf[9] = priv->dp_port_num;
- buf[10] = DIGI_DISABLE;
- buf[11] = 0;
-
- /* disable receive */
- buf[12] = DIGI_CMD_RECEIVE_ENABLE;
- buf[13] = priv->dp_port_num;
- buf[14] = DIGI_DISABLE;
- buf[15] = 0;
-
- /* flush fifos */
- buf[16] = DIGI_CMD_IFLUSH_FIFO;
- buf[17] = priv->dp_port_num;
- buf[18] = DIGI_FLUSH_TX | DIGI_FLUSH_RX;
- buf[19] = 0;
-
- ret = digi_write_oob_command(port, buf, 20, 0);
- if (ret != 0)
- dev_dbg(&port->dev, "digi_close: write oob failed, ret=%d\n", ret);
-
- /* wait for final commands on oob port to complete */
- prepare_to_wait(&priv->dp_flush_wait, &wait,
- TASK_INTERRUPTIBLE);
- schedule_timeout(DIGI_CLOSE_TIMEOUT);
- finish_wait(&priv->dp_flush_wait, &wait);
-
- /* shutdown any outstanding bulk writes */
- usb_kill_urb(port->write_urb);
- }
+ /* FIXME: Transmit idle belongs in the wait_unti_sent path */
+ digi_transmit_idle(port, DIGI_CLOSE_TIMEOUT);
+
+ /* disable input flow control */
+ buf[0] = DIGI_CMD_SET_INPUT_FLOW_CONTROL;
+ buf[1] = priv->dp_port_num;
+ buf[2] = DIGI_DISABLE;
+ buf[3] = 0;
+
+ /* disable output flow control */
+ buf[4] = DIGI_CMD_SET_OUTPUT_FLOW_CONTROL;
+ buf[5] = priv->dp_port_num;
+ buf[6] = DIGI_DISABLE;
+ buf[7] = 0;
+
+ /* disable reading modem signals automatically */
+ buf[8] = DIGI_CMD_READ_INPUT_SIGNALS;
+ buf[9] = priv->dp_port_num;
+ buf[10] = DIGI_DISABLE;
+ buf[11] = 0;
+
+ /* disable receive */
+ buf[12] = DIGI_CMD_RECEIVE_ENABLE;
+ buf[13] = priv->dp_port_num;
+ buf[14] = DIGI_DISABLE;
+ buf[15] = 0;
+
+ /* flush fifos */
+ buf[16] = DIGI_CMD_IFLUSH_FIFO;
+ buf[17] = priv->dp_port_num;
+ buf[18] = DIGI_FLUSH_TX | DIGI_FLUSH_RX;
+ buf[19] = 0;
+
+ ret = digi_write_oob_command(port, buf, 20, 0);
+ if (ret != 0)
+ dev_dbg(&port->dev, "digi_close: write oob failed, ret=%d\n",
+ ret);
+ /* wait for final commands on oob port to complete */
+ prepare_to_wait(&priv->dp_flush_wait, &wait,
+ TASK_INTERRUPTIBLE);
+ schedule_timeout(DIGI_CLOSE_TIMEOUT);
+ finish_wait(&priv->dp_flush_wait, &wait);
+
+ /* shutdown any outstanding bulk writes */
+ usb_kill_urb(port->write_urb);
exit:
spin_lock_irq(&priv->dp_port_lock);
priv->dp_write_urb_in_use = 0;
@@ -1252,7 +1237,6 @@ static int digi_port_init(struct usb_serial_port *port, unsigned port_num)
spin_lock_init(&priv->dp_port_lock);
priv->dp_port_num = port_num;
- init_waitqueue_head(&priv->dp_modem_change_wait);
init_waitqueue_head(&priv->dp_transmit_idle_wait);
init_waitqueue_head(&priv->dp_flush_wait);
init_waitqueue_head(&priv->dp_close_wait);
@@ -1319,11 +1303,7 @@ static void digi_release(struct usb_serial *serial)
static int digi_port_probe(struct usb_serial_port *port)
{
- unsigned port_num;
-
- port_num = port->number - port->serial->minor;
-
- return digi_port_init(port, port_num);
+ return digi_port_init(port, port->port_number);
}
static int digi_port_remove(struct usb_serial_port *port)
@@ -1399,9 +1379,7 @@ static void digi_read_bulk_callback(struct urb *urb)
static int digi_read_inb_callback(struct urb *urb)
{
-
struct usb_serial_port *port = urb->context;
- struct tty_struct *tty;
struct digi_port *priv = usb_get_serial_port_data(port);
int opcode = ((unsigned char *)urb->transfer_buffer)[0];
int len = ((unsigned char *)urb->transfer_buffer)[1];
@@ -1425,7 +1403,6 @@ static int digi_read_inb_callback(struct urb *urb)
return -1;
}
- tty = tty_port_tty_get(&port->port);
spin_lock(&priv->dp_port_lock);
/* check for throttle; if set, do not resubmit read urb */
@@ -1435,13 +1412,13 @@ static int digi_read_inb_callback(struct urb *urb)
priv->dp_throttle_restart = 1;
/* receive data */
- if (tty && opcode == DIGI_CMD_RECEIVE_DATA) {
+ if (opcode == DIGI_CMD_RECEIVE_DATA) {
/* get flag from port_status */
flag = 0;
/* overrun is special, not associated with a char */
if (port_status & DIGI_OVERRUN_ERROR)
- tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+ tty_insert_flip_char(&port->port, 0, TTY_OVERRUN);
/* break takes precedence over parity, */
/* which takes precedence over framing errors */
@@ -1455,13 +1432,12 @@ static int digi_read_inb_callback(struct urb *urb)
/* data length is len-1 (one byte of len is port_status) */
--len;
if (len > 0) {
- tty_insert_flip_string_fixed_flag(tty, data, flag,
- len);
- tty_flip_buffer_push(tty);
+ tty_insert_flip_string_fixed_flag(&port->port, data,
+ flag, len);
+ tty_flip_buffer_push(&port->port);
}
}
spin_unlock(&priv->dp_port_lock);
- tty_kref_put(tty);
if (opcode == DIGI_CMD_RECEIVE_DISABLE)
dev_dbg(&port->dev, "%s: got RECEIVE_DISABLE\n", __func__);
@@ -1526,7 +1502,7 @@ static int digi_read_oob_callback(struct urb *urb)
/* port must be open to use tty struct */
if (rts) {
tty->hw_stopped = 0;
- digi_wakeup_write(port);
+ tty_port_tty_wakeup(&port->port);
}
} else {
priv->dp_modem_signals &= ~TIOCM_CTS;
@@ -1547,7 +1523,6 @@ static int digi_read_oob_callback(struct urb *urb)
else
priv->dp_modem_signals &= ~TIOCM_CD;
- wake_up_interruptible(&priv->dp_modem_change_wait);
spin_unlock(&priv->dp_port_lock);
} else if (opcode == DIGI_CMD_TRANSMIT_IDLE) {
spin_lock(&priv->dp_port_lock);
diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c
index 0f658618db1..90e603d5f66 100644
--- a/drivers/usb/serial/empeg.c
+++ b/drivers/usb/serial/empeg.c
@@ -17,7 +17,6 @@
#include <linux/kernel.h>
#include <linux/errno.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 6e4eb57d017..c5dc233db2d 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -12,7 +12,6 @@
#include <linux/kernel.h>
#include <linux/errno.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
@@ -47,7 +46,6 @@ MODULE_DEVICE_TABLE(usb, id_table);
struct f81232_private {
spinlock_t lock;
- wait_queue_head_t delta_msr_wait;
u8 line_control;
u8 line_status;
};
@@ -56,6 +54,13 @@ static void f81232_update_line_status(struct usb_serial_port *port,
unsigned char *data,
unsigned int actual_length)
{
+ /*
+ * FIXME: Update port->icount, and call
+ *
+ * wake_up_interruptible(&port->port.delta_msr_wait);
+ *
+ * on MSR changes.
+ */
}
static void f81232_read_int_callback(struct urb *urb)
@@ -100,7 +105,6 @@ static void f81232_process_read_urb(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
struct f81232_private *priv = usb_get_serial_port_data(port);
- struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
char tty_flag = TTY_NORMAL;
unsigned long flags;
@@ -112,15 +116,10 @@ static void f81232_process_read_urb(struct urb *urb)
line_status = priv->line_status;
priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
spin_unlock_irqrestore(&priv->lock, flags);
- wake_up_interruptible(&priv->delta_msr_wait);
if (!urb->actual_length)
return;
- tty = tty_port_tty_get(&port->port);
- if (!tty)
- return;
-
/* break takes precedence over parity, */
/* which takes precedence over framing errors */
if (line_status & UART_BREAK_ERROR)
@@ -133,19 +132,19 @@ static void f81232_process_read_urb(struct urb *urb)
/* overrun is special, not associated with a char */
if (line_status & UART_OVERRUN_ERROR)
- tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+ tty_insert_flip_char(&port->port, 0, TTY_OVERRUN);
if (port->port.console && port->sysrq) {
for (i = 0; i < urb->actual_length; ++i)
if (!usb_serial_handle_sysrq_char(port, data[i]))
- tty_insert_flip_char(tty, data[i], tty_flag);
+ tty_insert_flip_char(&port->port, data[i],
+ tty_flag);
} else {
- tty_insert_flip_string_fixed_flag(tty, data, tty_flag,
+ tty_insert_flip_string_fixed_flag(&port->port, data, tty_flag,
urb->actual_length);
}
- tty_flip_buffer_push(tty);
- tty_kref_put(tty);
+ tty_flip_buffer_push(&port->port);
}
static int set_control_lines(struct usb_device *dev, u8 value)
@@ -171,11 +170,12 @@ static void f81232_set_termios(struct tty_struct *tty,
/* FIXME - Stubbed out for now */
/* Don't change anything if nothing has changed */
- if (!tty_termios_hw_change(&tty->termios, old_termios))
+ if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios))
return;
/* Do the real work here... */
- tty_termios_copy_hw(&tty->termios, old_termios);
+ if (old_termios)
+ tty_termios_copy_hw(&tty->termios, old_termios);
}
static int f81232_tiocmget(struct tty_struct *tty)
@@ -193,12 +193,11 @@ static int f81232_tiocmset(struct tty_struct *tty,
static int f81232_open(struct tty_struct *tty, struct usb_serial_port *port)
{
- struct ktermios tmp_termios;
int result;
/* Setup termios */
if (tty)
- f81232_set_termios(tty, port, &tmp_termios);
+ f81232_set_termios(tty, port, NULL);
result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (result) {
@@ -213,7 +212,6 @@ static int f81232_open(struct tty_struct *tty, struct usb_serial_port *port)
return result;
}
- port->port.drain_delay = 256;
return 0;
}
@@ -248,71 +246,25 @@ static int f81232_carrier_raised(struct usb_serial_port *port)
return 0;
}
-static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
-{
- struct f81232_private *priv = usb_get_serial_port_data(port);
- unsigned long flags;
- unsigned int prevstatus;
- unsigned int status;
- unsigned int changed;
-
- spin_lock_irqsave(&priv->lock, flags);
- prevstatus = priv->line_status;
- spin_unlock_irqrestore(&priv->lock, flags);
-
- while (1) {
- interruptible_sleep_on(&priv->delta_msr_wait);
- /* see if a signal did it */
- if (signal_pending(current))
- return -ERESTARTSYS;
-
- spin_lock_irqsave(&priv->lock, flags);
- status = priv->line_status;
- spin_unlock_irqrestore(&priv->lock, flags);
-
- changed = prevstatus ^ status;
-
- if (((arg & TIOCM_RNG) && (changed & UART_RING)) ||
- ((arg & TIOCM_DSR) && (changed & UART_DSR)) ||
- ((arg & TIOCM_CD) && (changed & UART_DCD)) ||
- ((arg & TIOCM_CTS) && (changed & UART_CTS))) {
- return 0;
- }
- prevstatus = status;
- }
- /* NOTREACHED */
- return 0;
-}
-
static int f81232_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
struct serial_struct ser;
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(&port->dev, "%s (%d) cmd = 0x%04x\n", __func__,
- port->number, cmd);
-
switch (cmd) {
case TIOCGSERIAL:
memset(&ser, 0, sizeof ser);
ser.type = PORT_16654;
- ser.line = port->serial->minor;
- ser.port = port->number;
+ ser.line = port->minor;
+ ser.port = port->port_number;
ser.baud_base = 460800;
if (copy_to_user((void __user *)arg, &ser, sizeof ser))
return -EFAULT;
return 0;
-
- case TIOCMIWAIT:
- dev_dbg(&port->dev, "%s (%d) TIOCMIWAIT\n", __func__,
- port->number);
- return wait_modem_info(port, arg);
default:
- dev_dbg(&port->dev, "%s not supported = 0x%04x\n",
- __func__, cmd);
break;
}
return -ENOIOCTLCMD;
@@ -327,10 +279,11 @@ static int f81232_port_probe(struct usb_serial_port *port)
return -ENOMEM;
spin_lock_init(&priv->lock);
- init_waitqueue_head(&priv->delta_msr_wait);
usb_set_serial_port_data(port, priv);
+ port->port.drain_delay = 256;
+
return 0;
}
@@ -362,6 +315,7 @@ static struct usb_serial_driver f81232_device = {
.set_termios = f81232_set_termios,
.tiocmget = f81232_tiocmget,
.tiocmset = f81232_tiocmset,
+ .tiocmiwait = usb_serial_generic_tiocmiwait,
.process_read_urb = f81232_process_read_urb,
.read_int_callback = f81232_read_int_callback,
.port_probe = f81232_port_probe,
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index ba68835d06a..8a3813be1b2 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -1,7 +1,7 @@
/*
* USB FTDI SIO driver
*
- * Copyright (C) 2009 - 2010
+ * Copyright (C) 2009 - 2013
* Johan Hovold (jhovold@gmail.com)
* Copyright (C) 1999 - 2001
* Greg Kroah-Hartman (greg@kroah.com)
@@ -33,7 +33,6 @@
#include <linux/kernel.h>
#include <linux/errno.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
@@ -51,11 +50,8 @@
#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>, Kuba Ober <kuba@mareimbrium.org>, Andreas Mohr, Johan Hovold <jhovold@gmail.com>"
#define DRIVER_DESC "USB FTDI Serial Converters Driver"
-static __u16 vendor = FTDI_VID;
-static __u16 product;
struct ftdi_private {
- struct kref kref;
enum ftdi_chip_type chip_type;
/* type of device, either SIO or FT8U232AM */
int baud_base; /* baud base clock for divisor setting */
@@ -68,10 +64,7 @@ struct ftdi_private {
*/
int flags; /* some ASYNC_xxxx flags are supported */
unsigned long last_dtr_rts; /* saved modem control outputs */
- struct async_icount icount;
- wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
char prev_status; /* Used for TIOCMIWAIT */
- bool dev_gone; /* Used to abort TIOCMIWAIT */
char transmit_empty; /* If transmitter is empty or not */
__u16 interface; /* FT2232C, FT2232H or FT4232H port interface
(0 for FT232/245) */
@@ -148,10 +141,10 @@ static struct ftdi_sio_quirk ftdi_8u2232c_quirk = {
/*
- * Device ID not listed? Test via module params product/vendor or
- * /sys/bus/usb/ftdi_sio/new_id, then send patch/report!
+ * Device ID not listed? Test it using
+ * /sys/bus/usb-serial/drivers/ftdi_sio/new_id and send a patch or report.
*/
-static struct usb_device_id id_table_combined [] = {
+static const struct usb_device_id id_table_combined[] = {
{ USB_DEVICE(FTDI_VID, FTDI_ZEITCONTROL_TAGTRACE_MIFARE_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CTI_MINI_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CTI_NANO_PID) },
@@ -159,6 +152,7 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_CANUSB_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CANDAPTER_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_NXTCAM_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_EV3CON_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_0_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_1_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_2_PID) },
@@ -191,10 +185,15 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_OPENDCC_THROTTLE_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GATEWAY_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GBM_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GBM_BOOST_PID) },
{ USB_DEVICE(NEWPORT_VID, NEWPORT_AGILIS_PID) },
+ { USB_DEVICE(NEWPORT_VID, NEWPORT_CONEX_CC_PID) },
+ { USB_DEVICE(NEWPORT_VID, NEWPORT_CONEX_AGP_PID) },
{ USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) },
{ USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_SPROG_II) },
+ { USB_DEVICE(FTDI_VID, FTDI_TAGSYS_LP101_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_TAGSYS_P200X_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_LENZ_LIUSB_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_XF_632_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_XF_634_PID) },
@@ -581,9 +580,12 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_TAVIR_STK500_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_TIAO_UMPA_PID),
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+ { USB_DEVICE(FTDI_VID, FTDI_NT_ORIONLXM_PID),
+ .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
/*
* ELV devices:
*/
+ { USB_DEVICE(FTDI_ELV_VID, FTDI_ELV_WS300_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_USR_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_MSM1_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_KL100_PID) },
@@ -641,6 +643,7 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_RM_CANVIEW_PID) },
{ USB_DEVICE(ACTON_VID, ACTON_SPECTRAPRO_PID) },
{ USB_DEVICE(CONTEC_VID, CONTEC_COM1USBH_PID) },
+ { USB_DEVICE(MITSUBISHI_VID, MITSUBISHI_FXUSB_PID) },
{ USB_DEVICE(BANDB_VID, BANDB_USOTL4_PID) },
{ USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) },
{ USB_DEVICE(BANDB_VID, BANDB_USO9ML2_PID) },
@@ -670,6 +673,7 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_5_PID) },
{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_6_PID) },
{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_7_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_OMNI1509) },
{ USB_DEVICE(MOBILITY_VID, MOBILITY_USB_SERIAL_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ACTIVE_ROBOTS_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_MHAM_KW_PID) },
@@ -716,7 +720,8 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_ACG_HFDUAL_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_YEI_SERVOCENTER31_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_THORLABS_PID) },
- { USB_DEVICE(TESTO_VID, TESTO_USB_INTERFACE_PID) },
+ { USB_DEVICE(TESTO_VID, TESTO_1_PID) },
+ { USB_DEVICE(TESTO_VID, TESTO_3_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_GAMMA_SCOUT_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13M_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13S_PID) },
@@ -733,9 +738,34 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_NDI_AURORA_SCU_PID),
.driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk },
{ USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) },
- { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_SERIAL_VX7_PID) },
- { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_CT29B_PID) },
- { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_RTS01_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_S03_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_59_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_57A_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_57B_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_29A_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_29B_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_29F_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_62B_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_S01_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_63_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_29C_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_81B_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_82B_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_K5D_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_K4Y_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_K5G_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_S05_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_60_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_61_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_62_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_63B_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_64_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_65_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_92_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_92D_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_W5R_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_A5R_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_PW1_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_MAXSTREAM_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_PHI_FISCO_PID) },
{ USB_DEVICE(TML_VID, TML_USB_SERIAL_PID) },
@@ -869,7 +899,9 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_DOTEC_PID) },
{ USB_DEVICE(QIHARDWARE_VID, MILKYMISTONE_JTAGSERIAL_PID),
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
- { USB_DEVICE(ST_VID, ST_STMCLT1030_PID),
+ { USB_DEVICE(ST_VID, ST_STMCLT_2232_PID),
+ .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+ { USB_DEVICE(ST_VID, ST_STMCLT_4232_PID),
.driver_info = (kernel_ulong_t)&ftdi_stmclite_quirk },
{ USB_DEVICE(FTDI_VID, FTDI_RF_R106) },
{ USB_DEVICE(FTDI_VID, FTDI_DISTORTEC_JTAG_LOCK_PICK_PID),
@@ -877,7 +909,44 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_LUMEL_PD12_PID) },
/* Crucible Devices */
{ USB_DEVICE(FTDI_VID, FTDI_CT_COMET_PID) },
- { }, /* Optional parameter entry */
+ { USB_DEVICE(FTDI_VID, FTDI_Z3X_PID) },
+ /* Cressi Devices */
+ { USB_DEVICE(FTDI_VID, FTDI_CRESSI_PID) },
+ /* Brainboxes Devices */
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_VX_001_PID) },
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_VX_012_PID) },
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_VX_023_PID) },
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_VX_034_PID) },
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_101_PID) },
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_1_PID) },
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_2_PID) },
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_3_PID) },
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_4_PID) },
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_5_PID) },
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_6_PID) },
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_7_PID) },
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_8_PID) },
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_257_PID) },
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_279_1_PID) },
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_279_2_PID) },
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_279_3_PID) },
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_279_4_PID) },
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_313_PID) },
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_324_PID) },
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_346_1_PID) },
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_346_2_PID) },
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_357_PID) },
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_606_1_PID) },
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_606_2_PID) },
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_606_3_PID) },
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_701_1_PID) },
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_701_2_PID) },
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_842_1_PID) },
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_842_2_PID) },
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_842_3_PID) },
+ { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_842_4_PID) },
+ /* Infineon Devices */
+ { USB_DEVICE_INTERFACE_NUMBER(INFINEON_VID, INFINEON_TRIBOARD_PID, 1) },
{ } /* Terminating entry */
};
@@ -901,16 +970,12 @@ static const char *ftdi_chip_name[] = {
#define FTDI_STATUS_B1_MASK (FTDI_RS_BI)
/* End TIOCMIWAIT */
-#define FTDI_IMPL_ASYNC_FLAGS = (ASYNC_SPD_HI | ASYNC_SPD_VHI \
- | ASYNC_SPD_CUST | ASYNC_SPD_SHI | ASYNC_SPD_WARP)
-
/* function prototypes for a FTDI serial converter */
static int ftdi_sio_probe(struct usb_serial *serial,
const struct usb_device_id *id);
static int ftdi_sio_port_probe(struct usb_serial_port *port);
static int ftdi_sio_port_remove(struct usb_serial_port *port);
static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port);
-static void ftdi_close(struct usb_serial_port *port);
static void ftdi_dtr_rts(struct usb_serial_port *port, int on);
static void ftdi_process_read_urb(struct urb *urb);
static int ftdi_prepare_write_buffer(struct usb_serial_port *port,
@@ -920,13 +985,11 @@ static void ftdi_set_termios(struct tty_struct *tty,
static int ftdi_tiocmget(struct tty_struct *tty);
static int ftdi_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear);
-static int ftdi_get_icount(struct tty_struct *tty,
- struct serial_icounter_struct *icount);
static int ftdi_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg);
static void ftdi_break_ctl(struct tty_struct *tty, int break_state);
-static int ftdi_chars_in_buffer(struct tty_struct *tty);
-static int ftdi_get_modem_status(struct tty_struct *tty,
+static bool ftdi_tx_empty(struct usb_serial_port *port);
+static int ftdi_get_modem_status(struct usb_serial_port *port,
unsigned char status[2]);
static unsigned short int ftdi_232am_baud_base_to_divisor(int baud, int base);
@@ -950,7 +1013,6 @@ static struct usb_serial_driver ftdi_sio_device = {
.port_probe = ftdi_sio_port_probe,
.port_remove = ftdi_sio_port_remove,
.open = ftdi_open,
- .close = ftdi_close,
.dtr_rts = ftdi_dtr_rts,
.throttle = usb_serial_generic_throttle,
.unthrottle = usb_serial_generic_unthrottle,
@@ -958,11 +1020,12 @@ static struct usb_serial_driver ftdi_sio_device = {
.prepare_write_buffer = ftdi_prepare_write_buffer,
.tiocmget = ftdi_tiocmget,
.tiocmset = ftdi_tiocmset,
- .get_icount = ftdi_get_icount,
+ .tiocmiwait = usb_serial_generic_tiocmiwait,
+ .get_icount = usb_serial_generic_get_icount,
.ioctl = ftdi_ioctl,
.set_termios = ftdi_set_termios,
.break_ctl = ftdi_break_ctl,
- .chars_in_buffer = ftdi_chars_in_buffer,
+ .tx_empty = ftdi_tx_empty,
};
static struct usb_serial_driver * const serial_drivers[] = {
@@ -973,10 +1036,6 @@ static struct usb_serial_driver * const serial_drivers[] = {
#define WDR_TIMEOUT 5000 /* default urb timeout */
#define WDR_SHORT_TIMEOUT 1000 /* shorter urb timeout */
-/* High and low are for DTR, RTS etc etc */
-#define HIGH 1
-#define LOW 0
-
/*
* ***************************************************************************
* Utility functions
@@ -1510,14 +1569,17 @@ static void ftdi_set_max_packet_size(struct usb_serial_port *port)
struct usb_device *udev = serial->dev;
struct usb_interface *interface = serial->interface;
- struct usb_endpoint_descriptor *ep_desc = &interface->cur_altsetting->endpoint[1].desc;
+ struct usb_endpoint_descriptor *ep_desc;
unsigned num_endpoints;
- int i;
+ unsigned i;
num_endpoints = interface->cur_altsetting->desc.bNumEndpoints;
dev_info(&udev->dev, "Number of endpoints %d\n", num_endpoints);
+ if (!num_endpoints)
+ return;
+
/* NOTE: some customers have programmed FT232R/FT245R devices
* with an endpoint size of 0 - not good. In this case, we
* want to override the endpoint descriptor setting and use a
@@ -1545,8 +1607,8 @@ static void ftdi_set_max_packet_size(struct usb_serial_port *port)
* ***************************************************************************
*/
-static ssize_t show_latency_timer(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t latency_timer_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct usb_serial_port *port = to_usb_serial_port(dev);
struct ftdi_private *priv = usb_get_serial_port_data(port);
@@ -1556,11 +1618,10 @@ static ssize_t show_latency_timer(struct device *dev,
return sprintf(buf, "%i\n", priv->latency);
}
-
/* Write a new value of the latency timer, in units of milliseconds. */
-static ssize_t store_latency_timer(struct device *dev,
- struct device_attribute *attr, const char *valbuf,
- size_t count)
+static ssize_t latency_timer_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *valbuf, size_t count)
{
struct usb_serial_port *port = to_usb_serial_port(dev);
struct ftdi_private *priv = usb_get_serial_port_data(port);
@@ -1573,6 +1634,7 @@ static ssize_t store_latency_timer(struct device *dev,
return -EIO;
return count;
}
+static DEVICE_ATTR_RW(latency_timer);
/* Write an event character directly to the FTDI register. The ASCII
value is in the low 8 bits, with the enable bit in the 9th bit. */
@@ -1600,9 +1662,6 @@ static ssize_t store_event_char(struct device *dev,
return count;
}
-
-static DEVICE_ATTR(latency_timer, S_IWUSR | S_IRUGO, show_latency_timer,
- store_latency_timer);
static DEVICE_ATTR(event_char, S_IWUSR, NULL, store_event_char);
static int create_sysfs_attrs(struct usb_serial_port *port)
@@ -1681,18 +1740,12 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
priv = kzalloc(sizeof(struct ftdi_private), GFP_KERNEL);
- if (!priv) {
- dev_err(&port->dev, "%s- kmalloc(%Zd) failed.\n", __func__,
- sizeof(struct ftdi_private));
+ if (!priv)
return -ENOMEM;
- }
- kref_init(&priv->kref);
mutex_init(&priv->cfg_lock);
- init_waitqueue_head(&priv->delta_msr_wait);
priv->flags = ASYNC_LOW_LATENCY;
- priv->dev_gone = false;
if (quirk && quirk->port_probe)
quirk->port_probe(priv);
@@ -1793,20 +1846,24 @@ static int ftdi_8u2232c_probe(struct usb_serial *serial)
}
/*
- * First and second port on STMCLiteadaptors is reserved for JTAG interface
- * and the forth port for pio
+ * First two ports on JTAG adaptors using an FT4232 such as STMicroelectronics's
+ * ST Micro Connect Lite are reserved for JTAG or other non-UART interfaces and
+ * can be accessed from userspace.
+ * The next two ports are enabled as UARTs by default, where port 2 is
+ * a conventional RS-232 UART.
*/
static int ftdi_stmclite_probe(struct usb_serial *serial)
{
struct usb_device *udev = serial->dev;
struct usb_interface *interface = serial->interface;
- if (interface == udev->actconfig->interface[2])
- return 0;
-
- dev_info(&udev->dev, "Ignoring serial port reserved for JTAG\n");
+ if (interface == udev->actconfig->interface[0] ||
+ interface == udev->actconfig->interface[1]) {
+ dev_info(&udev->dev, "Ignoring serial port reserved for JTAG\n");
+ return -ENODEV;
+ }
- return -ENODEV;
+ return 0;
}
/*
@@ -1827,33 +1884,21 @@ static int ftdi_mtxorb_hack_setup(struct usb_serial *serial)
return 0;
}
-static void ftdi_sio_priv_release(struct kref *k)
-{
- struct ftdi_private *priv = container_of(k, struct ftdi_private, kref);
-
- kfree(priv);
-}
-
static int ftdi_sio_port_remove(struct usb_serial_port *port)
{
struct ftdi_private *priv = usb_get_serial_port_data(port);
- priv->dev_gone = true;
- wake_up_interruptible_all(&priv->delta_msr_wait);
-
remove_sysfs_attrs(port);
- kref_put(&priv->kref, ftdi_sio_priv_release);
+ kfree(priv);
return 0;
}
static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)
{
- struct ktermios dummy;
struct usb_device *dev = port->serial->dev;
struct ftdi_private *priv = usb_get_serial_port_data(port);
- int result;
/* No error checking for this (will get errors later anyway) */
/* See ftdi_sio.h for description of what is reset */
@@ -1867,54 +1912,32 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)
This is same behaviour as serial.c/rs_open() - Kuba */
/* ftdi_set_termios will send usb control messages */
- if (tty) {
- memset(&dummy, 0, sizeof(dummy));
- ftdi_set_termios(tty, port, &dummy);
- }
-
- /* Start reading from the device */
- result = usb_serial_generic_open(tty, port);
- if (!result)
- kref_get(&priv->kref);
+ if (tty)
+ ftdi_set_termios(tty, port, NULL);
- return result;
+ return usb_serial_generic_open(tty, port);
}
static void ftdi_dtr_rts(struct usb_serial_port *port, int on)
{
struct ftdi_private *priv = usb_get_serial_port_data(port);
- mutex_lock(&port->serial->disc_mutex);
- if (!port->serial->disconnected) {
- /* Disable flow control */
- if (!on && usb_control_msg(port->serial->dev,
+ /* Disable flow control */
+ if (!on) {
+ if (usb_control_msg(port->serial->dev,
usb_sndctrlpipe(port->serial->dev, 0),
FTDI_SIO_SET_FLOW_CTRL_REQUEST,
FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
0, priv->interface, NULL, 0,
WDR_TIMEOUT) < 0) {
- dev_err(&port->dev, "error from flowcontrol urb\n");
+ dev_err(&port->dev, "error from flowcontrol urb\n");
}
- /* drop RTS and DTR */
- if (on)
- set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
- else
- clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
}
- mutex_unlock(&port->serial->disc_mutex);
-}
-
-/*
- * usbserial:__serial_close only calls ftdi_close if the point is open
- *
- * This only gets called when it is the last close
- */
-static void ftdi_close(struct usb_serial_port *port)
-{
- struct ftdi_private *priv = usb_get_serial_port_data(port);
-
- usb_serial_generic_close(port);
- kref_put(&priv->kref, ftdi_sio_priv_release);
+ /* drop RTS and DTR */
+ if (on)
+ set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+ else
+ clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
}
/* The SIO requires the first byte to have:
@@ -1944,7 +1967,7 @@ static int ftdi_prepare_write_buffer(struct usb_serial_port *port,
c = kfifo_out(&port->write_fifo, &buffer[i + 1], len);
if (!c)
break;
- priv->icount.tx += c;
+ port->icount.tx += c;
buffer[i] = (c << 2) + 1;
count += c + 1;
}
@@ -1952,7 +1975,7 @@ static int ftdi_prepare_write_buffer(struct usb_serial_port *port,
} else {
count = kfifo_out_locked(&port->write_fifo, dest, size,
&port->lock);
- priv->icount.tx += count;
+ port->icount.tx += count;
}
return count;
@@ -1960,9 +1983,8 @@ static int ftdi_prepare_write_buffer(struct usb_serial_port *port,
#define FTDI_RS_ERR_MASK (FTDI_RS_BI | FTDI_RS_PE | FTDI_RS_FE | FTDI_RS_OE)
-static int ftdi_process_packet(struct tty_struct *tty,
- struct usb_serial_port *port, struct ftdi_private *priv,
- char *packet, int len)
+static int ftdi_process_packet(struct usb_serial_port *port,
+ struct ftdi_private *priv, char *packet, int len)
{
int i;
char status;
@@ -1982,15 +2004,23 @@ static int ftdi_process_packet(struct tty_struct *tty,
char diff_status = status ^ priv->prev_status;
if (diff_status & FTDI_RS0_CTS)
- priv->icount.cts++;
+ port->icount.cts++;
if (diff_status & FTDI_RS0_DSR)
- priv->icount.dsr++;
+ port->icount.dsr++;
if (diff_status & FTDI_RS0_RI)
- priv->icount.rng++;
- if (diff_status & FTDI_RS0_RLSD)
- priv->icount.dcd++;
+ port->icount.rng++;
+ if (diff_status & FTDI_RS0_RLSD) {
+ struct tty_struct *tty;
+
+ port->icount.dcd++;
+ tty = tty_port_tty_get(&port->port);
+ if (tty)
+ usb_serial_handle_dcd_change(port, tty,
+ status & FTDI_RS0_RLSD);
+ tty_kref_put(tty);
+ }
- wake_up_interruptible_all(&priv->delta_msr_wait);
+ wake_up_interruptible(&port->port.delta_msr_wait);
priv->prev_status = status;
}
@@ -2000,19 +2030,19 @@ static int ftdi_process_packet(struct tty_struct *tty,
* over framing errors */
if (packet[1] & FTDI_RS_BI) {
flag = TTY_BREAK;
- priv->icount.brk++;
+ port->icount.brk++;
usb_serial_handle_break(port);
} else if (packet[1] & FTDI_RS_PE) {
flag = TTY_PARITY;
- priv->icount.parity++;
+ port->icount.parity++;
} else if (packet[1] & FTDI_RS_FE) {
flag = TTY_FRAME;
- priv->icount.frame++;
+ port->icount.frame++;
}
/* Overrun is special, not associated with a char */
if (packet[1] & FTDI_RS_OE) {
- priv->icount.overrun++;
- tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+ port->icount.overrun++;
+ tty_insert_flip_char(&port->port, 0, TTY_OVERRUN);
}
}
@@ -2025,16 +2055,16 @@ static int ftdi_process_packet(struct tty_struct *tty,
len -= 2;
if (!len)
return 0; /* status only */
- priv->icount.rx += len;
+ port->icount.rx += len;
ch = packet + 2;
if (port->port.console && port->sysrq) {
for (i = 0; i < len; i++, ch++) {
if (!usb_serial_handle_sysrq_char(port, *ch))
- tty_insert_flip_char(tty, *ch, flag);
+ tty_insert_flip_char(&port->port, *ch, flag);
}
} else {
- tty_insert_flip_string_fixed_flag(tty, ch, flag, len);
+ tty_insert_flip_string_fixed_flag(&port->port, ch, flag, len);
}
return len;
@@ -2043,25 +2073,19 @@ static int ftdi_process_packet(struct tty_struct *tty,
static void ftdi_process_read_urb(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
- struct tty_struct *tty;
struct ftdi_private *priv = usb_get_serial_port_data(port);
char *data = (char *)urb->transfer_buffer;
int i;
int len;
int count = 0;
- tty = tty_port_tty_get(&port->port);
- if (!tty)
- return;
-
for (i = 0; i < urb->actual_length; i += priv->max_packet_size) {
len = min_t(int, urb->actual_length - i, priv->max_packet_size);
- count += ftdi_process_packet(tty, port, priv, &data[i], len);
+ count += ftdi_process_packet(port, priv, &data[i], len);
}
if (count)
- tty_flip_buffer_push(tty);
- tty_kref_put(tty);
+ tty_flip_buffer_push(&port->port);
}
static void ftdi_break_ctl(struct tty_struct *tty, int break_state)
@@ -2094,27 +2118,18 @@ static void ftdi_break_ctl(struct tty_struct *tty, int break_state)
}
-static int ftdi_chars_in_buffer(struct tty_struct *tty)
+static bool ftdi_tx_empty(struct usb_serial_port *port)
{
- struct usb_serial_port *port = tty->driver_data;
- int chars;
unsigned char buf[2];
int ret;
- chars = usb_serial_generic_chars_in_buffer(tty);
- if (chars)
- goto out;
-
- /* Check if hardware buffer is empty. */
- ret = ftdi_get_modem_status(tty, buf);
+ ret = ftdi_get_modem_status(port, buf);
if (ret == 2) {
if (!(buf[1] & FTDI_RS_TEMT))
- chars = 1;
+ return false;
}
-out:
- dev_dbg(&port->dev, "%s - %d\n", __func__, chars);
- return chars;
+ return true;
}
/* old_termios contains the original termios settings and tty->termios contains
@@ -2150,6 +2165,30 @@ static void ftdi_set_termios(struct tty_struct *tty,
termios->c_cflag |= CRTSCTS;
}
+ /*
+ * All FTDI UART chips are limited to CS7/8. We shouldn't pretend to
+ * support CS5/6 and revert the CSIZE setting instead.
+ *
+ * CS5 however is used to control some smartcard readers which abuse
+ * this limitation to switch modes. Original FTDI chips fall back to
+ * eight data bits.
+ *
+ * TODO: Implement a quirk to only allow this with mentioned
+ * readers. One I know of (Argolis Smartreader V1)
+ * returns "USB smartcard server" as iInterface string.
+ * The vendor didn't bother with a custom VID/PID of
+ * course.
+ */
+ if (C_CSIZE(tty) == CS6) {
+ dev_warn(ddev, "requested CSIZE setting not supported\n");
+
+ termios->c_cflag &= ~CSIZE;
+ if (old_termios)
+ termios->c_cflag |= old_termios->c_cflag & CSIZE;
+ else
+ termios->c_cflag |= CS8;
+ }
+
cflag = termios->c_cflag;
if (!old_termios)
@@ -2186,19 +2225,19 @@ no_skip:
} else {
urb_value |= FTDI_SIO_SET_DATA_PARITY_NONE;
}
- if (cflag & CSIZE) {
- switch (cflag & CSIZE) {
- case CS7:
- urb_value |= 7;
- dev_dbg(ddev, "Setting CS7\n");
- break;
- case CS8:
- urb_value |= 8;
- dev_dbg(ddev, "Setting CS8\n");
- break;
- default:
- dev_err(ddev, "CSIZE was set but not CS7-CS8\n");
- }
+ switch (cflag & CSIZE) {
+ case CS5:
+ dev_dbg(ddev, "Setting CS5 quirk\n");
+ break;
+ case CS7:
+ urb_value |= 7;
+ dev_dbg(ddev, "Setting CS7\n");
+ break;
+ default:
+ case CS8:
+ urb_value |= 8;
+ dev_dbg(ddev, "Setting CS8\n");
+ break;
}
/* This is needed by the break command since it uses the same command
@@ -2235,7 +2274,7 @@ no_data_parity_stop_changes:
dev_err(ddev, "%s urb failed to set baudrate\n", __func__);
mutex_unlock(&priv->cfg_lock);
/* Ensure RTS and DTR are raised when baudrate changed from 0 */
- if (!old_termios || (old_termios->c_cflag & CBAUD) == B0)
+ if (old_termios && (old_termios->c_cflag & CBAUD) == B0)
set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
}
@@ -2306,10 +2345,9 @@ no_c_cflag_changes:
* Returns the number of status bytes retrieved (device dependant), or
* negative error code.
*/
-static int ftdi_get_modem_status(struct tty_struct *tty,
+static int ftdi_get_modem_status(struct usb_serial_port *port,
unsigned char status[2])
{
- struct usb_serial_port *port = tty->driver_data;
struct ftdi_private *priv = usb_get_serial_port_data(port);
unsigned char *buf;
int len;
@@ -2374,7 +2412,7 @@ static int ftdi_tiocmget(struct tty_struct *tty)
unsigned char buf[2];
int ret;
- ret = ftdi_get_modem_status(tty, buf);
+ ret = ftdi_get_modem_status(port, buf);
if (ret < 0)
return ret;
@@ -2395,36 +2433,10 @@ static int ftdi_tiocmset(struct tty_struct *tty,
return update_mctrl(port, set, clear);
}
-static int ftdi_get_icount(struct tty_struct *tty,
- struct serial_icounter_struct *icount)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct ftdi_private *priv = usb_get_serial_port_data(port);
- struct async_icount *ic = &priv->icount;
-
- icount->cts = ic->cts;
- icount->dsr = ic->dsr;
- icount->rng = ic->rng;
- icount->dcd = ic->dcd;
- icount->tx = ic->tx;
- icount->rx = ic->rx;
- icount->frame = ic->frame;
- icount->parity = ic->parity;
- icount->overrun = ic->overrun;
- icount->brk = ic->brk;
- icount->buf_overrun = ic->buf_overrun;
- return 0;
-}
-
static int ftdi_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
struct usb_serial_port *port = tty->driver_data;
- struct ftdi_private *priv = usb_get_serial_port_data(port);
- struct async_icount cnow;
- struct async_icount cprev;
-
- dev_dbg(&port->dev, "%s cmd 0x%04x\n", __func__, cmd);
/* Based on code from acm.c and others */
switch (cmd) {
@@ -2436,79 +2448,21 @@ static int ftdi_ioctl(struct tty_struct *tty,
case TIOCSSERIAL: /* sets serial port data */
return set_serial_info(tty, port,
(struct serial_struct __user *) arg);
-
- /*
- * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
- * - mask passed in arg for lines of interest
- * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
- * Caller should use TIOCGICOUNT to see which one it was.
- *
- * This code is borrowed from linux/drivers/char/serial.c
- */
- case TIOCMIWAIT:
- cprev = priv->icount;
- while (!priv->dev_gone) {
- interruptible_sleep_on(&priv->delta_msr_wait);
- /* see if a signal did it */
- if (signal_pending(current))
- return -ERESTARTSYS;
- cnow = priv->icount;
- if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
- ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
- ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
- ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
- return 0;
- }
- cprev = cnow;
- }
- return -EIO;
- break;
case TIOCSERGETLSR:
return get_lsr_info(port, (struct serial_struct __user *)arg);
break;
default:
break;
}
- /* This is not necessarily an error - turns out the higher layers
- * will do some ioctls themselves (see comment above)
- */
- dev_dbg(&port->dev, "%s arg not supported - it was 0x%04x - check /usr/include/asm/ioctls.h\n",
- __func__, cmd);
- return -ENOIOCTLCMD;
-}
-
-static int __init ftdi_init(void)
-{
- if (vendor > 0 && product > 0) {
- /* Add user specified VID/PID to reserved element of table. */
- int i;
- for (i = 0; id_table_combined[i].idVendor; i++)
- ;
- id_table_combined[i].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
- id_table_combined[i].idVendor = vendor;
- id_table_combined[i].idProduct = product;
- }
- return usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, id_table_combined);
-}
-static void __exit ftdi_exit(void)
-{
- usb_serial_deregister_drivers(serial_drivers);
+ return -ENOIOCTLCMD;
}
-
-module_init(ftdi_init);
-module_exit(ftdi_exit);
+module_usb_serial_driver(serial_drivers, id_table_combined);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
-module_param(vendor, ushort, 0);
-MODULE_PARM_DESC(vendor, "User specified vendor ID (default="
- __MODULE_STRING(FTDI_VID)")");
-module_param(product, ushort, 0);
-MODULE_PARM_DESC(product, "User specified product ID");
-
module_param(ndi_latency_timer, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(ndi_latency_timer, "NDI device latency timer override");
diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h
index fa5d5603827..c4777bc6aee 100644
--- a/drivers/usb/serial/ftdi_sio_ids.h
+++ b/drivers/usb/serial/ftdi_sio_ids.h
@@ -50,6 +50,7 @@
#define TI_XDS100V2_PID 0xa6d0
#define FTDI_NXTCAM_PID 0xABB8 /* NXTCam for Mindstorms NXT */
+#define FTDI_EV3CON_PID 0xABB9 /* Mindstorms EV3 Console Adapter */
/* US Interface Navigator (http://www.usinterface.com/) */
#define FTDI_USINT_CAT_PID 0xb810 /* Navigator CAT and 2nd PTT lines */
@@ -74,6 +75,7 @@
#define FTDI_OPENDCC_THROTTLE_PID 0xBFDA
#define FTDI_OPENDCC_GATEWAY_PID 0xBFDB
#define FTDI_OPENDCC_GBM_PID 0xBFDC
+#define FTDI_OPENDCC_GBM_BOOST_PID 0xBFDD
/* NZR SEM 16+ USB (http://www.nzr.de) */
#define FTDI_NZR_SEM_USB_PID 0xC1E0 /* NZR SEM-LOG16+ */
@@ -147,6 +149,11 @@
#define XSENS_CONVERTER_6_PID 0xD38E
#define XSENS_CONVERTER_7_PID 0xD38F
+/**
+ * Zolix (www.zolix.com.cb) product ids
+ */
+#define FTDI_OMNI1509 0xD491 /* Omni1509 embedded USB-serial */
+
/*
* NDI (www.ndigital.com) product ids
*/
@@ -204,7 +211,7 @@
/*
* ELV USB devices submitted by Christian Abt of ELV (www.elv.de).
- * All of these devices use FTDI's vendor ID (0x0403).
+ * Almost all of these devices use FTDI's vendor ID (0x0403).
* Further IDs taken from ELV Windows .inf file.
*
* The previously included PID for the UO 100 module was incorrect.
@@ -212,6 +219,8 @@
*
* Armin Laeuger originally sent the PID for the UM 100 module.
*/
+#define FTDI_ELV_VID 0x1B1F /* ELV AG */
+#define FTDI_ELV_WS300_PID 0xC006 /* eQ3 WS 300 PC II */
#define FTDI_ELV_USR_PID 0xE000 /* ELV Universal-Sound-Recorder */
#define FTDI_ELV_MSM1_PID 0xE001 /* ELV Mini-Sound-Modul */
#define FTDI_ELV_KL100_PID 0xE002 /* ELV Kfz-Leistungsmesser KL 100 */
@@ -355,6 +364,12 @@
/* Sprog II (Andrew Crosland's SprogII DCC interface) */
#define FTDI_SPROG_II 0xF0C8
+/*
+ * Two of the Tagsys RFID Readers
+ */
+#define FTDI_TAGSYS_LP101_PID 0xF0E9 /* Tagsys L-P101 RFID*/
+#define FTDI_TAGSYS_P200X_PID 0xF0EE /* Tagsys Medio P200x RFID*/
+
/* an infrared receiver for user access control with IR tags */
#define FTDI_PIEGROUP_PID 0xF208 /* Product Id */
@@ -523,6 +538,11 @@
*/
#define FTDI_TIAO_UMPA_PID 0x8a98 /* TIAO/DIYGADGET USB Multi-Protocol Adapter */
+/*
+ * NovaTech product ids (FTDI_VID)
+ */
+#define FTDI_NT_ORIONLXM_PID 0x7c90 /* OrionLXm Substation Automation Platform */
+
/********************************/
/** third-party VID/PID combos **/
@@ -564,6 +584,12 @@
#define RATOC_PRODUCT_ID_USB60F 0xb020
/*
+ * Infineon Technologies
+ */
+#define INFINEON_VID 0x058b
+#define INFINEON_TRIBOARD_PID 0x0028 /* DAS JTAG TriBoard TC1798 V1.0 */
+
+/*
* Acton Research Corp.
*/
#define ACTON_VID 0x0647 /* Vendor ID */
@@ -577,6 +603,13 @@
#define CONTEC_COM1USBH_PID 0x8311 /* COM-1(USB)H */
/*
+ * Mitsubishi Electric Corp. (http://www.meau.com)
+ * Submitted by Konstantin Holoborodko
+ */
+#define MITSUBISHI_VID 0x06D3
+#define MITSUBISHI_FXUSB_PID 0x0284 /* USB/RS422 converters: FX-USB-AW/-BD */
+
+/*
* Definitions for B&B Electronics products.
*/
#define BANDB_VID 0x0856 /* B&B Electronics Vendor ID */
@@ -757,6 +790,8 @@
*/
#define NEWPORT_VID 0x104D
#define NEWPORT_AGILIS_PID 0x3000
+#define NEWPORT_CONEX_CC_PID 0x3002
+#define NEWPORT_CONEX_AGP_PID 0x3006
/* Interbiometrics USB I/O Board */
/* Developed for Interbiometrics by Rudolf Gugler */
@@ -769,7 +804,8 @@
* Submitted by Colin Leroy
*/
#define TESTO_VID 0x128D
-#define TESTO_USB_INTERFACE_PID 0x0001
+#define TESTO_1_PID 0x0001
+#define TESTO_3_PID 0x0003
/*
* Mobility Electronics products.
@@ -798,11 +834,35 @@
/*
* RT Systems programming cables for various ham radios
*/
-#define RTSYSTEMS_VID 0x2100 /* Vendor ID */
-#define RTSYSTEMS_SERIAL_VX7_PID 0x9e52 /* Serial converter for VX-7 Radios using FT232RL */
-#define RTSYSTEMS_CT29B_PID 0x9e54 /* CT29B Radio Cable */
-#define RTSYSTEMS_RTS01_PID 0x9e57 /* USB-RTS01 Radio Cable */
-
+#define RTSYSTEMS_VID 0x2100 /* Vendor ID */
+#define RTSYSTEMS_USB_S03_PID 0x9001 /* RTS-03 USB to Serial Adapter */
+#define RTSYSTEMS_USB_59_PID 0x9e50 /* USB-59 USB to 8 pin plug */
+#define RTSYSTEMS_USB_57A_PID 0x9e51 /* USB-57A USB to 4pin 3.5mm plug */
+#define RTSYSTEMS_USB_57B_PID 0x9e52 /* USB-57B USB to extended 4pin 3.5mm plug */
+#define RTSYSTEMS_USB_29A_PID 0x9e53 /* USB-29A USB to 3.5mm stereo plug */
+#define RTSYSTEMS_USB_29B_PID 0x9e54 /* USB-29B USB to 6 pin mini din */
+#define RTSYSTEMS_USB_29F_PID 0x9e55 /* USB-29F USB to 6 pin modular plug */
+#define RTSYSTEMS_USB_62B_PID 0x9e56 /* USB-62B USB to 8 pin mini din plug*/
+#define RTSYSTEMS_USB_S01_PID 0x9e57 /* USB-RTS01 USB to 3.5 mm stereo plug*/
+#define RTSYSTEMS_USB_63_PID 0x9e58 /* USB-63 USB to 9 pin female*/
+#define RTSYSTEMS_USB_29C_PID 0x9e59 /* USB-29C USB to 4 pin modular plug*/
+#define RTSYSTEMS_USB_81B_PID 0x9e5A /* USB-81 USB to 8 pin mini din plug*/
+#define RTSYSTEMS_USB_82B_PID 0x9e5B /* USB-82 USB to 2.5 mm stereo plug*/
+#define RTSYSTEMS_USB_K5D_PID 0x9e5C /* USB-K5D USB to 8 pin modular plug*/
+#define RTSYSTEMS_USB_K4Y_PID 0x9e5D /* USB-K4Y USB to 2.5/3.5 mm plugs*/
+#define RTSYSTEMS_USB_K5G_PID 0x9e5E /* USB-K5G USB to 8 pin modular plug*/
+#define RTSYSTEMS_USB_S05_PID 0x9e5F /* USB-RTS05 USB to 2.5 mm stereo plug*/
+#define RTSYSTEMS_USB_60_PID 0x9e60 /* USB-60 USB to 6 pin din*/
+#define RTSYSTEMS_USB_61_PID 0x9e61 /* USB-61 USB to 6 pin mini din*/
+#define RTSYSTEMS_USB_62_PID 0x9e62 /* USB-62 USB to 8 pin mini din*/
+#define RTSYSTEMS_USB_63B_PID 0x9e63 /* USB-63 USB to 9 pin female*/
+#define RTSYSTEMS_USB_64_PID 0x9e64 /* USB-64 USB to 9 pin male*/
+#define RTSYSTEMS_USB_65_PID 0x9e65 /* USB-65 USB to 9 pin female null modem*/
+#define RTSYSTEMS_USB_92_PID 0x9e66 /* USB-92 USB to 12 pin plug*/
+#define RTSYSTEMS_USB_92D_PID 0x9e67 /* USB-92D USB to 12 pin plug data*/
+#define RTSYSTEMS_USB_W5R_PID 0x9e68 /* USB-W5R USB to 8 pin modular plug*/
+#define RTSYSTEMS_USB_A5R_PID 0x9e69 /* USB-A5R USB to 8 pin modular plug*/
+#define RTSYSTEMS_USB_PW1_PID 0x9e6A /* USB-PW1 USB to 8 pin modular plug*/
/*
* Physik Instrumente
@@ -1136,7 +1196,8 @@
* STMicroelectonics
*/
#define ST_VID 0x0483
-#define ST_STMCLT1030_PID 0x3747 /* ST Micro Connect Lite STMCLT1030 */
+#define ST_STMCLT_2232_PID 0x3746
+#define ST_STMCLT_4232_PID 0x3747
/*
* Papouch products (http://www.papouch.com/)
@@ -1265,3 +1326,52 @@
* Manufacturer: Crucible Technologies
*/
#define FTDI_CT_COMET_PID 0x8e08
+
+/*
+ * Product: Z3X Box
+ * Manufacturer: Smart GSM Team
+ */
+#define FTDI_Z3X_PID 0x0011
+
+/*
+ * Product: Cressi PC Interface
+ * Manufacturer: Cressi
+ */
+#define FTDI_CRESSI_PID 0x87d0
+
+/*
+ * Brainboxes devices
+ */
+#define BRAINBOXES_VID 0x05d1
+#define BRAINBOXES_VX_001_PID 0x1001 /* VX-001 ExpressCard 1 Port RS232 */
+#define BRAINBOXES_VX_012_PID 0x1002 /* VX-012 ExpressCard 2 Port RS232 */
+#define BRAINBOXES_VX_023_PID 0x1003 /* VX-023 ExpressCard 1 Port RS422/485 */
+#define BRAINBOXES_VX_034_PID 0x1004 /* VX-034 ExpressCard 2 Port RS422/485 */
+#define BRAINBOXES_US_101_PID 0x1011 /* US-101 1xRS232 */
+#define BRAINBOXES_US_324_PID 0x1013 /* US-324 1xRS422/485 1Mbaud */
+#define BRAINBOXES_US_606_1_PID 0x2001 /* US-606 6 Port RS232 Serial Port 1 and 2 */
+#define BRAINBOXES_US_606_2_PID 0x2002 /* US-606 6 Port RS232 Serial Port 3 and 4 */
+#define BRAINBOXES_US_606_3_PID 0x2003 /* US-606 6 Port RS232 Serial Port 4 and 6 */
+#define BRAINBOXES_US_701_1_PID 0x2011 /* US-701 4xRS232 1Mbaud Port 1 and 2 */
+#define BRAINBOXES_US_701_2_PID 0x2012 /* US-701 4xRS422 1Mbaud Port 3 and 4 */
+#define BRAINBOXES_US_279_1_PID 0x2021 /* US-279 8xRS422 1Mbaud Port 1 and 2 */
+#define BRAINBOXES_US_279_2_PID 0x2022 /* US-279 8xRS422 1Mbaud Port 3 and 4 */
+#define BRAINBOXES_US_279_3_PID 0x2023 /* US-279 8xRS422 1Mbaud Port 5 and 6 */
+#define BRAINBOXES_US_279_4_PID 0x2024 /* US-279 8xRS422 1Mbaud Port 7 and 8 */
+#define BRAINBOXES_US_346_1_PID 0x3011 /* US-346 4xRS422/485 1Mbaud Port 1 and 2 */
+#define BRAINBOXES_US_346_2_PID 0x3012 /* US-346 4xRS422/485 1Mbaud Port 3 and 4 */
+#define BRAINBOXES_US_257_PID 0x5001 /* US-257 2xRS232 1Mbaud */
+#define BRAINBOXES_US_313_PID 0x6001 /* US-313 2xRS422/485 1Mbaud */
+#define BRAINBOXES_US_357_PID 0x7001 /* US_357 1xRS232/422/485 */
+#define BRAINBOXES_US_842_1_PID 0x8001 /* US-842 8xRS422/485 1Mbaud Port 1 and 2 */
+#define BRAINBOXES_US_842_2_PID 0x8002 /* US-842 8xRS422/485 1Mbaud Port 3 and 4 */
+#define BRAINBOXES_US_842_3_PID 0x8003 /* US-842 8xRS422/485 1Mbaud Port 5 and 6 */
+#define BRAINBOXES_US_842_4_PID 0x8004 /* US-842 8xRS422/485 1Mbaud Port 7 and 8 */
+#define BRAINBOXES_US_160_1_PID 0x9001 /* US-160 16xRS232 1Mbaud Port 1 and 2 */
+#define BRAINBOXES_US_160_2_PID 0x9002 /* US-160 16xRS232 1Mbaud Port 3 and 4 */
+#define BRAINBOXES_US_160_3_PID 0x9003 /* US-160 16xRS232 1Mbaud Port 5 and 6 */
+#define BRAINBOXES_US_160_4_PID 0x9004 /* US-160 16xRS232 1Mbaud Port 7 and 8 */
+#define BRAINBOXES_US_160_5_PID 0x9005 /* US-160 16xRS232 1Mbaud Port 9 and 10 */
+#define BRAINBOXES_US_160_6_PID 0x9006 /* US-160 16xRS232 1Mbaud Port 11 and 12 */
+#define BRAINBOXES_US_160_7_PID 0x9007 /* US-160 16xRS232 1Mbaud Port 13 and 14 */
+#define BRAINBOXES_US_160_8_PID 0x9008 /* US-160 16xRS232 1Mbaud Port 15 and 16 */
diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c
deleted file mode 100644
index 9362f8fd238..00000000000
--- a/drivers/usb/serial/funsoft.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Funsoft Serial USB driver
- *
- * Copyright (C) 2006 Greg Kroah-Hartman <gregkh@suse.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/tty.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/usb/serial.h>
-#include <linux/uaccess.h>
-
-static const struct usb_device_id id_table[] = {
- { USB_DEVICE(0x1404, 0xcddc) },
- { },
-};
-MODULE_DEVICE_TABLE(usb, id_table);
-
-static struct usb_serial_driver funsoft_device = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "funsoft",
- },
- .id_table = id_table,
- .num_ports = 1,
-};
-
-static struct usb_serial_driver * const serial_drivers[] = {
- &funsoft_device, NULL
-};
-
-module_usb_serial_driver(serial_drivers, id_table);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c
index 203358d7e7b..db591d19d41 100644
--- a/drivers/usb/serial/garmin_gps.c
+++ b/drivers/usb/serial/garmin_gps.c
@@ -25,7 +25,6 @@
#include <linux/kernel.h>
#include <linux/errno.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/timer.h>
#include <linux/tty.h>
@@ -252,14 +251,11 @@ static inline int isAbortTrfCmnd(const unsigned char *buf)
static void send_to_tty(struct usb_serial_port *port,
char *data, unsigned int actual_length)
{
- struct tty_struct *tty = tty_port_tty_get(&port->port);
-
- if (tty && actual_length) {
+ if (actual_length) {
usb_serial_debug_data(&port->dev, __func__, actual_length, data);
- tty_insert_flip_string(tty, data, actual_length);
- tty_flip_buffer_push(tty);
+ tty_insert_flip_string(&port->port, data, actual_length);
+ tty_flip_buffer_push(&port->port);
}
- tty_kref_put(tty);
}
@@ -278,14 +274,13 @@ static int pkt_add(struct garmin_data *garmin_data_p,
unsigned long flags;
struct garmin_packet *pkt;
- /* process only packets containg data ... */
+ /* process only packets containing data ... */
if (data_length) {
pkt = kmalloc(sizeof(struct garmin_packet)+data_length,
GFP_ATOMIC);
- if (pkt == NULL) {
- dev_err(&garmin_data_p->port->dev, "out of memory\n");
+ if (!pkt)
return 0;
- }
+
pkt->size = data_length;
memcpy(pkt->data, data, data_length);
@@ -949,20 +944,13 @@ static int garmin_open(struct tty_struct *tty, struct usb_serial_port *port)
static void garmin_close(struct usb_serial_port *port)
{
- struct usb_serial *serial = port->serial;
struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);
- dev_dbg(&port->dev, "%s - port %d - mode=%d state=%d flags=0x%X\n",
- __func__, port->number, garmin_data_p->mode,
- garmin_data_p->state, garmin_data_p->flags);
-
- if (!serial)
- return;
-
- mutex_lock(&port->serial->disc_mutex);
+ dev_dbg(&port->dev, "%s - mode=%d state=%d flags=0x%X\n",
+ __func__, garmin_data_p->mode, garmin_data_p->state,
+ garmin_data_p->flags);
- if (!port->serial->disconnected)
- garmin_clear(garmin_data_p);
+ garmin_clear(garmin_data_p);
/* shutdown our urbs */
usb_kill_urb(port->read_urb);
@@ -971,8 +959,6 @@ static void garmin_close(struct usb_serial_port *port)
/* keep reset state so we know that we must start a new session */
if (garmin_data_p->state != STATE_RESET)
garmin_data_p->state = STATE_DISCONNECTED;
-
- mutex_unlock(&port->serial->disc_mutex);
}
@@ -1018,14 +1004,11 @@ static int garmin_write_bulk(struct usb_serial_port *port,
spin_unlock_irqrestore(&garmin_data_p->lock, flags);
buffer = kmalloc(count, GFP_ATOMIC);
- if (!buffer) {
- dev_err(&port->dev, "out of memory\n");
+ if (!buffer)
return -ENOMEM;
- }
urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) {
- dev_err(&port->dev, "no more free urbs\n");
kfree(buffer);
return -ENOMEM;
}
@@ -1160,7 +1143,7 @@ static void garmin_read_process(struct garmin_data *garmin_data_p,
unsigned long flags;
if (garmin_data_p->flags & FLAGS_DROP_DATA) {
- /* abort-transfer cmd is actice */
+ /* abort-transfer cmd is active */
dev_dbg(&garmin_data_p->port->dev, "%s - pkt dropped\n", __func__);
} else if (garmin_data_p->state != STATE_DISCONNECTED &&
garmin_data_p->state != STATE_RESET) {
@@ -1193,17 +1176,11 @@ static void garmin_read_bulk_callback(struct urb *urb)
{
unsigned long flags;
struct usb_serial_port *port = urb->context;
- struct usb_serial *serial = port->serial;
struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);
unsigned char *data = urb->transfer_buffer;
int status = urb->status;
int retval;
- if (!serial) {
- dev_dbg(&urb->dev->dev, "%s - bad serial pointer, exiting\n", __func__);
- return;
- }
-
if (status) {
dev_dbg(&urb->dev->dev, "%s - nonzero read bulk status received: %d\n",
__func__, status);
@@ -1411,10 +1388,9 @@ static int garmin_port_probe(struct usb_serial_port *port)
struct garmin_data *garmin_data_p;
garmin_data_p = kzalloc(sizeof(struct garmin_data), GFP_KERNEL);
- if (garmin_data_p == NULL) {
- dev_err(&port->dev, "%s - Out of memory\n", __func__);
+ if (!garmin_data_p)
return -ENOMEM;
- }
+
init_timer(&garmin_data_p->timer);
spin_lock_init(&garmin_data_p->lock);
INIT_LIST_HEAD(&garmin_data_p->pktlist);
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index 2ea70a63199..1bd192290b0 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -1,13 +1,12 @@
/*
* USB Serial Converter Generic functions
*
- * Copyright (C) 2010 - 2011 Johan Hovold (jhovold@gmail.com)
+ * Copyright (C) 2010 - 2013 Johan Hovold (jhovold@gmail.com)
* Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 as published by the Free Software Foundation.
- *
*/
#include <linux/kernel.h>
@@ -37,7 +36,6 @@ MODULE_PARM_DESC(product, "User specified USB idProduct");
static struct usb_device_id generic_device_ids[2]; /* Initially all zeroes. */
-/* All of the device info needed for the Generic Serial Converter */
struct usb_serial_driver usb_serial_generic_device = {
.driver = {
.owner = THIS_MODULE,
@@ -45,8 +43,6 @@ struct usb_serial_driver usb_serial_generic_device = {
},
.id_table = generic_device_ids,
.num_ports = 1,
- .disconnect = usb_serial_generic_disconnect,
- .release = usb_serial_generic_release,
.throttle = usb_serial_generic_throttle,
.unthrottle = usb_serial_generic_unthrottle,
.resume = usb_serial_generic_resume,
@@ -68,7 +64,6 @@ int usb_serial_generic_register(void)
generic_device_ids[0].match_flags =
USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT;
- /* register our generic driver with ourselves */
retval = usb_serial_register_drivers(serial_drivers,
"usbserial_generic", generic_device_ids);
#endif
@@ -78,7 +73,6 @@ int usb_serial_generic_register(void)
void usb_serial_generic_deregister(void)
{
#ifdef CONFIG_USB_SERIAL_GENERIC
- /* remove our generic driver */
usb_serial_deregister_drivers(serial_drivers);
#endif
}
@@ -88,13 +82,11 @@ int usb_serial_generic_open(struct tty_struct *tty, struct usb_serial_port *port
int result = 0;
unsigned long flags;
- /* clear the throttle flags */
spin_lock_irqsave(&port->lock, flags);
port->throttled = 0;
port->throttle_req = 0;
spin_unlock_irqrestore(&port->lock, flags);
- /* if we have a bulk endpoint, start reading from it */
if (port->bulk_in_size)
result = usb_serial_generic_submit_read_urbs(port, GFP_KERNEL);
@@ -102,32 +94,23 @@ int usb_serial_generic_open(struct tty_struct *tty, struct usb_serial_port *port
}
EXPORT_SYMBOL_GPL(usb_serial_generic_open);
-static void generic_cleanup(struct usb_serial_port *port)
+void usb_serial_generic_close(struct usb_serial_port *port)
{
- struct usb_serial *serial = port->serial;
unsigned long flags;
int i;
- if (serial->dev) {
- /* shutdown any bulk transfers that might be going on */
- if (port->bulk_out_size) {
- for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i)
- usb_kill_urb(port->write_urbs[i]);
+ if (port->bulk_out_size) {
+ for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i)
+ usb_kill_urb(port->write_urbs[i]);
- spin_lock_irqsave(&port->lock, flags);
- kfifo_reset_out(&port->write_fifo);
- spin_unlock_irqrestore(&port->lock, flags);
- }
- if (port->bulk_in_size) {
- for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i)
- usb_kill_urb(port->read_urbs[i]);
- }
+ spin_lock_irqsave(&port->lock, flags);
+ kfifo_reset_out(&port->write_fifo);
+ spin_unlock_irqrestore(&port->lock, flags);
+ }
+ if (port->bulk_in_size) {
+ for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i)
+ usb_kill_urb(port->read_urbs[i]);
}
-}
-
-void usb_serial_generic_close(struct usb_serial_port *port)
-{
- generic_cleanup(port);
}
EXPORT_SYMBOL_GPL(usb_serial_generic_close);
@@ -138,12 +121,16 @@ int usb_serial_generic_prepare_write_buffer(struct usb_serial_port *port,
}
/**
- * usb_serial_generic_write_start - kick off an URB write
- * @port: Pointer to the &struct usb_serial_port data
+ * usb_serial_generic_write_start - start writing buffered data
+ * @port: usb-serial port
+ * @mem_flags: flags to use for memory allocations
*
- * Returns zero on success, or a negative errno value
+ * Serialised using USB_SERIAL_WRITE_BUSY flag.
+ *
+ * Return: Zero on success or if busy, otherwise a negative errno value.
*/
-static int usb_serial_generic_write_start(struct usb_serial_port *port)
+int usb_serial_generic_write_start(struct usb_serial_port *port,
+ gfp_t mem_flags)
{
struct urb *urb;
int count, result;
@@ -174,7 +161,7 @@ retry:
spin_unlock_irqrestore(&port->lock, flags);
clear_bit(i, &port->write_urbs_free);
- result = usb_submit_urb(urb, GFP_ATOMIC);
+ result = usb_submit_urb(urb, mem_flags);
if (result) {
dev_err_console(port, "%s - error submitting urb: %d\n",
__func__, result);
@@ -187,33 +174,25 @@ retry:
return result;
}
- /* Try sending off another urb, unless in irq context (in which case
- * there will be no free urb). */
- if (!in_irq())
- goto retry;
-
- clear_bit_unlock(USB_SERIAL_WRITE_BUSY, &port->flags);
-
- return 0;
+ goto retry; /* try sending off another urb */
}
+EXPORT_SYMBOL_GPL(usb_serial_generic_write_start);
/**
- * usb_serial_generic_write - generic write function for serial USB devices
- * @tty: Pointer to &struct tty_struct for the device
- * @port: Pointer to the &usb_serial_port structure for the device
- * @buf: Pointer to the data to write
- * @count: Number of bytes to write
+ * usb_serial_generic_write - generic write function
+ * @tty: tty for the port
+ * @port: usb-serial port
+ * @buf: data to write
+ * @count: number of bytes to write
*
- * Returns the number of characters actually written, which may be anything
- * from zero to @count. If an error occurs, it returns the negative errno
- * value.
+ * Return: The number of characters buffered, which may be anything from
+ * zero to @count, or a negative errno value.
*/
int usb_serial_generic_write(struct tty_struct *tty,
struct usb_serial_port *port, const unsigned char *buf, int count)
{
int result;
- /* only do something if we have a bulk out endpoint */
if (!port->bulk_out_size)
return -ENODEV;
@@ -221,7 +200,7 @@ int usb_serial_generic_write(struct tty_struct *tty,
return 0;
count = kfifo_in_locked(&port->write_fifo, buf, count, &port->lock);
- result = usb_serial_generic_write_start(port);
+ result = usb_serial_generic_write_start(port, GFP_ATOMIC);
if (result)
return result;
@@ -264,6 +243,37 @@ int usb_serial_generic_chars_in_buffer(struct tty_struct *tty)
}
EXPORT_SYMBOL_GPL(usb_serial_generic_chars_in_buffer);
+void usb_serial_generic_wait_until_sent(struct tty_struct *tty, long timeout)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ unsigned int bps;
+ unsigned long period;
+ unsigned long expire;
+
+ bps = tty_get_baud_rate(tty);
+ if (!bps)
+ bps = 9600; /* B0 */
+ /*
+ * Use a poll-period of roughly the time it takes to send one
+ * character or at least one jiffy.
+ */
+ period = max_t(unsigned long, (10 * HZ / bps), 1);
+ period = min_t(unsigned long, period, timeout);
+
+ dev_dbg(&port->dev, "%s - timeout = %u ms, period = %u ms\n",
+ __func__, jiffies_to_msecs(timeout),
+ jiffies_to_msecs(period));
+ expire = jiffies + timeout;
+ while (!port->serial->type->tx_empty(port)) {
+ schedule_timeout_interruptible(period);
+ if (signal_pending(current))
+ break;
+ if (time_after(jiffies, expire))
+ break;
+ }
+}
+EXPORT_SYMBOL_GPL(usb_serial_generic_wait_until_sent);
+
static int usb_serial_generic_submit_read_urb(struct usb_serial_port *port,
int index, gfp_t mem_flags)
{
@@ -272,8 +282,7 @@ static int usb_serial_generic_submit_read_urb(struct usb_serial_port *port,
if (!test_and_clear_bit(index, &port->read_urbs_free))
return 0;
- dev_dbg(&port->dev, "%s - port %d, urb %d\n", __func__,
- port->number, index);
+ dev_dbg(&port->dev, "%s - urb %d\n", __func__, index);
res = usb_submit_urb(port->read_urbs[index], mem_flags);
if (res) {
@@ -313,30 +322,25 @@ EXPORT_SYMBOL_GPL(usb_serial_generic_submit_read_urbs);
void usb_serial_generic_process_read_urb(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
- struct tty_struct *tty;
char *ch = (char *)urb->transfer_buffer;
int i;
if (!urb->actual_length)
return;
-
- tty = tty_port_tty_get(&port->port);
- if (!tty)
- return;
-
- /* The per character mucking around with sysrq path it too slow for
- stuff like 3G modems, so shortcircuit it in the 99.9999999% of cases
- where the USB serial is not a console anyway */
- if (!port->port.console || !port->sysrq)
- tty_insert_flip_string(tty, ch, urb->actual_length);
- else {
+ /*
+ * The per character mucking around with sysrq path it too slow for
+ * stuff like 3G modems, so shortcircuit it in the 99.9999999% of
+ * cases where the USB serial is not a console anyway.
+ */
+ if (!port->port.console || !port->sysrq) {
+ tty_insert_flip_string(&port->port, ch, urb->actual_length);
+ } else {
for (i = 0; i < urb->actual_length; i++, ch++) {
if (!usb_serial_handle_sysrq_char(port, *ch))
- tty_insert_flip_char(tty, *ch, TTY_NORMAL);
+ tty_insert_flip_char(&port->port, *ch, TTY_NORMAL);
}
}
- tty_flip_buffer_push(tty);
- tty_kref_put(tty);
+ tty_flip_buffer_push(&port->port);
}
EXPORT_SYMBOL_GPL(usb_serial_generic_process_read_urb);
@@ -353,26 +357,40 @@ void usb_serial_generic_read_bulk_callback(struct urb *urb)
}
set_bit(i, &port->read_urbs_free);
- dev_dbg(&port->dev, "%s - port %d, urb %d, len %d\n",
- __func__, port->number, i, urb->actual_length);
-
- if (urb->status) {
- dev_dbg(&port->dev, "%s - non-zero urb status: %d\n",
- __func__, urb->status);
+ dev_dbg(&port->dev, "%s - urb %d, len %d\n", __func__, i,
+ urb->actual_length);
+ switch (urb->status) {
+ case 0:
+ break;
+ case -ENOENT:
+ case -ECONNRESET:
+ case -ESHUTDOWN:
+ dev_dbg(&port->dev, "%s - urb stopped: %d\n",
+ __func__, urb->status);
+ return;
+ case -EPIPE:
+ dev_err(&port->dev, "%s - urb stopped: %d\n",
+ __func__, urb->status);
return;
+ default:
+ dev_err(&port->dev, "%s - nonzero urb status: %d\n",
+ __func__, urb->status);
+ goto resubmit;
}
usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data);
port->serial->type->process_read_urb(urb);
+resubmit:
/* Throttle the device if requested by tty */
spin_lock_irqsave(&port->lock, flags);
port->throttled = port->throttle_req;
if (!port->throttled) {
spin_unlock_irqrestore(&port->lock, flags);
usb_serial_generic_submit_read_urb(port, i, GFP_ATOMIC);
- } else
+ } else {
spin_unlock_irqrestore(&port->lock, flags);
+ }
}
EXPORT_SYMBOL_GPL(usb_serial_generic_read_bulk_callback);
@@ -380,29 +398,38 @@ void usb_serial_generic_write_bulk_callback(struct urb *urb)
{
unsigned long flags;
struct usb_serial_port *port = urb->context;
- int status = urb->status;
int i;
- for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i)
+ for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) {
if (port->write_urbs[i] == urb)
break;
-
+ }
spin_lock_irqsave(&port->lock, flags);
port->tx_bytes -= urb->transfer_buffer_length;
set_bit(i, &port->write_urbs_free);
spin_unlock_irqrestore(&port->lock, flags);
- if (status) {
- dev_dbg(&port->dev, "%s - non-zero urb status: %d\n",
- __func__, status);
-
- spin_lock_irqsave(&port->lock, flags);
- kfifo_reset_out(&port->write_fifo);
- spin_unlock_irqrestore(&port->lock, flags);
- } else {
- usb_serial_generic_write_start(port);
+ switch (urb->status) {
+ case 0:
+ break;
+ case -ENOENT:
+ case -ECONNRESET:
+ case -ESHUTDOWN:
+ dev_dbg(&port->dev, "%s - urb stopped: %d\n",
+ __func__, urb->status);
+ return;
+ case -EPIPE:
+ dev_err_console(port, "%s - urb stopped: %d\n",
+ __func__, urb->status);
+ return;
+ default:
+ dev_err_console(port, "%s - nonzero urb status: %d\n",
+ __func__, urb->status);
+ goto resubmit;
}
+resubmit:
+ usb_serial_generic_write_start(port, GFP_ATOMIC);
usb_serial_port_softint(port);
}
EXPORT_SYMBOL_GPL(usb_serial_generic_write_bulk_callback);
@@ -412,8 +439,6 @@ void usb_serial_generic_throttle(struct tty_struct *tty)
struct usb_serial_port *port = tty->driver_data;
unsigned long flags;
- /* Set the throttle request flag. It will be picked up
- * by usb_serial_generic_read_bulk_callback(). */
spin_lock_irqsave(&port->lock, flags);
port->throttle_req = 1;
spin_unlock_irqrestore(&port->lock, flags);
@@ -425,7 +450,6 @@ void usb_serial_generic_unthrottle(struct tty_struct *tty)
struct usb_serial_port *port = tty->driver_data;
int was_throttled;
- /* Clear the throttle flags */
spin_lock_irq(&port->lock);
was_throttled = port->throttled;
port->throttled = port->throttle_req = 0;
@@ -436,6 +460,82 @@ void usb_serial_generic_unthrottle(struct tty_struct *tty)
}
EXPORT_SYMBOL_GPL(usb_serial_generic_unthrottle);
+static bool usb_serial_generic_msr_changed(struct tty_struct *tty,
+ unsigned long arg, struct async_icount *cprev)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ struct async_icount cnow;
+ unsigned long flags;
+ bool ret;
+
+ /*
+ * Use tty-port initialised flag to detect all hangups including the
+ * one generated at USB-device disconnect.
+ */
+ if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags))
+ return true;
+
+ spin_lock_irqsave(&port->lock, flags);
+ cnow = port->icount; /* atomic copy*/
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ ret = ((arg & TIOCM_RNG) && (cnow.rng != cprev->rng)) ||
+ ((arg & TIOCM_DSR) && (cnow.dsr != cprev->dsr)) ||
+ ((arg & TIOCM_CD) && (cnow.dcd != cprev->dcd)) ||
+ ((arg & TIOCM_CTS) && (cnow.cts != cprev->cts));
+
+ *cprev = cnow;
+
+ return ret;
+}
+
+int usb_serial_generic_tiocmiwait(struct tty_struct *tty, unsigned long arg)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ struct async_icount cnow;
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&port->lock, flags);
+ cnow = port->icount; /* atomic copy */
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ ret = wait_event_interruptible(port->port.delta_msr_wait,
+ usb_serial_generic_msr_changed(tty, arg, &cnow));
+ if (!ret && !test_bit(ASYNCB_INITIALIZED, &port->port.flags))
+ ret = -EIO;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(usb_serial_generic_tiocmiwait);
+
+int usb_serial_generic_get_icount(struct tty_struct *tty,
+ struct serial_icounter_struct *icount)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ struct async_icount cnow;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+ cnow = port->icount; /* atomic copy */
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ icount->cts = cnow.cts;
+ icount->dsr = cnow.dsr;
+ icount->rng = cnow.rng;
+ icount->dcd = cnow.dcd;
+ icount->tx = cnow.tx;
+ icount->rx = cnow.rx;
+ icount->frame = cnow.frame;
+ icount->parity = cnow.parity;
+ icount->overrun = cnow.overrun;
+ icount->brk = cnow.brk;
+ icount->buf_overrun = cnow.buf_overrun;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(usb_serial_generic_get_icount);
+
#ifdef CONFIG_MAGIC_SYSRQ
int usb_serial_handle_sysrq_char(struct usb_serial_port *port, unsigned int ch)
{
@@ -469,18 +569,27 @@ int usb_serial_handle_break(struct usb_serial_port *port)
EXPORT_SYMBOL_GPL(usb_serial_handle_break);
/**
- * usb_serial_handle_dcd_change - handle a change of carrier detect state
- * @port: usb_serial_port structure for the open port
- * @tty: tty_struct structure for the port
- * @status: new carrier detect status, nonzero if active
+ * usb_serial_handle_dcd_change - handle a change of carrier detect state
+ * @port: usb-serial port
+ * @tty: tty for the port
+ * @status: new carrier detect status, nonzero if active
*/
void usb_serial_handle_dcd_change(struct usb_serial_port *usb_port,
struct tty_struct *tty, unsigned int status)
{
struct tty_port *port = &usb_port->port;
- dev_dbg(&usb_port->dev, "%s - port %d, status %d\n", __func__,
- usb_port->number, status);
+ dev_dbg(&usb_port->dev, "%s - status %d\n", __func__, status);
+
+ if (tty) {
+ struct tty_ldisc *ld = tty_ldisc_ref(tty);
+
+ if (ld) {
+ if (ld->ops->dcd_change)
+ ld->ops->dcd_change(tty, status);
+ tty_ldisc_deref(ld);
+ }
+ }
if (status)
wake_up_interruptible(&port->open_wait);
@@ -507,7 +616,7 @@ int usb_serial_generic_resume(struct usb_serial *serial)
}
if (port->bulk_out_size) {
- r = usb_serial_generic_write_start(port);
+ r = usb_serial_generic_write_start(port, GFP_NOIO);
if (r < 0)
c++;
}
@@ -516,17 +625,3 @@ int usb_serial_generic_resume(struct usb_serial *serial)
return c ? -EIO : 0;
}
EXPORT_SYMBOL_GPL(usb_serial_generic_resume);
-
-void usb_serial_generic_disconnect(struct usb_serial *serial)
-{
- int i;
-
- /* stop reads and writes on all ports */
- for (i = 0; i < serial->num_ports; ++i)
- generic_cleanup(serial->port[i]);
-}
-EXPORT_SYMBOL_GPL(usb_serial_generic_disconnect);
-
-void usb_serial_generic_release(struct usb_serial *serial)
-{
-}
diff --git a/drivers/usb/serial/hp4x.c b/drivers/usb/serial/hp4x.c
deleted file mode 100644
index 2cba60d90c7..00000000000
--- a/drivers/usb/serial/hp4x.c
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * HP4x Calculators Serial USB driver
- *
- * Copyright (C) 2005 Arthur Huillet (ahuillet@users.sf.net)
- * Copyright (C) 2001-2005 Greg Kroah-Hartman (greg@kroah.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * See Documentation/usb/usb-serial.txt for more information on using this
- * driver
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/tty.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/usb/serial.h>
-
-#define DRIVER_DESC "HP4x (48/49) Generic Serial driver"
-
-#define HP_VENDOR_ID 0x03f0
-#define HP49GP_PRODUCT_ID 0x0121
-
-static const struct usb_device_id id_table[] = {
- { USB_DEVICE(HP_VENDOR_ID, HP49GP_PRODUCT_ID) },
- { } /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE(usb, id_table);
-
-static struct usb_serial_driver hp49gp_device = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "hp4X",
- },
- .id_table = id_table,
- .num_ports = 1,
-};
-
-static struct usb_serial_driver * const serial_drivers[] = {
- &hp49gp_device, NULL
-};
-
-module_usb_serial_driver(serial_drivers, id_table);
-
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index 7b770c7f8b1..c0866971db2 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -32,7 +32,6 @@
#include <linux/kernel.h>
#include <linux/jiffies.h>
#include <linux/errno.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
@@ -56,9 +55,7 @@
#define MAX_NAME_LEN 64
-#define CHASE_TIMEOUT (5*HZ) /* 5 seconds */
#define OPEN_TIMEOUT (5*HZ) /* 5 seconds */
-#define COMMAND_TIMEOUT (5*HZ) /* 5 seconds */
/* receive port state */
enum RXSTATE {
@@ -110,9 +107,7 @@ struct edgeport_port {
wait_queue_head_t wait_chase; /* for handling sleeping while waiting for chase to finish */
wait_queue_head_t wait_open; /* for handling sleeping while waiting for open to finish */
wait_queue_head_t wait_command; /* for handling sleeping while waiting for command to finish */
- wait_queue_head_t delta_msr_wait; /* for handling sleeping while waiting for msr change to happen */
- struct async_icount icount;
struct usb_serial_port *port; /* loop back to the owner of this object */
};
@@ -216,8 +211,6 @@ static void edge_break(struct tty_struct *tty, int break_state);
static int edge_tiocmget(struct tty_struct *tty);
static int edge_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear);
-static int edge_get_icount(struct tty_struct *tty,
- struct serial_icounter_struct *icount);
static int edge_startup(struct usb_serial *serial);
static void edge_disconnect(struct usb_serial *serial);
static void edge_release(struct usb_serial *serial);
@@ -232,8 +225,8 @@ static void process_rcvd_data(struct edgeport_serial *edge_serial,
unsigned char *buffer, __u16 bufferLength);
static void process_rcvd_status(struct edgeport_serial *edge_serial,
__u8 byte2, __u8 byte3);
-static void edge_tty_recv(struct device *dev, struct tty_struct *tty,
- unsigned char *data, int length);
+static void edge_tty_recv(struct usb_serial_port *port, unsigned char *data,
+ int length);
static void handle_new_msr(struct edgeport_port *edge_port, __u8 newMsr);
static void handle_new_lsr(struct edgeport_port *edge_port, __u8 lsrData,
__u8 lsr, __u8 data);
@@ -565,7 +558,6 @@ static void edge_interrupt_callback(struct urb *urb)
struct device *dev;
struct edgeport_port *edge_port;
struct usb_serial_port *port;
- struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
int length = urb->actual_length;
int bytes_avail;
@@ -644,12 +636,7 @@ static void edge_interrupt_callback(struct urb *urb)
/* tell the tty driver that something
has changed */
- tty = tty_port_tty_get(
- &edge_port->port->port);
- if (tty) {
- tty_wakeup(tty);
- tty_kref_put(tty);
- }
+ tty_port_tty_wakeup(&edge_port->port->port);
/* Since we have more credit, check
if more data can be sent */
send_more_port_data(edge_serial,
@@ -738,7 +725,6 @@ static void edge_bulk_in_callback(struct urb *urb)
static void edge_bulk_out_data_callback(struct urb *urb)
{
struct edgeport_port *edge_port = urb->context;
- struct tty_struct *tty;
int status = urb->status;
if (status) {
@@ -747,14 +733,8 @@ static void edge_bulk_out_data_callback(struct urb *urb)
__func__, status);
}
- tty = tty_port_tty_get(&edge_port->port->port);
-
- if (tty && edge_port->open) {
- /* let the tty driver wakeup if it has a special
- write_wakeup function */
- tty_wakeup(tty);
- }
- tty_kref_put(tty);
+ if (edge_port->open)
+ tty_port_tty_wakeup(&edge_port->port->port);
/* Release the Write URB */
edge_port->write_in_progress = false;
@@ -773,7 +753,6 @@ static void edge_bulk_out_data_callback(struct urb *urb)
static void edge_bulk_out_cmd_callback(struct urb *urb)
{
struct edgeport_port *edge_port = urb->context;
- struct tty_struct *tty;
int status = urb->status;
atomic_dec(&CmdUrbs);
@@ -794,13 +773,9 @@ static void edge_bulk_out_cmd_callback(struct urb *urb)
return;
}
- /* Get pointer to tty */
- tty = tty_port_tty_get(&edge_port->port->port);
-
/* tell the tty driver that something has changed */
- if (tty && edge_port->open)
- tty_wakeup(tty);
- tty_kref_put(tty);
+ if (edge_port->open)
+ tty_port_tty_wakeup(&edge_port->port->port);
/* we have completed the command */
edge_port->commandPending = false;
@@ -884,12 +859,8 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port)
/* initialize our wait queues */
init_waitqueue_head(&edge_port->wait_open);
init_waitqueue_head(&edge_port->wait_chase);
- init_waitqueue_head(&edge_port->delta_msr_wait);
init_waitqueue_head(&edge_port->wait_command);
- /* initialize our icount structure */
- memset(&(edge_port->icount), 0x00, sizeof(edge_port->icount));
-
/* initialize our port settings */
edge_port->txCredits = 0; /* Can't send any data yet */
/* Must always set this bit to enable ints! */
@@ -926,7 +897,6 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port)
edge_port->txfifo.fifo = kmalloc(edge_port->maxTxCredits, GFP_KERNEL);
if (!edge_port->txfifo.fifo) {
- dev_dbg(dev, "%s - no memory\n", __func__);
edge_close(port);
return -ENOMEM;
}
@@ -936,13 +906,12 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port)
edge_port->write_in_progress = false;
if (!edge_port->write_urb) {
- dev_dbg(dev, "%s - no memory\n", __func__);
edge_close(port);
return -ENOMEM;
}
- dev_dbg(dev, "%s(%d) - Initialize TX fifo to %d bytes\n",
- __func__, port->number, edge_port->maxTxCredits);
+ dev_dbg(dev, "%s - Initialize TX fifo to %d bytes\n",
+ __func__, edge_port->maxTxCredits);
return 0;
}
@@ -1148,9 +1117,8 @@ static int edge_write(struct tty_struct *tty, struct usb_serial_port *port,
copySize = min((unsigned int)count,
(edge_port->txCredits - fifo->count));
- dev_dbg(&port->dev, "%s(%d) of %d byte(s) Fifo room %d -- will copy %d bytes\n",
- __func__, port->number, count,
- edge_port->txCredits - fifo->count, copySize);
+ dev_dbg(&port->dev, "%s of %d byte(s) Fifo room %d -- will copy %d bytes\n",
+ __func__, count, edge_port->txCredits - fifo->count, copySize);
/* catch writes of 0 bytes which the tty driver likes to give us,
and when txCredits is empty */
@@ -1242,9 +1210,8 @@ static void send_more_port_data(struct edgeport_serial *edge_serial,
if (edge_port->write_in_progress ||
!edge_port->open ||
(fifo->count == 0)) {
- dev_dbg(dev, "%s(%d) EXIT - fifo %d, PendingWrite = %d\n",
- __func__, edge_port->port->number,
- fifo->count, edge_port->write_in_progress);
+ dev_dbg(dev, "%s EXIT - fifo %d, PendingWrite = %d\n",
+ __func__, fifo->count, edge_port->write_in_progress);
goto exit_send;
}
@@ -1256,9 +1223,8 @@ static void send_more_port_data(struct edgeport_serial *edge_serial,
* it's better to wait for more credits so we can do a larger write.
*/
if (edge_port->txCredits < EDGE_FW_GET_TX_CREDITS_SEND_THRESHOLD(edge_port->maxTxCredits, EDGE_FW_BULK_MAX_PACKET_SIZE)) {
- dev_dbg(dev, "%s(%d) Not enough credit - fifo %d TxCredit %d\n",
- __func__, edge_port->port->number, fifo->count,
- edge_port->txCredits);
+ dev_dbg(dev, "%s Not enough credit - fifo %d TxCredit %d\n",
+ __func__, fifo->count, edge_port->txCredits);
goto exit_send;
}
@@ -1276,16 +1242,12 @@ static void send_more_port_data(struct edgeport_serial *edge_serial,
to send out */
count = fifo->count;
buffer = kmalloc(count+2, GFP_ATOMIC);
- if (buffer == NULL) {
- dev_err_console(edge_port->port,
- "%s - no more kernel memory...\n", __func__);
+ if (!buffer) {
edge_port->write_in_progress = false;
goto exit_send;
}
- buffer[0] = IOSP_BUILD_DATA_HDR1(edge_port->port->number
- - edge_port->port->serial->minor, count);
- buffer[1] = IOSP_BUILD_DATA_HDR2(edge_port->port->number
- - edge_port->port->serial->minor, count);
+ buffer[0] = IOSP_BUILD_DATA_HDR1(edge_port->port->port_number, count);
+ buffer[1] = IOSP_BUILD_DATA_HDR2(edge_port->port->port_number, count);
/* now copy our data */
bytesleft = fifo->size - fifo->tail;
@@ -1316,7 +1278,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial,
/* decrement the number of credits we have by the number we just sent */
edge_port->txCredits -= count;
- edge_port->icount.tx += count;
+ edge_port->port->icount.tx += count;
status = usb_submit_urb(urb, GFP_ATOMIC);
if (status) {
@@ -1328,7 +1290,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial,
/* revert the credits as something bad happened. */
edge_port->txCredits += count;
- edge_port->icount.tx -= count;
+ edge_port->port->icount.tx -= count;
}
dev_dbg(dev, "%s wrote %d byte(s) TxCredit %d, Fifo %d\n",
__func__, count, edge_port->txCredits, fifo->count);
@@ -1403,8 +1365,7 @@ static int edge_chars_in_buffer(struct tty_struct *tty)
edge_port->txfifo.count;
spin_unlock_irqrestore(&edge_port->ep_lock, flags);
if (num_chars) {
- dev_dbg(&port->dev, "%s(port %d) - returns %d\n", __func__,
- port->number, num_chars);
+ dev_dbg(&port->dev, "%s - returns %d\n", __func__, num_chars);
}
return num_chars;
@@ -1590,31 +1551,6 @@ static int edge_tiocmget(struct tty_struct *tty)
return result;
}
-static int edge_get_icount(struct tty_struct *tty,
- struct serial_icounter_struct *icount)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct edgeport_port *edge_port = usb_get_serial_port_data(port);
- struct async_icount cnow;
- cnow = edge_port->icount;
-
- icount->cts = cnow.cts;
- icount->dsr = cnow.dsr;
- icount->rng = cnow.rng;
- icount->dcd = cnow.dcd;
- icount->rx = cnow.rx;
- icount->tx = cnow.tx;
- icount->frame = cnow.frame;
- icount->overrun = cnow.overrun;
- icount->parity = cnow.parity;
- icount->brk = cnow.brk;
- icount->buf_overrun = cnow.buf_overrun;
-
- dev_dbg(&port->dev, "%s (%d) TIOCGICOUNT RX=%d, TX=%d\n", __func__,
- port->number, icount->rx, icount->tx);
- return 0;
-}
-
static int get_serial_info(struct edgeport_port *edge_port,
struct serial_struct __user *retinfo)
{
@@ -1626,8 +1562,8 @@ static int get_serial_info(struct edgeport_port *edge_port,
memset(&tmp, 0, sizeof(tmp));
tmp.type = PORT_16550A;
- tmp.line = edge_port->port->serial->minor;
- tmp.port = edge_port->port->number;
+ tmp.line = edge_port->port->minor;
+ tmp.port = edge_port->port->port_number;
tmp.irq = 0;
tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
tmp.xmit_fifo_size = edge_port->maxTxCredits;
@@ -1651,46 +1587,15 @@ static int edge_ioctl(struct tty_struct *tty,
struct usb_serial_port *port = tty->driver_data;
DEFINE_WAIT(wait);
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
- struct async_icount cnow;
- struct async_icount cprev;
-
- dev_dbg(&port->dev, "%s - port %d, cmd = 0x%x\n", __func__, port->number, cmd);
switch (cmd) {
case TIOCSERGETLSR:
- dev_dbg(&port->dev, "%s (%d) TIOCSERGETLSR\n", __func__, port->number);
+ dev_dbg(&port->dev, "%s TIOCSERGETLSR\n", __func__);
return get_lsr_info(edge_port, (unsigned int __user *) arg);
case TIOCGSERIAL:
- dev_dbg(&port->dev, "%s (%d) TIOCGSERIAL\n", __func__, port->number);
+ dev_dbg(&port->dev, "%s TIOCGSERIAL\n", __func__);
return get_serial_info(edge_port, (struct serial_struct __user *) arg);
-
- case TIOCMIWAIT:
- dev_dbg(&port->dev, "%s (%d) TIOCMIWAIT\n", __func__, port->number);
- cprev = edge_port->icount;
- while (1) {
- prepare_to_wait(&edge_port->delta_msr_wait,
- &wait, TASK_INTERRUPTIBLE);
- schedule();
- finish_wait(&edge_port->delta_msr_wait, &wait);
- /* see if a signal did it */
- if (signal_pending(current))
- return -ERESTARTSYS;
- cnow = edge_port->icount;
- if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
- cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
- return -EIO; /* no change => error */
- if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
- ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
- ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
- ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
- return 0;
- }
- cprev = cnow;
- }
- /* NOTREACHED */
- break;
-
}
return -ENOIOCTLCMD;
}
@@ -1752,7 +1657,6 @@ static void process_rcvd_data(struct edgeport_serial *edge_serial,
struct device *dev = &edge_serial->serial->dev->dev;
struct usb_serial_port *port;
struct edgeport_port *edge_port;
- struct tty_struct *tty;
__u16 lastBufferLength;
__u16 rxLen;
@@ -1860,15 +1764,12 @@ static void process_rcvd_data(struct edgeport_serial *edge_serial,
edge_serial->rxPort];
edge_port = usb_get_serial_port_data(port);
if (edge_port->open) {
- tty = tty_port_tty_get(
- &edge_port->port->port);
- if (tty) {
- dev_dbg(dev, "%s - Sending %d bytes to TTY for port %d\n",
- __func__, rxLen, edge_serial->rxPort);
- edge_tty_recv(&edge_serial->serial->dev->dev, tty, buffer, rxLen);
- tty_kref_put(tty);
- }
- edge_port->icount.rx += rxLen;
+ dev_dbg(dev, "%s - Sending %d bytes to TTY for port %d\n",
+ __func__, rxLen,
+ edge_serial->rxPort);
+ edge_tty_recv(edge_port->port, buffer,
+ rxLen);
+ edge_port->port->icount.rx += rxLen;
}
buffer += rxLen;
}
@@ -2017,20 +1918,20 @@ static void process_rcvd_status(struct edgeport_serial *edge_serial,
* edge_tty_recv
* this function passes data on to the tty flip buffer
*****************************************************************************/
-static void edge_tty_recv(struct device *dev, struct tty_struct *tty,
- unsigned char *data, int length)
+static void edge_tty_recv(struct usb_serial_port *port, unsigned char *data,
+ int length)
{
int cnt;
- cnt = tty_insert_flip_string(tty, data, length);
+ cnt = tty_insert_flip_string(&port->port, data, length);
if (cnt < length) {
- dev_err(dev, "%s - dropping data, %d bytes lost\n",
+ dev_err(&port->dev, "%s - dropping data, %d bytes lost\n",
__func__, length - cnt);
}
data += cnt;
length -= cnt;
- tty_flip_buffer_push(tty);
+ tty_flip_buffer_push(&port->port);
}
@@ -2044,7 +1945,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 newMsr)
if (newMsr & (EDGEPORT_MSR_DELTA_CTS | EDGEPORT_MSR_DELTA_DSR |
EDGEPORT_MSR_DELTA_RI | EDGEPORT_MSR_DELTA_CD)) {
- icount = &edge_port->icount;
+ icount = &edge_port->port->icount;
/* update input line counters */
if (newMsr & EDGEPORT_MSR_DELTA_CTS)
@@ -2055,7 +1956,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 newMsr)
icount->dcd++;
if (newMsr & EDGEPORT_MSR_DELTA_RI)
icount->rng++;
- wake_up_interruptible(&edge_port->delta_msr_wait);
+ wake_up_interruptible(&edge_port->port->port.delta_msr_wait);
}
/* Save the new modem status */
@@ -2086,16 +1987,11 @@ static void handle_new_lsr(struct edgeport_port *edge_port, __u8 lsrData,
}
/* Place LSR data byte into Rx buffer */
- if (lsrData) {
- struct tty_struct *tty =
- tty_port_tty_get(&edge_port->port->port);
- if (tty) {
- edge_tty_recv(&edge_port->port->dev, tty, &data, 1);
- tty_kref_put(tty);
- }
- }
+ if (lsrData)
+ edge_tty_recv(edge_port->port, &data, 1);
+
/* update input line counters */
- icount = &edge_port->icount;
+ icount = &edge_port->port->icount;
if (newLsr & LSR_BREAK)
icount->brk++;
if (newLsr & LSR_OVER_ERR)
@@ -2124,11 +2020,8 @@ static int sram_write(struct usb_serial *serial, __u16 extAddr, __u16 addr,
dev_dbg(&serial->dev->dev, "%s - %x, %x, %d\n", __func__, extAddr, addr, length);
transfer_buffer = kmalloc(64, GFP_KERNEL);
- if (!transfer_buffer) {
- dev_err(&serial->dev->dev, "%s - kmalloc(%d) failed.\n",
- __func__, 64);
+ if (!transfer_buffer)
return -ENOMEM;
- }
/* need to split these writes up into 64 byte chunks */
result = 0;
@@ -2172,11 +2065,8 @@ static int rom_write(struct usb_serial *serial, __u16 extAddr, __u16 addr,
unsigned char *transfer_buffer;
transfer_buffer = kmalloc(64, GFP_KERNEL);
- if (!transfer_buffer) {
- dev_err(&serial->dev->dev, "%s - kmalloc(%d) failed.\n",
- __func__, 64);
+ if (!transfer_buffer)
return -ENOMEM;
- }
/* need to split these writes up into 64 byte chunks */
result = 0;
@@ -2218,11 +2108,8 @@ static int rom_read(struct usb_serial *serial, __u16 extAddr,
unsigned char *transfer_buffer;
transfer_buffer = kmalloc(64, GFP_KERNEL);
- if (!transfer_buffer) {
- dev_err(&serial->dev->dev,
- "%s - kmalloc(%d) failed.\n", __func__, 64);
+ if (!transfer_buffer)
return -ENOMEM;
- }
/* need to split these reads up into 64 byte chunks */
result = 0;
@@ -2262,17 +2149,13 @@ static int send_iosp_ext_cmd(struct edgeport_port *edge_port,
int status = 0;
buffer = kmalloc(10, GFP_ATOMIC);
- if (!buffer) {
- dev_err(&edge_port->port->dev,
- "%s - kmalloc(%d) failed.\n", __func__, 10);
+ if (!buffer)
return -ENOMEM;
- }
currentCommand = buffer;
- MAKE_CMD_EXT_CMD(&currentCommand, &length,
- edge_port->port->number - edge_port->port->serial->minor,
- command, param);
+ MAKE_CMD_EXT_CMD(&currentCommand, &length, edge_port->port->port_number,
+ command, param);
status = write_cmd_usb(edge_port, buffer, length);
if (status) {
@@ -2355,18 +2238,16 @@ static int send_cmd_write_baud_rate(struct edgeport_port *edge_port,
int cmdLen = 0;
int divisor;
int status;
- unsigned char number =
- edge_port->port->number - edge_port->port->serial->minor;
+ u32 number = edge_port->port->port_number;
if (edge_serial->is_epic &&
!edge_serial->epic_descriptor.Supports.IOSPSetBaudRate) {
- dev_dbg(dev, "SendCmdWriteBaudRate - NOT Setting baud rate for port = %d, baud = %d\n",
- edge_port->port->number, baudRate);
+ dev_dbg(dev, "SendCmdWriteBaudRate - NOT Setting baud rate for port, baud = %d\n",
+ baudRate);
return 0;
}
- dev_dbg(dev, "%s - port = %d, baud = %d\n", __func__,
- edge_port->port->number, baudRate);
+ dev_dbg(dev, "%s - baud = %d\n", __func__, baudRate);
status = calc_baud_rate_divisor(dev, baudRate, &divisor);
if (status) {
@@ -2376,10 +2257,9 @@ static int send_cmd_write_baud_rate(struct edgeport_port *edge_port,
/* Alloc memory for the string of commands. */
cmdBuffer = kmalloc(0x100, GFP_ATOMIC);
- if (!cmdBuffer) {
- dev_err(dev, "%s - kmalloc(%d) failed.\n", __func__, 0x100);
+ if (!cmdBuffer)
return -ENOMEM;
- }
+
currCmd = cmdBuffer;
/* Enable access to divisor latch */
@@ -2477,9 +2357,8 @@ static int send_cmd_write_uart_register(struct edgeport_port *edge_port,
currCmd = cmdBuffer;
/* Build a cmd in the buffer to write the given register */
- MAKE_CMD_WRITE_REG(&currCmd, &cmdLen,
- edge_port->port->number - edge_port->port->serial->minor,
- regNum, regValue);
+ MAKE_CMD_WRITE_REG(&currCmd, &cmdLen, edge_port->port->port_number,
+ regNum, regValue);
status = write_cmd_usb(edge_port, cmdBuffer, cmdLen);
if (status) {
@@ -2513,8 +2392,6 @@ static void change_port_settings(struct tty_struct *tty,
__u8 txFlow;
int status;
- dev_dbg(dev, "%s - port %d\n", __func__, edge_port->port->number);
-
if (!edge_port->open &&
!edge_port->openPending) {
dev_dbg(dev, "%s - port not opened\n", __func__);
@@ -2888,10 +2765,9 @@ static int edge_startup(struct usb_serial *serial)
/* create our private serial structure */
edge_serial = kzalloc(sizeof(struct edgeport_serial), GFP_KERNEL);
- if (edge_serial == NULL) {
- dev_err(&serial->dev->dev, "%s - Out of memory\n", __func__);
+ if (!edge_serial)
return -ENOMEM;
- }
+
spin_lock_init(&edge_serial->es_lock);
edge_serial->serial = serial;
usb_set_serial_data(serial, edge_serial);
@@ -2980,14 +2856,12 @@ static int edge_startup(struct usb_serial *serial)
/* not set up yet, so do it now */
edge_serial->interrupt_read_urb =
usb_alloc_urb(0, GFP_KERNEL);
- if (!edge_serial->interrupt_read_urb) {
- dev_err(ddev, "out of memory\n");
+ if (!edge_serial->interrupt_read_urb)
return -ENOMEM;
- }
+
edge_serial->interrupt_in_buffer =
kmalloc(buffer_size, GFP_KERNEL);
if (!edge_serial->interrupt_in_buffer) {
- dev_err(ddev, "out of memory\n");
usb_free_urb(edge_serial->interrupt_read_urb);
return -ENOMEM;
}
@@ -3017,14 +2891,12 @@ static int edge_startup(struct usb_serial *serial)
/* not set up yet, so do it now */
edge_serial->read_urb =
usb_alloc_urb(0, GFP_KERNEL);
- if (!edge_serial->read_urb) {
- dev_err(ddev, "out of memory\n");
+ if (!edge_serial->read_urb)
return -ENOMEM;
- }
+
edge_serial->bulk_in_buffer =
kmalloc(buffer_size, GFP_KERNEL);
if (!edge_serial->bulk_in_buffer) {
- dev_err(&dev->dev, "out of memory\n");
usb_free_urb(edge_serial->read_urb);
return -ENOMEM;
}
diff --git a/drivers/usb/serial/io_tables.h b/drivers/usb/serial/io_tables.h
index 1511dd0ad32..ae5fac5656c 100644
--- a/drivers/usb/serial/io_tables.h
+++ b/drivers/usb/serial/io_tables.h
@@ -116,7 +116,8 @@ static struct usb_serial_driver edgeport_2port_device = {
.set_termios = edge_set_termios,
.tiocmget = edge_tiocmget,
.tiocmset = edge_tiocmset,
- .get_icount = edge_get_icount,
+ .tiocmiwait = usb_serial_generic_tiocmiwait,
+ .get_icount = usb_serial_generic_get_icount,
.write = edge_write,
.write_room = edge_write_room,
.chars_in_buffer = edge_chars_in_buffer,
@@ -147,7 +148,8 @@ static struct usb_serial_driver edgeport_4port_device = {
.set_termios = edge_set_termios,
.tiocmget = edge_tiocmget,
.tiocmset = edge_tiocmset,
- .get_icount = edge_get_icount,
+ .tiocmiwait = usb_serial_generic_tiocmiwait,
+ .get_icount = usb_serial_generic_get_icount,
.write = edge_write,
.write_room = edge_write_room,
.chars_in_buffer = edge_chars_in_buffer,
@@ -178,7 +180,8 @@ static struct usb_serial_driver edgeport_8port_device = {
.set_termios = edge_set_termios,
.tiocmget = edge_tiocmget,
.tiocmset = edge_tiocmset,
- .get_icount = edge_get_icount,
+ .tiocmiwait = usb_serial_generic_tiocmiwait,
+ .get_icount = usb_serial_generic_get_icount,
.write = edge_write,
.write_room = edge_write_room,
.chars_in_buffer = edge_chars_in_buffer,
@@ -209,7 +212,8 @@ static struct usb_serial_driver epic_device = {
.set_termios = edge_set_termios,
.tiocmget = edge_tiocmget,
.tiocmset = edge_tiocmset,
- .get_icount = edge_get_icount,
+ .tiocmiwait = usb_serial_generic_tiocmiwait,
+ .get_icount = usb_serial_generic_get_icount,
.write = edge_write,
.write_room = edge_write_room,
.chars_in_buffer = edge_chars_in_buffer,
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index 82afc4d6a32..c0a42e9e677 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -20,7 +20,6 @@
#include <linux/kernel.h>
#include <linux/jiffies.h>
#include <linux/errno.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
@@ -29,6 +28,7 @@
#include <linux/spinlock.h>
#include <linux/mutex.h>
#include <linux/serial.h>
+#include <linux/swab.h>
#include <linux/kfifo.h>
#include <linux/ioctl.h>
#include <linux/firmware.h>
@@ -64,8 +64,6 @@
#define EDGE_CLOSING_WAIT 4000 /* in .01 sec */
-#define EDGE_OUT_BUF_SIZE 1024
-
/* Product information read from the Edgeport */
struct product_info {
@@ -86,17 +84,13 @@ struct edgeport_port {
int baud_rate;
int close_pending;
int lsr_event;
- struct async_icount icount;
- wait_queue_head_t delta_msr_wait; /* for handling sleeping while
- waiting for msr change to
- happen */
+
struct edgeport_serial *edge_serial;
struct usb_serial_port *port;
__u8 bUartMode; /* Port type, 0: RS232, etc. */
spinlock_t ep_lock;
int ep_read_urb_state;
int ep_write_urb_in_use;
- struct kfifo write_fifo;
};
struct edgeport_serial {
@@ -201,15 +195,15 @@ static int closing_wait = EDGE_CLOSING_WAIT;
static bool ignore_cpu_rev;
static int default_uart_mode; /* RS232 */
-static void edge_tty_recv(struct device *dev, struct tty_struct *tty,
- unsigned char *data, int length);
+static void edge_tty_recv(struct usb_serial_port *port, unsigned char *data,
+ int length);
static void stop_read(struct edgeport_port *edge_port);
static int restart_read(struct edgeport_port *edge_port);
static void edge_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios);
-static void edge_send(struct tty_struct *tty);
+static void edge_send(struct usb_serial_port *port, struct tty_struct *tty);
/* sysfs attributes */
static int edge_create_sysfs_attrs(struct usb_serial_port *port);
@@ -262,7 +256,7 @@ static int send_cmd(struct usb_device *dev, __u8 command,
/* clear tx/rx buffers and fifo in TI UMP */
static int purge_port(struct usb_serial_port *port, __u16 mask)
{
- int port_number = port->number - port->serial->minor;
+ int port_number = port->port_number;
dev_dbg(&port->dev, "%s - port %d, mask %x\n", __func__, port_number, mask);
@@ -287,7 +281,7 @@ static int read_download_mem(struct usb_device *dev, int start_address,
{
int status = 0;
__u8 read_length;
- __be16 be_start_address;
+ u16 be_start_address;
dev_dbg(&dev->dev, "%s - @ %x for %d\n", __func__, start_address, length);
@@ -303,10 +297,14 @@ static int read_download_mem(struct usb_device *dev, int start_address,
if (read_length > 1) {
dev_dbg(&dev->dev, "%s - @ %x for %d\n", __func__, start_address, read_length);
}
- be_start_address = cpu_to_be16(start_address);
+ /*
+ * NOTE: Must use swab as wIndex is sent in little-endian
+ * byte order regardless of host byte order.
+ */
+ be_start_address = swab16((u16)start_address);
status = ti_vread_sync(dev, UMPC_MEMORY_READ,
(__u16)address_type,
- (__force __u16)be_start_address,
+ be_start_address,
buffer, read_length);
if (status) {
@@ -370,11 +368,9 @@ static int write_boot_mem(struct edgeport_serial *serial,
/* Must do a read before write */
if (!serial->TiReadI2C) {
temp = kmalloc(1, GFP_KERNEL);
- if (!temp) {
- dev_err(&serial->serial->dev->dev,
- "%s - out of memory\n", __func__);
+ if (!temp)
return -ENOMEM;
- }
+
status = read_boot_mem(serial, 0, 1, temp);
kfree(temp);
if (status)
@@ -403,7 +399,7 @@ static int write_i2c_mem(struct edgeport_serial *serial,
struct device *dev = &serial->serial->dev->dev;
int status = 0;
int write_length;
- __be16 be_start_address;
+ u16 be_start_address;
/* We can only send a maximum of 1 aligned byte page at a time */
@@ -418,11 +414,16 @@ static int write_i2c_mem(struct edgeport_serial *serial,
__func__, start_address, write_length);
usb_serial_debug_data(dev, __func__, write_length, buffer);
- /* Write first page */
- be_start_address = cpu_to_be16(start_address);
+ /*
+ * Write first page.
+ *
+ * NOTE: Must use swab as wIndex is sent in little-endian byte order
+ * regardless of host byte order.
+ */
+ be_start_address = swab16((u16)start_address);
status = ti_vsend_sync(serial->serial->dev,
UMPC_MEMORY_WRITE, (__u16)address_type,
- (__force __u16)be_start_address,
+ be_start_address,
buffer, write_length);
if (status) {
dev_dbg(dev, "%s - ERROR %d\n", __func__, status);
@@ -445,11 +446,16 @@ static int write_i2c_mem(struct edgeport_serial *serial,
__func__, start_address, write_length);
usb_serial_debug_data(dev, __func__, write_length, buffer);
- /* Write next page */
- be_start_address = cpu_to_be16(start_address);
+ /*
+ * Write next page.
+ *
+ * NOTE: Must use swab as wIndex is sent in little-endian byte
+ * order regardless of host byte order.
+ */
+ be_start_address = swab16((u16)start_address);
status = ti_vsend_sync(serial->serial->dev, UMPC_MEMORY_WRITE,
(__u16)address_type,
- (__force __u16)be_start_address,
+ be_start_address,
buffer, write_length);
if (status) {
dev_err(dev, "%s - ERROR %d\n", __func__, status);
@@ -477,10 +483,8 @@ static int tx_active(struct edgeport_port *port)
int bytes_left = 0;
oedb = kmalloc(sizeof(*oedb), GFP_KERNEL);
- if (!oedb) {
- dev_err(&port->port->dev, "%s - out of memory\n", __func__);
+ if (!oedb)
return -ENOMEM;
- }
lsr = kmalloc(1, GFP_KERNEL); /* Sigh, that's right, just one byte,
as not all platforms can do DMA
@@ -521,65 +525,6 @@ exit_is_tx_active:
return bytes_left;
}
-static void chase_port(struct edgeport_port *port, unsigned long timeout,
- int flush)
-{
- int baud_rate;
- struct tty_struct *tty = tty_port_tty_get(&port->port->port);
- struct usb_serial *serial = port->port->serial;
- wait_queue_t wait;
- unsigned long flags;
-
- if (!tty)
- return;
-
- if (!timeout)
- timeout = (HZ * EDGE_CLOSING_WAIT)/100;
-
- /* wait for data to drain from the buffer */
- spin_lock_irqsave(&port->ep_lock, flags);
- init_waitqueue_entry(&wait, current);
- add_wait_queue(&tty->write_wait, &wait);
- for (;;) {
- set_current_state(TASK_INTERRUPTIBLE);
- if (kfifo_len(&port->write_fifo) == 0
- || timeout == 0 || signal_pending(current)
- || serial->disconnected)
- /* disconnect */
- break;
- spin_unlock_irqrestore(&port->ep_lock, flags);
- timeout = schedule_timeout(timeout);
- spin_lock_irqsave(&port->ep_lock, flags);
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&tty->write_wait, &wait);
- if (flush)
- kfifo_reset_out(&port->write_fifo);
- spin_unlock_irqrestore(&port->ep_lock, flags);
- tty_kref_put(tty);
-
- /* wait for data to drain from the device */
- timeout += jiffies;
- while ((long)(jiffies - timeout) < 0 && !signal_pending(current)
- && !serial->disconnected) {
- /* not disconnected */
- if (!tx_active(port))
- break;
- msleep(10);
- }
-
- /* disconnected */
- if (serial->disconnected)
- return;
-
- /* wait one more character time, based on baud rate */
- /* (tx_active doesn't seem to wait for the last byte) */
- baud_rate = port->baud_rate;
- if (baud_rate == 0)
- baud_rate = 50;
- msleep(max(1, DIV_ROUND_UP(10000, baud_rate)));
-}
-
static int choose_config(struct usb_device *dev)
{
/*
@@ -655,8 +600,8 @@ static int get_descriptor_addr(struct edgeport_serial *serial,
if (rom_desc->Type == desc_type)
return start_address;
- start_address = start_address + sizeof(struct ti_i2c_desc)
- + rom_desc->Size;
+ start_address = start_address + sizeof(struct ti_i2c_desc) +
+ le16_to_cpu(rom_desc->Size);
} while ((start_address < TI_MAX_I2C_SIZE) && rom_desc->Type);
@@ -669,7 +614,7 @@ static int valid_csum(struct ti_i2c_desc *rom_desc, __u8 *buffer)
__u16 i;
__u8 cs = 0;
- for (i = 0; i < rom_desc->Size; i++)
+ for (i = 0; i < le16_to_cpu(rom_desc->Size); i++)
cs = (__u8)(cs + buffer[i]);
if (cs != rom_desc->CheckSum) {
@@ -690,14 +635,11 @@ static int check_i2c_image(struct edgeport_serial *serial)
__u16 ttype;
rom_desc = kmalloc(sizeof(*rom_desc), GFP_KERNEL);
- if (!rom_desc) {
- dev_err(dev, "%s - out of memory\n", __func__);
+ if (!rom_desc)
return -ENOMEM;
- }
+
buffer = kmalloc(TI_MAX_I2C_SIZE, GFP_KERNEL);
if (!buffer) {
- dev_err(dev, "%s - out of memory when allocating buffer\n",
- __func__);
kfree(rom_desc);
return -ENOMEM;
}
@@ -723,7 +665,7 @@ static int check_i2c_image(struct edgeport_serial *serial)
break;
if ((start_address + sizeof(struct ti_i2c_desc) +
- rom_desc->Size) > TI_MAX_I2C_SIZE) {
+ le16_to_cpu(rom_desc->Size)) > TI_MAX_I2C_SIZE) {
status = -ENODEV;
dev_dbg(dev, "%s - structure too big, erroring out.\n", __func__);
break;
@@ -738,7 +680,8 @@ static int check_i2c_image(struct edgeport_serial *serial)
/* Read the descriptor data */
status = read_rom(serial, start_address +
sizeof(struct ti_i2c_desc),
- rom_desc->Size, buffer);
+ le16_to_cpu(rom_desc->Size),
+ buffer);
if (status)
break;
@@ -747,7 +690,7 @@ static int check_i2c_image(struct edgeport_serial *serial)
break;
}
start_address = start_address + sizeof(struct ti_i2c_desc) +
- rom_desc->Size;
+ le16_to_cpu(rom_desc->Size);
} while ((rom_desc->Type != I2C_DESC_TYPE_ION) &&
(start_address < TI_MAX_I2C_SIZE));
@@ -771,10 +714,9 @@ static int get_manuf_info(struct edgeport_serial *serial, __u8 *buffer)
struct device *dev = &serial->serial->dev->dev;
rom_desc = kmalloc(sizeof(*rom_desc), GFP_KERNEL);
- if (!rom_desc) {
- dev_err(dev, "%s - out of memory\n", __func__);
+ if (!rom_desc)
return -ENOMEM;
- }
+
start_address = get_descriptor_addr(serial, I2C_DESC_TYPE_ION,
rom_desc);
@@ -786,7 +728,7 @@ static int get_manuf_info(struct edgeport_serial *serial, __u8 *buffer)
/* Read the descriptor data */
status = read_rom(serial, start_address+sizeof(struct ti_i2c_desc),
- rom_desc->Size, buffer);
+ le16_to_cpu(rom_desc->Size), buffer);
if (status)
goto exit;
@@ -834,10 +776,8 @@ static int build_i2c_fw_hdr(__u8 *header, struct device *dev)
sizeof(struct ti_i2c_firmware_rec));
buffer = kmalloc(buffer_size, GFP_KERNEL);
- if (!buffer) {
- dev_err(dev, "%s - out of memory\n", __func__);
+ if (!buffer)
return -ENOMEM;
- }
// Set entire image of 0xffs
memset(buffer, 0xff, buffer_size);
@@ -881,7 +821,7 @@ static int build_i2c_fw_hdr(__u8 *header, struct device *dev)
firmware_rec = (struct ti_i2c_firmware_rec*)i2c_header->Data;
i2c_header->Type = I2C_DESC_TYPE_FIRMWARE_BLANK;
- i2c_header->Size = (__u16)buffer_size;
+ i2c_header->Size = cpu_to_le16(buffer_size);
i2c_header->CheckSum = cs;
firmware_rec->Ver_Major = OperationalMajorVersion;
firmware_rec->Ver_Minor = OperationalMinorVersion;
@@ -897,10 +837,8 @@ static int i2c_type_bootmode(struct edgeport_serial *serial)
u8 *data;
data = kmalloc(1, GFP_KERNEL);
- if (!data) {
- dev_err(dev, "%s - out of memory\n", __func__);
+ if (!data)
return -ENOMEM;
- }
/* Try to read type 2 */
status = ti_vread_sync(serial->serial->dev, UMPC_MEMORY_READ,
@@ -1051,10 +989,9 @@ static int download_fw(struct edgeport_serial *serial)
* Read Manufacturing Descriptor from TI Based Edgeport
*/
ti_manuf_desc = kmalloc(sizeof(*ti_manuf_desc), GFP_KERNEL);
- if (!ti_manuf_desc) {
- dev_err(dev, "%s - out of memory.\n", __func__);
+ if (!ti_manuf_desc)
return -ENOMEM;
- }
+
status = get_manuf_info(serial, (__u8 *)ti_manuf_desc);
if (status) {
kfree(ti_manuf_desc);
@@ -1071,7 +1008,6 @@ static int download_fw(struct edgeport_serial *serial)
rom_desc = kmalloc(sizeof(*rom_desc), GFP_KERNEL);
if (!rom_desc) {
- dev_err(dev, "%s - out of memory.\n", __func__);
kfree(ti_manuf_desc);
return -ENOMEM;
}
@@ -1088,7 +1024,6 @@ static int download_fw(struct edgeport_serial *serial)
firmware_version = kmalloc(sizeof(*firmware_version),
GFP_KERNEL);
if (!firmware_version) {
- dev_err(dev, "%s - out of memory.\n", __func__);
kfree(rom_desc);
kfree(ti_manuf_desc);
return -ENOMEM;
@@ -1133,8 +1068,6 @@ static int download_fw(struct edgeport_serial *serial)
record = kmalloc(1, GFP_KERNEL);
if (!record) {
- dev_err(dev, "%s - out of memory.\n",
- __func__);
kfree(firmware_version);
kfree(rom_desc);
kfree(ti_manuf_desc);
@@ -1218,7 +1151,6 @@ static int download_fw(struct edgeport_serial *serial)
header = kmalloc(HEADER_SIZE, GFP_KERNEL);
if (!header) {
- dev_err(dev, "%s - out of memory.\n", __func__);
kfree(rom_desc);
kfree(ti_manuf_desc);
return -ENOMEM;
@@ -1226,7 +1158,6 @@ static int download_fw(struct edgeport_serial *serial)
vheader = kmalloc(HEADER_SIZE, GFP_KERNEL);
if (!vheader) {
- dev_err(dev, "%s - out of memory.\n", __func__);
kfree(header);
kfree(rom_desc);
kfree(ti_manuf_desc);
@@ -1355,10 +1286,9 @@ static int download_fw(struct edgeport_serial *serial)
* Read Manufacturing Descriptor from TI Based Edgeport
*/
ti_manuf_desc = kmalloc(sizeof(*ti_manuf_desc), GFP_KERNEL);
- if (!ti_manuf_desc) {
- dev_err(dev, "%s - out of memory.\n", __func__);
+ if (!ti_manuf_desc)
return -ENOMEM;
- }
+
status = get_manuf_info(serial, (__u8 *)ti_manuf_desc);
if (status) {
kfree(ti_manuf_desc);
@@ -1393,10 +1323,8 @@ static int download_fw(struct edgeport_serial *serial)
buffer_size = (((1024 * 16) - 512) +
sizeof(struct ti_i2c_image_header));
buffer = kmalloc(buffer_size, GFP_KERNEL);
- if (!buffer) {
- dev_err(dev, "%s - out of memory\n", __func__);
+ if (!buffer)
return -ENOMEM;
- }
/* Initialize the buffer to 0xff (pad the buffer) */
memset(buffer, 0xff, buffer_size);
@@ -1454,7 +1382,8 @@ stayinbootmode:
static int ti_do_config(struct edgeport_port *port, int feature, int on)
{
- int port_number = port->port->number - port->port->serial->minor;
+ int port_number = port->port->port_number;
+
on = !!on; /* 1 or 0 not bitmask */
return send_cmd(port->port->serial->dev,
feature, (__u8)(UMPM_UART1_PORT + port_number),
@@ -1507,7 +1436,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr)
if (msr & (EDGEPORT_MSR_DELTA_CTS | EDGEPORT_MSR_DELTA_DSR |
EDGEPORT_MSR_DELTA_RI | EDGEPORT_MSR_DELTA_CD)) {
- icount = &edge_port->icount;
+ icount = &edge_port->port->icount;
/* update input line counters */
if (msr & EDGEPORT_MSR_DELTA_CTS)
@@ -1518,7 +1447,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr)
icount->dcd++;
if (msr & EDGEPORT_MSR_DELTA_RI)
icount->rng++;
- wake_up_interruptible(&edge_port->delta_msr_wait);
+ wake_up_interruptible(&edge_port->port->port.delta_msr_wait);
}
/* Save the new modem status */
@@ -1543,7 +1472,6 @@ static void handle_new_lsr(struct edgeport_port *edge_port, int lsr_data,
struct async_icount *icount;
__u8 new_lsr = (__u8)(lsr & (__u8)(LSR_OVER_ERR | LSR_PAR_ERR |
LSR_FRM_ERR | LSR_BREAK));
- struct tty_struct *tty;
dev_dbg(&edge_port->port->dev, "%s - %02x\n", __func__, new_lsr);
@@ -1557,16 +1485,11 @@ static void handle_new_lsr(struct edgeport_port *edge_port, int lsr_data,
new_lsr &= (__u8)(LSR_OVER_ERR | LSR_BREAK);
/* Place LSR data byte into Rx buffer */
- if (lsr_data) {
- tty = tty_port_tty_get(&edge_port->port->port);
- if (tty) {
- edge_tty_recv(&edge_port->port->dev, tty, &data, 1);
- tty_kref_put(tty);
- }
- }
+ if (lsr_data)
+ edge_tty_recv(edge_port->port, &data, 1);
/* update input line counters */
- icount = &edge_port->icount;
+ icount = &edge_port->port->icount;
if (new_lsr & LSR_BREAK)
icount->brk++;
if (new_lsr & LSR_OVER_ERR)
@@ -1679,7 +1602,6 @@ static void edge_bulk_in_callback(struct urb *urb)
struct edgeport_port *edge_port = urb->context;
struct device *dev = &edge_port->port->dev;
unsigned char *data = urb->transfer_buffer;
- struct tty_struct *tty;
int retval = 0;
int port_number;
int status = urb->status;
@@ -1706,7 +1628,7 @@ static void edge_bulk_in_callback(struct urb *urb)
return;
}
- port_number = edge_port->port->number - edge_port->port->serial->minor;
+ port_number = edge_port->port->port_number;
if (edge_port->lsr_event) {
edge_port->lsr_event = 0;
@@ -1718,17 +1640,16 @@ static void edge_bulk_in_callback(struct urb *urb)
++data;
}
- tty = tty_port_tty_get(&edge_port->port->port);
- if (tty && urb->actual_length) {
+ if (urb->actual_length) {
usb_serial_debug_data(dev, __func__, urb->actual_length, data);
if (edge_port->close_pending)
dev_dbg(dev, "%s - close pending, dropping data on the floor\n",
__func__);
else
- edge_tty_recv(dev, tty, data, urb->actual_length);
- edge_port->icount.rx += urb->actual_length;
+ edge_tty_recv(edge_port->port, data,
+ urb->actual_length);
+ edge_port->port->icount.rx += urb->actual_length;
}
- tty_kref_put(tty);
exit:
/* continue read unless stopped */
@@ -1743,16 +1664,16 @@ exit:
dev_err(dev, "%s - usb_submit_urb failed with result %d\n", __func__, retval);
}
-static void edge_tty_recv(struct device *dev, struct tty_struct *tty,
- unsigned char *data, int length)
+static void edge_tty_recv(struct usb_serial_port *port, unsigned char *data,
+ int length)
{
int queued;
- queued = tty_insert_flip_string(tty, data, length);
+ queued = tty_insert_flip_string(&port->port, data, length);
if (queued < length)
- dev_err(dev, "%s - dropping data, %d bytes lost\n",
+ dev_err(&port->dev, "%s - dropping data, %d bytes lost\n",
__func__, length - queued);
- tty_flip_buffer_push(tty);
+ tty_flip_buffer_push(&port->port);
}
static void edge_bulk_out_callback(struct urb *urb)
@@ -1782,7 +1703,7 @@ static void edge_bulk_out_callback(struct urb *urb)
/* send any buffered data */
tty = tty_port_tty_get(&port->port);
- edge_send(tty);
+ edge_send(port, tty);
tty_kref_put(tty);
}
@@ -1800,29 +1721,10 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port)
if (edge_port == NULL)
return -ENODEV;
- port_number = port->number - port->serial->minor;
- switch (port_number) {
- case 0:
- edge_port->uart_base = UMPMEM_BASE_UART1;
- edge_port->dma_address = UMPD_OEDB1_ADDRESS;
- break;
- case 1:
- edge_port->uart_base = UMPMEM_BASE_UART2;
- edge_port->dma_address = UMPD_OEDB2_ADDRESS;
- break;
- default:
- dev_err(&port->dev, "Unknown port number!!!\n");
- return -ENODEV;
- }
-
- dev_dbg(&port->dev, "%s - port_number = %d, uart_base = %04x, dma_address = %04x\n",
- __func__, port_number, edge_port->uart_base, edge_port->dma_address);
+ port_number = port->port_number;
dev = port->serial->dev;
- memset(&(edge_port->icount), 0x00, sizeof(edge_port->icount));
- init_waitqueue_head(&edge_port->delta_msr_wait);
-
/* turn off loopback */
status = ti_do_config(edge_port, UMPC_SET_CLR_LOOPBACK, 0);
if (status) {
@@ -1959,6 +1861,7 @@ static void edge_close(struct usb_serial_port *port)
struct edgeport_serial *edge_serial;
struct edgeport_port *edge_port;
struct usb_serial *serial = port->serial;
+ unsigned long flags;
int port_number;
edge_serial = usb_get_serial_data(port->serial);
@@ -1970,28 +1873,17 @@ static void edge_close(struct usb_serial_port *port)
* this flag and dump add read data */
edge_port->close_pending = 1;
- /* chase the port close and flush */
- chase_port(edge_port, (HZ * closing_wait) / 100, 1);
-
usb_kill_urb(port->read_urb);
usb_kill_urb(port->write_urb);
edge_port->ep_write_urb_in_use = 0;
+ spin_lock_irqsave(&edge_port->ep_lock, flags);
+ kfifo_reset_out(&port->write_fifo);
+ spin_unlock_irqrestore(&edge_port->ep_lock, flags);
- /* assuming we can still talk to the device,
- * send a close port command to it */
dev_dbg(&port->dev, "%s - send umpc_close_port\n", __func__);
- port_number = port->number - port->serial->minor;
-
- mutex_lock(&serial->disc_mutex);
- if (!serial->disconnected) {
- send_cmd(serial->dev,
- UMPC_CLOSE_PORT,
- (__u8)(UMPM_UART1_PORT + port_number),
- 0,
- NULL,
- 0);
- }
- mutex_unlock(&serial->disc_mutex);
+ port_number = port->port_number;
+ send_cmd(serial->dev, UMPC_CLOSE_PORT,
+ (__u8)(UMPM_UART1_PORT + port_number), 0, NULL, 0);
mutex_lock(&edge_serial->es_lock);
--edge_port->edge_serial->num_ports_open;
@@ -2019,16 +1911,15 @@ static int edge_write(struct tty_struct *tty, struct usb_serial_port *port,
if (edge_port->close_pending == 1)
return -ENODEV;
- count = kfifo_in_locked(&edge_port->write_fifo, data, count,
+ count = kfifo_in_locked(&port->write_fifo, data, count,
&edge_port->ep_lock);
- edge_send(tty);
+ edge_send(port, tty);
return count;
}
-static void edge_send(struct tty_struct *tty)
+static void edge_send(struct usb_serial_port *port, struct tty_struct *tty)
{
- struct usb_serial_port *port = tty->driver_data;
int count, result;
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
unsigned long flags;
@@ -2040,7 +1931,7 @@ static void edge_send(struct tty_struct *tty)
return;
}
- count = kfifo_out(&edge_port->write_fifo,
+ count = kfifo_out(&port->write_fifo,
port->write_urb->transfer_buffer,
port->bulk_out_size);
@@ -2067,7 +1958,7 @@ static void edge_send(struct tty_struct *tty)
edge_port->ep_write_urb_in_use = 0;
/* TODO: reschedule edge_send */
} else
- edge_port->icount.tx += count;
+ edge_port->port->icount.tx += count;
/* wakeup any process waiting for writes to complete */
/* there is now more room in the buffer for new writes */
@@ -2088,7 +1979,7 @@ static int edge_write_room(struct tty_struct *tty)
return 0;
spin_lock_irqsave(&edge_port->ep_lock, flags);
- room = kfifo_avail(&edge_port->write_fifo);
+ room = kfifo_avail(&port->write_fifo);
spin_unlock_irqrestore(&edge_port->ep_lock, flags);
dev_dbg(&port->dev, "%s - returns %d\n", __func__, room);
@@ -2101,20 +1992,29 @@ static int edge_chars_in_buffer(struct tty_struct *tty)
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
int chars = 0;
unsigned long flags;
-
if (edge_port == NULL)
return 0;
- if (edge_port->close_pending == 1)
- return 0;
spin_lock_irqsave(&edge_port->ep_lock, flags);
- chars = kfifo_len(&edge_port->write_fifo);
+ chars = kfifo_len(&port->write_fifo);
spin_unlock_irqrestore(&edge_port->ep_lock, flags);
dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars);
return chars;
}
+static bool edge_tx_empty(struct usb_serial_port *port)
+{
+ struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+ int ret;
+
+ ret = tx_active(edge_port);
+ if (ret > 0)
+ return false;
+
+ return true;
+}
+
static void edge_throttle(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
@@ -2210,15 +2110,11 @@ static void change_port_settings(struct tty_struct *tty,
int baud;
unsigned cflag;
int status;
- int port_number = edge_port->port->number -
- edge_port->port->serial->minor;
-
- dev_dbg(dev, "%s - port %d\n", __func__, edge_port->port->number);
+ int port_number = edge_port->port->port_number;
config = kmalloc (sizeof (*config), GFP_KERNEL);
if (!config) {
tty->termios = *old_termios;
- dev_err(dev, "%s - out of memory\n", __func__);
return;
}
@@ -2357,7 +2253,6 @@ static void edge_set_termios(struct tty_struct *tty,
tty->termios.c_cflag, tty->termios.c_iflag);
dev_dbg(&port->dev, "%s - old clfag %08x old iflag %08x\n", __func__,
old_termios->c_cflag, old_termios->c_iflag);
- dev_dbg(&port->dev, "%s - port %d\n", __func__, port->number);
if (edge_port == NULL)
return;
@@ -2423,46 +2318,30 @@ static int edge_tiocmget(struct tty_struct *tty)
return result;
}
-static int edge_get_icount(struct tty_struct *tty,
- struct serial_icounter_struct *icount)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct edgeport_port *edge_port = usb_get_serial_port_data(port);
- struct async_icount *ic = &edge_port->icount;
-
- icount->cts = ic->cts;
- icount->dsr = ic->dsr;
- icount->rng = ic->rng;
- icount->dcd = ic->dcd;
- icount->tx = ic->tx;
- icount->rx = ic->rx;
- icount->frame = ic->frame;
- icount->parity = ic->parity;
- icount->overrun = ic->overrun;
- icount->brk = ic->brk;
- icount->buf_overrun = ic->buf_overrun;
- return 0;
-}
-
static int get_serial_info(struct edgeport_port *edge_port,
struct serial_struct __user *retinfo)
{
struct serial_struct tmp;
+ unsigned cwait;
if (!retinfo)
return -EFAULT;
+ cwait = edge_port->port->port.closing_wait;
+ if (cwait != ASYNC_CLOSING_WAIT_NONE)
+ cwait = jiffies_to_msecs(cwait) / 10;
+
memset(&tmp, 0, sizeof(tmp));
tmp.type = PORT_16550A;
- tmp.line = edge_port->port->serial->minor;
- tmp.port = edge_port->port->number;
+ tmp.line = edge_port->port->minor;
+ tmp.port = edge_port->port->port_number;
tmp.irq = 0;
tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
tmp.xmit_fifo_size = edge_port->port->bulk_out_size;
tmp.baud_base = 9600;
tmp.close_delay = 5*HZ;
- tmp.closing_wait = closing_wait;
+ tmp.closing_wait = cwait;
if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
return -EFAULT;
@@ -2474,38 +2353,12 @@ static int edge_ioctl(struct tty_struct *tty,
{
struct usb_serial_port *port = tty->driver_data;
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
- struct async_icount cnow;
- struct async_icount cprev;
-
- dev_dbg(&port->dev, "%s - port %d, cmd = 0x%x\n", __func__, port->number, cmd);
switch (cmd) {
case TIOCGSERIAL:
dev_dbg(&port->dev, "%s - TIOCGSERIAL\n", __func__);
return get_serial_info(edge_port,
(struct serial_struct __user *) arg);
- case TIOCMIWAIT:
- dev_dbg(&port->dev, "%s - TIOCMIWAIT\n", __func__);
- cprev = edge_port->icount;
- while (1) {
- interruptible_sleep_on(&edge_port->delta_msr_wait);
- /* see if a signal did it */
- if (signal_pending(current))
- return -ERESTARTSYS;
- cnow = edge_port->icount;
- if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
- cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
- return -EIO; /* no change => error */
- if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
- ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
- ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
- ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
- return 0;
- }
- cprev = cnow;
- }
- /* not reached */
- break;
}
return -ENOIOCTLCMD;
}
@@ -2517,9 +2370,6 @@ static void edge_break(struct tty_struct *tty, int break_state)
int status;
int bv = 0; /* Off */
- /* chase the port close */
- chase_port(edge_port, 0, 0);
-
if (break_state == -1)
bv = 1; /* On */
status = ti_do_config(edge_port, UMPC_SET_CLR_BREAK, bv);
@@ -2535,10 +2385,9 @@ static int edge_startup(struct usb_serial *serial)
/* create our private serial structure */
edge_serial = kzalloc(sizeof(struct edgeport_serial), GFP_KERNEL);
- if (edge_serial == NULL) {
- dev_err(&serial->dev->dev, "%s - Out of memory\n", __func__);
+ if (!edge_serial)
return -ENOMEM;
- }
+
mutex_init(&edge_serial->es_lock);
edge_serial->serial = serial;
usb_set_serial_data(serial, edge_serial);
@@ -2570,28 +2419,45 @@ static int edge_port_probe(struct usb_serial_port *port)
if (!edge_port)
return -ENOMEM;
- ret = kfifo_alloc(&edge_port->write_fifo, EDGE_OUT_BUF_SIZE,
- GFP_KERNEL);
- if (ret) {
- kfree(edge_port);
- return -ENOMEM;
- }
-
spin_lock_init(&edge_port->ep_lock);
edge_port->port = port;
edge_port->edge_serial = usb_get_serial_data(port->serial);
edge_port->bUartMode = default_uart_mode;
+ switch (port->port_number) {
+ case 0:
+ edge_port->uart_base = UMPMEM_BASE_UART1;
+ edge_port->dma_address = UMPD_OEDB1_ADDRESS;
+ break;
+ case 1:
+ edge_port->uart_base = UMPMEM_BASE_UART2;
+ edge_port->dma_address = UMPD_OEDB2_ADDRESS;
+ break;
+ default:
+ dev_err(&port->dev, "unknown port number\n");
+ ret = -ENODEV;
+ goto err;
+ }
+
+ dev_dbg(&port->dev,
+ "%s - port_number = %d, uart_base = %04x, dma_address = %04x\n",
+ __func__, port->port_number, edge_port->uart_base,
+ edge_port->dma_address);
+
usb_set_serial_port_data(port, edge_port);
ret = edge_create_sysfs_attrs(port);
- if (ret) {
- kfifo_free(&edge_port->write_fifo);
- kfree(edge_port);
- return ret;
- }
+ if (ret)
+ goto err;
+
+ port->port.closing_wait = msecs_to_jiffies(closing_wait * 10);
+ port->port.drain_delay = 1;
return 0;
+err:
+ kfree(edge_port);
+
+ return ret;
}
static int edge_port_remove(struct usb_serial_port *port)
@@ -2599,9 +2465,7 @@ static int edge_port_remove(struct usb_serial_port *port)
struct edgeport_port *edge_port;
edge_port = usb_get_serial_port_data(port);
-
edge_remove_sysfs_attrs(port);
- kfifo_free(&edge_port->write_fifo);
kfree(edge_port);
return 0;
@@ -2609,7 +2473,7 @@ static int edge_port_remove(struct usb_serial_port *port)
/* Sysfs Attributes */
-static ssize_t show_uart_mode(struct device *dev,
+static ssize_t uart_mode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct usb_serial_port *port = to_usb_serial_port(dev);
@@ -2618,7 +2482,7 @@ static ssize_t show_uart_mode(struct device *dev,
return sprintf(buf, "%d\n", edge_port->bUartMode);
}
-static ssize_t store_uart_mode(struct device *dev,
+static ssize_t uart_mode_store(struct device *dev,
struct device_attribute *attr, const char *valbuf, size_t count)
{
struct usb_serial_port *port = to_usb_serial_port(dev);
@@ -2634,9 +2498,7 @@ static ssize_t store_uart_mode(struct device *dev,
return count;
}
-
-static DEVICE_ATTR(uart_mode, S_IWUSR | S_IRUGO, show_uart_mode,
- store_uart_mode);
+static DEVICE_ATTR_RW(uart_mode);
static int edge_create_sysfs_attrs(struct usb_serial_port *port)
{
@@ -2671,10 +2533,12 @@ static struct usb_serial_driver edgeport_1port_device = {
.set_termios = edge_set_termios,
.tiocmget = edge_tiocmget,
.tiocmset = edge_tiocmset,
- .get_icount = edge_get_icount,
+ .tiocmiwait = usb_serial_generic_tiocmiwait,
+ .get_icount = usb_serial_generic_get_icount,
.write = edge_write,
.write_room = edge_write_room,
.chars_in_buffer = edge_chars_in_buffer,
+ .tx_empty = edge_tx_empty,
.break_ctl = edge_break,
.read_int_callback = edge_interrupt_callback,
.read_bulk_callback = edge_bulk_in_callback,
@@ -2702,9 +2566,12 @@ static struct usb_serial_driver edgeport_2port_device = {
.set_termios = edge_set_termios,
.tiocmget = edge_tiocmget,
.tiocmset = edge_tiocmset,
+ .tiocmiwait = usb_serial_generic_tiocmiwait,
+ .get_icount = usb_serial_generic_get_icount,
.write = edge_write,
.write_room = edge_write_room,
.chars_in_buffer = edge_chars_in_buffer,
+ .tx_empty = edge_tx_empty,
.break_ctl = edge_break,
.read_int_callback = edge_interrupt_callback,
.read_bulk_callback = edge_bulk_in_callback,
diff --git a/drivers/usb/serial/io_usbvend.h b/drivers/usb/serial/io_usbvend.h
index 51f83fbb73b..6f6a856bc37 100644
--- a/drivers/usb/serial/io_usbvend.h
+++ b/drivers/usb/serial/io_usbvend.h
@@ -594,7 +594,7 @@ struct edge_boot_descriptor {
struct ti_i2c_desc {
__u8 Type; // Type of descriptor
- __u16 Size; // Size of data only not including header
+ __le16 Size; // Size of data only not including header
__u8 CheckSum; // Checksum (8 bit sum of data only)
__u8 Data[0]; // Data starts here
} __attribute__((packed));
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index 76c9a847da5..f51a5d52c0e 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -12,7 +12,6 @@
#include <linux/kernel.h>
#include <linux/errno.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
@@ -37,7 +36,7 @@ static int ipaq_open(struct tty_struct *tty,
static int ipaq_calc_num_ports(struct usb_serial *serial);
static int ipaq_startup(struct usb_serial *serial);
-static struct usb_device_id ipaq_id_table [] = {
+static const struct usb_device_id ipaq_id_table[] = {
{ USB_DEVICE(0x0104, 0x00BE) }, /* Socket USB Sync */
{ USB_DEVICE(0x03F0, 0x1016) }, /* HP USB Sync */
{ USB_DEVICE(0x03F0, 0x1116) }, /* HP USB Sync 1611 */
diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c
index 155eab14b30..8b1cf18a668 100644
--- a/drivers/usb/serial/ipw.c
+++ b/drivers/usb/serial/ipw.c
@@ -38,7 +38,6 @@
#include <linux/kernel.h>
#include <linux/errno.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
index e24e2d4f4c1..73956d48a0c 100644
--- a/drivers/usb/serial/ir-usb.c
+++ b/drivers/usb/serial/ir-usb.c
@@ -287,7 +287,6 @@ static void ir_process_read_urb(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
unsigned char *data = urb->transfer_buffer;
- struct tty_struct *tty;
if (!urb->actual_length)
return;
@@ -302,12 +301,8 @@ static void ir_process_read_urb(struct urb *urb)
if (urb->actual_length == 1)
return;
- tty = tty_port_tty_get(&port->port);
- if (!tty)
- return;
- tty_insert_flip_string(tty, data + 1, urb->actual_length - 1);
- tty_flip_buffer_push(tty);
- tty_kref_put(tty);
+ tty_insert_flip_string(&port->port, data + 1, urb->actual_length - 1);
+ tty_flip_buffer_push(&port->port);
}
static void ir_set_termios_callback(struct urb *urb)
@@ -382,15 +377,12 @@ static void ir_set_termios(struct tty_struct *tty,
* send the baud change out on an "empty" data packet
*/
urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!urb) {
- dev_err(&port->dev, "%s - no more urbs\n", __func__);
+ if (!urb)
return;
- }
+
transfer_buffer = kmalloc(1, GFP_KERNEL);
- if (!transfer_buffer) {
- dev_err(&port->dev, "%s - out of memory\n", __func__);
+ if (!transfer_buffer)
goto err_buf;
- }
*transfer_buffer = ir_xbof | ir_baud;
diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c
index 1e1fbed65ef..5ad4a0fb4b2 100644
--- a/drivers/usb/serial/iuu_phoenix.c
+++ b/drivers/usb/serial/iuu_phoenix.c
@@ -17,7 +17,6 @@
*/
#include <linux/kernel.h>
#include <linux/errno.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
@@ -55,7 +54,6 @@ static void read_rxcmd_callback(struct urb *urb);
struct iuu_private {
spinlock_t lock; /* store irq state */
- wait_queue_head_t delta_msr_wait;
u8 line_status;
int tiostatus; /* store IUART SIGNAL for tiocmget call */
u8 reset; /* if 1 reset is needed */
@@ -94,7 +92,6 @@ static int iuu_port_probe(struct usb_serial_port *port)
priv->vcc = vcc_default;
spin_lock_init(&priv->lock);
- init_waitqueue_head(&priv->delta_msr_wait);
usb_set_serial_port_data(port, priv);
@@ -289,7 +286,7 @@ static int bulk_immediate(struct usb_serial_port *port, u8 *buf, u8 count)
usb_bulk_msg(serial->dev,
usb_sndbulkpipe(serial->dev,
port->bulk_out_endpointAddress), buf,
- count, &actual, HZ * 1);
+ count, &actual, 1000);
if (status != IUU_OPERATION_OK)
dev_dbg(&port->dev, "%s - error = %2x\n", __func__, status);
@@ -309,7 +306,7 @@ static int read_immediate(struct usb_serial_port *port, u8 *buf, u8 count)
usb_bulk_msg(serial->dev,
usb_rcvbulkpipe(serial->dev,
port->bulk_in_endpointAddress), buf,
- count, &actual, HZ * 1);
+ count, &actual, 1000);
if (status != IUU_OPERATION_OK)
dev_dbg(&port->dev, "%s - error = %2x\n", __func__, status);
@@ -581,7 +578,6 @@ static void read_buf_callback(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
unsigned char *data = urb->transfer_buffer;
- struct tty_struct *tty;
int status = urb->status;
if (status) {
@@ -592,14 +588,12 @@ static void read_buf_callback(struct urb *urb)
}
dev_dbg(&port->dev, "%s - %i chars to write\n", __func__, urb->actual_length);
- tty = tty_port_tty_get(&port->port);
if (data == NULL)
dev_dbg(&port->dev, "%s - data is NULL !!!\n", __func__);
- if (tty && urb->actual_length && data) {
- tty_insert_flip_string(tty, data, urb->actual_length);
- tty_flip_buffer_push(tty);
+ if (urb->actual_length && data) {
+ tty_insert_flip_string(&port->port, data, urb->actual_length);
+ tty_flip_buffer_push(&port->port);
}
- tty_kref_put(tty);
iuu_led_activity_on(urb);
}
@@ -775,7 +769,7 @@ uart_enable_failed:
return status;
}
-/* Diables the IUU UART (a.k.a. the Phoenix voiderface) */
+/* Disables the IUU UART (a.k.a. the Phoenix voiderface) */
static int iuu_uart_off(struct usb_serial_port *port)
{
int status;
@@ -947,22 +941,13 @@ static void iuu_set_termios(struct tty_struct *tty,
static void iuu_close(struct usb_serial_port *port)
{
/* iuu_led (port,255,0,0,0); */
- struct usb_serial *serial;
-
- serial = port->serial;
- if (!serial)
- return;
iuu_uart_off(port);
- if (serial->dev) {
- /* free writebuf */
- /* shutdown our urbs */
- dev_dbg(&port->dev, "%s - shutting down urbs\n", __func__);
- usb_kill_urb(port->write_urb);
- usb_kill_urb(port->read_urb);
- usb_kill_urb(port->interrupt_in_urb);
- iuu_led(port, 0, 0, 0xF000, 0xFF);
- }
+
+ usb_kill_urb(port->write_urb);
+ usb_kill_urb(port->read_urb);
+
+ iuu_led(port, 0, 0, 0xF000, 0xFF);
}
static void iuu_init_termios(struct tty_struct *tty)
@@ -1144,7 +1129,7 @@ static int iuu_vcc_set(struct usb_serial_port *port, unsigned int vcc)
* Sysfs Attributes
*/
-static ssize_t show_vcc_mode(struct device *dev,
+static ssize_t vcc_mode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct usb_serial_port *port = to_usb_serial_port(dev);
@@ -1153,7 +1138,7 @@ static ssize_t show_vcc_mode(struct device *dev,
return sprintf(buf, "%d\n", priv->vcc);
}
-static ssize_t store_vcc_mode(struct device *dev,
+static ssize_t vcc_mode_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct usb_serial_port *port = to_usb_serial_port(dev);
@@ -1166,7 +1151,7 @@ static ssize_t store_vcc_mode(struct device *dev,
goto fail_store_vcc_mode;
}
- dev_dbg(dev, "%s: setting vcc_mode = %ld", __func__, v);
+ dev_dbg(dev, "%s: setting vcc_mode = %ld\n", __func__, v);
if ((v != 3) && (v != 5)) {
dev_err(dev, "%s - vcc_mode %ld is invalid\n", __func__, v);
@@ -1177,9 +1162,7 @@ static ssize_t store_vcc_mode(struct device *dev,
fail_store_vcc_mode:
return count;
}
-
-static DEVICE_ATTR(vcc_mode, S_IRUSR | S_IWUSR, show_vcc_mode,
- store_vcc_mode);
+static DEVICE_ATTR_RW(vcc_mode);
static int iuu_create_sysfs_attrs(struct usb_serial_port *port)
{
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index 97bc49f68ef..93cb7cebda6 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -31,7 +31,6 @@
#include <linux/kernel.h>
#include <linux/jiffies.h>
#include <linux/errno.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
@@ -50,23 +49,27 @@
#define INSTAT_BUFLEN 32
#define GLOCONT_BUFLEN 64
#define INDAT49W_BUFLEN 512
+#define IN_BUFLEN 64
+#define OUT_BUFLEN 64
+#define INACK_BUFLEN 1
+#define OUTCONT_BUFLEN 64
/* Per device and per port private data */
struct keyspan_serial_private {
const struct keyspan_device_details *device_details;
struct urb *instat_urb;
- char instat_buf[INSTAT_BUFLEN];
+ char *instat_buf;
/* added to support 49wg, where data from all 4 ports comes in
on 1 EP and high-speed supported */
struct urb *indat_urb;
- char indat_buf[INDAT49W_BUFLEN];
+ char *indat_buf;
/* XXX this one probably will need a lock */
struct urb *glocont_urb;
- char glocont_buf[GLOCONT_BUFLEN];
- char ctrl_buf[8]; /* for EP0 control message */
+ char *glocont_buf;
+ char *ctrl_buf; /* for EP0 control message */
};
struct keyspan_port_private {
@@ -81,18 +84,18 @@ struct keyspan_port_private {
/* Input endpoints and buffer for this port */
struct urb *in_urbs[2];
- char in_buffer[2][64];
+ char *in_buffer[2];
/* Output endpoints and buffer for this port */
struct urb *out_urbs[2];
- char out_buffer[2][64];
+ char *out_buffer[2];
/* Input ack endpoint */
struct urb *inack_urb;
- char inack_buffer[1];
+ char *inack_buffer;
/* Output control endpoint */
struct urb *outcont_urb;
- char outcont_buffer[64];
+ char *outcont_buffer;
/* Settings for the port */
int baud;
@@ -152,7 +155,7 @@ static void keyspan_set_termios(struct tty_struct *tty,
p_priv = usb_get_serial_port_data(port);
d_details = p_priv->device_details;
cflag = tty->termios.c_cflag;
- device_port = port->number - port->serial->minor;
+ device_port = port->port_number;
/* Baud rate calculation takes baud rate as an integer
so other rates can be generated if desired. */
@@ -161,7 +164,7 @@ static void keyspan_set_termios(struct tty_struct *tty,
if (d_details->calculate_baud_rate(port, baud_rate, d_details->baudclk,
NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) {
/* FIXME - more to do here to ensure rate changes cleanly */
- /* FIXME - calcuate exact rate from divisor ? */
+ /* FIXME - calculate exact rate from divisor ? */
p_priv->baud = baud_rate;
} else
baud_rate = tty_termios_baud_rate(old_termios);
@@ -234,8 +237,8 @@ static int keyspan_write(struct tty_struct *tty,
dataOffset = 1;
}
- dev_dbg(&port->dev, "%s - for port %d (%d chars), flip=%d\n",
- __func__, port->number, count, p_priv->out_flip);
+ dev_dbg(&port->dev, "%s - %d chars, flip=%d\n", __func__, count,
+ p_priv->out_flip);
for (left = count; left > 0; left -= todo) {
todo = left;
@@ -291,21 +294,19 @@ static void usa26_indat_callback(struct urb *urb)
int i, err;
int endpoint;
struct usb_serial_port *port;
- struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
int status = urb->status;
endpoint = usb_pipeendpoint(urb->pipe);
if (status) {
- dev_dbg(&urb->dev->dev,"%s - nonzero status: %x on endpoint %d.\n",
+ dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
__func__, status, endpoint);
return;
}
port = urb->context;
- tty = tty_port_tty_get(&port->port);
- if (tty && urb->actual_length) {
+ if (urb->actual_length) {
/* 0x80 bit is error flag */
if ((data[0] & 0x80) == 0) {
/* no errors on individual bytes, only
@@ -315,7 +316,7 @@ static void usa26_indat_callback(struct urb *urb)
else
err = 0;
for (i = 1; i < urb->actual_length ; ++i)
- tty_insert_flip_char(tty, data[i], err);
+ tty_insert_flip_char(&port->port, data[i], err);
} else {
/* some bytes had errors, every byte has status */
dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__);
@@ -328,12 +329,12 @@ static void usa26_indat_callback(struct urb *urb)
if (stat & RXERROR_PARITY)
flag |= TTY_PARITY;
/* XXX should handle break (0x10) */
- tty_insert_flip_char(tty, data[i+1], flag);
+ tty_insert_flip_char(&port->port, data[i+1],
+ flag);
}
}
- tty_flip_buffer_push(tty);
+ tty_flip_buffer_push(&port->port);
}
- tty_kref_put(tty);
/* Resubmit urb so we continue receiving */
err = usb_submit_urb(urb, GFP_ATOMIC);
@@ -380,7 +381,6 @@ static void usa26_instat_callback(struct urb *urb)
struct usb_serial *serial;
struct usb_serial_port *port;
struct keyspan_port_private *p_priv;
- struct tty_struct *tty;
int old_dcd_state, err;
int status = urb->status;
@@ -397,17 +397,6 @@ static void usa26_instat_callback(struct urb *urb)
msg = (struct keyspan_usa26_portStatusMessage *)data;
-#if 0
- dev_dbg(&urb->dev->dev,
- "%s - port status: port %d cts %d dcd %d dsr %d ri %d toff %d txoff %d rxen %d cr %d",
- __func__, msg->port, msg->hskia_cts, msg->gpia_dcd, msg->dsr,
- msg->ri, msg->_txOff, msg->_txXoff, msg->rxEnabled,
- msg->controlResponse);
-#endif
-
- /* Now do something useful with the data */
-
-
/* Check port number from message and retrieve private data */
if (msg->port >= serial->num_ports) {
dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
@@ -423,12 +412,8 @@ static void usa26_instat_callback(struct urb *urb)
p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
p_priv->ri_state = ((msg->ri) ? 1 : 0);
- if (old_dcd_state != p_priv->dcd_state) {
- tty = tty_port_tty_get(&port->port);
- if (tty && !C_CLOCAL(tty))
- tty_hangup(tty);
- tty_kref_put(tty);
- }
+ if (old_dcd_state != p_priv->dcd_state)
+ tty_port_tty_hangup(&port->port, true);
/* Resubmit urb so we continue receiving */
err = usb_submit_urb(urb, GFP_ATOMIC);
@@ -446,7 +431,6 @@ static void usa28_indat_callback(struct urb *urb)
{
int err;
struct usb_serial_port *port;
- struct tty_struct *tty;
unsigned char *data;
struct keyspan_port_private *p_priv;
int status = urb->status;
@@ -469,12 +453,11 @@ static void usa28_indat_callback(struct urb *urb)
p_priv = usb_get_serial_port_data(port);
data = urb->transfer_buffer;
- tty = tty_port_tty_get(&port->port);
- if (tty && urb->actual_length) {
- tty_insert_flip_string(tty, data, urb->actual_length);
- tty_flip_buffer_push(tty);
+ if (urb->actual_length) {
+ tty_insert_flip_string(&port->port, data,
+ urb->actual_length);
+ tty_flip_buffer_push(&port->port);
}
- tty_kref_put(tty);
/* Resubmit urb so we continue receiving */
err = usb_submit_urb(urb, GFP_ATOMIC);
@@ -514,7 +497,6 @@ static void usa28_instat_callback(struct urb *urb)
struct usb_serial *serial;
struct usb_serial_port *port;
struct keyspan_port_private *p_priv;
- struct tty_struct *tty;
int old_dcd_state;
int status = urb->status;
@@ -530,14 +512,6 @@ static void usa28_instat_callback(struct urb *urb)
goto exit;
}
- /*
- dev_dbg(&urb->dev->dev,
- "%s %x %x %x %x %x %x %x %x %x %x %x %x", __func__,
- data[0], data[1], data[2], data[3], data[4], data[5],
- data[6], data[7], data[8], data[9], data[10], data[11]);
- */
-
- /* Now do something useful with the data */
msg = (struct keyspan_usa28_portStatusMessage *)data;
/* Check port number from message and retrieve private data */
@@ -555,12 +529,8 @@ static void usa28_instat_callback(struct urb *urb)
p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
p_priv->ri_state = ((msg->ri) ? 1 : 0);
- if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
- tty = tty_port_tty_get(&port->port);
- if (tty && !C_CLOCAL(tty))
- tty_hangup(tty);
- tty_kref_put(tty);
- }
+ if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
+ tty_port_tty_hangup(&port->port, true);
/* Resubmit urb so we continue receiving */
err = usb_submit_urb(urb, GFP_ATOMIC);
@@ -621,13 +591,6 @@ static void usa49_instat_callback(struct urb *urb)
goto exit;
}
- /*
- dev_dbg(&urb->dev->dev, "%s: %x %x %x %x %x %x %x %x %x %x %x",
- __func__, data[0], data[1], data[2], data[3], data[4],
- data[5], data[6], data[7], data[8], data[9], data[10]);
- */
-
- /* Now do something useful with the data */
msg = (struct keyspan_usa49_portStatusMessage *)data;
/* Check port number from message and retrieve private data */
@@ -646,12 +609,8 @@ static void usa49_instat_callback(struct urb *urb)
p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
p_priv->ri_state = ((msg->ri) ? 1 : 0);
- if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
- struct tty_struct *tty = tty_port_tty_get(&port->port);
- if (tty && !C_CLOCAL(tty))
- tty_hangup(tty);
- tty_kref_put(tty);
- }
+ if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
+ tty_port_tty_hangup(&port->port, true);
/* Resubmit urb so we continue receiving */
err = usb_submit_urb(urb, GFP_ATOMIC);
@@ -669,7 +628,6 @@ static void usa49_indat_callback(struct urb *urb)
int i, err;
int endpoint;
struct usb_serial_port *port;
- struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
int status = urb->status;
@@ -682,12 +640,11 @@ static void usa49_indat_callback(struct urb *urb)
}
port = urb->context;
- tty = tty_port_tty_get(&port->port);
- if (tty && urb->actual_length) {
+ if (urb->actual_length) {
/* 0x80 bit is error flag */
if ((data[0] & 0x80) == 0) {
/* no error on any byte */
- tty_insert_flip_string(tty, data + 1,
+ tty_insert_flip_string(&port->port, data + 1,
urb->actual_length - 1);
} else {
/* some bytes had errors, every byte has status */
@@ -700,12 +657,12 @@ static void usa49_indat_callback(struct urb *urb)
if (stat & RXERROR_PARITY)
flag |= TTY_PARITY;
/* XXX should handle break (0x10) */
- tty_insert_flip_char(tty, data[i+1], flag);
+ tty_insert_flip_char(&port->port, data[i+1],
+ flag);
}
}
- tty_flip_buffer_push(tty);
+ tty_flip_buffer_push(&port->port);
}
- tty_kref_put(tty);
/* Resubmit urb so we continue receiving */
err = usb_submit_urb(urb, GFP_ATOMIC);
@@ -718,7 +675,6 @@ static void usa49wg_indat_callback(struct urb *urb)
int i, len, x, err;
struct usb_serial *serial;
struct usb_serial_port *port;
- struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
int status = urb->status;
@@ -733,46 +689,45 @@ static void usa49wg_indat_callback(struct urb *urb)
i = 0;
len = 0;
- if (urb->actual_length) {
- while (i < urb->actual_length) {
+ while (i < urb->actual_length) {
- /* Check port number from message*/
- if (data[i] >= serial->num_ports) {
- dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n",
- __func__, data[i]);
- return;
- }
- port = serial->port[data[i++]];
- tty = tty_port_tty_get(&port->port);
- len = data[i++];
+ /* Check port number from message */
+ if (data[i] >= serial->num_ports) {
+ dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n",
+ __func__, data[i]);
+ return;
+ }
+ port = serial->port[data[i++]];
+ len = data[i++];
- /* 0x80 bit is error flag */
- if ((data[i] & 0x80) == 0) {
- /* no error on any byte */
- i++;
- for (x = 1; x < len ; ++x)
- tty_insert_flip_char(tty, data[i++], 0);
- } else {
- /*
- * some bytes had errors, every byte has status
- */
- for (x = 0; x + 1 < len; x += 2) {
- int stat = data[i], flag = 0;
- if (stat & RXERROR_OVERRUN)
- flag |= TTY_OVERRUN;
- if (stat & RXERROR_FRAMING)
- flag |= TTY_FRAME;
- if (stat & RXERROR_PARITY)
- flag |= TTY_PARITY;
- /* XXX should handle break (0x10) */
- tty_insert_flip_char(tty,
- data[i+1], flag);
- i += 2;
- }
+ /* 0x80 bit is error flag */
+ if ((data[i] & 0x80) == 0) {
+ /* no error on any byte */
+ i++;
+ for (x = 1; x < len && i < urb->actual_length; ++x)
+ tty_insert_flip_char(&port->port,
+ data[i++], 0);
+ } else {
+ /*
+ * some bytes had errors, every byte has status
+ */
+ for (x = 0; x + 1 < len &&
+ i + 1 < urb->actual_length; x += 2) {
+ int stat = data[i], flag = 0;
+
+ if (stat & RXERROR_OVERRUN)
+ flag |= TTY_OVERRUN;
+ if (stat & RXERROR_FRAMING)
+ flag |= TTY_FRAME;
+ if (stat & RXERROR_PARITY)
+ flag |= TTY_PARITY;
+ /* XXX should handle break (0x10) */
+ tty_insert_flip_char(&port->port, data[i+1],
+ flag);
+ i += 2;
}
- tty_flip_buffer_push(tty);
- tty_kref_put(tty);
}
+ tty_flip_buffer_push(&port->port);
}
/* Resubmit urb so we continue receiving */
@@ -792,7 +747,6 @@ static void usa90_indat_callback(struct urb *urb)
int endpoint;
struct usb_serial_port *port;
struct keyspan_port_private *p_priv;
- struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
int status = urb->status;
@@ -808,12 +762,12 @@ static void usa90_indat_callback(struct urb *urb)
p_priv = usb_get_serial_port_data(port);
if (urb->actual_length) {
- tty = tty_port_tty_get(&port->port);
/* if current mode is DMA, looks like usa28 format
otherwise looks like usa26 data format */
if (p_priv->baud > 57600)
- tty_insert_flip_string(tty, data, urb->actual_length);
+ tty_insert_flip_string(&port->port, data,
+ urb->actual_length);
else {
/* 0x80 bit is error flag */
if ((data[0] & 0x80) == 0) {
@@ -824,8 +778,8 @@ static void usa90_indat_callback(struct urb *urb)
else
err = 0;
for (i = 1; i < urb->actual_length ; ++i)
- tty_insert_flip_char(tty, data[i],
- err);
+ tty_insert_flip_char(&port->port,
+ data[i], err);
} else {
/* some bytes had errors, every byte has status */
dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__);
@@ -838,13 +792,12 @@ static void usa90_indat_callback(struct urb *urb)
if (stat & RXERROR_PARITY)
flag |= TTY_PARITY;
/* XXX should handle break (0x10) */
- tty_insert_flip_char(tty, data[i+1],
- flag);
+ tty_insert_flip_char(&port->port,
+ data[i+1], flag);
}
}
}
- tty_flip_buffer_push(tty);
- tty_kref_put(tty);
+ tty_flip_buffer_push(&port->port);
}
/* Resubmit urb so we continue receiving */
@@ -861,7 +814,6 @@ static void usa90_instat_callback(struct urb *urb)
struct usb_serial *serial;
struct usb_serial_port *port;
struct keyspan_port_private *p_priv;
- struct tty_struct *tty;
int old_dcd_state, err;
int status = urb->status;
@@ -890,12 +842,8 @@ static void usa90_instat_callback(struct urb *urb)
p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
p_priv->ri_state = ((msg->ri) ? 1 : 0);
- if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
- tty = tty_port_tty_get(&port->port);
- if (tty && !C_CLOCAL(tty))
- tty_hangup(tty);
- tty_kref_put(tty);
- }
+ if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
+ tty_port_tty_hangup(&port->port, true);
/* Resubmit urb so we continue receiving */
err = usb_submit_urb(urb, GFP_ATOMIC);
@@ -963,12 +911,8 @@ static void usa67_instat_callback(struct urb *urb)
p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
- if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
- struct tty_struct *tty = tty_port_tty_get(&port->port);
- if (tty && !C_CLOCAL(tty))
- tty_hangup(tty);
- tty_kref_put(tty);
- }
+ if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
+ tty_port_tty_hangup(&port->port, true);
/* Resubmit urb so we continue receiving */
err = usb_submit_urb(urb, GFP_ATOMIC);
@@ -1083,7 +1027,7 @@ static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port)
/* get the terminal config for the setup message now so we don't
* need to send 2 of them */
- device_port = port->number - port->serial->minor;
+ device_port = port->port_number;
if (tty) {
cflag = tty->termios.c_cflag;
/* Baud rate calculation takes baud rate as an integer
@@ -1125,7 +1069,6 @@ static void keyspan_dtr_rts(struct usb_serial_port *port, int on)
static void keyspan_close(struct usb_serial_port *port)
{
int i;
- struct usb_serial *serial = port->serial;
struct keyspan_port_private *p_priv;
p_priv = usb_get_serial_port_data(port);
@@ -1133,28 +1076,17 @@ static void keyspan_close(struct usb_serial_port *port)
p_priv->rts_state = 0;
p_priv->dtr_state = 0;
- if (serial->dev) {
- keyspan_send_setup(port, 2);
- /* pilot-xfer seems to work best with this delay */
- mdelay(100);
- /* keyspan_set_termios(port, NULL); */
- }
-
- /*while (p_priv->outcont_urb->status == -EINPROGRESS) {
- dev_dbg(&port->dev, "%s - urb in progress\n", __func__);
- }*/
+ keyspan_send_setup(port, 2);
+ /* pilot-xfer seems to work best with this delay */
+ mdelay(100);
p_priv->out_flip = 0;
p_priv->in_flip = 0;
- if (serial->dev) {
- /* Stop reading/writing urbs */
- stop_urb(p_priv->inack_urb);
- /* stop_urb(p_priv->outcont_urb); */
- for (i = 0; i < 2; i++) {
- stop_urb(p_priv->in_urbs[i]);
- stop_urb(p_priv->out_urbs[i]);
- }
+ stop_urb(p_priv->inack_urb);
+ for (i = 0; i < 2; i++) {
+ stop_urb(p_priv->in_urbs[i]);
+ stop_urb(p_priv->out_urbs[i]);
}
}
@@ -1276,10 +1208,8 @@ static struct urb *keyspan_setup_urb(struct usb_serial *serial, int endpoint,
dev_dbg(&serial->interface->dev, "%s - alloc for endpoint %d.\n", __func__, endpoint);
urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
- if (urb == NULL) {
- dev_dbg(&serial->interface->dev, "%s - alloc for endpoint %d failed.\n", __func__, endpoint);
+ if (!urb)
return NULL;
- }
if (endpoint == 0) {
/* control EP filled in when used */
@@ -1593,7 +1523,6 @@ static int keyspan_usa26_send_setup(struct usb_serial *serial,
struct keyspan_serial_private *s_priv;
struct keyspan_port_private *p_priv;
const struct keyspan_device_details *d_details;
- int outcont_urb;
struct urb *this_urb;
int device_port, err;
@@ -1602,19 +1531,18 @@ static int keyspan_usa26_send_setup(struct usb_serial *serial,
s_priv = usb_get_serial_data(serial);
p_priv = usb_get_serial_port_data(port);
d_details = s_priv->device_details;
- device_port = port->number - port->serial->minor;
+ device_port = port->port_number;
- outcont_urb = d_details->outcont_endpoints[port->number];
this_urb = p_priv->outcont_urb;
- dev_dbg(&port->dev, "%s - endpoint %d\n", __func__, usb_pipeendpoint(this_urb->pipe));
-
/* Make sure we have an urb then send the message */
if (this_urb == NULL) {
dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
return -1;
}
+ dev_dbg(&port->dev, "%s - endpoint %d\n", __func__, usb_pipeendpoint(this_urb->pipe));
+
/* Save reset port val for resend.
Don't overwrite resend for open/close condition. */
if ((reset_port + 1) > p_priv->resend_cont)
@@ -1730,14 +1658,6 @@ static int keyspan_usa26_send_setup(struct usb_serial *serial,
err = usb_submit_urb(this_urb, GFP_ATOMIC);
if (err != 0)
dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
-#if 0
- else {
- dev_dbg(&port->dev, "%s - usb_submit_urb(%d) OK %d bytes (end %d)\n", __func__
- outcont_urb, this_urb->transfer_buffer_length,
- usb_pipeendpoint(this_urb->pipe));
- }
-#endif
-
return 0;
}
@@ -1755,7 +1675,7 @@ static int keyspan_usa28_send_setup(struct usb_serial *serial,
s_priv = usb_get_serial_data(serial);
p_priv = usb_get_serial_port_data(port);
d_details = s_priv->device_details;
- device_port = port->number - port->serial->minor;
+ device_port = port->port_number;
/* only do something if we have a bulk out endpoint */
this_urb = p_priv->outcont_urb;
@@ -1856,12 +1776,6 @@ static int keyspan_usa28_send_setup(struct usb_serial *serial,
err = usb_submit_urb(this_urb, GFP_ATOMIC);
if (err != 0)
dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed\n", __func__);
-#if 0
- else {
- dev_dbg(&port->dev, "%s - usb_submit_urb(setup) OK %d bytes\n", __func__,
- this_urb->transfer_buffer_length);
- }
-#endif
return 0;
}
@@ -1885,17 +1799,16 @@ static int keyspan_usa49_send_setup(struct usb_serial *serial,
this_urb = s_priv->glocont_urb;
/* Work out which port within the device is being setup */
- device_port = port->number - port->serial->minor;
+ device_port = port->port_number;
/* Make sure we have an urb then send the message */
if (this_urb == NULL) {
- dev_dbg(&port->dev, "%s - oops no urb for port %d.\n", __func__, port->number);
+ dev_dbg(&port->dev, "%s - oops no urb for port.\n", __func__);
return -1;
}
- dev_dbg(&port->dev, "%s - endpoint %d port %d (%d)\n",
- __func__, usb_pipeendpoint(this_urb->pipe),
- port->number, device_port);
+ dev_dbg(&port->dev, "%s - endpoint %d (%d)\n",
+ __func__, usb_pipeendpoint(this_urb->pipe), device_port);
/* Save reset port val for resend.
Don't overwrite resend for open/close condition. */
@@ -1910,7 +1823,6 @@ static int keyspan_usa49_send_setup(struct usb_serial *serial,
memset(&msg, 0, sizeof(struct keyspan_usa49_portControlMessage));
- /*msg.portNumber = port->number;*/
msg.portNumber = device_port;
/* Only set baud rate if it's changed */
@@ -2041,13 +1953,6 @@ static int keyspan_usa49_send_setup(struct usb_serial *serial,
err = usb_submit_urb(this_urb, GFP_ATOMIC);
if (err != 0)
dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
-#if 0
- else {
- dev_dbg(&port->dev, "%s - usb_submit_urb(%d) OK %d bytes (end %d)\n", __func__,
- outcont_urb, this_urb->transfer_buffer_length,
- usb_pipeendpoint(this_urb->pipe));
- }
-#endif
return 0;
}
@@ -2200,12 +2105,11 @@ static int keyspan_usa67_send_setup(struct usb_serial *serial,
this_urb = s_priv->glocont_urb;
/* Work out which port within the device is being setup */
- device_port = port->number - port->serial->minor;
+ device_port = port->port_number;
/* Make sure we have an urb then send the message */
if (this_urb == NULL) {
- dev_dbg(&port->dev, "%s - oops no urb for port %d.\n", __func__,
- port->number);
+ dev_dbg(&port->dev, "%s - oops no urb for port.\n", __func__);
return -1;
}
@@ -2370,15 +2274,29 @@ static int keyspan_startup(struct usb_serial *serial)
if (d_details == NULL) {
dev_err(&serial->dev->dev, "%s - unknown product id %x\n",
__func__, le16_to_cpu(serial->dev->descriptor.idProduct));
- return 1;
+ return -ENODEV;
}
/* Setup private data for serial driver */
s_priv = kzalloc(sizeof(struct keyspan_serial_private), GFP_KERNEL);
- if (!s_priv) {
- dev_dbg(&serial->dev->dev, "%s - kmalloc for keyspan_serial_private failed.\n", __func__);
+ if (!s_priv)
return -ENOMEM;
- }
+
+ s_priv->instat_buf = kzalloc(INSTAT_BUFLEN, GFP_KERNEL);
+ if (!s_priv->instat_buf)
+ goto err_instat_buf;
+
+ s_priv->indat_buf = kzalloc(INDAT49W_BUFLEN, GFP_KERNEL);
+ if (!s_priv->indat_buf)
+ goto err_indat_buf;
+
+ s_priv->glocont_buf = kzalloc(GLOCONT_BUFLEN, GFP_KERNEL);
+ if (!s_priv->glocont_buf)
+ goto err_glocont_buf;
+
+ s_priv->ctrl_buf = kzalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
+ if (!s_priv->ctrl_buf)
+ goto err_ctrl_buf;
s_priv->device_details = d_details;
usb_set_serial_data(serial, s_priv);
@@ -2397,6 +2315,17 @@ static int keyspan_startup(struct usb_serial *serial)
}
return 0;
+
+err_ctrl_buf:
+ kfree(s_priv->glocont_buf);
+err_glocont_buf:
+ kfree(s_priv->indat_buf);
+err_indat_buf:
+ kfree(s_priv->instat_buf);
+err_instat_buf:
+ kfree(s_priv);
+
+ return -ENOMEM;
}
static void keyspan_disconnect(struct usb_serial *serial)
@@ -2420,6 +2349,11 @@ static void keyspan_release(struct usb_serial *serial)
usb_free_urb(s_priv->indat_urb);
usb_free_urb(s_priv->glocont_urb);
+ kfree(s_priv->ctrl_buf);
+ kfree(s_priv->glocont_buf);
+ kfree(s_priv->indat_buf);
+ kfree(s_priv->instat_buf);
+
kfree(s_priv);
}
@@ -2441,19 +2375,40 @@ static int keyspan_port_probe(struct usb_serial_port *port)
if (!p_priv)
return -ENOMEM;
+ for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i) {
+ p_priv->in_buffer[i] = kzalloc(IN_BUFLEN, GFP_KERNEL);
+ if (!p_priv->in_buffer[i])
+ goto err_in_buffer;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i) {
+ p_priv->out_buffer[i] = kzalloc(OUT_BUFLEN, GFP_KERNEL);
+ if (!p_priv->out_buffer[i])
+ goto err_out_buffer;
+ }
+
+ p_priv->inack_buffer = kzalloc(INACK_BUFLEN, GFP_KERNEL);
+ if (!p_priv->inack_buffer)
+ goto err_inack_buffer;
+
+ p_priv->outcont_buffer = kzalloc(OUTCONT_BUFLEN, GFP_KERNEL);
+ if (!p_priv->outcont_buffer)
+ goto err_outcont_buffer;
+
p_priv->device_details = d_details;
/* Setup values for the various callback routines */
cback = &keyspan_callbacks[d_details->msg_format];
- port_num = port->number - port->serial->minor;
+ port_num = port->port_number;
/* Do indat endpoints first, once for each flip */
endp = d_details->indat_endpoints[port_num];
for (i = 0; i <= d_details->indat_endp_flip; ++i, ++endp) {
p_priv->in_urbs[i] = keyspan_setup_urb(serial, endp,
USB_DIR_IN, port,
- p_priv->in_buffer[i], 64,
+ p_priv->in_buffer[i],
+ IN_BUFLEN,
cback->indat_callback);
}
/* outdat endpoints also have flip */
@@ -2461,25 +2416,41 @@ static int keyspan_port_probe(struct usb_serial_port *port)
for (i = 0; i <= d_details->outdat_endp_flip; ++i, ++endp) {
p_priv->out_urbs[i] = keyspan_setup_urb(serial, endp,
USB_DIR_OUT, port,
- p_priv->out_buffer[i], 64,
+ p_priv->out_buffer[i],
+ OUT_BUFLEN,
cback->outdat_callback);
}
/* inack endpoint */
p_priv->inack_urb = keyspan_setup_urb(serial,
d_details->inack_endpoints[port_num],
USB_DIR_IN, port,
- p_priv->inack_buffer, 1,
+ p_priv->inack_buffer,
+ INACK_BUFLEN,
cback->inack_callback);
/* outcont endpoint */
p_priv->outcont_urb = keyspan_setup_urb(serial,
d_details->outcont_endpoints[port_num],
USB_DIR_OUT, port,
- p_priv->outcont_buffer, 64,
+ p_priv->outcont_buffer,
+ OUTCONT_BUFLEN,
cback->outcont_callback);
usb_set_serial_port_data(port, p_priv);
return 0;
+
+err_outcont_buffer:
+ kfree(p_priv->inack_buffer);
+err_inack_buffer:
+ for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i)
+ kfree(p_priv->out_buffer[i]);
+err_out_buffer:
+ for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i)
+ kfree(p_priv->in_buffer[i]);
+err_in_buffer:
+ kfree(p_priv);
+
+ return -ENOMEM;
}
static int keyspan_port_remove(struct usb_serial_port *port)
@@ -2503,6 +2474,13 @@ static int keyspan_port_remove(struct usb_serial_port *port)
usb_free_urb(p_priv->out_urbs[i]);
}
+ kfree(p_priv->outcont_buffer);
+ kfree(p_priv->inack_buffer);
+ for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i)
+ kfree(p_priv->out_buffer[i]);
+ for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i)
+ kfree(p_priv->in_buffer[i]);
+
kfree(p_priv);
return 0;
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index 41b01092af0..742d827f876 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -17,7 +17,6 @@
#include <linux/kernel.h>
#include <linux/errno.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
@@ -104,10 +103,8 @@ static void keyspan_pda_wakeup_write(struct work_struct *work)
struct keyspan_pda_private *priv =
container_of(work, struct keyspan_pda_private, wakeup_work);
struct usb_serial_port *port = priv->port;
- struct tty_struct *tty = tty_port_tty_get(&port->port);
- if (tty)
- tty_wakeup(tty);
- tty_kref_put(tty);
+
+ tty_port_tty_wakeup(&port->port);
}
static void keyspan_pda_request_unthrottle(struct work_struct *work)
@@ -138,7 +135,6 @@ static void keyspan_pda_request_unthrottle(struct work_struct *work)
static void keyspan_pda_rx_interrupt(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
- struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
int retval;
int status = urb->status;
@@ -163,14 +159,12 @@ static void keyspan_pda_rx_interrupt(struct urb *urb)
/* see if the message is data or a status interrupt */
switch (data[0]) {
case 0:
- tty = tty_port_tty_get(&port->port);
/* rest of message is rx data */
- if (tty && urb->actual_length) {
- tty_insert_flip_string(tty, data + 1,
+ if (urb->actual_length) {
+ tty_insert_flip_string(&port->port, data + 1,
urb->actual_length - 1);
- tty_flip_buffer_push(tty);
+ tty_flip_buffer_push(&port->port);
}
- tty_kref_put(tty);
break;
case 1:
/* status interrupt */
@@ -195,7 +189,7 @@ exit:
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval)
dev_err(&port->dev,
- "%s - usb_submit_urb failed with result %d",
+ "%s - usb_submit_urb failed with result %d\n",
__func__, retval);
}
@@ -598,12 +592,10 @@ static void keyspan_pda_dtr_rts(struct usb_serial_port *port, int on)
{
struct usb_serial *serial = port->serial;
- if (serial->dev) {
- if (on)
- keyspan_pda_set_modem_info(serial, (1<<7) | (1<< 2));
- else
- keyspan_pda_set_modem_info(serial, 0);
- }
+ if (on)
+ keyspan_pda_set_modem_info(serial, (1 << 7) | (1 << 2));
+ else
+ keyspan_pda_set_modem_info(serial, 0);
}
@@ -654,13 +646,8 @@ error:
}
static void keyspan_pda_close(struct usb_serial_port *port)
{
- struct usb_serial *serial = port->serial;
-
- if (serial->dev) {
- /* shutdown our bulk reads and writes */
- usb_kill_urb(port->write_urb);
- usb_kill_urb(port->interrupt_in_urb);
- }
+ usb_kill_urb(port->write_urb);
+ usb_kill_urb(port->interrupt_in_urb);
}
diff --git a/drivers/usb/serial/keyspan_usa26msg.h b/drivers/usb/serial/keyspan_usa26msg.h
index 3808727db65..09e21e84fc4 100644
--- a/drivers/usb/serial/keyspan_usa26msg.h
+++ b/drivers/usb/serial/keyspan_usa26msg.h
@@ -62,7 +62,7 @@
or:
(b) 0x80 bit set
- indiates that the bytes following alternate data and
+ indicates that the bytes following alternate data and
status bytes:
STAT DATA STAT DATA STAT DATA STAT DATA ...
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index fc9e14a1e9b..d7440b7557a 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -37,7 +37,6 @@
#include <linux/kernel.h>
#include <linux/errno.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
@@ -182,11 +181,9 @@ static int klsi_105_get_line_state(struct usb_serial_port *port,
dev_info(&port->serial->dev->dev, "sending SIO Poll request\n");
status_buf = kmalloc(KLSI_STATUSBUF_LEN, GFP_KERNEL);
- if (!status_buf) {
- dev_err(&port->dev, "%s - out of memory for status buffer.\n",
- __func__);
+ if (!status_buf)
return -ENOMEM;
- }
+
status_buf[0] = 0xff;
status_buf[1] = 0xff;
rc = usb_control_msg(port->serial->dev,
@@ -204,7 +201,7 @@ static int klsi_105_get_line_state(struct usb_serial_port *port,
else {
status = get_unaligned_le16(status_buf);
- dev_info(&port->serial->dev->dev, "read status %x %x",
+ dev_info(&port->serial->dev->dev, "read status %x %x\n",
status_buf[0], status_buf[1]);
*line_state_p = klsi_105_status2linestate(status);
@@ -273,11 +270,9 @@ static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port)
* priv->line_state.
*/
cfg = kmalloc(sizeof(*cfg), GFP_KERNEL);
- if (!cfg) {
- dev_err(&port->dev, "%s - out of memory for config buffer.\n",
- __func__);
+ if (!cfg)
return -ENOMEM;
- }
+
cfg->pktlen = 5;
cfg->baudrate = kl5kusb105a_sio_b9600;
cfg->databits = kl5kusb105a_dtb_8;
@@ -341,28 +336,20 @@ static void klsi_105_close(struct usb_serial_port *port)
{
int rc;
- mutex_lock(&port->serial->disc_mutex);
- if (!port->serial->disconnected) {
- /* send READ_OFF */
- rc = usb_control_msg(port->serial->dev,
- usb_sndctrlpipe(port->serial->dev, 0),
- KL5KUSB105A_SIO_CONFIGURE,
- USB_TYPE_VENDOR | USB_DIR_OUT,
- KL5KUSB105A_SIO_CONFIGURE_READ_OFF,
- 0, /* index */
- NULL, 0,
- KLSI_TIMEOUT);
- if (rc < 0)
- dev_err(&port->dev,
- "Disabling read failed (error = %d)\n", rc);
- }
- mutex_unlock(&port->serial->disc_mutex);
+ /* send READ_OFF */
+ rc = usb_control_msg(port->serial->dev,
+ usb_sndctrlpipe(port->serial->dev, 0),
+ KL5KUSB105A_SIO_CONFIGURE,
+ USB_TYPE_VENDOR | USB_DIR_OUT,
+ KL5KUSB105A_SIO_CONFIGURE_READ_OFF,
+ 0, /* index */
+ NULL, 0,
+ KLSI_TIMEOUT);
+ if (rc < 0)
+ dev_err(&port->dev, "failed to disable read: %d\n", rc);
/* shutdown our bulk reads and writes */
usb_serial_generic_close(port);
-
- /* wgg - do I need this? I think so. */
- usb_kill_urb(port->interrupt_in_urb);
}
/* We need to write a complete 64-byte data block and encode the
@@ -389,7 +376,6 @@ static void klsi_105_process_read_urb(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
unsigned char *data = urb->transfer_buffer;
- struct tty_struct *tty;
unsigned len;
/* empty urbs seem to happen, we ignore them */
@@ -401,19 +387,14 @@ static void klsi_105_process_read_urb(struct urb *urb)
return;
}
- tty = tty_port_tty_get(&port->port);
- if (!tty)
- return;
-
len = get_unaligned_le16(data);
if (len > urb->actual_length - KLSI_HDR_LEN) {
dev_dbg(&port->dev, "%s - packet length mismatch\n", __func__);
len = urb->actual_length - KLSI_HDR_LEN;
}
- tty_insert_flip_string(tty, data + KLSI_HDR_LEN, len);
- tty_flip_buffer_push(tty);
- tty_kref_put(tty);
+ tty_insert_flip_string(&port->port, data + KLSI_HDR_LEN, len);
+ tty_flip_buffer_push(&port->port);
}
static void klsi_105_set_termios(struct tty_struct *tty,
@@ -431,10 +412,8 @@ static void klsi_105_set_termios(struct tty_struct *tty,
speed_t baud;
cfg = kmalloc(sizeof(*cfg), GFP_KERNEL);
- if (!cfg) {
- dev_err(dev, "%s - out of memory for config buffer.\n", __func__);
+ if (!cfg)
return;
- }
/* lock while we are modifying the settings */
spin_lock_irqsave(&priv->lock, flags);
@@ -485,7 +464,7 @@ static void klsi_105_set_termios(struct tty_struct *tty,
priv->cfg.baudrate = kl5kusb105a_sio_b115200;
break;
default:
- dev_dbg(dev, "KLSI USB->Serial converter: unsupported baudrate request, using default of 9600");
+ dev_dbg(dev, "unsupported baudrate, using 9600\n");
priv->cfg.baudrate = kl5kusb105a_sio_b9600;
baud = 9600;
break;
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
index b747ba615d0..078f9ed419c 100644
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -25,7 +25,6 @@
#include <linux/kernel.h>
#include <linux/errno.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
@@ -65,7 +64,7 @@ static int kobil_tiocmget(struct tty_struct *tty);
static int kobil_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear);
static void kobil_read_int_callback(struct urb *urb);
-static void kobil_write_callback(struct urb *purb);
+static void kobil_write_int_callback(struct urb *urb);
static void kobil_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old);
static void kobil_init_termios(struct tty_struct *tty);
@@ -99,6 +98,7 @@ static struct usb_serial_driver kobil_device = {
.write = kobil_write,
.write_room = kobil_write_room,
.read_int_callback = kobil_read_int_callback,
+ .write_int_callback = kobil_write_int_callback,
};
static struct usb_serial_driver * const serial_drivers[] = {
@@ -106,8 +106,6 @@ static struct usb_serial_driver * const serial_drivers[] = {
};
struct kobil_private {
- int write_int_endpoint_address;
- int read_int_endpoint_address;
unsigned char buf[KOBIL_BUF_LENGTH]; /* buffer for the APDU to send */
int filled; /* index of the last char in buf */
int cur_pos; /* index of the next char to send in buf */
@@ -117,14 +115,8 @@ struct kobil_private {
static int kobil_port_probe(struct usb_serial_port *port)
{
- int i;
struct usb_serial *serial = port->serial;
struct kobil_private *priv;
- struct usb_device *pdev;
- struct usb_host_config *actconfig;
- struct usb_interface *interface;
- struct usb_host_interface *altsetting;
- struct usb_host_endpoint *endpoint;
priv = kmalloc(sizeof(struct kobil_private), GFP_KERNEL);
if (!priv)
@@ -150,30 +142,6 @@ static int kobil_port_probe(struct usb_serial_port *port)
}
usb_set_serial_port_data(port, priv);
- /* search for the necessary endpoints */
- pdev = serial->dev;
- actconfig = pdev->actconfig;
- interface = actconfig->interface[0];
- altsetting = interface->cur_altsetting;
- endpoint = altsetting->endpoint;
-
- for (i = 0; i < altsetting->desc.bNumEndpoints; i++) {
- endpoint = &altsetting->endpoint[i];
- if (usb_endpoint_is_int_out(&endpoint->desc)) {
- dev_dbg(&serial->dev->dev,
- "%s Found interrupt out endpoint. Address: %d\n",
- __func__, endpoint->desc.bEndpointAddress);
- priv->write_int_endpoint_address =
- endpoint->desc.bEndpointAddress;
- }
- if (usb_endpoint_is_int_in(&endpoint->desc)) {
- dev_dbg(&serial->dev->dev,
- "%s Found interrupt in endpoint. Address: %d\n",
- __func__, endpoint->desc.bEndpointAddress);
- priv->read_int_endpoint_address =
- endpoint->desc.bEndpointAddress;
- }
- }
return 0;
}
@@ -205,7 +173,6 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port)
struct kobil_private *priv;
unsigned char *transfer_buffer;
int transfer_buffer_length = 8;
- int write_urb_transfer_buffer_length = 8;
priv = usb_get_serial_port_data(port);
@@ -214,27 +181,6 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port)
if (!transfer_buffer)
return -ENOMEM;
- /* allocate write_urb */
- if (!port->write_urb) {
- dev_dbg(dev, "%s - Allocating port->write_urb\n", __func__);
- port->write_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!port->write_urb) {
- dev_dbg(dev, "%s - usb_alloc_urb failed\n", __func__);
- kfree(transfer_buffer);
- return -ENOMEM;
- }
- }
-
- /* allocate memory for write_urb transfer buffer */
- port->write_urb->transfer_buffer =
- kmalloc(write_urb_transfer_buffer_length, GFP_KERNEL);
- if (!port->write_urb->transfer_buffer) {
- kfree(transfer_buffer);
- usb_free_urb(port->write_urb);
- port->write_urb = NULL;
- return -ENOMEM;
- }
-
/* get hardware version */
result = usb_control_msg(port->serial->dev,
usb_rcvctrlpipe(port->serial->dev, 0),
@@ -247,7 +193,7 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port)
KOBIL_TIMEOUT
);
dev_dbg(dev, "%s - Send get_HW_version URB returns: %i\n", __func__, result);
- dev_dbg(dev, "Harware version: %i.%i.%i\n", transfer_buffer[0],
+ dev_dbg(dev, "Hardware version: %i.%i.%i\n", transfer_buffer[0],
transfer_buffer[1], transfer_buffer[2]);
/* get firmware version */
@@ -269,13 +215,13 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port)
priv->device_type == KOBIL_ADAPTER_K_PRODUCT_ID) {
/* Setting Baudrate, Parity and Stopbits */
result = usb_control_msg(port->serial->dev,
- usb_rcvctrlpipe(port->serial->dev, 0),
+ usb_sndctrlpipe(port->serial->dev, 0),
SUSBCRequest_SetBaudRateParityAndStopBits,
USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
SUSBCR_SBR_9600 | SUSBCR_SPASB_EvenParity |
SUSBCR_SPASB_1StopBit,
0,
- transfer_buffer,
+ NULL,
0,
KOBIL_TIMEOUT
);
@@ -283,12 +229,12 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port)
/* reset all queues */
result = usb_control_msg(port->serial->dev,
- usb_rcvctrlpipe(port->serial->dev, 0),
+ usb_sndctrlpipe(port->serial->dev, 0),
SUSBCRequest_Misc,
USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
SUSBCR_MSC_ResetAllQueues,
0,
- transfer_buffer,
+ NULL,
0,
KOBIL_TIMEOUT
);
@@ -310,12 +256,7 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port)
static void kobil_close(struct usb_serial_port *port)
{
/* FIXME: Add rts/dtr methods */
- if (port->write_urb) {
- usb_poison_urb(port->write_urb);
- kfree(port->write_urb->transfer_buffer);
- usb_free_urb(port->write_urb);
- port->write_urb = NULL;
- }
+ usb_kill_urb(port->interrupt_out_urb);
usb_kill_urb(port->interrupt_in_urb);
}
@@ -324,7 +265,6 @@ static void kobil_read_int_callback(struct urb *urb)
{
int result;
struct usb_serial_port *port = urb->context;
- struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
int status = urb->status;
@@ -333,37 +273,19 @@ static void kobil_read_int_callback(struct urb *urb)
return;
}
- tty = tty_port_tty_get(&port->port);
- if (tty && urb->actual_length) {
-
- /* BEGIN DEBUG */
- /*
- char *dbg_data;
-
- dbg_data = kzalloc((3 * purb->actual_length + 10)
- * sizeof(char), GFP_KERNEL);
- if (! dbg_data) {
- return;
- }
- for (i = 0; i < purb->actual_length; i++) {
- sprintf(dbg_data +3*i, "%02X ", data[i]);
- }
- dev_dbg(&port->dev, " <-- %s\n", dbg_data);
- kfree(dbg_data);
- */
- /* END DEBUG */
-
- tty_insert_flip_string(tty, data, urb->actual_length);
- tty_flip_buffer_push(tty);
+ if (urb->actual_length) {
+ usb_serial_debug_data(&port->dev, __func__, urb->actual_length,
+ data);
+ tty_insert_flip_string(&port->port, data, urb->actual_length);
+ tty_flip_buffer_push(&port->port);
}
- tty_kref_put(tty);
result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
dev_dbg(&port->dev, "%s - Send read URB returns: %i\n", __func__, result);
}
-static void kobil_write_callback(struct urb *purb)
+static void kobil_write_int_callback(struct urb *urb)
{
}
@@ -406,23 +328,14 @@ static int kobil_write(struct tty_struct *tty, struct usb_serial_port *port,
while (todo > 0) {
/* max 8 byte in one urb (endpoint size) */
- length = (todo < 8) ? todo : 8;
+ length = min(todo, port->interrupt_out_size);
/* copy data to transfer buffer */
- memcpy(port->write_urb->transfer_buffer,
+ memcpy(port->interrupt_out_buffer,
priv->buf + priv->cur_pos, length);
- usb_fill_int_urb(port->write_urb,
- port->serial->dev,
- usb_sndintpipe(port->serial->dev,
- priv->write_int_endpoint_address),
- port->write_urb->transfer_buffer,
- length,
- kobil_write_callback,
- port,
- 8
- );
+ port->interrupt_out_urb->transfer_buffer_length = length;
priv->cur_pos = priv->cur_pos + length;
- result = usb_submit_urb(port->write_urb, GFP_NOIO);
+ result = usb_submit_urb(port->interrupt_out_urb, GFP_NOIO);
dev_dbg(&port->dev, "%s - Send write URB returns: %i\n", __func__, result);
todo = priv->filled - priv->cur_pos;
@@ -532,12 +445,12 @@ static int kobil_tiocmset(struct tty_struct *tty,
else
dev_dbg(dev, "%s - Clearing DTR\n", __func__);
result = usb_control_msg(port->serial->dev,
- usb_rcvctrlpipe(port->serial->dev, 0),
+ usb_sndctrlpipe(port->serial->dev, 0),
SUSBCRequest_SetStatusLinesOrQueues,
USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
((dtr != 0) ? SUSBCR_SSL_SETDTR : SUSBCR_SSL_CLRDTR),
0,
- transfer_buffer,
+ NULL,
0,
KOBIL_TIMEOUT);
} else {
@@ -546,12 +459,12 @@ static int kobil_tiocmset(struct tty_struct *tty,
else
dev_dbg(dev, "%s - Clearing RTS\n", __func__);
result = usb_control_msg(port->serial->dev,
- usb_rcvctrlpipe(port->serial->dev, 0),
+ usb_sndctrlpipe(port->serial->dev, 0),
SUSBCRequest_SetStatusLinesOrQueues,
USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
((rts != 0) ? SUSBCR_SSL_SETRTS : SUSBCR_SSL_CLRRTS),
0,
- transfer_buffer,
+ NULL,
0,
KOBIL_TIMEOUT);
}
@@ -601,7 +514,7 @@ static void kobil_set_termios(struct tty_struct *tty,
tty_encode_baud_rate(tty, speed, speed);
result = usb_control_msg(port->serial->dev,
- usb_rcvctrlpipe(port->serial->dev, 0),
+ usb_sndctrlpipe(port->serial->dev, 0),
SUSBCRequest_SetBaudRateParityAndStopBits,
USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
urb_val,
@@ -633,18 +546,19 @@ static int kobil_ioctl(struct tty_struct *tty,
return -ENOBUFS;
result = usb_control_msg(port->serial->dev,
- usb_rcvctrlpipe(port->serial->dev, 0),
+ usb_sndctrlpipe(port->serial->dev, 0),
SUSBCRequest_Misc,
USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
SUSBCR_MSC_ResetAllQueues,
0,
- NULL, /* transfer_buffer, */
+ NULL,
0,
KOBIL_TIMEOUT
);
dev_dbg(&port->dev,
- "%s - Send reset_all_queues (FLUSH) URB returns: %i", __func__, result);
+ "%s - Send reset_all_queues (FLUSH) URB returns: %i\n",
+ __func__, result);
kfree(transfer_buffer);
return (result < 0) ? -EIO: 0;
default:
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index b6911757c85..fd707d6a10e 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -23,7 +23,6 @@
#include <linux/kernel.h>
#include <linux/errno.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
@@ -35,7 +34,6 @@
#include <linux/usb.h>
#include <linux/usb/serial.h>
#include <linux/serial.h>
-#include <linux/ioctl.h>
#include "mct_u232.h"
#define DRIVER_AUTHOR "Wolfgang Grandegger <wolfgang@ces.ch>"
@@ -44,7 +42,6 @@
/*
* Function prototypes
*/
-static int mct_u232_startup(struct usb_serial *serial);
static int mct_u232_port_probe(struct usb_serial_port *port);
static int mct_u232_port_remove(struct usb_serial_port *remove);
static int mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port);
@@ -57,10 +54,6 @@ static void mct_u232_break_ctl(struct tty_struct *tty, int break_state);
static int mct_u232_tiocmget(struct tty_struct *tty);
static int mct_u232_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear);
-static int mct_u232_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg);
-static int mct_u232_get_icount(struct tty_struct *tty,
- struct serial_icounter_struct *icount);
static void mct_u232_throttle(struct tty_struct *tty);
static void mct_u232_unthrottle(struct tty_struct *tty);
@@ -95,11 +88,10 @@ static struct usb_serial_driver mct_u232_device = {
.break_ctl = mct_u232_break_ctl,
.tiocmget = mct_u232_tiocmget,
.tiocmset = mct_u232_tiocmset,
- .attach = mct_u232_startup,
+ .tiocmiwait = usb_serial_generic_tiocmiwait,
.port_probe = mct_u232_port_probe,
.port_remove = mct_u232_port_remove,
- .ioctl = mct_u232_ioctl,
- .get_icount = mct_u232_get_icount,
+ .get_icount = usb_serial_generic_get_icount,
};
static struct usb_serial_driver * const serial_drivers[] = {
@@ -107,15 +99,13 @@ static struct usb_serial_driver * const serial_drivers[] = {
};
struct mct_u232_private {
+ struct urb *read_urb;
spinlock_t lock;
unsigned int control_state; /* Modem Line Setting (TIOCM) */
unsigned char last_lcr; /* Line Control Register */
unsigned char last_lsr; /* Line Status Register */
unsigned char last_msr; /* Modem Status Register */
unsigned int rx_flags; /* Throttling flags */
- struct async_icount icount;
- wait_queue_head_t msr_wait; /* for handling sleeping while waiting
- for msr change to happen */
};
#define THROTTLED 0x01
@@ -384,22 +374,6 @@ static void mct_u232_msr_to_state(struct usb_serial_port *port,
* Driver's tty interface functions
*/
-static int mct_u232_startup(struct usb_serial *serial)
-{
- struct usb_serial_port *port, *rport;
-
- /* Puh, that's dirty */
- port = serial->port[0];
- rport = serial->port[1];
- /* No unlinking, it wasn't submitted yet. */
- usb_free_urb(port->read_urb);
- port->read_urb = rport->interrupt_in_urb;
- rport->interrupt_in_urb = NULL;
- port->read_urb->context = port;
-
- return 0;
-} /* mct_u232_startup */
-
static int mct_u232_port_probe(struct usb_serial_port *port)
{
struct mct_u232_private *priv;
@@ -408,8 +382,11 @@ static int mct_u232_port_probe(struct usb_serial_port *port)
if (!priv)
return -ENOMEM;
+ /* Use second interrupt-in endpoint for reading. */
+ priv->read_urb = port->serial->port[1]->interrupt_in_urb;
+ priv->read_urb->context = port;
+
spin_lock_init(&priv->lock);
- init_waitqueue_head(&priv->msr_wait);
usb_set_serial_port_data(port, priv);
@@ -472,17 +449,17 @@ static int mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port)
mct_u232_msr_to_state(port, &priv->control_state, priv->last_msr);
spin_unlock_irqrestore(&priv->lock, flags);
- retval = usb_submit_urb(port->read_urb, GFP_KERNEL);
+ retval = usb_submit_urb(priv->read_urb, GFP_KERNEL);
if (retval) {
dev_err(&port->dev,
- "usb_submit_urb(read bulk) failed pipe 0x%x err %d\n",
+ "usb_submit_urb(read) failed pipe 0x%x err %d\n",
port->read_urb->pipe, retval);
goto error;
}
retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (retval) {
- usb_kill_urb(port->read_urb);
+ usb_kill_urb(priv->read_urb);
dev_err(&port->dev,
"usb_submit_urb(read int) failed pipe 0x%x err %d",
port->interrupt_in_urb->pipe, retval);
@@ -499,28 +476,22 @@ static void mct_u232_dtr_rts(struct usb_serial_port *port, int on)
unsigned int control_state;
struct mct_u232_private *priv = usb_get_serial_port_data(port);
- mutex_lock(&port->serial->disc_mutex);
- if (!port->serial->disconnected) {
- /* drop DTR and RTS */
- spin_lock_irq(&priv->lock);
- if (on)
- priv->control_state |= TIOCM_DTR | TIOCM_RTS;
- else
- priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
- control_state = priv->control_state;
- spin_unlock_irq(&priv->lock);
- mct_u232_set_modem_ctrl(port, control_state);
- }
- mutex_unlock(&port->serial->disc_mutex);
+ spin_lock_irq(&priv->lock);
+ if (on)
+ priv->control_state |= TIOCM_DTR | TIOCM_RTS;
+ else
+ priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
+ control_state = priv->control_state;
+ spin_unlock_irq(&priv->lock);
+
+ mct_u232_set_modem_ctrl(port, control_state);
}
static void mct_u232_close(struct usb_serial_port *port)
{
- /*
- * Must kill the read urb as it is actually an interrupt urb, which
- * generic close thus fails to kill.
- */
- usb_kill_urb(port->read_urb);
+ struct mct_u232_private *priv = usb_get_serial_port_data(port);
+
+ usb_kill_urb(priv->read_urb);
usb_kill_urb(port->interrupt_in_urb);
usb_serial_generic_close(port);
@@ -531,7 +502,6 @@ static void mct_u232_read_int_callback(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
struct mct_u232_private *priv = usb_get_serial_port_data(port);
- struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
int retval;
int status = urb->status;
@@ -561,13 +531,9 @@ static void mct_u232_read_int_callback(struct urb *urb)
*/
if (urb->transfer_buffer_length > 2) {
if (urb->actual_length) {
- tty = tty_port_tty_get(&port->port);
- if (tty) {
- tty_insert_flip_string(tty, data,
- urb->actual_length);
- tty_flip_buffer_push(tty);
- }
- tty_kref_put(tty);
+ tty_insert_flip_string(&port->port, data,
+ urb->actual_length);
+ tty_flip_buffer_push(&port->port);
}
goto exit;
}
@@ -582,7 +548,7 @@ static void mct_u232_read_int_callback(struct urb *urb)
/* Record Control Line states */
mct_u232_msr_to_state(port, &priv->control_state, priv->last_msr);
- mct_u232_msr_to_icount(&priv->icount, priv->last_msr);
+ mct_u232_msr_to_icount(&port->icount, priv->last_msr);
#if 0
/* Not yet handled. See belkin_sa.c for further information */
@@ -610,7 +576,7 @@ static void mct_u232_read_int_callback(struct urb *urb)
tty_kref_put(tty);
}
#endif
- wake_up_interruptible(&priv->msr_wait);
+ wake_up_interruptible(&port->port.delta_msr_wait);
spin_unlock_irqrestore(&priv->lock, flags);
exit:
retval = usb_submit_urb(urb, GFP_ATOMIC);
@@ -798,82 +764,6 @@ static void mct_u232_unthrottle(struct tty_struct *tty)
}
}
-static int mct_u232_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
-{
- DEFINE_WAIT(wait);
- struct usb_serial_port *port = tty->driver_data;
- struct mct_u232_private *mct_u232_port = usb_get_serial_port_data(port);
- struct async_icount cnow, cprev;
- unsigned long flags;
-
- dev_dbg(&port->dev, "%s - cmd = 0x%x\n", __func__, cmd);
-
- switch (cmd) {
-
- case TIOCMIWAIT:
-
- dev_dbg(&port->dev, "%s TIOCMIWAIT", __func__);
-
- spin_lock_irqsave(&mct_u232_port->lock, flags);
- cprev = mct_u232_port->icount;
- spin_unlock_irqrestore(&mct_u232_port->lock, flags);
- for ( ; ; ) {
- prepare_to_wait(&mct_u232_port->msr_wait,
- &wait, TASK_INTERRUPTIBLE);
- schedule();
- finish_wait(&mct_u232_port->msr_wait, &wait);
- /* see if a signal did it */
- if (signal_pending(current))
- return -ERESTARTSYS;
- spin_lock_irqsave(&mct_u232_port->lock, flags);
- cnow = mct_u232_port->icount;
- spin_unlock_irqrestore(&mct_u232_port->lock, flags);
- if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
- cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
- return -EIO; /* no change => error */
- if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
- ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
- ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
- ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
- return 0;
- }
- cprev = cnow;
- }
-
- }
- return -ENOIOCTLCMD;
-}
-
-static int mct_u232_get_icount(struct tty_struct *tty,
- struct serial_icounter_struct *icount)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct mct_u232_private *mct_u232_port = usb_get_serial_port_data(port);
- struct async_icount *ic = &mct_u232_port->icount;
- unsigned long flags;
-
- spin_lock_irqsave(&mct_u232_port->lock, flags);
-
- icount->cts = ic->cts;
- icount->dsr = ic->dsr;
- icount->rng = ic->rng;
- icount->dcd = ic->dcd;
- icount->rx = ic->rx;
- icount->tx = ic->tx;
- icount->frame = ic->frame;
- icount->overrun = ic->overrun;
- icount->parity = ic->parity;
- icount->brk = ic->brk;
- icount->buf_overrun = ic->buf_overrun;
-
- spin_unlock_irqrestore(&mct_u232_port->lock, flags);
-
- dev_dbg(&port->dev, "%s TIOCGICOUNT RX=%d, TX=%d\n",
- __func__, icount->rx, icount->tx);
- return 0;
-}
-
module_usb_serial_driver(serial_drivers, id_table);
MODULE_AUTHOR(DRIVER_AUTHOR);
diff --git a/drivers/usb/serial/metro-usb.c b/drivers/usb/serial/metro-usb.c
index 3d258448c29..39e683096e9 100644
--- a/drivers/usb/serial/metro-usb.c
+++ b/drivers/usb/serial/metro-usb.c
@@ -7,7 +7,6 @@
*/
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/tty.h>
#include <linux/module.h>
#include <linux/usb.h>
@@ -43,7 +42,7 @@ struct metrousb_private {
};
/* Device table list. */
-static struct usb_device_id id_table[] = {
+static const struct usb_device_id id_table[] = {
{ USB_DEVICE(FOCUS_VENDOR_ID, FOCUS_PRODUCT_ID_BI) },
{ USB_DEVICE(FOCUS_VENDOR_ID, FOCUS_PRODUCT_ID_UNI) },
{ }, /* Terminating entry. */
@@ -54,7 +53,7 @@ MODULE_DEVICE_TABLE(usb, id_table);
#define UNI_CMD_OPEN 0x80
#define UNI_CMD_CLOSE 0xFF
-inline int metrousb_is_unidirectional_mode(struct usb_serial_port *port)
+static inline int metrousb_is_unidirectional_mode(struct usb_serial_port *port)
{
__u16 product_id = le16_to_cpu(
port->serial->dev->descriptor.idProduct);
@@ -95,7 +94,6 @@ static void metrousb_read_int_callback(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
- struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
int throttled = 0;
int result = 0;
@@ -124,15 +122,13 @@ static void metrousb_read_int_callback(struct urb *urb)
/* Set the data read from the usb port into the serial port buffer. */
- tty = tty_port_tty_get(&port->port);
- if (tty && urb->actual_length) {
+ if (urb->actual_length) {
/* Loop through the data copying each byte to the tty layer. */
- tty_insert_flip_string(tty, data, urb->actual_length);
+ tty_insert_flip_string(&port->port, data, urb->actual_length);
/* Force the data to the tty layer. */
- tty_flip_buffer_push(tty);
+ tty_flip_buffer_push(&port->port);
}
- tty_kref_put(tty);
/* Set any port variables. */
spin_lock_irqsave(&metro_priv->lock, flags);
@@ -180,10 +176,7 @@ static void metrousb_cleanup(struct usb_serial_port *port)
usb_unlink_urb(port->interrupt_in_urb);
usb_kill_urb(port->interrupt_in_urb);
- mutex_lock(&port->serial->disc_mutex);
- if (!port->serial->disconnected)
- metrousb_send_unidirectional_cmd(UNI_CMD_CLOSE, port);
- mutex_unlock(&port->serial->disc_mutex);
+ metrousb_send_unidirectional_cmd(UNI_CMD_CLOSE, port);
}
static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port)
@@ -230,8 +223,8 @@ static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port)
result = metrousb_send_unidirectional_cmd(UNI_CMD_OPEN, port);
if (result) {
dev_err(&port->dev,
- "%s - failed to configure device for port number=%d, error code=%d\n",
- __func__, port->number, result);
+ "%s - failed to configure device, error code=%d\n",
+ __func__, result);
goto exit;
}
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index f57a6b1fe78..dfd728a263d 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -1,6 +1,6 @@
/*
* mos7720.c
- * Controls the Moschip 7720 usb to dual port serial convertor
+ * Controls the Moschip 7720 usb to dual port serial converter
*
* Copyright 2006 Moschip Semiconductor Tech. Ltd.
*
@@ -22,7 +22,6 @@
*/
#include <linux/kernel.h>
#include <linux/errno.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
@@ -40,13 +39,13 @@
#define DRIVER_DESC "Moschip USB Serial Driver"
/* default urb timeout */
-#define MOS_WDR_TIMEOUT (HZ * 5)
+#define MOS_WDR_TIMEOUT 5000
#define MOS_MAX_PORT 0x02
#define MOS_WRITE 0x0E
#define MOS_READ 0x0D
-/* Interrupt Rotinue Defines */
+/* Interrupt Routines Defines */
#define SERIAL_IIR_RLS 0x06
#define SERIAL_IIR_RDA 0x04
#define SERIAL_IIR_CTI 0x0c
@@ -62,7 +61,6 @@ struct moschip_port {
__u8 shadowMCR; /* last MCR value received */
__u8 shadowMSR; /* last MSR value received */
char open;
- struct async_icount icount;
struct usb_serial_port *port; /* loop back to the owner */
struct urb *write_urb_pool[NUM_URBS];
};
@@ -91,6 +89,7 @@ struct urbtracker {
struct list_head urblist_entry;
struct kref ref_count;
struct urb *urb;
+ struct usb_ctrlrequest *setup;
};
enum mos7715_pp_modes {
@@ -210,7 +209,7 @@ static int write_mos_reg(struct usb_serial *serial, unsigned int serial_portnum,
index, NULL, 0, MOS_WDR_TIMEOUT);
if (status < 0)
dev_err(&usbdev->dev,
- "mos7720: usb_control_msg() failed: %d", status);
+ "mos7720: usb_control_msg() failed: %d\n", status);
return status;
}
@@ -228,11 +227,22 @@ static int read_mos_reg(struct usb_serial *serial, unsigned int serial_portnum,
__u8 requesttype = (__u8)0xc0;
__u16 index = get_reg_index(reg);
__u16 value = get_reg_value(reg, serial_portnum);
- int status = usb_control_msg(usbdev, pipe, request, requesttype, value,
- index, data, 1, MOS_WDR_TIMEOUT);
- if (status < 0)
+ u8 *buf;
+ int status;
+
+ buf = kmalloc(1, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ status = usb_control_msg(usbdev, pipe, request, requesttype, value,
+ index, buf, 1, MOS_WDR_TIMEOUT);
+ if (status == 1)
+ *data = *buf;
+ else if (status < 0)
dev_err(&usbdev->dev,
- "mos7720: usb_control_msg() failed: %d", status);
+ "mos7720: usb_control_msg() failed: %d\n", status);
+ kfree(buf);
+
return status;
}
@@ -261,6 +271,7 @@ static void destroy_urbtracker(struct kref *kref)
struct mos7715_parport *mos_parport = urbtrack->mos_parport;
usb_free_urb(urbtrack->urb);
+ kfree(urbtrack->setup);
kfree(urbtrack);
kref_put(&mos_parport->ref_count, destroy_mos_parport);
}
@@ -345,32 +356,35 @@ static int write_parport_reg_nonblock(struct mos7715_parport *mos_parport,
struct urbtracker *urbtrack;
int ret_val;
unsigned long flags;
- struct usb_ctrlrequest setup;
struct usb_serial *serial = mos_parport->serial;
struct usb_device *usbdev = serial->dev;
/* create and initialize the control urb and containing urbtracker */
urbtrack = kmalloc(sizeof(struct urbtracker), GFP_ATOMIC);
- if (urbtrack == NULL) {
- dev_err(&usbdev->dev, "out of memory");
+ if (!urbtrack)
return -ENOMEM;
- }
+
kref_get(&mos_parport->ref_count);
urbtrack->mos_parport = mos_parport;
urbtrack->urb = usb_alloc_urb(0, GFP_ATOMIC);
- if (urbtrack->urb == NULL) {
- dev_err(&usbdev->dev, "out of urbs");
+ if (!urbtrack->urb) {
kfree(urbtrack);
return -ENOMEM;
}
- setup.bRequestType = (__u8)0x40;
- setup.bRequest = (__u8)0x0e;
- setup.wValue = get_reg_value(reg, dummy);
- setup.wIndex = get_reg_index(reg);
- setup.wLength = 0;
+ urbtrack->setup = kmalloc(sizeof(*urbtrack->setup), GFP_ATOMIC);
+ if (!urbtrack->setup) {
+ usb_free_urb(urbtrack->urb);
+ kfree(urbtrack);
+ return -ENOMEM;
+ }
+ urbtrack->setup->bRequestType = (__u8)0x40;
+ urbtrack->setup->bRequest = (__u8)0x0e;
+ urbtrack->setup->wValue = cpu_to_le16(get_reg_value(reg, dummy));
+ urbtrack->setup->wIndex = cpu_to_le16(get_reg_index(reg));
+ urbtrack->setup->wLength = 0;
usb_fill_control_urb(urbtrack->urb, usbdev,
usb_sndctrlpipe(usbdev, 0),
- (unsigned char *)&setup,
+ (unsigned char *)urbtrack->setup,
NULL, 0, async_complete, urbtrack);
kref_init(&urbtrack->ref_count);
INIT_LIST_HEAD(&urbtrack->urblist_entry);
@@ -385,7 +399,7 @@ static int write_parport_reg_nonblock(struct mos7715_parport *mos_parport,
&mos_parport->deferred_urbs);
spin_unlock_irqrestore(&mos_parport->listlock, flags);
tasklet_schedule(&mos_parport->urb_tasklet);
- dev_dbg(&usbdev->dev, "tasklet scheduled");
+ dev_dbg(&usbdev->dev, "tasklet scheduled\n");
return 0;
}
@@ -404,7 +418,7 @@ static int write_parport_reg_nonblock(struct mos7715_parport *mos_parport,
mutex_unlock(&serial->disc_mutex);
if (ret_val) {
dev_err(&usbdev->dev,
- "%s: submit_urb() failed: %d", __func__, ret_val);
+ "%s: submit_urb() failed: %d\n", __func__, ret_val);
spin_lock_irqsave(&mos_parport->listlock, flags);
list_del(&urbtrack->urblist_entry);
spin_unlock_irqrestore(&mos_parport->listlock, flags);
@@ -423,7 +437,7 @@ static int write_parport_reg_nonblock(struct mos7715_parport *mos_parport,
* not called the release function yet because someone has a serial port open.
* The shared release_lock prevents the first, and the mutex and disconnected
* flag maintained by usbserial covers the second. We also use the msg_pending
- * flag to ensure that all synchronous usb messgage calls have completed before
+ * flag to ensure that all synchronous usb message calls have completed before
* our release function can return.
*/
static int parport_prologue(struct parport *pp)
@@ -438,7 +452,7 @@ static int parport_prologue(struct parport *pp)
return -1;
}
mos_parport->msg_pending = true; /* synch usb call pending */
- INIT_COMPLETION(mos_parport->syncmsg_compl);
+ reinit_completion(&mos_parport->syncmsg_compl);
spin_unlock(&release_lock);
mutex_lock(&mos_parport->serial->disc_mutex);
@@ -454,7 +468,7 @@ static int parport_prologue(struct parport *pp)
}
/*
- * This is the the common bottom part of all parallel port functions that send
+ * This is the common bottom part of all parallel port functions that send
* synchronous messages to the device.
*/
static inline void parport_epilogue(struct parport *pp)
@@ -642,7 +656,7 @@ static size_t parport_mos7715_write_compat(struct parport *pp,
parport_epilogue(pp);
if (retval) {
dev_err(&mos_parport->serial->dev->dev,
- "mos7720: usb_bulk_msg() failed: %d", retval);
+ "mos7720: usb_bulk_msg() failed: %d\n", retval);
return 0;
}
return actual_len;
@@ -685,10 +699,9 @@ static int mos7715_parport_init(struct usb_serial *serial)
/* allocate and initialize parallel port control struct */
mos_parport = kzalloc(sizeof(struct mos7715_parport), GFP_KERNEL);
- if (mos_parport == NULL) {
- dev_dbg(&serial->dev->dev, "%s: kzalloc failed\n", __func__);
+ if (!mos_parport)
return -ENOMEM;
- }
+
mos_parport->msg_pending = false;
kref_init(&mos_parport->ref_count);
spin_lock_init(&mos_parport->listlock);
@@ -862,7 +875,7 @@ static void mos7715_interrupt_callback(struct urb *urb)
if (!(iir & 0x01)) { /* serial port interrupt pending */
switch (iir & 0x0f) {
case SERIAL_IIR_RLS:
- dev_dbg(dev, "Serial Port: Receiver status error or address bit detected in 9-bit mode\n\n");
+ dev_dbg(dev, "Serial Port: Receiver status error or address bit detected in 9-bit mode\n");
break;
case SERIAL_IIR_CTI:
dev_dbg(dev, "Serial Port: Receiver time out\n");
@@ -899,7 +912,6 @@ static void mos7720_bulk_in_callback(struct urb *urb)
int retval;
unsigned char *data ;
struct usb_serial_port *port;
- struct tty_struct *tty;
int status = urb->status;
if (status) {
@@ -913,12 +925,10 @@ static void mos7720_bulk_in_callback(struct urb *urb)
data = urb->transfer_buffer;
- tty = tty_port_tty_get(&port->port);
- if (tty && urb->actual_length) {
- tty_insert_flip_string(tty, data, urb->actual_length);
- tty_flip_buffer_push(tty);
+ if (urb->actual_length) {
+ tty_insert_flip_string(&port->port, data, urb->actual_length);
+ tty_flip_buffer_push(&port->port);
}
- tty_kref_put(tty);
if (port->read_urb->status != -EINPROGRESS) {
retval = usb_submit_urb(port->read_urb, GFP_ATOMIC);
@@ -935,7 +945,6 @@ static void mos7720_bulk_in_callback(struct urb *urb)
static void mos7720_bulk_out_data_callback(struct urb *urb)
{
struct moschip_port *mos7720_port;
- struct tty_struct *tty;
int status = urb->status;
if (status) {
@@ -949,11 +958,8 @@ static void mos7720_bulk_out_data_callback(struct urb *urb)
return ;
}
- tty = tty_port_tty_get(&mos7720_port->port->port);
-
- if (tty && mos7720_port->open)
- tty_wakeup(tty);
- tty_kref_put(tty);
+ if (mos7720_port->open)
+ tty_port_tty_wakeup(&mos7720_port->port->port);
}
/*
@@ -1008,18 +1014,12 @@ static int mos7720_open(struct tty_struct *tty, struct usb_serial_port *port)
for (j = 0; j < NUM_URBS; ++j) {
urb = usb_alloc_urb(0, GFP_KERNEL);
mos7720_port->write_urb_pool[j] = urb;
-
- if (urb == NULL) {
- dev_err(&port->dev, "No more urbs???\n");
+ if (!urb)
continue;
- }
urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE,
GFP_KERNEL);
if (!urb->transfer_buffer) {
- dev_err(&port->dev,
- "%s-out of memory for urb buffers.\n",
- __func__);
usb_free_urb(mos7720_port->write_urb_pool[j]);
mos7720_port->write_urb_pool[j] = NULL;
continue;
@@ -1044,7 +1044,7 @@ static int mos7720_open(struct tty_struct *tty, struct usb_serial_port *port)
*
* 0x08 : SP1/2 Control Reg
*/
- port_number = port->number - port->serial->minor;
+ port_number = port->port_number;
read_mos_reg(serial, port_number, LSR, &data);
dev_dbg(&port->dev, "SS::%p LSR:%x\n", mos7720_port, data);
@@ -1063,7 +1063,7 @@ static int mos7720_open(struct tty_struct *tty, struct usb_serial_port *port)
write_mos_reg(serial, port_number, SP_CONTROL_REG, 0x00);
read_mos_reg(serial, dummy, SP_CONTROL_REG, &data);
- data = data | (port->number - port->serial->minor + 1);
+ data = data | (port->port_number + 1);
write_mos_reg(serial, dummy, SP_CONTROL_REG, data);
mos7720_port->shadowLCR = 0x83;
write_mos_reg(serial, port_number, LCR, mos7720_port->shadowLCR);
@@ -1078,9 +1078,6 @@ static int mos7720_open(struct tty_struct *tty, struct usb_serial_port *port)
dev_err(&port->dev, "%s - Error %d submitting read urb\n",
__func__, response);
- /* initialize our icount structure */
- memset(&(mos7720_port->icount), 0x00, sizeof(mos7720_port->icount));
-
/* initialize our port settings */
mos7720_port->shadowMCR = UART_MCR_OUT2; /* Must set to enable ints! */
@@ -1147,16 +1144,9 @@ static void mos7720_close(struct usb_serial_port *port)
usb_kill_urb(port->write_urb);
usb_kill_urb(port->read_urb);
- mutex_lock(&serial->disc_mutex);
- /* these commands must not be issued if the device has
- * been disconnected */
- if (!serial->disconnected) {
- write_mos_reg(serial, port->number - port->serial->minor,
- MCR, 0x00);
- write_mos_reg(serial, port->number - port->serial->minor,
- IER, 0x00);
- }
- mutex_unlock(&serial->disc_mutex);
+ write_mos_reg(serial, port->port_number, MCR, 0x00);
+ write_mos_reg(serial, port->port_number, IER, 0x00);
+
mos7720_port->open = 0;
}
@@ -1179,8 +1169,7 @@ static void mos7720_break(struct tty_struct *tty, int break_state)
data = mos7720_port->shadowLCR & ~UART_LCR_SBC;
mos7720_port->shadowLCR = data;
- write_mos_reg(serial, port->number - port->serial->minor,
- LCR, mos7720_port->shadowLCR);
+ write_mos_reg(serial, port->port_number, LCR, mos7720_port->shadowLCR);
}
/*
@@ -1251,11 +1240,8 @@ static int mos7720_write(struct tty_struct *tty, struct usb_serial_port *port,
if (urb->transfer_buffer == NULL) {
urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE,
GFP_KERNEL);
- if (urb->transfer_buffer == NULL) {
- dev_err_console(port, "%s no more kernel memory...\n",
- __func__);
+ if (!urb->transfer_buffer)
goto exit;
- }
}
transfer_size = min(count, URB_TRANSFER_BUFFER_SIZE);
@@ -1311,8 +1297,8 @@ static void mos7720_throttle(struct tty_struct *tty)
/* if we are implementing RTS/CTS, toggle that line */
if (tty->termios.c_cflag & CRTSCTS) {
mos7720_port->shadowMCR &= ~UART_MCR_RTS;
- write_mos_reg(port->serial, port->number - port->serial->minor,
- MCR, mos7720_port->shadowMCR);
+ write_mos_reg(port->serial, port->port_number, MCR,
+ mos7720_port->shadowMCR);
if (status != 0)
return;
}
@@ -1343,8 +1329,8 @@ static void mos7720_unthrottle(struct tty_struct *tty)
/* if we are implementing RTS/CTS, toggle that line */
if (tty->termios.c_cflag & CRTSCTS) {
mos7720_port->shadowMCR |= UART_MCR_RTS;
- write_mos_reg(port->serial, port->number - port->serial->minor,
- MCR, mos7720_port->shadowMCR);
+ write_mos_reg(port->serial, port->port_number, MCR,
+ mos7720_port->shadowMCR);
if (status != 0)
return;
}
@@ -1368,7 +1354,7 @@ static int set_higher_rates(struct moschip_port *mos7720_port,
* Init Sequence for higher rates
***********************************************/
dev_dbg(&port->dev, "Sending Setting Commands ..........\n");
- port_number = port->number - port->serial->minor;
+ port_number = port->port_number;
write_mos_reg(serial, port_number, IER, 0x00);
write_mos_reg(serial, port_number, FCR, 0x00);
@@ -1494,7 +1480,7 @@ static int send_cmd_write_baud_rate(struct moschip_port *mos7720_port,
port = mos7720_port->port;
serial = port->serial;
- number = port->number - port->serial->minor;
+ number = port->port_number;
dev_dbg(&port->dev, "%s - baud = %d\n", __func__, baudrate);
/* Calculate the Divisor */
@@ -1545,7 +1531,7 @@ static void change_port_settings(struct tty_struct *tty,
port = mos7720_port->port;
serial = port->serial;
- port_number = port->number - port->serial->minor;
+ port_number = port->port_number;
if (!mos7720_port->open) {
dev_dbg(&port->dev, "%s - port not opened\n", __func__);
@@ -1636,7 +1622,7 @@ static void change_port_settings(struct tty_struct *tty,
mos7720_port->shadowMCR |= (UART_MCR_XONANY);
/* To set hardware flow control to the specified *
* serial port, in SP1/2_CONTROL_REG */
- if (port->number)
+ if (port_number)
write_mos_reg(serial, dummy, SP_CONTROL_REG, 0x01);
else
write_mos_reg(serial, dummy, SP_CONTROL_REG, 0x02);
@@ -1738,7 +1724,7 @@ static int get_lsr_info(struct tty_struct *tty,
struct usb_serial_port *port = tty->driver_data;
unsigned int result = 0;
unsigned char data = 0;
- int port_number = port->number - port->serial->minor;
+ int port_number = port->port_number;
int count;
count = mos7720_chars_in_buffer(tty);
@@ -1800,39 +1786,12 @@ static int mos7720_tiocmset(struct tty_struct *tty,
mcr &= ~UART_MCR_LOOP;
mos7720_port->shadowMCR = mcr;
- write_mos_reg(port->serial, port->number - port->serial->minor,
- MCR, mos7720_port->shadowMCR);
+ write_mos_reg(port->serial, port->port_number, MCR,
+ mos7720_port->shadowMCR);
return 0;
}
-static int mos7720_get_icount(struct tty_struct *tty,
- struct serial_icounter_struct *icount)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct moschip_port *mos7720_port;
- struct async_icount cnow;
-
- mos7720_port = usb_get_serial_port_data(port);
- cnow = mos7720_port->icount;
-
- icount->cts = cnow.cts;
- icount->dsr = cnow.dsr;
- icount->rng = cnow.rng;
- icount->dcd = cnow.dcd;
- icount->rx = cnow.rx;
- icount->tx = cnow.tx;
- icount->frame = cnow.frame;
- icount->overrun = cnow.overrun;
- icount->parity = cnow.parity;
- icount->brk = cnow.brk;
- icount->buf_overrun = cnow.buf_overrun;
-
- dev_dbg(&port->dev, "%s TIOCGICOUNT RX=%d, TX=%d\n", __func__,
- icount->rx, icount->tx);
- return 0;
-}
-
static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd,
unsigned int __user *value)
{
@@ -1872,8 +1831,8 @@ static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd,
}
mos7720_port->shadowMCR = mcr;
- write_mos_reg(port->serial, port->number - port->serial->minor,
- MCR, mos7720_port->shadowMCR);
+ write_mos_reg(port->serial, port->port_number, MCR,
+ mos7720_port->shadowMCR);
return 0;
}
@@ -1889,8 +1848,8 @@ static int get_serial_info(struct moschip_port *mos7720_port,
memset(&tmp, 0, sizeof(tmp));
tmp.type = PORT_16550A;
- tmp.line = mos7720_port->port->serial->minor;
- tmp.port = mos7720_port->port->number;
+ tmp.line = mos7720_port->port->minor;
+ tmp.port = mos7720_port->port->port_number;
tmp.irq = 0;
tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
tmp.xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE;
@@ -1908,15 +1867,11 @@ static int mos7720_ioctl(struct tty_struct *tty,
{
struct usb_serial_port *port = tty->driver_data;
struct moschip_port *mos7720_port;
- struct async_icount cnow;
- struct async_icount cprev;
mos7720_port = usb_get_serial_port_data(port);
if (mos7720_port == NULL)
return -ENODEV;
- dev_dbg(&port->dev, "%s - cmd = 0x%x", __func__, cmd);
-
switch (cmd) {
case TIOCSERGETLSR:
dev_dbg(&port->dev, "%s TIOCSERGETLSR\n", __func__);
@@ -1934,27 +1889,6 @@ static int mos7720_ioctl(struct tty_struct *tty,
dev_dbg(&port->dev, "%s TIOCGSERIAL\n", __func__);
return get_serial_info(mos7720_port,
(struct serial_struct __user *)arg);
-
- case TIOCMIWAIT:
- dev_dbg(&port->dev, "%s TIOCMIWAIT\n", __func__);
- cprev = mos7720_port->icount;
- while (1) {
- if (signal_pending(current))
- return -ERESTARTSYS;
- cnow = mos7720_port->icount;
- if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
- cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
- return -EIO; /* no change => error */
- if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
- ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
- ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
- ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
- return 0;
- }
- cprev = cnow;
- }
- /* NOTREACHED */
- break;
}
return -ENOIOCTLCMD;
@@ -1995,7 +1929,7 @@ static int mos7720_startup(struct usb_serial *serial)
/* setting configuration feature to one */
usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- (__u8)0x03, 0x00, 0x01, 0x00, NULL, 0x00, 5*HZ);
+ (__u8)0x03, 0x00, 0x01, 0x00, NULL, 0x00, 5000);
/* start the interrupt urb */
ret_val = usb_submit_urb(serial->port[0]->interrupt_in_urb, GFP_KERNEL);
@@ -2038,7 +1972,7 @@ static void mos7720_release(struct usb_serial *serial)
/* wait for synchronous usb calls to return */
if (mos_parport->msg_pending)
wait_for_completion_timeout(&mos_parport->syncmsg_compl,
- MOS_WDR_TIMEOUT);
+ msecs_to_jiffies(MOS_WDR_TIMEOUT));
parport_remove_port(mos_parport->pp);
usb_set_serial_data(serial, NULL);
@@ -2110,7 +2044,6 @@ static struct usb_serial_driver moschip7720_2port_driver = {
.ioctl = mos7720_ioctl,
.tiocmget = mos7720_tiocmget,
.tiocmset = mos7720_tiocmset,
- .get_icount = mos7720_get_icount,
.set_termios = mos7720_set_termios,
.write = mos7720_write,
.write_room = mos7720_write_room,
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 66d9e088d9d..393be562d87 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -24,7 +24,6 @@
#include <linux/kernel.h>
#include <linux/errno.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
@@ -183,7 +182,10 @@
#define LED_ON_MS 500
#define LED_OFF_MS 500
-static int device_type;
+enum mos7840_flag {
+ MOS7840_FLAG_CTRL_BUSY,
+ MOS7840_FLAG_LED_BUSY,
+};
static const struct usb_device_id id_table[] = {
{USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)},
@@ -218,10 +220,6 @@ struct moschip_port {
__u8 shadowMCR; /* last MCR value received */
char open;
char open_ports;
- wait_queue_head_t wait_chase; /* for handling sleeping while waiting for chase to finish */
- wait_queue_head_t delta_msr_wait; /* for handling sleeping while waiting for msr change to happen */
- int delta_msr_cond;
- struct async_icount icount;
struct usb_serial_port *port; /* loop back to the owner of this object */
/* Offsets */
@@ -241,9 +239,12 @@ struct moschip_port {
/* For device(s) with LED indicator */
bool has_led;
- bool led_flag;
struct timer_list led_timer1; /* Timer for LED on */
struct timer_list led_timer2; /* Timer for LED off */
+ struct urb *led_urb;
+ struct usb_ctrlrequest *led_dr;
+
+ unsigned long flags;
};
/*
@@ -306,15 +307,12 @@ static int mos7840_set_uart_reg(struct usb_serial_port *port, __u16 reg,
/* For the UART control registers, the application number need
to be Or'ed */
if (port->serial->num_ports == 4) {
- val |= (((__u16) port->number -
- (__u16) (port->serial->minor)) + 1) << 8;
+ val |= ((__u16)port->port_number + 1) << 8;
} else {
- if (((__u16) port->number - (__u16) (port->serial->minor)) == 0) {
- val |= (((__u16) port->number -
- (__u16) (port->serial->minor)) + 1) << 8;
+ if (port->port_number == 0) {
+ val |= ((__u16)port->port_number + 1) << 8;
} else {
- val |= (((__u16) port->number -
- (__u16) (port->serial->minor)) + 2) << 8;
+ val |= ((__u16)port->port_number + 2) << 8;
}
}
dev_dbg(&port->dev, "%s application number is %x\n", __func__, val);
@@ -343,16 +341,12 @@ static int mos7840_get_uart_reg(struct usb_serial_port *port, __u16 reg,
/* Wval is same as application number */
if (port->serial->num_ports == 4) {
- Wval =
- (((__u16) port->number - (__u16) (port->serial->minor)) +
- 1) << 8;
+ Wval = ((__u16)port->port_number + 1) << 8;
} else {
- if (((__u16) port->number - (__u16) (port->serial->minor)) == 0) {
- Wval = (((__u16) port->number -
- (__u16) (port->serial->minor)) + 1) << 8;
+ if (port->port_number == 0) {
+ Wval = ((__u16)port->port_number + 1) << 8;
} else {
- Wval = (((__u16) port->number -
- (__u16) (port->serial->minor)) + 2) << 8;
+ Wval = ((__u16)port->port_number + 2) << 8;
}
}
dev_dbg(&port->dev, "%s application number is %x\n", __func__, Wval);
@@ -400,29 +394,22 @@ static void mos7840_handle_new_msr(struct moschip_port *port, __u8 new_msr)
struct moschip_port *mos7840_port;
struct async_icount *icount;
mos7840_port = port;
- icount = &mos7840_port->icount;
if (new_msr &
(MOS_MSR_DELTA_CTS | MOS_MSR_DELTA_DSR | MOS_MSR_DELTA_RI |
MOS_MSR_DELTA_CD)) {
- icount = &mos7840_port->icount;
+ icount = &mos7840_port->port->icount;
/* update input line counters */
- if (new_msr & MOS_MSR_DELTA_CTS) {
+ if (new_msr & MOS_MSR_DELTA_CTS)
icount->cts++;
- smp_wmb();
- }
- if (new_msr & MOS_MSR_DELTA_DSR) {
+ if (new_msr & MOS_MSR_DELTA_DSR)
icount->dsr++;
- smp_wmb();
- }
- if (new_msr & MOS_MSR_DELTA_CD) {
+ if (new_msr & MOS_MSR_DELTA_CD)
icount->dcd++;
- smp_wmb();
- }
- if (new_msr & MOS_MSR_DELTA_RI) {
+ if (new_msr & MOS_MSR_DELTA_RI)
icount->rng++;
- smp_wmb();
- }
+
+ wake_up_interruptible(&port->port->port.delta_msr_wait);
}
}
@@ -440,23 +427,15 @@ static void mos7840_handle_new_lsr(struct moschip_port *port, __u8 new_lsr)
}
/* update input line counters */
- icount = &port->icount;
- if (new_lsr & SERIAL_LSR_BI) {
+ icount = &port->port->icount;
+ if (new_lsr & SERIAL_LSR_BI)
icount->brk++;
- smp_wmb();
- }
- if (new_lsr & SERIAL_LSR_OE) {
+ if (new_lsr & SERIAL_LSR_OE)
icount->overrun++;
- smp_wmb();
- }
- if (new_lsr & SERIAL_LSR_PE) {
+ if (new_lsr & SERIAL_LSR_PE)
icount->parity++;
- smp_wmb();
- }
- if (new_lsr & SERIAL_LSR_FE) {
+ if (new_lsr & SERIAL_LSR_FE)
icount->frame++;
- smp_wmb();
- }
}
/************************************************************************/
@@ -485,10 +464,10 @@ static void mos7840_control_callback(struct urb *urb)
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dev_dbg(dev, "%s - urb shutting down with status: %d\n", __func__, status);
- return;
+ goto out;
default:
dev_dbg(dev, "%s - nonzero urb status received: %d\n", __func__, status);
- return;
+ goto out;
}
dev_dbg(dev, "%s urb buffer size is %d\n", __func__, urb->actual_length);
@@ -501,6 +480,8 @@ static void mos7840_control_callback(struct urb *urb)
mos7840_handle_new_msr(mos7840_port, regval);
else if (mos7840_port->MsrLsr == 1)
mos7840_handle_new_lsr(mos7840_port, regval);
+out:
+ clear_bit_unlock(MOS7840_FLAG_CTRL_BUSY, &mos7840_port->flags);
}
static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg,
@@ -511,6 +492,9 @@ static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg,
unsigned char *buffer = mcs->ctrl_buf;
int ret;
+ if (test_and_set_bit_lock(MOS7840_FLAG_CTRL_BUSY, &mcs->flags))
+ return -EBUSY;
+
dr->bRequestType = MCS_RD_RTYPE;
dr->bRequest = MCS_RDREQ;
dr->wValue = cpu_to_le16(Wval); /* 0 */
@@ -522,6 +506,9 @@ static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg,
mos7840_control_callback, mcs);
mcs->control_urb->transfer_buffer_length = 2;
ret = usb_submit_urb(mcs->control_urb, GFP_ATOMIC);
+ if (ret)
+ clear_bit_unlock(MOS7840_FLAG_CTRL_BUSY, &mcs->flags);
+
return ret;
}
@@ -535,11 +522,11 @@ static void mos7840_set_led_callback(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* This urb is terminated, clean up */
- dev_dbg(&urb->dev->dev, "%s - urb shutting down with status: %d",
+ dev_dbg(&urb->dev->dev, "%s - urb shutting down: %d\n",
__func__, urb->status);
break;
default:
- dev_dbg(&urb->dev->dev, "%s - nonzero urb status received: %d",
+ dev_dbg(&urb->dev->dev, "%s - nonzero urb status: %d\n",
__func__, urb->status);
}
}
@@ -548,7 +535,7 @@ static void mos7840_set_led_async(struct moschip_port *mcs, __u16 wval,
__u16 reg)
{
struct usb_device *dev = mcs->port->serial->dev;
- struct usb_ctrlrequest *dr = mcs->dr;
+ struct usb_ctrlrequest *dr = mcs->led_dr;
dr->bRequestType = MCS_WR_RTYPE;
dr->bRequest = MCS_WRREQ;
@@ -556,10 +543,10 @@ static void mos7840_set_led_async(struct moschip_port *mcs, __u16 wval,
dr->wIndex = cpu_to_le16(reg);
dr->wLength = cpu_to_le16(0);
- usb_fill_control_urb(mcs->control_urb, dev, usb_sndctrlpipe(dev, 0),
+ usb_fill_control_urb(mcs->led_urb, dev, usb_sndctrlpipe(dev, 0),
(unsigned char *)dr, NULL, 0, mos7840_set_led_callback, NULL);
- usb_submit_urb(mcs->control_urb, GFP_ATOMIC);
+ usb_submit_urb(mcs->led_urb, GFP_ATOMIC);
}
static void mos7840_set_led_sync(struct usb_serial_port *port, __u16 reg,
@@ -585,7 +572,19 @@ static void mos7840_led_flag_off(unsigned long arg)
{
struct moschip_port *mcs = (struct moschip_port *) arg;
- mcs->led_flag = false;
+ clear_bit_unlock(MOS7840_FLAG_LED_BUSY, &mcs->flags);
+}
+
+static void mos7840_led_activity(struct usb_serial_port *port)
+{
+ struct moschip_port *mos7840_port = usb_get_serial_port_data(port);
+
+ if (test_and_set_bit_lock(MOS7840_FLAG_LED_BUSY, &mos7840_port->flags))
+ return;
+
+ mos7840_set_led_async(mos7840_port, 0x0301, MODEM_CONTROL_REGISTER);
+ mod_timer(&mos7840_port->led_timer1,
+ jiffies + msecs_to_jiffies(LED_ON_MS));
}
/*****************************************************************************
@@ -649,9 +648,7 @@ static void mos7840_interrupt_callback(struct urb *urb)
for (i = 0; i < serial->num_ports; i++) {
mos7840_port = mos7840_get_port_private(serial->port[i]);
- wval =
- (((__u16) serial->port[i]->number -
- (__u16) (serial->minor)) + 1) << 8;
+ wval = ((__u16)serial->port[i]->port_number + 1) << 8;
if (mos7840_port->open) {
if (sp[i] & 0x01) {
dev_dbg(&urb->dev->dev, "SP%d No Interrupt !!!\n", i);
@@ -744,7 +741,6 @@ static void mos7840_bulk_in_callback(struct urb *urb)
struct usb_serial *serial;
struct usb_serial_port *port;
struct moschip_port *mos7840_port;
- struct tty_struct *tty;
int status = urb->status;
mos7840_port = urb->context;
@@ -773,15 +769,11 @@ static void mos7840_bulk_in_callback(struct urb *urb)
usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data);
if (urb->actual_length) {
- tty = tty_port_tty_get(&mos7840_port->port->port);
- if (tty) {
- tty_insert_flip_string(tty, data, urb->actual_length);
- tty_flip_buffer_push(tty);
- tty_kref_put(tty);
- }
- mos7840_port->icount.rx += urb->actual_length;
- smp_wmb();
- dev_dbg(&port->dev, "mos7840_port->icount.rx is %d:\n", mos7840_port->icount.rx);
+ struct tty_port *tport = &mos7840_port->port->port;
+ tty_insert_flip_string(tport, data, urb->actual_length);
+ tty_flip_buffer_push(tport);
+ port->icount.rx += urb->actual_length;
+ dev_dbg(&port->dev, "icount.rx is %d:\n", port->icount.rx);
}
if (!mos7840_port->read_urb) {
@@ -790,14 +782,8 @@ static void mos7840_bulk_in_callback(struct urb *urb)
return;
}
- /* Turn on LED */
- if (mos7840_port->has_led && !mos7840_port->led_flag) {
- mos7840_port->led_flag = true;
- mos7840_set_led_async(mos7840_port, 0x0301,
- MODEM_CONTROL_REGISTER);
- mod_timer(&mos7840_port->led_timer1,
- jiffies + msecs_to_jiffies(LED_ON_MS));
- }
+ if (mos7840_port->has_led)
+ mos7840_led_activity(port);
mos7840_port->read_urb_busy = true;
retval = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);
@@ -818,7 +804,6 @@ static void mos7840_bulk_out_data_callback(struct urb *urb)
{
struct moschip_port *mos7840_port;
struct usb_serial_port *port;
- struct tty_struct *tty;
int status = urb->status;
int i;
@@ -841,28 +826,14 @@ static void mos7840_bulk_out_data_callback(struct urb *urb)
if (mos7840_port_paranoia_check(port, __func__))
return;
- tty = tty_port_tty_get(&port->port);
- if (tty && mos7840_port->open)
- tty_wakeup(tty);
- tty_kref_put(tty);
+ if (mos7840_port->open)
+ tty_port_tty_wakeup(&port->port);
}
/************************************************************************/
/* D R I V E R T T Y I N T E R F A C E F U N C T I O N S */
/************************************************************************/
-#ifdef MCSSerialProbe
-static int mos7840_serial_probe(struct usb_serial *serial,
- const struct usb_device_id *id)
-{
-
- /*need to implement the mode_reg reading and updating\
- structures usb_serial_ device_type\
- (i.e num_ports, num_bulkin,bulkout etc) */
- /* Also we can update the changes attach */
- return 1;
-}
-#endif
/*****************************************************************************
* mos7840_open
@@ -904,20 +875,14 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)
for (j = 0; j < NUM_URBS; ++j) {
urb = usb_alloc_urb(0, GFP_KERNEL);
mos7840_port->write_urb_pool[j] = urb;
-
- if (urb == NULL) {
- dev_err(&port->dev, "No more urbs???\n");
+ if (!urb)
continue;
- }
urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE,
GFP_KERNEL);
if (!urb->transfer_buffer) {
usb_free_urb(urb);
mos7840_port->write_urb_pool[j] = NULL;
- dev_err(&port->dev,
- "%s-out of memory for urb buffers.\n",
- __func__);
continue;
}
}
@@ -940,20 +905,20 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)
status = mos7840_get_reg_sync(port, mos7840_port->SpRegOffset, &Data);
if (status < 0) {
dev_dbg(&port->dev, "Reading Spreg failed\n");
- return -1;
+ goto err;
}
Data |= 0x80;
status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data);
if (status < 0) {
dev_dbg(&port->dev, "writing Spreg failed\n");
- return -1;
+ goto err;
}
Data &= ~0x80;
status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data);
if (status < 0) {
dev_dbg(&port->dev, "writing Spreg failed\n");
- return -1;
+ goto err;
}
/* End of block to be checked */
@@ -962,7 +927,7 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)
&Data);
if (status < 0) {
dev_dbg(&port->dev, "Reading Controlreg failed\n");
- return -1;
+ goto err;
}
Data |= 0x08; /* Driver done bit */
Data |= 0x20; /* rx_disable */
@@ -970,7 +935,7 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)
mos7840_port->ControlRegOffset, Data);
if (status < 0) {
dev_dbg(&port->dev, "writing Controlreg failed\n");
- return -1;
+ goto err;
}
/* do register settings here */
/* Set all regs to the device default values. */
@@ -981,21 +946,21 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)
status = mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
if (status < 0) {
dev_dbg(&port->dev, "disabling interrupts failed\n");
- return -1;
+ goto err;
}
/* Set FIFO_CONTROL_REGISTER to the default value */
Data = 0x00;
status = mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data);
if (status < 0) {
dev_dbg(&port->dev, "Writing FIFO_CONTROL_REGISTER failed\n");
- return -1;
+ goto err;
}
Data = 0xcf;
status = mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data);
if (status < 0) {
dev_dbg(&port->dev, "Writing FIFO_CONTROL_REGISTER failed\n");
- return -1;
+ goto err;
}
Data = 0x03;
@@ -1091,8 +1056,8 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)
* (can't set it up in mos7840_startup as the *
* structures were not set up at that time.) */
- dev_dbg(&port->dev, "port number is %d\n", port->number);
- dev_dbg(&port->dev, "serial number is %d\n", port->serial->minor);
+ dev_dbg(&port->dev, "port number is %d\n", port->port_number);
+ dev_dbg(&port->dev, "minor number is %d\n", port->minor);
dev_dbg(&port->dev, "Bulkin endpoint is %d\n", port->bulk_in_endpointAddress);
dev_dbg(&port->dev, "BulkOut endpoint is %d\n", port->bulk_out_endpointAddress);
dev_dbg(&port->dev, "Interrupt endpoint is %d\n", port->interrupt_in_endpointAddress);
@@ -1100,9 +1065,7 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)
mos7840_port->read_urb = port->read_urb;
/* set up our bulk in urb */
- if ((serial->num_ports == 2)
- && ((((__u16)port->number -
- (__u16)(port->serial->minor)) % 2) != 0)) {
+ if ((serial->num_ports == 2) && (((__u16)port->port_number % 2) != 0)) {
usb_fill_bulk_urb(mos7840_port->read_urb,
serial->dev,
usb_rcvbulkpipe(serial->dev,
@@ -1129,23 +1092,23 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)
mos7840_port->read_urb_busy = false;
}
- /* initialize our wait queues */
- init_waitqueue_head(&mos7840_port->wait_chase);
- init_waitqueue_head(&mos7840_port->delta_msr_wait);
-
- /* initialize our icount structure */
- memset(&(mos7840_port->icount), 0x00, sizeof(mos7840_port->icount));
-
/* initialize our port settings */
/* Must set to enable ints! */
mos7840_port->shadowMCR = MCR_MASTER_IE;
/* send a open port command */
mos7840_port->open = 1;
/* mos7840_change_port_settings(mos7840_port,old_termios); */
- mos7840_port->icount.tx = 0;
- mos7840_port->icount.rx = 0;
return 0;
+err:
+ for (j = 0; j < NUM_URBS; ++j) {
+ urb = mos7840_port->write_urb_pool[j];
+ if (!urb)
+ continue;
+ kfree(urb->transfer_buffer);
+ usb_free_urb(urb);
+ }
+ return status;
}
/*****************************************************************************
@@ -1226,27 +1189,12 @@ static void mos7840_close(struct usb_serial_port *port)
}
}
- /* While closing port, shutdown all bulk read, write *
- * and interrupt read if they exists */
- if (serial->dev) {
- if (mos7840_port->write_urb) {
- dev_dbg(&port->dev, "%s", "Shutdown bulk write\n");
- usb_kill_urb(mos7840_port->write_urb);
- }
- if (mos7840_port->read_urb) {
- dev_dbg(&port->dev, "%s", "Shutdown bulk read\n");
- usb_kill_urb(mos7840_port->read_urb);
- mos7840_port->read_urb_busy = false;
- }
- if ((&mos7840_port->control_urb)) {
- dev_dbg(&port->dev, "%s", "Shutdown control read\n");
- /*/ usb_kill_urb (mos7840_port->control_urb); */
- }
- }
-/* if(mos7840_port->ctrl_buf != NULL) */
-/* kfree(mos7840_port->ctrl_buf); */
+ usb_kill_urb(mos7840_port->write_urb);
+ usb_kill_urb(mos7840_port->read_urb);
+ mos7840_port->read_urb_busy = false;
+
port0->open_ports--;
- dev_dbg(&port->dev, "%s in close%d:in port%d\n", __func__, port0->open_ports, port->number);
+ dev_dbg(&port->dev, "%s in close%d\n", __func__, port0->open_ports);
if (port0->open_ports == 0) {
if (serial->port[0]->interrupt_in_urb) {
dev_dbg(&port->dev, "Shutdown interrupt_in_urb\n");
@@ -1256,8 +1204,7 @@ static void mos7840_close(struct usb_serial_port *port)
if (mos7840_port->write_urb) {
/* if this urb had a transfer buffer already (old tx) free it */
- if (mos7840_port->write_urb->transfer_buffer != NULL)
- kfree(mos7840_port->write_urb->transfer_buffer);
+ kfree(mos7840_port->write_urb->transfer_buffer);
usb_free_urb(mos7840_port->write_urb);
}
@@ -1270,47 +1217,6 @@ static void mos7840_close(struct usb_serial_port *port)
mos7840_port->open = 0;
}
-/************************************************************************
- *
- * mos7840_block_until_chase_response
- *
- * This function will block the close until one of the following:
- * 1. Response to our Chase comes from mos7840
- * 2. A timeout of 10 seconds without activity has expired
- * (1K of mos7840 data @ 2400 baud ==> 4 sec to empty)
- *
- ************************************************************************/
-
-static void mos7840_block_until_chase_response(struct tty_struct *tty,
- struct moschip_port *mos7840_port)
-{
- int timeout = msecs_to_jiffies(1000);
- int wait = 10;
- int count;
-
- while (1) {
- count = mos7840_chars_in_buffer(tty);
-
- /* Check for Buffer status */
- if (count <= 0)
- return;
-
- /* Block the thread for a while */
- interruptible_sleep_on_timeout(&mos7840_port->wait_chase,
- timeout);
- /* No activity.. count down section */
- wait--;
- if (wait == 0) {
- dev_dbg(&mos7840_port->port->dev, "%s - TIMEOUT\n", __func__);
- return;
- } else {
- /* Reset timeout value back to seconds */
- wait = 10;
- }
- }
-
-}
-
/*****************************************************************************
* mos7840_break
* this function sends a break to the port
@@ -1334,10 +1240,6 @@ static void mos7840_break(struct tty_struct *tty, int break_state)
if (mos7840_port == NULL)
return;
- if (serial->dev)
- /* flush and block until tx is empty */
- mos7840_block_until_chase_response(tty, mos7840_port);
-
if (break_state == -1)
data = mos7840_port->shadowLCR | LCR_SET_BREAK;
else
@@ -1472,21 +1374,15 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port,
if (urb->transfer_buffer == NULL) {
urb->transfer_buffer =
kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
-
- if (urb->transfer_buffer == NULL) {
- dev_err_console(port, "%s no more kernel memory...\n",
- __func__);
+ if (!urb->transfer_buffer)
goto exit;
- }
}
transfer_size = min(count, URB_TRANSFER_BUFFER_SIZE);
memcpy(urb->transfer_buffer, current_position, transfer_size);
/* fill urb with data and submit */
- if ((serial->num_ports == 2)
- && ((((__u16)port->number -
- (__u16)(port->serial->minor)) % 2) != 0)) {
+ if ((serial->num_ports == 2) && (((__u16)port->port_number % 2) != 0)) {
usb_fill_bulk_urb(urb,
serial->dev,
usb_sndbulkpipe(serial->dev,
@@ -1507,13 +1403,8 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port,
data1 = urb->transfer_buffer;
dev_dbg(&port->dev, "bulkout endpoint is %d\n", port->bulk_out_endpointAddress);
- /* Turn on LED */
- if (mos7840_port->has_led && !mos7840_port->led_flag) {
- mos7840_port->led_flag = true;
- mos7840_set_led_sync(port, MODEM_CONTROL_REGISTER, 0x0301);
- mod_timer(&mos7840_port->led_timer1,
- jiffies + msecs_to_jiffies(LED_ON_MS));
- }
+ if (mos7840_port->has_led)
+ mos7840_led_activity(port);
/* send it down the pipe */
status = usb_submit_urb(urb, GFP_ATOMIC);
@@ -1526,9 +1417,8 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port,
goto exit;
}
bytes_sent = transfer_size;
- mos7840_port->icount.tx += transfer_size;
- smp_wmb();
- dev_dbg(&port->dev, "mos7840_port->icount.tx is %d:\n", mos7840_port->icount.tx);
+ port->icount.tx += transfer_size;
+ dev_dbg(&port->dev, "icount.tx is %d:\n", port->icount.tx);
exit:
return bytes_sent;
@@ -1631,7 +1521,11 @@ static int mos7840_tiocmget(struct tty_struct *tty)
return -ENODEV;
status = mos7840_get_uart_reg(port, MODEM_STATUS_REGISTER, &msr);
+ if (status != 1)
+ return -EIO;
status = mos7840_get_uart_reg(port, MODEM_CONTROL_REGISTER, &mcr);
+ if (status != 1)
+ return -EIO;
result = ((mcr & MCR_DTR) ? TIOCM_DTR : 0)
| ((mcr & MCR_RTS) ? TIOCM_RTS : 0)
| ((mcr & MCR_LOOPBACK) ? TIOCM_LOOP : 0)
@@ -1782,10 +1676,9 @@ static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port,
if (mos7840_serial_paranoia_check(port->serial, __func__))
return -1;
- number = mos7840_port->port->number - mos7840_port->port->serial->minor;
+ number = mos7840_port->port->port_number;
- dev_dbg(&port->dev, "%s - port = %d, baud = %d\n", __func__,
- mos7840_port->port->number, baudRate);
+ dev_dbg(&port->dev, "%s - baud = %d\n", __func__, baudRate);
/* reset clk_uart_sel in spregOffset */
if (baudRate > 115200) {
#ifdef HW_flow_control
@@ -1909,25 +1802,25 @@ static void mos7840_change_port_settings(struct tty_struct *tty,
iflag = tty->termios.c_iflag;
/* Change the number of bits */
- if (cflag & CSIZE) {
- switch (cflag & CSIZE) {
- case CS5:
- lData = LCR_BITS_5;
- break;
+ switch (cflag & CSIZE) {
+ case CS5:
+ lData = LCR_BITS_5;
+ break;
- case CS6:
- lData = LCR_BITS_6;
- break;
+ case CS6:
+ lData = LCR_BITS_6;
+ break;
- case CS7:
- lData = LCR_BITS_7;
- break;
- default:
- case CS8:
- lData = LCR_BITS_8;
- break;
- }
+ case CS7:
+ lData = LCR_BITS_7;
+ break;
+
+ default:
+ case CS8:
+ lData = LCR_BITS_8;
+ break;
}
+
/* Change the Parity bit */
if (cflag & PARENB) {
if (cflag & PARODD) {
@@ -2021,8 +1914,6 @@ static void mos7840_change_port_settings(struct tty_struct *tty,
mos7840_port->read_urb_busy = false;
}
}
- wake_up(&mos7840_port->delta_msr_wait);
- mos7840_port->delta_msr_cond = 1;
dev_dbg(&port->dev, "%s - mos7840_port->shadowLCR is End %x\n", __func__,
mos7840_port->shadowLCR);
}
@@ -2068,7 +1959,6 @@ static void mos7840_set_termios(struct tty_struct *tty,
tty->termios.c_cflag, RELEVANT_IFLAG(tty->termios.c_iflag));
dev_dbg(&port->dev, "%s - old clfag %08x old iflag %08x\n", __func__,
old_termios->c_cflag, RELEVANT_IFLAG(old_termios->c_iflag));
- dev_dbg(&port->dev, "%s - port %d\n", __func__, port->number);
/* change the port settings to the new ones specified */
@@ -2135,8 +2025,8 @@ static int mos7840_get_serial_info(struct moschip_port *mos7840_port,
memset(&tmp, 0, sizeof(tmp));
tmp.type = PORT_16550A;
- tmp.line = mos7840_port->port->serial->minor;
- tmp.port = mos7840_port->port->number;
+ tmp.line = mos7840_port->port->minor;
+ tmp.port = mos7840_port->port->port_number;
tmp.irq = 0;
tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
tmp.xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE;
@@ -2149,34 +2039,6 @@ static int mos7840_get_serial_info(struct moschip_port *mos7840_port,
return 0;
}
-static int mos7840_get_icount(struct tty_struct *tty,
- struct serial_icounter_struct *icount)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct moschip_port *mos7840_port;
- struct async_icount cnow;
-
- mos7840_port = mos7840_get_port_private(port);
- cnow = mos7840_port->icount;
-
- smp_rmb();
- icount->cts = cnow.cts;
- icount->dsr = cnow.dsr;
- icount->rng = cnow.rng;
- icount->dcd = cnow.dcd;
- icount->rx = cnow.rx;
- icount->tx = cnow.tx;
- icount->frame = cnow.frame;
- icount->overrun = cnow.overrun;
- icount->parity = cnow.parity;
- icount->brk = cnow.brk;
- icount->buf_overrun = cnow.buf_overrun;
-
- dev_dbg(&port->dev, "%s TIOCGICOUNT RX=%d, TX=%d\n", __func__,
- icount->rx, icount->tx);
- return 0;
-}
-
/*****************************************************************************
* SerialIoctl
* this function handles any ioctl calls to the driver
@@ -2189,9 +2051,6 @@ static int mos7840_ioctl(struct tty_struct *tty,
void __user *argp = (void __user *)arg;
struct moschip_port *mos7840_port;
- struct async_icount cnow;
- struct async_icount cprev;
-
if (mos7840_port_paranoia_check(port, __func__))
return -1;
@@ -2200,8 +2059,6 @@ static int mos7840_ioctl(struct tty_struct *tty,
if (mos7840_port == NULL)
return -1;
- dev_dbg(&port->dev, "%s - cmd = 0x%x\n", __func__, cmd);
-
switch (cmd) {
/* return number of bytes available */
@@ -2216,36 +2073,6 @@ static int mos7840_ioctl(struct tty_struct *tty,
case TIOCSSERIAL:
dev_dbg(&port->dev, "%s TIOCSSERIAL\n", __func__);
break;
-
- case TIOCMIWAIT:
- dev_dbg(&port->dev, "%s TIOCMIWAIT\n", __func__);
- cprev = mos7840_port->icount;
- while (1) {
- /* interruptible_sleep_on(&mos7840_port->delta_msr_wait); */
- mos7840_port->delta_msr_cond = 0;
- wait_event_interruptible(mos7840_port->delta_msr_wait,
- (mos7840_port->
- delta_msr_cond == 1));
-
- /* see if a signal did it */
- if (signal_pending(current))
- return -ERESTARTSYS;
- cnow = mos7840_port->icount;
- smp_rmb();
- if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
- cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
- return -EIO; /* no change => error */
- if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
- ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
- ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
- ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
- return 0;
- }
- cprev = cnow;
- }
- /* NOTREACHED */
- break;
-
default:
break;
}
@@ -2255,13 +2082,21 @@ static int mos7840_ioctl(struct tty_struct *tty,
static int mos7810_check(struct usb_serial *serial)
{
int i, pass_count = 0;
+ u8 *buf;
__u16 data = 0, mcr_data = 0;
__u16 test_pattern = 0x55AA;
+ int res;
+
+ buf = kmalloc(VENDOR_READ_LENGTH, GFP_KERNEL);
+ if (!buf)
+ return 0; /* failed to identify 7810 */
/* Store MCR setting */
- usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+ res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
MCS_RDREQ, MCS_RD_RTYPE, 0x0300, MODEM_CONTROL_REGISTER,
- &mcr_data, VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT);
+ buf, VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT);
+ if (res == VENDOR_READ_LENGTH)
+ mcr_data = *buf;
for (i = 0; i < 16; i++) {
/* Send the 1-bit test pattern out to MCS7810 test pin */
@@ -2271,9 +2106,12 @@ static int mos7810_check(struct usb_serial *serial)
MODEM_CONTROL_REGISTER, NULL, 0, MOS_WDR_TIMEOUT);
/* Read the test pattern back */
- usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
- MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, &data,
- VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT);
+ res = usb_control_msg(serial->dev,
+ usb_rcvctrlpipe(serial->dev, 0), MCS_RDREQ,
+ MCS_RD_RTYPE, 0, GPIO_REGISTER, buf,
+ VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT);
+ if (res == VENDOR_READ_LENGTH)
+ data = *buf;
/* If this is a MCS7810 device, both test patterns must match */
if (((test_pattern >> i) ^ (~data >> 1)) & 0x0001)
@@ -2287,38 +2125,56 @@ static int mos7810_check(struct usb_serial *serial)
MCS_WR_RTYPE, 0x0300 | mcr_data, MODEM_CONTROL_REGISTER, NULL,
0, MOS_WDR_TIMEOUT);
+ kfree(buf);
+
if (pass_count == 16)
return 1;
return 0;
}
-static int mos7840_calc_num_ports(struct usb_serial *serial)
+static int mos7840_probe(struct usb_serial *serial,
+ const struct usb_device_id *id)
{
- __u16 data = 0x00;
- int mos7840_num_ports;
+ u16 product = le16_to_cpu(serial->dev->descriptor.idProduct);
+ u8 *buf;
+ int device_type;
+
+ if (product == MOSCHIP_DEVICE_ID_7810 ||
+ product == MOSCHIP_DEVICE_ID_7820) {
+ device_type = product;
+ goto out;
+ }
+
+ buf = kzalloc(VENDOR_READ_LENGTH, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
- MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, &data,
- VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT);
+ MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, buf,
+ VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT);
- if (serial->dev->descriptor.idProduct == MOSCHIP_DEVICE_ID_7810 ||
- serial->dev->descriptor.idProduct == MOSCHIP_DEVICE_ID_7820) {
- device_type = serial->dev->descriptor.idProduct;
- } else {
- /* For a MCS7840 device GPIO0 must be set to 1 */
- if ((data & 0x01) == 1)
- device_type = MOSCHIP_DEVICE_ID_7840;
- else if (mos7810_check(serial))
- device_type = MOSCHIP_DEVICE_ID_7810;
- else
- device_type = MOSCHIP_DEVICE_ID_7820;
- }
+ /* For a MCS7840 device GPIO0 must be set to 1 */
+ if (buf[0] & 0x01)
+ device_type = MOSCHIP_DEVICE_ID_7840;
+ else if (mos7810_check(serial))
+ device_type = MOSCHIP_DEVICE_ID_7810;
+ else
+ device_type = MOSCHIP_DEVICE_ID_7820;
+
+ kfree(buf);
+out:
+ usb_set_serial_data(serial, (void *)(unsigned long)device_type);
+
+ return 0;
+}
+
+static int mos7840_calc_num_ports(struct usb_serial *serial)
+{
+ int device_type = (unsigned long)usb_get_serial_data(serial);
+ int mos7840_num_ports;
mos7840_num_ports = (device_type >> 4) & 0x000F;
- serial->num_bulk_in = mos7840_num_ports;
- serial->num_bulk_out = mos7840_num_ports;
- serial->num_ports = mos7840_num_ports;
return mos7840_num_ports;
}
@@ -2326,6 +2182,7 @@ static int mos7840_calc_num_ports(struct usb_serial *serial)
static int mos7840_port_probe(struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
+ int device_type = (unsigned long)usb_get_serial_data(serial);
struct moschip_port *mos7840_port;
int status;
int pnum;
@@ -2334,14 +2191,12 @@ static int mos7840_port_probe(struct usb_serial_port *port)
/* we set up the pointers to the endpoints in the mos7840_open *
* function, as the structures aren't created yet. */
- pnum = port->number - serial->minor;
+ pnum = port->port_number;
dev_dbg(&port->dev, "mos7840_startup: configuring port %d\n", pnum);
mos7840_port = kzalloc(sizeof(struct moschip_port), GFP_KERNEL);
- if (mos7840_port == NULL) {
- dev_err(&port->dev, "%s - Out of memory\n", __func__);
+ if (!mos7840_port)
return -ENOMEM;
- }
/* Initialize all port interrupt end point to port 0 int
* endpoint. Our device has only one interrupt end point
@@ -2355,10 +2210,8 @@ static int mos7840_port_probe(struct usb_serial_port *port)
* usb-serial.c:get_free_serial() and cannot therefore be used
* to index device instances */
mos7840_port->port_num = pnum + 1;
- dev_dbg(&port->dev, "port->number = %d\n", port->number);
- dev_dbg(&port->dev, "port->serial->minor = %d\n", port->serial->minor);
+ dev_dbg(&port->dev, "port->minor = %d\n", port->minor);
dev_dbg(&port->dev, "mos7840_port->port_num = %d\n", mos7840_port->port_num);
- dev_dbg(&port->dev, "serial->minor = %d\n", serial->minor);
if (mos7840_port->port_num == 1) {
mos7840_port->SpRegOffset = 0x0;
@@ -2503,6 +2356,14 @@ static int mos7840_port_probe(struct usb_serial_port *port)
if (device_type == MOSCHIP_DEVICE_ID_7810) {
mos7840_port->has_led = true;
+ mos7840_port->led_urb = usb_alloc_urb(0, GFP_KERNEL);
+ mos7840_port->led_dr = kmalloc(sizeof(*mos7840_port->led_dr),
+ GFP_KERNEL);
+ if (!mos7840_port->led_urb || !mos7840_port->led_dr) {
+ status = -ENOMEM;
+ goto error;
+ }
+
init_timer(&mos7840_port->led_timer1);
mos7840_port->led_timer1.function = mos7840_led_off;
mos7840_port->led_timer1.expires =
@@ -2515,8 +2376,6 @@ static int mos7840_port_probe(struct usb_serial_port *port)
jiffies + msecs_to_jiffies(LED_OFF_MS);
mos7840_port->led_timer2.data = (unsigned long)mos7840_port;
- mos7840_port->led_flag = false;
-
/* Turn off LED */
mos7840_set_led_sync(port, MODEM_CONTROL_REGISTER, 0x0300);
}
@@ -2538,6 +2397,8 @@ out:
}
return 0;
error:
+ kfree(mos7840_port->led_dr);
+ usb_free_urb(mos7840_port->led_urb);
kfree(mos7840_port->dr);
kfree(mos7840_port->ctrl_buf);
usb_free_urb(mos7840_port->control_urb);
@@ -2558,6 +2419,10 @@ static int mos7840_port_remove(struct usb_serial_port *port)
del_timer_sync(&mos7840_port->led_timer1);
del_timer_sync(&mos7840_port->led_timer2);
+
+ usb_kill_urb(mos7840_port->led_urb);
+ usb_free_urb(mos7840_port->led_urb);
+ kfree(mos7840_port->led_dr);
}
usb_kill_urb(mos7840_port->control_urb);
usb_free_urb(mos7840_port->control_urb);
@@ -2584,15 +2449,14 @@ static struct usb_serial_driver moschip7840_4port_device = {
.throttle = mos7840_throttle,
.unthrottle = mos7840_unthrottle,
.calc_num_ports = mos7840_calc_num_ports,
-#ifdef MCSSerialProbe
- .probe = mos7840_serial_probe,
-#endif
+ .probe = mos7840_probe,
.ioctl = mos7840_ioctl,
.set_termios = mos7840_set_termios,
.break_ctl = mos7840_break,
.tiocmget = mos7840_tiocmget,
.tiocmset = mos7840_tiocmset,
- .get_icount = mos7840_get_icount,
+ .tiocmiwait = usb_serial_generic_tiocmiwait,
+ .get_icount = usb_serial_generic_get_icount,
.port_probe = mos7840_port_probe,
.port_remove = mos7840_port_remove,
.read_bulk_callback = mos7840_bulk_in_callback,
diff --git a/drivers/usb/serial/moto_modem.c b/drivers/usb/serial/moto_modem.c
deleted file mode 100644
index c5ff6c7795a..00000000000
--- a/drivers/usb/serial/moto_modem.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Motorola USB Phone driver
- *
- * Copyright (C) 2008 Greg Kroah-Hartman <greg@kroah.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * {sigh}
- * Motorola should be using the CDC ACM USB spec, but instead
- * they try to just "do their own thing"... This driver should handle a
- * few phones in which a basic "dumb serial connection" is needed to be
- * able to get a connection through to them.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/tty.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/usb/serial.h>
-
-static const struct usb_device_id id_table[] = {
- { USB_DEVICE(0x05c6, 0x3197) }, /* unknown Motorola phone */
- { USB_DEVICE(0x0c44, 0x0022) }, /* unknown Mororola phone */
- { USB_DEVICE(0x22b8, 0x2a64) }, /* Motorola KRZR K1m */
- { USB_DEVICE(0x22b8, 0x2c84) }, /* Motorola VE240 phone */
- { USB_DEVICE(0x22b8, 0x2c64) }, /* Motorola V950 phone */
- { },
-};
-MODULE_DEVICE_TABLE(usb, id_table);
-
-static struct usb_serial_driver moto_device = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "moto-modem",
- },
- .id_table = id_table,
- .num_ports = 1,
-};
-
-static struct usb_serial_driver * const serial_drivers[] = {
- &moto_device, NULL
-};
-
-module_usb_serial_driver(serial_drivers, id_table);
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/mxuport.c b/drivers/usb/serial/mxuport.c
new file mode 100644
index 00000000000..ab1d690274a
--- /dev/null
+++ b/drivers/usb/serial/mxuport.c
@@ -0,0 +1,1393 @@
+/*
+ * mxuport.c - MOXA UPort series driver
+ *
+ * Copyright (c) 2006 Moxa Technologies Co., Ltd.
+ * Copyright (c) 2013 Andrew Lunn <andrew@lunn.ch>
+ *
+ * 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.
+ *
+ * Supports the following Moxa USB to serial converters:
+ * 2 ports : UPort 1250, UPort 1250I
+ * 4 ports : UPort 1410, UPort 1450, UPort 1450I
+ * 8 ports : UPort 1610-8, UPort 1650-8
+ * 16 ports : UPort 1610-16, UPort 1650-16
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/firmware.h>
+#include <linux/jiffies.h>
+#include <linux/serial.h>
+#include <linux/serial_reg.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+#include <asm/unaligned.h>
+
+/* Definitions for the vendor ID and device ID */
+#define MX_USBSERIAL_VID 0x110A
+#define MX_UPORT1250_PID 0x1250
+#define MX_UPORT1251_PID 0x1251
+#define MX_UPORT1410_PID 0x1410
+#define MX_UPORT1450_PID 0x1450
+#define MX_UPORT1451_PID 0x1451
+#define MX_UPORT1618_PID 0x1618
+#define MX_UPORT1658_PID 0x1658
+#define MX_UPORT1613_PID 0x1613
+#define MX_UPORT1653_PID 0x1653
+
+/* Definitions for USB info */
+#define HEADER_SIZE 4
+#define EVENT_LENGTH 8
+#define DOWN_BLOCK_SIZE 64
+
+/* Definitions for firmware info */
+#define VER_ADDR_1 0x20
+#define VER_ADDR_2 0x24
+#define VER_ADDR_3 0x28
+
+/* Definitions for USB vendor request */
+#define RQ_VENDOR_NONE 0x00
+#define RQ_VENDOR_SET_BAUD 0x01 /* Set baud rate */
+#define RQ_VENDOR_SET_LINE 0x02 /* Set line status */
+#define RQ_VENDOR_SET_CHARS 0x03 /* Set Xon/Xoff chars */
+#define RQ_VENDOR_SET_RTS 0x04 /* Set RTS */
+#define RQ_VENDOR_SET_DTR 0x05 /* Set DTR */
+#define RQ_VENDOR_SET_XONXOFF 0x06 /* Set auto Xon/Xoff */
+#define RQ_VENDOR_SET_RX_HOST_EN 0x07 /* Set RX host enable */
+#define RQ_VENDOR_SET_OPEN 0x08 /* Set open/close port */
+#define RQ_VENDOR_PURGE 0x09 /* Purge Rx/Tx buffer */
+#define RQ_VENDOR_SET_MCR 0x0A /* Set MCR register */
+#define RQ_VENDOR_SET_BREAK 0x0B /* Set Break signal */
+
+#define RQ_VENDOR_START_FW_DOWN 0x0C /* Start firmware download */
+#define RQ_VENDOR_STOP_FW_DOWN 0x0D /* Stop firmware download */
+#define RQ_VENDOR_QUERY_FW_READY 0x0E /* Query if new firmware ready */
+
+#define RQ_VENDOR_SET_FIFO_DISABLE 0x0F /* Set fifo disable */
+#define RQ_VENDOR_SET_INTERFACE 0x10 /* Set interface */
+#define RQ_VENDOR_SET_HIGH_PERFOR 0x11 /* Set hi-performance */
+
+#define RQ_VENDOR_ERASE_BLOCK 0x12 /* Erase flash block */
+#define RQ_VENDOR_WRITE_PAGE 0x13 /* Write flash page */
+#define RQ_VENDOR_PREPARE_WRITE 0x14 /* Prepare write flash */
+#define RQ_VENDOR_CONFIRM_WRITE 0x15 /* Confirm write flash */
+#define RQ_VENDOR_LOCATE 0x16 /* Locate the device */
+
+#define RQ_VENDOR_START_ROM_DOWN 0x17 /* Start firmware download */
+#define RQ_VENDOR_ROM_DATA 0x18 /* Rom file data */
+#define RQ_VENDOR_STOP_ROM_DOWN 0x19 /* Stop firmware download */
+#define RQ_VENDOR_FW_DATA 0x20 /* Firmware data */
+
+#define RQ_VENDOR_RESET_DEVICE 0x23 /* Try to reset the device */
+#define RQ_VENDOR_QUERY_FW_CONFIG 0x24
+
+#define RQ_VENDOR_GET_VERSION 0x81 /* Get firmware version */
+#define RQ_VENDOR_GET_PAGE 0x82 /* Read flash page */
+#define RQ_VENDOR_GET_ROM_PROC 0x83 /* Get ROM process state */
+
+#define RQ_VENDOR_GET_INQUEUE 0x84 /* Data in input buffer */
+#define RQ_VENDOR_GET_OUTQUEUE 0x85 /* Data in output buffer */
+
+#define RQ_VENDOR_GET_MSR 0x86 /* Get modem status register */
+
+/* Definitions for UPort event type */
+#define UPORT_EVENT_NONE 0 /* None */
+#define UPORT_EVENT_TXBUF_THRESHOLD 1 /* Tx buffer threshold */
+#define UPORT_EVENT_SEND_NEXT 2 /* Send next */
+#define UPORT_EVENT_MSR 3 /* Modem status */
+#define UPORT_EVENT_LSR 4 /* Line status */
+#define UPORT_EVENT_MCR 5 /* Modem control */
+
+/* Definitions for serial event type */
+#define SERIAL_EV_CTS 0x0008 /* CTS changed state */
+#define SERIAL_EV_DSR 0x0010 /* DSR changed state */
+#define SERIAL_EV_RLSD 0x0020 /* RLSD changed state */
+
+/* Definitions for modem control event type */
+#define SERIAL_EV_XOFF 0x40 /* XOFF received */
+
+/* Definitions for line control of communication */
+#define MX_WORDLENGTH_5 5
+#define MX_WORDLENGTH_6 6
+#define MX_WORDLENGTH_7 7
+#define MX_WORDLENGTH_8 8
+
+#define MX_PARITY_NONE 0
+#define MX_PARITY_ODD 1
+#define MX_PARITY_EVEN 2
+#define MX_PARITY_MARK 3
+#define MX_PARITY_SPACE 4
+
+#define MX_STOP_BITS_1 0
+#define MX_STOP_BITS_1_5 1
+#define MX_STOP_BITS_2 2
+
+#define MX_RTS_DISABLE 0x0
+#define MX_RTS_ENABLE 0x1
+#define MX_RTS_HW 0x2
+#define MX_RTS_NO_CHANGE 0x3 /* Flag, not valid register value*/
+
+#define MX_INT_RS232 0
+#define MX_INT_2W_RS485 1
+#define MX_INT_RS422 2
+#define MX_INT_4W_RS485 3
+
+/* Definitions for holding reason */
+#define MX_WAIT_FOR_CTS 0x0001
+#define MX_WAIT_FOR_DSR 0x0002
+#define MX_WAIT_FOR_DCD 0x0004
+#define MX_WAIT_FOR_XON 0x0008
+#define MX_WAIT_FOR_START_TX 0x0010
+#define MX_WAIT_FOR_UNTHROTTLE 0x0020
+#define MX_WAIT_FOR_LOW_WATER 0x0040
+#define MX_WAIT_FOR_SEND_NEXT 0x0080
+
+#define MX_UPORT_2_PORT BIT(0)
+#define MX_UPORT_4_PORT BIT(1)
+#define MX_UPORT_8_PORT BIT(2)
+#define MX_UPORT_16_PORT BIT(3)
+
+/* This structure holds all of the local port information */
+struct mxuport_port {
+ u8 mcr_state; /* Last MCR state */
+ u8 msr_state; /* Last MSR state */
+ struct mutex mutex; /* Protects mcr_state */
+ spinlock_t spinlock; /* Protects msr_state */
+};
+
+/* Table of devices that work with this driver */
+static const struct usb_device_id mxuport_idtable[] = {
+ { USB_DEVICE(MX_USBSERIAL_VID, MX_UPORT1250_PID),
+ .driver_info = MX_UPORT_2_PORT },
+ { USB_DEVICE(MX_USBSERIAL_VID, MX_UPORT1251_PID),
+ .driver_info = MX_UPORT_2_PORT },
+ { USB_DEVICE(MX_USBSERIAL_VID, MX_UPORT1410_PID),
+ .driver_info = MX_UPORT_4_PORT },
+ { USB_DEVICE(MX_USBSERIAL_VID, MX_UPORT1450_PID),
+ .driver_info = MX_UPORT_4_PORT },
+ { USB_DEVICE(MX_USBSERIAL_VID, MX_UPORT1451_PID),
+ .driver_info = MX_UPORT_4_PORT },
+ { USB_DEVICE(MX_USBSERIAL_VID, MX_UPORT1618_PID),
+ .driver_info = MX_UPORT_8_PORT },
+ { USB_DEVICE(MX_USBSERIAL_VID, MX_UPORT1658_PID),
+ .driver_info = MX_UPORT_8_PORT },
+ { USB_DEVICE(MX_USBSERIAL_VID, MX_UPORT1613_PID),
+ .driver_info = MX_UPORT_16_PORT },
+ { USB_DEVICE(MX_USBSERIAL_VID, MX_UPORT1653_PID),
+ .driver_info = MX_UPORT_16_PORT },
+ {} /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, mxuport_idtable);
+
+/*
+ * Add a four byte header containing the port number and the number of
+ * bytes of data in the message. Return the number of bytes in the
+ * buffer.
+ */
+static int mxuport_prepare_write_buffer(struct usb_serial_port *port,
+ void *dest, size_t size)
+{
+ u8 *buf = dest;
+ int count;
+
+ count = kfifo_out_locked(&port->write_fifo, buf + HEADER_SIZE,
+ size - HEADER_SIZE,
+ &port->lock);
+
+ put_unaligned_be16(port->port_number, buf);
+ put_unaligned_be16(count, buf + 2);
+
+ dev_dbg(&port->dev, "%s - size %zd count %d\n", __func__,
+ size, count);
+
+ return count + HEADER_SIZE;
+}
+
+/* Read the given buffer in from the control pipe. */
+static int mxuport_recv_ctrl_urb(struct usb_serial *serial,
+ u8 request, u16 value, u16 index,
+ u8 *data, size_t size)
+{
+ int status;
+
+ status = usb_control_msg(serial->dev,
+ usb_rcvctrlpipe(serial->dev, 0),
+ request,
+ (USB_DIR_IN | USB_TYPE_VENDOR |
+ USB_RECIP_DEVICE), value, index,
+ data, size,
+ USB_CTRL_GET_TIMEOUT);
+ if (status < 0) {
+ dev_err(&serial->interface->dev,
+ "%s - usb_control_msg failed (%d)\n",
+ __func__, status);
+ return status;
+ }
+
+ if (status != size) {
+ dev_err(&serial->interface->dev,
+ "%s - short read (%d / %zd)\n",
+ __func__, status, size);
+ return -EIO;
+ }
+
+ return status;
+}
+
+/* Write the given buffer out to the control pipe. */
+static int mxuport_send_ctrl_data_urb(struct usb_serial *serial,
+ u8 request,
+ u16 value, u16 index,
+ u8 *data, size_t size)
+{
+ int status;
+
+ status = usb_control_msg(serial->dev,
+ usb_sndctrlpipe(serial->dev, 0),
+ request,
+ (USB_DIR_OUT | USB_TYPE_VENDOR |
+ USB_RECIP_DEVICE), value, index,
+ data, size,
+ USB_CTRL_SET_TIMEOUT);
+ if (status < 0) {
+ dev_err(&serial->interface->dev,
+ "%s - usb_control_msg failed (%d)\n",
+ __func__, status);
+ return status;
+ }
+
+ if (status != size) {
+ dev_err(&serial->interface->dev,
+ "%s - short write (%d / %zd)\n",
+ __func__, status, size);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/* Send a vendor request without any data */
+static int mxuport_send_ctrl_urb(struct usb_serial *serial,
+ u8 request, u16 value, u16 index)
+{
+ return mxuport_send_ctrl_data_urb(serial, request, value, index,
+ NULL, 0);
+}
+
+/*
+ * mxuport_throttle - throttle function of driver
+ *
+ * This function is called by the tty driver when it wants to stop the
+ * data being read from the port. Since all the data comes over one
+ * bulk in endpoint, we cannot stop submitting urbs by setting
+ * port->throttle. Instead tell the device to stop sending us data for
+ * the port.
+ */
+static void mxuport_throttle(struct tty_struct *tty)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ struct usb_serial *serial = port->serial;
+
+ dev_dbg(&port->dev, "%s\n", __func__);
+
+ mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_RX_HOST_EN,
+ 0, port->port_number);
+}
+
+/*
+ * mxuport_unthrottle - unthrottle function of driver
+ *
+ * This function is called by the tty driver when it wants to resume
+ * the data being read from the port. Tell the device it can resume
+ * sending us received data from the port.
+ */
+static void mxuport_unthrottle(struct tty_struct *tty)
+{
+
+ struct usb_serial_port *port = tty->driver_data;
+ struct usb_serial *serial = port->serial;
+
+ dev_dbg(&port->dev, "%s\n", __func__);
+
+ mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_RX_HOST_EN,
+ 1, port->port_number);
+}
+
+/*
+ * Processes one chunk of data received for a port. Mostly a copy of
+ * usb_serial_generic_process_read_urb().
+ */
+static void mxuport_process_read_urb_data(struct usb_serial_port *port,
+ char *data, int size)
+{
+ int i;
+
+ if (!port->port.console || !port->sysrq) {
+ tty_insert_flip_string(&port->port, data, size);
+ } else {
+ for (i = 0; i < size; i++, data++) {
+ if (!usb_serial_handle_sysrq_char(port, *data))
+ tty_insert_flip_char(&port->port, *data,
+ TTY_NORMAL);
+ }
+ }
+ tty_flip_buffer_push(&port->port);
+}
+
+static void mxuport_msr_event(struct usb_serial_port *port, u8 buf[4])
+{
+ struct mxuport_port *mxport = usb_get_serial_port_data(port);
+ u8 rcv_msr_hold = buf[2] & 0xF0;
+ u16 rcv_msr_event = get_unaligned_be16(buf);
+ unsigned long flags;
+
+ if (rcv_msr_event == 0)
+ return;
+
+ /* Update MSR status */
+ spin_lock_irqsave(&mxport->spinlock, flags);
+
+ dev_dbg(&port->dev, "%s - current MSR status = 0x%x\n",
+ __func__, mxport->msr_state);
+
+ if (rcv_msr_hold & UART_MSR_CTS) {
+ mxport->msr_state |= UART_MSR_CTS;
+ dev_dbg(&port->dev, "%s - CTS high\n", __func__);
+ } else {
+ mxport->msr_state &= ~UART_MSR_CTS;
+ dev_dbg(&port->dev, "%s - CTS low\n", __func__);
+ }
+
+ if (rcv_msr_hold & UART_MSR_DSR) {
+ mxport->msr_state |= UART_MSR_DSR;
+ dev_dbg(&port->dev, "%s - DSR high\n", __func__);
+ } else {
+ mxport->msr_state &= ~UART_MSR_DSR;
+ dev_dbg(&port->dev, "%s - DSR low\n", __func__);
+ }
+
+ if (rcv_msr_hold & UART_MSR_DCD) {
+ mxport->msr_state |= UART_MSR_DCD;
+ dev_dbg(&port->dev, "%s - DCD high\n", __func__);
+ } else {
+ mxport->msr_state &= ~UART_MSR_DCD;
+ dev_dbg(&port->dev, "%s - DCD low\n", __func__);
+ }
+ spin_unlock_irqrestore(&mxport->spinlock, flags);
+
+ if (rcv_msr_event &
+ (SERIAL_EV_CTS | SERIAL_EV_DSR | SERIAL_EV_RLSD)) {
+
+ if (rcv_msr_event & SERIAL_EV_CTS) {
+ port->icount.cts++;
+ dev_dbg(&port->dev, "%s - CTS change\n", __func__);
+ }
+
+ if (rcv_msr_event & SERIAL_EV_DSR) {
+ port->icount.dsr++;
+ dev_dbg(&port->dev, "%s - DSR change\n", __func__);
+ }
+
+ if (rcv_msr_event & SERIAL_EV_RLSD) {
+ port->icount.dcd++;
+ dev_dbg(&port->dev, "%s - DCD change\n", __func__);
+ }
+ wake_up_interruptible(&port->port.delta_msr_wait);
+ }
+}
+
+static void mxuport_lsr_event(struct usb_serial_port *port, u8 buf[4])
+{
+ u8 lsr_event = buf[2];
+
+ if (lsr_event & UART_LSR_BI) {
+ port->icount.brk++;
+ dev_dbg(&port->dev, "%s - break error\n", __func__);
+ }
+
+ if (lsr_event & UART_LSR_FE) {
+ port->icount.frame++;
+ dev_dbg(&port->dev, "%s - frame error\n", __func__);
+ }
+
+ if (lsr_event & UART_LSR_PE) {
+ port->icount.parity++;
+ dev_dbg(&port->dev, "%s - parity error\n", __func__);
+ }
+
+ if (lsr_event & UART_LSR_OE) {
+ port->icount.overrun++;
+ dev_dbg(&port->dev, "%s - overrun error\n", __func__);
+ }
+}
+
+/*
+ * When something interesting happens, modem control lines XON/XOFF
+ * etc, the device sends an event. Process these events.
+ */
+static void mxuport_process_read_urb_event(struct usb_serial_port *port,
+ u8 buf[4], u32 event)
+{
+ dev_dbg(&port->dev, "%s - receive event : %04x\n", __func__, event);
+
+ switch (event) {
+ case UPORT_EVENT_SEND_NEXT:
+ /*
+ * Sent as part of the flow control on device buffers.
+ * Not currently used.
+ */
+ break;
+ case UPORT_EVENT_MSR:
+ mxuport_msr_event(port, buf);
+ break;
+ case UPORT_EVENT_LSR:
+ mxuport_lsr_event(port, buf);
+ break;
+ case UPORT_EVENT_MCR:
+ /*
+ * Event to indicate a change in XON/XOFF from the
+ * peer. Currently not used. We just continue
+ * sending the device data and it will buffer it if
+ * needed. This event could be used for flow control
+ * between the host and the device.
+ */
+ break;
+ default:
+ dev_dbg(&port->dev, "Unexpected event\n");
+ break;
+ }
+}
+
+/*
+ * One URB can contain data for multiple ports. Demultiplex the data,
+ * checking the port exists, is opened and the message is valid.
+ */
+static void mxuport_process_read_urb_demux_data(struct urb *urb)
+{
+ struct usb_serial_port *port = urb->context;
+ struct usb_serial *serial = port->serial;
+ u8 *data = urb->transfer_buffer;
+ u8 *end = data + urb->actual_length;
+ struct usb_serial_port *demux_port;
+ u8 *ch;
+ u16 rcv_port;
+ u16 rcv_len;
+
+ while (data < end) {
+ if (data + HEADER_SIZE > end) {
+ dev_warn(&port->dev, "%s - message with short header\n",
+ __func__);
+ return;
+ }
+
+ rcv_port = get_unaligned_be16(data);
+ if (rcv_port >= serial->num_ports) {
+ dev_warn(&port->dev, "%s - message for invalid port\n",
+ __func__);
+ return;
+ }
+
+ demux_port = serial->port[rcv_port];
+ rcv_len = get_unaligned_be16(data + 2);
+ if (!rcv_len || data + HEADER_SIZE + rcv_len > end) {
+ dev_warn(&port->dev, "%s - short data\n", __func__);
+ return;
+ }
+
+ if (test_bit(ASYNCB_INITIALIZED, &demux_port->port.flags)) {
+ ch = data + HEADER_SIZE;
+ mxuport_process_read_urb_data(demux_port, ch, rcv_len);
+ } else {
+ dev_dbg(&demux_port->dev, "%s - data for closed port\n",
+ __func__);
+ }
+ data += HEADER_SIZE + rcv_len;
+ }
+}
+
+/*
+ * One URB can contain events for multiple ports. Demultiplex the event,
+ * checking the port exists, and is opened.
+ */
+static void mxuport_process_read_urb_demux_event(struct urb *urb)
+{
+ struct usb_serial_port *port = urb->context;
+ struct usb_serial *serial = port->serial;
+ u8 *data = urb->transfer_buffer;
+ u8 *end = data + urb->actual_length;
+ struct usb_serial_port *demux_port;
+ u8 *ch;
+ u16 rcv_port;
+ u16 rcv_event;
+
+ while (data < end) {
+ if (data + EVENT_LENGTH > end) {
+ dev_warn(&port->dev, "%s - message with short event\n",
+ __func__);
+ return;
+ }
+
+ rcv_port = get_unaligned_be16(data);
+ if (rcv_port >= serial->num_ports) {
+ dev_warn(&port->dev, "%s - message for invalid port\n",
+ __func__);
+ return;
+ }
+
+ demux_port = serial->port[rcv_port];
+ if (test_bit(ASYNCB_INITIALIZED, &demux_port->port.flags)) {
+ ch = data + HEADER_SIZE;
+ rcv_event = get_unaligned_be16(data + 2);
+ mxuport_process_read_urb_event(demux_port, ch,
+ rcv_event);
+ } else {
+ dev_dbg(&demux_port->dev,
+ "%s - event for closed port\n", __func__);
+ }
+ data += EVENT_LENGTH;
+ }
+}
+
+/*
+ * This is called when we have received data on the bulk in
+ * endpoint. Depending on which port it was received on, it can
+ * contain serial data or events.
+ */
+static void mxuport_process_read_urb(struct urb *urb)
+{
+ struct usb_serial_port *port = urb->context;
+ struct usb_serial *serial = port->serial;
+
+ if (port == serial->port[0])
+ mxuport_process_read_urb_demux_data(urb);
+
+ if (port == serial->port[1])
+ mxuport_process_read_urb_demux_event(urb);
+}
+
+/*
+ * Ask the device how many bytes it has queued to be sent out. If
+ * there are none, return true.
+ */
+static bool mxuport_tx_empty(struct usb_serial_port *port)
+{
+ struct usb_serial *serial = port->serial;
+ bool is_empty = true;
+ u32 txlen;
+ u8 *len_buf;
+ int err;
+
+ len_buf = kzalloc(4, GFP_KERNEL);
+ if (!len_buf)
+ goto out;
+
+ err = mxuport_recv_ctrl_urb(serial, RQ_VENDOR_GET_OUTQUEUE, 0,
+ port->port_number, len_buf, 4);
+ if (err < 0)
+ goto out;
+
+ txlen = get_unaligned_be32(len_buf);
+ dev_dbg(&port->dev, "%s - tx len = %u\n", __func__, txlen);
+
+ if (txlen != 0)
+ is_empty = false;
+
+out:
+ kfree(len_buf);
+ return is_empty;
+}
+
+static int mxuport_set_mcr(struct usb_serial_port *port, u8 mcr_state)
+{
+ struct usb_serial *serial = port->serial;
+ int err;
+
+ dev_dbg(&port->dev, "%s - %02x\n", __func__, mcr_state);
+
+ err = mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_MCR,
+ mcr_state, port->port_number);
+ if (err)
+ dev_err(&port->dev, "%s - failed to change MCR\n", __func__);
+
+ return err;
+}
+
+static int mxuport_set_dtr(struct usb_serial_port *port, int on)
+{
+ struct mxuport_port *mxport = usb_get_serial_port_data(port);
+ struct usb_serial *serial = port->serial;
+ int err;
+
+ mutex_lock(&mxport->mutex);
+
+ err = mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_DTR,
+ !!on, port->port_number);
+ if (!err) {
+ if (on)
+ mxport->mcr_state |= UART_MCR_DTR;
+ else
+ mxport->mcr_state &= ~UART_MCR_DTR;
+ }
+
+ mutex_unlock(&mxport->mutex);
+
+ return err;
+}
+
+static int mxuport_set_rts(struct usb_serial_port *port, u8 state)
+{
+ struct mxuport_port *mxport = usb_get_serial_port_data(port);
+ struct usb_serial *serial = port->serial;
+ int err;
+ u8 mcr_state;
+
+ mutex_lock(&mxport->mutex);
+ mcr_state = mxport->mcr_state;
+
+ switch (state) {
+ case MX_RTS_DISABLE:
+ mcr_state &= ~UART_MCR_RTS;
+ break;
+ case MX_RTS_ENABLE:
+ mcr_state |= UART_MCR_RTS;
+ break;
+ case MX_RTS_HW:
+ /*
+ * Do not update mxport->mcr_state when doing hardware
+ * flow control.
+ */
+ break;
+ default:
+ /*
+ * Should not happen, but somebody might try passing
+ * MX_RTS_NO_CHANGE, which is not valid.
+ */
+ err = -EINVAL;
+ goto out;
+ }
+ err = mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_RTS,
+ state, port->port_number);
+ if (!err)
+ mxport->mcr_state = mcr_state;
+
+out:
+ mutex_unlock(&mxport->mutex);
+
+ return err;
+}
+
+static void mxuport_dtr_rts(struct usb_serial_port *port, int on)
+{
+ struct mxuport_port *mxport = usb_get_serial_port_data(port);
+ u8 mcr_state;
+ int err;
+
+ mutex_lock(&mxport->mutex);
+ mcr_state = mxport->mcr_state;
+
+ if (on)
+ mcr_state |= (UART_MCR_RTS | UART_MCR_DTR);
+ else
+ mcr_state &= ~(UART_MCR_RTS | UART_MCR_DTR);
+
+ err = mxuport_set_mcr(port, mcr_state);
+ if (!err)
+ mxport->mcr_state = mcr_state;
+
+ mutex_unlock(&mxport->mutex);
+}
+
+static int mxuport_tiocmset(struct tty_struct *tty, unsigned int set,
+ unsigned int clear)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ struct mxuport_port *mxport = usb_get_serial_port_data(port);
+ int err;
+ u8 mcr_state;
+
+ mutex_lock(&mxport->mutex);
+ mcr_state = mxport->mcr_state;
+
+ if (set & TIOCM_RTS)
+ mcr_state |= UART_MCR_RTS;
+
+ if (set & TIOCM_DTR)
+ mcr_state |= UART_MCR_DTR;
+
+ if (clear & TIOCM_RTS)
+ mcr_state &= ~UART_MCR_RTS;
+
+ if (clear & TIOCM_DTR)
+ mcr_state &= ~UART_MCR_DTR;
+
+ err = mxuport_set_mcr(port, mcr_state);
+ if (!err)
+ mxport->mcr_state = mcr_state;
+
+ mutex_unlock(&mxport->mutex);
+
+ return err;
+}
+
+static int mxuport_tiocmget(struct tty_struct *tty)
+{
+ struct mxuport_port *mxport;
+ struct usb_serial_port *port = tty->driver_data;
+ unsigned int result;
+ unsigned long flags;
+ unsigned int msr;
+ unsigned int mcr;
+
+ mxport = usb_get_serial_port_data(port);
+
+ mutex_lock(&mxport->mutex);
+ spin_lock_irqsave(&mxport->spinlock, flags);
+
+ msr = mxport->msr_state;
+ mcr = mxport->mcr_state;
+
+ spin_unlock_irqrestore(&mxport->spinlock, flags);
+ mutex_unlock(&mxport->mutex);
+
+ result = (((mcr & UART_MCR_DTR) ? TIOCM_DTR : 0) | /* 0x002 */
+ ((mcr & UART_MCR_RTS) ? TIOCM_RTS : 0) | /* 0x004 */
+ ((msr & UART_MSR_CTS) ? TIOCM_CTS : 0) | /* 0x020 */
+ ((msr & UART_MSR_DCD) ? TIOCM_CAR : 0) | /* 0x040 */
+ ((msr & UART_MSR_RI) ? TIOCM_RI : 0) | /* 0x080 */
+ ((msr & UART_MSR_DSR) ? TIOCM_DSR : 0)); /* 0x100 */
+
+ dev_dbg(&port->dev, "%s - 0x%04x\n", __func__, result);
+
+ return result;
+}
+
+static int mxuport_set_termios_flow(struct tty_struct *tty,
+ struct ktermios *old_termios,
+ struct usb_serial_port *port,
+ struct usb_serial *serial)
+{
+ u8 xon = START_CHAR(tty);
+ u8 xoff = STOP_CHAR(tty);
+ int enable;
+ int err;
+ u8 *buf;
+ u8 rts;
+
+ buf = kmalloc(2, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ /* S/W flow control settings */
+ if (I_IXOFF(tty) || I_IXON(tty)) {
+ enable = 1;
+ buf[0] = xon;
+ buf[1] = xoff;
+
+ err = mxuport_send_ctrl_data_urb(serial, RQ_VENDOR_SET_CHARS,
+ 0, port->port_number,
+ buf, 2);
+ if (err)
+ goto out;
+
+ dev_dbg(&port->dev, "%s - XON = 0x%02x, XOFF = 0x%02x\n",
+ __func__, xon, xoff);
+ } else {
+ enable = 0;
+ }
+
+ err = mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_XONXOFF,
+ enable, port->port_number);
+ if (err)
+ goto out;
+
+ rts = MX_RTS_NO_CHANGE;
+
+ /* H/W flow control settings */
+ if (!old_termios ||
+ C_CRTSCTS(tty) != (old_termios->c_cflag & CRTSCTS)) {
+ if (C_CRTSCTS(tty))
+ rts = MX_RTS_HW;
+ else
+ rts = MX_RTS_ENABLE;
+ }
+
+ if (C_BAUD(tty)) {
+ if (old_termios && (old_termios->c_cflag & CBAUD) == B0) {
+ /* Raise DTR and RTS */
+ if (C_CRTSCTS(tty))
+ rts = MX_RTS_HW;
+ else
+ rts = MX_RTS_ENABLE;
+ mxuport_set_dtr(port, 1);
+ }
+ } else {
+ /* Drop DTR and RTS */
+ rts = MX_RTS_DISABLE;
+ mxuport_set_dtr(port, 0);
+ }
+
+ if (rts != MX_RTS_NO_CHANGE)
+ err = mxuport_set_rts(port, rts);
+
+out:
+ kfree(buf);
+ return err;
+}
+
+static void mxuport_set_termios(struct tty_struct *tty,
+ struct usb_serial_port *port,
+ struct ktermios *old_termios)
+{
+ struct usb_serial *serial = port->serial;
+ u8 *buf;
+ u8 data_bits;
+ u8 stop_bits;
+ u8 parity;
+ int baud;
+ int err;
+
+ if (old_termios &&
+ !tty_termios_hw_change(&tty->termios, old_termios) &&
+ tty->termios.c_iflag == old_termios->c_iflag) {
+ dev_dbg(&port->dev, "%s - nothing to change\n", __func__);
+ return;
+ }
+
+ buf = kmalloc(4, GFP_KERNEL);
+ if (!buf)
+ return;
+
+ /* Set data bit of termios */
+ switch (C_CSIZE(tty)) {
+ case CS5:
+ data_bits = MX_WORDLENGTH_5;
+ break;
+ case CS6:
+ data_bits = MX_WORDLENGTH_6;
+ break;
+ case CS7:
+ data_bits = MX_WORDLENGTH_7;
+ break;
+ case CS8:
+ default:
+ data_bits = MX_WORDLENGTH_8;
+ break;
+ }
+
+ /* Set parity of termios */
+ if (C_PARENB(tty)) {
+ if (C_CMSPAR(tty)) {
+ if (C_PARODD(tty))
+ parity = MX_PARITY_MARK;
+ else
+ parity = MX_PARITY_SPACE;
+ } else {
+ if (C_PARODD(tty))
+ parity = MX_PARITY_ODD;
+ else
+ parity = MX_PARITY_EVEN;
+ }
+ } else {
+ parity = MX_PARITY_NONE;
+ }
+
+ /* Set stop bit of termios */
+ if (C_CSTOPB(tty))
+ stop_bits = MX_STOP_BITS_2;
+ else
+ stop_bits = MX_STOP_BITS_1;
+
+ buf[0] = data_bits;
+ buf[1] = parity;
+ buf[2] = stop_bits;
+ buf[3] = 0;
+
+ err = mxuport_send_ctrl_data_urb(serial, RQ_VENDOR_SET_LINE,
+ 0, port->port_number, buf, 4);
+ if (err)
+ goto out;
+
+ err = mxuport_set_termios_flow(tty, old_termios, port, serial);
+ if (err)
+ goto out;
+
+ baud = tty_get_baud_rate(tty);
+ if (!baud)
+ baud = 9600;
+
+ /* Note: Little Endian */
+ put_unaligned_le32(baud, buf);
+
+ err = mxuport_send_ctrl_data_urb(serial, RQ_VENDOR_SET_BAUD,
+ 0, port->port_number,
+ buf, 4);
+ if (err)
+ goto out;
+
+ dev_dbg(&port->dev, "baud_rate : %d\n", baud);
+ dev_dbg(&port->dev, "data_bits : %d\n", data_bits);
+ dev_dbg(&port->dev, "parity : %d\n", parity);
+ dev_dbg(&port->dev, "stop_bits : %d\n", stop_bits);
+
+out:
+ kfree(buf);
+}
+
+/*
+ * Determine how many ports this device has dynamically. It will be
+ * called after the probe() callback is called, but before attach().
+ */
+static int mxuport_calc_num_ports(struct usb_serial *serial)
+{
+ unsigned long features = (unsigned long)usb_get_serial_data(serial);
+
+ if (features & MX_UPORT_2_PORT)
+ return 2;
+ if (features & MX_UPORT_4_PORT)
+ return 4;
+ if (features & MX_UPORT_8_PORT)
+ return 8;
+ if (features & MX_UPORT_16_PORT)
+ return 16;
+
+ return 0;
+}
+
+/* Get the version of the firmware currently running. */
+static int mxuport_get_fw_version(struct usb_serial *serial, u32 *version)
+{
+ u8 *ver_buf;
+ int err;
+
+ ver_buf = kzalloc(4, GFP_KERNEL);
+ if (!ver_buf)
+ return -ENOMEM;
+
+ /* Get firmware version from SDRAM */
+ err = mxuport_recv_ctrl_urb(serial, RQ_VENDOR_GET_VERSION, 0, 0,
+ ver_buf, 4);
+ if (err != 4) {
+ err = -EIO;
+ goto out;
+ }
+
+ *version = (ver_buf[0] << 16) | (ver_buf[1] << 8) | ver_buf[2];
+ err = 0;
+out:
+ kfree(ver_buf);
+ return err;
+}
+
+/* Given a firmware blob, download it to the device. */
+static int mxuport_download_fw(struct usb_serial *serial,
+ const struct firmware *fw_p)
+{
+ u8 *fw_buf;
+ size_t txlen;
+ size_t fwidx;
+ int err;
+
+ fw_buf = kmalloc(DOWN_BLOCK_SIZE, GFP_KERNEL);
+ if (!fw_buf)
+ return -ENOMEM;
+
+ dev_dbg(&serial->interface->dev, "Starting firmware download...\n");
+ err = mxuport_send_ctrl_urb(serial, RQ_VENDOR_START_FW_DOWN, 0, 0);
+ if (err)
+ goto out;
+
+ fwidx = 0;
+ do {
+ txlen = min_t(size_t, (fw_p->size - fwidx), DOWN_BLOCK_SIZE);
+
+ memcpy(fw_buf, &fw_p->data[fwidx], txlen);
+ err = mxuport_send_ctrl_data_urb(serial, RQ_VENDOR_FW_DATA,
+ 0, 0, fw_buf, txlen);
+ if (err) {
+ mxuport_send_ctrl_urb(serial, RQ_VENDOR_STOP_FW_DOWN,
+ 0, 0);
+ goto out;
+ }
+
+ fwidx += txlen;
+ usleep_range(1000, 2000);
+
+ } while (fwidx < fw_p->size);
+
+ msleep(1000);
+ err = mxuport_send_ctrl_urb(serial, RQ_VENDOR_STOP_FW_DOWN, 0, 0);
+ if (err)
+ goto out;
+
+ msleep(1000);
+ err = mxuport_send_ctrl_urb(serial, RQ_VENDOR_QUERY_FW_READY, 0, 0);
+
+out:
+ kfree(fw_buf);
+ return err;
+}
+
+static int mxuport_probe(struct usb_serial *serial,
+ const struct usb_device_id *id)
+{
+ u16 productid = le16_to_cpu(serial->dev->descriptor.idProduct);
+ const struct firmware *fw_p = NULL;
+ u32 version;
+ int local_ver;
+ char buf[32];
+ int err;
+
+ /* Load our firmware */
+ err = mxuport_send_ctrl_urb(serial, RQ_VENDOR_QUERY_FW_CONFIG, 0, 0);
+ if (err) {
+ mxuport_send_ctrl_urb(serial, RQ_VENDOR_RESET_DEVICE, 0, 0);
+ return err;
+ }
+
+ err = mxuport_get_fw_version(serial, &version);
+ if (err < 0)
+ return err;
+
+ dev_dbg(&serial->interface->dev, "Device firmware version v%x.%x.%x\n",
+ (version & 0xff0000) >> 16,
+ (version & 0xff00) >> 8,
+ (version & 0xff));
+
+ snprintf(buf, sizeof(buf) - 1, "moxa/moxa-%04x.fw", productid);
+
+ err = request_firmware(&fw_p, buf, &serial->interface->dev);
+ if (err) {
+ dev_warn(&serial->interface->dev, "Firmware %s not found\n",
+ buf);
+
+ /* Use the firmware already in the device */
+ err = 0;
+ } else {
+ local_ver = ((fw_p->data[VER_ADDR_1] << 16) |
+ (fw_p->data[VER_ADDR_2] << 8) |
+ fw_p->data[VER_ADDR_3]);
+ dev_dbg(&serial->interface->dev,
+ "Available firmware version v%x.%x.%x\n",
+ fw_p->data[VER_ADDR_1], fw_p->data[VER_ADDR_2],
+ fw_p->data[VER_ADDR_3]);
+ if (local_ver > version) {
+ err = mxuport_download_fw(serial, fw_p);
+ if (err)
+ goto out;
+ err = mxuport_get_fw_version(serial, &version);
+ if (err < 0)
+ goto out;
+ }
+ }
+
+ dev_info(&serial->interface->dev,
+ "Using device firmware version v%x.%x.%x\n",
+ (version & 0xff0000) >> 16,
+ (version & 0xff00) >> 8,
+ (version & 0xff));
+
+ /*
+ * Contains the features of this hardware. Store away for
+ * later use, eg, number of ports.
+ */
+ usb_set_serial_data(serial, (void *)id->driver_info);
+out:
+ if (fw_p)
+ release_firmware(fw_p);
+ return err;
+}
+
+
+static int mxuport_port_probe(struct usb_serial_port *port)
+{
+ struct usb_serial *serial = port->serial;
+ struct mxuport_port *mxport;
+ int err;
+
+ mxport = devm_kzalloc(&port->dev, sizeof(struct mxuport_port),
+ GFP_KERNEL);
+ if (!mxport)
+ return -ENOMEM;
+
+ mutex_init(&mxport->mutex);
+ spin_lock_init(&mxport->spinlock);
+
+ /* Set the port private data */
+ usb_set_serial_port_data(port, mxport);
+
+ /* Set FIFO (Enable) */
+ err = mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_FIFO_DISABLE,
+ 0, port->port_number);
+ if (err)
+ return err;
+
+ /* Set transmission mode (Hi-Performance) */
+ err = mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_HIGH_PERFOR,
+ 0, port->port_number);
+ if (err)
+ return err;
+
+ /* Set interface (RS-232) */
+ err = mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_INTERFACE,
+ MX_INT_RS232,
+ port->port_number);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static int mxuport_alloc_write_urb(struct usb_serial *serial,
+ struct usb_serial_port *port,
+ struct usb_serial_port *port0,
+ int j)
+{
+ struct usb_device *dev = interface_to_usbdev(serial->interface);
+
+ set_bit(j, &port->write_urbs_free);
+ port->write_urbs[j] = usb_alloc_urb(0, GFP_KERNEL);
+ if (!port->write_urbs[j])
+ return -ENOMEM;
+
+ port->bulk_out_buffers[j] = kmalloc(port0->bulk_out_size, GFP_KERNEL);
+ if (!port->bulk_out_buffers[j])
+ return -ENOMEM;
+
+ usb_fill_bulk_urb(port->write_urbs[j], dev,
+ usb_sndbulkpipe(dev, port->bulk_out_endpointAddress),
+ port->bulk_out_buffers[j],
+ port->bulk_out_size,
+ serial->type->write_bulk_callback,
+ port);
+ return 0;
+}
+
+
+static int mxuport_alloc_write_urbs(struct usb_serial *serial,
+ struct usb_serial_port *port,
+ struct usb_serial_port *port0)
+{
+ int j;
+ int ret;
+
+ for (j = 0; j < ARRAY_SIZE(port->write_urbs); ++j) {
+ ret = mxuport_alloc_write_urb(serial, port, port0, j);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+
+static int mxuport_attach(struct usb_serial *serial)
+{
+ struct usb_serial_port *port0 = serial->port[0];
+ struct usb_serial_port *port1 = serial->port[1];
+ struct usb_serial_port *port;
+ int err;
+ int i;
+ int j;
+
+ /*
+ * Throw away all but the first allocated write URBs so we can
+ * set them up again to fit the multiplexing scheme.
+ */
+ for (i = 1; i < serial->num_bulk_out; ++i) {
+ port = serial->port[i];
+ for (j = 0; j < ARRAY_SIZE(port->write_urbs); ++j) {
+ usb_free_urb(port->write_urbs[j]);
+ kfree(port->bulk_out_buffers[j]);
+ port->write_urbs[j] = NULL;
+ port->bulk_out_buffers[j] = NULL;
+ }
+ port->write_urbs_free = 0;
+ }
+
+ /*
+ * All write data is sent over the first bulk out endpoint,
+ * with an added header to indicate the port. Allocate URBs
+ * for each port to the first bulk out endpoint.
+ */
+ for (i = 1; i < serial->num_ports; ++i) {
+ port = serial->port[i];
+ port->bulk_out_size = port0->bulk_out_size;
+ port->bulk_out_endpointAddress =
+ port0->bulk_out_endpointAddress;
+
+ err = mxuport_alloc_write_urbs(serial, port, port0);
+ if (err)
+ return err;
+
+ port->write_urb = port->write_urbs[0];
+ port->bulk_out_buffer = port->bulk_out_buffers[0];
+
+ /*
+ * Ensure each port has a fifo. The framework only
+ * allocates a fifo to ports with a bulk out endpoint,
+ * where as we need one for every port.
+ */
+ if (!kfifo_initialized(&port->write_fifo)) {
+ err = kfifo_alloc(&port->write_fifo, PAGE_SIZE,
+ GFP_KERNEL);
+ if (err)
+ return err;
+ }
+ }
+
+ /*
+ * All data from the ports is received on the first bulk in
+ * endpoint, with a multiplex header. The second bulk in is
+ * used for events.
+ *
+ * Start to read from the device.
+ */
+ err = usb_serial_generic_submit_read_urbs(port0, GFP_KERNEL);
+ if (err)
+ return err;
+
+ err = usb_serial_generic_submit_read_urbs(port1, GFP_KERNEL);
+ if (err) {
+ usb_serial_generic_close(port0);
+ return err;
+ }
+
+ return 0;
+}
+
+static int mxuport_open(struct tty_struct *tty, struct usb_serial_port *port)
+{
+ struct mxuport_port *mxport = usb_get_serial_port_data(port);
+ struct usb_serial *serial = port->serial;
+ int err;
+
+ /* Set receive host (enable) */
+ err = mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_RX_HOST_EN,
+ 1, port->port_number);
+ if (err)
+ return err;
+
+ err = mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_OPEN,
+ 1, port->port_number);
+ if (err) {
+ mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_RX_HOST_EN,
+ 0, port->port_number);
+ return err;
+ }
+
+ /* Initial port termios */
+ mxuport_set_termios(tty, port, NULL);
+
+ /*
+ * TODO: use RQ_VENDOR_GET_MSR, once we know what it
+ * returns.
+ */
+ mxport->msr_state = 0;
+
+ return err;
+}
+
+static void mxuport_close(struct usb_serial_port *port)
+{
+ struct usb_serial *serial = port->serial;
+
+ mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_OPEN, 0,
+ port->port_number);
+
+ mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_RX_HOST_EN, 0,
+ port->port_number);
+}
+
+/* Send a break to the port. */
+static void mxuport_break_ctl(struct tty_struct *tty, int break_state)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ struct usb_serial *serial = port->serial;
+ int enable;
+
+ if (break_state == -1) {
+ enable = 1;
+ dev_dbg(&port->dev, "%s - sending break\n", __func__);
+ } else {
+ enable = 0;
+ dev_dbg(&port->dev, "%s - clearing break\n", __func__);
+ }
+
+ mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_BREAK,
+ enable, port->port_number);
+}
+
+static int mxuport_resume(struct usb_serial *serial)
+{
+ struct usb_serial_port *port;
+ int c = 0;
+ int i;
+ int r;
+
+ for (i = 0; i < 2; i++) {
+ port = serial->port[i];
+
+ r = usb_serial_generic_submit_read_urbs(port, GFP_NOIO);
+ if (r < 0)
+ c++;
+ }
+
+ for (i = 0; i < serial->num_ports; i++) {
+ port = serial->port[i];
+ if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags))
+ continue;
+
+ r = usb_serial_generic_write_start(port, GFP_NOIO);
+ if (r < 0)
+ c++;
+ }
+
+ return c ? -EIO : 0;
+}
+
+static struct usb_serial_driver mxuport_device = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "mxuport",
+ },
+ .description = "MOXA UPort",
+ .id_table = mxuport_idtable,
+ .num_ports = 0,
+ .probe = mxuport_probe,
+ .port_probe = mxuport_port_probe,
+ .attach = mxuport_attach,
+ .calc_num_ports = mxuport_calc_num_ports,
+ .open = mxuport_open,
+ .close = mxuport_close,
+ .set_termios = mxuport_set_termios,
+ .break_ctl = mxuport_break_ctl,
+ .tx_empty = mxuport_tx_empty,
+ .tiocmiwait = usb_serial_generic_tiocmiwait,
+ .get_icount = usb_serial_generic_get_icount,
+ .throttle = mxuport_throttle,
+ .unthrottle = mxuport_unthrottle,
+ .tiocmget = mxuport_tiocmget,
+ .tiocmset = mxuport_tiocmset,
+ .dtr_rts = mxuport_dtr_rts,
+ .process_read_urb = mxuport_process_read_urb,
+ .prepare_write_buffer = mxuport_prepare_write_buffer,
+ .resume = mxuport_resume,
+};
+
+static struct usb_serial_driver *const serial_drivers[] = {
+ &mxuport_device, NULL
+};
+
+module_usb_serial_driver(serial_drivers, mxuport_idtable);
+
+MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch>");
+MODULE_AUTHOR("<support@moxa.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/navman.c b/drivers/usb/serial/navman.c
index 1566f8f500a..2a97cdc078d 100644
--- a/drivers/usb/serial/navman.c
+++ b/drivers/usb/serial/navman.c
@@ -14,7 +14,6 @@
#include <linux/gfp.h>
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/module.h>
@@ -32,7 +31,6 @@ static void navman_read_int_callback(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
unsigned char *data = urb->transfer_buffer;
- struct tty_struct *tty;
int status = urb->status;
int result;
@@ -55,12 +53,10 @@ static void navman_read_int_callback(struct urb *urb)
usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data);
- tty = tty_port_tty_get(&port->port);
- if (tty && urb->actual_length) {
- tty_insert_flip_string(tty, data, urb->actual_length);
- tty_flip_buffer_push(tty);
+ if (urb->actual_length) {
+ tty_insert_flip_string(&port->port, data, urb->actual_length);
+ tty_flip_buffer_push(&port->port);
}
- tty_kref_put(tty);
exit:
result = usb_submit_urb(urb, GFP_ATOMIC);
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
index 7818af931a4..f6c6900bccf 100644
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -13,7 +13,6 @@
#include <linux/kernel.h>
#include <linux/errno.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
@@ -33,8 +32,7 @@
/* function prototypes */
static int omninet_open(struct tty_struct *tty, struct usb_serial_port *port);
-static void omninet_close(struct usb_serial_port *port);
-static void omninet_read_bulk_callback(struct urb *urb);
+static void omninet_process_read_urb(struct urb *urb);
static void omninet_write_bulk_callback(struct urb *urb);
static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count);
@@ -61,11 +59,10 @@ static struct usb_serial_driver zyxel_omninet_device = {
.port_probe = omninet_port_probe,
.port_remove = omninet_port_remove,
.open = omninet_open,
- .close = omninet_close,
.write = omninet_write,
.write_room = omninet_write_room,
- .read_bulk_callback = omninet_read_bulk_callback,
.write_bulk_callback = omninet_write_bulk_callback,
+ .process_read_urb = omninet_process_read_urb,
.disconnect = omninet_disconnect,
};
@@ -74,29 +71,28 @@ static struct usb_serial_driver * const serial_drivers[] = {
};
-/* The protocol.
+/*
+ * The protocol.
*
* The omni.net always exchange 64 bytes of data with the host. The first
- * four bytes are the control header, you can see it in the above structure.
+ * four bytes are the control header.
*
* oh_seq is a sequence number. Don't know if/how it's used.
* oh_len is the length of the data bytes in the packet.
* oh_xxx Bit-mapped, related to handshaking and status info.
- * I normally set it to 0x03 in trasmitted frames.
+ * I normally set it to 0x03 in transmitted frames.
* 7: Active when the TA is in a CONNECTed state.
* 6: unknown
* 5: handshaking, unknown
* 4: handshaking, unknown
* 3: unknown, usually 0
* 2: unknown, usually 0
- * 1: handshaking, unknown, usually set to 1 in trasmitted frames
- * 0: handshaking, unknown, usually set to 1 in trasmitted frames
+ * 1: handshaking, unknown, usually set to 1 in transmitted frames
+ * 0: handshaking, unknown, usually set to 1 in transmitted frames
* oh_pad Probably a pad byte.
*
* After the header you will find data bytes if oh_len was greater than zero.
- *
*/
-
struct omninet_header {
__u8 oh_seq;
__u8 oh_len;
@@ -112,7 +108,7 @@ static int omninet_port_probe(struct usb_serial_port *port)
{
struct omninet_data *od;
- od = kmalloc(sizeof(struct omninet_data), GFP_KERNEL);
+ od = kzalloc(sizeof(*od), GFP_KERNEL);
if (!od)
return -ENOMEM;
@@ -135,60 +131,32 @@ static int omninet_open(struct tty_struct *tty, struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
struct usb_serial_port *wport;
- int result = 0;
wport = serial->port[1];
tty_port_tty_set(&wport->port, tty);
- /* Start reading from the device */
- result = usb_submit_urb(port->read_urb, GFP_KERNEL);
- if (result)
- dev_err(&port->dev,
- "%s - failed submitting read urb, error %d\n",
- __func__, result);
- return result;
-}
-
-static void omninet_close(struct usb_serial_port *port)
-{
- usb_kill_urb(port->read_urb);
+ return usb_serial_generic_open(tty, port);
}
+#define OMNINET_HEADERLEN 4
+#define OMNINET_BULKOUTSIZE 64
+#define OMNINET_PAYLOADSIZE (OMNINET_BULKOUTSIZE - OMNINET_HEADERLEN)
-#define OMNINET_DATAOFFSET 0x04
-#define OMNINET_HEADERLEN sizeof(struct omninet_header)
-#define OMNINET_BULKOUTSIZE (64 - OMNINET_HEADERLEN)
-
-static void omninet_read_bulk_callback(struct urb *urb)
+static void omninet_process_read_urb(struct urb *urb)
{
- struct usb_serial_port *port = urb->context;
- unsigned char *data = urb->transfer_buffer;
- struct omninet_header *header = (struct omninet_header *) &data[0];
- int status = urb->status;
- int result;
+ struct usb_serial_port *port = urb->context;
+ const struct omninet_header *hdr = urb->transfer_buffer;
+ const unsigned char *data;
+ size_t data_len;
- if (status) {
- dev_dbg(&port->dev, "%s - nonzero read bulk status received: %d\n",
- __func__, status);
+ if (urb->actual_length <= OMNINET_HEADERLEN || !hdr->oh_len)
return;
- }
-
- if (urb->actual_length && header->oh_len) {
- struct tty_struct *tty = tty_port_tty_get(&port->port);
- if (tty) {
- tty_insert_flip_string(tty, data + OMNINET_DATAOFFSET,
- header->oh_len);
- tty_flip_buffer_push(tty);
- tty_kref_put(tty);
- }
- }
- /* Continue trying to always read */
- result = usb_submit_urb(urb, GFP_ATOMIC);
- if (result)
- dev_err(&port->dev,
- "%s - failed resubmitting read urb, error %d\n",
- __func__, result);
+ data = (char *)urb->transfer_buffer + OMNINET_HEADERLEN;
+ data_len = min_t(size_t, urb->actual_length - OMNINET_HEADERLEN,
+ hdr->oh_len);
+ tty_insert_flip_string(&port->port, data, data_len);
+ tty_flip_buffer_push(&port->port);
}
static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port,
@@ -213,9 +181,9 @@ static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port,
return 0;
}
- count = (count > OMNINET_BULKOUTSIZE) ? OMNINET_BULKOUTSIZE : count;
+ count = (count > OMNINET_PAYLOADSIZE) ? OMNINET_PAYLOADSIZE : count;
- memcpy(wport->write_urb->transfer_buffer + OMNINET_DATAOFFSET,
+ memcpy(wport->write_urb->transfer_buffer + OMNINET_HEADERLEN,
buf, count);
usb_serial_debug_data(&port->dev, __func__, count,
@@ -227,7 +195,7 @@ static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port,
header->oh_pad = 0x00;
/* send the data out the bulk port, always 64 bytes */
- wport->write_urb->transfer_buffer_length = 64;
+ wport->write_urb->transfer_buffer_length = OMNINET_BULKOUTSIZE;
result = usb_submit_urb(wport->write_urb, GFP_ATOMIC);
if (result) {
diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c
index c6bfb83efb1..4856fb7e637 100644
--- a/drivers/usb/serial/opticon.c
+++ b/drivers/usb/serial/opticon.c
@@ -12,7 +12,6 @@
*/
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/slab.h>
@@ -51,15 +50,8 @@ struct opticon_private {
static void opticon_process_data_packet(struct usb_serial_port *port,
const unsigned char *buf, size_t len)
{
- struct tty_struct *tty;
-
- tty = tty_port_tty_get(&port->port);
- if (!tty)
- return;
-
- tty_insert_flip_string(tty, buf, len);
- tty_flip_buffer_push(tty);
- tty_kref_put(tty);
+ tty_insert_flip_string(&port->port, buf, len);
+ tty_flip_buffer_push(&port->port);
}
static void opticon_process_status_packet(struct usb_serial_port *port,
@@ -127,7 +119,10 @@ static int send_control_msg(struct usb_serial_port *port, u8 requesttype,
0, 0, buffer, 1, 0);
kfree(buffer);
- return retval;
+ if (retval < 0)
+ return retval;
+
+ return 0;
}
static int opticon_open(struct tty_struct *tty, struct usb_serial_port *port)
@@ -143,7 +138,7 @@ static int opticon_open(struct tty_struct *tty, struct usb_serial_port *port)
/* Clear RTS line */
send_control_msg(port, CONTROL_RTS, 0);
- /* clear the halt status of the enpoint */
+ /* clear the halt status of the endpoint */
usb_clear_halt(port->serial->dev, port->read_urb->pipe);
res = usb_serial_generic_open(tty, port);
@@ -204,15 +199,12 @@ static int opticon_write(struct tty_struct *tty, struct usb_serial_port *port,
buffer = kmalloc(count, 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;
}
@@ -221,11 +213,10 @@ static int opticon_write(struct tty_struct *tty, struct usb_serial_port *port,
usb_serial_debug_data(&port->dev, __func__, count, buffer);
- /* The conncected devices do not have a bulk write endpoint,
+ /* The connected devices do not have a bulk write endpoint,
* to transmit data to de barcode device the control endpoint is used */
dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO);
if (!dr) {
- dev_err(&port->dev, "out of memory\n");
count = -ENOMEM;
goto error_no_dr;
}
@@ -313,7 +304,6 @@ static int opticon_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear)
{
struct usb_serial_port *port = tty->driver_data;
- struct usb_serial *serial = port->serial;
struct opticon_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
bool rts;
@@ -334,15 +324,11 @@ static int opticon_tiocmset(struct tty_struct *tty,
if (!changed)
return 0;
- /* Send the new RTS state to the connected device */
- mutex_lock(&serial->disc_mutex);
- if (!serial->disconnected)
- ret = send_control_msg(port, CONTROL_RTS, !rts);
- else
- ret = -ENODEV;
- mutex_unlock(&serial->disc_mutex);
+ ret = send_control_msg(port, CONTROL_RTS, !rts);
+ if (ret)
+ return usb_translate_errors(ret);
- return ret;
+ return 0;
}
static int get_serial_info(struct usb_serial_port *port,
@@ -357,7 +343,7 @@ static int get_serial_info(struct usb_serial_port *port,
/* fake emulate a 16550 uart to make userspace code happy */
tmp.type = PORT_16550A;
- tmp.line = port->serial->minor;
+ tmp.line = port->minor;
tmp.port = 0;
tmp.irq = 0;
tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
@@ -376,8 +362,6 @@ static int opticon_ioctl(struct tty_struct *tty,
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(&port->dev, "%s - port %d, cmd = 0x%x\n", __func__, port->number, cmd);
-
switch (cmd) {
case TIOCGSERIAL:
return get_serial_info(port,
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 0d9dac9e7f9..a9688940543 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -81,9 +81,11 @@ static void option_instat_callback(struct urb *urb);
#define HUAWEI_VENDOR_ID 0x12D1
#define HUAWEI_PRODUCT_E173 0x140C
+#define HUAWEI_PRODUCT_E1750 0x1406
#define HUAWEI_PRODUCT_K4505 0x1464
#define HUAWEI_PRODUCT_K3765 0x1465
#define HUAWEI_PRODUCT_K4605 0x14C6
+#define HUAWEI_PRODUCT_E173S6 0x1C07
#define QUANTA_VENDOR_ID 0x0408
#define QUANTA_PRODUCT_Q101 0xEA02
@@ -159,8 +161,7 @@ static void option_instat_callback(struct urb *urb);
#define NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_FULLSPEED 0x9000
#define NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_HIGHSPEED 0x9001
#define NOVATELWIRELESS_PRODUCT_E362 0x9010
-#define NOVATELWIRELESS_PRODUCT_G1 0xA001
-#define NOVATELWIRELESS_PRODUCT_G1_M 0xA002
+#define NOVATELWIRELESS_PRODUCT_E371 0x9011
#define NOVATELWIRELESS_PRODUCT_G2 0xA010
#define NOVATELWIRELESS_PRODUCT_MC551 0xB001
@@ -196,6 +197,7 @@ static void option_instat_callback(struct urb *urb);
#define DELL_PRODUCT_5800_MINICARD_VZW 0x8195 /* Novatel E362 */
#define DELL_PRODUCT_5800_V2_MINICARD_VZW 0x8196 /* Novatel E362 */
+#define DELL_PRODUCT_5804_MINICARD_ATT 0x819b /* Novatel E371 */
#define KYOCERA_VENDOR_ID 0x0c88
#define KYOCERA_PRODUCT_KPC650 0x17da
@@ -233,8 +235,31 @@ static void option_instat_callback(struct urb *urb);
#define QUALCOMM_VENDOR_ID 0x05C6
#define CMOTECH_VENDOR_ID 0x16d8
-#define CMOTECH_PRODUCT_6008 0x6008
-#define CMOTECH_PRODUCT_6280 0x6280
+#define CMOTECH_PRODUCT_6001 0x6001
+#define CMOTECH_PRODUCT_CMU_300 0x6002
+#define CMOTECH_PRODUCT_6003 0x6003
+#define CMOTECH_PRODUCT_6004 0x6004
+#define CMOTECH_PRODUCT_6005 0x6005
+#define CMOTECH_PRODUCT_CGU_628A 0x6006
+#define CMOTECH_PRODUCT_CHE_628S 0x6007
+#define CMOTECH_PRODUCT_CMU_301 0x6008
+#define CMOTECH_PRODUCT_CHU_628 0x6280
+#define CMOTECH_PRODUCT_CHU_628S 0x6281
+#define CMOTECH_PRODUCT_CDU_680 0x6803
+#define CMOTECH_PRODUCT_CDU_685A 0x6804
+#define CMOTECH_PRODUCT_CHU_720S 0x7001
+#define CMOTECH_PRODUCT_7002 0x7002
+#define CMOTECH_PRODUCT_CHU_629K 0x7003
+#define CMOTECH_PRODUCT_7004 0x7004
+#define CMOTECH_PRODUCT_7005 0x7005
+#define CMOTECH_PRODUCT_CGU_629 0x7006
+#define CMOTECH_PRODUCT_CHU_629S 0x700a
+#define CMOTECH_PRODUCT_CHU_720I 0x7211
+#define CMOTECH_PRODUCT_7212 0x7212
+#define CMOTECH_PRODUCT_7213 0x7213
+#define CMOTECH_PRODUCT_7251 0x7251
+#define CMOTECH_PRODUCT_7252 0x7252
+#define CMOTECH_PRODUCT_7253 0x7253
#define TELIT_VENDOR_ID 0x1bc7
#define TELIT_PRODUCT_UC864E 0x1003
@@ -242,19 +267,16 @@ static void option_instat_callback(struct urb *urb);
#define TELIT_PRODUCT_CC864_DUAL 0x1005
#define TELIT_PRODUCT_CC864_SINGLE 0x1006
#define TELIT_PRODUCT_DE910_DUAL 0x1010
+#define TELIT_PRODUCT_UE910_V2 0x1012
+#define TELIT_PRODUCT_LE920 0x1200
/* ZTE PRODUCTS */
#define ZTE_VENDOR_ID 0x19d2
#define ZTE_PRODUCT_MF622 0x0001
#define ZTE_PRODUCT_MF628 0x0015
#define ZTE_PRODUCT_MF626 0x0031
-#define ZTE_PRODUCT_CDMA_TECH 0xfffe
-#define ZTE_PRODUCT_AC8710 0xfff1
-#define ZTE_PRODUCT_AC2726 0xfff5
-#define ZTE_PRODUCT_AC8710T 0xffff
#define ZTE_PRODUCT_MC2718 0xffe8
-#define ZTE_PRODUCT_AD3812 0xffeb
-#define ZTE_PRODUCT_MC2716 0xffed
+#define ZTE_PRODUCT_AC2726 0xfff1
#define BENQ_VENDOR_ID 0x04a5
#define BENQ_PRODUCT_H10 0x4068
@@ -289,6 +311,7 @@ static void option_instat_callback(struct urb *urb);
#define ALCATEL_PRODUCT_X060S_X200 0x0000
#define ALCATEL_PRODUCT_X220_X500D 0x0017
#define ALCATEL_PRODUCT_L100V 0x011e
+#define ALCATEL_PRODUCT_L800MA 0x0203
#define PIRELLI_VENDOR_ID 0x1266
#define PIRELLI_PRODUCT_C100_1 0x1002
@@ -323,9 +346,15 @@ static void option_instat_callback(struct urb *urb);
* It seems to contain a Qualcomm QSC6240/6290 chipset */
#define FOUR_G_SYSTEMS_PRODUCT_W14 0x9603
+/* iBall 3.5G connect wireless modem */
+#define IBALL_3_5G_CONNECT 0x9605
+
/* Zoom */
#define ZOOM_PRODUCT_4597 0x9607
+/* SpeedUp SU9800 usb 3g modem */
+#define SPEEDUP_PRODUCT_SU9800 0x9800
+
/* Haier products */
#define HAIER_VENDOR_ID 0x201e
#define HAIER_PRODUCT_CE100 0x2009
@@ -340,21 +369,24 @@ static void option_instat_callback(struct urb *urb);
#define CINTERION_PRODUCT_EU3_E 0x0051
#define CINTERION_PRODUCT_EU3_P 0x0052
#define CINTERION_PRODUCT_PH8 0x0053
+#define CINTERION_PRODUCT_AHXX 0x0055
+#define CINTERION_PRODUCT_PLXX 0x0060
/* Olivetti products */
#define OLIVETTI_VENDOR_ID 0x0b3c
#define OLIVETTI_PRODUCT_OLICARD100 0xc000
+#define OLIVETTI_PRODUCT_OLICARD120 0xc001
+#define OLIVETTI_PRODUCT_OLICARD140 0xc002
+#define OLIVETTI_PRODUCT_OLICARD145 0xc003
+#define OLIVETTI_PRODUCT_OLICARD155 0xc004
+#define OLIVETTI_PRODUCT_OLICARD200 0xc005
+#define OLIVETTI_PRODUCT_OLICARD160 0xc00a
+#define OLIVETTI_PRODUCT_OLICARD500 0xc00b
/* Celot products */
#define CELOT_VENDOR_ID 0x211f
#define CELOT_PRODUCT_CT680M 0x6801
-/* ONDA Communication vendor id */
-#define ONDA_VENDOR_ID 0x1ee8
-
-/* ONDA MT825UP HSDPA 14.2 modem */
-#define ONDA_MT825UP 0x000b
-
/* Samsung products */
#define SAMSUNG_VENDOR_ID 0x04e8
#define SAMSUNG_PRODUCT_GT_B3730 0x6889
@@ -447,12 +479,21 @@ static void option_instat_callback(struct urb *urb);
/* Hyundai Petatel Inc. products */
#define PETATEL_VENDOR_ID 0x1ff4
-#define PETATEL_PRODUCT_NP10T 0x600e
+#define PETATEL_PRODUCT_NP10T_600A 0x600a
+#define PETATEL_PRODUCT_NP10T_600E 0x600e
/* TP-LINK Incorporated products */
#define TPLINK_VENDOR_ID 0x2357
#define TPLINK_PRODUCT_MA180 0x0201
+/* Changhong products */
+#define CHANGHONG_VENDOR_ID 0x2077
+#define CHANGHONG_PRODUCT_CH690 0x7001
+
+/* Inovia */
+#define INOVIA_VENDOR_ID 0x20a6
+#define INOVIA_SEW858 0x1105
+
/* some devices interfaces need special handling due to a number of reasons */
enum option_blacklist_reason {
OPTION_BLACKLIST_NONE = 0,
@@ -474,6 +515,7 @@ static const struct option_blacklist_info four_g_w14_blacklist = {
static const struct option_blacklist_info alcatel_x200_blacklist = {
.sendsetup = BIT(0) | BIT(1),
+ .reserved = BIT(4),
};
static const struct option_blacklist_info zte_0037_blacklist = {
@@ -485,22 +527,18 @@ static const struct option_blacklist_info zte_k3765_z_blacklist = {
.reserved = BIT(4),
};
-static const struct option_blacklist_info zte_ad3812_z_blacklist = {
- .sendsetup = BIT(0) | BIT(1) | BIT(2),
-};
-
static const struct option_blacklist_info zte_mc2718_z_blacklist = {
.sendsetup = BIT(1) | BIT(2) | BIT(3) | BIT(4),
};
-static const struct option_blacklist_info zte_mc2716_z_blacklist = {
- .sendsetup = BIT(1) | BIT(2) | BIT(3),
-};
-
static const struct option_blacklist_info huawei_cdc12_blacklist = {
.reserved = BIT(1) | BIT(2),
};
+static const struct option_blacklist_info net_intf0_blacklist = {
+ .reserved = BIT(0),
+};
+
static const struct option_blacklist_info net_intf1_blacklist = {
.reserved = BIT(1),
};
@@ -534,6 +572,11 @@ static const struct option_blacklist_info zte_1255_blacklist = {
.reserved = BIT(3) | BIT(4),
};
+static const struct option_blacklist_info telit_le920_blacklist = {
+ .sendsetup = BIT(0),
+ .reserved = BIT(1) | BIT(5),
+};
+
static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) },
@@ -565,12 +608,25 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GLX) },
{ USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GKE) },
{ USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GLE) },
+ { USB_DEVICE(QUANTA_VENDOR_ID, 0xea42),
+ .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c05, USB_CLASS_COMM, 0x02, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c1f, USB_CLASS_COMM, 0x02, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c23, USB_CLASS_COMM, 0x02, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E173, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t) &net_intf1_blacklist },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E173S6, 0xff, 0xff, 0xff),
+ .driver_info = (kernel_ulong_t) &net_intf1_blacklist },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1750, 0xff, 0xff, 0xff),
+ .driver_info = (kernel_ulong_t) &net_intf2_blacklist },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1441, USB_CLASS_COMM, 0x02, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1442, USB_CLASS_COMM, 0x02, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4505, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3765, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x14ac, 0xff, 0xff, 0xff), /* Huawei E1820 */
+ .driver_info = (kernel_ulong_t) &net_intf1_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4605, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0xff, 0xff) },
@@ -623,6 +679,10 @@ static const struct usb_device_id option_ids[] = {
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x6D) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x6E) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x6F) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x72) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x73) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x74) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x75) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x78) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x79) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x7A) },
@@ -677,11 +737,247 @@ static const struct usb_device_id option_ids[] = {
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x6D) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x6E) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x6F) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x72) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x73) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x74) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x75) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x78) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x79) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x7A) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x7B) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x7C) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x01) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x02) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x03) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x04) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x05) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x06) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x0A) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x0B) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x0D) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x0E) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x0F) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x10) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x12) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x13) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x14) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x15) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x17) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x18) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x19) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x1A) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x1B) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x1C) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x31) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x32) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x33) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x34) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x35) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x36) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x3A) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x3B) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x3D) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x3E) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x3F) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x48) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x49) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x4A) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x4B) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x4C) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x61) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x62) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x63) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x64) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x65) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x66) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x6A) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x6B) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x6D) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x6E) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x6F) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x72) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x73) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x74) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x75) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x78) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x79) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x7A) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x7B) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x7C) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x01) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x02) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x03) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x04) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x05) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x06) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x0A) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x0B) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x0D) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x0E) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x0F) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x10) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x12) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x13) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x14) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x15) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x17) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x18) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x19) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x1A) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x1B) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x1C) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x31) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x32) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x33) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x34) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x35) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x36) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x3A) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x3B) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x3D) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x3E) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x3F) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x48) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x49) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x4A) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x4B) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x4C) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x61) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x62) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x63) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x64) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x65) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x66) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x6A) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x6B) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x6D) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x6E) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x6F) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x72) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x73) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x74) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x75) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x78) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x79) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x7A) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x7B) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x7C) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x01) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x02) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x03) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x04) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x05) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x06) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x0A) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x0B) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x0D) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x0E) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x0F) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x10) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x12) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x13) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x14) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x15) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x17) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x18) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x19) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x1A) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x1B) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x1C) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x31) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x32) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x33) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x34) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x35) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x36) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x3A) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x3B) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x3D) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x3E) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x3F) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x48) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x49) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x4A) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x4B) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x4C) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x61) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x62) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x63) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x64) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x65) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x66) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x6A) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x6B) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x6D) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x6E) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x6F) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x72) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x73) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x74) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x75) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x78) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x79) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x7A) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x7B) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x7C) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x01) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x02) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x03) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x04) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x05) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x06) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x0A) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x0B) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x0D) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x0E) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x0F) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x10) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x12) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x13) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x14) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x15) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x17) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x18) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x19) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x1A) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x1B) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x1C) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x31) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x32) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x33) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x34) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x35) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x36) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x3A) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x3B) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x3D) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x3E) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x3F) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x48) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x49) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x4A) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x4B) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x4C) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x61) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x62) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x63) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x64) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x65) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x66) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x6A) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x6B) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x6D) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x6E) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x6F) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x72) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x73) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x74) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x75) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x78) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x79) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x7A) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x7B) },
+ { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x7C) },
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V640) },
@@ -720,12 +1016,11 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC547) },
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EVDO_EMBEDDED_HIGHSPEED) },
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_HIGHSPEED) },
- { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_G1) },
- { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_G1_M) },
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_G2) },
/* Novatel Ovation MC551 a.k.a. Verizon USB551L */
{ USB_DEVICE_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC551, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_E362, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_E371, 0xff, 0xff, 0xff) },
{ USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H01) },
{ USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H01A) },
@@ -750,6 +1045,7 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5730_MINICARD_VZW) }, /* Dell Wireless 5730 Mobile Broadband EVDO/HSPA Mini-Card */
{ USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, DELL_PRODUCT_5800_MINICARD_VZW, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, DELL_PRODUCT_5800_V2_MINICARD_VZW, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, DELL_PRODUCT_5804_MINICARD_ATT, 0xff, 0xff, 0xff) },
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_E100A) }, /* ADU-E100, ADU-310 */
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_500A) },
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_620UW) },
@@ -774,16 +1070,58 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_INTERFACE_CLASS(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1012, 0xff) },
{ USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC650) },
{ USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC680) },
- { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6000)}, /* ZTE AC8700 */
{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */
+ { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x0023)}, /* ONYX 3G device */
{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000)}, /* SIMCom SIM5218 */
- { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6280) }, /* BP3-USB & BP3-EXT HSDPA */
- { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6008) },
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6001) },
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CMU_300) },
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6003),
+ .driver_info = (kernel_ulong_t)&net_intf0_blacklist },
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6004) },
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6005) },
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CGU_628A) },
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHE_628S),
+ .driver_info = (kernel_ulong_t)&net_intf0_blacklist },
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CMU_301),
+ .driver_info = (kernel_ulong_t)&net_intf0_blacklist },
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHU_628),
+ .driver_info = (kernel_ulong_t)&net_intf0_blacklist },
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHU_628S) },
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CDU_680) },
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CDU_685A) },
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHU_720S),
+ .driver_info = (kernel_ulong_t)&net_intf0_blacklist },
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7002),
+ .driver_info = (kernel_ulong_t)&net_intf0_blacklist },
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHU_629K),
+ .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7004),
+ .driver_info = (kernel_ulong_t)&net_intf3_blacklist },
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7005) },
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CGU_629),
+ .driver_info = (kernel_ulong_t)&net_intf5_blacklist },
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHU_629S),
+ .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHU_720I),
+ .driver_info = (kernel_ulong_t)&net_intf0_blacklist },
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7212),
+ .driver_info = (kernel_ulong_t)&net_intf0_blacklist },
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7213),
+ .driver_info = (kernel_ulong_t)&net_intf0_blacklist },
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7251),
+ .driver_info = (kernel_ulong_t)&net_intf1_blacklist },
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7252),
+ .driver_info = (kernel_ulong_t)&net_intf1_blacklist },
+ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7253),
+ .driver_info = (kernel_ulong_t)&net_intf1_blacklist },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864E) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864G) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_DUAL) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_SINGLE) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_DE910_DUAL) },
+ { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UE910_V2) },
+ { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920),
+ .driver_info = (kernel_ulong_t)&telit_le920_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622, 0xff, 0xff, 0xff) }, /* ZTE WCDMA products */
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0002, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&net_intf1_blacklist },
@@ -809,7 +1147,8 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0017, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&net_intf3_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0018, 0xff, 0xff, 0xff) },
- { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0019, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0019, 0xff, 0xff, 0xff),
+ .driver_info = (kernel_ulong_t)&net_intf3_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0020, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0021, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&net_intf4_blacklist },
@@ -943,6 +1282,8 @@ static const struct usb_device_id option_ids[] = {
.driver_info = (kernel_ulong_t)&net_intf4_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0330, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0395, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0412, 0xff, 0xff, 0xff), /* Telewell TW-LTE 4G */
+ .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0414, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0417, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1008, 0xff, 0xff, 0xff),
@@ -1100,7 +1441,8 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1267, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1268, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1269, 0xff, 0xff, 0xff) },
- { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1270, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1270, 0xff, 0xff, 0xff),
+ .driver_info = (kernel_ulong_t)&net_intf5_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1271, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1272, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1273, 0xff, 0xff, 0xff) },
@@ -1145,6 +1487,25 @@ static const struct usb_device_id option_ids[] = {
.driver_info = (kernel_ulong_t)&net_intf2_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1426, 0xff, 0xff, 0xff), /* ZTE MF91 */
.driver_info = (kernel_ulong_t)&net_intf2_blacklist },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1428, 0xff, 0xff, 0xff), /* Telewell TW-LTE 4G v2 */
+ .driver_info = (kernel_ulong_t)&net_intf2_blacklist },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1533, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1534, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1535, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1545, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1546, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1547, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1565, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1566, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1567, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1589, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1590, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1591, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1592, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1594, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1596, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1598, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1600, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2002, 0xff,
0xff, 0xff), .driver_info = (kernel_ulong_t)&zte_k3765_z_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2003, 0xff, 0xff, 0xff) },
@@ -1171,20 +1532,25 @@ static const struct usb_device_id option_ids[] = {
.driver_info = (kernel_ulong_t)&net_intf3_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0178, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&net_intf3_blacklist },
-
- { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_CDMA_TECH, 0xff, 0xff, 0xff) },
- { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC8710, 0xff, 0xff, 0xff) },
- { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC2726, 0xff, 0xff, 0xff) },
- { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC8710T, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffe9, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff8b, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff8c, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff8d, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff8e, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff8f, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff90, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff91, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff92, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff93, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff94, 0xff, 0xff, 0xff) },
+
+ /* NOTE: most ZTE CDMA devices should be driven by zte_ev, not option */
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MC2718, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&zte_mc2718_z_blacklist },
- { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AD3812, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&zte_ad3812_z_blacklist },
- { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MC2716, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&zte_mc2716_z_blacklist },
{ USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x02, 0x01) },
{ USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x02, 0x05) },
{ USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x86, 0x10) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC2726, 0xff, 0xff, 0xff) },
{ USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_H10) },
{ USB_DEVICE(DLINK_VENDOR_ID, DLINK_PRODUCT_DWM_652) },
@@ -1203,15 +1569,26 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X060S_X200),
.driver_info = (kernel_ulong_t)&alcatel_x200_blacklist
},
- { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X220_X500D) },
+ { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X220_X500D),
+ .driver_info = (kernel_ulong_t)&net_intf6_blacklist },
+ { USB_DEVICE(ALCATEL_VENDOR_ID, 0x0052),
+ .driver_info = (kernel_ulong_t)&net_intf6_blacklist },
+ { USB_DEVICE(ALCATEL_VENDOR_ID, 0x00b6),
+ .driver_info = (kernel_ulong_t)&net_intf3_blacklist },
+ { USB_DEVICE(ALCATEL_VENDOR_ID, 0x00b7),
+ .driver_info = (kernel_ulong_t)&net_intf5_blacklist },
{ USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_L100V),
.driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_L800MA),
+ .driver_info = (kernel_ulong_t)&net_intf2_blacklist },
{ USB_DEVICE(AIRPLUS_VENDOR_ID, AIRPLUS_PRODUCT_MCD650) },
{ USB_DEVICE(TLAYTECH_VENDOR_ID, TLAYTECH_PRODUCT_TEU800) },
{ USB_DEVICE(LONGCHEER_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W14),
.driver_info = (kernel_ulong_t)&four_g_w14_blacklist
},
+ { USB_DEVICE_INTERFACE_CLASS(LONGCHEER_VENDOR_ID, SPEEDUP_PRODUCT_SU9800, 0xff) },
{ USB_DEVICE(LONGCHEER_VENDOR_ID, ZOOM_PRODUCT_4597) },
+ { USB_DEVICE(LONGCHEER_VENDOR_ID, IBALL_3_5G_CONNECT) },
{ USB_DEVICE(HAIER_VENDOR_ID, HAIER_PRODUCT_CE100) },
/* Pirelli */
{ USB_DEVICE_INTERFACE_CLASS(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_C100_1, 0xff) },
@@ -1233,17 +1610,33 @@ static const struct usb_device_id option_ids[] = {
/* Cinterion */
{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_E) },
{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_P) },
- { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8) },
+ { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8),
+ .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX) },
+ { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PLXX),
+ .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDM) },
{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDMNET) },
{ USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC25_MDM) },
{ USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC25_MDMNET) },
{ USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC28_MDM) }, /* HC28 enumerates with Siemens or Cinterion VID depending on FW revision */
{ USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC28_MDMNET) },
-
- { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100) },
+ { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100),
+ .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD120),
+ .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD140),
+ .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD145) },
+ { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD155),
+ .driver_info = (kernel_ulong_t)&net_intf6_blacklist },
+ { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD200),
+ .driver_info = (kernel_ulong_t)&net_intf6_blacklist },
+ { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD160),
+ .driver_info = (kernel_ulong_t)&net_intf6_blacklist },
+ { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD500),
+ .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
{ USB_DEVICE(CELOT_VENDOR_ID, CELOT_PRODUCT_CT680M) }, /* CT-650 CDMA 450 1xEVDO modem */
- { USB_DEVICE(ONDA_VENDOR_ID, ONDA_MT825UP) }, /* ONDA MT825UP modem */
{ USB_DEVICE_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_GT_B3730, USB_CLASS_CDC_DATA, 0x00, 0x00) }, /* Samsung GT-B3730 LTE USB modem.*/
{ USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM600) },
{ USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM610) },
@@ -1315,9 +1708,22 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_4COM2, 0xff, 0x02, 0x01) },
{ USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_4COM2, 0xff, 0x00, 0x00) },
{ USB_DEVICE(CELLIENT_VENDOR_ID, CELLIENT_PRODUCT_MEN200) },
- { USB_DEVICE(PETATEL_VENDOR_ID, PETATEL_PRODUCT_NP10T) },
+ { USB_DEVICE(PETATEL_VENDOR_ID, PETATEL_PRODUCT_NP10T_600A) },
+ { USB_DEVICE(PETATEL_VENDOR_ID, PETATEL_PRODUCT_NP10T_600E) },
{ USB_DEVICE(TPLINK_VENDOR_ID, TPLINK_PRODUCT_MA180),
.driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ { USB_DEVICE(TPLINK_VENDOR_ID, 0x9000), /* TP-Link MA260 */
+ .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ { USB_DEVICE(CHANGHONG_VENDOR_ID, CHANGHONG_PRODUCT_CH690) },
+ { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d01, 0xff, 0x02, 0x01) }, /* D-Link DWM-156 (variant) */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d01, 0xff, 0x00, 0x00) }, /* D-Link DWM-156 (variant) */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d02, 0xff, 0x02, 0x01) },
+ { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d02, 0xff, 0x00, 0x00) },
+ { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d03, 0xff, 0x02, 0x01) },
+ { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d03, 0xff, 0x00, 0x00) },
+ { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e01, 0xff, 0xff, 0xff) }, /* D-Link DWM-152/C1 */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e02, 0xff, 0xff, 0xff) }, /* D-Link DWM-156/C1 */
+ { USB_DEVICE(INOVIA_VENDOR_ID, INOVIA_SEW858) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, option_ids);
@@ -1341,7 +1747,6 @@ static struct usb_serial_driver option_1port_device = {
.write = usb_wwan_write,
.write_room = usb_wwan_write_room,
.chars_in_buffer = usb_wwan_chars_in_buffer,
- .set_termios = usb_wwan_set_termios,
.tiocmget = usb_wwan_tiocmget,
.tiocmset = usb_wwan_tiocmset,
.ioctl = usb_wwan_ioctl,
@@ -1505,13 +1910,8 @@ static void option_instat_callback(struct urb *urb)
portdata->dsr_state = ((signals & 0x02) ? 1 : 0);
portdata->ri_state = ((signals & 0x08) ? 1 : 0);
- if (old_dcd_state && !portdata->dcd_state) {
- struct tty_struct *tty =
- tty_port_tty_get(&port->port);
- if (tty && !C_CLOCAL(tty))
- tty_hangup(tty);
- tty_kref_put(tty);
- }
+ if (old_dcd_state && !portdata->dcd_state)
+ tty_port_tty_hangup(&port->port, true);
} else {
dev_dbg(dev, "%s: type %x req %x\n", __func__,
req_pkt->bRequestType, req_pkt->bRequest);
@@ -1521,6 +1921,7 @@ static void option_instat_callback(struct urb *urb)
/* Resubmit urb so we continue receiving IRQ data */
if (status != -ESHUTDOWN && status != -ENOENT) {
+ usb_mark_last_busy(port->serial->dev);
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err)
dev_dbg(dev, "%s: resubmit intr urb failed. (%d)\n",
@@ -1540,6 +1941,7 @@ static int option_send_setup(struct usb_serial_port *port)
struct option_private *priv = intfdata->private;
struct usb_wwan_port_private *portdata;
int val = 0;
+ int res;
portdata = usb_get_serial_port_data(port);
@@ -1548,9 +1950,17 @@ static int option_send_setup(struct usb_serial_port *port)
if (portdata->rts_state)
val |= 0x02;
- return usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+ res = usb_autopm_get_interface(serial->interface);
+ if (res)
+ return res;
+
+ res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
0x22, 0x21, val, priv->bInterfaceNumber, NULL,
0, USB_CTRL_SET_TIMEOUT);
+
+ usb_autopm_put_interface(serial->interface);
+
+ return res;
}
MODULE_AUTHOR(DRIVER_AUTHOR);
diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c
index d217fd6ee43..a4b88bc038b 100644
--- a/drivers/usb/serial/oti6858.c
+++ b/drivers/usb/serial/oti6858.c
@@ -39,7 +39,6 @@
#include <linux/kernel.h>
#include <linux/errno.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
@@ -103,6 +102,7 @@ struct oti6858_control_pkt {
#define TX_BUFFER_EMPTIED 0x09
u8 pin_state;
#define PIN_MASK 0x3f
+#define PIN_MSR_MASK 0x1b
#define PIN_RTS 0x20 /* output pin */
#define PIN_CTS 0x10 /* input pin, active low */
#define PIN_DSR 0x08 /* input pin, active low */
@@ -124,8 +124,6 @@ static void oti6858_close(struct usb_serial_port *port);
static void oti6858_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old);
static void oti6858_init_termios(struct tty_struct *tty);
-static int oti6858_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg);
static void oti6858_read_int_callback(struct urb *urb);
static void oti6858_read_bulk_callback(struct urb *urb);
static void oti6858_write_bulk_callback(struct urb *urb);
@@ -150,11 +148,11 @@ static struct usb_serial_driver oti6858_device = {
.open = oti6858_open,
.close = oti6858_close,
.write = oti6858_write,
- .ioctl = oti6858_ioctl,
.set_termios = oti6858_set_termios,
.init_termios = oti6858_init_termios,
.tiocmget = oti6858_tiocmget,
.tiocmset = oti6858_tiocmset,
+ .tiocmiwait = usb_serial_generic_tiocmiwait,
.read_bulk_callback = oti6858_read_bulk_callback,
.read_int_callback = oti6858_read_int_callback,
.write_bulk_callback = oti6858_write_bulk_callback,
@@ -188,7 +186,6 @@ struct oti6858_private {
u8 setup_done;
struct delayed_work delayed_setup_work;
- wait_queue_head_t intr_wait;
struct usb_serial_port *port; /* USB port with which associated */
};
@@ -202,8 +199,7 @@ static void setup_line(struct work_struct *work)
int result;
new_setup = kmalloc(OTI6858_CTRL_PKT_SIZE, GFP_KERNEL);
- if (new_setup == NULL) {
- dev_err(&port->dev, "%s(): out of memory!\n", __func__);
+ if (!new_setup) {
/* we will try again */
schedule_delayed_work(&priv->delayed_setup_work,
msecs_to_jiffies(2));
@@ -289,11 +285,9 @@ static void send_data(struct work_struct *work)
if (count != 0) {
allow = kmalloc(1, GFP_KERNEL);
- if (!allow) {
- dev_err_console(port, "%s(): kmalloc failed\n",
- __func__);
+ if (!allow)
return;
- }
+
result = usb_control_msg(port->serial->dev,
usb_rcvctrlpipe(port->serial->dev, 0),
OTI6858_REQ_T_CHECK_TXBUFF,
@@ -339,13 +333,14 @@ static int oti6858_port_probe(struct usb_serial_port *port)
return -ENOMEM;
spin_lock_init(&priv->lock);
- init_waitqueue_head(&priv->intr_wait);
priv->port = port;
INIT_DELAYED_WORK(&priv->delayed_setup_work, setup_line);
INIT_DELAYED_WORK(&priv->delayed_write_work, send_data);
usb_set_serial_port_data(port, priv);
+ port->port.drain_delay = 256; /* FIXME: check the FIFO length */
+
return 0;
}
@@ -414,9 +409,6 @@ static void oti6858_set_termios(struct tty_struct *tty,
__le16 divisor;
int br;
- if (!tty)
- return;
-
cflag = tty->termios.c_cflag;
spin_lock_irqsave(&priv->lock, flags);
@@ -512,7 +504,6 @@ static void oti6858_set_termios(struct tty_struct *tty,
static int oti6858_open(struct tty_struct *tty, struct usb_serial_port *port)
{
struct oti6858_private *priv = usb_get_serial_port_data(port);
- struct ktermios tmp_termios;
struct usb_serial *serial = port->serial;
struct oti6858_control_pkt *buf;
unsigned long flags;
@@ -522,10 +513,8 @@ static int oti6858_open(struct tty_struct *tty, struct usb_serial_port *port)
usb_clear_halt(serial->dev, port->read_urb->pipe);
buf = kmalloc(OTI6858_CTRL_PKT_SIZE, GFP_KERNEL);
- if (buf == NULL) {
- dev_err(&port->dev, "%s(): out of memory!\n", __func__);
+ if (!buf)
return -ENOMEM;
- }
result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
OTI6858_REQ_T_GET_STATUS,
@@ -563,8 +552,8 @@ static int oti6858_open(struct tty_struct *tty, struct usb_serial_port *port)
/* setup termios */
if (tty)
- oti6858_set_termios(tty, port, &tmp_termios);
- port->port.drain_delay = 256; /* FIXME: check the FIFO length */
+ oti6858_set_termios(tty, port, NULL);
+
return 0;
}
@@ -652,59 +641,6 @@ static int oti6858_tiocmget(struct tty_struct *tty)
return result;
}
-static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
-{
- struct oti6858_private *priv = usb_get_serial_port_data(port);
- unsigned long flags;
- unsigned int prev, status;
- unsigned int changed;
-
- spin_lock_irqsave(&priv->lock, flags);
- prev = priv->status.pin_state;
- spin_unlock_irqrestore(&priv->lock, flags);
-
- while (1) {
- wait_event_interruptible(priv->intr_wait,
- priv->status.pin_state != prev);
- if (signal_pending(current))
- return -ERESTARTSYS;
-
- spin_lock_irqsave(&priv->lock, flags);
- status = priv->status.pin_state & PIN_MASK;
- spin_unlock_irqrestore(&priv->lock, flags);
-
- changed = prev ^ status;
- /* FIXME: check if this is correct (active high/low) */
- if (((arg & TIOCM_RNG) && (changed & PIN_RI)) ||
- ((arg & TIOCM_DSR) && (changed & PIN_DSR)) ||
- ((arg & TIOCM_CD) && (changed & PIN_DCD)) ||
- ((arg & TIOCM_CTS) && (changed & PIN_CTS)))
- return 0;
- prev = status;
- }
-
- /* NOTREACHED */
- return 0;
-}
-
-static int oti6858_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
-{
- struct usb_serial_port *port = tty->driver_data;
-
- dev_dbg(&port->dev, "%s(cmd = 0x%04x, arg = 0x%08lx)\n", __func__, cmd, arg);
-
- switch (cmd) {
- case TIOCMIWAIT:
- dev_dbg(&port->dev, "%s(): TIOCMIWAIT\n", __func__);
- return wait_modem_info(port, arg);
- default:
- dev_dbg(&port->dev, "%s(): 0x%04x not supported\n", __func__, cmd);
- break;
- }
- return -ENOIOCTLCMD;
-}
-
static void oti6858_read_int_callback(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
@@ -762,8 +698,21 @@ static void oti6858_read_int_callback(struct urb *urb)
}
if (!priv->transient) {
- if (xs->pin_state != priv->status.pin_state)
- wake_up_interruptible(&priv->intr_wait);
+ u8 delta = xs->pin_state ^ priv->status.pin_state;
+
+ if (delta & PIN_MSR_MASK) {
+ if (delta & PIN_CTS)
+ port->icount.cts++;
+ if (delta & PIN_DSR)
+ port->icount.dsr++;
+ if (delta & PIN_RI)
+ port->icount.rng++;
+ if (delta & PIN_DCD)
+ port->icount.dcd++;
+
+ wake_up_interruptible(&port->port.delta_msr_wait);
+ }
+
memcpy(&priv->status, xs, OTI6858_CTRL_PKT_SIZE);
}
@@ -820,7 +769,6 @@ static void oti6858_read_bulk_callback(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
struct oti6858_private *priv = usb_get_serial_port_data(port);
- struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
unsigned long flags;
int status = urb->status;
@@ -835,12 +783,10 @@ static void oti6858_read_bulk_callback(struct urb *urb)
return;
}
- tty = tty_port_tty_get(&port->port);
- if (tty != NULL && urb->actual_length > 0) {
- tty_insert_flip_string(tty, data, urb->actual_length);
- tty_flip_buffer_push(tty);
+ if (urb->actual_length > 0) {
+ tty_insert_flip_string(&port->port, data, urb->actual_length);
+ tty_flip_buffer_push(&port->port);
}
- tty_kref_put(tty);
/* schedule the interrupt urb */
result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 60024190136..b3d5a35c0d4 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -12,12 +12,10 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this
* driver
- *
*/
#include <linux/kernel.h>
#include <linux/errno.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
@@ -29,12 +27,12 @@
#include <linux/uaccess.h>
#include <linux/usb.h>
#include <linux/usb/serial.h>
+#include <asm/unaligned.h>
#include "pl2303.h"
-/*
- * Version Information
- */
-#define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver"
+
+#define PL2303_QUIRK_UART_STATE_IDX0 BIT(0)
+#define PL2303_QUIRK_LEGACY BIT(1)
static const struct usb_device_id id_table[] = {
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },
@@ -63,9 +61,12 @@ static const struct usb_device_id id_table[] = {
{ USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) },
{ USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) },
{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) },
- { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) },
- { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) },
- { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) },
+ { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1),
+ .driver_info = PL2303_QUIRK_UART_STATE_IDX0 },
+ { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65),
+ .driver_info = PL2303_QUIRK_UART_STATE_IDX0 },
+ { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75),
+ .driver_info = PL2303_QUIRK_UART_STATE_IDX0 },
{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) },
{ USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_ID_S81) }, /* Benq/Siemens S81 */
{ USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) },
@@ -82,6 +83,9 @@ static const struct usb_device_id id_table[] = {
{ USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) },
{ USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) },
{ USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) },
+ { USB_DEVICE(HP_VENDOR_ID, HP_LD960_PRODUCT_ID) },
+ { USB_DEVICE(HP_VENDOR_ID, HP_LCM220_PRODUCT_ID) },
+ { USB_DEVICE(HP_VENDOR_ID, HP_LCM960_PRODUCT_ID) },
{ USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) },
{ USB_DEVICE(ZEAGLE_VENDOR_ID, ZEAGLE_N2ITION3_PRODUCT_ID) },
{ USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) },
@@ -115,7 +119,8 @@ MODULE_DEVICE_TABLE(usb, id_table);
#define VENDOR_READ_REQUEST_TYPE 0xc0
#define VENDOR_READ_REQUEST 0x01
-#define UART_STATE 0x08
+#define UART_STATE_INDEX 8
+#define UART_STATE_MSR_MASK 0x8b
#define UART_STATE_TRANSIENT_MASK 0x74
#define UART_DCD 0x01
#define UART_DSR 0x02
@@ -128,99 +133,142 @@ MODULE_DEVICE_TABLE(usb, id_table);
enum pl2303_type {
- type_0, /* don't know the difference between type 0 and */
- type_1, /* type 1, until someone from prolific tells us... */
- HX, /* HX version of the pl2303 chip */
+ TYPE_01, /* Type 0 and 1 (difference unknown) */
+ TYPE_HX, /* HX version of the pl2303 chip */
+ TYPE_COUNT
+};
+
+struct pl2303_type_data {
+ speed_t max_baud_rate;
+ unsigned long quirks;
};
struct pl2303_serial_private {
- enum pl2303_type type;
+ const struct pl2303_type_data *type;
+ unsigned long quirks;
};
struct pl2303_private {
spinlock_t lock;
- wait_queue_head_t delta_msr_wait;
u8 line_control;
u8 line_status;
+
+ u8 line_settings[7];
};
-static int pl2303_vendor_read(__u16 value, __u16 index,
- struct usb_serial *serial, unsigned char *buf)
+static const struct pl2303_type_data pl2303_type_data[TYPE_COUNT] = {
+ [TYPE_01] = {
+ .max_baud_rate = 1228800,
+ .quirks = PL2303_QUIRK_LEGACY,
+ },
+};
+
+static int pl2303_vendor_read(struct usb_serial *serial, u16 value,
+ unsigned char buf[1])
{
- int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+ struct device *dev = &serial->interface->dev;
+ int res;
+
+ res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,
- value, index, buf, 1, 100);
- dev_dbg(&serial->dev->dev, "0x%x:0x%x:0x%x:0x%x %d - %x\n",
- VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, value, index,
- res, buf[0]);
- return res;
+ value, 0, buf, 1, 100);
+ if (res != 1) {
+ dev_err(dev, "%s - failed to read [%04x]: %d\n", __func__,
+ value, res);
+ if (res >= 0)
+ res = -EIO;
+
+ return res;
+ }
+
+ dev_dbg(dev, "%s - [%04x] = %02x\n", __func__, value, buf[0]);
+
+ return 0;
}
-static int pl2303_vendor_write(__u16 value, __u16 index,
- struct usb_serial *serial)
+static int pl2303_vendor_write(struct usb_serial *serial, u16 value, u16 index)
{
- int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ struct device *dev = &serial->interface->dev;
+ int res;
+
+ dev_dbg(dev, "%s - [%04x] = %02x\n", __func__, value, index);
+
+ res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
value, index, NULL, 0, 100);
- dev_dbg(&serial->dev->dev, "0x%x:0x%x:0x%x:0x%x %d\n",
- VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, value, index,
- res);
- return res;
+ if (res) {
+ dev_err(dev, "%s - failed to write [%04x]: %d\n", __func__,
+ value, res);
+ return res;
+ }
+
+ return 0;
+}
+
+static int pl2303_probe(struct usb_serial *serial,
+ const struct usb_device_id *id)
+{
+ usb_set_serial_data(serial, (void *)id->driver_info);
+
+ return 0;
}
static int pl2303_startup(struct usb_serial *serial)
{
struct pl2303_serial_private *spriv;
- enum pl2303_type type = type_0;
+ enum pl2303_type type = TYPE_01;
unsigned char *buf;
spriv = kzalloc(sizeof(*spriv), GFP_KERNEL);
if (!spriv)
return -ENOMEM;
- buf = kmalloc(10, GFP_KERNEL);
+ buf = kmalloc(1, GFP_KERNEL);
if (!buf) {
kfree(spriv);
return -ENOMEM;
}
if (serial->dev->descriptor.bDeviceClass == 0x02)
- type = type_0;
+ type = TYPE_01; /* type 0 */
else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40)
- type = HX;
+ type = TYPE_HX;
else if (serial->dev->descriptor.bDeviceClass == 0x00)
- type = type_1;
+ type = TYPE_01; /* type 1 */
else if (serial->dev->descriptor.bDeviceClass == 0xFF)
- type = type_1;
+ type = TYPE_01; /* type 1 */
dev_dbg(&serial->interface->dev, "device type: %d\n", type);
- spriv->type = type;
+ spriv->type = &pl2303_type_data[type];
+ spriv->quirks = (unsigned long)usb_get_serial_data(serial);
+ spriv->quirks |= spriv->type->quirks;
+
usb_set_serial_data(serial, spriv);
- pl2303_vendor_read(0x8484, 0, serial, buf);
- pl2303_vendor_write(0x0404, 0, serial);
- pl2303_vendor_read(0x8484, 0, serial, buf);
- pl2303_vendor_read(0x8383, 0, serial, buf);
- pl2303_vendor_read(0x8484, 0, serial, buf);
- pl2303_vendor_write(0x0404, 1, serial);
- pl2303_vendor_read(0x8484, 0, serial, buf);
- pl2303_vendor_read(0x8383, 0, serial, buf);
- pl2303_vendor_write(0, 1, serial);
- pl2303_vendor_write(1, 0, serial);
- if (type == HX)
- pl2303_vendor_write(2, 0x44, serial);
+ pl2303_vendor_read(serial, 0x8484, buf);
+ pl2303_vendor_write(serial, 0x0404, 0);
+ pl2303_vendor_read(serial, 0x8484, buf);
+ pl2303_vendor_read(serial, 0x8383, buf);
+ pl2303_vendor_read(serial, 0x8484, buf);
+ pl2303_vendor_write(serial, 0x0404, 1);
+ pl2303_vendor_read(serial, 0x8484, buf);
+ pl2303_vendor_read(serial, 0x8383, buf);
+ pl2303_vendor_write(serial, 0, 1);
+ pl2303_vendor_write(serial, 1, 0);
+ if (spriv->quirks & PL2303_QUIRK_LEGACY)
+ pl2303_vendor_write(serial, 2, 0x24);
else
- pl2303_vendor_write(2, 0x24, serial);
+ pl2303_vendor_write(serial, 2, 0x44);
kfree(buf);
+
return 0;
}
static void pl2303_release(struct usb_serial *serial)
{
- struct pl2303_serial_private *spriv;
+ struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
- spriv = usb_get_serial_data(serial);
kfree(spriv);
}
@@ -233,35 +281,181 @@ static int pl2303_port_probe(struct usb_serial_port *port)
return -ENOMEM;
spin_lock_init(&priv->lock);
- init_waitqueue_head(&priv->delta_msr_wait);
usb_set_serial_port_data(port, priv);
+ port->port.drain_delay = 256;
+
return 0;
}
static int pl2303_port_remove(struct usb_serial_port *port)
{
- struct pl2303_private *priv;
+ struct pl2303_private *priv = usb_get_serial_port_data(port);
- priv = usb_get_serial_port_data(port);
kfree(priv);
return 0;
}
-static int set_control_lines(struct usb_device *dev, u8 value)
+static int pl2303_set_control_lines(struct usb_serial_port *port, u8 value)
{
+ struct usb_device *dev = port->serial->dev;
int retval;
+ dev_dbg(&port->dev, "%s - %02x\n", __func__, value);
+
retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
value, 0, NULL, 0, 100);
- dev_dbg(&dev->dev, "%s - value = %d, retval = %d\n", __func__,
- value, retval);
+ if (retval)
+ dev_err(&port->dev, "%s - failed: %d\n", __func__, retval);
+
return retval;
}
+/*
+ * Returns the nearest supported baud rate that can be set directly without
+ * using divisors.
+ */
+static speed_t pl2303_get_supported_baud_rate(speed_t baud)
+{
+ static const speed_t baud_sup[] = {
+ 75, 150, 300, 600, 1200, 1800, 2400, 3600, 4800, 7200, 9600,
+ 14400, 19200, 28800, 38400, 57600, 115200, 230400, 460800,
+ 614400, 921600, 1228800, 2457600, 3000000, 6000000
+ };
+
+ unsigned i;
+
+ for (i = 0; i < ARRAY_SIZE(baud_sup); ++i) {
+ if (baud_sup[i] > baud)
+ break;
+ }
+
+ if (i == ARRAY_SIZE(baud_sup))
+ baud = baud_sup[i - 1];
+ else if (i > 0 && (baud_sup[i] - baud) > (baud - baud_sup[i - 1]))
+ baud = baud_sup[i - 1];
+ else
+ baud = baud_sup[i];
+
+ return baud;
+}
+
+/*
+ * NOTE: If unsupported baud rates are set directly, the PL2303 seems to
+ * use 9600 baud.
+ */
+static speed_t pl2303_encode_baud_rate_direct(unsigned char buf[4],
+ speed_t baud)
+{
+ put_unaligned_le32(baud, buf);
+
+ return baud;
+}
+
+static speed_t pl2303_encode_baud_rate_divisor(unsigned char buf[4],
+ speed_t baud)
+{
+ unsigned int tmp;
+
+ /*
+ * Apparently the formula is:
+ * baudrate = 12M * 32 / (2^buf[1]) / buf[0]
+ */
+ tmp = 12000000 * 32 / baud;
+ buf[3] = 0x80;
+ buf[2] = 0;
+ buf[1] = (tmp >= 256);
+ while (tmp >= 256) {
+ tmp >>= 2;
+ buf[1] <<= 1;
+ }
+ buf[0] = tmp;
+
+ return baud;
+}
+
+static void pl2303_encode_baud_rate(struct tty_struct *tty,
+ struct usb_serial_port *port,
+ u8 buf[4])
+{
+ struct usb_serial *serial = port->serial;
+ struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
+ speed_t baud_sup;
+ speed_t baud;
+
+ baud = tty_get_baud_rate(tty);
+ dev_dbg(&port->dev, "baud requested = %u\n", baud);
+ if (!baud)
+ return;
+
+ if (spriv->type->max_baud_rate)
+ baud = min_t(speed_t, baud, spriv->type->max_baud_rate);
+ /*
+ * Set baud rate to nearest supported value.
+ *
+ * NOTE: Baud rate 500k can only be set using divisors.
+ */
+ baud_sup = pl2303_get_supported_baud_rate(baud);
+
+ if (baud == 500000)
+ baud = pl2303_encode_baud_rate_divisor(buf, baud);
+ else
+ baud = pl2303_encode_baud_rate_direct(buf, baud_sup);
+
+ /* Save resulting baud rate */
+ tty_encode_baud_rate(tty, baud, baud);
+ dev_dbg(&port->dev, "baud set = %u\n", baud);
+}
+
+static int pl2303_get_line_request(struct usb_serial_port *port,
+ unsigned char buf[7])
+{
+ struct usb_device *udev = port->serial->dev;
+ int ret;
+
+ ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+ GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
+ 0, 0, buf, 7, 100);
+ if (ret != 7) {
+ dev_err(&port->dev, "%s - failed: %d\n", __func__, ret);
+
+ if (ret > 0)
+ ret = -EIO;
+
+ return ret;
+ }
+
+ dev_dbg(&port->dev, "%s - %7ph\n", __func__, buf);
+
+ return 0;
+}
+
+static int pl2303_set_line_request(struct usb_serial_port *port,
+ unsigned char buf[7])
+{
+ struct usb_device *udev = port->serial->dev;
+ int ret;
+
+ ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
+ 0, 0, buf, 7, 100);
+ if (ret != 7) {
+ dev_err(&port->dev, "%s - failed: %d\n", __func__, ret);
+
+ if (ret > 0)
+ ret = -EIO;
+
+ return ret;
+ }
+
+ dev_dbg(&port->dev, "%s - %7ph\n", __func__, buf);
+
+ return 0;
+}
+
static void pl2303_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios)
{
@@ -269,122 +463,51 @@ static void pl2303_set_termios(struct tty_struct *tty,
struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
struct pl2303_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
- unsigned int cflag;
unsigned char *buf;
- int baud;
- int i;
+ int ret;
u8 control;
- const int baud_sup[] = { 75, 150, 300, 600, 1200, 1800, 2400, 3600,
- 4800, 7200, 9600, 14400, 19200, 28800, 38400,
- 57600, 115200, 230400, 460800, 614400,
- 921600, 1228800, 2457600, 3000000, 6000000 };
- int baud_floor, baud_ceil;
- int k;
-
- /* The PL2303 is reported to lose bytes if you change
- serial settings even to the same values as before. Thus
- we actually need to filter in this specific case */
-
- if (!tty_termios_hw_change(&tty->termios, old_termios))
- return;
- cflag = tty->termios.c_cflag;
+ if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios))
+ return;
buf = kzalloc(7, GFP_KERNEL);
if (!buf) {
- dev_err(&port->dev, "%s - out of memory.\n", __func__);
/* Report back no change occurred */
- tty->termios = *old_termios;
+ if (old_termios)
+ tty->termios = *old_termios;
return;
}
- i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
- GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
- 0, 0, buf, 7, 100);
- dev_dbg(&port->dev, "0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x\n", i,
- buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
+ pl2303_get_line_request(port, buf);
- if (cflag & CSIZE) {
- switch (cflag & CSIZE) {
- case CS5:
- buf[6] = 5;
- break;
- case CS6:
- buf[6] = 6;
- break;
- case CS7:
- buf[6] = 7;
- break;
- default:
- case CS8:
- buf[6] = 8;
- break;
- }
- dev_dbg(&port->dev, "data bits = %d\n", buf[6]);
+ switch (C_CSIZE(tty)) {
+ case CS5:
+ buf[6] = 5;
+ break;
+ case CS6:
+ buf[6] = 6;
+ break;
+ case CS7:
+ buf[6] = 7;
+ break;
+ default:
+ case CS8:
+ buf[6] = 8;
}
+ dev_dbg(&port->dev, "data bits = %d\n", buf[6]);
/* For reference buf[0]:buf[3] baud rate value */
- /* NOTE: Only the values defined in baud_sup are supported !
- * => if unsupported values are set, the PL2303 seems to use
- * 9600 baud (at least my PL2303X always does)
- */
- baud = tty_get_baud_rate(tty);
- dev_dbg(&port->dev, "baud requested = %d\n", baud);
- if (baud) {
- /* Set baudrate to nearest supported value */
- for (k=0; k<ARRAY_SIZE(baud_sup); k++) {
- if (baud_sup[k] / baud) {
- baud_ceil = baud_sup[k];
- if (k==0) {
- baud = baud_ceil;
- } else {
- baud_floor = baud_sup[k-1];
- if ((baud_ceil % baud)
- > (baud % baud_floor))
- baud = baud_floor;
- else
- baud = baud_ceil;
- }
- break;
- }
- }
- if (baud > 1228800) {
- /* type_0, type_1 only support up to 1228800 baud */
- if (spriv->type != HX)
- baud = 1228800;
- else if (baud > 6000000)
- baud = 6000000;
- }
- dev_dbg(&port->dev, "baud set = %d\n", baud);
- if (baud <= 115200) {
- buf[0] = baud & 0xff;
- buf[1] = (baud >> 8) & 0xff;
- buf[2] = (baud >> 16) & 0xff;
- buf[3] = (baud >> 24) & 0xff;
- } else {
- /* apparently the formula for higher speeds is:
- * baudrate = 12M * 32 / (2^buf[1]) / buf[0]
- */
- unsigned tmp = 12*1000*1000*32 / baud;
- buf[3] = 0x80;
- buf[2] = 0;
- buf[1] = (tmp >= 256);
- while (tmp >= 256) {
- tmp >>= 2;
- buf[1] <<= 1;
- }
- buf[0] = tmp;
- }
- }
+ pl2303_encode_baud_rate(tty, port, &buf[0]);
/* For reference buf[4]=0 is 1 stop bits */
/* For reference buf[4]=1 is 1.5 stop bits */
/* For reference buf[4]=2 is 2 stop bits */
- if (cflag & CSTOPB) {
- /* NOTE: Comply with "real" UARTs / RS232:
+ if (C_CSTOPB(tty)) {
+ /*
+ * NOTE: Comply with "real" UARTs / RS232:
* use 1.5 instead of 2 stop bits with 5 data bits
*/
- if ((cflag & CSIZE) == CS5) {
+ if (C_CSIZE(tty) == CS5) {
buf[4] = 1;
dev_dbg(&port->dev, "stop bits = 1.5\n");
} else {
@@ -396,14 +519,14 @@ static void pl2303_set_termios(struct tty_struct *tty,
dev_dbg(&port->dev, "stop bits = 1\n");
}
- if (cflag & PARENB) {
+ if (C_PARENB(tty)) {
/* For reference buf[5]=0 is none parity */
/* For reference buf[5]=1 is odd parity */
/* For reference buf[5]=2 is even parity */
/* For reference buf[5]=3 is mark parity */
/* For reference buf[5]=4 is space parity */
- if (cflag & PARODD) {
- if (cflag & CMSPAR) {
+ if (C_PARODD(tty)) {
+ if (C_CMSPAR(tty)) {
buf[5] = 3;
dev_dbg(&port->dev, "parity = mark\n");
} else {
@@ -411,7 +534,7 @@ static void pl2303_set_termios(struct tty_struct *tty,
dev_dbg(&port->dev, "parity = odd\n");
}
} else {
- if (cflag & CMSPAR) {
+ if (C_CMSPAR(tty)) {
buf[5] = 4;
dev_dbg(&port->dev, "parity = space\n");
} else {
@@ -424,47 +547,48 @@ static void pl2303_set_termios(struct tty_struct *tty,
dev_dbg(&port->dev, "parity = none\n");
}
- i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
- 0, 0, buf, 7, 100);
- dev_dbg(&port->dev, "0x21:0x20:0:0 %d\n", i);
+ /*
+ * Some PL2303 are known to lose bytes if you change serial settings
+ * even to the same values as before. Thus we actually need to filter
+ * in this specific case.
+ *
+ * Note that the tty_termios_hw_change check above is not sufficient
+ * as a previously requested baud rate may differ from the one
+ * actually used (and stored in old_termios).
+ *
+ * NOTE: No additional locking needed for line_settings as it is
+ * only used in set_termios, which is serialised against itself.
+ */
+ if (!old_termios || memcmp(buf, priv->line_settings, 7)) {
+ ret = pl2303_set_line_request(port, buf);
+ if (!ret)
+ memcpy(priv->line_settings, buf, 7);
+ }
/* change control lines if we are switching to or from B0 */
spin_lock_irqsave(&priv->lock, flags);
control = priv->line_control;
- if ((cflag & CBAUD) == B0)
+ if (C_BAUD(tty) == B0)
priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
- else if ((old_termios->c_cflag & CBAUD) == B0)
+ else if (old_termios && (old_termios->c_cflag & CBAUD) == B0)
priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
if (control != priv->line_control) {
control = priv->line_control;
spin_unlock_irqrestore(&priv->lock, flags);
- set_control_lines(serial->dev, control);
+ pl2303_set_control_lines(port, control);
} else {
spin_unlock_irqrestore(&priv->lock, flags);
}
- buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
-
- i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
- GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
- 0, 0, buf, 7, 100);
- dev_dbg(&port->dev, "0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x\n", i,
- buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
-
- if (cflag & CRTSCTS) {
- if (spriv->type == HX)
- pl2303_vendor_write(0x0, 0x61, serial);
+ if (C_CRTSCTS(tty)) {
+ if (spriv->quirks & PL2303_QUIRK_LEGACY)
+ pl2303_vendor_write(serial, 0x0, 0x41);
else
- pl2303_vendor_write(0x0, 0x41, serial);
+ pl2303_vendor_write(serial, 0x0, 0x61);
} else {
- pl2303_vendor_write(0x0, 0x0, serial);
+ pl2303_vendor_write(serial, 0x0, 0x0);
}
- /* Save resulting baud rate */
- if (baud)
- tty_encode_baud_rate(tty, baud, baud);
-
kfree(buf);
}
@@ -475,14 +599,14 @@ static void pl2303_dtr_rts(struct usb_serial_port *port, int on)
u8 control;
spin_lock_irqsave(&priv->lock, flags);
- /* Change DTR and RTS */
if (on)
priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
else
priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
control = priv->line_control;
spin_unlock_irqrestore(&priv->lock, flags);
- set_control_lines(port->serial->dev, control);
+
+ pl2303_set_control_lines(port, control);
}
static void pl2303_close(struct usb_serial_port *port)
@@ -493,28 +617,27 @@ static void pl2303_close(struct usb_serial_port *port)
static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
{
- struct ktermios tmp_termios;
struct usb_serial *serial = port->serial;
struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
int result;
- if (spriv->type != HX) {
+ if (spriv->quirks & PL2303_QUIRK_LEGACY) {
usb_clear_halt(serial->dev, port->write_urb->pipe);
usb_clear_halt(serial->dev, port->read_urb->pipe);
} else {
/* reset upstream data pipes */
- pl2303_vendor_write(8, 0, serial);
- pl2303_vendor_write(9, 0, serial);
+ pl2303_vendor_write(serial, 8, 0);
+ pl2303_vendor_write(serial, 9, 0);
}
/* Setup termios */
if (tty)
- pl2303_set_termios(tty, port, &tmp_termios);
+ pl2303_set_termios(tty, port, NULL);
result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (result) {
- dev_err(&port->dev, "%s - failed submitting interrupt urb,"
- " error %d\n", __func__, result);
+ dev_err(&port->dev, "failed to submit interrupt urb: %d\n",
+ result);
return result;
}
@@ -524,7 +647,6 @@ static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
return result;
}
- port->port.drain_delay = 256;
return 0;
}
@@ -532,7 +654,6 @@ static int pl2303_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear)
{
struct usb_serial_port *port = tty->driver_data;
- struct usb_serial *serial = port->serial;
struct pl2303_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
u8 control;
@@ -550,14 +671,11 @@ static int pl2303_tiocmset(struct tty_struct *tty,
control = priv->line_control;
spin_unlock_irqrestore(&priv->lock, flags);
- mutex_lock(&serial->disc_mutex);
- if (!serial->disconnected)
- ret = set_control_lines(serial->dev, control);
- else
- ret = -ENODEV;
- mutex_unlock(&serial->disc_mutex);
+ ret = pl2303_set_control_lines(port, control);
+ if (ret)
+ return usb_translate_errors(ret);
- return ret;
+ return 0;
}
static int pl2303_tiocmget(struct tty_struct *tty)
@@ -589,44 +707,10 @@ static int pl2303_tiocmget(struct tty_struct *tty)
static int pl2303_carrier_raised(struct usb_serial_port *port)
{
struct pl2303_private *priv = usb_get_serial_port_data(port);
+
if (priv->line_status & UART_DCD)
return 1;
- return 0;
-}
-
-static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
-{
- struct pl2303_private *priv = usb_get_serial_port_data(port);
- unsigned long flags;
- unsigned int prevstatus;
- unsigned int status;
- unsigned int changed;
-
- spin_lock_irqsave(&priv->lock, flags);
- prevstatus = priv->line_status;
- spin_unlock_irqrestore(&priv->lock, flags);
-
- while (1) {
- interruptible_sleep_on(&priv->delta_msr_wait);
- /* see if a signal did it */
- if (signal_pending(current))
- return -ERESTARTSYS;
-
- spin_lock_irqsave(&priv->lock, flags);
- status = priv->line_status;
- spin_unlock_irqrestore(&priv->lock, flags);
-
- changed = prevstatus ^ status;
- if (((arg & TIOCM_RNG) && (changed & UART_RING)) ||
- ((arg & TIOCM_DSR) && (changed & UART_DSR)) ||
- ((arg & TIOCM_CD) && (changed & UART_DCD)) ||
- ((arg & TIOCM_CTS) && (changed & UART_CTS))) {
- return 0;
- }
- prevstatus = status;
- }
- /* NOTREACHED */
return 0;
}
@@ -636,28 +720,22 @@ static int pl2303_ioctl(struct tty_struct *tty,
struct serial_struct ser;
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(&port->dev, "%s cmd = 0x%04x\n", __func__, cmd);
-
switch (cmd) {
case TIOCGSERIAL:
memset(&ser, 0, sizeof ser);
ser.type = PORT_16654;
- ser.line = port->serial->minor;
- ser.port = port->number;
+ ser.line = port->minor;
+ ser.port = port->port_number;
ser.baud_base = 460800;
if (copy_to_user((void __user *)arg, &ser, sizeof ser))
return -EFAULT;
return 0;
-
- case TIOCMIWAIT:
- dev_dbg(&port->dev, "%s TIOCMIWAIT\n", __func__);
- return wait_modem_info(port, arg);
default:
- dev_dbg(&port->dev, "%s not supported = 0x%04x\n", __func__, cmd);
break;
}
+
return -ENOIOCTLCMD;
}
@@ -672,6 +750,7 @@ static void pl2303_break_ctl(struct tty_struct *tty, int break_state)
state = BREAK_OFF;
else
state = BREAK_ON;
+
dev_dbg(&port->dev, "%s - turning break %s\n", __func__,
state == BREAK_OFF ? "off" : "on");
@@ -686,48 +765,51 @@ static void pl2303_update_line_status(struct usb_serial_port *port,
unsigned char *data,
unsigned int actual_length)
{
-
+ struct usb_serial *serial = port->serial;
+ struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
struct pl2303_private *priv = usb_get_serial_port_data(port);
struct tty_struct *tty;
unsigned long flags;
- u8 status_idx = UART_STATE;
- u8 length = UART_STATE + 1;
- u8 prev_line_status;
- u16 idv, idp;
+ unsigned int status_idx = UART_STATE_INDEX;
+ u8 status;
+ u8 delta;
- idv = le16_to_cpu(port->serial->dev->descriptor.idVendor);
- idp = le16_to_cpu(port->serial->dev->descriptor.idProduct);
+ if (spriv->quirks & PL2303_QUIRK_UART_STATE_IDX0)
+ status_idx = 0;
-
- if (idv == SIEMENS_VENDOR_ID) {
- if (idp == SIEMENS_PRODUCT_ID_X65 ||
- idp == SIEMENS_PRODUCT_ID_SX1 ||
- idp == SIEMENS_PRODUCT_ID_X75) {
-
- length = 1;
- status_idx = 0;
- }
- }
-
- if (actual_length < length)
+ if (actual_length < status_idx + 1)
return;
+ status = data[status_idx];
+
/* Save off the uart status for others to look at */
spin_lock_irqsave(&priv->lock, flags);
- prev_line_status = priv->line_status;
- priv->line_status = data[status_idx];
+ delta = priv->line_status ^ status;
+ priv->line_status = status;
spin_unlock_irqrestore(&priv->lock, flags);
- if (priv->line_status & UART_BREAK_ERROR)
+
+ if (status & UART_BREAK_ERROR)
usb_serial_handle_break(port);
- wake_up_interruptible(&priv->delta_msr_wait);
- tty = tty_port_tty_get(&port->port);
- if (!tty)
- return;
- if ((priv->line_status ^ prev_line_status) & UART_DCD)
- usb_serial_handle_dcd_change(port, tty,
- priv->line_status & UART_DCD);
- tty_kref_put(tty);
+ if (delta & UART_STATE_MSR_MASK) {
+ if (delta & UART_CTS)
+ port->icount.cts++;
+ if (delta & UART_DSR)
+ port->icount.dsr++;
+ if (delta & UART_RING)
+ port->icount.rng++;
+ if (delta & UART_DCD) {
+ port->icount.dcd++;
+ tty = tty_port_tty_get(&port->port);
+ if (tty) {
+ usb_serial_handle_dcd_change(port, tty,
+ status & UART_DCD);
+ tty_kref_put(tty);
+ }
+ }
+
+ wake_up_interruptible(&port->port.delta_msr_wait);
+ }
}
static void pl2303_read_int_callback(struct urb *urb)
@@ -762,17 +844,17 @@ static void pl2303_read_int_callback(struct urb *urb)
exit:
retval = usb_submit_urb(urb, GFP_ATOMIC);
- if (retval)
+ if (retval) {
dev_err(&port->dev,
"%s - usb_submit_urb failed with result %d\n",
__func__, retval);
+ }
}
static void pl2303_process_read_urb(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
struct pl2303_private *priv = usb_get_serial_port_data(port);
- struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
char tty_flag = TTY_NORMAL;
unsigned long flags;
@@ -784,43 +866,41 @@ static void pl2303_process_read_urb(struct urb *urb)
line_status = priv->line_status;
priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
spin_unlock_irqrestore(&priv->lock, flags);
- wake_up_interruptible(&priv->delta_msr_wait);
if (!urb->actual_length)
return;
- tty = tty_port_tty_get(&port->port);
- if (!tty)
- return;
-
- /* break takes precedence over parity, */
- /* which takes precedence over framing errors */
+ /*
+ * Break takes precedence over parity, which takes precedence over
+ * framing errors.
+ */
if (line_status & UART_BREAK_ERROR)
tty_flag = TTY_BREAK;
else if (line_status & UART_PARITY_ERROR)
tty_flag = TTY_PARITY;
else if (line_status & UART_FRAME_ERROR)
tty_flag = TTY_FRAME;
- dev_dbg(&port->dev, "%s - tty_flag = %d\n", __func__, tty_flag);
+ if (tty_flag != TTY_NORMAL)
+ dev_dbg(&port->dev, "%s - tty_flag = %d\n", __func__,
+ tty_flag);
/* overrun is special, not associated with a char */
if (line_status & UART_OVERRUN_ERROR)
- tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+ tty_insert_flip_char(&port->port, 0, TTY_OVERRUN);
if (port->port.console && port->sysrq) {
for (i = 0; i < urb->actual_length; ++i)
if (!usb_serial_handle_sysrq_char(port, data[i]))
- tty_insert_flip_char(tty, data[i], tty_flag);
+ tty_insert_flip_char(&port->port, data[i],
+ tty_flag);
} else {
- tty_insert_flip_string_fixed_flag(tty, data, tty_flag,
+ tty_insert_flip_string_fixed_flag(&port->port, data, tty_flag,
urb->actual_length);
}
- tty_flip_buffer_push(tty);
- tty_kref_put(tty);
+ tty_flip_buffer_push(&port->port);
}
-/* All of the device info needed for the PL2303 SIO serial converter */
static struct usb_serial_driver pl2303_device = {
.driver = {
.owner = THIS_MODULE,
@@ -832,15 +912,17 @@ static struct usb_serial_driver pl2303_device = {
.bulk_out_size = 256,
.open = pl2303_open,
.close = pl2303_close,
- .dtr_rts = pl2303_dtr_rts,
+ .dtr_rts = pl2303_dtr_rts,
.carrier_raised = pl2303_carrier_raised,
.ioctl = pl2303_ioctl,
.break_ctl = pl2303_break_ctl,
.set_termios = pl2303_set_termios,
.tiocmget = pl2303_tiocmget,
.tiocmset = pl2303_tiocmset,
+ .tiocmiwait = usb_serial_generic_tiocmiwait,
.process_read_urb = pl2303_process_read_urb,
.read_int_callback = pl2303_read_int_callback,
+ .probe = pl2303_probe,
.attach = pl2303_startup,
.release = pl2303_release,
.port_probe = pl2303_port_probe,
@@ -853,5 +935,5 @@ static struct usb_serial_driver * const serial_drivers[] = {
module_usb_serial_driver(serial_drivers, id_table);
-MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_DESCRIPTION("Prolific PL2303 USB to serial adaptor driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h
index c38b8c00c06..42bc082896a 100644
--- a/drivers/usb/serial/pl2303.h
+++ b/drivers/usb/serial/pl2303.h
@@ -121,8 +121,11 @@
#define SUPERIAL_VENDOR_ID 0x5372
#define SUPERIAL_PRODUCT_ID 0x2303
-/* Hewlett-Packard LD220-HP POS Pole Display */
+/* Hewlett-Packard POS Pole Displays */
#define HP_VENDOR_ID 0x03f0
+#define HP_LD960_PRODUCT_ID 0x0b39
+#define HP_LCM220_PRODUCT_ID 0x3139
+#define HP_LCM960_PRODUCT_ID 0x3239
#define HP_LD220_PRODUCT_ID 0x3524
/* Cressi Edy (diving computer) PC interface */
diff --git a/drivers/usb/serial/qcaux.c b/drivers/usb/serial/qcaux.c
index 9b1b96f2d09..6e9f8af9695 100644
--- a/drivers/usb/serial/qcaux.c
+++ b/drivers/usb/serial/qcaux.c
@@ -16,7 +16,6 @@
*/
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/tty.h>
#include <linux/module.h>
#include <linux/usb.h>
@@ -54,7 +53,7 @@
#define SAMSUNG_VENDOR_ID 0x04e8
#define SAMSUNG_PRODUCT_U520 0x6640 /* SCH-U520 */
-static struct usb_device_id id_table[] = {
+static const struct usb_device_id id_table[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, UTSTARCOM_PRODUCT_PC5740, 0xff, 0x00, 0x00) },
{ USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, UTSTARCOM_PRODUCT_PC5750, 0xff, 0x00, 0x00) },
{ USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, UTSTARCOM_PRODUCT_UM150, 0xff, 0x00, 0x00) },
@@ -69,6 +68,7 @@ static struct usb_device_id id_table[] = {
{ USB_VENDOR_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, 0xff, 0xfd, 0xff) }, /* NMEA */
{ USB_VENDOR_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, 0xff, 0xfe, 0xff) }, /* WMC */
{ USB_VENDOR_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, 0xff, 0xff, 0xff) }, /* DIAG */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x1fac, 0x0151, 0xff, 0xff, 0xff) },
{ },
};
MODULE_DEVICE_TABLE(usb, id_table);
diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c
index aa148c21ea4..b2aa003bf41 100644
--- a/drivers/usb/serial/qcserial.c
+++ b/drivers/usb/serial/qcserial.c
@@ -22,8 +22,17 @@
#define DRIVER_AUTHOR "Qualcomm Inc"
#define DRIVER_DESC "Qualcomm USB Serial driver"
+/* standard device layouts supported by this driver */
+enum qcserial_layouts {
+ QCSERIAL_G2K = 0, /* Gobi 2000 */
+ QCSERIAL_G1K = 1, /* Gobi 1000 */
+ QCSERIAL_SWI = 2, /* Sierra Wireless */
+};
+
#define DEVICE_G1K(v, p) \
- USB_DEVICE(v, p), .driver_info = 1
+ USB_DEVICE(v, p), .driver_info = QCSERIAL_G1K
+#define DEVICE_SWI(v, p) \
+ USB_DEVICE(v, p), .driver_info = QCSERIAL_SWI
static const struct usb_device_id id_table[] = {
/* Gobi 1000 devices */
@@ -35,7 +44,13 @@ static const struct usb_device_id id_table[] = {
{DEVICE_G1K(0x04da, 0x250c)}, /* Panasonic Gobi QDL device */
{DEVICE_G1K(0x413c, 0x8172)}, /* Dell Gobi Modem device */
{DEVICE_G1K(0x413c, 0x8171)}, /* Dell Gobi QDL device */
- {DEVICE_G1K(0x1410, 0xa001)}, /* Novatel Gobi Modem device */
+ {DEVICE_G1K(0x1410, 0xa001)}, /* Novatel/Verizon USB-1000 */
+ {DEVICE_G1K(0x1410, 0xa002)}, /* Novatel Gobi Modem device */
+ {DEVICE_G1K(0x1410, 0xa003)}, /* Novatel Gobi Modem device */
+ {DEVICE_G1K(0x1410, 0xa004)}, /* Novatel Gobi Modem device */
+ {DEVICE_G1K(0x1410, 0xa005)}, /* Novatel Gobi Modem device */
+ {DEVICE_G1K(0x1410, 0xa006)}, /* Novatel Gobi Modem device */
+ {DEVICE_G1K(0x1410, 0xa007)}, /* Novatel Gobi Modem device */
{DEVICE_G1K(0x1410, 0xa008)}, /* Novatel Gobi QDL device */
{DEVICE_G1K(0x0b05, 0x1776)}, /* Asus Gobi Modem device */
{DEVICE_G1K(0x0b05, 0x1774)}, /* Asus Gobi QDL device */
@@ -53,6 +68,7 @@ static const struct usb_device_id id_table[] = {
{DEVICE_G1K(0x05c6, 0x9221)}, /* Generic Gobi QDL device */
{DEVICE_G1K(0x05c6, 0x9231)}, /* Generic Gobi QDL device */
{DEVICE_G1K(0x1f45, 0x0001)}, /* Unknown Gobi QDL device */
+ {DEVICE_G1K(0x1bc7, 0x900e)}, /* Telit Gobi QDL device */
/* Gobi 2000 devices */
{USB_DEVICE(0x1410, 0xa010)}, /* Novatel Gobi 2000 QDL device */
@@ -117,20 +133,29 @@ static const struct usb_device_id id_table[] = {
{USB_DEVICE(0x1199, 0x901b)}, /* Sierra Wireless MC7770 */
{USB_DEVICE(0x12D1, 0x14F0)}, /* Sony Gobi 3000 QDL */
{USB_DEVICE(0x12D1, 0x14F1)}, /* Sony Gobi 3000 Composite */
-
- /* non Gobi Qualcomm serial devices */
- {USB_DEVICE_INTERFACE_NUMBER(0x0f3d, 0x68a2, 0)}, /* Sierra Wireless MC7700 Device Management */
- {USB_DEVICE_INTERFACE_NUMBER(0x0f3d, 0x68a2, 2)}, /* Sierra Wireless MC7700 NMEA */
- {USB_DEVICE_INTERFACE_NUMBER(0x0f3d, 0x68a2, 3)}, /* Sierra Wireless MC7700 Modem */
- {USB_DEVICE_INTERFACE_NUMBER(0x114f, 0x68a2, 0)}, /* Sierra Wireless MC7750 Device Management */
- {USB_DEVICE_INTERFACE_NUMBER(0x114f, 0x68a2, 2)}, /* Sierra Wireless MC7750 NMEA */
- {USB_DEVICE_INTERFACE_NUMBER(0x114f, 0x68a2, 3)}, /* Sierra Wireless MC7750 Modem */
- {USB_DEVICE_INTERFACE_NUMBER(0x1199, 0x68a2, 0)}, /* Sierra Wireless MC7710 Device Management */
- {USB_DEVICE_INTERFACE_NUMBER(0x1199, 0x68a2, 2)}, /* Sierra Wireless MC7710 NMEA */
- {USB_DEVICE_INTERFACE_NUMBER(0x1199, 0x68a2, 3)}, /* Sierra Wireless MC7710 Modem */
- {USB_DEVICE_INTERFACE_NUMBER(0x1199, 0x901c, 0)}, /* Sierra Wireless EM7700 Device Management */
- {USB_DEVICE_INTERFACE_NUMBER(0x1199, 0x901c, 2)}, /* Sierra Wireless EM7700 NMEA */
- {USB_DEVICE_INTERFACE_NUMBER(0x1199, 0x901c, 3)}, /* Sierra Wireless EM7700 Modem */
+ {USB_DEVICE(0x0AF0, 0x8120)}, /* Option GTM681W */
+
+ /* non-Gobi Sierra Wireless devices */
+ {DEVICE_SWI(0x0f3d, 0x68a2)}, /* Sierra Wireless MC7700 */
+ {DEVICE_SWI(0x114f, 0x68a2)}, /* Sierra Wireless MC7750 */
+ {DEVICE_SWI(0x1199, 0x68a2)}, /* Sierra Wireless MC7710 */
+ {DEVICE_SWI(0x1199, 0x68c0)}, /* Sierra Wireless MC73xx */
+ {DEVICE_SWI(0x1199, 0x901c)}, /* Sierra Wireless EM7700 */
+ {DEVICE_SWI(0x1199, 0x901f)}, /* Sierra Wireless EM7355 */
+ {DEVICE_SWI(0x1199, 0x9040)}, /* Sierra Wireless Modem */
+ {DEVICE_SWI(0x1199, 0x9041)}, /* Sierra Wireless MC7305/MC7355 */
+ {DEVICE_SWI(0x1199, 0x9051)}, /* Netgear AirCard 340U */
+ {DEVICE_SWI(0x1199, 0x9053)}, /* Sierra Wireless Modem */
+ {DEVICE_SWI(0x1199, 0x9054)}, /* Sierra Wireless Modem */
+ {DEVICE_SWI(0x1199, 0x9055)}, /* Netgear AirCard 341U */
+ {DEVICE_SWI(0x1199, 0x9056)}, /* Sierra Wireless Modem */
+ {DEVICE_SWI(0x1199, 0x9060)}, /* Sierra Wireless Modem */
+ {DEVICE_SWI(0x1199, 0x9061)}, /* Sierra Wireless Modem */
+ {DEVICE_SWI(0x413c, 0x81a2)}, /* Dell Wireless 5806 Gobi(TM) 4G LTE Mobile Broadband Card */
+ {DEVICE_SWI(0x413c, 0x81a3)}, /* Dell Wireless 5570 HSPA+ (42Mbps) Mobile Broadband Card */
+ {DEVICE_SWI(0x413c, 0x81a4)}, /* Dell Wireless 5570e HSPA+ (42Mbps) Mobile Broadband Card */
+ {DEVICE_SWI(0x413c, 0x81a8)}, /* Dell Wireless 5808 Gobi(TM) 4G LTE Mobile Broadband Card */
+ {DEVICE_SWI(0x413c, 0x81a9)}, /* Dell Wireless 5808e Gobi(TM) 4G LTE Mobile Broadband Card */
{ } /* Terminating entry */
};
@@ -143,11 +168,8 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
int retval = -ENODEV;
__u8 nintf;
__u8 ifnum;
- bool is_gobi1k = id->driver_info ? true : false;
int altsetting = -1;
- dev_dbg(dev, "Is Gobi 1000 = %d\n", is_gobi1k);
-
nintf = serial->dev->actconfig->desc.bNumInterfaces;
dev_dbg(dev, "Num Interfaces = %d\n", nintf);
ifnum = intf->desc.bInterfaceNumber;
@@ -175,43 +197,51 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
}
- /* allow any number of interfaces when doing direct interface match */
- if (id->match_flags & USB_DEVICE_ID_MATCH_INT_NUMBER) {
- dev_dbg(dev, "Generic Qualcomm serial interface found\n");
- altsetting = 0;
- goto done;
- }
-
- if (nintf < 3 || nintf > 4) {
- dev_err(dev, "unknown number of interfaces: %d\n", nintf);
- goto done;
- }
-
/* default to enabling interface */
altsetting = 0;
- /* Composite mode; don't bind to the QMI/net interface as that
+ /*
+ * Composite mode; don't bind to the QMI/net interface as that
* gets handled by other drivers.
*/
- if (is_gobi1k) {
- /* Gobi 1K USB layout:
- * 0: serial port (doesn't respond)
+ switch (id->driver_info) {
+ case QCSERIAL_G1K:
+ /*
+ * Gobi 1K USB layout:
+ * 0: DM/DIAG (use libqcdm from ModemManager for communication)
* 1: serial port (doesn't respond)
* 2: AT-capable modem port
* 3: QMI/net
*/
- if (ifnum == 2)
+ if (nintf < 3 || nintf > 4) {
+ dev_err(dev, "unknown number of interfaces: %d\n", nintf);
+ altsetting = -1;
+ goto done;
+ }
+
+ if (ifnum == 0) {
+ dev_dbg(dev, "Gobi 1K DM/DIAG interface found\n");
+ altsetting = 1;
+ } else if (ifnum == 2)
dev_dbg(dev, "Modem port found\n");
else
altsetting = -1;
- } else {
- /* Gobi 2K+ USB layout:
+ break;
+ case QCSERIAL_G2K:
+ /*
+ * Gobi 2K+ USB layout:
* 0: QMI/net
* 1: DM/DIAG (use libqcdm from ModemManager for communication)
* 2: AT-capable modem port
* 3: NMEA
*/
+ if (nintf < 3 || nintf > 4) {
+ dev_err(dev, "unknown number of interfaces: %d\n", nintf);
+ altsetting = -1;
+ goto done;
+ }
+
switch (ifnum) {
case 0:
/* Don't claim the QMI/net interface */
@@ -232,6 +262,35 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
dev_dbg(dev, "Gobi 2K+ NMEA GPS interface found\n");
break;
}
+ break;
+ case QCSERIAL_SWI:
+ /*
+ * Sierra Wireless layout:
+ * 0: DM/DIAG (use libqcdm from ModemManager for communication)
+ * 2: NMEA
+ * 3: AT-capable modem port
+ * 8: QMI/net
+ */
+ switch (ifnum) {
+ case 0:
+ dev_dbg(dev, "DM/DIAG interface found\n");
+ break;
+ case 2:
+ dev_dbg(dev, "NMEA GPS interface found\n");
+ break;
+ case 3:
+ dev_dbg(dev, "Modem port found\n");
+ break;
+ default:
+ /* don't claim any unsupported interface */
+ altsetting = -1;
+ break;
+ }
+ break;
+ default:
+ dev_err(dev, "unsupported device layout type: %lu\n",
+ id->driver_info);
+ break;
}
done:
diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c
index d152be97d04..504f5bff79c 100644
--- a/drivers/usb/serial/quatech2.c
+++ b/drivers/usb/serial/quatech2.c
@@ -15,7 +15,6 @@
#include <asm/unaligned.h>
#include <linux/errno.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
@@ -62,6 +61,7 @@
#define MAX_BAUD_RATE 921600
#define DEFAULT_BAUD_RATE 9600
+#define QT2_READ_BUFFER_SIZE 512 /* size of read buffer */
#define QT2_WRITE_BUFFER_SIZE 512 /* size of write buffer */
#define QT2_WRITE_CONTROL_SIZE 5 /* control bytes used for a write */
@@ -112,25 +112,21 @@ struct qt2_serial_private {
unsigned char current_port; /* current port for incoming data */
struct urb *read_urb; /* shared among all ports */
- char read_buffer[512];
+ char *read_buffer;
};
struct qt2_port_private {
- bool is_open;
u8 device_port;
spinlock_t urb_lock;
bool urb_in_use;
struct urb *write_urb;
- char write_buffer[QT2_WRITE_BUFFER_SIZE];
+ char *write_buffer;
spinlock_t lock;
u8 shadowLSR;
u8 shadowMSR;
- wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
- struct async_icount icount;
-
struct usb_serial_port *port;
};
@@ -146,6 +142,7 @@ static void qt2_release(struct usb_serial *serial)
serial_priv = usb_get_serial_data(serial);
usb_free_urb(serial_priv->read_urb);
+ kfree(serial_priv->read_buffer);
kfree(serial_priv);
}
@@ -347,7 +344,7 @@ static int qt2_open(struct tty_struct *tty, struct usb_serial_port *port)
int status;
unsigned long flags;
- device_port = (u16) (port->number - port->serial->minor);
+ device_port = port->port_number;
serial = port->serial;
@@ -375,7 +372,7 @@ static int qt2_open(struct tty_struct *tty, struct usb_serial_port *port)
device_port, data, 2, QT2_USB_TIMEOUT);
if (status < 0) {
- dev_err(&port->dev, "%s - open port failed %i", __func__,
+ dev_err(&port->dev, "%s - open port failed %i\n", __func__,
status);
kfree(data);
return status;
@@ -392,13 +389,11 @@ static int qt2_open(struct tty_struct *tty, struct usb_serial_port *port)
status = qt2_set_port_config(serial->dev, device_port,
DEFAULT_BAUD_RATE, UART_LCR_WLEN8);
if (status < 0) {
- dev_err(&port->dev,
- "%s - initial setup failed for port %i (%i)\n",
- __func__, port->number, device_port);
+ dev_err(&port->dev, "%s - initial setup failed (%i)\n",
+ __func__, device_port);
return status;
}
- port_priv->is_open = true;
port_priv->device_port = (u8) device_port;
if (tty)
@@ -418,19 +413,11 @@ static void qt2_close(struct usb_serial_port *port)
serial = port->serial;
port_priv = usb_get_serial_port_data(port);
- port_priv->is_open = false;
-
spin_lock_irqsave(&port_priv->urb_lock, flags);
usb_kill_urb(port_priv->write_urb);
port_priv->urb_in_use = false;
spin_unlock_irqrestore(&port_priv->urb_lock, flags);
- mutex_lock(&port->serial->disc_mutex);
- if (port->serial->disconnected) {
- mutex_unlock(&port->serial->disc_mutex);
- return;
- }
-
/* flush the port transmit buffer */
i = usb_control_msg(serial->dev,
usb_rcvctrlpipe(serial->dev, 0),
@@ -461,8 +448,6 @@ static void qt2_close(struct usb_serial_port *port)
if (i < 0)
dev_err(&port->dev, "%s - close port failed %i\n",
__func__, i);
-
- mutex_unlock(&port->serial->disc_mutex);
}
static void qt2_disconnect(struct usb_serial *serial)
@@ -481,7 +466,7 @@ static int get_serial_info(struct usb_serial_port *port,
return -EFAULT;
memset(&tmp, 0, sizeof(tmp));
- tmp.line = port->serial->minor;
+ tmp.line = port->minor;
tmp.port = 0;
tmp.irq = 0;
tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
@@ -495,67 +480,6 @@ static int get_serial_info(struct usb_serial_port *port,
return 0;
}
-static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
-{
- struct qt2_port_private *priv = usb_get_serial_port_data(port);
- struct async_icount prev, cur;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->lock, flags);
- prev = priv->icount;
- spin_unlock_irqrestore(&priv->lock, flags);
-
- while (1) {
- wait_event_interruptible(priv->delta_msr_wait,
- ((priv->icount.rng != prev.rng) ||
- (priv->icount.dsr != prev.dsr) ||
- (priv->icount.dcd != prev.dcd) ||
- (priv->icount.cts != prev.cts)));
-
- if (signal_pending(current))
- return -ERESTARTSYS;
-
- spin_lock_irqsave(&priv->lock, flags);
- cur = priv->icount;
- spin_unlock_irqrestore(&priv->lock, flags);
-
- if ((prev.rng == cur.rng) &&
- (prev.dsr == cur.dsr) &&
- (prev.dcd == cur.dcd) &&
- (prev.cts == cur.cts))
- return -EIO;
-
- if ((arg & TIOCM_RNG && (prev.rng != cur.rng)) ||
- (arg & TIOCM_DSR && (prev.dsr != cur.dsr)) ||
- (arg & TIOCM_CD && (prev.dcd != cur.dcd)) ||
- (arg & TIOCM_CTS && (prev.cts != cur.cts)))
- return 0;
- }
- return 0;
-}
-
-static int qt2_get_icount(struct tty_struct *tty,
- struct serial_icounter_struct *icount)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct qt2_port_private *priv = usb_get_serial_port_data(port);
- struct async_icount cnow = priv->icount;
-
- icount->cts = cnow.cts;
- icount->dsr = cnow.dsr;
- icount->rng = cnow.rng;
- icount->dcd = cnow.dcd;
- icount->rx = cnow.rx;
- icount->tx = cnow.tx;
- icount->frame = cnow.frame;
- icount->overrun = cnow.overrun;
- icount->parity = cnow.parity;
- icount->brk = cnow.brk;
- icount->buf_overrun = cnow.buf_overrun;
-
- return 0;
-}
-
static int qt2_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
@@ -565,10 +489,6 @@ static int qt2_ioctl(struct tty_struct *tty,
case TIOCGSERIAL:
return get_serial_info(port,
(struct serial_struct __user *)arg);
-
- case TIOCMIWAIT:
- return wait_modem_info(port, arg);
-
default:
break;
}
@@ -603,13 +523,12 @@ static void qt2_process_flush(struct usb_serial_port *port, unsigned char *ch)
return;
}
-void qt2_process_read_urb(struct urb *urb)
+static void qt2_process_read_urb(struct urb *urb)
{
struct usb_serial *serial;
struct qt2_serial_private *serial_priv;
struct usb_serial_port *port;
struct qt2_port_private *port_priv;
- struct tty_struct *tty;
bool escapeflag;
unsigned char *ch;
int i;
@@ -620,15 +539,11 @@ void qt2_process_read_urb(struct urb *urb)
return;
ch = urb->transfer_buffer;
- tty = NULL;
serial = urb->context;
serial_priv = usb_get_serial_data(serial);
port = serial->port[serial_priv->current_port];
port_priv = usb_get_serial_port_data(port);
- if (port_priv->is_open)
- tty = tty_port_tty_get(&port->port);
-
for (i = 0; i < urb->actual_length; i++) {
ch = (unsigned char *)urb->transfer_buffer + i;
if ((i <= (len - 3)) &&
@@ -666,10 +581,7 @@ void qt2_process_read_urb(struct urb *urb)
__func__);
break;
}
- if (tty) {
- tty_flip_buffer_push(tty);
- tty_kref_put(tty);
- }
+ tty_flip_buffer_push(&port->port);
newport = *(ch + 3);
@@ -683,10 +595,6 @@ void qt2_process_read_urb(struct urb *urb)
serial_priv->current_port = newport;
port = serial->port[serial_priv->current_port];
port_priv = usb_get_serial_port_data(port);
- if (port_priv->is_open)
- tty = tty_port_tty_get(&port->port);
- else
- tty = NULL;
i += 3;
escapeflag = true;
break;
@@ -697,8 +605,8 @@ void qt2_process_read_urb(struct urb *urb)
escapeflag = true;
break;
case QT2_CONTROL_ESCAPE:
- tty_buffer_request_room(tty, 2);
- tty_insert_flip_string(tty, ch, 2);
+ tty_buffer_request_room(&port->port, 2);
+ tty_insert_flip_string(&port->port, ch, 2);
i += 2;
escapeflag = true;
break;
@@ -712,16 +620,11 @@ void qt2_process_read_urb(struct urb *urb)
continue;
}
- if (tty) {
- tty_buffer_request_room(tty, 1);
- tty_insert_flip_string(tty, ch, 1);
- }
+ tty_buffer_request_room(&port->port, 1);
+ tty_insert_flip_string(&port->port, ch, 1);
}
- if (tty) {
- tty_flip_buffer_push(tty);
- tty_kref_put(tty);
- }
+ tty_flip_buffer_push(&port->port);
}
static void qt2_write_bulk_callback(struct urb *urb)
@@ -772,16 +675,14 @@ static int qt2_setup_urbs(struct usb_serial *serial)
serial_priv = usb_get_serial_data(serial);
serial_priv->read_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!serial_priv->read_urb) {
- dev_err(&serial->dev->dev, "No free urbs available\n");
+ if (!serial_priv->read_urb)
return -ENOMEM;
- }
usb_fill_bulk_urb(serial_priv->read_urb, serial->dev,
usb_rcvbulkpipe(serial->dev,
port0->bulk_in_endpointAddress),
serial_priv->read_buffer,
- sizeof(serial_priv->read_buffer),
+ QT2_READ_BUFFER_SIZE,
qt2_read_bulk_callback, serial);
status = usb_submit_urb(serial_priv->read_urb, GFP_KERNEL);
@@ -811,9 +712,13 @@ static int qt2_attach(struct usb_serial *serial)
}
serial_priv = kzalloc(sizeof(*serial_priv), GFP_KERNEL);
- if (!serial_priv) {
- dev_err(&serial->dev->dev, "%s - Out of memory\n", __func__);
+ if (!serial_priv)
return -ENOMEM;
+
+ serial_priv->read_buffer = kmalloc(QT2_READ_BUFFER_SIZE, GFP_KERNEL);
+ if (!serial_priv->read_buffer) {
+ status = -ENOMEM;
+ goto err_buf;
}
usb_set_serial_data(serial, serial_priv);
@@ -825,6 +730,8 @@ static int qt2_attach(struct usb_serial *serial)
return 0;
attach_failed:
+ kfree(serial_priv->read_buffer);
+err_buf:
kfree(serial_priv);
return status;
}
@@ -841,24 +748,31 @@ static int qt2_port_probe(struct usb_serial_port *port)
spin_lock_init(&port_priv->lock);
spin_lock_init(&port_priv->urb_lock);
- init_waitqueue_head(&port_priv->delta_msr_wait);
port_priv->port = port;
+ port_priv->write_buffer = kmalloc(QT2_WRITE_BUFFER_SIZE, GFP_KERNEL);
+ if (!port_priv->write_buffer)
+ goto err_buf;
+
port_priv->write_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!port_priv->write_urb) {
- kfree(port_priv);
- return -ENOMEM;
- }
+ if (!port_priv->write_urb)
+ goto err_urb;
+
bEndpointAddress = serial->port[0]->bulk_out_endpointAddress;
usb_fill_bulk_urb(port_priv->write_urb, serial->dev,
usb_sndbulkpipe(serial->dev, bEndpointAddress),
port_priv->write_buffer,
- sizeof(port_priv->write_buffer),
+ QT2_WRITE_BUFFER_SIZE,
qt2_write_bulk_callback, port);
usb_set_serial_port_data(port, port_priv);
return 0;
+err_urb:
+ kfree(port_priv->write_buffer);
+err_buf:
+ kfree(port_priv);
+ return -ENOMEM;
}
static int qt2_port_remove(struct usb_serial_port *port)
@@ -867,6 +781,7 @@ static int qt2_port_remove(struct usb_serial_port *port)
port_priv = usb_get_serial_port_data(port);
usb_free_urb(port_priv->write_urb);
+ kfree(port_priv->write_buffer);
kfree(port_priv);
return 0;
@@ -922,12 +837,6 @@ static void qt2_break_ctl(struct tty_struct *tty, int break_state)
port_priv = usb_get_serial_port_data(port);
- if (!port_priv->is_open) {
- dev_err(&port->dev,
- "%s - port is not open\n", __func__);
- return;
- }
-
val = (break_state == -1) ? 1 : 0;
status = qt2_control_msg(port->serial->dev, QT2_BREAK_CONTROL,
@@ -945,19 +854,17 @@ static void qt2_dtr_rts(struct usb_serial_port *port, int on)
struct usb_device *dev = port->serial->dev;
struct qt2_port_private *port_priv = usb_get_serial_port_data(port);
- mutex_lock(&port->serial->disc_mutex);
- if (!port->serial->disconnected) {
- /* Disable flow control */
- if (!on && qt2_setregister(dev, port_priv->device_port,
+ /* Disable flow control */
+ if (!on) {
+ if (qt2_setregister(dev, port_priv->device_port,
UART_MCR, 0) < 0)
dev_warn(&port->dev, "error from flowcontrol urb\n");
- /* drop RTS and DTR */
- if (on)
- update_mctrl(port_priv, TIOCM_DTR | TIOCM_RTS, 0);
- else
- update_mctrl(port_priv, 0, TIOCM_DTR | TIOCM_RTS);
}
- mutex_unlock(&port->serial->disc_mutex);
+ /* drop RTS and DTR */
+ if (on)
+ update_mctrl(port_priv, TIOCM_DTR | TIOCM_RTS, 0);
+ else
+ update_mctrl(port_priv, 0, TIOCM_DTR | TIOCM_RTS);
}
static void qt2_update_msr(struct usb_serial_port *port, unsigned char *ch)
@@ -975,18 +882,15 @@ static void qt2_update_msr(struct usb_serial_port *port, unsigned char *ch)
if (newMSR & UART_MSR_ANY_DELTA) {
/* update input line counters */
if (newMSR & UART_MSR_DCTS)
- port_priv->icount.cts++;
-
+ port->icount.cts++;
if (newMSR & UART_MSR_DDSR)
- port_priv->icount.dsr++;
-
+ port->icount.dsr++;
if (newMSR & UART_MSR_DDCD)
- port_priv->icount.dcd++;
-
+ port->icount.dcd++;
if (newMSR & UART_MSR_TERI)
- port_priv->icount.rng++;
+ port->icount.rng++;
- wake_up_interruptible(&port_priv->delta_msr_wait);
+ wake_up_interruptible(&port->port.delta_msr_wait);
}
}
@@ -1006,7 +910,7 @@ static void qt2_update_lsr(struct usb_serial_port *port, unsigned char *ch)
port_priv->shadowLSR = newLSR;
spin_unlock_irqrestore(&port_priv->lock, flags);
- icount = &port_priv->icount;
+ icount = &port->icount;
if (newLSR & UART_LSR_BRK_ERROR_BITS) {
@@ -1116,7 +1020,8 @@ static struct usb_serial_driver qt2_device = {
.break_ctl = qt2_break_ctl,
.tiocmget = qt2_tiocmget,
.tiocmset = qt2_tiocmset,
- .get_icount = qt2_get_icount,
+ .tiocmiwait = usb_serial_generic_tiocmiwait,
+ .get_icount = usb_serial_generic_get_icount,
.ioctl = qt2_ioctl,
.set_termios = qt2_set_termios,
};
diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c
index c949ce6ef0c..b2dff0f1474 100644
--- a/drivers/usb/serial/safe_serial.c
+++ b/drivers/usb/serial/safe_serial.c
@@ -67,7 +67,6 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/gfp.h>
-#include <linux/init.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
@@ -92,13 +91,6 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
-static __u16 vendor; /* no default */
-static __u16 product; /* no default */
-module_param(vendor, ushort, 0);
-MODULE_PARM_DESC(vendor, "User specified USB idVendor (required)");
-module_param(product, ushort, 0);
-MODULE_PARM_DESC(product, "User specified USB idProduct (required)");
-
module_param(safe, bool, 0);
MODULE_PARM_DESC(safe, "Turn Safe Encapsulation On/Off");
@@ -132,7 +124,7 @@ MODULE_PARM_DESC(padded, "Pad to full wMaxPacketSize On/Off");
.bInterfaceClass = (ic), \
.bInterfaceSubClass = (isc),
-static struct usb_device_id id_table[] = {
+static const struct usb_device_id id_table[] = {
{MY_USB_DEVICE(0x49f, 0xffff, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, /* Itsy */
{MY_USB_DEVICE(0x3f0, 0x2101, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, /* Calypso */
{MY_USB_DEVICE(0x4dd, 0x8001, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, /* Iris */
@@ -140,8 +132,6 @@ static struct usb_device_id id_table[] = {
{MY_USB_DEVICE(0x4dd, 0x8003, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, /* Collie */
{MY_USB_DEVICE(0x4dd, 0x8004, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, /* Collie */
{MY_USB_DEVICE(0x5f9, 0xffff, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, /* Sharp tmp */
- /* extra null entry for module vendor/produc parameters */
- {MY_USB_DEVICE(0, 0, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},
{} /* terminating entry */
};
@@ -207,38 +197,31 @@ static void safe_process_read_urb(struct urb *urb)
unsigned char *data = urb->transfer_buffer;
unsigned char length = urb->actual_length;
int actual_length;
- struct tty_struct *tty;
__u16 fcs;
if (!length)
return;
- tty = tty_port_tty_get(&port->port);
- if (!tty)
- return;
-
if (!safe)
goto out;
fcs = fcs_compute10(data, length, CRC10_INITFCS);
if (fcs) {
dev_err(&port->dev, "%s - bad CRC %x\n", __func__, fcs);
- goto err;
+ return;
}
actual_length = data[length - 2] >> 2;
if (actual_length > (length - 2)) {
dev_err(&port->dev, "%s - inconsistent lengths %d:%d\n",
__func__, actual_length, length);
- goto err;
+ return;
}
dev_info(&urb->dev->dev, "%s - actual: %d\n", __func__, actual_length);
length = actual_length;
out:
- tty_insert_flip_string(tty, data, length);
- tty_flip_buffer_push(tty);
-err:
- tty_kref_put(tty);
+ tty_insert_flip_string(&port->port, data, length);
+ tty_flip_buffer_push(&port->port);
}
static int safe_prepare_write_buffer(struct usb_serial_port *port,
@@ -279,7 +262,19 @@ static int safe_prepare_write_buffer(struct usb_serial_port *port,
static int safe_startup(struct usb_serial *serial)
{
- switch (serial->interface->cur_altsetting->desc.bInterfaceProtocol) {
+ struct usb_interface_descriptor *desc;
+
+ if (serial->dev->descriptor.bDeviceClass != CDC_DEVICE_CLASS)
+ return -ENODEV;
+
+ desc = &serial->interface->cur_altsetting->desc;
+
+ if (desc->bInterfaceClass != LINEO_INTERFACE_CLASS)
+ return -ENODEV;
+ if (desc->bInterfaceSubClass != LINEO_INTERFACE_SUBCLASS_SAFESERIAL)
+ return -ENODEV;
+
+ switch (desc->bInterfaceProtocol) {
case LINEO_SAFESERIAL_CRC:
break;
case LINEO_SAFESERIAL_CRC_PADDED:
@@ -307,30 +302,4 @@ static struct usb_serial_driver * const serial_drivers[] = {
&safe_device, NULL
};
-static int __init safe_init(void)
-{
- int i;
-
- /* if we have vendor / product parameters patch them into id list */
- if (vendor || product) {
- pr_info("vendor: %x product: %x\n", vendor, product);
-
- for (i = 0; i < ARRAY_SIZE(id_table); i++) {
- if (!id_table[i].idVendor && !id_table[i].idProduct) {
- id_table[i].idVendor = vendor;
- id_table[i].idProduct = product;
- break;
- }
- }
- }
-
- return usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, id_table);
-}
-
-static void __exit safe_exit(void)
-{
- usb_serial_deregister_drivers(serial_drivers);
-}
-
-module_init(safe_init);
-module_exit(safe_exit);
+module_usb_serial_driver(serial_drivers, id_table);
diff --git a/drivers/usb/serial/siemens_mpi.c b/drivers/usb/serial/siemens_mpi.c
deleted file mode 100644
index a76b1ae54a2..00000000000
--- a/drivers/usb/serial/siemens_mpi.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Siemens USB-MPI Serial USB driver
- *
- * Copyright (C) 2005 Thomas Hergenhahn <thomas.hergenhahn@suse.de>
- * Copyright (C) 2005,2008 Greg Kroah-Hartman <gregkh@suse.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/tty.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/usb/serial.h>
-
-#define DRIVER_AUTHOR "Thomas Hergenhahn@web.de http://libnodave.sf.net"
-#define DRIVER_DESC "Driver for Siemens USB/MPI adapter"
-
-
-static const struct usb_device_id id_table[] = {
- /* Vendor and product id for 6ES7-972-0CB20-0XA0 */
- { USB_DEVICE(0x908, 0x0004) },
- { },
-};
-MODULE_DEVICE_TABLE(usb, id_table);
-
-static struct usb_serial_driver siemens_usb_mpi_device = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "siemens_mpi",
- },
- .id_table = id_table,
- .num_ports = 1,
-};
-
-static struct usb_serial_driver * const serial_drivers[] = {
- &siemens_usb_mpi_device, NULL
-};
-
-module_usb_serial_driver(serial_drivers, id_table);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index af06f2f5f38..6f7f01eb556 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -58,6 +58,7 @@ struct sierra_intf_private {
spinlock_t susp_lock;
unsigned int suspended:1;
int in_flight;
+ unsigned int open_ports;
};
static int sierra_set_power_state(struct usb_device *udev, __u16 swiState)
@@ -291,7 +292,6 @@ static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x0f3d, 0x68A3), /* Airprime/Sierra Wireless Direct IP modems */
.driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist
},
- { USB_DEVICE(0x413C, 0x08133) }, /* Dell Computer Corp. Wireless 5720 VZW Mobile Broadband (EVDO Rev-A) Minicard GPS Port */
{ }
};
@@ -316,7 +316,6 @@ struct sierra_port_private {
int dsr_state;
int dcd_state;
int ri_state;
- unsigned int opened:1;
};
static int sierra_send_setup(struct usb_serial_port *port)
@@ -365,20 +364,13 @@ static int sierra_send_setup(struct usb_serial_port *port)
if (retval < 0)
return retval;
- retval = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+ retval = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
0x22, 0x21, val, interface, NULL, 0, USB_CTRL_SET_TIMEOUT);
usb_autopm_put_interface(serial->interface);
return retval;
}
-static void sierra_set_termios(struct tty_struct *tty,
- struct usb_serial_port *port, struct ktermios *old_termios)
-{
- tty_termios_copy_hw(&tty->termios, old_termios);
- sierra_send_setup(port);
-}
-
static int sierra_tiocmget(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
@@ -419,9 +411,7 @@ static int sierra_tiocmset(struct tty_struct *tty,
static void sierra_release_urb(struct urb *urb)
{
- struct usb_serial_port *port;
if (urb) {
- port = urb->context;
kfree(urb->transfer_buffer);
usb_free_urb(urb);
}
@@ -434,7 +424,7 @@ static void sierra_outdat_callback(struct urb *urb)
struct sierra_intf_private *intfdata;
int status = urb->status;
- intfdata = port->serial->private;
+ intfdata = usb_get_serial_data(port->serial);
/* free up the transfer buffer, as usb_free_urb() does not do this */
kfree(urb->transfer_buffer);
@@ -471,7 +461,7 @@ static int sierra_write(struct tty_struct *tty, struct usb_serial_port *port,
return 0;
portdata = usb_get_serial_port_data(port);
- intfdata = serial->private;
+ intfdata = usb_get_serial_data(serial);
dev_dbg(&port->dev, "%s: write (%zd bytes)\n", __func__, writesize);
spin_lock_irqsave(&portdata->lock, flags);
@@ -497,14 +487,12 @@ static int sierra_write(struct tty_struct *tty, struct usb_serial_port *port,
buffer = kmalloc(writesize, GFP_ATOMIC);
if (!buffer) {
- dev_err(&port->dev, "out of memory\n");
retval = -ENOMEM;
goto error_no_buffer;
}
urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) {
- dev_err(&port->dev, "no more free urbs\n");
retval = -ENOMEM;
goto error_no_urb;
}
@@ -569,7 +557,6 @@ static void sierra_indat_callback(struct urb *urb)
int err;
int endpoint;
struct usb_serial_port *port;
- struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
int status = urb->status;
@@ -581,16 +568,12 @@ static void sierra_indat_callback(struct urb *urb)
" endpoint %02x\n", __func__, status, endpoint);
} else {
if (urb->actual_length) {
- tty = tty_port_tty_get(&port->port);
- if (tty) {
- tty_insert_flip_string(tty, data,
- urb->actual_length);
- tty_flip_buffer_push(tty);
-
- tty_kref_put(tty);
- usb_serial_debug_data(&port->dev, __func__,
- urb->actual_length, data);
- }
+ tty_insert_flip_string(&port->port, data,
+ urb->actual_length);
+ tty_flip_buffer_push(&port->port);
+
+ usb_serial_debug_data(&port->dev, __func__,
+ urb->actual_length, data);
} else {
dev_dbg(&port->dev, "%s: empty read urb"
" received\n", __func__);
@@ -633,7 +616,6 @@ static void sierra_instat_callback(struct urb *urb)
unsigned char signals = *((unsigned char *)
urb->transfer_buffer +
sizeof(struct usb_ctrlrequest));
- struct tty_struct *tty;
dev_dbg(&port->dev, "%s: signal x%x\n", __func__,
signals);
@@ -644,11 +626,8 @@ static void sierra_instat_callback(struct urb *urb)
portdata->dsr_state = ((signals & 0x02) ? 1 : 0);
portdata->ri_state = ((signals & 0x08) ? 1 : 0);
- tty = tty_port_tty_get(&port->port);
- if (tty && !C_CLOCAL(tty) &&
- old_dcd_state && !portdata->dcd_state)
- tty_hangup(tty);
- tty_kref_put(tty);
+ if (old_dcd_state && !portdata->dcd_state)
+ tty_port_tty_hangup(&port->port, true);
} else {
dev_dbg(&port->dev, "%s: type %x req %x\n",
__func__, req_pkt->bRequestType,
@@ -686,6 +665,23 @@ static int sierra_write_room(struct tty_struct *tty)
return 2048;
}
+static int sierra_chars_in_buffer(struct tty_struct *tty)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ struct sierra_port_private *portdata = usb_get_serial_port_data(port);
+ unsigned long flags;
+ int chars;
+
+ /* NOTE: This overcounts somewhat. */
+ spin_lock_irqsave(&portdata->lock, flags);
+ chars = portdata->outstanding_urbs * MAX_TRANSFER;
+ spin_unlock_irqrestore(&portdata->lock, flags);
+
+ dev_dbg(&port->dev, "%s - %d\n", __func__, chars);
+
+ return chars;
+}
+
static void sierra_stop_rx_urbs(struct usb_serial_port *port)
{
int i;
@@ -741,15 +737,9 @@ static struct urb *sierra_setup_urb(struct usb_serial *serial, int endpoint,
struct urb *urb;
u8 *buf;
- if (endpoint == -1)
- return NULL;
-
urb = usb_alloc_urb(0, mem_flags);
- if (urb == NULL) {
- dev_dbg(&serial->dev->dev, "%s: alloc for endpoint %d failed\n",
- __func__, endpoint);
+ if (!urb)
return NULL;
- }
buf = kmalloc(len, mem_flags);
if (buf) {
@@ -761,9 +751,6 @@ static struct urb *sierra_setup_urb(struct usb_serial *serial, int endpoint,
dev_dbg(&serial->dev->dev, "%s %c u : %p d:%p\n", __func__,
dir == USB_DIR_IN ? 'i' : 'o', urb, buf);
} else {
- dev_dbg(&serial->dev->dev, "%s %c u:%p d:%p\n", __func__,
- dir == USB_DIR_IN ? 'i' : 'o', urb, buf);
-
sierra_release_urb(urb);
urb = NULL;
}
@@ -776,45 +763,48 @@ static void sierra_close(struct usb_serial_port *port)
int i;
struct usb_serial *serial = port->serial;
struct sierra_port_private *portdata;
- struct sierra_intf_private *intfdata = port->serial->private;
+ struct sierra_intf_private *intfdata = usb_get_serial_data(serial);
+ struct urb *urb;
portdata = usb_get_serial_port_data(port);
- portdata->rts_state = 0;
- portdata->dtr_state = 0;
-
- if (serial->dev) {
- mutex_lock(&serial->disc_mutex);
- if (!serial->disconnected) {
- serial->interface->needs_remote_wakeup = 0;
- /* odd error handling due to pm counters */
- if (!usb_autopm_get_interface(serial->interface))
- sierra_send_setup(port);
- else
- usb_autopm_get_interface_no_resume(serial->interface);
-
- }
- mutex_unlock(&serial->disc_mutex);
- spin_lock_irq(&intfdata->susp_lock);
- portdata->opened = 0;
- spin_unlock_irq(&intfdata->susp_lock);
+ /*
+ * Need to take susp_lock to make sure port is not already being
+ * resumed, but no need to hold it due to ASYNC_INITIALIZED.
+ */
+ spin_lock_irq(&intfdata->susp_lock);
+ if (--intfdata->open_ports == 0)
+ serial->interface->needs_remote_wakeup = 0;
+ spin_unlock_irq(&intfdata->susp_lock);
+
+ for (;;) {
+ urb = usb_get_from_anchor(&portdata->delayed);
+ if (!urb)
+ break;
+ kfree(urb->transfer_buffer);
+ usb_free_urb(urb);
+ usb_autopm_put_interface_async(serial->interface);
+ spin_lock(&portdata->lock);
+ portdata->outstanding_urbs--;
+ spin_unlock(&portdata->lock);
+ }
+ sierra_stop_rx_urbs(port);
+ usb_kill_anchored_urbs(&portdata->active);
- /* Stop reading urbs */
- sierra_stop_rx_urbs(port);
- /* .. and release them */
- for (i = 0; i < portdata->num_in_urbs; i++) {
- sierra_release_urb(portdata->in_urbs[i]);
- portdata->in_urbs[i] = NULL;
- }
+ for (i = 0; i < portdata->num_in_urbs; i++) {
+ sierra_release_urb(portdata->in_urbs[i]);
+ portdata->in_urbs[i] = NULL;
}
+
+ usb_autopm_get_interface_no_resume(serial->interface);
}
static int sierra_open(struct tty_struct *tty, struct usb_serial_port *port)
{
struct sierra_port_private *portdata;
struct usb_serial *serial = port->serial;
- struct sierra_intf_private *intfdata = serial->private;
+ struct sierra_intf_private *intfdata = usb_get_serial_data(serial);
int i;
int err;
int endpoint;
@@ -822,11 +812,6 @@ static int sierra_open(struct tty_struct *tty, struct usb_serial_port *port)
portdata = usb_get_serial_port_data(port);
- /* Set some sane defaults */
- portdata->rts_state = 1;
- portdata->dtr_state = 1;
-
-
endpoint = port->bulk_in_endpointAddress;
for (i = 0; i < portdata->num_in_urbs; i++) {
urb = sierra_setup_urb(serial, endpoint, USB_DIR_IN, port,
@@ -839,41 +824,38 @@ static int sierra_open(struct tty_struct *tty, struct usb_serial_port *port)
usb_sndbulkpipe(serial->dev, endpoint) | USB_DIR_IN);
err = sierra_submit_rx_urbs(port, GFP_KERNEL);
- if (err) {
- /* get rid of everything as in close */
- sierra_close(port);
- /* restore balance for autopm */
- if (!serial->disconnected)
- usb_autopm_put_interface(serial->interface);
- return err;
- }
- sierra_send_setup(port);
+ if (err)
+ goto err_submit;
- serial->interface->needs_remote_wakeup = 1;
spin_lock_irq(&intfdata->susp_lock);
- portdata->opened = 1;
+ if (++intfdata->open_ports == 1)
+ serial->interface->needs_remote_wakeup = 1;
spin_unlock_irq(&intfdata->susp_lock);
usb_autopm_put_interface(serial->interface);
return 0;
+
+err_submit:
+ sierra_stop_rx_urbs(port);
+
+ for (i = 0; i < portdata->num_in_urbs; i++) {
+ sierra_release_urb(portdata->in_urbs[i]);
+ portdata->in_urbs[i] = NULL;
+ }
+
+ return err;
}
static void sierra_dtr_rts(struct usb_serial_port *port, int on)
{
- struct usb_serial *serial = port->serial;
struct sierra_port_private *portdata;
portdata = usb_get_serial_port_data(port);
portdata->rts_state = on;
portdata->dtr_state = on;
- if (serial->dev) {
- mutex_lock(&serial->disc_mutex);
- if (!serial->disconnected)
- sierra_send_setup(port);
- mutex_unlock(&serial->disc_mutex);
- }
+ sierra_send_setup(port);
}
static int sierra_startup(struct usb_serial *serial)
@@ -934,7 +916,7 @@ static int sierra_port_probe(struct usb_serial_port *port)
/* This is really the usb-serial port number of the interface
* rather than the interface number.
*/
- ifnum = port->number - serial->minor;
+ ifnum = port->port_number;
himemoryp = &typeA_interface_list;
}
@@ -957,6 +939,7 @@ static int sierra_port_remove(struct usb_serial_port *port)
struct sierra_port_private *portdata;
portdata = usb_get_serial_port_data(port);
+ usb_set_serial_port_data(port, NULL);
kfree(portdata);
return 0;
@@ -973,6 +956,8 @@ static void stop_read_write_urbs(struct usb_serial *serial)
for (i = 0; i < serial->num_ports; ++i) {
port = serial->port[i];
portdata = usb_get_serial_port_data(port);
+ if (!portdata)
+ continue;
sierra_stop_rx_urbs(port);
usb_kill_anchored_urbs(&portdata->active);
}
@@ -980,58 +965,84 @@ static void stop_read_write_urbs(struct usb_serial *serial)
static int sierra_suspend(struct usb_serial *serial, pm_message_t message)
{
- struct sierra_intf_private *intfdata;
- int b;
+ struct sierra_intf_private *intfdata = usb_get_serial_data(serial);
+ spin_lock_irq(&intfdata->susp_lock);
if (PMSG_IS_AUTO(message)) {
- intfdata = serial->private;
- spin_lock_irq(&intfdata->susp_lock);
- b = intfdata->in_flight;
-
- if (b) {
+ if (intfdata->in_flight) {
spin_unlock_irq(&intfdata->susp_lock);
return -EBUSY;
- } else {
- intfdata->suspended = 1;
- spin_unlock_irq(&intfdata->susp_lock);
}
}
+ intfdata->suspended = 1;
+ spin_unlock_irq(&intfdata->susp_lock);
+
stop_read_write_urbs(serial);
return 0;
}
+/* Caller must hold susp_lock. */
+static int sierra_submit_delayed_urbs(struct usb_serial_port *port)
+{
+ struct sierra_port_private *portdata = usb_get_serial_port_data(port);
+ struct sierra_intf_private *intfdata;
+ struct urb *urb;
+ int ec = 0;
+ int err;
+
+ intfdata = usb_get_serial_data(port->serial);
+
+ for (;;) {
+ urb = usb_get_from_anchor(&portdata->delayed);
+ if (!urb)
+ break;
+
+ usb_anchor_urb(urb, &portdata->active);
+ intfdata->in_flight++;
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err) {
+ dev_err(&port->dev, "%s - submit urb failed: %d",
+ __func__, err);
+ ec++;
+ intfdata->in_flight--;
+ usb_unanchor_urb(urb);
+ kfree(urb->transfer_buffer);
+ usb_free_urb(urb);
+
+ spin_lock(&portdata->lock);
+ portdata->outstanding_urbs--;
+ spin_unlock(&portdata->lock);
+ }
+ }
+
+ if (ec)
+ return -EIO;
+
+ return 0;
+}
+
static int sierra_resume(struct usb_serial *serial)
{
struct usb_serial_port *port;
- struct sierra_intf_private *intfdata = serial->private;
- struct sierra_port_private *portdata;
- struct urb *urb;
+ struct sierra_intf_private *intfdata = usb_get_serial_data(serial);
int ec = 0;
int i, err;
spin_lock_irq(&intfdata->susp_lock);
for (i = 0; i < serial->num_ports; i++) {
port = serial->port[i];
- portdata = usb_get_serial_port_data(port);
- while ((urb = usb_get_from_anchor(&portdata->delayed))) {
- usb_anchor_urb(urb, &portdata->active);
- intfdata->in_flight++;
- err = usb_submit_urb(urb, GFP_ATOMIC);
- if (err < 0) {
- intfdata->in_flight--;
- usb_unanchor_urb(urb);
- usb_scuttle_anchored_urbs(&portdata->delayed);
- break;
- }
- }
+ if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags))
+ continue;
- if (portdata->opened) {
- err = sierra_submit_rx_urbs(port, GFP_ATOMIC);
- if (err)
- ec++;
- }
+ err = sierra_submit_delayed_urbs(port);
+ if (err)
+ ec++;
+
+ err = sierra_submit_rx_urbs(port, GFP_ATOMIC);
+ if (err)
+ ec++;
}
intfdata->suspended = 0;
spin_unlock_irq(&intfdata->susp_lock);
@@ -1058,7 +1069,7 @@ static struct usb_serial_driver sierra_device = {
.dtr_rts = sierra_dtr_rts,
.write = sierra_write,
.write_room = sierra_write_room,
- .set_termios = sierra_set_termios,
+ .chars_in_buffer = sierra_chars_in_buffer,
.tiocmget = sierra_tiocmget,
.tiocmset = sierra_tiocmset,
.attach = sierra_startup,
diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c
index a42536af125..ef0dbf0703c 100644
--- a/drivers/usb/serial/spcp8x5.c
+++ b/drivers/usb/serial/spcp8x5.c
@@ -1,7 +1,7 @@
/*
* spcp8x5 USB to serial adaptor driver
*
- * Copyright (C) 2010 Johan Hovold (jhovold@gmail.com)
+ * Copyright (C) 2010-2013 Johan Hovold (jhovold@gmail.com)
* Copyright (C) 2006 Linxb (xubin.lin@worldplus.com.cn)
* Copyright (C) 2006 S1 Corp.
*
@@ -13,12 +13,9 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- *
*/
#include <linux/kernel.h>
#include <linux/errno.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
@@ -28,7 +25,10 @@
#include <linux/usb.h>
#include <linux/usb/serial.h>
-#define DRIVER_DESC "SPCP8x5 USB to serial adaptor driver"
+#define DRIVER_DESC "SPCP8x5 USB to serial adaptor driver"
+
+#define SPCP825_QUIRK_NO_UART_STATUS 0x01
+#define SPCP825_QUIRK_NO_WORK_MODE 0x02
#define SPCP8x5_007_VID 0x04FC
#define SPCP8x5_007_PID 0x0201
@@ -46,13 +46,15 @@ static const struct usb_device_id id_table[] = {
{ USB_DEVICE(SPCP8x5_INTERMATIC_VID, SPCP8x5_INTERMATIC_PID)},
{ USB_DEVICE(SPCP8x5_835_VID, SPCP8x5_835_PID)},
{ USB_DEVICE(SPCP8x5_008_VID, SPCP8x5_008_PID)},
- { USB_DEVICE(SPCP8x5_007_VID, SPCP8x5_007_PID)},
+ { USB_DEVICE(SPCP8x5_007_VID, SPCP8x5_007_PID),
+ .driver_info = SPCP825_QUIRK_NO_UART_STATUS |
+ SPCP825_QUIRK_NO_WORK_MODE },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, id_table);
struct spcp8x5_usb_ctrl_arg {
- u8 type;
+ u8 type;
u8 cmd;
u8 cmd_type;
u16 value;
@@ -138,51 +140,35 @@ struct spcp8x5_usb_ctrl_arg {
#define UART_OVERRUN_ERROR 0x40
#define UART_CTS 0x80
-enum spcp8x5_type {
- SPCP825_007_TYPE,
- SPCP825_008_TYPE,
- SPCP825_PHILIP_TYPE,
- SPCP825_INTERMATIC_TYPE,
- SPCP835_TYPE,
-};
-
struct spcp8x5_private {
- spinlock_t lock;
- enum spcp8x5_type type;
- wait_queue_head_t delta_msr_wait;
- u8 line_control;
- u8 line_status;
+ unsigned quirks;
+ spinlock_t lock;
+ u8 line_control;
};
+static int spcp8x5_probe(struct usb_serial *serial,
+ const struct usb_device_id *id)
+{
+ usb_set_serial_data(serial, (void *)id);
+
+ return 0;
+}
+
static int spcp8x5_port_probe(struct usb_serial_port *port)
{
- struct usb_serial *serial = port->serial;
+ const struct usb_device_id *id = usb_get_serial_data(port->serial);
struct spcp8x5_private *priv;
- enum spcp8x5_type type = SPCP825_007_TYPE;
- u16 product = le16_to_cpu(serial->dev->descriptor.idProduct);
-
- if (product == 0x0201)
- type = SPCP825_007_TYPE;
- else if (product == 0x0231)
- type = SPCP835_TYPE;
- else if (product == 0x0235)
- type = SPCP825_008_TYPE;
- else if (product == 0x0204)
- type = SPCP825_INTERMATIC_TYPE;
- else if (product == 0x0471 &&
- serial->dev->descriptor.idVendor == cpu_to_le16(0x081e))
- type = SPCP825_PHILIP_TYPE;
- dev_dbg(&serial->dev->dev, "device type = %d\n", (int)type);
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
spin_lock_init(&priv->lock);
- init_waitqueue_head(&priv->delta_msr_wait);
- priv->type = type;
+ priv->quirks = id->driver_info;
- usb_set_serial_port_data(port , priv);
+ usb_set_serial_port_data(port, priv);
+
+ port->port.drain_delay = 256;
return 0;
}
@@ -197,86 +183,79 @@ static int spcp8x5_port_remove(struct usb_serial_port *port)
return 0;
}
-/* set the modem control line of the device.
- * NOTE spcp825-007 not supported this */
-static int spcp8x5_set_ctrlLine(struct usb_device *dev, u8 value,
- enum spcp8x5_type type)
+static int spcp8x5_set_ctrl_line(struct usb_serial_port *port, u8 mcr)
{
+ struct spcp8x5_private *priv = usb_get_serial_port_data(port);
+ struct usb_device *dev = port->serial->dev;
int retval;
- u8 mcr = 0 ;
- if (type == SPCP825_007_TYPE)
+ if (priv->quirks & SPCP825_QUIRK_NO_UART_STATUS)
return -EPERM;
- mcr = (unsigned short)value;
retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
SET_UART_STATUS_TYPE, SET_UART_STATUS,
mcr, 0x04, NULL, 0, 100);
- if (retval != 0)
- dev_dbg(&dev->dev, "usb_control_msg return %#x\n", retval);
+ if (retval != 0) {
+ dev_err(&port->dev, "failed to set control lines: %d\n",
+ retval);
+ }
return retval;
}
-/* get the modem status register of the device
- * NOTE spcp825-007 not supported this */
-static int spcp8x5_get_msr(struct usb_device *dev, u8 *status,
- enum spcp8x5_type type)
+static int spcp8x5_get_msr(struct usb_serial_port *port, u8 *status)
{
- u8 *status_buffer;
+ struct spcp8x5_private *priv = usb_get_serial_port_data(port);
+ struct usb_device *dev = port->serial->dev;
+ u8 *buf;
int ret;
- /* I return Permited not support here but seem inval device
- * is more fix */
- if (type == SPCP825_007_TYPE)
+ if (priv->quirks & SPCP825_QUIRK_NO_UART_STATUS)
return -EPERM;
- if (status == NULL)
- return -EINVAL;
- status_buffer = kmalloc(1, GFP_KERNEL);
- if (!status_buffer)
+ buf = kzalloc(1, GFP_KERNEL);
+ if (!buf)
return -ENOMEM;
- status_buffer[0] = status[0];
ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
GET_UART_STATUS, GET_UART_STATUS_TYPE,
- 0, GET_UART_STATUS_MSR, status_buffer, 1, 100);
+ 0, GET_UART_STATUS_MSR, buf, 1, 100);
if (ret < 0)
- dev_dbg(&dev->dev, "Get MSR = 0x%p failed (error = %d)",
- status_buffer, ret);
+ dev_err(&port->dev, "failed to get modem status: %d\n", ret);
- dev_dbg(&dev->dev, "0xc0:0x22:0:6 %d - 0x%p ", ret, status_buffer);
- status[0] = status_buffer[0];
- kfree(status_buffer);
+ dev_dbg(&port->dev, "0xc0:0x22:0:6 %d - 0x02%x\n", ret, *buf);
+ *status = *buf;
+ kfree(buf);
return ret;
}
-/* select the work mode.
- * NOTE this function not supported by spcp825-007 */
-static void spcp8x5_set_workMode(struct usb_device *dev, u16 value,
- u16 index, enum spcp8x5_type type)
+static void spcp8x5_set_work_mode(struct usb_serial_port *port, u16 value,
+ u16 index)
{
+ struct spcp8x5_private *priv = usb_get_serial_port_data(port);
+ struct usb_device *dev = port->serial->dev;
int ret;
- /* I return Permited not support here but seem inval device
- * is more fix */
- if (type == SPCP825_007_TYPE)
+ if (priv->quirks & SPCP825_QUIRK_NO_WORK_MODE)
return;
ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
SET_WORKING_MODE_TYPE, SET_WORKING_MODE,
value, index, NULL, 0, 100);
- dev_dbg(&dev->dev, "value = %#x , index = %#x\n", value, index);
+ dev_dbg(&port->dev, "value = %#x , index = %#x\n", value, index);
if (ret < 0)
- dev_dbg(&dev->dev,
- "RTSCTS usb_control_msg(enable flowctrl) = %d\n", ret);
+ dev_err(&port->dev, "failed to set work mode: %d\n", ret);
}
static int spcp8x5_carrier_raised(struct usb_serial_port *port)
{
- struct spcp8x5_private *priv = usb_get_serial_port_data(port);
- if (priv->line_status & MSR_STATUS_LINE_DCD)
+ u8 msr;
+ int ret;
+
+ ret = spcp8x5_get_msr(port, &msr);
+ if (ret || msr & MSR_STATUS_LINE_DCD)
return 1;
+
return 0;
}
@@ -295,20 +274,17 @@ static void spcp8x5_dtr_rts(struct usb_serial_port *port, int on)
| MCR_CONTROL_LINE_RTS);
control = priv->line_control;
spin_unlock_irqrestore(&priv->lock, flags);
- spcp8x5_set_ctrlLine(port->serial->dev, control , priv->type);
+ spcp8x5_set_ctrl_line(port, control);
}
static void spcp8x5_init_termios(struct tty_struct *tty)
{
- /* for the 1st time call this function */
tty->termios = tty_std_termios;
tty->termios.c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL;
tty->termios.c_ispeed = 115200;
tty->termios.c_ospeed = 115200;
}
-/* set the serial param for transfer. we should check if we really need to
- * transfer. if we set flow control we should do this too. */
static void spcp8x5_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios)
{
@@ -316,30 +292,28 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
struct spcp8x5_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
unsigned int cflag = tty->termios.c_cflag;
- unsigned int old_cflag = old_termios->c_cflag;
unsigned short uartdata;
unsigned char buf[2] = {0, 0};
int baud;
int i;
u8 control;
-
/* check that they really want us to change something */
- if (!tty_termios_hw_change(&tty->termios, old_termios))
+ if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios))
return;
/* set DTR/RTS active */
spin_lock_irqsave(&priv->lock, flags);
control = priv->line_control;
- if ((old_cflag & CBAUD) == B0) {
+ if (old_termios && (old_termios->c_cflag & CBAUD) == B0) {
priv->line_control |= MCR_DTR;
- if (!(old_cflag & CRTSCTS))
+ if (!(old_termios->c_cflag & CRTSCTS))
priv->line_control |= MCR_RTS;
}
if (control != priv->line_control) {
control = priv->line_control;
spin_unlock_irqrestore(&priv->lock, flags);
- spcp8x5_set_ctrlLine(serial->dev, control , priv->type);
+ spcp8x5_set_ctrl_line(port, control);
} else {
spin_unlock_irqrestore(&priv->lock, flags);
}
@@ -368,27 +342,24 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
case 1000000:
buf[0] = 0x0b; break;
default:
- dev_err(&port->dev, "spcp825 driver does not support the "
- "baudrate requested, using default of 9600.\n");
+ dev_err(&port->dev, "unsupported baudrate, using 9600\n");
}
/* Set Data Length : 00:5bit, 01:6bit, 10:7bit, 11:8bit */
- if (cflag & CSIZE) {
- switch (cflag & CSIZE) {
- case CS5:
- buf[1] |= SET_UART_FORMAT_SIZE_5;
- break;
- case CS6:
- buf[1] |= SET_UART_FORMAT_SIZE_6;
- break;
- case CS7:
- buf[1] |= SET_UART_FORMAT_SIZE_7;
- break;
- default:
- case CS8:
- buf[1] |= SET_UART_FORMAT_SIZE_8;
- break;
- }
+ switch (cflag & CSIZE) {
+ case CS5:
+ buf[1] |= SET_UART_FORMAT_SIZE_5;
+ break;
+ case CS6:
+ buf[1] |= SET_UART_FORMAT_SIZE_6;
+ break;
+ case CS7:
+ buf[1] |= SET_UART_FORMAT_SIZE_7;
+ break;
+ default:
+ case CS8:
+ buf[1] |= SET_UART_FORMAT_SIZE_8;
+ break;
}
/* Set Stop bit2 : 0:1bit 1:2bit */
@@ -399,9 +370,9 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
if (cflag & PARENB) {
buf[1] |= (cflag & PARODD) ?
SET_UART_FORMAT_PAR_ODD : SET_UART_FORMAT_PAR_EVEN ;
- } else
+ } else {
buf[1] |= SET_UART_FORMAT_PAR_NONE;
-
+ }
uartdata = buf[0] | buf[1]<<8;
i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
@@ -414,22 +385,15 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
if (cflag & CRTSCTS) {
/* enable hardware flow control */
- spcp8x5_set_workMode(serial->dev, 0x000a,
- SET_WORKING_MODE_U2C, priv->type);
+ spcp8x5_set_work_mode(port, 0x000a, SET_WORKING_MODE_U2C);
}
}
-/* open the serial port. do some usb system call. set termios and get the line
- * status of the device. */
static int spcp8x5_open(struct tty_struct *tty, struct usb_serial_port *port)
{
- struct ktermios tmp_termios;
struct usb_serial *serial = port->serial;
struct spcp8x5_private *priv = usb_get_serial_port_data(port);
int ret;
- unsigned long flags;
- u8 status = 0x30;
- /* status 0x30 means DSR and CTS = 1 other CDC RI and delta = 0 */
usb_clear_halt(serial->dev, port->write_urb->pipe);
usb_clear_halt(serial->dev, port->read_urb->pipe);
@@ -440,139 +404,14 @@ static int spcp8x5_open(struct tty_struct *tty, struct usb_serial_port *port)
if (ret)
return ret;
- spcp8x5_set_ctrlLine(serial->dev, priv->line_control , priv->type);
+ spcp8x5_set_ctrl_line(port, priv->line_control);
- /* Setup termios */
if (tty)
- spcp8x5_set_termios(tty, port, &tmp_termios);
-
- spcp8x5_get_msr(serial->dev, &status, priv->type);
-
- /* may be we should update uart status here but now we did not do */
- spin_lock_irqsave(&priv->lock, flags);
- priv->line_status = status & 0xf0 ;
- spin_unlock_irqrestore(&priv->lock, flags);
-
- port->port.drain_delay = 256;
+ spcp8x5_set_termios(tty, port, NULL);
return usb_serial_generic_open(tty, port);
}
-static void spcp8x5_process_read_urb(struct urb *urb)
-{
- struct usb_serial_port *port = urb->context;
- struct spcp8x5_private *priv = usb_get_serial_port_data(port);
- struct tty_struct *tty;
- unsigned char *data = urb->transfer_buffer;
- unsigned long flags;
- u8 status;
- char tty_flag;
-
- /* get tty_flag from status */
- tty_flag = TTY_NORMAL;
-
- spin_lock_irqsave(&priv->lock, flags);
- status = priv->line_status;
- priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
- spin_unlock_irqrestore(&priv->lock, flags);
- /* wake up the wait for termios */
- wake_up_interruptible(&priv->delta_msr_wait);
-
- if (!urb->actual_length)
- return;
-
- tty = tty_port_tty_get(&port->port);
- if (!tty)
- return;
-
- if (status & UART_STATE_TRANSIENT_MASK) {
- /* break takes precedence over parity, which takes precedence
- * over framing errors */
- if (status & UART_BREAK_ERROR)
- tty_flag = TTY_BREAK;
- else if (status & UART_PARITY_ERROR)
- tty_flag = TTY_PARITY;
- else if (status & UART_FRAME_ERROR)
- tty_flag = TTY_FRAME;
- dev_dbg(&port->dev, "tty_flag = %d\n", tty_flag);
-
- /* overrun is special, not associated with a char */
- if (status & UART_OVERRUN_ERROR)
- tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-
- if (status & UART_DCD)
- usb_serial_handle_dcd_change(port, tty,
- priv->line_status & MSR_STATUS_LINE_DCD);
- }
-
- tty_insert_flip_string_fixed_flag(tty, data, tty_flag,
- urb->actual_length);
- tty_flip_buffer_push(tty);
- tty_kref_put(tty);
-}
-
-static int spcp8x5_wait_modem_info(struct usb_serial_port *port,
- unsigned int arg)
-{
- struct spcp8x5_private *priv = usb_get_serial_port_data(port);
- unsigned long flags;
- unsigned int prevstatus;
- unsigned int status;
- unsigned int changed;
-
- spin_lock_irqsave(&priv->lock, flags);
- prevstatus = priv->line_status;
- spin_unlock_irqrestore(&priv->lock, flags);
-
- while (1) {
- /* wake up in bulk read */
- interruptible_sleep_on(&priv->delta_msr_wait);
-
- /* see if a signal did it */
- if (signal_pending(current))
- return -ERESTARTSYS;
-
- spin_lock_irqsave(&priv->lock, flags);
- status = priv->line_status;
- spin_unlock_irqrestore(&priv->lock, flags);
-
- changed = prevstatus^status;
-
- if (((arg & TIOCM_RNG) && (changed & MSR_STATUS_LINE_RI)) ||
- ((arg & TIOCM_DSR) && (changed & MSR_STATUS_LINE_DSR)) ||
- ((arg & TIOCM_CD) && (changed & MSR_STATUS_LINE_DCD)) ||
- ((arg & TIOCM_CTS) && (changed & MSR_STATUS_LINE_CTS)))
- return 0;
-
- prevstatus = status;
- }
- /* NOTREACHED */
- return 0;
-}
-
-static int spcp8x5_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
-{
- struct usb_serial_port *port = tty->driver_data;
-
- dev_dbg(&port->dev, "%s (%d) cmd = 0x%04x\n", __func__,
- port->number, cmd);
-
- switch (cmd) {
- case TIOCMIWAIT:
- dev_dbg(&port->dev, "%s (%d) TIOCMIWAIT\n", __func__,
- port->number);
- return spcp8x5_wait_modem_info(port, arg);
-
- default:
- dev_dbg(&port->dev, "%s not supported = 0x%04x", __func__,
- cmd);
- break;
- }
-
- return -ENOIOCTLCMD;
-}
-
static int spcp8x5_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear)
{
@@ -593,7 +432,7 @@ static int spcp8x5_tiocmset(struct tty_struct *tty,
control = priv->line_control;
spin_unlock_irqrestore(&priv->lock, flags);
- return spcp8x5_set_ctrlLine(port->serial->dev, control , priv->type);
+ return spcp8x5_set_ctrl_line(port, control);
}
static int spcp8x5_tiocmget(struct tty_struct *tty)
@@ -602,12 +441,15 @@ static int spcp8x5_tiocmget(struct tty_struct *tty)
struct spcp8x5_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
unsigned int mcr;
- unsigned int status;
+ u8 status;
unsigned int result;
+ result = spcp8x5_get_msr(port, &status);
+ if (result)
+ return result;
+
spin_lock_irqsave(&priv->lock, flags);
mcr = priv->line_control;
- status = priv->line_status;
spin_unlock_irqrestore(&priv->lock, flags);
result = ((mcr & MCR_DTR) ? TIOCM_DTR : 0)
@@ -620,7 +462,6 @@ static int spcp8x5_tiocmget(struct tty_struct *tty)
return result;
}
-/* All of the device info needed for the spcp8x5 SIO serial converter */
static struct usb_serial_driver spcp8x5_device = {
.driver = {
.owner = THIS_MODULE,
@@ -628,17 +469,16 @@ static struct usb_serial_driver spcp8x5_device = {
},
.id_table = id_table,
.num_ports = 1,
- .open = spcp8x5_open,
+ .open = spcp8x5_open,
.dtr_rts = spcp8x5_dtr_rts,
.carrier_raised = spcp8x5_carrier_raised,
- .set_termios = spcp8x5_set_termios,
+ .set_termios = spcp8x5_set_termios,
.init_termios = spcp8x5_init_termios,
- .ioctl = spcp8x5_ioctl,
- .tiocmget = spcp8x5_tiocmget,
- .tiocmset = spcp8x5_tiocmset,
+ .tiocmget = spcp8x5_tiocmget,
+ .tiocmset = spcp8x5_tiocmset,
+ .probe = spcp8x5_probe,
.port_probe = spcp8x5_port_probe,
.port_remove = spcp8x5_port_remove,
- .process_read_urb = spcp8x5_process_read_urb,
};
static struct usb_serial_driver * const serial_drivers[] = {
diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c
index 4543ea35022..a7fe664b6b7 100644
--- a/drivers/usb/serial/ssu100.c
+++ b/drivers/usb/serial/ssu100.c
@@ -6,7 +6,6 @@
*/
#include <linux/errno.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
@@ -61,8 +60,6 @@ struct ssu100_port_private {
spinlock_t status_lock;
u8 shadowLSR;
u8 shadowMSR;
- wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
- struct async_icount icount;
};
static inline int ssu100_control_msg(struct usb_device *dev,
@@ -316,11 +313,6 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port)
return usb_serial_generic_open(tty, port);
}
-static void ssu100_close(struct usb_serial_port *port)
-{
- usb_serial_generic_close(port);
-}
-
static int get_serial_info(struct usb_serial_port *port,
struct serial_struct __user *retinfo)
{
@@ -330,7 +322,7 @@ static int get_serial_info(struct usb_serial_port *port,
return -EFAULT;
memset(&tmp, 0, sizeof(tmp));
- tmp.line = port->serial->minor;
+ tmp.line = port->minor;
tmp.port = 0;
tmp.irq = 0;
tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
@@ -344,90 +336,19 @@ static int get_serial_info(struct usb_serial_port *port,
return 0;
}
-static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
-{
- struct ssu100_port_private *priv = usb_get_serial_port_data(port);
- struct async_icount prev, cur;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->status_lock, flags);
- prev = priv->icount;
- spin_unlock_irqrestore(&priv->status_lock, flags);
-
- while (1) {
- wait_event_interruptible(priv->delta_msr_wait,
- ((priv->icount.rng != prev.rng) ||
- (priv->icount.dsr != prev.dsr) ||
- (priv->icount.dcd != prev.dcd) ||
- (priv->icount.cts != prev.cts)));
-
- if (signal_pending(current))
- return -ERESTARTSYS;
-
- spin_lock_irqsave(&priv->status_lock, flags);
- cur = priv->icount;
- spin_unlock_irqrestore(&priv->status_lock, flags);
-
- if ((prev.rng == cur.rng) &&
- (prev.dsr == cur.dsr) &&
- (prev.dcd == cur.dcd) &&
- (prev.cts == cur.cts))
- return -EIO;
-
- if ((arg & TIOCM_RNG && (prev.rng != cur.rng)) ||
- (arg & TIOCM_DSR && (prev.dsr != cur.dsr)) ||
- (arg & TIOCM_CD && (prev.dcd != cur.dcd)) ||
- (arg & TIOCM_CTS && (prev.cts != cur.cts)))
- return 0;
- }
- return 0;
-}
-
-static int ssu100_get_icount(struct tty_struct *tty,
- struct serial_icounter_struct *icount)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct ssu100_port_private *priv = usb_get_serial_port_data(port);
- struct async_icount cnow = priv->icount;
-
- icount->cts = cnow.cts;
- icount->dsr = cnow.dsr;
- icount->rng = cnow.rng;
- icount->dcd = cnow.dcd;
- icount->rx = cnow.rx;
- icount->tx = cnow.tx;
- icount->frame = cnow.frame;
- icount->overrun = cnow.overrun;
- icount->parity = cnow.parity;
- icount->brk = cnow.brk;
- icount->buf_overrun = cnow.buf_overrun;
-
- return 0;
-}
-
-
-
static int ssu100_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(&port->dev, "%s cmd 0x%04x\n", __func__, cmd);
-
switch (cmd) {
case TIOCGSERIAL:
return get_serial_info(port,
(struct serial_struct __user *) arg);
-
- case TIOCMIWAIT:
- return wait_modem_info(port, arg);
-
default:
break;
}
- dev_dbg(&port->dev, "%s arg not supported\n", __func__);
-
return -ENOIOCTLCMD;
}
@@ -445,7 +366,6 @@ static int ssu100_port_probe(struct usb_serial_port *port)
return -ENOMEM;
spin_lock_init(&priv->status_lock);
- init_waitqueue_head(&priv->delta_msr_wait);
usb_set_serial_port_data(port, priv);
@@ -506,19 +426,16 @@ static void ssu100_dtr_rts(struct usb_serial_port *port, int on)
{
struct usb_device *dev = port->serial->dev;
- mutex_lock(&port->serial->disc_mutex);
- if (!port->serial->disconnected) {
- /* Disable flow control */
- if (!on &&
- ssu100_setregister(dev, 0, UART_MCR, 0) < 0)
+ /* Disable flow control */
+ if (!on) {
+ if (ssu100_setregister(dev, 0, UART_MCR, 0) < 0)
dev_err(&port->dev, "error from flowcontrol urb\n");
- /* drop RTS and DTR */
- if (on)
- set_mctrl(dev, TIOCM_DTR | TIOCM_RTS);
- else
- clear_mctrl(dev, TIOCM_DTR | TIOCM_RTS);
}
- mutex_unlock(&port->serial->disc_mutex);
+ /* drop RTS and DTR */
+ if (on)
+ set_mctrl(dev, TIOCM_DTR | TIOCM_RTS);
+ else
+ clear_mctrl(dev, TIOCM_DTR | TIOCM_RTS);
}
static void ssu100_update_msr(struct usb_serial_port *port, u8 msr)
@@ -533,14 +450,14 @@ static void ssu100_update_msr(struct usb_serial_port *port, u8 msr)
if (msr & UART_MSR_ANY_DELTA) {
/* update input line counters */
if (msr & UART_MSR_DCTS)
- priv->icount.cts++;
+ port->icount.cts++;
if (msr & UART_MSR_DDSR)
- priv->icount.dsr++;
+ port->icount.dsr++;
if (msr & UART_MSR_DDCD)
- priv->icount.dcd++;
+ port->icount.dcd++;
if (msr & UART_MSR_TERI)
- priv->icount.rng++;
- wake_up_interruptible(&priv->delta_msr_wait);
+ port->icount.rng++;
+ wake_up_interruptible(&port->port.delta_msr_wait);
}
}
@@ -559,22 +476,22 @@ static void ssu100_update_lsr(struct usb_serial_port *port, u8 lsr,
/* we always want to update icount, but we only want to
* update tty_flag for one case */
if (lsr & UART_LSR_BI) {
- priv->icount.brk++;
+ port->icount.brk++;
*tty_flag = TTY_BREAK;
usb_serial_handle_break(port);
}
if (lsr & UART_LSR_PE) {
- priv->icount.parity++;
+ port->icount.parity++;
if (*tty_flag == TTY_NORMAL)
*tty_flag = TTY_PARITY;
}
if (lsr & UART_LSR_FE) {
- priv->icount.frame++;
+ port->icount.frame++;
if (*tty_flag == TTY_NORMAL)
*tty_flag = TTY_FRAME;
}
if (lsr & UART_LSR_OE){
- priv->icount.overrun++;
+ port->icount.overrun++;
if (*tty_flag == TTY_NORMAL)
*tty_flag = TTY_OVERRUN;
}
@@ -582,8 +499,7 @@ static void ssu100_update_lsr(struct usb_serial_port *port, u8 lsr,
}
-static int ssu100_process_packet(struct urb *urb,
- struct tty_struct *tty)
+static void ssu100_process_read_urb(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
char *packet = (char *)urb->transfer_buffer;
@@ -598,7 +514,8 @@ static int ssu100_process_packet(struct urb *urb,
if (packet[2] == 0x00) {
ssu100_update_lsr(port, packet[3], &flag);
if (flag == TTY_OVERRUN)
- tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+ tty_insert_flip_char(&port->port, 0,
+ TTY_OVERRUN);
}
if (packet[2] == 0x01)
ssu100_update_msr(port, packet[3]);
@@ -609,34 +526,17 @@ static int ssu100_process_packet(struct urb *urb,
ch = packet;
if (!len)
- return 0; /* status only */
+ return; /* status only */
if (port->port.console && port->sysrq) {
for (i = 0; i < len; i++, ch++) {
if (!usb_serial_handle_sysrq_char(port, *ch))
- tty_insert_flip_char(tty, *ch, flag);
+ tty_insert_flip_char(&port->port, *ch, flag);
}
} else
- tty_insert_flip_string_fixed_flag(tty, ch, flag, len);
-
- return len;
-}
-
-static void ssu100_process_read_urb(struct urb *urb)
-{
- struct usb_serial_port *port = urb->context;
- struct tty_struct *tty;
- int count;
-
- tty = tty_port_tty_get(&port->port);
- if (!tty)
- return;
-
- count = ssu100_process_packet(urb, tty);
+ tty_insert_flip_string_fixed_flag(&port->port, ch, flag, len);
- if (count)
- tty_flip_buffer_push(tty);
- tty_kref_put(tty);
+ tty_flip_buffer_push(&port->port);
}
static struct usb_serial_driver ssu100_device = {
@@ -648,7 +548,6 @@ static struct usb_serial_driver ssu100_device = {
.id_table = id_table,
.num_ports = 1,
.open = ssu100_open,
- .close = ssu100_close,
.attach = ssu100_attach,
.port_probe = ssu100_port_probe,
.port_remove = ssu100_port_remove,
@@ -656,10 +555,10 @@ static struct usb_serial_driver ssu100_device = {
.process_read_urb = ssu100_process_read_urb,
.tiocmget = ssu100_tiocmget,
.tiocmset = ssu100_tiocmset,
- .get_icount = ssu100_get_icount,
+ .tiocmiwait = usb_serial_generic_tiocmiwait,
+ .get_icount = usb_serial_generic_get_icount,
.ioctl = ssu100_ioctl,
.set_termios = ssu100_set_termios,
- .disconnect = usb_serial_generic_disconnect,
};
static struct usb_serial_driver * const serial_drivers[] = {
diff --git a/drivers/usb/serial/symbolserial.c b/drivers/usb/serial/symbolserial.c
index 701fffa8431..8fceec7298e 100644
--- a/drivers/usb/serial/symbolserial.c
+++ b/drivers/usb/serial/symbolserial.c
@@ -1,6 +1,7 @@
/*
* Symbol USB barcode to serial driver
*
+ * Copyright (C) 2013 Johan Hovold <jhovold@gmail.com>
* Copyright (C) 2009 Greg Kroah-Hartman <gregkh@suse.de>
* Copyright (C) 2009 Novell Inc.
*
@@ -10,7 +11,6 @@
*/
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/tty_driver.h>
@@ -26,29 +26,18 @@ static const struct usb_device_id id_table[] = {
};
MODULE_DEVICE_TABLE(usb, id_table);
-/* This structure holds all of the individual device information */
struct symbol_private {
- struct usb_device *udev;
- struct usb_serial *serial;
- struct usb_serial_port *port;
- unsigned char *int_buffer;
- struct urb *int_urb;
- int buffer_size;
- u8 bInterval;
- u8 int_address;
spinlock_t lock; /* protects the following flags */
bool throttled;
bool actually_throttled;
- bool rts;
};
static void symbol_int_callback(struct urb *urb)
{
- struct symbol_private *priv = urb->context;
+ struct usb_serial_port *port = urb->context;
+ struct symbol_private *priv = usb_get_serial_port_data(port);
unsigned char *data = urb->transfer_buffer;
- struct usb_serial_port *port = priv->port;
int status = urb->status;
- struct tty_struct *tty;
int result;
int data_length;
@@ -82,16 +71,10 @@ static void symbol_int_callback(struct urb *urb)
* we pretty much just ignore the size and send everything
* else to the tty layer.
*/
- tty = tty_port_tty_get(&port->port);
- if (tty) {
- tty_insert_flip_string(tty, &data[1], data_length);
- tty_flip_buffer_push(tty);
- tty_kref_put(tty);
- }
+ tty_insert_flip_string(&port->port, &data[1], data_length);
+ tty_flip_buffer_push(&port->port);
} else {
- dev_dbg(&priv->udev->dev,
- "Improper amount of data received from the device, "
- "%d bytes", urb->actual_length);
+ dev_dbg(&port->dev, "%s - short packet\n", __func__);
}
exit:
@@ -99,12 +82,7 @@ exit:
/* Continue trying to always read if we should */
if (!priv->throttled) {
- usb_fill_int_urb(priv->int_urb, priv->udev,
- usb_rcvintpipe(priv->udev,
- priv->int_address),
- priv->int_buffer, priv->buffer_size,
- symbol_int_callback, priv, priv->bInterval);
- result = usb_submit_urb(priv->int_urb, GFP_ATOMIC);
+ result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
if (result)
dev_err(&port->dev,
"%s - failed resubmitting read urb, error %d\n",
@@ -123,15 +101,10 @@ static int symbol_open(struct tty_struct *tty, struct usb_serial_port *port)
spin_lock_irqsave(&priv->lock, flags);
priv->throttled = false;
priv->actually_throttled = false;
- priv->port = port;
spin_unlock_irqrestore(&priv->lock, flags);
/* Start reading from the device */
- usb_fill_int_urb(priv->int_urb, priv->udev,
- usb_rcvintpipe(priv->udev, priv->int_address),
- priv->int_buffer, priv->buffer_size,
- symbol_int_callback, priv, priv->bInterval);
- result = usb_submit_urb(priv->int_urb, GFP_KERNEL);
+ result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (result)
dev_err(&port->dev,
"%s - failed resubmitting read urb, error %d\n",
@@ -141,10 +114,7 @@ static int symbol_open(struct tty_struct *tty, struct usb_serial_port *port)
static void symbol_close(struct usb_serial_port *port)
{
- struct symbol_private *priv = usb_get_serial_data(port->serial);
-
- /* shutdown our urbs */
- usb_kill_urb(priv->int_urb);
+ usb_kill_urb(port->interrupt_in_urb);
}
static void symbol_throttle(struct tty_struct *tty)
@@ -171,7 +141,7 @@ static void symbol_unthrottle(struct tty_struct *tty)
spin_unlock_irq(&priv->lock);
if (was_throttled) {
- result = usb_submit_urb(priv->int_urb, GFP_KERNEL);
+ result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (result)
dev_err(&port->dev,
"%s - failed submitting read urb, error %d\n",
@@ -181,89 +151,36 @@ static void symbol_unthrottle(struct tty_struct *tty)
static int symbol_startup(struct usb_serial *serial)
{
+ if (!serial->num_interrupt_in) {
+ dev_err(&serial->dev->dev, "no interrupt-in endpoint\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int symbol_port_probe(struct usb_serial_port *port)
+{
struct symbol_private *priv;
- struct usb_host_interface *intf;
- int i;
- int retval = -ENOMEM;
- bool int_in_found = false;
- /* create our private serial structure */
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- if (priv == NULL) {
- dev_err(&serial->dev->dev, "%s - Out of memory\n", __func__);
+ if (!priv)
return -ENOMEM;
- }
+
spin_lock_init(&priv->lock);
- priv->serial = serial;
- priv->port = serial->port[0];
- priv->udev = serial->dev;
-
- /* find our interrupt endpoint */
- intf = serial->interface->altsetting;
- for (i = 0; i < intf->desc.bNumEndpoints; ++i) {
- struct usb_endpoint_descriptor *endpoint;
-
- endpoint = &intf->endpoint[i].desc;
- if (!usb_endpoint_is_int_in(endpoint))
- continue;
-
- priv->int_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!priv->int_urb) {
- dev_err(&priv->udev->dev, "out of memory\n");
- goto error;
- }
-
- priv->buffer_size = usb_endpoint_maxp(endpoint) * 2;
- priv->int_buffer = kmalloc(priv->buffer_size, GFP_KERNEL);
- if (!priv->int_buffer) {
- dev_err(&priv->udev->dev, "out of memory\n");
- goto error;
- }
-
- priv->int_address = endpoint->bEndpointAddress;
- priv->bInterval = endpoint->bInterval;
-
- /* set up our int urb */
- usb_fill_int_urb(priv->int_urb, priv->udev,
- usb_rcvintpipe(priv->udev,
- endpoint->bEndpointAddress),
- priv->int_buffer, priv->buffer_size,
- symbol_int_callback, priv, priv->bInterval);
-
- int_in_found = true;
- break;
- }
- if (!int_in_found) {
- dev_err(&priv->udev->dev,
- "Error - the proper endpoints were not found!\n");
- goto error;
- }
+ usb_set_serial_port_data(port, priv);
- usb_set_serial_data(serial, priv);
return 0;
-
-error:
- usb_free_urb(priv->int_urb);
- kfree(priv->int_buffer);
- kfree(priv);
- return retval;
-}
-
-static void symbol_disconnect(struct usb_serial *serial)
-{
- struct symbol_private *priv = usb_get_serial_data(serial);
-
- usb_kill_urb(priv->int_urb);
- usb_free_urb(priv->int_urb);
}
-static void symbol_release(struct usb_serial *serial)
+static int symbol_port_remove(struct usb_serial_port *port)
{
- struct symbol_private *priv = usb_get_serial_data(serial);
+ struct symbol_private *priv = usb_get_serial_port_data(port);
- kfree(priv->int_buffer);
kfree(priv);
+
+ return 0;
}
static struct usb_serial_driver symbol_device = {
@@ -274,12 +191,13 @@ static struct usb_serial_driver symbol_device = {
.id_table = id_table,
.num_ports = 1,
.attach = symbol_startup,
+ .port_probe = symbol_port_probe,
+ .port_remove = symbol_port_remove,
.open = symbol_open,
.close = symbol_close,
- .disconnect = symbol_disconnect,
- .release = symbol_release,
.throttle = symbol_throttle,
.unthrottle = symbol_unthrottle,
+ .read_int_callback = symbol_int_callback,
};
static struct usb_serial_driver * const serial_drivers[] = {
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index f2530d2ef3c..3dd3ff8c50d 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -21,7 +21,6 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/firmware.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
@@ -45,8 +44,6 @@
#define TI_FIRMWARE_BUF_SIZE 16284
-#define TI_WRITE_BUF_SIZE 1024
-
#define TI_TRANSFER_TIMEOUT 2
#define TI_DEFAULT_CLOSING_WAIT 4000 /* in .01 secs */
@@ -67,21 +64,15 @@
struct ti_port {
int tp_is_open;
__u8 tp_msr;
- __u8 tp_lsr;
__u8 tp_shadow_mcr;
__u8 tp_uart_mode; /* 232 or 485 modes */
unsigned int tp_uart_base_addr;
int tp_flags;
- int tp_closing_wait;/* in .01 secs */
- struct async_icount tp_icount;
- wait_queue_head_t tp_msr_wait; /* wait for msr change */
- wait_queue_head_t tp_write_wait;
struct ti_device *tp_tdev;
struct usb_serial_port *tp_port;
spinlock_t tp_lock;
int tp_read_urb_state;
int tp_write_urb_in_use;
- struct kfifo write_fifo;
};
struct ti_device {
@@ -105,12 +96,11 @@ static int ti_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *data, int count);
static int ti_write_room(struct tty_struct *tty);
static int ti_chars_in_buffer(struct tty_struct *tty);
+static bool ti_tx_empty(struct usb_serial_port *port);
static void ti_throttle(struct tty_struct *tty);
static void ti_unthrottle(struct tty_struct *tty);
static int ti_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg);
-static int ti_get_icount(struct tty_struct *tty,
- struct serial_icounter_struct *icount);
static void ti_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios);
static int ti_tiocmget(struct tty_struct *tty);
@@ -121,19 +111,17 @@ static void ti_interrupt_callback(struct urb *urb);
static void ti_bulk_in_callback(struct urb *urb);
static void ti_bulk_out_callback(struct urb *urb);
-static void ti_recv(struct device *dev, struct tty_struct *tty,
- unsigned char *data, int length);
+static void ti_recv(struct usb_serial_port *port, unsigned char *data,
+ int length);
static void ti_send(struct ti_port *tport);
static int ti_set_mcr(struct ti_port *tport, unsigned int mcr);
-static int ti_get_lsr(struct ti_port *tport);
+static int ti_get_lsr(struct ti_port *tport, u8 *lsr);
static int ti_get_serial_info(struct ti_port *tport,
struct serial_struct __user *ret_arg);
static int ti_set_serial_info(struct tty_struct *tty, struct ti_port *tport,
struct serial_struct __user *new_arg);
static void ti_handle_new_msr(struct ti_port *tport, __u8 msr);
-static void ti_drain(struct ti_port *tport, unsigned long timeout, int flush);
-
static void ti_stop_read(struct ti_port *tport, struct tty_struct *tty);
static int ti_restart_read(struct ti_port *tport, struct tty_struct *tty);
@@ -152,20 +140,9 @@ static int ti_download_firmware(struct ti_device *tdev);
/* module parameters */
static int closing_wait = TI_DEFAULT_CLOSING_WAIT;
-static ushort vendor_3410[TI_EXTRA_VID_PID_COUNT];
-static unsigned int vendor_3410_count;
-static ushort product_3410[TI_EXTRA_VID_PID_COUNT];
-static unsigned int product_3410_count;
-static ushort vendor_5052[TI_EXTRA_VID_PID_COUNT];
-static unsigned int vendor_5052_count;
-static ushort product_5052[TI_EXTRA_VID_PID_COUNT];
-static unsigned int product_5052_count;
/* supported devices */
-/* the array dimension is the number of default entries plus */
-/* TI_EXTRA_VID_PID_COUNT user defined entries plus 1 terminating */
-/* null entry */
-static struct usb_device_id ti_id_table_3410[15+TI_EXTRA_VID_PID_COUNT+1] = {
+static const struct usb_device_id ti_id_table_3410[] = {
{ USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) },
{ USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) },
{ USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) },
@@ -179,18 +156,21 @@ static struct usb_device_id ti_id_table_3410[15+TI_EXTRA_VID_PID_COUNT+1] = {
{ USB_DEVICE(IBM_VENDOR_ID, IBM_4543_PRODUCT_ID) },
{ USB_DEVICE(IBM_VENDOR_ID, IBM_454B_PRODUCT_ID) },
{ USB_DEVICE(IBM_VENDOR_ID, IBM_454C_PRODUCT_ID) },
- { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_PRODUCT_ID) },
+ { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STEREO_PLUG_ID) },
+ { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STRIP_PORT_ID) },
{ USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) },
+ { } /* terminator */
};
-static struct usb_device_id ti_id_table_5052[5+TI_EXTRA_VID_PID_COUNT+1] = {
+static const struct usb_device_id ti_id_table_5052[] = {
{ USB_DEVICE(TI_VENDOR_ID, TI_5052_BOOT_PRODUCT_ID) },
{ USB_DEVICE(TI_VENDOR_ID, TI_5152_BOOT_PRODUCT_ID) },
{ USB_DEVICE(TI_VENDOR_ID, TI_5052_EEPROM_PRODUCT_ID) },
{ USB_DEVICE(TI_VENDOR_ID, TI_5052_FIRMWARE_PRODUCT_ID) },
+ { } /* terminator */
};
-static struct usb_device_id ti_id_table_combined[19+2*TI_EXTRA_VID_PID_COUNT+1] = {
+static const struct usb_device_id ti_id_table_combined[] = {
{ USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) },
{ USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) },
{ USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) },
@@ -209,8 +189,9 @@ static struct usb_device_id ti_id_table_combined[19+2*TI_EXTRA_VID_PID_COUNT+1]
{ USB_DEVICE(IBM_VENDOR_ID, IBM_454B_PRODUCT_ID) },
{ USB_DEVICE(IBM_VENDOR_ID, IBM_454C_PRODUCT_ID) },
{ USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_PRODUCT_ID) },
+ { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STRIP_PORT_ID) },
{ USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) },
- { }
+ { } /* terminator */
};
static struct usb_serial_driver ti_1port_device = {
@@ -230,13 +211,15 @@ static struct usb_serial_driver ti_1port_device = {
.write = ti_write,
.write_room = ti_write_room,
.chars_in_buffer = ti_chars_in_buffer,
+ .tx_empty = ti_tx_empty,
.throttle = ti_throttle,
.unthrottle = ti_unthrottle,
.ioctl = ti_ioctl,
.set_termios = ti_set_termios,
.tiocmget = ti_tiocmget,
.tiocmset = ti_tiocmset,
- .get_icount = ti_get_icount,
+ .tiocmiwait = usb_serial_generic_tiocmiwait,
+ .get_icount = usb_serial_generic_get_icount,
.break_ctl = ti_break,
.read_int_callback = ti_interrupt_callback,
.read_bulk_callback = ti_bulk_in_callback,
@@ -260,13 +243,15 @@ static struct usb_serial_driver ti_2port_device = {
.write = ti_write,
.write_room = ti_write_room,
.chars_in_buffer = ti_chars_in_buffer,
+ .tx_empty = ti_tx_empty,
.throttle = ti_throttle,
.unthrottle = ti_unthrottle,
.ioctl = ti_ioctl,
.set_termios = ti_set_termios,
.tiocmget = ti_tiocmget,
.tiocmset = ti_tiocmset,
- .get_icount = ti_get_icount,
+ .tiocmiwait = usb_serial_generic_tiocmiwait,
+ .get_icount = usb_serial_generic_get_icount,
.break_ctl = ti_break,
.read_int_callback = ti_interrupt_callback,
.read_bulk_callback = ti_bulk_in_callback,
@@ -295,61 +280,12 @@ module_param(closing_wait, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(closing_wait,
"Maximum wait for data to drain in close, in .01 secs, default is 4000");
-module_param_array(vendor_3410, ushort, &vendor_3410_count, S_IRUGO);
-MODULE_PARM_DESC(vendor_3410,
- "Vendor ids for 3410 based devices, 1-5 short integers");
-module_param_array(product_3410, ushort, &product_3410_count, S_IRUGO);
-MODULE_PARM_DESC(product_3410,
- "Product ids for 3410 based devices, 1-5 short integers");
-module_param_array(vendor_5052, ushort, &vendor_5052_count, S_IRUGO);
-MODULE_PARM_DESC(vendor_5052,
- "Vendor ids for 5052 based devices, 1-5 short integers");
-module_param_array(product_5052, ushort, &product_5052_count, S_IRUGO);
-MODULE_PARM_DESC(product_5052,
- "Product ids for 5052 based devices, 1-5 short integers");
-
MODULE_DEVICE_TABLE(usb, ti_id_table_combined);
+module_usb_serial_driver(serial_drivers, ti_id_table_combined);
/* Functions */
-static int __init ti_init(void)
-{
- int i, j, c;
-
- /* insert extra vendor and product ids */
- c = ARRAY_SIZE(ti_id_table_combined) - 2 * TI_EXTRA_VID_PID_COUNT - 1;
- j = ARRAY_SIZE(ti_id_table_3410) - TI_EXTRA_VID_PID_COUNT - 1;
- for (i = 0; i < min(vendor_3410_count, product_3410_count); i++, j++, c++) {
- ti_id_table_3410[j].idVendor = vendor_3410[i];
- ti_id_table_3410[j].idProduct = product_3410[i];
- ti_id_table_3410[j].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
- ti_id_table_combined[c].idVendor = vendor_3410[i];
- ti_id_table_combined[c].idProduct = product_3410[i];
- ti_id_table_combined[c].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
- }
- j = ARRAY_SIZE(ti_id_table_5052) - TI_EXTRA_VID_PID_COUNT - 1;
- for (i = 0; i < min(vendor_5052_count, product_5052_count); i++, j++, c++) {
- ti_id_table_5052[j].idVendor = vendor_5052[i];
- ti_id_table_5052[j].idProduct = product_5052[i];
- ti_id_table_5052[j].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
- ti_id_table_combined[c].idVendor = vendor_5052[i];
- ti_id_table_combined[c].idProduct = product_5052[i];
- ti_id_table_combined[c].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
- }
-
- return usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, ti_id_table_combined);
-}
-
-static void __exit ti_exit(void)
-{
- usb_serial_deregister_drivers(serial_drivers);
-}
-
-module_init(ti_init);
-module_exit(ti_exit);
-
-
static int ti_startup(struct usb_serial *serial)
{
struct ti_device *tdev;
@@ -357,23 +293,22 @@ static int ti_startup(struct usb_serial *serial)
int status;
dev_dbg(&dev->dev,
- "%s - product 0x%4X, num configurations %d, configuration value %d",
+ "%s - product 0x%4X, num configurations %d, configuration value %d\n",
__func__, le16_to_cpu(dev->descriptor.idProduct),
dev->descriptor.bNumConfigurations,
dev->actconfig->desc.bConfigurationValue);
/* create device structure */
tdev = kzalloc(sizeof(struct ti_device), GFP_KERNEL);
- if (tdev == NULL) {
- dev_err(&dev->dev, "%s - out of memory\n", __func__);
+ if (!tdev)
return -ENOMEM;
- }
+
mutex_init(&tdev->td_open_close_lock);
tdev->td_serial = serial;
usb_set_serial_data(serial, tdev);
/* determine device type */
- if (usb_match_id(serial->interface, ti_id_table_3410))
+ if (serial->type == &ti_1port_device)
tdev->td_is_3410 = 1;
dev_dbg(&dev->dev, "%s - device type is %s\n", __func__,
tdev->td_is_3410 ? "3410" : "5052");
@@ -431,19 +366,15 @@ static int ti_port_probe(struct usb_serial_port *port)
tport->tp_uart_base_addr = TI_UART1_BASE_ADDR;
else
tport->tp_uart_base_addr = TI_UART2_BASE_ADDR;
- tport->tp_closing_wait = closing_wait;
- init_waitqueue_head(&tport->tp_msr_wait);
- init_waitqueue_head(&tport->tp_write_wait);
- if (kfifo_alloc(&tport->write_fifo, TI_WRITE_BUF_SIZE, GFP_KERNEL)) {
- kfree(tport);
- return -ENOMEM;
- }
+ port->port.closing_wait = msecs_to_jiffies(10 * closing_wait);
tport->tp_port = port;
tport->tp_tdev = usb_get_serial_data(port->serial);
tport->tp_uart_mode = 0; /* default is RS232 */
usb_set_serial_port_data(port, tport);
+ port->port.drain_delay = 3;
+
return 0;
}
@@ -452,7 +383,6 @@ static int ti_port_remove(struct usb_serial_port *port)
struct ti_port *tport;
tport = usb_get_serial_port_data(port);
- kfifo_free(&tport->write_fifo);
kfree(tport);
return 0;
@@ -480,9 +410,7 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port)
if (mutex_lock_interruptible(&tdev->td_open_close_lock))
return -ERESTARTSYS;
- port_number = port->number - port->serial->minor;
-
- memset(&(tport->tp_icount), 0x00, sizeof(tport->tp_icount));
+ port_number = port->port_number;
tport->tp_msr = 0;
tport->tp_shadow_mcr |= (TI_MCR_RTS | TI_MCR_DTR);
@@ -606,6 +534,7 @@ static void ti_close(struct usb_serial_port *port)
int port_number;
int status;
int do_unlock;
+ unsigned long flags;
tdev = usb_get_serial_data(port->serial);
tport = usb_get_serial_port_data(port);
@@ -614,13 +543,14 @@ static void ti_close(struct usb_serial_port *port)
tport->tp_is_open = 0;
- ti_drain(tport, (tport->tp_closing_wait*HZ)/100, 1);
-
usb_kill_urb(port->read_urb);
usb_kill_urb(port->write_urb);
tport->tp_write_urb_in_use = 0;
+ spin_lock_irqsave(&tport->tp_lock, flags);
+ kfifo_reset_out(&port->write_fifo);
+ spin_unlock_irqrestore(&tport->tp_lock, flags);
- port_number = port->number - port->serial->minor;
+ port_number = port->port_number;
dev_dbg(&port->dev, "%s - sending TI_CLOSE_PORT\n", __func__);
status = ti_command_out_sync(tdev, TI_CLOSE_PORT,
@@ -656,7 +586,7 @@ static int ti_write(struct tty_struct *tty, struct usb_serial_port *port,
if (tport == NULL || !tport->tp_is_open)
return -ENODEV;
- count = kfifo_in_locked(&tport->write_fifo, data, count,
+ count = kfifo_in_locked(&port->write_fifo, data, count,
&tport->tp_lock);
ti_send(tport);
@@ -675,7 +605,7 @@ static int ti_write_room(struct tty_struct *tty)
return 0;
spin_lock_irqsave(&tport->tp_lock, flags);
- room = kfifo_avail(&tport->write_fifo);
+ room = kfifo_avail(&port->write_fifo);
spin_unlock_irqrestore(&tport->tp_lock, flags);
dev_dbg(&port->dev, "%s - returns %d\n", __func__, room);
@@ -694,13 +624,25 @@ static int ti_chars_in_buffer(struct tty_struct *tty)
return 0;
spin_lock_irqsave(&tport->tp_lock, flags);
- chars = kfifo_len(&tport->write_fifo);
+ chars = kfifo_len(&port->write_fifo);
spin_unlock_irqrestore(&tport->tp_lock, flags);
dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars);
return chars;
}
+static bool ti_tx_empty(struct usb_serial_port *port)
+{
+ struct ti_port *tport = usb_get_serial_port_data(port);
+ int ret;
+ u8 lsr;
+
+ ret = ti_get_lsr(tport, &lsr);
+ if (!ret && !(lsr & TI_LSR_TX_EMPTY))
+ return false;
+
+ return true;
+}
static void ti_throttle(struct tty_struct *tty)
{
@@ -733,40 +675,11 @@ static void ti_unthrottle(struct tty_struct *tty)
}
}
-static int ti_get_icount(struct tty_struct *tty,
- struct serial_icounter_struct *icount)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct ti_port *tport = usb_get_serial_port_data(port);
- struct async_icount cnow = tport->tp_icount;
-
- dev_dbg(&port->dev, "%s - TIOCGICOUNT RX=%d, TX=%d\n", __func__,
- cnow.rx, cnow.tx);
-
- icount->cts = cnow.cts;
- icount->dsr = cnow.dsr;
- icount->rng = cnow.rng;
- icount->dcd = cnow.dcd;
- icount->rx = cnow.rx;
- icount->tx = cnow.tx;
- icount->frame = cnow.frame;
- icount->overrun = cnow.overrun;
- icount->parity = cnow.parity;
- icount->brk = cnow.brk;
- icount->buf_overrun = cnow.buf_overrun;
-
- return 0;
-}
-
static int ti_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
struct usb_serial_port *port = tty->driver_data;
struct ti_port *tport = usb_get_serial_port_data(port);
- struct async_icount cnow;
- struct async_icount cprev;
-
- dev_dbg(&port->dev, "%s - cmd = 0x%04X\n", __func__, cmd);
if (tport == NULL)
return -ENODEV;
@@ -780,25 +693,6 @@ static int ti_ioctl(struct tty_struct *tty,
dev_dbg(&port->dev, "%s - TIOCSSERIAL\n", __func__);
return ti_set_serial_info(tty, tport,
(struct serial_struct __user *)arg);
- case TIOCMIWAIT:
- dev_dbg(&port->dev, "%s - TIOCMIWAIT\n", __func__);
- cprev = tport->tp_icount;
- while (1) {
- interruptible_sleep_on(&tport->tp_msr_wait);
- if (signal_pending(current))
- return -ERESTARTSYS;
- cnow = tport->tp_icount;
- if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
- cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
- return -EIO; /* no change => error */
- if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
- ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
- ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
- ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)))
- return 0;
- cprev = cnow;
- }
- break;
}
return -ENOIOCTLCMD;
}
@@ -812,7 +706,7 @@ static void ti_set_termios(struct tty_struct *tty,
tcflag_t cflag, iflag;
int baud;
int status;
- int port_number = port->number - port->serial->minor;
+ int port_number = port->port_number;
unsigned int mcr;
cflag = tty->termios.c_cflag;
@@ -826,10 +720,8 @@ static void ti_set_termios(struct tty_struct *tty,
return;
config = kmalloc(sizeof(*config), GFP_KERNEL);
- if (!config) {
- dev_err(&port->dev, "%s - out of memory\n", __func__);
+ if (!config)
return;
- }
config->wFlags = 0;
@@ -911,7 +803,7 @@ static void ti_set_termios(struct tty_struct *tty,
tty_encode_baud_rate(tty, baud, baud);
dev_dbg(&port->dev,
- "%s - BaudRate=%d, wBaudRate=%d, wFlags=0x%04X, bDataBits=%d, bParity=%d, bStopBits=%d, cXon=%d, cXoff=%d, bUartMode=%d",
+ "%s - BaudRate=%d, wBaudRate=%d, wFlags=0x%04X, bDataBits=%d, bParity=%d, bStopBits=%d, cXon=%d, cXoff=%d, bUartMode=%d\n",
__func__, baud, config->wBaudRate, config->wFlags,
config->bDataBits, config->bParity, config->bStopBits,
config->cXon, config->cXoff, config->bUartMode);
@@ -1016,8 +908,6 @@ static void ti_break(struct tty_struct *tty, int break_state)
if (tport == NULL)
return;
- ti_drain(tport, (tport->tp_closing_wait*HZ)/100, 0);
-
status = ti_write_byte(port, tport->tp_tdev,
tport->tp_uart_base_addr + TI_UART_OFFSET_LCR,
TI_LCR_BREAK, break_state == -1 ? TI_LCR_BREAK : 0);
@@ -1118,7 +1008,6 @@ static void ti_bulk_in_callback(struct urb *urb)
struct device *dev = &urb->dev->dev;
int status = urb->status;
int retval = 0;
- struct tty_struct *tty;
switch (status) {
case 0:
@@ -1128,13 +1017,11 @@ static void ti_bulk_in_callback(struct urb *urb)
case -ESHUTDOWN:
dev_dbg(dev, "%s - urb shutting down, %d\n", __func__, status);
tport->tp_tdev->td_urb_error = 1;
- wake_up_interruptible(&tport->tp_write_wait);
return;
default:
dev_err(dev, "%s - nonzero urb status, %d\n",
__func__, status);
tport->tp_tdev->td_urb_error = 1;
- wake_up_interruptible(&tport->tp_write_wait);
}
if (status == -EPIPE)
@@ -1145,24 +1032,18 @@ static void ti_bulk_in_callback(struct urb *urb)
return;
}
- tty = tty_port_tty_get(&port->port);
- if (tty) {
- if (urb->actual_length) {
- usb_serial_debug_data(dev, __func__, urb->actual_length,
- urb->transfer_buffer);
+ if (urb->actual_length) {
+ usb_serial_debug_data(dev, __func__, urb->actual_length,
+ urb->transfer_buffer);
- if (!tport->tp_is_open)
- dev_dbg(dev, "%s - port closed, dropping data\n",
- __func__);
- else
- ti_recv(&urb->dev->dev, tty,
- urb->transfer_buffer,
- urb->actual_length);
- spin_lock(&tport->tp_lock);
- tport->tp_icount.rx += urb->actual_length;
- spin_unlock(&tport->tp_lock);
- }
- tty_kref_put(tty);
+ if (!tport->tp_is_open)
+ dev_dbg(dev, "%s - port closed, dropping data\n",
+ __func__);
+ else
+ ti_recv(port, urb->transfer_buffer, urb->actual_length);
+ spin_lock(&tport->tp_lock);
+ port->icount.rx += urb->actual_length;
+ spin_unlock(&tport->tp_lock);
}
exit:
@@ -1196,13 +1077,11 @@ static void ti_bulk_out_callback(struct urb *urb)
case -ESHUTDOWN:
dev_dbg(&port->dev, "%s - urb shutting down, %d\n", __func__, status);
tport->tp_tdev->td_urb_error = 1;
- wake_up_interruptible(&tport->tp_write_wait);
return;
default:
dev_err_console(port, "%s - nonzero urb status, %d\n",
__func__, status);
tport->tp_tdev->td_urb_error = 1;
- wake_up_interruptible(&tport->tp_write_wait);
}
/* send any buffered data */
@@ -1210,24 +1089,23 @@ static void ti_bulk_out_callback(struct urb *urb)
}
-static void ti_recv(struct device *dev, struct tty_struct *tty,
- unsigned char *data, int length)
+static void ti_recv(struct usb_serial_port *port, unsigned char *data,
+ int length)
{
int cnt;
do {
- cnt = tty_insert_flip_string(tty, data, length);
+ cnt = tty_insert_flip_string(&port->port, data, length);
if (cnt < length) {
- dev_err(dev, "%s - dropping data, %d bytes lost\n",
+ dev_err(&port->dev, "%s - dropping data, %d bytes lost\n",
__func__, length - cnt);
if (cnt == 0)
break;
}
- tty_flip_buffer_push(tty);
+ tty_flip_buffer_push(&port->port);
data += cnt;
length -= cnt;
} while (length > 0);
-
}
@@ -1235,7 +1113,6 @@ static void ti_send(struct ti_port *tport)
{
int count, result;
struct usb_serial_port *port = tport->tp_port;
- struct tty_struct *tty = tty_port_tty_get(&port->port); /* FIXME */
unsigned long flags;
spin_lock_irqsave(&tport->tp_lock, flags);
@@ -1243,7 +1120,7 @@ static void ti_send(struct ti_port *tport)
if (tport->tp_write_urb_in_use)
goto unlock;
- count = kfifo_out(&tport->write_fifo,
+ count = kfifo_out(&port->write_fifo,
port->write_urb->transfer_buffer,
port->bulk_out_size);
@@ -1271,19 +1148,16 @@ static void ti_send(struct ti_port *tport)
/* TODO: reschedule ti_send */
} else {
spin_lock_irqsave(&tport->tp_lock, flags);
- tport->tp_icount.tx += count;
+ port->icount.tx += count;
spin_unlock_irqrestore(&tport->tp_lock, flags);
}
/* more room in the buffer for new writes, wakeup */
- if (tty)
- tty_wakeup(tty);
- tty_kref_put(tty);
- wake_up_interruptible(&tport->tp_write_wait);
+ tty_port_tty_wakeup(&port->port);
+
return;
unlock:
spin_unlock_irqrestore(&tport->tp_lock, flags);
- tty_kref_put(tty);
return;
}
@@ -1306,20 +1180,18 @@ static int ti_set_mcr(struct ti_port *tport, unsigned int mcr)
}
-static int ti_get_lsr(struct ti_port *tport)
+static int ti_get_lsr(struct ti_port *tport, u8 *lsr)
{
int size, status;
struct ti_device *tdev = tport->tp_tdev;
struct usb_serial_port *port = tport->tp_port;
- int port_number = port->number - port->serial->minor;
+ int port_number = port->port_number;
struct ti_port_status *data;
size = sizeof(struct ti_port_status);
data = kmalloc(size, GFP_KERNEL);
- if (!data) {
- dev_err(&port->dev, "%s - out of memory\n", __func__);
+ if (!data)
return -ENOMEM;
- }
status = ti_command_in_sync(tdev, TI_GET_PORT_STATUS,
(__u8)(TI_UART1_PORT+port_number), 0, (__u8 *)data, size);
@@ -1332,7 +1204,7 @@ static int ti_get_lsr(struct ti_port *tport)
dev_dbg(&port->dev, "%s - lsr 0x%02X\n", __func__, data->bLSR);
- tport->tp_lsr = data->bLSR;
+ *lsr = data->bLSR;
free_data:
kfree(data);
@@ -1345,19 +1217,24 @@ static int ti_get_serial_info(struct ti_port *tport,
{
struct usb_serial_port *port = tport->tp_port;
struct serial_struct ret_serial;
+ unsigned cwait;
if (!ret_arg)
return -EFAULT;
+ cwait = port->port.closing_wait;
+ if (cwait != ASYNC_CLOSING_WAIT_NONE)
+ cwait = jiffies_to_msecs(cwait) / 10;
+
memset(&ret_serial, 0, sizeof(ret_serial));
ret_serial.type = PORT_16550A;
- ret_serial.line = port->serial->minor;
- ret_serial.port = port->number - port->serial->minor;
+ ret_serial.line = port->minor;
+ ret_serial.port = port->port_number;
ret_serial.flags = tport->tp_flags;
- ret_serial.xmit_fifo_size = TI_WRITE_BUF_SIZE;
+ ret_serial.xmit_fifo_size = kfifo_size(&port->write_fifo);
ret_serial.baud_base = tport->tp_tdev->td_is_3410 ? 921600 : 460800;
- ret_serial.closing_wait = tport->tp_closing_wait;
+ ret_serial.closing_wait = cwait;
if (copy_to_user(ret_arg, &ret_serial, sizeof(*ret_arg)))
return -EFAULT;
@@ -1370,12 +1247,17 @@ static int ti_set_serial_info(struct tty_struct *tty, struct ti_port *tport,
struct serial_struct __user *new_arg)
{
struct serial_struct new_serial;
+ unsigned cwait;
if (copy_from_user(&new_serial, new_arg, sizeof(new_serial)))
return -EFAULT;
+ cwait = new_serial.closing_wait;
+ if (cwait != ASYNC_CLOSING_WAIT_NONE)
+ cwait = msecs_to_jiffies(10 * new_serial.closing_wait);
+
tport->tp_flags = new_serial.flags & TI_SET_SERIAL_FLAGS;
- tport->tp_closing_wait = new_serial.closing_wait;
+ tport->tp_port->port.closing_wait = cwait;
return 0;
}
@@ -1391,7 +1273,7 @@ static void ti_handle_new_msr(struct ti_port *tport, __u8 msr)
if (msr & TI_MSR_DELTA_MASK) {
spin_lock_irqsave(&tport->tp_lock, flags);
- icount = &tport->tp_icount;
+ icount = &tport->tp_port->icount;
if (msr & TI_MSR_DELTA_CTS)
icount->cts++;
if (msr & TI_MSR_DELTA_DSR)
@@ -1400,7 +1282,7 @@ static void ti_handle_new_msr(struct ti_port *tport, __u8 msr)
icount->dcd++;
if (msr & TI_MSR_DELTA_RI)
icount->rng++;
- wake_up_interruptible(&tport->tp_msr_wait);
+ wake_up_interruptible(&tport->tp_port->port.delta_msr_wait);
spin_unlock_irqrestore(&tport->tp_lock, flags);
}
@@ -1420,56 +1302,6 @@ static void ti_handle_new_msr(struct ti_port *tport, __u8 msr)
}
-static void ti_drain(struct ti_port *tport, unsigned long timeout, int flush)
-{
- struct ti_device *tdev = tport->tp_tdev;
- struct usb_serial_port *port = tport->tp_port;
- wait_queue_t wait;
-
- spin_lock_irq(&tport->tp_lock);
-
- /* wait for data to drain from the buffer */
- tdev->td_urb_error = 0;
- init_waitqueue_entry(&wait, current);
- add_wait_queue(&tport->tp_write_wait, &wait);
- for (;;) {
- set_current_state(TASK_INTERRUPTIBLE);
- if (kfifo_len(&tport->write_fifo) == 0
- || timeout == 0 || signal_pending(current)
- || tdev->td_urb_error
- || port->serial->disconnected) /* disconnect */
- break;
- spin_unlock_irq(&tport->tp_lock);
- timeout = schedule_timeout(timeout);
- spin_lock_irq(&tport->tp_lock);
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&tport->tp_write_wait, &wait);
-
- /* flush any remaining data in the buffer */
- if (flush)
- kfifo_reset_out(&tport->write_fifo);
-
- spin_unlock_irq(&tport->tp_lock);
-
- mutex_lock(&port->serial->disc_mutex);
- /* wait for data to drain from the device */
- /* wait for empty tx register, plus 20 ms */
- timeout += jiffies;
- tport->tp_lsr &= ~TI_LSR_TX_EMPTY;
- while ((long)(jiffies - timeout) < 0 && !signal_pending(current)
- && !(tport->tp_lsr&TI_LSR_TX_EMPTY) && !tdev->td_urb_error
- && !port->serial->disconnected) {
- if (ti_get_lsr(tport))
- break;
- mutex_unlock(&port->serial->disc_mutex);
- msleep_interruptible(20);
- mutex_lock(&port->serial->disc_mutex);
- }
- mutex_unlock(&port->serial->disc_mutex);
-}
-
-
static void ti_stop_read(struct ti_port *tport, struct tty_struct *tty)
{
unsigned long flags;
@@ -1559,10 +1391,8 @@ static int ti_write_byte(struct usb_serial_port *port,
size = sizeof(struct ti_write_data_bytes) + 2;
data = kmalloc(size, GFP_KERNEL);
- if (!data) {
- dev_err(&port->dev, "%s - out of memory\n", __func__);
+ if (!data)
return -ENOMEM;
- }
data->bAddrType = TI_RW_DATA_ADDR_XDATA;
data->bDataType = TI_RW_DATA_BYTE;
@@ -1624,14 +1454,15 @@ static int ti_download_firmware(struct ti_device *tdev)
char buf[32];
/* try ID specific firmware first, then try generic firmware */
- sprintf(buf, "ti_usb-v%04x-p%04x.fw", dev->descriptor.idVendor,
- dev->descriptor.idProduct);
+ sprintf(buf, "ti_usb-v%04x-p%04x.fw",
+ le16_to_cpu(dev->descriptor.idVendor),
+ le16_to_cpu(dev->descriptor.idProduct));
status = request_firmware(&fw_p, buf, &dev->dev);
if (status != 0) {
buf[0] = '\0';
- if (dev->descriptor.idVendor == MTS_VENDOR_ID) {
- switch (dev->descriptor.idProduct) {
+ if (le16_to_cpu(dev->descriptor.idVendor) == MTS_VENDOR_ID) {
+ switch (le16_to_cpu(dev->descriptor.idProduct)) {
case MTS_CDMA_PRODUCT_ID:
strcpy(buf, "mts_cdma.fw");
break;
@@ -1677,7 +1508,6 @@ static int ti_download_firmware(struct ti_device *tdev)
status = ti_do_download(dev, pipe, buffer, fw_p->size);
kfree(buffer);
} else {
- dev_dbg(&dev->dev, "%s ENOMEM\n", __func__);
status = -ENOMEM;
}
release_firmware(fw_p);
diff --git a/drivers/usb/serial/ti_usb_3410_5052.h b/drivers/usb/serial/ti_usb_3410_5052.h
index b353e7e3d48..4a2423e84d5 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.h
+++ b/drivers/usb/serial/ti_usb_3410_5052.h
@@ -52,7 +52,9 @@
/* Abbott Diabetics vendor and product ids */
#define ABBOTT_VENDOR_ID 0x1a61
-#define ABBOTT_PRODUCT_ID 0x3410
+#define ABBOTT_STEREO_PLUG_ID 0x3410
+#define ABBOTT_PRODUCT_ID ABBOTT_STEREO_PLUG_ID
+#define ABBOTT_STRIP_PORT_ID 0x3420
/* Commands */
#define TI_GET_VERSION 0x01
diff --git a/drivers/usb/serial/usb-serial-simple.c b/drivers/usb/serial/usb-serial-simple.c
new file mode 100644
index 00000000000..fb79775447b
--- /dev/null
+++ b/drivers/usb/serial/usb-serial-simple.c
@@ -0,0 +1,110 @@
+/*
+ * USB Serial "Simple" driver
+ *
+ * Copyright (C) 2001-2006,2008,2013 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (C) 2005 Arthur Huillet (ahuillet@users.sf.net)
+ * Copyright (C) 2005 Thomas Hergenhahn <thomas.hergenhahn@suse.de>
+ * Copyright (C) 2009 Outpost Embedded, LLC
+ * Copyright (C) 2010 Zilogic Systems <code@zilogic.com>
+ * Copyright (C) 2013 Wei Shuai <cpuwolf@gmail.com>
+ * Copyright (C) 2013 Linux Foundation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+
+#define DEVICE(vendor, IDS) \
+static const struct usb_device_id vendor##_id_table[] = { \
+ IDS(), \
+ { }, \
+}; \
+static struct usb_serial_driver vendor##_device = { \
+ .driver = { \
+ .owner = THIS_MODULE, \
+ .name = #vendor, \
+ }, \
+ .id_table = vendor##_id_table, \
+ .num_ports = 1, \
+};
+
+
+/* ZIO Motherboard USB driver */
+#define ZIO_IDS() \
+ { USB_DEVICE(0x1CBE, 0x0103) }
+DEVICE(zio, ZIO_IDS);
+
+/* Funsoft Serial USB driver */
+#define FUNSOFT_IDS() \
+ { USB_DEVICE(0x1404, 0xcddc) }
+DEVICE(funsoft, FUNSOFT_IDS);
+
+/* Infineon Flashloader driver */
+#define FLASHLOADER_IDS() \
+ { USB_DEVICE(0x8087, 0x0716) }
+DEVICE(flashloader, FLASHLOADER_IDS);
+
+/* ViVOpay USB Serial Driver */
+#define VIVOPAY_IDS() \
+ { USB_DEVICE(0x1d5f, 0x1004) } /* ViVOpay 8800 */
+DEVICE(vivopay, VIVOPAY_IDS);
+
+/* Motorola USB Phone driver */
+#define MOTO_IDS() \
+ { USB_DEVICE(0x05c6, 0x3197) }, /* unknown Motorola phone */ \
+ { USB_DEVICE(0x0c44, 0x0022) }, /* unknown Mororola phone */ \
+ { USB_DEVICE(0x22b8, 0x2a64) }, /* Motorola KRZR K1m */ \
+ { USB_DEVICE(0x22b8, 0x2c84) }, /* Motorola VE240 phone */ \
+ { USB_DEVICE(0x22b8, 0x2c64) } /* Motorola V950 phone */
+DEVICE(moto_modem, MOTO_IDS);
+
+/* HP4x (48/49) Generic Serial driver */
+#define HP4X_IDS() \
+ { USB_DEVICE(0x03f0, 0x0121) }
+DEVICE(hp4x, HP4X_IDS);
+
+/* Suunto ANT+ USB Driver */
+#define SUUNTO_IDS() \
+ { USB_DEVICE(0x0fcf, 0x1008) }, \
+ { USB_DEVICE(0x0fcf, 0x1009) } /* Dynastream ANT USB-m Stick */
+DEVICE(suunto, SUUNTO_IDS);
+
+/* Siemens USB/MPI adapter */
+#define SIEMENS_IDS() \
+ { USB_DEVICE(0x908, 0x0004) }
+DEVICE(siemens_mpi, SIEMENS_IDS);
+
+/* All of the above structures mushed into two lists */
+static struct usb_serial_driver * const serial_drivers[] = {
+ &zio_device,
+ &funsoft_device,
+ &flashloader_device,
+ &vivopay_device,
+ &moto_modem_device,
+ &hp4x_device,
+ &suunto_device,
+ &siemens_mpi_device,
+ NULL
+};
+
+static const struct usb_device_id id_table[] = {
+ ZIO_IDS(),
+ FUNSOFT_IDS(),
+ FLASHLOADER_IDS(),
+ VIVOPAY_IDS(),
+ MOTO_IDS(),
+ HP4X_IDS(),
+ SUUNTO_IDS(),
+ SIEMENS_IDS(),
+ { },
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+module_usb_serial_driver(serial_drivers, id_table);
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 64bda135ba7..02de3110fe9 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -1,6 +1,7 @@
/*
* USB Serial Converter driver
*
+ * Copyright (C) 2009 - 2013 Johan Hovold (jhovold@gmail.com)
* Copyright (C) 1999 - 2012 Greg Kroah-Hartman (greg@kroah.com)
* Copyright (C) 2000 Peter Berger (pberger@brimson.com)
* Copyright (C) 2000 Al Borchers (borchers@steinerpoint.com)
@@ -14,7 +15,6 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this
* driver
- *
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -37,11 +37,15 @@
#include <linux/usb.h>
#include <linux/usb/serial.h>
#include <linux/kfifo.h>
+#include <linux/idr.h>
#include "pl2303.h"
#define DRIVER_AUTHOR "Greg Kroah-Hartman <gregkh@linuxfoundation.org>"
#define DRIVER_DESC "USB Serial Driver core"
+#define USB_SERIAL_TTY_MAJOR 188
+#define USB_SERIAL_TTY_MINORS 512 /* should be enough for a while */
+
/* There is no MODULE_DEVICE_TABLE for usbserial.c. Instead
the MODULE_DEVICE_TABLE declarations in each serial driver
cause the "hotplug" program to pull in whatever module is necessary
@@ -49,82 +53,75 @@
drivers depend on it.
*/
-/* initially all NULL */
-static struct usb_serial *serial_table[SERIAL_TTY_MINORS];
+static DEFINE_IDR(serial_minors);
static DEFINE_MUTEX(table_lock);
static LIST_HEAD(usb_serial_driver_list);
/*
- * Look up the serial structure. If it is found and it hasn't been
- * disconnected, return with its disc_mutex held and its refcount
- * incremented. Otherwise return NULL.
+ * Look up the serial port structure. If it is found and it hasn't been
+ * disconnected, return with the parent usb_serial structure's disc_mutex held
+ * and its refcount incremented. Otherwise return NULL.
*/
-struct usb_serial *usb_serial_get_by_index(unsigned index)
+struct usb_serial_port *usb_serial_port_get_by_minor(unsigned minor)
{
struct usb_serial *serial;
+ struct usb_serial_port *port;
mutex_lock(&table_lock);
- serial = serial_table[index];
-
- if (serial) {
- mutex_lock(&serial->disc_mutex);
- if (serial->disconnected) {
- mutex_unlock(&serial->disc_mutex);
- serial = NULL;
- } else {
- kref_get(&serial->kref);
- }
+ port = idr_find(&serial_minors, minor);
+ if (!port)
+ goto exit;
+
+ serial = port->serial;
+ mutex_lock(&serial->disc_mutex);
+ if (serial->disconnected) {
+ mutex_unlock(&serial->disc_mutex);
+ port = NULL;
+ } else {
+ kref_get(&serial->kref);
}
+exit:
mutex_unlock(&table_lock);
- return serial;
+ return port;
}
-static struct usb_serial *get_free_serial(struct usb_serial *serial,
- int num_ports, unsigned int *minor)
+static int allocate_minors(struct usb_serial *serial, int num_ports)
{
+ struct usb_serial_port *port;
unsigned int i, j;
- int good_spot;
+ int minor;
dev_dbg(&serial->interface->dev, "%s %d\n", __func__, num_ports);
- *minor = 0;
mutex_lock(&table_lock);
- for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
- if (serial_table[i])
- continue;
-
- good_spot = 1;
- for (j = 1; j <= num_ports-1; ++j)
- if ((i+j >= SERIAL_TTY_MINORS) || (serial_table[i+j])) {
- good_spot = 0;
- i += j;
- break;
- }
- if (good_spot == 0)
- continue;
-
- *minor = i;
- j = 0;
- dev_dbg(&serial->interface->dev, "%s - minor base = %d\n", __func__, *minor);
- for (i = *minor; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i) {
- serial_table[i] = serial;
- serial->port[j++]->number = i;
- }
- mutex_unlock(&table_lock);
- return serial;
+ for (i = 0; i < num_ports; ++i) {
+ port = serial->port[i];
+ minor = idr_alloc(&serial_minors, port, 0, 0, GFP_KERNEL);
+ if (minor < 0)
+ goto error;
+ port->minor = minor;
+ port->port_number = i;
}
+ serial->minors_reserved = 1;
mutex_unlock(&table_lock);
- return NULL;
+ return 0;
+error:
+ /* unwind the already allocated minors */
+ for (j = 0; j < i; ++j)
+ idr_remove(&serial_minors, serial->port[j]->minor);
+ mutex_unlock(&table_lock);
+ return minor;
}
-static void return_serial(struct usb_serial *serial)
+static void release_minors(struct usb_serial *serial)
{
int i;
mutex_lock(&table_lock);
for (i = 0; i < serial->num_ports; ++i)
- serial_table[serial->minor + i] = NULL;
+ idr_remove(&serial_minors, serial->port[i]->minor);
mutex_unlock(&table_lock);
+ serial->minors_reserved = 0;
}
static void destroy_serial(struct kref *kref)
@@ -136,10 +133,10 @@ static void destroy_serial(struct kref *kref)
serial = to_usb_serial(kref);
/* return the minor range that this device had */
- if (serial->minor != SERIAL_TTY_NO_MINOR)
- return_serial(serial);
+ if (serial->minors_reserved)
+ release_minors(serial);
- if (serial->attached)
+ if (serial->attached && serial->type->release)
serial->type->release(serial);
/* Now that nothing is using the ports, they can be freed */
@@ -151,6 +148,7 @@ static void destroy_serial(struct kref *kref)
}
}
+ usb_put_intf(serial->interface);
usb_put_dev(serial->dev);
kfree(serial);
}
@@ -185,13 +183,11 @@ static int serial_install(struct tty_driver *driver, struct tty_struct *tty)
struct usb_serial_port *port;
int retval = -ENODEV;
- serial = usb_serial_get_by_index(idx);
- if (!serial)
+ port = usb_serial_port_get_by_minor(idx);
+ if (!port)
return retval;
- port = serial->port[idx - serial->minor];
- if (!port)
- goto error_no_port;
+ serial = port->serial;
if (!try_module_get(serial->type->driver.owner))
goto error_module_get;
@@ -218,13 +214,12 @@ static int serial_install(struct tty_driver *driver, struct tty_struct *tty)
error_get_interface:
module_put(serial->type->driver.owner);
error_module_get:
- error_no_port:
usb_serial_put(serial);
mutex_unlock(&serial->disc_mutex);
return retval;
}
-static int serial_activate(struct tty_port *tport, struct tty_struct *tty)
+static int serial_port_activate(struct tty_port *tport, struct tty_struct *tty)
{
struct usb_serial_port *port =
container_of(tport, struct usb_serial_port, port);
@@ -248,30 +243,27 @@ static int serial_open(struct tty_struct *tty, struct file *filp)
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+ dev_dbg(tty->dev, "%s\n", __func__);
+
return tty_port_open(&port->port, tty, filp);
}
/**
- * serial_down - shut down hardware
+ * serial_port_shutdown - shut down hardware
* @tport: tty port to shut down
*
- * Shut down a USB serial port unless it is the console. We never
- * shut down the console hardware as it will always be in use. Serialized
- * against activate by the tport mutex and kept to matching open/close pairs
+ * Shut down a USB serial port. Serialized against activate by the
+ * tport mutex and kept to matching open/close pairs
* of calls by the ASYNCB_INITIALIZED flag.
+ *
+ * Not called if tty is console.
*/
-static void serial_down(struct tty_port *tport)
+static void serial_port_shutdown(struct tty_port *tport)
{
struct usb_serial_port *port =
container_of(tport, struct usb_serial_port, port);
struct usb_serial_driver *drv = port->serial->type;
- /*
- * The console is magical. Do not hang up the console hardware
- * or there will be tears.
- */
- if (port->port.console)
- return;
+
if (drv->close)
drv->close(port);
}
@@ -280,7 +272,8 @@ static void serial_hangup(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+ dev_dbg(tty->dev, "%s\n", __func__);
+
tty_port_hangup(&port->port);
}
@@ -288,7 +281,8 @@ static void serial_close(struct tty_struct *tty, struct file *filp)
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+ dev_dbg(tty->dev, "%s\n", __func__);
+
tty_port_close(&port->port, tty, filp);
}
@@ -307,14 +301,14 @@ static void serial_cleanup(struct tty_struct *tty)
struct usb_serial *serial;
struct module *owner;
+ dev_dbg(tty->dev, "%s\n", __func__);
+
/* The console is magical. Do not hang up the console hardware
* or there will be tears.
*/
if (port->port.console)
return;
- dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
-
tty->driver_data = NULL;
serial = port->serial;
@@ -338,10 +332,8 @@ static int serial_write(struct tty_struct *tty, const unsigned char *buf,
if (port->serial->dev->state == USB_STATE_NOTATTACHED)
goto exit;
- dev_dbg(tty->dev, "%s - port %d, %d byte(s)\n", __func__,
- port->number, count);
+ dev_dbg(tty->dev, "%s - %d byte(s)\n", __func__, count);
- /* pass on to the driver specific version of this function */
retval = port->serial->type->write(tty, port, buf, count);
if (retval < 0)
retval = usb_translate_errors(retval);
@@ -353,32 +345,46 @@ static int serial_write_room(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
- /* pass on to the driver specific version of this function */
+ dev_dbg(tty->dev, "%s\n", __func__);
+
return port->serial->type->write_room(tty);
}
static int serial_chars_in_buffer(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
+ struct usb_serial *serial = port->serial;
- dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+ dev_dbg(tty->dev, "%s\n", __func__);
- /* if the device was unplugged then any remaining characters
- fell out of the connector ;) */
- if (port->serial->disconnected)
+ if (serial->disconnected)
return 0;
- /* pass on to the driver specific version of this function */
- return port->serial->type->chars_in_buffer(tty);
+
+ return serial->type->chars_in_buffer(tty);
+}
+
+static void serial_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ struct usb_serial *serial = port->serial;
+
+ dev_dbg(tty->dev, "%s\n", __func__);
+
+ if (!port->serial->type->wait_until_sent)
+ return;
+
+ mutex_lock(&serial->disc_mutex);
+ if (!serial->disconnected)
+ port->serial->type->wait_until_sent(tty, timeout);
+ mutex_unlock(&serial->disc_mutex);
}
static void serial_throttle(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+ dev_dbg(tty->dev, "%s\n", __func__);
- /* pass on to the driver specific version of this function */
if (port->serial->type->throttle)
port->serial->type->throttle(tty);
}
@@ -387,9 +393,8 @@ static void serial_unthrottle(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+ dev_dbg(tty->dev, "%s\n", __func__);
- /* pass on to the driver specific version of this function */
if (port->serial->type->unthrottle)
port->serial->type->unthrottle(tty);
}
@@ -398,17 +403,20 @@ static int serial_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
struct usb_serial_port *port = tty->driver_data;
- int retval = -ENODEV;
-
- dev_dbg(tty->dev, "%s - port %d, cmd 0x%.4x\n", __func__,
- port->number, cmd);
+ int retval = -ENOIOCTLCMD;
+
+ dev_dbg(tty->dev, "%s - cmd 0x%04x\n", __func__, cmd);
+
+ switch (cmd) {
+ case TIOCMIWAIT:
+ if (port->serial->type->tiocmiwait)
+ retval = port->serial->type->tiocmiwait(tty, arg);
+ break;
+ default:
+ if (port->serial->type->ioctl)
+ retval = port->serial->type->ioctl(tty, cmd, arg);
+ }
- /* pass on to the driver specific version of this function
- if it is available */
- if (port->serial->type->ioctl) {
- retval = port->serial->type->ioctl(tty, cmd, arg);
- } else
- retval = -ENOIOCTLCMD;
return retval;
}
@@ -416,10 +424,8 @@ static void serial_set_termios(struct tty_struct *tty, struct ktermios *old)
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+ dev_dbg(tty->dev, "%s\n", __func__);
- /* pass on to the driver specific version of this function
- if it is available */
if (port->serial->type->set_termios)
port->serial->type->set_termios(tty, port, old);
else
@@ -430,26 +436,27 @@ static int serial_break(struct tty_struct *tty, int break_state)
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+ dev_dbg(tty->dev, "%s\n", __func__);
- /* pass on to the driver specific version of this function
- if it is available */
if (port->serial->type->break_ctl)
port->serial->type->break_ctl(tty, break_state);
+
return 0;
}
static int serial_proc_show(struct seq_file *m, void *v)
{
struct usb_serial *serial;
+ struct usb_serial_port *port;
int i;
char tmp[40];
seq_puts(m, "usbserinfo:1.0 driver:2.0\n");
- for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
- serial = usb_serial_get_by_index(i);
- if (serial == NULL)
+ for (i = 0; i < USB_SERIAL_TTY_MINORS; ++i) {
+ port = usb_serial_port_get_by_minor(i);
+ if (port == NULL)
continue;
+ serial = port->serial;
seq_printf(m, "%d:", i);
if (serial->type->driver.owner)
@@ -461,7 +468,7 @@ static int serial_proc_show(struct seq_file *m, void *v)
le16_to_cpu(serial->dev->descriptor.idVendor),
le16_to_cpu(serial->dev->descriptor.idProduct));
seq_printf(m, " num_ports:%d", serial->num_ports);
- seq_printf(m, " port:%d", i - serial->minor + 1);
+ seq_printf(m, " port:%d", port->port_number);
usb_make_path(serial->dev, tmp, sizeof(tmp));
seq_printf(m, " path:%s", tmp);
@@ -489,7 +496,7 @@ static int serial_tiocmget(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+ dev_dbg(tty->dev, "%s\n", __func__);
if (port->serial->type->tiocmget)
return port->serial->type->tiocmget(tty);
@@ -501,7 +508,7 @@ static int serial_tiocmset(struct tty_struct *tty,
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+ dev_dbg(tty->dev, "%s\n", __func__);
if (port->serial->type->tiocmset)
return port->serial->type->tiocmset(tty, set, clear);
@@ -513,7 +520,7 @@ static int serial_get_icount(struct tty_struct *tty,
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+ dev_dbg(tty->dev, "%s\n", __func__);
if (port->serial->type->get_icount)
return port->serial->type->get_icount(tty, icount);
@@ -535,55 +542,43 @@ static void usb_serial_port_work(struct work_struct *work)
{
struct usb_serial_port *port =
container_of(work, struct usb_serial_port, work);
- struct tty_struct *tty;
- tty = tty_port_tty_get(&port->port);
- if (!tty)
- return;
+ tty_port_tty_wakeup(&port->port);
+}
- dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+static void usb_serial_port_poison_urbs(struct usb_serial_port *port)
+{
+ int i;
- tty_wakeup(tty);
- tty_kref_put(tty);
+ for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i)
+ usb_poison_urb(port->read_urbs[i]);
+ for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i)
+ usb_poison_urb(port->write_urbs[i]);
+
+ usb_poison_urb(port->interrupt_in_urb);
+ usb_poison_urb(port->interrupt_out_urb);
}
-static void kill_traffic(struct usb_serial_port *port)
+static void usb_serial_port_unpoison_urbs(struct usb_serial_port *port)
{
int i;
for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i)
- usb_kill_urb(port->read_urbs[i]);
+ usb_unpoison_urb(port->read_urbs[i]);
for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i)
- usb_kill_urb(port->write_urbs[i]);
- /*
- * This is tricky.
- * Some drivers submit the read_urb in the
- * handler for the write_urb or vice versa
- * this order determines the order in which
- * usb_kill_urb() must be used to reliably
- * kill the URBs. As it is unknown here,
- * both orders must be used in turn.
- * The call below is not redundant.
- */
- usb_kill_urb(port->read_urb);
- usb_kill_urb(port->interrupt_in_urb);
- usb_kill_urb(port->interrupt_out_urb);
+ usb_unpoison_urb(port->write_urbs[i]);
+
+ usb_unpoison_urb(port->interrupt_in_urb);
+ usb_unpoison_urb(port->interrupt_out_urb);
}
-static void port_release(struct device *dev)
+static void usb_serial_port_release(struct device *dev)
{
struct usb_serial_port *port = to_usb_serial_port(dev);
int i;
dev_dbg(dev, "%s\n", __func__);
- /*
- * Stop all the traffic before cancelling the work, so that
- * nobody will restart it by calling usb_serial_port_softint.
- */
- kill_traffic(port);
- cancel_work_sync(&port->work);
-
usb_free_urb(port->interrupt_in_urb);
usb_free_urb(port->interrupt_out_urb);
for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) {
@@ -608,16 +603,14 @@ static struct usb_serial *create_serial(struct usb_device *dev,
struct usb_serial *serial;
serial = kzalloc(sizeof(*serial), GFP_KERNEL);
- if (!serial) {
- dev_err(&dev->dev, "%s - out of memory\n", __func__);
+ if (!serial)
return NULL;
- }
serial->dev = usb_get_dev(dev);
serial->type = driver;
- serial->interface = interface;
+ serial->interface = usb_get_intf(interface);
kref_init(&serial->kref);
mutex_init(&serial->disc_mutex);
- serial->minor = SERIAL_TTY_NO_MINOR;
+ serial->minors_reserved = 0;
return serial;
}
@@ -674,7 +667,7 @@ static struct usb_serial_driver *search_serial_device(
return NULL;
}
-static int serial_carrier_raised(struct tty_port *port)
+static int serial_port_carrier_raised(struct tty_port *port)
{
struct usb_serial_port *p = container_of(port, struct usb_serial_port, port);
struct usb_serial_driver *drv = p->serial->type;
@@ -685,7 +678,7 @@ static int serial_carrier_raised(struct tty_port *port)
return 1;
}
-static void serial_dtr_rts(struct tty_port *port, int on)
+static void serial_port_dtr_rts(struct tty_port *port, int on)
{
struct usb_serial_port *p = container_of(port, struct usb_serial_port, port);
struct usb_serial_driver *drv = p->serial->type;
@@ -695,10 +688,10 @@ static void serial_dtr_rts(struct tty_port *port, int on)
}
static const struct tty_port_operations serial_port_ops = {
- .carrier_raised = serial_carrier_raised,
- .dtr_rts = serial_dtr_rts,
- .activate = serial_activate,
- .shutdown = serial_down,
+ .carrier_raised = serial_port_carrier_raised,
+ .dtr_rts = serial_port_dtr_rts,
+ .activate = serial_port_activate,
+ .shutdown = serial_port_shutdown,
};
static int usb_serial_probe(struct usb_interface *interface,
@@ -716,7 +709,6 @@ static int usb_serial_probe(struct usb_interface *interface,
struct usb_endpoint_descriptor *bulk_out_endpoint[MAX_NUM_PORTS];
struct usb_serial_driver *type = NULL;
int retval;
- unsigned int minor;
int buffer_size;
int i;
int j;
@@ -745,7 +737,6 @@ static int usb_serial_probe(struct usb_interface *interface,
serial = create_serial(dev, interface, type);
if (!serial) {
module_put(type->driver.owner);
- dev_err(ddev, "%s - out of memory\n", __func__);
return -ENOMEM;
}
@@ -877,7 +868,7 @@ static int usb_serial_probe(struct usb_interface *interface,
max_endpoints = max(max_endpoints, (int)serial->num_ports);
serial->num_port_pointers = max_endpoints;
- dev_dbg(ddev, "setting up %d port structures for this device", max_endpoints);
+ dev_dbg(ddev, "setting up %d port structure(s)\n", max_endpoints);
for (i = 0; i < max_endpoints; ++i) {
port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL);
if (!port)
@@ -893,7 +884,7 @@ static int usb_serial_probe(struct usb_interface *interface,
port->dev.parent = &interface->dev;
port->dev.driver = NULL;
port->dev.bus = &usb_serial_bus_type;
- port->dev.release = &port_release;
+ port->dev.release = &usb_serial_port_release;
device_initialize(&port->dev);
}
@@ -909,16 +900,12 @@ static int usb_serial_probe(struct usb_interface *interface,
for (j = 0; j < ARRAY_SIZE(port->read_urbs); ++j) {
set_bit(j, &port->read_urbs_free);
port->read_urbs[j] = usb_alloc_urb(0, GFP_KERNEL);
- if (!port->read_urbs[j]) {
- dev_err(ddev, "No free urbs available\n");
+ if (!port->read_urbs[j])
goto probe_error;
- }
port->bulk_in_buffers[j] = kmalloc(buffer_size,
GFP_KERNEL);
- if (!port->bulk_in_buffers[j]) {
- dev_err(ddev, "Couldn't allocate bulk_in_buffer\n");
+ if (!port->bulk_in_buffers[j])
goto probe_error;
- }
usb_fill_bulk_urb(port->read_urbs[j], dev,
usb_rcvbulkpipe(dev,
endpoint->bEndpointAddress),
@@ -936,25 +923,20 @@ static int usb_serial_probe(struct usb_interface *interface,
port = serial->port[i];
if (kfifo_alloc(&port->write_fifo, PAGE_SIZE, GFP_KERNEL))
goto probe_error;
- buffer_size = serial->type->bulk_out_size;
- if (!buffer_size)
- buffer_size = usb_endpoint_maxp(endpoint);
+ buffer_size = max_t(int, serial->type->bulk_out_size,
+ usb_endpoint_maxp(endpoint));
port->bulk_out_size = buffer_size;
port->bulk_out_endpointAddress = endpoint->bEndpointAddress;
for (j = 0; j < ARRAY_SIZE(port->write_urbs); ++j) {
set_bit(j, &port->write_urbs_free);
port->write_urbs[j] = usb_alloc_urb(0, GFP_KERNEL);
- if (!port->write_urbs[j]) {
- dev_err(ddev, "No free urbs available\n");
+ if (!port->write_urbs[j])
goto probe_error;
- }
port->bulk_out_buffers[j] = kmalloc(buffer_size,
GFP_KERNEL);
- if (!port->bulk_out_buffers[j]) {
- dev_err(ddev, "Couldn't allocate bulk_out_buffer\n");
+ if (!port->bulk_out_buffers[j])
goto probe_error;
- }
usb_fill_bulk_urb(port->write_urbs[j], dev,
usb_sndbulkpipe(dev,
endpoint->bEndpointAddress),
@@ -972,19 +954,15 @@ static int usb_serial_probe(struct usb_interface *interface,
endpoint = interrupt_in_endpoint[i];
port = serial->port[i];
port->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!port->interrupt_in_urb) {
- dev_err(ddev, "No free urbs available\n");
+ if (!port->interrupt_in_urb)
goto probe_error;
- }
buffer_size = usb_endpoint_maxp(endpoint);
port->interrupt_in_endpointAddress =
endpoint->bEndpointAddress;
port->interrupt_in_buffer = kmalloc(buffer_size,
GFP_KERNEL);
- if (!port->interrupt_in_buffer) {
- dev_err(ddev, "Couldn't allocate interrupt_in_buffer\n");
+ if (!port->interrupt_in_buffer)
goto probe_error;
- }
usb_fill_int_urb(port->interrupt_in_urb, dev,
usb_rcvintpipe(dev,
endpoint->bEndpointAddress),
@@ -1001,20 +979,16 @@ static int usb_serial_probe(struct usb_interface *interface,
endpoint = interrupt_out_endpoint[i];
port = serial->port[i];
port->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!port->interrupt_out_urb) {
- dev_err(ddev, "No free urbs available\n");
+ if (!port->interrupt_out_urb)
goto probe_error;
- }
buffer_size = usb_endpoint_maxp(endpoint);
port->interrupt_out_size = buffer_size;
port->interrupt_out_endpointAddress =
endpoint->bEndpointAddress;
port->interrupt_out_buffer = kmalloc(buffer_size,
GFP_KERNEL);
- if (!port->interrupt_out_buffer) {
- dev_err(ddev, "Couldn't allocate interrupt_out_buffer\n");
+ if (!port->interrupt_out_buffer)
goto probe_error;
- }
usb_fill_int_urb(port->interrupt_out_urb, dev,
usb_sndintpipe(dev,
endpoint->bEndpointAddress),
@@ -1050,17 +1024,16 @@ static int usb_serial_probe(struct usb_interface *interface,
*/
serial->disconnected = 1;
- if (get_free_serial(serial, num_ports, &minor) == NULL) {
- dev_err(ddev, "No more free serial devices\n");
+ if (allocate_minors(serial, num_ports)) {
+ dev_err(ddev, "No more free serial minor numbers\n");
goto probe_error;
}
- serial->minor = minor;
/* register all of the individual ports with the driver core */
for (i = 0; i < num_ports; ++i) {
port = serial->port[i];
- dev_set_name(&port->dev, "ttyUSB%d", port->number);
- dev_dbg(ddev, "registering %s", dev_name(&port->dev));
+ dev_set_name(&port->dev, "ttyUSB%d", port->minor);
+ dev_dbg(ddev, "registering %s\n", dev_name(&port->dev));
device_enable_async_suspend(&port->dev);
retval = device_add(&port->dev);
@@ -1070,7 +1043,7 @@ static int usb_serial_probe(struct usb_interface *interface,
serial->disconnected = 0;
- usb_serial_console_init(minor);
+ usb_serial_console_init(serial->port[0]->minor);
exit:
module_put(type->driver.owner);
return 0;
@@ -1087,6 +1060,7 @@ static void usb_serial_disconnect(struct usb_interface *interface)
struct usb_serial *serial = usb_get_intfdata(interface);
struct device *dev = &interface->dev;
struct usb_serial_port *port;
+ struct tty_struct *tty;
usb_serial_console_disconnect(serial);
@@ -1097,19 +1071,19 @@ static void usb_serial_disconnect(struct usb_interface *interface)
for (i = 0; i < serial->num_ports; ++i) {
port = serial->port[i];
- if (port) {
- struct tty_struct *tty = tty_port_tty_get(&port->port);
- if (tty) {
- tty_vhangup(tty);
- tty_kref_put(tty);
- }
- kill_traffic(port);
- cancel_work_sync(&port->work);
- if (device_is_registered(&port->dev))
- device_del(&port->dev);
+ tty = tty_port_tty_get(&port->port);
+ if (tty) {
+ tty_vhangup(tty);
+ tty_kref_put(tty);
}
+ usb_serial_port_poison_urbs(port);
+ wake_up_interruptible(&port->port.delta_msr_wait);
+ cancel_work_sync(&port->work);
+ if (device_is_registered(&port->dev))
+ device_del(&port->dev);
}
- serial->type->disconnect(serial);
+ if (serial->type->disconnect)
+ serial->type->disconnect(serial);
/* let the last holder of this object cause it to be cleaned up */
usb_serial_put(serial);
@@ -1119,11 +1093,15 @@ static void usb_serial_disconnect(struct usb_interface *interface)
int usb_serial_suspend(struct usb_interface *intf, pm_message_t message)
{
struct usb_serial *serial = usb_get_intfdata(intf);
- struct usb_serial_port *port;
int i, r = 0;
serial->suspending = 1;
+ /*
+ * serial->type->suspend() MUST return 0 in system sleep context,
+ * otherwise, the resume callback has to recover device from
+ * previous suspend failure.
+ */
if (serial->type->suspend) {
r = serial->type->suspend(serial, message);
if (r < 0) {
@@ -1132,22 +1110,28 @@ int usb_serial_suspend(struct usb_interface *intf, pm_message_t message)
}
}
- for (i = 0; i < serial->num_ports; ++i) {
- port = serial->port[i];
- if (port)
- kill_traffic(port);
- }
-
+ for (i = 0; i < serial->num_ports; ++i)
+ usb_serial_port_poison_urbs(serial->port[i]);
err_out:
return r;
}
EXPORT_SYMBOL(usb_serial_suspend);
+static void usb_serial_unpoison_port_urbs(struct usb_serial *serial)
+{
+ int i;
+
+ for (i = 0; i < serial->num_ports; ++i)
+ usb_serial_port_unpoison_urbs(serial->port[i]);
+}
+
int usb_serial_resume(struct usb_interface *intf)
{
struct usb_serial *serial = usb_get_intfdata(intf);
int rv;
+ usb_serial_unpoison_port_urbs(serial);
+
serial->suspending = 0;
if (serial->type->resume)
rv = serial->type->resume(serial);
@@ -1163,10 +1147,12 @@ static int usb_serial_reset_resume(struct usb_interface *intf)
struct usb_serial *serial = usb_get_intfdata(intf);
int rv;
+ usb_serial_unpoison_port_urbs(serial);
+
serial->suspending = 0;
- if (serial->type->reset_resume)
+ if (serial->type->reset_resume) {
rv = serial->type->reset_resume(serial);
- else {
+ } else {
rv = -EOPNOTSUPP;
intf->needs_binding = 1;
}
@@ -1186,6 +1172,7 @@ static const struct tty_operations serial_ops = {
.unthrottle = serial_unthrottle,
.break_ctl = serial_break,
.chars_in_buffer = serial_chars_in_buffer,
+ .wait_until_sent = serial_wait_until_sent,
.tiocmget = serial_tiocmget,
.tiocmset = serial_tiocmset,
.get_icount = serial_get_icount,
@@ -1210,17 +1197,13 @@ static struct usb_driver usb_serial_driver = {
static int __init usb_serial_init(void)
{
- int i;
int result;
- usb_serial_tty_driver = alloc_tty_driver(SERIAL_TTY_MINORS);
+ usb_serial_tty_driver = alloc_tty_driver(USB_SERIAL_TTY_MINORS);
if (!usb_serial_tty_driver)
return -ENOMEM;
/* Initialize our global data */
- for (i = 0; i < SERIAL_TTY_MINORS; ++i)
- serial_table[i] = NULL;
-
result = bus_register(&usb_serial_bus_type);
if (result) {
pr_err("%s - registering bus driver failed\n", __func__);
@@ -1229,7 +1212,7 @@ static int __init usb_serial_init(void)
usb_serial_tty_driver->driver_name = "usbserial";
usb_serial_tty_driver->name = "ttyUSB";
- usb_serial_tty_driver->major = SERIAL_TTY_MAJOR;
+ usb_serial_tty_driver->major = USB_SERIAL_TTY_MAJOR;
usb_serial_tty_driver->minor_start = 0;
usb_serial_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
usb_serial_tty_driver->subtype = SERIAL_TYPE_NORMAL;
@@ -1299,22 +1282,22 @@ module_exit(usb_serial_exit);
do { \
if (!type->function) { \
type->function = usb_serial_generic_##function; \
- pr_debug("Had to override the " #function \
- " usb serial operation with the generic one.");\
- } \
+ pr_debug("%s: using generic " #function "\n", \
+ type->driver.name); \
+ } \
} while (0)
-static void fixup_generic(struct usb_serial_driver *device)
+static void usb_serial_operations_init(struct usb_serial_driver *device)
{
set_to_generic_if_null(device, open);
set_to_generic_if_null(device, write);
set_to_generic_if_null(device, close);
set_to_generic_if_null(device, write_room);
set_to_generic_if_null(device, chars_in_buffer);
+ if (device->tx_empty)
+ set_to_generic_if_null(device, wait_until_sent);
set_to_generic_if_null(device, read_bulk_callback);
set_to_generic_if_null(device, write_bulk_callback);
- set_to_generic_if_null(device, disconnect);
- set_to_generic_if_null(device, release);
set_to_generic_if_null(device, process_read_urb);
set_to_generic_if_null(device, prepare_write_buffer);
}
@@ -1326,8 +1309,6 @@ static int usb_serial_register(struct usb_serial_driver *driver)
if (usb_disabled())
return -ENODEV;
- fixup_generic(driver);
-
if (!driver->description)
driver->description = driver->driver.name;
if (!driver->usb_driver) {
@@ -1336,6 +1317,8 @@ static int usb_serial_register(struct usb_serial_driver *driver)
return -EINVAL;
}
+ usb_serial_operations_init(driver);
+
/* Add this device to our list of devices */
mutex_lock(&table_lock);
list_add(&driver->driver_list, &usb_serial_driver_list);
@@ -1344,9 +1327,9 @@ static int usb_serial_register(struct usb_serial_driver *driver)
if (retval) {
pr_err("problem %d when registering driver %s\n", retval, driver->description);
list_del(&driver->driver_list);
- } else
+ } else {
pr_info("USB Serial support registered for %s\n", driver->description);
-
+ }
mutex_unlock(&table_lock);
return retval;
}
@@ -1354,10 +1337,12 @@ static int usb_serial_register(struct usb_serial_driver *driver)
static void usb_serial_deregister(struct usb_serial_driver *device)
{
pr_info("USB Serial deregistering driver %s\n", device->description);
+
mutex_lock(&table_lock);
list_del(&device->driver_list);
- usb_serial_bus_deregister(device);
mutex_unlock(&table_lock);
+
+ usb_serial_bus_deregister(device);
}
/**
@@ -1453,7 +1438,6 @@ void usb_serial_deregister_drivers(struct usb_serial_driver *const serial_driver
}
EXPORT_SYMBOL_GPL(usb_serial_deregister_drivers);
-/* Module information */
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/usb-wwan.h b/drivers/usb/serial/usb-wwan.h
index 684739b8efd..f22dff58b58 100644
--- a/drivers/usb/serial/usb-wwan.h
+++ b/drivers/usb/serial/usb-wwan.h
@@ -11,15 +11,11 @@ extern void usb_wwan_close(struct usb_serial_port *port);
extern int usb_wwan_port_probe(struct usb_serial_port *port);
extern int usb_wwan_port_remove(struct usb_serial_port *port);
extern int usb_wwan_write_room(struct tty_struct *tty);
-extern void usb_wwan_set_termios(struct tty_struct *tty,
- struct usb_serial_port *port,
- struct ktermios *old);
extern int usb_wwan_tiocmget(struct tty_struct *tty);
extern int usb_wwan_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear);
extern int usb_wwan_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg);
-extern int usb_wwan_send_setup(struct usb_serial_port *port);
extern int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count);
extern int usb_wwan_chars_in_buffer(struct tty_struct *tty);
@@ -39,6 +35,7 @@ struct usb_wwan_intf_private {
spinlock_t susp_lock;
unsigned int suspended:1;
int in_flight;
+ unsigned int open_ports;
int (*send_setup) (struct usb_serial_port *port);
void *private;
};
@@ -51,7 +48,6 @@ struct usb_wwan_port_private {
struct urb *out_urbs[N_OUT_URB];
u8 *out_buffer[N_OUT_URB];
unsigned long out_busy; /* Bit vector of URBs in use */
- int opened;
struct usb_anchor delayed;
/* Settings for the port */
diff --git a/drivers/usb/serial/usb_debug.c b/drivers/usb/serial/usb_debug.c
index 5760f97ee50..ca2fa5bbe17 100644
--- a/drivers/usb/serial/usb_debug.c
+++ b/drivers/usb/serial/usb_debug.c
@@ -10,7 +10,6 @@
#include <linux/gfp.h>
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/tty.h>
#include <linux/module.h>
#include <linux/usb.h>
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
index 01c94aada56..2f805cb386a 100644
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
@@ -38,38 +38,22 @@
void usb_wwan_dtr_rts(struct usb_serial_port *port, int on)
{
- struct usb_serial *serial = port->serial;
struct usb_wwan_port_private *portdata;
struct usb_wwan_intf_private *intfdata;
- intfdata = port->serial->private;
+ intfdata = usb_get_serial_data(port->serial);
if (!intfdata->send_setup)
return;
portdata = usb_get_serial_port_data(port);
- mutex_lock(&serial->disc_mutex);
+ /* FIXME: locking */
portdata->rts_state = on;
portdata->dtr_state = on;
- if (serial->dev)
- intfdata->send_setup(port);
- mutex_unlock(&serial->disc_mutex);
-}
-EXPORT_SYMBOL(usb_wwan_dtr_rts);
-
-void usb_wwan_set_termios(struct tty_struct *tty,
- struct usb_serial_port *port,
- struct ktermios *old_termios)
-{
- struct usb_wwan_intf_private *intfdata = port->serial->private;
-
- /* Doesn't support option setting */
- tty_termios_copy_hw(&tty->termios, old_termios);
- if (intfdata->send_setup)
- intfdata->send_setup(port);
+ intfdata->send_setup(port);
}
-EXPORT_SYMBOL(usb_wwan_set_termios);
+EXPORT_SYMBOL(usb_wwan_dtr_rts);
int usb_wwan_tiocmget(struct tty_struct *tty)
{
@@ -98,7 +82,7 @@ int usb_wwan_tiocmset(struct tty_struct *tty,
struct usb_wwan_intf_private *intfdata;
portdata = usb_get_serial_port_data(port);
- intfdata = port->serial->private;
+ intfdata = usb_get_serial_data(port->serial);
if (!intfdata->send_setup)
return -EINVAL;
@@ -126,8 +110,8 @@ static int get_serial_info(struct usb_serial_port *port,
return -EFAULT;
memset(&tmp, 0, sizeof(tmp));
- tmp.line = port->serial->minor;
- tmp.port = port->number;
+ tmp.line = port->minor;
+ tmp.port = port->port_number;
tmp.baud_base = tty_get_baud_rate(port->port.tty);
tmp.close_delay = port->port.close_delay / 10;
tmp.closing_wait = port->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
@@ -194,7 +178,6 @@ int usb_wwan_ioctl(struct tty_struct *tty,
}
EXPORT_SYMBOL(usb_wwan_ioctl);
-/* Write */
int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count)
{
@@ -207,7 +190,7 @@ int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port,
unsigned long flags;
portdata = usb_get_serial_port_data(port);
- intfdata = port->serial->private;
+ intfdata = usb_get_serial_data(port->serial);
dev_dbg(&port->dev, "%s: write (%d chars)\n", __func__, count);
@@ -230,8 +213,10 @@ int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port,
usb_pipeendpoint(this_urb->pipe), i);
err = usb_autopm_get_interface_async(port->serial->interface);
- if (err < 0)
+ if (err < 0) {
+ clear_bit(i, &portdata->out_busy);
break;
+ }
/* send the data */
memcpy(this_urb->transfer_buffer, buf, todo);
@@ -246,9 +231,9 @@ int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port,
spin_unlock_irqrestore(&intfdata->susp_lock, flags);
err = usb_submit_urb(this_urb, GFP_ATOMIC);
if (err) {
- dev_dbg(&port->dev,
- "usb_submit_urb %p (write bulk) failed (%d)\n",
- this_urb, err);
+ dev_err(&port->dev,
+ "%s: submit urb %d failed: %d\n",
+ __func__, i, err);
clear_bit(i, &portdata->out_busy);
spin_lock_irqsave(&intfdata->susp_lock, flags);
intfdata->in_flight--;
@@ -275,7 +260,6 @@ static void usb_wwan_indat_callback(struct urb *urb)
int err;
int endpoint;
struct usb_serial_port *port;
- struct tty_struct *tty;
struct device *dev;
unsigned char *data = urb->transfer_buffer;
int status = urb->status;
@@ -288,28 +272,24 @@ static void usb_wwan_indat_callback(struct urb *urb)
dev_dbg(dev, "%s: nonzero status: %d on endpoint %02x.\n",
__func__, status, endpoint);
} else {
- tty = tty_port_tty_get(&port->port);
- if (tty) {
- if (urb->actual_length) {
- tty_insert_flip_string(tty, data,
- urb->actual_length);
- tty_flip_buffer_push(tty);
- } else
- dev_dbg(dev, "%s: empty read urb received\n", __func__);
- tty_kref_put(tty);
- }
-
- /* Resubmit urb so we continue receiving */
- err = usb_submit_urb(urb, GFP_ATOMIC);
- if (err) {
- if (err != -EPERM) {
- dev_err(dev, "%s: resubmit read urb failed. (%d)\n", __func__, err);
- /* busy also in error unless we are killed */
- usb_mark_last_busy(port->serial->dev);
- }
- } else {
+ if (urb->actual_length) {
+ tty_insert_flip_string(&port->port, data,
+ urb->actual_length);
+ tty_flip_buffer_push(&port->port);
+ } else
+ dev_dbg(dev, "%s: empty read urb received\n", __func__);
+ }
+ /* Resubmit urb so we continue receiving */
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err) {
+ if (err != -EPERM) {
+ dev_err(dev, "%s: resubmit read urb failed. (%d)\n",
+ __func__, err);
+ /* busy also in error unless we are killed */
usb_mark_last_busy(port->serial->dev);
}
+ } else {
+ usb_mark_last_busy(port->serial->dev);
}
}
@@ -321,7 +301,7 @@ static void usb_wwan_outdat_callback(struct urb *urb)
int i;
port = urb->context;
- intfdata = port->serial->private;
+ intfdata = usb_get_serial_data(port->serial);
usb_serial_port_softint(port);
usb_autopm_put_interface_async(port->serial->interface);
@@ -332,7 +312,7 @@ static void usb_wwan_outdat_callback(struct urb *urb)
for (i = 0; i < N_OUT_URB; ++i) {
if (portdata->out_urbs[i] == urb) {
- smp_mb__before_clear_bit();
+ smp_mb__before_atomic();
clear_bit(i, &portdata->out_busy);
break;
}
@@ -391,7 +371,15 @@ int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port)
struct urb *urb;
portdata = usb_get_serial_port_data(port);
- intfdata = serial->private;
+ intfdata = usb_get_serial_data(serial);
+
+ if (port->interrupt_in_urb) {
+ err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
+ if (err) {
+ dev_err(&port->dev, "%s: submit int urb failed: %d\n",
+ __func__, err);
+ }
+ }
/* Start reading from the IN endpoint */
for (i = 0; i < N_IN_URB; i++) {
@@ -400,17 +388,15 @@ int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port)
continue;
err = usb_submit_urb(urb, GFP_KERNEL);
if (err) {
- dev_dbg(&port->dev, "%s: submit urb %d failed (%d) %d\n",
- __func__, i, err, urb->transfer_buffer_length);
+ dev_err(&port->dev,
+ "%s: submit read urb %d failed: %d\n",
+ __func__, i, err);
}
}
- if (intfdata->send_setup)
- intfdata->send_setup(port);
-
- serial->interface->needs_remote_wakeup = 1;
spin_lock_irq(&intfdata->susp_lock);
- portdata->opened = 1;
+ if (++intfdata->open_ports == 1)
+ serial->interface->needs_remote_wakeup = 1;
spin_unlock_irq(&intfdata->susp_lock);
/* this balances a get in the generic USB serial code */
usb_autopm_put_interface(serial->interface);
@@ -419,33 +405,56 @@ int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port)
}
EXPORT_SYMBOL(usb_wwan_open);
+static void unbusy_queued_urb(struct urb *urb,
+ struct usb_wwan_port_private *portdata)
+{
+ int i;
+
+ for (i = 0; i < N_OUT_URB; i++) {
+ if (urb == portdata->out_urbs[i]) {
+ clear_bit(i, &portdata->out_busy);
+ break;
+ }
+ }
+}
+
void usb_wwan_close(struct usb_serial_port *port)
{
int i;
struct usb_serial *serial = port->serial;
struct usb_wwan_port_private *portdata;
- struct usb_wwan_intf_private *intfdata = port->serial->private;
+ struct usb_wwan_intf_private *intfdata = usb_get_serial_data(serial);
+ struct urb *urb;
portdata = usb_get_serial_port_data(port);
- if (serial->dev) {
- /* Stop reading/writing urbs */
- spin_lock_irq(&intfdata->susp_lock);
- portdata->opened = 0;
- spin_unlock_irq(&intfdata->susp_lock);
-
- for (i = 0; i < N_IN_URB; i++)
- usb_kill_urb(portdata->in_urbs[i]);
- for (i = 0; i < N_OUT_URB; i++)
- usb_kill_urb(portdata->out_urbs[i]);
- /* balancing - important as an error cannot be handled*/
- usb_autopm_get_interface_no_resume(serial->interface);
+ /*
+ * Need to take susp_lock to make sure port is not already being
+ * resumed, but no need to hold it due to ASYNC_INITIALIZED.
+ */
+ spin_lock_irq(&intfdata->susp_lock);
+ if (--intfdata->open_ports == 0)
serial->interface->needs_remote_wakeup = 0;
+ spin_unlock_irq(&intfdata->susp_lock);
+
+ for (;;) {
+ urb = usb_get_from_anchor(&portdata->delayed);
+ if (!urb)
+ break;
+ unbusy_queued_urb(urb, portdata);
+ usb_autopm_put_interface_async(serial->interface);
}
+
+ for (i = 0; i < N_IN_URB; i++)
+ usb_kill_urb(portdata->in_urbs[i]);
+ for (i = 0; i < N_OUT_URB; i++)
+ usb_kill_urb(portdata->out_urbs[i]);
+ usb_kill_urb(port->interrupt_in_urb);
+
+ usb_autopm_get_interface_no_resume(serial->interface);
}
EXPORT_SYMBOL(usb_wwan_close);
-/* Helper functions used by usb_wwan_setup_urbs */
static struct urb *usb_wwan_setup_urb(struct usb_serial_port *port,
int endpoint,
int dir, void *ctx, char *buf, int len,
@@ -455,14 +464,9 @@ static struct urb *usb_wwan_setup_urb(struct usb_serial_port *port,
struct urb *urb;
urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
- if (urb == NULL) {
- dev_dbg(&serial->interface->dev,
- "%s: alloc for endpoint %d failed.\n", __func__,
- endpoint);
+ if (!urb)
return NULL;
- }
- /* Fill URB using supplied data. */
usb_fill_bulk_urb(urb, serial->dev,
usb_sndbulkpipe(serial->dev, endpoint) | dir,
buf, len, callback, ctx);
@@ -475,9 +479,11 @@ int usb_wwan_port_probe(struct usb_serial_port *port)
struct usb_wwan_port_private *portdata;
struct urb *urb;
u8 *buffer;
- int err;
int i;
+ if (!port->bulk_in_size || !port->bulk_out_size)
+ return -ENODEV;
+
portdata = kzalloc(sizeof(*portdata), GFP_KERNEL);
if (!portdata)
return -ENOMEM;
@@ -485,9 +491,6 @@ int usb_wwan_port_probe(struct usb_serial_port *port)
init_usb_anchor(&portdata->delayed);
for (i = 0; i < N_IN_URB; i++) {
- if (!port->bulk_in_size)
- break;
-
buffer = (u8 *)__get_free_page(GFP_KERNEL);
if (!buffer)
goto bail_out_error;
@@ -501,9 +504,6 @@ int usb_wwan_port_probe(struct usb_serial_port *port)
}
for (i = 0; i < N_OUT_URB; i++) {
- if (!port->bulk_out_size)
- break;
-
buffer = kmalloc(OUT_BUFLEN, GFP_KERNEL);
if (!buffer)
goto bail_out_error2;
@@ -518,13 +518,6 @@ int usb_wwan_port_probe(struct usb_serial_port *port)
usb_set_serial_port_data(port, portdata);
- if (port->interrupt_in_urb) {
- err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
- if (err)
- dev_dbg(&port->dev, "%s: submit irq_in urb failed %d\n",
- __func__, err);
- }
-
return 0;
bail_out_error2:
@@ -551,32 +544,28 @@ int usb_wwan_port_remove(struct usb_serial_port *port)
portdata = usb_get_serial_port_data(port);
usb_set_serial_port_data(port, NULL);
- /* Stop reading/writing urbs and free them */
for (i = 0; i < N_IN_URB; i++) {
- usb_kill_urb(portdata->in_urbs[i]);
usb_free_urb(portdata->in_urbs[i]);
free_page((unsigned long)portdata->in_buffer[i]);
}
for (i = 0; i < N_OUT_URB; i++) {
- usb_kill_urb(portdata->out_urbs[i]);
usb_free_urb(portdata->out_urbs[i]);
kfree(portdata->out_buffer[i]);
}
- /* Now free port private data */
kfree(portdata);
+
return 0;
}
EXPORT_SYMBOL(usb_wwan_port_remove);
#ifdef CONFIG_PM
-static void stop_read_write_urbs(struct usb_serial *serial)
+static void stop_urbs(struct usb_serial *serial)
{
int i, j;
struct usb_serial_port *port;
struct usb_wwan_port_private *portdata;
- /* Stop reading/writing urbs */
for (i = 0; i < serial->num_ports; ++i) {
port = serial->port[i];
portdata = usb_get_serial_port_data(port);
@@ -586,123 +575,117 @@ static void stop_read_write_urbs(struct usb_serial *serial)
usb_kill_urb(portdata->in_urbs[j]);
for (j = 0; j < N_OUT_URB; j++)
usb_kill_urb(portdata->out_urbs[j]);
+ usb_kill_urb(port->interrupt_in_urb);
}
}
int usb_wwan_suspend(struct usb_serial *serial, pm_message_t message)
{
- struct usb_wwan_intf_private *intfdata = serial->private;
- int b;
+ struct usb_wwan_intf_private *intfdata = usb_get_serial_data(serial);
+ spin_lock_irq(&intfdata->susp_lock);
if (PMSG_IS_AUTO(message)) {
- spin_lock_irq(&intfdata->susp_lock);
- b = intfdata->in_flight;
- spin_unlock_irq(&intfdata->susp_lock);
-
- if (b)
+ if (intfdata->in_flight) {
+ spin_unlock_irq(&intfdata->susp_lock);
return -EBUSY;
+ }
}
-
- spin_lock_irq(&intfdata->susp_lock);
intfdata->suspended = 1;
spin_unlock_irq(&intfdata->susp_lock);
- stop_read_write_urbs(serial);
+
+ stop_urbs(serial);
return 0;
}
EXPORT_SYMBOL(usb_wwan_suspend);
-static void unbusy_queued_urb(struct urb *urb, struct usb_wwan_port_private *portdata)
+/* Caller must hold susp_lock. */
+static int usb_wwan_submit_delayed_urbs(struct usb_serial_port *port)
{
- int i;
-
- for (i = 0; i < N_OUT_URB; i++) {
- if (urb == portdata->out_urbs[i]) {
- clear_bit(i, &portdata->out_busy);
- break;
- }
- }
-}
-
-static void play_delayed(struct usb_serial_port *port)
-{
- struct usb_wwan_intf_private *data;
+ struct usb_serial *serial = port->serial;
+ struct usb_wwan_intf_private *data = usb_get_serial_data(serial);
struct usb_wwan_port_private *portdata;
struct urb *urb;
+ int err_count = 0;
int err;
portdata = usb_get_serial_port_data(port);
- data = port->serial->private;
- while ((urb = usb_get_from_anchor(&portdata->delayed))) {
- err = usb_submit_urb(urb, GFP_ATOMIC);
- if (!err) {
- data->in_flight++;
- } else {
- /* we have to throw away the rest */
- do {
- unbusy_queued_urb(urb, portdata);
- usb_autopm_put_interface_no_suspend(port->serial->interface);
- } while ((urb = usb_get_from_anchor(&portdata->delayed)));
+
+ for (;;) {
+ urb = usb_get_from_anchor(&portdata->delayed);
+ if (!urb)
break;
+
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err) {
+ dev_err(&port->dev, "%s: submit urb failed: %d\n",
+ __func__, err);
+ err_count++;
+ unbusy_queued_urb(urb, portdata);
+ usb_autopm_put_interface_async(serial->interface);
+ continue;
}
+ data->in_flight++;
}
+
+ if (err_count)
+ return -EIO;
+
+ return 0;
}
int usb_wwan_resume(struct usb_serial *serial)
{
int i, j;
struct usb_serial_port *port;
- struct usb_wwan_intf_private *intfdata = serial->private;
+ struct usb_wwan_intf_private *intfdata = usb_get_serial_data(serial);
struct usb_wwan_port_private *portdata;
struct urb *urb;
- int err = 0;
+ int err;
+ int err_count = 0;
- /* get the interrupt URBs resubmitted unconditionally */
+ spin_lock_irq(&intfdata->susp_lock);
for (i = 0; i < serial->num_ports; i++) {
port = serial->port[i];
- if (!port->interrupt_in_urb) {
- dev_dbg(&port->dev, "%s: No interrupt URB for port\n", __func__);
+
+ if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags))
continue;
- }
- err = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO);
- dev_dbg(&port->dev, "Submitted interrupt URB for port (result %d)\n", err);
- if (err < 0) {
- dev_err(&port->dev, "%s: Error %d for interrupt URB\n",
- __func__, err);
- goto err_out;
- }
- }
- for (i = 0; i < serial->num_ports; i++) {
- /* walk all ports */
- port = serial->port[i];
portdata = usb_get_serial_port_data(port);
- /* skip closed ports */
- spin_lock_irq(&intfdata->susp_lock);
- if (!portdata || !portdata->opened) {
- spin_unlock_irq(&intfdata->susp_lock);
- continue;
+ if (port->interrupt_in_urb) {
+ err = usb_submit_urb(port->interrupt_in_urb,
+ GFP_ATOMIC);
+ if (err) {
+ dev_err(&port->dev,
+ "%s: submit int urb failed: %d\n",
+ __func__, err);
+ err_count++;
+ }
}
+ err = usb_wwan_submit_delayed_urbs(port);
+ if (err)
+ err_count++;
+
for (j = 0; j < N_IN_URB; j++) {
urb = portdata->in_urbs[j];
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err < 0) {
- dev_err(&port->dev, "%s: Error %d for bulk URB %d\n",
- __func__, err, i);
- spin_unlock_irq(&intfdata->susp_lock);
- goto err_out;
+ dev_err(&port->dev,
+ "%s: submit read urb %d failed: %d\n",
+ __func__, i, err);
+ err_count++;
}
}
- play_delayed(port);
- spin_unlock_irq(&intfdata->susp_lock);
}
- spin_lock_irq(&intfdata->susp_lock);
intfdata->suspended = 0;
spin_unlock_irq(&intfdata->susp_lock);
-err_out:
- return err;
+
+ if (err_count)
+ return -EIO;
+
+ return 0;
}
EXPORT_SYMBOL(usb_wwan_resume);
#endif
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index 1129aa73c23..bf2bd40e5f2 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -16,7 +16,6 @@
#include <linux/kernel.h>
#include <linux/errno.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
@@ -51,7 +50,7 @@ static int palm_os_3_probe(struct usb_serial *serial,
static int palm_os_4_probe(struct usb_serial *serial,
const struct usb_device_id *id);
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID),
.driver_info = (kernel_ulong_t)&palm_os_3_probe },
{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_TREO_ID),
@@ -113,18 +112,18 @@ static struct usb_device_id id_table [] = {
{ } /* Terminating entry */
};
-static struct usb_device_id clie_id_5_table [] = {
+static const struct usb_device_id clie_id_5_table[] = {
{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_UX50_ID),
.driver_info = (kernel_ulong_t)&palm_os_4_probe },
{ } /* Terminating entry */
};
-static struct usb_device_id clie_id_3_5_table [] = {
+static const struct usb_device_id clie_id_3_5_table[] = {
{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_3_5_ID) },
{ } /* Terminating entry */
};
-static struct usb_device_id id_table_combined [] = {
+static const struct usb_device_id id_table_combined[] = {
{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID) },
{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_TREO_ID) },
{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_TREO600_ID) },
@@ -257,24 +256,18 @@ static void visor_close(struct usb_serial_port *port)
{
unsigned char *transfer_buffer;
- /* shutdown our urbs */
usb_serial_generic_close(port);
usb_kill_urb(port->interrupt_in_urb);
- mutex_lock(&port->serial->disc_mutex);
- if (!port->serial->disconnected) {
- /* Try to send shutdown message, unless the device is gone */
- transfer_buffer = kmalloc(0x12, GFP_KERNEL);
- if (transfer_buffer) {
- usb_control_msg(port->serial->dev,
+ transfer_buffer = kmalloc(0x12, GFP_KERNEL);
+ if (!transfer_buffer)
+ return;
+ usb_control_msg(port->serial->dev,
usb_rcvctrlpipe(port->serial->dev, 0),
VISOR_CLOSE_NOTIFICATION, 0xc2,
0x0000, 0x0000,
transfer_buffer, 0x12, 300);
- kfree(transfer_buffer);
- }
- }
- mutex_unlock(&port->serial->disc_mutex);
+ kfree(transfer_buffer);
}
static void visor_read_int_callback(struct urb *urb)
@@ -330,11 +323,8 @@ static int palm_os_3_probe(struct usb_serial *serial,
int num_ports = 0;
transfer_buffer = kmalloc(sizeof(*connection_info), GFP_KERNEL);
- if (!transfer_buffer) {
- dev_err(dev, "%s - kmalloc(%Zd) failed.\n", __func__,
- sizeof(*connection_info));
+ if (!transfer_buffer)
return -ENOMEM;
- }
/* send a get connection info request */
retval = usb_control_msg(serial->dev,
@@ -425,11 +415,8 @@ static int palm_os_4_probe(struct usb_serial *serial,
int retval;
transfer_buffer = kmalloc(sizeof(*connection_info), GFP_KERNEL);
- if (!transfer_buffer) {
- dev_err(dev, "%s - kmalloc(%Zd) failed.\n", __func__,
- sizeof(*connection_info));
+ if (!transfer_buffer)
return -ENOMEM;
- }
retval = usb_control_msg(serial->dev,
usb_rcvctrlpipe(serial->dev, 0),
@@ -566,10 +553,19 @@ static int treo_attach(struct usb_serial *serial)
*/
#define COPY_PORT(dest, src) \
do { \
+ int i; \
+ \
+ for (i = 0; i < ARRAY_SIZE(src->read_urbs); ++i) { \
+ dest->read_urbs[i] = src->read_urbs[i]; \
+ dest->read_urbs[i]->context = dest; \
+ dest->bulk_in_buffers[i] = src->bulk_in_buffers[i]; \
+ } \
dest->read_urb = src->read_urb; \
dest->bulk_in_endpointAddress = src->bulk_in_endpointAddress;\
dest->bulk_in_buffer = src->bulk_in_buffer; \
+ dest->bulk_in_size = src->bulk_in_size; \
dest->interrupt_in_urb = src->interrupt_in_urb; \
+ dest->interrupt_in_urb->context = dest; \
dest->interrupt_in_endpointAddress = \
src->interrupt_in_endpointAddress;\
dest->interrupt_in_buffer = src->interrupt_in_buffer; \
diff --git a/drivers/usb/serial/visor.h b/drivers/usb/serial/visor.h
index 88db4d06aef..4c456dd69ce 100644
--- a/drivers/usb/serial/visor.h
+++ b/drivers/usb/serial/visor.h
@@ -136,7 +136,7 @@ struct visor_connection_info {
* connections.end_point_info is non-zero. If value is 0, then
* connections.port contains the endpoint number, which is the same for in
* and out.
- * @port_function_id: contains the creator id of the applicaton that opened
+ * @port_function_id: contains the creator id of the application that opened
* this connection.
* @port: contains the in/out endpoint number. Is 0 if in and out endpoint
* numbers are different.
diff --git a/drivers/usb/serial/vivopay-serial.c b/drivers/usb/serial/vivopay-serial.c
deleted file mode 100644
index 6299526ff8c..00000000000
--- a/drivers/usb/serial/vivopay-serial.c
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2001-2005 Greg Kroah-Hartman (greg@kroah.com)
- * Copyright (C) 2009 Outpost Embedded, LLC
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/tty.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/usb/serial.h>
-
-#define DRIVER_DESC "ViVOpay USB Serial Driver"
-
-#define VIVOPAY_VENDOR_ID 0x1d5f
-
-
-static struct usb_device_id id_table [] = {
- /* ViVOpay 8800 */
- { USB_DEVICE(VIVOPAY_VENDOR_ID, 0x1004) },
- { },
-};
-
-MODULE_DEVICE_TABLE(usb, id_table);
-
-static struct usb_serial_driver vivopay_serial_device = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "vivopay-serial",
- },
- .id_table = id_table,
- .num_ports = 1,
-};
-
-static struct usb_serial_driver * const serial_drivers[] = {
- &vivopay_serial_device, NULL
-};
-
-module_usb_serial_driver(serial_drivers, id_table);
-
-MODULE_AUTHOR("Forest Bond <forest.bond@outpostembedded.com>");
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index b9fca3586d7..e62f2dff8b7 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -18,7 +18,6 @@
#include <linux/kernel.h>
#include <linux/errno.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
@@ -288,12 +287,8 @@ static int whiteheat_attach(struct usb_serial *serial)
command_info = kmalloc(sizeof(struct whiteheat_command_private),
GFP_KERNEL);
- if (command_info == NULL) {
- dev_err(&serial->dev->dev,
- "%s: Out of memory for port structures\n",
- serial->type->description);
+ if (!command_info)
goto no_command_private;
- }
mutex_init(&command_info->mutex);
command_info->port_running = 0;
@@ -455,14 +450,12 @@ static int whiteheat_ioctl(struct tty_struct *tty,
struct serial_struct serstruct;
void __user *user_arg = (void __user *)arg;
- dev_dbg(&port->dev, "%s - cmd 0x%.4x\n", __func__, cmd);
-
switch (cmd) {
case TIOCGSERIAL:
memset(&serstruct, 0, sizeof(serstruct));
serstruct.type = PORT_16654;
- serstruct.line = port->serial->minor;
- serstruct.port = port->number;
+ serstruct.line = port->minor;
+ serstruct.port = port->port_number;
serstruct.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
serstruct.xmit_fifo_size = kfifo_size(&port->write_fifo);
serstruct.custom_divisor = 0;
@@ -626,7 +619,7 @@ static int firm_open(struct usb_serial_port *port)
{
struct whiteheat_simple open_command;
- open_command.port = port->number - port->serial->minor + 1;
+ open_command.port = port->port_number + 1;
return firm_send_command(port, WHITEHEAT_OPEN,
(__u8 *)&open_command, sizeof(open_command));
}
@@ -636,7 +629,7 @@ static int firm_close(struct usb_serial_port *port)
{
struct whiteheat_simple close_command;
- close_command.port = port->number - port->serial->minor + 1;
+ close_command.port = port->port_number + 1;
return firm_send_command(port, WHITEHEAT_CLOSE,
(__u8 *)&close_command, sizeof(close_command));
}
@@ -649,7 +642,7 @@ static void firm_setup_port(struct tty_struct *tty)
struct whiteheat_port_settings port_settings;
unsigned int cflag = tty->termios.c_cflag;
- port_settings.port = port->number + 1;
+ port_settings.port = port->port_number + 1;
/* get the byte size */
switch (cflag & CSIZE) {
@@ -726,7 +719,7 @@ static int firm_set_rts(struct usb_serial_port *port, __u8 onoff)
{
struct whiteheat_set_rdb rts_command;
- rts_command.port = port->number - port->serial->minor + 1;
+ rts_command.port = port->port_number + 1;
rts_command.state = onoff;
return firm_send_command(port, WHITEHEAT_SET_RTS,
(__u8 *)&rts_command, sizeof(rts_command));
@@ -737,7 +730,7 @@ static int firm_set_dtr(struct usb_serial_port *port, __u8 onoff)
{
struct whiteheat_set_rdb dtr_command;
- dtr_command.port = port->number - port->serial->minor + 1;
+ dtr_command.port = port->port_number + 1;
dtr_command.state = onoff;
return firm_send_command(port, WHITEHEAT_SET_DTR,
(__u8 *)&dtr_command, sizeof(dtr_command));
@@ -748,7 +741,7 @@ static int firm_set_break(struct usb_serial_port *port, __u8 onoff)
{
struct whiteheat_set_rdb break_command;
- break_command.port = port->number - port->serial->minor + 1;
+ break_command.port = port->port_number + 1;
break_command.state = onoff;
return firm_send_command(port, WHITEHEAT_SET_BREAK,
(__u8 *)&break_command, sizeof(break_command));
@@ -759,7 +752,7 @@ static int firm_purge(struct usb_serial_port *port, __u8 rxtx)
{
struct whiteheat_purge purge_command;
- purge_command.port = port->number - port->serial->minor + 1;
+ purge_command.port = port->port_number + 1;
purge_command.what = rxtx;
return firm_send_command(port, WHITEHEAT_PURGE,
(__u8 *)&purge_command, sizeof(purge_command));
@@ -770,7 +763,7 @@ static int firm_get_dtr_rts(struct usb_serial_port *port)
{
struct whiteheat_simple get_dr_command;
- get_dr_command.port = port->number - port->serial->minor + 1;
+ get_dr_command.port = port->port_number + 1;
return firm_send_command(port, WHITEHEAT_GET_DTR_RTS,
(__u8 *)&get_dr_command, sizeof(get_dr_command));
}
@@ -780,7 +773,7 @@ static int firm_report_tx_done(struct usb_serial_port *port)
{
struct whiteheat_simple close_command;
- close_command.port = port->number - port->serial->minor + 1;
+ close_command.port = port->port_number + 1;
return firm_send_command(port, WHITEHEAT_REPORT_TX_DONE,
(__u8 *)&close_command, sizeof(close_command));
}
diff --git a/drivers/usb/serial/wishbone-serial.c b/drivers/usb/serial/wishbone-serial.c
new file mode 100644
index 00000000000..4fed4a0bd70
--- /dev/null
+++ b/drivers/usb/serial/wishbone-serial.c
@@ -0,0 +1,94 @@
+/*
+ * USB Wishbone-Serial adapter driver
+ *
+ * Copyright (C) 2013 Wesley W. Terpstra <w.terpstra@gsi.de>
+ * Copyright (C) 2013 GSI Helmholtz Centre for Heavy Ion Research GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+#include <linux/uaccess.h>
+
+#define GSI_VENDOR_OPENCLOSE 0xB0
+
+static const struct usb_device_id id_table[] = {
+ { USB_DEVICE_AND_INTERFACE_INFO(0x1D50, 0x6062, 0xFF, 0xFF, 0xFF) },
+ { },
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+/*
+ * Etherbone must be told that a new stream has begun before data arrives.
+ * This is necessary to restart the negotiation of Wishbone bus parameters.
+ * Similarly, when the stream ends, Etherbone must be told so that the cycle
+ * line can be driven low in the case that userspace failed to do so.
+ */
+static int usb_gsi_openclose(struct usb_serial_port *port, int value)
+{
+ struct usb_device *dev = port->serial->dev;
+
+ return usb_control_msg(
+ dev,
+ usb_sndctrlpipe(dev, 0), /* Send to EP0OUT */
+ GSI_VENDOR_OPENCLOSE,
+ USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE,
+ value, /* wValue = device is open(1) or closed(0) */
+ port->serial->interface->cur_altsetting->desc.bInterfaceNumber,
+ NULL, 0, /* There is no data stage */
+ 5000); /* Timeout till operation fails */
+}
+
+static int wishbone_serial_open(struct tty_struct *tty,
+ struct usb_serial_port *port)
+{
+ int retval;
+
+ retval = usb_gsi_openclose(port, 1);
+ if (retval) {
+ dev_err(&port->serial->dev->dev,
+ "Could not mark device as open (%d)\n",
+ retval);
+ return retval;
+ }
+
+ retval = usb_serial_generic_open(tty, port);
+ if (retval)
+ usb_gsi_openclose(port, 0);
+
+ return retval;
+}
+
+static void wishbone_serial_close(struct usb_serial_port *port)
+{
+ usb_serial_generic_close(port);
+ usb_gsi_openclose(port, 0);
+}
+
+static struct usb_serial_driver wishbone_serial_device = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "wishbone_serial",
+ },
+ .id_table = id_table,
+ .num_ports = 1,
+ .open = &wishbone_serial_open,
+ .close = &wishbone_serial_close,
+};
+
+static struct usb_serial_driver * const serial_drivers[] = {
+ &wishbone_serial_device, NULL
+};
+
+module_usb_serial_driver(serial_drivers, id_table);
+
+MODULE_AUTHOR("Wesley W. Terpstra <w.terpstra@gsi.de>");
+MODULE_DESCRIPTION("USB Wishbone-Serial adapter");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/xsens_mt.c b/drivers/usb/serial/xsens_mt.c
new file mode 100644
index 00000000000..4841fb57400
--- /dev/null
+++ b/drivers/usb/serial/xsens_mt.c
@@ -0,0 +1,85 @@
+/*
+ * Xsens MT USB driver
+ *
+ * Copyright (C) 2013 Xsens <info@xsens.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+#include <linux/uaccess.h>
+
+#define XSENS_VID 0x2639
+
+#define MTi_10_IMU_PID 0x0001
+#define MTi_20_VRU_PID 0x0002
+#define MTi_30_AHRS_PID 0x0003
+
+#define MTi_100_IMU_PID 0x0011
+#define MTi_200_VRU_PID 0x0012
+#define MTi_300_AHRS_PID 0x0013
+
+#define MTi_G_700_GPS_INS_PID 0x0017
+
+static const struct usb_device_id id_table[] = {
+ { USB_DEVICE(XSENS_VID, MTi_10_IMU_PID) },
+ { USB_DEVICE(XSENS_VID, MTi_20_VRU_PID) },
+ { USB_DEVICE(XSENS_VID, MTi_30_AHRS_PID) },
+
+ { USB_DEVICE(XSENS_VID, MTi_100_IMU_PID) },
+ { USB_DEVICE(XSENS_VID, MTi_200_VRU_PID) },
+ { USB_DEVICE(XSENS_VID, MTi_300_AHRS_PID) },
+
+ { USB_DEVICE(XSENS_VID, MTi_G_700_GPS_INS_PID) },
+ { },
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+static int has_required_endpoints(const struct usb_host_interface *interface)
+{
+ __u8 i;
+ int has_bulk_in = 0;
+ int has_bulk_out = 0;
+
+ for (i = 0; i < interface->desc.bNumEndpoints; ++i) {
+ if (usb_endpoint_is_bulk_in(&interface->endpoint[i].desc))
+ has_bulk_in = 1;
+ else if (usb_endpoint_is_bulk_out(&interface->endpoint[i].desc))
+ has_bulk_out = 1;
+ }
+
+ return has_bulk_in && has_bulk_out;
+}
+
+static int xsens_mt_probe(struct usb_serial *serial,
+ const struct usb_device_id *id)
+{
+ if (!has_required_endpoints(serial->interface->cur_altsetting))
+ return -ENODEV;
+ return 0;
+}
+
+static struct usb_serial_driver xsens_mt_device = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "xsens_mt",
+ },
+ .id_table = id_table,
+ .num_ports = 1,
+
+ .probe = xsens_mt_probe,
+};
+
+static struct usb_serial_driver * const serial_drivers[] = {
+ &xsens_mt_device, NULL
+};
+
+module_usb_serial_driver(serial_drivers, id_table);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/zio.c b/drivers/usb/serial/zio.c
deleted file mode 100644
index c043aa84a0b..00000000000
--- a/drivers/usb/serial/zio.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * ZIO Motherboard USB driver
- *
- * Copyright (C) 2010 Zilogic Systems <code@zilogic.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/tty.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/usb/serial.h>
-#include <linux/uaccess.h>
-
-static const struct usb_device_id id_table[] = {
- { USB_DEVICE(0x1CBE, 0x0103) },
- { },
-};
-MODULE_DEVICE_TABLE(usb, id_table);
-
-static struct usb_serial_driver zio_device = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "zio",
- },
- .id_table = id_table,
- .num_ports = 1,
-};
-
-static struct usb_serial_driver * const serial_drivers[] = {
- &zio_device, NULL
-};
-
-module_usb_serial_driver(serial_drivers, id_table);
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/zte_ev.c b/drivers/usb/serial/zte_ev.c
index 39ee7373b4e..e40ab739c4a 100644
--- a/drivers/usb/serial/zte_ev.c
+++ b/drivers/usb/serial/zte_ev.c
@@ -13,7 +13,6 @@
* show the commands used to talk to the device, but I am not sure.
*/
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/module.h>
@@ -41,9 +40,6 @@ static int zte_ev_usb_serial_open(struct tty_struct *tty,
int len;
unsigned char *buf;
- if (port->number != 0)
- return -ENODEV;
-
buf = kmalloc(MAX_SETUP_DATA_SIZE, GFP_KERNEL);
if (!buf)
return -ENOMEM;
@@ -53,10 +49,10 @@ static int zte_ev_usb_serial_open(struct tty_struct *tty,
result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
0x22, 0x21,
0x0001, 0x0000, NULL, len,
- HZ * USB_CTRL_GET_TIMEOUT);
+ USB_CTRL_GET_TIMEOUT);
dev_dbg(dev, "result = %d\n", result);
- /* send 2st cmd and recieve data */
+ /* send 2st cmd and receive data */
/*
* 16.0 CTL a1 21 00 00 00 00 07 00 CLASS 25.1.0(5)
* 16.0 DI 00 96 00 00 00 00 08
@@ -65,10 +61,10 @@ static int zte_ev_usb_serial_open(struct tty_struct *tty,
result = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
0x21, 0xa1,
0x0000, 0x0000, buf, len,
- HZ * USB_CTRL_GET_TIMEOUT);
+ USB_CTRL_GET_TIMEOUT);
debug_data(dev, __func__, len, buf, result);
- /* send 3 cmd */
+ /* send 3rd cmd */
/*
* 16.0 CTL 21 20 00 00 00 00 07 00 CLASS 30.1.0
* 16.0 DO 80 25 00 00 00 00 08 .%..... 30.2.0
@@ -84,10 +80,10 @@ static int zte_ev_usb_serial_open(struct tty_struct *tty,
result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
0x20, 0x21,
0x0000, 0x0000, buf, len,
- HZ * USB_CTRL_GET_TIMEOUT);
+ USB_CTRL_GET_TIMEOUT);
debug_data(dev, __func__, len, buf, result);
- /* send 4 cmd */
+ /* send 4th cmd */
/*
* 16.0 CTL 21 22 03 00 00 00 00 00
*/
@@ -95,10 +91,10 @@ static int zte_ev_usb_serial_open(struct tty_struct *tty,
result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
0x22, 0x21,
0x0003, 0x0000, NULL, len,
- HZ * USB_CTRL_GET_TIMEOUT);
+ USB_CTRL_GET_TIMEOUT);
dev_dbg(dev, "result = %d\n", result);
- /* send 5 cmd */
+ /* send 5th cmd */
/*
* 16.0 CTL a1 21 00 00 00 00 07 00 CLASS 33.1.0
* 16.0 DI 80 25 00 00 00 00 08
@@ -107,10 +103,10 @@ static int zte_ev_usb_serial_open(struct tty_struct *tty,
result = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
0x21, 0xa1,
0x0000, 0x0000, buf, len,
- HZ * USB_CTRL_GET_TIMEOUT);
+ USB_CTRL_GET_TIMEOUT);
debug_data(dev, __func__, len, buf, result);
- /* send 6 cmd */
+ /* send 6th cmd */
/*
* 16.0 CTL 21 20 00 00 00 00 07 00 CLASS 34.1.0
* 16.0 DO 80 25 00 00 00 00 08
@@ -126,7 +122,7 @@ static int zte_ev_usb_serial_open(struct tty_struct *tty,
result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
0x20, 0x21,
0x0000, 0x0000, buf, len,
- HZ * USB_CTRL_GET_TIMEOUT);
+ USB_CTRL_GET_TIMEOUT);
debug_data(dev, __func__, len, buf, result);
kfree(buf);
@@ -166,9 +162,6 @@ static void zte_ev_usb_serial_close(struct usb_serial_port *port)
int len;
unsigned char *buf;
- if (port->number != 0)
- return;
-
buf = kmalloc(MAX_SETUP_DATA_SIZE, GFP_KERNEL);
if (!buf)
return;
@@ -178,7 +171,7 @@ static void zte_ev_usb_serial_close(struct usb_serial_port *port)
result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
0x22, 0x21,
0x0002, 0x0000, NULL, len,
- HZ * USB_CTRL_GET_TIMEOUT);
+ USB_CTRL_GET_TIMEOUT);
dev_dbg(dev, "result = %d\n", result);
/* send 2st ctl cmd(CTL 21 22 03 00 00 00 00 00 ) */
@@ -186,7 +179,7 @@ static void zte_ev_usb_serial_close(struct usb_serial_port *port)
result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
0x22, 0x21,
0x0003, 0x0000, NULL, len,
- HZ * USB_CTRL_GET_TIMEOUT);
+ USB_CTRL_GET_TIMEOUT);
dev_dbg(dev, "result = %d\n", result);
/* send 3st cmd and recieve data */
@@ -198,10 +191,10 @@ static void zte_ev_usb_serial_close(struct usb_serial_port *port)
result = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
0x21, 0xa1,
0x0000, 0x0000, buf, len,
- HZ * USB_CTRL_GET_TIMEOUT);
+ USB_CTRL_GET_TIMEOUT);
debug_data(dev, __func__, len, buf, result);
- /* send 4 cmd */
+ /* send 4th cmd */
/*
* 16.0 CTL 21 20 00 00 00 00 07 00 CLASS 30.1.0
* 16.0 DO 00 c2 01 00 00 00 08 .%..... 30.2.0
@@ -217,10 +210,10 @@ static void zte_ev_usb_serial_close(struct usb_serial_port *port)
result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
0x20, 0x21,
0x0000, 0x0000, buf, len,
- HZ * USB_CTRL_GET_TIMEOUT);
+ USB_CTRL_GET_TIMEOUT);
debug_data(dev, __func__, len, buf, result);
- /* send 5 cmd */
+ /* send 5th cmd */
/*
* 16.0 CTL 21 22 03 00 00 00 00 00
*/
@@ -228,10 +221,10 @@ static void zte_ev_usb_serial_close(struct usb_serial_port *port)
result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
0x22, 0x21,
0x0003, 0x0000, NULL, len,
- HZ * USB_CTRL_GET_TIMEOUT);
+ USB_CTRL_GET_TIMEOUT);
dev_dbg(dev, "result = %d\n", result);
- /* send 6 cmd */
+ /* send 6th cmd */
/*
* 16.0 CTL a1 21 00 00 00 00 07 00 CLASS 33.1.0
* 16.0 DI 00 c2 01 00 00 00 08
@@ -240,10 +233,10 @@ static void zte_ev_usb_serial_close(struct usb_serial_port *port)
result = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
0x21, 0xa1,
0x0000, 0x0000, buf, len,
- HZ * USB_CTRL_GET_TIMEOUT);
+ USB_CTRL_GET_TIMEOUT);
debug_data(dev, __func__, len, buf, result);
- /* send 7 cmd */
+ /* send 7th cmd */
/*
* 16.0 CTL 21 20 00 00 00 00 07 00 CLASS 354.1.0
* 16.0 DO 00 c2 01 00 00 00 08 ....... 354.2.0
@@ -259,10 +252,10 @@ static void zte_ev_usb_serial_close(struct usb_serial_port *port)
result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
0x20, 0x21,
0x0000, 0x0000, buf, len,
- HZ * USB_CTRL_GET_TIMEOUT);
+ USB_CTRL_GET_TIMEOUT);
debug_data(dev, __func__, len, buf, result);
- /* send 8 cmd */
+ /* send 8th cmd */
/*
* 16.0 CTL 21 22 03 00 00 00 00 00
*/
@@ -270,7 +263,7 @@ static void zte_ev_usb_serial_close(struct usb_serial_port *port)
result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
0x22, 0x21,
0x0003, 0x0000, NULL, len,
- HZ * USB_CTRL_GET_TIMEOUT);
+ USB_CTRL_GET_TIMEOUT);
dev_dbg(dev, "result = %d\n", result);
kfree(buf);
@@ -279,11 +272,28 @@ static void zte_ev_usb_serial_close(struct usb_serial_port *port)
}
static const struct usb_device_id id_table[] = {
- { USB_DEVICE(0x19d2, 0xffff) }, /* AC8700 */
- { USB_DEVICE(0x19d2, 0xfffe) },
- { USB_DEVICE(0x19d2, 0xfffd) }, /* MG880 */
+ /* AC8710, AC8710T */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x19d2, 0xffff, 0xff, 0xff, 0xff) },
+ /* AC8700 */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x19d2, 0xfffe, 0xff, 0xff, 0xff) },
+ /* MG880 */
+ { USB_DEVICE(0x19d2, 0xfffd) },
+ { USB_DEVICE(0x19d2, 0xfffc) },
+ { USB_DEVICE(0x19d2, 0xfffb) },
+ /* AC8710_V3 */
+ { USB_DEVICE(0x19d2, 0xfff6) },
+ { USB_DEVICE(0x19d2, 0xfff7) },
+ { USB_DEVICE(0x19d2, 0xfff8) },
+ { USB_DEVICE(0x19d2, 0xfff9) },
+ { USB_DEVICE(0x19d2, 0xffee) },
+ /* AC2716, MC2716 */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x19d2, 0xffed, 0xff, 0xff, 0xff) },
+ /* AD3812 */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x19d2, 0xffeb, 0xff, 0xff, 0xff) },
+ { USB_DEVICE(0x19d2, 0xffec) },
{ USB_DEVICE(0x05C6, 0x3197) },
{ USB_DEVICE(0x05C6, 0x6000) },
+ { USB_DEVICE(0x05C6, 0x9008) },
{ },
};
MODULE_DEVICE_TABLE(usb, id_table);