USB: cp210x: add support for Corsair usb dongle
[pandora-kernel.git] / drivers / tty / tty_io.c
index 4f1fc81..446df6b 100644 (file)
@@ -194,8 +194,7 @@ static inline struct tty_struct *file_tty(struct file *file)
        return ((struct tty_file_private *)file->private_data)->tty;
 }
 
-/* Associate a new file with the tty structure */
-int tty_add_file(struct tty_struct *tty, struct file *file)
+int tty_alloc_file(struct file *file)
 {
        struct tty_file_private *priv;
 
@@ -203,15 +202,36 @@ int tty_add_file(struct tty_struct *tty, struct file *file)
        if (!priv)
                return -ENOMEM;
 
+       file->private_data = priv;
+
+       return 0;
+}
+
+/* Associate a new file with the tty structure */
+void tty_add_file(struct tty_struct *tty, struct file *file)
+{
+       struct tty_file_private *priv = file->private_data;
+
        priv->tty = tty;
        priv->file = file;
-       file->private_data = priv;
 
        spin_lock(&tty_files_lock);
        list_add(&priv->list, &tty->tty_files);
        spin_unlock(&tty_files_lock);
+}
 
-       return 0;
+/**
+ * tty_free_file - free file->private_data
+ *
+ * This shall be used only for fail path handling when tty_add_file was not
+ * called yet.
+ */
+void tty_free_file(struct file *file)
+{
+       struct tty_file_private *priv = file->private_data;
+
+       file->private_data = NULL;
+       kfree(priv);
 }
 
 /* Delete file from its tty */
@@ -222,8 +242,7 @@ void tty_del_file(struct file *file)
        spin_lock(&tty_files_lock);
        list_del(&priv->list);
        spin_unlock(&tty_files_lock);
-       file->private_data = NULL;
-       kfree(priv);
+       tty_free_file(file);
 }
 
 
@@ -921,6 +940,14 @@ void start_tty(struct tty_struct *tty)
 
 EXPORT_SYMBOL(start_tty);
 
+/* We limit tty time update visibility to every 8 seconds or so. */
+static void tty_update_time(struct timespec *time)
+{
+       unsigned long sec = get_seconds() & ~7;
+       if ((long)(sec - time->tv_sec) > 0)
+               time->tv_sec = sec;
+}
+
 /**
  *     tty_read        -       read method for tty device files
  *     @file: pointer to tty file
@@ -957,8 +984,10 @@ static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
        else
                i = -EIO;
        tty_ldisc_deref(ld);
+
        if (i > 0)
-               inode->i_atime = current_fs_time(inode->i_sb);
+               tty_update_time(&inode->i_atime);
+
        return i;
 }
 
@@ -1060,8 +1089,8 @@ static inline ssize_t do_tty_write(
                cond_resched();
        }
        if (written) {
-               struct inode *inode = file->f_path.dentry->d_inode;
-               inode->i_mtime = current_fs_time(inode->i_sb);
+               struct inode *inode = file->f_path.dentry->d_inode;
+               tty_update_time(&inode->i_mtime);
                ret = written;
        }
 out:
@@ -1193,9 +1222,9 @@ static void pty_line_name(struct tty_driver *driver, int index, char *p)
  *
  *     Locking: None
  */
-static void tty_line_name(struct tty_driver *driver, int index, char *p)
+static ssize_t tty_line_name(struct tty_driver *driver, int index, char *p)
 {
-       sprintf(p, "%s%d", driver->name, index + driver->name_base);
+       return sprintf(p, "%s%d", driver->name, index + driver->name_base);
 }
 
 /**
@@ -1811,6 +1840,10 @@ static int tty_open(struct inode *inode, struct file *filp)
        nonseekable_open(inode, filp);
 
 retry_open:
+       retval = tty_alloc_file(filp);
+       if (retval)
+               return -ENOMEM;
+
        noctty = filp->f_flags & O_NOCTTY;
        index  = -1;
        retval = 0;
@@ -1823,6 +1856,7 @@ retry_open:
                if (!tty) {
                        tty_unlock();
                        mutex_unlock(&tty_mutex);
+                       tty_free_file(filp);
                        return -ENXIO;
                }
                driver = tty_driver_kref_get(tty->driver);
@@ -1855,6 +1889,7 @@ retry_open:
                }
                tty_unlock();
                mutex_unlock(&tty_mutex);
+               tty_free_file(filp);
                return -ENODEV;
        }
 
@@ -1862,6 +1897,7 @@ retry_open:
        if (!driver) {
                tty_unlock();
                mutex_unlock(&tty_mutex);
+               tty_free_file(filp);
                return -ENODEV;
        }
 got_driver:
@@ -1872,6 +1908,8 @@ got_driver:
                if (IS_ERR(tty)) {
                        tty_unlock();
                        mutex_unlock(&tty_mutex);
+                       tty_driver_kref_put(driver);
+                       tty_free_file(filp);
                        return PTR_ERR(tty);
                }
        }
@@ -1887,15 +1925,11 @@ got_driver:
        tty_driver_kref_put(driver);
        if (IS_ERR(tty)) {
                tty_unlock();
+               tty_free_file(filp);
                return PTR_ERR(tty);
        }
 
-       retval = tty_add_file(tty, filp);
-       if (retval) {
-               tty_unlock();
-               tty_release(inode, filp);
-               return retval;
-       }
+       tty_add_file(tty, filp);
 
        check_tty_count(tty, "tty_open");
        if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
@@ -2716,6 +2750,8 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd,
        ld = tty_ldisc_ref_wait(tty);
        if (ld->ops->compat_ioctl)
                retval = ld->ops->compat_ioctl(tty, file, cmd, arg);
+       else
+               retval = n_tty_compat_ioctl_helper(tty, file, cmd, arg);
        tty_ldisc_deref(ld);
 
        return retval;
@@ -3285,9 +3321,19 @@ static ssize_t show_cons_active(struct device *dev,
                if (i >= ARRAY_SIZE(cs))
                        break;
        }
-       while (i--)
-               count += sprintf(buf + count, "%s%d%c",
-                                cs[i]->name, cs[i]->index, i ? ' ':'\n');
+       while (i--) {
+               int index = cs[i]->index;
+               struct tty_driver *drv = cs[i]->device(cs[i], &index);
+
+               /* don't resolve tty0 as some programs depend on it */
+               if (drv && (cs[i]->index > 0 || drv->major != TTY_MAJOR))
+                       count += tty_line_name(drv, index, buf + count);
+               else
+                       count += sprintf(buf + count, "%s%d",
+                                        cs[i]->name, cs[i]->index);
+
+               count += sprintf(buf + count, "%c", i ? ' ':'\n');
+       }
        console_unlock();
 
        return count;