summaryrefslogtreecommitdiff
path: root/drivers/usb/serial
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/serial')
-rw-r--r--drivers/usb/serial/Kconfig12
-rw-r--r--drivers/usb/serial/Makefile1
-rw-r--r--drivers/usb/serial/io_ti.c89
-rw-r--r--drivers/usb/serial/keyspan.c4
-rw-r--r--drivers/usb/serial/option.c10
-rw-r--r--drivers/usb/serial/usb-serial.c14
-rw-r--r--drivers/usb/serial/xsens_mt.c86
7 files changed, 142 insertions, 74 deletions
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index 76f462241738..dad8363e5b2a 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -647,6 +647,18 @@ config USB_SERIAL_VIVOPAY_SERIAL
To compile this driver as a module, choose M here: the
module will be called vivopay-serial.
+config USB_SERIAL_XSENS_MT
+ tristate "Xsens motion tracker serial interface driver"
+ help
+ Say Y here if you want to use Xsens motion trackers.
+
+ This driver supports the new generation of motion trackers
+ by Xsens. Older devices can be accessed using the FTDI_SIO
+ driver.
+
+ To compile this driver as a module, choose M here: the
+ module will be called xsens_mt.
+
config USB_SERIAL_ZIO
tristate "ZIO Motherboard USB serial interface driver"
help
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index 3b3e7308d476..eaf5ca14dfeb 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -61,5 +61,6 @@ obj-$(CONFIG_USB_SERIAL_VISOR) += visor.o
obj-$(CONFIG_USB_SERIAL_WHITEHEAT) += whiteheat.o
obj-$(CONFIG_USB_SERIAL_XIRCOM) += keyspan_pda.o
obj-$(CONFIG_USB_SERIAL_VIVOPAY_SERIAL) += vivopay-serial.o
+obj-$(CONFIG_USB_SERIAL_XSENS_MT) += xsens_mt.o
obj-$(CONFIG_USB_SERIAL_ZIO) += zio.o
obj-$(CONFIG_USB_SERIAL_ZTE) += zte_ev.o
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index 82afc4d6a327..641ab3da2d83 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -521,65 +521,6 @@ exit_is_tx_active:
return bytes_left;
}
-static void chase_port(struct edgeport_port *port, unsigned long timeout,
- int flush)
-{
- int baud_rate;
- struct tty_struct *tty = tty_port_tty_get(&port->port->port);
- struct usb_serial *serial = port->port->serial;
- wait_queue_t wait;
- unsigned long flags;
-
- if (!tty)
- return;
-
- if (!timeout)
- timeout = (HZ * EDGE_CLOSING_WAIT)/100;
-
- /* wait for data to drain from the buffer */
- spin_lock_irqsave(&port->ep_lock, flags);
- init_waitqueue_entry(&wait, current);
- add_wait_queue(&tty->write_wait, &wait);
- for (;;) {
- set_current_state(TASK_INTERRUPTIBLE);
- if (kfifo_len(&port->write_fifo) == 0
- || timeout == 0 || signal_pending(current)
- || serial->disconnected)
- /* disconnect */
- break;
- spin_unlock_irqrestore(&port->ep_lock, flags);
- timeout = schedule_timeout(timeout);
- spin_lock_irqsave(&port->ep_lock, flags);
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&tty->write_wait, &wait);
- if (flush)
- kfifo_reset_out(&port->write_fifo);
- spin_unlock_irqrestore(&port->ep_lock, flags);
- tty_kref_put(tty);
-
- /* wait for data to drain from the device */
- timeout += jiffies;
- while ((long)(jiffies - timeout) < 0 && !signal_pending(current)
- && !serial->disconnected) {
- /* not disconnected */
- if (!tx_active(port))
- break;
- msleep(10);
- }
-
- /* disconnected */
- if (serial->disconnected)
- return;
-
- /* wait one more character time, based on baud rate */
- /* (tx_active doesn't seem to wait for the last byte) */
- baud_rate = port->baud_rate;
- if (baud_rate == 0)
- baud_rate = 50;
- msleep(max(1, DIV_ROUND_UP(10000, baud_rate)));
-}
-
static int choose_config(struct usb_device *dev)
{
/*
@@ -1944,6 +1885,8 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port)
++edge_serial->num_ports_open;
+ port->port.drain_delay = 1;
+
goto release_es_lock;
unlink_int_urb:
@@ -1959,6 +1902,7 @@ static void edge_close(struct usb_serial_port *port)
struct edgeport_serial *edge_serial;
struct edgeport_port *edge_port;
struct usb_serial *serial = port->serial;
+ unsigned long flags;
int port_number;
edge_serial = usb_get_serial_data(port->serial);
@@ -1970,12 +1914,12 @@ static void edge_close(struct usb_serial_port *port)
* this flag and dump add read data */
edge_port->close_pending = 1;
- /* chase the port close and flush */
- chase_port(edge_port, (HZ * closing_wait) / 100, 1);
-
usb_kill_urb(port->read_urb);
usb_kill_urb(port->write_urb);
edge_port->ep_write_urb_in_use = 0;
+ spin_lock_irqsave(&edge_port->ep_lock, flags);
+ kfifo_reset_out(&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 */
@@ -2101,16 +2045,21 @@ static int edge_chars_in_buffer(struct tty_struct *tty)
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
int chars = 0;
unsigned long flags;
+ int ret;
if (edge_port == NULL)
return 0;
- if (edge_port->close_pending == 1)
- return 0;
spin_lock_irqsave(&edge_port->ep_lock, flags);
chars = kfifo_len(&edge_port->write_fifo);
spin_unlock_irqrestore(&edge_port->ep_lock, flags);
+ if (!chars) {
+ ret = tx_active(edge_port);
+ if (ret > 0)
+ chars = ret;
+ }
+
dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars);
return chars;
}
@@ -2448,10 +2397,15 @@ static int get_serial_info(struct edgeport_port *edge_port,
struct serial_struct __user *retinfo)
{
struct serial_struct tmp;
+ unsigned cwait;
if (!retinfo)
return -EFAULT;
+ cwait = edge_port->port->port.closing_wait;
+ if (cwait != ASYNC_CLOSING_WAIT_NONE)
+ cwait = jiffies_to_msecs(closing_wait) / 10;
+
memset(&tmp, 0, sizeof(tmp));
tmp.type = PORT_16550A;
@@ -2462,7 +2416,7 @@ static int get_serial_info(struct edgeport_port *edge_port,
tmp.xmit_fifo_size = edge_port->port->bulk_out_size;
tmp.baud_base = 9600;
tmp.close_delay = 5*HZ;
- tmp.closing_wait = closing_wait;
+ tmp.closing_wait = cwait;
if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
return -EFAULT;
@@ -2517,8 +2471,7 @@ static void edge_break(struct tty_struct *tty, int break_state)
int status;
int bv = 0; /* Off */
- /* chase the port close */
- chase_port(edge_port, 0, 0);
+ tty_wait_until_sent(tty, 0);
if (break_state == -1)
bv = 1; /* On */
@@ -2591,6 +2544,8 @@ static int edge_port_probe(struct usb_serial_port *port)
return ret;
}
+ port->port.closing_wait = msecs_to_jiffies(closing_wait * 10);
+
return 0;
}
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index 97bc49f68efd..3d95637f3d68 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -298,7 +298,7 @@ static void usa26_indat_callback(struct urb *urb)
endpoint = usb_pipeendpoint(urb->pipe);
if (status) {
- dev_dbg(&urb->dev->dev,"%s - nonzero status: %x on endpoint %d.\n",
+ dev_dbg(&urb->dev->dev, "%s - nonzero status: %x on endpoint %d.\n",
__func__, status, endpoint);
return;
}
@@ -532,7 +532,7 @@ static void usa28_instat_callback(struct urb *urb)
/*
dev_dbg(&urb->dev->dev,
- "%s %x %x %x %x %x %x %x %x %x %x %x %x", __func__,
+ "%s %x %x %x %x %x %x %x %x %x %x %x %x", __func__,
data[0], data[1], data[2], data[3], data[4], data[5],
data[6], data[7], data[8], data[9], data[10], data[11]);
*/
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 0d9dac9e7f93..b51abfd87cc6 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -474,6 +474,7 @@ static const struct option_blacklist_info four_g_w14_blacklist = {
static const struct option_blacklist_info alcatel_x200_blacklist = {
.sendsetup = BIT(0) | BIT(1),
+ .reserved = BIT(4),
};
static const struct option_blacklist_info zte_0037_blacklist = {
@@ -1203,7 +1204,14 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X060S_X200),
.driver_info = (kernel_ulong_t)&alcatel_x200_blacklist
},
- { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X220_X500D) },
+ { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X220_X500D),
+ .driver_info = (kernel_ulong_t)&net_intf6_blacklist },
+ { USB_DEVICE(ALCATEL_VENDOR_ID, 0x0052),
+ .driver_info = (kernel_ulong_t)&net_intf6_blacklist },
+ { USB_DEVICE(ALCATEL_VENDOR_ID, 0x00b6),
+ .driver_info = (kernel_ulong_t)&net_intf3_blacklist },
+ { USB_DEVICE(ALCATEL_VENDOR_ID, 0x00b7),
+ .driver_info = (kernel_ulong_t)&net_intf5_blacklist },
{ USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_L100V),
.driver_info = (kernel_ulong_t)&net_intf4_blacklist },
{ USB_DEVICE(AIRPLUS_VENDOR_ID, AIRPLUS_PRODUCT_MCD650) },
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 64bda135ba7e..0a17f5942552 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -361,15 +361,21 @@ static int serial_write_room(struct tty_struct *tty)
static int serial_chars_in_buffer(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
+ struct usb_serial *serial = port->serial;
+ int count = 0;
dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+ mutex_lock(&serial->disc_mutex);
/* if the device was unplugged then any remaining characters
fell out of the connector ;) */
- if (port->serial->disconnected)
- return 0;
- /* pass on to the driver specific version of this function */
- return port->serial->type->chars_in_buffer(tty);
+ if (serial->disconnected)
+ count = 0;
+ else
+ count = serial->type->chars_in_buffer(tty);
+ mutex_unlock(&serial->disc_mutex);
+
+ return count;
}
static void serial_throttle(struct tty_struct *tty)
diff --git a/drivers/usb/serial/xsens_mt.c b/drivers/usb/serial/xsens_mt.c
new file mode 100644
index 000000000000..1d5798d891bc
--- /dev/null
+++ b/drivers/usb/serial/xsens_mt.c
@@ -0,0 +1,86 @@
+/*
+ * Xsens MT USB driver
+ *
+ * Copyright (C) 2013 Xsens <info@xsens.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+#include <linux/uaccess.h>
+
+#define XSENS_VID 0x2639
+
+#define MTi_10_IMU_PID 0x0001
+#define MTi_20_VRU_PID 0x0002
+#define MTi_30_AHRS_PID 0x0003
+
+#define MTi_100_IMU_PID 0x0011
+#define MTi_200_VRU_PID 0x0012
+#define MTi_300_AHRS_PID 0x0013
+
+#define MTi_G_700_GPS_INS_PID 0x0017
+
+static const struct usb_device_id id_table[] = {
+ { USB_DEVICE(XSENS_VID, MTi_10_IMU_PID) },
+ { USB_DEVICE(XSENS_VID, MTi_20_VRU_PID) },
+ { USB_DEVICE(XSENS_VID, MTi_30_AHRS_PID) },
+
+ { USB_DEVICE(XSENS_VID, MTi_100_IMU_PID) },
+ { USB_DEVICE(XSENS_VID, MTi_200_VRU_PID) },
+ { USB_DEVICE(XSENS_VID, MTi_300_AHRS_PID) },
+
+ { USB_DEVICE(XSENS_VID, MTi_G_700_GPS_INS_PID) },
+ { },
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+static int has_required_endpoints(const struct usb_host_interface *interface)
+{
+ __u8 i;
+ int has_bulk_in = 0;
+ int has_bulk_out = 0;
+
+ for (i = 0; i < interface->desc.bNumEndpoints; ++i) {
+ if (usb_endpoint_is_bulk_in(&interface->endpoint[i].desc))
+ has_bulk_in = 1;
+ else if (usb_endpoint_is_bulk_out(&interface->endpoint[i].desc))
+ has_bulk_out = 1;
+ }
+
+ return has_bulk_in && has_bulk_out;
+}
+
+static int xsens_mt_probe(struct usb_serial *serial,
+ const struct usb_device_id *id)
+{
+ if (!has_required_endpoints(serial->interface->cur_altsetting))
+ return -ENODEV;
+ return 0;
+}
+
+static struct usb_serial_driver xsens_mt_device = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "xsens_mt",
+ },
+ .id_table = id_table,
+ .num_ports = 1,
+
+ .probe = xsens_mt_probe,
+};
+
+static struct usb_serial_driver * const serial_drivers[] = {
+ &xsens_mt_device, NULL
+};
+
+module_usb_serial_driver(serial_drivers, id_table);
+
+MODULE_LICENSE("GPL");