USB: serial: ch341: fix modem-control and B0 handling
authorJohan Hovold <johan@kernel.org>
Fri, 6 Jan 2017 18:15:12 +0000 (19:15 +0100)
committerBen Hutchings <ben@decadent.org.uk>
Thu, 16 Mar 2017 02:18:41 +0000 (02:18 +0000)
commit 030ee7ae52a46a2be52ccc8242c4a330aba8d38e upstream.

The modem-control signals are managed by the tty-layer during open and
should not be asserted prematurely when set_termios is called from
driver open.

Also make sure that the signals are asserted only when changing speed
from B0.

Fixes: 664d5df92e88 ("USB: usb-serial ch341: support for DTR/RTS/CTS")
Signed-off-by: Johan Hovold <johan@kernel.org>
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
drivers/usb/serial/ch341.c

index db5b7bb..e138f3c 100644 (file)
@@ -369,10 +369,6 @@ static void ch341_set_termios(struct tty_struct *tty,
        ctrl = CH341_LCR_ENABLE_RX | CH341_LCR_ENABLE_TX | CH341_LCR_CS8;
 
        if (baud_rate) {
-               spin_lock_irqsave(&priv->lock, flags);
-               priv->line_control |= (CH341_BIT_DTR | CH341_BIT_RTS);
-               spin_unlock_irqrestore(&priv->lock, flags);
-
                priv->baud_rate = baud_rate;
 
                r = ch341_init_set_baudrate(port->serial->dev, priv, ctrl);
@@ -380,13 +376,14 @@ static void ch341_set_termios(struct tty_struct *tty,
                        priv->baud_rate = tty_termios_baud_rate(old_termios);
                        tty_termios_copy_hw(tty->termios, old_termios);
                }
-       } else {
-               spin_lock_irqsave(&priv->lock, flags);
-               priv->line_control &= ~(CH341_BIT_DTR | CH341_BIT_RTS);
-               spin_unlock_irqrestore(&priv->lock, flags);
        }
 
-       ch341_set_handshake(port->serial->dev, priv->line_control);
+       spin_lock_irqsave(&priv->lock, flags);
+       if (C_BAUD(tty) == B0)
+               priv->line_control &= ~(CH341_BIT_DTR | CH341_BIT_RTS);
+       else if (old_termios && (old_termios->c_cflag & CBAUD) == B0)
+               priv->line_control |= (CH341_BIT_DTR | CH341_BIT_RTS);
+       spin_unlock_irqrestore(&priv->lock, flags);
 
        /* Unimplemented:
         * (cflag & CSIZE) : data bits [5, 8]