]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/tty/tty_io.c
tty: Document c_line == N_TTY initial condition
[karo-tx-linux.git] / drivers / tty / tty_io.c
index 741a0d7f51ce14e55630e8927281931aedaf9ff9..3c90ad44b585c7e1ba998c70bf504a99684dd59c 100644 (file)
@@ -123,7 +123,8 @@ struct ktermios tty_std_termios = { /* for the benefit of tty drivers  */
                   ECHOCTL | ECHOKE | IEXTEN,
        .c_cc = INIT_C_CC,
        .c_ispeed = 38400,
-       .c_ospeed = 38400
+       .c_ospeed = 38400,
+       /* .c_line = N_TTY, */
 };
 
 EXPORT_SYMBOL(tty_std_termios);
@@ -727,7 +728,7 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session)
        while (refs--)
                tty_kref_put(tty);
 
-       tty_ldisc_hangup(tty);
+       tty_ldisc_hangup(tty, cons_filp != NULL);
 
        spin_lock_irq(&tty->ctrl_lock);
        clear_bit(TTY_THROTTLED, &tty->flags);
@@ -752,10 +753,9 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session)
        } else if (tty->ops->hangup)
                tty->ops->hangup(tty);
        /*
-        * We don't want to have driver/ldisc interactions beyond
-        * the ones we did here. The driver layer expects no
-        * calls after ->hangup() from the ldisc side. However we
-        * can't yet guarantee all that.
+        * We don't want to have driver/ldisc interactions beyond the ones
+        * we did here. The driver layer expects no calls after ->hangup()
+        * from the ldisc side, which is now guaranteed.
         */
        set_bit(TTY_HUPPED, &tty->flags);
        tty_unlock(tty);
@@ -1068,6 +1068,8 @@ static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
        /* We want to wait for the line discipline to sort out in this
           situation */
        ld = tty_ldisc_ref_wait(tty);
+       if (!ld)
+               return hung_up_tty_read(file, buf, count, ppos);
        if (ld->ops->read)
                i = ld->ops->read(tty, file, buf, count);
        else
@@ -1242,6 +1244,8 @@ static ssize_t tty_write(struct file *file, const char __user *buf,
        if (tty->ops->write_room == NULL)
                tty_err(tty, "missing write_room method\n");
        ld = tty_ldisc_ref_wait(tty);
+       if (!ld)
+               return hung_up_tty_write(file, buf, count, ppos);
        if (!ld->ops->write)
                ret = -EIO;
        else
@@ -1387,9 +1391,10 @@ void tty_init_termios(struct tty_struct *tty)
        else {
                /* Check for lazy saved data */
                tp = tty->driver->termios[idx];
-               if (tp != NULL)
+               if (tp != NULL) {
                        tty->termios = *tp;
-               else
+                       tty->termios.c_line  = tty->driver->init_termios.c_line;
+               } else
                        tty->termios = tty->driver->init_termios;
        }
        /* Compatibility until drivers always set this */
@@ -1470,7 +1475,8 @@ static int tty_reopen(struct tty_struct *tty)
 
        tty->count++;
 
-       WARN_ON(!tty->ldisc);
+       if (!tty->ldisc)
+               return tty_ldisc_reinit(tty, tty->termios.c_line);
 
        return 0;
 }
@@ -1994,6 +2000,69 @@ static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp,
        return driver;
 }
 
+/**
+ *     tty_open_by_driver      -       open a tty device
+ *     @device: dev_t of device to open
+ *     @inode: inode of device file
+ *     @filp: file pointer to tty
+ *
+ *     Performs the driver lookup, checks for a reopen, or otherwise
+ *     performs the first-time tty initialization.
+ *
+ *     Returns the locked initialized or re-opened &tty_struct
+ *
+ *     Claims the global tty_mutex to serialize:
+ *       - concurrent first-time tty initialization
+ *       - concurrent tty driver removal w/ lookup
+ *       - concurrent tty removal from driver table
+ */
+static struct tty_struct *tty_open_by_driver(dev_t device, struct inode *inode,
+                                            struct file *filp)
+{
+       struct tty_struct *tty;
+       struct tty_driver *driver = NULL;
+       int index = -1;
+       int retval;
+
+       mutex_lock(&tty_mutex);
+       driver = tty_lookup_driver(device, filp, &index);
+       if (IS_ERR(driver)) {
+               mutex_unlock(&tty_mutex);
+               return ERR_CAST(driver);
+       }
+
+       /* check whether we're reopening an existing tty */
+       tty = tty_driver_lookup_tty(driver, inode, index);
+       if (IS_ERR(tty)) {
+               mutex_unlock(&tty_mutex);
+               goto out;
+       }
+
+       if (tty) {
+               mutex_unlock(&tty_mutex);
+               retval = tty_lock_interruptible(tty);
+               if (retval) {
+                       if (retval == -EINTR)
+                               retval = -ERESTARTSYS;
+                       tty = ERR_PTR(retval);
+                       goto out;
+               }
+               /* safe to drop the kref from tty_driver_lookup_tty() */
+               tty_kref_put(tty);
+               retval = tty_reopen(tty);
+               if (retval < 0) {
+                       tty_unlock(tty);
+                       tty = ERR_PTR(retval);
+               }
+       } else { /* Returns with the tty_lock held for now */
+               tty = tty_init_dev(driver, index);
+               mutex_unlock(&tty_mutex);
+       }
+out:
+       tty_driver_kref_put(driver);
+       return tty;
+}
+
 /**
  *     tty_open                -       open a tty device
  *     @inode: inode of device file
@@ -2022,8 +2091,6 @@ static int tty_open(struct inode *inode, struct file *filp)
 {
        struct tty_struct *tty;
        int noctty, retval;
-       struct tty_driver *driver = NULL;
-       int index;
        dev_t device = inode->i_rdev;
        unsigned saved_flags = filp->f_flags;
 
@@ -2034,53 +2101,15 @@ retry_open:
        if (retval)
                return -ENOMEM;
 
-       index  = -1;
-       retval = 0;
-
        tty = tty_open_current_tty(device, filp);
-       if (!tty) {
-               mutex_lock(&tty_mutex);
-               driver = tty_lookup_driver(device, filp, &index);
-               if (IS_ERR(driver)) {
-                       retval = PTR_ERR(driver);
-                       goto err_unlock;
-               }
-
-               /* check whether we're reopening an existing tty */
-               tty = tty_driver_lookup_tty(driver, inode, index);
-               if (IS_ERR(tty)) {
-                       retval = PTR_ERR(tty);
-                       goto err_unlock;
-               }
-
-               if (tty) {
-                       mutex_unlock(&tty_mutex);
-                       retval = tty_lock_interruptible(tty);
-                       if (retval) {
-                               if (retval == -EINTR)
-                                       retval = -ERESTARTSYS;
-                               goto err_unref;
-                       }
-                       /* safe to drop the kref from tty_driver_lookup_tty() */
-                       tty_kref_put(tty);
-                       retval = tty_reopen(tty);
-                       if (retval < 0) {
-                               tty_unlock(tty);
-                               tty = ERR_PTR(retval);
-                       }
-               } else { /* Returns with the tty_lock held for now */
-                       tty = tty_init_dev(driver, index);
-                       mutex_unlock(&tty_mutex);
-               }
-
-               tty_driver_kref_put(driver);
-       }
+       if (!tty)
+               tty = tty_open_by_driver(device, inode, filp);
 
        if (IS_ERR(tty)) {
+               tty_free_file(filp);
                retval = PTR_ERR(tty);
                if (retval != -EAGAIN || signal_pending(current))
-                       goto err_file;
-               tty_free_file(filp);
+                       return retval;
                schedule();
                goto retry_open;
        }
@@ -2151,15 +2180,6 @@ retry_open:
        read_unlock(&tasklist_lock);
        tty_unlock(tty);
        return 0;
-err_unlock:
-       mutex_unlock(&tty_mutex);
-err_unref:
-       /* after locks to avoid deadlock */
-       if (!IS_ERR_OR_NULL(driver))
-               tty_driver_kref_put(driver);
-err_file:
-       tty_free_file(filp);
-       return retval;
 }
 
 
@@ -2186,6 +2206,8 @@ static unsigned int tty_poll(struct file *filp, poll_table *wait)
                return 0;
 
        ld = tty_ldisc_ref_wait(tty);
+       if (!ld)
+               return hung_up_tty_poll(filp, wait);
        if (ld->ops->poll)
                ret = ld->ops->poll(tty, filp, wait);
        tty_ldisc_deref(ld);
@@ -2275,6 +2297,8 @@ static int tiocsti(struct tty_struct *tty, char __user *p)
                return -EFAULT;
        tty_audit_tiocsti(tty, ch);
        ld = tty_ldisc_ref_wait(tty);
+       if (!ld)
+               return -EIO;
        ld->ops->receive_buf(tty, &ch, &mbz, 1);
        tty_ldisc_deref(ld);
        return 0;
@@ -2639,13 +2663,13 @@ static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t _
 
 static int tiocsetd(struct tty_struct *tty, int __user *p)
 {
-       int ldisc;
+       int disc;
        int ret;
 
-       if (get_user(ldisc, p))
+       if (get_user(disc, p))
                return -EFAULT;
 
-       ret = tty_set_ldisc(tty, ldisc);
+       ret = tty_set_ldisc(tty, disc);
 
        return ret;
 }
@@ -2667,6 +2691,8 @@ static int tiocgetd(struct tty_struct *tty, int __user *p)
        int ret;
 
        ld = tty_ldisc_ref_wait(tty);
+       if (!ld)
+               return -EIO;
        ret = put_user(ld->ops->num, p);
        tty_ldisc_deref(ld);
        return ret;
@@ -2964,6 +2990,8 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                        return retval;
        }
        ld = tty_ldisc_ref_wait(tty);
+       if (!ld)
+               return hung_up_tty_ioctl(file, cmd, arg);
        retval = -EINVAL;
        if (ld->ops->ioctl) {
                retval = ld->ops->ioctl(tty, file, cmd, arg);
@@ -2992,6 +3020,8 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd,
        }
 
        ld = tty_ldisc_ref_wait(tty);
+       if (!ld)
+               return hung_up_tty_compat_ioctl(file, cmd, arg);
        if (ld->ops->compat_ioctl)
                retval = ld->ops->compat_ioctl(tty, file, cmd, arg);
        else