Commit ebfb319b authored by Konstantin Shkolnyy's avatar Konstantin Shkolnyy Committed by Johan Hovold

USB: cp210x: flush device queues at close

Flush all device queues at close in order to work around a cp2108 Tx
queue bug.

Occasionally, writing data and immediately closing the port makes cp2108
stop responding. The device has to be unplugged to clear the error.
The failure is induced by shutting down the device while its Tx queue
still has unsent data. This condition is avoided by issuing PURGE command
from the close() callback.

This change is applied to all cp210x devices. Clearing internal queues on
close is generally good.
Signed-off-by: default avatarKonstantin Shkolnyy <konstantin.shkolnyy@gmail.com>
[johan: amend commit message ]
Signed-off-by: default avatarJohan Hovold <johan@kernel.org>
parent 8005c49d
...@@ -300,6 +300,14 @@ static struct usb_serial_driver * const serial_drivers[] = { ...@@ -300,6 +300,14 @@ 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_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 * cp210x_get_config
* Reads from the CP210x configuration registers * Reads from the CP210x configuration registers
...@@ -475,7 +483,14 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port) ...@@ -475,7 +483,14 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port)
static void cp210x_close(struct usb_serial_port *port) static void cp210x_close(struct usb_serial_port *port)
{ {
unsigned int purge_ctl;
usb_serial_generic_close(port); 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); cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_DISABLE);
} }
......
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