V4L/DVB (10978): Report tuning algorith correctly
[safe/jmp/linux-2.6] / drivers / char / pty.c
index c5a192d..31038a0 100644 (file)
@@ -5,13 +5,13 @@
  *
  *  Added support for a Unix98-style ptmx device.
  *    -- C. Scott Ananian <cananian@alumni.princeton.edu>, 14-Jan-1998
- *  Added TTY_DO_WRITE_WAKEUP to enable n_tty to send POLL_OUT to
- *      waiting writers -- Sapan Bhatia <sapan@corewars.org>
- *
  *
+ *  When reading this code see also fs/devpts. In particular note that the
+ *  driver_data field is used by the devpts side as a binding to the devpts
+ *  inode.
  */
 
-#include <linux/module.h>      /* For EXPORT_SYMBOL */
+#include <linux/module.h>
 
 #include <linux/errno.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/sysctl.h>
 #include <linux/device.h>
-
-#include <asm/uaccess.h>
-#include <asm/system.h>
+#include <linux/uaccess.h>
 #include <linux/bitops.h>
 #include <linux/devpts_fs.h>
 
+#include <asm/system.h>
+
 /* These are global because they are accessed in tty_io.c */
 #ifdef CONFIG_UNIX98_PTYS
-struct tty_driver *ptm_driver;
+static struct tty_driver *ptm_driver;
 static struct tty_driver *pts_driver;
 #endif
 
-static void pty_close(struct tty_struct * tty, struct file * filp)
+static void pty_close(struct tty_struct *tty, struct file *filp)
 {
-       if (!tty)
-               return;
-       if (tty->driver->subtype == PTY_TYPE_MASTER) {
-               if (tty->count > 1)
-                       printk("master pty_close: count = %d!!\n", tty->count);
-       } else {
+       BUG_ON(!tty);
+       if (tty->driver->subtype == PTY_TYPE_MASTER)
+               WARN_ON(tty->count > 1);
+       else {
                if (tty->count > 2)
                        return;
        }
@@ -60,7 +58,7 @@ static void pty_close(struct tty_struct * tty, struct file * filp)
                set_bit(TTY_OTHER_CLOSED, &tty->flags);
 #ifdef CONFIG_UNIX98_PTYS
                if (tty->driver == ptm_driver)
-                       devpts_pty_kill(tty->index);
+                       devpts_pty_kill(tty->link);
 #endif
                tty_vhangup(tty->link);
        }
@@ -70,13 +68,13 @@ static void pty_close(struct tty_struct * tty, struct file * filp)
  * The unthrottle routine is called by the line discipline to signal
  * that it can receive more characters.  For PTY's, the TTY_THROTTLED
  * flag is always set, to force the line discipline to always call the
- * unthrottle routine when there are fewer than TTY_THRESHOLD_UNTHROTTLE 
+ * unthrottle routine when there are fewer than TTY_THRESHOLD_UNTHROTTLE
  * characters in the queue.  This is necessary since each time this
  * happens, we need to wake up any sleeping processes that could be
  * (1) trying to send data to the pty, or (2) waiting in wait_until_sent()
  * for the pty buffer to be drained.
  */
-static void pty_unthrottle(struct tty_struct * tty)
+static void pty_unthrottle(struct tty_struct *tty)
 {
        struct tty_struct *o_tty = tty->link;
 
@@ -88,7 +86,7 @@ static void pty_unthrottle(struct tty_struct * tty)
 }
 
 /*
- * WSH 05/24/97: modified to 
+ * WSH 05/24/97: modified to
  *   (1) use space in tty->flip instead of a shared temp buffer
  *      The flip buffers aren't being used for a pty, so there's lots
  *      of space available.  The buffer is protected by a per-pty
@@ -101,7 +99,8 @@ static void pty_unthrottle(struct tty_struct * tty)
  * not our partners. We can't just take the other one blindly without
  * risking deadlocks.
  */
-static int pty_write(struct tty_struct * tty, const unsigned char *buf, int count)
+static int pty_write(struct tty_struct *tty, const unsigned char *buf,
+                                                               int count)
 {
        struct tty_struct *to = tty->link;
        int     c;
@@ -113,7 +112,7 @@ static int pty_write(struct tty_struct * tty, const unsigned char *buf, int coun
        if (c > count)
                c = count;
        to->ldisc.ops->receive_buf(to, buf, NULL, c);
-       
+
        return c;
 }
 
@@ -129,17 +128,17 @@ static int pty_write_room(struct tty_struct *tty)
 
 /*
  *     WSH 05/24/97:  Modified for asymmetric MASTER/SLAVE behavior
- *     The chars_in_buffer() value is used by the ldisc select() function 
+ *     The chars_in_buffer() value is used by the ldisc select() function
  *     to hold off writing when chars_in_buffer > WAKEUP_CHARS (== 256).
  *     The pty driver chars_in_buffer() Master/Slave must behave differently:
  *
  *      The Master side needs to allow typed-ahead commands to accumulate
  *      while being canonicalized, so we report "our buffer" as empty until
  *     some threshold is reached, and then report the count. (Any count >
- *     WAKEUP_CHARS is regarded by select() as "full".)  To avoid deadlock 
- *     the count returned must be 0 if no canonical data is available to be 
+ *     WAKEUP_CHARS is regarded by select() as "full".)  To avoid deadlock
+ *     the count returned must be 0 if no canonical data is available to be
  *     read. (The N_TTY ldisc.chars_in_buffer now knows this.)
- *  
+ *
  *     The Slave side passes all characters in raw mode to the Master side's
  *     buffer where they can be read immediately, so in this case we can
  *     return the true count in the buffer.
@@ -156,21 +155,22 @@ static int pty_chars_in_buffer(struct tty_struct *tty)
        /* The ldisc must report 0 if no characters available to be read */
        count = to->ldisc.ops->chars_in_buffer(to);
 
-       if (tty->driver->subtype == PTY_TYPE_SLAVE) return count;
+       if (tty->driver->subtype == PTY_TYPE_SLAVE)
+               return count;
 
-       /* Master side driver ... if the other side's read buffer is less than 
+       /* Master side driver ... if the other side's read buffer is less than
         * half full, return 0 to allow writers to proceed; otherwise return
-        * the count.  This leaves a comfortable margin to avoid overflow, 
+        * the count.  This leaves a comfortable margin to avoid overflow,
         * and still allows half a buffer's worth of typed-ahead commands.
         */
-       return ((count < N_TTY_BUF_SIZE/2) ? 0 : count);
+       return (count < N_TTY_BUF_SIZE/2) ? 0 : count;
 }
 
 /* Set the lock flag on a pty */
-static int pty_set_lock(struct tty_struct *tty, int __user * arg)
+static int pty_set_lock(struct tty_struct *tty, int __user *arg)
 {
        int val;
-       if (get_user(val,arg))
+       if (get_user(val, arg))
                return -EFAULT;
        if (val)
                set_bit(TTY_PTY_LOCK, &tty->flags);
@@ -183,13 +183,13 @@ static void pty_flush_buffer(struct tty_struct *tty)
 {
        struct tty_struct *to = tty->link;
        unsigned long flags;
-       
+
        if (!to)
                return;
-       
+
        if (to->ldisc.ops->flush_buffer)
                to->ldisc.ops->flush_buffer(to);
-       
+
        if (to->packet) {
                spin_lock_irqsave(&tty->ctrl_lock, flags);
                tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
@@ -198,7 +198,7 @@ static void pty_flush_buffer(struct tty_struct *tty)
        }
 }
 
-static int pty_open(struct tty_struct *tty, struct file * filp)
+static int pty_open(struct tty_struct *tty, struct file *filp)
 {
        int     retval = -ENODEV;
 
@@ -215,16 +215,63 @@ static int pty_open(struct tty_struct *tty, struct file * filp)
 
        clear_bit(TTY_OTHER_CLOSED, &tty->link->flags);
        set_bit(TTY_THROTTLED, &tty->flags);
-       set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
        retval = 0;
 out:
        return retval;
 }
 
-static void pty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
+static void pty_set_termios(struct tty_struct *tty,
+                                       struct ktermios *old_termios)
 {
-        tty->termios->c_cflag &= ~(CSIZE | PARENB);
-        tty->termios->c_cflag |= (CS8 | CREAD);
+       tty->termios->c_cflag &= ~(CSIZE | PARENB);
+       tty->termios->c_cflag |= (CS8 | CREAD);
+}
+
+/**
+ *     pty_do_resize           -       resize event
+ *     @tty: tty being resized
+ *     @ws: window size being set.
+ *
+ *     Update the termios variables and send the neccessary signals to
+ *     peform a terminal resize correctly
+ */
+
+int pty_resize(struct tty_struct *tty,  struct winsize *ws)
+{
+       struct pid *pgrp, *rpgrp;
+       unsigned long flags;
+       struct tty_struct *pty = tty->link;
+
+       /* For a PTY we need to lock the tty side */
+       mutex_lock(&tty->termios_mutex);
+       if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
+               goto done;
+
+       /* Get the PID values and reference them so we can
+          avoid holding the tty ctrl lock while sending signals.
+          We need to lock these individually however. */
+
+       spin_lock_irqsave(&tty->ctrl_lock, flags);
+       pgrp = get_pid(tty->pgrp);
+       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+
+       spin_lock_irqsave(&pty->ctrl_lock, flags);
+       rpgrp = get_pid(pty->pgrp);
+       spin_unlock_irqrestore(&pty->ctrl_lock, flags);
+
+       if (pgrp)
+               kill_pgrp(pgrp, SIGWINCH, 1);
+       if (rpgrp != pgrp && rpgrp)
+               kill_pgrp(rpgrp, SIGWINCH, 1);
+
+       put_pid(pgrp);
+       put_pid(rpgrp);
+
+       tty->winsize = *ws;
+       pty->winsize = *ws;     /* Never used so will go away soon */
+done:
+       mutex_unlock(&tty->termios_mutex);
+       return 0;
 }
 
 static int pty_install(struct tty_driver *driver, struct tty_struct *tty)
@@ -254,7 +301,7 @@ static int pty_install(struct tty_driver *driver, struct tty_struct *tty)
                tty_free_termios(tty);
                goto free_mem_out;
        }
-       
+
        /*
         * Everything allocated ... set up the o_tty structure.
         */
@@ -287,6 +334,7 @@ static const struct tty_operations pty_ops = {
        .chars_in_buffer = pty_chars_in_buffer,
        .unthrottle = pty_unthrottle,
        .set_termios = pty_set_termios,
+       .resize = pty_resize
 };
 
 /* Traditional BSD devices */
@@ -316,6 +364,7 @@ static const struct tty_operations pty_ops_bsd = {
        .unthrottle = pty_unthrottle,
        .set_termios = pty_set_termios,
        .ioctl = pty_bsd_ioctl,
+       .resize = pty_resize
 };
 
 static void __init legacy_pty_init(void)
@@ -381,9 +430,9 @@ static inline void legacy_pty_init(void) { }
  * Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly.
  */
 int pty_limit = NR_UNIX98_PTY_DEFAULT;
-static int pty_limit_min = 0;
+static int pty_limit_min;
 static int pty_limit_max = NR_UNIX98_PTY_MAX;
-static int pty_count = 0;
+static int pty_count;
 
 static struct cdev ptmx_cdev;
 
@@ -453,9 +502,10 @@ static int pty_unix98_ioctl(struct tty_struct *tty, struct file *file,
  *     This provides our locking.
  */
 
-static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver, int idx)
+static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver,
+               struct inode *ptm_inode, int idx)
 {
-       struct tty_struct *tty = devpts_get_tty(idx);
+       struct tty_struct *tty = devpts_get_tty(ptm_inode, idx);
        if (tty)
                tty = tty->link;
        return tty;
@@ -470,9 +520,10 @@ static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver, int idx)
  *     This provides our locking.
  */
 
-static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver, int idx)
+static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver,
+               struct inode *pts_inode, int idx)
 {
-       struct tty_struct *tty = devpts_get_tty(idx);
+       struct tty_struct *tty = devpts_get_tty(pts_inode, idx);
        /* Master must be open before slave */
        if (!tty)
                return ERR_PTR(-EIO);
@@ -483,7 +534,6 @@ static void pty_unix98_shutdown(struct tty_struct *tty)
 {
        /* We have our own method as we don't use the tty index */
        kfree(tty->termios);
-       kfree(tty->termios_locked);
 }
 
 /* We have no need to install and remove our tty objects as devpts does all
@@ -504,20 +554,17 @@ static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty)
        }
        initialize_tty_struct(o_tty, driver->other, idx);
 
-       tty->termios = kmalloc(sizeof(struct ktermios), GFP_KERNEL);
+       tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
        if (tty->termios == NULL)
                goto free_mem_out;
        *tty->termios = driver->init_termios;
-       tty->termios_locked = kzalloc(sizeof(struct ktermios), GFP_KERNEL);
-       if (tty->termios_locked == NULL)
-               goto free_mem_out;
-       o_tty->termios = kmalloc(sizeof(struct ktermios), GFP_KERNEL);
+       tty->termios_locked = tty->termios + 1;
+
+       o_tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
        if (o_tty->termios == NULL)
                goto free_mem_out;
        *o_tty->termios = driver->other->init_termios;
-       o_tty->termios_locked = kzalloc(sizeof(struct ktermios), GFP_KERNEL);
-       if (o_tty->termios_locked == NULL)
-               goto free_mem_out;
+       o_tty->termios_locked = o_tty->termios + 1;
 
        tty_driver_kref_get(driver->other);
        if (driver->subtype == PTY_TYPE_MASTER)
@@ -538,10 +585,7 @@ free_mem_out:
        kfree(o_tty->termios);
        module_put(o_tty->driver->owner);
        free_tty_struct(o_tty);
-       kfree(tty->termios_locked);
        kfree(tty->termios);
-       free_tty_struct(tty);
-       module_put(driver->owner);
        return -ENOMEM;
 }
 
@@ -563,7 +607,8 @@ static const struct tty_operations ptm_unix98_ops = {
        .unthrottle = pty_unthrottle,
        .set_termios = pty_set_termios,
        .ioctl = pty_unix98_ioctl,
-       .shutdown = pty_unix98_shutdown
+       .shutdown = pty_unix98_shutdown,
+       .resize = pty_resize
 };
 
 static const struct tty_operations pty_unix98_ops = {
@@ -602,7 +647,7 @@ static int __ptmx_open(struct inode *inode, struct file *filp)
        nonseekable_open(inode, filp);
 
        /* find a device that is not in use. */
-       index = devpts_new_index();
+       index = devpts_new_index(inode);
        if (index < 0)
                return index;
 
@@ -619,7 +664,7 @@ static int __ptmx_open(struct inode *inode, struct file *filp)
        filp->private_data = tty;
        file_move(filp, &tty->tty_files);
 
-       retval = devpts_pty_new(tty->link);
+       retval = devpts_pty_new(inode, tty->link);
        if (retval)
                goto out1;
 
@@ -630,7 +675,7 @@ out1:
        tty_release_dev(filp);
        return retval;
 out:
-       devpts_kill_index(index);
+       devpts_kill_index(inode, index);
        return retval;
 }
 
@@ -689,13 +734,13 @@ static void __init unix98_pty_init(void)
                TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
        pts_driver->other = ptm_driver;
        tty_set_operations(pts_driver, &pty_unix98_ops);
-       
+
        if (tty_register_driver(ptm_driver))
                panic("Couldn't register Unix98 ptm driver");
        if (tty_register_driver(pts_driver))
                panic("Couldn't register Unix98 pts driver");
 
-       register_sysctl_table(pty_root_table);  
+       register_sysctl_table(pty_root_table);
 
        /* Now create the /dev/ptmx special device */
        tty_default_fops(&ptmx_fops);