Bug 197109
Summary: | Hardware flow control (both CTS/RTS and XON/XOFF) not respected | ||
---|---|---|---|
Product: | Drivers | Reporter: | ejtagle |
Component: | Serial | Assignee: | Russell King (rmk) |
Status: | NEW --- | ||
Severity: | high | CC: | kernel, m.cavallini, o-schindler, olof.tangrot, sven.koehler |
Priority: | P1 | ||
Hardware: | All | ||
OS: | Linux | ||
Kernel Version: | latest | Subsystem: | |
Regression: | No | Bisected commit-id: |
Description
ejtagle
2017-10-02 18:15:56 UTC
I can confirm this problem using the ch341 driver. However using FTDI-driver detecting a FTDI232RL chip flow control with XON/XOFF works (verifed using gtkterm and an own POSIX compliant program). Both drivers provides a /dev/ttyUSBx device so I can't confirm that the problem affects all USB-2-serial drivers and for the FTDI driver the kernel seems to provide working XON/XOFF flow control. To enable RTS/CTS hardware flow control, the following code needs to be added to ch341_set_termios: if (C_CRTSCTS(tty)) { ch341_control_out(port->serial->dev, CH341_REQ_WRITE_REG, 0x2727, 0x0101); } else { ch341_control_out(port->serial->dev, CH341_REQ_WRITE_REG, 0x2727, 0x0000); } Not sure if I got this right. I have an CH340G adapter from ebay with RTS/CTS pins. I will test RTS/CTS flow control with Windows and a patched Linux soon. I can confirm this issue. Using a kernel 4.9 Xon/Xoff flow control is ignored where using 3.10.17 it works. Bug (or missing feature ) is still there on 4.15.17 ( Ubuntu 18.04 latest ) and on latest kernel master. There is already a patchset available, which fixes even some more things : https://www.spinics.net/lists/linux-serial/msg21947.html but this has to be reworked. Picking and adapting patch 8/10 , solved the issue : ``` --- a/drivers/usb/serial/ch341.c +++ b/drivers/usb/serial/ch341.c @@ -66,6 +66,7 @@ #define CH341_REG_BREAK 0x05 #define CH341_REG_LCR 0x18 +#define CH341_REG_RTSCTS 0x27 #define CH341_NBREAK_BITS 0x01 #define CH341_LCR_ENABLE_RX 0x80 @@ -467,6 +468,7 @@ static int ch341_tiocmset(struct tty_struct *tty, struct ch341_private *priv = usb_get_serial_port_data(port); unsigned long flags; u8 control; + int r; spin_lock_irqsave(&priv->lock, flags); if (set & TIOCM_RTS) @@ -480,6 +482,18 @@ static int ch341_tiocmset(struct tty_struct *tty, control = priv->mcr; spin_unlock_irqrestore(&priv->lock, flags); + if (tty->termios.c_cflag & CRTSCTS) { + r = ch341_control_out(port->serial->dev, CH341_REQ_WRITE_REG, + CH341_REG_RTSCTS | ((uint16_t)CH341_REG_RTSCTS << 8), + 0x0101); + if (r < 0) { + dev_err(&port->dev, "%s - USB control write error (%d)\n", + __func__, r); + tty->termios.c_cflag &= ~CRTSCTS; + } + } + + return ch341_set_handshake(port->serial->dev, control); } ``` |