Commit b40e9dc0 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

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

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

Johan writes:

USB-serial updates for v4.5-rc1

These updates add support for Moxa UPort 1100-series devices through a
new mxu11x0 driver.

The cp210x driver gains proper support for cp2108 devices by working
around a couple of firmware bugs, and generic wait-until-sent support
(e.g. for tcdrain) is also added.

Included are also some general clean ups.
Signed-off-by: default avatarJohan Hovold <johan@kernel.org>
parents daf27335 6ff9d276
......@@ -475,6 +475,22 @@ config USB_SERIAL_MOS7840
To compile this driver as a module, choose M here: the
module will be called mos7840. If unsure, choose N.
config USB_SERIAL_MXUPORT11
tristate "USB Moxa UPORT 11x0 Serial Driver"
---help---
Say Y here if you want to use a MOXA UPort 11x0 Serial hub.
This driver supports:
- UPort 1110 : 1 port RS-232 USB to Serial Hub.
- UPort 1130 : 1 port RS-422/485 USB to Serial Hub.
- UPort 1130I : 1 port RS-422/485 USB to Serial Hub with Isolation.
- UPort 1150 : 1 port RS-232/422/485 USB to Serial Hub.
- UPort 1150I : 1 port RS-232/422/485 USB to Serial Hub with Isolation.
To compile this driver as a module, choose M here: the
module will be called mxu11x0.
config USB_SERIAL_MXUPORT
tristate "USB Moxa UPORT Serial Driver"
---help---
......
......@@ -38,6 +38,7 @@ obj-$(CONFIG_USB_SERIAL_METRO) += metro-usb.o
obj-$(CONFIG_USB_SERIAL_MOS7720) += mos7720.o
obj-$(CONFIG_USB_SERIAL_MOS7840) += mos7840.o
obj-$(CONFIG_USB_SERIAL_MXUPORT) += mxuport.o
obj-$(CONFIG_USB_SERIAL_MXUPORT11) += mxu11x0.o
obj-$(CONFIG_USB_SERIAL_NAVMAN) += navman.o
obj-$(CONFIG_USB_SERIAL_OMNINET) += omninet.o
obj-$(CONFIG_USB_SERIAL_OPTICON) += opticon.o
......
......@@ -38,13 +38,14 @@ static void cp210x_change_speed(struct tty_struct *, struct usb_serial_port *,
struct ktermios *);
static void cp210x_set_termios(struct tty_struct *, struct usb_serial_port *,
struct ktermios*);
static bool cp210x_tx_empty(struct usb_serial_port *port);
static int cp210x_tiocmget(struct tty_struct *);
static int cp210x_tiocmset(struct tty_struct *, unsigned int, unsigned int);
static int cp210x_tiocmset_port(struct usb_serial_port *port,
unsigned int, unsigned int);
static void cp210x_break_ctl(struct tty_struct *, int);
static int cp210x_startup(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_dtr_rts(struct usb_serial_port *p, int on);
static const struct usb_device_id id_table[] = {
......@@ -196,8 +197,9 @@ static const struct usb_device_id id_table[] = {
MODULE_DEVICE_TABLE(usb, id_table);
struct cp210x_serial_private {
struct cp210x_port_private {
__u8 bInterfaceNumber;
bool has_swapped_line_ctl;
};
static struct usb_serial_driver cp210x_device = {
......@@ -213,10 +215,11 @@ static struct usb_serial_driver cp210x_device = {
.close = cp210x_close,
.break_ctl = cp210x_break_ctl,
.set_termios = cp210x_set_termios,
.tx_empty = cp210x_tx_empty,
.tiocmget = cp210x_tiocmget,
.tiocmset = cp210x_tiocmset,
.attach = cp210x_startup,
.release = cp210x_release,
.port_probe = cp210x_port_probe,
.port_remove = cp210x_port_remove,
.dtr_rts = cp210x_dtr_rts
};
......@@ -299,6 +302,25 @@ static struct usb_serial_driver * const serial_drivers[] = {
#define CONTROL_WRITE_DTR 0x0100
#define CONTROL_WRITE_RTS 0x0200
/* CP210X_GET_COMM_STATUS returns these 0x13 bytes */
struct cp210x_comm_status {
__le32 ulErrors;
__le32 ulHoldReasons;
__le32 ulAmountInInQueue;
__le32 ulAmountInOutQueue;
u8 bEofReceived;
u8 bWaitForImmediate;
u8 bReserved;
} __packed;
/*
* CP210X_PURGE - 16 bits passed in wValue of USB request.
* SiLabs app note AN571 gives a strange description of the 4 bits:
* bit 0 or bit 2 clears the transmit queue and 1 or 3 receive.
* writing 1 to all, however, purges cp2108 well enough to avoid the hang.
*/
#define PURGE_ALL 0x000f
/*
* cp210x_get_config
* Reads from the CP210x configuration registers
......@@ -310,7 +332,7 @@ static int cp210x_get_config(struct usb_serial_port *port, u8 request,
unsigned int *data, int size)
{
struct usb_serial *serial = port->serial;
struct cp210x_serial_private *spriv = usb_get_serial_data(serial);
struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);
__le32 *buf;
int result, i, length;
......@@ -324,7 +346,7 @@ static int cp210x_get_config(struct usb_serial_port *port, u8 request,
/* Issue the request, attempting to read 'size' bytes */
result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
request, REQTYPE_INTERFACE_TO_HOST, 0x0000,
spriv->bInterfaceNumber, buf, size,
port_priv->bInterfaceNumber, buf, size,
USB_CTRL_GET_TIMEOUT);
/* Convert data into an array of integers */
......@@ -355,7 +377,7 @@ static int cp210x_set_config(struct usb_serial_port *port, u8 request,
unsigned int *data, int size)
{
struct usb_serial *serial = port->serial;
struct cp210x_serial_private *spriv = usb_get_serial_data(serial);
struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);
__le32 *buf;
int result, i, length;
......@@ -374,13 +396,13 @@ static int cp210x_set_config(struct usb_serial_port *port, u8 request,
result = usb_control_msg(serial->dev,
usb_sndctrlpipe(serial->dev, 0),
request, REQTYPE_HOST_TO_INTERFACE, 0x0000,
spriv->bInterfaceNumber, buf, size,
port_priv->bInterfaceNumber, buf, size,
USB_CTRL_SET_TIMEOUT);
} else {
result = usb_control_msg(serial->dev,
usb_sndctrlpipe(serial->dev, 0),
request, REQTYPE_HOST_TO_INTERFACE, data[0],
spriv->bInterfaceNumber, NULL, 0,
port_priv->bInterfaceNumber, NULL, 0,
USB_CTRL_SET_TIMEOUT);
}
......@@ -409,6 +431,60 @@ static inline int cp210x_set_config_single(struct usb_serial_port *port,
return cp210x_set_config(port, request, &data, 2);
}
/*
* Detect CP2108 GET_LINE_CTL bug and activate workaround.
* Write a known good value 0x800, read it back.
* If it comes back swapped the bug is detected.
* Preserve the original register value.
*/
static int cp210x_detect_swapped_line_ctl(struct usb_serial_port *port)
{
struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);
unsigned int line_ctl_save;
unsigned int line_ctl_test;
int err;
err = cp210x_get_config(port, CP210X_GET_LINE_CTL, &line_ctl_save, 2);
if (err)
return err;
line_ctl_test = 0x800;
err = cp210x_set_config(port, CP210X_SET_LINE_CTL, &line_ctl_test, 2);
if (err)
return err;
err = cp210x_get_config(port, CP210X_GET_LINE_CTL, &line_ctl_test, 2);
if (err)
return err;
if (line_ctl_test == 8) {
port_priv->has_swapped_line_ctl = true;
line_ctl_save = swab16((u16)line_ctl_save);
}
return cp210x_set_config(port, CP210X_SET_LINE_CTL, &line_ctl_save, 2);
}
/*
* Must always be called instead of cp210x_get_config(CP210X_GET_LINE_CTL)
* to workaround cp2108 bug and get correct value.
*/
static int cp210x_get_line_ctl(struct usb_serial_port *port, unsigned int *ctl)
{
struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);
int err;
err = cp210x_get_config(port, CP210X_GET_LINE_CTL, ctl, 2);
if (err)
return err;
/* Workaround swapped bytes in 16-bit value from CP210X_GET_LINE_CTL */
if (port_priv->has_swapped_line_ctl)
*ctl = swab16((u16)(*ctl));
return 0;
}
/*
* cp210x_quantise_baudrate
* Quantises the baud rate as per AN205 Table 1
......@@ -474,10 +550,62 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port)
static void cp210x_close(struct usb_serial_port *port)
{
unsigned int purge_ctl;
usb_serial_generic_close(port);
/* Clear both queues; cp2108 needs this to avoid an occasional hang */
purge_ctl = PURGE_ALL;
cp210x_set_config(port, CP210X_PURGE, &purge_ctl, 2);
cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_DISABLE);
}
/*
* Read how many bytes are waiting in the TX queue.
*/
static int cp210x_get_tx_queue_byte_count(struct usb_serial_port *port,
u32 *count)
{
struct usb_serial *serial = port->serial;
struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);
struct cp210x_comm_status *sts;
int result;
sts = kmalloc(sizeof(*sts), GFP_KERNEL);
if (!sts)
return -ENOMEM;
result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
CP210X_GET_COMM_STATUS, REQTYPE_INTERFACE_TO_HOST,
0, port_priv->bInterfaceNumber, sts, sizeof(*sts),
USB_CTRL_GET_TIMEOUT);
if (result == sizeof(*sts)) {
*count = le32_to_cpu(sts->ulAmountInOutQueue);
result = 0;
} else {
dev_err(&port->dev, "failed to get comm status: %d\n", result);
if (result >= 0)
result = -EPROTO;
}
kfree(sts);
return result;
}
static bool cp210x_tx_empty(struct usb_serial_port *port)
{
int err;
u32 count;
err = cp210x_get_tx_queue_byte_count(port, &count);
if (err)
return true;
return !count;
}
/*
* cp210x_get_termios
* Reads the baud rate, data bits, parity, stop bits and flow control mode
......@@ -519,7 +647,7 @@ static void cp210x_get_termios_port(struct usb_serial_port *port,
cflag = *cflagp;
cp210x_get_config(port, CP210X_GET_LINE_CTL, &bits, 2);
cp210x_get_line_ctl(port, &bits);
cflag &= ~CSIZE;
switch (bits & BITS_DATA_MASK) {
case BITS_DATA_5:
......@@ -687,7 +815,7 @@ static void cp210x_set_termios(struct tty_struct *tty,
/* If the number of data bits is to be updated */
if ((cflag & CSIZE) != (old_cflag & CSIZE)) {
cp210x_get_config(port, CP210X_GET_LINE_CTL, &bits, 2);
cp210x_get_line_ctl(port, &bits);
bits &= ~BITS_DATA_MASK;
switch (cflag & CSIZE) {
case CS5:
......@@ -721,7 +849,7 @@ static void cp210x_set_termios(struct tty_struct *tty,
if ((cflag & (PARENB|PARODD|CMSPAR)) !=
(old_cflag & (PARENB|PARODD|CMSPAR))) {
cp210x_get_config(port, CP210X_GET_LINE_CTL, &bits, 2);
cp210x_get_line_ctl(port, &bits);
bits &= ~BITS_PARITY_MASK;
if (cflag & PARENB) {
if (cflag & CMSPAR) {
......@@ -747,7 +875,7 @@ static void cp210x_set_termios(struct tty_struct *tty,
}
if ((cflag & CSTOPB) != (old_cflag & CSTOPB)) {
cp210x_get_config(port, CP210X_GET_LINE_CTL, &bits, 2);
cp210x_get_line_ctl(port, &bits);
bits &= ~BITS_STOP_MASK;
if (cflag & CSTOPB) {
bits |= BITS_STOP_2;
......@@ -862,29 +990,39 @@ static void cp210x_break_ctl(struct tty_struct *tty, int break_state)
cp210x_set_config(port, CP210X_SET_BREAK, &state, 2);
}
static int cp210x_startup(struct usb_serial *serial)
static int cp210x_port_probe(struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
struct usb_host_interface *cur_altsetting;
struct cp210x_serial_private *spriv;
struct cp210x_port_private *port_priv;
int ret;
spriv = kzalloc(sizeof(*spriv), GFP_KERNEL);
if (!spriv)
port_priv = kzalloc(sizeof(*port_priv), GFP_KERNEL);
if (!port_priv)
return -ENOMEM;
cur_altsetting = serial->interface->cur_altsetting;
spriv->bInterfaceNumber = cur_altsetting->desc.bInterfaceNumber;
port_priv->bInterfaceNumber = cur_altsetting->desc.bInterfaceNumber;
usb_set_serial_port_data(port, port_priv);
usb_set_serial_data(serial, spriv);
ret = cp210x_detect_swapped_line_ctl(port);
if (ret) {
kfree(port_priv);
return ret;
}
return 0;
}
static void cp210x_release(struct usb_serial *serial)
static int cp210x_port_remove(struct usb_serial_port *port)
{
struct cp210x_serial_private *spriv;
struct cp210x_port_private *port_priv;
port_priv = usb_get_serial_port_data(port);
kfree(port_priv);
spriv = usb_get_serial_data(serial);
kfree(spriv);
return 0;
}
module_usb_serial_driver(serial_drivers, id_table);
......
......@@ -1046,9 +1046,8 @@ static void edge_close(struct usb_serial_port *port)
edge_port->closePending = true;
if ((!edge_serial->is_epic) ||
((edge_serial->is_epic) &&
(edge_serial->epic_descriptor.Supports.IOSPChase))) {
if (!edge_serial->is_epic ||
edge_serial->epic_descriptor.Supports.IOSPChase) {
/* flush and chase */
edge_port->chaseResponsePending = true;
......@@ -1061,9 +1060,8 @@ static void edge_close(struct usb_serial_port *port)
edge_port->chaseResponsePending = false;
}
if ((!edge_serial->is_epic) ||
((edge_serial->is_epic) &&
(edge_serial->epic_descriptor.Supports.IOSPClose))) {
if (!edge_serial->is_epic ||
edge_serial->epic_descriptor.Supports.IOSPClose) {
/* close the port */
dev_dbg(&port->dev, "%s - Sending IOSP_CMD_CLOSE_PORT\n", __func__);
send_iosp_ext_cmd(edge_port, IOSP_CMD_CLOSE_PORT, 0);
......@@ -1612,9 +1610,8 @@ static void edge_break(struct tty_struct *tty, int break_state)
struct edgeport_serial *edge_serial = usb_get_serial_data(port->serial);
int status;
if ((!edge_serial->is_epic) ||
((edge_serial->is_epic) &&
(edge_serial->epic_descriptor.Supports.IOSPChase))) {
if (!edge_serial->is_epic ||
edge_serial->epic_descriptor.Supports.IOSPChase) {
/* flush and chase */
edge_port->chaseResponsePending = true;
......@@ -1628,9 +1625,8 @@ static void edge_break(struct tty_struct *tty, int break_state)
}
}
if ((!edge_serial->is_epic) ||
((edge_serial->is_epic) &&
(edge_serial->epic_descriptor.Supports.IOSPSetClrBreak))) {
if (!edge_serial->is_epic ||
edge_serial->epic_descriptor.Supports.IOSPSetClrBreak) {
if (break_state == -1) {
dev_dbg(&port->dev, "%s - Sending IOSP_CMD_SET_BREAK\n", __func__);
status = send_iosp_ext_cmd(edge_port,
......@@ -2465,9 +2461,8 @@ static void change_port_settings(struct tty_struct *tty,
unsigned char stop_char = STOP_CHAR(tty);
unsigned char start_char = START_CHAR(tty);
if ((!edge_serial->is_epic) ||
((edge_serial->is_epic) &&
(edge_serial->epic_descriptor.Supports.IOSPSetXChar))) {
if (!edge_serial->is_epic ||
edge_serial->epic_descriptor.Supports.IOSPSetXChar) {
send_iosp_ext_cmd(edge_port,
IOSP_CMD_SET_XON_CHAR, start_char);
send_iosp_ext_cmd(edge_port,
......@@ -2494,13 +2489,11 @@ static void change_port_settings(struct tty_struct *tty,
}
/* Set flow control to the configured value */
if ((!edge_serial->is_epic) ||
((edge_serial->is_epic) &&
(edge_serial->epic_descriptor.Supports.IOSPSetRxFlow)))
if (!edge_serial->is_epic ||
edge_serial->epic_descriptor.Supports.IOSPSetRxFlow)
send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_RX_FLOW, rxFlow);
if ((!edge_serial->is_epic) ||
((edge_serial->is_epic) &&
(edge_serial->epic_descriptor.Supports.IOSPSetTxFlow)))
if (!edge_serial->is_epic ||
edge_serial->epic_descriptor.Supports.IOSPSetTxFlow)
send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_TX_FLOW, txFlow);
......
......@@ -635,7 +635,7 @@ static void mos7840_interrupt_callback(struct urb *urb)
* Byte 4 IIR Port 4 (port.number is 3)
* Byte 5 FIFO status for both */
if (length && length > 5) {
if (length > 5) {
dev_dbg(&urb->dev->dev, "%s", "Wrong data !!!\n");
return;
}
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment