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:
commit
c85bfed171
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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) },
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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");
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue