Merge branch 'drm-sti-next-add-dvo' of git://git.linaro.org/people/benjamin.gaignard...
[firefly-linux-kernel-4.4.55.git] / drivers / tty / tty_ldisc.c
index 5bdc241628ac5970c44291f068de70c678137275..3737f55272d2c1184463edc3714f89fb2724730e 100644 (file)
@@ -325,6 +325,24 @@ static inline void __tty_ldisc_unlock(struct tty_struct *tty)
        return ldsem_up_write(&tty->ldisc_sem);
 }
 
+static int __lockfunc
+tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout)
+{
+       int ret;
+
+       ret = __tty_ldisc_lock(tty, timeout);
+       if (!ret)
+               return -EBUSY;
+       set_bit(TTY_LDISC_HALTED, &tty->flags);
+       return 0;
+}
+
+static void tty_ldisc_unlock(struct tty_struct *tty)
+{
+       clear_bit(TTY_LDISC_HALTED, &tty->flags);
+       __tty_ldisc_unlock(tty);
+}
+
 static int __lockfunc
 tty_ldisc_lock_pair_timeout(struct tty_struct *tty, struct tty_struct *tty2,
                            unsigned long timeout)
@@ -375,33 +393,21 @@ static void __lockfunc tty_ldisc_unlock_pair(struct tty_struct *tty,
                __tty_ldisc_unlock(tty2);
 }
 
-static void __lockfunc tty_ldisc_enable_pair(struct tty_struct *tty,
-                                            struct tty_struct *tty2)
-{
-       clear_bit(TTY_LDISC_HALTED, &tty->flags);
-       if (tty2)
-               clear_bit(TTY_LDISC_HALTED, &tty2->flags);
-
-       tty_ldisc_unlock_pair(tty, tty2);
-}
-
 /**
  *     tty_ldisc_flush -       flush line discipline queue
  *     @tty: tty
  *
- *     Flush the line discipline queue (if any) for this tty. If there
- *     is no line discipline active this is a no-op.
+ *     Flush the line discipline queue (if any) and the tty flip buffers
+ *     for this tty.
  */
 
 void tty_ldisc_flush(struct tty_struct *tty)
 {
        struct tty_ldisc *ld = tty_ldisc_ref(tty);
-       if (ld) {
-               if (ld->ops->flush_buffer)
-                       ld->ops->flush_buffer(tty);
+
+       tty_buffer_flush(tty, ld);
+       if (ld)
                tty_ldisc_deref(ld);
-       }
-       tty_buffer_flush(tty);
 }
 EXPORT_SYMBOL_GPL(tty_ldisc_flush);
 
@@ -517,14 +523,13 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
 {
        int retval;
        struct tty_ldisc *old_ldisc, *new_ldisc;
-       struct tty_struct *o_tty = tty->link;
 
        new_ldisc = tty_ldisc_get(tty, ldisc);
        if (IS_ERR(new_ldisc))
                return PTR_ERR(new_ldisc);
 
        tty_lock(tty);
-       retval = tty_ldisc_lock_pair_timeout(tty, o_tty, 5 * HZ);
+       retval = tty_ldisc_lock(tty, 5 * HZ);
        if (retval) {
                tty_ldisc_put(new_ldisc);
                tty_unlock(tty);
@@ -536,7 +541,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
         */
 
        if (tty->ldisc->ops->num == ldisc) {
-               tty_ldisc_enable_pair(tty, o_tty);
+               tty_ldisc_unlock(tty);
                tty_ldisc_put(new_ldisc);
                tty_unlock(tty);
                return 0;
@@ -547,7 +552,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
        if (test_bit(TTY_HUPPED, &tty->flags)) {
                /* We were raced by the hangup method. It will have stomped
                   the ldisc data and closed the ldisc down */
-               tty_ldisc_enable_pair(tty, o_tty);
+               tty_ldisc_unlock(tty);
                tty_ldisc_put(new_ldisc);
                tty_unlock(tty);
                return -EIO;
@@ -567,8 +572,11 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
                tty_ldisc_restore(tty, old_ldisc);
        }
 
-       if (tty->ldisc->ops->num != old_ldisc->ops->num && tty->ops->set_ldisc)
+       if (tty->ldisc->ops->num != old_ldisc->ops->num && tty->ops->set_ldisc) {
+               down_read(&tty->termios_rwsem);
                tty->ops->set_ldisc(tty);
+               up_read(&tty->termios_rwsem);
+       }
 
        /* At this point we hold a reference to the new ldisc and a
           reference to the old ldisc, or we hold two references to
@@ -581,13 +589,11 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
        /*
         *      Allow ldisc referencing to occur again
         */
-       tty_ldisc_enable_pair(tty, o_tty);
+       tty_ldisc_unlock(tty);
 
        /* Restart the work queue in case no characters kick it off. Safe if
           already running */
        schedule_work(&tty->port->buf.work);
-       if (o_tty)
-               schedule_work(&o_tty->port->buf.work);
 
        tty_unlock(tty);
        return retval;
@@ -682,7 +688,7 @@ void tty_ldisc_hangup(struct tty_struct *tty)
         *
         * Avoid racing set_ldisc or tty_ldisc_release
         */
-       tty_ldisc_lock_pair(tty, tty->link);
+       tty_ldisc_lock(tty, MAX_SCHEDULE_TIMEOUT);
 
        if (tty->ldisc) {
 
@@ -704,7 +710,7 @@ void tty_ldisc_hangup(struct tty_struct *tty)
                        WARN_ON(tty_ldisc_open(tty, tty->ldisc));
                }
        }
-       tty_ldisc_enable_pair(tty, tty->link);
+       tty_ldisc_unlock(tty);
        if (reset)
                tty_reset_termios(tty);