USB-serial updates for 5.12-rc1

Here are the USB-serial updates for 5.12-rc1, including:
 
  - a line-speed fix for newer pl2303 devices
  - a line-speed fix for FTDI FT-X devices
  - a new xr_serial driver for MaxLinear/Exar devices (non-ACM mode)
  - a cdc-acm blacklist entry for when the xr_serial driver is enabled
  - cp210x support for software flow control
  - various cp210x modem-control fixes
  - an updated ZTE P685M modem entry to stop claiming the QMI interface
  - an update to drop the port_remove() driver-callback return value
 
 Included are also various clean ups.
 
 All have been in linux-next with no reported issues.
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYIAB0WIQQHbPq+cpGvN/peuzMLxc3C7H1lCAUCYCPxBQAKCRALxc3C7H1l
 CP1iAQCRn7/4ulkGXgSjVL2o8TfGAQRhvxL14qtzysOyPLwgrAD6ApuJdPRHnetL
 q0TDaRqnXqVTV6uUfoSC5eVEF4dS/Qs=
 =5ZLn
 -----END PGP SIGNATURE-----

Merge tag 'usb-serial-5.12-rc1' of https://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial into usb-next

Johan writes:

USB-serial updates for 5.12-rc1

Here are the USB-serial updates for 5.12-rc1, including:

 - a line-speed fix for newer pl2303 devices
 - a line-speed fix for FTDI FT-X devices
 - a new xr_serial driver for MaxLinear/Exar devices (non-ACM mode)
 - a cdc-acm blacklist entry for when the xr_serial driver is enabled
 - cp210x support for software flow control
 - various cp210x modem-control fixes
 - an updated ZTE P685M modem entry to stop claiming the QMI interface
 - an update to drop the port_remove() driver-callback return value

Included are also various clean ups.

All have been in linux-next with no reported issues.

* tag 'usb-serial-5.12-rc1' of https://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial: (41 commits)
  USB: serial: drop bogus to_usb_serial_port() checks
  USB: serial: make remove callback return void
  USB: serial: drop if with an always false condition
  USB: serial: option: update interface mapping for ZTE P685M
  USB: serial: ftdi_sio: restore divisor-encoding comments
  USB: serial: ftdi_sio: fix FTX sub-integer prescaler
  USB: serial: cp210x: clean up auto-RTS handling
  USB: serial: cp210x: fix RTS handling
  USB: serial: cp210x: clean up printk zero padding
  USB: serial: cp210x: clean up flow-control debug message
  USB: serial: cp210x: drop shift macros
  USB: serial: cp210x: fix modem-control handling
  USB: serial: cp210x: suppress modem-control errors
  USB: serial: mos7720: fix error code in mos7720_write()
  USB: serial: xr: fix B0 handling
  USB: serial: xr: fix pin configuration
  USB: serial: xr: fix gpio-mode handling
  USB: serial: xr: simplify line-speed logic
  USB: serial: xr: clean up line-settings handling
  USB: serial: xr: document vendor-request recipient
  ...
This commit is contained in:
Greg Kroah-Hartman 2021-02-10 15:58:04 +01:00
commit c85bfed171
44 changed files with 888 additions and 225 deletions

View File

@ -1901,6 +1901,12 @@ static const struct usb_device_id acm_ids[] = {
},
#endif
#if IS_ENABLED(CONFIG_USB_SERIAL_XR)
{ USB_DEVICE(0x04e2, 0x1410), /* Ignore XR21V141X USB to Serial converter */
.driver_info = IGNORE_DEVICE,
},
#endif
/*Samsung phone in firmware update mode */
{ USB_DEVICE(0x04e8, 0x685d),
.driver_info = IGNORE_DEVICE,

View File

@ -633,6 +633,15 @@ config USB_SERIAL_UPD78F0730
To compile this driver as a module, choose M here: the
module will be called upd78f0730.
config USB_SERIAL_XR
tristate "USB MaxLinear/Exar USB to Serial driver"
help
Say Y here if you want to use MaxLinear/Exar USB to Serial converter
devices.
To compile this driver as a module, choose M here: the
module will be called xr_serial.
config USB_SERIAL_DEBUG
tristate "USB Debugging Device"
help

View File

@ -61,4 +61,5 @@ obj-$(CONFIG_USB_SERIAL_UPD78F0730) += upd78f0730.o
obj-$(CONFIG_USB_SERIAL_VISOR) += visor.o
obj-$(CONFIG_USB_SERIAL_WISHBONE) += wishbone-serial.o
obj-$(CONFIG_USB_SERIAL_WHITEHEAT) += whiteheat.o
obj-$(CONFIG_USB_SERIAL_XR) += xr_serial.o
obj-$(CONFIG_USB_SERIAL_XSENS_MT) += xsens_mt.o

View File

@ -178,15 +178,13 @@ static int ark3116_port_probe(struct usb_serial_port *port)
return 0;
}
static int ark3116_port_remove(struct usb_serial_port *port)
static void ark3116_port_remove(struct usb_serial_port *port)
{
struct ark3116_private *priv = usb_get_serial_port_data(port);
/* device is closed, so URBs and DMA should be down */
mutex_destroy(&priv->hw_lock);
kfree(priv);
return 0;
}
static void ark3116_set_termios(struct tty_struct *tty,

View File

@ -37,7 +37,7 @@
/* function prototypes for a Belkin USB Serial Adapter F5U103 */
static int belkin_sa_port_probe(struct usb_serial_port *port);
static int belkin_sa_port_remove(struct usb_serial_port *port);
static void belkin_sa_port_remove(struct usb_serial_port *port);
static int belkin_sa_open(struct tty_struct *tty,
struct usb_serial_port *port);
static void belkin_sa_close(struct usb_serial_port *port);
@ -134,14 +134,12 @@ static int belkin_sa_port_probe(struct usb_serial_port *port)
return 0;
}
static int belkin_sa_port_remove(struct usb_serial_port *port)
static void belkin_sa_port_remove(struct usb_serial_port *port)
{
struct belkin_sa_private *priv;
priv = usb_get_serial_port_data(port);
kfree(priv);
return 0;
}
static int belkin_sa_open(struct tty_struct *tty,

View File

@ -16,19 +16,13 @@
static int usb_serial_device_match(struct device *dev,
struct device_driver *drv)
{
struct usb_serial_driver *driver;
const struct usb_serial_port *port;
const struct usb_serial_port *port = to_usb_serial_port(dev);
struct usb_serial_driver *driver = to_usb_serial_driver(drv);
/*
* drivers are already assigned to ports in serial_probe so it's
* a simple check here.
*/
port = to_usb_serial_port(dev);
if (!port)
return 0;
driver = to_usb_serial_driver(drv);
if (driver == port->serial->type)
return 1;
@ -37,16 +31,12 @@ static int usb_serial_device_match(struct device *dev,
static int usb_serial_device_probe(struct device *dev)
{
struct usb_serial_port *port = to_usb_serial_port(dev);
struct usb_serial_driver *driver;
struct usb_serial_port *port;
struct device *tty_dev;
int retval = 0;
int minor;
port = to_usb_serial_port(dev);
if (!port)
return -ENODEV;
/* make sure suspend/resume doesn't race against port_probe */
retval = usb_autopm_get_interface(port->serial->interface);
if (retval)
@ -86,16 +76,11 @@ err_autopm_put:
static int usb_serial_device_remove(struct device *dev)
{
struct usb_serial_port *port = to_usb_serial_port(dev);
struct usb_serial_driver *driver;
struct usb_serial_port *port;
int retval = 0;
int minor;
int autopm_err;
port = to_usb_serial_port(dev);
if (!port)
return -ENODEV;
/*
* Make sure suspend/resume doesn't race against port_remove.
*
@ -109,7 +94,7 @@ static int usb_serial_device_remove(struct device *dev)
driver = port->serial->type;
if (driver->port_remove)
retval = driver->port_remove(port);
driver->port_remove(port);
dev_info(dev, "%s converter now disconnected from ttyUSB%d\n",
driver->description, minor);
@ -117,7 +102,7 @@ static int usb_serial_device_remove(struct device *dev)
if (!autopm_err)
usb_autopm_put_interface(port->serial->interface);
return retval;
return 0;
}
static ssize_t new_id_store(struct device_driver *driver,

View File

@ -419,14 +419,12 @@ error: kfree(priv);
return r;
}
static int ch341_port_remove(struct usb_serial_port *port)
static void ch341_port_remove(struct usb_serial_port *port)
{
struct ch341_private *priv;
priv = usb_get_serial_port_data(port);
kfree(priv);
return 0;
}
static int ch341_carrier_raised(struct usb_serial_port *port)

View File

@ -3,6 +3,7 @@
* Silicon Laboratories CP210x USB to RS232 serial adaptor driver
*
* Copyright (C) 2005 Craig Shelley (craig@microtron.org.uk)
* Copyright (C) 2010-2021 Johan Hovold (johan@kernel.org)
*
* Support to set flow control line levels using TIOCMGET and TIOCMSET
* thanks to Karl Hiramoto karl@hiramoto.org. RTSCTS hardware flow
@ -16,9 +17,7 @@
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/usb.h>
#include <linux/uaccess.h>
#include <linux/usb/serial.h>
#include <linux/gpio/driver.h>
#include <linux/bitops.h>
@ -45,7 +44,7 @@ static int cp210x_attach(struct usb_serial *);
static void cp210x_disconnect(struct usb_serial *);
static void cp210x_release(struct usb_serial *);
static int cp210x_port_probe(struct usb_serial_port *);
static int cp210x_port_remove(struct usb_serial_port *);
static void cp210x_port_remove(struct usb_serial_port *);
static void cp210x_dtr_rts(struct usb_serial_port *port, int on);
static void cp210x_process_read_urb(struct urb *urb);
static void cp210x_enable_event_mode(struct usb_serial_port *port);
@ -268,7 +267,12 @@ struct cp210x_port_private {
u8 bInterfaceNumber;
bool event_mode;
enum cp210x_event_state event_state;
u8 lsr;
u8 lsr;
struct mutex mutex;
bool crtscts;
bool dtr;
bool rts;
};
static struct usb_serial_driver cp210x_device = {
@ -379,6 +383,16 @@ static struct usb_serial_driver * const serial_drivers[] = {
#define CONTROL_WRITE_DTR 0x0100
#define CONTROL_WRITE_RTS 0x0200
/* CP210X_(GET|SET)_CHARS */
struct cp210x_special_chars {
u8 bEofChar;
u8 bErrorChar;
u8 bBreakChar;
u8 bEventChar;
u8 bXonChar;
u8 bXoffChar;
};
/* CP210X_VENDOR_SPECIFIC values */
#define CP210X_READ_2NCONFIG 0x000E
#define CP210X_READ_LATCH 0x00C2
@ -437,17 +451,14 @@ struct cp210x_flow_ctl {
/* cp210x_flow_ctl::ulControlHandshake */
#define CP210X_SERIAL_DTR_MASK GENMASK(1, 0)
#define CP210X_SERIAL_DTR_SHIFT(_mode) (_mode)
#define CP210X_SERIAL_DTR_INACTIVE (0 << 0)
#define CP210X_SERIAL_DTR_ACTIVE (1 << 0)
#define CP210X_SERIAL_DTR_FLOW_CTL (2 << 0)
#define CP210X_SERIAL_CTS_HANDSHAKE BIT(3)
#define CP210X_SERIAL_DSR_HANDSHAKE BIT(4)
#define CP210X_SERIAL_DCD_HANDSHAKE BIT(5)
#define CP210X_SERIAL_DSR_SENSITIVITY BIT(6)
/* values for cp210x_flow_ctl::ulControlHandshake::CP210X_SERIAL_DTR_MASK */
#define CP210X_SERIAL_DTR_INACTIVE 0
#define CP210X_SERIAL_DTR_ACTIVE 1
#define CP210X_SERIAL_DTR_FLOW_CTL 2
/* cp210x_flow_ctl::ulFlowReplace */
#define CP210X_SERIAL_AUTO_TRANSMIT BIT(0)
#define CP210X_SERIAL_AUTO_RECEIVE BIT(1)
@ -455,14 +466,11 @@ struct cp210x_flow_ctl {
#define CP210X_SERIAL_NULL_STRIPPING BIT(3)
#define CP210X_SERIAL_BREAK_CHAR BIT(4)
#define CP210X_SERIAL_RTS_MASK GENMASK(7, 6)
#define CP210X_SERIAL_RTS_SHIFT(_mode) (_mode << 6)
#define CP210X_SERIAL_RTS_INACTIVE (0 << 6)
#define CP210X_SERIAL_RTS_ACTIVE (1 << 6)
#define CP210X_SERIAL_RTS_FLOW_CTL (2 << 6)
#define CP210X_SERIAL_XOFF_CONTINUE BIT(31)
/* values for cp210x_flow_ctl::ulFlowReplace::CP210X_SERIAL_RTS_MASK */
#define CP210X_SERIAL_RTS_INACTIVE 0
#define CP210X_SERIAL_RTS_ACTIVE 1
#define CP210X_SERIAL_RTS_FLOW_CTL 2
/* CP210X_VENDOR_SPECIFIC, CP210X_GET_DEVICEMODE call reads these 0x2 bytes. */
struct cp210x_pin_mode {
u8 eci;
@ -666,16 +674,13 @@ static int cp210x_write_reg_block(struct usb_serial_port *port, u8 req,
kfree(dmabuf);
if (result == bufsize) {
result = 0;
} else {
if (result < 0) {
dev_err(&port->dev, "failed set req 0x%x size %d status: %d\n",
req, bufsize, result);
if (result >= 0)
result = -EIO;
return result;
}
return result;
return 0;
}
/*
@ -712,17 +717,14 @@ static int cp210x_write_vendor_block(struct usb_serial *serial, u8 type,
kfree(dmabuf);
if (result == bufsize) {
result = 0;
} else {
if (result < 0) {
dev_err(&serial->interface->dev,
"failed to set vendor val 0x%04x size %d: %d\n", val,
bufsize, result);
if (result >= 0)
result = -EIO;
return result;
}
return result;
return 0;
}
#endif
@ -1076,30 +1078,80 @@ static void cp210x_disable_event_mode(struct usb_serial_port *port)
port_priv->event_mode = false;
}
static int cp210x_set_chars(struct usb_serial_port *port,
struct cp210x_special_chars *chars)
{
struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);
struct usb_serial *serial = port->serial;
void *dmabuf;
int result;
dmabuf = kmemdup(chars, sizeof(*chars), GFP_KERNEL);
if (!dmabuf)
return -ENOMEM;
result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
CP210X_SET_CHARS, REQTYPE_HOST_TO_INTERFACE, 0,
port_priv->bInterfaceNumber,
dmabuf, sizeof(*chars), USB_CTRL_SET_TIMEOUT);
kfree(dmabuf);
if (result < 0) {
dev_err(&port->dev, "failed to set special chars: %d\n", result);
return result;
}
return 0;
}
static bool cp210x_termios_change(const struct ktermios *a, const struct ktermios *b)
{
bool iflag_change;
bool iflag_change, cc_change;
iflag_change = ((a->c_iflag ^ b->c_iflag) & INPCK);
iflag_change = ((a->c_iflag ^ b->c_iflag) & (INPCK | IXON | IXOFF));
cc_change = a->c_cc[VSTART] != b->c_cc[VSTART] ||
a->c_cc[VSTOP] != b->c_cc[VSTOP];
return tty_termios_hw_change(a, b) || iflag_change;
return tty_termios_hw_change(a, b) || iflag_change || cc_change;
}
static void cp210x_set_flow_control(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios)
{
struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);
struct cp210x_special_chars chars;
struct cp210x_flow_ctl flow_ctl;
u32 flow_repl;
u32 ctl_hs;
int ret;
if (old_termios && C_CRTSCTS(tty) == (old_termios->c_cflag & CRTSCTS))
if (old_termios &&
C_CRTSCTS(tty) == (old_termios->c_cflag & CRTSCTS) &&
I_IXON(tty) == (old_termios->c_iflag & IXON) &&
I_IXOFF(tty) == (old_termios->c_iflag & IXOFF) &&
START_CHAR(tty) == old_termios->c_cc[VSTART] &&
STOP_CHAR(tty) == old_termios->c_cc[VSTOP]) {
return;
}
if (I_IXON(tty) || I_IXOFF(tty)) {
memset(&chars, 0, sizeof(chars));
chars.bXonChar = START_CHAR(tty);
chars.bXoffChar = STOP_CHAR(tty);
ret = cp210x_set_chars(port, &chars);
if (ret)
return;
}
mutex_lock(&port_priv->mutex);
ret = cp210x_read_reg_block(port, CP210X_GET_FLOW, &flow_ctl,
sizeof(flow_ctl));
if (ret)
return;
goto out_unlock;
ctl_hs = le32_to_cpu(flow_ctl.ulControlHandshake);
flow_repl = le32_to_cpu(flow_ctl.ulFlowReplace);
@ -1108,26 +1160,51 @@ static void cp210x_set_flow_control(struct tty_struct *tty,
ctl_hs &= ~CP210X_SERIAL_DCD_HANDSHAKE;
ctl_hs &= ~CP210X_SERIAL_DSR_SENSITIVITY;
ctl_hs &= ~CP210X_SERIAL_DTR_MASK;
ctl_hs |= CP210X_SERIAL_DTR_SHIFT(CP210X_SERIAL_DTR_ACTIVE);
if (port_priv->dtr)
ctl_hs |= CP210X_SERIAL_DTR_ACTIVE;
else
ctl_hs |= CP210X_SERIAL_DTR_INACTIVE;
flow_repl &= ~CP210X_SERIAL_RTS_MASK;
if (C_CRTSCTS(tty)) {
ctl_hs |= CP210X_SERIAL_CTS_HANDSHAKE;
flow_repl &= ~CP210X_SERIAL_RTS_MASK;
flow_repl |= CP210X_SERIAL_RTS_SHIFT(CP210X_SERIAL_RTS_FLOW_CTL);
if (port_priv->rts)
flow_repl |= CP210X_SERIAL_RTS_FLOW_CTL;
else
flow_repl |= CP210X_SERIAL_RTS_INACTIVE;
port_priv->crtscts = true;
} else {
ctl_hs &= ~CP210X_SERIAL_CTS_HANDSHAKE;
flow_repl &= ~CP210X_SERIAL_RTS_MASK;
flow_repl |= CP210X_SERIAL_RTS_SHIFT(CP210X_SERIAL_RTS_ACTIVE);
if (port_priv->rts)
flow_repl |= CP210X_SERIAL_RTS_ACTIVE;
else
flow_repl |= CP210X_SERIAL_RTS_INACTIVE;
port_priv->crtscts = false;
}
dev_dbg(&port->dev, "%s - ulControlHandshake=0x%08x, ulFlowReplace=0x%08x\n",
__func__, ctl_hs, flow_repl);
if (I_IXOFF(tty))
flow_repl |= CP210X_SERIAL_AUTO_RECEIVE;
else
flow_repl &= ~CP210X_SERIAL_AUTO_RECEIVE;
if (I_IXON(tty))
flow_repl |= CP210X_SERIAL_AUTO_TRANSMIT;
else
flow_repl &= ~CP210X_SERIAL_AUTO_TRANSMIT;
flow_ctl.ulXonLimit = cpu_to_le32(128);
flow_ctl.ulXoffLimit = cpu_to_le32(128);
dev_dbg(&port->dev, "%s - ctrl = 0x%02x, flow = 0x%02x\n", __func__,
ctl_hs, flow_repl);
flow_ctl.ulControlHandshake = cpu_to_le32(ctl_hs);
flow_ctl.ulFlowReplace = cpu_to_le32(flow_repl);
cp210x_write_reg_block(port, CP210X_SET_FLOW, &flow_ctl,
sizeof(flow_ctl));
out_unlock:
mutex_unlock(&port_priv->mutex);
}
static void cp210x_set_termios(struct tty_struct *tty,
@ -1212,28 +1289,77 @@ static int cp210x_tiocmset(struct tty_struct *tty,
static int cp210x_tiocmset_port(struct usb_serial_port *port,
unsigned int set, unsigned int clear)
{
struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);
struct cp210x_flow_ctl flow_ctl;
u32 ctl_hs, flow_repl;
u16 control = 0;
int ret;
mutex_lock(&port_priv->mutex);
if (set & TIOCM_RTS) {
port_priv->rts = true;
control |= CONTROL_RTS;
control |= CONTROL_WRITE_RTS;
}
if (set & TIOCM_DTR) {
port_priv->dtr = true;
control |= CONTROL_DTR;
control |= CONTROL_WRITE_DTR;
}
if (clear & TIOCM_RTS) {
port_priv->rts = false;
control &= ~CONTROL_RTS;
control |= CONTROL_WRITE_RTS;
}
if (clear & TIOCM_DTR) {
port_priv->dtr = false;
control &= ~CONTROL_DTR;
control |= CONTROL_WRITE_DTR;
}
dev_dbg(&port->dev, "%s - control = 0x%.4x\n", __func__, control);
/*
* Use SET_FLOW to set DTR and enable/disable auto-RTS when hardware
* flow control is enabled.
*/
if (port_priv->crtscts && control & CONTROL_WRITE_RTS) {
ret = cp210x_read_reg_block(port, CP210X_GET_FLOW, &flow_ctl,
sizeof(flow_ctl));
if (ret)
goto out_unlock;
return cp210x_write_u16_reg(port, CP210X_SET_MHS, control);
ctl_hs = le32_to_cpu(flow_ctl.ulControlHandshake);
flow_repl = le32_to_cpu(flow_ctl.ulFlowReplace);
ctl_hs &= ~CP210X_SERIAL_DTR_MASK;
if (port_priv->dtr)
ctl_hs |= CP210X_SERIAL_DTR_ACTIVE;
else
ctl_hs |= CP210X_SERIAL_DTR_INACTIVE;
flow_repl &= ~CP210X_SERIAL_RTS_MASK;
if (port_priv->rts)
flow_repl |= CP210X_SERIAL_RTS_FLOW_CTL;
else
flow_repl |= CP210X_SERIAL_RTS_INACTIVE;
flow_ctl.ulControlHandshake = cpu_to_le32(ctl_hs);
flow_ctl.ulFlowReplace = cpu_to_le32(flow_repl);
dev_dbg(&port->dev, "%s - ctrl = 0x%02x, flow = 0x%02x\n",
__func__, ctl_hs, flow_repl);
ret = cp210x_write_reg_block(port, CP210X_SET_FLOW, &flow_ctl,
sizeof(flow_ctl));
} else {
dev_dbg(&port->dev, "%s - control = 0x%04x\n", __func__, control);
ret = cp210x_write_u16_reg(port, CP210X_SET_MHS, control);
}
out_unlock:
mutex_unlock(&port_priv->mutex);
return ret;
}
static void cp210x_dtr_rts(struct usb_serial_port *port, int on)
@ -1261,7 +1387,7 @@ static int cp210x_tiocmget(struct tty_struct *tty)
|((control & CONTROL_RING)? TIOCM_RI : 0)
|((control & CONTROL_DCD) ? TIOCM_CD : 0);
dev_dbg(&port->dev, "%s - control = 0x%.2x\n", __func__, control);
dev_dbg(&port->dev, "%s - control = 0x%02x\n", __func__, control);
return result;
}
@ -1710,20 +1836,19 @@ static int cp210x_port_probe(struct usb_serial_port *port)
return -ENOMEM;
port_priv->bInterfaceNumber = cp210x_interface_num(serial);
mutex_init(&port_priv->mutex);
usb_set_serial_port_data(port, port_priv);
return 0;
}
static int cp210x_port_remove(struct usb_serial_port *port)
static void cp210x_port_remove(struct usb_serial_port *port)
{
struct cp210x_port_private *port_priv;
port_priv = usb_get_serial_port_data(port);
kfree(port_priv);
return 0;
}
static void cp210x_init_max_speed(struct usb_serial *serial)

View File

@ -47,7 +47,7 @@
/* Function prototypes */
static int cyberjack_port_probe(struct usb_serial_port *port);
static int cyberjack_port_remove(struct usb_serial_port *port);
static void cyberjack_port_remove(struct usb_serial_port *port);
static int cyberjack_open(struct tty_struct *tty,
struct usb_serial_port *port);
static void cyberjack_close(struct usb_serial_port *port);
@ -120,7 +120,7 @@ static int cyberjack_port_probe(struct usb_serial_port *port)
return 0;
}
static int cyberjack_port_remove(struct usb_serial_port *port)
static void cyberjack_port_remove(struct usb_serial_port *port)
{
struct cyberjack_private *priv;
@ -128,8 +128,6 @@ static int cyberjack_port_remove(struct usb_serial_port *port)
priv = usb_get_serial_port_data(port);
kfree(priv);
return 0;
}
static int cyberjack_open(struct tty_struct *tty,

View File

@ -115,7 +115,7 @@ struct cypress_private {
static int cypress_earthmate_port_probe(struct usb_serial_port *port);
static int cypress_hidcom_port_probe(struct usb_serial_port *port);
static int cypress_ca42v2_port_probe(struct usb_serial_port *port);
static int cypress_port_remove(struct usb_serial_port *port);
static void cypress_port_remove(struct usb_serial_port *port);
static int cypress_open(struct tty_struct *tty, struct usb_serial_port *port);
static void cypress_close(struct usb_serial_port *port);
static void cypress_dtr_rts(struct usb_serial_port *port, int on);
@ -564,7 +564,7 @@ static int cypress_ca42v2_port_probe(struct usb_serial_port *port)
return 0;
}
static int cypress_port_remove(struct usb_serial_port *port)
static void cypress_port_remove(struct usb_serial_port *port)
{
struct cypress_private *priv;
@ -572,8 +572,6 @@ static int cypress_port_remove(struct usb_serial_port *port)
kfifo_free(&priv->write_fifo);
kfree(priv);
return 0;
}
static int cypress_open(struct tty_struct *tty, struct usb_serial_port *port)

View File

@ -233,7 +233,7 @@ static int digi_startup(struct usb_serial *serial);
static void digi_disconnect(struct usb_serial *serial);
static void digi_release(struct usb_serial *serial);
static int digi_port_probe(struct usb_serial_port *port);
static int digi_port_remove(struct usb_serial_port *port);
static void digi_port_remove(struct usb_serial_port *port);
static void digi_read_bulk_callback(struct urb *urb);
static int digi_read_inb_callback(struct urb *urb);
static int digi_read_oob_callback(struct urb *urb);
@ -1281,14 +1281,12 @@ static int digi_port_probe(struct usb_serial_port *port)
return digi_port_init(port, port->port_number);
}
static int digi_port_remove(struct usb_serial_port *port)
static void digi_port_remove(struct usb_serial_port *port)
{
struct digi_port *priv;
priv = usb_get_serial_port_data(port);
kfree(priv);
return 0;
}
static void digi_read_bulk_callback(struct urb *urb)

View File

@ -192,13 +192,9 @@ static int f81232_set_register(struct usb_serial_port *port, u16 reg, u8 val)
tmp,
sizeof(val),
USB_CTRL_SET_TIMEOUT);
if (status != sizeof(val)) {
if (status < 0) {
dev_err(&port->dev, "%s failed status: %d\n", __func__, status);
if (status < 0)
status = usb_translate_errors(status);
else
status = -EIO;
status = usb_translate_errors(status);
} else {
status = 0;
}
@ -886,10 +882,6 @@ static int f81534a_ctrl_set_register(struct usb_interface *intf, u16 reg,
status = usb_translate_errors(status);
if (status == -EIO)
continue;
} else if (status != size) {
/* Retry on short transfers */
status = -EIO;
continue;
} else {
status = 0;
}

View File

@ -235,11 +235,9 @@ static int f81534_set_register(struct usb_serial *serial, u16 reg, u8 data)
USB_TYPE_VENDOR | USB_DIR_OUT,
reg, 0, tmp, sizeof(u8),
F81534_USB_TIMEOUT);
if (status > 0) {
if (status == sizeof(u8)) {
status = 0;
break;
} else if (status == 0) {
status = -EIO;
}
}
@ -1432,12 +1430,11 @@ static int f81534_port_probe(struct usb_serial_port *port)
return f81534_set_port_output_pin(port);
}
static int f81534_port_remove(struct usb_serial_port *port)
static void f81534_port_remove(struct usb_serial_port *port)
{
struct f81534_port_private *port_priv = usb_get_serial_port_data(port);
flush_work(&port_priv->lsr_work);
return 0;
}
static int f81534_tiocmget(struct tty_struct *tty)

View File

@ -1069,7 +1069,7 @@ static const char *ftdi_chip_name[] = {
static int ftdi_sio_probe(struct usb_serial *serial,
const struct usb_device_id *id);
static int ftdi_sio_port_probe(struct usb_serial_port *port);
static int ftdi_sio_port_remove(struct usb_serial_port *port);
static void ftdi_sio_port_remove(struct usb_serial_port *port);
static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port);
static void ftdi_dtr_rts(struct usb_serial_port *port, int on);
static void ftdi_process_read_urb(struct urb *urb);
@ -1153,13 +1153,13 @@ static unsigned short int ftdi_232am_baud_base_to_divisor(int baud, int base)
divisor = divisor3 >> 3;
divisor3 &= 0x7;
if (divisor3 == 1)
divisor |= 0xc000;
divisor |= 0xc000; /* +0.125 */
else if (divisor3 >= 4)
divisor |= 0x4000;
divisor |= 0x4000; /* +0.5 */
else if (divisor3 != 0)
divisor |= 0x8000;
divisor |= 0x8000; /* +0.25 */
else if (divisor == 1)
divisor = 0; /* special case for maximum baud rate */
divisor = 0; /* special case for maximum baud rate */
return divisor;
}
@ -1177,9 +1177,9 @@ static u32 ftdi_232bm_baud_base_to_divisor(int baud, int base)
divisor = divisor3 >> 3;
divisor |= (u32)divfrac[divisor3 & 0x7] << 14;
/* Deal with special cases for highest baud rates. */
if (divisor == 1)
if (divisor == 1) /* 1.0 */
divisor = 0;
else if (divisor == 0x4001)
else if (divisor == 0x4001) /* 1.5 */
divisor = 1;
return divisor;
}
@ -1201,9 +1201,9 @@ static u32 ftdi_2232h_baud_base_to_divisor(int baud, int base)
divisor = divisor3 >> 3;
divisor |= (u32)divfrac[divisor3 & 0x7] << 14;
/* Deal with special cases for highest baud rates. */
if (divisor == 1)
if (divisor == 1) /* 1.0 */
divisor = 0;
else if (divisor == 0x4001)
else if (divisor == 0x4001) /* 1.5 */
divisor = 1;
/*
* Set this bit to turn off a divide by 2.5 on baud rate generator
@ -1386,8 +1386,9 @@ static int change_speed(struct tty_struct *tty, struct usb_serial_port *port)
index_value = get_ftdi_divisor(tty, port);
value = (u16)index_value;
index = (u16)(index_value >> 16);
if ((priv->chip_type == FT2232C) || (priv->chip_type == FT2232H) ||
(priv->chip_type == FT4232H) || (priv->chip_type == FT232H)) {
if (priv->chip_type == FT2232C || priv->chip_type == FT2232H ||
priv->chip_type == FT4232H || priv->chip_type == FT232H ||
priv->chip_type == FTX) {
/* Probably the BM type needs the MSB of the encoded fractional
* divider also moved like for the chips above. Any infos? */
index = (u16)((index << 8) | priv->interface);
@ -2399,7 +2400,7 @@ static int ftdi_stmclite_probe(struct usb_serial *serial)
return 0;
}
static int ftdi_sio_port_remove(struct usb_serial_port *port)
static void ftdi_sio_port_remove(struct usb_serial_port *port)
{
struct ftdi_private *priv = usb_get_serial_port_data(port);
@ -2408,8 +2409,6 @@ static int ftdi_sio_port_remove(struct usb_serial_port *port)
remove_sysfs_attrs(port);
kfree(priv);
return 0;
}
static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)

View File

@ -1401,7 +1401,7 @@ err_free:
}
static int garmin_port_remove(struct usb_serial_port *port)
static void garmin_port_remove(struct usb_serial_port *port)
{
struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);
@ -1409,7 +1409,6 @@ static int garmin_port_remove(struct usb_serial_port *port)
usb_kill_urb(port->interrupt_in_urb);
del_timer_sync(&garmin_data_p->timer);
kfree(garmin_data_p);
return 0;
}

View File

@ -293,7 +293,7 @@ static int edge_startup(struct usb_serial *serial);
static void edge_disconnect(struct usb_serial *serial);
static void edge_release(struct usb_serial *serial);
static int edge_port_probe(struct usb_serial_port *port);
static int edge_port_remove(struct usb_serial_port *port);
static void edge_port_remove(struct usb_serial_port *port);
/* function prototypes for all of our local functions */
@ -3078,14 +3078,12 @@ static int edge_port_probe(struct usb_serial_port *port)
return 0;
}
static int edge_port_remove(struct usb_serial_port *port)
static void edge_port_remove(struct usb_serial_port *port)
{
struct edgeport_port *edge_port;
edge_port = usb_get_serial_port_data(port);
kfree(edge_port);
return 0;
}
static struct usb_serial_driver edgeport_2port_device = {

View File

@ -266,7 +266,7 @@ static int ti_vread_sync(struct usb_device *dev, __u8 request,
if (status < 0)
return status;
if (status != size) {
dev_dbg(&dev->dev, "%s - wanted to write %d, but only wrote %d\n",
dev_dbg(&dev->dev, "%s - wanted to read %d, but only read %d\n",
__func__, size, status);
return -ECOMM;
}
@ -283,11 +283,7 @@ static int ti_vsend_sync(struct usb_device *dev, u8 request, u16 value,
value, index, data, size, timeout);
if (status < 0)
return status;
if (status != size) {
dev_dbg(&dev->dev, "%s - wanted to write %d, but only wrote %d\n",
__func__, size, status);
return -ECOMM;
}
return 0;
}
@ -2629,15 +2625,13 @@ err:
return ret;
}
static int edge_port_remove(struct usb_serial_port *port)
static void edge_port_remove(struct usb_serial_port *port)
{
struct edgeport_port *edge_port;
edge_port = usb_get_serial_port_data(port);
edge_remove_sysfs_attrs(port);
kfree(edge_port);
return 0;
}
/* Sysfs Attributes */

View File

@ -100,7 +100,7 @@ static int iuu_port_probe(struct usb_serial_port *port)
return 0;
}
static int iuu_port_remove(struct usb_serial_port *port)
static void iuu_port_remove(struct usb_serial_port *port)
{
struct iuu_private *priv = usb_get_serial_port_data(port);
@ -108,8 +108,6 @@ static int iuu_port_remove(struct usb_serial_port *port)
kfree(priv->writebuf);
kfree(priv->buf);
kfree(priv);
return 0;
}
static int iuu_tiocmset(struct tty_struct *tty,

View File

@ -49,7 +49,7 @@ static int keyspan_startup(struct usb_serial *serial);
static void keyspan_disconnect(struct usb_serial *serial);
static void keyspan_release(struct usb_serial *serial);
static int keyspan_port_probe(struct usb_serial_port *port);
static int keyspan_port_remove(struct usb_serial_port *port);
static void keyspan_port_remove(struct usb_serial_port *port);
static int keyspan_write_room(struct tty_struct *tty);
static int keyspan_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count);
@ -2985,7 +2985,7 @@ err_in_buffer:
return -ENOMEM;
}
static int keyspan_port_remove(struct usb_serial_port *port)
static void keyspan_port_remove(struct usb_serial_port *port)
{
struct keyspan_port_private *p_priv;
int i;
@ -3014,8 +3014,6 @@ static int keyspan_port_remove(struct usb_serial_port *port)
kfree(p_priv->in_buffer[i]);
kfree(p_priv);
return 0;
}
/* Structs for the devices, pre and post renumeration. */

View File

@ -672,14 +672,12 @@ static int keyspan_pda_port_probe(struct usb_serial_port *port)
return 0;
}
static int keyspan_pda_port_remove(struct usb_serial_port *port)
static void keyspan_pda_port_remove(struct usb_serial_port *port)
{
struct keyspan_pda_private *priv;
priv = usb_get_serial_port_data(port);
kfree(priv);
return 0;
}
static struct usb_serial_driver keyspan_pda_fake_device = {

View File

@ -52,7 +52,7 @@
* Function prototypes
*/
static int klsi_105_port_probe(struct usb_serial_port *port);
static int klsi_105_port_remove(struct usb_serial_port *port);
static void klsi_105_port_remove(struct usb_serial_port *port);
static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port);
static void klsi_105_close(struct usb_serial_port *port);
static void klsi_105_set_termios(struct tty_struct *tty,
@ -231,14 +231,12 @@ static int klsi_105_port_probe(struct usb_serial_port *port)
return 0;
}
static int klsi_105_port_remove(struct usb_serial_port *port)
static void klsi_105_port_remove(struct usb_serial_port *port)
{
struct klsi_105_private *priv;
priv = usb_get_serial_port_data(port);
kfree(priv);
return 0;
}
static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port)

View File

@ -48,7 +48,7 @@
/* Function prototypes */
static int kobil_port_probe(struct usb_serial_port *probe);
static int kobil_port_remove(struct usb_serial_port *probe);
static void kobil_port_remove(struct usb_serial_port *probe);
static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port);
static void kobil_close(struct usb_serial_port *port);
static int kobil_write(struct tty_struct *tty, struct usb_serial_port *port,
@ -143,14 +143,12 @@ static int kobil_port_probe(struct usb_serial_port *port)
}
static int kobil_port_remove(struct usb_serial_port *port)
static void kobil_port_remove(struct usb_serial_port *port)
{
struct kobil_private *priv;
priv = usb_get_serial_port_data(port);
kfree(priv);
return 0;
}
static void kobil_init_termios(struct tty_struct *tty)

View File

@ -39,7 +39,7 @@
* Function prototypes
*/
static int mct_u232_port_probe(struct usb_serial_port *port);
static int mct_u232_port_remove(struct usb_serial_port *remove);
static void mct_u232_port_remove(struct usb_serial_port *remove);
static int mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port);
static void mct_u232_close(struct usb_serial_port *port);
static void mct_u232_dtr_rts(struct usb_serial_port *port, int on);
@ -400,14 +400,12 @@ static int mct_u232_port_probe(struct usb_serial_port *port)
return 0;
}
static int mct_u232_port_remove(struct usb_serial_port *port)
static void mct_u232_port_remove(struct usb_serial_port *port)
{
struct mct_u232_private *priv;
priv = usb_get_serial_port_data(port);
kfree(priv);
return 0;
}
static int mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port)

View File

@ -256,14 +256,12 @@ static int metrousb_port_probe(struct usb_serial_port *port)
return 0;
}
static int metrousb_port_remove(struct usb_serial_port *port)
static void metrousb_port_remove(struct usb_serial_port *port)
{
struct metrousb_private *metro_priv;
metro_priv = usb_get_serial_port_data(port);
kfree(metro_priv);
return 0;
}
static void metrousb_throttle(struct tty_struct *tty)

View File

@ -215,8 +215,10 @@ static int read_mos_reg(struct usb_serial *serial, unsigned int serial_portnum,
int status;
buf = kmalloc(1, GFP_KERNEL);
if (!buf)
if (!buf) {
*data = 0;
return -ENOMEM;
}
status = usb_control_msg(usbdev, pipe, request, requesttype, value,
index, buf, 1, MOS_WDR_TIMEOUT);
@ -1092,8 +1094,10 @@ static int mos7720_write(struct tty_struct *tty, struct usb_serial_port *port,
if (urb->transfer_buffer == NULL) {
urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE,
GFP_ATOMIC);
if (!urb->transfer_buffer)
if (!urb->transfer_buffer) {
bytes_sent = -ENOMEM;
goto exit;
}
}
transfer_size = min(count, URB_TRANSFER_BUFFER_SIZE);
@ -1756,14 +1760,12 @@ static int mos7720_port_probe(struct usb_serial_port *port)
return 0;
}
static int mos7720_port_remove(struct usb_serial_port *port)
static void mos7720_port_remove(struct usb_serial_port *port)
{
struct moschip_port *mos7720_port;
mos7720_port = usb_get_serial_port_data(port);
kfree(mos7720_port);
return 0;
}
static struct usb_serial_driver moschip7720_2port_driver = {

View File

@ -883,8 +883,10 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port,
if (urb->transfer_buffer == NULL) {
urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE,
GFP_ATOMIC);
if (!urb->transfer_buffer)
if (!urb->transfer_buffer) {
bytes_sent = -ENOMEM;
goto exit;
}
}
transfer_size = min(count, URB_TRANSFER_BUFFER_SIZE);
@ -1743,7 +1745,7 @@ error:
return status;
}
static int mos7840_port_remove(struct usb_serial_port *port)
static void mos7840_port_remove(struct usb_serial_port *port)
{
struct moschip_port *mos7840_port = usb_get_serial_port_data(port);
@ -1760,8 +1762,6 @@ static int mos7840_port_remove(struct usb_serial_port *port)
}
kfree(mos7840_port);
return 0;
}
static struct usb_serial_driver moschip7840_4port_device = {

View File

@ -261,13 +261,6 @@ static int mxuport_send_ctrl_data_urb(struct usb_serial *serial,
return status;
}
if (status != size) {
dev_err(&serial->interface->dev,
"%s - short write (%d / %zd)\n",
__func__, status, size);
return -EIO;
}
return 0;
}

View File

@ -36,7 +36,7 @@ static int omninet_prepare_write_buffer(struct usb_serial_port *port,
static int omninet_calc_num_ports(struct usb_serial *serial,
struct usb_serial_endpoints *epds);
static int omninet_port_probe(struct usb_serial_port *port);
static int omninet_port_remove(struct usb_serial_port *port);
static void omninet_port_remove(struct usb_serial_port *port);
static const struct usb_device_id id_table[] = {
{ USB_DEVICE(ZYXEL_VENDOR_ID, ZYXEL_OMNINET_ID) },
@ -121,14 +121,12 @@ static int omninet_port_probe(struct usb_serial_port *port)
return 0;
}
static int omninet_port_remove(struct usb_serial_port *port)
static void omninet_port_remove(struct usb_serial_port *port)
{
struct omninet_data *od;
od = usb_get_serial_port_data(port);
kfree(od);
return 0;
}
#define OMNINET_HEADERLEN 4

View File

@ -385,13 +385,11 @@ static int opticon_port_probe(struct usb_serial_port *port)
return 0;
}
static int opticon_port_remove(struct usb_serial_port *port)
static void opticon_port_remove(struct usb_serial_port *port)
{
struct opticon_private *priv = usb_get_serial_port_data(port);
kfree(priv);
return 0;
}
static struct usb_serial_driver opticon_device = {

View File

@ -1569,7 +1569,8 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1272, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1273, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1274, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1275, 0xff, 0xff, 0xff) },
{ USB_DEVICE(ZTE_VENDOR_ID, 0x1275), /* ZTE P685M */
.driver_info = RSVD(3) | RSVD(4) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1276, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1277, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1278, 0xff, 0xff, 0xff) },

View File

@ -132,7 +132,7 @@ static int oti6858_tiocmget(struct tty_struct *tty);
static int oti6858_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear);
static int oti6858_port_probe(struct usb_serial_port *port);
static int oti6858_port_remove(struct usb_serial_port *port);
static void oti6858_port_remove(struct usb_serial_port *port);
/* device info */
static struct usb_serial_driver oti6858_device = {
@ -344,14 +344,12 @@ static int oti6858_port_probe(struct usb_serial_port *port)
return 0;
}
static int oti6858_port_remove(struct usb_serial_port *port)
static void oti6858_port_remove(struct usb_serial_port *port)
{
struct oti6858_private *priv;
priv = usb_get_serial_port_data(port);
kfree(priv);
return 0;
}
static int oti6858_write(struct tty_struct *tty, struct usb_serial_port *port,

View File

@ -183,6 +183,7 @@ struct pl2303_type_data {
speed_t max_baud_rate;
unsigned long quirks;
unsigned int no_autoxonxoff:1;
unsigned int no_divisors:1;
};
struct pl2303_serial_private {
@ -209,6 +210,7 @@ static const struct pl2303_type_data pl2303_type_data[TYPE_COUNT] = {
},
[TYPE_HXN] = {
.max_baud_rate = 12000000,
.no_divisors = true,
},
};
@ -448,13 +450,11 @@ static int pl2303_port_probe(struct usb_serial_port *port)
return 0;
}
static int pl2303_port_remove(struct usb_serial_port *port)
static void pl2303_port_remove(struct usb_serial_port *port)
{
struct pl2303_private *priv = usb_get_serial_port_data(port);
kfree(priv);
return 0;
}
static int pl2303_set_control_lines(struct usb_serial_port *port, u8 value)
@ -571,8 +571,12 @@ static void pl2303_encode_baud_rate(struct tty_struct *tty,
baud = min_t(speed_t, baud, spriv->type->max_baud_rate);
/*
* Use direct method for supported baud rates, otherwise use divisors.
* Newer chip types do not support divisor encoding.
*/
baud_sup = pl2303_get_supported_baud_rate(baud);
if (spriv->type->no_divisors)
baud_sup = baud;
else
baud_sup = pl2303_get_supported_baud_rate(baud);
if (baud == baud_sup)
baud = pl2303_encode_baud_rate_direct(buf, baud);

View File

@ -727,7 +727,7 @@ err_buf:
return -ENOMEM;
}
static int qt2_port_remove(struct usb_serial_port *port)
static void qt2_port_remove(struct usb_serial_port *port)
{
struct qt2_port_private *port_priv;
@ -735,8 +735,6 @@ static int qt2_port_remove(struct usb_serial_port *port)
usb_free_urb(port_priv->write_urb);
kfree(port_priv->write_buffer);
kfree(port_priv);
return 0;
}
static int qt2_tiocmget(struct tty_struct *tty)

View File

@ -901,15 +901,13 @@ static int sierra_port_probe(struct usb_serial_port *port)
return 0;
}
static int sierra_port_remove(struct usb_serial_port *port)
static void sierra_port_remove(struct usb_serial_port *port)
{
struct sierra_port_private *portdata;
portdata = usb_get_serial_port_data(port);
usb_set_serial_port_data(port, NULL);
kfree(portdata);
return 0;
}
#ifdef CONFIG_PM

View File

@ -169,14 +169,12 @@ static int spcp8x5_port_probe(struct usb_serial_port *port)
return 0;
}
static int spcp8x5_port_remove(struct usb_serial_port *port)
static void spcp8x5_port_remove(struct usb_serial_port *port)
{
struct spcp8x5_private *priv;
priv = usb_get_serial_port_data(port);
kfree(priv);
return 0;
}
static int spcp8x5_set_ctrl_line(struct usb_serial_port *port, u8 mcr)

View File

@ -366,14 +366,12 @@ static int ssu100_port_probe(struct usb_serial_port *port)
return 0;
}
static int ssu100_port_remove(struct usb_serial_port *port)
static void ssu100_port_remove(struct usb_serial_port *port)
{
struct ssu100_port_private *priv;
priv = usb_get_serial_port_data(port);
kfree(priv);
return 0;
}
static int ssu100_tiocmget(struct tty_struct *tty)

View File

@ -160,13 +160,11 @@ static int symbol_port_probe(struct usb_serial_port *port)
return 0;
}
static int symbol_port_remove(struct usb_serial_port *port)
static void symbol_port_remove(struct usb_serial_port *port)
{
struct symbol_private *priv = usb_get_serial_port_data(port);
kfree(priv);
return 0;
}
static struct usb_serial_driver symbol_device = {

View File

@ -303,7 +303,7 @@ struct ti_device {
static int ti_startup(struct usb_serial *serial);
static void ti_release(struct usb_serial *serial);
static int ti_port_probe(struct usb_serial_port *port);
static int ti_port_remove(struct usb_serial_port *port);
static void ti_port_remove(struct usb_serial_port *port);
static int ti_open(struct tty_struct *tty, struct usb_serial_port *port);
static void ti_close(struct usb_serial_port *port);
static int ti_write(struct tty_struct *tty, struct usb_serial_port *port,
@ -629,14 +629,12 @@ static int ti_port_probe(struct usb_serial_port *port)
return 0;
}
static int ti_port_remove(struct usb_serial_port *port)
static void ti_port_remove(struct usb_serial_port *port)
{
struct ti_port *tport;
tport = usb_get_serial_port_data(port);
kfree(tport);
return 0;
}
static int ti_open(struct tty_struct *tty, struct usb_serial_port *port)

View File

@ -145,14 +145,11 @@ static int upd78f0730_send_ctl(struct usb_serial_port *port,
kfree(buf);
if (res != size) {
if (res < 0) {
struct device *dev = &port->dev;
dev_err(dev, "failed to send control request %02x: %d\n",
*(u8 *)data, res);
/* The maximum expected length of a transfer is 6 bytes */
if (res >= 0)
res = -EIO;
return res;
}
@ -174,15 +171,13 @@ static int upd78f0730_port_probe(struct usb_serial_port *port)
return 0;
}
static int upd78f0730_port_remove(struct usb_serial_port *port)
static void upd78f0730_port_remove(struct usb_serial_port *port)
{
struct upd78f0730_port_private *private;
private = usb_get_serial_port_data(port);
mutex_destroy(&private->lock);
kfree(private);
return 0;
}
static int upd78f0730_tiocmget(struct tty_struct *tty)

View File

@ -10,7 +10,7 @@ extern void usb_wwan_dtr_rts(struct usb_serial_port *port, int on);
extern int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port);
extern void usb_wwan_close(struct usb_serial_port *port);
extern int usb_wwan_port_probe(struct usb_serial_port *port);
extern int usb_wwan_port_remove(struct usb_serial_port *port);
extern void usb_wwan_port_remove(struct usb_serial_port *port);
extern int usb_wwan_write_room(struct tty_struct *tty);
extern int usb_wwan_tiocmget(struct tty_struct *tty);
extern int usb_wwan_tiocmset(struct tty_struct *tty,

View File

@ -544,7 +544,7 @@ bail_out_error:
}
EXPORT_SYMBOL_GPL(usb_wwan_port_probe);
int usb_wwan_port_remove(struct usb_serial_port *port)
void usb_wwan_port_remove(struct usb_serial_port *port)
{
int i;
struct usb_wwan_port_private *portdata;
@ -562,8 +562,6 @@ int usb_wwan_port_remove(struct usb_serial_port *port)
}
kfree(portdata);
return 0;
}
EXPORT_SYMBOL(usb_wwan_port_remove);

View File

@ -79,7 +79,7 @@ static int whiteheat_firmware_attach(struct usb_serial *serial);
static int whiteheat_attach(struct usb_serial *serial);
static void whiteheat_release(struct usb_serial *serial);
static int whiteheat_port_probe(struct usb_serial_port *port);
static int whiteheat_port_remove(struct usb_serial_port *port);
static void whiteheat_port_remove(struct usb_serial_port *port);
static int whiteheat_open(struct tty_struct *tty,
struct usb_serial_port *port);
static void whiteheat_close(struct usb_serial_port *port);
@ -345,14 +345,12 @@ static int whiteheat_port_probe(struct usb_serial_port *port)
return 0;
}
static int whiteheat_port_remove(struct usb_serial_port *port)
static void whiteheat_port_remove(struct usb_serial_port *port)
{
struct whiteheat_private *info;
info = usb_get_serial_port_data(port);
kfree(info);
return 0;
}
static int whiteheat_open(struct tty_struct *tty, struct usb_serial_port *port)

View File

@ -0,0 +1,611 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* MaxLinear/Exar USB to Serial driver
*
* Copyright (c) 2020 Manivannan Sadhasivam <mani@kernel.org>
*
* Based on the initial driver written by Patong Yang:
*
* https://lore.kernel.org/r/20180404070634.nhspvmxcjwfgjkcv@advantechmxl-desktop
*
* Copyright (c) 2018 Patong Yang <patong.mxl@gmail.com>
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/usb.h>
#include <linux/usb/serial.h>
struct xr_txrx_clk_mask {
u16 tx;
u16 rx0;
u16 rx1;
};
#define XR_INT_OSC_HZ 48000000U
#define XR21V141X_MIN_SPEED 46U
#define XR21V141X_MAX_SPEED XR_INT_OSC_HZ
/* USB Requests */
#define XR21V141X_SET_REQ 0
#define XR21V141X_GET_REQ 1
#define XR21V141X_CLOCK_DIVISOR_0 0x04
#define XR21V141X_CLOCK_DIVISOR_1 0x05
#define XR21V141X_CLOCK_DIVISOR_2 0x06
#define XR21V141X_TX_CLOCK_MASK_0 0x07
#define XR21V141X_TX_CLOCK_MASK_1 0x08
#define XR21V141X_RX_CLOCK_MASK_0 0x09
#define XR21V141X_RX_CLOCK_MASK_1 0x0a
/* XR21V141X register blocks */
#define XR21V141X_UART_REG_BLOCK 0
#define XR21V141X_UM_REG_BLOCK 4
#define XR21V141X_UART_CUSTOM_BLOCK 0x66
/* XR21V141X UART Manager Registers */
#define XR21V141X_UM_FIFO_ENABLE_REG 0x10
#define XR21V141X_UM_ENABLE_TX_FIFO 0x01
#define XR21V141X_UM_ENABLE_RX_FIFO 0x02
#define XR21V141X_UM_RX_FIFO_RESET 0x18
#define XR21V141X_UM_TX_FIFO_RESET 0x1c
#define XR21V141X_UART_ENABLE_TX 0x1
#define XR21V141X_UART_ENABLE_RX 0x2
#define XR21V141X_UART_MODE_RI BIT(0)
#define XR21V141X_UART_MODE_CD BIT(1)
#define XR21V141X_UART_MODE_DSR BIT(2)
#define XR21V141X_UART_MODE_DTR BIT(3)
#define XR21V141X_UART_MODE_CTS BIT(4)
#define XR21V141X_UART_MODE_RTS BIT(5)
#define XR21V141X_UART_BREAK_ON 0xff
#define XR21V141X_UART_BREAK_OFF 0
#define XR21V141X_UART_DATA_MASK GENMASK(3, 0)
#define XR21V141X_UART_DATA_7 0x7
#define XR21V141X_UART_DATA_8 0x8
#define XR21V141X_UART_PARITY_MASK GENMASK(6, 4)
#define XR21V141X_UART_PARITY_SHIFT 4
#define XR21V141X_UART_PARITY_NONE (0x0 << XR21V141X_UART_PARITY_SHIFT)
#define XR21V141X_UART_PARITY_ODD (0x1 << XR21V141X_UART_PARITY_SHIFT)
#define XR21V141X_UART_PARITY_EVEN (0x2 << XR21V141X_UART_PARITY_SHIFT)
#define XR21V141X_UART_PARITY_MARK (0x3 << XR21V141X_UART_PARITY_SHIFT)
#define XR21V141X_UART_PARITY_SPACE (0x4 << XR21V141X_UART_PARITY_SHIFT)
#define XR21V141X_UART_STOP_MASK BIT(7)
#define XR21V141X_UART_STOP_SHIFT 7
#define XR21V141X_UART_STOP_1 (0x0 << XR21V141X_UART_STOP_SHIFT)
#define XR21V141X_UART_STOP_2 (0x1 << XR21V141X_UART_STOP_SHIFT)
#define XR21V141X_UART_FLOW_MODE_NONE 0x0
#define XR21V141X_UART_FLOW_MODE_HW 0x1
#define XR21V141X_UART_FLOW_MODE_SW 0x2
#define XR21V141X_UART_MODE_GPIO_MASK GENMASK(2, 0)
#define XR21V141X_UART_MODE_RTS_CTS 0x1
#define XR21V141X_UART_MODE_DTR_DSR 0x2
#define XR21V141X_UART_MODE_RS485 0x3
#define XR21V141X_UART_MODE_RS485_ADDR 0x4
#define XR21V141X_REG_ENABLE 0x03
#define XR21V141X_REG_FORMAT 0x0b
#define XR21V141X_REG_FLOW_CTRL 0x0c
#define XR21V141X_REG_XON_CHAR 0x10
#define XR21V141X_REG_XOFF_CHAR 0x11
#define XR21V141X_REG_LOOPBACK 0x12
#define XR21V141X_REG_TX_BREAK 0x14
#define XR21V141X_REG_RS845_DELAY 0x15
#define XR21V141X_REG_GPIO_MODE 0x1a
#define XR21V141X_REG_GPIO_DIR 0x1b
#define XR21V141X_REG_GPIO_INT_MASK 0x1c
#define XR21V141X_REG_GPIO_SET 0x1d
#define XR21V141X_REG_GPIO_CLR 0x1e
#define XR21V141X_REG_GPIO_STATUS 0x1f
static int xr_set_reg(struct usb_serial_port *port, u8 block, u8 reg, u8 val)
{
struct usb_serial *serial = port->serial;
int ret;
ret = usb_control_msg(serial->dev,
usb_sndctrlpipe(serial->dev, 0),
XR21V141X_SET_REQ,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
val, reg | (block << 8), NULL, 0,
USB_CTRL_SET_TIMEOUT);
if (ret < 0) {
dev_err(&port->dev, "Failed to set reg 0x%02x: %d\n", reg, ret);
return ret;
}
return 0;
}
static int xr_get_reg(struct usb_serial_port *port, u8 block, u8 reg, u8 *val)
{
struct usb_serial *serial = port->serial;
u8 *dmabuf;
int ret;
dmabuf = kmalloc(1, GFP_KERNEL);
if (!dmabuf)
return -ENOMEM;
ret = usb_control_msg(serial->dev,
usb_rcvctrlpipe(serial->dev, 0),
XR21V141X_GET_REQ,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0, reg | (block << 8), dmabuf, 1,
USB_CTRL_GET_TIMEOUT);
if (ret == 1) {
*val = *dmabuf;
ret = 0;
} else {
dev_err(&port->dev, "Failed to get reg 0x%02x: %d\n", reg, ret);
if (ret >= 0)
ret = -EIO;
}
kfree(dmabuf);
return ret;
}
static int xr_set_reg_uart(struct usb_serial_port *port, u8 reg, u8 val)
{
return xr_set_reg(port, XR21V141X_UART_REG_BLOCK, reg, val);
}
static int xr_get_reg_uart(struct usb_serial_port *port, u8 reg, u8 *val)
{
return xr_get_reg(port, XR21V141X_UART_REG_BLOCK, reg, val);
}
static int xr_set_reg_um(struct usb_serial_port *port, u8 reg, u8 val)
{
return xr_set_reg(port, XR21V141X_UM_REG_BLOCK, reg, val);
}
/*
* According to datasheet, below is the recommended sequence for enabling UART
* module in XR21V141X:
*
* Enable Tx FIFO
* Enable Tx and Rx
* Enable Rx FIFO
*/
static int xr_uart_enable(struct usb_serial_port *port)
{
int ret;
ret = xr_set_reg_um(port, XR21V141X_UM_FIFO_ENABLE_REG,
XR21V141X_UM_ENABLE_TX_FIFO);
if (ret)
return ret;
ret = xr_set_reg_uart(port, XR21V141X_REG_ENABLE,
XR21V141X_UART_ENABLE_TX | XR21V141X_UART_ENABLE_RX);
if (ret)
return ret;
ret = xr_set_reg_um(port, XR21V141X_UM_FIFO_ENABLE_REG,
XR21V141X_UM_ENABLE_TX_FIFO | XR21V141X_UM_ENABLE_RX_FIFO);
if (ret)
xr_set_reg_uart(port, XR21V141X_REG_ENABLE, 0);
return ret;
}
static int xr_uart_disable(struct usb_serial_port *port)
{
int ret;
ret = xr_set_reg_uart(port, XR21V141X_REG_ENABLE, 0);
if (ret)
return ret;
ret = xr_set_reg_um(port, XR21V141X_UM_FIFO_ENABLE_REG, 0);
return ret;
}
static int xr_tiocmget(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
u8 status;
int ret;
ret = xr_get_reg_uart(port, XR21V141X_REG_GPIO_STATUS, &status);
if (ret)
return ret;
/*
* Modem control pins are active low, so reading '0' means it is active
* and '1' means not active.
*/
ret = ((status & XR21V141X_UART_MODE_DTR) ? 0 : TIOCM_DTR) |
((status & XR21V141X_UART_MODE_RTS) ? 0 : TIOCM_RTS) |
((status & XR21V141X_UART_MODE_CTS) ? 0 : TIOCM_CTS) |
((status & XR21V141X_UART_MODE_DSR) ? 0 : TIOCM_DSR) |
((status & XR21V141X_UART_MODE_RI) ? 0 : TIOCM_RI) |
((status & XR21V141X_UART_MODE_CD) ? 0 : TIOCM_CD);
return ret;
}
static int xr_tiocmset_port(struct usb_serial_port *port,
unsigned int set, unsigned int clear)
{
u8 gpio_set = 0;
u8 gpio_clr = 0;
int ret = 0;
/* Modem control pins are active low, so set & clr are swapped */
if (set & TIOCM_RTS)
gpio_clr |= XR21V141X_UART_MODE_RTS;
if (set & TIOCM_DTR)
gpio_clr |= XR21V141X_UART_MODE_DTR;
if (clear & TIOCM_RTS)
gpio_set |= XR21V141X_UART_MODE_RTS;
if (clear & TIOCM_DTR)
gpio_set |= XR21V141X_UART_MODE_DTR;
/* Writing '0' to gpio_{set/clr} bits has no effect, so no need to do */
if (gpio_clr)
ret = xr_set_reg_uart(port, XR21V141X_REG_GPIO_CLR, gpio_clr);
if (gpio_set)
ret = xr_set_reg_uart(port, XR21V141X_REG_GPIO_SET, gpio_set);
return ret;
}
static int xr_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear)
{
struct usb_serial_port *port = tty->driver_data;
return xr_tiocmset_port(port, set, clear);
}
static void xr_dtr_rts(struct usb_serial_port *port, int on)
{
if (on)
xr_tiocmset_port(port, TIOCM_DTR | TIOCM_RTS, 0);
else
xr_tiocmset_port(port, 0, TIOCM_DTR | TIOCM_RTS);
}
static void xr_break_ctl(struct tty_struct *tty, int break_state)
{
struct usb_serial_port *port = tty->driver_data;
u8 state;
if (break_state == 0)
state = XR21V141X_UART_BREAK_OFF;
else
state = XR21V141X_UART_BREAK_ON;
dev_dbg(&port->dev, "Turning break %s\n",
state == XR21V141X_UART_BREAK_OFF ? "off" : "on");
xr_set_reg_uart(port, XR21V141X_REG_TX_BREAK, state);
}
/* Tx and Rx clock mask values obtained from section 3.3.4 of datasheet */
static const struct xr_txrx_clk_mask xr21v141x_txrx_clk_masks[] = {
{ 0x000, 0x000, 0x000 },
{ 0x000, 0x000, 0x000 },
{ 0x100, 0x000, 0x100 },
{ 0x020, 0x400, 0x020 },
{ 0x010, 0x100, 0x010 },
{ 0x208, 0x040, 0x208 },
{ 0x104, 0x820, 0x108 },
{ 0x844, 0x210, 0x884 },
{ 0x444, 0x110, 0x444 },
{ 0x122, 0x888, 0x224 },
{ 0x912, 0x448, 0x924 },
{ 0x492, 0x248, 0x492 },
{ 0x252, 0x928, 0x292 },
{ 0x94a, 0x4a4, 0xa52 },
{ 0x52a, 0xaa4, 0x54a },
{ 0xaaa, 0x954, 0x4aa },
{ 0xaaa, 0x554, 0xaaa },
{ 0x555, 0xad4, 0x5aa },
{ 0xb55, 0xab4, 0x55a },
{ 0x6b5, 0x5ac, 0xb56 },
{ 0x5b5, 0xd6c, 0x6d6 },
{ 0xb6d, 0xb6a, 0xdb6 },
{ 0x76d, 0x6da, 0xbb6 },
{ 0xedd, 0xdda, 0x76e },
{ 0xddd, 0xbba, 0xeee },
{ 0x7bb, 0xf7a, 0xdde },
{ 0xf7b, 0xef6, 0x7de },
{ 0xdf7, 0xbf6, 0xf7e },
{ 0x7f7, 0xfee, 0xefe },
{ 0xfdf, 0xfbe, 0x7fe },
{ 0xf7f, 0xefe, 0xffe },
{ 0xfff, 0xffe, 0xffd },
};
static int xr_set_baudrate(struct tty_struct *tty,
struct usb_serial_port *port)
{
u32 divisor, baud, idx;
u16 tx_mask, rx_mask;
int ret;
baud = tty->termios.c_ospeed;
if (!baud)
return 0;
baud = clamp(baud, XR21V141X_MIN_SPEED, XR21V141X_MAX_SPEED);
divisor = XR_INT_OSC_HZ / baud;
idx = ((32 * XR_INT_OSC_HZ) / baud) & 0x1f;
tx_mask = xr21v141x_txrx_clk_masks[idx].tx;
if (divisor & 0x01)
rx_mask = xr21v141x_txrx_clk_masks[idx].rx1;
else
rx_mask = xr21v141x_txrx_clk_masks[idx].rx0;
dev_dbg(&port->dev, "Setting baud rate: %u\n", baud);
/*
* XR21V141X uses fractional baud rate generator with 48MHz internal
* oscillator and 19-bit programmable divisor. So theoretically it can
* generate most commonly used baud rates with high accuracy.
*/
ret = xr_set_reg_uart(port, XR21V141X_CLOCK_DIVISOR_0,
divisor & 0xff);
if (ret)
return ret;
ret = xr_set_reg_uart(port, XR21V141X_CLOCK_DIVISOR_1,
(divisor >> 8) & 0xff);
if (ret)
return ret;
ret = xr_set_reg_uart(port, XR21V141X_CLOCK_DIVISOR_2,
(divisor >> 16) & 0xff);
if (ret)
return ret;
ret = xr_set_reg_uart(port, XR21V141X_TX_CLOCK_MASK_0,
tx_mask & 0xff);
if (ret)
return ret;
ret = xr_set_reg_uart(port, XR21V141X_TX_CLOCK_MASK_1,
(tx_mask >> 8) & 0xff);
if (ret)
return ret;
ret = xr_set_reg_uart(port, XR21V141X_RX_CLOCK_MASK_0,
rx_mask & 0xff);
if (ret)
return ret;
ret = xr_set_reg_uart(port, XR21V141X_RX_CLOCK_MASK_1,
(rx_mask >> 8) & 0xff);
if (ret)
return ret;
tty_encode_baud_rate(tty, baud, baud);
return 0;
}
static void xr_set_flow_mode(struct tty_struct *tty,
struct usb_serial_port *port,
struct ktermios *old_termios)
{
u8 flow, gpio_mode;
int ret;
ret = xr_get_reg_uart(port, XR21V141X_REG_GPIO_MODE, &gpio_mode);
if (ret)
return;
/* Set GPIO mode for controlling the pins manually by default. */
gpio_mode &= ~XR21V141X_UART_MODE_GPIO_MASK;
if (C_CRTSCTS(tty) && C_BAUD(tty) != B0) {
dev_dbg(&port->dev, "Enabling hardware flow ctrl\n");
gpio_mode |= XR21V141X_UART_MODE_RTS_CTS;
flow = XR21V141X_UART_FLOW_MODE_HW;
} else if (I_IXON(tty)) {
u8 start_char = START_CHAR(tty);
u8 stop_char = STOP_CHAR(tty);
dev_dbg(&port->dev, "Enabling sw flow ctrl\n");
flow = XR21V141X_UART_FLOW_MODE_SW;
xr_set_reg_uart(port, XR21V141X_REG_XON_CHAR, start_char);
xr_set_reg_uart(port, XR21V141X_REG_XOFF_CHAR, stop_char);
} else {
dev_dbg(&port->dev, "Disabling flow ctrl\n");
flow = XR21V141X_UART_FLOW_MODE_NONE;
}
/*
* As per the datasheet, UART needs to be disabled while writing to
* FLOW_CONTROL register.
*/
xr_uart_disable(port);
xr_set_reg_uart(port, XR21V141X_REG_FLOW_CTRL, flow);
xr_uart_enable(port);
xr_set_reg_uart(port, XR21V141X_REG_GPIO_MODE, gpio_mode);
if (C_BAUD(tty) == B0)
xr_dtr_rts(port, 0);
else if (old_termios && (old_termios->c_cflag & CBAUD) == B0)
xr_dtr_rts(port, 1);
}
static void xr_set_termios(struct tty_struct *tty,
struct usb_serial_port *port,
struct ktermios *old_termios)
{
struct ktermios *termios = &tty->termios;
u8 bits = 0;
int ret;
if (!old_termios || (tty->termios.c_ospeed != old_termios->c_ospeed))
xr_set_baudrate(tty, port);
switch (C_CSIZE(tty)) {
case CS5:
case CS6:
/* CS5 and CS6 are not supported, so just restore old setting */
termios->c_cflag &= ~CSIZE;
if (old_termios)
termios->c_cflag |= old_termios->c_cflag & CSIZE;
else
bits |= XR21V141X_UART_DATA_8;
break;
case CS7:
bits |= XR21V141X_UART_DATA_7;
break;
case CS8:
default:
bits |= XR21V141X_UART_DATA_8;
break;
}
if (C_PARENB(tty)) {
if (C_CMSPAR(tty)) {
if (C_PARODD(tty))
bits |= XR21V141X_UART_PARITY_MARK;
else
bits |= XR21V141X_UART_PARITY_SPACE;
} else {
if (C_PARODD(tty))
bits |= XR21V141X_UART_PARITY_ODD;
else
bits |= XR21V141X_UART_PARITY_EVEN;
}
}
if (C_CSTOPB(tty))
bits |= XR21V141X_UART_STOP_2;
else
bits |= XR21V141X_UART_STOP_1;
ret = xr_set_reg_uart(port, XR21V141X_REG_FORMAT, bits);
if (ret)
return;
xr_set_flow_mode(tty, port, old_termios);
}
static int xr_open(struct tty_struct *tty, struct usb_serial_port *port)
{
u8 gpio_dir;
int ret;
ret = xr_uart_enable(port);
if (ret) {
dev_err(&port->dev, "Failed to enable UART\n");
return ret;
}
/*
* Configure DTR and RTS as outputs and RI, CD, DSR and CTS as
* inputs.
*/
gpio_dir = XR21V141X_UART_MODE_DTR | XR21V141X_UART_MODE_RTS;
xr_set_reg_uart(port, XR21V141X_REG_GPIO_DIR, gpio_dir);
/* Setup termios */
if (tty)
xr_set_termios(tty, port, NULL);
ret = usb_serial_generic_open(tty, port);
if (ret) {
xr_uart_disable(port);
return ret;
}
return 0;
}
static void xr_close(struct usb_serial_port *port)
{
usb_serial_generic_close(port);
xr_uart_disable(port);
}
static int xr_probe(struct usb_serial *serial, const struct usb_device_id *id)
{
struct usb_driver *driver = serial->type->usb_driver;
struct usb_interface *control_interface;
int ret;
/* Don't bind to control interface */
if (serial->interface->cur_altsetting->desc.bInterfaceNumber == 0)
return -ENODEV;
/* But claim the control interface during data interface probe */
control_interface = usb_ifnum_to_if(serial->dev, 0);
if (!control_interface)
return -ENODEV;
ret = usb_driver_claim_interface(driver, control_interface, NULL);
if (ret) {
dev_err(&serial->interface->dev, "Failed to claim control interface\n");
return ret;
}
return 0;
}
static void xr_disconnect(struct usb_serial *serial)
{
struct usb_driver *driver = serial->type->usb_driver;
struct usb_interface *control_interface;
control_interface = usb_ifnum_to_if(serial->dev, 0);
usb_driver_release_interface(driver, control_interface);
}
static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x04e2, 0x1410) }, /* XR21V141X */
{ }
};
MODULE_DEVICE_TABLE(usb, id_table);
static struct usb_serial_driver xr_device = {
.driver = {
.owner = THIS_MODULE,
.name = "xr_serial",
},
.id_table = id_table,
.num_ports = 1,
.probe = xr_probe,
.disconnect = xr_disconnect,
.open = xr_open,
.close = xr_close,
.break_ctl = xr_break_ctl,
.set_termios = xr_set_termios,
.tiocmget = xr_tiocmget,
.tiocmset = xr_tiocmset,
.dtr_rts = xr_dtr_rts
};
static struct usb_serial_driver * const serial_drivers[] = {
&xr_device, NULL
};
module_usb_serial_driver(serial_drivers, id_table);
MODULE_AUTHOR("Manivannan Sadhasivam <mani@kernel.org>");
MODULE_DESCRIPTION("MaxLinear/Exar USB to Serial driver");
MODULE_LICENSE("GPL");

View File

@ -260,7 +260,7 @@ struct usb_serial_driver {
void (*release)(struct usb_serial *serial);
int (*port_probe)(struct usb_serial_port *port);
int (*port_remove)(struct usb_serial_port *port);
void (*port_remove)(struct usb_serial_port *port);
int (*suspend)(struct usb_serial *serial, pm_message_t message);
int (*resume)(struct usb_serial *serial);