提交 c85bfed1 编写于 作者: G Greg Kroah-Hartman

Merge tag 'usb-serial-5.12-rc1' of...

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
  ...
...@@ -1901,6 +1901,12 @@ static const struct usb_device_id acm_ids[] = { ...@@ -1901,6 +1901,12 @@ static const struct usb_device_id acm_ids[] = {
}, },
#endif #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 */ /*Samsung phone in firmware update mode */
{ USB_DEVICE(0x04e8, 0x685d), { USB_DEVICE(0x04e8, 0x685d),
.driver_info = IGNORE_DEVICE, .driver_info = IGNORE_DEVICE,
......
...@@ -633,6 +633,15 @@ config USB_SERIAL_UPD78F0730 ...@@ -633,6 +633,15 @@ config USB_SERIAL_UPD78F0730
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called upd78f0730. 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 config USB_SERIAL_DEBUG
tristate "USB Debugging Device" tristate "USB Debugging Device"
help help
......
...@@ -61,4 +61,5 @@ obj-$(CONFIG_USB_SERIAL_UPD78F0730) += upd78f0730.o ...@@ -61,4 +61,5 @@ obj-$(CONFIG_USB_SERIAL_UPD78F0730) += upd78f0730.o
obj-$(CONFIG_USB_SERIAL_VISOR) += visor.o obj-$(CONFIG_USB_SERIAL_VISOR) += visor.o
obj-$(CONFIG_USB_SERIAL_WISHBONE) += wishbone-serial.o obj-$(CONFIG_USB_SERIAL_WISHBONE) += wishbone-serial.o
obj-$(CONFIG_USB_SERIAL_WHITEHEAT) += whiteheat.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 obj-$(CONFIG_USB_SERIAL_XSENS_MT) += xsens_mt.o
...@@ -178,15 +178,13 @@ static int ark3116_port_probe(struct usb_serial_port *port) ...@@ -178,15 +178,13 @@ static int ark3116_port_probe(struct usb_serial_port *port)
return 0; 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); struct ark3116_private *priv = usb_get_serial_port_data(port);
/* device is closed, so URBs and DMA should be down */ /* device is closed, so URBs and DMA should be down */
mutex_destroy(&priv->hw_lock); mutex_destroy(&priv->hw_lock);
kfree(priv); kfree(priv);
return 0;
} }
static void ark3116_set_termios(struct tty_struct *tty, static void ark3116_set_termios(struct tty_struct *tty,
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
/* function prototypes for a Belkin USB Serial Adapter F5U103 */ /* 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_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, static int belkin_sa_open(struct tty_struct *tty,
struct usb_serial_port *port); struct usb_serial_port *port);
static void belkin_sa_close(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) ...@@ -134,14 +134,12 @@ static int belkin_sa_port_probe(struct usb_serial_port *port)
return 0; 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; struct belkin_sa_private *priv;
priv = usb_get_serial_port_data(port); priv = usb_get_serial_port_data(port);
kfree(priv); kfree(priv);
return 0;
} }
static int belkin_sa_open(struct tty_struct *tty, static int belkin_sa_open(struct tty_struct *tty,
......
...@@ -16,19 +16,13 @@ ...@@ -16,19 +16,13 @@
static int usb_serial_device_match(struct device *dev, static int usb_serial_device_match(struct device *dev,
struct device_driver *drv) struct device_driver *drv)
{ {
struct usb_serial_driver *driver; const struct usb_serial_port *port = to_usb_serial_port(dev);
const struct usb_serial_port *port; struct usb_serial_driver *driver = to_usb_serial_driver(drv);
/* /*
* drivers are already assigned to ports in serial_probe so it's * drivers are already assigned to ports in serial_probe so it's
* a simple check here. * 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) if (driver == port->serial->type)
return 1; return 1;
...@@ -37,16 +31,12 @@ static int usb_serial_device_match(struct device *dev, ...@@ -37,16 +31,12 @@ static int usb_serial_device_match(struct device *dev,
static int usb_serial_device_probe(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_driver *driver;
struct usb_serial_port *port;
struct device *tty_dev; struct device *tty_dev;
int retval = 0; int retval = 0;
int minor; int minor;
port = to_usb_serial_port(dev);
if (!port)
return -ENODEV;
/* make sure suspend/resume doesn't race against port_probe */ /* make sure suspend/resume doesn't race against port_probe */
retval = usb_autopm_get_interface(port->serial->interface); retval = usb_autopm_get_interface(port->serial->interface);
if (retval) if (retval)
...@@ -86,16 +76,11 @@ static int usb_serial_device_probe(struct device *dev) ...@@ -86,16 +76,11 @@ static int usb_serial_device_probe(struct device *dev)
static int usb_serial_device_remove(struct device *dev) 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_driver *driver;
struct usb_serial_port *port;
int retval = 0;
int minor; int minor;
int autopm_err; int autopm_err;
port = to_usb_serial_port(dev);
if (!port)
return -ENODEV;
/* /*
* Make sure suspend/resume doesn't race against port_remove. * Make sure suspend/resume doesn't race against port_remove.
* *
...@@ -109,7 +94,7 @@ static int usb_serial_device_remove(struct device *dev) ...@@ -109,7 +94,7 @@ static int usb_serial_device_remove(struct device *dev)
driver = port->serial->type; driver = port->serial->type;
if (driver->port_remove) if (driver->port_remove)
retval = driver->port_remove(port); driver->port_remove(port);
dev_info(dev, "%s converter now disconnected from ttyUSB%d\n", dev_info(dev, "%s converter now disconnected from ttyUSB%d\n",
driver->description, minor); driver->description, minor);
...@@ -117,7 +102,7 @@ static int usb_serial_device_remove(struct device *dev) ...@@ -117,7 +102,7 @@ static int usb_serial_device_remove(struct device *dev)
if (!autopm_err) if (!autopm_err)
usb_autopm_put_interface(port->serial->interface); usb_autopm_put_interface(port->serial->interface);
return retval; return 0;
} }
static ssize_t new_id_store(struct device_driver *driver, static ssize_t new_id_store(struct device_driver *driver,
......
...@@ -419,14 +419,12 @@ error: kfree(priv); ...@@ -419,14 +419,12 @@ error: kfree(priv);
return r; 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; struct ch341_private *priv;
priv = usb_get_serial_port_data(port); priv = usb_get_serial_port_data(port);
kfree(priv); kfree(priv);
return 0;
} }
static int ch341_carrier_raised(struct usb_serial_port *port) static int ch341_carrier_raised(struct usb_serial_port *port)
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
* Silicon Laboratories CP210x USB to RS232 serial adaptor driver * Silicon Laboratories CP210x USB to RS232 serial adaptor driver
* *
* Copyright (C) 2005 Craig Shelley (craig@microtron.org.uk) * 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 * Support to set flow control line levels using TIOCMGET and TIOCMSET
* thanks to Karl Hiramoto karl@hiramoto.org. RTSCTS hardware flow * thanks to Karl Hiramoto karl@hiramoto.org. RTSCTS hardware flow
...@@ -16,9 +17,7 @@ ...@@ -16,9 +17,7 @@
#include <linux/tty.h> #include <linux/tty.h>
#include <linux/tty_flip.h> #include <linux/tty_flip.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/uaccess.h>
#include <linux/usb/serial.h> #include <linux/usb/serial.h>
#include <linux/gpio/driver.h> #include <linux/gpio/driver.h>
#include <linux/bitops.h> #include <linux/bitops.h>
...@@ -45,7 +44,7 @@ static int cp210x_attach(struct usb_serial *); ...@@ -45,7 +44,7 @@ static int cp210x_attach(struct usb_serial *);
static void cp210x_disconnect(struct usb_serial *); static void cp210x_disconnect(struct usb_serial *);
static void cp210x_release(struct usb_serial *); static void cp210x_release(struct usb_serial *);
static int cp210x_port_probe(struct usb_serial_port *); 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_dtr_rts(struct usb_serial_port *port, int on);
static void cp210x_process_read_urb(struct urb *urb); static void cp210x_process_read_urb(struct urb *urb);
static void cp210x_enable_event_mode(struct usb_serial_port *port); static void cp210x_enable_event_mode(struct usb_serial_port *port);
...@@ -268,7 +267,12 @@ struct cp210x_port_private { ...@@ -268,7 +267,12 @@ struct cp210x_port_private {
u8 bInterfaceNumber; u8 bInterfaceNumber;
bool event_mode; bool event_mode;
enum cp210x_event_state event_state; 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 = { static struct usb_serial_driver cp210x_device = {
...@@ -379,6 +383,16 @@ static struct usb_serial_driver * const serial_drivers[] = { ...@@ -379,6 +383,16 @@ static struct usb_serial_driver * const serial_drivers[] = {
#define CONTROL_WRITE_DTR 0x0100 #define CONTROL_WRITE_DTR 0x0100
#define CONTROL_WRITE_RTS 0x0200 #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 */ /* CP210X_VENDOR_SPECIFIC values */
#define CP210X_READ_2NCONFIG 0x000E #define CP210X_READ_2NCONFIG 0x000E
#define CP210X_READ_LATCH 0x00C2 #define CP210X_READ_LATCH 0x00C2
...@@ -437,17 +451,14 @@ struct cp210x_flow_ctl { ...@@ -437,17 +451,14 @@ struct cp210x_flow_ctl {
/* cp210x_flow_ctl::ulControlHandshake */ /* cp210x_flow_ctl::ulControlHandshake */
#define CP210X_SERIAL_DTR_MASK GENMASK(1, 0) #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_CTS_HANDSHAKE BIT(3)
#define CP210X_SERIAL_DSR_HANDSHAKE BIT(4) #define CP210X_SERIAL_DSR_HANDSHAKE BIT(4)
#define CP210X_SERIAL_DCD_HANDSHAKE BIT(5) #define CP210X_SERIAL_DCD_HANDSHAKE BIT(5)
#define CP210X_SERIAL_DSR_SENSITIVITY BIT(6) #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 */ /* cp210x_flow_ctl::ulFlowReplace */
#define CP210X_SERIAL_AUTO_TRANSMIT BIT(0) #define CP210X_SERIAL_AUTO_TRANSMIT BIT(0)
#define CP210X_SERIAL_AUTO_RECEIVE BIT(1) #define CP210X_SERIAL_AUTO_RECEIVE BIT(1)
...@@ -455,14 +466,11 @@ struct cp210x_flow_ctl { ...@@ -455,14 +466,11 @@ struct cp210x_flow_ctl {
#define CP210X_SERIAL_NULL_STRIPPING BIT(3) #define CP210X_SERIAL_NULL_STRIPPING BIT(3)
#define CP210X_SERIAL_BREAK_CHAR BIT(4) #define CP210X_SERIAL_BREAK_CHAR BIT(4)
#define CP210X_SERIAL_RTS_MASK GENMASK(7, 6) #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) #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. */ /* CP210X_VENDOR_SPECIFIC, CP210X_GET_DEVICEMODE call reads these 0x2 bytes. */
struct cp210x_pin_mode { struct cp210x_pin_mode {
u8 eci; u8 eci;
...@@ -666,16 +674,13 @@ static int cp210x_write_reg_block(struct usb_serial_port *port, u8 req, ...@@ -666,16 +674,13 @@ static int cp210x_write_reg_block(struct usb_serial_port *port, u8 req,
kfree(dmabuf); kfree(dmabuf);
if (result == bufsize) { if (result < 0) {
result = 0;
} else {
dev_err(&port->dev, "failed set req 0x%x size %d status: %d\n", dev_err(&port->dev, "failed set req 0x%x size %d status: %d\n",
req, bufsize, result); req, bufsize, result);
if (result >= 0) return result;
result = -EIO;
} }
return result; return 0;
} }
/* /*
...@@ -712,17 +717,14 @@ static int cp210x_write_vendor_block(struct usb_serial *serial, u8 type, ...@@ -712,17 +717,14 @@ static int cp210x_write_vendor_block(struct usb_serial *serial, u8 type,
kfree(dmabuf); kfree(dmabuf);
if (result == bufsize) { if (result < 0) {
result = 0;
} else {
dev_err(&serial->interface->dev, dev_err(&serial->interface->dev,
"failed to set vendor val 0x%04x size %d: %d\n", val, "failed to set vendor val 0x%04x size %d: %d\n", val,
bufsize, result); bufsize, result);
if (result >= 0) return result;
result = -EIO;
} }
return result; return 0;
} }
#endif #endif
...@@ -1076,30 +1078,80 @@ static void cp210x_disable_event_mode(struct usb_serial_port *port) ...@@ -1076,30 +1078,80 @@ static void cp210x_disable_event_mode(struct usb_serial_port *port)
port_priv->event_mode = false; 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) 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, static void cp210x_set_flow_control(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios) 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; struct cp210x_flow_ctl flow_ctl;
u32 flow_repl; u32 flow_repl;
u32 ctl_hs; u32 ctl_hs;
int ret; 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; 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, ret = cp210x_read_reg_block(port, CP210X_GET_FLOW, &flow_ctl,
sizeof(flow_ctl)); sizeof(flow_ctl));
if (ret) if (ret)
return; goto out_unlock;
ctl_hs = le32_to_cpu(flow_ctl.ulControlHandshake); ctl_hs = le32_to_cpu(flow_ctl.ulControlHandshake);
flow_repl = le32_to_cpu(flow_ctl.ulFlowReplace); flow_repl = le32_to_cpu(flow_ctl.ulFlowReplace);
...@@ -1108,26 +1160,51 @@ static void cp210x_set_flow_control(struct tty_struct *tty, ...@@ -1108,26 +1160,51 @@ static void cp210x_set_flow_control(struct tty_struct *tty,
ctl_hs &= ~CP210X_SERIAL_DCD_HANDSHAKE; ctl_hs &= ~CP210X_SERIAL_DCD_HANDSHAKE;
ctl_hs &= ~CP210X_SERIAL_DSR_SENSITIVITY; ctl_hs &= ~CP210X_SERIAL_DSR_SENSITIVITY;
ctl_hs &= ~CP210X_SERIAL_DTR_MASK; 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)) { if (C_CRTSCTS(tty)) {
ctl_hs |= CP210X_SERIAL_CTS_HANDSHAKE; ctl_hs |= CP210X_SERIAL_CTS_HANDSHAKE;
flow_repl &= ~CP210X_SERIAL_RTS_MASK; if (port_priv->rts)
flow_repl |= CP210X_SERIAL_RTS_SHIFT(CP210X_SERIAL_RTS_FLOW_CTL); flow_repl |= CP210X_SERIAL_RTS_FLOW_CTL;
else
flow_repl |= CP210X_SERIAL_RTS_INACTIVE;
port_priv->crtscts = true;
} else { } else {
ctl_hs &= ~CP210X_SERIAL_CTS_HANDSHAKE; ctl_hs &= ~CP210X_SERIAL_CTS_HANDSHAKE;
flow_repl &= ~CP210X_SERIAL_RTS_MASK; if (port_priv->rts)
flow_repl |= CP210X_SERIAL_RTS_SHIFT(CP210X_SERIAL_RTS_ACTIVE); 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", if (I_IXOFF(tty))
__func__, ctl_hs, flow_repl); 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.ulControlHandshake = cpu_to_le32(ctl_hs);
flow_ctl.ulFlowReplace = cpu_to_le32(flow_repl); flow_ctl.ulFlowReplace = cpu_to_le32(flow_repl);
cp210x_write_reg_block(port, CP210X_SET_FLOW, &flow_ctl, cp210x_write_reg_block(port, CP210X_SET_FLOW, &flow_ctl,
sizeof(flow_ctl)); sizeof(flow_ctl));
out_unlock:
mutex_unlock(&port_priv->mutex);
} }
static void cp210x_set_termios(struct tty_struct *tty, static void cp210x_set_termios(struct tty_struct *tty,
...@@ -1212,28 +1289,77 @@ static int cp210x_tiocmset(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, static int cp210x_tiocmset_port(struct usb_serial_port *port,
unsigned int set, unsigned int clear) 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; u16 control = 0;
int ret;
mutex_lock(&port_priv->mutex);
if (set & TIOCM_RTS) { if (set & TIOCM_RTS) {
port_priv->rts = true;
control |= CONTROL_RTS; control |= CONTROL_RTS;
control |= CONTROL_WRITE_RTS; control |= CONTROL_WRITE_RTS;
} }
if (set & TIOCM_DTR) { if (set & TIOCM_DTR) {
port_priv->dtr = true;
control |= CONTROL_DTR; control |= CONTROL_DTR;
control |= CONTROL_WRITE_DTR; control |= CONTROL_WRITE_DTR;
} }
if (clear & TIOCM_RTS) { if (clear & TIOCM_RTS) {
port_priv->rts = false;
control &= ~CONTROL_RTS; control &= ~CONTROL_RTS;
control |= CONTROL_WRITE_RTS; control |= CONTROL_WRITE_RTS;
} }
if (clear & TIOCM_DTR) { if (clear & TIOCM_DTR) {
port_priv->dtr = false;
control &= ~CONTROL_DTR; control &= ~CONTROL_DTR;
control |= CONTROL_WRITE_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;
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;
return cp210x_write_u16_reg(port, CP210X_SET_MHS, control); 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) static void cp210x_dtr_rts(struct usb_serial_port *port, int on)
...@@ -1261,7 +1387,7 @@ static int cp210x_tiocmget(struct tty_struct *tty) ...@@ -1261,7 +1387,7 @@ static int cp210x_tiocmget(struct tty_struct *tty)
|((control & CONTROL_RING)? TIOCM_RI : 0) |((control & CONTROL_RING)? TIOCM_RI : 0)
|((control & CONTROL_DCD) ? TIOCM_CD : 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; return result;
} }
...@@ -1710,20 +1836,19 @@ static int cp210x_port_probe(struct usb_serial_port *port) ...@@ -1710,20 +1836,19 @@ static int cp210x_port_probe(struct usb_serial_port *port)
return -ENOMEM; return -ENOMEM;
port_priv->bInterfaceNumber = cp210x_interface_num(serial); port_priv->bInterfaceNumber = cp210x_interface_num(serial);
mutex_init(&port_priv->mutex);
usb_set_serial_port_data(port, port_priv); usb_set_serial_port_data(port, port_priv);
return 0; 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; struct cp210x_port_private *port_priv;
port_priv = usb_get_serial_port_data(port); port_priv = usb_get_serial_port_data(port);
kfree(port_priv); kfree(port_priv);
return 0;
} }
static void cp210x_init_max_speed(struct usb_serial *serial) static void cp210x_init_max_speed(struct usb_serial *serial)
......
...@@ -47,7 +47,7 @@ ...@@ -47,7 +47,7 @@
/* Function prototypes */ /* Function prototypes */
static int cyberjack_port_probe(struct usb_serial_port *port); 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, static int cyberjack_open(struct tty_struct *tty,
struct usb_serial_port *port); struct usb_serial_port *port);
static void cyberjack_close(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) ...@@ -120,7 +120,7 @@ static int cyberjack_port_probe(struct usb_serial_port *port)
return 0; 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; struct cyberjack_private *priv;
...@@ -128,8 +128,6 @@ static int cyberjack_port_remove(struct usb_serial_port *port) ...@@ -128,8 +128,6 @@ static int cyberjack_port_remove(struct usb_serial_port *port)
priv = usb_get_serial_port_data(port); priv = usb_get_serial_port_data(port);
kfree(priv); kfree(priv);
return 0;
} }
static int cyberjack_open(struct tty_struct *tty, static int cyberjack_open(struct tty_struct *tty,
......
...@@ -115,7 +115,7 @@ struct cypress_private { ...@@ -115,7 +115,7 @@ struct cypress_private {
static int cypress_earthmate_port_probe(struct usb_serial_port *port); 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_hidcom_port_probe(struct usb_serial_port *port);
static int cypress_ca42v2_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 int cypress_open(struct tty_struct *tty, struct usb_serial_port *port);
static void cypress_close(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); 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) ...@@ -564,7 +564,7 @@ static int cypress_ca42v2_port_probe(struct usb_serial_port *port)
return 0; 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; struct cypress_private *priv;
...@@ -572,8 +572,6 @@ static int cypress_port_remove(struct usb_serial_port *port) ...@@ -572,8 +572,6 @@ static int cypress_port_remove(struct usb_serial_port *port)
kfifo_free(&priv->write_fifo); kfifo_free(&priv->write_fifo);
kfree(priv); kfree(priv);
return 0;
} }
static int cypress_open(struct tty_struct *tty, struct usb_serial_port *port) static int cypress_open(struct tty_struct *tty, struct usb_serial_port *port)
......
...@@ -233,7 +233,7 @@ static int digi_startup(struct usb_serial *serial); ...@@ -233,7 +233,7 @@ static int digi_startup(struct usb_serial *serial);
static void digi_disconnect(struct usb_serial *serial); static void digi_disconnect(struct usb_serial *serial);
static void digi_release(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_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 void digi_read_bulk_callback(struct urb *urb);
static int digi_read_inb_callback(struct urb *urb); static int digi_read_inb_callback(struct urb *urb);
static int digi_read_oob_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) ...@@ -1281,14 +1281,12 @@ static int digi_port_probe(struct usb_serial_port *port)
return digi_port_init(port, port->port_number); 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; struct digi_port *priv;
priv = usb_get_serial_port_data(port); priv = usb_get_serial_port_data(port);
kfree(priv); kfree(priv);
return 0;
} }
static void digi_read_bulk_callback(struct urb *urb) static void digi_read_bulk_callback(struct urb *urb)
......
...@@ -192,13 +192,9 @@ static int f81232_set_register(struct usb_serial_port *port, u16 reg, u8 val) ...@@ -192,13 +192,9 @@ static int f81232_set_register(struct usb_serial_port *port, u16 reg, u8 val)
tmp, tmp,
sizeof(val), sizeof(val),
USB_CTRL_SET_TIMEOUT); USB_CTRL_SET_TIMEOUT);
if (status != sizeof(val)) { if (status < 0) {
dev_err(&port->dev, "%s failed status: %d\n", __func__, status); dev_err(&port->dev, "%s failed status: %d\n", __func__, status);
status = usb_translate_errors(status);
if (status < 0)
status = usb_translate_errors(status);
else
status = -EIO;
} else { } else {
status = 0; status = 0;
} }
...@@ -886,10 +882,6 @@ static int f81534a_ctrl_set_register(struct usb_interface *intf, u16 reg, ...@@ -886,10 +882,6 @@ static int f81534a_ctrl_set_register(struct usb_interface *intf, u16 reg,
status = usb_translate_errors(status); status = usb_translate_errors(status);
if (status == -EIO) if (status == -EIO)
continue; continue;
} else if (status != size) {
/* Retry on short transfers */
status = -EIO;
continue;
} else { } else {
status = 0; status = 0;
} }
......
...@@ -235,11 +235,9 @@ static int f81534_set_register(struct usb_serial *serial, u16 reg, u8 data) ...@@ -235,11 +235,9 @@ static int f81534_set_register(struct usb_serial *serial, u16 reg, u8 data)
USB_TYPE_VENDOR | USB_DIR_OUT, USB_TYPE_VENDOR | USB_DIR_OUT,
reg, 0, tmp, sizeof(u8), reg, 0, tmp, sizeof(u8),
F81534_USB_TIMEOUT); F81534_USB_TIMEOUT);
if (status > 0) { if (status == sizeof(u8)) {
status = 0; status = 0;
break; break;
} else if (status == 0) {
status = -EIO;
} }
} }
...@@ -1432,12 +1430,11 @@ static int f81534_port_probe(struct usb_serial_port *port) ...@@ -1432,12 +1430,11 @@ static int f81534_port_probe(struct usb_serial_port *port)
return f81534_set_port_output_pin(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); struct f81534_port_private *port_priv = usb_get_serial_port_data(port);
flush_work(&port_priv->lsr_work); flush_work(&port_priv->lsr_work);
return 0;
} }
static int f81534_tiocmget(struct tty_struct *tty) static int f81534_tiocmget(struct tty_struct *tty)
......
...@@ -1069,7 +1069,7 @@ static const char *ftdi_chip_name[] = { ...@@ -1069,7 +1069,7 @@ static const char *ftdi_chip_name[] = {
static int ftdi_sio_probe(struct usb_serial *serial, static int ftdi_sio_probe(struct usb_serial *serial,
const struct usb_device_id *id); const struct usb_device_id *id);
static int ftdi_sio_port_probe(struct usb_serial_port *port); 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 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_dtr_rts(struct usb_serial_port *port, int on);
static void ftdi_process_read_urb(struct urb *urb); 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) ...@@ -1153,13 +1153,13 @@ static unsigned short int ftdi_232am_baud_base_to_divisor(int baud, int base)
divisor = divisor3 >> 3; divisor = divisor3 >> 3;
divisor3 &= 0x7; divisor3 &= 0x7;
if (divisor3 == 1) if (divisor3 == 1)
divisor |= 0xc000; divisor |= 0xc000; /* +0.125 */
else if (divisor3 >= 4) else if (divisor3 >= 4)
divisor |= 0x4000; divisor |= 0x4000; /* +0.5 */
else if (divisor3 != 0) else if (divisor3 != 0)
divisor |= 0x8000; divisor |= 0x8000; /* +0.25 */
else if (divisor == 1) else if (divisor == 1)
divisor = 0; /* special case for maximum baud rate */ divisor = 0; /* special case for maximum baud rate */
return divisor; return divisor;
} }
...@@ -1177,9 +1177,9 @@ static u32 ftdi_232bm_baud_base_to_divisor(int baud, int base) ...@@ -1177,9 +1177,9 @@ static u32 ftdi_232bm_baud_base_to_divisor(int baud, int base)
divisor = divisor3 >> 3; divisor = divisor3 >> 3;
divisor |= (u32)divfrac[divisor3 & 0x7] << 14; divisor |= (u32)divfrac[divisor3 & 0x7] << 14;
/* Deal with special cases for highest baud rates. */ /* Deal with special cases for highest baud rates. */
if (divisor == 1) if (divisor == 1) /* 1.0 */
divisor = 0; divisor = 0;
else if (divisor == 0x4001) else if (divisor == 0x4001) /* 1.5 */
divisor = 1; divisor = 1;
return divisor; return divisor;
} }
...@@ -1201,9 +1201,9 @@ static u32 ftdi_2232h_baud_base_to_divisor(int baud, int base) ...@@ -1201,9 +1201,9 @@ static u32 ftdi_2232h_baud_base_to_divisor(int baud, int base)
divisor = divisor3 >> 3; divisor = divisor3 >> 3;
divisor |= (u32)divfrac[divisor3 & 0x7] << 14; divisor |= (u32)divfrac[divisor3 & 0x7] << 14;
/* Deal with special cases for highest baud rates. */ /* Deal with special cases for highest baud rates. */
if (divisor == 1) if (divisor == 1) /* 1.0 */
divisor = 0; divisor = 0;
else if (divisor == 0x4001) else if (divisor == 0x4001) /* 1.5 */
divisor = 1; divisor = 1;
/* /*
* Set this bit to turn off a divide by 2.5 on baud rate generator * 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) ...@@ -1386,8 +1386,9 @@ static int change_speed(struct tty_struct *tty, struct usb_serial_port *port)
index_value = get_ftdi_divisor(tty, port); index_value = get_ftdi_divisor(tty, port);
value = (u16)index_value; value = (u16)index_value;
index = (u16)(index_value >> 16); index = (u16)(index_value >> 16);
if ((priv->chip_type == FT2232C) || (priv->chip_type == FT2232H) || if (priv->chip_type == FT2232C || priv->chip_type == FT2232H ||
(priv->chip_type == FT4232H) || (priv->chip_type == FT232H)) { priv->chip_type == FT4232H || priv->chip_type == FT232H ||
priv->chip_type == FTX) {
/* Probably the BM type needs the MSB of the encoded fractional /* Probably the BM type needs the MSB of the encoded fractional
* divider also moved like for the chips above. Any infos? */ * divider also moved like for the chips above. Any infos? */
index = (u16)((index << 8) | priv->interface); index = (u16)((index << 8) | priv->interface);
...@@ -2399,7 +2400,7 @@ static int ftdi_stmclite_probe(struct usb_serial *serial) ...@@ -2399,7 +2400,7 @@ static int ftdi_stmclite_probe(struct usb_serial *serial)
return 0; 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); 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) ...@@ -2408,8 +2409,6 @@ static int ftdi_sio_port_remove(struct usb_serial_port *port)
remove_sysfs_attrs(port); remove_sysfs_attrs(port);
kfree(priv); kfree(priv);
return 0;
} }
static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port) static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)
......
...@@ -1401,7 +1401,7 @@ static int garmin_port_probe(struct usb_serial_port *port) ...@@ -1401,7 +1401,7 @@ static int garmin_port_probe(struct usb_serial_port *port)
} }
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); 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) ...@@ -1409,7 +1409,6 @@ static int garmin_port_remove(struct usb_serial_port *port)
usb_kill_urb(port->interrupt_in_urb); usb_kill_urb(port->interrupt_in_urb);
del_timer_sync(&garmin_data_p->timer); del_timer_sync(&garmin_data_p->timer);
kfree(garmin_data_p); kfree(garmin_data_p);
return 0;
} }
......
...@@ -293,7 +293,7 @@ static int edge_startup(struct usb_serial *serial); ...@@ -293,7 +293,7 @@ static int edge_startup(struct usb_serial *serial);
static void edge_disconnect(struct usb_serial *serial); static void edge_disconnect(struct usb_serial *serial);
static void edge_release(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_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 */ /* function prototypes for all of our local functions */
...@@ -3078,14 +3078,12 @@ static int edge_port_probe(struct usb_serial_port *port) ...@@ -3078,14 +3078,12 @@ static int edge_port_probe(struct usb_serial_port *port)
return 0; 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; struct edgeport_port *edge_port;
edge_port = usb_get_serial_port_data(port); edge_port = usb_get_serial_port_data(port);
kfree(edge_port); kfree(edge_port);
return 0;
} }
static struct usb_serial_driver edgeport_2port_device = { static struct usb_serial_driver edgeport_2port_device = {
......
...@@ -266,7 +266,7 @@ static int ti_vread_sync(struct usb_device *dev, __u8 request, ...@@ -266,7 +266,7 @@ static int ti_vread_sync(struct usb_device *dev, __u8 request,
if (status < 0) if (status < 0)
return status; return status;
if (status != size) { 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); __func__, size, status);
return -ECOMM; return -ECOMM;
} }
...@@ -283,11 +283,7 @@ static int ti_vsend_sync(struct usb_device *dev, u8 request, u16 value, ...@@ -283,11 +283,7 @@ static int ti_vsend_sync(struct usb_device *dev, u8 request, u16 value,
value, index, data, size, timeout); value, index, data, size, timeout);
if (status < 0) if (status < 0)
return status; 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; return 0;
} }
...@@ -2629,15 +2625,13 @@ static int edge_port_probe(struct usb_serial_port *port) ...@@ -2629,15 +2625,13 @@ static int edge_port_probe(struct usb_serial_port *port)
return ret; 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; struct edgeport_port *edge_port;
edge_port = usb_get_serial_port_data(port); edge_port = usb_get_serial_port_data(port);
edge_remove_sysfs_attrs(port); edge_remove_sysfs_attrs(port);
kfree(edge_port); kfree(edge_port);
return 0;
} }
/* Sysfs Attributes */ /* Sysfs Attributes */
......
...@@ -100,7 +100,7 @@ static int iuu_port_probe(struct usb_serial_port *port) ...@@ -100,7 +100,7 @@ static int iuu_port_probe(struct usb_serial_port *port)
return 0; 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); struct iuu_private *priv = usb_get_serial_port_data(port);
...@@ -108,8 +108,6 @@ static int iuu_port_remove(struct usb_serial_port *port) ...@@ -108,8 +108,6 @@ static int iuu_port_remove(struct usb_serial_port *port)
kfree(priv->writebuf); kfree(priv->writebuf);
kfree(priv->buf); kfree(priv->buf);
kfree(priv); kfree(priv);
return 0;
} }
static int iuu_tiocmset(struct tty_struct *tty, static int iuu_tiocmset(struct tty_struct *tty,
......
...@@ -49,7 +49,7 @@ static int keyspan_startup(struct usb_serial *serial); ...@@ -49,7 +49,7 @@ static int keyspan_startup(struct usb_serial *serial);
static void keyspan_disconnect(struct usb_serial *serial); static void keyspan_disconnect(struct usb_serial *serial);
static void keyspan_release(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_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_room(struct tty_struct *tty);
static int keyspan_write(struct tty_struct *tty, struct usb_serial_port *port, static int keyspan_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count); const unsigned char *buf, int count);
...@@ -2985,7 +2985,7 @@ static int keyspan_port_probe(struct usb_serial_port *port) ...@@ -2985,7 +2985,7 @@ static int keyspan_port_probe(struct usb_serial_port *port)
return -ENOMEM; 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; struct keyspan_port_private *p_priv;
int i; int i;
...@@ -3014,8 +3014,6 @@ static int keyspan_port_remove(struct usb_serial_port *port) ...@@ -3014,8 +3014,6 @@ static int keyspan_port_remove(struct usb_serial_port *port)
kfree(p_priv->in_buffer[i]); kfree(p_priv->in_buffer[i]);
kfree(p_priv); kfree(p_priv);
return 0;
} }
/* Structs for the devices, pre and post renumeration. */ /* Structs for the devices, pre and post renumeration. */
......
...@@ -672,14 +672,12 @@ static int keyspan_pda_port_probe(struct usb_serial_port *port) ...@@ -672,14 +672,12 @@ static int keyspan_pda_port_probe(struct usb_serial_port *port)
return 0; 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; struct keyspan_pda_private *priv;
priv = usb_get_serial_port_data(port); priv = usb_get_serial_port_data(port);
kfree(priv); kfree(priv);
return 0;
} }
static struct usb_serial_driver keyspan_pda_fake_device = { static struct usb_serial_driver keyspan_pda_fake_device = {
......
...@@ -52,7 +52,7 @@ ...@@ -52,7 +52,7 @@
* Function prototypes * Function prototypes
*/ */
static int klsi_105_port_probe(struct usb_serial_port *port); 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 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_close(struct usb_serial_port *port);
static void klsi_105_set_termios(struct tty_struct *tty, 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) ...@@ -231,14 +231,12 @@ static int klsi_105_port_probe(struct usb_serial_port *port)
return 0; 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; struct klsi_105_private *priv;
priv = usb_get_serial_port_data(port); priv = usb_get_serial_port_data(port);
kfree(priv); kfree(priv);
return 0;
} }
static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port) static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port)
......
...@@ -48,7 +48,7 @@ ...@@ -48,7 +48,7 @@
/* Function prototypes */ /* Function prototypes */
static int kobil_port_probe(struct usb_serial_port *probe); 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 int kobil_open(struct tty_struct *tty, struct usb_serial_port *port);
static void kobil_close(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, 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) ...@@ -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; struct kobil_private *priv;
priv = usb_get_serial_port_data(port); priv = usb_get_serial_port_data(port);
kfree(priv); kfree(priv);
return 0;
} }
static void kobil_init_termios(struct tty_struct *tty) static void kobil_init_termios(struct tty_struct *tty)
......
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
* Function prototypes * Function prototypes
*/ */
static int mct_u232_port_probe(struct usb_serial_port *port); 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 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_close(struct usb_serial_port *port);
static void mct_u232_dtr_rts(struct usb_serial_port *port, int on); 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) ...@@ -400,14 +400,12 @@ static int mct_u232_port_probe(struct usb_serial_port *port)
return 0; 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; struct mct_u232_private *priv;
priv = usb_get_serial_port_data(port); priv = usb_get_serial_port_data(port);
kfree(priv); kfree(priv);
return 0;
} }
static int mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port) static int mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port)
......
...@@ -256,14 +256,12 @@ static int metrousb_port_probe(struct usb_serial_port *port) ...@@ -256,14 +256,12 @@ static int metrousb_port_probe(struct usb_serial_port *port)
return 0; 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; struct metrousb_private *metro_priv;
metro_priv = usb_get_serial_port_data(port); metro_priv = usb_get_serial_port_data(port);
kfree(metro_priv); kfree(metro_priv);
return 0;
} }
static void metrousb_throttle(struct tty_struct *tty) static void metrousb_throttle(struct tty_struct *tty)
......
...@@ -215,8 +215,10 @@ static int read_mos_reg(struct usb_serial *serial, unsigned int serial_portnum, ...@@ -215,8 +215,10 @@ static int read_mos_reg(struct usb_serial *serial, unsigned int serial_portnum,
int status; int status;
buf = kmalloc(1, GFP_KERNEL); buf = kmalloc(1, GFP_KERNEL);
if (!buf) if (!buf) {
*data = 0;
return -ENOMEM; return -ENOMEM;
}
status = usb_control_msg(usbdev, pipe, request, requesttype, value, status = usb_control_msg(usbdev, pipe, request, requesttype, value,
index, buf, 1, MOS_WDR_TIMEOUT); index, buf, 1, MOS_WDR_TIMEOUT);
...@@ -1092,8 +1094,10 @@ static int mos7720_write(struct tty_struct *tty, struct usb_serial_port *port, ...@@ -1092,8 +1094,10 @@ static int mos7720_write(struct tty_struct *tty, struct usb_serial_port *port,
if (urb->transfer_buffer == NULL) { if (urb->transfer_buffer == NULL) {
urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE, urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE,
GFP_ATOMIC); GFP_ATOMIC);
if (!urb->transfer_buffer) if (!urb->transfer_buffer) {
bytes_sent = -ENOMEM;
goto exit; goto exit;
}
} }
transfer_size = min(count, URB_TRANSFER_BUFFER_SIZE); transfer_size = min(count, URB_TRANSFER_BUFFER_SIZE);
...@@ -1756,14 +1760,12 @@ static int mos7720_port_probe(struct usb_serial_port *port) ...@@ -1756,14 +1760,12 @@ static int mos7720_port_probe(struct usb_serial_port *port)
return 0; 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; struct moschip_port *mos7720_port;
mos7720_port = usb_get_serial_port_data(port); mos7720_port = usb_get_serial_port_data(port);
kfree(mos7720_port); kfree(mos7720_port);
return 0;
} }
static struct usb_serial_driver moschip7720_2port_driver = { static struct usb_serial_driver moschip7720_2port_driver = {
......
...@@ -883,8 +883,10 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port, ...@@ -883,8 +883,10 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port,
if (urb->transfer_buffer == NULL) { if (urb->transfer_buffer == NULL) {
urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE, urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE,
GFP_ATOMIC); GFP_ATOMIC);
if (!urb->transfer_buffer) if (!urb->transfer_buffer) {
bytes_sent = -ENOMEM;
goto exit; goto exit;
}
} }
transfer_size = min(count, URB_TRANSFER_BUFFER_SIZE); transfer_size = min(count, URB_TRANSFER_BUFFER_SIZE);
...@@ -1743,7 +1745,7 @@ static int mos7840_port_probe(struct usb_serial_port *port) ...@@ -1743,7 +1745,7 @@ static int mos7840_port_probe(struct usb_serial_port *port)
return status; 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); 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) ...@@ -1760,8 +1762,6 @@ static int mos7840_port_remove(struct usb_serial_port *port)
} }
kfree(mos7840_port); kfree(mos7840_port);
return 0;
} }
static struct usb_serial_driver moschip7840_4port_device = { static struct usb_serial_driver moschip7840_4port_device = {
......
...@@ -261,13 +261,6 @@ static int mxuport_send_ctrl_data_urb(struct usb_serial *serial, ...@@ -261,13 +261,6 @@ static int mxuport_send_ctrl_data_urb(struct usb_serial *serial,
return status; return status;
} }
if (status != size) {
dev_err(&serial->interface->dev,
"%s - short write (%d / %zd)\n",
__func__, status, size);
return -EIO;
}
return 0; return 0;
} }
......
...@@ -36,7 +36,7 @@ static int omninet_prepare_write_buffer(struct usb_serial_port *port, ...@@ -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, static int omninet_calc_num_ports(struct usb_serial *serial,
struct usb_serial_endpoints *epds); struct usb_serial_endpoints *epds);
static int omninet_port_probe(struct usb_serial_port *port); 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[] = { static const struct usb_device_id id_table[] = {
{ USB_DEVICE(ZYXEL_VENDOR_ID, ZYXEL_OMNINET_ID) }, { USB_DEVICE(ZYXEL_VENDOR_ID, ZYXEL_OMNINET_ID) },
...@@ -121,14 +121,12 @@ static int omninet_port_probe(struct usb_serial_port *port) ...@@ -121,14 +121,12 @@ static int omninet_port_probe(struct usb_serial_port *port)
return 0; 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; struct omninet_data *od;
od = usb_get_serial_port_data(port); od = usb_get_serial_port_data(port);
kfree(od); kfree(od);
return 0;
} }
#define OMNINET_HEADERLEN 4 #define OMNINET_HEADERLEN 4
......
...@@ -385,13 +385,11 @@ static int opticon_port_probe(struct usb_serial_port *port) ...@@ -385,13 +385,11 @@ static int opticon_port_probe(struct usb_serial_port *port)
return 0; 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); struct opticon_private *priv = usb_get_serial_port_data(port);
kfree(priv); kfree(priv);
return 0;
} }
static struct usb_serial_driver opticon_device = { static struct usb_serial_driver opticon_device = {
......
...@@ -1569,7 +1569,8 @@ static const struct usb_device_id option_ids[] = { ...@@ -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, 0x1272, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1273, 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, 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, 0x1276, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1277, 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) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1278, 0xff, 0xff, 0xff) },
......
...@@ -132,7 +132,7 @@ static int oti6858_tiocmget(struct tty_struct *tty); ...@@ -132,7 +132,7 @@ static int oti6858_tiocmget(struct tty_struct *tty);
static int oti6858_tiocmset(struct tty_struct *tty, static int oti6858_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear); unsigned int set, unsigned int clear);
static int oti6858_port_probe(struct usb_serial_port *port); 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 */ /* device info */
static struct usb_serial_driver oti6858_device = { static struct usb_serial_driver oti6858_device = {
...@@ -344,14 +344,12 @@ static int oti6858_port_probe(struct usb_serial_port *port) ...@@ -344,14 +344,12 @@ static int oti6858_port_probe(struct usb_serial_port *port)
return 0; 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; struct oti6858_private *priv;
priv = usb_get_serial_port_data(port); priv = usb_get_serial_port_data(port);
kfree(priv); kfree(priv);
return 0;
} }
static int oti6858_write(struct tty_struct *tty, struct usb_serial_port *port, static int oti6858_write(struct tty_struct *tty, struct usb_serial_port *port,
......
...@@ -183,6 +183,7 @@ struct pl2303_type_data { ...@@ -183,6 +183,7 @@ struct pl2303_type_data {
speed_t max_baud_rate; speed_t max_baud_rate;
unsigned long quirks; unsigned long quirks;
unsigned int no_autoxonxoff:1; unsigned int no_autoxonxoff:1;
unsigned int no_divisors:1;
}; };
struct pl2303_serial_private { struct pl2303_serial_private {
...@@ -209,6 +210,7 @@ static const struct pl2303_type_data pl2303_type_data[TYPE_COUNT] = { ...@@ -209,6 +210,7 @@ static const struct pl2303_type_data pl2303_type_data[TYPE_COUNT] = {
}, },
[TYPE_HXN] = { [TYPE_HXN] = {
.max_baud_rate = 12000000, .max_baud_rate = 12000000,
.no_divisors = true,
}, },
}; };
...@@ -448,13 +450,11 @@ static int pl2303_port_probe(struct usb_serial_port *port) ...@@ -448,13 +450,11 @@ static int pl2303_port_probe(struct usb_serial_port *port)
return 0; 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); struct pl2303_private *priv = usb_get_serial_port_data(port);
kfree(priv); kfree(priv);
return 0;
} }
static int pl2303_set_control_lines(struct usb_serial_port *port, u8 value) 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, ...@@ -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); baud = min_t(speed_t, baud, spriv->type->max_baud_rate);
/* /*
* Use direct method for supported baud rates, otherwise use divisors. * 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) if (baud == baud_sup)
baud = pl2303_encode_baud_rate_direct(buf, baud); baud = pl2303_encode_baud_rate_direct(buf, baud);
......
...@@ -727,7 +727,7 @@ static int qt2_port_probe(struct usb_serial_port *port) ...@@ -727,7 +727,7 @@ static int qt2_port_probe(struct usb_serial_port *port)
return -ENOMEM; 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; struct qt2_port_private *port_priv;
...@@ -735,8 +735,6 @@ static int qt2_port_remove(struct usb_serial_port *port) ...@@ -735,8 +735,6 @@ static int qt2_port_remove(struct usb_serial_port *port)
usb_free_urb(port_priv->write_urb); usb_free_urb(port_priv->write_urb);
kfree(port_priv->write_buffer); kfree(port_priv->write_buffer);
kfree(port_priv); kfree(port_priv);
return 0;
} }
static int qt2_tiocmget(struct tty_struct *tty) static int qt2_tiocmget(struct tty_struct *tty)
......
...@@ -901,15 +901,13 @@ static int sierra_port_probe(struct usb_serial_port *port) ...@@ -901,15 +901,13 @@ static int sierra_port_probe(struct usb_serial_port *port)
return 0; 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; struct sierra_port_private *portdata;
portdata = usb_get_serial_port_data(port); portdata = usb_get_serial_port_data(port);
usb_set_serial_port_data(port, NULL); usb_set_serial_port_data(port, NULL);
kfree(portdata); kfree(portdata);
return 0;
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM
......
...@@ -169,14 +169,12 @@ static int spcp8x5_port_probe(struct usb_serial_port *port) ...@@ -169,14 +169,12 @@ static int spcp8x5_port_probe(struct usb_serial_port *port)
return 0; 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; struct spcp8x5_private *priv;
priv = usb_get_serial_port_data(port); priv = usb_get_serial_port_data(port);
kfree(priv); kfree(priv);
return 0;
} }
static int spcp8x5_set_ctrl_line(struct usb_serial_port *port, u8 mcr) static int spcp8x5_set_ctrl_line(struct usb_serial_port *port, u8 mcr)
......
...@@ -366,14 +366,12 @@ static int ssu100_port_probe(struct usb_serial_port *port) ...@@ -366,14 +366,12 @@ static int ssu100_port_probe(struct usb_serial_port *port)
return 0; 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; struct ssu100_port_private *priv;
priv = usb_get_serial_port_data(port); priv = usb_get_serial_port_data(port);
kfree(priv); kfree(priv);
return 0;
} }
static int ssu100_tiocmget(struct tty_struct *tty) static int ssu100_tiocmget(struct tty_struct *tty)
......
...@@ -160,13 +160,11 @@ static int symbol_port_probe(struct usb_serial_port *port) ...@@ -160,13 +160,11 @@ static int symbol_port_probe(struct usb_serial_port *port)
return 0; 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); struct symbol_private *priv = usb_get_serial_port_data(port);
kfree(priv); kfree(priv);
return 0;
} }
static struct usb_serial_driver symbol_device = { static struct usb_serial_driver symbol_device = {
......
...@@ -303,7 +303,7 @@ struct ti_device { ...@@ -303,7 +303,7 @@ struct ti_device {
static int ti_startup(struct usb_serial *serial); static int ti_startup(struct usb_serial *serial);
static void ti_release(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_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 int ti_open(struct tty_struct *tty, struct usb_serial_port *port);
static void ti_close(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, 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) ...@@ -629,14 +629,12 @@ static int ti_port_probe(struct usb_serial_port *port)
return 0; 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; struct ti_port *tport;
tport = usb_get_serial_port_data(port); tport = usb_get_serial_port_data(port);
kfree(tport); kfree(tport);
return 0;
} }
static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) static int ti_open(struct tty_struct *tty, struct usb_serial_port *port)
......
...@@ -145,14 +145,11 @@ static int upd78f0730_send_ctl(struct usb_serial_port *port, ...@@ -145,14 +145,11 @@ static int upd78f0730_send_ctl(struct usb_serial_port *port,
kfree(buf); kfree(buf);
if (res != size) { if (res < 0) {
struct device *dev = &port->dev; struct device *dev = &port->dev;
dev_err(dev, "failed to send control request %02x: %d\n", dev_err(dev, "failed to send control request %02x: %d\n",
*(u8 *)data, res); *(u8 *)data, res);
/* The maximum expected length of a transfer is 6 bytes */
if (res >= 0)
res = -EIO;
return res; return res;
} }
...@@ -174,15 +171,13 @@ static int upd78f0730_port_probe(struct usb_serial_port *port) ...@@ -174,15 +171,13 @@ static int upd78f0730_port_probe(struct usb_serial_port *port)
return 0; 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; struct upd78f0730_port_private *private;
private = usb_get_serial_port_data(port); private = usb_get_serial_port_data(port);
mutex_destroy(&private->lock); mutex_destroy(&private->lock);
kfree(private); kfree(private);
return 0;
} }
static int upd78f0730_tiocmget(struct tty_struct *tty) static int upd78f0730_tiocmget(struct tty_struct *tty)
......
...@@ -10,7 +10,7 @@ extern void usb_wwan_dtr_rts(struct usb_serial_port *port, int on); ...@@ -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 int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port);
extern void usb_wwan_close(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_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_write_room(struct tty_struct *tty);
extern int usb_wwan_tiocmget(struct tty_struct *tty); extern int usb_wwan_tiocmget(struct tty_struct *tty);
extern int usb_wwan_tiocmset(struct tty_struct *tty, extern int usb_wwan_tiocmset(struct tty_struct *tty,
......
...@@ -544,7 +544,7 @@ int usb_wwan_port_probe(struct usb_serial_port *port) ...@@ -544,7 +544,7 @@ int usb_wwan_port_probe(struct usb_serial_port *port)
} }
EXPORT_SYMBOL_GPL(usb_wwan_port_probe); 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; int i;
struct usb_wwan_port_private *portdata; struct usb_wwan_port_private *portdata;
...@@ -562,8 +562,6 @@ int usb_wwan_port_remove(struct usb_serial_port *port) ...@@ -562,8 +562,6 @@ int usb_wwan_port_remove(struct usb_serial_port *port)
} }
kfree(portdata); kfree(portdata);
return 0;
} }
EXPORT_SYMBOL(usb_wwan_port_remove); EXPORT_SYMBOL(usb_wwan_port_remove);
......
...@@ -79,7 +79,7 @@ static int whiteheat_firmware_attach(struct usb_serial *serial); ...@@ -79,7 +79,7 @@ static int whiteheat_firmware_attach(struct usb_serial *serial);
static int whiteheat_attach(struct usb_serial *serial); static int whiteheat_attach(struct usb_serial *serial);
static void whiteheat_release(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_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, static int whiteheat_open(struct tty_struct *tty,
struct usb_serial_port *port); struct usb_serial_port *port);
static void whiteheat_close(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) ...@@ -345,14 +345,12 @@ static int whiteheat_port_probe(struct usb_serial_port *port)
return 0; 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; struct whiteheat_private *info;
info = usb_get_serial_port_data(port); info = usb_get_serial_port_data(port);
kfree(info); kfree(info);
return 0;
} }
static int whiteheat_open(struct tty_struct *tty, struct usb_serial_port *port) static int whiteheat_open(struct tty_struct *tty, struct usb_serial_port *port)
......
// 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");
...@@ -260,7 +260,7 @@ struct usb_serial_driver { ...@@ -260,7 +260,7 @@ struct usb_serial_driver {
void (*release)(struct usb_serial *serial); void (*release)(struct usb_serial *serial);
int (*port_probe)(struct usb_serial_port *port); 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 (*suspend)(struct usb_serial *serial, pm_message_t message);
int (*resume)(struct usb_serial *serial); int (*resume)(struct usb_serial *serial);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册