summaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/serial')
-rw-r--r--drivers/usb/serial/Kconfig19
-rw-r--r--drivers/usb/serial/Makefile1
-rw-r--r--drivers/usb/serial/ark3116.c87
-rw-r--r--drivers/usb/serial/bus.c5
-rw-r--r--drivers/usb/serial/ch341.c30
-rw-r--r--drivers/usb/serial/cp210x.c6
-rw-r--r--drivers/usb/serial/cyberjack.c19
-rw-r--r--drivers/usb/serial/cypress_m8.c94
-rw-r--r--drivers/usb/serial/digi_acceleport.c95
-rw-r--r--drivers/usb/serial/f81232.c13
-rw-r--r--drivers/usb/serial/ftdi_sio.c144
-rw-r--r--drivers/usb/serial/ftdi_sio_ids.h4
-rw-r--r--drivers/usb/serial/garmin_gps.c10
-rw-r--r--drivers/usb/serial/generic.c144
-rw-r--r--drivers/usb/serial/io_edgeport.c76
-rw-r--r--drivers/usb/serial/io_tables.h12
-rw-r--r--drivers/usb/serial/io_ti.c98
-rw-r--r--drivers/usb/serial/iuu_phoenix.c21
-rw-r--r--drivers/usb/serial/keyspan.c96
-rw-r--r--drivers/usb/serial/keyspan_pda.c19
-rw-r--r--drivers/usb/serial/kl5kusb105.c30
-rw-r--r--drivers/usb/serial/kobil_sct.c103
-rw-r--r--drivers/usb/serial/mct_u232.c131
-rw-r--r--drivers/usb/serial/metro-usb.c5
-rw-r--r--drivers/usb/serial/mos7720.c68
-rw-r--r--drivers/usb/serial/mos7840.c157
-rw-r--r--drivers/usb/serial/omninet.c81
-rw-r--r--drivers/usb/serial/opticon.c18
-rw-r--r--drivers/usb/serial/option.c8
-rw-r--r--drivers/usb/serial/oti6858.c30
-rw-r--r--drivers/usb/serial/pl2303.c39
-rw-r--r--drivers/usb/serial/quatech2.c97
-rw-r--r--drivers/usb/serial/sierra.c39
-rw-r--r--drivers/usb/serial/spcp8x5.c301
-rw-r--r--drivers/usb/serial/ssu100.c100
-rw-r--r--drivers/usb/serial/symbolserial.c130
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.c163
-rw-r--r--drivers/usb/serial/usb-serial.c230
-rw-r--r--drivers/usb/serial/usb_wwan.c25
-rw-r--r--drivers/usb/serial/visor.c16
-rw-r--r--drivers/usb/serial/wishbone-serial.c95
41 files changed, 885 insertions, 1974 deletions
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index 17b7f9a..1d55762 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 && TTY
+ 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
@@ -667,6 +667,23 @@ config USB_SERIAL_ZIO
To compile this driver as a module, choose M here: the
module will be called zio.
+config USB_SERIAL_WISHBONE
+ tristate "USB-Wishbone adapter interface driver"
+ help
+ 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 wishbone-serial.
+
config USB_SERIAL_ZTE
tristate "ZTE USB serial driver"
help
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index eaf5ca1..cec63fa 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -58,6 +58,7 @@ 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
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
index 4775f82..3b16118 100644
--- a/drivers/usb/serial/ark3116.c
+++ b/drivers/usb/serial/ark3116.c
@@ -62,7 +62,6 @@ static int is_irda(struct usb_serial *serial)
}
struct ark3116_private {
- struct async_icount icount;
int irda; /* 1 for irda device */
/* protects hw register updates */
@@ -341,18 +340,15 @@ static void ark3116_close(struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
- if (serial->dev) {
- /* disable DMA */
- ark3116_write_reg(serial, UART_FCR, 0);
-
- /* deactivate interrupts */
- ark3116_write_reg(serial, UART_IER, 0);
+ /* disable DMA */
+ ark3116_write_reg(serial, UART_FCR, 0);
- usb_serial_generic_close(port);
- if (serial->num_interrupt_in)
- usb_kill_urb(port->interrupt_in_urb);
- }
+ /* deactivate interrupts */
+ ark3116_write_reg(serial, UART_IER, 0);
+ usb_serial_generic_close(port);
+ if (serial->num_interrupt_in)
+ usb_kill_urb(port->interrupt_in_urb);
}
static int ark3116_open(struct tty_struct *tty, struct usb_serial_port *port)
@@ -405,31 +401,10 @@ err_out:
return result;
}
-static int ark3116_get_icount(struct tty_struct *tty,
- struct serial_icounter_struct *icount)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct ark3116_private *priv = usb_get_serial_port_data(port);
- struct async_icount cnow = priv->icount;
- icount->cts = cnow.cts;
- icount->dsr = cnow.dsr;
- icount->rng = cnow.rng;
- icount->dcd = cnow.dcd;
- icount->rx = cnow.rx;
- icount->tx = cnow.tx;
- icount->frame = cnow.frame;
- icount->overrun = cnow.overrun;
- icount->parity = cnow.parity;
- icount->brk = cnow.brk;
- icount->buf_overrun = cnow.buf_overrun;
- return 0;
-}
-
static int ark3116_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
struct usb_serial_port *port = tty->driver_data;
- struct ark3116_private *priv = usb_get_serial_port_data(port);
struct serial_struct serstruct;
void __user *user_arg = (void __user *)arg;
@@ -451,33 +426,6 @@ static int ark3116_ioctl(struct tty_struct *tty,
if (copy_from_user(&serstruct, user_arg, sizeof(serstruct)))
return -EFAULT;
return 0;
- case TIOCMIWAIT:
- for (;;) {
- struct async_icount prev = priv->icount;
- interruptible_sleep_on(&port->delta_msr_wait);
- /* see if a signal did it */
- if (signal_pending(current))
- return -ERESTARTSYS;
-
- if (port->serial->disconnected)
- return -EIO;
-
- if ((prev.rng == priv->icount.rng) &&
- (prev.dsr == priv->icount.dsr) &&
- (prev.dcd == priv->icount.dcd) &&
- (prev.cts == priv->icount.cts))
- return -EIO;
- if ((arg & TIOCM_RNG &&
- (prev.rng != priv->icount.rng)) ||
- (arg & TIOCM_DSR &&
- (prev.dsr != priv->icount.dsr)) ||
- (arg & TIOCM_CD &&
- (prev.dcd != priv->icount.dcd)) ||
- (arg & TIOCM_CTS &&
- (prev.cts != priv->icount.cts)))
- return 0;
- }
- break;
}
return -ENOIOCTLCMD;
@@ -575,14 +523,14 @@ static void ark3116_update_msr(struct usb_serial_port *port, __u8 msr)
if (msr & UART_MSR_ANY_DELTA) {
/* update input line counters */
if (msr & UART_MSR_DCTS)
- priv->icount.cts++;
+ port->icount.cts++;
if (msr & UART_MSR_DDSR)
- priv->icount.dsr++;
+ port->icount.dsr++;
if (msr & UART_MSR_DDCD)
- priv->icount.dcd++;
+ port->icount.dcd++;
if (msr & UART_MSR_TERI)
- priv->icount.rng++;
- wake_up_interruptible(&port->delta_msr_wait);
+ port->icount.rng++;
+ wake_up_interruptible(&port->port.delta_msr_wait);
}
}
@@ -598,13 +546,13 @@ static void ark3116_update_lsr(struct usb_serial_port *port, __u8 lsr)
if (lsr&UART_LSR_BRK_ERROR_BITS) {
if (lsr & UART_LSR_BI)
- priv->icount.brk++;
+ port->icount.brk++;
if (lsr & UART_LSR_FE)
- priv->icount.frame++;
+ port->icount.frame++;
if (lsr & UART_LSR_PE)
- priv->icount.parity++;
+ port->icount.parity++;
if (lsr & UART_LSR_OE)
- priv->icount.overrun++;
+ port->icount.overrun++;
}
}
@@ -722,7 +670,8 @@ static struct usb_serial_driver ark3116_device = {
.ioctl = ark3116_ioctl,
.tiocmget = ark3116_tiocmget,
.tiocmset = ark3116_tiocmset,
- .get_icount = ark3116_get_icount,
+ .tiocmiwait = usb_serial_generic_tiocmiwait,
+ .get_icount = usb_serial_generic_get_icount,
.open = ark3116_open,
.close = ark3116_close,
.break_ctl = ark3116_break_ctl,
diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c
index 37decb1..3c4db6d 100644
--- a/drivers/usb/serial/bus.c
+++ b/drivers/usb/serial/bus.c
@@ -106,14 +106,15 @@ static int usb_serial_device_remove(struct device *dev)
/* make sure suspend/resume doesn't race against port_remove */
usb_autopm_get_interface(port->serial->interface);
+ minor = port->number;
+ tty_unregister_device(usb_serial_tty_driver, minor);
+
device_remove_file(&port->dev, &dev_attr_port_number);
driver = port->serial->type;
if (driver->port_remove)
retval = driver->port_remove(port);
- minor = port->number;
- tty_unregister_device(usb_serial_tty_driver, minor);
dev_info(dev, "%s converter now disconnected from ttyUSB%d\n",
driver->description, minor);
diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c
index 07d4650..c2a4171 100644
--- a/drivers/usb/serial/ch341.c
+++ b/drivers/usb/serial/ch341.c
@@ -296,7 +296,6 @@ static void ch341_dtr_rts(struct usb_serial_port *port, int on)
priv->line_control &= ~(CH341_BIT_RTS | CH341_BIT_DTR);
spin_unlock_irqrestore(&priv->lock, flags);
ch341_set_handshake(port->serial->dev, priv->line_control);
- wake_up_interruptible(&port->delta_msr_wait);
}
static void ch341_close(struct usb_serial_port *port)
@@ -489,7 +488,7 @@ static void ch341_read_int_callback(struct urb *urb)
tty_kref_put(tty);
}
- wake_up_interruptible(&port->delta_msr_wait);
+ wake_up_interruptible(&port->port.delta_msr_wait);
}
exit:
@@ -500,8 +499,9 @@ exit:
__func__, status);
}
-static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
+static int ch341_tiocmiwait(struct tty_struct *tty, unsigned long arg)
{
+ struct usb_serial_port *port = tty->driver_data;
struct ch341_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
u8 prevstatus;
@@ -515,7 +515,7 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
spin_unlock_irqrestore(&priv->lock, flags);
while (!multi_change) {
- interruptible_sleep_on(&port->delta_msr_wait);
+ interruptible_sleep_on(&port->port.delta_msr_wait);
/* see if a signal did it */
if (signal_pending(current))
return -ERESTARTSYS;
@@ -542,26 +542,6 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
return 0;
}
-static int ch341_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
-{
- struct usb_serial_port *port = tty->driver_data;
-
- dev_dbg(&port->dev, "%s (%d) cmd = 0x%04x\n", __func__, port->number, cmd);
-
- switch (cmd) {
- case TIOCMIWAIT:
- dev_dbg(&port->dev, "%s (%d) TIOCMIWAIT\n", __func__, port->number);
- return wait_modem_info(port, arg);
-
- default:
- dev_dbg(&port->dev, "%s not supported = 0x%04x\n", __func__, cmd);
- break;
- }
-
- return -ENOIOCTLCMD;
-}
-
static int ch341_tiocmget(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
@@ -611,11 +591,11 @@ static struct usb_serial_driver ch341_device = {
.dtr_rts = ch341_dtr_rts,
.carrier_raised = ch341_carrier_raised,
.close = ch341_close,
- .ioctl = ch341_ioctl,
.set_termios = ch341_set_termios,
.break_ctl = ch341_break_ctl,
.tiocmget = ch341_tiocmget,
.tiocmset = ch341_tiocmset,
+ .tiocmiwait = ch341_tiocmiwait,
.read_int_callback = ch341_read_int_callback,
.port_probe = ch341_port_probe,
.port_remove = ch341_port_remove,
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index 4747d1c..2c65955 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -462,11 +462,7 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port)
static void cp210x_close(struct usb_serial_port *port)
{
usb_serial_generic_close(port);
-
- mutex_lock(&port->serial->disc_mutex);
- if (!port->serial->disconnected)
- cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_DISABLE);
- mutex_unlock(&port->serial->disc_mutex);
+ cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_DISABLE);
}
/*
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
index 629bd28..7814262 100644
--- a/drivers/usb/serial/cyberjack.c
+++ b/drivers/usb/serial/cyberjack.c
@@ -51,7 +51,6 @@
#define CYBERJACK_PRODUCT_ID 0x0100
/* Function prototypes */
-static void cyberjack_disconnect(struct usb_serial *serial);
static int cyberjack_port_probe(struct usb_serial_port *port);
static int cyberjack_port_remove(struct usb_serial_port *port);
static int cyberjack_open(struct tty_struct *tty,
@@ -79,7 +78,6 @@ static struct usb_serial_driver cyberjack_device = {
.description = "Reiner SCT Cyberjack USB card reader",
.id_table = id_table,
.num_ports = 1,
- .disconnect = cyberjack_disconnect,
.port_probe = cyberjack_port_probe,
.port_remove = cyberjack_port_remove,
.open = cyberjack_open,
@@ -130,20 +128,14 @@ static int cyberjack_port_remove(struct usb_serial_port *port)
{
struct cyberjack_private *priv;
+ usb_kill_urb(port->interrupt_in_urb);
+
priv = usb_get_serial_port_data(port);
kfree(priv);
return 0;
}
-static void cyberjack_disconnect(struct usb_serial *serial)
-{
- int i;
-
- for (i = 0; i < serial->num_ports; ++i)
- usb_kill_urb(serial->port[i]->interrupt_in_urb);
-}
-
static int cyberjack_open(struct tty_struct *tty,
struct usb_serial_port *port)
{
@@ -166,11 +158,8 @@ static int cyberjack_open(struct tty_struct *tty,
static void cyberjack_close(struct usb_serial_port *port)
{
- if (port->serial->dev) {
- /* shutdown any bulk reads that might be going on */
- usb_kill_urb(port->write_urb);
- usb_kill_urb(port->read_urb);
- }
+ usb_kill_urb(port->write_urb);
+ usb_kill_urb(port->read_urb);
}
static int cyberjack_write(struct tty_struct *tty,
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index ba7352e..d341555 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -129,13 +129,12 @@ static int cypress_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count);
static void cypress_send(struct usb_serial_port *port);
static int cypress_write_room(struct tty_struct *tty);
-static int cypress_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg);
static void cypress_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old);
static int cypress_tiocmget(struct tty_struct *tty);
static int cypress_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear);
+static int cypress_tiocmiwait(struct tty_struct *tty, unsigned long arg);
static int cypress_chars_in_buffer(struct tty_struct *tty);
static void cypress_throttle(struct tty_struct *tty);
static void cypress_unthrottle(struct tty_struct *tty);
@@ -158,10 +157,10 @@ static struct usb_serial_driver cypress_earthmate_device = {
.dtr_rts = cypress_dtr_rts,
.write = cypress_write,
.write_room = cypress_write_room,
- .ioctl = cypress_ioctl,
.set_termios = cypress_set_termios,
.tiocmget = cypress_tiocmget,
.tiocmset = cypress_tiocmset,
+ .tiocmiwait = cypress_tiocmiwait,
.chars_in_buffer = cypress_chars_in_buffer,
.throttle = cypress_throttle,
.unthrottle = cypress_unthrottle,
@@ -184,10 +183,10 @@ static struct usb_serial_driver cypress_hidcom_device = {
.dtr_rts = cypress_dtr_rts,
.write = cypress_write,
.write_room = cypress_write_room,
- .ioctl = cypress_ioctl,
.set_termios = cypress_set_termios,
.tiocmget = cypress_tiocmget,
.tiocmset = cypress_tiocmset,
+ .tiocmiwait = cypress_tiocmiwait,
.chars_in_buffer = cypress_chars_in_buffer,
.throttle = cypress_throttle,
.unthrottle = cypress_unthrottle,
@@ -210,10 +209,10 @@ static struct usb_serial_driver cypress_ca42v2_device = {
.dtr_rts = cypress_dtr_rts,
.write = cypress_write,
.write_room = cypress_write_room,
- .ioctl = cypress_ioctl,
.set_termios = cypress_set_termios,
.tiocmget = cypress_tiocmget,
.tiocmset = cypress_tiocmset,
+ .tiocmiwait = cypress_tiocmiwait,
.chars_in_buffer = cypress_chars_in_buffer,
.throttle = cypress_throttle,
.unthrottle = cypress_unthrottle,
@@ -633,12 +632,6 @@ static void cypress_close(struct usb_serial_port *port)
struct cypress_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
- /* writing is potentially harmful, lock must be taken */
- mutex_lock(&port->serial->disc_mutex);
- if (port->serial->disconnected) {
- mutex_unlock(&port->serial->disc_mutex);
- return;
- }
spin_lock_irqsave(&priv->lock, flags);
kfifo_reset_out(&priv->write_fifo);
spin_unlock_irqrestore(&priv->lock, flags);
@@ -650,7 +643,6 @@ static void cypress_close(struct usb_serial_port *port)
if (stats)
dev_info(&port->dev, "Statistics: %d Bytes In | %d Bytes Out | %d Commands Issued\n",
priv->bytes_in, priv->bytes_out, priv->cmd_count);
- mutex_unlock(&port->serial->disc_mutex);
} /* cypress_close */
@@ -855,55 +847,43 @@ static int cypress_tiocmset(struct tty_struct *tty,
}
-static int cypress_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
+static int cypress_tiocmiwait(struct tty_struct *tty, unsigned long arg)
{
struct usb_serial_port *port = tty->driver_data;
struct cypress_private *priv = usb_get_serial_port_data(port);
-
- dev_dbg(&port->dev, "%s - port %d, cmd 0x%.4x\n", __func__, port->number, cmd);
-
- switch (cmd) {
- /* This code comes from drivers/char/serial.c and ftdi_sio.c */
- case TIOCMIWAIT:
- for (;;) {
- interruptible_sleep_on(&port->delta_msr_wait);
- /* see if a signal did it */
- if (signal_pending(current))
- return -ERESTARTSYS;
-
- if (port->serial->disconnected)
- return -EIO;
-
- {
- char diff = priv->diff_status;
- if (diff == 0)
- return -EIO; /* no change => error */
-
- /* consume all events */
- priv->diff_status = 0;
-
- /* return 0 if caller wanted to know about
- these bits */
- if (((arg & TIOCM_RNG) && (diff & UART_RI)) ||
- ((arg & TIOCM_DSR) && (diff & UART_DSR)) ||
- ((arg & TIOCM_CD) && (diff & UART_CD)) ||
- ((arg & TIOCM_CTS) && (diff & UART_CTS)))
- return 0;
- /* otherwise caller can't care less about what
- * happened, and so we continue to wait for
- * more events.
- */
- }
- }
- return 0;
- default:
- break;
+ char diff;
+
+ for (;;) {
+ interruptible_sleep_on(&port->port.delta_msr_wait);
+ /* see if a signal did it */
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+
+ if (port->serial->disconnected)
+ return -EIO;
+
+ diff = priv->diff_status;
+ if (diff == 0)
+ return -EIO; /* no change => error */
+
+ /* consume all events */
+ priv->diff_status = 0;
+
+ /* return 0 if caller wanted to know about
+ these bits */
+ if (((arg & TIOCM_RNG) && (diff & UART_RI)) ||
+ ((arg & TIOCM_DSR) && (diff & UART_DSR)) ||
+ ((arg & TIOCM_CD) && (diff & UART_CD)) ||
+ ((arg & TIOCM_CTS) && (diff & UART_CTS)))
+ return 0;
+ /* otherwise caller can't care less about what
+ * happened, and so we continue to wait for
+ * more events.
+ */
}
- dev_dbg(&port->dev, "%s - arg not supported - it was 0x%04x - check include/asm/ioctls.h\n", __func__, cmd);
- return -ENOIOCTLCMD;
-} /* cypress_ioctl */
+ return 0;
+}
static void cypress_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios)
@@ -1189,7 +1169,7 @@ static void cypress_read_int_callback(struct urb *urb)
if (priv->current_status != priv->prev_status) {
priv->diff_status |= priv->current_status ^
priv->prev_status;
- wake_up_interruptible(&port->delta_msr_wait);
+ wake_up_interruptible(&port->port.delta_msr_wait);
priv->prev_status = priv->current_status;
}
spin_unlock_irqrestore(&priv->lock, flags);
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index 3119158..7b807d3 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -196,7 +196,6 @@ struct digi_port {
unsigned char dp_out_buf[DIGI_OUT_BUF_SIZE];
int dp_write_urb_in_use;
unsigned int dp_modem_signals;
- wait_queue_head_t dp_modem_change_wait;
int dp_transmit_idle;
wait_queue_head_t dp_transmit_idle_wait;
int dp_throttled;
@@ -1138,53 +1137,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;
@@ -1241,7 +1238,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);
@@ -1532,7 +1528,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/f81232.c b/drivers/usb/serial/f81232.c
index a172ad5..090b411 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -110,7 +110,7 @@ static void f81232_process_read_urb(struct urb *urb)
line_status = priv->line_status;
priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
spin_unlock_irqrestore(&priv->lock, flags);
- wake_up_interruptible(&port->delta_msr_wait);
+ wake_up_interruptible(&port->port.delta_msr_wait);
if (!urb->actual_length)
return;
@@ -242,8 +242,9 @@ static int f81232_carrier_raised(struct usb_serial_port *port)
return 0;
}
-static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
+static int f81232_tiocmiwait(struct tty_struct *tty, unsigned long arg)
{
+ struct usb_serial_port *port = tty->driver_data;
struct f81232_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
unsigned int prevstatus;
@@ -255,7 +256,7 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
spin_unlock_irqrestore(&priv->lock, flags);
while (1) {
- interruptible_sleep_on(&port->delta_msr_wait);
+ interruptible_sleep_on(&port->port.delta_msr_wait);
/* see if a signal did it */
if (signal_pending(current))
return -ERESTARTSYS;
@@ -302,11 +303,6 @@ static int f81232_ioctl(struct tty_struct *tty,
return -EFAULT;
return 0;
-
- case TIOCMIWAIT:
- dev_dbg(&port->dev, "%s (%d) TIOCMIWAIT\n", __func__,
- port->number);
- return wait_modem_info(port, arg);
default:
dev_dbg(&port->dev, "%s not supported = 0x%04x\n",
__func__, cmd);
@@ -358,6 +354,7 @@ static struct usb_serial_driver f81232_device = {
.set_termios = f81232_set_termios,
.tiocmget = f81232_tiocmget,
.tiocmset = f81232_tiocmset,
+ .tiocmiwait = f81232_tiocmiwait,
.process_read_urb = f81232_process_read_urb,
.read_int_callback = f81232_read_int_callback,
.port_probe = f81232_port_probe,
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 9886180..242b577 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)
@@ -55,7 +55,6 @@ static __u16 vendor = FTDI_VID;
static __u16 product;
struct ftdi_private {
- struct kref kref;
enum ftdi_chip_type chip_type;
/* type of device, either SIO or FT8U232AM */
int baud_base; /* baud base clock for divisor setting */
@@ -68,7 +67,6 @@ struct ftdi_private {
*/
int flags; /* some ASYNC_xxxx flags are supported */
unsigned long last_dtr_rts; /* saved modem control outputs */
- struct async_icount icount;
char prev_status; /* Used for TIOCMIWAIT */
char transmit_empty; /* If transmitter is empty or not */
__u16 interface; /* FT2232C, FT2232H or FT4232H port interface
@@ -189,6 +187,7 @@ 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(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) },
{ USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) },
@@ -870,7 +869,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),
@@ -911,7 +912,6 @@ static int ftdi_sio_probe(struct usb_serial *serial,
static int ftdi_sio_port_probe(struct usb_serial_port *port);
static int ftdi_sio_port_remove(struct usb_serial_port *port);
static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port);
-static void ftdi_close(struct usb_serial_port *port);
static void ftdi_dtr_rts(struct usb_serial_port *port, int on);
static void ftdi_process_read_urb(struct urb *urb);
static int ftdi_prepare_write_buffer(struct usb_serial_port *port,
@@ -921,8 +921,6 @@ static void ftdi_set_termios(struct tty_struct *tty,
static int ftdi_tiocmget(struct tty_struct *tty);
static int ftdi_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear);
-static int ftdi_get_icount(struct tty_struct *tty,
- struct serial_icounter_struct *icount);
static int ftdi_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg);
static void ftdi_break_ctl(struct tty_struct *tty, int break_state);
@@ -951,7 +949,6 @@ static struct usb_serial_driver ftdi_sio_device = {
.port_probe = ftdi_sio_port_probe,
.port_remove = ftdi_sio_port_remove,
.open = ftdi_open,
- .close = ftdi_close,
.dtr_rts = ftdi_dtr_rts,
.throttle = usb_serial_generic_throttle,
.unthrottle = usb_serial_generic_unthrottle,
@@ -959,7 +956,8 @@ static struct usb_serial_driver ftdi_sio_device = {
.prepare_write_buffer = ftdi_prepare_write_buffer,
.tiocmget = ftdi_tiocmget,
.tiocmset = ftdi_tiocmset,
- .get_icount = ftdi_get_icount,
+ .tiocmiwait = usb_serial_generic_tiocmiwait,
+ .get_icount = usb_serial_generic_get_icount,
.ioctl = ftdi_ioctl,
.set_termios = ftdi_set_termios,
.break_ctl = ftdi_break_ctl,
@@ -1688,7 +1686,6 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
return -ENOMEM;
}
- kref_init(&priv->kref);
mutex_init(&priv->cfg_lock);
priv->flags = ASYNC_LOW_LATENCY;
@@ -1792,20 +1789,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;
}
/*
@@ -1826,22 +1827,13 @@ static int ftdi_mtxorb_hack_setup(struct usb_serial *serial)
return 0;
}
-static void ftdi_sio_priv_release(struct kref *k)
-{
- struct ftdi_private *priv = container_of(k, struct ftdi_private, kref);
-
- kfree(priv);
-}
-
static int ftdi_sio_port_remove(struct usb_serial_port *port)
{
struct ftdi_private *priv = usb_get_serial_port_data(port);
- wake_up_interruptible(&port->delta_msr_wait);
-
remove_sysfs_attrs(port);
- kref_put(&priv->kref, ftdi_sio_priv_release);
+ kfree(priv);
return 0;
}
@@ -1851,7 +1843,6 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)
struct ktermios dummy;
struct usb_device *dev = port->serial->dev;
struct ftdi_private *priv = usb_get_serial_port_data(port);
- int result;
/* No error checking for this (will get errors later anyway) */
/* See ftdi_sio.h for description of what is reset */
@@ -1870,12 +1861,7 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)
ftdi_set_termios(tty, port, &dummy);
}
- /* Start reading from the device */
- result = usb_serial_generic_open(tty, port);
- if (!result)
- kref_get(&priv->kref);
-
- return result;
+ return usb_serial_generic_open(tty, port);
}
static void ftdi_dtr_rts(struct usb_serial_port *port, int on)
@@ -1900,19 +1886,6 @@ static void ftdi_dtr_rts(struct usb_serial_port *port, int on)
clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
}
-/*
- * usbserial:__serial_close only calls ftdi_close if the point is open
- *
- * This only gets called when it is the last close
- */
-static void ftdi_close(struct usb_serial_port *port)
-{
- struct ftdi_private *priv = usb_get_serial_port_data(port);
-
- usb_serial_generic_close(port);
- kref_put(&priv->kref, ftdi_sio_priv_release);
-}
-
/* The SIO requires the first byte to have:
* B0 1
* B1 0
@@ -1940,7 +1913,7 @@ static int ftdi_prepare_write_buffer(struct usb_serial_port *port,
c = kfifo_out(&port->write_fifo, &buffer[i + 1], len);
if (!c)
break;
- priv->icount.tx += c;
+ port->icount.tx += c;
buffer[i] = (c << 2) + 1;
count += c + 1;
}
@@ -1948,7 +1921,7 @@ static int ftdi_prepare_write_buffer(struct usb_serial_port *port,
} else {
count = kfifo_out_locked(&port->write_fifo, dest, size,
&port->lock);
- priv->icount.tx += count;
+ port->icount.tx += count;
}
return count;
@@ -1977,15 +1950,15 @@ static int ftdi_process_packet(struct usb_serial_port *port,
char diff_status = status ^ priv->prev_status;
if (diff_status & FTDI_RS0_CTS)
- priv->icount.cts++;
+ port->icount.cts++;
if (diff_status & FTDI_RS0_DSR)
- priv->icount.dsr++;
+ port->icount.dsr++;
if (diff_status & FTDI_RS0_RI)
- priv->icount.rng++;
+ port->icount.rng++;
if (diff_status & FTDI_RS0_RLSD)
- priv->icount.dcd++;
+ port->icount.dcd++;
- wake_up_interruptible(&port->delta_msr_wait);
+ wake_up_interruptible(&port->port.delta_msr_wait);
priv->prev_status = status;
}
@@ -1995,18 +1968,18 @@ static int ftdi_process_packet(struct usb_serial_port *port,
* over framing errors */
if (packet[1] & FTDI_RS_BI) {
flag = TTY_BREAK;
- priv->icount.brk++;
+ port->icount.brk++;
usb_serial_handle_break(port);
} else if (packet[1] & FTDI_RS_PE) {
flag = TTY_PARITY;
- priv->icount.parity++;
+ port->icount.parity++;
} else if (packet[1] & FTDI_RS_FE) {
flag = TTY_FRAME;
- priv->icount.frame++;
+ port->icount.frame++;
}
/* Overrun is special, not associated with a char */
if (packet[1] & FTDI_RS_OE) {
- priv->icount.overrun++;
+ port->icount.overrun++;
tty_insert_flip_char(&port->port, 0, TTY_OVERRUN);
}
}
@@ -2020,7 +1993,7 @@ static int ftdi_process_packet(struct usb_serial_port *port,
len -= 2;
if (!len)
return 0; /* status only */
- priv->icount.rx += len;
+ port->icount.rx += len;
ch = packet + 2;
if (port->port.console && port->sysrq) {
@@ -2384,34 +2357,10 @@ static int ftdi_tiocmset(struct tty_struct *tty,
return update_mctrl(port, set, clear);
}
-static int ftdi_get_icount(struct tty_struct *tty,
- struct serial_icounter_struct *icount)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct ftdi_private *priv = usb_get_serial_port_data(port);
- struct async_icount *ic = &priv->icount;
-
- icount->cts = ic->cts;
- icount->dsr = ic->dsr;
- icount->rng = ic->rng;
- icount->dcd = ic->dcd;
- icount->tx = ic->tx;
- icount->rx = ic->rx;
- icount->frame = ic->frame;
- icount->parity = ic->parity;
- icount->overrun = ic->overrun;
- icount->brk = ic->brk;
- icount->buf_overrun = ic->buf_overrun;
- return 0;
-}
-
static int ftdi_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
struct usb_serial_port *port = tty->driver_data;
- struct ftdi_private *priv = usb_get_serial_port_data(port);
- struct async_icount cnow;
- struct async_icount cprev;
dev_dbg(&port->dev, "%s cmd 0x%04x\n", __func__, cmd);
@@ -2425,35 +2374,6 @@ static int ftdi_ioctl(struct tty_struct *tty,
case TIOCSSERIAL: /* sets serial port data */
return set_serial_info(tty, port,
(struct serial_struct __user *) arg);
-
- /*
- * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
- * - mask passed in arg for lines of interest
- * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
- * Caller should use TIOCGICOUNT to see which one it was.
- *
- * This code is borrowed from linux/drivers/char/serial.c
- */
- case TIOCMIWAIT:
- cprev = priv->icount;
- for (;;) {
- interruptible_sleep_on(&port->delta_msr_wait);
- /* see if a signal did it */
- if (signal_pending(current))
- return -ERESTARTSYS;
-
- if (port->serial->disconnected)
- return -EIO;
-
- cnow = priv->icount;
- if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
- ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
- ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
- ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
- return 0;
- }
- cprev = cnow;
- }
case TIOCSERGETLSR:
return get_lsr_info(port, (struct serial_struct __user *)arg);
break;
diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h
index e79861e..9852827 100644
--- a/drivers/usb/serial/ftdi_sio_ids.h
+++ b/drivers/usb/serial/ftdi_sio_ids.h
@@ -74,6 +74,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+ */
@@ -1150,7 +1151,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/)
diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c
index 81caf56..b110c57 100644
--- a/drivers/usb/serial/garmin_gps.c
+++ b/drivers/usb/serial/garmin_gps.c
@@ -946,16 +946,12 @@ static int garmin_open(struct tty_struct *tty, struct usb_serial_port *port)
static void garmin_close(struct usb_serial_port *port)
{
- struct usb_serial *serial = port->serial;
struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);
dev_dbg(&port->dev, "%s - port %d - mode=%d state=%d flags=0x%X\n",
__func__, port->number, garmin_data_p->mode,
garmin_data_p->state, garmin_data_p->flags);
- if (!serial)
- return;
-
garmin_clear(garmin_data_p);
/* shutdown our urbs */
@@ -1185,17 +1181,11 @@ static void garmin_read_bulk_callback(struct urb *urb)
{
unsigned long flags;
struct usb_serial_port *port = urb->context;
- struct usb_serial *serial = port->serial;
struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);
unsigned char *data = urb->transfer_buffer;
int status = urb->status;
int retval;
- if (!serial) {
- dev_dbg(&urb->dev->dev, "%s - bad serial pointer, exiting\n", __func__);
- return;
- }
-
if (status) {
dev_dbg(&urb->dev->dev, "%s - nonzero read bulk status received: %d\n",
__func__, status);
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index 4c5c23f..297665f 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -1,7 +1,7 @@
/*
* USB Serial Converter Generic functions
*
- * Copyright (C) 2010 - 2011 Johan Hovold (jhovold@gmail.com)
+ * Copyright (C) 2010 - 2013 Johan Hovold (jhovold@gmail.com)
* Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com)
*
* This program is free software; you can redistribute it and/or
@@ -45,8 +45,6 @@ struct usb_serial_driver usb_serial_generic_device = {
},
.id_table = generic_device_ids,
.num_ports = 1,
- .disconnect = usb_serial_generic_disconnect,
- .release = usb_serial_generic_release,
.throttle = usb_serial_generic_throttle,
.unthrottle = usb_serial_generic_unthrottle,
.resume = usb_serial_generic_resume,
@@ -102,32 +100,23 @@ int usb_serial_generic_open(struct tty_struct *tty, struct usb_serial_port *port
}
EXPORT_SYMBOL_GPL(usb_serial_generic_open);
-static void generic_cleanup(struct usb_serial_port *port)
+void usb_serial_generic_close(struct usb_serial_port *port)
{
- struct usb_serial *serial = port->serial;
unsigned long flags;
int i;
- if (serial->dev) {
- /* shutdown any bulk transfers that might be going on */
- if (port->bulk_out_size) {
- for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i)
- usb_kill_urb(port->write_urbs[i]);
+ if (port->bulk_out_size) {
+ for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i)
+ usb_kill_urb(port->write_urbs[i]);
- spin_lock_irqsave(&port->lock, flags);
- kfifo_reset_out(&port->write_fifo);
- spin_unlock_irqrestore(&port->lock, flags);
- }
- if (port->bulk_in_size) {
- for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i)
- usb_kill_urb(port->read_urbs[i]);
- }
+ spin_lock_irqsave(&port->lock, flags);
+ kfifo_reset_out(&port->write_fifo);
+ spin_unlock_irqrestore(&port->lock, flags);
+ }
+ if (port->bulk_in_size) {
+ for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i)
+ usb_kill_urb(port->read_urbs[i]);
}
-}
-
-void usb_serial_generic_close(struct usb_serial_port *port)
-{
- generic_cleanup(port);
}
EXPORT_SYMBOL_GPL(usb_serial_generic_close);
@@ -272,8 +261,7 @@ static int usb_serial_generic_submit_read_urb(struct usb_serial_port *port,
if (!test_and_clear_bit(index, &port->read_urbs_free))
return 0;
- dev_dbg(&port->dev, "%s - port %d, urb %d\n", __func__,
- port->number, index);
+ dev_dbg(&port->dev, "%s - urb %d\n", __func__, index);
res = usb_submit_urb(port->read_urbs[index], mem_flags);
if (res) {
@@ -347,8 +335,8 @@ void usb_serial_generic_read_bulk_callback(struct urb *urb)
}
set_bit(i, &port->read_urbs_free);
- dev_dbg(&port->dev, "%s - port %d, urb %d, len %d\n",
- __func__, port->number, i, urb->actual_length);
+ dev_dbg(&port->dev, "%s - urb %d, len %d\n", __func__, i,
+ urb->actual_length);
if (urb->status) {
dev_dbg(&port->dev, "%s - non-zero urb status: %d\n",
@@ -430,6 +418,91 @@ void usb_serial_generic_unthrottle(struct tty_struct *tty)
}
EXPORT_SYMBOL_GPL(usb_serial_generic_unthrottle);
+static bool usb_serial_generic_msr_changed(struct tty_struct *tty,
+ unsigned long arg, struct async_icount *cprev)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ struct async_icount cnow;
+ unsigned long flags;
+ bool ret;
+
+ /*
+ * Use tty-port initialised flag to detect all hangups including the
+ * one generated at USB-device disconnect.
+ *
+ * FIXME: Remove hupping check once tty_port_hangup calls shutdown
+ * (which clears the initialised flag) before wake up.
+ */
+ if (test_bit(TTY_HUPPING, &tty->flags))
+ return true;
+ if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags))
+ return true;
+
+ spin_lock_irqsave(&port->lock, flags);
+ cnow = port->icount; /* atomic copy*/
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ ret = ((arg & TIOCM_RNG) && (cnow.rng != cprev->rng)) ||
+ ((arg & TIOCM_DSR) && (cnow.dsr != cprev->dsr)) ||
+ ((arg & TIOCM_CD) && (cnow.dcd != cprev->dcd)) ||
+ ((arg & TIOCM_CTS) && (cnow.cts != cprev->cts));
+
+ *cprev = cnow;
+
+ return ret;
+}
+
+int usb_serial_generic_tiocmiwait(struct tty_struct *tty, unsigned long arg)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ struct async_icount cnow;
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&port->lock, flags);
+ cnow = port->icount; /* atomic copy */
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ ret = wait_event_interruptible(port->port.delta_msr_wait,
+ usb_serial_generic_msr_changed(tty, arg, &cnow));
+ if (!ret) {
+ if (test_bit(TTY_HUPPING, &tty->flags))
+ ret = -EIO;
+ if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags))
+ ret = -EIO;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(usb_serial_generic_tiocmiwait);
+
+int usb_serial_generic_get_icount(struct tty_struct *tty,
+ struct serial_icounter_struct *icount)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ struct async_icount cnow;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+ cnow = port->icount; /* atomic copy */
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ icount->cts = cnow.cts;
+ icount->dsr = cnow.dsr;
+ icount->rng = cnow.rng;
+ icount->dcd = cnow.dcd;
+ icount->tx = cnow.tx;
+ icount->rx = cnow.rx;
+ icount->frame = cnow.frame;
+ icount->parity = cnow.parity;
+ icount->overrun = cnow.overrun;
+ icount->brk = cnow.brk;
+ icount->buf_overrun = cnow.buf_overrun;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(usb_serial_generic_get_icount);
+
#ifdef CONFIG_MAGIC_SYSRQ
int usb_serial_handle_sysrq_char(struct usb_serial_port *port, unsigned int ch)
{
@@ -473,8 +546,7 @@ void usb_serial_handle_dcd_change(struct usb_serial_port *usb_port,
{
struct tty_port *port = &usb_port->port;
- dev_dbg(&usb_port->dev, "%s - port %d, status %d\n", __func__,
- usb_port->number, status);
+ dev_dbg(&usb_port->dev, "%s - status %d\n", __func__, status);
if (status)
wake_up_interruptible(&port->open_wait);
@@ -510,17 +582,3 @@ int usb_serial_generic_resume(struct usb_serial *serial)
return c ? -EIO : 0;
}
EXPORT_SYMBOL_GPL(usb_serial_generic_resume);
-
-void usb_serial_generic_disconnect(struct usb_serial *serial)
-{
- int i;
-
- /* stop reads and writes on all ports */
- for (i = 0; i < serial->num_ports; ++i)
- generic_cleanup(serial->port[i]);
-}
-EXPORT_SYMBOL_GPL(usb_serial_generic_disconnect);
-
-void usb_serial_generic_release(struct usb_serial *serial)
-{
-}
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index cf0b0a2..1477e85 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -111,7 +111,6 @@ struct edgeport_port {
wait_queue_head_t wait_open; /* for handling sleeping while waiting for open to finish */
wait_queue_head_t wait_command; /* for handling sleeping while waiting for command to finish */
- struct async_icount icount;
struct usb_serial_port *port; /* loop back to the owner of this object */
};
@@ -215,8 +214,6 @@ static void edge_break(struct tty_struct *tty, int break_state);
static int edge_tiocmget(struct tty_struct *tty);
static int edge_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear);
-static int edge_get_icount(struct tty_struct *tty,
- struct serial_icounter_struct *icount);
static int edge_startup(struct usb_serial *serial);
static void edge_disconnect(struct usb_serial *serial);
static void edge_release(struct usb_serial *serial);
@@ -867,9 +864,6 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port)
init_waitqueue_head(&edge_port->wait_chase);
init_waitqueue_head(&edge_port->wait_command);
- /* initialize our icount structure */
- memset(&(edge_port->icount), 0x00, sizeof(edge_port->icount));
-
/* initialize our port settings */
edge_port->txCredits = 0; /* Can't send any data yet */
/* Must always set this bit to enable ints! */
@@ -1296,7 +1290,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) {
@@ -1308,7 +1302,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);
@@ -1570,31 +1564,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)
{
@@ -1631,8 +1600,6 @@ static int edge_ioctl(struct tty_struct *tty,
struct usb_serial_port *port = tty->driver_data;
DEFINE_WAIT(wait);
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
- struct async_icount cnow;
- struct async_icount cprev;
dev_dbg(&port->dev, "%s - port %d, cmd = 0x%x\n", __func__, port->number, cmd);
@@ -1644,37 +1611,6 @@ static int edge_ioctl(struct tty_struct *tty,
case TIOCGSERIAL:
dev_dbg(&port->dev, "%s (%d) TIOCGSERIAL\n", __func__, port->number);
return get_serial_info(edge_port, (struct serial_struct __user *) arg);
-
- case TIOCMIWAIT:
- dev_dbg(&port->dev, "%s (%d) TIOCMIWAIT\n", __func__, port->number);
- cprev = edge_port->icount;
- while (1) {
- prepare_to_wait(&port->delta_msr_wait,
- &wait, TASK_INTERRUPTIBLE);
- schedule();
- finish_wait(&port->delta_msr_wait, &wait);
- /* see if a signal did it */
- if (signal_pending(current))
- return -ERESTARTSYS;
-
- if (port->serial->disconnected)
- return -EIO;
-
- cnow = edge_port->icount;
- if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
- cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
- return -EIO; /* no change => error */
- if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
- ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
- ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
- ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
- return 0;
- }
- cprev = cnow;
- }
- /* NOTREACHED */
- break;
-
}
return -ENOIOCTLCMD;
}
@@ -1848,7 +1784,7 @@ static void process_rcvd_data(struct edgeport_serial *edge_serial,
edge_serial->rxPort);
edge_tty_recv(edge_port->port, buffer,
rxLen);
- edge_port->icount.rx += rxLen;
+ edge_port->port->icount.rx += rxLen;
}
buffer += rxLen;
}
@@ -2024,7 +1960,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)
@@ -2035,7 +1971,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 newMsr)
icount->dcd++;
if (newMsr & EDGEPORT_MSR_DELTA_RI)
icount->rng++;
- wake_up_interruptible(&edge_port->port->delta_msr_wait);
+ wake_up_interruptible(&edge_port->port->port.delta_msr_wait);
}
/* Save the new modem status */
@@ -2070,7 +2006,7 @@ static void handle_new_lsr(struct edgeport_port *edge_port, __u8 lsrData,
edge_tty_recv(edge_port->port, &data, 1);
/* update input line counters */
- icount = &edge_port->icount;
+ icount = &edge_port->port->icount;
if (newLsr & LSR_BREAK)
icount->brk++;
if (newLsr & LSR_OVER_ERR)
diff --git a/drivers/usb/serial/io_tables.h b/drivers/usb/serial/io_tables.h
index 1511dd0..ae5fac5 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 7777172..158bf4b 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -86,7 +86,7 @@ struct edgeport_port {
int baud_rate;
int close_pending;
int lsr_event;
- struct async_icount icount;
+
struct edgeport_serial *edge_serial;
struct usb_serial_port *port;
__u8 bUartMode; /* Port type, 0: RS232, etc. */
@@ -206,7 +206,7 @@ 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);
@@ -1445,7 +1445,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr)
if (msr & (EDGEPORT_MSR_DELTA_CTS | EDGEPORT_MSR_DELTA_DSR |
EDGEPORT_MSR_DELTA_RI | EDGEPORT_MSR_DELTA_CD)) {
- icount = &edge_port->icount;
+ icount = &edge_port->port->icount;
/* update input line counters */
if (msr & EDGEPORT_MSR_DELTA_CTS)
@@ -1456,7 +1456,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr)
icount->dcd++;
if (msr & EDGEPORT_MSR_DELTA_RI)
icount->rng++;
- wake_up_interruptible(&edge_port->port->delta_msr_wait);
+ wake_up_interruptible(&edge_port->port->port.delta_msr_wait);
}
/* Save the new modem status */
@@ -1498,7 +1498,7 @@ static void handle_new_lsr(struct edgeport_port *edge_port, int lsr_data,
edge_tty_recv(edge_port->port, &data, 1);
/* update input line counters */
- icount = &edge_port->icount;
+ icount = &edge_port->port->icount;
if (new_lsr & LSR_BREAK)
icount->brk++;
if (new_lsr & LSR_OVER_ERR)
@@ -1657,7 +1657,7 @@ static void edge_bulk_in_callback(struct urb *urb)
else
edge_tty_recv(edge_port->port, data,
urb->actual_length);
- edge_port->icount.rx += urb->actual_length;
+ edge_port->port->icount.rx += urb->actual_length;
}
exit:
@@ -1712,7 +1712,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);
}
@@ -1750,8 +1750,6 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port)
dev = port->serial->dev;
- memset(&(edge_port->icount), 0x00, sizeof(edge_port->icount));
-
/* turn off loopback */
status = ti_do_config(edge_port, UMPC_SET_CLR_LOOPBACK, 0);
if (status) {
@@ -1909,21 +1907,10 @@ static void edge_close(struct usb_serial_port *port)
kfifo_reset_out(&edge_port->write_fifo);
spin_unlock_irqrestore(&edge_port->ep_lock, flags);
- /* assuming we can still talk to the device,
- * send a close port command to it */
dev_dbg(&port->dev, "%s - send umpc_close_port\n", __func__);
port_number = port->number - port->serial->minor;
-
- mutex_lock(&serial->disc_mutex);
- if (!serial->disconnected) {
- send_cmd(serial->dev,
- UMPC_CLOSE_PORT,
- (__u8)(UMPM_UART1_PORT + port_number),
- 0,
- NULL,
- 0);
- }
- mutex_unlock(&serial->disc_mutex);
+ send_cmd(serial->dev, UMPC_CLOSE_PORT,
+ (__u8)(UMPM_UART1_PORT + port_number), 0, NULL, 0);
mutex_lock(&edge_serial->es_lock);
--edge_port->edge_serial->num_ports_open;
@@ -1953,14 +1940,13 @@ static int edge_write(struct tty_struct *tty, struct usb_serial_port *port,
count = kfifo_in_locked(&edge_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;
@@ -1999,7 +1985,7 @@ static void edge_send(struct tty_struct *tty)
edge_port->ep_write_urb_in_use = 0;
/* TODO: reschedule edge_send */
} else
- edge_port->icount.tx += count;
+ edge_port->port->icount.tx += count;
/* wakeup any process waiting for writes to complete */
/* there is now more room in the buffer for new writes */
@@ -2360,27 +2346,6 @@ static int edge_tiocmget(struct tty_struct *tty)
return result;
}
-static int edge_get_icount(struct tty_struct *tty,
- struct serial_icounter_struct *icount)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct edgeport_port *edge_port = usb_get_serial_port_data(port);
- struct async_icount *ic = &edge_port->icount;
-
- icount->cts = ic->cts;
- icount->dsr = ic->dsr;
- icount->rng = ic->rng;
- icount->dcd = ic->dcd;
- icount->tx = ic->tx;
- icount->rx = ic->rx;
- icount->frame = ic->frame;
- icount->parity = ic->parity;
- icount->overrun = ic->overrun;
- icount->brk = ic->brk;
- icount->buf_overrun = ic->buf_overrun;
- return 0;
-}
-
static int get_serial_info(struct edgeport_port *edge_port,
struct serial_struct __user *retinfo)
{
@@ -2392,7 +2357,7 @@ static int get_serial_info(struct edgeport_port *edge_port,
cwait = edge_port->port->port.closing_wait;
if (cwait != ASYNC_CLOSING_WAIT_NONE)
- cwait = jiffies_to_msecs(closing_wait) / 10;
+ cwait = jiffies_to_msecs(cwait) / 10;
memset(&tmp, 0, sizeof(tmp));
@@ -2416,8 +2381,6 @@ static int edge_ioctl(struct tty_struct *tty,
{
struct usb_serial_port *port = tty->driver_data;
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
- struct async_icount cnow;
- struct async_icount cprev;
dev_dbg(&port->dev, "%s - port %d, cmd = 0x%x\n", __func__, port->number, cmd);
@@ -2426,32 +2389,6 @@ static int edge_ioctl(struct tty_struct *tty,
dev_dbg(&port->dev, "%s - TIOCGSERIAL\n", __func__);
return get_serial_info(edge_port,
(struct serial_struct __user *) arg);
- case TIOCMIWAIT:
- dev_dbg(&port->dev, "%s - TIOCMIWAIT\n", __func__);
- cprev = edge_port->icount;
- while (1) {
- interruptible_sleep_on(&port->delta_msr_wait);
- /* see if a signal did it */
- if (signal_pending(current))
- return -ERESTARTSYS;
-
- if (port->serial->disconnected)
- return -EIO;
-
- cnow = edge_port->icount;
- if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
- cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
- return -EIO; /* no change => error */
- if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
- ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
- ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
- ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
- return 0;
- }
- cprev = cnow;
- }
- /* not reached */
- break;
}
return -ENOIOCTLCMD;
}
@@ -2463,8 +2400,6 @@ static void edge_break(struct tty_struct *tty, int break_state)
int status;
int bv = 0; /* Off */
- tty_wait_until_sent(tty, 0);
-
if (break_state == -1)
bv = 1; /* On */
status = ti_do_config(edge_port, UMPC_SET_CLR_BREAK, bv);
@@ -2546,7 +2481,6 @@ static int edge_port_remove(struct usb_serial_port *port)
struct edgeport_port *edge_port;
edge_port = usb_get_serial_port_data(port);
-
edge_remove_sysfs_attrs(port);
kfifo_free(&edge_port->write_fifo);
kfree(edge_port);
@@ -2618,7 +2552,8 @@ static struct usb_serial_driver edgeport_1port_device = {
.set_termios = edge_set_termios,
.tiocmget = edge_tiocmget,
.tiocmset = edge_tiocmset,
- .get_icount = edge_get_icount,
+ .tiocmiwait = usb_serial_generic_tiocmiwait,
+ .get_icount = usb_serial_generic_get_icount,
.write = edge_write,
.write_room = edge_write_room,
.chars_in_buffer = edge_chars_in_buffer,
@@ -2649,7 +2584,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,
diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c
index ff77027..9d74c27 100644
--- a/drivers/usb/serial/iuu_phoenix.c
+++ b/drivers/usb/serial/iuu_phoenix.c
@@ -55,7 +55,6 @@ static void read_rxcmd_callback(struct urb *urb);
struct iuu_private {
spinlock_t lock; /* store irq state */
- wait_queue_head_t delta_msr_wait;
u8 line_status;
int tiostatus; /* store IUART SIGNAL for tiocmget call */
u8 reset; /* if 1 reset is needed */
@@ -94,7 +93,6 @@ static int iuu_port_probe(struct usb_serial_port *port)
priv->vcc = vcc_default;
spin_lock_init(&priv->lock);
- init_waitqueue_head(&priv->delta_msr_wait);
usb_set_serial_port_data(port, priv);
@@ -944,22 +942,13 @@ static void iuu_set_termios(struct tty_struct *tty,
static void iuu_close(struct usb_serial_port *port)
{
/* iuu_led (port,255,0,0,0); */
- struct usb_serial *serial;
-
- serial = port->serial;
- if (!serial)
- return;
iuu_uart_off(port);
- if (serial->dev) {
- /* free writebuf */
- /* shutdown our urbs */
- dev_dbg(&port->dev, "%s - shutting down urbs\n", __func__);
- usb_kill_urb(port->write_urb);
- usb_kill_urb(port->read_urb);
- usb_kill_urb(port->interrupt_in_urb);
- iuu_led(port, 0, 0, 0xF000, 0xFF);
- }
+
+ usb_kill_urb(port->write_urb);
+ usb_kill_urb(port->read_urb);
+
+ iuu_led(port, 0, 0, 0xF000, 0xFF);
}
static void iuu_init_termios(struct tty_struct *tty)
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index b011478..eb30d7b 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -712,45 +712,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++]];
- 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(&port->port,
- 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(&port->port,
- 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(&port->port);
}
+ tty_flip_buffer_push(&port->port);
}
/* Resubmit urb so we continue receiving */
@@ -1092,7 +1092,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);
@@ -1100,28 +1099,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]);
}
}
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index 2230223..5f1d382e 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -593,12 +593,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);
}
@@ -649,13 +647,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/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index 769d910..1b4054f 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -341,28 +341,20 @@ static void klsi_105_close(struct usb_serial_port *port)
{
int rc;
- mutex_lock(&port->serial->disc_mutex);
- if (!port->serial->disconnected) {
- /* send READ_OFF */
- rc = usb_control_msg(port->serial->dev,
- usb_sndctrlpipe(port->serial->dev, 0),
- KL5KUSB105A_SIO_CONFIGURE,
- USB_TYPE_VENDOR | USB_DIR_OUT,
- KL5KUSB105A_SIO_CONFIGURE_READ_OFF,
- 0, /* index */
- NULL, 0,
- KLSI_TIMEOUT);
- if (rc < 0)
- dev_err(&port->dev,
- "Disabling read failed (error = %d)\n", rc);
- }
- mutex_unlock(&port->serial->disc_mutex);
+ /* send READ_OFF */
+ rc = usb_control_msg(port->serial->dev,
+ usb_sndctrlpipe(port->serial->dev, 0),
+ KL5KUSB105A_SIO_CONFIGURE,
+ USB_TYPE_VENDOR | USB_DIR_OUT,
+ KL5KUSB105A_SIO_CONFIGURE_READ_OFF,
+ 0, /* index */
+ NULL, 0,
+ KLSI_TIMEOUT);
+ if (rc < 0)
+ dev_err(&port->dev, "failed to disable read: %d\n", rc);
/* shutdown our bulk reads and writes */
usb_serial_generic_close(port);
-
- /* wgg - do I need this? I think so. */
- usb_kill_urb(port->interrupt_in_urb);
}
/* We need to write a complete 64-byte data block and encode the
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
index 903d938..78b48c3 100644
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -65,7 +65,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 +99,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 +107,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 +116,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 +143,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 +174,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 +182,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),
@@ -310,12 +257,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);
}
@@ -333,24 +275,8 @@ static void kobil_read_int_callback(struct urb *urb)
}
if (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 */
-
+ 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);
}
@@ -360,7 +286,7 @@ 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)
{
}
@@ -403,23 +329,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;
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index 06d5a60..6a15adf 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -35,7 +35,6 @@
#include <linux/usb.h>
#include <linux/usb/serial.h>
#include <linux/serial.h>
-#include <linux/ioctl.h>
#include "mct_u232.h"
#define DRIVER_AUTHOR "Wolfgang Grandegger <wolfgang@ces.ch>"
@@ -44,7 +43,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 +55,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 +89,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,13 +100,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;
};
#define THROTTLED 0x01
@@ -382,22 +375,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;
@@ -406,6 +383,10 @@ 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);
usb_set_serial_port_data(port, priv);
@@ -469,17 +450,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);
@@ -509,11 +490,9 @@ static void mct_u232_dtr_rts(struct usb_serial_port *port, int on)
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);
@@ -570,7 +549,7 @@ static void mct_u232_read_int_callback(struct urb *urb)
/* Record Control Line states */
mct_u232_msr_to_state(port, &priv->control_state, priv->last_msr);
- mct_u232_msr_to_icount(&priv->icount, priv->last_msr);
+ mct_u232_msr_to_icount(&port->icount, priv->last_msr);
#if 0
/* Not yet handled. See belkin_sa.c for further information */
@@ -598,7 +577,7 @@ static void mct_u232_read_int_callback(struct urb *urb)
tty_kref_put(tty);
}
#endif
- wake_up_interruptible(&port->delta_msr_wait);
+ wake_up_interruptible(&port->port.delta_msr_wait);
spin_unlock_irqrestore(&priv->lock, flags);
exit:
retval = usb_submit_urb(urb, GFP_ATOMIC);
@@ -786,86 +765,6 @@ static void mct_u232_unthrottle(struct tty_struct *tty)
}
}
-static int mct_u232_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
-{
- DEFINE_WAIT(wait);
- struct usb_serial_port *port = tty->driver_data;
- struct mct_u232_private *mct_u232_port = usb_get_serial_port_data(port);
- struct async_icount cnow, cprev;
- unsigned long flags;
-
- dev_dbg(&port->dev, "%s - cmd = 0x%x\n", __func__, cmd);
-
- switch (cmd) {
-
- case TIOCMIWAIT:
-
- dev_dbg(&port->dev, "%s TIOCMIWAIT", __func__);
-
- spin_lock_irqsave(&mct_u232_port->lock, flags);
- cprev = mct_u232_port->icount;
- spin_unlock_irqrestore(&mct_u232_port->lock, flags);
- for ( ; ; ) {
- prepare_to_wait(&port->delta_msr_wait,
- &wait, TASK_INTERRUPTIBLE);
- schedule();
- finish_wait(&port->delta_msr_wait, &wait);
- /* see if a signal did it */
- if (signal_pending(current))
- return -ERESTARTSYS;
-
- if (port->serial->disconnected)
- return -EIO;
-
- spin_lock_irqsave(&mct_u232_port->lock, flags);
- cnow = mct_u232_port->icount;
- spin_unlock_irqrestore(&mct_u232_port->lock, flags);
- if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
- cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
- return -EIO; /* no change => error */
- if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
- ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
- ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
- ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
- return 0;
- }
- cprev = cnow;
- }
-
- }
- return -ENOIOCTLCMD;
-}
-
-static int mct_u232_get_icount(struct tty_struct *tty,
- struct serial_icounter_struct *icount)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct mct_u232_private *mct_u232_port = usb_get_serial_port_data(port);
- struct async_icount *ic = &mct_u232_port->icount;
- unsigned long flags;
-
- spin_lock_irqsave(&mct_u232_port->lock, flags);
-
- icount->cts = ic->cts;
- icount->dsr = ic->dsr;
- icount->rng = ic->rng;
- icount->dcd = ic->dcd;
- icount->rx = ic->rx;
- icount->tx = ic->tx;
- icount->frame = ic->frame;
- icount->overrun = ic->overrun;
- icount->parity = ic->parity;
- icount->brk = ic->brk;
- icount->buf_overrun = ic->buf_overrun;
-
- spin_unlock_irqrestore(&mct_u232_port->lock, flags);
-
- dev_dbg(&port->dev, "%s TIOCGICOUNT RX=%d, TX=%d\n",
- __func__, icount->rx, icount->tx);
- return 0;
-}
-
module_usb_serial_driver(serial_drivers, id_table);
MODULE_AUTHOR(DRIVER_AUTHOR);
diff --git a/drivers/usb/serial/metro-usb.c b/drivers/usb/serial/metro-usb.c
index bf3c7a2..47e2477 100644
--- a/drivers/usb/serial/metro-usb.c
+++ b/drivers/usb/serial/metro-usb.c
@@ -177,10 +177,7 @@ static void metrousb_cleanup(struct usb_serial_port *port)
usb_unlink_urb(port->interrupt_in_urb);
usb_kill_urb(port->interrupt_in_urb);
- mutex_lock(&port->serial->disc_mutex);
- if (!port->serial->disconnected)
- metrousb_send_unidirectional_cmd(UNI_CMD_CLOSE, port);
- mutex_unlock(&port->serial->disc_mutex);
+ metrousb_send_unidirectional_cmd(UNI_CMD_CLOSE, port);
}
static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port)
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index e956eae..cc0e543 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -62,7 +62,6 @@ struct moschip_port {
__u8 shadowMCR; /* last MCR value received */
__u8 shadowMSR; /* last MSR value received */
char open;
- struct async_icount icount;
struct usb_serial_port *port; /* loop back to the owner */
struct urb *write_urb_pool[NUM_URBS];
};
@@ -1071,9 +1070,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! */
@@ -1140,16 +1136,9 @@ static void mos7720_close(struct usb_serial_port *port)
usb_kill_urb(port->write_urb);
usb_kill_urb(port->read_urb);
- mutex_lock(&serial->disc_mutex);
- /* these commands must not be issued if the device has
- * been disconnected */
- if (!serial->disconnected) {
- write_mos_reg(serial, port->number - port->serial->minor,
- MCR, 0x00);
- write_mos_reg(serial, port->number - port->serial->minor,
- IER, 0x00);
- }
- mutex_unlock(&serial->disc_mutex);
+ write_mos_reg(serial, port->number - port->serial->minor, MCR, 0x00);
+ write_mos_reg(serial, port->number - port->serial->minor, IER, 0x00);
+
mos7720_port->open = 0;
}
@@ -1799,33 +1788,6 @@ static int mos7720_tiocmset(struct tty_struct *tty,
return 0;
}
-static int mos7720_get_icount(struct tty_struct *tty,
- struct serial_icounter_struct *icount)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct moschip_port *mos7720_port;
- struct async_icount cnow;
-
- mos7720_port = usb_get_serial_port_data(port);
- cnow = mos7720_port->icount;
-
- icount->cts = cnow.cts;
- icount->dsr = cnow.dsr;
- icount->rng = cnow.rng;
- icount->dcd = cnow.dcd;
- icount->rx = cnow.rx;
- icount->tx = cnow.tx;
- icount->frame = cnow.frame;
- icount->overrun = cnow.overrun;
- icount->parity = cnow.parity;
- icount->brk = cnow.brk;
- icount->buf_overrun = cnow.buf_overrun;
-
- dev_dbg(&port->dev, "%s TIOCGICOUNT RX=%d, TX=%d\n", __func__,
- icount->rx, icount->tx);
- return 0;
-}
-
static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd,
unsigned int __user *value)
{
@@ -1901,8 +1863,6 @@ static int mos7720_ioctl(struct tty_struct *tty,
{
struct usb_serial_port *port = tty->driver_data;
struct moschip_port *mos7720_port;
- struct async_icount cnow;
- struct async_icount cprev;
mos7720_port = usb_get_serial_port_data(port);
if (mos7720_port == NULL)
@@ -1927,27 +1887,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;
@@ -2103,7 +2042,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 2be376a..a0d5ea5 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -219,8 +219,6 @@ struct moschip_port {
char open;
char open_ports;
wait_queue_head_t wait_chase; /* for handling sleeping while waiting for chase to finish */
- int delta_msr_cond;
- struct async_icount icount;
struct usb_serial_port *port; /* loop back to the owner of this object */
/* Offsets */
@@ -399,32 +397,22 @@ static void mos7840_handle_new_msr(struct moschip_port *port, __u8 new_msr)
struct moschip_port *mos7840_port;
struct async_icount *icount;
mos7840_port = port;
- icount = &mos7840_port->icount;
if (new_msr &
(MOS_MSR_DELTA_CTS | MOS_MSR_DELTA_DSR | MOS_MSR_DELTA_RI |
MOS_MSR_DELTA_CD)) {
- icount = &mos7840_port->icount;
+ icount = &mos7840_port->port->icount;
/* update input line counters */
- if (new_msr & MOS_MSR_DELTA_CTS) {
+ if (new_msr & MOS_MSR_DELTA_CTS)
icount->cts++;
- smp_wmb();
- }
- if (new_msr & MOS_MSR_DELTA_DSR) {
+ if (new_msr & MOS_MSR_DELTA_DSR)
icount->dsr++;
- smp_wmb();
- }
- if (new_msr & MOS_MSR_DELTA_CD) {
+ if (new_msr & MOS_MSR_DELTA_CD)
icount->dcd++;
- smp_wmb();
- }
- if (new_msr & MOS_MSR_DELTA_RI) {
+ if (new_msr & MOS_MSR_DELTA_RI)
icount->rng++;
- smp_wmb();
- }
- mos7840_port->delta_msr_cond = 1;
- wake_up_interruptible(&port->port->delta_msr_wait);
+ wake_up_interruptible(&port->port->port.delta_msr_wait);
}
}
@@ -442,23 +430,15 @@ static void mos7840_handle_new_lsr(struct moschip_port *port, __u8 new_lsr)
}
/* update input line counters */
- icount = &port->icount;
- if (new_lsr & SERIAL_LSR_BI) {
+ icount = &port->port->icount;
+ if (new_lsr & SERIAL_LSR_BI)
icount->brk++;
- smp_wmb();
- }
- if (new_lsr & SERIAL_LSR_OE) {
+ if (new_lsr & SERIAL_LSR_OE)
icount->overrun++;
- smp_wmb();
- }
- if (new_lsr & SERIAL_LSR_PE) {
+ if (new_lsr & SERIAL_LSR_PE)
icount->parity++;
- smp_wmb();
- }
- if (new_lsr & SERIAL_LSR_FE) {
+ if (new_lsr & SERIAL_LSR_FE)
icount->frame++;
- smp_wmb();
- }
}
/************************************************************************/
@@ -777,9 +757,8 @@ static void mos7840_bulk_in_callback(struct urb *urb)
struct tty_port *tport = &mos7840_port->port->port;
tty_insert_flip_string(tport, data, urb->actual_length);
tty_flip_buffer_push(tport);
- mos7840_port->icount.rx += urb->actual_length;
- smp_wmb();
- dev_dbg(&port->dev, "mos7840_port->icount.rx is %d:\n", mos7840_port->icount.rx);
+ port->icount.rx += urb->actual_length;
+ dev_dbg(&port->dev, "icount.rx is %d:\n", port->icount.rx);
}
if (!mos7840_port->read_urb) {
@@ -1127,17 +1106,12 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)
/* initialize our wait queues */
init_waitqueue_head(&mos7840_port->wait_chase);
- /* initialize our icount structure */
- memset(&(mos7840_port->icount), 0x00, sizeof(mos7840_port->icount));
-
/* initialize our port settings */
/* Must set to enable ints! */
mos7840_port->shadowMCR = MCR_MASTER_IE;
/* send a open port command */
mos7840_port->open = 1;
/* mos7840_change_port_settings(mos7840_port,old_termios); */
- mos7840_port->icount.tx = 0;
- mos7840_port->icount.rx = 0;
return 0;
}
@@ -1220,25 +1194,10 @@ static void mos7840_close(struct usb_serial_port *port)
}
}
- /* While closing port, shutdown all bulk read, write *
- * and interrupt read if they exists */
- if (serial->dev) {
- if (mos7840_port->write_urb) {
- dev_dbg(&port->dev, "%s", "Shutdown bulk write\n");
- usb_kill_urb(mos7840_port->write_urb);
- }
- if (mos7840_port->read_urb) {
- dev_dbg(&port->dev, "%s", "Shutdown bulk read\n");
- usb_kill_urb(mos7840_port->read_urb);
- mos7840_port->read_urb_busy = false;
- }
- if ((&mos7840_port->control_urb)) {
- dev_dbg(&port->dev, "%s", "Shutdown control read\n");
- /*/ usb_kill_urb (mos7840_port->control_urb); */
- }
- }
-/* if(mos7840_port->ctrl_buf != NULL) */
-/* kfree(mos7840_port->ctrl_buf); */
+ usb_kill_urb(mos7840_port->write_urb);
+ usb_kill_urb(mos7840_port->read_urb);
+ mos7840_port->read_urb_busy = false;
+
port0->open_ports--;
dev_dbg(&port->dev, "%s in close%d:in port%d\n", __func__, port0->open_ports, port->number);
if (port0->open_ports == 0) {
@@ -1250,8 +1209,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);
}
@@ -1328,9 +1286,8 @@ static void mos7840_break(struct tty_struct *tty, int break_state)
if (mos7840_port == NULL)
return;
- if (serial->dev)
- /* flush and block until tx is empty */
- mos7840_block_until_chase_response(tty, mos7840_port);
+ /* flush and block until tx is empty */
+ mos7840_block_until_chase_response(tty, mos7840_port);
if (break_state == -1)
data = mos7840_port->shadowLCR | LCR_SET_BREAK;
@@ -1520,9 +1477,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;
@@ -2141,34 +2097,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
@@ -2181,9 +2109,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;
@@ -2208,41 +2133,6 @@ static int mos7840_ioctl(struct tty_struct *tty,
case TIOCSSERIAL:
dev_dbg(&port->dev, "%s TIOCSSERIAL\n", __func__);
break;
-
- case TIOCMIWAIT:
- dev_dbg(&port->dev, "%s TIOCMIWAIT\n", __func__);
- cprev = mos7840_port->icount;
- while (1) {
- /* interruptible_sleep_on(&mos7840_port->delta_msr_wait); */
- mos7840_port->delta_msr_cond = 0;
- wait_event_interruptible(port->delta_msr_wait,
- (port->serial->disconnected ||
- mos7840_port->
- delta_msr_cond == 1));
-
- /* see if a signal did it */
- if (signal_pending(current))
- return -ERESTARTSYS;
-
- if (port->serial->disconnected)
- return -EIO;
-
- cnow = mos7840_port->icount;
- smp_rmb();
- if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
- cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
- return -EIO; /* no change => error */
- if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
- ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
- ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
- ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
- return 0;
- }
- cprev = cnow;
- }
- /* NOTREACHED */
- break;
-
default:
break;
}
@@ -2589,7 +2479,8 @@ static struct usb_serial_driver moschip7840_4port_device = {
.break_ctl = mos7840_break,
.tiocmget = mos7840_tiocmget,
.tiocmset = mos7840_tiocmset,
- .get_icount = mos7840_get_icount,
+ .tiocmiwait = usb_serial_generic_tiocmiwait,
+ .get_icount = usb_serial_generic_get_icount,
.port_probe = mos7840_port_probe,
.port_remove = mos7840_port_remove,
.read_bulk_callback = mos7840_bulk_in_callback,
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
index 1e1cafe..5739bf6 100644
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -33,8 +33,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 +60,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 +72,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 +109,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,56 +132,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) {
- tty_insert_flip_string(&port->port, data + OMNINET_DATAOFFSET,
- header->oh_len);
- tty_flip_buffer_push(&port->port);
- }
- /* 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,
@@ -209,9 +182,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,
@@ -223,7 +196,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 e13e1a4..5f4b0cd 100644
--- a/drivers/usb/serial/opticon.c
+++ b/drivers/usb/serial/opticon.c
@@ -120,7 +120,10 @@ static int send_control_msg(struct usb_serial_port *port, u8 requesttype,
0, 0, buffer, 1, 0);
kfree(buffer);
- return retval;
+ if (retval < 0)
+ return retval;
+
+ return 0;
}
static int opticon_open(struct tty_struct *tty, struct usb_serial_port *port)
@@ -306,7 +309,6 @@ static int opticon_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear)
{
struct usb_serial_port *port = tty->driver_data;
- struct usb_serial *serial = port->serial;
struct opticon_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
bool rts;
@@ -327,15 +329,11 @@ static int opticon_tiocmset(struct tty_struct *tty,
if (!changed)
return 0;
- /* Send the new RTS state to the connected device */
- mutex_lock(&serial->disc_mutex);
- if (!serial->disconnected)
- ret = send_control_msg(port, CONTROL_RTS, !rts);
- else
- ret = -ENODEV;
- mutex_unlock(&serial->disc_mutex);
+ ret = send_control_msg(port, CONTROL_RTS, !rts);
+ if (ret)
+ return usb_translate_errors(ret);
- return ret;
+ return 0;
}
static int get_serial_info(struct usb_serial_port *port,
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 09cd396..7343728 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -347,6 +347,7 @@ static void option_instat_callback(struct urb *urb);
/* Olivetti products */
#define OLIVETTI_VENDOR_ID 0x0b3c
#define OLIVETTI_PRODUCT_OLICARD100 0xc000
+#define OLIVETTI_PRODUCT_OLICARD145 0xc003
/* Celot products */
#define CELOT_VENDOR_ID 0x211f
@@ -1273,6 +1274,7 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC28_MDMNET) },
{ USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100) },
+ { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD145) },
{ 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.*/
@@ -1350,6 +1352,12 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(TPLINK_VENDOR_ID, TPLINK_PRODUCT_MA180),
.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) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, option_ids);
diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c
index 87c71cc..7e3e078 100644
--- a/drivers/usb/serial/oti6858.c
+++ b/drivers/usb/serial/oti6858.c
@@ -124,8 +124,6 @@ static void oti6858_close(struct usb_serial_port *port);
static void oti6858_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old);
static void oti6858_init_termios(struct tty_struct *tty);
-static int oti6858_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg);
static void oti6858_read_int_callback(struct urb *urb);
static void oti6858_read_bulk_callback(struct urb *urb);
static void oti6858_write_bulk_callback(struct urb *urb);
@@ -136,6 +134,7 @@ static int oti6858_chars_in_buffer(struct tty_struct *tty);
static int oti6858_tiocmget(struct tty_struct *tty);
static int oti6858_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear);
+static int oti6858_tiocmiwait(struct tty_struct *tty, unsigned long arg);
static int oti6858_port_probe(struct usb_serial_port *port);
static int oti6858_port_remove(struct usb_serial_port *port);
@@ -150,11 +149,11 @@ static struct usb_serial_driver oti6858_device = {
.open = oti6858_open,
.close = oti6858_close,
.write = oti6858_write,
- .ioctl = oti6858_ioctl,
.set_termios = oti6858_set_termios,
.init_termios = oti6858_init_termios,
.tiocmget = oti6858_tiocmget,
.tiocmset = oti6858_tiocmset,
+ .tiocmiwait = oti6858_tiocmiwait,
.read_bulk_callback = oti6858_read_bulk_callback,
.read_int_callback = oti6858_read_int_callback,
.write_bulk_callback = oti6858_write_bulk_callback,
@@ -650,8 +649,9 @@ static int oti6858_tiocmget(struct tty_struct *tty)
return result;
}
-static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
+static int oti6858_tiocmiwait(struct tty_struct *tty, unsigned long arg)
{
+ struct usb_serial_port *port = tty->driver_data;
struct oti6858_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
unsigned int prev, status;
@@ -662,7 +662,7 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
spin_unlock_irqrestore(&priv->lock, flags);
while (1) {
- wait_event_interruptible(port->delta_msr_wait,
+ wait_event_interruptible(port->port.delta_msr_wait,
port->serial->disconnected ||
priv->status.pin_state != prev);
if (signal_pending(current))
@@ -689,24 +689,6 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
return 0;
}
-static int oti6858_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
-{
- struct usb_serial_port *port = tty->driver_data;
-
- dev_dbg(&port->dev, "%s(cmd = 0x%04x, arg = 0x%08lx)\n", __func__, cmd, arg);
-
- switch (cmd) {
- case TIOCMIWAIT:
- dev_dbg(&port->dev, "%s(): TIOCMIWAIT\n", __func__);
- return wait_modem_info(port, arg);
- default:
- dev_dbg(&port->dev, "%s(): 0x%04x not supported\n", __func__, cmd);
- break;
- }
- return -ENOIOCTLCMD;
-}
-
static void oti6858_read_int_callback(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
@@ -765,7 +747,7 @@ static void oti6858_read_int_callback(struct urb *urb)
if (!priv->transient) {
if (xs->pin_state != priv->status.pin_state)
- wake_up_interruptible(&port->delta_msr_wait);
+ wake_up_interruptible(&port->port.delta_msr_wait);
memcpy(&priv->status, xs, OTI6858_CTRL_PKT_SIZE);
}
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 3b10018..7151659 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -149,7 +149,7 @@ static int pl2303_vendor_read(__u16 value, __u16 index,
int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,
value, index, buf, 1, 100);
- dev_dbg(&serial->dev->dev, "0x%x:0x%x:0x%x:0x%x %d - %x\n",
+ dev_dbg(&serial->interface->dev, "0x%x:0x%x:0x%x:0x%x %d - %x\n",
VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, value, index,
res, buf[0]);
return res;
@@ -161,7 +161,7 @@ static int pl2303_vendor_write(__u16 value, __u16 index,
int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
value, index, NULL, 0, 100);
- dev_dbg(&serial->dev->dev, "0x%x:0x%x:0x%x:0x%x %d\n",
+ dev_dbg(&serial->interface->dev, "0x%x:0x%x:0x%x:0x%x %d\n",
VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, value, index,
res);
return res;
@@ -248,14 +248,15 @@ static int pl2303_port_remove(struct usb_serial_port *port)
return 0;
}
-static int set_control_lines(struct usb_device *dev, u8 value)
+static int pl2303_set_control_lines(struct usb_serial_port *port, u8 value)
{
+ struct usb_device *dev = port->serial->dev;
int retval;
retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
value, 0, NULL, 0, 100);
- dev_dbg(&dev->dev, "%s - value = %d, retval = %d\n", __func__,
+ dev_dbg(&port->dev, "%s - value = %d, retval = %d\n", __func__,
value, retval);
return retval;
}
@@ -437,7 +438,7 @@ static void pl2303_set_termios(struct tty_struct *tty,
if (control != priv->line_control) {
control = priv->line_control;
spin_unlock_irqrestore(&priv->lock, flags);
- set_control_lines(serial->dev, control);
+ pl2303_set_control_lines(port, control);
} else {
spin_unlock_irqrestore(&priv->lock, flags);
}
@@ -480,7 +481,7 @@ static void pl2303_dtr_rts(struct usb_serial_port *port, int on)
priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
control = priv->line_control;
spin_unlock_irqrestore(&priv->lock, flags);
- set_control_lines(port->serial->dev, control);
+ pl2303_set_control_lines(port, control);
}
static void pl2303_close(struct usb_serial_port *port)
@@ -530,7 +531,6 @@ static int pl2303_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear)
{
struct usb_serial_port *port = tty->driver_data;
- struct usb_serial *serial = port->serial;
struct pl2303_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
u8 control;
@@ -548,14 +548,11 @@ static int pl2303_tiocmset(struct tty_struct *tty,
control = priv->line_control;
spin_unlock_irqrestore(&priv->lock, flags);
- mutex_lock(&serial->disc_mutex);
- if (!serial->disconnected)
- ret = set_control_lines(serial->dev, control);
- else
- ret = -ENODEV;
- mutex_unlock(&serial->disc_mutex);
+ ret = pl2303_set_control_lines(port, control);
+ if (ret)
+ return usb_translate_errors(ret);
- return ret;
+ return 0;
}
static int pl2303_tiocmget(struct tty_struct *tty)
@@ -592,8 +589,9 @@ static int pl2303_carrier_raised(struct usb_serial_port *port)
return 0;
}
-static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
+static int pl2303_tiocmiwait(struct tty_struct *tty, unsigned long arg)
{
+ struct usb_serial_port *port = tty->driver_data;
struct pl2303_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
unsigned int prevstatus;
@@ -605,7 +603,7 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
spin_unlock_irqrestore(&priv->lock, flags);
while (1) {
- interruptible_sleep_on(&port->delta_msr_wait);
+ interruptible_sleep_on(&port->port.delta_msr_wait);
/* see if a signal did it */
if (signal_pending(current))
return -ERESTARTSYS;
@@ -651,10 +649,6 @@ static int pl2303_ioctl(struct tty_struct *tty,
return -EFAULT;
return 0;
-
- case TIOCMIWAIT:
- dev_dbg(&port->dev, "%s TIOCMIWAIT\n", __func__);
- return wait_modem_info(port, arg);
default:
dev_dbg(&port->dev, "%s not supported = 0x%04x\n", __func__, cmd);
break;
@@ -720,7 +714,7 @@ static void pl2303_update_line_status(struct usb_serial_port *port,
spin_unlock_irqrestore(&priv->lock, flags);
if (priv->line_status & UART_BREAK_ERROR)
usb_serial_handle_break(port);
- wake_up_interruptible(&port->delta_msr_wait);
+ wake_up_interruptible(&port->port.delta_msr_wait);
tty = tty_port_tty_get(&port->port);
if (!tty)
@@ -784,7 +778,7 @@ static void pl2303_process_read_urb(struct urb *urb)
line_status = priv->line_status;
priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
spin_unlock_irqrestore(&priv->lock, flags);
- wake_up_interruptible(&port->delta_msr_wait);
+ wake_up_interruptible(&port->port.delta_msr_wait);
if (!urb->actual_length)
return;
@@ -835,6 +829,7 @@ static struct usb_serial_driver pl2303_device = {
.set_termios = pl2303_set_termios,
.tiocmget = pl2303_tiocmget,
.tiocmset = pl2303_tiocmset,
+ .tiocmiwait = pl2303_tiocmiwait,
.process_read_urb = pl2303_process_read_urb,
.read_int_callback = pl2303_read_int_callback,
.attach = pl2303_startup,
diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c
index ef3a7d5..02b0803 100644
--- a/drivers/usb/serial/quatech2.c
+++ b/drivers/usb/serial/quatech2.c
@@ -127,8 +127,6 @@ struct qt2_port_private {
u8 shadowLSR;
u8 shadowMSR;
- struct async_icount icount;
-
struct usb_serial_port *port;
};
@@ -420,12 +418,6 @@ static void qt2_close(struct usb_serial_port *port)
port_priv->urb_in_use = false;
spin_unlock_irqrestore(&port_priv->urb_lock, flags);
- mutex_lock(&port->serial->disc_mutex);
- if (port->serial->disconnected) {
- mutex_unlock(&port->serial->disc_mutex);
- return;
- }
-
/* flush the port transmit buffer */
i = usb_control_msg(serial->dev,
usb_rcvctrlpipe(serial->dev, 0),
@@ -456,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)
@@ -490,71 +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(port->delta_msr_wait,
- (port->serial->disconnected ||
- (priv->icount.rng != prev.rng) ||
- (priv->icount.dsr != prev.dsr) ||
- (priv->icount.dcd != prev.dcd) ||
- (priv->icount.cts != prev.cts)));
-
- if (signal_pending(current))
- return -ERESTARTSYS;
-
- if (port->serial->disconnected)
- return -EIO;
-
- spin_lock_irqsave(&priv->lock, flags);
- cur = priv->icount;
- spin_unlock_irqrestore(&priv->lock, flags);
-
- if ((prev.rng == cur.rng) &&
- (prev.dsr == cur.dsr) &&
- (prev.dcd == cur.dcd) &&
- (prev.cts == cur.cts))
- return -EIO;
-
- if ((arg & TIOCM_RNG && (prev.rng != cur.rng)) ||
- (arg & TIOCM_DSR && (prev.dsr != cur.dsr)) ||
- (arg & TIOCM_CD && (prev.dcd != cur.dcd)) ||
- (arg & TIOCM_CTS && (prev.cts != cur.cts)))
- return 0;
- }
- return 0;
-}
-
-static int qt2_get_icount(struct tty_struct *tty,
- struct serial_icounter_struct *icount)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct qt2_port_private *priv = usb_get_serial_port_data(port);
- struct async_icount cnow = priv->icount;
-
- icount->cts = cnow.cts;
- icount->dsr = cnow.dsr;
- icount->rng = cnow.rng;
- icount->dcd = cnow.dcd;
- icount->rx = cnow.rx;
- icount->tx = cnow.tx;
- icount->frame = cnow.frame;
- icount->overrun = cnow.overrun;
- icount->parity = cnow.parity;
- icount->brk = cnow.brk;
- icount->buf_overrun = cnow.buf_overrun;
-
- return 0;
-}
-
static int qt2_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
@@ -564,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;
}
@@ -948,18 +869,15 @@ static void qt2_update_msr(struct usb_serial_port *port, unsigned char *ch)
if (newMSR & UART_MSR_ANY_DELTA) {
/* update input line counters */
if (newMSR & UART_MSR_DCTS)
- port_priv->icount.cts++;
-
+ port->icount.cts++;
if (newMSR & UART_MSR_DDSR)
- port_priv->icount.dsr++;
-
+ port->icount.dsr++;
if (newMSR & UART_MSR_DDCD)
- port_priv->icount.dcd++;
-
+ port->icount.dcd++;
if (newMSR & UART_MSR_TERI)
- port_priv->icount.rng++;
+ port->icount.rng++;
- wake_up_interruptible(&port->delta_msr_wait);
+ wake_up_interruptible(&port->port.delta_msr_wait);
}
}
@@ -979,7 +897,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) {
@@ -1089,7 +1007,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/sierra.c b/drivers/usb/serial/sierra.c
index d66148a..8894665 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -774,30 +774,25 @@ static void sierra_close(struct usb_serial_port *port)
portdata->rts_state = 0;
portdata->dtr_state = 0;
- if (serial->dev) {
- mutex_lock(&serial->disc_mutex);
- if (!serial->disconnected) {
- serial->interface->needs_remote_wakeup = 0;
- /* odd error handling due to pm counters */
- if (!usb_autopm_get_interface(serial->interface))
- sierra_send_setup(port);
- else
- usb_autopm_get_interface_no_resume(serial->interface);
-
- }
- mutex_unlock(&serial->disc_mutex);
- spin_lock_irq(&intfdata->susp_lock);
- portdata->opened = 0;
- spin_unlock_irq(&intfdata->susp_lock);
+ mutex_lock(&serial->disc_mutex);
+ if (!serial->disconnected) {
+ serial->interface->needs_remote_wakeup = 0;
+ /* odd error handling due to pm counters */
+ if (!usb_autopm_get_interface(serial->interface))
+ sierra_send_setup(port);
+ else
+ usb_autopm_get_interface_no_resume(serial->interface);
+ }
+ mutex_unlock(&serial->disc_mutex);
+ spin_lock_irq(&intfdata->susp_lock);
+ portdata->opened = 0;
+ spin_unlock_irq(&intfdata->susp_lock);
- /* Stop reading urbs */
- sierra_stop_rx_urbs(port);
- /* .. and release them */
- for (i = 0; i < portdata->num_in_urbs; i++) {
- sierra_release_urb(portdata->in_urbs[i]);
- portdata->in_urbs[i] = NULL;
- }
+ sierra_stop_rx_urbs(port);
+ for (i = 0; i < portdata->num_in_urbs; i++) {
+ sierra_release_urb(portdata->in_urbs[i]);
+ portdata->in_urbs[i] = NULL;
}
}
diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c
index 549ef68..cf3df79 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,8 +13,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- *
*/
#include <linux/kernel.h>
#include <linux/errno.h>
@@ -28,7 +26,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 +47,15 @@ static const struct usb_device_id id_table[] = {
{ USB_DEVICE(SPCP8x5_INTERMATIC_VID, SPCP8x5_INTERMATIC_PID)},
{ USB_DEVICE(SPCP8x5_835_VID, SPCP8x5_835_PID)},
{ USB_DEVICE(SPCP8x5_008_VID, SPCP8x5_008_PID)},
- { USB_DEVICE(SPCP8x5_007_VID, SPCP8x5_007_PID)},
+ { USB_DEVICE(SPCP8x5_007_VID, SPCP8x5_007_PID),
+ .driver_info = SPCP825_QUIRK_NO_UART_STATUS |
+ SPCP825_QUIRK_NO_WORK_MODE },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, id_table);
struct spcp8x5_usb_ctrl_arg {
- u8 type;
+ u8 type;
u8 cmd;
u8 cmd_type;
u16 value;
@@ -138,49 +141,33 @@ struct spcp8x5_usb_ctrl_arg {
#define UART_OVERRUN_ERROR 0x40
#define UART_CTS 0x80
-enum spcp8x5_type {
- SPCP825_007_TYPE,
- SPCP825_008_TYPE,
- SPCP825_PHILIP_TYPE,
- SPCP825_INTERMATIC_TYPE,
- SPCP835_TYPE,
-};
-
struct spcp8x5_private {
- spinlock_t lock;
- enum spcp8x5_type type;
- u8 line_control;
- u8 line_status;
+ unsigned quirks;
+ spinlock_t lock;
+ u8 line_control;
};
+static int spcp8x5_probe(struct usb_serial *serial,
+ const struct usb_device_id *id)
+{
+ usb_set_serial_data(serial, (void *)id);
+
+ return 0;
+}
+
static int spcp8x5_port_probe(struct usb_serial_port *port)
{
- struct usb_serial *serial = port->serial;
+ const struct usb_device_id *id = usb_get_serial_data(port->serial);
struct spcp8x5_private *priv;
- enum spcp8x5_type type = SPCP825_007_TYPE;
- u16 product = le16_to_cpu(serial->dev->descriptor.idProduct);
-
- if (product == 0x0201)
- type = SPCP825_007_TYPE;
- else if (product == 0x0231)
- type = SPCP835_TYPE;
- else if (product == 0x0235)
- type = SPCP825_008_TYPE;
- else if (product == 0x0204)
- type = SPCP825_INTERMATIC_TYPE;
- else if (product == 0x0471 &&
- serial->dev->descriptor.idVendor == cpu_to_le16(0x081e))
- type = SPCP825_PHILIP_TYPE;
- dev_dbg(&serial->dev->dev, "device type = %d\n", (int)type);
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
spin_lock_init(&priv->lock);
- priv->type = type;
+ priv->quirks = id->driver_info;
- usb_set_serial_port_data(port , priv);
+ usb_set_serial_port_data(port, priv);
return 0;
}
@@ -195,86 +182,79 @@ static int spcp8x5_port_remove(struct usb_serial_port *port)
return 0;
}
-/* set the modem control line of the device.
- * NOTE spcp825-007 not supported this */
-static int spcp8x5_set_ctrlLine(struct usb_device *dev, u8 value,
- enum spcp8x5_type type)
+static int spcp8x5_set_ctrl_line(struct usb_serial_port *port, u8 mcr)
{
+ struct spcp8x5_private *priv = usb_get_serial_port_data(port);
+ struct usb_device *dev = port->serial->dev;
int retval;
- u8 mcr = 0 ;
- if (type == SPCP825_007_TYPE)
+ if (priv->quirks & SPCP825_QUIRK_NO_UART_STATUS)
return -EPERM;
- mcr = (unsigned short)value;
retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
SET_UART_STATUS_TYPE, SET_UART_STATUS,
mcr, 0x04, NULL, 0, 100);
- if (retval != 0)
- dev_dbg(&dev->dev, "usb_control_msg return %#x\n", retval);
+ if (retval != 0) {
+ dev_err(&port->dev, "failed to set control lines: %d\n",
+ retval);
+ }
return retval;
}
-/* get the modem status register of the device
- * NOTE spcp825-007 not supported this */
-static int spcp8x5_get_msr(struct usb_device *dev, u8 *status,
- enum spcp8x5_type type)
+static int spcp8x5_get_msr(struct usb_serial_port *port, u8 *status)
{
- u8 *status_buffer;
+ struct spcp8x5_private *priv = usb_get_serial_port_data(port);
+ struct usb_device *dev = port->serial->dev;
+ u8 *buf;
int ret;
- /* I return Permited not support here but seem inval device
- * is more fix */
- if (type == SPCP825_007_TYPE)
+ if (priv->quirks & SPCP825_QUIRK_NO_UART_STATUS)
return -EPERM;
- if (status == NULL)
- return -EINVAL;
- status_buffer = kmalloc(1, GFP_KERNEL);
- if (!status_buffer)
+ buf = kzalloc(1, GFP_KERNEL);
+ if (!buf)
return -ENOMEM;
- status_buffer[0] = status[0];
ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
GET_UART_STATUS, GET_UART_STATUS_TYPE,
- 0, GET_UART_STATUS_MSR, status_buffer, 1, 100);
+ 0, GET_UART_STATUS_MSR, buf, 1, 100);
if (ret < 0)
- dev_dbg(&dev->dev, "Get MSR = 0x%p failed (error = %d)",
- status_buffer, ret);
+ dev_err(&port->dev, "failed to get modem status: %d", ret);
- dev_dbg(&dev->dev, "0xc0:0x22:0:6 %d - 0x%p ", ret, status_buffer);
- status[0] = status_buffer[0];
- kfree(status_buffer);
+ dev_dbg(&port->dev, "0xc0:0x22:0:6 %d - 0x02%x", ret, *buf);
+ *status = *buf;
+ kfree(buf);
return ret;
}
-/* select the work mode.
- * NOTE this function not supported by spcp825-007 */
-static void spcp8x5_set_workMode(struct usb_device *dev, u16 value,
- u16 index, enum spcp8x5_type type)
+static void spcp8x5_set_work_mode(struct usb_serial_port *port, u16 value,
+ u16 index)
{
+ struct spcp8x5_private *priv = usb_get_serial_port_data(port);
+ struct usb_device *dev = port->serial->dev;
int ret;
- /* I return Permited not support here but seem inval device
- * is more fix */
- if (type == SPCP825_007_TYPE)
+ if (priv->quirks & SPCP825_QUIRK_NO_WORK_MODE)
return;
ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
SET_WORKING_MODE_TYPE, SET_WORKING_MODE,
value, index, NULL, 0, 100);
- dev_dbg(&dev->dev, "value = %#x , index = %#x\n", value, index);
+ dev_dbg(&port->dev, "value = %#x , index = %#x\n", value, index);
if (ret < 0)
- dev_dbg(&dev->dev,
- "RTSCTS usb_control_msg(enable flowctrl) = %d\n", ret);
+ dev_err(&port->dev, "failed to set work mode: %d\n", ret);
}
static int spcp8x5_carrier_raised(struct usb_serial_port *port)
{
- struct spcp8x5_private *priv = usb_get_serial_port_data(port);
- if (priv->line_status & MSR_STATUS_LINE_DCD)
+ u8 msr;
+ int ret;
+
+ ret = spcp8x5_get_msr(port, &msr);
+ if (ret || msr & MSR_STATUS_LINE_DCD)
return 1;
+
return 0;
}
@@ -293,20 +273,17 @@ static void spcp8x5_dtr_rts(struct usb_serial_port *port, int on)
| MCR_CONTROL_LINE_RTS);
control = priv->line_control;
spin_unlock_irqrestore(&priv->lock, flags);
- spcp8x5_set_ctrlLine(port->serial->dev, control , priv->type);
+ spcp8x5_set_ctrl_line(port, control);
}
static void spcp8x5_init_termios(struct tty_struct *tty)
{
- /* for the 1st time call this function */
tty->termios = tty_std_termios;
tty->termios.c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL;
tty->termios.c_ispeed = 115200;
tty->termios.c_ospeed = 115200;
}
-/* set the serial param for transfer. we should check if we really need to
- * transfer. if we set flow control we should do this too. */
static void spcp8x5_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios)
{
@@ -321,7 +298,6 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
int i;
u8 control;
-
/* check that they really want us to change something */
if (!tty_termios_hw_change(&tty->termios, old_termios))
return;
@@ -337,7 +313,7 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
if (control != priv->line_control) {
control = priv->line_control;
spin_unlock_irqrestore(&priv->lock, flags);
- spcp8x5_set_ctrlLine(serial->dev, control , priv->type);
+ spcp8x5_set_ctrl_line(port, control);
} else {
spin_unlock_irqrestore(&priv->lock, flags);
}
@@ -397,9 +373,9 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
if (cflag & PARENB) {
buf[1] |= (cflag & PARODD) ?
SET_UART_FORMAT_PAR_ODD : SET_UART_FORMAT_PAR_EVEN ;
- } else
+ } else {
buf[1] |= SET_UART_FORMAT_PAR_NONE;
-
+ }
uartdata = buf[0] | buf[1]<<8;
i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
@@ -412,22 +388,16 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
if (cflag & CRTSCTS) {
/* enable hardware flow control */
- spcp8x5_set_workMode(serial->dev, 0x000a,
- SET_WORKING_MODE_U2C, priv->type);
+ spcp8x5_set_work_mode(port, 0x000a, SET_WORKING_MODE_U2C);
}
}
-/* open the serial port. do some usb system call. set termios and get the line
- * status of the device. */
static int spcp8x5_open(struct tty_struct *tty, struct usb_serial_port *port)
{
struct ktermios tmp_termios;
struct usb_serial *serial = port->serial;
struct spcp8x5_private *priv = usb_get_serial_port_data(port);
int ret;
- unsigned long flags;
- u8 status = 0x30;
- /* status 0x30 means DSR and CTS = 1 other CDC RI and delta = 0 */
usb_clear_halt(serial->dev, port->write_urb->pipe);
usb_clear_halt(serial->dev, port->read_urb->pipe);
@@ -438,142 +408,16 @@ static int spcp8x5_open(struct tty_struct *tty, struct usb_serial_port *port)
if (ret)
return ret;
- spcp8x5_set_ctrlLine(serial->dev, priv->line_control , priv->type);
+ spcp8x5_set_ctrl_line(port, priv->line_control);
- /* Setup termios */
if (tty)
spcp8x5_set_termios(tty, port, &tmp_termios);
- spcp8x5_get_msr(serial->dev, &status, priv->type);
-
- /* may be we should update uart status here but now we did not do */
- spin_lock_irqsave(&priv->lock, flags);
- priv->line_status = status & 0xf0 ;
- spin_unlock_irqrestore(&priv->lock, flags);
-
port->port.drain_delay = 256;
return usb_serial_generic_open(tty, port);
}
-static void spcp8x5_process_read_urb(struct urb *urb)
-{
- struct usb_serial_port *port = urb->context;
- struct spcp8x5_private *priv = usb_get_serial_port_data(port);
- unsigned char *data = urb->transfer_buffer;
- unsigned long flags;
- u8 status;
- char tty_flag;
-
- /* get tty_flag from status */
- tty_flag = TTY_NORMAL;
-
- spin_lock_irqsave(&priv->lock, flags);
- status = priv->line_status;
- priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
- spin_unlock_irqrestore(&priv->lock, flags);
- /* wake up the wait for termios */
- wake_up_interruptible(&port->delta_msr_wait);
-
- if (!urb->actual_length)
- return;
-
-
- if (status & UART_STATE_TRANSIENT_MASK) {
- /* break takes precedence over parity, which takes precedence
- * over framing errors */
- if (status & UART_BREAK_ERROR)
- tty_flag = TTY_BREAK;
- else if (status & UART_PARITY_ERROR)
- tty_flag = TTY_PARITY;
- else if (status & UART_FRAME_ERROR)
- tty_flag = TTY_FRAME;
- dev_dbg(&port->dev, "tty_flag = %d\n", tty_flag);
-
- /* overrun is special, not associated with a char */
- if (status & UART_OVERRUN_ERROR)
- tty_insert_flip_char(&port->port, 0, TTY_OVERRUN);
-
- if (status & UART_DCD) {
- struct tty_struct *tty = tty_port_tty_get(&port->port);
- if (tty) {
- usb_serial_handle_dcd_change(port, tty,
- priv->line_status & MSR_STATUS_LINE_DCD);
- tty_kref_put(tty);
- }
- }
- }
-
- tty_insert_flip_string_fixed_flag(&port->port, data, tty_flag,
- urb->actual_length);
- tty_flip_buffer_push(&port->port);
-}
-
-static int spcp8x5_wait_modem_info(struct usb_serial_port *port,
- unsigned int arg)
-{
- struct spcp8x5_private *priv = usb_get_serial_port_data(port);
- unsigned long flags;
- unsigned int prevstatus;
- unsigned int status;
- unsigned int changed;
-
- spin_lock_irqsave(&priv->lock, flags);
- prevstatus = priv->line_status;
- spin_unlock_irqrestore(&priv->lock, flags);
-
- while (1) {
- /* wake up in bulk read */
- interruptible_sleep_on(&port->delta_msr_wait);
-
- /* see if a signal did it */
- if (signal_pending(current))
- return -ERESTARTSYS;
-
- if (port->serial->disconnected)
- return -EIO;
-
- spin_lock_irqsave(&priv->lock, flags);
- status = priv->line_status;
- spin_unlock_irqrestore(&priv->lock, flags);
-
- changed = prevstatus^status;
-
- if (((arg & TIOCM_RNG) && (changed & MSR_STATUS_LINE_RI)) ||
- ((arg & TIOCM_DSR) && (changed & MSR_STATUS_LINE_DSR)) ||
- ((arg & TIOCM_CD) && (changed & MSR_STATUS_LINE_DCD)) ||
- ((arg & TIOCM_CTS) && (changed & MSR_STATUS_LINE_CTS)))
- return 0;
-
- prevstatus = status;
- }
- /* NOTREACHED */
- return 0;
-}
-
-static int spcp8x5_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
-{
- struct usb_serial_port *port = tty->driver_data;
-
- dev_dbg(&port->dev, "%s (%d) cmd = 0x%04x\n", __func__,
- port->number, cmd);
-
- switch (cmd) {
- case TIOCMIWAIT:
- dev_dbg(&port->dev, "%s (%d) TIOCMIWAIT\n", __func__,
- port->number);
- return spcp8x5_wait_modem_info(port, arg);
-
- default:
- dev_dbg(&port->dev, "%s not supported = 0x%04x", __func__,
- cmd);
- break;
- }
-
- return -ENOIOCTLCMD;
-}
-
static int spcp8x5_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear)
{
@@ -594,7 +438,7 @@ static int spcp8x5_tiocmset(struct tty_struct *tty,
control = priv->line_control;
spin_unlock_irqrestore(&priv->lock, flags);
- return spcp8x5_set_ctrlLine(port->serial->dev, control , priv->type);
+ return spcp8x5_set_ctrl_line(port, control);
}
static int spcp8x5_tiocmget(struct tty_struct *tty)
@@ -603,12 +447,15 @@ static int spcp8x5_tiocmget(struct tty_struct *tty)
struct spcp8x5_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
unsigned int mcr;
- unsigned int status;
+ u8 status;
unsigned int result;
+ result = spcp8x5_get_msr(port, &status);
+ if (result)
+ return result;
+
spin_lock_irqsave(&priv->lock, flags);
mcr = priv->line_control;
- status = priv->line_status;
spin_unlock_irqrestore(&priv->lock, flags);
result = ((mcr & MCR_DTR) ? TIOCM_DTR : 0)
@@ -621,7 +468,6 @@ static int spcp8x5_tiocmget(struct tty_struct *tty)
return result;
}
-/* All of the device info needed for the spcp8x5 SIO serial converter */
static struct usb_serial_driver spcp8x5_device = {
.driver = {
.owner = THIS_MODULE,
@@ -629,17 +475,16 @@ static struct usb_serial_driver spcp8x5_device = {
},
.id_table = id_table,
.num_ports = 1,
- .open = spcp8x5_open,
+ .open = spcp8x5_open,
.dtr_rts = spcp8x5_dtr_rts,
.carrier_raised = spcp8x5_carrier_raised,
- .set_termios = spcp8x5_set_termios,
+ .set_termios = spcp8x5_set_termios,
.init_termios = spcp8x5_init_termios,
- .ioctl = spcp8x5_ioctl,
- .tiocmget = spcp8x5_tiocmget,
- .tiocmset = spcp8x5_tiocmset,
+ .tiocmget = spcp8x5_tiocmget,
+ .tiocmset = spcp8x5_tiocmset,
+ .probe = spcp8x5_probe,
.port_probe = spcp8x5_port_probe,
.port_remove = spcp8x5_port_remove,
- .process_read_urb = spcp8x5_process_read_urb,
};
static struct usb_serial_driver * const serial_drivers[] = {
diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c
index 4b2a197..5b62dbb 100644
--- a/drivers/usb/serial/ssu100.c
+++ b/drivers/usb/serial/ssu100.c
@@ -61,7 +61,6 @@ struct ssu100_port_private {
spinlock_t status_lock;
u8 shadowLSR;
u8 shadowMSR;
- struct async_icount icount;
};
static inline int ssu100_control_msg(struct usb_device *dev,
@@ -315,11 +314,6 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port)
return usb_serial_generic_open(tty, port);
}
-static void ssu100_close(struct usb_serial_port *port)
-{
- usb_serial_generic_close(port);
-}
-
static int get_serial_info(struct usb_serial_port *port,
struct serial_struct __user *retinfo)
{
@@ -343,73 +337,6 @@ static int get_serial_info(struct usb_serial_port *port,
return 0;
}
-static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
-{
- struct ssu100_port_private *priv = usb_get_serial_port_data(port);
- struct async_icount prev, cur;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->status_lock, flags);
- prev = priv->icount;
- spin_unlock_irqrestore(&priv->status_lock, flags);
-
- while (1) {
- wait_event_interruptible(port->delta_msr_wait,
- (port->serial->disconnected ||
- (priv->icount.rng != prev.rng) ||
- (priv->icount.dsr != prev.dsr) ||
- (priv->icount.dcd != prev.dcd) ||
- (priv->icount.cts != prev.cts)));
-
- if (signal_pending(current))
- return -ERESTARTSYS;
-
- if (port->serial->disconnected)
- return -EIO;
-
- spin_lock_irqsave(&priv->status_lock, flags);
- cur = priv->icount;
- spin_unlock_irqrestore(&priv->status_lock, flags);
-
- if ((prev.rng == cur.rng) &&
- (prev.dsr == cur.dsr) &&
- (prev.dcd == cur.dcd) &&
- (prev.cts == cur.cts))
- return -EIO;
-
- if ((arg & TIOCM_RNG && (prev.rng != cur.rng)) ||
- (arg & TIOCM_DSR && (prev.dsr != cur.dsr)) ||
- (arg & TIOCM_CD && (prev.dcd != cur.dcd)) ||
- (arg & TIOCM_CTS && (prev.cts != cur.cts)))
- return 0;
- }
- return 0;
-}
-
-static int ssu100_get_icount(struct tty_struct *tty,
- struct serial_icounter_struct *icount)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct ssu100_port_private *priv = usb_get_serial_port_data(port);
- struct async_icount cnow = priv->icount;
-
- icount->cts = cnow.cts;
- icount->dsr = cnow.dsr;
- icount->rng = cnow.rng;
- icount->dcd = cnow.dcd;
- icount->rx = cnow.rx;
- icount->tx = cnow.tx;
- icount->frame = cnow.frame;
- icount->overrun = cnow.overrun;
- icount->parity = cnow.parity;
- icount->brk = cnow.brk;
- icount->buf_overrun = cnow.buf_overrun;
-
- return 0;
-}
-
-
-
static int ssu100_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
@@ -421,10 +348,6 @@ static int ssu100_ioctl(struct tty_struct *tty,
case TIOCGSERIAL:
return get_serial_info(port,
(struct serial_struct __user *) arg);
-
- case TIOCMIWAIT:
- return wait_modem_info(port, arg);
-
default:
break;
}
@@ -532,14 +455,14 @@ static void ssu100_update_msr(struct usb_serial_port *port, u8 msr)
if (msr & UART_MSR_ANY_DELTA) {
/* update input line counters */
if (msr & UART_MSR_DCTS)
- priv->icount.cts++;
+ port->icount.cts++;
if (msr & UART_MSR_DDSR)
- priv->icount.dsr++;
+ port->icount.dsr++;
if (msr & UART_MSR_DDCD)
- priv->icount.dcd++;
+ port->icount.dcd++;
if (msr & UART_MSR_TERI)
- priv->icount.rng++;
- wake_up_interruptible(&port->delta_msr_wait);
+ port->icount.rng++;
+ wake_up_interruptible(&port->port.delta_msr_wait);
}
}
@@ -558,22 +481,22 @@ static void ssu100_update_lsr(struct usb_serial_port *port, u8 lsr,
/* we always want to update icount, but we only want to
* update tty_flag for one case */
if (lsr & UART_LSR_BI) {
- priv->icount.brk++;
+ port->icount.brk++;
*tty_flag = TTY_BREAK;
usb_serial_handle_break(port);
}
if (lsr & UART_LSR_PE) {
- priv->icount.parity++;
+ port->icount.parity++;
if (*tty_flag == TTY_NORMAL)
*tty_flag = TTY_PARITY;
}
if (lsr & UART_LSR_FE) {
- priv->icount.frame++;
+ port->icount.frame++;
if (*tty_flag == TTY_NORMAL)
*tty_flag = TTY_FRAME;
}
if (lsr & UART_LSR_OE){
- priv->icount.overrun++;
+ port->icount.overrun++;
if (*tty_flag == TTY_NORMAL)
*tty_flag = TTY_OVERRUN;
}
@@ -630,7 +553,6 @@ static struct usb_serial_driver ssu100_device = {
.id_table = id_table,
.num_ports = 1,
.open = ssu100_open,
- .close = ssu100_close,
.attach = ssu100_attach,
.port_probe = ssu100_port_probe,
.port_remove = ssu100_port_remove,
@@ -638,10 +560,10 @@ static struct usb_serial_driver ssu100_device = {
.process_read_urb = ssu100_process_read_urb,
.tiocmget = ssu100_tiocmget,
.tiocmset = ssu100_tiocmset,
- .get_icount = ssu100_get_icount,
+ .tiocmiwait = usb_serial_generic_tiocmiwait,
+ .get_icount = usb_serial_generic_get_icount,
.ioctl = ssu100_ioctl,
.set_termios = ssu100_set_termios,
- .disconnect = usb_serial_generic_disconnect,
};
static struct usb_serial_driver * const serial_drivers[] = {
diff --git a/drivers/usb/serial/symbolserial.c b/drivers/usb/serial/symbolserial.c
index be05e6c..9b16489 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.
*
@@ -26,27 +27,17 @@ 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;
int result;
int data_length;
@@ -84,7 +75,7 @@ static void symbol_int_callback(struct urb *urb)
tty_insert_flip_string(&port->port, &data[1], data_length);
tty_flip_buffer_push(&port->port);
} else {
- dev_dbg(&priv->udev->dev,
+ dev_dbg(&port->dev,
"Improper amount of data received from the device, "
"%d bytes", urb->actual_length);
}
@@ -94,12 +85,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",
@@ -118,15 +104,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",
@@ -136,10 +117,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)
@@ -166,7 +144,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",
@@ -176,89 +154,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 = {
@@ -269,12 +194,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 19a71a9..cac47ae 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -67,13 +67,10 @@
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_write_wait;
struct ti_device *tp_tdev;
struct usb_serial_port *tp_port;
@@ -108,8 +105,6 @@ static void ti_throttle(struct tty_struct *tty);
static void ti_unthrottle(struct tty_struct *tty);
static int ti_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg);
-static int ti_get_icount(struct tty_struct *tty,
- struct serial_icounter_struct *icount);
static void ti_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios);
static int ti_tiocmget(struct tty_struct *tty);
@@ -124,15 +119,13 @@ 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);
@@ -235,7 +228,8 @@ static struct usb_serial_driver ti_1port_device = {
.set_termios = ti_set_termios,
.tiocmget = ti_tiocmget,
.tiocmset = ti_tiocmset,
- .get_icount = ti_get_icount,
+ .tiocmiwait = usb_serial_generic_tiocmiwait,
+ .get_icount = usb_serial_generic_get_icount,
.break_ctl = ti_break,
.read_int_callback = ti_interrupt_callback,
.read_bulk_callback = ti_bulk_in_callback,
@@ -265,7 +259,8 @@ static struct usb_serial_driver ti_2port_device = {
.set_termios = ti_set_termios,
.tiocmget = ti_tiocmget,
.tiocmset = ti_tiocmset,
- .get_icount = ti_get_icount,
+ .tiocmiwait = usb_serial_generic_tiocmiwait,
+ .get_icount = usb_serial_generic_get_icount,
.break_ctl = ti_break,
.read_int_callback = ti_interrupt_callback,
.read_bulk_callback = ti_bulk_in_callback,
@@ -430,7 +425,7 @@ 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;
+ port->port.closing_wait = msecs_to_jiffies(10 * closing_wait);
init_waitqueue_head(&tport->tp_write_wait);
if (kfifo_alloc(&tport->write_fifo, TI_WRITE_BUF_SIZE, GFP_KERNEL)) {
kfree(tport);
@@ -480,8 +475,6 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port)
port_number = port->number - port->serial->minor;
- memset(&(tport->tp_icount), 0x00, sizeof(tport->tp_icount));
-
tport->tp_msr = 0;
tport->tp_shadow_mcr |= (TI_MCR_RTS | TI_MCR_DTR);
@@ -585,6 +578,8 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port)
tport->tp_is_open = 1;
++tdev->td_open_port_count;
+ port->port.drain_delay = 3;
+
goto release_lock;
unlink_int_urb:
@@ -604,6 +599,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);
@@ -612,11 +608,12 @@ 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(&tport->write_fifo);
+ spin_unlock_irqrestore(&tport->tp_lock, flags);
port_number = port->number - port->serial->minor;
@@ -687,6 +684,8 @@ static int ti_chars_in_buffer(struct tty_struct *tty)
struct ti_port *tport = usb_get_serial_port_data(port);
int chars = 0;
unsigned long flags;
+ int ret;
+ u8 lsr;
if (tport == NULL)
return 0;
@@ -695,6 +694,12 @@ static int ti_chars_in_buffer(struct tty_struct *tty)
chars = kfifo_len(&tport->write_fifo);
spin_unlock_irqrestore(&tport->tp_lock, flags);
+ if (!chars) {
+ ret = ti_get_lsr(tport, &lsr);
+ if (!ret && !(lsr & TI_LSR_TX_EMPTY))
+ chars = 1;
+ }
+
dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars);
return chars;
}
@@ -731,38 +736,11 @@ static void ti_unthrottle(struct tty_struct *tty)
}
}
-static int ti_get_icount(struct tty_struct *tty,
- struct serial_icounter_struct *icount)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct ti_port *tport = usb_get_serial_port_data(port);
- struct async_icount cnow = tport->tp_icount;
-
- dev_dbg(&port->dev, "%s - TIOCGICOUNT RX=%d, TX=%d\n", __func__,
- cnow.rx, cnow.tx);
-
- icount->cts = cnow.cts;
- icount->dsr = cnow.dsr;
- icount->rng = cnow.rng;
- icount->dcd = cnow.dcd;
- icount->rx = cnow.rx;
- icount->tx = cnow.tx;
- icount->frame = cnow.frame;
- icount->overrun = cnow.overrun;
- icount->parity = cnow.parity;
- icount->brk = cnow.brk;
- icount->buf_overrun = cnow.buf_overrun;
-
- return 0;
-}
-
static int ti_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
struct usb_serial_port *port = tty->driver_data;
struct ti_port *tport = usb_get_serial_port_data(port);
- struct async_icount cnow;
- struct async_icount cprev;
dev_dbg(&port->dev, "%s - cmd = 0x%04X\n", __func__, cmd);
@@ -778,29 +756,6 @@ static int ti_ioctl(struct tty_struct *tty,
dev_dbg(&port->dev, "%s - TIOCSSERIAL\n", __func__);
return ti_set_serial_info(tty, tport,
(struct serial_struct __user *)arg);
- case TIOCMIWAIT:
- dev_dbg(&port->dev, "%s - TIOCMIWAIT\n", __func__);
- cprev = tport->tp_icount;
- while (1) {
- interruptible_sleep_on(&port->delta_msr_wait);
- if (signal_pending(current))
- return -ERESTARTSYS;
-
- if (port->serial->disconnected)
- return -EIO;
-
- cnow = tport->tp_icount;
- if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
- cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
- return -EIO; /* no change => error */
- if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
- ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
- ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
- ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)))
- return 0;
- cprev = cnow;
- }
- break;
}
return -ENOIOCTLCMD;
}
@@ -1018,8 +973,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);
@@ -1156,7 +1109,7 @@ static void ti_bulk_in_callback(struct urb *urb)
else
ti_recv(port, urb->transfer_buffer, urb->actual_length);
spin_lock(&tport->tp_lock);
- tport->tp_icount.rx += urb->actual_length;
+ port->icount.rx += urb->actual_length;
spin_unlock(&tport->tp_lock);
}
@@ -1264,7 +1217,7 @@ static void ti_send(struct ti_port *tport)
/* TODO: reschedule ti_send */
} else {
spin_lock_irqsave(&tport->tp_lock, flags);
- tport->tp_icount.tx += count;
+ port->icount.tx += count;
spin_unlock_irqrestore(&tport->tp_lock, flags);
}
@@ -1297,7 +1250,7 @@ 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;
@@ -1323,7 +1276,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);
@@ -1336,10 +1289,15 @@ 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;
@@ -1348,7 +1306,7 @@ static int ti_get_serial_info(struct ti_port *tport,
ret_serial.flags = tport->tp_flags;
ret_serial.xmit_fifo_size = TI_WRITE_BUF_SIZE;
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;
@@ -1361,12 +1319,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;
}
@@ -1382,7 +1345,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)
@@ -1391,7 +1354,7 @@ static void ti_handle_new_msr(struct ti_port *tport, __u8 msr)
icount->dcd++;
if (msr & TI_MSR_DELTA_RI)
icount->rng++;
- wake_up_interruptible(&tport->tp_port->delta_msr_wait);
+ wake_up_interruptible(&tport->tp_port->port.delta_msr_wait);
spin_unlock_irqrestore(&tport->tp_lock, flags);
}
@@ -1411,56 +1374,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;
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 650be17..cf75beb 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
@@ -49,7 +49,6 @@
drivers depend on it.
*/
-/* initially all NULL */
static struct usb_serial *serial_table[SERIAL_TTY_MINORS];
static DEFINE_MUTEX(table_lock);
static LIST_HEAD(usb_serial_driver_list);
@@ -139,7 +138,7 @@ static void destroy_serial(struct kref *kref)
if (serial->minor != SERIAL_TTY_NO_MINOR)
return_serial(serial);
- if (serial->attached)
+ if (serial->attached && serial->type->release)
serial->type->release(serial);
/* Now that nothing is using the ports, they can be freed */
@@ -225,7 +224,7 @@ static int serial_install(struct tty_driver *driver, struct tty_struct *tty)
return retval;
}
-static int serial_activate(struct tty_port *tport, struct tty_struct *tty)
+static int serial_port_activate(struct tty_port *tport, struct tty_struct *tty)
{
struct usb_serial_port *port =
container_of(tport, struct usb_serial_port, port);
@@ -249,30 +248,27 @@ static int serial_open(struct tty_struct *tty, struct file *filp)
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+ dev_dbg(tty->dev, "%s\n", __func__);
+
return tty_port_open(&port->port, tty, filp);
}
/**
- * serial_down - shut down hardware
+ * serial_port_shutdown - shut down hardware
* @tport: tty port to shut down
*
- * Shut down a USB serial port unless it is the console. We never
- * shut down the console hardware as it will always be in use. Serialized
- * against activate by the tport mutex and kept to matching open/close pairs
+ * Shut down a USB serial port. Serialized against activate by the
+ * tport mutex and kept to matching open/close pairs
* of calls by the ASYNCB_INITIALIZED flag.
+ *
+ * Not called if tty is console.
*/
-static void serial_down(struct tty_port *tport)
+static void serial_port_shutdown(struct tty_port *tport)
{
struct usb_serial_port *port =
container_of(tport, struct usb_serial_port, port);
struct usb_serial_driver *drv = port->serial->type;
- /*
- * The console is magical. Do not hang up the console hardware
- * or there will be tears.
- */
- if (port->port.console)
- return;
+
if (drv->close)
drv->close(port);
}
@@ -281,7 +277,8 @@ static void serial_hangup(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+ dev_dbg(tty->dev, "%s\n", __func__);
+
tty_port_hangup(&port->port);
}
@@ -289,7 +286,8 @@ static void serial_close(struct tty_struct *tty, struct file *filp)
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+ dev_dbg(tty->dev, "%s\n", __func__);
+
tty_port_close(&port->port, tty, filp);
}
@@ -308,14 +306,14 @@ static void serial_cleanup(struct tty_struct *tty)
struct usb_serial *serial;
struct module *owner;
+ dev_dbg(tty->dev, "%s\n", __func__);
+
/* The console is magical. Do not hang up the console hardware
* or there will be tears.
*/
if (port->port.console)
return;
- dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
-
tty->driver_data = NULL;
serial = port->serial;
@@ -339,10 +337,8 @@ static int serial_write(struct tty_struct *tty, const unsigned char *buf,
if (port->serial->dev->state == USB_STATE_NOTATTACHED)
goto exit;
- dev_dbg(tty->dev, "%s - port %d, %d byte(s)\n", __func__,
- port->number, count);
+ dev_dbg(tty->dev, "%s - %d byte(s)\n", __func__, count);
- /* pass on to the driver specific version of this function */
retval = port->serial->type->write(tty, port, buf, count);
if (retval < 0)
retval = usb_translate_errors(retval);
@@ -354,8 +350,8 @@ static int serial_write_room(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
- /* pass on to the driver specific version of this function */
+ dev_dbg(tty->dev, "%s\n", __func__);
+
return port->serial->type->write_room(tty);
}
@@ -365,7 +361,7 @@ static int serial_chars_in_buffer(struct tty_struct *tty)
struct usb_serial *serial = port->serial;
int count = 0;
- dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+ dev_dbg(tty->dev, "%s\n", __func__);
mutex_lock(&serial->disc_mutex);
/* if the device was unplugged then any remaining characters
@@ -383,9 +379,8 @@ static void serial_throttle(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+ dev_dbg(tty->dev, "%s\n", __func__);
- /* pass on to the driver specific version of this function */
if (port->serial->type->throttle)
port->serial->type->throttle(tty);
}
@@ -394,9 +389,8 @@ static void serial_unthrottle(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+ dev_dbg(tty->dev, "%s\n", __func__);
- /* pass on to the driver specific version of this function */
if (port->serial->type->unthrottle)
port->serial->type->unthrottle(tty);
}
@@ -407,15 +401,20 @@ static int serial_ioctl(struct tty_struct *tty,
struct usb_serial_port *port = tty->driver_data;
int retval = -ENODEV;
- dev_dbg(tty->dev, "%s - port %d, cmd 0x%.4x\n", __func__,
- port->number, cmd);
+ dev_dbg(tty->dev, "%s - cmd 0x%.4x\n", __func__, cmd);
+
+ switch (cmd) {
+ case TIOCMIWAIT:
+ if (port->serial->type->tiocmiwait)
+ retval = port->serial->type->tiocmiwait(tty, arg);
+ break;
+ default:
+ if (port->serial->type->ioctl)
+ retval = port->serial->type->ioctl(tty, cmd, arg);
+ else
+ retval = -ENOIOCTLCMD;
+ }
- /* pass on to the driver specific version of this function
- if it is available */
- if (port->serial->type->ioctl) {
- retval = port->serial->type->ioctl(tty, cmd, arg);
- } else
- retval = -ENOIOCTLCMD;
return retval;
}
@@ -423,10 +422,8 @@ static void serial_set_termios(struct tty_struct *tty, struct ktermios *old)
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+ dev_dbg(tty->dev, "%s\n", __func__);
- /* pass on to the driver specific version of this function
- if it is available */
if (port->serial->type->set_termios)
port->serial->type->set_termios(tty, port, old);
else
@@ -437,12 +434,11 @@ static int serial_break(struct tty_struct *tty, int break_state)
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+ dev_dbg(tty->dev, "%s\n", __func__);
- /* pass on to the driver specific version of this function
- if it is available */
if (port->serial->type->break_ctl)
port->serial->type->break_ctl(tty, break_state);
+
return 0;
}
@@ -496,7 +492,7 @@ static int serial_tiocmget(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+ dev_dbg(tty->dev, "%s\n", __func__);
if (port->serial->type->tiocmget)
return port->serial->type->tiocmget(tty);
@@ -508,7 +504,7 @@ static int serial_tiocmset(struct tty_struct *tty,
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+ dev_dbg(tty->dev, "%s\n", __func__);
if (port->serial->type->tiocmset)
return port->serial->type->tiocmset(tty, set, clear);
@@ -520,7 +516,7 @@ static int serial_get_icount(struct tty_struct *tty,
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+ dev_dbg(tty->dev, "%s\n", __func__);
if (port->serial->type->get_icount)
return port->serial->type->get_icount(tty, icount);
@@ -546,43 +542,39 @@ static void usb_serial_port_work(struct work_struct *work)
tty_port_tty_wakeup(&port->port);
}
-static void kill_traffic(struct usb_serial_port *port)
+static void usb_serial_port_poison_urbs(struct usb_serial_port *port)
{
int i;
for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i)
- usb_kill_urb(port->read_urbs[i]);
+ usb_poison_urb(port->read_urbs[i]);
for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i)
- usb_kill_urb(port->write_urbs[i]);
- /*
- * This is tricky.
- * Some drivers submit the read_urb in the
- * handler for the write_urb or vice versa
- * this order determines the order in which
- * usb_kill_urb() must be used to reliably
- * kill the URBs. As it is unknown here,
- * both orders must be used in turn.
- * The call below is not redundant.
- */
- usb_kill_urb(port->read_urb);
- usb_kill_urb(port->interrupt_in_urb);
- usb_kill_urb(port->interrupt_out_urb);
+ usb_poison_urb(port->write_urbs[i]);
+
+ usb_poison_urb(port->interrupt_in_urb);
+ usb_poison_urb(port->interrupt_out_urb);
+}
+
+static void usb_serial_port_unpoison_urbs(struct usb_serial_port *port)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i)
+ usb_unpoison_urb(port->read_urbs[i]);
+ for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i)
+ usb_unpoison_urb(port->write_urbs[i]);
+
+ usb_unpoison_urb(port->interrupt_in_urb);
+ usb_unpoison_urb(port->interrupt_out_urb);
}
-static void port_release(struct device *dev)
+static void usb_serial_port_release(struct device *dev)
{
struct usb_serial_port *port = to_usb_serial_port(dev);
int i;
dev_dbg(dev, "%s\n", __func__);
- /*
- * Stop all the traffic before cancelling the work, so that
- * nobody will restart it by calling usb_serial_port_softint.
- */
- kill_traffic(port);
- cancel_work_sync(&port->work);
-
usb_free_urb(port->interrupt_in_urb);
usb_free_urb(port->interrupt_out_urb);
for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) {
@@ -607,10 +599,8 @@ static struct usb_serial *create_serial(struct usb_device *dev,
struct usb_serial *serial;
serial = kzalloc(sizeof(*serial), GFP_KERNEL);
- if (!serial) {
- dev_err(&dev->dev, "%s - out of memory\n", __func__);
+ if (!serial)
return NULL;
- }
serial->dev = usb_get_dev(dev);
serial->type = driver;
serial->interface = usb_get_intf(interface);
@@ -673,7 +663,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;
@@ -684,7 +674,7 @@ static int serial_carrier_raised(struct tty_port *port)
return 1;
}
-static void serial_dtr_rts(struct tty_port *port, int on)
+static void serial_port_dtr_rts(struct tty_port *port, int on)
{
struct usb_serial_port *p = container_of(port, struct usb_serial_port, port);
struct usb_serial *serial = p->serial;
@@ -704,10 +694,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,
@@ -754,7 +744,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;
}
@@ -895,7 +884,6 @@ static int usb_serial_probe(struct usb_interface *interface,
port->port.ops = &serial_port_ops;
port->serial = serial;
spin_lock_init(&port->lock);
- init_waitqueue_head(&port->delta_msr_wait);
/* Keep this for private driver use for the moment but
should probably go away */
INIT_WORK(&port->work, usb_serial_port_work);
@@ -903,7 +891,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);
}
@@ -919,16 +907,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),
@@ -955,16 +939,12 @@ static int usb_serial_probe(struct usb_interface *interface,
for (j = 0; j < ARRAY_SIZE(port->write_urbs); ++j) {
set_bit(j, &port->write_urbs_free);
port->write_urbs[j] = usb_alloc_urb(0, GFP_KERNEL);
- if (!port->write_urbs[j]) {
- dev_err(ddev, "No free urbs available\n");
+ if (!port->write_urbs[j])
goto probe_error;
- }
port->bulk_out_buffers[j] = kmalloc(buffer_size,
GFP_KERNEL);
- if (!port->bulk_out_buffers[j]) {
- dev_err(ddev, "Couldn't allocate bulk_out_buffer\n");
+ if (!port->bulk_out_buffers[j])
goto probe_error;
- }
usb_fill_bulk_urb(port->write_urbs[j], dev,
usb_sndbulkpipe(dev,
endpoint->bEndpointAddress),
@@ -982,19 +962,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),
@@ -1011,20 +987,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),
@@ -1113,13 +1085,15 @@ static void usb_serial_disconnect(struct usb_interface *interface)
tty_vhangup(tty);
tty_kref_put(tty);
}
- kill_traffic(port);
+ usb_serial_port_poison_urbs(port);
+ wake_up_interruptible(&port->port.delta_msr_wait);
cancel_work_sync(&port->work);
if (device_is_registered(&port->dev))
device_del(&port->dev);
}
}
- serial->type->disconnect(serial);
+ if (serial->type->disconnect)
+ serial->type->disconnect(serial);
/* let the last holder of this object cause it to be cleaned up */
usb_serial_put(serial);
@@ -1134,6 +1108,11 @@ int usb_serial_suspend(struct usb_interface *intf, pm_message_t message)
serial->suspending = 1;
+ /*
+ * serial->type->suspend() MUST return 0 in system sleep context,
+ * otherwise, the resume callback has to recover device from
+ * previous suspend failure.
+ */
if (serial->type->suspend) {
r = serial->type->suspend(serial, message);
if (r < 0) {
@@ -1145,7 +1124,7 @@ int usb_serial_suspend(struct usb_interface *intf, pm_message_t message)
for (i = 0; i < serial->num_ports; ++i) {
port = serial->port[i];
if (port)
- kill_traffic(port);
+ usb_serial_port_poison_urbs(port);
}
err_out:
@@ -1153,11 +1132,25 @@ err_out:
}
EXPORT_SYMBOL(usb_serial_suspend);
+static void usb_serial_unpoison_port_urbs(struct usb_serial *serial)
+{
+ struct usb_serial_port *port;
+ int i;
+
+ for (i = 0; i < serial->num_ports; ++i) {
+ port = serial->port[i];
+ if (port)
+ usb_serial_port_unpoison_urbs(port);
+ }
+}
+
int usb_serial_resume(struct usb_interface *intf)
{
struct usb_serial *serial = usb_get_intfdata(intf);
int rv;
+ usb_serial_unpoison_port_urbs(serial);
+
serial->suspending = 0;
if (serial->type->resume)
rv = serial->type->resume(serial);
@@ -1173,6 +1166,8 @@ static int usb_serial_reset_resume(struct usb_interface *intf)
struct usb_serial *serial = usb_get_intfdata(intf);
int rv;
+ usb_serial_unpoison_port_urbs(serial);
+
serial->suspending = 0;
if (serial->type->reset_resume)
rv = serial->type->reset_resume(serial);
@@ -1309,12 +1304,12 @@ module_exit(usb_serial_exit);
do { \
if (!type->function) { \
type->function = usb_serial_generic_##function; \
- pr_debug("Had to override the " #function \
- " usb serial operation with the generic one.");\
- } \
+ pr_debug("%s: using generic " #function "\n", \
+ type->driver.name); \
+ } \
} while (0)
-static void fixup_generic(struct usb_serial_driver *device)
+static void usb_serial_operations_init(struct usb_serial_driver *device)
{
set_to_generic_if_null(device, open);
set_to_generic_if_null(device, write);
@@ -1323,8 +1318,6 @@ static void fixup_generic(struct usb_serial_driver *device)
set_to_generic_if_null(device, chars_in_buffer);
set_to_generic_if_null(device, read_bulk_callback);
set_to_generic_if_null(device, write_bulk_callback);
- set_to_generic_if_null(device, disconnect);
- set_to_generic_if_null(device, release);
set_to_generic_if_null(device, process_read_urb);
set_to_generic_if_null(device, prepare_write_buffer);
}
@@ -1336,8 +1329,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) {
@@ -1346,6 +1337,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);
@@ -1463,7 +1456,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.c b/drivers/usb/serial/usb_wwan.c
index 571965a..ece326e 100644
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
@@ -421,20 +421,19 @@ void usb_wwan_close(struct usb_serial_port *port)
portdata = usb_get_serial_port_data(port);
- if (serial->dev) {
- /* Stop reading/writing urbs */
- spin_lock_irq(&intfdata->susp_lock);
- portdata->opened = 0;
- spin_unlock_irq(&intfdata->susp_lock);
+ /* Stop reading/writing urbs */
+ spin_lock_irq(&intfdata->susp_lock);
+ portdata->opened = 0;
+ spin_unlock_irq(&intfdata->susp_lock);
- for (i = 0; i < N_IN_URB; i++)
- usb_kill_urb(portdata->in_urbs[i]);
- for (i = 0; i < N_OUT_URB; i++)
- usb_kill_urb(portdata->out_urbs[i]);
- /* balancing - important as an error cannot be handled*/
- usb_autopm_get_interface_no_resume(serial->interface);
- serial->interface->needs_remote_wakeup = 0;
- }
+ for (i = 0; i < N_IN_URB; i++)
+ usb_kill_urb(portdata->in_urbs[i]);
+ for (i = 0; i < N_OUT_URB; i++)
+ usb_kill_urb(portdata->out_urbs[i]);
+
+ /* balancing - important as an error cannot be handled*/
+ usb_autopm_get_interface_no_resume(serial->interface);
+ serial->interface->needs_remote_wakeup = 0;
}
EXPORT_SYMBOL(usb_wwan_close);
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index 1129aa7..7573ec8 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -257,24 +257,18 @@ static void visor_close(struct usb_serial_port *port)
{
unsigned char *transfer_buffer;
- /* shutdown our urbs */
usb_serial_generic_close(port);
usb_kill_urb(port->interrupt_in_urb);
- mutex_lock(&port->serial->disc_mutex);
- if (!port->serial->disconnected) {
- /* Try to send shutdown message, unless the device is gone */
- transfer_buffer = kmalloc(0x12, GFP_KERNEL);
- if (transfer_buffer) {
- usb_control_msg(port->serial->dev,
+ transfer_buffer = kmalloc(0x12, GFP_KERNEL);
+ if (!transfer_buffer)
+ return;
+ usb_control_msg(port->serial->dev,
usb_rcvctrlpipe(port->serial->dev, 0),
VISOR_CLOSE_NOTIFICATION, 0xc2,
0x0000, 0x0000,
transfer_buffer, 0x12, 300);
- kfree(transfer_buffer);
- }
- }
- mutex_unlock(&port->serial->disc_mutex);
+ kfree(transfer_buffer);
}
static void visor_read_int_callback(struct urb *urb)
diff --git a/drivers/usb/serial/wishbone-serial.c b/drivers/usb/serial/wishbone-serial.c
new file mode 100644
index 0000000..100573c
--- /dev/null
+++ b/drivers/usb/serial/wishbone-serial.c
@@ -0,0 +1,95 @@
+/*
+ * 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/init.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");
OpenPOWER on IntegriCloud