r2013 - in trunk/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian: . patches patches/series
Simon Horman
horms@haydn.debian.org
Tue, 21 Dec 2004 02:35:18 -0700
Author: horms
Date: 2004-12-21 02:34:50 -0700 (Tue, 21 Dec 2004)
New Revision: 2013
Added:
trunk/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/patches/093-tty_lockup-3.diff
Removed:
trunk/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/patches/115_tty_lockup-3.diff
Modified:
trunk/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/changelog
trunk/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/patches/series/2.4.27-7
Log:
updated tty/ldisc fix (CAN-2004-0814)
Modified: trunk/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/changelog
===================================================================
--- trunk/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/changelog 2004-12-21 08:22:52 UTC (rev 2012)
+++ trunk/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/changelog 2004-12-21 09:34:50 UTC (rev 2013)
@@ -13,10 +13,12 @@
(dann frazier)
* 117-igmp-source-filter-fixes.patch: IGMP source filter fixes
(CAN-2004-1137) (dann frazier)
- * 119-acpi_early-build.diff: Build fix for ACPI
+ * 119-acpi_early-build.diff: Build fix for ACPI
(Closes: #286226) (Simon Horman)
+ * 093-tty_lockup-3.diff: Updateded patch for race conditions in
+ linux terminal subsystem from uptream (CAN-2004-0814) (Simon Horman)
- -- Simon Horman <horms@debian.org> Tue, 21 Dec 2004 17:11:10 +0900
+ -- Simon Horman <horms@debian.org> Tue, 21 Dec 2004 18:27:09 +0900
kernel-source-2.4.27 (2.4.27-6) unstable; urgency=low
Added: trunk/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/patches/093-tty_lockup-3.diff
===================================================================
--- trunk/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/patches/093-tty_lockup-3.diff 2004-12-21 08:22:52 UTC (rev 2012)
+++ trunk/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/patches/093-tty_lockup-3.diff 2004-12-21 09:34:50 UTC (rev 2013)
@@ -0,0 +1,4732 @@
+# origin: marcelo (BitKeeper)
+# cset: 1.1546 (2.4) key=41c3801dxJnuBSRCpUiMRkwItPHjWA
+# inclusion: upstream
+# descrition: [PATCH] Backport v2.6 tty/ldisc locking fixes
+# revision date: Tue, 21 Dec 2004 17:33:16 +0900
+#
+# S rset: ChangeSet|1.1545..1.1546
+# I rset: drivers/char/rio/riointr.c|1.4..1.5
+# I rset: drivers/char/mux.c|1.1..1.2
+# I rset: drivers/char/esp.c|1.8..1.9
+# I rset: drivers/net/wan/8253x/8253xutl.c|1.2..1.3
+# I rset: drivers/char/vme_scc.c|1.5..1.6
+# I rset: drivers/char/n_tty.c|1.6..1.7
+# I rset: drivers/char/isicom.c|1.8..1.9
+# I rset: drivers/usb/serial/io_edgeport.c|1.29..1.30
+# I rset: drivers/char/dz.c|1.11..1.12
+# I rset: drivers/char/serial_amba.c|1.5..1.6
+# I rset: drivers/sbus/char/aurora.c|1.15..1.16
+# I rset: drivers/net/hamradio/6pack.c|1.8..1.9
+# I rset: drivers/sbus/char/su.c|1.13..1.14
+# I rset: drivers/char/stallion.c|1.9..1.10
+# I rset: drivers/usb/bluetooth.c|1.18..1.19
+# I rset: drivers/net/wan/x25_asy.c|1.3..1.4
+# I rset: drivers/char/cyclades.c|1.10..1.11
+# I rset: net/bluetooth/rfcomm/tty.c|1.11..1.12
+# I rset: drivers/net/irda/irtty.c|1.11..1.12
+# I rset: drivers/char/sgiserial.c|1.9..1.10
+# I rset: drivers/char/n_hdlc.c|1.5..1.6
+# I rset: drivers/char/ser_a2232.c|1.3..1.4
+# I rset: drivers/char/serial.c|1.39..1.40
+# I rset: drivers/char/hvc_console.c|1.2..1.3
+# I rset: drivers/char/pty.c|1.5..1.6
+# I rset: net/irda/ircomm/ircomm_tty.c|1.8..1.9
+# I rset: drivers/char/synclink.c|1.16..1.17
+# I rset: fs/proc/proc_tty.c|1.2..1.3
+# I rset: drivers/net/wan/pc300_tty.c|1.2..1.3
+# I rset: drivers/char/serial_txx927.c|1.4..1.5
+# I rset: drivers/sbus/char/sab82532.c|1.11..1.12
+# I rset: drivers/char/sx.c|1.14..1.15
+# I rset: drivers/usb/serial/usbserial.c|1.32..1.33
+# I rset: drivers/net/ppp_synctty.c|1.6..1.7
+# I rset: drivers/char/serial167.c|1.7..1.8
+# I rset: drivers/macintosh/macserial.c|1.8..1.9
+# I rset: drivers/net/hamradio/mkiss.c|1.7..1.8
+# I rset: drivers/char/pdc_console.c|1.2..1.3
+# I rset: drivers/char/riscom8.c|1.5..1.6
+# I rset: drivers/char/synclinkmp.c|1.5..1.6
+# I rset: drivers/usb/serial/digi_acceleport.c|1.14..1.15
+# I rset: drivers/net/wan/sdla_chdlc.c|1.15..1.16
+# I rset: drivers/char/pcmcia/synclink_cs.c|1.3..1.4
+# I rset: include/linux/tty.h|1.6..1.7
+# I rset: drivers/char/generic_serial.c|1.5..1.6
+# I rset: drivers/char/serial_tx3912.c|1.6..1.7
+# I rset: drivers/s390/net/ctctty.c|1.5..1.6
+# I rset: drivers/char/epca.c|1.10..1.11
+# I rset: drivers/char/tty_io.c|1.32..1.33
+# I rset: drivers/char/pcxx.c|1.6..1.7
+# I rset: drivers/net/wan/8253x/8253xtty.c|1.2..1.3
+# I rset: drivers/char/istallion.c|1.10..1.11
+# I rset: drivers/usb/acm.c|1.16..1.17
+# I rset: drivers/net/wan/8253x/8253xsyn.c|1.1..1.2
+# I rset: drivers/usb/serial/keyspan_pda.c|1.11..1.12
+# I rset: drivers/usb/serial/mct_u232.c|1.20..1.21
+# I rset: arch/cris/drivers/serial.c|1.16..1.17
+# I rset: drivers/char/mxser.c|1.12..1.13
+# I rset: drivers/char/rocket.c|1.10..1.11
+# I rset: drivers/s390/char/con3215.c|1.7..1.8
+# I rset: drivers/char/vt.c|1.14..1.15
+# I rset: drivers/net/strip.c|1.5..1.6
+# I rset: drivers/isdn/isdn_tty.c|1.9..1.10
+# I rset: arch/ppc/8xx_io/uart.c|1.23..1.24
+# I rset: drivers/net/ppp_async.c|1.8..1.9
+# I rset: drivers/s390/char/tubtty.c|1.7..1.8
+# I rset: drivers/tc/zs.c|1.7..1.8
+# I rset: drivers/bluetooth/hci_ldisc.c|1.7..1.8
+# I rset: drivers/char/specialix.c|1.5..1.6
+# I rset: drivers/char/moxa.c|1.7..1.8
+# I rset: drivers/char/n_r3964.c|1.8..1.9
+# I rset: drivers/char/sh-sci.c|1.14..1.15
+# I rset: drivers/char/selection.c|1.3..1.4
+# I rset: drivers/usb/serial/io_ti.c|1.8..1.9
+# I rset: drivers/char/ip2/i2lib.c|1.4..1.5
+# I rset: include/linux/tty_ldisc.h|1.2..1.3
+# I rset: drivers/char/amiserial.c|1.8..1.9
+# I rset: drivers/char/tty_ioctl.c|1.4..1.5
+# I rset: drivers/sbus/char/zs.c|1.11..1.12
+# I rset: drivers/net/slip.c|1.7..1.8
+# I rset: drivers/char/ip2main.c|1.10..1.11
+#
+# This is a BitKeeper generated diff -Nru style patch.
+#
+# ChangeSet
+# 2004/12/17 22:55:57-02:00 marcelo@logos.cnet
+# [PATCH] Backport v2.6 tty/ldisc locking fixes
+#
+# net/irda/ircomm/ircomm_tty.c
+# 2004/12/16 12:09:13-02:00 marcelo@logos.cnet +2 -8
+# Import patch 2.4-tty-V8.patch
+#
+# net/bluetooth/rfcomm/tty.c
+# 2004/12/16 12:20:47-02:00 marcelo@logos.cnet +2 -5
+# Import patch 2.4-tty-V8.patch
+#
+# include/linux/tty_ldisc.h
+# 2004/12/16 11:57:23-02:00 marcelo@logos.cnet +9 -0
+# Import patch 2.4-tty-V8.patch
+#
+# include/linux/tty.h
+# 2004/12/16 11:57:23-02:00 marcelo@logos.cnet +28 -14
+# Import patch 2.4-tty-V8.patch
+#
+# fs/proc/proc_tty.c
+# 2004/12/16 11:57:23-02:00 marcelo@logos.cnet +6 -5
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/usb/serial/usbserial.c
+# 2004/12/16 12:55:02-02:00 marcelo@logos.cnet +10 -3
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/usb/serial/mct_u232.c
+# 2004/12/16 11:57:23-02:00 marcelo@logos.cnet +1 -5
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/usb/serial/keyspan_pda.c
+# 2004/12/16 11:57:23-02:00 marcelo@logos.cnet +1 -7
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/usb/serial/io_ti.c
+# 2004/12/16 11:57:23-02:00 marcelo@logos.cnet +1 -6
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/usb/serial/io_edgeport.c
+# 2004/12/16 11:57:23-02:00 marcelo@logos.cnet +1 -6
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/usb/serial/digi_acceleport.c
+# 2004/12/16 11:57:23-02:00 marcelo@logos.cnet +2 -10
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/usb/bluetooth.c
+# 2004/12/16 16:49:03-02:00 marcelo@logos.cnet +10 -3
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/usb/acm.c
+# 2004/12/16 12:55:33-02:00 marcelo@logos.cnet +1 -4
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/tc/zs.c
+# 2004/12/16 11:57:23-02:00 marcelo@logos.cnet +3 -10
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/sbus/char/zs.c
+# 2004/12/16 11:57:23-02:00 marcelo@logos.cnet +5 -12
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/sbus/char/su.c
+# 2004/12/16 13:07:37-02:00 marcelo@logos.cnet +3 -10
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/sbus/char/sab82532.c
+# 2004/12/16 13:06:52-02:00 marcelo@logos.cnet +3 -10
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/sbus/char/aurora.c
+# 2004/12/16 11:57:23-02:00 marcelo@logos.cnet +4 -11
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/s390/net/ctctty.c
+# 2004/12/16 12:59:01-02:00 marcelo@logos.cnet +4 -9
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/s390/char/tubtty.c
+# 2004/12/16 12:56:31-02:00 marcelo@logos.cnet +2 -8
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/s390/char/con3215.c
+# 2004/12/16 11:57:23-02:00 marcelo@logos.cnet +2 -8
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/net/wan/x25_asy.c
+# 2004/12/16 13:02:12-02:00 marcelo@logos.cnet +1 -3
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/net/wan/sdla_chdlc.c
+# 2004/12/16 11:57:23-02:00 marcelo@logos.cnet +8 -11
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/net/wan/pc300_tty.c
+# 2004/12/16 11:57:23-02:00 marcelo@logos.cnet +15 -19
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/net/wan/8253x/8253xutl.c
+# 2004/12/16 13:01:56-02:00 marcelo@logos.cnet +1 -6
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/net/wan/8253x/8253xtty.c
+# 2004/12/16 13:01:04-02:00 marcelo@logos.cnet +2 -8
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/net/wan/8253x/8253xsyn.c
+# 2004/12/16 13:00:20-02:00 marcelo@logos.cnet +1 -4
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/net/strip.c
+# 2004/12/16 13:02:33-02:00 marcelo@logos.cnet +1 -2
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/net/slip.c
+# 2004/12/16 11:57:23-02:00 marcelo@logos.cnet +12 -8
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/net/ppp_synctty.c
+# 2004/12/16 11:57:23-02:00 marcelo@logos.cnet +15 -0
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/net/ppp_async.c
+# 2004/12/16 11:57:23-02:00 marcelo@logos.cnet +28 -3
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/net/irda/irtty.c
+# 2004/12/16 12:59:36-02:00 marcelo@logos.cnet +2 -3
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/net/hamradio/mkiss.c
+# 2004/12/16 13:03:13-02:00 marcelo@logos.cnet +1 -2
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/net/hamradio/6pack.c
+# 2004/12/16 13:02:53-02:00 marcelo@logos.cnet +1 -2
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/macintosh/macserial.c
+# 2004/12/16 11:57:23-02:00 marcelo@logos.cnet +4 -12
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/isdn/isdn_tty.c
+# 2004/12/16 13:05:22-02:00 marcelo@logos.cnet +5 -16
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/char/vt.c
+# 2004/12/16 11:57:23-02:00 marcelo@logos.cnet +1 -2
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/char/vme_scc.c
+# 2004/12/16 11:57:23-02:00 marcelo@logos.cnet +2 -6
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/char/tty_ioctl.c
+# 2004/12/16 11:57:23-02:00 marcelo@logos.cnet +43 -11
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/char/tty_io.c
+# 2004/12/16 11:57:23-02:00 marcelo@logos.cnet +497 -87
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/char/synclinkmp.c
+# 2004/12/16 11:57:23-02:00 marcelo@logos.cnet +28 -21
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/char/synclink.c
+# 2004/12/16 16:43:15-02:00 marcelo@logos.cnet +30 -25
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/char/sx.c
+# 2004/12/16 11:57:23-02:00 marcelo@logos.cnet +1 -3
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/char/stallion.c
+# 2004/12/16 11:57:23-02:00 marcelo@logos.cnet +3 -10
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/char/specialix.c
+# 2004/12/16 13:28:34-02:00 marcelo@logos.cnet +4 -12
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/char/sh-sci.c
+# 2004/12/16 12:37:32-02:00 marcelo@logos.cnet +1 -4
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/char/sgiserial.c
+# 2004/12/16 11:57:23-02:00 marcelo@logos.cnet +2 -2
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/char/serial_txx927.c
+# 2004/12/16 12:38:45-02:00 marcelo@logos.cnet +3 -10
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/char/serial_tx3912.c
+# 2004/12/16 11:57:23-02:00 marcelo@logos.cnet +1 -4
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/char/serial_amba.c
+# 2004/12/16 12:40:14-02:00 marcelo@logos.cnet +3 -10
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/char/serial167.c
+# 2004/12/16 11:57:23-02:00 marcelo@logos.cnet +3 -18
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/char/serial.c
+# 2004/12/16 16:42:06-02:00 marcelo@logos.cnet +6 -12
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/char/ser_a2232.c
+# 2004/12/16 11:57:23-02:00 marcelo@logos.cnet +1 -4
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/char/selection.c
+# 2004/12/16 13:23:54-02:00 marcelo@logos.cnet +6 -2
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/char/rocket.c
+# 2004/12/16 11:57:23-02:00 marcelo@logos.cnet +10 -16
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/char/riscom8.c
+# 2004/12/16 11:57:23-02:00 marcelo@logos.cnet +3 -9
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/char/rio/riointr.c
+# 2004/12/16 12:41:40-02:00 marcelo@logos.cnet +1 -4
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/char/pty.c
+# 2004/12/16 12:40:52-02:00 marcelo@logos.cnet +7 -7
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/char/pdc_console.c
+# 2004/12/16 12:36:12-02:00 marcelo@logos.cnet +1 -2
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/char/pcxx.c
+# 2004/12/16 11:57:23-02:00 marcelo@logos.cnet +5 -31
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/char/pcmcia/synclink_cs.c
+# 2004/12/16 13:22:51-02:00 marcelo@logos.cnet +29 -19
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/char/n_tty.c
+# 2004/12/16 11:57:23-02:00 marcelo@logos.cnet +283 -48
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/char/n_r3964.c
+# 2004/12/16 11:57:23-02:00 marcelo@logos.cnet +2 -1
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/char/n_hdlc.c
+# 2004/12/16 12:36:41-02:00 marcelo@logos.cnet +2 -3
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/char/mxser.c
+# 2004/12/16 13:14:49-02:00 marcelo@logos.cnet +4 -10
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/char/mux.c
+# 2004/12/16 12:40:33-02:00 marcelo@logos.cnet +1 -2
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/char/moxa.c
+# 2004/12/16 13:14:38-02:00 marcelo@logos.cnet +5 -14
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/char/istallion.c
+# 2004/12/16 12:35:07-02:00 marcelo@logos.cnet +12 -10
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/char/isicom.c
+# 2004/12/16 13:13:54-02:00 marcelo@logos.cnet +5 -11
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/char/ip2main.c
+# 2004/12/16 12:27:10-02:00 marcelo@logos.cnet +2 -4
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/char/ip2/i2lib.c
+# 2004/12/16 12:44:31-02:00 marcelo@logos.cnet +2 -8
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/char/hvc_console.c
+# 2004/12/16 11:57:23-02:00 marcelo@logos.cnet +1 -4
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/char/generic_serial.c
+# 2004/12/16 13:13:15-02:00 marcelo@logos.cnet +5 -12
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/char/esp.c
+# 2004/12/16 11:57:23-02:00 marcelo@logos.cnet +3 -10
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/char/epca.c
+# 2004/12/16 13:13:00-02:00 marcelo@logos.cnet +9 -22
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/char/dz.c
+# 2004/12/16 11:57:23-02:00 marcelo@logos.cnet +5 -11
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/char/cyclades.c
+# 2004/12/16 11:57:23-02:00 marcelo@logos.cnet +3 -11
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/char/amiserial.c
+# 2004/12/16 13:11:41-02:00 marcelo@logos.cnet +3 -10
+# Import patch 2.4-tty-V8.patch
+#
+# drivers/bluetooth/hci_ldisc.c
+# 2004/12/16 13:03:36-02:00 marcelo@logos.cnet +5 -6
+# Import patch 2.4-tty-V8.patch
+#
+# arch/ppc/8xx_io/uart.c
+# 2004/12/16 12:22:28-02:00 marcelo@logos.cnet +3 -10
+# Import patch 2.4-tty-V8.patch
+#
+# arch/cris/drivers/serial.c
+# 2004/12/16 12:23:53-02:00 marcelo@logos.cnet +3 -11
+# Import patch 2.4-tty-V8.patch
+#
+#
+===== drivers/char/rio/riointr.c 1.4 vs 1.5 =====
+--- 1.4/drivers/char/rio/riointr.c 2002-02-05 16:45:07 +09:00
++++ 1.5/drivers/char/rio/riointr.c 2004-12-16 23:41:40 +09:00
+@@ -248,12 +248,9 @@
+ rio_dprintk (RIO_DEBUG_INTR, "Waking up.... ldisc:%d (%d/%d)....",
+ (int)(PortP->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)),
+ PortP->gs.wakeup_chars, PortP->gs.xmit_cnt);
+- if ((PortP->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+- PortP->gs.tty->ldisc.write_wakeup)
+- (PortP->gs.tty->ldisc.write_wakeup)(PortP->gs.tty);
++ tty_wakeup(PortP->gs.tty);
+ rio_dprintk (RIO_DEBUG_INTR, "(%d/%d)\n",
+ PortP->gs.wakeup_chars, PortP->gs.xmit_cnt);
+- wake_up_interruptible(&PortP->gs.tty->write_wait);
+ }
+
+ }
+===== drivers/char/mux.c 1.1 vs 1.2 =====
+--- 1.1/drivers/char/mux.c 2003-01-07 00:38:22 +09:00
++++ 1.2/drivers/char/mux.c 2004-12-16 23:40:33 +09:00
+@@ -429,8 +429,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;
+===== drivers/char/esp.c 1.8 vs 1.9 =====
+--- 1.8/drivers/char/esp.c 2002-03-11 23:13:27 +09:00
++++ 1.9/drivers/char/esp.c 2004-12-16 22:57:23 +09:00
+@@ -786,10 +786,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);
+ }
+ }
+
+@@ -1395,10 +1392,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);
+ }
+
+ /*
+@@ -2115,8 +2109,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;
+===== drivers/net/wan/8253x/8253xutl.c 1.2 vs 1.3 =====
+--- 1.2/drivers/net/wan/8253x/8253xutl.c 2002-05-10 08:16:03 +09:00
++++ 1.3/drivers/net/wan/8253x/8253xutl.c 2004-12-17 00:01:56 +09:00
+@@ -1412,11 +1412,6 @@
+ WRITEB(port,cmdr,SAB82532_CMDR_XRES);
+ restore_flags(flags);
+
+- wake_up_interruptible(&tty->write_wait); /* wake up tty driver */
+- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+- tty->ldisc.write_wakeup)
+- {
+- (*tty->ldisc.write_wakeup)(tty);
+- }
++ tty_wakeup(tty);
+ }
+
+===== drivers/char/vme_scc.c 1.5 vs 1.6 =====
+--- 1.5/drivers/char/vme_scc.c 2002-03-31 00:45:50 +09:00
++++ 1.6/drivers/char/vme_scc.c 2004-12-16 22:57:23 +09:00
+@@ -569,12 +569,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);
+ }
+===== drivers/char/n_tty.c 1.6 vs 1.7 =====
+--- 1.6/drivers/char/n_tty.c 2003-08-04 03:15:35 +09:00
++++ 1.7/drivers/char/n_tty.c 2004-12-16 22:57:23 +09:00
+@@ -112,11 +112,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 &&
+@@ -125,10 +132,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)
+ {
+@@ -142,9 +152,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 */
+@@ -159,9 +179,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;
+@@ -242,10 +267,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 * inbuf, unsigned int nr)
+ {
+@@ -334,6 +369,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;
+@@ -450,6 +495,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)
+@@ -461,6 +518,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))
+@@ -477,19 +544,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)
+ {
+@@ -507,6 +595,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;
+@@ -698,6 +796,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;
+@@ -716,10 +824,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)
+@@ -732,6 +843,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 queue_ldisc)
++ */
++
+ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
+ char *fp, int count)
+ {
+@@ -813,6 +937,18 @@
+ current->sig->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)
+@@ -828,7 +964,6 @@
+ I_ICRNL(tty) || I_INLCR(tty) || L_ICANON(tty) ||
+ I_IXON(tty) || L_ISIG(tty) || L_ECHO(tty) ||
+ I_PARMRK(tty)) {
+- cli();
+ memset(tty->process_char_map, 0, 256/8);
+
+ if (I_IGNCR(tty) || I_ICRNL(tty))
+@@ -864,7 +999,6 @@
+ set_bit(SUSP_CHAR(tty), &tty->process_char_map);
+ }
+ clear_bit(__DISABLED_CHAR, &tty->process_char_map);
+- sti();
+ tty->raw = 0;
+ tty->real_raw = 0;
+ } else {
+@@ -878,6 +1012,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);
+@@ -887,11 +1031,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)
+@@ -917,14 +1072,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 **b,
+ size_t *nr)
+@@ -952,25 +1116,18 @@
+ return retval;
+ }
+
+-static ssize_t read_chan(struct tty_struct *tty, struct file *file,
+- unsigned char *buf, size_t nr)
+-{
+- unsigned char *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 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)
++{
+ /* 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
+@@ -989,7 +1146,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) {
+@@ -1011,6 +1209,9 @@
+ }
+ }
+
++ /*
++ * Internal serialization of reads.
++ */
+ if (file->f_flags & O_NONBLOCK) {
+ if (down_trylock(&tty->atomic_read))
+ return -EAGAIN;
+@@ -1146,6 +1347,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 * buf, size_t nr)
+ {
+@@ -1217,7 +1433,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;
+@@ -1258,6 +1492,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 */
+===== drivers/char/isicom.c 1.8 vs 1.9 =====
+--- 1.8/drivers/char/isicom.c 2002-10-31 00:50:25 +09:00
++++ 1.9/drivers/char/isicom.c 2004-12-17 00:13:54 +09:00
+@@ -502,11 +502,8 @@
+
+ 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);
+ }
+
+ /* main interrupt handler routine */
+@@ -1199,8 +1196,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 = 0;
+ if (port->blocked_open) {
+@@ -1670,10 +1667,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);
+ }
+
+
+===== drivers/usb/serial/io_edgeport.c 1.29 vs 1.30 =====
+--- 1.29/drivers/usb/serial/io_edgeport.c 2004-07-15 20:48:06 +09:00
++++ 1.30/drivers/usb/serial/io_edgeport.c 2004-12-16 22:57:23 +09:00
+@@ -902,12 +902,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
+===== drivers/char/dz.c 1.11 vs 1.12 =====
+--- 1.11/drivers/char/dz.c 2003-10-13 21:43:06 +09:00
++++ 1.12/drivers/char/dz.c 2004-12-16 22:57:23 +09:00
+@@ -402,9 +402,7 @@
+ return;
+
+ if (test_and_clear_bit(DZ_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);
+ }
+ }
+
+@@ -804,10 +802,7 @@
+ 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);
+ }
+
+ /*
+@@ -1106,16 +1101,15 @@
+
+ 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 (tty->ldisc.num != ldiscs[N_TTY].num) {
++ if (tty->ldisc.num != N_TTY) {
+ if (tty->ldisc.close)
+ (tty->ldisc.close) (tty);
+- tty->ldisc = ldiscs[N_TTY];
++ tty->ldisc = *(tty_ldisc_get(N_TTY));
+ tty->termios->c_line = N_TTY;
+ if (tty->ldisc.open)
+ (tty->ldisc.open) (tty);
+===== drivers/char/serial_amba.c 1.5 vs 1.6 =====
+--- 1.5/drivers/char/serial_amba.c 2002-03-31 00:45:50 +09:00
++++ 1.6/drivers/char/serial_amba.c 2004-12-16 23:40:14 +09:00
+@@ -569,10 +569,7 @@
+ if (!tty || !test_and_clear_bit(EVT_WRITE_WAKEUP, &info->event))
+ 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);
+ }
+
+ static int ambauart_startup(struct amba_info *info)
+@@ -958,10 +955,7 @@
+ save_flags(flags); cli();
+ 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);
+ }
+
+ /*
+@@ -1459,8 +1453,7 @@
+ ambauart_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;
+===== drivers/sbus/char/aurora.c 1.15 vs 1.16 =====
+--- 1.15/drivers/sbus/char/aurora.c 2002-08-24 08:07:25 +09:00
++++ 1.16/drivers/sbus/char/aurora.c 2004-12-16 22:57:23 +09:00
+@@ -1573,8 +1573,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;
+@@ -1785,11 +1784,8 @@
+ save_flags(flags); cli();
+ 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
+@@ -2286,10 +2282,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");
+===== drivers/net/hamradio/6pack.c 1.8 vs 1.9 =====
+--- 1.8/drivers/net/hamradio/6pack.c 2003-10-22 03:28:22 +09:00
++++ 1.9/drivers/net/hamradio/6pack.c 2004-12-17 00:02:53 +09:00
+@@ -571,8 +571,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);
+
+ /* Restore default settings */
+ sp->dev->type = ARPHRD_AX25;
+===== drivers/sbus/char/su.c 1.13 vs 1.14 =====
+--- 1.13/drivers/sbus/char/su.c 2002-03-31 00:45:50 +09:00
++++ 1.14/drivers/sbus/char/su.c 2004-12-17 00:07:37 +09:00
+@@ -698,10 +698,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);
+ }
+ }
+
+@@ -1313,10 +1310,7 @@
+ save_flags(flags); cli();
+ 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);
+ }
+
+ /*
+@@ -1815,8 +1809,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;
+===== drivers/char/stallion.c 1.9 vs 1.10 =====
+--- 1.9/drivers/char/stallion.c 2004-07-13 09:39:49 +09:00
++++ 1.10/drivers/char/stallion.c 2004-12-16 22:57:23 +09:00
+@@ -1238,8 +1238,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;
+@@ -1850,10 +1849,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);
+ }
+
+ /*****************************************************************************/
+@@ -2224,10 +2220,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);
+===== drivers/usb/bluetooth.c 1.18 vs 1.19 =====
+--- 1.18/drivers/usb/bluetooth.c 2003-08-28 20:13:49 +09:00
++++ 1.19/drivers/usb/bluetooth.c 2004-12-17 03:49:03 +09:00
+@@ -1017,6 +1017,7 @@
+ {
+ struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)private, __FUNCTION__);
+ struct tty_struct *tty;
++ struct tty_ldisc *ld;
+
+ dbg("%s", __FUNCTION__);
+
+@@ -1025,9 +1026,15 @@
+ }
+
+ 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);
++ if (tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) {
++ ld = tty_ldisc_ref(tty);
++ if(ld) {
++ if(ld->write_wakeup) {
++ ld->write_wakeup(tty);
++ dbg("%s - write wakeup call.", __FUNCTION__);
++ }
++ tty_ldisc_deref(tty);
++ }
+ }
+
+ wake_up_interruptible(&tty->write_wait);
+===== drivers/net/wan/x25_asy.c 1.3 vs 1.4 =====
+--- 1.3/drivers/net/wan/x25_asy.c 2002-02-05 16:45:17 +09:00
++++ 1.4/drivers/net/wan/x25_asy.c 2004-12-17 00:02:12 +09:00
+@@ -619,9 +619,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);
+
+ /* Restore default settings */
+ sl->dev->type = ARPHRD_X25;
+===== drivers/char/cyclades.c 1.10 vs 1.11 =====
+--- 1.10/drivers/char/cyclades.c 2002-11-21 05:08:49 +09:00
++++ 1.11/drivers/char/cyclades.c 2004-12-16 22:57:23 +09:00
+@@ -1000,11 +1000,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);
+- }
+- wake_up_interruptible(&tty->write_wait);
++ tty_wakeup(tty);
+ }
+ #ifdef Z_WAKE
+ if (test_and_clear_bit(Cy_EVENT_SHUTDOWN_WAKEUP, &info->event)) {
+@@ -2918,8 +2914,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;
+@@ -4689,10 +4684,7 @@
+ }
+ CY_UNLOCK(info, 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 */
+
+
+===== net/bluetooth/rfcomm/tty.c 1.11 vs 1.12 =====
+--- 1.11/net/bluetooth/rfcomm/tty.c 2004-04-16 20:55:48 +09:00
++++ 1.12/net/bluetooth/rfcomm/tty.c 2004-12-16 23:20:47 +09:00
+@@ -532,10 +532,8 @@
+
+ BT_DBG("dev %p tty %p", dev, tty);
+
+- if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && tty->ldisc.write_wakeup)
+- (tty->ldisc.write_wakeup)(tty);
++ tty_wakeup(tty);
+
+- wake_up_interruptible(&tty->write_wait);
+ #ifdef SERIAL_HAVE_POLL_WAIT
+ wake_up_interruptible(&tty->poll_wait);
+ #endif
+@@ -853,8 +851,7 @@
+
+ skb_queue_purge(&dev->dlc->tx_queue);
+
+- if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && tty->ldisc.write_wakeup)
+- tty->ldisc.write_wakeup(tty);
++ tty_wakeup(tty);
+ }
+
+ static void rfcomm_tty_send_xchar(struct tty_struct *tty, char ch)
+===== drivers/net/irda/irtty.c 1.11 vs 1.12 =====
+--- 1.11/drivers/net/irda/irtty.c 2002-08-07 03:08:16 +09:00
++++ 1.12/drivers/net/irda/irtty.c 2004-12-16 23:59:36 +09:00
+@@ -179,9 +179,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);
+
+ self->magic = IRTTY_MAGIC;
+ self->mode = IRDA_IRLAP;
+===== drivers/char/sgiserial.c 1.9 vs 1.10 =====
+--- 1.9/drivers/char/sgiserial.c 2003-11-25 08:22:51 +09:00
++++ 1.10/drivers/char/sgiserial.c 2004-12-16 22:57:23 +09:00
+@@ -1498,10 +1498,10 @@
+ tty->closing = 0;
+ info->event = 0;
+ info->tty = 0;
+- if (tty->ldisc.num != ldiscs[N_TTY].num) {
++ if (tty->ldisc.num != N_TTY) {
+ if (tty->ldisc.close)
+ (tty->ldisc.close)(tty);
+- tty->ldisc = ldiscs[N_TTY];
++ tty->ldisc = *(tty_ldisc_get(N_TTY));
+ tty->termios->c_line = N_TTY;
+ if (tty->ldisc.open)
+ (tty->ldisc.open)(tty);
+===== drivers/char/n_hdlc.c 1.5 vs 1.6 =====
+--- 1.5/drivers/char/n_hdlc.c 2003-09-04 23:17:06 +09:00
++++ 1.6/drivers/char/n_hdlc.c 2004-12-16 23:36:41 +09:00
+@@ -351,9 +351,8 @@
+ #endif
+
+ /* 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);
+===== drivers/char/ser_a2232.c 1.3 vs 1.4 =====
+--- 1.3/drivers/char/ser_a2232.c 2002-12-03 11:10:12 +09:00
++++ 1.4/drivers/char/ser_a2232.c 2004-12-16 22:57:23 +09:00
+@@ -633,10 +633,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
+===== drivers/char/serial.c 1.39 vs 1.40 =====
+--- 1.39/drivers/char/serial.c 2004-09-29 23:09:07 +09:00
++++ 1.40/drivers/char/serial.c 2004-12-17 03:42:06 +09:00
+@@ -1068,17 +1068,15 @@
+ static void do_softint(void *private_)
+ {
+ struct async_struct *info = (struct async_struct *) private_;
+- struct tty_struct *tty;
+-
++ struct tty_struct *tty;
++
+ tty = info->tty;
+ 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);
++ tty_wakeup(tty);
++
+ #ifdef SERIAL_HAVE_POLL_WAIT
+ wake_up_interruptible(&tty->poll_wait);
+ #endif
+@@ -1976,13 +1974,10 @@
+ save_flags(flags); cli();
+ info->xmit.head = info->xmit.tail = 0;
+ restore_flags(flags);
+- wake_up_interruptible(&tty->write_wait);
+ #ifdef 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);
+ }
+
+ /*
+@@ -2867,8 +2862,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;
+===== drivers/char/hvc_console.c 1.2 vs 1.3 =====
+--- 1.2/drivers/char/hvc_console.c 2004-02-04 15:10:16 +09:00
++++ 1.3/drivers/char/hvc_console.c 2004-12-16 22:57:23 +09:00
+@@ -217,10 +217,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);
+ }
+ }
+
+===== drivers/char/pty.c 1.5 vs 1.6 =====
+--- 1.5/drivers/char/pty.c 2004-12-17 02:29:44 +09:00
++++ 1.6/drivers/char/pty.c 2004-12-16 23:40:52 +09:00
+@@ -121,10 +121,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);
+ }
+
+@@ -137,6 +134,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)
+@@ -299,9 +300,8 @@
+
+ if (!to)
+ return;
+-
+- if (to->ldisc.flush_buffer)
+- to->ldisc.flush_buffer(to);
++
++ tty_ldisc_flush(to);
+
+ if (to->packet) {
+ tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
+===== net/irda/ircomm/ircomm_tty.c 1.8 vs 1.9 =====
+--- 1.8/net/irda/ircomm/ircomm_tty.c 2002-09-12 20:37:06 +09:00
++++ 1.9/net/irda/ircomm/ircomm_tty.c 2004-12-16 23:09:13 +09:00
+@@ -566,8 +566,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;
+ self->tty = 0;
+@@ -662,12 +661,7 @@
+ ircomm_tty_do_event(self, IRCOMM_TTY_DATA_REQUEST, skb, NULL);
+
+ /* Check if user (still) wants to be waken up */
+- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+- tty->ldisc.write_wakeup)
+- {
+- (tty->ldisc.write_wakeup)(tty);
+- }
+- wake_up_interruptible(&tty->write_wait);
++ tty_wakeup(tty);
+ }
+
+ /*
+===== drivers/char/synclink.c 1.16 vs 1.17 =====
+--- 1.16/drivers/char/synclink.c 2003-11-19 02:31:14 +09:00
++++ 1.17/drivers/char/synclink.c 2004-12-17 03:43:15 +09:00
+@@ -1011,6 +1011,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
+@@ -1170,14 +1193,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);
+- }
+- wake_up_interruptible(&tty->write_wait);
++ tty_wakeup(tty);
+ }
+
+ /* if transmitter idle and loopmode_send_done_requested
+@@ -2433,12 +2449,8 @@
+ del_timer(&info->tx_timer);
+ 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()
+ *
+@@ -3342,9 +3354,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);
+
+@@ -7007,11 +7018,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. */
+@@ -7183,9 +7190,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. */
+===== fs/proc/proc_tty.c 1.2 vs 1.3 =====
+--- 1.2/fs/proc/proc_tty.c 2003-07-15 05:10:30 +09:00
++++ 1.3/fs/proc/proc_tty.c 2004-12-16 22:57:23 +09:00
+@@ -15,8 +15,6 @@
+ #include <asm/bitops.h>
+
+ extern struct tty_driver *tty_drivers; /* linked list of tty drivers */
+-extern struct tty_ldisc ldiscs[];
+-
+
+ static int tty_drivers_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data);
+@@ -106,12 +104,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) {
+===== drivers/net/wan/pc300_tty.c 1.2 vs 1.3 =====
+--- 1.2/drivers/net/wan/pc300_tty.c 2004-08-12 05:05:57 +09:00
++++ 1.3/drivers/net/wan/pc300_tty.c 2004-12-16 22:57:23 +09:00
+@@ -627,14 +627,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;
+ }
+
+@@ -696,16 +690,22 @@
+ flg_rx = 0;
+ port = (int) data;
+ for (j=0; j < CPC_TTY_NPORTS; j++) {
+- cpc_tty = &cpc_tty_area[port];
+-
++ 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, buf->data,
+- &flags, buf->size);
+- }
+- cpc_tty->buf_rx.first = cpc_tty->buf_rx.first->next;
++ if(cpc_tty->tty)
++ {
++ struct tty_ldisc *ld = tty_ldisc_ref(cpc_tty->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);
+ buf = cpc_tty->buf_rx.first;
+ flg_rx = 1;
+@@ -908,12 +909,7 @@
+ 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);
+ }
+
+ /*
+===== drivers/char/serial_txx927.c 1.4 vs 1.5 =====
+--- 1.4/drivers/char/serial_txx927.c 2002-03-31 00:45:50 +09:00
++++ 1.5/drivers/char/serial_txx927.c 2004-12-16 23:38:45 +09:00
+@@ -535,10 +535,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);
+ #ifdef SERIAL_HAVE_POLL_WAIT
+ wake_up_interruptible(&tty->poll_wait);
+ #endif
+@@ -1104,13 +1101,10 @@
+ save_flags(flags); cli();
+ info->xmit.head = info->xmit.tail = 0;
+ restore_flags(flags);
+- wake_up_interruptible(&tty->write_wait);
+ #ifdef 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);
+ }
+
+ /*
+@@ -1465,8 +1459,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;
+===== drivers/sbus/char/sab82532.c 1.11 vs 1.12 =====
+--- 1.11/drivers/sbus/char/sab82532.c 2002-03-31 00:45:50 +09:00
++++ 1.12/drivers/sbus/char/sab82532.c 2004-12-17 00:06:52 +09:00
+@@ -669,10 +669,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);
+ }
+ }
+
+@@ -1206,10 +1203,7 @@
+ 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);
+ }
+
+ /*
+@@ -1667,8 +1661,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;
+===== drivers/char/sx.c 1.14 vs 1.15 =====
+--- 1.14/drivers/char/sx.c 2003-03-25 03:08:18 +09:00
++++ 1.15/drivers/char/sx.c 2004-12-16 22:57:23 +09:00
+@@ -1057,9 +1057,7 @@
+ }
+
+ 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);
+===== drivers/usb/serial/usbserial.c 1.32 vs 1.33 =====
+--- 1.32/drivers/usb/serial/usbserial.c 2004-11-01 23:29:07 +09:00
++++ 1.33/drivers/usb/serial/usbserial.c 2004-12-16 23:55:02 +09:00
+@@ -1326,6 +1326,7 @@
+ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
+ struct tty_struct *tty;
+ unsigned long flags;
++ struct tty_ldisc *ld;
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+
+@@ -1341,9 +1342,15 @@
+ 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);
++ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP))) {
++ ld = tty_ldisc_ref(tty);
++ if(ld) {
++ if(ld->write_wakeup) {
++ ld->write_wakeup(tty);
++ dbg("%s - write wakeup call.", __FUNCTION__);
++ }
++ tty_ldisc_deref(ld);
++ }
+ }
+
+ wake_up_interruptible(&tty->write_wait);
+===== drivers/net/ppp_synctty.c 1.6 vs 1.7 =====
+--- 1.6/drivers/net/ppp_synctty.c 2002-03-11 23:13:28 +09:00
++++ 1.7/drivers/net/ppp_synctty.c 2004-12-16 22:57:23 +09:00
+@@ -172,6 +172,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;
+
+@@ -280,6 +282,18 @@
+ }
+
+ /*
++ * Called on tty hangup in process context.
++ *
++ * Wait for I/O to driver to complete and unregister PPP channel.
++ * This is already done by the close routine, so just call that.
++ */
++static int ppp_sync_hangup(struct tty_struct *tty)
++{
++ ppp_sync_close(tty);
++ return 0;
++}
++
++/*
+ * Read does nothing - no data is ever available this way.
+ * Pppd reads and writes packets via /dev/ppp instead.
+ */
+@@ -412,6 +426,7 @@
+ write: ppp_sync_write,
+ ioctl: ppp_synctty_ioctl,
+ poll: ppp_sync_poll,
++ hangup: ppp_sync_hangup,
+ receive_room: ppp_sync_room,
+ receive_buf: ppp_sync_receive,
+ write_wakeup: ppp_sync_wakeup,
+===== drivers/char/serial167.c 1.7 vs 1.8 =====
+--- 1.7/drivers/char/serial167.c 2002-08-05 21:48:52 +09:00
++++ 1.8/drivers/char/serial167.c 2004-12-16 22:57:23 +09:00
+@@ -773,11 +773,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 */
+
+@@ -1357,9 +1353,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);
+ } /* cy_flush_buffer */
+
+
+@@ -1916,18 +1910,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;
+===== drivers/macintosh/macserial.c 1.8 vs 1.9 =====
+--- 1.8/drivers/macintosh/macserial.c 2002-03-31 00:45:50 +09:00
++++ 1.9/drivers/macintosh/macserial.c 2004-12-16 22:57:23 +09:00
+@@ -735,12 +735,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)
+@@ -1595,10 +1591,7 @@
+ save_flags(flags); cli();
+ 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);
+ }
+
+ /*
+@@ -2029,8 +2022,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;
+===== drivers/net/hamradio/mkiss.c 1.7 vs 1.8 =====
+--- 1.7/drivers/net/hamradio/mkiss.c 2003-06-04 20:18:22 +09:00
++++ 1.8/drivers/net/hamradio/mkiss.c 2004-12-17 00:03:13 +09:00
+@@ -654,8 +654,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);
+
+ /* Restore default settings */
+ ax->dev->type = ARPHRD_AX25;
+===== drivers/char/pdc_console.c 1.2 vs 1.3 =====
+--- 1.2/drivers/char/pdc_console.c 2002-12-31 02:27:35 +09:00
++++ 1.3/drivers/char/pdc_console.c 2004-12-16 23:36:12 +09:00
+@@ -463,8 +463,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;
+===== drivers/char/riscom8.c 1.5 vs 1.6 =====
+--- 1.5/drivers/char/riscom8.c 2002-02-05 16:45:17 +09:00
++++ 1.6/drivers/char/riscom8.c 2004-12-16 22:57:23 +09:00
+@@ -1200,8 +1200,7 @@
+ 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 = 0;
+@@ -1375,9 +1374,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_get_modem_info(struct riscom_port * port, unsigned int *value)
+@@ -1734,10 +1731,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);
+ }
+ }
+
+===== drivers/char/synclinkmp.c 1.5 vs 1.6 =====
+--- 1.5/drivers/char/synclinkmp.c 2004-08-27 03:02:57 +09:00
++++ 1.6/drivers/char/synclinkmp.c 2004-12-16 22:57:23 +09:00
+@@ -735,6 +735,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.
+@@ -906,8 +929,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);
+
+@@ -1315,9 +1337,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
+@@ -1983,13 +2003,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);
+ }
+ }
+@@ -4989,15 +5003,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. */
+===== drivers/usb/serial/digi_acceleport.c 1.14 vs 1.15 =====
+--- 1.14/drivers/usb/serial/digi_acceleport.c 2002-08-30 02:51:26 +09:00
++++ 1.15/drivers/usb/serial/digi_acceleport.c 2004-12-16 22:57:23 +09:00
+@@ -614,14 +614,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);
+ }
+
+
+@@ -1557,8 +1550,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 */
+===== drivers/net/wan/sdla_chdlc.c 1.15 vs 1.16 =====
+--- 1.15/drivers/net/wan/sdla_chdlc.c 2002-12-03 11:10:12 +09:00
++++ 1.16/drivers/net/wan/sdla_chdlc.c 2004-12-16 22:57:23 +09:00
+@@ -3868,11 +3868,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) || \
+ (defined LINUX_2_1 && LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,15))
+ wake_up_interruptible(&tty->poll_wait);
+@@ -4098,6 +4094,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",
+@@ -4185,8 +4182,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
+@@ -4493,14 +4493,11 @@
+ if (!tty)
+ return;
+
+- wake_up_interruptible(&tty->write_wait);
+ #if defined(SERIAL_HAVE_POLL_WAIT) || \
+ (defined LINUX_2_1 && LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,15))
+ 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;
+ }
+===== drivers/char/pcmcia/synclink_cs.c 1.3 vs 1.4 =====
+--- 1.3/drivers/char/pcmcia/synclink_cs.c 2003-09-09 23:43:21 +09:00
++++ 1.4/drivers/char/pcmcia/synclink_cs.c 2004-12-17 00:22:51 +09:00
+@@ -553,6 +553,29 @@
+ static void* mgslpc_get_text_ptr(void);
+ static void* mgslpc_get_text_ptr() {return mgslpc_get_text_ptr;}
+
++/**
++ * 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);
++ }
++}
++
+ static dev_link_t *mgslpc_attach(void)
+ {
+ MGSLPC_INFO *info;
+@@ -1027,13 +1050,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);
+ }
+ }
+@@ -1917,11 +1934,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
+@@ -2685,9 +2700,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);
+
+@@ -4199,11 +4213,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);
+ }
+ }
+
+===== include/linux/tty.h 1.6 vs 1.7 =====
+--- 1.6/include/linux/tty.h 2003-05-17 19:56:48 +09:00
++++ 1.7/include/linux/tty.h 2004-12-16 22:57:23 +09:00
+@@ -260,6 +260,7 @@
+ int magic;
+ struct tty_driver driver;
+ struct tty_ldisc ldisc;
++ struct semaphore termios_sem;
+ struct termios *termios, *termios_locked;
+ int pgrp;
+ int session;
+@@ -322,26 +323,28 @@
+ * 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 struct tty_ldisc tty_ldiscs[];
+ extern int fg_console, last_console, want_console;
+
+ extern int kmsg_redirect;
+@@ -395,6 +398,17 @@
+ extern void disassociate_ctty(int priv);
+ extern void tty_flip_buffer_push(struct tty_struct *tty);
+ extern int tty_get_baud_rate(struct tty_struct *tty);
++
++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);
++
+
+ /* n_tty.c */
+ extern struct tty_ldisc tty_ldisc_N_TTY;
+===== drivers/char/generic_serial.c 1.5 vs 1.6 =====
+--- 1.5/drivers/char/generic_serial.c 2002-07-30 02:09:00 +09:00
++++ 1.6/drivers/char/generic_serial.c 2004-12-17 00:13:15 +09:00
+@@ -439,10 +439,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);
+ func_exit ();
+ }
+
+@@ -582,10 +579,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);
+- wake_up_interruptible(&tty->write_wait);
++ tty_wakeup(tty);
+ }
+ func_exit ();
+ }
+@@ -729,8 +723,8 @@
+ {
+ unsigned long flags;
+ struct gs_port *port;
+-
+- func_enter ();
++
++ func_enter();
+
+ if (!tty) return;
+
+@@ -803,8 +797,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;
+
+ port->event = 0;
+===== drivers/char/serial_tx3912.c 1.6 vs 1.7 =====
+--- 1.6/drivers/char/serial_tx3912.c 2002-06-26 10:08:07 +09:00
++++ 1.7/drivers/char/serial_tx3912.c 2004-12-16 22:57:23 +09:00
+@@ -127,12 +127,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);
+ }
+ }
+
+===== drivers/s390/net/ctctty.c 1.5 vs 1.6 =====
+--- 1.5/drivers/s390/net/ctctty.c 2002-12-03 11:10:12 +09:00
++++ 1.6/drivers/s390/net/ctctty.c 2004-12-16 23:59:01 +09:00
+@@ -362,9 +362,8 @@
+
+ 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);
++ if (wake)
++ tty_wakeup(tty);
+ wake_up_interruptible(&tty->write_wait);
+ }
+ }
+@@ -655,10 +654,7 @@
+ skb_queue_purge(&info->tx_queue);
+ info->lsr |= UART_LSR_TEMT;
+ 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
+@@ -1168,8 +1164,7 @@
+ ctc_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);
+ spin_lock_irqsave(&ctc_tty_lock, saveflags);
+ info->tty = 0;
+ spin_unlock_irqrestore(&ctc_tty_lock, saveflags);
+===== drivers/char/epca.c 1.10 vs 1.11 =====
+--- 1.10/drivers/char/epca.c 2003-02-20 01:15:53 +09:00
++++ 1.11/drivers/char/epca.c 2004-12-17 00:13:00 +09:00
+@@ -585,9 +585,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;
+@@ -692,15 +690,13 @@
+ 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);
+
+ if (ch->count)
+ MOD_DEC_USE_COUNT;
+-
+
+ ch->tty = NULL;
+ ch->event = 0;
+@@ -1175,9 +1171,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);
+
+ } /* End pc_flush_buffer */
+
+@@ -2383,10 +2377,7 @@
+ { /* Begin if 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);
+
+ } /* End if LOWWAIT */
+
+@@ -2402,11 +2393,7 @@
+ { /* Begin if 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);
+
+ } /* End if EMPTYWAIT */
+
+@@ -3255,8 +3242,8 @@
+ }
+ else
+ {
+- if (tty->ldisc.flush_buffer)
+- tty->ldisc.flush_buffer(tty);
++ /* ldisc lock already held in ioctl */
++ tty_ldisc_flush(tty);
+ }
+
+ /* Fall Thru */
+===== drivers/char/tty_io.c 1.32 vs 1.33 =====
+--- 1.32/drivers/char/tty_io.c 2004-10-22 05:55:41 +09:00
++++ 1.33/drivers/char/tty_io.c 2004-12-16 22:57:23 +09:00
+@@ -120,7 +120,6 @@
+
+ struct termios tty_std_termios; /* for the benefit of tty drivers */
+ struct tty_driver *tty_drivers; /* linked list of tty drivers */
+-struct tty_ldisc ldiscs[NR_LDISCS]; /* line disc dispatch table */
+
+ #ifdef CONFIG_UNIX98_PTYS
+ extern struct tty_driver ptm_driver[]; /* Unix98 pty masters; for /dev/ptmx */
+@@ -260,63 +259,315 @@
+ 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)
++{
++ down(&tty->termios_sem);
++ tty->termios->c_line = num;
++ up(&tty->termios_sem);
++}
++
++/*
++ * 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.
++ */
++
++spinlock_t tty_ldisc_lock = SPIN_LOCK_UNLOCKED;
++DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait);
++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)
++ 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--;
++ 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));
++ 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);
++
++
++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_EMERG "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)
++ {
+ char modname [20];
+- sprintf(modname, "tty-ldisc-%d", ldisc);
+- request_module (modname);
++ sprintf(modname, "tty-ldisc-%d", ldisc);
++ request_module (modname);
++ 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 */
++
+ 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.
++ */
++
++ /*
++ * Wait for ->hangup_work and ->flip.work handlers to terminate
++ */
++ run_task_queue(&tq_timer);
++ flush_scheduled_tasks();
+
+ /* 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);
+
+@@ -327,8 +578,21 @@
+ }
+ }
+ }
++ /* At this point we hold a reference to the new ldisc and 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);
++
+ return retval;
+ }
+
+@@ -430,11 +694,45 @@
+
+ static spinlock_t redirect_lock = SPIN_LOCK_UNLOCKED;
+ static struct file *redirect;
+-/*
+- * This can be called by the "eventd" kernel thread. That is process synchronous,
+- * but doesn't hold any locks, so we need to make sure we have the appropriate
+- * locks for what we're doing..
+- */
++
++/**
++ * 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);
++
++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);
++
+ void do_tty_hangup(void *data)
+ {
+ struct tty_struct *tty = (struct tty_struct *) data;
+@@ -442,6 +740,7 @@
+ struct file *f = NULL;
+ struct task_struct *p;
+ struct list_head *l;
++ struct tty_ldisc *ld;
+ int closecount = 0, n;
+
+ if (!tty)
+@@ -475,20 +774,22 @@
+ file_list_unlock();
+
+ /* FIXME! What are the locking issues here? This may me overdoing things.. */
++ ld = tty_ldisc_ref(tty);
++ if(ld != NULL)
+ {
+- unsigned long flags;
+-
+- save_flags(flags); cli();
+- if (tty->ldisc.flush_buffer)
+- tty->ldisc.flush_buffer(tty);
++ 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);
+- restore_flags(flags);
++ if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) && 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);
+
+@@ -496,21 +797,19 @@
+ * Shutdown the current line discipline, and reset it to
+ * N_TTY.
+ */
++
+ if (tty->driver.flags & TTY_DRIVER_RESET_TERMIOS)
+- *tty->termios = tty->driver.init_termios;
+- 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) {
+- int i = (tty->ldisc.open)(tty);
+- if (i < 0)
+- printk(KERN_ERR "do_tty_hangup: N_TTY open: "
+- "error %d\n", -i);
+- }
++ {
++ down(&tty->termios_sem);
++ *tty->termios = tty->driver.init_termios;
++ up(&tty->termios_sem);
+ }
+-
++
++ /* 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);
+ for_each_task(p) {
+ if ((tty->session > 0) && (p->session == tty->session) &&
+@@ -541,6 +840,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);
+@@ -644,10 +954,8 @@
+ }
+ 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);
+- wake_up_interruptible(&tty->write_wait);
++ /* If we have a running line discipline it may need kicking */
++ tty_wakeup(tty);
+ }
+
+ static ssize_t tty_read(struct file * file, char * buf, size_t count,
+@@ -656,6 +964,7 @@
+ int i;
+ struct tty_struct * tty;
+ struct inode *inode;
++ struct tty_ldisc *ld;
+
+ /* Can't seek (pread) on ttys. */
+ if (ppos != &file->f_pos)
+@@ -684,11 +993,15 @@
+ return -ERESTARTSYS;
+ }
+ #endif
++ /* 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;
+@@ -757,6 +1070,8 @@
+ int is_console;
+ struct tty_struct * tty;
+ struct inode *inode = file->f_dentry->d_inode;
++ ssize_t ret;
++ struct tty_ldisc *ld;
+
+ /* Can't seek (pwrite) on ttys. */
+ if (ppos != &file->f_pos)
+@@ -803,13 +1118,19 @@
+ }
+ }
+ #endif
+- if (!tty->ldisc.write)
+- return -EIO;
+- return do_tty_write(tty->ldisc.write, tty, file,
+- (const unsigned char *)buf, count);
++
++ 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;
+ }
+
+-/* 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 */
+ static DECLARE_MUTEX(tty_sem);
+
+ static void down_tty_sem(int index)
+@@ -971,7 +1292,10 @@
+ (tty->ldisc.close)(tty);
+ goto release_mem_out;
+ }
++ set_bit(TTY_LDISC, &o_tty->flags);
++ tty_ldisc_enable(o_tty);
+ }
++ tty_ldisc_enable(tty);
+ goto success;
+
+ /*
+@@ -999,7 +1323,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;
+
+@@ -1080,6 +1406,7 @@
+ int pty_master, tty_closing, o_tty_closing, do_sleep;
+ 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->i_rdev, "release_dev"))
+@@ -1272,24 +1599,59 @@
+ #endif
+
+ /*
++ * Prevent flush_to_ldisc() from rescheduling the work for later. Then
++ * 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);
++
++ /*
++ * Wait for ->hangup_work and ->flip.work handlers to terminate
++ */
++
++ run_task_queue(&tq_timer);
++ flush_scheduled_tasks();
++
++ /*
++ * 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);
+- tty->ldisc = ldiscs[N_TTY];
+- tty->termios->c_line = N_TTY;
++ tty_ldisc_put(tty->ldisc.num);
++
++ /*
++ * 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);
+- 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);
+ }
+-
+- /*
+- * Make sure that the tty's task queue isn't activated.
+- */
+- run_task_queue(&tq_timer);
+- flush_scheduled_tasks();
+
+ /*
+ * The release_mem function takes care of the details of clearing
+@@ -1464,14 +1826,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->i_rdev, "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)
+@@ -1505,12 +1871,15 @@
+ static int tiocsti(struct tty_struct *tty, char * arg)
+ {
+ char ch, mbz = 0;
++ struct tty_ldisc *ld;
+
+ if ((current->tty != tty) && !suser())
+ return -EPERM;
+ if (get_user(ch, arg))
+ 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;
+ }
+
+@@ -1718,6 +2087,7 @@
+ {
+ struct tty_struct *tty, *real_tty;
+ int retval;
++ struct tty_ldisc *ld;
+
+ tty = (struct tty_struct *)file->private_data;
+ if (tty_paranoia_check(tty, inode->i_rdev, "tty_ioctl"))
+@@ -1808,6 +2178,7 @@
+ case TIOCGSID:
+ return tiocgsid(tty, real_tty, (pid_t *) arg);
+ case TIOCGETD:
++ /* FIXME: check this is ok */
+ return put_user(tty->ldisc.num, (int *) arg);
+ case TIOCSETD:
+ return tiocsetd(tty, (int *) arg);
+@@ -1841,16 +2212,19 @@
+ return send_break(tty, arg ? arg*(HZ/10) : HZ/4);
+ }
+ 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;
+ }
+
+
+@@ -1883,14 +2257,20 @@
+ 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(p) {
+ if ((p->tty == tty) ||
+@@ -1942,11 +2322,16 @@
+ 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)) {
+ queue_task(&tty->flip.tqueue, &tq_timer);
+- return;
++ goto out;
+ }
+ if (tty->flip.buf_num) {
+ cp = tty->flip.char_buf + TTY_FLIPBUF_SIZE;
+@@ -1969,7 +2354,31 @@
+ tty->flip.count = 0;
+ restore_flags(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;
++
+ }
+
+ /*
+@@ -2032,13 +2441,14 @@
+ {
+ 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;
+ tty->flip.tqueue.routine = flush_to_ldisc;
+ tty->flip.tqueue.data = tty;
+ init_MUTEX(&tty->flip.pty_sem);
++ init_MUTEX(&tty->termios_sem);
+ init_waitqueue_head(&tty->write_wait);
+ init_waitqueue_head(&tty->read_wait);
+ tty->tq_hangup.routine = do_tty_hangup;
+@@ -2217,7 +2627,7 @@
+ void __init console_init(void)
+ {
+ /* Setup the default TTY line discipline. */
+- memset(ldiscs, 0, sizeof(ldiscs));
++ memset(tty_ldiscs, 0, NR_LDISCS*sizeof(struct tty_ldisc));
+ (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);
+
+ /*
+===== drivers/char/pcxx.c 1.6 vs 1.7 =====
+--- 1.6/drivers/char/pcxx.c 2002-08-06 23:42:07 +09:00
++++ 1.7/drivers/char/pcxx.c 2004-12-16 22:57:23 +09:00
+@@ -619,28 +619,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;
+@@ -883,9 +866,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)
+@@ -1793,10 +1774,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);
+ }
+ }
+
+@@ -1804,10 +1782,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);
+ }
+ }
+ }
+@@ -2254,8 +2229,7 @@
+ tty_wait_until_sent(tty, 0);
+ }
+ else {
+- if(tty->ldisc.flush_buffer)
+- tty->ldisc.flush_buffer(tty);
++ tty_ldisc_flush(tty);
+ }
+
+ /* Fall Thru */
+===== drivers/net/wan/8253x/8253xtty.c 1.2 vs 1.3 =====
+--- 1.2/drivers/net/wan/8253x/8253xtty.c 2003-02-12 03:04:34 +09:00
++++ 1.3/drivers/net/wan/8253x/8253xtty.c 2004-12-17 00:01:04 +09:00
+@@ -691,10 +691,7 @@
+ port->DoingInterrupt = 1;
+ if (test_and_clear_bit(SAB8253X_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); /* in case tty driver waiting on write */
++ tty_wakeup(tty);
+ }
+ port->DoingInterrupt = 0;
+ }
+@@ -2001,10 +1998,7 @@
+ {
+ 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;
+===== drivers/char/istallion.c 1.10 vs 1.11 =====
+--- 1.10/drivers/char/istallion.c 2004-07-13 09:39:43 +09:00
++++ 1.11/drivers/char/istallion.c 2004-12-16 23:35:07 +09:00
+@@ -1214,8 +1214,7 @@
+ clear_bit(ST_TXBUSY, &portp->state);
+ clear_bit(ST_RXSTOP, &portp->state);
+ set_bit(TTY_IO_ERROR, &tty->flags);
+- if (tty->ldisc.flush_buffer)
+- (tty->ldisc.flush_buffer)(tty);
++ tty_ldisc_flush(tty);
+ set_bit(ST_DOFLUSHRX, &portp->state);
+ stli_flushbuffer(tty);
+
+@@ -2477,10 +2476,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);
+ }
+
+ /*****************************************************************************/
+@@ -2915,6 +2911,7 @@
+ asynotify_t nt;
+ unsigned long oldsigs;
+ int rc, donerx;
++ struct tty_ldisc *ld;
+
+ #if DEBUG
+ printk(KERN_DEBUG "stli_hostcmd(brdp=%x,channr=%d)\n",
+@@ -3014,10 +3011,15 @@
+ clear_bit(ST_TXBUSY, &portp->state);
+ if (nt.data & (DT_TXEMPTY | DT_TXLOW)) {
+ if (tty != (struct tty_struct *) NULL) {
+- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+- tty->ldisc.write_wakeup) {
+- (tty->ldisc.write_wakeup)(tty);
+- EBRDENABLE(brdp);
++ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP))) {
++ ld = tty_ldisc_ref(tty);
++ if(ld) {
++ if(ld->write_wakeup) {
++ ld->write_wakeup(tty);
++ EBRDENABLE(brdp);
++ }
++ tty_ldisc_deref(ld);
++ }
+ }
+ wake_up_interruptible(&tty->write_wait);
+ }
+===== drivers/usb/acm.c 1.16 vs 1.17 =====
+--- 1.16/drivers/usb/acm.c 2003-09-06 00:45:49 +09:00
++++ 1.17/drivers/usb/acm.c 2004-12-16 23:55:33 +09:00
+@@ -285,10 +285,7 @@
+
+ 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(tty);
+ }
+
+ /*
+===== drivers/net/wan/8253x/8253xsyn.c 1.1 vs 1.2 =====
+--- 1.1/drivers/net/wan/8253x/8253xsyn.c 2002-04-05 04:05:10 +09:00
++++ 1.2/drivers/net/wan/8253x/8253xsyn.c 2004-12-17 00:00:20 +09:00
+@@ -1108,10 +1108,7 @@
+ {
+ 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;
+===== drivers/usb/serial/keyspan_pda.c 1.11 vs 1.12 =====
+--- 1.11/drivers/usb/serial/keyspan_pda.c 2003-08-28 20:13:49 +09:00
++++ 1.12/drivers/usb/serial/keyspan_pda.c 2004-12-16 22:57:23 +09:00
+@@ -183,13 +183,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 )
+===== drivers/usb/serial/mct_u232.c 1.20 vs 1.21 =====
+--- 1.20/drivers/usb/serial/mct_u232.c 2004-06-13 06:24:26 +09:00
++++ 1.21/drivers/usb/serial/mct_u232.c 2004-12-16 22:57:23 +09:00
+@@ -569,11 +569,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 */
+ queue_task(&port->tqueue, &tq_immediate);
+===== arch/cris/drivers/serial.c 1.16 vs 1.17 =====
+--- 1.16/arch/cris/drivers/serial.c 2003-08-30 04:32:50 +09:00
++++ 1.17/arch/cris/drivers/serial.c 2004-12-16 23:23:53 +09:00
+@@ -3324,10 +3324,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);
+ }
+ }
+
+@@ -3952,11 +3949,7 @@
+ 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);
+ }
+
+ /*
+@@ -4578,8 +4571,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;
+===== drivers/char/mxser.c 1.12 vs 1.13 =====
+--- 1.12/drivers/char/mxser.c 2004-08-17 03:17:23 +09:00
++++ 1.13/drivers/char/mxser.c 2004-12-17 00:14:49 +09:00
+@@ -725,10 +725,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);
+- wake_up_interruptible(&tty->write_wait);
++ tty_wakeup(tty);
+ }
+ if (test_and_clear_bit(MXSER_EVENT_HANGUP, &info->event)) {
+ tty_hangup(tty); /* FIXME: module removal race here - AKPM */
+@@ -890,8 +887,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 = 0;
+@@ -1050,10 +1047,7 @@
+ cli();
+ 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,
+===== drivers/char/rocket.c 1.10 vs 1.11 =====
+--- 1.10/drivers/char/rocket.c 2003-09-12 00:22:06 +09:00
++++ 1.11/drivers/char/rocket.c 2004-12-16 22:57:23 +09:00
+@@ -241,9 +241,12 @@
+ 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 = 2*TTY_FLIPBUF_SIZE;
+@@ -348,8 +351,8 @@
+ fbuf += ToRecv;
+ count += ToRecv;
+ }
+- 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);
+ }
+
+ /*
+@@ -400,10 +403,7 @@
+ if (info->xmit_cnt == 0)
+ xmit_flags[info->line >> 5] &= ~(1 << (info->line & 0x1f));
+ if (info->xmit_cnt < WAKEUP_CHARS) {
+- 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 ROCKET_DEBUG_INTR
+ printk("(%d,%d,%d,%d)...", info->xmit_cnt, info->xmit_head,
+@@ -1128,8 +1128,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);
+
+ xmit_flags[info->line >> 5] &= ~(1 << (info->line & 0x1f));
+ if (info->blocked_open) {
+@@ -1806,10 +1805,7 @@
+ restore_flags(flags);
+ end:
+ if (info->xmit_cnt < WAKEUP_CHARS) {
+- 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 retval;
+ }
+@@ -1868,9 +1864,7 @@
+ 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);
+
+ cp = &info->channel;
+
+===== drivers/s390/char/con3215.c 1.7 vs 1.8 =====
+--- 1.7/drivers/s390/char/con3215.c 2003-06-27 20:39:05 +09:00
++++ 1.8/drivers/s390/char/con3215.c 2004-12-16 22:57:23 +09:00
+@@ -363,10 +363,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);
+ }
+ }
+
+@@ -978,10 +975,7 @@
+
+ raw = (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);
+ }
+
+ /*
+===== drivers/char/vt.c 1.14 vs 1.15 =====
+--- 1.14/drivers/char/vt.c 2004-01-11 02:47:12 +09:00
++++ 1.15/drivers/char/vt.c 2004-12-16 22:57:23 +09:00
+@@ -588,8 +588,7 @@
+ default:
+ return -EINVAL;
+ }
+- if (tty->ldisc.flush_buffer)
+- tty->ldisc.flush_buffer(tty);
++ tty_ldisc_flush(tty);
+ return 0;
+
+ case KDGKBMODE:
+===== drivers/net/strip.c 1.5 vs 1.6 =====
+--- 1.5/drivers/net/strip.c 2002-02-05 16:55:07 +09:00
++++ 1.6/drivers/net/strip.c 2004-12-17 00:02:33 +09:00
+@@ -2706,8 +2706,7 @@
+ 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);
++ tty_ldisc_flush(tty);
+
+ /*
+ * Restore default settings
+===== drivers/isdn/isdn_tty.c 1.9 vs 1.10 =====
+--- 1.9/drivers/isdn/isdn_tty.c 2002-02-05 23:07:05 +09:00
++++ 1.10/drivers/isdn/isdn_tty.c 2004-12-17 00:05:22 +09:00
+@@ -321,10 +321,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) {
+@@ -1214,10 +1211,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;
+ }
+@@ -1335,10 +1329,7 @@
+ isdn_tty_cleanup_xmit(info);
+ info->xmit_count = 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 void
+@@ -1867,8 +1858,7 @@
+ 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 = 0;
+ info->ncarrier = 0;
+ tty->closing = 0;
+@@ -2791,8 +2781,7 @@
+ restore_flags(flags);
+ return;
+ }
+- if (info->tty->ldisc.flush_buffer)
+- info->tty->ldisc.flush_buffer(info->tty);
++ tty_ldisc_flush(info->tty);
+ if ((info->flags & ISDN_ASYNC_CHECK_CD) &&
+ (!((info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) &&
+ (info->flags & ISDN_ASYNC_CALLOUT_NOHUP)))) {
+===== arch/ppc/8xx_io/uart.c 1.23 vs 1.24 =====
+--- 1.23/arch/ppc/8xx_io/uart.c 2003-10-01 08:26:08 +09:00
++++ 1.24/arch/ppc/8xx_io/uart.c 2004-12-16 23:22:28 +09:00
+@@ -738,10 +738,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);
+ }
+ }
+
+@@ -1209,10 +1206,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;
+ }
+
+@@ -1791,8 +1785,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;
+===== drivers/net/ppp_async.c 1.8 vs 1.9 =====
+--- 1.8/drivers/net/ppp_async.c 2002-03-11 23:13:28 +09:00
++++ 1.9/drivers/net/ppp_async.c 2004-12-16 22:57:23 +09:00
+@@ -117,6 +117,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;
+
+@@ -139,7 +142,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)
+@@ -227,6 +231,18 @@
+ }
+
+ /*
++ * Called on tty hangup in process context.
++ *
++ * Wait for I/O to driver to complete and unregister PPP channel.
++ * This is already done by the close routine, so just call that.
++ */
++static int ppp_asynctty_hangup(struct tty_struct *tty)
++{
++ ppp_asynctty_close(tty);
++ return 0;
++}
++
++/*
+ * Read does nothing - no data is ever available this way.
+ * Pppd reads and writes packets via /dev/ppp instead.
+ */
+@@ -248,6 +264,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)
+@@ -359,6 +380,7 @@
+ write: ppp_asynctty_write,
+ ioctl: ppp_asynctty_ioctl,
+ poll: ppp_asynctty_poll,
++ hangup: ppp_asynctty_hangup,
+ receive_room: ppp_asynctty_room,
+ receive_buf: ppp_asynctty_receive,
+ write_wakeup: ppp_asynctty_wakeup,
+@@ -714,7 +736,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)
+@@ -819,7 +842,9 @@
+ ppp_input_error(&ap->chan, code);
+ }
+
+-/* 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)
+===== drivers/s390/char/tubtty.c 1.7 vs 1.8 =====
+--- 1.7/drivers/s390/char/tubtty.c 2002-10-07 23:42:10 +09:00
++++ 1.8/drivers/s390/char/tubtty.c 2004-12-16 23:56:31 +09:00
+@@ -445,10 +445,7 @@
+ ob->bc_cnt = 0;
+ TUBUNLOCK(tubp->irq, 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
+@@ -646,10 +643,7 @@
+ }
+
+ if (tty != NULL) {
+- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+- tty->ldisc.write_wakeup != NULL)
+- (tty->ldisc.write_wakeup)(tty);
+- wake_up_interruptible(&tty->write_wait);
++ tty_wakeup(tty);
+ }
+ do_unlock:
+ TUBUNLOCK(tubp->irq, flags);
+===== drivers/tc/zs.c 1.7 vs 1.8 =====
+--- 1.7/drivers/tc/zs.c 2004-01-21 00:13:29 +09:00
++++ 1.8/drivers/tc/zs.c 2004-12-16 22:57:23 +09:00
+@@ -695,10 +695,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);
+ }
+ }
+
+@@ -1020,10 +1017,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);
+ }
+
+ /*
+@@ -1429,8 +1423,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;
+===== drivers/bluetooth/hci_ldisc.c 1.7 vs 1.8 =====
+--- 1.7/drivers/bluetooth/hci_ldisc.c 2004-06-20 20:50:15 +09:00
++++ 1.8/drivers/bluetooth/hci_ldisc.c 2004-12-17 00:03:36 +09:00
+@@ -188,9 +188,7 @@
+ kfree_skb(hu->tx_skb); hu->tx_skb = NULL;
+ }
+
+- /* 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);
+@@ -283,9 +281,10 @@
+
+ spin_lock_init(&hu->rx_lock);
+
+- /* Flush any pending characters in the driver and line discipline */
+- if (tty->ldisc.flush_buffer)
+- tty->ldisc.flush_buffer(tty);
++ /* 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 */
++ tty_ldisc_flush(tty);
+
+ if (tty->driver.flush_buffer)
+ tty->driver.flush_buffer(tty);
+===== drivers/char/specialix.c 1.5 vs 1.6 =====
+--- 1.5/drivers/char/specialix.c 2002-05-31 07:24:01 +09:00
++++ 1.6/drivers/char/specialix.c 2004-12-17 00:28:34 +09:00
+@@ -1579,8 +1579,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 = 0;
+@@ -1758,10 +1757,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);
+ }
+
+
+@@ -2211,12 +2207,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);
+ }
+
+
+===== drivers/char/moxa.c 1.7 vs 1.8 =====
+--- 1.7/drivers/char/moxa.c 2002-02-05 16:53:47 +09:00
++++ 1.8/drivers/char/moxa.c 2004-12-17 00:14:38 +09:00
+@@ -677,8 +677,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 = 0;
+@@ -754,10 +754,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);
+- wake_up_interruptible(&tty->write_wait);
++ tty_wakeup(tty);
+ }
+
+ static int moxa_chars_in_buffer(struct tty_struct *tty)
+@@ -1011,10 +1008,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);
+- wake_up_interruptible(&tp->write_wait);
++ tty_wakeup(tp);
+ }
+ }
+ }
+@@ -1203,10 +1197,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);
+- wake_up_interruptible(&ch->tty->write_wait);
++ tty_wakeup(ch->tty);
+ return;
+ }
+ moxaEmptyTimer[ch->port].expires = jiffies + HZ;
+===== drivers/char/n_r3964.c 1.8 vs 1.9 =====
+--- 1.8/drivers/char/n_r3964.c 2002-12-31 02:26:52 +09:00
++++ 1.9/drivers/char/n_r3964.c 2004-12-16 22:57:23 +09:00
+@@ -158,7 +158,8 @@
+ r3964_write, /* write */
+ r3964_ioctl, /* ioctl */
+ r3964_set_termios, /* set_termios */
+- r3964_poll, /* poll */
++ r3964_poll, /* poll */
++ NULL, /* hangup */
+ r3964_receive_buf, /* receive_buf */
+ r3964_receive_room, /* receive_room */
+ 0 /* write_wakeup */
+===== drivers/char/sh-sci.c 1.14 vs 1.15 =====
+--- 1.14/drivers/char/sh-sci.c 2003-09-20 03:05:52 +09:00
++++ 1.15/drivers/char/sh-sci.c 2004-12-16 23:37:32 +09:00
+@@ -1021,10 +1021,7 @@
+ return;
+
+ if (test_and_clear_bit(SCI_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);
+ }
+ }
+
+===== drivers/char/selection.c 1.3 vs 1.4 =====
+--- 1.3/drivers/char/selection.c 2002-02-05 16:44:55 +09:00
++++ 1.4/drivers/char/selection.c 2004-12-17 00:23:54 +09:00
+@@ -290,9 +290,11 @@
+ {
+ struct vt_struct *vt = (struct vt_struct *) tty->driver_data;
+ int pasted = 0, count;
++ struct tty_ldisc *ld;
+ DECLARE_WAITQUEUE(wait, current);
+
+ poke_blanked_console();
++ 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,12 +303,14 @@
+ continue;
+ }
+ count = sel_buffer_lth - pasted;
+- count = MIN(count, tty->ldisc.receive_room(tty));
+- tty->ldisc.receive_buf(tty, sel_buffer + pasted, 0, count);
++ count = MIN(count, ld->receive_room(tty));
++ ld->receive_buf(tty, sel_buffer + pasted, 0, count);
+ pasted += count;
+ }
+ remove_wait_queue(&vt->paste_wait, &wait);
+ current->state = TASK_RUNNING;
++
++ tty_ldisc_deref(ld);
+ return 0;
+ }
+
+===== drivers/usb/serial/io_ti.c 1.8 vs 1.9 =====
+--- 1.8/drivers/usb/serial/io_ti.c 2003-08-28 20:13:49 +09:00
++++ 1.9/drivers/usb/serial/io_ti.c 2004-12-16 22:57:23 +09:00
+@@ -1800,12 +1800,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);
+ }
+ }
+
+===== drivers/char/ip2/i2lib.c 1.4 vs 1.5 =====
+--- 1.4/drivers/char/ip2/i2lib.c 2002-02-28 22:57:21 +09:00
++++ 1.5/drivers/char/ip2/i2lib.c 2004-12-16 23:44:31 +09:00
+@@ -1385,15 +1385,9 @@
+ ip2trace (CHANN, ITRC_SICMD, 10, 2, tp->flags,
+ (1 << TTY_DO_WRITE_WAKEUP) );
+
+- wake_up_interruptible ( &tp->write_wait );
+- if ( ( tp->flags & (1 << TTY_DO_WRITE_WAKEUP) )
+- && tp->ldisc.write_wakeup )
+- {
+- (tp->ldisc.write_wakeup) ( tp );
++ tty_wakeup(tp);
++ ip2trace (CHANN, ITRC_SICMD, 11, 0 );
+
+- ip2trace (CHANN, ITRC_SICMD, 11, 0 );
+-
+- }
+ }
+
+ static inline void
+===== include/linux/tty_ldisc.h 1.2 vs 1.3 =====
+--- 1.2/include/linux/tty_ldisc.h 2002-02-05 16:39:25 +09:00
++++ 1.3/include/linux/tty_ldisc.h 2004-12-16 22:57:23 +09:00
+@@ -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>
+@@ -121,6 +128,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.
+@@ -129,6 +137,7 @@
+ char *fp, int count);
+ int (*receive_room)(struct tty_struct *);
+ void (*write_wakeup)(struct tty_struct *);
++ int refcount;
+ };
+
+ #define TTY_LDISC_MAGIC 0x5403
+===== drivers/char/amiserial.c 1.8 vs 1.9 =====
+--- 1.8/drivers/char/amiserial.c 2002-08-05 21:48:52 +09:00
++++ 1.9/drivers/char/amiserial.c 2004-12-17 00:11:41 +09:00
+@@ -575,10 +575,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);
+ }
+ }
+
+@@ -1040,10 +1037,7 @@
+ save_flags(flags); cli();
+ 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);
+ }
+
+ /*
+@@ -1608,8 +1602,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;
+===== drivers/char/tty_ioctl.c 1.4 vs 1.5 =====
+--- 1.4/drivers/char/tty_ioctl.c 2002-07-30 20:19:55 +09:00
++++ 1.5/drivers/char/tty_ioctl.c 2004-12-16 22:57:23 +09:00
+@@ -96,8 +96,16 @@
+ {
+ int canon_change;
+ struct termios old_termios = *tty->termios;
++ struct tty_ldisc *ld;
++
++ /*
++ * Perform the actual termios internal changes under lock.
++ */
++
++ /* FIXME: we need to decide on some locking/ordering semantics
++ for the set_termios notification eventually */
++ down(&tty->termios_sem);
+
+- cli();
+ *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;
+@@ -107,7 +115,6 @@
+ tty->canon_data = 0;
+ tty->erasing = 0;
+ }
+- sti();
+ if (canon_change && !L_ICANON(tty) && tty->read_cnt)
+ /* Get characters left over from canonical mode. */
+ wake_up_interruptible(&tty->read_wait);
+@@ -134,13 +141,19 @@
+ 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);
++ }
++ up(&tty->termios_sem);
+ }
+
+ static int set_termios(struct tty_struct * tty, unsigned long arg, int opt)
+ {
+ struct termios tmp_termios;
++ struct tty_ldisc *ld;
+ int retval = tty_check_change(tty);
+
+ if (retval)
+@@ -157,8 +170,13 @@
+ 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);
+@@ -223,12 +241,16 @@
+ static int get_sgttyb(struct tty_struct * tty, struct sgttyb * sgttyb)
+ {
+ struct sgttyb tmp;
++ unsigned long flags;
+
++ down(&tty->termios_sem);
+ 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);
++ up(&tty->termios_sem);
++
+ return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
+ }
+
+@@ -267,12 +289,14 @@
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+- termios = *tty->termios;
+ if (copy_from_user(&tmp, sgttyb, sizeof(tmp)))
+ return -EFAULT;
++ down(&tty->termios_sem);
++ termios = *tty->termios;
+ termios.c_cc[VERASE] = tmp.sg_erase;
+ termios.c_cc[VKILL] = tmp.sg_kill;
+ set_sgflags(&termios, tmp.sg_flags);
++ up(&tty->termios_sem);
+ change_termios(tty, &termios);
+ return 0;
+ }
+@@ -362,6 +386,8 @@
+ {
+ struct tty_struct * real_tty;
+ int retval;
++ struct tty_ldisc *ld;
++ unsigned long flags;
+
+ if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
+ tty->driver.subtype == PTY_TYPE_MASTER)
+@@ -440,22 +466,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 ?
+@@ -501,9 +531,11 @@
+ case TIOCSSOFTCAR:
+ if (get_user(arg, (unsigned int *) arg))
+ return -EFAULT;
++ down(&tty->termios_sem);
+ tty->termios->c_cflag =
+ ((tty->termios->c_cflag & ~CLOCAL) |
+ (arg ? CLOCAL : 0));
++ up(&tty->termios_sem);
+ return 0;
+ default:
+ return -ENOIOCTLCMD;
+===== drivers/sbus/char/zs.c 1.11 vs 1.12 =====
+--- 1.11/drivers/sbus/char/zs.c 2002-03-31 00:45:50 +09:00
++++ 1.12/drivers/sbus/char/zs.c 2004-12-16 22:57:23 +09:00
+@@ -746,10 +746,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);
+ }
+ }
+
+@@ -1199,10 +1196,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);
+ }
+
+ /*
+@@ -1600,15 +1594,14 @@
+ 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 (tty->ldisc.num != ldiscs[N_TTY].num) {
++ if (tty->ldisc.num != N_TTY) {
+ if (tty->ldisc.close)
+ (tty->ldisc.close)(tty);
+- tty->ldisc = ldiscs[N_TTY];
++ tty->ldisc = *(tty_ldisc_get(N_TTY));
+ tty->termios->c_line = N_TTY;
+ if (tty->ldisc.open)
+ (tty->ldisc.open)(tty);
+===== drivers/net/slip.c 1.7 vs 1.8 =====
+--- 1.7/drivers/net/slip.c 2002-08-16 22:59:45 +09:00
++++ 1.8/drivers/net/slip.c 2004-12-16 22:57:23 +09:00
+@@ -670,7 +670,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)
+@@ -826,9 +828,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;
+@@ -865,8 +869,6 @@
+ sl->pid = current->pid;
+ 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. */
+@@ -910,6 +912,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!
+@@ -928,9 +933,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)
+===== drivers/char/ip2main.c 1.10 vs 1.11 =====
+--- 1.10/drivers/char/ip2main.c 2004-08-17 03:41:24 +09:00
++++ 1.11/drivers/char/ip2main.c 2004-12-16 23:27:10 +09:00
+@@ -1462,8 +1462,7 @@
+ if (tty->pgrp > 0)
+ kill_pg(tty->pgrp, sig, 1);
+ if (flush || !L_NOFLSH(tty)) {
+- if ( tty->ldisc.flush_buffer )
+- tty->ldisc.flush_buffer(tty);
++ tty_ldisc_flush(tty);
+ i2InputFlush( tty->driver_data );
+ }
+ }
+@@ -1853,8 +1852,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;
+
+ pCh->pTTY = NULL;
Deleted: trunk/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/patches/115_tty_lockup-3.diff
===================================================================
--- trunk/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/patches/115_tty_lockup-3.diff 2004-12-21 08:22:52 UTC (rev 2012)
+++ trunk/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/patches/115_tty_lockup-3.diff 2004-12-21 09:34:50 UTC (rev 2013)
@@ -1,18 +0,0 @@
-# origin: dann frazier <dannf@debian.org>
-# cset: n/a
-# inclusion: missing comment text backported from 2.6 bitkeeper
-# revision date: 2004-12-14
-# description: Fix unterminated comment
-diff -urN kernel-source-2.4.27.orig/drivers/char/tty_io.c kernel-source-2.4.27/drivers/char/tty_io.c
---- kernel-source-2.4.27.orig/drivers/char/tty_io.c 2004-12-01 03:07:57.000000000 -0700
-+++ kernel-source-2.4.27/drivers/char/tty_io.c 2004-12-14 19:32:06.886350385 -0700
-@@ -767,6 +767,9 @@
- /* 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);
- for_each_task(p) {
- if ((tty->session > 0) && (p->session == tty->session) &&
Modified: trunk/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/patches/series/2.4.27-7
===================================================================
--- trunk/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/patches/series/2.4.27-7 2004-12-21 08:22:52 UTC (rev 2012)
+++ trunk/kernel-2.4/source/kernel-source-2.4.27-2.4.27/debian/patches/series/2.4.27-7 2004-12-21 09:34:50 UTC (rev 2013)
@@ -1,7 +1,9 @@
+ 113-unix-serialization.diff
+ 114-binfmt_aout-CAN-2004-1074.diff
-+ 115_tty_lockup-3.diff
+ 116-cmsg-validation-checks.diff
+ 117-igmp-source-filter-fixes.diff
+ 118-cmsg-validation-checks-compat.diff
+ 119-acpi_early-build.diff
+- 093_tty_lockup.diff
+- 093_tty_lockup-2.diff
++ 093-tty_lockup-3.diff