diff -u --recursive --new-file v2.3.11/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.3.11/linux/Documentation/Configure.help	Wed Jul 21 15:46:48 1999
+++ linux/Documentation/Configure.help	Tue Jul 27 16:05:50 1999
@@ -11921,7 +11921,7 @@
 CONFIG_USB_HUB
   To expand beyond the USB ports on the computer, a device called a 
   hub is used. This driver supports hubs, allowing them to be used. 
-  Say 'Y'
+  Say 'Y'.
 
 USB mouse support
 CONFIG_USB_MOUSE  
@@ -11931,7 +11931,7 @@
 
 USB keyboard support
 CONFIG_USB_KBD
-  This driver allows usb keyboards to work under the USB stack.
+  This driver allows USB keyboards to work under the USB stack.
 
 USB audio parsing support (Preliminary)
 CONFIG_USB_AUDIO
@@ -11943,10 +11943,17 @@
   This driver allows for devices which support the Abstract Control Model,
   including many USB-based modems, ISDN adapters, and network adapters.
 
+USB /proc filesystem entry support (Preliminary)
+CONFIG_USB_PROC
+  This reports USB drivers and devices in the /proc filesystem.
+  Entries are located in /proc/bus/usb.
+  Note that you must enable support for the proc filesystem
+  for this to work.
+
 Support for user-space parallel port device drivers
 CONFIG_PPDEV
   Saying Y to this adds support for /dev/parport device nodes.  This
-  is needed for programs that want portable access to the parallel
+  is needed for programs that want low-level access to the parallel
   port, for instance deviceid (which displays Plug-and-Play device
   IDs) and vlp (which makes a Linux computer act as though it's a
   printer).
diff -u --recursive --new-file v2.3.11/linux/Documentation/IO-APIC.txt linux/Documentation/IO-APIC.txt
--- v2.3.11/linux/Documentation/IO-APIC.txt	Wed Jun 24 14:30:07 1998
+++ linux/Documentation/IO-APIC.txt	Sun Jul 25 10:26:01 1999
@@ -1,51 +1,41 @@
-Most (all) Intel SMP boards have the so-called 'IO-APIC', which is
-an enhanced interrupt controller, able to route hardware interrupts
-to multiple CPUs, or to CPU groups.
+Most (all) Intel-MP compliant SMP boards have the so-called 'IO-APIC',
+which is an enhanced interrupt controller, it enables us to route
+hardware interrupts to multiple CPUs, or to CPU groups.
+
+Linux supports all variants of compliant SMP boards, including ones with
+multiple IO-APICs. (multiple IO-APICs are used in high-end servers to
+distribute IRQ load further).
+
+There are (a few) known breakages in certain older boards, which bugs are
+usually worked around by the kernel. If your MP-compliant SMP board does
+not boot Linux, then consult the linux-smp mailing list archives first.
 
-Linux supports the IO-APIC, but unfortunately there are broken boards
-out there which make it unsafe to enable the IO-APIC unconditionally.
-The Linux policy thus is to enable the IO-APIC only if it's 100% safe, ie.:
-
-	   - the board is on the 'whitelist'
-
-	or - the board does not have PCI pins connected to the IO-APIC
-
-	or - the user has overridden blacklisted settings with the
-	     pirq= boot option line.
-
-Kernel messages tell you whether the board is 'safe'. If your box
-boots with enabled IO-APIC IRQs, then you have nothing else to do. Your
+If your box boots fine with enabled IO-APIC IRQs, then your
 /proc/interrupts will look like this one:
 
    ---------------------------->
-   hell:~> cat /proc/interrupts
-              CPU0       CPU1
-     0:      90782          0   XT PIC   timer
-     1:       4135       2375  IO-APIC   keyboard
-     2:          0          0   XT PIC   cascade
-     3:        851        807  IO-APIC   serial
-     9:          6         22  IO-APIC   ncr53c8xx
-    11:        307        154  IO-APIC   NE2000
-    13:          4          0   XT PIC   fpu
-    14:      56000      30610  IO-APIC   ide0
-   NMI:          0
-   IPI:          0
-   <----------------------------
-
-some interrupts will still be 'XT PIC', but this is not a problem, none
-of those IRQ sources is 'heavy'.
-
-If one of your boot messages says 'unlisted/blacklisted board, DISABLING
-IO-APIC IRQs', then you should do this to get multi-CPU IO-APIC IRQs
-running:
-
-	A) if your board is unlisted, then mail to linux-smp to get
-	   it into either the white or the blacklist
-	B) if your board is blacklisted, then figure out the appropriate
-	   pirq= option to get your system to boot
-
-
-pirq= lines look like the following in /etc/lilo.conf:
+  hell:~> cat /proc/interrupts
+             CPU0
+    0:    1360293    IO-APIC-edge  timer
+    1:          4    IO-APIC-edge  keyboard
+    2:          0          XT-PIC  cascade
+   13:          1          XT-PIC  fpu
+   14:       1448    IO-APIC-edge  ide0
+   16:      28232   IO-APIC-level  Intel EtherExpress Pro 10/100 Ethernet
+   17:      51304   IO-APIC-level  eth0
+  NMI:          0
+  ERR:          0
+  hell:~>
+  <----------------------------
+
+some interrupts are still listed as 'XT PIC', but this is not a problem,
+none of those IRQ sources is performance-critical.
+
+
+in the unlikely case that your board does not create a working mp-table,
+you can use the pirq= boot parameter to 'hand-construct' IRQ entries. This
+is nontrivial though and cannot be automated. One sample /etc/lilo.conf
+entry:
 
 	append="pirq=15,11,10"
 
@@ -111,22 +101,13 @@
 won't function properly (if it's inserted as eg. a module).
 
 If you have 2 PCI buses, then you can use up to 8 pirq values. Although such
-boards tend to have a good configuration and will be included in the
-whitelist.
+boards tend to have a good configuration.
 
 Be prepared that it might happen that you need some strange pirq line:
 
 	append="pirq=0,0,0,0,0,0,9,11"
 
 use smart try-and-err techniques to find out the correct pirq line ...
-
-
-the following pirq line can be used to force a board into the whitelist:
-
-	append="pirq=0"
-
-[if your system works with no problems after this, then it should be added
-to the official whitelist, contact us]
 
 good luck and mail to linux-smp@vger.rutgers.edu or
 linux-kernel@vger.rutgers.edu if you have any problems that are not covered
diff -u --recursive --new-file v2.3.11/linux/Documentation/proc_usb_info.txt linux/Documentation/proc_usb_info.txt
--- v2.3.11/linux/Documentation/proc_usb_info.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/proc_usb_info.txt	Tue Jul 27 16:05:50 1999
@@ -0,0 +1,221 @@
+/proc/bus/usb filesystem output
+===============================
+(version 19990722)
+
+
+The /proc filesystem for USB devices generates
+/proc/bus/usb/drivers and /proc/bus/usb/devices.
+
+/proc/bus/usb/drivers just lists the registered drivers,
+one per line.  Not very interesting or pretty.
+
+In /proc/bus/usb/devices, each device's output has multiple
+lines (except for a root hub) of ASCII output.
+I made it ASCII instead of binary on purpose, so that someone
+can obtain some useful data from it without the use of an
+auxiliary program.  However, with an auxiliary program, the numbers
+in the first 4 columns of each "T:" line (topology info:
+Lev, Prnt, Port, Cnt) can be used to build a USB topology diagram.
+(I think.  I haven't proved this, but I have tested it with 3
+different topo/connections and it looked possible.)
+
+Each line is tagged with a one-character ID for that line:
+
+T = Topology (etc.)
+D = Device descriptor info.
+P = Product ID info. (from Device descriptor, but they won't fit
+    together on one line)
+C = Configuration descriptor info. (* = active configuration)
+I = Interface descriptor info.
+E = Endpoint descriptor info.
+
+=======================================================================
+
+/proc/bus/usb/devices output format:
+
+Legend:
+  d = decimal number (may have leading spaces or 0's)
+  x = hexadecimal number (may have leading spaces or 0's)
+  s = string
+
+
+Topology info:
+
+T:  Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=ddd If#=ddd MxCh=dd Driver=%s
+|   |      |       |       |      |        |       |       |       |__DriverName
+|   |      |       |       |      |        |       |       |__MaxChildren
+|   |      |       |       |      |        |       |__Configured InterfaceNumber
+|   |      |       |       |      |        |__Device Speed in Mbps
+|   |      |       |       |      |__DeviceNumber
+|   |      |       |       |__Count of devices at this level
+|   |      |       |__Connector/Port on Parent for this device
+|   |      |__Parent DeviceNumber
+|   |__Level in topology
+|__Topology info tag
+
+
+Device descriptor info & Product ID info:
+
+D:  Ver=x.xx Cls=xx(s) Sub=xx Prot=xx MxPS=dd #Cfgs=dd
+P:  Vendor=xxxx ProdID=xxxx Rev=xx.xx
+
+where
+D:  Ver=x.xx Cls=xx(sssss) Sub=xx Prot=xx MxPS=dd #Cfgs=dd
+|   |        |             |      |       |       |__NumberConfigurations
+|   |        |             |      |       |__MaxPacketSize of Default Endpoint
+|   |        |             |      |__DeviceProtocol
+|   |        |             |__DeviceSubClass
+|   |        |__DeviceClass
+|   |__Device USB version
+|__Device info tag #1
+
+where
+P:  Vendor=xxxx ProdID=xxxx Rev=xx.xx
+|   |           |           |__Product revision number
+|   |           |__Product ID code
+|   |__Vendor ID code
+|__Device info tag #2
+
+
+Configuration descriptor info:
+
+C:  #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA
+|   |       |       |      |__MaxPower in mA
+|   |       |       |__Attributes
+|   |       |__ConfiguratioNumber
+|   |__NumberOfInterfaces
+|__Config info tag
+
+
+Interface descriptor info (can be multiple per Config):
+
+I:  If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx
+|   |      |      |       |             |      |__InterfaceProtocol
+|   |      |      |       |             |__InterfaceSubClass
+|   |      |      |       |__InterfaceClass
+|   |      |      |__NumberOfEndpoints
+|   |      |__AlternateSettingNumber
+|   |__InterfaceNumber
+|__Interface info tag
+
+
+Endpoint descriptor info (can be multiple per Interface):
+
+E:  Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms
+E:  Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms
+|   |        |         |         |__Interval
+|   |        |         |__EndpointMaxPacketSize
+|   |        |__Attributes(EndpointType)
+|   |__EndpointAddress(I=In,O=Out)
+|__Endpoint info tag
+
+=======================================================================
+
+
+If a user or script is interested only in Topology info, for
+example, use something like "grep ^T: /proc/bus/usb/devices"
+for only the Topology lines.  A command like
+"grep -i ^[tdp]: /proc/bus/usb/devices" can be used to list
+only the lines that begin with the characters in square brackets,
+where the valid characters are TDPCIE.  With a slightly more able
+script, it can display any selected lines (for example, only T, D,
+and P lines) and change their output format.  (The "procusb"
+Perl script is the beginning of this idea.  It will list only
+selected lines [selected from TDPCIE] or "All" lines from
+/proc/bus/usb/devices.)
+
+The Topology lines can be used to generate a graphic/pictorial
+of the USB devices on a system's root hub.  (See more below
+on how to do this.)
+
+The Configuration lines could be used to list maximum power
+(in milliamps) that a system's USB devices are using.
+For example, "grep ^C: /proc/bus/usb/devices".
+
+
+Here's an example, from a system which has a UHCI root hub,
+an external hub connected to the root hub, and a mouse and
+a video camera connected to the external hub.  [The video
+camera is listed as (none) since it is not recognized by
+any driver.]
+
+
+T:  Lev=00 Prnt=00 Port=00 Cnt=00 Dev#= -1 Spd=12  If#=  0 MxCh= 2 Driver=(root hub)
+T:  Lev=01 Prnt=00 Port=00 Cnt=01 Dev#=  1 Spd=12  If#=  0 MxCh= 4 Driver=hub
+D:  Ver= 1.00 Cls=09(hub  ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
+P:  Vendor=0451 ProdID=1446 Rev= 1.00
+C:* #If= 1 Cfg#= 1 Atr=e0 MxPwr=100mA
+I:  If#= 0 Alt= 0 #EP= 1 Cls=09(hub  ) Sub=00 Prot=00
+E:  Ad=81(I) Atr=03(Int.) MxPS=   1 Ivl=255ms
+T:  Lev=02 Prnt=01 Port=00 Cnt=01 Dev#=  3 Spd=1.5 If#=  0 MxCh= 0 Driver=mouse
+D:  Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
+P:  Vendor=0458 ProdID=0001 Rev= 0.00
+C:* #If= 1 Cfg#= 1 Atr=a0 MxPwr=100mA
+I:  If#= 0 Alt= 0 #EP= 1 Cls=03(HID  ) Sub=01 Prot=02
+E:  Ad=81(I) Atr=03(Int.) MxPS=   3 Ivl= 10ms
+T:  Lev=02 Prnt=01 Port=02 Cnt=02 Dev#=  4 Spd=12  If#=  0 MxCh= 0 Driver=(none)
+D:  Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
+P:  Vendor=04c8 ProdID=0720 Rev= 1.01
+C:* #If= 1 Cfg#= 1 Atr=80 MxPwr=500mA
+I:  If#= 0 Alt= 0 #EP= 2 Cls=0a(unk. ) Sub=ff Prot=00
+E:  Ad=81(I) Atr=01(Isoc) MxPS=   1 Ivl=  1ms
+E:  Ad=82(I) Atr=01(Isoc) MxPS= 384 Ivl=  1ms
+I:  If#= 0 Alt= 1 #EP= 2 Cls=0a(unk. ) Sub=ff Prot=00
+E:  Ad=81(I) Atr=01(Isoc) MxPS=   1 Ivl=  1ms
+E:  Ad=82(I) Atr=01(Isoc) MxPS= 240 Ivl=  1ms
+I:  If#= 0 Alt= 2 #EP= 2 Cls=0a(unk. ) Sub=ff Prot=00
+E:  Ad=81(I) Atr=01(Isoc) MxPS=   1 Ivl=  1ms
+E:  Ad=82(I) Atr=01(Isoc) MxPS= 576 Ivl=  1ms
+I:  If#= 0 Alt= 3 #EP= 2 Cls=0a(unk. ) Sub=ff Prot=00
+E:  Ad=81(I) Atr=01(Isoc) MxPS=   1 Ivl=  1ms
+E:  Ad=82(I) Atr=01(Isoc) MxPS= 464 Ivl=  1ms
+I:  If#= 0 Alt= 4 #EP= 2 Cls=0a(unk. ) Sub=ff Prot=00
+E:  Ad=81(I) Atr=01(Isoc) MxPS=   1 Ivl=  1ms
+E:  Ad=82(I) Atr=01(Isoc) MxPS= 688 Ivl=  1ms
+
+
+Selecting only the "T:" lines from this (for example, by using
+"procusb t"), we have:
+
+T:  Lev=00 Prnt=00 Port=00 Cnt=00 Dev#= -1 Spd=12  If#=  0 MxCh= 2 Driver=(root hub)
+T:  Lev=01 Prnt=00 Port=00 Cnt=01 Dev#=  1 Spd=12  If#=  0 MxCh= 4 Driver=hub
+T:  Lev=02 Prnt=01 Port=00 Cnt=01 Dev#=  3 Spd=1.5 If#=  0 MxCh= 0 Driver=mouse
+T:  Lev=02 Prnt=01 Port=02 Cnt=02 Dev#=  4 Spd=12  If#=  0 MxCh= 0 Driver=(none)
+
+
+Physically this looks like (or could be converted to):
+
+                      +------------------+
+                      |  PC/root_hub (12)|   Dev# = -1
+                      +------------------+   (nn) is Mbps.
+    Level 0           |  CN.0   |  CN.1  |   [CN = connector/port #]
+                      +------------------+
+                          /
+                         /
+            +-----------------------+
+  Level 1   | Dev#1: 4-port hub (12)|
+            +-----------------------+
+            |CN.0 |CN.1 |CN.2 |CN.3 |
+            +-----------------------+
+                \           \____________________
+                 \_____                          \
+                       \                          \
+               +--------------------+      +--------------------+
+  Level 2      | Dev# 3: mouse (1.5)|      | Dev# 4: (none) (12)|
+               +--------------------+      +--------------------+
+
+
+
+Or, in a more tree-like structure (ports [Connectors] without
+connections could be omitted):
+
+PC:  Dev# -1, root hub, 2 ports, 12 Mbps
+|_ CN.0:  Dev# 1, hub, 4 ports, 12 Mbps
+     |_ CN.0:  Dev #3, mouse, 1.5 Mbps
+     |_ CN.1:
+     |_ CN.2:  Dev #4, (none), 12 Mbps  [or use "unknown" for (none)]
+     |_ CN.3:
+|_ CN.1:
+
+
+                         ### END ###
diff -u --recursive --new-file v2.3.11/linux/Makefile linux/Makefile
--- v2.3.11/linux/Makefile	Wed Jul 21 15:46:48 1999
+++ linux/Makefile	Sat Jul 24 16:46:46 1999
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 3
-SUBLEVEL = 11
+SUBLEVEL = 12
 EXTRAVERSION =
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
@@ -111,7 +111,7 @@
 NETWORKS	=net/network.a
 DRIVERS		=drivers/block/block.a \
 		 drivers/char/char.a \
-	         drivers/misc/misc.a
+	         drivers/parport/parport.a
 LIBS		=$(TOPDIR)/lib/lib.a
 SUBDIRS		=kernel drivers mm fs net ipc lib
 
diff -u --recursive --new-file v2.3.11/linux/arch/alpha/config.in linux/arch/alpha/config.in
--- v2.3.11/linux/arch/alpha/config.in	Thu Jul  8 15:42:19 1999
+++ linux/arch/alpha/config.in	Sun Jul 25 15:32:53 1999
@@ -188,7 +188,7 @@
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 tristate 'Kernel support for Linux/Intel ELF binaries' CONFIG_BINFMT_EM86
-source drivers/misc/Config.in
+source drivers/parport/Config.in
 endmenu
 
 source drivers/pnp/Config.in
diff -u --recursive --new-file v2.3.11/linux/arch/alpha/kernel/process.c linux/arch/alpha/kernel/process.c
--- v2.3.11/linux/arch/alpha/kernel/process.c	Wed Jul 21 15:46:48 1999
+++ linux/arch/alpha/kernel/process.c	Mon Jul 26 22:41:09 1999
@@ -55,7 +55,6 @@
 unsigned long init_user_stack[1024] = { STACK_MAGIC, };
 static struct vm_area_struct init_mmap = INIT_MMAP;
 static struct fs_struct init_fs = INIT_FS;
-static struct file * init_fd_array[NR_OPEN] = { NULL, };
 static struct files_struct init_files = INIT_FILES;
 static struct signal_struct init_signals = INIT_SIGNALS;
 struct mm_struct init_mm = INIT_MM(init_mm);
diff -u --recursive --new-file v2.3.11/linux/arch/alpha/kernel/signal.c linux/arch/alpha/kernel/signal.c
--- v2.3.11/linux/arch/alpha/kernel/signal.c	Thu Jul  8 15:42:19 1999
+++ linux/arch/alpha/kernel/signal.c	Thu Jul 22 09:47:55 1999
@@ -688,12 +688,8 @@
 
 			case SIGQUIT: case SIGILL: case SIGTRAP:
 			case SIGABRT: case SIGFPE: case SIGSEGV:
-				lock_kernel();
-				if (current->binfmt
-				    && current->binfmt->core_dump
-				    && current->binfmt->core_dump(signr, regs))
+				if (do_coredump(signr, regs))
 					exit_code |= 0x80;
-				unlock_kernel();
 				/* FALLTHRU */
 
 			default:
diff -u --recursive --new-file v2.3.11/linux/arch/arm/kernel/init_task.c linux/arch/arm/kernel/init_task.c
--- v2.3.11/linux/arch/arm/kernel/init_task.c	Thu Jun 17 01:11:35 1999
+++ linux/arch/arm/kernel/init_task.c	Mon Jul 26 22:41:09 1999
@@ -6,7 +6,6 @@
 
 static struct vm_area_struct init_mmap = INIT_MMAP;
 static struct fs_struct init_fs = INIT_FS;
-static struct file * init_fd_array[NR_OPEN] = { NULL, };
 static struct files_struct init_files = INIT_FILES;
 static struct signal_struct init_signals = INIT_SIGNALS;
 struct mm_struct init_mm = INIT_MM(init_mm);
diff -u --recursive --new-file v2.3.11/linux/arch/arm/kernel/setup.c linux/arch/arm/kernel/setup.c
--- v2.3.11/linux/arch/arm/kernel/setup.c	Wed Jul 21 15:46:48 1999
+++ linux/arch/arm/kernel/setup.c	Fri Jul 23 12:20:23 1999
@@ -297,10 +297,10 @@
 
 	setup_processor();
 
-	init_task.mm->start_code = TASK_SIZE;
-	init_task.mm->end_code	 = TASK_SIZE + (unsigned long) &_etext;
-	init_task.mm->end_data	 = TASK_SIZE + (unsigned long) &_edata;
-	init_task.mm->brk	 = TASK_SIZE + (unsigned long) &_end;
+	init_mm.start_code = TASK_SIZE;
+	init_mm.end_code	 = TASK_SIZE + (unsigned long) &_etext;
+	init_mm.end_data	 = TASK_SIZE + (unsigned long) &_edata;
+	init_mm.brk	 = TASK_SIZE + (unsigned long) &_end;
 
 	/*
 	 * Add your machine dependencies here
diff -u --recursive --new-file v2.3.11/linux/arch/arm/kernel/signal.c linux/arch/arm/kernel/signal.c
--- v2.3.11/linux/arch/arm/kernel/signal.c	Thu Jun 17 01:11:35 1999
+++ linux/arch/arm/kernel/signal.c	Thu Jul 22 09:47:55 1999
@@ -543,12 +543,8 @@
 
 			case SIGQUIT: case SIGILL: case SIGTRAP:
 			case SIGABRT: case SIGFPE: case SIGSEGV:
-				lock_kernel();
-				if (current->binfmt
-				    && current->binfmt->core_dump
-				    && current->binfmt->core_dump(signr, regs))
+				if (do_coredump(signr, regs))
 					exit_code |= 0x80;
-				unlock_kernel();
 				/* FALLTHRU */
 
 			default:
diff -u --recursive --new-file v2.3.11/linux/arch/arm/mm/fault-common.c linux/arch/arm/mm/fault-common.c
--- v2.3.11/linux/arch/arm/mm/fault-common.c	Thu Jun 17 01:11:35 1999
+++ linux/arch/arm/mm/fault-common.c	Fri Jul 23 12:20:23 1999
@@ -106,7 +106,7 @@
 	 * If we're in an interrupt or have no user
 	 * context, we must not take the fault..
 	 */
-	if (in_interrupt() || mm == &init_mm)
+	if (in_interrupt() || !mm)
 		goto no_context;
 
 	down(&mm->mmap_sem);
diff -u --recursive --new-file v2.3.11/linux/arch/i386/config.in linux/arch/i386/config.in
--- v2.3.11/linux/arch/i386/config.in	Thu Jul  8 15:42:19 1999
+++ linux/arch/i386/config.in	Sat Jul 24 16:46:46 1999
@@ -92,7 +92,7 @@
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 
-source drivers/misc/Config.in
+source drivers/parport/Config.in
 
 bool 'Advanced Power Management BIOS support' CONFIG_APM
 if [ "$CONFIG_APM" = "y" ]; then
diff -u --recursive --new-file v2.3.11/linux/arch/i386/kernel/init_task.c linux/arch/i386/kernel/init_task.c
--- v2.3.11/linux/arch/i386/kernel/init_task.c	Wed Jul 21 15:46:48 1999
+++ linux/arch/i386/kernel/init_task.c	Mon Jul 26 22:41:09 1999
@@ -8,7 +8,6 @@
 
 static struct vm_area_struct init_mmap = INIT_MMAP;
 static struct fs_struct init_fs = INIT_FS;
-static struct file * init_fd_array[NR_OPEN] = { NULL, };
 static struct files_struct init_files = INIT_FILES;
 static struct signal_struct init_signals = INIT_SIGNALS;
 struct mm_struct init_mm = INIT_MM(init_mm);
diff -u --recursive --new-file v2.3.11/linux/arch/i386/kernel/io_apic.c linux/arch/i386/kernel/io_apic.c
--- v2.3.11/linux/arch/i386/kernel/io_apic.c	Thu May  6 16:07:03 1999
+++ linux/arch/i386/kernel/io_apic.c	Sun Jul 25 10:26:01 1999
@@ -5,6 +5,12 @@
  *
  *	Many thanks to Stig Venaas for trying out countless experimental
  *	patches and reporting/debugging problems patiently!
+ *
+ *	(c) 1999, Multiple IO-APIC support, developed by
+ *	Ken-ichi Yaku <yaku@css1.kbnes.nec.co.jp> and
+ *      Hidemi Kishimoto <kisimoto@css1.kbnes.nec.co.jp>,
+ *	further tested and cleaned up by Zach Brown <zab@redhat.com>
+ *	and Ingo Molnar <mingo@redhat.com>
  */
 
 #include <linux/sched.h>
@@ -19,7 +25,7 @@
  * volatile is justified in this case, IO-APIC register contents
  * might change spontaneously, GCC should not cache it
  */
-#define IO_APIC_BASE ((volatile int *)fix_to_virt(FIX_IO_APIC_BASE))
+#define IO_APIC_BASE(idx) ((volatile int *)__fix_to_virt(FIX_IO_APIC_BASE_0 + idx))
 
 /*
  * The structure of the IO-APIC:
@@ -45,9 +51,10 @@
 } __attribute__ ((packed));
 
 /*
- * # of IRQ routing registers
+ * # of IO-APICs and # of IRQ routing registers
  */
-int nr_ioapic_registers = 0;
+int nr_ioapics = 0;
+int nr_ioapic_registers[MAX_IO_APICS];
 
 enum ioapic_irq_destination_types {
 	dest_Fixed = 0,
@@ -94,6 +101,7 @@
 	mp_ExtINT = 3
 };
 
+struct mpc_config_ioapic mp_apics[MAX_IO_APICS];/* I/O APIC entries */
 int mp_irq_entries = 0;				/* # of MP IRQ source entries */
 struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES];
 						/* MP IRQ source entries */
@@ -108,34 +116,34 @@
  * between pins and IRQs.
  */
 
-static inline unsigned int io_apic_read(unsigned int reg)
+static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg)
 {
-	*IO_APIC_BASE = reg;
-	return *(IO_APIC_BASE+4);
+	*IO_APIC_BASE(apic) = reg;
+	return *(IO_APIC_BASE(apic)+4);
 }
 
-static inline void io_apic_write(unsigned int reg, unsigned int value)
+static inline void io_apic_write(unsigned int apic, unsigned int reg, unsigned int value)
 {
-	*IO_APIC_BASE = reg;
-	*(IO_APIC_BASE+4) = value;
+	*IO_APIC_BASE(apic) = reg;
+	*(IO_APIC_BASE(apic)+4) = value;
 }
 
 /*
  * Re-write a value: to be used for read-modify-write
  * cycles where the read already set up the index register.
  */
-static inline void io_apic_modify(unsigned int value)
+static inline void io_apic_modify(unsigned int apic, unsigned int value)
 {
-	*(IO_APIC_BASE+4) = value;
+	*(IO_APIC_BASE(apic)+4) = value;
 }
 
 /*
  * Synchronize the IO-APIC and the CPU by doing
  * a dummy read from the IO-APIC
  */
-static inline void io_apic_sync(void)
+static inline void io_apic_sync(unsigned int apic)
 {
-	(void) *(IO_APIC_BASE+4);
+	(void) *(IO_APIC_BASE(apic)+4);
 }
 
 /*
@@ -146,7 +154,7 @@
 #define PIN_MAP_SIZE (MAX_PLUS_SHARED_IRQS + NR_IRQS)
 
 static struct irq_pin_list {
-	int pin, next;
+	int apic, pin, next;
 } irq_2_pin[PIN_MAP_SIZE];
 
 /*
@@ -154,7 +162,7 @@
  * shared ISA-space IRQs, so we have to support them. We are super
  * fast in the common case, and fast for shared ISA-space IRQs.
  */
-static void add_pin_to_irq(unsigned int irq, int pin)
+static void add_pin_to_irq(unsigned int irq, int apic, int pin)
 {
 	static int first_free_entry = NR_IRQS;
 	struct irq_pin_list *entry = irq_2_pin + irq;
@@ -168,6 +176,7 @@
 		if (++first_free_entry >= PIN_MAP_SIZE)
 			panic("io_apic.c: whoops");
 	}
+	entry->apic = apic;
 	entry->pin = pin;
 }
 
@@ -183,9 +192,9 @@
 		pin = entry->pin;					\
 		if (pin == -1)						\
 			break;						\
-		reg = io_apic_read(0x10 + R + pin*2);			\
+		reg = io_apic_read(entry->apic, 0x10 + R + pin*2);	\
 		reg ACTION;						\
-		io_apic_modify(reg);					\
+		io_apic_modify(entry->apic, reg);			\
 		if (!entry->next)					\
 			break;						\
 		entry = irq_2_pin + entry->next;			\
@@ -197,12 +206,12 @@
  * We disable IO-APIC IRQs by setting their 'destination CPU mask' to
  * zero. Trick by Ramesh Nalluri.
  */
-DO_ACTION( disable, 1, &= 0x00ffffff, io_apic_sync())		/* destination = 0x00 */
+DO_ACTION( disable, 1, &= 0x00ffffff, io_apic_sync(entry->apic))/* destination = 0x00 */
 DO_ACTION( enable,  1, |= 0xff000000, )				/* destination = 0xff */
-DO_ACTION( mask,    0, |= 0x00010000, io_apic_sync())		/* mask = 1 */
+DO_ACTION( mask,    0, |= 0x00010000, io_apic_sync(entry->apic))/* mask = 1 */
 DO_ACTION( unmask,  0, &= 0xfffeffff, )				/* mask = 0 */
 
-static void clear_IO_APIC_pin(unsigned int pin)
+static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
 {
 	struct IO_APIC_route_entry entry;
 
@@ -211,16 +220,17 @@
 	 */
 	memset(&entry, 0, sizeof(entry));
 	entry.mask = 1;
-	io_apic_write(0x10 + 2 * pin, *(((int *)&entry) + 0));
-	io_apic_write(0x11 + 2 * pin, *(((int *)&entry) + 1));
+	io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&entry) + 0));
+	io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&entry) + 1));
 }
 
 static void clear_IO_APIC (void)
 {
-	int pin;
+	int apic, pin;
 
-	for (pin = 0; pin < nr_ioapic_registers; pin++)
-		clear_IO_APIC_pin(pin);
+	for (apic = 0; apic < nr_ioapics; apic++)
+		for (pin = 0; pin < nr_ioapic_registers[apic]; pin++)
+			clear_IO_APIC_pin(apic, pin);
 }
 
 /*
@@ -270,12 +280,13 @@
 /*
  * Find the IRQ entry number of a certain pin.
  */
-static int __init find_irq_entry(int pin, int type)
+static int __init find_irq_entry(int apic, int pin, int type)
 {
 	int i;
 
 	for (i = 0; i < mp_irq_entries; i++)
 		if ( (mp_irqs[i].mpc_irqtype == type) &&
+			(mp_irqs[i].mpc_dstapic == mp_apics[apic].mpc_apicid) &&
 			(mp_irqs[i].mpc_dstirq == pin))
 
 			return i;
@@ -307,21 +318,26 @@
  * Find a specific PCI IRQ entry.
  * Not an initfunc, possibly needed by modules
  */
+static int __init pin_2_irq(int idx, int apic, int pin);
 int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pci_pin)
 {
-	int i;
+	int apic, i;
 
 	for (i = 0; i < mp_irq_entries; i++) {
 		int lbus = mp_irqs[i].mpc_srcbus;
 
-		if (IO_APIC_IRQ(mp_irqs[i].mpc_dstirq) &&
+		for (apic = 0; apic < nr_ioapics; apic++)
+			if (mp_apics[apic].mpc_apicid == mp_irqs[i].mpc_dstapic)
+				break;
+
+		if ((apic || IO_APIC_IRQ(mp_irqs[i].mpc_dstirq)) &&
 		    (mp_bus_id_to_type[lbus] == MP_BUS_PCI) &&
 		    !mp_irqs[i].mpc_irqtype &&
 		    (bus == mp_bus_id_to_pci_bus[mp_irqs[i].mpc_srcbus]) &&
 		    (slot == ((mp_irqs[i].mpc_srcbusirq >> 2) & 0x1f)) &&
 		    (pci_pin == (mp_irqs[i].mpc_srcbusirq & 3)))
 
-			return mp_irqs[i].mpc_dstirq;
+			return pin_2_irq(i,apic,mp_irqs[i].mpc_dstirq);
 	}
 	return -1;
 }
@@ -491,9 +507,9 @@
 	return MPBIOS_trigger(idx);
 }
 
-static int __init pin_2_irq(int idx, int pin)
+static int __init pin_2_irq(int idx, int apic, int pin)
 {
-	int irq;
+	int irq, i;
 	int bus = mp_irqs[idx].mpc_srcbus;
 
 	/*
@@ -513,9 +529,12 @@
 		case MP_BUS_PCI: /* PCI pin */
 		{
 			/*
-			 * PCI IRQs are 'directly mapped'
+			 * PCI IRQs are mapped in order
 			 */
-			irq = pin;
+			i = irq = 0;
+			while (i < apic)
+				irq += nr_ioapic_registers[i++];
+			irq += pin;
 			break;
 		}
 		default:
@@ -545,12 +564,14 @@
 
 static inline int IO_APIC_irq_trigger(int irq)
 {
-	int idx, pin;
+	int apic, idx, pin;
 
-	for (pin = 0; pin < nr_ioapic_registers; pin++) {
-		idx = find_irq_entry(pin,mp_INT);
-		if ((idx != -1) && (irq == pin_2_irq(idx,pin)))
-			return irq_trigger(idx);
+	for (apic = 0; apic < nr_ioapics; apic++) {
+		for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
+			idx = find_irq_entry(apic,pin,mp_INT);
+			if ((idx != -1) && (irq == pin_2_irq(idx,apic,pin)))
+				return irq_trigger(idx);
+		}
 	}
 	/*
 	 * nonexistent IRQs are edge default
@@ -582,11 +603,12 @@
 void __init setup_IO_APIC_irqs(void)
 {
 	struct IO_APIC_route_entry entry;
-	int pin, idx, bus, irq, first_notcon = 1;
+	int apic, pin, idx, irq, first_notcon = 1;
 
 	printk("init IO_APIC IRQs\n");
 
-	for (pin = 0; pin < nr_ioapic_registers; pin++) {
+	for (apic = 0; apic < nr_ioapics; apic++) {
+	for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
 
 		/*
 		 * add it to the IO-APIC irq-routing table:
@@ -598,13 +620,13 @@
 		entry.mask = 0;				/* enable IRQ */
 		entry.dest.logical.logical_dest = 0;	/* but no route */
 
-		idx = find_irq_entry(pin,mp_INT);
+		idx = find_irq_entry(apic,pin,mp_INT);
 		if (idx == -1) {
 			if (first_notcon) {
-				printk(" IO-APIC pin %d", pin);
+				printk(" IO-APIC (apicid-pin) %d-%d", mp_apics[apic].mpc_apicid, pin);
 				first_notcon = 0;
 			} else
-				printk(", %d", pin);
+				printk(", %d-%d", mp_apics[apic].mpc_apicid, pin);
 			continue;
 		}
 
@@ -617,18 +639,17 @@
 			entry.dest.logical.logical_dest = 0xff;
 		}
 
-		irq = pin_2_irq(idx,pin);
-		add_pin_to_irq(irq, pin);
+		irq = pin_2_irq(idx,apic,pin);
+		add_pin_to_irq(irq, apic, pin);
 
-		if (!IO_APIC_IRQ(irq))
+		if (!apic && !IO_APIC_IRQ(irq))
 			continue;
 
 		entry.vector = assign_irq_vector(irq);
 
-		bus = mp_irqs[idx].mpc_srcbus;
-
-		io_apic_write(0x11+2*pin, *(((int *)&entry)+1));
-		io_apic_write(0x10+2*pin, *(((int *)&entry)+0));
+		io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1));
+		io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0));
+	}
 	}
 
 	if (!first_notcon)
@@ -638,7 +659,7 @@
 /*
  * Set up a certain pin as ExtINT delivered interrupt
  */
-void __init setup_ExtINT_pin(unsigned int pin, int irq)
+void __init setup_ExtINT_pin(unsigned int apic, unsigned int pin, int irq)
 {
 	struct IO_APIC_route_entry entry;
 
@@ -662,8 +683,8 @@
 	entry.polarity = 0;
 	entry.trigger = 0;
 
-	io_apic_write(0x10+2*pin, *(((int *)&entry)+0));
-	io_apic_write(0x11+2*pin, *(((int *)&entry)+1));
+	io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0));
+	io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1));
 }
 
 void __init UNEXPECTED_IO_APIC(void)
@@ -674,17 +695,14 @@
 
 void __init print_IO_APIC(void)
 {
-	int i;
+	int apic, i;
 	struct IO_APIC_reg_00 reg_00;
 	struct IO_APIC_reg_01 reg_01;
 	struct IO_APIC_reg_02 reg_02;
 
  	printk("number of MP IRQ sources: %d.\n", mp_irq_entries);
- 	printk("number of IO-APIC registers: %d.\n", nr_ioapic_registers);
-
-	*(int *)&reg_00 = io_apic_read(0);
-	*(int *)&reg_01 = io_apic_read(1);
-	*(int *)&reg_02 = io_apic_read(2);
+	for (i = 0; i < nr_ioapics; i++)
+		printk("number of IO-APIC #%d registers: %d.\n", mp_apics[i].mpc_apicid, nr_ioapic_registers[i]);
 
 	/*
 	 * We are a bit conservative about what we expect.  We have to
@@ -692,6 +710,12 @@
 	 */
 	printk("testing the IO APIC.......................\n");
 
+	for (apic = 0; apic < nr_ioapics; apic++) {
+
+	*(int *)&reg_00 = io_apic_read(apic, 0);
+	*(int *)&reg_01 = io_apic_read(apic, 1);
+	*(int *)&reg_02 = io_apic_read(apic, 2);
+	printk("\nIO APIC #%d......\n", mp_apics[apic].mpc_apicid);
 	printk(".... register #00: %08X\n", *(int *)&reg_00);
 	printk(".......    : physical APIC id: %02X\n", reg_00.ID);
 	if (reg_00.__reserved_1 || reg_00.__reserved_2)
@@ -706,8 +730,6 @@
 		(reg_01.entries != 0x3F)    /* bigger Xeon boards */
 	)
 		UNEXPECTED_IO_APIC();
-	if (reg_01.entries == 0x0f)
-		printk(".......       [IO-APIC cannot route PCI PIRQ 0-3]\n");
 
 	printk(".......     : IO APIC version: %04X\n", reg_01.version);
 	if (	(reg_01.version != 0x10) && /* oldest IO-APICs */
@@ -731,8 +753,8 @@
 	for (i = 0; i <= reg_01.entries; i++) {
 		struct IO_APIC_route_entry entry;
 
-		*(((int *)&entry)+0) = io_apic_read(0x10+i*2);
-		*(((int *)&entry)+1) = io_apic_read(0x11+i*2);
+		*(((int *)&entry)+0) = io_apic_read(apic, 0x10+i*2);
+		*(((int *)&entry)+1) = io_apic_read(apic, 0x11+i*2);
 
 		printk(" %02x %03X %02X  ",
 			i,
@@ -751,7 +773,7 @@
 			entry.vector
 		);
 	}
-
+	}
 	printk(KERN_DEBUG "IRQ to pin mappings:\n");
 	for (i = 0; i < NR_IRQS; i++) {
 		struct irq_pin_list *entry = irq_2_pin + i;
@@ -796,9 +818,12 @@
 	 */
 	{
 		struct IO_APIC_reg_01 reg_01;
+		int i;
 
-		*(int *)&reg_01 = io_apic_read(1);
-		nr_ioapic_registers = reg_01.entries+1;
+		for (i = 0; i < nr_ioapics; i++) {
+			*(int *)&reg_01 = io_apic_read(i, 1);
+			nr_ioapic_registers[i] = reg_01.entries+1;
+		}
 	}
 
 	/*
@@ -827,55 +852,6 @@
 	printk("...done.\n");
 }
 
-char ioapic_OEM_ID [16];
-char ioapic_Product_ID [16];
-
-struct ioapic_list_entry {
-	char * oem_id;
-	char * product_id;
-};
-
-struct ioapic_list_entry __initdata ioapic_whitelist [] = {
-
-	{ "INTEL   "	, 	"PR440FX     "	},
-	{ "INTEL   "	,	"82440FX     "	},
-	{ "AIR     "	,	"KDI         "	},
-	{ 0		,	0		}
-};
-
-struct ioapic_list_entry __initdata ioapic_blacklist [] = {
-
-	{ "OEM00000"	,	"PROD00000000"	},
-	{ 0		,	0		}
-};
-
-static int __init in_ioapic_list(struct ioapic_list_entry * table)
-{
-	for ( ; table->oem_id ; table++)
-		if ((!strcmp(table->oem_id,ioapic_OEM_ID)) &&
-		    (!strcmp(table->product_id,ioapic_Product_ID)))
-			return 1;
-	return 0;
-}
-
-static int __init ioapic_whitelisted(void)
-{
-/*
- * Right now, whitelist everything to see whether the new parsing
- * routines really do work for everybody.
- */
-#if 1
-	return 1;
-#else
-	return in_ioapic_list(ioapic_whitelist);
-#endif
-}
-
-static int __init ioapic_blacklisted(void)
-{
-	return in_ioapic_list(ioapic_blacklist);
-}
-
 static void __init setup_ioapic_id(void)
 {
 	struct IO_APIC_reg_00 reg_00;
@@ -897,15 +873,15 @@
 	/*
 	 * Set the ID
 	 */
-	*(int *)&reg_00 = io_apic_read(0);
+	*(int *)&reg_00 = io_apic_read(0, 0);
 	printk("...changing IO-APIC physical APIC ID to 2...\n");
 	reg_00.ID = 0x2;
-	io_apic_write(0, *(int *)&reg_00);
+	io_apic_write(0, 0, *(int *)&reg_00);
 
 	/*
 	 * Sanity check
 	 */
-	*(int *)&reg_00 = io_apic_read(0);
+	*(int *)&reg_00 = io_apic_read(0, 0);
 	if (reg_00.ID != 0x2)
 		panic("could not set ID");
 }
@@ -1227,7 +1203,10 @@
 
 		if (pin2 != -1) {
 			printk(".. (found pin %d) ...", pin2);
-			setup_ExtINT_pin(pin2, 0);
+			/*
+			 * legacy devices should be connected to IO APIC #0
+			 */
+			setup_ExtINT_pin(0, pin2, 0);
 			make_8259A_irq(0);
 		}
 
@@ -1238,9 +1217,9 @@
 			 * Just in case ...
 			 */
 			if (pin1 != -1)
-				clear_IO_APIC_pin(pin1);
+				clear_IO_APIC_pin(0, pin1);
 			if (pin2 != -1)
-				clear_IO_APIC_pin(pin2);
+				clear_IO_APIC_pin(0, pin2);
 
 			make_8259A_irq(0);
 
@@ -1273,29 +1252,8 @@
 {
 	init_sym_mode();
 
-	/*
-	 * Determine the range of IRQs handled by the IO-APIC. The
-	 * following boards can be fully enabled:
-	 *
-	 * - whitelisted ones
-	 * - those which have no PCI pins connected
-	 * - those for which the user has specified a pirq= parameter
-	 */
-	if (	ioapic_whitelisted() ||
-		(nr_ioapic_registers == 16) ||
-		pirqs_enabled)
-	{
-		printk("ENABLING IO-APIC IRQs\n");
-		io_apic_irqs = ~PIC_IRQS;
-	} else {
-		if (ioapic_blacklisted())
-			printk(" blacklisted board, DISABLING IO-APIC IRQs\n");
-		else
-			printk(" unlisted board, DISABLING IO-APIC IRQs\n");
-
-		printk(" see Documentation/IO-APIC.txt to enable them\n");
-		io_apic_irqs = 0;
-	}
+	printk("ENABLING IO-APIC IRQs\n");
+	io_apic_irqs = ~PIC_IRQS;
 
 	/*
 	 * If there are no explicit MP IRQ entries, it's either one of the
diff -u --recursive --new-file v2.3.11/linux/arch/i386/kernel/irq.h linux/arch/i386/kernel/irq.h
--- v2.3.11/linux/arch/i386/kernel/irq.h	Thu Jul  8 15:42:19 1999
+++ linux/arch/i386/kernel/irq.h	Wed Jul 28 13:58:07 1999
@@ -57,9 +57,9 @@
 /*
  * Special IRQ vectors used by the SMP architecture:
  *
- * (some of the following vectors are 'rare', they might be merged
- *  into a single vector to save vector space. TLB, reschedule and
- *  local APIC vectors are performance-critical.)
+ * (some of the following vectors are 'rare', they are merged
+ *  into a single vector (FUNCTION_VECTOR) to save vector space.
+ *  TLB, reschedule and local APIC vectors are performance-critical.)
  */
 #define RESCHEDULE_VECTOR	0x30
 #define INVALIDATE_TLB_VECTOR	0x31
@@ -120,8 +120,6 @@
 };
 extern int mp_bus_id_to_type [MAX_MP_BUSSES];
 extern int mp_bus_id_to_pci_bus [MAX_MP_BUSSES];
-extern char ioapic_OEM_ID [16];
-extern char ioapic_Product_ID [16];
 
 extern spinlock_t irq_controller_lock;
 
diff -u --recursive --new-file v2.3.11/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c
--- v2.3.11/linux/arch/i386/kernel/process.c	Wed Jul 21 15:46:48 1999
+++ linux/arch/i386/kernel/process.c	Sun Jul 25 23:15:13 1999
@@ -40,6 +40,7 @@
 #include <asm/ldt.h>
 #include <asm/processor.h>
 #include <asm/desc.h>
+#include <asm/mmu_context.h>
 #ifdef CONFIG_MATH_EMULATION
 #include <asm/math_emu.h>
 #endif
@@ -321,13 +322,9 @@
 	pg0[0] = _PAGE_RW | _PAGE_PRESENT;
 
 	/*
-	 * Use `swapper_pg_dir' as our page directory.  We bother with
-	 * `SET_PAGE_DIR' because although might be rebooting, but if we change
-	 * the way we set root page dir in the future, then we wont break a
-	 * seldom used feature ;)
+	 * Use `swapper_pg_dir' as our page directory.
 	 */
-
-	SET_PAGE_DIR(current,swapper_pg_dir);
+	asm volatile("movl %0,%%cr3": :"r" (__pa(swapper_pg_dir)));
 
 	/* Write 0x1234 to absolute memory location 0x472.  The BIOS reads
 	   this on booting to tell it to "Bypass memory test (also warm
@@ -488,16 +485,7 @@
 	 */
 	if (ldt) {
 		mm->segments = NULL;
-		/*
-		 * special case, when we release the LDT from under
-		 * the running CPU. Other CPUs cannot possibly use
-		 * this LDT as we were getting here through mmput() ...
-		 */
-		if (mm == current->mm)
-			load_LDT(mm);
-		/*
-		 * Nobody anymore uses the LDT, we can free it:
-		 */
+		clear_LDT();
 		vfree(ldt);
 	}
 }
@@ -579,12 +567,8 @@
 }
 
 /*
- * If new_mm is NULL, we're being called to set up the LDT for
- * a clone task: this is easy since the clone is not running yet.
- * otherwise we copy the old segment into a new segment.
- *
  * we do not have to muck with descriptors here, that is
- * done in __switch_to() and get_mmu_context().
+ * done in switch_mm() as needed.
  */
 void copy_segments(struct task_struct *p, struct mm_struct *new_mm)
 {
@@ -595,22 +579,19 @@
 		/*
 		 * default LDT - use the one from init_task
 		 */
-		if (new_mm)
-			new_mm->segments = NULL;
+		new_mm->segments = NULL;
 		return;
 	}
 
-	if (new_mm) {
-		/*
-		 * Completely new LDT, we initialize it from the parent:
-		 */
-		ldt = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
-		if (!ldt)
-			printk(KERN_WARNING "ldt allocation failed\n");
-		else
-			memcpy(ldt, old_ldt, LDT_ENTRIES*LDT_ENTRY_SIZE);
-		new_mm->segments = ldt;
-	}
+	/*
+	 * Completely new LDT, we initialize it from the parent:
+	 */
+	ldt = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
+	if (!ldt)
+		printk(KERN_WARNING "ldt allocation failed\n");
+	else
+		memcpy(ldt, old_ldt, LDT_ENTRIES*LDT_ENTRY_SIZE);
+	new_mm->segments = ldt;
 	return;
 }
 
@@ -754,21 +735,6 @@
 	 */
 	asm volatile("movl %%fs,%0":"=m" (*(int *)&prev->fs));
 	asm volatile("movl %%gs,%0":"=m" (*(int *)&prev->gs));
-
-	/*
-	 * Re-load LDT if necessary
-	 */
-	if (prev_p->active_mm->segments != next_p->active_mm->segments)
-		load_LDT(next_p->mm);
-
-	/* Re-load page tables */
-	{
-		unsigned long new_cr3 = next->cr3;
-
-		tss->cr3 = new_cr3;
-		if (new_cr3 != prev->cr3)
-			asm volatile("movl %0,%%cr3": :"r" (new_cr3));
-	}
 
 	/*
 	 * Restore %fs and %gs.
diff -u --recursive --new-file v2.3.11/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- v2.3.11/linux/arch/i386/kernel/setup.c	Wed Jul 21 15:46:48 1999
+++ linux/arch/i386/kernel/setup.c	Sun Jul 25 13:45:25 1999
@@ -313,10 +313,10 @@
 	if (!MOUNT_ROOT_RDONLY)
 		root_mountflags &= ~MS_RDONLY;
 	memory_start = (unsigned long) &_end;
-	init_task.mm->start_code = PAGE_OFFSET;
-	init_task.mm->end_code = (unsigned long) &_etext;
-	init_task.mm->end_data = (unsigned long) &_edata;
-	init_task.mm->brk = (unsigned long) &_end;
+	init_mm.start_code = PAGE_OFFSET;
+	init_mm.end_code = (unsigned long) &_etext;
+	init_mm.end_data = (unsigned long) &_edata;
+	init_mm.brk = (unsigned long) &_end;
 
 	/* Save unparsed command line copy for /proc/cmdline */
 	memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE);
@@ -354,7 +354,7 @@
 	*to = '\0';
 	*cmdline_p = command_line;
 
-#define VMALLOC_RESERVE	(64 << 20)	/* 64MB for vmalloc */
+#define VMALLOC_RESERVE	(128 << 20)	/* 128MB for vmalloc and initrd */
 #define MAXMEM	((unsigned long)(-PAGE_OFFSET-VMALLOC_RESERVE))
 
 	if (memory_end > MAXMEM)
diff -u --recursive --new-file v2.3.11/linux/arch/i386/kernel/signal.c linux/arch/i386/kernel/signal.c
--- v2.3.11/linux/arch/i386/kernel/signal.c	Wed Jul 21 15:46:48 1999
+++ linux/arch/i386/kernel/signal.c	Thu Jul 22 09:47:55 1999
@@ -687,12 +687,8 @@
 
 			case SIGQUIT: case SIGILL: case SIGTRAP:
 			case SIGABRT: case SIGFPE: case SIGSEGV:
-				lock_kernel();
-				if (current->binfmt
-				    && current->binfmt->core_dump
-				    && current->binfmt->core_dump(signr, regs))
+				if (do_coredump(signr, regs))
 					exit_code |= 0x80;
-				unlock_kernel();
 				/* FALLTHRU */
 
 			default:
diff -u --recursive --new-file v2.3.11/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c
--- v2.3.11/linux/arch/i386/kernel/smp.c	Wed Jul 21 15:46:48 1999
+++ linux/arch/i386/kernel/smp.c	Wed Jul 28 10:45:39 1999
@@ -128,6 +128,8 @@
 const char lk_lockmsg[] = "lock from interrupt context at %p\n"; 
 
 int mp_bus_id_to_type [MAX_MP_BUSSES] = { -1, };
+extern int nr_ioapics;
+extern struct mpc_config_ioapic mp_apics [MAX_IO_APICS];
 extern int mp_irq_entries;
 extern struct mpc_config_intsrc mp_irqs [MAX_IRQ_SOURCES];
 extern int mpc_default_type;
@@ -258,12 +260,10 @@
 	}
 	memcpy(str,mpc->mpc_oem,8);
 	str[8]=0;
-	memcpy(ioapic_OEM_ID,str,9);
 	printk("OEM ID: %s ",str);
 	
 	memcpy(str,mpc->mpc_productid,12);
 	str[12]=0;
-	memcpy(ioapic_Product_ID,str,13);
 	printk("Product ID: %s ",str);
 
 	printk("APIC at: 0x%lX\n",mpc->mpc_lapic);
@@ -368,11 +368,9 @@
 					printk("I/O APIC #%d Version %d at 0x%lX.\n",
 						m->mpc_apicid,m->mpc_apicver,
 						m->mpc_apicaddr);
-					/*
-					 * we use the first one only currently
-					 */
-					if (ioapics == 1)
-						mp_ioapic_addr = m->mpc_apicaddr;
+					mp_apics [nr_ioapics] = *m;
+					if (++nr_ioapics > MAX_IO_APICS)
+						--nr_ioapics;
 				}
 				mpt+=sizeof(*m);
 				count+=sizeof(*m);
@@ -404,9 +402,9 @@
 			}
 		}
 	}
-	if (ioapics > 1)
+	if (ioapics > MAX_IO_APICS)
 	{
-		printk("Warning: Multiple IO-APICs not yet supported.\n");
+		printk("Warning: Max I/O APICs exceeded (max %d, found %d).\n", MAX_IO_APICS, ioapics);
 		printk("Warning: switching to non APIC mode.\n");
 		skip_ioapic_setup=1;
 	}
@@ -774,18 +772,22 @@
 
 #ifdef CONFIG_X86_IO_APIC
 	{
-		unsigned long ioapic_phys;
+		unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0;
+		int i;
 
-		if (smp_found_config) {
-			ioapic_phys = mp_ioapic_addr;
-		} else {
-			ioapic_phys = __pa(memory_start);
-			memset((void *)memory_start, 0, PAGE_SIZE);
-			memory_start += PAGE_SIZE;
+		for (i = 0; i < nr_ioapics; i++) {
+			if (smp_found_config) {
+				ioapic_phys = mp_apics[i].mpc_apicaddr;
+			} else {
+				ioapic_phys = __pa(memory_start);
+				memset((void *)memory_start, 0, PAGE_SIZE);
+				memory_start += PAGE_SIZE;
+			}
+			set_fixmap(idx,ioapic_phys);
+			printk("mapped IOAPIC to %08lx (%08lx)\n",
+					__fix_to_virt(idx), ioapic_phys);
+			idx++;
 		}
-		set_fixmap(FIX_IO_APIC_BASE,ioapic_phys);
-		printk("mapped IOAPIC to %08lx (%08lx)\n",
-				fix_to_virt(FIX_IO_APIC_BASE), ioapic_phys);
 	}
 #endif
 
@@ -1382,12 +1384,6 @@
 		printk(KERN_WARNING "WARNING: SMP operation may be unreliable with B stepping processors.\n");
 	SMP_PRINTK(("Boot done.\n"));
 
-	/*
-	 * now we know the other CPUs have fired off and we know our
-	 * APIC ID, so we can go init the TSS and stuff:
-	 */
-	cpu_init();
-
 	cache_APIC_registers();
 #ifndef CONFIG_VISWS
 	/*
@@ -1399,6 +1395,11 @@
 #endif
 
 smp_done:
+	/*
+	 * now we know the other CPUs have fired off and we know our
+	 * APIC ID, so we can go init the TSS and stuff:
+	 */
+	cpu_init();
 }
 
 
@@ -1578,8 +1579,7 @@
  * bad as in the early days of SMP, so we might ease some of the
  * paranoia here.
  */
-
-void smp_flush_tlb(void)
+static void flush_tlb_others(unsigned int cpumask)
 {
 	int cpu = smp_processor_id();
 	int stuck;
@@ -1589,17 +1589,9 @@
 	 * it's important that we do not generate any APIC traffic
 	 * until the AP CPUs have booted up!
 	 */
-	if (cpu_online_map) {
-		/*
-		 * The assignment is safe because it's volatile so the
-		 * compiler cannot reorder it, because the i586 has
-		 * strict memory ordering and because only the kernel
-		 * lock holder may issue a tlb flush. If you break any
-		 * one of those three change this to an atomic bus
-		 * locked or.
-		 */
-
-		smp_invalidate_needed = cpu_online_map;
+	cpumask &= cpu_online_map;
+	if (cpumask) {
+		atomic_set_mask(cpumask, &smp_invalidate_needed);
 
 		/*
 		 * Processors spinning on some lock with IRQs disabled
@@ -1622,8 +1614,10 @@
 			/*
 			 * Take care of "crossing" invalidates
 			 */
-			if (test_bit(cpu, &smp_invalidate_needed))
-			clear_bit(cpu, &smp_invalidate_needed);
+			if (test_bit(cpu, &smp_invalidate_needed)) {
+				clear_bit(cpu, &smp_invalidate_needed);
+				local_flush_tlb();
+			}
 			--stuck;
 			if (!stuck) {
 				printk("stuck on TLB IPI wait (CPU#%d)\n",cpu);
@@ -1632,12 +1626,58 @@
 		}
 		__restore_flags(flags);
 	}
+}
 
-	/*
-	 *	Flush the local TLB
-	 */
+/*
+ *	Smarter SMP flushing macros. 
+ *		c/o Linus Torvalds.
+ *
+ *	These mean you can really definitely utterly forget about
+ *	writing to user space from interrupts. (Its not allowed anyway).
+ */	
+void flush_tlb_current_task(void)
+{
+	unsigned long vm_mask = 1 << current->processor;
+	struct mm_struct *mm = current->mm;
+
+	if (mm->cpu_vm_mask != vm_mask) {
+		flush_tlb_others(mm->cpu_vm_mask & ~vm_mask);
+		mm->cpu_vm_mask = vm_mask;
+	}
 	local_flush_tlb();
+}
+
+void flush_tlb_mm(struct mm_struct * mm)
+{
+	unsigned long vm_mask = 1 << current->processor;
+	unsigned long cpu_mask = mm->cpu_vm_mask & ~vm_mask;
+
+	mm->cpu_vm_mask = 0;
+	if (current->active_mm == mm) {
+		mm->cpu_vm_mask = vm_mask;
+		local_flush_tlb();
+	}
+	flush_tlb_others(cpu_mask);
+}
 
+void flush_tlb_page(struct vm_area_struct * vma, unsigned long va)
+{
+	unsigned long vm_mask = 1 << current->processor;
+	struct mm_struct *mm = vma->vm_mm;
+	unsigned long cpu_mask = mm->cpu_vm_mask & ~vm_mask;
+
+	mm->cpu_vm_mask = 0;
+	if (current->active_mm == mm) {
+		__flush_tlb_one(va);
+		mm->cpu_vm_mask = vm_mask;
+	}
+	flush_tlb_others(cpu_mask);
+}
+
+void flush_tlb_all(void)
+{
+	flush_tlb_others(~(1 << current->processor));
+	local_flush_tlb();
 }
 
 
@@ -1860,13 +1900,24 @@
 }
 
 /*
- * Invalidate call-back
+ * Invalidate call-back.
+ *
+ * Mark the CPU as a VM user if there is a active
+ * thread holding on to an mm at this time. This
+ * allows us to optimize CPU cross-calls even in the
+ * presense of lazy TLB handling.
  */
 asmlinkage void smp_invalidate_interrupt(void)
 {
-	if (test_and_clear_bit(smp_processor_id(), &smp_invalidate_needed))
-		local_flush_tlb();
+	struct task_struct *tsk = current;
+	unsigned int cpu = tsk->processor;
 
+	if (test_and_clear_bit(cpu, &smp_invalidate_needed)) {
+		struct mm_struct *mm = tsk->mm;
+		if (mm)
+			atomic_set_mask(1 << cpu, &mm->cpu_vm_mask);
+		local_flush_tlb();
+	}
 	ack_APIC_irq();
 
 }
diff -u --recursive --new-file v2.3.11/linux/arch/i386/math-emu/fpu_entry.c linux/arch/i386/math-emu/fpu_entry.c
--- v2.3.11/linux/arch/i386/math-emu/fpu_entry.c	Sun Sep 13 12:17:48 1998
+++ linux/arch/i386/math-emu/fpu_entry.c	Fri Jul 23 13:19:02 1999
@@ -283,8 +283,8 @@
 	  FPU_EIP = FPU_ORIG_EIP;	/* Point to current FPU instruction. */
 
 	  RE_ENTRANT_CHECK_OFF;
-	  current->tss.trap_no = 16;
-	  current->tss.error_code = 0;
+	  current->thread.trap_no = 16;
+	  current->thread.error_code = 0;
 	  send_sig(SIGFPE, current, 1);
 	  return;
 	}
@@ -662,8 +662,8 @@
 void math_abort(struct info * info, unsigned int signal)
 {
 	FPU_EIP = FPU_ORIG_EIP;
-	current->tss.trap_no = 16;
-	current->tss.error_code = 0;
+	current->thread.trap_no = 16;
+	current->thread.error_code = 0;
 	send_sig(signal,current,1);
 	RE_ENTRANT_CHECK_OFF;
 	__asm__("movl %0,%%esp ; ret": :"g" (((long) info)-4));
diff -u --recursive --new-file v2.3.11/linux/arch/i386/math-emu/fpu_system.h linux/arch/i386/math-emu/fpu_system.h
--- v2.3.11/linux/arch/i386/math-emu/fpu_system.h	Sun Sep 13 12:58:04 1998
+++ linux/arch/i386/math-emu/fpu_system.h	Fri Jul 23 13:19:02 1999
@@ -33,7 +33,7 @@
 #define SEG_EXPAND_DOWN(s)	(((s).b & ((1 << 11) | (1 << 10))) \
 				 == (1 << 10))
 
-#define I387			(current->tss.i387)
+#define I387			(current->thread.i387)
 #define FPU_info		(I387.soft.info)
 
 #define FPU_CS			(*(unsigned short *) &(FPU_info->___cs))
diff -u --recursive --new-file v2.3.11/linux/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c
--- v2.3.11/linux/arch/i386/mm/fault.c	Wed Jul 21 15:46:48 1999
+++ linux/arch/i386/mm/fault.c	Wed Jul 28 10:45:39 1999
@@ -245,9 +245,6 @@
 	printk(" at virtual address %08lx\n",address);
 	printk(" printing eip:\n");
 	printk("%08lx\n", regs->eip);
-	__asm__("movl %%cr3,%0" : "=r" (page));
-	printk(KERN_ALERT "current->thread.cr3 = %08lx, %%cr3 = %08lx\n",
-		tsk->thread.cr3, page);
 	page = ((unsigned long *) __va(page))[address >> 22];
 	printk(KERN_ALERT "*pde = %08lx\n", page);
 	if (page & 1) {
diff -u --recursive --new-file v2.3.11/linux/arch/m68k/atari/stram.c linux/arch/m68k/atari/stram.c
--- v2.3.11/linux/arch/m68k/atari/stram.c	Wed Nov 11 11:50:00 1998
+++ linux/arch/m68k/atari/stram.c	Fri Jul 23 12:20:23 1999
@@ -805,7 +805,7 @@
 	/*
 	 * Go through process' page directory.
 	 */
-	if (!mm || mm == &init_mm)
+	if (!mm)
 		return;
 	for (vma = mm->mmap; vma; vma = vma->vm_next) {
 		pgd_t * pgd = pgd_offset(mm, vma->vm_start);
diff -u --recursive --new-file v2.3.11/linux/arch/m68k/kernel/process.c linux/arch/m68k/kernel/process.c
--- v2.3.11/linux/arch/m68k/kernel/process.c	Tue May 11 09:57:14 1999
+++ linux/arch/m68k/kernel/process.c	Mon Jul 26 22:41:09 1999
@@ -40,10 +40,9 @@
  */
 static struct vm_area_struct init_mmap = INIT_MMAP;
 static struct fs_struct init_fs = INIT_FS;
-static struct file * init_fd_array[NR_OPEN] = { NULL, };
 static struct files_struct init_files = INIT_FILES;
 static struct signal_struct init_signals = INIT_SIGNALS;
-struct mm_struct init_mm = INIT_MM;
+struct mm_struct init_mm = INIT_MM(init_mm);
 
 union task_union init_task_union
 	__attribute__((section("init_task"), aligned(2*PAGE_SIZE)))
diff -u --recursive --new-file v2.3.11/linux/arch/m68k/kernel/setup.c linux/arch/m68k/kernel/setup.c
--- v2.3.11/linux/arch/m68k/kernel/setup.c	Tue May 11 09:57:14 1999
+++ linux/arch/m68k/kernel/setup.c	Fri Jul 23 12:20:23 1999
@@ -213,10 +213,10 @@
 		asm __volatile__ ("frestore %0" : : "m" (zero));
 	}
 
-	init_task.mm->start_code = PAGE_OFFSET;
-	init_task.mm->end_code = (unsigned long) &_etext;
-	init_task.mm->end_data = (unsigned long) &_edata;
-	init_task.mm->brk = (unsigned long) &_end;
+	init_mm.start_code = PAGE_OFFSET;
+	init_mm.end_code = (unsigned long) &_etext;
+	init_mm.end_data = (unsigned long) &_edata;
+	init_mm.brk = (unsigned long) &_end;
 
 	*cmdline_p = m68k_command_line;
 	memcpy(saved_command_line, *cmdline_p, CL_SIZE);
diff -u --recursive --new-file v2.3.11/linux/arch/m68k/kernel/signal.c linux/arch/m68k/kernel/signal.c
--- v2.3.11/linux/arch/m68k/kernel/signal.c	Thu Jan  7 08:41:55 1999
+++ linux/arch/m68k/kernel/signal.c	Thu Jul 22 09:47:55 1999
@@ -1084,9 +1084,7 @@
 
 			case SIGQUIT: case SIGILL: case SIGTRAP:
 			case SIGIOT: case SIGFPE: case SIGSEGV:
-				if (current->binfmt
-				    && current->binfmt->core_dump
-				    && current->binfmt->core_dump(signr, regs))
+				if (do_coredump(signr, regs))
 					exit_code |= 0x80;
 				/* FALLTHRU */
 
diff -u --recursive --new-file v2.3.11/linux/arch/m68k/mm/fault.c linux/arch/m68k/mm/fault.c
--- v2.3.11/linux/arch/m68k/mm/fault.c	Thu Dec 17 09:06:30 1998
+++ linux/arch/m68k/mm/fault.c	Fri Jul 23 12:20:23 1999
@@ -49,7 +49,7 @@
 	 * If we're in an interrupt or have no user
 	 * context, we must not take the fault..
 	 */
-	if (in_interrupt() || mm == &init_mm)
+	if (in_interrupt() || !mm)
 		goto no_context;
 
 	down(&mm->mmap_sem);
diff -u --recursive --new-file v2.3.11/linux/arch/mips/config.in linux/arch/mips/config.in
--- v2.3.11/linux/arch/mips/config.in	Thu Jul  8 15:42:19 1999
+++ linux/arch/mips/config.in	Sat Jul 24 16:46:46 1999
@@ -93,7 +93,7 @@
 bool 'Sysctl support' CONFIG_SYSCTL
 
 if [ "$CONFIG_SGI" != "y" -a "$CONFIG_DECSTATION" != "y" -a "$CONFIG_BAGET_MIPS" != "y" ]; then
-source drivers/misc/Config.in
+source drivers/parport/Config.in
 fi
 endmenu
 
diff -u --recursive --new-file v2.3.11/linux/arch/mips/kernel/init_task.c linux/arch/mips/kernel/init_task.c
--- v2.3.11/linux/arch/mips/kernel/init_task.c	Wed Jun 30 13:38:18 1999
+++ linux/arch/mips/kernel/init_task.c	Mon Jul 26 22:41:09 1999
@@ -6,7 +6,6 @@
 
 static struct vm_area_struct init_mmap = INIT_MMAP;
 static struct fs_struct init_fs = INIT_FS;
-static struct files * init_fd_array[NR_OPEN] = { NULL, };
 static struct files_struct init_files = INIT_FILES;
 static struct signal_struct init_signals = INIT_SIGNALS;
 struct mm_struct init_mm = INIT_MM(init_mm);
diff -u --recursive --new-file v2.3.11/linux/arch/mips/kernel/irixelf.c linux/arch/mips/kernel/irixelf.c
--- v2.3.11/linux/arch/mips/kernel/irixelf.c	Wed Jul 21 15:46:48 1999
+++ linux/arch/mips/kernel/irixelf.c	Sun Jul 25 13:45:25 1999
@@ -48,11 +48,13 @@
 extern int dump_fpu (elf_fpregset_t *);
 
 static struct linux_binfmt irix_format = {
+	NULL,
 #ifndef MODULE
-	NULL, NULL, load_irix_binary, load_irix_library, irix_core_dump
+	NULL,
 #else
-	NULL, &__this_module.usecount, load_irix_binary, load_irix_library, irix_core_dump
+	&__this_module.usecount,
 #endif
+	load_irix_binary, load_irix_library, irix_core_dump, PAGE_SIZE
 };
 
 #ifndef elf_addr_t
@@ -1105,24 +1107,20 @@
 
 #define DUMP_WRITE(addr, nr)	\
 	if (!dump_write(file, (addr), (nr))) \
-		goto close_coredump;
+		goto end_coredump;
 #define DUMP_SEEK(off)	\
 	if (!dump_seek(file, (off))) \
-		goto close_coredump;
+		goto end_coredump;
 /* Actual dumper.
  *
  * This is a two-pass process; first we find the offsets of the bits,
  * and then they are actually written out.  If we run out of core limit
  * we just truncate.
  */
-static int irix_core_dump(long signr, struct pt_regs * regs)
+static int irix_core_dump(long signr, struct pt_regs * regs, struct file *file)
 {
 	int has_dumped = 0;
-	struct file *file;
-	struct dentry *dentry;
-	struct inode *inode;
 	mm_segment_t fs;
-	char corefile[6+sizeof(current->comm)];
 	int segs;
 	int i;
 	size_t size;
@@ -1135,10 +1133,6 @@
 	struct elf_prstatus prstatus;	/* NT_PRSTATUS */
 	elf_fpregset_t fpu;		/* NT_PRFPREG */
 	struct elf_prpsinfo psinfo;	/* NT_PRPSINFO */
-	
-	if (!current->dumpable || limit < PAGE_SIZE)
-		return 0;
-	current->dumpable = 0;
 
 #ifndef CONFIG_BINFMT_IRIX
 	MOD_INC_USE_COUNT;
@@ -1188,27 +1182,6 @@
 	fs = get_fs();
 	set_fs(KERNEL_DS);
 
-	memcpy(corefile,"core.", 5);
-#if 0
-	memcpy(corefile+5,current->comm,sizeof(current->comm));
-#else
-	corefile[4] = '\0';
-#endif
-	file = filp_open(corefile, O_CREAT | 2 | O_TRUNC | O_NOFOLLOW, 0600);
-	if (IS_ERR(file))
-		goto end_coredump;
-	dentry = file->f_dentry;
-	inode = dentry->d_inode;
-	if (inode->i_nlink > 1)
-		goto close_coredump;	/* multiple links - don't dump */
-
-	if (!S_ISREG(inode->i_mode))
-		goto close_coredump;
-	if (!inode->i_op || !inode->i_op->default_file_ops)
-		goto close_coredump;
-	if (!file->f_op->write)
-		goto close_coredump;
-
 	has_dumped = 1;
 	current->flags |= PF_DUMPCORE;
 
@@ -1345,7 +1318,7 @@
 
 	for(i = 0; i < numnote; i++)
 		if (!writenote(&notes[i], file))
-			goto close_coredump;
+			goto end_coredump;
 	
 	set_fs(fs);
 
@@ -1371,9 +1344,6 @@
 		printk("elf_core_dump: file->f_pos (%ld) != offset (%ld)\n",
 		       (off_t) file->f_pos, offset);
 	}
-
- close_coredump:
-	filp_close(file, NULL);
 
  end_coredump:
 	set_fs(fs);
diff -u --recursive --new-file v2.3.11/linux/arch/mips/kernel/irixsig.c linux/arch/mips/kernel/irixsig.c
--- v2.3.11/linux/arch/mips/kernel/irixsig.c	Wed Jun 30 13:38:18 1999
+++ linux/arch/mips/kernel/irixsig.c	Thu Jul 22 09:47:55 1999
@@ -261,12 +261,8 @@
 
 			case SIGQUIT: case SIGILL: case SIGTRAP:
 			case SIGABRT: case SIGFPE: case SIGSEGV:
-				lock_kernel();
-				if (current->binfmt
-				    && current->binfmt->core_dump
-				    && current->binfmt->core_dump(signr, regs))
+				if (do_coredump(signr, regs))
 					exit_code |= 0x80;
-				unlock_kernel();
 				/* FALLTHRU */
 
 			default:
diff -u --recursive --new-file v2.3.11/linux/arch/mips/kernel/signal.c linux/arch/mips/kernel/signal.c
--- v2.3.11/linux/arch/mips/kernel/signal.c	Wed Jun 30 13:38:18 1999
+++ linux/arch/mips/kernel/signal.c	Thu Jul 22 09:47:55 1999
@@ -493,12 +493,8 @@
 			case SIGQUIT: case SIGILL: case SIGTRAP:
 			case SIGABRT: case SIGFPE: case SIGSEGV:
 			case SIGBUS:
-				lock_kernel();
-				if (current->binfmt
-				    && current->binfmt->core_dump
-				    && current->binfmt->core_dump(signr, regs))
+				if (do_coredump(signr, regs))
 					exit_code |= 0x80;
-				unlock_kernel();
 				/* FALLTHRU */
 
 			default:
diff -u --recursive --new-file v2.3.11/linux/arch/mips/mm/fault.c linux/arch/mips/mm/fault.c
--- v2.3.11/linux/arch/mips/mm/fault.c	Thu Jul  8 15:42:19 1999
+++ linux/arch/mips/mm/fault.c	Fri Jul 23 12:20:23 1999
@@ -55,7 +55,7 @@
 	 * If we're in an interrupt or have no user
 	 * context, we must not take the fault..
 	 */
-	if (in_interrupt() || mm == &init_mm)
+	if (in_interrupt() || !mm)
 		goto no_context;
 #if 0
 	printk("[%s:%d:%08lx:%ld:%08lx]\n", current->comm, current->pid,
diff -u --recursive --new-file v2.3.11/linux/arch/ppc/config.in linux/arch/ppc/config.in
--- v2.3.11/linux/arch/ppc/config.in	Wed Jul 21 15:46:48 1999
+++ linux/arch/ppc/config.in	Sat Jul 24 16:46:46 1999
@@ -66,7 +66,7 @@
 define_bool CONFIG_KERNEL_ELF y
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 
-source drivers/misc/Config.in
+source drivers/parport/Config.in
 
 bool 'Support for VGA Console' CONFIG_VGA_CONSOLE
 bool 'Support for frame buffer devices' CONFIG_FB
diff -u --recursive --new-file v2.3.11/linux/arch/ppc/kernel/apus_setup.c linux/arch/ppc/kernel/apus_setup.c
--- v2.3.11/linux/arch/ppc/kernel/apus_setup.c	Thu May 13 11:00:08 1999
+++ linux/arch/ppc/kernel/apus_setup.c	Fri Jul 23 12:20:23 1999
@@ -345,7 +345,7 @@
 	{
 		pte_t *pte;
 
-		pte = my_find_pte(init_task.mm, address);
+		pte = my_find_pte(&init_mm, address);
 		if ( !pte )
 		{
 			printk("pte NULL in kernel_set_cachemode()\n");
@@ -354,7 +354,7 @@
 
                 pte_val (*pte) &= mask;
                 pte_val (*pte) |= flags;
-                flush_tlb_page(find_vma(init_task.mm,address),address);
+                flush_tlb_page(find_vma(&init_mm,address),address);
 
 		address += PAGE_SIZE;
 	}
diff -u --recursive --new-file v2.3.11/linux/arch/ppc/kernel/idle.c linux/arch/ppc/kernel/idle.c
--- v2.3.11/linux/arch/ppc/kernel/idle.c	Wed Jun 30 13:38:19 1999
+++ linux/arch/ppc/kernel/idle.c	Fri Jul 23 12:20:23 1999
@@ -227,7 +227,7 @@
 		/*
 		 * Make the page no cache so we don't blow our cache with 0's
 		 */
-		pte = find_pte(init_task.mm, pageptr);
+		pte = find_pte(&init_mm, pageptr);
 		if ( !pte )
 		{
 			printk("pte NULL in zero_paged()\n");
@@ -235,7 +235,7 @@
 		}
 		
 		pte_uncache(*pte);
-		flush_tlb_page(find_vma(init_task.mm,pageptr),pageptr);
+		flush_tlb_page(find_vma(&init_mm,pageptr),pageptr);
 		/*
 		 * Important here to not take time away from real processes.
 		 */
@@ -260,7 +260,7 @@
 		
 		/* turn cache on for this page */
 		pte_cache(*pte);
-		flush_tlb_page(find_vma(init_task.mm,pageptr),pageptr);
+		flush_tlb_page(find_vma(&init_mm,pageptr),pageptr);
 		/* atomically add this page to the list */
 		asm (	"101:lwarx  %0,0,%1\n"  /* reserve zero_cache */
 			"    stw    %0,0(%2)\n" /* update *pageptr */
diff -u --recursive --new-file v2.3.11/linux/arch/ppc/kernel/process.c linux/arch/ppc/kernel/process.c
--- v2.3.11/linux/arch/ppc/kernel/process.c	Wed Jul 21 15:46:48 1999
+++ linux/arch/ppc/kernel/process.c	Mon Jul 26 22:41:09 1999
@@ -47,7 +47,6 @@
 struct task_struct *last_task_used_math = NULL;
 static struct vm_area_struct init_mmap = INIT_MMAP;
 static struct fs_struct init_fs = INIT_FS;
-static struct file * init_fd_array[NR_OPEN] = { NULL, };
 static struct files_struct init_files = INIT_FILES;
 static struct signal_struct init_signals = INIT_SIGNALS;
 struct mm_struct init_mm = INIT_MM(init_mm);
diff -u --recursive --new-file v2.3.11/linux/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c
--- v2.3.11/linux/arch/ppc/kernel/setup.c	Wed Jul 21 15:46:48 1999
+++ linux/arch/ppc/kernel/setup.c	Fri Jul 23 12:20:23 1999
@@ -527,10 +527,10 @@
 	/* reboot on panic */	
 	panic_timeout = 180;
 	
-	init_task.mm->start_code = PAGE_OFFSET;
-	init_task.mm->end_code = (unsigned long) _etext;
-	init_task.mm->end_data = (unsigned long) _edata;
-	init_task.mm->brk = (unsigned long) klimit;	
+	init_mm.start_code = PAGE_OFFSET;
+	init_mm.end_code = (unsigned long) _etext;
+	init_mm.end_data = (unsigned long) _edata;
+	init_mm.brk = (unsigned long) klimit;	
 
 	/* Save unparsed command line copy for /proc/cmdline */
 	strcpy(saved_command_line, cmd_line);
diff -u --recursive --new-file v2.3.11/linux/arch/ppc/kernel/signal.c linux/arch/ppc/kernel/signal.c
--- v2.3.11/linux/arch/ppc/kernel/signal.c	Wed Jun 30 13:38:19 1999
+++ linux/arch/ppc/kernel/signal.c	Thu Jul 22 09:47:55 1999
@@ -444,12 +444,8 @@
 
 			case SIGQUIT: case SIGILL: case SIGTRAP:
 			case SIGABRT: case SIGFPE: case SIGSEGV:
-				lock_kernel();
-				if (current->binfmt
-				    && current->binfmt->core_dump
-				    && current->binfmt->core_dump(signr, regs))
+				if (do_coredump(signr, regs))
 					exit_code |= 0x80;
-				unlock_kernel();
 				/* FALLTHRU */
 
 			default:
diff -u --recursive --new-file v2.3.11/linux/arch/ppc/kernel/smp.c linux/arch/ppc/kernel/smp.c
--- v2.3.11/linux/arch/ppc/kernel/smp.c	Wed Jul 21 15:46:48 1999
+++ linux/arch/ppc/kernel/smp.c	Fri Jul 23 12:20:23 1999
@@ -403,7 +403,7 @@
 #if 0
 	current->mm->mmap->vm_page_prot = PAGE_SHARED;
 	current->mm->mmap->vm_start = PAGE_OFFSET;
-	current->mm->mmap->vm_end = init_task.mm->mmap->vm_end;
+	current->mm->mmap->vm_end = init_mm.mmap->vm_end;
 #endif
 	cpu_callin_map[current->processor] = 1;
 	while(!smp_commenced)
diff -u --recursive --new-file v2.3.11/linux/arch/ppc/mm/fault.c linux/arch/ppc/mm/fault.c
--- v2.3.11/linux/arch/ppc/mm/fault.c	Sat May 22 13:03:00 1999
+++ linux/arch/ppc/mm/fault.c	Fri Jul 23 12:20:23 1999
@@ -82,7 +82,7 @@
 			return;
 	}
 #endif
-	if (in_interrupt()) {
+	if (in_interrupt() || !mm) {
 		static int complained;
 		if (complained < 20) {
 			++complained;
diff -u --recursive --new-file v2.3.11/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c
--- v2.3.11/linux/arch/ppc/mm/init.c	Wed Jul 21 15:46:48 1999
+++ linux/arch/ppc/mm/init.c	Sun Jul 25 13:45:25 1999
@@ -444,11 +444,11 @@
 #endif /* CONFIG_APUS */
 #endif /* CONFIG_8xx */
 	/* Do we have a page table? */
-	if (init_task.mm->pgd == NULL)
+	if (init_mm.pgd == NULL)
 		return 0;
 
 	/* Use upper 10 bits of addr to index the first level map */
-	pd = (pmd_t *) (init_task.mm->pgd + (addr >> PGDIR_SHIFT));
+	pd = (pmd_t *) (init_mm.pgd + (addr >> PGDIR_SHIFT));
 	if (pmd_none(*pd))
 		return 0;
 
diff -u --recursive --new-file v2.3.11/linux/arch/sparc/ap1000/apmmu.c linux/arch/sparc/ap1000/apmmu.c
--- v2.3.11/linux/arch/sparc/ap1000/apmmu.c	Tue Apr 14 17:44:18 1998
+++ linux/arch/sparc/ap1000/apmmu.c	Fri Jul 23 12:20:23 1999
@@ -295,7 +295,7 @@
 
 static inline void apmmu_uncache_page(unsigned long addr)
 {
-	pgd_t *pgdp = apmmu_pgd_offset(init_task.mm, addr);
+	pgd_t *pgdp = apmmu_pgd_offset(&init_mm, addr);
 	pmd_t *pmdp;
 	pte_t *ptep;
 
@@ -316,7 +316,7 @@
 
 static inline void apmmu_recache_page(unsigned long addr)
 {
-	pgd_t *pgdp = apmmu_pgd_offset(init_task.mm, addr);
+	pgd_t *pgdp = apmmu_pgd_offset(&init_mm, addr);
 	pmd_t *pmdp;
 	pte_t *ptep;
 
@@ -782,7 +782,7 @@
 	pte_t *ptep;
 
 	while(start < end) {
-		pgdp = apmmu_pgd_offset(init_task.mm, start);
+		pgdp = apmmu_pgd_offset(&init_mm, start);
 		if(apmmu_pgd_none(*pgdp)) {
 			pmdp = sparc_init_alloc(&mempool, APMMU_PMD_TABLE_SIZE);
 			apmmu_early_pgd_set(pgdp, pmdp);
@@ -804,7 +804,7 @@
 	pte_t *ptep;
 	unsigned start = virt_page<<12;
 
-	pgdp = apmmu_pgd_offset(init_task.mm, start);
+	pgdp = apmmu_pgd_offset(&init_mm, start);
 	if(apmmu_pgd_none(*pgdp)) {
 		pmdp = sparc_init_alloc(&mempool, APMMU_PMD_TABLE_SIZE);
 		apmmu_early_pgd_set(pgdp, pmdp);
@@ -824,7 +824,7 @@
 	pgd_t *pgdp;
 	unsigned start = virt_page<<12;
 
-	pgdp = apmmu_pgd_offset(init_task.mm, start);
+	pgdp = apmmu_pgd_offset(&init_mm, start);
 	*pgdp = __pgd((phys_page<<8) | prot);
 }
 
@@ -907,7 +907,7 @@
 		make_large_page((KERNBASE+phys)>>12,
 				(phys>>12),
 				APMMU_CACHE|APMMU_PRIV|APMMU_VALID);
-	init_task.mm->mmap->vm_start = page_offset = KERNBASE;
+	init_mm.mmap->vm_start = page_offset = KERNBASE;
 	stack_top = page_offset - PAGE_SIZE;
 }
 
diff -u --recursive --new-file v2.3.11/linux/arch/sparc/kernel/init_task.c linux/arch/sparc/kernel/init_task.c
--- v2.3.11/linux/arch/sparc/kernel/init_task.c	Wed May 12 08:41:12 1999
+++ linux/arch/sparc/kernel/init_task.c	Mon Jul 26 22:41:09 1999
@@ -6,7 +6,6 @@
 
 static struct vm_area_struct init_mmap = INIT_MMAP;
 static struct fs_struct init_fs = INIT_FS;
-static struct file * init_fd_array[NR_OPEN] = { NULL, };
 static struct files_struct init_files = INIT_FILES;
 static struct signal_struct init_signals = INIT_SIGNALS;
 struct mm_struct init_mm = INIT_MM(init_mm);
diff -u --recursive --new-file v2.3.11/linux/arch/sparc/kernel/setup.c linux/arch/sparc/kernel/setup.c
--- v2.3.11/linux/arch/sparc/kernel/setup.c	Wed Jun  9 14:44:25 1999
+++ linux/arch/sparc/kernel/setup.c	Fri Jul 23 12:20:23 1999
@@ -489,10 +489,10 @@
 
 
 	/* Due to stack alignment restrictions and assumptions... */
-	init_task.mm->mmap->vm_page_prot = PAGE_SHARED;
-	init_task.mm->mmap->vm_start = KERNBASE;
-	init_task.mm->mmap->vm_end = *memory_end_p;
-	init_task.mm->context = (unsigned long) NO_CONTEXT;
+	init_mm.mmap->vm_page_prot = PAGE_SHARED;
+	init_mm.mmap->vm_start = KERNBASE;
+	init_mm.mmap->vm_end = *memory_end_p;
+	init_mm.context = (unsigned long) NO_CONTEXT;
 	init_task.tss.kregs = &fake_swapper_regs;
 
 	if (serial_console)
diff -u --recursive --new-file v2.3.11/linux/arch/sparc/kernel/signal.c linux/arch/sparc/kernel/signal.c
--- v2.3.11/linux/arch/sparc/kernel/signal.c	Thu Jun 17 01:08:50 1999
+++ linux/arch/sparc/kernel/signal.c	Thu Jul 22 09:47:55 1999
@@ -1160,14 +1160,8 @@
 
 			case SIGQUIT: case SIGILL: case SIGTRAP:
 			case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS:
-				if(current->binfmt && current->binfmt->core_dump) {
-					lock_kernel();
-					if(current->binfmt &&
-					   current->binfmt->core_dump &&
-					   current->binfmt->core_dump(signr, regs))
-						exit_code |= 0x80;
-					unlock_kernel();
-				}
+				if (do_coredump(signr, regs))
+					exit_code |= 0x80;
 #ifdef DEBUG_SIGNALS
 				/* Very useful to debug dynamic linker problems */
 				printk ("Sig %ld going for %s[%d]...\n", signr, current->comm, current->pid);
diff -u --recursive --new-file v2.3.11/linux/arch/sparc/kernel/sun4d_smp.c linux/arch/sparc/kernel/sun4d_smp.c
--- v2.3.11/linux/arch/sparc/kernel/sun4d_smp.c	Thu Jul  8 15:42:19 1999
+++ linux/arch/sparc/kernel/sun4d_smp.c	Fri Jul 23 12:20:23 1999
@@ -131,7 +131,7 @@
 	
 	current->mm->mmap->vm_page_prot = PAGE_SHARED;
 	current->mm->mmap->vm_start = PAGE_OFFSET;
-	current->mm->mmap->vm_end = init_task.mm->mmap->vm_end;
+	current->mm->mmap->vm_end = init_mm.mmap->vm_end;
 	
 	local_flush_cache_all();
 	local_flush_tlb_all();
diff -u --recursive --new-file v2.3.11/linux/arch/sparc/kernel/sun4m_smp.c linux/arch/sparc/kernel/sun4m_smp.c
--- v2.3.11/linux/arch/sparc/kernel/sun4m_smp.c	Thu Jul  8 15:42:19 1999
+++ linux/arch/sparc/kernel/sun4m_smp.c	Fri Jul 23 12:20:23 1999
@@ -109,7 +109,7 @@
 			     : "memory" /* paranoid */);
 	current->mm->mmap->vm_page_prot = PAGE_SHARED;
 	current->mm->mmap->vm_start = PAGE_OFFSET;
-	current->mm->mmap->vm_end = init_task.mm->mmap->vm_end;
+	current->mm->mmap->vm_end = init_mm.mmap->vm_end;
 	
 	while(!smp_commenced)
 		barrier();
diff -u --recursive --new-file v2.3.11/linux/arch/sparc/mm/fault.c linux/arch/sparc/mm/fault.c
--- v2.3.11/linux/arch/sparc/mm/fault.c	Thu Jul  8 15:42:19 1999
+++ linux/arch/sparc/mm/fault.c	Fri Jul 23 12:20:23 1999
@@ -205,7 +205,7 @@
 	 * If we're in an interrupt or have no user
 	 * context, we must not take the fault..
 	 */
-        if (in_interrupt() || mm == &init_mm)
+        if (in_interrupt() || !mm)
                 goto do_kernel_fault;
 
 	down(&mm->mmap_sem);
diff -u --recursive --new-file v2.3.11/linux/arch/sparc/mm/srmmu.c linux/arch/sparc/mm/srmmu.c
--- v2.3.11/linux/arch/sparc/mm/srmmu.c	Thu Jul  8 15:42:19 1999
+++ linux/arch/sparc/mm/srmmu.c	Sun Jul 25 13:45:25 1999
@@ -846,7 +846,7 @@
 	unsigned long tmp;
 
 	physaddr &= PAGE_MASK;
-	pgdp = srmmu_pgd_offset(init_task.mm, virt_addr);
+	pgdp = srmmu_pgd_offset(&init_mm, virt_addr);
 	pmdp = pmd_offset(pgdp, virt_addr);
 	ptep = pte_offset(pmdp, virt_addr);
 	tmp = (physaddr >> 4) | SRMMU_ET_PTE;
@@ -871,7 +871,7 @@
 	pmd_t *pmdp;
 	pte_t *ptep;
 
-	pgdp = srmmu_pgd_offset(init_task.mm, virt_addr);
+	pgdp = srmmu_pgd_offset(&init_mm, virt_addr);
 	pmdp = pmd_offset(pgdp, virt_addr);
 	ptep = pte_offset(pmdp, virt_addr);
 
@@ -1476,7 +1476,7 @@
 	pte_t *ptep;
 
 	while(start < end) {
-		pgdp = srmmu_pgd_offset(init_task.mm, start);
+		pgdp = srmmu_pgd_offset(&init_mm, start);
 		if(srmmu_pgd_none(*pgdp)) {
 			pmdp = sparc_init_alloc(&mempool, SRMMU_PMD_TABLE_SIZE);
 			srmmu_early_pgd_set(pgdp, pmdp);
@@ -1526,7 +1526,7 @@
 				what = 2;
 		}
     
-		pgdp = srmmu_pgd_offset(init_task.mm, start);
+		pgdp = srmmu_pgd_offset(&init_mm, start);
 		if(what == 2) {
 			*pgdp = __pgd(prompte);
 			start += SRMMU_PGDIR_SIZE;
@@ -1626,7 +1626,7 @@
 /* Create a third-level SRMMU 16MB page mapping. */
 __initfunc(static void do_large_mapping(unsigned long vaddr, unsigned long phys_base))
 {
-	pgd_t *pgdp = srmmu_pgd_offset(init_task.mm, vaddr);
+	pgd_t *pgdp = srmmu_pgd_offset(&init_mm, vaddr);
 	unsigned long big_pte;
 
 	MKTRACE(("dlm[v<%08lx>-->p<%08lx>]", vaddr, phys_base));
@@ -1840,7 +1840,7 @@
 		}
 	}
 	MKTRACE(("success\n"));
-	init_task.mm->mmap->vm_start = page_offset = low_base;
+	init_mm.mmap->vm_start = page_offset = low_base;
 	stack_top = page_offset - PAGE_SIZE;
 	BTFIXUPSET_SETHI(page_offset, low_base);
 	BTFIXUPSET_SETHI(stack_top, page_offset - PAGE_SIZE);
diff -u --recursive --new-file v2.3.11/linux/arch/sparc/mm/sun4c.c linux/arch/sparc/mm/sun4c.c
--- v2.3.11/linux/arch/sparc/mm/sun4c.c	Thu Jul  8 15:42:19 1999
+++ linux/arch/sparc/mm/sun4c.c	Sun Jul 25 13:45:25 1999
@@ -1560,7 +1560,7 @@
 	memset((void *) start_mem, 0, bitmap_size);
 	start_mem += bitmap_size;
 
-	sun4c_kstack_vma.vm_mm = init_task.mm;
+	sun4c_kstack_vma.vm_mm = &init_mm;
 	sun4c_kstack_vma.vm_start = sun4c_taskstack_start;
 	sun4c_kstack_vma.vm_end = sun4c_taskstack_end;
 	sun4c_kstack_vma.vm_page_prot = PAGE_SHARED;
diff -u --recursive --new-file v2.3.11/linux/arch/sparc64/config.in linux/arch/sparc64/config.in
--- v2.3.11/linux/arch/sparc64/config.in	Thu Jul  8 15:42:19 1999
+++ linux/arch/sparc64/config.in	Sat Jul 24 16:46:46 1999
@@ -68,7 +68,7 @@
 fi
 
 if [ "$CONFIG_PCI" = "y" ]; then
-  source drivers/misc/Config.in
+  source drivers/parport/Config.in
   dep_tristate '  Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT
   tristate 'SUNW,envctrl support' CONFIG_ENVCTRL
 fi
diff -u --recursive --new-file v2.3.11/linux/arch/sparc64/kernel/binfmt_aout32.c linux/arch/sparc64/kernel/binfmt_aout32.c
--- v2.3.11/linux/arch/sparc64/kernel/binfmt_aout32.c	Thu Jul  8 15:42:19 1999
+++ linux/arch/sparc64/kernel/binfmt_aout32.c	Sun Jul 25 13:45:25 1999
@@ -39,7 +39,8 @@
 extern void dump_thread(struct pt_regs *, struct user *);
 
 static struct linux_binfmt aout32_format = {
-	NULL, NULL, load_aout32_binary, load_aout32_library, aout32_core_dump
+	NULL, NULL, load_aout32_binary, load_aout32_library, aout32_core_dump,
+	PAGE_SIZE
 };
 
 static void set_brk(unsigned long start, unsigned long end)
@@ -63,12 +64,12 @@
 
 #define DUMP_WRITE(addr, nr)	\
 	if (!dump_write(file, (void *)(addr), (nr))) \
-		goto close_coredump;
+		goto end_coredump;
 
 #define DUMP_SEEK(offset) \
 if (file->f_op->llseek) { \
 	if (file->f_op->llseek(file,(offset),0) != (offset)) \
- 		goto close_coredump; \
+ 		goto end_coredump; \
 } else file->f_pos = (offset)
 
 /*
@@ -82,45 +83,17 @@
  */
 
 static inline int
-do_aout32_core_dump(long signr, struct pt_regs * regs)
+do_aout32_core_dump(long signr, struct pt_regs * regs, struct file *file)
 {
-	struct dentry * dentry = NULL;
-	struct inode * inode = NULL;
-	struct file * file;
 	mm_segment_t fs;
 	int has_dumped = 0;
-	char corefile[6+sizeof(current->comm)];
 	unsigned long dump_start, dump_size;
 	struct user dump;
 #       define START_DATA(u)    (u.u_tsize)
 #       define START_STACK(u)   ((regs->u_regs[UREG_FP]) & ~(PAGE_SIZE - 1))
 
-	if (!current->dumpable || atomic_read(&current->mm->count) != 1)
-		return 0;
-	current->dumpable = 0;
-
-/* See if we have enough room to write the upage.  */
-	if (current->rlim[RLIMIT_CORE].rlim_cur < PAGE_SIZE)
-		return 0;
 	fs = get_fs();
 	set_fs(KERNEL_DS);
-	memcpy(corefile,"core.",5);
-#if 0
-	memcpy(corefile+5,current->comm,sizeof(current->comm));
-#else
-	corefile[4] = '\0';
-#endif
-	file = filp_open(corefile,O_CREAT | 2 | O_TRUNC | O_NOFOLLOW, 0600);
-	if (IS_ERR(file))
-		goto end_coredump;
-	dentry = file->f_dentry;
-	inode = dentry->d_inode;
-	if (!S_ISREG(inode->i_mode))
-		goto close_coredump;
-	if (!inode->i_op || !inode->i_op->default_file_ops)
-		goto close_coredump;
-	if (!file->f_op->write)
-		goto close_coredump;
 	has_dumped = 1;
 	current->flags |= PF_DUMPCORE;
        	strncpy(dump.u_comm, current->comm, sizeof(current->comm));
@@ -165,20 +138,18 @@
 /* Finally dump the task struct.  Not be used by gdb, but could be useful */
 	set_fs(KERNEL_DS);
 	DUMP_WRITE(current,sizeof(*current));
-close_coredump:
-	filp_close(file, NULL);
 end_coredump:
 	set_fs(fs);
 	return has_dumped;
 }
 
 static int
-aout32_core_dump(long signr, struct pt_regs * regs)
+aout32_core_dump(long signr, struct pt_regs * regs, struct file * file)
 {
 	int retval;
 
 	MOD_INC_USE_COUNT;
-	retval = do_aout32_core_dump(signr, regs);
+	retval = do_aout32_core_dump(signr, regs, file);
 	MOD_DEC_USE_COUNT;
 	return retval;
 }
diff -u --recursive --new-file v2.3.11/linux/arch/sparc64/kernel/init_task.c linux/arch/sparc64/kernel/init_task.c
--- v2.3.11/linux/arch/sparc64/kernel/init_task.c	Wed May 12 08:41:12 1999
+++ linux/arch/sparc64/kernel/init_task.c	Mon Jul 26 22:41:09 1999
@@ -6,7 +6,6 @@
 
 static struct vm_area_struct init_mmap = INIT_MMAP;
 static struct fs_struct init_fs = INIT_FS;
-static struct file * init_fd_array[NR_OPEN] = { NULL, };
 static struct files_struct init_files = INIT_FILES;
 static struct signal_struct init_signals = INIT_SIGNALS;
 struct mm_struct init_mm = INIT_MM(init_mm);
diff -u --recursive --new-file v2.3.11/linux/arch/sparc64/kernel/setup.c linux/arch/sparc64/kernel/setup.c
--- v2.3.11/linux/arch/sparc64/kernel/setup.c	Sat May 29 11:09:04 1999
+++ linux/arch/sparc64/kernel/setup.c	Fri Jul 23 12:20:23 1999
@@ -531,10 +531,10 @@
 #endif	
 
 	/* Due to stack alignment restrictions and assumptions... */
-	init_task.mm->mmap->vm_page_prot = PAGE_SHARED;
-	init_task.mm->mmap->vm_start = PAGE_OFFSET;
-	init_task.mm->mmap->vm_end = *memory_end_p;
-	init_task.mm->context = (unsigned long) NO_CONTEXT;
+	init_mm.mmap->vm_page_prot = PAGE_SHARED;
+	init_mm.mmap->vm_start = PAGE_OFFSET;
+	init_mm.mmap->vm_end = *memory_end_p;
+	init_mm.context = (unsigned long) NO_CONTEXT;
 	init_task.tss.kregs = &fake_swapper_regs;
 
 #ifdef CONFIG_IP_PNP
diff -u --recursive --new-file v2.3.11/linux/arch/sparc64/kernel/signal.c linux/arch/sparc64/kernel/signal.c
--- v2.3.11/linux/arch/sparc64/kernel/signal.c	Thu Jun 17 01:08:50 1999
+++ linux/arch/sparc64/kernel/signal.c	Thu Jul 22 09:47:55 1999
@@ -866,12 +866,8 @@
 
 			case SIGQUIT: case SIGILL: case SIGTRAP:
 			case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS:
-				if(current->binfmt && current->binfmt->core_dump) {
-					lock_kernel();
-					if(current->binfmt->core_dump(signr, regs))
-						exit_code |= 0x80;
-					unlock_kernel();
-				}
+				if (do_coredump(signr, regs))
+					exit_code |= 0x80;
 #ifdef DEBUG_SIGNALS
 				/* Very useful to debug the dynamic linker */
 				printk ("Sig %d going...\n", (int)signr);
diff -u --recursive --new-file v2.3.11/linux/arch/sparc64/kernel/signal32.c linux/arch/sparc64/kernel/signal32.c
--- v2.3.11/linux/arch/sparc64/kernel/signal32.c	Thu Jun 17 01:08:50 1999
+++ linux/arch/sparc64/kernel/signal32.c	Thu Jul 22 09:47:55 1999
@@ -1291,14 +1291,8 @@
 
 			case SIGQUIT: case SIGILL: case SIGTRAP:
 			case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS:
-				if(current->binfmt && current->binfmt->core_dump) {
-					lock_kernel();
-					if(current->binfmt &&
-					   current->binfmt->core_dump &&
-					   current->binfmt->core_dump(signr, regs))
-						exit_code |= 0x80;
-					unlock_kernel();
-				}
+				if (do_coredump(signr, regs))
+					exit_code |= 0x80;
 #ifdef DEBUG_SIGNALS
 				/* Very useful to debug dynamic linker problems */
 				printk ("Sig %ld going for %s[%d]...\n", signr, current->comm, current->pid);
diff -u --recursive --new-file v2.3.11/linux/arch/sparc64/mm/fault.c linux/arch/sparc64/mm/fault.c
--- v2.3.11/linux/arch/sparc64/mm/fault.c	Thu Jul  8 15:42:19 1999
+++ linux/arch/sparc64/mm/fault.c	Fri Jul 23 12:20:23 1999
@@ -154,7 +154,7 @@
 	 * If we're in an interrupt or have no user
 	 * context, we must not take the fault..
 	 */
-	if (in_interrupt() || mm == &init_mm)
+	if (in_interrupt() || !mm)
 		goto do_kernel_fault;
 
 	down(&mm->mmap_sem);
diff -u --recursive --new-file v2.3.11/linux/arch/sparc64/solaris/timod.c linux/arch/sparc64/solaris/timod.c
--- v2.3.11/linux/arch/sparc64/solaris/timod.c	Wed May 12 08:41:12 1999
+++ linux/arch/sparc64/solaris/timod.c	Mon Jul 26 22:41:09 1999
@@ -866,7 +866,7 @@
 
 	SOLD("entry");
 	lock_kernel();
-	if(fd >= NR_OPEN) goto out;
+	if(fd >= current->files->max_fds) goto out;
 
 	filp = current->files->fd[fd];
 	if(!filp) goto out;
@@ -933,7 +933,7 @@
 
 	SOLD("entry");
 	lock_kernel();
-	if(fd >= NR_OPEN) goto out;
+	if(fd >= current->files->max_fds) goto out;
 
 	filp = current->files->fd[fd];
 	if(!filp) goto out;
diff -u --recursive --new-file v2.3.11/linux/drivers/Makefile linux/drivers/Makefile
--- v2.3.11/linux/drivers/Makefile	Wed Jun 30 13:38:19 1999
+++ linux/drivers/Makefile	Sat Jul 24 16:46:46 1999
@@ -7,7 +7,7 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile.
 
-SUB_DIRS     := block char net misc sound
+SUB_DIRS     := block char net parport sound
 MOD_SUB_DIRS := $(SUB_DIRS)
 ALL_SUB_DIRS := $(SUB_DIRS) pci sgi scsi sbus cdrom isdn pnp i2o \
 				macintosh video dio zorro fc4 usb \
diff -u --recursive --new-file v2.3.11/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- v2.3.11/linux/drivers/block/ll_rw_blk.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/block/ll_rw_blk.c	Tue Jul 27 16:06:40 1999
@@ -403,7 +403,7 @@
 		unsigned long maxsector = (blk_size[major][MINOR(bh->b_rdev)] << 1) + 1;
 
 		if (maxsector < count || maxsector - count < sector) {
-			bh->b_state &= (1 << BH_Lock);
+			bh->b_state &= (1 << BH_Lock) | (1 << BH_Mapped);
                         /* This may well happen - the kernel calls bread()
                            without checking the size of the device, e.g.,
                            when mounting a device. */
@@ -428,6 +428,9 @@
 			kstat.pgpgin++;
 			max_req = NR_REQUEST;	/* reads take precedence */
 			break;
+		case WRITERAW:
+			rw = WRITE;
+			goto do_write;	/* Skip the buffer refile */
 		case WRITEA:
 			rw_ahead = 1;
 			rw = WRITE;	/* drop into WRITE */
@@ -435,6 +438,7 @@
 			if (!test_and_clear_bit(BH_Dirty, &bh->b_state))
 				goto end_io;	/* Hmmph! Nothing to write */
 			refile_buffer(bh);
+		do_write:
 			/*
 			 * We don't allow the write-requests to fill up the
 			 * queue completely:  we want some room for reads,
@@ -641,7 +645,7 @@
 #endif
 	}
 
-	if ((rw == WRITE || rw == WRITEA) && is_read_only(bh[0]->b_dev)) {
+	if ((rw & WRITE) && is_read_only(bh[0]->b_dev)) {
 		printk(KERN_NOTICE "Can't write to read-only device %s\n",
 		       kdevname(bh[0]->b_dev));
 		goto sorry;
diff -u --recursive --new-file v2.3.11/linux/drivers/char/Makefile linux/drivers/char/Makefile
--- v2.3.11/linux/drivers/char/Makefile	Thu Jul  8 15:42:20 1999
+++ linux/drivers/char/Makefile	Mon Jul 26 22:50:35 1999
@@ -20,7 +20,7 @@
 
 L_TARGET := char.a
 M_OBJS   :=
-L_OBJS   := tty_io.o n_tty.o tty_ioctl.o mem.o random.o
+L_OBJS   := tty_io.o n_tty.o tty_ioctl.o mem.o random.o raw.o
 LX_OBJS  := pty.o misc.o
 
 ifdef CONFIG_VT
diff -u --recursive --new-file v2.3.11/linux/drivers/char/mem.c linux/drivers/char/mem.c
--- v2.3.11/linux/drivers/char/mem.c	Fri May 14 18:15:02 1999
+++ linux/drivers/char/mem.c	Mon Jul 26 22:50:35 1999
@@ -16,6 +16,7 @@
 #include <linux/init.h>
 #include <linux/joystick.h>
 #include <linux/i2c.h>
+#include <linux/raw.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -602,6 +603,7 @@
 	if (register_chrdev(MEM_MAJOR,"mem",&memory_fops))
 		printk("unable to get major %d for memory devs\n", MEM_MAJOR);
 	rand_initialize();
+	raw_init();
 #ifdef CONFIG_USB
 	usb_init();
 #endif
diff -u --recursive --new-file v2.3.11/linux/drivers/char/ppdev.c linux/drivers/char/ppdev.c
--- v2.3.11/linux/drivers/char/ppdev.c	Wed Jul 21 15:46:48 1999
+++ linux/drivers/char/ppdev.c	Wed Jul 28 01:19:37 1999
@@ -11,7 +11,7 @@
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  *
- * A /dev/parportxy device node represents an arbitrary device ('y')
+ * A /dev/parportx device node represents an arbitrary device
  * on port 'x'.  The following operations are possible:
  *
  * open		do nothing, set up default IEEE 1284 protocol to be COMPAT
@@ -30,6 +30,8 @@
  *   RSTATUS	read_status
  *   NEGOT	parport_negotiate
  *   YIELD	parport_yield_blocking
+ *   WCTLONIRQ	on interrupt, set control lines
+ *   CLRIRQ	clear (and return) interrupt count
  * read/write	read or write in current IEEE 1284 protocol
  * select	wait for interrupt (in readfds)
  */
@@ -53,9 +55,13 @@
 struct pp_struct {
 	struct pardevice * pdev;
 	wait_queue_head_t irq_wait;
-	int got_irq;
+	atomic_t irqc;
 	int mode;
 	unsigned int flags;
+	int irqresponse;
+	unsigned char irqctl;
+	struct ieee1284_info state;
+	struct ieee1284_info saved_state;
 };
 
 /* pp_struct.flags bitfields */
@@ -85,8 +91,10 @@
 {
 	size_t (*fn) (struct parport *, void *, size_t, int);
 	struct parport *port = pp->pdev->port;
+	int addr = pp->mode & IEEE1284_ADDR;
+	int mode = pp->mode & ~(IEEE1284_DEVICEID | IEEE1284_ADDR);
 
-	switch (pp->mode) {
+	switch (mode) {
 	case IEEE1284_MODE_COMPAT:
 		/* This is a write-only mode. */
 		return -EIO;
@@ -100,7 +108,10 @@
 		break;
 
 	case IEEE1284_MODE_EPP:
-		fn = port->ops->epp_read_data;
+		if (addr)
+			fn = port->ops->epp_read_addr;
+		else
+			fn = port->ops->epp_read_data;
 		break;
 
 	case IEEE1284_MODE_ECP:
@@ -128,8 +139,10 @@
 {
 	size_t (*fn) (struct parport *, const void *, size_t, int);
 	struct parport *port = pp->pdev->port;
+	int addr = pp->mode & IEEE1284_ADDR;
+	int mode = pp->mode & ~(IEEE1284_DEVICEID | IEEE1284_ADDR);
 
-	switch (pp->mode) {
+	switch (mode) {
 	case IEEE1284_MODE_NIBBLE:
 	case IEEE1284_MODE_BYTE:
 		/* Read-only modes. */
@@ -140,16 +153,25 @@
 		break;
 
 	case IEEE1284_MODE_EPP:
-		fn = port->ops->epp_write_data;
+		if (addr)
+			fn = port->ops->epp_write_addr;
+		else
+			fn = port->ops->epp_write_data;
 		break;
 
 	case IEEE1284_MODE_ECP:
 	case IEEE1284_MODE_ECPRLE:
-		fn = port->ops->ecp_write_data;
+		if (addr)
+			fn = port->ops->ecp_write_addr;
+		else
+			fn = port->ops->ecp_write_data;
 		break;
 
 	case IEEE1284_MODE_ECPSWE:
-		fn = parport_ieee1284_ecp_write_data;
+		if (addr)
+			fn = parport_ieee1284_ecp_write_addr;
+		else
+			fn = parport_ieee1284_ecp_write_data;
 		break;
 
 	default:
@@ -271,7 +293,13 @@
 static void pp_irq (int irq, void * private, struct pt_regs * unused)
 {
 	struct pp_struct * pp = (struct pp_struct *) private;
-	pp->got_irq = 1;
+
+	if (pp->irqresponse) {
+		parport_write_control (pp->pdev->port, pp->irqctl);
+		pp->irqresponse = 0;
+	}
+
+	atomic_inc (&pp->irqc);
 	wake_up_interruptible (&pp->irq_wait);
 }
 
@@ -322,6 +350,9 @@
 
 	/* First handle the cases that don't take arguments. */
 	if (cmd == PPCLAIM) {
+		struct ieee1284_info *info;
+		int first_claim = 0;
+
 		if (pp->flags & PP_CLAIMED) {
 			printk (KERN_DEBUG CHRDEV
 				"%x: you've already got it!\n", minor);
@@ -333,6 +364,8 @@
 			int err = register_device (minor, pp);
 			if (err)
 				return err;
+
+			first_claim = 1;
 		}
 
 		parport_claim_or_block (pp->pdev);
@@ -341,6 +374,30 @@
 		/* For interrupt-reporting to work, we need to be
 		 * informed of each interrupt. */
 		enable_irq (pp);
+
+		/* We may need to fix up the state machine. */
+		info = &pp->pdev->port->ieee1284;
+		pp->saved_state.mode = info->mode;
+		pp->saved_state.phase = info->phase;
+		if (pp->mode != info->mode) {
+			int phase = IEEE1284_PH_FWD_IDLE;
+
+			if (first_claim) {
+				info->mode = pp->mode;
+				switch (pp->mode & ~(IEEE1284_DEVICEID
+						     | IEEE1284_ADDR)) {
+				case IEEE1284_MODE_NIBBLE:
+				case IEEE1284_MODE_BYTE:
+					phase = IEEE1284_PH_REV_IDLE;
+				}
+				info->phase = phase;
+			} else {
+				/* Just restore the state. */
+				info->mode = pp->state.mode;
+				info->phase = pp->state.phase;
+			}
+		}
+
 		return 0;
 	}
 
@@ -380,6 +437,7 @@
 
 	port = pp->pdev->port;
 	switch (cmd) {
+		struct ieee1284_info *info;
 		unsigned char reg;
 		unsigned char mask;
 		int mode;
@@ -405,6 +463,12 @@
 		return 0;
 
 	case PPRELEASE:
+		/* Save the state machine's state. */
+		info = &pp->pdev->port->ieee1284;
+		pp->state.mode = info->mode;
+		pp->state.phase = info->phase;
+		info->mode = pp->saved_state.mode;
+		info->phase = pp->saved_state.phase;
 		parport_release (pp->pdev);
 		pp->flags &= ~PP_CLAIMED;
 		return 0;
@@ -443,11 +507,36 @@
 	case PPNEGOT:
 		if (copy_from_user (&mode, (int *) arg, sizeof (mode)))
 			return -EFAULT;
-		/* FIXME: validate mode */
-		ret = parport_negotiate (port, mode);
+		switch ((ret = parport_negotiate (port, mode))) {
+		case 0: break;
+		case -1: /* handshake failed, peripheral not IEEE 1284 */
+			ret = -EIO;
+			break;
+		case 1:  /* handshake succeeded, peripheral rejected mode */
+			ret = -ENXIO;
+			break;
+		}
 		enable_irq (pp);
 		return ret;
 
+	case PPWCTLONIRQ:
+		if (copy_from_user (&reg, (unsigned char *) arg,
+				    sizeof (reg)))
+			return -EFAULT;
+
+		/* Remember what to set the control lines to, for next
+		 * time we get an interrupt. */
+		pp->irqctl = reg;
+		pp->irqresponse = 1;
+		return 0;
+
+	case PPCLRIRQ:
+		ret = atomic_read (&pp->irqc);
+		if (copy_to_user ((int *) arg, &ret, sizeof (ret)))
+			return -EFAULT;
+		atomic_sub (ret, &pp->irqc);
+		return 0;
+
 	default:
 		printk (KERN_DEBUG CHRDEV "%x: What? (cmd=0x%x)\n", minor,
 			cmd);
@@ -472,7 +561,7 @@
 
 	pp->mode = IEEE1284_MODE_COMPAT;
 	pp->flags = 0;
-	pp->got_irq = 0;
+	atomic_set (&pp->irqc, 0);
 	init_waitqueue_head (&pp->irq_wait);
 
 	/* Defer the actual device registration until the first claim.
@@ -515,10 +604,10 @@
 {
 	struct pp_struct *pp = file->private_data;
 	unsigned int mask = 0;
-	if (pp->got_irq) {
-		pp->got_irq = 0;
+
+	if (atomic_read (&pp->irqc))
 		mask |= POLLIN | POLLRDNORM;
-	}
+
 	poll_wait (file, &pp->irq_wait, wait);
 	return mask;
 }
diff -u --recursive --new-file v2.3.11/linux/drivers/char/ppdev.h linux/drivers/char/ppdev.h
--- v2.3.11/linux/drivers/char/ppdev.h	Thu Jul  8 15:42:20 1999
+++ linux/drivers/char/ppdev.h	Mon Jul 26 14:11:05 1999
@@ -63,3 +63,9 @@
 
 /* Negotiate a particular IEEE 1284 mode. */
 #define PPNEGOT		_IOW(PP_IOCTL, 0x91, int)
+
+/* Set control lines when an interrupt occurs. */
+#define PPWCTLONIRQ	_IOW(PP_IOCTL, 0x92, unsigned char)
+
+/* Clear (and return) interrupt count. */
+#define PPCLRIRQ	_IOR(PP_IOCTL, 0x93, int)
diff -u --recursive --new-file v2.3.11/linux/drivers/char/raw.c linux/drivers/char/raw.c
--- v2.3.11/linux/drivers/char/raw.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/raw.c	Mon Jul 26 22:50:35 1999
@@ -0,0 +1,384 @@
+/*
+ * linux/drivers/char/raw.c
+ *
+ * Front-end raw character devices.  These can be bound to any block
+ * devices to provide genuine Unix raw character device semantics.
+ *
+ * We reserve minor number 0 for a control interface.  ioctl()s on this
+ * device are used to bind the other minor numbers to block devices.
+ */
+
+#include <linux/fs.h>
+#include <linux/iobuf.h>
+#include <linux/major.h>
+#include <linux/blkdev.h>
+#include <linux/raw.h>
+#include <asm/uaccess.h>
+
+#define dprintk(x...) 
+
+static kdev_t raw_device_bindings[256] = {};
+static int raw_device_inuse[256] = {};
+static int raw_device_sector_size[256] = {};
+static int raw_device_sector_bits[256] = {};
+
+extern struct file_operations * get_blkfops(unsigned int major);
+
+static ssize_t rw_raw_dev(int rw, struct file *, char *, size_t, loff_t *);
+
+ssize_t	raw_read(struct file *, char *, size_t, loff_t *);
+ssize_t	raw_write(struct file *, const char *, size_t, loff_t *);
+int	raw_open(struct inode *, struct file *);
+int	raw_release(struct inode *, struct file *);
+int	raw_ctl_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
+
+
+static struct file_operations raw_fops = {
+	NULL,		/* llseek */
+	raw_read,	/* read */
+	raw_write,	/* write */
+	NULL,		/* readdir */
+	NULL,		/* poll */
+	NULL,		/* ioctl */
+	NULL,		/* mmap */
+	raw_open,	/* open */
+	NULL,		/* flush */
+	raw_release,	/* release */
+	NULL		/* fsync */
+};
+
+static struct file_operations raw_ctl_fops = {
+	NULL,		/* llseek */
+	NULL,		/* read */
+	NULL,		/* write */
+	NULL,		/* readdir */
+	NULL,		/* poll */
+	raw_ctl_ioctl,	/* ioctl */
+	NULL,		/* mmap */
+	raw_open,	/* open */
+	NULL,		/* flush */
+	NULL,		/* no special release code */
+	NULL		/* fsync */
+};
+
+
+
+void __init raw_init(void)
+{
+	register_chrdev(RAW_MAJOR, "raw", &raw_fops);
+}
+
+
+/*
+ * The raw IO open and release code needs to fake appropriate
+ * open/release calls to the underlying block devices.  
+ */
+
+static int bdev_open(kdev_t dev, int mode)
+{
+	int err = 0;
+	struct file dummy_file = {};
+	struct dentry dummy_dentry = {};
+	struct inode * inode = get_empty_inode();
+	
+	if (!inode)
+		return -ENOMEM;
+	
+	dummy_file.f_op = get_blkfops(MAJOR(dev));
+	if (!dummy_file.f_op) {
+		err = -ENODEV;
+		goto done;
+	}
+	
+	if (dummy_file.f_op->open) {
+		inode->i_rdev = dev;
+		dummy_dentry.d_inode = inode;
+		dummy_file.f_dentry = &dummy_dentry;
+		dummy_file.f_mode = mode;
+		err = dummy_file.f_op->open(inode, &dummy_file);
+	}
+
+ done:
+	iput(inode);
+	return err;
+}
+
+static int bdev_close(kdev_t dev)
+{
+	int err;
+	struct inode * inode = get_empty_inode();
+
+	if (!inode)
+		return -ENOMEM;
+	
+	inode->i_rdev = dev;
+	err = blkdev_release(inode);
+	iput(inode);
+	return err;
+}
+
+
+
+/* 
+ * Open/close code for raw IO.
+ */
+
+int raw_open(struct inode *inode, struct file *filp)
+{
+	int minor;
+	kdev_t bdev;
+	int err;
+	int sector_size;
+	int sector_bits;
+
+	minor = MINOR(inode->i_rdev);
+	
+	/* 
+	 * Is it the control device? 
+	 */
+	
+	if (minor == 0) {
+		filp->f_op = &raw_ctl_fops;
+		return 0;
+	}
+	
+	/*
+	 * No, it is a normal raw device.  All we need to do on open is
+	 * to check that the device is bound, and force the underlying
+	 * block device to a sector-size blocksize. 
+	 */
+
+	bdev = raw_device_bindings[minor];
+	if (bdev == NODEV) 
+		return -ENODEV;
+
+	err = bdev_open(bdev, filp->f_mode);
+	if (err)
+		return err;
+	
+	/*
+	 * Don't change the blocksize if we already have users using
+	 * this device 
+	 */
+
+	if (raw_device_inuse[minor]++)
+		return 0;
+	
+	/* 
+	 * Don't interfere with mounted devices: we cannot safely set
+	 * the blocksize on a device which is already mounted.  
+	 */
+	
+	sector_size = 512;
+	if (lookup_vfsmnt(bdev) != NULL) {
+		if (blksize_size[MAJOR(bdev)])
+			sector_size = blksize_size[MAJOR(bdev)][MINOR(bdev)];
+	} else {
+		if (hardsect_size[MAJOR(bdev)])
+			sector_size = hardsect_size[MAJOR(bdev)][MINOR(bdev)];
+	}
+
+	set_blocksize(bdev, sector_size);
+	raw_device_sector_size[minor] = sector_size;
+
+	for (sector_bits = 0; !(sector_size & 1); )
+		sector_size>>=1, sector_bits++;
+	raw_device_sector_bits[minor] = sector_bits;
+	
+	return 0;
+}
+
+int raw_release(struct inode *inode, struct file *filp)
+{
+	int minor;
+	kdev_t bdev;
+	
+	minor = MINOR(inode->i_rdev);
+	bdev = raw_device_bindings[minor];
+	bdev_close(bdev);
+	raw_device_inuse[minor]--;
+	return 0;
+}
+
+
+
+/*
+ * Deal with ioctls against the raw-device control interface, to bind
+ * and unbind other raw devices.  
+ */
+
+int raw_ctl_ioctl(struct inode *inode, 
+		  struct file *flip,
+		  unsigned int command, 
+		  unsigned long arg)
+{
+	struct raw_config_request rq;
+	int err = 0;
+	int minor;
+	
+	switch (command) {
+	case RAW_SETBIND:
+	case RAW_GETBIND:
+
+		/* First, find out which raw minor we want */
+
+		err = copy_from_user(&rq, (void *) arg, sizeof(rq));
+		if (err)
+			break;
+		
+		minor = rq.raw_minor;
+		if (minor == 0 || minor > MINORMASK) {
+			err = -EINVAL;
+			break;
+		}
+
+		if (command == RAW_SETBIND) {
+			/* 
+			 * For now, we don't need to check that the underlying
+			 * block device is present or not: we can do that when
+			 * the raw device is opened.  Just check that the
+			 * major/minor numbers make sense. 
+			 */
+
+			if (rq.block_major == NODEV || 
+			    rq.block_major > MAX_BLKDEV ||
+			    rq.block_minor > MINORMASK) {
+				err = -EINVAL;
+				break;
+			}
+			
+			if (raw_device_inuse[minor]) {
+				err = -EBUSY;
+				break;
+			}
+			raw_device_bindings[minor] = 
+				MKDEV(rq.block_major, rq.block_minor);
+		} else {
+			rq.block_major = MAJOR(raw_device_bindings[minor]);
+			rq.block_minor = MINOR(raw_device_bindings[minor]);
+			err = copy_to_user((void *) arg, &rq, sizeof(rq));
+		}
+		break;
+		
+	default:
+		err = -EINVAL;
+	}
+	
+	return err;
+}
+
+
+
+ssize_t	raw_read(struct file *filp, char * buf, 
+		 size_t size, loff_t *offp)
+{
+	return rw_raw_dev(READ, filp, buf, size, offp);
+}
+
+ssize_t	raw_write(struct file *filp, const char *buf, 
+		  size_t size, loff_t *offp)
+{
+	return rw_raw_dev(WRITE, filp, (char *) buf, size, offp);
+}
+
+#define SECTOR_BITS 9
+#define SECTOR_SIZE (1U << SECTOR_BITS)
+#define SECTOR_MASK (SECTOR_SIZE - 1)
+
+ssize_t	rw_raw_dev(int rw, struct file *filp, char *buf, 
+		   size_t size, loff_t *offp)
+{
+	struct kiobuf * iobuf;
+	int		err;
+	unsigned long	blocknr, blocks;
+	unsigned long	b[KIO_MAX_SECTORS];
+	size_t		transferred;
+	int		iosize;
+	int		i;
+	int		minor;
+	kdev_t		dev;
+	unsigned long	limit;
+
+	int		sector_size, sector_bits, sector_mask;
+	int		max_sectors;
+	
+	/*
+	 * First, a few checks on device size limits 
+	 */
+
+	minor = MINOR(filp->f_dentry->d_inode->i_rdev);
+	dev = raw_device_bindings[minor];
+	sector_size = raw_device_sector_size[minor];
+	sector_bits = raw_device_sector_bits[minor];
+	sector_mask = sector_size- 1;
+	max_sectors = KIO_MAX_SECTORS >> (sector_bits - 9);
+	
+	if (blk_size[MAJOR(dev)])
+		limit = (((loff_t) blk_size[MAJOR(dev)][MINOR(dev)]) << BLOCK_SIZE_BITS) >> sector_bits;
+	else
+		limit = INT_MAX;
+	dprintk ("rw_raw_dev: dev %d:%d (+%d)\n",
+		 MAJOR(dev), MINOR(dev), limit);
+	
+	if ((*offp & sector_mask) || (size & sector_mask))
+		return -EINVAL;
+	if ((*offp >> sector_bits) > limit)
+		return 0;
+
+	/* 
+	 * We'll just use one kiobuf
+	 */
+
+	err = alloc_kiovec(1, &iobuf);
+	if (err)
+		return err;
+
+	/*
+	 * Split the IO into KIO_MAX_SECTORS chunks, mapping and
+	 * unmapping the single kiobuf as we go to perform each chunk of
+	 * IO.  
+	 */
+
+	transferred = 0;
+	blocknr = *offp >> sector_bits;
+	while (size > 0) {
+		blocks = size >> sector_bits;
+		if (blocks > max_sectors)
+			blocks = max_sectors;
+		if (blocks > limit - blocknr)
+			blocks = limit - blocknr;
+		if (!blocks)
+			break;
+
+		iosize = blocks << sector_bits;
+
+		err = map_user_kiobuf(rw, iobuf, (unsigned long) buf, iosize);
+		if (err)
+			break;
+		
+		for (i=0; i < blocks; i++) 
+			b[i] = blocknr++;
+		
+		err = brw_kiovec(rw, 1, &iobuf, dev, b, sector_size, 0);
+
+		if (err >= 0) {
+			transferred += err;
+			size -= err;
+			buf += err;
+		}
+
+		unmap_kiobuf(iobuf);
+
+		if (err != iosize)
+			break;
+	}
+	
+	free_kiovec(1, &iobuf);
+
+	if (transferred) {
+		*offp += transferred;
+		return transferred;
+	}
+	
+	return err;
+}
diff -u --recursive --new-file v2.3.11/linux/drivers/misc/BUGS-parport linux/drivers/misc/BUGS-parport
--- v2.3.11/linux/drivers/misc/BUGS-parport	Thu Jun  3 16:21:47 1999
+++ linux/drivers/misc/BUGS-parport	Wed Dec 31 16:00:00 1969
@@ -1,5 +0,0 @@
-Currently known (or at least suspected) bugs in parport:
-
-o lp doesn't allow you to read status while printing is in progress.
-
-See <URL:http://www.cyberelk.demon.co.uk/parport.html>.
diff -u --recursive --new-file v2.3.11/linux/drivers/misc/Config.in linux/drivers/misc/Config.in
--- v2.3.11/linux/drivers/misc/Config.in	Thu Jul  8 15:42:20 1999
+++ linux/drivers/misc/Config.in	Wed Dec 31 16:00:00 1969
@@ -1,37 +0,0 @@
-#
-# For a description of the syntax of this configuration file,
-# see the Configure script.
-#
-# Parport configuration.
-#
-
-tristate 'Parallel port support' CONFIG_PARPORT
-if [ "$CONFIG_PARPORT" != "n" ]; then
-  dep_tristate '   PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT
-  if [ "$CONFIG_PARPORT_PC" != "n" ]; then
-    bool '   Use FIFO/DMA if available' CONFIG_PARPORT_PC_FIFO
-  fi
-  if [ "$CONFIG_ARM" = "y" ]; then
-    dep_tristate '   Archimedes hardware' CONFIG_PARPORT_ARC $CONFIG_PARPORT
-  fi
-  if [ "$CONFIG_AMIGA" = "y" ]; then
-    dep_tristate '   Amiga builtin port' CONFIG_PARPORT_AMIGA $CONFIG_PARPORT
-    if [ "$CONFIG_ZORRO" != "n" ]; then
-      dep_tristate '   Multiface III parallel port' CONFIG_PARPORT_MFC3 $CONFIG_PARPORT
-    fi
-  else
-    define_bool CONFIG_PARPORT_AMIGA n
-    define_bool CONFIG_PARPORT_MFC3 n
-  fi
-  if [ "$CONFIG_ATARI" = "y" ]; then
-    dep_tristate '   Atari hardware' CONFIG_PARPORT_ATARI $CONFIG_PARPORT
-  else
-    define_bool CONFIG_PARPORT_ATARI n
-  fi
-
-  # If exactly one hardware type is selected then parport will optimise away
-  # support for loading any others.  Defeat this if the user is keen.
-  bool '   Support foreign hardware' CONFIG_PARPORT_OTHER
-
-  bool '   IEEE 1284 transfer modes' CONFIG_PARPORT_1284
-fi
diff -u --recursive --new-file v2.3.11/linux/drivers/misc/Makefile linux/drivers/misc/Makefile
--- v2.3.11/linux/drivers/misc/Makefile	Thu Jul  8 15:42:20 1999
+++ linux/drivers/misc/Makefile	Wed Dec 31 16:00:00 1969
@@ -1,102 +0,0 @@
-#
-# Makefile for the kernel miscellaneous drivers.
-#
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now inherited from the
-# parent makes..
-#
-# Note 3! Parport is the Borg.  We have assimilated some other
-# drivers in the `char', `net' and `scsi' directories, but left them
-# there to allay suspicion.
-
-SUB_DIRS     := 
-MOD_SUB_DIRS := $(SUB_DIRS)
-ALL_SUB_DIRS := $(SUB_DIRS)
-
-L_TARGET := misc.a
-MX_OBJS  :=
-LX_OBJS  := 
-MI_OBJS  :=
-MIX_OBJS :=
-
-ifeq ($(CONFIG_PARPORT),y)
-  L_OBJS += parport_share.o parport_ieee1284.o parport_ieee1284_ops.o \
-            parport_procfs.o
-
-  ifeq ($(CONFIG_PARPORT_1284),y)
-    L_OBJS += parport_daisy.o parport_probe.o
-  endif
-
-  ifeq ($(CONFIG_PARPORT_PC),y)
-    LX_OBJS += parport_pc.o
-  else
-    ifeq ($(CONFIG_PARPORT_PC),m)
-      M_OBJS += parport_pc.o
-    endif
-  endif
-  ifeq ($(CONFIG_PARPORT_AX),y)
-    LX_OBJS += parport_ax.o
-  else
-    ifeq ($(CONFIG_PARPORT_AX),m)
-      M_OBJS += parport_ax.o
-    endif
-  endif
-  ifeq ($(CONFIG_PARPORT_AMIGA),y)
-    LX_OBJS += parport_amiga.o
-  else
-    ifeq ($(CONFIG_PARPORT_AMIGA),m)
-      M_OBJS += parport_amiga.o
-    endif
-  endif
-  ifeq ($(CONFIG_PARPORT_MFC3),y)
-    LX_OBJS += parport_mfc3.o
-  else
-    ifeq ($(CONFIG_PARPORT_MFC3),m)
-      M_OBJS += parport_mfc3.o
-    endif
-  endif
-  ifeq ($(CONFIG_PARPORT_ATARI),y)
-    LX_OBJS += parport_atari.o
-  else
-    ifeq ($(CONFIG_PARPORT_ATARI),m)
-      M_OBJS += parport_atari.o
-    endif
-  endif
-  LX_OBJS += parport_init.o
-else
-  ifeq ($(CONFIG_PARPORT),m)
-    MI_OBJS += parport_share.o parport_ieee1284.o parport_ieee1284_ops.o
-    ifeq ($(CONFIG_PARPORT_1284),y)
-      MI_OBJS += parport_daisy.o parport_probe.o
-    endif
-    ifneq ($(CONFIG_PROC_FS),n) 
-      MI_OBJS += parport_procfs.o
-    endif
-    MIX_OBJS += parport_init.o
-    M_OBJS += parport.o
-  endif
-  ifeq ($(CONFIG_PARPORT_PC),m)
-    M_OBJS += parport_pc.o
-  endif
-  ifeq ($(CONFIG_PARPORT_AX),m)
-    M_OBJS += parport_ax.o
-  endif
-  ifeq ($(CONFIG_PARPORT_AMIGA),m)
-    M_OBJS += parport_amiga.o
-  endif
-  ifeq ($(CONFIG_PARPORT_MFC3),m)
-    M_OBJS += parport_mfc3.o
-  endif
-  ifeq ($(CONFIG_PARPORT_ATARI),m)
-    M_OBJS += parport_atari.o
-  endif
-endif
-
-include $(TOPDIR)/Rules.make
-
-# Special rule to build the composite parport.o module
-parport.o: $(MI_OBJS) $(MIX_OBJS)
-	$(LD) $(LD_RFLAG) -r -o $@ $(MI_OBJS) $(MIX_OBJS)
diff -u --recursive --new-file v2.3.11/linux/drivers/misc/TODO-parport linux/drivers/misc/TODO-parport
--- v2.3.11/linux/drivers/misc/TODO-parport	Thu Jun  3 16:21:47 1999
+++ linux/drivers/misc/TODO-parport	Wed Dec 31 16:00:00 1969
@@ -1,20 +0,0 @@
-Things to be done.
-
-0. Fix the bugs (see BUGS-parport).
-
-1. Proper documentation.
-
-2. A better lp.c:
-
-   a) ECP support would be nice.  This can only work if both the port and
-      the printer support it.
-
-   b) Handle status readback automatically.  IEEE1284 printers can post status
-      bits when they have something to say.  We should read out and deal 
-      with (maybe just log) whatever the printer wants to tell the world.
-
-3. Support more hardware (eg m68k, Sun bpp).
-
-4. A better PLIP (make use of bidirectional/ECP/EPP ports).
-
-See <URL:http://www.cyberelk.demon.co.uk/parport.html>.
diff -u --recursive --new-file v2.3.11/linux/drivers/misc/multiface.h linux/drivers/misc/multiface.h
--- v2.3.11/linux/drivers/misc/multiface.h	Tue May 11 09:55:49 1999
+++ linux/drivers/misc/multiface.h	Wed Dec 31 16:00:00 1969
@@ -1,20 +0,0 @@
-#ifndef _MULTIFACE_H_
-#define _MULTIFACE_H_
-
-/*
- * Defines for SerialMaster, Multiface Card II and Multiface Card III
- * The addresses given below are offsets to the board base address
- * 
- * 6.11.95 Joerg Dorchain (dorchain@mpi-sb.mpg.de)
- *
- */
-
-#define PIA_REG_PADWIDTH 255
-
-#define DUARTBASE 0x0000
-#define PITBASE   0x0100
-#define ROMBASE   0x0200
-#define PIABASE   0x4000
-
-#endif
-
diff -u --recursive --new-file v2.3.11/linux/drivers/misc/parport_amiga.c linux/drivers/misc/parport_amiga.c
--- v2.3.11/linux/drivers/misc/parport_amiga.c	Mon Jun  7 12:10:10 1999
+++ linux/drivers/misc/parport_amiga.c	Wed Dec 31 16:00:00 1969
@@ -1,312 +0,0 @@
-/* Low-level parallel port routines for the Amiga buildin port
- *
- * Author: Joerg Dorchain <dorchain@wirbel.com>
- *
- * This is a complete rewrite of the code, but based heaviy upon the old
- * lp_intern. code.
- *
- * The built-in Amiga parallel port provides one port at a fixed address
- * with 8 bisdirecttional data lines (D0 - D7) and 3 bidirectional status
- * lines (BUSY, POUT, SEL), 1 output control line /STROBE (raised automatically in
- * hardware when the data register is accessed), and 1 input control line
- * /ACK, able to cause an interrupt, but both not directly settable by
- * software.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/parport.h>
-#include <asm/setup.h>
-#include <asm/amigahw.h>
-#include <asm/irq.h>
-#include <asm/amigaints.h>
-
-#undef DEBUG
-#ifdef DEBUG
-#define DPRINTK printk
-#else
-static inline int DPRINTK() {return 0;}
-#endif
-
-static struct parport *this_port = NULL;
-
-static void amiga_write_data(struct parport *p, unsigned char data)
-{
-DPRINTK("write_data %c\n",data);
-	/* Triggers also /STROBE. This behavior cannot be changed */
-	ciaa.prb = data;
-}
-
-static unsigned char amiga_read_data(struct parport *p)
-{
-	/* Triggers also /STROBE. This behavior cannot be changed */
-	return ciaa.prb;
-}
-
-#if 0
-static unsigned char control_pc_to_amiga(unsigned char control)
-{
-	unsigned char ret = 0;
-
-	if (control & PARPORT_CONTROL_DIRECTION) /* XXX: What is this? */
-		;
-	if (control & PARPORT_CONTROL_INTEN) /* XXX: What is INTEN? */
-		;
-	if (control & PARPORT_CONTROL_SELECT) /* XXX: What is SELECP? */
-		;
-	if (control & PARPORT_CONTROL_INIT) /* INITP */
-		/* reset connected to cpu reset pin */;
-	if (control & PARPORT_CONTROL_AUTOFD) /* AUTOLF */
-		/* Not connected */;
-	if (control & PARPORT_CONTROL_STROBE) /* Strobe */
-		/* Handled only directly by hardware */;
-	return ret;
-}
-#endif
-
-static unsigned char control_amiga_to_pc(unsigned char control)
-{
-	return PARPORT_CONTROL_INTEN | PARPORT_CONTROL_SELECT |
-	      PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_STROBE;
-	/* fake value: interrupt enable, select in, no reset,
-	no autolf, no strobe - seems to be closest the wiring diagram */
-}
-
-static void amiga_write_control(struct parport *p, unsigned char control)
-{
-DPRINTK("write_control %02x\n",control);
-	/* No implementation possible */
-}
-	
-static unsigned char amiga_read_control( struct parport *p)
-{
-DPRINTK("read_control \n");
-	return control_amiga_to_pc(0);
-}
-
-static unsigned char amiga_frob_control( struct parport *p, unsigned char mask, unsigned char val)
-{
-	unsigned char old;
-
-DPRINTK("frob_control mask %02x, value %02x\n",mask,val);
-	old = amiga_read_control(p);
-	amiga_write_control(p, (old & ~mask) ^ val);
-	return old;
-}
-
-
-static unsigned char status_pc_to_amiga(unsigned char status)
-{
-	unsigned char ret = 1;
-
-	if (status & PARPORT_STATUS_BUSY) /* Busy */
-		ret &= ~1;
-	if (status & PARPORT_STATUS_ACK) /* Ack */
-		/* handled in hardware */;
-	if (status & PARPORT_STATUS_PAPEROUT) /* PaperOut */
-		ret |= 2;
-	if (status & PARPORT_STATUS_SELECT) /* select */
-		ret |= 4;
-	if (status & PARPORT_STATUS_ERROR) /* error */
-		/* not connected */;
-	return ret;
-}
-
-static unsigned char status_amiga_to_pc(unsigned char status)
-{
-	unsigned char ret = PARPORT_STATUS_BUSY | PARPORT_STATUS_ACK | PARPORT_STATUS_ERROR;
-
-	if (status & 1) /* Busy */
-		ret &= ~PARPORT_STATUS_BUSY;
-	if (status & 2) /* PaperOut */
-		ret |= PARPORT_STATUS_PAPEROUT;
-	if (status & 4) /* Selected */
-		ret |= PARPORT_STATUS_SELECT;
-	/* the rest is not connected or handled autonomously in hardware */
-
-	return ret;
-}
-
-static void amiga_write_status( struct parport *p, unsigned char status)
-{
-DPRINTK("write_status %02x\n",status);
-	ciab.pra |= (ciab.pra & 0xf8) | status_pc_to_amiga(status);
-}
-
-static unsigned char amiga_read_status(struct parport *p)
-{
-	unsigned char status;
-
-	status = status_amiga_to_pc(ciab.pra & 7);
-DPRINTK("read_status %02x\n", status);
-	return status;
-}
-
-static void amiga_change_mode( struct parport *p, int m)
-{
-	/* XXX: This port only has one mode, and I am
-	not sure about the corresponding PC-style mode*/
-}
-
-/* as this ports irq handling is already done, we use a generic funktion */
-static void amiga_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	parport_generic_irq(irq, (struct parport *) dev_id, regs);
-}
-
-
-static void amiga_init_state(struct parport_state *s)
-{
-	s->u.amiga.data = 0;
-	s->u.amiga.datadir = 255;
-	s->u.amiga.status = 0;
-	s->u.amiga.statusdir = 0;
-}
-
-static void amiga_save_state(struct parport *p, struct parport_state *s)
-{
-	s->u.amiga.data = ciaa.prb;
-	s->u.amiga.datadir = ciaa.ddrb;
-	s->u.amiga.status = ciab.pra & 7;
-	s->u.amiga.statusdir = ciab.ddra & 7;
-}
-
-static void amiga_restore_state(struct parport *p, struct parport_state *s)
-{
-	ciaa.prb = s->u.amiga.data;
-	ciaa.ddrb = s->u.amiga.datadir;
-	ciab.pra |= (ciab.pra & 0xf8) | s->u.amiga.status;
-	ciab.ddra |= (ciab.ddra & 0xf8) | s->u.amiga.statusdir;
-}
-
-static void amiga_enable_irq(struct parport *p)
-{
-	enable_irq(IRQ_AMIGA_CIAA_FLG);
-}
-
-static void amiga_disable_irq(struct parport *p)
-{
-	disable_irq(IRQ_AMIGA_CIAA_FLG);
-}
-
-static void amiga_inc_use_count(void)
-{
-	MOD_INC_USE_COUNT;
-}
-
-static void amiga_dec_use_count(void)
-{
-	MOD_DEC_USE_COUNT;
-}
-
-static void amiga_fill_inode(struct inode *inode, int fill)
-{
-#ifdef MODULE
-	if (fill)
-		MOD_INC_USE_COUNT;
-	else
-		MOD_DEC_USE_COUNT;
-#endif
-}
-
-static struct parport_operations pp_amiga_ops = {
-	amiga_write_data,
-	amiga_read_data,
-
-	amiga_write_control,
-	amiga_read_control,
-	amiga_frob_control,
-
-	NULL, /* write_econtrol */
-	NULL, /* read_econtrol */
-	NULL, /* frob_econtrol */
-
-	amiga_write_status,
-	amiga_read_status,
-
-	NULL, /* write fifo */
-	NULL, /* read fifo */
-
-	amiga_change_mode,
-
-
-	NULL, /* epp_write_data */
-	NULL, /* epp_read_data */
-	NULL, /* epp_write_addr */
-	NULL, /* epp_read_addr */
-	NULL, /* epp_check_timeout */
-
-	NULL, /* epp_write_block */
-	NULL, /* epp_read_block */
-
-	NULL, /* ecp_write_block */
-	NULL, /* ecp_read_block */
-
-	amiga_init_state,
-	amiga_save_state,
-	amiga_restore_state,
-
-	amiga_enable_irq,
-	amiga_disable_irq,
-	amiga_interrupt, 
-
-	amiga_inc_use_count,
-	amiga_dec_use_count,
-	amiga_fill_inode
-};
-
-/* ----------- Initialisation code --------------------------------- */
-
-__initfunc(int parport_amiga_init(void))
-{
-	struct parport *p;
-
-	if (MACH_IS_AMIGA && AMIGAHW_PRESENT(AMI_PARALLEL)) {
-		ciaa.ddrb = 0xff;
-		ciab.ddra &= 0xf8;
-		if (!(p = parport_register_port((unsigned long)&ciaa.prb,
-					IRQ_AMIGA_CIAA_FLG, PARPORT_DMA_NONE,
-					&pp_amiga_ops)))
-			return 0;
-		this_port = p;
-		printk(KERN_INFO "%s: Amiga built-in port using irq\n", p->name);
-		/* XXX: set operating mode */
-		parport_proc_register(p);
-		if (request_irq(IRQ_AMIGA_CIAA_FLG, amiga_interrupt, 0,
-				p->name, p)) {
-			parport_unregister_port (p);
-			return 0;
-		}
-
-		if (parport_probe_hook)
-			(*parport_probe_hook)(p);
-
-		parport_announce_port (p);
-
-		return 1;
-
-	}
-	return 0;
-}
-
-#ifdef MODULE
-
-MODULE_AUTHOR("Joerg Dorchain");
-MODULE_DESCRIPTION("Parport Driver for Amiga builtin Port");
-MODULE_SUPPORTED_DEVICE("Amiga builtin Parallel Port");
-
-int init_module(void)
-{
-	return ! parport_amiga_init();
-}
-
-void cleanup_module(void)
-{
-	if (p->irq != PARPORT_IRQ_NONE)
-		free_irq(IRQ_AMIGA_CIAA_FLG, p);
-	parport_proc_unregister(this_port);
-	parport_unregister_port(this_port);
-}
-#endif
-
-
diff -u --recursive --new-file v2.3.11/linux/drivers/misc/parport_arc.c linux/drivers/misc/parport_arc.c
--- v2.3.11/linux/drivers/misc/parport_arc.c	Wed Jul 21 15:46:48 1999
+++ linux/drivers/misc/parport_arc.c	Wed Dec 31 16:00:00 1969
@@ -1,160 +0,0 @@
-/* Low-level parallel port routines for Archimedes onboard hardware
- *
- * Author: Phil Blundell <Philip.Blundell@pobox.com>
- */
-
-/* This driver is for the parallel port hardware found on Acorn's old
- * range of Archimedes machines.  The A5000 and newer systems have PC-style
- * I/O hardware and should use the parport_pc driver instead.
- *
- * The Acorn printer port hardware is very simple.  There is a single 8-bit
- * write-only latch for the data port and control/status bits are handled
- * with various auxilliary input and output lines.  The port is not
- * bidirectional, does not support any modes other than SPP, and has only
- * a subset of the standard printer control lines connected.
- */
-
-#include <linux/threads.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/malloc.h>
-#include <linux/parport.h>
-
-#include <asm/ptrace.h>
-#include <asm/io.h>
-#include <asm/arch/oldlatches.h>
-#include <asm/arch/irqs.h>
-
-#define DATA_ADDRESS    0x3350010
-
-/* This is equivalent to the above and only used for request_region. */
-#define PORT_BASE       0x80000000 | ((DATA_ADDRESS - IO_BASE) >> 2)
-
-/* The hardware can't read from the data latch, so we must use a soft
-   copy. */
-static unsigned char data_copy;
-
-/* These are pretty simple. We know the irq is never shared and the
-   kernel does all the magic that's required. */
-static void arc_enable_irq(struct parport *p)
-{
-	enable_irq(p->irq);
-}
-
-static void arc_disable_irq(struct parport *p)
-{
-	disable_irq(p->irq);
-}
-
-static void arc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	parport_generic_irq(irq, (struct parport *) dev_id, regs);
-}
-
-static void arc_write_data(struct parport *p, unsigned char data)
-{
-	data_copy = data;
-	outb_t(data, DATA_LATCH);
-}
-
-static unsigned char arc_read_data(struct parport *p)
-{
-	return data_copy;
-}
-
-static void arc_inc_use_count(void)
-{
-#ifdef MODULE
-	MOD_INC_USE_COUNT;
-#endif
-}
-
-static void arc_dec_use_count(void)
-{
-#ifdef MODULE
-	MOD_DEC_USE_COUNT;
-#endif
-}
-
-static void arc_fill_inode(struct inode *inode, int fill)
-{
-#ifdef MODULE
-	if (fill)
-		MOD_INC_USE_COUNT;
-	else
-		MOD_DEC_USE_COUNT;
-#endif
-}
-
-static struct parport_operations parport_arc_ops = 
-{
-	arc_write_data,
-	arc_read_data,
-
-	arc_write_control,
-	arc_read_control,
-	arc_frob_control,
-
-	arc_read_status,
-
-	arc_enable_irq,
-	arc_disable_irq,
-
-	arc_data_forward,
-	arc_data_reverse,
-
-	arc_interrupt,
-
-	arc_init_state,
-	arc_save_state,
-	arc_restore_state,
-
-	arc_inc_use_count,
-	arc_dec_use_count,
-	arc_fill_inode,
-
-	parport_ieee1284_epp_write_data,
-	parport_ieee1284_epp_read_data,
-	parport_ieee1284_epp_write_addr,
-	parport_ieee1284_epp_read_addr,
-
-	parport_ieee1284_ecp_write_data,
-	parport_ieee1284_ecp_read_data,
-	parport_ieee1284_ecp_write_addr,
-	
-	parport_ieee1284_write_compat,
-	parport_ieee1284_read_nibble,
-	parport_ieee1284_read_byte,
-};
-
-/* --- Initialisation code -------------------------------- */
-
-int parport_arc_init(void)
-{
-	/* Archimedes hardware provides only one port, at a fixed address */
-	struct parport *p;
-
-	if (check_region(PORT_BASE, 1))
-		return 0;
-
-	p = parport_register_port (PORT_BASE, IRQ_PRINTERACK,
-				   PARPORT_DMA_NONE, &parport_arc_ops);
-
-	if (!p)
-		return 0;
-
-	p->modes = PARPORT_MODE_ARCSPP;
-	p->size = 1;
-
-	printk(KERN_INFO "%s: Archimedes on-board port, using irq %d\n",
-	       p->irq);
-	parport_proc_register(p);
-
-	/* Tell the high-level drivers about the port. */
-	parport_announce_port (p);
-
-	return 1;
-}
diff -u --recursive --new-file v2.3.11/linux/drivers/misc/parport_atari.c linux/drivers/misc/parport_atari.c
--- v2.3.11/linux/drivers/misc/parport_atari.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/misc/parport_atari.c	Wed Dec 31 16:00:00 1969
@@ -1,251 +0,0 @@
-/* Low-level parallel port routines for the Atari builtin port
- *
- * Author: Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
- *
- * Based on parport_amiga.c.
- *
- * The built-in Atari parallel port provides one port at a fixed address
- * with 8 output data lines (D0 - D7), 1 output control line (STROBE)
- * and 1 input status line (BUSY) able to cause an interrupt.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/parport.h>
-#include <asm/setup.h>
-#include <asm/atarihw.h>
-#include <asm/irq.h>
-#include <asm/atariints.h>
-
-static struct parport *this_port = NULL;
-
-static unsigned char
-parport_atari_read_data(struct parport *p)
-{
-	unsigned long flags;
-	unsigned char data;
-
-	save_flags(flags);
-	cli();
-	sound_ym.rd_data_reg_sel = 15;
-	data = sound_ym.rd_data_reg_sel;
-	restore_flags(flags);
-	return data;
-}
-
-static void
-parport_atari_write_data(struct parport *p, unsigned char data)
-{
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	sound_ym.rd_data_reg_sel = 15;
-	sound_ym.wd_data = data;
-	restore_flags(flags);
-}
-
-static unsigned char
-parport_atari_read_control(struct parport *p)
-{
-	unsigned long flags;
-	unsigned char control = 0;
-
-	save_flags(flags);
-	cli();
-	sound_ym.rd_data_reg_sel = 14;
-	if (!(sound_ym.rd_data_reg_sel & (1 << 5)))
-		control = PARPORT_CONTROL_STROBE;
-	restore_flags(flags);
-	return control;
-}
-
-static void
-parport_atari_write_control(struct parport *p, unsigned char control)
-{
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	sound_ym.rd_data_reg_sel = 14;
-	if (control & PARPORT_CONTROL_STROBE)
-		sound_ym.wd_data = sound_ym.rd_data_reg_sel & ~(1 << 5);
-	else
-		sound_ym.wd_data = sound_ym.rd_data_reg_sel | (1 << 5);
-	restore_flags(flags);
-}
-
-static unsigned char
-parport_atari_frob_control(struct parport *p, unsigned char mask,
-			   unsigned char val)
-{
-	unsigned char old = parport_atari_read_control(p);
-	parport_atari_write_control(p, (old & ~mask) ^ val);
-	return old;
-}
-
-static unsigned char
-parport_atari_read_status(struct parport *p)
-{
-	return ((mfp.par_dt_reg & 1 ? 0 : PARPORT_STATUS_BUSY) |
-		PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR);
-}
-
-static void
-parport_atari_write_status(struct parport *p, unsigned char status)
-{
-}
-
-static void
-parport_atari_init_state(struct parport_state *s)
-{
-}
-
-static void
-parport_atari_save_state(struct parport *p, struct parport_state *s)
-{
-}
-
-static void
-parport_atari_restore_state(struct parport *p, struct parport_state *s)
-{
-}
-
-static void
-parport_atari_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	parport_generic_irq(irq, (struct parport *) dev_id, regs);
-}
-
-static void
-parport_atari_inc_use_count(void)
-{
-	MOD_INC_USE_COUNT;
-}
-
-static void
-parport_atari_dec_use_count(void)
-{
-	MOD_DEC_USE_COUNT;
-}
-
-static void
-parport_atari_fill_inode(struct inode *inode, int fill)
-{
-#ifdef MODULE
-	if (fill)
-		MOD_INC_USE_COUNT;
-	else
-		MOD_DEC_USE_COUNT;
-#endif
-}
-
-static struct parport_operations parport_atari_ops = {
-	parport_atari_write_data,
-	parport_atari_read_data,
-
-	parport_atari_write_control,
-	parport_atari_read_control,
-	parport_atari_frob_control,
-
-	NULL, /* write_econtrol */
-	NULL, /* read_econtrol */
-	NULL, /* frob_econtrol */
-
-	parport_atari_write_status,
-	parport_atari_read_status,
-
-	NULL, /* write fifo */
-	NULL, /* read fifo */
-
-	NULL, /* change_mode */
-
-	NULL, /* epp_write_data */
-	NULL, /* epp_read_data */
-	NULL, /* epp_write_addr */
-	NULL, /* epp_read_addr */
-	NULL, /* epp_check_timeout */
-
-	NULL, /* epp_write_block */
-	NULL, /* epp_read_block */
-
-	NULL, /* ecp_write_block */
-	NULL, /* ecp_read_block */
-
-	parport_atari_init_state,
-	parport_atari_save_state,
-	parport_atari_restore_state,
-
-	NULL, /* enable_irq */
-	NULL, /* disable_irq */
-	parport_atari_interrupt,
-
-	parport_atari_inc_use_count,
-	parport_atari_dec_use_count,
-	parport_atari_fill_inode
-};
-
-
-int __init
-parport_atari_init(void)
-{
-	struct parport *p;
-	unsigned long flags;
-
-	if (MACH_IS_ATARI) {
-		save_flags(flags);
-		cli();
-		/* Soundchip port A/B as output. */
-		sound_ym.rd_data_reg_sel = 7;
-		sound_ym.wd_data = (sound_ym.rd_data_reg_sel & 0x3f) | 0xc0;
-		/* STROBE high. */
-		sound_ym.rd_data_reg_sel = 14;
-		sound_ym.wd_data = sound_ym.rd_data_reg_sel | (1 << 5);
-		restore_flags(flags);
-		/* MFP port I0 as input. */
-		mfp.data_dir &= ~1;
-		/* MFP port I0 interrupt on high->low edge. */
-		mfp.active_edge &= ~1;
-		p = parport_register_port((unsigned long)&sound_ym.wd_data,
-					  IRQ_MFP_BUSY, PARPORT_DMA_NONE,
-					  &parport_atari_ops);
-		if (!p)
-			return 0;
-		if (request_irq(IRQ_MFP_BUSY, parport_atari_interrupt,
-				IRQ_TYPE_SLOW, p->name, p)) {
-			parport_unregister_port (p);
-			return 0;
-		}
-
-		this_port = p;
-		printk(KERN_INFO "%s: Atari built-in port using irq\n", p->name);
-		parport_proc_register(p);
-
-		parport_announce_port (p);
-
-		return 1;
-	}
-	return 0;
-}
-
-#ifdef MODULE
-
-MODULE_AUTHOR("Andreas Schwab");
-MODULE_DESCRIPTION("Parport Driver for Atari builtin Port");
-MODULE_SUPPORTED_DEVICE("Atari builtin Parallel Port");
-
-int
-init_module(void)
-{
-	return parport_atari_init() ? 0 : -ENODEV;
-}
-
-void
-cleanup_module(void)
-{
-	if (p->irq != PARPORT_IRQ_NONE)
-		free_irq(IRQ_MFP_BUSY, p);
-	parport_proc_unregister(this_port);
-	parport_unregister_port(this_port);
-}
-#endif
diff -u --recursive --new-file v2.3.11/linux/drivers/misc/parport_ax.c linux/drivers/misc/parport_ax.c
--- v2.3.11/linux/drivers/misc/parport_ax.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/misc/parport_ax.c	Wed Dec 31 16:00:00 1969
@@ -1,600 +0,0 @@
-/* $Id: parport_ax.c,v 1.20 1999/07/03 08:56:21 davem Exp $
- * Parallel-port routines for Sun Ultra/AX architecture
- * 
- * Author: Eddie C. Dost <ecd@skynet.be>
- *
- * based on work by:
- *          Phil Blundell <Philip.Blundell@pobox.com>
- *          Tim Waugh <tim@cyberelk.demon.co.uk>
- *	    Jose Renau <renau@acm.org>
- *          David Campbell <campbell@tirian.che.curtin.edu.au>
- *          Grant Guenther <grant@torque.net>
- */
-
-#include <linux/string.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/malloc.h>
-#include <linux/init.h>
-
-#include <linux/parport.h>
-
-#include <asm/ptrace.h>
-#include <linux/interrupt.h>
-
-#include <asm/io.h>
-#include <asm/ebus.h>
-#include <asm/ns87303.h>
-#include <asm/irq.h>
-
-
-/*
- * Define this if you have Devices which don't support short
- * host read/write cycles.
- */
-#undef HAVE_SLOW_DEVICES
-
-
-#define DATA		0x00
-#define STATUS		0x01
-#define CONTROL		0x02
-#define EPPADDR		0x03
-#define EPPDATA		0x04
-
-#define CFIFO		0x400
-#define DFIFO		0x400
-#define TFIFO		0x400
-#define CONFIGA		0x400
-#define CONFIGB		0x401
-#define ECONTROL	0x402
-
-static void parport_ax_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	parport_generic_irq(irq, (struct parport *) dev_id, regs);
-}
-
-void
-parport_ax_write_epp(struct parport *p, unsigned char d)
-{
-	outb(d, p->base + EPPDATA);
-}
-
-unsigned char
-parport_ax_read_epp(struct parport *p)
-{
-	return inb(p->base + EPPDATA);
-}
-
-void
-parport_ax_write_epp_addr(struct parport *p, unsigned char d)
-{
-	outb(d, p->base + EPPADDR);
-}
-
-unsigned char
-parport_ax_read_epp_addr(struct parport *p)
-{
-	return inb(p->base + EPPADDR);
-}
-
-int parport_ax_epp_clear_timeout(struct parport *pb);
-
-int 
-parport_ax_check_epp_timeout(struct parport *p)
-{
-	if (!(inb(p->base+STATUS) & 1))
-		return 0;
-	parport_ax_epp_clear_timeout(p);
-	return 1;
-}
-
-unsigned char
-parport_ax_read_configb(struct parport *p)
-{
-	return inb(p->base + CONFIGB);
-}
-
-void
-parport_ax_write_data(struct parport *p, unsigned char d)
-{
-	outb(d, p->base + DATA);
-}
-
-unsigned char
-parport_ax_read_data(struct parport *p)
-{
-	return inb(p->base + DATA);
-}
-
-void
-parport_ax_write_control(struct parport *p, unsigned char d)
-{
-	outb(d, p->base + CONTROL);
-}
-
-unsigned char
-parport_ax_read_control(struct parport *p)
-{
-	return inb(p->base + CONTROL);
-}
-
-unsigned char
-parport_ax_frob_control(struct parport *p, unsigned char mask,  unsigned char val)
-{
-	unsigned char old = inb(p->base + CONTROL);
-	outb(((old & ~mask) ^ val), p->base + CONTROL);
-	return old;
-}
-
-void
-parport_ax_write_status(struct parport *p, unsigned char d)
-{
-	outb(d, p->base + STATUS);
-}
-
-unsigned char
-parport_ax_read_status(struct parport *p)
-{
-	return inb(p->base + STATUS);
-}
-
-void
-parport_ax_write_econtrol(struct parport *p, unsigned char d)
-{
-	outb(d, p->base + ECONTROL);
-}
-
-unsigned char
-parport_ax_read_econtrol(struct parport *p)
-{
-	return inb(p->base + ECONTROL);
-}
-
-unsigned char
-parport_ax_frob_econtrol(struct parport *p, unsigned char mask, unsigned char val)
-{
-	unsigned char old = inb(p->base + ECONTROL);
-	outb(((old & ~mask) ^ val), p->base + ECONTROL);
-	return old;
-}
-
-void
-parport_ax_change_mode(struct parport *p, int m)
-{
-	/* FIXME */
-	parport_ax_frob_econtrol(p, 0xe0, m << 5);
-}
-
-void
-parport_ax_write_fifo(struct parport *p, unsigned char v)
-{
-	outb(v, p->base + DFIFO);
-}
-
-unsigned char
-parport_ax_read_fifo(struct parport *p)
-{
-	return inb(p->base + DFIFO);
-}
-
-void
-parport_ax_disable_irq(struct parport *p)
-{
-	struct linux_ebus_dma *dma = p->private_data;
-	unsigned int dcsr;
-
-	dcsr = readl((unsigned long)&dma->dcsr);
-	dcsr &= ~(EBUS_DCSR_INT_EN);
-	writel(dcsr, (unsigned long)&dma->dcsr);
-}
-
-void
-parport_ax_enable_irq(struct parport *p)
-{
-	struct linux_ebus_dma *dma = p->private_data;
-	unsigned int dcsr;
-
-	dcsr = readl((unsigned long)&dma->dcsr);
-	dcsr |= EBUS_DCSR_INT_EN;
-	writel(dcsr, (unsigned long)&dma->dcsr);
-}
-
-void
-parport_ax_init_state(struct pardevice *dev, struct parport_state *s)
-{
-	struct linux_ebus_dma *dma = dev->port->private_data;
-
-	s->u.ax.ctr = 0xc | (dev->irq_func ? 0x10 : 0x0);
-	s->u.ax.ecr = 0x0;
-
-	if (dev->irq_func)
-		s->u.ax.dcsr = (readl((unsigned long)&dma->dcsr)
-				| EBUS_DCSR_INT_EN);
-	else
-		s->u.ax.dcsr = (readl((unsigned long)&dma->dcsr)
-				& ~EBUS_DCSR_INT_EN);
-}
-
-void
-parport_ax_save_state(struct parport *p, struct parport_state *s)
-{
-	struct linux_ebus_dma *dma = p->private_data;
-
-	s->u.ax.ctr = parport_ax_read_control(p);
-	s->u.ax.ecr = parport_ax_read_econtrol(p);
-	s->u.ax.dcsr = readl((unsigned long)&dma->dcsr);
-}
-
-void
-parport_ax_restore_state(struct parport *p, struct parport_state *s)
-{
-	struct linux_ebus_dma *dma = p->private_data;
-
-	parport_ax_write_control(p, s->u.ax.ctr);
-	parport_ax_write_econtrol(p, s->u.ax.ecr);
-	writel(s->u.ax.dcsr, (unsigned long)&dma->dcsr);
-}
-
-void
-parport_ax_inc_use_count(void)
-{
-#ifdef MODULE
-	MOD_INC_USE_COUNT;
-#endif
-}
-
-void
-parport_ax_dec_use_count(void)
-{
-#ifdef MODULE
-	MOD_DEC_USE_COUNT;
-#endif
-}
-
-static void parport_ax_fill_inode(struct inode *inode, int fill)
-{
-#ifdef MODULE
-	if (fill)
-		MOD_INC_USE_COUNT;
-	else
-		MOD_DEC_USE_COUNT;
-#endif
-}
-
-static struct parport_operations parport_ax_ops = 
-{
-	parport_ax_write_data,
-	parport_ax_read_data,
-
-	parport_ax_write_control,
-	parport_ax_read_control,
-	parport_ax_frob_control,
-
-	parport_ax_read_status,
-
-	parport_ax_enable_irq,
-	parport_ax_disable_irq,
-
-	parport_ax_data_forward,
-	parport_ax_data_reverse,
-
-	parport_ax_interrupt,
-
-	parport_ax_init_state,
-	parport_ax_save_state,
-	parport_ax_restore_state,
-
-	parport_ax_inc_use_count,
-	parport_ax_dec_use_count,
-	parport_ax_fill_inode,
-
-	parport_ieee1284_epp_write_data,
-	parport_ieee1284_epp_read_data,
-	parport_ieee1284_epp_write_addr,
-	parport_ieee1284_epp_read_addr,
-
-	parport_ieee1284_ecp_write_data,
-	parport_ieee1284_ecp_read_data,
-	parport_ieee1284_ecp_write_addr,
-
-	parport_ieee1284_write_compat,
-	parport_ieee1284_read_nibble,
-	parport_ieee1284_read_byte,
-};
-
-
-/******************************************************
- *  MODE detection section:
- */
-
-/*
- * Clear TIMEOUT BIT in EPP MODE
- */
-int parport_ax_epp_clear_timeout(struct parport *pb)
-{
-	unsigned char r;
-
-	if (!(parport_ax_read_status(pb) & 0x01))
-		return 1;
-
-	/* To clear timeout some chips require double read */
-	parport_ax_read_status(pb);
-	r = parport_ax_read_status(pb);
-	parport_ax_write_status(pb, r | 0x01); /* Some reset by writing 1 */
-	parport_ax_write_status(pb, r & 0xfe); /* Others by writing 0 */
-	r = parport_ax_read_status(pb);
-
-	return !(r & 0x01);
-}
-
-/* Check for ECP
- *
- * Old style XT ports alias io ports every 0x400, hence accessing ECONTROL
- * on these cards actually accesses the CTR.
- *
- * Modern cards don't do this but reading from ECONTROL will return 0xff
- * regardless of what is written here if the card does NOT support
- * ECP.
- *
- * We will write 0x2c to ECONTROL and 0xcc to CTR since both of these
- * values are "safe" on the CTR since bits 6-7 of CTR are unused.
- */
-static int parport_ECR_present(struct parport *pb)
-{
-	unsigned int r;
-	unsigned char octr = pb->ops->read_control(pb), 
-	  oecr = pb->ops->read_econtrol(pb);
-
-	r = pb->ops->read_control(pb);	
-	if ((pb->ops->read_econtrol(pb) & 0x3) == (r & 0x3)) {
-		pb->ops->write_control(pb, r ^ 0x2 ); /* Toggle bit 1 */
-
-		r = pb->ops->read_control(pb);	
-		if ((pb->ops->read_econtrol(pb) & 0x2) == (r & 0x2)) {
-			pb->ops->write_control(pb, octr);
-			return 0; /* Sure that no ECONTROL register exists */
-		}
-	}
-	
-	if ((pb->ops->read_econtrol(pb) & 0x3 ) != 0x1)
-		return 0;
-
-	pb->ops->write_econtrol(pb, 0x34);
-	if (pb->ops->read_econtrol(pb) != 0x35)
-		return 0;
-
-	pb->ops->write_econtrol(pb, oecr);
-	pb->ops->write_control(pb, octr);
-	
-	return PARPORT_MODE_PCECR;
-}
-
-static int parport_ECP_supported(struct parport *pb)
-{
-	int i;
-	unsigned char oecr = pb->ops->read_econtrol(pb);
-	
-	/* If there is no ECONTROL, we have no hope of supporting ECP. */
-	if (!(pb->modes & PARPORT_MODE_PCECR))
-		return 0;
-
-	/*
-	 * Using LGS chipset it uses ECONTROL register, but
-	 * it doesn't support ECP or FIFO MODE
-	 */
-	
-	pb->ops->write_econtrol(pb, 0xc0); /* TEST FIFO */
-	for (i=0; i < 1024 && (pb->ops->read_econtrol(pb) & 0x01); i++)
-		pb->ops->write_fifo(pb, 0xaa);
-
-	pb->ops->write_econtrol(pb, oecr);
-	return (i == 1024) ? 0 : PARPORT_MODE_PCECP;
-}
-
-/* Detect PS/2 support.
- *
- * Bit 5 (0x20) sets the PS/2 data direction; setting this high
- * allows us to read data from the data lines.  In theory we would get back
- * 0xff but any peripheral attached to the port may drag some or all of the
- * lines down to zero.  So if we get back anything that isn't the contents
- * of the data register we deem PS/2 support to be present. 
- *
- * Some SPP ports have "half PS/2" ability - you can't turn off the line
- * drivers, but an external peripheral with sufficiently beefy drivers of
- * its own can overpower them and assert its own levels onto the bus, from
- * where they can then be read back as normal.  Ports with this property
- * and the right type of device attached are likely to fail the SPP test,
- * (as they will appear to have stuck bits) and so the fact that they might
- * be misdetected here is rather academic. 
- */
-
-static int parport_PS2_supported(struct parport *pb)
-{
-	int ok = 0;
-	unsigned char octr = pb->ops->read_control(pb);
-  
-	pb->ops->write_control(pb, octr | 0x20);  /* try to tri-state buffer */
-	
-	pb->ops->write_data(pb, 0x55);
-	if (pb->ops->read_data(pb) != 0x55) ok++;
-
-	pb->ops->write_data(pb, 0xaa);
-	if (pb->ops->read_data(pb) != 0xaa) ok++;
-	
-	pb->ops->write_control(pb, octr);          /* cancel input mode */
-
-	return ok ? PARPORT_MODE_PCPS2 : 0;
-}
-
-static int parport_ECPPS2_supported(struct parport *pb)
-{
-	int mode;
-	unsigned char oecr = pb->ops->read_econtrol(pb);
-
-	if (!(pb->modes & PARPORT_MODE_PCECR))
-		return 0;
-	
-	pb->ops->write_econtrol(pb, 0x20);
-	
-	mode = parport_PS2_supported(pb);
-
-	pb->ops->write_econtrol(pb, oecr);
-	return mode ? PARPORT_MODE_PCECPPS2 : 0;
-}
-
-#define printmode(x)					\
-{							\
-	if (p->modes & PARPORT_MODE_PC##x) {		\
-		printk("%s%s", f ? "," : "", #x);	\
-		f++;					\
-	}						\
-}
-
-int
-init_one_port(struct linux_ebus_device *dev)
-{
-	struct parport tmpport, *p;
-	unsigned long base;
-	unsigned long config;
-	unsigned char tmp;
-	int irq, dma;
-
-	/* Pointer to NS87303 Configuration Registers */
-	config = dev->base_address[1];
-
-	/* Setup temporary access to Device operations */
-	tmpport.base = dev->base_address[0];
-	tmpport.ops = &parport_ax_ops;
-
-	/* Enable ECP mode, set bit 2 of the CTR first */
-	tmpport.ops->write_control(&tmpport, 0x04);
-	tmp = ns87303_readb(config, PCR);
-	tmp |= (PCR_EPP_IEEE | PCR_ECP_ENABLE | PCR_ECP_CLK_ENA);
-	ns87303_writeb(config, PCR, tmp);
-
-	/* LPT CTR bit 5 controls direction of parallel port */
-	tmp = ns87303_readb(config, PTR);
-	tmp |= PTR_LPT_REG_DIR;
-	ns87303_writeb(config, PTR, tmp);
-
-	/* Configure IRQ to Push Pull, Level Low */
-	tmp = ns87303_readb(config, PCR);
-	tmp &= ~(PCR_IRQ_ODRAIN);
-	tmp |= PCR_IRQ_POLAR;
-	ns87303_writeb(config, PCR, tmp);
-
-#ifndef HAVE_SLOW_DEVICES
-	/* Enable Zero Wait State for ECP */
-	tmp = ns87303_readb(config, FCR);
-	tmp |= FCR_ZWS_ENA;
-	ns87303_writeb(config, FCR, tmp);
-#endif
-
-	/*
-	 * Now continue initializing the port
-	 */
-	base = dev->base_address[0];
-	irq = dev->irqs[0];
-	dma = PARPORT_DMA_AUTO;
-
-	if (!(p = parport_register_port(base, irq, dma, &parport_ax_ops)))
-		return 0;
-
-	/* Save away pointer to our EBus DMA */
-	p->private_data = (void *)dev->base_address[2];
-
-	p->modes = PARPORT_MODE_PCSPP | parport_PS2_supported(p);
-	if (!check_region(p->base + 0x400, 3)) {
-		p->modes |= parport_ECR_present(p);
-		p->modes |= parport_ECP_supported(p);
-		p->modes |= parport_ECPPS2_supported(p);
-	}
-	p->size = 3;
-
-	if (p->dma == PARPORT_DMA_AUTO)
-		p->dma = (p->modes & PARPORT_MODE_PCECP) ? 0 : PARPORT_DMA_NONE;
-
-	printk(KERN_INFO "%s: PC-style at 0x%lx", p->name, p->base);
-	if (p->irq != PARPORT_IRQ_NONE)
-		printk(", irq %s", __irq_itoa(p->irq));
-	if (p->dma != PARPORT_DMA_NONE)
-		printk(", dma %d", p->dma);
-	printk(" [");
-	{
-		int f = 0;
-		printmode(SPP);
-		printmode(PS2);
-		printmode(ECP);
-		printmode(ECPPS2);
-	}
-	printk("]\n");
-	parport_proc_register(p);
-
-	if (p->irq != PARPORT_IRQ_NONE)
-		if ((err = request_irq(p->irq, parport_ax_interrupt,
-				       0, p->name, p)) != 0)
-			return 0;		/* @@@ FIXME */
-
-	request_region(p->base, p->size, p->name);
-	if (p->modes & PARPORT_MODE_PCECR)
-		request_region(p->base+0x400, 3, p->name);
-	request_region((unsigned long)p->private_data,
-		       sizeof(struct linux_ebus_dma), p->name);
-
-	p->ops->write_control(p, 0x0c);
-	p->ops->write_data(p, 0);
-
-	/* Tell the high-level drivers about the port. */
-	parport_announce_port (p);
-
-	return 1;
-}
-
-EXPORT_NO_SYMBOLS;
-
-#ifdef MODULE
-int init_module(void)
-#else
-__initfunc(int parport_ax_init(void))
-#endif
-{
-	struct linux_ebus *ebus;
-	struct linux_ebus_device *edev;
-	int count = 0;
-
-	for_each_ebus(ebus) {
-		for_each_ebusdev(edev, ebus) {
-			if (!strcmp(edev->prom_name, "ecpp"))
-				count += init_one_port(edev);
-		}
-	}
-	return count ? 0 : -ENODEV;
-}
-
-#ifdef MODULE
-void
-cleanup_module(void)
-{
-	struct parport *p = parport_enumerate(), *tmp;
-	while (p) {
-		tmp = p->next;
-		if (p->modes & PARPORT_MODE_PCSPP) { 
-			if (p->irq != PARPORT_IRQ_NONE) {
-				parport_ax_disable_irq(p);
-				free_irq(p->irq, p);
-			}
-			release_region(p->base, p->size);
-			if (p->modes & PARPORT_MODE_PCECR)
-				release_region(p->base+0x400, 3);
-			release_region((unsigned long)p->private_data,
-				       sizeof(struct linux_ebus_dma));
-			parport_proc_unregister(p);
-			parport_unregister_port(p);
-		}
-		p = tmp;
-	}
-}
-#endif
diff -u --recursive --new-file v2.3.11/linux/drivers/misc/parport_daisy.c linux/drivers/misc/parport_daisy.c
--- v2.3.11/linux/drivers/misc/parport_daisy.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/misc/parport_daisy.c	Wed Dec 31 16:00:00 1969
@@ -1,473 +0,0 @@
-/*
- * IEEE 1284.3 Parallel port daisy chain and multiplexor code
- * 
- * Copyright (C) 1999  Tim Waugh <tim@cyberelk.demon.co.uk>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- * ??-12-1998: Initial implementation.
- * 31-01-1999: Make port-cloning transparent.
- * 13-02-1999: Move DeviceID technique from parport_probe.
- * 13-03-1999: Get DeviceID from non-IEEE 1284.3 devices too.
- *
- */
-
-#include <linux/parport.h>
-#include <linux/delay.h>
-#include <asm/uaccess.h>
-
-#define DEBUG /* undef me for production */
-
-#ifdef DEBUG
-#define DPRINTK(stuff...) printk (stuff)
-#else
-#define DPRINTK(stuff...)
-#endif
-
-static struct daisydev {
-	struct daisydev *next;
-	struct parport *port;
-	int daisy;
-	int devnum;
-} *topology = NULL;
-
-static int numdevs = 0;
-
-/* Forward-declaration of lower-level functions. */
-static int mux_present (struct parport *port);
-static int num_mux_ports (struct parport *port);
-static int select_port (struct parport *port);
-static int assign_addrs (struct parport *port);
-
-/* Add a device to the discovered topology. */
-static void add_dev (int devnum, struct parport *port, int daisy)
-{
-	struct daisydev *newdev;
-	newdev = kmalloc (GFP_KERNEL, sizeof (struct daisydev));
-	if (newdev) {
-		newdev->port = port;
-		newdev->daisy = daisy;
-		newdev->devnum = devnum;
-		newdev->next = topology;
-		if (!topology || topology->devnum >= devnum)
-			topology = newdev;
-		else {
-			struct daisydev *prev = topology;
-			while (prev->next && prev->next->devnum < devnum)
-				prev = prev->next;
-			newdev->next = prev->next;
-			prev->next = newdev;
-		}
-	}
-}
-
-/* Clone a parport (actually, make an alias). */
-static struct parport *clone_parport (struct parport *real, int muxport)
-{
-	struct parport *extra = parport_register_port (real->base,
-						       real->irq,
-						       real->dma,
-						       real->ops);
-	if (extra) {
-		extra->portnum = real->portnum;
-		extra->physport = real;
-		extra->muxport = muxport;
-	}
-
-	return extra;
-}
-
-/* Discover the IEEE1284.3 topology on a port -- muxes and daisy chains. */
-int parport_daisy_init (struct parport *port)
-{
-	char *deviceid;
-	static const char *th[] = { /*0*/"th", "st", "nd", "rd", "th" };
-	int num_ports;
-	int i;
-
-	/* Because this is called before any other devices exist,
-	 * we don't have to claim exclusive access.  */
-
-	/* If mux present on normal port, need to create new
-	 * parports for each extra port. */
-	if (port->muxport < 0 && mux_present (port) &&
-	    /* don't be fooled: a mux must have 2 or 4 ports. */
-	    ((num_ports = num_mux_ports (port)) == 2 || num_ports == 4)) {
-		/* Leave original as port zero. */
-		port->muxport = 0;
-		printk (KERN_INFO
-			"%s: 1st (default) port of %d-way multiplexor\n",
-			port->name, num_ports);
-		for (i = 1; i < num_ports; i++) {
-			/* Clone the port. */
-			struct parport *extra = clone_parport (port, i);
-			if (!extra) {
-				if (signal_pending (current))
-					break;
-
-				schedule ();
-				continue;
-			}
-
-			printk (KERN_INFO
-				"%s: %d%s port of %d-way multiplexor on %s\n",
-				extra->name, i + 1, th[i + 1], num_ports,
-				port->name);
-
-			/* Analyse that port too.  We won't recurse
-			   forever because of the 'port->muxport < 0'
-			   test above. */
-			parport_announce_port (extra);
-		}
-	}
-
-	if (port->muxport >= 0)
-		select_port (port);
-
-	parport_daisy_deselect_all (port);
-	assign_addrs (port);
-
-	/* Count the potential legacy device at the end. */
-	add_dev (numdevs++, port, -1);
-
-	/* Find out the legacy device's IEEE 1284 device ID. */
-	deviceid = kmalloc (1000, GFP_KERNEL);
-	if (deviceid) {
-		parport_device_id (numdevs - 1, deviceid, 1000);
-		kfree (deviceid);
-	}
-
-	return 0;
-}
-
-/* Forget about devices on a physical port. */
-void parport_daisy_fini (struct parport *port)
-{
-	struct daisydev *dev, *prev = topology;
-	while (prev && prev->port == port)
-		prev = topology = topology->next;
-
-	while (prev) {
-		dev = prev->next;
-		if (dev && dev->port == port)
-			prev->next = dev->next;
-
-		prev = prev->next;
-	}
-
-	/* Gaps in the numbering could be handled better.  How should
-           someone enumerate through all IEEE1284.3 devices in the
-           topology?. */
-	if (!topology) numdevs = 0;
-	return; }
-
-/* Find a device by canonical device number. */
-struct pardevice *parport_open (int devnum, const char *name,
-				int (*pf) (void *), void (*kf) (void *),
-				void (*irqf) (int, void *, struct pt_regs *),
-				int flags, void *handle)
-{
-	struct parport *port = parport_enumerate ();
-	struct pardevice *dev;
-	int portnum;
-	int muxnum;
-	int daisynum;
-
-	if (parport_device_coords (devnum,  &portnum, &muxnum, &daisynum))
-		return NULL;
-
-	while (port && ((port->portnum != portnum) ||
-			(port->muxport != muxnum)))
-		port = port->next;
-
-	if (!port)
-		/* No corresponding parport. */
-		return NULL;
-
-	dev = parport_register_device (port, name, pf, kf,
-				       irqf, flags, handle);
-	if (dev)
-		dev->daisy = daisynum;
-
-	/* Check that there really is a device to select. */
-	if (daisynum >= 0) {
-		int selected;
-		parport_claim_or_block (dev);
-		selected = port->daisy;
-		parport_release (dev);
-
-		if (selected != port->daisy) {
-			/* No corresponding device. */
-			parport_unregister_device (dev);
-			return NULL;
-		}
-	}
-
-	return dev;
-}
-
-/* The converse of parport_open. */
-void parport_close (struct pardevice *dev)
-{
-	parport_unregister_device (dev);
-}
-
-/* Convert device coordinates into a canonical device number. */
-int parport_device_num (int parport, int mux, int daisy)
-{
-	struct daisydev *dev = topology;
-
-	while (dev && dev->port->portnum != parport &&
-	       dev->port->muxport != mux && dev->daisy != daisy)
-		dev = dev->next;
-
-	if (!dev)
-		return -ENXIO;
-
-	return dev->devnum;
-}
-
-/* Convert a canonical device number into device coordinates. */
-int parport_device_coords (int devnum, int *parport, int *mux, int *daisy)
-{
-	struct daisydev *dev = topology;
-
-	while (dev && dev->devnum != devnum)
-		dev = dev->next;
-
-	if (!dev)
-		return -ENXIO;
-
-	if (parport) *parport = dev->port->portnum;
-	if (mux) *mux = dev->port->muxport;
-	if (daisy) *daisy = dev->daisy;
-	return 0;
-}
-
-/* Send a daisy-chain-style CPP command packet. */
-static int cpp_daisy (struct parport *port, int cmd)
-{
-	unsigned char s;
-
-	parport_write_data (port, 0xaa); udelay (2);
-	parport_write_data (port, 0x55); udelay (2);
-	parport_write_data (port, 0x00); udelay (2);
-	parport_write_data (port, 0xff); udelay (2);
-	s = parport_read_status (port) & (PARPORT_STATUS_BUSY
-					  | PARPORT_STATUS_PAPEROUT
-					  | PARPORT_STATUS_SELECT
-					  | PARPORT_STATUS_ERROR);
-	if (s != (PARPORT_STATUS_BUSY
-		  | PARPORT_STATUS_PAPEROUT
-		  | PARPORT_STATUS_SELECT
-		  | PARPORT_STATUS_ERROR)) {
-		DPRINTK (KERN_DEBUG "%s: cpp_daisy: aa5500ff(%02x)\n",
-			 port->name, s);
-		return -ENXIO;
-	}
-
-	parport_write_data (port, 0x87); udelay (2);
-	s = parport_read_status (port) & (PARPORT_STATUS_BUSY
-					  | PARPORT_STATUS_PAPEROUT
-					  | PARPORT_STATUS_SELECT
-					  | PARPORT_STATUS_ERROR);
-	if (s != (PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR)) {
-		DPRINTK (KERN_DEBUG "%s: cpp_daisy: aa5500ff87(%02x)\n",
-			 port->name, s);
-		return -ENXIO;
-	}
-
-	parport_write_data (port, 0x78); udelay (2);
-	parport_write_data (port, cmd); udelay (2);
-	parport_frob_control (port,
-			      PARPORT_CONTROL_STROBE,
-			      PARPORT_CONTROL_STROBE);
-	udelay (1);
-	parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
-	udelay (1);
-	s = parport_read_status (port);
-	parport_write_data (port, 0xff); udelay (2);
-
-	return s;
-}
-
-/* Send a mux-style CPP command packet. */
-static int cpp_mux (struct parport *port, int cmd)
-{
-	unsigned char s;
-	int rc;
-
-	parport_write_data (port, 0xaa); udelay (2);
-	parport_write_data (port, 0x55); udelay (2);
-	parport_write_data (port, 0xf0); udelay (2);
-	parport_write_data (port, 0x0f); udelay (2);
-	parport_write_data (port, 0x52); udelay (2);
-	parport_write_data (port, 0xad); udelay (2);
-	parport_write_data (port, cmd); udelay (2);
-
-	s = parport_read_status (port);
-	if (!(s & PARPORT_STATUS_ACK)) {
-		DPRINTK (KERN_DEBUG "%s: cpp_mux: aa55f00f52ad%02x(%02x)\n",
-			 port->name, cmd, s);
-		return -EIO;
-	}
-
-	rc = (((s & PARPORT_STATUS_SELECT   ? 1 : 0) << 0) |
-	      ((s & PARPORT_STATUS_PAPEROUT ? 1 : 0) << 1) |
-	      ((s & PARPORT_STATUS_BUSY     ? 0 : 1) << 2) |
-	      ((s & PARPORT_STATUS_ERROR    ? 0 : 1) << 3));
-
-	return rc;
-}
-
-void parport_daisy_deselect_all (struct parport *port)
-{
-	cpp_daisy (port, 0x30);
-}
-
-int parport_daisy_select (struct parport *port, int daisy, int mode)
-{
-	/* mode is currently ignored. FIXME? */
-	return cpp_daisy (port, 0xe0 + daisy) & PARPORT_STATUS_ERROR;
-}
-
-static int mux_present (struct parport *port)
-{
-	return cpp_mux (port, 0x51) == 3;
-}
-
-static int num_mux_ports (struct parport *port)
-{
-	return cpp_mux (port, 0x58);
-}
-
-static int select_port (struct parport *port)
-{
-	int muxport = port->muxport;
-	return cpp_mux (port, 0x60 + muxport) == muxport;
-}
-
-static int assign_addrs (struct parport *port)
-{
-	unsigned char s, last_dev;
-	unsigned char daisy;
-	int thisdev = numdevs;
-	char *deviceid;
-
-	parport_write_data (port, 0xaa); udelay (2);
-	parport_write_data (port, 0x55); udelay (2);
-	parport_write_data (port, 0x00); udelay (2);
-	parport_write_data (port, 0xff); udelay (2);
-	s = parport_read_status (port) & (PARPORT_STATUS_BUSY
-					  | PARPORT_STATUS_PAPEROUT
-					  | PARPORT_STATUS_SELECT
-					  | PARPORT_STATUS_ERROR);
-	if (s != (PARPORT_STATUS_BUSY
-		  | PARPORT_STATUS_PAPEROUT
-		  | PARPORT_STATUS_SELECT
-		  | PARPORT_STATUS_ERROR)) {
-		DPRINTK (KERN_DEBUG "%s: assign_addrs: aa5500ff(%02x)\n",
-			 port->name, s);
-		return -ENXIO;
-	}
-
-	parport_write_data (port, 0x87); udelay (2);
-	s = parport_read_status (port) & (PARPORT_STATUS_BUSY
-					  | PARPORT_STATUS_PAPEROUT
-					  | PARPORT_STATUS_SELECT
-					  | PARPORT_STATUS_ERROR);
-	if (s != (PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR)) {
-		DPRINTK (KERN_DEBUG "%s: assign_addrs: aa5500ff87(%02x)\n",
-			 port->name, s);
-		return -ENXIO;
-	}
-
-	parport_write_data (port, 0x78); udelay (2);
-	last_dev = 0; /* We've just been speaking to a device, so we
-			 know there must be at least _one_ out there. */
-
-	for (daisy = 0; daisy < 4; daisy++) {
-		parport_write_data (port, daisy);
-		udelay (2);
-		parport_frob_control (port,
-				      PARPORT_CONTROL_STROBE,
-				      PARPORT_CONTROL_STROBE);
-		udelay (1);
-		parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
-		udelay (1);
-
-		if (last_dev)
-			/* No more devices. */
-			break;
-
-		last_dev = !(parport_read_status (port)
-			     & PARPORT_STATUS_BUSY);
-
-		add_dev (numdevs++, port, daisy);
-	}
-
-	parport_write_data (port, 0xff); udelay (2);
-	DPRINTK (KERN_DEBUG "%s: Found %d daisy-chained devices\n", port->name,
-		numdevs - thisdev);
-
-	/* Ask the new devices to introduce themselves. */
-	deviceid = kmalloc (1000, GFP_KERNEL);
-	if (!deviceid) return 0;
-
-	for (daisy = 0; thisdev < numdevs; thisdev++, daisy++)
-		parport_device_id (thisdev, deviceid, 1000);
-
-	kfree (deviceid);
-	return 0;
-}
-
-/* Find a device with a particular manufacturer and model string,
-   starting from a given device number.  Like the PCI equivalent,
-   'from' itself is skipped. */
-int parport_find_device (const char *mfg, const char *mdl, int from)
-{
-	struct daisydev *d = topology; /* sorted by devnum */
-
-	/* Find where to start. */
-	while (d && d->devnum <= from)
-		d = d->next;
-
-	/* Search. */
-	while (d) {
-		struct parport_device_info *info;
-		info = &d->port->probe_info[1 + d->daisy];
-		if ((!mfg || !strcmp (mfg, info->mfr)) &&
-		    (!mdl || !strcmp (mdl, info->model)))
-			break;
-
-		d = d->next;
-	}
-
-	if (d)
-		return d->devnum;
-
-	return -1;
-}
-
-/* Find a device in a particular class.  Like the PCI equivalent,
-   'from' itself is skipped. */
-int parport_find_class (parport_device_class cls, int from)
-{
-	struct daisydev *d = topology; /* sorted by devnum */
-
-	/* Find where to start. */
-	while (d && d->devnum <= from)
-		d = d->next;
-
-	/* Search. */
-	while (d && d->port->probe_info[1 + d->daisy].class != cls)
-		d = d->next;
-
-	if (d)
-		return d->devnum;
-
-	return -1;
-}
diff -u --recursive --new-file v2.3.11/linux/drivers/misc/parport_ieee1284.c linux/drivers/misc/parport_ieee1284.c
--- v2.3.11/linux/drivers/misc/parport_ieee1284.c	Wed Jul 21 15:46:48 1999
+++ linux/drivers/misc/parport_ieee1284.c	Wed Dec 31 16:00:00 1969
@@ -1,545 +0,0 @@
-/* $Id: parport_ieee1284.c,v 1.4 1997/10/19 21:37:21 philip Exp $
- * IEEE-1284 implementation for parport.
- *
- * Authors: Phil Blundell <Philip.Blundell@pobox.com>
- *          Carsten Gross <carsten@sol.wohnheim.uni-ulm.de>
- *	    Jose Renau <renau@acm.org>
- *          Tim Waugh <tim@cyberelk.demon.co.uk> (largely rewritten)
- *
- * This file is responsible for IEEE 1284 negotiation, and for handing
- * read/write requests to low-level drivers.
- */
-
-#include <linux/config.h>
-#include <linux/threads.h>
-#include <linux/parport.h>
-#include <linux/delay.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-
-#undef DEBUG /* undef me for production */
-
-#ifdef CONFIG_LP_CONSOLE
-#undef DEBUG /* Don't want a garbled console */
-#endif
-
-#ifdef DEBUG
-#define DPRINTK(stuff...) printk (stuff)
-#else
-#define DPRINTK(stuff...)
-#endif
-
-/* Make parport_wait_peripheral wake up.
- * It will be useful to call this from an interrupt handler. */
-void parport_ieee1284_wakeup (struct parport *port)
-{
-	up (&port->physport->ieee1284.irq);
-}
-
-static struct parport *port_from_cookie[PARPORT_MAX];
-static void timeout_waiting_on_port (unsigned long cookie)
-{
-	parport_ieee1284_wakeup (port_from_cookie[cookie % PARPORT_MAX]);
-}
-
-/* Wait for a parport_ieee1284_wakeup.
- * 0:      success
- * <0:     error (exit as soon as possible)
- * >0:     timed out
- */
-int parport_wait_event (struct parport *port, signed long timeout)
-{
-	int ret;
-	struct timer_list timer;
-
-	if (!port->physport->cad->timeout)
-		/* Zero timeout is special, and we can't down() the
-		   semaphore. */
-		return 1;
-
-	init_timer (&timer);
-	timer.expires = jiffies + timeout;
-	timer.function = timeout_waiting_on_port;
-	port_from_cookie[port->number % PARPORT_MAX] = port;
-	timer.data = port->number;
-
-	add_timer (&timer);
-	ret = down_interruptible (&port->physport->ieee1284.irq);
-	if (!del_timer (&timer) && !ret)
-		/* Timed out. */
-		ret = 1;
-
-	return ret;
-}
-
-/* Wait for Status line(s) to change in 35 ms - see IEEE1284-1994 page 24 to
- * 25 for this. After this time we can create a timeout because the
- * peripheral doesn't conform to IEEE1284.  We want to save CPU time: we are
- * waiting a maximum time of 500 us busy (this is for speed).  If there is
- * not the right answer in this time, we call schedule and other processes
- * are able to eat the time up to 40ms.
- */ 
-
-int parport_wait_peripheral(struct parport *port,
-			    unsigned char mask, 
-			    unsigned char result)
-{
-	int counter;
-	long deadline;
-	unsigned char status;
-
-	counter = port->physport->spintime; /* usecs of fast polling */
-	if (!port->physport->cad->timeout)
-		/* A zero timeout is "special": busy wait for the
-		   entire 35ms. */
-		counter = 35000;
-
-	/* Fast polling.
-	 *
-	 * This should be adjustable.
-	 * How about making a note (in the device structure) of how long
-	 * it takes, so we know for next time?
-	 */
-	for (counter /= 5; counter > 0; counter--) {
-		status = parport_read_status (port);
-		if ((status & mask) == result)
-			return 0;
-		if (signal_pending (current))
-			return -EINTR;
-		if (current->need_resched)
-			break;
-		udelay(5);
-	}
-
-	if (!port->physport->cad->timeout)
-		/* We may be in an interrupt handler, so we can't poll
-		 * slowly anyway. */
-		return 1;
-
-	/* 40ms of slow polling. */
-	deadline = jiffies + (HZ + 24) / 25;
-	while (time_before (jiffies, deadline)) {
-		int ret;
-
-		if (signal_pending (current))
-			return -EINTR;
-
-		/* Wait for 10ms (or until an interrupt occurs if
-		 * the handler is set) */
-		if ((ret = parport_wait_event (port, (HZ + 99) / 100)) < 0)
-			return ret;
-
-		status = parport_read_status (port);
-		if ((status & mask) == result)
-			return 0;
-
-		if (!ret) {
-			/* parport_wait_event didn't time out, but the
-			 * peripheral wasn't actually ready either.
-			 * Wait for another 10ms. */
-			current->state = TASK_INTERRUPTIBLE;
-			schedule_timeout ((HZ+ 99) / 100);
-		}
-	}
-
-	return 1;
-}
-
-#ifdef CONFIG_PARPORT_1284
-/* Terminate a negotiated mode. */
-static void parport_ieee1284_terminate (struct parport *port)
-{
-	port = port->physport;
-
-	port->ieee1284.phase = IEEE1284_PH_TERMINATE;
-
-	/* EPP terminates differently. */
-	switch (port->ieee1284.mode) {
-	case IEEE1284_MODE_EPP:
-	case IEEE1284_MODE_EPPSL:
-	case IEEE1284_MODE_EPPSWE:
-		/* Terminate from EPP mode. */
-
-		/* Event 68: Set nInit low */
-		parport_frob_control (port,
-				      PARPORT_CONTROL_INIT,
-				      PARPORT_CONTROL_INIT);
-		udelay (50);
-
-		/* Event 69: Set nInit high, nSelectIn low */
-		parport_frob_control (port,
-				      PARPORT_CONTROL_SELECT,
-				      PARPORT_CONTROL_SELECT);
-		break;
-		
-	default:
-		/* Terminate from all other modes. */
-
-		/* Event 22: Set nSelectIn low, nAutoFd high */
-		parport_frob_control (port,
-				      PARPORT_CONTROL_SELECT
-				      | PARPORT_CONTROL_AUTOFD,
-				      PARPORT_CONTROL_SELECT);
-
-		/* Event 24: nAck goes low */
-		parport_wait_peripheral (port, PARPORT_STATUS_ACK, 0);
-
-		/* Event 25: Set nAutoFd low */
-		parport_frob_control (port,
-				      PARPORT_CONTROL_AUTOFD,
-				      PARPORT_CONTROL_AUTOFD);
-
-		/* Event 27: nAck goes high */
-		parport_wait_peripheral (port,
-					 PARPORT_STATUS_ACK, 
-					 PARPORT_STATUS_ACK);
-
-		/* Event 29: Set nAutoFd high */
-		parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
-	}
-
-	port->ieee1284.mode = IEEE1284_MODE_COMPAT;
-	port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
-
-	DPRINTK (KERN_DEBUG "%s: In compatibility (forward idle) mode\n",
-		 port->name);
-}		
-#endif /* IEEE1284 support */
-
-/* Negotiate an IEEE 1284 mode.
- * return values are:
- *   0 - handshake OK; IEEE1284 peripheral and mode available
- *  -1 - handshake failed; peripheral is not compliant (or none present)
- *   1 - handshake OK; IEEE1284 peripheral present but mode not available
- */
-int parport_negotiate (struct parport *port, int mode)
-{
-#ifndef CONFIG_PARPORT_1284
-	if (mode == IEEE1284_MODE_COMPAT)
-		return 0;
-	printk (KERN_ERR "parport: IEEE1284 not supported in this kernel\n");
-	return -1;
-#else
-	int m = mode & ~IEEE1284_ADDR;
-	unsigned char xflag;
-
-	port = port->physport;
-
-	/* Is there anything to do? */
-	if (port->ieee1284.mode == mode)
-		return 0;
-
-	/* Is the difference just an address-or-not bit? */
-	if ((port->ieee1284.mode & ~IEEE1284_ADDR) == (mode & ~IEEE1284_ADDR)){
-		port->ieee1284.mode = mode;
-		return 0;
-	}
-
-	/* Go to compability forward idle mode */
-	if (port->ieee1284.mode != IEEE1284_MODE_COMPAT)
-		parport_ieee1284_terminate (port);
-
-	if (mode == IEEE1284_MODE_COMPAT)
-		/* Compatibility mode: no negotiation. */
-		return 0; 
-
-	switch (mode) {
-	case IEEE1284_MODE_ECPSWE:
-		m = IEEE1284_MODE_ECP;
-		break;
-	case IEEE1284_MODE_EPPSL:
-	case IEEE1284_MODE_EPPSWE:
-		m = IEEE1284_MODE_EPP;
-		break;
-	case IEEE1284_MODE_BECP:
-		return -ENOSYS; /* FIXME (implement BECP) */
-	}
-
-	port->ieee1284.phase = IEEE1284_PH_NEGOTIATION;
-
-	/* Start off with nStrobe and nAutoFd high, and nSelectIn low */
-	parport_frob_control (port,
-			      PARPORT_CONTROL_STROBE
-			      | PARPORT_CONTROL_AUTOFD
-			      | PARPORT_CONTROL_SELECT,
-			      PARPORT_CONTROL_SELECT);
-	udelay(1);
-
-	/* Event 0: Set data */
-	parport_write_data (port, m);
-	udelay (400); /* Shouldn't need to wait this long. */
-
-	/* Event 1: Set nSelectIn high, nAutoFd low */
-	parport_frob_control (port,
-			      PARPORT_CONTROL_SELECT
-			      | PARPORT_CONTROL_AUTOFD,
-			      PARPORT_CONTROL_AUTOFD);
-
-	/* Event 2: PError, Select, nFault go high, nAck goes low */
-	if (parport_wait_peripheral (port,
-				     PARPORT_STATUS_ERROR
-				     | PARPORT_STATUS_SELECT
-				     | PARPORT_STATUS_PAPEROUT
-				     | PARPORT_STATUS_ACK,
-				     PARPORT_STATUS_ERROR
-				     | PARPORT_STATUS_SELECT
-				     | PARPORT_STATUS_PAPEROUT)) {
-		/* Timeout */
-		parport_frob_control (port,
-				      PARPORT_CONTROL_SELECT
-				      | PARPORT_CONTROL_AUTOFD,
-				      PARPORT_CONTROL_SELECT);
-		DPRINTK (KERN_DEBUG
-			 "%s: Peripheral not IEEE1284 compliant (0x%02X)\n",
-			 port->name, parport_read_status (port));
-		port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
-		return -1; /* Not IEEE1284 compliant */
-	}
-
-	/* Event 3: Set nStrobe low */
-	parport_frob_control (port,
-			      PARPORT_CONTROL_STROBE,
-			      PARPORT_CONTROL_STROBE);
-
-	/* Event 4: Set nStrobe and nAutoFd high */
-	udelay (5);
-	parport_frob_control (port,
-			      PARPORT_CONTROL_STROBE
-			      | PARPORT_CONTROL_AUTOFD,
-			      0);
-
-	/* Event 6: nAck goes high */
-	if (parport_wait_peripheral (port,
-				     PARPORT_STATUS_ACK
-				     | PARPORT_STATUS_PAPEROUT,
-				     PARPORT_STATUS_ACK)) {
-		if (parport_read_status (port) & PARPORT_STATUS_ACK)
-			printk (KERN_DEBUG
-				"%s: working around buggy peripheral: tell "
-				"Tim what make it is\n", port->name);
-		DPRINTK (KERN_DEBUG
-			 "%s: Mode 0x%02x not supported? (0x%02x)\n",
-			 port->name, mode, port->ops->read_status (port));
-		parport_ieee1284_terminate (port);
-		return 1;
-	}
-
-	xflag = parport_read_status (port) & PARPORT_STATUS_SELECT;
-
-	/* xflag should be high for all modes other than nibble (0). */
-	if (mode && !xflag) {
-		/* Mode not supported. */
-		DPRINTK (KERN_DEBUG "%s: Mode 0x%02x not supported\n",
-			 port->name, mode);
-		parport_ieee1284_terminate (port);
-		return 1;
-	}
-
-	/* Mode is supported */
-	DPRINTK (KERN_DEBUG "%s: In mode 0x%02x\n", port->name, mode);
-	port->ieee1284.mode = mode;
-
-	/* But ECP is special */
-	if (mode & IEEE1284_MODE_ECP) {
-		port->ieee1284.phase = IEEE1284_PH_ECP_SETUP;
-
-		/* Event 30: Set nAutoFd low */
-		parport_frob_control (port,
-				      PARPORT_CONTROL_AUTOFD,
-				      PARPORT_CONTROL_AUTOFD);
-
-		/* Event 31: PError goes high. */
-		parport_wait_peripheral (port,
-					 PARPORT_STATUS_PAPEROUT,
-					 PARPORT_STATUS_PAPEROUT);
-		/* (Should check that this works..) */
-
-		port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
-		DPRINTK (KERN_DEBUG "%s: ECP direction: forward\n",
-			 port->name);
-	} else switch (mode) {
-	case IEEE1284_MODE_NIBBLE:
-	case IEEE1284_MODE_BYTE:
-		port->ieee1284.phase = IEEE1284_PH_REV_IDLE;
-		break;
-	default:
-		port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
-	}
-
-
-	return 0;
-#endif /* IEEE1284 support */
-}
-
-/* Acknowledge that the peripheral has data available.
- * Events 18-20, in order to get from Reverse Idle phase
- * to Host Busy Data Available.
- * This will most likely be called from an interrupt.
- * Returns zero if data was available.
- */
-#ifdef CONFIG_PARPORT_1284
-static int parport_ieee1284_ack_data_avail (struct parport *port)
-{
-	if (parport_read_status (port) & PARPORT_STATUS_ERROR)
-		/* Event 18 didn't happen. */
-		return -1;
-
-	/* Event 20: nAutoFd goes high. */
-	port->ops->frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
-	port->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL;
-	return 0;
-}
-#endif /* IEEE1284 support */
-
-/* Handle an interrupt. */
-void parport_ieee1284_interrupt (int which, void *handle, struct pt_regs *regs)
-{
-	struct parport *port = handle;
-	parport_ieee1284_wakeup (port);
-
-#ifdef CONFIG_PARPORT_1284
-	if (port->ieee1284.phase == IEEE1284_PH_REV_IDLE) {
-		/* An interrupt in this phase means that data
-		 * is now available. */
-		DPRINTK (KERN_DEBUG "%s: Data available\n", port->name);
-		parport_ieee1284_ack_data_avail (port);
-	}
-#endif /* IEEE1284 support */
-}
-
-/* Write a block of data. */
-ssize_t parport_write (struct parport *port, const void *buffer, size_t len)
-{
-#ifndef CONFIG_PARPORT_1284
-	return port->ops->compat_write_data (port, buffer, len, 0);
-#else
-	ssize_t retval;
-	int mode = port->ieee1284.mode;
-	int addr = mode & IEEE1284_ADDR;
-	size_t (*fn) (struct parport *, const void *, size_t, int);
-
-	/* Ignore the device-ID-request bit and the address bit. */
-	mode &= ~(IEEE1284_DEVICEID | IEEE1284_ADDR);
-
-	/* Use the mode we're in. */
-	switch (mode) {
-	case IEEE1284_MODE_NIBBLE:
-		parport_negotiate (port, IEEE1284_MODE_COMPAT);
-	case IEEE1284_MODE_COMPAT:
-		DPRINTK (KERN_DEBUG "%s: Using compatibility mode\n",
-			 port->name);
-		fn = port->ops->compat_write_data;
-		break;
-
-	case IEEE1284_MODE_EPP:
-		DPRINTK (KERN_DEBUG "%s: Using EPP mode\n", port->name);
-		if (addr)
-			fn = port->ops->epp_write_addr;
-		else
-			fn = port->ops->epp_write_data;
-		break;
-
-	case IEEE1284_MODE_ECP:
-	case IEEE1284_MODE_ECPRLE:
-		DPRINTK (KERN_DEBUG "%s: Using ECP mode\n", port->name);
-		if (addr)
-			fn = port->ops->ecp_write_addr;
-		else
-			fn = port->ops->ecp_write_data;
-		break;
-
-	case IEEE1284_MODE_ECPSWE:
-		DPRINTK (KERN_DEBUG "%s: Using software-emulated ECP mode\n",
-			 port->name);
-		/* The caller has specified that it must be emulated,
-		 * even if we have ECP hardware! */
-		if (addr)
-			fn = parport_ieee1284_ecp_write_addr;
-		else
-			fn = parport_ieee1284_ecp_write_data;
-		break;
-
-	default:
-		DPRINTK (KERN_DEBUG "%s: Unknown mode 0x%02x\n", port->name,
-			port->ieee1284.mode);
-		return -ENOSYS;
-	}
-
-	retval = (*fn) (port, buffer, len, 0);
-	DPRINTK (KERN_DEBUG "%s: wrote %d/%d bytes\n", port->name, retval,
-		 len);
-	return retval;
-#endif /* IEEE1284 support */
-}
-
-/* Read a block of data. */
-ssize_t parport_read (struct parport *port, void *buffer, size_t len)
-{
-#ifndef CONFIG_PARPORT_1284
-	printk (KERN_ERR "parport: IEEE1284 not supported in this kernel\n");
-	return -ENODEV;
-#else
-	int mode = port->physport->ieee1284.mode;
-	int addr = mode & IEEE1284_ADDR;
-	size_t (*fn) (struct parport *, void *, size_t, int);
-
-	/* Ignore the device-ID-request bit and the address bit. */
-	mode &= ~(IEEE1284_DEVICEID | IEEE1284_ADDR);
-
-	/* Use the mode we're in. */
-	switch (mode) {
-	case IEEE1284_MODE_COMPAT:
-		if (parport_negotiate (port, IEEE1284_MODE_NIBBLE))
-			return -EIO;
-	case IEEE1284_MODE_NIBBLE:
-		DPRINTK (KERN_DEBUG "%s: Using nibble mode\n", port->name);
-		fn = port->ops->nibble_read_data;
-		break;
-
-	case IEEE1284_MODE_BYTE:
-		DPRINTK (KERN_DEBUG "%s: Using byte mode\n", port->name);
-		fn = port->ops->byte_read_data;
-		break;
-
-	case IEEE1284_MODE_EPP:
-		DPRINTK (KERN_DEBUG "%s: Using EPP mode\n", port->name);
-		if (addr)
-			fn = port->ops->epp_read_addr;
-		else
-			fn = port->ops->epp_read_data;
-		break;
-
-	case IEEE1284_MODE_ECP:
-	case IEEE1284_MODE_ECPRLE:
-		DPRINTK (KERN_DEBUG "%s: Using ECP mode\n", port->name);
-		fn = port->ops->ecp_read_data;
-		break;
-
-	case IEEE1284_MODE_ECPSWE:
-		DPRINTK (KERN_DEBUG "%s: Using software-emulated ECP mode\n",
-			 port->name);
-		fn = parport_ieee1284_ecp_read_data;
-		break;
-
-	default:
-		DPRINTK (KERN_DEBUG "%s: Unknown mode 0x%02x\n", port->name,
-			 port->physport->ieee1284.mode);
-		return -ENOSYS;
-	}
-
-	return (*fn) (port, buffer, len, 0);
-#endif /* IEEE1284 support */
-}
-
-/* Set the amount of time we wait while nothing's happening. */
-long parport_set_timeout (struct pardevice *dev, long inactivity)
-{
-	long int old = dev->timeout;
-
-	dev->timeout = inactivity;
-
-	if (dev->port->physport->cad == dev)
-		parport_ieee1284_wakeup (dev->port);
-
-	return old;
-}
diff -u --recursive --new-file v2.3.11/linux/drivers/misc/parport_ieee1284_ops.c linux/drivers/misc/parport_ieee1284_ops.c
--- v2.3.11/linux/drivers/misc/parport_ieee1284_ops.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/misc/parport_ieee1284_ops.c	Wed Dec 31 16:00:00 1969
@@ -1,848 +0,0 @@
-/* IEEE-1284 operations for parport.
- *
- * This file is for generic IEEE 1284 operations.  The idea is that
- * they are used by the low-level drivers.  If they have a special way
- * of doing something, they can provide their own routines (and put
- * the function pointers in port->ops); if not, they can just use these
- * as a fallback.
- *
- * Note: Make no assumptions about hardware or architecture in this file!
- *
- * Author: Tim Waugh <tim@cyberelk.demon.co.uk>
- */
-
-#include <linux/config.h>
-#include <linux/parport.h>
-#include <linux/delay.h>
-#include <asm/uaccess.h>
-
-#define DEBUG /* undef me for production */
-
-#ifdef CONFIG_LP_CONSOLE
-#undef DEBUG /* Don't want a garbled console */
-#endif
-
-#ifdef DEBUG
-#define DPRINTK(stuff...) printk (stuff)
-#else
-#define DPRINTK(stuff...)
-#endif
-
-/***                                *
- * One-way data transfer functions. *
- *                                ***/
-
-static inline
-int polling (struct pardevice *dev)
-{
-	return dev->port->irq == PARPORT_IRQ_NONE;
-}
-
-/* Compatibility mode. */
-size_t parport_ieee1284_write_compat (struct parport *port,
-				      const void *buffer, size_t len,
-				      int flags)
-{
-	ssize_t count = 0;
-	const unsigned char *addr = buffer;
-	unsigned char byte;
-	struct pardevice *dev = port->physport->cad;
-	unsigned char ctl = (PARPORT_CONTROL_SELECT
-			     | PARPORT_CONTROL_INIT);
-
-	if (port->irq != PARPORT_IRQ_NONE)
-		parport_enable_irq (port);
-
-	port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
-	while (count < len) {
-		long expire = jiffies + dev->timeout;
-		long wait = (HZ + 99) / 100;
-		unsigned char mask = (PARPORT_STATUS_ERROR
-				      | PARPORT_STATUS_BUSY);
-		unsigned char val = (PARPORT_STATUS_ERROR
-				     | PARPORT_STATUS_BUSY);
-		int i;
-
-		/* Write the character to the data lines. */
-		byte = *addr++;
-		parport_write_data (port, byte);
-		udelay (1);
-
-		/* Wait until the peripheral's ready */
-		do {
-			/* Is the peripheral ready yet? */
-			if (!parport_wait_peripheral (port, mask, val))
-				/* Skip the loop */
-				goto ready;
-
-			/* Is the peripheral upset? */
-			if ((parport_read_status (port) &
-			     (PARPORT_STATUS_PAPEROUT |
-			      PARPORT_STATUS_SELECT |
-			      PARPORT_STATUS_ERROR))
-			    != (PARPORT_STATUS_SELECT |
-				PARPORT_STATUS_ERROR))
-				/* If nFault is asserted (i.e. no
-				 * error) and PAPEROUT and SELECT are
-				 * just red herrings, give the driver
-				 * a chance to check it's happy with
-				 * that before continuing. */
-				goto stop;
-
-			/* Have we run out of time? */
-			if (!time_before (jiffies, expire))
-				break;
-
-			/* Yield the port for a while.  If this is the
-                           first time around the loop, don't let go of
-                           the port.  This way, we find out if we have
-                           our interrupt handler called. */
-			if (count && polling (dev)) {
-				parport_release (dev);
-				current->state = TASK_INTERRUPTIBLE;
-				schedule_timeout (wait);
-				parport_claim_or_block (dev);
-			}
-			else
-				/* We must have the device claimed here */
-				parport_wait_event (port, wait);
-
-			/* Is there a signal pending? */
-			if (signal_pending (current))
-				goto stop;
-
-			/* Wait longer next time. */
-			wait *= 2;
-		} while (time_before (jiffies, expire));
-
-		DPRINTK (KERN_DEBUG "%s: Timed out\n", port->name);
-		break;
-
-	ready:
-		/* Clear out previous irqs. */
-		while (!down_trylock (&port->physport->ieee1284.irq));
-
-		/* Pulse strobe. */
-		parport_write_control (port, ctl | PARPORT_CONTROL_STROBE);
-		udelay (1); /* strobe */
-
-		parport_write_control (port, ctl);
-		udelay (1); /* hold */
-
-		/* Wait until it's received (up to 20us). */
-		for (i = 0; i < 20; i++) {
-			if (!down_trylock (&port->physport->ieee1284.irq) ||
-			    !(parport_read_status (port) & PARPORT_STATUS_ACK))
-				break;
-			udelay (1);
-		}
-
-		count++;
-
-                /* Let another process run if it needs to. */
-		if (time_before (jiffies, expire))
-			if (!parport_yield_blocking (dev)
-			    && current->need_resched)
-				schedule ();
-	}
- stop:
-	port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
-
-	return count;
-}
-
-/* Nibble mode. */
-size_t parport_ieee1284_read_nibble (struct parport *port, 
-				     void *buffer, size_t len,
-				     int flags)
-{
-#ifndef CONFIG_PARPORT_1284
-	return 0;
-#else
-	unsigned char *buf = buffer;
-	int i;
-	unsigned char byte = 0;
-
-	len *= 2; /* in nibbles */
-	for (i=0; i < len; i++) {
-		unsigned char nibble;
-
-		/* Does the error line indicate end of data? */
-		if (((i & 1) == 0) &&
-		    (parport_read_status(port) & PARPORT_STATUS_ERROR)) {
-			port->physport->ieee1284.phase = IEEE1284_PH_HBUSY_DNA;
-			DPRINTK (KERN_DEBUG
-				"%s: No more nibble data (%d bytes)\n",
-				port->name, i/2);
-
-			/* Go to reverse idle phase. */
-			parport_frob_control (port,
-					      PARPORT_CONTROL_AUTOFD,
-					      PARPORT_CONTROL_AUTOFD);
-			port->physport->ieee1284.phase = IEEE1284_PH_REV_IDLE;
-			break;
-		}
-
-		/* Event 7: Set nAutoFd low. */
-		parport_frob_control (port,
-				      PARPORT_CONTROL_AUTOFD,
-				      PARPORT_CONTROL_AUTOFD);
-
-		/* Event 9: nAck goes low. */
-		port->ieee1284.phase = IEEE1284_PH_REV_DATA;
-		if (parport_wait_peripheral (port,
-					     PARPORT_STATUS_ACK, 0)) {
-			/* Timeout -- no more data? */
-			DPRINTK (KERN_DEBUG
-				 "%s: Nibble timeout at event 9 (%d bytes)\n",
-				 port->name, i/2);
-			break;
-		}
-
-
-		/* Read a nibble. */
-		nibble = parport_read_status (port) >> 3;
-		nibble &= ~8;
-		if ((nibble & 0x10) == 0)
-			nibble |= 8;
-		nibble &= 0xf;
-
-		/* Event 10: Set nAutoFd high. */
-		parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
-
-		/* Event 11: nAck goes high. */
-		if (parport_wait_peripheral (port,
-					     PARPORT_STATUS_ACK,
-					     PARPORT_STATUS_ACK)) {
-			/* Timeout -- no more data? */
-			DPRINTK (KERN_DEBUG
-				 "%s: Nibble timeout at event 11\n",
-				 port->name);
-			break;
-		}
-
-		if (i & 1) {
-			/* Second nibble */
-			byte |= nibble << 4;
-			*buf++ = byte;
-		} else 
-			byte = nibble;
-	}
-
-	i /= 2; /* i is now in bytes */
-
-	if (i == len) {
-		/* Read the last nibble without checking data avail. */
-		port = port->physport;
-		if (parport_read_status (port) & PARPORT_STATUS_ERROR)
-			port->ieee1284.phase = IEEE1284_PH_HBUSY_DNA;
-		else
-			port->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL;
-	}
-
-	return i;
-#endif /* IEEE1284 support */
-}
-
-/* Byte mode. */
-size_t parport_ieee1284_read_byte (struct parport *port,
-				   void *buffer, size_t len,
-				   int flags)
-{
-#ifndef CONFIG_PARPORT_1284
-	return 0;
-#else
-	unsigned char *buf = buffer;
-	ssize_t count = 0;
-
-	for (count = 0; count < len; count++) {
-		unsigned char byte;
-
-		/* Data available? */
-		if (parport_read_status (port) & PARPORT_STATUS_ERROR) {
-			port->physport->ieee1284.phase = IEEE1284_PH_HBUSY_DNA;
-			DPRINTK (KERN_DEBUG
-				 "%s: No more byte data (%d bytes)\n",
-				 port->name, count);
-
-			/* Go to reverse idle phase. */
-			parport_frob_control (port,
-					      PARPORT_CONTROL_AUTOFD,
-					      PARPORT_CONTROL_AUTOFD);
-			port->physport->ieee1284.phase = IEEE1284_PH_REV_IDLE;
-			break;
-		}
-
-		/* Event 7: Set nAutoFd low. */
-		parport_frob_control (port,
-				      PARPORT_CONTROL_AUTOFD,
-				      PARPORT_CONTROL_AUTOFD);
-
-		/* Event 9: nAck goes low. */
-		port->physport->ieee1284.phase = IEEE1284_PH_REV_DATA;
-		if (parport_wait_peripheral (port,
-					     PARPORT_STATUS_ACK,
-					     0)) {
-			/* Timeout -- no more data? */
-			parport_frob_control (port, PARPORT_CONTROL_AUTOFD,
-						 0);
-			DPRINTK (KERN_DEBUG "%s: Byte timeout at event 9\n",
-				 port->name);
-			break;
-		}
-
-		byte = parport_read_data (port);
-		*buf++ = byte;
-
-		/* Event 10: Set nAutoFd high */
-		parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
-
-		/* Event 11: nAck goes high. */
-		if (parport_wait_peripheral (port,
-					     PARPORT_STATUS_ACK,
-					     PARPORT_STATUS_ACK)) {
-			/* Timeout -- no more data? */
-			DPRINTK (KERN_DEBUG "%s: Byte timeout at event 11\n",
-				 port->name);
-			break;
-		}
-
-		/* Event 16: Set nStrobe low. */
-		parport_frob_control (port,
-				      PARPORT_CONTROL_STROBE,
-				      PARPORT_CONTROL_STROBE);
-		udelay (5);
-
-		/* Event 17: Set nStrobe high. */
-		parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
-	}
-
-	if (count == len) {
-		/* Read the last byte without checking data avail. */
-		port = port->physport;
-		if (parport_read_status (port) & PARPORT_STATUS_ERROR)
-			port->ieee1284.phase = IEEE1284_PH_HBUSY_DNA;
-		else
-			port->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL;
-	}
-
-	return count;
-#endif /* IEEE1284 support */
-}
-
-/***              *
- * ECP Functions. *
- *              ***/
-
-#ifdef CONFIG_PARPORT_1284
-
-static inline
-int ecp_forward_to_reverse (struct parport *port)
-{
-	int retval;
-
-	/* Event 38: Set nAutoFd low */
-	parport_frob_control (port,
-			      PARPORT_CONTROL_AUTOFD,
-			      PARPORT_CONTROL_AUTOFD);
-	parport_data_reverse (port);
-	udelay (5);
-
-	/* Event 39: Set nInit low to initiate bus reversal */
-	parport_frob_control (port,
-			      PARPORT_CONTROL_INIT,
-			      PARPORT_CONTROL_INIT);
-
-	/* Event 40: PError goes low */
-	retval = parport_wait_peripheral (port,
-					  PARPORT_STATUS_PAPEROUT, 0);
-
-	if (!retval) {
-		DPRINTK (KERN_DEBUG "%s: ECP direction: reverse\n",
-			 port->name);
-		port->ieee1284.phase = IEEE1284_PH_REV_IDLE;
-	}
-
-	return retval;
-}
-
-static inline
-int ecp_reverse_to_forward (struct parport *port)
-{
-	int retval;
-
-	/* Event 47: Set nInit high */
-	parport_frob_control (port,
-			      PARPORT_CONTROL_INIT,
-			      PARPORT_CONTROL_INIT);
-	parport_data_reverse (port);
-
-	/* Event 49: PError goes high */
-	retval = parport_wait_peripheral (port,
-					  PARPORT_STATUS_PAPEROUT,
-					  PARPORT_STATUS_PAPEROUT);
-
-	if (!retval) {
-		parport_data_forward (port);
-		DPRINTK (KERN_DEBUG "%s: ECP direction: forward\n",
-			 port->name);
-		port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
-	}
-
-	return retval;
-}
-
-#endif /* IEEE1284 support */
-
-/* ECP mode, forward channel, data. */
-size_t parport_ieee1284_ecp_write_data (struct parport *port,
-					const void *buffer, size_t len,
-					int flags)
-{
-#ifndef CONFIG_PARPORT_1284
-	return 0;
-#else
-	const unsigned char *buf = buffer;
-	size_t written;
-	int ctl = parport_read_control (port) & ~PARPORT_CONTROL_AUTOFD;
-	int retry;
-
-	port = port->physport;
-
-	if (port->ieee1284.phase != IEEE1284_PH_FWD_IDLE)
-		if (ecp_reverse_to_forward (port))
-			return 0;
-
-	port->ieee1284.phase = IEEE1284_PH_FWD_DATA;
-
-	/* HostAck high (data, not command) */
-	parport_write_control (port, ctl);
-	for (written = 0; written < len; written++, buf++) {
-		long expire = jiffies + port->cad->timeout;
-		unsigned char byte;
-
-		byte = *buf;
-	try_again:
-		parport_write_data (port, byte);
-		parport_write_control (port, ctl | PARPORT_CONTROL_STROBE);
-		udelay (5);
-		for (retry = 0; retry < 100; retry++) {
-			if (!parport_wait_peripheral (port,
-						      PARPORT_STATUS_BUSY, 0))
-				goto success;
-
-			if (signal_pending (current)) {
-				parport_write_control (port, ctl);
-				break;
-			}
-		}
-
-		/* Time for Host Transfer Recovery (page 41 of IEEE1284) */
-		DPRINTK (KERN_DEBUG "%s: ECP transfer stalled!\n", port->name);
-
-		parport_write_control (port, ctl | PARPORT_CONTROL_INIT);
-		udelay (50);
-		if (parport_read_status (port) & PARPORT_STATUS_PAPEROUT) {
-			/* It's buggered. */
-			parport_write_control (port, ctl);
-			break;
-		}
-
-		parport_write_control (port, ctl);
-		udelay (50);
-		if (!(parport_read_status (port) & PARPORT_STATUS_PAPEROUT))
-			break;
-
-		DPRINTK (KERN_DEBUG "%s: Host transfer recovered\n",
-			 port->name);
-
-		if (time_after_eq (jiffies, expire)) break;
-		goto try_again;
-	success:
-		parport_write_control (port, ctl);
-		udelay (5);
-		if (parport_wait_peripheral (port,
-					     PARPORT_STATUS_BUSY,
-					     PARPORT_STATUS_BUSY))
-			/* Peripheral hasn't accepted the data. */
-			break;
-	}
-
-	port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
-
-	return written;
-#endif /* IEEE1284 support */
-}
-
-/* ECP mode, reverse channel, data. */
-size_t parport_ieee1284_ecp_read_data (struct parport *port,
-				       void *buffer, size_t len, int flags)
-{
-#ifndef CONFIG_PARPORT_1284
-	return 0;
-#else
-	struct pardevice *dev = port->cad;
-	unsigned char *buf = buffer;
-	int rle_count = 0; /* shut gcc up */
-	int rle = 0;
-	ssize_t count = 0;
-
-	port = port->physport;
-
-	if (port->ieee1284.phase != IEEE1284_PH_REV_IDLE)
-		if (ecp_forward_to_reverse (port))
-			return 0;
-
-	port->ieee1284.phase = IEEE1284_PH_REV_DATA;
-
-	/* Set HostAck low to start accepting data. */
-	parport_frob_control (port, PARPORT_CONTROL_AUTOFD,
-			      PARPORT_CONTROL_AUTOFD);
-	while (count < len) {
-		long expire = jiffies + dev->timeout;
-		unsigned char byte;
-		int command;
-
-		/* Event 43: Peripheral sets nAck low. It can take as
-                   long as it wants. */
-		while (parport_wait_peripheral (port,
-						PARPORT_STATUS_ACK,
-						PARPORT_STATUS_ACK)) {
-			/* The peripheral hasn't given us data in
-			   35ms.  If we have data to give back to the
-			   caller, do it now. */
-			if (count)
-				goto out;
-
-			/* If we've used up all the time we were allowed,
-			   give up altogether. */
-			if (!time_before (jiffies, expire))
-				goto out;
-
-			/* Yield the port for a while. */
-			if (count && polling (dev)) {
-				parport_release (dev);
-				current->state = TASK_INTERRUPTIBLE;
-				schedule_timeout ((HZ + 99) / 25);
-				parport_claim_or_block (dev);
-			}
-			else
-				/* We must have the device claimed here. */
-				parport_wait_event (port, (HZ + 99) / 25);
-
-			/* Is there a signal pending? */
-			if (signal_pending (current))
-				goto out;
-		}
-
-		/* Is this a command? */
-		if (rle)
-			/* The last byte was a run-length count, so
-                           this can't be as well. */
-			command = 0;
-		else
-			command = (parport_read_status (port) &
-				   PARPORT_STATUS_BUSY) ? 1 : 0;
-
-		/* Read the data. */
-		byte = parport_read_data (port);
-
-		/* If this is a channel command, rather than an RLE
-                   command or a normal data byte, don't accept it. */
-		if (command) {
-			if (byte & 0x80) {
-				DPRINTK (KERN_DEBUG "%s: stopping short at "
-					 "channel command (%02x)\n",
-					 port->name, byte);
-				goto out;
-			}
-			else if (port->ieee1284.mode != IEEE1284_MODE_ECPRLE)
-				DPRINTK (KERN_DEBUG "%s: device illegally "
-					 "using RLE; accepting anyway\n",
-					 port->name);
-
-			rle_count = byte + 1;
-
-			/* Are we allowed to read that many bytes? */
-			if (rle_count > (len - count)) {
-				DPRINTK (KERN_DEBUG "%s: leaving %d RLE bytes "
-					 "for next time\n", port->name,
-					 rle_count);
-				break;
-			}
-
-			rle = 1;
-		}
-
-		/* Event 44: Set HostAck high, acknowledging handshake. */
-		parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
-
-		/* Event 45: The peripheral has 35ms to set nAck high. */
-		if (parport_wait_peripheral (port, PARPORT_STATUS_ACK, 0)) {
-			/* It's gone wrong.  Return what data we have
-                           to the caller. */
-			DPRINTK (KERN_DEBUG "ECP read timed out at 45\n");
-
-			if (command)
-				printk (KERN_WARNING
-					"%s: command ignored (%02x)\n",
-					port->name, byte);
-
-			break;
-		}
-
-		/* Event 46: Set HostAck low and accept the data. */
-		parport_frob_control (port,
-				      PARPORT_CONTROL_AUTOFD,
-				      PARPORT_CONTROL_AUTOFD);
-
-		/* If we just read a run-length count, fetch the data. */
-		if (command)
-			continue;
-
-		/* If this is the byte after a run-length count, decompress. */
-		if (rle) {
-			rle = 0;
-			memset (buf, byte, rle_count);
-			buf += rle_count;
-			count += rle_count;
-			DPRINTK (KERN_DEBUG "%s: decompressed to %d bytes\n",
-				 port->name, rle_count);
-		}
-		else
-			/* Normal data byte. */
-			*buf++ = byte, count++;
-	}
-
- out:
-	return count;
-#endif /* IEEE1284 support */
-}
-
-/* ECP mode, forward channel, commands. */
-size_t parport_ieee1284_ecp_write_addr (struct parport *port,
-					const void *buffer, size_t len,
-					int flags)
-{
-#ifndef CONFIG_PARPORT_1284
-	return 0;
-#else
-	const unsigned char *buf = buffer;
-	size_t written;
-	int ctl = parport_read_control (port) | PARPORT_CONTROL_AUTOFD;
-	int retry;
-
-	port = port->physport;
-
-	if (port->ieee1284.phase != IEEE1284_PH_FWD_IDLE)
-		if (ecp_reverse_to_forward (port))
-			return 0;
-
-	port->ieee1284.phase = IEEE1284_PH_FWD_DATA;
-
-	/* HostAck low (command, not data) */
-	parport_write_control (port, ctl);
-	for (written = 0; written < len; written++, buf++) {
-		long expire = jiffies + port->cad->timeout;
-		unsigned char byte;
-
-		byte = *buf;
-	try_again:
-		parport_write_data (port, byte);
-		parport_write_control (port, ctl | PARPORT_CONTROL_STROBE);
-		udelay (5);
-		for (retry = 0; retry < 100; retry++) {
-			if (!parport_wait_peripheral (port,
-						      PARPORT_STATUS_BUSY, 0))
-				goto success;
-
-			if (signal_pending (current)) {
-				parport_write_control (port, ctl);
-				break;
-			}
-		}
-
-		/* Time for Host Transfer Recovery (page 41 of IEEE1284) */
-		DPRINTK (KERN_DEBUG "%s: ECP transfer stalled!\n", port->name);
-
-		parport_write_control (port, ctl | PARPORT_CONTROL_INIT);
-		udelay (50);
-		if (parport_read_status (port) & PARPORT_STATUS_PAPEROUT) {
-			/* It's buggered. */
-			parport_write_control (port, ctl);
-			break;
-		}
-
-		parport_write_control (port, ctl);
-		udelay (50);
-		if (!(parport_read_status (port) & PARPORT_STATUS_PAPEROUT))
-			break;
-
-		DPRINTK (KERN_DEBUG "%s: Host transfer recovered\n",
-			 port->name);
-
-		if (time_after_eq (jiffies, expire)) break;
-		goto try_again;
-	success:
-		parport_write_control (port, ctl);
-		udelay (5);
-		if (parport_wait_peripheral (port,
-					     PARPORT_STATUS_BUSY,
-					     PARPORT_STATUS_BUSY))
-			/* Peripheral hasn't accepted the data. */
-			break;
-	}
-
-	port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
-
-	return written;
-#endif /* IEEE1284 support */
-}
-
-/***              *
- * EPP functions. *
- *              ***/
-
-/* EPP mode, forward channel, data. */
-size_t parport_ieee1284_epp_write_data (struct parport *port,
-					const void *buffer, size_t len,
-					int flags)
-{
-	/* This is untested */
-	unsigned char *bp = (unsigned char *) buffer;
-	size_t ret = 0;
-
-	parport_frob_control (port,
-			      PARPORT_CONTROL_STROBE |
-			      PARPORT_CONTROL_AUTOFD |
-			      PARPORT_CONTROL_SELECT,
-			      PARPORT_CONTROL_STROBE |
-			      PARPORT_CONTROL_SELECT);
-	port->ops->data_forward (port);
-	for (; len > 0; len--, bp++) {
-		parport_write_data (port, *bp);
-
-		if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY,
-					     PARPORT_STATUS_BUSY))
-			break;
-
-		/* Strobe data */
-		parport_frob_control (port, PARPORT_CONTROL_AUTOFD,
-				      PARPORT_CONTROL_AUTOFD);
-
-		if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0))
-			break;
-
-		parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
-		ret++;
-	}
-
-	return ret;
-}
-
-/* EPP mode, reverse channel, data. */
-size_t parport_ieee1284_epp_read_data (struct parport *port,
-				       void *buffer, size_t len,
-				       int flags)
-{
-	/* This is untested. */
-	unsigned char *bp = (unsigned char *) buffer;
-	unsigned ret = 0;
-
-	parport_frob_control (port,
-			      PARPORT_CONTROL_STROBE |
-			      PARPORT_CONTROL_AUTOFD |
-			      PARPORT_CONTROL_SELECT, 0);
-	port->ops->data_reverse (port);
-	for (; len > 0; len--, bp++) {
-		if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY,
-					     PARPORT_STATUS_BUSY))
-			break;
-
-		parport_frob_control (port, PARPORT_CONTROL_AUTOFD,
-				      PARPORT_CONTROL_AUTOFD);
-
-		if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0))
-			break;
-
-		*bp = parport_read_data (port);
-
-		parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
-		ret++;
-	}
-	port->ops->data_forward (port);
-
-	return ret;
-}
-
-/* EPP mode, forward channel, addresses. */
-size_t parport_ieee1284_epp_write_addr (struct parport *port,
-					const void *buffer, size_t len,
-					int flags)
-{
-	/* This is untested */
-	unsigned char *bp = (unsigned char *) buffer;
-	size_t ret = 0;
-
-	parport_frob_control (port,
-			      PARPORT_CONTROL_STROBE |
-			      PARPORT_CONTROL_SELECT |
-			      PARPORT_CONTROL_AUTOFD,
-			      PARPORT_CONTROL_STROBE |
-			      PARPORT_CONTROL_SELECT);
-	port->ops->data_forward (port);
-	for (; len > 0; len--, bp++) {
-		parport_write_data (port, *bp);
-
-		if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY,
-					     PARPORT_STATUS_BUSY))
-			break;
-
-		/* Strobe data */
-		parport_frob_control (port, PARPORT_CONTROL_SELECT,
-				      PARPORT_CONTROL_SELECT);
-
-		if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0))
-			break;
-
-		parport_frob_control (port, PARPORT_CONTROL_SELECT, 0);
-		ret++;
-	}
-
-	return ret;
-}
-
-/* EPP mode, reverse channel, addresses. */
-size_t parport_ieee1284_epp_read_addr (struct parport *port,
-				       void *buffer, size_t len,
-				       int flags)
-{
-	/* This is untested. */
-	unsigned char *bp = (unsigned char *) buffer;
-	unsigned ret = 0;
-
-	parport_frob_control (port,
-			      PARPORT_CONTROL_STROBE |
-			      PARPORT_CONTROL_SELECT |
-			      PARPORT_CONTROL_AUTOFD, 0);
-	port->ops->data_reverse (port);
-	for (; len > 0; len--, bp++) {
-		if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY,
-					     PARPORT_STATUS_BUSY))
-			break;
-
-		parport_frob_control (port, PARPORT_CONTROL_SELECT,
-				      PARPORT_CONTROL_SELECT);
-
-		if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0))
-			break;
-
-		*bp = parport_read_data (port);
-
-		parport_frob_control (port, PARPORT_CONTROL_SELECT, 0);
-		ret++;
-	}
-	port->ops->data_forward (port);
-
-	return ret;
-}
diff -u --recursive --new-file v2.3.11/linux/drivers/misc/parport_init.c linux/drivers/misc/parport_init.c
--- v2.3.11/linux/drivers/misc/parport_init.c	Wed Jul 21 15:46:48 1999
+++ linux/drivers/misc/parport_init.c	Wed Dec 31 16:00:00 1969
@@ -1,210 +0,0 @@
-/* Parallel-port initialisation code.
- * 
- * Authors: David Campbell <campbell@torque.net>
- *          Tim Waugh <tim@cyberelk.demon.co.uk>
- *	    Jose Renau <renau@acm.org>
- *
- * based on work by Grant Guenther <grant@torque.net>
- *              and Philip Blundell <Philip.Blundell@pobox.com>
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/threads.h>
-
-#include <linux/parport.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/malloc.h>
-#include <linux/init.h>
-
-#ifndef MODULE
-static int io[PARPORT_MAX+1] __initdata = { [0 ... PARPORT_MAX] = 0 };
-static int io_hi[PARPORT_MAX+1] __initdata = { [0 ... PARPORT_MAX] = 0 };
-static int irq[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_IRQ_PROBEONLY };
-static int dma[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_DMA_NONE };
-
-extern int parport_pc_init(int *io, int *io_hi, int *irq, int *dma);
-extern int parport_ax_init(void);
-
-static int parport_setup_ptr __initdata = 0;
-
-__initfunc(void parport_setup(char *str, int *ints))
-{
-	if (ints[0] == 0) {
-		if (str && !strncmp(str, "auto", 4)) {
-			irq[0] = PARPORT_IRQ_AUTO;
-			dma[0] = PARPORT_DMA_AUTO;
-		}
-		else if (str)
-			printk (KERN_ERR "parport: `%s': huh?\n", str);
-		else
-			printk (KERN_ERR "parport: parport=.. what?\n");
-		
-		return;
-	}
-	else if (ints[1] == 0) {
-		/* Disable parport if "parport=0" in cmdline */
-		io[0] = PARPORT_DISABLE; 
-		return;
-	}
-
-	if (parport_setup_ptr < PARPORT_MAX) {
-		char *sep;
-		io[parport_setup_ptr] = ints[1];
-		irq[parport_setup_ptr] = PARPORT_IRQ_NONE;
-		dma[parport_setup_ptr] = PARPORT_DMA_NONE;
-		if (ints[0] > 1) {
-			irq[parport_setup_ptr] = ints[2];
-			if (ints[0] > 2) {
-				dma[parport_setup_ptr] = ints[3];
-				goto done;
-			}
-
-			if (str == NULL)
-				goto done;
-
-			goto dma_from_str;
-		}
-		else if (str == NULL)
-			goto done;
-		else if (!strncmp(str, "auto", 4))
-			irq[parport_setup_ptr] = PARPORT_IRQ_AUTO;
-		else if (strncmp(str, "none", 4) != 0) {
-			printk(KERN_ERR "parport: bad irq `%s'\n", str);
-			return;
-		}
-
-		if ((sep = strchr(str, ',')) == NULL) goto done;
-		str = sep+1;
-	dma_from_str:
-		if (!strncmp(str, "auto", 4))
-			dma[parport_setup_ptr] = PARPORT_DMA_AUTO;
-		else if (strncmp(str, "none", 4) != 0) {
-			char *ep;
-			dma[parport_setup_ptr] = simple_strtoul(str, &ep, 0);
-			if (ep == str) {
-				printk(KERN_ERR "parport: bad dma `%s'\n",
-				       str);
-				return;
-			}
-		}
-	done:
-		parport_setup_ptr++;
-	} else
-		printk(KERN_ERR "parport=%s ignored, too many ports\n", str);
-}
-#endif
-
-#ifdef MODULE
-int init_module(void)
-{
-#ifdef CONFIG_SYSCTL
-	parport_default_proc_register ();
-#endif
-	return 0;
-}
-
-void cleanup_module(void)
-{
-#ifdef CONFIG_SYSCTL
-	parport_default_proc_unregister ();
-#endif
-}
-
-#else
-
-__initfunc(int parport_init(void))
-{
-	if (io[0] == PARPORT_DISABLE) 
-		return 1;
-
-#ifdef CONFIG_SYSCTL
-	parport_default_proc_register ();
-#endif
-
-#ifdef CONFIG_PARPORT_PC
-	parport_pc_init(io, io_hi, irq, dma);
-#endif
-#ifdef CONFIG_PARPORT_AX
-	parport_ax_init();
-#endif
-#ifdef CONFIG_PARPORT_AMIGA
-	parport_amiga_init();
-#endif
-#ifdef CONFIG_PARPORT_MFC3
-	parport_mfc3_init();
-#endif
-#ifdef CONFIG_PARPORT_ATARI
-	parport_atari_init();
-#endif
-#ifdef CONFIG_PARPORT_ARC
-	parport_arc_init();
-#endif
-	return 0;
-}
-#endif
-
-/* Exported symbols for modules. */
-
-EXPORT_SYMBOL(parport_claim);
-EXPORT_SYMBOL(parport_claim_or_block);
-EXPORT_SYMBOL(parport_release);
-EXPORT_SYMBOL(parport_register_port);
-EXPORT_SYMBOL(parport_announce_port);
-EXPORT_SYMBOL(parport_unregister_port);
-EXPORT_SYMBOL(parport_register_driver);
-EXPORT_SYMBOL(parport_unregister_driver);
-EXPORT_SYMBOL(parport_register_device);
-EXPORT_SYMBOL(parport_unregister_device);
-EXPORT_SYMBOL(parport_enumerate);
-EXPORT_SYMBOL(parport_negotiate);
-EXPORT_SYMBOL(parport_write);
-EXPORT_SYMBOL(parport_read);
-EXPORT_SYMBOL(parport_ieee1284_wakeup);
-EXPORT_SYMBOL(parport_wait_peripheral);
-EXPORT_SYMBOL(parport_wait_event);
-EXPORT_SYMBOL(parport_set_timeout);
-EXPORT_SYMBOL(parport_ieee1284_interrupt);
-EXPORT_SYMBOL(parport_ieee1284_ecp_write_data);
-EXPORT_SYMBOL(parport_ieee1284_ecp_read_data);
-EXPORT_SYMBOL(parport_ieee1284_ecp_write_addr);
-EXPORT_SYMBOL(parport_ieee1284_write_compat);
-EXPORT_SYMBOL(parport_ieee1284_read_nibble);
-EXPORT_SYMBOL(parport_ieee1284_read_byte);
-EXPORT_SYMBOL(parport_ieee1284_epp_write_data);
-EXPORT_SYMBOL(parport_ieee1284_epp_read_data);
-EXPORT_SYMBOL(parport_ieee1284_epp_write_addr);
-EXPORT_SYMBOL(parport_ieee1284_epp_read_addr);
-EXPORT_SYMBOL(parport_proc_register);
-EXPORT_SYMBOL(parport_proc_unregister);
-EXPORT_SYMBOL(parport_device_proc_register);
-EXPORT_SYMBOL(parport_device_proc_unregister);
-EXPORT_SYMBOL(parport_default_proc_register);
-EXPORT_SYMBOL(parport_default_proc_unregister);
-EXPORT_SYMBOL(parport_parse_irqs);
-EXPORT_SYMBOL(parport_parse_dmas);
-#ifdef CONFIG_PARPORT_1284
-EXPORT_SYMBOL(parport_open);
-EXPORT_SYMBOL(parport_close);
-EXPORT_SYMBOL(parport_device_id);
-EXPORT_SYMBOL(parport_device_num);
-EXPORT_SYMBOL(parport_device_coords);
-EXPORT_SYMBOL(parport_daisy_deselect_all);
-EXPORT_SYMBOL(parport_daisy_select);
-EXPORT_SYMBOL(parport_daisy_init);
-#endif
-
-void inc_parport_count(void)
-{
-#ifdef MODULE
-	MOD_INC_USE_COUNT;
-#endif
-}
-
-void dec_parport_count(void)
-{
-#ifdef MODULE
-	MOD_DEC_USE_COUNT;
-#endif
-}
diff -u --recursive --new-file v2.3.11/linux/drivers/misc/parport_mfc3.c linux/drivers/misc/parport_mfc3.c
--- v2.3.11/linux/drivers/misc/parport_mfc3.c	Thu Jun  3 16:21:47 1999
+++ linux/drivers/misc/parport_mfc3.c	Wed Dec 31 16:00:00 1969
@@ -1,414 +0,0 @@
-/* Low-level parallel port routines for the Multiface 3 card
- *
- * Author: Joerg Dorchain <dorchain@wirbel.com>
- *
- * (C) The elitist m68k Users(TM)
- *
- * based on the existing parport_amiga and lp_mfc
- *
- *
- * From the MFC3 documentation:
- * 
- * Miscellaneous PIA Details
- * -------------------------
- * 
- * 	The two open-drain interrupt outputs /IRQA and /IRQB are routed to
- * /INT2 of the Z2 bus.
- * 
- * 	The CPU data bus of the PIA (D0-D7) is connected to D8-D15 on the Z2
- * bus. This means that any PIA registers are accessed at even addresses.
- * 
- * Centronics Pin Connections for the PIA
- * --------------------------------------
- * 
- * 	The following table shows the connections between the PIA and the
- * Centronics interface connector. These connections implement a single, but
- * very complete, Centronics type interface. The Pin column gives the pin
- * numbers of the PIA. The Centronics pin numbers can be found in the section
- * "Parallel Connectors".
- * 
- * 
- *    Pin | PIA | Dir | Centronics Names
- * -------+-----+-----+---------------------------------------------------------
- *     19 | CB2 | --> | /STROBE (aka /DRDY)
- *  10-17 | PBx | <-> | DATA0 - DATA7
- *     18 | CB1 | <-- | /ACK
- *     40 | CA1 | <-- | BUSY
- *      3 | PA1 | <-- | PAPER-OUT (aka POUT)
- *      4 | PA2 | <-- | SELECTED (aka SEL)
- *      9 | PA7 | --> | /INIT (aka /RESET or /INPUT-PRIME)
- *      6 | PA4 | <-- | /ERROR (aka /FAULT)
- *      7 | PA5 | --> | DIR (aka /SELECT-IN)
- *      8 | PA6 | --> | /AUTO-FEED-XT
- *     39 | CA2 | --> | open
- *      5 | PA3 | <-- | /ACK (same as CB1!)
- *      2 | PA0 | <-- | BUSY (same as CA1!)
- * -------+-----+-----+---------------------------------------------------------
- * 
- * Should be enough to understand some of the driver.
- */
-
-#include "multiface.h"
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/parport.h>
-#include <linux/delay.h>
-#include <linux/mc6821.h>
-#include <linux/zorro.h>
-#include <asm/setup.h>
-#include <asm/amigahw.h>
-#include <asm/irq.h>
-#include <asm/amigaints.h>
-
-/* Maximum Number of Cards supported */
-#define MAX_MFC 5
-
-#undef DEBUG
-#ifdef DEBUG
-#define DPRINTK printk
-#else
-static inline int DPRINTK() {return 0;}
-#endif
-
-static struct parport *this_port[MAX_MFC] = {NULL, };
-static volatile int dummy; /* for trigger readds */
-
-#define pia(dev) ((struct pia *)(dev->base))
-static struct parport_operations pp_mfc3_ops;
-
-static void mfc3_write_data(struct parport *p, unsigned char data)
-{
-DPRINTK("write_data %c\n",data);
-
-	dummy = pia(p)->pprb; /* clears irq bit */
-	/* Triggers also /STROBE.*/
-	pia(p)->pprb = data;
-}
-
-static unsigned char mfc3_read_data(struct parport *p)
-{
-	/* clears interupt bit. Triggers also /STROBE. */
-	return pia(p)->pprb;
-}
-
-static unsigned char control_pc_to_mfc3(unsigned char control)
-{
-	unsigned char ret = 32|64;
-
-	if (control & PARPORT_CONTROL_DIRECTION) /* XXX: What is this? */
-		;
-	if (control & PARPORT_CONTROL_INTEN) /* XXX: What is INTEN? */
-		;
-	if (control & PARPORT_CONTROL_SELECT) /* XXX: What is SELECP? */
-		ret &= ~32; /* /SELECT_IN */
-	if (control & PARPORT_CONTROL_INIT) /* INITP */
-		ret |= 128;
-	if (control & PARPORT_CONTROL_AUTOFD) /* AUTOLF */
-		ret &= ~64;
-	if (control & PARPORT_CONTROL_STROBE) /* Strobe */
-		/* Handled directly by hardware */;
-	return ret;
-}
-
-static unsigned char control_mfc3_to_pc(unsigned char control)
-{
-	unsigned char ret = PARPORT_CONTROL_INTEN | PARPORT_CONTROL_STROBE 
-			  | PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_SELECT;
-
-	if (control & 128) /* /INITP */
-		ret |= PARPORT_CONTROL_INIT;
-	if (control & 64) /* /AUTOLF */
-		ret &= ~PARPORT_CONTROL_AUTOFD;
-	if (control & 32) /* /SELECT_IN */
-		ret &= ~PARPORT_CONTROL_SELECT;
-	return ret;
-}
-
-static void mfc3_write_control(struct parport *p, unsigned char control)
-{
-DPRINTK("write_control %02x\n",control);
-	pia(p)->ppra = (pia(p)->ppra & 0x1f) | control_pc_to_mfc3(control);
-}
-	
-static unsigned char mfc3_read_control( struct parport *p)
-{
-DPRINTK("read_control \n");
-	return control_mfc3_to_pc(pia(p)->ppra & 0xe0);
-}
-
-static unsigned char mfc3_frob_control( struct parport *p, unsigned char mask, unsigned char val)
-{
-	unsigned char old;
-
-DPRINTK("frob_control mask %02x, value %02x\n",mask,val);
-	old = mfc3_read_control(p);
-	mfc3_write_control(p, (old & ~mask) ^ val);
-	return old;
-}
-
-
-static unsigned char status_pc_to_mfc3(unsigned char status)
-{
-	unsigned char ret = 1;
-
-	if (status & PARPORT_STATUS_BUSY) /* Busy */
-		ret &= ~1;
-	if (status & PARPORT_STATUS_ACK) /* Ack */
-		ret |= 8;
-	if (status & PARPORT_STATUS_PAPEROUT) /* PaperOut */
-		ret |= 2;
-	if (status & PARPORT_STATUS_SELECT) /* select */
-		ret |= 4;
-	if (status & PARPORT_STATUS_ERROR) /* error */
-		ret |= 16;
-	return ret;
-}
-
-static unsigned char status_mfc3_to_pc(unsigned char status)
-{
-	unsigned char ret = PARPORT_STATUS_BUSY;
-
-	if (status & 1) /* Busy */
-		ret &= ~PARPORT_STATUS_BUSY;
-	if (status & 2) /* PaperOut */
-		ret |= PARPORT_STATUS_PAPEROUT;
-	if (status & 4) /* Selected */
-		ret |= PARPORT_STATUS_SELECT;
-	if (status & 8) /* Ack */
-		ret |= PARPORT_STATUS_ACK;
-	if (status & 16) /* /ERROR */
-		ret |= PARPORT_STATUS_ERROR;
-
-	return ret;
-}
-
-static void mfc3_write_status( struct parport *p, unsigned char status)
-{
-DPRINTK("write_status %02x\n",status);
-	pia(p)->ppra = (pia(p)->ppra & 0xe0) | status_pc_to_mfc3(status);
-}
-
-static unsigned char mfc3_read_status(struct parport *p)
-{
-	unsigned char status;
-
-	status = status_mfc3_to_pc(pia(p)->ppra & 0x1f);
-DPRINTK("read_status %02x\n", status);
-	return status;
-}
-
-static void mfc3_change_mode( struct parport *p, int m)
-{
-	/* XXX: This port only has one mode, and I am
-	not sure about the corresponding PC-style mode*/
-}
-
-static int use_cnt = 0;
-
-static void mfc3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	int i;
-
-	for( i = 0; i < MAX_MFC; i++)
-		if (this_port[i] != NULL)
-			if (pia(this_port[i])->crb & 128) { /* Board caused interrupt */
-				dummy = pia(this_port[i])->pprb; /* clear irq bit */
-				parport_generic_irq(irq, this_port[i], regs);
-			}
-}
-
-static int mfc3_claim_resources(struct parport *p)
-{
-DPRINTK("claim_resources\n");
-}
-
-static void mfc3_init_state(struct parport_state *s)
-{
-	s->u.amiga.data = 0;
-	s->u.amiga.datadir = 255;
-	s->u.amiga.status = 0;
-	s->u.amiga.statusdir = 0xe0;
-}
-
-static void mfc3_save_state(struct parport *p, struct parport_state *s)
-{
-	s->u.amiga.data = pia(p)->pprb;
-	pia(p)->crb &= ~PIA_DDR;
-	s->u.amiga.datadir = pia(p)->pddrb;
-	pia(p)->crb |= PIA_DDR;
-	s->u.amiga.status = pia(p)->ppra;
-	pia(p)->cra &= ~PIA_DDR;
-	s->u.amiga.statusdir = pia(p)->pddrb;
-	pia(p)->cra |= PIA_DDR;
-}
-
-static void mfc3_restore_state(struct parport *p, struct parport_state *s)
-{
-	pia(p)->pprb = s->u.amiga.data;
-	pia(p)->crb &= ~PIA_DDR;
-	pia(p)->pddrb = s->u.amiga.datadir;
-	pia(p)->crb |= PIA_DDR;
-	pia(p)->ppra = s->u.amiga.status;
-	pia(p)->cra &= ~PIA_DDR;
-	pia(p)->pddrb = s->u.amiga.statusdir;
-	pia(p)->cra |= PIA_DDR;
-}
-
-static void mfc3_enable_irq(struct parport *p)
-{
-	pia(p)->crb |= PIA_C1_ENABLE_IRQ;
-}
-
-static void mfc3_disable_irq(struct parport *p)
-{
-	pia(p)->crb &= ~PIA_C1_ENABLE_IRQ;
-}
-
-static void mfc3_inc_use_count(void)
-{
-	MOD_INC_USE_COUNT;
-}
-
-static void mfc3_dec_use_count(void)
-{
-	MOD_DEC_USE_COUNT;
-}
-
-static void mfc3_fill_inode(struct inode *inode, int fill)
-{
-#ifdef MODULE
-	if (fill)
-		MOD_INC_USE_COUNT;
-	else
-		MOD_DEC_USE_COUNT;
-#endif
-}
-
-static struct parport_operations pp_mfc3_ops = {
-	mfc3_write_data,
-	mfc3_read_data,
-
-	mfc3_write_control,
-	mfc3_read_control,
-	mfc3_frob_control,
-
-	NULL, /* write_econtrol */
-	NULL, /* read_econtrol */
-	NULL, /* frob_econtrol */
-
-	mfc3_write_status,
-	mfc3_read_status,
-
-	NULL, /* write fifo */
-	NULL, /* read fifo */
-
-	mfc3_change_mode,
-
-
-	mfc3_release_resources,
-	mfc3_claim_resources,
-
-
-	NULL, /* epp_write_data */
-	NULL, /* epp_read_data */
-	NULL, /* epp_write_addr */
-	NULL, /* epp_read_addr */
-	NULL, /* epp_check_timeout */
-
-	NULL, /* epp_write_block */
-	NULL, /* epp_read_block */
-
-	NULL, /* ecp_write_block */
-	NULL, /* ecp_read_block */
-
-	mfc3_init_state,
-	mfc3_save_state,
-	mfc3_restore_state,
-
-	mfc3_enable_irq,
-	mfc3_disable_irq,
-	mfc3_interrupt,
-
-	mfc3_inc_use_count,
-	mfc3_dec_use_count,
-	mfc3_fill_inode
-};
-
-/* ----------- Initialisation code --------------------------------- */
-
-__initfunc(int parport_mfc3_init(void))
-{
-	struct parport *p;
-	int pias = 0;
-	struct pia *pp;
-	unsigned int key = 0;
-	const struct ConfigDev *cd;
-
-	if (MACH_IS_AMIGA) {
-		while ((key = zorro_find(ZORRO_PROD_BSC_MULTIFACE_III, 0, key))) {
-			cd = zorro_get_board(key);
-			pp = (struct pia *)ZTWO_VADDR((((u_char *)cd->cd_BoardAddr)+PIABASE));
-			if (pias < MAX_MFC) {
-				pp->crb = 0;
-				pp->pddrb = 255; /* all data pins output */
-				pp->crb = PIA_DDR|32|8;
-				dummy = pp->pddrb; /* reading clears interrupt */
-				pp->cra = 0;
-				pp->pddra = 0xe0; /* /RESET,  /DIR ,/AUTO-FEED output */
-				pp->cra = PIA_DDR;
-				pp->ppra = 0; /* reset printer */
-				udelay(10);
-				pp->ppra = 128;
-				if ((p = parport_register_port((unsigned long)pp,
-					IRQ_AMIGA_PORTS, PARPORT_DMA_NONE,
-					&pp_mfc3_ops))) {
-					this_port[pias++] = p;
-					printk(KERN_INFO "%s: Multiface III port using irq\n", p->name);
-					/* XXX: set operating mode */
-					parport_proc_register(p);
-
-					if (p->irq != PARPORT_IRQ_NONE)
-						if (use_cnt++ == 0)
-							if (request_irq(IRQ_AMIGA_PORTS, mfc3_interrupt, 0, p->name, &pp_mfc3_ops))
-								use_cnt--;
-
-					if (parport_probe_hook)
-						(*parport_probe_hook)(p);
-					zorro_config_board(key, 0);
-					p->private_data = (void *)key;
-					parport_announce_port (p);
-				}
-			}
-		}
-	}
-	return pias;
-}
-
-#ifdef MODULE
-
-MODULE_AUTHOR("Joerg Dorchain");
-MODULE_DESCRIPTION("Parport Driver for Multiface 3 expansion cards Paralllel Port");
-MODULE_SUPPORTED_DEVICE("Multiface 3 Parallel Port");
-
-int init_module(void)
-{
-	return ! parport_mfc3_init();
-}
-
-void cleanup_module(void)
-{
-	int i;
-
-	for (i = 0; i < MAX_MFC; i++)
-		if (this_port[i] != NULL) {
-			if (p->irq != PARPORT_IRQ_NONE) 
-				if (--use_cnt == 0) 
-			free_irq(IRQ_AMIGA_PORTS, &pp_mfc3_ops);
-			parport_proc_unregister(this_port[i]);
-			parport_unregister_port(this_port[i]);
-			zorro_unconfig_board((unsigned int)this_port[i]->private_data, 0);
-		}
-}
-#endif
-
-
diff -u --recursive --new-file v2.3.11/linux/drivers/misc/parport_pc.c linux/drivers/misc/parport_pc.c
--- v2.3.11/linux/drivers/misc/parport_pc.c	Wed Jul 21 15:46:48 1999
+++ linux/drivers/misc/parport_pc.c	Wed Dec 31 16:00:00 1969
@@ -1,1904 +0,0 @@
-/* Low-level parallel-port routines for 8255-based PC-style hardware.
- * 
- * Authors: Phil Blundell <Philip.Blundell@pobox.com>
- *          Tim Waugh <tim@cyberelk.demon.co.uk>
- *	    Jose Renau <renau@acm.org>
- *          David Campbell <campbell@torque.net>
- *          Andrea Arcangeli
- *
- * based on work by Grant Guenther <grant@torque.net> and Phil Blundell.
- *
- * Cleaned up include files - Russell King <linux@arm.uk.linux.org>
- * DMA support - Bert De Jonghe <bert@sophis.be>
- * Better EPP probing - Carlos Henrique Bauer <chbauer@acm.org>
- */
-
-/* This driver should work with any hardware that is broadly compatible
- * with that in the IBM PC.  This applies to the majority of integrated
- * I/O chipsets that are commonly available.  The expected register
- * layout is:
- *
- *	base+0		data
- *	base+1		status
- *	base+2		control
- *
- * In addition, there are some optional registers:
- *
- *	base+3		EPP address
- *	base+4		EPP data
- *	base+0x400	ECP config A
- *	base+0x401	ECP config B
- *	base+0x402	ECP control
- *
- * All registers are 8 bits wide and read/write.  If your hardware differs
- * only in register addresses (eg because your registers are on 32-bit
- * word boundaries) then you can alter the constants in parport_pc.h to
- * accomodate this.
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/malloc.h>
-#include <linux/pci.h>
-#include <linux/sysctl.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/uaccess.h>
-
-#include <linux/parport.h>
-#include <linux/parport_pc.h>
-
-/* Maximum number of ports to support.  It is useless to set this greater
-   than PARPORT_MAX (in <linux/parport.h>).  */
-#define PARPORT_PC_MAX_PORTS  8
-
-/* ECR modes */
-#define ECR_SPP 00
-#define ECR_PS2 01
-#define ECR_PPF 02
-#define ECR_ECP 03
-#define ECR_EPP 04
-#define ECR_VND 05
-#define ECR_TST 06
-#define ECR_CNF 07
-
-static int user_specified __initdata = 0;
-
-/* frob_control, but for ECR */
-static void frob_econtrol (struct parport *pb, unsigned char m,
-			   unsigned char v)
-{
-	outb ((inb (ECONTROL (pb)) & ~m) ^ v, ECONTROL (pb));
-}
-
-#ifdef CONFIG_PARPORT_1284
-/* Safely change the mode bits in the ECR */
-static int change_mode(struct parport *p, int m)
-{
-	const struct parport_pc_private *priv = p->physport->private_data;
-	int ecr = ECONTROL(p);
-	unsigned char oecr;
-	int mode;
-
-	if (!priv->ecr) {
-		printk (KERN_DEBUG "change_mode: but there's no ECR!\n");
-		return 0;
-	}
-
-	/* Bits <7:5> contain the mode. */
-	oecr = inb (ecr);
-	mode = (oecr >> 5) & 0x7;
-	if (mode == m) return 0;
-	if (mode && m)
-		/* We have to go through mode 000 */
-		change_mode (p, ECR_SPP);
-
-	if (m < 2 && !(parport_read_control (p) & 0x20)) {
-		/* This mode resets the FIFO, so we may
-		 * have to wait for it to drain first. */
-		long expire = jiffies + p->physport->cad->timeout;
-		int counter;
-		switch (mode) {
-		case ECR_PPF: /* Parallel Port FIFO mode */
-		case ECR_ECP: /* ECP Parallel Port mode */
-			/* Busy wait for 200us */
-			for (counter = 0; counter < 40; counter++) {
-				if (inb (ECONTROL (p)) & 0x01)
-					break;
-				if (signal_pending (current)) break;
-				udelay (5);
-			}
-
-			/* Poll slowly. */
-			while (!(inb (ECONTROL (p)) & 0x01)) {
-				if (time_after_eq (jiffies, expire))
-					/* The FIFO is stuck. */
-					return -EBUSY;
-				current->state = TASK_INTERRUPTIBLE;
-				schedule_timeout ((HZ + 99) / 100);
-				if (signal_pending (current))
-					break;
-			}
-		}
-	}
-
-	/* Set the mode. */
-	oecr &= ~(7 << 5);
-	oecr |= m << 5;
-	outb (oecr, ecr);
-	return 0;
-}
-
-/* Find FIFO lossage; FIFO is reset */
-static int get_fifo_residue (struct parport *p)
-{
-	int residue;
-	int cnfga;
-	const struct parport_pc_private *priv = p->physport->private_data;
-
-	/* Prevent further data transfer. */
-	parport_frob_control (p,
-			      PARPORT_CONTROL_STROBE,
-			      PARPORT_CONTROL_STROBE);
-
-	/* Adjust for the contents of the FIFO. */
-	for (residue = priv->fifo_depth; ; residue--) {
-		if (inb (ECONTROL (p)) & 0x2)
-				/* Full up. */
-			break;
-
-		outb (0, FIFO (p));
-	}
-
-	printk (KERN_DEBUG "%s: %d PWords were left in FIFO\n", p->name,
-		residue);
-
-	/* Reset the FIFO. */
-	frob_econtrol (p, 0xe0, 0x20);
-	parport_frob_control (p, PARPORT_CONTROL_STROBE, 0);
-
-	/* Now change to config mode and clean up. FIXME */
-	frob_econtrol (p, 0xe0, 0xe0);
-	cnfga = inb (CONFIGA (p));
-	printk (KERN_DEBUG "%s: cnfgA contains 0x%02x\n", p->name, cnfga);
-
-	if (!(cnfga & (1<<2))) {
-		printk (KERN_DEBUG "%s: Accounting for extra byte\n", p->name);
-		residue++;
-	}
-
-	/* Don't care about partial PWords until support is added for
-	 * PWord != 1 byte. */
-
-	/* Back to PS2 mode. */
-	frob_econtrol (p, 0xe0, 0x20);
-
-	return residue;
-}
-
-#endif /* IEEE 1284 support */
-
-/*
- * Clear TIMEOUT BIT in EPP MODE
- *
- * This is also used in SPP detection.
- */
-static int clear_epp_timeout(struct parport *pb)
-{
-	unsigned char r;
-
-	if (!(parport_pc_read_status(pb) & 0x01))
-		return 1;
-
-	/* To clear timeout some chips require double read */
-	parport_pc_read_status(pb);
-	r = parport_pc_read_status(pb);
-	outb (r | 0x01, STATUS (pb)); /* Some reset by writing 1 */
-	outb (r & 0xfe, STATUS (pb)); /* Others by writing 0 */
-	r = parport_pc_read_status(pb);
-
-	return !(r & 0x01);
-}
-
-/*
- * Access functions.
- *
- * These aren't static because they may be used by the parport_xxx_yyy
- * macros.  extern __inline__ versions of several of these are in
- * parport_pc.h.
- */
-
-static void parport_pc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	parport_generic_irq(irq, (struct parport *) dev_id, regs);
-}
-
-void parport_pc_write_data(struct parport *p, unsigned char d)
-{
-	outb (d, DATA (p));
-}
-
-unsigned char parport_pc_read_data(struct parport *p)
-{
-	return inb (DATA (p));
-}
-
-unsigned char __frob_control (struct parport *p, unsigned char mask,
-			      unsigned char val)
-{
-	struct parport_pc_private *priv = p->physport->private_data;
-	unsigned char ctr = priv->ctr;
-	ctr = (ctr & ~mask) ^ val;
-	ctr &= priv->ctr_writable; /* only write writable bits. */
-	outb (ctr, CONTROL (p));
-	return priv->ctr = ctr; /* update soft copy */
-}
-
-void parport_pc_write_control(struct parport *p, unsigned char d)
-{
-	const unsigned char wm = (PARPORT_CONTROL_STROBE |
-				  PARPORT_CONTROL_AUTOFD |
-				  PARPORT_CONTROL_INIT |
-				  PARPORT_CONTROL_SELECT);
-
-	/* Take this out when drivers have adapted to the newer interface. */
-	if (d & 0x20) {
-			printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n",
-					p->name, p->cad->name);
-			parport_pc_data_reverse (p);
-	}
-
-	__frob_control (p, wm, d & wm);
-}
-
-unsigned char parport_pc_read_control(struct parport *p)
-{
-	const struct parport_pc_private *priv = p->physport->private_data;
-	return priv->ctr; /* Use soft copy */
-}
-
-unsigned char parport_pc_frob_control (struct parport *p, unsigned char mask,
-				       unsigned char val)
-{
-	const unsigned char wm = (PARPORT_CONTROL_STROBE |
-				  PARPORT_CONTROL_AUTOFD |
-				  PARPORT_CONTROL_INIT |
-				  PARPORT_CONTROL_SELECT);
-
-	/* Take this out when drivers have adapted to the newer interface. */
-	if (mask & 0x20) {
-			printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n",
-					p->name, p->cad->name);
-			parport_pc_data_reverse (p);
-	}
-
-	/* Restrict mask and val to control lines. */
-	mask &= wm;
-	val &= wm;
-
-	return __frob_control (p, mask, val);
-}
-
-unsigned char parport_pc_read_status(struct parport *p)
-{
-	return inb (STATUS (p));
-}
-
-void parport_pc_disable_irq(struct parport *p)
-{
-	__frob_control (p, 0x10, 0);
-}
-
-void parport_pc_enable_irq(struct parport *p)
-{
-	__frob_control (p, 0x10, 0x10);
-}
-
-void parport_pc_data_forward (struct parport *p)
-{
-	__frob_control (p, 0x20, 0);
-}
-
-void parport_pc_data_reverse (struct parport *p)
-{
-	__frob_control (p, 0x20, 0x20);
-}
-
-void parport_pc_init_state(struct pardevice *dev, struct parport_state *s)
-{
-	s->u.pc.ctr = 0xc | (dev->irq_func ? 0x10 : 0x0);
-	s->u.pc.ecr = 0x24;
-}
-
-void parport_pc_save_state(struct parport *p, struct parport_state *s)
-{
-	const struct parport_pc_private *priv = p->physport->private_data;
-	s->u.pc.ctr = inb (CONTROL (p));
-	if (priv->ecr)
-		s->u.pc.ecr = inb (ECONTROL (p));
-}
-
-void parport_pc_restore_state(struct parport *p, struct parport_state *s)
-{
-	const struct parport_pc_private *priv = p->physport->private_data;
-	outb (s->u.pc.ctr, CONTROL (p));
-	if (priv->ecr)
-		outb (s->u.pc.ecr, ECONTROL (p));
-}
-
-#ifdef CONFIG_PARPORT_1284
-static size_t parport_pc_epp_read_data (struct parport *port, void *buf,
-					size_t length, int flags)
-{
-	size_t got = 0;
-	for (; got < length; got++) {
-		*((char*)buf)++ = inb (EPPDATA(port));
-		if (inb (STATUS(port)) & 0x01) {
-			clear_epp_timeout (port);
-			break;
-		}
-	}
-
-	return got;
-}
-
-static size_t parport_pc_epp_write_data (struct parport *port, const void *buf,
-					 size_t length, int flags)
-{
-	size_t written = 0;
-	for (; written < length; written++) {
-		outb (*((char*)buf)++, EPPDATA(port));
-		if (inb (STATUS(port)) & 0x01) {
-			clear_epp_timeout (port);
-			break;
-		}
-	}
-
-	return written;
-}
-
-static size_t parport_pc_epp_read_addr (struct parport *port, void *buf,
-					size_t length, int flags)
-{
-	size_t got = 0;
-	for (; got < length; got++) {
-		*((char*)buf)++ = inb (EPPADDR (port));
-		if (inb (STATUS (port)) & 0x01) {
-			clear_epp_timeout (port);
-			break;
-		}
-	}
-
-	return got;
-}
-
-static size_t parport_pc_epp_write_addr (struct parport *port,
-					 const void *buf, size_t length,
-					 int flags)
-{
-	size_t written = 0;
-	for (; written < length; written++) {
-		outb (*((char*)buf)++, EPPADDR (port));
-		if (inb (STATUS (port)) & 0x01) {
-			clear_epp_timeout (port);
-			break;
-		}
-	}
-
-	return written;
-}
-
-static size_t parport_pc_ecpepp_read_data (struct parport *port, void *buf,
-					   size_t length, int flags)
-{
-	size_t got;
-
-	frob_econtrol (port, 0xe0, ECR_EPP << 5);
-	got = parport_pc_epp_read_data (port, buf, length, flags);
-	frob_econtrol (port, 0xe0, ECR_PS2 << 5);
-
-	return got;
-}
-
-static size_t parport_pc_ecpepp_write_data (struct parport *port,
-					    const void *buf, size_t length,
-					    int flags)
-{
-	size_t written;
-
-	frob_econtrol (port, 0xe0, ECR_EPP << 5);
-	written = parport_pc_epp_write_data (port, buf, length, flags);
-	frob_econtrol (port, 0xe0, ECR_PS2 << 5);
-
-	return written;
-}
-
-static size_t parport_pc_ecpepp_read_addr (struct parport *port, void *buf,
-					   size_t length, int flags)
-{
-	size_t got;
-
-	frob_econtrol (port, 0xe0, ECR_EPP << 5);
-	got = parport_pc_epp_read_addr (port, buf, length, flags);
-	frob_econtrol (port, 0xe0, ECR_PS2 << 5);
-
-	return got;
-}
-
-static size_t parport_pc_ecpepp_write_addr (struct parport *port,
-					    const void *buf, size_t length,
-					    int flags)
-{
-	size_t written;
-
-	frob_econtrol (port, 0xe0, ECR_EPP << 5);
-	written = parport_pc_epp_write_addr (port, buf, length, flags);
-	frob_econtrol (port, 0xe0, ECR_PS2 << 5);
-
-	return written;
-}
-#endif /* IEEE 1284 support */
-
-#ifdef CONFIG_PARPORT_PC_FIFO
-static size_t parport_pc_fifo_write_block_pio (struct parport *port,
-					       const void *buf, size_t length)
-{
-	int ret = 0;
-	const unsigned char *bufp = buf;
-	size_t left = length;
-	long expire = jiffies + port->physport->cad->timeout;
-	const int fifo = FIFO (port);
-	int poll_for = 8; /* 80 usecs */
-	const struct parport_pc_private *priv = port->physport->private_data;
-	const int fifo_depth = priv->fifo_depth;
-
-	port = port->physport;
-
-	/* We don't want to be interrupted every character. */
-	parport_pc_disable_irq (port);
-	frob_econtrol (port, (1<<4), (1<<4)); /* nErrIntrEn */
-
-	/* Forward mode. */
-	parport_pc_data_forward (port);
-
-	while (left) {
-		unsigned char byte;
-		unsigned char ecrval = inb (ECONTROL (port));
-		int i = 0;
-
-		if (current->need_resched && time_before (jiffies, expire))
-			/* Can't yield the port. */
-			schedule ();
-
-		/* Anyone else waiting for the port? */
-		if (port->waithead) {
-			printk (KERN_DEBUG "Somebody wants the port\n");
-			break;
-		}
-
-		if (ecrval & 0x02) {
-			/* FIFO is full. Wait for interrupt. */
-
-			/* Clear serviceIntr */
-			outb (ecrval & ~(1<<2), ECONTROL (port));
-		false_alarm:
-			ret = parport_wait_event (port, HZ);
-			if (ret < 0) break;
-			ret = 0;
-			if (!time_before (jiffies, expire)) {
-				/* Timed out. */
-				printk (KERN_DEBUG "Timed out\n");
-				break;
-			}
-			ecrval = inb (ECONTROL (port));
-			if (!(ecrval & (1<<2))) {
-				if (current->need_resched &&
-				    time_before (jiffies, expire))
-					schedule ();
-
-				goto false_alarm;
-			}
-
-			continue;
-		}
-
-		/* Can't fail now. */
-		expire = jiffies + port->cad->timeout;
-
-	poll:
-		if (signal_pending (current))
-			break;
-
-		if (ecrval & 0x01) {
-			/* FIFO is empty. Blast it full. */
-			const int n = left < fifo_depth ? left : fifo_depth;
-			outsb (fifo, bufp, n);
-			bufp += n;
-			left -= n;
-
-			/* Adjust the poll time. */
-			if (i < (poll_for - 2)) poll_for--;
-			continue;
-		} else if (i++ < poll_for) {
-			udelay (10);
-			ecrval = inb (ECONTROL (port));
-			goto poll;
-		}
-
-		/* Half-full (call me an optimist) */
-		byte = *bufp++;
-		outb (byte, fifo);
-		left--;
-        }
-
-	return length - left;
-}
-
-static size_t parport_pc_fifo_write_block_dma (struct parport *port,
-					       const void *buf, size_t length)
-{
-	int ret = 0;
-	unsigned long dmaflag;
-	size_t left  = length;
-	const struct parport_pc_private *priv = port->physport->private_data;
-
-	port = port->physport;
-
-	/* We don't want to be interrupted every character. */
-	parport_pc_disable_irq (port);
-	frob_econtrol (port, (1<<4), (1<<4)); /* nErrIntrEn */
-
-	/* Forward mode. */
-	parport_pc_data_forward (port);
-
-	while (left) {
-		long expire = jiffies + port->physport->cad->timeout;
-
-		size_t count = left;
-
-		if (count > PAGE_SIZE)
-			count = PAGE_SIZE;
-
-		memcpy(priv->dma_buf, buf, count);
-
-		dmaflag = claim_dma_lock();
-		disable_dma(port->dma);
-		clear_dma_ff(port->dma);
-		set_dma_mode(port->dma, DMA_MODE_WRITE);
-		set_dma_addr(port->dma, virt_to_bus((volatile char *) priv->dma_buf));
-		set_dma_count(port->dma, count);
-
-		/* Set DMA mode */
-		frob_econtrol (port, 1<<3, 1<<3);
-
-		/* Clear serviceIntr */
-		frob_econtrol (port, 1<<2, 0);
-
-		enable_dma(port->dma);
-		release_dma_lock(dmaflag);
-
-		/* assume DMA will be successful */
-		left -= count;
-		buf  += count;
-
-		/* Wait for interrupt. */
-	false_alarm:
-		ret = parport_wait_event (port, HZ);
-		if (ret < 0) break;
-		ret = 0;
-		if (!time_before (jiffies, expire)) {
-			/* Timed out. */
-			printk (KERN_DEBUG "Timed out\n");
-			break;
-		}
-		/* Is serviceIntr set? */
-		if (!(inb (ECONTROL (port)) & (1<<2))) {
-			if (current->need_resched)
-				schedule ();
-
-			goto false_alarm;
-		}
-
-		dmaflag = claim_dma_lock();
-		disable_dma(port->dma);
-		clear_dma_ff(port->dma);
-		count = get_dma_residue(port->dma);
-		release_dma_lock(dmaflag);
-
-		if (current->need_resched)
-			/* Can't yield the port. */
-			schedule ();
-
-		/* Anyone else waiting for the port? */
-		if (port->waithead) {
-			printk (KERN_DEBUG "Somebody wants the port\n");
-			break;
-		}
-
-		/* update for possible DMA residue ! */
-		buf  -= count;
-		left += count;
-	}
-
-	/* Maybe got here through break, so adjust for DMA residue! */
-	dmaflag = claim_dma_lock();
-	disable_dma(port->dma);
-	clear_dma_ff(port->dma);
-	left += get_dma_residue(port->dma);
-	release_dma_lock(dmaflag);
-
-	/* Turn off DMA mode */
-	frob_econtrol (port, 1<<3, 0);
-
-	return length - left;
-}
-
-/* Parallel Port FIFO mode (ECP chipsets) */
-size_t parport_pc_compat_write_block_pio (struct parport *port,
-					  const void *buf, size_t length,
-					  int flags)
-{
-	size_t written;
-
-	/* Special case: a timeout of zero means we cannot call schedule(). */
-	if (!port->physport->cad->timeout)
-		return parport_ieee1284_write_compat (port, buf,
-						      length, flags);
-
-	/* Set up parallel port FIFO mode.*/
-	change_mode (port, ECR_PPF); /* Parallel port FIFO */
-	parport_pc_data_forward (port);
-	port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
-
-	/* Write the data to the FIFO. */
-	if (port->dma != PARPORT_DMA_NONE)
-		written = parport_pc_fifo_write_block_dma (port, buf, length);
-	else
-		written = parport_pc_fifo_write_block_pio (port, buf, length);
-
-	/* Finish up. */
-	if (change_mode (port, ECR_PS2) == -EBUSY) {
-		const struct parport_pc_private *priv = 
-			port->physport->private_data;
-
-		printk (KERN_DEBUG "%s: FIFO is stuck\n", port->name);
-
-		/* Prevent further data transfer. */
-		parport_frob_control (port,
-				      PARPORT_CONTROL_STROBE,
-				      PARPORT_CONTROL_STROBE);
-
-		/* Adjust for the contents of the FIFO. */
-		for (written -= priv->fifo_depth; ; written++) {
-			if (inb (ECONTROL (port)) & 0x2)
-				/* Full up. */
-				break;
-
-			outb (0, FIFO (port));
-		}
-
-		/* Reset the FIFO. */
-		frob_econtrol (port, 0xe0, 0);
-
-		/* De-assert strobe. */
-		parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
-	}
-
-	parport_wait_peripheral (port,
-				 PARPORT_STATUS_BUSY,
-				 PARPORT_STATUS_BUSY);
-	port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
-
-	return written;
-}
-
-/* ECP */
-#ifdef CONFIG_PARPORT_1284
-size_t parport_pc_ecp_write_block_pio (struct parport *port,
-				       const void *buf, size_t length,
-				       int flags)
-{
-	size_t written;
-
-	/* Special case: a timeout of zero means we cannot call schedule(). */
-	if (!port->physport->cad->timeout)
-		return parport_ieee1284_ecp_write_data (port, buf,
-							length, flags);
-
-	/* Switch to forward mode if necessary. */
-	if (port->physport->ieee1284.phase != IEEE1284_PH_FWD_IDLE) {
-		/* Event 47: Set nInit high. */
-		parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
-
-		/* Event 40: PError goes high. */
-		parport_wait_peripheral (port,
-					 PARPORT_STATUS_PAPEROUT,
-					 PARPORT_STATUS_PAPEROUT);
-	}
-
-	/* Set up ECP parallel port mode.*/
-	change_mode (port, ECR_ECP); /* ECP FIFO */
-	parport_pc_data_forward (port);
-	port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
-
-	/* Write the data to the FIFO. */
-	if (port->dma != PARPORT_DMA_NONE)
-		written = parport_pc_fifo_write_block_dma (port, buf, length);
-	else
-		written = parport_pc_fifo_write_block_pio (port, buf, length);
-
-	/* Finish up. */
-	if (change_mode (port, ECR_PS2) == -EBUSY) {
-		const struct parport_pc_private *priv =
-			port->physport->private_data;
-
-		printk (KERN_DEBUG "%s: FIFO is stuck\n", port->name);
-
-		/* Prevent further data transfer. */
-		parport_frob_control (port,
-				      PARPORT_CONTROL_STROBE,
-				      PARPORT_CONTROL_STROBE);
-
-		/* Adjust for the contents of the FIFO. */
-		for (written -= priv->fifo_depth; ; written++) {
-			if (inb (ECONTROL (port)) & 0x2)
-				/* Full up. */
-				break;
-
-			outb (0, FIFO (port));
-		}
-
-		/* Reset the FIFO. */
-		frob_econtrol (port, 0xe0, 0);
-		parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
-
-		/* Host transfer recovery. */
-		parport_frob_control (port,
-				      PARPORT_CONTROL_INIT,
-				      PARPORT_CONTROL_INIT);
-		parport_pc_data_reverse (port);
-		parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0);
-		parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
-		parport_wait_peripheral (port,
-					 PARPORT_STATUS_PAPEROUT,
-					 PARPORT_STATUS_PAPEROUT);
-	}
-
-	parport_wait_peripheral (port,
-				 PARPORT_STATUS_BUSY, 
-				 PARPORT_STATUS_BUSY);
-	port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
-
-	return written;
-}
-
-size_t parport_pc_ecp_read_block_pio (struct parport *port,
-				      void *buf, size_t length, int flags)
-{
-	size_t left = length;
-	size_t fifofull;
-	const int fifo = FIFO(port);
-	const struct parport_pc_private *priv = port->physport->private_data;
-	const int fifo_depth = priv->fifo_depth;
-	char *bufp = buf;
-
-	port = port->physport;
-
-	/* Special case: a timeout of zero means we cannot call schedule(). */
-	if (!port->cad->timeout)
-		return parport_ieee1284_ecp_read_data (port, buf,
-						       length, flags);
-
-	fifofull = fifo_depth;
-	if (port->ieee1284.mode == IEEE1284_MODE_ECPRLE)
-		/* If the peripheral is allowed to send RLE compressed
-		 * data, it is possible for a byte to expand to 128
-		 * bytes in the FIFO. */
-		fifofull = 128;
-
-	/* If the caller wants less than a full FIFO's worth of data,
-	 * go through software emulation.  Otherwise we may have to through
-	 * away data. */
-	if (length < fifofull)
-		return parport_ieee1284_ecp_read_data (port, buf,
-						       length, flags);
-
-	/* Switch to reverse mode if necessary. */
-	if (port->ieee1284.phase != IEEE1284_PH_REV_IDLE) {
-		/* Event 38: Set nAutoFd low */
-		parport_frob_control (port,
-				      PARPORT_CONTROL_AUTOFD,
-				      PARPORT_CONTROL_AUTOFD);
-		parport_pc_data_reverse (port);
-		udelay (5);
-
-		/* Event 39: Set nInit low to initiate bus reversal */
-		parport_frob_control (port,
-				      PARPORT_CONTROL_INIT,
-				      PARPORT_CONTROL_INIT);
-
-		/* Event 40: PError goes low */
-		parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0);
-	}
-
-	/* Set up ECP parallel port mode.*/
-	change_mode (port, ECR_ECP); /* ECP FIFO */
-	parport_pc_data_reverse (port);
-	port->ieee1284.phase = IEEE1284_PH_REV_DATA;
-
-	/* Do the transfer. */
-	while (left > fifofull) {
-		int ret;
-		long int expire = jiffies + port->cad->timeout;
-		unsigned char ecrval = inb (ECONTROL (port));
-
-		if (current->need_resched && time_before (jiffies, expire))
-			/* Can't yield the port. */
-			schedule ();
-
-		/* At this point, the FIFO may already be full.
-		 * Ideally, we'd be able to tell the port to hold on
-		 * for a second while we empty the FIFO, and we'd be
-		 * able to ensure that no data is lost.  I'm not sure
-		 * that's the case. :-(  It might be that you can play
-		 * games with STB, as in the forward case; someone should
-		 * look at a datasheet. */
-
-		if (ecrval & 0x01) {
-			/* FIFO is empty. Wait for interrupt. */
-
-			/* Anyone else waiting for the port? */
-			if (port->waithead) {
-				printk (KERN_DEBUG
-					"Somebody wants the port\n");
-				break;
-			}
-
-			/* Clear serviceIntr */
-			outb (ecrval & ~(1<<2), ECONTROL (port));
-		false_alarm:
-			ret = parport_wait_event (port, HZ);
-			if (ret < 0) break;
-			ret = 0;
-			if (!time_before (jiffies, expire)) {
-				/* Timed out. */
-				printk (KERN_DEBUG "Timed out\n");
-				break;
-			}
-			ecrval = inb (ECONTROL (port));
-			if (!(ecrval & (1<<2))) {
-				if (current->need_resched &&
-				    time_before (jiffies, expire))
-					schedule ();
-
-				goto false_alarm;
-			}
-
-			continue;
-		}
-
-		if (ecrval & 0x02) {
-			/* FIFO is full. */
-			insb (fifo, bufp, fifo_depth);
-			bufp += fifo_depth;
-			left -= fifo_depth;
-			continue;
-		}
-
-		*bufp++ = inb (fifo);
-		left--;
-	}
-
-	/* Finish up. */
-	if (change_mode (port, ECR_PS2) == -EBUSY) {
-		int lost = get_fifo_residue (port);
-		printk (KERN_DEBUG "%s: DATA LOSS (%d bytes)!\n", port->name,
-			lost);
-	}
-
-	port->ieee1284.phase = IEEE1284_PH_REV_IDLE;
-
-	return length - left;
-}
-
-#endif /* IEEE 1284 support */
-
-#endif /* Allowed to use FIFO/DMA */
-
-void parport_pc_inc_use_count(void)
-{
-#ifdef MODULE
-	MOD_INC_USE_COUNT;
-#endif
-}
-
-void parport_pc_dec_use_count(void)
-{
-#ifdef MODULE
-	MOD_DEC_USE_COUNT;
-#endif
-}
-
-static void parport_pc_fill_inode(struct inode *inode, int fill)
-{
-	/* Is this still needed? -tim */
-#ifdef MODULE
-	if (fill)
-		MOD_INC_USE_COUNT;
-	else
-		MOD_DEC_USE_COUNT;
-#endif
-}
-
-struct parport_operations parport_pc_ops = 
-{
-	parport_pc_write_data,
-	parport_pc_read_data,
-
-	parport_pc_write_control,
-	parport_pc_read_control,
-	parport_pc_frob_control,
-
-	parport_pc_read_status,
-
-	parport_pc_enable_irq,
-	parport_pc_disable_irq,
-
-	parport_pc_data_forward,
-	parport_pc_data_reverse,
-
-	parport_pc_interrupt,
-	parport_pc_init_state,
-	parport_pc_save_state,
-	parport_pc_restore_state,
-
-	parport_pc_inc_use_count,
-	parport_pc_dec_use_count,
-	parport_pc_fill_inode,
-
-	parport_ieee1284_epp_write_data,
-	parport_ieee1284_epp_read_data,
-	parport_ieee1284_epp_write_addr,
-	parport_ieee1284_epp_read_addr,
-
-	parport_ieee1284_ecp_write_data,
-	parport_ieee1284_ecp_read_data,
-	parport_ieee1284_ecp_write_addr,
-
-	parport_ieee1284_write_compat,
-	parport_ieee1284_read_nibble,
-	parport_ieee1284_read_byte,
-};
-
-/* --- Mode detection ------------------------------------- */
-
-/*
- * Checks for port existence, all ports support SPP MODE
- */
-static int __init parport_SPP_supported(struct parport *pb)
-{
-	unsigned char r, w;
-
-	/*
-	 * first clear an eventually pending EPP timeout 
-	 * I (sailer@ife.ee.ethz.ch) have an SMSC chipset
-	 * that does not even respond to SPP cycles if an EPP
-	 * timeout is pending
-	 */
-	clear_epp_timeout(pb);
-
-	/* Do a simple read-write test to make sure the port exists. */
-	w = 0xc;
-	outb (w, CONTROL (pb));
-
-	/* Is there a control register that we can read from?  Some
-	 * ports don't allow reads, so read_control just returns a
-	 * software copy. Some ports _do_ allow reads, so bypass the
-	 * software copy here.  In addition, some bits aren't
-	 * writable. */
-	r = inb (CONTROL (pb));
-	if ((r & 0xf) == w) {
-		w = 0xe;
-		outb (w, CONTROL (pb));
-		r = inb (CONTROL (pb));
-		outb (0xc, CONTROL (pb));
-		if ((r & 0xf) == w)
-			return PARPORT_MODE_PCSPP;
-	}
-
-	if (user_specified)
-		/* That didn't work, but the user thinks there's a
-		 * port here. */
-		printk (KERN_DEBUG "0x%lx: CTR: wrote 0x%02x, read 0x%02x\n",
-			pb->base, w, r);
-
-	/* Try the data register.  The data lines aren't tri-stated at
-	 * this stage, so we expect back what we wrote. */
-	w = 0xaa;
-	parport_pc_write_data (pb, w);
-	r = parport_pc_read_data (pb);
-	if (r == w) {
-		w = 0x55;
-		parport_pc_write_data (pb, w);
-		r = parport_pc_read_data (pb);
-		if (r == w)
-			return PARPORT_MODE_PCSPP;
-	}
-
-	if (user_specified)
-		/* Didn't work, but the user is convinced this is the
-		 * place. */
-		printk (KERN_DEBUG "0x%lx: DATA: wrote 0x%02x, read 0x%02x\n",
-			pb->base, w, r);
-
-	/* It's possible that we can't read the control register or
-	 * the data register.  In that case just believe the user. */
-	if (user_specified)
-		return PARPORT_MODE_PCSPP;
-
-	return 0;
-}
-
-/* Check for ECR
- *
- * Old style XT ports alias io ports every 0x400, hence accessing ECR
- * on these cards actually accesses the CTR.
- *
- * Modern cards don't do this but reading from ECR will return 0xff
- * regardless of what is written here if the card does NOT support
- * ECP.
- *
- * We first check to see if ECR is the same as CTR.  If not, the low
- * two bits of ECR aren't writable, so we check by writing ECR and
- * reading it back to see if it's what we expect.
- */
-static int __init parport_ECR_present(struct parport *pb)
-{
-	struct parport_pc_private *priv = pb->private_data;
-	unsigned char r = 0xc;
-
-	priv->ecr = 0;
-	outb (r, CONTROL (pb));
-	if ((inb (ECONTROL (pb)) & 0x3) == (r & 0x3)) {
-		outb (r ^ 0x2, CONTROL (pb)); /* Toggle bit 1 */
-
-		r = inb (CONTROL (pb));
-		if ((inb (ECONTROL (pb)) & 0x2) == (r & 0x2))
-			goto no_reg; /* Sure that no ECR register exists */
-	}
-	
-	if ((inb (ECONTROL (pb)) & 0x3 ) != 0x1)
-		goto no_reg;
-
-	outb (0x34, ECONTROL (pb));
-	if (inb (ECONTROL (pb)) != 0x35)
-		goto no_reg;
-
-	priv->ecr = 1;
-	outb (0xc, CONTROL (pb));
-	
-	/* Go to mode 000 */
-	frob_econtrol (pb, 0xe0, ECR_SPP << 5);
-
-	return 1;
-
- no_reg:
-	outb (0xc, CONTROL (pb));
-	return 0; 
-}
-
-#ifdef CONFIG_PARPORT_1284
-/* Detect PS/2 support.
- *
- * Bit 5 (0x20) sets the PS/2 data direction; setting this high
- * allows us to read data from the data lines.  In theory we would get back
- * 0xff but any peripheral attached to the port may drag some or all of the
- * lines down to zero.  So if we get back anything that isn't the contents
- * of the data register we deem PS/2 support to be present. 
- *
- * Some SPP ports have "half PS/2" ability - you can't turn off the line
- * drivers, but an external peripheral with sufficiently beefy drivers of
- * its own can overpower them and assert its own levels onto the bus, from
- * where they can then be read back as normal.  Ports with this property
- * and the right type of device attached are likely to fail the SPP test,
- * (as they will appear to have stuck bits) and so the fact that they might
- * be misdetected here is rather academic. 
- */
-
-static int __init parport_PS2_supported(struct parport *pb)
-{
-	int ok = 0;
-  
-	clear_epp_timeout(pb);
-
-	/* try to tri-state the buffer */
-	parport_pc_data_reverse (pb);
-	
-	parport_pc_write_data(pb, 0x55);
-	if (parport_pc_read_data(pb) != 0x55) ok++;
-
-	parport_pc_write_data(pb, 0xaa);
-	if (parport_pc_read_data(pb) != 0xaa) ok++;
-
-	/* cancel input mode */
-	parport_pc_data_forward (pb);
-
-	if (ok)
-		pb->modes |= PARPORT_MODE_TRISTATE;
-	else {
-		struct parport_pc_private *priv = pb->private_data;
-		priv->ctr_writable &= ~0x20;
-	}
-
-	return ok;
-}
-
-static int __init parport_ECP_supported(struct parport *pb)
-{
-	int i;
-	int config;
-	int pword;
-	struct parport_pc_private *priv = pb->private_data;
-
-	/* If there is no ECR, we have no hope of supporting ECP. */
-	if (!priv->ecr)
-		return 0;
-
-	/* Find out FIFO depth */
-	outb (ECR_SPP << 5, ECONTROL (pb)); /* Reset FIFO */
-	outb (ECR_TST << 5, ECONTROL (pb)); /* TEST FIFO */
-	for (i=0; i < 1024 && !(inb (ECONTROL (pb)) & 0x02); i++)
-		outb (0xaa, FIFO (pb));
-
-	/*
-	 * Using LGS chipset it uses ECR register, but
-	 * it doesn't support ECP or FIFO MODE
-	 */
-	if (i == 1024) {
-		outb (ECR_SPP << 5, ECONTROL (pb));
-		return 0;
-	}
-
-	priv->fifo_depth = i;
-	printk (KERN_INFO "0x%lx: FIFO is %d bytes\n", pb->base, i);
-
-	/* Find out writeIntrThreshold */
-	frob_econtrol (pb, 1<<2, 1<<2);
-	frob_econtrol (pb, 1<<2, 0);
-	for (i = 1; i <= priv->fifo_depth; i++) {
-		inb (FIFO (pb));
-		udelay (50);
-		if (inb (ECONTROL (pb)) & (1<<2))
-			break;
-	}
-
-	if (i <= priv->fifo_depth)
-		printk (KERN_INFO "0x%lx: writeIntrThreshold is %d\n",
-			pb->base, i);
-	else
-		/* Number of bytes we know we can write if we get an
-                   interrupt. */
-		i = 0;
-
-	priv->writeIntrThreshold = i;
-
-	/* Find out readIntrThreshold */
-	frob_econtrol (pb, 0xe0, ECR_PS2 << 5); /* Reset FIFO */
-	parport_pc_data_reverse (pb);
-	frob_econtrol (pb, 0xe0, ECR_TST << 5); /* Test FIFO */
-	frob_econtrol (pb, 1<<2, 1<<2);
-	frob_econtrol (pb, 1<<2, 0);
-	for (i = 1; i <= priv->fifo_depth; i++) {
-		outb (0xaa, FIFO (pb));
-		if (inb (ECONTROL (pb)) & (1<<2))
-			break;
-	}
-
-	if (i <= priv->fifo_depth)
-		printk (KERN_INFO "0x%lx: readIntrThreshold is %d\n",
-			pb->base, i);
-	else
-		/* Number of bytes we can read if we get an interrupt. */
-		i = 0;
-
-	priv->readIntrThreshold = i;
-
-	outb (ECR_SPP << 5, ECONTROL (pb)); /* Reset FIFO */
-	outb (0xf4, ECONTROL (pb)); /* Configuration mode */
-	config = inb (FIFO (pb));
-	pword = (config >> 4) & 0x7;
-	switch (pword) {
-	case 0:
-		pword = 2;
-		printk (KERN_WARNING "0x%lx: Unsupported pword size!\n",
-			pb->base);
-		break;
-	case 2:
-		pword = 4;
-		printk (KERN_WARNING "0x%lx: Unsupported pword size!\n",
-			pb->base);
-		break;
-	default:
-		printk (KERN_WARNING "0x%lx: Unknown implementation ID\n",
-			pb->base);
-		/* Assume 1 */
-	case 1:
-		pword = 1;
-	}
-	priv->pword = pword;
-	printk (KERN_DEBUG "0x%lx: PWord is %d bits\n", pb->base, 8 * pword);
-
-	config = inb (CONFIGB (pb));
-	printk (KERN_DEBUG "0x%lx: Interrupts are ISA-%s\n", pb->base,
-		config & 0x80 ? "Level" : "Pulses");
-
-	if (!(config & 0x40)) {
-		printk (KERN_WARNING "0x%lx: IRQ conflict!\n", pb->base);
-		pb->irq = PARPORT_IRQ_NONE;
-	}
-
-	/* Go back to mode 000 */
-	frob_econtrol (pb, 0xe0, ECR_SPP << 5);
-	pb->modes |= PARPORT_MODE_ECP;
-
-	return 1;
-}
-
-static int __init parport_ECPPS2_supported(struct parport *pb)
-{
-	const struct parport_pc_private *priv = pb->private_data;
-	int result;
-	unsigned char oecr;
-
-	if (!priv->ecr)
-		return 0;
-
-	oecr = inb (ECONTROL (pb));
-	outb (ECR_PS2 << 5, ECONTROL (pb));
-	
-	result = parport_PS2_supported(pb);
-
-	outb (oecr, ECONTROL (pb));
-	return result;
-}
-
-/* EPP mode detection  */
-
-static int __init parport_EPP_supported(struct parport *pb)
-{
-	const struct parport_pc_private *priv = pb->private_data;
-
-	/*
-	 * Theory:
-	 *	Bit 0 of STR is the EPP timeout bit, this bit is 0
-	 *	when EPP is possible and is set high when an EPP timeout
-	 *	occurs (EPP uses the HALT line to stop the CPU while it does
-	 *	the byte transfer, an EPP timeout occurs if the attached
-	 *	device fails to respond after 10 micro seconds).
-	 *
-	 *	This bit is cleared by either reading it (National Semi)
-	 *	or writing a 1 to the bit (SMC, UMC, WinBond), others ???
-	 *	This bit is always high in non EPP modes.
-	 */
-
-	/* If EPP timeout bit clear then EPP available */
-	if (!clear_epp_timeout(pb))
-		return 0;  /* No way to clear timeout */
-
-	/* Check for Intel bug. */
-	if (priv->ecr) {
-		unsigned char i;
-		for (i = 0x00; i < 0x80; i += 0x20) {
-			outb (i, ECONTROL (pb));
-			if (clear_epp_timeout (pb))
-				/* Phony EPP in ECP. */
-				return 0;
-		}
-	}
-
-	pb->modes |= PARPORT_MODE_EPP;
-
-	/* Set up access functions to use EPP hardware. */
-	parport_pc_ops.epp_read_data = parport_pc_epp_read_data;
-	parport_pc_ops.epp_write_data = parport_pc_epp_write_data;
-	parport_pc_ops.epp_read_addr = parport_pc_epp_read_addr;
-	parport_pc_ops.epp_write_addr = parport_pc_epp_write_addr;
-
-	return 1;
-}
-
-static int __init parport_ECPEPP_supported(struct parport *pb)
-{
-	struct parport_pc_private *priv = pb->private_data;
-	int result;
-	unsigned char oecr;
-
-	if (!priv->ecr)
-		return 0;
-
-	oecr = inb (ECONTROL (pb));
-	/* Search for SMC style EPP+ECP mode */
-	outb (0x80, ECONTROL (pb));
-	
-	result = parport_EPP_supported(pb);
-
-	outb (oecr, ECONTROL (pb));
-
-	if (result) {
-		/* Set up access functions to use ECP+EPP hardware. */
-		parport_pc_ops.epp_read_data = parport_pc_ecpepp_read_data;
-		parport_pc_ops.epp_write_data = parport_pc_ecpepp_write_data;
-		parport_pc_ops.epp_read_addr = parport_pc_ecpepp_read_addr;
-		parport_pc_ops.epp_write_addr = parport_pc_ecpepp_write_addr;
-	}
-
-	return result;
-}
-
-#else /* No IEEE 1284 support */
-
-/* Don't bother probing for modes we know we won't use. */
-static int __init parport_PS2_supported(struct parport *pb) { return 0; }
-static int __init parport_ECP_supported(struct parport *pb) { return 0; }
-static int __init parport_EPP_supported(struct parport *pb) { return 0; }
-static int __init parport_ECPEPP_supported(struct parport *pb) { return 0; }
-static int __init parport_ECPPS2_supported(struct parport *pb) { return 0; }
-
-#endif /* No IEEE 1284 support */
-
-/* --- IRQ detection -------------------------------------- */
-
-/* Only if supports ECP mode */
-static int __init programmable_irq_support(struct parport *pb)
-{
-	int irq, intrLine;
-	unsigned char oecr = inb (ECONTROL (pb));
-	static const int lookup[8] = {
-		PARPORT_IRQ_NONE, 7, 9, 10, 11, 14, 15, 5
-	};
-
-	outb (ECR_CNF << 5, ECONTROL (pb)); /* Configuration MODE */
-
-	intrLine = (inb (CONFIGB (pb)) >> 3) & 0x07;
-	irq = lookup[intrLine];
-
-	outb (oecr, ECONTROL (pb));
-	return irq;
-}
-
-static int __init irq_probe_ECP(struct parport *pb)
-{
-	int i;
-	unsigned long irqs;
-
-	sti();
-	irqs = probe_irq_on();
-		
-	outb (ECR_SPP << 5, ECONTROL (pb)); /* Reset FIFO */
-	outb ((ECR_TST << 5) | 0x04, ECONTROL (pb));
-	outb (ECR_TST << 5, ECONTROL (pb));
-
-	/* If Full FIFO sure that writeIntrThreshold is generated */
-	for (i=0; i < 1024 && !(inb (ECONTROL (pb)) & 0x02) ; i++) 
-		outb (0xaa, FIFO (pb));
-		
-	pb->irq = probe_irq_off(irqs);
-	outb (ECR_SPP << 5, ECONTROL (pb));
-
-	if (pb->irq <= 0)
-		pb->irq = PARPORT_IRQ_NONE;
-
-	return pb->irq;
-}
-
-/*
- * This detection seems that only works in National Semiconductors
- * This doesn't work in SMC, LGS, and Winbond 
- */
-static int __init irq_probe_EPP(struct parport *pb)
-{
-#ifndef ADVANCED_DETECT
-	return PARPORT_IRQ_NONE;
-#else
-	int irqs;
-	unsigned char oecr;
-
-	if (pb->modes & PARPORT_MODE_PCECR)
-		oecr = inb (ECONTROL (pb));
-
-	sti();
-	irqs = probe_irq_on();
-
-	if (pb->modes & PARPORT_MODE_PCECR)
-		frob_econtrol (pb, 0x10, 0x10);
-	
-	clear_epp_timeout(pb);
-	parport_pc_frob_control (pb, 0x20, 0x20);
-	parport_pc_frob_control (pb, 0x10, 0x10);
-	clear_epp_timeout(pb);
-
-	/* Device isn't expecting an EPP read
-	 * and generates an IRQ.
-	 */
-	parport_pc_read_epp(pb);
-	udelay(20);
-
-	pb->irq = probe_irq_off (irqs);
-	if (pb->modes & PARPORT_MODE_PCECR)
-		outb (oecr, ECONTROL (pb));
-	parport_pc_write_control(pb, 0xc);
-
-	if (pb->irq <= 0)
-		pb->irq = PARPORT_IRQ_NONE;
-
-	return pb->irq;
-#endif /* Advanced detection */
-}
-
-static int __init irq_probe_SPP(struct parport *pb)
-{
-	/* Don't even try to do this. */
-	return PARPORT_IRQ_NONE;
-}
-
-/* We will attempt to share interrupt requests since other devices
- * such as sound cards and network cards seem to like using the
- * printer IRQs.
- *
- * When ECP is available we can autoprobe for IRQs.
- * NOTE: If we can autoprobe it, we can register the IRQ.
- */
-static int __init parport_irq_probe(struct parport *pb)
-{
-	const struct parport_pc_private *priv = pb->private_data;
-
-	if (priv->ecr) {
-		pb->irq = programmable_irq_support(pb);
-		if (pb->irq != PARPORT_IRQ_NONE)
-			goto out;
-	}
-
-	if (pb->modes & PARPORT_MODE_ECP)
-		pb->irq = irq_probe_ECP(pb);
-
-	if (pb->irq == PARPORT_IRQ_NONE && priv->ecr &&
-	    (pb->modes & PARPORT_MODE_EPP))
-		pb->irq = irq_probe_EPP(pb);
-
-	clear_epp_timeout(pb);
-
-	if (pb->irq == PARPORT_IRQ_NONE && (pb->modes & PARPORT_MODE_EPP))
-		pb->irq = irq_probe_EPP(pb);
-
-	clear_epp_timeout(pb);
-
-	if (pb->irq == PARPORT_IRQ_NONE)
-		pb->irq = irq_probe_SPP(pb);
-
-out:
-	return pb->irq;
-}
-
-/* --- DMA detection -------------------------------------- */
-
-/* Only if supports ECP mode */
-static int __init programmable_dma_support (struct parport *p)
-{
-	unsigned char oecr = inb (ECONTROL (p));
-	int dma;
-
-	frob_econtrol (p, 0xe0, ECR_CNF << 5);
-	
-	dma = inb (CONFIGB(p)) & 0x03;
-	if (!dma)
-		dma = PARPORT_DMA_NONE;
-
-	outb (oecr, ECONTROL (p));
-	return dma;
-}
-
-static int __init parport_dma_probe (struct parport *p)
-{
-	const struct parport_pc_private *priv = p->private_data;
-	if (priv->ecr)
-		p->dma = programmable_dma_support(p);
-
-	return p->dma;
-}
-
-/* --- Initialisation code -------------------------------- */
-
-static int __init probe_one_port(unsigned long int base,
-				 unsigned long int base_hi,
-				 int irq, int dma)
-{
-	struct parport_pc_private *priv;
-	struct parport tmp;
-	struct parport *p = &tmp;
-	int probedirq = PARPORT_IRQ_NONE;
-	if (check_region(base, 3)) return 0;
-	priv = kmalloc (sizeof (struct parport_pc_private), GFP_KERNEL);
-	if (!priv) {
-		printk (KERN_DEBUG "parport (0x%lx): no memory!\n", base);
-		return 0;
-	}
-	priv->ctr = 0xc;
-	priv->ctr_writable = 0xff;
-	priv->ecr = 0;
-	priv->fifo_depth = 0;
-	priv->dma_buf = 0;
-	p->base = base;
-	p->base_hi = base_hi;
-	p->irq = irq;
-	p->dma = dma;
-	p->modes = PARPORT_MODE_PCSPP;
-	p->ops = &parport_pc_ops;
-	p->private_data = priv;
-	p->physport = p;
-	if (base_hi && !check_region(base_hi,3)) {
-		parport_ECR_present(p);
-		parport_ECP_supported(p);
-		parport_ECPPS2_supported(p);
-	}
-	if (base != 0x3bc) {
-		if (!check_region(base+0x3, 5)) {
-			parport_EPP_supported(p);
-			if (!(p->modes & PARPORT_MODE_EPP))
-				parport_ECPEPP_supported(p);
-		}
-	}
-	if (!parport_SPP_supported (p)) {
-		/* No port. */
-		kfree (priv);
-		return 0;
-	}
-
-	parport_PS2_supported (p);
-
-	if (!(p = parport_register_port(base, PARPORT_IRQ_NONE,
-									PARPORT_DMA_NONE, &parport_pc_ops))) {
-		kfree (priv);
-		return 0;
-	}
-
-	p->base_hi = base_hi;
-	p->modes = tmp.modes;
-	p->size = (p->modes & PARPORT_MODE_EPP)?8:3;
-	p->private_data = priv;
-
-	printk(KERN_INFO "%s: PC-style at 0x%lx", p->name, p->base);
-	if (p->base_hi && (p->modes & PARPORT_MODE_ECP))
-		printk(" (0x%lx)", p->base_hi);
-	p->irq = irq;
-	p->dma = dma;
-	if (p->irq == PARPORT_IRQ_AUTO) {
-		p->irq = PARPORT_IRQ_NONE;
-		parport_irq_probe(p);
-	} else if (p->irq == PARPORT_IRQ_PROBEONLY) {
-		p->irq = PARPORT_IRQ_NONE;
-		parport_irq_probe(p);
-		probedirq = p->irq;
-		p->irq = PARPORT_IRQ_NONE;
-	}
-	if (p->irq != PARPORT_IRQ_NONE) {
-		printk(", irq %d", p->irq);
-
-		if (p->dma == PARPORT_DMA_AUTO) {
-			p->dma = PARPORT_DMA_NONE;
-			parport_dma_probe(p);
-		}
-	}
-	if (p->dma == PARPORT_DMA_AUTO)		
-		p->dma = PARPORT_DMA_NONE;
-	if (p->dma != PARPORT_DMA_NONE) 
-		printk(", dma %d", p->dma);
-
-#ifdef CONFIG_PARPORT_PC_FIFO
-	if (priv->fifo_depth > 0 && p->irq != PARPORT_IRQ_NONE) {
-		parport_pc_ops.compat_write_data =
-			parport_pc_compat_write_block_pio;
-#ifdef CONFIG_PARPORT_1284
-		parport_pc_ops.ecp_write_data =
-			parport_pc_ecp_write_block_pio;
-#endif /* IEEE 1284 support */
-		if (p->dma != PARPORT_DMA_NONE)
-			p->modes |= PARPORT_MODE_DMA;
-		printk(", using FIFO");
-	}
-#endif /* Allowed to use FIFO/DMA */
-
-	printk(" [");
-#define printmode(x) {if(p->modes&PARPORT_MODE_##x){printk("%s%s",f?",":"",#x);f++;}}
-	{
-		int f = 0;
-		printmode(PCSPP);
-		printmode(TRISTATE);
-		printmode(COMPAT)
-		printmode(EPP);
-		printmode(ECP);
-		printmode(DMA);
-	}
-#undef printmode
-	printk("]\n");
-	if (probedirq != PARPORT_IRQ_NONE) 
-		printk("%s: irq %d detected\n", p->name, probedirq);
-	parport_proc_register(p);
-
-	request_region (p->base, 3, p->name);
-	if (p->size > 3)
-		request_region (p->base + 3, p->size - 3, p->name);
-	if (p->modes & PARPORT_MODE_ECP)
-		request_region (p->base_hi, 3, p->name);
-
-	if (p->irq != PARPORT_IRQ_NONE) {
-		if (request_irq (p->irq, parport_pc_interrupt,
-				 0, p->name, p)) {
-			printk (KERN_WARNING "%s: irq %d in use, "
-				"resorting to polled operation\n",
-				p->name, p->irq);
-			p->irq = PARPORT_IRQ_NONE;
-			p->dma = PARPORT_DMA_NONE;
-		}
-
-		if (p->dma != PARPORT_DMA_NONE) {
-			if (request_dma (p->dma, p->name)) {
-				printk (KERN_WARNING "%s: dma %d in use, "
-					"resorting to PIO operation\n",
-					p->name, p->dma);
-				p->dma = PARPORT_DMA_NONE;
-			} else {
-				priv->dma_buf = (char *) __get_dma_pages(GFP_KERNEL, 1);
-				if (! priv->dma_buf) {
-					printk (KERN_WARNING "%s: "
-						"cannot get buffer for DMA, "
-						"resorting to PIO operation\n",
-						p->name);
-					free_dma(p->dma);
-					p->dma = PARPORT_DMA_NONE;
-				}
-			}
-		}
-	}
-
-	/* Done probing.  Now put the port into a sensible start-up state.
-	 * SELECT | INIT also puts IEEE1284-compliant devices into
-	 * compatibility mode. */
-	if (p->modes & PARPORT_MODE_ECP)
-		/*
-		 * Put the ECP detected port in PS2 mode.
-		 */
-		outb (0x24, ECONTROL (p));
-
-	parport_pc_write_data(p, 0);
-	parport_pc_data_forward (p);
-	parport_pc_write_control(p, PARPORT_CONTROL_SELECT);
-	udelay (50);
-	parport_pc_write_control(p,
-				 PARPORT_CONTROL_SELECT
-				 | PARPORT_CONTROL_INIT);
-	udelay (50);
-
-	/* Now that we've told the sharing engine about the port, and
-	   found out its characteristics, let the high-level drivers
-	   know about it. */
-	parport_announce_port (p);
-
-	return 1;
-}
-
-/* Look for PCI parallel port cards. */
-static int __init parport_pc_init_pci (int irq, int dma)
-{
-/* These need to go in pci.h: */
-#ifndef PCI_VENDOR_ID_SIIG
-#define PCI_VENDOR_ID_SIIG              0x131f
-#define PCI_DEVICE_ID_SIIG_1S1P_10x_550 0x1010
-#define PCI_DEVICE_ID_SIIG_1S1P_10x_650 0x1011
-#define PCI_DEVICE_ID_SIIG_1S1P_10x_850 0x1012
-#define PCI_DEVICE_ID_SIIG_1P_10x       0x1020
-#define PCI_DEVICE_ID_SIIG_2P_10x       0x1021
-#define PCI_DEVICE_ID_SIIG_2S1P_10x_550 0x1034
-#define PCI_DEVICE_ID_SIIG_2S1P_10x_650 0x1035
-#define PCI_DEVICE_ID_SIIG_2S1P_10x_850 0x1036
-#define PCI_DEVICE_ID_SIIG_1P_20x       0x2020
-#define PCI_DEVICE_ID_SIIG_2P_20x       0x2021
-#define PCI_DEVICE_ID_SIIG_2P1S_20x_550 0x2040
-#define PCI_DEVICE_ID_SIIG_2P1S_20x_650 0x2041
-#define PCI_DEVICE_ID_SIIG_2P1S_20x_850 0x2042
-#define PCI_DEVICE_ID_SIIG_1S1P_20x_550 0x2010
-#define PCI_DEVICE_ID_SIIG_1S1P_20x_650 0x2011
-#define PCI_DEVICE_ID_SIIG_1S1P_20x_850 0x2012
-#define PCI_DEVICE_ID_SIIG_2S1P_20x_550 0x2060
-#define PCI_DEVICE_ID_SIIG_2S1P_20x_650 0x2061
-#define PCI_DEVICE_ID_SIIG_2S1P_20x_850 0x2062
-#define PCI_VENDOR_ID_LAVA              0x1407
-#define PCI_DEVICE_ID_LAVA_PARALLEL     0x8000
-#define PCI_DEVICE_ID_LAVA_DUAL_PAR_A   0x8001 /* The Lava Dual Parallel is */
-#define PCI_DEVICE_ID_LAVA_DUAL_PAR_B   0x8002 /* two PCI devices on a card */
-#endif
-
-	struct {
-		unsigned int vendor;
-		unsigned int device;
-		unsigned int numports;
-		struct {
-			unsigned int lo;
-			unsigned int hi; /* -ve if not there */
-		} addr[4];
-	} cards[] = {
-		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_550, 1,
-		  { { 3, 4 }, } },
-		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_650, 1,
-		  { { 3, 4 }, } },
-		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_850, 1,
-		  { { 3, 4 }, } },
-		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1P_10x, 1,
-		  { { 2, 3 }, } },
-		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P_10x, 2,
-		  { { 2, 3 }, { 4, 5 }, } },
-		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_550, 1,
-		  { { 4, 5 }, } },
-		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_650, 1,
-		  { { 4, 5 }, } },
-		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_850, 1,
-		  { { 4, 5 }, } },
-		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1P_20x, 1,
-		  { { 0, 1 }, } },
-		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P_20x, 2,
-		  { { 0, 1 }, { 2, 3 }, } },
-		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_550, 2,
-		  { { 1, 2 }, { 3, 4 }, } },
-		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_650, 2,
-		  { { 1, 2 }, { 3, 4 }, } },
-		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_850, 2,
-		  { { 1, 2 }, { 3, 4 }, } },
-		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_550, 1,
-		  { { 1, 2 }, } },
-		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_650, 1,
-		  { { 1, 2 }, } },
-		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_850, 1,
-		  { { 1, 2 }, } },
-		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_550, 1,
-		  { { 2, 3 }, } },
-		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_650, 1,
-		  { { 2, 3 }, } },
-		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_850, 1,
-		  { { 2, 3 }, } },
-		{ PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PARALLEL, 1,
-		  { { 0, -1 }, } },
-		{ PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DUAL_PAR_A, 1,
-		  { { 0, -1 }, } },
-		{ PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DUAL_PAR_B, 1,
-		  { { 0, -1 }, } },
-		{ 0, }
-	};
-
-	int count = 0;
-	int i;
-
-	if (!pci_present ())
-		return 0;
-
-	for (i = 0; cards[i].vendor; i++) {
-		struct pci_dev *pcidev = NULL;
-		while ((pcidev = pci_find_device (cards[i].vendor,
-						  cards[i].device,
-						  pcidev)) != NULL) {
-			int n;
-			for (n = 0; n < cards[i].numports; n++) {
-				int lo = cards[i].addr[n].lo;
-				int hi = cards[i].addr[n].hi;
-				int io_lo = pcidev->base_address[lo];
-				int io_hi = ((hi < 0) ? 0 :
-					     pcidev->base_address[hi]);
-				io_lo &= PCI_BASE_ADDRESS_IO_MASK;
-				io_hi &= PCI_BASE_ADDRESS_IO_MASK;
-				count += probe_one_port (io_lo, io_hi,
-							 irq, dma);
-			}
-		}
-	}
-
-	return count;
-}
-
-int __init parport_pc_init(int *io, int *io_hi, int *irq, int *dma)
-{
-	int count = 0, i = 0;
-	if (io && *io) {
-		/* Only probe the ports we were given. */
-		user_specified = 1;
-		do {
-			if (!*io_hi) *io_hi = 0x400 + *io;
-			count += probe_one_port(*(io++), *(io_hi++),
-						*(irq++), *(dma++));
-		} while (*io && (++i < PARPORT_PC_MAX_PORTS));
-	} else {
-		/* Probe all the likely ports. */
-		count += probe_one_port(0x3bc, 0x7bc, irq[0], dma[0]);
-		count += probe_one_port(0x378, 0x778, irq[0], dma[0]);
-		count += probe_one_port(0x278, 0x678, irq[0], dma[0]);
-		count += parport_pc_init_pci (irq[0], dma[0]);
-	}
-
-	return count;
-}
-
-#ifdef MODULE
-static int io[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 };
-static int io_hi[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 };
-static int dmaval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_DMA_AUTO };
-static int irqval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_IRQ_PROBEONLY };
-static const char *irq[PARPORT_PC_MAX_PORTS] = { NULL, };
-static const char *dma[PARPORT_PC_MAX_PORTS] = { NULL, };
-MODULE_PARM(io, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i");
-MODULE_PARM(io_hi, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i");
-MODULE_PARM(irq, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s");
-MODULE_PARM(dma, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s");
-
-int init_module(void)
-{	
-	/* Work out how many ports we have, then get parport_share to parse
-	   the irq values. */
-	unsigned int i;
-	for (i = 0; i < PARPORT_PC_MAX_PORTS && io[i]; i++);
-	if (i) {
-		if (parport_parse_irqs(i, irq, irqval)) return 1;
-		if (parport_parse_dmas(i, dma, dmaval)) return 1;
-	}
-	else {
-		/* The user can make us use any IRQs or DMAs we find. */
-		int val;
-
-		if (irq[0] && !parport_parse_irqs (1, irq, &val))
-			switch (val) {
-			case PARPORT_IRQ_NONE:
-			case PARPORT_IRQ_AUTO:
-				irqval[0] = val;
-			}
-
-		if (dma[0] && !parport_parse_dmas (1, dma, &val))
-			switch (val) {
-			case PARPORT_DMA_NONE:
-			case PARPORT_DMA_AUTO:
-				dmaval[0] = val;
-			}
-	}
-
-	return (parport_pc_init(io, io_hi, irqval, dmaval)?0:1);
-}
-
-void cleanup_module(void)
-{
-	struct parport *p = parport_enumerate(), *tmp;
-	while (p) {
-		tmp = p->next;
-		if (p->modes & PARPORT_MODE_PCSPP) { 
-			struct parport_pc_private *priv = p->private_data;
-			if (p->dma != PARPORT_DMA_NONE)
-				free_dma(p->dma);
-			if (p->irq != PARPORT_IRQ_NONE)
-				free_irq(p->irq, p);
-			release_region(p->base, 3);
-			if (p->size > 3);
-				release_region(p->base + 3, p->size - 3);
-			if (p->modes & PARPORT_MODE_ECP)
-				release_region(p->base_hi, 3);
-			parport_proc_unregister(p);
-			if (priv->dma_buf)
-				free_page((unsigned long) priv->dma_buf);
-			kfree (p->private_data);
-			parport_unregister_port(p);
-		}
-		p = tmp;
-	}
-}
-#endif
diff -u --recursive --new-file v2.3.11/linux/drivers/misc/parport_probe.c linux/drivers/misc/parport_probe.c
--- v2.3.11/linux/drivers/misc/parport_probe.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/misc/parport_probe.c	Wed Dec 31 16:00:00 1969
@@ -1,212 +0,0 @@
-/* $Id: parport_probe.c,v 1.1 1999/07/03 08:56:17 davem Exp $
- * Parallel port device probing code
- *
- * Authors:    Carsten Gross, carsten@sol.wohnheim.uni-ulm.de
- *             Philip Blundell <Philip.Blundell@pobox.com>
- */
-
-#include <linux/parport.h>
-#include <linux/ctype.h>
-#include <asm/uaccess.h>
-
-static struct {
-	char *token;
-	char *descr;
-} classes[] = {
-	{ "",            "Legacy device" },
-	{ "PRINTER",     "Printer" },
-	{ "MODEM",       "Modem" },
-	{ "NET",         "Network device" },
-	{ "HDC",       	 "Hard disk" },
-	{ "PCMCIA",      "PCMCIA" },
-	{ "MEDIA",       "Multimedia device" },
-	{ "FDC",         "Floppy disk" },
-	{ "PORTS",       "Ports" },
-	{ "SCANNER",     "Scanner" },
-	{ "DIGICAM",     "Digital camera" },
-	{ "",            "Unknown device" },
-	{ "",            "Unspecified" },
-	{ "SCSIADAPTER", "SCSI adapter" },
-	{ NULL,          NULL }
-};
-
-static void pretty_print(struct parport *port, int device)
-{
-	struct parport_device_info *info = &port->probe_info[device + 1];
-
-	printk(KERN_INFO "%s", port->name);
-
-	if (device >= 0)
-		printk (" (addr %d)", device);
-
-	printk (": %s", classes[info->class].descr);
-	if (info->class)
-		printk(", %s %s", info->mfr, info->model);
-
-	printk("\n");
-}
-
-static char *strdup(char *str)
-{
-	int n = strlen(str)+1;
-	char *s = kmalloc(n, GFP_KERNEL);
-	if (!s) return NULL;
-	return strcpy(s, str);
-}
-
-static void parse_data(struct parport *port, int device, char *str)
-{
-	char *txt = kmalloc(strlen(str)+1, GFP_KERNEL);
-	char *p = txt, *q;
-	int guessed_class = PARPORT_CLASS_UNSPEC;
-	struct parport_device_info *info = &port->probe_info[device + 1];
-
-	if (!txt) {
-		printk("%s probe: memory squeeze\n", port->name);
-		return;
-	}
-	strcpy(txt, str);
-	while (p) {
-		char *sep;
-		q = strchr(p, ';');
-		if (q) *q = 0;
-		sep = strchr(p, ':');
-		if (sep) {
-			char *u = p;
-			*(sep++) = 0;
-			while (*u) {
-				*u = toupper(*u);
-				u++;
-			}
-			if (!strcmp(p, "MFG") || !strcmp(p, "MANUFACTURER")) {
-				if (info->mfr)
-					kfree (info->mfr);
-				info->mfr = strdup(sep);
-			} else if (!strcmp(p, "MDL") || !strcmp(p, "MODEL")) {
-				if (info->model)
-					kfree (info->model);
-				info->model = strdup(sep);
-			} else if (!strcmp(p, "CLS") || !strcmp(p, "CLASS")) {
-				int i;
-				if (info->class_name)
-					kfree (info->class_name);
-				info->class_name = strdup(sep);
-				for (u = sep; *u; u++)
-					*u = toupper(*u);
-				for (i = 0; classes[i].token; i++) {
-					if (!strcmp(classes[i].token, sep)) {
-						info->class = i;
-						goto rock_on;
-					}
-				}
-				printk(KERN_WARNING "%s probe: warning, class '%s' not understood.\n", port->name, sep);
-				info->class = PARPORT_CLASS_OTHER;
-			} else if (!strcmp(p, "CMD") ||
-				   !strcmp(p, "COMMAND SET")) {
-				if (info->cmdset)
-					kfree (info->cmdset);
-				info->cmdset = strdup(sep);
-				/* if it speaks printer language, it's
-				   probably a printer */
-				if (strstr(sep, "PJL") || strstr(sep, "PCL"))
-					guessed_class = PARPORT_CLASS_PRINTER;
-			} else if (!strcmp(p, "DES") || !strcmp(p, "DESCRIPTION")) {
-				if (info->description)
-					kfree (info->description);
-				info->description = strdup(sep);
-			}
-		}
-	rock_on:
-		if (q) p = q+1; else p=NULL;
-	}
-
-	/* If the device didn't tell us its class, maybe we have managed to
-	   guess one from the things it did say. */
-	if (info->class == PARPORT_CLASS_UNSPEC)
-		info->class = guessed_class;
-
-	pretty_print (port, device);
-
-	kfree(txt);
-}
-
-/* Get Std 1284 Device ID. */
-ssize_t parport_device_id (int devnum, char *buffer, size_t len)
-{
-	ssize_t retval = -ENXIO;
-	struct pardevice *dev = parport_open (devnum, "Device ID probe",
-					      NULL, NULL, NULL, 0, NULL);
-	if (!dev)
-		return -ENXIO;
-
-	parport_claim_or_block (dev);
-
-	/* Negotiate to compatibility mode, and then to device ID mode.
-	 * (This is in case we are already in device ID mode.) */
-	parport_negotiate (dev->port, IEEE1284_MODE_COMPAT);
-	retval = parport_negotiate (dev->port,
-				    IEEE1284_MODE_NIBBLE | IEEE1284_DEVICEID);
-
-	if (!retval) {
-		int idlen;
-		unsigned char length[2];
-		mm_segment_t oldfs = get_fs ();
-		set_fs (get_ds ());
-
-		/* First two bytes are MSB,LSB of inclusive length. */
-		retval = parport_read (dev->port, length, 2);
-
-		if (retval != 2) goto restore_fs;
-
-		idlen = (length[0] << 8) + length[1] - 2;
-		if (idlen < len)
-			len = idlen;
-		retval = parport_read (dev->port, buffer, len);
-
-		if (retval != len) {
-			printk (KERN_DEBUG "%s: only read %d of %d ID bytes\n",
-				dev->port->name, retval, len);
-			goto restore_fs;
-		}
-
-		/* Some printer manufacturers mistakenly believe that
-                   the length field is supposed to be _exclusive_. */
-		/* In addition, there are broken devices out there
-                   that don't even finish off with a semi-colon. */
-		if (idlen == len && buffer[len - 1] != ';') {
-			ssize_t diff;
-			diff = parport_read (dev->port, buffer + len, 2);
-			retval += diff;
-
-			if (diff)
-				printk (KERN_DEBUG
-					"%s: device reported incorrect "
-					"length field (%d, should be %d)\n",
-					dev->port->name, idlen, retval);
-			else {
-				/* One semi-colon short of a device ID. */
-				buffer[len++] = ';';
-				buffer[len] = '\0';
-				printk (KERN_DEBUG "%s: faking semi-colon\n",
-					dev->port->name);
-
-				/* If we get here, I don't think we
-                                   need to worry about the possible
-                                   standard violation of having read
-                                   more than we were told to.  The
-                                   device is non-compliant anyhow. */
-			}
-		}
-
-	restore_fs:
-		set_fs (oldfs);
-		parport_negotiate (dev->port, IEEE1284_MODE_COMPAT);
-	}
-	parport_release (dev);
-
-	if (retval > 0)
-		parse_data (dev->port, dev->daisy, buffer);
-
-	parport_close (dev);
-	return retval;
-}
diff -u --recursive --new-file v2.3.11/linux/drivers/misc/parport_procfs.c linux/drivers/misc/parport_procfs.c
--- v2.3.11/linux/drivers/misc/parport_procfs.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/misc/parport_procfs.c	Wed Dec 31 16:00:00 1969
@@ -1,434 +0,0 @@
-/* Sysctl interface for parport devices.
- * 
- * Authors: David Campbell <campbell@torque.net>
- *          Tim Waugh <tim@cyberelk.demon.co.uk>
- *          Philip Blundell <philb@gnu.org>
- *          Andrea Arcangeli
- *          Riccardo Facchetti <fizban@tin.it>
- *
- * based on work by Grant Guenther <grant@torque.net>
- *              and Philip Blundell
- *
- * Cleaned up include files - Russell King <linux@arm.uk.linux.org>
- */
-
-#include <linux/string.h>
-#include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/malloc.h>
-#include <linux/parport.h>
-#include <linux/ctype.h>
-#include <linux/sysctl.h>
-
-#include <asm/uaccess.h>
-
-#ifdef CONFIG_SYSCTL
-
-
-static int do_active_device(ctl_table *table, int write, struct file *filp,
-		      void *result, size_t *lenp)
-{
-	struct parport *port = (struct parport *)table->extra1;
-	char buffer[256];
-	struct pardevice *dev;
-	int len = 0;
-
-	if (write)		/* can't happen anyway */
-		return -EACCES;
-
-	if (filp->f_pos) {
-		*lenp = 0;
-		return 0;
-	}
-	
-	for (dev = port->devices; dev ; dev = dev->next) {
-		if(dev == port->cad) {
-			len += sprintf(buffer, "%s\n", dev->name);
-		}
-	}
-
-	if(!len) {
-		len += sprintf(buffer, "%s\n", "none");
-	}
-
-	if (len > *lenp)
-		len = *lenp;
-	else
-		*lenp = len;
-
-	filp->f_pos += len;
-
-	return copy_to_user(result, buffer, len) ? -EFAULT : 0;
-}
-
-#ifdef CONFIG_PARPORT_1284
-static int do_autoprobe(ctl_table *table, int write, struct file *filp,
-			void *result, size_t *lenp)
-{
-	struct parport_device_info *info = table->extra2;
-	const char *str;
-	char buffer[256];
-	int len = 0;
-
-	if (write) /* permissions stop this */
-		return -EACCES;
-
-	if (filp->f_pos) {
-		*lenp = 0;
-		return 0;
-	}
-	
-	if ((str = info->class_name) != NULL)
-		len += sprintf (buffer + len, "CLASS:%s;\n", str);
-
-	if ((str = info->model) != NULL)
-		len += sprintf (buffer + len, "MODEL:%s;\n", str);
-
-	if ((str = info->mfr) != NULL)
-		len += sprintf (buffer + len, "MANUFACTURER:%s;\n", str);
-
-	if ((str = info->description) != NULL)
-		len += sprintf (buffer + len, "DESCRIPTION:%s;\n", str);
-
-	if ((str = info->cmdset) != NULL)
-		len += sprintf (buffer + len, "COMMAND SET:%s;\n", str);
-
-	if (len > *lenp)
-		len = *lenp;
-	else
-		*lenp = len;
-
-	filp->f_pos += len;
-
-	return copy_to_user (result, buffer, len) ? -EFAULT : 0;
-}
-#endif /* IEEE1284.3 support. */
-
-static int do_hardware(ctl_table *table, int write, struct file *filp,
-		       void *result, size_t *lenp)
-{
-	struct parport *port = (struct parport *)table->extra1;
-	char buffer[256];
-	int len = 0;
-
-	if (filp->f_pos) {
-		*lenp = 0;
-		return 0;
-	}
-	
-	if (write)		/* can't happen anyway */
-		return -EACCES;
-	
-	len += sprintf(buffer+len, "base:\t0x%lx", port->base);
-	if (port->base_hi)
-		len += sprintf(buffer+len, " (0x%lx)", port->base_hi);
-	buffer[len++] = '\n';
-
-	if (port->irq == PARPORT_IRQ_NONE) {
-		len += sprintf(buffer+len, "irq:\tnone\n");
-	} else {
-#ifdef __sparc__
-		len += sprintf(buffer+len, "irq:\t%s\n", 
-			       __irq_itoa(port->irq));
-#else
-		len += sprintf(buffer+len, "irq:\t%d\n", port->irq);
-#endif
-	}
-
-	if (port->dma == PARPORT_DMA_NONE)
-		len += sprintf(buffer+len, "dma:\tnone\n");
-	else
-		len += sprintf(buffer+len, "dma:\t%d\n", port->dma);
-
-	len += sprintf(buffer+len, "modes:\t");
-	{
-#define printmode(x) {if(port->modes&PARPORT_MODE_##x){len+=sprintf(buffer+len,"%s%s",f?",":"",#x);f++;}}
-		int f = 0;
-		printmode(PCSPP);
-		printmode(TRISTATE);
-		printmode(COMPAT);
-		printmode(EPP);
-		printmode(ECP);
-		printmode(DMA);
-#undef printmode
-	}
-	buffer[len++] = '\n';
-
-	if (len > *lenp)
-		len = *lenp;
-	else
-		*lenp = len;
-
-	filp->f_pos += len;
-
-	return copy_to_user(result, buffer, len) ? -EFAULT : 0;
-}
-
-#define PARPORT_PORT_DIR(child) { 0, NULL, NULL, 0, 0555, child }
-#define PARPORT_PARPORT_DIR(child) { DEV_PARPORT, "parport", \
-                                     NULL, 0, 0555, child }
-#define PARPORT_DEV_DIR(child) { CTL_DEV, "dev", NULL, 0, 0555, child }
-#define PARPORT_DEVICES_ROOT_DIR  { DEV_PARPORT_DEVICES, "devices", \
-                                    NULL, 0, 0555, NULL }
-
-
-struct parport_sysctl_table {
-	struct ctl_table_header *sysctl_header;
-	ctl_table vars[9];
-	ctl_table device_dir[2];
-	ctl_table port_dir[2];
-	ctl_table parport_dir[2];
-	ctl_table dev_dir[2];
-};
-
-static const struct parport_sysctl_table parport_sysctl_template = {
-	NULL,
-        {
-		{ DEV_PARPORT_SPINTIME, "spintime",
-		  NULL, sizeof(int), 0644, NULL,
-		  &proc_dointvec },
-		{ DEV_PARPORT_HARDWARE, "hardware",
-		  NULL, 0, 0444, NULL,
-		  &do_hardware },
-		PARPORT_DEVICES_ROOT_DIR,
-#ifdef CONFIG_PARPORT_1284
-		{ DEV_PARPORT_AUTOPROBE, "autoprobe",
-		  NULL, 0, 0444, NULL,
-		  &do_autoprobe },
-		{ DEV_PARPORT_AUTOPROBE + 1, "autoprobe0",
-		 NULL, 0, 0444, NULL,
-		 &do_autoprobe },
-		{ DEV_PARPORT_AUTOPROBE + 2, "autoprobe1",
-		  NULL, 0, 0444, NULL,
-		  &do_autoprobe },
-		{ DEV_PARPORT_AUTOPROBE + 3, "autoprobe2",
-		  NULL, 0, 0444, NULL,
-		  &do_autoprobe },
-		{ DEV_PARPORT_AUTOPROBE + 4, "autoprobe3",
-		  NULL, 0, 0444, NULL,
-		  &do_autoprobe },
-#endif /* IEEE 1284 support */
-		{0}
-	},
-	{ {DEV_PARPORT_DEVICES_ACTIVE, "active", NULL, 0, 444, NULL,
-	  &do_active_device }, {0}},
-	{ PARPORT_PORT_DIR(NULL), {0}},
-	{ PARPORT_PARPORT_DIR(NULL), {0}},
-	{ PARPORT_DEV_DIR(NULL), {0}}
-};
-
-struct parport_device_sysctl_table
-{
-	struct ctl_table_header *sysctl_header;
-	ctl_table vars[2];
-	ctl_table device_dir[2];
-	ctl_table devices_root_dir[2];
-	ctl_table port_dir[2];
-	ctl_table parport_dir[2];
-	ctl_table dev_dir[2];
-};
-
-static const struct parport_device_sysctl_table
-parport_device_sysctl_template = {
-	NULL,
-	{
-		{ DEV_PARPORT_DEVICE_TIMESLICE, "timeslice",
-		  NULL, sizeof(int), 0644, NULL,
-		  &proc_dointvec },
-	},
-	{ {0, NULL, NULL, 0, 0555, NULL}, {0}},
-	{ PARPORT_DEVICES_ROOT_DIR, {0}},
-	{ PARPORT_PORT_DIR(NULL), {0}},
-	{ PARPORT_PARPORT_DIR(NULL), {0}},
-	{ PARPORT_DEV_DIR(NULL), {0}}
-};
-
-struct parport_default_sysctl_table
-{
-	struct ctl_table_header *sysctl_header;
-	ctl_table vars[3];
-        ctl_table default_dir[2];
-	ctl_table parport_dir[2];
-	ctl_table dev_dir[2];
-};
-
-extern unsigned long parport_default_timeslice;
-extern int parport_default_spintime;
-
-static struct parport_default_sysctl_table
-parport_default_sysctl_table = {
-	NULL,
-	{
-		{ DEV_PARPORT_DEFAULT_TIMESLICE, "timeslice",
-		  &parport_default_timeslice,
-		  sizeof(parport_default_timeslice), 0644, NULL,
-		  &proc_dointvec },
-		{ DEV_PARPORT_DEFAULT_SPINTIME, "spintime",
-		  &parport_default_spintime,
-		  sizeof(parport_default_timeslice), 0644, NULL,
-		  &proc_dointvec },
-		{0}
-	},
-	{ { DEV_PARPORT_DEFAULT, "default", NULL, 0, 0555,
-	    parport_default_sysctl_table.vars },{0}},
-	{
-	PARPORT_PARPORT_DIR(parport_default_sysctl_table.default_dir), 
-	{0}},
-	{ PARPORT_DEV_DIR(parport_default_sysctl_table.parport_dir), {0}}
-};
-
-
-int parport_proc_register(struct parport *port)
-{
-	struct parport_sysctl_table *t;
-	int i;
-
-	t = kmalloc(sizeof(*t), GFP_KERNEL);
-	if (t == NULL)
-		return -ENOMEM;
-	memcpy(t, &parport_sysctl_template, sizeof(*t));
-
-	t->device_dir[0].extra1 = port;
-
-	for (i = 0; i < 8; i++)
-		t->vars[i].extra1 = port;
-
-	t->vars[0].data = &port->spintime;
-	t->vars[2].child = t->device_dir;
-	
-	for (i = 0; i < 5; i++)
-		t->vars[3 + i].extra2 = &port->probe_info[i];
-
-	t->port_dir[0].procname = port->name;
-	t->port_dir[0].ctl_name = port->number + 1; /* nb 0 isn't legal here */
-
-	t->port_dir[0].child = t->vars;
-	t->parport_dir[0].child = t->port_dir;
-	t->dev_dir[0].child = t->parport_dir;
-
-	t->sysctl_header = register_sysctl_table(t->dev_dir, 0);
-	if (t->sysctl_header == NULL) {
-		kfree(t);
-		t = NULL;
-	}
-	port->sysctl_table = t;
-	return 0;
-}
-
-int parport_proc_unregister(struct parport *port)
-{
-	if (port->sysctl_table) {
-		struct parport_sysctl_table *t = port->sysctl_table;
-		port->sysctl_table = NULL;
-		unregister_sysctl_table(t->sysctl_header);
-		kfree(t);
-	}
-	return 0;
-}
-
-int parport_device_proc_register(struct pardevice *device)
-{
-	struct parport_device_sysctl_table *t;
-	struct parport * port = device->port;
-	
-	t = kmalloc(sizeof(*t), GFP_KERNEL);
-	if (t == NULL)
-		return -ENOMEM;
-	memcpy(t, &parport_device_sysctl_template, sizeof(*t));
-
-	t->dev_dir[0].child = t->parport_dir;
-	t->parport_dir[0].child = t->port_dir;
-	t->port_dir[0].procname = port->name;
-	t->port_dir[0].ctl_name = port->number + 1; /* nb 0 isn't legal here */
-	t->port_dir[0].child = t->devices_root_dir;
-	t->devices_root_dir[0].child = t->device_dir;
-
-#ifdef CONFIG_PARPORT_1284
-
-	t->device_dir[0].ctl_name =
-		parport_device_num(port->number, port->muxport,
-				   device->daisy)
-		+ 1;  /* nb 0 isn't legal here */ 
-
-#else /* No IEEE 1284 support */
-
-	/* parport_device_num isn't available. */
-	t->device_dir[0].ctl_name = 1;
-	
-#endif /* IEEE 1284 support or not */
-
-	t->device_dir[0].procname = device->name;
-	t->device_dir[0].extra1 = device;
-	t->device_dir[0].child = t->vars;
-	t->vars[0].data = &device->timeslice;
-
-	t->sysctl_header = register_sysctl_table(t->dev_dir, 0);
-	if (t->sysctl_header == NULL) {
-		kfree(t);
-		t = NULL;
-	}
-	device->sysctl_table = t;
-	return 0;
-}
-
-int parport_device_proc_unregister(struct pardevice *device)
-{
-	if (device->sysctl_table) {
-		struct parport_device_sysctl_table *t = device->sysctl_table;
-		device->sysctl_table = NULL;
-		unregister_sysctl_table(t->sysctl_header);
-		kfree(t);
-	}
-	return 0;
-}
-
-int parport_default_proc_register(void)
-{
-	parport_default_sysctl_table.sysctl_header =
-		register_sysctl_table(parport_default_sysctl_table.dev_dir, 0);
-	return 0;
-}
-
-int parport_default_proc_unregister(void)
-{
-	if (parport_default_sysctl_table.sysctl_header) {
-		unregister_sysctl_table(parport_default_sysctl_table.
-					sysctl_header);
-		parport_default_sysctl_table.sysctl_header = NULL;
-	}
-	return 0;
-}
-
-#else /* no sysctl */
-
-int parport_proc_register(struct parport *pp)
-{
-	return 0;
-}
-
-int parport_proc_unregister(struct parport *pp)
-{
-	return 0;
-}
-
-int parport_device_proc_register(struct pardevice *device)
-{
-	return 0;
-}
-
-int parport_device_proc_unregister(struct pardevice *device)
-{
-	return 0;
-}
-
-int parport_default_proc_register (void)
-{
-	return 0;
-}
-
-int parport_default_proc_unregister (void)
-{
-	return 0;
-}
-#endif
diff -u --recursive --new-file v2.3.11/linux/drivers/misc/parport_share.c linux/drivers/misc/parport_share.c
--- v2.3.11/linux/drivers/misc/parport_share.c	Wed Jul 21 15:46:48 1999
+++ linux/drivers/misc/parport_share.c	Wed Dec 31 16:00:00 1969
@@ -1,602 +0,0 @@
-/* $Id: parport_share.c,v 1.15 1998/01/11 12:06:17 philip Exp $
- * Parallel-port resource manager code.
- * 
- * Authors: David Campbell <campbell@tirian.che.curtin.edu.au>
- *          Tim Waugh <tim@cyberelk.demon.co.uk>
- *          Jose Renau <renau@acm.org>
- *          Philip Blundell <philb@gnu.org>
- *	    Andrea Arcangeli
- *
- * based on work by Grant Guenther <grant@torque.net>
- *          and Philip Blundell
- */
-
-#undef PARPORT_DEBUG_SHARING		/* undef for production */
-
-#include <linux/config.h>
-#include <linux/string.h>
-#include <linux/threads.h>
-#include <linux/parport.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/malloc.h>
-#include <linux/sched.h>
-
-#include <asm/spinlock.h>
-#include <asm/irq.h>
-
-#undef PARPORT_PARANOID
-
-#define PARPORT_DEFAULT_TIMESLICE	(HZ/5)
-
-unsigned long parport_default_timeslice = PARPORT_DEFAULT_TIMESLICE;
-int parport_default_spintime =  DEFAULT_SPIN_TIME;
-
-static struct parport *portlist = NULL, *portlist_tail = NULL;
-spinlock_t parportlist_lock = SPIN_LOCK_UNLOCKED;
-
-static struct parport_driver *driver_chain = NULL;
-spinlock_t driverlist_lock = SPIN_LOCK_UNLOCKED;
-
-static void call_driver_chain(int attach, struct parport *port)
-{
-	struct parport_driver *drv;
-
-	for (drv = driver_chain; drv; drv = drv->next) {
-		if (attach)
-			drv->attach (port);
-		else
-			drv->detach (port);
-	}
-}
-
-int parport_register_driver (struct parport_driver *drv)
-{
-	struct parport *port;
-
-	spin_lock (&driverlist_lock);
-	drv->next = driver_chain;
-	driver_chain = drv;
-	spin_unlock (&driverlist_lock);
-
-	for (port = portlist; port; port = port->next)
-		drv->attach (port);
-
-	return 0;
-}
-
-void parport_unregister_driver (struct parport_driver *arg)
-{
-	struct parport_driver *drv = driver_chain, *olddrv = NULL;
-
-	while (drv) {
-		if (drv == arg) {
-			spin_lock (&driverlist_lock);
-			if (olddrv)
-				olddrv->next = drv->next;
-			else
-				driver_chain = drv->next;
-			spin_unlock (&driverlist_lock);
-			return;
-		}
-		olddrv = drv;
-		drv = drv->next;
-	}
-}
-
-/* Return a list of all the ports we know about. */
-struct parport *parport_enumerate(void)
-{
-	return portlist;
-}
-
-struct parport *parport_register_port(unsigned long base, int irq, int dma,
-				      struct parport_operations *ops)
-{
-	struct parport *tmp;
-	int portnum;
-	int device;
-	char *name;
-
-	tmp = kmalloc(sizeof(struct parport), GFP_KERNEL);
-	if (!tmp) {
-		printk(KERN_WARNING "parport: memory squeeze\n");
-		return NULL;
-	}
-
-	/* Search for the lowest free parport number. */
-	for (portnum = 0; ; portnum++) {
-		struct parport *itr = portlist;
-		while (itr) {
-			if (itr->number == portnum)
-				/* No good, already used. */
-				break;
-			else
-				itr = itr->next;
-		}
-
-		if (itr == NULL)
-			/* Got to the end of the list. */
-			break;
-	}
-	
-	/* Init our structure */
- 	memset(tmp, 0, sizeof(struct parport));
-	tmp->base = base;
-	tmp->irq = irq;
-	tmp->dma = dma;
-	tmp->muxport = tmp->daisy = tmp->muxsel = -1;
-	tmp->modes = 0;
- 	tmp->next = NULL;
-	tmp->devices = tmp->cad = NULL;
-	tmp->flags = 0;
-	tmp->ops = ops;
-	tmp->portnum = tmp->number = portnum;
-	tmp->physport = tmp;
-	memset (tmp->probe_info, 0, 5 * sizeof (struct parport_device_info));
-	tmp->cad_lock = RW_LOCK_UNLOCKED;
-	spin_lock_init(&tmp->waitlist_lock);
-	spin_lock_init(&tmp->pardevice_lock);
-	tmp->ieee1284.mode = IEEE1284_MODE_COMPAT;
-	tmp->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
-	init_MUTEX_LOCKED (&tmp->ieee1284.irq); /* actually a semaphore at 0 */
-	tmp->spintime = parport_default_spintime;
-
-	name = kmalloc(15, GFP_KERNEL);
-	if (!name) {
-		printk(KERN_ERR "parport: memory squeeze\n");
-		kfree(tmp);
-		return NULL;
-	}
-	sprintf(name, "parport%d", portnum);
-	tmp->name = name;
-
-	/*
-	 * Chain the entry to our list.
-	 *
-	 * This function must not run from an irq handler so we don' t need
-	 * to clear irq on the local CPU. -arca
-	 */
-	spin_lock(&parportlist_lock);
-	if (portlist_tail)
-		portlist_tail->next = tmp;
-	portlist_tail = tmp;
-	if (!portlist)
-		portlist = tmp;
-	spin_unlock(&parportlist_lock);
-
-	for (device = 0; device < 5; device++)
-		/* assume the worst */
-		tmp->probe_info[device].class = PARPORT_CLASS_LEGACY;
-
-	tmp->waithead = tmp->waittail = NULL;
-
-	return tmp;
-}
-
-void parport_announce_port (struct parport *port)
-{
-#ifdef CONFIG_PARPORT_1284
-	/* Analyse the IEEE1284.3 topology of the port. */
-	parport_daisy_init (port);
-#endif
-
-	/* Let drivers know that a new port has arrived. */
-	call_driver_chain (1, port);
-}
-
-void parport_unregister_port(struct parport *port)
-{
-	struct parport *p;
-	int d;
-
-	/* Spread the word. */
-	call_driver_chain (0, port);
-
-#ifdef CONFIG_PARPORT_1284
-	/* Forget the IEEE1284.3 topology of the port. */
-	parport_daisy_fini (port);
-#endif
-
-	spin_lock(&parportlist_lock);
-	if (portlist == port) {
-		if ((portlist = port->next) == NULL)
-			portlist_tail = NULL;
-	} else {
-		for (p = portlist; (p != NULL) && (p->next != port); 
-		     p=p->next);
-		if (p) {
-			if ((p->next = port->next) == NULL)
-				portlist_tail = p;
-		}
-		else printk (KERN_WARNING
-			     "%s not found in port list!\n", port->name);
-	}
-	spin_unlock(&parportlist_lock);
-
-	for (d = 0; d < 5; d++) {
-		if (port->probe_info[d].class_name)
-			kfree (port->probe_info[d].class_name);
-		if (port->probe_info[d].mfr)
-			kfree (port->probe_info[d].mfr);
-		if (port->probe_info[d].model)
-			kfree (port->probe_info[d].model);
-		if (port->probe_info[d].cmdset)
-			kfree (port->probe_info[d].cmdset);
-		if (port->probe_info[d].description)
-			kfree (port->probe_info[d].description);
-	}
-
-	kfree(port->name);
-	kfree(port);
-}
-
-struct pardevice *parport_register_device(struct parport *port, const char *name,
-			  int (*pf)(void *), void (*kf)(void *),
-			  void (*irq_func)(int, void *, struct pt_regs *), 
-			  int flags, void *handle)
-{
-	struct pardevice *tmp;
-
-	if (port->physport->flags & PARPORT_FLAG_EXCL) {
-		/* An exclusive device is registered. */
-		printk (KERN_DEBUG "%s: no more devices allowed\n",
-			port->name);
-		return NULL;
-	}
-
-	if (flags & PARPORT_DEV_LURK) {
-		if (!pf || !kf) {
-			printk(KERN_INFO "%s: refused to register lurking device (%s) without callbacks\n", port->name, name);
-			return NULL;
-		}
-	}
-
-	tmp = kmalloc(sizeof(struct pardevice), GFP_KERNEL);
-	if (tmp == NULL) {
-		printk(KERN_WARNING "%s: memory squeeze, couldn't register %s.\n", port->name, name);
-		return NULL;
-	}
-
-	tmp->state = kmalloc(sizeof(struct parport_state), GFP_KERNEL);
-	if (tmp->state == NULL) {
-		printk(KERN_WARNING "%s: memory squeeze, couldn't register %s.\n", port->name, name);
-		kfree(tmp);
-		return NULL;
-	}
-
-	tmp->name = name;
-	tmp->port = port;
-	tmp->daisy = -1;
-	tmp->preempt = pf;
-	tmp->wakeup = kf;
-	tmp->private = handle;
-	tmp->flags = flags;
-	tmp->irq_func = irq_func;
-	tmp->waiting = 0;
-	tmp->timeout = 5 * HZ;
-
-	/* Chain this onto the list */
-	tmp->prev = NULL;
-	/*
-	 * This function must not run from an irq handler so we don' t need
-	 * to clear irq on the local CPU. -arca
-	 */
-	spin_lock(&port->physport->pardevice_lock);
-
-	if (flags & PARPORT_DEV_EXCL) {
-		if (port->physport->devices) {
-			spin_unlock (&port->physport->pardevice_lock);
-			kfree (tmp->state);
-			kfree (tmp);
-			printk (KERN_DEBUG
-				"%s: cannot grant exclusive access for "
-				"device %s\n", port->name, name);
-			return NULL;
-		}
-		port->flags |= PARPORT_FLAG_EXCL;
-	}
-
-	tmp->next = port->physport->devices;
-	if (port->physport->devices)
-		port->physport->devices->prev = tmp;
-	port->physport->devices = tmp;
-	spin_unlock(&port->physport->pardevice_lock);
-
-	inc_parport_count();
-	port->ops->inc_use_count();
-
-	init_waitqueue_head(&tmp->wait_q);
-	tmp->timeslice = parport_default_timeslice;
-	tmp->waitnext = tmp->waitprev = NULL;
-
-	/*
-	 * This has to be run as last thing since init_state may need other
-	 * pardevice fields. -arca
-	 */
-	port->ops->init_state(tmp, tmp->state);
-	parport_device_proc_register(tmp);
-	return tmp;
-}
-
-void parport_unregister_device(struct pardevice *dev)
-{
-	struct parport *port;
-
-#ifdef PARPORT_PARANOID
-	if (dev == NULL) {
-		printk(KERN_ERR "parport_unregister_device: passed NULL\n");
-		return;
-	}
-#endif
-
-	parport_device_proc_unregister(dev);
-
-	port = dev->port->physport;
-
-	if (port->cad == dev) {
-		printk(KERN_DEBUG "%s: %s forgot to release port\n",
-		       port->name, dev->name);
-		parport_release (dev);
-	}
-
-	spin_lock(&port->pardevice_lock);
-	if (dev->next)
-		dev->next->prev = dev->prev;
-	if (dev->prev)
-		dev->prev->next = dev->next;
-	else
-		port->devices = dev->next;
-
-	if (dev->flags & PARPORT_DEV_EXCL)
-		port->flags &= ~PARPORT_FLAG_EXCL;
-
-	spin_unlock(&port->pardevice_lock);
-
-	kfree(dev->state);
-	kfree(dev);
-
-	dec_parport_count();
-	port->ops->dec_use_count();
-}
-
-int parport_claim(struct pardevice *dev)
-{
-	struct pardevice *oldcad;
-	struct parport *port = dev->port->physport;
-	unsigned long flags;
-
-	if (port->cad == dev) {
-		printk(KERN_INFO "%s: %s already owner\n",
-		       dev->port->name,dev->name);
-		return 0;
-	}
-
-try_again:
-	/* Preempt any current device */
-	if ((oldcad = port->cad) != NULL) {
-		if (oldcad->preempt) {
-			if (oldcad->preempt(oldcad->private))
-				goto blocked;
-			port->ops->save_state(port, dev->state);
-		} else
-			goto blocked;
-
-		if (port->cad != oldcad) {
-			printk(KERN_WARNING 
-			       "%s: %s released port when preempted!\n",
-			       port->name, oldcad->name);
-			if (port->cad)
-				goto blocked;
-		}
-	}
-
-	/* Can't fail from now on, so mark ourselves as no longer waiting.  */
-	if (dev->waiting & 1) {
-		dev->waiting = 0;
-
-		/* Take ourselves out of the wait list again.  */
-		spin_lock_irqsave (&port->waitlist_lock, flags);
-		if (dev->waitprev)
-			dev->waitprev->waitnext = dev->waitnext;
-		else
-			port->waithead = dev->waitnext;
-		if (dev->waitnext)
-			dev->waitnext->waitprev = dev->waitprev;
-		else
-			port->waittail = dev->waitprev;
-		spin_unlock_irqrestore (&port->waitlist_lock, flags);
-		dev->waitprev = dev->waitnext = NULL;
-	}
-
-	/* Now we do the change of devices */
-	write_lock_irqsave(&port->cad_lock, flags);
-	port->cad = dev;
-	write_unlock_irqrestore(&port->cad_lock, flags);
-
-#ifdef CONFIG_PARPORT_1284
-	/* If it's a mux port, select it. */
-	if (dev->port->muxport >= 0) {
-		/* FIXME */
-		port->muxsel = dev->port->muxport;
-	}
-
-	/* If it's a daisy chain device, select it. */
-	if (dev->daisy >= 0) {
-		/* This could be lazier. */
-		if (!parport_daisy_select (port, dev->daisy,
-					   IEEE1284_MODE_COMPAT))
-			port->daisy = dev->daisy;
-	}
-#endif /* IEEE1284.3 support */
-
-	/* Restore control registers */
-	port->ops->restore_state(port, dev->state);
-	dev->time = jiffies;
-	return 0;
-
-blocked:
-	/* If this is the first time we tried to claim the port, register an
-	   interest.  This is only allowed for devices sleeping in
-	   parport_claim_or_block(), or those with a wakeup function.  */
-	if (dev->waiting & 2 || dev->wakeup) {
-		spin_lock_irqsave (&port->waitlist_lock, flags);
-		if (port->cad == NULL) {
-			/* The port got released in the meantime. */
-			spin_unlock_irqrestore (&port->waitlist_lock, flags);
-			goto try_again;
-		}
-		if (test_and_set_bit(0, &dev->waiting) == 0) {
-			/* First add ourselves to the end of the wait list. */
-			dev->waitnext = NULL;
-			dev->waitprev = port->waittail;
-			if (port->waittail) {
-				port->waittail->waitnext = dev;
-				port->waittail = dev;
-			} else
-				port->waithead = port->waittail = dev;
-		}
-		spin_unlock_irqrestore (&port->waitlist_lock, flags);
-	}
-	return -EAGAIN;
-}
-
-int parport_claim_or_block(struct pardevice *dev)
-{
-	int r;
-
-	/* Signal to parport_claim() that we can wait even without a
-	   wakeup function.  */
-	dev->waiting = 2;
-
-	/* Try to claim the port.  If this fails, we need to sleep.  */
-	r = parport_claim(dev);
-	if (r == -EAGAIN) {
-		unsigned long flags;
-#ifdef PARPORT_DEBUG_SHARING
-		printk(KERN_DEBUG "%s: parport_claim() returned -EAGAIN\n", dev->name);
-#endif
-		save_flags (flags);
-		cli();
-		/* If dev->waiting is clear now, an interrupt
-		   gave us the port and we would deadlock if we slept.  */
-		if (dev->waiting) {
-			sleep_on(&dev->wait_q);
-			r = 1;
-		} else {
-			r = 0;
-#ifdef PARPORT_DEBUG_SHARING
-			printk(KERN_DEBUG "%s: didn't sleep in parport_claim_or_block()\n",
-			       dev->name);
-#endif
-		}
-		restore_flags(flags);
-#ifdef PARPORT_DEBUG_SHARING
-		if (dev->port->physport->cad != dev)
-			printk(KERN_DEBUG "%s: exiting parport_claim_or_block "
-			       "but %s owns port!\n", dev->name,
-			       dev->port->physport->cad ?
-			       dev->port->physport->cad->name:"nobody");
-#endif
-	}
-	dev->waiting = 0;
-	return r;
-}
-
-void parport_release(struct pardevice *dev)
-{
-	struct parport *port = dev->port->physport;
-	struct pardevice *pd;
-	unsigned long flags;
-
-	/* Make sure that dev is the current device */
-	if (port->cad != dev) {
-		printk(KERN_WARNING "%s: %s tried to release parport "
-		       "when not owner\n", port->name, dev->name);
-		return;
-	}
-
-#ifdef CONFIG_PARPORT_1284
-	/* If this is on a mux port, deselect it. */
-	if (dev->port->muxport >= 0) {
-		/* FIXME */
-		port->muxsel = -1;
-	}
-
-	/* If this is a daisy device, deselect it. */
-	if (dev->daisy >= 0) {
-		parport_daisy_deselect_all (port);
-		port->daisy = -1;
-	}
-#endif
-
-	write_lock_irqsave(&port->cad_lock, flags);
-	port->cad = NULL;
-	write_unlock_irqrestore(&port->cad_lock, flags);
-
-	/* Save control registers */
-	port->ops->save_state(port, dev->state);
-
-	/* If anybody is waiting, find out who's been there longest and
-	   then wake them up. (Note: no locking required) */
-	for (pd = port->waithead; pd; pd = pd->waitnext) {
-		if (pd->waiting & 2) { /* sleeping in claim_or_block */
-			parport_claim(pd);
-			if (waitqueue_active(&pd->wait_q))
-				wake_up(&pd->wait_q);
-			return;
-		} else if (pd->wakeup) {
-			pd->wakeup(pd->private);
-			if (dev->port->cad)
-				return;
-		} else {
-			printk(KERN_ERR "%s: don't know how to wake %s\n", port->name, pd->name);
-		}
-	}
-
-	/* Nobody was waiting, so walk the list to see if anyone is
-	   interested in being woken up.  */
-	for (pd = port->devices; (port->cad == NULL) && pd; pd = pd->next) {
-		if (pd->wakeup && pd != dev)
-			pd->wakeup(pd->private);
-	}
-}
-
-static int parport_parse_params (int nports, const char *str[], int val[],
-				 int automatic, int none)
-{
-	unsigned int i;
-	for (i = 0; i < nports && str[i]; i++) {
-		if (!strncmp(str[i], "auto", 4))
-			val[i] = automatic;
-		else if (!strncmp(str[i], "none", 4))
-			val[i] = none;
-		else {
-			char *ep;
-			unsigned long r = simple_strtoul(str[i], &ep, 0);
-			if (ep != str[i])
-				val[i] = r;
-			else {
-				printk("parport: bad specifier `%s'\n", str[i]);
-				return -1;
-			}
-		}
-	}
-
-	return 0;
-}
-
-int parport_parse_irqs(int nports, const char *irqstr[], int irqval[])
-{
-	return parport_parse_params (nports, irqstr, irqval, PARPORT_IRQ_AUTO,
-				     PARPORT_IRQ_NONE);
-}
-
-int parport_parse_dmas(int nports, const char *dmastr[], int dmaval[])
-{
-	return parport_parse_params (nports, dmastr, dmaval, PARPORT_DMA_AUTO,
-				     PARPORT_DMA_NONE);
-}
diff -u --recursive --new-file v2.3.11/linux/drivers/net/hamradio/baycom_epp.c linux/drivers/net/hamradio/baycom_epp.c
--- v2.3.11/linux/drivers/net/hamradio/baycom_epp.c	Fri Mar 26 13:57:41 1999
+++ linux/drivers/net/hamradio/baycom_epp.c	Mon Jul 26 14:11:37 1999
@@ -3,7 +3,7 @@
 /*
  *	baycom_epp.c  -- baycom epp radio modem driver.
  *
- *	Copyright (C) 1998
+ *	Copyright (C) 1998-1999
  *          Thomas Sailer (sailer@ife.ee.ethz.ch)
  *
  *	This program is free software; you can redistribute it and/or modify
@@ -30,6 +30,7 @@
  *   0.2  21.04.98  Massive rework by Thomas Sailer
  *                  Integrated FPGA EPP modem configuration routines
  *   0.3  11.05.98  Took FPGA config out and moved it into a separate program
+ *   0.4  26.07.99  Adapted to new lowlevel parport driver interface
  *
  */
 
@@ -148,7 +149,7 @@
 
 static const char bc_drvname[] = "baycom_epp";
 static const char bc_drvinfo[] = KERN_INFO "baycom_epp: (C) 1998 Thomas Sailer, HB9JNX/AE4WA\n"
-KERN_INFO "baycom_epp: version 0.3 compiled " __TIME__ " " __DATE__ "\n";
+KERN_INFO "baycom_epp: version 0.4 compiled " __TIME__ " " __DATE__ "\n";
 
 /* --------------------------------------------------------------------- */
 
@@ -264,7 +265,8 @@
 
 	struct {
 		unsigned int intclk;
-		unsigned int divider;
+		unsigned int fclk;
+		unsigned int bps;
 		unsigned int extmodem;
 		unsigned int loopback;
 	} cfg;
@@ -433,7 +435,7 @@
  *    eppconfig_path should be setable  via /proc/sys.
  */
 
-char eppconfig_path[256] = "/sbin/eppfpga";
+char eppconfig_path[256] = "/usr/sbin/eppfpga";
 
 static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/usr/bin:/bin", NULL };
 
@@ -448,9 +450,10 @@
         int i;
 
 	/* set up arguments */
-	sprintf(modearg, "%sclk,%smodem,divider=%d%s,extstat",
+	sprintf(modearg, "%sclk,%smodem,fclk=%d,bps=%d,divider=%d%s,extstat",
 		bc->cfg.intclk ? "int" : "ext",
-		bc->cfg.extmodem ? "ext" : "int", bc->cfg.divider,
+		bc->cfg.extmodem ? "ext" : "int", bc->cfg.fclk, bc->cfg.bps,
+		(bc->cfg.fclk + 8 * bc->cfg.bps) / (16 * bc->cfg.bps),
 		bc->cfg.loopback ? ",loopback" : "");
 	sprintf(portarg, "%ld", bc->pdev->port->base);
 	printk(KERN_DEBUG "%s: %s -s -p %s -m %s\n", bc_drvname, eppconfig_path, portarg, modearg);
@@ -655,10 +658,11 @@
 
 /* ---------------------------------------------------------------------- */
 
-static void transmit(struct baycom_state *bc, int cnt, unsigned char stat)
+static int transmit(struct baycom_state *bc, int cnt, unsigned char stat)
 {
 	struct parport *pp = bc->pdev->port;
-	int i;
+	unsigned char tmp[128];
+	int i, j;
 
 	if (bc->hdlctx.state == tx_tail && !(stat & EPP_PTTBIT))
 		bc->hdlctx.state = tx_idle;
@@ -666,17 +670,17 @@
 		if (bc->hdlctx.bufcnt <= 0)
 			encode_hdlc(bc);
 		if (bc->hdlctx.bufcnt <= 0)
-			return;
+			return 0;
 		if (!bc->ch_params.fulldup) {
 			if (!(stat & EPP_DCDBIT)) {
 				bc->hdlctx.slotcnt = bc->ch_params.slottime;
-				return;
+				return 0;
 			}
 			if ((--bc->hdlctx.slotcnt) > 0)
-				return;
+				return 0;
 			bc->hdlctx.slotcnt = bc->ch_params.slottime;
 			if ((random_num() % 256) > bc->ch_params.ppersist)
-				return;
+				return 0;
 		}
 	}
 	if (bc->hdlctx.state == tx_idle && bc->hdlctx.bufcnt > 0) {
@@ -692,8 +696,13 @@
 			bc->hdlctx.flags -= i;
 			if (bc->hdlctx.flags <= 0)
 				bc->hdlctx.state = tx_data;
-			for (; i > 0; i--)
-				parport_epp_write_data(pp, 0x7e);
+			memset(tmp, 0x7e, sizeof(tmp));
+			while (i > 0) {
+				j = (i > sizeof(tmp)) ? sizeof(tmp) : i;
+				if (j != pp->ops->epp_write_data(pp, tmp, j, 0))
+					return -1;
+				i -= j;
+			}
 			break;
 
 		case tx_data:
@@ -708,8 +717,9 @@
 			i = min(cnt, bc->hdlctx.bufcnt);
 			bc->hdlctx.bufcnt -= i;
 			cnt -= i;
-			for (; i > 0; i--)
-				parport_epp_write_data(pp, *(bc->hdlctx.bufptr)++);
+			if (i != pp->ops->epp_write_data(pp, bc->hdlctx.bufptr, i, 0))
+					return -1;
+			bc->hdlctx.bufptr += i;
 			break;
 			
 		case tx_tail:
@@ -722,22 +732,33 @@
 			if (i) {
 				cnt -= i;
 				bc->hdlctx.flags -= i;
-				for (; i > 0; i--)
-					parport_epp_write_data(pp, 0x7e);
+				memset(tmp, 0x7e, sizeof(tmp));
+				while (i > 0) {
+					j = (i > sizeof(tmp)) ? sizeof(tmp) : i;
+					if (j != pp->ops->epp_write_data(pp, tmp, j, 0))
+						return -1;
+					i -= j;
+				}
 				break;
 			}
 
 		default:  /* fall through */
 			if (bc->hdlctx.calibrate <= 0)
-				return;
+				return 0;
 			i = min(cnt, bc->hdlctx.calibrate);
 			cnt -= i;
 			bc->hdlctx.calibrate -= i;
-			for (; i > 0; i--)
-				parport_epp_write_data(pp, 0);
+			memset(tmp, 0, sizeof(tmp));
+			while (i > 0) {
+				j = (i > sizeof(tmp)) ? sizeof(tmp) : i;
+				if (j != pp->ops->epp_write_data(pp, tmp, j, 0))
+					return -1;
+				i -= j;
+			}
 			break;
 		}
 	}
+	return 0;
 }
 
 /* ---------------------------------------------------------------------- */
@@ -800,57 +821,68 @@
         goto enditer##j;                                                               \
 })
         
-static void receive(struct device *dev, int cnt)
+static int receive(struct device *dev, int cnt)
 {
 	struct baycom_state *bc = (struct baycom_state *)dev->priv;
 	struct parport *pp = bc->pdev->port;
         unsigned int bitbuf, notbitstream, bitstream, numbits, state;
-        unsigned char ch;
+	unsigned char tmp[128];
+        unsigned char *cp;
+	int cnt2, ret = 0;
         
         numbits = bc->hdlcrx.numbits;
 	state = bc->hdlcrx.state;
 	bitstream = bc->hdlcrx.bitstream;
 	bitbuf = bc->hdlcrx.bitbuf;
-	for (; cnt > 0; cnt--) {
-		ch = parport_epp_read_data(pp);
-		bitstream >>= 8;
-                bitstream |= ch << 8;
-                bitbuf >>= 8;
-                bitbuf |= ch << 8;
-                numbits += 8;
-                notbitstream = ~bitstream;
-                DECODEITERA(0);
-                DECODEITERA(1);
-                DECODEITERA(2);
-                DECODEITERA(3);
-                DECODEITERA(4);
-                DECODEITERA(5);
-                DECODEITERA(6);
-                DECODEITERA(7);
-                goto enddec;
-                DECODEITERB(0);
-                DECODEITERB(1);
-                DECODEITERB(2);
-                DECODEITERB(3);
-                DECODEITERB(4);
-                DECODEITERB(5);
-                DECODEITERB(6);
-                DECODEITERB(7);
-          enddec:
-                while (state && numbits >= 8) {
-                        if (bc->hdlcrx.bufcnt >= TXBUFFER_SIZE) {
-                                state = 0;
-                        } else {
-				*(bc->hdlcrx.bufptr)++ = bitbuf >> (16-numbits);
-				bc->hdlcrx.bufcnt++;
-				numbits -= 8;
+	while (cnt > 0) {
+		cnt2 = (cnt > sizeof(tmp)) ? sizeof(tmp) : cnt;
+		cnt -= cnt2;
+		if (cnt2 != pp->ops->epp_read_data(pp, tmp, cnt2, 0)) {
+			ret = -1;
+			break;
+		}
+		cp = tmp;
+		for (; cnt2 > 0; cnt2--, cp++) {
+			bitstream >>= 8;
+			bitstream |= (*cp) << 8;
+			bitbuf >>= 8;
+			bitbuf |= (*cp) << 8;
+			numbits += 8;
+			notbitstream = ~bitstream;
+			DECODEITERA(0);
+			DECODEITERA(1);
+			DECODEITERA(2);
+			DECODEITERA(3);
+			DECODEITERA(4);
+			DECODEITERA(5);
+			DECODEITERA(6);
+			DECODEITERA(7);
+			goto enddec;
+			DECODEITERB(0);
+			DECODEITERB(1);
+			DECODEITERB(2);
+			DECODEITERB(3);
+			DECODEITERB(4);
+			DECODEITERB(5);
+			DECODEITERB(6);
+			DECODEITERB(7);
+		enddec:
+			while (state && numbits >= 8) {
+				if (bc->hdlcrx.bufcnt >= TXBUFFER_SIZE) {
+					state = 0;
+				} else {
+					*(bc->hdlcrx.bufptr)++ = bitbuf >> (16-numbits);
+					bc->hdlcrx.bufcnt++;
+					numbits -= 8;
+				}
 			}
 		}
-        }
+	}
         bc->hdlcrx.numbits = numbits;
 	bc->hdlcrx.state = state;
 	bc->hdlcrx.bitstream = bitstream;
 	bc->hdlcrx.bitbuf = bitbuf;
+	return ret;
 }
 
 /* --------------------------------------------------------------------- */
@@ -870,6 +902,7 @@
 	struct baycom_state *bc;
 	struct parport *pp;
 	unsigned char stat;
+	unsigned char tmp[2];
 	unsigned int time1 = 0, time2 = 0, time3 = 0;
 	int cnt, cnt2;
 	
@@ -880,26 +913,40 @@
 	baycom_int_freq(bc);
 	pp = bc->pdev->port;
 	/* update status */
-	bc->stat = stat = parport_epp_read_addr(pp);
+	if (pp->ops->epp_read_addr(pp, &stat, 1, 0) != 1)
+		goto epptimeout;
+	bc->stat = stat;
 	bc->debug_vals.last_pllcorr = stat;
 	GETTICK(time1);
 	if (bc->modem == EPP_FPGAEXTSTATUS) {
 		/* get input count */
-		parport_epp_write_addr(pp, EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE|1);
-		cnt = parport_epp_read_addr(pp);
-		cnt |= parport_epp_read_addr(pp) << 8;
+		tmp[0] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE|1;
+		if (pp->ops->epp_write_addr(pp, tmp, 1, 0) != 1)
+			goto epptimeout;
+		if (pp->ops->epp_read_addr(pp, tmp, 2, 0) != 2)
+			goto epptimeout;
+		cnt = tmp[0] | (tmp[1] << 8);
 		cnt &= 0x7fff;
 		/* get output count */
-		parport_epp_write_addr(pp, EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE|2);
-		cnt2 = parport_epp_read_addr(pp);
-		cnt2 |= parport_epp_read_addr(pp) << 8;
+		tmp[0] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE|2;
+		if (pp->ops->epp_write_addr(pp, tmp, 1, 0) != 1)
+			goto epptimeout;
+		if (pp->ops->epp_read_addr(pp, tmp, 2, 0) != 2)
+			goto epptimeout;
+		cnt2 = tmp[0] | (tmp[1] << 8);
 		cnt2 = 16384 - (cnt2 & 0x7fff);
 		/* return to normal */
-		parport_epp_write_addr(pp, EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE);
-		transmit(bc, cnt2, stat);
+		tmp[0] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE;
+		if (pp->ops->epp_write_addr(pp, tmp, 1, 0) != 1)
+			goto epptimeout;
+		if (transmit(bc, cnt2, stat))
+			goto epptimeout;
 		GETTICK(time2);
-		receive(dev, cnt);
-		bc->stat = stat = parport_epp_read_addr(pp);
+		if (receive(dev, cnt))
+			goto epptimeout;
+		if (pp->ops->epp_read_addr(pp, &stat, 1, 0) != 1)
+			goto epptimeout;
+		bc->stat = stat;
 	} else {
 		/* try to tx */
 		switch (stat & (EPP_NTAEF|EPP_NTHF)) {
@@ -919,7 +966,8 @@
 			cnt = 2048 - 1025;
 			break;
 		}
-		transmit(bc, cnt, stat);
+		if (transmit(bc, cnt, stat))
+			goto epptimeout;
 		GETTICK(time2);
 		/* do receiver */
 		while ((stat & (EPP_NRAEF|EPP_NRHF)) != EPP_NRHF) {
@@ -936,9 +984,9 @@
 				cnt = 256;
 				break;
 			}
-			receive(dev, cnt);
-			stat = parport_epp_read_addr(pp);
-			if (parport_epp_check_timeout(pp))
+			if (receive(dev, cnt))
+				goto epptimeout;
+			if (pp->ops->epp_read_addr(pp, &stat, 1, 0) != 1)
 				goto epptimeout;
 		}
 		cnt = 0;
@@ -947,9 +995,11 @@
 		else if (bc->bitrate < 100000)
 			cnt = 128;
 		while (cnt > 0 && stat & EPP_NREF) {
-			receive(dev, 1);
+			if (receive(dev, 1))
+				goto epptimeout;
 			cnt--;
-			stat = parport_epp_read_addr(pp);
+			if (pp->ops->epp_read_addr(pp, &stat, 1, 0) != 1)
+				goto epptimeout;
 		}
 	}
 	GETTICK(time3);
@@ -957,8 +1007,6 @@
 	bc->debug_vals.mod_cycles = time2 - time1;
 	bc->debug_vals.demod_cycles = time3 - time2;
 #endif /* BAYCOM_DEBUG */
-	if (parport_epp_check_timeout(pp)) 
-		goto epptimeout;
 	queue_task(&bc->run_bh, &tq_timer);
 	return;
  epptimeout:
@@ -1040,6 +1088,7 @@
 		0, 0, (void *)(void *)epp_bh, dev
 	};
 	unsigned int i, j;
+	unsigned char tmp[128];
 	unsigned char stat;
 	unsigned long tstart;
 	
@@ -1071,8 +1120,8 @@
                 parport_unregister_device(bc->pdev);
                 return -EBUSY;
         }
-	if (!(pp->modes & (PARPORT_MODE_PCECPEPP|PARPORT_MODE_PCEPP))) {
-                printk(KERN_ERR "%s: parport at 0x%lx does not support any EPP mode\n",
+	if (!(pp->modes & PARPORT_MODE_TRISTATE)) {
+                printk(KERN_ERR "%s: parport at 0x%lx does not support bidirectional data transfer\n",
 		       bc_drvname, pp->base);
 		parport_release(bc->pdev);
                 parport_unregister_device(bc->pdev);
@@ -1081,11 +1130,6 @@
         dev->irq = /*pp->irq*/ 0;
 	bc->run_bh = run_bh;
 	bc->bh_running = 1;
-	if (pp->modes & PARPORT_MODE_PCECPEPP) {
-		printk(KERN_INFO "%s: trying to enable EPP mode\n", bc_drvname);
-		parport_frob_econtrol(pp, 0xe0, 0x80);
-	}
-        /* bc->pdev->port->ops->change_mode(bc->pdev->port, PARPORT_MODE_PCEPP);  not yet implemented */
 	bc->modem = EPP_CONVENTIONAL;
 	if (eppconfig(bc))
 		printk(KERN_INFO "%s: no FPGA detected, assuming conventional EPP modem\n", bc_drvname);
@@ -1093,26 +1137,33 @@
 		bc->modem = /*EPP_FPGA*/ EPP_FPGAEXTSTATUS;
 	parport_write_control(pp, LPTCTRL_PROGRAM); /* prepare EPP mode; we aren't using interrupts */
 	/* reset the modem */
-	parport_epp_write_addr(pp, 0);
-	parport_epp_write_addr(pp, EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE);
+	tmp[0] = 0;
+	tmp[1] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE;
+	if (pp->ops->epp_write_addr(pp, tmp, 2, 0) != 2)
+		goto epptimeout;
 	/* autoprobe baud rate */
 	tstart = jiffies;
 	i = 0;
 	while ((signed)(jiffies-tstart-HZ/3) < 0) {
-		stat = parport_epp_read_addr(pp);
+		if (pp->ops->epp_read_addr(pp, &stat, 1, 0) != 1)
+			goto epptimeout;
 		if ((stat & (EPP_NRAEF|EPP_NRHF)) == EPP_NRHF) {
 			schedule();
 			continue;
 		}
-		for (j = 0; j < 256; j++)
-			parport_epp_read_data(pp);
+		if (pp->ops->epp_read_data(pp, tmp, 128, 0) != 128)
+			goto epptimeout;
+		if (pp->ops->epp_read_data(pp, tmp, 128, 0) != 128)
+			goto epptimeout;
 		i += 256;
 	}
 	for (j = 0; j < 256; j++) {
-		stat = parport_epp_read_addr(pp);
+		if (pp->ops->epp_read_addr(pp, &stat, 1, 0) != 1)
+			goto epptimeout;
 		if (!(stat & EPP_NREF))
 			break;
-		parport_epp_read_data(pp);
+		if (pp->ops->epp_read_data(pp, tmp, 1, 0) != 1)
+			goto epptimeout;
 		i++;
 	}
 	tstart = jiffies - tstart;
@@ -1125,7 +1176,9 @@
 	}
 	printk(KERN_INFO "%s: autoprobed bitrate: %d  int divider: %d  int rate: %d\n", 
 	       bc_drvname, bc->bitrate, j, bc->bitrate >> (j+2));
-	parport_epp_write_addr(pp, EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE/*|j*/);
+	tmp[0] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE/*|j*/;
+	if (pp->ops->epp_write_addr(pp, tmp, 1, 0) != 1)
+		goto epptimeout;
 	/*
 	 * initialise hdlc variables
 	 */
@@ -1143,12 +1196,12 @@
 	MOD_INC_USE_COUNT;
 	return 0;
 
-#if 0
-  errreturn:
+ epptimeout:
+	printk(KERN_ERR "%s: epp timeout during bitrate probe\n", bc_drvname);
+	parport_write_control(pp, 0); /* reset the adapter */
         parport_release(bc->pdev);
         parport_unregister_device(bc->pdev);
 	return -EIO;
-#endif
 }
 
 /* --------------------------------------------------------------------- */
@@ -1158,6 +1211,7 @@
 	struct baycom_state *bc;
 	struct parport *pp;
 	struct sk_buff *skb;
+	unsigned char tmp[1];
 
 	baycom_paranoia_check(dev, "epp_close", -EINVAL);
 	if (!dev->start)
@@ -1169,7 +1223,8 @@
 	dev->tbusy = 1;
 	run_task_queue(&tq_timer);  /* dequeue bottom half */
 	bc->stat = EPP_DCDBIT;
-	parport_epp_write_addr(pp, 0);
+	tmp[0] = 0;
+	pp->ops->epp_write_addr(pp, tmp, 1, 0);
 	parport_write_control(pp, 0); /* reset the adapter */
         parport_release(bc->pdev);
         parport_unregister_device(bc->pdev);
@@ -1200,12 +1255,19 @@
 		bc->cfg.loopback = 0;
 	if (strstr(modestr,"loopback"))
 		bc->cfg.loopback = 1;
-	if ((cp = strstr(modestr,"divider="))) {
-		bc->cfg.divider = simple_strtoul(cp+8, NULL, 0);
-		if (bc->cfg.divider < 1)
-			bc->cfg.divider = 1;
-		if (bc->cfg.divider > 1023)
-			bc->cfg.divider = 1023;
+	if ((cp = strstr(modestr,"fclk="))) {
+		bc->cfg.fclk = simple_strtoul(cp+5, NULL, 0);
+		if (bc->cfg.fclk < 1000000)
+			bc->cfg.fclk = 1000000;
+		if (bc->cfg.fclk > 25000000)
+			bc->cfg.fclk = 25000000;
+	}
+	if ((cp = strstr(modestr,"bps="))) {
+		bc->cfg.bps = simple_strtoul(cp+4, NULL, 0);
+		if (bc->cfg.bps < 1000)
+			bc->cfg.bps = 1000;
+		if (bc->cfg.bps > 1500000)
+			bc->cfg.bps = 1500000;
 	}
 	return 0;
 }
@@ -1316,9 +1378,9 @@
 		break;
 		
 	case HDLCDRVCTL_GETMODE:
-		sprintf(hi.data.modename, "%sclk,%smodem,divider=%d%s", 
+		sprintf(hi.data.modename, "%sclk,%smodem,fclk=%d,bps=%d%s", 
 			bc->cfg.intclk ? "int" : "ext",
-			bc->cfg.extmodem ? "ext" : "int", bc->cfg.divider,
+			bc->cfg.extmodem ? "ext" : "int", bc->cfg.fclk, bc->cfg.bps,
 			bc->cfg.loopback ? ",loopback" : "");
 		break;
 
@@ -1441,6 +1503,8 @@
 		memset(bc, 0, sizeof(struct baycom_state));
 		bc->magic = BAYCOM_MAGIC;
 		sprintf(bc->ifname, "bce%d", i);
+		bc->cfg.fclk = 19666600;
+		bc->cfg.bps = 9600;
 		/*
 		 * initialize part of the device struct
 		 */
diff -u --recursive --new-file v2.3.11/linux/drivers/parport/BUGS-parport linux/drivers/parport/BUGS-parport
--- v2.3.11/linux/drivers/parport/BUGS-parport	Wed Dec 31 16:00:00 1969
+++ linux/drivers/parport/BUGS-parport	Thu Jun  3 16:21:47 1999
@@ -0,0 +1,5 @@
+Currently known (or at least suspected) bugs in parport:
+
+o lp doesn't allow you to read status while printing is in progress.
+
+See <URL:http://www.cyberelk.demon.co.uk/parport.html>.
diff -u --recursive --new-file v2.3.11/linux/drivers/parport/Config.in linux/drivers/parport/Config.in
--- v2.3.11/linux/drivers/parport/Config.in	Wed Dec 31 16:00:00 1969
+++ linux/drivers/parport/Config.in	Thu Jul  1 14:22:57 1999
@@ -0,0 +1,37 @@
+#
+# For a description of the syntax of this configuration file,
+# see the Configure script.
+#
+# Parport configuration.
+#
+
+tristate 'Parallel port support' CONFIG_PARPORT
+if [ "$CONFIG_PARPORT" != "n" ]; then
+  dep_tristate '   PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT
+  if [ "$CONFIG_PARPORT_PC" != "n" ]; then
+    bool '   Use FIFO/DMA if available' CONFIG_PARPORT_PC_FIFO
+  fi
+  if [ "$CONFIG_ARM" = "y" ]; then
+    dep_tristate '   Archimedes hardware' CONFIG_PARPORT_ARC $CONFIG_PARPORT
+  fi
+  if [ "$CONFIG_AMIGA" = "y" ]; then
+    dep_tristate '   Amiga builtin port' CONFIG_PARPORT_AMIGA $CONFIG_PARPORT
+    if [ "$CONFIG_ZORRO" != "n" ]; then
+      dep_tristate '   Multiface III parallel port' CONFIG_PARPORT_MFC3 $CONFIG_PARPORT
+    fi
+  else
+    define_bool CONFIG_PARPORT_AMIGA n
+    define_bool CONFIG_PARPORT_MFC3 n
+  fi
+  if [ "$CONFIG_ATARI" = "y" ]; then
+    dep_tristate '   Atari hardware' CONFIG_PARPORT_ATARI $CONFIG_PARPORT
+  else
+    define_bool CONFIG_PARPORT_ATARI n
+  fi
+
+  # If exactly one hardware type is selected then parport will optimise away
+  # support for loading any others.  Defeat this if the user is keen.
+  bool '   Support foreign hardware' CONFIG_PARPORT_OTHER
+
+  bool '   IEEE 1284 transfer modes' CONFIG_PARPORT_1284
+fi
diff -u --recursive --new-file v2.3.11/linux/drivers/parport/Makefile linux/drivers/parport/Makefile
--- v2.3.11/linux/drivers/parport/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/drivers/parport/Makefile	Tue Jul 27 13:55:52 1999
@@ -0,0 +1,94 @@
+#
+# Makefile for the kernel miscellaneous drivers.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now inherited from the
+# parent makes..
+#
+# Note 3! Parport is the Borg.  We have assimilated some other
+# drivers in the `char', `net' and `scsi' directories, but left them
+# there to allay suspicion.
+
+SUB_DIRS     := 
+MOD_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS)
+
+L_TARGET := parport.a
+MX_OBJS  :=
+LX_OBJS  := 
+MI_OBJS  :=
+MIX_OBJS :=
+
+ifeq ($(CONFIG_PARPORT),y)
+  L_OBJS += share.o ieee1284.o ieee1284_ops.o procfs.o
+
+  ifeq ($(CONFIG_PARPORT_1284),y)
+    L_OBJS += daisy.o probe.o
+  endif
+
+  ifeq ($(CONFIG_PARPORT_PC),y)
+    LX_OBJS += parport_pc.o
+  else
+    ifeq ($(CONFIG_PARPORT_PC),m)
+      M_OBJS += parport_pc.o
+    endif
+  endif
+  ifeq ($(CONFIG_PARPORT_AMIGA),y)
+    LX_OBJS += parport_amiga.o
+  else
+    ifeq ($(CONFIG_PARPORT_AMIGA),m)
+      M_OBJS += parport_amiga.o
+    endif
+  endif
+  ifeq ($(CONFIG_PARPORT_MFC3),y)
+    LX_OBJS += parport_mfc3.o
+  else
+    ifeq ($(CONFIG_PARPORT_MFC3),m)
+      M_OBJS += parport_mfc3.o
+    endif
+  endif
+  ifeq ($(CONFIG_PARPORT_ATARI),y)
+    LX_OBJS += parport_atari.o
+  else
+    ifeq ($(CONFIG_PARPORT_ATARI),m)
+      M_OBJS += parport_atari.o
+    endif
+  endif
+  LX_OBJS += init.o
+else
+  ifeq ($(CONFIG_PARPORT),m)
+    MI_OBJS += share.o ieee1284.o ieee1284_ops.o
+    ifeq ($(CONFIG_PARPORT_1284),y)
+      MI_OBJS += daisy.o probe.o
+    endif
+    ifneq ($(CONFIG_PROC_FS),n) 
+      MI_OBJS += procfs.o
+    endif
+    MIX_OBJS += init.o
+    M_OBJS += parport.o
+  endif
+  ifeq ($(CONFIG_PARPORT_PC),m)
+    M_OBJS += parport_pc.o
+  endif
+  ifeq ($(CONFIG_PARPORT_AX),m)
+    M_OBJS += parport_ax.o
+  endif
+  ifeq ($(CONFIG_PARPORT_AMIGA),m)
+    M_OBJS += parport_amiga.o
+  endif
+  ifeq ($(CONFIG_PARPORT_MFC3),m)
+    M_OBJS += parport_mfc3.o
+  endif
+  ifeq ($(CONFIG_PARPORT_ATARI),m)
+    M_OBJS += parport_atari.o
+  endif
+endif
+
+include $(TOPDIR)/Rules.make
+
+# Special rule to build the composite parport.o module
+parport.o: $(MI_OBJS) $(MIX_OBJS)
+	$(LD) $(LD_RFLAG) -r -o $@ $(MI_OBJS) $(MIX_OBJS)
diff -u --recursive --new-file v2.3.11/linux/drivers/parport/TODO-parport linux/drivers/parport/TODO-parport
--- v2.3.11/linux/drivers/parport/TODO-parport	Wed Dec 31 16:00:00 1969
+++ linux/drivers/parport/TODO-parport	Thu Jun  3 16:21:47 1999
@@ -0,0 +1,20 @@
+Things to be done.
+
+0. Fix the bugs (see BUGS-parport).
+
+1. Proper documentation.
+
+2. A better lp.c:
+
+   a) ECP support would be nice.  This can only work if both the port and
+      the printer support it.
+
+   b) Handle status readback automatically.  IEEE1284 printers can post status
+      bits when they have something to say.  We should read out and deal 
+      with (maybe just log) whatever the printer wants to tell the world.
+
+3. Support more hardware (eg m68k, Sun bpp).
+
+4. A better PLIP (make use of bidirectional/ECP/EPP ports).
+
+See <URL:http://www.cyberelk.demon.co.uk/parport.html>.
diff -u --recursive --new-file v2.3.11/linux/drivers/parport/daisy.c linux/drivers/parport/daisy.c
--- v2.3.11/linux/drivers/parport/daisy.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/parport/daisy.c	Sat Jul  3 10:45:04 1999
@@ -0,0 +1,473 @@
+/*
+ * IEEE 1284.3 Parallel port daisy chain and multiplexor code
+ * 
+ * Copyright (C) 1999  Tim Waugh <tim@cyberelk.demon.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * ??-12-1998: Initial implementation.
+ * 31-01-1999: Make port-cloning transparent.
+ * 13-02-1999: Move DeviceID technique from parport_probe.
+ * 13-03-1999: Get DeviceID from non-IEEE 1284.3 devices too.
+ *
+ */
+
+#include <linux/parport.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+
+#define DEBUG /* undef me for production */
+
+#ifdef DEBUG
+#define DPRINTK(stuff...) printk (stuff)
+#else
+#define DPRINTK(stuff...)
+#endif
+
+static struct daisydev {
+	struct daisydev *next;
+	struct parport *port;
+	int daisy;
+	int devnum;
+} *topology = NULL;
+
+static int numdevs = 0;
+
+/* Forward-declaration of lower-level functions. */
+static int mux_present (struct parport *port);
+static int num_mux_ports (struct parport *port);
+static int select_port (struct parport *port);
+static int assign_addrs (struct parport *port);
+
+/* Add a device to the discovered topology. */
+static void add_dev (int devnum, struct parport *port, int daisy)
+{
+	struct daisydev *newdev;
+	newdev = kmalloc (GFP_KERNEL, sizeof (struct daisydev));
+	if (newdev) {
+		newdev->port = port;
+		newdev->daisy = daisy;
+		newdev->devnum = devnum;
+		newdev->next = topology;
+		if (!topology || topology->devnum >= devnum)
+			topology = newdev;
+		else {
+			struct daisydev *prev = topology;
+			while (prev->next && prev->next->devnum < devnum)
+				prev = prev->next;
+			newdev->next = prev->next;
+			prev->next = newdev;
+		}
+	}
+}
+
+/* Clone a parport (actually, make an alias). */
+static struct parport *clone_parport (struct parport *real, int muxport)
+{
+	struct parport *extra = parport_register_port (real->base,
+						       real->irq,
+						       real->dma,
+						       real->ops);
+	if (extra) {
+		extra->portnum = real->portnum;
+		extra->physport = real;
+		extra->muxport = muxport;
+	}
+
+	return extra;
+}
+
+/* Discover the IEEE1284.3 topology on a port -- muxes and daisy chains. */
+int parport_daisy_init (struct parport *port)
+{
+	char *deviceid;
+	static const char *th[] = { /*0*/"th", "st", "nd", "rd", "th" };
+	int num_ports;
+	int i;
+
+	/* Because this is called before any other devices exist,
+	 * we don't have to claim exclusive access.  */
+
+	/* If mux present on normal port, need to create new
+	 * parports for each extra port. */
+	if (port->muxport < 0 && mux_present (port) &&
+	    /* don't be fooled: a mux must have 2 or 4 ports. */
+	    ((num_ports = num_mux_ports (port)) == 2 || num_ports == 4)) {
+		/* Leave original as port zero. */
+		port->muxport = 0;
+		printk (KERN_INFO
+			"%s: 1st (default) port of %d-way multiplexor\n",
+			port->name, num_ports);
+		for (i = 1; i < num_ports; i++) {
+			/* Clone the port. */
+			struct parport *extra = clone_parport (port, i);
+			if (!extra) {
+				if (signal_pending (current))
+					break;
+
+				schedule ();
+				continue;
+			}
+
+			printk (KERN_INFO
+				"%s: %d%s port of %d-way multiplexor on %s\n",
+				extra->name, i + 1, th[i + 1], num_ports,
+				port->name);
+
+			/* Analyse that port too.  We won't recurse
+			   forever because of the 'port->muxport < 0'
+			   test above. */
+			parport_announce_port (extra);
+		}
+	}
+
+	if (port->muxport >= 0)
+		select_port (port);
+
+	parport_daisy_deselect_all (port);
+	assign_addrs (port);
+
+	/* Count the potential legacy device at the end. */
+	add_dev (numdevs++, port, -1);
+
+	/* Find out the legacy device's IEEE 1284 device ID. */
+	deviceid = kmalloc (1000, GFP_KERNEL);
+	if (deviceid) {
+		parport_device_id (numdevs - 1, deviceid, 1000);
+		kfree (deviceid);
+	}
+
+	return 0;
+}
+
+/* Forget about devices on a physical port. */
+void parport_daisy_fini (struct parport *port)
+{
+	struct daisydev *dev, *prev = topology;
+	while (prev && prev->port == port)
+		prev = topology = topology->next;
+
+	while (prev) {
+		dev = prev->next;
+		if (dev && dev->port == port)
+			prev->next = dev->next;
+
+		prev = prev->next;
+	}
+
+	/* Gaps in the numbering could be handled better.  How should
+           someone enumerate through all IEEE1284.3 devices in the
+           topology?. */
+	if (!topology) numdevs = 0;
+	return; }
+
+/* Find a device by canonical device number. */
+struct pardevice *parport_open (int devnum, const char *name,
+				int (*pf) (void *), void (*kf) (void *),
+				void (*irqf) (int, void *, struct pt_regs *),
+				int flags, void *handle)
+{
+	struct parport *port = parport_enumerate ();
+	struct pardevice *dev;
+	int portnum;
+	int muxnum;
+	int daisynum;
+
+	if (parport_device_coords (devnum,  &portnum, &muxnum, &daisynum))
+		return NULL;
+
+	while (port && ((port->portnum != portnum) ||
+			(port->muxport != muxnum)))
+		port = port->next;
+
+	if (!port)
+		/* No corresponding parport. */
+		return NULL;
+
+	dev = parport_register_device (port, name, pf, kf,
+				       irqf, flags, handle);
+	if (dev)
+		dev->daisy = daisynum;
+
+	/* Check that there really is a device to select. */
+	if (daisynum >= 0) {
+		int selected;
+		parport_claim_or_block (dev);
+		selected = port->daisy;
+		parport_release (dev);
+
+		if (selected != port->daisy) {
+			/* No corresponding device. */
+			parport_unregister_device (dev);
+			return NULL;
+		}
+	}
+
+	return dev;
+}
+
+/* The converse of parport_open. */
+void parport_close (struct pardevice *dev)
+{
+	parport_unregister_device (dev);
+}
+
+/* Convert device coordinates into a canonical device number. */
+int parport_device_num (int parport, int mux, int daisy)
+{
+	struct daisydev *dev = topology;
+
+	while (dev && dev->port->portnum != parport &&
+	       dev->port->muxport != mux && dev->daisy != daisy)
+		dev = dev->next;
+
+	if (!dev)
+		return -ENXIO;
+
+	return dev->devnum;
+}
+
+/* Convert a canonical device number into device coordinates. */
+int parport_device_coords (int devnum, int *parport, int *mux, int *daisy)
+{
+	struct daisydev *dev = topology;
+
+	while (dev && dev->devnum != devnum)
+		dev = dev->next;
+
+	if (!dev)
+		return -ENXIO;
+
+	if (parport) *parport = dev->port->portnum;
+	if (mux) *mux = dev->port->muxport;
+	if (daisy) *daisy = dev->daisy;
+	return 0;
+}
+
+/* Send a daisy-chain-style CPP command packet. */
+static int cpp_daisy (struct parport *port, int cmd)
+{
+	unsigned char s;
+
+	parport_write_data (port, 0xaa); udelay (2);
+	parport_write_data (port, 0x55); udelay (2);
+	parport_write_data (port, 0x00); udelay (2);
+	parport_write_data (port, 0xff); udelay (2);
+	s = parport_read_status (port) & (PARPORT_STATUS_BUSY
+					  | PARPORT_STATUS_PAPEROUT
+					  | PARPORT_STATUS_SELECT
+					  | PARPORT_STATUS_ERROR);
+	if (s != (PARPORT_STATUS_BUSY
+		  | PARPORT_STATUS_PAPEROUT
+		  | PARPORT_STATUS_SELECT
+		  | PARPORT_STATUS_ERROR)) {
+		DPRINTK (KERN_DEBUG "%s: cpp_daisy: aa5500ff(%02x)\n",
+			 port->name, s);
+		return -ENXIO;
+	}
+
+	parport_write_data (port, 0x87); udelay (2);
+	s = parport_read_status (port) & (PARPORT_STATUS_BUSY
+					  | PARPORT_STATUS_PAPEROUT
+					  | PARPORT_STATUS_SELECT
+					  | PARPORT_STATUS_ERROR);
+	if (s != (PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR)) {
+		DPRINTK (KERN_DEBUG "%s: cpp_daisy: aa5500ff87(%02x)\n",
+			 port->name, s);
+		return -ENXIO;
+	}
+
+	parport_write_data (port, 0x78); udelay (2);
+	parport_write_data (port, cmd); udelay (2);
+	parport_frob_control (port,
+			      PARPORT_CONTROL_STROBE,
+			      PARPORT_CONTROL_STROBE);
+	udelay (1);
+	parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
+	udelay (1);
+	s = parport_read_status (port);
+	parport_write_data (port, 0xff); udelay (2);
+
+	return s;
+}
+
+/* Send a mux-style CPP command packet. */
+static int cpp_mux (struct parport *port, int cmd)
+{
+	unsigned char s;
+	int rc;
+
+	parport_write_data (port, 0xaa); udelay (2);
+	parport_write_data (port, 0x55); udelay (2);
+	parport_write_data (port, 0xf0); udelay (2);
+	parport_write_data (port, 0x0f); udelay (2);
+	parport_write_data (port, 0x52); udelay (2);
+	parport_write_data (port, 0xad); udelay (2);
+	parport_write_data (port, cmd); udelay (2);
+
+	s = parport_read_status (port);
+	if (!(s & PARPORT_STATUS_ACK)) {
+		DPRINTK (KERN_DEBUG "%s: cpp_mux: aa55f00f52ad%02x(%02x)\n",
+			 port->name, cmd, s);
+		return -EIO;
+	}
+
+	rc = (((s & PARPORT_STATUS_SELECT   ? 1 : 0) << 0) |
+	      ((s & PARPORT_STATUS_PAPEROUT ? 1 : 0) << 1) |
+	      ((s & PARPORT_STATUS_BUSY     ? 0 : 1) << 2) |
+	      ((s & PARPORT_STATUS_ERROR    ? 0 : 1) << 3));
+
+	return rc;
+}
+
+void parport_daisy_deselect_all (struct parport *port)
+{
+	cpp_daisy (port, 0x30);
+}
+
+int parport_daisy_select (struct parport *port, int daisy, int mode)
+{
+	/* mode is currently ignored. FIXME? */
+	return cpp_daisy (port, 0xe0 + daisy) & PARPORT_STATUS_ERROR;
+}
+
+static int mux_present (struct parport *port)
+{
+	return cpp_mux (port, 0x51) == 3;
+}
+
+static int num_mux_ports (struct parport *port)
+{
+	return cpp_mux (port, 0x58);
+}
+
+static int select_port (struct parport *port)
+{
+	int muxport = port->muxport;
+	return cpp_mux (port, 0x60 + muxport) == muxport;
+}
+
+static int assign_addrs (struct parport *port)
+{
+	unsigned char s, last_dev;
+	unsigned char daisy;
+	int thisdev = numdevs;
+	char *deviceid;
+
+	parport_write_data (port, 0xaa); udelay (2);
+	parport_write_data (port, 0x55); udelay (2);
+	parport_write_data (port, 0x00); udelay (2);
+	parport_write_data (port, 0xff); udelay (2);
+	s = parport_read_status (port) & (PARPORT_STATUS_BUSY
+					  | PARPORT_STATUS_PAPEROUT
+					  | PARPORT_STATUS_SELECT
+					  | PARPORT_STATUS_ERROR);
+	if (s != (PARPORT_STATUS_BUSY
+		  | PARPORT_STATUS_PAPEROUT
+		  | PARPORT_STATUS_SELECT
+		  | PARPORT_STATUS_ERROR)) {
+		DPRINTK (KERN_DEBUG "%s: assign_addrs: aa5500ff(%02x)\n",
+			 port->name, s);
+		return -ENXIO;
+	}
+
+	parport_write_data (port, 0x87); udelay (2);
+	s = parport_read_status (port) & (PARPORT_STATUS_BUSY
+					  | PARPORT_STATUS_PAPEROUT
+					  | PARPORT_STATUS_SELECT
+					  | PARPORT_STATUS_ERROR);
+	if (s != (PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR)) {
+		DPRINTK (KERN_DEBUG "%s: assign_addrs: aa5500ff87(%02x)\n",
+			 port->name, s);
+		return -ENXIO;
+	}
+
+	parport_write_data (port, 0x78); udelay (2);
+	last_dev = 0; /* We've just been speaking to a device, so we
+			 know there must be at least _one_ out there. */
+
+	for (daisy = 0; daisy < 4; daisy++) {
+		parport_write_data (port, daisy);
+		udelay (2);
+		parport_frob_control (port,
+				      PARPORT_CONTROL_STROBE,
+				      PARPORT_CONTROL_STROBE);
+		udelay (1);
+		parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
+		udelay (1);
+
+		if (last_dev)
+			/* No more devices. */
+			break;
+
+		last_dev = !(parport_read_status (port)
+			     & PARPORT_STATUS_BUSY);
+
+		add_dev (numdevs++, port, daisy);
+	}
+
+	parport_write_data (port, 0xff); udelay (2);
+	DPRINTK (KERN_DEBUG "%s: Found %d daisy-chained devices\n", port->name,
+		numdevs - thisdev);
+
+	/* Ask the new devices to introduce themselves. */
+	deviceid = kmalloc (1000, GFP_KERNEL);
+	if (!deviceid) return 0;
+
+	for (daisy = 0; thisdev < numdevs; thisdev++, daisy++)
+		parport_device_id (thisdev, deviceid, 1000);
+
+	kfree (deviceid);
+	return 0;
+}
+
+/* Find a device with a particular manufacturer and model string,
+   starting from a given device number.  Like the PCI equivalent,
+   'from' itself is skipped. */
+int parport_find_device (const char *mfg, const char *mdl, int from)
+{
+	struct daisydev *d = topology; /* sorted by devnum */
+
+	/* Find where to start. */
+	while (d && d->devnum <= from)
+		d = d->next;
+
+	/* Search. */
+	while (d) {
+		struct parport_device_info *info;
+		info = &d->port->probe_info[1 + d->daisy];
+		if ((!mfg || !strcmp (mfg, info->mfr)) &&
+		    (!mdl || !strcmp (mdl, info->model)))
+			break;
+
+		d = d->next;
+	}
+
+	if (d)
+		return d->devnum;
+
+	return -1;
+}
+
+/* Find a device in a particular class.  Like the PCI equivalent,
+   'from' itself is skipped. */
+int parport_find_class (parport_device_class cls, int from)
+{
+	struct daisydev *d = topology; /* sorted by devnum */
+
+	/* Find where to start. */
+	while (d && d->devnum <= from)
+		d = d->next;
+
+	/* Search. */
+	while (d && d->port->probe_info[1 + d->daisy].class != cls)
+		d = d->next;
+
+	if (d)
+		return d->devnum;
+
+	return -1;
+}
diff -u --recursive --new-file v2.3.11/linux/drivers/parport/ieee1284.c linux/drivers/parport/ieee1284.c
--- v2.3.11/linux/drivers/parport/ieee1284.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/parport/ieee1284.c	Wed Jul 21 15:38:39 1999
@@ -0,0 +1,545 @@
+/* $Id: parport_ieee1284.c,v 1.4 1997/10/19 21:37:21 philip Exp $
+ * IEEE-1284 implementation for parport.
+ *
+ * Authors: Phil Blundell <Philip.Blundell@pobox.com>
+ *          Carsten Gross <carsten@sol.wohnheim.uni-ulm.de>
+ *	    Jose Renau <renau@acm.org>
+ *          Tim Waugh <tim@cyberelk.demon.co.uk> (largely rewritten)
+ *
+ * This file is responsible for IEEE 1284 negotiation, and for handing
+ * read/write requests to low-level drivers.
+ */
+
+#include <linux/config.h>
+#include <linux/threads.h>
+#include <linux/parport.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+
+#undef DEBUG /* undef me for production */
+
+#ifdef CONFIG_LP_CONSOLE
+#undef DEBUG /* Don't want a garbled console */
+#endif
+
+#ifdef DEBUG
+#define DPRINTK(stuff...) printk (stuff)
+#else
+#define DPRINTK(stuff...)
+#endif
+
+/* Make parport_wait_peripheral wake up.
+ * It will be useful to call this from an interrupt handler. */
+void parport_ieee1284_wakeup (struct parport *port)
+{
+	up (&port->physport->ieee1284.irq);
+}
+
+static struct parport *port_from_cookie[PARPORT_MAX];
+static void timeout_waiting_on_port (unsigned long cookie)
+{
+	parport_ieee1284_wakeup (port_from_cookie[cookie % PARPORT_MAX]);
+}
+
+/* Wait for a parport_ieee1284_wakeup.
+ * 0:      success
+ * <0:     error (exit as soon as possible)
+ * >0:     timed out
+ */
+int parport_wait_event (struct parport *port, signed long timeout)
+{
+	int ret;
+	struct timer_list timer;
+
+	if (!port->physport->cad->timeout)
+		/* Zero timeout is special, and we can't down() the
+		   semaphore. */
+		return 1;
+
+	init_timer (&timer);
+	timer.expires = jiffies + timeout;
+	timer.function = timeout_waiting_on_port;
+	port_from_cookie[port->number % PARPORT_MAX] = port;
+	timer.data = port->number;
+
+	add_timer (&timer);
+	ret = down_interruptible (&port->physport->ieee1284.irq);
+	if (!del_timer (&timer) && !ret)
+		/* Timed out. */
+		ret = 1;
+
+	return ret;
+}
+
+/* Wait for Status line(s) to change in 35 ms - see IEEE1284-1994 page 24 to
+ * 25 for this. After this time we can create a timeout because the
+ * peripheral doesn't conform to IEEE1284.  We want to save CPU time: we are
+ * waiting a maximum time of 500 us busy (this is for speed).  If there is
+ * not the right answer in this time, we call schedule and other processes
+ * are able to eat the time up to 40ms.
+ */ 
+
+int parport_wait_peripheral(struct parport *port,
+			    unsigned char mask, 
+			    unsigned char result)
+{
+	int counter;
+	long deadline;
+	unsigned char status;
+
+	counter = port->physport->spintime; /* usecs of fast polling */
+	if (!port->physport->cad->timeout)
+		/* A zero timeout is "special": busy wait for the
+		   entire 35ms. */
+		counter = 35000;
+
+	/* Fast polling.
+	 *
+	 * This should be adjustable.
+	 * How about making a note (in the device structure) of how long
+	 * it takes, so we know for next time?
+	 */
+	for (counter /= 5; counter > 0; counter--) {
+		status = parport_read_status (port);
+		if ((status & mask) == result)
+			return 0;
+		if (signal_pending (current))
+			return -EINTR;
+		if (current->need_resched)
+			break;
+		udelay(5);
+	}
+
+	if (!port->physport->cad->timeout)
+		/* We may be in an interrupt handler, so we can't poll
+		 * slowly anyway. */
+		return 1;
+
+	/* 40ms of slow polling. */
+	deadline = jiffies + (HZ + 24) / 25;
+	while (time_before (jiffies, deadline)) {
+		int ret;
+
+		if (signal_pending (current))
+			return -EINTR;
+
+		/* Wait for 10ms (or until an interrupt occurs if
+		 * the handler is set) */
+		if ((ret = parport_wait_event (port, (HZ + 99) / 100)) < 0)
+			return ret;
+
+		status = parport_read_status (port);
+		if ((status & mask) == result)
+			return 0;
+
+		if (!ret) {
+			/* parport_wait_event didn't time out, but the
+			 * peripheral wasn't actually ready either.
+			 * Wait for another 10ms. */
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout ((HZ+ 99) / 100);
+		}
+	}
+
+	return 1;
+}
+
+#ifdef CONFIG_PARPORT_1284
+/* Terminate a negotiated mode. */
+static void parport_ieee1284_terminate (struct parport *port)
+{
+	port = port->physport;
+
+	port->ieee1284.phase = IEEE1284_PH_TERMINATE;
+
+	/* EPP terminates differently. */
+	switch (port->ieee1284.mode) {
+	case IEEE1284_MODE_EPP:
+	case IEEE1284_MODE_EPPSL:
+	case IEEE1284_MODE_EPPSWE:
+		/* Terminate from EPP mode. */
+
+		/* Event 68: Set nInit low */
+		parport_frob_control (port,
+				      PARPORT_CONTROL_INIT,
+				      PARPORT_CONTROL_INIT);
+		udelay (50);
+
+		/* Event 69: Set nInit high, nSelectIn low */
+		parport_frob_control (port,
+				      PARPORT_CONTROL_SELECT,
+				      PARPORT_CONTROL_SELECT);
+		break;
+		
+	default:
+		/* Terminate from all other modes. */
+
+		/* Event 22: Set nSelectIn low, nAutoFd high */
+		parport_frob_control (port,
+				      PARPORT_CONTROL_SELECT
+				      | PARPORT_CONTROL_AUTOFD,
+				      PARPORT_CONTROL_SELECT);
+
+		/* Event 24: nAck goes low */
+		parport_wait_peripheral (port, PARPORT_STATUS_ACK, 0);
+
+		/* Event 25: Set nAutoFd low */
+		parport_frob_control (port,
+				      PARPORT_CONTROL_AUTOFD,
+				      PARPORT_CONTROL_AUTOFD);
+
+		/* Event 27: nAck goes high */
+		parport_wait_peripheral (port,
+					 PARPORT_STATUS_ACK, 
+					 PARPORT_STATUS_ACK);
+
+		/* Event 29: Set nAutoFd high */
+		parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
+	}
+
+	port->ieee1284.mode = IEEE1284_MODE_COMPAT;
+	port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+
+	DPRINTK (KERN_DEBUG "%s: In compatibility (forward idle) mode\n",
+		 port->name);
+}		
+#endif /* IEEE1284 support */
+
+/* Negotiate an IEEE 1284 mode.
+ * return values are:
+ *   0 - handshake OK; IEEE1284 peripheral and mode available
+ *  -1 - handshake failed; peripheral is not compliant (or none present)
+ *   1 - handshake OK; IEEE1284 peripheral present but mode not available
+ */
+int parport_negotiate (struct parport *port, int mode)
+{
+#ifndef CONFIG_PARPORT_1284
+	if (mode == IEEE1284_MODE_COMPAT)
+		return 0;
+	printk (KERN_ERR "parport: IEEE1284 not supported in this kernel\n");
+	return -1;
+#else
+	int m = mode & ~IEEE1284_ADDR;
+	unsigned char xflag;
+
+	port = port->physport;
+
+	/* Is there anything to do? */
+	if (port->ieee1284.mode == mode)
+		return 0;
+
+	/* Is the difference just an address-or-not bit? */
+	if ((port->ieee1284.mode & ~IEEE1284_ADDR) == (mode & ~IEEE1284_ADDR)){
+		port->ieee1284.mode = mode;
+		return 0;
+	}
+
+	/* Go to compability forward idle mode */
+	if (port->ieee1284.mode != IEEE1284_MODE_COMPAT)
+		parport_ieee1284_terminate (port);
+
+	if (mode == IEEE1284_MODE_COMPAT)
+		/* Compatibility mode: no negotiation. */
+		return 0; 
+
+	switch (mode) {
+	case IEEE1284_MODE_ECPSWE:
+		m = IEEE1284_MODE_ECP;
+		break;
+	case IEEE1284_MODE_EPPSL:
+	case IEEE1284_MODE_EPPSWE:
+		m = IEEE1284_MODE_EPP;
+		break;
+	case IEEE1284_MODE_BECP:
+		return -ENOSYS; /* FIXME (implement BECP) */
+	}
+
+	port->ieee1284.phase = IEEE1284_PH_NEGOTIATION;
+
+	/* Start off with nStrobe and nAutoFd high, and nSelectIn low */
+	parport_frob_control (port,
+			      PARPORT_CONTROL_STROBE
+			      | PARPORT_CONTROL_AUTOFD
+			      | PARPORT_CONTROL_SELECT,
+			      PARPORT_CONTROL_SELECT);
+	udelay(1);
+
+	/* Event 0: Set data */
+	parport_write_data (port, m);
+	udelay (400); /* Shouldn't need to wait this long. */
+
+	/* Event 1: Set nSelectIn high, nAutoFd low */
+	parport_frob_control (port,
+			      PARPORT_CONTROL_SELECT
+			      | PARPORT_CONTROL_AUTOFD,
+			      PARPORT_CONTROL_AUTOFD);
+
+	/* Event 2: PError, Select, nFault go high, nAck goes low */
+	if (parport_wait_peripheral (port,
+				     PARPORT_STATUS_ERROR
+				     | PARPORT_STATUS_SELECT
+				     | PARPORT_STATUS_PAPEROUT
+				     | PARPORT_STATUS_ACK,
+				     PARPORT_STATUS_ERROR
+				     | PARPORT_STATUS_SELECT
+				     | PARPORT_STATUS_PAPEROUT)) {
+		/* Timeout */
+		parport_frob_control (port,
+				      PARPORT_CONTROL_SELECT
+				      | PARPORT_CONTROL_AUTOFD,
+				      PARPORT_CONTROL_SELECT);
+		DPRINTK (KERN_DEBUG
+			 "%s: Peripheral not IEEE1284 compliant (0x%02X)\n",
+			 port->name, parport_read_status (port));
+		port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+		return -1; /* Not IEEE1284 compliant */
+	}
+
+	/* Event 3: Set nStrobe low */
+	parport_frob_control (port,
+			      PARPORT_CONTROL_STROBE,
+			      PARPORT_CONTROL_STROBE);
+
+	/* Event 4: Set nStrobe and nAutoFd high */
+	udelay (5);
+	parport_frob_control (port,
+			      PARPORT_CONTROL_STROBE
+			      | PARPORT_CONTROL_AUTOFD,
+			      0);
+
+	/* Event 6: nAck goes high */
+	if (parport_wait_peripheral (port,
+				     PARPORT_STATUS_ACK
+				     | PARPORT_STATUS_PAPEROUT,
+				     PARPORT_STATUS_ACK)) {
+		if (parport_read_status (port) & PARPORT_STATUS_ACK)
+			printk (KERN_DEBUG
+				"%s: working around buggy peripheral: tell "
+				"Tim what make it is\n", port->name);
+		DPRINTK (KERN_DEBUG
+			 "%s: Mode 0x%02x not supported? (0x%02x)\n",
+			 port->name, mode, port->ops->read_status (port));
+		parport_ieee1284_terminate (port);
+		return 1;
+	}
+
+	xflag = parport_read_status (port) & PARPORT_STATUS_SELECT;
+
+	/* xflag should be high for all modes other than nibble (0). */
+	if (mode && !xflag) {
+		/* Mode not supported. */
+		DPRINTK (KERN_DEBUG "%s: Mode 0x%02x not supported\n",
+			 port->name, mode);
+		parport_ieee1284_terminate (port);
+		return 1;
+	}
+
+	/* Mode is supported */
+	DPRINTK (KERN_DEBUG "%s: In mode 0x%02x\n", port->name, mode);
+	port->ieee1284.mode = mode;
+
+	/* But ECP is special */
+	if (mode & IEEE1284_MODE_ECP) {
+		port->ieee1284.phase = IEEE1284_PH_ECP_SETUP;
+
+		/* Event 30: Set nAutoFd low */
+		parport_frob_control (port,
+				      PARPORT_CONTROL_AUTOFD,
+				      PARPORT_CONTROL_AUTOFD);
+
+		/* Event 31: PError goes high. */
+		parport_wait_peripheral (port,
+					 PARPORT_STATUS_PAPEROUT,
+					 PARPORT_STATUS_PAPEROUT);
+		/* (Should check that this works..) */
+
+		port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+		DPRINTK (KERN_DEBUG "%s: ECP direction: forward\n",
+			 port->name);
+	} else switch (mode) {
+	case IEEE1284_MODE_NIBBLE:
+	case IEEE1284_MODE_BYTE:
+		port->ieee1284.phase = IEEE1284_PH_REV_IDLE;
+		break;
+	default:
+		port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+	}
+
+
+	return 0;
+#endif /* IEEE1284 support */
+}
+
+/* Acknowledge that the peripheral has data available.
+ * Events 18-20, in order to get from Reverse Idle phase
+ * to Host Busy Data Available.
+ * This will most likely be called from an interrupt.
+ * Returns zero if data was available.
+ */
+#ifdef CONFIG_PARPORT_1284
+static int parport_ieee1284_ack_data_avail (struct parport *port)
+{
+	if (parport_read_status (port) & PARPORT_STATUS_ERROR)
+		/* Event 18 didn't happen. */
+		return -1;
+
+	/* Event 20: nAutoFd goes high. */
+	port->ops->frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
+	port->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL;
+	return 0;
+}
+#endif /* IEEE1284 support */
+
+/* Handle an interrupt. */
+void parport_ieee1284_interrupt (int which, void *handle, struct pt_regs *regs)
+{
+	struct parport *port = handle;
+	parport_ieee1284_wakeup (port);
+
+#ifdef CONFIG_PARPORT_1284
+	if (port->ieee1284.phase == IEEE1284_PH_REV_IDLE) {
+		/* An interrupt in this phase means that data
+		 * is now available. */
+		DPRINTK (KERN_DEBUG "%s: Data available\n", port->name);
+		parport_ieee1284_ack_data_avail (port);
+	}
+#endif /* IEEE1284 support */
+}
+
+/* Write a block of data. */
+ssize_t parport_write (struct parport *port, const void *buffer, size_t len)
+{
+#ifndef CONFIG_PARPORT_1284
+	return port->ops->compat_write_data (port, buffer, len, 0);
+#else
+	ssize_t retval;
+	int mode = port->ieee1284.mode;
+	int addr = mode & IEEE1284_ADDR;
+	size_t (*fn) (struct parport *, const void *, size_t, int);
+
+	/* Ignore the device-ID-request bit and the address bit. */
+	mode &= ~(IEEE1284_DEVICEID | IEEE1284_ADDR);
+
+	/* Use the mode we're in. */
+	switch (mode) {
+	case IEEE1284_MODE_NIBBLE:
+		parport_negotiate (port, IEEE1284_MODE_COMPAT);
+	case IEEE1284_MODE_COMPAT:
+		DPRINTK (KERN_DEBUG "%s: Using compatibility mode\n",
+			 port->name);
+		fn = port->ops->compat_write_data;
+		break;
+
+	case IEEE1284_MODE_EPP:
+		DPRINTK (KERN_DEBUG "%s: Using EPP mode\n", port->name);
+		if (addr)
+			fn = port->ops->epp_write_addr;
+		else
+			fn = port->ops->epp_write_data;
+		break;
+
+	case IEEE1284_MODE_ECP:
+	case IEEE1284_MODE_ECPRLE:
+		DPRINTK (KERN_DEBUG "%s: Using ECP mode\n", port->name);
+		if (addr)
+			fn = port->ops->ecp_write_addr;
+		else
+			fn = port->ops->ecp_write_data;
+		break;
+
+	case IEEE1284_MODE_ECPSWE:
+		DPRINTK (KERN_DEBUG "%s: Using software-emulated ECP mode\n",
+			 port->name);
+		/* The caller has specified that it must be emulated,
+		 * even if we have ECP hardware! */
+		if (addr)
+			fn = parport_ieee1284_ecp_write_addr;
+		else
+			fn = parport_ieee1284_ecp_write_data;
+		break;
+
+	default:
+		DPRINTK (KERN_DEBUG "%s: Unknown mode 0x%02x\n", port->name,
+			port->ieee1284.mode);
+		return -ENOSYS;
+	}
+
+	retval = (*fn) (port, buffer, len, 0);
+	DPRINTK (KERN_DEBUG "%s: wrote %d/%d bytes\n", port->name, retval,
+		 len);
+	return retval;
+#endif /* IEEE1284 support */
+}
+
+/* Read a block of data. */
+ssize_t parport_read (struct parport *port, void *buffer, size_t len)
+{
+#ifndef CONFIG_PARPORT_1284
+	printk (KERN_ERR "parport: IEEE1284 not supported in this kernel\n");
+	return -ENODEV;
+#else
+	int mode = port->physport->ieee1284.mode;
+	int addr = mode & IEEE1284_ADDR;
+	size_t (*fn) (struct parport *, void *, size_t, int);
+
+	/* Ignore the device-ID-request bit and the address bit. */
+	mode &= ~(IEEE1284_DEVICEID | IEEE1284_ADDR);
+
+	/* Use the mode we're in. */
+	switch (mode) {
+	case IEEE1284_MODE_COMPAT:
+		if (parport_negotiate (port, IEEE1284_MODE_NIBBLE))
+			return -EIO;
+	case IEEE1284_MODE_NIBBLE:
+		DPRINTK (KERN_DEBUG "%s: Using nibble mode\n", port->name);
+		fn = port->ops->nibble_read_data;
+		break;
+
+	case IEEE1284_MODE_BYTE:
+		DPRINTK (KERN_DEBUG "%s: Using byte mode\n", port->name);
+		fn = port->ops->byte_read_data;
+		break;
+
+	case IEEE1284_MODE_EPP:
+		DPRINTK (KERN_DEBUG "%s: Using EPP mode\n", port->name);
+		if (addr)
+			fn = port->ops->epp_read_addr;
+		else
+			fn = port->ops->epp_read_data;
+		break;
+
+	case IEEE1284_MODE_ECP:
+	case IEEE1284_MODE_ECPRLE:
+		DPRINTK (KERN_DEBUG "%s: Using ECP mode\n", port->name);
+		fn = port->ops->ecp_read_data;
+		break;
+
+	case IEEE1284_MODE_ECPSWE:
+		DPRINTK (KERN_DEBUG "%s: Using software-emulated ECP mode\n",
+			 port->name);
+		fn = parport_ieee1284_ecp_read_data;
+		break;
+
+	default:
+		DPRINTK (KERN_DEBUG "%s: Unknown mode 0x%02x\n", port->name,
+			 port->physport->ieee1284.mode);
+		return -ENOSYS;
+	}
+
+	return (*fn) (port, buffer, len, 0);
+#endif /* IEEE1284 support */
+}
+
+/* Set the amount of time we wait while nothing's happening. */
+long parport_set_timeout (struct pardevice *dev, long inactivity)
+{
+	long int old = dev->timeout;
+
+	dev->timeout = inactivity;
+
+	if (dev->port->physport->cad == dev)
+		parport_ieee1284_wakeup (dev->port);
+
+	return old;
+}
diff -u --recursive --new-file v2.3.11/linux/drivers/parport/ieee1284_ops.c linux/drivers/parport/ieee1284_ops.c
--- v2.3.11/linux/drivers/parport/ieee1284_ops.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/parport/ieee1284_ops.c	Tue Jul  6 19:08:33 1999
@@ -0,0 +1,848 @@
+/* IEEE-1284 operations for parport.
+ *
+ * This file is for generic IEEE 1284 operations.  The idea is that
+ * they are used by the low-level drivers.  If they have a special way
+ * of doing something, they can provide their own routines (and put
+ * the function pointers in port->ops); if not, they can just use these
+ * as a fallback.
+ *
+ * Note: Make no assumptions about hardware or architecture in this file!
+ *
+ * Author: Tim Waugh <tim@cyberelk.demon.co.uk>
+ */
+
+#include <linux/config.h>
+#include <linux/parport.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+
+#define DEBUG /* undef me for production */
+
+#ifdef CONFIG_LP_CONSOLE
+#undef DEBUG /* Don't want a garbled console */
+#endif
+
+#ifdef DEBUG
+#define DPRINTK(stuff...) printk (stuff)
+#else
+#define DPRINTK(stuff...)
+#endif
+
+/***                                *
+ * One-way data transfer functions. *
+ *                                ***/
+
+static inline
+int polling (struct pardevice *dev)
+{
+	return dev->port->irq == PARPORT_IRQ_NONE;
+}
+
+/* Compatibility mode. */
+size_t parport_ieee1284_write_compat (struct parport *port,
+				      const void *buffer, size_t len,
+				      int flags)
+{
+	ssize_t count = 0;
+	const unsigned char *addr = buffer;
+	unsigned char byte;
+	struct pardevice *dev = port->physport->cad;
+	unsigned char ctl = (PARPORT_CONTROL_SELECT
+			     | PARPORT_CONTROL_INIT);
+
+	if (port->irq != PARPORT_IRQ_NONE)
+		parport_enable_irq (port);
+
+	port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
+	while (count < len) {
+		long expire = jiffies + dev->timeout;
+		long wait = (HZ + 99) / 100;
+		unsigned char mask = (PARPORT_STATUS_ERROR
+				      | PARPORT_STATUS_BUSY);
+		unsigned char val = (PARPORT_STATUS_ERROR
+				     | PARPORT_STATUS_BUSY);
+		int i;
+
+		/* Write the character to the data lines. */
+		byte = *addr++;
+		parport_write_data (port, byte);
+		udelay (1);
+
+		/* Wait until the peripheral's ready */
+		do {
+			/* Is the peripheral ready yet? */
+			if (!parport_wait_peripheral (port, mask, val))
+				/* Skip the loop */
+				goto ready;
+
+			/* Is the peripheral upset? */
+			if ((parport_read_status (port) &
+			     (PARPORT_STATUS_PAPEROUT |
+			      PARPORT_STATUS_SELECT |
+			      PARPORT_STATUS_ERROR))
+			    != (PARPORT_STATUS_SELECT |
+				PARPORT_STATUS_ERROR))
+				/* If nFault is asserted (i.e. no
+				 * error) and PAPEROUT and SELECT are
+				 * just red herrings, give the driver
+				 * a chance to check it's happy with
+				 * that before continuing. */
+				goto stop;
+
+			/* Have we run out of time? */
+			if (!time_before (jiffies, expire))
+				break;
+
+			/* Yield the port for a while.  If this is the
+                           first time around the loop, don't let go of
+                           the port.  This way, we find out if we have
+                           our interrupt handler called. */
+			if (count && polling (dev)) {
+				parport_release (dev);
+				current->state = TASK_INTERRUPTIBLE;
+				schedule_timeout (wait);
+				parport_claim_or_block (dev);
+			}
+			else
+				/* We must have the device claimed here */
+				parport_wait_event (port, wait);
+
+			/* Is there a signal pending? */
+			if (signal_pending (current))
+				goto stop;
+
+			/* Wait longer next time. */
+			wait *= 2;
+		} while (time_before (jiffies, expire));
+
+		DPRINTK (KERN_DEBUG "%s: Timed out\n", port->name);
+		break;
+
+	ready:
+		/* Clear out previous irqs. */
+		while (!down_trylock (&port->physport->ieee1284.irq));
+
+		/* Pulse strobe. */
+		parport_write_control (port, ctl | PARPORT_CONTROL_STROBE);
+		udelay (1); /* strobe */
+
+		parport_write_control (port, ctl);
+		udelay (1); /* hold */
+
+		/* Wait until it's received (up to 20us). */
+		for (i = 0; i < 20; i++) {
+			if (!down_trylock (&port->physport->ieee1284.irq) ||
+			    !(parport_read_status (port) & PARPORT_STATUS_ACK))
+				break;
+			udelay (1);
+		}
+
+		count++;
+
+                /* Let another process run if it needs to. */
+		if (time_before (jiffies, expire))
+			if (!parport_yield_blocking (dev)
+			    && current->need_resched)
+				schedule ();
+	}
+ stop:
+	port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+
+	return count;
+}
+
+/* Nibble mode. */
+size_t parport_ieee1284_read_nibble (struct parport *port, 
+				     void *buffer, size_t len,
+				     int flags)
+{
+#ifndef CONFIG_PARPORT_1284
+	return 0;
+#else
+	unsigned char *buf = buffer;
+	int i;
+	unsigned char byte = 0;
+
+	len *= 2; /* in nibbles */
+	for (i=0; i < len; i++) {
+		unsigned char nibble;
+
+		/* Does the error line indicate end of data? */
+		if (((i & 1) == 0) &&
+		    (parport_read_status(port) & PARPORT_STATUS_ERROR)) {
+			port->physport->ieee1284.phase = IEEE1284_PH_HBUSY_DNA;
+			DPRINTK (KERN_DEBUG
+				"%s: No more nibble data (%d bytes)\n",
+				port->name, i/2);
+
+			/* Go to reverse idle phase. */
+			parport_frob_control (port,
+					      PARPORT_CONTROL_AUTOFD,
+					      PARPORT_CONTROL_AUTOFD);
+			port->physport->ieee1284.phase = IEEE1284_PH_REV_IDLE;
+			break;
+		}
+
+		/* Event 7: Set nAutoFd low. */
+		parport_frob_control (port,
+				      PARPORT_CONTROL_AUTOFD,
+				      PARPORT_CONTROL_AUTOFD);
+
+		/* Event 9: nAck goes low. */
+		port->ieee1284.phase = IEEE1284_PH_REV_DATA;
+		if (parport_wait_peripheral (port,
+					     PARPORT_STATUS_ACK, 0)) {
+			/* Timeout -- no more data? */
+			DPRINTK (KERN_DEBUG
+				 "%s: Nibble timeout at event 9 (%d bytes)\n",
+				 port->name, i/2);
+			break;
+		}
+
+
+		/* Read a nibble. */
+		nibble = parport_read_status (port) >> 3;
+		nibble &= ~8;
+		if ((nibble & 0x10) == 0)
+			nibble |= 8;
+		nibble &= 0xf;
+
+		/* Event 10: Set nAutoFd high. */
+		parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
+
+		/* Event 11: nAck goes high. */
+		if (parport_wait_peripheral (port,
+					     PARPORT_STATUS_ACK,
+					     PARPORT_STATUS_ACK)) {
+			/* Timeout -- no more data? */
+			DPRINTK (KERN_DEBUG
+				 "%s: Nibble timeout at event 11\n",
+				 port->name);
+			break;
+		}
+
+		if (i & 1) {
+			/* Second nibble */
+			byte |= nibble << 4;
+			*buf++ = byte;
+		} else 
+			byte = nibble;
+	}
+
+	i /= 2; /* i is now in bytes */
+
+	if (i == len) {
+		/* Read the last nibble without checking data avail. */
+		port = port->physport;
+		if (parport_read_status (port) & PARPORT_STATUS_ERROR)
+			port->ieee1284.phase = IEEE1284_PH_HBUSY_DNA;
+		else
+			port->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL;
+	}
+
+	return i;
+#endif /* IEEE1284 support */
+}
+
+/* Byte mode. */
+size_t parport_ieee1284_read_byte (struct parport *port,
+				   void *buffer, size_t len,
+				   int flags)
+{
+#ifndef CONFIG_PARPORT_1284
+	return 0;
+#else
+	unsigned char *buf = buffer;
+	ssize_t count = 0;
+
+	for (count = 0; count < len; count++) {
+		unsigned char byte;
+
+		/* Data available? */
+		if (parport_read_status (port) & PARPORT_STATUS_ERROR) {
+			port->physport->ieee1284.phase = IEEE1284_PH_HBUSY_DNA;
+			DPRINTK (KERN_DEBUG
+				 "%s: No more byte data (%d bytes)\n",
+				 port->name, count);
+
+			/* Go to reverse idle phase. */
+			parport_frob_control (port,
+					      PARPORT_CONTROL_AUTOFD,
+					      PARPORT_CONTROL_AUTOFD);
+			port->physport->ieee1284.phase = IEEE1284_PH_REV_IDLE;
+			break;
+		}
+
+		/* Event 7: Set nAutoFd low. */
+		parport_frob_control (port,
+				      PARPORT_CONTROL_AUTOFD,
+				      PARPORT_CONTROL_AUTOFD);
+
+		/* Event 9: nAck goes low. */
+		port->physport->ieee1284.phase = IEEE1284_PH_REV_DATA;
+		if (parport_wait_peripheral (port,
+					     PARPORT_STATUS_ACK,
+					     0)) {
+			/* Timeout -- no more data? */
+			parport_frob_control (port, PARPORT_CONTROL_AUTOFD,
+						 0);
+			DPRINTK (KERN_DEBUG "%s: Byte timeout at event 9\n",
+				 port->name);
+			break;
+		}
+
+		byte = parport_read_data (port);
+		*buf++ = byte;
+
+		/* Event 10: Set nAutoFd high */
+		parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
+
+		/* Event 11: nAck goes high. */
+		if (parport_wait_peripheral (port,
+					     PARPORT_STATUS_ACK,
+					     PARPORT_STATUS_ACK)) {
+			/* Timeout -- no more data? */
+			DPRINTK (KERN_DEBUG "%s: Byte timeout at event 11\n",
+				 port->name);
+			break;
+		}
+
+		/* Event 16: Set nStrobe low. */
+		parport_frob_control (port,
+				      PARPORT_CONTROL_STROBE,
+				      PARPORT_CONTROL_STROBE);
+		udelay (5);
+
+		/* Event 17: Set nStrobe high. */
+		parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
+	}
+
+	if (count == len) {
+		/* Read the last byte without checking data avail. */
+		port = port->physport;
+		if (parport_read_status (port) & PARPORT_STATUS_ERROR)
+			port->ieee1284.phase = IEEE1284_PH_HBUSY_DNA;
+		else
+			port->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL;
+	}
+
+	return count;
+#endif /* IEEE1284 support */
+}
+
+/***              *
+ * ECP Functions. *
+ *              ***/
+
+#ifdef CONFIG_PARPORT_1284
+
+static inline
+int ecp_forward_to_reverse (struct parport *port)
+{
+	int retval;
+
+	/* Event 38: Set nAutoFd low */
+	parport_frob_control (port,
+			      PARPORT_CONTROL_AUTOFD,
+			      PARPORT_CONTROL_AUTOFD);
+	parport_data_reverse (port);
+	udelay (5);
+
+	/* Event 39: Set nInit low to initiate bus reversal */
+	parport_frob_control (port,
+			      PARPORT_CONTROL_INIT,
+			      PARPORT_CONTROL_INIT);
+
+	/* Event 40: PError goes low */
+	retval = parport_wait_peripheral (port,
+					  PARPORT_STATUS_PAPEROUT, 0);
+
+	if (!retval) {
+		DPRINTK (KERN_DEBUG "%s: ECP direction: reverse\n",
+			 port->name);
+		port->ieee1284.phase = IEEE1284_PH_REV_IDLE;
+	}
+
+	return retval;
+}
+
+static inline
+int ecp_reverse_to_forward (struct parport *port)
+{
+	int retval;
+
+	/* Event 47: Set nInit high */
+	parport_frob_control (port,
+			      PARPORT_CONTROL_INIT,
+			      PARPORT_CONTROL_INIT);
+	parport_data_reverse (port);
+
+	/* Event 49: PError goes high */
+	retval = parport_wait_peripheral (port,
+					  PARPORT_STATUS_PAPEROUT,
+					  PARPORT_STATUS_PAPEROUT);
+
+	if (!retval) {
+		parport_data_forward (port);
+		DPRINTK (KERN_DEBUG "%s: ECP direction: forward\n",
+			 port->name);
+		port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+	}
+
+	return retval;
+}
+
+#endif /* IEEE1284 support */
+
+/* ECP mode, forward channel, data. */
+size_t parport_ieee1284_ecp_write_data (struct parport *port,
+					const void *buffer, size_t len,
+					int flags)
+{
+#ifndef CONFIG_PARPORT_1284
+	return 0;
+#else
+	const unsigned char *buf = buffer;
+	size_t written;
+	int ctl = parport_read_control (port) & ~PARPORT_CONTROL_AUTOFD;
+	int retry;
+
+	port = port->physport;
+
+	if (port->ieee1284.phase != IEEE1284_PH_FWD_IDLE)
+		if (ecp_reverse_to_forward (port))
+			return 0;
+
+	port->ieee1284.phase = IEEE1284_PH_FWD_DATA;
+
+	/* HostAck high (data, not command) */
+	parport_write_control (port, ctl);
+	for (written = 0; written < len; written++, buf++) {
+		long expire = jiffies + port->cad->timeout;
+		unsigned char byte;
+
+		byte = *buf;
+	try_again:
+		parport_write_data (port, byte);
+		parport_write_control (port, ctl | PARPORT_CONTROL_STROBE);
+		udelay (5);
+		for (retry = 0; retry < 100; retry++) {
+			if (!parport_wait_peripheral (port,
+						      PARPORT_STATUS_BUSY, 0))
+				goto success;
+
+			if (signal_pending (current)) {
+				parport_write_control (port, ctl);
+				break;
+			}
+		}
+
+		/* Time for Host Transfer Recovery (page 41 of IEEE1284) */
+		DPRINTK (KERN_DEBUG "%s: ECP transfer stalled!\n", port->name);
+
+		parport_write_control (port, ctl | PARPORT_CONTROL_INIT);
+		udelay (50);
+		if (parport_read_status (port) & PARPORT_STATUS_PAPEROUT) {
+			/* It's buggered. */
+			parport_write_control (port, ctl);
+			break;
+		}
+
+		parport_write_control (port, ctl);
+		udelay (50);
+		if (!(parport_read_status (port) & PARPORT_STATUS_PAPEROUT))
+			break;
+
+		DPRINTK (KERN_DEBUG "%s: Host transfer recovered\n",
+			 port->name);
+
+		if (time_after_eq (jiffies, expire)) break;
+		goto try_again;
+	success:
+		parport_write_control (port, ctl);
+		udelay (5);
+		if (parport_wait_peripheral (port,
+					     PARPORT_STATUS_BUSY,
+					     PARPORT_STATUS_BUSY))
+			/* Peripheral hasn't accepted the data. */
+			break;
+	}
+
+	port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+
+	return written;
+#endif /* IEEE1284 support */
+}
+
+/* ECP mode, reverse channel, data. */
+size_t parport_ieee1284_ecp_read_data (struct parport *port,
+				       void *buffer, size_t len, int flags)
+{
+#ifndef CONFIG_PARPORT_1284
+	return 0;
+#else
+	struct pardevice *dev = port->cad;
+	unsigned char *buf = buffer;
+	int rle_count = 0; /* shut gcc up */
+	int rle = 0;
+	ssize_t count = 0;
+
+	port = port->physport;
+
+	if (port->ieee1284.phase != IEEE1284_PH_REV_IDLE)
+		if (ecp_forward_to_reverse (port))
+			return 0;
+
+	port->ieee1284.phase = IEEE1284_PH_REV_DATA;
+
+	/* Set HostAck low to start accepting data. */
+	parport_frob_control (port, PARPORT_CONTROL_AUTOFD,
+			      PARPORT_CONTROL_AUTOFD);
+	while (count < len) {
+		long expire = jiffies + dev->timeout;
+		unsigned char byte;
+		int command;
+
+		/* Event 43: Peripheral sets nAck low. It can take as
+                   long as it wants. */
+		while (parport_wait_peripheral (port,
+						PARPORT_STATUS_ACK,
+						PARPORT_STATUS_ACK)) {
+			/* The peripheral hasn't given us data in
+			   35ms.  If we have data to give back to the
+			   caller, do it now. */
+			if (count)
+				goto out;
+
+			/* If we've used up all the time we were allowed,
+			   give up altogether. */
+			if (!time_before (jiffies, expire))
+				goto out;
+
+			/* Yield the port for a while. */
+			if (count && polling (dev)) {
+				parport_release (dev);
+				current->state = TASK_INTERRUPTIBLE;
+				schedule_timeout ((HZ + 99) / 25);
+				parport_claim_or_block (dev);
+			}
+			else
+				/* We must have the device claimed here. */
+				parport_wait_event (port, (HZ + 99) / 25);
+
+			/* Is there a signal pending? */
+			if (signal_pending (current))
+				goto out;
+		}
+
+		/* Is this a command? */
+		if (rle)
+			/* The last byte was a run-length count, so
+                           this can't be as well. */
+			command = 0;
+		else
+			command = (parport_read_status (port) &
+				   PARPORT_STATUS_BUSY) ? 1 : 0;
+
+		/* Read the data. */
+		byte = parport_read_data (port);
+
+		/* If this is a channel command, rather than an RLE
+                   command or a normal data byte, don't accept it. */
+		if (command) {
+			if (byte & 0x80) {
+				DPRINTK (KERN_DEBUG "%s: stopping short at "
+					 "channel command (%02x)\n",
+					 port->name, byte);
+				goto out;
+			}
+			else if (port->ieee1284.mode != IEEE1284_MODE_ECPRLE)
+				DPRINTK (KERN_DEBUG "%s: device illegally "
+					 "using RLE; accepting anyway\n",
+					 port->name);
+
+			rle_count = byte + 1;
+
+			/* Are we allowed to read that many bytes? */
+			if (rle_count > (len - count)) {
+				DPRINTK (KERN_DEBUG "%s: leaving %d RLE bytes "
+					 "for next time\n", port->name,
+					 rle_count);
+				break;
+			}
+
+			rle = 1;
+		}
+
+		/* Event 44: Set HostAck high, acknowledging handshake. */
+		parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
+
+		/* Event 45: The peripheral has 35ms to set nAck high. */
+		if (parport_wait_peripheral (port, PARPORT_STATUS_ACK, 0)) {
+			/* It's gone wrong.  Return what data we have
+                           to the caller. */
+			DPRINTK (KERN_DEBUG "ECP read timed out at 45\n");
+
+			if (command)
+				printk (KERN_WARNING
+					"%s: command ignored (%02x)\n",
+					port->name, byte);
+
+			break;
+		}
+
+		/* Event 46: Set HostAck low and accept the data. */
+		parport_frob_control (port,
+				      PARPORT_CONTROL_AUTOFD,
+				      PARPORT_CONTROL_AUTOFD);
+
+		/* If we just read a run-length count, fetch the data. */
+		if (command)
+			continue;
+
+		/* If this is the byte after a run-length count, decompress. */
+		if (rle) {
+			rle = 0;
+			memset (buf, byte, rle_count);
+			buf += rle_count;
+			count += rle_count;
+			DPRINTK (KERN_DEBUG "%s: decompressed to %d bytes\n",
+				 port->name, rle_count);
+		}
+		else
+			/* Normal data byte. */
+			*buf++ = byte, count++;
+	}
+
+ out:
+	return count;
+#endif /* IEEE1284 support */
+}
+
+/* ECP mode, forward channel, commands. */
+size_t parport_ieee1284_ecp_write_addr (struct parport *port,
+					const void *buffer, size_t len,
+					int flags)
+{
+#ifndef CONFIG_PARPORT_1284
+	return 0;
+#else
+	const unsigned char *buf = buffer;
+	size_t written;
+	int ctl = parport_read_control (port) | PARPORT_CONTROL_AUTOFD;
+	int retry;
+
+	port = port->physport;
+
+	if (port->ieee1284.phase != IEEE1284_PH_FWD_IDLE)
+		if (ecp_reverse_to_forward (port))
+			return 0;
+
+	port->ieee1284.phase = IEEE1284_PH_FWD_DATA;
+
+	/* HostAck low (command, not data) */
+	parport_write_control (port, ctl);
+	for (written = 0; written < len; written++, buf++) {
+		long expire = jiffies + port->cad->timeout;
+		unsigned char byte;
+
+		byte = *buf;
+	try_again:
+		parport_write_data (port, byte);
+		parport_write_control (port, ctl | PARPORT_CONTROL_STROBE);
+		udelay (5);
+		for (retry = 0; retry < 100; retry++) {
+			if (!parport_wait_peripheral (port,
+						      PARPORT_STATUS_BUSY, 0))
+				goto success;
+
+			if (signal_pending (current)) {
+				parport_write_control (port, ctl);
+				break;
+			}
+		}
+
+		/* Time for Host Transfer Recovery (page 41 of IEEE1284) */
+		DPRINTK (KERN_DEBUG "%s: ECP transfer stalled!\n", port->name);
+
+		parport_write_control (port, ctl | PARPORT_CONTROL_INIT);
+		udelay (50);
+		if (parport_read_status (port) & PARPORT_STATUS_PAPEROUT) {
+			/* It's buggered. */
+			parport_write_control (port, ctl);
+			break;
+		}
+
+		parport_write_control (port, ctl);
+		udelay (50);
+		if (!(parport_read_status (port) & PARPORT_STATUS_PAPEROUT))
+			break;
+
+		DPRINTK (KERN_DEBUG "%s: Host transfer recovered\n",
+			 port->name);
+
+		if (time_after_eq (jiffies, expire)) break;
+		goto try_again;
+	success:
+		parport_write_control (port, ctl);
+		udelay (5);
+		if (parport_wait_peripheral (port,
+					     PARPORT_STATUS_BUSY,
+					     PARPORT_STATUS_BUSY))
+			/* Peripheral hasn't accepted the data. */
+			break;
+	}
+
+	port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+
+	return written;
+#endif /* IEEE1284 support */
+}
+
+/***              *
+ * EPP functions. *
+ *              ***/
+
+/* EPP mode, forward channel, data. */
+size_t parport_ieee1284_epp_write_data (struct parport *port,
+					const void *buffer, size_t len,
+					int flags)
+{
+	/* This is untested */
+	unsigned char *bp = (unsigned char *) buffer;
+	size_t ret = 0;
+
+	parport_frob_control (port,
+			      PARPORT_CONTROL_STROBE |
+			      PARPORT_CONTROL_AUTOFD |
+			      PARPORT_CONTROL_SELECT,
+			      PARPORT_CONTROL_STROBE |
+			      PARPORT_CONTROL_SELECT);
+	port->ops->data_forward (port);
+	for (; len > 0; len--, bp++) {
+		parport_write_data (port, *bp);
+
+		if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY,
+					     PARPORT_STATUS_BUSY))
+			break;
+
+		/* Strobe data */
+		parport_frob_control (port, PARPORT_CONTROL_AUTOFD,
+				      PARPORT_CONTROL_AUTOFD);
+
+		if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0))
+			break;
+
+		parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
+		ret++;
+	}
+
+	return ret;
+}
+
+/* EPP mode, reverse channel, data. */
+size_t parport_ieee1284_epp_read_data (struct parport *port,
+				       void *buffer, size_t len,
+				       int flags)
+{
+	/* This is untested. */
+	unsigned char *bp = (unsigned char *) buffer;
+	unsigned ret = 0;
+
+	parport_frob_control (port,
+			      PARPORT_CONTROL_STROBE |
+			      PARPORT_CONTROL_AUTOFD |
+			      PARPORT_CONTROL_SELECT, 0);
+	port->ops->data_reverse (port);
+	for (; len > 0; len--, bp++) {
+		if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY,
+					     PARPORT_STATUS_BUSY))
+			break;
+
+		parport_frob_control (port, PARPORT_CONTROL_AUTOFD,
+				      PARPORT_CONTROL_AUTOFD);
+
+		if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0))
+			break;
+
+		*bp = parport_read_data (port);
+
+		parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
+		ret++;
+	}
+	port->ops->data_forward (port);
+
+	return ret;
+}
+
+/* EPP mode, forward channel, addresses. */
+size_t parport_ieee1284_epp_write_addr (struct parport *port,
+					const void *buffer, size_t len,
+					int flags)
+{
+	/* This is untested */
+	unsigned char *bp = (unsigned char *) buffer;
+	size_t ret = 0;
+
+	parport_frob_control (port,
+			      PARPORT_CONTROL_STROBE |
+			      PARPORT_CONTROL_SELECT |
+			      PARPORT_CONTROL_AUTOFD,
+			      PARPORT_CONTROL_STROBE |
+			      PARPORT_CONTROL_SELECT);
+	port->ops->data_forward (port);
+	for (; len > 0; len--, bp++) {
+		parport_write_data (port, *bp);
+
+		if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY,
+					     PARPORT_STATUS_BUSY))
+			break;
+
+		/* Strobe data */
+		parport_frob_control (port, PARPORT_CONTROL_SELECT,
+				      PARPORT_CONTROL_SELECT);
+
+		if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0))
+			break;
+
+		parport_frob_control (port, PARPORT_CONTROL_SELECT, 0);
+		ret++;
+	}
+
+	return ret;
+}
+
+/* EPP mode, reverse channel, addresses. */
+size_t parport_ieee1284_epp_read_addr (struct parport *port,
+				       void *buffer, size_t len,
+				       int flags)
+{
+	/* This is untested. */
+	unsigned char *bp = (unsigned char *) buffer;
+	unsigned ret = 0;
+
+	parport_frob_control (port,
+			      PARPORT_CONTROL_STROBE |
+			      PARPORT_CONTROL_SELECT |
+			      PARPORT_CONTROL_AUTOFD, 0);
+	port->ops->data_reverse (port);
+	for (; len > 0; len--, bp++) {
+		if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY,
+					     PARPORT_STATUS_BUSY))
+			break;
+
+		parport_frob_control (port, PARPORT_CONTROL_SELECT,
+				      PARPORT_CONTROL_SELECT);
+
+		if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0))
+			break;
+
+		*bp = parport_read_data (port);
+
+		parport_frob_control (port, PARPORT_CONTROL_SELECT, 0);
+		ret++;
+	}
+	port->ops->data_forward (port);
+
+	return ret;
+}
diff -u --recursive --new-file v2.3.11/linux/drivers/parport/init.c linux/drivers/parport/init.c
--- v2.3.11/linux/drivers/parport/init.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/parport/init.c	Tue Jul 27 13:55:52 1999
@@ -0,0 +1,206 @@
+/* Parallel-port initialisation code.
+ * 
+ * Authors: David Campbell <campbell@torque.net>
+ *          Tim Waugh <tim@cyberelk.demon.co.uk>
+ *	    Jose Renau <renau@acm.org>
+ *
+ * based on work by Grant Guenther <grant@torque.net>
+ *              and Philip Blundell <Philip.Blundell@pobox.com>
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/threads.h>
+
+#include <linux/parport.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/init.h>
+
+#ifndef MODULE
+static int io[PARPORT_MAX+1] __initdata = { [0 ... PARPORT_MAX] = 0 };
+static int io_hi[PARPORT_MAX+1] __initdata = { [0 ... PARPORT_MAX] = 0 };
+static int irq[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_IRQ_PROBEONLY };
+static int dma[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_DMA_NONE };
+
+extern int parport_pc_init(int *io, int *io_hi, int *irq, int *dma);
+
+static int parport_setup_ptr __initdata = 0;
+
+__initfunc(void parport_setup(char *str, int *ints))
+{
+	if (ints[0] == 0) {
+		if (str && !strncmp(str, "auto", 4)) {
+			irq[0] = PARPORT_IRQ_AUTO;
+			dma[0] = PARPORT_DMA_AUTO;
+		}
+		else if (str)
+			printk (KERN_ERR "parport: `%s': huh?\n", str);
+		else
+			printk (KERN_ERR "parport: parport=.. what?\n");
+		
+		return;
+	}
+	else if (ints[1] == 0) {
+		/* Disable parport if "parport=0" in cmdline */
+		io[0] = PARPORT_DISABLE; 
+		return;
+	}
+
+	if (parport_setup_ptr < PARPORT_MAX) {
+		char *sep;
+		io[parport_setup_ptr] = ints[1];
+		irq[parport_setup_ptr] = PARPORT_IRQ_NONE;
+		dma[parport_setup_ptr] = PARPORT_DMA_NONE;
+		if (ints[0] > 1) {
+			irq[parport_setup_ptr] = ints[2];
+			if (ints[0] > 2) {
+				dma[parport_setup_ptr] = ints[3];
+				goto done;
+			}
+
+			if (str == NULL)
+				goto done;
+
+			goto dma_from_str;
+		}
+		else if (str == NULL)
+			goto done;
+		else if (!strncmp(str, "auto", 4))
+			irq[parport_setup_ptr] = PARPORT_IRQ_AUTO;
+		else if (strncmp(str, "none", 4) != 0) {
+			printk(KERN_ERR "parport: bad irq `%s'\n", str);
+			return;
+		}
+
+		if ((sep = strchr(str, ',')) == NULL) goto done;
+		str = sep+1;
+	dma_from_str:
+		if (!strncmp(str, "auto", 4))
+			dma[parport_setup_ptr] = PARPORT_DMA_AUTO;
+		else if (strncmp(str, "none", 4) != 0) {
+			char *ep;
+			dma[parport_setup_ptr] = simple_strtoul(str, &ep, 0);
+			if (ep == str) {
+				printk(KERN_ERR "parport: bad dma `%s'\n",
+				       str);
+				return;
+			}
+		}
+	done:
+		parport_setup_ptr++;
+	} else
+		printk(KERN_ERR "parport=%s ignored, too many ports\n", str);
+}
+#endif
+
+#ifdef MODULE
+int init_module(void)
+{
+#ifdef CONFIG_SYSCTL
+	parport_default_proc_register ();
+#endif
+	return 0;
+}
+
+void cleanup_module(void)
+{
+#ifdef CONFIG_SYSCTL
+	parport_default_proc_unregister ();
+#endif
+}
+
+#else
+
+__initfunc(int parport_init(void))
+{
+	if (io[0] == PARPORT_DISABLE) 
+		return 1;
+
+#ifdef CONFIG_SYSCTL
+	parport_default_proc_register ();
+#endif
+
+#ifdef CONFIG_PARPORT_PC
+	parport_pc_init(io, io_hi, irq, dma);
+#endif
+#ifdef CONFIG_PARPORT_AMIGA
+	parport_amiga_init();
+#endif
+#ifdef CONFIG_PARPORT_MFC3
+	parport_mfc3_init();
+#endif
+#ifdef CONFIG_PARPORT_ATARI
+	parport_atari_init();
+#endif
+#ifdef CONFIG_PARPORT_ARC
+	parport_arc_init();
+#endif
+	return 0;
+}
+#endif
+
+/* Exported symbols for modules. */
+
+EXPORT_SYMBOL(parport_claim);
+EXPORT_SYMBOL(parport_claim_or_block);
+EXPORT_SYMBOL(parport_release);
+EXPORT_SYMBOL(parport_register_port);
+EXPORT_SYMBOL(parport_announce_port);
+EXPORT_SYMBOL(parport_unregister_port);
+EXPORT_SYMBOL(parport_register_driver);
+EXPORT_SYMBOL(parport_unregister_driver);
+EXPORT_SYMBOL(parport_register_device);
+EXPORT_SYMBOL(parport_unregister_device);
+EXPORT_SYMBOL(parport_enumerate);
+EXPORT_SYMBOL(parport_negotiate);
+EXPORT_SYMBOL(parport_write);
+EXPORT_SYMBOL(parport_read);
+EXPORT_SYMBOL(parport_ieee1284_wakeup);
+EXPORT_SYMBOL(parport_wait_peripheral);
+EXPORT_SYMBOL(parport_wait_event);
+EXPORT_SYMBOL(parport_set_timeout);
+EXPORT_SYMBOL(parport_ieee1284_interrupt);
+EXPORT_SYMBOL(parport_ieee1284_ecp_write_data);
+EXPORT_SYMBOL(parport_ieee1284_ecp_read_data);
+EXPORT_SYMBOL(parport_ieee1284_ecp_write_addr);
+EXPORT_SYMBOL(parport_ieee1284_write_compat);
+EXPORT_SYMBOL(parport_ieee1284_read_nibble);
+EXPORT_SYMBOL(parport_ieee1284_read_byte);
+EXPORT_SYMBOL(parport_ieee1284_epp_write_data);
+EXPORT_SYMBOL(parport_ieee1284_epp_read_data);
+EXPORT_SYMBOL(parport_ieee1284_epp_write_addr);
+EXPORT_SYMBOL(parport_ieee1284_epp_read_addr);
+EXPORT_SYMBOL(parport_proc_register);
+EXPORT_SYMBOL(parport_proc_unregister);
+EXPORT_SYMBOL(parport_device_proc_register);
+EXPORT_SYMBOL(parport_device_proc_unregister);
+EXPORT_SYMBOL(parport_default_proc_register);
+EXPORT_SYMBOL(parport_default_proc_unregister);
+EXPORT_SYMBOL(parport_parse_irqs);
+EXPORT_SYMBOL(parport_parse_dmas);
+#ifdef CONFIG_PARPORT_1284
+EXPORT_SYMBOL(parport_open);
+EXPORT_SYMBOL(parport_close);
+EXPORT_SYMBOL(parport_device_id);
+EXPORT_SYMBOL(parport_device_num);
+EXPORT_SYMBOL(parport_device_coords);
+EXPORT_SYMBOL(parport_daisy_deselect_all);
+EXPORT_SYMBOL(parport_daisy_select);
+EXPORT_SYMBOL(parport_daisy_init);
+#endif
+
+void inc_parport_count(void)
+{
+#ifdef MODULE
+	MOD_INC_USE_COUNT;
+#endif
+}
+
+void dec_parport_count(void)
+{
+#ifdef MODULE
+	MOD_DEC_USE_COUNT;
+#endif
+}
diff -u --recursive --new-file v2.3.11/linux/drivers/parport/multiface.h linux/drivers/parport/multiface.h
--- v2.3.11/linux/drivers/parport/multiface.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/parport/multiface.h	Tue May 11 09:55:49 1999
@@ -0,0 +1,20 @@
+#ifndef _MULTIFACE_H_
+#define _MULTIFACE_H_
+
+/*
+ * Defines for SerialMaster, Multiface Card II and Multiface Card III
+ * The addresses given below are offsets to the board base address
+ * 
+ * 6.11.95 Joerg Dorchain (dorchain@mpi-sb.mpg.de)
+ *
+ */
+
+#define PIA_REG_PADWIDTH 255
+
+#define DUARTBASE 0x0000
+#define PITBASE   0x0100
+#define ROMBASE   0x0200
+#define PIABASE   0x4000
+
+#endif
+
diff -u --recursive --new-file v2.3.11/linux/drivers/parport/parport_amiga.c linux/drivers/parport/parport_amiga.c
--- v2.3.11/linux/drivers/parport/parport_amiga.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/parport/parport_amiga.c	Tue Jul 27 13:55:52 1999
@@ -0,0 +1,295 @@
+/* Low-level parallel port routines for the Amiga buildin port
+ *
+ * Author: Joerg Dorchain <dorchain@wirbel.com>
+ *
+ * This is a complete rewrite of the code, but based heaviy upon the old
+ * lp_intern. code.
+ *
+ * The built-in Amiga parallel port provides one port at a fixed address
+ * with 8 bisdirecttional data lines (D0 - D7) and 3 bidirectional status
+ * lines (BUSY, POUT, SEL), 1 output control line /STROBE (raised automatically in
+ * hardware when the data register is accessed), and 1 input control line
+ * /ACK, able to cause an interrupt, but both not directly settable by
+ * software.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/parport.h>
+#include <asm/setup.h>
+#include <asm/amigahw.h>
+#include <asm/irq.h>
+#include <asm/amigaints.h>
+
+#undef DEBUG
+#ifdef DEBUG
+#define DPRINTK printk
+#else
+static inline int DPRINTK() {return 0;}
+#endif
+
+static struct parport *this_port = NULL;
+
+static void amiga_write_data(struct parport *p, unsigned char data)
+{
+DPRINTK("write_data %c\n",data);
+	/* Triggers also /STROBE. This behavior cannot be changed */
+	ciaa.prb = data;
+}
+
+static unsigned char amiga_read_data(struct parport *p)
+{
+	/* Triggers also /STROBE. This behavior cannot be changed */
+	return ciaa.prb;
+}
+
+#if 0
+static unsigned char control_pc_to_amiga(unsigned char control)
+{
+	unsigned char ret = 0;
+
+	if (control & PARPORT_CONTROL_DIRECTION) /* XXX: What is this? */
+		;
+	if (control & PARPORT_CONTROL_INTEN) /* XXX: What is INTEN? */
+		;
+	if (control & PARPORT_CONTROL_SELECT) /* XXX: What is SELECP? */
+		;
+	if (control & PARPORT_CONTROL_INIT) /* INITP */
+		/* reset connected to cpu reset pin */;
+	if (control & PARPORT_CONTROL_AUTOFD) /* AUTOLF */
+		/* Not connected */;
+	if (control & PARPORT_CONTROL_STROBE) /* Strobe */
+		/* Handled only directly by hardware */;
+	return ret;
+}
+#endif
+
+static unsigned char control_amiga_to_pc(unsigned char control)
+{
+	return PARPORT_CONTROL_INTEN | PARPORT_CONTROL_SELECT |
+	      PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_STROBE;
+	/* fake value: interrupt enable, select in, no reset,
+	no autolf, no strobe - seems to be closest the wiring diagram */
+}
+
+static void amiga_write_control(struct parport *p, unsigned char control)
+{
+DPRINTK("write_control %02x\n",control);
+	/* No implementation possible */
+}
+	
+static unsigned char amiga_read_control( struct parport *p)
+{
+DPRINTK("read_control \n");
+	return control_amiga_to_pc(0);
+}
+
+static unsigned char amiga_frob_control( struct parport *p, unsigned char mask, unsigned char val)
+{
+	unsigned char old;
+
+DPRINTK("frob_control mask %02x, value %02x\n",mask,val);
+	old = amiga_read_control(p);
+	amiga_write_control(p, (old & ~mask) ^ val);
+	return old;
+}
+
+
+static unsigned char status_pc_to_amiga(unsigned char status)
+{
+	unsigned char ret = 1;
+
+	if (status & PARPORT_STATUS_BUSY) /* Busy */
+		ret &= ~1;
+	if (status & PARPORT_STATUS_ACK) /* Ack */
+		/* handled in hardware */;
+	if (status & PARPORT_STATUS_PAPEROUT) /* PaperOut */
+		ret |= 2;
+	if (status & PARPORT_STATUS_SELECT) /* select */
+		ret |= 4;
+	if (status & PARPORT_STATUS_ERROR) /* error */
+		/* not connected */;
+	return ret;
+}
+
+static unsigned char status_amiga_to_pc(unsigned char status)
+{
+	unsigned char ret = PARPORT_STATUS_BUSY | PARPORT_STATUS_ACK | PARPORT_STATUS_ERROR;
+
+	if (status & 1) /* Busy */
+		ret &= ~PARPORT_STATUS_BUSY;
+	if (status & 2) /* PaperOut */
+		ret |= PARPORT_STATUS_PAPEROUT;
+	if (status & 4) /* Selected */
+		ret |= PARPORT_STATUS_SELECT;
+	/* the rest is not connected or handled autonomously in hardware */
+
+	return ret;
+}
+
+static void amiga_write_status( struct parport *p, unsigned char status)
+{
+DPRINTK("write_status %02x\n",status);
+	ciab.pra |= (ciab.pra & 0xf8) | status_pc_to_amiga(status);
+}
+
+static unsigned char amiga_read_status(struct parport *p)
+{
+	unsigned char status;
+
+	status = status_amiga_to_pc(ciab.pra & 7);
+DPRINTK("read_status %02x\n", status);
+	return status;
+}
+
+static void amiga_change_mode( struct parport *p, int m)
+{
+	/* XXX: This port only has one mode, and I am
+	not sure about the corresponding PC-style mode*/
+}
+
+/* as this ports irq handling is already done, we use a generic funktion */
+static void amiga_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	parport_generic_irq(irq, (struct parport *) dev_id, regs);
+}
+
+
+static void amiga_init_state(struct parport_state *s)
+{
+	s->u.amiga.data = 0;
+	s->u.amiga.datadir = 255;
+	s->u.amiga.status = 0;
+	s->u.amiga.statusdir = 0;
+}
+
+static void amiga_save_state(struct parport *p, struct parport_state *s)
+{
+	s->u.amiga.data = ciaa.prb;
+	s->u.amiga.datadir = ciaa.ddrb;
+	s->u.amiga.status = ciab.pra & 7;
+	s->u.amiga.statusdir = ciab.ddra & 7;
+}
+
+static void amiga_restore_state(struct parport *p, struct parport_state *s)
+{
+	ciaa.prb = s->u.amiga.data;
+	ciaa.ddrb = s->u.amiga.datadir;
+	ciab.pra |= (ciab.pra & 0xf8) | s->u.amiga.status;
+	ciab.ddra |= (ciab.ddra & 0xf8) | s->u.amiga.statusdir;
+}
+
+static void amiga_enable_irq(struct parport *p)
+{
+	enable_irq(IRQ_AMIGA_CIAA_FLG);
+}
+
+static void amiga_disable_irq(struct parport *p)
+{
+	disable_irq(IRQ_AMIGA_CIAA_FLG);
+}
+
+static void amiga_inc_use_count(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void amiga_dec_use_count(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+static struct parport_operations pp_amiga_ops = {
+	amiga_write_data,
+	amiga_read_data,
+
+	amiga_write_control,
+	amiga_read_control,
+	amiga_frob_control,
+
+	amiga_read_status,
+
+	amiga_enable_irq,
+	amiga_disable_irq,
+
+	NULL, /* data_forward */
+	NULL, /* data_reverse */
+
+	amiga_interrupt, 
+
+	amiga_init_state,
+	amiga_save_state,
+	amiga_restore_state,
+
+	amiga_inc_use_count,
+	amiga_dec_use_count,
+
+	parport_ieee1284_epp_write_data,
+	parport_ieee1284_epp_read_data, /* impossible? */
+	parport_ieee1284_epp_write_addr,
+	parport_ieee1284_epp_read_addr, /* impossible? */
+
+	parport_ieee1284_ecp_write_data,
+	parport_ieee1284_ecp_read_data, /* impossible? */
+	parport_ieee1284_ecp_write_addr,
+
+	parport_ieee1284_write_compat, /* FIXME - need to write amiga one */
+	parport_ieee1284_read_nibble,
+	parport_ieee1284_read_byte, /* impossible? */
+};
+
+/* ----------- Initialisation code --------------------------------- */
+
+__initfunc(int parport_amiga_init(void))
+{
+	struct parport *p;
+
+	if (MACH_IS_AMIGA && AMIGAHW_PRESENT(AMI_PARALLEL)) {
+		ciaa.ddrb = 0xff;
+		ciab.ddra &= 0xf8;
+		if (!(p = parport_register_port((unsigned long)&ciaa.prb,
+					IRQ_AMIGA_CIAA_FLG, PARPORT_DMA_NONE,
+					&pp_amiga_ops)))
+			return 0;
+		this_port = p;
+		printk(KERN_INFO "%s: Amiga built-in port using irq\n", p->name);
+		/* XXX: set operating mode */
+		parport_proc_register(p);
+		if (request_irq(IRQ_AMIGA_CIAA_FLG, amiga_interrupt, 0,
+				p->name, p)) {
+			parport_unregister_port (p);
+			return 0;
+		}
+
+		if (parport_probe_hook)
+			(*parport_probe_hook)(p);
+
+		parport_announce_port (p);
+
+		return 1;
+
+	}
+	return 0;
+}
+
+#ifdef MODULE
+
+MODULE_AUTHOR("Joerg Dorchain");
+MODULE_DESCRIPTION("Parport Driver for Amiga builtin Port");
+MODULE_SUPPORTED_DEVICE("Amiga builtin Parallel Port");
+
+int init_module(void)
+{
+	return ! parport_amiga_init();
+}
+
+void cleanup_module(void)
+{
+	if (p->irq != PARPORT_IRQ_NONE)
+		free_irq(IRQ_AMIGA_CIAA_FLG, p);
+	parport_proc_unregister(this_port);
+	parport_unregister_port(this_port);
+}
+#endif
+
+
diff -u --recursive --new-file v2.3.11/linux/drivers/parport/parport_arc.c linux/drivers/parport/parport_arc.c
--- v2.3.11/linux/drivers/parport/parport_arc.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/parport/parport_arc.c	Tue Jul 27 13:55:52 1999
@@ -0,0 +1,149 @@
+/* Low-level parallel port routines for Archimedes onboard hardware
+ *
+ * Author: Phil Blundell <Philip.Blundell@pobox.com>
+ */
+
+/* This driver is for the parallel port hardware found on Acorn's old
+ * range of Archimedes machines.  The A5000 and newer systems have PC-style
+ * I/O hardware and should use the parport_pc driver instead.
+ *
+ * The Acorn printer port hardware is very simple.  There is a single 8-bit
+ * write-only latch for the data port and control/status bits are handled
+ * with various auxilliary input and output lines.  The port is not
+ * bidirectional, does not support any modes other than SPP, and has only
+ * a subset of the standard printer control lines connected.
+ */
+
+#include <linux/threads.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/parport.h>
+
+#include <asm/ptrace.h>
+#include <asm/io.h>
+#include <asm/arch/oldlatches.h>
+#include <asm/arch/irqs.h>
+
+#define DATA_ADDRESS    0x3350010
+
+/* This is equivalent to the above and only used for request_region. */
+#define PORT_BASE       0x80000000 | ((DATA_ADDRESS - IO_BASE) >> 2)
+
+/* The hardware can't read from the data latch, so we must use a soft
+   copy. */
+static unsigned char data_copy;
+
+/* These are pretty simple. We know the irq is never shared and the
+   kernel does all the magic that's required. */
+static void arc_enable_irq(struct parport *p)
+{
+	enable_irq(p->irq);
+}
+
+static void arc_disable_irq(struct parport *p)
+{
+	disable_irq(p->irq);
+}
+
+static void arc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	parport_generic_irq(irq, (struct parport *) dev_id, regs);
+}
+
+static void arc_write_data(struct parport *p, unsigned char data)
+{
+	data_copy = data;
+	outb_t(data, DATA_LATCH);
+}
+
+static unsigned char arc_read_data(struct parport *p)
+{
+	return data_copy;
+}
+
+static void arc_inc_use_count(void)
+{
+#ifdef MODULE
+	MOD_INC_USE_COUNT;
+#endif
+}
+
+static void arc_dec_use_count(void)
+{
+#ifdef MODULE
+	MOD_DEC_USE_COUNT;
+#endif
+}
+
+static struct parport_operations parport_arc_ops = 
+{
+	arc_write_data,
+	arc_read_data,
+
+	arc_write_control,
+	arc_read_control,
+	arc_frob_control,
+
+	arc_read_status,
+
+	arc_enable_irq,
+	arc_disable_irq,
+
+	arc_data_forward,
+	arc_data_reverse,
+
+	arc_interrupt,
+
+	arc_init_state,
+	arc_save_state,
+	arc_restore_state,
+
+	arc_inc_use_count,
+	arc_dec_use_count,
+
+	parport_ieee1284_epp_write_data,
+	parport_ieee1284_epp_read_data,
+	parport_ieee1284_epp_write_addr,
+	parport_ieee1284_epp_read_addr,
+
+	parport_ieee1284_ecp_write_data,
+	parport_ieee1284_ecp_read_data,
+	parport_ieee1284_ecp_write_addr,
+	
+	parport_ieee1284_write_compat,
+	parport_ieee1284_read_nibble,
+	parport_ieee1284_read_byte,
+};
+
+/* --- Initialisation code -------------------------------- */
+
+int parport_arc_init(void)
+{
+	/* Archimedes hardware provides only one port, at a fixed address */
+	struct parport *p;
+
+	if (check_region(PORT_BASE, 1))
+		return 0;
+
+	p = parport_register_port (PORT_BASE, IRQ_PRINTERACK,
+				   PARPORT_DMA_NONE, &parport_arc_ops);
+
+	if (!p)
+		return 0;
+
+	p->modes = PARPORT_MODE_ARCSPP;
+	p->size = 1;
+
+	printk(KERN_INFO "%s: Archimedes on-board port, using irq %d\n",
+	       p->irq);
+	parport_proc_register(p);
+
+	/* Tell the high-level drivers about the port. */
+	parport_announce_port (p);
+
+	return 1;
+}
diff -u --recursive --new-file v2.3.11/linux/drivers/parport/parport_atari.c linux/drivers/parport/parport_atari.c
--- v2.3.11/linux/drivers/parport/parport_atari.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/parport/parport_atari.c	Tue Jul 27 13:55:52 1999
@@ -0,0 +1,229 @@
+/* Low-level parallel port routines for the Atari builtin port
+ *
+ * Author: Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
+ *
+ * Based on parport_amiga.c.
+ *
+ * The built-in Atari parallel port provides one port at a fixed address
+ * with 8 output data lines (D0 - D7), 1 output control line (STROBE)
+ * and 1 input status line (BUSY) able to cause an interrupt.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/parport.h>
+#include <asm/setup.h>
+#include <asm/atarihw.h>
+#include <asm/irq.h>
+#include <asm/atariints.h>
+
+static struct parport *this_port = NULL;
+
+static unsigned char
+parport_atari_read_data(struct parport *p)
+{
+	unsigned long flags;
+	unsigned char data;
+
+	save_flags(flags);
+	cli();
+	sound_ym.rd_data_reg_sel = 15;
+	data = sound_ym.rd_data_reg_sel;
+	restore_flags(flags);
+	return data;
+}
+
+static void
+parport_atari_write_data(struct parport *p, unsigned char data)
+{
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	sound_ym.rd_data_reg_sel = 15;
+	sound_ym.wd_data = data;
+	restore_flags(flags);
+}
+
+static unsigned char
+parport_atari_read_control(struct parport *p)
+{
+	unsigned long flags;
+	unsigned char control = 0;
+
+	save_flags(flags);
+	cli();
+	sound_ym.rd_data_reg_sel = 14;
+	if (!(sound_ym.rd_data_reg_sel & (1 << 5)))
+		control = PARPORT_CONTROL_STROBE;
+	restore_flags(flags);
+	return control;
+}
+
+static void
+parport_atari_write_control(struct parport *p, unsigned char control)
+{
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	sound_ym.rd_data_reg_sel = 14;
+	if (control & PARPORT_CONTROL_STROBE)
+		sound_ym.wd_data = sound_ym.rd_data_reg_sel & ~(1 << 5);
+	else
+		sound_ym.wd_data = sound_ym.rd_data_reg_sel | (1 << 5);
+	restore_flags(flags);
+}
+
+static unsigned char
+parport_atari_frob_control(struct parport *p, unsigned char mask,
+			   unsigned char val)
+{
+	unsigned char old = parport_atari_read_control(p);
+	parport_atari_write_control(p, (old & ~mask) ^ val);
+	return old;
+}
+
+static unsigned char
+parport_atari_read_status(struct parport *p)
+{
+	return ((mfp.par_dt_reg & 1 ? 0 : PARPORT_STATUS_BUSY) |
+		PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR);
+}
+
+static void
+parport_atari_init_state(struct parport_state *s)
+{
+}
+
+static void
+parport_atari_save_state(struct parport *p, struct parport_state *s)
+{
+}
+
+static void
+parport_atari_restore_state(struct parport *p, struct parport_state *s)
+{
+}
+
+static void
+parport_atari_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	parport_generic_irq(irq, (struct parport *) dev_id, regs);
+}
+
+static void
+parport_atari_inc_use_count(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void
+parport_atari_dec_use_count(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+static struct parport_operations parport_atari_ops = {
+	parport_atari_write_data,
+	parport_atari_read_data,
+
+	parport_atari_write_control,
+	parport_atari_read_control,
+	parport_atari_frob_control,
+
+	parport_atari_read_status,
+
+	NULL, /* enable_irq - FIXME */
+	NULL, /* disable_irq - FIXME */
+
+	NULL, /* data_forward - FIXME */
+	NULL, /* data_reverse - FIXME */
+
+	parport_atari_interrupt,
+
+	parport_atari_init_state,
+	parport_atari_save_state,
+	parport_atari_restore_state,
+
+	parport_atari_inc_use_count,
+	parport_atari_dec_use_count,
+
+	parport_ieee1284_epp_write_data,
+	parport_ieee1284_epp_read_data,
+	parport_ieee1284_epp_write_addr,
+	parport_ieee1284_epp_read_addr,
+
+	parport_ieee1284_ecp_write_data,
+	parport_ieee1284_ecp_read_data,
+	parport_ieee1284_ecp_write_addr,
+
+	parport_ieee1284_write_compat,
+	parport_ieee1284_read_nibble,
+	parport_ieee1284_read_byte,
+};
+
+
+int __init
+parport_atari_init(void)
+{
+	struct parport *p;
+	unsigned long flags;
+
+	if (MACH_IS_ATARI) {
+		save_flags(flags);
+		cli();
+		/* Soundchip port A/B as output. */
+		sound_ym.rd_data_reg_sel = 7;
+		sound_ym.wd_data = (sound_ym.rd_data_reg_sel & 0x3f) | 0xc0;
+		/* STROBE high. */
+		sound_ym.rd_data_reg_sel = 14;
+		sound_ym.wd_data = sound_ym.rd_data_reg_sel | (1 << 5);
+		restore_flags(flags);
+		/* MFP port I0 as input. */
+		mfp.data_dir &= ~1;
+		/* MFP port I0 interrupt on high->low edge. */
+		mfp.active_edge &= ~1;
+		p = parport_register_port((unsigned long)&sound_ym.wd_data,
+					  IRQ_MFP_BUSY, PARPORT_DMA_NONE,
+					  &parport_atari_ops);
+		if (!p)
+			return 0;
+		if (request_irq(IRQ_MFP_BUSY, parport_atari_interrupt,
+				IRQ_TYPE_SLOW, p->name, p)) {
+			parport_unregister_port (p);
+			return 0;
+		}
+
+		this_port = p;
+		printk(KERN_INFO "%s: Atari built-in port using irq\n", p->name);
+		parport_proc_register(p);
+
+		parport_announce_port (p);
+
+		return 1;
+	}
+	return 0;
+}
+
+#ifdef MODULE
+
+MODULE_AUTHOR("Andreas Schwab");
+MODULE_DESCRIPTION("Parport Driver for Atari builtin Port");
+MODULE_SUPPORTED_DEVICE("Atari builtin Parallel Port");
+
+int
+init_module(void)
+{
+	return parport_atari_init() ? 0 : -ENODEV;
+}
+
+void
+cleanup_module(void)
+{
+	if (p->irq != PARPORT_IRQ_NONE)
+		free_irq(IRQ_MFP_BUSY, p);
+	parport_proc_unregister(this_port);
+	parport_unregister_port(this_port);
+}
+#endif
diff -u --recursive --new-file v2.3.11/linux/drivers/parport/parport_mfc3.c linux/drivers/parport/parport_mfc3.c
--- v2.3.11/linux/drivers/parport/parport_mfc3.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/parport/parport_mfc3.c	Tue Jul 27 13:55:52 1999
@@ -0,0 +1,393 @@
+/* Low-level parallel port routines for the Multiface 3 card
+ *
+ * Author: Joerg Dorchain <dorchain@wirbel.com>
+ *
+ * (C) The elitist m68k Users(TM)
+ *
+ * based on the existing parport_amiga and lp_mfc
+ *
+ *
+ * From the MFC3 documentation:
+ * 
+ * Miscellaneous PIA Details
+ * -------------------------
+ * 
+ * 	The two open-drain interrupt outputs /IRQA and /IRQB are routed to
+ * /INT2 of the Z2 bus.
+ * 
+ * 	The CPU data bus of the PIA (D0-D7) is connected to D8-D15 on the Z2
+ * bus. This means that any PIA registers are accessed at even addresses.
+ * 
+ * Centronics Pin Connections for the PIA
+ * --------------------------------------
+ * 
+ * 	The following table shows the connections between the PIA and the
+ * Centronics interface connector. These connections implement a single, but
+ * very complete, Centronics type interface. The Pin column gives the pin
+ * numbers of the PIA. The Centronics pin numbers can be found in the section
+ * "Parallel Connectors".
+ * 
+ * 
+ *    Pin | PIA | Dir | Centronics Names
+ * -------+-----+-----+---------------------------------------------------------
+ *     19 | CB2 | --> | /STROBE (aka /DRDY)
+ *  10-17 | PBx | <-> | DATA0 - DATA7
+ *     18 | CB1 | <-- | /ACK
+ *     40 | CA1 | <-- | BUSY
+ *      3 | PA1 | <-- | PAPER-OUT (aka POUT)
+ *      4 | PA2 | <-- | SELECTED (aka SEL)
+ *      9 | PA7 | --> | /INIT (aka /RESET or /INPUT-PRIME)
+ *      6 | PA4 | <-- | /ERROR (aka /FAULT)
+ *      7 | PA5 | --> | DIR (aka /SELECT-IN)
+ *      8 | PA6 | --> | /AUTO-FEED-XT
+ *     39 | CA2 | --> | open
+ *      5 | PA3 | <-- | /ACK (same as CB1!)
+ *      2 | PA0 | <-- | BUSY (same as CA1!)
+ * -------+-----+-----+---------------------------------------------------------
+ * 
+ * Should be enough to understand some of the driver.
+ */
+
+#include "multiface.h"
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/parport.h>
+#include <linux/delay.h>
+#include <linux/mc6821.h>
+#include <linux/zorro.h>
+#include <asm/setup.h>
+#include <asm/amigahw.h>
+#include <asm/irq.h>
+#include <asm/amigaints.h>
+
+/* Maximum Number of Cards supported */
+#define MAX_MFC 5
+
+#undef DEBUG
+#ifdef DEBUG
+#define DPRINTK printk
+#else
+static inline int DPRINTK() {return 0;}
+#endif
+
+static struct parport *this_port[MAX_MFC] = {NULL, };
+static volatile int dummy; /* for trigger readds */
+
+#define pia(dev) ((struct pia *)(dev->base))
+static struct parport_operations pp_mfc3_ops;
+
+static void mfc3_write_data(struct parport *p, unsigned char data)
+{
+DPRINTK("write_data %c\n",data);
+
+	dummy = pia(p)->pprb; /* clears irq bit */
+	/* Triggers also /STROBE.*/
+	pia(p)->pprb = data;
+}
+
+static unsigned char mfc3_read_data(struct parport *p)
+{
+	/* clears interupt bit. Triggers also /STROBE. */
+	return pia(p)->pprb;
+}
+
+static unsigned char control_pc_to_mfc3(unsigned char control)
+{
+	unsigned char ret = 32|64;
+
+	if (control & PARPORT_CONTROL_DIRECTION) /* XXX: What is this? */
+		;
+	if (control & PARPORT_CONTROL_INTEN) /* XXX: What is INTEN? */
+		;
+	if (control & PARPORT_CONTROL_SELECT) /* XXX: What is SELECP? */
+		ret &= ~32; /* /SELECT_IN */
+	if (control & PARPORT_CONTROL_INIT) /* INITP */
+		ret |= 128;
+	if (control & PARPORT_CONTROL_AUTOFD) /* AUTOLF */
+		ret &= ~64;
+	if (control & PARPORT_CONTROL_STROBE) /* Strobe */
+		/* Handled directly by hardware */;
+	return ret;
+}
+
+static unsigned char control_mfc3_to_pc(unsigned char control)
+{
+	unsigned char ret = PARPORT_CONTROL_INTEN | PARPORT_CONTROL_STROBE 
+			  | PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_SELECT;
+
+	if (control & 128) /* /INITP */
+		ret |= PARPORT_CONTROL_INIT;
+	if (control & 64) /* /AUTOLF */
+		ret &= ~PARPORT_CONTROL_AUTOFD;
+	if (control & 32) /* /SELECT_IN */
+		ret &= ~PARPORT_CONTROL_SELECT;
+	return ret;
+}
+
+static void mfc3_write_control(struct parport *p, unsigned char control)
+{
+DPRINTK("write_control %02x\n",control);
+	pia(p)->ppra = (pia(p)->ppra & 0x1f) | control_pc_to_mfc3(control);
+}
+	
+static unsigned char mfc3_read_control( struct parport *p)
+{
+DPRINTK("read_control \n");
+	return control_mfc3_to_pc(pia(p)->ppra & 0xe0);
+}
+
+static unsigned char mfc3_frob_control( struct parport *p, unsigned char mask, unsigned char val)
+{
+	unsigned char old;
+
+DPRINTK("frob_control mask %02x, value %02x\n",mask,val);
+	old = mfc3_read_control(p);
+	mfc3_write_control(p, (old & ~mask) ^ val);
+	return old;
+}
+
+
+static unsigned char status_pc_to_mfc3(unsigned char status)
+{
+	unsigned char ret = 1;
+
+	if (status & PARPORT_STATUS_BUSY) /* Busy */
+		ret &= ~1;
+	if (status & PARPORT_STATUS_ACK) /* Ack */
+		ret |= 8;
+	if (status & PARPORT_STATUS_PAPEROUT) /* PaperOut */
+		ret |= 2;
+	if (status & PARPORT_STATUS_SELECT) /* select */
+		ret |= 4;
+	if (status & PARPORT_STATUS_ERROR) /* error */
+		ret |= 16;
+	return ret;
+}
+
+static unsigned char status_mfc3_to_pc(unsigned char status)
+{
+	unsigned char ret = PARPORT_STATUS_BUSY;
+
+	if (status & 1) /* Busy */
+		ret &= ~PARPORT_STATUS_BUSY;
+	if (status & 2) /* PaperOut */
+		ret |= PARPORT_STATUS_PAPEROUT;
+	if (status & 4) /* Selected */
+		ret |= PARPORT_STATUS_SELECT;
+	if (status & 8) /* Ack */
+		ret |= PARPORT_STATUS_ACK;
+	if (status & 16) /* /ERROR */
+		ret |= PARPORT_STATUS_ERROR;
+
+	return ret;
+}
+
+static void mfc3_write_status( struct parport *p, unsigned char status)
+{
+DPRINTK("write_status %02x\n",status);
+	pia(p)->ppra = (pia(p)->ppra & 0xe0) | status_pc_to_mfc3(status);
+}
+
+static unsigned char mfc3_read_status(struct parport *p)
+{
+	unsigned char status;
+
+	status = status_mfc3_to_pc(pia(p)->ppra & 0x1f);
+DPRINTK("read_status %02x\n", status);
+	return status;
+}
+
+static void mfc3_change_mode( struct parport *p, int m)
+{
+	/* XXX: This port only has one mode, and I am
+	not sure about the corresponding PC-style mode*/
+}
+
+static int use_cnt = 0;
+
+static void mfc3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	int i;
+
+	for( i = 0; i < MAX_MFC; i++)
+		if (this_port[i] != NULL)
+			if (pia(this_port[i])->crb & 128) { /* Board caused interrupt */
+				dummy = pia(this_port[i])->pprb; /* clear irq bit */
+				parport_generic_irq(irq, this_port[i], regs);
+			}
+}
+
+static int mfc3_claim_resources(struct parport *p)
+{
+DPRINTK("claim_resources\n");
+}
+
+static void mfc3_init_state(struct parport_state *s)
+{
+	s->u.amiga.data = 0;
+	s->u.amiga.datadir = 255;
+	s->u.amiga.status = 0;
+	s->u.amiga.statusdir = 0xe0;
+}
+
+static void mfc3_save_state(struct parport *p, struct parport_state *s)
+{
+	s->u.amiga.data = pia(p)->pprb;
+	pia(p)->crb &= ~PIA_DDR;
+	s->u.amiga.datadir = pia(p)->pddrb;
+	pia(p)->crb |= PIA_DDR;
+	s->u.amiga.status = pia(p)->ppra;
+	pia(p)->cra &= ~PIA_DDR;
+	s->u.amiga.statusdir = pia(p)->pddrb;
+	pia(p)->cra |= PIA_DDR;
+}
+
+static void mfc3_restore_state(struct parport *p, struct parport_state *s)
+{
+	pia(p)->pprb = s->u.amiga.data;
+	pia(p)->crb &= ~PIA_DDR;
+	pia(p)->pddrb = s->u.amiga.datadir;
+	pia(p)->crb |= PIA_DDR;
+	pia(p)->ppra = s->u.amiga.status;
+	pia(p)->cra &= ~PIA_DDR;
+	pia(p)->pddrb = s->u.amiga.statusdir;
+	pia(p)->cra |= PIA_DDR;
+}
+
+static void mfc3_enable_irq(struct parport *p)
+{
+	pia(p)->crb |= PIA_C1_ENABLE_IRQ;
+}
+
+static void mfc3_disable_irq(struct parport *p)
+{
+	pia(p)->crb &= ~PIA_C1_ENABLE_IRQ;
+}
+
+static void mfc3_inc_use_count(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void mfc3_dec_use_count(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+static struct parport_operations pp_mfc3_ops = {
+	mfc3_write_data,
+	mfc3_read_data,
+
+	mfc3_write_control,
+	mfc3_read_control,
+	mfc3_frob_control,
+
+	mfc3_read_status,
+
+	mfc3_enable_irq,
+	mfc3_disable_irq,
+
+	NULL, /* data_forward - FIXME */
+	NULL, /* data_reverse - FIXME */
+
+	mfc3_interrupt,
+
+	mfc3_init_state,
+	mfc3_save_state,
+	mfc3_restore_state,
+
+	mfc3_inc_use_count,
+	mfc3_dec_use_count,
+
+	parport_ieee1284_epp_write_data,
+	parport_ieee1284_epp_read_data,
+	parport_ieee1284_epp_write_addr,
+	parport_ieee1284_epp_read_addr,
+
+	parport_ieee1284_ecp_write_data,
+	parport_ieee1284_ecp_read_data,
+	parport_ieee1284_ecp_write_addr,
+
+	parport_ieee1284_write_compat,
+	parport_ieee1284_read_nibble,
+	parport_ieee1284_read_byte,
+};
+
+/* ----------- Initialisation code --------------------------------- */
+
+__initfunc(int parport_mfc3_init(void))
+{
+	struct parport *p;
+	int pias = 0;
+	struct pia *pp;
+	unsigned int key = 0;
+	const struct ConfigDev *cd;
+
+	if (MACH_IS_AMIGA) {
+		while ((key = zorro_find(ZORRO_PROD_BSC_MULTIFACE_III, 0, key))) {
+			cd = zorro_get_board(key);
+			pp = (struct pia *)ZTWO_VADDR((((u_char *)cd->cd_BoardAddr)+PIABASE));
+			if (pias < MAX_MFC) {
+				pp->crb = 0;
+				pp->pddrb = 255; /* all data pins output */
+				pp->crb = PIA_DDR|32|8;
+				dummy = pp->pddrb; /* reading clears interrupt */
+				pp->cra = 0;
+				pp->pddra = 0xe0; /* /RESET,  /DIR ,/AUTO-FEED output */
+				pp->cra = PIA_DDR;
+				pp->ppra = 0; /* reset printer */
+				udelay(10);
+				pp->ppra = 128;
+				if ((p = parport_register_port((unsigned long)pp,
+					IRQ_AMIGA_PORTS, PARPORT_DMA_NONE,
+					&pp_mfc3_ops))) {
+					this_port[pias++] = p;
+					printk(KERN_INFO "%s: Multiface III port using irq\n", p->name);
+					/* XXX: set operating mode */
+					parport_proc_register(p);
+
+					if (p->irq != PARPORT_IRQ_NONE)
+						if (use_cnt++ == 0)
+							if (request_irq(IRQ_AMIGA_PORTS, mfc3_interrupt, 0, p->name, &pp_mfc3_ops))
+								use_cnt--;
+
+					if (parport_probe_hook)
+						(*parport_probe_hook)(p);
+					zorro_config_board(key, 0);
+					p->private_data = (void *)key;
+					parport_announce_port (p);
+				}
+			}
+		}
+	}
+	return pias;
+}
+
+#ifdef MODULE
+
+MODULE_AUTHOR("Joerg Dorchain");
+MODULE_DESCRIPTION("Parport Driver for Multiface 3 expansion cards Paralllel Port");
+MODULE_SUPPORTED_DEVICE("Multiface 3 Parallel Port");
+
+int init_module(void)
+{
+	return ! parport_mfc3_init();
+}
+
+void cleanup_module(void)
+{
+	int i;
+
+	for (i = 0; i < MAX_MFC; i++)
+		if (this_port[i] != NULL) {
+			if (p->irq != PARPORT_IRQ_NONE) 
+				if (--use_cnt == 0) 
+			free_irq(IRQ_AMIGA_PORTS, &pp_mfc3_ops);
+			parport_proc_unregister(this_port[i]);
+			parport_unregister_port(this_port[i]);
+			zorro_unconfig_board((unsigned int)this_port[i]->private_data, 0);
+		}
+}
+#endif
+
+
diff -u --recursive --new-file v2.3.11/linux/drivers/parport/parport_pc.c linux/drivers/parport/parport_pc.c
--- v2.3.11/linux/drivers/parport/parport_pc.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/parport/parport_pc.c	Wed Jul 28 10:26:36 1999
@@ -0,0 +1,1854 @@
+/* Low-level parallel-port routines for 8255-based PC-style hardware.
+ * 
+ * Authors: Phil Blundell <Philip.Blundell@pobox.com>
+ *          Tim Waugh <tim@cyberelk.demon.co.uk>
+ *	    Jose Renau <renau@acm.org>
+ *          David Campbell <campbell@torque.net>
+ *          Andrea Arcangeli
+ *
+ * based on work by Grant Guenther <grant@torque.net> and Phil Blundell.
+ *
+ * Cleaned up include files - Russell King <linux@arm.uk.linux.org>
+ * DMA support - Bert De Jonghe <bert@sophis.be>
+ * Better EPP probing - Carlos Henrique Bauer <chbauer@acm.org>
+ */
+
+/* This driver should work with any hardware that is broadly compatible
+ * with that in the IBM PC.  This applies to the majority of integrated
+ * I/O chipsets that are commonly available.  The expected register
+ * layout is:
+ *
+ *	base+0		data
+ *	base+1		status
+ *	base+2		control
+ *
+ * In addition, there are some optional registers:
+ *
+ *	base+3		EPP address
+ *	base+4		EPP data
+ *	base+0x400	ECP config A
+ *	base+0x401	ECP config B
+ *	base+0x402	ECP control
+ *
+ * All registers are 8 bits wide and read/write.  If your hardware differs
+ * only in register addresses (eg because your registers are on 32-bit
+ * word boundaries) then you can alter the constants in parport_pc.h to
+ * accomodate this.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/pci.h>
+#include <linux/sysctl.h>
+
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/uaccess.h>
+
+#include <linux/parport.h>
+#include <linux/parport_pc.h>
+#include <asm/parport.h>
+
+/* ECR modes */
+#define ECR_SPP 00
+#define ECR_PS2 01
+#define ECR_PPF 02
+#define ECR_ECP 03
+#define ECR_EPP 04
+#define ECR_VND 05
+#define ECR_TST 06
+#define ECR_CNF 07
+
+/* frob_control, but for ECR */
+static void frob_econtrol (struct parport *pb, unsigned char m,
+			   unsigned char v)
+{
+	outb ((inb (ECONTROL (pb)) & ~m) ^ v, ECONTROL (pb));
+}
+
+#ifdef CONFIG_PARPORT_1284
+/* Safely change the mode bits in the ECR */
+static int change_mode(struct parport *p, int m)
+{
+	const struct parport_pc_private *priv = p->physport->private_data;
+	int ecr = ECONTROL(p);
+	unsigned char oecr;
+	int mode;
+
+	if (!priv->ecr) {
+		printk (KERN_DEBUG "change_mode: but there's no ECR!\n");
+		return 0;
+	}
+
+	/* Bits <7:5> contain the mode. */
+	oecr = inb (ecr);
+	mode = (oecr >> 5) & 0x7;
+	if (mode == m) return 0;
+	if (mode && m)
+		/* We have to go through mode 000 */
+		change_mode (p, ECR_SPP);
+
+	if (m < 2 && !(parport_read_control (p) & 0x20)) {
+		/* This mode resets the FIFO, so we may
+		 * have to wait for it to drain first. */
+		long expire = jiffies + p->physport->cad->timeout;
+		int counter;
+		switch (mode) {
+		case ECR_PPF: /* Parallel Port FIFO mode */
+		case ECR_ECP: /* ECP Parallel Port mode */
+			/* Busy wait for 200us */
+			for (counter = 0; counter < 40; counter++) {
+				if (inb (ECONTROL (p)) & 0x01)
+					break;
+				if (signal_pending (current)) break;
+				udelay (5);
+			}
+
+			/* Poll slowly. */
+			while (!(inb (ECONTROL (p)) & 0x01)) {
+				if (time_after_eq (jiffies, expire))
+					/* The FIFO is stuck. */
+					return -EBUSY;
+				current->state = TASK_INTERRUPTIBLE;
+				schedule_timeout ((HZ + 99) / 100);
+				if (signal_pending (current))
+					break;
+			}
+		}
+	}
+
+	/* Set the mode. */
+	oecr &= ~(7 << 5);
+	oecr |= m << 5;
+	outb (oecr, ecr);
+	return 0;
+}
+
+/* Find FIFO lossage; FIFO is reset */
+static int get_fifo_residue (struct parport *p)
+{
+	int residue;
+	int cnfga;
+	const struct parport_pc_private *priv = p->physport->private_data;
+
+	/* Prevent further data transfer. */
+	parport_frob_control (p,
+			      PARPORT_CONTROL_STROBE,
+			      PARPORT_CONTROL_STROBE);
+
+	/* Adjust for the contents of the FIFO. */
+	for (residue = priv->fifo_depth; ; residue--) {
+		if (inb (ECONTROL (p)) & 0x2)
+				/* Full up. */
+			break;
+
+		outb (0, FIFO (p));
+	}
+
+	printk (KERN_DEBUG "%s: %d PWords were left in FIFO\n", p->name,
+		residue);
+
+	/* Reset the FIFO. */
+	frob_econtrol (p, 0xe0, 0x20);
+	parport_frob_control (p, PARPORT_CONTROL_STROBE, 0);
+
+	/* Now change to config mode and clean up. FIXME */
+	frob_econtrol (p, 0xe0, 0xe0);
+	cnfga = inb (CONFIGA (p));
+	printk (KERN_DEBUG "%s: cnfgA contains 0x%02x\n", p->name, cnfga);
+
+	if (!(cnfga & (1<<2))) {
+		printk (KERN_DEBUG "%s: Accounting for extra byte\n", p->name);
+		residue++;
+	}
+
+	/* Don't care about partial PWords until support is added for
+	 * PWord != 1 byte. */
+
+	/* Back to PS2 mode. */
+	frob_econtrol (p, 0xe0, 0x20);
+
+	return residue;
+}
+
+#endif /* IEEE 1284 support */
+
+/*
+ * Clear TIMEOUT BIT in EPP MODE
+ *
+ * This is also used in SPP detection.
+ */
+static int clear_epp_timeout(struct parport *pb)
+{
+	unsigned char r;
+
+	if (!(parport_pc_read_status(pb) & 0x01))
+		return 1;
+
+	/* To clear timeout some chips require double read */
+	parport_pc_read_status(pb);
+	r = parport_pc_read_status(pb);
+	outb (r | 0x01, STATUS (pb)); /* Some reset by writing 1 */
+	outb (r & 0xfe, STATUS (pb)); /* Others by writing 0 */
+	r = parport_pc_read_status(pb);
+
+	return !(r & 0x01);
+}
+
+/*
+ * Access functions.
+ *
+ * These aren't static because they may be used by the parport_xxx_yyy
+ * macros.  extern __inline__ versions of several of these are in
+ * parport_pc.h.
+ */
+
+static void parport_pc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	parport_generic_irq(irq, (struct parport *) dev_id, regs);
+}
+
+void parport_pc_write_data(struct parport *p, unsigned char d)
+{
+	outb (d, DATA (p));
+}
+
+unsigned char parport_pc_read_data(struct parport *p)
+{
+	return inb (DATA (p));
+}
+
+unsigned char __frob_control (struct parport *p, unsigned char mask,
+			      unsigned char val)
+{
+	struct parport_pc_private *priv = p->physport->private_data;
+	unsigned char ctr = priv->ctr;
+	ctr = (ctr & ~mask) ^ val;
+	ctr &= priv->ctr_writable; /* only write writable bits. */
+	outb (ctr, CONTROL (p));
+	return priv->ctr = ctr; /* update soft copy */
+}
+
+void parport_pc_write_control(struct parport *p, unsigned char d)
+{
+	const unsigned char wm = (PARPORT_CONTROL_STROBE |
+				  PARPORT_CONTROL_AUTOFD |
+				  PARPORT_CONTROL_INIT |
+				  PARPORT_CONTROL_SELECT);
+
+	/* Take this out when drivers have adapted to the newer interface. */
+	if (d & 0x20) {
+			printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n",
+					p->name, p->cad->name);
+			parport_pc_data_reverse (p);
+	}
+
+	__frob_control (p, wm, d & wm);
+}
+
+unsigned char parport_pc_read_control(struct parport *p)
+{
+	const struct parport_pc_private *priv = p->physport->private_data;
+	return priv->ctr; /* Use soft copy */
+}
+
+unsigned char parport_pc_frob_control (struct parport *p, unsigned char mask,
+				       unsigned char val)
+{
+	const unsigned char wm = (PARPORT_CONTROL_STROBE |
+				  PARPORT_CONTROL_AUTOFD |
+				  PARPORT_CONTROL_INIT |
+				  PARPORT_CONTROL_SELECT);
+
+	/* Take this out when drivers have adapted to the newer interface. */
+	if (mask & 0x20) {
+			printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n",
+					p->name, p->cad->name);
+			parport_pc_data_reverse (p);
+	}
+
+	/* Restrict mask and val to control lines. */
+	mask &= wm;
+	val &= wm;
+
+	return __frob_control (p, mask, val);
+}
+
+unsigned char parport_pc_read_status(struct parport *p)
+{
+	return inb (STATUS (p));
+}
+
+void parport_pc_disable_irq(struct parport *p)
+{
+	__frob_control (p, 0x10, 0);
+}
+
+void parport_pc_enable_irq(struct parport *p)
+{
+	__frob_control (p, 0x10, 0x10);
+}
+
+void parport_pc_data_forward (struct parport *p)
+{
+	__frob_control (p, 0x20, 0);
+}
+
+void parport_pc_data_reverse (struct parport *p)
+{
+	__frob_control (p, 0x20, 0x20);
+}
+
+void parport_pc_init_state(struct pardevice *dev, struct parport_state *s)
+{
+	s->u.pc.ctr = 0xc | (dev->irq_func ? 0x10 : 0x0);
+	s->u.pc.ecr = 0x24;
+}
+
+void parport_pc_save_state(struct parport *p, struct parport_state *s)
+{
+	const struct parport_pc_private *priv = p->physport->private_data;
+	s->u.pc.ctr = inb (CONTROL (p));
+	if (priv->ecr)
+		s->u.pc.ecr = inb (ECONTROL (p));
+}
+
+void parport_pc_restore_state(struct parport *p, struct parport_state *s)
+{
+	const struct parport_pc_private *priv = p->physport->private_data;
+	outb (s->u.pc.ctr, CONTROL (p));
+	if (priv->ecr)
+		outb (s->u.pc.ecr, ECONTROL (p));
+}
+
+#ifdef CONFIG_PARPORT_1284
+static size_t parport_pc_epp_read_data (struct parport *port, void *buf,
+					size_t length, int flags)
+{
+	size_t got = 0;
+	for (; got < length; got++) {
+		*((char*)buf)++ = inb (EPPDATA(port));
+		if (inb (STATUS(port)) & 0x01) {
+			clear_epp_timeout (port);
+			break;
+		}
+	}
+
+	return got;
+}
+
+static size_t parport_pc_epp_write_data (struct parport *port, const void *buf,
+					 size_t length, int flags)
+{
+	size_t written = 0;
+	for (; written < length; written++) {
+		outb (*((char*)buf)++, EPPDATA(port));
+		if (inb (STATUS(port)) & 0x01) {
+			clear_epp_timeout (port);
+			break;
+		}
+	}
+
+	return written;
+}
+
+static size_t parport_pc_epp_read_addr (struct parport *port, void *buf,
+					size_t length, int flags)
+{
+	size_t got = 0;
+	for (; got < length; got++) {
+		*((char*)buf)++ = inb (EPPADDR (port));
+		if (inb (STATUS (port)) & 0x01) {
+			clear_epp_timeout (port);
+			break;
+		}
+	}
+
+	return got;
+}
+
+static size_t parport_pc_epp_write_addr (struct parport *port,
+					 const void *buf, size_t length,
+					 int flags)
+{
+	size_t written = 0;
+	for (; written < length; written++) {
+		outb (*((char*)buf)++, EPPADDR (port));
+		if (inb (STATUS (port)) & 0x01) {
+			clear_epp_timeout (port);
+			break;
+		}
+	}
+
+	return written;
+}
+
+static size_t parport_pc_ecpepp_read_data (struct parport *port, void *buf,
+					   size_t length, int flags)
+{
+	size_t got;
+
+	frob_econtrol (port, 0xe0, ECR_EPP << 5);
+	got = parport_pc_epp_read_data (port, buf, length, flags);
+	frob_econtrol (port, 0xe0, ECR_PS2 << 5);
+
+	return got;
+}
+
+static size_t parport_pc_ecpepp_write_data (struct parport *port,
+					    const void *buf, size_t length,
+					    int flags)
+{
+	size_t written;
+
+	frob_econtrol (port, 0xe0, ECR_EPP << 5);
+	written = parport_pc_epp_write_data (port, buf, length, flags);
+	frob_econtrol (port, 0xe0, ECR_PS2 << 5);
+
+	return written;
+}
+
+static size_t parport_pc_ecpepp_read_addr (struct parport *port, void *buf,
+					   size_t length, int flags)
+{
+	size_t got;
+
+	frob_econtrol (port, 0xe0, ECR_EPP << 5);
+	got = parport_pc_epp_read_addr (port, buf, length, flags);
+	frob_econtrol (port, 0xe0, ECR_PS2 << 5);
+
+	return got;
+}
+
+static size_t parport_pc_ecpepp_write_addr (struct parport *port,
+					    const void *buf, size_t length,
+					    int flags)
+{
+	size_t written;
+
+	frob_econtrol (port, 0xe0, ECR_EPP << 5);
+	written = parport_pc_epp_write_addr (port, buf, length, flags);
+	frob_econtrol (port, 0xe0, ECR_PS2 << 5);
+
+	return written;
+}
+#endif /* IEEE 1284 support */
+
+#ifdef CONFIG_PARPORT_PC_FIFO
+static size_t parport_pc_fifo_write_block_pio (struct parport *port,
+					       const void *buf, size_t length)
+{
+	int ret = 0;
+	const unsigned char *bufp = buf;
+	size_t left = length;
+	long expire = jiffies + port->physport->cad->timeout;
+	const int fifo = FIFO (port);
+	int poll_for = 8; /* 80 usecs */
+	const struct parport_pc_private *priv = port->physport->private_data;
+	const int fifo_depth = priv->fifo_depth;
+
+	port = port->physport;
+
+	/* We don't want to be interrupted every character. */
+	parport_pc_disable_irq (port);
+	frob_econtrol (port, (1<<4), (1<<4)); /* nErrIntrEn */
+
+	/* Forward mode. */
+	parport_pc_data_forward (port);
+
+	while (left) {
+		unsigned char byte;
+		unsigned char ecrval = inb (ECONTROL (port));
+		int i = 0;
+
+		if (current->need_resched && time_before (jiffies, expire))
+			/* Can't yield the port. */
+			schedule ();
+
+		/* Anyone else waiting for the port? */
+		if (port->waithead) {
+			printk (KERN_DEBUG "Somebody wants the port\n");
+			break;
+		}
+
+		if (ecrval & 0x02) {
+			/* FIFO is full. Wait for interrupt. */
+
+			/* Clear serviceIntr */
+			outb (ecrval & ~(1<<2), ECONTROL (port));
+		false_alarm:
+			ret = parport_wait_event (port, HZ);
+			if (ret < 0) break;
+			ret = 0;
+			if (!time_before (jiffies, expire)) {
+				/* Timed out. */
+				printk (KERN_DEBUG "Timed out\n");
+				break;
+			}
+			ecrval = inb (ECONTROL (port));
+			if (!(ecrval & (1<<2))) {
+				if (current->need_resched &&
+				    time_before (jiffies, expire))
+					schedule ();
+
+				goto false_alarm;
+			}
+
+			continue;
+		}
+
+		/* Can't fail now. */
+		expire = jiffies + port->cad->timeout;
+
+	poll:
+		if (signal_pending (current))
+			break;
+
+		if (ecrval & 0x01) {
+			/* FIFO is empty. Blast it full. */
+			const int n = left < fifo_depth ? left : fifo_depth;
+			outsb (fifo, bufp, n);
+			bufp += n;
+			left -= n;
+
+			/* Adjust the poll time. */
+			if (i < (poll_for - 2)) poll_for--;
+			continue;
+		} else if (i++ < poll_for) {
+			udelay (10);
+			ecrval = inb (ECONTROL (port));
+			goto poll;
+		}
+
+		/* Half-full (call me an optimist) */
+		byte = *bufp++;
+		outb (byte, fifo);
+		left--;
+        }
+
+	return length - left;
+}
+
+static size_t parport_pc_fifo_write_block_dma (struct parport *port,
+					       const void *buf, size_t length)
+{
+	int ret = 0;
+	unsigned long dmaflag;
+	size_t left  = length;
+	const struct parport_pc_private *priv = port->physport->private_data;
+
+	port = port->physport;
+
+	/* We don't want to be interrupted every character. */
+	parport_pc_disable_irq (port);
+	frob_econtrol (port, (1<<4), (1<<4)); /* nErrIntrEn */
+
+	/* Forward mode. */
+	parport_pc_data_forward (port);
+
+	while (left) {
+		long expire = jiffies + port->physport->cad->timeout;
+
+		size_t count = left;
+
+		if (count > PAGE_SIZE)
+			count = PAGE_SIZE;
+
+		memcpy(priv->dma_buf, buf, count);
+
+		dmaflag = claim_dma_lock();
+		disable_dma(port->dma);
+		clear_dma_ff(port->dma);
+		set_dma_mode(port->dma, DMA_MODE_WRITE);
+		set_dma_addr(port->dma, virt_to_bus((volatile char *) priv->dma_buf));
+		set_dma_count(port->dma, count);
+
+		/* Set DMA mode */
+		frob_econtrol (port, 1<<3, 1<<3);
+
+		/* Clear serviceIntr */
+		frob_econtrol (port, 1<<2, 0);
+
+		enable_dma(port->dma);
+		release_dma_lock(dmaflag);
+
+		/* assume DMA will be successful */
+		left -= count;
+		buf  += count;
+
+		/* Wait for interrupt. */
+	false_alarm:
+		ret = parport_wait_event (port, HZ);
+		if (ret < 0) break;
+		ret = 0;
+		if (!time_before (jiffies, expire)) {
+			/* Timed out. */
+			printk (KERN_DEBUG "Timed out\n");
+			break;
+		}
+		/* Is serviceIntr set? */
+		if (!(inb (ECONTROL (port)) & (1<<2))) {
+			if (current->need_resched)
+				schedule ();
+
+			goto false_alarm;
+		}
+
+		dmaflag = claim_dma_lock();
+		disable_dma(port->dma);
+		clear_dma_ff(port->dma);
+		count = get_dma_residue(port->dma);
+		release_dma_lock(dmaflag);
+
+		if (current->need_resched)
+			/* Can't yield the port. */
+			schedule ();
+
+		/* Anyone else waiting for the port? */
+		if (port->waithead) {
+			printk (KERN_DEBUG "Somebody wants the port\n");
+			break;
+		}
+
+		/* update for possible DMA residue ! */
+		buf  -= count;
+		left += count;
+	}
+
+	/* Maybe got here through break, so adjust for DMA residue! */
+	dmaflag = claim_dma_lock();
+	disable_dma(port->dma);
+	clear_dma_ff(port->dma);
+	left += get_dma_residue(port->dma);
+	release_dma_lock(dmaflag);
+
+	/* Turn off DMA mode */
+	frob_econtrol (port, 1<<3, 0);
+
+	return length - left;
+}
+
+/* Parallel Port FIFO mode (ECP chipsets) */
+size_t parport_pc_compat_write_block_pio (struct parport *port,
+					  const void *buf, size_t length,
+					  int flags)
+{
+	size_t written;
+
+	/* Special case: a timeout of zero means we cannot call schedule(). */
+	if (!port->physport->cad->timeout)
+		return parport_ieee1284_write_compat (port, buf,
+						      length, flags);
+
+	/* Set up parallel port FIFO mode.*/
+	change_mode (port, ECR_PPF); /* Parallel port FIFO */
+	parport_pc_data_forward (port);
+	port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
+
+	/* Write the data to the FIFO. */
+	if (port->dma != PARPORT_DMA_NONE)
+		written = parport_pc_fifo_write_block_dma (port, buf, length);
+	else
+		written = parport_pc_fifo_write_block_pio (port, buf, length);
+
+	/* Finish up. */
+	if (change_mode (port, ECR_PS2) == -EBUSY) {
+		const struct parport_pc_private *priv = 
+			port->physport->private_data;
+
+		printk (KERN_DEBUG "%s: FIFO is stuck\n", port->name);
+
+		/* Prevent further data transfer. */
+		parport_frob_control (port,
+				      PARPORT_CONTROL_STROBE,
+				      PARPORT_CONTROL_STROBE);
+
+		/* Adjust for the contents of the FIFO. */
+		for (written -= priv->fifo_depth; ; written++) {
+			if (inb (ECONTROL (port)) & 0x2)
+				/* Full up. */
+				break;
+
+			outb (0, FIFO (port));
+		}
+
+		/* Reset the FIFO. */
+		frob_econtrol (port, 0xe0, 0);
+
+		/* De-assert strobe. */
+		parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
+	}
+
+	parport_wait_peripheral (port,
+				 PARPORT_STATUS_BUSY,
+				 PARPORT_STATUS_BUSY);
+	port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+
+	return written;
+}
+
+/* ECP */
+#ifdef CONFIG_PARPORT_1284
+size_t parport_pc_ecp_write_block_pio (struct parport *port,
+				       const void *buf, size_t length,
+				       int flags)
+{
+	size_t written;
+
+	/* Special case: a timeout of zero means we cannot call schedule(). */
+	if (!port->physport->cad->timeout)
+		return parport_ieee1284_ecp_write_data (port, buf,
+							length, flags);
+
+	/* Switch to forward mode if necessary. */
+	if (port->physport->ieee1284.phase != IEEE1284_PH_FWD_IDLE) {
+		/* Event 47: Set nInit high. */
+		parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
+
+		/* Event 40: PError goes high. */
+		parport_wait_peripheral (port,
+					 PARPORT_STATUS_PAPEROUT,
+					 PARPORT_STATUS_PAPEROUT);
+	}
+
+	/* Set up ECP parallel port mode.*/
+	change_mode (port, ECR_ECP); /* ECP FIFO */
+	parport_pc_data_forward (port);
+	port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
+
+	/* Write the data to the FIFO. */
+	if (port->dma != PARPORT_DMA_NONE)
+		written = parport_pc_fifo_write_block_dma (port, buf, length);
+	else
+		written = parport_pc_fifo_write_block_pio (port, buf, length);
+
+	/* Finish up. */
+	if (change_mode (port, ECR_PS2) == -EBUSY) {
+		const struct parport_pc_private *priv =
+			port->physport->private_data;
+
+		printk (KERN_DEBUG "%s: FIFO is stuck\n", port->name);
+
+		/* Prevent further data transfer. */
+		parport_frob_control (port,
+				      PARPORT_CONTROL_STROBE,
+				      PARPORT_CONTROL_STROBE);
+
+		/* Adjust for the contents of the FIFO. */
+		for (written -= priv->fifo_depth; ; written++) {
+			if (inb (ECONTROL (port)) & 0x2)
+				/* Full up. */
+				break;
+
+			outb (0, FIFO (port));
+		}
+
+		/* Reset the FIFO. */
+		frob_econtrol (port, 0xe0, 0);
+		parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
+
+		/* Host transfer recovery. */
+		parport_frob_control (port,
+				      PARPORT_CONTROL_INIT,
+				      PARPORT_CONTROL_INIT);
+		parport_pc_data_reverse (port);
+		parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0);
+		parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
+		parport_wait_peripheral (port,
+					 PARPORT_STATUS_PAPEROUT,
+					 PARPORT_STATUS_PAPEROUT);
+	}
+
+	parport_wait_peripheral (port,
+				 PARPORT_STATUS_BUSY, 
+				 PARPORT_STATUS_BUSY);
+	port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+
+	return written;
+}
+
+size_t parport_pc_ecp_read_block_pio (struct parport *port,
+				      void *buf, size_t length, int flags)
+{
+	size_t left = length;
+	size_t fifofull;
+	const int fifo = FIFO(port);
+	const struct parport_pc_private *priv = port->physport->private_data;
+	const int fifo_depth = priv->fifo_depth;
+	char *bufp = buf;
+
+	port = port->physport;
+
+	/* Special case: a timeout of zero means we cannot call schedule(). */
+	if (!port->cad->timeout)
+		return parport_ieee1284_ecp_read_data (port, buf,
+						       length, flags);
+
+	fifofull = fifo_depth;
+	if (port->ieee1284.mode == IEEE1284_MODE_ECPRLE)
+		/* If the peripheral is allowed to send RLE compressed
+		 * data, it is possible for a byte to expand to 128
+		 * bytes in the FIFO. */
+		fifofull = 128;
+
+	/* If the caller wants less than a full FIFO's worth of data,
+	 * go through software emulation.  Otherwise we may have to through
+	 * away data. */
+	if (length < fifofull)
+		return parport_ieee1284_ecp_read_data (port, buf,
+						       length, flags);
+
+	/* Switch to reverse mode if necessary. */
+	if (port->ieee1284.phase != IEEE1284_PH_REV_IDLE) {
+		/* Event 38: Set nAutoFd low */
+		parport_frob_control (port,
+				      PARPORT_CONTROL_AUTOFD,
+				      PARPORT_CONTROL_AUTOFD);
+		parport_pc_data_reverse (port);
+		udelay (5);
+
+		/* Event 39: Set nInit low to initiate bus reversal */
+		parport_frob_control (port,
+				      PARPORT_CONTROL_INIT,
+				      PARPORT_CONTROL_INIT);
+
+		/* Event 40: PError goes low */
+		parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0);
+	}
+
+	/* Set up ECP parallel port mode.*/
+	change_mode (port, ECR_ECP); /* ECP FIFO */
+	parport_pc_data_reverse (port);
+	port->ieee1284.phase = IEEE1284_PH_REV_DATA;
+
+	/* Do the transfer. */
+	while (left > fifofull) {
+		int ret;
+		long int expire = jiffies + port->cad->timeout;
+		unsigned char ecrval = inb (ECONTROL (port));
+
+		if (current->need_resched && time_before (jiffies, expire))
+			/* Can't yield the port. */
+			schedule ();
+
+		/* At this point, the FIFO may already be full.
+		 * Ideally, we'd be able to tell the port to hold on
+		 * for a second while we empty the FIFO, and we'd be
+		 * able to ensure that no data is lost.  I'm not sure
+		 * that's the case. :-(  It might be that you can play
+		 * games with STB, as in the forward case; someone should
+		 * look at a datasheet. */
+
+		if (ecrval & 0x01) {
+			/* FIFO is empty. Wait for interrupt. */
+
+			/* Anyone else waiting for the port? */
+			if (port->waithead) {
+				printk (KERN_DEBUG
+					"Somebody wants the port\n");
+				break;
+			}
+
+			/* Clear serviceIntr */
+			outb (ecrval & ~(1<<2), ECONTROL (port));
+		false_alarm:
+			ret = parport_wait_event (port, HZ);
+			if (ret < 0) break;
+			ret = 0;
+			if (!time_before (jiffies, expire)) {
+				/* Timed out. */
+				printk (KERN_DEBUG "Timed out\n");
+				break;
+			}
+			ecrval = inb (ECONTROL (port));
+			if (!(ecrval & (1<<2))) {
+				if (current->need_resched &&
+				    time_before (jiffies, expire))
+					schedule ();
+
+				goto false_alarm;
+			}
+
+			continue;
+		}
+
+		if (ecrval & 0x02) {
+			/* FIFO is full. */
+			insb (fifo, bufp, fifo_depth);
+			bufp += fifo_depth;
+			left -= fifo_depth;
+			continue;
+		}
+
+		*bufp++ = inb (fifo);
+		left--;
+	}
+
+	/* Finish up. */
+	if (change_mode (port, ECR_PS2) == -EBUSY) {
+		int lost = get_fifo_residue (port);
+		printk (KERN_DEBUG "%s: DATA LOSS (%d bytes)!\n", port->name,
+			lost);
+	}
+
+	port->ieee1284.phase = IEEE1284_PH_REV_IDLE;
+
+	return length - left;
+}
+
+#endif /* IEEE 1284 support */
+
+#endif /* Allowed to use FIFO/DMA */
+
+void parport_pc_inc_use_count(void)
+{
+#ifdef MODULE
+	MOD_INC_USE_COUNT;
+#endif
+}
+
+void parport_pc_dec_use_count(void)
+{
+#ifdef MODULE
+	MOD_DEC_USE_COUNT;
+#endif
+}
+
+struct parport_operations parport_pc_ops = 
+{
+	parport_pc_write_data,
+	parport_pc_read_data,
+
+	parport_pc_write_control,
+	parport_pc_read_control,
+	parport_pc_frob_control,
+
+	parport_pc_read_status,
+
+	parport_pc_enable_irq,
+	parport_pc_disable_irq,
+
+	parport_pc_data_forward,
+	parport_pc_data_reverse,
+
+	parport_pc_interrupt,
+	parport_pc_init_state,
+	parport_pc_save_state,
+	parport_pc_restore_state,
+
+	parport_pc_inc_use_count,
+	parport_pc_dec_use_count,
+
+	parport_ieee1284_epp_write_data,
+	parport_ieee1284_epp_read_data,
+	parport_ieee1284_epp_write_addr,
+	parport_ieee1284_epp_read_addr,
+
+	parport_ieee1284_ecp_write_data,
+	parport_ieee1284_ecp_read_data,
+	parport_ieee1284_ecp_write_addr,
+
+	parport_ieee1284_write_compat,
+	parport_ieee1284_read_nibble,
+	parport_ieee1284_read_byte,
+};
+
+/* --- Mode detection ------------------------------------- */
+
+/*
+ * Checks for port existence, all ports support SPP MODE
+ */
+static int __init parport_SPP_supported(struct parport *pb)
+{
+	unsigned char r, w;
+
+	/*
+	 * first clear an eventually pending EPP timeout 
+	 * I (sailer@ife.ee.ethz.ch) have an SMSC chipset
+	 * that does not even respond to SPP cycles if an EPP
+	 * timeout is pending
+	 */
+	clear_epp_timeout(pb);
+
+	/* Do a simple read-write test to make sure the port exists. */
+	w = 0xc;
+	outb (w, CONTROL (pb));
+
+	/* Is there a control register that we can read from?  Some
+	 * ports don't allow reads, so read_control just returns a
+	 * software copy. Some ports _do_ allow reads, so bypass the
+	 * software copy here.  In addition, some bits aren't
+	 * writable. */
+	r = inb (CONTROL (pb));
+	if ((r & 0xf) == w) {
+		w = 0xe;
+		outb (w, CONTROL (pb));
+		r = inb (CONTROL (pb));
+		outb (0xc, CONTROL (pb));
+		if ((r & 0xf) == w)
+			return PARPORT_MODE_PCSPP;
+	}
+
+	if (user_specified)
+		/* That didn't work, but the user thinks there's a
+		 * port here. */
+		printk (KERN_DEBUG "0x%lx: CTR: wrote 0x%02x, read 0x%02x\n",
+			pb->base, w, r);
+
+	/* Try the data register.  The data lines aren't tri-stated at
+	 * this stage, so we expect back what we wrote. */
+	w = 0xaa;
+	parport_pc_write_data (pb, w);
+	r = parport_pc_read_data (pb);
+	if (r == w) {
+		w = 0x55;
+		parport_pc_write_data (pb, w);
+		r = parport_pc_read_data (pb);
+		if (r == w)
+			return PARPORT_MODE_PCSPP;
+	}
+
+	if (user_specified)
+		/* Didn't work, but the user is convinced this is the
+		 * place. */
+		printk (KERN_DEBUG "0x%lx: DATA: wrote 0x%02x, read 0x%02x\n",
+			pb->base, w, r);
+
+	/* It's possible that we can't read the control register or
+	 * the data register.  In that case just believe the user. */
+	if (user_specified)
+		return PARPORT_MODE_PCSPP;
+
+	return 0;
+}
+
+/* Check for ECR
+ *
+ * Old style XT ports alias io ports every 0x400, hence accessing ECR
+ * on these cards actually accesses the CTR.
+ *
+ * Modern cards don't do this but reading from ECR will return 0xff
+ * regardless of what is written here if the card does NOT support
+ * ECP.
+ *
+ * We first check to see if ECR is the same as CTR.  If not, the low
+ * two bits of ECR aren't writable, so we check by writing ECR and
+ * reading it back to see if it's what we expect.
+ */
+static int __init parport_ECR_present(struct parport *pb)
+{
+	struct parport_pc_private *priv = pb->private_data;
+	unsigned char r = 0xc;
+
+	priv->ecr = 0;
+	outb (r, CONTROL (pb));
+	if ((inb (ECONTROL (pb)) & 0x3) == (r & 0x3)) {
+		outb (r ^ 0x2, CONTROL (pb)); /* Toggle bit 1 */
+
+		r = inb (CONTROL (pb));
+		if ((inb (ECONTROL (pb)) & 0x2) == (r & 0x2))
+			goto no_reg; /* Sure that no ECR register exists */
+	}
+	
+	if ((inb (ECONTROL (pb)) & 0x3 ) != 0x1)
+		goto no_reg;
+
+	outb (0x34, ECONTROL (pb));
+	if (inb (ECONTROL (pb)) != 0x35)
+		goto no_reg;
+
+	priv->ecr = 1;
+	outb (0xc, CONTROL (pb));
+	
+	/* Go to mode 000 */
+	frob_econtrol (pb, 0xe0, ECR_SPP << 5);
+
+	return 1;
+
+ no_reg:
+	outb (0xc, CONTROL (pb));
+	return 0; 
+}
+
+#ifdef CONFIG_PARPORT_1284
+/* Detect PS/2 support.
+ *
+ * Bit 5 (0x20) sets the PS/2 data direction; setting this high
+ * allows us to read data from the data lines.  In theory we would get back
+ * 0xff but any peripheral attached to the port may drag some or all of the
+ * lines down to zero.  So if we get back anything that isn't the contents
+ * of the data register we deem PS/2 support to be present. 
+ *
+ * Some SPP ports have "half PS/2" ability - you can't turn off the line
+ * drivers, but an external peripheral with sufficiently beefy drivers of
+ * its own can overpower them and assert its own levels onto the bus, from
+ * where they can then be read back as normal.  Ports with this property
+ * and the right type of device attached are likely to fail the SPP test,
+ * (as they will appear to have stuck bits) and so the fact that they might
+ * be misdetected here is rather academic. 
+ */
+
+static int __init parport_PS2_supported(struct parport *pb)
+{
+	int ok = 0;
+  
+	clear_epp_timeout(pb);
+
+	/* try to tri-state the buffer */
+	parport_pc_data_reverse (pb);
+	
+	parport_pc_write_data(pb, 0x55);
+	if (parport_pc_read_data(pb) != 0x55) ok++;
+
+	parport_pc_write_data(pb, 0xaa);
+	if (parport_pc_read_data(pb) != 0xaa) ok++;
+
+	/* cancel input mode */
+	parport_pc_data_forward (pb);
+
+	if (ok)
+		pb->modes |= PARPORT_MODE_TRISTATE;
+	else {
+		struct parport_pc_private *priv = pb->private_data;
+		priv->ctr_writable &= ~0x20;
+	}
+
+	return ok;
+}
+
+static int __init parport_ECP_supported(struct parport *pb)
+{
+	int i;
+	int config;
+	int pword;
+	struct parport_pc_private *priv = pb->private_data;
+
+	/* If there is no ECR, we have no hope of supporting ECP. */
+	if (!priv->ecr)
+		return 0;
+
+	/* Find out FIFO depth */
+	outb (ECR_SPP << 5, ECONTROL (pb)); /* Reset FIFO */
+	outb (ECR_TST << 5, ECONTROL (pb)); /* TEST FIFO */
+	for (i=0; i < 1024 && !(inb (ECONTROL (pb)) & 0x02); i++)
+		outb (0xaa, FIFO (pb));
+
+	/*
+	 * Using LGS chipset it uses ECR register, but
+	 * it doesn't support ECP or FIFO MODE
+	 */
+	if (i == 1024) {
+		outb (ECR_SPP << 5, ECONTROL (pb));
+		return 0;
+	}
+
+	priv->fifo_depth = i;
+	printk (KERN_INFO "0x%lx: FIFO is %d bytes\n", pb->base, i);
+
+	/* Find out writeIntrThreshold */
+	frob_econtrol (pb, 1<<2, 1<<2);
+	frob_econtrol (pb, 1<<2, 0);
+	for (i = 1; i <= priv->fifo_depth; i++) {
+		inb (FIFO (pb));
+		udelay (50);
+		if (inb (ECONTROL (pb)) & (1<<2))
+			break;
+	}
+
+	if (i <= priv->fifo_depth)
+		printk (KERN_INFO "0x%lx: writeIntrThreshold is %d\n",
+			pb->base, i);
+	else
+		/* Number of bytes we know we can write if we get an
+                   interrupt. */
+		i = 0;
+
+	priv->writeIntrThreshold = i;
+
+	/* Find out readIntrThreshold */
+	frob_econtrol (pb, 0xe0, ECR_PS2 << 5); /* Reset FIFO */
+	parport_pc_data_reverse (pb);
+	frob_econtrol (pb, 0xe0, ECR_TST << 5); /* Test FIFO */
+	frob_econtrol (pb, 1<<2, 1<<2);
+	frob_econtrol (pb, 1<<2, 0);
+	for (i = 1; i <= priv->fifo_depth; i++) {
+		outb (0xaa, FIFO (pb));
+		if (inb (ECONTROL (pb)) & (1<<2))
+			break;
+	}
+
+	if (i <= priv->fifo_depth)
+		printk (KERN_INFO "0x%lx: readIntrThreshold is %d\n",
+			pb->base, i);
+	else
+		/* Number of bytes we can read if we get an interrupt. */
+		i = 0;
+
+	priv->readIntrThreshold = i;
+
+	outb (ECR_SPP << 5, ECONTROL (pb)); /* Reset FIFO */
+	outb (0xf4, ECONTROL (pb)); /* Configuration mode */
+	config = inb (FIFO (pb));
+	pword = (config >> 4) & 0x7;
+	switch (pword) {
+	case 0:
+		pword = 2;
+		printk (KERN_WARNING "0x%lx: Unsupported pword size!\n",
+			pb->base);
+		break;
+	case 2:
+		pword = 4;
+		printk (KERN_WARNING "0x%lx: Unsupported pword size!\n",
+			pb->base);
+		break;
+	default:
+		printk (KERN_WARNING "0x%lx: Unknown implementation ID\n",
+			pb->base);
+		/* Assume 1 */
+	case 1:
+		pword = 1;
+	}
+	priv->pword = pword;
+	printk (KERN_DEBUG "0x%lx: PWord is %d bits\n", pb->base, 8 * pword);
+
+	config = inb (CONFIGB (pb));
+	printk (KERN_DEBUG "0x%lx: Interrupts are ISA-%s\n", pb->base,
+		config & 0x80 ? "Level" : "Pulses");
+
+	if (!(config & 0x40)) {
+		printk (KERN_WARNING "0x%lx: IRQ conflict!\n", pb->base);
+		pb->irq = PARPORT_IRQ_NONE;
+	}
+
+	/* Go back to mode 000 */
+	frob_econtrol (pb, 0xe0, ECR_SPP << 5);
+	pb->modes |= PARPORT_MODE_ECP;
+
+	return 1;
+}
+
+static int __init parport_ECPPS2_supported(struct parport *pb)
+{
+	const struct parport_pc_private *priv = pb->private_data;
+	int result;
+	unsigned char oecr;
+
+	if (!priv->ecr)
+		return 0;
+
+	oecr = inb (ECONTROL (pb));
+	outb (ECR_PS2 << 5, ECONTROL (pb));
+	
+	result = parport_PS2_supported(pb);
+
+	outb (oecr, ECONTROL (pb));
+	return result;
+}
+
+/* EPP mode detection  */
+
+static int __init parport_EPP_supported(struct parport *pb)
+{
+	const struct parport_pc_private *priv = pb->private_data;
+
+	/*
+	 * Theory:
+	 *	Bit 0 of STR is the EPP timeout bit, this bit is 0
+	 *	when EPP is possible and is set high when an EPP timeout
+	 *	occurs (EPP uses the HALT line to stop the CPU while it does
+	 *	the byte transfer, an EPP timeout occurs if the attached
+	 *	device fails to respond after 10 micro seconds).
+	 *
+	 *	This bit is cleared by either reading it (National Semi)
+	 *	or writing a 1 to the bit (SMC, UMC, WinBond), others ???
+	 *	This bit is always high in non EPP modes.
+	 */
+
+	/* If EPP timeout bit clear then EPP available */
+	if (!clear_epp_timeout(pb))
+		return 0;  /* No way to clear timeout */
+
+	/* Check for Intel bug. */
+	if (priv->ecr) {
+		unsigned char i;
+		for (i = 0x00; i < 0x80; i += 0x20) {
+			outb (i, ECONTROL (pb));
+			if (clear_epp_timeout (pb))
+				/* Phony EPP in ECP. */
+				return 0;
+		}
+	}
+
+	pb->modes |= PARPORT_MODE_EPP;
+
+	/* Set up access functions to use EPP hardware. */
+	parport_pc_ops.epp_read_data = parport_pc_epp_read_data;
+	parport_pc_ops.epp_write_data = parport_pc_epp_write_data;
+	parport_pc_ops.epp_read_addr = parport_pc_epp_read_addr;
+	parport_pc_ops.epp_write_addr = parport_pc_epp_write_addr;
+
+	return 1;
+}
+
+static int __init parport_ECPEPP_supported(struct parport *pb)
+{
+	struct parport_pc_private *priv = pb->private_data;
+	int result;
+	unsigned char oecr;
+
+	if (!priv->ecr)
+		return 0;
+
+	oecr = inb (ECONTROL (pb));
+	/* Search for SMC style EPP+ECP mode */
+	outb (0x80, ECONTROL (pb));
+	
+	result = parport_EPP_supported(pb);
+
+	outb (oecr, ECONTROL (pb));
+
+	if (result) {
+		/* Set up access functions to use ECP+EPP hardware. */
+		parport_pc_ops.epp_read_data = parport_pc_ecpepp_read_data;
+		parport_pc_ops.epp_write_data = parport_pc_ecpepp_write_data;
+		parport_pc_ops.epp_read_addr = parport_pc_ecpepp_read_addr;
+		parport_pc_ops.epp_write_addr = parport_pc_ecpepp_write_addr;
+	}
+
+	return result;
+}
+
+#else /* No IEEE 1284 support */
+
+/* Don't bother probing for modes we know we won't use. */
+static int __init parport_PS2_supported(struct parport *pb) { return 0; }
+static int __init parport_ECP_supported(struct parport *pb) { return 0; }
+static int __init parport_EPP_supported(struct parport *pb) { return 0; }
+static int __init parport_ECPEPP_supported(struct parport *pb) { return 0; }
+static int __init parport_ECPPS2_supported(struct parport *pb) { return 0; }
+
+#endif /* No IEEE 1284 support */
+
+/* --- IRQ detection -------------------------------------- */
+
+/* Only if supports ECP mode */
+static int __init programmable_irq_support(struct parport *pb)
+{
+	int irq, intrLine;
+	unsigned char oecr = inb (ECONTROL (pb));
+	static const int lookup[8] = {
+		PARPORT_IRQ_NONE, 7, 9, 10, 11, 14, 15, 5
+	};
+
+	outb (ECR_CNF << 5, ECONTROL (pb)); /* Configuration MODE */
+
+	intrLine = (inb (CONFIGB (pb)) >> 3) & 0x07;
+	irq = lookup[intrLine];
+
+	outb (oecr, ECONTROL (pb));
+	return irq;
+}
+
+static int __init irq_probe_ECP(struct parport *pb)
+{
+	int i;
+	unsigned long irqs;
+
+	sti();
+	irqs = probe_irq_on();
+		
+	outb (ECR_SPP << 5, ECONTROL (pb)); /* Reset FIFO */
+	outb ((ECR_TST << 5) | 0x04, ECONTROL (pb));
+	outb (ECR_TST << 5, ECONTROL (pb));
+
+	/* If Full FIFO sure that writeIntrThreshold is generated */
+	for (i=0; i < 1024 && !(inb (ECONTROL (pb)) & 0x02) ; i++) 
+		outb (0xaa, FIFO (pb));
+		
+	pb->irq = probe_irq_off(irqs);
+	outb (ECR_SPP << 5, ECONTROL (pb));
+
+	if (pb->irq <= 0)
+		pb->irq = PARPORT_IRQ_NONE;
+
+	return pb->irq;
+}
+
+/*
+ * This detection seems that only works in National Semiconductors
+ * This doesn't work in SMC, LGS, and Winbond 
+ */
+static int __init irq_probe_EPP(struct parport *pb)
+{
+#ifndef ADVANCED_DETECT
+	return PARPORT_IRQ_NONE;
+#else
+	int irqs;
+	unsigned char oecr;
+
+	if (pb->modes & PARPORT_MODE_PCECR)
+		oecr = inb (ECONTROL (pb));
+
+	sti();
+	irqs = probe_irq_on();
+
+	if (pb->modes & PARPORT_MODE_PCECR)
+		frob_econtrol (pb, 0x10, 0x10);
+	
+	clear_epp_timeout(pb);
+	parport_pc_frob_control (pb, 0x20, 0x20);
+	parport_pc_frob_control (pb, 0x10, 0x10);
+	clear_epp_timeout(pb);
+
+	/* Device isn't expecting an EPP read
+	 * and generates an IRQ.
+	 */
+	parport_pc_read_epp(pb);
+	udelay(20);
+
+	pb->irq = probe_irq_off (irqs);
+	if (pb->modes & PARPORT_MODE_PCECR)
+		outb (oecr, ECONTROL (pb));
+	parport_pc_write_control(pb, 0xc);
+
+	if (pb->irq <= 0)
+		pb->irq = PARPORT_IRQ_NONE;
+
+	return pb->irq;
+#endif /* Advanced detection */
+}
+
+static int __init irq_probe_SPP(struct parport *pb)
+{
+	/* Don't even try to do this. */
+	return PARPORT_IRQ_NONE;
+}
+
+/* We will attempt to share interrupt requests since other devices
+ * such as sound cards and network cards seem to like using the
+ * printer IRQs.
+ *
+ * When ECP is available we can autoprobe for IRQs.
+ * NOTE: If we can autoprobe it, we can register the IRQ.
+ */
+static int __init parport_irq_probe(struct parport *pb)
+{
+	const struct parport_pc_private *priv = pb->private_data;
+
+	if (priv->ecr) {
+		pb->irq = programmable_irq_support(pb);
+		if (pb->irq != PARPORT_IRQ_NONE)
+			goto out;
+	}
+
+	if (pb->modes & PARPORT_MODE_ECP)
+		pb->irq = irq_probe_ECP(pb);
+
+	if (pb->irq == PARPORT_IRQ_NONE && priv->ecr &&
+	    (pb->modes & PARPORT_MODE_EPP))
+		pb->irq = irq_probe_EPP(pb);
+
+	clear_epp_timeout(pb);
+
+	if (pb->irq == PARPORT_IRQ_NONE && (pb->modes & PARPORT_MODE_EPP))
+		pb->irq = irq_probe_EPP(pb);
+
+	clear_epp_timeout(pb);
+
+	if (pb->irq == PARPORT_IRQ_NONE)
+		pb->irq = irq_probe_SPP(pb);
+
+out:
+	return pb->irq;
+}
+
+/* --- DMA detection -------------------------------------- */
+
+/* Only if supports ECP mode */
+static int __init programmable_dma_support (struct parport *p)
+{
+	unsigned char oecr = inb (ECONTROL (p));
+	int dma;
+
+	frob_econtrol (p, 0xe0, ECR_CNF << 5);
+	
+	dma = inb (CONFIGB(p)) & 0x03;
+	if (!dma)
+		dma = PARPORT_DMA_NONE;
+
+	outb (oecr, ECONTROL (p));
+	return dma;
+}
+
+static int __init parport_dma_probe (struct parport *p)
+{
+	const struct parport_pc_private *priv = p->private_data;
+	if (priv->ecr)
+		p->dma = programmable_dma_support(p);
+
+	return p->dma;
+}
+
+/* --- Initialisation code -------------------------------- */
+
+static int __init probe_one_port(unsigned long int base,
+				 unsigned long int base_hi,
+				 int irq, int dma)
+{
+	struct parport_pc_private *priv;
+	struct parport_operations *ops;
+	struct parport tmp;
+	struct parport *p = &tmp;
+	int probedirq = PARPORT_IRQ_NONE;
+	if (check_region(base, 3)) return 0;
+	priv = kmalloc (sizeof (struct parport_pc_private), GFP_KERNEL);
+	if (!priv) {
+		printk (KERN_DEBUG "parport (0x%lx): no memory!\n", base);
+		return 0;
+	}
+	ops = kmalloc (sizeof (struct parport_operations), GFP_KERNEL);
+	if (!ops) {
+		printk (KERN_DEBUG "parport (0x%lx): no memory for ops!\n",
+			base);
+		kfree (priv);
+		return 0;
+	}
+	memcpy (ops, &parport_pc_ops, sizeof (struct parport_operations));
+	priv->ctr = 0xc;
+	priv->ctr_writable = 0xff;
+	priv->ecr = 0;
+	priv->fifo_depth = 0;
+	priv->dma_buf = 0;
+	p->base = base;
+	p->base_hi = base_hi;
+	p->irq = irq;
+	p->dma = dma;
+	p->modes = PARPORT_MODE_PCSPP;
+	p->ops = ops;
+	p->private_data = priv;
+	p->physport = p;
+	if (base_hi && !check_region(base_hi,3)) {
+		parport_ECR_present(p);
+		parport_ECP_supported(p);
+		parport_ECPPS2_supported(p);
+	}
+	if (base != 0x3bc) {
+		if (!check_region(base+0x3, 5)) {
+			parport_EPP_supported(p);
+			if (!(p->modes & PARPORT_MODE_EPP))
+				parport_ECPEPP_supported(p);
+		}
+	}
+	if (!parport_SPP_supported (p)) {
+		/* No port. */
+		kfree (priv);
+		return 0;
+	}
+
+	parport_PS2_supported (p);
+
+	if (!(p = parport_register_port(base, PARPORT_IRQ_NONE,
+					PARPORT_DMA_NONE, ops))) {
+		kfree (priv);
+		kfree (ops);
+		return 0;
+	}
+
+	p->base_hi = base_hi;
+	p->modes = tmp.modes;
+	p->size = (p->modes & PARPORT_MODE_EPP)?8:3;
+	p->private_data = priv;
+
+	printk(KERN_INFO "%s: PC-style at 0x%lx", p->name, p->base);
+	if (p->base_hi && (p->modes & PARPORT_MODE_ECP))
+		printk(" (0x%lx)", p->base_hi);
+	p->irq = irq;
+	p->dma = dma;
+	if (p->irq == PARPORT_IRQ_AUTO) {
+		p->irq = PARPORT_IRQ_NONE;
+		parport_irq_probe(p);
+	} else if (p->irq == PARPORT_IRQ_PROBEONLY) {
+		p->irq = PARPORT_IRQ_NONE;
+		parport_irq_probe(p);
+		probedirq = p->irq;
+		p->irq = PARPORT_IRQ_NONE;
+	}
+	if (p->irq != PARPORT_IRQ_NONE) {
+		printk(", irq %d", p->irq);
+
+		if (p->dma == PARPORT_DMA_AUTO) {
+			p->dma = PARPORT_DMA_NONE;
+			parport_dma_probe(p);
+		}
+	}
+	if (p->dma == PARPORT_DMA_AUTO)		
+		p->dma = PARPORT_DMA_NONE;
+	if (p->dma != PARPORT_DMA_NONE) 
+		printk(", dma %d", p->dma);
+
+#ifdef CONFIG_PARPORT_PC_FIFO
+	if (priv->fifo_depth > 0 && p->irq != PARPORT_IRQ_NONE) {
+		parport_pc_ops.compat_write_data =
+			parport_pc_compat_write_block_pio;
+#ifdef CONFIG_PARPORT_1284
+		parport_pc_ops.ecp_write_data =
+			parport_pc_ecp_write_block_pio;
+#endif /* IEEE 1284 support */
+		if (p->dma != PARPORT_DMA_NONE)
+			p->modes |= PARPORT_MODE_DMA;
+		printk(", using FIFO");
+	}
+#endif /* Allowed to use FIFO/DMA */
+
+	printk(" [");
+#define printmode(x) {if(p->modes&PARPORT_MODE_##x){printk("%s%s",f?",":"",#x);f++;}}
+	{
+		int f = 0;
+		printmode(PCSPP);
+		printmode(TRISTATE);
+		printmode(COMPAT)
+		printmode(EPP);
+		printmode(ECP);
+		printmode(DMA);
+	}
+#undef printmode
+	printk("]\n");
+	if (probedirq != PARPORT_IRQ_NONE) 
+		printk("%s: irq %d detected\n", p->name, probedirq);
+	parport_proc_register(p);
+
+	request_region (p->base, 3, p->name);
+	if (p->size > 3)
+		request_region (p->base + 3, p->size - 3, p->name);
+	if (p->modes & PARPORT_MODE_ECP)
+		request_region (p->base_hi, 3, p->name);
+
+	if (p->irq != PARPORT_IRQ_NONE) {
+		if (request_irq (p->irq, parport_pc_interrupt,
+				 0, p->name, p)) {
+			printk (KERN_WARNING "%s: irq %d in use, "
+				"resorting to polled operation\n",
+				p->name, p->irq);
+			p->irq = PARPORT_IRQ_NONE;
+			p->dma = PARPORT_DMA_NONE;
+		}
+
+		if (p->dma != PARPORT_DMA_NONE) {
+			if (request_dma (p->dma, p->name)) {
+				printk (KERN_WARNING "%s: dma %d in use, "
+					"resorting to PIO operation\n",
+					p->name, p->dma);
+				p->dma = PARPORT_DMA_NONE;
+			} else {
+				priv->dma_buf = (char *) __get_dma_pages(GFP_KERNEL, 1);
+				if (! priv->dma_buf) {
+					printk (KERN_WARNING "%s: "
+						"cannot get buffer for DMA, "
+						"resorting to PIO operation\n",
+						p->name);
+					free_dma(p->dma);
+					p->dma = PARPORT_DMA_NONE;
+				}
+			}
+		}
+	}
+
+	/* Done probing.  Now put the port into a sensible start-up state.
+	 * SELECT | INIT also puts IEEE1284-compliant devices into
+	 * compatibility mode. */
+	if (p->modes & PARPORT_MODE_ECP)
+		/*
+		 * Put the ECP detected port in PS2 mode.
+		 */
+		outb (0x24, ECONTROL (p));
+
+	parport_pc_write_data(p, 0);
+	parport_pc_data_forward (p);
+	parport_pc_write_control(p, PARPORT_CONTROL_SELECT);
+	udelay (50);
+	parport_pc_write_control(p,
+				 PARPORT_CONTROL_SELECT
+				 | PARPORT_CONTROL_INIT);
+	udelay (50);
+
+	/* Now that we've told the sharing engine about the port, and
+	   found out its characteristics, let the high-level drivers
+	   know about it. */
+	parport_announce_port (p);
+
+	return 1;
+}
+
+/* Look for PCI parallel port cards. */
+static int __init parport_pc_init_pci (int irq, int dma)
+{
+	struct {
+		unsigned int vendor;
+		unsigned int device;
+		unsigned int numports;
+		struct {
+			unsigned long lo;
+			unsigned long hi; /* -ve if not there */
+		} addr[4];
+	} cards[] = {
+		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_550, 1,
+		  { { 3, 4 }, } },
+		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_650, 1,
+		  { { 3, 4 }, } },
+		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_850, 1,
+		  { { 3, 4 }, } },
+		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1P_10x, 1,
+		  { { 2, 3 }, } },
+		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P_10x, 2,
+		  { { 2, 3 }, { 4, 5 }, } },
+		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_550, 1,
+		  { { 4, 5 }, } },
+		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_650, 1,
+		  { { 4, 5 }, } },
+		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_850, 1,
+		  { { 4, 5 }, } },
+		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1P_20x, 1,
+		  { { 0, 1 }, } },
+		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P_20x, 2,
+		  { { 0, 1 }, { 2, 3 }, } },
+		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_550, 2,
+		  { { 1, 2 }, { 3, 4 }, } },
+		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_650, 2,
+		  { { 1, 2 }, { 3, 4 }, } },
+		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_850, 2,
+		  { { 1, 2 }, { 3, 4 }, } },
+		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_550, 1,
+		  { { 1, 2 }, } },
+		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_650, 1,
+		  { { 1, 2 }, } },
+		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_850, 1,
+		  { { 1, 2 }, } },
+		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_550, 1,
+		  { { 2, 3 }, } },
+		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_650, 1,
+		  { { 2, 3 }, } },
+		{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_850, 1,
+		  { { 2, 3 }, } },
+		{ PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PARALLEL, 1,
+		  { { 0, -1 }, } },
+		{ PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DUAL_PAR_A, 1,
+		  { { 0, -1 }, } },
+		{ PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DUAL_PAR_B, 1,
+		  { { 0, -1 }, } },
+		{ 0, }
+	};
+
+	int count = 0;
+	int i;
+
+	if (!pci_present ())
+		return 0;
+
+	for (i = 0; cards[i].vendor; i++) {
+		struct pci_dev *pcidev = NULL;
+		while ((pcidev = pci_find_device (cards[i].vendor,
+						  cards[i].device,
+						  pcidev)) != NULL) {
+			int n;
+			for (n = 0; n < cards[i].numports; n++) {
+				unsigned long lo = cards[i].addr[n].lo;
+				unsigned long hi = cards[i].addr[n].hi;
+				unsigned long io_lo = pcidev->base_address[lo];
+				unsigned long io_hi = ((hi < 0) ? 0 :
+						pcidev->base_address[hi]);
+				io_lo &= PCI_BASE_ADDRESS_IO_MASK;
+				io_hi &= PCI_BASE_ADDRESS_IO_MASK;
+				if (irq == PARPORT_IRQ_AUTO)
+					count += probe_one_port (io_lo, io_hi,
+								 pcidev->irq,
+								 dma);
+				else
+					count += probe_one_port (io_lo, io_hi,
+								 irq, dma);
+			}
+		}
+	}
+
+	return count;
+}
+
+#ifdef MODULE
+static int io[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 };
+static int io_hi[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 };
+static int dmaval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_DMA_AUTO };
+static int irqval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_IRQ_PROBEONLY };
+static const char *irq[PARPORT_PC_MAX_PORTS] = { NULL, };
+static const char *dma[PARPORT_PC_MAX_PORTS] = { NULL, };
+MODULE_PARM(io, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i");
+MODULE_PARM(io_hi, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i");
+MODULE_PARM(irq, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s");
+MODULE_PARM(dma, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s");
+
+int init_module(void)
+{	
+	/* Work out how many ports we have, then get parport_share to parse
+	   the irq values. */
+	unsigned int i;
+	for (i = 0; i < PARPORT_PC_MAX_PORTS && io[i]; i++);
+	if (i) {
+		if (parport_parse_irqs(i, irq, irqval)) return 1;
+		if (parport_parse_dmas(i, dma, dmaval)) return 1;
+	}
+	else {
+		/* The user can make us use any IRQs or DMAs we find. */
+		int val;
+
+		if (irq[0] && !parport_parse_irqs (1, irq, &val))
+			switch (val) {
+			case PARPORT_IRQ_NONE:
+			case PARPORT_IRQ_AUTO:
+				irqval[0] = val;
+			}
+
+		if (dma[0] && !parport_parse_dmas (1, dma, &val))
+			switch (val) {
+			case PARPORT_DMA_NONE:
+			case PARPORT_DMA_AUTO:
+				dmaval[0] = val;
+			}
+	}
+
+	return (parport_pc_init(io, io_hi, irqval, dmaval)?0:1);
+}
+
+void cleanup_module(void)
+{
+	struct parport *p = parport_enumerate(), *tmp;
+	while (p) {
+		tmp = p->next;
+		if (p->modes & PARPORT_MODE_PCSPP) { 
+			struct parport_pc_private *priv = p->private_data;
+			struct parport_operations *ops = p->ops;
+			if (p->dma != PARPORT_DMA_NONE)
+				free_dma(p->dma);
+			if (p->irq != PARPORT_IRQ_NONE)
+				free_irq(p->irq, p);
+			release_region(p->base, 3);
+			if (p->size > 3);
+				release_region(p->base + 3, p->size - 3);
+			if (p->modes & PARPORT_MODE_ECP)
+				release_region(p->base_hi, 3);
+			parport_proc_unregister(p);
+			if (priv->dma_buf)
+				free_page((unsigned long) priv->dma_buf);
+			kfree (p->private_data);
+			parport_unregister_port(p);
+			kfree (ops); /* hope no-one cached it */
+		}
+		p = tmp;
+	}
+}
+#endif
diff -u --recursive --new-file v2.3.11/linux/drivers/parport/probe.c linux/drivers/parport/probe.c
--- v2.3.11/linux/drivers/parport/probe.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/parport/probe.c	Wed Jul 28 11:22:46 1999
@@ -0,0 +1,210 @@
+/* $Id: parport_probe.c,v 1.1 1999/07/03 08:56:17 davem Exp $
+ * Parallel port device probing code
+ *
+ * Authors:    Carsten Gross, carsten@sol.wohnheim.uni-ulm.de
+ *             Philip Blundell <Philip.Blundell@pobox.com>
+ */
+
+#include <linux/parport.h>
+#include <linux/ctype.h>
+#include <asm/uaccess.h>
+
+static struct {
+	char *token;
+	char *descr;
+} classes[] = {
+	{ "",            "Legacy device" },
+	{ "PRINTER",     "Printer" },
+	{ "MODEM",       "Modem" },
+	{ "NET",         "Network device" },
+	{ "HDC",       	 "Hard disk" },
+	{ "PCMCIA",      "PCMCIA" },
+	{ "MEDIA",       "Multimedia device" },
+	{ "FDC",         "Floppy disk" },
+	{ "PORTS",       "Ports" },
+	{ "SCANNER",     "Scanner" },
+	{ "DIGICAM",     "Digital camera" },
+	{ "",            "Unknown device" },
+	{ "",            "Unspecified" },
+	{ "SCSIADAPTER", "SCSI adapter" },
+	{ NULL,          NULL }
+};
+
+static void pretty_print(struct parport *port, int device)
+{
+	struct parport_device_info *info = &port->probe_info[device + 1];
+
+	printk(KERN_INFO "%s", port->name);
+
+	if (device >= 0)
+		printk (" (addr %d)", device);
+
+	printk (": %s", classes[info->class].descr);
+	if (info->class)
+		printk(", %s %s", info->mfr, info->model);
+
+	printk("\n");
+}
+
+static char *strdup(char *str)
+{
+	int n = strlen(str)+1;
+	char *s = kmalloc(n, GFP_KERNEL);
+	if (!s) return NULL;
+	return strcpy(s, str);
+}
+
+static void parse_data(struct parport *port, int device, char *str)
+{
+	char *txt = kmalloc(strlen(str)+1, GFP_KERNEL);
+	char *p = txt, *q;
+	int guessed_class = PARPORT_CLASS_UNSPEC;
+	struct parport_device_info *info = &port->probe_info[device + 1];
+
+	if (!txt) {
+		printk("%s probe: memory squeeze\n", port->name);
+		return;
+	}
+	strcpy(txt, str);
+	while (p) {
+		char *sep;
+		q = strchr(p, ';');
+		if (q) *q = 0;
+		sep = strchr(p, ':');
+		if (sep) {
+			char *u = p;
+			*(sep++) = 0;
+			while (*u) {
+				*u = toupper(*u);
+				u++;
+			}
+			if (!strcmp(p, "MFG") || !strcmp(p, "MANUFACTURER")) {
+				if (info->mfr)
+					kfree (info->mfr);
+				info->mfr = strdup(sep);
+			} else if (!strcmp(p, "MDL") || !strcmp(p, "MODEL")) {
+				if (info->model)
+					kfree (info->model);
+				info->model = strdup(sep);
+			} else if (!strcmp(p, "CLS") || !strcmp(p, "CLASS")) {
+				int i;
+				if (info->class_name)
+					kfree (info->class_name);
+				info->class_name = strdup(sep);
+				for (u = sep; *u; u++)
+					*u = toupper(*u);
+				for (i = 0; classes[i].token; i++) {
+					if (!strcmp(classes[i].token, sep)) {
+						info->class = i;
+						goto rock_on;
+					}
+				}
+				printk(KERN_WARNING "%s probe: warning, class '%s' not understood.\n", port->name, sep);
+				info->class = PARPORT_CLASS_OTHER;
+			} else if (!strcmp(p, "CMD") ||
+				   !strcmp(p, "COMMAND SET")) {
+				if (info->cmdset)
+					kfree (info->cmdset);
+				info->cmdset = strdup(sep);
+				/* if it speaks printer language, it's
+				   probably a printer */
+				if (strstr(sep, "PJL") || strstr(sep, "PCL"))
+					guessed_class = PARPORT_CLASS_PRINTER;
+			} else if (!strcmp(p, "DES") || !strcmp(p, "DESCRIPTION")) {
+				if (info->description)
+					kfree (info->description);
+				info->description = strdup(sep);
+			}
+		}
+	rock_on:
+		if (q) p = q+1; else p=NULL;
+	}
+
+	/* If the device didn't tell us its class, maybe we have managed to
+	   guess one from the things it did say. */
+	if (info->class == PARPORT_CLASS_UNSPEC)
+		info->class = guessed_class;
+
+	pretty_print (port, device);
+
+	kfree(txt);
+}
+
+/* Get Std 1284 Device ID. */
+ssize_t parport_device_id (int devnum, char *buffer, size_t len)
+{
+	ssize_t retval = -ENXIO;
+	struct pardevice *dev = parport_open (devnum, "Device ID probe",
+					      NULL, NULL, NULL, 0, NULL);
+	if (!dev)
+		return -ENXIO;
+
+	parport_claim_or_block (dev);
+
+	/* Negotiate to compatibility mode, and then to device ID mode.
+	 * (This is in case we are already in device ID mode.) */
+	parport_negotiate (dev->port, IEEE1284_MODE_COMPAT);
+	retval = parport_negotiate (dev->port,
+				    IEEE1284_MODE_NIBBLE | IEEE1284_DEVICEID);
+
+	if (!retval) {
+		int idlen;
+		unsigned char length[2];
+		mm_segment_t oldfs = get_fs ();
+		set_fs (get_ds ());
+
+		/* First two bytes are MSB,LSB of inclusive length. */
+		retval = parport_read (dev->port, length, 2);
+
+		if (retval != 2) goto restore_fs;
+
+		idlen = (length[0] << 8) + length[1] - 2;
+		if (idlen < len)
+			len = idlen;
+		retval = parport_read (dev->port, buffer, len);
+
+		if (retval != len)
+			printk (KERN_DEBUG "%s: only read %d of %d ID bytes\n",
+				dev->port->name, retval, len);
+
+		/* Some printer manufacturers mistakenly believe that
+                   the length field is supposed to be _exclusive_. */
+		/* In addition, there are broken devices out there
+                   that don't even finish off with a semi-colon. */
+		if (buffer[len - 1] != ';') {
+			ssize_t diff;
+			diff = parport_read (dev->port, buffer + len, 2);
+			retval += diff;
+
+			if (diff)
+				printk (KERN_DEBUG
+					"%s: device reported incorrect "
+					"length field (%d, should be %d)\n",
+					dev->port->name, idlen, retval);
+			else {
+				/* One semi-colon short of a device ID. */
+				buffer[len++] = ';';
+				printk (KERN_DEBUG "%s: faking semi-colon\n",
+					dev->port->name);
+
+				/* If we get here, I don't think we
+                                   need to worry about the possible
+                                   standard violation of having read
+                                   more than we were told to.  The
+                                   device is non-compliant anyhow. */
+			}
+		}
+
+	restore_fs:
+		buffer[len] = '\0';
+		set_fs (oldfs);
+		parport_negotiate (dev->port, IEEE1284_MODE_COMPAT);
+	}
+	parport_release (dev);
+
+	if (retval > 2)
+		parse_data (dev->port, dev->daisy, buffer);
+
+	parport_close (dev);
+	return retval;
+}
diff -u --recursive --new-file v2.3.11/linux/drivers/parport/procfs.c linux/drivers/parport/procfs.c
--- v2.3.11/linux/drivers/parport/procfs.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/parport/procfs.c	Tue Jul 27 13:55:52 1999
@@ -0,0 +1,429 @@
+/* Sysctl interface for parport devices.
+ * 
+ * Authors: David Campbell <campbell@torque.net>
+ *          Tim Waugh <tim@cyberelk.demon.co.uk>
+ *          Philip Blundell <philb@gnu.org>
+ *          Andrea Arcangeli
+ *          Riccardo Facchetti <fizban@tin.it>
+ *
+ * based on work by Grant Guenther <grant@torque.net>
+ *              and Philip Blundell
+ *
+ * Cleaned up include files - Russell King <linux@arm.uk.linux.org>
+ */
+
+#include <linux/string.h>
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/parport.h>
+#include <linux/ctype.h>
+#include <linux/sysctl.h>
+
+#include <asm/uaccess.h>
+
+#ifdef CONFIG_SYSCTL
+
+
+static int do_active_device(ctl_table *table, int write, struct file *filp,
+		      void *result, size_t *lenp)
+{
+	struct parport *port = (struct parport *)table->extra1;
+	char buffer[256];
+	struct pardevice *dev;
+	int len = 0;
+
+	if (write)		/* can't happen anyway */
+		return -EACCES;
+
+	if (filp->f_pos) {
+		*lenp = 0;
+		return 0;
+	}
+	
+	for (dev = port->devices; dev ; dev = dev->next) {
+		if(dev == port->cad) {
+			len += sprintf(buffer, "%s\n", dev->name);
+		}
+	}
+
+	if(!len) {
+		len += sprintf(buffer, "%s\n", "none");
+	}
+
+	if (len > *lenp)
+		len = *lenp;
+	else
+		*lenp = len;
+
+	filp->f_pos += len;
+
+	return copy_to_user(result, buffer, len) ? -EFAULT : 0;
+}
+
+#ifdef CONFIG_PARPORT_1284
+static int do_autoprobe(ctl_table *table, int write, struct file *filp,
+			void *result, size_t *lenp)
+{
+	struct parport_device_info *info = table->extra2;
+	const char *str;
+	char buffer[256];
+	int len = 0;
+
+	if (write) /* permissions stop this */
+		return -EACCES;
+
+	if (filp->f_pos) {
+		*lenp = 0;
+		return 0;
+	}
+	
+	if ((str = info->class_name) != NULL)
+		len += sprintf (buffer + len, "CLASS:%s;\n", str);
+
+	if ((str = info->model) != NULL)
+		len += sprintf (buffer + len, "MODEL:%s;\n", str);
+
+	if ((str = info->mfr) != NULL)
+		len += sprintf (buffer + len, "MANUFACTURER:%s;\n", str);
+
+	if ((str = info->description) != NULL)
+		len += sprintf (buffer + len, "DESCRIPTION:%s;\n", str);
+
+	if ((str = info->cmdset) != NULL)
+		len += sprintf (buffer + len, "COMMAND SET:%s;\n", str);
+
+	if (len > *lenp)
+		len = *lenp;
+	else
+		*lenp = len;
+
+	filp->f_pos += len;
+
+	return copy_to_user (result, buffer, len) ? -EFAULT : 0;
+}
+#endif /* IEEE1284.3 support. */
+
+static int do_hardware(ctl_table *table, int write, struct file *filp,
+		       void *result, size_t *lenp)
+{
+	struct parport *port = (struct parport *)table->extra1;
+	char buffer[256];
+	int len = 0;
+
+	if (filp->f_pos) {
+		*lenp = 0;
+		return 0;
+	}
+	
+	if (write)		/* can't happen anyway */
+		return -EACCES;
+	
+	len += sprintf(buffer+len, "base:\t0x%lx", port->base);
+	if (port->base_hi)
+		len += sprintf(buffer+len, " (0x%lx)", port->base_hi);
+	buffer[len++] = '\n';
+
+	if (port->irq == PARPORT_IRQ_NONE) {
+		len += sprintf(buffer+len, "irq:\tnone\n");
+	} else {
+		len += sprintf(buffer+len, "irq:\t%d\n", port->irq);
+	}
+
+	if (port->dma == PARPORT_DMA_NONE)
+		len += sprintf(buffer+len, "dma:\tnone\n");
+	else
+		len += sprintf(buffer+len, "dma:\t%d\n", port->dma);
+
+	len += sprintf(buffer+len, "modes:\t");
+	{
+#define printmode(x) {if(port->modes&PARPORT_MODE_##x){len+=sprintf(buffer+len,"%s%s",f?",":"",#x);f++;}}
+		int f = 0;
+		printmode(PCSPP);
+		printmode(TRISTATE);
+		printmode(COMPAT);
+		printmode(EPP);
+		printmode(ECP);
+		printmode(DMA);
+#undef printmode
+	}
+	buffer[len++] = '\n';
+
+	if (len > *lenp)
+		len = *lenp;
+	else
+		*lenp = len;
+
+	filp->f_pos += len;
+
+	return copy_to_user(result, buffer, len) ? -EFAULT : 0;
+}
+
+#define PARPORT_PORT_DIR(child) { 0, NULL, NULL, 0, 0555, child }
+#define PARPORT_PARPORT_DIR(child) { DEV_PARPORT, "parport", \
+                                     NULL, 0, 0555, child }
+#define PARPORT_DEV_DIR(child) { CTL_DEV, "dev", NULL, 0, 0555, child }
+#define PARPORT_DEVICES_ROOT_DIR  { DEV_PARPORT_DEVICES, "devices", \
+                                    NULL, 0, 0555, NULL }
+
+
+struct parport_sysctl_table {
+	struct ctl_table_header *sysctl_header;
+	ctl_table vars[9];
+	ctl_table device_dir[2];
+	ctl_table port_dir[2];
+	ctl_table parport_dir[2];
+	ctl_table dev_dir[2];
+};
+
+static const struct parport_sysctl_table parport_sysctl_template = {
+	NULL,
+        {
+		{ DEV_PARPORT_SPINTIME, "spintime",
+		  NULL, sizeof(int), 0644, NULL,
+		  &proc_dointvec },
+		{ DEV_PARPORT_HARDWARE, "hardware",
+		  NULL, 0, 0444, NULL,
+		  &do_hardware },
+		PARPORT_DEVICES_ROOT_DIR,
+#ifdef CONFIG_PARPORT_1284
+		{ DEV_PARPORT_AUTOPROBE, "autoprobe",
+		  NULL, 0, 0444, NULL,
+		  &do_autoprobe },
+		{ DEV_PARPORT_AUTOPROBE + 1, "autoprobe0",
+		 NULL, 0, 0444, NULL,
+		 &do_autoprobe },
+		{ DEV_PARPORT_AUTOPROBE + 2, "autoprobe1",
+		  NULL, 0, 0444, NULL,
+		  &do_autoprobe },
+		{ DEV_PARPORT_AUTOPROBE + 3, "autoprobe2",
+		  NULL, 0, 0444, NULL,
+		  &do_autoprobe },
+		{ DEV_PARPORT_AUTOPROBE + 4, "autoprobe3",
+		  NULL, 0, 0444, NULL,
+		  &do_autoprobe },
+#endif /* IEEE 1284 support */
+		{0}
+	},
+	{ {DEV_PARPORT_DEVICES_ACTIVE, "active", NULL, 0, 444, NULL,
+	  &do_active_device }, {0}},
+	{ PARPORT_PORT_DIR(NULL), {0}},
+	{ PARPORT_PARPORT_DIR(NULL), {0}},
+	{ PARPORT_DEV_DIR(NULL), {0}}
+};
+
+struct parport_device_sysctl_table
+{
+	struct ctl_table_header *sysctl_header;
+	ctl_table vars[2];
+	ctl_table device_dir[2];
+	ctl_table devices_root_dir[2];
+	ctl_table port_dir[2];
+	ctl_table parport_dir[2];
+	ctl_table dev_dir[2];
+};
+
+static const struct parport_device_sysctl_table
+parport_device_sysctl_template = {
+	NULL,
+	{
+		{ DEV_PARPORT_DEVICE_TIMESLICE, "timeslice",
+		  NULL, sizeof(int), 0644, NULL,
+		  &proc_dointvec },
+	},
+	{ {0, NULL, NULL, 0, 0555, NULL}, {0}},
+	{ PARPORT_DEVICES_ROOT_DIR, {0}},
+	{ PARPORT_PORT_DIR(NULL), {0}},
+	{ PARPORT_PARPORT_DIR(NULL), {0}},
+	{ PARPORT_DEV_DIR(NULL), {0}}
+};
+
+struct parport_default_sysctl_table
+{
+	struct ctl_table_header *sysctl_header;
+	ctl_table vars[3];
+        ctl_table default_dir[2];
+	ctl_table parport_dir[2];
+	ctl_table dev_dir[2];
+};
+
+extern unsigned long parport_default_timeslice;
+extern int parport_default_spintime;
+
+static struct parport_default_sysctl_table
+parport_default_sysctl_table = {
+	NULL,
+	{
+		{ DEV_PARPORT_DEFAULT_TIMESLICE, "timeslice",
+		  &parport_default_timeslice,
+		  sizeof(parport_default_timeslice), 0644, NULL,
+		  &proc_dointvec },
+		{ DEV_PARPORT_DEFAULT_SPINTIME, "spintime",
+		  &parport_default_spintime,
+		  sizeof(parport_default_timeslice), 0644, NULL,
+		  &proc_dointvec },
+		{0}
+	},
+	{ { DEV_PARPORT_DEFAULT, "default", NULL, 0, 0555,
+	    parport_default_sysctl_table.vars },{0}},
+	{
+	PARPORT_PARPORT_DIR(parport_default_sysctl_table.default_dir), 
+	{0}},
+	{ PARPORT_DEV_DIR(parport_default_sysctl_table.parport_dir), {0}}
+};
+
+
+int parport_proc_register(struct parport *port)
+{
+	struct parport_sysctl_table *t;
+	int i;
+
+	t = kmalloc(sizeof(*t), GFP_KERNEL);
+	if (t == NULL)
+		return -ENOMEM;
+	memcpy(t, &parport_sysctl_template, sizeof(*t));
+
+	t->device_dir[0].extra1 = port;
+
+	for (i = 0; i < 8; i++)
+		t->vars[i].extra1 = port;
+
+	t->vars[0].data = &port->spintime;
+	t->vars[2].child = t->device_dir;
+	
+	for (i = 0; i < 5; i++)
+		t->vars[3 + i].extra2 = &port->probe_info[i];
+
+	t->port_dir[0].procname = port->name;
+	t->port_dir[0].ctl_name = port->number + 1; /* nb 0 isn't legal here */
+
+	t->port_dir[0].child = t->vars;
+	t->parport_dir[0].child = t->port_dir;
+	t->dev_dir[0].child = t->parport_dir;
+
+	t->sysctl_header = register_sysctl_table(t->dev_dir, 0);
+	if (t->sysctl_header == NULL) {
+		kfree(t);
+		t = NULL;
+	}
+	port->sysctl_table = t;
+	return 0;
+}
+
+int parport_proc_unregister(struct parport *port)
+{
+	if (port->sysctl_table) {
+		struct parport_sysctl_table *t = port->sysctl_table;
+		port->sysctl_table = NULL;
+		unregister_sysctl_table(t->sysctl_header);
+		kfree(t);
+	}
+	return 0;
+}
+
+int parport_device_proc_register(struct pardevice *device)
+{
+	struct parport_device_sysctl_table *t;
+	struct parport * port = device->port;
+	
+	t = kmalloc(sizeof(*t), GFP_KERNEL);
+	if (t == NULL)
+		return -ENOMEM;
+	memcpy(t, &parport_device_sysctl_template, sizeof(*t));
+
+	t->dev_dir[0].child = t->parport_dir;
+	t->parport_dir[0].child = t->port_dir;
+	t->port_dir[0].procname = port->name;
+	t->port_dir[0].ctl_name = port->number + 1; /* nb 0 isn't legal here */
+	t->port_dir[0].child = t->devices_root_dir;
+	t->devices_root_dir[0].child = t->device_dir;
+
+#ifdef CONFIG_PARPORT_1284
+
+	t->device_dir[0].ctl_name =
+		parport_device_num(port->number, port->muxport,
+				   device->daisy)
+		+ 1;  /* nb 0 isn't legal here */ 
+
+#else /* No IEEE 1284 support */
+
+	/* parport_device_num isn't available. */
+	t->device_dir[0].ctl_name = 1;
+	
+#endif /* IEEE 1284 support or not */
+
+	t->device_dir[0].procname = device->name;
+	t->device_dir[0].extra1 = device;
+	t->device_dir[0].child = t->vars;
+	t->vars[0].data = &device->timeslice;
+
+	t->sysctl_header = register_sysctl_table(t->dev_dir, 0);
+	if (t->sysctl_header == NULL) {
+		kfree(t);
+		t = NULL;
+	}
+	device->sysctl_table = t;
+	return 0;
+}
+
+int parport_device_proc_unregister(struct pardevice *device)
+{
+	if (device->sysctl_table) {
+		struct parport_device_sysctl_table *t = device->sysctl_table;
+		device->sysctl_table = NULL;
+		unregister_sysctl_table(t->sysctl_header);
+		kfree(t);
+	}
+	return 0;
+}
+
+int parport_default_proc_register(void)
+{
+	parport_default_sysctl_table.sysctl_header =
+		register_sysctl_table(parport_default_sysctl_table.dev_dir, 0);
+	return 0;
+}
+
+int parport_default_proc_unregister(void)
+{
+	if (parport_default_sysctl_table.sysctl_header) {
+		unregister_sysctl_table(parport_default_sysctl_table.
+					sysctl_header);
+		parport_default_sysctl_table.sysctl_header = NULL;
+	}
+	return 0;
+}
+
+#else /* no sysctl */
+
+int parport_proc_register(struct parport *pp)
+{
+	return 0;
+}
+
+int parport_proc_unregister(struct parport *pp)
+{
+	return 0;
+}
+
+int parport_device_proc_register(struct pardevice *device)
+{
+	return 0;
+}
+
+int parport_device_proc_unregister(struct pardevice *device)
+{
+	return 0;
+}
+
+int parport_default_proc_register (void)
+{
+	return 0;
+}
+
+int parport_default_proc_unregister (void)
+{
+	return 0;
+}
+#endif
diff -u --recursive --new-file v2.3.11/linux/drivers/parport/share.c linux/drivers/parport/share.c
--- v2.3.11/linux/drivers/parport/share.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/parport/share.c	Tue Jul 27 13:55:52 1999
@@ -0,0 +1,671 @@
+/* $Id: parport_share.c,v 1.15 1998/01/11 12:06:17 philip Exp $
+ * Parallel-port resource manager code.
+ * 
+ * Authors: David Campbell <campbell@tirian.che.curtin.edu.au>
+ *          Tim Waugh <tim@cyberelk.demon.co.uk>
+ *          Jose Renau <renau@acm.org>
+ *          Philip Blundell <philb@gnu.org>
+ *	    Andrea Arcangeli
+ *
+ * based on work by Grant Guenther <grant@torque.net>
+ *          and Philip Blundell
+ */
+
+#undef PARPORT_DEBUG_SHARING		/* undef for production */
+
+#include <linux/config.h>
+#include <linux/string.h>
+#include <linux/threads.h>
+#include <linux/parport.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/sched.h>
+#include <linux/kmod.h>
+
+#include <asm/spinlock.h>
+#include <asm/irq.h>
+
+#undef PARPORT_PARANOID
+
+#define PARPORT_DEFAULT_TIMESLICE	(HZ/5)
+
+unsigned long parport_default_timeslice = PARPORT_DEFAULT_TIMESLICE;
+int parport_default_spintime =  DEFAULT_SPIN_TIME;
+
+static struct parport *portlist = NULL, *portlist_tail = NULL;
+spinlock_t parportlist_lock = SPIN_LOCK_UNLOCKED;
+
+static struct parport_driver *driver_chain = NULL;
+spinlock_t driverlist_lock = SPIN_LOCK_UNLOCKED;
+
+/* What you can do to a port that's gone away.. */
+static void dead_write_lines (struct parport *p, unsigned char b){}
+static unsigned char dead_read_lines (struct parport *p) { return 0; }
+static unsigned char dead_frob_lines (struct parport *p, unsigned char b,
+			     unsigned char c) { return 0; }
+static void dead_onearg (struct parport *p){}
+static void dead_irq (int i, void *p, struct pt_regs *r) { }
+static void dead_initstate (struct pardevice *d, struct parport_state *s) { }
+static void dead_state (struct parport *p, struct parport_state *s) { }
+static void dead_noargs (void) { }
+static size_t dead_write (struct parport *p, const void *b, size_t l, int f)
+{ return 0; }
+static size_t dead_read (struct parport *p, void *b, size_t l, int f)
+{ return 0; }
+static struct parport_operations dead_ops = {
+	dead_write_lines,	/* data */
+	dead_read_lines,
+	dead_write_lines,	/* control */
+	dead_read_lines,
+	dead_frob_lines,
+	dead_read_lines,	/* status */
+	dead_onearg,		/* enable_irq */
+	dead_onearg,		/* disable_irq */
+	dead_onearg,		/* data_forward */
+	dead_onearg,		/* data_reverse */
+	dead_irq,
+	dead_initstate,		/* init_state */
+	dead_state,
+	dead_state,
+	dead_noargs,		/* xxx_use_count */
+	dead_noargs,
+	dead_write,		/* epp */
+	dead_read,
+	dead_write,
+	dead_read,
+	dead_write,		/* ecp */
+	dead_read,
+	dead_write,
+	dead_write,		/* compat */
+	dead_read,		/* nibble */
+	dead_read		/* byte */
+};
+
+static void call_driver_chain(int attach, struct parport *port)
+{
+	struct parport_driver *drv;
+
+	for (drv = driver_chain; drv; drv = drv->next) {
+		if (attach)
+			drv->attach (port);
+		else
+			drv->detach (port);
+	}
+}
+
+int parport_register_driver (struct parport_driver *drv)
+{
+	struct parport *port;
+
+	spin_lock (&driverlist_lock);
+	drv->next = driver_chain;
+	driver_chain = drv;
+	spin_unlock (&driverlist_lock);
+
+	for (port = portlist; port; port = port->next)
+		drv->attach (port);
+
+	return 0;
+}
+
+void parport_unregister_driver (struct parport_driver *arg)
+{
+	struct parport_driver *drv = driver_chain, *olddrv = NULL;
+
+	while (drv) {
+		if (drv == arg) {
+			spin_lock (&driverlist_lock);
+			if (olddrv)
+				olddrv->next = drv->next;
+			else
+				driver_chain = drv->next;
+			spin_unlock (&driverlist_lock);
+			return;
+		}
+		olddrv = drv;
+		drv = drv->next;
+	}
+}
+
+/* Return a list of all the ports we know about. */
+struct parport *parport_enumerate(void)
+{
+	/* Attempt to make things work on 2.2 systems. */
+	if (!portlist) {
+		request_module ("parport_lowlevel");
+		if (portlist)
+			/* The user has a parport_lowlevel alias in
+			 * conf.modules. Warn them that it won't work
+			 * for long. */
+			printk (KERN_WARNING
+				"parport: 'parport_lowlevel' is deprecated; "
+				"see parport.txt\n");
+	}
+
+	return portlist;
+}
+
+struct parport *parport_register_port(unsigned long base, int irq, int dma,
+				      struct parport_operations *ops)
+{
+	struct parport *tmp;
+	int portnum;
+	int device;
+	char *name;
+
+	tmp = kmalloc(sizeof(struct parport), GFP_KERNEL);
+	if (!tmp) {
+		printk(KERN_WARNING "parport: memory squeeze\n");
+		return NULL;
+	}
+
+	/* Search for the lowest free parport number. */
+	for (portnum = 0; ; portnum++) {
+		struct parport *itr = portlist;
+		while (itr) {
+			if (itr->number == portnum)
+				/* No good, already used. */
+				break;
+			else
+				itr = itr->next;
+		}
+
+		if (itr == NULL)
+			/* Got to the end of the list. */
+			break;
+	}
+	
+	/* Init our structure */
+ 	memset(tmp, 0, sizeof(struct parport));
+	tmp->base = base;
+	tmp->irq = irq;
+	tmp->dma = dma;
+	tmp->muxport = tmp->daisy = tmp->muxsel = -1;
+	tmp->modes = 0;
+ 	tmp->next = NULL;
+	tmp->devices = tmp->cad = NULL;
+	tmp->flags = 0;
+	tmp->ops = ops;
+	tmp->portnum = tmp->number = portnum;
+	tmp->physport = tmp;
+	memset (tmp->probe_info, 0, 5 * sizeof (struct parport_device_info));
+	tmp->cad_lock = RW_LOCK_UNLOCKED;
+	spin_lock_init(&tmp->waitlist_lock);
+	spin_lock_init(&tmp->pardevice_lock);
+	tmp->ieee1284.mode = IEEE1284_MODE_COMPAT;
+	tmp->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+	init_MUTEX_LOCKED (&tmp->ieee1284.irq); /* actually a semaphore at 0 */
+	tmp->spintime = parport_default_spintime;
+
+	name = kmalloc(15, GFP_KERNEL);
+	if (!name) {
+		printk(KERN_ERR "parport: memory squeeze\n");
+		kfree(tmp);
+		return NULL;
+	}
+	sprintf(name, "parport%d", portnum);
+	tmp->name = name;
+
+	/*
+	 * Chain the entry to our list.
+	 *
+	 * This function must not run from an irq handler so we don' t need
+	 * to clear irq on the local CPU. -arca
+	 */
+	spin_lock(&parportlist_lock);
+	if (portlist_tail)
+		portlist_tail->next = tmp;
+	portlist_tail = tmp;
+	if (!portlist)
+		portlist = tmp;
+	spin_unlock(&parportlist_lock);
+
+	for (device = 0; device < 5; device++)
+		/* assume the worst */
+		tmp->probe_info[device].class = PARPORT_CLASS_LEGACY;
+
+	tmp->waithead = tmp->waittail = NULL;
+
+	return tmp;
+}
+
+void parport_announce_port (struct parport *port)
+{
+#ifdef CONFIG_PARPORT_1284
+	/* Analyse the IEEE1284.3 topology of the port. */
+	parport_daisy_init (port);
+#endif
+
+	/* Let drivers know that a new port has arrived. */
+	call_driver_chain (1, port);
+}
+
+static void free_port (struct parport *port)
+{
+	int d;
+	for (d = 0; d < 5; d++) {
+		if (port->probe_info[d].class_name)
+			kfree (port->probe_info[d].class_name);
+		if (port->probe_info[d].mfr)
+			kfree (port->probe_info[d].mfr);
+		if (port->probe_info[d].model)
+			kfree (port->probe_info[d].model);
+		if (port->probe_info[d].cmdset)
+			kfree (port->probe_info[d].cmdset);
+		if (port->probe_info[d].description)
+			kfree (port->probe_info[d].description);
+	}
+
+	kfree(port->name);
+	kfree(port);
+}
+
+void parport_unregister_port(struct parport *port)
+{
+	struct parport *p;
+
+	port->ops = &dead_ops;
+
+	/* Spread the word. */
+	call_driver_chain (0, port);
+
+#ifdef CONFIG_PARPORT_1284
+	/* Forget the IEEE1284.3 topology of the port. */
+	parport_daisy_fini (port);
+#endif
+
+	spin_lock(&parportlist_lock);
+	if (portlist == port) {
+		if ((portlist = port->next) == NULL)
+			portlist_tail = NULL;
+	} else {
+		for (p = portlist; (p != NULL) && (p->next != port); 
+		     p=p->next);
+		if (p) {
+			if ((p->next = port->next) == NULL)
+				portlist_tail = p;
+		}
+		else printk (KERN_WARNING
+			     "%s not found in port list!\n", port->name);
+	}
+	spin_unlock(&parportlist_lock);
+
+	if (!port->devices)
+		free_port (port);
+}
+
+struct pardevice *parport_register_device(struct parport *port, const char *name,
+			  int (*pf)(void *), void (*kf)(void *),
+			  void (*irq_func)(int, void *, struct pt_regs *), 
+			  int flags, void *handle)
+{
+	struct pardevice *tmp;
+
+	if (port->physport->flags & PARPORT_FLAG_EXCL) {
+		/* An exclusive device is registered. */
+		printk (KERN_DEBUG "%s: no more devices allowed\n",
+			port->name);
+		return NULL;
+	}
+
+	if (flags & PARPORT_DEV_LURK) {
+		if (!pf || !kf) {
+			printk(KERN_INFO "%s: refused to register lurking device (%s) without callbacks\n", port->name, name);
+			return NULL;
+		}
+	}
+
+	tmp = kmalloc(sizeof(struct pardevice), GFP_KERNEL);
+	if (tmp == NULL) {
+		printk(KERN_WARNING "%s: memory squeeze, couldn't register %s.\n", port->name, name);
+		return NULL;
+	}
+
+	tmp->state = kmalloc(sizeof(struct parport_state), GFP_KERNEL);
+	if (tmp->state == NULL) {
+		printk(KERN_WARNING "%s: memory squeeze, couldn't register %s.\n", port->name, name);
+		kfree(tmp);
+		return NULL;
+	}
+
+	tmp->name = name;
+	tmp->port = port;
+	tmp->daisy = -1;
+	tmp->preempt = pf;
+	tmp->wakeup = kf;
+	tmp->private = handle;
+	tmp->flags = flags;
+	tmp->irq_func = irq_func;
+	tmp->waiting = 0;
+	tmp->timeout = 5 * HZ;
+
+	/* Chain this onto the list */
+	tmp->prev = NULL;
+	/*
+	 * This function must not run from an irq handler so we don' t need
+	 * to clear irq on the local CPU. -arca
+	 */
+	spin_lock(&port->physport->pardevice_lock);
+
+	if (flags & PARPORT_DEV_EXCL) {
+		if (port->physport->devices) {
+			spin_unlock (&port->physport->pardevice_lock);
+			kfree (tmp->state);
+			kfree (tmp);
+			printk (KERN_DEBUG
+				"%s: cannot grant exclusive access for "
+				"device %s\n", port->name, name);
+			return NULL;
+		}
+		port->flags |= PARPORT_FLAG_EXCL;
+	}
+
+	tmp->next = port->physport->devices;
+	if (port->physport->devices)
+		port->physport->devices->prev = tmp;
+	port->physport->devices = tmp;
+	spin_unlock(&port->physport->pardevice_lock);
+
+	inc_parport_count();
+	port->ops->inc_use_count();
+
+	init_waitqueue_head(&tmp->wait_q);
+	tmp->timeslice = parport_default_timeslice;
+	tmp->waitnext = tmp->waitprev = NULL;
+
+	/*
+	 * This has to be run as last thing since init_state may need other
+	 * pardevice fields. -arca
+	 */
+	port->ops->init_state(tmp, tmp->state);
+	parport_device_proc_register(tmp);
+	return tmp;
+}
+
+void parport_unregister_device(struct pardevice *dev)
+{
+	struct parport *port;
+
+#ifdef PARPORT_PARANOID
+	if (dev == NULL) {
+		printk(KERN_ERR "parport_unregister_device: passed NULL\n");
+		return;
+	}
+#endif
+
+	parport_device_proc_unregister(dev);
+
+	port = dev->port->physport;
+
+	if (port->cad == dev) {
+		printk(KERN_DEBUG "%s: %s forgot to release port\n",
+		       port->name, dev->name);
+		parport_release (dev);
+	}
+
+	spin_lock(&port->pardevice_lock);
+	if (dev->next)
+		dev->next->prev = dev->prev;
+	if (dev->prev)
+		dev->prev->next = dev->next;
+	else
+		port->devices = dev->next;
+
+	if (dev->flags & PARPORT_DEV_EXCL)
+		port->flags &= ~PARPORT_FLAG_EXCL;
+
+	spin_unlock(&port->pardevice_lock);
+
+	kfree(dev->state);
+	kfree(dev);
+
+	dec_parport_count();
+	port->ops->dec_use_count();
+
+	/* If this was the last device on a port that's already gone away,
+	 * free up the resources. */
+	if (port->ops == &dead_ops && !port->devices)
+		free_port (port);
+}
+
+int parport_claim(struct pardevice *dev)
+{
+	struct pardevice *oldcad;
+	struct parport *port = dev->port->physport;
+	unsigned long flags;
+
+	if (port->cad == dev) {
+		printk(KERN_INFO "%s: %s already owner\n",
+		       dev->port->name,dev->name);
+		return 0;
+	}
+
+try_again:
+	/* Preempt any current device */
+	if ((oldcad = port->cad) != NULL) {
+		if (oldcad->preempt) {
+			if (oldcad->preempt(oldcad->private))
+				goto blocked;
+			port->ops->save_state(port, dev->state);
+		} else
+			goto blocked;
+
+		if (port->cad != oldcad) {
+			printk(KERN_WARNING 
+			       "%s: %s released port when preempted!\n",
+			       port->name, oldcad->name);
+			if (port->cad)
+				goto blocked;
+		}
+	}
+
+	/* Can't fail from now on, so mark ourselves as no longer waiting.  */
+	if (dev->waiting & 1) {
+		dev->waiting = 0;
+
+		/* Take ourselves out of the wait list again.  */
+		spin_lock_irqsave (&port->waitlist_lock, flags);
+		if (dev->waitprev)
+			dev->waitprev->waitnext = dev->waitnext;
+		else
+			port->waithead = dev->waitnext;
+		if (dev->waitnext)
+			dev->waitnext->waitprev = dev->waitprev;
+		else
+			port->waittail = dev->waitprev;
+		spin_unlock_irqrestore (&port->waitlist_lock, flags);
+		dev->waitprev = dev->waitnext = NULL;
+	}
+
+	/* Now we do the change of devices */
+	write_lock_irqsave(&port->cad_lock, flags);
+	port->cad = dev;
+	write_unlock_irqrestore(&port->cad_lock, flags);
+
+#ifdef CONFIG_PARPORT_1284
+	/* If it's a mux port, select it. */
+	if (dev->port->muxport >= 0) {
+		/* FIXME */
+		port->muxsel = dev->port->muxport;
+	}
+
+	/* If it's a daisy chain device, select it. */
+	if (dev->daisy >= 0) {
+		/* This could be lazier. */
+		if (!parport_daisy_select (port, dev->daisy,
+					   IEEE1284_MODE_COMPAT))
+			port->daisy = dev->daisy;
+	}
+#endif /* IEEE1284.3 support */
+
+	/* Restore control registers */
+	port->ops->restore_state(port, dev->state);
+	dev->time = jiffies;
+	return 0;
+
+blocked:
+	/* If this is the first time we tried to claim the port, register an
+	   interest.  This is only allowed for devices sleeping in
+	   parport_claim_or_block(), or those with a wakeup function.  */
+	if (dev->waiting & 2 || dev->wakeup) {
+		spin_lock_irqsave (&port->waitlist_lock, flags);
+		if (port->cad == NULL) {
+			/* The port got released in the meantime. */
+			spin_unlock_irqrestore (&port->waitlist_lock, flags);
+			goto try_again;
+		}
+		if (test_and_set_bit(0, &dev->waiting) == 0) {
+			/* First add ourselves to the end of the wait list. */
+			dev->waitnext = NULL;
+			dev->waitprev = port->waittail;
+			if (port->waittail) {
+				port->waittail->waitnext = dev;
+				port->waittail = dev;
+			} else
+				port->waithead = port->waittail = dev;
+		}
+		spin_unlock_irqrestore (&port->waitlist_lock, flags);
+	}
+	return -EAGAIN;
+}
+
+int parport_claim_or_block(struct pardevice *dev)
+{
+	int r;
+
+	/* Signal to parport_claim() that we can wait even without a
+	   wakeup function.  */
+	dev->waiting = 2;
+
+	/* Try to claim the port.  If this fails, we need to sleep.  */
+	r = parport_claim(dev);
+	if (r == -EAGAIN) {
+		unsigned long flags;
+#ifdef PARPORT_DEBUG_SHARING
+		printk(KERN_DEBUG "%s: parport_claim() returned -EAGAIN\n", dev->name);
+#endif
+		save_flags (flags);
+		cli();
+		/* If dev->waiting is clear now, an interrupt
+		   gave us the port and we would deadlock if we slept.  */
+		if (dev->waiting) {
+			sleep_on(&dev->wait_q);
+			r = 1;
+		} else {
+			r = 0;
+#ifdef PARPORT_DEBUG_SHARING
+			printk(KERN_DEBUG "%s: didn't sleep in parport_claim_or_block()\n",
+			       dev->name);
+#endif
+		}
+		restore_flags(flags);
+#ifdef PARPORT_DEBUG_SHARING
+		if (dev->port->physport->cad != dev)
+			printk(KERN_DEBUG "%s: exiting parport_claim_or_block "
+			       "but %s owns port!\n", dev->name,
+			       dev->port->physport->cad ?
+			       dev->port->physport->cad->name:"nobody");
+#endif
+	}
+	dev->waiting = 0;
+	return r;
+}
+
+void parport_release(struct pardevice *dev)
+{
+	struct parport *port = dev->port->physport;
+	struct pardevice *pd;
+	unsigned long flags;
+
+	/* Make sure that dev is the current device */
+	if (port->cad != dev) {
+		printk(KERN_WARNING "%s: %s tried to release parport "
+		       "when not owner\n", port->name, dev->name);
+		return;
+	}
+
+#ifdef CONFIG_PARPORT_1284
+	/* If this is on a mux port, deselect it. */
+	if (dev->port->muxport >= 0) {
+		/* FIXME */
+		port->muxsel = -1;
+	}
+
+	/* If this is a daisy device, deselect it. */
+	if (dev->daisy >= 0) {
+		parport_daisy_deselect_all (port);
+		port->daisy = -1;
+	}
+#endif
+
+	write_lock_irqsave(&port->cad_lock, flags);
+	port->cad = NULL;
+	write_unlock_irqrestore(&port->cad_lock, flags);
+
+	/* Save control registers */
+	port->ops->save_state(port, dev->state);
+
+	/* If anybody is waiting, find out who's been there longest and
+	   then wake them up. (Note: no locking required) */
+	for (pd = port->waithead; pd; pd = pd->waitnext) {
+		if (pd->waiting & 2) { /* sleeping in claim_or_block */
+			parport_claim(pd);
+			if (waitqueue_active(&pd->wait_q))
+				wake_up(&pd->wait_q);
+			return;
+		} else if (pd->wakeup) {
+			pd->wakeup(pd->private);
+			if (dev->port->cad)
+				return;
+		} else {
+			printk(KERN_ERR "%s: don't know how to wake %s\n", port->name, pd->name);
+		}
+	}
+
+	/* Nobody was waiting, so walk the list to see if anyone is
+	   interested in being woken up.  */
+	for (pd = port->devices; (port->cad == NULL) && pd; pd = pd->next) {
+		if (pd->wakeup && pd != dev)
+			pd->wakeup(pd->private);
+	}
+}
+
+static int parport_parse_params (int nports, const char *str[], int val[],
+				 int automatic, int none)
+{
+	unsigned int i;
+	for (i = 0; i < nports && str[i]; i++) {
+		if (!strncmp(str[i], "auto", 4))
+			val[i] = automatic;
+		else if (!strncmp(str[i], "none", 4))
+			val[i] = none;
+		else {
+			char *ep;
+			unsigned long r = simple_strtoul(str[i], &ep, 0);
+			if (ep != str[i])
+				val[i] = r;
+			else {
+				printk("parport: bad specifier `%s'\n", str[i]);
+				return -1;
+			}
+		}
+	}
+
+	return 0;
+}
+
+int parport_parse_irqs(int nports, const char *irqstr[], int irqval[])
+{
+	return parport_parse_params (nports, irqstr, irqval, PARPORT_IRQ_AUTO,
+				     PARPORT_IRQ_NONE);
+}
+
+int parport_parse_dmas(int nports, const char *dmastr[], int dmaval[])
+{
+	return parport_parse_params (nports, dmastr, dmaval, PARPORT_DMA_AUTO,
+				     PARPORT_DMA_NONE);
+}
diff -u --recursive --new-file v2.3.11/linux/drivers/usb/Config.in linux/drivers/usb/Config.in
--- v2.3.11/linux/drivers/usb/Config.in	Wed Jul 21 15:46:48 1999
+++ linux/drivers/usb/Config.in	Tue Jul 27 16:05:50 1999
@@ -35,6 +35,9 @@
 	  dep_tristate '  USB SCSI verbose debug' CONFIG_USB_SCSI_DEBUG $CONFIG_USB_SCSI
   fi
   dep_tristate 'EZUSB Firmware downloader' CONFIG_USB_EZUSB $CONFIG_USB
+  if [ "$CONFIG_PROC_FS" != "n" ]; then
+  	bool 'Preliminary /proc/bus/usb support' CONFIG_USB_PROC
+  fi
 fi
 
 endmenu
diff -u --recursive --new-file v2.3.11/linux/drivers/usb/Makefile linux/drivers/usb/Makefile
--- v2.3.11/linux/drivers/usb/Makefile	Wed Jul 21 15:46:48 1999
+++ linux/drivers/usb/Makefile	Tue Jul 27 16:05:50 1999
@@ -22,6 +22,9 @@
 ifeq ($(CONFIG_USB),m)
   M_OBJS +=usbcore.o
   MIX_OBJS +=usb.o usb-debug.o usb-core.o
+  ifeq ($(CONFIG_USB_PROC),y)
+    MIX_OBJS += proc_usb.o
+  endif
 endif
 
 ifeq ($(CONFIG_USB_UHCI),y)
@@ -153,7 +156,10 @@
 usb-ohci-hcd.o: ohci-hcd.o ohci-root-hub.o 
 	$(LD) $(LD_RFLAG) -r -o $@ ohci-hcd.o ohci-root-hub.o 
        
+ifeq ($(CONFIG_USB_PROC),y)
+usbcore.o: usb.o usb-debug.o usb-core.o proc_usb.o
+	$(LD) $(LD_RFLAG) -r -o $@ usb.o usb-debug.o usb-core.o proc_usb.o
+else
 usbcore.o: usb.o usb-debug.o usb-core.o
 	$(LD) $(LD_RFLAG) -r -o $@ usb.o usb-debug.o usb-core.o
-
-       
+endif
diff -u --recursive --new-file v2.3.11/linux/drivers/usb/cpia.c linux/drivers/usb/cpia.c
--- v2.3.11/linux/drivers/usb/cpia.c	Wed Jul 21 15:46:48 1999
+++ linux/drivers/usb/cpia.c	Mon Jul 26 16:05:45 1999
@@ -583,7 +583,7 @@
 
 	cpia->fbuf = rvmalloc(2 * MAX_FRAME_SIZE);
 	if (!cpia->fbuf)
-		return -ENOMEM;
+		goto open_err_ret;
 
 	cpia->frame[0].state = FRAME_DONE;
 	cpia->frame[1].state = FRAME_DONE;
@@ -595,15 +595,15 @@
 
 	cpia->sbuf[0].data = kmalloc(STREAM_BUF_SIZE, GFP_KERNEL);
 	if (!cpia->sbuf[0].data)
-		return -ENOMEM;
+		goto open_err_on0;
 
 	cpia->sbuf[1].data = kmalloc(STREAM_BUF_SIZE, GFP_KERNEL);
 	if (!cpia->sbuf[1].data)
-		return -ENOMEM;
+		goto open_err_on1;
 
 	cpia->sbuf[2].data = kmalloc(STREAM_BUF_SIZE, GFP_KERNEL);
 	if (!cpia->sbuf[2].data)
-		return -ENOMEM;
+		goto open_err_on2;
 
 	printk("sbuf[0] @ %p\n", cpia->sbuf[0].data);
 	printk("sbuf[1] @ %p\n", cpia->sbuf[1].data);
@@ -617,6 +617,15 @@
 	cpia_init_isoc(cpia);
 
 	return 0;
+
+open_err_on2:
+	kfree (cpia->sbuf[1].data);
+open_err_on1:
+	kfree (cpia->sbuf[0].data);
+open_err_on0:
+	rvfree(cpia->fbuf, 2 * MAX_FRAME_SIZE);
+open_err_ret:
+	return -ENOMEM;
 }
 
 static void cpia_close(struct video_device *dev)
diff -u --recursive --new-file v2.3.11/linux/drivers/usb/ezusb.c linux/drivers/usb/ezusb.c
--- v2.3.11/linux/drivers/usb/ezusb.c	Wed Jul 21 15:46:48 1999
+++ linux/drivers/usb/ezusb.c	Wed Jul 28 10:45:39 1999
@@ -27,7 +27,6 @@
 
 /*****************************************************************************/
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/socket.h>
 #include <asm/uaccess.h>
diff -u --recursive --new-file v2.3.11/linux/drivers/usb/hub.c linux/drivers/usb/hub.c
--- v2.3.11/linux/drivers/usb/hub.c	Wed Jul 21 15:46:48 1999
+++ linux/drivers/usb/hub.c	Mon Jul 26 22:37:36 1999
@@ -432,38 +432,14 @@
 
 void usb_hub_cleanup(void)
 {
-	struct list_head *next, *tmp, *head = &all_hubs_list;
-	struct usb_hub *hub;
-	unsigned long flags, flags2;
-
-	/* Free the resources allocated by each hub */
-	spin_lock_irqsave(&hub_list_lock, flags);
-	spin_lock_irqsave(&hub_event_lock, flags2);
-
-	tmp = head->next;
-	while (tmp != head) {
-		hub = list_entry(tmp, struct usb_hub, hub_list);
-
-		next = tmp->next;
-
-		list_del(&hub->event_list);
-		INIT_LIST_HEAD(&hub->event_list);
-		list_del(tmp);         /* &hub->hub_list */
-		INIT_LIST_HEAD(tmp);   /* &hub->hub_list */
-
-		/* XXX we should disconnect each connected port here */
-
-		usb_release_irq(hub->dev, hub->irq_handle);
-		hub->irq_handle = NULL;
-		kfree(hub);
-
-		tmp = next;
-	}
-
+	/*
+	 * Hub resources are freed for us by usb_deregister.  It
+	 * usb_driver_purge on every device which in turn calls that
+	 * devices disconnect function if it is using this driver.
+	 * The hub_disconnect function takes care of releasing the
+	 * individual hub resources. -greg
+	 */
 	usb_deregister(&hub_driver);
-
-	spin_unlock_irqrestore(&hub_event_lock, flags2);
-	spin_unlock_irqrestore(&hub_list_lock, flags);
 } /* usb_hub_cleanup() */
 
 #ifdef MODULE
diff -u --recursive --new-file v2.3.11/linux/drivers/usb/inits.h linux/drivers/usb/inits.h
--- v2.3.11/linux/drivers/usb/inits.h	Mon May 31 09:01:50 1999
+++ linux/drivers/usb/inits.h	Tue Jul 27 16:05:50 1999
@@ -5,3 +5,5 @@
 int usb_printer_init(void);
 void usb_hub_cleanup(void);
 void usb_mouse_cleanup(void);
+int proc_usb_init (void);
+void proc_usb_cleanup (void);
diff -u --recursive --new-file v2.3.11/linux/drivers/usb/mouse.c linux/drivers/usb/mouse.c
--- v2.3.11/linux/drivers/usb/mouse.c	Wed Jul 21 15:46:48 1999
+++ linux/drivers/usb/mouse.c	Sun Jul 25 20:30:46 1999
@@ -336,15 +336,15 @@
 {
 	struct mouse_state *mouse = &static_mouse_state;
 
-	misc_register(&usb_mouse);
-
 	mouse->present = mouse->active = 0;
 	mouse->irq_handle = NULL;
 	init_waitqueue_head(&mouse->wait);
 	mouse->fasync = NULL;
 
+	misc_register(&usb_mouse);
+
 	usb_register(&mouse_driver);
-	printk(KERN_INFO "USB HID boot protocol mouse registered.\n");
+	printk(KERN_INFO "USB HID boot protocol mouse driver registered.\n");
 	return 0;
 }
 
diff -u --recursive --new-file v2.3.11/linux/drivers/usb/ohci-debug.c linux/drivers/usb/ohci-debug.c
--- v2.3.11/linux/drivers/usb/ohci-debug.c	Thu Jul  8 15:42:21 1999
+++ linux/drivers/usb/ohci-debug.c	Sun Jul 25 20:30:46 1999
@@ -131,7 +131,18 @@
 	printk(KERN_DEBUG "      next_td  =  0x%x\n", le32_to_cpup(&td->next_td));
 	printk(KERN_DEBUG "      buf_end  =  0x%x\n", le32_to_cpup(&td->buf_end));
 	printk(KERN_DEBUG "   ohci TD driver fields:\n");
+	printk(KERN_DEBUG "      flags    =  %x {", td->hcd_flags);
+	if (td_allocated(*td))
+		printk(" alloc");
+	if (td_dummy(*td))
+		printk(" dummy");
+	if (td_endofchain(*td))
+		printk(" endofchain");
+	if (!can_auto_free(*td))
+		printk(" noautofree");
+	printk("}\n");
 	printk(KERN_DEBUG "      data     =  %p\n", td->data);
+	printk(KERN_DEBUG "      cmpltd   =  %p\n", td->completed);
 	printk(KERN_DEBUG "      dev_id   =  %p\n", td->dev_id);
 	printk(KERN_DEBUG "      ed       =  %p\n", td->ed);
 	if (td->data != NULL) {
diff -u --recursive --new-file v2.3.11/linux/drivers/usb/ohci.c linux/drivers/usb/ohci.c
--- v2.3.11/linux/drivers/usb/ohci.c	Wed Jul 21 15:46:48 1999
+++ linux/drivers/usb/ohci.c	Sun Jul 25 20:30:46 1999
@@ -111,8 +111,8 @@
  *
  * This function can be called by the interrupt handler.
  */
-static struct ohci_td *ohci_add_td_to_ed(struct ohci_td *td,
-				struct ohci_td *last_td, struct ohci_ed *ed)
+static struct ohci_td *ohci_add_tds_to_ed(struct ohci_td *td,
+					  struct ohci_ed *ed)
 {
 	struct ohci_td *t, *dummy_td;
 	u32 new_dummy;
@@ -127,14 +127,14 @@
 
 	for (t = td; ; t = bus_to_virt(le32_to_cpup(&t->next_td))) {
 		t->ed = ed;
-		if (t == last_td)
+		if (t->next_td == 0)
 			break;
 	}
 
 	/* Make the last TD point back to the first, since it
 	 * will become the new dummy TD. */
 	new_dummy = cpu_to_le32(virt_to_bus(td));
-	last_td->next_td = new_dummy;
+	t->next_td = new_dummy;
 
 	/* Copy the contents of the first TD into the dummy */
 	*dummy_td = *td;
@@ -146,34 +146,7 @@
 	ed->tail_td = new_dummy;
 
 	return dummy_td;	/* replacement head of chain */
-} /* ohci_add_td_to_ed() */
-
-
-/*
- * Add a whole chain of TDs to an ED using the above function.
- * The same restrictions apply.
- *
- * XXX This function is being removed in the future! XXX
- */
-static struct ohci_td *ohci_add_td_chain_to_ed(struct ohci_td *td, struct ohci_ed *ed)
-{
-	struct ohci_td *cur_td;
-	if (!td)
-		return NULL;
-
-	/* Find the last TD in this chain, storing its pointer in cur_td */
-	cur_td = td;
-	for (;;) {
-		__u32 next_td = cur_td->next_td;
-
-		/* advance to the next td, exit if there isn't one */
-		if (!next_td)
-			break;
-		cur_td = bus_to_virt(le32_to_cpup(&next_td));
-	}
-
-	return td = ohci_add_td_to_ed(td, cur_td, ed);
-} /* ohci_add_td_chain_to_ed() */
+} /* ohci_add_tds_to_ed() */
 
 
 /* .......... */
@@ -261,6 +234,7 @@
 	 */
 	int_ed = &root_hub->ed[ms_to_ed_int(period)];
 #ifdef OHCI_DEBUG
+	if (MegaDebug)
 	printk(KERN_DEBUG "usb-ohci: Using INT ED queue %d for %dms period\n",
 	       ms_to_ed_int(period), period);
 #endif
@@ -278,6 +252,42 @@
 } /* ohci_add_periodic_ed() */
 
 /*
+ * Locate the periodic ED for a given interrupt endpoint.
+ */
+struct ohci_ed *ohci_get_periodic_ed(struct ohci_device *dev, int period,
+				     unsigned int pipe, int isoc)
+{
+	struct ohci_device *root_hub = usb_to_ohci(dev->ohci->bus->root_hub);
+	unsigned long flags;
+	struct ohci_ed *int_ed;
+	unsigned int status, req_status;
+
+	/* get the dummy ED before the EDs for this period */
+	int_ed = &root_hub->ed[ms_to_ed_int(period)];
+
+	/* decide on what the status field should look like */
+	req_status = ed_set_maxpacket(usb_maxpacket(ohci_to_usb(dev), pipe))
+		| ed_set_speed(usb_pipeslow(pipe))
+		| (usb_pipe_endpdev(pipe) & 0x7ff)
+		| ed_set_type_isoc(isoc);
+
+	spin_lock_irqsave(&ohci_edtd_lock, flags);
+	for (;;) {
+		int_ed = bus_to_virt(le32_to_cpup(&int_ed->next_ed));
+		/* stop if we get to the end or to another dummy ED. */
+		if (int_ed == 0)
+			break;
+		status = le32_to_cpup(&int_ed->status);
+		if ((status & OHCI_ED_FA) == 0)
+			break;
+		/* check whether all the appropriate fields match */
+		if ((status & 0x7ffa7ff) == req_status)
+			return int_ed;
+	}
+	return 0;
+}
+
+/*
  *  Put an isochronous ED on the controller's list
  */
 inline void ohci_add_isoc_ed(struct ohci *ohci, struct ohci_ed *ed)
@@ -507,6 +517,7 @@
 			/* set the controller to skip this one
 			   and remove it from the list */
 			ed->status |= cpu_to_le32(OHCI_ED_SKIP);
+			/* XXX should call td->completed for each td */
 			*prevp = ed->next_ed;
 			removed = 1;
 		} else {
@@ -670,6 +681,7 @@
 			new_ed->status |= cpu_to_le32(OHCI_ED_SKIP);
 			/* mark it as allocated */
 			allocate_ed(new_ed);
+			new_ed->ohci_dev = dev;
 			return new_ed;
 		}
 	}
@@ -722,7 +734,7 @@
 			       flags);
 	td->cur_buf = (data == NULL) ? 0 : cpu_to_le32(virt_to_bus(data));
 	td->buf_end = (len == 0) ? 0 :
-		cpu_to_le32(le32_to_cpup(&td->cur_buf) + len - 1);
+		cpu_to_le32(virt_to_bus((char *)data + len - 1));
 
 	/* driver fields */
 	td->data = data;
@@ -789,31 +801,24 @@
  *
  *  Returns the head TD in the chain.
  */
-struct ohci_td *ohci_build_td_chain(struct ohci_device *dev, void *data, unsigned int len, int dir, __u32 toggle, int round, int auto_free, void* dev_id, usb_device_irq handler, __u32 next_td)
+struct ohci_td *ohci_build_td_chain(struct ohci_device *dev,
+		void *data, unsigned int len, int dir, __u32 toggle,
+		int round, int auto_free, void* dev_id,
+		usb_device_irq handler, __u32 next_td)
 {
 	struct ohci_td *head, *cur_td;
-	__u32 bus_data_start, bus_data_end;
-	unsigned short max_page0_len;
+	unsigned max_len;
 
 	if (!data || (len == 0))
 		return NULL;
 
-	/* Setup the first TD, leaving buf_end = 0 */
+	/* Get the first TD */
 	head = ohci_get_free_td(dev);
 	if (head == NULL) {
 		printk(KERN_ERR "usb-ohci: out of TDs\n");
 		return NULL;
 	}
 
-	ohci_fill_new_td(head,
-		td_set_dir_out(dir),
-		toggle & OHCI_TD_DT,
-		(round ? OHCI_TD_ROUND : 0),
-		data, 0,
-		dev_id, handler);
-	if (!auto_free)
-		noauto_free_td(head);
-
 	cur_td = head;
 
 	/* AFICT, that the OHCI controller takes care of the innards of
@@ -821,66 +826,60 @@
 	 * packets as necessary if the transfer falls on an even packet
 	 * size boundary, we don't need a special TD for that. */
 
-	while (len > 0) {
-		bus_data_start = virt_to_bus(data);
-		bus_data_end = virt_to_bus(data+(len-1));
-
-		/* check the 4096 byte alignment of the start of the data */
-		max_page0_len = 0x1000 - (bus_data_start & 0xfff);
-
-		/* check if the remaining data occupies more than two pages */
-		if ((max_page0_len < len) && (len - max_page0_len > 0x1000)) {
-			struct ohci_td *new_td;
-
-			/* Point this TD to data up through the end of
-			 * the second page */
-			cur_td->buf_end = bus_data_start +
-				(max_page0_len + 0xfff);
-
-			/* adjust the data pointer & remaining length */
-			data += (max_page0_len + 0x1000);
-			len  -= (max_page0_len + 0x1000);
-
-			/* TODO lookup effect of rounding bit on
-			 * individual TDs vs. whole TD chain transfers;
-			 * disable cur_td's rounding bit here if needed. */
-
-			/* mark that this is not the last TD... */
-			clear_td_endofchain(cur_td);
-
-			/* allocate another td */
-			new_td = ohci_get_free_td(dev);
-			if (new_td == NULL) {
-				printk(KERN_ERR "usb-ohci: out of TDs\n");
-				/* FIXME: free any allocated TDs */
-				return NULL;
-			}
+	/* check the 4096 byte alignment of the start of the data */
+	max_len = 0x2000 - ((unsigned long)data & 0xfff);
 
-			ohci_fill_new_td(new_td,
-				td_set_dir_out(dir),
-				TOGGLE_AUTO,  /* toggle Data0/1 via the ED */
-				round ? OHCI_TD_ROUND : 0,
-				data, 0,
-				dev_id, handler);
-			if (!auto_free)
-				noauto_free_td(new_td);
-
-			/* Link the new TD to the chain & advance */
-			cur_td->next_td = virt_to_bus(new_td);
-			cur_td = new_td;
-		} else {
-			/* Last TD in this chain, normal buf_end is fine */
-			cur_td->buf_end = bus_data_end;
-
-			set_td_endofchain(cur_td);
+	/* check if the remaining data occupies more than two pages */
+	while (len > max_len) {
+		struct ohci_td *new_td;
+
+		/* TODO lookup effect of rounding bit on
+		 * individual TDs vs. whole TD chain transfers;
+		 * disable cur_td's rounding bit here if needed. */
+
+		ohci_fill_new_td(cur_td,
+				 td_set_dir_out(dir),
+				 toggle & OHCI_TD_DT,
+				 (round ? OHCI_TD_ROUND : 0),
+				 data, max_len - 1,
+				 dev_id, handler);
+		if (!auto_free)
+			noauto_free_td(head);
+
+		/* adjust the data pointer & remaining length */
+		data += max_len;
+		len  -= max_len;
+
+		/* allocate another td */
+		new_td = ohci_get_free_td(dev);
+		if (new_td == NULL) {
+			printk(KERN_ERR "usb-ohci: out of TDs\n");
+			/* FIXME: free any allocated TDs */
+			return NULL;
+		}
+
+		/* Link the new TD to the chain & advance */
+		cur_td->next_td = cpu_to_le32(virt_to_bus(new_td));
+		cur_td = new_td;
+
+		/* address is page-aligned now */
+		max_len = 0x2000;
+		toggle = TOGGLE_AUTO;  /* toggle Data0/1 via the ED */
+	}
 
-			len = 0;
-			break;
-		}
-	} /* while */
+	ohci_fill_new_td(cur_td,
+		td_set_dir_out(dir),
+		toggle & OHCI_TD_DT,
+		(round ? OHCI_TD_ROUND : 0),
+		data, len,
+		dev_id, handler);
+	if (!auto_free)
+		noauto_free_td(head);
 
 	/* link the given next_td to the end of this chain */
-	cur_td->next_td = next_td;
+	cur_td->next_td = cpu_to_le32(next_td);
+	if (next_td == 0)
+		set_td_endofchain(cur_td);
 
 	return head;
 } /* ohci_build_td_chain() */
@@ -902,10 +901,10 @@
 
 	/* if cur_buf is 0, all data has been transferred */
 	if (!td->cur_buf) {
-		return td->buf_end - bus_data_start + 1;
+		return le32_to_cpup(&td->buf_end) - bus_data_start + 1;
 	}
 
-	bus_data_end = td->cur_buf;
+	bus_data_end = le32_to_cpup(&td->cur_buf);
 
 	/* is it on the same page? */
 	if ((bus_data_start & ~0xfff) == (bus_data_end & ~0xfff)) {
@@ -945,13 +944,36 @@
 	struct ohci_td *td;
 	struct ohci_ed *interrupt_ed;	/* endpoint descriptor for this irq */
 	int maxps = usb_maxpacket(usb, pipe);
+	unsigned long flags;
 
 	/* Get an ED and TD */
-	interrupt_ed = ohci_get_free_ed(dev);
-	if (!interrupt_ed) {
-		printk(KERN_ERR "Out of EDs on device %p in ohci_request_irq\n", dev);
-		return NULL;
+	interrupt_ed = ohci_get_periodic_ed(dev, period, pipe, 0);
+	if (interrupt_ed == 0) {
+		interrupt_ed = ohci_get_free_ed(dev);
+		if (!interrupt_ed) {
+			printk(KERN_ERR "Out of EDs on device %p in ohci_request_irq\n", dev);
+			return NULL;
+		}
+
+		/*
+		 * Set the max packet size, device speed, endpoint number, usb
+		 * device number (function address), and type of TD.
+		 */
+		ohci_fill_ed(dev, interrupt_ed, maxps, usb_pipeslow(pipe),
+			     usb_pipe_endpdev(pipe), 0 /* normal TDs */);
+		interrupt_ed->status &= cpu_to_le32(~OHCI_ED_SKIP);
+
+		/* Assimilate the new ED into the collective */
+		ohci_add_periodic_ed(dev->ohci, interrupt_ed, period);
 	}
+#ifdef OHCI_DEBUG
+	if (MegaDebug) {
+	printk(KERN_DEBUG "ohci_request irq: using ED %p [%x %x %x %x]\n",
+	       interrupt_ed, FIELDS_OF_ED(interrupt_ed));
+	printk(KERN_DEBUG "  for dev %d pipe %x period %d\n", usb->devnum,
+	       pipe, period);
+	}
+#endif
 
 	td = ohci_get_free_td(dev);
 	if (!td) {
@@ -960,13 +982,6 @@
 		return NULL;
 	}
 
-	/*
-	 * Set the max packet size, device speed, endpoint number, usb
-	 * device number (function address), and type of TD.
-	 */
-	ohci_fill_ed(dev, interrupt_ed, maxps, usb_pipeslow(pipe),
-		     usb_pipe_endpdev(pipe), 0 /* normal TDs */);
-
 	/* Fill in the TD */
 	if (maxps > sizeof(dev->data))
 		maxps = sizeof(dev->data);
@@ -975,20 +990,15 @@
 			OHCI_TD_ROUND,
 			dev->data, maxps,
 			dev_id, handler);
+	set_td_endofchain(td);
 
 	/*
 	 *  Put the TD onto our ED and make sure its ready to run
 	 */
-	td = ohci_add_td_to_ed(td, td, interrupt_ed);
-	interrupt_ed->status &= cpu_to_le32(~OHCI_ED_SKIP);
-	ohci_unhalt_ed(interrupt_ed);
-
-	/* Make sure all the stores above get done before
-	 * the store which tells the OHCI about the new ed. */
-	wmb();
-
-	/* Assimilate the new ED into the collective */
-	ohci_add_periodic_ed(dev->ohci, interrupt_ed, period);
+	td->next_td = 0;
+	spin_lock_irqsave(&ohci_edtd_lock, flags);
+	td = ohci_add_tds_to_ed(td, interrupt_ed);
+	spin_unlock_irqrestore(&ohci_edtd_lock, flags);
 
 	return (void*)td;
 } /* ohci_request_irq() */
@@ -1148,6 +1158,7 @@
 			0 /* flags */,
 			NULL /* data */, 0 /* data len */,
 			&completion_status, ohci_control_completed);
+	set_td_endofchain(status_td);
 	status_td->next_td = 0; /* end of TDs */
 
 	/* If there is data to transfer, create the chain of data TDs
@@ -1167,18 +1178,18 @@
 		}
 
 		/* link the to the data & status TDs */
-		setup_td->next_td = virt_to_bus(data_td);
+		setup_td->next_td = cpu_to_le32(virt_to_bus(data_td));
 	} else {
 		/* no data TDs, link to the status TD */
-		setup_td->next_td = virt_to_bus(status_td);
+		setup_td->next_td = cpu_to_le32(virt_to_bus(status_td));
 	}
 
 	/*
 	 * Add the control TDs to the control ED (setup_td is the first)
 	 */
-	setup_td = ohci_add_td_chain_to_ed(setup_td, control_ed);
-  	control_ed->status &= ~OHCI_ED_SKIP;
-  	ohci_unhalt_ed(control_ed);
+	setup_td = ohci_add_tds_to_ed(setup_td, control_ed);
+  	control_ed->status &= cpu_to_le32(~OHCI_ED_SKIP);
+  	/* ohci_unhalt_ed(control_ed); */
 
 #ifdef OHCI_DEBUG
 	if (MegaDebug) {
@@ -1201,35 +1212,34 @@
 	/* Give the ED to the HC */
 	ohci_add_control_ed(dev->ohci, control_ed);
 
-	schedule_timeout(HZ/10);
+	schedule_timeout(HZ);
 
 	remove_wait_queue(&control_wakeup, &wait);
 
 #ifdef OHCI_DEBUG
-	if (MegaDebug) {
-	/* complete transaction debugging output (after) */
-	printk(KERN_DEBUG " *after* Control ED %lx:\n", virt_to_bus(control_ed));
-	show_ohci_ed(control_ed);
-	printk(KERN_DEBUG " *after* Control TD chain:\n");
-	show_ohci_td_chain(setup_td);
-	printk(KERN_DEBUG " *after* OHCI Controller Status:\n");
-	show_ohci_status(dev->ohci);
-	}
-#endif
-
-	/* no TD cleanup, the TDs were auto-freed as they finished */
-
-	/* remove the control ED from the HC */
-	ohci_remove_control_ed(dev->ohci, control_ed);
-	ohci_free_ed(control_ed);	 /* return it to the pool */
-
-#ifdef OHCI_DEBUG
 	if (completion_status != 0) {
 		const char *what = (completion_status < 0)? "timed out":
 			cc_names[completion_status & 0xf];
-		printk(KERN_ERR "ohci_control_msg: %s on pipe %x cmd %x %x %x %x %x\n",
+		printk(KERN_ERR "ohci_control_msg: %s on pipe %x cmd %x %x %x %x %x",
 		       what, pipe, cmd->requesttype, cmd->request,
 		       cmd->value, cmd->index, cmd->length);
+		if (usb_pipeout(pipe) && len > 0) {
+			int i;
+			printk(" data");
+			for (i = 0; i < 16 && i < len; ++i)
+				printk(" %.2x", ((unsigned char *)data)[i]);
+			if (i < len)
+				printk(" ...");
+		}
+		printk("\n");
+		if (MegaDebug && completion_status < 0) {
+			printk(KERN_DEBUG "control_ed at %p:\n", control_ed);
+			show_ohci_ed(control_ed);
+			if (ed_head_td(control_ed) != ed_tail_td(control_ed))
+				show_ohci_td_chain(bus_to_virt(ed_head_td(control_ed)));
+			printk(KERN_DEBUG "setup TD at %p:\n", setup_td);
+			show_ohci_td(setup_td);
+		}
 	} else if (!usb_pipeout(pipe)) {
 		unsigned char *q = data;
 		int i;
@@ -1243,7 +1253,26 @@
 		}
 		printk("\n");
 	}
+
+	if (MegaDebug) {
+	/* complete transaction debugging output (after) */
+	printk(KERN_DEBUG " *after* Control ED %lx:\n", virt_to_bus(control_ed));
+	show_ohci_ed(control_ed);
+	printk(KERN_DEBUG " *after* Control TD chain:\n");
+	show_ohci_td_chain(setup_td);
+	printk(KERN_DEBUG " *after* OHCI Controller Status:\n");
+	show_ohci_status(dev->ohci);
+	}
 #endif
+
+	/* no TD cleanup, the TDs were auto-freed as they finished */
+
+	/* remove the control ED from the HC */
+	ohci_remove_control_ed(dev->ohci, control_ed);
+	ohci_free_ed(control_ed);	 /* return it to the pool */
+
+	if (completion_status < 0)
+		completion_status = USB_ST_TIMEOUT;
 	return completion_status;
 } /* ohci_control_msg() */
 
@@ -1278,6 +1307,7 @@
 	req = (struct ohci_bulk_request_state *) dev_id;
 
 #ifdef OHCI_DEBUG
+	if (MegaDebug)
 	printk(KERN_DEBUG "ohci_bulk_td_handler stats %x, buffer %p, len %d, req %p\n", stats, buffer, len, req);
 #endif
 
@@ -1285,11 +1315,24 @@
 	if (stats == USB_ST_NOERROR)
 		req->_bytes_done += len;
 
+#ifdef OHCI_DEBUG
+	if (MegaDebug && req->_bytes_done) {
+		int i;
+		printk(KERN_DEBUG " %d bytes, bulk data:", req->_bytes_done);
+		for (i = 0; i < 16 && i < req->_bytes_done; ++i)
+			printk(" %.2x", ((unsigned char *)buffer)[i]);
+		if (i < req->_bytes_done)
+			printk(" ...");
+		printk("\n");
+	}
+#endif
+
 	/* call the real completion handler when done or on an error */
 	if ((stats != USB_ST_NOERROR) ||
 	    (req->_bytes_done >= req->length && req->completion != NULL)) {
 		*req->bytes_transferred_p += req->_bytes_done;
 #ifdef OHCI_DEBUG
+		if (MegaDebug)
 		printk(KERN_DEBUG "usb-ohci: bulk request %p ending\n", req);
 #endif
 		req->completion(stats, buffer, req->_bytes_done, req->dev_id);
@@ -1305,7 +1348,7 @@
  * to an error.
  *
  * bytes_transferred_p is a pointer to an integer that will be
- * -incremented- by the number of bytes that have been successfully
+ * set to the number of bytes that have been successfully
  * transferred.  The interrupt handler will update it after each
  * internal TD completes successfully.
  *
@@ -1329,6 +1372,7 @@
 	unsigned long flags;
 
 #ifdef OHCI_DEBUG 
+	if (MegaDebug)
 	printk(KERN_DEBUG "ohci_request_bulk(%p) ohci_dev %p, completion %p, pipe %x, data %p, len %d\n", bulk_request, dev, bulk_request->completion, pipe, data, len);
 #endif
 
@@ -1358,6 +1402,10 @@
 		usb_pipeslow(pipe),
 		usb_pipe_endpdev(pipe), 0 /* bulk uses normal TDs */);
 
+	/* initialize the toggle carry */
+	if (usb_gettoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)))
+		ohci_ed_set_carry(bulk_ed);
+
 	/* initialize the internal counter */
 	bulk_request->_bytes_done = 0;
 
@@ -1365,13 +1413,11 @@
 	 * Add the TDs to the ED
 	 */
 	spin_lock_irqsave(&ohci_edtd_lock, flags);
-	bulk_ed->status |= OHCI_ED_SKIP;
-	head_td = ohci_add_td_chain_to_ed(head_td, bulk_ed);
-	bulk_ed->status &= ~OHCI_ED_SKIP;
-	ohci_unhalt_ed(bulk_ed);
+	head_td = ohci_add_tds_to_ed(head_td, bulk_ed);
+	bulk_ed->status &= cpu_to_le32(~OHCI_ED_SKIP);
+	/* ohci_unhalt_ed(bulk_ed); */
 	spin_unlock_irqrestore(&ohci_edtd_lock, flags);
 
-
 #ifdef OHCI_DEBUG
 	if (MegaDebug) {
 	/* complete request debugging output (before) */
@@ -1414,7 +1460,8 @@
 	struct ohci_bulk_request_state req;
 	struct ohci_ed *req_ed;
 
-#ifdef OHCI_DEBUG 
+#ifdef OHCI_DEBUG
+	if (MegaDebug)
 	printk(KERN_DEBUG "ohci_bulk_msg %p pipe %x, data %p, len %d, bytes_transferred %p\n", usb_dev, pipe, data, len, bytes_transferred_p);
 #endif
 
@@ -1430,6 +1477,12 @@
 	req.bytes_transferred_p = bytes_transferred_p;
 	req.dev_id = &completion_status;
 	req.completion = ohci_bulk_msg_completed;
+	if (bytes_transferred_p)
+		*bytes_transferred_p = 0;
+
+	if (usb_endpoint_halted(usb_dev, usb_pipeendpoint(pipe))
+	    && usb_clear_halt(usb_dev, usb_pipeendpoint(pipe) | (pipe & 0x80)))
+		return USB_ST_STALL;
 
 	/*
 	 * Start the transaction..
@@ -1442,7 +1495,8 @@
 	/* FIXME this should to wait for a caller specified time... */
 	schedule_timeout(HZ*5);
 
-	/* it'll only stay in this state of the request never finished */
+	/* completion_status will only stay in this state of the
+	 * request never finished */
 	if (completion_status == USB_ST_INTERNALERROR) {
 		struct ohci_device *dev = usb_to_ohci(usb_dev);
 		struct ohci_regs *regs = dev->ohci->regs;
@@ -1485,9 +1539,15 @@
 
 	/* remove the ED from the HC */
 	ohci_remove_bulk_ed(usb_to_ohci(usb_dev)->ohci, req_ed);
+
+	/* save the toggle value back into the usb_dev */
+	usb_settoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe),
+		      ohci_ed_carry(req_ed));
+
 	ohci_free_ed(req_ed);	 /* return it to the pool */
 
 #ifdef OHCI_DEBUG
+	if (completion_status != 0 || MegaDebug)
 	printk(KERN_DEBUG "ohci_bulk_msg done, status %x (bytes_transferred = %ld).\n", completion_status, *bytes_transferred_p);
 #endif
 
@@ -1659,7 +1719,6 @@
 
 	struct ohci_device *root_hub=usb_to_ohci(ohci->bus->root_hub);
 
-	fminterval = readl(&ohci->regs->fminterval) & 0x3fff;
 #if 0
 	printk(KERN_DEBUG "entering start_hc %p\n", ohci);
 #endif
@@ -1671,16 +1730,22 @@
 	writel(virt_to_bus(root_hub->hcca), &ohci->regs->hcca);
 
 	/*
-	 * XXX Should fminterval also be set here?
-	 * The spec suggests 0x2edf [11,999]. (FIXME: make this a constant)
+	 * fminterval has to be 11999 (it can be adjusted +/- 1
+	 * to sync with other things if necessary).
 	 */
-	/* fminterval |= (0x2edf << 16); */
-	fminterval = (10240 << 16) | 11999;
-	writel(fminterval, &ohci->regs->fminterval);
+	fminterval = 11999;
+
 	/* Start periodic transfers at 90% of fminterval (fmremaining
 	 * counts down; this will put them in the first 10% of the
 	 * frame). */
-	writel((0x2edf*9)/10, &ohci->regs->periodicstart);
+	writel((fminterval * 9) / 10, &ohci->regs->periodicstart);
+
+	/* Set largest data packet counter and frame interval. */
+	fminterval |= ((fminterval - 210) * 6 / 7) << 16;
+	writel(fminterval, &ohci->regs->fminterval);
+
+	/* Set low-speed threshold (value from MacOS) */
+	writel(1576, &ohci->regs->lsthresh);
 
 	/*
 	 * FNO (frame number overflow) could be enabled...  they
@@ -1926,7 +1991,8 @@
 	struct ohci_td *td;		/* used for walking the list */
 
 	/* um... isn't this dangerous to do in an interrupt handler? -greg */
-//	spin_lock(&ohci_edtd_lock);
+	/* nope. -paulus */
+	spin_lock(&ohci_edtd_lock);
 
 	/* create the FIFO ordered donelist */
 	td = ohci_reverse_donelist(ohci);
@@ -1934,18 +2000,33 @@
 	while (td != NULL) {
 		struct ohci_td *next_td = td->next_dl_td;
 		int cc = OHCI_TD_CC_GET(le32_to_cpup(&td->info));
+		struct ohci_ed *ed = td->ed;
 
 		if (td_dummy(*td))
 			printk(KERN_ERR "yikes! reaping a dummy TD\n");
 
-		if (cc != 0 && ohci_ed_halted(td->ed) && !td_endofchain(*td)) {
+#ifdef OHCI_DEBUG
+		if (cc != 0 && MegaDebug) {
+			printk("cc=%s on td %p (ed %p)\n", cc_names[cc], td, ed);
+			show_ohci_td(td);
+			show_ohci_ed(ed);
+			if (ed_head_td(ed) != ed_tail_td(ed))
+				show_ohci_td_chain(bus_to_virt(ed_head_td(ed)));
+		}
+#endif
+
+		if (cc == USB_ST_STALL) {
+			/* mark endpoint as halted */
+			usb_endpoint_halt(ed->ohci_dev->usb, ed_get_en(ed));
+		}
+
+		if (cc != 0 && ohci_ed_halted(ed) && !td_endofchain(*td)) {
 			/*
 			 * There was an error on this TD and the ED
 			 * is halted, and this was not the last TD
 			 * of the transaction, so there will be TDs
 			 * to clean off the ED.
 			 */
-			struct ohci_ed *ed = td->ed;
 			struct ohci_td *tail_td = bus_to_virt(ed_tail_td(ed));
 			struct ohci_td *ntd;
 
@@ -1953,24 +2034,17 @@
 			td = ntd = bus_to_virt(ed_head_td(ed));
 			while (td != tail_td) {
 				ntd = bus_to_virt(le32_to_cpup(&td->next_td));
+				if (td_endofchain(*td))
+					break;
 
-				/* only deal with TDs from this ED,
-				 * the host controller could have
-				 * processed other endpoints at the
-				 * same time as this one.. */
-				if (td->ed == ed) {
-					if (td_endofchain(*td))
-						break;
-
-					/* FIXME: unlink this TD from the
-					 * reverse donelist! */
-					ohci_free_td(td);
-				}
+				printk(KERN_DEBUG "skipping TD %p\n", td);
+				ohci_free_td(td);
 
 				td = ntd;
 			}
 			/* Set the ED head past the ones we cleaned
 			   off, and clear the halted flag */
+			printk(KERN_DEBUG "restarting ED %p at TD %p\n", ed, ntd);
 			set_ed_head_td(ed, virt_to_bus(ntd));
 			ohci_unhalt_ed(ed);
 			/* If we didn't find an endofchain TD, give up */
@@ -1996,8 +2070,9 @@
 			td->cur_buf = cpu_to_le32(virt_to_bus(td->data));
 
 			/* insert it back on its ED */
-			ohci_add_td_to_ed(td, td, td->ed);
-			ohci_unhalt_ed(td->ed);
+			td->next_td = 0;
+			ohci_add_tds_to_ed(td, ed);
+			/* ohci_unhalt_ed(td->ed); */
 		} else {
 			/* return it to the pool of free TDs */
 			if (can_auto_free(*td))
@@ -2007,7 +2082,7 @@
 		td = next_td;
 	}
 
-//	spin_unlock(&ohci_edtd_lock);
+	spin_unlock(&ohci_edtd_lock);
 } /* ohci_reap_donelist() */
 
 
@@ -2259,8 +2334,10 @@
 	writel(0, &ohci->regs->ed_bulkhead);
 
 #ifdef OHCI_DEBUG
+	if (MegaDebug) {
 	printk(KERN_DEBUG "alloc_ohci(): controller\n");
 	show_ohci_status(ohci);
+	}
 #endif
 
 #if 0
@@ -2333,7 +2410,7 @@
 	printk(KERN_DEBUG "ohci-control thread code for 0x%p code at 0x%p\n", __ohci, &ohci_control_thread);
 	exit_mm(current);
 	exit_files(current);
-	exit_fs(current);
+	/*exit_fs(current);*/	/* can't do kernel_thread if we do this */
 
 	strcpy(current->comm, "ohci-control");
 
@@ -2398,6 +2475,7 @@
 #endif
 			} else {
 				/* unknown signal, exit the thread */
+				printk(KERN_DEBUG "usb-ohci: control thread for %p exiting on signal %ld\n", __ohci, signr);
 				break;
 			}
 		}
@@ -2406,7 +2484,6 @@
 	reset_hc(ohci);
 	release_ohci(ohci);
 	usb_deregister_bus(ohci->bus);
-	printk(KERN_DEBUG "ohci-control thread for 0x%p exiting\n", __ohci);
 
 	return 0;
 } /* ohci_control_thread() */
diff -u --recursive --new-file v2.3.11/linux/drivers/usb/ohci.h linux/drivers/usb/ohci.h
--- v2.3.11/linux/drivers/usb/ohci.h	Wed Jul 21 15:46:48 1999
+++ linux/drivers/usb/ohci.h	Sun Jul 25 20:30:46 1999
@@ -41,8 +41,7 @@
 		/* bit0: Is this TD allocated? */
 		/* bit1: Is this a dummy (end of list) TD? */
 		/* bit2: do NOT automatically free this TD on completion */
-		/* bit3: this is NOT the last TD in a contiguious TD chain
-		 *       on the indicated ED.  (0 means it is the last) */
+		/* bit3: this is the last TD in a contiguious TD chain */
 
 	struct usb_device *usb_dev;	/* the owning device */
 
@@ -86,9 +85,9 @@
 #define make_dumb_td(td)	((td)->hcd_flags |= 2)
 #define clear_dumb_td(td)	((td)->hcd_flags &= ~(__u32)2)
 
-#define td_endofchain(td)	(!((td).hcd_flags & (1 << 3)))
-#define set_td_endofchain(td)	((td)->hcd_flags &= ~(1 << 3))
-#define clear_td_endofchain(td)	((td)->hcd_flags |= (1 << 3))
+#define td_endofchain(td)	((td).hcd_flags & (1 << 3))
+#define clear_td_endofchain(td)	((td)->hcd_flags &= ~(1 << 3))
+#define set_td_endofchain(td)	((td)->hcd_flags |= (1 << 3))
 
 /*
  * These control if the IRQ will call ohci_free_td after taking the TDs
@@ -109,6 +108,10 @@
 	__u32 tail_td;	/* TD Queue tail pointer */
 	__u32 _head_td;	/* TD Queue head pointer, toggle carry & halted bits */
 	__u32 next_ed;	/* Next ED */
+
+	/* driver fields */
+	struct ohci_device *ohci_dev;
+	struct ohci_ed	*ed_chain;
 } __attribute((aligned(16)));
 
 /* get the head_td */
@@ -119,10 +122,13 @@
 #define set_ed_head_td(ed, td)	((ed)->_head_td = cpu_to_le32((td)) \
 				 | ((ed)->_head_td & cpu_to_le32(3)))
 
-/* Control the ED's halted flag */
+/* Control the ED's halted and carry flags */
 #define ohci_halt_ed(ed)	((ed)->_head_td |= cpu_to_le32(1))
 #define ohci_unhalt_ed(ed)	((ed)->_head_td &= cpu_to_le32(~(__u32)1))
 #define ohci_ed_halted(ed)	((ed)->_head_td & cpu_to_le32(1))
+#define ohci_ed_set_carry(ed)	((ed)->_head_td |= cpu_to_le32(2))
+#define ohci_ed_clr_carry(ed)	((ed)->_head_td &= ~cpu_to_le32(2))
+#define ohci_ed_carry(ed)	((le32_to_cpup(&(ed)->_head_td) >> 1) & 1)
 
 #define OHCI_ED_SKIP	(1 << 14)
 #define OHCI_ED_MPS	(0x7ff << 16)
@@ -142,6 +148,8 @@
 #define OHCI_ED_EN	(0xf << 7)
 #define OHCI_ED_FA	(0x7f)
 
+#define ed_get_en(ed)	((le32_to_cpup(&(ed)->status) & OHCI_ED_EN) >> 7)
+#define ed_get_fa(ed)	(le32_to_cpup(&(ed)->status) & OHCI_ED_FA)
 
 /* NOTE: bits 27-31 of the status dword are reserved for the HCD */
 /*
diff -u --recursive --new-file v2.3.11/linux/drivers/usb/proc_usb.c linux/drivers/usb/proc_usb.c
--- v2.3.11/linux/drivers/usb/proc_usb.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/proc_usb.c	Wed Jul 28 10:45:39 1999
@@ -0,0 +1,487 @@
+/*
+ * drivers/usb/proc_usb.c
+ * (C) Copyright 1999 Randy Dunlap.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *************************************************************
+ *
+ * This is a /proc/bus/usb filesystem output module for USB.
+ * It creates /proc/bus/usb/drivers and /proc/bus/usb/devices.
+ *
+ * /proc/bus/usb/devices contains USB topology, device, config, class,
+ * interface, & endpoint data.
+ *
+ * I considered using /proc/bus/usb/devices/device# for each device
+ * as it is attached or detached, but I didn't like this for some
+ * reason -- maybe it's just too deep of a directory structure.
+ * I also don't like looking in multiple places to gather and view
+ * the data.  Having only one file for ./devices also prevents race
+ * conditions that could arise if a program was reading device info
+ * for devices that are being removed (unplugged).  (That is, the
+ * program may find a directory for devnum_12 then try to open it,
+ * but it was just unplugged, so the directory is now deleted.
+ * But programs would just have to be prepared for situations like
+ * this in any plug-and-play environment.)
+ */
+
+#define __KERNEL__	1
+
+#include <linux/types.h>
+#include <asm/types.h>
+#include <linux/kernel.h>
+/* #include <linux/module.h> */
+#include <linux/fs.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+#include <linux/list.h>
+
+#include "usb.h"
+
+#define DUMP_LIMIT		(PAGE_SIZE - 100)
+	/* limit to only one memory page of output */
+
+#define MAX_TOPO_LEVEL		6
+
+
+static char *format_topo =
+/* T:  Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=ddd If#=ddd MxCh=dd Driver=%s */
+  "T:  Lev=%2.2d Prnt=%2.2d Port=%2.2d Cnt=%2.2d Dev#=%3d Spd=%3s If#=%3d MxCh=%2d Driver=%s\n";
+  
+static char *format_device1 =
+/* D:  Ver=xx.xx Cls=xx(sssss) Sub=xx Prot=xx MxPS=dd #Cfgs=dd */
+  "D:  Ver=%2x.%02x Cls=%02x(%-5s) Sub=%02x Prot=%02x MxPS=%2d #Cfgs=%3d\n";
+
+static char *format_device2 =
+/* P:  Vendor=xxxx ProdID=xxxx Rev=xx.xx */
+  "P:  Vendor=%04x ProdID=%04x Rev=%2x.%02x\n";
+
+static char *format_config =
+/* C:  #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA */
+  "C:%c #Ifs=%2d Cfg#=%2d Atr=%02x MxPwr=%3dmA\n";
+  
+static char *format_iface =
+/* I:  If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx */
+  "I:  If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x\n";
+
+static char *format_endpt =
+/* E:  Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms */
+  "E:  Ad=%02x(%c) Atr=%02x(%-4s) MxPS=%4d Ivl=%3dms\n";
+
+
+/*
+ * Need access to the driver and USB bus lists.
+ * extern struct list_head usb_driver_list;
+ * extern struct list_head usb_bus_list;
+ * However, these will come from functions that return ptrs to each of them.
+ */
+
+extern struct list_head *usb_driver_get_list (void);
+extern struct list_head *usb_bus_get_list (void);
+
+extern struct proc_dir_entry *proc_bus;
+
+static struct proc_dir_entry *usbdir = NULL, *driversdir = NULL;
+static struct proc_dir_entry *devicesdir = NULL;
+
+struct class_info {
+	int class;
+	char *class_name;
+};
+
+struct class_info clas_info [] =
+{					/* max. 5 chars. per name string */
+	{USB_CLASS_PER_INTERFACE,	">ifc"},
+	{USB_CLASS_AUDIO,		"audio"},
+	{USB_CLASS_COMM,		"comm."},
+	{USB_CLASS_HID,			"HID"},
+	{USB_CLASS_HUB,			"hub"},
+	{USB_CLASS_PRINTER,		"print"},
+	{USB_CLASS_MASS_STORAGE,	"stor."},
+	{USB_CLASS_VENDOR_SPEC,		"vend."},
+	{-1,				"unk."}		/* leave as last */
+};
+
+/*****************************************************************/
+
+static char *class_decode (const int class)
+{
+	int	ix;
+
+	for (ix = 0; clas_info [ix].class != -1; ix++)
+		if (clas_info [ix].class == class)
+			break;
+
+	return (clas_info [ix].class_name);
+}
+static int usb_dump_endpoint_descriptor (const struct usb_endpoint_descriptor *desc,
+					char *buf, int *len)
+{
+	char *EndpointType [4] = {"Ctrl", "Isoc", "Bulk", "Int."};
+
+	*len += sprintf (buf + *len, format_endpt,
+		desc->bEndpointAddress,
+		(desc->bEndpointAddress & USB_DIR_IN) ? 'I' : 'O',
+		desc->bmAttributes,
+		EndpointType[desc->bmAttributes & 3],
+		desc->wMaxPacketSize,
+		desc->bInterval
+		);
+
+	return (*len >= DUMP_LIMIT) ? -1 : 0;
+}
+
+static int usb_dump_endpoint (const struct usb_endpoint_descriptor *endpoint,
+				char *buf, int *len)
+{
+	if (usb_dump_endpoint_descriptor (endpoint, buf, len) < 0)
+		return -1;
+
+	return 0;
+}
+
+static int usb_dump_interface_descriptor (const struct usb_interface_descriptor *desc,
+						char *buf, int *len)
+{
+	*len += sprintf (buf + *len, format_iface,
+		desc->bInterfaceNumber,
+		desc->bAlternateSetting,
+		desc->bNumEndpoints,
+		desc->bInterfaceClass,
+		class_decode (desc->bInterfaceClass),
+		desc->bInterfaceSubClass,
+		desc->bInterfaceProtocol
+		);
+
+	return (*len >= DUMP_LIMIT) ? -1 : 0;
+}
+
+static int usb_dump_interface (const struct usb_interface_descriptor *interface,
+				char *buf, int *len)
+{
+	int i;
+
+	if (usb_dump_interface_descriptor (interface, buf, len) < 0)
+		return -1;
+
+	for (i = 0; i < interface->bNumEndpoints; i++) {
+		if (usb_dump_endpoint (interface->endpoint + i, buf, len) < 0)
+			return -1;
+	}
+
+	return 0;
+}
+
+/* TBD:
+ * 0. TBDs
+ * 1. marking active config and ifaces (code lists all, but should mark
+ *    which ones are active, if any)
+ * 2. Add proc_usb_init() call from usb-core.c.
+ * 3. proc_usb as a MODULE ?
+ * 4. use __initfunc() ?
+ * 5. add <halted> status to each endpoint line
+ */
+
+static int usb_dump_config_descriptor (const struct usb_config_descriptor *desc,
+					const int active, char *buf, int *len)
+{
+	*len += sprintf (buf + *len, format_config,
+		active ? '*' : ' ',	/* mark active/actual/current cfg. */
+		desc->bNumInterfaces,
+		desc->bConfigurationValue,
+		desc->bmAttributes,
+		desc->MaxPower * 2
+		);
+
+	return (*len >= DUMP_LIMIT) ? -1 : 0;
+}
+
+static int usb_dump_config (const struct usb_config_descriptor *config,
+				const int active, char *buf, int *len)
+{
+	int i, j;
+	struct usb_alternate_setting *as;
+
+	if (!config) {		/* getting these some in 2.3.7; none in 2.3.6 */
+		*len += sprintf (buf + *len, "(null Cfg. desc.)\n");
+		return 0;
+	}
+
+	if (usb_dump_config_descriptor (config, active, buf, len) < 0)
+		return -1;
+
+	for (i = 0; i < config->num_altsetting; i++) {
+		as = config->altsetting + i;
+		if ((as) == NULL)
+			break;
+
+		for (j = 0; j < config->bNumInterfaces; j++)
+			if (usb_dump_interface (as->interface + j, buf, len) < 0)
+				return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * Dump the different USB descriptors.
+ */
+static int usb_dump_device_descriptor (const struct usb_device_descriptor *desc,
+				char *buf, int *len)
+{
+	*len += sprintf (buf + *len, format_device1,
+			desc->bcdUSB >> 8, desc->bcdUSB & 0xff,
+			desc->bDeviceClass,
+			class_decode (desc->bDeviceClass),
+			desc->bDeviceSubClass,
+			desc->bDeviceProtocol,
+			desc->bMaxPacketSize0,
+			desc->bNumConfigurations
+			);
+	if (*len >= DUMP_LIMIT) return -1;
+
+	*len += sprintf (buf + *len, format_device2,
+			desc->idVendor, desc->idProduct,
+			desc->bcdDevice >> 8, desc->bcdDevice & 0xff
+			);
+
+	return (*len >= DUMP_LIMIT) ? -1 : 0;
+}
+
+static int usb_dump_desc (const struct usb_device *dev, char *buf, int *len)
+{
+	int i;
+
+	if (usb_dump_device_descriptor (&dev->descriptor, buf, len) < 0)
+		return -1;
+
+	for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
+		if (usb_dump_config (dev->config + i,
+			(dev->config + i) == dev->actconfig, /* active ? */
+			buf, len) < 0)
+				return -1;
+	}
+
+	return 0;
+}
+
+#ifdef PROC_EXTRA /* TBD: may want to add this code later */
+
+static int usb_dump_hub_descriptor (const struct usb_hub_descriptor * desc,
+					char *buf, int *len)
+{
+	int leng = USB_DT_HUB_NONVAR_SIZE;
+	unsigned char *ptr = (unsigned char *) desc;
+
+	*len += sprintf (buf + *len, "Interface:");
+
+	while (leng) {
+		*len += sprintf (buf + *len, " %02x", *ptr);
+		ptr++; leng--;
+	}
+	*len += sprintf (buf + *len, "\n");
+
+	return (*len >= DUMP_LIMIT) ? -1 : 0;
+}
+
+static int usb_dump_string (const struct usb_device *dev, char *id, int index,
+				char *buf, int *len)
+{
+	if (index <= dev->maxstring && dev->stringindex && dev->stringindex[index])
+		*len += sprintf (buf + *len, "%s: %s ", id, dev->stringindex[index]);
+
+	return (*len >= DUMP_LIMIT) ? -1 : 0;
+}
+
+#endif /* PROC_EXTRA */
+
+/*****************************************************************/
+
+static int usb_device_dump (char *buf, int *len,
+			const struct usb_device *usbdev,
+			int level, int index, int count)
+{
+	int	chix;
+	int	cnt = 0;
+	int	parent_devnum;
+
+	if (level > MAX_TOPO_LEVEL) return -1;
+
+	parent_devnum = usbdev->parent ? (usbdev->parent->devnum == -1) ? 0
+			: usbdev->parent->devnum : 0;
+		/*
+		 * So the root hub's parent is 0 and any device that is
+		 * plugged into the root hub has a parent of 0.
+		 */
+	*len += sprintf (buf + *len, format_topo,
+		level, parent_devnum, index, count,
+		usbdev->devnum,
+		usbdev->slow ? "1.5" : "12 ",
+		usbdev->ifnum, usbdev->maxchild,
+		usbdev->driver ? usbdev->driver->name :
+		(level == 0) ? "(root hub)" : "(none)"
+		);
+		/*
+		 * level = topology-tier level;
+		 * parent_devnum = parent device number;
+		 * index = parent's connector number;
+		 * count = device count at this level
+		 */
+
+	if (*len >= DUMP_LIMIT)
+		return -1;
+
+	if (usbdev->devnum > 0) {	/* for any except root hub */
+		if (usb_dump_desc (usbdev, buf, len) < 0)
+			return -1;
+	}
+
+	/* Now look at all of this device's children. */
+	for (chix = 0; chix < usbdev->maxchild; chix++) {
+		if (usbdev->children [chix]) {
+			if (usb_device_dump (buf, len,
+				usbdev->children [chix],
+				level + 1, chix, ++cnt) < 0)
+					return -1;
+		}
+	}
+
+	return 0;
+}
+
+static int usb_bus_list_dump (char *buf, int len)
+{
+	struct list_head *usb_bus_list = usb_bus_get_list ();
+	struct list_head *list = usb_bus_list->next;
+
+	len = 0;
+
+	/*
+	 * Go thru each usb_bus. Within each usb_bus: each usb_device.
+	 * Within each usb_device: all of its device & config. descriptors,
+	 * marking the currently active ones.
+	 */
+
+
+        while (list != usb_bus_list) {
+		struct usb_bus *bus = list_entry (list, struct usb_bus, bus_list);
+
+		if (usb_device_dump (buf, &len, bus->root_hub, 0, 0, 0)
+			< 0)
+			break;
+
+	        list = list->next;
+
+		if (len >= DUMP_LIMIT) {
+			len += sprintf (buf + len, "(truncated)\n");
+			break;
+		}
+        }
+
+	return (len);
+}
+
+static int usb_bus_list_dump_devices (char *buf, char **start, off_t offset,
+				int len, int *eof, void *data)
+{
+	return usb_bus_list_dump (buf, len);
+}
+
+/*
+ * Dump usb_driver_list.
+ *
+ * We now walk the list of registered USB drivers.
+ */
+static int usb_driver_list_dump (char *buf, char **start, off_t offset,
+				int len, int *eof, void *data)
+{
+	struct list_head *usb_driver_list = usb_driver_get_list ();
+	struct list_head *tmp = usb_driver_list->next;
+	int cnt = 0;
+
+	len = 0;
+
+	while (tmp != usb_driver_list) {
+		struct usb_driver *driver = list_entry (tmp, struct usb_driver,
+						       driver_list);
+		len += sprintf (buf + len, "%s\n", driver->name);
+		cnt++;
+		tmp = tmp->next;
+
+		if (len >= DUMP_LIMIT)
+		{
+			len += sprintf (buf + len, "(truncated)\n");
+			return (len);
+		}
+	}
+
+	if (!cnt)
+		len += sprintf (buf + len, "(none)\n");
+	return (len);
+}
+
+void proc_usb_cleanup (void)
+{
+	if (driversdir)
+		remove_proc_entry ("drivers", usbdir);
+	if (devicesdir)
+		remove_proc_entry ("devices", usbdir);
+	if (usbdir)
+		remove_proc_entry ("usb", proc_bus);
+}
+
+int proc_usb_init (void)
+{
+	usbdir = create_proc_entry ("usb", S_IFDIR, proc_bus);
+	if (!usbdir) {
+		printk ("proc_usb: cannot create /proc/bus/usb entry\n");
+		return -1;
+	}
+
+	driversdir = create_proc_entry ("drivers", 0, usbdir);
+	if (!driversdir) {
+		printk ("proc_usb: cannot create /proc/bus/usb/drivers entry\n");
+		proc_usb_cleanup ();
+		return -1;
+	}
+	driversdir->read_proc = usb_driver_list_dump;
+
+	devicesdir = create_proc_entry ("devices", 0, usbdir);
+	if (!devicesdir) {
+		printk ("proc_usb: cannot create /proc/bus/usb/devices entry\n");
+		proc_usb_cleanup ();
+		return -1;
+	}
+	devicesdir->read_proc = usb_bus_list_dump_devices;
+
+	return 0;
+}
+
+#ifdef PROCFS_MODULE /* TBD: support proc_fs MODULE ??? */
+
+int init_module (void)
+{
+	return proc_usb_init ();
+}
+
+void cleanup_module (void)
+{
+	proc_usb_cleanup ();
+}
+
+#endif /* PROCFS_MODULE */
+
+/* end proc_usb.c */
diff -u --recursive --new-file v2.3.11/linux/drivers/usb/procusb linux/drivers/usb/procusb
--- v2.3.11/linux/drivers/usb/procusb	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/procusb	Tue Jul 27 16:05:50 1999
@@ -0,0 +1,41 @@
+#!/usr/bin/perl
+
+# Reads /proc/bus/usb/devices and selectively lists and/or
+# interprets it.
+
+$DEVFILENAME = "/proc/bus/usb/devices";
+$PROGNAME = $0;
+
+$TAGS = $ARGV[0];		# save user TAGS
+if (length ($TAGS) == 0)
+{
+	print "usage: $PROGNAME tags\n";
+	print "  where 'tags' can be any number of 'TDPCIE' or 'A(LL)'\n";
+	exit 1;
+}
+
+$ALL = ($TAGS =~ /all/i) || ($TAGS =~ /a/i);
+
+# TBD: Check that $TAGS is valid.
+if (! $ALL)
+{
+}
+
+if (! open (DEVNUM, "<$DEVFILENAME"))
+{
+	print "$PROGNAME: cannot open '$DEVFILENAME'\n";
+	exit 1;
+}
+
+while ($line = <DEVNUM>)	# read a text line from DEVNUM
+{
+	if (($ALL) || ($line =~ /^[$TAGS]:/i))	# any of TAGS at beg. of line?
+	{
+		print "$line";	# still has newline char on it
+				# TBD: add more/paging functionality.
+	}
+} # end while DEVNUM
+
+close (DEVNUM);
+
+# END.
diff -u --recursive --new-file v2.3.11/linux/drivers/usb/uhci.c linux/drivers/usb/uhci.c
--- v2.3.11/linux/drivers/usb/uhci.c	Wed Jul 21 15:46:48 1999
+++ linux/drivers/usb/uhci.c	Mon Jul 26 16:05:45 1999
@@ -361,7 +361,7 @@
 	unsigned int destination, status;
 
 	/* Destination: pipe destination with INPUT */
-	destination = (pipe & PIPE_DEVEP_MASK) | 0x69;
+	destination = (pipe & PIPE_DEVEP_MASK) | usb_packetid (pipe);
 
 	/* Status:    slow/fast,      Interrupt,   Active,    Short Packet Detect     Infinite Errors */
 	status = (pipe & (1 << 26)) | (1 << 24) | (1 << 23)   |   (1 << 29)       |    (0 << 27);
@@ -371,7 +371,7 @@
 		       interrupt_qh->element);
 
 	td->link = 1;
-	td->status = status;			/* In */
+	td->status = status;
 	td->info = destination | ((usb_maxpacket(usb_dev, pipe) - 1) << 21) |
 		(usb_gettoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)) << 19);
 	td->buffer = virt_to_bus(dev->data);
@@ -633,12 +633,8 @@
 		td = &isodesc->td[i];
 
 		/* The "pipe" thing contains the destination in bits 8--18 */
-		destination = (pipe & PIPE_DEVEP_MASK);
-
-		if (usb_pipeout(pipe))
-			destination |= 0xE1;	/* OUT */
-		else
-			destination |= 0x69;	/* IN */
+		destination = (pipe & PIPE_DEVEP_MASK)
+			| usb_packetid (pipe);	/* add IN or OUT */
 
 		/* Status:    slow/fast,       Active,       Isochronous */
 		status = (pipe & (1 << 26)) | (1 << 23)   |   (1 << 25);
@@ -1010,18 +1006,8 @@
 	if (len > maxsze * 31)
 		printk("Warning, too much data for a bulk packet, crashing (%d/%d)\n", len, maxsze);
 
-	/* The "pipe" thing contains the destination in bits 8--18, 0x69 is IN */
-	/*
-	  IS THIS NECCESARY? PERHAPS WE CAN JUST USE THE PIPE
-	  LOOK AT: usb_pipeout and the pipe bits
-	  I FORGOT WHAT IT EXACTLY DOES
-	*/
-	if (usb_pipeout(pipe)) {
-		destination = (pipe & PIPE_DEVEP_MASK) | 0xE1;
-	}
-	else {
-		destination = (pipe & PIPE_DEVEP_MASK) | 0x69;
-	}
+	/* The "pipe" thing contains the destination in bits 8--18 */
+	destination = (pipe & PIPE_DEVEP_MASK) | usb_packetid (pipe);
 
 	/* Status:    slow/fast,       Active,    Short Packet Detect     Three Errors */
 	status = (pipe & (1 << 26)) | (1 << 23)   |   (1 << 29)       |    (3 << 27);
diff -u --recursive --new-file v2.3.11/linux/drivers/usb/usb-core.c linux/drivers/usb/usb-core.c
--- v2.3.11/linux/drivers/usb/usb-core.c	Wed Jun 16 19:26:27 1999
+++ linux/drivers/usb/usb-core.c	Tue Jul 27 16:05:50 1999
@@ -28,6 +28,7 @@
 #	endif
 #endif
 
+
 int usb_init(void)
 {
 #ifndef CONFIG_USB_MODULE
@@ -65,6 +66,9 @@
 		usb_scsi_init();
 #	endif
 #endif
+#ifdef CONFIG_USB_PROC
+	proc_usb_init ();
+#endif
 	return 0;
 }
 /*
@@ -72,6 +76,9 @@
  */
 void cleanup_drivers(void)
 {
+#ifdef CONFIG_USB_PROC
+	proc_usb_cleanup ();
+#endif
 #ifndef MODULE
 #	ifdef CONFIG_USB_HUB
 		usb_hub_cleanup();
diff -u --recursive --new-file v2.3.11/linux/drivers/usb/usb.c linux/drivers/usb/usb.c
--- v2.3.11/linux/drivers/usb/usb.c	Wed Jul 21 15:46:48 1999
+++ linux/drivers/usb/usb.c	Wed Jul 28 10:45:39 1999
@@ -36,6 +36,7 @@
  * 6		wLength		2	Count		Bytes for data
  */
 
+#include <linux/config.h>
 #include <linux/string.h>
 #include <linux/bitops.h>
 #include <linux/malloc.h>
@@ -1140,3 +1141,15 @@
 {
 	return dev->bus->op->release_irq(handle);
 }
+
+#ifdef CONFIG_PROC_FS
+struct list_head * usb_driver_get_list (void)
+{
+	return &usb_driver_list;
+}
+
+struct list_head * usb_bus_get_list (void)
+{
+	return &usb_bus_list;
+}
+#endif
diff -u --recursive --new-file v2.3.11/linux/drivers/usb/usb.h linux/drivers/usb/usb.h
--- v2.3.11/linux/drivers/usb/usb.h	Wed Jul 21 15:46:48 1999
+++ linux/drivers/usb/usb.h	Mon Jul 26 16:05:45 1999
@@ -406,6 +406,7 @@
 #define usb_packetid(pipe)	(((pipe) & 0x80) ? 0x69 : 0xE1)
 
 #define usb_pipeout(pipe)	((((pipe) >> 7) & 1) ^ 1)
+#define usb_pipein(pipe)	(((pipe) >> 7) & 1)
 #define usb_pipedevice(pipe)	(((pipe) >> 8) & 0x7f)
 #define usb_pipe_endpdev(pipe)	(((pipe) >> 8) & 0x7ff)
 #define usb_pipeendpoint(pipe)	(((pipe) >> 15) & 0xf)
diff -u --recursive --new-file v2.3.11/linux/drivers/usb/usb_scsi.c linux/drivers/usb/usb_scsi.c
--- v2.3.11/linux/drivers/usb/usb_scsi.c	Wed Jun 30 13:38:20 1999
+++ linux/drivers/usb/usb_scsi.c	Sun Jul 25 20:30:47 1999
@@ -139,10 +139,20 @@
 	this_xfer = length > max_size ? max_size : length;
 	length -= this_xfer;
 	do {
-	    US_DEBUGP("Bulk xfer %x(%d)\n", (unsigned int)buf, this_xfer);
+	    /*US_DEBUGP("Bulk xfer %x(%d)\n", (unsigned int)buf, this_xfer);*/
 	    result = us->pusb_dev->bus->op->bulk_msg(us->pusb_dev, pipe, buf, 
 						    this_xfer, &partial);
 
+	    if (result != 0 || partial != this_xfer)
+		US_DEBUGP("bulk_msg returned %d xferred %lu/%d\n",
+			  result, partial, this_xfer);
+
+	    if (result == USB_ST_STALL) {
+		US_DEBUGP("clearing endpoing halt for pipe %x\n", pipe);
+		usb_clear_halt(us->pusb_dev,
+			       usb_pipeendpoint(pipe) | (pipe & 0x80));
+	    }
+
 	    /* we want to retry if the device reported NAK */
 	    if (result == USB_ST_TIMEOUT) {
 		if (partial != this_xfer) {
@@ -171,28 +181,31 @@
     return 0;
 
 }
+
 static int us_transfer(Scsi_Cmnd *srb, int dir_in)
 {
     struct us_data *us = (struct us_data *)srb->host_scribble;
     int i;
     int result = -1;
+    unsigned int pipe = dir_in ? usb_rcvbulkpipe(us->pusb_dev, us->ep_in) :
+	    usb_sndbulkpipe(us->pusb_dev, us->ep_out);
 
     if (srb->use_sg) {
 	struct scatterlist *sg = (struct scatterlist *) srb->request_buffer;
 
 	for (i = 0; i < srb->use_sg; i++) {
-	    result = us_one_transfer(us, dir_in ? usb_rcvbulkpipe(us->pusb_dev, us->ep_in) :
-						  usb_sndbulkpipe(us->pusb_dev, us->ep_out),
-				     sg[i].address, sg[i].length);
+	    result = us_one_transfer(us, pipe, sg[i].address, sg[i].length);
 	    if (result)
 		break;
 	}
-	return result;
     }
     else
-	return us_one_transfer(us, dir_in ? usb_rcvbulkpipe(us->pusb_dev, us->ep_in) :
-					    usb_sndbulkpipe(us->pusb_dev, us->ep_out),
-			       srb->request_buffer, srb->request_bufflen);
+	result = us_one_transfer(us, pipe,
+				 srb->request_buffer, srb->request_bufflen);
+
+    if (result)
+	US_DEBUGP("us_transfer returning error %d\n", result);
+    return result;
 }
 
 static unsigned int us_transfer_length(Scsi_Cmnd *srb)
@@ -232,12 +245,13 @@
     struct us_data *us = (struct us_data *)dev_id;
 
     if (state != USB_ST_REMOVED) {
-	us->ip_data = *(__u16 *)buffer;
-	US_DEBUGP("Interrupt Status %x\n", us->ip_data);
+	us->ip_data = le16_to_cpup((__u16 *)buffer);
+	/* US_DEBUGP("Interrupt Status %x\n", us->ip_data); */
     }
-    if (us->ip_wanted)
+    if (us->ip_wanted) {
+	us->ip_wanted = 0;
 	wake_up(&us->ip_waitq);
-    us->ip_wanted = 0;
+    }
 
     /* we dont want another interrupt */
 
@@ -250,6 +264,7 @@
     devrequest dr;
     int result;
 
+    US_DEBUGP("pop_CB_reset\n");
     dr.requesttype = USB_TYPE_CLASS | USB_RT_INTERFACE;
     dr.request = US_CBI_ADSC;
     dr.value = 0;
@@ -262,12 +277,15 @@
 					usb_sndctrlpipe(us->pusb_dev,0),
 					&dr, cmd, 12);
 
-    usb_clear_halt(us->pusb_dev, us->ep_in | 0x80);
-    usb_clear_halt(us->pusb_dev, us->ep_out);
-
     /* long wait for reset */
 
     schedule_timeout(HZ*5);
+
+    US_DEBUGP("pop_CB_reset: clearing endpoint halt\n");
+    usb_clear_halt(us->pusb_dev, us->ep_in | 0x80);
+    usb_clear_halt(us->pusb_dev, us->ep_out);
+
+    US_DEBUGP("pop_CB_reset done\n");
     return 0;
 }
 
@@ -325,6 +343,7 @@
 		/* as per spec try a start command, wait and retry */
 
 		done_start++;
+		memset(cmd, 0, sizeof(cmd));
 		cmd[0] = START_STOP;
 		cmd[4] = 1;		/* start */
 		result = us->pusb_dev->bus->op->control_msg(us->pusb_dev, 
@@ -338,7 +357,7 @@
 	    result = us->pusb_dev->bus->op->control_msg(us->pusb_dev, 
 						  usb_sndctrlpipe(us->pusb_dev,0),
 						  &dr, srb->cmnd, srb->cmd_len);
-	if (result != USB_ST_STALL && result != USB_ST_TIMEOUT)
+	if (/*result != USB_ST_STALL &&*/ result != USB_ST_TIMEOUT)
 	    return result;
     }
     return result;
@@ -356,6 +375,7 @@
     devrequest dr;
     int retry = 5;
 
+    US_DEBUGP("pop_CB_status, proto=%x\n", us->protocol);
     switch (us->protocol) {
     case US_PR_CB:
 	/* get from control */
@@ -439,23 +459,26 @@
 	if (result == USB_ST_STALL || result == USB_ST_TIMEOUT)	{
 	    return (DID_OK << 16) | 2;
 	}
-	return DID_ABORT << 16;
+	return DID_ERROR << 16;
     }
 
     /* transfer the data */
 
     if (us_transfer_length(srb)) {
 	result = us_transfer(srb, US_DIRECTION(srb->cmnd[0]));
-	if (result && result != USB_ST_DATAUNDERRUN) {
+	if (result && result != USB_ST_DATAUNDERRUN && result != USB_ST_STALL) {
 	    US_DEBUGP("CBI  transfer %x\n", result);
-	    return DID_ABORT << 16;
-	} else if (result == USB_ST_DATAUNDERRUN) {
+	    return DID_ERROR << 16;
+	}
+#if 0
+	else if (result == USB_ST_DATAUNDERRUN) {
 	    return DID_OK << 16;
 	}
     } else {
 	if (!result) {
 	    return DID_OK << 16;
 	}
+#endif
     }
 
     /* get status */
@@ -947,6 +970,7 @@
 			    US_DEBUGP("Old/New length = %d/%d\n", savelen, length);
 
 			    if (us->srb->request_bufflen != length) {
+			        US_DEBUGP("redoing cmd with len=%d\n", length);
 				us->srb->request_bufflen = length;
 				us->srb->result = us->pop(us->srb);
 			    }
@@ -957,6 +981,15 @@
 			    case REQUEST_SENSE:
 			    case INQUIRY:
 			    case MODE_SENSE:
+				if (us->srb->use_sg == 0 && length > 0) {
+				    int i;
+				    printk(KERN_DEBUG "Data is");
+				    for (i = 0; i < 32 && i < length; ++i)
+					printk(" %.2x", ((unsigned char *)us->srb->request_buffer)[i]);
+				    if (i < length)
+					printk(" ...");
+				    printk("\n");
+				}
 				us->srb->cmnd[4] = saveallocation;
 				break;
 
@@ -969,6 +1002,7 @@
 			}
 			/* force attention on first command */
 			if (!us->attention_done) {
+			    US_DEBUGP("forcing unit attention\n");
 			    if (us->srb->cmnd[0] == REQUEST_SENSE) {
 				if (us->srb->result == (DID_OK << 16)) {
 				    unsigned char *p = (unsigned char *)us->srb->request_buffer;
@@ -987,6 +1021,7 @@
 			}
 		    }
 		}
+		US_DEBUGP("scsi cmd done, result=%x\n", us->srb->result);
 		us->srb->scsi_done(us->srb);
 		us->srb = NULL;
 		break;
diff -u --recursive --new-file v2.3.11/linux/fs/Makefile linux/fs/Makefile
--- v2.3.11/linux/fs/Makefile	Wed Jun 30 13:38:20 1999
+++ linux/fs/Makefile	Mon Jul 26 22:51:07 1999
@@ -13,7 +13,7 @@
 O_OBJS    = open.o read_write.o devices.o file_table.o buffer.o \
 		super.o  block_dev.o stat.o exec.o pipe.o namei.o fcntl.o \
 		ioctl.o readdir.o select.o fifo.o locks.o filesystems.o \
-		dcache.o inode.o attr.o bad_inode.o $(BINFMTS) 
+		dcache.o inode.o attr.o bad_inode.o file.o iobuf.o $(BINFMTS) 
 
 MOD_LIST_NAME := FS_MODULES
 ALL_SUB_DIRS = coda minix ext2 fat msdos vfat proc isofs nfs umsdos ntfs \
diff -u --recursive --new-file v2.3.11/linux/fs/binfmt_aout.c linux/fs/binfmt_aout.c
--- v2.3.11/linux/fs/binfmt_aout.c	Wed Jul 21 15:46:48 1999
+++ linux/fs/binfmt_aout.c	Thu Jul 22 09:51:58 1999
@@ -31,16 +31,18 @@
 
 static int load_aout_binary(struct linux_binprm *, struct pt_regs * regs);
 static int load_aout_library(int fd);
-static int aout_core_dump(long signr, struct pt_regs * regs);
+static int aout_core_dump(long signr, struct pt_regs * regs, struct file *file);
 
 extern void dump_thread(struct pt_regs *, struct user *);
 
 static struct linux_binfmt aout_format = {
+	NULL,
 #ifndef MODULE
-	NULL, NULL, load_aout_binary, load_aout_library, aout_core_dump
+	NULL,
 #else
-	NULL, &__this_module, load_aout_binary, load_aout_library, aout_core_dump
+	&__this_module,
 #endif
+	load_aout_binary, load_aout_library, aout_core_dump, PAGE_SIZE
 };
 
 static void set_brk(unsigned long start, unsigned long end)
@@ -64,12 +66,12 @@
 
 #define DUMP_WRITE(addr, nr)	\
 	if (!dump_write(file, (void *)(addr), (nr))) \
-		goto close_coredump;
+		goto end_coredump;
 
 #define DUMP_SEEK(offset) \
 if (file->f_op->llseek) { \
 	if (file->f_op->llseek(file,(offset),0) != (offset)) \
- 		goto close_coredump; \
+ 		goto end_coredump; \
 } else file->f_pos = (offset)
 
 /*
@@ -83,14 +85,10 @@
  */
 
 static inline int
-do_aout_core_dump(long signr, struct pt_regs * regs)
+do_aout_core_dump(long signr, struct pt_regs * regs, struct file *file)
 {
-	struct dentry * dentry = NULL;
-	struct inode * inode = NULL;
-	struct file * file;
 	mm_segment_t fs;
 	int has_dumped = 0;
-	char corefile[6+sizeof(current->comm)];
 	unsigned long dump_start, dump_size;
 	struct user dump;
 #if defined(__alpha__)
@@ -106,32 +104,8 @@
 #       define START_STACK(u)   (u.start_stack)
 #endif
 
-	if (!current->dumpable || atomic_read(&current->mm->mm_users) != 1)
-		return 0;
-	current->dumpable = 0;
-
-/* See if we have enough room to write the upage.  */
-	if (current->rlim[RLIMIT_CORE].rlim_cur < PAGE_SIZE)
-		return 0;
 	fs = get_fs();
 	set_fs(KERNEL_DS);
-	memcpy(corefile,"core.",5);
-#if 0
-	memcpy(corefile+5,current->comm,sizeof(current->comm));
-#else
-	corefile[4] = '\0';
-#endif
-	file = filp_open(corefile,O_CREAT | 2 | O_TRUNC | O_NOFOLLOW, 0600);
-	if (IS_ERR(file))
-		goto end_coredump;
-	dentry = file->f_dentry;
-	inode = dentry->d_inode;
-	if (!S_ISREG(inode->i_mode))
-		goto close_coredump;
-	if (!inode->i_op || !inode->i_op->default_file_ops)
-		goto close_coredump;
-	if (!file->f_op->write)
-		goto close_coredump;
 	has_dumped = 1;
 	current->flags |= PF_DUMPCORE;
        	strncpy(dump.u_comm, current->comm, sizeof(current->comm));
@@ -210,20 +184,18 @@
 /* Finally dump the task struct.  Not be used by gdb, but could be useful */
 	set_fs(KERNEL_DS);
 	DUMP_WRITE(current,sizeof(*current));
-close_coredump:
-	filp_close(file, NULL);
 end_coredump:
 	set_fs(fs);
 	return has_dumped;
 }
 
 static int
-aout_core_dump(long signr, struct pt_regs * regs)
+aout_core_dump(long signr, struct pt_regs * regs, struct file *file)
 {
 	int retval;
 
 	MOD_INC_USE_COUNT;
-	retval = do_aout_core_dump(signr, regs);
+	retval = do_aout_core_dump(signr, regs, file);
 	MOD_DEC_USE_COUNT;
 	return retval;
 }
diff -u --recursive --new-file v2.3.11/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- v2.3.11/linux/fs/binfmt_elf.c	Wed Jul 21 15:46:48 1999
+++ linux/fs/binfmt_elf.c	Thu Jul 22 09:47:55 1999
@@ -54,7 +54,7 @@
  * don't even try.
  */
 #ifdef USE_ELF_CORE_DUMP
-static int elf_core_dump(long signr, struct pt_regs * regs);
+static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file);
 #else
 #define elf_core_dump	NULL
 #endif
@@ -64,11 +64,13 @@
 #define ELF_PAGEALIGN(_v) (((_v) + ELF_EXEC_PAGESIZE - 1) & ~(ELF_EXEC_PAGESIZE - 1))
 
 static struct linux_binfmt elf_format = {
+	NULL,
 #ifndef MODULE
-	NULL, NULL, load_elf_binary, load_elf_library, elf_core_dump
+	NULL,
 #else
-	NULL, &__this_module, load_elf_binary, load_elf_library, elf_core_dump
+	&__this_module,
 #endif
+	load_elf_binary, load_elf_library, elf_core_dump, ELF_EXEC_PAGESIZE
 };
 
 static void set_brk(unsigned long start, unsigned long end)
@@ -1026,10 +1028,10 @@
 
 #define DUMP_WRITE(addr, nr)	\
 	if (!dump_write(file, (addr), (nr))) \
-		goto close_coredump;
+		goto end_coredump;
 #define DUMP_SEEK(off)	\
 	if (!dump_seek(file, (off))) \
-		goto close_coredump;
+		goto end_coredump;
 /*
  * Actual dumper
  *
@@ -1037,14 +1039,10 @@
  * and then they are actually written out.  If we run out of core limit
  * we just truncate.
  */
-static int elf_core_dump(long signr, struct pt_regs * regs)
+static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file)
 {
 	int has_dumped = 0;
-	struct file *file;
-	struct dentry *dentry;
-	struct inode *inode;
 	mm_segment_t fs;
-	char corefile[6+sizeof(current->comm)];
 	int segs;
 	int i;
 	size_t size;
@@ -1058,12 +1056,6 @@
 	elf_fpregset_t fpu;		/* NT_PRFPREG */
 	struct elf_prpsinfo psinfo;	/* NT_PRPSINFO */
 
-	if (!current->dumpable ||
-	    limit < ELF_EXEC_PAGESIZE ||
-	    atomic_read(&current->mm->mm_users) != 1)
-		return 0;
-	current->dumpable = 0;
-
 #ifndef CONFIG_BINFMT_ELF
 	MOD_INC_USE_COUNT;
 #endif
@@ -1112,27 +1104,6 @@
 	fs = get_fs();
 	set_fs(KERNEL_DS);
 
-	memcpy(corefile,"core.",5);
-#if 0
-	memcpy(corefile+5,current->comm,sizeof(current->comm));
-#else
-	corefile[4] = '\0';
-#endif
-	file = filp_open(corefile, O_CREAT | 2 | O_TRUNC | O_NOFOLLOW, 0600);
-	if (IS_ERR(file))
-		goto end_coredump;
-	dentry = file->f_dentry;
-	inode = dentry->d_inode;
-	if (inode->i_nlink > 1)
-		goto close_coredump;	/* multiple links - don't dump */
-
-	if (!S_ISREG(inode->i_mode))
-		goto close_coredump;
-	if (!inode->i_op || !inode->i_op->default_file_ops)
-		goto close_coredump;
-	if (!file->f_op->write)
-		goto close_coredump;
-
 	has_dumped = 1;
 	current->flags |= PF_DUMPCORE;
 
@@ -1289,7 +1260,7 @@
 
 	for(i = 0; i < numnote; i++)
 		if (!writenote(&notes[i], file))
-			goto close_coredump;
+			goto end_coredump;
 
 	set_fs(fs);
 
@@ -1315,9 +1286,6 @@
 		printk("elf_core_dump: file->f_pos (%ld) != offset (%ld)\n",
 		       (off_t) file->f_pos, offset);
 	}
-
- close_coredump:
- 	filp_close(file, NULL);
 
  end_coredump:
 	set_fs(fs);
diff -u --recursive --new-file v2.3.11/linux/fs/binfmt_em86.c linux/fs/binfmt_em86.c
--- v2.3.11/linux/fs/binfmt_em86.c	Wed Jun  2 13:49:55 1999
+++ linux/fs/binfmt_em86.c	Thu Jul 22 09:47:55 1999
@@ -105,11 +105,13 @@
 }
 
 struct linux_binfmt em86_format = {
+	NULL,
 #ifndef MODULE
-	NULL, 0, load_em86, NULL, NULL
+	NULL,
 #else
-	NULL, &__this_module, load_em86, NULL, NULL
+	&__this_module,
 #endif
+	load_em86, NULL, NULL, 0
 };
 
 int __init init_em86_binfmt(void)
diff -u --recursive --new-file v2.3.11/linux/fs/binfmt_misc.c linux/fs/binfmt_misc.c
--- v2.3.11/linux/fs/binfmt_misc.c	Wed Jun  2 13:50:01 1999
+++ linux/fs/binfmt_misc.c	Thu Jul 22 09:47:55 1999
@@ -64,11 +64,13 @@
 static int entry_proc_setup(struct binfmt_entry *e);
 
 static struct linux_binfmt misc_format = {
+	NULL,
 #ifndef MODULE
-	NULL, 0, load_misc_binary, NULL, NULL
+	NULL,
 #else
-	NULL, &__this_module, load_misc_binary, NULL, NULL
+	&__this_module,
 #endif
+	load_misc_binary, NULL, NULL, 0
 };
 
 static struct proc_dir_entry *bm_dir = NULL;
diff -u --recursive --new-file v2.3.11/linux/fs/binfmt_script.c linux/fs/binfmt_script.c
--- v2.3.11/linux/fs/binfmt_script.c	Wed Jun  2 13:50:04 1999
+++ linux/fs/binfmt_script.c	Thu Jul 22 09:47:55 1999
@@ -101,11 +101,13 @@
 }
 
 struct linux_binfmt script_format = {
+	NULL,
 #ifndef MODULE
-	NULL, 0, load_script, NULL, NULL
+	NULL,
 #else
-	NULL, &__this_module, load_script, NULL, NULL
+	&__this_module,
 #endif
+	load_script, NULL, NULL, 0
 };
 
 int __init init_script_binfmt(void)
diff -u --recursive --new-file v2.3.11/linux/fs/buffer.c linux/fs/buffer.c
--- v2.3.11/linux/fs/buffer.c	Wed Jul 21 15:46:48 1999
+++ linux/fs/buffer.c	Mon Jul 26 22:50:35 1999
@@ -40,10 +40,12 @@
 #include <linux/file.h>
 #include <linux/init.h>
 #include <linux/quotaops.h>
+#include <linux/iobuf.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/bitops.h>
+#include <asm/mmu_context.h>
 
 #define NR_SIZES 7
 static char buffersize_index[65] =
@@ -1526,6 +1528,221 @@
 	return err;
 }
 
+
+/*
+ * IO completion routine for a buffer_head being used for kiobuf IO: we
+ * can't dispatch the kiobuf callback until io_count reaches 0.  
+ */
+
+static void end_buffer_io_kiobuf(struct buffer_head *bh, int uptodate)
+{
+	struct kiobuf *kiobuf;
+	
+	mark_buffer_uptodate(bh, uptodate);
+
+	kiobuf = bh->b_kiobuf;
+	if (atomic_dec_and_test(&kiobuf->io_count))
+		kiobuf->end_io(kiobuf);
+	if (!uptodate)
+		kiobuf->errno = -EIO;
+}
+
+
+/*
+ * For brw_kiovec: submit a set of buffer_head temporary IOs and wait
+ * for them to complete.  Clean up the buffer_heads afterwards.  
+ */
+
+#define dprintk(x...) 
+
+static int do_kio(struct kiobuf *kiobuf,
+		  int rw, int nr, struct buffer_head *bh[], int size)
+{
+	int iosize;
+	int i;
+	struct buffer_head *tmp;
+
+	struct task_struct *tsk = current;
+	DECLARE_WAITQUEUE(wait, tsk);
+
+	dprintk ("do_kio start %d\n", rw);
+
+	if (rw == WRITE)
+		rw = WRITERAW;
+	atomic_add(nr, &kiobuf->io_count);
+	kiobuf->errno = 0;
+	ll_rw_block(rw, nr, bh);
+
+	kiobuf_wait_for_io(kiobuf);
+	
+	spin_lock(&unused_list_lock);
+	
+	iosize = 0;
+	for (i = nr; --i >= 0; ) {
+		iosize += size;
+		tmp = bh[i];
+		if (!buffer_uptodate(tmp)) {
+			/* We are traversing bh'es in reverse order so
+                           clearing iosize on error calculates the
+                           amount of IO before the first error. */
+			iosize = 0;
+		}
+		__put_unused_buffer_head(tmp);
+	}
+	
+	spin_unlock(&unused_list_lock);
+
+	dprintk ("do_kio end %d %d\n", iosize, err);
+	
+	if (iosize)
+		return iosize;
+	if (kiobuf->errno)
+		return kiobuf->errno;
+	return -EIO;
+}
+
+/*
+ * Start I/O on a physical range of kernel memory, defined by a vector
+ * of kiobuf structs (much like a user-space iovec list).
+ *
+ * The kiobuf must already be locked for IO.  IO is submitted
+ * asynchronously: you need to check page->locked, page->uptodate, and
+ * maybe wait on page->wait.
+ *
+ * It is up to the caller to make sure that there are enough blocks
+ * passed in to completely map the iobufs to disk.
+ */
+
+int brw_kiovec(int rw, int nr, struct kiobuf *iovec[], 
+	       kdev_t dev, unsigned long b[], int size, int bmap)
+{
+	int		err;
+	int		length;
+	int		transferred;
+	int		i;
+	int		bufind;
+	int		pageind;
+	int		bhind;
+	int		offset;
+	unsigned long	blocknr;
+	struct kiobuf *	iobuf = NULL;
+	unsigned long	page;
+	struct page *	map;
+	struct buffer_head *tmp, *bh[KIO_MAX_SECTORS];
+
+	if (!nr)
+		return 0;
+	
+	/* 
+	 * First, do some alignment and validity checks 
+	 */
+	for (i = 0; i < nr; i++) {
+		iobuf = iovec[i];
+		if ((iobuf->offset & (size-1)) ||
+		    (iobuf->length & (size-1)))
+			return -EINVAL;
+		if (!iobuf->locked)
+			panic("brw_kiovec: iobuf not locked for I/O");
+		if (!iobuf->nr_pages)
+			panic("brw_kiovec: iobuf not initialised");
+	}
+
+	/* DEBUG */
+#if 0
+	return iobuf->length;
+#endif
+	dprintk ("brw_kiovec: start\n");
+	
+	/* 
+	 * OK to walk down the iovec doing page IO on each page we find. 
+	 */
+	bufind = bhind = transferred = err = 0;
+	for (i = 0; i < nr; i++) {
+		iobuf = iovec[i];
+		offset = iobuf->offset;
+		length = iobuf->length;
+		dprintk ("iobuf %d %d %d\n", offset, length, size);
+
+		for (pageind = 0; pageind < iobuf->nr_pages; pageind++) {
+			page = iobuf->pagelist[pageind];
+			map  = iobuf->maplist[pageind];
+
+			while (length > 0) {
+				blocknr = b[bufind++];
+				tmp = get_unused_buffer_head(0);
+				if (!tmp) {
+					err = -ENOMEM;
+					goto error;
+				}
+				
+				tmp->b_dev = B_FREE;
+				tmp->b_size = size;
+				tmp->b_data = (char *) (page + offset);
+				tmp->b_this_page = tmp;
+
+				init_buffer(tmp, end_buffer_io_kiobuf, NULL);
+				tmp->b_dev = dev;
+				tmp->b_blocknr = blocknr;
+				tmp->b_state = 1 << BH_Mapped;
+				tmp->b_kiobuf = iobuf;
+
+				if (rw == WRITE) {
+					set_bit(BH_Uptodate, &tmp->b_state);
+					set_bit(BH_Dirty, &tmp->b_state);
+				}
+
+				dprintk ("buffer %d (%d) at %p\n", 
+					 bhind, tmp->b_blocknr, tmp->b_data);
+				bh[bhind++] = tmp;
+				length -= size;
+				offset += size;
+
+				/* 
+				 * Start the IO if we have got too much 
+				 */
+				if (bhind >= KIO_MAX_SECTORS) {
+					err = do_kio(iobuf, rw, bhind, bh, size);
+					if (err >= 0)
+						transferred += err;
+					else
+						goto finished;
+					bhind = 0;
+				}
+				
+				if (offset >= PAGE_SIZE) {
+					offset = 0;
+					break;
+				}
+			} /* End of block loop */
+		} /* End of page loop */		
+	} /* End of iovec loop */
+
+	/* Is there any IO still left to submit? */
+	if (bhind) {
+		err = do_kio(iobuf, rw, bhind, bh, size);
+		if (err >= 0)
+			transferred += err;
+		else
+			goto finished;
+	}
+
+ finished:
+	dprintk ("brw_kiovec: end (%d, %d)\n", transferred, err);
+	if (transferred)
+		return transferred;
+	return err;
+
+ error:
+	/* We got an error allocation the bh'es.  Just free the current
+           buffer_heads and exit. */
+	spin_lock(&unused_list_lock);
+	for (i = bhind; --i >= 0; ) {
+		__put_unused_buffer_head(bh[bhind]);
+	}
+	spin_unlock(&unused_list_lock);
+	goto finished;
+}
+
 /*
  * Start I/O on a page.
  * This function expects the page to be locked and may return
@@ -1955,7 +2172,6 @@
 	return 0;
 }
 
-
 /* This is the interface to bdflush.  As we get more sophisticated, we can
  * pass tuning parameters to this "process", to adjust how it behaves. 
  * We would want to verify each parameter, however, to make sure that it 
@@ -1963,57 +2179,45 @@
 
 asmlinkage int sys_bdflush(int func, long data)
 {
-	int i, error = -EPERM;
-
 	if (!capable(CAP_SYS_ADMIN))
-		goto out;
+		return -EPERM;
 
 	if (func == 1) {
+		int error;
 		struct mm_struct *user_mm;
+
 		/*
 		 * bdflush will spend all of it's time in kernel-space,
 		 * without touching user-space, so we can switch it into
 		 * 'lazy TLB mode' to reduce the cost of context-switches
 		 * to and from bdflush.
 		 */
-		user_mm = current->mm;
-		atomic_inc(&user_mm->mm_count);
-		current->mm = NULL;
-		/* active_mm is still 'user_mm' */
-
+		user_mm = start_lazy_tlb();
 		error = sync_old_buffers();
-
-		current->mm = user_mm;
-		mmdrop(current->active_mm);
-		current->active_mm = user_mm;
-
-		goto out;
+		end_lazy_tlb(user_mm);
+		return error;
 	}
 
 	/* Basically func 1 means read param 1, 2 means write param 1, etc */
 	if (func >= 2) {
-		i = (func-2) >> 1;
-		error = -EINVAL;
-		if (i < 0 || i >= N_PARAM)
-			goto out;
-		if((func & 1) == 0) {
-			error = put_user(bdf_prm.data[i], (int*)data);
-			goto out;
+		int i = (func-2) >> 1;
+		if (i >= 0 && i < N_PARAM) {
+			if ((func & 1) == 0)
+				return put_user(bdf_prm.data[i], (int*)data);
+
+			if (data >= bdflush_min[i] && data <= bdflush_max[i]) {
+				bdf_prm.data[i] = data;
+				return 0;
+			}
 		}
-		if (data < bdflush_min[i] || data > bdflush_max[i])
-			goto out;
-		bdf_prm.data[i] = data;
-		error = 0;
-		goto out;
-	};
+		return -EINVAL;
+	}
 
 	/* Having func 0 used to launch the actual bdflush and then never
 	 * return (unless explicitly killed). We return zero here to 
 	 * remain semi-compatible with present update(8) programs.
 	 */
-	error = 0;
-out:
-	return error;
+	return 0;
 }
 
 /*
diff -u --recursive --new-file v2.3.11/linux/fs/exec.c linux/fs/exec.c
--- v2.3.11/linux/fs/exec.c	Wed Jul 21 15:46:48 1999
+++ linux/fs/exec.c	Tue Jul 27 14:53:14 1999
@@ -371,7 +371,6 @@
 	if (old_mm && atomic_read(&old_mm->mm_users) == 1) {
 		flush_cache_mm(old_mm);
 		mm_release();
-		release_segments(old_mm);
 		exit_mmap(old_mm);
 		flush_tlb_mm(old_mm);
 		return 0;
@@ -379,26 +378,19 @@
 
 	mm = mm_alloc();
 	if (mm) {
-		mm->cpu_vm_mask = (1UL << smp_processor_id());
-		mm->total_vm = 0;
-		mm->rss = 0;
-		mm->pgd = pgd_alloc();
-		if (mm->pgd) {
-			struct mm_struct *active_mm = current->active_mm;
-
-			current->mm = mm;
-			current->active_mm = mm;
-			SET_PAGE_DIR(current, mm->pgd);
-			activate_context(current);
-			mm_release();
-			if (old_mm) {
-				mmput(old_mm);
-				return 0;
-			}
-			mmdrop(active_mm);
+		struct mm_struct *active_mm = current->active_mm;
+
+		current->mm = mm;
+		current->active_mm = mm;
+		switch_mm(active_mm, mm, smp_processor_id());
+		mm_release();
+		if (old_mm) {
+			if (active_mm != old_mm) BUG();
+			mmput(old_mm);
 			return 0;
 		}
-		kmem_cache_free(mm_cachep, mm);
+		mmdrop(active_mm);
+		return 0;
 	}
 	return -ENOMEM;
 }
@@ -455,9 +447,9 @@
 		unsigned long set, i;
 
 		i = j * __NFDBITS;
-		if (i >= files->max_fds)
+		if (i >= files->max_fds || i >= files->max_fdset)
 			break;
-		set = xchg(&files->close_on_exec.fds_bits[j], 0);
+		set = xchg(&files->close_on_exec->fds_bits[j], 0);
 		j++;
 		for ( ; set ; i++,set >>= 1) {
 			if (set & 1)
@@ -836,4 +828,54 @@
 		free_page(bprm.page[i]);
 
 	return retval;
+}
+
+int do_coredump(long signr, struct pt_regs * regs)
+{
+	struct linux_binfmt * binfmt;
+	char corename[6+sizeof(current->comm)];
+	struct file * file;
+	struct dentry * dentry;
+	struct inode * inode;
+
+	lock_kernel();
+	binfmt = current->binfmt;
+	if (!binfmt || !binfmt->core_dump)
+		goto fail;
+	if (!current->dumpable || atomic_read(&current->mm->mm_users) != 1)
+	current->dumpable = 0;
+	if (current->rlim[RLIMIT_CORE].rlim_cur < binfmt->min_coredump)
+		goto fail;
+
+	memcpy(corename,"core.", 5);
+#if 0
+	memcpy(corename+5,current->comm,sizeof(current->comm));
+#else
+	corename[4] = '\0';
+#endif
+	file = filp_open(corename, O_CREAT | 2 | O_TRUNC | O_NOFOLLOW, 0600);
+	if (IS_ERR(file))
+		goto fail;
+	dentry = file->f_dentry;
+	inode = dentry->d_inode;
+	if (inode->i_nlink > 1)
+		goto close_fail;	/* multiple links - don't dump */
+
+	if (!S_ISREG(inode->i_mode))
+		goto close_fail;
+	if (!inode->i_op || !inode->i_op->default_file_ops)
+		goto close_fail;
+	if (!file->f_op->write)
+		goto close_fail;
+	if (!binfmt->core_dump(signr, regs, file))
+		goto close_fail;
+	filp_close(file, NULL);
+	unlock_kernel();
+	return 1;
+
+close_fail:
+	filp_close(file, NULL);
+fail:
+	unlock_kernel();
+	return 0;
 }
diff -u --recursive --new-file v2.3.11/linux/fs/fcntl.c linux/fs/fcntl.c
--- v2.3.11/linux/fs/fcntl.c	Wed Jul 21 15:46:48 1999
+++ linux/fs/fcntl.c	Mon Jul 26 22:41:09 1999
@@ -12,36 +12,89 @@
 
 extern int sock_fcntl (struct file *, unsigned int cmd, unsigned long arg);
 
-static inline int dupfd(struct file *file, unsigned int arg)
+/*
+ * locate_fd finds a free file descriptor in the open_fds fdset,
+ * expanding the fd arrays if necessary.  The files write lock will be
+ * held on exit to ensure that the fd can be entered atomically.
+ */
+
+static inline int locate_fd(struct files_struct *files, 
+			    struct file *file, int start)
 {
-	struct files_struct * files = current->files;
+	unsigned int newfd;
 	int error;
 
-	error = -EMFILE;
 	write_lock(&files->file_lock);
-	arg = find_next_zero_bit(&files->open_fds, NR_OPEN, arg);
-	if (arg >= current->rlim[RLIMIT_NOFILE].rlim_cur)
-		goto out_putf;
-	FD_SET(arg, &files->open_fds);
-	FD_CLR(arg, &files->close_on_exec);
-	write_unlock(&files->file_lock);
-	fd_install(arg, file);
-	error = arg;
+	
+repeat:
+	error = -EMFILE;
+	if (start < files->next_fd)
+		start = files->next_fd;
+	if (start >= files->max_fdset) {
+	expand:
+		error = expand_files(files, start);
+		if (error < 0)
+			goto out;
+		goto repeat;
+	}
+	
+	newfd = find_next_zero_bit(files->open_fds->fds_bits, 
+				   files->max_fdset, start);
+
+	error = -EMFILE;
+	if (newfd >= current->rlim[RLIMIT_NOFILE].rlim_cur)
+		goto out;
+	if (newfd >= files->max_fdset) 
+		goto expand;
+
+	error = expand_files(files, newfd);
+	if (error < 0)
+		goto out;
+	if (error) /* If we might have blocked, try again. */
+		goto repeat;
+
+	if (start <= files->next_fd)
+		files->next_fd = newfd + 1;
+	
+	error = newfd;
+	
 out:
 	return error;
+}
+
+static inline void allocate_fd(struct files_struct *files, 
+					struct file *file, int fd)
+{
+	FD_SET(fd, files->open_fds);
+	FD_CLR(fd, files->close_on_exec);
+	write_unlock(&files->file_lock);
+	fd_install(fd, file);
+}
+
+static int dupfd(struct file *file, int start)
+{
+	struct files_struct * files = current->files;
+	int ret;
+
+	ret = locate_fd(files, file, start);
+	if (ret < 0) 
+		goto out_putf;
+	allocate_fd(files, file, ret);
+	return ret;
 
 out_putf:
 	write_unlock(&files->file_lock);
 	fput(file);
-	goto out;
+	return ret;
 }
 
 asmlinkage int sys_dup2(unsigned int oldfd, unsigned int newfd)
 {
 	int err = -EBADF;
 	struct file * file;
+	struct files_struct * files = current->files;
 
-	read_lock(&current->files->file_lock);
+	write_lock(&current->files->file_lock);
 	if (!(file = fcheck(oldfd)))
 		goto out_unlock;
 	err = newfd;
@@ -50,15 +103,33 @@
 	err = -EBADF;
 	if (newfd >= NR_OPEN)
 		goto out_unlock;	/* following POSIX.1 6.2.1 */
-	get_file(file);
-	read_unlock(&current->files->file_lock);
+	get_file(file);			/* We are now finished with oldfd */
+
+	err = expand_files(files, newfd);
+	if (err < 0) {
+		write_unlock(&files->file_lock);
+		fput(file);
+		goto out;
+	}
+
+	/* To avoid races with open() and dup(), we will mark the fd as
+	 * in-use in the open-file bitmap throughout the entire dup2()
+	 * process.  This is quite safe: do_close() uses the fd array
+	 * entry, not the bitmap, to decide what work needs to be
+	 * done.  --sct */
+	FD_SET(newfd, files->open_fds);
+	write_unlock(&files->file_lock);
+	
+	do_close(newfd, 0);
+
+	write_lock(&files->file_lock);
+	allocate_fd(files, file, newfd);
+	err = newfd;
 
-	sys_close(newfd);
-	err = dupfd(file, newfd);
 out:
 	return err;
 out_unlock:
-	read_unlock(&current->files->file_lock);
+	write_unlock(&current->files->file_lock);
 	goto out;
 }
 
@@ -66,6 +137,7 @@
 {
 	int ret = -EBADF;
 	struct file * file = fget(fildes);
+
 	if (file)
 		ret = dupfd(file, 0);
 	return ret;
@@ -118,13 +190,13 @@
 			}
 			break;
 		case F_GETFD:
-			err = FD_ISSET(fd, &current->files->close_on_exec);
+			err = FD_ISSET(fd, current->files->close_on_exec);
 			break;
 		case F_SETFD:
 			if (arg&1)
-				FD_SET(fd, &current->files->close_on_exec);
+				FD_SET(fd, current->files->close_on_exec);
 			else
-				FD_CLR(fd, &current->files->close_on_exec);
+				FD_CLR(fd, current->files->close_on_exec);
 			break;
 		case F_GETFL:
 			err = filp->f_flags;
@@ -152,7 +224,6 @@
 			err = filp->f_owner.pid;
 			break;
 		case F_SETOWN:
-			err = 0;
 			filp->f_owner.pid = arg;
 			filp->f_owner.uid = current->uid;
 			filp->f_owner.euid = current->euid;
@@ -172,10 +243,9 @@
 			break;
 		default:
 			/* sockets need a few special fcntls. */
+			err = -EINVAL;
 			if (S_ISSOCK (filp->f_dentry->d_inode->i_mode))
 				err = sock_fcntl (filp, cmd, arg);
-			else
-				err = -EINVAL;
 			break;
 	}
 	fput(filp);
diff -u --recursive --new-file v2.3.11/linux/fs/file.c linux/fs/file.c
--- v2.3.11/linux/fs/file.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/file.c	Mon Jul 26 22:41:09 1999
@@ -0,0 +1,240 @@
+/*
+ *  linux/fs/open.c
+ *
+ *  Copyright (C) 1998-1999, Stephen Tweedie and Bill Hawes
+ *
+ *  Manage the dynamic fd arrays in the process files_struct.
+ */
+
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/vmalloc.h>
+
+#include <asm/bitops.h>
+
+
+/*
+ * Allocate an fd array, using get_free_page() if possible.
+ * Note: the array isn't cleared at allocation time.
+ */
+struct file ** alloc_fd_array(int num)
+{
+	struct file **new_fds;
+	int size = num * sizeof(struct file *);
+
+	if (size < PAGE_SIZE)
+		new_fds = (struct file **) kmalloc(size, GFP_KERNEL);
+	else if (size == PAGE_SIZE)
+		new_fds = (struct file **) __get_free_page(GFP_KERNEL);
+	else
+		new_fds = (struct file **) vmalloc(size);
+	return new_fds;
+}
+
+void free_fd_array(struct file **array, int num)
+{
+	int size = num * sizeof(struct file *);
+
+	if (!array) {
+		printk (KERN_ERR __FUNCTION__ "array = 0 (num = %d)\n", num);
+		return;
+	}
+
+	if (num <= NR_OPEN_DEFAULT) /* Don't free the embedded fd array! */
+		return;
+	else if (size < PAGE_SIZE)
+		kfree(array);
+	else if (size == PAGE_SIZE)
+		free_page((unsigned long) array);
+	else
+		vfree(array);
+}
+
+/*
+ * Expand the fd array in the files_struct.  Called with the files
+ * spinlock held for write.
+ */
+
+int expand_fd_array(struct files_struct *files, int nr)
+{
+	struct file **new_fds;
+	int error, nfds;
+
+	
+	error = -EMFILE;
+	if (files->max_fds >= NR_OPEN || nr > NR_OPEN)
+		goto out;
+
+	nfds = files->max_fds;
+	write_unlock(&files->file_lock);
+
+	/* 
+	 * Expand to the max in easy steps, and keep expanding it until
+	 * we have enough for the requested fd array size. 
+	 */
+
+	do {
+#if NR_OPEN_DEFAULT < 256
+		if (nfds < 256)
+			nfds = 256;
+		else 
+#endif
+		if (nfds < (PAGE_SIZE / sizeof(struct file *)))
+			nfds = PAGE_SIZE / sizeof(struct file *);
+		else {
+			nfds = nfds * 2;
+			if (nfds > NR_OPEN)
+				nfds = NR_OPEN;
+		}
+	} while (nfds < nr);
+
+	error = -ENOMEM;
+	new_fds = alloc_fd_array(nfds);
+	write_lock(&files->file_lock);
+	if (!new_fds)
+		goto out;
+
+	/* Copy the existing array and install the new pointer */
+
+	if (nfds > files->max_fds) {
+		struct file **old_fds;
+		int i;
+		
+		old_fds = xchg(&files->fd, new_fds);
+		i = xchg(&files->max_fds, nfds);
+
+		/* Don't copy/clear the array if we are creating a new
+		   fd array for fork() */
+		if (i) {
+			memcpy(new_fds, old_fds, i * sizeof(struct file *));
+			/* clear the remainder of the array */
+			memset(&new_fds[i], 0,
+			       (nfds-i) * sizeof(struct file *)); 
+
+			write_unlock(&files->file_lock);
+			free_fd_array(old_fds, i);
+			write_lock(&files->file_lock);
+		}
+	} else {
+		/* Somebody expanded the array while we slept ... */
+		write_unlock(&files->file_lock);
+		free_fd_array(new_fds, nfds);
+		write_lock(&files->file_lock);
+	}
+	error = 0;
+out:
+	return error;
+}
+
+/*
+ * Allocate an fdset array, using get_free_page() if possible.
+ * Note: the array isn't cleared at allocation time.
+ */
+fd_set * alloc_fdset(int num)
+{
+	fd_set *new_fdset;
+	int size = num / 8;
+
+	if (size < PAGE_SIZE)
+		new_fdset = (fd_set *) kmalloc(size, GFP_KERNEL);
+	else if (size == PAGE_SIZE)
+		new_fdset = (fd_set *) __get_free_page(GFP_KERNEL);
+	else
+		new_fdset = (fd_set *) vmalloc(size);
+	return new_fdset;
+}
+
+void free_fdset(fd_set *array, int num)
+{
+	int size = num / 8;
+
+	if (!array) {
+		printk (KERN_ERR __FUNCTION__ "array = 0 (num = %d)\n", num);
+		return;
+	}
+	
+	if (num <= __FD_SETSIZE) /* Don't free an embedded fdset */
+		return;
+	else if (size < PAGE_SIZE)
+		kfree(array);
+	else if (size == PAGE_SIZE)
+		free_page((unsigned long) array);
+	else
+		vfree(array);
+}
+
+/*
+ * Expand the fdset in the files_struct.  Called with the files spinlock
+ * held for write.
+ */
+int expand_fdset(struct files_struct *files, int nr)
+{
+	fd_set *new_openset = 0, *new_execset = 0;
+	int error, nfds = 0;
+
+	error = -EMFILE;
+	if (files->max_fdset >= NR_OPEN || nr > NR_OPEN)
+		goto out;
+
+	nfds = files->max_fdset;
+	write_unlock(&files->file_lock);
+
+	/* Expand to the max in easy steps */
+	do {
+		if (nfds < (PAGE_SIZE * 8))
+			nfds = PAGE_SIZE * 8;
+		else {
+			nfds = nfds * 2;
+			if (nfds > NR_OPEN)
+				nfds = NR_OPEN;
+		}
+	} while (nfds < nr);
+
+	error = -ENOMEM;
+	new_openset = alloc_fdset(nfds);
+	new_execset = alloc_fdset(nfds);
+	write_lock(&files->file_lock);
+	if (!new_openset || !new_execset)
+		goto out;
+
+	error = 0;
+	
+	/* Copy the existing tables and install the new pointers */
+	if (nfds > files->max_fdset) {
+		int i = files->max_fdset / (sizeof(unsigned long) * 8);
+		int count = (nfds - files->max_fdset) / 8;
+		
+		/* 
+		 * Don't copy the entire array if the current fdset is
+		 * not yet initialised.  
+		 */
+		if (i) {
+			memcpy (new_openset, files->open_fds, files->max_fdset/8);
+			memcpy (new_execset, files->close_on_exec, files->max_fdset/8);
+			memset (&new_openset->fds_bits[i], 0, count);
+			memset (&new_execset->fds_bits[i], 0, count);
+		}
+		
+		nfds = xchg(&files->max_fdset, nfds);
+		new_openset = xchg(&files->open_fds, new_openset);
+		new_execset = xchg(&files->close_on_exec, new_execset);
+		write_unlock(&files->file_lock);
+		free_fdset (new_openset, nfds);
+		free_fdset (new_execset, nfds);
+		write_lock(&files->file_lock);
+		return 0;
+	} 
+	/* Somebody expanded the array while we slept ... */
+
+out:
+	write_unlock(&files->file_lock);
+	if (new_openset)
+		free_fdset(new_openset, nfds);
+	if (new_execset)
+		free_fdset(new_execset, nfds);
+	write_lock(&files->file_lock);
+	return error;
+}
+
diff -u --recursive --new-file v2.3.11/linux/fs/iobuf.c linux/fs/iobuf.c
--- v2.3.11/linux/fs/iobuf.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/iobuf.c	Mon Jul 26 22:50:35 1999
@@ -0,0 +1,136 @@
+/*
+ * iobuf.c
+ *
+ * Keep track of the general-purpose IO-buffer structures used to track
+ * abstract kernel-space io buffers.
+ * 
+ */
+
+#include <linux/iobuf.h>
+#include <linux/malloc.h>
+#include <linux/slab.h>
+
+static kmem_cache_t *kiobuf_cachep;
+
+/*
+ * The default IO completion routine for kiobufs: just wake up
+ * the kiobuf, nothing more.  
+ */
+
+void simple_wakeup_kiobuf(struct kiobuf *kiobuf)
+{
+	wake_up(&kiobuf->wait_queue);
+}
+
+
+void __init kiobuf_init(void)
+{
+	kiobuf_cachep =  kmem_cache_create("kiobuf",
+					   sizeof(struct kiobuf),
+					   0,
+					   SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if(!kiobuf_cachep)
+		panic("Cannot create kernel iobuf cache\n");
+}
+
+
+int alloc_kiovec(int nr, struct kiobuf **bufp)
+{
+	int i;
+	struct kiobuf *iobuf;
+	
+	for (i = 0; i < nr; i++) {
+		iobuf = kmem_cache_alloc(kiobuf_cachep, SLAB_KERNEL);
+		if (!iobuf) {
+			free_kiovec(i, bufp);
+			return -ENOMEM;
+		}
+		
+		memset(iobuf, 0, sizeof(*iobuf));
+		init_waitqueue_head(&iobuf->wait_queue);
+		iobuf->end_io = simple_wakeup_kiobuf;
+		iobuf->array_len = KIO_STATIC_PAGES;
+		iobuf->pagelist  = iobuf->page_array;
+		iobuf->maplist   = iobuf->map_array;
+		*bufp++ = iobuf;
+	}
+	
+	return 0;
+}
+
+void free_kiovec(int nr, struct kiobuf **bufp) 
+{
+	int i;
+	struct kiobuf *iobuf;
+	
+	for (i = 0; i < nr; i++) {
+		iobuf = bufp[i];
+		if (iobuf->array_len > KIO_STATIC_PAGES) {
+			kfree (iobuf->pagelist);
+			kfree (iobuf->maplist);
+		}
+		kmem_cache_free(kiobuf_cachep, bufp[i]);
+	}
+}
+
+int expand_kiobuf(struct kiobuf *iobuf, int wanted)
+{
+	unsigned long *	pagelist;
+	struct page ** maplist;
+	
+	if (iobuf->array_len >= wanted)
+		return 0;
+	
+	pagelist = (unsigned long *) 
+		kmalloc(wanted * sizeof(unsigned long), GFP_KERNEL);
+	if (!pagelist)
+		return -ENOMEM;
+	
+	maplist = (struct page **) 
+		kmalloc(wanted * sizeof(struct page **), GFP_KERNEL);
+	if (!maplist) {
+		kfree(pagelist);
+		return -ENOMEM;
+	}
+
+	/* Did it grow while we waited? */
+	if (iobuf->array_len >= wanted) {
+		kfree(pagelist);
+		kfree(maplist);
+		return 0;
+	}
+	
+	memcpy (pagelist, iobuf->pagelist, wanted * sizeof(unsigned long));
+	memcpy (maplist,  iobuf->maplist,   wanted * sizeof(struct page **));
+
+	if (iobuf->array_len > KIO_STATIC_PAGES) {
+		kfree (iobuf->pagelist);
+		kfree (iobuf->maplist);
+	}
+	
+	iobuf->pagelist  = pagelist;
+	iobuf->maplist   = maplist;
+	iobuf->array_len = wanted;
+	return 0;
+}
+
+
+void kiobuf_wait_for_io(struct kiobuf *kiobuf)
+{
+	struct task_struct *tsk = current;
+	DECLARE_WAITQUEUE(wait, tsk);
+
+	add_wait_queue(&kiobuf->wait_queue, &wait);
+repeat:
+	tsk->state = TASK_UNINTERRUPTIBLE;
+	run_task_queue(&tq_disk);
+	if (atomic_read(&kiobuf->io_count) != 0) {
+		schedule();
+		goto repeat;
+	}
+	tsk->state = TASK_RUNNING;
+	remove_wait_queue(&kiobuf->wait_queue, &wait);
+}
+
+
+
diff -u --recursive --new-file v2.3.11/linux/fs/ioctl.c linux/fs/ioctl.c
--- v2.3.11/linux/fs/ioctl.c	Thu Jul  8 15:42:21 1999
+++ linux/fs/ioctl.c	Mon Jul 26 22:41:09 1999
@@ -61,11 +61,11 @@
 	lock_kernel();
 	switch (cmd) {
 		case FIOCLEX:
-			FD_SET(fd, &current->files->close_on_exec);
+			FD_SET(fd, current->files->close_on_exec);
 			break;
 
 		case FIONCLEX:
-			FD_CLR(fd, &current->files->close_on_exec);
+			FD_CLR(fd, current->files->close_on_exec);
 			break;
 
 		case FIONBIO:
diff -u --recursive --new-file v2.3.11/linux/fs/minix/file.c linux/fs/minix/file.c
--- v2.3.11/linux/fs/minix/file.c	Thu Jul  8 15:42:21 1999
+++ linux/fs/minix/file.c	Fri Jul 23 10:30:42 1999
@@ -24,6 +24,7 @@
 #define MAX(a,b) (((a)>(b))?(a):(b))
 
 #include <linux/fs.h>
+#include <linux/minix_fs.h>
 
 /*
  * Write to a file (through the page cache).
diff -u --recursive --new-file v2.3.11/linux/fs/open.c linux/fs/open.c
--- v2.3.11/linux/fs/open.c	Wed Jul 21 15:46:48 1999
+++ linux/fs/open.c	Mon Jul 26 22:41:09 1999
@@ -685,10 +685,14 @@
 	struct files_struct * files = current->files;
 	int fd, error;
 
-	error = -EMFILE;
-
+  	error = -EMFILE;
 	write_lock(&files->file_lock);
-	fd = find_first_zero_bit(&files->open_fds, NR_OPEN);
+
+repeat:
+ 	fd = find_next_zero_bit(files->open_fds, 
+				current->files->max_fdset, 
+				files->next_fd);
+
 	/*
 	 * N.B. For clone tasks sharing a files structure, this test
 	 * will limit the total number of files that can be opened.
@@ -696,10 +700,31 @@
 	if (fd >= current->rlim[RLIMIT_NOFILE].rlim_cur)
 		goto out;
 
-	/* Check here for fd > files->max_fds to do dynamic expansion */
+	/* Do we need to expand the fdset array? */
+	if (fd >= current->files->max_fdset) {
+		error = expand_fdset(files, 0);
+		if (!error) {
+			error = -EMFILE;
+			goto repeat;
+		}
+		goto out;
+	}
+	
+	/* 
+	 * Check whether we need to expand the fd array.
+	 */
+	if (fd >= files->max_fds) {
+		error = expand_fd_array(files, 0);
+		if (!error) {
+			error = -EMFILE;
+			goto repeat;
+		}
+		goto out;
+	}
 
-	FD_SET(fd, &files->open_fds);
-	FD_CLR(fd, &files->close_on_exec);
+	FD_SET(fd, files->open_fds);
+	FD_CLR(fd, files->close_on_exec);
+	files->next_fd = fd + 1;
 #if 1
 	/* Sanity check */
 	if (files->fd[fd] != NULL) {
@@ -717,7 +742,9 @@
 inline void put_unused_fd(unsigned int fd)
 {
 	write_lock(&current->files->file_lock);
-	FD_CLR(fd, &current->files->open_fds);
+	FD_CLR(fd, current->files->open_fds);
+	if (fd < current->files->next_fd)
+		current->files->next_fd = fd;
 	write_unlock(&current->files->file_lock);
 }
 
@@ -790,8 +817,12 @@
  * Careful here! We test whether the file pointer is NULL before
  * releasing the fd. This ensures that one clone task can't release
  * an fd while another clone is opening it.
+ *
+ * The "release" argument tells us whether or not to mark the fd as free
+ * or not in the open-files bitmap.  dup2 uses this to retain the fd
+ * without races.
  */
-asmlinkage int sys_close(unsigned int fd)
+int do_close(unsigned int fd, int release)
 {
 	int error;
 	struct file * filp;
@@ -802,9 +833,10 @@
 	filp = frip(fd);
 	if (!filp)
 		goto out_unlock;
-	FD_CLR(fd, &files->close_on_exec);
+	FD_CLR(fd, files->close_on_exec);
 	write_unlock(&files->file_lock);
-	put_unused_fd(fd);
+	if (release)
+		put_unused_fd(fd);
 	lock_kernel();
 	error = filp_close(filp, files);
 	unlock_kernel();
@@ -813,6 +845,11 @@
 out_unlock:
 	write_unlock(&files->file_lock);
 	goto out;
+}
+
+asmlinkage int sys_close(unsigned int fd)
+{
+	return do_close(fd, 1);
 }
 
 /*
diff -u --recursive --new-file v2.3.11/linux/fs/proc/array.c linux/fs/proc/array.c
--- v2.3.11/linux/fs/proc/array.c	Wed Jul 21 15:46:48 1999
+++ linux/fs/proc/array.c	Wed Jul 28 10:45:39 1999
@@ -42,6 +42,8 @@
  * Alan Cox	     :  security fixes.
  *			<Alan.Cox@linux.org>
  *
+ * Al Viro           :  safe handling of mm_struct
+ *
  */
 
 #include <linux/types.h>
@@ -386,21 +388,15 @@
 	return sprintf(buffer, "%s\n", saved_command_line);
 }
 
-static unsigned long get_phys_addr(struct task_struct * p, unsigned long ptr)
+static unsigned long get_phys_addr(struct mm_struct * mm, unsigned long ptr)
 {
 	pgd_t *page_dir;
 	pmd_t *page_middle;
 	pte_t pte;
 
-	if (!p || !p->mm || ptr >= TASK_SIZE)
-		return 0;
-	/* Check for NULL pgd .. shouldn't happen! */
-	if (!p->mm->pgd) {
-		printk("get_phys_addr: pid %d has NULL pgd!\n", p->pid);
+	if (ptr >= TASK_SIZE)
 		return 0;
-	}
-
-	page_dir = pgd_offset(p->mm,ptr);
+	page_dir = pgd_offset(mm,ptr);
 	if (pgd_none(*page_dir))
 		return 0;
 	if (pgd_bad(*page_dir)) {
@@ -422,7 +418,7 @@
 	return pte_page(pte) + (ptr & ~PAGE_MASK);
 }
 
-static int get_array(struct task_struct *p, unsigned long start, unsigned long end, char * buffer)
+static int get_array(struct mm_struct *mm, unsigned long start, unsigned long end, char * buffer)
 {
 	unsigned long addr;
 	int size = 0, result = 0;
@@ -431,7 +427,7 @@
 	if (start >= end)
 		return result;
 	for (;;) {
-		addr = get_phys_addr(p, start);
+		addr = get_phys_addr(mm, start);
 		if (!addr)
 			return result;
 		do {
@@ -451,29 +447,42 @@
 	return result;
 }
 
-static int get_env(int pid, char * buffer)
+static struct mm_struct *get_mm(int pid)
 {
 	struct task_struct *p;
+	struct mm_struct *mm = NULL;
 	
 	read_lock(&tasklist_lock);
 	p = find_task_by_pid(pid);
-	read_unlock(&tasklist_lock);	/* FIXME!! This should be done after the last use */
+	if (p)
+		mm = p->mm;
+	if (mm)
+		atomic_inc(&mm->mm_users);
+	read_unlock(&tasklist_lock);
+	return mm;
+}
 
-	if (!p || !p->mm)
-		return 0;
-	return get_array(p, p->mm->env_start, p->mm->env_end, buffer);
+
+static int get_env(int pid, char * buffer)
+{
+	struct mm_struct *mm = get_mm(pid);
+	int res = 0;
+	if (mm) {
+		res = get_array(mm, mm->env_start, mm->env_end, buffer);
+		mmput(mm);
+	}
+	return res;
 }
 
 static int get_arg(int pid, char * buffer)
 {
-	struct task_struct *p;
-
-	read_lock(&tasklist_lock);
-	p = find_task_by_pid(pid);
-	read_unlock(&tasklist_lock);	/* FIXME!! This should be done after the last use */
-	if (!p || !p->mm)
-		return 0;
-	return get_array(p, p->mm->arg_start, p->mm->arg_end, buffer);
+	struct mm_struct *mm = get_mm(pid);
+	int res = 0;
+	if (mm) {
+		res = get_array(mm, mm->arg_start, mm->arg_end, buffer);
+		mmput(mm);
+	}
+	return res;
 }
 
 /*
@@ -725,11 +734,13 @@
 		"PPid:\t%d\n"
 		"Uid:\t%d\t%d\t%d\t%d\n"
 		"Gid:\t%d\t%d\t%d\t%d\n"
+		"FDSize:\t%d\n"
 		"Groups:\t",
 		get_task_state(p),
 		p->pid, p->p_pptr->pid,
 		p->uid, p->euid, p->suid, p->fsuid,
-		p->gid, p->egid, p->sgid, p->fsgid);
+		p->gid, p->egid, p->sgid, p->fsgid,
+		p->files ? p->files->max_fds : 0);
 
 	for (g = 0; g < p->ngroups; g++)
 		buffer += sprintf(buffer, "%d ", p->groups[g]);
@@ -738,46 +749,44 @@
 	return buffer;
 }
 
-static inline char * task_mem(struct task_struct *p, char *buffer)
+static inline char * task_mem(struct mm_struct *mm, char *buffer)
 {
-	struct mm_struct * mm = p->mm;
-
-	if (mm) {
-		struct vm_area_struct * vma = mm->mmap;
-		unsigned long data = 0, stack = 0;
-		unsigned long exec = 0, lib = 0;
-
-		for (vma = mm->mmap; vma; vma = vma->vm_next) {
-			unsigned long len = (vma->vm_end - vma->vm_start) >> 10;
-			if (!vma->vm_file) {
-				data += len;
-				if (vma->vm_flags & VM_GROWSDOWN)
-					stack += len;
-				continue;
-			}
-			if (vma->vm_flags & VM_WRITE)
+	struct vm_area_struct * vma;
+	unsigned long data = 0, stack = 0;
+	unsigned long exec = 0, lib = 0;
+
+	down(&mm->mmap_sem);
+	for (vma = mm->mmap; vma; vma = vma->vm_next) {
+		unsigned long len = (vma->vm_end - vma->vm_start) >> 10;
+		if (!vma->vm_file) {
+			data += len;
+			if (vma->vm_flags & VM_GROWSDOWN)
+				stack += len;
+			continue;
+		}
+		if (vma->vm_flags & VM_WRITE)
+			continue;
+		if (vma->vm_flags & VM_EXEC) {
+			exec += len;
+			if (vma->vm_flags & VM_EXECUTABLE)
 				continue;
-			if (vma->vm_flags & VM_EXEC) {
-				exec += len;
-				if (vma->vm_flags & VM_EXECUTABLE)
-					continue;
-				lib += len;
-			}
-		}	
-		buffer += sprintf(buffer,
-			"VmSize:\t%8lu kB\n"
-			"VmLck:\t%8lu kB\n"
-			"VmRSS:\t%8lu kB\n"
-			"VmData:\t%8lu kB\n"
-			"VmStk:\t%8lu kB\n"
-			"VmExe:\t%8lu kB\n"
-			"VmLib:\t%8lu kB\n",
-			mm->total_vm << (PAGE_SHIFT-10),
-			mm->locked_vm << (PAGE_SHIFT-10),
-			mm->rss << (PAGE_SHIFT-10),
-			data - stack, stack,
-			exec - lib, lib);
+			lib += len;
+		}
 	}
+	buffer += sprintf(buffer,
+		"VmSize:\t%8lu kB\n"
+		"VmLck:\t%8lu kB\n"
+		"VmRSS:\t%8lu kB\n"
+		"VmData:\t%8lu kB\n"
+		"VmStk:\t%8lu kB\n"
+		"VmExe:\t%8lu kB\n"
+		"VmLib:\t%8lu kB\n",
+		mm->total_vm << (PAGE_SHIFT-10),
+		mm->locked_vm << (PAGE_SHIFT-10),
+		mm->rss << (PAGE_SHIFT-10),
+		data - stack, stack,
+		exec - lib, lib);
+	up(&mm->mmap_sem);
 	return buffer;
 }
 
@@ -838,44 +847,61 @@
 {
 	char * orig = buffer;
 	struct task_struct *tsk;
+	struct mm_struct *mm = NULL;
 
 	read_lock(&tasklist_lock);
 	tsk = find_task_by_pid(pid);
+	if (tsk)
+		mm = tsk->mm;
+	if (mm)
+		atomic_inc(&mm->mm_users);
 	read_unlock(&tasklist_lock);	/* FIXME!! This should be done after the last use */
 	if (!tsk)
 		return 0;
 	buffer = task_name(tsk, buffer);
 	buffer = task_state(tsk, buffer);
-	buffer = task_mem(tsk, buffer);
+	if (mm)
+		buffer = task_mem(mm, buffer);
 	buffer = task_sig(tsk, buffer);
 	buffer = task_cap(tsk, buffer);
+	if (mm)
+		mmput(mm);
 	return buffer - orig;
 }
 
 static int get_stat(int pid, char * buffer)
 {
 	struct task_struct *tsk;
+	struct mm_struct *mm = NULL;
 	unsigned long vsize, eip, esp, wchan;
 	long priority, nice;
 	int tty_pgrp;
 	sigset_t sigign, sigcatch;
 	char state;
+	int res;
 
 	read_lock(&tasklist_lock);
 	tsk = find_task_by_pid(pid);
+	if (tsk)
+		mm = tsk->mm;
+	if (mm)
+		atomic_inc(&mm->mm_users);
 	read_unlock(&tasklist_lock);	/* FIXME!! This should be done after the last use */
 	if (!tsk)
 		return 0;
 	state = *get_task_state(tsk);
 	vsize = eip = esp = 0;
-	if (tsk->mm) {
-		struct vm_area_struct *vma = tsk->mm->mmap;
+	if (mm) {
+		struct vm_area_struct *vma;
+		down(&mm->mmap_sem);
+		vma = mm->mmap;
 		while (vma) {
 			vsize += vma->vm_end - vma->vm_start;
 			vma = vma->vm_next;
 		}
 		eip = KSTK_EIP(tsk);
 		esp = KSTK_ESP(tsk);
+		up(&mm->mmap_sem);
 	}
 
 	wchan = get_wchan(tsk);
@@ -894,7 +920,7 @@
 	nice = tsk->priority;
 	nice = 20 - (nice * 20 + DEF_PRIORITY / 2) / DEF_PRIORITY;
 
-	return sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
+	res = sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
 %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu \
 %lu %lu %lu %lu %lu %lu %lu %lu %d %d\n",
 		pid,
@@ -920,11 +946,11 @@
 		tsk->it_real_value,
 		tsk->start_time,
 		vsize,
-		tsk->mm ? tsk->mm->rss : 0, /* you might want to shift this left 3 */
+		mm ? mm->rss : 0, /* you might want to shift this left 3 */
 		tsk->rlim ? tsk->rlim[RLIMIT_RSS].rlim_cur : 0,
-		tsk->mm ? tsk->mm->start_code : 0,
-		tsk->mm ? tsk->mm->end_code : 0,
-		tsk->mm ? tsk->mm->start_stack : 0,
+		mm ? mm->start_code : 0,
+		mm ? mm->end_code : 0,
+		mm ? mm->start_stack : 0,
 		esp,
 		eip,
 		/* The signal information here is obsolete.
@@ -940,6 +966,9 @@
 		tsk->cnswap,
 		tsk->exit_signal,
 		tsk->processor);
+	if (mm)
+		mmput(mm);
+	return res;
 }
 		
 static inline void statm_pte_range(pmd_t * pmd, unsigned long address, unsigned long size,
@@ -1017,19 +1046,15 @@
 
 static int get_statm(int pid, char * buffer)
 {
-	struct task_struct *tsk;
+	struct mm_struct *mm = get_mm(pid);
 	int size=0, resident=0, share=0, trs=0, lrs=0, drs=0, dt=0;
 
-	read_lock(&tasklist_lock);
-	tsk = find_task_by_pid(pid);
-	read_unlock(&tasklist_lock);	/* FIXME!! This should be done after the last use */
-	if (!tsk)
-		return 0;
-	if (tsk->mm) {
-		struct vm_area_struct * vma = tsk->mm->mmap;
-
+	if (mm) {
+		struct vm_area_struct * vma;
+		down(&mm->mmap_sem);
+		vma = mm->mmap;
 		while (vma) {
-			pgd_t *pgd = pgd_offset(tsk->mm, vma->vm_start);
+			pgd_t *pgd = pgd_offset(mm, vma->vm_start);
 			int pages = 0, shared = 0, dirty = 0, total = 0;
 
 			statm_pgd_range(pgd, vma->vm_start, vma->vm_end, &pages, &shared, &dirty, &total);
@@ -1047,6 +1072,8 @@
 				drs += pages;
 			vma = vma->vm_next;
 		}
+		up(&mm->mmap_sem);
+		mmput(mm);
 	}
 	return sprintf(buffer,"%d %d %d %d %d %d %d\n",
 		       size, resident, share, trs, lrs, drs, dt);
diff -u --recursive --new-file v2.3.11/linux/fs/proc/link.c linux/fs/proc/link.c
--- v2.3.11/linux/fs/proc/link.c	Thu Jul  8 15:42:21 1999
+++ linux/fs/proc/link.c	Wed Jul 28 10:45:39 1999
@@ -82,60 +82,70 @@
 	ino &= 0x0000ffff;
 
 	result = ERR_PTR(-ENOENT);
-	read_lock(&tasklist_lock);
-	p = find_task_by_pid(pid);
-	if (!p)
-		goto out_unlock;
 
 	switch (ino) {
 		case PROC_PID_CWD:
-			if (!p->fs || !p->fs->pwd)
-				goto out_unlock;
-			result = p->fs->pwd;
-			goto out_dget;
+			read_lock(&tasklist_lock);
+			p = find_task_by_pid(pid);
+			if (p && p->fs && p->fs->pwd)
+				result = dget(p->fs->pwd);
+			read_unlock(&tasklist_lock);
+			break;
 
 		case PROC_PID_ROOT:
-			if (!p->fs || !p->fs->root)
-				goto out_unlock;
-			result = p->fs->root;
-			goto out_dget;
+			read_lock(&tasklist_lock);
+			p = find_task_by_pid(pid);
+			if (p && p->fs && p->fs->root)
+				result = dget(p->fs->root);
+			read_unlock(&tasklist_lock);
+			break;
 
 		case PROC_PID_EXE: {
+			struct mm_struct *mm = NULL;
 			struct vm_area_struct * vma;
-			if (!p->mm)
-				goto out_unlock;
-			vma = p->mm->mmap;
+			read_lock(&tasklist_lock);
+			p = find_task_by_pid(pid);
+			if (p)
+				mm = p->mm;
+			if (mm)
+				atomic_inc(&mm->mm_users);
+			read_unlock(&tasklist_lock);
+			if (!mm)
+				break;
+			down(&mm->mmap_sem);
+			vma = mm->mmap;
 			while (vma) {
 				if ((vma->vm_flags & VM_EXECUTABLE) && 
 				    vma->vm_file) {
-					result = vma->vm_file->f_dentry;
-					goto out_dget;
+					result = dget(vma->vm_file->f_dentry);
+					break;
 				}
 				vma = vma->vm_next;
 			}
-			goto out_unlock;
+			up(&mm->mmap_sem);
+			mmput(mm);
+			break;
 		}
 		default:
 			if (ino & PROC_PID_FD_DIR) {
 				struct file * file;
+				struct files_struct *files = NULL;
+				read_lock(&tasklist_lock);
+				p = find_task_by_pid(pid);
+				if (p)
+					files = p->files;
+				read_unlock(&tasklist_lock);
+				if (!files)
+					break;
 				ino &= 0x7fff;
-				if (!p->files) /* shouldn't happen here */
-					goto out_unlock;
-				read_lock(&p->files->file_lock);
-				file = fcheck_task(p, ino);
-				if (!file || !file->f_dentry)
-					goto out_unlock;
-				result = file->f_dentry;
+				read_lock(&files->file_lock);
+				/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
+				if (ino < files->max_fds &&
+				    (file = files->fd[ino]) && file->f_dentry)
+					result = dget(file->f_dentry);
 				read_unlock(&p->files->file_lock);
-				goto out_dget;
 			}
 	}
-out_dget:
-	result = dget(result);
-
-out_unlock:
-	read_unlock(&tasklist_lock);
-
 out:
 	return result;
 }
diff -u --recursive --new-file v2.3.11/linux/fs/select.c linux/fs/select.c
--- v2.3.11/linux/fs/select.c	Thu Jul  8 15:42:21 1999
+++ linux/fs/select.c	Wed Jul 28 13:52:38 1999
@@ -106,7 +106,7 @@
 	/* handle last in-complete long-word first */
 	set = ~(~0UL << (n & (__NFDBITS-1)));
 	n /= __NFDBITS;
-	open_fds = current->files->open_fds.fds_bits+n;
+	open_fds = current->files->open_fds->fds_bits+n;
 	max = 0;
 	if (set) {
 		set &= BITS(fds, n);
@@ -268,8 +268,8 @@
 	if (n < 0)
 		goto out_nofds;
 
-	if (n > KFDS_NR)
-		n = KFDS_NR;
+	if (n > current->files->max_fdset)
+		n = current->files->max_fdset;
 
 	/*
 	 * We need 6 bitmaps (in/out/ex for both incoming and outgoing),
@@ -380,7 +380,7 @@
 	lock_kernel();
 	/* Do a sanity check on nfds ... */
 	err = -EINVAL;
-	if (nfds > NR_OPEN)
+	if (nfds > current->files->max_fds)
 		goto out;
 
 	if (timeout) {
diff -u --recursive --new-file v2.3.11/linux/include/asm-alpha/resource.h linux/include/asm-alpha/resource.h
--- v2.3.11/linux/include/asm-alpha/resource.h	Fri Aug 23 05:30:14 1996
+++ linux/include/asm-alpha/resource.h	Mon Jul 26 22:41:09 1999
@@ -28,7 +28,7 @@
     {_STK_LIM, _STK_LIM},			/* RLIMIT_STACK */	\
     {       0, LONG_MAX},			/* RLIMIT_CORE */	\
     {LONG_MAX, LONG_MAX},			/* RLIMIT_RSS */	\
-    { NR_OPEN,  NR_OPEN},			/* RLIMIT_NOFILE */	\
+    {INR_OPEN, INR_OPEN},			/* RLIMIT_NOFILE */	\
     {LONG_MAX, LONG_MAX},			/* RLIMIT_AS */		\
     {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER},	/* RLIMIT_NPROC */	\
     {LONG_MAX, LONG_MAX},			/* RLIMIT_MEMLOCK */	\
diff -u --recursive --new-file v2.3.11/linux/include/asm-arm/resource.h linux/include/asm-arm/resource.h
--- v2.3.11/linux/include/asm-arm/resource.h	Tue Jan 20 16:39:43 1998
+++ linux/include/asm-arm/resource.h	Mon Jul 26 22:41:09 1999
@@ -29,7 +29,7 @@
 	{        0, LONG_MAX },				\
 	{ LONG_MAX, LONG_MAX },				\
 	{ MAX_TASKS_PER_USER, MAX_TASKS_PER_USER },	\
-	{ NR_OPEN, NR_OPEN },				\
+	{ INR_OPEN, INR_OPEN },				\
 	{ LONG_MAX, LONG_MAX },				\
 	{ LONG_MAX, LONG_MAX },				\
 }
diff -u --recursive --new-file v2.3.11/linux/include/asm-i386/apic.h linux/include/asm-i386/apic.h
--- v2.3.11/linux/include/asm-i386/apic.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-i386/apic.h	Sun Jul 25 10:26:01 1999
@@ -0,0 +1,95 @@
+#ifndef __ASM_APIC_H
+#define __ASM_APIC_H
+
+/*
+ * Constants for various Intel APICs. (local APIC, IOAPIC, etc.)
+ *
+ * Alan Cox <Alan.Cox@linux.org>, 1995.
+ */
+#define		APIC_PHYS_BASE	0xfee00000 /* IA s/w dev Vol 3, Section 7.4 */
+ 
+#define		APIC_ID		0x20
+#define			GET_APIC_ID(x)		(((x)>>24)&0x0F)
+#define		APIC_VERSION	0x30
+#define		APIC_TASKPRI	0x80
+#define			APIC_TPRI_MASK		0xFF
+#define		APIC_ARBPRI	0x90
+#define			APIC_ARBPRI_MASK	0xFF
+#define		APIC_PROCPRI	0xA0
+#define		APIC_EOI	0xB0
+#define			APIC_EIO_ACK		0x0		/* Write this to the EOI register */
+#define		APIC_RRR	0xC0
+#define		APIC_LDR	0xD0
+#define			APIC_LDR_MASK		(0xFF<<24)
+#define			GET_APIC_LOGICAL_ID(x)	(((x)>>24)&0xFF)
+#define			SET_APIC_LOGICAL_ID(x)	(((x)<<24))
+#define		APIC_DFR	0xE0
+#define			GET_APIC_DFR(x)		(((x)>>28)&0x0F)
+#define			SET_APIC_DFR(x)		((x)<<28)
+#define		APIC_SPIV	0xF0
+#define		APIC_ISR	0x100
+#define		APIC_TMR	0x180
+#define 	APIC_IRR	0x200
+#define 	APIC_ESR	0x280
+#define			APIC_ESR_SEND_CS	0x00001
+#define			APIC_ESR_RECV_CS	0x00002
+#define			APIC_ESR_SEND_ACC	0x00004
+#define			APIC_ESR_RECV_ACC	0x00008
+#define			APIC_ESR_SENDILL	0x00020
+#define			APIC_ESR_RECVILL	0x00040
+#define			APIC_ESR_ILLREGA	0x00080
+#define		APIC_ICR	0x300
+#define			APIC_DEST_SELF		0x40000
+#define			APIC_DEST_ALLINC	0x80000
+#define			APIC_DEST_ALLBUT	0xC0000
+#define			APIC_DEST_RR_MASK	0x30000
+#define			APIC_DEST_RR_INVALID	0x00000
+#define			APIC_DEST_RR_INPROG	0x10000
+#define			APIC_DEST_RR_VALID	0x20000
+#define			APIC_DEST_LEVELTRIG	0x08000
+#define			APIC_DEST_ASSERT	0x04000
+#define			APIC_DEST_BUSY		0x01000
+#define			APIC_DEST_LOGICAL	0x00800
+#define			APIC_DEST_DM_FIXED	0x00000
+#define			APIC_DEST_DM_LOWEST	0x00100
+#define			APIC_DEST_DM_SMI	0x00200
+#define			APIC_DEST_DM_REMRD	0x00300
+#define			APIC_DEST_DM_NMI	0x00400
+#define			APIC_DEST_DM_INIT	0x00500
+#define			APIC_DEST_DM_STARTUP	0x00600
+#define			APIC_DEST_VECTOR_MASK	0x000FF
+#define		APIC_ICR2	0x310
+#define			GET_APIC_DEST_FIELD(x)	(((x)>>24)&0xFF)
+#define			SET_APIC_DEST_FIELD(x)	((x)<<24)
+#define		APIC_LVTT	0x320
+#define		APIC_LVT0	0x350
+#define			APIC_LVT_TIMER_PERIODIC		(1<<17)
+#define			APIC_LVT_MASKED			(1<<16)
+#define			APIC_LVT_LEVEL_TRIGGER		(1<<15)
+#define			APIC_LVT_REMOTE_IRR		(1<<14)
+#define			APIC_INPUT_POLARITY		(1<<13)
+#define			APIC_SEND_PENDING		(1<<12)
+#define			GET_APIC_DELIVERY_MODE(x)	(((x)>>8)&0x7)
+#define			SET_APIC_DELIVERY_MODE(x,y)	(((x)&~0x700)|((y)<<8))
+#define				APIC_MODE_FIXED		0x0
+#define				APIC_MODE_NMI		0x4
+#define				APIC_MODE_EXINT		0x7
+#define 	APIC_LVT1	0x360
+#define		APIC_LVERR	0x370
+#define		APIC_TMICT	0x380
+#define		APIC_TMCCT	0x390
+#define		APIC_TDCR	0x3E0
+#define			APIC_TDR_DIV_1		0xB
+#define			APIC_TDR_DIV_2		0x0
+#define			APIC_TDR_DIV_4		0x1
+#define			APIC_TDR_DIV_8		0x2
+#define			APIC_TDR_DIV_16		0x3
+#define			APIC_TDR_DIV_32		0x8
+#define			APIC_TDR_DIV_64		0x9
+#define			APIC_TDR_DIV_128	0xA
+
+#define APIC_BASE (fix_to_virt(FIX_APIC_BASE))
+
+#define MAX_IO_APICS 8
+
+#endif
diff -u --recursive --new-file v2.3.11/linux/include/asm-i386/desc.h linux/include/asm-i386/desc.h
--- v2.3.11/linux/include/asm-i386/desc.h	Wed Jul 21 15:46:48 1999
+++ linux/include/asm-i386/desc.h	Sun Jul 25 23:15:13 1999
@@ -69,17 +69,28 @@
 extern void set_ldt_desc(unsigned int n, void *addr, unsigned int size);
 extern void set_tss_desc(unsigned int n, void *addr);
 
+extern inline void clear_LDT(void)
+{
+	int cpu = smp_processor_id();
+	set_ldt_desc(cpu, &default_ldt, 1);
+	__load_LDT(cpu);
+}
+
 /*
  * load one particular LDT into the current CPU
  */
 extern inline void load_LDT (struct mm_struct *mm)
 {
 	int cpu = smp_processor_id();
+	void *segments = mm->segments;
+	int count = LDT_ENTRIES;
 
-	if (mm->segments)
-		set_ldt_desc(cpu, mm->segments, LDT_ENTRIES);
-	else
-		set_ldt_desc(cpu, &default_ldt, 1);
+	if (!segments) {
+		segments = &default_ldt;
+		count = 1;
+	}
+		
+	set_ldt_desc(cpu, segments, count);
 	__load_LDT(cpu);
 }
 
diff -u --recursive --new-file v2.3.11/linux/include/asm-i386/fixmap.h linux/include/asm-i386/fixmap.h
--- v2.3.11/linux/include/asm-i386/fixmap.h	Tue Jun 22 14:41:40 1999
+++ linux/include/asm-i386/fixmap.h	Wed Jul 28 13:56:29 1999
@@ -13,6 +13,7 @@
 
 #include <linux/config.h>
 #include <linux/kernel.h>
+#include <asm/apic.h>
 #include <asm/page.h>
 
 /*
@@ -45,7 +46,8 @@
 	FIX_APIC_BASE,	/* local (CPU) APIC) -- required for SMP or not */
 #endif
 #ifdef CONFIG_X86_IO_APIC
-	FIX_IO_APIC_BASE,
+	FIX_IO_APIC_BASE_0,
+	FIX_IO_APIC_BASE_END = FIX_IO_APIC_BASE_0 + MAX_IO_APICS-1,
 #endif
 #ifdef CONFIG_X86_VISWS_APIC
 	FIX_CO_CPU,	/* Cobalt timer */
diff -u --recursive --new-file v2.3.11/linux/include/asm-i386/i82489.h linux/include/asm-i386/i82489.h
--- v2.3.11/linux/include/asm-i386/i82489.h	Thu Jan 21 11:28:40 1999
+++ linux/include/asm-i386/i82489.h	Wed Dec 31 16:00:00 1969
@@ -1,103 +0,0 @@
-#ifndef __ASM_I82489_H
-#define __ASM_I82489_H
-
-/*
- *	Offsets for programming the 82489 and Pentium integrated APIC
- *
- *	Alan Cox <Alan.Cox@linux.org>, 1995.
- */
-#define		APIC_PHYS_BASE	0xfee00000 /* IA s/w dev Vol 3, Section 7.4 */
- 
-#define		APIC_ID		0x20
-#define			GET_APIC_ID(x)		(((x)>>24)&0x0F)
-#define		APIC_VERSION	0x30
-#define		APIC_TASKPRI	0x80
-#define			APIC_TPRI_MASK		0xFF
-#define		APIC_ARBPRI	0x90
-#define			APIC_ARBPRI_MASK	0xFF
-#define		APIC_PROCPRI	0xA0
-#define		APIC_EOI	0xB0
-#define			APIC_EIO_ACK		0x0		/* Write this to the EOI register */
-#define		APIC_RRR	0xC0
-#define		APIC_LDR	0xD0
-#define			APIC_LDR_MASK		(0xFF<<24)
-#define			GET_APIC_LOGICAL_ID(x)	(((x)>>24)&0xFF)
-#define			SET_APIC_LOGICAL_ID(x)	(((x)<<24))
-#define		APIC_DFR	0xE0
-#define			GET_APIC_DFR(x)		(((x)>>28)&0x0F)
-#define			SET_APIC_DFR(x)		((x)<<28)
-#define		APIC_SPIV	0xF0
-#define		APIC_ISR	0x100
-#define		APIC_TMR	0x180
-#define 	APIC_IRR	0x200
-#define 	APIC_ESR	0x280
-#define			APIC_ESR_SEND_CS	0x00001
-#define			APIC_ESR_RECV_CS	0x00002
-#define			APIC_ESR_SEND_ACC	0x00004
-#define			APIC_ESR_RECV_ACC	0x00008
-#define			APIC_ESR_SENDILL	0x00020
-#define			APIC_ESR_RECVILL	0x00040
-#define			APIC_ESR_ILLREGA	0x00080
-#define		APIC_ICR	0x300
-#define			APIC_DEST_SELF		0x40000
-#define			APIC_DEST_ALLINC	0x80000
-#define			APIC_DEST_ALLBUT	0xC0000
-#define			APIC_DEST_RR_MASK	0x30000
-#define			APIC_DEST_RR_INVALID	0x00000
-#define			APIC_DEST_RR_INPROG	0x10000
-#define			APIC_DEST_RR_VALID	0x20000
-#define			APIC_DEST_LEVELTRIG	0x08000
-#define			APIC_DEST_ASSERT	0x04000
-#define			APIC_DEST_BUSY		0x01000
-#define			APIC_DEST_LOGICAL	0x00800
-#define			APIC_DEST_DM_FIXED	0x00000
-#define			APIC_DEST_DM_LOWEST	0x00100
-#define			APIC_DEST_DM_SMI	0x00200
-#define			APIC_DEST_DM_REMRD	0x00300
-#define			APIC_DEST_DM_NMI	0x00400
-#define			APIC_DEST_DM_INIT	0x00500
-#define			APIC_DEST_DM_STARTUP	0x00600
-#define			APIC_DEST_VECTOR_MASK	0x000FF
-#define		APIC_ICR2	0x310
-#define			GET_APIC_DEST_FIELD(x)	(((x)>>24)&0xFF)
-#define			SET_APIC_DEST_FIELD(x)	((x)<<24)
-#define		APIC_LVTT	0x320
-#define		APIC_LVT0	0x350
-#define			APIC_LVT_TIMER_PERIODIC		(1<<17)
-#define			APIC_LVT_MASKED			(1<<16)
-#define			APIC_LVT_LEVEL_TRIGGER		(1<<15)
-#define			APIC_LVT_REMOTE_IRR		(1<<14)
-#define			APIC_INPUT_POLARITY		(1<<13)
-#define			APIC_SEND_PENDING		(1<<12)
-#define			GET_APIC_DELIVERY_MODE(x)	(((x)>>8)&0x7)
-#define			SET_APIC_DELIVERY_MODE(x,y)	(((x)&~0x700)|((y)<<8))
-#define				APIC_MODE_FIXED		0x0
-#define				APIC_MODE_NMI		0x4
-#define				APIC_MODE_EXINT		0x7
-#define 	APIC_LVT1	0x360
-#define		APIC_LVERR	0x370
-#define		APIC_TMICT	0x380
-#define		APIC_TMCCT	0x390
-#define		APIC_TDCR	0x3E0
-#define			APIC_TDR_DIV_1		0xB
-#define			APIC_TDR_DIV_2		0x0
-#define			APIC_TDR_DIV_4		0x1
-#define			APIC_TDR_DIV_8		0x2
-#define			APIC_TDR_DIV_16		0x3
-#define			APIC_TDR_DIV_32		0x8
-#define			APIC_TDR_DIV_64		0x9
-#define			APIC_TDR_DIV_128	0xA
-
-#define APIC_BASE (fix_to_virt(FIX_APIC_BASE))
-
-extern __inline void apic_write(unsigned long reg, unsigned long v)
-{
-	*((volatile unsigned long *)(APIC_BASE+reg))=v;
-}
-
-extern __inline unsigned long apic_read(unsigned long reg)
-{
-	return *((volatile unsigned long *)(APIC_BASE+reg));
-}
-
-#endif
diff -u --recursive --new-file v2.3.11/linux/include/asm-i386/mmu_context.h linux/include/asm-i386/mmu_context.h
--- v2.3.11/linux/include/asm-i386/mmu_context.h	Wed Jul 21 15:46:48 1999
+++ linux/include/asm-i386/mmu_context.h	Wed Jul 28 13:56:27 1999
@@ -2,26 +2,29 @@
 #define __I386_MMU_CONTEXT_H
 
 #include <asm/desc.h>
+#include <asm/atomic.h>
 
 /*
- * get a new mmu context.. x86's don't know much about contexts,
- * but we have to reload the new LDT in exec().
- *
- * We implement lazy MMU context-switching on x86 to optimize context
- * switches done to/from kernel threads. Kernel threads 'inherit' the
- * previous MM, so Linux doesnt have to flush the TLB. In most cases
- * we switch back to the same process so we preserve the TLB cache.
- * This all means that kernel threads have about as much overhead as
- * a function call ...
- */
-#define get_mmu_context(next) do { } while (0)
-#define set_mmu_context(prev,next) do { next->thread.cr3 = prev->thread.cr3; } while(0)
-
-#define init_new_context(mm)	do { } while(0)
-/*
  * possibly do the LDT unload here?
  */
-#define destroy_context(mm)	do { } while(0)
-#define activate_context(x)	load_LDT((x)->mm)
+#define destroy_context(mm)		do { } while(0)
+#define init_new_context(tsk,mm)	do { } while (0)
+
+static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, unsigned cpu)
+{
+
+	if (prev != next) {
+		/*
+		 * Re-load LDT if necessary
+		 */
+		if (prev->segments != next->segments)
+			load_LDT(next);
+
+		/* Re-load page tables */
+		asm volatile("movl %0,%%cr3": :"r" (__pa(next->pgd)));
+		clear_bit(cpu, &prev->cpu_vm_mask);
+	}
+	set_bit(cpu, &next->cpu_vm_mask);
+}
 
 #endif
diff -u --recursive --new-file v2.3.11/linux/include/asm-i386/parport.h linux/include/asm-i386/parport.h
--- v2.3.11/linux/include/asm-i386/parport.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-i386/parport.h	Tue Jul 27 13:55:52 1999
@@ -0,0 +1,46 @@
+/*
+ * parport.h: ia32-specific parport initialisation
+ *
+ * Copyright (C) 1999  Tim Waugh <tim@cyberelk.demon.co.uk>
+ *
+ * This file should only be included by drivers/parport/parport_pc.c.
+ */
+
+#ifndef _ASM_I386_PARPORT_H
+#define _ASM_I386_PARPORT_H 1
+
+/* Maximum number of ports to support.  It is useless to set this greater
+   than PARPORT_MAX (in <linux/parport.h>).  */
+#define PARPORT_PC_MAX_PORTS  8
+
+static int __init probe_one_port(unsigned long int base,
+				 unsigned long int base_hi,
+				 int irq, int dma);
+static int __init parport_pc_init_pci(int irq, int dma);
+
+static int user_specified __initdata = 0;
+int __init
+parport_pc_init(int *io, int *io_hi, int *irq, int *dma)
+{
+	int count = 0, i = 0;
+
+	if (io && *io) {
+		/* Only probe the ports we were given. */
+		user_specified = 1;
+		do {
+			if (!*io_hi) *io_hi = 0x400 + *io;
+			count += probe_one_port(*(io++), *(io_hi++),
+						*(irq++), *(dma++));
+		} while (*io && (++i < PARPORT_PC_MAX_PORTS));
+	} else {
+		/* Probe all the likely ports. */
+		count += probe_one_port(0x3bc, 0x7bc, irq[0], dma[0]);
+		count += probe_one_port(0x378, 0x778, irq[0], dma[0]);
+		count += probe_one_port(0x278, 0x678, irq[0], dma[0]);
+		count += parport_pc_init_pci (irq[0], dma[0]);
+	}
+
+        return count;
+}
+
+#endif /* !(_ASM_I386_PARPORT_H) */
diff -u --recursive --new-file v2.3.11/linux/include/asm-i386/pgtable.h linux/include/asm-i386/pgtable.h
--- v2.3.11/linux/include/asm-i386/pgtable.h	Wed Jul 21 15:46:48 1999
+++ linux/include/asm-i386/pgtable.h	Wed Jul 28 13:56:31 1999
@@ -17,6 +17,8 @@
 #include <asm/fixmap.h>
 #include <linux/threads.h>
 
+extern pgd_t swapper_pg_dir[1024];
+
 /* Caches aren't brain-dead on the intel. */
 #define flush_cache_all()			do { } while (0)
 #define flush_cache_mm(mm)			do { } while (0)
@@ -56,21 +58,21 @@
 
 static inline void flush_tlb_mm(struct mm_struct *mm)
 {
-	if (mm == current->mm)
+	if (mm == current->active_mm)
 		__flush_tlb();
 }
 
 static inline void flush_tlb_page(struct vm_area_struct *vma,
 	unsigned long addr)
 {
-	if (vma->vm_mm == current->mm)
+	if (vma->vm_mm == current->active_mm)
 		__flush_tlb_one(addr);
 }
 
 static inline void flush_tlb_range(struct mm_struct *mm,
 	unsigned long start, unsigned long end)
 {
-	if (mm == current->mm)
+	if (mm == current->active_mm)
 		__flush_tlb();
 }
 
@@ -86,79 +88,19 @@
 #define local_flush_tlb() \
 	__flush_tlb()
 
+extern void flush_tlb_all(void);
+extern void flush_tlb_current_task(void);
+extern void flush_tlb_mm(struct mm_struct *);
+extern void flush_tlb_page(struct vm_area_struct *, unsigned long);
 
-#define CLEVER_SMP_INVALIDATE
-#ifdef CLEVER_SMP_INVALIDATE
-
-/*
- *	Smarter SMP flushing macros. 
- *		c/o Linus Torvalds.
- *
- *	These mean you can really definitely utterly forget about
- *	writing to user space from interrupts. (Its not allowed anyway).
- */
- 
-static inline void flush_tlb_current_task(void)
-{
-	/* just one copy of this mm? */
-	if (atomic_read(&current->mm->mm_users) == 1)
-		local_flush_tlb();	/* and that's us, so.. */
-	else
-		smp_flush_tlb();
-}
-
-#define flush_tlb() flush_tlb_current_task()
-
-#define flush_tlb_all() smp_flush_tlb()
-
-static inline void flush_tlb_mm(struct mm_struct * mm)
-{
-	if (mm == current->mm && atomic_read(&mm->mm_users) == 1)
-		local_flush_tlb();
-	else
-		smp_flush_tlb();
-}
-
-static inline void flush_tlb_page(struct vm_area_struct * vma,
-	unsigned long va)
-{
-	if (vma->vm_mm == current->mm && atomic_read(&current->mm->mm_users) == 1)
-		__flush_tlb_one(va);
-	else
-		smp_flush_tlb();
-}
+#define flush_tlb()	flush_tlb_current_task()
 
-static inline void flush_tlb_range(struct mm_struct * mm,
-	unsigned long start, unsigned long end)
+static inline void flush_tlb_range(struct mm_struct * mm, unsigned long start, unsigned long end)
 {
 	flush_tlb_mm(mm);
 }
 
 
-#else
-
-#define flush_tlb() \
-	smp_flush_tlb()
-
-#define flush_tlb_all() flush_tlb()
-
-static inline void flush_tlb_mm(struct mm_struct *mm)
-{
-	flush_tlb();
-}
-
-static inline void flush_tlb_page(struct vm_area_struct *vma,
-	unsigned long addr)
-{
-	flush_tlb();
-}
-
-static inline void flush_tlb_range(struct mm_struct *mm,
-	unsigned long start, unsigned long end)
-{
-	flush_tlb();
-}
-#endif
 #endif
 #endif /* !__ASSEMBLY__ */
 
@@ -302,15 +244,6 @@
 #define PAGE_PTR(address) \
 ((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK)
 
-/* to set the page-dir */
-#define SET_PAGE_DIR(tsk,pgdir) \
-do { \
-	unsigned long __pgdir = __pa(pgdir); \
-	(tsk)->thread.cr3 = __pgdir; \
-	if ((tsk) == current) \
-		__asm__ __volatile__("movl %0,%%cr3": :"r" (__pgdir)); \
-} while (0)
-
 #define pte_none(x)	(!pte_val(x))
 #define pte_present(x)	(pte_val(x) & (_PAGE_PRESENT | _PAGE_PROTNONE))
 #define pte_clear(xp)	do { pte_val(*(xp)) = 0; } while (0)
@@ -401,13 +334,11 @@
 
 extern __inline__ pgd_t *get_pgd_slow(void)
 {
-	pgd_t *ret = (pgd_t *)__get_free_page(GFP_KERNEL), *init;
+	pgd_t *ret = (pgd_t *)__get_free_page(GFP_KERNEL);
 
 	if (ret) {
-		init = pgd_offset(&init_mm, 0);
-		memset (ret, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
-		memcpy (ret + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
-			(PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
+		memset(ret, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
+		memcpy(ret + USER_PTRS_PER_PGD, swapper_pg_dir + USER_PTRS_PER_PGD, (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
 	}
 	return ret;
 }
@@ -416,9 +347,9 @@
 {
 	unsigned long *ret;
 
-	if((ret = pgd_quicklist) != NULL) {
+	if ((ret = pgd_quicklist) != NULL) {
 		pgd_quicklist = (unsigned long *)(*ret);
-		ret[0] = ret[1];
+		ret[0] = 0;
 		pgtable_cache_size--;
 	} else
 		ret = (unsigned long *)get_pgd_slow();
@@ -571,8 +502,6 @@
 			pgd[address >> PGDIR_SHIFT] = entry;
 #endif
 }
-
-extern pgd_t swapper_pg_dir[1024];
 
 /*
  * The i386 doesn't have any external MMU info: the kernel page
diff -u --recursive --new-file v2.3.11/linux/include/asm-i386/processor.h linux/include/asm-i386/processor.h
--- v2.3.11/linux/include/asm-i386/processor.h	Wed Jul 21 15:46:48 1999
+++ linux/include/asm-i386/processor.h	Wed Jul 28 13:56:29 1999
@@ -267,7 +267,7 @@
 	unsigned short	ss1,__ss1h;
 	unsigned long	esp2;
 	unsigned short	ss2,__ss2h;
-	unsigned long	cr3;
+	unsigned long	__cr3;
 	unsigned long	eip;
 	unsigned long	eflags;
 	unsigned long	eax,ecx,edx,ebx;
@@ -292,7 +292,6 @@
 
 struct thread_struct {
 	unsigned long	esp0;
-	unsigned long	cr3;
 	unsigned long	eip;
 	unsigned long	esp;
 	unsigned long	fs;
@@ -313,7 +312,7 @@
 };
 
 #define INIT_THREAD  {						\
-	0,(long) &swapper_pg_dir - PAGE_OFFSET,			\
+	0,							\
 	0, 0, 0, 0, 						\
 	{ [0 ... 7] = 0 },	/* debugging registers */	\
 	0, 0, 0,						\
@@ -330,7 +329,7 @@
 	sizeof(init_stack) + (long) &init_stack, /* esp0 */	\
 	__KERNEL_DS, 0, /* ss0 */				\
 	0,0,0,0,0,0, /* stack1, stack2 */			\
-	(long) &swapper_pg_dir - PAGE_OFFSET, /* cr3 */		\
+	0, /* cr3 */						\
 	0,0, /* eip,eflags */					\
 	0,0,0,0, /* eax,ecx,edx,ebx */				\
 	0,0,0,0, /* esp,ebp,esi,edi */				\
diff -u --recursive --new-file v2.3.11/linux/include/asm-i386/resource.h linux/include/asm-i386/resource.h
--- v2.3.11/linux/include/asm-i386/resource.h	Wed Jul 21 15:46:48 1999
+++ linux/include/asm-i386/resource.h	Mon Jul 26 22:41:09 1999
@@ -29,7 +29,7 @@
 	{        0, LONG_MAX },				\
 	{ LONG_MAX, LONG_MAX },				\
 	{ 0, 0 },					\
-	{ NR_OPEN, NR_OPEN },				\
+	{ INR_OPEN, INR_OPEN },				\
 	{ LONG_MAX, LONG_MAX },				\
 	{ LONG_MAX, LONG_MAX },				\
 }
diff -u --recursive --new-file v2.3.11/linux/include/asm-i386/semaphore.h linux/include/asm-i386/semaphore.h
--- v2.3.11/linux/include/asm-i386/semaphore.h	Tue Jun 22 14:41:41 1999
+++ linux/include/asm-i386/semaphore.h	Wed Jul 28 13:56:30 1999
@@ -17,6 +17,10 @@
  *		       potential and subtle race discovered by Ulrich Schmid
  *		       in down_interruptible(). Since I started to play here I
  *		       also implemented the `trylock' semaphore operation.
+ *          1999-07-02 Artur Skawina <skawina@geocities.com>
+ *                     Optimized "0(ecx)" -> "(ecx)" (the assembler does not
+ *                     do this). Changed calling sequences from push/jmp to
+ *                     traditional call/ret.
  *
  * If you would like to see an analysis of this implementation, please
  * ftp to gcom.com and download the file
@@ -112,12 +116,12 @@
 #ifdef __SMP__
 		"lock ; "
 #endif
-		"decl 0(%0)\n\t"
+		"decl (%0)\n\t"     /* --sem->count */
 		"js 2f\n"
 		"1:\n"
 		".section .text.lock,\"ax\"\n"
-		"2:\tpushl $1b\n\t"
-		"jmp __down_failed\n"
+		"2:\tcall __down_failed\n\t"
+		"jmp 1b\n"
 		".previous"
 		:/* no outputs */
 		:"c" (sem)
@@ -137,13 +141,13 @@
 #ifdef __SMP__
 		"lock ; "
 #endif
-		"decl 0(%1)\n\t"
+		"decl (%1)\n\t"     /* --sem->count */
 		"js 2f\n\t"
 		"xorl %0,%0\n"
 		"1:\n"
 		".section .text.lock,\"ax\"\n"
-		"2:\tpushl $1b\n\t"
-		"jmp __down_failed_interruptible\n"
+		"2:\tcall __down_failed_interruptible\n\t"
+		"jmp 1b\n"
 		".previous"
 		:"=a" (result)
 		:"c" (sem)
@@ -164,13 +168,13 @@
 #ifdef __SMP__
 		"lock ; "
 #endif
-		"decl 0(%1)\n\t"
+		"decl (%1)\n\t"     /* --sem->count */
 		"js 2f\n\t"
 		"xorl %0,%0\n"
 		"1:\n"
 		".section .text.lock,\"ax\"\n"
-		"2:\tpushl $1b\n\t"
-		"jmp __down_failed_trylock\n"
+		"2:\tcall __down_failed_trylock\n\t"
+		"jmp 1b\n"
 		".previous"
 		:"=a" (result)
 		:"c" (sem)
@@ -194,12 +198,12 @@
 #ifdef __SMP__
 		"lock ; "
 #endif
-		"incl 0(%0)\n\t"
+		"incl (%0)\n\t"     /* ++sem->count */
 		"jle 2f\n"
 		"1:\n"
 		".section .text.lock,\"ax\"\n"
-		"2:\tpushl $1b\n\t"
-		"jmp __up_wakeup\n"
+		"2:\tcall __up_wakeup\n\t"
+		"jmp 1b\n"
 		".previous"
 		:/* no outputs */
 		:"c" (sem)
diff -u --recursive --new-file v2.3.11/linux/include/asm-i386/signal.h linux/include/asm-i386/signal.h
--- v2.3.11/linux/include/asm-i386/signal.h	Sun Dec 27 22:18:28 1998
+++ linux/include/asm-i386/signal.h	Wed Jul 28 12:55:50 1999
@@ -180,12 +180,12 @@
 
 extern __inline__ void sigaddset(sigset_t *set, int _sig)
 {
-	__asm__("btsl %1,%0" : "=m"(*set) : "ir"(_sig - 1) : "cc");
+	__asm__("btsl %1,%0" : "=m"(*set) : "Ir"(_sig - 1) : "cc");
 }
 
 extern __inline__ void sigdelset(sigset_t *set, int _sig)
 {
-	__asm__("btrl %1,%0" : "=m"(*set) : "ir"(_sig - 1) : "cc");
+	__asm__("btrl %1,%0" : "=m"(*set) : "Ir"(_sig - 1) : "cc");
 }
 
 extern __inline__ int __const_sigismember(sigset_t *set, int _sig)
@@ -198,7 +198,7 @@
 {
 	int ret;
 	__asm__("btl %2,%1\n\tsbbl %0,%0"
-		: "=r"(ret) : "m"(*set), "ir"(_sig-1) : "cc");
+		: "=r"(ret) : "m"(*set), "Ir"(_sig-1) : "cc");
 	return ret;
 }
 
diff -u --recursive --new-file v2.3.11/linux/include/asm-i386/smp.h linux/include/asm-i386/smp.h
--- v2.3.11/linux/include/asm-i386/smp.h	Wed Jul 21 15:46:48 1999
+++ linux/include/asm-i386/smp.h	Wed Jul 28 13:56:29 1999
@@ -8,7 +8,7 @@
 #ifdef CONFIG_X86_LOCAL_APIC
 #ifndef ASSEMBLY
 #include <asm/fixmap.h>
-#include <asm/i82489.h>
+#include <asm/apic.h>
 #include <asm/bitops.h>
 #endif
 #endif
@@ -184,6 +184,16 @@
 extern inline int cpu_logical_map(int cpu)
 {
 	return __cpu_logical_map[cpu];
+}
+
+extern __inline void apic_write(unsigned long reg, unsigned long v)
+{
+	*((volatile unsigned long *)(APIC_BASE+reg))=v;
+}
+
+extern __inline unsigned long apic_read(unsigned long reg)
+{
+	return *((volatile unsigned long *)(APIC_BASE+reg));
 }
 
 
diff -u --recursive --new-file v2.3.11/linux/include/asm-m68k/resource.h linux/include/asm-m68k/resource.h
--- v2.3.11/linux/include/asm-m68k/resource.h	Tue Jan  5 11:20:43 1999
+++ linux/include/asm-m68k/resource.h	Mon Jul 26 22:41:09 1999
@@ -29,7 +29,7 @@
   {       0, LONG_MAX}, \
   {LONG_MAX, LONG_MAX}, \
   {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER}, \
-  {NR_OPEN, NR_OPEN},   \
+  {INR_OPEN, INR_OPEN}, \
   {LONG_MAX, LONG_MAX}, \
   {LONG_MAX, LONG_MAX}  \
 }
diff -u --recursive --new-file v2.3.11/linux/include/asm-mips/resource.h linux/include/asm-mips/resource.h
--- v2.3.11/linux/include/asm-mips/resource.h	Wed Jun 30 13:38:20 1999
+++ linux/include/asm-mips/resource.h	Mon Jul 26 22:41:09 1999
@@ -34,7 +34,7 @@
 	{ LONG_MAX, LONG_MAX },				\
 	{ _STK_LIM, LONG_MAX },				\
 	{        0, LONG_MAX },				\
-	{ NR_OPEN, NR_OPEN },				\
+	{ INR_OPEN, INR_OPEN },				\
 	{ LONG_MAX, LONG_MAX },				\
 	{ LONG_MAX, LONG_MAX },				\
 	{ MAX_TASKS_PER_USER, MAX_TASKS_PER_USER },	\
diff -u --recursive --new-file v2.3.11/linux/include/asm-ppc/resource.h linux/include/asm-ppc/resource.h
--- v2.3.11/linux/include/asm-ppc/resource.h	Mon Dec 21 08:37:24 1998
+++ linux/include/asm-ppc/resource.h	Mon Jul 26 22:41:09 1999
@@ -25,7 +25,7 @@
     {       0, LONG_MAX},			/* RLIMIT_CORE */	\
     {LONG_MAX, LONG_MAX},			/* RLIMIT_RSS */	\
     {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER},	/* RLIMIT_NPROC */	\
-    { NR_OPEN,  NR_OPEN},			/* RLIMIT_NOFILE */	\
+    {INR_OPEN, INR_OPEN},			/* RLIMIT_NOFILE */	\
     {LONG_MAX, LONG_MAX},			/* RLIMIT_MEMLOCK */	\
     {LONG_MAX, LONG_MAX},			/* RLIMIT_AS */		\
 }
diff -u --recursive --new-file v2.3.11/linux/include/asm-sparc/resource.h linux/include/asm-sparc/resource.h
--- v2.3.11/linux/include/asm-sparc/resource.h	Wed Mar 10 16:53:37 1999
+++ linux/include/asm-sparc/resource.h	Mon Jul 26 22:41:09 1999
@@ -31,7 +31,7 @@
     {LONG_MAX, LONG_MAX}, {LONG_MAX, LONG_MAX},				\
     {LONG_MAX, LONG_MAX}, {_STK_LIM, LONG_MAX},				\
     {       0, LONG_MAX}, {LONG_MAX, LONG_MAX},				\
-    {NR_OPEN, NR_OPEN}, {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER},	\
+    {INR_OPEN, INR_OPEN}, {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER},	\
     {LONG_MAX, LONG_MAX}, {LONG_MAX, LONG_MAX}                          \
 }
 
diff -u --recursive --new-file v2.3.11/linux/include/asm-sparc64/parport.h linux/include/asm-sparc64/parport.h
--- v2.3.11/linux/include/asm-sparc64/parport.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sparc64/parport.h	Tue Jul 27 13:55:52 1999
@@ -0,0 +1,152 @@
+/* $Id$
+ * parport.h: sparc64 specific parport initialization and dma.
+ *
+ * Copyright (C) 1999  Eddie C. Dost  (ecd@skynet.be)
+ */
+
+#ifndef _ASM_SPARC64_PARPORT_H
+#define _ASM_SPARC64_PARPORT_H 1
+
+#include <asm/ebus.h>
+#include <asm/ns87303.h>
+
+static struct linux_ebus_dma *sparc_ebus_dmas[PARPORT_MAX];
+
+static __inline__ void
+reset_dma(unsigned int dmanr)
+{
+	unsigned int dcsr;
+
+	dcsr = readl(&sparc_ebus_dmas[dmanr]->dcsr) & EBUS_DCSR_INT_EN;
+	writel(EBUS_DCSR_RESET, &sparc_ebus_dmas[dmanr]->dcsr);
+
+	dcsr |= EBUS_DCSR_BURST_SZ_16 | EBUS_DCSR_TCI_DIS |
+	        EBUS_DCSR_EN_CNT;
+	writel(dcsr, &sparc_ebus_dmas[dmanr]->dcsr);
+}
+
+static __inline__ void
+enable_dma(unsigned int dmanr)
+{
+	unsigned int dcsr;
+
+	dcsr = readl(&sparc_ebus_dmas[dmanr]->dcsr);
+	dcsr |= EBUS_DCSR_EN_DMA;
+	writel(dcsr, &sparc_ebus_dmas[dmanr]->dcsr);
+}
+
+static __inline__ void
+disable_dma(unsigned int dmanr)
+{
+	unsigned int dcsr;
+
+	dcsr = readl(&sparc_ebus_dmas[dmanr]->dcsr);
+	while (dcsr & EBUS_DCSR_DRAIN)
+		dcsr = readl(&sparc_ebus_dmas[dmanr]->dcsr);
+	dcsr &= ~(EBUS_DCSR_EN_DMA);
+	if (dcsr & EBUS_DCSR_ERR_PEND) {
+		reset_dma(dmanr);
+		dcsr &= ~(EBUS_DCSR_ERR_PEND);
+	}
+	writel(dcsr, &sparc_ebus_dmas[dmanr]->dcsr);
+}
+
+static __inline__ void
+clear_dma_ff(unsigned int dmanr)
+{
+	/* nothing */
+}
+
+static __inline__ void
+set_dma_mode(unsigned int dmanr, char mode)
+{
+	unsigned int dcsr;
+
+	dcsr = readl(&sparc_ebus_dmas[dmanr]->dcsr);
+	dcsr |= EBUS_DCSR_EN_CNT | EBUS_DCSR_TC;
+	if (mode == DMA_MODE_WRITE)
+		dcsr &= ~(EBUS_DCSR_WRITE);
+	else
+		dcsr |= EBUS_DCSR_WRITE;
+	writel(dcsr, &sparc_ebus_dmas[dmanr]->dcsr);
+}
+
+static __inline__ void
+set_dma_addr(unsigned int dmanr, unsigned int addr)
+{
+	writel(addr, &sparc_ebus_dmas[dmanr]->dacr);
+}
+
+static __inline__ void
+set_dma_count(unsigned int dmanr, unsigned int count)
+{
+	writel(count, &sparc_ebus_dmas[dmanr]->dbcr);
+}
+
+static __inline__ int
+get_dma_residue(unsigned int dmanr)
+{
+	return readl(&sparc_ebus_dmas[dmanr]->dbcr);
+}
+
+static int __init probe_one_port(unsigned long int base,
+				 unsigned long int base_hi,
+				 int irq, int dma);
+static int __init parport_pc_init_pci(int irq, int dma);
+
+int __init
+parport_pc_init(int *io, int *io_hi, int *irq, int *dma)
+{
+	struct linux_ebus *ebus;
+	struct linux_ebus_device *edev;
+	int count = 0;
+
+	if (!pci_present())
+		return 0;
+
+	for_each_ebus(ebus) {
+		for_each_ebusdev(edev, ebus) {
+			if (!strcmp(edev->prom_name, "ecpp")) {
+				unsigned long base = edev->base_address[0];
+				unsigned long config = edev->base_address[1];
+				unsigned char cfg;
+
+				sparc_ebus_dmas[count] =
+						(struct linux_ebus_dma *)
+							edev->base_address[2];
+
+				/* Enable ECP, set bit 2 of the CTR first */
+				outb(0x04, base + 0x02);
+				cfg = ns87303_readb(config, PCR);
+				cfg |= (PCR_ECP_ENABLE | PCR_ECP_CLK_ENA);
+				ns87303_writeb(config, PCR, cfg);
+
+				/* CTR bit 5 controls direction of port */
+				cfg = ns87303_readb(config, PTR);
+				cfg |= PTR_LPT_REG_DIR;
+				ns87303_writeb(config, PTR, cfg);
+
+				/* Configure IRQ to Push Pull, Level Low */
+				cfg = ns87303_readb(config, PCR);
+				cfg &= ~(PCR_IRQ_ODRAIN);
+				cfg |= PCR_IRQ_POLAR;
+				ns87303_writeb(config, PCR, cfg);
+
+#ifndef HAVE_SLOW_DEVICES
+				/* Enable Zero Wait State for ECP */
+				cfg = ns87303_readb(config, FCR);
+				cfg |= FCR_ZWS_ENA;
+				ns87303_writeb(config, FCR, cfg);
+#endif
+
+				count += probe_one_port(base, base + 0x400,
+						        edev->irqs[0], count);
+			}
+		}
+	}
+
+	count += parport_pc_init_pci(PARPORT_IRQ_AUTO, PARPORT_DMA_NONE);
+	return count;
+}
+
+#endif /* !(_ASM_SPARC64_PARPORT_H */
diff -u --recursive --new-file v2.3.11/linux/include/asm-sparc64/resource.h linux/include/asm-sparc64/resource.h
--- v2.3.11/linux/include/asm-sparc64/resource.h	Wed Mar 10 16:53:38 1999
+++ linux/include/asm-sparc64/resource.h	Mon Jul 26 22:41:09 1999
@@ -30,7 +30,7 @@
     {LONG_MAX, LONG_MAX}, {LONG_MAX, LONG_MAX},				\
     {LONG_MAX, LONG_MAX}, {_STK_LIM, LONG_MAX},				\
     {       0, LONG_MAX}, {LONG_MAX, LONG_MAX},				\
-    {NR_OPEN, NR_OPEN}, {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER},	\
+    {INR_OPEN, INR_OPEN}, {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER},	\
     {LONG_MAX, LONG_MAX}, {LONG_MAX, LONG_MAX}                          \
 }
 
diff -u --recursive --new-file v2.3.11/linux/include/linux/arcdevice.h linux/include/linux/arcdevice.h
--- v2.3.11/linux/include/linux/arcdevice.h	Tue Dec 29 11:18:18 1998
+++ linux/include/linux/arcdevice.h	Wed Jul 28 11:23:14 1999
@@ -69,7 +69,7 @@
  * increased.  The larger it is, though, the longer it will be between
  * necessary transmits - don't set this too large.
  */
-#define TX_TIMEOUT 20
+#define TX_TIMEOUT (20*HZ/100)
 
 
 /* Display warnings about the driver being an ALPHA version.
diff -u --recursive --new-file v2.3.11/linux/include/linux/binfmts.h linux/include/linux/binfmts.h
--- v2.3.11/linux/include/linux/binfmts.h	Wed Jun 30 13:38:20 1999
+++ linux/include/linux/binfmts.h	Wed Jul 28 13:56:37 1999
@@ -38,7 +38,8 @@
 	struct module *module;
 	int (*load_binary)(struct linux_binprm *, struct  pt_regs * regs);
 	int (*load_shlib)(int fd);
-	int (*core_dump)(long signr, struct pt_regs * regs);
+	int (*core_dump)(long signr, struct pt_regs * regs, struct file * file);
+	unsigned long min_coredump;	/* minimal dump size */
 };
 
 extern int register_binfmt(struct linux_binfmt *);
@@ -66,6 +67,7 @@
 extern int copy_strings(int argc,char ** argv,struct linux_binprm *bprm); 
 extern int copy_strings_kernel(int argc,char ** argv,struct linux_binprm *bprm);
 extern void compute_creds(struct linux_binprm *binprm);
+extern int do_coredump(long signr, struct pt_regs * regs);
 
 
 #if 0
diff -u --recursive --new-file v2.3.11/linux/include/linux/file.h linux/include/linux/file.h
--- v2.3.11/linux/include/linux/file.h	Wed Jul 21 15:46:48 1999
+++ linux/include/linux/file.h	Mon Jul 26 22:41:09 1999
@@ -56,18 +56,6 @@
 }
 
 /*
- * Install a file pointer in the fd array.
- */
-extern inline void fd_install(unsigned int fd, struct file * file)
-{
-	struct files_struct *files = current->files;
-
-	write_lock(&files->file_lock);
-	files->fd[fd] = file;
-	write_unlock(&files->file_lock);
-}
-
-/*
  * 23/12/1998 Marcin Dalecki <dalecki@cs.net.pl>: 
  * 
  * Since those functions where calling other functions, it was compleatly 
@@ -89,5 +77,27 @@
 		_fput(file);
 }
 extern void put_filp(struct file *);
+
+/*
+ * Install a file pointer in the fd array.  
+ *
+ * The VFS is full of places where we drop the files lock between
+ * setting the open_fds bitmap and installing the file in the file
+ * array.  At any such point, we are vulnerable to a dup2() race
+ * installing a file in the array before us.  We need to detect this and
+ * fput() the struct file we are about to overwrite in this case.
+ */
+
+extern inline void fd_install(unsigned int fd, struct file * file)
+{
+	struct files_struct *files = current->files;
+	struct file * result;
+	
+	write_lock(&files->file_lock);
+	result = xchg(&files->fd[fd], file);
+	write_unlock(&files->file_lock);
+	if (result)
+		fput(result);
+}
 
 #endif /* __LINUX_FILE_H */
diff -u --recursive --new-file v2.3.11/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.3.11/linux/include/linux/fs.h	Thu Jul  8 15:42:21 1999
+++ linux/include/linux/fs.h	Wed Jul 28 13:56:34 1999
@@ -27,17 +27,19 @@
 
 
 /*
- * It's silly to have NR_OPEN bigger than NR_FILE, but I'll fix
- * that later. Anyway, now the file code is no longer dependent
- * on bitmaps in unsigned longs, but uses the new fd_set structure..
+ * It's silly to have NR_OPEN bigger than NR_FILE, but you can change
+ * the file limit at runtime and only root can increase the per-process
+ * nr_file rlimit, so it's safe to set up a ridiculously high absolute
+ * upper limit on files-per-process.
  *
  * Some programs (notably those using select()) may have to be 
- * recompiled to take full advantage of the new limits..
+ * recompiled to take full advantage of the new limits..  
  */
 
 /* Fixed constants first: */
 #undef NR_OPEN
-#define NR_OPEN 1024
+#define NR_OPEN (1024*1024)	/* Absolute upper limit on fd num */
+#define INR_OPEN 1024		/* Initial setting for nfile rlimits */
 
 #define BLOCK_SIZE_BITS 10
 #define BLOCK_SIZE (1<<BLOCK_SIZE_BITS)
@@ -62,6 +64,7 @@
 #define WRITE 1
 #define READA 2		/* read-ahead  - don't block if no resources */
 #define WRITEA 3	/* write-ahead - don't block if no resources */
+#define WRITERAW 5	/* raw write - don't play with buffer lists */
 
 #ifndef NULL
 #define NULL ((void *) 0)
@@ -228,6 +231,7 @@
 
 	unsigned long b_rsector;	/* Real buffer location on disk */
 	wait_queue_head_t b_wait;
+	struct kiobuf * b_kiobuf;	/* kiobuf which owns this IO */
 };
 
 typedef void (bh_end_io_t)(struct buffer_head *bh, int uptodate);
@@ -704,6 +708,7 @@
 
 asmlinkage int sys_open(const char *, int, int);
 asmlinkage int sys_close(unsigned int);		/* yes, it's really unsigned */
+extern int do_close(unsigned int, int);		/* yes, it's really unsigned */
 extern int do_truncate(struct dentry *, unsigned long);
 extern int get_unused_fd(void);
 extern void put_unused_fd(unsigned int);
diff -u --recursive --new-file v2.3.11/linux/include/linux/iobuf.h linux/include/linux/iobuf.h
--- v2.3.11/linux/include/linux/iobuf.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/iobuf.h	Wed Jul 28 13:56:48 1999
@@ -0,0 +1,80 @@
+/*
+ * iobuf.h
+ *
+ * Defines the structures used to track abstract kernel-space io buffers.
+ *
+ */
+
+#ifndef __LINUX_IOBUF_H
+#define __LINUX_IOBUF_H
+
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <asm/atomic.h>
+
+/*
+ * The kiobuf structure describes a physical set of pages reserved
+ * locked for IO.  The reference counts on each page will have been
+ * incremented, and the flags field will indicate whether or not we have
+ * pre-locked all of the pages for IO.
+ *
+ * kiobufs may be passed in arrays to form a kiovec, but we must
+ * preserve the property that no page is present more than once over the
+ * entire iovec.
+ */
+
+#define KIO_MAX_ATOMIC_IO	64 /* in kb */
+#define KIO_MAX_ATOMIC_BYTES	(64 * 1024)
+#define KIO_STATIC_PAGES	(KIO_MAX_ATOMIC_IO / (PAGE_SIZE >> 10) + 1)
+#define KIO_MAX_SECTORS		(KIO_MAX_ATOMIC_IO * 2)
+
+struct kiobuf 
+{
+	int		nr_pages;	/* Pages actually referenced */
+	int		array_len;	/* Space in the allocated lists */
+	int		offset;		/* Offset to start of valid data */
+	int		length;		/* Number of valid bytes of data */
+
+	/* Keep separate track of the physical addresses and page
+	 * structs involved.  If we do IO to a memory-mapped device
+	 * region, there won't necessarily be page structs defined for
+	 * every address. */
+
+	unsigned long *	pagelist;
+	struct page **	maplist;
+
+	unsigned int	locked : 1;	/* If set, pages has been locked */
+	
+	/* Always embed enough struct pages for 64k of IO */
+	unsigned long	page_array[KIO_STATIC_PAGES];
+	struct page *	map_array[KIO_STATIC_PAGES];
+
+	/* Dynamic state for IO completion: */
+	atomic_t	io_count;	/* IOs still in progress */
+	int		errno;		/* Status of completed IO */
+	void		(*end_io) (struct kiobuf *); /* Completion callback */
+	wait_queue_head_t wait_queue;
+};
+
+
+/* mm/memory.c */
+
+int	map_user_kiobuf(int rw, struct kiobuf *, unsigned long va, size_t len);
+void	unmap_kiobuf(struct kiobuf *iobuf);
+
+/* fs/iobuf.c */
+
+void __init kiobuf_init(void);
+void	simple_wakeup_kiobuf(struct kiobuf *);
+int	alloc_kiovec(int nr, struct kiobuf **);
+void	free_kiovec(int nr, struct kiobuf **);
+int	expand_kiobuf(struct kiobuf *, int);
+void	kiobuf_wait_for_io(struct kiobuf *);
+
+/* fs/buffer.c */
+
+int	brw_kiovec(int rw, int nr, struct kiobuf *iovec[], 
+		   kdev_t dev, unsigned long b[], int size, int bmap);
+
+#endif /* __LINUX_IOBUF_H */
diff -u --recursive --new-file v2.3.11/linux/include/linux/limits.h linux/include/linux/limits.h
--- v2.3.11/linux/include/linux/limits.h	Tue Dec  2 13:44:40 1997
+++ linux/include/linux/limits.h	Wed Jul 28 10:30:10 1999
@@ -1,7 +1,7 @@
 #ifndef _LINUX_LIMITS_H
 #define _LINUX_LIMITS_H
 
-#define NR_OPEN		1024
+#define NR_OPEN	        1024
 
 #define NGROUPS_MAX       32	/* supplemental group IDs are available */
 #define ARG_MAX       131072	/* # bytes of args + environ for exec() */
diff -u --recursive --new-file v2.3.11/linux/include/linux/major.h linux/include/linux/major.h
--- v2.3.11/linux/include/linux/major.h	Thu Jul  8 15:42:21 1999
+++ linux/include/linux/major.h	Mon Jul 26 22:50:35 1999
@@ -115,6 +115,8 @@
 
 #define AURORA_MAJOR 79
 
+#define RAW_MAJOR	162
+
 #define UNIX98_PTY_MASTER_MAJOR	128
 #define UNIX98_PTY_MAJOR_COUNT	8
 #define UNIX98_PTY_SLAVE_MAJOR	(UNIX98_PTY_MASTER_MAJOR+UNIX98_PTY_MAJOR_COUNT)
diff -u --recursive --new-file v2.3.11/linux/include/linux/mm.h linux/include/linux/mm.h
--- v2.3.11/linux/include/linux/mm.h	Wed Jul 21 15:46:48 1999
+++ linux/include/linux/mm.h	Wed Jul 28 13:56:38 1999
@@ -304,7 +304,6 @@
 extern unsigned long put_dirty_page(struct task_struct * tsk,unsigned long page,
 	unsigned long address);
 
-extern void free_page_tables(struct mm_struct * mm);
 extern void clear_page_tables(struct mm_struct *, unsigned long, int);
 
 extern void zap_page_range(struct mm_struct *mm, unsigned long address, unsigned long size);
diff -u --recursive --new-file v2.3.11/linux/include/linux/parport.h linux/include/linux/parport.h
--- v2.3.11/linux/include/linux/parport.h	Wed Jul 21 15:46:48 1999
+++ linux/include/linux/parport.h	Wed Jul 28 13:57:23 1999
@@ -74,6 +74,7 @@
  * parport_negotiate to use address operations.  They have no effect
  * other than to make parport_read/write use address transfers. */
 #define IEEE1284_ADDR			(1<<13)	/* This is a flag */
+#define IEEE1284_DATA			 0	/* So is this */
 
 /* The rest is for the kernel only */
 #ifdef __KERNEL__
@@ -143,7 +144,7 @@
 	void (*data_reverse) (struct parport *);
 
 	/* For core parport code. */
-	void (*interrupt)(int, void *, struct pt_regs *); /* ? */
+	void (*interrupt)(int, void *, struct pt_regs *);
 
 	void (*init_state)(struct pardevice *, struct parport_state *);
 	void (*save_state)(struct parport *, struct parport_state *);
@@ -151,7 +152,6 @@
 
 	void (*inc_use_count)(void);
 	void (*dec_use_count)(void);
-	void (*fill_inode)(struct inode *inode, int fill); /* ? */
 
 	/* Block read/write */
 	size_t (*epp_write_data) (struct parport *port, const void *buf,
diff -u --recursive --new-file v2.3.11/linux/include/linux/pci.h linux/include/linux/pci.h
--- v2.3.11/linux/include/linux/pci.h	Thu Jul  8 15:42:21 1999
+++ linux/include/linux/pci.h	Wed Jul 28 13:56:27 1999
@@ -994,8 +994,34 @@
 #define PCI_VENDOR_ID_CBOARDS		0x1307
 #define PCI_DEVICE_ID_CBOARDS_DAS1602_16 0x0001
 
+#define PCI_VENDOR_ID_SIIG		0x131f
+#define PCI_DEVICE_ID_SIIG_1S1P_10x_550	0x1010
+#define PCI_DEVICE_ID_SIIG_1S1P_10x_650	0x1011
+#define PCI_DEVICE_ID_SIIG_1S1P_10x_850	0x1012
+#define PCI_DEVICE_ID_SIIG_1P_10x	0x1020
+#define PCI_DEVICE_ID_SIIG_2P_10x	0x1021
+#define PCI_DEVICE_ID_SIIG_2S1P_10x_550	0x1034
+#define PCI_DEVICE_ID_SIIG_2S1P_10x_650	0x1035
+#define PCI_DEVICE_ID_SIIG_2S1P_10x_850	0x1036
+#define PCI_DEVICE_ID_SIIG_1P_20x	0x2020
+#define PCI_DEVICE_ID_SIIG_2P_20x	0x2021
+#define PCI_DEVICE_ID_SIIG_2P1S_20x_550	0x2040
+#define PCI_DEVICE_ID_SIIG_2P1S_20x_650	0x2041
+#define PCI_DEVICE_ID_SIIG_2P1S_20x_850	0x2042
+#define PCI_DEVICE_ID_SIIG_1S1P_20x_550	0x2010
+#define PCI_DEVICE_ID_SIIG_1S1P_20x_650	0x2011
+#define PCI_DEVICE_ID_SIIG_1S1P_20x_850	0x2012
+#define PCI_DEVICE_ID_SIIG_2S1P_20x_550	0x2060
+#define PCI_DEVICE_ID_SIIG_2S1P_20x_650	0x2061
+#define PCI_DEVICE_ID_SIIG_2S1P_20x_850	0x2062
+
 #define PCI_VENDOR_ID_NETGEAR		0x1385
 #define PCI_DEVICE_ID_NETGEAR_GA620	0x620a
+
+#define PCI_VENDOR_ID_LAVA		0x1407
+#define PCI_DEVICE_ID_LAVA_PARALLEL	0x8000
+#define PCI_DEVICE_ID_LAVA_DUAL_PAR_A	0x8001 /* The Lava Dual Parallel is */
+#define PCI_DEVICE_ID_LAVA_DUAL_PAR_B	0x8002 /* two PCI devices on a card */
 
 #define PCI_VENDOR_ID_SYMPHONY		0x1c1c
 #define PCI_DEVICE_ID_SYMPHONY_101	0x0001
diff -u --recursive --new-file v2.3.11/linux/include/linux/raw.h linux/include/linux/raw.h
--- v2.3.11/linux/include/linux/raw.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/raw.h	Mon Jul 26 22:50:35 1999
@@ -0,0 +1,23 @@
+#ifndef __LINUX_RAW_H
+#define __LINUX_RAW_H
+
+#include <linux/types.h>
+
+#define RAW_SETBIND	_IO( 0xac, 0 )
+#define RAW_GETBIND	_IO( 0xac, 1 )
+
+struct raw_config_request 
+{
+	int	raw_minor;
+	__u64	block_major;
+	__u64	block_minor;
+};
+
+#ifdef __KERNEL__
+
+/* drivers/char/raw.c */
+extern void raw_init(void);
+
+#endif /* __KERNEL__ */
+
+#endif /* __LINUX_RAW_H */
diff -u --recursive --new-file v2.3.11/linux/include/linux/sched.h linux/include/linux/sched.h
--- v2.3.11/linux/include/linux/sched.h	Wed Jul 21 15:46:48 1999
+++ linux/include/linux/sched.h	Wed Jul 28 13:56:37 1999
@@ -35,6 +35,7 @@
 #define CLONE_PID	0x00001000	/* set if pid shared */
 #define CLONE_PTRACE	0x00002000	/* set if we want to let tracing continue on the child too */
 #define CLONE_VFORK	0x00004000	/* set if the parent wants the child to wake it up on mm_release */
+#define CLONE_PARENT	0x00008000	/* set if we want to have the same parent as the cloner */
 
 /*
  * These are the constant used to fake the fixed-point load-average
@@ -127,24 +128,40 @@
 asmlinkage void schedule(void);
 
 /*
+ * The default fd array needs to be at least BITS_PER_LONG,
+ * as this is the granularity returned by copy_fdset().
+ */
+#define NR_OPEN_DEFAULT BITS_PER_LONG
+
+/*
  * Open file table structure
  */
 struct files_struct {
 	atomic_t count;
 	rwlock_t file_lock;
 	int max_fds;
+	int max_fdset;
+	int next_fd;
 	struct file ** fd;	/* current fd array */
-	fd_set close_on_exec;
-	fd_set open_fds;
+	fd_set *close_on_exec;
+	fd_set *open_fds;
+	fd_set close_on_exec_init;
+	fd_set open_fds_init;
+	struct file * fd_array[NR_OPEN_DEFAULT];
 };
 
 #define INIT_FILES { \
 	ATOMIC_INIT(1), \
 	RW_LOCK_UNLOCKED, \
-	NR_OPEN, \
-	&init_fd_array[0], \
+	NR_OPEN_DEFAULT, \
+	__FD_SETSIZE, \
+	0, \
+	&init_files.fd_array[0], \
+	&init_files.close_on_exec_init, \
+	&init_files.open_fds_init, \
 	{ { 0, } }, \
-	{ { 0, } } \
+	{ { 0, } }, \
+	{ NULL, } \
 }
 
 struct fs_struct {
@@ -593,6 +610,9 @@
  */
 extern struct mm_struct * mm_alloc(void);
 
+extern struct mm_struct * start_lazy_tlb(void);
+extern void end_lazy_tlb(struct mm_struct *mm);
+
 /* mmdrop drops the mm and the page tables */
 extern inline void FASTCALL(__mmdrop(struct mm_struct *));
 static inline void mmdrop(struct mm_struct * mm)
@@ -605,6 +625,48 @@
 extern void mmput(struct mm_struct *);
 /* Remove the current tasks stale references to the old mm_struct */
 extern void mm_release(void);
+
+/*
+ * Routines for handling the fd arrays
+ */
+extern struct file ** alloc_fd_array(int);
+extern int expand_fd_array(struct files_struct *, int nr);
+extern void free_fd_array(struct file **, int);
+
+extern fd_set *alloc_fdset(int);
+extern int expand_fdset(struct files_struct *, int nr);
+extern void free_fdset(fd_set *, int);
+
+/* Expand files.  Return <0 on error; 0 nothing done; 1 files expanded,
+ * we may have blocked. 
+ *
+ * Should be called with the files->file_lock spinlock held for write.
+ */
+static inline int expand_files(struct files_struct *files, int nr)
+{
+	int err, expand = 0;
+#ifdef FDSET_DEBUG	
+	printk (KERN_ERR __FUNCTION__ " %d: nr = %d\n", current->pid, nr);
+#endif
+	
+	if (nr >= files->max_fdset) {
+		expand = 1;
+		if ((err = expand_fdset(files, nr)))
+			goto out;
+	}
+	if (nr >= files->max_fds) {
+		expand = 1;
+		if ((err = expand_fd_array(files, nr)))
+			goto out;
+	}
+	err = expand;
+ out:
+#ifdef FDSET_DEBUG	
+	if (err)
+		printk (KERN_ERR __FUNCTION__ " %d: return %d\n", current->pid, err);
+#endif
+	return err;
+}
 
 extern int  copy_thread(int, unsigned long, unsigned long, struct task_struct *, struct pt_regs *);
 extern void flush_thread(void);
diff -u --recursive --new-file v2.3.11/linux/init/main.c linux/init/main.c
--- v2.3.11/linux/init/main.c	Wed Jul 21 15:46:48 1999
+++ linux/init/main.c	Mon Jul 26 22:50:35 1999
@@ -23,6 +23,7 @@
 #include <linux/smp_lock.h>
 #include <linux/blk.h>
 #include <linux/hdreg.h>
+#include <linux/iobuf.h>
 
 #include <asm/io.h>
 #include <asm/bugs.h>
@@ -1193,6 +1194,7 @@
 	vma_init();
 	buffer_init(memory_end-memory_start);
 	page_cache_init(memory_end-memory_start);
+	kiobuf_init();
 	signals_init();
 	inode_init();
 	file_table_init();
diff -u --recursive --new-file v2.3.11/linux/kernel/exit.c linux/kernel/exit.c
--- v2.3.11/linux/kernel/exit.c	Wed Jul 21 15:46:48 1999
+++ linux/kernel/exit.c	Wed Jul 28 10:30:45 1999
@@ -26,13 +26,17 @@
 {
 	if (p != current) {
 #ifdef __SMP__
+		int has_cpu;
+
 		/*
 		 * Wait to make sure the process isn't on the
 		 * runqueue (active on some other CPU still)
 		 */
 		do {
-			barrier();
-		} while (p->has_cpu);
+			spin_lock_irq(&runqueue_lock);
+			has_cpu = p->has_cpu;
+			spin_unlock_irq(&runqueue_lock);
+		} while (has_cpu);
 #endif
 		free_uid(p);
 		unhash_process(p);
@@ -145,11 +149,11 @@
 
 	j = 0;
 	for (;;) {
-		unsigned long set = files->open_fds.fds_bits[j];
+		unsigned long set;
 		i = j * __NFDBITS;
-		j++;
-		if (i >= files->max_fds)
+		if (i >= files->max_fdset || i >= files->max_fds)
 			break;
+		set = files->open_fds->fds_bits[j++];
 		while (set) {
 			if (set & 1) {
 				struct file * file = xchg(&files->fd[i], NULL);
@@ -172,12 +176,14 @@
 		if (atomic_dec_and_test(&files->count)) {
 			close_files(files);
 			/*
-			 * Free the fd array as appropriate ...
+			 * Free the fd and fdset arrays if we expanded them.
 			 */
-			if (NR_OPEN * sizeof(struct file *) == PAGE_SIZE)
-				free_page((unsigned long) files->fd);
-			else
-				kfree(files->fd);
+			if (files->fd != &files->fd_array[0])
+				free_fd_array(files->fd, files->max_fds);
+			if (files->max_fdset > __FD_SETSIZE) {
+				free_fdset(files->open_fds, files->max_fdset);
+				free_fdset(files->close_on_exec, files->max_fdset);
+			}
 			kmem_cache_free(files_cachep, files);
 		}
 	}
@@ -230,6 +236,31 @@
 }
 
 /*
+ * We can use these to temporarily drop into
+ * "lazy TLB" mode and back.
+ */
+struct mm_struct * start_lazy_tlb(void)
+{
+	struct mm_struct *mm = current->mm;
+	current->mm = NULL;
+	/* active_mm is still 'mm' */
+	atomic_inc(&mm->mm_count);
+	return mm;
+}
+
+void end_lazy_tlb(struct mm_struct *mm)
+{
+	struct mm_struct *active_mm = current->active_mm;
+
+	current->mm = mm;
+	if (mm != active_mm) {
+		current->active_mm = mm;
+		switch_mm(active_mm, mm, current->processor);
+	}
+	mmdrop(active_mm);
+}
+
+/*
  * Turn us into a lazy TLB process if we
  * aren't already..
  */
@@ -238,8 +269,9 @@
 	struct mm_struct * mm = tsk->mm;
 
 	if (mm) {
-		mm_release();
 		atomic_inc(&mm->mm_count);
+		mm_release();
+		if (mm != tsk->active_mm) BUG();
 		tsk->mm = NULL;
 		mmput(mm);
 	}
diff -u --recursive --new-file v2.3.11/linux/kernel/fork.c linux/kernel/fork.c
--- v2.3.11/linux/kernel/fork.c	Wed Jul 21 15:46:48 1999
+++ linux/kernel/fork.c	Wed Jul 28 13:23:22 1999
@@ -300,13 +300,39 @@
 	mm = kmem_cache_alloc(mm_cachep, SLAB_KERNEL);
 	if (mm) {
 		memset(mm, 0, sizeof(*mm));
-		init_new_context(mm);
 		atomic_set(&mm->mm_users, 1);
 		atomic_set(&mm->mm_count, 1);
 		init_MUTEX(&mm->mmap_sem);
 		mm->page_table_lock = SPIN_LOCK_UNLOCKED;
+		mm->pgd = pgd_alloc();
+		if (mm->pgd)
+			return mm;
+		kmem_cache_free(mm_cachep, mm);
+	}
+	return NULL;
+}
+
+/*
+ * Called when the last reference to the mm
+ * is dropped: either by a lazy thread or by
+ * mmput. Free the page directory and the mm.
+ */
+inline void __mmdrop(struct mm_struct *mm)
+{
+	if (mm == &init_mm) BUG();
+	pgd_free(mm->pgd);
+	kmem_cache_free(mm_cachep, mm);
+}
+
+/*
+ * Decrement the use count and release all resources for an mm.
+ */
+void mmput(struct mm_struct *mm)
+{
+	if (atomic_dec_and_test(&mm->mm_users)) {
+		exit_mmap(mm);
+		mmdrop(mm);
 	}
-	return mm;
 }
 
 /* Please note the differences between mmput and mm_release.
@@ -333,30 +359,6 @@
 	}
 }
 
-/*
- * Called when the last reference to the mm
- * is dropped: either by a lazy thread or by
- * mmput
- */
-inline void __mmdrop(struct mm_struct *mm)
-{
-	if (mm == &init_mm) BUG();
-	free_page_tables(mm);
-	kmem_cache_free(mm_cachep, mm);
-}
-
-/*
- * Decrement the use count and release all resources for an mm.
- */
-void mmput(struct mm_struct *mm)
-{
-	if (atomic_dec_and_test(&mm->mm_users)) {
-		release_segments(mm);
-		exit_mmap(mm);
-		mmdrop(mm);
-	}
-}
-
 static inline int copy_mm(unsigned long clone_flags, struct task_struct * tsk)
 {
 	struct mm_struct * mm;
@@ -391,10 +393,6 @@
 	tsk->mm = mm;
 	tsk->active_mm = mm;
 
-	mm->pgd = pgd_alloc();
-	if (!mm->pgd)
-		goto free_mm;
-
 	/*
 	 * child gets a private LDT (if there was an LDT in the parent)
 	 */
@@ -409,12 +407,9 @@
 good_mm:
 	tsk->mm = mm;
 	tsk->active_mm = mm;
-	SET_PAGE_DIR(tsk, mm->pgd);
+	init_new_context(tsk,mm);
 	return 0;
 
-free_mm:
-	kmem_cache_free(mm_cachep, mm);
-	return retval;
 free_pt:
 	mmput(mm);
 fail_nomem:
@@ -437,32 +432,24 @@
 	return 0;
 }
 
-/*
- * Copy a fd_set and compute the maximum fd it contains. 
- */
-static inline int __copy_fdset(unsigned long *d, unsigned long *src)
+static int count_open_files(struct files_struct *files, int size)
 {
-	int i; 
-	unsigned long *p = src; 
-	unsigned long *max = src; 
-
-	for (i = __FDSET_LONGS; i; --i) {
-		if ((*d++ = *p++) != 0) 
-			max = p; 
+	int i;
+	
+	/* Find the last open fd */
+	for (i = size/(8*sizeof(long)); i > 0; ) {
+		if (files->open_fds->fds_bits[--i])
+			break;
 	}
-	return (max - src)*sizeof(long)*8; 
-}
-
-static inline int copy_fdset(fd_set *dst, fd_set *src)
-{
-	return __copy_fdset(dst->fds_bits, src->fds_bits);  
+	i = (i+1) * 8 * sizeof(long);
+	return i;
 }
 
 static int copy_files(unsigned long clone_flags, struct task_struct * tsk)
 {
 	struct files_struct *oldf, *newf;
 	struct file **old_fds, **new_fds;
-	int size, i, error = 0;
+	int open_files, nfds, size, i, error = 0;
 
 	/*
 	 * A background process may not have any files ...
@@ -482,43 +469,85 @@
 	if (!newf) 
 		goto out;
 
-	/*
-	 * Allocate the fd array, using get_free_page() if possible.
-	 * Eventually we want to make the array size variable ...
-	 */
-	size = NR_OPEN * sizeof(struct file *);
-	if (size == PAGE_SIZE)
-		new_fds = (struct file **) __get_free_page(GFP_KERNEL);
-	else
-		new_fds = (struct file **) kmalloc(size, GFP_KERNEL);
-	if (!new_fds)
-		goto out_release;
-
-	newf->file_lock = RW_LOCK_UNLOCKED;
 	atomic_set(&newf->count, 1);
-	newf->max_fds = NR_OPEN;
-	newf->fd = new_fds;
+
+	newf->file_lock	    = RW_LOCK_UNLOCKED;
+	newf->next_fd	    = 0;
+	newf->max_fds	    = NR_OPEN_DEFAULT;
+	newf->max_fdset	    = __FD_SETSIZE;
+	newf->close_on_exec = &newf->close_on_exec_init;
+	newf->open_fds	    = &newf->open_fds_init;
+	newf->fd	    = &newf->fd_array[0];
+
+	/* We don't yet have the oldf readlock, but even if the old
+           fdset gets grown now, we'll only copy up to "size" fds */
+	size = oldf->max_fdset;
+	if (size > __FD_SETSIZE) {
+		newf->max_fdset = 0;
+		write_lock(&newf->file_lock);
+		error = expand_fdset(newf, size);
+		write_unlock(&newf->file_lock);
+		if (error)
+			goto out_release;
+	}
 	read_lock(&oldf->file_lock);
-	newf->close_on_exec = oldf->close_on_exec;
-	i = copy_fdset(&newf->open_fds, &oldf->open_fds);
+
+	open_files = count_open_files(oldf, size);
+
+	/*
+	 * Check whether we need to allocate a larger fd array.
+	 * Note: we're not a clone task, so the open count won't
+	 * change.
+	 */
+	nfds = NR_OPEN_DEFAULT;
+	if (open_files > nfds) {
+		read_unlock(&oldf->file_lock);
+		newf->max_fds = 0;
+		write_lock(&newf->file_lock);
+		error = expand_fd_array(newf, open_files);
+		write_unlock(&newf->file_lock);
+		if (error) 
+			goto out_release;
+		nfds = newf->max_fds;
+		read_lock(&oldf->file_lock);
+	}
 
 	old_fds = oldf->fd;
-	for (; i != 0; i--) {
+	new_fds = newf->fd;
+
+	memcpy(newf->open_fds->fds_bits, oldf->open_fds->fds_bits, open_files/8);
+	memcpy(newf->close_on_exec->fds_bits, oldf->close_on_exec->fds_bits, open_files/8);
+
+	for (i = open_files; i != 0; i--) {
 		struct file *f = *old_fds++;
 		if (f)
 			get_file(f);
 		*new_fds++ = f;
 	}
 	read_unlock(&oldf->file_lock);
+
+	/* compute the remainder to be cleared */
+	size = (newf->max_fds - open_files) * sizeof(struct file *);
+
 	/* This is long word aligned thus could use a optimized version */ 
-	memset(new_fds, 0, (char *)newf->fd + size - (char *)new_fds); 
-      
+	memset(new_fds, 0, size); 
+
+	if (newf->max_fdset > open_files) {
+		int left = (newf->max_fdset-open_files)/8;
+		int start = open_files / (8 * sizeof(unsigned long));
+		
+		memset(&newf->open_fds->fds_bits[start], 0, left);
+		memset(&newf->close_on_exec->fds_bits[start], 0, left);
+	}
+
 	tsk->files = newf;
 	error = 0;
 out:
 	return error;
 
 out_release:
+	free_fdset (newf->close_on_exec, newf->max_fdset);
+	free_fdset (newf->open_fds, newf->max_fdset);
 	kmem_cache_free(files_cachep, newf);
 	goto out;
 }
@@ -608,7 +637,8 @@
 	p->run_list.next = NULL;
 	p->run_list.prev = NULL;
 
-	p->p_pptr = p->p_opptr = current;
+	if ((clone_flags & CLONE_VFORK) || !(clone_flags & CLONE_PARENT))
+		p->p_pptr = p->p_opptr = current;
 	p->p_cptr = NULL;
 	init_waitqueue_head(&p->wait_chldexit);
 	p->vfork_sem = NULL;
diff -u --recursive --new-file v2.3.11/linux/kernel/sched.c linux/kernel/sched.c
--- v2.3.11/linux/kernel/sched.c	Wed Jul 21 15:46:48 1999
+++ linux/kernel/sched.c	Wed Jul 28 10:45:39 1999
@@ -621,15 +621,6 @@
  */
 static inline void __schedule_tail(struct task_struct *prev)
 {
-	if (!current->active_mm) BUG();
-
-	if (!prev->mm) {
-		struct mm_struct *mm = prev->active_mm;
-		if (mm) {
-			prev->active_mm = NULL;
-			mmdrop(mm);
-		}
-	}
 #ifdef __SMP__
 	if ((prev->state == TASK_RUNNING) &&
 			(prev != idle_task(smp_processor_id())))
@@ -790,16 +781,26 @@
 	 */
 	{
 		struct mm_struct *mm = next->mm;
+		struct mm_struct *oldmm = prev->active_mm;
 		if (!mm) {
-			mm = prev->active_mm;
-			set_mmu_context(prev,next);
 			if (next->active_mm) BUG();
-			next->active_mm = mm;
-			atomic_inc(&mm->mm_count);
+			next->active_mm = oldmm;
+			atomic_inc(&oldmm->mm_count);
+		} else {
+			if (next->active_mm != mm) BUG();
+			switch_mm(oldmm, mm, this_cpu);
+		}
+
+		if (!prev->mm) {
+			prev->active_mm = NULL;
+			mmdrop(oldmm);
 		}
 	}
 
-	get_mmu_context(next);
+	/*
+	 * This just switches the register state and the
+	 * stack.
+	 */
 	switch_to(prev, next, prev);
 	__schedule_tail(prev);
 
diff -u --recursive --new-file v2.3.11/linux/lib/vsprintf.c linux/lib/vsprintf.c
--- v2.3.11/linux/lib/vsprintf.c	Mon Mar 15 11:19:05 1999
+++ linux/lib/vsprintf.c	Sat Jul 24 16:42:01 1999
@@ -156,7 +156,9 @@
 	int precision;		/* min. # of digits for integers; max
 				   number of chars for from string */
 	int qualifier;		/* 'h', 'l', or 'L' for integer fields */
+	                        /* 'z' support added 23/7/1999 S.H.    */
 
+	
 	for (str=buf ; *fmt ; ++fmt) {
 		if (*fmt != '%') {
 			*str++ = *fmt;
@@ -206,7 +208,7 @@
 
 		/* get the conversion qualifier */
 		qualifier = -1;
-		if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
+		if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt =='z') {
 			qualifier = *fmt;
 			++fmt;
 		}
@@ -255,6 +257,9 @@
 			if (qualifier == 'l') {
 				long * ip = va_arg(args, long *);
 				*ip = (str - buf);
+			} else if (qualifier == 'z') {
+				size_t * ip = va_arg(args, size_t *);
+				*ip = (str - buf);
 			} else {
 				int * ip = va_arg(args, int *);
 				*ip = (str - buf);
@@ -292,6 +297,8 @@
 		}
 		if (qualifier == 'l')
 			num = va_arg(args, unsigned long);
+		else if (qualifier == 'z')
+			num = va_arg(args, size_t);
 		else if (qualifier == 'h') {
 			num = (unsigned short) va_arg(args, int);
 			if (flags & SIGN)
diff -u --recursive --new-file v2.3.11/linux/mm/memory.c linux/mm/memory.c
--- v2.3.11/linux/mm/memory.c	Wed Jul 21 15:46:48 1999
+++ linux/mm/memory.c	Wed Jul 28 11:32:23 1999
@@ -39,6 +39,7 @@
 #include <linux/pagemap.h>
 #include <linux/smp_lock.h>
 #include <linux/swapctl.h>
+#include <linux/iobuf.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -142,28 +143,6 @@
 	check_pgt_cache();
 }
 
-/*
- * This function just free's the page directory - the
- * pages tables themselves have been freed earlier by 
- * clear_page_tables().
- */
-void free_page_tables(struct mm_struct * mm)
-{
-	pgd_t * page_dir = mm->pgd;
-
-	if (page_dir) {
-		if (page_dir == swapper_pg_dir)
-			goto out_bad;
-		pgd_free(page_dir);
-	}
-	return;
-
-out_bad:
-	printk(KERN_ERR
-		"free_page_tables: Trying to free kernel pgd\n");
-	return;
-}
-
 #define PTE_TABLE_MASK	((PTRS_PER_PTE-1) * sizeof(pte_t))
 #define PMD_TABLE_MASK	((PTRS_PER_PMD-1) * sizeof(pmd_t))
 
@@ -406,6 +385,190 @@
 	}
 }
 
+
+/*
+ * Do a quick page-table lookup for a single page. 
+ */
+static unsigned long follow_page(unsigned long address) 
+{
+	pgd_t *pgd;
+	pmd_t *pmd;
+
+	pgd = pgd_offset(current->mm, address);
+	pmd = pmd_offset(pgd, address);
+	if (pmd) {
+		pte_t * pte = pte_offset(pmd, address);
+		if (pte && pte_present(*pte)) {
+			return pte_page(*pte);
+		}
+	}
+	
+	printk(KERN_ERR "Missing page in follow_page\n");
+	return 0;
+}
+
+/* 
+ * Given a physical address, is there a useful struct page pointing to it?
+ */
+
+static struct page * get_page_map(unsigned long page)
+{
+	struct page *map;
+	
+	if (MAP_NR(page) >= max_mapnr)
+		return 0;
+	if (page == ZERO_PAGE(page))
+		return 0;
+	map = mem_map + MAP_NR(page);
+	if (PageReserved(map))
+		return 0;
+	return map;
+}
+
+/*
+ * Force in an entire range of pages from the current process's user VA,
+ * and pin and lock the pages for IO.  
+ */
+
+#define dprintk(x...)
+int map_user_kiobuf(int rw, struct kiobuf *iobuf, unsigned long va, size_t len)
+{
+	unsigned long		ptr, end;
+	int			err;
+	struct mm_struct *	mm;
+	struct vm_area_struct *	vma = 0;
+	unsigned long		page;
+	struct page *		map;
+	int			doublepage = 0;
+	int			repeat = 0;
+	int			i;
+	
+	/* Make sure the iobuf is not already mapped somewhere. */
+	if (iobuf->nr_pages)
+		return -EINVAL;
+
+	mm = current->mm;
+	dprintk ("map_user_kiobuf: begin\n");
+	
+	ptr = va & PAGE_MASK;
+	end = (va + len + PAGE_SIZE - 1) & PAGE_MASK;
+	err = expand_kiobuf(iobuf, (end - ptr) >> PAGE_SHIFT);
+	if (err)
+		return err;
+
+ repeat:
+	down(&mm->mmap_sem);
+
+	err = -EFAULT;
+	iobuf->locked = 1;
+	iobuf->offset = va & ~PAGE_MASK;
+	iobuf->length = len;
+	
+	i = 0;
+	
+	/* 
+	 * First of all, try to fault in all of the necessary pages
+	 */
+	while (ptr < end) {
+		if (!vma || ptr >= vma->vm_end) {
+			vma = find_vma(current->mm, ptr);
+			if (!vma) 
+				goto out_unlock;
+		}
+		if (handle_mm_fault(current, vma, ptr, (rw==READ)) <= 0) 
+			goto out_unlock;
+		spin_lock(&mm->page_table_lock);
+		page = follow_page(ptr);
+		if (!page) {
+			dprintk (KERN_ERR "Missing page in map_user_kiobuf\n");
+			map = NULL;
+			goto retry;
+		}
+		map = get_page_map(page);
+		if (map) {
+			if (TryLockPage(map)) {
+				goto retry;
+			}
+			atomic_inc(&map->count);
+		}
+		spin_unlock(&mm->page_table_lock);
+		dprintk ("Installing page %p %p: %d\n", (void *)page, map, i);
+		iobuf->pagelist[i] = page;
+		iobuf->maplist[i] = map;
+		iobuf->nr_pages = ++i;
+		
+		ptr += PAGE_SIZE;
+	}
+
+	up(&mm->mmap_sem);
+	dprintk ("map_user_kiobuf: end OK\n");
+	return 0;
+
+ out_unlock:
+	up(&mm->mmap_sem);
+	unmap_kiobuf(iobuf);
+	dprintk ("map_user_kiobuf: end %d\n", err);
+	return err;
+
+ retry:
+
+	/* 
+	 * Undo the locking so far, wait on the page we got to, and try again.
+	 */
+	spin_unlock(&mm->page_table_lock);
+	unmap_kiobuf(iobuf);
+	up(&mm->mmap_sem);
+
+	/* 
+	 * Did the release also unlock the page we got stuck on?
+	 */
+	if (map) {
+		if (!PageLocked(map)) {
+			/* If so, we may well have the page mapped twice
+			 * in the IO address range.  Bad news.  Of
+			 * course, it _might_ * just be a coincidence,
+			 * but if it happens more than * once, chances
+			 * are we have a double-mapped page. */
+			if (++doublepage >= 3) {
+				return -EINVAL;
+			}
+		}
+	
+		/*
+		 * Try again...
+		 */
+		wait_on_page(map);
+	}
+	
+	if (++repeat < 16)
+		goto repeat;
+	return -EAGAIN;
+}
+
+
+/*
+ * Unmap all of the pages referenced by a kiobuf.  We release the pages,
+ * and unlock them if they were locked. 
+ */
+
+void unmap_kiobuf (struct kiobuf *iobuf) 
+{
+	int i;
+	struct page *map;
+	
+	for (i = 0; i < iobuf->nr_pages; i++) {
+		map = iobuf->maplist[i];
+		
+		if (map && iobuf->locked) {
+			__free_page(map);
+			UnlockPage(map);
+		}
+	}
+	
+	iobuf->nr_pages = 0;
+	iobuf->locked = 0;
+}
+
 static inline void zeromap_pte_range(pte_t * pte, unsigned long address,
                                      unsigned long size, pgprot_t prot)
 {
@@ -670,6 +833,7 @@
 	return 1;
 
 bad_wp_page:
+	spin_unlock(&tsk->mm->page_table_lock);
 	printk("do_wp_page: bogus page at address %08lx (%08lx)\n",address,old_page);
 	return -1;
 }
diff -u --recursive --new-file v2.3.11/linux/mm/mmap.c linux/mm/mmap.c
--- v2.3.11/linux/mm/mmap.c	Thu Jul  8 15:42:21 1999
+++ linux/mm/mmap.c	Tue Jul 27 12:33:27 1999
@@ -813,6 +813,7 @@
 {
 	struct vm_area_struct * mpnt;
 
+	release_segments(mm);
 	mpnt = mm->mmap;
 	mm->mmap = mm->mmap_avl = mm->mmap_cache = NULL;
 	mm->rss = 0;
diff -u --recursive --new-file v2.3.11/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c
--- v2.3.11/linux/net/ipv4/tcp_ipv4.c	Thu Jul  8 15:42:21 1999
+++ linux/net/ipv4/tcp_ipv4.c	Thu Jul 22 13:18:12 1999
@@ -401,10 +401,9 @@
  * The sockhash lock must be held as a reader here.
  */
 static inline struct sock *__tcp_v4_lookup(u32 saddr, u16 sport,
-					   u32 daddr, u16 dport, int dif)
+					   u32 daddr, u16 hnum, int dif)
 {
 	TCP_V4_ADDR_COOKIE(acookie, saddr, daddr)
-	__u16 hnum = ntohs(dport);
 	__u32 ports = TCP_COMBINED_PORTS(sport, hnum);
 	struct sock *sk;
 	int hash;
@@ -439,7 +438,7 @@
 	struct sock *sk;
 
 	SOCKHASH_LOCK_READ();
-	sk = __tcp_v4_lookup(saddr, sport, daddr, dport, dif);
+	sk = __tcp_v4_lookup(saddr, sport, daddr, ntohs(dport), dif);
 	SOCKHASH_UNLOCK_READ();
 
 	return sk;
@@ -1729,7 +1728,7 @@
 #endif
 		SOCKHASH_LOCK_READ_BH();
 		sk = __tcp_v4_lookup(skb->nh.iph->saddr, th->source,
-				     skb->nh.iph->daddr, th->dest, skb->dev->ifindex);
+				     skb->nh.iph->daddr, ntohs(th->dest), skb->dev->ifindex);
 		SOCKHASH_UNLOCK_READ_BH();
 #ifdef CONFIG_IP_TRANSPARENT_PROXY
 		if (!sk)
diff -u --recursive --new-file v2.3.11/linux/scripts/ver_linux linux/scripts/ver_linux
--- v2.3.11/linux/scripts/ver_linux	Thu Jul  8 15:42:21 1999
+++ linux/scripts/ver_linux	Thu Jul 22 07:18:50 1999
@@ -5,7 +5,7 @@
 # differ on your system.
 #
 PATH=/sbin:/usr/sbin:/bin:/usr/bin:$PATH
-echo '-- Versions installed: (if some fields are empty or looks'
+echo '-- Versions installed: (if some fields are empty or look'
 echo '-- unusual then possibly you have very old versions)'
 uname -a
 insmod -V  2>&1 | awk 'NR==1 {print "Kernel modules        ",$NF}'
