summaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/serial')
-rw-r--r--drivers/usb/serial/ark3116.c13
-rw-r--r--drivers/usb/serial/cp210x.c31
-rw-r--r--drivers/usb/serial/f81232.c12
-rw-r--r--drivers/usb/serial/f81534.c7
-rw-r--r--drivers/usb/serial/ftdi_sio.c35
-rw-r--r--drivers/usb/serial/io_edgeport.c67
-rw-r--r--drivers/usb/serial/io_edgeport.h68
-rw-r--r--drivers/usb/serial/io_ti.c210
-rw-r--r--drivers/usb/serial/io_ti.h38
-rw-r--r--drivers/usb/serial/iuu_phoenix.c4
-rw-r--r--drivers/usb/serial/keyspan.c20
-rw-r--r--drivers/usb/serial/metro-usb.c4
-rw-r--r--drivers/usb/serial/mos7720.c20
-rw-r--r--drivers/usb/serial/mos7840.c23
-rw-r--r--drivers/usb/serial/opticon.c18
-rw-r--r--drivers/usb/serial/option.c2
-rw-r--r--drivers/usb/serial/pl2303.c188
-rw-r--r--drivers/usb/serial/quatech2.c16
-rw-r--r--drivers/usb/serial/ssu100.c16
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.c213
-rw-r--r--drivers/usb/serial/upd78f0730.c7
-rw-r--r--drivers/usb/serial/usb-serial.c226
-rw-r--r--drivers/usb/serial/usb-wwan.h4
-rw-r--r--drivers/usb/serial/usb_wwan.c45
-rw-r--r--drivers/usb/serial/whiteheat.c17
-rw-r--r--drivers/usb/serial/xr_serial.c754
26 files changed, 1140 insertions, 918 deletions
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
index b9bedfe9bd09..5dd710e9fe7d 100644
--- a/drivers/usb/serial/ark3116.c
+++ b/drivers/usb/serial/ark3116.c
@@ -385,18 +385,6 @@ err_free:
return result;
}
-static int ark3116_get_serial_info(struct tty_struct *tty,
- struct serial_struct *ss)
-{
- struct usb_serial_port *port = tty->driver_data;
-
- ss->type = PORT_16654;
- ss->line = port->minor;
- ss->port = port->port_number;
- ss->baud_base = 460800;
- return 0;
-}
-
static int ark3116_tiocmget(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
@@ -633,7 +621,6 @@ static struct usb_serial_driver ark3116_device = {
.port_probe = ark3116_port_probe,
.port_remove = ark3116_port_remove,
.set_termios = ark3116_set_termios,
- .get_serial = ark3116_get_serial_info,
.tiocmget = ark3116_tiocmget,
.tiocmset = ark3116_tiocmset,
.tiocmiwait = usb_serial_generic_tiocmiwait,
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index a373cd63b3a4..ee595d1bea0a 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -1410,17 +1410,6 @@ static void cp210x_break_ctl(struct tty_struct *tty, int break_state)
}
#ifdef CONFIG_GPIOLIB
-static int cp210x_gpio_request(struct gpio_chip *gc, unsigned int offset)
-{
- struct usb_serial *serial = gpiochip_get_data(gc);
- struct cp210x_serial_private *priv = usb_get_serial_data(serial);
-
- if (priv->gpio_altfunc & BIT(offset))
- return -ENODEV;
-
- return 0;
-}
-
static int cp210x_gpio_get(struct gpio_chip *gc, unsigned int gpio)
{
struct usb_serial *serial = gpiochip_get_data(gc);
@@ -1549,6 +1538,24 @@ static int cp210x_gpio_set_config(struct gpio_chip *gc, unsigned int gpio,
return -ENOTSUPP;
}
+static int cp210x_gpio_init_valid_mask(struct gpio_chip *gc,
+ unsigned long *valid_mask, unsigned int ngpios)
+{
+ struct usb_serial *serial = gpiochip_get_data(gc);
+ struct cp210x_serial_private *priv = usb_get_serial_data(serial);
+ struct device *dev = &serial->interface->dev;
+ unsigned long altfunc_mask = priv->gpio_altfunc;
+
+ bitmap_complement(valid_mask, &altfunc_mask, ngpios);
+
+ if (bitmap_empty(valid_mask, ngpios))
+ dev_dbg(dev, "no pin configured for GPIO\n");
+ else
+ dev_dbg(dev, "GPIO.%*pbl configured for GPIO\n", ngpios,
+ valid_mask);
+ return 0;
+}
+
/*
* This function is for configuring GPIO using shared pins, where other signals
* are made unavailable by configuring the use of GPIO. This is believed to be
@@ -1786,13 +1793,13 @@ static int cp210x_gpio_init(struct usb_serial *serial)
return result;
priv->gc.label = "cp210x";
- priv->gc.request = cp210x_gpio_request;
priv->gc.get_direction = cp210x_gpio_direction_get;
priv->gc.direction_input = cp210x_gpio_direction_input;
priv->gc.direction_output = cp210x_gpio_direction_output;
priv->gc.get = cp210x_gpio_get;
priv->gc.set = cp210x_gpio_set;
priv->gc.set_config = cp210x_gpio_set_config;
+ priv->gc.init_valid_mask = cp210x_gpio_init_valid_mask;
priv->gc.owner = THIS_MODULE;
priv->gc.parent = &serial->interface->dev;
priv->gc.base = -1;
diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 6a8f39147d8e..a7a7af8d05bf 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -820,17 +820,12 @@ static int f81232_carrier_raised(struct usb_serial_port *port)
return 0;
}
-static int f81232_get_serial_info(struct tty_struct *tty,
- struct serial_struct *ss)
+static void f81232_get_serial(struct tty_struct *tty, struct serial_struct *ss)
{
struct usb_serial_port *port = tty->driver_data;
struct f81232_private *priv = usb_get_serial_port_data(port);
- ss->type = PORT_16550A;
- ss->line = port->minor;
- ss->port = port->port_number;
ss->baud_base = priv->baud_base;
- return 0;
}
static void f81232_interrupt_work(struct work_struct *work)
@@ -953,7 +948,6 @@ static int f81232_port_probe(struct usb_serial_port *port)
usb_set_serial_port_data(port, priv);
- port->port.drain_delay = 256;
priv->port = port;
return 0;
@@ -1021,7 +1015,7 @@ static struct usb_serial_driver f81232_device = {
.close = f81232_close,
.dtr_rts = f81232_dtr_rts,
.carrier_raised = f81232_carrier_raised,
- .get_serial = f81232_get_serial_info,
+ .get_serial = f81232_get_serial,
.break_ctl = f81232_break_ctl,
.set_termios = f81232_set_termios,
.tiocmget = f81232_tiocmget,
@@ -1046,7 +1040,7 @@ static struct usb_serial_driver f81534a_device = {
.close = f81232_close,
.dtr_rts = f81232_dtr_rts,
.carrier_raised = f81232_carrier_raised,
- .get_serial = f81232_get_serial_info,
+ .get_serial = f81232_get_serial,
.break_ctl = f81232_break_ctl,
.set_termios = f81232_set_termios,
.tiocmget = f81232_tiocmget,
diff --git a/drivers/usb/serial/f81534.c b/drivers/usb/serial/f81534.c
index a763b362f081..c0bca52ef92a 100644
--- a/drivers/usb/serial/f81534.c
+++ b/drivers/usb/serial/f81534.c
@@ -1140,19 +1140,14 @@ static void f81534_close(struct usb_serial_port *port)
mutex_unlock(&serial_priv->urb_mutex);
}
-static int f81534_get_serial_info(struct tty_struct *tty,
- struct serial_struct *ss)
+static void f81534_get_serial_info(struct tty_struct *tty, struct serial_struct *ss)
{
struct usb_serial_port *port = tty->driver_data;
struct f81534_port_private *port_priv;
port_priv = usb_get_serial_port_data(port);
- ss->type = PORT_16550A;
- ss->port = port->port_number;
- ss->line = port->minor;
ss->baud_base = port_priv->baud_base;
- return 0;
}
static void f81534_process_per_serial_block(struct usb_serial_port *port,
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index c867592477c9..6f2659e59b2e 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -1082,8 +1082,7 @@ static int ftdi_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear);
static int ftdi_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg);
-static int get_serial_info(struct tty_struct *tty,
- struct serial_struct *ss);
+static void get_serial_info(struct tty_struct *tty, struct serial_struct *ss);
static int set_serial_info(struct tty_struct *tty,
struct serial_struct *ss);
static void ftdi_break_ctl(struct tty_struct *tty, int break_state);
@@ -1477,8 +1476,7 @@ static int read_latency_timer(struct usb_serial_port *port)
return 0;
}
-static int get_serial_info(struct tty_struct *tty,
- struct serial_struct *ss)
+static void get_serial_info(struct tty_struct *tty, struct serial_struct *ss)
{
struct usb_serial_port *port = tty->driver_data;
struct ftdi_private *priv = usb_get_serial_port_data(port);
@@ -1486,49 +1484,34 @@ static int get_serial_info(struct tty_struct *tty,
ss->flags = priv->flags;
ss->baud_base = priv->baud_base;
ss->custom_divisor = priv->custom_divisor;
- return 0;
}
-static int set_serial_info(struct tty_struct *tty,
- struct serial_struct *ss)
+static int set_serial_info(struct tty_struct *tty, struct serial_struct *ss)
{
struct usb_serial_port *port = tty->driver_data;
struct ftdi_private *priv = usb_get_serial_port_data(port);
- struct ftdi_private old_priv;
+ int old_flags, old_divisor;
mutex_lock(&priv->cfg_lock);
- old_priv = *priv;
-
- /* Do error checking and permission checking */
if (!capable(CAP_SYS_ADMIN)) {
if ((ss->flags ^ priv->flags) & ~ASYNC_USR_MASK) {
mutex_unlock(&priv->cfg_lock);
return -EPERM;
}
- priv->flags = ((priv->flags & ~ASYNC_USR_MASK) |
- (ss->flags & ASYNC_USR_MASK));
- priv->custom_divisor = ss->custom_divisor;
- goto check_and_exit;
- }
-
- if (ss->baud_base != priv->baud_base) {
- mutex_unlock(&priv->cfg_lock);
- return -EINVAL;
}
- /* Make the changes - these are privileged changes! */
+ old_flags = priv->flags;
+ old_divisor = priv->custom_divisor;
- priv->flags = ((priv->flags & ~ASYNC_FLAGS) |
- (ss->flags & ASYNC_FLAGS));
+ priv->flags = ss->flags & ASYNC_FLAGS;
priv->custom_divisor = ss->custom_divisor;
-check_and_exit:
write_latency_timer(port);
- if ((priv->flags ^ old_priv.flags) & ASYNC_SPD_MASK ||
+ if ((priv->flags ^ old_flags) & ASYNC_SPD_MASK ||
((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST &&
- priv->custom_divisor != old_priv.custom_divisor)) {
+ priv->custom_divisor != old_divisor)) {
/* warn about deprecation unless clearing */
if (priv->flags & ASYNC_SPD_MASK)
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index 68401adcffde..e6fe3882bf69 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -263,39 +263,9 @@ static const struct divisor_table_entry divisor_table[] = {
static atomic_t CmdUrbs = ATOMIC_INIT(0);
-/* local function prototypes */
+/* function prototypes */
-/* function prototypes for all URB callbacks */
-static void edge_interrupt_callback(struct urb *urb);
-static void edge_bulk_in_callback(struct urb *urb);
-static void edge_bulk_out_data_callback(struct urb *urb);
-static void edge_bulk_out_cmd_callback(struct urb *urb);
-
-/* function prototypes for the usbserial callbacks */
-static int edge_open(struct tty_struct *tty, struct usb_serial_port *port);
static void edge_close(struct usb_serial_port *port);
-static int edge_write(struct tty_struct *tty, struct usb_serial_port *port,
- const unsigned char *buf, int count);
-static int edge_write_room(struct tty_struct *tty);
-static int edge_chars_in_buffer(struct tty_struct *tty);
-static void edge_throttle(struct tty_struct *tty);
-static void edge_unthrottle(struct tty_struct *tty);
-static void edge_set_termios(struct tty_struct *tty,
- struct usb_serial_port *port,
- struct ktermios *old_termios);
-static int edge_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg);
-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_startup(struct usb_serial *serial);
-static void edge_disconnect(struct usb_serial *serial);
-static void edge_release(struct usb_serial *serial);
-static int edge_port_probe(struct usb_serial_port *port);
-static void edge_port_remove(struct usb_serial_port *port);
-
-/* function prototypes for all of our local functions */
static void process_rcvd_data(struct edgeport_serial *edge_serial,
unsigned char *buffer, __u16 bufferLength);
@@ -309,8 +279,6 @@ static void handle_new_lsr(struct edgeport_port *edge_port, __u8 lsrData,
static int send_iosp_ext_cmd(struct edgeport_port *edge_port, __u8 command,
__u8 param);
static int calc_baud_rate_divisor(struct device *dev, int baud_rate, int *divisor);
-static int send_cmd_write_baud_rate(struct edgeport_port *edge_port,
- int baudRate);
static void change_port_settings(struct tty_struct *tty,
struct edgeport_port *edge_port,
struct ktermios *old_termios);
@@ -321,19 +289,8 @@ static int write_cmd_usb(struct edgeport_port *edge_port,
static void send_more_port_data(struct edgeport_serial *edge_serial,
struct edgeport_port *edge_port);
-static int sram_write(struct usb_serial *serial, __u16 extAddr, __u16 addr,
- __u16 length, const __u8 *data);
-static int rom_read(struct usb_serial *serial, __u16 extAddr, __u16 addr,
- __u16 length, __u8 *data);
static int rom_write(struct usb_serial *serial, __u16 extAddr, __u16 addr,
__u16 length, const __u8 *data);
-static void get_manufacturing_desc(struct edgeport_serial *edge_serial);
-static void get_boot_desc(struct edgeport_serial *edge_serial);
-static void load_application_firmware(struct edgeport_serial *edge_serial);
-
-static void unicode_to_ascii(char *string, int buflen,
- __le16 *unicode, int unicode_size);
-
/* ************************************************************************ */
/* ************************************************************************ */
@@ -1637,24 +1594,6 @@ static int edge_tiocmget(struct tty_struct *tty)
return result;
}
-static int get_serial_info(struct tty_struct *tty,
- struct serial_struct *ss)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct edgeport_port *edge_port = usb_get_serial_port_data(port);
-
- ss->type = PORT_16550A;
- ss->line = edge_port->port->minor;
- ss->port = edge_port->port->port_number;
- ss->irq = 0;
- ss->xmit_fifo_size = edge_port->maxTxCredits;
- ss->baud_base = 9600;
- ss->close_delay = 5*HZ;
- ss->closing_wait = 30*HZ;
- return 0;
-}
-
-
/*****************************************************************************
* SerialIoctl
* this function handles any ioctl calls to the driver
@@ -3116,7 +3055,6 @@ static struct usb_serial_driver edgeport_2port_device = {
.set_termios = edge_set_termios,
.tiocmget = edge_tiocmget,
.tiocmset = edge_tiocmset,
- .get_serial = get_serial_info,
.tiocmiwait = usb_serial_generic_tiocmiwait,
.get_icount = usb_serial_generic_get_icount,
.write = edge_write,
@@ -3152,7 +3090,6 @@ static struct usb_serial_driver edgeport_4port_device = {
.set_termios = edge_set_termios,
.tiocmget = edge_tiocmget,
.tiocmset = edge_tiocmset,
- .get_serial = get_serial_info,
.tiocmiwait = usb_serial_generic_tiocmiwait,
.get_icount = usb_serial_generic_get_icount,
.write = edge_write,
@@ -3188,7 +3125,6 @@ static struct usb_serial_driver edgeport_8port_device = {
.set_termios = edge_set_termios,
.tiocmget = edge_tiocmget,
.tiocmset = edge_tiocmset,
- .get_serial = get_serial_info,
.tiocmiwait = usb_serial_generic_tiocmiwait,
.get_icount = usb_serial_generic_get_icount,
.write = edge_write,
@@ -3224,7 +3160,6 @@ static struct usb_serial_driver epic_device = {
.set_termios = edge_set_termios,
.tiocmget = edge_tiocmget,
.tiocmset = edge_tiocmset,
- .get_serial = get_serial_info,
.tiocmiwait = usb_serial_generic_tiocmiwait,
.get_icount = usb_serial_generic_get_icount,
.write = edge_write,
diff --git a/drivers/usb/serial/io_edgeport.h b/drivers/usb/serial/io_edgeport.h
index 43ba53a3a6fa..7c9f62af5ed6 100644
--- a/drivers/usb/serial/io_edgeport.h
+++ b/drivers/usb/serial/io_edgeport.h
@@ -10,7 +10,6 @@
#if !defined(_IO_EDGEPORT_H_)
#define _IO_EDGEPORT_H_
-
#define MAX_RS232_PORTS 8 /* Max # of RS-232 ports per device */
/* typedefs that the insideout headers need */
@@ -21,57 +20,8 @@
#define HIGH8(a) ((unsigned char)((a & 0xff00) >> 8))
#endif
-#ifndef __KERNEL__
-#define __KERNEL__
-#endif
-
#include "io_usbvend.h"
-
-
-/* The following table is used to map the USBx port number to
- * the device serial number (or physical USB path), */
-#define MAX_EDGEPORTS 64
-
-struct comMapper {
- char SerialNumber[MAX_SERIALNUMBER_LEN+1]; /* Serial number/usb path */
- int numPorts; /* Number of ports */
- int Original[MAX_RS232_PORTS]; /* Port numbers set by IOCTL */
- int Port[MAX_RS232_PORTS]; /* Actual used port numbers */
-};
-
-
-#define EDGEPORT_CONFIG_DEVICE "/proc/edgeport"
-
-/* /proc/edgeport Interface
- * This interface uses read/write/lseek interface to talk to the edgeport driver
- * the following read functions are supported: */
-#define PROC_GET_MAPPING_TO_PATH 1
-#define PROC_GET_COM_ENTRY 2
-#define PROC_GET_EDGE_MANUF_DESCRIPTOR 3
-#define PROC_GET_BOOT_DESCRIPTOR 4
-#define PROC_GET_PRODUCT_INFO 5
-#define PROC_GET_STRINGS 6
-#define PROC_GET_CURRENT_COM_MAPPING 7
-
-/* The parameters to the lseek() for the read is: */
-#define PROC_READ_SETUP(Command, Argument) ((Command) + ((Argument)<<8))
-
-
-/* the following write functions are supported: */
-#define PROC_SET_COM_MAPPING 1
-#define PROC_SET_COM_ENTRY 2
-
-
-/* The following structure is passed to the write */
-struct procWrite {
- int Command;
- union {
- struct comMapper Entry;
- int ComMappingBasedOnUSBPort; /* Boolean value */
- } u;
-};
-
/*
* Product information read from the Edgeport
*/
@@ -108,22 +58,4 @@ struct edgeport_product_info {
struct edge_compatibility_bits Epic;
};
-/*
- * Edgeport Stringblock String locations
- */
-#define EDGESTRING_MANUFNAME 1 /* Manufacture Name */
-#define EDGESTRING_PRODNAME 2 /* Product Name */
-#define EDGESTRING_SERIALNUM 3 /* Serial Number */
-#define EDGESTRING_ASSEMNUM 4 /* Assembly Number */
-#define EDGESTRING_OEMASSEMNUM 5 /* OEM Assembly Number */
-#define EDGESTRING_MANUFDATE 6 /* Manufacture Date */
-#define EDGESTRING_ORIGSERIALNUM 7 /* Serial Number */
-
-struct string_block {
- __u16 NumStrings; /* Number of strings in block */
- __u16 Strings[1]; /* Start of string block */
-};
-
-
-
#endif
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index e800547be9e0..39503fdccebf 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -60,14 +60,12 @@
#define EDGE_READ_URB_STOPPING 1
#define EDGE_READ_URB_STOPPED 2
-#define EDGE_CLOSING_WAIT 4000 /* in .01 sec */
-
/* Product information read from the Edgeport */
struct product_info {
int TiMode; /* Current TI Mode */
- __u8 hardware_type; /* Type of hardware */
-} __attribute__((packed));
+ u8 hardware_type; /* Type of hardware */
+} __packed;
/*
* Edgeport firmware header
@@ -89,13 +87,13 @@ struct edgeport_fw_hdr {
} __packed;
struct edgeport_port {
- __u16 uart_base;
- __u16 dma_address;
- __u8 shadow_msr;
- __u8 shadow_mcr;
- __u8 shadow_lsr;
- __u8 lsr_mask;
- __u32 ump_read_timeout; /*
+ u16 uart_base;
+ u16 dma_address;
+ u8 shadow_msr;
+ u8 shadow_mcr;
+ u8 shadow_lsr;
+ u8 lsr_mask;
+ u32 ump_read_timeout; /*
* Number of milliseconds the UMP will
* wait without data before completing
* a read short
@@ -106,7 +104,7 @@ struct edgeport_port {
struct edgeport_serial *edge_serial;
struct usb_serial_port *port;
- __u8 bUartMode; /* Port type, 0: RS232, etc. */
+ u8 bUartMode; /* Port type, 0: RS232, etc. */
spinlock_t ep_lock;
int ep_read_urb_state;
int ep_write_urb_in_use;
@@ -211,7 +209,6 @@ static const struct usb_device_id id_table_combined[] = {
MODULE_DEVICE_TABLE(usb, id_table_combined);
-static int closing_wait = EDGE_CLOSING_WAIT;
static bool ignore_cpu_rev;
static int default_uart_mode; /* RS232 */
@@ -255,8 +252,8 @@ static int edge_remove_sysfs_attrs(struct usb_serial_port *port);
#define TI_VSEND_TIMEOUT_DEFAULT 1000
#define TI_VSEND_TIMEOUT_FW_DOWNLOAD 10000
-static int ti_vread_sync(struct usb_device *dev, __u8 request,
- __u16 value, __u16 index, u8 *data, int size)
+static int ti_vread_sync(struct usb_device *dev, u8 request, u16 value,
+ u16 index, void *data, int size)
{
int status;
@@ -274,7 +271,7 @@ static int ti_vread_sync(struct usb_device *dev, __u8 request,
}
static int ti_vsend_sync(struct usb_device *dev, u8 request, u16 value,
- u16 index, u8 *data, int size, int timeout)
+ u16 index, void *data, int size, int timeout)
{
int status;
@@ -287,27 +284,30 @@ static int ti_vsend_sync(struct usb_device *dev, u8 request, u16 value,
return 0;
}
-static int send_cmd(struct usb_device *dev, __u8 command,
- __u8 moduleid, __u16 value, u8 *data,
- int size)
+static int read_port_cmd(struct usb_serial_port *port, u8 command, u16 value,
+ void *data, int size)
+{
+ return ti_vread_sync(port->serial->dev, command, value,
+ UMPM_UART1_PORT + port->port_number,
+ data, size);
+}
+
+static int send_port_cmd(struct usb_serial_port *port, u8 command, u16 value,
+ void *data, int size)
{
- return ti_vsend_sync(dev, command, value, moduleid, data, size,
- TI_VSEND_TIMEOUT_DEFAULT);
+ return ti_vsend_sync(port->serial->dev, command, value,
+ UMPM_UART1_PORT + port->port_number,
+ data, size, TI_VSEND_TIMEOUT_DEFAULT);
}
/* clear tx/rx buffers and fifo in TI UMP */
-static int purge_port(struct usb_serial_port *port, __u16 mask)
+static int purge_port(struct usb_serial_port *port, u16 mask)
{
int port_number = port->port_number;
dev_dbg(&port->dev, "%s - port %d, mask %x\n", __func__, port_number, mask);
- return send_cmd(port->serial->dev,
- UMPC_PURGE_PORT,
- (__u8)(UMPM_UART1_PORT + port_number),
- mask,
- NULL,
- 0);
+ return send_port_cmd(port, UMPC_PURGE_PORT, mask, NULL, 0);
}
/**
@@ -319,10 +319,10 @@ static int purge_port(struct usb_serial_port *port, __u16 mask)
* @buffer: pointer to input data buffer
*/
static int read_download_mem(struct usb_device *dev, int start_address,
- int length, __u8 address_type, __u8 *buffer)
+ int length, u8 address_type, u8 *buffer)
{
int status = 0;
- __u8 read_length;
+ u8 read_length;
u16 be_start_address;
dev_dbg(&dev->dev, "%s - @ %x for %d\n", __func__, start_address, length);
@@ -335,7 +335,7 @@ static int read_download_mem(struct usb_device *dev, int start_address,
if (length > 64)
read_length = 64;
else
- read_length = (__u8)length;
+ read_length = (u8)length;
if (read_length > 1) {
dev_dbg(&dev->dev, "%s - @ %x for %d\n", __func__, start_address, read_length);
@@ -346,7 +346,7 @@ static int read_download_mem(struct usb_device *dev, int start_address,
*/
be_start_address = swab16((u16)start_address);
status = ti_vread_sync(dev, UMPC_MEMORY_READ,
- (__u16)address_type,
+ (u16)address_type,
be_start_address,
buffer, read_length);
@@ -368,7 +368,7 @@ static int read_download_mem(struct usb_device *dev, int start_address,
}
static int read_ram(struct usb_device *dev, int start_address,
- int length, __u8 *buffer)
+ int length, u8 *buffer)
{
return read_download_mem(dev, start_address, length,
DTK_ADDR_SPACE_XDATA, buffer);
@@ -376,7 +376,7 @@ static int read_ram(struct usb_device *dev, int start_address,
/* Read edgeport memory to a given block */
static int read_boot_mem(struct edgeport_serial *serial,
- int start_address, int length, __u8 *buffer)
+ int start_address, int length, u8 *buffer)
{
int status = 0;
int i;
@@ -384,7 +384,7 @@ static int read_boot_mem(struct edgeport_serial *serial,
for (i = 0; i < length; i++) {
status = ti_vread_sync(serial->serial->dev,
UMPC_MEMORY_READ, serial->TI_I2C_Type,
- (__u16)(start_address+i), &buffer[i], 0x01);
+ (u16)(start_address+i), &buffer[i], 0x01);
if (status) {
dev_dbg(&serial->serial->dev->dev, "%s - ERROR %x\n", __func__, status);
return status;
@@ -402,7 +402,7 @@ static int read_boot_mem(struct edgeport_serial *serial,
/* Write given block to TI EPROM memory */
static int write_boot_mem(struct edgeport_serial *serial,
- int start_address, int length, __u8 *buffer)
+ int start_address, int length, u8 *buffer)
{
int status = 0;
int i;
@@ -436,7 +436,7 @@ static int write_boot_mem(struct edgeport_serial *serial,
/* Write edgeport I2C memory to TI chip */
static int write_i2c_mem(struct edgeport_serial *serial,
- int start_address, int length, __u8 address_type, __u8 *buffer)
+ int start_address, int length, u8 address_type, u8 *buffer)
{
struct device *dev = &serial->serial->dev->dev;
int status = 0;
@@ -522,7 +522,7 @@ static int tx_active(struct edgeport_port *port)
{
int status;
struct out_endpoint_desc_block *oedb;
- __u8 *lsr;
+ u8 *lsr;
int bytes_left = 0;
oedb = kmalloc(sizeof(*oedb), GFP_KERNEL);
@@ -593,7 +593,7 @@ static int choose_config(struct usb_device *dev)
}
static int read_rom(struct edgeport_serial *serial,
- int start_address, int length, __u8 *buffer)
+ int start_address, int length, u8 *buffer)
{
int status;
@@ -611,7 +611,7 @@ static int read_rom(struct edgeport_serial *serial,
}
static int write_rom(struct edgeport_serial *serial, int start_address,
- int length, __u8 *buffer)
+ int length, u8 *buffer)
{
if (serial->product_info.TiMode == TI_MODE_BOOT)
return write_boot_mem(serial, start_address, length,
@@ -636,7 +636,7 @@ static int get_descriptor_addr(struct edgeport_serial *serial,
status = read_rom(serial,
start_address,
sizeof(struct ti_i2c_desc),
- (__u8 *)rom_desc);
+ (u8 *)rom_desc);
if (status)
return 0;
@@ -652,13 +652,13 @@ static int get_descriptor_addr(struct edgeport_serial *serial,
}
/* Validate descriptor checksum */
-static int valid_csum(struct ti_i2c_desc *rom_desc, __u8 *buffer)
+static int valid_csum(struct ti_i2c_desc *rom_desc, u8 *buffer)
{
- __u16 i;
- __u8 cs = 0;
+ u16 i;
+ u8 cs = 0;
for (i = 0; i < le16_to_cpu(rom_desc->Size); i++)
- cs = (__u8)(cs + buffer[i]);
+ cs = (u8)(cs + buffer[i]);
if (cs != rom_desc->CheckSum) {
pr_debug("%s - Mismatch %x - %x", __func__, rom_desc->CheckSum, cs);
@@ -674,8 +674,8 @@ static int check_i2c_image(struct edgeport_serial *serial)
int status = 0;
struct ti_i2c_desc *rom_desc;
int start_address = 2;
- __u8 *buffer;
- __u16 ttype;
+ u8 *buffer;
+ u16 ttype;
rom_desc = kmalloc(sizeof(*rom_desc), GFP_KERNEL);
if (!rom_desc)
@@ -703,7 +703,7 @@ static int check_i2c_image(struct edgeport_serial *serial)
status = read_rom(serial,
start_address,
sizeof(struct ti_i2c_desc),
- (__u8 *)rom_desc);
+ (u8 *)rom_desc);
if (status)
break;
@@ -748,7 +748,7 @@ out:
return status;
}
-static int get_manuf_info(struct edgeport_serial *serial, __u8 *buffer)
+static int get_manuf_info(struct edgeport_serial *serial, u8 *buffer)
{
int status;
int start_address;
@@ -793,10 +793,10 @@ exit:
/* Build firmware header used for firmware update */
static int build_i2c_fw_hdr(u8 *header, const struct firmware *fw)
{
- __u8 *buffer;
+ u8 *buffer;
int buffer_size;
int i;
- __u8 cs = 0;
+ u8 cs = 0;
struct ti_i2c_desc *i2c_header;
struct ti_i2c_image_header *img_header;
struct ti_i2c_firmware_rec *firmware_rec;
@@ -840,7 +840,7 @@ static int build_i2c_fw_hdr(u8 *header, const struct firmware *fw)
le16_to_cpu(img_header->Length));
for (i=0; i < buffer_size; i++) {
- cs = (__u8)(cs + buffer[i]);
+ cs = (u8)(cs + buffer[i]);
}
kfree(buffer);
@@ -916,7 +916,7 @@ static int bulk_xfer(struct usb_serial *serial, void *buffer,
}
/* Download given firmware image to the device (IN BOOT MODE) */
-static int download_code(struct edgeport_serial *serial, __u8 *image,
+static int download_code(struct edgeport_serial *serial, u8 *image,
int image_length)
{
int status = 0;
@@ -1090,7 +1090,7 @@ static int do_download_mode(struct edgeport_serial *serial,
if (!ti_manuf_desc)
return -ENOMEM;
- status = get_manuf_info(serial, (__u8 *)ti_manuf_desc);
+ status = get_manuf_info(serial, (u8 *)ti_manuf_desc);
if (status) {
kfree(ti_manuf_desc);
return status;
@@ -1135,7 +1135,7 @@ static int do_download_mode(struct edgeport_serial *serial,
status = read_rom(serial, start_address +
sizeof(struct ti_i2c_desc),
sizeof(struct ti_i2c_firmware_rec),
- (__u8 *)firmware_version);
+ (u8 *)firmware_version);
if (status) {
kfree(firmware_version);
kfree(rom_desc);
@@ -1261,8 +1261,8 @@ static int do_download_mode(struct edgeport_serial *serial,
if (start_address != 0) {
#define HEADER_SIZE (sizeof(struct ti_i2c_desc) + \
sizeof(struct ti_i2c_firmware_rec))
- __u8 *header;
- __u8 *vheader;
+ u8 *header;
+ u8 *vheader;
header = kmalloc(HEADER_SIZE, GFP_KERNEL);
if (!header) {
@@ -1408,8 +1408,8 @@ static int do_boot_mode(struct edgeport_serial *serial,
if (!check_i2c_image(serial)) {
struct ti_i2c_image_header *header;
int i;
- __u8 cs = 0;
- __u8 *buffer;
+ u8 cs = 0;
+ u8 *buffer;
int buffer_size;
/*
@@ -1420,7 +1420,7 @@ static int do_boot_mode(struct edgeport_serial *serial,
if (!ti_manuf_desc)
return -ENOMEM;
- status = get_manuf_info(serial, (__u8 *)ti_manuf_desc);
+ status = get_manuf_info(serial, (u8 *)ti_manuf_desc);
if (status) {
kfree(ti_manuf_desc);
goto stayinbootmode;
@@ -1463,13 +1463,13 @@ static int do_boot_mode(struct edgeport_serial *serial,
for (i = sizeof(struct ti_i2c_image_header);
i < buffer_size; i++) {
- cs = (__u8)(cs + buffer[i]);
+ cs = (u8)(cs + buffer[i]);
}
header = (struct ti_i2c_image_header *)buffer;
/* update length and checksum after padding */
- header->Length = cpu_to_le16((__u16)(buffer_size -
+ header->Length = cpu_to_le16((u16)(buffer_size -
sizeof(struct ti_i2c_image_header)));
header->CheckSum = cs;
@@ -1504,15 +1504,12 @@ stayinbootmode:
static int ti_do_config(struct edgeport_port *port, int feature, int on)
{
- int port_number = port->port->port_number;
-
on = !!on; /* 1 or 0 not bitmask */
- return send_cmd(port->port->serial->dev,
- feature, (__u8)(UMPM_UART1_PORT + port_number),
- on, NULL, 0);
+
+ return send_port_cmd(port->port, feature, on, NULL, 0);
}
-static int restore_mcr(struct edgeport_port *port, __u8 mcr)
+static int restore_mcr(struct edgeport_port *port, u8 mcr)
{
int status = 0;
@@ -1528,9 +1525,9 @@ static int restore_mcr(struct edgeport_port *port, __u8 mcr)
}
/* Convert TI LSR to standard UART flags */
-static __u8 map_line_status(__u8 ti_lsr)
+static u8 map_line_status(u8 ti_lsr)
{
- __u8 lsr = 0;
+ u8 lsr = 0;
#define MAP_FLAG(flagUmp, flagUart) \
if (ti_lsr & flagUmp) \
@@ -1548,7 +1545,7 @@ static __u8 map_line_status(__u8 ti_lsr)
return lsr;
}
-static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr)
+static void handle_new_msr(struct edgeport_port *edge_port, u8 msr)
{
struct async_icount *icount;
struct tty_struct *tty;
@@ -1584,10 +1581,10 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr)
}
static void handle_new_lsr(struct edgeport_port *edge_port, int lsr_data,
- __u8 lsr, __u8 data)
+ u8 lsr, u8 data)
{
struct async_icount *icount;
- __u8 new_lsr = (__u8)(lsr & (__u8)(LSR_OVER_ERR | LSR_PAR_ERR |
+ u8 new_lsr = (u8)(lsr & (u8)(LSR_OVER_ERR | LSR_PAR_ERR |
LSR_FRM_ERR | LSR_BREAK));
dev_dbg(&edge_port->port->dev, "%s - %02x\n", __func__, new_lsr);
@@ -1599,7 +1596,7 @@ static void handle_new_lsr(struct edgeport_port *edge_port, int lsr_data,
* Parity and Framing errors only count if they
* occur exclusive of a break being received.
*/
- new_lsr &= (__u8)(LSR_OVER_ERR | LSR_BREAK);
+ new_lsr &= (u8)(LSR_OVER_ERR | LSR_BREAK);
/* Place LSR data byte into Rx buffer */
if (lsr_data)
@@ -1628,8 +1625,8 @@ static void edge_interrupt_callback(struct urb *urb)
int port_number;
int function;
int retval;
- __u8 lsr;
- __u8 msr;
+ u8 lsr;
+ u8 msr;
int status = urb->status;
switch (status) {
@@ -1837,7 +1834,6 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port)
struct edgeport_serial *edge_serial;
struct usb_device *dev;
struct urb *urb;
- int port_number;
int status;
u16 open_settings;
u8 transaction_timeout;
@@ -1845,8 +1841,6 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port)
if (edge_port == NULL)
return -ENODEV;
- port_number = port->port_number;
-
dev = port->serial->dev;
/* turn off loopback */
@@ -1878,8 +1872,7 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port)
dev_dbg(&port->dev, "%s - Sending UMPC_OPEN_PORT\n", __func__);
/* Tell TI to open and start the port */
- status = send_cmd(dev, UMPC_OPEN_PORT,
- (u8)(UMPM_UART1_PORT + port_number), open_settings, NULL, 0);
+ status = send_port_cmd(port, UMPC_OPEN_PORT, open_settings, NULL, 0);
if (status) {
dev_err(&port->dev, "%s - cannot send open command, %d\n",
__func__, status);
@@ -1887,8 +1880,7 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port)
}
/* Start the DMA? */
- status = send_cmd(dev, UMPC_START_PORT,
- (u8)(UMPM_UART1_PORT + port_number), 0, NULL, 0);
+ status = send_port_cmd(port, UMPC_START_PORT, 0, NULL, 0);
if (status) {
dev_err(&port->dev, "%s - cannot send start DMA command, %d\n",
__func__, status);
@@ -1905,9 +1897,7 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port)
}
/* Read Initial MSR */
- status = ti_vread_sync(dev, UMPC_READ_MSR, 0,
- (__u16)(UMPM_UART1_PORT + port_number),
- &edge_port->shadow_msr, 1);
+ status = read_port_cmd(port, UMPC_READ_MSR, 0, &edge_port->shadow_msr, 1);
if (status) {
dev_err(&port->dev, "%s - cannot send read MSR command, %d\n",
__func__, status);
@@ -1971,9 +1961,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);
edge_port = usb_get_serial_port_data(port);
@@ -1994,9 +1982,7 @@ static void edge_close(struct usb_serial_port *port)
spin_unlock_irqrestore(&edge_port->ep_lock, flags);
dev_dbg(&port->dev, "%s - send umpc_close_port\n", __func__);
- port_number = port->port_number;
- send_cmd(serial->dev, UMPC_CLOSE_PORT,
- (__u8)(UMPM_UART1_PORT + port_number), 0, NULL, 0);
+ send_port_cmd(port, UMPC_CLOSE_PORT, 0, NULL, 0);
mutex_lock(&edge_serial->es_lock);
--edge_port->edge_serial->num_ports_open;
@@ -2229,7 +2215,6 @@ static void change_port_settings(struct tty_struct *tty,
int baud;
unsigned cflag;
int status;
- int port_number = edge_port->port->port_number;
config = kmalloc (sizeof (*config), GFP_KERNEL);
if (!config) {
@@ -2244,7 +2229,7 @@ static void change_port_settings(struct tty_struct *tty,
/* These flags must be set */
config->wFlags |= UMP_MASK_UART_FLAGS_RECEIVE_MS_INT;
config->wFlags |= UMP_MASK_UART_FLAGS_AUTO_START_ON_ERR;
- config->bUartMode = (__u8)(edge_port->bUartMode);
+ config->bUartMode = (u8)(edge_port->bUartMode);
switch (cflag & CSIZE) {
case CS5:
@@ -2336,7 +2321,7 @@ static void change_port_settings(struct tty_struct *tty,
}
edge_port->baud_rate = baud;
- config->wBaudRate = (__u16)((461550L + baud/2) / baud);
+ config->wBaudRate = (u16)((461550L + baud/2) / baud);
/* FIXME: Recompute actual baud from divisor here */
@@ -2355,9 +2340,8 @@ static void change_port_settings(struct tty_struct *tty,
cpu_to_be16s(&config->wFlags);
cpu_to_be16s(&config->wBaudRate);
- status = send_cmd(edge_port->port->serial->dev, UMPC_SET_CONFIG,
- (__u8)(UMPM_UART1_PORT + port_number),
- 0, (__u8 *)config, sizeof(*config));
+ status = send_port_cmd(edge_port->port, UMPC_SET_CONFIG, 0, config,
+ sizeof(*config));
if (status)
dev_dbg(dev, "%s - error %d when trying to write config to device\n",
__func__, status);
@@ -2433,28 +2417,6 @@ static int edge_tiocmget(struct tty_struct *tty)
return result;
}
-static int get_serial_info(struct tty_struct *tty,
- struct serial_struct *ss)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct edgeport_port *edge_port = usb_get_serial_port_data(port);
- unsigned cwait;
-
- cwait = edge_port->port->port.closing_wait;
- if (cwait != ASYNC_CLOSING_WAIT_NONE)
- cwait = jiffies_to_msecs(cwait) / 10;
-
- ss->type = PORT_16550A;
- ss->line = edge_port->port->minor;
- ss->port = edge_port->port->port_number;
- ss->irq = 0;
- ss->xmit_fifo_size = edge_port->port->bulk_out_size;
- ss->baud_base = 9600;
- ss->close_delay = 5*HZ;
- ss->closing_wait = cwait;
- return 0;
-}
-
static void edge_break(struct tty_struct *tty, int break_state)
{
struct usb_serial_port *port = tty->driver_data;
@@ -2615,7 +2577,10 @@ static int edge_port_probe(struct usb_serial_port *port)
if (ret)
goto err;
- port->port.closing_wait = msecs_to_jiffies(closing_wait * 10);
+ /*
+ * The LSR does not tell when the transmitter shift register has
+ * emptied so add a one-character drain delay.
+ */
port->port.drain_delay = 1;
return 0;
@@ -2713,7 +2678,6 @@ static struct usb_serial_driver edgeport_1port_device = {
.release = edge_release,
.port_probe = edge_port_probe,
.port_remove = edge_port_remove,
- .get_serial = get_serial_info,
.set_termios = edge_set_termios,
.tiocmget = edge_tiocmget,
.tiocmset = edge_tiocmset,
@@ -2752,7 +2716,6 @@ static struct usb_serial_driver edgeport_2port_device = {
.release = edge_release,
.port_probe = edge_port_probe,
.port_remove = edge_port_remove,
- .get_serial = get_serial_info,
.set_termios = edge_set_termios,
.tiocmget = edge_tiocmget,
.tiocmset = edge_tiocmset,
@@ -2783,9 +2746,6 @@ MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
MODULE_FIRMWARE("edgeport/down3.bin");
-module_param(closing_wait, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(closing_wait, "Maximum wait for data to drain, in .01 secs");
-
module_param(ignore_cpu_rev, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(ignore_cpu_rev,
"Ignore the cpu revision when connecting to a device");
diff --git a/drivers/usb/serial/io_ti.h b/drivers/usb/serial/io_ti.h
index 50b899d55ed0..24fe1312c84d 100644
--- a/drivers/usb/serial/io_ti.h
+++ b/drivers/usb/serial/io_ti.h
@@ -133,15 +133,15 @@
#define UMPD_OEDB2_ADDRESS 0xFF10
struct out_endpoint_desc_block {
- __u8 Configuration;
- __u8 XBufAddr;
- __u8 XByteCount;
- __u8 Unused1;
- __u8 Unused2;
- __u8 YBufAddr;
- __u8 YByteCount;
- __u8 BufferSize;
-} __attribute__((packed));
+ u8 Configuration;
+ u8 XBufAddr;
+ u8 XByteCount;
+ u8 Unused1;
+ u8 Unused2;
+ u8 YBufAddr;
+ u8 YByteCount;
+ u8 BufferSize;
+};
/*
@@ -150,16 +150,16 @@ struct out_endpoint_desc_block {
*/
/* UART settings */
struct ump_uart_config {
- __u16 wBaudRate; /* Baud rate */
- __u16 wFlags; /* Bitmap mask of flags */
- __u8 bDataBits; /* 5..8 - data bits per character */
- __u8 bParity; /* Parity settings */
- __u8 bStopBits; /* Stop bits settings */
+ u16 wBaudRate; /* Baud rate */
+ u16 wFlags; /* Bitmap mask of flags */
+ u8 bDataBits; /* 5..8 - data bits per character */
+ u8 bParity; /* Parity settings */
+ u8 bStopBits; /* Stop bits settings */
char cXon; /* XON character */
char cXoff; /* XOFF character */
- __u8 bUartMode; /* Will be updated when a user */
+ u8 bUartMode; /* Will be updated when a user */
/* interface is defined */
-} __attribute__((packed));
+};
/*
@@ -168,9 +168,9 @@ struct ump_uart_config {
*/
/* Interrupt packet structure */
struct ump_interrupt {
- __u8 bICode; /* Interrupt code (interrupt num) */
- __u8 bIInfo; /* Interrupt information */
-} __attribute__((packed));
+ u8 bICode; /* Interrupt code (interrupt num) */
+ u8 bIInfo; /* Interrupt information */
+};
#define TIUMP_GET_PORT_FROM_CODE(c) (((c) >> 6) & 0x01)
diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c
index 093afd67a664..19753611e7b0 100644
--- a/drivers/usb/serial/iuu_phoenix.c
+++ b/drivers/usb/serial/iuu_phoenix.c
@@ -643,7 +643,6 @@ static void iuu_uart_read_callback(struct urb *urb)
struct iuu_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
int status = urb->status;
- int error = 0;
int len = 0;
unsigned char *data = urb->transfer_buffer;
priv->poll++;
@@ -660,12 +659,11 @@ static void iuu_uart_read_callback(struct urb *urb)
if (urb->actual_length > 1) {
dev_dbg(&port->dev, "%s - urb->actual_length = %i\n", __func__,
urb->actual_length);
- error = 1;
return;
}
/* if len > 0 call readbuf */
- if (len > 0 && error == 0) {
+ if (len > 0) {
dev_dbg(&port->dev, "%s - call read buf - len to read is %i\n",
__func__, len);
status = iuu_read_buf(port, len);
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index 622077dcc344..b04a029e3657 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -41,27 +41,7 @@
#define DRIVER_AUTHOR "Hugh Blemings <hugh@misc.nu"
#define DRIVER_DESC "Keyspan USB to Serial Converter Driver"
-/* Function prototypes for Keyspan serial converter */
-static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port);
-static void keyspan_close(struct usb_serial_port *port);
-static void keyspan_dtr_rts(struct usb_serial_port *port, int on);
-static int keyspan_startup(struct usb_serial *serial);
-static void keyspan_disconnect(struct usb_serial *serial);
-static void keyspan_release(struct usb_serial *serial);
-static int keyspan_port_probe(struct usb_serial_port *port);
-static void keyspan_port_remove(struct usb_serial_port *port);
-static int keyspan_write_room(struct tty_struct *tty);
-static int keyspan_write(struct tty_struct *tty, struct usb_serial_port *port,
- const unsigned char *buf, int count);
static void keyspan_send_setup(struct usb_serial_port *port, int reset_port);
-static void keyspan_set_termios(struct tty_struct *tty,
- struct usb_serial_port *port,
- struct ktermios *old);
-static void keyspan_break_ctl(struct tty_struct *tty, int break_state);
-static int keyspan_tiocmget(struct tty_struct *tty);
-static int keyspan_tiocmset(struct tty_struct *tty, unsigned int set,
- unsigned int clear);
-static int keyspan_fake_startup(struct usb_serial *serial);
static int keyspan_usa19_calc_baud(struct usb_serial_port *port,
u32 baud_rate, u32 baudclk,
diff --git a/drivers/usb/serial/metro-usb.c b/drivers/usb/serial/metro-usb.c
index 0bfe4459c37f..f9ce9e7b9b80 100644
--- a/drivers/usb/serial/metro-usb.c
+++ b/drivers/usb/serial/metro-usb.c
@@ -299,7 +299,7 @@ static int metrousb_tiocmset(struct tty_struct *tty,
unsigned long flags = 0;
unsigned long control_state = 0;
- dev_dbg(tty->dev, "%s - set=%d, clear=%d\n", __func__, set, clear);
+ dev_dbg(&port->dev, "%s - set=%d, clear=%d\n", __func__, set, clear);
spin_lock_irqsave(&metro_priv->lock, flags);
control_state = metro_priv->control_state;
@@ -334,7 +334,7 @@ static void metrousb_unthrottle(struct tty_struct *tty)
/* Submit the urb to read from the port. */
result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
if (result)
- dev_err(tty->dev,
+ dev_err(&port->dev,
"failed submitting interrupt in urb error code=%d\n",
result);
}
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index 701dfb32b129..6ee83886e2c9 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -1042,7 +1042,7 @@ static int mos7720_write_room(struct tty_struct *tty)
mos7720_port = usb_get_serial_port_data(port);
if (mos7720_port == NULL)
- return -ENODEV;
+ return 0;
/* FIXME: Locking */
for (i = 0; i < NUM_URBS; ++i) {
@@ -1634,23 +1634,6 @@ static int mos7720_tiocmset(struct tty_struct *tty,
return 0;
}
-static int get_serial_info(struct tty_struct *tty,
- struct serial_struct *ss)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct moschip_port *mos7720_port = usb_get_serial_port_data(port);
-
- ss->type = PORT_16550A;
- ss->line = mos7720_port->port->minor;
- ss->port = mos7720_port->port->port_number;
- ss->irq = 0;
- ss->xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE;
- ss->baud_base = 9600;
- ss->close_delay = 5*HZ;
- ss->closing_wait = 30*HZ;
- return 0;
-}
-
static int mos7720_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
@@ -1790,7 +1773,6 @@ static struct usb_serial_driver moschip7720_2port_driver = {
.ioctl = mos7720_ioctl,
.tiocmget = mos7720_tiocmget,
.tiocmset = mos7720_tiocmset,
- .get_serial = get_serial_info,
.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 1bf0d066f55a..28e4093794e0 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -1384,28 +1384,6 @@ static int mos7840_get_lsr_info(struct tty_struct *tty,
}
/*****************************************************************************
- * mos7840_get_serial_info
- * function to get information about serial port
- *****************************************************************************/
-
-static int mos7840_get_serial_info(struct tty_struct *tty,
- struct serial_struct *ss)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct moschip_port *mos7840_port = usb_get_serial_port_data(port);
-
- ss->type = PORT_16550A;
- ss->line = mos7840_port->port->minor;
- ss->port = mos7840_port->port->port_number;
- ss->irq = 0;
- ss->xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE;
- ss->baud_base = 9600;
- ss->close_delay = 5 * HZ;
- ss->closing_wait = 30 * HZ;
- return 0;
-}
-
-/*****************************************************************************
* SerialIoctl
* this function handles any ioctl calls to the driver
*****************************************************************************/
@@ -1783,7 +1761,6 @@ static struct usb_serial_driver moschip7840_4port_device = {
.probe = mos7840_probe,
.attach = mos7840_attach,
.ioctl = mos7840_ioctl,
- .get_serial = mos7840_get_serial_info,
.set_termios = mos7840_set_termios,
.break_ctl = mos7840_break,
.tiocmget = mos7840_tiocmget,
diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c
index eecb72aef83e..40c713fae0c3 100644
--- a/drivers/usb/serial/opticon.c
+++ b/drivers/usb/serial/opticon.c
@@ -352,23 +352,6 @@ static int opticon_tiocmset(struct tty_struct *tty,
return 0;
}
-static int get_serial_info(struct tty_struct *tty,
- struct serial_struct *ss)
-{
- struct usb_serial_port *port = tty->driver_data;
-
- /* fake emulate a 16550 uart to make userspace code happy */
- ss->type = PORT_16550A;
- ss->line = port->minor;
- ss->port = 0;
- ss->irq = 0;
- ss->xmit_fifo_size = 1024;
- ss->baud_base = 9600;
- ss->close_delay = 5*HZ;
- ss->closing_wait = 30*HZ;
- return 0;
-}
-
static int opticon_port_probe(struct usb_serial_port *port)
{
struct opticon_private *priv;
@@ -410,7 +393,6 @@ static struct usb_serial_driver opticon_device = {
.chars_in_buffer = opticon_chars_in_buffer,
.throttle = usb_serial_generic_throttle,
.unthrottle = usb_serial_generic_unthrottle,
- .get_serial = get_serial_info,
.tiocmget = opticon_tiocmget,
.tiocmset = opticon_tiocmset,
.process_read_urb = opticon_process_read_urb,
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index c6969ca72839..3e79a543d3e7 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -2095,8 +2095,6 @@ static struct usb_serial_driver option_1port_device = {
.chars_in_buffer = usb_wwan_chars_in_buffer,
.tiocmget = usb_wwan_tiocmget,
.tiocmset = usb_wwan_tiocmset,
- .get_serial = usb_wwan_get_serial_info,
- .set_serial = usb_wwan_set_serial_info,
.attach = option_attach,
.release = option_release,
.port_probe = usb_wwan_port_probe,
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index eed9acd1ae08..fd773d252691 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -173,17 +173,22 @@ MODULE_DEVICE_TABLE(usb, id_table);
static void pl2303_set_break(struct usb_serial_port *port, bool enable);
enum pl2303_type {
- TYPE_01, /* Type 0 and 1 (difference unknown) */
- TYPE_HX, /* HX version of the pl2303 chip */
- TYPE_HXN, /* HXN version of the pl2303 chip */
+ TYPE_H,
+ TYPE_HX,
+ TYPE_TA,
+ TYPE_TB,
+ TYPE_HXD,
+ TYPE_HXN,
TYPE_COUNT
};
struct pl2303_type_data {
+ const char *name;
speed_t max_baud_rate;
unsigned long quirks;
unsigned int no_autoxonxoff:1;
unsigned int no_divisors:1;
+ unsigned int alt_divisors:1;
};
struct pl2303_serial_private {
@@ -200,15 +205,32 @@ struct pl2303_private {
};
static const struct pl2303_type_data pl2303_type_data[TYPE_COUNT] = {
- [TYPE_01] = {
+ [TYPE_H] = {
+ .name = "H",
.max_baud_rate = 1228800,
.quirks = PL2303_QUIRK_LEGACY,
.no_autoxonxoff = true,
},
[TYPE_HX] = {
+ .name = "HX",
+ .max_baud_rate = 6000000,
+ },
+ [TYPE_TA] = {
+ .name = "TA",
+ .max_baud_rate = 6000000,
+ .alt_divisors = true,
+ },
+ [TYPE_TB] = {
+ .name = "TB",
+ .max_baud_rate = 12000000,
+ .alt_divisors = true,
+ },
+ [TYPE_HXD] = {
+ .name = "HXD",
.max_baud_rate = 12000000,
},
[TYPE_HXN] = {
+ .name = "G",
.max_baud_rate = 12000000,
.no_divisors = true,
},
@@ -362,42 +384,82 @@ static int pl2303_calc_num_ports(struct usb_serial *serial,
return 1;
}
+static bool pl2303_supports_hx_status(struct usb_serial *serial)
+{
+ int ret;
+ u8 buf;
+
+ ret = usb_control_msg_recv(serial->dev, 0, VENDOR_READ_REQUEST,
+ VENDOR_READ_REQUEST_TYPE, PL2303_READ_TYPE_HX_STATUS,
+ 0, &buf, 1, 100, GFP_KERNEL);
+
+ return ret == 0;
+}
+
+static int pl2303_detect_type(struct usb_serial *serial)
+{
+ struct usb_device_descriptor *desc = &serial->dev->descriptor;
+ u16 bcdDevice, bcdUSB;
+
+ /*
+ * Legacy PL2303H, variants 0 and 1 (difference unknown).
+ */
+ if (desc->bDeviceClass == 0x02)
+ return TYPE_H; /* variant 0 */
+
+ if (desc->bMaxPacketSize0 != 0x40) {
+ if (desc->bDeviceClass == 0x00 || desc->bDeviceClass == 0xff)
+ return TYPE_H; /* variant 1 */
+
+ return TYPE_H; /* variant 0 */
+ }
+
+ bcdDevice = le16_to_cpu(desc->bcdDevice);
+ bcdUSB = le16_to_cpu(desc->bcdUSB);
+
+ switch (bcdDevice) {
+ case 0x100:
+ /*
+ * Assume it's an HXN-type if the device doesn't support the old read
+ * request value.
+ */
+ if (bcdUSB == 0x200 && !pl2303_supports_hx_status(serial))
+ return TYPE_HXN;
+ break;
+ case 0x300:
+ if (bcdUSB == 0x200)
+ return TYPE_TA;
+
+ return TYPE_HX;
+ case 0x400:
+ return TYPE_HXD;
+ case 0x500:
+ return TYPE_TB;
+ }
+
+ dev_err(&serial->interface->dev,
+ "unknown device type, please report to linux-usb@vger.kernel.org\n");
+ return -ENODEV;
+}
+
static int pl2303_startup(struct usb_serial *serial)
{
struct pl2303_serial_private *spriv;
- enum pl2303_type type = TYPE_01;
+ enum pl2303_type type;
unsigned char *buf;
- int res;
+ int ret;
+
+ ret = pl2303_detect_type(serial);
+ if (ret < 0)
+ return ret;
+
+ type = ret;
+ dev_dbg(&serial->interface->dev, "device type: %s\n", pl2303_type_data[type].name);
spriv = kzalloc(sizeof(*spriv), GFP_KERNEL);
if (!spriv)
return -ENOMEM;
- buf = kmalloc(1, GFP_KERNEL);
- if (!buf) {
- kfree(spriv);
- return -ENOMEM;
- }
-
- if (serial->dev->descriptor.bDeviceClass == 0x02)
- type = TYPE_01; /* type 0 */
- else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40)
- type = TYPE_HX;
- else if (serial->dev->descriptor.bDeviceClass == 0x00)
- type = TYPE_01; /* type 1 */
- else if (serial->dev->descriptor.bDeviceClass == 0xFF)
- type = TYPE_01; /* type 1 */
- dev_dbg(&serial->interface->dev, "device type: %d\n", type);
-
- if (type == TYPE_HX) {
- res = usb_control_msg(serial->dev,
- usb_rcvctrlpipe(serial->dev, 0),
- VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,
- PL2303_READ_TYPE_HX_STATUS, 0, buf, 1, 100);
- if (res != 1)
- type = TYPE_HXN;
- }
-
spriv->type = &pl2303_type_data[type];
spriv->quirks = (unsigned long)usb_get_serial_data(serial);
spriv->quirks |= spriv->type->quirks;
@@ -405,6 +467,12 @@ static int pl2303_startup(struct usb_serial *serial)
usb_set_serial_data(serial, spriv);
if (type != TYPE_HXN) {
+ buf = kmalloc(1, GFP_KERNEL);
+ if (!buf) {
+ kfree(spriv);
+ return -ENOMEM;
+ }
+
pl2303_vendor_read(serial, 0x8484, buf);
pl2303_vendor_write(serial, 0x0404, 0);
pl2303_vendor_read(serial, 0x8484, buf);
@@ -419,9 +487,9 @@ static int pl2303_startup(struct usb_serial *serial)
pl2303_vendor_write(serial, 2, 0x24);
else
pl2303_vendor_write(serial, 2, 0x44);
- }
- kfree(buf);
+ kfree(buf);
+ }
return 0;
}
@@ -553,6 +621,45 @@ static speed_t pl2303_encode_baud_rate_divisor(unsigned char buf[4],
return baud;
}
+static speed_t pl2303_encode_baud_rate_divisor_alt(unsigned char buf[4],
+ speed_t baud)
+{
+ unsigned int baseline, mantissa, exponent;
+
+ /*
+ * Apparently, for the TA version the formula is:
+ * baudrate = 12M * 32 / (mantissa * 2^exponent)
+ * where
+ * mantissa = buf[10:0]
+ * exponent = buf[15:13 16]
+ */
+ baseline = 12000000 * 32;
+ mantissa = baseline / baud;
+ if (mantissa == 0)
+ mantissa = 1; /* Avoid dividing by zero if baud > 32*12M. */
+ exponent = 0;
+ while (mantissa >= 2048) {
+ if (exponent < 15) {
+ mantissa >>= 1; /* divide by 2 */
+ exponent++;
+ } else {
+ /* Exponent is maxed. Trim mantissa and leave. */
+ mantissa = 2047;
+ break;
+ }
+ }
+
+ buf[3] = 0x80;
+ buf[2] = exponent & 0x01;
+ buf[1] = (exponent & ~0x01) << 4 | mantissa >> 8;
+ buf[0] = mantissa & 0xff;
+
+ /* Calculate and return the exact baud rate. */
+ baud = (baseline / mantissa) >> exponent;
+
+ return baud;
+}
+
static void pl2303_encode_baud_rate(struct tty_struct *tty,
struct usb_serial_port *port,
u8 buf[4])
@@ -580,6 +687,8 @@ static void pl2303_encode_baud_rate(struct tty_struct *tty,
if (baud == baud_sup)
baud = pl2303_encode_baud_rate_direct(buf, baud);
+ else if (spriv->type->alt_divisors)
+ baud = pl2303_encode_baud_rate_divisor_alt(buf, baud);
else
baud = pl2303_encode_baud_rate_divisor(buf, baud);
@@ -939,18 +1048,6 @@ static int pl2303_carrier_raised(struct usb_serial_port *port)
return 0;
}
-static int pl2303_get_serial(struct tty_struct *tty,
- struct serial_struct *ss)
-{
- struct usb_serial_port *port = tty->driver_data;
-
- ss->type = PORT_16654;
- ss->line = port->minor;
- ss->port = port->port_number;
- ss->baud_base = 460800;
- return 0;
-}
-
static void pl2303_set_break(struct usb_serial_port *port, bool enable)
{
struct usb_serial *serial = port->serial;
@@ -1134,7 +1231,6 @@ static struct usb_serial_driver pl2303_device = {
.close = pl2303_close,
.dtr_rts = pl2303_dtr_rts,
.carrier_raised = pl2303_carrier_raised,
- .get_serial = pl2303_get_serial,
.break_ctl = pl2303_break_ctl,
.set_termios = pl2303_set_termios,
.tiocmget = pl2303_tiocmget,
diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c
index 599dcb2e374d..5f2e7f668e68 100644
--- a/drivers/usb/serial/quatech2.c
+++ b/drivers/usb/serial/quatech2.c
@@ -453,21 +453,6 @@ static void qt2_disconnect(struct usb_serial *serial)
usb_kill_urb(serial_priv->read_urb);
}
-static int get_serial_info(struct tty_struct *tty,
- struct serial_struct *ss)
-{
- struct usb_serial_port *port = tty->driver_data;
-
- ss->line = port->minor;
- ss->port = 0;
- ss->irq = 0;
- ss->xmit_fifo_size = port->bulk_out_size;
- ss->baud_base = 9600;
- ss->close_delay = 5*HZ;
- ss->closing_wait = 30*HZ;
- return 0;
-}
-
static void qt2_process_status(struct usb_serial_port *port, unsigned char *ch)
{
switch (*ch) {
@@ -978,7 +963,6 @@ static struct usb_serial_driver qt2_device = {
.tiocmset = qt2_tiocmset,
.tiocmiwait = usb_serial_generic_tiocmiwait,
.get_icount = usb_serial_generic_get_icount,
- .get_serial = get_serial_info,
.set_termios = qt2_set_termios,
};
diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c
index 89fdc5c19285..3baf7c0f5a98 100644
--- a/drivers/usb/serial/ssu100.c
+++ b/drivers/usb/serial/ssu100.c
@@ -331,21 +331,6 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port)
return usb_serial_generic_open(tty, port);
}
-static int get_serial_info(struct tty_struct *tty,
- struct serial_struct *ss)
-{
- struct usb_serial_port *port = tty->driver_data;
-
- ss->line = port->minor;
- ss->port = 0;
- ss->irq = 0;
- ss->xmit_fifo_size = port->bulk_out_size;
- ss->baud_base = 9600;
- ss->close_delay = 5*HZ;
- ss->closing_wait = 30*HZ;
- return 0;
-}
-
static int ssu100_attach(struct usb_serial *serial)
{
return ssu100_initdevice(serial->dev);
@@ -545,7 +530,6 @@ static struct usb_serial_driver ssu100_device = {
.tiocmset = ssu100_tiocmset,
.tiocmiwait = usb_serial_generic_tiocmiwait,
.get_icount = usb_serial_generic_get_icount,
- .get_serial = get_serial_info,
.set_termios = ssu100_set_termios,
};
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index 7252b0ce75a6..caa46ac23db9 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -121,6 +121,7 @@
#define TI_LSR_ERROR 0x0F
#define TI_LSR_RX_FULL 0x10
#define TI_LSR_TX_EMPTY 0x20
+#define TI_LSR_TX_EMPTY_BOTH 0x40
/* Line control */
#define TI_LCR_BREAK 0x40
@@ -183,7 +184,7 @@ struct ti_uart_config {
char cXon;
char cXoff;
u8 bUartMode;
-} __packed;
+};
/* Get port status */
struct ti_port_status {
@@ -192,7 +193,7 @@ struct ti_port_status {
u8 bErrorCode;
u8 bMSR;
u8 bLSR;
-} __packed;
+};
/* Purge modes */
#define TI_PURGE_OUTPUT 0x00
@@ -223,25 +224,25 @@ struct ti_write_data_bytes {
} __packed;
struct ti_read_data_request {
- __u8 bAddrType;
- __u8 bDataType;
- __u8 bDataCounter;
+ u8 bAddrType;
+ u8 bDataType;
+ u8 bDataCounter;
__be16 wBaseAddrHi;
__be16 wBaseAddrLo;
} __packed;
struct ti_read_data_bytes {
- __u8 bCmdCode;
- __u8 bModuleId;
- __u8 bErrorCode;
- __u8 bData[];
-} __packed;
+ u8 bCmdCode;
+ u8 bModuleId;
+ u8 bErrorCode;
+ u8 bData[];
+};
/* Interrupt struct */
struct ti_interrupt {
- __u8 bICode;
- __u8 bIInfo;
-} __packed;
+ u8 bICode;
+ u8 bIInfo;
+};
/* Interrupt codes */
#define TI_CODE_HARDWARE_ERROR 0xFF
@@ -270,8 +271,6 @@ struct ti_firmware_header {
#define TI_TRANSFER_TIMEOUT 2
-#define TI_DEFAULT_CLOSING_WAIT 4000 /* in .01 secs */
-
/* read urb states */
#define TI_READ_URB_RUNNING 0
#define TI_READ_URB_STOPPING 1
@@ -328,27 +327,26 @@ static void ti_recv(struct usb_serial_port *port, unsigned char *data,
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, u8 *lsr);
-static int ti_get_serial_info(struct tty_struct *tty,
- struct serial_struct *ss);
-static int ti_set_serial_info(struct tty_struct *tty,
- struct serial_struct *ss);
+static void ti_get_serial_info(struct tty_struct *tty, struct serial_struct *ss);
static void ti_handle_new_msr(struct ti_port *tport, u8 msr);
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);
-static int ti_command_out_sync(struct ti_device *tdev, __u8 command,
- __u16 moduleid, __u16 value, __u8 *data, int size);
-static int ti_command_in_sync(struct ti_device *tdev, __u8 command,
- __u16 moduleid, __u16 value, __u8 *data, int size);
+static int ti_command_out_sync(struct usb_device *udev, u8 command,
+ u16 moduleid, u16 value, void *data, int size);
+static int ti_command_in_sync(struct usb_device *udev, u8 command,
+ u16 moduleid, u16 value, void *data, int size);
+static int ti_port_cmd_out(struct usb_serial_port *port, u8 command,
+ u16 value, void *data, int size);
+static int ti_port_cmd_in(struct usb_serial_port *port, u8 command,
+ u16 value, void *data, int size);
static int ti_write_byte(struct usb_serial_port *port, struct ti_device *tdev,
unsigned long addr, u8 mask, u8 byte);
static int ti_download_firmware(struct ti_device *tdev);
-static int closing_wait = TI_DEFAULT_CLOSING_WAIT;
-
static const struct usb_device_id ti_id_table_3410[] = {
{ USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) },
{ USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) },
@@ -435,7 +433,6 @@ static struct usb_serial_driver ti_1port_device = {
.throttle = ti_throttle,
.unthrottle = ti_unthrottle,
.get_serial = ti_get_serial_info,
- .set_serial = ti_set_serial_info,
.set_termios = ti_set_termios,
.tiocmget = ti_tiocmget,
.tiocmset = ti_tiocmset,
@@ -469,7 +466,6 @@ static struct usb_serial_driver ti_2port_device = {
.throttle = ti_throttle,
.unthrottle = ti_unthrottle,
.get_serial = ti_get_serial_info,
- .set_serial = ti_set_serial_info,
.set_termios = ti_set_termios,
.tiocmget = ti_tiocmget,
.tiocmset = ti_tiocmset,
@@ -502,10 +498,6 @@ MODULE_FIRMWARE("moxa/moxa-1131.fw");
MODULE_FIRMWARE("moxa/moxa-1150.fw");
MODULE_FIRMWARE("moxa/moxa-1151.fw");
-module_param(closing_wait, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(closing_wait,
- "Maximum wait for data to drain in close, in .01 secs, default is 4000");
-
MODULE_DEVICE_TABLE(usb, ti_id_table_combined);
module_usb_serial_driver(serial_drivers, ti_id_table_combined);
@@ -613,7 +605,6 @@ 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;
- port->port.closing_wait = msecs_to_jiffies(10 * closing_wait);
tport->tp_port = port;
tport->tp_tdev = usb_get_serial_data(port->serial);
@@ -624,7 +615,12 @@ static int ti_port_probe(struct usb_serial_port *port)
usb_set_serial_port_data(port, tport);
- port->port.drain_delay = 3;
+ /*
+ * The TUSB5052 LSR does not tell when the transmitter shift register
+ * has emptied so add a one-character drain delay.
+ */
+ if (!tport->tp_tdev->td_is_3410)
+ port->port.drain_delay = 1;
return 0;
}
@@ -643,7 +639,6 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port)
struct ti_device *tdev;
struct usb_device *dev;
struct urb *urb;
- int port_number;
int status;
u16 open_settings;
@@ -658,8 +653,6 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port)
if (mutex_lock_interruptible(&tdev->td_open_close_lock))
return -ERESTARTSYS;
- port_number = port->port_number;
-
tport->tp_msr = 0;
tport->tp_shadow_mcr |= (TI_MCR_RTS | TI_MCR_DTR);
@@ -683,31 +676,27 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port)
if (tty)
ti_set_termios(tty, port, &tty->termios);
- status = ti_command_out_sync(tdev, TI_OPEN_PORT,
- (__u8)(TI_UART1_PORT + port_number), open_settings, NULL, 0);
+ status = ti_port_cmd_out(port, TI_OPEN_PORT, open_settings, NULL, 0);
if (status) {
dev_err(&port->dev, "%s - cannot send open command, %d\n",
__func__, status);
goto unlink_int_urb;
}
- status = ti_command_out_sync(tdev, TI_START_PORT,
- (__u8)(TI_UART1_PORT + port_number), 0, NULL, 0);
+ status = ti_port_cmd_out(port, TI_START_PORT, 0, NULL, 0);
if (status) {
dev_err(&port->dev, "%s - cannot send start command, %d\n",
__func__, status);
goto unlink_int_urb;
}
- status = ti_command_out_sync(tdev, TI_PURGE_PORT,
- (__u8)(TI_UART1_PORT + port_number), TI_PURGE_INPUT, NULL, 0);
+ status = ti_port_cmd_out(port, TI_PURGE_PORT, TI_PURGE_INPUT, NULL, 0);
if (status) {
dev_err(&port->dev, "%s - cannot clear input buffers, %d\n",
__func__, status);
goto unlink_int_urb;
}
- status = ti_command_out_sync(tdev, TI_PURGE_PORT,
- (__u8)(TI_UART1_PORT + port_number), TI_PURGE_OUTPUT, NULL, 0);
+ status = ti_port_cmd_out(port, TI_PURGE_PORT, TI_PURGE_OUTPUT, NULL, 0);
if (status) {
dev_err(&port->dev, "%s - cannot clear output buffers, %d\n",
__func__, status);
@@ -722,16 +711,14 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port)
if (tty)
ti_set_termios(tty, port, &tty->termios);
- status = ti_command_out_sync(tdev, TI_OPEN_PORT,
- (__u8)(TI_UART1_PORT + port_number), open_settings, NULL, 0);
+ status = ti_port_cmd_out(port, TI_OPEN_PORT, open_settings, NULL, 0);
if (status) {
dev_err(&port->dev, "%s - cannot send open command (2), %d\n",
__func__, status);
goto unlink_int_urb;
}
- status = ti_command_out_sync(tdev, TI_START_PORT,
- (__u8)(TI_UART1_PORT + port_number), 0, NULL, 0);
+ status = ti_port_cmd_out(port, TI_START_PORT, 0, NULL, 0);
if (status) {
dev_err(&port->dev, "%s - cannot send start command (2), %d\n",
__func__, status);
@@ -772,7 +759,6 @@ static void ti_close(struct usb_serial_port *port)
{
struct ti_device *tdev;
struct ti_port *tport;
- int port_number;
int status;
unsigned long flags;
@@ -788,10 +774,7 @@ static void ti_close(struct usb_serial_port *port)
kfifo_reset_out(&port->write_fifo);
spin_unlock_irqrestore(&tport->tp_lock, flags);
- port_number = port->port_number;
-
- status = ti_command_out_sync(tdev, TI_CLOSE_PORT,
- (__u8)(TI_UART1_PORT + port_number), 0, NULL, 0);
+ status = ti_port_cmd_out(port, TI_CLOSE_PORT, 0, NULL, 0);
if (status)
dev_err(&port->dev,
"%s - cannot send close port command, %d\n"
@@ -861,11 +844,20 @@ static int ti_chars_in_buffer(struct tty_struct *tty)
static bool ti_tx_empty(struct usb_serial_port *port)
{
struct ti_port *tport = usb_get_serial_port_data(port);
+ u8 lsr, mask;
int ret;
- u8 lsr;
+
+ /*
+ * TUSB5052 does not have the TEMT bit to tell if the shift register
+ * is empty.
+ */
+ if (tport->tp_tdev->td_is_3410)
+ mask = TI_LSR_TX_EMPTY_BOTH;
+ else
+ mask = TI_LSR_TX_EMPTY;
ret = ti_get_lsr(tport, &lsr);
- if (!ret && !(lsr & TI_LSR_TX_EMPTY))
+ if (!ret && !(lsr & mask))
return false;
return true;
@@ -903,7 +895,6 @@ static void ti_set_termios(struct tty_struct *tty,
struct ti_uart_config *config;
int baud;
int status;
- int port_number = port->port_number;
unsigned int mcr;
u16 wbaudrate;
u16 wflags = 0;
@@ -919,18 +910,18 @@ static void ti_set_termios(struct tty_struct *tty,
switch (C_CSIZE(tty)) {
case CS5:
- config->bDataBits = TI_UART_5_DATA_BITS;
- break;
+ config->bDataBits = TI_UART_5_DATA_BITS;
+ break;
case CS6:
- config->bDataBits = TI_UART_6_DATA_BITS;
- break;
+ config->bDataBits = TI_UART_6_DATA_BITS;
+ break;
case CS7:
- config->bDataBits = TI_UART_7_DATA_BITS;
- break;
+ config->bDataBits = TI_UART_7_DATA_BITS;
+ break;
default:
case CS8:
- config->bDataBits = TI_UART_8_DATA_BITS;
- break;
+ config->bDataBits = TI_UART_8_DATA_BITS;
+ break;
}
/* CMSPAR isn't supported by this driver */
@@ -997,12 +988,11 @@ static void ti_set_termios(struct tty_struct *tty,
config->wBaudRate = cpu_to_be16(wbaudrate);
config->wFlags = cpu_to_be16(wflags);
- status = ti_command_out_sync(tport->tp_tdev, TI_SET_CONFIG,
- (__u8)(TI_UART1_PORT + port_number), 0, (__u8 *)config,
- sizeof(*config));
+ status = ti_port_cmd_out(port, TI_SET_CONFIG, 0, config,
+ sizeof(*config));
if (status)
dev_err(&port->dev, "%s - cannot set config on port %d, %d\n",
- __func__, port_number, status);
+ __func__, port->port_number, status);
/* SET_CONFIG asserts RTS and DTR, reset them correctly */
mcr = tport->tp_shadow_mcr;
@@ -1011,9 +1001,8 @@ static void ti_set_termios(struct tty_struct *tty,
mcr &= ~(TI_MCR_DTR | TI_MCR_RTS);
status = ti_set_mcr(tport, mcr);
if (status)
- dev_err(&port->dev,
- "%s - cannot set modem control on port %d, %d\n",
- __func__, port_number, status);
+ dev_err(&port->dev, "%s - cannot set modem control on port %d, %d\n",
+ __func__, port->port_number, status);
kfree(config);
}
@@ -1364,9 +1353,7 @@ static int ti_set_mcr(struct ti_port *tport, unsigned int mcr)
static int ti_get_lsr(struct ti_port *tport, u8 *lsr)
{
int size, status;
- struct ti_device *tdev = tport->tp_tdev;
struct usb_serial_port *port = tport->tp_port;
- int port_number = port->port_number;
struct ti_port_status *data;
size = sizeof(struct ti_port_status);
@@ -1374,8 +1361,7 @@ static int ti_get_lsr(struct ti_port *tport, u8 *lsr)
if (!data)
return -ENOMEM;
- status = ti_command_in_sync(tdev, TI_GET_PORT_STATUS,
- (__u8)(TI_UART1_PORT+port_number), 0, (__u8 *)data, size);
+ status = ti_port_cmd_in(port, TI_GET_PORT_STATUS, 0, data, size);
if (status) {
dev_err(&port->dev,
"%s - get port status command failed, %d\n",
@@ -1393,41 +1379,12 @@ free_data:
}
-static int ti_get_serial_info(struct tty_struct *tty,
- struct serial_struct *ss)
+static void ti_get_serial_info(struct tty_struct *tty, struct serial_struct *ss)
{
struct usb_serial_port *port = tty->driver_data;
struct ti_port *tport = usb_get_serial_port_data(port);
- unsigned cwait;
-
- cwait = port->port.closing_wait;
- if (cwait != ASYNC_CLOSING_WAIT_NONE)
- cwait = jiffies_to_msecs(cwait) / 10;
- ss->type = PORT_16550A;
- ss->line = port->minor;
- ss->port = port->port_number;
- ss->xmit_fifo_size = kfifo_size(&port->write_fifo);
ss->baud_base = tport->tp_tdev->td_is_3410 ? 921600 : 460800;
- ss->closing_wait = cwait;
- return 0;
-}
-
-
-static int ti_set_serial_info(struct tty_struct *tty,
- struct serial_struct *ss)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct ti_port *tport = usb_get_serial_port_data(port);
- unsigned cwait;
-
- cwait = ss->closing_wait;
- if (cwait != ASYNC_CLOSING_WAIT_NONE)
- cwait = msecs_to_jiffies(10 * ss->closing_wait);
-
- tport->tp_port->port.closing_wait = cwait;
-
- return 0;
}
@@ -1501,34 +1458,28 @@ static int ti_restart_read(struct ti_port *tport, struct tty_struct *tty)
return status;
}
-
-static int ti_command_out_sync(struct ti_device *tdev, __u8 command,
- __u16 moduleid, __u16 value, __u8 *data, int size)
+static int ti_command_out_sync(struct usb_device *udev, u8 command,
+ u16 moduleid, u16 value, void *data, int size)
{
int status;
- status = usb_control_msg(tdev->td_serial->dev,
- usb_sndctrlpipe(tdev->td_serial->dev, 0), command,
- (USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT),
- value, moduleid, data, size, 1000);
-
+ status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), command,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+ value, moduleid, data, size, 1000);
if (status < 0)
return status;
return 0;
}
-
-static int ti_command_in_sync(struct ti_device *tdev, __u8 command,
- __u16 moduleid, __u16 value, __u8 *data, int size)
+static int ti_command_in_sync(struct usb_device *udev, u8 command,
+ u16 moduleid, u16 value, void *data, int size)
{
int status;
- status = usb_control_msg(tdev->td_serial->dev,
- usb_rcvctrlpipe(tdev->td_serial->dev, 0), command,
- (USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN),
- value, moduleid, data, size, 1000);
-
+ status = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), command,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+ value, moduleid, data, size, 1000);
if (status == size)
status = 0;
else if (status >= 0)
@@ -1537,6 +1488,21 @@ static int ti_command_in_sync(struct ti_device *tdev, __u8 command,
return status;
}
+static int ti_port_cmd_out(struct usb_serial_port *port, u8 command,
+ u16 value, void *data, int size)
+{
+ return ti_command_out_sync(port->serial->dev, command,
+ TI_UART1_PORT + port->port_number,
+ value, data, size);
+}
+
+static int ti_port_cmd_in(struct usb_serial_port *port, u8 command,
+ u16 value, void *data, int size)
+{
+ return ti_command_in_sync(port->serial->dev, command,
+ TI_UART1_PORT + port->port_number,
+ value, data, size);
+}
static int ti_write_byte(struct usb_serial_port *port,
struct ti_device *tdev, unsigned long addr,
@@ -1562,9 +1528,8 @@ static int ti_write_byte(struct usb_serial_port *port,
data->bData[0] = mask;
data->bData[1] = byte;
- status = ti_command_out_sync(tdev, TI_WRITE_DATA, TI_RAM_PORT, 0,
- (__u8 *)data, size);
-
+ status = ti_command_out_sync(port->serial->dev, TI_WRITE_DATA,
+ TI_RAM_PORT, 0, data, size);
if (status < 0)
dev_err(&port->dev, "%s - failed, %d\n", __func__, status);
diff --git a/drivers/usb/serial/upd78f0730.c b/drivers/usb/serial/upd78f0730.c
index 26d7b003b7e3..63d4a784ae45 100644
--- a/drivers/usb/serial/upd78f0730.c
+++ b/drivers/usb/serial/upd78f0730.c
@@ -182,7 +182,6 @@ static void upd78f0730_port_remove(struct usb_serial_port *port)
static int upd78f0730_tiocmget(struct tty_struct *tty)
{
- struct device *dev = tty->dev;
struct upd78f0730_port_private *private;
struct usb_serial_port *port = tty->driver_data;
int signals;
@@ -197,7 +196,7 @@ static int upd78f0730_tiocmget(struct tty_struct *tty)
res = ((signals & UPD78F0730_DTR) ? TIOCM_DTR : 0) |
((signals & UPD78F0730_RTS) ? TIOCM_RTS : 0);
- dev_dbg(dev, "%s - res = %x\n", __func__, res);
+ dev_dbg(&port->dev, "%s - res = %x\n", __func__, res);
return res;
}
@@ -205,10 +204,10 @@ static int upd78f0730_tiocmget(struct tty_struct *tty)
static int upd78f0730_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear)
{
- struct device *dev = tty->dev;
struct usb_serial_port *port = tty->driver_data;
struct upd78f0730_port_private *private;
struct upd78f0730_set_dtr_rts request;
+ struct device *dev = &port->dev;
int res;
private = usb_get_serial_port_data(port);
@@ -241,10 +240,10 @@ static int upd78f0730_tiocmset(struct tty_struct *tty,
static void upd78f0730_break_ctl(struct tty_struct *tty, int break_state)
{
- struct device *dev = tty->dev;
struct upd78f0730_port_private *private;
struct usb_serial_port *port = tty->driver_data;
struct upd78f0730_set_dtr_rts request;
+ struct device *dev = &port->dev;
private = usb_get_serial_port_data(port);
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 27e3bb58c872..98b33b1b5357 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -121,6 +121,44 @@ static void release_minors(struct usb_serial *serial)
serial->minors_reserved = 0;
}
+int usb_serial_claim_interface(struct usb_serial *serial, struct usb_interface *intf)
+{
+ struct usb_driver *driver = serial->type->usb_driver;
+ int ret;
+
+ if (serial->sibling)
+ return -EBUSY;
+
+ ret = usb_driver_claim_interface(driver, intf, serial);
+ if (ret) {
+ dev_err(&serial->interface->dev,
+ "failed to claim sibling interface: %d\n", ret);
+ return ret;
+ }
+
+ serial->sibling = intf;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(usb_serial_claim_interface);
+
+static void release_sibling(struct usb_serial *serial, struct usb_interface *intf)
+{
+ struct usb_driver *driver = serial->type->usb_driver;
+ struct usb_interface *sibling;
+
+ if (!serial->sibling)
+ return;
+
+ if (intf == serial->sibling)
+ sibling = serial->interface;
+ else
+ sibling = serial->sibling;
+
+ usb_set_intfdata(sibling, NULL);
+ usb_driver_release_interface(driver, sibling);
+}
+
static void destroy_serial(struct kref *kref)
{
struct usb_serial *serial;
@@ -243,7 +281,7 @@ static int serial_open(struct tty_struct *tty, struct file *filp)
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(tty->dev, "%s\n", __func__);
+ dev_dbg(&port->dev, "%s\n", __func__);
return tty_port_open(&port->port, tty, filp);
}
@@ -272,7 +310,7 @@ static void serial_hangup(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(tty->dev, "%s\n", __func__);
+ dev_dbg(&port->dev, "%s\n", __func__);
tty_port_hangup(&port->port);
}
@@ -281,7 +319,7 @@ static void serial_close(struct tty_struct *tty, struct file *filp)
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(tty->dev, "%s\n", __func__);
+ dev_dbg(&port->dev, "%s\n", __func__);
tty_port_close(&port->port, tty, filp);
}
@@ -301,7 +339,7 @@ static void serial_cleanup(struct tty_struct *tty)
struct usb_serial *serial;
struct module *owner;
- dev_dbg(tty->dev, "%s\n", __func__);
+ dev_dbg(&port->dev, "%s\n", __func__);
/* The console is magical. Do not hang up the console hardware
* or there will be tears.
@@ -329,7 +367,7 @@ 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 - %d byte(s)\n", __func__, count);
+ dev_dbg(&port->dev, "%s - %d byte(s)\n", __func__, count);
retval = port->serial->type->write(tty, port, buf, count);
if (retval < 0)
@@ -342,7 +380,7 @@ static int serial_write_room(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(tty->dev, "%s\n", __func__);
+ dev_dbg(&port->dev, "%s\n", __func__);
return port->serial->type->write_room(tty);
}
@@ -352,7 +390,7 @@ static int serial_chars_in_buffer(struct tty_struct *tty)
struct usb_serial_port *port = tty->driver_data;
struct usb_serial *serial = port->serial;
- dev_dbg(tty->dev, "%s\n", __func__);
+ dev_dbg(&port->dev, "%s\n", __func__);
if (serial->disconnected)
return 0;
@@ -365,7 +403,7 @@ static void serial_wait_until_sent(struct tty_struct *tty, int timeout)
struct usb_serial_port *port = tty->driver_data;
struct usb_serial *serial = port->serial;
- dev_dbg(tty->dev, "%s\n", __func__);
+ dev_dbg(&port->dev, "%s\n", __func__);
if (!port->serial->type->wait_until_sent)
return;
@@ -380,7 +418,7 @@ static void serial_throttle(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(tty->dev, "%s\n", __func__);
+ dev_dbg(&port->dev, "%s\n", __func__);
if (port->serial->type->throttle)
port->serial->type->throttle(tty);
@@ -390,7 +428,7 @@ static void serial_unthrottle(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(tty->dev, "%s\n", __func__);
+ dev_dbg(&port->dev, "%s\n", __func__);
if (port->serial->type->unthrottle)
port->serial->type->unthrottle(tty);
@@ -399,19 +437,62 @@ static void serial_unthrottle(struct tty_struct *tty)
static int serial_get_serial(struct tty_struct *tty, struct serial_struct *ss)
{
struct usb_serial_port *port = tty->driver_data;
+ struct tty_port *tport = &port->port;
+ unsigned int close_delay, closing_wait;
+
+ mutex_lock(&tport->mutex);
+
+ close_delay = jiffies_to_msecs(tport->close_delay) / 10;
+ closing_wait = tport->closing_wait;
+ if (closing_wait != ASYNC_CLOSING_WAIT_NONE)
+ closing_wait = jiffies_to_msecs(closing_wait) / 10;
+
+ ss->line = port->minor;
+ ss->close_delay = close_delay;
+ ss->closing_wait = closing_wait;
if (port->serial->type->get_serial)
- return port->serial->type->get_serial(tty, ss);
- return -ENOTTY;
+ port->serial->type->get_serial(tty, ss);
+
+ mutex_unlock(&tport->mutex);
+
+ return 0;
}
static int serial_set_serial(struct tty_struct *tty, struct serial_struct *ss)
{
struct usb_serial_port *port = tty->driver_data;
+ struct tty_port *tport = &port->port;
+ unsigned int close_delay, closing_wait;
+ int ret = 0;
+
+ close_delay = msecs_to_jiffies(ss->close_delay * 10);
+ closing_wait = ss->closing_wait;
+ if (closing_wait != ASYNC_CLOSING_WAIT_NONE)
+ closing_wait = msecs_to_jiffies(closing_wait * 10);
+
+ mutex_lock(&tport->mutex);
+
+ if (!capable(CAP_SYS_ADMIN)) {
+ if (close_delay != tport->close_delay ||
+ closing_wait != tport->closing_wait) {
+ ret = -EPERM;
+ goto out_unlock;
+ }
+ }
- if (port->serial->type->set_serial)
- return port->serial->type->set_serial(tty, ss);
- return -ENOTTY;
+ if (port->serial->type->set_serial) {
+ ret = port->serial->type->set_serial(tty, ss);
+ if (ret)
+ goto out_unlock;
+ }
+
+ tport->close_delay = close_delay;
+ tport->closing_wait = closing_wait;
+out_unlock:
+ mutex_unlock(&tport->mutex);
+
+ return ret;
}
static int serial_ioctl(struct tty_struct *tty,
@@ -420,7 +501,7 @@ static int serial_ioctl(struct tty_struct *tty,
struct usb_serial_port *port = tty->driver_data;
int retval = -ENOIOCTLCMD;
- dev_dbg(tty->dev, "%s - cmd 0x%04x\n", __func__, cmd);
+ dev_dbg(&port->dev, "%s - cmd 0x%04x\n", __func__, cmd);
switch (cmd) {
case TIOCMIWAIT:
@@ -439,7 +520,7 @@ 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\n", __func__);
+ dev_dbg(&port->dev, "%s\n", __func__);
if (port->serial->type->set_termios)
port->serial->type->set_termios(tty, port, old);
@@ -451,7 +532,7 @@ static int serial_break(struct tty_struct *tty, int break_state)
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(tty->dev, "%s\n", __func__);
+ dev_dbg(&port->dev, "%s\n", __func__);
if (port->serial->type->break_ctl)
port->serial->type->break_ctl(tty, break_state);
@@ -498,11 +579,11 @@ static int serial_tiocmget(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(tty->dev, "%s\n", __func__);
+ dev_dbg(&port->dev, "%s\n", __func__);
if (port->serial->type->tiocmget)
return port->serial->type->tiocmget(tty);
- return -EINVAL;
+ return -ENOTTY;
}
static int serial_tiocmset(struct tty_struct *tty,
@@ -510,11 +591,11 @@ static int serial_tiocmset(struct tty_struct *tty,
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(tty->dev, "%s\n", __func__);
+ dev_dbg(&port->dev, "%s\n", __func__);
if (port->serial->type->tiocmset)
return port->serial->type->tiocmset(tty, set, clear);
- return -EINVAL;
+ return -ENOTTY;
}
static int serial_get_icount(struct tty_struct *tty,
@@ -522,11 +603,11 @@ static int serial_get_icount(struct tty_struct *tty,
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(tty->dev, "%s\n", __func__);
+ dev_dbg(&port->dev, "%s\n", __func__);
if (port->serial->type->get_icount)
return port->serial->type->get_icount(tty, icount);
- return -EINVAL;
+ return -ENOTTY;
}
/*
@@ -711,36 +792,48 @@ static const struct tty_port_operations serial_port_ops = {
.shutdown = serial_port_shutdown,
};
-static void find_endpoints(struct usb_serial *serial,
- struct usb_serial_endpoints *epds)
+static void store_endpoint(struct usb_serial *serial,
+ struct usb_serial_endpoints *epds,
+ struct usb_endpoint_descriptor *epd)
{
struct device *dev = &serial->interface->dev;
+ u8 addr = epd->bEndpointAddress;
+
+ if (usb_endpoint_is_bulk_in(epd)) {
+ if (epds->num_bulk_in == ARRAY_SIZE(epds->bulk_in))
+ return;
+ dev_dbg(dev, "found bulk in endpoint %02x\n", addr);
+ epds->bulk_in[epds->num_bulk_in++] = epd;
+ } else if (usb_endpoint_is_bulk_out(epd)) {
+ if (epds->num_bulk_out == ARRAY_SIZE(epds->bulk_out))
+ return;
+ dev_dbg(dev, "found bulk out endpoint %02x\n", addr);
+ epds->bulk_out[epds->num_bulk_out++] = epd;
+ } else if (usb_endpoint_is_int_in(epd)) {
+ if (epds->num_interrupt_in == ARRAY_SIZE(epds->interrupt_in))
+ return;
+ dev_dbg(dev, "found interrupt in endpoint %02x\n", addr);
+ epds->interrupt_in[epds->num_interrupt_in++] = epd;
+ } else if (usb_endpoint_is_int_out(epd)) {
+ if (epds->num_interrupt_out == ARRAY_SIZE(epds->interrupt_out))
+ return;
+ dev_dbg(dev, "found interrupt out endpoint %02x\n", addr);
+ epds->interrupt_out[epds->num_interrupt_out++] = epd;
+ }
+}
+
+static void find_endpoints(struct usb_serial *serial,
+ struct usb_serial_endpoints *epds,
+ struct usb_interface *intf)
+{
struct usb_host_interface *iface_desc;
struct usb_endpoint_descriptor *epd;
unsigned int i;
- BUILD_BUG_ON(ARRAY_SIZE(epds->bulk_in) < USB_MAXENDPOINTS / 2);
- BUILD_BUG_ON(ARRAY_SIZE(epds->bulk_out) < USB_MAXENDPOINTS / 2);
- BUILD_BUG_ON(ARRAY_SIZE(epds->interrupt_in) < USB_MAXENDPOINTS / 2);
- BUILD_BUG_ON(ARRAY_SIZE(epds->interrupt_out) < USB_MAXENDPOINTS / 2);
-
- iface_desc = serial->interface->cur_altsetting;
+ iface_desc = intf->cur_altsetting;
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
epd = &iface_desc->endpoint[i].desc;
-
- if (usb_endpoint_is_bulk_in(epd)) {
- dev_dbg(dev, "found bulk in on endpoint %u\n", i);
- epds->bulk_in[epds->num_bulk_in++] = epd;
- } else if (usb_endpoint_is_bulk_out(epd)) {
- dev_dbg(dev, "found bulk out on endpoint %u\n", i);
- epds->bulk_out[epds->num_bulk_out++] = epd;
- } else if (usb_endpoint_is_int_in(epd)) {
- dev_dbg(dev, "found interrupt in on endpoint %u\n", i);
- epds->interrupt_in[epds->num_interrupt_in++] = epd;
- } else if (usb_endpoint_is_int_out(epd)) {
- dev_dbg(dev, "found interrupt out on endpoint %u\n", i);
- epds->interrupt_out[epds->num_interrupt_out++] = epd;
- }
+ store_endpoint(serial, epds, epd);
}
}
@@ -906,7 +999,7 @@ static int usb_serial_probe(struct usb_interface *interface,
if (retval) {
dev_dbg(ddev, "sub driver rejected device\n");
- goto err_put_serial;
+ goto err_release_sibling;
}
}
@@ -914,10 +1007,12 @@ static int usb_serial_probe(struct usb_interface *interface,
epds = kzalloc(sizeof(*epds), GFP_KERNEL);
if (!epds) {
retval = -ENOMEM;
- goto err_put_serial;
+ goto err_release_sibling;
}
- find_endpoints(serial, epds);
+ find_endpoints(serial, epds, interface);
+ if (serial->sibling)
+ find_endpoints(serial, epds, serial->sibling);
if (epds->num_bulk_in < type->num_bulk_in ||
epds->num_bulk_out < type->num_bulk_out ||
@@ -1065,7 +1160,8 @@ exit:
err_free_epds:
kfree(epds);
-err_put_serial:
+err_release_sibling:
+ release_sibling(serial, interface);
usb_serial_put(serial);
err_put_module:
module_put(type->driver.owner);
@@ -1081,6 +1177,10 @@ static void usb_serial_disconnect(struct usb_interface *interface)
struct usb_serial_port *port;
struct tty_struct *tty;
+ /* sibling interface is cleaning up */
+ if (!serial)
+ return;
+
usb_serial_console_disconnect(serial);
mutex_lock(&serial->disc_mutex);
@@ -1104,6 +1204,8 @@ static void usb_serial_disconnect(struct usb_interface *interface)
if (serial->type->disconnect)
serial->type->disconnect(serial);
+ release_sibling(serial, interface);
+
/* let the last holder of this object cause it to be cleaned up */
usb_serial_put(serial);
dev_info(dev, "device disconnected\n");
@@ -1112,9 +1214,11 @@ static void usb_serial_disconnect(struct usb_interface *interface)
int usb_serial_suspend(struct usb_interface *intf, pm_message_t message)
{
struct usb_serial *serial = usb_get_intfdata(intf);
- int i, r = 0;
+ int i, r;
- serial->suspending = 1;
+ /* suspend when called for first sibling interface */
+ if (serial->suspend_count++)
+ return 0;
/*
* serial->type->suspend() MUST return 0 in system sleep context,
@@ -1124,15 +1228,15 @@ int usb_serial_suspend(struct usb_interface *intf, pm_message_t message)
if (serial->type->suspend) {
r = serial->type->suspend(serial, message);
if (r < 0) {
- serial->suspending = 0;
- goto err_out;
+ serial->suspend_count--;
+ return r;
}
}
for (i = 0; i < serial->num_ports; ++i)
usb_serial_port_poison_urbs(serial->port[i]);
-err_out:
- return r;
+
+ return 0;
}
EXPORT_SYMBOL(usb_serial_suspend);
@@ -1149,9 +1253,12 @@ int usb_serial_resume(struct usb_interface *intf)
struct usb_serial *serial = usb_get_intfdata(intf);
int rv;
+ /* resume when called for last sibling interface */
+ if (--serial->suspend_count)
+ return 0;
+
usb_serial_unpoison_port_urbs(serial);
- serial->suspending = 0;
if (serial->type->resume)
rv = serial->type->resume(serial);
else
@@ -1166,9 +1273,12 @@ static int usb_serial_reset_resume(struct usb_interface *intf)
struct usb_serial *serial = usb_get_intfdata(intf);
int rv;
+ /* resume when called for last sibling interface */
+ if (--serial->suspend_count)
+ return 0;
+
usb_serial_unpoison_port_urbs(serial);
- serial->suspending = 0;
if (serial->type->reset_resume) {
rv = serial->type->reset_resume(serial);
} else {
diff --git a/drivers/usb/serial/usb-wwan.h b/drivers/usb/serial/usb-wwan.h
index 79dafd98e0a1..b5331d03092f 100644
--- a/drivers/usb/serial/usb-wwan.h
+++ b/drivers/usb/serial/usb-wwan.h
@@ -15,10 +15,6 @@ extern int usb_wwan_write_room(struct tty_struct *tty);
extern int usb_wwan_tiocmget(struct tty_struct *tty);
extern int usb_wwan_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear);
-extern int usb_wwan_get_serial_info(struct tty_struct *tty,
- struct serial_struct *ss);
-extern int usb_wwan_set_serial_info(struct tty_struct *tty,
- struct serial_struct *ss);
extern int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count);
extern int usb_wwan_chars_in_buffer(struct tty_struct *tty);
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
index 46d46a4f99c9..3eb72c59ede6 100644
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
@@ -132,51 +132,6 @@ int usb_wwan_tiocmset(struct tty_struct *tty,
}
EXPORT_SYMBOL(usb_wwan_tiocmset);
-int usb_wwan_get_serial_info(struct tty_struct *tty,
- struct serial_struct *ss)
-{
- struct usb_serial_port *port = tty->driver_data;
-
- ss->line = port->minor;
- ss->port = port->port_number;
- ss->baud_base = tty_get_baud_rate(port->port.tty);
- ss->close_delay = port->port.close_delay / 10;
- ss->closing_wait = port->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
- ASYNC_CLOSING_WAIT_NONE :
- port->port.closing_wait / 10;
- return 0;
-}
-EXPORT_SYMBOL(usb_wwan_get_serial_info);
-
-int usb_wwan_set_serial_info(struct tty_struct *tty,
- struct serial_struct *ss)
-{
- struct usb_serial_port *port = tty->driver_data;
- unsigned int closing_wait, close_delay;
- int retval = 0;
-
- close_delay = ss->close_delay * 10;
- closing_wait = ss->closing_wait == ASYNC_CLOSING_WAIT_NONE ?
- ASYNC_CLOSING_WAIT_NONE : ss->closing_wait * 10;
-
- mutex_lock(&port->port.mutex);
-
- if (!capable(CAP_SYS_ADMIN)) {
- if ((close_delay != port->port.close_delay) ||
- (closing_wait != port->port.closing_wait))
- retval = -EPERM;
- else
- retval = -EOPNOTSUPP;
- } else {
- port->port.close_delay = close_delay;
- port->port.closing_wait = closing_wait;
- }
-
- mutex_unlock(&port->port.mutex);
- return retval;
-}
-EXPORT_SYMBOL(usb_wwan_set_serial_info);
-
int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count)
{
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index ccfd5ed652cd..5116ed9db3eb 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -83,7 +83,7 @@ static void whiteheat_port_remove(struct usb_serial_port *port);
static int whiteheat_open(struct tty_struct *tty,
struct usb_serial_port *port);
static void whiteheat_close(struct usb_serial_port *port);
-static int whiteheat_get_serial(struct tty_struct *tty,
+static void whiteheat_get_serial(struct tty_struct *tty,
struct serial_struct *ss);
static void whiteheat_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old);
@@ -170,7 +170,6 @@ static int firm_report_tx_done(struct usb_serial_port *port);
#define COMMAND_PORT 4
#define COMMAND_TIMEOUT (2*HZ) /* 2 second timeout for a command */
#define COMMAND_TIMEOUT_MS 2000
-#define CLOSING_DELAY (30 * HZ)
/*****************************************************************************
@@ -440,21 +439,9 @@ static int whiteheat_tiocmset(struct tty_struct *tty,
}
-static int whiteheat_get_serial(struct tty_struct *tty,
- struct serial_struct *ss)
+static void whiteheat_get_serial(struct tty_struct *tty, struct serial_struct *ss)
{
- struct usb_serial_port *port = tty->driver_data;
-
- ss->type = PORT_16654;
- ss->line = port->minor;
- ss->port = port->port_number;
- ss->xmit_fifo_size = kfifo_size(&port->write_fifo);
- ss->custom_divisor = 0;
ss->baud_base = 460800;
- ss->close_delay = CLOSING_DELAY;
- ss->closing_wait = CLOSING_DELAY;
-
- return 0;
}
diff --git a/drivers/usb/serial/xr_serial.c b/drivers/usb/serial/xr_serial.c
index 0ca04906da4b..6853cd56d8dc 100644
--- a/drivers/usb/serial/xr_serial.c
+++ b/drivers/usb/serial/xr_serial.c
@@ -3,6 +3,7 @@
* MaxLinear/Exar USB to Serial driver
*
* Copyright (c) 2020 Manivannan Sadhasivam <mani@kernel.org>
+ * Copyright (c) 2021 Johan Hovold <johan@kernel.org>
*
* Based on the initial driver written by Patong Yang:
*
@@ -16,6 +17,7 @@
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/usb.h>
+#include <linux/usb/cdc.h>
#include <linux/usb/serial.h>
struct xr_txrx_clk_mask {
@@ -28,10 +30,12 @@ struct xr_txrx_clk_mask {
#define XR21V141X_MIN_SPEED 46U
#define XR21V141X_MAX_SPEED XR_INT_OSC_HZ
-/* USB Requests */
-#define XR21V141X_SET_REQ 0
-#define XR21V141X_GET_REQ 1
+/* XR21V141X register blocks */
+#define XR21V141X_UART_REG_BLOCK 0
+#define XR21V141X_UM_REG_BLOCK 4
+#define XR21V141X_UART_CUSTOM_BLOCK 0x66
+/* XR21V141X UART registers */
#define XR21V141X_CLOCK_DIVISOR_0 0x04
#define XR21V141X_CLOCK_DIVISOR_1 0x05
#define XR21V141X_CLOCK_DIVISOR_2 0x06
@@ -39,13 +43,9 @@ struct xr_txrx_clk_mask {
#define XR21V141X_TX_CLOCK_MASK_1 0x08
#define XR21V141X_RX_CLOCK_MASK_0 0x09
#define XR21V141X_RX_CLOCK_MASK_1 0x0a
+#define XR21V141X_REG_FORMAT 0x0b
-/* XR21V141X register blocks */
-#define XR21V141X_UART_REG_BLOCK 0
-#define XR21V141X_UM_REG_BLOCK 4
-#define XR21V141X_UART_CUSTOM_BLOCK 0x66
-
-/* XR21V141X UART Manager Registers */
+/* XR21V141X UART Manager registers */
#define XR21V141X_UM_FIFO_ENABLE_REG 0x10
#define XR21V141X_UM_ENABLE_TX_FIFO 0x01
#define XR21V141X_UM_ENABLE_RX_FIFO 0x02
@@ -53,72 +53,203 @@ struct xr_txrx_clk_mask {
#define XR21V141X_UM_RX_FIFO_RESET 0x18
#define XR21V141X_UM_TX_FIFO_RESET 0x1c
-#define XR21V141X_UART_ENABLE_TX 0x1
-#define XR21V141X_UART_ENABLE_RX 0x2
-
-#define XR21V141X_UART_MODE_RI BIT(0)
-#define XR21V141X_UART_MODE_CD BIT(1)
-#define XR21V141X_UART_MODE_DSR BIT(2)
-#define XR21V141X_UART_MODE_DTR BIT(3)
-#define XR21V141X_UART_MODE_CTS BIT(4)
-#define XR21V141X_UART_MODE_RTS BIT(5)
-
-#define XR21V141X_UART_BREAK_ON 0xff
-#define XR21V141X_UART_BREAK_OFF 0
-
-#define XR21V141X_UART_DATA_MASK GENMASK(3, 0)
-#define XR21V141X_UART_DATA_7 0x7
-#define XR21V141X_UART_DATA_8 0x8
-
-#define XR21V141X_UART_PARITY_MASK GENMASK(6, 4)
-#define XR21V141X_UART_PARITY_SHIFT 4
-#define XR21V141X_UART_PARITY_NONE (0x0 << XR21V141X_UART_PARITY_SHIFT)
-#define XR21V141X_UART_PARITY_ODD (0x1 << XR21V141X_UART_PARITY_SHIFT)
-#define XR21V141X_UART_PARITY_EVEN (0x2 << XR21V141X_UART_PARITY_SHIFT)
-#define XR21V141X_UART_PARITY_MARK (0x3 << XR21V141X_UART_PARITY_SHIFT)
-#define XR21V141X_UART_PARITY_SPACE (0x4 << XR21V141X_UART_PARITY_SHIFT)
-
-#define XR21V141X_UART_STOP_MASK BIT(7)
-#define XR21V141X_UART_STOP_SHIFT 7
-#define XR21V141X_UART_STOP_1 (0x0 << XR21V141X_UART_STOP_SHIFT)
-#define XR21V141X_UART_STOP_2 (0x1 << XR21V141X_UART_STOP_SHIFT)
-
-#define XR21V141X_UART_FLOW_MODE_NONE 0x0
-#define XR21V141X_UART_FLOW_MODE_HW 0x1
-#define XR21V141X_UART_FLOW_MODE_SW 0x2
-
-#define XR21V141X_UART_MODE_GPIO_MASK GENMASK(2, 0)
-#define XR21V141X_UART_MODE_RTS_CTS 0x1
-#define XR21V141X_UART_MODE_DTR_DSR 0x2
-#define XR21V141X_UART_MODE_RS485 0x3
-#define XR21V141X_UART_MODE_RS485_ADDR 0x4
-
-#define XR21V141X_REG_ENABLE 0x03
-#define XR21V141X_REG_FORMAT 0x0b
-#define XR21V141X_REG_FLOW_CTRL 0x0c
-#define XR21V141X_REG_XON_CHAR 0x10
-#define XR21V141X_REG_XOFF_CHAR 0x11
-#define XR21V141X_REG_LOOPBACK 0x12
-#define XR21V141X_REG_TX_BREAK 0x14
-#define XR21V141X_REG_RS845_DELAY 0x15
-#define XR21V141X_REG_GPIO_MODE 0x1a
-#define XR21V141X_REG_GPIO_DIR 0x1b
-#define XR21V141X_REG_GPIO_INT_MASK 0x1c
-#define XR21V141X_REG_GPIO_SET 0x1d
-#define XR21V141X_REG_GPIO_CLR 0x1e
-#define XR21V141X_REG_GPIO_STATUS 0x1f
-
-static int xr_set_reg(struct usb_serial_port *port, u8 block, u8 reg, u8 val)
+#define XR_UART_ENABLE_TX 0x1
+#define XR_UART_ENABLE_RX 0x2
+
+#define XR_GPIO_RI BIT(0)
+#define XR_GPIO_CD BIT(1)
+#define XR_GPIO_DSR BIT(2)
+#define XR_GPIO_DTR BIT(3)
+#define XR_GPIO_CTS BIT(4)
+#define XR_GPIO_RTS BIT(5)
+#define XR_GPIO_CLK BIT(6)
+#define XR_GPIO_XEN BIT(7)
+#define XR_GPIO_TXT BIT(8)
+#define XR_GPIO_RXT BIT(9)
+
+#define XR_UART_DATA_MASK GENMASK(3, 0)
+#define XR_UART_DATA_7 0x7
+#define XR_UART_DATA_8 0x8
+
+#define XR_UART_PARITY_MASK GENMASK(6, 4)
+#define XR_UART_PARITY_SHIFT 4
+#define XR_UART_PARITY_NONE (0x0 << XR_UART_PARITY_SHIFT)
+#define XR_UART_PARITY_ODD (0x1 << XR_UART_PARITY_SHIFT)
+#define XR_UART_PARITY_EVEN (0x2 << XR_UART_PARITY_SHIFT)
+#define XR_UART_PARITY_MARK (0x3 << XR_UART_PARITY_SHIFT)
+#define XR_UART_PARITY_SPACE (0x4 << XR_UART_PARITY_SHIFT)
+
+#define XR_UART_STOP_MASK BIT(7)
+#define XR_UART_STOP_SHIFT 7
+#define XR_UART_STOP_1 (0x0 << XR_UART_STOP_SHIFT)
+#define XR_UART_STOP_2 (0x1 << XR_UART_STOP_SHIFT)
+
+#define XR_UART_FLOW_MODE_NONE 0x0
+#define XR_UART_FLOW_MODE_HW 0x1
+#define XR_UART_FLOW_MODE_SW 0x2
+
+#define XR_GPIO_MODE_SEL_MASK GENMASK(2, 0)
+#define XR_GPIO_MODE_SEL_RTS_CTS 0x1
+#define XR_GPIO_MODE_SEL_DTR_DSR 0x2
+#define XR_GPIO_MODE_SEL_RS485 0x3
+#define XR_GPIO_MODE_SEL_RS485_ADDR 0x4
+#define XR_GPIO_MODE_TX_TOGGLE 0x100
+#define XR_GPIO_MODE_RX_TOGGLE 0x200
+
+#define XR_FIFO_RESET 0x1
+
+#define XR_CUSTOM_DRIVER_ACTIVE 0x1
+
+static int xr21v141x_uart_enable(struct usb_serial_port *port);
+static int xr21v141x_uart_disable(struct usb_serial_port *port);
+static int xr21v141x_fifo_reset(struct usb_serial_port *port);
+static void xr21v141x_set_line_settings(struct tty_struct *tty,
+ struct usb_serial_port *port, struct ktermios *old_termios);
+
+struct xr_type {
+ int reg_width;
+ u8 reg_recipient;
+ u8 set_reg;
+ u8 get_reg;
+
+ u16 uart_enable;
+ u16 flow_control;
+ u16 xon_char;
+ u16 xoff_char;
+ u16 tx_break;
+ u16 gpio_mode;
+ u16 gpio_direction;
+ u16 gpio_set;
+ u16 gpio_clear;
+ u16 gpio_status;
+ u16 tx_fifo_reset;
+ u16 rx_fifo_reset;
+ u16 custom_driver;
+
+ bool have_5_6_bit_mode;
+ bool have_xmit_toggle;
+
+ int (*enable)(struct usb_serial_port *port);
+ int (*disable)(struct usb_serial_port *port);
+ int (*fifo_reset)(struct usb_serial_port *port);
+ void (*set_line_settings)(struct tty_struct *tty,
+ struct usb_serial_port *port,
+ struct ktermios *old_termios);
+};
+
+enum xr_type_id {
+ XR21V141X,
+ XR21B142X,
+ XR21B1411,
+ XR2280X,
+ XR_TYPE_COUNT,
+};
+
+static const struct xr_type xr_types[] = {
+ [XR21V141X] = {
+ .reg_width = 8,
+ .reg_recipient = USB_RECIP_DEVICE,
+ .set_reg = 0x00,
+ .get_reg = 0x01,
+
+ .uart_enable = 0x03,
+ .flow_control = 0x0c,
+ .xon_char = 0x10,
+ .xoff_char = 0x11,
+ .tx_break = 0x14,
+ .gpio_mode = 0x1a,
+ .gpio_direction = 0x1b,
+ .gpio_set = 0x1d,
+ .gpio_clear = 0x1e,
+ .gpio_status = 0x1f,
+
+ .enable = xr21v141x_uart_enable,
+ .disable = xr21v141x_uart_disable,
+ .fifo_reset = xr21v141x_fifo_reset,
+ .set_line_settings = xr21v141x_set_line_settings,
+ },
+ [XR21B142X] = {
+ .reg_width = 16,
+ .reg_recipient = USB_RECIP_INTERFACE,
+ .set_reg = 0x00,
+ .get_reg = 0x00,
+
+ .uart_enable = 0x00,
+ .flow_control = 0x06,
+ .xon_char = 0x07,
+ .xoff_char = 0x08,
+ .tx_break = 0x0a,
+ .gpio_mode = 0x0c,
+ .gpio_direction = 0x0d,
+ .gpio_set = 0x0e,
+ .gpio_clear = 0x0f,
+ .gpio_status = 0x10,
+ .tx_fifo_reset = 0x40,
+ .rx_fifo_reset = 0x43,
+ .custom_driver = 0x60,
+
+ .have_5_6_bit_mode = true,
+ .have_xmit_toggle = true,
+ },
+ [XR21B1411] = {
+ .reg_width = 12,
+ .reg_recipient = USB_RECIP_DEVICE,
+ .set_reg = 0x00,
+ .get_reg = 0x01,
+
+ .uart_enable = 0xc00,
+ .flow_control = 0xc06,
+ .xon_char = 0xc07,
+ .xoff_char = 0xc08,
+ .tx_break = 0xc0a,
+ .gpio_mode = 0xc0c,
+ .gpio_direction = 0xc0d,
+ .gpio_set = 0xc0e,
+ .gpio_clear = 0xc0f,
+ .gpio_status = 0xc10,
+ .tx_fifo_reset = 0xc80,
+ .rx_fifo_reset = 0xcc0,
+ .custom_driver = 0x20d,
+ },
+ [XR2280X] = {
+ .reg_width = 16,
+ .reg_recipient = USB_RECIP_DEVICE,
+ .set_reg = 0x05,
+ .get_reg = 0x05,
+
+ .uart_enable = 0x40,
+ .flow_control = 0x46,
+ .xon_char = 0x47,
+ .xoff_char = 0x48,
+ .tx_break = 0x4a,
+ .gpio_mode = 0x4c,
+ .gpio_direction = 0x4d,
+ .gpio_set = 0x4e,
+ .gpio_clear = 0x4f,
+ .gpio_status = 0x50,
+ .tx_fifo_reset = 0x60,
+ .rx_fifo_reset = 0x63,
+ .custom_driver = 0x81,
+ },
+};
+
+struct xr_data {
+ const struct xr_type *type;
+ u8 channel; /* zero-based index or interface number */
+};
+
+static int xr_set_reg(struct usb_serial_port *port, u8 channel, u16 reg, u16 val)
{
+ struct xr_data *data = usb_get_serial_port_data(port);
+ const struct xr_type *type = data->type;
struct usb_serial *serial = port->serial;
int ret;
- ret = usb_control_msg(serial->dev,
- usb_sndctrlpipe(serial->dev, 0),
- XR21V141X_SET_REQ,
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- val, reg | (block << 8), NULL, 0,
- USB_CTRL_SET_TIMEOUT);
+ ret = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ type->set_reg,
+ USB_DIR_OUT | USB_TYPE_VENDOR | type->reg_recipient,
+ val, (channel << 8) | reg, NULL, 0,
+ USB_CTRL_SET_TIMEOUT);
if (ret < 0) {
dev_err(&port->dev, "Failed to set reg 0x%02x: %d\n", reg, ret);
return ret;
@@ -127,24 +258,33 @@ static int xr_set_reg(struct usb_serial_port *port, u8 block, u8 reg, u8 val)
return 0;
}
-static int xr_get_reg(struct usb_serial_port *port, u8 block, u8 reg, u8 *val)
+static int xr_get_reg(struct usb_serial_port *port, u8 channel, u16 reg, u16 *val)
{
+ struct xr_data *data = usb_get_serial_port_data(port);
+ const struct xr_type *type = data->type;
struct usb_serial *serial = port->serial;
u8 *dmabuf;
- int ret;
+ int ret, len;
+
+ if (type->reg_width == 8)
+ len = 1;
+ else
+ len = 2;
- dmabuf = kmalloc(1, GFP_KERNEL);
+ dmabuf = kmalloc(len, GFP_KERNEL);
if (!dmabuf)
return -ENOMEM;
- ret = usb_control_msg(serial->dev,
- usb_rcvctrlpipe(serial->dev, 0),
- XR21V141X_GET_REQ,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0, reg | (block << 8), dmabuf, 1,
- USB_CTRL_GET_TIMEOUT);
- if (ret == 1) {
- *val = *dmabuf;
+ ret = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+ type->get_reg,
+ USB_DIR_IN | USB_TYPE_VENDOR | type->reg_recipient,
+ 0, (channel << 8) | reg, dmabuf, len,
+ USB_CTRL_GET_TIMEOUT);
+ if (ret == len) {
+ if (len == 2)
+ *val = le16_to_cpup((__le16 *)dmabuf);
+ else
+ *val = *dmabuf;
ret = 0;
} else {
dev_err(&port->dev, "Failed to get reg 0x%02x: %d\n", reg, ret);
@@ -157,21 +297,45 @@ static int xr_get_reg(struct usb_serial_port *port, u8 block, u8 reg, u8 *val)
return ret;
}
-static int xr_set_reg_uart(struct usb_serial_port *port, u8 reg, u8 val)
+static int xr_set_reg_uart(struct usb_serial_port *port, u16 reg, u16 val)
{
- return xr_set_reg(port, XR21V141X_UART_REG_BLOCK, reg, val);
+ struct xr_data *data = usb_get_serial_port_data(port);
+
+ return xr_set_reg(port, data->channel, reg, val);
}
-static int xr_get_reg_uart(struct usb_serial_port *port, u8 reg, u8 *val)
+static int xr_get_reg_uart(struct usb_serial_port *port, u16 reg, u16 *val)
{
- return xr_get_reg(port, XR21V141X_UART_REG_BLOCK, reg, val);
+ struct xr_data *data = usb_get_serial_port_data(port);
+
+ return xr_get_reg(port, data->channel, reg, val);
}
-static int xr_set_reg_um(struct usb_serial_port *port, u8 reg, u8 val)
+static int xr_set_reg_um(struct usb_serial_port *port, u8 reg_base, u8 val)
{
+ struct xr_data *data = usb_get_serial_port_data(port);
+ u8 reg;
+
+ reg = reg_base + data->channel;
+
return xr_set_reg(port, XR21V141X_UM_REG_BLOCK, reg, val);
}
+static int __xr_uart_enable(struct usb_serial_port *port)
+{
+ struct xr_data *data = usb_get_serial_port_data(port);
+
+ return xr_set_reg_uart(port, data->type->uart_enable,
+ XR_UART_ENABLE_TX | XR_UART_ENABLE_RX);
+}
+
+static int __xr_uart_disable(struct usb_serial_port *port)
+{
+ struct xr_data *data = usb_get_serial_port_data(port);
+
+ return xr_set_reg_uart(port, data->type->uart_enable, 0);
+}
+
/*
* According to datasheet, below is the recommended sequence for enabling UART
* module in XR21V141X:
@@ -180,7 +344,7 @@ static int xr_set_reg_um(struct usb_serial_port *port, u8 reg, u8 val)
* Enable Tx and Rx
* Enable Rx FIFO
*/
-static int xr_uart_enable(struct usb_serial_port *port)
+static int xr21v141x_uart_enable(struct usb_serial_port *port)
{
int ret;
@@ -189,25 +353,23 @@ static int xr_uart_enable(struct usb_serial_port *port)
if (ret)
return ret;
- ret = xr_set_reg_uart(port, XR21V141X_REG_ENABLE,
- XR21V141X_UART_ENABLE_TX | XR21V141X_UART_ENABLE_RX);
+ ret = __xr_uart_enable(port);
if (ret)
return ret;
ret = xr_set_reg_um(port, XR21V141X_UM_FIFO_ENABLE_REG,
XR21V141X_UM_ENABLE_TX_FIFO | XR21V141X_UM_ENABLE_RX_FIFO);
-
if (ret)
- xr_set_reg_uart(port, XR21V141X_REG_ENABLE, 0);
+ __xr_uart_disable(port);
return ret;
}
-static int xr_uart_disable(struct usb_serial_port *port)
+static int xr21v141x_uart_disable(struct usb_serial_port *port)
{
int ret;
- ret = xr_set_reg_uart(port, XR21V141X_REG_ENABLE, 0);
+ ret = __xr_uart_disable(port);
if (ret)
return ret;
@@ -216,13 +378,68 @@ static int xr_uart_disable(struct usb_serial_port *port)
return ret;
}
+static int xr_uart_enable(struct usb_serial_port *port)
+{
+ struct xr_data *data = usb_get_serial_port_data(port);
+
+ if (data->type->enable)
+ return data->type->enable(port);
+
+ return __xr_uart_enable(port);
+}
+
+static int xr_uart_disable(struct usb_serial_port *port)
+{
+ struct xr_data *data = usb_get_serial_port_data(port);
+
+ if (data->type->disable)
+ return data->type->disable(port);
+
+ return __xr_uart_disable(port);
+}
+
+static int xr21v141x_fifo_reset(struct usb_serial_port *port)
+{
+ int ret;
+
+ ret = xr_set_reg_um(port, XR21V141X_UM_TX_FIFO_RESET, XR_FIFO_RESET);
+ if (ret)
+ return ret;
+
+ ret = xr_set_reg_um(port, XR21V141X_UM_RX_FIFO_RESET, XR_FIFO_RESET);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int xr_fifo_reset(struct usb_serial_port *port)
+{
+ struct xr_data *data = usb_get_serial_port_data(port);
+ int ret;
+
+ if (data->type->fifo_reset)
+ return data->type->fifo_reset(port);
+
+ ret = xr_set_reg_uart(port, data->type->tx_fifo_reset, XR_FIFO_RESET);
+ if (ret)
+ return ret;
+
+ ret = xr_set_reg_uart(port, data->type->rx_fifo_reset, XR_FIFO_RESET);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
static int xr_tiocmget(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- u8 status;
+ struct xr_data *data = usb_get_serial_port_data(port);
+ u16 status;
int ret;
- ret = xr_get_reg_uart(port, XR21V141X_REG_GPIO_STATUS, &status);
+ ret = xr_get_reg_uart(port, data->type->gpio_status, &status);
if (ret)
return ret;
@@ -230,12 +447,12 @@ static int xr_tiocmget(struct tty_struct *tty)
* Modem control pins are active low, so reading '0' means it is active
* and '1' means not active.
*/
- ret = ((status & XR21V141X_UART_MODE_DTR) ? 0 : TIOCM_DTR) |
- ((status & XR21V141X_UART_MODE_RTS) ? 0 : TIOCM_RTS) |
- ((status & XR21V141X_UART_MODE_CTS) ? 0 : TIOCM_CTS) |
- ((status & XR21V141X_UART_MODE_DSR) ? 0 : TIOCM_DSR) |
- ((status & XR21V141X_UART_MODE_RI) ? 0 : TIOCM_RI) |
- ((status & XR21V141X_UART_MODE_CD) ? 0 : TIOCM_CD);
+ ret = ((status & XR_GPIO_DTR) ? 0 : TIOCM_DTR) |
+ ((status & XR_GPIO_RTS) ? 0 : TIOCM_RTS) |
+ ((status & XR_GPIO_CTS) ? 0 : TIOCM_CTS) |
+ ((status & XR_GPIO_DSR) ? 0 : TIOCM_DSR) |
+ ((status & XR_GPIO_RI) ? 0 : TIOCM_RI) |
+ ((status & XR_GPIO_CD) ? 0 : TIOCM_CD);
return ret;
}
@@ -243,26 +460,28 @@ static int xr_tiocmget(struct tty_struct *tty)
static int xr_tiocmset_port(struct usb_serial_port *port,
unsigned int set, unsigned int clear)
{
- u8 gpio_set = 0;
- u8 gpio_clr = 0;
+ struct xr_data *data = usb_get_serial_port_data(port);
+ const struct xr_type *type = data->type;
+ u16 gpio_set = 0;
+ u16 gpio_clr = 0;
int ret = 0;
/* Modem control pins are active low, so set & clr are swapped */
if (set & TIOCM_RTS)
- gpio_clr |= XR21V141X_UART_MODE_RTS;
+ gpio_clr |= XR_GPIO_RTS;
if (set & TIOCM_DTR)
- gpio_clr |= XR21V141X_UART_MODE_DTR;
+ gpio_clr |= XR_GPIO_DTR;
if (clear & TIOCM_RTS)
- gpio_set |= XR21V141X_UART_MODE_RTS;
+ gpio_set |= XR_GPIO_RTS;
if (clear & TIOCM_DTR)
- gpio_set |= XR21V141X_UART_MODE_DTR;
+ gpio_set |= XR_GPIO_DTR;
/* Writing '0' to gpio_{set/clr} bits has no effect, so no need to do */
if (gpio_clr)
- ret = xr_set_reg_uart(port, XR21V141X_REG_GPIO_CLR, gpio_clr);
+ ret = xr_set_reg_uart(port, type->gpio_clear, gpio_clr);
if (gpio_set)
- ret = xr_set_reg_uart(port, XR21V141X_REG_GPIO_SET, gpio_set);
+ ret = xr_set_reg_uart(port, type->gpio_set, gpio_set);
return ret;
}
@@ -286,16 +505,18 @@ static void xr_dtr_rts(struct usb_serial_port *port, int on)
static void xr_break_ctl(struct tty_struct *tty, int break_state)
{
struct usb_serial_port *port = tty->driver_data;
- u8 state;
+ struct xr_data *data = usb_get_serial_port_data(port);
+ const struct xr_type *type = data->type;
+ u16 state;
if (break_state == 0)
- state = XR21V141X_UART_BREAK_OFF;
+ state = 0;
else
- state = XR21V141X_UART_BREAK_ON;
+ state = GENMASK(type->reg_width - 1, 0);
+
+ dev_dbg(&port->dev, "Turning break %s\n", state == 0 ? "off" : "on");
- dev_dbg(&port->dev, "Turning break %s\n",
- state == XR21V141X_UART_BREAK_OFF ? "off" : "on");
- xr_set_reg_uart(port, XR21V141X_REG_TX_BREAK, state);
+ xr_set_reg_uart(port, type->tx_break, state);
}
/* Tx and Rx clock mask values obtained from section 3.3.4 of datasheet */
@@ -334,8 +555,7 @@ static const struct xr_txrx_clk_mask xr21v141x_txrx_clk_masks[] = {
{ 0xfff, 0xffe, 0xffd },
};
-static int xr_set_baudrate(struct tty_struct *tty,
- struct usb_serial_port *port)
+static int xr21v141x_set_baudrate(struct tty_struct *tty, struct usb_serial_port *port)
{
u32 divisor, baud, idx;
u16 tx_mask, rx_mask;
@@ -405,43 +625,47 @@ static void xr_set_flow_mode(struct tty_struct *tty,
struct usb_serial_port *port,
struct ktermios *old_termios)
{
- u8 flow, gpio_mode;
+ struct xr_data *data = usb_get_serial_port_data(port);
+ const struct xr_type *type = data->type;
+ u16 flow, gpio_mode;
int ret;
- ret = xr_get_reg_uart(port, XR21V141X_REG_GPIO_MODE, &gpio_mode);
+ ret = xr_get_reg_uart(port, type->gpio_mode, &gpio_mode);
if (ret)
return;
+ /*
+ * According to the datasheets, the UART needs to be disabled while
+ * writing to the FLOW_CONTROL register (XR21V141X), or any register
+ * but GPIO_SET, GPIO_CLEAR, TX_BREAK and ERROR_STATUS (XR21B142X).
+ */
+ xr_uart_disable(port);
+
/* Set GPIO mode for controlling the pins manually by default. */
- gpio_mode &= ~XR21V141X_UART_MODE_GPIO_MASK;
+ gpio_mode &= ~XR_GPIO_MODE_SEL_MASK;
if (C_CRTSCTS(tty) && C_BAUD(tty) != B0) {
dev_dbg(&port->dev, "Enabling hardware flow ctrl\n");
- gpio_mode |= XR21V141X_UART_MODE_RTS_CTS;
- flow = XR21V141X_UART_FLOW_MODE_HW;
+ gpio_mode |= XR_GPIO_MODE_SEL_RTS_CTS;
+ flow = XR_UART_FLOW_MODE_HW;
} else if (I_IXON(tty)) {
u8 start_char = START_CHAR(tty);
u8 stop_char = STOP_CHAR(tty);
dev_dbg(&port->dev, "Enabling sw flow ctrl\n");
- flow = XR21V141X_UART_FLOW_MODE_SW;
+ flow = XR_UART_FLOW_MODE_SW;
- xr_set_reg_uart(port, XR21V141X_REG_XON_CHAR, start_char);
- xr_set_reg_uart(port, XR21V141X_REG_XOFF_CHAR, stop_char);
+ xr_set_reg_uart(port, type->xon_char, start_char);
+ xr_set_reg_uart(port, type->xoff_char, stop_char);
} else {
dev_dbg(&port->dev, "Disabling flow ctrl\n");
- flow = XR21V141X_UART_FLOW_MODE_NONE;
+ flow = XR_UART_FLOW_MODE_NONE;
}
- /*
- * As per the datasheet, UART needs to be disabled while writing to
- * FLOW_CONTROL register.
- */
- xr_uart_disable(port);
- xr_set_reg_uart(port, XR21V141X_REG_FLOW_CTRL, flow);
- xr_uart_enable(port);
+ xr_set_reg_uart(port, type->flow_control, flow);
+ xr_set_reg_uart(port, type->gpio_mode, gpio_mode);
- xr_set_reg_uart(port, XR21V141X_REG_GPIO_MODE, gpio_mode);
+ xr_uart_enable(port);
if (C_BAUD(tty) == B0)
xr_dtr_rts(port, 0);
@@ -449,16 +673,15 @@ static void xr_set_flow_mode(struct tty_struct *tty,
xr_dtr_rts(port, 1);
}
-static void xr_set_termios(struct tty_struct *tty,
- struct usb_serial_port *port,
- struct ktermios *old_termios)
+static void xr21v141x_set_line_settings(struct tty_struct *tty,
+ struct usb_serial_port *port, struct ktermios *old_termios)
{
struct ktermios *termios = &tty->termios;
u8 bits = 0;
int ret;
if (!old_termios || (tty->termios.c_ospeed != old_termios->c_ospeed))
- xr_set_baudrate(tty, port);
+ xr21v141x_set_baudrate(tty, port);
switch (C_CSIZE(tty)) {
case CS5:
@@ -468,61 +691,154 @@ static void xr_set_termios(struct tty_struct *tty,
if (old_termios)
termios->c_cflag |= old_termios->c_cflag & CSIZE;
else
- bits |= XR21V141X_UART_DATA_8;
+ termios->c_cflag |= CS8;
+
+ if (C_CSIZE(tty) == CS7)
+ bits |= XR_UART_DATA_7;
+ else
+ bits |= XR_UART_DATA_8;
break;
case CS7:
- bits |= XR21V141X_UART_DATA_7;
+ bits |= XR_UART_DATA_7;
break;
case CS8:
default:
- bits |= XR21V141X_UART_DATA_8;
+ bits |= XR_UART_DATA_8;
break;
}
if (C_PARENB(tty)) {
if (C_CMSPAR(tty)) {
if (C_PARODD(tty))
- bits |= XR21V141X_UART_PARITY_MARK;
+ bits |= XR_UART_PARITY_MARK;
else
- bits |= XR21V141X_UART_PARITY_SPACE;
+ bits |= XR_UART_PARITY_SPACE;
} else {
if (C_PARODD(tty))
- bits |= XR21V141X_UART_PARITY_ODD;
+ bits |= XR_UART_PARITY_ODD;
else
- bits |= XR21V141X_UART_PARITY_EVEN;
+ bits |= XR_UART_PARITY_EVEN;
}
}
if (C_CSTOPB(tty))
- bits |= XR21V141X_UART_STOP_2;
+ bits |= XR_UART_STOP_2;
else
- bits |= XR21V141X_UART_STOP_1;
+ bits |= XR_UART_STOP_1;
ret = xr_set_reg_uart(port, XR21V141X_REG_FORMAT, bits);
if (ret)
return;
+}
+
+static void xr_cdc_set_line_coding(struct tty_struct *tty,
+ struct usb_serial_port *port, struct ktermios *old_termios)
+{
+ struct xr_data *data = usb_get_serial_port_data(port);
+ struct usb_host_interface *alt = port->serial->interface->cur_altsetting;
+ struct usb_device *udev = port->serial->dev;
+ struct usb_cdc_line_coding *lc;
+ int ret;
+
+ lc = kzalloc(sizeof(*lc), GFP_KERNEL);
+ if (!lc)
+ return;
+
+ if (tty->termios.c_ospeed)
+ lc->dwDTERate = cpu_to_le32(tty->termios.c_ospeed);
+ else if (old_termios)
+ lc->dwDTERate = cpu_to_le32(old_termios->c_ospeed);
+ else
+ lc->dwDTERate = cpu_to_le32(9600);
+
+ if (C_CSTOPB(tty))
+ lc->bCharFormat = USB_CDC_2_STOP_BITS;
+ else
+ lc->bCharFormat = USB_CDC_1_STOP_BITS;
+
+ if (C_PARENB(tty)) {
+ if (C_CMSPAR(tty)) {
+ if (C_PARODD(tty))
+ lc->bParityType = USB_CDC_MARK_PARITY;
+ else
+ lc->bParityType = USB_CDC_SPACE_PARITY;
+ } else {
+ if (C_PARODD(tty))
+ lc->bParityType = USB_CDC_ODD_PARITY;
+ else
+ lc->bParityType = USB_CDC_EVEN_PARITY;
+ }
+ } else {
+ lc->bParityType = USB_CDC_NO_PARITY;
+ }
+
+ if (!data->type->have_5_6_bit_mode &&
+ (C_CSIZE(tty) == CS5 || C_CSIZE(tty) == CS6)) {
+ tty->termios.c_cflag &= ~CSIZE;
+ if (old_termios)
+ tty->termios.c_cflag |= old_termios->c_cflag & CSIZE;
+ else
+ tty->termios.c_cflag |= CS8;
+ }
+
+ switch (C_CSIZE(tty)) {
+ case CS5:
+ lc->bDataBits = 5;
+ break;
+ case CS6:
+ lc->bDataBits = 6;
+ break;
+ case CS7:
+ lc->bDataBits = 7;
+ break;
+ case CS8:
+ default:
+ lc->bDataBits = 8;
+ break;
+ }
+
+ ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ USB_CDC_REQ_SET_LINE_CODING,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0, alt->desc.bInterfaceNumber,
+ lc, sizeof(*lc), USB_CTRL_SET_TIMEOUT);
+ if (ret < 0)
+ dev_err(&port->dev, "Failed to set line coding: %d\n", ret);
+
+ kfree(lc);
+}
+
+static void xr_set_termios(struct tty_struct *tty,
+ struct usb_serial_port *port, struct ktermios *old_termios)
+{
+ struct xr_data *data = usb_get_serial_port_data(port);
+
+ /*
+ * XR21V141X does not have a CUSTOM_DRIVER flag and always enters CDC
+ * mode upon receiving CDC requests.
+ */
+ if (data->type->set_line_settings)
+ data->type->set_line_settings(tty, port, old_termios);
+ else
+ xr_cdc_set_line_coding(tty, port, old_termios);
xr_set_flow_mode(tty, port, old_termios);
}
static int xr_open(struct tty_struct *tty, struct usb_serial_port *port)
{
- u8 gpio_dir;
int ret;
+ ret = xr_fifo_reset(port);
+ if (ret)
+ return ret;
+
ret = xr_uart_enable(port);
if (ret) {
dev_err(&port->dev, "Failed to enable UART\n");
return ret;
}
- /*
- * Configure DTR and RTS as outputs and RI, CD, DSR and CTS as
- * inputs.
- */
- gpio_dir = XR21V141X_UART_MODE_DTR | XR21V141X_UART_MODE_RTS;
- xr_set_reg_uart(port, XR21V141X_REG_GPIO_DIR, gpio_dir);
-
/* Setup termios */
if (tty)
xr_set_termios(tty, port, NULL);
@@ -545,15 +861,133 @@ static void xr_close(struct usb_serial_port *port)
static int xr_probe(struct usb_serial *serial, const struct usb_device_id *id)
{
- /* Don't bind to control interface */
- if (serial->interface->cur_altsetting->desc.bInterfaceNumber == 0)
+ struct usb_interface *control = serial->interface;
+ struct usb_host_interface *alt = control->cur_altsetting;
+ struct usb_cdc_parsed_header hdrs;
+ struct usb_cdc_union_desc *desc;
+ struct usb_interface *data;
+ int ret;
+
+ ret = cdc_parse_cdc_header(&hdrs, control, alt->extra, alt->extralen);
+ if (ret < 0)
+ return -ENODEV;
+
+ desc = hdrs.usb_cdc_union_desc;
+ if (!desc)
+ return -ENODEV;
+
+ data = usb_ifnum_to_if(serial->dev, desc->bSlaveInterface0);
+ if (!data)
return -ENODEV;
+ ret = usb_serial_claim_interface(serial, data);
+ if (ret)
+ return ret;
+
+ usb_set_serial_data(serial, (void *)id->driver_info);
+
+ return 0;
+}
+
+static int xr_gpio_init(struct usb_serial_port *port, const struct xr_type *type)
+{
+ u16 mask, mode;
+ int ret;
+
+ /*
+ * Configure all pins as GPIO except for Receive and Transmit Toggle.
+ */
+ mode = 0;
+ if (type->have_xmit_toggle)
+ mode |= XR_GPIO_MODE_RX_TOGGLE | XR_GPIO_MODE_TX_TOGGLE;
+
+ ret = xr_set_reg_uart(port, type->gpio_mode, mode);
+ if (ret)
+ return ret;
+
+ /*
+ * Configure DTR and RTS as outputs and make sure they are deasserted
+ * (active low), and configure RI, CD, DSR and CTS as inputs.
+ */
+ mask = XR_GPIO_DTR | XR_GPIO_RTS;
+ ret = xr_set_reg_uart(port, type->gpio_direction, mask);
+ if (ret)
+ return ret;
+
+ ret = xr_set_reg_uart(port, type->gpio_set, mask);
+ if (ret)
+ return ret;
+
return 0;
}
+static int xr_port_probe(struct usb_serial_port *port)
+{
+ struct usb_interface_descriptor *desc;
+ const struct xr_type *type;
+ struct xr_data *data;
+ enum xr_type_id type_id;
+ int ret;
+
+ type_id = (int)(unsigned long)usb_get_serial_data(port->serial);
+ type = &xr_types[type_id];
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->type = type;
+
+ desc = &port->serial->interface->cur_altsetting->desc;
+ if (type_id == XR21V141X)
+ data->channel = desc->bInterfaceNumber / 2;
+ else
+ data->channel = desc->bInterfaceNumber;
+
+ usb_set_serial_port_data(port, data);
+
+ if (type->custom_driver) {
+ ret = xr_set_reg_uart(port, type->custom_driver,
+ XR_CUSTOM_DRIVER_ACTIVE);
+ if (ret)
+ goto err_free;
+ }
+
+ ret = xr_gpio_init(port, type);
+ if (ret)
+ goto err_free;
+
+ return 0;
+
+err_free:
+ kfree(data);
+
+ return ret;
+}
+
+static void xr_port_remove(struct usb_serial_port *port)
+{
+ struct xr_data *data = usb_get_serial_port_data(port);
+
+ kfree(data);
+}
+
+#define XR_DEVICE(vid, pid, type) \
+ USB_DEVICE_INTERFACE_CLASS((vid), (pid), USB_CLASS_COMM), \
+ .driver_info = (type)
+
static const struct usb_device_id id_table[] = {
- { USB_DEVICE(0x04e2, 0x1410) }, /* XR21V141X */
+ { XR_DEVICE(0x04e2, 0x1400, XR2280X) },
+ { XR_DEVICE(0x04e2, 0x1401, XR2280X) },
+ { XR_DEVICE(0x04e2, 0x1402, XR2280X) },
+ { XR_DEVICE(0x04e2, 0x1403, XR2280X) },
+ { XR_DEVICE(0x04e2, 0x1410, XR21V141X) },
+ { XR_DEVICE(0x04e2, 0x1411, XR21B1411) },
+ { XR_DEVICE(0x04e2, 0x1412, XR21V141X) },
+ { XR_DEVICE(0x04e2, 0x1414, XR21V141X) },
+ { XR_DEVICE(0x04e2, 0x1420, XR21B142X) },
+ { XR_DEVICE(0x04e2, 0x1422, XR21B142X) },
+ { XR_DEVICE(0x04e2, 0x1424, XR21B142X) },
{ }
};
MODULE_DEVICE_TABLE(usb, id_table);
@@ -566,6 +1000,8 @@ static struct usb_serial_driver xr_device = {
.id_table = id_table,
.num_ports = 1,
.probe = xr_probe,
+ .port_probe = xr_port_probe,
+ .port_remove = xr_port_remove,
.open = xr_open,
.close = xr_close,
.break_ctl = xr_break_ctl,