]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/tty/tty_io.c
Merge tag 'v2.6.37' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[mv-sheeva.git] / drivers / tty / tty_io.c
similarity index 97%
rename from drivers/char/tty_io.c
rename to drivers/tty/tty_io.c
index 613c852ee0feced279c50f6850e9e30c7c870111..35480dd57a307e72b2893d484a86783659c6a45d 100644 (file)
@@ -96,6 +96,7 @@
 #include <linux/bitops.h>
 #include <linux/delay.h>
 #include <linux/seq_file.h>
+#include <linux/serial.h>
 
 #include <linux/uaccess.h>
 #include <asm/system.h>
@@ -183,6 +184,8 @@ struct tty_struct *alloc_tty_struct(void)
 
 void free_tty_struct(struct tty_struct *tty)
 {
+       if (tty->dev)
+               put_device(tty->dev);
        kfree(tty->write_buf);
        tty_buffer_free_all(tty);
        kfree(tty);
@@ -194,12 +197,13 @@ static inline struct tty_struct *file_tty(struct file *file)
 }
 
 /* Associate a new file with the tty structure */
-void tty_add_file(struct tty_struct *tty, struct file *file)
+int tty_add_file(struct tty_struct *tty, struct file *file)
 {
        struct tty_file_private *priv;
 
-       /* XXX: must implement proper error handling in callers */
-       priv = kmalloc(sizeof(*priv), GFP_KERNEL|__GFP_NOFAIL);
+       priv = kmalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
 
        priv->tty = tty;
        priv->file = file;
@@ -208,6 +212,8 @@ void tty_add_file(struct tty_struct *tty, struct file *file)
        spin_lock(&tty_files_lock);
        list_add(&priv->list, &tty->tty_files);
        spin_unlock(&tty_files_lock);
+
+       return 0;
 }
 
 /* Delete file from its tty */
@@ -553,6 +559,9 @@ void __tty_hangup(struct tty_struct *tty)
 
        tty_lock();
 
+       /* some functions below drop BTM, so we need this bit */
+       set_bit(TTY_HUPPING, &tty->flags);
+
        /* inuse_filps is protected by the single tty lock,
           this really needs to change if we want to flush the
           workqueue with the lock held */
@@ -572,6 +581,10 @@ void __tty_hangup(struct tty_struct *tty)
        }
        spin_unlock(&tty_files_lock);
 
+       /*
+        * it drops BTM and thus races with reopen
+        * we protect the race by TTY_HUPPING
+        */
        tty_ldisc_hangup(tty);
 
        read_lock(&tasklist_lock);
@@ -609,7 +622,6 @@ void __tty_hangup(struct tty_struct *tty)
        tty->session = NULL;
        tty->pgrp = NULL;
        tty->ctrl_status = 0;
-       set_bit(TTY_HUPPED, &tty->flags);
        spin_unlock_irqrestore(&tty->ctrl_lock, flags);
 
        /* Account for the p->signal references we killed */
@@ -635,6 +647,7 @@ void __tty_hangup(struct tty_struct *tty)
         * can't yet guarantee all that.
         */
        set_bit(TTY_HUPPED, &tty->flags);
+       clear_bit(TTY_HUPPING, &tty->flags);
        tty_ldisc_enable(tty);
 
        tty_unlock();
@@ -1304,7 +1317,9 @@ static int tty_reopen(struct tty_struct *tty)
 {
        struct tty_driver *driver = tty->driver;
 
-       if (test_bit(TTY_CLOSING, &tty->flags))
+       if (test_bit(TTY_CLOSING, &tty->flags) ||
+                       test_bit(TTY_HUPPING, &tty->flags) ||
+                       test_bit(TTY_LDISC_CHANGING, &tty->flags))
                return -EIO;
 
        if (driver->type == TTY_DRIVER_TYPE_PTY &&
@@ -1875,7 +1890,11 @@ got_driver:
                return PTR_ERR(tty);
        }
 
-       tty_add_file(tty, filp);
+       retval = tty_add_file(tty, filp);
+       if (retval) {
+               tty_unlock();
+               return retval;
+       }
 
        check_tty_count(tty, "tty_open");
        if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
@@ -2502,6 +2521,20 @@ static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int
        return tty->ops->tiocmset(tty, file, set, clear);
 }
 
+static int tty_tiocgicount(struct tty_struct *tty, void __user *arg)
+{
+       int retval = -EINVAL;
+       struct serial_icounter_struct icount;
+       memset(&icount, 0, sizeof(icount));
+       if (tty->ops->get_icount)
+               retval = tty->ops->get_icount(tty, &icount);
+       if (retval != 0)
+               return retval;
+       if (copy_to_user(arg, &icount, sizeof(icount)))
+               return -EFAULT;
+       return 0;
+}
+
 struct tty_struct *tty_pair_get_tty(struct tty_struct *tty)
 {
        if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
@@ -2622,6 +2655,12 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        case TIOCMBIC:
        case TIOCMBIS:
                return tty_tiocmset(tty, file, cmd, p);
+       case TIOCGICOUNT:
+               retval = tty_tiocgicount(tty, p);
+               /* For the moment allow fall through to the old method */
+               if (retval != -EINVAL)
+                       return retval;
+               break;
        case TCFLSH:
                switch (arg) {
                case TCIFLUSH:
@@ -2783,6 +2822,20 @@ void do_SAK(struct tty_struct *tty)
 
 EXPORT_SYMBOL(do_SAK);
 
+static int dev_match_devt(struct device *dev, void *data)
+{
+       dev_t *devt = data;
+       return dev->devt == *devt;
+}
+
+/* Must put_device() after it's unused! */
+static struct device *tty_get_device(struct tty_struct *tty)
+{
+       dev_t devt = tty_devnum(tty);
+       return class_find_device(tty_class, NULL, &devt, dev_match_devt);
+}
+
+
 /**
  *     initialize_tty_struct
  *     @tty: tty to initialize
@@ -2823,6 +2876,7 @@ void initialize_tty_struct(struct tty_struct *tty,
        tty->ops = driver->ops;
        tty->index = idx;
        tty_line_name(driver, idx, tty->name);
+       tty->dev = tty_get_device(tty);
 }
 
 /**
@@ -2980,6 +3034,7 @@ int tty_register_driver(struct tty_driver *driver)
        int i;
        dev_t dev;
        void **p = NULL;
+       struct device *d;
 
        if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) {
                p = kzalloc(driver->num * 2 * sizeof(void *), GFP_KERNEL);
@@ -3027,12 +3082,31 @@ int tty_register_driver(struct tty_driver *driver)
        mutex_unlock(&tty_mutex);
 
        if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) {
-               for (i = 0; i < driver->num; i++)
-                   tty_register_device(driver, i, NULL);
+               for (i = 0; i < driver->num; i++) {
+                       d = tty_register_device(driver, i, NULL);
+                       if (IS_ERR(d)) {
+                               error = PTR_ERR(d);
+                               goto err;
+                       }
+               }
        }
        proc_tty_register_driver(driver);
        driver->flags |= TTY_DRIVER_INSTALLED;
        return 0;
+
+err:
+       for (i--; i >= 0; i--)
+               tty_unregister_device(driver, i);
+
+       mutex_lock(&tty_mutex);
+       list_del(&driver->tty_drivers);
+       mutex_unlock(&tty_mutex);
+
+       unregister_chrdev_region(dev, driver->num);
+       driver->ttys = NULL;
+       driver->termios = NULL;
+       kfree(p);
+       return error;
 }
 
 EXPORT_SYMBOL(tty_register_driver);