linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / drivers / char / tty_io.c
index d70a259..6ba0b9a 100644 (file)
@@ -65,6 +65,7 @@
  * alloc_tty_struct() always uses kmalloc() -- Andrew Morton <andrewm@uow.edu.eu> 17Mar01
  */
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/major.h>
 #include <linux/errno.h>
 #include <linux/kbd_kern.h>
 #include <linux/vt_kern.h>
 #include <linux/selection.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/vs_cvirt.h>
 
 #include <linux/kmod.h>
-#include <linux/vs_cvirt.h>
 
 #undef TTY_DEBUG_HANGUP
 
@@ -127,10 +129,9 @@ EXPORT_SYMBOL(tty_std_termios);
    
 LIST_HEAD(tty_drivers);                        /* linked list of tty drivers */
 
-/* Mutex to protect creating and releasing a tty. This is shared with
+/* Semaphore to protect creating and releasing a tty. This is shared with
    vt.c for deeply disgusting hack reasons */
-DEFINE_MUTEX(tty_mutex);
-EXPORT_SYMBOL(tty_mutex);
+DECLARE_MUTEX(tty_sem);
 
 #ifdef CONFIG_UNIX98_PTYS
 extern struct tty_driver *ptm_driver;  /* Unix98 pty masters; for /dev/ptmx */
@@ -155,31 +156,19 @@ int tty_ioctl(struct inode * inode, struct file * file,
 static int tty_fasync(int fd, struct file * filp, int on);
 static void release_mem(struct tty_struct *tty, int idx);
 
-/**
- *     alloc_tty_struct        -       allocate a tty object
- *
- *     Return a new empty tty structure. The data fields have not
- *     been initialized in any way but has been zeroed
- *
- *     Locking: none
- */
 
 static struct tty_struct *alloc_tty_struct(void)
 {
-       return kzalloc(sizeof(struct tty_struct), GFP_KERNEL);
+       struct tty_struct *tty;
+
+       tty = kmalloc(sizeof(struct tty_struct), GFP_KERNEL);
+       if (tty)
+               memset(tty, 0, sizeof(struct tty_struct));
+       return tty;
 }
 
 static void tty_buffer_free_all(struct tty_struct *);
 
-/**
- *     free_tty_struct         -       free a disused tty
- *     @tty: tty struct to free
- *
- *     Free the write buffers, tty queue and tty memory itself.
- *
- *     Locking: none. Must be called after tty is definitely unused
- */
-
 static inline void free_tty_struct(struct tty_struct *tty)
 {
        kfree(tty->write_buf);
@@ -189,17 +178,6 @@ static inline void free_tty_struct(struct tty_struct *tty)
 
 #define TTY_NUMBER(tty) ((tty)->index + (tty)->driver->name_base)
 
-/**
- *     tty_name        -       return tty naming
- *     @tty: tty structure
- *     @buf: buffer for output
- *
- *     Convert a tty structure into a name. The name reflects the kernel
- *     naming policy and if udev is in use may not reflect user space
- *
- *     Locking: none
- */
-
 char *tty_name(struct tty_struct *tty, char *buf)
 {
        if (!tty) /* Hmm.  NULL pointer.  That's fun. */
@@ -251,7 +229,7 @@ static int check_tty_count(struct tty_struct *tty, const char *routine)
                                    "!= #fd's(%d) in %s\n",
                       tty->name, tty->count, count, routine);
                return count;
-       }
+       }       
 #endif
        return 0;
 }
@@ -260,16 +238,6 @@ static int check_tty_count(struct tty_struct *tty, const char *routine)
  * Tty buffer allocation management
  */
 
-/**
- *     tty_buffer_free_all             -       free buffers used by a tty
- *     @tty: tty to free from
- *
- *     Remove all the buffers pending on a tty whether queued with data
- *     or in the free ring. Must be called when the tty is no longer in use
- *
- *     Locking: none
- */
-
 static void tty_buffer_free_all(struct tty_struct *tty)
 {
        struct tty_buffer *thead;
@@ -282,77 +250,40 @@ static void tty_buffer_free_all(struct tty_struct *tty)
                kfree(thead);
        }
        tty->buf.tail = NULL;
-       tty->buf.memory_used = 0;
 }
 
-/**
- *     tty_buffer_init         -       prepare a tty buffer structure
- *     @tty: tty to initialise
- *
- *     Set up the initial state of the buffer management for a tty device.
- *     Must be called before the other tty buffer functions are used.
- *
- *     Locking: none
- */
-
 static void tty_buffer_init(struct tty_struct *tty)
 {
        spin_lock_init(&tty->buf.lock);
        tty->buf.head = NULL;
        tty->buf.tail = NULL;
        tty->buf.free = NULL;
-       tty->buf.memory_used = 0;
 }
 
-/**
- *     tty_buffer_alloc        -       allocate a tty buffer
- *     @tty: tty device
- *     @size: desired size (characters)
- *
- *     Allocate a new tty buffer to hold the desired number of characters.
- *     Return NULL if out of memory or the allocation would exceed the
- *     per device queue
- *
- *     Locking: Caller must hold tty->buf.lock
- */
-
-static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size)
+static struct tty_buffer *tty_buffer_alloc(size_t size)
 {
-       struct tty_buffer *p;
-
-       if (tty->buf.memory_used + size > 65536)
-               return NULL;
-       p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC);
+       struct tty_buffer *p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC);
        if(p == NULL)
                return NULL;
        p->used = 0;
        p->size = size;
        p->next = NULL;
+       p->active = 0;
        p->commit = 0;
        p->read = 0;
        p->char_buf_ptr = (char *)(p->data);
        p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size;
-       tty->buf.memory_used += size;
+/*     printk("Flip create %p\n", p); */
        return p;
 }
 
-/**
- *     tty_buffer_free         -       free a tty buffer
- *     @tty: tty owning the buffer
- *     @b: the buffer to free
- *
- *     Free a tty buffer, or add it to the free list according to our
- *     internal strategy
- *
- *     Locking: Caller must hold tty->buf.lock
- */
+/* Must be called with the tty_read lock held. This needs to acquire strategy
+   code to decide if we should kfree or relink a given expired buffer */
 
 static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b)
 {
        /* Dumb strategy for now - should keep some stats */
-       tty->buf.memory_used -= b->size;
-       WARN_ON(tty->buf.memory_used < 0);
-
+/*     printk("Flip dispose %p\n", b); */
        if(b->size >= 512)
                kfree(b);
        else {
@@ -361,18 +292,6 @@ static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b)
        }
 }
 
-/**
- *     tty_buffer_find         -       find a free tty buffer
- *     @tty: tty owning the buffer
- *     @size: characters wanted
- *
- *     Locate an existing suitable tty buffer or if we are lacking one then
- *     allocate a new one. We round our buffers off in 256 character chunks
- *     to get better allocation behaviour.
- *
- *     Locking: Caller must hold tty->buf.lock
- */
-
 static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
 {
        struct tty_buffer **tbh = &tty->buf.free;
@@ -384,28 +303,20 @@ static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
                        t->used = 0;
                        t->commit = 0;
                        t->read = 0;
-                       tty->buf.memory_used += t->size;
+                       /* DEBUG ONLY */
+/*                     memset(t->data, '*', size); */
+/*                     printk("Flip recycle %p\n", t); */
                        return t;
                }
                tbh = &((*tbh)->next);
        }
        /* Round the buffer size out */
        size = (size + 0xFF) & ~ 0xFF;
-       return tty_buffer_alloc(tty, size);
+       return tty_buffer_alloc(size);
        /* Should possibly check if this fails for the largest buffer we
           have queued and recycle that ? */
 }
 
-/**
- *     tty_buffer_request_room         -       grow tty buffer if needed
- *     @tty: tty structure
- *     @size: size desired
- *
- *     Make at least size bytes of linear space available for the tty
- *     buffer. If we fail return the size we managed to find.
- *
- *     Locking: Takes tty->buf.lock
- */
 int tty_buffer_request_room(struct tty_struct *tty, size_t size)
 {
        struct tty_buffer *b, *n;
@@ -417,9 +328,10 @@ int tty_buffer_request_room(struct tty_struct *tty, size_t size)
        /* OPTIMISATION: We could keep a per tty "zero" sized buffer to
           remove this conditional if its worth it. This would be invisible
           to the callers */
-       if ((b = tty->buf.tail) != NULL)
+       if ((b = tty->buf.tail) != NULL) {
                left = b->size - b->used;
-       else
+               b->active = 1;
+       } else
                left = 0;
 
        if (left < size) {
@@ -427,10 +339,12 @@ int tty_buffer_request_room(struct tty_struct *tty, size_t size)
                if ((n = tty_buffer_find(tty, size)) != NULL) {
                        if (b != NULL) {
                                b->next = n;
+                               b->active = 0;
                                b->commit = b->used;
                        } else
                                tty->buf.head = n;
                        tty->buf.tail = n;
+                       n->active = 1;
                } else
                        size = left;
        }
@@ -438,22 +352,10 @@ int tty_buffer_request_room(struct tty_struct *tty, size_t size)
        spin_unlock_irqrestore(&tty->buf.lock, flags);
        return size;
 }
-EXPORT_SYMBOL_GPL(tty_buffer_request_room);
 
-/**
- *     tty_insert_flip_string  -       Add characters to the tty buffer
- *     @tty: tty structure
- *     @chars: characters
- *     @size: size
- *
- *     Queue a series of bytes to the tty buffering. All the characters
- *     passed are marked as without error. Returns the number added.
- *
- *     Locking: Called functions may take tty->buf.lock
- */
+EXPORT_SYMBOL_GPL(tty_buffer_request_room);
 
-int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars,
-                               size_t size)
+int tty_insert_flip_string(struct tty_struct *tty, unsigned char *chars, size_t size)
 {
        int copied = 0;
        do {
@@ -467,29 +369,17 @@ int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars,
                tb->used += space;
                copied += space;
                chars += space;
-               /* There is a small chance that we need to split the data over
-                  several buffers. If this is the case we must loop */
-       } while (unlikely(size > copied));
+/*             printk("Flip insert %d.\n", space); */
+       }
+       /* There is a small chance that we need to split the data over
+          several buffers. If this is the case we must loop */
+       while (unlikely(size > copied));
        return copied;
 }
-EXPORT_SYMBOL(tty_insert_flip_string);
 
-/**
- *     tty_insert_flip_string_flags    -       Add characters to the tty buffer
- *     @tty: tty structure
- *     @chars: characters
- *     @flags: flag bytes
- *     @size: size
- *
- *     Queue a series of bytes to the tty buffering. For each character
- *     the flags array indicates the status of the character. Returns the
- *     number added.
- *
- *     Locking: Called functions may take tty->buf.lock
- */
+EXPORT_SYMBOL_GPL(tty_insert_flip_string);
 
-int tty_insert_flip_string_flags(struct tty_struct *tty,
-               const unsigned char *chars, const char *flags, size_t size)
+int tty_insert_flip_string_flags(struct tty_struct *tty, unsigned char *chars, char *flags, size_t size)
 {
        int copied = 0;
        do {
@@ -504,48 +394,22 @@ int tty_insert_flip_string_flags(struct tty_struct *tty,
                copied += space;
                chars += space;
                flags += space;
-               /* There is a small chance that we need to split the data over
-                  several buffers. If this is the case we must loop */
-       } while (unlikely(size > copied));
+       }
+       /* There is a small chance that we need to split the data over
+          several buffers. If this is the case we must loop */
+       while (unlikely(size > copied));
        return copied;
 }
-EXPORT_SYMBOL(tty_insert_flip_string_flags);
 
-/**
- *     tty_schedule_flip       -       push characters to ldisc
- *     @tty: tty to push from
- *
- *     Takes any pending buffers and transfers their ownership to the
- *     ldisc side of the queue. It then schedules those characters for
- *     processing by the line discipline.
- *
- *     Locking: Takes tty->buf.lock
- */
+EXPORT_SYMBOL_GPL(tty_insert_flip_string_flags);
 
-void tty_schedule_flip(struct tty_struct *tty)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&tty->buf.lock, flags);
-       if (tty->buf.tail != NULL)
-               tty->buf.tail->commit = tty->buf.tail->used;
-       spin_unlock_irqrestore(&tty->buf.lock, flags);
-       schedule_delayed_work(&tty->buf.work, 1);
-}
-EXPORT_SYMBOL(tty_schedule_flip);
 
-/**
- *     tty_prepare_flip_string         -       make room for characters
- *     @tty: tty
- *     @chars: return pointer for character write area
- *     @size: desired size
- *
+/*
  *     Prepare a block of space in the buffer for data. Returns the length
  *     available and buffer pointer to the space which is now allocated and
  *     accounted for as ready for normal characters. This is used for drivers
  *     that need their own block copy routines into the buffer. There is no
  *     guarantee the buffer is a DMA target!
- *
- *     Locking: May call functions taking tty->buf.lock
  */
 
 int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, size_t size)
@@ -562,20 +426,12 @@ int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, size_
 
 EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
 
-/**
- *     tty_prepare_flip_string_flags   -       make room for characters
- *     @tty: tty
- *     @chars: return pointer for character write area
- *     @flags: return pointer for status flag write area
- *     @size: desired size
- *
+/*
  *     Prepare a block of space in the buffer for data. Returns the length
  *     available and buffer pointer to the space which is now allocated and
  *     accounted for as ready for characters. This is used for drivers
  *     that need their own block copy routines into the buffer. There is no
  *     guarantee the buffer is a DMA target!
- *
- *     Locking: May call functions taking tty->buf.lock
  */
 
 int tty_prepare_flip_string_flags(struct tty_struct *tty, unsigned char **chars, char **flags, size_t size)
@@ -594,23 +450,17 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
 
 
 
-/**
- *     tty_set_termios_ldisc           -       set ldisc field
- *     @tty: tty structure
- *     @num: line discipline number
- *
+/*
  *     This is probably overkill for real world processors but
  *     they are not on hot paths so a little discipline won't do 
  *     any harm.
- *
- *     Locking: takes termios_mutex
  */
  
 static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
 {
-       mutex_lock(&tty->termios_mutex);
+       down(&tty->termios_sem);
        tty->termios->c_line = num;
-       mutex_unlock(&tty->termios_mutex);
+       up(&tty->termios_sem);
 }
 
 /*
@@ -623,19 +473,6 @@ static DEFINE_SPINLOCK(tty_ldisc_lock);
 static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait);
 static struct tty_ldisc tty_ldiscs[NR_LDISCS]; /* line disc dispatch table */
 
-/**
- *     tty_register_ldisc      -       install a line discipline
- *     @disc: ldisc number
- *     @new_ldisc: pointer to the ldisc object
- *
- *     Installs a new line discipline into the kernel. The discipline
- *     is set up as unreferenced and then made available to the kernel
- *     from this point onwards.
- *
- *     Locking:
- *             takes tty_ldisc_lock to guard against ldisc races
- */
-
 int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc)
 {
        unsigned long flags;
@@ -655,18 +492,6 @@ int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc)
 }
 EXPORT_SYMBOL(tty_register_ldisc);
 
-/**
- *     tty_unregister_ldisc    -       unload a line discipline
- *     @disc: ldisc number
- *     @new_ldisc: pointer to the ldisc object
- *
- *     Remove a line discipline from the kernel providing it is not
- *     currently in use.
- *
- *     Locking:
- *             takes tty_ldisc_lock to guard against ldisc races
- */
-
 int tty_unregister_ldisc(int disc)
 {
        unsigned long flags;
@@ -686,19 +511,6 @@ int tty_unregister_ldisc(int disc)
 }
 EXPORT_SYMBOL(tty_unregister_ldisc);
 
-/**
- *     tty_ldisc_get           -       take a reference to an ldisc
- *     @disc: ldisc number
- *
- *     Takes a reference to a line discipline. Deals with refcounts and
- *     module locking counts. Returns NULL if the discipline is not available.
- *     Returns a pointer to the discipline and bumps the ref count if it is
- *     available
- *
- *     Locking:
- *             takes tty_ldisc_lock to guard against ldisc races
- */
-
 struct tty_ldisc *tty_ldisc_get(int disc)
 {
        unsigned long flags;
@@ -727,47 +539,25 @@ struct tty_ldisc *tty_ldisc_get(int disc)
 
 EXPORT_SYMBOL_GPL(tty_ldisc_get);
 
-/**
- *     tty_ldisc_put           -       drop ldisc reference
- *     @disc: ldisc number
- *
- *     Drop a reference to a line discipline. Manage refcounts and
- *     module usage counts
- *
- *     Locking:
- *             takes tty_ldisc_lock to guard against ldisc races
- */
-
 void tty_ldisc_put(int disc)
 {
        struct tty_ldisc *ld;
        unsigned long flags;
        
-       BUG_ON(disc < N_TTY || disc >= NR_LDISCS);
+       if (disc < N_TTY || disc >= NR_LDISCS)
+               BUG();
                
        spin_lock_irqsave(&tty_ldisc_lock, flags);
        ld = &tty_ldiscs[disc];
-       BUG_ON(ld->refcount == 0);
-       ld->refcount--;
+       if(ld->refcount == 0)
+               BUG();
+       ld->refcount --;
        module_put(ld->owner);
        spin_unlock_irqrestore(&tty_ldisc_lock, flags);
 }
        
 EXPORT_SYMBOL_GPL(tty_ldisc_put);
 
-/**
- *     tty_ldisc_assign        -       set ldisc on a tty
- *     @tty: tty to assign
- *     @ld: line discipline
- *
- *     Install an instance of a line discipline into a tty structure. The
- *     ldisc must have a reference count above zero to ensure it remains/
- *     The tty instance refcount starts at zero.
- *
- *     Locking:
- *             Caller must hold references
- */
-
 static void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld)
 {
        tty->ldisc = *ld;
@@ -782,8 +572,6 @@ static void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld)
  *     the tty ldisc. Return 0 on failure or 1 on success. This is
  *     used to implement both the waiting and non waiting versions
  *     of tty_ldisc_ref
- *
- *     Locking: takes tty_ldisc_lock
  */
 
 static int tty_ldisc_try(struct tty_struct *tty)
@@ -815,8 +603,6 @@ static int tty_ldisc_try(struct tty_struct *tty)
  *     must also be careful not to hold other locks that will deadlock
  *     against a discipline change, such as an existing ldisc reference
  *     (which we check for)
- *
- *     Locking: call functions take tty_ldisc_lock
  */
  
 struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty)
@@ -837,8 +623,6 @@ EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait);
  *     Dereference the line discipline for the terminal and take a 
  *     reference to it. If the line discipline is in flux then 
  *     return NULL. Can be called from IRQ and timer functions.
- *
- *     Locking: called functions take tty_ldisc_lock
  */
  
 struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty)
@@ -856,15 +640,14 @@ EXPORT_SYMBOL_GPL(tty_ldisc_ref);
  *
  *     Undoes the effect of tty_ldisc_ref or tty_ldisc_ref_wait. May
  *     be called in IRQ context.
- *
- *     Locking: takes tty_ldisc_lock
  */
  
 void tty_ldisc_deref(struct tty_ldisc *ld)
 {
        unsigned long flags;
 
-       BUG_ON(ld == NULL);
+       if(ld == NULL)
+               BUG();
                
        spin_lock_irqsave(&tty_ldisc_lock, flags);
        if(ld->refcount == 0)
@@ -902,9 +685,6 @@ static void tty_ldisc_enable(struct tty_struct *tty)
  *
  *     Set the discipline of a tty line. Must be called from a process
  *     context.
- *
- *     Locking: takes tty_ldisc_lock.
- *              called functions take termios_mutex
  */
  
 static int tty_set_ldisc(struct tty_struct *tty, int ldisc)
@@ -998,8 +778,11 @@ restart:
        }
 
        clear_bit(TTY_LDISC, &tty->flags);
-       if (o_tty)
+       clear_bit(TTY_DONT_FLIP, &tty->flags);
+       if (o_tty) {
                clear_bit(TTY_LDISC, &o_tty->flags);
+               clear_bit(TTY_DONT_FLIP, &o_tty->flags);
+       }
        spin_unlock_irqrestore(&tty_ldisc_lock, flags);
 
        /*
@@ -1068,17 +851,9 @@ restart:
        return retval;
 }
 
-/**
- *     get_tty_driver          -       find device of a tty
- *     @dev_t: device identifier
- *     @index: returns the index of the tty
- *
- *     This routine returns a tty driver structure, given a device number
- *     and also passes back the index number.
- *
- *     Locking: caller must hold tty_mutex
+/*
+ * This routine returns a tty driver structure, given a device number
  */
-
 static struct tty_driver *get_tty_driver(dev_t device, int *index)
 {
        struct tty_driver *p;
@@ -1093,17 +868,11 @@ static struct tty_driver *get_tty_driver(dev_t device, int *index)
        return NULL;
 }
 
-/**
- *     tty_check_change        -       check for POSIX terminal changes
- *     @tty: tty to check
- *
- *     If we try to write to, or set the state of, a terminal and we're
- *     not in the foreground, send a SIGTTOU.  If the signal is blocked or
- *     ignored, go ahead and perform the operation.  (POSIX 7.2)
- *
- *     Locking: none
+/*
+ * If we try to write to, or set the state of, a terminal and we're
+ * not in the foreground, send a SIGTTOU.  If the signal is blocked or
+ * ignored, go ahead and perform the operation.  (POSIX 7.2)
  */
-
 int tty_check_change(struct tty_struct * tty)
 {
        if (current->signal->tty != tty)
@@ -1148,7 +917,7 @@ static int hung_up_tty_ioctl(struct inode * inode, struct file * file,
        return cmd == TIOCSPGRP ? -ENOTTY : -EIO;
 }
 
-static const struct file_operations tty_fops = {
+static struct file_operations tty_fops = {
        .llseek         = no_llseek,
        .read           = tty_read,
        .write          = tty_write,
@@ -1160,7 +929,7 @@ static const struct file_operations tty_fops = {
 };
 
 #ifdef CONFIG_UNIX98_PTYS
-static const struct file_operations ptmx_fops = {
+static struct file_operations ptmx_fops = {
        .llseek         = no_llseek,
        .read           = tty_read,
        .write          = tty_write,
@@ -1172,7 +941,7 @@ static const struct file_operations ptmx_fops = {
 };
 #endif
 
-static const struct file_operations console_fops = {
+static struct file_operations console_fops = {
        .llseek         = no_llseek,
        .read           = tty_read,
        .write          = redirected_tty_write,
@@ -1183,7 +952,7 @@ static const struct file_operations console_fops = {
        .fasync         = tty_fasync,
 };
 
-static const struct file_operations hung_up_tty_fops = {
+static struct file_operations hung_up_tty_fops = {
        .llseek         = no_llseek,
        .read           = hung_up_tty_read,
        .write          = hung_up_tty_write,
@@ -1241,27 +1010,10 @@ void tty_ldisc_flush(struct tty_struct *tty)
 
 EXPORT_SYMBOL_GPL(tty_ldisc_flush);
        
-/**
- *     do_tty_hangup           -       actual handler for hangup events
- *     @data: tty device
- *
- *     This can be called by the "eventd" kernel thread.  That is process
- *     synchronous but doesn't hold any locks, so we need to make sure we
- *     have the appropriate locks for what we're doing.
- *
- *     The hangup event clears any pending redirections onto the hung up
- *     device. It ensures future writes will error and it does the needed
- *     line discipline hangup and signal delivery. The tty object itself
- *     remains intact.
- *
- *     Locking:
- *             BKL
- *               redirect lock for undoing redirection
- *               file list lock for manipulating list of ttys
- *               tty_ldisc_lock from called functions
- *               termios_mutex resetting termios data
- *               tasklist_lock to walk task list for hangup event
- *                 ->siglock to protect ->signal/->sighand
+/*
+ * This can be called by the "eventd" kernel thread.  That is process synchronous,
+ * but doesn't hold any locks, so we need to make sure we have the appropriate
+ * locks for what we're doing..
  */
 static void do_tty_hangup(void *data)
 {
@@ -1328,9 +1080,9 @@ static void do_tty_hangup(void *data)
         */
        if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS)
        {
-               mutex_lock(&tty->termios_mutex);
+               down(&tty->termios_sem);
                *tty->termios = tty->driver->init_termios;
-               mutex_unlock(&tty->termios_mutex);
+               up(&tty->termios_sem);
        }
        
        /* Defer ldisc switch */
@@ -1342,18 +1094,14 @@ static void do_tty_hangup(void *data)
        read_lock(&tasklist_lock);
        if (tty->session > 0) {
                do_each_task_pid(tty->session, PIDTYPE_SID, p) {
-                       spin_lock_irq(&p->sighand->siglock);
                        if (p->signal->tty == tty)
                                p->signal->tty = NULL;
-                       if (!p->signal->leader) {
-                               spin_unlock_irq(&p->sighand->siglock);
+                       if (!p->signal->leader)
                                continue;
-                       }
-                       __group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p);
-                       __group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p);
+                       send_group_sig_info(SIGHUP, SEND_SIG_PRIV, p);
+                       send_group_sig_info(SIGCONT, SEND_SIG_PRIV, p);
                        if (tty->pgrp > 0)
                                p->signal->tty_old_pgrp = tty->pgrp;
-                       spin_unlock_irq(&p->sighand->siglock);
                } while_each_task_pid(tty->session, PIDTYPE_SID, p);
        }
        read_unlock(&tasklist_lock);
@@ -1390,14 +1138,6 @@ static void do_tty_hangup(void *data)
                fput(f);
 }
 
-/**
- *     tty_hangup              -       trigger a hangup event
- *     @tty: tty to hangup
- *
- *     A carrier loss (virtual or otherwise) has occurred on this like
- *     schedule a hangup sequence to run after this event.
- */
-
 void tty_hangup(struct tty_struct * tty)
 {
 #ifdef TTY_DEBUG_HANGUP
@@ -1410,15 +1150,6 @@ void tty_hangup(struct tty_struct * tty)
 
 EXPORT_SYMBOL(tty_hangup);
 
-/**
- *     tty_vhangup             -       process vhangup
- *     @tty: tty to hangup
- *
- *     The user has asked via system call for the terminal to be hung up.
- *     We do this synchronously so that when the syscall returns the process
- *     is complete. That guarantee is neccessary for security reasons.
- */
-
 void tty_vhangup(struct tty_struct * tty)
 {
 #ifdef TTY_DEBUG_HANGUP
@@ -1430,14 +1161,6 @@ void tty_vhangup(struct tty_struct * tty)
 }
 EXPORT_SYMBOL(tty_vhangup);
 
-/**
- *     tty_hung_up_p           -       was tty hung up
- *     @filp: file pointer of tty
- *
- *     Return true if the tty has been subject to a vhangup or a carrier
- *     loss
- */
-
 int tty_hung_up_p(struct file * filp)
 {
        return (filp->f_op == &hung_up_tty_fops);
@@ -1445,61 +1168,40 @@ int tty_hung_up_p(struct file * filp)
 
 EXPORT_SYMBOL(tty_hung_up_p);
 
-static void session_clear_tty(pid_t session)
-{
-       struct task_struct *p;
-       do_each_task_pid(session, PIDTYPE_SID, p) {
-               proc_clear_tty(p);
-       } while_each_task_pid(session, PIDTYPE_SID, p);
-}
-
-/**
- *     disassociate_ctty       -       disconnect controlling tty
- *     @on_exit: true if exiting so need to "hang up" the session
- *
- *     This function is typically called only by the session leader, when
- *     it wants to disassociate itself from its controlling tty.
+/*
+ * This function is typically called only by the session leader, when
+ * it wants to disassociate itself from its controlling tty.
  *
- *     It performs the following functions:
+ * It performs the following functions:
  *     (1)  Sends a SIGHUP and SIGCONT to the foreground process group
  *     (2)  Clears the tty from being controlling the session
  *     (3)  Clears the controlling tty for all processes in the
  *             session group.
  *
- *     The argument on_exit is set to 1 if called when a process is
- *     exiting; it is 0 if called by the ioctl TIOCNOTTY.
- *
- *     Locking:
- *             BKL is taken for hysterical raisins
- *               tty_mutex is taken to protect tty
- *               ->siglock is taken to protect ->signal/->sighand
- *               tasklist_lock is taken to walk process list for sessions
- *                 ->siglock is taken to protect ->signal/->sighand
+ * The argument on_exit is set to 1 if called when a process is
+ * exiting; it is 0 if called by the ioctl TIOCNOTTY.
  */
-
 void disassociate_ctty(int on_exit)
 {
        struct tty_struct *tty;
+       struct task_struct *p;
        int tty_pgrp = -1;
-       int session;
 
        lock_kernel();
 
-       mutex_lock(&tty_mutex);
-       tty = get_current_tty();
+       down(&tty_sem);
+       tty = current->signal->tty;
        if (tty) {
                tty_pgrp = tty->pgrp;
-               mutex_unlock(&tty_mutex);
-               /* XXX: here we race, there is nothing protecting tty */
+               up(&tty_sem);
                if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY)
                        tty_vhangup(tty);
        } else {
-               pid_t old_pgrp = current->signal->tty_old_pgrp;
-               if (old_pgrp) {
-                       kill_pg(old_pgrp, SIGHUP, on_exit);
-                       kill_pg(old_pgrp, SIGCONT, on_exit);
+               if (current->signal->tty_old_pgrp) {
+                       kill_pg(current->signal->tty_old_pgrp, SIGHUP, on_exit);
+                       kill_pg(current->signal->tty_old_pgrp, SIGCONT, on_exit);
                }
-               mutex_unlock(&tty_mutex);
+               up(&tty_sem);
                unlock_kernel();        
                return;
        }
@@ -1509,51 +1211,22 @@ void disassociate_ctty(int on_exit)
                        kill_pg(tty_pgrp, SIGCONT, on_exit);
        }
 
-       spin_lock_irq(&current->sighand->siglock);
+       /* Must lock changes to tty_old_pgrp */
+       down(&tty_sem);
        current->signal->tty_old_pgrp = 0;
-       session = current->signal->session;
-       spin_unlock_irq(&current->sighand->siglock);
-
-       mutex_lock(&tty_mutex);
-       /* It is possible that do_tty_hangup has free'd this tty */
-       tty = get_current_tty();
-       if (tty) {
-               tty->session = 0;
-               tty->pgrp = 0;
-       } else {
-#ifdef TTY_DEBUG_HANGUP
-               printk(KERN_DEBUG "error attempted to write to tty [0x%p]"
-                      " = NULL", tty);
-#endif
-       }
-       mutex_unlock(&tty_mutex);
+       tty->session = 0;
+       tty->pgrp = -1;
 
        /* Now clear signal->tty under the lock */
        read_lock(&tasklist_lock);
-       session_clear_tty(session);
+       do_each_task_pid(current->signal->session, PIDTYPE_SID, p) {
+               p->signal->tty = NULL;
+       } while_each_task_pid(current->signal->session, PIDTYPE_SID, p);
        read_unlock(&tasklist_lock);
+       up(&tty_sem);
        unlock_kernel();
 }
 
-
-/**
- *     stop_tty        -       propogate flow control
- *     @tty: tty to stop
- *
- *     Perform flow control to the driver. For PTY/TTY pairs we
- *     must also propogate the TIOCKPKT status. May be called
- *     on an already stopped device and will not re-call the driver
- *     method.
- *
- *     This functionality is used by both the line disciplines for
- *     halting incoming flow and by the driver. It may therefore be
- *     called from any context, may be under the tty atomic_write_lock
- *     but not always.
- *
- *     Locking:
- *             Broken. Relies on BKL which is unsafe here.
- */
-
 void stop_tty(struct tty_struct *tty)
 {
        if (tty->stopped)
@@ -1570,19 +1243,6 @@ void stop_tty(struct tty_struct *tty)
 
 EXPORT_SYMBOL(stop_tty);
 
-/**
- *     start_tty       -       propogate flow control
- *     @tty: tty to start
- *
- *     Start a tty that has been stopped if at all possible. Perform
- *     any neccessary wakeups and propogate the TIOCPKT status. If this
- *     is the tty was previous stopped and is being started then the
- *     driver start method is invoked and the line discipline woken.
- *
- *     Locking:
- *             Broken. Relies on BKL which is unsafe here.
- */
-
 void start_tty(struct tty_struct *tty)
 {
        if (!tty->stopped || tty->flow_stopped)
@@ -1603,23 +1263,6 @@ void start_tty(struct tty_struct *tty)
 
 EXPORT_SYMBOL(start_tty);
 
-/**
- *     tty_read        -       read method for tty device files
- *     @file: pointer to tty file
- *     @buf: user buffer
- *     @count: size of user buffer
- *     @ppos: unused
- *
- *     Perform the read system call function on this terminal device. Checks
- *     for hung up devices before calling the line discipline method.
- *
- *     Locking:
- *             Locks the line discipline internally while needed
- *             For historical reasons the line discipline read method is
- *     invoked under the BKL. This will go away in time so do not rely on it
- *     in new code. Multiple read calls may be outstanding in parallel.
- */
-
 static ssize_t tty_read(struct file * file, char __user * buf, size_t count, 
                        loff_t *ppos)
 {
@@ -1664,8 +1307,7 @@ static inline ssize_t do_tty_write(
        ssize_t ret = 0, written = 0;
        unsigned int chunk;
        
-       /* FIXME: O_NDELAY ... */
-       if (mutex_lock_interruptible(&tty->atomic_write_lock)) {
+       if (down_interruptible(&tty->atomic_write)) {
                return -ERESTARTSYS;
        }
 
@@ -1681,9 +1323,6 @@ static inline ssize_t do_tty_write(
         * layer has problems with bigger chunks. It will
         * claim to be able to handle more characters than
         * it actually does.
-        *
-        * FIXME: This can probably go away now except that 64K chunks
-        * are too likely to fail unless switched to vmalloc...
         */
        chunk = 2048;
        if (test_bit(TTY_NO_WRITE_SPLIT, &tty->flags))
@@ -1691,7 +1330,7 @@ static inline ssize_t do_tty_write(
        if (count < chunk)
                chunk = count;
 
-       /* write_buf/write_cnt is protected by the atomic_write_lock mutex */
+       /* write_buf/write_cnt is protected by the atomic_write semaphore */
        if (tty->write_cnt < chunk) {
                unsigned char *buf;
 
@@ -1700,7 +1339,7 @@ static inline ssize_t do_tty_write(
 
                buf = kmalloc(chunk, GFP_KERNEL);
                if (!buf) {
-                       mutex_unlock(&tty->atomic_write_lock);
+                       up(&tty->atomic_write);
                        return -ENOMEM;
                }
                kfree(tty->write_buf);
@@ -1736,29 +1375,11 @@ static inline ssize_t do_tty_write(
                inode->i_mtime = current_fs_time(inode->i_sb);
                ret = written;
        }
-       mutex_unlock(&tty->atomic_write_lock);
+       up(&tty->atomic_write);
        return ret;
 }
 
 
-/**
- *     tty_write               -       write method for tty device file
- *     @file: tty file pointer
- *     @buf: user data to write
- *     @count: bytes to write
- *     @ppos: unused
- *
- *     Write data to a tty device via the line discipline.
- *
- *     Locking:
- *             Locks the line discipline as required
- *             Writes to the tty driver are serialized by the atomic_write_lock
- *     and are then processed in chunks to the device. The line discipline
- *     write method will not be involked in parallel for each device
- *             The line discipline write method is called under the big
- *     kernel lock for historical reasons. New code should not rely on this.
- */
-
 static ssize_t tty_write(struct file * file, const char __user * buf, size_t count,
                         loff_t *ppos)
 {
@@ -1806,18 +1427,7 @@ ssize_t redirected_tty_write(struct file * file, const char __user * buf, size_t
 
 static char ptychar[] = "pqrstuvwxyzabcde";
 
-/**
- *     pty_line_name   -       generate name for a pty
- *     @driver: the tty driver in use
- *     @index: the minor number
- *     @p: output buffer of at least 6 bytes
- *
- *     Generate a name from a driver reference and write it to the output
- *     buffer.
- *
- *     Locking: None
- */
-static void pty_line_name(struct tty_driver *driver, int index, char *p)
+static inline void pty_line_name(struct tty_driver *driver, int index, char *p)
 {
        int i = index + driver->name_base;
        /* ->name is initialized to "ttyp", but "tty" is expected */
@@ -1826,53 +1436,24 @@ static void pty_line_name(struct tty_driver *driver, int index, char *p)
                        ptychar[i >> 4 & 0xf], i & 0xf);
 }
 
-/**
- *     pty_line_name   -       generate name for a tty
- *     @driver: the tty driver in use
- *     @index: the minor number
- *     @p: output buffer of at least 7 bytes
- *
- *     Generate a name from a driver reference and write it to the output
- *     buffer.
- *
- *     Locking: None
- */
-static void tty_line_name(struct tty_driver *driver, int index, char *p)
+static inline void tty_line_name(struct tty_driver *driver, int index, char *p)
 {
        sprintf(p, "%s%d", driver->name, index + driver->name_base);
 }
 
-/**
- *     init_dev                -       initialise a tty device
- *     @driver: tty driver we are opening a device on
- *     @idx: device index
- *     @tty: returned tty structure
- *
- *     Prepare a tty device. This may not be a "new" clean device but
- *     could also be an active device. The pty drivers require special
- *     handling because of this.
- *
- *     Locking:
- *             The function is called under the tty_mutex, which
- *     protects us from the tty struct or driver itself going away.
- *
- *     On exit the tty device has the line discipline attached and
- *     a reference count of 1. If a pair was created for pty/tty use
- *     and the other was a pty master then it too has a reference count of 1.
- *
+/*
  * WSH 06/09/97: Rewritten to remove races and properly clean up after a
- * failed open.  The new code protects the open with a mutex, so it's
- * really quite straightforward.  The mutex locking can probably be
+ * failed open.  The new code protects the open with a semaphore, so it's
+ * really quite straightforward.  The semaphore locking can probably be
  * relaxed for the (most common) case of reopening a tty.
  */
-
 static int init_dev(struct tty_driver *driver, int idx,
        struct tty_struct **ret_tty)
 {
        struct tty_struct *tty, *o_tty;
        struct termios *tp, **tp_loc, *o_tp, **o_tp_loc;
        struct termios *ltp, **ltp_loc, *o_ltp, **o_ltp_loc;
-       int retval = 0;
+       int retval=0;
 
        /* check whether we're reopening an existing tty */
        if (driver->flags & TTY_DRIVER_DEVPTS_MEM) {
@@ -2060,7 +1641,7 @@ fast_track:
 success:
        *ret_tty = tty;
        
-       /* All paths come through here to release the mutex */
+       /* All paths come through here to release the semaphore */
 end_init:
        return retval;
 
@@ -2086,20 +1667,10 @@ release_mem_out:
        goto end_init;
 }
 
-/**
- *     release_mem             -       release tty structure memory
- *
- *     Releases memory associated with a tty structure, and clears out the
- *     driver table slots. This function is called when a device is no longer
- *     in use. It also gets called when setup of a device fails.
- *
- *     Locking:
- *             tty_mutex - sometimes only
- *             takes the file list lock internally when working on the list
- *     of ttys that the driver keeps.
- *             FIXME: should we require tty_mutex is held here ??
+/*
+ * Releases memory associated with a tty structure, and clears out the
+ * driver table slots.
  */
-
 static void release_mem(struct tty_struct *tty, int idx)
 {
        struct tty_struct *o_tty;
@@ -2163,7 +1734,7 @@ static void release_dev(struct file * filp)
 {
        struct tty_struct *tty, *o_tty;
        int     pty_master, tty_closing, o_tty_closing, do_sleep;
-       int     devpts;
+       int     devpts_master, devpts;
        int     idx;
        char    buf[64];
        unsigned long flags;
@@ -2180,6 +1751,7 @@ static void release_dev(struct file * filp)
        pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
                      tty->driver->subtype == PTY_TYPE_MASTER);
        devpts = (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) != 0;
+       devpts_master = pty_master && devpts;
        o_tty = tty->link;
 
 #ifdef TTY_PARANOIA_CHECK
@@ -2266,7 +1838,7 @@ static void release_dev(struct file * filp)
                /* Guard against races with tty->count changes elsewhere and
                   opens on /dev/tty */
                   
-               mutex_lock(&tty_mutex);
+               down(&tty_sem);
                tty_closing = tty->count <= 1;
                o_tty_closing = o_tty &&
                        (o_tty->count <= (pty_master ? 1 : 0));
@@ -2297,7 +1869,7 @@ static void release_dev(struct file * filp)
 
                printk(KERN_WARNING "release_dev: %s: read/write wait queue "
                                    "active!\n", tty_name(tty, buf));
-               mutex_unlock(&tty_mutex);
+               up(&tty_sem);
                schedule();
        }       
 
@@ -2350,14 +1922,20 @@ static void release_dev(struct file * filp)
         * tty.
         */
        if (tty_closing || o_tty_closing) {
+               struct task_struct *p;
+
                read_lock(&tasklist_lock);
-               session_clear_tty(tty->session);
+               do_each_task_pid(tty->session, PIDTYPE_SID, p) {
+                       p->signal->tty = NULL;
+               } while_each_task_pid(tty->session, PIDTYPE_SID, p);
                if (o_tty)
-                       session_clear_tty(o_tty->session);
+                       do_each_task_pid(o_tty->session, PIDTYPE_SID, p) {
+                               p->signal->tty = NULL;
+                       } while_each_task_pid(o_tty->session, PIDTYPE_SID, p);
                read_unlock(&tasklist_lock);
        }
 
-       mutex_unlock(&tty_mutex);
+       up(&tty_sem);
 
        /* check whether both sides are closing ... */
        if (!tty_closing || (o_tty && !o_tty_closing))
@@ -2372,6 +1950,7 @@ static void release_dev(struct file * filp)
         * race with the set_ldisc code path.
         */
        clear_bit(TTY_LDISC, &tty->flags);
+       clear_bit(TTY_DONT_FLIP, &tty->flags);
        cancel_delayed_work(&tty->buf.work);
 
        /*
@@ -2434,27 +2013,18 @@ static void release_dev(struct file * filp)
 
 }
 
-/**
- *     tty_open                -       open a tty device
- *     @inode: inode of device file
- *     @filp: file pointer to tty
- *
- *     tty_open and tty_release keep up the tty count that contains the
- *     number of opens done on a tty. We cannot use the inode-count, as
- *     different inodes might point to the same tty.
- *
- *     Open-counting is needed for pty masters, as well as for keeping
- *     track of serial lines: DTR is dropped when the last close happens.
- *     (This is not done solely through tty->count, now.  - Ted 1/27/92)
+/*
+ * tty_open and tty_release keep up the tty count that contains the
+ * number of opens done on a tty. We cannot use the inode-count, as
+ * different inodes might point to the same tty.
  *
- *     The termios state of a pty is reset on first open so that
- *     settings don't persist across reuse.
+ * Open-counting is needed for pty masters, as well as for keeping
+ * track of serial lines: DTR is dropped when the last close happens.
+ * (This is not done solely through tty->count, now.  - Ted 1/27/92)
  *
- *     Locking: tty_mutex protects tty, get_tty_driver and init_dev work.
- *              tty->count should protect the rest.
- *              ->siglock protects ->signal/->sighand
+ * The termios state of a pty is reset on first open so that
+ * settings don't persist across reuse.
  */
-
 static int tty_open(struct inode * inode, struct file * filp)
 {
        struct tty_struct *tty;
@@ -2471,16 +2041,15 @@ retry_open:
        index  = -1;
        retval = 0;
        
-       mutex_lock(&tty_mutex);
+       down(&tty_sem);
 
        if (device == MKDEV(TTYAUX_MAJOR,0)) {
-               tty = get_current_tty();
-               if (!tty) {
-                       mutex_unlock(&tty_mutex);
+               if (!current->signal->tty) {
+                       up(&tty_sem);
                        return -ENXIO;
                }
-               driver = tty->driver;
-               index = tty->index;
+               driver = current->signal->tty->driver;
+               index = current->signal->tty->index;
                filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */
                /* noctty = 1; */
                goto got_driver;
@@ -2502,18 +2071,18 @@ retry_open:
                        noctty = 1;
                        goto got_driver;
                }
-               mutex_unlock(&tty_mutex);
+               up(&tty_sem);
                return -ENODEV;
        }
 
        driver = get_tty_driver(device, &index);
        if (!driver) {
-               mutex_unlock(&tty_mutex);
+               up(&tty_sem);
                return -ENODEV;
        }
 got_driver:
        retval = init_dev(driver, index, &tty);
-       mutex_unlock(&tty_mutex);
+       up(&tty_sem);
        if (retval)
                return retval;
 
@@ -2555,32 +2124,21 @@ got_driver:
                        filp->f_op = &tty_fops;
                goto retry_open;
        }
-
-       mutex_lock(&tty_mutex);
-       spin_lock_irq(&current->sighand->siglock);
        if (!noctty &&
            current->signal->leader &&
            !current->signal->tty &&
-           tty->session == 0)
-               __proc_set_tty(current, tty);
-       spin_unlock_irq(&current->sighand->siglock);
-       mutex_unlock(&tty_mutex);
+           tty->session == 0) {
+               task_lock(current);
+               current->signal->tty = tty;
+               task_unlock(current);
+               current->signal->tty_old_pgrp = 0;
+               tty->session = current->signal->session;
+               tty->pgrp = process_group(current);
+       }
        return 0;
 }
 
 #ifdef CONFIG_UNIX98_PTYS
-/**
- *     ptmx_open               -       open a unix 98 pty master
- *     @inode: inode of device file
- *     @filp: file pointer to tty
- *
- *     Allocate a unix98 pty master device from the ptmx driver.
- *
- *     Locking: tty_mutex protects theinit_dev work. tty->count should
-               protect the rest.
- *             allocated_ptys_lock handles the list of free pty numbers
- */
-
 static int ptmx_open(struct inode * inode, struct file * filp)
 {
        struct tty_struct *tty;
@@ -2610,9 +2168,9 @@ static int ptmx_open(struct inode * inode, struct file * filp)
        }
        up(&allocated_ptys_lock);
 
-       mutex_lock(&tty_mutex);
+       down(&tty_sem);
        retval = init_dev(ptm_driver, index, &tty);
-       mutex_unlock(&tty_mutex);
+       up(&tty_sem);
        
        if (retval)
                goto out;
@@ -2631,7 +2189,6 @@ static int ptmx_open(struct inode * inode, struct file * filp)
                return 0;
 out1:
        release_dev(filp);
-       return retval;
 out:
        down(&allocated_ptys_lock);
        idr_remove(&allocated_ptys, index);
@@ -2640,18 +2197,6 @@ out:
 }
 #endif
 
-/**
- *     tty_release             -       vfs callback for close
- *     @inode: inode of tty
- *     @filp: file pointer for handle to tty
- *
- *     Called the last time each file handle is closed that references
- *     this tty. There may however be several such references.
- *
- *     Locking:
- *             Takes bkl. See release_dev
- */
-
 static int tty_release(struct inode * inode, struct file * filp)
 {
        lock_kernel();
@@ -2660,18 +2205,7 @@ static int tty_release(struct inode * inode, struct file * filp)
        return 0;
 }
 
-/**
- *     tty_poll        -       check tty status
- *     @filp: file being polled
- *     @wait: poll wait structures to update
- *
- *     Call the line discipline polling method to obtain the poll
- *     status of the device.
- *
- *     Locking: locks called line discipline but ldisc poll method
- *     may be re-entered freely by other callers.
- */
-
+/* No kernel lock held - fine */
 static unsigned int tty_poll(struct file * filp, poll_table * wait)
 {
        struct tty_struct * tty;
@@ -2715,23 +2249,6 @@ static int tty_fasync(int fd, struct file * filp, int on)
        return 0;
 }
 
-/**
- *     tiocsti                 -       fake input character
- *     @tty: tty to fake input into
- *     @p: pointer to character
- *
- *     Fake input to a tty device. Does the neccessary locking and
- *     input management.
- *
- *     FIXME: does not honour flow control ??
- *
- *     Locking:
- *             Called functions take tty_ldisc_lock
- *             current->signal->tty check is safe without locks
- *
- *     FIXME: may race normal receive processing
- */
-
 static int tiocsti(struct tty_struct *tty, char __user *p)
 {
        char ch, mbz = 0;
@@ -2747,45 +2264,13 @@ static int tiocsti(struct tty_struct *tty, char __user *p)
        return 0;
 }
 
-/**
- *     tiocgwinsz              -       implement window query ioctl
- *     @tty; tty
- *     @arg: user buffer for result
- *
- *     Copies the kernel idea of the window size into the user buffer.
- *
- *     Locking: tty->termios_mutex is taken to ensure the winsize data
- *             is consistent.
- */
-
 static int tiocgwinsz(struct tty_struct *tty, struct winsize __user * arg)
 {
-       int err;
-
-       mutex_lock(&tty->termios_mutex);
-       err = copy_to_user(arg, &tty->winsize, sizeof(*arg));
-       mutex_unlock(&tty->termios_mutex);
-
-       return err ? -EFAULT: 0;
+       if (copy_to_user(arg, &tty->winsize, sizeof(*arg)))
+               return -EFAULT;
+       return 0;
 }
 
-/**
- *     tiocswinsz              -       implement window size set ioctl
- *     @tty; tty
- *     @arg: user buffer for result
- *
- *     Copies the user idea of the window size to the kernel. Traditionally
- *     this is just advisory information but for the Linux console it
- *     actually has driver level meaning and triggers a VC resize.
- *
- *     Locking:
- *             Called function use the console_sem is used to ensure we do
- *     not try and resize the console twice at once.
- *             The tty->termios_mutex is used to ensure we don't double
- *     resize and get confused. Lock order - tty->termios_mutex before
- *     console sem
- */
-
 static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty,
        struct winsize __user * arg)
 {
@@ -2793,18 +2278,17 @@ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty,
 
        if (copy_from_user(&tmp_ws, arg, sizeof(*arg)))
                return -EFAULT;
-
-       mutex_lock(&tty->termios_mutex);
        if (!memcmp(&tmp_ws, &tty->winsize, sizeof(*arg)))
-               goto done;
-
+               return 0;
 #ifdef CONFIG_VT
        if (tty->driver->type == TTY_DRIVER_TYPE_CONSOLE) {
-               if (vc_lock_resize(tty->driver_data, tmp_ws.ws_col,
-                                       tmp_ws.ws_row)) {
-                       mutex_unlock(&tty->termios_mutex);
-                       return -ENXIO;
-               }
+               int rc;
+
+               acquire_console_sem();
+               rc = vc_resize(tty->driver_data, tmp_ws.ws_col, tmp_ws.ws_row);
+               release_console_sem();
+               if (rc)
+                       return -ENXIO;
        }
 #endif
        if (tty->pgrp > 0)
@@ -2813,20 +2297,9 @@ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty,
                kill_pg(real_tty->pgrp, SIGWINCH, 1);
        tty->winsize = tmp_ws;
        real_tty->winsize = tmp_ws;
-done:
-       mutex_unlock(&tty->termios_mutex);
        return 0;
 }
 
-/**
- *     tioccons        -       allow admin to move logical console
- *     @file: the file to become console
- *
- *     Allow the adminstrator to move the redirected console device
- *
- *     Locking: uses redirect_lock to guard the redirect information
- */
-
 static int tioccons(struct file *file)
 {
        if (!capable(CAP_SYS_ADMIN))
@@ -2852,17 +2325,6 @@ static int tioccons(struct file *file)
        return 0;
 }
 
-/**
- *     fionbio         -       non blocking ioctl
- *     @file: file to set blocking value
- *     @p: user parameter
- *
- *     Historical tty interfaces had a blocking control ioctl before
- *     the generic functionality existed. This piece of history is preserved
- *     in the expected tty API of posix OS's.
- *
- *     Locking: none, the open fle handle ensures it won't go away.
- */
 
 static int fionbio(struct file *file, int __user *p)
 {
@@ -2878,37 +2340,19 @@ static int fionbio(struct file *file, int __user *p)
        return 0;
 }
 
-/**
- *     tiocsctty       -       set controlling tty
- *     @tty: tty structure
- *     @arg: user argument
- *
- *     This ioctl is used to manage job control. It permits a session
- *     leader to set this tty as the controlling tty for the session.
- *
- *     Locking:
- *             Takes tty_mutex() to protect tty instance
- *             Takes tasklist_lock internally to walk sessions
- *             Takes ->siglock() when updating signal->tty
- */
-
 static int tiocsctty(struct tty_struct *tty, int arg)
 {
-       int ret = 0;
+       task_t *p;
+
        if (current->signal->leader &&
            (current->signal->session == tty->session))
-               return ret;
-
-       mutex_lock(&tty_mutex);
+               return 0;
        /*
         * The process must be a session leader and
         * not have a controlling tty already.
         */
-       if (!current->signal->leader || current->signal->tty) {
-               ret = -EPERM;
-               goto unlock;
-       }
-
+       if (!current->signal->leader || current->signal->tty)
+               return -EPERM;
        if (tty->session > 0) {
                /*
                 * This tty is already the controlling
@@ -2918,32 +2362,24 @@ static int tiocsctty(struct tty_struct *tty, int arg)
                        /*
                         * Steal it away
                         */
+
                        read_lock(&tasklist_lock);
-                       session_clear_tty(tty->session);
+                       do_each_task_pid(tty->session, PIDTYPE_SID, p) {
+                               p->signal->tty = NULL;
+                       } while_each_task_pid(tty->session, PIDTYPE_SID, p);
                        read_unlock(&tasklist_lock);
-               } else {
-                       ret = -EPERM;
-                       goto unlock;
-               }
+               } else
+                       return -EPERM;
        }
-       proc_set_tty(current, tty);
-unlock:
-       mutex_unlock(&tty_mutex);
-       return ret;
+       task_lock(current);
+       current->signal->tty = tty;
+       task_unlock(current);
+       current->signal->tty_old_pgrp = 0;
+       tty->session = current->signal->session;
+       tty->pgrp = process_group(current);
+       return 0;
 }
 
-/**
- *     tiocgpgrp               -       get process group
- *     @tty: tty passed by user
- *     @real_tty: tty side of the tty pased by the user if a pty else the tty
- *     @p: returned pid
- *
- *     Obtain the process group of the tty. If there is no process group
- *     return an error.
- *
- *     Locking: none. Reference to current->signal->tty is safe.
- */
-
 static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
 {
        pid_t pgrp;
@@ -2958,18 +2394,6 @@ static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t
        return put_user(pgrp, p);
 }
 
-/**
- *     tiocspgrp               -       attempt to set process group
- *     @tty: tty passed by user
- *     @real_tty: tty side device matching tty passed by user
- *     @p: pid pointer
- *
- *     Set the process group of the tty to the session passed. Only
- *     permitted where the tty session is our session.
- *
- *     Locking: None
- */
-
 static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
 {
        pid_t pgrp;
@@ -2995,18 +2419,6 @@ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t
        return 0;
 }
 
-/**
- *     tiocgsid                -       get session id
- *     @tty: tty passed by user
- *     @real_tty: tty side of the tty pased by the user if a pty else the tty
- *     @p: pointer to returned session id
- *
- *     Obtain the session id of the tty. If there is no session
- *     return an error.
- *
- *     Locking: none. Reference to current->signal->tty is safe.
- */
-
 static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
 {
        /*
@@ -3020,16 +2432,6 @@ static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t _
        return put_user(real_tty->session, p);
 }
 
-/**
- *     tiocsetd        -       set line discipline
- *     @tty: tty device
- *     @p: pointer to user data
- *
- *     Set the line discipline according to user request.
- *
- *     Locking: see tty_set_ldisc, this function is just a helper
- */
-
 static int tiocsetd(struct tty_struct *tty, int __user *p)
 {
        int ldisc;
@@ -3039,47 +2441,20 @@ static int tiocsetd(struct tty_struct *tty, int __user *p)
        return tty_set_ldisc(tty, ldisc);
 }
 
-/**
- *     send_break      -       performed time break
- *     @tty: device to break on
- *     @duration: timeout in mS
- *
- *     Perform a timed break on hardware that lacks its own driver level
- *     timed break functionality.
- *
- *     Locking:
- *             atomic_write_lock serializes
- *
- */
-
 static int send_break(struct tty_struct *tty, unsigned int duration)
 {
-       if (mutex_lock_interruptible(&tty->atomic_write_lock))
-               return -EINTR;
        tty->driver->break_ctl(tty, -1);
        if (!signal_pending(current)) {
                msleep_interruptible(duration);
        }
        tty->driver->break_ctl(tty, 0);
-       mutex_unlock(&tty->atomic_write_lock);
        if (signal_pending(current))
                return -EINTR;
        return 0;
 }
 
-/**
- *     tiocmget                -       get modem status
- *     @tty: tty device
- *     @file: user file pointer
- *     @p: pointer to result
- *
- *     Obtain the modem status bits from the tty driver if the feature
- *     is supported. Return -EINVAL if it is not available.
- *
- *     Locking: none (up to the driver)
- */
-
-static int tty_tiocmget(struct tty_struct *tty, struct file *file, int __user *p)
+static int
+tty_tiocmget(struct tty_struct *tty, struct file *file, int __user *p)
 {
        int retval = -EINVAL;
 
@@ -3092,20 +2467,8 @@ static int tty_tiocmget(struct tty_struct *tty, struct file *file, int __user *p
        return retval;
 }
 
-/**
- *     tiocmset                -       set modem status
- *     @tty: tty device
- *     @file: user file pointer
- *     @cmd: command - clear bits, set bits or set all
- *     @p: pointer to desired bits
- *
- *     Set the modem status bits from the tty driver if the feature
- *     is supported. Return -EINVAL if it is not available.
- *
- *     Locking: none (up to the driver)
- */
-
-static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int cmd,
+static int
+tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int cmd,
             unsigned __user *p)
 {
        int retval = -EINVAL;
@@ -3154,8 +2517,6 @@ int tty_ioctl(struct inode * inode, struct file * file,
        if (tty_paranoia_check(tty, inode, "tty_ioctl"))
                return -EINVAL;
 
-       /* CHECKME: is this safe as one end closes ? */
-
        real_tty = tty;
        if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
            tty->driver->subtype == PTY_TYPE_MASTER)
@@ -3227,7 +2588,9 @@ int tty_ioctl(struct inode * inode, struct file * file,
                                return -ENOTTY;
                        if (current->signal->leader)
                                disassociate_ctty(0);
-                       proc_clear_tty(current);
+                       task_lock(current);
+                       current->signal->tty = NULL;
+                       task_unlock(current);
                        return 0;
                case TIOCSCTTY:
                        return tiocsctty(tty, arg);
@@ -3257,9 +2620,10 @@ int tty_ioctl(struct inode * inode, struct file * file,
                        tty->driver->break_ctl(tty, 0);
                        return 0;
                case TCSBRK:   /* SVID version: non-zero arg --> no break */
-                       /* non-zero arg means wait for all output data
-                        * to be sent (performed above) but don't send break.
-                        * This is used by the tcdrain() termios function.
+                       /*
+                        * XXX is the above comment correct, or the
+                        * code below correct?  Is this ioctl used at
+                        * all by anyone?
                         */
                        if (!arg)
                                return send_break(tty, 250);
@@ -3317,7 +2681,7 @@ static void __do_SAK(void *arg)
        tty_hangup(tty);
 #else
        struct tty_struct *tty = arg;
-       struct task_struct *g, *p;
+       struct task_struct *p;
        int session;
        int             i;
        struct file     *filp;
@@ -3326,7 +2690,7 @@ static void __do_SAK(void *arg)
        
        if (!tty)
                return;
-       session = tty->session;
+       session  = tty->session;
        
        /* We don't want an ldisc switch during this */
        disc = tty_ldisc_ref(tty);
@@ -3338,18 +2702,8 @@ static void __do_SAK(void *arg)
                tty->driver->flush_buffer(tty);
        
        read_lock(&tasklist_lock);
-       /* Kill the entire session */
        do_each_task_pid(session, PIDTYPE_SID, p) {
-               printk(KERN_NOTICE "SAK: killed process %d"
-                       " (%s): p->signal->session==tty->session\n",
-                       p->pid, p->comm);
-               send_sig(SIGKILL, p, 1);
-       } while_each_task_pid(session, PIDTYPE_SID, p);
-       /* Now kill any processes that happen to have the
-        * tty open.
-        */
-       do_each_thread(g, p) {
-               if (p->signal->tty == tty) {
+               if (p->signal->tty == tty || session > 0) {
                        printk(KERN_NOTICE "SAK: killed process %d"
                            " (%s): p->signal->session==tty->session\n",
                            p->pid, p->comm);
@@ -3373,14 +2727,14 @@ static void __do_SAK(void *arg)
                                        printk(KERN_NOTICE "SAK: killed process %d"
                                            " (%s): fd#%d opened to the tty\n",
                                            p->pid, p->comm, i);
-                                       force_sig(SIGKILL, p);
+                                       send_sig(SIGKILL, p, 1);
                                        break;
                                }
                        }
                        spin_unlock(&p->files->file_lock);
                }
                task_unlock(p);
-       } while_each_thread(g, p);
+       } while_each_task_pid(session, PIDTYPE_SID, p);
        read_unlock(&tasklist_lock);
 #endif
 }
@@ -3401,16 +2755,9 @@ void do_SAK(struct tty_struct *tty)
 
 EXPORT_SYMBOL(do_SAK);
 
-/**
- *     flush_to_ldisc
- *     @private_: tty structure passed from work queue.
- *
- *     This routine is called out of the software interrupt to flush data
- *     from the buffer chain to the line discipline.
- *
- *     Locking: holds tty->buf.lock to guard buffer list. Drops the lock
- *     while invoking the line discipline receive_buf method. The
- *     receive_buf method is single threaded for each tty instance.
+/*
+ * This routine is called out of the software interrupt to flush data
+ * from the buffer chain to the line discipline.
  */
  
 static void flush_to_ldisc(void *private_)
@@ -3419,6 +2766,7 @@ static void flush_to_ldisc(void *private_)
        unsigned long   flags;
        struct tty_ldisc *disc;
        struct tty_buffer *tbuf, *head;
+       int count;
        char *char_buf;
        unsigned char *flag_buf;
 
@@ -3426,37 +2774,36 @@ static void flush_to_ldisc(void *private_)
        if (disc == NULL)       /*  !TTY_LDISC */
                return;
 
+       if (test_bit(TTY_DONT_FLIP, &tty->flags)) {
+               /*
+                * Do it after the next timer tick:
+                */
+               schedule_delayed_work(&tty->buf.work, 1);
+               goto out;
+       }
        spin_lock_irqsave(&tty->buf.lock, flags);
        head = tty->buf.head;
-       if (head != NULL) {
-               tty->buf.head = NULL;
-               for (;;) {
-                       int count = head->commit - head->read;
-                       if (!count) {
-                               if (head->next == NULL)
-                                       break;
-                               tbuf = head;
-                               head = head->next;
-                               tty_buffer_free(tty, tbuf);
-                               continue;
-                       }
-                       if (!tty->receive_room) {
-                               schedule_delayed_work(&tty->buf.work, 1);
-                               break;
-                       }
-                       if (count > tty->receive_room)
-                               count = tty->receive_room;
-                       char_buf = head->char_buf_ptr + head->read;
-                       flag_buf = head->flag_buf_ptr + head->read;
-                       head->read += count;
+       tty->buf.head = NULL;
+       while((tbuf = head) != NULL) {
+               while ((count = tbuf->commit - tbuf->read) != 0) {
+                       char_buf = tbuf->char_buf_ptr + tbuf->read;
+                       flag_buf = tbuf->flag_buf_ptr + tbuf->read;
+                       tbuf->read += count;
                        spin_unlock_irqrestore(&tty->buf.lock, flags);
                        disc->receive_buf(tty, char_buf, flag_buf, count);
                        spin_lock_irqsave(&tty->buf.lock, flags);
                }
-               tty->buf.head = head;
+               if (tbuf->active) {
+                       tty->buf.head = head;
+                       break;
+               }
+               head = tbuf->next;
+               if (head == NULL)
+                       tty->buf.tail = NULL;
+               tty_buffer_free(tty, tbuf);
        }
        spin_unlock_irqrestore(&tty->buf.lock, flags);
-
+out:
        tty_ldisc_deref(disc);
 }
 
@@ -3486,8 +2833,6 @@ static int n_baud_table = ARRAY_SIZE(baud_table);
  *     Convert termios baud rate data into a speed. This should be called
  *     with the termios lock held if this termios is a terminal termios
  *     structure. May change the termios data.
- *
- *     Locking: none
  */
  
 int tty_termios_baud_rate(struct termios *termios)
@@ -3516,8 +2861,6 @@ EXPORT_SYMBOL(tty_termios_baud_rate);
  *     Returns the baud rate as an integer for this terminal. The
  *     termios lock must be held by the caller and the terminal bit
  *     flags may be updated.
- *
- *     Locking: none
  */
  
 int tty_get_baud_rate(struct tty_struct *tty)
@@ -3547,16 +2890,16 @@ EXPORT_SYMBOL(tty_get_baud_rate);
  *
  *     In the event of the queue being busy for flipping the work will be
  *     held off and retried later.
- *
- *     Locking: tty buffer lock. Driver locks in low latency mode.
  */
 
 void tty_flip_buffer_push(struct tty_struct *tty)
 {
        unsigned long flags;
        spin_lock_irqsave(&tty->buf.lock, flags);
-       if (tty->buf.tail != NULL)
+       if (tty->buf.tail != NULL) {
+               tty->buf.tail->active = 0;
                tty->buf.tail->commit = tty->buf.tail->used;
+       }
        spin_unlock_irqrestore(&tty->buf.lock, flags);
 
        if (tty->low_latency)
@@ -3568,16 +2911,9 @@ void tty_flip_buffer_push(struct tty_struct *tty)
 EXPORT_SYMBOL(tty_flip_buffer_push);
 
 
-/**
- *     initialize_tty_struct
- *     @tty: tty to initialize
- *
- *     This subroutine initializes a tty structure that has been newly
- *     allocated.
- *
- *     Locking: none - tty in question must not be exposed at this point
+/*
+ * This subroutine initializes a tty structure.
  */
-
 static void initialize_tty_struct(struct tty_struct *tty)
 {
        memset(tty, 0, sizeof(struct tty_struct));
@@ -3589,12 +2925,12 @@ static void initialize_tty_struct(struct tty_struct *tty)
        tty_buffer_init(tty);
        INIT_WORK(&tty->buf.work, flush_to_ldisc, tty);
        init_MUTEX(&tty->buf.pty_sem);
-       mutex_init(&tty->termios_mutex);
+       init_MUTEX(&tty->termios_sem);
        init_waitqueue_head(&tty->write_wait);
        init_waitqueue_head(&tty->read_wait);
        INIT_WORK(&tty->hangup_work, do_tty_hangup, tty);
-       mutex_init(&tty->atomic_read_lock);
-       mutex_init(&tty->atomic_write_lock);
+       sema_init(&tty->atomic_read, 1);
+       sema_init(&tty->atomic_write, 1);
        spin_lock_init(&tty->read_lock);
        INIT_LIST_HEAD(&tty->tty_files);
        INIT_WORK(&tty->SAK_work, NULL, NULL);
@@ -3603,7 +2939,6 @@ static void initialize_tty_struct(struct tty_struct *tty)
 /*
  * The default put_char routine if the driver did not define one.
  */
-
 static void tty_default_put_char(struct tty_struct *tty, unsigned char ch)
 {
        tty->driver->write(tty, &ch, 1);
@@ -3612,25 +2947,19 @@ static void tty_default_put_char(struct tty_struct *tty, unsigned char ch)
 static struct class *tty_class;
 
 /**
- *     tty_register_device - register a tty device
- *     @driver: the tty driver that describes the tty device
- *     @index: the index in the tty driver for this tty device
- *     @device: a struct device that is associated with this tty device.
- *             This field is optional, if there is no known struct device
- *             for this tty device it can be set to NULL safely.
+ * tty_register_device - register a tty device
+ * @driver: the tty driver that describes the tty device
+ * @index: the index in the tty driver for this tty device
+ * @device: a struct device that is associated with this tty device.
+ *     This field is optional, if there is no known struct device for this
+ *     tty device it can be set to NULL safely.
  *
- *     Returns a pointer to the class device (or ERR_PTR(-EFOO) on error).
- *
- *     This call is required to be made to register an individual tty device
- *     if the tty driver's flags have the TTY_DRIVER_DYNAMIC_DEV bit set.  If
- *     that bit is not set, this function should not be called by a tty
- *     driver.
- *
- *     Locking: ??
+ * This call is required to be made to register an individual tty device if
+ * the tty driver's flags have the TTY_DRIVER_NO_DEVFS bit set.  If that
+ * bit is not set, this function should not be called.
  */
-
-struct class_device *tty_register_device(struct tty_driver *driver,
-                                        unsigned index, struct device *device)
+void tty_register_device(struct tty_driver *driver, unsigned index,
+                        struct device *device)
 {
        char name[64];
        dev_t dev = MKDEV(driver->major, driver->minor_start) + index;
@@ -3638,30 +2967,30 @@ struct class_device *tty_register_device(struct tty_driver *driver,
        if (index >= driver->num) {
                printk(KERN_ERR "Attempt to register invalid tty line number "
                       " (%d).\n", index);
-               return ERR_PTR(-EINVAL);
+               return;
        }
 
+       devfs_mk_cdev(dev, S_IFCHR | S_IRUSR | S_IWUSR,
+                       "%s%d", driver->devfs_name, index + driver->name_base);
+
        if (driver->type == TTY_DRIVER_TYPE_PTY)
                pty_line_name(driver, index, name);
        else
                tty_line_name(driver, index, name);
-
-       return class_device_create(tty_class, NULL, dev, device, "%s", name);
+       class_device_create(tty_class, NULL, dev, device, "%s", name);
 }
 
 /**
- *     tty_unregister_device - unregister a tty device
- *     @driver: the tty driver that describes the tty device
- *     @index: the index in the tty driver for this tty device
+ * tty_unregister_device - unregister a tty device
+ * @driver: the tty driver that describes the tty device
+ * @index: the index in the tty driver for this tty device
  *
- *     If a tty device is registered with a call to tty_register_device() then
- *     this function must be called when the tty device is gone.
- *
- *     Locking: ??
+ * If a tty device is registered with a call to tty_register_device() then
+ * this function must be made when the tty device is gone.
  */
-
 void tty_unregister_device(struct tty_driver *driver, unsigned index)
 {
+       devfs_remove("%s%d", driver->devfs_name, index + driver->name_base);
        class_device_destroy(tty_class, MKDEV(driver->major, driver->minor_start) + index);
 }
 
@@ -3770,6 +3099,7 @@ int tty_register_driver(struct tty_driver *driver)
        driver->cdev.owner = driver->owner;
        error = cdev_add(&driver->cdev, dev, driver->num);
        if (error) {
+               cdev_del(&driver->cdev);
                unregister_chrdev_region(dev, driver->num);
                driver->ttys = NULL;
                driver->termios = driver->termios_locked = NULL;
@@ -3782,7 +3112,7 @@ int tty_register_driver(struct tty_driver *driver)
        
        list_add(&driver->tty_drivers, &tty_drivers);
        
-       if ( !(driver->flags & TTY_DRIVER_DYNAMIC_DEV) ) {
+       if ( !(driver->flags & TTY_DRIVER_NO_DEVFS) ) {
                for(i = 0; i < driver->num; i++)
                    tty_register_device(driver, i, NULL);
        }
@@ -3825,7 +3155,7 @@ int tty_unregister_driver(struct tty_driver *driver)
                        driver->termios_locked[i] = NULL;
                        kfree(tp);
                }
-               if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV))
+               if (!(driver->flags & TTY_DRIVER_NO_DEVFS))
                        tty_unregister_device(driver, i);
        }
        p = driver->ttys;
@@ -3901,12 +3231,14 @@ static int __init tty_init(void)
        if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) ||
            register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0)
                panic("Couldn't register /dev/tty driver\n");
+       devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 0), S_IFCHR|S_IRUGO|S_IWUGO, "tty");
        class_device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL, "tty");
 
        cdev_init(&console_cdev, &console_fops);
        if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) ||
            register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0)
                panic("Couldn't register /dev/console driver\n");
+       devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 1), S_IFCHR|S_IRUSR|S_IWUSR, "console");
        class_device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL, "console");
 
 #ifdef CONFIG_UNIX98_PTYS
@@ -3914,6 +3246,7 @@ static int __init tty_init(void)
        if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) ||
            register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0)
                panic("Couldn't register /dev/ptmx driver\n");
+       devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 2), S_IFCHR|S_IRUGO|S_IWUGO, "ptmx");
        class_device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx");
 #endif
 
@@ -3922,10 +3255,10 @@ static int __init tty_init(void)
        if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) ||
            register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0)
                panic("Couldn't register /dev/tty0 driver\n");
+       devfs_mk_cdev(MKDEV(TTY_MAJOR, 0), S_IFCHR|S_IRUSR|S_IWUSR, "vc/0");
        class_device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0");
 
        vty_init();
- out_vt:
 #endif
        return 0;
 }