Update Linux to v5.4.2
Change-Id: Idf6911045d9d382da2cfe01b1edff026404ac8fd
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index 533f127..67279c6 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
#
# USB Serial device configuration
#
@@ -10,7 +11,7 @@
ports, or acts like a serial device, and you want to connect it to
your USB bus.
- Please read <file:Documentation/usb/usb-serial.txt> for more
+ Please read <file:Documentation/usb/usb-serial.rst> for more
information on the specifics of the different devices that are
supported, and on how to use them.
@@ -46,7 +47,7 @@
bool "USB Generic Serial Driver"
help
Say Y here if you want to use the generic USB serial driver. Please
- read <file:Documentation/usb/usb-serial.txt> for more information on
+ read <file:Documentation/usb/usb-serial.rst> for more information on
using this driver. It is recommended that the "USB Serial converter
support" be compiled as a module for this driver to be used
properly.
@@ -162,7 +163,7 @@
help
Say Y here if you want to connect to your Empeg empeg-car Mark I/II
mp3 player via USB. The driver uses a single ttyUSB{0,1,2,...}
- device node. See <file:Documentation/usb/usb-serial.txt> for more
+ device node. See <file:Documentation/usb/usb-serial.rst> for more
tidbits of information.
To compile this driver as a module, choose M here: the
@@ -198,7 +199,7 @@
Say Y here if you want to connect to your Compaq iPAQ, HP Jornada
or any other PDA running Windows CE 3.0 or PocketPC 2002
using a USB cradle/cable. For information on using the driver,
- read <file:Documentation/usb/usb-serial.txt>.
+ read <file:Documentation/usb/usb-serial.rst>.
To compile this driver as a module, choose M here: the
module will be called ipaq.
@@ -333,7 +334,7 @@
adapter sold by Palm Inc. for use with their Palm III and Palm V
series PDAs.
- Please read <file:Documentation/usb/usb-serial.txt> for more
+ Please read <file:Documentation/usb/usb-serial.rst> for more
information.
To compile this driver as a module, choose M here: the
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
index 7796ad8..71a9206 100644
--- a/drivers/usb/serial/ark3116.c
+++ b/drivers/usb/serial/ark3116.c
@@ -189,16 +189,6 @@
return 0;
}
-static void ark3116_init_termios(struct tty_struct *tty)
-{
- struct ktermios *termios = &tty->termios;
- *termios = tty_std_termios;
- termios->c_cflag = B9600 | CS8
- | CREAD | HUPCL | CLOCAL;
- termios->c_ispeed = 9600;
- termios->c_ospeed = 9600;
-}
-
static void ark3116_set_termios(struct tty_struct *tty,
struct usb_serial_port *port,
struct ktermios *old_termios)
@@ -397,38 +387,16 @@
return result;
}
-static int ark3116_get_serial_info(struct usb_serial_port *port,
- struct serial_struct __user *retinfo)
-{
- struct serial_struct tmp;
-
- memset(&tmp, 0, sizeof(tmp));
-
- tmp.type = PORT_16654;
- tmp.line = port->minor;
- tmp.port = port->port_number;
- tmp.baud_base = 460800;
-
- if (copy_to_user(retinfo, &tmp, sizeof(tmp)))
- return -EFAULT;
-
- return 0;
-}
-
-static int ark3116_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
+static int ark3116_get_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss)
{
struct usb_serial_port *port = tty->driver_data;
- void __user *user_arg = (void __user *)arg;
- switch (cmd) {
- case TIOCGSERIAL:
- return ark3116_get_serial_info(port, user_arg);
- default:
- break;
- }
-
- return -ENOIOCTLCMD;
+ 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)
@@ -667,8 +635,7 @@
.port_probe = ark3116_port_probe,
.port_remove = ark3116_port_remove,
.set_termios = ark3116_set_termios,
- .init_termios = ark3116_init_termios,
- .ioctl = ark3116_ioctl,
+ .get_serial = ark3116_get_serial_info,
.tiocmget = ark3116_tiocmget,
.tiocmset = ark3116_tiocmset,
.tiocmiwait = usb_serial_generic_tiocmiwait,
diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
index c1235d5..9bb123a 100644
--- a/drivers/usb/serial/belkin_sa.c
+++ b/drivers/usb/serial/belkin_sa.c
@@ -10,7 +10,7 @@
* and associated source files. Please see the usb/serial files for
* individual credits and copyrights.
*
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
* driver
*
* TODO:
diff --git a/drivers/usb/serial/belkin_sa.h b/drivers/usb/serial/belkin_sa.h
index 51bc062..a13a98d 100644
--- a/drivers/usb/serial/belkin_sa.h
+++ b/drivers/usb/serial/belkin_sa.h
@@ -9,7 +9,7 @@
* and associated source files. Please see the usb/serial files for
* individual credits and copyrights.
*
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
* driver
*
* 12-Mar-2001 gkh
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index c0777a3..f5143ee 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -61,6 +61,7 @@
{ USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */
{ USB_DEVICE(0x08FD, 0x000A) }, /* Digianswer A/S , ZigBee/802.15.4 MAC Device */
{ USB_DEVICE(0x0908, 0x01FF) }, /* Siemens RUGGEDCOM USB Serial Console */
+ { USB_DEVICE(0x0B00, 0x3070) }, /* Ingenico 3070 */
{ USB_DEVICE(0x0BED, 0x1100) }, /* MEI (TM) Cashflow-SC Bill/Voucher Acceptor */
{ USB_DEVICE(0x0BED, 0x1101) }, /* MEI series 2000 Combo Acceptor */
{ USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */
@@ -79,6 +80,7 @@
{ USB_DEVICE(0x10C4, 0x804E) }, /* Software Bisque Paramount ME build-in converter */
{ USB_DEVICE(0x10C4, 0x8053) }, /* Enfora EDG1228 */
{ USB_DEVICE(0x10C4, 0x8054) }, /* Enfora GSM2228 */
+ { USB_DEVICE(0x10C4, 0x8056) }, /* Lorenz Messtechnik devices */
{ USB_DEVICE(0x10C4, 0x8066) }, /* Argussoft In-System Programmer */
{ USB_DEVICE(0x10C4, 0x806F) }, /* IMS USB to RS422 Converter Cable */
{ USB_DEVICE(0x10C4, 0x807A) }, /* Crumb128 board */
@@ -123,6 +125,7 @@
{ USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */
{ USB_DEVICE(0x10C4, 0x8382) }, /* Cygnal Integrated Products, Inc. */
{ USB_DEVICE(0x10C4, 0x83A8) }, /* Amber Wireless AMB2560 */
+ { USB_DEVICE(0x10C4, 0x83AA) }, /* Mark-10 Digital Force Gauge */
{ USB_DEVICE(0x10C4, 0x83D8) }, /* DekTec DTA Plus VHF/UHF Booster/Attenuator */
{ USB_DEVICE(0x10C4, 0x8411) }, /* Kyocera GPS Module */
{ USB_DEVICE(0x10C4, 0x8418) }, /* IRZ Automation Teleport SG-10 GSM/GPRS Modem */
@@ -245,6 +248,7 @@
u8 gpio_input;
#endif
u8 partnum;
+ speed_t min_speed;
speed_t max_speed;
bool use_actual_rate;
};
@@ -443,10 +447,10 @@
#define CP210X_PIN_MODE_GPIO BIT(0)
/*
- * CP210X_VENDOR_SPECIFIC, CP210X_GET_PORTCONFIG call reads these 0xf bytes.
- * Structure needs padding due to unused/unspecified bytes.
+ * CP210X_VENDOR_SPECIFIC, CP210X_GET_PORTCONFIG call reads these 0xf bytes
+ * on a CP2105 chip. Structure needs padding due to unused/unspecified bytes.
*/
-struct cp210x_config {
+struct cp210x_dual_port_config {
__le16 gpio_mode;
u8 __pad0[2];
__le16 reset_state;
@@ -457,6 +461,19 @@
u8 device_cfg;
} __packed;
+/*
+ * CP210X_VENDOR_SPECIFIC, CP210X_GET_PORTCONFIG call reads these 0xd bytes
+ * on a CP2104 chip. Structure needs padding due to unused/unspecified bytes.
+ */
+struct cp210x_single_port_config {
+ __le16 gpio_mode;
+ u8 __pad0[2];
+ __le16 reset_state;
+ u8 __pad1[4];
+ __le16 suspend_state;
+ u8 device_cfg;
+} __packed;
+
/* GPIO modes */
#define CP210X_SCI_GPIO_MODE_OFFSET 9
#define CP210X_SCI_GPIO_MODE_MASK GENMASK(11, 9)
@@ -464,11 +481,19 @@
#define CP210X_ECI_GPIO_MODE_OFFSET 2
#define CP210X_ECI_GPIO_MODE_MASK GENMASK(3, 2)
+#define CP210X_GPIO_MODE_OFFSET 8
+#define CP210X_GPIO_MODE_MASK GENMASK(11, 8)
+
/* CP2105 port configuration values */
#define CP2105_GPIO0_TXLED_MODE BIT(0)
#define CP2105_GPIO1_RXLED_MODE BIT(1)
#define CP2105_GPIO1_RS485_MODE BIT(2)
+/* CP2104 port configuration values */
+#define CP2104_GPIO0_TXLED_MODE BIT(0)
+#define CP2104_GPIO1_RXLED_MODE BIT(1)
+#define CP2104_GPIO2_RS485_MODE BIT(2)
+
/* CP2102N configuration array indices */
#define CP210X_2NCONFIG_CONFIG_VERSION_IDX 2
#define CP210X_2NCONFIG_GPIO_MODE_IDX 581
@@ -1051,14 +1076,11 @@
return cp210x_an205_table1[i].rate;
}
-static speed_t cp210x_get_actual_rate(struct usb_serial *serial, speed_t baud)
+static speed_t cp210x_get_actual_rate(speed_t baud)
{
- struct cp210x_serial_private *priv = usb_get_serial_data(serial);
unsigned int prescale = 1;
unsigned int div;
- baud = clamp(baud, 300u, priv->max_speed);
-
if (baud <= 365)
prescale = 4;
@@ -1101,20 +1123,18 @@
struct cp210x_serial_private *priv = usb_get_serial_data(serial);
u32 baud;
- baud = tty->termios.c_ospeed;
-
/*
* This maps the requested rate to the actual rate, a valid rate on
* cp2102 or cp2103, or to an arbitrary rate in [1M, max_speed].
*
* NOTE: B0 is not implemented.
*/
+ baud = clamp(tty->termios.c_ospeed, priv->min_speed, priv->max_speed);
+
if (priv->use_actual_rate)
- baud = cp210x_get_actual_rate(serial, baud);
+ baud = cp210x_get_actual_rate(baud);
else if (baud < 1000000)
baud = cp210x_get_an205_rate(baud);
- else if (baud > priv->max_speed)
- baud = priv->max_speed;
dev_dbg(&port->dev, "%s - setting baud rate to %u\n", __func__, baud);
if (cp210x_write_u32_reg(port, CP210X_SET_BAUDRATE, baud)) {
@@ -1353,8 +1373,13 @@
if (priv->partnum == CP210X_PARTNUM_CP2105)
req_type = REQTYPE_INTERFACE_TO_HOST;
+ result = usb_autopm_get_interface(serial->interface);
+ if (result)
+ return result;
+
result = cp210x_read_vendor_block(serial, req_type,
CP210X_READ_LATCH, &buf, sizeof(buf));
+ usb_autopm_put_interface(serial->interface);
if (result < 0)
return result;
@@ -1375,6 +1400,10 @@
buf.mask = BIT(gpio);
+ result = usb_autopm_get_interface(serial->interface);
+ if (result)
+ goto out;
+
if (priv->partnum == CP210X_PARTNUM_CP2105) {
result = cp210x_write_vendor_block(serial,
REQTYPE_HOST_TO_INTERFACE,
@@ -1392,6 +1421,8 @@
NULL, 0, USB_CTRL_SET_TIMEOUT);
}
+ usb_autopm_put_interface(serial->interface);
+out:
if (result < 0) {
dev_err(&serial->interface->dev, "failed to set GPIO value: %d\n",
result);
@@ -1470,7 +1501,7 @@
{
struct cp210x_serial_private *priv = usb_get_serial_data(serial);
struct cp210x_pin_mode mode;
- struct cp210x_config config;
+ struct cp210x_dual_port_config config;
u8 intf_num = cp210x_interface_num(serial);
u8 iface_config;
int result;
@@ -1529,6 +1560,56 @@
return 0;
}
+static int cp2104_gpioconf_init(struct usb_serial *serial)
+{
+ struct cp210x_serial_private *priv = usb_get_serial_data(serial);
+ struct cp210x_single_port_config config;
+ u8 iface_config;
+ u8 gpio_latch;
+ int result;
+ u8 i;
+
+ result = cp210x_read_vendor_block(serial, REQTYPE_DEVICE_TO_HOST,
+ CP210X_GET_PORTCONFIG, &config,
+ sizeof(config));
+ if (result < 0)
+ return result;
+
+ priv->gc.ngpio = 4;
+
+ iface_config = config.device_cfg;
+ priv->gpio_pushpull = (u8)((le16_to_cpu(config.gpio_mode) &
+ CP210X_GPIO_MODE_MASK) >>
+ CP210X_GPIO_MODE_OFFSET);
+ gpio_latch = (u8)((le16_to_cpu(config.reset_state) &
+ CP210X_GPIO_MODE_MASK) >>
+ CP210X_GPIO_MODE_OFFSET);
+
+ /* mark all pins which are not in GPIO mode */
+ if (iface_config & CP2104_GPIO0_TXLED_MODE) /* GPIO 0 */
+ priv->gpio_altfunc |= BIT(0);
+ if (iface_config & CP2104_GPIO1_RXLED_MODE) /* GPIO 1 */
+ priv->gpio_altfunc |= BIT(1);
+ if (iface_config & CP2104_GPIO2_RS485_MODE) /* GPIO 2 */
+ priv->gpio_altfunc |= BIT(2);
+
+ /*
+ * Like CP2102N, CP2104 has also no strict input and output pin
+ * modes.
+ * Do the same input mode emulation as CP2102N.
+ */
+ for (i = 0; i < priv->gc.ngpio; ++i) {
+ /*
+ * Set direction to "input" iff pin is open-drain and reset
+ * value is 1.
+ */
+ if (!(priv->gpio_pushpull & BIT(i)) && (gpio_latch & BIT(i)))
+ priv->gpio_input |= BIT(i);
+ }
+
+ return 0;
+}
+
static int cp2102n_gpioconf_init(struct usb_serial *serial)
{
struct cp210x_serial_private *priv = usb_get_serial_data(serial);
@@ -1574,12 +1655,6 @@
if (config_version != 0x01)
return -ENOTSUPP;
- /*
- * We only support 4 GPIOs even on the QFN28 package, because
- * config locations of GPIOs 4-6 determined using reverse
- * engineering revealed conflicting offsets with other
- * documented functions. So we'll just play it safe for now.
- */
priv->gc.ngpio = 4;
/*
@@ -1594,6 +1669,19 @@
/* 0 indicates GPIO mode, 1 is alternate function */
priv->gpio_altfunc = (gpio_ctrl >> 2) & 0x0f;
+ if (priv->partnum == CP210X_PARTNUM_CP2102N_QFN28) {
+ /*
+ * For the QFN28 package, GPIO4-6 are controlled by
+ * the low three bits of the mode/latch fields.
+ * Contrary to the document linked above, the bits for
+ * the SUSPEND pins are elsewhere. No alternate
+ * function is available for these pins.
+ */
+ priv->gc.ngpio = 7;
+ gpio_latch |= (gpio_rst_latch & 7) << 4;
+ priv->gpio_pushpull |= (gpio_pushpull & 7) << 4;
+ }
+
/*
* The CP2102N does not strictly has input and output pin modes,
* it only knows open-drain and push-pull modes which is set at
@@ -1620,6 +1708,9 @@
int result;
switch (priv->partnum) {
+ case CP210X_PARTNUM_CP2104:
+ result = cp2104_gpioconf_init(serial);
+ break;
case CP210X_PARTNUM_CP2105:
result = cp2105_gpioconf_init(serial);
break;
@@ -1716,6 +1807,7 @@
{
struct cp210x_serial_private *priv = usb_get_serial_data(serial);
bool use_actual_rate = false;
+ speed_t min = 300;
speed_t max;
switch (priv->partnum) {
@@ -1738,6 +1830,7 @@
use_actual_rate = true;
max = 2000000; /* ECI */
} else {
+ min = 2400;
max = 921600; /* SCI */
}
break;
@@ -1752,6 +1845,7 @@
break;
}
+ priv->min_speed = min;
priv->max_speed = max;
priv->use_actual_rate = use_actual_rate;
}
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index e0035c0..216edd5 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -7,7 +7,7 @@
* Copyright (C) 2003,2004
* Neil Whelchel (koyama@firstlight.net)
*
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
* driver
*
* See http://geocities.com/i0xox0i for information on this driver and the
@@ -98,7 +98,6 @@
int write_urb_interval; /* interval to use for write urb */
int read_urb_interval; /* interval to use for read urb */
int comm_is_ok; /* true if communication is (still) ok */
- int termios_initialized;
__u8 line_control; /* holds dtr / rts value */
__u8 current_status; /* received from last read - info on dsr,cts,cd,ri,etc */
__u8 current_config; /* stores the current configuration byte */
@@ -107,11 +106,7 @@
int get_cfg_unsafe; /* If true, the CYPRESS_GET_CONFIG is unsafe */
int baud_rate; /* stores current baud rate in
integer form */
- int isthrottled; /* if throttled, discard reads */
char prev_status; /* used for TIOCMIWAIT */
- /* we pass a pointer to this as the argument sent to
- cypress_set_termios old_termios */
- struct ktermios tmp_termios; /* stores the old termios settings */
};
/* function prototypes for the Cypress USB to serial device */
@@ -126,6 +121,7 @@
const unsigned char *buf, int count);
static void cypress_send(struct usb_serial_port *port);
static int cypress_write_room(struct tty_struct *tty);
+static void cypress_earthmate_init_termios(struct tty_struct *tty);
static void cypress_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old);
static int cypress_tiocmget(struct tty_struct *tty);
@@ -153,6 +149,7 @@
.dtr_rts = cypress_dtr_rts,
.write = cypress_write,
.write_room = cypress_write_room,
+ .init_termios = cypress_earthmate_init_termios,
.set_termios = cypress_set_termios,
.tiocmget = cypress_tiocmget,
.tiocmset = cypress_tiocmset,
@@ -378,7 +375,7 @@
retval = -ENOTTY;
goto out;
}
- dev_dbg(dev, "%s - retreiving serial line settings\n", __func__);
+ dev_dbg(dev, "%s - retrieving serial line settings\n", __func__);
do {
retval = usb_control_msg(port->serial->dev,
usb_rcvctrlpipe(port->serial->dev, 0),
@@ -467,7 +464,6 @@
priv->cmd_ctrl = 0;
priv->line_control = 0;
- priv->termios_initialized = 0;
priv->rx_flags = 0;
/* Default packet format setting is determined by packet size.
Anything with a size larger then 9 must have a separate
@@ -604,7 +600,7 @@
cypress_send(port);
if (tty)
- cypress_set_termios(tty, port, &priv->tmp_termios);
+ cypress_set_termios(tty, port, NULL);
/* setup the port and start reading from the device */
usb_fill_int_urb(port->interrupt_in_urb, serial->dev,
@@ -769,7 +765,7 @@
usb_fill_int_urb(port->interrupt_out_urb, port->serial->dev,
usb_sndintpipe(port->serial->dev, port->interrupt_out_endpointAddress),
- port->interrupt_out_buffer, port->interrupt_out_size,
+ port->interrupt_out_buffer, actual_size,
cypress_write_int_callback, port, priv->write_urb_interval);
result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC);
if (result) {
@@ -857,56 +853,26 @@
return cypress_write(tty, port, NULL, 0);
}
+static void cypress_earthmate_init_termios(struct tty_struct *tty)
+{
+ tty_encode_baud_rate(tty, 4800, 4800);
+}
+
static void cypress_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios)
{
struct cypress_private *priv = usb_get_serial_port_data(port);
struct device *dev = &port->dev;
int data_bits, stop_bits, parity_type, parity_enable;
- unsigned cflag, iflag;
+ unsigned int cflag;
unsigned long flags;
__u8 oldlines;
int linechange = 0;
- spin_lock_irqsave(&priv->lock, flags);
- /* We can't clean this one up as we don't know the device type
- early enough */
- if (!priv->termios_initialized) {
- if (priv->chiptype == CT_EARTHMATE) {
- tty->termios = tty_std_termios;
- tty->termios.c_cflag = B4800 | CS8 | CREAD | HUPCL |
- CLOCAL;
- tty->termios.c_ispeed = 4800;
- tty->termios.c_ospeed = 4800;
- } else if (priv->chiptype == CT_CYPHIDCOM) {
- tty->termios = tty_std_termios;
- tty->termios.c_cflag = B9600 | CS8 | CREAD | HUPCL |
- CLOCAL;
- tty->termios.c_ispeed = 9600;
- tty->termios.c_ospeed = 9600;
- } else if (priv->chiptype == CT_CA42V2) {
- tty->termios = tty_std_termios;
- tty->termios.c_cflag = B9600 | CS8 | CREAD | HUPCL |
- CLOCAL;
- tty->termios.c_ispeed = 9600;
- tty->termios.c_ospeed = 9600;
- }
- priv->termios_initialized = 1;
- }
- spin_unlock_irqrestore(&priv->lock, flags);
-
/* Unsupported features need clearing */
tty->termios.c_cflag &= ~(CMSPAR|CRTSCTS);
cflag = tty->termios.c_cflag;
- iflag = tty->termios.c_iflag;
-
- /* check if there are new settings */
- if (old_termios) {
- spin_lock_irqsave(&priv->lock, flags);
- priv->tmp_termios = tty->termios;
- spin_unlock_irqrestore(&priv->lock, flags);
- }
/* set number of data bits, parity, stop bits */
/* when parity is disabled the parity type bit is ignored */
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index e7f244c..578ebdd 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -569,9 +569,9 @@
ret = usb_submit_urb(oob_port->write_urb, GFP_ATOMIC);
if (ret == 0) {
oob_priv->dp_write_urb_in_use = 1;
- port_priv->dp_modem_signals =
- (port_priv->dp_modem_signals&~(TIOCM_DTR|TIOCM_RTS))
- | (modem_signals&(TIOCM_DTR|TIOCM_RTS));
+ port_priv->dp_modem_signals &= ~(TIOCM_DTR | TIOCM_RTS);
+ port_priv->dp_modem_signals |=
+ modem_signals & (TIOCM_DTR | TIOCM_RTS);
}
spin_unlock(&port_priv->dp_port_lock);
spin_unlock_irqrestore(&oob_priv->dp_port_lock, flags);
@@ -740,9 +740,9 @@
/* set parity */
tty->termios.c_cflag &= ~CMSPAR;
- if ((cflag&(PARENB|PARODD)) != (old_cflag&(PARENB|PARODD))) {
- if (cflag&PARENB) {
- if (cflag&PARODD)
+ if ((cflag & (PARENB | PARODD)) != (old_cflag & (PARENB | PARODD))) {
+ if (cflag & PARENB) {
+ if (cflag & PARODD)
arg = DIGI_PARITY_ODD;
else
arg = DIGI_PARITY_EVEN;
@@ -755,9 +755,9 @@
buf[i++] = 0;
}
/* set word size */
- if ((cflag&CSIZE) != (old_cflag&CSIZE)) {
+ if ((cflag & CSIZE) != (old_cflag & CSIZE)) {
arg = -1;
- switch (cflag&CSIZE) {
+ switch (cflag & CSIZE) {
case CS5: arg = DIGI_WORD_SIZE_5; break;
case CS6: arg = DIGI_WORD_SIZE_6; break;
case CS7: arg = DIGI_WORD_SIZE_7; break;
@@ -765,7 +765,7 @@
default:
dev_dbg(dev,
"digi_set_termios: can't handle word size %d\n",
- (cflag&CSIZE));
+ cflag & CSIZE);
break;
}
@@ -779,9 +779,9 @@
}
/* set stop bits */
- if ((cflag&CSTOPB) != (old_cflag&CSTOPB)) {
+ if ((cflag & CSTOPB) != (old_cflag & CSTOPB)) {
- if ((cflag&CSTOPB))
+ if ((cflag & CSTOPB))
arg = DIGI_STOP_BITS_2;
else
arg = DIGI_STOP_BITS_1;
@@ -794,15 +794,15 @@
}
/* set input flow control */
- if ((iflag&IXOFF) != (old_iflag&IXOFF)
- || (cflag&CRTSCTS) != (old_cflag&CRTSCTS)) {
+ if ((iflag & IXOFF) != (old_iflag & IXOFF) ||
+ (cflag & CRTSCTS) != (old_cflag & CRTSCTS)) {
arg = 0;
- if (iflag&IXOFF)
+ if (iflag & IXOFF)
arg |= DIGI_INPUT_FLOW_CONTROL_XON_XOFF;
else
arg &= ~DIGI_INPUT_FLOW_CONTROL_XON_XOFF;
- if (cflag&CRTSCTS) {
+ if (cflag & CRTSCTS) {
arg |= DIGI_INPUT_FLOW_CONTROL_RTS;
/* On USB-4 it is necessary to assert RTS prior */
@@ -822,19 +822,18 @@
}
/* set output flow control */
- if ((iflag & IXON) != (old_iflag & IXON)
- || (cflag & CRTSCTS) != (old_cflag & CRTSCTS)) {
+ if ((iflag & IXON) != (old_iflag & IXON) ||
+ (cflag & CRTSCTS) != (old_cflag & CRTSCTS)) {
arg = 0;
if (iflag & IXON)
arg |= DIGI_OUTPUT_FLOW_CONTROL_XON_XOFF;
else
arg &= ~DIGI_OUTPUT_FLOW_CONTROL_XON_XOFF;
- if (cflag & CRTSCTS) {
+ if (cflag & CRTSCTS)
arg |= DIGI_OUTPUT_FLOW_CONTROL_CTS;
- } else {
+ else
arg &= ~DIGI_OUTPUT_FLOW_CONTROL_CTS;
- }
buf[i++] = DIGI_CMD_SET_OUTPUT_FLOW_CONTROL;
buf[i++] = priv->dp_port_num;
@@ -1084,7 +1083,7 @@
static void digi_dtr_rts(struct usb_serial_port *port, int on)
{
/* Adjust DTR and RTS */
- digi_set_modem_signals(port, on * (TIOCM_DTR|TIOCM_RTS), 1);
+ digi_set_modem_signals(port, on * (TIOCM_DTR | TIOCM_RTS), 1);
}
static int digi_open(struct tty_struct *tty, struct usb_serial_port *port)
diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c
index d680bec..405e835 100644
--- a/drivers/usb/serial/empeg.c
+++ b/drivers/usb/serial/empeg.c
@@ -8,7 +8,7 @@
* Copyright (C) 1999 - 2001
* Greg Kroah-Hartman (greg@kroah.com)
*
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
* driver
*/
diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 96036f8..43fa1f0 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -28,7 +28,8 @@
MODULE_DEVICE_TABLE(usb, id_table);
/* Maximum baudrate for F81232 */
-#define F81232_MAX_BAUDRATE 115200
+#define F81232_MAX_BAUDRATE 1500000
+#define F81232_DEF_BAUDRATE 9600
/* USB Control EP parameter */
#define F81232_REGISTER_REQUEST 0xa0
@@ -41,19 +42,46 @@
#define FIFO_CONTROL_REGISTER (0x02 + SERIAL_BASE_ADDRESS)
#define LINE_CONTROL_REGISTER (0x03 + SERIAL_BASE_ADDRESS)
#define MODEM_CONTROL_REGISTER (0x04 + SERIAL_BASE_ADDRESS)
+#define LINE_STATUS_REGISTER (0x05 + SERIAL_BASE_ADDRESS)
#define MODEM_STATUS_REGISTER (0x06 + SERIAL_BASE_ADDRESS)
+/*
+ * F81232 Clock registers (106h)
+ *
+ * Bit1-0: Clock source selector
+ * 00: 1.846MHz.
+ * 01: 18.46MHz.
+ * 10: 24MHz.
+ * 11: 14.77MHz.
+ */
+#define F81232_CLK_REGISTER 0x106
+#define F81232_CLK_1_846_MHZ 0
+#define F81232_CLK_18_46_MHZ BIT(0)
+#define F81232_CLK_24_MHZ BIT(1)
+#define F81232_CLK_14_77_MHZ (BIT(1) | BIT(0))
+#define F81232_CLK_MASK GENMASK(1, 0)
+
struct f81232_private {
struct mutex lock;
u8 modem_control;
u8 modem_status;
+ u8 shadow_lcr;
+ speed_t baud_base;
+ struct work_struct lsr_work;
struct work_struct interrupt_work;
struct usb_serial_port *port;
};
-static int calc_baud_divisor(speed_t baudrate)
+static u32 const baudrate_table[] = { 115200, 921600, 1152000, 1500000 };
+static u8 const clock_table[] = { F81232_CLK_1_846_MHZ, F81232_CLK_14_77_MHZ,
+ F81232_CLK_18_46_MHZ, F81232_CLK_24_MHZ };
+
+static int calc_baud_divisor(speed_t baudrate, speed_t clockrate)
{
- return DIV_ROUND_CLOSEST(F81232_MAX_BAUDRATE, baudrate);
+ if (!baudrate)
+ return 0;
+
+ return DIV_ROUND_CLOSEST(clockrate, baudrate);
}
static int f81232_get_register(struct usb_serial_port *port, u16 reg, u8 *val)
@@ -127,6 +155,21 @@
return status;
}
+static int f81232_set_mask_register(struct usb_serial_port *port, u16 reg,
+ u8 mask, u8 val)
+{
+ int status;
+ u8 tmp;
+
+ status = f81232_get_register(port, reg, &tmp);
+ if (status)
+ return status;
+
+ tmp = (tmp & ~mask) | (val & mask);
+
+ return f81232_set_register(port, reg, tmp);
+}
+
static void f81232_read_msr(struct usb_serial_port *port)
{
int status;
@@ -282,6 +325,7 @@
static void f81232_process_read_urb(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
+ struct f81232_private *priv = usb_get_serial_port_data(port);
unsigned char *data = urb->transfer_buffer;
char tty_flag;
unsigned int i;
@@ -315,6 +359,7 @@
if (lsr & UART_LSR_OE) {
port->icount.overrun++;
+ schedule_work(&priv->lsr_work);
tty_insert_flip_char(&port->port, 0,
TTY_OVERRUN);
}
@@ -333,22 +378,72 @@
static void f81232_break_ctl(struct tty_struct *tty, int break_state)
{
- /* FIXME - Stubbed out for now */
+ struct usb_serial_port *port = tty->driver_data;
+ struct f81232_private *priv = usb_get_serial_port_data(port);
+ int status;
- /*
- * break_state = -1 to turn on break, and 0 to turn off break
- * see drivers/char/tty_io.c to see it used.
- * last_set_data_urb_value NEVER has the break bit set in it.
- */
+ mutex_lock(&priv->lock);
+
+ if (break_state)
+ priv->shadow_lcr |= UART_LCR_SBC;
+ else
+ priv->shadow_lcr &= ~UART_LCR_SBC;
+
+ status = f81232_set_register(port, LINE_CONTROL_REGISTER,
+ priv->shadow_lcr);
+ if (status)
+ dev_err(&port->dev, "set break failed: %d\n", status);
+
+ mutex_unlock(&priv->lock);
}
-static void f81232_set_baudrate(struct usb_serial_port *port, speed_t baudrate)
+static int f81232_find_clk(speed_t baudrate)
{
+ int idx;
+
+ for (idx = 0; idx < ARRAY_SIZE(baudrate_table); ++idx) {
+ if (baudrate <= baudrate_table[idx] &&
+ baudrate_table[idx] % baudrate == 0)
+ return idx;
+ }
+
+ return -EINVAL;
+}
+
+static void f81232_set_baudrate(struct tty_struct *tty,
+ struct usb_serial_port *port, speed_t baudrate,
+ speed_t old_baudrate)
+{
+ struct f81232_private *priv = usb_get_serial_port_data(port);
u8 lcr;
int divisor;
int status = 0;
+ int i;
+ int idx;
+ speed_t baud_list[] = { baudrate, old_baudrate, F81232_DEF_BAUDRATE };
- divisor = calc_baud_divisor(baudrate);
+ for (i = 0; i < ARRAY_SIZE(baud_list); ++i) {
+ idx = f81232_find_clk(baud_list[i]);
+ if (idx >= 0) {
+ baudrate = baud_list[i];
+ tty_encode_baud_rate(tty, baudrate, baudrate);
+ break;
+ }
+ }
+
+ if (idx < 0)
+ return;
+
+ priv->baud_base = baudrate_table[idx];
+ divisor = calc_baud_divisor(baudrate, priv->baud_base);
+
+ status = f81232_set_mask_register(port, F81232_CLK_REGISTER,
+ F81232_CLK_MASK, clock_table[idx]);
+ if (status) {
+ dev_err(&port->dev, "%s failed to set CLK_REG: %d\n",
+ __func__, status);
+ return;
+ }
status = f81232_get_register(port, LINE_CONTROL_REGISTER,
&lcr); /* get LCR */
@@ -435,9 +530,11 @@
static void f81232_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios)
{
+ struct f81232_private *priv = usb_get_serial_port_data(port);
u8 new_lcr = 0;
int status = 0;
speed_t baudrate;
+ speed_t old_baud;
/* Don't change anything if nothing has changed */
if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios))
@@ -450,11 +547,12 @@
baudrate = tty_get_baud_rate(tty);
if (baudrate > 0) {
- if (baudrate > F81232_MAX_BAUDRATE) {
- baudrate = F81232_MAX_BAUDRATE;
- tty_encode_baud_rate(tty, baudrate, baudrate);
- }
- f81232_set_baudrate(port, baudrate);
+ if (old_termios)
+ old_baud = tty_termios_baud_rate(old_termios);
+ else
+ old_baud = F81232_DEF_BAUDRATE;
+
+ f81232_set_baudrate(tty, port, baudrate, old_baud);
}
if (C_PARENB(tty)) {
@@ -486,11 +584,18 @@
break;
}
+ mutex_lock(&priv->lock);
+
+ new_lcr |= (priv->shadow_lcr & UART_LCR_SBC);
status = f81232_set_register(port, LINE_CONTROL_REGISTER, new_lcr);
if (status) {
dev_err(&port->dev, "%s failed to set LCR: %d\n",
__func__, status);
}
+
+ priv->shadow_lcr = new_lcr;
+
+ mutex_unlock(&priv->lock);
}
static int f81232_tiocmget(struct tty_struct *tty)
@@ -556,9 +661,13 @@
static void f81232_close(struct usb_serial_port *port)
{
+ struct f81232_private *port_priv = usb_get_serial_port_data(port);
+
f81232_port_disable(port);
usb_serial_generic_close(port);
usb_kill_urb(port->interrupt_in_urb);
+ flush_work(&port_priv->interrupt_work);
+ flush_work(&port_priv->lsr_work);
}
static void f81232_dtr_rts(struct usb_serial_port *port, int on)
@@ -583,36 +692,17 @@
return 0;
}
-static int f81232_get_serial_info(struct usb_serial_port *port,
- unsigned long arg)
-{
- struct serial_struct ser;
-
- memset(&ser, 0, sizeof(ser));
-
- ser.type = PORT_16550A;
- ser.line = port->minor;
- ser.port = port->port_number;
- ser.baud_base = F81232_MAX_BAUDRATE;
-
- if (copy_to_user((void __user *)arg, &ser, sizeof(ser)))
- return -EFAULT;
-
- return 0;
-}
-
-static int f81232_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
+static int f81232_get_serial_info(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);
- switch (cmd) {
- case TIOCGSERIAL:
- return f81232_get_serial_info(port, arg);
- default:
- break;
- }
- return -ENOIOCTLCMD;
+ 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)
@@ -623,6 +713,21 @@
f81232_read_msr(priv->port);
}
+static void f81232_lsr_worker(struct work_struct *work)
+{
+ struct f81232_private *priv;
+ struct usb_serial_port *port;
+ int status;
+ u8 tmp;
+
+ priv = container_of(work, struct f81232_private, lsr_work);
+ port = priv->port;
+
+ status = f81232_get_register(port, LINE_STATUS_REGISTER, &tmp);
+ if (status)
+ dev_warn(&port->dev, "read LSR failed: %d\n", status);
+}
+
static int f81232_port_probe(struct usb_serial_port *port)
{
struct f81232_private *priv;
@@ -633,6 +738,7 @@
mutex_init(&priv->lock);
INIT_WORK(&priv->interrupt_work, f81232_interrupt_work);
+ INIT_WORK(&priv->lsr_work, f81232_lsr_worker);
usb_set_serial_port_data(port, priv);
@@ -652,6 +758,42 @@
return 0;
}
+static int f81232_suspend(struct usb_serial *serial, pm_message_t message)
+{
+ struct usb_serial_port *port = serial->port[0];
+ struct f81232_private *port_priv = usb_get_serial_port_data(port);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i)
+ usb_kill_urb(port->read_urbs[i]);
+
+ usb_kill_urb(port->interrupt_in_urb);
+
+ if (port_priv) {
+ flush_work(&port_priv->interrupt_work);
+ flush_work(&port_priv->lsr_work);
+ }
+
+ return 0;
+}
+
+static int f81232_resume(struct usb_serial *serial)
+{
+ struct usb_serial_port *port = serial->port[0];
+ int result;
+
+ if (tty_port_initialized(&port->port)) {
+ result = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO);
+ if (result) {
+ dev_err(&port->dev, "submit interrupt urb failed: %d\n",
+ result);
+ return result;
+ }
+ }
+
+ return usb_serial_generic_resume(serial);
+}
+
static struct usb_serial_driver f81232_device = {
.driver = {
.owner = THIS_MODULE,
@@ -665,7 +807,7 @@
.close = f81232_close,
.dtr_rts = f81232_dtr_rts,
.carrier_raised = f81232_carrier_raised,
- .ioctl = f81232_ioctl,
+ .get_serial = f81232_get_serial_info,
.break_ctl = f81232_break_ctl,
.set_termios = f81232_set_termios,
.tiocmget = f81232_tiocmget,
@@ -675,6 +817,8 @@
.read_int_callback = f81232_read_int_callback,
.port_probe = f81232_port_probe,
.port_remove = f81232_port_remove,
+ .suspend = f81232_suspend,
+ .resume = f81232_resume,
};
static struct usb_serial_driver * const serial_drivers[] = {
diff --git a/drivers/usb/serial/f81534.c b/drivers/usb/serial/f81534.c
index 4dfbff2..2b39bda 100644
--- a/drivers/usb/serial/f81534.c
+++ b/drivers/usb/serial/f81534.c
@@ -45,14 +45,17 @@
#define F81534_CONFIG1_REG (0x09 + F81534_UART_BASE_ADDRESS)
#define F81534_DEF_CONF_ADDRESS_START 0x3000
-#define F81534_DEF_CONF_SIZE 8
+#define F81534_DEF_CONF_SIZE 12
#define F81534_CUSTOM_ADDRESS_START 0x2f00
#define F81534_CUSTOM_DATA_SIZE 0x10
#define F81534_CUSTOM_NO_CUSTOM_DATA 0xff
#define F81534_CUSTOM_VALID_TOKEN 0xf0
#define F81534_CONF_OFFSET 1
-#define F81534_CONF_GPIO_OFFSET 4
+#define F81534_CONF_INIT_GPIO_OFFSET 4
+#define F81534_CONF_WORK_GPIO_OFFSET 8
+#define F81534_CONF_GPIO_SHUTDOWN 7
+#define F81534_CONF_GPIO_RS232 1
#define F81534_MAX_DATA_BLOCK 64
#define F81534_MAX_BUS_RETRY 20
@@ -1139,43 +1142,21 @@
mutex_unlock(&serial_priv->urb_mutex);
}
-static int f81534_get_serial_info(struct usb_serial_port *port,
- struct serial_struct __user *retinfo)
+static int 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;
- struct serial_struct tmp;
port_priv = usb_get_serial_port_data(port);
- memset(&tmp, 0, sizeof(tmp));
-
- tmp.type = PORT_16550A;
- tmp.port = port->port_number;
- tmp.line = port->minor;
- tmp.baud_base = port_priv->baud_base;
-
- if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
- return -EFAULT;
-
+ ss->type = PORT_16550A;
+ ss->port = port->port_number;
+ ss->line = port->minor;
+ ss->baud_base = port_priv->baud_base;
return 0;
}
-static int f81534_ioctl(struct tty_struct *tty, unsigned int cmd,
- unsigned long arg)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct serial_struct __user *buf = (struct serial_struct __user *)arg;
-
- switch (cmd) {
- case TIOCGSERIAL:
- return f81534_get_serial_info(port, buf);
- default:
- break;
- }
-
- return -ENOIOCTLCMD;
-}
-
static void f81534_process_per_serial_block(struct usb_serial_port *port,
u8 *data)
{
@@ -1359,8 +1340,19 @@
serial_priv = usb_get_serial_data(serial);
port_priv = usb_get_serial_port_data(port);
- idx = F81534_CONF_GPIO_OFFSET + port_priv->phy_num;
+ idx = F81534_CONF_INIT_GPIO_OFFSET + port_priv->phy_num;
value = serial_priv->conf_data[idx];
+ if (value >= F81534_CONF_GPIO_SHUTDOWN) {
+ /*
+ * Newer IC configure will make transceiver in shutdown mode on
+ * initial power on. We need enable it before using UARTs.
+ */
+ idx = F81534_CONF_WORK_GPIO_OFFSET + port_priv->phy_num;
+ value = serial_priv->conf_data[idx];
+ if (value >= F81534_CONF_GPIO_SHUTDOWN)
+ value = F81534_CONF_GPIO_RS232;
+ }
+
pins = &f81534_port_out_pins[port_priv->phy_num];
for (i = 0; i < ARRAY_SIZE(pins->pin); ++i) {
@@ -1581,7 +1573,7 @@
.break_ctl = f81534_break_ctl,
.dtr_rts = f81534_dtr_rts,
.process_read_urb = f81534_process_read_urb,
- .ioctl = f81534_ioctl,
+ .get_serial = f81534_get_serial_info,
.tiocmget = f81534_tiocmget,
.tiocmset = f81534_tiocmset,
.write_bulk_callback = f81534_write_usb_callback,
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index b5cef32..9ad44a9 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -10,7 +10,7 @@
* Copyright (C) 2002
* Kuba Ober (kuba@mareimbrium.org)
*
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
* driver
*
* See http://ftdi-usb-sio.sourceforge.net for up to date testing info
@@ -39,6 +39,7 @@
#include <linux/uaccess.h>
#include <linux/usb.h>
#include <linux/serial.h>
+#include <linux/gpio/driver.h>
#include <linux/usb/serial.h>
#include "ftdi_sio.h"
#include "ftdi_sio_ids.h"
@@ -72,6 +73,15 @@
unsigned int latency; /* latency setting in use */
unsigned short max_packet_size;
struct mutex cfg_lock; /* Avoid mess by parallel calls of config ioctl() and change_speed() */
+#ifdef CONFIG_GPIOLIB
+ struct gpio_chip gc;
+ struct mutex gpio_lock; /* protects GPIO state */
+ bool gpio_registered; /* is the gpiochip in kernel registered */
+ bool gpio_used; /* true if the user requested a gpio */
+ u8 gpio_altfunc; /* which pins are in gpio mode */
+ u8 gpio_output; /* pin directions cache */
+ u8 gpio_value; /* pin value for outputs */
+#endif
};
/* struct ftdi_sio_quirk is used by devices requiring special attention. */
@@ -599,6 +609,8 @@
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
{ USB_DEVICE(FTDI_VID, FTDI_NT_ORIONLXM_PID),
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+ { USB_DEVICE(FTDI_VID, FTDI_NT_ORIONLX_PLUS_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_NT_ORION_IO_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_SYNAPSE_SS200_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CUSTOMWARE_MINIPLEX_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CUSTOMWARE_MINIPLEX2_PID) },
@@ -1015,6 +1027,15 @@
{ USB_DEVICE(CYPRESS_VID, CYPRESS_WICED_BT_USB_PID) },
{ USB_DEVICE(CYPRESS_VID, CYPRESS_WICED_WL_USB_PID) },
{ USB_DEVICE(AIRBUS_DS_VID, AIRBUS_DS_P8GR) },
+ /* EZPrototypes devices */
+ { USB_DEVICE(EZPROTOTYPES_VID, HJELMSLUND_USB485_ISO_PID) },
+ { USB_DEVICE_INTERFACE_NUMBER(UNJO_VID, UNJO_ISODEBUG_V1_PID, 1) },
+ /* Sienna devices */
+ { USB_DEVICE(FTDI_VID, FTDI_SIENNA_PID) },
+ { USB_DEVICE(ECHELON_VID, ECHELON_U20_PID) },
+ /* U-Blox devices */
+ { USB_DEVICE(UBLOX_VID, UBLOX_C099F9P_ZED_PID) },
+ { USB_DEVICE(UBLOX_VID, UBLOX_C099F9P_ODIN_PID) },
{ } /* Terminating entry */
};
@@ -1055,6 +1076,10 @@
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 int set_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss);
static void ftdi_break_ctl(struct tty_struct *tty, int break_state);
static bool ftdi_tx_empty(struct usb_serial_port *port);
static int ftdi_get_modem_status(struct usb_serial_port *port,
@@ -1091,6 +1116,8 @@
.tiocmiwait = usb_serial_generic_tiocmiwait,
.get_icount = usb_serial_generic_get_icount,
.ioctl = ftdi_ioctl,
+ .get_serial = get_serial_info,
+ .set_serial = set_serial_info,
.set_termios = ftdi_set_termios,
.break_ctl = ftdi_break_ctl,
.tx_empty = ftdi_tx_empty,
@@ -1114,7 +1141,7 @@
{
unsigned short int divisor;
/* divisor shifted 3 bits to the left */
- int divisor3 = base / 2 / baud;
+ int divisor3 = DIV_ROUND_CLOSEST(base, 2 * baud);
if ((divisor3 & 0x7) == 7)
divisor3++; /* round x.7/8 up to x+1 */
divisor = divisor3 >> 3;
@@ -1140,7 +1167,7 @@
static const unsigned char divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 };
u32 divisor;
/* divisor shifted 3 bits to the left */
- int divisor3 = base / 2 / baud;
+ int divisor3 = DIV_ROUND_CLOSEST(base, 2 * baud);
divisor = divisor3 >> 3;
divisor |= (u32)divfrac[divisor3 & 0x7] << 14;
/* Deal with special cases for highest baud rates. */
@@ -1163,7 +1190,7 @@
int divisor3;
/* hi-speed baud rate is 10-bit sampling instead of 16-bit */
- divisor3 = base * 8 / (baud * 10);
+ divisor3 = DIV_ROUND_CLOSEST(8 * base, 10 * baud);
divisor = divisor3 >> 3;
divisor |= (u32)divfrac[divisor3 & 0x7] << 14;
@@ -1443,48 +1470,42 @@
return 0;
}
-static int get_serial_info(struct usb_serial_port *port,
- struct serial_struct __user *retinfo)
+static int 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);
- struct serial_struct tmp;
- memset(&tmp, 0, sizeof(tmp));
- tmp.flags = priv->flags;
- tmp.baud_base = priv->baud_base;
- tmp.custom_divisor = priv->custom_divisor;
- if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
- return -EFAULT;
+ 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 usb_serial_port *port, struct serial_struct __user *newinfo)
+ struct serial_struct *ss)
{
+ struct usb_serial_port *port = tty->driver_data;
struct ftdi_private *priv = usb_get_serial_port_data(port);
- struct serial_struct new_serial;
struct ftdi_private old_priv;
- if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
- return -EFAULT;
-
mutex_lock(&priv->cfg_lock);
old_priv = *priv;
/* Do error checking and permission checking */
if (!capable(CAP_SYS_ADMIN)) {
- if ((new_serial.flags ^ priv->flags) & ~ASYNC_USR_MASK) {
+ if ((ss->flags ^ priv->flags) & ~ASYNC_USR_MASK) {
mutex_unlock(&priv->cfg_lock);
return -EPERM;
}
priv->flags = ((priv->flags & ~ASYNC_USR_MASK) |
- (new_serial.flags & ASYNC_USR_MASK));
- priv->custom_divisor = new_serial.custom_divisor;
+ (ss->flags & ASYNC_USR_MASK));
+ priv->custom_divisor = ss->custom_divisor;
goto check_and_exit;
}
- if (new_serial.baud_base != priv->baud_base) {
+ if (ss->baud_base != priv->baud_base) {
mutex_unlock(&priv->cfg_lock);
return -EINVAL;
}
@@ -1492,8 +1513,8 @@
/* Make the changes - these are privileged changes! */
priv->flags = ((priv->flags & ~ASYNC_FLAGS) |
- (new_serial.flags & ASYNC_FLAGS));
- priv->custom_divisor = new_serial.custom_divisor;
+ (ss->flags & ASYNC_FLAGS));
+ priv->custom_divisor = ss->custom_divisor;
check_and_exit:
write_latency_timer(port);
@@ -1507,10 +1528,8 @@
dev_warn_ratelimited(&port->dev, "use of SPD flags is deprecated\n");
change_speed(tty, port);
- mutex_unlock(&priv->cfg_lock);
}
- else
- mutex_unlock(&priv->cfg_lock);
+ mutex_unlock(&priv->cfg_lock);
return 0;
}
@@ -1766,6 +1785,431 @@
}
+#ifdef CONFIG_GPIOLIB
+
+static int ftdi_set_bitmode(struct usb_serial_port *port, u8 mode)
+{
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+ struct usb_serial *serial = port->serial;
+ int result;
+ u16 val;
+
+ result = usb_autopm_get_interface(serial->interface);
+ if (result)
+ return result;
+
+ val = (mode << 8) | (priv->gpio_output << 4) | priv->gpio_value;
+ result = usb_control_msg(serial->dev,
+ usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_BITMODE_REQUEST,
+ FTDI_SIO_SET_BITMODE_REQUEST_TYPE, val,
+ priv->interface, NULL, 0, WDR_TIMEOUT);
+ if (result < 0) {
+ dev_err(&serial->interface->dev,
+ "bitmode request failed for value 0x%04x: %d\n",
+ val, result);
+ }
+
+ usb_autopm_put_interface(serial->interface);
+
+ return result;
+}
+
+static int ftdi_set_cbus_pins(struct usb_serial_port *port)
+{
+ return ftdi_set_bitmode(port, FTDI_SIO_BITMODE_CBUS);
+}
+
+static int ftdi_exit_cbus_mode(struct usb_serial_port *port)
+{
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+
+ priv->gpio_output = 0;
+ priv->gpio_value = 0;
+ return ftdi_set_bitmode(port, FTDI_SIO_BITMODE_RESET);
+}
+
+static int ftdi_gpio_request(struct gpio_chip *gc, unsigned int offset)
+{
+ struct usb_serial_port *port = gpiochip_get_data(gc);
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+ int result;
+
+ if (priv->gpio_altfunc & BIT(offset))
+ return -ENODEV;
+
+ mutex_lock(&priv->gpio_lock);
+ if (!priv->gpio_used) {
+ /* Set default pin states, as we cannot get them from device */
+ priv->gpio_output = 0x00;
+ priv->gpio_value = 0x00;
+ result = ftdi_set_cbus_pins(port);
+ if (result) {
+ mutex_unlock(&priv->gpio_lock);
+ return result;
+ }
+
+ priv->gpio_used = true;
+ }
+ mutex_unlock(&priv->gpio_lock);
+
+ return 0;
+}
+
+static int ftdi_read_cbus_pins(struct usb_serial_port *port)
+{
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+ struct usb_serial *serial = port->serial;
+ unsigned char *buf;
+ int result;
+
+ result = usb_autopm_get_interface(serial->interface);
+ if (result)
+ return result;
+
+ buf = kmalloc(1, GFP_KERNEL);
+ if (!buf) {
+ usb_autopm_put_interface(serial->interface);
+ return -ENOMEM;
+ }
+
+ result = usb_control_msg(serial->dev,
+ usb_rcvctrlpipe(serial->dev, 0),
+ FTDI_SIO_READ_PINS_REQUEST,
+ FTDI_SIO_READ_PINS_REQUEST_TYPE, 0,
+ priv->interface, buf, 1, WDR_TIMEOUT);
+ if (result < 1) {
+ if (result >= 0)
+ result = -EIO;
+ } else {
+ result = buf[0];
+ }
+
+ kfree(buf);
+ usb_autopm_put_interface(serial->interface);
+
+ return result;
+}
+
+static int ftdi_gpio_get(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct usb_serial_port *port = gpiochip_get_data(gc);
+ int result;
+
+ result = ftdi_read_cbus_pins(port);
+ if (result < 0)
+ return result;
+
+ return !!(result & BIT(gpio));
+}
+
+static void ftdi_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value)
+{
+ struct usb_serial_port *port = gpiochip_get_data(gc);
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+
+ mutex_lock(&priv->gpio_lock);
+
+ if (value)
+ priv->gpio_value |= BIT(gpio);
+ else
+ priv->gpio_value &= ~BIT(gpio);
+
+ ftdi_set_cbus_pins(port);
+
+ mutex_unlock(&priv->gpio_lock);
+}
+
+static int ftdi_gpio_get_multiple(struct gpio_chip *gc, unsigned long *mask,
+ unsigned long *bits)
+{
+ struct usb_serial_port *port = gpiochip_get_data(gc);
+ int result;
+
+ result = ftdi_read_cbus_pins(port);
+ if (result < 0)
+ return result;
+
+ *bits = result & *mask;
+
+ return 0;
+}
+
+static void ftdi_gpio_set_multiple(struct gpio_chip *gc, unsigned long *mask,
+ unsigned long *bits)
+{
+ struct usb_serial_port *port = gpiochip_get_data(gc);
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+
+ mutex_lock(&priv->gpio_lock);
+
+ priv->gpio_value &= ~(*mask);
+ priv->gpio_value |= *bits & *mask;
+ ftdi_set_cbus_pins(port);
+
+ mutex_unlock(&priv->gpio_lock);
+}
+
+static int ftdi_gpio_direction_get(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct usb_serial_port *port = gpiochip_get_data(gc);
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+
+ return !(priv->gpio_output & BIT(gpio));
+}
+
+static int ftdi_gpio_direction_input(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct usb_serial_port *port = gpiochip_get_data(gc);
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+ int result;
+
+ mutex_lock(&priv->gpio_lock);
+
+ priv->gpio_output &= ~BIT(gpio);
+ result = ftdi_set_cbus_pins(port);
+
+ mutex_unlock(&priv->gpio_lock);
+
+ return result;
+}
+
+static int ftdi_gpio_direction_output(struct gpio_chip *gc, unsigned int gpio,
+ int value)
+{
+ struct usb_serial_port *port = gpiochip_get_data(gc);
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+ int result;
+
+ mutex_lock(&priv->gpio_lock);
+
+ priv->gpio_output |= BIT(gpio);
+ if (value)
+ priv->gpio_value |= BIT(gpio);
+ else
+ priv->gpio_value &= ~BIT(gpio);
+
+ result = ftdi_set_cbus_pins(port);
+
+ mutex_unlock(&priv->gpio_lock);
+
+ return result;
+}
+
+static int ftdi_read_eeprom(struct usb_serial *serial, void *dst, u16 addr,
+ u16 nbytes)
+{
+ int read = 0;
+
+ if (addr % 2 != 0)
+ return -EINVAL;
+ if (nbytes % 2 != 0)
+ return -EINVAL;
+
+ /* Read EEPROM two bytes at a time */
+ while (read < nbytes) {
+ int rv;
+
+ rv = usb_control_msg(serial->dev,
+ usb_rcvctrlpipe(serial->dev, 0),
+ FTDI_SIO_READ_EEPROM_REQUEST,
+ FTDI_SIO_READ_EEPROM_REQUEST_TYPE,
+ 0, (addr + read) / 2, dst + read, 2,
+ WDR_TIMEOUT);
+ if (rv < 2) {
+ if (rv >= 0)
+ return -EIO;
+ else
+ return rv;
+ }
+
+ read += rv;
+ }
+
+ return 0;
+}
+
+static int ftdi_gpio_init_ft232h(struct usb_serial_port *port)
+{
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+ u16 cbus_config;
+ u8 *buf;
+ int ret;
+ int i;
+
+ buf = kmalloc(4, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ ret = ftdi_read_eeprom(port->serial, buf, 0x1a, 4);
+ if (ret < 0)
+ goto out_free;
+
+ /*
+ * FT232H CBUS Memory Map
+ *
+ * 0x1a: X- (upper nibble -> AC5)
+ * 0x1b: -X (lower nibble -> AC6)
+ * 0x1c: XX (upper nibble -> AC9 | lower nibble -> AC8)
+ */
+ cbus_config = buf[2] << 8 | (buf[1] & 0xf) << 4 | (buf[0] & 0xf0) >> 4;
+
+ priv->gc.ngpio = 4;
+ priv->gpio_altfunc = 0xff;
+
+ for (i = 0; i < priv->gc.ngpio; ++i) {
+ if ((cbus_config & 0xf) == FTDI_FTX_CBUS_MUX_GPIO)
+ priv->gpio_altfunc &= ~BIT(i);
+ cbus_config >>= 4;
+ }
+
+out_free:
+ kfree(buf);
+
+ return ret;
+}
+
+static int ftdi_gpio_init_ft232r(struct usb_serial_port *port)
+{
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+ u16 cbus_config;
+ u8 *buf;
+ int ret;
+ int i;
+
+ buf = kmalloc(2, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ ret = ftdi_read_eeprom(port->serial, buf, 0x14, 2);
+ if (ret < 0)
+ goto out_free;
+
+ cbus_config = le16_to_cpup((__le16 *)buf);
+ dev_dbg(&port->dev, "cbus_config = 0x%04x\n", cbus_config);
+
+ priv->gc.ngpio = 4;
+
+ priv->gpio_altfunc = 0xff;
+ for (i = 0; i < priv->gc.ngpio; ++i) {
+ if ((cbus_config & 0xf) == FTDI_FT232R_CBUS_MUX_GPIO)
+ priv->gpio_altfunc &= ~BIT(i);
+ cbus_config >>= 4;
+ }
+out_free:
+ kfree(buf);
+
+ return ret;
+}
+
+static int ftdi_gpio_init_ftx(struct usb_serial_port *port)
+{
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+ struct usb_serial *serial = port->serial;
+ const u16 cbus_cfg_addr = 0x1a;
+ const u16 cbus_cfg_size = 4;
+ u8 *cbus_cfg_buf;
+ int result;
+ u8 i;
+
+ cbus_cfg_buf = kmalloc(cbus_cfg_size, GFP_KERNEL);
+ if (!cbus_cfg_buf)
+ return -ENOMEM;
+
+ result = ftdi_read_eeprom(serial, cbus_cfg_buf,
+ cbus_cfg_addr, cbus_cfg_size);
+ if (result < 0)
+ goto out_free;
+
+ /* FIXME: FT234XD alone has 1 GPIO, but how to recognize this IC? */
+ priv->gc.ngpio = 4;
+
+ /* Determine which pins are configured for CBUS bitbanging */
+ priv->gpio_altfunc = 0xff;
+ for (i = 0; i < priv->gc.ngpio; ++i) {
+ if (cbus_cfg_buf[i] == FTDI_FTX_CBUS_MUX_GPIO)
+ priv->gpio_altfunc &= ~BIT(i);
+ }
+
+out_free:
+ kfree(cbus_cfg_buf);
+
+ return result;
+}
+
+static int ftdi_gpio_init(struct usb_serial_port *port)
+{
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+ struct usb_serial *serial = port->serial;
+ int result;
+
+ switch (priv->chip_type) {
+ case FT232H:
+ result = ftdi_gpio_init_ft232h(port);
+ break;
+ case FT232RL:
+ result = ftdi_gpio_init_ft232r(port);
+ break;
+ case FTX:
+ result = ftdi_gpio_init_ftx(port);
+ break;
+ default:
+ return 0;
+ }
+
+ if (result < 0)
+ return result;
+
+ mutex_init(&priv->gpio_lock);
+
+ priv->gc.label = "ftdi-cbus";
+ priv->gc.request = ftdi_gpio_request;
+ priv->gc.get_direction = ftdi_gpio_direction_get;
+ priv->gc.direction_input = ftdi_gpio_direction_input;
+ priv->gc.direction_output = ftdi_gpio_direction_output;
+ priv->gc.get = ftdi_gpio_get;
+ priv->gc.set = ftdi_gpio_set;
+ priv->gc.get_multiple = ftdi_gpio_get_multiple;
+ priv->gc.set_multiple = ftdi_gpio_set_multiple;
+ priv->gc.owner = THIS_MODULE;
+ priv->gc.parent = &serial->interface->dev;
+ priv->gc.base = -1;
+ priv->gc.can_sleep = true;
+
+ result = gpiochip_add_data(&priv->gc, port);
+ if (!result)
+ priv->gpio_registered = true;
+
+ return result;
+}
+
+static void ftdi_gpio_remove(struct usb_serial_port *port)
+{
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+
+ if (priv->gpio_registered) {
+ gpiochip_remove(&priv->gc);
+ priv->gpio_registered = false;
+ }
+
+ if (priv->gpio_used) {
+ /* Exiting CBUS-mode does not reset pin states. */
+ ftdi_exit_cbus_mode(port);
+ priv->gpio_used = false;
+ }
+}
+
+#else
+
+static int ftdi_gpio_init(struct usb_serial_port *port)
+{
+ return 0;
+}
+
+static void ftdi_gpio_remove(struct usb_serial_port *port) { }
+
+#endif /* CONFIG_GPIOLIB */
+
/*
* ***************************************************************************
* FTDI driver specific functions
@@ -1794,7 +2238,7 @@
{
struct ftdi_private *priv;
const struct ftdi_sio_quirk *quirk = usb_get_serial_data(port->serial);
-
+ int result;
priv = kzalloc(sizeof(struct ftdi_private), GFP_KERNEL);
if (!priv)
@@ -1813,6 +2257,14 @@
priv->latency = 16;
write_latency_timer(port);
create_sysfs_attrs(port);
+
+ result = ftdi_gpio_init(port);
+ if (result < 0) {
+ dev_err(&port->serial->interface->dev,
+ "GPIO initialisation failed: %d\n",
+ result);
+ }
+
return 0;
}
@@ -1930,6 +2382,8 @@
{
struct ftdi_private *priv = usb_get_serial_port_data(port);
+ ftdi_gpio_remove(port);
+
remove_sysfs_attrs(port);
kfree(priv);
@@ -2452,10 +2906,6 @@
void __user *argp = (void __user *)arg;
switch (cmd) {
- case TIOCGSERIAL:
- return get_serial_info(port, argp);
- case TIOCSSERIAL:
- return set_serial_info(tty, port, argp);
case TIOCSERGETLSR:
return get_lsr_info(port, argp);
default:
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index dcd0b6e..a79a132 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -35,7 +35,10 @@
#define FTDI_SIO_SET_EVENT_CHAR 6 /* Set the event character */
#define FTDI_SIO_SET_ERROR_CHAR 7 /* Set the error character */
#define FTDI_SIO_SET_LATENCY_TIMER 9 /* Set the latency timer */
-#define FTDI_SIO_GET_LATENCY_TIMER 10 /* Get the latency timer */
+#define FTDI_SIO_GET_LATENCY_TIMER 0x0a /* Get the latency timer */
+#define FTDI_SIO_SET_BITMODE 0x0b /* Set bitbang mode */
+#define FTDI_SIO_READ_PINS 0x0c /* Read immediate value of pins */
+#define FTDI_SIO_READ_EEPROM 0x90 /* Read EEPROM */
/* Interface indices for FT2232, FT2232H and FT4232H devices */
#define INTERFACE_A 1
@@ -433,6 +436,29 @@
* 1 = active
*/
+/* FTDI_SIO_SET_BITMODE */
+#define FTDI_SIO_SET_BITMODE_REQUEST_TYPE 0x40
+#define FTDI_SIO_SET_BITMODE_REQUEST FTDI_SIO_SET_BITMODE
+
+/* Possible bitmodes for FTDI_SIO_SET_BITMODE_REQUEST */
+#define FTDI_SIO_BITMODE_RESET 0x00
+#define FTDI_SIO_BITMODE_CBUS 0x20
+
+/* FTDI_SIO_READ_PINS */
+#define FTDI_SIO_READ_PINS_REQUEST_TYPE 0xc0
+#define FTDI_SIO_READ_PINS_REQUEST FTDI_SIO_READ_PINS
+
+/*
+ * FTDI_SIO_READ_EEPROM
+ *
+ * EEPROM format found in FTDI AN_201, "FT-X MTP memory Configuration",
+ * http://www.ftdichip.com/Support/Documents/AppNotes/AN_201_FT-X%20MTP%20Memory%20Configuration.pdf
+ */
+#define FTDI_SIO_READ_EEPROM_REQUEST_TYPE 0xc0
+#define FTDI_SIO_READ_EEPROM_REQUEST FTDI_SIO_READ_EEPROM
+
+#define FTDI_FTX_CBUS_MUX_GPIO 0x8
+#define FTDI_FT232R_CBUS_MUX_GPIO 0xa
/* Descriptors returned by the device
diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h
index 975d026..e837352 100644
--- a/drivers/usb/serial/ftdi_sio_ids.h
+++ b/drivers/usb/serial/ftdi_sio_ids.h
@@ -39,6 +39,9 @@
#define FTDI_LUMEL_PD12_PID 0x6002
+/* Sienna Serial Interface by Secyourit GmbH */
+#define FTDI_SIENNA_PID 0x8348
+
/* Cyber Cortex AV by Fabulous Silicon (http://fabuloussilicon.com) */
#define CYBER_CORTEX_AV_PID 0x8698
@@ -567,7 +570,9 @@
/*
* NovaTech product ids (FTDI_VID)
*/
-#define FTDI_NT_ORIONLXM_PID 0x7c90 /* OrionLXm Substation Automation Platform */
+#define FTDI_NT_ORIONLXM_PID 0x7c90 /* OrionLXm Substation Automation Platform */
+#define FTDI_NT_ORIONLX_PLUS_PID 0x7c91 /* OrionLX+ Substation Automation Platform */
+#define FTDI_NT_ORION_IO_PID 0x7c92 /* Orion I/O */
/*
* Synapse Wireless product ids (FTDI_VID)
@@ -687,6 +692,12 @@
#define BANDB_ZZ_PROG1_USB_PID 0xBA02
/*
+ * Echelon USB Serial Interface
+ */
+#define ECHELON_VID 0x0920
+#define ECHELON_U20_PID 0x7500
+
+/*
* Intrepid Control Systems (http://www.intrepidcs.com/) ValueCAN and NeoVI
*/
#define INTREPID_VID 0x093C
@@ -1309,6 +1320,12 @@
#define IONICS_PLUGCOMPUTER_PID 0x0102
/*
+ * EZPrototypes (PID reseller)
+ */
+#define EZPROTOTYPES_VID 0x1c40
+#define HJELMSLUND_USB485_ISO_PID 0x0477
+
+/*
* Dresden Elektronik Sensor Terminal Board
*/
#define DE_VID 0x1cf1 /* Vendor ID */
@@ -1535,3 +1552,16 @@
#define CHETCO_SEASMART_DISPLAY_PID 0xA5AD /* SeaSmart NMEA2000 Display */
#define CHETCO_SEASMART_LITE_PID 0xA5AE /* SeaSmart Lite USB Adapter */
#define CHETCO_SEASMART_ANALOG_PID 0xA5AF /* SeaSmart Analog Adapter */
+
+/*
+ * Unjo AB
+ */
+#define UNJO_VID 0x22B7
+#define UNJO_ISODEBUG_V1_PID 0x150D
+
+/*
+ * U-Blox products (http://www.u-blox.com).
+ */
+#define UBLOX_VID 0x1546
+#define UBLOX_C099F9P_ZED_PID 0x0502
+#define UBLOX_C099F9P_ODIN_PID 0x0503
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index 2274d96..1be8bea 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -106,12 +106,8 @@
int usb_serial_generic_open(struct tty_struct *tty, struct usb_serial_port *port)
{
int result = 0;
- unsigned long flags;
- spin_lock_irqsave(&port->lock, flags);
- port->throttled = 0;
- port->throttle_req = 0;
- spin_unlock_irqrestore(&port->lock, flags);
+ clear_bit(USB_SERIAL_THROTTLED, &port->flags);
if (port->bulk_in_size)
result = usb_serial_generic_submit_read_urbs(port, GFP_KERNEL);
@@ -375,7 +371,7 @@
{
struct usb_serial_port *port = urb->context;
unsigned char *data = urb->transfer_buffer;
- unsigned long flags;
+ bool stopped = false;
int status = urb->status;
int i;
@@ -383,42 +379,55 @@
if (urb == port->read_urbs[i])
break;
}
- set_bit(i, &port->read_urbs_free);
dev_dbg(&port->dev, "%s - urb %d, len %d\n", __func__, i,
urb->actual_length);
switch (status) {
case 0:
+ usb_serial_debug_data(&port->dev, __func__, urb->actual_length,
+ data);
+ port->serial->type->process_read_urb(urb);
break;
case -ENOENT:
case -ECONNRESET:
case -ESHUTDOWN:
dev_dbg(&port->dev, "%s - urb stopped: %d\n",
__func__, status);
- return;
+ stopped = true;
+ break;
case -EPIPE:
dev_err(&port->dev, "%s - urb stopped: %d\n",
__func__, status);
- return;
+ stopped = true;
+ break;
default:
dev_dbg(&port->dev, "%s - nonzero urb status: %d\n",
__func__, status);
- goto resubmit;
+ break;
}
- usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data);
- port->serial->type->process_read_urb(urb);
+ /*
+ * Make sure URB processing is done before marking as free to avoid
+ * racing with unthrottle() on another CPU. Matches the barriers
+ * implied by the test_and_clear_bit() in
+ * usb_serial_generic_submit_read_urb().
+ */
+ smp_mb__before_atomic();
+ set_bit(i, &port->read_urbs_free);
+ /*
+ * Make sure URB is marked as free before checking the throttled flag
+ * to avoid racing with unthrottle() on another CPU. Matches the
+ * smp_mb() in unthrottle().
+ */
+ smp_mb__after_atomic();
-resubmit:
- /* Throttle the device if requested by tty */
- spin_lock_irqsave(&port->lock, flags);
- port->throttled = port->throttle_req;
- if (!port->throttled) {
- spin_unlock_irqrestore(&port->lock, flags);
- usb_serial_generic_submit_read_urb(port, i, GFP_ATOMIC);
- } else {
- spin_unlock_irqrestore(&port->lock, flags);
- }
+ if (stopped)
+ return;
+
+ if (test_bit(USB_SERIAL_THROTTLED, &port->flags))
+ return;
+
+ usb_serial_generic_submit_read_urb(port, i, GFP_ATOMIC);
}
EXPORT_SYMBOL_GPL(usb_serial_generic_read_bulk_callback);
@@ -454,10 +463,9 @@
default:
dev_err_console(port, "%s - nonzero urb status: %d\n",
__func__, status);
- goto resubmit;
+ break;
}
-resubmit:
usb_serial_generic_write_start(port, GFP_ATOMIC);
usb_serial_port_softint(port);
}
@@ -466,26 +474,24 @@
void usb_serial_generic_throttle(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- unsigned long flags;
- spin_lock_irqsave(&port->lock, flags);
- port->throttle_req = 1;
- spin_unlock_irqrestore(&port->lock, flags);
+ set_bit(USB_SERIAL_THROTTLED, &port->flags);
}
EXPORT_SYMBOL_GPL(usb_serial_generic_throttle);
void usb_serial_generic_unthrottle(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- int was_throttled;
- spin_lock_irq(&port->lock);
- was_throttled = port->throttled;
- port->throttled = port->throttle_req = 0;
- spin_unlock_irq(&port->lock);
+ clear_bit(USB_SERIAL_THROTTLED, &port->flags);
- if (was_throttled)
- usb_serial_generic_submit_read_urbs(port, GFP_KERNEL);
+ /*
+ * Matches the smp_mb__after_atomic() in
+ * usb_serial_generic_read_bulk_callback().
+ */
+ smp_mb();
+
+ usb_serial_generic_submit_read_urbs(port, GFP_KERNEL);
}
EXPORT_SYMBOL_GPL(usb_serial_generic_unthrottle);
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index 97c69d3..48a4392 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -1637,24 +1637,20 @@
return result;
}
-static int get_serial_info(struct edgeport_port *edge_port,
- struct serial_struct __user *retinfo)
+static int get_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss)
{
- struct serial_struct tmp;
+ struct usb_serial_port *port = tty->driver_data;
+ struct edgeport_port *edge_port = usb_get_serial_port_data(port);
- memset(&tmp, 0, sizeof(tmp));
-
- tmp.type = PORT_16550A;
- tmp.line = edge_port->port->minor;
- tmp.port = edge_port->port->port_number;
- tmp.irq = 0;
- tmp.xmit_fifo_size = edge_port->maxTxCredits;
- tmp.baud_base = 9600;
- tmp.close_delay = 5*HZ;
- tmp.closing_wait = 30*HZ;
-
- if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
- return -EFAULT;
+ 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;
}
@@ -1667,17 +1663,12 @@
unsigned int cmd, unsigned long arg)
{
struct usb_serial_port *port = tty->driver_data;
- DEFINE_WAIT(wait);
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
switch (cmd) {
case TIOCSERGETLSR:
dev_dbg(&port->dev, "%s TIOCSERGETLSR\n", __func__);
return get_lsr_info(edge_port, (unsigned int __user *) arg);
-
- case TIOCGSERIAL:
- dev_dbg(&port->dev, "%s TIOCGSERIAL\n", __func__);
- return get_serial_info(edge_port, (struct serial_struct __user *) arg);
}
return -ENOIOCTLCMD;
}
@@ -1760,7 +1751,7 @@
edge_serial->rxState = EXPECT_HDR2;
break;
}
- /* otherwise, drop on through */
+ /* Fall through */
case EXPECT_HDR2:
edge_serial->rxHeader2 = *buffer;
++buffer;
@@ -1799,29 +1790,20 @@
edge_serial->rxHeader2, 0);
edge_serial->rxState = EXPECT_HDR1;
break;
- } else {
- edge_serial->rxPort =
- IOSP_GET_HDR_PORT(edge_serial->rxHeader1);
- edge_serial->rxBytesRemaining =
- IOSP_GET_HDR_DATA_LEN(
- edge_serial->rxHeader1,
- edge_serial->rxHeader2);
- dev_dbg(dev, "%s - Data for Port %u Len %u\n",
- __func__,
- edge_serial->rxPort,
- edge_serial->rxBytesRemaining);
-
- /* ASSERT(DevExt->RxPort < DevExt->NumPorts);
- * ASSERT(DevExt->RxBytesRemaining <
- * IOSP_MAX_DATA_LENGTH);
- */
-
- if (bufferLength == 0) {
- edge_serial->rxState = EXPECT_DATA;
- break;
- }
- /* Else, drop through */
}
+
+ edge_serial->rxPort = IOSP_GET_HDR_PORT(edge_serial->rxHeader1);
+ edge_serial->rxBytesRemaining = IOSP_GET_HDR_DATA_LEN(edge_serial->rxHeader1,
+ edge_serial->rxHeader2);
+ dev_dbg(dev, "%s - Data for Port %u Len %u\n", __func__,
+ edge_serial->rxPort,
+ edge_serial->rxBytesRemaining);
+
+ if (bufferLength == 0) {
+ edge_serial->rxState = EXPECT_DATA;
+ break;
+ }
+ /* Fall through */
case EXPECT_DATA: /* Expect data */
if (bufferLength < edge_serial->rxBytesRemaining) {
rxLen = bufferLength;
@@ -3126,6 +3108,7 @@
.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,
@@ -3161,6 +3144,7 @@
.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,
@@ -3196,6 +3180,7 @@
.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,
@@ -3231,6 +3216,7 @@
.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_ti.c b/drivers/usb/serial/io_ti.c
index 6d1d6ef..c327d4c 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -2437,47 +2437,28 @@
return result;
}
-static int get_serial_info(struct edgeport_port *edge_port,
- struct serial_struct __user *retinfo)
+static int get_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss)
{
- struct serial_struct tmp;
+ 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;
- memset(&tmp, 0, sizeof(tmp));
-
- tmp.type = PORT_16550A;
- tmp.line = edge_port->port->minor;
- tmp.port = edge_port->port->port_number;
- tmp.irq = 0;
- tmp.xmit_fifo_size = edge_port->port->bulk_out_size;
- tmp.baud_base = 9600;
- tmp.close_delay = 5*HZ;
- tmp.closing_wait = cwait;
-
- if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
- return -EFAULT;
+ 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 int edge_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct edgeport_port *edge_port = usb_get_serial_port_data(port);
-
- switch (cmd) {
- case TIOCGSERIAL:
- dev_dbg(&port->dev, "%s - TIOCGSERIAL\n", __func__);
- return get_serial_info(edge_port,
- (struct serial_struct __user *) arg);
- }
- return -ENOIOCTLCMD;
-}
-
static void edge_break(struct tty_struct *tty, int break_state)
{
struct usb_serial_port *port = tty->driver_data;
@@ -2738,7 +2719,7 @@
.release = edge_release,
.port_probe = edge_port_probe,
.port_remove = edge_port_remove,
- .ioctl = edge_ioctl,
+ .get_serial = get_serial_info,
.set_termios = edge_set_termios,
.tiocmget = edge_tiocmget,
.tiocmset = edge_tiocmset,
@@ -2777,7 +2758,7 @@
.release = edge_release,
.port_probe = edge_port_probe,
.port_remove = edge_port_remove,
- .ioctl = edge_ioctl,
+ .get_serial = get_serial_info,
.set_termios = edge_set_termios,
.tiocmget = edge_tiocmget,
.tiocmset = edge_tiocmset,
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
index 7643716..302eb95 100644
--- a/drivers/usb/serial/ir-usb.c
+++ b/drivers/usb/serial/ir-usb.c
@@ -16,7 +16,7 @@
* was written by Roman Weissgaerber <weissg@vienna.at>, Dag Brattli
* <dag@brattli.net>, and Jean Tourrilhes <jt@hpl.hp.com>
*
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
* driver
*/
diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c
index 449e89d..d5bff69 100644
--- a/drivers/usb/serial/iuu_phoenix.c
+++ b/drivers/usb/serial/iuu_phoenix.c
@@ -942,9 +942,7 @@
static void iuu_init_termios(struct tty_struct *tty)
{
- tty->termios = tty_std_termios;
- tty->termios.c_cflag = CLOCAL | CREAD | CS8 | B9600
- | TIOCM_CTS | CSTOPB | PARENB;
+ tty->termios.c_cflag = B9600 | CS8 | CSTOPB | CREAD | PARENB | CLOCAL;
tty->termios.c_ispeed = 9600;
tty->termios.c_ospeed = 9600;
tty->termios.c_lflag = 0;
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index d34779f..e66a59e 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -1741,8 +1741,8 @@
ep_desc = find_ep(serial, endpoint);
if (!ep_desc) {
- /* leak the urb, something's wrong and the callers don't care */
- return urb;
+ usb_free_urb(urb);
+ return NULL;
}
if (usb_endpoint_xfer_int(ep_desc)) {
ep_type_name = "INT";
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index 38d43c4..bf988f7 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -6,7 +6,7 @@
* Copyright (C) 1999, 2000 Brian Warner <warner@lothar.com>
* Copyright (C) 2000 Al Borchers <borchers@steinerpoint.com>
*
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
* driver
*/
diff --git a/drivers/usb/serial/keyspan_usa26msg.h b/drivers/usb/serial/keyspan_usa26msg.h
index 09e21e8..a68f1fb 100644
--- a/drivers/usb/serial/keyspan_usa26msg.h
+++ b/drivers/usb/serial/keyspan_usa26msg.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
/*
usa26msg.h
diff --git a/drivers/usb/serial/keyspan_usa28msg.h b/drivers/usb/serial/keyspan_usa28msg.h
index dee454c..a19f3fe 100644
--- a/drivers/usb/serial/keyspan_usa28msg.h
+++ b/drivers/usb/serial/keyspan_usa28msg.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
/*
usa28msg.h
diff --git a/drivers/usb/serial/keyspan_usa49msg.h b/drivers/usb/serial/keyspan_usa49msg.h
index 163b2de..8c3970f 100644
--- a/drivers/usb/serial/keyspan_usa49msg.h
+++ b/drivers/usb/serial/keyspan_usa49msg.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
/*
usa49msg.h
diff --git a/drivers/usb/serial/keyspan_usa67msg.h b/drivers/usb/serial/keyspan_usa67msg.h
index 20fa3e2..dcf502f 100644
--- a/drivers/usb/serial/keyspan_usa67msg.h
+++ b/drivers/usb/serial/keyspan_usa67msg.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
/*
usa67msg.h
diff --git a/drivers/usb/serial/keyspan_usa90msg.h b/drivers/usb/serial/keyspan_usa90msg.h
index 86708ec..c4ca0f6 100644
--- a/drivers/usb/serial/keyspan_usa90msg.h
+++ b/drivers/usb/serial/keyspan_usa90msg.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
/*
usa90msg.h
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index 2710952..2ec4eea 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -366,8 +366,6 @@
if (!urbtrack)
return -ENOMEM;
- kref_get(&mos_parport->ref_count);
- urbtrack->mos_parport = mos_parport;
urbtrack->urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urbtrack->urb) {
kfree(urbtrack);
@@ -388,6 +386,8 @@
usb_sndctrlpipe(usbdev, 0),
(unsigned char *)urbtrack->setup,
NULL, 0, async_complete, urbtrack);
+ kref_get(&mos_parport->ref_count);
+ urbtrack->mos_parport = mos_parport;
kref_init(&urbtrack->ref_count);
INIT_LIST_HEAD(&urbtrack->urblist_entry);
@@ -1786,69 +1786,20 @@
return 0;
}
-static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd,
- unsigned int __user *value)
+static int get_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss)
{
- unsigned int mcr;
- unsigned int arg;
+ struct usb_serial_port *port = tty->driver_data;
+ struct moschip_port *mos7720_port = usb_get_serial_port_data(port);
- struct usb_serial_port *port;
-
- if (mos7720_port == NULL)
- return -1;
-
- port = (struct usb_serial_port *)mos7720_port->port;
- mcr = mos7720_port->shadowMCR;
-
- if (copy_from_user(&arg, value, sizeof(int)))
- return -EFAULT;
-
- switch (cmd) {
- case TIOCMBIS:
- if (arg & TIOCM_RTS)
- mcr |= UART_MCR_RTS;
- if (arg & TIOCM_DTR)
- mcr |= UART_MCR_RTS;
- if (arg & TIOCM_LOOP)
- mcr |= UART_MCR_LOOP;
- break;
-
- case TIOCMBIC:
- if (arg & TIOCM_RTS)
- mcr &= ~UART_MCR_RTS;
- if (arg & TIOCM_DTR)
- mcr &= ~UART_MCR_RTS;
- if (arg & TIOCM_LOOP)
- mcr &= ~UART_MCR_LOOP;
- break;
-
- }
-
- mos7720_port->shadowMCR = mcr;
- write_mos_reg(port->serial, port->port_number, MOS7720_MCR,
- mos7720_port->shadowMCR);
-
- return 0;
-}
-
-static int get_serial_info(struct moschip_port *mos7720_port,
- struct serial_struct __user *retinfo)
-{
- struct serial_struct tmp;
-
- memset(&tmp, 0, sizeof(tmp));
-
- tmp.type = PORT_16550A;
- tmp.line = mos7720_port->port->minor;
- tmp.port = mos7720_port->port->port_number;
- tmp.irq = 0;
- tmp.xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE;
- tmp.baud_base = 9600;
- tmp.close_delay = 5*HZ;
- tmp.closing_wait = 30*HZ;
-
- if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
- return -EFAULT;
+ 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;
}
@@ -1867,18 +1818,6 @@
dev_dbg(&port->dev, "%s TIOCSERGETLSR\n", __func__);
return get_lsr_info(tty, mos7720_port,
(unsigned int __user *)arg);
-
- /* FIXME: These should be using the mode methods */
- case TIOCMBIS:
- case TIOCMBIC:
- dev_dbg(&port->dev, "%s TIOCMSET/TIOCMBIC/TIOCMSET\n", __func__);
- return set_modem_info(mos7720_port, cmd,
- (unsigned int __user *)arg);
-
- case TIOCGSERIAL:
- dev_dbg(&port->dev, "%s TIOCGSERIAL\n", __func__);
- return get_serial_info(mos7720_port,
- (struct serial_struct __user *)arg);
}
return -ENOIOCTLCMD;
@@ -1894,10 +1833,6 @@
product = le16_to_cpu(serial->dev->descriptor.idProduct);
dev = serial->dev;
- /* setting configuration feature to one */
- usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- (__u8)0x03, 0x00, 0x01, 0x00, NULL, 0x00, 5000);
-
if (product == MOSCHIP_DEVICE_ID_7715) {
struct urb *urb = serial->port[0]->interrupt_in_urb;
@@ -2015,6 +1950,7 @@
.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 b42bad8..ab4bf8d 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -94,6 +94,7 @@
/* The native mos7840/7820 component */
#define USB_VENDOR_ID_MOSCHIP 0x9710
#define MOSCHIP_DEVICE_ID_7840 0x7840
+#define MOSCHIP_DEVICE_ID_7843 0x7843
#define MOSCHIP_DEVICE_ID_7820 0x7820
#define MOSCHIP_DEVICE_ID_7810 0x7810
/* The native component can have its vendor/device id's overridden
@@ -118,11 +119,15 @@
/* This driver also supports
* ATEN UC2324 device using Moschip MCS7840
* ATEN UC2322 device using Moschip MCS7820
+ * MOXA UPort 2210 device using Moschip MCS7820
*/
#define USB_VENDOR_ID_ATENINTL 0x0557
#define ATENINTL_DEVICE_ID_UC2324 0x2011
#define ATENINTL_DEVICE_ID_UC2322 0x7820
+#define USB_VENDOR_ID_MOXA 0x110a
+#define MOXA_DEVICE_ID_2210 0x2210
+
/* Interrupt Routine Defines */
#define SERIAL_IIR_RLS 0x06
@@ -176,6 +181,7 @@
static const struct usb_device_id id_table[] = {
{USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)},
+ {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7843)},
{USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)},
{USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7810)},
{USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2)},
@@ -193,6 +199,7 @@
{USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL2_4)},
{USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2324)},
{USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)},
+ {USB_DEVICE(USB_VENDOR_ID_MOXA, MOXA_DEVICE_ID_2210)},
{} /* terminating entry */
};
MODULE_DEVICE_TABLE(usb, id_table);
@@ -298,15 +305,10 @@
val = val & 0x00ff;
/* For the UART control registers, the application number need
to be Or'ed */
- if (port->serial->num_ports == 4) {
+ if (port->serial->num_ports == 2 && port->port_number != 0)
+ val |= ((__u16)port->port_number + 2) << 8;
+ else
val |= ((__u16)port->port_number + 1) << 8;
- } else {
- if (port->port_number == 0) {
- val |= ((__u16)port->port_number + 1) << 8;
- } else {
- val |= ((__u16)port->port_number + 2) << 8;
- }
- }
dev_dbg(&port->dev, "%s application number is %x\n", __func__, val);
return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), MCS_WRREQ,
MCS_WR_RTYPE, val, reg, NULL, 0,
@@ -332,15 +334,10 @@
return -ENOMEM;
/* Wval is same as application number */
- if (port->serial->num_ports == 4) {
+ if (port->serial->num_ports == 2 && port->port_number != 0)
+ Wval = ((__u16)port->port_number + 2) << 8;
+ else
Wval = ((__u16)port->port_number + 1) << 8;
- } else {
- if (port->port_number == 0) {
- Wval = ((__u16)port->port_number + 1) << 8;
- } else {
- Wval = ((__u16)port->port_number + 2) << 8;
- }
- }
dev_dbg(&port->dev, "%s application number is %x\n", __func__, Wval);
ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ,
MCS_RD_RTYPE, Wval, reg, buf, VENDOR_READ_LENGTH,
@@ -601,7 +598,7 @@
struct usb_serial *serial;
__u16 Data;
unsigned char *data;
- __u8 sp[5], st;
+ __u8 sp[5];
int i, rv = 0;
__u16 wval, wreg = 0;
int status = urb->status;
@@ -644,7 +641,6 @@
sp[1] = (__u8) data[1];
sp[2] = (__u8) data[2];
sp[3] = (__u8) data[3];
- st = (__u8) data[4];
for (i = 0; i < serial->num_ports; i++) {
mos7840_port = mos7840_get_port_private(serial->port[i]);
@@ -1300,7 +1296,6 @@
struct urb *urb;
/* __u16 Data; */
const unsigned char *current_position = data;
- unsigned char *data1;
if (mos7840_port_paranoia_check(port, __func__))
return -1;
@@ -1361,7 +1356,6 @@
mos7840_bulk_out_data_callback, mos7840_port);
}
- data1 = urb->transfer_buffer;
dev_dbg(&port->dev, "bulkout endpoint is %d\n", port->bulk_out_endpointAddress);
if (mos7840_port->has_led)
@@ -1592,7 +1586,6 @@
int divisor = 0;
int status;
__u16 Data;
- unsigned char number;
__u16 clk_sel_val;
struct usb_serial_port *port;
@@ -1606,8 +1599,6 @@
if (mos7840_serial_paranoia_check(port->serial, __func__))
return -1;
- number = mos7840_port->port->port_number;
-
dev_dbg(&port->dev, "%s - baud = %d\n", __func__, baudRate);
/* reset clk_uart_sel in spregOffset */
if (baudRate > 115200) {
@@ -1697,14 +1688,12 @@
{
int baud;
unsigned cflag;
- unsigned iflag;
__u8 lData;
__u8 lParity;
__u8 lStop;
int status;
__u16 Data;
struct usb_serial_port *port;
- struct usb_serial *serial;
if (mos7840_port == NULL)
return;
@@ -1717,8 +1706,6 @@
if (mos7840_serial_paranoia_check(port->serial, __func__))
return;
- serial = port->serial;
-
if (!mos7840_port->open) {
dev_dbg(&port->dev, "%s - port not opened\n", __func__);
return;
@@ -1729,7 +1716,6 @@
lParity = LCR_PAR_NONE;
cflag = tty->termios.c_cflag;
- iflag = tty->termios.c_iflag;
/* Change the number of bits */
switch (cflag & CSIZE) {
@@ -1931,27 +1917,20 @@
* function to get information about serial port
*****************************************************************************/
-static int mos7840_get_serial_info(struct moschip_port *mos7840_port,
- struct serial_struct __user *retinfo)
+static int mos7840_get_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss)
{
- struct serial_struct tmp;
+ struct usb_serial_port *port = tty->driver_data;
+ struct moschip_port *mos7840_port = mos7840_get_port_private(port);
- if (mos7840_port == NULL)
- return -1;
-
- memset(&tmp, 0, sizeof(tmp));
-
- tmp.type = PORT_16550A;
- tmp.line = mos7840_port->port->minor;
- tmp.port = mos7840_port->port->port_number;
- tmp.irq = 0;
- tmp.xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE;
- tmp.baud_base = 9600;
- tmp.close_delay = 5 * HZ;
- tmp.closing_wait = 30 * HZ;
-
- if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
- return -EFAULT;
+ 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;
}
@@ -1982,13 +1961,6 @@
dev_dbg(&port->dev, "%s TIOCSERGETLSR\n", __func__);
return mos7840_get_lsr_info(tty, argp);
- case TIOCGSERIAL:
- dev_dbg(&port->dev, "%s TIOCGSERIAL\n", __func__);
- return mos7840_get_serial_info(mos7840_port, argp);
-
- case TIOCSSERIAL:
- dev_dbg(&port->dev, "%s TIOCSSERIAL\n", __func__);
- break;
default:
break;
}
@@ -2053,15 +2025,22 @@
const struct usb_device_id *id)
{
u16 product = le16_to_cpu(serial->dev->descriptor.idProduct);
+ u16 vid = le16_to_cpu(serial->dev->descriptor.idVendor);
u8 *buf;
int device_type;
if (product == MOSCHIP_DEVICE_ID_7810 ||
- product == MOSCHIP_DEVICE_ID_7820) {
+ product == MOSCHIP_DEVICE_ID_7820 ||
+ product == MOSCHIP_DEVICE_ID_7843) {
device_type = product;
goto out;
}
+ if (vid == USB_VENDOR_ID_MOXA && product == MOXA_DEVICE_ID_2210) {
+ device_type = MOSCHIP_DEVICE_ID_7820;
+ goto out;
+ }
+
buf = kzalloc(VENDOR_READ_LENGTH, GFP_KERNEL);
if (!buf)
return -ENOMEM;
@@ -2091,7 +2070,10 @@
int device_type = (unsigned long)usb_get_serial_data(serial);
int num_ports;
- num_ports = (device_type >> 4) & 0x000F;
+ if (device_type == MOSCHIP_DEVICE_ID_7843)
+ num_ports = 3;
+ else
+ num_ports = (device_type >> 4) & 0x000F;
/*
* num_ports is currently never zero as device_type is one of
@@ -2146,22 +2128,16 @@
mos7840_port->SpRegOffset = 0x0;
mos7840_port->ControlRegOffset = 0x1;
mos7840_port->DcrRegOffset = 0x4;
- } else if ((mos7840_port->port_num == 2) && (serial->num_ports == 4)) {
- mos7840_port->SpRegOffset = 0x8;
- mos7840_port->ControlRegOffset = 0x9;
- mos7840_port->DcrRegOffset = 0x16;
- } else if ((mos7840_port->port_num == 2) && (serial->num_ports == 2)) {
- mos7840_port->SpRegOffset = 0xa;
- mos7840_port->ControlRegOffset = 0xb;
- mos7840_port->DcrRegOffset = 0x19;
- } else if ((mos7840_port->port_num == 3) && (serial->num_ports == 4)) {
- mos7840_port->SpRegOffset = 0xa;
- mos7840_port->ControlRegOffset = 0xb;
- mos7840_port->DcrRegOffset = 0x19;
- } else if ((mos7840_port->port_num == 4) && (serial->num_ports == 4)) {
- mos7840_port->SpRegOffset = 0xc;
- mos7840_port->ControlRegOffset = 0xd;
- mos7840_port->DcrRegOffset = 0x1c;
+ } else {
+ u8 phy_num = mos7840_port->port_num;
+
+ /* Port 2 in the 2-port case uses registers of port 3 */
+ if (serial->num_ports == 2)
+ phy_num = 3;
+
+ mos7840_port->SpRegOffset = 0x8 + 2 * (phy_num - 2);
+ mos7840_port->ControlRegOffset = 0x9 + 2 * (phy_num - 2);
+ mos7840_port->DcrRegOffset = 0x16 + 3 * (phy_num - 2);
}
mos7840_dump_serial_port(port, mos7840_port);
mos7840_set_port_private(port, mos7840_port);
@@ -2314,11 +2290,6 @@
goto error;
} else
dev_dbg(&port->dev, "ZLP_REG5 Writing success status%d\n", status);
-
- /* setting configuration feature to one */
- usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- 0x03, 0x00, 0x01, 0x00, NULL, 0x00,
- MOS_WDR_TIMEOUT);
}
return 0;
error:
@@ -2376,6 +2347,7 @@
.calc_num_ports = mos7840_calc_num_ports,
.probe = mos7840_probe,
.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/omninet.c b/drivers/usb/serial/omninet.c
index e51c946..5b6e982 100644
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -4,7 +4,7 @@
*
* Copyright (C) 2013,2017 Johan Hovold <johan@kernel.org>
*
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
* driver
*
* Please report both successes and troubles to the author at omninet@kroah.com
diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c
index caa0746..cb7aac9 100644
--- a/drivers/usb/serial/opticon.c
+++ b/drivers/usb/serial/opticon.c
@@ -328,40 +328,21 @@
return 0;
}
-static int get_serial_info(struct usb_serial_port *port,
- struct serial_struct __user *serial)
-{
- struct serial_struct tmp;
-
- memset(&tmp, 0x00, sizeof(tmp));
-
- /* fake emulate a 16550 uart to make userspace code happy */
- tmp.type = PORT_16550A;
- tmp.line = port->minor;
- tmp.port = 0;
- tmp.irq = 0;
- tmp.xmit_fifo_size = 1024;
- tmp.baud_base = 9600;
- tmp.close_delay = 5*HZ;
- tmp.closing_wait = 30*HZ;
-
- if (copy_to_user(serial, &tmp, sizeof(*serial)))
- return -EFAULT;
- return 0;
-}
-
-static int opticon_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
+static int get_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss)
{
struct usb_serial_port *port = tty->driver_data;
- switch (cmd) {
- case TIOCGSERIAL:
- return get_serial_info(port,
- (struct serial_struct __user *)arg);
- }
-
- return -ENOIOCTLCMD;
+ /* 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)
@@ -404,7 +385,7 @@
.write_room = opticon_write_room,
.throttle = usb_serial_generic_throttle,
.unthrottle = usb_serial_generic_unthrottle,
- .ioctl = opticon_ioctl,
+ .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 17787dc..e9491d4 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -197,6 +197,7 @@
#define DELL_PRODUCT_5804_MINICARD_ATT 0x819b /* Novatel E371 */
#define DELL_PRODUCT_5821E 0x81d7
+#define DELL_PRODUCT_5821E_ESIM 0x81e0
#define KYOCERA_VENDOR_ID 0x0c88
#define KYOCERA_PRODUCT_KPC650 0x17da
@@ -246,6 +247,7 @@
#define QUECTEL_PRODUCT_EC25 0x0125
#define QUECTEL_PRODUCT_BG96 0x0296
#define QUECTEL_PRODUCT_EP06 0x0306
+#define QUECTEL_PRODUCT_EM12 0x0512
#define CMOTECH_VENDOR_ID 0x16d8
#define CMOTECH_PRODUCT_6001 0x6001
@@ -418,6 +420,7 @@
#define CINTERION_PRODUCT_PH8_AUDIO 0x0083
#define CINTERION_PRODUCT_AHXX_2RMNET 0x0084
#define CINTERION_PRODUCT_AHXX_AUDIO 0x0085
+#define CINTERION_PRODUCT_CLS8 0x00b0
/* Olivetti products */
#define OLIVETTI_VENDOR_ID 0x0b3c
@@ -967,6 +970,11 @@
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x7B) },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x7C) },
+ /* Motorola devices */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x22b8, 0x2a70, 0xff, 0xff, 0xff) }, /* mdm6600 */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x22b8, 0x2e0a, 0xff, 0xff, 0xff) }, /* mdm9600 */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x22b8, 0x4281, 0x0a, 0x00, 0xfc) }, /* mdm ram dl */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x22b8, 0x900e, 0xff, 0xff, 0xff) }, /* mdm qc dl */
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V640) },
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V620) },
@@ -1037,6 +1045,8 @@
{ USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, DELL_PRODUCT_5804_MINICARD_ATT, 0xff, 0xff, 0xff) },
{ USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5821E),
.driver_info = RSVD(0) | RSVD(1) | RSVD(6) },
+ { USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5821E_ESIM),
+ .driver_info = RSVD(0) | RSVD(1) | RSVD(6) },
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_E100A) }, /* ADU-E100, ADU-310 */
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_500A) },
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_620UW) },
@@ -1066,7 +1076,8 @@
.driver_info = RSVD(3) },
{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */
{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x0023)}, /* ONYX 3G device */
- { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000)}, /* SIMCom SIM5218 */
+ { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000), /* SIMCom SIM5218 */
+ .driver_info = NCTRL(0) | NCTRL(1) | NCTRL(2) | NCTRL(3) | RSVD(4) },
/* Quectel products using Qualcomm vendor ID */
{ USB_DEVICE(QUALCOMM_VENDOR_ID, QUECTEL_PRODUCT_UC15)},
{ USB_DEVICE(QUALCOMM_VENDOR_ID, QUECTEL_PRODUCT_UC20),
@@ -1087,6 +1098,9 @@
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06, 0xff, 0xff, 0xff),
.driver_info = RSVD(1) | RSVD(2) | RSVD(3) | RSVD(4) | NUMEP2 },
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06, 0xff, 0, 0) },
+ { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM12, 0xff, 0xff, 0xff),
+ .driver_info = RSVD(1) | RSVD(2) | RSVD(3) | RSVD(4) | NUMEP2 },
+ { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM12, 0xff, 0, 0) },
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6001) },
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CMU_300) },
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6003),
@@ -1144,10 +1158,20 @@
.driver_info = NCTRL(0) | RSVD(1) | RSVD(2) | RSVD(3) },
{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG5, 0xff),
.driver_info = RSVD(0) | RSVD(1) | NCTRL(2) | RSVD(3) },
+ { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1050, 0xff), /* Telit FN980 (rmnet) */
+ .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) },
+ { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1051, 0xff), /* Telit FN980 (MBIM) */
+ .driver_info = NCTRL(0) | RSVD(1) },
+ { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1052, 0xff), /* Telit FN980 (RNDIS) */
+ .driver_info = NCTRL(2) | RSVD(3) },
+ { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1053, 0xff), /* Telit FN980 (ECM) */
+ .driver_info = NCTRL(0) | RSVD(1) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_ME910),
.driver_info = NCTRL(0) | RSVD(1) | RSVD(3) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_ME910_DUAL_MODEM),
.driver_info = NCTRL(0) | RSVD(3) },
+ { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1102, 0xff), /* Telit ME910 (ECM) */
+ .driver_info = NCTRL(0) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910),
.driver_info = NCTRL(0) | RSVD(1) | RSVD(2) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910_USBCFG4),
@@ -1164,6 +1188,10 @@
{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920A4_1213, 0xff) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920A4_1214),
.driver_info = NCTRL(0) | RSVD(1) | RSVD(2) | RSVD(3) },
+ { USB_DEVICE(TELIT_VENDOR_ID, 0x1260),
+ .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) },
+ { USB_DEVICE(TELIT_VENDOR_ID, 0x1261),
+ .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) },
{ USB_DEVICE(TELIT_VENDOR_ID, 0x1900), /* Telit LN940 (QMI) */
.driver_info = NCTRL(0) | RSVD(1) },
{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1901, 0xff), /* Telit LN940 (MBIM) */
@@ -1332,6 +1360,7 @@
.driver_info = RSVD(4) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0414, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0417, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_INTERFACE_CLASS(ZTE_VENDOR_ID, 0x0601, 0xff) }, /* GosunCn ZTE WeLink ME3630 (RNDIS mode) */
{ USB_DEVICE_INTERFACE_CLASS(ZTE_VENDOR_ID, 0x0602, 0xff) }, /* GosunCn ZTE WeLink ME3630 (MBIM mode) */
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1008, 0xff, 0xff, 0xff),
.driver_info = RSVD(4) },
@@ -1537,6 +1566,7 @@
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1428, 0xff, 0xff, 0xff), /* Telewell TW-LTE 4G v2 */
.driver_info = RSVD(2) },
{ USB_DEVICE_INTERFACE_CLASS(ZTE_VENDOR_ID, 0x1476, 0xff) }, /* GosunCn ZTE WeLink ME3630 (ECM/NCM mode) */
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1481, 0xff, 0x00, 0x00) }, /* ZTE MF871A */
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1533, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1534, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1535, 0xff, 0xff, 0xff) },
@@ -1765,6 +1795,8 @@
{ USB_DEVICE(ALINK_VENDOR_ID, SIMCOM_PRODUCT_SIM7100E),
.driver_info = RSVD(5) | RSVD(6) },
{ USB_DEVICE_INTERFACE_CLASS(0x1e0e, 0x9003, 0xff) }, /* Simcom SIM7500/SIM7600 MBIM mode */
+ { USB_DEVICE_INTERFACE_CLASS(0x1e0e, 0x9011, 0xff), /* Simcom SIM7500/SIM7600 RNDIS mode */
+ .driver_info = RSVD(7) },
{ USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X060S_X200),
.driver_info = NCTRL(0) | NCTRL(1) | RSVD(4) },
{ USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X220_X500D),
@@ -1827,6 +1859,8 @@
.driver_info = RSVD(4) },
{ USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX_2RMNET, 0xff) },
{ USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX_AUDIO, 0xff) },
+ { USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_CLS8, 0xff),
+ .driver_info = RSVD(0) | RSVD(4) },
{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDM) },
{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDMNET) },
{ USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC25_MDM) },
@@ -1938,10 +1972,16 @@
.driver_info = RSVD(4) },
{ USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7e35, 0xff), /* D-Link DWM-222 */
.driver_info = RSVD(4) },
- { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e01, 0xff, 0xff, 0xff) }, /* D-Link DWM-152/C1 */
- { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e02, 0xff, 0xff, 0xff) }, /* D-Link DWM-156/C1 */
- { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x7e11, 0xff, 0xff, 0xff) }, /* D-Link DWM-156/A3 */
- { USB_DEVICE_INTERFACE_CLASS(0x2020, 0x4000, 0xff) }, /* OLICARD300 - MT6225 */
+ { USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7e3d, 0xff), /* D-Link DWM-222 A2 */
+ .driver_info = RSVD(4) },
+ { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e01, 0xff, 0xff, 0xff) }, /* D-Link DWM-152/C1 */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e02, 0xff, 0xff, 0xff) }, /* D-Link DWM-156/C1 */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x7e11, 0xff, 0xff, 0xff) }, /* D-Link DWM-156/A3 */
+ { USB_DEVICE_INTERFACE_CLASS(0x2020, 0x2031, 0xff), /* Olicard 600 */
+ .driver_info = RSVD(4) },
+ { USB_DEVICE_INTERFACE_CLASS(0x2020, 0x2060, 0xff), /* BroadMobi BM818 */
+ .driver_info = RSVD(4) },
+ { USB_DEVICE_INTERFACE_CLASS(0x2020, 0x4000, 0xff) }, /* OLICARD300 - MT6225 */
{ USB_DEVICE(INOVIA_VENDOR_ID, INOVIA_SEW858) },
{ USB_DEVICE(VIATELECOM_VENDOR_ID, VIATELECOM_PRODUCT_CDS7) },
{ USB_DEVICE_AND_INTERFACE_INFO(WETELECOM_VENDOR_ID, WETELECOM_PRODUCT_WMD200, 0xff, 0xff, 0xff) },
@@ -1953,8 +1993,16 @@
{ USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0xa31d, 0xff, 0x06, 0x13) },
{ USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0xa31d, 0xff, 0x06, 0x14) },
{ USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0xa31d, 0xff, 0x06, 0x1b) },
+ { USB_DEVICE(0x0489, 0xe0b4), /* Foxconn T77W968 */
+ .driver_info = RSVD(0) | RSVD(1) | RSVD(6) },
+ { USB_DEVICE(0x0489, 0xe0b5), /* Foxconn T77W968 ESIM */
+ .driver_info = RSVD(0) | RSVD(1) | RSVD(6) },
{ USB_DEVICE(0x1508, 0x1001), /* Fibocom NL668 */
.driver_info = RSVD(4) | RSVD(5) | RSVD(6) },
+ { USB_DEVICE(0x2cb7, 0x0104), /* Fibocom NL678 series */
+ .driver_info = RSVD(4) | RSVD(5) },
+ { USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x0105, 0xff), /* Fibocom NL678 series */
+ .driver_info = RSVD(6) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, option_ids);
@@ -1980,7 +2028,8 @@
.chars_in_buffer = usb_wwan_chars_in_buffer,
.tiocmget = usb_wwan_tiocmget,
.tiocmset = usb_wwan_tiocmset,
- .ioctl = usb_wwan_ioctl,
+ .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/oti6858.c b/drivers/usb/serial/oti6858.c
index ae9cb15..8151dd7 100644
--- a/drivers/usb/serial/oti6858.c
+++ b/drivers/usb/serial/oti6858.c
@@ -22,7 +22,7 @@
* So, THIS CODE CAN DESTROY OTi-6858 AND ANY OTHER DEVICES, THAT ARE
* CONNECTED TO IT!
*
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
* driver
*
* TODO:
@@ -393,10 +393,7 @@
static void oti6858_init_termios(struct tty_struct *tty)
{
- tty->termios = tty_std_termios;
- tty->termios.c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL;
- tty->termios.c_ispeed = 38400;
- tty->termios.c_ospeed = 38400;
+ tty_encode_baud_rate(tty, 38400, 38400);
}
static void oti6858_set_termios(struct tty_struct *tty,
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index e41f725..9d27b76 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -7,7 +7,7 @@
*
* Original driver for 2.2.x by anonymous
*
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
* driver
*/
@@ -46,6 +46,7 @@
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_HCR331) },
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MOTOROLA) },
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ZTEK) },
+ { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_TB) },
{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },
{ USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID),
@@ -91,15 +92,21 @@
{ USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) },
{ USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) },
{ USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) },
+ { USB_DEVICE(HP_VENDOR_ID, HP_LD220TA_PRODUCT_ID) },
{ USB_DEVICE(HP_VENDOR_ID, HP_LD960_PRODUCT_ID) },
+ { USB_DEVICE(HP_VENDOR_ID, HP_LD960TA_PRODUCT_ID) },
{ USB_DEVICE(HP_VENDOR_ID, HP_LCM220_PRODUCT_ID) },
{ USB_DEVICE(HP_VENDOR_ID, HP_LCM960_PRODUCT_ID) },
+ { USB_DEVICE(HP_VENDOR_ID, HP_LM920_PRODUCT_ID) },
+ { USB_DEVICE(HP_VENDOR_ID, HP_LM940_PRODUCT_ID) },
+ { USB_DEVICE(HP_VENDOR_ID, HP_TD620_PRODUCT_ID) },
{ USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) },
{ USB_DEVICE(ZEAGLE_VENDOR_ID, ZEAGLE_N2ITION3_PRODUCT_ID) },
{ USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) },
{ USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) },
{ USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530_PRODUCT_ID) },
{ USB_DEVICE(SMART_VENDOR_ID, SMART_PRODUCT_ID) },
+ { USB_DEVICE(AT_VENDOR_ID, AT_VTKIT3_PRODUCT_ID) },
{ } /* Terminating entry */
};
@@ -139,6 +146,8 @@
#define UART_OVERRUN_ERROR 0x40
#define UART_CTS 0x80
+#define PL2303_FLOWCTRL_MASK 0xf0
+
static void pl2303_set_break(struct usb_serial_port *port, bool enable);
enum pl2303_type {
@@ -150,6 +159,7 @@
struct pl2303_type_data {
speed_t max_baud_rate;
unsigned long quirks;
+ unsigned int no_autoxonxoff:1;
};
struct pl2303_serial_private {
@@ -167,11 +177,12 @@
static const struct pl2303_type_data pl2303_type_data[TYPE_COUNT] = {
[TYPE_01] = {
- .max_baud_rate = 1228800,
- .quirks = PL2303_QUIRK_LEGACY,
+ .max_baud_rate = 1228800,
+ .quirks = PL2303_QUIRK_LEGACY,
+ .no_autoxonxoff = true,
},
[TYPE_HX] = {
- .max_baud_rate = 12000000,
+ .max_baud_rate = 12000000,
},
};
@@ -217,6 +228,29 @@
return 0;
}
+static int pl2303_update_reg(struct usb_serial *serial, u8 reg, u8 mask, u8 val)
+{
+ int ret = 0;
+ u8 *buf;
+
+ buf = kmalloc(1, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ ret = pl2303_vendor_read(serial, reg | 0x80, buf);
+ if (ret)
+ goto out_free;
+
+ *buf &= ~mask;
+ *buf |= val & mask;
+
+ ret = pl2303_vendor_write(serial, reg, *buf);
+out_free:
+ kfree(buf);
+
+ return ret;
+}
+
static int pl2303_probe(struct usb_serial *serial,
const struct usb_device_id *id)
{
@@ -546,6 +580,20 @@
return tty_termios_hw_change(a, b) || ixon_change;
}
+static bool pl2303_enable_xonxoff(struct tty_struct *tty, const struct pl2303_type_data *type)
+{
+ if (!I_IXON(tty) || I_IXANY(tty))
+ return false;
+
+ if (START_CHAR(tty) != 0x11 || STOP_CHAR(tty) != 0x13)
+ return false;
+
+ if (type->no_autoxonxoff)
+ return false;
+
+ return true;
+}
+
static void pl2303_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios)
{
@@ -672,14 +720,13 @@
if (C_CRTSCTS(tty)) {
if (spriv->quirks & PL2303_QUIRK_LEGACY)
- pl2303_vendor_write(serial, 0x0, 0x41);
+ pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0x40);
else
- pl2303_vendor_write(serial, 0x0, 0x61);
- } else if (I_IXON(tty) && !I_IXANY(tty) && START_CHAR(tty) == 0x11 &&
- STOP_CHAR(tty) == 0x13) {
- pl2303_vendor_write(serial, 0x0, 0xc0);
+ pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0x60);
+ } else if (pl2303_enable_xonxoff(tty, spriv->type)) {
+ pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0xc0);
} else {
- pl2303_vendor_write(serial, 0x0, 0x0);
+ pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0);
}
kfree(buf);
@@ -808,29 +855,16 @@
return 0;
}
-static int pl2303_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
+static int pl2303_get_serial(struct tty_struct *tty,
+ struct serial_struct *ss)
{
- struct serial_struct ser;
struct usb_serial_port *port = tty->driver_data;
- switch (cmd) {
- case TIOCGSERIAL:
- memset(&ser, 0, sizeof ser);
- ser.type = PORT_16654;
- ser.line = port->minor;
- ser.port = port->port_number;
- ser.baud_base = 460800;
-
- if (copy_to_user((void __user *)arg, &ser, sizeof ser))
- return -EFAULT;
-
- return 0;
- default:
- break;
- }
-
- return -ENOIOCTLCMD;
+ 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)
@@ -1016,7 +1050,7 @@
.close = pl2303_close,
.dtr_rts = pl2303_dtr_rts,
.carrier_raised = pl2303_carrier_raised,
- .ioctl = pl2303_ioctl,
+ .get_serial = pl2303_get_serial,
.break_ctl = pl2303_break_ctl,
.set_termios = pl2303_set_termios,
.tiocmget = pl2303_tiocmget,
diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h
index 26965cc..b0175f1 100644
--- a/drivers/usb/serial/pl2303.h
+++ b/drivers/usb/serial/pl2303.h
@@ -8,6 +8,7 @@
#define PL2303_VENDOR_ID 0x067b
#define PL2303_PRODUCT_ID 0x2303
+#define PL2303_PRODUCT_ID_TB 0x2304
#define PL2303_PRODUCT_ID_RSAQ2 0x04bb
#define PL2303_PRODUCT_ID_DCU11 0x1234
#define PL2303_PRODUCT_ID_PHAROS 0xaaa0
@@ -20,6 +21,7 @@
#define PL2303_PRODUCT_ID_MOTOROLA 0x0307
#define PL2303_PRODUCT_ID_ZTEK 0xe1f1
+
#define ATEN_VENDOR_ID 0x0557
#define ATEN_VENDOR_ID2 0x0547
#define ATEN_PRODUCT_ID 0x2008
@@ -119,10 +121,15 @@
/* Hewlett-Packard POS Pole Displays */
#define HP_VENDOR_ID 0x03f0
+#define HP_LM920_PRODUCT_ID 0x026b
+#define HP_TD620_PRODUCT_ID 0x0956
#define HP_LD960_PRODUCT_ID 0x0b39
#define HP_LCM220_PRODUCT_ID 0x3139
#define HP_LCM960_PRODUCT_ID 0x3239
#define HP_LD220_PRODUCT_ID 0x3524
+#define HP_LD220TA_PRODUCT_ID 0x4349
+#define HP_LD960TA_PRODUCT_ID 0x4439
+#define HP_LM940_PRODUCT_ID 0x5039
/* Cressi Edy (diving computer) PC interface */
#define CRESSI_VENDOR_ID 0x04b8
@@ -148,3 +155,6 @@
#define SMART_VENDOR_ID 0x0b8c
#define SMART_PRODUCT_ID 0x2303
+/* Allied Telesis VT-Kit3 */
+#define AT_VENDOR_ID 0x0caa
+#define AT_VTKIT3_PRODUCT_ID 0x3001
diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c
index b61c2a9..a62981c 100644
--- a/drivers/usb/serial/quatech2.c
+++ b/drivers/usb/serial/quatech2.c
@@ -453,39 +453,19 @@
usb_kill_urb(serial_priv->read_urb);
}
-static int get_serial_info(struct usb_serial_port *port,
- struct serial_struct __user *retinfo)
-{
- struct serial_struct tmp;
-
- memset(&tmp, 0, sizeof(tmp));
- tmp.line = port->minor;
- tmp.port = 0;
- tmp.irq = 0;
- tmp.xmit_fifo_size = port->bulk_out_size;
- tmp.baud_base = 9600;
- tmp.close_delay = 5*HZ;
- tmp.closing_wait = 30*HZ;
-
- if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
- return -EFAULT;
- return 0;
-}
-
-static int qt2_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
+static int get_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss)
{
struct usb_serial_port *port = tty->driver_data;
- switch (cmd) {
- case TIOCGSERIAL:
- return get_serial_info(port,
- (struct serial_struct __user *)arg);
- default:
- break;
- }
-
- return -ENOIOCTLCMD;
+ 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)
@@ -520,7 +500,6 @@
struct usb_serial *serial;
struct qt2_serial_private *serial_priv;
struct usb_serial_port *port;
- struct qt2_port_private *port_priv;
bool escapeflag;
unsigned char *ch;
int i;
@@ -534,7 +513,6 @@
serial = urb->context;
serial_priv = usb_get_serial_data(serial);
port = serial->port[serial_priv->current_port];
- port_priv = usb_get_serial_port_data(port);
for (i = 0; i < urb->actual_length; i++) {
ch = (unsigned char *)urb->transfer_buffer + i;
@@ -586,7 +564,6 @@
serial_priv->current_port = newport;
port = serial->port[serial_priv->current_port];
- port_priv = usb_get_serial_port_data(port);
i += 3;
escapeflag = true;
break;
@@ -1013,7 +990,7 @@
.tiocmset = qt2_tiocmset,
.tiocmiwait = usb_serial_generic_tiocmiwait,
.get_icount = usb_serial_generic_get_icount,
- .ioctl = qt2_ioctl,
+ .get_serial = get_serial_info,
.set_termios = qt2_set_termios,
};
diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c
index b427148..3bac55b 100644
--- a/drivers/usb/serial/spcp8x5.c
+++ b/drivers/usb/serial/spcp8x5.c
@@ -281,10 +281,7 @@
static void spcp8x5_init_termios(struct tty_struct *tty)
{
- tty->termios = tty_std_termios;
- tty->termios.c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL;
- tty->termios.c_ispeed = 115200;
- tty->termios.c_ospeed = 115200;
+ tty_encode_baud_rate(tty, 115200, 115200);
}
static void spcp8x5_set_termios(struct tty_struct *tty,
diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c
index 0900b47..f6aea9f 100644
--- a/drivers/usb/serial/ssu100.c
+++ b/drivers/usb/serial/ssu100.c
@@ -331,39 +331,19 @@
return usb_serial_generic_open(tty, port);
}
-static int get_serial_info(struct usb_serial_port *port,
- struct serial_struct __user *retinfo)
-{
- struct serial_struct tmp;
-
- memset(&tmp, 0, sizeof(tmp));
- tmp.line = port->minor;
- tmp.port = 0;
- tmp.irq = 0;
- tmp.xmit_fifo_size = port->bulk_out_size;
- tmp.baud_base = 9600;
- tmp.close_delay = 5*HZ;
- tmp.closing_wait = 30*HZ;
-
- if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
- return -EFAULT;
- return 0;
-}
-
-static int ssu100_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
+static int get_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss)
{
struct usb_serial_port *port = tty->driver_data;
- switch (cmd) {
- case TIOCGSERIAL:
- return get_serial_info(port,
- (struct serial_struct __user *) arg);
- default:
- break;
- }
-
- return -ENOIOCTLCMD;
+ 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)
@@ -566,7 +546,7 @@
.tiocmset = ssu100_tiocmset,
.tiocmiwait = usb_serial_generic_tiocmiwait,
.get_icount = usb_serial_generic_get_icount,
- .ioctl = ssu100_ioctl,
+ .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 e3c5832..ef23acc 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -313,8 +313,6 @@
static bool ti_tx_empty(struct usb_serial_port *port);
static void ti_throttle(struct tty_struct *tty);
static void ti_unthrottle(struct tty_struct *tty);
-static int ti_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg);
static void ti_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios);
static int ti_tiocmget(struct tty_struct *tty);
@@ -330,10 +328,10 @@
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 ti_port *tport,
- struct serial_struct __user *ret_arg);
-static int ti_set_serial_info(struct tty_struct *tty, struct ti_port *tport,
- struct serial_struct __user *new_arg);
+static 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_handle_new_msr(struct ti_port *tport, u8 msr);
static void ti_stop_read(struct ti_port *tport, struct tty_struct *tty);
@@ -436,7 +434,8 @@
.tx_empty = ti_tx_empty,
.throttle = ti_throttle,
.unthrottle = ti_unthrottle,
- .ioctl = ti_ioctl,
+ .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 +468,8 @@
.tx_empty = ti_tx_empty,
.throttle = ti_throttle,
.unthrottle = ti_unthrottle,
- .ioctl = ti_ioctl,
+ .get_serial = ti_get_serial_info,
+ .set_serial = ti_set_serial_info,
.set_termios = ti_set_termios,
.tiocmget = ti_tiocmget,
.tiocmset = ti_tiocmset,
@@ -776,7 +776,6 @@
struct ti_port *tport;
int port_number;
int status;
- int do_unlock;
unsigned long flags;
tdev = usb_get_serial_data(port->serial);
@@ -800,16 +799,13 @@
"%s - cannot send close port command, %d\n"
, __func__, status);
- /* if mutex_lock is interrupted, continue anyway */
- do_unlock = !mutex_lock_interruptible(&tdev->td_open_close_lock);
- --tport->tp_tdev->td_open_port_count;
- if (tport->tp_tdev->td_open_port_count <= 0) {
+ mutex_lock(&tdev->td_open_close_lock);
+ --tdev->td_open_port_count;
+ if (tdev->td_open_port_count == 0) {
/* last port is closed, shut down interrupt urb */
usb_kill_urb(port->serial->port[0]->interrupt_in_urb);
- tport->tp_tdev->td_open_port_count = 0;
}
- if (do_unlock)
- mutex_unlock(&tdev->td_open_close_lock);
+ mutex_unlock(&tdev->td_open_close_lock);
}
@@ -902,24 +898,6 @@
}
}
-static int ti_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct ti_port *tport = usb_get_serial_port_data(port);
-
- switch (cmd) {
- case TIOCGSERIAL:
- return ti_get_serial_info(tport,
- (struct serial_struct __user *)arg);
- case TIOCSSERIAL:
- return ti_set_serial_info(tty, tport,
- (struct serial_struct __user *)arg);
- }
- return -ENOIOCTLCMD;
-}
-
-
static void ti_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios)
{
@@ -1417,45 +1395,37 @@
}
-static int ti_get_serial_info(struct ti_port *tport,
- struct serial_struct __user *ret_arg)
+static int ti_get_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss)
{
- struct usb_serial_port *port = tport->tp_port;
- struct serial_struct ret_serial;
+ 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;
- memset(&ret_serial, 0, sizeof(ret_serial));
-
- ret_serial.type = PORT_16550A;
- ret_serial.line = port->minor;
- ret_serial.port = port->port_number;
- ret_serial.xmit_fifo_size = kfifo_size(&port->write_fifo);
- ret_serial.baud_base = tport->tp_tdev->td_is_3410 ? 921600 : 460800;
- ret_serial.closing_wait = cwait;
-
- if (copy_to_user(ret_arg, &ret_serial, sizeof(*ret_arg)))
- return -EFAULT;
-
+ 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 ti_port *tport,
- struct serial_struct __user *new_arg)
+static int ti_set_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss)
{
- struct serial_struct new_serial;
+ struct usb_serial_port *port = tty->driver_data;
+ struct ti_port *tport = usb_get_serial_port_data(port);
unsigned cwait;
- if (copy_from_user(&new_serial, new_arg, sizeof(new_serial)))
- return -EFAULT;
-
- cwait = new_serial.closing_wait;
+ cwait = ss->closing_wait;
if (cwait != ASYNC_CLOSING_WAIT_NONE)
- cwait = msecs_to_jiffies(10 * new_serial.closing_wait);
+ cwait = msecs_to_jiffies(10 * ss->closing_wait);
tport->tp_port->port.closing_wait = cwait;
diff --git a/drivers/usb/serial/usb-serial-simple.c b/drivers/usb/serial/usb-serial-simple.c
index 4d02735..edbbb13 100644
--- a/drivers/usb/serial/usb-serial-simple.c
+++ b/drivers/usb/serial/usb-serial-simple.c
@@ -85,7 +85,8 @@
/* Motorola Tetra driver */
#define MOTOROLA_TETRA_IDS() \
{ USB_DEVICE(0x0cad, 0x9011) }, /* Motorola Solutions TETRA PEI */ \
- { USB_DEVICE(0x0cad, 0x9012) } /* MTP6550 */
+ { USB_DEVICE(0x0cad, 0x9012) }, /* MTP6550 */ \
+ { USB_DEVICE(0x0cad, 0x9016) } /* TPG2200 */
DEVICE(motorola_tetra, MOTOROLA_TETRA_IDS);
/* Novatel Wireless GPS driver */
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index f7aaa7f..8f066bb 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -10,7 +10,7 @@
* This driver was originally based on the ACM driver by Armin Fuerst (which was
* based on a driver by Brad Keryan)
*
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
* driver
*/
@@ -164,9 +164,9 @@
* @driver: the driver (USB in our case)
* @tty: the tty being created
*
- * Create the termios objects for this tty. We use the default
+ * Initialise the termios structure for this tty. We use the default
* USB serial settings but permit them to be overridden by
- * serial->type->init_termios.
+ * serial->type->init_termios on first open.
*
* This is the first place a new tty gets used. Hence this is where we
* acquire references to the usb_serial structure and the driver module,
@@ -178,6 +178,7 @@
int idx = tty->index;
struct usb_serial *serial;
struct usb_serial_port *port;
+ bool init_termios;
int retval = -ENODEV;
port = usb_serial_port_get_by_minor(idx);
@@ -192,14 +193,16 @@
if (retval)
goto error_get_interface;
+ init_termios = (driver->termios[idx] == NULL);
+
retval = tty_standard_install(driver, tty);
if (retval)
goto error_init_termios;
mutex_unlock(&serial->disc_mutex);
- /* allow the driver to update the settings */
- if (serial->type->init_termios)
+ /* allow the driver to update the initial settings */
+ if (init_termios && serial->type->init_termios)
serial->type->init_termios(tty);
tty->driver_data = port;
@@ -311,10 +314,7 @@
serial = port->serial;
owner = serial->type->driver.owner;
- mutex_lock(&serial->disc_mutex);
- if (!serial->disconnected)
- usb_autopm_put_interface(serial->interface);
- mutex_unlock(&serial->disc_mutex);
+ usb_autopm_put_interface(serial->interface);
usb_serial_put(serial);
module_put(owner);
@@ -396,6 +396,24 @@
port->serial->type->unthrottle(tty);
}
+static int serial_get_serial(struct tty_struct *tty, struct serial_struct *ss)
+{
+ struct usb_serial_port *port = tty->driver_data;
+
+ if (port->serial->type->get_serial)
+ return port->serial->type->get_serial(tty, ss);
+ return -ENOTTY;
+}
+
+static int serial_set_serial(struct tty_struct *tty, struct serial_struct *ss)
+{
+ struct usb_serial_port *port = tty->driver_data;
+
+ if (port->serial->type->set_serial)
+ return port->serial->type->set_serial(tty, ss);
+ return -ENOTTY;
+}
+
static int serial_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
@@ -1177,6 +1195,8 @@
.tiocmget = serial_tiocmget,
.tiocmset = serial_tiocmset,
.get_icount = serial_get_icount,
+ .set_serial = serial_set_serial,
+ .get_serial = serial_get_serial,
.cleanup = serial_cleanup,
.install = serial_install,
.proc_show = serial_proc_show,
diff --git a/drivers/usb/serial/usb-wwan.h b/drivers/usb/serial/usb-wwan.h
index d28dab4..1c120ea 100644
--- a/drivers/usb/serial/usb-wwan.h
+++ b/drivers/usb/serial/usb-wwan.h
@@ -15,8 +15,10 @@
extern int usb_wwan_tiocmget(struct tty_struct *tty);
extern int usb_wwan_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear);
-extern int usb_wwan_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg);
+extern int usb_wwan_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 912472f..7e855c8 100644
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
@@ -132,38 +132,32 @@
}
EXPORT_SYMBOL(usb_wwan_tiocmset);
-static int get_serial_info(struct usb_serial_port *port,
- struct serial_struct __user *retinfo)
+int usb_wwan_get_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss)
{
- struct serial_struct tmp;
+ struct usb_serial_port *port = tty->driver_data;
- memset(&tmp, 0, sizeof(tmp));
- tmp.line = port->minor;
- tmp.port = port->port_number;
- tmp.baud_base = tty_get_baud_rate(port->port.tty);
- tmp.close_delay = port->port.close_delay / 10;
- tmp.closing_wait = port->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
+ 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;
-
- if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
- return -EFAULT;
return 0;
}
+EXPORT_SYMBOL(usb_wwan_get_serial_info);
-static int set_serial_info(struct usb_serial_port *port,
- struct serial_struct __user *newinfo)
+int usb_wwan_set_serial_info(struct tty_struct *tty,
+ struct serial_struct *ss)
{
- struct serial_struct new_serial;
+ struct usb_serial_port *port = tty->driver_data;
unsigned int closing_wait, close_delay;
int retval = 0;
- if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
- return -EFAULT;
-
- close_delay = new_serial.close_delay * 10;
- closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
- ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10;
+ 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);
@@ -181,30 +175,7 @@
mutex_unlock(&port->port.mutex);
return retval;
}
-
-int usb_wwan_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
-{
- struct usb_serial_port *port = tty->driver_data;
-
- dev_dbg(&port->dev, "%s cmd 0x%04x\n", __func__, cmd);
-
- switch (cmd) {
- case TIOCGSERIAL:
- return get_serial_info(port,
- (struct serial_struct __user *) arg);
- case TIOCSSERIAL:
- return set_serial_info(port,
- (struct serial_struct __user *) arg);
- default:
- break;
- }
-
- dev_dbg(&port->dev, "%s arg not supported\n", __func__);
-
- return -ENOIOCTLCMD;
-}
-EXPORT_SYMBOL(usb_wwan_ioctl);
+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/visor.c b/drivers/usb/serial/visor.c
index 8ddbecc..4412834 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -6,7 +6,7 @@
* Copyright (C) 1999 - 2004
* Greg Kroah-Hartman (greg@kroah.com)
*
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
* driver
*
*/
diff --git a/drivers/usb/serial/visor.h b/drivers/usb/serial/visor.h
index fe29024..4bd69d0 100644
--- a/drivers/usb/serial/visor.h
+++ b/drivers/usb/serial/visor.h
@@ -5,7 +5,7 @@
* Copyright (C) 1999 - 2003
* Greg Kroah-Hartman (greg@kroah.com)
*
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
* driver.
*
*/
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index 1c7b46a..ca3bd58 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -8,7 +8,7 @@
* Copyright (C) 1999 - 2001
* Greg Kroah-Hartman (greg@kroah.com)
*
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
* driver
*/
@@ -83,8 +83,8 @@
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_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg);
+static int 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);
static int whiteheat_tiocmget(struct tty_struct *tty);
@@ -120,7 +120,7 @@
.port_remove = whiteheat_port_remove,
.open = whiteheat_open,
.close = whiteheat_close,
- .ioctl = whiteheat_ioctl,
+ .get_serial = whiteheat_get_serial,
.set_termios = whiteheat_set_termios,
.break_ctl = whiteheat_break_ctl,
.tiocmget = whiteheat_tiocmget,
@@ -442,33 +442,21 @@
}
-static int whiteheat_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
+static int whiteheat_get_serial(struct tty_struct *tty,
+ struct serial_struct *ss)
{
struct usb_serial_port *port = tty->driver_data;
- struct serial_struct serstruct;
- void __user *user_arg = (void __user *)arg;
- switch (cmd) {
- case TIOCGSERIAL:
- memset(&serstruct, 0, sizeof(serstruct));
- serstruct.type = PORT_16654;
- serstruct.line = port->minor;
- serstruct.port = port->port_number;
- serstruct.xmit_fifo_size = kfifo_size(&port->write_fifo);
- serstruct.custom_divisor = 0;
- serstruct.baud_base = 460800;
- serstruct.close_delay = CLOSING_DELAY;
- serstruct.closing_wait = CLOSING_DELAY;
+ 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;
- if (copy_to_user(user_arg, &serstruct, sizeof(serstruct)))
- return -EFAULT;
- break;
- default:
- break;
- }
-
- return -ENOIOCTLCMD;
+ return 0;
}
@@ -571,6 +559,10 @@
command_port = port->serial->port[COMMAND_PORT];
command_info = usb_get_serial_port_data(command_port);
+
+ if (command_port->bulk_out_size < datasize + 1)
+ return -EIO;
+
mutex_lock(&command_info->mutex);
command_info->command_finished = false;
@@ -644,6 +636,7 @@
struct device *dev = &port->dev;
struct whiteheat_port_settings port_settings;
unsigned int cflag = tty->termios.c_cflag;
+ speed_t baud;
port_settings.port = port->port_number + 1;
@@ -704,11 +697,13 @@
dev_dbg(dev, "%s - XON = %2x, XOFF = %2x\n", __func__, port_settings.xon, port_settings.xoff);
/* get the baud rate wanted */
- port_settings.baud = tty_get_baud_rate(tty);
- dev_dbg(dev, "%s - baud rate = %d\n", __func__, port_settings.baud);
+ baud = tty_get_baud_rate(tty);
+ port_settings.baud = cpu_to_le32(baud);
+ dev_dbg(dev, "%s - baud rate = %u\n", __func__, baud);
/* fixme: should set validated settings */
- tty_encode_baud_rate(tty, port_settings.baud, port_settings.baud);
+ tty_encode_baud_rate(tty, baud, baud);
+
/* handle any settings that aren't specified in the tty structure */
port_settings.lloop = 0;
diff --git a/drivers/usb/serial/whiteheat.h b/drivers/usb/serial/whiteheat.h
index 72c1b0c..269e727 100644
--- a/drivers/usb/serial/whiteheat.h
+++ b/drivers/usb/serial/whiteheat.h
@@ -8,7 +8,7 @@
* Copyright (C) 1999, 2000
* Greg Kroah-Hartman (greg@kroah.com)
*
- * See Documentation/usb/usb-serial.txt for more information on using this
+ * See Documentation/usb/usb-serial.rst for more information on using this
* driver
*
*/
@@ -87,7 +87,7 @@
struct whiteheat_port_settings {
__u8 port; /* port number (1 to N) */
- __u32 baud; /* any value 7 - 460800, firmware calculates
+ __le32 baud; /* any value 7 - 460800, firmware calculates
best fit; arrives little endian */
__u8 bits; /* 5, 6, 7, or 8 */
__u8 stop; /* 1 or 2, default 1 (2 = 1.5 if bits = 5) */