TTY: fix DTR not being dropped on hang up
[firefly-linux-kernel-4.4.55.git] / drivers / tty / tty_port.c
index 7e3eaf4eb9fea923972e94f26493a60cbb8e3a12..0af8d9aa5b0231e179bdb448f02c296a03b6af55 100644 (file)
@@ -196,13 +196,20 @@ void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
 }
 EXPORT_SYMBOL(tty_port_tty_set);
 
-static void tty_port_shutdown(struct tty_port *port)
+static void tty_port_shutdown(struct tty_port *port, struct tty_struct *tty)
 {
        mutex_lock(&port->mutex);
        if (port->console)
                goto out;
 
        if (test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags)) {
+               /*
+                * Drop DTR/RTS if HUPCL is set. This causes any attached
+                * modem to hang up the line.
+                */
+               if (tty && C_HUPCL(tty))
+                       tty_port_lower_dtr_rts(port);
+
                if (port->ops->shutdown)
                        port->ops->shutdown(port);
        }
@@ -220,18 +227,19 @@ out:
 
 void tty_port_hangup(struct tty_port *port)
 {
+       struct tty_struct *tty;
        unsigned long flags;
 
        spin_lock_irqsave(&port->lock, flags);
        port->count = 0;
        port->flags &= ~ASYNC_NORMAL_ACTIVE;
-       if (port->tty) {
-               set_bit(TTY_IO_ERROR, &port->tty->flags);
-               tty_kref_put(port->tty);
-       }
+       tty = port->tty;
+       if (tty)
+               set_bit(TTY_IO_ERROR, &tty->flags);
        port->tty = NULL;
        spin_unlock_irqrestore(&port->lock, flags);
-       tty_port_shutdown(port);
+       tty_port_shutdown(port, tty);
+       tty_kref_put(tty);
        wake_up_interruptible(&port->open_wait);
        wake_up_interruptible(&port->delta_msr_wait);
 }
@@ -485,11 +493,6 @@ int tty_port_close_start(struct tty_port *port,
        /* Flush the ldisc buffering */
        tty_ldisc_flush(tty);
 
-       /* Drop DTR/RTS if HUPCL is set. This causes any attached modem to
-          hang up the line */
-       if (tty->termios.c_cflag & HUPCL)
-               tty_port_lower_dtr_rts(port);
-
        /* Don't call port->drop for the last reference. Callers will want
           to drop the last active reference in ->shutdown() or the tty
           shutdown path */
@@ -524,7 +527,7 @@ void tty_port_close(struct tty_port *port, struct tty_struct *tty,
 {
        if (tty_port_close_start(port, tty, filp) == 0)
                return;
-       tty_port_shutdown(port);
+       tty_port_shutdown(port, tty);
        set_bit(TTY_IO_ERROR, &tty->flags);
        tty_port_close_end(port, tty);
        tty_port_tty_set(port, NULL);