diff options
author | Guy Martin <gmsoft@gentoo.org> | 2004-11-24 17:35:47 +0000 |
---|---|---|
committer | Guy Martin <gmsoft@gentoo.org> | 2004-11-24 17:35:47 +0000 |
commit | b53428232c39bbbe0ff357b1db573ba510070184 (patch) | |
tree | fd90858a1ded56a75c7277fa89b5deb2a4ef3e99 /sys-kernel | |
parent | New version, culled older versions (diff) | |
download | historical-b53428232c39bbbe0ff357b1db573ba510070184.tar.gz historical-b53428232c39bbbe0ff357b1db573ba510070184.tar.bz2 historical-b53428232c39bbbe0ff357b1db573ba510070184.zip |
Various security fixes (#70681, #65877, #68421, #62524).
Diffstat (limited to 'sys-kernel')
8 files changed, 4608 insertions, 16 deletions
diff --git a/sys-kernel/hppa-dev-sources/ChangeLog b/sys-kernel/hppa-dev-sources/ChangeLog index 4415e5fec467..45ff614793d4 100644 --- a/sys-kernel/hppa-dev-sources/ChangeLog +++ b/sys-kernel/hppa-dev-sources/ChangeLog @@ -1,6 +1,13 @@ # ChangeLog for sys-kernel/hppa-dev-sources # Copyright 2002-2004 Gentoo Foundation; Distributed under the GPL v2 -# $Header: /var/cvsroot/gentoo-x86/sys-kernel/hppa-dev-sources/ChangeLog,v 1.23 2004/10/01 22:07:20 vapier Exp $ +# $Header: /var/cvsroot/gentoo-x86/sys-kernel/hppa-dev-sources/ChangeLog,v 1.24 2004/11/24 17:35:47 gmsoft Exp $ + +*hppa-dev-sources-2.6.8.1_p11-r1 (24 Nov 2004) + + 24 Nov 2004; Guy Martin <gmsoft@gentoo.org> +files/CAN-2004-0814.patch, + +files/CAN-2004-0883.patch, +files/binfmt_elf-loader-security.patch, + +files/ptmx-security.patch, +hppa-dev-sources-2.6.8.1_p11-r1.ebuild: + Various security fixes (#70681, #65877, #68421, #62524). *hppa-dev-sources-2.6.8.1_p11 (01 Oct 2004) diff --git a/sys-kernel/hppa-dev-sources/Manifest b/sys-kernel/hppa-dev-sources/Manifest index 05aa258c421c..ee22d371ab03 100644 --- a/sys-kernel/hppa-dev-sources/Manifest +++ b/sys-kernel/hppa-dev-sources/Manifest @@ -1,26 +1,22 @@ ------BEGIN PGP SIGNED MESSAGE----- -Hash: SHA1 - -MD5 d8af906155acd20021d8a44fcb30cce9 ChangeLog 4368 +MD5 faf9dd76877c34d04b7dcebb187fcd54 ChangeLog 4692 MD5 ae5609d9bd55ed7d9792b7b86da4df6b hppa-dev-sources-2.6.7_p1-r2.ebuild 1180 +MD5 73864d24b030876a0f811d73fdbf556c hppa-dev-sources-2.6.7_p14-r1.ebuild 1449 MD5 05bef7ac2c9a5cdf016c4be6f71d034b hppa-dev-sources-2.6.7_p14.ebuild 1176 +MD5 109cb26368a56cea9cf1d1210cb3e857 hppa-dev-sources-2.6.8.1_p11-r1.ebuild 1274 MD5 f1b3ae515c1f32812ecbf25193148a90 metadata.xml 223 -MD5 73864d24b030876a0f811d73fdbf556c hppa-dev-sources-2.6.7_p14-r1.ebuild 1449 MD5 e659a5ccd8cb4f1630eb94a992053474 hppa-dev-sources-2.6.8.1_p11.ebuild 1098 -MD5 ce5fc85224c09cf512dc725ee88945e4 files/digest-hppa-dev-sources-2.6.7_p1-r2 129 -MD5 f0e12ba218f53c2694a91259bdc2fdc7 files/CAN-2004-0596.patch 494 -MD5 c857b174f7e6a6b0ab2e26f9306ad0a0 files/ncr53c8xx.diff 3701 MD5 b6e38b41c8a79943df2ab2642149d06f files/CAN-2004-0497.patch 2214 +MD5 f0e12ba218f53c2694a91259bdc2fdc7 files/CAN-2004-0596.patch 494 MD5 c91330cc5b4044b6f59696095c2dc0fb files/CAN-2004-0626-death_packet.patch 423 +MD5 ce5fc85224c09cf512dc725ee88945e4 files/digest-hppa-dev-sources-2.6.7_p1-r2 129 MD5 2dfffb2597dfa71f526d15fdb55ce4f8 files/digest-hppa-dev-sources-2.6.7_p14 130 MD5 2c3b568f5f12b140ab983b53543bca15 files/digest-hppa-dev-sources-2.6.7_p14-r1 206 +MD5 154a348c46bdd0a33b20d3bbfb5e2a3b files/CAN-2004-0814.patch 131240 +MD5 452e04a312368605e145428c35bd0e05 files/ptmx-security.patch 572 +MD5 8165de5e2ab6e0d3263ea35ce856fd1b files/CAN-2004-0883.patch 3309 MD5 b36a855496ce31ee483358985b3a409c files/firmware.c.patch 3604 +MD5 c857b174f7e6a6b0ab2e26f9306ad0a0 files/ncr53c8xx.diff 3701 MD5 222e890035f4ad3152f0c2a625a9ea67 files/security-proc-cmdline.patch 693 MD5 00d36aabec0074afff01d252833fdcd0 files/digest-hppa-dev-sources-2.6.8.1_p11 133 ------BEGIN PGP SIGNATURE----- -Version: GnuPG v1.9.10 (GNU/Linux) - -iD8DBQFBXdVKHTu7gpaalycRAtm2AKCskwMdk1Ak94Hg8X6Y8c8EN7fnuACfbet4 -vd9yqrmpErraIKCBB1IVqno= -=psPk ------END PGP SIGNATURE----- +MD5 1ee8ba8362089c31fdd7d88b32eaf63e files/binfmt_elf-loader-security.patch 1938 +MD5 00d36aabec0074afff01d252833fdcd0 files/digest-hppa-dev-sources-2.6.8.1_p11-r1 133 diff --git a/sys-kernel/hppa-dev-sources/files/CAN-2004-0814.patch b/sys-kernel/hppa-dev-sources/files/CAN-2004-0814.patch new file mode 100644 index 000000000000..ec94a9f6db3a --- /dev/null +++ b/sys-kernel/hppa-dev-sources/files/CAN-2004-0814.patch @@ -0,0 +1,4365 @@ +diff -Nur linux-2.6.8.1/Documentation/tty.txt linux-2.6.8.1-plasmaroo/Documentation/tty.txt +--- linux-2.6.8.1/Documentation/tty.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/Documentation/tty.txt 2004-11-06 22:55:10.540666520 +0000 +@@ -0,0 +1,194 @@ ++ ++ The Lockronomicon ++ ++Your guide to the ancient and twisted locking policies of the tty layer and ++the warped logic behind them. Beware all ye who read on. ++ ++FIXME: still need to work out the full set of BKL assumptions and document ++them so they can eventually be killed off. ++ ++ ++Line Discipline ++--------------- ++ ++Line disciplines are registered with tty_register_ldisc() passing the ++discipline number and the ldisc structure. At the point of registration the ++discipline must be ready to use and it is possible it will get used before ++the call returns success. If the call returns an error then it won't get ++called. Do not re-use ldisc numbers as they are part of the userspace ABI ++and writing over an existing ldisc will cause demons to eat your computer. ++After the return the ldisc data has been copied so you may free your own ++copy of the structure. You must not re-register over the top of the line ++discipline even with the same data or your computer again will be eaten by ++demons. ++ ++In order to remove a line discipline call tty_register_ldisc passing NULL. ++In ancient times this always worked. In modern times the function will ++return -EBUSY if the ldisc is currently in use. Since the ldisc referencing ++code manages the module counts this should not usually be a concern. ++ ++Heed this warning: the reference count field of the registered copies of the ++tty_ldisc structure in the ldisc table counts the number of lines using this ++discipline. The reference count of the tty_ldisc structure within a tty ++counts the number of active users of the ldisc at this instant. In effect it ++counts the number of threads of execution within an ldisc method (plus those ++about to enter and exit although this detail matters not). ++ ++Line Discipline Methods ++----------------------- ++ ++TTY side interfaces: ++ ++close() - This is called on a terminal when the line ++ discipline is being unplugged. At the point of ++ execution no further users will enter the ++ ldisc code for this tty. Can sleep. ++ ++open() - Called when the line discipline is attached to ++ the terminal. No other call into the line ++ discipline for this tty will occur until it ++ completes successfully. Can sleep. ++ ++write() - A process is writing data from user space ++ through the line discipline. Multiple write calls ++ are serialized by the tty layer for the ldisc. May ++ sleep. ++ ++flush_buffer() - May be called at any point between open and close. ++ ++chars_in_buffer() - Report the number of bytes in the buffer. ++ ++set_termios() - Called on termios structure changes. The caller ++ passes the old termios data and the current data ++ is in the tty. Called under the termios lock so ++ may not sleep. Serialized against itself only. ++ ++read() - Move data from the line discipline to the user. ++ Multiple read calls may occur in parallel and the ++ ldisc must deal with serialization issues. May ++ sleep. ++ ++poll() - Check the status for the poll/select calls. Multiple ++ poll calls may occur in parallel. May sleep. ++ ++ioctl() - Called when an ioctl is handed to the tty layer ++ that might be for the ldisc. Multiple ioctl calls ++ may occur in parallel. May sleep. ++ ++Driver Side Interfaces: ++ ++receive_buf() - Hand buffers of bytes from the driver to the ldisc ++ for processing. Semantics currently rather ++ mysterious 8( ++ ++receive_room() - Can be called by the driver layer at any time when ++ the ldisc is opened. The ldisc must be able to ++ handle the reported amount of data at that instant. ++ Synchronization between active receive_buf and ++ receive_room calls is down to the driver not the ++ ldisc. Must not sleep. ++ ++write_wakeup() - May be called at any point between open and close. ++ The TTY_DO_WRITE_WAKEUP flag indicates if a call ++ is needed but always races versus calls. Thus the ++ ldisc must be careful about setting order and to ++ handle unexpected calls. Must not sleep. ++ ++ ++Locking ++ ++Callers to the line discipline functions from the tty layer are required to ++take line discipline locks. The same is true of calls from the driver side ++but not yet enforced. ++ ++Three calls are now provided ++ ++ ldisc = tty_ldisc_ref(tty); ++ ++takes a handle to the line discipline in the tty and returns it. If no ldisc ++is currently attached or the ldisc is being closed and re-opened at this ++point then NULL is returned. While this handle is held the ldisc will not ++change or go away. ++ ++ tty_ldisc_deref(ldisc) ++ ++Returns the ldisc reference and allows the ldisc to be closed. Returning the ++reference takes away your right to call the ldisc functions until you take ++a new reference. ++ ++ ldisc = tty_ldisc_ref_wait(tty); ++ ++Performs the same function as tty_ldisc_ref except that it will wait for an ++ldisc change to complete and then return a reference to the new ldisc. ++ ++While these functions are slightly slower than the old code they should have ++minimal impact as most receive logic uses the flip buffers and they only ++need to take a reference when they push bits up through the driver. ++ ++A caution: The ldisc->open(), ldisc->close() and driver->set_ldisc ++functions are called with the ldisc unavailable. Thus tty_ldisc_ref will ++fail in this situation if used within these functions. Ldisc and driver ++code calling its own functions must be careful in this case. ++ ++ ++Driver Interface ++---------------- ++ ++open() - Called when a device is opened. May sleep ++ ++close() - Called when a device is closed. At the point of ++ return from this call the driver must make no ++ further ldisc calls of any kind. May sleep ++ ++write() - Called to write bytes to the device. May not ++ sleep. May occur in parallel in special cases. ++ Because this includes panic paths drivers generally ++ shouldn't try and do clever locking here. ++ ++put_char() - Stuff a single character onto the queue. The ++ driver is guaranteed following up calls to ++ flush_chars. ++ ++flush_chars() - Ask the kernel to write put_char queue ++ ++write_room() - Return the number of characters tht can be stuffed ++ into the port buffers without overflow (or less). ++ The ldisc is responsible for being intelligent ++ about multi-threading of write_room/write calls ++ ++ioctl() - Called when an ioctl may be for the driver ++ ++set_termios() - Called on termios change, may get parallel calls, ++ may block for now (may change that) ++ ++set_ldisc() - Notifier for discipline change. At the point this ++ is done the discipline is not yet usable. Can now ++ sleep (I think) ++ ++throttle() - Called by the ldisc to ask the driver to do flow ++ control. Serialization including with unthrottle ++ is the job of the ldisc layer. ++ ++unthrottle() - Called by the ldisc to ask the driver to stop flow ++ control. ++ ++stop() - Ldisc notifier to the driver to stop output. As with ++ throttle the serializations with start() are down ++ to the ldisc layer. ++ ++start() - Ldisc notifier to the driver to start output. ++ ++hangup() - Ask the tty driver to cause a hangup initiated ++ from the host side. [Can sleep ??] ++ ++break_ctl() - Send RS232 break. Can sleep. Can get called in ++ parallel, driver must serialize (for now), and ++ with write calls. ++ ++wait_until_sent() - Wait for characters to exit the hardware queue ++ of the driver. Can sleep ++ ++send_xchar() - Send XON/XOFF and if possible jump the queue with ++ it in order to get fast flow control responses. ++ Cannot sleep ?? ++ +diff -Nur linux-2.6.8.1/drivers/bluetooth/hci_ldisc.c linux-2.6.8.1-plasmaroo/drivers/bluetooth/hci_ldisc.c +--- linux-2.6.8.1/drivers/bluetooth/hci_ldisc.c 2004-08-14 11:55:48.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/bluetooth/hci_ldisc.c 2004-11-06 22:55:10.555664240 +0000 +@@ -188,9 +188,7 @@ + } + + /* Flush any pending characters in the driver and discipline. */ +- if (tty->ldisc.flush_buffer) +- tty->ldisc.flush_buffer(tty); +- ++ tty_ldisc_flush(tty); + if (tty->driver->flush_buffer) + tty->driver->flush_buffer(tty); + +@@ -280,7 +278,9 @@ + + spin_lock_init(&hu->rx_lock); + +- /* Flush any pending characters in the driver and line discipline */ ++ /* Flush any pending characters in the driver and line discipline. */ ++ /* 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); + +diff -Nur linux-2.6.8.1/drivers/char/amiserial.c linux-2.6.8.1-plasmaroo/drivers/char/amiserial.c +--- linux-2.6.8.1/drivers/char/amiserial.c 2004-08-14 11:56:24.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/char/amiserial.c 2004-11-06 22:55:10.582660136 +0000 +@@ -557,9 +557,7 @@ + return; + + if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- tty->ldisc.write_wakeup) +- (tty->ldisc.write_wakeup)(tty); ++ tty_wakeup(tty); + wake_up_interruptible(&tty->write_wait); + } + } +@@ -1023,9 +1021,7 @@ + info->xmit.head = info->xmit.tail = 0; + local_irq_restore(flags); + wake_up_interruptible(&tty->write_wait); +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- tty->ldisc.write_wakeup) +- (tty->ldisc.write_wakeup)(tty); ++ tty_wakeup(tty); + } + + /* +@@ -1564,8 +1560,8 @@ + shutdown(info); + if (tty->driver->flush_buffer) + tty->driver->flush_buffer(tty); +- if (tty->ldisc.flush_buffer) +- tty->ldisc.flush_buffer(tty); ++ ++ tty_ldisc_flush(tty); + tty->closing = 0; + info->event = 0; + info->tty = 0; +diff -Nur linux-2.6.8.1/drivers/char/cyclades.c linux-2.6.8.1-plasmaroo/drivers/char/cyclades.c +--- linux-2.6.8.1/drivers/char/cyclades.c 2004-08-14 11:54:51.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/char/cyclades.c 2004-11-06 22:55:10.593658464 +0000 +@@ -970,10 +970,7 @@ + wake_up_interruptible(&info->delta_msr_wait); + } + if (test_and_clear_bit(Cy_EVENT_WRITE_WAKEUP, &info->event)) { +- if((tty->flags & (1<< TTY_DO_WRITE_WAKEUP)) +- && tty->ldisc.write_wakeup){ +- (tty->ldisc.write_wakeup)(tty); +- } ++ tty_wakeup(tty); + wake_up_interruptible(&tty->write_wait); + } + #ifdef Z_WAKE +@@ -2850,8 +2847,7 @@ + shutdown(info); + if (tty->driver->flush_buffer) + tty->driver->flush_buffer(tty); +- if (tty->ldisc.flush_buffer) +- tty->ldisc.flush_buffer(tty); ++ tty_ldisc_flush(tty); + CY_LOCK(info, flags); + + tty->closing = 0; +@@ -4554,10 +4550,8 @@ + } + CY_UNLOCK(info, flags); + } ++ tty_wakeup(tty); + wake_up_interruptible(&tty->write_wait); +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) +- && tty->ldisc.write_wakeup) +- (tty->ldisc.write_wakeup)(tty); + } /* cy_flush_buffer */ + + +diff -Nur linux-2.6.8.1/drivers/char/epca.c linux-2.6.8.1-plasmaroo/drivers/char/epca.c +--- linux-2.6.8.1/drivers/char/epca.c 2004-08-14 11:55:33.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/char/epca.c 2004-11-06 22:55:10.608656184 +0000 +@@ -551,9 +551,7 @@ + if (tty->driver->flush_buffer) + tty->driver->flush_buffer(tty); + +- if (tty->ldisc.flush_buffer) +- tty->ldisc.flush_buffer(tty); +- ++ tty_ldisc_flush(tty); + shutdown(ch); + tty->closing = 0; + ch->event = 0; +@@ -657,10 +655,7 @@ + cli(); + if (tty->driver->flush_buffer) + tty->driver->flush_buffer(tty); +- +- if (tty->ldisc.flush_buffer) +- tty->ldisc.flush_buffer(tty); +- ++ tty_ldisc_flush(tty); + shutdown(ch); + + ch->tty = NULL; +@@ -1120,8 +1115,7 @@ + restore_flags(flags); + + wake_up_interruptible(&tty->write_wait); +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) +- (tty->ldisc.write_wakeup)(tty); ++ tty_wakeup(tty); + + } /* End pc_flush_buffer */ + +@@ -2262,9 +2256,7 @@ + { /* Begin if LOWWAIT */ + + ch->statusflags &= ~LOWWAIT; +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- tty->ldisc.write_wakeup) +- (tty->ldisc.write_wakeup)(tty); ++ tty_wakeup(tty); + wake_up_interruptible(&tty->write_wait); + + } /* End if LOWWAIT */ +@@ -2281,9 +2273,7 @@ + { /* Begin if EMPTYWAIT */ + + ch->statusflags &= ~EMPTYWAIT; +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- tty->ldisc.write_wakeup) +- (tty->ldisc.write_wakeup)(tty); ++ tty_wakeup(tty); + + wake_up_interruptible(&tty->write_wait); + +@@ -3136,6 +3126,7 @@ + } + else + { ++ /* ldisc lock already held in ioctl */ + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + } +diff -Nur linux-2.6.8.1/drivers/char/esp.c linux-2.6.8.1-plasmaroo/drivers/char/esp.c +--- linux-2.6.8.1/drivers/char/esp.c 2004-08-14 11:54:46.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/char/esp.c 2004-11-06 22:55:10.625653600 +0000 +@@ -762,10 +762,7 @@ + return; + + if (test_and_clear_bit(ESP_EVENT_WRITE_WAKEUP, &info->event)) { +- 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); + } + } + +@@ -1370,10 +1367,7 @@ + cli(); + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + sti(); +- wake_up_interruptible(&tty->write_wait); +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- tty->ldisc.write_wakeup) +- (tty->ldisc.write_wakeup)(tty); ++ tty_wakeup(tty); + } + + /* +@@ -2069,8 +2063,7 @@ + shutdown(info); + if (tty->driver->flush_buffer) + tty->driver->flush_buffer(tty); +- if (tty->ldisc.flush_buffer) +- tty->ldisc.flush_buffer(tty); ++ tty_ldisc_flush(tty); + tty->closing = 0; + info->event = 0; + info->tty = NULL; +diff -Nur linux-2.6.8.1/drivers/char/generic_serial.c linux-2.6.8.1-plasmaroo/drivers/char/generic_serial.c +--- linux-2.6.8.1/drivers/char/generic_serial.c 2004-08-14 11:55:32.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/char/generic_serial.c 2004-11-06 22:55:10.630652840 +0000 +@@ -436,9 +436,7 @@ + restore_flags(flags); + + wake_up_interruptible(&tty->write_wait); +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- tty->ldisc.write_wakeup) +- (tty->ldisc.write_wakeup)(tty); ++ tty_wakeup(tty); + func_exit (); + } + +@@ -578,9 +576,7 @@ + if (!tty) return; + + if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) { +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- tty->ldisc.write_wakeup) +- (tty->ldisc.write_wakeup)(tty); ++ tty_wakeup(tty); + wake_up_interruptible(&tty->write_wait); + } + func_exit (); +@@ -694,8 +690,8 @@ + { + unsigned long flags; + struct gs_port *port; +- +- func_enter (); ++ ++ func_enter () + + if (!tty) return; + +@@ -760,8 +756,8 @@ + + if (tty->driver->flush_buffer) + tty->driver->flush_buffer(tty); +- if (tty->ldisc.flush_buffer) +- tty->ldisc.flush_buffer(tty); ++ ++ tty_ldisc_flush(tty); + tty->closing = 0; + + port->event = 0; +diff -Nur linux-2.6.8.1/drivers/char/hvc_console.c linux-2.6.8.1-plasmaroo/drivers/char/hvc_console.c +--- linux-2.6.8.1/drivers/char/hvc_console.c 2004-08-14 11:56:00.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/char/hvc_console.c 2004-11-06 22:56:30.270545736 +0000 +@@ -248,10 +248,7 @@ + + if (hp->do_wakeup) { + hp->do_wakeup = 0; +- 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); + } + } + +diff -Nur linux-2.6.8.1/drivers/char/hvcs.c linux-2.6.8.1-plasmaroo/drivers/char/hvcs.c +--- linux-2.6.8.1/drivers/char/hvcs.c 2004-08-14 11:55:33.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/char/hvcs.c 2004-11-06 22:55:10.652649496 +0000 +@@ -393,10 +393,7 @@ + * a non-existent tty. + */ + if (tty) { +- 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); + } + } + } +diff -Nur linux-2.6.8.1/drivers/char/isicom.c linux-2.6.8.1-plasmaroo/drivers/char/isicom.c +--- linux-2.6.8.1/drivers/char/isicom.c 2004-08-14 11:54:47.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/char/isicom.c 2004-11-06 22:55:10.655649040 +0000 +@@ -484,10 +484,8 @@ + + if (!tty) + return; +- +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- tty->ldisc.write_wakeup) +- (tty->ldisc.write_wakeup)(tty); ++ ++ tty_wakeup(tty); + wake_up_interruptible(&tty->write_wait); + } + +@@ -1119,8 +1117,8 @@ + isicom_shutdown_port(port); + if (tty->driver->flush_buffer) + tty->driver->flush_buffer(tty); +- if (tty->ldisc.flush_buffer) +- tty->ldisc.flush_buffer(tty); ++ ++ tty_ldisc_flush(tty); + tty->closing = 0; + port->tty = NULL; + if (port->blocked_open) { +@@ -1563,9 +1561,7 @@ + restore_flags(flags); + + wake_up_interruptible(&tty->write_wait); +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- tty->ldisc.write_wakeup) +- (tty->ldisc.write_wakeup)(tty); ++ tty_wakeup(tty); + } + + +diff -Nur linux-2.6.8.1/drivers/char/moxa.c linux-2.6.8.1-plasmaroo/drivers/char/moxa.c +--- linux-2.6.8.1/drivers/char/moxa.c 2004-08-14 11:56:22.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/char/moxa.c 2004-11-06 22:55:10.660648280 +0000 +@@ -618,8 +618,8 @@ + + if (tty->driver->flush_buffer) + tty->driver->flush_buffer(tty); +- if (tty->ldisc.flush_buffer) +- tty->ldisc.flush_buffer(tty); ++ tty_ldisc_flush(tty); ++ + tty->closing = 0; + ch->event = 0; + ch->tty = NULL; +@@ -693,9 +693,7 @@ + if (ch == NULL) + return; + MoxaPortFlushData(ch->port, 1); +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- tty->ldisc.write_wakeup) +- (tty->ldisc.write_wakeup) (tty); ++ tty_wakeup(tty); + wake_up_interruptible(&tty->write_wait); + } + +@@ -954,9 +952,7 @@ + if (MoxaPortTxQueue(ch->port) <= WAKEUP_CHARS) { + if (!tp->stopped) { + ch->statusflags &= ~LOWWAIT; +- if ((tp->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- tp->ldisc.write_wakeup) +- (tp->ldisc.write_wakeup) (tp); ++ tty_wakeup(tty); + wake_up_interruptible(&tp->write_wait); + } + } +@@ -1123,9 +1119,7 @@ + if (ch->tty && (ch->statusflags & EMPTYWAIT)) { + if (MoxaPortTxQueue(ch->port) == 0) { + ch->statusflags &= ~EMPTYWAIT; +- if ((ch->tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- ch->tty->ldisc.write_wakeup) +- (ch->tty->ldisc.write_wakeup) (ch->tty); ++ tty_wakeup(tty); + wake_up_interruptible(&ch->tty->write_wait); + return; + } +diff -Nur linux-2.6.8.1/drivers/char/mxser.c linux-2.6.8.1-plasmaroo/drivers/char/mxser.c +--- linux-2.6.8.1/drivers/char/mxser.c 2004-08-14 11:55:47.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/char/mxser.c 2004-11-06 22:55:10.670646760 +0000 +@@ -678,9 +678,7 @@ + tty = info->tty; + if (tty) { + if (test_and_clear_bit(MXSER_EVENT_TXLOW, &info->event)) { +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- tty->ldisc.write_wakeup) +- (tty->ldisc.write_wakeup) (tty); ++ tty_wakeup(tty); + wake_up_interruptible(&tty->write_wait); + } + if (test_and_clear_bit(MXSER_EVENT_HANGUP, &info->event)) { +@@ -817,8 +815,8 @@ + mxser_shutdown(info); + if (tty->driver->flush_buffer) + tty->driver->flush_buffer(tty); +- if (tty->ldisc.flush_buffer) +- tty->ldisc.flush_buffer(tty); ++ tty_ldisc_flush(tty); ++ + tty->closing = 0; + info->event = 0; + info->tty = NULL; +@@ -976,9 +974,7 @@ + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + restore_flags(flags); + wake_up_interruptible(&tty->write_wait); +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- tty->ldisc.write_wakeup) +- (tty->ldisc.write_wakeup) (tty); ++ tty_wakeup(tty); + } + + static int mxser_ioctl(struct tty_struct *tty, struct file *file, +diff -Nur linux-2.6.8.1/drivers/char/n_tty.c linux-2.6.8.1-plasmaroo/drivers/char/n_tty.c +--- linux-2.6.8.1/drivers/char/n_tty.c 2004-08-14 11:54:47.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/char/n_tty.c 2004-11-06 22:55:10.684644632 +0000 +@@ -99,11 +99,18 @@ + spin_unlock_irqrestore(&tty->read_lock, flags); + } + +-/* +- * Check whether to call the driver.unthrottle function. +- * We test the TTY_THROTTLED bit first so that it always +- * indicates the current state. ++/** ++ * check_unthrottle - allow new receive data ++ * @tty; tty device ++ * ++ * Check whether to call the driver.unthrottle function. ++ * We test the TTY_THROTTLED bit first so that it always ++ * indicates the current state. The decision about whether ++ * it is worth allowing more input has been taken by the caller. ++ * Can sleep, may be called under the atomic_read semaphore but ++ * this is not guaranteed. + */ ++ + static void check_unthrottle(struct tty_struct * tty) + { + if (tty->count && +@@ -112,10 +119,13 @@ + tty->driver->unthrottle(tty); + } + +-/* +- * Reset the read buffer counters, clear the flags, +- * and make sure the driver is unthrottled. Called +- * from n_tty_open() and n_tty_flush_buffer(). ++/** ++ * reset_buffer_flags - reset buffer state ++ * @tty: terminal to reset ++ * ++ * Reset the read buffer counters, clear the flags, ++ * and make sure the driver is unthrottled. Called ++ * from n_tty_open() and n_tty_flush_buffer(). + */ + static void reset_buffer_flags(struct tty_struct *tty) + { +@@ -129,9 +139,19 @@ + check_unthrottle(tty); + } + +-/* +- * Flush the input buffer ++/** ++ * n_tty_flush_buffer - clean input queue ++ * @tty: terminal device ++ * ++ * Flush the input buffer. Called when the line discipline is ++ * being closed, when the tty layer wants the buffer flushed (eg ++ * at hangup) or when the N_TTY line discipline internally has to ++ * clean the pending queue (for example some signals). ++ * ++ * FIXME: tty->ctrl_status is not spinlocked and relies on ++ * lock_kernel() still. + */ ++ + void n_tty_flush_buffer(struct tty_struct * tty) + { + /* clear everything and unthrottle the driver */ +@@ -146,9 +166,14 @@ + } + } + +-/* +- * Return number of characters buffered to be delivered to user ++/** ++ * n_tty_chars_in_buffer - report available bytes ++ * @tty: tty device ++ * ++ * Report the number of characters buffered to be delivered to user ++ * at this instant in time. + */ ++ + ssize_t n_tty_chars_in_buffer(struct tty_struct *tty) + { + unsigned long flags; +@@ -166,20 +191,47 @@ + return n; + } + ++/** ++ * is_utf8_continuation - utf8 multibyte check ++ * @c: byte to check ++ * ++ * Returns true if the utf8 character 'c' is a multibyte continuation ++ * character. We use this to correctly compute the on screen size ++ * of the character when printing ++ */ ++ + static inline int is_utf8_continuation(unsigned char c) + { + return (c & 0xc0) == 0x80; + } + ++/** ++ * is_continuation - multibyte check ++ * @c: byte to check ++ * ++ * Returns true if the utf8 character 'c' is a multibyte continuation ++ * character and the terminal is in unicode mode. ++ */ ++ + static inline int is_continuation(unsigned char c, struct tty_struct *tty) + { + return I_IUTF8(tty) && is_utf8_continuation(c); + } + +-/* +- * Perform OPOST processing. Returns -1 when the output device is +- * full and the character must be retried. ++/** ++ * opost - output post processor ++ * @c: character (or partial unicode symbol) ++ * @tty: terminal device ++ * ++ * Perform OPOST processing. Returns -1 when the output device is ++ * full and the character must be retried. Note that Linux currently ++ * ignores TABDLY, CRDLY, VTDLY, FFDLY and NLDLY. They simply aren't ++ * relevant in the world today. If you ever need them, add them here. ++ * ++ * Called from both the receive and transmit sides and can be called ++ * re-entrantly. Relies on lock_kernel() still. + */ ++ + static int opost(unsigned char c, struct tty_struct *tty) + { + int space, spaces; +@@ -239,10 +291,20 @@ + return 0; + } + +-/* +- * opost_block --- to speed up block console writes, among other +- * things. ++/** ++ * opost_block - block postprocess ++ * @tty: terminal device ++ * @inbuf: user buffer ++ * @nr: number of bytes ++ * ++ * This path is used to speed up block console writes, among other ++ * things when processing blocks of output data. It handles only ++ * the simple cases normally found and helps to generate blocks of ++ * symbols for the console driver and thus improve performance. ++ * ++ * Called from write_chan under the tty layer write lock. + */ ++ + static ssize_t opost_block(struct tty_struct * tty, + const unsigned char __user * inbuf, unsigned int nr) + { +@@ -304,13 +366,27 @@ + } + + +- ++/** ++ * put_char - write character to driver ++ * @c: character (or part of unicode symbol) ++ * @tty: terminal device ++ * ++ * Queue a byte to the driver layer for output ++ */ ++ + static inline void put_char(unsigned char c, struct tty_struct *tty) + { + tty->driver->put_char(tty, c); + } + +-/* Must be called only when L_ECHO(tty) is true. */ ++/** ++ * echo_char - echo characters ++ * @c: unicode byte to echo ++ * @tty: terminal device ++ * ++ * Echo user input back onto the screen. This must be called only when ++ * L_ECHO(tty) is true. Called from the driver receive_buf path. ++ */ + + static void echo_char(unsigned char c, struct tty_struct *tty) + { +@@ -331,6 +407,16 @@ + } + } + ++/** ++ * eraser - handle erase function ++ * @c: character input ++ * @tty: terminal device ++ * ++ * Perform erase and neccessary output when an erase character is ++ * present in the stream from the driver layer. Handles the complexities ++ * of UTF-8 multibyte symbols. ++ */ ++ + static void eraser(unsigned char c, struct tty_struct *tty) + { + enum { ERASE, WERASE, KILL } kill_type; +@@ -463,6 +549,18 @@ + finish_erasing(tty); + } + ++/** ++ * isig - handle the ISIG optio ++ * @sig: signal ++ * @tty: terminal ++ * @flush: force flush ++ * ++ * Called when a signal is being sent due to terminal input. This ++ * may caus terminal flushing to take place according to the termios ++ * settings and character used. Called from the driver receive_buf ++ * path so serialized. ++ */ ++ + static inline void isig(int sig, struct tty_struct *tty, int flush) + { + if (tty->pgrp > 0) +@@ -474,6 +572,16 @@ + } + } + ++/** ++ * n_tty_receive_break - handle break ++ * @tty: terminal ++ * ++ * An RS232 break event has been hit in the incoming bitstream. This ++ * can cause a variety of events depending upon the termios settings. ++ * ++ * Called from the receive_buf path so single threaded. ++ */ ++ + static inline void n_tty_receive_break(struct tty_struct *tty) + { + if (I_IGNBRK(tty)) +@@ -490,19 +598,40 @@ + wake_up_interruptible(&tty->read_wait); + } + ++/** ++ * n_tty_receive_overrun - handle overrun reporting ++ * @tty: terminal ++ * ++ * Data arrived faster than we could process it. While the tty ++ * driver has flagged this the bits that were missed are gone ++ * forever. ++ * ++ * Called from the receive_buf path so single threaded. Does not ++ * need locking as num_overrun and overrun_time are function ++ * private. ++ */ ++ + static inline void n_tty_receive_overrun(struct tty_struct *tty) + { + char buf[64]; + + tty->num_overrun++; + if (time_before(tty->overrun_time, jiffies - HZ)) { +- printk("%s: %d input overrun(s)\n", tty_name(tty, buf), ++ printk(KERN_WARNING "%s: %d input overrun(s)\n", tty_name(tty, buf), + tty->num_overrun); + tty->overrun_time = jiffies; + tty->num_overrun = 0; + } + } + ++/** ++ * n_tty_receive_parity_error - error notifier ++ * @tty: terminal device ++ * @c: character ++ * ++ * Process a parity error and queue the right data to indicate ++ * the error case if neccessary. Locking as per n_tty_receive_buf. ++ */ + static inline void n_tty_receive_parity_error(struct tty_struct *tty, + unsigned char c) + { +@@ -520,6 +649,16 @@ + wake_up_interruptible(&tty->read_wait); + } + ++/** ++ * n_tty_receive_char - perform processing ++ * @tty: terminal device ++ * @c: character ++ * ++ * Process an individual character of input received from the driver. ++ * This is serialized with respect to itself by the rules for the ++ * driver above. ++ */ ++ + static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) + { + unsigned long flags; +@@ -711,6 +850,16 @@ + put_tty_queue(c, tty); + } + ++/** ++ * n_tty_receive_room - receive space ++ * @tty: terminal ++ * ++ * Called by the driver to find out how much data it is ++ * permitted to feed to the line discipline without any being lost ++ * and thus to manage flow control. Not serialized. Answers for the ++ * "instant". ++ */ ++ + static int n_tty_receive_room(struct tty_struct *tty) + { + int left = N_TTY_BUF_SIZE - tty->read_cnt - 1; +@@ -729,10 +878,13 @@ + return 0; + } + +-/* +- * Required for the ptys, serial driver etc. since processes +- * that attach themselves to the master and rely on ASYNC +- * IO must be woken up ++/** ++ * n_tty_write_wakeup - asynchronous I/O notifier ++ * @tty: tty device ++ * ++ * Required for the ptys, serial driver etc. since processes ++ * that attach themselves to the master and rely on ASYNC ++ * IO must be woken up + */ + + static void n_tty_write_wakeup(struct tty_struct *tty) +@@ -745,6 +897,19 @@ + return; + } + ++/** ++ * n_tty_receive_buf - data receive ++ * @tty: terminal device ++ * @cp: buffer ++ * @fp: flag buffer ++ * @count: characters ++ * ++ * Called by the terminal driver when a block of characters has ++ * been received. This function must be called from soft contexts ++ * not from interrupt context. The driver is responsible for making ++ * calls one at a time and in order (or using flush_to_ldisc) ++ */ ++ + static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp, + char *fp, int count) + { +@@ -828,6 +993,18 @@ + current->sighand->action[sig-1].sa.sa_handler == SIG_IGN); + } + ++/** ++ * n_tty_set_termios - termios data changed ++ * @tty: terminal ++ * @old: previous data ++ * ++ * Called by the tty layer when the user changes termios flags so ++ * that the line discipline can plan ahead. This function cannot sleep ++ * and is protected from re-entry by the tty layer. The user is ++ * guaranteed that this function will not be re-entered or in progress ++ * when the ldisc is closed. ++ */ ++ + static void n_tty_set_termios(struct tty_struct *tty, struct termios * old) + { + if (!tty) +@@ -843,7 +1020,6 @@ + I_ICRNL(tty) || I_INLCR(tty) || L_ICANON(tty) || + I_IXON(tty) || L_ISIG(tty) || L_ECHO(tty) || + I_PARMRK(tty)) { +- local_irq_disable(); // FIXME: is this safe? + memset(tty->process_char_map, 0, 256/8); + + if (I_IGNCR(tty) || I_ICRNL(tty)) +@@ -879,7 +1055,6 @@ + set_bit(SUSP_CHAR(tty), tty->process_char_map); + } + clear_bit(__DISABLED_CHAR, tty->process_char_map); +- local_irq_enable(); // FIXME: is this safe? + tty->raw = 0; + tty->real_raw = 0; + } else { +@@ -893,6 +1068,16 @@ + } + } + ++/** ++ * n_tty_close - close the ldisc for this tty ++ * @tty: device ++ * ++ * Called from the terminal layer when this line discipline is ++ * being shut down, either because of a close or becsuse of a ++ * discipline change. The function will not be called while other ++ * ldisc methods are in progress. ++ */ ++ + static void n_tty_close(struct tty_struct *tty) + { + n_tty_flush_buffer(tty); +@@ -902,11 +1087,22 @@ + } + } + ++/** ++ * n_tty_open - open an ldisc ++ * @tty: terminal to open ++ * ++ * Called when this line discipline is being attached to the ++ * terminal device. Can sleep. Called serialized so that no ++ * other events will occur in parallel. No further open will occur ++ * until a close. ++ */ ++ + static int n_tty_open(struct tty_struct *tty) + { + if (!tty) + return -EINVAL; + ++ /* This one is ugly. Currently a malloc failure here can panic */ + if (!tty->read_buf) { + tty->read_buf = alloc_buf(); + if (!tty->read_buf) +@@ -932,14 +1128,23 @@ + return 0; + } + +-/* +- * Helper function to speed up read_chan. It is only called when +- * ICANON is off; it copies characters straight from the tty queue to +- * user space directly. It can be profitably called twice; once to +- * drain the space from the tail pointer to the (physical) end of the +- * buffer, and once to drain the space from the (physical) beginning of +- * the buffer to head pointer. ++/** ++ * copy_from_read_buf - copy read data directly ++ * @tty: terminal device ++ * @b: user data ++ * @nr: size of data ++ * ++ * Helper function to speed up read_chan. It is only called when ++ * ICANON is off; it copies characters straight from the tty queue to ++ * user space directly. It can be profitably called twice; once to ++ * drain the space from the tail pointer to the (physical) end of the ++ * buffer, and once to drain the space from the (physical) beginning of ++ * the buffer to head pointer. ++ * ++ * Called under the tty->atomic_read sem and with TTY_DONT_FLIP set ++ * + */ ++ + static inline int copy_from_read_buf(struct tty_struct *tty, + unsigned char __user **b, + size_t *nr) +@@ -970,25 +1175,18 @@ + + extern ssize_t redirected_tty_write(struct file *,const char *,size_t,loff_t *); + +-static ssize_t read_chan(struct tty_struct *tty, struct file *file, +- unsigned char __user *buf, size_t nr) ++/** ++ * job_control - check job control ++ * @tty: tty ++ * @file: file handle ++ * ++ * Perform job control management checks on this file/tty descriptor ++ * and if appropriate send any needed signals and return a negative ++ * error code if action should be taken. ++ */ ++ ++static int job_control(struct tty_struct *tty, struct file *file) + { +- unsigned char __user *b = buf; +- DECLARE_WAITQUEUE(wait, current); +- int c; +- int minimum, time; +- ssize_t retval = 0; +- ssize_t size; +- long timeout; +- unsigned long flags; +- +-do_it_again: +- +- if (!tty->read_buf) { +- printk("n_tty_read_chan: called with read_buf == NULL?!?\n"); +- return -EIO; +- } +- + /* Job control check -- must be done at start and after + every sleep (POSIX.1 7.1.1.4). */ + /* NOTE: not yet done after every sleep pending a thorough +@@ -1006,7 +1204,48 @@ + return -ERESTARTSYS; + } + } ++ return 0; ++} ++ ++ ++/** ++ * read_chan - read function for tty ++ * @tty: tty device ++ * @file: file object ++ * @buf: userspace buffer pointer ++ * @nr: size of I/O ++ * ++ * Perform reads for the line discipline. We are guaranteed that the ++ * line discipline will not be closed under us but we may get multiple ++ * parallel readers and must handle this ourselves. We may also get ++ * a hangup. Always called in user context, may sleep. ++ * ++ * This code must be sure never to sleep through a hangup. ++ */ ++ ++static ssize_t read_chan(struct tty_struct *tty, struct file *file, ++ unsigned char __user *buf, size_t nr) ++{ ++ unsigned char __user *b = buf; ++ DECLARE_WAITQUEUE(wait, current); ++ int c; ++ int minimum, time; ++ ssize_t retval = 0; ++ ssize_t size; ++ long timeout; ++ unsigned long flags; ++ ++do_it_again: ++ ++ if (!tty->read_buf) { ++ printk("n_tty_read_chan: called with read_buf == NULL?!?\n"); ++ return -EIO; ++ } + ++ c = job_control(tty, file); ++ if(c < 0) ++ return c; ++ + minimum = time = 0; + timeout = MAX_SCHEDULE_TIMEOUT; + if (!tty->icanon) { +@@ -1028,6 +1267,9 @@ + } + } + ++ /* ++ * Internal serialization of reads. ++ */ + if (file->f_flags & O_NONBLOCK) { + if (down_trylock(&tty->atomic_read)) + return -EAGAIN; +@@ -1177,6 +1419,21 @@ + return retval; + } + ++/** ++ * write_chan - write function for tty ++ * @tty: tty device ++ * @file: file object ++ * @buf: userspace buffer pointer ++ * @nr: size of I/O ++ * ++ * Write function of the terminal device. This is serialized with ++ * respect to other write callers but not to termios changes, reads ++ * and other such events. We must be careful with N_TTY as the receive ++ * code will echo characters, thus calling driver write methods. ++ * ++ * This code must be sure never to sleep through a hangup. ++ */ ++ + static ssize_t write_chan(struct tty_struct * tty, struct file * file, + const unsigned char __user * buf, size_t nr) + { +@@ -1246,7 +1503,25 @@ + return (b - buf) ? b - buf : retval; + } + +-/* Called without the kernel lock held - fine */ ++/** ++ * normal_poll - poll method for N_TTY ++ * @tty: terminal device ++ * @file: file accessing it ++ * @wait: poll table ++ * ++ * Called when the line discipline is asked to poll() for data or ++ * for special events. This code is not serialized with respect to ++ * other events save open/close. ++ * ++ * This code must be sure never to sleep through a hangup. ++ * Called without the kernel lock held - fine ++ * ++ * FIXME: if someone changes the VMIN or discipline settings for the ++ * terminal while another process is in poll() the poll does not ++ * recompute the new limits. Possibly set_termios should issue ++ * a read wakeup to fix this bug. ++ */ ++ + static unsigned int normal_poll(struct tty_struct * tty, struct file * file, poll_table *wait) + { + unsigned int mask = 0; +@@ -1287,6 +1562,7 @@ + n_tty_ioctl, /* ioctl */ + n_tty_set_termios, /* set_termios */ + normal_poll, /* poll */ ++ NULL, /* hangup */ + n_tty_receive_buf, /* receive_buf */ + n_tty_receive_room, /* receive_room */ + n_tty_write_wakeup /* write_wakeup */ +diff -Nur linux-2.6.8.1/drivers/char/pcmcia/synclink_cs.c linux-2.6.8.1-plasmaroo/drivers/char/pcmcia/synclink_cs.c +--- linux-2.6.8.1/drivers/char/pcmcia/synclink_cs.c 2004-08-14 11:55:10.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/char/pcmcia/synclink_cs.c 2004-11-06 22:55:10.696642808 +0000 +@@ -531,6 +531,40 @@ + return mgslpc_get_text_ptr; + } + ++/** ++ * line discipline callback wrappers ++ * ++ * The wrappers maintain line discipline references ++ * while calling into the line discipline. ++ * ++ * ldisc_flush_buffer - flush line discipline receive buffers ++ * ldisc_receive_buf - pass receive data to line discipline ++ */ ++ ++static void ldisc_flush_buffer(struct tty_struct *tty) ++{ ++ struct tty_ldisc *ld = tty_ldisc_ref(tty); ++ if (ld) { ++ if (ld->flush_buffer) ++ ld->flush_buffer(tty); ++ tty_ldisc_deref(ld); ++ } ++} ++ ++static void ldisc_receive_buf(struct tty_struct *tty, ++ const __u8 *data, char *flags, int count) ++{ ++ struct tty_ldisc *ld; ++ if (!tty) ++ return; ++ ld = tty_ldisc_ref(tty); ++ if (ld) { ++ if (ld->receive_buf) ++ ld->receive_buf(tty, data, flags, count); ++ tty_ldisc_deref(ld); ++ } ++} ++ + static dev_link_t *mgslpc_attach(void) + { + MGSLPC_INFO *info; +@@ -984,13 +1018,7 @@ + printk("bh_transmit() entry on %s\n", info->device_name); + + if (tty) { +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- tty->ldisc.write_wakeup) { +- if ( debug_level >= DEBUG_LEVEL_BH ) +- printk( "%s(%d):calling ldisc.write_wakeup on %s\n", +- __FILE__,__LINE__,info->device_name); +- (tty->ldisc.write_wakeup)(tty); +- } ++ tty_wakeup(tty); + wake_up_interruptible(&tty->write_wait); + } + } +@@ -1875,11 +1903,9 @@ + info->tx_count = info->tx_put = info->tx_get = 0; + del_timer(&info->tx_timer); + spin_unlock_irqrestore(&info->lock,flags); +- ++ + wake_up_interruptible(&tty->write_wait); +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- tty->ldisc.write_wakeup) +- (tty->ldisc.write_wakeup)(tty); ++ tty_wakeup(tty); + } + + /* Send a high-priority XON/XOFF character +@@ -2588,9 +2614,8 @@ + + if (tty->driver->flush_buffer) + tty->driver->flush_buffer(tty); +- +- if (tty->ldisc.flush_buffer) +- tty->ldisc.flush_buffer(tty); ++ ++ ldisc_flush_buffer(tty); + + shutdown(info); + +@@ -4059,11 +4084,7 @@ + } + else + #endif +- { +- /* Call the line discipline receive callback directly. */ +- if (tty && tty->ldisc.receive_buf) +- tty->ldisc.receive_buf(tty, buf->data, info->flag_buf, framesize); +- } ++ ldisc_receive_buf(tty, buf->data, info->flag_buf, framesize); + } + } + +diff -Nur linux-2.6.8.1/drivers/char/pcxx.c linux-2.6.8.1-plasmaroo/drivers/char/pcxx.c +--- linux-2.6.8.1/drivers/char/pcxx.c 2004-08-14 11:55:34.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/char/pcxx.c 2004-11-06 22:55:10.705641440 +0000 +@@ -538,28 +538,11 @@ + + if(tty->driver->flush_buffer) + tty->driver->flush_buffer(tty); +- if(tty->ldisc.flush_buffer) +- tty->ldisc.flush_buffer(tty); ++ tty_ldisc_flush(tty); + shutdown(info); + tty->closing = 0; + info->event = 0; + info->tty = NULL; +-#ifndef MODULE +-/* ldiscs[] is not available in a MODULE +-** worth noting that while I'm not sure what this hunk of code is supposed +-** to do, it is not present in the serial.c driver. Hmmm. If you know, +-** please send me a note. brian@ilinx.com +-** Don't know either what this is supposed to do christoph@lameter.com. +-*/ +- if(tty->ldisc.num != ldiscs[N_TTY].num) { +- if(tty->ldisc.close) +- (tty->ldisc.close)(tty); +- tty->ldisc = ldiscs[N_TTY]; +- tty->termios->c_line = N_TTY; +- if(tty->ldisc.open) +- (tty->ldisc.open)(tty); +- } +-#endif + if(info->blocked_open) { + if(info->close_delay) { + current->state = TASK_INTERRUPTIBLE; +@@ -800,9 +783,7 @@ + memoff(ch); + restore_flags(flags); + +- wake_up_interruptible(&tty->write_wait); +- if((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) +- (tty->ldisc.write_wakeup)(tty); ++ tty_wakeup(tty); + } + + static void pcxe_flush_chars(struct tty_struct *tty) +@@ -1675,10 +1656,7 @@ + if (event & LOWTX_IND) { + if (ch->statusflags & LOWWAIT) { + ch->statusflags &= ~LOWWAIT; +- 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); + } + } + +@@ -1686,10 +1664,7 @@ + ch->statusflags &= ~TXBUSY; + if (ch->statusflags & EMPTYWAIT) { + ch->statusflags &= ~EMPTYWAIT; +- 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); + } + } + } +@@ -2165,8 +2140,7 @@ + tty_wait_until_sent(tty, 0); + } + else { +- if(tty->ldisc.flush_buffer) +- tty->ldisc.flush_buffer(tty); ++ tty_ldisc_flush(tty); + } + + /* Fall Thru */ +diff -Nur linux-2.6.8.1/drivers/char/pty.c linux-2.6.8.1-plasmaroo/drivers/char/pty.c +--- linux-2.6.8.1/drivers/char/pty.c 2004-08-14 11:55:10.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/char/pty.c 2004-11-06 22:55:10.707641136 +0000 +@@ -91,10 +91,7 @@ + if (!o_tty) + return; + +- if ((o_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- o_tty->ldisc.write_wakeup) +- (o_tty->ldisc.write_wakeup)(o_tty); +- wake_up_interruptible(&o_tty->write_wait); ++ tty_wakeup(o_tty); + set_bit(TTY_THROTTLED, &tty->flags); + } + +@@ -107,6 +104,10 @@ + * (2) avoid redundant copying for cases where count >> receive_room + * N.B. Calls from user space may now return an error code instead of + * a count. ++ * ++ * FIXME: Our pty_write method is called with our ldisc lock held but ++ * not our partners. We can't just take the other one blindly without ++ * risking deadlocks. There is also the small matter of TTY_DONT_FLIP + */ + static int pty_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +diff -Nur linux-2.6.8.1/drivers/char/riscom8.c linux-2.6.8.1-plasmaroo/drivers/char/riscom8.c +--- linux-2.6.8.1/drivers/char/riscom8.c 2004-08-14 11:55:31.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/char/riscom8.c 2004-11-06 22:55:10.723638704 +0000 +@@ -1127,8 +1127,8 @@ + rc_shutdown_port(bp, port); + if (tty->driver->flush_buffer) + tty->driver->flush_buffer(tty); +- if (tty->ldisc.flush_buffer) +- tty->ldisc.flush_buffer(tty); ++ tty_ldisc_flush(tty); ++ + tty->closing = 0; + port->event = 0; + port->tty = NULL; +@@ -1301,9 +1301,7 @@ + restore_flags(flags); + + wake_up_interruptible(&tty->write_wait); +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- tty->ldisc.write_wakeup) +- (tty->ldisc.write_wakeup)(tty); ++ tty_wakeup(tty); + } + + static int rc_tiocmget(struct tty_struct *tty, struct file *file) +@@ -1644,9 +1642,7 @@ + return; + + if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) { +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- tty->ldisc.write_wakeup) +- (tty->ldisc.write_wakeup)(tty); ++ tty_wakeup(tty); + wake_up_interruptible(&tty->write_wait); + } + } +diff -Nur linux-2.6.8.1/drivers/char/rocket.c linux-2.6.8.1-plasmaroo/drivers/char/rocket.c +--- linux-2.6.8.1/drivers/char/rocket.c 2004-08-14 11:55:47.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/char/rocket.c 2004-11-06 22:55:10.736636728 +0000 +@@ -250,12 +250,16 @@ + CHANNEL_t * cp, unsigned int ChanStatus) + { + unsigned int CharNStat; +- int ToRecv, wRecv, space, count; ++ int ToRecv, wRecv, space = 0, count; + unsigned char *cbuf; + char *fbuf; ++ struct tty_ldisc *ld; ++ ++ ld = tty_ldisc_ref(tty); + + ToRecv = sGetRxCnt(cp); +- space = tty->ldisc.receive_room(tty); ++ if (ld) ++ space = ld->receive_room(tty); + if (space > 2 * TTY_FLIPBUF_SIZE) + space = 2 * TTY_FLIPBUF_SIZE; + cbuf = tty->flip.char_buf; +@@ -354,7 +358,8 @@ + count += ToRecv; + } + /* Push the data up to the tty layer */ +- tty->ldisc.receive_buf(tty, tty->flip.char_buf, tty->flip.flag_buf, count); ++ ld->receive_buf(tty, tty->flip.char_buf, tty->flip.flag_buf, count); ++ tty_ldisc_deref(ld); + } + + /* +@@ -408,8 +413,7 @@ + clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); + + if (info->xmit_cnt < WAKEUP_CHARS) { +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) +- (tty->ldisc.write_wakeup) (tty); ++ tty_wakeup(tty); + wake_up_interruptible(&tty->write_wait); + #ifdef ROCKETPORT_HAVE_POLL_WAIT + wake_up_interruptible(&tty->poll_wait); +@@ -1022,7 +1026,7 @@ + unsigned long flags; + int timeout; + CHANNEL_t *cp; +- ++ + if (rocket_paranoia_check(info, "rp_close")) + return; + +@@ -1101,8 +1105,8 @@ + + if (TTY_DRIVER_FLUSH_BUFFER_EXISTS(tty)) + TTY_DRIVER_FLUSH_BUFFER(tty); +- if (tty->ldisc.flush_buffer) +- tty->ldisc.flush_buffer(tty); ++ ++ tty_ldisc_flush(tty); + + clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); + +@@ -1731,8 +1735,7 @@ + + end: + if (info->xmit_cnt < WAKEUP_CHARS) { +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) +- (tty->ldisc.write_wakeup) (tty); ++ tty_wakeup(tty); + wake_up_interruptible(&tty->write_wait); + #ifdef ROCKETPORT_HAVE_POLL_WAIT + wake_up_interruptible(&tty->poll_wait); +@@ -1806,8 +1809,7 @@ + #ifdef ROCKETPORT_HAVE_POLL_WAIT + wake_up_interruptible(&tty->poll_wait); + #endif +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) +- (tty->ldisc.write_wakeup) (tty); ++ tty_wakeup(tty); + + cp = &info->channel; + sFlushTxFIFO(cp); +diff -Nur linux-2.6.8.1/drivers/char/selection.c linux-2.6.8.1-plasmaroo/drivers/char/selection.c +--- linux-2.6.8.1/drivers/char/selection.c 2004-08-14 11:56:22.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/char/selection.c 2004-11-06 22:55:10.747635056 +0000 +@@ -281,12 +281,15 @@ + { + struct vt_struct *vt = (struct vt_struct *) tty->driver_data; + int pasted = 0, count; ++ struct tty_ldisc *ld; + DECLARE_WAITQUEUE(wait, current); + + acquire_console_sem(); + poke_blanked_console(); + release_console_sem(); + ++ ld = tty_ldisc_ref_wait(tty); ++ + add_wait_queue(&vt->paste_wait, &wait); + while (sel_buffer && sel_buffer_lth > pasted) { + set_current_state(TASK_INTERRUPTIBLE); +@@ -301,6 +304,8 @@ + } + remove_wait_queue(&vt->paste_wait, &wait); + current->state = TASK_RUNNING; ++ ++ tty_ldisc_deref(ld); + return 0; + } + +diff -Nur linux-2.6.8.1/drivers/char/ser_a2232.c linux-2.6.8.1-plasmaroo/drivers/char/ser_a2232.c +--- linux-2.6.8.1/drivers/char/ser_a2232.c 2004-08-14 11:55:09.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/char/ser_a2232.c 2004-11-06 22:55:10.748634904 +0000 +@@ -599,10 +599,7 @@ + + /* WakeUp if output buffer runs low */ + if ((port->gs.xmit_cnt <= port->gs.wakeup_chars) && port->gs.tty) { +- if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && port->gs.tty->ldisc.write_wakeup){ +- (port->gs.tty->ldisc.write_wakeup)(port->gs.tty); +- } +- wake_up_interruptible(&port->gs.tty->write_wait); ++ tty_wakeup(port->gs.tty); + } + } // if the port is used + } // for every port on the board +diff -Nur linux-2.6.8.1/drivers/char/serial167.c linux-2.6.8.1-plasmaroo/drivers/char/serial167.c +--- linux-2.6.8.1/drivers/char/serial167.c 2004-08-14 11:55:20.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/char/serial167.c 2004-11-06 22:55:10.756633688 +0000 +@@ -760,11 +760,7 @@ + wake_up_interruptible(&info->open_wait); + } + if (test_and_clear_bit(Cy_EVENT_WRITE_WAKEUP, &info->event)) { +- 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); + } + } /* do_softint */ + +@@ -1343,10 +1339,7 @@ + local_irq_save(flags); + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + local_irq_restore(flags); +- wake_up_interruptible(&tty->write_wait); +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) +- && tty->ldisc.write_wakeup) +- (tty->ldisc.write_wakeup)(tty); ++ tty_wakeup(tty); + } /* cy_flush_buffer */ + + +@@ -1846,18 +1839,9 @@ + shutdown(info); + if (tty->driver->flush_buffer) + tty->driver->flush_buffer(tty); +- if (tty->ldisc.flush_buffer) +- tty->ldisc.flush_buffer(tty); ++ tty_ldisc_flush(tty); + info->event = 0; + info->tty = 0; +- if (tty->ldisc.num != ldiscs[N_TTY].num) { +- if (tty->ldisc.close) +- (tty->ldisc.close)(tty); +- tty->ldisc = ldiscs[N_TTY]; +- tty->termios->c_line = N_TTY; +- if (tty->ldisc.open) +- (tty->ldisc.open)(tty); +- } + if (info->blocked_open) { + if (info->close_delay) { + current->state = TASK_INTERRUPTIBLE; +diff -Nur linux-2.6.8.1/drivers/char/serial_tx3912.c linux-2.6.8.1-plasmaroo/drivers/char/serial_tx3912.c +--- linux-2.6.8.1/drivers/char/serial_tx3912.c 2004-08-14 11:55:33.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/char/serial_tx3912.c 2004-11-06 22:55:10.758633384 +0000 +@@ -191,12 +191,9 @@ + } + + if (port->gs.xmit_cnt <= port->gs.wakeup_chars) { +- if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- port->gs.tty->ldisc.write_wakeup) +- (port->gs.tty->ldisc.write_wakeup)(port->gs.tty); ++ tty_wakeup(port->gs.tty); + rs_dprintk (TX3912_UART_DEBUG_TRANSMIT, "Waking up.... ldisc (%d)....\n", + port->gs.wakeup_chars); +- wake_up_interruptible(&port->gs.tty->write_wait); + } + } + +diff -Nur linux-2.6.8.1/drivers/char/specialix.c linux-2.6.8.1-plasmaroo/drivers/char/specialix.c +--- linux-2.6.8.1/drivers/char/specialix.c 2004-08-14 11:56:09.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/char/specialix.c 2004-11-06 22:55:10.762632776 +0000 +@@ -1468,8 +1468,7 @@ + sx_shutdown_port(bp, port); + if (tty->driver->flush_buffer) + tty->driver->flush_buffer(tty); +- if (tty->ldisc.flush_buffer) +- tty->ldisc.flush_buffer(tty); ++ tty_ldisc_flush(tty); + tty->closing = 0; + port->event = 0; + port->tty = NULL; +@@ -1646,10 +1645,8 @@ + port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; + restore_flags(flags); + ++ tty_wakeup(tty); + wake_up_interruptible(&tty->write_wait); +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- tty->ldisc.write_wakeup) +- (tty->ldisc.write_wakeup)(tty); + } + + +@@ -2052,12 +2049,8 @@ + if(!(tty = port->tty)) + return; + +- if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) { +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- tty->ldisc.write_wakeup) +- (tty->ldisc.write_wakeup)(tty); +- wake_up_interruptible(&tty->write_wait); +- } ++ if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) ++ tty_wakeup(tty); + } + + static struct tty_operations sx_ops = { +diff -Nur linux-2.6.8.1/drivers/char/stallion.c linux-2.6.8.1-plasmaroo/drivers/char/stallion.c +--- linux-2.6.8.1/drivers/char/stallion.c 2004-08-14 11:55:48.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/char/stallion.c 2004-11-06 22:55:10.774630952 +0000 +@@ -1197,8 +1197,7 @@ + portp->tx.tail = (char *) NULL; + } + set_bit(TTY_IO_ERROR, &tty->flags); +- if (tty->ldisc.flush_buffer) +- (tty->ldisc.flush_buffer)(tty); ++ tty_ldisc_flush(tty); + + tty->closing = 0; + portp->tty = (struct tty_struct *) NULL; +@@ -1809,10 +1808,7 @@ + return; + + stl_flush(portp); +- wake_up_interruptible(&tty->write_wait); +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- tty->ldisc.write_wakeup) +- (tty->ldisc.write_wakeup)(tty); ++ tty_wakeup(tty); + } + + /*****************************************************************************/ +@@ -2193,10 +2189,7 @@ + + lock_kernel(); + if (test_bit(ASYI_TXLOW, &portp->istate)) { +- 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); + } + if (test_bit(ASYI_DCDCHANGE, &portp->istate)) { + clear_bit(ASYI_DCDCHANGE, &portp->istate); +diff -Nur linux-2.6.8.1/drivers/char/sx.c linux-2.6.8.1-plasmaroo/drivers/char/sx.c +--- linux-2.6.8.1/drivers/char/sx.c 2004-08-14 11:55:19.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/char/sx.c 2004-11-06 22:55:10.777630496 +0000 +@@ -1046,12 +1046,9 @@ + } + + if ((port->gs.xmit_cnt <= port->gs.wakeup_chars) && port->gs.tty) { +- if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- port->gs.tty->ldisc.write_wakeup) +- (port->gs.tty->ldisc.write_wakeup)(port->gs.tty); ++ tty_wakeup(port->gs.tty); + sx_dprintk (SX_DEBUG_TRANSMIT, "Waking up.... ldisc (%d)....\n", + port->gs.wakeup_chars); +- wake_up_interruptible(&port->gs.tty->write_wait); + } + + clear_bit (SX_PORT_TRANSMIT_LOCK, &port->locks); +diff -Nur linux-2.6.8.1/drivers/char/synclink.c linux-2.6.8.1-plasmaroo/drivers/char/synclink.c +--- linux-2.6.8.1/drivers/char/synclink.c 2004-08-14 11:55:10.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/char/synclink.c 2004-11-06 22:55:10.794627912 +0000 +@@ -993,6 +993,29 @@ + return 0; + } + ++/** ++ * line discipline callback wrappers ++ * ++ * The wrappers maintain line discipline references ++ * while calling into the line discipline. ++ * ++ * ldisc_receive_buf - pass receive data to line discipline ++ */ ++ ++static void ldisc_receive_buf(struct tty_struct *tty, ++ const __u8 *data, char *flags, int count) ++{ ++ struct tty_ldisc *ld; ++ if (!tty) ++ return; ++ ld = tty_ldisc_ref(tty); ++ if (ld) { ++ if (ld->receive_buf) ++ ld->receive_buf(tty, data, flags, count); ++ tty_ldisc_deref(ld); ++ } ++} ++ + /* mgsl_stop() throttle (stop) transmitter + * + * Arguments: tty pointer to tty info structure +@@ -1153,13 +1176,7 @@ + __FILE__,__LINE__,info->device_name); + + if (tty) { +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- tty->ldisc.write_wakeup) { +- if ( debug_level >= DEBUG_LEVEL_BH ) +- printk( "%s(%d):calling ldisc.write_wakeup on %s\n", +- __FILE__,__LINE__,info->device_name); +- (tty->ldisc.write_wakeup)(tty); +- } ++ tty_wakeup(tty); + wake_up_interruptible(&tty->write_wait); + } + +@@ -2415,11 +2432,8 @@ + spin_unlock_irqrestore(&info->irq_spinlock,flags); + + wake_up_interruptible(&tty->write_wait); +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- tty->ldisc.write_wakeup) +- (tty->ldisc.write_wakeup)(tty); +- +-} /* end of mgsl_flush_buffer() */ ++ tty_wakeup(tty); ++} + + /* mgsl_send_xchar() + * +@@ -3253,9 +3267,8 @@ + + if (tty->driver->flush_buffer) + tty->driver->flush_buffer(tty); +- +- if (tty->ldisc.flush_buffer) +- tty->ldisc.flush_buffer(tty); ++ ++ tty_ldisc_flush(tty); + + shutdown(info); + +@@ -6830,11 +6843,7 @@ + } + else + #endif +- { +- /* Call the line discipline receive callback directly. */ +- if ( tty && tty->ldisc.receive_buf ) +- tty->ldisc.receive_buf(tty, info->intermediate_rxbuffer, info->flag_buf, framesize); +- } ++ ldisc_receive_buf(tty, info->intermediate_rxbuffer, info->flag_buf, framesize); + } + } + /* Free the buffers used by this frame. */ +@@ -7006,9 +7015,7 @@ + memcpy( info->intermediate_rxbuffer, pBufEntry->virt_addr, framesize); + info->icount.rxok++; + +- /* Call the line discipline receive callback directly. */ +- if ( tty && tty->ldisc.receive_buf ) +- tty->ldisc.receive_buf(tty, info->intermediate_rxbuffer, info->flag_buf, framesize); ++ ldisc_receive_buf(tty, info->intermediate_rxbuffer, info->flag_buf, framesize); + } + + /* Free the buffers used by this frame. */ +diff -Nur linux-2.6.8.1/drivers/char/synclinkmp.c linux-2.6.8.1-plasmaroo/drivers/char/synclinkmp.c +--- linux-2.6.8.1/drivers/char/synclinkmp.c 2004-08-14 11:54:51.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/char/synclinkmp.c 2004-11-06 22:55:10.802626696 +0000 +@@ -722,6 +722,29 @@ + return 0; + } + ++/** ++ * line discipline callback wrappers ++ * ++ * The wrappers maintain line discipline references ++ * while calling into the line discipline. ++ * ++ * ldisc_receive_buf - pass receive data to line discipline ++ */ ++ ++static void ldisc_receive_buf(struct tty_struct *tty, ++ const __u8 *data, char *flags, int count) ++{ ++ struct tty_ldisc *ld; ++ if (!tty) ++ return; ++ ld = tty_ldisc_ref(tty); ++ if (ld) { ++ if (ld->receive_buf) ++ ld->receive_buf(tty, data, flags, count); ++ tty_ldisc_deref(ld); ++ } ++} ++ + /* tty callbacks */ + + /* Called when a port is opened. Init and enable port. +@@ -869,8 +892,7 @@ + if (tty->driver->flush_buffer) + tty->driver->flush_buffer(tty); + +- if (tty->ldisc.flush_buffer) +- tty->ldisc.flush_buffer(tty); ++ tty_ldisc_flush(tty); + + shutdown(info); + +@@ -1275,9 +1297,7 @@ + spin_unlock_irqrestore(&info->lock,flags); + + wake_up_interruptible(&tty->write_wait); +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- tty->ldisc.write_wakeup) +- (tty->ldisc.write_wakeup)(tty); ++ tty_wakeup(tty); + } + + /* throttle (stop) transmitter +@@ -1941,13 +1961,7 @@ + __FILE__,__LINE__,info->device_name); + + if (tty) { +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- tty->ldisc.write_wakeup) { +- if ( debug_level >= DEBUG_LEVEL_BH ) +- printk( "%s(%d):%s calling ldisc.write_wakeup\n", +- __FILE__,__LINE__,info->device_name); +- (tty->ldisc.write_wakeup)(tty); +- } ++ tty_wakeup(tty); + wake_up_interruptible(&tty->write_wait); + } + } +@@ -4869,15 +4883,8 @@ + } + else + #endif +- { +- if ( tty && tty->ldisc.receive_buf ) { +- /* Call the line discipline receive callback directly. */ +- tty->ldisc.receive_buf(tty, +- info->tmp_rx_buf, +- info->flag_buf, +- framesize); +- } +- } ++ ldisc_receive_buf(tty,info->tmp_rx_buf, ++ info->flag_buf, framesize); + } + } + /* Free the buffers used by this frame. */ +diff -Nur linux-2.6.8.1/drivers/char/tty_io.c linux-2.6.8.1-plasmaroo/drivers/char/tty_io.c +--- linux-2.6.8.1/drivers/char/tty_io.c 2004-08-14 11:55:34.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/char/tty_io.c 2004-11-06 22:57:19.465067032 +0000 +@@ -92,6 +92,7 @@ + #include <linux/smp_lock.h> + #include <linux/device.h> + #include <linux/idr.h> ++#include <linux/wait.h> + + #include <asm/uaccess.h> + #include <asm/system.h> +@@ -120,11 +121,17 @@ + + EXPORT_SYMBOL(tty_std_termios); + ++/* This list gets poked at by procfs and various bits of boot up code. This ++ could do with some rationalisation such as pulling the tty proc function ++ into this file */ ++ + LIST_HEAD(tty_drivers); /* linked list of tty drivers */ +-struct tty_ldisc ldiscs[NR_LDISCS]; /* line disc dispatch table */ + +-/* Semaphore to protect creating and releasing a tty */ ++/* Semaphore to protect creating and releasing a tty. This is shared with ++ vt.c for deeply disgusting hack reasons */ + DECLARE_MUTEX(tty_sem); ++/* Lock for tty_termios changes - private to tty_io/tty_ioctl */ ++spinlock_t tty_termios_lock = SPIN_LOCK_UNLOCKED; + + #ifdef CONFIG_UNIX98_PTYS + extern struct tty_driver *ptm_driver; /* Unix98 pty masters; for /dev/ptmx */ +@@ -223,65 +230,324 @@ + return 0; + } + ++/* ++ * This is probably overkill for real world processors but ++ * they are not on hot paths so a little discipline won't do ++ * any harm. ++ */ ++ ++static void tty_set_termios_ldisc(struct tty_struct *tty, int num) ++{ ++ unsigned long flags; ++ spin_lock_irqsave(&tty_termios_lock, flags); ++ tty->termios->c_line = num; ++ spin_unlock_irqrestore(&tty_termios_lock, flags); ++} ++ ++/* ++ * This guards the refcounted line discipline lists. The lock ++ * must be taken with irqs off because there are hangup path ++ * callers who will do ldisc lookups and cannot sleep. ++ */ ++ ++static spinlock_t tty_ldisc_lock = SPIN_LOCK_UNLOCKED; ++static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait); ++static struct tty_ldisc tty_ldiscs[NR_LDISCS]; /* line disc dispatch table */ ++ + int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc) + { ++ unsigned long flags; ++ int ret = 0; ++ + if (disc < N_TTY || disc >= NR_LDISCS) + return -EINVAL; + ++ spin_lock_irqsave(&tty_ldisc_lock, flags); + if (new_ldisc) { +- ldiscs[disc] = *new_ldisc; +- ldiscs[disc].flags |= LDISC_FLAG_DEFINED; +- ldiscs[disc].num = disc; +- } else +- memset(&ldiscs[disc], 0, sizeof(struct tty_ldisc)); ++ tty_ldiscs[disc] = *new_ldisc; ++ tty_ldiscs[disc].num = disc; ++ tty_ldiscs[disc].flags |= LDISC_FLAG_DEFINED; ++ tty_ldiscs[disc].refcount = 0; ++ } else { ++ if(tty_ldiscs[disc].refcount) ++ ret = -EBUSY; ++ else ++ tty_ldiscs[disc].flags &= ~LDISC_FLAG_DEFINED; ++ } ++ spin_unlock_irqrestore(&tty_ldisc_lock, flags); + +- return 0; ++ return ret; + } + + EXPORT_SYMBOL(tty_register_ldisc); + +-/* Set the discipline of a tty line. */ ++struct tty_ldisc *tty_ldisc_get(int disc) ++{ ++ unsigned long flags; ++ struct tty_ldisc *ld; ++ ++ 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; ++} ++ ++EXPORT_SYMBOL_GPL(tty_ldisc_get); ++ ++void tty_ldisc_put(int disc) ++{ ++ struct tty_ldisc *ld; ++ unsigned long flags; ++ ++ if (disc < N_TTY || disc >= NR_LDISCS) ++ BUG(); ++ ++ spin_lock_irqsave(&tty_ldisc_lock, flags); ++ ld = &tty_ldiscs[disc]; ++ if(ld->refcount == 0) ++ BUG(); ++ ld->refcount --; ++ module_put(ld->owner); ++ spin_unlock_irqrestore(&tty_ldisc_lock, flags); ++} ++ ++EXPORT_SYMBOL_GPL(tty_ldisc_put); ++ ++void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld) ++{ ++ tty->ldisc = *ld; ++ tty->ldisc.refcount = 0; ++} ++ ++/** ++ * tty_ldisc_try - internal helper ++ * @tty: the tty ++ * ++ * Make a single attempt to grab and bump the refcount on ++ * 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 ++ */ ++ ++static int tty_ldisc_try(struct tty_struct *tty) ++{ ++ unsigned long flags; ++ struct tty_ldisc *ld; ++ int ret = 0; ++ ++ spin_lock_irqsave(&tty_ldisc_lock, flags); ++ ld = &tty->ldisc; ++ if(test_bit(TTY_LDISC, &tty->flags)) ++ { ++ ld->refcount++; ++ ret = 1; ++ } ++ spin_unlock_irqrestore(&tty_ldisc_lock, flags); ++ return ret; ++} ++ ++/** ++ * tty_ldisc_ref_wait - wait for the tty ldisc ++ * @tty: tty device ++ * ++ * Dereference the line discipline for the terminal and take a ++ * reference to it. If the line discipline is in flux then ++ * wait patiently until it changes. ++ * ++ * Note: Must not be called from an IRQ/timer context. The caller ++ * 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) ++ */ ++ ++struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty) ++{ ++ /* wait_event is a macro */ ++ wait_event(tty_ldisc_wait, tty_ldisc_try(tty)); ++ if(tty->ldisc.refcount == 0) ++ printk(KERN_ERR "tty_ldisc_ref_wait\n"); ++ return &tty->ldisc; ++} ++ ++EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait); ++ ++/** ++ * tty_ldisc_ref - get the tty ldisc ++ * @tty: tty device ++ * ++ * 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. ++ */ ++ ++struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty) ++{ ++ if(tty_ldisc_try(tty)) ++ return &tty->ldisc; ++ return NULL; ++} ++ ++EXPORT_SYMBOL_GPL(tty_ldisc_ref); ++ ++/** ++ * tty_ldisc_deref - free a tty ldisc reference ++ * @ld: reference to free up ++ * ++ * Undoes the effect of tty_ldisc_ref or tty_ldisc_ref_wait. May ++ * be called in IRQ context. ++ */ ++ ++void tty_ldisc_deref(struct tty_ldisc *ld) ++{ ++ unsigned long flags; ++ ++ if(ld == NULL) ++ BUG(); ++ ++ spin_lock_irqsave(&tty_ldisc_lock, flags); ++ if(ld->refcount == 0) ++ printk(KERN_ERR "tty_ldisc_deref: no references.\n"); ++ else ++ ld->refcount--; ++ if(ld->refcount == 0) ++ wake_up(&tty_ldisc_wait); ++ spin_unlock_irqrestore(&tty_ldisc_lock, flags); ++} ++ ++EXPORT_SYMBOL_GPL(tty_ldisc_deref); ++ ++/** ++ * tty_ldisc_enable - allow ldisc use ++ * @tty: terminal to activate ldisc on ++ * ++ * Set the TTY_LDISC flag when the line discipline can be called ++ * again. Do neccessary wakeups for existing sleepers. ++ * ++ * Note: nobody should set this bit except via this function. Clearing ++ * directly is allowed. ++ */ ++ ++static void tty_ldisc_enable(struct tty_struct *tty) ++{ ++ set_bit(TTY_LDISC, &tty->flags); ++ wake_up(&tty_ldisc_wait); ++} ++ ++/** ++ * tty_set_ldisc - set line discipline ++ * @tty: the terminal to set ++ * @ldisc: the line discipline ++ * ++ * Set the discipline of a tty line. Must be called from a process ++ * context. ++ */ ++ + static int tty_set_ldisc(struct tty_struct *tty, int ldisc) + { + int retval = 0; + struct tty_ldisc o_ldisc; + char buf[64]; ++ int work; ++ unsigned long flags; ++ struct tty_ldisc *ld; + + if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS)) + return -EINVAL; ++ ++restart: ++ ++ if (tty->ldisc.num == ldisc) ++ return 0; /* We are already in the desired discipline */ ++ ++ ld = tty_ldisc_get(ldisc); + /* Eduardo Blanco <ejbs@cs.cs.com.uy> */ + /* Cyrus Durgin <cider@speakeasy.org> */ +- if (!(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED)) { ++ if (ld == NULL) { + request_module("tty-ldisc-%d", ldisc); ++ ld = tty_ldisc_get(ldisc); + } +- if (!(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED)) ++ if (ld == NULL) + return -EINVAL; + +- if (tty->ldisc.num == ldisc) +- return 0; /* We are already in the desired discipline */ +- +- if (!try_module_get(ldiscs[ldisc].owner)) +- return -EINVAL; +- + o_ldisc = tty->ldisc; + + tty_wait_until_sent(tty, 0); ++ ++ /* ++ * Make sure we don't change while someone holds a ++ * reference to the line discipline. The TTY_LDISC bit ++ * prevents anyone taking a reference once it is clear. ++ * We need the lock to avoid racing reference takers. ++ */ ++ ++ spin_lock_irqsave(&tty_ldisc_lock, flags); ++ if(tty->ldisc.refcount) ++ { ++ /* Free the new ldisc we grabbed. Must drop the lock ++ first. */ ++ spin_unlock_irqrestore(&tty_ldisc_lock, flags); ++ tty_ldisc_put(ldisc); ++ /* ++ * There are several reasons we may be busy, including ++ * random momentary I/O traffic. We must therefore ++ * retry. We could distinguish between blocking ops ++ * and retries if we made tty_ldisc_wait() smarter. That ++ * is up for discussion. ++ */ ++ if(wait_event_interruptible(tty_ldisc_wait, tty->ldisc.refcount == 0) < 0) ++ return -ERESTARTSYS; ++ goto restart; ++ } ++ clear_bit(TTY_LDISC, &tty->flags); ++ clear_bit(TTY_DONT_FLIP, &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 ++ * we say so later on. ++ */ ++ ++ work = cancel_delayed_work(&tty->flip.work); ++ /* ++ * Wait for ->hangup_work and ->flip.work handlers to terminate ++ */ ++ ++ flush_scheduled_work(); + /* Shutdown the current discipline. */ + if (tty->ldisc.close) + (tty->ldisc.close)(tty); + + /* Now set up the new line discipline. */ +- tty->ldisc = ldiscs[ldisc]; +- tty->termios->c_line = ldisc; ++ tty_ldisc_assign(tty, ld); ++ tty_set_termios_ldisc(tty, ldisc); + if (tty->ldisc.open) + retval = (tty->ldisc.open)(tty); + if (retval < 0) { +- tty->ldisc = o_ldisc; +- tty->termios->c_line = tty->ldisc.num; ++ 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 = ldiscs[N_TTY]; +- tty->termios->c_line = N_TTY; ++ 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); + +@@ -291,12 +557,27 @@ + tty_name(tty, buf), r); + } + } +- } else { +- module_put(o_ldisc.owner); + } ++ /* 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->driver->set_ldisc) + tty->driver->set_ldisc(tty); ++ ++ tty_ldisc_put(o_ldisc.num); ++ ++ /* ++ * Allow ldisc referencing to occur as soon as the driver ++ * ldisc callback completes. ++ */ ++ ++ tty_ldisc_enable(tty); ++ ++ /* Restart it in case no characters kick it off. Safe if ++ already running */ ++ if(work) ++ schedule_delayed_work(&tty->flip.work, 1); + return retval; + } + +@@ -399,6 +680,53 @@ + + static spinlock_t redirect_lock = SPIN_LOCK_UNLOCKED; + static struct file *redirect; ++ ++/** ++ * tty_wakeup - request more data ++ * @tty: terminal ++ * ++ * Internal and external helper for wakeups of tty. This function ++ * informs the line discipline if present that the driver is ready ++ * to receive more output data. ++ */ ++ ++void tty_wakeup(struct tty_struct *tty) ++{ ++ struct tty_ldisc *ld; ++ ++ if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) { ++ ld = tty_ldisc_ref(tty); ++ if(ld) { ++ if(ld->write_wakeup) ++ ld->write_wakeup(tty); ++ tty_ldisc_deref(ld); ++ } ++ } ++ wake_up_interruptible(&tty->write_wait); ++} ++ ++EXPORT_SYMBOL_GPL(tty_wakeup); ++ ++/** ++ * tty_ldisc_flush - flush line discipline queue ++ * @tty: tty ++ * ++ * Flush the line discipline queue (if any) for this tty. If there ++ * is no line discipline active this is a no-op. ++ */ ++ ++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); ++ tty_ldisc_deref(ld); ++ } ++} ++ ++EXPORT_SYMBOL_GPL(tty_ldisc_flush); ++ + /* + * 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 +@@ -410,6 +738,7 @@ + struct file * cons_filp = NULL; + struct file *filp, *f = NULL; + struct task_struct *p; ++ struct tty_ldisc *ld; + struct pid *pid; + int closecount = 0, n; + +@@ -428,6 +757,7 @@ + + check_tty_count(tty, "do_tty_hangup"); + file_list_lock(); ++ /* This breaks for file handles being sent over AF_UNIX sockets ? */ + list_for_each_entry(filp, &tty->tty_files, f_list) { + if (filp->f_op->write == redirected_tty_write) + cons_filp = filp; +@@ -440,21 +770,25 @@ + file_list_unlock(); + + /* FIXME! What are the locking issues here? This may me overdoing things.. +- * this question is especially important now that we've removed the irqlock. */ +- { +- unsigned long flags; ++ * this question is especially important now that we've removed the irqlock. */ + +- local_irq_save(flags); // FIXME: is this safe? +- if (tty->ldisc.flush_buffer) +- tty->ldisc.flush_buffer(tty); ++ 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 (tty->driver->flush_buffer) + tty->driver->flush_buffer(tty); + if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) && +- tty->ldisc.write_wakeup) +- (tty->ldisc.write_wakeup)(tty); +- local_irq_restore(flags); // FIXME: is this safe? ++ ld->write_wakeup) ++ ld->write_wakeup(tty); ++ if (ld->hangup) ++ ld->hangup(tty); + } + ++ /* FIXME: Once we trust the LDISC code better we can wait here for ++ ldisc completion and fix the driver call race */ ++ + wake_up_interruptible(&tty->write_wait); + wake_up_interruptible(&tty->read_wait); + +@@ -463,22 +797,19 @@ + * N_TTY. + */ + if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) ++ { ++ unsigned long flags; ++ spin_lock_irqsave(&tty_termios_lock, flags); + *tty->termios = tty->driver->init_termios; +- if (tty->ldisc.num != ldiscs[N_TTY].num) { +- if (tty->ldisc.close) +- (tty->ldisc.close)(tty); +- module_put(tty->ldisc.owner); +- +- tty->ldisc = ldiscs[N_TTY]; +- tty->termios->c_line = N_TTY; +- if (tty->ldisc.open) { +- int i = (tty->ldisc.open)(tty); +- if (i < 0) +- printk(KERN_ERR "do_tty_hangup: N_TTY open: " +- "error %d\n", -i); +- } ++ spin_unlock_irqrestore(&tty_termios_lock, flags); + } + ++ /* Defer ldisc switch */ ++ /* tty_deferred_ldisc_switch(N_TTY); ++ ++ This should get done automatically when the port closes and ++ tty_release is called */ ++ + read_lock(&tasklist_lock); + if (tty->session > 0) { + struct list_head *l; +@@ -511,6 +842,17 @@ + tty->driver->close(tty, cons_filp); + } else if (tty->driver->hangup) + (tty->driver->hangup)(tty); ++ ++ /* We don't want to have driver/ldisc interactions beyond ++ the ones we did here. The driver layer expects no ++ calls after ->hangup() from the ldisc side. However we ++ can't yet guarantee all that */ ++ ++ set_bit(TTY_HUPPED, &tty->flags); ++ if (ld) { ++ tty_ldisc_enable(tty); ++ tty_ldisc_deref(ld); ++ } + unlock_kernel(); + if (f) + fput(f); +@@ -627,9 +969,9 @@ + } + if (tty->driver->start) + (tty->driver->start)(tty); +- if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) && +- tty->ldisc.write_wakeup) +- (tty->ldisc.write_wakeup)(tty); ++ ++ /* If we have a running line discipline it may need kicking */ ++ tty_wakeup(tty); + wake_up_interruptible(&tty->write_wait); + } + +@@ -641,6 +983,7 @@ + int i; + struct tty_struct * tty; + struct inode *inode; ++ struct tty_ldisc *ld; + + tty = (struct tty_struct *)file->private_data; + inode = file->f_dentry->d_inode; +@@ -649,11 +992,15 @@ + if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags))) + return -EIO; + ++ /* We want to wait for the line discipline to sort out in this ++ situation */ ++ ld = tty_ldisc_ref_wait(tty); + lock_kernel(); +- if (tty->ldisc.read) +- i = (tty->ldisc.read)(tty,file,buf,count); ++ if (ld->read) ++ i = (ld->read)(tty,file,buf,count); + else + i = -EIO; ++ tty_ldisc_deref(ld); + unlock_kernel(); + if (i > 0) + inode->i_atime = CURRENT_TIME; +@@ -715,16 +1062,23 @@ + { + struct tty_struct * tty; + struct inode *inode = file->f_dentry->d_inode; +- ++ ssize_t ret; ++ struct tty_ldisc *ld; ++ + tty = (struct tty_struct *)file->private_data; + if (tty_paranoia_check(tty, inode, "tty_write")) + return -EIO; + if (!tty || !tty->driver->write || (test_bit(TTY_IO_ERROR, &tty->flags))) + return -EIO; +- if (!tty->ldisc.write) +- return -EIO; +- return do_tty_write(tty->ldisc.write, tty, file, ++ ++ ld = tty_ldisc_ref_wait(tty); ++ if (!ld->write) ++ ret = -EIO; ++ else ++ ret = do_tty_write(ld->write, tty, file, + (const unsigned char __user *)buf, count); ++ tty_ldisc_deref(ld); ++ return ret; + } + + ssize_t redirected_tty_write(struct file * file, const char __user * buf, size_t count, +@@ -910,6 +1264,7 @@ + * If we fail here just call release_mem to clean up. No need + * to decrement the use counts, as release_mem doesn't care. + */ ++ + if (tty->ldisc.open) { + retval = (tty->ldisc.open)(tty); + if (retval) +@@ -922,7 +1277,9 @@ + (tty->ldisc.close)(tty); + goto release_mem_out; + } ++ tty_ldisc_enable(o_tty); + } ++ tty_ldisc_enable(tty); + goto success; + + /* +@@ -951,6 +1308,9 @@ + tty->count++; + tty->driver = driver; /* N.B. why do this every time?? */ + ++ /* FIXME */ ++ if(!test_bit(TTY_LDISC, &tty->flags)) ++ printk(KERN_ERR "init_dev but no ldisc\n"); + success: + *ret_tty = tty; + +@@ -1054,6 +1414,7 @@ + int devpts_master, devpts; + int idx; + char buf[64]; ++ unsigned long flags; + + tty = (struct tty_struct *)filp->private_data; + if (tty_paranoia_check(tty, filp->f_dentry->d_inode, "release_dev")) +@@ -1130,7 +1491,6 @@ + } + } + #endif +- + if (tty->driver->close) + tty->driver->close(tty, filp); + +@@ -1254,36 +1614,58 @@ + #ifdef TTY_DEBUG_HANGUP + printk(KERN_DEBUG "freeing tty structure..."); + #endif +- + /* + * Prevent flush_to_ldisc() from rescheduling the work for later. Then +- * kill any delayed work. ++ * kill any delayed work. As this is the final close it does not ++ * race with the set_ldisc code path. + */ ++ clear_bit(TTY_LDISC, &tty->flags); + clear_bit(TTY_DONT_FLIP, &tty->flags); + cancel_delayed_work(&tty->flip.work); + + /* + * Wait for ->hangup_work and ->flip.work handlers to terminate + */ ++ + flush_scheduled_work(); +- ++ ++ /* ++ * Wait for any short term users (we know they are just driver ++ * side waiters as the file is closing so user count on the file ++ * side is zero. ++ */ ++ spin_lock_irqsave(&tty_ldisc_lock, flags); ++ while(tty->ldisc.refcount) ++ { ++ spin_unlock_irqrestore(&tty_ldisc_lock, flags); ++ wait_event(tty_ldisc_wait, tty->ldisc.refcount == 0); ++ spin_lock_irqsave(&tty_ldisc_lock, flags); ++ } ++ 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); +- module_put(tty->ldisc.owner); ++ tty_ldisc_put(tty->ldisc.num); + +- tty->ldisc = ldiscs[N_TTY]; +- tty->termios->c_line = N_TTY; ++ /* ++ * Switch the line discipline back ++ */ ++ tty_ldisc_assign(tty, tty_ldisc_get(N_TTY)); ++ 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); +- module_put(o_tty->ldisc.owner); +- o_tty->ldisc = ldiscs[N_TTY]; ++ tty_ldisc_put(o_tty->ldisc.num); ++ tty_ldisc_assign(o_tty, tty_ldisc_get(N_TTY)); ++ tty_set_termios_ldisc(o_tty,N_TTY); + } +- + /* + * The release_mem function takes care of the details of clearing + * the slots and preserving the termios structure. +@@ -1323,6 +1705,7 @@ + unsigned short saved_flags = filp->f_flags; + + nonseekable_open(inode, filp); ++ + retry_open: + noctty = filp->f_flags & O_NOCTTY; + index = -1; +@@ -1479,14 +1862,18 @@ + static unsigned int tty_poll(struct file * filp, poll_table * wait) + { + struct tty_struct * tty; ++ struct tty_ldisc *ld; ++ int ret = 0; + + tty = (struct tty_struct *)filp->private_data; + if (tty_paranoia_check(tty, filp->f_dentry->d_inode, "tty_poll")) + return 0; +- +- if (tty->ldisc.poll) +- return (tty->ldisc.poll)(tty, filp, wait); +- return 0; ++ ++ ld = tty_ldisc_ref_wait(tty); ++ if (ld->poll) ++ ret = (ld->poll)(tty, filp, wait); ++ tty_ldisc_deref(ld); ++ return ret; + } + + static int tty_fasync(int fd, struct file * filp, int on) +@@ -1518,12 +1905,15 @@ + static int tiocsti(struct tty_struct *tty, char __user *p) + { + char ch, mbz = 0; +- ++ struct tty_ldisc *ld; ++ + if ((current->signal->tty != tty) && !capable(CAP_SYS_ADMIN)) + return -EPERM; + if (get_user(ch, p)) + return -EFAULT; +- tty->ldisc.receive_buf(tty, &ch, &mbz, 1); ++ ld = tty_ldisc_ref_wait(tty); ++ ld->receive_buf(tty, &ch, &mbz, 1); ++ tty_ldisc_deref(ld); + return 0; + } + +@@ -1772,6 +2162,7 @@ + struct tty_struct *tty, *real_tty; + void __user *p = (void __user *)arg; + int retval; ++ struct tty_ldisc *ld; + + tty = (struct tty_struct *)file->private_data; + if (tty_paranoia_check(tty, inode, "tty_ioctl")) +@@ -1861,6 +2252,7 @@ + case TIOCGSID: + return tiocgsid(tty, real_tty, p); + case TIOCGETD: ++ /* FIXME: check this is ok */ + return put_user(tty->ldisc.num, (int __user *)p); + case TIOCSETD: + return tiocsetd(tty, p); +@@ -1899,16 +2291,19 @@ + return tty_tiocmset(tty, file, cmd, p); + } + if (tty->driver->ioctl) { +- int retval = (tty->driver->ioctl)(tty, file, cmd, arg); ++ retval = (tty->driver->ioctl)(tty, file, cmd, arg); + if (retval != -ENOIOCTLCMD) + return retval; + } +- if (tty->ldisc.ioctl) { +- int retval = (tty->ldisc.ioctl)(tty, file, cmd, arg); +- if (retval != -ENOIOCTLCMD) +- return retval; ++ ld = tty_ldisc_ref_wait(tty); ++ retval = -EINVAL; ++ if (ld->ioctl) { ++ retval = ld->ioctl(tty, file, cmd, arg); ++ if (retval == -ENOIOCTLCMD) ++ retval = -EINVAL; + } +- return -EINVAL; ++ tty_ldisc_deref(ld); ++ return retval; + } + + +@@ -1943,14 +2338,21 @@ + int session; + int i; + struct file *filp; ++ struct tty_ldisc *disc; + + if (!tty) + return; + session = tty->session; +- if (tty->ldisc.flush_buffer) +- tty->ldisc.flush_buffer(tty); ++ ++ /* We don't want an ldisc switch during this */ ++ disc = tty_ldisc_ref(tty); ++ if (disc && disc->flush_buffer) ++ disc->flush_buffer(tty); ++ tty_ldisc_deref(disc); ++ + if (tty->driver->flush_buffer) + tty->driver->flush_buffer(tty); ++ + read_lock(&tasklist_lock); + for_each_task_pid(session, PIDTYPE_SID, p, l, pid) { + if (p->signal->tty == tty || session > 0) { +@@ -2002,24 +2404,29 @@ + + /* + * This routine is called out of the software interrupt to flush data +- * from the flip buffer to the line discipline. ++ * from the flip buffer to the line discipline. + */ ++ + static void flush_to_ldisc(void *private_) + { + struct tty_struct *tty = (struct tty_struct *) private_; + unsigned char *cp; + char *fp; + int count; +- unsigned long flags; ++ unsigned long flags; ++ struct tty_ldisc *disc; ++ ++ disc = tty_ldisc_ref(tty); ++ 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->flip.work, 1); +- return; ++ goto out; + } +- + spin_lock_irqsave(&tty->read_lock, flags); + if (tty->flip.buf_num) { + cp = tty->flip.char_buf + TTY_FLIPBUF_SIZE; +@@ -2038,7 +2445,31 @@ + tty->flip.count = 0; + spin_unlock_irqrestore(&tty->read_lock, flags); + +- tty->ldisc.receive_buf(tty, cp, fp, count); ++ disc->receive_buf(tty, cp, fp, count); ++out: ++ tty_ldisc_deref(disc); ++} ++ ++/* ++ * Call the ldisc flush directly from a driver. This function may ++ * return an error and need retrying by the user. ++ */ ++ ++int tty_push_data(struct tty_struct *tty, unsigned char *cp, unsigned char *fp, int count) ++{ ++ int ret = 0; ++ struct tty_ldisc *disc; ++ ++ disc = tty_ldisc_ref(tty); ++ if(test_bit(TTY_DONT_FLIP, &tty->flags)) ++ ret = -EAGAIN; ++ else if(disc == NULL) ++ ret = -EIO; ++ else ++ disc->receive_buf(tty, cp, fp, count); ++ tty_ldisc_deref(disc); ++ return ret; ++ + } + + /* +@@ -2060,9 +2491,20 @@ + + static int n_baud_table = ARRAY_SIZE(baud_table); + ++/** ++ * tty_termios_baud_rate ++ * @termios: termios structure ++ * ++ * 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. ++ */ ++ + int tty_termios_baud_rate(struct termios *termios) + { +- unsigned int cbaud = termios->c_cflag & CBAUD; ++ unsigned int cbaud; ++ ++ cbaud = termios->c_cflag & CBAUD; + + if (cbaud & CBAUDEX) { + cbaud &= ~CBAUDEX; +@@ -2072,12 +2514,20 @@ + else + cbaud += 15; + } +- + return baud_table[cbaud]; + } + + EXPORT_SYMBOL(tty_termios_baud_rate); + ++/** ++ * tty_get_baud_rate - get tty bit rates ++ * @tty: tty to query ++ * ++ * 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. ++ */ ++ + int tty_get_baud_rate(struct tty_struct *tty) + { + int baud = tty_termios_baud_rate(tty->termios); +@@ -2096,6 +2546,17 @@ + + EXPORT_SYMBOL(tty_get_baud_rate); + ++/** ++ * tty_flip_buffer_push - terminal ++ * @tty: tty to push ++ * ++ * Queue a push of the terminal flip buffers to the line discipline. This ++ * function must not be called from IRQ context if tty->low_latency is set. ++ * ++ * In the event of the queue being busy for flipping the work will be ++ * held off and retried later. ++ */ ++ + void tty_flip_buffer_push(struct tty_struct *tty) + { + if (tty->low_latency) +@@ -2113,7 +2574,7 @@ + { + memset(tty, 0, sizeof(struct tty_struct)); + tty->magic = TTY_MAGIC; +- tty->ldisc = ldiscs[N_TTY]; ++ tty_ldisc_assign(tty, tty_ldisc_get(N_TTY)); + tty->pgrp = -1; + tty->flip.char_buf_ptr = tty->flip.char_buf; + tty->flip.flag_buf_ptr = tty->flip.flag_buf; +diff -Nur linux-2.6.8.1/drivers/char/tty_ioctl.c linux-2.6.8.1-plasmaroo/drivers/char/tty_ioctl.c +--- linux-2.6.8.1/drivers/char/tty_ioctl.c 2004-08-14 11:56:24.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/char/tty_ioctl.c 2004-11-06 22:55:10.853618944 +0000 +@@ -29,6 +29,8 @@ + + #undef DEBUG + ++extern spinlock_t tty_termios_lock; ++ + /* + * Internal flag options for termios setting behavior + */ +@@ -98,8 +100,18 @@ + { + int canon_change; + struct termios old_termios = *tty->termios; ++ struct tty_ldisc *ld; ++ unsigned long flags; ++ ++ /* ++ * Perform the actual termios internal changes under lock. ++ */ ++ ++ ++ /* FIXME: we need to decide on some locking/ordering semantics ++ for the set_termios notification eventually */ ++ spin_lock_irqsave(&tty_termios_lock, flags); + +- local_irq_disable(); // FIXME: is this safe? + *tty->termios = *new_termios; + unset_locked_termios(tty->termios, &old_termios, tty->termios_locked); + canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON; +@@ -109,12 +121,13 @@ + tty->canon_data = 0; + tty->erasing = 0; + } +- local_irq_enable(); // FIXME: is this safe? ++ ++ + if (canon_change && !L_ICANON(tty) && tty->read_cnt) + /* Get characters left over from canonical mode. */ + wake_up_interruptible(&tty->read_wait); + +- /* see if packet mode change of state */ ++ /* See if packet mode change of state. */ + + if (tty->link && tty->link->packet) { + int old_flow = ((old_termios.c_iflag & IXON) && +@@ -132,17 +145,23 @@ + wake_up_interruptible(&tty->link->read_wait); + } + } +- ++ + if (tty->driver->set_termios) + (*tty->driver->set_termios)(tty, &old_termios); + +- if (tty->ldisc.set_termios) +- (*tty->ldisc.set_termios)(tty, &old_termios); ++ ld = tty_ldisc_ref(tty); ++ if (ld != NULL) { ++ if (ld->set_termios) ++ (ld->set_termios)(tty, &old_termios); ++ tty_ldisc_deref(ld); ++ } ++ spin_unlock_irqrestore(&tty_termios_lock, flags); + } + + static int set_termios(struct tty_struct * tty, void __user *arg, int opt) + { + struct termios tmp_termios; ++ struct tty_ldisc *ld; + int retval = tty_check_change(tty); + + if (retval) +@@ -159,9 +178,14 @@ + return -EFAULT; + } + +- if ((opt & TERMIOS_FLUSH) && tty->ldisc.flush_buffer) +- tty->ldisc.flush_buffer(tty); +- ++ ld = tty_ldisc_ref(tty); ++ ++ if (ld != NULL) { ++ if ((opt & TERMIOS_FLUSH) && ld->flush_buffer) ++ ld->flush_buffer(tty); ++ tty_ldisc_deref(ld); ++ } ++ + if (opt & TERMIOS_WAIT) { + tty_wait_until_sent(tty, 0); + if (signal_pending(current)) +@@ -225,12 +249,16 @@ + static int get_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb) + { + struct sgttyb tmp; ++ unsigned long flags; + ++ spin_lock_irqsave(&tty_termios_lock, flags); + tmp.sg_ispeed = 0; + tmp.sg_ospeed = 0; + tmp.sg_erase = tty->termios->c_cc[VERASE]; + tmp.sg_kill = tty->termios->c_cc[VKILL]; + tmp.sg_flags = get_sgflags(tty); ++ spin_unlock_irqrestore(&tty_termios_lock, flags); ++ + return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0; + } + +@@ -269,12 +297,16 @@ + retval = tty_check_change(tty); + if (retval) + return retval; +- termios = *tty->termios; ++ + if (copy_from_user(&tmp, sgttyb, sizeof(tmp))) + return -EFAULT; ++ ++ spin_lock_irqsave(&tty_termios_lock, flags); ++ termios = *tty->termios; + termios.c_cc[VERASE] = tmp.sg_erase; + termios.c_cc[VKILL] = tmp.sg_kill; + set_sgflags(&termios, tmp.sg_flags); ++ spin_unlock_irqrestore(&tty_termios_lock, flags); + change_termios(tty, &termios); + return 0; + } +@@ -365,6 +397,8 @@ + struct tty_struct * real_tty; + void __user *p = (void __user *)arg; + int retval; ++ struct tty_ldisc *ld; ++ unsigned long flags; + + if (tty->driver->type == TTY_DRIVER_TYPE_PTY && + tty->driver->subtype == PTY_TYPE_MASTER) +@@ -443,22 +477,26 @@ + retval = tty_check_change(tty); + if (retval) + return retval; ++ ++ ld = tty_ldisc_ref(tty); + switch (arg) { + case TCIFLUSH: +- if (tty->ldisc.flush_buffer) +- tty->ldisc.flush_buffer(tty); ++ if (ld->flush_buffer) ++ ld->flush_buffer(tty); + break; + case TCIOFLUSH: +- if (tty->ldisc.flush_buffer) +- tty->ldisc.flush_buffer(tty); ++ if (ld->flush_buffer) ++ ld->flush_buffer(tty); + /* fall through */ + case TCOFLUSH: + if (tty->driver->flush_buffer) + tty->driver->flush_buffer(tty); + break; + default: ++ tty_ldisc_deref(ld); + return -EINVAL; + } ++ tty_ldisc_deref(ld); + return 0; + case TIOCOUTQ: + return put_user(tty->driver->chars_in_buffer ? +@@ -504,9 +542,11 @@ + case TIOCSSOFTCAR: + if (get_user(arg, (unsigned int __user *) arg)) + return -EFAULT; ++ spin_lock_irqsave(&tty_termios_lock, flags); + tty->termios->c_cflag = + ((tty->termios->c_cflag & ~CLOCAL) | + (arg ? CLOCAL : 0)); ++ spin_unlock_irqrestore(&tty_termios_lock, flags); + return 0; + default: + return -ENOIOCTLCMD; +diff -Nur linux-2.6.8.1/drivers/char/viocons.c linux-2.6.8.1-plasmaroo/drivers/char/viocons.c +--- linux-2.6.8.1/drivers/char/viocons.c 2004-08-14 11:54:46.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/char/viocons.c 2004-11-06 22:55:10.855618640 +0000 +@@ -422,10 +422,7 @@ + pi->overflowMessage = 0; + + if (pi->tty) { +- if ((pi->tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- (pi->tty->ldisc.write_wakeup)) +- (pi->tty->ldisc.write_wakeup)(pi->tty); +- wake_up_interruptible(&pi->tty->write_wait); ++ tty_wakeup(pi->tty); + } + } + +diff -Nur linux-2.6.8.1/drivers/char/vme_scc.c linux-2.6.8.1-plasmaroo/drivers/char/vme_scc.c +--- linux-2.6.8.1/drivers/char/vme_scc.c 2004-08-14 11:54:47.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/char/vme_scc.c 2004-11-06 22:55:10.856618488 +0000 +@@ -544,12 +544,8 @@ + SCCwrite(COMMAND_REG, CR_TX_PENDING_RESET); /* disable tx_int on next tx underrun? */ + port->gs.flags &= ~GS_TX_INTEN; + } +- if (port->gs.tty && port->gs.xmit_cnt <= port->gs.wakeup_chars) { +- if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- port->gs.tty->ldisc.write_wakeup) +- (port->gs.tty->ldisc.write_wakeup)(port->gs.tty); +- wake_up_interruptible(&port->gs.tty->write_wait); +- } ++ if (port->gs.tty && port->gs.xmit_cnt <= port->gs.wakeup_chars) ++ tty_wakeup(port->gs.tty); + + SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); + return IRQ_HANDLED; +diff -Nur linux-2.6.8.1/drivers/char/vt_ioctl.c linux-2.6.8.1-plasmaroo/drivers/char/vt_ioctl.c +--- linux-2.6.8.1/drivers/char/vt_ioctl.c 2004-08-14 11:55:47.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/char/vt_ioctl.c 2004-11-06 22:55:10.858618184 +0000 +@@ -536,8 +536,7 @@ + default: + return -EINVAL; + } +- if (tty->ldisc.flush_buffer) +- tty->ldisc.flush_buffer(tty); ++ tty_ldisc_flush(tty); + return 0; + + case KDGKBMODE: +diff -Nur linux-2.6.8.1/drivers/isdn/capi/capi.c linux-2.6.8.1-plasmaroo/drivers/isdn/capi/capi.c +--- linux-2.6.8.1/drivers/isdn/capi/capi.c 2004-08-14 11:56:22.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/isdn/capi/capi.c 2004-11-06 22:55:10.885614080 +0000 +@@ -436,51 +436,62 @@ + struct sk_buff *nskb; + int datalen; + u16 errcode, datahandle; +- ++ struct tty_ldisc *ld; ++ + datalen = skb->len - CAPIMSG_LEN(skb->data); +- if (mp->tty) { +- if (mp->tty->ldisc.receive_buf == 0) { +- printk(KERN_ERR "capi: ldisc has no receive_buf function\n"); +- return -1; +- } +- if (mp->ttyinstop) { ++ if (mp->tty == NULL) ++ { ++#ifdef _DEBUG_DATAFLOW ++ printk(KERN_DEBUG "capi: currently no receiver\n"); ++#endif ++ return -1; ++ } ++ ++ ld = tty_ldisc_ref(mp->tty); ++ if (ld == NULL) ++ return -1; ++ if (ld->receive_buf == NULL) { + #if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) +- printk(KERN_DEBUG "capi: recv tty throttled\n"); ++ printk(KERN_DEBUG "capi: ldisc has no receive_buf function\n"); + #endif +- return -1; +- } +- if (mp->tty->ldisc.receive_room && +- mp->tty->ldisc.receive_room(mp->tty) < datalen) { ++ goto bad; ++ } ++ if (mp->ttyinstop) { + #if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) +- printk(KERN_DEBUG "capi: no room in tty\n"); ++ printk(KERN_DEBUG "capi: recv tty throttled\n"); + #endif +- return -1; +- } +- if ((nskb = gen_data_b3_resp_for(mp, skb)) == 0) { +- printk(KERN_ERR "capi: gen_data_b3_resp failed\n"); +- return -1; +- } +- datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4); +- errcode = capi20_put_message(mp->ap, nskb); +- if (errcode != CAPI_NOERROR) { +- printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n", +- errcode); +- kfree_skb(nskb); +- return -1; +- } +- (void)skb_pull(skb, CAPIMSG_LEN(skb->data)); +-#ifdef _DEBUG_DATAFLOW +- printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => ldisc\n", +- datahandle, skb->len); ++ goto bad; ++ } ++ if (ld->receive_room && ++ ld->receive_room(mp->tty) < datalen) { ++#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) ++ printk(KERN_DEBUG "capi: no room in tty\n"); + #endif +- mp->tty->ldisc.receive_buf(mp->tty, skb->data, NULL, skb->len); +- kfree_skb(skb); +- return 0; +- ++ goto bad; ++ } ++ if ((nskb = gen_data_b3_resp_for(mp, skb)) == 0) { ++ printk(KERN_ERR "capi: gen_data_b3_resp failed\n"); ++ goto bad; ++ } ++ datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4); ++ errcode = capi20_put_message(mp->ap, nskb); ++ if (errcode != CAPI_NOERROR) { ++ printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n", ++ errcode); ++ kfree_skb(nskb); ++ goto bad; + } ++ (void)skb_pull(skb, CAPIMSG_LEN(skb->data)); + #ifdef _DEBUG_DATAFLOW +- printk(KERN_DEBUG "capi: currently no receiver\n"); ++ 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); ++ kfree_skb(skb); ++ tty_ldisc_deref(ld); ++ return 0; ++bad: ++ tty_ldisc_deref(ld); + return -1; + } + +@@ -614,6 +625,7 @@ + + + if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND) { ++ + datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4+4+2); + #ifdef _DEBUG_DATAFLOW + printk(KERN_DEBUG "capi_signal: DATA_B3_IND %u len=%d\n", +@@ -633,10 +645,8 @@ + #endif + kfree_skb(skb); + (void)capiminor_del_ack(mp, datahandle); +- if (mp->tty) { +- if (mp->tty->ldisc.write_wakeup) +- mp->tty->ldisc.write_wakeup(mp->tty); +- } ++ if (mp->tty) ++ tty_wakeup(tty); + (void)handle_minor_send(mp); + + } else { +diff -Nur linux-2.6.8.1/drivers/isdn/i4l/isdn_tty.c linux-2.6.8.1-plasmaroo/drivers/isdn/i4l/isdn_tty.c +--- linux-2.6.8.1/drivers/isdn/i4l/isdn_tty.c 2004-08-14 11:55:48.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/isdn/i4l/isdn_tty.c 2004-11-06 22:55:10.900611800 +0000 +@@ -296,10 +296,7 @@ + info->send_outstanding++; + info->msr &= ~UART_MSR_CTS; + info->lsr &= ~UART_LSR_TEMT; +- 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); + return; + } + if (slen < 0) { +@@ -1174,10 +1171,7 @@ + /* If DLE decoding results in zero-transmit, but + * c originally was non-zero, do a wakeup. + */ +- 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); + info->msr |= UART_MSR_CTS; + info->lsr |= UART_LSR_TEMT; + } +@@ -1290,9 +1284,7 @@ + isdn_tty_cleanup_xmit(info); + info->xmit_count = 0; + wake_up_interruptible(&tty->write_wait); +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- tty->ldisc.write_wakeup) +- (tty->ldisc.write_wakeup) (tty); ++ tty_wakeup(tty); + } + + static void +@@ -1747,10 +1739,10 @@ + } + dev->modempoll--; + isdn_tty_shutdown(info); ++ + if (tty->driver->flush_buffer) + tty->driver->flush_buffer(tty); +- if (tty->ldisc.flush_buffer) +- tty->ldisc.flush_buffer(tty); ++ tty_ldisc_flush(tty); + info->tty = NULL; + info->ncarrier = 0; + tty->closing = 0; +@@ -2681,8 +2673,7 @@ + if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) { + return; + } +- if (info->tty->ldisc.flush_buffer) +- info->tty->ldisc.flush_buffer(info->tty); ++ tty_ldisc_flush(tty); + if ((info->flags & ISDN_ASYNC_CHECK_CD) && + (!((info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) && + (info->flags & ISDN_ASYNC_CALLOUT_NOHUP)))) { +diff -Nur linux-2.6.8.1/drivers/macintosh/macserial.c linux-2.6.8.1-plasmaroo/drivers/macintosh/macserial.c +--- linux-2.6.8.1/drivers/macintosh/macserial.c 2004-08-14 11:56:23.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/macintosh/macserial.c 2004-11-06 22:55:10.910610280 +0000 +@@ -713,12 +713,8 @@ + if (!tty) + return; + +- if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- tty->ldisc.write_wakeup) +- (tty->ldisc.write_wakeup)(tty); +- wake_up_interruptible(&tty->write_wait); +- } ++ if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) ++ tty_wakeup(tty); + } + + static int startup(struct mac_serial * info) +@@ -1564,10 +1560,7 @@ + spin_lock_irqsave(&info->lock, flags); + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + spin_unlock_irqrestore(&info->lock, flags); +- wake_up_interruptible(&tty->write_wait); +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- tty->ldisc.write_wakeup) +- (tty->ldisc.write_wakeup)(tty); ++ tty_wakeup(tty); + } + + /* +@@ -1994,8 +1987,7 @@ + + if (tty->driver->flush_buffer) + tty->driver->flush_buffer(tty); +- if (tty->ldisc.flush_buffer) +- tty->ldisc.flush_buffer(tty); ++ tty_ldisc_flush(tty); + tty->closing = 0; + info->event = 0; + info->tty = 0; +diff -Nur linux-2.6.8.1/drivers/net/hamradio/mkiss.c linux-2.6.8.1-plasmaroo/drivers/net/hamradio/mkiss.c +--- linux-2.6.8.1/drivers/net/hamradio/mkiss.c 2004-08-14 11:56:23.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/net/hamradio/mkiss.c 2004-11-06 22:55:10.931607088 +0000 +@@ -602,8 +602,6 @@ + + if (tty->driver->flush_buffer) + tty->driver->flush_buffer(tty); +- if (tty->ldisc.flush_buffer) +- tty->ldisc.flush_buffer(tty); + + /* Restore default settings */ + ax->dev->type = ARPHRD_AX25; +diff -Nur linux-2.6.8.1/drivers/net/irda/irtty-sir.c linux-2.6.8.1-plasmaroo/drivers/net/irda/irtty-sir.c +--- linux-2.6.8.1/drivers/net/irda/irtty-sir.c 2004-08-14 11:54:46.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/net/irda/irtty-sir.c 2004-11-06 22:55:10.944605112 +0000 +@@ -509,13 +509,6 @@ + if (tty->driver->flush_buffer) + tty->driver->flush_buffer(tty); + +-/* from old irtty - but what is it good for? +- * we _are_ the ldisc and we _don't_ implement flush_buffer! +- * +- * if (tty->ldisc.flush_buffer) +- * tty->ldisc.flush_buffer(tty); +- */ +- + /* apply mtt override */ + sir_tty_drv.qos_mtt_bits = qos_mtt_bits; + +diff -Nur linux-2.6.8.1/drivers/net/ppp_async.c linux-2.6.8.1-plasmaroo/drivers/net/ppp_async.c +--- linux-2.6.8.1/drivers/net/ppp_async.c 2004-08-14 11:55:48.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/net/ppp_async.c 2004-11-06 22:55:10.957603136 +0000 +@@ -122,6 +122,9 @@ + * frees the memory that ppp_asynctty_receive is using. The best + * way to fix this is to use a rwlock in the tty struct, but for now + * we use a single global rwlock for all ttys in ppp line discipline. ++ * ++ * FIXME: this is no longer true. The _close path for the ldisc is ++ * now guaranteed to be sane. + */ + static rwlock_t disc_data_lock = RW_LOCK_UNLOCKED; + +@@ -144,7 +147,8 @@ + } + + /* +- * Called when a tty is put into PPP line discipline. ++ * Called when a tty is put into PPP line discipline. Called in process ++ * context. + */ + static int + ppp_asynctty_open(struct tty_struct *tty) +@@ -255,6 +259,11 @@ + return -EAGAIN; + } + ++/* ++ * Called in process context only. May be re-entered by multiple ++ * ioctl calling threads. ++ */ ++ + static int + ppp_asynctty_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) +@@ -716,7 +725,8 @@ + + /* + * Flush output from our internal buffers. +- * Called for the TCFLSH ioctl. ++ * Called for the TCFLSH ioctl. Can be entered in parallel ++ * but this is covered by the xmit_lock. + */ + static void + ppp_async_flush_output(struct asyncppp *ap) +@@ -816,7 +826,9 @@ + skb_trim(skb, 0); + } + +-/* called when the tty driver has data for us. */ ++/* Called when the tty driver has data for us. Runs parallel with the ++ other ldisc functions but will not be re-entered */ ++ + static void + ppp_async_input(struct asyncppp *ap, const unsigned char *buf, + char *flags, int count) +diff -Nur linux-2.6.8.1/drivers/net/ppp_synctty.c linux-2.6.8.1-plasmaroo/drivers/net/ppp_synctty.c +--- linux-2.6.8.1/drivers/net/ppp_synctty.c 2004-08-14 11:55:20.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/net/ppp_synctty.c 2004-11-06 22:55:10.963602224 +0000 +@@ -175,6 +175,8 @@ + * frees the memory that ppp_synctty_receive is using. The best + * way to fix this is to use a rwlock in the tty struct, but for now + * we use a single global rwlock for all ttys in ppp line discipline. ++ * ++ * FIXME: Fixed in tty_io nowdays. + */ + static rwlock_t disc_data_lock = RW_LOCK_UNLOCKED; + +diff -Nur linux-2.6.8.1/drivers/net/slip.c linux-2.6.8.1-plasmaroo/drivers/net/slip.c +--- linux-2.6.8.1/drivers/net/slip.c 2004-08-14 11:56:24.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/net/slip.c 2004-11-06 22:55:10.969601312 +0000 +@@ -672,7 +672,9 @@ + * Handle the 'receiver data ready' interrupt. + * This function is called by the 'tty_io' module in the kernel when + * a block of SLIP data has been received, which can now be decapsulated +- * and sent on to some IP layer for further processing. ++ * and sent on to some IP layer for further processing. This will not ++ * be re-entered while running but other ldisc functions may be called ++ * in parallel + */ + + static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) +@@ -841,9 +843,11 @@ + * SLIP line discipline is called for. Because we are + * sure the tty line exists, we only have to link it to + * a free SLIP channel... ++ * ++ * Called in process context serialized from other ldisc calls. + */ +-static int +-slip_open(struct tty_struct *tty) ++ ++static int slip_open(struct tty_struct *tty) + { + struct slip *sl; + int err; +@@ -876,11 +880,11 @@ + tty->disc_data = sl; + sl->line = tty_devnum(tty); + sl->pid = current->pid; ++ ++ /* FIXME: already done before we were called - seems this can go */ + if (tty->driver->flush_buffer) + tty->driver->flush_buffer(tty); +- if (tty->ldisc.flush_buffer) +- tty->ldisc.flush_buffer(tty); +- ++ + if (!test_bit(SLF_INUSE, &sl->flags)) { + /* Perform the low-level SLIP initialization. */ + if ((err = sl_alloc_bufs(sl, SL_MTU)) != 0) +@@ -923,6 +927,9 @@ + } + + /* ++ ++ FIXME: 1,2 are fixed 3 was never true anyway. ++ + Let me to blame a bit. + 1. TTY module calls this funstion on soft interrupt. + 2. TTY module calls this function WITH MASKED INTERRUPTS! +@@ -941,9 +948,8 @@ + + /* + * Close down a SLIP channel. +- * This means flushing out any pending queues, and then restoring the +- * TTY line discipline to what it was before it got hooked to SLIP +- * (which usually is TTY again). ++ * This means flushing out any pending queues, and then returning. This ++ * call is serialized against other ldisc functions. + */ + static void + slip_close(struct tty_struct *tty) +diff -Nur linux-2.6.8.1/drivers/net/wan/pc300_tty.c linux-2.6.8.1-plasmaroo/drivers/net/wan/pc300_tty.c +--- linux-2.6.8.1/drivers/net/wan/pc300_tty.c 2004-08-14 11:55:20.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/net/wan/pc300_tty.c 2004-11-06 22:55:11.003596144 +0000 +@@ -634,14 +634,8 @@ + } + + CPC_TTY_DBG("%s: call wake_up_interruptible\n",cpc_tty->name); +- +- wake_up_interruptible(&tty->write_wait); +- +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup){ +- CPC_TTY_DBG("%s: call line disc. wake up\n",cpc_tty->name); +- tty->ldisc.write_wakeup(tty); +- } + ++ tty_wakeup(tty); + return; + } + +@@ -692,9 +686,11 @@ + st_cpc_tty_area *cpc_tty; + volatile st_cpc_rx_buf * buf; + char flags=0,flg_rx=1; ++ struct tty_ldisc *ld; + + if (cpc_tty_cnt == 0) return; + ++ + for (i=0; (i < 4) && flg_rx ; i++) { + flg_rx = 0; + port = (int) data; +@@ -702,11 +698,18 @@ + cpc_tty = &cpc_tty_area[port]; + + if ((buf=cpc_tty->buf_rx.first) != 0) { +- +- if (cpc_tty->tty && (cpc_tty->tty->ldisc.receive_buf)) { +- CPC_TTY_DBG("%s: call line disc. receive_buf\n",cpc_tty->name); +- cpc_tty->tty->ldisc.receive_buf(cpc_tty->tty, (char *)(buf->data), +- &flags, buf->size); ++ ++ if(cpc_tty->tty) ++ { ++ ld = tty_ldisc_ref(cpc_tty); ++ if(ld) ++ { ++ if (ld->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); ++ } ++ tty_ldisc_deref(ld); ++ } + } + cpc_tty->buf_rx.first = cpc_tty->buf_rx.first->next; + kfree((unsigned char *)buf); +@@ -910,13 +913,7 @@ + CPC_TTY_DBG("%s: the interface is not opened\n",cpc_tty->name); + return; + } +- +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup){ +- CPC_TTY_DBG("%s:call line disc. wakeup\n",cpc_tty->name); +- tty->ldisc.write_wakeup (tty); +- } +- +- wake_up_interruptible(&tty->write_wait); ++ tty_wakeup(tty); + } + + /* +diff -Nur linux-2.6.8.1/drivers/net/wan/sdla_chdlc.c linux-2.6.8.1-plasmaroo/drivers/net/wan/sdla_chdlc.c +--- linux-2.6.8.1/drivers/net/wan/sdla_chdlc.c 2004-08-14 11:55:32.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/net/wan/sdla_chdlc.c 2004-11-06 22:55:11.017594016 +0000 +@@ -3628,11 +3628,7 @@ + if ((tty=card->tty)==NULL) + return; + +- 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); + #if defined(SERIAL_HAVE_POLL_WAIT) + wake_up_interruptible(&tty->poll_wait); + #endif +@@ -3857,6 +3853,7 @@ + char fp=0; + struct tty_struct *tty; + int i; ++ struct tty_ldisc *ld; + + if (!card->tty_open){ + dbg_printk(KERN_INFO "%s: TTY not open during receive\n", +@@ -3944,8 +3941,11 @@ + len -= offset; + } + sdla_peek(&card->hw, addr, card->tty_rx+offset, len); +- if (tty->ldisc.receive_buf){ +- tty->ldisc.receive_buf(tty,card->tty_rx,&fp,olen); ++ ld = tty_ldisc_ref(tty); ++ if (ld) { ++ if (ld->receive_buf) ++ ld->receive_buf(tty,card->tty_rx,&fp,olen); ++ tty_ldisc_deref(ld); + }else{ + if (net_ratelimit()){ + printk(KERN_INFO +@@ -4252,14 +4252,10 @@ + if (!tty) + return; + +- wake_up_interruptible(&tty->write_wait); + #if defined(SERIAL_HAVE_POLL_WAIT) + wake_up_interruptible(&tty->poll_wait); + #endif +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- tty->ldisc.write_wakeup) +- (tty->ldisc.write_wakeup)(tty); +- ++ tty_wakeup(tty); + return; + } + +diff -Nur linux-2.6.8.1/drivers/net/wireless/strip.c linux-2.6.8.1-plasmaroo/drivers/net/wireless/strip.c +--- linux-2.6.8.1/drivers/net/wireless/strip.c 2004-08-14 11:55:47.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/net/wireless/strip.c 2004-11-06 22:55:11.026592648 +0000 +@@ -2661,8 +2661,6 @@ + tty->disc_data = strip_info; + if (tty->driver->flush_buffer) + tty->driver->flush_buffer(tty); +- if (tty->ldisc.flush_buffer) +- tty->ldisc.flush_buffer(tty); + + /* + * Restore default settings +diff -Nur linux-2.6.8.1/drivers/s390/char/con3215.c linux-2.6.8.1-plasmaroo/drivers/s390/char/con3215.c +--- linux-2.6.8.1/drivers/s390/char/con3215.c 2004-08-14 11:55:47.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/s390/char/con3215.c 2004-11-06 22:55:11.039590672 +0000 +@@ -366,10 +366,7 @@ + tty = raw->tty; + if (tty != NULL && + RAW3215_BUFFER_SIZE - raw->count >= RAW3215_MIN_SPACE) { +- 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); + } + } + +@@ -1055,10 +1052,7 @@ + + raw = (struct raw3215_info *) tty->driver_data; + raw3215_flush_buffer(raw); +- wake_up_interruptible(&tty->write_wait); +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- tty->ldisc.write_wakeup) +- (tty->ldisc.write_wakeup)(tty); ++ tty_wakeup(tty); + } + + /* +diff -Nur linux-2.6.8.1/drivers/s390/char/sclp_tty.c linux-2.6.8.1-plasmaroo/drivers/s390/char/sclp_tty.c +--- linux-2.6.8.1/drivers/s390/char/sclp_tty.c 2004-08-14 11:56:25.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/s390/char/sclp_tty.c 2004-11-06 22:55:11.048589304 +0000 +@@ -277,10 +277,7 @@ + wake_up(&sclp_tty_waitq); + /* check if the tty needs a wake up call */ + if (sclp_tty != NULL) { +- if ((sclp_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- sclp_tty->ldisc.write_wakeup) +- (sclp_tty->ldisc.write_wakeup)(sclp_tty); +- wake_up_interruptible(&sclp_tty->write_wait); ++ tty_wakeup(tty); + } + } + +diff -Nur linux-2.6.8.1/drivers/s390/char/sclp_vt220.c linux-2.6.8.1-plasmaroo/drivers/s390/char/sclp_vt220.c +--- linux-2.6.8.1/drivers/s390/char/sclp_vt220.c 2004-08-14 11:55:10.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/s390/char/sclp_vt220.c 2004-11-06 22:55:11.050589000 +0000 +@@ -139,10 +139,7 @@ + wake_up(&sclp_vt220_waitq); + /* Check if the tty needs a wake up call */ + if (sclp_vt220_tty != NULL) { +- if ((sclp_vt220_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- (sclp_vt220_tty->ldisc.write_wakeup != NULL)) +- (sclp_vt220_tty->ldisc.write_wakeup)(sclp_vt220_tty); +- wake_up_interruptible(&sclp_vt220_tty->write_wait); ++ tty_wakeup(tty); + } + } + +diff -Nur linux-2.6.8.1/drivers/s390/net/ctctty.c linux-2.6.8.1-plasmaroo/drivers/s390/net/ctctty.c +--- linux-2.6.8.1/drivers/s390/net/ctctty.c 2004-08-14 11:55:33.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/s390/net/ctctty.c 2004-11-06 22:55:11.064586872 +0000 +@@ -307,10 +307,7 @@ + + info->flags &= ~CTC_ASYNC_TX_LINESTAT; + if (tty) { +- if (wake && (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); + } + } + return (skb_queue_empty(&info->tx_queue) ? 0 : 1); +@@ -589,9 +586,7 @@ + info->lsr |= UART_LSR_TEMT; + spin_unlock_irqrestore(&ctc_tty_lock, flags); + wake_up_interruptible(&tty->write_wait); +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- tty->ldisc.write_wakeup) +- (tty->ldisc.write_wakeup) (tty); ++ tty_wakeup(tty); + ex: + DBF_TEXT_(trace, 2, "ex: %s ", __FUNCTION__); + return; +@@ -1066,8 +1061,7 @@ + skb_queue_purge(&info->tx_queue); + info->lsr |= UART_LSR_TEMT; + } +- if (tty->ldisc.flush_buffer) +- tty->ldisc.flush_buffer(tty); ++ tty_ldisc_flush(tty); + info->tty = 0; + tty->closing = 0; + if (info->blocked_open) { +diff -Nur linux-2.6.8.1/drivers/sbus/char/aurora.c linux-2.6.8.1-plasmaroo/drivers/sbus/char/aurora.c +--- linux-2.6.8.1/drivers/sbus/char/aurora.c 2004-08-14 11:54:50.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/sbus/char/aurora.c 2004-11-06 22:55:11.101581248 +0000 +@@ -1531,8 +1531,7 @@ + aurora_shutdown_port(bp, port); + if (tty->driver->flush_buffer) + tty->driver->flush_buffer(tty); +- if (tty->ldisc.flush_buffer) +- tty->ldisc.flush_buffer(tty); ++ tty_ldisc_flush(tty); + tty->closing = 0; + port->event = 0; + port->tty = 0; +@@ -1743,10 +1742,7 @@ + port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; + restore_flags(flags); + +- wake_up_interruptible(&tty->write_wait); +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- tty->ldisc.write_wakeup) +- (tty->ldisc.write_wakeup)(tty); ++ tty_wakeup(tty); + #ifdef AURORA_DEBUG + printk("aurora_flush_buffer: end\n"); + #endif +@@ -2223,10 +2219,7 @@ + return; + + if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) { +- 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); + } + #ifdef AURORA_DEBUG + printk("do_softint: end\n"); +diff -Nur linux-2.6.8.1/drivers/serial/68328serial.c linux-2.6.8.1-plasmaroo/drivers/serial/68328serial.c +--- linux-2.6.8.1/drivers/serial/68328serial.c 2004-08-14 11:56:23.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/serial/68328serial.c 2004-11-06 22:55:11.109580032 +0000 +@@ -435,10 +435,7 @@ + return; + #if 0 + if (clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { +- 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); + } + #endif + } +@@ -858,10 +855,7 @@ + cli(); + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + sti(); +- wake_up_interruptible(&tty->write_wait); +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- tty->ldisc.write_wakeup) +- (tty->ldisc.write_wakeup)(tty); ++ tty_wakeup(tty); + } + + /* +@@ -1185,11 +1179,13 @@ + shutdown(info); + if (tty->driver->flush_buffer) + tty->driver->flush_buffer(tty); +- if (tty->ldisc.flush_buffer) +- tty->ldisc.flush_buffer(tty); ++ ++ tty_ldisc_flush(tty); + tty->closing = 0; + info->event = 0; + info->tty = 0; ++#warning "This is not and has never been valid so fix it" ++#if 0 + if (tty->ldisc.num != ldiscs[N_TTY].num) { + if (tty->ldisc.close) + (tty->ldisc.close)(tty); +@@ -1198,6 +1194,7 @@ + if (tty->ldisc.open) + (tty->ldisc.open)(tty); + } ++#endif + if (info->blocked_open) { + if (info->close_delay) { + current->state = TASK_INTERRUPTIBLE; +diff -Nur linux-2.6.8.1/drivers/serial/68360serial.c linux-2.6.8.1-plasmaroo/drivers/serial/68360serial.c +--- linux-2.6.8.1/drivers/serial/68360serial.c 2004-08-14 11:56:23.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/serial/68360serial.c 2004-11-06 22:55:11.116578968 +0000 +@@ -700,12 +700,8 @@ + if (!tty) + return; + +- if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- tty->ldisc.write_wakeup) +- (tty->ldisc.write_wakeup)(tty); +- wake_up_interruptible(&tty->write_wait); +- } ++ if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) ++ tty_wakeup(tty); + } + + +@@ -1152,10 +1148,7 @@ + /* There is nothing to "flush", whatever we gave the CPM + * is on its way out. + */ +- wake_up_interruptible(&tty->write_wait); +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- tty->ldisc.write_wakeup) +- (tty->ldisc.write_wakeup)(tty); ++ tty_wakeup(tty); + info->flags &= ~TX_WAKEUP; + } + +@@ -1716,8 +1709,7 @@ + shutdown(info); + if (tty->driver->flush_buffer) + tty->driver->flush_buffer(tty); +- if (tty->ldisc.flush_buffer) +- tty->ldisc.flush_buffer(tty); ++ tty_ldisc_flush(tty); + tty->closing = 0; + info->event = 0; + info->tty = 0; +diff -Nur linux-2.6.8.1/drivers/serial/mcfserial.c linux-2.6.8.1-plasmaroo/drivers/serial/mcfserial.c +--- linux-2.6.8.1/drivers/serial/mcfserial.c 2004-08-14 11:55:20.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/serial/mcfserial.c 2004-11-06 22:55:11.126577448 +0000 +@@ -424,11 +424,7 @@ + tty = info->tty; + if (!tty) + return; +- +- 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); + } + + +@@ -835,10 +831,7 @@ + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + local_irq_restore(flags); + +- wake_up_interruptible(&tty->write_wait); +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- tty->ldisc.write_wakeup) +- (tty->ldisc.write_wakeup)(tty); ++ tty_wakeup(tty); + } + + /* +@@ -1232,11 +1225,12 @@ + shutdown(info); + if (tty->driver->flush_buffer) + tty->driver->flush_buffer(tty); +- if (tty->ldisc.flush_buffer) +- tty->ldisc.flush_buffer(tty); ++ tty_ldisc_flush(tty); ++ + tty->closing = 0; + info->event = 0; + info->tty = 0; ++#if 0 + if (tty->ldisc.num != ldiscs[N_TTY].num) { + if (tty->ldisc.close) + (tty->ldisc.close)(tty); +@@ -1245,6 +1239,7 @@ + if (tty->ldisc.open) + (tty->ldisc.open)(tty); + } ++#endif + if (info->blocked_open) { + if (info->close_delay) { + current->state = TASK_INTERRUPTIBLE; +diff -Nur linux-2.6.8.1/drivers/serial/serial_core.c linux-2.6.8.1-plasmaroo/drivers/serial/serial_core.c +--- linux-2.6.8.1/drivers/serial/serial_core.c 2004-08-14 11:54:51.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/serial/serial_core.c 2004-11-06 22:55:11.131576688 +0000 +@@ -107,15 +107,7 @@ + static void uart_tasklet_action(unsigned long data) + { + struct uart_state *state = (struct uart_state *)data; +- struct tty_struct *tty; +- +- tty = state->info->tty; +- if (tty) { +- 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(state->info->tty); + } + + static inline void +@@ -581,10 +573,7 @@ + spin_lock_irqsave(&port->lock, flags); + uart_circ_clear(&state->info->xmit); + spin_unlock_irqrestore(&port->lock, flags); +- wake_up_interruptible(&tty->write_wait); +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- tty->ldisc.write_wakeup) +- (tty->ldisc.write_wakeup)(tty); ++ tty_wakeup(tty); + } + + /* +@@ -1216,7 +1205,7 @@ + { + struct uart_state *state = tty->driver_data; + struct uart_port *port; +- ++ + BUG_ON(!kernel_locked()); + + if (!state || !state->port) +@@ -1239,12 +1228,12 @@ + * one, we've got real problems, since it means the + * serial port won't be shutdown. + */ +- printk("uart_close: bad serial port count; tty->count is 1, " ++ printk(KERN_ERR "uart_close: bad serial port count; tty->count is 1, " + "state->count is %d\n", state->count); + state->count = 1; + } + if (--state->count < 0) { +- printk("rs_close: bad serial port count for %s: %d\n", ++ printk(KERN_ERR "uart_close: bad serial port count for %s: %d\n", + tty->name, state->count); + state->count = 0; + } +@@ -1280,8 +1269,9 @@ + + uart_shutdown(state); + uart_flush_buffer(tty); +- if (tty->ldisc.flush_buffer) +- tty->ldisc.flush_buffer(tty); ++ ++ tty_ldisc_flush(tty); ++ + tty->closing = 0; + state->info->tty = NULL; + +diff -Nur linux-2.6.8.1/drivers/tc/zs.c linux-2.6.8.1-plasmaroo/drivers/tc/zs.c +--- linux-2.6.8.1/drivers/tc/zs.c 2004-08-14 11:56:00.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/tc/zs.c 2004-11-06 22:55:11.138575624 +0000 +@@ -683,10 +683,7 @@ + return; + + if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { +- 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); + } + } + +@@ -1010,10 +1007,7 @@ + cli(); + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + sti(); +- wake_up_interruptible(&tty->write_wait); +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && +- tty->ldisc.write_wakeup) +- (tty->ldisc.write_wakeup)(tty); ++ tty_wakeup(tty); + } + + /* +@@ -1407,8 +1401,7 @@ + shutdown(info); + if (tty->driver->flush_buffer) + tty->driver->flush_buffer(tty); +- if (tty->ldisc.flush_buffer) +- tty->ldisc.flush_buffer(tty); ++ tty_ldisc_flush(tty); + tty->closing = 0; + info->event = 0; + info->tty = 0; +diff -Nur linux-2.6.8.1/drivers/usb/class/bluetty.c linux-2.6.8.1-plasmaroo/drivers/usb/class/bluetty.c +--- linux-2.6.8.1/drivers/usb/class/bluetty.c 2004-08-14 11:55:48.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/usb/class/bluetty.c 2004-11-06 22:55:11.145574560 +0000 +@@ -992,17 +992,10 @@ + + dbg("%s", __FUNCTION__); + +- if (!bluetooth) { ++ if (!bluetooth) + return; +- } +- +- tty = bluetooth->tty; +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) { +- dbg("%s - write wakeup call.", __FUNCTION__); +- (tty->ldisc.write_wakeup)(tty); +- } + +- wake_up_interruptible(&tty->write_wait); ++ tty_wakeup(&bluetooth->tty); + } + + +diff -Nur linux-2.6.8.1/drivers/usb/class/cdc-acm.c linux-2.6.8.1-plasmaroo/drivers/usb/class/cdc-acm.c +--- linux-2.6.8.1/drivers/usb/class/cdc-acm.c 2004-08-14 11:55:35.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/usb/class/cdc-acm.c 2004-11-06 22:55:11.146574408 +0000 +@@ -248,16 +248,11 @@ + static void acm_softint(void *private) + { + struct acm *acm = private; +- struct tty_struct *tty = acm->tty; + dbg("Entering acm_softint.\n"); + + if (!ACM_READY(acm)) + return; +- +- 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(acm->tty); + } + + /* +diff -Nur linux-2.6.8.1/drivers/usb/serial/digi_acceleport.c linux-2.6.8.1-plasmaroo/drivers/usb/serial/digi_acceleport.c +--- linux-2.6.8.1/drivers/usb/serial/digi_acceleport.c 2004-08-14 11:55:31.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/usb/serial/digi_acceleport.c 2004-11-06 22:55:11.152573496 +0000 +@@ -624,14 +624,7 @@ + wake_up_interruptible( &port->write_wait ); + + /* wake up line discipline */ +- if( (tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) +- && tty->ldisc.write_wakeup ) +- (tty->ldisc.write_wakeup)(tty); +- +- /* wake up other tty processes */ +- wake_up_interruptible( &tty->write_wait ); +- /* For 2.2.16 backport -- wake_up_interruptible( &tty->poll_wait ); */ +- ++ tty_wakeup(tty); + } + + +@@ -1569,8 +1562,7 @@ + /* flush driver and line discipline buffers */ + if( tty->driver->flush_buffer ) + tty->driver->flush_buffer( tty ); +- if( tty->ldisc.flush_buffer ) +- tty->ldisc.flush_buffer( tty ); ++ tty_ldisc_flush(tty); + + if (port->serial->dev) { + /* wait for transmit idle */ +diff -Nur linux-2.6.8.1/drivers/usb/serial/empeg.c linux-2.6.8.1-plasmaroo/drivers/usb/serial/empeg.c +--- linux-2.6.8.1/drivers/usb/serial/empeg.c 2004-08-14 11:56:23.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/usb/serial/empeg.c 2004-11-06 22:55:11.155573040 +0000 +@@ -516,7 +516,9 @@ + */ + port->tty->low_latency = 1; + +- /* Notify the tty driver that the termios have changed. */ ++ /* Notify the tty driver that the termios have changed. ++ FIXME: Why - the ldisc will do this anyway and NULL is not ++ a valid previous state */ + port->tty->ldisc.set_termios(port->tty, NULL); + + return; +diff -Nur linux-2.6.8.1/drivers/usb/serial/io_edgeport.c linux-2.6.8.1-plasmaroo/drivers/usb/serial/io_edgeport.c +--- linux-2.6.8.1/drivers/usb/serial/io_edgeport.c 2004-08-14 11:54:48.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/usb/serial/io_edgeport.c 2004-11-06 22:55:11.169570912 +0000 +@@ -900,12 +900,7 @@ + + if (tty && edge_port->open) { + /* let the tty driver wakeup if it has a special write_wakeup function */ +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) { +- (tty->ldisc.write_wakeup)(tty); +- } +- +- /* tell the tty driver that something has changed */ +- wake_up_interruptible(&tty->write_wait); ++ tty_wakeup(tty); + } + + // Release the Write URB +diff -Nur linux-2.6.8.1/drivers/usb/serial/io_ti.c linux-2.6.8.1-plasmaroo/drivers/usb/serial/io_ti.c +--- linux-2.6.8.1/drivers/usb/serial/io_ti.c 2004-08-14 11:56:23.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/usb/serial/io_ti.c 2004-11-06 22:55:11.178569544 +0000 +@@ -1804,12 +1804,7 @@ + tty = port->tty; + if (tty) { + /* let the tty driver wakeup if it has a special write_wakeup function */ +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) { +- (tty->ldisc.write_wakeup)(tty); +- } +- +- /* tell the tty driver that something has changed */ +- wake_up_interruptible(&tty->write_wait); ++ tty_wakeup(tty); + } + } + +diff -Nur linux-2.6.8.1/drivers/usb/serial/ir-usb.c linux-2.6.8.1-plasmaroo/drivers/usb/serial/ir-usb.c +--- linux-2.6.8.1/drivers/usb/serial/ir-usb.c 2004-08-14 11:55:31.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/usb/serial/ir-usb.c 2004-11-06 22:55:11.188568024 +0000 +@@ -449,6 +449,10 @@ + */ + tty = port->tty; + ++ /* ++ * FIXME: must not do this in IRQ context, ++ * must honour TTY_DONT_FLIP ++ */ + tty->ldisc.receive_buf( + tty, + data+1, +diff -Nur linux-2.6.8.1/drivers/usb/serial/keyspan_pda.c linux-2.6.8.1-plasmaroo/drivers/usb/serial/keyspan_pda.c +--- linux-2.6.8.1/drivers/usb/serial/keyspan_pda.c 2004-08-14 11:55:35.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/usb/serial/keyspan_pda.c 2004-11-06 22:55:11.189567872 +0000 +@@ -186,13 +186,7 @@ + wake_up_interruptible( &port->write_wait ); + + /* wake up line discipline */ +- if( (tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) +- && tty->ldisc.write_wakeup ) +- (tty->ldisc.write_wakeup)(tty); +- +- /* wake up other tty processes */ +- wake_up_interruptible( &tty->write_wait ); +- /* For 2.2.16 backport -- wake_up_interruptible( &tty->poll_wait ); */ ++ tty_wakeup(tty); + } + + static void keyspan_pda_request_unthrottle( struct usb_serial *serial ) +diff -Nur linux-2.6.8.1/drivers/usb/serial/mct_u232.c linux-2.6.8.1-plasmaroo/drivers/usb/serial/mct_u232.c +--- linux-2.6.8.1/drivers/usb/serial/mct_u232.c 2004-08-14 11:55:47.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/usb/serial/mct_u232.c 2004-11-06 22:55:11.195566960 +0000 +@@ -579,11 +579,7 @@ + + if (write_blocking) { + wake_up_interruptible(&port->write_wait); +- 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); + } else { + /* from generic_write_bulk_callback */ + schedule_work(&port->work); +diff -Nur linux-2.6.8.1/drivers/usb/serial/usb-serial.c linux-2.6.8.1-plasmaroo/drivers/usb/serial/usb-serial.c +--- linux-2.6.8.1/drivers/usb/serial/usb-serial.c 2004-08-14 11:56:26.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/usb/serial/usb-serial.c 2004-11-06 22:55:11.209564832 +0000 +@@ -755,12 +755,7 @@ + if (!tty) + return; + +- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) { +- dbg("%s - write wakeup call.", __FUNCTION__); +- (tty->ldisc.write_wakeup)(tty); +- } +- +- wake_up_interruptible(&tty->write_wait); ++ tty_wakeup(tty); + } + + static void destroy_serial(struct kref *kref) +diff -Nur linux-2.6.8.1/drivers/usb/serial/whiteheat.c linux-2.6.8.1-plasmaroo/drivers/usb/serial/whiteheat.c +--- linux-2.6.8.1/drivers/usb/serial/whiteheat.c 2004-08-14 11:55:10.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/drivers/usb/serial/whiteheat.c 2004-11-06 22:55:11.217563616 +0000 +@@ -668,8 +668,7 @@ + + if (port->tty->driver->flush_buffer) + port->tty->driver->flush_buffer(port->tty); +- if (port->tty->ldisc.flush_buffer) +- port->tty->ldisc.flush_buffer(port->tty); ++ tty_ldisc_flush(port->tty); + + firm_report_tx_done(port); + +diff -Nur linux-2.6.8.1/fs/proc/proc_tty.c linux-2.6.8.1-plasmaroo/fs/proc/proc_tty.c +--- linux-2.6.8.1/fs/proc/proc_tty.c 2004-08-14 11:55:10.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/fs/proc/proc_tty.c 2004-11-06 22:55:11.236560728 +0000 +@@ -15,9 +15,6 @@ + #include <linux/seq_file.h> + #include <asm/bitops.h> + +-extern struct tty_ldisc ldiscs[]; +- +- + static int tty_ldiscs_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data); + +@@ -159,12 +156,15 @@ + int i; + int len = 0; + off_t begin = 0; +- ++ struct tty_ldisc *ld; ++ + for (i=0; i < NR_LDISCS; i++) { +- if (!(ldiscs[i].flags & LDISC_FLAG_DEFINED)) ++ ld = tty_ldisc_get(i); ++ if (ld == NULL) + continue; + len += sprintf(page+len, "%-10s %2d\n", +- ldiscs[i].name ? ldiscs[i].name : "???", i); ++ ld->name ? ld->name : "???", i); ++ tty_ldisc_put(i); + if (len+begin > off+count) + break; + if (len+begin < off) { +diff -Nur linux-2.6.8.1/include/linux/tty.h linux-2.6.8.1-plasmaroo/include/linux/tty.h +--- linux-2.6.8.1/include/linux/tty.h 2004-08-14 11:55:32.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/include/linux/tty.h 2004-11-06 22:55:11.237560576 +0000 +@@ -306,26 +306,27 @@ + * tty->write. Thus, you must use the inline functions set_bit() and + * clear_bit() to make things atomic. + */ +-#define TTY_THROTTLED 0 +-#define TTY_IO_ERROR 1 +-#define TTY_OTHER_CLOSED 2 +-#define TTY_EXCLUSIVE 3 +-#define TTY_DEBUG 4 +-#define TTY_DO_WRITE_WAKEUP 5 +-#define TTY_PUSH 6 +-#define TTY_CLOSING 7 +-#define TTY_DONT_FLIP 8 +-#define TTY_HW_COOK_OUT 14 +-#define TTY_HW_COOK_IN 15 +-#define TTY_PTY_LOCK 16 +-#define TTY_NO_WRITE_SPLIT 17 ++#define TTY_THROTTLED 0 /* Call unthrottle() at threshold min */ ++#define TTY_IO_ERROR 1 /* Canse an I/O error (may be no ldisc too) */ ++#define TTY_OTHER_CLOSED 2 /* Other side (if any) has closed */ ++#define TTY_EXCLUSIVE 3 /* Exclusive open mode */ ++#define TTY_DEBUG 4 /* Debugging */ ++#define TTY_DO_WRITE_WAKEUP 5 /* Call write_wakeup after queuing new */ ++#define TTY_PUSH 6 /* n_tty private */ ++#define TTY_CLOSING 7 /* ->close() in progress */ ++#define TTY_DONT_FLIP 8 /* Defer buffer flip */ ++#define TTY_LDISC 9 /* Line discipline attached */ ++#define TTY_HW_COOK_OUT 14 /* Hardware can do output cooking */ ++#define TTY_HW_COOK_IN 15 /* Hardware can do input cooking */ ++#define TTY_PTY_LOCK 16 /* pty private */ ++#define TTY_NO_WRITE_SPLIT 17 /* Preserve write boundaries to driver */ ++#define TTY_HUPPED 18 /* Post driver->hangup() */ + + #define TTY_WRITE_FLUSH(tty) tty_write_flush((tty)) + + extern void tty_write_flush(struct tty_struct *); + + extern struct termios tty_std_termios; +-extern struct tty_ldisc ldiscs[]; + extern int fg_console, last_console, want_console; + + extern int kmsg_redirect; +@@ -362,6 +363,16 @@ + extern int tty_get_baud_rate(struct tty_struct *tty); + extern int tty_termios_baud_rate(struct termios *termios); + ++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 void tty_wakeup(struct tty_struct *tty); ++extern void tty_ldisc_flush(struct tty_struct *tty); ++ + struct semaphore; + extern struct semaphore tty_sem; + +diff -Nur linux-2.6.8.1/include/linux/tty_ldisc.h linux-2.6.8.1-plasmaroo/include/linux/tty_ldisc.h +--- linux-2.6.8.1/include/linux/tty_ldisc.h 2004-08-14 11:56:23.000000000 +0100 ++++ linux-2.6.8.1-plasmaroo/include/linux/tty_ldisc.h 2004-11-06 22:55:11.238560424 +0000 +@@ -95,6 +95,13 @@ + * that line discpline should try to send more characters to the + * low-level driver for transmission. If the line discpline does + * not have any more data to send, it can just return. ++ * ++ * int (*hangup)(struct tty_struct *) ++ * ++ * Called on a hangup. Tells the discipline that it should ++ * cease I/O to the tty driver. Can sleep. The driver should ++ * seek to perform this action quickly but should wait until ++ * any pending driver I/O is completed. + */ + + #include <linux/fs.h> +@@ -122,6 +129,7 @@ + void (*set_termios)(struct tty_struct *tty, struct termios * old); + unsigned int (*poll)(struct tty_struct *, struct file *, + struct poll_table_struct *); ++ int (*hangup)(struct tty_struct *tty); + + /* + * The following routines are called from below. +@@ -132,6 +140,8 @@ + void (*write_wakeup)(struct tty_struct *); + + struct module *owner; ++ ++ int refcount; + }; + + #define TTY_LDISC_MAGIC 0x5403 diff --git a/sys-kernel/hppa-dev-sources/files/CAN-2004-0883.patch b/sys-kernel/hppa-dev-sources/files/CAN-2004-0883.patch new file mode 100644 index 000000000000..99401cf93a0e --- /dev/null +++ b/sys-kernel/hppa-dev-sources/files/CAN-2004-0883.patch @@ -0,0 +1,93 @@ +diff -urN linux-2.6.8.1/fs/smbfs/proc.c linux-2.6.8.1.plasmaroo/fs/smbfs/proc.c +--- linux-2.6.8.1/fs/smbfs/proc.c 2004-08-24 17:15:57.000000000 +1000 ++++ linux-2.6.8.1.plasmaroo/fs/smbfs/proc.c 2004-11-06 11:27:20.000000000 +1100 +@@ -1427,9 +1427,9 @@ + * So we must first calculate the amount of padding used by the server. + */ + data_off -= hdrlen; +- if (data_off > SMB_READX_MAX_PAD) { +- PARANOIA("offset is larger than max pad!\n"); +- PARANOIA("%d > %d\n", data_off, SMB_READX_MAX_PAD); ++ if (data_off > SMB_READX_MAX_PAD || data_off < 0) { ++ PARANOIA("offset is larger than SMB_READX_MAX_PAD or negative!\n"); ++ PARANOIA("%d > %d || %d < 0\n", data_off, SMB_READX_MAX_PAD, data_off); + req->rq_rlen = req->rq_bufsize + 1; + return; + } +diff -urN linux-2.6.8.1/fs/smbfs/request.c linux-2.6.8.1.plasmaroo/fs/smbfs/request.c +--- linux-2.6.8.1/fs/smbfs/request.c 2004-11-06 11:27:51.000000000 +1100 ++++ linux-2.6.8.1.plasmaroo/fs/smbfs/request.c 2004-11-06 11:27:20.000000000 +1100 +@@ -588,6 +588,10 @@ + data_count = WVAL(inbuf, smb_drcnt); + + /* Modify offset for the split header/buffer we use */ ++ if (data_offset < hdrlen) ++ goto out_bad_data; ++ if (parm_offset < hdrlen) ++ goto out_bad_parm; + data_offset -= hdrlen; + parm_offset -= hdrlen; + +@@ -607,6 +611,10 @@ + req->rq_lparm = parm_count; + req->rq_data = req->rq_buffer + data_offset; + req->rq_parm = req->rq_buffer + parm_offset; ++ if (parm_offset + parm_count > req->rq_rlen) ++ goto out_bad_parm; ++ if (data_offset + data_count > req->rq_rlen) ++ goto out_bad_data; + return 0; + } + +@@ -634,6 +642,7 @@ + req->rq_trans2buffer = smb_kmalloc(buf_len, GFP_NOFS); + if (!req->rq_trans2buffer) + goto out_no_mem; ++ memset(req->rq_trans2buffer, 0, buf_len); + + req->rq_parm = req->rq_trans2buffer; + req->rq_data = req->rq_trans2buffer + parm_tot; +@@ -643,8 +652,12 @@ + + if (parm_disp + parm_count > req->rq_total_parm) + goto out_bad_parm; ++ if (parm_offset + parm_count > req->rq_rlen) ++ goto out_bad_parm; + if (data_disp + data_count > req->rq_total_data) + goto out_bad_data; ++ if (data_offset + data_count > req->rq_rlen) ++ goto out_bad_data; + + inbuf = req->rq_buffer; + memcpy(req->rq_parm + parm_disp, inbuf + parm_offset, parm_count); +@@ -657,8 +670,11 @@ + * Check whether we've received all of the data. Note that + * we use the packet totals -- total lengths might shrink! + */ +- if (req->rq_ldata >= data_tot && req->rq_lparm >= parm_tot) ++ if (req->rq_ldata >= data_tot && req->rq_lparm >= parm_tot) { ++ req->rq_ldata = data_tot; ++ req->rq_lparm = parm_tot; + return 0; ++ } + return 1; + + out_too_long: +@@ -676,13 +692,13 @@ + req->rq_errno = -EIO; + goto out; + out_bad_parm: +- printk(KERN_ERR "smb_trans2: invalid parms, disp=%d, cnt=%d, tot=%d\n", +- parm_disp, parm_count, parm_tot); ++ printk(KERN_ERR "smb_trans2: invalid parms, disp=%d, cnt=%d, tot=%d, ofs=%d\n", ++ parm_disp, parm_count, parm_tot, parm_offset); + req->rq_errno = -EIO; + goto out; + out_bad_data: +- printk(KERN_ERR "smb_trans2: invalid data, disp=%d, cnt=%d, tot=%d\n", +- data_disp, data_count, data_tot); ++ printk(KERN_ERR "smb_trans2: invalid data, disp=%d, cnt=%d, tot=%d, ofs=%d\n", ++ data_disp, data_count, data_tot, data_offset); + req->rq_errno = -EIO; + out: + return req->rq_errno; diff --git a/sys-kernel/hppa-dev-sources/files/binfmt_elf-loader-security.patch b/sys-kernel/hppa-dev-sources/files/binfmt_elf-loader-security.patch new file mode 100644 index 000000000000..9ca23675f25d --- /dev/null +++ b/sys-kernel/hppa-dev-sources/files/binfmt_elf-loader-security.patch @@ -0,0 +1,72 @@ +--- linux-2.6.7-uc0-r8/fs/binfmt_elf.c 2004-11-12 11:50:08 -08:00 ++++ linux-2.6.7-uc0-r8-plasmaroo/fs/binfmt_elf.c 2004-11-12 11:50:08 -08:00 +@@ -335,9 +335,12 @@ + goto out; + + retval = kernel_read(interpreter,interp_elf_ex->e_phoff,(char *)elf_phdata,size); +- error = retval; +- if (retval < 0) ++ error = -EIO; ++ if (retval != size) { ++ if (retval < 0) ++ error = retval; + goto out_close; ++ } + + eppnt = elf_phdata; + for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) { +@@ -532,8 +535,11 @@ + goto out; + + retval = kernel_read(bprm->file, elf_ex.e_phoff, (char *) elf_phdata, size); +- if (retval < 0) ++ if (retval != size) { ++ if (retval >= 0) ++ retval = -EIO; + goto out_free_ph; ++ } + + files = current->files; /* Refcounted so ok */ + retval = unshare_files(); +@@ -580,8 +586,14 @@ + retval = kernel_read(bprm->file, elf_ppnt->p_offset, + elf_interpreter, + elf_ppnt->p_filesz); +- if (retval < 0) ++ if (retval != elf_ppnt->p_filesz) { ++ if (retval >= 0) ++ retval = -EIO; + goto out_free_interp; ++ } ++ /* make sure path is NULL terminated */ ++ elf_interpreter[elf_ppnt->p_filesz - 1] = '\0'; ++ + /* If the program interpreter is one of these two, + * then assume an iBCS2 image. Otherwise assume + * a native linux image. +@@ -616,8 +628,11 @@ + if (IS_ERR(interpreter)) + goto out_free_interp; + retval = kernel_read(interpreter, 0, bprm->buf, BINPRM_BUF_SIZE); +- if (retval < 0) ++ if (retval != BINPRM_BUF_SIZE) { ++ if (retval >= 0) ++ retval = -EIO; + goto out_free_dentry; ++ } + + /* Get the exec headers */ + loc->interp_ex = *((struct exec *) bprm->buf); +@@ -776,8 +791,10 @@ + } + + error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, elf_prot, elf_flags); +- if (BAD_ADDR(error)) +- continue; ++ if (BAD_ADDR(error)) { ++ send_sig(SIGKILL, current, 0); ++ goto out_free_dentry; ++ } + + if (!load_addr_set) { + load_addr_set = 1; diff --git a/sys-kernel/hppa-dev-sources/files/digest-hppa-dev-sources-2.6.8.1_p11-r1 b/sys-kernel/hppa-dev-sources/files/digest-hppa-dev-sources-2.6.8.1_p11-r1 new file mode 100644 index 000000000000..4571cc199906 --- /dev/null +++ b/sys-kernel/hppa-dev-sources/files/digest-hppa-dev-sources-2.6.8.1_p11-r1 @@ -0,0 +1,2 @@ +MD5 9517ca999e822b898fbdc7e72796b1aa linux-2.6.8.1.tar.bz2 35628066 +MD5 7d2bce70b2d231234bef64dbebb33385 patch-2.6.8.1-pa11.gz 89416 diff --git a/sys-kernel/hppa-dev-sources/files/ptmx-security.patch b/sys-kernel/hppa-dev-sources/files/ptmx-security.patch new file mode 100644 index 000000000000..2312a2bf5e3b --- /dev/null +++ b/sys-kernel/hppa-dev-sources/files/ptmx-security.patch @@ -0,0 +1,21 @@ +Index: linux-2.6.5/fs/devpts/inode.c +=================================================================== +--- linux-2.6.5.orig/fs/devpts/inode.c ++++ linux-2.6.5/fs/devpts/inode.c +@@ -178,9 +178,13 @@ struct tty_struct *devpts_get_tty(int nu + { + struct dentry *dentry = get_node(number); + struct tty_struct *tty; +- +- tty = (IS_ERR(dentry) || !dentry->d_inode) ? NULL : +- dentry->d_inode->u.generic_ip; ++ ++ tty = NULL; ++ if (!IS_ERR(dentry)) { ++ if (dentry->d_inode) ++ tty = dentry->d_inode->u.generic_ip; ++ dput(dentry); ++ } + + up(&devpts_root->d_inode->i_sem); + diff --git a/sys-kernel/hppa-dev-sources/hppa-dev-sources-2.6.8.1_p11-r1.ebuild b/sys-kernel/hppa-dev-sources/hppa-dev-sources-2.6.8.1_p11-r1.ebuild new file mode 100644 index 000000000000..e5bee9809ecb --- /dev/null +++ b/sys-kernel/hppa-dev-sources/hppa-dev-sources-2.6.8.1_p11-r1.ebuild @@ -0,0 +1,36 @@ +# Copyright 1999-2004 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-x86/sys-kernel/hppa-dev-sources/hppa-dev-sources-2.6.8.1_p11-r1.ebuild,v 1.1 2004/11/24 17:35:47 gmsoft Exp $ +#OKV=original kernel version, KV=patched kernel version. They can be the same. + +ETYPE="sources" +inherit kernel-2 eutils +OKV="${PV/_p*/}" +PATCH_LEVEL="${PV/${OKV}_p/}" +EXTRAVERSION="-pa${PATCH_LEVEL}" +[ ! "${PR}" = "r0" ] && EXTRAVERSION="${EXTRAVERSION}-${PR}" +KV=${OKV}${EXTRAVERSION} +S=${WORKDIR}/linux-${KV} + + +DESCRIPTION="Full sources for the Linux kernel with patch for hppa" +SRC_URI="mirror://kernel/linux/kernel/v2.6/linux-${OKV}.tar.bz2 http://ftp.parisc-linux.org/cvs/linux-2.6/patch-${OKV}-pa${PATCH_LEVEL}.gz" +HOMEPAGE="http://www.kernel.org/ http://www.gentoo.org/ http://parisc-linux.org" +KEYWORDS="hppa -*" +IUSE="" +SLOT="${KV}" + + +src_unpack() { + unpack linux-${OKV}.tar.bz2 + mv ${WORKDIR}/linux-${OKV} ${WORKDIR}/linux-${KV} + cd ${S} + + epatch ${DISTDIR}/patch-${OKV}-pa${PATCH_LEVEL}.gz + epatch ${FILESDIR}/security-proc-cmdline.patch + epatch ${FILESDIR}/binfmt_elf-loader-security.patch + epatch ${FILESDIR}/CAN-2004-0883.patch + epatch ${FILESDIR}/ptmx-security.patch + epatch ${FILESDIR}/CAN-2004-0814.patch + +} |