tty: Ldisc revamp
authorAlan Cox <alan@redhat.com>
Wed, 16 Jul 2008 20:53:12 +0000 (21:53 +0100)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 21 Jul 2008 00:12:34 +0000 (17:12 -0700)
Move the line disciplines towards a conventional ->ops arrangement.  For
the moment the actual 'tty_ldisc' struct in the tty is kept as part of
the tty struct but this can then be changed if it turns out that when it
all settles down we want to refcount ldiscs separately to the tty.

Pull the ldisc code out of /proc and put it with our ldisc code.

Signed-off-by: Alan Cox <alan@redhat.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
32 files changed:
drivers/bluetooth/hci_ldisc.c
drivers/char/cyclades.c
drivers/char/epca.c
drivers/char/ip2/i2lib.c
drivers/char/ip2/ip2main.c
drivers/char/n_hdlc.c
drivers/char/n_r3964.c
drivers/char/n_tty.c
drivers/char/pcmcia/synclink_cs.c
drivers/char/pty.c
drivers/char/selection.c
drivers/char/synclink.c
drivers/char/synclink_gt.c
drivers/char/synclinkmp.c
drivers/char/tty_io.c
drivers/char/tty_ioctl.c
drivers/input/serio/serport.c
drivers/isdn/capi/capi.c
drivers/isdn/gigaset/ser-gigaset.c
drivers/net/hamradio/6pack.c
drivers/net/hamradio/mkiss.c
drivers/net/irda/irtty-sir.c
drivers/net/ppp_async.c
drivers/net/ppp_synctty.c
drivers/net/slip.c
drivers/net/wan/pc300_tty.c
drivers/net/wan/x25_asy.c
fs/proc/proc_tty.c
include/linux/tty.h
include/linux/tty_ldisc.h
net/bluetooth/rfcomm/tty.c
net/irda/ircomm/ircomm_tty.c

index e5cd856a2fea9cce67404059f0e52d8a82ac5d2c..69df187d74ced8d2d262309c203e071669089f3d 100644 (file)
@@ -282,8 +282,8 @@ static int hci_uart_tty_open(struct tty_struct *tty)
        /* FIXME: why is this needed. Note don't use ldisc_ref here as the
           open path is before the ldisc is referencable */
 
-       if (tty->ldisc.flush_buffer)
-               tty->ldisc.flush_buffer(tty);
+       if (tty->ldisc.ops->flush_buffer)
+               tty->ldisc.ops->flush_buffer(tty);
        tty_driver_flush_buffer(tty);
 
        return 0;
@@ -514,7 +514,7 @@ static unsigned int hci_uart_tty_poll(struct tty_struct *tty,
 
 static int __init hci_uart_init(void)
 {
-       static struct tty_ldisc hci_uart_ldisc;
+       static struct tty_ldisc_ops hci_uart_ldisc;
        int err;
 
        BT_INFO("HCI UART driver ver %s", VERSION);
index 6bff9d87dc5784289ef575962cfae3479287538e..a957dbcc5a463502f45ea3d10641e77e53c591de 100644 (file)
@@ -5246,7 +5246,8 @@ cyclades_get_proc_info(char *buf, char **start, off_t offset, int length,
                                        HZ, info->idle_stats.recv_bytes,
                                        (cur_jifs - info->idle_stats.recv_idle)/
                                        HZ, info->idle_stats.overruns,
-                                       (long)info->tty->ldisc.num);
+                                       /* FIXME: double check locking */
+                                       (long)info->tty->ldisc.ops->num);
                        else
                                size = sprintf(buf + len, "%3d %8lu %10lu %8lu "
                                        "%10lu %8lu %9lu %6ld\n",
index 60a4df7dac12ed9e073c29c991e97178d42c7e1b..aa8e19f44b45e028fbaa454de2af218e9f3542d2 100644 (file)
@@ -2262,8 +2262,8 @@ static int pc_ioctl(struct tty_struct *tty, struct file *file,
                        tty_wait_until_sent(tty, 0);
                } else {
                        /* ldisc lock already held in ioctl */
-                       if (tty->ldisc.flush_buffer)
-                               tty->ldisc.flush_buffer(tty);
+                       if (tty->ldisc.ops->flush_buffer)
+                               tty->ldisc.ops->flush_buffer(tty);
                }
                unlock_kernel();
                /* Fall Thru */
index 938879cc7bccc66e394a32c034a45fcb0c79be27..0061e18aff6045624e6fad0eaaa804f8f9d951e2 100644 (file)
@@ -868,11 +868,11 @@ i2Input(i2ChanStrPtr pCh)
                amountToMove = count;
        }
        // Move the first block
-       pCh->pTTY->ldisc.receive_buf( pCh->pTTY, 
+       pCh->pTTY->ldisc.ops->receive_buf( pCh->pTTY,
                 &(pCh->Ibuf[stripIndex]), NULL, amountToMove );
        // If we needed to wrap, do the second data move
        if (count > amountToMove) {
-               pCh->pTTY->ldisc.receive_buf( pCh->pTTY, 
+               pCh->pTTY->ldisc.ops->receive_buf( pCh->pTTY,
                 pCh->Ibuf, NULL, count - amountToMove );
        }
        // Bump and wrap the stripIndex all at once by the amount of data read. This
index 9a2394cda9430bb2da11e7e39a7ddac6054273e9..5dc74404058f6eb46941a4af8bad71dfe3a5229e 100644 (file)
@@ -1289,11 +1289,12 @@ static void do_input(struct work_struct *work)
 // code duplicated from n_tty (ldisc)
 static inline void  isig(int sig, struct tty_struct *tty, int flush)
 {
+       /* FIXME: This is completely bogus */
        if (tty->pgrp)
                kill_pgrp(tty->pgrp, sig, 1);
        if (flush || !L_NOFLSH(tty)) {
-               if ( tty->ldisc.flush_buffer )  
-                       tty->ldisc.flush_buffer(tty);
+               if ( tty->ldisc.ops->flush_buffer )  
+                       tty->ldisc.ops->flush_buffer(tty);
                i2InputFlush( tty->driver_data );
        }
 }
@@ -1342,7 +1343,7 @@ static void do_status(struct work_struct *work)
                }
                tmp = pCh->pTTY->real_raw;
                pCh->pTTY->real_raw = 0;
-               pCh->pTTY->ldisc.receive_buf( pCh->pTTY, &brkc, &brkf, 1 );
+               pCh->pTTY->ldisc->ops.receive_buf( pCh->pTTY, &brkc, &brkf, 1 );
                pCh->pTTY->real_raw = tmp;
        }
 #endif /* NEVER_HAPPENS_AS_SETUP_XXX */
index a35bfd7ee80ecca131d37e8ea0798390ed5896d6..ed4e03333ab4646029f61236a554daa23a65a2df 100644 (file)
@@ -199,7 +199,7 @@ static void n_hdlc_tty_wakeup(struct tty_struct *tty);
 #define tty2n_hdlc(tty)        ((struct n_hdlc *) ((tty)->disc_data))
 #define n_hdlc2tty(n_hdlc)     ((n_hdlc)->tty)
 
-static struct tty_ldisc n_hdlc_ldisc = {
+static struct tty_ldisc_ops n_hdlc_ldisc = {
        .owner          = THIS_MODULE,
        .magic          = TTY_LDISC_MAGIC,
        .name           = "hdlc",
@@ -342,8 +342,8 @@ static int n_hdlc_tty_open (struct tty_struct *tty)
 #endif
        
        /* Flush any pending characters in the driver and discipline. */
-       if (tty->ldisc.flush_buffer)
-               tty->ldisc.flush_buffer(tty);
+       if (tty->ldisc.ops->flush_buffer)
+               tty->ldisc.ops->flush_buffer(tty);
 
        tty_driver_flush_buffer(tty);
                
index 902169062332483a8449a4f68b8c69756600b544..ae377aa473ba6fbe5644ac47866fd9637fc1499b 100644 (file)
@@ -143,7 +143,7 @@ static unsigned int r3964_poll(struct tty_struct *tty, struct file *file,
 static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
                char *fp, int count);
 
-static struct tty_ldisc tty_ldisc_N_R3964 = {
+static struct tty_ldisc_ops tty_ldisc_N_R3964 = {
        .owner = THIS_MODULE,
        .magic = TTY_LDISC_MAGIC,
        .name = "R3964",
index 8096389b0dc2d4bd07df5d9cfc902902a043b333..708c2b1dbe51068a5d1b91ba27d38d79d0c39308 100644 (file)
@@ -1573,7 +1573,7 @@ static unsigned int normal_poll(struct tty_struct *tty, struct file *file,
        return mask;
 }
 
-struct tty_ldisc tty_ldisc_N_TTY = {
+struct tty_ldisc_ops tty_ldisc_N_TTY = {
        .magic           = TTY_LDISC_MAGIC,
        .name            = "n_tty",
        .open            = n_tty_open,
index 1dd0e992c83d9ceddc777b3d6b6cc892e25044f8..95743e2682fea9b949d9cedf18eaa6512eb5ee7d 100644 (file)
@@ -514,8 +514,8 @@ static void ldisc_receive_buf(struct tty_struct *tty,
                return;
        ld = tty_ldisc_ref(tty);
        if (ld) {
-               if (ld->receive_buf)
-                       ld->receive_buf(tty, data, flags, count);
+               if (ld->ops->receive_buf)
+                       ld->ops->receive_buf(tty, data, flags, count);
                tty_ldisc_deref(ld);
        }
 }
index 0a05c038ae6f168236c0b5de08ddb79a9de4e45d..76b27932d229df31d3ff24f7d09e83afecdb278a 100644 (file)
@@ -111,7 +111,7 @@ static int pty_write(struct tty_struct * tty, const unsigned char *buf, int coun
        c = to->receive_room;
        if (c > count)
                c = count;
-       to->ldisc.receive_buf(to, buf, NULL, c);
+       to->ldisc.ops->receive_buf(to, buf, NULL, c);
        
        return c;
 }
@@ -149,11 +149,11 @@ static int pty_chars_in_buffer(struct tty_struct *tty)
        int count;
 
        /* We should get the line discipline lock for "tty->link" */
-       if (!to || !to->ldisc.chars_in_buffer)
+       if (!to || !to->ldisc.ops->chars_in_buffer)
                return 0;
 
        /* The ldisc must report 0 if no characters available to be read */
-       count = to->ldisc.chars_in_buffer(to);
+       count = to->ldisc.ops->chars_in_buffer(to);
 
        if (tty->driver->subtype == PTY_TYPE_SLAVE) return count;
 
@@ -186,8 +186,8 @@ static void pty_flush_buffer(struct tty_struct *tty)
        if (!to)
                return;
        
-       if (to->ldisc.flush_buffer)
-               to->ldisc.flush_buffer(to);
+       if (to->ldisc.ops->flush_buffer)
+               to->ldisc.ops->flush_buffer(to);
        
        if (to->packet) {
                spin_lock_irqsave(&tty->ctrl_lock, flags);
index d63f5ccc29e6de95f3141bc9a8df5444e6d94b19..2978a49a172b0cdba3d91814fd3b68b614645fea 100644 (file)
@@ -327,7 +327,8 @@ int paste_selection(struct tty_struct *tty)
                }
                count = sel_buffer_lth - pasted;
                count = min(count, tty->receive_room);
-               tty->ldisc.receive_buf(tty, sel_buffer + pasted, NULL, count);
+               tty->ldisc.ops->receive_buf(tty, sel_buffer + pasted,
+                                                               NULL, count);
                pasted += count;
        }
        remove_wait_queue(&vc->paste_wait, &wait);
index ac5080df2565aef4cd85e96a112d3cd3ffa7820f..5e4b2e638d0c25e50a8e2d6dd8e1b5d7e64a451a 100644 (file)
@@ -975,8 +975,8 @@ static void ldisc_receive_buf(struct tty_struct *tty,
                return;
        ld = tty_ldisc_ref(tty);
        if (ld) {
-               if (ld->receive_buf)
-                       ld->receive_buf(tty, data, flags, count);
+               if (ld->ops->receive_buf)
+                       ld->ops->receive_buf(tty, data, flags, count);
                tty_ldisc_deref(ld);
        }
 }
index 55c1653be00ca86f0f76051d940cfe7e5e933145..e473778cd6fadbadd1146a6fa4c16cf573c70225 100644 (file)
@@ -641,8 +641,8 @@ static void ldisc_receive_buf(struct tty_struct *tty,
                return;
        ld = tty_ldisc_ref(tty);
        if (ld) {
-               if (ld->receive_buf)
-                       ld->receive_buf(tty, data, flags, count);
+               if (ld->ops->receive_buf)
+                       ld->ops->receive_buf(tty, data, flags, count);
                tty_ldisc_deref(ld);
        }
 }
index bec54866e0bb6630b0f6d05f7890daf365695134..5341b5aaf8bc306ed2c87632add2ac542eaf13b2 100644 (file)
@@ -712,8 +712,8 @@ static void ldisc_receive_buf(struct tty_struct *tty,
                return;
        ld = tty_ldisc_ref(tty);
        if (ld) {
-               if (ld->receive_buf)
-                       ld->receive_buf(tty, data, flags, count);
+               if (ld->ops->receive_buf)
+                       ld->ops->receive_buf(tty, data, flags, count);
                tty_ldisc_deref(ld);
        }
 }
index 047a17339f835f1891dbd3db58371a9e25975f91..54c4ada460ee157910452a46735a8b44b83847c9 100644 (file)
@@ -95,8 +95,9 @@
 #include <linux/wait.h>
 #include <linux/bitops.h>
 #include <linux/delay.h>
+#include <linux/seq_file.h>
 
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 #include <asm/system.h>
 
 #include <linux/kbd_kern.h>
@@ -682,7 +683,7 @@ static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
 static DEFINE_SPINLOCK(tty_ldisc_lock);
 static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait);
 /* Line disc dispatch table */
-static struct tty_ldisc tty_ldiscs[NR_LDISCS];
+static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS];
 
 /**
  *     tty_register_ldisc      -       install a line discipline
@@ -697,7 +698,7 @@ static struct tty_ldisc tty_ldiscs[NR_LDISCS];
  *             takes tty_ldisc_lock to guard against ldisc races
  */
 
-int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc)
+int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc)
 {
        unsigned long flags;
        int ret = 0;
@@ -706,10 +707,9 @@ int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc)
                return -EINVAL;
 
        spin_lock_irqsave(&tty_ldisc_lock, flags);
-       tty_ldiscs[disc] = *new_ldisc;
-       tty_ldiscs[disc].num = disc;
-       tty_ldiscs[disc].flags |= LDISC_FLAG_DEFINED;
-       tty_ldiscs[disc].refcount = 0;
+       tty_ldiscs[disc] = new_ldisc;
+       new_ldisc->num = disc;
+       new_ldisc->refcount = 0;
        spin_unlock_irqrestore(&tty_ldisc_lock, flags);
 
        return ret;
@@ -737,19 +737,56 @@ int tty_unregister_ldisc(int disc)
                return -EINVAL;
 
        spin_lock_irqsave(&tty_ldisc_lock, flags);
-       if (tty_ldiscs[disc].refcount)
+       if (tty_ldiscs[disc]->refcount)
                ret = -EBUSY;
        else
-               tty_ldiscs[disc].flags &= ~LDISC_FLAG_DEFINED;
+               tty_ldiscs[disc] = NULL;
        spin_unlock_irqrestore(&tty_ldisc_lock, flags);
 
        return ret;
 }
 EXPORT_SYMBOL(tty_unregister_ldisc);
 
+
+/**
+ *     tty_ldisc_try_get       -       try and reference an ldisc
+ *     @disc: ldisc number
+ *     @ld: tty ldisc structure to complete
+ *
+ *     Attempt to open and lock a line discipline into place. Return
+ *     the line discipline refcounted and assigned in ld. On an error
+ *     report the error code back
+ */
+
+static int tty_ldisc_try_get(int disc, struct tty_ldisc *ld)
+{
+       unsigned long flags;
+       struct tty_ldisc_ops *ldops;
+       int err = -EINVAL;
+       
+       spin_lock_irqsave(&tty_ldisc_lock, flags);
+       ld->ops = NULL;
+       ldops = tty_ldiscs[disc];
+       /* Check the entry is defined */
+       if (ldops) {
+               /* If the module is being unloaded we can't use it */
+               if (!try_module_get(ldops->owner))
+                       err = -EAGAIN;
+               else {
+                       /* lock it */
+                       ldops->refcount++;
+                       ld->ops = ldops;
+                       err = 0;
+               }
+       }
+       spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+       return err;
+}
+
 /**
  *     tty_ldisc_get           -       take a reference to an ldisc
  *     @disc: ldisc number
+ *     @ld: tty line discipline structure to use
  *
  *     Takes a reference to a line discipline. Deals with refcounts and
  *     module locking counts. Returns NULL if the discipline is not available.
@@ -760,32 +797,20 @@ EXPORT_SYMBOL(tty_unregister_ldisc);
  *             takes tty_ldisc_lock to guard against ldisc races
  */
 
-struct tty_ldisc *tty_ldisc_get(int disc)
+static int tty_ldisc_get(int disc, struct tty_ldisc *ld)
 {
-       unsigned long flags;
-       struct tty_ldisc *ld;
+       int err;
 
        if (disc < N_TTY || disc >= NR_LDISCS)
-               return NULL;
-
-       spin_lock_irqsave(&tty_ldisc_lock, flags);
-
-       ld = &tty_ldiscs[disc];
-       /* Check the entry is defined */
-       if (ld->flags & LDISC_FLAG_DEFINED) {
-               /* If the module is being unloaded we can't use it */
-               if (!try_module_get(ld->owner))
-                       ld = NULL;
-               else /* lock it */
-                       ld->refcount++;
-       } else
-               ld = NULL;
-       spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-       return ld;
+               return -EINVAL;
+       err = tty_ldisc_try_get(disc, ld);
+       if (err == -EAGAIN) {
+               request_module("tty-ldisc-%d", disc);
+               err = tty_ldisc_try_get(disc, ld);
+       }
+       return err;
 }
 
-EXPORT_SYMBOL_GPL(tty_ldisc_get);
-
 /**
  *     tty_ldisc_put           -       drop ldisc reference
  *     @disc: ldisc number
@@ -797,22 +822,67 @@ EXPORT_SYMBOL_GPL(tty_ldisc_get);
  *             takes tty_ldisc_lock to guard against ldisc races
  */
 
-void tty_ldisc_put(int disc)
+static void tty_ldisc_put(struct tty_ldisc_ops *ld)
 {
-       struct tty_ldisc *ld;
        unsigned long flags;
+       int disc = ld->num;
 
        BUG_ON(disc < N_TTY || disc >= NR_LDISCS);
 
        spin_lock_irqsave(&tty_ldisc_lock, flags);
-       ld = &tty_ldiscs[disc];
+       ld = tty_ldiscs[disc];
        BUG_ON(ld->refcount == 0);
        ld->refcount--;
        module_put(ld->owner);
        spin_unlock_irqrestore(&tty_ldisc_lock, flags);
 }
 
-EXPORT_SYMBOL_GPL(tty_ldisc_put);
+static void * tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos)
+{
+       return (*pos < NR_LDISCS) ? pos : NULL;
+}
+
+static void * tty_ldiscs_seq_next(struct seq_file *m, void *v, loff_t *pos)
+{
+       (*pos)++;
+       return (*pos < NR_LDISCS) ? pos : NULL;
+}
+
+static void tty_ldiscs_seq_stop(struct seq_file *m, void *v)
+{
+}
+
+static int tty_ldiscs_seq_show(struct seq_file *m, void *v)
+{
+       int i = *(loff_t *)v;
+       struct tty_ldisc ld;
+       
+       if (tty_ldisc_get(i, &ld) < 0)
+               return 0;
+       seq_printf(m, "%-10s %2d\n", ld.ops->name ? ld.ops->name : "???", i);
+       tty_ldisc_put(ld.ops);
+       return 0;
+}
+
+static const struct seq_operations tty_ldiscs_seq_ops = {
+       .start  = tty_ldiscs_seq_start,
+       .next   = tty_ldiscs_seq_next,
+       .stop   = tty_ldiscs_seq_stop,
+       .show   = tty_ldiscs_seq_show,
+};
+
+static int proc_tty_ldiscs_open(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &tty_ldiscs_seq_ops);
+}
+
+const struct file_operations tty_ldiscs_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = proc_tty_ldiscs_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release,
+};
 
 /**
  *     tty_ldisc_assign        -       set ldisc on a tty
@@ -829,8 +899,8 @@ EXPORT_SYMBOL_GPL(tty_ldisc_put);
 
 static void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld)
 {
+       ld->refcount = 0;
        tty->ldisc = *ld;
-       tty->ldisc.refcount = 0;
 }
 
 /**
@@ -953,6 +1023,41 @@ static void tty_ldisc_enable(struct tty_struct *tty)
        wake_up(&tty_ldisc_wait);
 }
 
+/**
+ *     tty_ldisc_restore       -       helper for tty ldisc change
+ *     @tty: tty to recover
+ *     @old: previous ldisc
+ *
+ *     Restore the previous line discipline or N_TTY when a line discipline
+ *     change fails due to an open error
+ */
+
+static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
+{
+       char buf[64];
+       struct tty_ldisc new_ldisc;
+
+       /* There is an outstanding reference here so this is safe */
+       tty_ldisc_get(old->ops->num, old);
+       tty_ldisc_assign(tty, old);
+       tty_set_termios_ldisc(tty, old->ops->num);
+       if (old->ops->open && (old->ops->open(tty) < 0)) {
+               tty_ldisc_put(old->ops);
+               /* This driver is always present */
+               if (tty_ldisc_get(N_TTY, &new_ldisc) < 0)
+                       panic("n_tty: get");
+               tty_ldisc_assign(tty, &new_ldisc);
+               tty_set_termios_ldisc(tty, N_TTY);
+               if (new_ldisc.ops->open) {
+                       int r = new_ldisc.ops->open(tty);
+                               if (r < 0)
+                               panic("Couldn't open N_TTY ldisc for "
+                                     "%s --- error %d.",
+                                     tty_name(tty, buf), r);
+               }
+       }
+}
+
 /**
  *     tty_set_ldisc           -       set line discipline
  *     @tty: the terminal to set
@@ -967,28 +1072,18 @@ static void tty_ldisc_enable(struct tty_struct *tty)
 
 static int tty_set_ldisc(struct tty_struct *tty, int ldisc)
 {
-       int retval = 0;
-       struct tty_ldisc o_ldisc;
-       char buf[64];
+       int retval;
+       struct tty_ldisc o_ldisc, new_ldisc;
        int work;
        unsigned long flags;
-       struct tty_ldisc *ld;
        struct tty_struct *o_tty;
 
-       if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS))
-               return -EINVAL;
-
 restart:
-
-       ld = tty_ldisc_get(ldisc);
-       /* Eduardo Blanco <ejbs@cs.cs.com.uy> */
-       /* Cyrus Durgin <cider@speakeasy.org> */
-       if (ld == NULL) {
-               request_module("tty-ldisc-%d", ldisc);
-               ld = tty_ldisc_get(ldisc);
-       }
-       if (ld == NULL)
-               return -EINVAL;
+       /* This is a bit ugly for now but means we can break the 'ldisc
+          is part of the tty struct' assumption later */
+       retval = tty_ldisc_get(ldisc, &new_ldisc);
+       if (retval)
+               return retval;
 
        /*
         *      Problem: What do we do if this blocks ?
@@ -996,8 +1091,8 @@ restart:
 
        tty_wait_until_sent(tty, 0);
 
-       if (tty->ldisc.num == ldisc) {
-               tty_ldisc_put(ldisc);
+       if (tty->ldisc.ops->num == ldisc) {
+               tty_ldisc_put(new_ldisc.ops);
                return 0;
        }
 
@@ -1024,7 +1119,7 @@ restart:
                        /* Free the new ldisc we grabbed. Must drop the lock
                           first. */
                        spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-                       tty_ldisc_put(ldisc);
+                       tty_ldisc_put(o_ldisc.ops);
                        /*
                         * There are several reasons we may be busy, including
                         * random momentary I/O traffic. We must therefore
@@ -1038,7 +1133,7 @@ restart:
                }
                if (o_tty && o_tty->ldisc.refcount) {
                        spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-                       tty_ldisc_put(ldisc);
+                       tty_ldisc_put(o_tty->ldisc.ops);
                        if (wait_event_interruptible(tty_ldisc_wait, o_tty->ldisc.refcount == 0) < 0)
                                return -ERESTARTSYS;
                        goto restart;
@@ -1049,8 +1144,9 @@ restart:
         *      another ldisc change
         */
        if (!test_bit(TTY_LDISC, &tty->flags)) {
+               struct tty_ldisc *ld;
                spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-               tty_ldisc_put(ldisc);
+               tty_ldisc_put(new_ldisc.ops);
                ld = tty_ldisc_ref_wait(tty);
                tty_ldisc_deref(ld);
                goto restart;
@@ -1060,7 +1156,7 @@ restart:
        if (o_tty)
                clear_bit(TTY_LDISC, &o_tty->flags);
        spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-
+       
        /*
         *      From this point on we know nobody has an ldisc
         *      usage reference, nor can they obtain one until
@@ -1070,45 +1166,30 @@ restart:
        work = cancel_delayed_work(&tty->buf.work);
        /*
         * Wait for ->hangup_work and ->buf.work handlers to terminate
+        * MUST NOT hold locks here.
         */
        flush_scheduled_work();
        /* Shutdown the current discipline. */
-       if (tty->ldisc.close)
-               (tty->ldisc.close)(tty);
+       if (o_ldisc.ops->close)
+               (o_ldisc.ops->close)(tty);
 
        /* Now set up the new line discipline. */
-       tty_ldisc_assign(tty, ld);
+       tty_ldisc_assign(tty, &new_ldisc);
        tty_set_termios_ldisc(tty, ldisc);
-       if (tty->ldisc.open)
-               retval = (tty->ldisc.open)(tty);
+       if (new_ldisc.ops->open)
+               retval = (new_ldisc.ops->open)(tty);
        if (retval < 0) {
-               tty_ldisc_put(ldisc);
-               /* There is an outstanding reference here so this is safe */
-               tty_ldisc_assign(tty, tty_ldisc_get(o_ldisc.num));
-               tty_set_termios_ldisc(tty, tty->ldisc.num);
-               if (tty->ldisc.open && (tty->ldisc.open(tty) < 0)) {
-                       tty_ldisc_put(o_ldisc.num);
-                       /* This driver is always present */
-                       tty_ldisc_assign(tty, tty_ldisc_get(N_TTY));
-                       tty_set_termios_ldisc(tty, N_TTY);
-                       if (tty->ldisc.open) {
-                               int r = tty->ldisc.open(tty);
-
-                               if (r < 0)
-                                       panic("Couldn't open N_TTY ldisc for "
-                                             "%s --- error %d.",
-                                             tty_name(tty, buf), r);
-                       }
-               }
+               tty_ldisc_put(new_ldisc.ops);
+               tty_ldisc_restore(tty, &o_ldisc);
        }
        /* At this point we hold a reference to the new ldisc and a
           a reference to the old ldisc. If we ended up flipping back
           to the existing ldisc we have two references to it */
 
-       if (tty->ldisc.num != o_ldisc.num && tty->ops->set_ldisc)
+       if (tty->ldisc.ops->num != o_ldisc.ops->num && tty->ops->set_ldisc)
                tty->ops->set_ldisc(tty);
 
-       tty_ldisc_put(o_ldisc.num);
+       tty_ldisc_put(o_ldisc.ops);
 
        /*
         *      Allow ldisc referencing to occur as soon as the driver
@@ -1335,8 +1416,8 @@ void tty_wakeup(struct tty_struct *tty)
        if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) {
                ld = tty_ldisc_ref(tty);
                if (ld) {
-                       if (ld->write_wakeup)
-                               ld->write_wakeup(tty);
+                       if (ld->ops->write_wakeup)
+                               ld->ops->write_wakeup(tty);
                        tty_ldisc_deref(ld);
                }
        }
@@ -1357,8 +1438,8 @@ void tty_ldisc_flush(struct tty_struct *tty)
 {
        struct tty_ldisc *ld = tty_ldisc_ref(tty);
        if (ld) {
-               if (ld->flush_buffer)
-                       ld->flush_buffer(tty);
+               if (ld->ops->flush_buffer)
+                       ld->ops->flush_buffer(tty);
                tty_ldisc_deref(ld);
        }
        tty_buffer_flush(tty);
@@ -1386,7 +1467,7 @@ static void tty_reset_termios(struct tty_struct *tty)
  *     do_tty_hangup           -       actual handler for hangup events
  *     @work: tty device
  *
- *     This can be called by the "eventd" kernel thread.  That is process
+k *    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.
  *
@@ -1449,14 +1530,14 @@ static void do_tty_hangup(struct work_struct *work)
        ld = tty_ldisc_ref(tty);
        if (ld != NULL) {
                /* We may have no line discipline at this point */
-               if (ld->flush_buffer)
-                       ld->flush_buffer(tty);
+               if (ld->ops->flush_buffer)
+                       ld->ops->flush_buffer(tty);
                tty_driver_flush_buffer(tty);
                if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) &&
-                   ld->write_wakeup)
-                       ld->write_wakeup(tty);
-               if (ld->hangup)
-                       ld->hangup(tty);
+                   ld->ops->write_wakeup)
+                       ld->ops->write_wakeup(tty);
+               if (ld->ops->hangup)
+                       ld->ops->hangup(tty);
        }
        /*
         * FIXME: Once we trust the LDISC code better we can wait here for
@@ -1825,8 +1906,8 @@ static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
        /* We want to wait for the line discipline to sort out in this
           situation */
        ld = tty_ldisc_ref_wait(tty);
-       if (ld->read)
-               i = (ld->read)(tty, file, buf, count);
+       if (ld->ops->read)
+               i = (ld->ops->read)(tty, file, buf, count);
        else
                i = -EIO;
        tty_ldisc_deref(ld);
@@ -1978,10 +2059,10 @@ static ssize_t tty_write(struct file *file, const char __user *buf,
                printk(KERN_ERR "tty driver %s lacks a write_room method.\n",
                        tty->driver->name);
        ld = tty_ldisc_ref_wait(tty);
-       if (!ld->write)
+       if (!ld->ops->write)
                ret = -EIO;
        else
-               ret = do_tty_write(ld->write, tty, file, buf, count);
+               ret = do_tty_write(ld->ops->write, tty, file, buf, count);
        tty_ldisc_deref(ld);
        return ret;
 }
@@ -2076,6 +2157,7 @@ static int init_dev(struct tty_driver *driver, int idx,
        struct ktermios *tp, **tp_loc, *o_tp, **o_tp_loc;
        struct ktermios *ltp, **ltp_loc, *o_ltp, **o_ltp_loc;
        int retval = 0;
+       struct tty_ldisc *ld;
 
        /* check whether we're reopening an existing tty */
        if (driver->flags & TTY_DRIVER_DEVPTS_MEM) {
@@ -2224,17 +2306,19 @@ static int init_dev(struct tty_driver *driver, int idx,
         * If we fail here just call release_tty to clean up.  No need
         * to decrement the use counts, as release_tty doesn't care.
         */
+        
+       ld = &tty->ldisc;
 
-       if (tty->ldisc.open) {
-               retval = (tty->ldisc.open)(tty);
+       if (ld->ops->open) {
+               retval = (ld->ops->open)(tty);
                if (retval)
                        goto release_mem_out;
        }
-       if (o_tty && o_tty->ldisc.open) {
-               retval = (o_tty->ldisc.open)(o_tty);
+       if (o_tty && o_tty->ldisc.ops->open) {
+               retval = (o_tty->ldisc.ops->open)(o_tty);
                if (retval) {
-                       if (tty->ldisc.close)
-                               (tty->ldisc.close)(tty);
+                       if (ld->ops->close)
+                               (ld->ops->close)(tty);
                        goto release_mem_out;
                }
                tty_ldisc_enable(o_tty);
@@ -2378,6 +2462,7 @@ static void release_tty(struct tty_struct *tty, int idx)
 static void release_dev(struct file *filp)
 {
        struct tty_struct *tty, *o_tty;
+       struct tty_ldisc ld;
        int     pty_master, tty_closing, o_tty_closing, do_sleep;
        int     devpts;
        int     idx;
@@ -2611,26 +2696,27 @@ static void release_dev(struct file *filp)
        spin_unlock_irqrestore(&tty_ldisc_lock, flags);
        /*
         * Shutdown the current line discipline, and reset it to N_TTY.
-        * N.B. why reset ldisc when we're releasing the memory??
         *
         * FIXME: this MUST get fixed for the new reflocking
         */
-       if (tty->ldisc.close)
-               (tty->ldisc.close)(tty);
-       tty_ldisc_put(tty->ldisc.num);
+       if (tty->ldisc.ops->close)
+               (tty->ldisc.ops->close)(tty);
+       tty_ldisc_put(tty->ldisc.ops);
 
        /*
         *      Switch the line discipline back
         */
-       tty_ldisc_assign(tty, tty_ldisc_get(N_TTY));
+       WARN_ON(tty_ldisc_get(N_TTY, &ld));
+       tty_ldisc_assign(tty, &ld);
        tty_set_termios_ldisc(tty, N_TTY);
        if (o_tty) {
                /* FIXME: could o_tty be in setldisc here ? */
                clear_bit(TTY_LDISC, &o_tty->flags);
-               if (o_tty->ldisc.close)
-                       (o_tty->ldisc.close)(o_tty);
-               tty_ldisc_put(o_tty->ldisc.num);
-               tty_ldisc_assign(o_tty, tty_ldisc_get(N_TTY));
+               if (o_tty->ldisc.ops->close)
+                       (o_tty->ldisc.ops->close)(o_tty);
+               tty_ldisc_put(o_tty->ldisc.ops);
+               WARN_ON(tty_ldisc_get(N_TTY, &ld));
+               tty_ldisc_assign(o_tty, &ld);
                tty_set_termios_ldisc(o_tty, N_TTY);
        }
        /*
@@ -2899,8 +2985,8 @@ static unsigned int tty_poll(struct file *filp, poll_table *wait)
                return 0;
 
        ld = tty_ldisc_ref_wait(tty);
-       if (ld->poll)
-               ret = (ld->poll)(tty, filp, wait);
+       if (ld->ops->poll)
+               ret = (ld->ops->poll)(tty, filp, wait);
        tty_ldisc_deref(ld);
        return ret;
 }
@@ -2974,7 +3060,7 @@ static int tiocsti(struct tty_struct *tty, char __user *p)
        if (get_user(ch, p))
                return -EFAULT;
        ld = tty_ldisc_ref_wait(tty);
-       ld->receive_buf(tty, &ch, &mbz, 1);
+       ld->ops->receive_buf(tty, &ch, &mbz, 1);
        tty_ldisc_deref(ld);
        return 0;
 }
@@ -3528,7 +3614,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        case TIOCGSID:
                return tiocgsid(tty, real_tty, p);
        case TIOCGETD:
-               return put_user(tty->ldisc.num, (int __user *)p);
+               return put_user(tty->ldisc.ops->num, (int __user *)p);
        case TIOCSETD:
                return tiocsetd(tty, p);
 #ifdef CONFIG_VT
@@ -3581,8 +3667,8 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        }
        ld = tty_ldisc_ref_wait(tty);
        retval = -EINVAL;
-       if (ld->ioctl) {
-               retval = ld->ioctl(tty, file, cmd, arg);
+       if (ld->ops->ioctl) {
+               retval = ld->ops->ioctl(tty, file, cmd, arg);
                if (retval == -ENOIOCTLCMD)
                        retval = -EINVAL;
        }
@@ -3609,8 +3695,8 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd,
        }
 
        ld = tty_ldisc_ref_wait(tty);
-       if (ld->compat_ioctl)
-               retval = ld->compat_ioctl(tty, file, cmd, arg);
+       if (ld->ops->compat_ioctl)
+               retval = ld->ops->compat_ioctl(tty, file, cmd, arg);
        tty_ldisc_deref(ld);
 
        return retval;
@@ -3782,7 +3868,8 @@ static void flush_to_ldisc(struct work_struct *work)
                        flag_buf = head->flag_buf_ptr + head->read;
                        head->read += count;
                        spin_unlock_irqrestore(&tty->buf.lock, flags);
-                       disc->receive_buf(tty, char_buf, flag_buf, count);
+                       disc->ops->receive_buf(tty, char_buf,
+                                                       flag_buf, count);
                        spin_lock_irqsave(&tty->buf.lock, flags);
                }
                /* Restore the queue head */
@@ -3843,9 +3930,12 @@ EXPORT_SYMBOL(tty_flip_buffer_push);
 
 static void initialize_tty_struct(struct tty_struct *tty)
 {
+       struct tty_ldisc ld;
        memset(tty, 0, sizeof(struct tty_struct));
        tty->magic = TTY_MAGIC;
-       tty_ldisc_assign(tty, tty_ldisc_get(N_TTY));
+       if (tty_ldisc_get(N_TTY, &ld) < 0)
+               panic("n_tty: init_tty");
+       tty_ldisc_assign(tty, &ld);
        tty->session = NULL;
        tty->pgrp = NULL;
        tty->overrun_time = jiffies;
index 8f81139d61949b4f4300baaacb69e56e473a8a69..ea9fc5d03b991d924761a12a74b029546629d4a3 100644 (file)
@@ -491,8 +491,8 @@ static void change_termios(struct tty_struct *tty, struct ktermios *new_termios)
 
        ld = tty_ldisc_ref(tty);
        if (ld != NULL) {
-               if (ld->set_termios)
-                       (ld->set_termios)(tty, &old_termios);
+               if (ld->ops->set_termios)
+                       (ld->ops->set_termios)(tty, &old_termios);
                tty_ldisc_deref(ld);
        }
        mutex_unlock(&tty->termios_mutex);
@@ -552,8 +552,8 @@ static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
        ld = tty_ldisc_ref(tty);
 
        if (ld != NULL) {
-               if ((opt & TERMIOS_FLUSH) && ld->flush_buffer)
-                       ld->flush_buffer(tty);
+               if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
+                       ld->ops->flush_buffer(tty);
                tty_ldisc_deref(ld);
        }
 
@@ -959,12 +959,12 @@ int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
        ld = tty_ldisc_ref(tty);
        switch (arg) {
        case TCIFLUSH:
-               if (ld && ld->flush_buffer)
-                       ld->flush_buffer(tty);
+               if (ld && ld->ops->flush_buffer)
+                       ld->ops->flush_buffer(tty);
                break;
        case TCIOFLUSH:
-               if (ld && ld->flush_buffer)
-                       ld->flush_buffer(tty);
+               if (ld && ld->ops->flush_buffer)
+                       ld->ops->flush_buffer(tty);
                /* fall through */
        case TCOFLUSH:
                tty_driver_flush_buffer(tty);
index 7ff71ba7b7c90265875ed79052c18966a81a0614..b9694b6445d00267142a14c04fe175405bcfd10f 100644 (file)
@@ -216,7 +216,7 @@ static void serport_ldisc_write_wakeup(struct tty_struct * tty)
  * The line discipline structure.
  */
 
-static struct tty_ldisc serport_ldisc = {
+static struct tty_ldisc_ops serport_ldisc = {
        .owner =        THIS_MODULE,
        .name =         "input",
        .open =         serport_ldisc_open,
index 2095153582f13a639ac6feeb19a8fe2a247a7ad1..8a35029caca096d976c064967380037fff2a9cb2 100644 (file)
@@ -466,7 +466,7 @@ static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb)
        ld = tty_ldisc_ref(mp->tty);
        if (ld == NULL)
                return -1;
-       if (ld->receive_buf == NULL) {
+       if (ld->ops->receive_buf == NULL) {
 #if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
                printk(KERN_DEBUG "capi: ldisc has no receive_buf function\n");
 #endif
@@ -501,7 +501,7 @@ static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb)
        printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => ldisc\n",
                                datahandle, skb->len);
 #endif
-       ld->receive_buf(mp->tty, skb->data, NULL, skb->len);
+       ld->ops->receive_buf(mp->tty, skb->data, NULL, skb->len);
        kfree_skb(skb);
        tty_ldisc_deref(ld);
        return 0;
index 45d1ee93cd39979e0f6788f73f9b7a4571eed4e6..5e89fa177816f54b45bce84cf65ba3dd09f01b34 100644 (file)
@@ -766,7 +766,7 @@ gigaset_tty_wakeup(struct tty_struct *tty)
        cs_put(cs);
 }
 
-static struct tty_ldisc gigaset_ldisc = {
+static struct tty_ldisc_ops gigaset_ldisc = {
        .owner          = THIS_MODULE,
        .magic          = TTY_LDISC_MAGIC,
        .name           = "ser_gigaset",
index 9d5721287d6f50d7030499e4470b41a36f4cb6b5..19dd0a61749ccb4da0343643e71ece903bfbd992 100644 (file)
@@ -783,7 +783,7 @@ static int sixpack_ioctl(struct tty_struct *tty, struct file *file,
        return err;
 }
 
-static struct tty_ldisc sp_ldisc = {
+static struct tty_ldisc_ops sp_ldisc = {
        .owner          = THIS_MODULE,
        .magic          = TTY_LDISC_MAGIC,
        .name           = "6pack",
index 65166035aca0c81b5bea15d608bb88cf945ef24c..c6ca47599fd4581b1c6f24aaedb27ce0efb991a2 100644 (file)
@@ -969,7 +969,7 @@ out:
        mkiss_put(ax);
 }
 
-static struct tty_ldisc ax_ldisc = {
+static struct tty_ldisc_ops ax_ldisc = {
        .owner          = THIS_MODULE,
        .magic          = TTY_LDISC_MAGIC,
        .name           = "mkiss",
index e6f40b7f9041d48e8c8b0d2020175dbff20e1331..9e33196f945975cfd75d2372940119da46ebb612 100644 (file)
@@ -533,7 +533,7 @@ static void irtty_close(struct tty_struct *tty)
 
 /* ------------------------------------------------------- */
 
-static struct tty_ldisc irda_ldisc = {
+static struct tty_ldisc_ops irda_ldisc = {
        .magic          = TTY_LDISC_MAGIC,
        .name           = "irda",
        .flags          = 0,
index f1a52def1241a387c28ed6f5a045b839df8f994f..451bdb57d6fc98b5389a9067e52c49fff9df37c9 100644 (file)
@@ -378,7 +378,7 @@ ppp_asynctty_wakeup(struct tty_struct *tty)
 }
 
 
-static struct tty_ldisc ppp_ldisc = {
+static struct tty_ldisc_ops ppp_ldisc = {
        .owner  = THIS_MODULE,
        .magic  = TTY_LDISC_MAGIC,
        .name   = "ppp",
index b8f0369a71e777a30b8a52897184a6cca3a2cb4a..801d8f99d4714155e2f3b3f9c0879ec15d2de8ba 100644 (file)
@@ -418,7 +418,7 @@ ppp_sync_wakeup(struct tty_struct *tty)
 }
 
 
-static struct tty_ldisc ppp_sync_ldisc = {
+static struct tty_ldisc_ops ppp_sync_ldisc = {
        .owner  = THIS_MODULE,
        .magic  = TTY_LDISC_MAGIC,
        .name   = "pppsync",
index 84af68fdb6c2b08ca53bc2357a5db17959825cee..1d58991d395b6ef32120e1e265c8245ab61219e3 100644 (file)
@@ -1301,7 +1301,7 @@ static int sl_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 #endif
 /* VSV changes end */
 
-static struct tty_ldisc        sl_ldisc = {
+static struct tty_ldisc_ops sl_ldisc = {
        .owner          = THIS_MODULE,
        .magic          = TTY_LDISC_MAGIC,
        .name           = "slip",
index e03eef2f2282088c3366356e80979ad52d538661..c2c10c6322602dbfa462d5e54eb75c75eede5ccd 100644 (file)
@@ -688,9 +688,9 @@ static void cpc_tty_rx_work(struct work_struct *work)
                                if (cpc_tty->tty) {
                                        ld = tty_ldisc_ref(cpc_tty->tty);
                                        if (ld) {
-                                               if (ld->receive_buf) {
+                                               if (ld->ops->receive_buf) {
                                                        CPC_TTY_DBG("%s: call line disc. receive_buf\n",cpc_tty->name);
-                                                       ld->receive_buf(cpc_tty->tty, (char *)(buf->data), &flags, buf->size);
+                                                       ld->ops->receive_buf(cpc_tty->tty, (char *)(buf->data), &flags, buf->size);
                                                }
                                                tty_ldisc_deref(ld);
                                        }
index 069f8bb0a99fa401e254a03ff94a77a4217d58b5..2a6c7a60756f38a8c5ad00064562c4059de1089c 100644 (file)
@@ -754,7 +754,7 @@ static void x25_asy_setup(struct net_device *dev)
        dev->flags              = IFF_NOARP;
 }
 
-static struct tty_ldisc x25_ldisc = {
+static struct tty_ldisc_ops x25_ldisc = {
        .owner          = THIS_MODULE,
        .magic          = TTY_LDISC_MAGIC,
        .name           = "X.25",
index 21f490f5d65ce1f96eb37095516eddb3c80aa4f8..d153946d6d15553223c563f901d12bd976c65832 100644 (file)
@@ -136,54 +136,6 @@ static const struct file_operations proc_tty_drivers_operations = {
        .release        = seq_release,
 };
 
-static void * tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos)
-{
-       return (*pos < NR_LDISCS) ? pos : NULL;
-}
-
-static void * tty_ldiscs_seq_next(struct seq_file *m, void *v, loff_t *pos)
-{
-       (*pos)++;
-       return (*pos < NR_LDISCS) ? pos : NULL;
-}
-
-static void tty_ldiscs_seq_stop(struct seq_file *m, void *v)
-{
-}
-
-static int tty_ldiscs_seq_show(struct seq_file *m, void *v)
-{
-       int i = *(loff_t *)v;
-       struct tty_ldisc *ld;
-       
-       ld = tty_ldisc_get(i);
-       if (ld == NULL)
-               return 0;
-       seq_printf(m, "%-10s %2d\n", ld->name ? ld->name : "???", i);
-       tty_ldisc_put(i);
-       return 0;
-}
-
-static const struct seq_operations tty_ldiscs_seq_ops = {
-       .start  = tty_ldiscs_seq_start,
-       .next   = tty_ldiscs_seq_next,
-       .stop   = tty_ldiscs_seq_stop,
-       .show   = tty_ldiscs_seq_show,
-};
-
-static int proc_tty_ldiscs_open(struct inode *inode, struct file *file)
-{
-       return seq_open(file, &tty_ldiscs_seq_ops);
-}
-
-static const struct file_operations tty_ldiscs_proc_fops = {
-       .owner          = THIS_MODULE,
-       .open           = proc_tty_ldiscs_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = seq_release,
-};
-
 /*
  * This function is called by tty_register_driver() to handle
  * registering the driver's /proc handler into /proc/tty/driver/<foo>
index 324a3b231d407e1810ac1fc5801e688636506622..013711ea7385fa09f4b53ed338a2e2463a47eb8e 100644 (file)
@@ -185,6 +185,7 @@ struct tty_struct {
        struct tty_driver *driver;
        const struct tty_operations *ops;
        int index;
+       /* The ldisc objects are protected by tty_ldisc_lock at the moment */
        struct tty_ldisc ldisc;
        struct mutex termios_mutex;
        spinlock_t ctrl_lock;
@@ -289,7 +290,7 @@ extern void tty_wait_until_sent(struct tty_struct * tty, long timeout);
 extern int tty_check_change(struct tty_struct * tty);
 extern void stop_tty(struct tty_struct * tty);
 extern void start_tty(struct tty_struct * tty);
-extern int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc);
+extern int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc);
 extern int tty_unregister_ldisc(int disc);
 extern int tty_register_driver(struct tty_driver *driver);
 extern int tty_unregister_driver(struct tty_driver *driver);
@@ -330,9 +331,7 @@ extern int tty_termios_hw_change(struct ktermios *a, struct ktermios *b);
 extern struct tty_ldisc *tty_ldisc_ref(struct tty_struct *);
 extern void tty_ldisc_deref(struct tty_ldisc *);
 extern struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *);
-
-extern struct tty_ldisc *tty_ldisc_get(int);
-extern void tty_ldisc_put(int);
+extern const struct file_operations tty_ldiscs_proc_fops;
 
 extern void tty_wakeup(struct tty_struct *tty);
 extern void tty_ldisc_flush(struct tty_struct *tty);
@@ -354,7 +353,7 @@ extern int tty_write_lock(struct tty_struct *tty, int ndelay);
 
 
 /* n_tty.c */
-extern struct tty_ldisc tty_ldisc_N_TTY;
+extern struct tty_ldisc_ops tty_ldisc_N_TTY;
 
 /* tty_audit.c */
 #ifdef CONFIG_AUDIT
index 6226504d91080bd10b9eb91e7a6adf4cbc3ab579..40f38d896777400f1bcbb56c36063eed22db45fe 100644 (file)
 #include <linux/fs.h>
 #include <linux/wait.h>
 
-struct tty_ldisc {
+struct tty_ldisc_ops {
        int     magic;
        char    *name;
        int     num;
@@ -142,6 +142,11 @@ struct tty_ldisc {
        int refcount;
 };
 
+struct tty_ldisc {
+       struct tty_ldisc_ops *ops;
+       int refcount;
+};
+
 #define TTY_LDISC_MAGIC        0x5403
 
 #define LDISC_FLAG_DEFINED     0x00000001
index c9191871c1e0921cf9b096a3fdcad79c28f30309..0a387f2eb7a96aa0b83014175153482d3a80ed8d 100644 (file)
@@ -617,14 +617,7 @@ static void rfcomm_tty_wakeup(unsigned long arg)
                return;
 
        BT_DBG("dev %p tty %p", dev, tty);
-
-       if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && tty->ldisc.write_wakeup)
-               (tty->ldisc.write_wakeup)(tty);
-
-       wake_up_interruptible(&tty->write_wait);
-#ifdef SERIAL_HAVE_POLL_WAIT
-       wake_up_interruptible(&tty->poll_wait);
-#endif
+       tty_wakeup(tty);
 }
 
 static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
@@ -1005,9 +998,7 @@ static void rfcomm_tty_flush_buffer(struct tty_struct *tty)
                return;
 
        skb_queue_purge(&dev->dlc->tx_queue);
-
-       if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && tty->ldisc.write_wakeup)
-               tty->ldisc.write_wakeup(tty);
+       tty_wakeup(tty);
 }
 
 static void rfcomm_tty_send_xchar(struct tty_struct *tty, char ch)
index 76c3057d01790c23ae1e1055e6927cf6c2d2a6a0..e4e2caeb9d82d9d1061e27b64c10476125806846 100644 (file)
@@ -650,12 +650,7 @@ static void ircomm_tty_do_softint(struct work_struct *work)
        }
 
        /* Check if user (still) wants to be waken up */
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-           tty->ldisc.write_wakeup)
-       {
-               (tty->ldisc.write_wakeup)(tty);
-       }
-       wake_up_interruptible(&tty->write_wait);
+       tty_wakeup(tty);
 }
 
 /*
@@ -1141,6 +1136,7 @@ static int ircomm_tty_data_indication(void *instance, void *sap,
                                      struct sk_buff *skb)
 {
        struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
+       struct tty_ldisc *ld;
 
        IRDA_DEBUG(2, "%s()\n", __func__ );
 
@@ -1173,7 +1169,11 @@ static int ircomm_tty_data_indication(void *instance, void *sap,
         * involve the flip buffers, since we are not running in an interrupt
         * handler
         */
-       self->tty->ldisc.receive_buf(self->tty, skb->data, NULL, skb->len);
+
+       ld = tty_ldisc_ref(self->tty);
+       if (ld)
+               ld->ops->receive_buf(self->tty, skb->data, NULL, skb->len);
+       tty_ldisc_deref(ld);
 
        /* No need to kfree_skb - see ircomm_ttp_data_indication() */