On USB to serial devices, if I set cooked mode, hardware flow control (either XON/XOFF or RTS/CTS), even if the device sends an XOFF char, the USB to serial converter will still continue sending characters. I have traced the problem: If you look at n_tty.c: (https://github.com/torvalds/linux/blob/master/drivers/tty/n_tty.c) , take a look at n_tty_receive_char_special() . There you will see "... if (c == STOP_CHAR(tty)) { stop_tty(tty);"... This should stop the tty sending bytes when an XOFF char is sent. stop_tty(tty) is defined in tty_io.c: (https://github.com/torvalds/linux/blob/master/drivers/tty/tty_io.c) , and that calls : if (tty->ops->stop) tty->ops->stop(tty); ops is a pointer to the tty operations. In the case of USB to serial adapters, that structure is defined on (usb-serial.c): https://github.com/torvalds/linux/blob/master/drivers/usb/serial/usb-serial.c Take a look at the definition of tty_operations (line 1180). There is no definition for either start() or stop() methods, so essentially, the USB to serial driver will never stop sending characters. If there is something waiting to be sent, it will be sent. (original analysis was done by TG9541 (https://github.com/neundorf/CuteCom/issues/22, last comment), and I verified that it still applies to the latest kernel version
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); } ```