diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/CREDITS linux.14p1/CREDITS
--- linux.vanilla/CREDITS	Wed Oct 20 01:12:32 1999
+++ linux.14p1/CREDITS	Fri Oct 22 22:42:34 1999
@@ -789,12 +789,12 @@
 D: Selection mechanism
 
 N: Jochen Hein
-E: jochen.hein@delphi.central.de
+E: jochen@jochen.org
 P: 1024/4A27F015 25 72 FB E3 85 9F DE 3B  CB 0A DA DA 40 77 05 6C
 D: National Language Support
 D: Linux Internationalization Project
 D: German Localization for Linux and GNU software
-S: Frankenstraße
+S: Frankenstraße 33
 S: 34131 Kassel
 S: Germany
 
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/Documentation/Changes linux.14p1/Documentation/Changes
--- linux.vanilla/Documentation/Changes	Sat Aug 14 02:27:12 1999
+++ linux.14p1/Documentation/Changes	Fri Oct 22 22:44:33 1999
@@ -43,7 +43,7 @@
 
    for all your Linux kernel needs.
 
-Last updated: July 13, 1999
+Last updated: October 13, 1999
 Current Author: Chris Ricker (kaboom@gatech.edu or
 	chris.ricker@genetics.utah.edu).
 
@@ -61,19 +61,19 @@
 - Linux libc6 C Library  2.0.7pre6               ; ls -l /lib/libc*
 - Dynamic Linker (ld.so) 1.9.9                   ; ldd --version or ldd -v
 - Linux C++ Library	 2.7.2.8                 ; ls -l /usr/lib/libg++.so.*
-- Procps		 1.2.9                   ; ps --version
+- Procps		 2.0.3                   ; ps --version
 - Procinfo               16                      ; procinfo -v
 - Psmisc		 17			 ; pstree -V
 - Net-tools              1.52                    ; hostname -V
 - Loadlin                1.6a
 - Sh-utils               1.16                    ; basename --v
-- Autofs                 3.1.1                   ; automount --version
+- Autofs                 3.1.3                   ; automount --version
 - NFS                    2.2beta40               ; showmount --version
 - Bash                   1.14.7                  ; bash -version
 - Ncpfs                  2.2.0                   ; ncpmount -v
-- Pcmcia-cs              3.0.13                  ; cardmgr -V
-- PPP                    2.3.8                   ; pppd --version
-- Util-linux             2.9t                    ; chsh -v
+- Pcmcia-cs              3.0.14                  ; cardmgr -V
+- PPP                    2.3.10                  ; pppd --version
+- Util-linux             2.9z                    ; chsh -v
 
 Upgrade notes
 *************
@@ -226,7 +226,7 @@
    Note that the latest compilers (egcs, pgcc, gcc 2.8) may do Bad
 Things while compiling your kernel, particularly if absurd
 optimizations (like -O9) are used.  Caveat emptor.  Currently, the only
-C compiler available in a binary distribution is egcs.  Version 1.0.3
+C compiler available in a binary distribution is egcs.  Version 1.1.2
 seems okay; if you have to have a binary, you may be successful using
 that.  In general, however, gcc-2.7.2.3 is known to be stable, while
 egcs and others have not been as thoroughly tested yet.
@@ -284,8 +284,8 @@
 ======
 
    As of 2.1.41, the format of /proc/meminfo has changed.  This broke
-many memory utils, which have to be upgraded.  Get the new procps-1.2
-and you should be set.
+many memory utils, which have to be upgraded.  Get the new procps and
+you should be set.
 
 Network File System
 ===================
@@ -519,23 +519,15 @@
 Binutils
 ========
 
-The 2.8.1.0.23 release:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.8.1.0.23.bin.tar.gz
-ftp://metalab.unc.edu/pub/Linux/GCC/binutils-2.8.1.0.23.bin.tar.gz
+The 2.9.1.0.25 release:
+ftp://ftp.varesearch.com/pub/support/hjl/binutils/2.9.1/binutils-2.9.1.0.25.tar.gz
 Installation notes:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.binutils-2.8.1.0.23
-ftp://metalab.unc.edu/pub/Linux/GCC/release.binutils-2.8.1.0.23
+ftp://ftp.varesearch.com/pub/support/hjl/binutils/2.9.1/release.binutils-2.9.1.0.25
 
-The 2.9.1.0.15 release:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.9.1.0.15-glibc.x86.tar.gz
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.9.1.0.15-libc5.x86.tar.gz
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.9.1.0.15.tar.gz
-ftp://metalab.unc.edu/pub/Linux/GCC/binutils-2.9.1.0.15-glibc.x86.tar.gz
-ftp://metalab.unc.edu/pub/Linux/GCC/binutils-2.9.1.0.15-libc5.x86.tar.gz
-ftp://metalab.unc.edu/pub/Linux/GCC/binutils-2.9.1.0.15.tar.gz
+The 2.9.5.0.16 release:
+ftp://ftp.varesearch.com/pub/support/hjl/binutils/binutils-2.9.5.0.16.tar.bz2
 Installation notes:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.binutils-2.9.1.0.15
-ftp://metalab.unc.edu/pub/Linux/GCC/release.binutils-2.9.1.0.15
+ftp://ftp.varesearch.com/pub/support/hjl/binutils/release.binutils-2.9.5.0.16
 
 Bin86
 =====
@@ -547,14 +539,12 @@
 Gnu C
 =====
 
-The egcs-1.0.3 release:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/egcs-1.0.3-glibc.x86.tar.bz2
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/egcs-1.0.3-libc5.x86.tar.bz2
-ftp://metalab.unc.edu/pub/Linux/GCC/egcs-1.0.3-glibc.x86.tar.bz2
-ftp://metalab.unc.edu/pub/Linux/GCC/egcs-1.0.3-libc5.x86.tar.bz2
+The egcs-1.1.2 release:
+ftp://ftp.varesearch.com/pub/support/hjl/gcc/egcs-1.1.2/egcs-1.1.2-glibc.x86.tar.bz2
+ftp://ftp.varesearch.com/pub/support/hjl/gcc/egcs-1.1.2/egcs-1.1.2-libc5.x86.tar.bz2
+ftp://ftp.varesearch.com/pub/support/hjl/gcc/egcs-1.1.2/egcs-1.1.2-alpha.x86.tar.bz2
 Installation notes:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.egcs-1.0.3
-ftp://metalab.unc.edu/pub/Linux/GCC/release.egcs-1.0.3
+ftp://ftp.varesearch.com/pub/support/hjl/gcc/egcs-1.1.2/release.egcs-1.1.2
 
 Gnu C 2.7.2.3 source:
 ftp://ftp.gnu.org/gnu/gcc/gcc-2.7.2.3.tar.gz
@@ -596,15 +586,14 @@
 Procps utilities
 ================
 
-The 1.2 release:
-ftp://tsx-11.mit.edu/pub/linux/sources/usr.bin/procps-1.2.9.tar.gz
-ftp://metalab.unc.edu/pub/Linux/system/status/ps/procps-1.2.9.tgz
+The 2.0.3 release:
+ftp://tsx-11.mit.edu/pub/linux/sources/usr.bin/procps-2.0.3.tar.gz
 
 Procinfo utilities
 ==================
 
-The 16 release:
-ftp://ftp.cistron.nl/pub/people/svm/procinfo-16.tar.gz
+The 17 release:
+ftp://ftp.cistron.nl/pub/people/svm/procinfo-17.tar.gz
 
 Psmisc utilities
 ================
@@ -624,7 +613,6 @@
 ======
 
 The 0.98.6 release:
-ftp://tsx-11.mit.edu/pub/linux/ALPHA/dosemu/dosemu-0.98.6.tgz
 ftp://ftp.dosemu.org/dosemu/dosemu-0.98.6.tgz
 
 Loadlin
@@ -645,7 +633,7 @@
 ==========
 
 The 2.9 release:
-ftp://ftp.win.tue.nl/pub/linux/utils/util-linux/util-linux-2.9t.tar.gz
+ftp://ftp.win.tue.nl/pub/linux/utils/util-linux/util-linux-2.9z.tar.gz
 
 Autofs
 ======
@@ -660,9 +648,9 @@
 ftp://ftp.mathematik.th-darmstadt.de/pub/linux/okir/dontuse/nfs-server-2.2beta40.tar.gz
 ftp://linux.nrao.edu/mirrors/fb0429.mathematik.th-darmstadt.de/pub/linux/okir/dontuse/nfs-server-2.2beta40.tar.gz
 
-The kernel-level 1.4.4 release:
-ftp://ftp.varesearch.com/pub/support/hjl/knfsd/knfsd-1.4.4.tar.gz
-ftp://ftp.kernel.org/pub/linux/devel/gcc/knfsd-1.4.4.tar.gz
+The kernel-level 1.4.7 release:
+ftp://ftp.varesearch.com/pub/support/hjl/knfsd/knfsd-1.4.7.tar.gz
+ftp://ftp.kernel.org/pub/linux/devel/gcc/knfsd-1.4.7.tar.gz
 
 Net-tools
 =========
@@ -707,8 +695,8 @@
 Pcmcia-cs
 =========
 
-The 3.0.13 release:
-ftp://hyper.stanford.edu/pub/pcmcia/pcmcia-cs.3.0.13.tar.gz
+The 3.0.14 release:
+ftp://sourceforge.org/pcmcia/pcmcia-cs.3.0.14.tar.gz
 
 Setserial
 =========
@@ -720,15 +708,15 @@
 PPP
 ===
 
-The 2.3.8 release:
-ftp://cs.anu.edu.au/pub/software/ppp/ppp-2.3.8.tar.gz
+The 2.3.10 release:
+ftp://cs.anu.edu.au/pub/software/ppp/ppp-2.3.10.tar.gz
 
 IP Chains
 =========
 
-The 1.3.8 release:
-ftp://ftp.rustcorp.com/ipchains/ipchains-1.3.8.tar.gz
-ftp://ftp.rustcorp.com/ipchains/ipchains-1.3.8.tar.bz2
+The 1.3.9 release:
+ftp://ftp.rustcorp.com/ipchains/ipchains-1.3.9.tar.gz
+ftp://ftp.rustcorp.com/ipchains/ipchains-1.3.9.tar.bz2
 
 IP Masq Adm
 ===========
@@ -739,11 +727,11 @@
 DHCP clients
 ============
 
-The 2.0b1pl27 ISC dhcpclient release:
-ftp://ftp.isc.org/isc/dhcp/test/dhcp-2.0b1pl27.tar.gz
+The 2.0 ISC dhcpclient release:
+ftp://ftp.isc.org/isc/dhcp/test/dhcp-2.0.tar.gz
 
-The 1.3.17-pl2 PhysTech dhcpcd release:
-ftp://ftp.phystech.com/pub/dhcpcd-1.3.17-pl2.tar.gz
+The 1.3.18-pl1 PhysTech dhcpcd release:
+ftp://ftp.phystech.com/pub/dhcpcd-1.3.18-pl1.tar.gz
 
 iBCS
 ====
@@ -754,8 +742,8 @@
 Asun netatalk
 =============
 
-The 2.0a18.2 release:
-ftp://ftp.u.washington.edu/pub/user-supported/asun/netatalk-1.4b2+asun2.0a18.2.tar.gz
+The 2.1.3 release:
+ftp://ftp.u.washington.edu/pub/user-supported/asun/netatalk-1.4b2+asun2.1.3.tar.gz
 
 Fbset
 =====
@@ -792,9 +780,9 @@
 IP utils
 ========
 
-The June 1999 release:
-ftp://ftp.inr.ac.ru/ip-routing/iproute2-2.2.4-now-ss990630.tar.gz
-ftp://ftp.inr.ac.ru/ip-routing/iputils-ss990610.tar.gz
+The latest releases:
+ftp://ftp.inr.ac.ru/ip-routing/iproute2-2.2.4-now-ss990824.tar.gz
+ftp://ftp.inr.ac.ru/ip-routing/iputils-ss990915.tar.gz
 
 Patch
 =====
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/Documentation/Configure.help linux.14p1/Documentation/Configure.help
--- linux.vanilla/Documentation/Configure.help	Wed Oct 20 01:12:32 1999
+++ linux.14p1/Documentation/Configure.help	Fri Oct 22 22:52:53 1999
@@ -9422,20 +9422,6 @@
   You can say M here to compile this driver as a module; the module is
   called sb.o.
 
-Generic OPL2/OPL3 FM synthesizer support
-CONFIG_SOUND_ADLIB
-  Answer Y if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4).
-  Answering Y is usually a safe and recommended choice, however some
-  cards may have software (TSR) FM emulation. Enabling FM support with
-  these cards may cause trouble (I don't currently know of any such
-  cards, however). 
-
-  Please read the file Documentation/sound/OPL3 if your card has an
-  OPL3 chip.
-
-  If unsure, say Y.
-  
-
 #Loopback MIDI device support
 #CONFIG_SOUND_VMIDI
 ###
@@ -9715,7 +9701,15 @@
 
 FM synthesizer (YM3812/OPL-3) support
 CONFIG_SOUND_YM3812
-  Answer Y here, unless you know you will not need the option.
+  Answer Y if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4).
+  Answering Y is usually a safe and recommended choice, however some
+  cards may have software (TSR) FM emulation. Enabling FM support with
+  these cards may cause trouble (I don't currently know of any such
+  cards, however).
+  Please read the file Documentation/sound/OPL3 if your card has an
+  OPL3 chip.
+
+  If unsure, say Y.
 
 Sun Audio support
 CONFIG_SUN_AUDIO
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/Documentation/kernel-parameters.txt linux.14p1/Documentation/kernel-parameters.txt
--- linux.vanilla/Documentation/kernel-parameters.txt	Sat Aug 14 02:26:45 1999
+++ linux.14p1/Documentation/kernel-parameters.txt	Fri Oct 22 22:38:10 1999
@@ -50,7 +50,7 @@
 it will appear as a kernel argument readable via /proc/cmdline by programs
 running once the system is up.
 
-    53c7xx=		[HW,SCSI]
+    53c7xx=		[HW,SCSI] Amiga SCSI controllers
 
     adb_buttons=	[HW,MOUSE]
 
@@ -68,6 +68,8 @@
 
     arcrimi=		[HW,NET]
 
+	ataflop=		[HW, M68k]
+
     atamouse=		[HW,MOUSE] Atari Mouse.
 
     atascsi=		[HW,SCSI] Atari SCSI.
@@ -96,22 +98,22 @@
 
     com90xx=		[HW,NET]
 
-    console=		
+    console=		[KNL] output console + comm spec (speed, control, parity)
 
     cyclades=		[HW,SERIAL] Cyclades multi-serial port adapter.
 
-    debug		[KNL] Enable kernel debugging.
+    debug		[KNL] Enable kernel debugging (events log level).
 
     decnet=		[HW,NET]
 
-    digi=		[HW,SERIAL]
+    digi=		[HW,SERIAL] io parameters + enable/disable command
 
     digiepca=		[HW,SERIAL]
 
     dmascc=		[HW,AX25,SERIAL] AX.25 Z80SCC driver with DMA
 			support available.
 
-    dmasound=		[HW,SOUND]
+    dmasound=		[HW,SOUND] (sound subsystem buffers)
 
     dtc3181e=		[HW,SCSI]
 
@@ -121,7 +123,7 @@
 
     edb=		[HW,PS2]
 
-    ether=		[HW,NET] Ethernet.
+    ether=		[HW,NET] Ethernet cards parameters (iomem,irq,dev_name).
 
     fd_mcs=		[HW,SCSI]
 
@@ -129,7 +131,7 @@
 
     floppy=		[HW]
 
-    ftape=		[HW] Floppy Tape subsystem.
+    ftape=		[HW] Floppy Tape subsystem debugging options.
 
     gdth=		[HW,SCSI]
 
@@ -137,7 +139,8 @@
 
     gvp11=		[HW,SCSI]
 
-    hd= 		[EIDE] IDE and EIDE hard drive subsystem.
+    hd= 		[EIDE] (E)IDE hard drive subsystem
+                geometry (Cyl/heads/sectors) or tune parameters.
 
     hfmodem=		[HW,AX25]
 
@@ -149,10 +152,18 @@
 
     icn=		[HW,ISDN]
 
+	ide?=		[HW] (E)IDE subsystem : config (iomem/irq), tuning or
+                     debugging (serialize,reset,no{dma,tune,probe}) or
+					chipset specific parameters
+
+	idebus=		[HW] (E)IDE subsystem : VLB/PCI bus speed
+
     in2000=		[HW,SCSI]
 
     init=		[KNL]
 
+	initrd=		[KNL] initial ramdisk path
+
     ip= 		[PNP]
 
     isp16=		[HW,CD]
@@ -185,7 +196,7 @@
 
     kbd-reset		[VT]
 
-    load_ramdisk=	[RAM]
+    load_ramdisk=	[RAM] initrd loading boolean
 
     lp= 		[LPT] Parallel Printer.
 
@@ -204,7 +215,7 @@
 
     mcdx=		[HW,CD]
 
-    md= 		[HW]
+    md= 		[HW] RAID subsystems devices and level
 
     mdacon=		[MDA]
 
@@ -224,6 +235,8 @@
 
     nfsroot=		[NFS]
 
+	nmi_watchdog=	[KNL, BUGS=ix86] debugging features for SMP kernels
+
     no387		[BUGS=ix86] Tells the kernel to use the 387 maths
 			emulation library even if a 387 maths coprocessor
 			is present.
@@ -231,6 +244,10 @@
     noapic		[SMP,APIC] Tells the kernel not to make use of any
 			APIC that may be present on the system.
 
+    noasync		[HW, M68K] Disables async and sync negotiation for all devices.
+
+    nodisconnect	[HW,SCSI, M68K] Disables SCSI disconnects.
+
     no-halt		[BUGS=ix86]
 
     noinitrd		[RAM] Tells the kernel not to load any configured
@@ -240,6 +257,8 @@
 
     nosmp		[SMP] Tells an SMP kernel to act as a UP kernel.
 
+    nosync		[HW, M68K] Disables sync negotiation for all devices.
+
     optcd=		[HW,CD]
 
     panic=		
@@ -260,7 +279,7 @@
 
     pg. 		[PARIDE]
 
-    pirq=		[SMP,APIC]
+    pirq=		[SMP,APIC] mp-table
 
     plip=		[LP,NET] Parallel port network link.
 
@@ -275,13 +294,14 @@
 
     ramdisk_size=	[RAM]
 
-    ramdisk_start=	[RAM]
+    ramdisk_start=	[RAM] offset of the initrd image when cohabiting with
+					a kernel image on a floppy
 
     reboot=		[BUGS=ix86]
 
     reserve=
 
-    riscom8=		[HW,SERIAL]
+    riscom8=		[HW,SERIAL] multi-port serial driver (io parameters)
 
     ro			[KNL] Mount root device read-only on boot.
 
@@ -303,12 +323,14 @@
 
     specialix=		[HW,SERIAL] Specialix multi-serial port adapter.
 
-    st= 		[HW]
+    st= 		[HW] SCSI tape parameters (buffers, ..)
 
     st0x=		[HW,SCSI]
 
     stram_swap= 	[HW]
 
+    switches=		[HW, M68K]
+
     sym53c416=		[HW,SCSI]
 
     sym53c8xx=		[HW,SCSI]
@@ -331,6 +353,6 @@
 
     wdt=		[HW]
 
-    xd= 		[HW,XT]
+    xd= 		[HW,XT] Original XT 8bit disk controllers
 
     xd_geo=		[HW,XT]
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/Makefile linux.14p1/Makefile
--- linux.vanilla/Makefile	Wed Oct 20 01:12:33 1999
+++ linux.14p1/Makefile	Fri Oct 22 22:16:43 1999
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 2
-SUBLEVEL = 13
-EXTRAVERSION =
+SUBLEVEL = 14
+EXTRAVERSION = pre1
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
@@ -381,6 +381,10 @@
 	rm -f drivers/net/hamradio/soundmodem/gentbl
 	rm -f drivers/char/hfmodem/gentbl drivers/char/hfmodem/tables.h
 	rm -f drivers/sound/*_boot.h drivers/sound/.*.boot
+	rm -f drivers/sound/msndinit.c
+	rm -f drivers/sound/msndperm.c
+	rm -f drivers/sound/pndsperm.c
+	rm -f drivers/sound/pndspini.c
 	rm -f .version .config* config.in config.old
 	rm -f scripts/tkparse scripts/kconfig.tk scripts/kconfig.tmp
 	rm -f scripts/lxdialog/*.o scripts/lxdialog/lxdialog
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/arch/alpha/kernel/process.c linux.14p1/arch/alpha/kernel/process.c
--- linux.vanilla/arch/alpha/kernel/process.c	Sat Aug 28 20:00:53 1999
+++ linux.14p1/arch/alpha/kernel/process.c	Fri Oct 22 21:20:22 1999
@@ -117,58 +117,44 @@
 	}
 }
 
-void
-generic_kill_arch (int mode, char *restart_cmd)
-{
-	/* The following currently only has any effect on SRM.  We should
-	   fix MILO to understand it.  Should be pretty easy.  Also we can
-	   support RESTART2 via the ipc_buffer machinations pictured below,
-	   which SRM ignores.  */
-
-	if (alpha_using_srm) {
-		struct percpu_struct *cpup;
-		unsigned long flags;
-	
-		cpup = (struct percpu_struct *)
-		  ((unsigned long)hwrpb + hwrpb->processor_offset);
-
-		flags = cpup->flags;
-
-		/* Clear reason to "default"; clear "bootstrap in progress". */
-		flags &= ~0x00ff0001UL;
-
-		if (mode == LINUX_REBOOT_CMD_RESTART) {
-			if (!restart_cmd) {
-				flags |= 0x00020000UL; /* "cold bootstrap" */
-				cpup->ipc_buffer[0] = 0;
-			} else {
-				flags |=  0x00030000UL; /* "warm bootstrap" */
-				strncpy((char *)cpup->ipc_buffer, restart_cmd,
-					sizeof(cpup->ipc_buffer));
-			}
-		} else {
-			flags |=  0x00040000UL; /* "remain halted" */
-		}
-			
-		cpup->flags = flags;					       
-		mb();						
-
-		reset_for_srm();
-		set_hae(srm_hae);
+struct halt_info {
+	int	mode;
+	char *	restart_cmd;
+};
 
-#ifdef CONFIG_DUMMY_CONSOLE
-		/* This has the effect of reseting the VGA video origin.  */
-		take_over_console(&dummy_con, 0, MAX_NR_CONSOLES-1, 1);
-#endif
+static void
+halt_processor(void * generic_ptr)
+{
+	struct percpu_struct * cpup;
+	struct halt_info * how = (struct halt_info *)generic_ptr;
+	unsigned long *flags;
+	int cpuid = smp_processor_id();
+
+	/* No point in taking interrupts anymore. */
+	__cli();
+
+	cpup = (struct percpu_struct *)
+			((unsigned long)hwrpb + hwrpb->processor_offset
+			 + hwrpb->processor_size * cpuid);
+	flags = &cpup->flags;
+
+	/* Clear reason to "default"; clear "bootstrap in progress". */
+	*flags &= ~0x00ff0001UL;
+
+#ifdef __SMP__
+	/* Secondaries halt here. */
+	if (cpuid != smp_boot_cpuid) {
+		*flags |= 0x00040000UL; /* "remain halted" */
+		clear_bit(cpuid, &cpu_present_mask);
+		halt();
 	}
+#endif /* __SMP__ */
 
 #ifdef CONFIG_RTC
 	/* Reset rtc to defaults.  */
 	{
 		unsigned char control;
 
-		cli();
-
 		/* Reset periodic interrupt frequency.  */
 		CMOS_WRITE(0x26, RTC_FREQ_SELECT);
 
@@ -177,22 +163,73 @@
 		control |= RTC_PIE;
 		CMOS_WRITE(control, RTC_CONTROL);	
 		CMOS_READ(RTC_INTR_FLAGS);
-
-		sti();
 	}
-#endif
+#endif /* CONFIG_RTC */
 
-	if (!alpha_using_srm && mode != LINUX_REBOOT_CMD_RESTART) {
+	if (how->mode == LINUX_REBOOT_CMD_RESTART) {
+		if (!how->restart_cmd) {
+			*flags |= 0x00020000UL; /* "cold bootstrap" */
+			cpup->ipc_buffer[0] = 0;
+		} else {
+		  /* NOTE: this could really only work when returning
+		     into MILO, rather than SRM console. The latter
+		     does NOT look at the ipc_buffer to get a new
+		     boot command. It could be done by using callbacks
+		     to change some of the SRM environment variables,
+		     but that is beyond our capabilities at this time.
+		     At the moment, SRM will use the last boot device,
+		     but the file and flags will be the defaults, when
+		     doing a "warm" bootstrap.
+		  */
+			*flags |=  0x00030000UL; /* "warm bootstrap" */
+			strncpy((char *)cpup->ipc_buffer,
+				how->restart_cmd,
+				sizeof(cpup->ipc_buffer));
+		}
+	} else
+		*flags |=  0x00040000UL; /* "remain halted" */
+
+#ifdef __SMP__
+	/* Wait for the secondaries to halt. */
+	clear_bit(smp_boot_cpuid, &cpu_present_mask);
+	while (cpu_present_mask)
+		/* Make sure we sample memory and not a register. */
+		barrier();
+#endif /* __SMP__ */
+
+        /* If booted from SRM, reset some of the original environment. */
+	if (alpha_using_srm) {
+#ifdef CONFIG_DUMMY_CONSOLE
+		/* This has the effect of resetting the VGA video origin.  */
+		take_over_console(&dummy_con, 0, MAX_NR_CONSOLES-1, 1);
+#endif
+		reset_for_srm();
+		set_hae(srm_hae);
+	}
+	else if (how->mode != LINUX_REBOOT_CMD_RESTART &&
+		 how->mode != LINUX_REBOOT_CMD_RESTART2) {
 		/* Unfortunately, since MILO doesn't currently understand
 		   the hwrpb bits above, we can't reliably halt the 
 		   processor and keep it halted.  So just loop.  */
 		return;
 	}
 
-	if (alpha_using_srm)
-		srm_paging_stop();
-
+	/* PRIMARY */
 	halt();
+}
+
+void
+generic_kill_arch(int mode, char * restart_cmd)
+{
+	struct halt_info copy_of_args;
+
+	copy_of_args.mode = mode;
+	copy_of_args.restart_cmd = restart_cmd;
+#ifdef __SMP__
+	/* A secondary can't wait here for the primary to finish, can it now? */
+	smp_call_function(halt_processor, (void *)&copy_of_args, 1, 0);
+#endif /* __SMP__ */
+	halt_processor(&copy_of_args);
 }
 
 void
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/arch/alpha/kernel/proto.h linux.14p1/arch/alpha/kernel/proto.h
--- linux.vanilla/arch/alpha/kernel/proto.h	Sat Aug 14 02:27:12 1999
+++ linux.14p1/arch/alpha/kernel/proto.h	Fri Oct 22 21:20:22 1999
@@ -153,6 +153,7 @@
 extern void handle_ipi(struct pt_regs *);
 extern void smp_percpu_timer_interrupt(struct pt_regs *);
 extern int smp_boot_cpuid;
+extern unsigned long cpu_present_mask;
 
 /* bios32.c */
 extern void reset_for_srm(void);
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/arch/alpha/math-emu/fp-emul.c linux.14p1/arch/alpha/math-emu/fp-emul.c
--- linux.vanilla/arch/alpha/math-emu/fp-emul.c	Sat Aug 28 20:00:53 1999
+++ linux.14p1/arch/alpha/math-emu/fp-emul.c	Fri Oct 22 22:30:50 1999
@@ -85,15 +85,15 @@
 
 /* For 128-bit division.  */
 
-__complex__ unsigned long
+void
 udiv128(unsigned long divisor_f0, unsigned long divisor_f1,
-	unsigned long dividend_f0, unsigned long dividend_f1)
+	unsigned long dividend_f0, unsigned long dividend_f1,
+	unsigned long *quot, unsigned long *remd)
 {
 	_FP_FRAC_DECL_2(quo);
 	_FP_FRAC_DECL_2(rem);
 	_FP_FRAC_DECL_2(tmp);
 	unsigned long i, num_bits, bit;
-	__complex__ unsigned long ret;
 
 	_FP_FRAC_SET_2(rem, _FP_ZEROFRAC_2);
 	_FP_FRAC_SET_2(quo, _FP_ZEROFRAC_2);
@@ -139,9 +139,9 @@
 	}
 
 out:
-	__real__ ret = quo_f1;
-	__imag__ ret = rem_f1;
-	return ret;
+	*quot = quo_f1;
+	*remd = rem_f1;
+	return;
 }
 
 /*
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/arch/alpha/math-emu/sfp-machine.h linux.14p1/arch/alpha/math-emu/sfp-machine.h
--- linux.vanilla/arch/alpha/math-emu/sfp-machine.h	Sat Aug 28 20:00:53 1999
+++ linux.14p1/arch/alpha/math-emu/sfp-machine.h	Fri Oct 22 22:30:50 1999
@@ -552,15 +552,17 @@
 	   : "r" ((UDItype)(u)),		\
 	     "r" ((UDItype)(v)))
 
-extern __complex__ unsigned long udiv128(unsigned long, unsigned long,
-					 unsigned long, unsigned long);
+extern void udiv128(unsigned long, unsigned long,
+		    unsigned long, unsigned long,
+		    unsigned long *,
+		    unsigned long *);
 
-#define udiv_qrnnd(q, r, n1, n0, d)	\
-  do {					\
-    __complex__ unsigned long x_;	\
-    x_ = udiv128((n0), (n1), 0, (d));	\
-    (q) = __real__ x_;			\
-    (r) = __imag__ x_;			\
+#define udiv_qrnnd(q, r, n1, n0, d)		\
+  do {						\
+    unsigned long xr, xi;			\
+    udiv128((n0), (n1), 0, (d), &xr, &xi);	\
+    (q) = xr; 					\
+    (r) = xi;					\
   } while (0)
 
 #define UDIV_NEEDS_NORMALIZATION 1  
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/arch/i386/boot/compressed/Makefile linux.14p1/arch/i386/boot/compressed/Makefile
--- linux.vanilla/arch/i386/boot/compressed/Makefile	Wed Oct 20 01:12:33 1999
+++ linux.14p1/arch/i386/boot/compressed/Makefile	Fri Oct 22 22:27:46 1999
@@ -37,7 +37,7 @@
 	tmppiggy=_tmp_$$$$piggy; \
 	rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk; \
 	$(OBJCOPY) $(SYSTEM) $$tmppiggy; \
-	gzip -f -3 < $$tmppiggy > $$tmppiggy.gz; \
+	gzip -f -9 < $$tmppiggy > $$tmppiggy.gz; \
 	echo "SECTIONS { .data : { input_len = .; LONG(input_data_end - input_data) input_data = .; *(.data) input_data_end = .; }}" > $$tmppiggy.lnk; \
 	$(LD) -m elf_i386 -r -o piggy.o -b binary $$tmppiggy.gz -b elf32-i386 -T $$tmppiggy.lnk; \
 	rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/arch/i386/boot/compressed/misc.c linux.14p1/arch/i386/boot/compressed/misc.c
--- linux.vanilla/arch/i386/boot/compressed/misc.c	Wed Jun 24 22:30:08 1998
+++ linux.14p1/arch/i386/boot/compressed/misc.c	Fri Oct 22 22:27:14 1999
@@ -104,7 +104,7 @@
 #define LOW_BUFFER_START      0x2000
 #define LOW_BUFFER_END       0x90000
 #define LOW_BUFFER_SIZE      ( LOW_BUFFER_END - LOW_BUFFER_START )
-#define HEAP_SIZE             0x2000
+#define HEAP_SIZE             0x2400
 static int high_loaded =0;
 static uch *high_buffer_start /* = (uch *)(((ulg)&end) + HEAP_SIZE)*/;
 
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/arch/i386/kernel/bios32.c linux.14p1/arch/i386/kernel/bios32.c
--- linux.vanilla/arch/i386/kernel/bios32.c	Sat Aug 14 02:25:55 1999
+++ linux.14p1/arch/i386/kernel/bios32.c	Fri Oct 22 21:21:07 1999
@@ -1097,6 +1097,7 @@
 
 extern int skip_ioapic_setup;
 
+extern int skip_ioapic_setup;	/* defined in arch/i386/kernel/smp.c */
 static void __init pcibios_fixup_devices(void)
 {
 	struct pci_dev *dev;
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/arch/i386/kernel/io_apic.c linux.14p1/arch/i386/kernel/io_apic.c
--- linux.vanilla/arch/i386/kernel/io_apic.c	Wed Oct 20 01:12:33 1999
+++ linux.14p1/arch/i386/kernel/io_apic.c	Fri Oct 22 21:21:27 1999
@@ -19,7 +19,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:
@@ -47,7 +47,7 @@
 /*
  * # of IRQ routing registers
  */
-int nr_ioapic_registers = 0;
+int nr_ioapic_registers[MAX_IO_APICS];
 
 enum ioapic_irq_destination_types {
 	dest_Fixed = 0,
@@ -94,6 +94,8 @@
 	mp_ExtINT = 3
 };
 
+int mp_apic_entries = 0;			/* # of I/O APIC entries */
+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 +110,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 +148,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 +156,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 +170,7 @@
 		if (++first_free_entry >= PIN_MAP_SIZE)
 			panic("io_apic.c: whoops");
 	}
+	entry->apic = apic;
 	entry->pin = pin;
 }
 
@@ -183,9 +186,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 +200,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 +214,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 < mp_apic_entries; apic++)
+		for (pin = 0; pin < nr_ioapic_registers[apic]; pin++)
+			clear_IO_APIC_pin(apic, pin);
 }
 
 /*
@@ -270,12 +274,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 +312,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 < mp_apic_entries; 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 +501,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 +523,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 +558,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 < mp_apic_entries; 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 +597,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 < mp_apic_entries; apic++) {
+	for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
 
 		/*
 		 * add it to the IO-APIC irq-routing table:
@@ -598,13 +614,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 +633,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 +653,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 +677,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 +689,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 < mp_apic_entries; 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 +704,12 @@
 	 */
 	printk("testing the IO APIC.......................\n");
 
+	for (apic = 0; apic < mp_apic_entries; 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)
@@ -731,8 +749,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 +769,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 +814,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 < mp_apic_entries; i++) {
+			*(int *)&reg_01 = io_apic_read(i, 1);
+			nr_ioapic_registers[i] = reg_01.entries+1;
+		}
 	}
 
 	/*
@@ -897,15 +918,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 +1248,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 +1262,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);
 
@@ -1282,7 +1306,8 @@
 	 * - those for which the user has specified a pirq= parameter
 	 */
 	if (	ioapic_whitelisted() ||
-		(nr_ioapic_registers == 16) ||
+		(mp_apic_entries == 1 && nr_ioapic_registers[0] == 16) ||
+		(mp_apic_entries > 1) ||
 		pirqs_enabled)
 	{
 		printk("ENABLING IO-APIC IRQs\n");
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/arch/i386/kernel/irq.h linux.14p1/arch/i386/kernel/irq.h
--- linux.vanilla/arch/i386/kernel/irq.h	Sat Aug 14 02:27:13 1999
+++ linux.14p1/arch/i386/kernel/irq.h	Fri Oct 22 23:30:31 1999
@@ -112,6 +112,11 @@
 
 extern char _stext, _etext;
 
+/*
+ * IF YOU CHANGE THIS, PLEASE ALSO CHANGE
+ * FIX_IO_APIC_BASE_* in fixmap.h
+ */
+#define MAX_IO_APICS 4
 #define MAX_IRQ_SOURCES 128
 #define MAX_MP_BUSSES 32
 enum mp_bustype {
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/arch/i386/kernel/setup.c linux.14p1/arch/i386/kernel/setup.c
--- linux.vanilla/arch/i386/kernel/setup.c	Wed Oct 20 01:12:33 1999
+++ linux.14p1/arch/i386/kernel/setup.c	Fri Oct 22 23:31:10 1999
@@ -366,7 +366,7 @@
 			/* Zero is valid according to the BIOS weenies */
 			if(i386_endbase)
 			{
-				printk(KERN_NOTICE "Ignoring bogus EBDA pointer %X\n", 
+				printk(KERN_NOTICE "Ignoring bogus EBDA pointer %lX\n", 
 					i386_endbase);
 			}
 			i386_endbase = BIOS_ENDBASE;
@@ -755,8 +755,8 @@
 	{ X86_VENDOR_INTEL,	6,
 	  { "Pentium Pro A-step", "Pentium Pro", NULL, "Pentium II (Klamath)", 
 	    NULL, "Pentium II (Deschutes)", "Mobile Pentium II", 
-            "Pentium III (Katmai)", "Pentium III (Coppermine)", NULL, NULL, 
-            NULL, NULL, NULL, NULL }},
+	    "Pentium III (Katmai)", "Pentium III (Coppermine)", NULL, NULL, 
+	    NULL, NULL, NULL, NULL, NULL }},
 	{ X86_VENDOR_AMD,	4,
 	  { NULL, NULL, NULL, "486 DX/2", NULL, NULL, NULL, "486 DX/2-WB",
 	    "486 DX/4", "486 DX/4-WB", NULL, NULL, NULL, NULL, "Am5x86-WT",
@@ -1019,8 +1019,9 @@
 			x86_cap_flags[14] = "mca";
 			x86_cap_flags[16] = "pat";
 			x86_cap_flags[17] = "pse36";
-			x86_cap_flags[18] = "psn";
-			x86_cap_flags[24] = "osfxsr";
+			x86_cap_flags[18] = "pn";
+			x86_cap_flags[24] = "fxsr";
+			x86_cap_flags[25] = "xmm";
 			break;
 
 		    case X86_VENDOR_CENTAUR:
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/arch/i386/kernel/smp.c linux.14p1/arch/i386/kernel/smp.c
--- linux.vanilla/arch/i386/kernel/smp.c	Wed Oct 20 01:12:33 1999
+++ linux.14p1/arch/i386/kernel/smp.c	Fri Oct 22 21:23:03 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 mp_apic_entries;
+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;
@@ -367,11 +369,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 [mp_apic_entries] = *m;
+					if (++mp_apic_entries > MAX_IO_APICS)
+						--mp_apic_entries;
 				}
 				mpt+=sizeof(*m);
 				count+=sizeof(*m);
@@ -403,9 +403,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;
 	}
@@ -772,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 < mp_apic_entries; 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
 
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/arch/ppc/common_defconfig linux.14p1/arch/ppc/common_defconfig
--- linux.vanilla/arch/ppc/common_defconfig	Sat Aug 14 02:27:15 1999
+++ linux.14p1/arch/ppc/common_defconfig	Fri Oct 22 22:26:41 1999
@@ -91,8 +91,10 @@
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_BLK_DEV_XD is not set
+# CONFIG_BLK_DEV_DAC960 is not set
 CONFIG_PARIDE_PARPORT=y
 # CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
@@ -155,7 +157,7 @@
 CONFIG_CHR_DEV_ST=y
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
-# CONFIG_CHR_DEV_SG is not set
+CONFIG_CHR_DEV_SG=y
 
 #
 # Some SCSI devices (e.g. CD jukebox) support multiple LUNs
@@ -226,10 +228,19 @@
 # Network device support
 #
 CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
 # CONFIG_ARCNET is not set
 # CONFIG_DUMMY is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_ETHERTAP is not set
+# CONFIG_NET_SB1000 is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
 CONFIG_NET_ETHERNET=y
 CONFIG_MACE=y
 CONFIG_BMAC=y
@@ -238,11 +249,12 @@
 # CONFIG_NET_VENDOR_SMC is not set
 # CONFIG_NET_VENDOR_RACAL is not set
 # CONFIG_RTL8139 is not set
+# CONFIG_SIS900 is not set
 # CONFIG_YELLOWFIN is not set
-# CONFIG_ACENIC is not set
 # CONFIG_NET_ISA is not set
 CONFIG_NET_EISA=y
 CONFIG_PCNET32=y
+# CONFIG_ACENIC is not set
 # CONFIG_AC3200 is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
@@ -261,7 +273,10 @@
 # CONFIG_NET_POCKET is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
-# CONFIG_DLCI is not set
+
+#
+# Appletalk devices
+#
 # CONFIG_LTPC is not set
 # CONFIG_COPS is not set
 # CONFIG_IPDDP is not set
@@ -272,11 +287,22 @@
 #
 # CONFIG_SLIP is not set
 # CONFIG_NET_RADIO is not set
+
+#
+# Token ring devices
+#
 # CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
 # CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
 # CONFIG_HOSTESS_SV11 is not set
 # CONFIG_COSA is not set
-# CONFIG_RCPCI is not set
+# CONFIG_SEALEVEL_4021 is not set
+# CONFIG_DLCI is not set
 
 #
 # Amateur Radio support
@@ -311,7 +337,6 @@
 CONFIG_FB_MATROX_MYSTIQUE=y
 CONFIG_FB_MATROX_G100=y
 # CONFIG_FB_MATROX_MULTIHEAD is not set
-# CONFIG_FB_ATY is not set
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FBCON_ADVANCED is not set
 CONFIG_FBCON_CFB8=y
@@ -407,6 +432,7 @@
 CONFIG_EXT2_FS=y
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_EFS_FS is not set
 
 #
 # Network File Systems
@@ -458,6 +484,7 @@
 # CONFIG_NLS_ISO8859_7 is not set
 # CONFIG_NLS_ISO8859_8 is not set
 # CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_14 is not set
 # CONFIG_NLS_ISO8859_15 is not set
 # CONFIG_NLS_KOI8_R is not set
 
@@ -468,6 +495,7 @@
 CONFIG_DMASOUND=y
 # CONFIG_SOUND_ES1370 is not set
 # CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_ESSSOLO1 is not set
 # CONFIG_SOUND_SONICVIBES is not set
 # CONFIG_SOUND_MSNDCLAS is not set
 # CONFIG_SOUND_MSNDPIN is not set
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/arch/ppc/defconfig linux.14p1/arch/ppc/defconfig
--- linux.vanilla/arch/ppc/defconfig	Wed Oct 20 01:12:33 1999
+++ linux.14p1/arch/ppc/defconfig	Fri Oct 22 22:26:41 1999
@@ -9,14 +9,13 @@
 CONFIG_6xx=y
 # CONFIG_PPC64 is not set
 # CONFIG_8xx is not set
-CONFIG_PMAC=y
+# CONFIG_PMAC is not set
 # CONFIG_PREP is not set
 # CONFIG_CHRP is not set
-# CONFIG_ALL_PPC is not set
+CONFIG_ALL_PPC=y
 # CONFIG_APUS is not set
 # CONFIG_MBX is not set
 # CONFIG_SMP is not set
-CONFIG_MACH_SPECIFIC=y
 CONFIG_6xx=y
 
 #
@@ -24,7 +23,7 @@
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_MODULES=y
-# CONFIG_MODVERSIONS is not set
+CONFIG_MODVERSIONS=y
 CONFIG_KMOD=y
 CONFIG_PCI=y
 # CONFIG_PCI_QUIRKS is not set
@@ -35,11 +34,10 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_BINFMT_ELF=y
 CONFIG_KERNEL_ELF=y
-CONFIG_BINFMT_MISC=m
+# CONFIG_BINFMT_MISC is not set
 # CONFIG_BINFMT_JAVA is not set
-CONFIG_PARPORT=m
-# CONFIG_PARPORT_PC is not set
-# CONFIG_VGA_CONSOLE is not set
+# CONFIG_PARPORT is not set
+CONFIG_VGA_CONSOLE=y
 CONFIG_FB=y
 CONFIG_FB_COMPAT_XPMAC=y
 CONFIG_PMAC_PBOOK=y
@@ -52,6 +50,7 @@
 # CONFIG_TOTALMP is not set
 CONFIG_BOOTX_TEXT=y
 # CONFIG_MOTOROLA_HOTSWAP is not set
+# CONFIG_CMDLINE_BOOL is not set
 
 #
 # Plug and Play support
@@ -61,7 +60,7 @@
 #
 # Block devices
 #
-# CONFIG_BLK_DEV_FD is not set
+CONFIG_BLK_DEV_FD=y
 CONFIG_BLK_DEV_IDE=y
 
 #
@@ -75,16 +74,8 @@
 # CONFIG_BLK_DEV_IDESCSI is not set
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
-CONFIG_BLK_DEV_IDEPCI=y
-CONFIG_BLK_DEV_IDEDMA=y
-# CONFIG_BLK_DEV_OFFBOARD is not set
-CONFIG_IDEDMA_AUTO=y
-# CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_TRM290 is not set
-# CONFIG_BLK_DEV_NS87415 is not set
-# CONFIG_BLK_DEV_VIA82C586 is not set
-CONFIG_BLK_DEV_CMD646=y
-# CONFIG_BLK_DEV_SL82C105 is not set
+# CONFIG_BLK_DEV_IDEPCI is not set
+CONFIG_BLK_DEV_SL82C105=y
 CONFIG_BLK_DEV_IDE_PMAC=y
 CONFIG_BLK_DEV_IDEDMA_PMAC=y
 CONFIG_BLK_DEV_IDEDMA=y
@@ -101,7 +92,7 @@
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_BLK_DEV_XD is not set
 # CONFIG_BLK_DEV_DAC960 is not set
-CONFIG_PARIDE_PARPORT=m
+CONFIG_PARIDE_PARPORT=y
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_DEV_HD is not set
@@ -125,7 +116,7 @@
 # CONFIG_NET_IPGRE is not set
 # CONFIG_IP_MROUTE is not set
 CONFIG_IP_ALIAS=y
-# CONFIG_SYN_COOKIES is not set
+CONFIG_SYN_COOKIES=y
 
 #
 # (it is safe to leave these untouched)
@@ -166,7 +157,7 @@
 CONFIG_CHR_DEV_ST=y
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
-# CONFIG_CHR_DEV_SG is not set
+CONFIG_CHR_DEV_SG=y
 
 #
 # Some SCSI devices (e.g. CD jukebox) support multiple LUNs
@@ -200,14 +191,14 @@
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
 # CONFIG_SCSI_GDTH is not set
 # CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_G_NCR5380_PORT is not set
+# CONFIG_SCSI_G_NCR5380_MEM is not set
 # CONFIG_SCSI_INITIO is not set
 # CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_PPA is not set
-# CONFIG_SCSI_IMM is not set
 # CONFIG_SCSI_NCR53C406A is not set
 # CONFIG_SCSI_SYM53C416 is not set
 # CONFIG_SCSI_NCR53C7xx is not set
-CONFIG_SCSI_NCR53C8XX=y
+# CONFIG_SCSI_NCR53C8XX is not set
 CONFIG_SCSI_SYM53C8XX=y
 CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
 CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
@@ -215,7 +206,7 @@
 # CONFIG_SCSI_NCR53C8XX_PROFILE is not set
 # CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
 # CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set
-CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT=y
+# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
 # CONFIG_SCSI_PAS16 is not set
 # CONFIG_SCSI_PCI2000 is not set
 # CONFIG_SCSI_PCI2220I is not set
@@ -262,7 +253,7 @@
 # CONFIG_YELLOWFIN is not set
 # CONFIG_NET_ISA is not set
 CONFIG_NET_EISA=y
-# CONFIG_PCNET32 is not set
+CONFIG_PCNET32=y
 # CONFIG_ACENIC is not set
 # CONFIG_AC3200 is not set
 # CONFIG_APRICOT is not set
@@ -289,7 +280,6 @@
 # CONFIG_LTPC is not set
 # CONFIG_COPS is not set
 # CONFIG_IPDDP is not set
-# CONFIG_PLIP is not set
 CONFIG_PPP=y
 
 #
@@ -338,12 +328,15 @@
 CONFIG_FB_CONTROL=y
 CONFIG_FB_PLATINUM=y
 CONFIG_FB_VALKYRIE=y
-CONFIG_FB_ATY=y
+# CONFIG_FB_ATY is not set
 CONFIG_FB_IMSTT=y
 CONFIG_FB_CT65550=y
 # CONFIG_FB_S3TRIO is not set
-# CONFIG_FB_MATROX is not set
-CONFIG_FB_ATY=y
+CONFIG_FB_MATROX=y
+# CONFIG_FB_MATROX_MILLENIUM is not set
+CONFIG_FB_MATROX_MYSTIQUE=y
+CONFIG_FB_MATROX_G100=y
+# CONFIG_FB_MATROX_MULTIHEAD is not set
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FBCON_ADVANCED is not set
 CONFIG_FBCON_CFB8=y
@@ -365,13 +358,22 @@
 #
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
-# CONFIG_SERIAL is not set
+CONFIG_SERIAL=m
 # CONFIG_SERIAL_EXTENDED is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
-# CONFIG_PRINTER is not set
-# CONFIG_MOUSE is not set
+CONFIG_MOUSE=y
+
+#
+# Mice
+#
+# CONFIG_ATIXL_BUSMOUSE is not set
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MS_BUSMOUSE is not set
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
 # CONFIG_QIC02_TAPE is not set
 # CONFIG_WATCHDOG is not set
 CONFIG_NVRAM=y
@@ -392,6 +394,14 @@
 # Ftape, the floppy tape device driver
 #
 # CONFIG_FTAPE is not set
+# CONFIG_FT_NORMAL_DEBUG is not set
+# CONFIG_FT_FULL_DEBUG is not set
+# CONFIG_FT_NO_TRACE is not set
+# CONFIG_FT_NO_TRACE_AT_ALL is not set
+# CONFIG_FT_STD_FDC is not set
+# CONFIG_FT_MACH2 is not set
+# CONFIG_FT_PROBE_FC10 is not set
+# CONFIG_FT_ALT_FDC is not set
 
 #
 # USB drivers - not for the faint of heart
@@ -406,10 +416,10 @@
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
 CONFIG_HFS_FS=y
-CONFIG_FAT_FS=m
-CONFIG_MSDOS_FS=m
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
 # CONFIG_UMSDOS_FS is not set
-CONFIG_VFAT_FS=m
+CONFIG_VFAT_FS=y
 CONFIG_ISO9660_FS=y
 # CONFIG_JOLIET is not set
 # CONFIG_MINIX_FS is not set
@@ -475,7 +485,7 @@
 # CONFIG_NLS_ISO8859_8 is not set
 # CONFIG_NLS_ISO8859_9 is not set
 # CONFIG_NLS_ISO8859_14 is not set
-CONFIG_NLS_ISO8859_15=y
+# CONFIG_NLS_ISO8859_15 is not set
 # CONFIG_NLS_KOI8_R is not set
 
 #
@@ -489,7 +499,34 @@
 # CONFIG_SOUND_SONICVIBES is not set
 # CONFIG_SOUND_MSNDCLAS is not set
 # CONFIG_SOUND_MSNDPIN is not set
-# CONFIG_SOUND_OSS is not set
+CONFIG_SOUND_OSS=y
+# CONFIG_SOUND_DMAP is not set
+# CONFIG_SOUND_PAS is not set
+# CONFIG_SOUND_SB is not set
+# CONFIG_SOUND_ADLIB is not set
+# CONFIG_SOUND_GUS is not set
+# CONFIG_SOUND_MPU401 is not set
+# CONFIG_SOUND_PSS is not set
+# CONFIG_SOUND_MSS is not set
+# CONFIG_SOUND_SSCAPE is not set
+# CONFIG_SOUND_TRIX is not set
+# CONFIG_SOUND_MAD16 is not set
+# CONFIG_SOUND_WAVEFRONT is not set
+CONFIG_SOUND_CS4232=m
+# CONFIG_SOUND_OPL3SA2 is not set
+# CONFIG_SOUND_MAUI is not set
+# CONFIG_SOUND_SGALAXY is not set
+# CONFIG_SOUND_AD1816 is not set
+# CONFIG_SOUND_OPL3SA1 is not set
+# CONFIG_SOUND_SOFTOSS is not set
+# CONFIG_SOUND_YM3812 is not set
+# CONFIG_SOUND_VMIDI is not set
+# CONFIG_SOUND_UART6850 is not set
+
+#
+# Additional low level sound drivers
+#
+# CONFIG_LOWLEVEL_SOUND is not set
 
 #
 # Kernel hacking
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/arch/ppc/kernel/chrp_pci.c linux.14p1/arch/ppc/kernel/chrp_pci.c
--- linux.vanilla/arch/ppc/kernel/chrp_pci.c	Wed Oct 20 01:12:33 1999
+++ linux.14p1/arch/ppc/kernel/chrp_pci.c	Fri Oct 22 22:26:41 1999
@@ -287,9 +287,6 @@
 	{
 		if ( dev->irq )
 			dev->irq = openpic_to_irq( dev->irq );
-		/* adjust the io_port for the NCR cards for busses other than 0 -- Cort */
-		if ( (dev->bus->number > 0) && (dev->vendor == PCI_VENDOR_ID_NCR) )
-			dev->base_address[0] += (dev->bus->number*0x08000000);
 		/* these need to be absolute addrs for OF and Matrox FB -- Cort */
 		if ( dev->vendor == PCI_VENDOR_ID_MATROX )
 		{
@@ -306,6 +303,10 @@
 			pcibios_write_config_word(dev->bus->number,
 			  dev->devfn, PCI_VENDOR_ID, PCI_VENDOR_ID_AMD);
 		}
+		if ( (dev->bus->number > 0) &&
+		     ((dev->vendor == PCI_VENDOR_ID_NCR) ||
+		      (dev->vendor == PCI_VENDOR_ID_AMD)))
+			dev->base_address[0] += (dev->bus->number*0x08000000);
 	}
 }
 
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/arch/ppc/kernel/head.S linux.14p1/arch/ppc/kernel/head.S
--- linux.vanilla/arch/ppc/kernel/head.S	Sat Aug 28 20:00:53 1999
+++ linux.14p1/arch/ppc/kernel/head.S	Fri Oct 22 22:26:41 1999
@@ -1,7 +1,7 @@
 /*
  *  arch/ppc/kernel/head.S
  *
- *  $Id: head.S,v 1.130.2.3 1999/08/10 21:36:48 cort Exp $
+ *  $Id: head.S,v 1.130.2.6 1999/10/12 01:03:34 cort Exp $
  *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -112,6 +112,10 @@
 	
 /* 601 only have IBAT cr0.eq is set on 601 when using this macro */ 
 #define LOAD_BAT(n, offset, reg, RA, RB) \
+	/* see the comment for clear_bats() -- Cort */ \
+	li	RA,0;			\
+	mtspr	IBAT##n##U,RA;		\
+	mtspr	DBAT##n##U,RA;		\
 	lwz	RA,offset+0(reg);	\
 	lwz	RB,offset+4(reg);	\
 	mtspr	IBAT##n##U,RA;		\
@@ -285,6 +289,14 @@
 	clrldi	r16,r16,63
 	mtsdr1	r16
 #else /* CONFIG_PPC64 */
+	/*
+	 * If the MMU is off clear the bats.  See clear_bat() -- Cort
+	 */
+	mfmsr	r20
+	andi.	r20,r20,MSR_DR
+	bne	100f
+	bl	clear_bats
+100:
 	/* 
 	 * allow secondary cpus to get at all of ram in early bootup
 	 * since their init_task may be up there -- Cort
@@ -1312,7 +1324,6 @@
 #else
 	bnelr-
 #endif
-
 	ori	r6,r6,0x100		/* set _PAGE_ACCESSED in pte */
 	rlwinm	r5,r4,5,24,24		/* _PAGE_RW access -> _PAGE_DIRTY */
 	rlwimi	r5,r4,7,22,22		/* _PAGE_RW -> _PAGE_HWWRITE */
@@ -2733,3 +2744,36 @@
 	.globl	cmd_line
 cmd_line:
 	.space	512
+
+/* 
+ * An undocumented "feature" of 604e requires that the v bit
+ * be cleared before changing BAT values.
+ *
+ * Also, newer IBM firmware does not clear bat3 and 4 so
+ * this makes sure it's done.
+ *  -- Cort 
+ */
+clear_bats:
+	li	r20,0
+	
+	mtspr	DBAT0U,r20
+	mtspr	DBAT0L,r20
+	mtspr	IBAT0U,r20
+	mtspr	IBAT0L,r20
+	
+	mtspr	DBAT1U,r20
+	mtspr	DBAT1L,r20
+	mtspr	IBAT1U,r20
+	mtspr	IBAT1L,r20
+	
+	mtspr	DBAT2U,r20
+	mtspr	DBAT2L,r20
+	mtspr	IBAT2U,r20
+	mtspr	IBAT2L,r20
+	
+	mtspr	DBAT3U,r20
+	mtspr	DBAT3L,r20
+	mtspr	IBAT3U,r20
+	mtspr	IBAT3L,r20
+
+	blr
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/arch/ppc/kernel/setup.c linux.14p1/arch/ppc/kernel/setup.c
--- linux.vanilla/arch/ppc/kernel/setup.c	Wed Oct 20 01:12:33 1999
+++ linux.14p1/arch/ppc/kernel/setup.c	Fri Oct 22 22:26:41 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: setup.c,v 1.132.2.5 1999/09/11 03:32:50 paulus Exp $
+ * $Id: setup.c,v 1.132.2.6 1999/10/19 04:32:33 paulus Exp $
  * Common prep/pmac/chrp boot and setup code.
  */
 
@@ -497,6 +497,28 @@
 		extern int __map_without_bats;
 		__map_without_bats = 1;
 	}
+
+	/* Look for mem= option on command line */
+	if (strstr(cmd_line, "mem=")) {
+		char *p, *q;
+		unsigned long maxmem = 0;
+		extern unsigned long __max_memory;
+
+		for (q = cmd_line; (p = strstr(q, "mem=")) != 0; ) {
+			q = p + 4;
+			if (p > cmd_line && p[-1] != ' ')
+				continue;
+			maxmem = simple_strtoul(q, &q, 0);
+			if (*q == 'k' || *q == 'K') {
+				maxmem <<= 10;
+				++q;
+			} else if (*q == 'm' || *q == 'M') {
+				maxmem <<= 20;
+				++q;
+			}
+		}
+		__max_memory = maxmem;
+	}
 	
 	return 0;
 }
@@ -522,7 +544,7 @@
 }
 
 __initfunc(void setup_arch(char **cmdline_p,
-			   unsigned long * memory_start_p, unsigned long * memory_end_p))
+		unsigned long * memory_start_p, unsigned long * memory_end_p))
 {
 	extern int panic_timeout;
 	extern char _etext[], _edata[];
@@ -532,8 +554,11 @@
 
 #ifdef CONFIG_XMON
 	extern void xmon_map_scc(void);
+	char *p;
+
 	xmon_map_scc();
-	if (strstr(cmd_line, "xmon"))
+	p = strstr(cmd_line, "xmon");
+	if (p != NULL && (p == cmd_line || p[-1] == ' '))
 		xmon(0);
 #endif /* CONFIG_XMON */
  
@@ -547,6 +572,7 @@
 
 	/* Save unparsed command line copy for /proc/cmdline */
 	strcpy(saved_command_line, cmd_line);
+
 	*cmdline_p = cmd_line;
 
 	*memory_start_p = find_available_memory();
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/arch/ppc/mm/init.c linux.14p1/arch/ppc/mm/init.c
--- linux.vanilla/arch/ppc/mm/init.c	Wed Oct 20 01:12:33 1999
+++ linux.14p1/arch/ppc/mm/init.c	Fri Oct 22 22:26:41 1999
@@ -1,5 +1,5 @@
 /*
- *  $Id: init.c,v 1.164.2.5 1999/09/07 00:59:22 paulus Exp $
+ *  $Id: init.c,v 1.164.2.7 1999/10/19 04:32:39 paulus Exp $
  *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -149,6 +149,9 @@
  */
 int __map_without_bats = 0;
 
+/* max amount of RAM to use */
+unsigned long __max_memory;
+
 /* optimization for 603 to load the tlb directly from the linux table -- Cort */
 #define NO_RELOAD_HTAB 1 /* change in kernel/head.S too! */
 
@@ -1296,7 +1299,7 @@
 	int i;
 	
 	/* max amount of RAM we allow -- Cort */
-#define RAM_LIMIT (256<<20)
+#define RAM_LIMIT (768<<20)
 
 	memory_node = find_devices("memory");
 	if (memory_node == NULL) {
@@ -1329,8 +1332,12 @@
 	 * to our nearest IO area.
 	 * -- Cort
 	 */
-	if ( phys_mem.regions[0].size >= RAM_LIMIT )
-		phys_mem.regions[0].size = RAM_LIMIT;
+	if (__max_memory == 0 || __max_memory > RAM_LIMIT)
+		__max_memory = RAM_LIMIT;
+	if (phys_mem.regions[0].size >= __max_memory) {
+		phys_mem.regions[0].size = __max_memory;
+		phys_mem.n_regions = 1;
+	}
 	total = phys_mem.regions[0].size;
 	
 	if (phys_mem.n_regions > 1) {
@@ -1343,20 +1350,15 @@
 	if (boot_infos == 0) {
 		/* record which bits the prom is using */
 		get_mem_prop("available", &phys_avail);
+		prom_mem = phys_mem;
+		for (i = 0; i < phys_avail.n_regions; ++i)
+			remove_mem_piece(&prom_mem,
+					 phys_avail.regions[i].address,
+					 phys_avail.regions[i].size, 0);
 	} else {
 		/* booted from BootX - it's all available (after klimit) */
 		phys_avail = phys_mem;
-	}
-	prom_mem = phys_mem;
-	for (i = 0; i < phys_avail.n_regions; ++i)
-	{
-		if ( phys_avail.regions[i].address >= RAM_LIMIT )
-			continue;
-		if ( (phys_avail.regions[i].address+phys_avail.regions[i].size)
-		     >= RAM_LIMIT )
-			phys_avail.regions[i].size = RAM_LIMIT - phys_avail.regions[i].address;
-		remove_mem_piece(&prom_mem, phys_avail.regions[i].address,
-				 phys_avail.regions[i].size, 1);
+		prom_mem.n_regions = 0;
 	}
 
 	/*
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/arch/ppc/xmon/xmon.c linux.14p1/arch/ppc/xmon/xmon.c
--- linux.vanilla/arch/ppc/xmon/xmon.c	Sat Aug 28 20:00:54 1999
+++ linux.14p1/arch/ppc/xmon/xmon.c	Fri Oct 22 22:26:41 1999
@@ -115,9 +115,13 @@
 {
 	struct pt_regs regs;
 	int msr, cmd;
+	static int entered = 0;
+
+	if (!entered) {
+		entered = 1;
+		printk("Entering xmon kernel debugger.\n");
+	}
 
-	printk("Entering xmon kernel debugger.\n");
-	
 	if (excp == NULL) {
 		asm volatile ("stw	0,0(%0)\n\
 			lwz	0,0(1)\n\
@@ -230,7 +234,7 @@
 
 	if (dabr.enabled && pc == dabr.instr)
 		return &dabr;
-	if (iabr.enabled && pc == iabr.address)
+	if (iabr.enabled && ((pc ^ iabr.address) & ~3) == 0)
 		return &iabr;
 	bp = bpts;
 	for (i = 0; i < NBPTS; ++i, ++bp)
@@ -254,7 +258,9 @@
 			printf("Couldn't insert breakpoint at %x, disabling\n",
 			       bp->address);
 			bp->enabled = 0;
+			continue;
 		}
+		store_inst((void *) bp->address);
 	}
 	if (dabr.enabled)
 		set_dabr(dabr.address);
@@ -277,9 +283,12 @@
 			continue;
 		if (mread(bp->address, &instr, 4) == 4
 		    && instr == bpinstr
-		    && mwrite(bp->address, &bp->instr, 4) != 4)
+		    && mwrite(bp->address, &bp->instr, 4) != 4) {
 			printf("Couldn't remove breakpoint at %x\n",
 			       bp->address);
+			continue;
+		}
+		store_inst((void *) bp->address);
 	}
 }
 
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/drivers/block/Config.in linux.14p1/drivers/block/Config.in
--- linux.vanilla/drivers/block/Config.in	Sat Aug 14 02:27:16 1999
+++ linux.14p1/drivers/block/Config.in	Fri Oct 22 22:18:35 1999
@@ -131,7 +131,9 @@
 if [ "$CONFIG_PARIDE" = "y" -o "$CONFIG_PARIDE" = "m" ]; then
   source drivers/block/paride/Config.in
 fi
-tristate 'Compaq SMART2 support' CONFIG_BLK_CPQ_DA
+if [ "$CONFIG_PCI" = "y" ]; then
+  tristate 'Compaq SMART2 support' CONFIG_BLK_CPQ_DA
+fi
 
 if [ "$CONFIG_BLK_DEV_HD_IDE" = "y" -o "$CONFIG_BLK_DEV_HD_ONLY" = "y" ]; then
   define_bool CONFIG_BLK_DEV_HD y
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/drivers/block/genhd.c linux.14p1/drivers/block/genhd.c
--- linux.vanilla/drivers/block/genhd.c	Wed Oct 20 01:12:34 1999
+++ linux.14p1/drivers/block/genhd.c	Fri Oct 22 22:15:20 1999
@@ -784,8 +784,11 @@
 	label = (struct sun_disklabel *) bh->b_data;
 	p = label->partitions;
 	if (be16_to_cpu(label->magic) != SUN_LABEL_MAGIC) {
+#if 0
+		/* There is no error here - it is just not a sunlabel. */
 		printk("Dev %s Sun disklabel: bad magic %04x\n",
 		       kdevname(dev), be16_to_cpu(label->magic));
+#endif
 		brelse(bh);
 		return 0;
 	}
@@ -856,8 +859,11 @@
 	p = &label->partitions[0];
 	magic = label->magic_mushroom;
 	if(be32_to_cpu(magic) != SGI_LABEL_MAGIC) {
+#if 0
+		/* There is no error here - it is just not an sgilabel. */
 		printk("Dev %s SGI disklabel: bad magic %08x\n",
 		       kdevname(dev), magic);
+#endif
 		brelse(bh);
 		return 0;
 	}
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/drivers/block/ide-disk.c linux.14p1/drivers/block/ide-disk.c
--- linux.vanilla/drivers/block/ide-disk.c	Thu Mar 11 01:49:43 1999
+++ linux.14p1/drivers/block/ide-disk.c	Fri Oct 22 22:15:20 1999
@@ -88,30 +88,35 @@
  */
 static int lba_capacity_is_ok (struct hd_driveid *id)
 {
-	unsigned long lba_sects   = id->lba_capacity;
-	unsigned long chs_sects   = id->cyls * id->heads * id->sectors;
-	unsigned long _10_percent = chs_sects / 10;
+	unsigned long lba_sects, chs_sects, head, tail;
 
 	/*
-	 * very large drives (8GB+) may lie about the number of cylinders
-	 * This is a split test for drives 8 Gig and Bigger only.
+	 * The ATA spec tells large drives to return
+	 * C/H/S = 16383/16/63 independent of their size.
+	 * Some drives can be jumpered to use 15 heads instead of 16.
 	 */
-	if ((id->lba_capacity >= 16514064) && (id->cyls == 0x3fff) &&
-	    (id->heads == 16) && (id->sectors == 63)) {
-		id->cyls = lba_sects / (16 * 63); /* correct cyls */
-		return 1;	/* lba_capacity is our only option */
-	}
+	if (id->cyls == 16383 && id->sectors == 63 &&
+	    (id->heads == 15 || id->heads == 16) &&
+	    id->lba_capacity >= 16383*63*id->heads)
+		return 1;
+
+	lba_sects   = id->lba_capacity;
+	chs_sects   = id->cyls * id->heads * id->sectors;
+
 	/* perform a rough sanity check on lba_sects:  within 10% is "okay" */
-	if ((lba_sects - chs_sects) < _10_percent) {
-		return 1;	/* lba_capacity is good */
-	}
+	if ((lba_sects - chs_sects) < chs_sects/10)
+		return 1;
+
 	/* some drives have the word order reversed */
-	lba_sects = (lba_sects << 16) | (lba_sects >> 16);
-	if ((lba_sects - chs_sects) < _10_percent) {
-		id->lba_capacity = lba_sects;	/* fix it */
+	head = ((lba_sects >> 16) & 0xffff);
+	tail = (lba_sects & 0xffff);
+	lba_sects = (head | (tail << 16));
+	if ((lba_sects - chs_sects) < chs_sects/10) {
+		id->lba_capacity = lba_sects;
 		return 1;	/* lba_capacity is (now) good */
 	}
-	return 0;	/* lba_capacity value is bad */
+
+	return 0;	/* lba_capacity value may be bad */
 }
 
 /*
@@ -446,7 +451,6 @@
 	/* Determine capacity, and use LBA if the drive properly supports it */
 	if (id != NULL && (id->capability & 2) && lba_capacity_is_ok(id)) {
 		if (id->lba_capacity >= capacity) {
-			drive->cyl = id->lba_capacity / (drive->head * drive->sect);
 			capacity = id->lba_capacity;
 			drive->select.b.lba = 1;
 		}
@@ -721,9 +725,9 @@
 		if ((id->lba_capacity > 16514064) || (id->cyls == 0x3fff)) {
 			id->cyls = ((int)(id->lba_capacity/(id->heads * id->sectors)));
 		}
-		drive->cyl  = id->cur_cyls    = id->cyls;
-		drive->head = id->cur_heads   = id->heads;
-		drive->sect = id->cur_sectors = id->sectors;
+		drive->cyl  = id->cyls;
+		drive->head = id->heads;
+		drive->sect = id->sectors;
 	}
 
 	/* calculate drive capacity, and select LBA if possible */
@@ -733,21 +737,19 @@
 	 * if possible, give fdisk access to more of the drive,
 	 * by correcting bios_cyls:
 	 */
-	if ((capacity >= (drive->bios_cyl * drive->bios_sect * drive->bios_head)) &&
-	    (!drive->forced_geom) && drive->bios_sect && drive->bios_head) {
-		drive->bios_cyl = (capacity / drive->bios_sect) / drive->bios_head;
-#ifdef DEBUG
-		printk("Fixing Geometry :: CHS=%d/%d/%d to CHS=%d/%d/%d\n",
-			drive->id->cur_cyls,
-			drive->id->cur_heads,
-			drive->id->cur_sectors,
-			drive->bios_cyl,
-			drive->bios_head,
-			drive->bios_sect);
-#endif
-		drive->id->cur_cyls    = drive->bios_cyl;
-		drive->id->cur_heads   = drive->bios_head;
-		drive->id->cur_sectors = drive->bios_sect;
+	if (!drive->forced_geom &&
+	    capacity > drive->bios_cyl * drive->bios_sect * drive->bios_head) {
+		unsigned long cylsize;
+		cylsize = drive->bios_sect * drive->bios_head;
+		if (cylsize == 0 || capacity/cylsize > 65535) {
+			drive->bios_sect = 63;
+			drive->bios_head = 255;
+			cylsize = 63*255;
+		}
+		if (capacity/cylsize > 65535)
+			drive->bios_cyl = 65535;
+		else
+			drive->bios_cyl = capacity/cylsize;
 	}
 
 #if 0	/* done instead for entire identify block in arch/ide.h stuff */
@@ -770,19 +772,6 @@
 		}
 	}
 	printk("\n");
-
-	if (drive->select.b.lba) {
-		if (*(int *)&id->cur_capacity0 < id->lba_capacity) {
-#ifdef DEBUG
-			printk("     CurSects=%d, LBASects=%d, ",
-				*(int *)&id->cur_capacity0, id->lba_capacity);
-#endif
-			*(int *)&id->cur_capacity0 = id->lba_capacity;
-#ifdef DEBUG
-			printk( "Fixed CurSects=%d\n", *(int *)&id->cur_capacity0);
-#endif
-		}
-	}
 
 	drive->mult_count = 0;
 	if (id->max_multsect) {
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/drivers/block/ide-proc.c linux.14p1/drivers/block/ide-proc.c
--- linux.vanilla/drivers/block/ide-proc.c	Wed May  6 22:42:53 1998
+++ linux.14p1/drivers/block/ide-proc.c	Fri Oct 22 22:15:20 1999
@@ -516,8 +516,10 @@
 	char		*out = page;
 	int		len;
 
-	out += sprintf(out,"physical     %hi/%hi/%hi\n", drive->cyl, drive->head, drive->sect);
-	out += sprintf(out,"logical      %hi/%hi/%hi\n", drive->bios_cyl, drive->bios_head, drive->bios_sect);
+	out += sprintf(out,"physical     %d/%d/%d\n",
+		       drive->cyl, drive->head, drive->sect);
+	out += sprintf(out,"logical      %d/%d/%d\n",
+		       drive->bios_cyl, drive->bios_head, drive->bios_sect);
 	len = out - page;
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/drivers/char/bttv.c linux.14p1/drivers/char/bttv.c
--- linux.vanilla/drivers/char/bttv.c	Wed Oct 20 01:12:35 1999
+++ linux.14p1/drivers/char/bttv.c	Fri Oct 22 22:16:43 1999
@@ -403,7 +403,7 @@
 	}
 }
 
-void attach_inform(struct i2c_bus *bus, int id)
+static void attach_inform(struct i2c_bus *bus, int id)
 {
         struct bttv *btv = (struct bttv*)bus->data;
         
@@ -422,7 +422,7 @@
 	}
 }
 
-void detach_inform(struct i2c_bus *bus, int id)
+static void detach_inform(struct i2c_bus *bus, int id)
 {
         struct bttv *btv = (struct bttv*)bus->data;
 
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/drivers/char/buz.c linux.14p1/drivers/char/buz.c
--- linux.vanilla/drivers/char/buz.c	Wed Oct 20 01:12:35 1999
+++ linux.14p1/drivers/char/buz.c	Fri Oct 22 22:16:43 1999
@@ -374,13 +374,13 @@
 	return (btread(ZR36057_I2CBR) >> 1) & 1;
 }
 
-void attach_inform(struct i2c_bus *bus, int id)
+static void attach_inform(struct i2c_bus *bus, int id)
 {
 	DEBUG(struct zoran *zr = (struct zoran *) bus->data);
 	DEBUG(printk(BUZ_DEBUG "-%u: i2c attach %02x\n", zr->id, id));
 }
 
-void detach_inform(struct i2c_bus *bus, int id)
+static void detach_inform(struct i2c_bus *bus, int id)
 {
 	DEBUG(struct zoran *zr = (struct zoran *) bus->data);
 	DEBUG(printk(BUZ_DEBUG "-%u: i2c detach %02x\n", zr->id, id));
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/drivers/char/radio-aimslab.c linux.14p1/drivers/char/radio-aimslab.c
--- linux.vanilla/drivers/char/radio-aimslab.c	Sat Aug 14 02:25:39 1999
+++ linux.14p1/drivers/char/radio-aimslab.c	Fri Oct 22 22:18:35 1999
@@ -195,7 +195,7 @@
 	return 0;
 }
 
-int rt_getsigstr(struct rt_device *dev)
+static int rt_getsigstr(struct rt_device *dev)
 {
 	if (inb(io) & 2)	/* bit set = no signal present	*/
 		return 0;
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/drivers/char/radio-cadet.c linux.14p1/drivers/char/radio-cadet.c
--- linux.vanilla/drivers/char/radio-cadet.c	Sat Aug 14 02:27:17 1999
+++ linux.14p1/drivers/char/radio-cadet.c	Fri Oct 22 22:16:43 1999
@@ -39,6 +39,7 @@
 static __u8 rdsin=0,rdsout=0,rdsstat=0;
 static unsigned char rdsbuf[RDS_BUFFER];
 static int cadet_lock=0;
+static int cadet_probe(void);
 
 /*
  * Signal Strength Threshold Values
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/drivers/char/radio-rtrack2.c linux.14p1/drivers/char/radio-rtrack2.c
--- linux.vanilla/drivers/char/radio-rtrack2.c	Sat Aug 14 02:25:40 1999
+++ linux.14p1/drivers/char/radio-rtrack2.c	Fri Oct 22 22:18:35 1999
@@ -89,7 +89,7 @@
 	return 0;
 }
 
-int rt_getsigstr(struct rt_device *dev)
+static int rt_getsigstr(struct rt_device *dev)
 {
 	if (inb(io) & 2)	/* bit set = no signal present	*/
 		return 0;
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/drivers/fc4/Makefile linux.14p1/drivers/fc4/Makefile
--- linux.vanilla/drivers/fc4/Makefile	Tue Mar 16 00:11:29 1999
+++ linux.14p1/drivers/fc4/Makefile	Fri Oct 22 21:24:05 1999
@@ -7,8 +7,6 @@
 M_OBJS   :=
 MOD_LIST_NAME := FC4_MODULES
 
-include ../../.config
-
 ifeq ($(CONFIG_FC4),y)
   FC4 = fc.o
   ifeq ($(CONFIG_MODULES),y)
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/drivers/isdn/avmb1/capi.c linux.14p1/drivers/isdn/avmb1/capi.c
--- linux.vanilla/drivers/isdn/avmb1/capi.c	Wed Oct 20 01:12:36 1999
+++ linux.14p1/drivers/isdn/avmb1/capi.c	Fri Oct 22 22:18:35 1999
@@ -109,6 +109,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/version.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/drivers/macintosh/macserial.c linux.14p1/drivers/macintosh/macserial.c
--- linux.vanilla/drivers/macintosh/macserial.c	Wed Oct 20 01:12:38 1999
+++ linux.14p1/drivers/macintosh/macserial.c	Fri Oct 22 22:26:41 1999
@@ -6,7 +6,9 @@
  * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  *
- * $Id: macserial.c,v 1.24.2.3 1999/09/10 02:05:58 paulus Exp $
+ * Receive DMA code by Takashi Oe <toe@unlserve.unl.edu>.
+ *
+ * $Id: macserial.c,v 1.24.2.4 1999/10/19 04:36:42 paulus Exp $
  */
 
 #include <linux/config.h>
@@ -28,6 +30,7 @@
 #ifdef CONFIG_SERIAL_CONSOLE
 #include <linux/console.h>
 #endif
+#include <linux/slab.h>
 
 #include <asm/io.h>
 #include <asm/pgtable.h>
@@ -42,6 +45,7 @@
 #ifdef CONFIG_KGDB
 #include <asm/kgdb.h>
 #endif
+#include <asm/dbdma.h>
 
 #include "macserial.h"
 
@@ -53,6 +57,8 @@
 };
 #endif
 
+#define SUPPORT_SERIAL_DMA
+
 /*
  * It would be nice to dynamically allocate everything that
  * depends on NUM_SERIAL, so we could support any number of
@@ -128,6 +134,13 @@
 static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
 static int set_scc_power(struct mac_serial * info, int state);
 static int setup_scc(struct mac_serial * info);
+static void dbdma_reset(volatile struct dbdma_regs *dma);
+static void dbdma_flush(volatile struct dbdma_regs *dma);
+static void rs_txdma_irq(int irq, void *dev_id, struct pt_regs *regs);
+static void rs_rxdma_irq(int irq, void *dev_id, struct pt_regs *regs);
+static void dma_init(struct mac_serial * info);
+static void rxdma_start(struct mac_serial * info, int current);
+static void rxdma_to_tty(struct mac_serial * info);
 
 static struct tty_struct *serial_table[NUM_CHANNELS];
 static struct termios *serial_termios[NUM_CHANNELS];
@@ -153,7 +166,7 @@
 __openfirmware
 #endif /* MODULE */
 static inline int serial_paranoia_check(struct mac_serial *info,
-					dev_t device, const char *routine)
+                                       dev_t device, const char *routine)
 {
 #ifdef SERIAL_PARANOIA_CHECK
 	static const char *badmagic =
@@ -177,7 +190,7 @@
  * Reading and writing Z8530 registers.
  */
 static inline unsigned char read_zsreg(struct mac_zschannel *channel,
-				       unsigned char reg)
+                                      unsigned char reg)
 {
 	unsigned char retval;
 	unsigned long flags;
@@ -197,7 +210,7 @@
 }
 
 static inline void write_zsreg(struct mac_zschannel *channel,
-			       unsigned char reg, unsigned char value)
+                              unsigned char reg, unsigned char value)
 {
 	unsigned long flags;
 
@@ -290,6 +303,39 @@
 }
 
 /*
+ * Reset a Descriptor-Based DMA channel.
+ */
+static void dbdma_reset(volatile struct dbdma_regs *dma)
+{
+	int i;
+
+	out_le32(&dma->control, (WAKE|FLUSH|PAUSE|RUN) << 16);
+
+	/*
+	 * Yes this looks peculiar, but apparently it needs to be this
+	 * way on some machines.  (We need to make sure the DBDMA
+	 * engine has actually got the write above and responded
+	 * to it. - paulus)
+	 */
+	for (i = 200; i > 0; --i)
+		if (ld_le32(&dma->control) & RUN)
+			udelay(1);
+}
+
+/*
+ * Tells a DBDMA channel to stop and write any buffered data
+ * it might have to memory.
+ */
+static _INLINE_ void dbdma_flush(volatile struct dbdma_regs *dma)
+{
+	int i = 0;
+
+	out_le32(&dma->control, (FLUSH << 16) | FLUSH);
+	while (((in_le32(&dma->status) & FLUSH) != 0) && (i++ < 100))
+		udelay(1);
+}
+
+/*
  * ----------------------------------------------------------------------
  *
  * Here starts the interrupt handling routines.  All of the following
@@ -312,6 +358,22 @@
 	mark_bh(MACSERIAL_BH);
 }
 
+/* Work out the flag value for a z8530 status value. */
+static _INLINE_ int stat_to_flag(int stat)
+{
+	int flag;
+
+	if (stat & Rx_OVR) {
+		flag = TTY_OVERRUN;
+	} else if (stat & FRM_ERR) {
+		flag = TTY_FRAME;
+	} else if (stat & PAR_ERR) {
+		flag = TTY_PARITY;
+	} else
+		flag = 0;
+	return flag;
+}
+
 static _INLINE_ void receive_chars(struct mac_serial *info,
 				   struct pt_regs *regs)
 {
@@ -349,14 +411,7 @@
 			if (flip_max_cnt < tty->flip.count)
 				flip_max_cnt = tty->flip.count;
 		}
-		if (stat & Rx_OVR) {
-			flag = TTY_OVERRUN;
-		} else if (stat & FRM_ERR) {
-			flag = TTY_FRAME;
-		} else if (stat & PAR_ERR) {
-			flag = TTY_PARITY;
-		} else
-			flag = 0;
+		flag = stat_to_flag(stat);
 		if (flag)
 			/* reset the error indication */
 			write_zsreg(info->zs_channel, 0, ERR_RES);
@@ -452,6 +507,32 @@
 	info->read_reg_zero = status;
 }
 
+static _INLINE_ void receive_special_dma(struct mac_serial *info)
+{
+	unsigned char stat, flag;
+	volatile struct dbdma_regs *rd = &info->rx->dma;
+	int where = RX_BUF_SIZE;
+
+	spin_lock(&info->rx_dma_lock);
+	if ((ld_le32(&rd->status) & ACTIVE) != 0)
+		dbdma_flush(rd);
+	if (in_le32(&rd->cmdptr)
+	    == virt_to_bus(info->rx_cmds[info->rx_cbuf] + 1))
+		where -= in_le16(&info->rx->res_count);
+	where--;
+	
+	stat = read_zsreg(info->zs_channel, R1);
+
+	flag = stat_to_flag(stat);
+	if (flag) {
+		info->rx_flag_buf[info->rx_cbuf][where] = flag;
+		/* reset the error indication */
+		write_zsreg(info->zs_channel, 0, ERR_RES);
+	}
+
+	spin_unlock(&info->rx_dma_lock);
+}
+
 /*
  * This is the serial driver's generic interrupt routine
  */
@@ -461,6 +542,12 @@
 	unsigned char zs_intreg;
 	int shift;
 
+	if (!(info->flags & ZILOG_INITIALIZED)) {
+		printk("rs_interrupt: irq %d, port not initialized\n", irq);
+		disable_irq(irq);
+		return;
+	}
+
 	/* NOTE: The read register 3, which holds the irq status,
 	 *       does so for both channels on each chip.  Although
 	 *       the status value itself must be read from the A
@@ -477,19 +564,21 @@
 	for (;;) {
 		zs_intreg = read_zsreg(info->zs_chan_a, 3) >> shift;
 #ifdef SERIAL_DEBUG_INTR
-		printk("rs_interrupt: irq %d, zs_intreg 0x%x\n", irq, (int)zs_intreg);
+		printk("rs_interrupt: irq %d, zs_intreg 0x%x\n",
+		       irq, (int)zs_intreg);
 #endif	
 
 		if ((zs_intreg & CHAN_IRQMASK) == 0)
 			break;
 
-		if (!(info->flags & ZILOG_INITIALIZED)) {
-			printk("rs_interrupt: irq %d, port not initialized\n", irq);
-			break;
+		if (zs_intreg & CHBRxIP) {
+			/* If we are doing DMA, we only ask for interrupts
+			   on characters with errors or special conditions. */
+			if (info->dma_initted)
+				receive_special_dma(info);
+			else
+				receive_chars(info, regs);
 		}
-
-		if (zs_intreg & CHBRxIP)
-			receive_chars(info, regs);
 		if (zs_intreg & CHBTxIP)
 			transmit_chars(info);
 		if (zs_intreg & CHBEXT)
@@ -497,6 +586,39 @@
 	}
 }
 
+/* Transmit DMA interrupt - not used at present */
+static void rs_txdma_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+}
+
+/*
+ * Receive DMA interrupt.
+ */
+static void rs_rxdma_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct mac_serial *info = (struct mac_serial *) dev_id;
+	volatile struct dbdma_cmd *cd;
+
+	if (!info->dma_initted)
+		return;
+	spin_lock(&info->rx_dma_lock);
+	/* First, confirm that this interrupt is, indeed, coming */
+	/* from Rx DMA */
+	cd = info->rx_cmds[info->rx_cbuf] + 2;
+	if ((in_le16(&cd->xfer_status) & (RUN | ACTIVE)) != (RUN | ACTIVE)) {
+		spin_unlock(&info->rx_dma_lock);
+		return;
+	}
+	if (info->rx_fbuf != RX_NO_FBUF) {
+		info->rx_cbuf = info->rx_fbuf;
+		if (++info->rx_fbuf == info->rx_nbuf)
+			info->rx_fbuf = 0;
+		if (info->rx_fbuf == info->rx_ubuf)
+			info->rx_fbuf = RX_NO_FBUF;
+	}
+	spin_unlock(&info->rx_dma_lock);
+}
+
 /*
  * -------------------------------------------------------------------
  * Here ends the serial interrupt routines.
@@ -592,10 +714,6 @@
 	}
 }
 
-static void rs_timer(void)
-{
-}
-
 static int startup(struct mac_serial * info, int can_sleep)
 {
 	int delay;
@@ -631,6 +749,10 @@
 
 	info->flags |= ZILOG_INITIALIZED;
 	enable_irq(info->irq);
+	if (info->dma_initted) {
+//		enable_irq(info->tx_dma_irq);
+		enable_irq(info->rx_dma_irq);
+	}
 
 	if (delay) {
 		if (can_sleep) {
@@ -644,6 +766,187 @@
 	return 0;
 }
 
+static _INLINE_ void rxdma_start(struct mac_serial * info, int current)
+{
+	volatile struct dbdma_regs *rd = &info->rx->dma;
+	volatile struct dbdma_cmd *cd = info->rx_cmds[current];
+
+//printk(KERN_DEBUG "SCC: rxdma_start\n");
+
+	st_le32(&rd->cmdptr, virt_to_bus(cd));
+	out_le32(&rd->control, (RUN << 16) | RUN);
+}
+
+static void rxdma_to_tty(struct mac_serial *info)
+{
+	struct tty_struct	*tty = info->tty;
+	volatile struct dbdma_regs *rd = &info->rx->dma;
+	unsigned long flags;
+	int residue, available, space, do_queue;
+
+	if (!tty)
+		return;
+
+	do_queue = 0;
+	spin_lock_irqsave(&info->rx_dma_lock, flags);
+more:
+	space = TTY_FLIPBUF_SIZE - tty->flip.count;
+	if (!space) {
+		do_queue++;
+		goto out;
+	}
+	residue = 0;
+	if (info->rx_ubuf == info->rx_cbuf) {
+		if ((ld_le32(&rd->status) & ACTIVE) != 0) {
+			dbdma_flush(rd);
+			if (in_le32(&rd->cmdptr)
+			    == virt_to_bus(info->rx_cmds[info->rx_cbuf]+1))
+				residue = in_le16(&info->rx->res_count);
+		}
+	}
+	available = RX_BUF_SIZE - residue - info->rx_done_bytes;
+	if (available > space)
+		available = space;
+	if (available) {
+		memcpy(tty->flip.char_buf_ptr,
+		       info->rx_char_buf[info->rx_ubuf] + info->rx_done_bytes,
+		       available);
+		memcpy(tty->flip.flag_buf_ptr,
+		       info->rx_flag_buf[info->rx_ubuf] + info->rx_done_bytes,
+		       available);
+		tty->flip.char_buf_ptr += available;
+		tty->flip.count += available;
+		tty->flip.flag_buf_ptr += available;
+		memset(info->rx_flag_buf[info->rx_ubuf] + info->rx_done_bytes,
+		       0, available);
+		info->rx_done_bytes += available;
+		do_queue++;
+	}
+	if (info->rx_done_bytes == RX_BUF_SIZE) {
+		volatile struct dbdma_cmd *cd = info->rx_cmds[info->rx_ubuf];
+
+		if (info->rx_ubuf == info->rx_cbuf)
+			goto out;
+		/* mark rx_char_buf[rx_ubuf] free */
+		st_le16(&cd->command, DBDMA_NOP);
+		cd++;
+		st_le32(&cd->cmd_dep, 0);
+		st_le32((unsigned int *)&cd->res_count, 0);
+		cd++;
+		st_le16(&cd->xfer_status, 0);
+
+		if (info->rx_fbuf == RX_NO_FBUF) {
+			info->rx_fbuf = info->rx_ubuf;
+			if (!(ld_le32(&rd->status) & ACTIVE)) {
+				dbdma_reset(&info->rx->dma);
+				rxdma_start(info, info->rx_ubuf);
+				info->rx_cbuf = info->rx_ubuf;
+			}
+		}
+		info->rx_done_bytes = 0;
+		if (++info->rx_ubuf == info->rx_nbuf)
+			info->rx_ubuf = 0;
+		if (info->rx_fbuf == info->rx_ubuf)
+			info->rx_fbuf = RX_NO_FBUF;
+		goto more;
+	}
+out:
+	spin_unlock_irqrestore(&info->rx_dma_lock, flags);
+	if (do_queue)
+		queue_task(&tty->flip.tqueue, &tq_timer);
+}
+
+static void poll_rxdma(void *private_)
+{
+	struct mac_serial	*info = (struct mac_serial *) private_;
+	unsigned long flags;
+
+	rxdma_to_tty(info);
+	spin_lock_irqsave(&info->rx_dma_lock, flags);
+	mod_timer(&info->poll_dma_timer, RX_DMA_TIMER);
+	spin_unlock_irqrestore(&info->rx_dma_lock, flags);
+}
+
+static void dma_init(struct mac_serial * info)
+{
+	int i, size;
+	volatile struct dbdma_cmd *cd;
+	unsigned char *p;
+
+//printk(KERN_DEBUG "SCC: dma_init\n");
+
+	info->rx_nbuf = 8;
+
+	/* various mem set up */
+	size = sizeof(struct dbdma_cmd) * (3 * info->rx_nbuf + 2)
+		+ (RX_BUF_SIZE * 2 + sizeof(*info->rx_cmds)
+		   + sizeof(*info->rx_char_buf) + sizeof(*info->rx_flag_buf))
+		* info->rx_nbuf;
+	info->dma_priv = kmalloc(size, GFP_KERNEL | GFP_DMA);
+	if (info->dma_priv == NULL)
+		return;
+	memset(info->dma_priv, 0, size);
+
+	info->rx_cmds = (volatile struct dbdma_cmd **)info->dma_priv;
+	info->rx_char_buf = (unsigned char **) (info->rx_cmds + info->rx_nbuf);
+	info->rx_flag_buf = info->rx_char_buf + info->rx_nbuf;
+	p = (unsigned char *) (info->rx_flag_buf + info->rx_nbuf);
+	for (i = 0; i < info->rx_nbuf; i++, p += RX_BUF_SIZE)
+		info->rx_char_buf[i] = p;
+	for (i = 0; i < info->rx_nbuf; i++, p += RX_BUF_SIZE)
+		info->rx_flag_buf[i] = p;
+
+	/* a bit of DMA programming */
+	cd = info->rx_cmds[0] = (volatile struct dbdma_cmd *) DBDMA_ALIGN(p);
+	st_le16(&cd->command, DBDMA_NOP);
+	cd++;
+	st_le16(&cd->req_count, RX_BUF_SIZE);
+	st_le16(&cd->command, INPUT_MORE);
+	st_le32(&cd->phy_addr, virt_to_bus(info->rx_char_buf[0]));
+	cd++;
+	st_le16(&cd->req_count, 4);
+	st_le16(&cd->command, STORE_WORD | INTR_ALWAYS);
+	st_le32(&cd->phy_addr, virt_to_bus(cd-2));
+	st_le32(&cd->cmd_dep, DBDMA_STOP);
+	for (i = 1; i < info->rx_nbuf; i++) {
+		info->rx_cmds[i] = ++cd;
+		st_le16(&cd->command, DBDMA_NOP);
+		cd++;
+		st_le16(&cd->req_count, RX_BUF_SIZE);
+		st_le16(&cd->command, INPUT_MORE);
+		st_le32(&cd->phy_addr, virt_to_bus(info->rx_char_buf[i]));
+		cd++;
+		st_le16(&cd->req_count, 4);
+		st_le16(&cd->command, STORE_WORD | INTR_ALWAYS);
+		st_le32(&cd->phy_addr, virt_to_bus(cd-2));
+		st_le32(&cd->cmd_dep, DBDMA_STOP);
+	}
+	cd++;
+	st_le16(&cd->command, DBDMA_NOP | BR_ALWAYS);
+	st_le32(&cd->cmd_dep, virt_to_bus(info->rx_cmds[0]));
+
+	/* setup DMA to our liking */
+	dbdma_reset(&info->rx->dma);
+	st_le32(&info->rx->dma.intr_sel, 0x10001);
+	st_le32(&info->rx->dma.br_sel, 0x10001);
+	out_le32(&info->rx->dma.wait_sel, 0x10001);
+
+	/* set various flags */
+	info->rx_ubuf = 0;
+	info->rx_cbuf = 0;
+	info->rx_fbuf = info->rx_ubuf + 1;
+	if (info->rx_fbuf == info->rx_nbuf)
+		info->rx_fbuf = RX_NO_FBUF;
+	info->rx_done_bytes = 0;
+
+	/* setup polling */
+	init_timer(&info->poll_dma_timer);
+	info->poll_dma_timer.function = (void *)&poll_rxdma;
+	info->poll_dma_timer.data = (unsigned long)info;
+
+	info->dma_initted = 1;
+}
+
 static int setup_scc(struct mac_serial * info)
 {
 	unsigned long flags;
@@ -669,6 +972,12 @@
 	info->xmit_fifo_size = 1;
 
 	/*
+	 * Reset DMAs
+	 */
+	if (info->has_dma)
+		dma_init(info);
+
+	/*
 	 * Clear the interrupt registers.
 	 */
 	write_zsreg(info->zs_channel, 0, ERR_RES);
@@ -682,7 +991,23 @@
 	/*
 	 * Finally, enable sequencing and interrupts
 	 */
-	info->curregs[1] = (info->curregs[1] & ~0x18) | (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB);
+	if (!info->dma_initted) {
+		/* interrupt on ext/status changes, all received chars,
+		   transmit ready */
+		info->curregs[1] = (info->curregs[1] & ~0x18)
+				| (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB);
+	} else {
+		/* interrupt on ext/status changes, W/Req pin is
+		   receive DMA request */
+		info->curregs[1] = (info->curregs[1] & ~(0x18 | TxINT_ENAB))
+				| (EXT_INT_ENAB | WT_RDY_RT | WT_FN_RDYFN);
+		write_zsreg(info->zs_channel, 1, info->curregs[1]);
+		/* enable W/Req pin */
+		info->curregs[1] |= WT_RDY_ENAB;
+		write_zsreg(info->zs_channel, 1, info->curregs[1]);
+		/* enable interrupts on transmit ready and receive errors */
+		info->curregs[1] |= INT_ERR_Rx | TxINT_ENAB;
+	}
 	info->pendregs[1] = info->curregs[1];
 	info->curregs[3] |= (RxENABLE | Rx8);
 	info->pendregs[3] = info->curregs[3];
@@ -708,6 +1033,14 @@
 
 	restore_flags(flags);
 
+	if (info->dma_initted) {
+		spin_lock_irqsave(&info->rx_dma_lock, flags);
+		rxdma_start(info, 0);
+		info->poll_dma_timer.expires = RX_DMA_TIMER;
+		add_timer(&info->poll_dma_timer);
+		spin_unlock_irqrestore(&info->rx_dma_lock, flags);
+	}
+
 	return 0;
 }
 
@@ -729,7 +1062,14 @@
 	
 		return;
 	}
-	
+
+	if (info->has_dma) {
+		del_timer(&info->poll_dma_timer);
+		dbdma_reset(info->tx_dma);
+		dbdma_reset(&info->rx->dma);
+		disable_irq(info->tx_dma_irq);
+		disable_irq(info->rx_dma_irq);
+	}
 	disable_irq(info->irq);
 
 	info->pendregs[1] = info->curregs[1] = 0;
@@ -755,6 +1095,12 @@
 		info->xmit_buf = 0;
 	}
 
+	if (info->has_dma && info->dma_priv) {
+		kfree(info->dma_priv);
+		info->dma_priv = NULL;
+		info->dma_initted = 0;
+	}
+
 	memset(info->curregs, 0, sizeof(info->curregs));
 	memset(info->curregs, 0, sizeof(info->pendregs));
 
@@ -1052,7 +1398,6 @@
 	if (!tty || !info->xmit_buf || !tmp_buf)
 		return 0;
 
-	save_flags(flags);
 	if (from_user) {
 		down(&tmp_buf_sem);
 		while (1) {
@@ -1068,6 +1413,7 @@
 					ret = -EFAULT;
 				break;
 			}
+			save_flags(flags);
 			cli();
 			c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
 				       SERIAL_XMIT_SIZE - info->xmit_head));
@@ -1083,6 +1429,7 @@
 		up(&tmp_buf_sem);
 	} else {
 		while (1) {
+			save_flags(flags);
 			cli();		
 			c = MIN(count,
 				MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
@@ -1104,7 +1451,6 @@
 	if (info->xmit_cnt && !tty->stopped && !info->tx_stopped
 	    && !info->tx_active)
 		transmit_chars(info);
-	restore_flags(flags);
 	return ret;
 }
 
@@ -1133,12 +1479,13 @@
 static void rs_flush_buffer(struct tty_struct *tty)
 {
 	struct mac_serial *info = (struct mac_serial *)tty->driver_data;
+	unsigned long flags;
 				
 	if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
 		return;
-	cli();
+	save_flags(flags); cli();
 	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-	sti();
+	restore_flags(flags);
 	wake_up_interruptible(&tty->write_wait);
 	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
 	    tty->ldisc.write_wakeup)
@@ -1158,7 +1505,6 @@
 	struct mac_serial *info = (struct mac_serial *)tty->driver_data;
 	unsigned long flags;
 #ifdef SERIAL_DEBUG_THROTTLE
-	char	buf[64];
 	
 	printk("throttle %ld....\n",tty->ldisc.chars_in_buffer(tty));
 #endif
@@ -1195,7 +1541,6 @@
 	struct mac_serial *info = (struct mac_serial *)tty->driver_data;
 	unsigned long flags;
 #ifdef SERIAL_DEBUG_THROTTLE
-	char	buf[64];
 	
 	printk("unthrottle %s: %d....\n",tty->ldisc.chars_in_buffer(tty));
 #endif
@@ -1473,6 +1818,7 @@
 	save_flags(flags); cli();
 	
 	if (tty_hung_up_p(filp)) {
+		MOD_DEC_USE_COUNT;
 		restore_flags(flags);
 		return;
 	}
@@ -1498,6 +1844,7 @@
 		info->count = 0;
 	}
 	if (info->count) {
+		MOD_DEC_USE_COUNT;
 		restore_flags(flags);
 		return;
 	}
@@ -1518,8 +1865,12 @@
 	printk("waiting end of Tx... (timeout:%d)\n", info->closing_wait);
 #endif
 	tty->closing = 1;
-	if (info->closing_wait != ZILOG_CLOSING_WAIT_NONE)
+	if (info->closing_wait != ZILOG_CLOSING_WAIT_NONE) {
+		restore_flags(flags);
 		tty_wait_until_sent(tty, info->closing_wait);
+		save_flags(flags); cli();
+	}
+
 	/*
 	 * At this point we stop accepting input.  To do this, we
 	 * disable the receiver and receive interrupts.
@@ -1539,7 +1890,9 @@
 #ifdef SERIAL_DEBUG_OPEN
 		printk("waiting end of Rx...\n");
 #endif
+		restore_flags(flags);
 		rs_wait_until_sent(tty, info->timeout);
+		save_flags(flags); cli();
 	}
 
 	shutdown(info);
@@ -1565,6 +1918,7 @@
 	info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE|
 			 ZILOG_CLOSING);
 	wake_up_interruptible(&info->close_wait);
+	MOD_DEC_USE_COUNT;
 }
 
 /*
@@ -1603,7 +1957,6 @@
 		char_time = MIN(char_time, timeout);
 	while ((read_zsreg(info->zs_channel, 1) & ALL_SNT) == 0) {
 		current->state = TASK_INTERRUPTIBLE;
-		current->counter = 0;	/* make us low-priority */
 		schedule_timeout(char_time);
 		if (signal_pending(current))
 			break;
@@ -1775,14 +2128,19 @@
 	int 			retval, line;
 	unsigned long		page;
 
+	MOD_INC_USE_COUNT;
 	line = MINOR(tty->device) - tty->driver.minor_start;
-	if ((line < 0) || (line >= zs_channels_found))
+	if ((line < 0) || (line >= zs_channels_found)) {
+		MOD_DEC_USE_COUNT;
 		return -ENODEV;
+	}
 	info = zs_soft + line;
 
 #ifdef CONFIG_KGDB
-	if (info->kgdb_channel)
+	if (info->kgdb_channel) {
+		MOD_DEC_USE_COUNT;
 		return -ENODEV;
+	}
 #endif
 	if (serial_paranoia_check(info, tty->device, "rs_open"))
 		return -ENODEV;
@@ -1865,7 +2223,58 @@
 
 static void show_serial_version(void)
 {
-	printk("PowerMac Z8530 serial driver version 1.01\n");
+	printk("PowerMac Z8530 serial driver version 2.0\n");
+}
+
+/*
+ * Initialize one channel, both the mac_serial and mac_zschannel
+ * structs.  We use the dev_node field of the mac_serial struct.
+ */
+static void
+chan_init(struct mac_serial *zss, struct mac_zschannel *zs_chan,
+	  struct mac_zschannel *zs_chan_a)
+{
+	struct device_node *ch = zss->dev_node;
+	char *conn;
+	int len;
+
+	zss->irq = ch->intrs[0].line;
+	zss->has_dma = 0;
+#if !defined(CONFIG_KGDB) && defined(SUPPORT_SERIAL_DMA)
+	if (ch->n_addrs == 3 && ch->n_intrs == 3)
+		zss->has_dma = 1;
+#endif
+	zss->dma_initted = 0;
+
+	zs_chan->control = (volatile unsigned char *)
+		ioremap(ch->addrs[0].address, 0x1000);
+	zs_chan->data = zs_chan->control + 0x10;
+	spin_lock_init(&zs_chan->lock);
+	zs_chan->parent = zss;
+	zss->zs_channel = zs_chan;
+	zss->zs_chan_a = zs_chan_a;
+
+	/* setup misc varariables */
+	zss->kgdb_channel = 0;
+	zss->is_cobalt_modem = device_is_compatible(ch, "cobalt");
+
+	/* XXX tested only with wallstreet PowerBook,
+	   should do no harm anyway */
+	conn = get_property(ch, "AAPL,connector", &len);
+	zss->is_pwbk_ir = conn && (strcmp(conn, "infrared") == 0);
+
+	if (zss->has_dma) {
+		zss->dma_priv = NULL;
+		/* it seems that the last two addresses are the
+		   DMA controllers */
+		zss->tx_dma = (volatile struct dbdma_regs *)
+			ioremap(ch->addrs[ch->n_addrs - 2].address, 0x100);
+		zss->rx = (volatile struct mac_dma *)
+			ioremap(ch->addrs[ch->n_addrs - 1].address, 0x100);
+		zss->tx_dma_irq = ch->intrs[1].line;
+		zss->rx_dma_irq = ch->intrs[2].line;
+		spin_lock_init(&zss->rx_dma_lock);
+	}
 }
 
 /* Ask the PROM how many Z8530s we have and initialize their zs_channels */
@@ -1874,51 +2283,63 @@
 {
 	struct device_node *dev, *ch;
 	struct mac_serial **pp;
-	int n, lenp;
-	char *conn;
+	int n, chip, nchan;
+	struct mac_zschannel *zs_chan;
+	int chan_a_index;
 
 	n = 0;
 	pp = &zs_chain;
+	zs_chan = zs_channels;
 	for (dev = find_devices("escc"); dev != 0; dev = dev->next) {
+		nchan = 0;
+		chip = n;
 		if (n >= NUM_CHANNELS) {
 			printk("Sorry, can't use %s: no more channels\n",
 			       dev->full_name);
 			continue;
 		}
+		chan_a_index = 0;
 		for (ch = dev->child; ch != 0; ch = ch->sibling) {
+			if (nchan >= 2) {
+				printk(KERN_WARNING "SCC: Only 2 channels per "
+					"chip are supported\n");
+				break;
+			}
 			if (ch->n_addrs < 1 || (ch ->n_intrs < 1)) {
 				printk("Can't use %s: %d addrs %d intrs\n",
 				      ch->full_name, ch->n_addrs, ch->n_intrs);
 				continue;
 			}
-			zs_channels[n].control = (volatile unsigned char *)
-				ioremap(ch->addrs[0].address, 0x1000);
-			zs_channels[n].data = zs_channels[n].control + 0x10;
-			spin_lock_init(&zs_channels[n].lock);
-			zs_soft[n].zs_channel = &zs_channels[n];
-			zs_soft[n].dev_node = ch;
-			zs_soft[n].irq = ch->intrs[0].line;
-			zs_soft[n].zs_channel->parent = &zs_soft[n];
-			zs_soft[n].is_cobalt_modem = device_is_compatible(ch, "cobalt");
-
-			/* XXX tested only with wallstreet PowerBook,
-			   should do no harm anyway */
-			conn = get_property(ch, "AAPL,connector", &lenp);
-			zs_soft[n].is_pwbk_ir =
-				conn && (strcmp(conn, "infrared") == 0);
-
-			/* XXX this assumes the prom puts chan A before B */
-			if (n & 1)
-				zs_soft[n].zs_chan_a = &zs_channels[n-1];
-			else
-				zs_soft[n].zs_chan_a = &zs_channels[n];
 
+			/* The channel with the higher address
+			   will be the A side. */
+			if (nchan > 0 &&
+			    ch->addrs[0].address
+			    > zs_soft[n-1].dev_node->addrs[0].address)
+				chan_a_index = 1;
+
+			/* minimal initialization for now */
+			zs_soft[n].dev_node = ch;
 			*pp = &zs_soft[n];
 			pp = &zs_soft[n].zs_next;
+			++nchan;
 			++n;
 		}
+		if (nchan == 0)
+			continue;
+
+		/* set up A side */
+		chan_init(&zs_soft[chip + chan_a_index], zs_chan, zs_chan);
+		++zs_chan;
+
+		/* set up B side, if it exists */
+		if (nchan > 1)
+			chan_init(&zs_soft[chip + 1 - chan_a_index],
+				  zs_chan, zs_chan - 1);
+		++zs_chan;
 	}
 	*pp = 0;
+
 	zs_channels_found = n;
 #ifdef CONFIG_PMAC_PBOOK
 	if (n)
@@ -1935,8 +2356,6 @@
 
 	/* Setup base handler, and timer table. */
 	init_bh(MACSERIAL_BH, do_serial_bh);
-	timer_table[RS_TIMER].fn = rs_timer;
-	timer_table[RS_TIMER].expires = 0;
 
 	/* Find out how many Z8530 SCCs we have */
 	if (zs_chain == 0)
@@ -1948,6 +2367,18 @@
 	/* Register the interrupt handler for each one */
 	save_flags(flags); cli();
 	for (i = 0; i < zs_channels_found; ++i) {
+		if (zs_soft[i].has_dma) {
+			if (request_irq(zs_soft[i].tx_dma_irq, rs_txdma_irq, 0,
+					"SCC-txdma", &zs_soft[i]))
+				printk(KERN_ERR "macserial: can't get irq %d\n",
+				       zs_soft[i].tx_dma_irq);
+			disable_irq(zs_soft[i].tx_dma_irq);
+			if (request_irq(zs_soft[i].rx_dma_irq, rs_rxdma_irq, 0,
+					"SCC-rxdma", &zs_soft[i]))
+				printk(KERN_ERR "macserial: can't get irq %d\n",
+				       zs_soft[i].rx_dma_irq);
+			disable_irq(zs_soft[i].rx_dma_irq);
+		}
 		if (request_irq(zs_soft[i].irq, rs_interrupt, 0,
 				"SCC", &zs_soft[i]))
 			printk(KERN_ERR "macserial: can't get irq %d\n",
@@ -2107,8 +2538,13 @@
 	for (info = zs_chain, i = 0; info; info = info->zs_next, i++)
 		set_scc_power(info, 0);
 	save_flags(flags); cli();
-	for (i = 0; i < zs_channels_found; ++i)
+	for (i = 0; i < zs_channels_found; ++i) {
 		free_irq(zs_soft[i].irq, &zs_soft[i]);
+		if (zs_soft[i].has_dma) {
+			free_irq(zs_soft[i].tx_dma_irq, &zs_soft[i]);
+			free_irq(zs_soft[i].rx_dma_irq, &zs_soft[i]);
+		}
+	}
 	restore_flags(flags);
 	tty_unregister_driver(&callout_driver);
 	tty_unregister_driver(&serial_driver);
@@ -2238,6 +2674,8 @@
 	if (zs_chain == 0)
 		return -1;
 
+	set_scc_power(info, 1);
+
 	/* Reset the channel */
 	write_zsreg(info->zs_channel, R9, CHRA);
 
@@ -2481,14 +2919,13 @@
 	if (zs_chain == 0)
 		probe_sccs();
 
-	set_scc_power(&zs_soft[n], 1);
+	set_scc_power(&zs_soft[tty_num], 1);
 	
 	zs_kgdbchan = zs_soft[tty_num].zs_channel;
 	zs_soft[tty_num].change_needed = 0;
 	zs_soft[tty_num].clk_divisor = 16;
 	zs_soft[tty_num].zs_baud = 38400;
 	zs_soft[tty_num].kgdb_channel = 1;     /* This runs kgdb */
-	zs_soft[tty_num ^ 1].kgdb_channel = 0; /* This does not */
 
 	/* Turn on transmitter/receiver at 8-bits/char */
         kgdb_chaninit(zs_soft[tty_num].zs_channel, 1, 38400);
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/drivers/macintosh/macserial.h linux.14p1/drivers/macintosh/macserial.h
--- linux.vanilla/drivers/macintosh/macserial.h	Wed Oct 20 01:12:38 1999
+++ linux.14p1/drivers/macintosh/macserial.h	Fri Oct 22 22:26:41 1999
@@ -92,6 +92,13 @@
 	struct mac_serial*	parent;
 };
 
+struct mac_dma {
+	volatile struct dbdma_regs	dma;
+	volatile unsigned short		res_count;
+	volatile unsigned short		command;
+	volatile unsigned int		buf_addr;
+};
+
 struct mac_serial {
 	struct mac_serial *zs_next;	/* For IRQ servicing chain */
 	struct mac_zschannel *zs_channel; /* Channel registers */
@@ -156,6 +163,28 @@
 	struct termios		callout_termios;
 	struct wait_queue	*open_wait;
 	struct wait_queue	*close_wait;
+
+	volatile struct dbdma_regs *tx_dma;
+	int			tx_dma_irq;
+	volatile struct dbdma_cmd *tx_cmds;
+	volatile struct mac_dma *rx;
+	int 			rx_dma_irq;
+	volatile struct dbdma_cmd **rx_cmds;
+	unsigned char		**rx_char_buf;
+	unsigned char		**rx_flag_buf;
+#define	RX_BUF_SIZE	256
+	int			rx_nbuf;
+	int			rx_done_bytes;
+	int			rx_ubuf;
+	int			rx_fbuf;
+#define	RX_NO_FBUF	(-1)
+	int			rx_cbuf;
+	spinlock_t		rx_dma_lock;
+	int			has_dma;
+	int			dma_initted;
+	void			*dma_priv;
+	struct timer_list	poll_dma_timer;
+#define RX_DMA_TIMER	(jiffies + 10*HZ/1000)
 };
 
 
@@ -226,9 +255,9 @@
 #define	INT_ALL_Rx	0x10	/* Int on all Rx Characters or error */
 #define	INT_ERR_Rx	0x18	/* Int on error only */
 
-#define	WT_RDY_RT	0x20	/* Wait/Ready on R/T */
-#define	WT_FN_RDYFN	0x40	/* Wait/FN/Ready FN */
-#define	WT_RDY_ENAB	0x80	/* Wait/Ready Enable */
+#define	WT_RDY_RT	0x20	/* W/Req reflects recv if 1, xmit if 0 */
+#define	WT_FN_RDYFN	0x40	/* W/Req pin is DMA request if 1, wait if 0 */
+#define	WT_RDY_ENAB	0x80	/* Enable W/Req pin */
 
 /* Write Register #2 (Interrupt Vector) */
 
@@ -286,6 +315,9 @@
 
 /* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
 
+/* Write Register 7' (Some enhanced feature control) */
+#define	ENEXREAD	0x40	/* Enable read of some write registers */
+
 /* Write Register 8 (transmit buffer) */
 
 /* Write Register 9 (Master interrupt control) */
@@ -346,7 +378,9 @@
 #define	SNRZI	0xe0	/* Set NRZI mode */
 
 /* Write Register 15 (external/status interrupt control) */
+#define	EN85C30	1	/* Enable some 85c30-enhanced registers */
 #define	ZCIE	2	/* Zero count IE */
+#define	ENSTFIFO 4	/* Enable status FIFO (SDLC) */
 #define	DCDIE	8	/* DCD IE */
 #define	SYNCIE	0x10	/* Sync/hunt IE */
 #define	CTSIE	0x20	/* CTS IE */
@@ -382,6 +416,15 @@
 #define	END_FR		0x80	/* End of Frame (SDLC) */
 
 /* Read Register 2 (channel b only) - Interrupt vector */
+#define	CHB_Tx_EMPTY	0x00
+#define	CHB_EXT_STAT	0x02
+#define	CHB_Rx_AVAIL	0x04
+#define	CHB_SPECIAL	0x06
+#define	CHA_Tx_EMPTY	0x08
+#define	CHA_EXT_STAT	0x0a
+#define	CHA_Rx_AVAIL	0x0c
+#define	CHA_SPECIAL	0x0e
+#define	STATUS_MASK	0x06
 
 /* Read Register 3 (interrupt pending register) ch a only */
 #define	CHBEXT	0x1		/* Channel B Ext/Stat IP */
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/drivers/macintosh/mediabay.c linux.14p1/drivers/macintosh/mediabay.c
--- linux.vanilla/drivers/macintosh/mediabay.c	Wed Oct 20 01:12:38 1999
+++ linux.14p1/drivers/macintosh/mediabay.c	Fri Oct 22 22:26:41 1999
@@ -94,6 +94,12 @@
  */
 #define MB_IDE_WAIT	1500
 
+/*
+ * Wait at least this many ticks after resetting an IDE device before
+ * believing its ready bit.
+ */
+#define MB_IDE_MINWAIT	250
+
 static void poll_media_bay(int which);
 static void set_media_bay(int which, int id);
 static int media_bay_task(void *);
@@ -285,7 +291,10 @@
 #endif
 			}
 #ifdef CONFIG_BLK_DEV_IDE
-		} else if (bay->cd_timer && (--bay->cd_timer == 0 || MB_IDE_READY(i))
+		} else if (bay->cd_timer
+			   && (--bay->cd_timer == 0
+			       || (bay->cd_timer < MB_IDE_WAIT - MB_IDE_MINWAIT
+				   && MB_IDE_READY(i)))
 			   && bay->cd_index < 0) {
 			bay->cd_timer = 0;
 			printk(KERN_DEBUG "Registering IDE, base:0x%08lx, irq:%d\n", bay->cd_base, bay->cd_irq);
@@ -299,11 +308,13 @@
 		}
 
 		bay->previous_id = bay->content_id;
-		current->state = TASK_INTERRUPTIBLE;
-		schedule_timeout(1);
-		if (signal_pending(current))
-			return 0;
-		i = (i+1)%media_bay_count;
+		if (++i >= media_bay_count) {
+			i = 0;
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout(1);
+			if (signal_pending(current))
+				return 0;
+		}
 	}
 }
 
@@ -405,25 +416,25 @@
 			feature_set(bay->dev_node, FEATURE_Mediabay_enable);
 			/* I suppose this is enough delay to stabilize MB_CONTENT ... */
 			mdelay(10);
-			/* We re-enable the bay using it's previous content only if
-			   it did not change */
-			if (MB_CONTENTS(i) == bay->content_id) {
-				set_media_bay(i, bay->content_id);
-				if (bay->content_id != MB_NO) {
-					mdelay(400);
-					/* Clear the bay reset */
-					feature_clear(bay->dev_node, FEATURE_Mediabay_reset);
-					/* This small delay makes sure the device has time
-					   to assert the BUSY bit (used by IDE sleep) */
-					udelay(100);
-					/* We reset the state machine timers in case we were in the
-					   middle of a wait loop */
-					if (bay->reset_timer)
-						bay->reset_timer = MB_RESET_COUNT;
-					if (bay->cd_timer)
-						bay->cd_timer = MB_IDE_WAIT;
-				}
-			}
+			/* We re-enable the bay using it's previous content
+			   only if it did not change */
+			if (MB_CONTENTS(i) != bay->content_id)
+				continue;
+			set_media_bay(i, bay->content_id);
+			if (bay->content_id == MB_NO)
+				continue;
+			mdelay(400);
+			/* Clear the bay reset */
+			feature_clear(bay->dev_node, FEATURE_Mediabay_reset);
+			/* This small delay makes sure the device has time
+			   to assert the BUSY bit (used by IDE sleep) */
+			udelay(100);
+			/* We reset the state machine timers in case we were
+			   in the middle of a wait loop */
+			if (bay->reset_timer)
+				bay->reset_timer = MB_RESET_COUNT;
+			if (bay->cd_timer)
+				bay->cd_timer = MB_IDE_WAIT;
 		}
 		break;
 	}
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/drivers/net/Config.in linux.14p1/drivers/net/Config.in
--- linux.vanilla/drivers/net/Config.in	Wed Oct 20 01:12:38 1999
+++ linux.14p1/drivers/net/Config.in	Fri Oct 22 22:16:43 1999
@@ -165,7 +165,9 @@
 fi
 
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  bool 'HIPPI driver support (EXPERIMENTAL)' CONFIG_HIPPI
+  if [ "$CONFIG_INET" = "y" ]; then
+    bool 'HIPPI driver support (EXPERIMENTAL)' CONFIG_HIPPI
+  fi
   if [ "$CONFIG_HIPPI" = "y" ]; then
     tristate 'Essential RoadRunner HIPPI PCI adapter support' CONFIG_ROADRUNNER
     if [ "$CONFIG_ROADRUNNER" != "n" ]; then
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/drivers/net/arlan-proc.c linux.14p1/drivers/net/arlan-proc.c
--- linux.vanilla/drivers/net/arlan-proc.c	Sat Aug 14 02:27:28 1999
+++ linux.14p1/drivers/net/arlan-proc.c	Fri Oct 22 22:16:55 1999
@@ -1,11 +1,11 @@
 #include <linux/config.h>
 #include "arlan.h"
+#include <linux/sysctl.h>
+#include <linux/version.h>
 
 #ifdef CONFIG_PROC_FS
 
 
-#include <linux/sysctl.h>
-#include <linux/version.h>
 
 /* void enableReceive(struct device* dev);
 */
@@ -1001,6 +1001,11 @@
 	{0}
 };
 #endif
+#else
+static ctl_table arlan_table[MAX_ARLANS + 1] =
+{
+	{0}
+};
 #endif
 
 static int mmtu = 1234;
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/drivers/net/hamradio/Config.in linux.14p1/drivers/net/hamradio/Config.in
--- linux.vanilla/drivers/net/hamradio/Config.in	Sat Aug 14 02:27:29 1999
+++ linux.14p1/drivers/net/hamradio/Config.in	Fri Oct 22 22:17:18 1999
@@ -29,4 +29,4 @@
   bool '   soundmodem support for 9600 baud FSK G3RUH modulation' CONFIG_SOUNDMODEM_FSK9600
 fi
 
-tristate 'YAM driver for AX.25' CONFIG_YAM
+dep_tristate 'YAM driver for AX.25' CONFIG_YAM $CONFIG_AX25
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/drivers/net/pcnet32.c linux.14p1/drivers/net/pcnet32.c
--- linux.vanilla/drivers/net/pcnet32.c	Wed Oct 20 01:12:39 1999
+++ linux.14p1/drivers/net/pcnet32.c	Fri Oct 22 21:24:24 1999
@@ -13,7 +13,7 @@
  * 	This driver is for PCnet32 and PCnetPCI based ethercards
  */
 
-static const char *version = "pcnet32.c:v1.23 6.7.1999 tsbogend@alpha.franken.de\n";
+static const char *version = "pcnet32.c:v1.25kf 26.9.1999 tsbogend@alpha.franken.de\n";
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -39,16 +39,18 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
+#include <asm/spinlock.h>
 
 static unsigned int pcnet32_portlist[] __initdata = {0x300, 0x320, 0x340, 0x360, 0};
 
 static int pcnet32_debug = 1;
+static int tx_start = 1; /* Mapping -- 0:20, 1:64, 2:128, 3:~220 (depends on chip vers) */
 
 #ifdef MODULE
 static struct device *pcnet32_dev = NULL;
 #endif
 
-static const int max_interrupt_work = 20;
+static const int max_interrupt_work = 80;
 static const int rx_copybreak = 200;
 
 #define PORT_AUI      0x00
@@ -156,6 +158,12 @@
  *	   Michael Richard <mcr@solidum.com>)
  *         added chip id for 79c973/975 (thanks to Zach Brown <zab@zabbo.net>)
  * v1.23   fixed small bug, when manual selecting MII speed/duplex
+ * v1.24   Applied Thomas' patch to use TxStartPoint and thus decrease TxFIFO
+ *         underflows.  Added tx_start_pt module parameter. Increased
+ *         TX_RING_SIZE from 16 to 32.  Added #ifdef'd code to use DXSUFLO
+ *         for FAST[+] chipsets. <kaf@fc.hp.com>
+ * v1.24ac Added SMP spinlocking - Alan Cox <alan@redhat.com>
+ * v1.25kf Added No Interrupt on successful Tx for some Tx's <kaf@fc.hp.com>
  */
 
 
@@ -166,7 +174,7 @@
  */
 #ifndef PCNET32_LOG_TX_BUFFERS
 #define PCNET32_LOG_TX_BUFFERS 4
-#define PCNET32_LOG_RX_BUFFERS 4
+#define PCNET32_LOG_RX_BUFFERS 5
 #endif
 
 #define TX_RING_SIZE			(1 << (PCNET32_LOG_TX_BUFFERS))
@@ -255,12 +263,17 @@
     struct sk_buff *rx_skbuff[RX_RING_SIZE];
     struct pcnet32_access a;
     void *origmem;
-    int cur_rx, cur_tx;			/* The next free ring entry */
-    int dirty_rx, dirty_tx;		        /* The ring entries to be free()ed. */
+    spinlock_t lock;				/* Guard lock */
+    unsigned int cur_rx, cur_tx;		/* The next free ring entry */
+    unsigned int dirty_rx, dirty_tx;		/* The ring entries to be free()ed. */
     struct net_device_stats stats;
     char tx_full;
     int  options;
     int  shared_irq:1,                      /* shared irq possible */
+	 ltint:1,
+#ifdef DO_DXSUFLO
+	 dxsuflo:1,			    /* disable transmit stop on uflo */
+#endif
          full_duplex:1,                     /* full duplex possible */
          mii:1;                             /* mii port available */
 #ifdef MODULE
@@ -299,6 +312,10 @@
 	PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, 0, 0,
 	PCI_USES_IO|PCI_USES_MASTER, PCNET32_TOTAL_SIZE,
 	pcnet32_probe1},
+    { "AMD PCnetPCI series (IBM)",
+	PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, 0x1014, 0x2000,
+	PCI_USES_IO|PCI_USES_MASTER, PCNET32_TOTAL_SIZE,
+	pcnet32_probe1},
     { "AMD PCnetHome series",
 	PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_PCNETHOME, 0, 0,
 	PCI_USES_IO|PCI_USES_MASTER, PCNET32_TOTAL_SIZE,
@@ -448,8 +465,8 @@
 	    int chip_idx;
 	    u16 sdid,svid;
 
-	    pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &sdid);
-	    pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &svid);
+	    pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &svid);
+	    pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &sdid);
 	    for (chip_idx = 0; pcnet32_tbl[chip_idx].vendor_id; chip_idx++)
 		if ((pdev->vendor == pcnet32_tbl[chip_idx].vendor_id) &&
 		    (pdev->device == pcnet32_tbl[chip_idx].device_id) &&
@@ -514,6 +531,10 @@
 {
     struct pcnet32_private *lp;
     int i,media,fdx = 0, mii = 0;
+#ifdef DO_DXSUFLO
+    int dxsuflo = 0;
+#endif
+    int ltint = 0;
     int chip_version;
     char *chipname;
     char *priv;
@@ -532,12 +553,14 @@
 	    return ENODEV;
     }
 
+
     chip_version = a->read_csr (ioaddr, 88) | (a->read_csr (ioaddr,89) << 16);
     if (pcnet32_debug > 2)
 	printk("  PCnet chip version is %#x.\n", chip_version);
     if ((chip_version & 0xfff) != 0x003)
 	return ENODEV;
     chip_version = (chip_version >> 12) & 0xffff;
+
     switch (chip_version) {
      case 0x2420:
 	chipname = "PCnet/PCI 79C970";
@@ -554,11 +577,33 @@
 	break;
      case 0x2623:
 	chipname = "PCnet/FAST 79C971";
+	/* To prevent Tx FIFO underflows ... (may increase Tx latency) */
+	/* Set BCR18:NOUFLO to not start Tx until reach Tx start point */
+	/* Looks like EEPROM sets BCR18:5/6 for BurstWrite/Read */
+        a->write_bcr(ioaddr, 18, (a->read_bcr(ioaddr, 18) | 0x0800));
+	/* Set CSR80:XMTSP, Tx start point = 20|64|128|248 bytes or size of frame */
+        i = a->read_csr(ioaddr, 80) & ~0x0C00; /* Clear bits we are touching */
+        a->write_csr(ioaddr, 80, i | (tx_start << 10));
 	fdx = 1; mii = 1;
+#ifdef DO_DXSUFLO
+	dxsuflo = 1;
+#endif
+	ltint = 1;
 	break;
      case 0x2624:
 	chipname = "PCnet/FAST+ 79C972";
+	/* To prevent Tx FIFO underflows ... (may increase Tx latency) */
+	/* Set BCR18:NOUFLO to not start Tx until reach Tx start point */
+	/* Looks like EEPROM sets BCR18:5/6 for BurstWrite/Read */
+        a->write_bcr(ioaddr, 18, (a->read_bcr(ioaddr, 18) | 0x0800));
+	/* Set CSR80:XMTSP, Tx start point = 20|64|128|220 bytes or size of frame */
+        i = a->read_csr(ioaddr, 80) & ~0x0C00; /* Clear bits we are touching */
+        a->write_csr(ioaddr, 80, i | (tx_start << 10));
 	fdx = 1; mii = 1;
+#ifdef DO_DXSUFLO
+	dxsuflo = 1;
+#endif
+	ltint = 1;
 	break;
      case 0x2625:
 	chipname = "PCnet/FAST III 79C973";
@@ -602,6 +647,29 @@
     for (i = 0; i < 6; i++)
       printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i));
 
+    if (((chip_version + 1) & 0xfffe) == 0x2624) { /* Version 0x2623 or 0x2624 */
+        i = a->read_csr(ioaddr, 80) & 0x0C00;  /* Check tx_start_pt */
+	printk("\n    tx_start_pt(0x%04x):",i);
+	switch(i>>10) {
+	    case 0: printk("  20 bytes,"); break;
+	    case 1: printk("  64 bytes,"); break;
+	    case 2: printk(" 128 bytes,"); break;
+	    case 3: printk("~220 bytes,"); break;
+	}
+        i = a->read_bcr(ioaddr, 18);  /* Check Burst/Bus control */
+        printk(" BCR18(%x):",i&0xffff);
+	if (i & (1<<5)) printk("BurstWrEn ");
+	if (i & (1<<6)) printk("BurstRdEn ");
+	if (i & (1<<7)) printk("DWordIO ");
+	if (i & (1<<11)) printk("NoUFlow ");
+        i = a->read_bcr(ioaddr, 25);
+        printk("\n    SRAMSIZE=0x%04x,",i<<8);
+        i = a->read_bcr(ioaddr, 26);
+        printk(" SRAM_BND=0x%04x,",i<<8);
+        i = a->read_bcr(ioaddr, 27);
+	if (i & (1<<14)) printk("LowLatRx,");
+    }
+
     dev->base_addr = ioaddr;
     request_region(ioaddr, PCNET32_TOTAL_SIZE, chipname);
     
@@ -615,10 +683,17 @@
     lp = (struct pcnet32_private *)(((unsigned long)priv+15) & ~15);
       
     memset(lp, 0, sizeof(*lp));
+    
+    spin_lock_init(&lp->lock);
+    
     dev->priv = lp;
     lp->name = chipname;
     lp->shared_irq = shared;
     lp->full_duplex = fdx;
+#ifdef DO_DXSUFLO
+    lp->dxsuflo = dxsuflo;
+#endif
+    lp->ltint = ltint;
     lp->mii = mii;
     if (options[card_idx] > sizeof (options_mapping))
 	lp->options = PORT_ASEL;
@@ -746,7 +821,7 @@
 	lp->a.write_bcr (ioaddr, 9, val);
     }
     
-    /* set/reset GPSI bit in test register */
+    /* NOOP ??? set/reset GPSI bit in test register */
     val = lp->a.read_csr (ioaddr, 124) & ~0x10;
     if ((lp->options & PORT_PORTSEL) == PORT_GPSI)
 	val |= 0x10;
@@ -760,6 +835,19 @@
 	    val |= 0x08;
 	lp->a.write_bcr (ioaddr, 32, val);
     }
+
+#ifdef DO_DXSUFLO 
+    if (lp->dxsuflo) { /* Disable transmit stop on underflow */
+        val = lp->a.read_csr (ioaddr, 3);
+	val |= 0x40;
+        lp->a.write_csr (ioaddr, 3, val);
+    }
+#endif
+    if (lp->ltint) { /* Enable TxDone-intr inhibitor */
+        val = lp->a.read_csr (ioaddr, 5);
+	val |= (1<<14);
+        lp->a.write_csr (ioaddr, 5, val);
+    }
     
     lp->init_block.mode = le16_to_cpu((lp->options & PORT_PORTSEL) << 7);
     lp->init_block.filter[0] = 0x00000000;
@@ -890,6 +978,7 @@
 {
     struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
     unsigned int ioaddr = dev->base_addr;
+    u16 status;
     int entry;
     unsigned long flags;
 
@@ -937,8 +1026,23 @@
 	return 1;
     }
 
-    save_flags (flags);
-    cli ();
+    spin_lock_irqsave(&lp->lock, flags);
+
+    /* Default status -- will not enable Successful-TxDone
+     * interrupt when that option is available to us.
+     */
+    status = 0x8300;
+    if ((lp->ltint) &&
+	((lp->cur_tx - lp->dirty_tx == TX_RING_SIZE/2) ||
+	 (lp->cur_tx - lp->dirty_tx >= TX_RING_SIZE-2)))
+    {
+	/* Enable Successful-TxDone interrupt if we have
+	 * 1/2 of, or nearly all of, our ring buffer Tx'd
+	 * but not yet cleaned up.  Thus, most of the time,
+	 * we will not enable Successful-TxDone interrupts.
+	 */
+	status = 0x9300;
+    }
 
     /* Fill in a Tx ring entry */
 
@@ -954,7 +1058,8 @@
 
     lp->tx_skbuff[entry] = skb;
     lp->tx_ring[entry].base = (u32)le32_to_cpu(virt_to_bus(skb->data));
-    lp->tx_ring[entry].status = le16_to_cpu(0x8300);
+
+    lp->tx_ring[entry].status = le16_to_cpu(status);
 
     lp->cur_tx++;
     lp->stats.tx_bytes += skb->len;
@@ -968,7 +1073,7 @@
 	clear_bit (0, (void *)&dev->tbusy);
     else
 	lp->tx_full = 1;
-    restore_flags(flags);
+    spin_unlock_irqrestore(&lp->lock, flags);
     return 0;
 }
 
@@ -990,6 +1095,9 @@
 
     ioaddr = dev->base_addr;
     lp = (struct pcnet32_private *)dev->priv;
+
+    spin_lock(&lp->lock);
+
     if (dev->interrupt)
 	printk("%s: Re-entering the interrupt handler.\n", dev->name);
 
@@ -1010,7 +1118,7 @@
 	    pcnet32_rx(dev);
 
 	if (csr0 & 0x0200) {		/* Tx-done interrupt */
-	    int dirty_tx = lp->dirty_tx;
+	    unsigned int dirty_tx = lp->dirty_tx;
 
 	    while (dirty_tx < lp->cur_tx) {
 		int entry = dirty_tx & TX_RING_MOD_MASK;
@@ -1028,14 +1136,27 @@
 		    if (err_status & 0x04000000) lp->stats.tx_aborted_errors++;
 		    if (err_status & 0x08000000) lp->stats.tx_carrier_errors++;
 		    if (err_status & 0x10000000) lp->stats.tx_window_errors++;
+#ifndef DO_DXSUFLO
 		    if (err_status & 0x40000000) {
-			/* Ackk!  On FIFO errors the Tx unit is turned off! */
 			lp->stats.tx_fifo_errors++;
+			/* Ackk!  On FIFO errors the Tx unit is turned off! */
 			/* Remove this verbosity later! */
-			printk("%s: Tx FIFO error! Status %4.4x.\n",
-			       dev->name, csr0);
+			printk("%s: Tx FIFO error! CSR0=%4.4x\n",
+					    dev->name, csr0);
 			must_restart = 1;
 					}
+#else
+		    if (err_status & 0x40000000) {
+			lp->stats.tx_fifo_errors++;
+			if (! lp->dxsuflo) {  /* If controller doesn't recover ... */
+			    /* Ackk!  On FIFO errors the Tx unit is turned off! */
+			    /* Remove this verbosity later! */
+			    printk("%s: Tx FIFO error! CSR0=%4.4x\n",
+					   	dev->name, csr0);
+			    must_restart = 1;
+			}
+		    }
+#endif
 		} else {
 		    if (status & 0x1800)
 			lp->stats.collisions++;
@@ -1104,6 +1225,8 @@
 	       dev->name, lp->a.read_csr (ioaddr, 0));
 
     dev->interrupt = 0;
+
+    spin_unlock(&lp->lock);
     return;
 }
 
@@ -1252,12 +1375,11 @@
     u16 saved_addr;
     unsigned long flags;
 
-    save_flags(flags);
-    cli();
+    spin_lock_irqsave(&lp->lock, flags);
     saved_addr = lp->a.read_rap(ioaddr);
     lp->stats.rx_missed_errors = lp->a.read_csr (ioaddr, 112);
     lp->a.write_rap(ioaddr, saved_addr);
-    restore_flags(flags);
+    spin_unlock_irqrestore(&lp->lock, flags);
 
     return &lp->stats;
 }
@@ -1371,18 +1493,22 @@
 MODULE_PARM(debug, "i");
 MODULE_PARM(max_interrupt_work, "i");
 MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(tx_start_pt, "i");
 MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
 					     
 
 /* An additional parameter that may be passed in... */
 static int debug = -1;
+static int tx_start_pt = -1;
 
 int
 init_module(void)
 {
     if (debug > 0)
 	pcnet32_debug = debug;
+    if ((tx_start_pt >= 0) && (tx_start_pt <= 3))
+	tx_start = tx_start_pt;
     
     pcnet32_dev = NULL;
     return pcnet32_probe(NULL);
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/drivers/net/sis900.c linux.14p1/drivers/net/sis900.c
--- linux.vanilla/drivers/net/sis900.c	Wed Oct 20 01:12:39 1999
+++ linux.14p1/drivers/net/sis900.c	Fri Oct 22 22:25:35 1999
@@ -1,58 +1,28 @@
-/*****************************************************************************/
-/*      sis900.c: A SiS 900 PCI Fast Ethernet driver for Linux.              */
-/*                                                                           */
-/*                Silicon Integrated System Corporation                      */ 
-/*                Revision:	1.05	Aug 7 1999                           */
-/*                                                                           */
-/*****************************************************************************/
-
-/*                                                                            
-      Modified from the driver which is originally written by Donald Becker. 
-
-      This software may be used and distributed according to the terms
-      of the GNU Public License (GPL), incorporated herein by reference.
-      Drivers based on this skeleton fall under the GPL and must retain
-      the authorship (implicit copyright) notice.
-
-      The author may be reached as becker@tidalwave.net, or
-      Donald Becker
-      312 Severn Ave. #W302
-      Annapolis MD 21403
-
-      Support and updates [to the original skeleton] available at
-      http://www.tidalwave.net/~becker/pci-skeleton.html
+/* sis900.c: A SiS 900/7016 PCI Fast Ethernet driver for Linux.
+   Silicon Integrated System Corporation 
+   Revision:	1.05	Aug 7 1999
+   
+   Modified from the driver which is originally written by Donald Becker. 
+   
+   This software may be used and distributed according to the terms
+   of the GNU Public License (GPL), incorporated herein by reference.
+   Drivers based on this skeleton fall under the GPL and must retain
+   the authorship (implicit copyright) notice.
+   
+   References:
+   SiS 7016 Fast Ethernet PCI Bus 10/100 Mbps LAN Controller with OnNow Support,
+   preliminary Rev. 1.0 Jan. 14, 1998
+   SiS 900 Fast Ethernet PCI Bus 10/100 Mbps LAN Single Chip with OnNow Support,
+   preliminary Rev. 1.0 Nov. 10, 1998
+   SiS 7014 Single Chip 100BASE-TX/10BASE-T Physical Layer Solution,
+   preliminary Rev. 1.0 Jan. 18, 1998
+   http://www.sis.com.tw/support/databook.htm
+   
+   Ollie Lho (ollie@sis.com.tw) 
+   Chin-Shan Li (lcs@sis.com.tw) Added AMD Am79c901 HomePNA PHY support
+   Rev 1.05 Aug. 7 1999 Jim Huang (cmhuang@sis.com.tw) Initial release
 */
 
-static const char *version =
-"sis900.c:v1.05  8/07/99\n";
-
-static int max_interrupt_work = 20;
-#define sis900_debug debug
-static int sis900_debug = 0;
-
-static int multicast_filter_limit = 128;
-
-#define MAX_UNITS 8             /* More are supported, limit only on options */
-static int speeds[MAX_UNITS] = {100, 100, 100, 100, 100, 100, 100, 100};
-static int full_duplex[MAX_UNITS] = {1, 1, 1, 1, 1, 1, 1, 1};
-
-#define TX_BUF_SIZE     1536
-#define RX_BUF_SIZE     1536
-
-#define TX_DMA_BURST    0
-#define RX_DMA_BURST    0
-#define TX_FIFO_THRESH  16
-#define TxDRNT_100      (1536>>5)
-#define TxDRNT_10       16 
-#define RxDRNT_100      8
-#define RxDRNT_10       8 
-#define TRUE            1
-#define FALSE           0
-
-/* Operational parameters that usually are not changed. */
-/* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT  (4*HZ)
-
 #include <linux/module.h>
 #include <linux/version.h>
 #include <linux/kernel.h>
@@ -70,293 +40,59 @@
 #include <asm/processor.h>      /* Processor type for cache alignment. */
 #include <asm/bitops.h>
 #include <asm/io.h>
-
-#define RUN_AT(x) (jiffies + (x))
-
 #include <linux/delay.h>
 
-#if LINUX_VERSION_CODE < 0x20123
-#define test_and_set_bit(val, addr) set_bit(val, addr)
-#endif
-#if LINUX_VERSION_CODE <= 0x20139
-#define net_device_stats enet_statistics
-#else
-#define NETSTATS_VER2
-#endif
-#if LINUX_VERSION_CODE < 0x20155  ||  defined(CARDBUS)
-/* Grrrr, the PCI code changed, but did not consider CardBus... */
-#include <linux/bios32.h>
-#define PCI_SUPPORT_VER1
-#else
-#define PCI_SUPPORT_VER2
-#endif
-#if LINUX_VERSION_CODE < 0x20159
-#define dev_free_skb(skb) dev_kfree_skb(skb, FREE_WRITE);
-#else
-#define dev_free_skb(skb) dev_kfree_skb(skb);
-#endif
+#include "sis900.h"
 
-/* The I/O extent. */
-#define SIS900_TOTAL_SIZE 0x100
+static const char *version =
+"sis900.c:v1.05  8/07/99\n";
 
-/* This table drives the PCI probe routines.  It's mostly boilerplate in all
-   of the drivers, and will likely be provided by some future kernel.
-   Note the matching code -- the first table entry matchs all 56** cards but
-   second only the 1234 card.
-*/
+static int max_interrupt_work = 20;
+#define sis900_debug debug
+static int sis900_debug = 0;
 
-enum pci_flags_bit {
-        PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
-};
+static int multicast_filter_limit = 128;
+
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT  (4*HZ)
 
-struct pci_id_info {
+struct mac_chip_info {
         const char *name;
-        u16     vendor_id, device_id, device_id_mask, flags;
-        int io_size;
-        struct device *(*probe1)(int pci_bus, int pci_devfn, struct device *dev,
-                         long ioaddr, int irq, int chip_idx, int fnd_cnt);
+        u16 	vendor_id, device_id, flags;
+        int 	io_size;
+        struct device *(*probe) (struct mac_chip_info *mac, struct pci_dev * pci_dev, 
+				 struct device * net_dev);
 };
+static struct device * sis900_mac_probe (struct mac_chip_info * mac, struct pci_dev * pci_dev,
+					 struct device * net_dev);
 
-static struct device * sis900_probe1(int pci_bus, int pci_devfn,
-                                  struct device *dev, long ioaddr,
-                                  int irq, int chp_idx, int fnd_cnt);
-
-static struct pci_id_info pci_tbl[] =
-{{ "SiS 900 PCI Fast Ethernet",
-   0x1039, 0x0900, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x100, sis900_probe1},
-  { "SiS 7016 PCI Fast Ethernet",
-   0x1039, 0x7016, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x100, sis900_probe1},
- {0,},                                          /* 0 terminated list. */
+static struct mac_chip_info  mac_chip_table[] = {
+	{ "SiS 900 PCI Fast Ethernet", PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_900,
+	  PCI_COMMAND_IO|PCI_COMMAND_MASTER, SIS900_TOTAL_SIZE, sis900_mac_probe},
+	{ "SiS 7016 PCI Fast Ethernet",PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7016,
+	  PCI_COMMAND_IO|PCI_COMMAND_MASTER, SIS900_TOTAL_SIZE, sis900_mac_probe},
+	{0,},                                          /* 0 terminated list. */
 };
 
-/* The capability table matches the chip table above. */
-enum {HAS_MII_XCVR=0x01, HAS_CHIP_XCVR=0x02, HAS_LNK_CHNG=0x04};
-static int sis_cap_tbl[] = {
-        HAS_MII_XCVR|HAS_CHIP_XCVR|HAS_LNK_CHNG,
-        HAS_MII_XCVR|HAS_CHIP_XCVR|HAS_LNK_CHNG,
+static struct mii_chip_info {
+	const char * name;
+	u16 phy_id0;
+	u16 phy_id1;
+} mii_chip_table[] = {
+	{"SiS 900 Internal MII PHY", 0x001d, 0x8000},
+	{"SiS 7014 Physical Layer Solution", 0x0016, 0xf830},
+	{"AMD 79C901 10BASE-T PHY", 0x0000, 0x35b9},
+	{"AMD 79C901 HomePNA PHY",  0x0000, 0x35c8},
+	{0,},
 };
 
-/* The rest of these values should never change. */
-#define NUM_TX_DESC     16      /* Number of Tx descriptor registers. */
-#define NUM_RX_DESC     8       /* Number of Rx descriptor registers. */
-
-/* Symbolic offsets to registers. */
-enum SIS900_registers {
-        cr=0x0,                 //Command Register
-        cfg=0x4,                //Configuration Register
-        mear=0x8,               //EEPROM Access Register
-        ptscr=0xc,              //PCI Test Control Register
-        isr=0x10,               //Interrupt Status Register
-        imr=0x14,               //Interrupt Mask Register
-        ier=0x18,               //Interrupt Enable Register
-        epar=0x18,              //Enhanced PHY Access Register
-        txdp=0x20,              //Transmit Descriptor Pointer Register
-        txcfg=0x24,             //Transmit Configuration Register
-        rxdp=0x30,              //Receive Descriptor Pointer Register
-        rxcfg=0x34,             //Receive Configuration Register
-        flctrl=0x38,            //Flow Control Register
-        rxlen=0x3c,             //Receive Packet Length Register
-        rfcr=0x48,              //Receive Filter Control Register
-        rfdr=0x4C,              //Receive Filter Data Register
-        pmctrl=0xB0,            //Power Management Control Register
-        pmer=0xB4               //Power Management Wake-up Event Register
+struct mii_phy {
+	struct mii_phy * next;
+	struct mii_chip_info * chip_info;
+	int phy_addr;
+	u16 status;
 };
 
-#define RESET           0x00000100
-#define SWI             0x00000080
-#define RxRESET         0x00000020
-#define TxRESET         0x00000010
-#define RxDIS           0x00000008
-#define RxENA           0x00000004
-#define TxDIS           0x00000002
-#define TxENA           0x00000001
-
-#define BISE            0x80000000
-#define EUPHCOM         0x00000100
-#define REQALG          0x00000080
-#define SB              0x00000040
-#define POW             0x00000020
-#define EXD             0x00000010
-#define PESEL           0x00000008
-#define LPM             0x00000004
-#define BEM             0x00000001
-
-/* Interrupt register bits, using my own meaningful names. */
-#define WKEVT           0x10000000
-#define TxPAUSEEND      0x08000000
-#define TxPAUSE         0x04000000
-#define TxRCMP          0x02000000
-#define RxRCMP          0x01000000
-#define DPERR           0x00800000
-#define SSERR           0x00400000
-#define RMABT           0x00200000
-#define RTABT           0x00100000
-#define RxSOVR          0x00010000
-#define HIBERR          0x00008000
-#define SWINT           0x00001000
-#define MIBINT          0x00000800
-#define TxURN           0x00000400
-#define TxIDLE          0x00000200
-#define TxERR           0x00000100
-#define TxDESC          0x00000080
-#define TxOK            0x00000040
-#define RxORN           0x00000020
-#define RxIDLE          0x00000010
-#define RxEARLY         0x00000008
-#define RxERR           0x00000004
-#define RxDESC          0x00000002
-#define RxOK            0x00000001
-
-#define IE              0x00000001
-
-#define TxCSI           0x80000000
-#define TxHBI           0x40000000
-#define TxMLB           0x20000000
-#define TxATP           0x10000000
-#define TxIFG           0x0C000000
-#define TxMXF           0x03800000
-#define TxMXF_shift     0x23
-#define TxMXDMA         0x00700000
-#define TxMXDMA_shift   20
-#define TxRTCNT         0x000F0000
-#define TxRTCNT_shift   16
-#define TxFILLT         0x00007F00
-#define TxFILLT_shift   8
-#define TxDRNT          0x0000007F
-
-#define RxAEP           0x80000000
-#define RxARP           0x40000000
-#define RxATP           0x10000000
-#define RxAJAB          0x08000000
-#define RxMXF           0x03800000
-#define RxMXF_shift     23
-#define RxMXDMA         0x00700000
-#define RxMXDMA_shift   20
-#define RxDRNT          0x0000007F
-
-#define RFEN            0x80000000
-#define RFAAB           0x40000000
-#define RFAAM           0x20000000
-#define RFAAP           0x10000000
-#define RFPromiscuous   (RFAAB|RFAAM|RFAAP)
-#define RFAA_shift      28
-#define RFEP            0x00070000
-#define RFEP_shift      16
-
-#define RFDAT           0x0000FFFF
-
-#define OWN             0x80000000
-#define MORE            0x40000000
-#define INTR            0x20000000
-#define OK              0x08000000
-#define DSIZE           0x00000FFF
-
-#define SUPCRC          0x10000000
-#define ABORT           0x04000000
-#define UNDERRUN        0x02000000
-#define NOCARRIER       0x01000000
-#define DEFERD          0x00800000
-#define EXCDEFER        0x00400000
-#define OWCOLL          0x00200000
-#define EXCCOLL         0x00100000
-#define COLCNT          0x000F0000
-
-#define INCCRC          0x10000000
-//      ABORT           0x04000000
-#define OVERRUN         0x02000000
-#define DEST            0x01800000
-#define BCAST           0x01800000
-#define MCAST           0x01000000
-#define UNIMATCH        0x00800000
-#define TOOLONG         0x00400000
-#define RUNT            0x00200000
-#define RXISERR         0x00100000
-#define CRCERR          0x00080000
-#define FAERR           0x00040000
-#define LOOPBK          0x00020000
-#define RXCOL           0x00010000
-
-#define EuphLiteEEMACAddr               0x08
-#define EuphLiteEEVendorID              0x02
-#define EuphLiteEEDeviceID              0x03
-#define EuphLiteEECardTypeRev           0x0b
-#define EuphLiteEEPlexusRev             0x0c
-#define EuphLiteEEChecksum              0x0f
-
-#define RXSTS_shift     18
-#define OWN             0x80000000
-#define MORE            0x40000000
-#define INTR            0x20000000
-#define OK              0x08000000
-#define DSIZE           0x00000FFF
-/* MII register offsets */
-#define MII_CONTROL             0x0000
-#define MII_STATUS              0x0001
-#define MII_PHY_ID0             0x0002
-#define MII_PHY_ID1             0x0003
-#define MII_ANAR                0x0004
-#define MII_ANLPAR              0x0005
-#define MII_ANER                0x0006
-/* MII Control register bit definitions. */
-#define MIICNTL_FDX             0x0100
-#define MIICNTL_RST_AUTO        0x0200
-#define MIICNTL_ISOLATE         0x0400
-#define MIICNTL_PWRDWN          0x0800
-#define MIICNTL_AUTO            0x1000
-#define MIICNTL_SPEED           0x2000
-#define MIICNTL_LPBK            0x4000
-#define MIICNTL_RESET           0x8000
-/* MII Status register bit significance. */
-#define MIISTAT_EXT             0x0001
-#define MIISTAT_JAB             0x0002
-#define MIISTAT_LINK            0x0004
-#define MIISTAT_CAN_AUTO        0x0008
-#define MIISTAT_FAULT           0x0010
-#define MIISTAT_AUTO_DONE       0x0020
-#define MIISTAT_CAN_T           0x0800
-#define MIISTAT_CAN_T_FDX       0x1000
-#define MIISTAT_CAN_TX          0x2000
-#define MIISTAT_CAN_TX_FDX      0x4000
-#define MIISTAT_CAN_T4          0x8000
-/* MII NWAY Register Bits ...
-** valid for the ANAR (Auto-Negotiation Advertisement) and
-** ANLPAR (Auto-Negotiation Link Partner) registers */
-#define MII_NWAY_NODE_SEL       0x001f
-#define MII_NWAY_CSMA_CD        0x0001
-#define MII_NWAY_T              0x0020
-#define MII_NWAY_T_FDX          0x0040
-#define MII_NWAY_TX             0x0080
-#define MII_NWAY_TX_FDX         0x0100
-#define MII_NWAY_T4             0x0200
-#define MII_NWAY_RF             0x2000
-#define MII_NWAY_ACK            0x4000
-#define MII_NWAY_NP             0x8000
-
-/* MII Auto-Negotiation Expansion Register Bits */
-#define MII_ANER_PDF            0x0010
-#define MII_ANER_LP_NP_ABLE     0x0008
-#define MII_ANER_NP_ABLE        0x0004
-#define MII_ANER_RX_PAGE        0x0002
-#define MII_ANER_LP_AN_ABLE     0x0001
-#define HALF_DUPLEX                     1
-#define FDX_CAPABLE_DUPLEX_UNKNOWN      2
-#define FDX_CAPABLE_HALF_SELECTED       3
-#define FDX_CAPABLE_FULL_SELECTED       4
-#define HW_SPEED_UNCONFIG       0
-#define HW_SPEED_10_MBPS        10
-#define HW_SPEED_100_MBPS       100
-#define HW_SPEED_DEFAULT        (HW_SPEED_10_MBPS)
-
-#define ACCEPT_ALL_PHYS         0x01
-#define ACCEPT_ALL_MCASTS       0x02
-#define ACCEPT_ALL_BCASTS       0x04
-#define ACCEPT_ALL_ERRORS       0x08
-#define ACCEPT_CAM_QUALIFIED    0x10
-#define MAC_LOOPBACK            0x20
-//#define FDX_CAPABLE_FULL_SELECTED     4
-#define CRC_SIZE                4
-#define MAC_HEADER_SIZE         14
-
 typedef struct _EuphLiteDesc {
         u32     llink;
         unsigned char*  buf;
@@ -368,19 +104,15 @@
 } EuphLiteDesc;
 
 struct sis900_private {
-        char devname[8];                /* Used only for kernel debugging. */
-        const char *product_name;
         struct device *next_module;
-        int chip_id;
-        int chip_revision;
-        unsigned char pci_bus, pci_devfn;
-#if LINUX_VERSION_CODE > 0x20139
         struct net_device_stats stats;
-#else
-        struct enet_statistics stats;
-#endif
-        struct timer_list timer;        /* Media selection timer. */
-        unsigned int cur_rx;    /* Index into the Rx buffer of next Rx pkt. */
+	struct pci_dev * pci_dev;
+
+	struct mac_chip_info * mac;
+	struct mii_phy * mii;
+
+        struct timer_list timer;        		/* Media selection timer. */
+        unsigned int cur_rx;			/* Index into the Rx buffer of next Rx pkt. */
         unsigned int cur_tx, dirty_tx, tx_flag;
 
         /* The saved address of a sent-in-place packet/buffer, for skfree(). */
@@ -388,15 +120,12 @@
         EuphLiteDesc tx_buf[NUM_TX_DESC];       /* Tx bounce buffers */
         EuphLiteDesc rx_buf[NUM_RX_DESC];
         unsigned char *rx_bufs;
-        unsigned char *tx_bufs;                 /* Tx bounce buffer region. */
-        char phys[4];                           /* MII device addresses.    */
-        int phy_idx;                            /* Support Max 4 PHY        */
-        u16 pmd_status;
-        unsigned int tx_full;                   /* The Tx queue is full.    */
-	int MediaSpeed;                         /* user force speed         */
-	int MediaDuplex;                        /* user force duplex        */
-        int full_duplex;                        /* Full/Half-duplex.        */
-        int speeds;                             /* 100/10 Mbps.             */
+	unsigned char *tx_bufs;                 	/* Tx bounce buffer region. */
+        unsigned int tx_full;			/* The Tx queue is full.    */
+	int MediaSpeed;                         	/* user force speed         */
+	int MediaDuplex;                        	/* user force duplex        */
+        int full_duplex;                        	/* Full/Half-duplex.        */
+        int speeds;                             	/* 100/10 Mbps.             */
         u16 LinkOn;
         u16 LinkChange;
 };
@@ -414,8 +143,10 @@
 #endif
 
 static int sis900_open(struct device *dev);
+static int sis900_mii_probe (struct device * dev);
+static void sis900_init_rxfilter (struct device * dev);
 static u16 read_eeprom(long ioaddr, int location);
-static int mdio_read(struct device *dev, int phy_id, int location);
+static u16 mdio_read(struct device *dev, int phy_id, int location);
 static void mdio_write(struct device *dev, int phy_id, int location, int val);
 static void sis900_timer(unsigned long data);
 static void sis900_tx_timeout(struct device *dev);
@@ -431,314 +162,199 @@
 static u16 elAutoNegotiate(struct device *dev, int phy_id, int *duplex, int *speed);
 static void elSetCapability(struct device *dev, int phy_id, int duplex, int speed);
 static u16 elPMDreadMode(struct device *dev, int phy_id, int *speed, int *duplex);
-static u16 elMIIpollBit(struct device *dev, int phy_id, int location, u16 mask, u16 polarity, u16 *value);
+static u16 elMIIpollBit(struct device *dev, int phy_id, int location, u16 mask, 
+					u16 polarity, u16 *value);
 static void elSetMediaType(struct device *dev, int speed, int duplex);
 
 /* A list of all installed SiS900 devices, for removing the driver module. */
 static struct device *root_sis900_dev = NULL;
 
-/* Ideally we would detect all network cards in slot order.  That would
-   be best done a central PCI probe dispatch, which wouldn't work
-   well when dynamically adding drivers.  So instead we detect just the
-   SiS 900 cards in slot order. */
-
-int sis900_probe(struct device *dev)
-{
-        int cards_found = 0;
-        int pci_index = 0;
-        unsigned char pci_bus, pci_device_fn;
-
-        if ( ! pcibios_present())
-                return -ENODEV;
-
-        for (;pci_index < 0xff; pci_index++) {
-                u16 vendor, device, pci_command, new_command;
-                int chip_idx, irq;
-                long ioaddr;
-
-                if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8,
-                                                pci_index,
-                                                &pci_bus, &pci_device_fn)
-                                != PCIBIOS_SUCCESSFUL) {
-                        break;
-                }
-                pcibios_read_config_word(pci_bus, pci_device_fn, PCI_VENDOR_ID,
-                                                        &vendor);
-                pcibios_read_config_word(pci_bus, pci_device_fn, PCI_DEVICE_ID,
-                                                        &device);
-
-                for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++)
-                        if (vendor == pci_tbl[chip_idx].vendor_id &&
-                                (device & pci_tbl[chip_idx].device_id_mask) ==
-                                pci_tbl[chip_idx].device_id)
-                                break;
-                if (pci_tbl[chip_idx].vendor_id == 0)   /* Compiled out! */
-                        continue;
+/* walk through every ethernet PCI devices to see if some of them are matched with our card list*/
+int sis900_probe (struct device * net_dev)
+{
+	int found = 0;
+	struct pci_dev * pci_dev = NULL;
+		
+	if (!pci_present())
+		return -ENODEV;
+		
+	while ((pci_dev = pci_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_dev)) != NULL) {
+		/* pci_dev contains all ethernet devices */
+		u32 pci_io_base;
+		struct mac_chip_info * mac;
+
+		for (mac = mac_chip_table; mac->vendor_id; mac++) {
+			/* try to match our card list */
+			if (pci_dev->vendor == mac->vendor_id &&
+			    pci_dev->device == mac->device_id)
+				break;
+		}
+		
+		if (mac->vendor_id == 0)
+			/* pci_dev does not match any of our cards */
+			continue;
+		
+		/* now, pci_dev should be either 900 or 7016 */
+		pci_io_base = pci_dev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
+		if ((mac->flags & PCI_COMMAND_IO ) && 
+		    check_region(pci_io_base, mac->io_size))
+			continue;
+		
+		/* setup various bits in PCI command register */
+		pci_set_master(pci_dev);
+
+		/* do the real low level jobs */
+		net_dev = mac->probe(mac, pci_dev, net_dev);
+		
+		if (net_dev != NULL) {
+			found++;
+		}
+		net_dev = NULL;
+	}
+	return found ? 0 : -ENODEV;
+}
 
-        {
-#if defined(PCI_SUPPORT_VER2)
-                struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
-                ioaddr = pdev->base_address[0] & ~3;
-                irq = pdev->irq;
-#else
-                u32 pci_ioaddr;
-                u8 pci_irq_line;
-                pcibios_read_config_byte(pci_bus, pci_device_fn,
-                                         PCI_INTERRUPT_LINE, &pci_irq_line);
-                pcibios_read_config_dword(pci_bus, pci_device_fn,
-                                         PCI_BASE_ADDRESS_0, &pci_ioaddr);
-                ioaddr = pci_ioaddr & ~3;
-                irq = pci_irq_line;
-#endif
-        }
+static struct device * sis900_mac_probe (struct mac_chip_info * mac, struct pci_dev * pci_dev, 
+					 struct device * net_dev)
+{
+	struct sis900_private *sis_priv;
+	long ioaddr = pci_dev->base_address[0] & ~3;
+	int irq = pci_dev->irq;
+	static int did_version = 0;
+	u16 signature;
+	int i;
+
+	if (did_version++ == 0)
+		printk(KERN_INFO "%s", version);
+
+	/* check to see if  we have sane EEPROM */
+	signature = (u16) read_eeprom(ioaddr, EEPROMSignature);    
+	if (signature == 0xffff || signature == 0x0000) {
+		printk (KERN_INFO "Error EERPOM read %x\n", signature);
+		return NULL;
+	}
 
-                if ((pci_tbl[chip_idx].flags & PCI_USES_IO) &&
-                        check_region(ioaddr, pci_tbl[chip_idx].io_size))
-                        continue;
-
-                /* Activate the card: fix for brain-damaged Win98 BIOSes. */
-                pcibios_read_config_word(pci_bus, pci_device_fn,
-                                         PCI_COMMAND, &pci_command);
-                new_command = pci_command | (pci_tbl[chip_idx].flags & 7);
-                if (pci_command != new_command) {
-                        printk(KERN_INFO "  The PCI BIOS has not enabled the"
-                                   " device at %d/%d!"
-                                   "Updating PCI command %4.4x->%4.4x.\n",
-                                        pci_bus, pci_device_fn,
-                                        pci_command, new_command);
+	if ((net_dev = init_etherdev(net_dev, 0)) == NULL)
+		return NULL;
 
-                        pcibios_write_config_word(pci_bus, pci_device_fn,
-                                                  PCI_COMMAND, new_command);
-                }
+	printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", net_dev->name, mac->name,
+	       ioaddr, irq);
 
-                dev = pci_tbl[chip_idx].probe1(pci_bus,
-                                                pci_device_fn,
-                                                dev,
-                                                ioaddr,
-                                                irq,
-                                                chip_idx,
-                                                cards_found);
-
-                if (dev  && (pci_tbl[chip_idx].flags & PCI_COMMAND_MASTER)) {
-                        u8 pci_latency;
-
-                        pcibios_read_config_byte(pci_bus, pci_device_fn,
-                                        PCI_LATENCY_TIMER, &pci_latency);
-
-                        if (pci_latency < 32) {
-                           printk(KERN_NOTICE "  PCI latency timer (CFLT) is "
-                           "unreasonably low at %d.  Setting to 64 clocks.\n",
-                                           pci_latency);
-                           pcibios_write_config_byte(pci_bus, pci_device_fn,
-                                          PCI_LATENCY_TIMER, 64);
-                        }
-                }
-                dev = 0;
-                cards_found++;
-        }
-        return cards_found ? 0 : -ENODEV;
-}
+	/* get MAC address from EEPROM */
+	for (i = 0; i < 3; i++)
+		((u16 *)(net_dev->dev_addr))[i] = read_eeprom(ioaddr, i+EEPROMMACAddr);
+	for (i = 0; i < 5; i++)
+		printk("%2.2x:", (u8)net_dev->dev_addr[i]);
+	printk("%2.2x.\n", net_dev->dev_addr[i]);
+
+	if ((net_dev->priv = kmalloc(sizeof(struct sis900_private), GFP_KERNEL)) == NULL)
+	    /* FIXME: possible mem leak here */
+	    return NULL;
+
+	sis_priv = net_dev->priv;
+	memset(sis_priv, 0, sizeof(struct sis900_private));
+
+	/* We do a request_region() to register /proc/ioports info. */
+	request_region(ioaddr, mac->io_size, net_dev->name);
+	net_dev->base_addr = ioaddr;
+	net_dev->irq = irq;
+	sis_priv->pci_dev = pci_dev;
+	sis_priv->mac = mac;
+
+	/* probe for mii transciver */
+	if (sis900_mii_probe(net_dev) == 0) {
+		/* FIXME: how to clean up this */
+		release_region (ioaddr, mac->io_size);
+		return NULL;
+	}
 
-static struct device * sis900_probe1(   int pci_bus,
-                                        int pci_devfn,
-                                        struct device *dev,
-                                        long ioaddr,
-                                        int irq,
-                                        int chip_idx,
-                                        int found_cnt)
-{
-        static int did_version = 0;     /* Already printed version info. */
-        struct sis900_private *tp;
-	u16    status;
-        int    duplex = found_cnt < MAX_UNITS ? full_duplex[found_cnt] : 0 ;
-        int    speed  = found_cnt < MAX_UNITS ? speeds[found_cnt] : 0 ;
-        int    phy=0, phy_idx=0, i;
-
-        if (did_version++ == 0)
-                printk(KERN_INFO "%s", version);
-
-        dev = init_etherdev(dev, 0);
-        
-        if(dev==NULL)
-        	return NULL;
-
-        printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ",
-                   dev->name, pci_tbl[chip_idx].name, ioaddr, irq);
-
-        if ((u16)read_eeprom(ioaddr, EuphLiteEEVendorID) != 0xffff) {
-                for (i = 0; i < 3; i++)
-                        ((u16 *)(dev->dev_addr))[i] =
-                                        read_eeprom(ioaddr,i+EuphLiteEEMACAddr);
-                for (i = 0; i < 5; i++)
-                        printk("%2.2x:", (u8)dev->dev_addr[i]);
-                printk("%2.2x.\n", dev->dev_addr[i]);
-        } else
-                printk(KERN_INFO "Error EEPROM read\n");
-
-        /* We do a request_region() to register /proc/ioports info. */
-        request_region(ioaddr, pci_tbl[chip_idx].io_size, dev->name);
-
-        dev->base_addr = ioaddr;
-        dev->irq = irq;
-
-        /* Some data structures must be quadword aligned. */
-        tp = kmalloc(sizeof(*tp), GFP_KERNEL | GFP_DMA);
-        if(tp==NULL)
-        {
-        	release_region(ioaddr, pci_tbl[chip_idx].io_size);
-        	return NULL;
-        }
-        memset(tp, 0, sizeof(*tp));
-        dev->priv = tp;
-
-        tp->next_module = root_sis900_dev;
-        root_sis900_dev = dev;
-
-        tp->chip_id = chip_idx;
-        tp->pci_bus = pci_bus;
-        tp->pci_devfn = pci_devfn;
-
-        /* Find the connected MII xcvrs.
-           Doing this in open() would allow detecting external xcvrs later, but
-           takes too much time. */
-        if (sis_cap_tbl[chip_idx] & HAS_MII_XCVR) {
-                for (phy = 0, phy_idx = 0;
-                        phy < 32 && phy_idx < sizeof(tp->phys); phy++)
-                {
-                        int mii_status ;
-			mii_status = mdio_read(dev, phy, MII_STATUS);
-
-                        if (mii_status != 0xffff && mii_status != 0x0000) {
-                                tp->phy_idx = phy_idx;
-                                tp->phys[phy_idx++] = phy;
-                                tp->pmd_status=mdio_read(dev, phy, MII_STATUS);
-                                printk(KERN_INFO "%s: MII transceiver found "
-                                                 "at address %d.\n",
-                                                 dev->name, phy);
-                                break;
-                        }
-                }
+	sis_priv->next_module = root_sis900_dev;
+	root_sis900_dev = net_dev;
 
-                if (phy_idx == 0) {
-                        printk(KERN_INFO "%s: No MII transceivers found!\n",
-                                        dev->name);
-                        tp->phys[0] = -1;
-			tp->pmd_status = 0;
-                }
-        } else {
-                        tp->phys[0] = -1;
-			tp->pmd_status = 0;
-        }
-
-        if ((tp->pmd_status > 0) && (phy_idx > 0)) {
-		if (sis900_debug > 1) {
-			printk(KERN_INFO "duplex=%d, speed=%d\n",
-						duplex, speed);
-		}
-		if (!duplex && !speed) {  
-			// auto-config media type
-			// Set full capability
-			if (sis900_debug > 1) {
-				printk(KERN_INFO "Auto Config ...\n");
-			}
-			elSetCapability(dev, tp->phys[tp->phy_idx], 1, 100);
-            		tp->pmd_status=elAutoNegotiate(dev,
-               	    				       tp->phys[tp->phy_idx],
-			                  	       &tp->full_duplex,
-						       &tp->speeds);
-		} else {
-			tp->MediaSpeed = speed;
-			tp->MediaDuplex = duplex;
-			elSetCapability(dev, tp->phys[tp->phy_idx],
-					duplex, speed);
-            		elAutoNegotiate(dev, tp->phys[tp->phy_idx],
-			                &tp->full_duplex,
-					&tp->speeds);
-			status = mdio_read(dev, phy, MII_ANLPAR);
-			if ( !(status & (MII_NWAY_T  | MII_NWAY_T_FDX |
-					 MII_NWAY_TX | MII_NWAY_TX_FDX )))
-			{
-				u16 cmd=0;
-				cmd |= ( speed == 100 ?
-					 MIICNTL_SPEED : 0 );
-				cmd |= ( duplex ? MIICNTL_FDX : 0 );
-        			mdio_write(dev, phy, MII_CONTROL, cmd);
-				elSetMediaType(dev, speed==100 ? 
-						    HW_SPEED_100_MBPS :
-						    HW_SPEED_10_MBPS,
-						    duplex ?
-						    FDX_CAPABLE_FULL_SELECTED:
-						    FDX_CAPABLE_HALF_SELECTED);
-        			elMIIpollBit(dev, phy, MII_STATUS,
-						MIISTAT_LINK, TRUE, &status);
-			} else {
-				status = mdio_read(dev, phy, MII_STATUS);
-			}
-		}
+	/* The SiS900-specific entries in the device structure. */
+	net_dev->open = &sis900_open;
+	net_dev->hard_start_xmit = &sis900_start_xmit;
+	net_dev->stop = &sis900_close;
+	net_dev->get_stats = &sis900_get_stats;
+	net_dev->set_multicast_list = &set_rx_mode;
+	net_dev->do_ioctl = &mii_ioctl;
 
-                if (tp->pmd_status & MIISTAT_LINK) 
-               	        tp->LinkOn = TRUE;
-	        else
-                        tp->LinkOn = FALSE;
+	return net_dev;
+}
 
-		tp->LinkChange = FALSE;
+static int sis900_mii_probe (struct device * net_dev)
+{
+	struct sis900_private * sis_priv = (struct sis900_private *)net_dev->priv;
+	int phy_addr;
 	
-        }
-
-	if (sis900_debug > 1) {
-        	if (tp->full_duplex == FDX_CAPABLE_FULL_SELECTED) {
-                	printk(KERN_INFO "%s: Media type is Full Duplex.\n",
-						dev->name);
-        	} else {
-                	printk(KERN_INFO "%s: Media type is Half Duplex.\n",
-						dev->name);
-        	}
-        	if (tp->speeds == HW_SPEED_100_MBPS) {
-                	printk(KERN_INFO "%s: Speed is 100mbps.\n", dev->name);
-        	} else {
-                	printk(KERN_INFO "%s: Speed is 10mbps.\n", dev->name);
-        	}
+	sis_priv->mii = NULL;
+	
+	/* search for total of 32 possible mii phy address */
+	for (phy_addr = 0; phy_addr < 32; phy_addr++) {
+		u16 mii_status;
+		u16 phy_id0, phy_id1;
+		int i;
+		
+		mii_status = mdio_read(net_dev, phy_addr, MII_STATUS);
+		if (mii_status == 0xffff || mii_status == 0x0000)
+			/* the mii is not accessable, try next one */
+			continue;
+		
+		phy_id0 = mdio_read(net_dev, phy_addr, MII_PHY_ID0);
+		phy_id1 = mdio_read(net_dev, phy_addr, MII_PHY_ID1);
+		
+		/* search our mii table for the current mii */ 
+		for (i = 0; mii_chip_table[i].phy_id1; i++)
+			if (phy_id0 == mii_chip_table[i].phy_id0) {
+				struct mii_phy * mii_phy;
+				
+				printk(KERN_INFO 
+				       "%s: %s transceiver found at address %d.\n",
+				       net_dev->name, mii_chip_table[i].name, 
+				       phy_addr);;
+				if ((mii_phy = kmalloc(sizeof(struct mii_phy), GFP_KERNEL)) != NULL) {
+					mii_phy->chip_info = mii_chip_table+i;
+					mii_phy->phy_addr = phy_addr;
+					mii_phy->status = mdio_read(net_dev, phy_addr, 
+								    MII_STATUS);
+					mii_phy->next = sis_priv->mii;
+					sis_priv->mii = mii_phy;
+				}
+				/* the current mii is on our mii_info_table, quit searching (table) */
+				break;
+			}
+	}
+	
+	if (sis_priv->mii == NULL) {
+		printk(KERN_INFO "%s: No MII transceivers found!\n", net_dev->name);
+		return 0;
 	}
 
-        /* The SiS900-specific entries in the device structure. */
-        dev->open = &sis900_open;
-        dev->hard_start_xmit = &sis900_start_xmit;
-        dev->stop = &sis900_close;
-        dev->get_stats = &sis900_get_stats;
-        dev->set_multicast_list = &set_rx_mode;
-        dev->do_ioctl = &mii_ioctl;
-
-        return dev;
-}
-
-/* Serial EEPROM section. */
-
-/*  EEPROM_Ctrl bits. */
-#define EECLK           0x00000004      /* EEPROM shift clock. */
-#define EECS            0x00000008      /* EEPROM chip select. */
-#define EEDO            0x00000002      /* EEPROM chip data out. */
-#define EEDI            0x00000001      /* EEPROM chip data in. */
-
-/* Delay between EEPROM clock transitions.
-   No extra delay is needed with 33Mhz PCI, but 66Mhz may change this.
- */
+	/* FIXME: AMD stuff should be added */
+	/* auto negotiate FIXME: not completed */
+	elSetCapability(net_dev, sis_priv->mii->phy_addr, 1, 100);
+	sis_priv->mii->status = elAutoNegotiate(net_dev, sis_priv->mii->phy_addr,
+						&sis_priv->full_duplex, 
+						&sis_priv->speeds);
+	
+	if (sis_priv->mii->status & MIISTAT_LINK) 
+		sis_priv->LinkOn = TRUE;
+	else
+		sis_priv->LinkOn = FALSE;
+	
+	sis_priv->LinkChange = FALSE;
+	
+	return 1;
+}
 
+/* Delay between EEPROM clock transitions. */
 #define eeprom_delay()  inl(ee_addr)
 
-/* The EEPROM commands include the alway-set leading bit. */
-#define EEread          0x0180
-#define EEwrite         0x0140
-#define EEerase         0x01C0
-#define EEwriteEnable   0x0130
-#define EEwriteDisable  0x0100
-#define EEeraseAll      0x0120
-#define EEwriteAll      0x0110
-#define EEaddrMask      0x013F
-#define EEcmdShift      16
-
+/* Read Serial EEPROM through EEPROM Access Register, Note that location is 
+   in word (16 bits) unit */
 static u16 read_eeprom(long ioaddr, int location)
 {
-        int i;
+	int i;
         u16 retval = 0;
         long ee_addr = ioaddr + mear;
         u32 read_cmd = location | EEread;
@@ -748,7 +364,7 @@
         outl(EECLK, ee_addr);
         eeprom_delay();
 
-        /* Shift the read command bits out. */
+        /* Shift the read command (9) bits out. */
         for (i = 8; i >= 0; i--) {
                 u32 dataval = (read_cmd & (1 << i)) ? EEDI | EECS : EECS;
                 outl(dataval, ee_addr);
@@ -759,6 +375,7 @@
         outb(EECS, ee_addr);
         eeprom_delay();
 
+	/* read the 16-bits data in */
         for (i = 16; i > 0; i--) {
                 outl(EECS, ee_addr);
                 eeprom_delay();
@@ -767,39 +384,21 @@
                 retval = (retval << 1) | ((inl(ee_addr) & EEDO) ? 1 : 0);
                 eeprom_delay();
         }
-
+		
         /* Terminate the EEPROM access. */
         outl(0, ee_addr);
         eeprom_delay();
         outl(EECLK, ee_addr);
+
         return (retval);
 }
 
-/* MII serial management: mostly bogus for now. */
 /* Read and write the MII management registers using software-generated
-   serial MDIO protocol.
-   The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually
-   met by back-to-back PCI I/O cycles, but we insert a delay to avoid
-   "overclocking" issues. */
+   serial MDIO protocol. Note that the command bits and data bits are
+   send out seperately */
 
 #define mdio_delay()    inl(mdio_addr)
 
-#define MIIread         0x6000
-#define MIIwrite        0x6002
-#define MIIpmdMask      0x0F80
-#define MIIpmdShift     7
-#define MIIregMask      0x007C
-#define MIIregShift     2
-#define MIIturnaroundBits       2
-#define MIIcmdLen       16
-#define MIIcmdShift     16
-#define MIIreset        0xFFFFFFFF
-#define MIIwrLen        32
-
-#define MDC             0x00000040
-#define MDDIR           0x00000020
-#define MDIO            0x00000010
-
 static void mdio_idle(long mdio_addr)
 {
         outl(MDIO | MDDIR, mdio_addr);
@@ -821,11 +420,11 @@
         return;
 }
 
-static int mdio_read(struct device *dev, int phy_id, int location)
+static u16 mdio_read(struct device *dev, int phy_id, int location)
 {
         long mdio_addr = dev->base_addr + mear;
         int mii_cmd = MIIread|(phy_id<<MIIpmdShift)|(location<<MIIregShift);
-        int retval = 0;
+        u16 retval = 0;
         int i;
 
         mdio_reset(mdio_addr);
@@ -834,13 +433,15 @@
         for (i = 15; i >= 0; i--) {
                 int dataval = (mii_cmd & (1 << i)) ? MDDIR | MDIO : MDDIR;
                 outl(dataval, mdio_addr);
+		mdio_delay();
                 outl(dataval | MDC, mdio_addr);
+		mdio_delay();
         }
 
-        /* Read the two transition, 16 data, and wire-idle bits. */
+        /* Read the 16 data bits. */
         for (i = 16; i > 0; i--) {
                 outl(0, mdio_addr);
-                //mdio_delay();
+                mdio_delay();
                 retval = (retval << 1) | ((inl(mdio_addr) & MDIO) ? 1 : 0);
                 outl(MDC, mdio_addr);
                 mdio_delay();
@@ -858,7 +459,7 @@
         mdio_idle(mdio_addr);
 
         /* Shift the command bits out. */
-        for (i = 31; i >= 0; i--) {
+        for (i = 15; i >= 0; i--) {
                 int dataval = (mii_cmd & (1 << i)) ? MDDIR | MDIO : MDDIR;
                 outb(dataval, mdio_addr);
                 mdio_delay();
@@ -866,6 +467,17 @@
                 mdio_delay();
         }
         mdio_delay();
+
+	/* Shift the value bits out. */
+	for (i = 15; i >= 0; i--) {
+		int dataval = (value & (1 << i)) ? MDDIR | MDIO : MDDIR;
+	        outl(dataval, mdio_addr);
+	        mdio_delay();
+	        outl(dataval | MDC, mdio_addr);
+	       	mdio_delay();
+	}
+	mdio_delay();
+	
         /* Clear out extra bits. */
         for (i = 2; i > 0; i--) {
                 outb(0, mdio_addr);
@@ -879,110 +491,62 @@
 static int
 sis900_open(struct device *dev)
 {
-        struct sis900_private *tp = (struct sis900_private *)dev->priv;
+        struct sis900_private *sis_priv = (struct sis900_private *)dev->priv;
         long ioaddr = dev->base_addr;
-
-        if (sis900_debug > 0)
-                printk(KERN_INFO "%s sis900_open, IO Addr=%x, Irq=%x\n",
-                                dev->name, (unsigned int)ioaddr, dev->irq);
+	int i = 0;
+	u32 status = TxRCMP | RxRCMP;
 
         /* Soft reset the chip. */
-        outl(0, ioaddr + imr);
-        outl(0, ioaddr + ier);
-        outl(0, ioaddr + rfcr);
-        outl(RESET | RxRESET | TxRESET, ioaddr + cr);
+	sis900_reset(dev);
 
-        if (request_irq(dev->irq, &sis900_interrupt, SA_SHIRQ, dev->name, dev))
-        {
+        if (request_irq(dev->irq, &sis900_interrupt, SA_SHIRQ, dev->name, dev)) {
                 return -EAGAIN;
         }
 
         MOD_INC_USE_COUNT;      
 
-        tp->tx_bufs = kmalloc(TX_BUF_SIZE * NUM_TX_DESC, GFP_KERNEL);
-        tp->rx_bufs = kmalloc(RX_BUF_SIZE * NUM_RX_DESC, GFP_KERNEL);
-        if (tp->tx_bufs == NULL || tp->rx_bufs == NULL) {
-                if (tp->tx_bufs)
-                        kfree(tp->tx_bufs);
-                if (tp->rx_bufs)
-                        kfree(tp->rx_bufs);
-		if (!tp->tx_bufs) {
-	              printk(KERN_ERR "%s: Can't allocate a %d byte TX Bufs.\n",
-                                   dev->name, TX_BUF_SIZE * NUM_TX_DESC);
-		}
-		if (!tp->rx_bufs) {
-	              printk(KERN_ERR "%s: Can't allocate a %d byte RX Bufs.\n",
-                                   dev->name, RX_BUF_SIZE * NUM_RX_DESC);
-		}
-                return -ENOMEM;
-        }
+        if ((sis_priv->tx_bufs = kmalloc(TX_BUF_SIZE * NUM_TX_DESC, GFP_KERNEL)) == NULL) {
+		printk(KERN_ERR "%s: Can't allocate a %d byte TX Bufs.\n",
+		       dev->name, TX_BUF_SIZE * NUM_TX_DESC);
+		return -ENOMEM;
+	}
+	if ((sis_priv->rx_bufs = kmalloc(RX_BUF_SIZE * NUM_RX_DESC, GFP_KERNEL)) == NULL) {
+		kfree (sis_priv->tx_buf);
+		printk(KERN_ERR "%s: Can't allocate a %d byte RX Bufs.\n",
+		       dev->name, RX_BUF_SIZE * NUM_RX_DESC);
+		return -ENOMEM;
+	}
 
-        {
-                u32 rfcrSave;
-                u32 w;
-                u32 i;
-
-                rfcrSave = inl(rfcr);
-                outl(rfcrSave & ~RFEN, rfcr);
-                for (i=0 ; i<3 ; i++) {
-                        w = (u16)*((u16*)(dev->dev_addr)+i);
-                        outl((((u32) i) << RFEP_shift), ioaddr + rfcr);
-                        outl((u32)w, ioaddr + rfdr);
-                        if (sis900_debug > 4) {
-                                printk(KERN_INFO "Filter Addr[%d]=%x\n",
-                                        i, inl(ioaddr + rfdr));
-                        }
-                }
-                outl(rfcrSave, rfcr);
-        }
+	sis900_init_rxfilter(dev);
 
-        sis900_init_ring(dev);
-        outl((u32)tp->tx_buf[0].physAddr, ioaddr + txdp);
-        outl((u32)tp->rx_buf[0].physAddr, ioaddr + rxdp);
+	sis900_reset_tx_ring(dev);
+	sis900_reset_rx_ring(dev);
 
         if (sis900_debug > 4)
-                printk(KERN_INFO "txdp:%8.8x\n", inl(ioaddr + txdp));
+                printk(KERN_INFO "%s: txdp:%8.8x\n", dev->name, inl(ioaddr + txdp));
 
-        /* Check that the chip has finished the reset. */
-        {
-                u32 status;
-                int j=0;
-                status = TxRCMP | RxRCMP;
-                while (status && (j++ < 30000)) {
-                        status ^= (inl(isr) & status);
-                }
+	/* Check that the chip has finished the reset. */
+	while (status && (i++ < 30000)) {
+		status ^= (inl(isr + ioaddr) & status);
         }
 
         outl(PESEL, ioaddr + cfg);
 
-        /* Must enable Tx/Rx before setting transfer thresholds! */
-        /*
-         *      #define TX_DMA_BURST    0
-         *      #define RX_DMA_BURST    0
-         *      #define TX_FIFO_THRESH  16
-         *      #define TxDRNT_100      (1536>>5)
-         *      #define TxDRNT_10       (1536>>5)
-         *      #define RxDRNT_100      (1536>>5)
-         *      #define RxDRNT_10       (1536>>5)
-         */
-        outl((RX_DMA_BURST<<20) | (RxDRNT_10 << 1), ioaddr+rxcfg);
-        outl(TxATP | (TX_DMA_BURST << 20) | (TX_FIFO_THRESH<<8) | TxDRNT_10,
-                                                ioaddr + txcfg);
-        if (sis900_debug > 1)
-        {
-        	if (tp->LinkOn) {
-        		printk(KERN_INFO"%s: Media Type %s%s-duplex.\n",
-                                dev->name,
-                                tp->speeds==HW_SPEED_100_MBPS ?
-					"100mbps " : "10mbps ",
-                                tp->full_duplex== FDX_CAPABLE_FULL_SELECTED ?
-					"full" : "half");
-		}
-		else
-		{
-			printk(KERN_INFO"%s: Media Link Off\n", dev->name);
-		}
+	/* FIXME: should be removed, and replaced by AutoNeogotiate stuff */
+        outl((RX_DMA_BURST << RxMXDMA_shift) | (RxDRNT_10 << RxDRNT_shift), 
+	     ioaddr + rxcfg);
+        outl(TxATP | (TX_DMA_BURST << TxMXDMA_shift) | (TX_FILL_THRESH << TxFILLT_shift) | TxDRNT_10,
+	     ioaddr + txcfg);
+
+	if (sis_priv->LinkOn) {
+		printk(KERN_INFO "%s: Media Type %s%s-duplex.\n",
+		       dev->name, 
+		       sis_priv->speeds == HW_SPEED_100_MBPS ? "100mbps " : "10mbps ",
+		       sis_priv->full_duplex == FDX_CAPABLE_FULL_SELECTED ? "full" : "half");
+	} else {
+		printk(KERN_INFO "%s: Media Link Off\n", dev->name);
 	}
+
         set_rx_mode(dev);
 
         dev->tbusy = 0;
@@ -990,56 +554,77 @@
         dev->start = 1;
 
         /* Enable all known interrupts by setting the interrupt mask. */
-        outl((RxOK|RxERR|RxORN|RxSOVR|TxOK|TxERR|TxURN), ioaddr + imr);
+        outl((RxRCMP|RxOK|RxERR|RxORN|RxSOVR|TxOK|TxERR|TxURN), ioaddr + imr);
         outl(RxENA, ioaddr + cr);
         outl(IE, ioaddr + ier);
 
-        if (sis900_debug > 3)
-                printk(KERN_INFO "%s: sis900_open() ioaddr %#lx IRQ %d \n",
-                           dev->name, ioaddr, dev->irq);
-
         /* Set the timer to switch to check for link beat and perhaps switch
            to an alternate media type. */
-        init_timer(&tp->timer);
-        tp->timer.expires = RUN_AT((24*HZ)/10);         /* 2.4 sec. */
-        tp->timer.data = (unsigned long)dev;
-        tp->timer.function = &sis900_timer;             /* timer handler */
-        add_timer(&tp->timer);
+        init_timer(&sis_priv->timer);
+        sis_priv->timer.expires = jiffies + 2*HZ;
+        sis_priv->timer.data = (unsigned long)dev;
+        sis_priv->timer.function = &sis900_timer;
+        add_timer(&sis_priv->timer);
 
         return 0;
 }
 
+/* set receive filter address to our MAC address */
+static void
+sis900_init_rxfilter (struct device * net_dev)
+{
+	long ioaddr = net_dev->base_addr;
+	u32 rfcrSave;
+	u32 i;
+	
+	rfcrSave = inl(rfcr + ioaddr);
+
+	/* disable packet filtering before setting filter */
+	outl(rfcrSave & ~RFEN, rfcr);
+
+	for (i = 0 ; i < 3 ; i++) {
+		u32 w;
+
+		w = (u32) *((u16 *)(net_dev->dev_addr)+i);
+		outl((i << RFADDR_shift), ioaddr + rfcr);
+		outl(w, ioaddr + rfdr);
+
+		if (sis900_debug > 4) {
+			printk(KERN_INFO "%s: Receive Filter Addrss[%d]=%x\n",
+			       net_dev->name, i, inl(ioaddr + rfdr));
+		}
+	}
+	outl(rfcrSave, rfcr + ioaddr);
+}
+
 static void sis900_timer(unsigned long data)
 {
         struct device *dev = (struct device *)data;
         struct sis900_private *tp = (struct sis900_private *)dev->priv;
-        int next_tick = 0;
+        int next_tick = 2*HZ;
         u16 status;
 
+	/* FIXME: call auto negotiate routine to detect link status */
         if (!tp->LinkOn) {
-                status = mdio_read(dev, tp->phys[tp->phy_idx], MII_STATUS);
+                status = mdio_read(dev, tp->mii->phy_addr, MII_STATUS);
 		if (status & MIISTAT_LINK) {
-                	elPMDreadMode(dev, tp->phys[tp->phy_idx],
-                                        &tp->speeds, &tp->full_duplex);
+                	elPMDreadMode(dev, tp->mii->phy_addr,
+				      &tp->speeds, &tp->full_duplex);
 			tp->LinkOn = TRUE;
-                        printk(KERN_INFO "%s: Media Link On %s%s-duplex ",
-                                   dev->name,
-                                   tp->speeds == HW_SPEED_100_MBPS ?
-						"100mbps " : "10mbps ",
-                                   tp->full_duplex==FDX_CAPABLE_FULL_SELECTED ?
-						"full" : "half");
+                        printk(KERN_INFO "%s: Media Link On %s%s-duplex \n", dev->name,
+			       tp->speeds == HW_SPEED_100_MBPS ? "100mbps " : "10mbps ",
+			       tp->full_duplex == FDX_CAPABLE_FULL_SELECTED ? "full" : "half");
 		}
         } else { // previous link on
-                status = mdio_read(dev, tp->phys[tp->phy_idx], MII_STATUS);
+                status = mdio_read(dev, tp->mii->phy_addr, MII_STATUS);
 		if (!(status & MIISTAT_LINK)) {
 			tp->LinkOn = FALSE;
                         printk(KERN_INFO "%s: Media Link Off\n", dev->name);
 		}
         }
-        next_tick = 2*HZ;
 
         if (next_tick) {
-                tp->timer.expires = RUN_AT(next_tick);
+                tp->timer.expires = jiffies + next_tick;
                 add_timer(&tp->timer);
         }
 }
@@ -1068,20 +653,9 @@
                       		" (queue head)" : "");
 	}
 
-        /* Soft reset the chip. */
-        //outb(RESET, ioaddr + cr);
-        /* Check that the chip has finished the reset. */
-        /*
-        for (i = 1000; i > 0; i--)
-                if ((inb(ioaddr + cr) & RESET) == 0)
-                        break;
-        */
 
         tp->cur_rx = 0; 
-        /* Must enable Tx/Rx before setting transfer thresholds! */
-        /*
-        set_rx_mode(dev);
-        */
+
         {       /* Save the unsent Tx packets. */
                 struct sk_buff *saved_skb[NUM_TX_DESC], *skb;
                 int j;
@@ -1095,11 +669,6 @@
                         memcpy((unsigned char*)(tp->tx_buf[i].buf),
                                                 skb->data, skb->len);
                         tp->tx_buf[i].cmdsts = OWN | skb->len;
-                        /* Note: the chip doesn't have auto-pad! */
-                        /*
-                        outl(tp->tx_flag|(skb->len>=ETH_ZLEN?skb->len:ETH_ZLEN),
-                                 ioaddr + TxStatus0 + i*4);
-                        */
                 }
                 outl(TxENA, ioaddr + cr);
                 tp->cur_tx = i;
@@ -1116,28 +685,27 @@
         dev->trans_start = jiffies;
         tp->stats.tx_errors++;
         /* Enable all known interrupts by setting the interrupt mask. */
-        outl((RxOK|RxERR|RxORN|RxSOVR|TxOK|TxERR|TxURN), ioaddr + imr);
+        outl((RxRCMP|RxOK|RxERR|RxORN|RxSOVR|TxOK|TxERR|TxURN), ioaddr + imr);
         return;
 }
 
-
-/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
+/* Reset (Initialize) the Tx rings, along with various 'dev' bits. */
 static void
-sis900_init_ring(struct device *dev)
+sis900_reset_tx_ring(struct device *dev)
 {
         struct sis900_private *tp = (struct sis900_private *)dev->priv;
+        long ioaddr = dev->base_addr; 
         int i;
-
+	
         tp->tx_full = 0;
-        tp->cur_rx = 0;
         tp->dirty_tx = tp->cur_tx = 0;
-
+	
         /* Tx Buffer */
         for (i = 0; i < NUM_TX_DESC; i++) {
-                tp->tx_skbuff[i] = 0;
-                tp->tx_buf[i].buf = &tp->tx_bufs[i*TX_BUF_SIZE];
+		tp->tx_skbuff[i] = 0;
+		tp->tx_buf[i].buf = &tp->tx_bufs[i*TX_BUF_SIZE];
                 tp->tx_buf[i].bufPhys =
-                                virt_to_bus(&tp->tx_bufs[i*TX_BUF_SIZE]);
+			virt_to_bus(&tp->tx_bufs[i*TX_BUF_SIZE]);
         }
 
         /* Tx Descriptor */
@@ -1152,6 +720,19 @@
                 tp->tx_buf[i].cmdsts=0;
         }
 
+        outl((u32)tp->tx_buf[0].physAddr, ioaddr + txdp); 
+}
+
+/* Reset (Initialize) the Rx rings, along with various 'dev' bits. */ 
+static void 
+sis900_reset_rx_ring(struct device *dev) 
+{ 
+        struct sis900_private *tp = (struct sis900_private *)dev->priv; 
+        long ioaddr = dev->base_addr; 
+        int i; 
+ 
+        tp->cur_rx = 0; 
+
         /* Rx Buffer */
         for (i = 0; i < NUM_RX_DESC; i++) {
                 tp->rx_buf[i].buf = &tp->rx_bufs[i*RX_BUF_SIZE];
@@ -1170,6 +751,8 @@
                                 virt_to_bus(&(tp->rx_buf[i].plink));
                 tp->rx_buf[i].cmdsts=RX_BUF_SIZE;
         }
+
+        outl((u32)tp->rx_buf[0].physAddr, ioaddr + rxdp); 
 }
 
 static int
@@ -1241,7 +824,8 @@
 
 #if defined(__i386__)
         /* A lock to prevent simultaneous entry bug on Intel SMP machines. */
-        if (test_and_set_bit(0, (void*)&dev->interrupt)) {
+        if (test_and_set_bit(0, (void*)&dev->interrupt)
+) {
                 printk(KERN_INFO "%s: SMP simultaneous entry of "
                                 "an interrupt handler.\n", dev->name);
                 dev->interrupt = 0;     /* Avoid halting machine. */
@@ -1258,8 +842,6 @@
 
         do {
                 status = inl(ioaddr + isr);
-                /* Acknowledge all of the current interrupt sources ASAP. */
-                outl(status, ioaddr + isr); // ?????
 
                 if (sis900_debug > 4)
                         printk(KERN_INFO "%s: interrupt  status=%#4.4x "
@@ -1267,6 +849,7 @@
                                 dev->name, status, inl(ioaddr + isr));
 
                 if ((status & (TxURN|TxERR|TxOK | RxORN|RxERR|RxOK)) == 0) {
+			/* nothing intresting happened */
                         break;
                 }
 
@@ -1354,7 +937,7 @@
                                 /* Free the original skb. */
                                 if (sis900_debug > 2)
                                         printk(KERN_INFO "Free original skb\n");
-                                dev_free_skb(tp->tx_skbuff[entry]);
+                                dev_kfree_skb(tp->tx_skbuff[entry]);
                                 tp->tx_skbuff[entry] = 0;
                         } // for dirty
 
@@ -1419,8 +1002,6 @@
         return;
 }
 
-/* The data sheet doesn't describe the Rx ring at all, so I'm guessing at the
-   field alignments and semantics. */
 static int sis900_rx(struct device *dev)
 {
         struct sis900_private *tp = (struct sis900_private *)dev->priv;
@@ -1533,6 +1114,7 @@
                            dev->name, cur_rx,
                            inb(ioaddr + cr));
         tp->cur_rx = cur_rx;
+	outl( RxENA , ioaddr + cr );  /* LCS */
         return 0;
 }
 
@@ -1546,10 +1128,6 @@
         dev->start = 0;
         dev->tbusy = 1;
 
-        if (sis900_debug > 1)
-                printk(KERN_DEBUG"%s: Shutting down ethercard, status was 0x%4.4x.\n",
-                           dev->name, inl(ioaddr + isr));
-
         /* Disable interrupts by clearing the interrupt mask. */
         outl(0x0000, ioaddr + imr);
 
@@ -1562,7 +1140,7 @@
 
         for (i = 0; i < NUM_TX_DESC; i++) {
                 if (tp->tx_skbuff[i])
-                        dev_free_skb(tp->tx_skbuff[i]);
+                        dev_kfree_skb(tp->tx_skbuff[i]);
                 tp->tx_skbuff[i] = 0;
         }
         kfree(tp->rx_bufs);
@@ -1581,13 +1159,13 @@
         u16 *data = (u16 *)&rq->ifr_data;
 
         switch(cmd) {
-        case SIOCDEVPRIVATE:            /* Get the address of the PHY in use. */
-                data[0] = tp->phys[tp->phy_idx];
+        case SIOCDEVPRIVATE:            	/* Get the address of the PHY in use. */
+                data[0] = tp->mii->phy_addr;
                 /* Fall Through */
-        case SIOCDEVPRIVATE+1:          /* Read the specified MII register. */
+        case SIOCDEVPRIVATE+1:          	/* Read the specified MII register. */
                 data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f);
                 return 0;
-        case SIOCDEVPRIVATE+2:          /* Write the specified MII register */
+        case SIOCDEVPRIVATE+2:          	/* Write the specified MII register */
                 if (!suser())
                         return -EPERM;
                 mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);
@@ -1727,17 +1305,17 @@
         retnVal = elMIIpollBit(dev, phy_id, MII_CONTROL, MIICNTL_RST_AUTO,
 				FALSE,&status);
 	if (!retnVal) {
-		printk(KERN_INFO "Not wait for Reset Complete\n");
+		printk(KERN_INFO "%s: Not wait for Reset Complete\n", dev->name);
 	}
         retnVal = elMIIpollBit(dev, phy_id, MII_STATUS, MIISTAT_AUTO_DONE,
 				TRUE, &status);
 	if (!retnVal) {
-		printk(KERN_INFO "Not wait for AutoNego Complete\n");
+		printk(KERN_INFO "%s: Not wait for AutoNego Complete\n", dev->name);
 	}
         retnVal = elMIIpollBit(dev, phy_id, MII_STATUS, MIISTAT_LINK,
 				TRUE, &status);
 	if (!retnVal) {
-		printk(KERN_INFO "Not wait for Link Complete\n");
+		printk(KERN_INFO "%s: Not wait for Link Complete\n", dev->name);
 	}
         if (status & MIISTAT_LINK) {
                 elPMDreadMode(dev, phy_id, speed, duplex);
@@ -1814,9 +1392,8 @@
                 for (i=0 ; i<8 ; i++)
                         mc_filter[i]=0xffff;
         } else if ((dev->mc_count > multicast_filter_limit)
-                           ||  (dev->flags & IFF_ALLMULTI)) {
-                rx_mode = ACCEPT_ALL_BCASTS | ACCEPT_ALL_MCASTS |
-                                ACCEPT_CAM_QUALIFIED;
+				   ||  (dev->flags & IFF_ALLMULTI)) {
+                rx_mode = ACCEPT_ALL_BCASTS | ACCEPT_ALL_MCASTS | ACCEPT_CAM_QUALIFIED;
                 for (i=0 ; i<8 ; i++)
                         mc_filter[i]=0xffff;
         } else {
@@ -1875,49 +1452,40 @@
 static void sis900_reset(struct device *dev)
 {
         long ioaddr = dev->base_addr;
-
+	
         outl(0, ioaddr + ier);
         outl(0, ioaddr + imr);
         outl(0, ioaddr + rfcr);
 
         outl(RxRESET | TxRESET | RESET, ioaddr + cr);
         outl(PESEL, ioaddr + cfg);
-
+	
         set_rx_mode(dev);
 }
 
 #ifdef MODULE
 int init_module(void)
 {
-        return sis900_probe(0);
+        return sis900_probe(NULL);
 }
 
 void
 cleanup_module(void)
 {
-        struct device *next_dev;
+	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
+	while (root_sis900_dev) {
+		struct sis900_private *tp =
+			(struct sis900_private *)root_sis900_dev->priv;
+		struct device *next_dev = tp->next_module;
+		
+		unregister_netdev(root_sis900_dev);
+		release_region(root_sis900_dev->base_addr,
+			       tp->mac->io_size);
+		kfree(tp);
+		kfree(root_sis900_dev);
 
-        /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
-        while (root_sis900_dev) {
-                struct sis900_private *tp =
-                        (struct sis900_private *)root_sis900_dev->priv;
-                next_dev = tp->next_module;
-                unregister_netdev(root_sis900_dev);
-                release_region(root_sis900_dev->base_addr,
-                                           pci_tbl[tp->chip_id].io_size);
-                kfree(tp);
-                kfree(root_sis900_dev);
-                root_sis900_dev = next_dev;
+		root_sis900_dev = next_dev;
         }
 }
 
 #endif  /* MODULE */
-/*
- * Local variables:
- *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c sis900.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
- *  SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c sis900.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
- *  c-indent-level: 4
- *  c-basic-offset: 4
- *  tab-width: 4
- * End:
- */
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/drivers/net/sis900.h linux.14p1/drivers/net/sis900.h
--- linux.vanilla/drivers/net/sis900.h	Thu Jan  1 01:00:00 1970
+++ linux.14p1/drivers/net/sis900.h	Fri Oct 22 22:25:35 1999
@@ -0,0 +1,256 @@
+/* sis900.h Definitions for SiS ethernet controllers including 7014/7016 and 900 
+ * Copyrigth 1999 Silicon Integrated System Corporation
+ * References:
+ *   SiS 7016 Fast Ethernet PCI Bus 10/100 Mbps LAN Controller with OnNow Support,
+ *	preliminary Rev. 1.0 Jan. 14, 1998
+ *   SiS 900 Fast Ethernet PCI Bus 10/100 Mbps LAN Single Chip with OnNow Support,
+ *	preliminary Rev. 1.0 Nov. 10, 1998
+ *   SiS 7014 Single Chip 100BASE-TX/10BASE-T Physical Layer Solution,
+ *	preliminary Rev. 1.0 Jan. 18, 1998
+ *   http://www.sis.com.tw/support/databook.htm
+ */
+
+/* MAC operationl registers of SiS 7016 and SiS 900 ehternet controller */
+/* The I/O extent, SiS 900 needs 256 bytes of io address */
+#define SIS900_TOTAL_SIZE 0x100
+
+/* Symbolic offsets to registers. */
+enum SIS900_registers {
+	cr=0x0,                 //Command Register
+	cfg=0x4,                //Configuration Register
+	mear=0x8,               //EEPROM Access Register
+	ptscr=0xc,              //PCI Test Control Register
+	isr=0x10,               //Interrupt Status Register
+	imr=0x14,               //Interrupt Mask Register
+	ier=0x18,               //Interrupt Enable Register
+	epar=0x18,              //Enhanced PHY Access Register
+	txdp=0x20,              //Transmit Descriptor Pointer Register
+        txcfg=0x24,             //Transmit Configuration Register
+        rxdp=0x30,              //Receive Descriptor Pointer Register
+        rxcfg=0x34,             //Receive Configuration Register
+        flctrl=0x38,            //Flow Control Register
+        rxlen=0x3c,             //Receive Packet Length Register
+        rfcr=0x48,              //Receive Filter Control Register
+        rfdr=0x4C,              //Receive Filter Data Register
+        pmctrl=0xB0,            //Power Management Control Register
+        pmer=0xB4               //Power Management Wake-up Event Register
+};
+
+/* Symbolic names for bits in various registers */
+enum sis900_command_register_bits {
+	RESET   = 0x00000100, SWI = 0x00000080, RxRESET = 0x00000020,
+	TxRESET = 0x00000010, RxDIS = 0x00000008, RxENA = 0x00000004,
+	TxDIS   = 0x00000002, TxENA = 0x00000001
+};
+
+enum sis900_configuration_register_bits {
+	DESCRFMT = 0x00000100 /* 7016 specific */, REQALG = 0x00000080,
+	SB    = 0x00000040, POW = 0x00000020, EXD = 0x00000010, 
+	PESEL = 0x00000008, LPM = 0x00000004, BEM = 0x00000001
+};
+
+enum sis900_eeprom_access_reigster_bits {
+	MDC  = 0x00000040, MDDIR = 0x00000020, MDIO = 0x00000010, /* 7016 specific */ 
+	EECS = 0x00000008, EECLK = 0x00000004, EEDO = 0x00000002,
+	EEDI = 0x00000001
+};
+
+enum sis900_interrupt_register_bits {
+	WKEVT  = 0x10000000, TxPAUSEEND = 0x08000000, TxPAUSE = 0x04000000,
+	TxRCMP = 0x02000000, RxRCMP = 0x01000000, DPERR = 0x00800000,
+	SSERR  = 0x00400000, RMABT  = 0x00200000, RTABT = 0x00100000,
+	RxSOVR = 0x00010000, HIBERR = 0x00008000, SWINT = 0x00001000,
+	MIBINT = 0x00000800, TxURN  = 0x00000400, TxIDLE  = 0x00000200,
+	TxERR  = 0x00000100, TxDESC = 0x00000080, TxOK  = 0x00000040,
+	RxORN  = 0x00000020, RxIDLE = 0x00000010, RxEARLY = 0x00000008,
+	RxERR  = 0x00000004, RxDESC = 0x00000002, RxOK  = 0x00000001
+};
+
+enum sis900_interrupt_enable_reigster_bits {
+	IE = 0x00000001
+};
+
+/* maximum dma burst fro transmission and receive*/
+#define MAX_DMA_RANGE	7	/* actually 0 means MAXIMUM !! */
+#define TxMXDMA_shift   	20
+#define RxMXDMA_shift    20
+#define TX_DMA_BURST    	0
+#define RX_DMA_BURST    	0
+
+/* transmit FIFO threshholds */
+#define TX_FILL_THRESH   16
+#define TxFILLT_shift   	8
+#define TxDRNT_shift    	0
+#define TxDRNT_100      (1536>>5)
+#define TxDRNT_10		16 
+
+enum sis900_transmit_config_register_bits {
+	TxCSI = 0x80000000, TxHBI = 0x40000000, TxMLB = 0x20000000,
+	TxATP = 0x10000000, TxIFG = 0x0C000000, TxFILLT = 0x00003F00,
+	TxDRNT = 0x0000003F
+};
+
+/* recevie FFIFO thresholds */
+#define RxDRNT_shift     1
+#define RxDRNT_100	8
+#define RxDRNT_10		8 
+
+enum sis900_reveive_config_register_bits {
+	RxAEP  = 0x80000000, RxARP = 0x40000000, RxATP   = 0x10000000,
+	RxAJAB = 0x08000000, RxDRNT = 0x0000007F
+};
+
+#define RFAA_shift      28
+#define RFADDR_shift    16
+
+enum sis900_receive_filter_control_register_bits {
+	RFEN  = 0x80000000, RFAAB = 0x40000000, RFAAM = 0x20000000,
+	RFAAP = 0x10000000, RFPromiscuous = (RFAAB|RFAAM|RFAAP)
+};
+
+enum sis900_reveive_filter_data_mask {
+	RFDAT =  0x0000FFFF
+};
+
+/* EEPROM Addresses */
+enum sis900_eeprom_address {
+	EEPROMSignature = 0x00, EEPROMVendorID = 0x02, EEPROMDeviceID = 0x03,
+	EEPROMMACAddr   = 0x08, EEPROMChecksum = 0x0b
+};
+
+/* The EEPROM commands include the alway-set leading bit. Refer to NM93Cxx datasheet */
+enum sis900_eeprom_command {
+	EEread = 0x0180, EEwrite = 0x0140, EEerase = 0x01C0, 
+	EEwriteEnable = 0x0130, EEwriteDisable = 0x0100,
+	EEeraseAll = 0x0120, EEwriteAll = 0x0110, 
+	EEaddrMask = 0x013F, EEcmdShift = 16
+};
+
+/* Manamgement Data I/O (mdio) frame */
+#define MIIread         0x6000
+#define MIIwrite        0x5002
+#define MIIpmdShift     7
+#define MIIregShift     2
+#define MIIcmdLen       16
+#define MIIcmdShift     16
+
+/* Buffer Descriptor */
+#define OWN             0x80000000
+#define MORE            0x40000000
+#define INTR            0x20000000
+#define OK              0x08000000
+#define DSIZE           0x00000FFF
+
+#define SUPCRC          0x10000000
+#define ABORT           0x04000000
+#define UNDERRUN        0x02000000
+#define NOCARRIER       0x01000000
+#define DEFERD          0x00800000
+#define EXCDEFER        0x00400000
+#define OWCOLL          0x00200000
+#define EXCCOLL         0x00100000
+#define COLCNT          0x000F0000
+
+#define INCCRC          0x10000000
+//      ABORT           0x04000000
+#define OVERRUN         0x02000000
+#define DEST            0x01800000
+#define BCAST           0x01800000
+#define MCAST           0x01000000
+#define UNIMATCH        0x00800000
+#define TOOLONG         0x00400000
+#define RUNT            0x00200000
+#define RXISERR         0x00100000
+#define CRCERR          0x00080000
+#define FAERR           0x00040000
+#define LOOPBK          0x00020000
+#define RXCOL           0x00010000
+
+#define RXSTS_shift     18
+
+/* MII register offsets */
+#define MII_CONTROL             0x0000
+#define MII_STATUS              0x0001
+#define MII_PHY_ID0             0x0002
+#define MII_PHY_ID1             0x0003
+#define MII_ANAR                0x0004
+#define MII_ANLPAR              0x0005
+#define MII_ANER                0x0006
+/* MII Control register bit definitions. */
+#define MIICNTL_FDX             0x0100
+#define MIICNTL_RST_AUTO        0x0200
+#define MIICNTL_ISOLATE         0x0400
+#define MIICNTL_PWRDWN          0x0800
+#define MIICNTL_AUTO            0x1000
+#define MIICNTL_SPEED           0x2000
+#define MIICNTL_LPBK            0x4000
+#define MIICNTL_RESET           0x8000
+/* MII Status register bit significance. */
+#define MIISTAT_EXT             0x0001
+#define MIISTAT_JAB             0x0002
+#define MIISTAT_LINK            0x0004
+#define MIISTAT_CAN_AUTO        0x0008
+#define MIISTAT_FAULT           0x0010
+#define MIISTAT_AUTO_DONE       0x0020
+#define MIISTAT_CAN_T           0x0800
+#define MIISTAT_CAN_T_FDX       0x1000
+#define MIISTAT_CAN_TX          0x2000
+#define MIISTAT_CAN_TX_FDX      0x4000
+#define MIISTAT_CAN_T4          0x8000
+/* MII NWAY Register Bits ...
+** valid for the ANAR (Auto-Negotiation Advertisement) and
+** ANLPAR (Auto-Negotiation Link Partner) registers */
+#define MII_NWAY_NODE_SEL       0x001f
+#define MII_NWAY_CSMA_CD        0x0001
+#define MII_NWAY_T              0x0020
+#define MII_NWAY_T_FDX          0x0040
+#define MII_NWAY_TX             0x0080
+#define MII_NWAY_TX_FDX         0x0100
+#define MII_NWAY_T4             0x0200
+#define MII_NWAY_RF             0x2000
+#define MII_NWAY_ACK            0x4000
+#define MII_NWAY_NP             0x8000
+
+/* MII Auto-Negotiation Expansion Register Bits */
+#define MII_ANER_PDF            0x0010
+#define MII_ANER_LP_NP_ABLE     0x0008
+#define MII_ANER_NP_ABLE        0x0004
+#define MII_ANER_RX_PAGE        0x0002
+#define MII_ANER_LP_AN_ABLE     0x0001
+#define HALF_DUPLEX                     1
+#define FDX_CAPABLE_DUPLEX_UNKNOWN      2
+#define FDX_CAPABLE_HALF_SELECTED       3
+#define FDX_CAPABLE_FULL_SELECTED       4
+#define HW_SPEED_UNCONFIG       0
+#define HW_SPEED_10_MBPS        10
+#define HW_SPEED_100_MBPS       100
+#define HW_SPEED_DEFAULT        (HW_SPEED_10_MBPS)
+
+#define ACCEPT_ALL_PHYS         0x01
+#define ACCEPT_ALL_MCASTS       0x02
+#define ACCEPT_ALL_BCASTS       0x04
+#define ACCEPT_ALL_ERRORS       0x08
+#define ACCEPT_CAM_QUALIFIED    0x10
+#define MAC_LOOPBACK            0x20
+
+//#define FDX_CAPABLE_FULL_SELECTED     4
+#define CRC_SIZE                4
+#define MAC_HEADER_SIZE         14
+
+#define TX_BUF_SIZE     1536
+#define RX_BUF_SIZE     1536
+
+#define NUM_TX_DESC     16      	/* Number of Tx descriptor registers. */
+#define NUM_RX_DESC     8       	/* Number of Rx descriptor registers. */
+
+#define TRUE            1
+#define FALSE           0
+
+/* PCI stuff, should be move to pic.h */
+#define PCI_DEVICE_ID_SI_900	0x900   
+#define PCI_DEVICE_ID_SI_7016	0x7016  
+
+/* ioctl for accessing MII transveiver */
+#define SIOCGMIIPHY (SIOCDEVPRIVATE)		/* Get the PHY in use. */
+#define SIOCGMIIREG (SIOCDEVPRIVATE+1)		/* Read a PHY register. */
+#define SIOCSMIIREG (SIOCDEVPRIVATE+2)		/* Write a PHY register */
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/drivers/pci/oldproc.c linux.14p1/drivers/pci/oldproc.c
--- linux.vanilla/drivers/pci/oldproc.c	Wed Oct 20 01:12:39 1999
+++ linux.14p1/drivers/pci/oldproc.c	Fri Oct 22 21:24:50 1999
@@ -526,6 +526,7 @@
 	DEVICE( INTEL,		INTEL_82441,	"82441FX Natoma"),
 	DEVICE( INTEL,		INTEL_82380FB,	"82380FB Mobile"),
 	DEVICE( INTEL,		INTEL_82439,	"82439HX Triton II"),
+	DEVICE(	INTEL,		INTEL_MEGARAID,	"OEM MegaRAID Controller"),
 	DEVICE(	INTEL,		INTEL_82371SB_0,"82371SB PIIX3 ISA"),
 	DEVICE(	INTEL,		INTEL_82371SB_1,"82371SB PIIX3 IDE"),
 	DEVICE( INTEL,		INTEL_82371SB_2,"82371SB PIIX3 USB"),
@@ -536,13 +537,16 @@
 	DEVICE( INTEL,		INTEL_82371AB_2,"82371AB PIIX4 USB"),
 	DEVICE( INTEL,		INTEL_82371AB_3,"82371AB PIIX4 ACPI"),
 	DEVICE( INTEL,		INTEL_82443LX_0,"440LX - 82443LX PAC Host"),
-	DEVICE( COMPUTONE,	COMPUTONE_IP2EX, "Computone IntelliPort Plus"),
 	DEVICE( INTEL,		INTEL_82443LX_1,"440LX - 82443LX PAC AGP"),
 	DEVICE( INTEL,		INTEL_82443BX_0,"440BX - 82443BX Host"),
 	DEVICE( INTEL,		INTEL_82443BX_1,"440BX - 82443BX AGP"),
 	DEVICE( INTEL,		INTEL_82443BX_2,"440BX - 82443BX Host (no AGP)"),
 	DEVICE( INTEL,		INTEL_P6,	"Orion P6"),
- 	DEVICE( INTEL,		INTEL_82450GX,	"82450GX Orion P6"),
+ 	DEVICE( INTEL,		INTEL_82450GX,	"450KX/GX [Orion] - 82454KX/GX PCI Bridge"),
+ 	DEVICE( INTEL,		INTEL_82453GX,	"450KX/GX [Orion] - 82453KX/GX Memory Controller"),
+ 	DEVICE( INTEL,		INTEL_82451NX,	"450NX - 82451NX Memory & I/O Controller"),
+ 	DEVICE( INTEL,		INTEL_82454NX,	"450NX - 82454NX PCI Expander Bridge"),
+	DEVICE( COMPUTONE,	COMPUTONE_IP2EX, "Computone IntelliPort Plus"),
 	DEVICE(	KTI,		KTI_ET32P2,	"ET32P2"),
 	DEVICE( ADAPTEC,	ADAPTEC_7810,	"AIC-7810 RAID"),
 	DEVICE( ADAPTEC,	ADAPTEC_7821,	"AIC-7860"),
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/drivers/scsi/fdomain.c linux.14p1/drivers/scsi/fdomain.c
--- linux.vanilla/drivers/scsi/fdomain.c	Tue Dec 29 19:44:53 1998
+++ linux.14p1/drivers/scsi/fdomain.c	Fri Oct 22 22:32:09 1999
@@ -875,6 +875,8 @@
    int              retcode;
    struct Scsi_Host *shpnt;
 #if DO_DETECT
+   int i = 0;
+   int j = 0;
    const int        buflen = 255;
    Scsi_Cmnd        SCinit;
    unsigned char    do_inquiry[] =       { INQUIRY, 0, 0, 0, buflen, 0 };
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/drivers/scsi/gdth.h linux.14p1/drivers/scsi/gdth.h
--- linux.vanilla/drivers/scsi/gdth.h	Sat Aug 14 02:25:41 1999
+++ linux.14p1/drivers/scsi/gdth.h	Fri Oct 22 23:26:35 1999
@@ -249,8 +249,10 @@
 #define HIGH_PRI        0x08
 
 /* data directions */
+#ifndef HOSTS_C
 #define DATA_IN         0x01000000L             /* data from target */
 #define DATA_OUT        0x00000000L             /* data to target */
+#endif
 
 /* BMIC registers (EISA controllers) */
 #define ID0REG          0x0c80                  /* board ID */
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/drivers/scsi/ips.h linux.14p1/drivers/scsi/ips.h
--- linux.vanilla/drivers/scsi/ips.h	Wed Oct 20 01:12:41 1999
+++ linux.14p1/drivers/scsi/ips.h	Fri Oct 22 23:26:35 1999
@@ -233,6 +233,7 @@
 /*
  * DCDB Table Equates
  */
+#ifndef HOSTS_C 
    #define NO_DISCONNECT                0x00
    #define DISCONNECT_ALLOWED           0x80
    #define NO_AUTO_REQUEST_SENSE        0x40
@@ -243,7 +244,6 @@
    #define TIMEOUT10                    0x10
    #define TIMEOUT60                    0x20
    #define TIMEOUT20M                   0x30
-
 /*
  * Host adapter Flags (bit numbers)
  */
@@ -256,7 +256,7 @@
  */
    #define SCB_ACTIVE                   0x00001
    #define SCB_WAITING                  0x00002
-
+#endif /* HOSTS_C */
 /*
  * Passthru stuff
  */
@@ -590,6 +590,8 @@
 /*
  * Inquiry Data Format
  */
+#ifndef HOSTS_C
+
 typedef struct {
    u8        DeviceType:5;
    u8        DeviceTypeQualifier:3;
@@ -614,6 +616,7 @@
    u8        Reserved3[40];
 } INQUIRYDATA, *PINQUIRYDATA;
 
+#endif
 /*
  * Read Capacity Data Format
  */
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/drivers/scsi/megaraid.h linux.14p1/drivers/scsi/megaraid.h
--- linux.vanilla/drivers/scsi/megaraid.h	Sat Aug 28 20:00:57 1999
+++ linux.14p1/drivers/scsi/megaraid.h	Fri Oct 22 23:26:35 1999
@@ -11,6 +11,7 @@
 #define BOARD_QUARTZ            0x08000000L
 #define BOARD_40LD              0x04000000L
 
+#ifndef HOSTS_C
 #define SCB_FREE     0x0
 #define SCB_ACTIVE   0x1
 #define SCB_WAITQ    0x2
@@ -18,6 +19,7 @@
 #define SCB_COMPLETE 0x4
 #define SCB_ABORTED  0x5
 #define SCB_RESET    0x6
+#endif
 
 #define MEGA_CMD_TIMEOUT        10
 
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/drivers/scsi/psi240i.h linux.14p1/drivers/scsi/psi240i.h
--- linux.vanilla/drivers/scsi/psi240i.h	Mon Dec 28 06:19:22 1998
+++ linux.14p1/drivers/scsi/psi240i.h	Fri Oct 22 23:26:35 1999
@@ -211,6 +211,8 @@
 	}	READ_CAPACITY_DATA, *PREAD_CAPACITY_DATA;
 
 // SCSI inquiry data
+#ifndef HOSTS_C
+
 typedef struct _INQUIRYDATA
 	{
 	UCHAR DeviceType			:5;
@@ -235,6 +237,7 @@
     UCHAR VendorSpecific[20];
     UCHAR Reserved3[40];
 	}	INQUIRYDATA, *PINQUIRYDATA;
+#endif
 
 // IDE IDENTIFY data
 typedef struct _IDENTIFY_DATA
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/drivers/scsi/qlogicfc.c linux.14p1/drivers/scsi/qlogicfc.c
--- linux.vanilla/drivers/scsi/qlogicfc.c	Wed Oct 20 01:12:41 1999
+++ linux.14p1/drivers/scsi/qlogicfc.c	Fri Oct 22 21:25:11 1999
@@ -1855,7 +1855,7 @@
 
 static int isp2x00_init(struct Scsi_Host *sh)
 {
-	u_int io_base;
+	u_long io_base;
 	struct isp2x00_hostdata *hostdata;
 	u_char revision;
 	u_int irq;
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/drivers/scsi/qlogicisp.c linux.14p1/drivers/scsi/qlogicisp.c
--- linux.vanilla/drivers/scsi/qlogicisp.c	Wed Oct 20 01:12:42 1999
+++ linux.14p1/drivers/scsi/qlogicisp.c	Fri Oct 22 21:25:11 1999
@@ -1262,6 +1262,13 @@
 		pci_write_config_byte(pdev, PCI_LATENCY_TIMER, latency_timer);
 	}
 #endif
+#ifdef __alpha__
+	/* Force ALPHA to use bus I/O and not bus MEM. 
+	   This is to avoid having to use HAE_MEM registers,
+	   which is broken on some platforms and with SMP.
+	*/
+	command &= ~PCI_COMMAND_MEMORY;
+#endif
 
 	if ((command & PCI_COMMAND_MEMORY) &&
 	    ((mem_base & 1) == 0)) {
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/drivers/scsi/sym53c416.h linux.14p1/drivers/scsi/sym53c416.h
--- linux.vanilla/drivers/scsi/sym53c416.h	Sun Mar 28 19:04:11 1999
+++ linux.14p1/drivers/scsi/sym53c416.h	Fri Oct 22 23:26:35 1999
@@ -22,7 +22,9 @@
 #include <linux/version.h>
 #endif
 
+#ifndef LinuxVersionCode
 #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
+#endif
 
 #include <linux/types.h>
 #include <linux/kdev_t.h>
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/drivers/scsi/sym53c8xx_defs.h linux.14p1/drivers/scsi/sym53c8xx_defs.h
--- linux.vanilla/drivers/scsi/sym53c8xx_defs.h	Wed Oct 20 01:12:47 1999
+++ linux.14p1/drivers/scsi/sym53c8xx_defs.h	Fri Oct 22 23:26:35 1999
@@ -66,8 +66,9 @@
 #endif
 #include <linux/config.h>
 
+#ifndef LinuxVersionCode
 #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
-
+#endif
 /*
  * NCR PQS/PDS special device support.
  */
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/drivers/scsi/u14-34f.h linux.14p1/drivers/scsi/u14-34f.h
--- linux.vanilla/drivers/scsi/u14-34f.h	Sun Mar 28 19:04:08 1999
+++ linux.14p1/drivers/scsi/u14-34f.h	Fri Oct 22 23:26:35 1999
@@ -18,7 +18,9 @@
 
 #define U14_34F_VERSION "4.33.00"
 
+#ifndef LinuxVersionCode
 #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
+#endif
 
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,101)
 
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/drivers/sound/Config.in linux.14p1/drivers/sound/Config.in
--- linux.vanilla/drivers/sound/Config.in	Wed Oct 20 01:12:47 1999
+++ linux.14p1/drivers/sound/Config.in	Fri Oct 22 22:52:53 1999
@@ -115,8 +115,6 @@
       int 'SB MPU401 IRQ (Jazz16, SM Wave and ES1688) Check from manual of the card' CONFIG_SB_MPU_IRQ -1
   fi
   
-  dep_tristate 'Generic OPL2/OPL3 FM synthesizer support' CONFIG_SOUND_ADLIB $CONFIG_SOUND_OSS
-  
   dep_tristate 'Gravis Ultrasound support' CONFIG_SOUND_GUS $CONFIG_SOUND_OSS
   if [ "$CONFIG_SOUND_GUS" = "y" -o "$CONFIG_SOUND_GUS" = "m" ]; then
       bool '16 bit sampling option of GUS (_NOT_ GUS MAX)' CONFIG_GUS16 
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/drivers/sound/Makefile linux.14p1/drivers/sound/Makefile
--- linux.vanilla/drivers/sound/Makefile	Wed Oct 20 01:12:47 1999
+++ linux.14p1/drivers/sound/Makefile	Fri Oct 22 22:52:53 1999
@@ -43,7 +43,6 @@
 obj-$(CONFIG_SOUND)		+= soundcore.o
 obj-$(CONFIG_DMASOUND)		+= dmasound.o
 obj-$(CONFIG_SOUND_OSS)		+= sound.o
-obj-$(CONFIG_SOUND_ADLIB)	+= adlib_card.o opl3.o
 obj-$(CONFIG_SOUND_CS4232)	+= cs4232.o ad1848.o 
 
 # In theory, there's probably no reason to include the uart401 code
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/drivers/sound/ac97.h linux.14p1/drivers/sound/ac97.h
--- linux.vanilla/drivers/sound/ac97.h	Wed Oct 20 01:12:47 1999
+++ linux.14p1/drivers/sound/ac97.h	Fri Oct 22 23:39:41 1999
@@ -33,6 +33,19 @@
 
 /* registers 0x0028 - 0x0058 are reserved */
 
+/* AC'97 2.0 */
+#define AC97_EXTENDED_ID	0x0028	/* Extended Audio ID */
+#define AC97_EXTENDED_STATUS	0x002A	/* Extended Audio Status */
+#define AC97_PCM_FRONT_DAC_RATE 0x002C  /* PCM Front DAC Rate */
+#define AC97_PCM_SURR_DAC_RATE  0x002E  /* PCM Surround DAC Rate */
+#define AC97_PCM_LFE_DAC_RATE   0x0030  /* PCM LFE DAC Rate */
+#define AC97_PCM_LR_DAC_RATE	0x0032	/* PCM LR DAC Rate */
+#define AC97_PCM_MIC_ADC_RATE   0x0034  /* PCM MIC ADC Rate */
+#define AC97_CENTER_LFE_MASTER  0x0036  /* Center + LFE Master Volume */
+#define AC97_SURROUND_MASTER    0x0038  /* Surround (Rear) Master Volume */
+#define AC97_RESERVED_3A	0x003A	/* Reserved */
+/* range 0x3c-0x58 - MODEM */
+
 /* registers 0x005a - 0x007a are vendor reserved */
 
 #define  AC97_VENDOR_ID1         0x007c
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/drivers/sound/adlib_card.c linux.14p1/drivers/sound/adlib_card.c
--- linux.vanilla/drivers/sound/adlib_card.c	Thu May 14 18:33:17 1998
+++ linux.14p1/drivers/sound/adlib_card.c	Fri Oct 22 22:52:53 1999
@@ -16,8 +16,6 @@
 #include "sound_config.h"
 #include "soundmodule.h"
 
-#ifdef CONFIG_YM3812
-
 void attach_adlib_card(struct address_info *hw_config)
 {
 	hw_config->slots[0] = opl3_init(hw_config->io_base, hw_config->osp);
@@ -69,5 +67,4 @@
 	SOUND_LOCK_END;
 }
 
-#endif
 #endif
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/drivers/sound/es1370.c linux.14p1/drivers/sound/es1370.c
--- linux.vanilla/drivers/sound/es1370.c	Sat Aug 14 02:27:34 1999
+++ linux.14p1/drivers/sound/es1370.c	Fri Oct 22 22:34:17 1999
@@ -101,6 +101,17 @@
  *    15.06.99   0.23  Fix bad allocation bug.
  *                     Thanks to Deti Fliegl <fliegl@in.tum.de>
  *    28.06.99   0.24  Add pci_set_master
+ *    02.08.99   0.25  Added workaround for the "phantom write" bug first
+ *                     documented by Dave Sharpless from Anchor Games
+ *    03.08.99   0.26  adapt to Linus' new __setup/__initcall
+ *                     added kernel command line option "es1370=joystick[,lineout[,micbias]]"
+ *                     removed CONFIG_SOUND_ES1370_JOYPORT_BOOT kludge
+ *    12.08.99   0.27  module_init/__setup fixes
+ *    19.08.99   0.28  SOUND_MIXER_IMIX fixes, reported by Gianluca <gialluca@mail.tiscalinet.it>
+ *    31.08.99   0.29  add spin_lock_init
+ *                     __initlocaldata to fix gcc 2.7.x problems
+ *    03.09.99   0.30  change read semantics for MIDI to match
+ *                     OSS more closely; remove possible wakeup race
  *
  * some important things missing in Ensoniq documentation:
  *
@@ -123,7 +134,6 @@
 
 /*****************************************************************************/
       
-#include <linux/config.h>
 #include <linux/version.h>
 #include <linux/module.h>
 #include <linux/string.h>
@@ -175,12 +185,14 @@
 #define ES1370_REG_DAC2_SCOUNT    0x28
 #define ES1370_REG_ADC_SCOUNT     0x2c
 
-#define ES1370_REG_DAC1_FRAMEADR  0xc30
-#define ES1370_REG_DAC1_FRAMECNT  0xc34
-#define ES1370_REG_DAC2_FRAMEADR  0xc38
-#define ES1370_REG_DAC2_FRAMECNT  0xc3c
-#define ES1370_REG_ADC_FRAMEADR   0xd30
-#define ES1370_REG_ADC_FRAMECNT   0xd34
+#define ES1370_REG_DAC1_FRAMEADR    0xc30
+#define ES1370_REG_DAC1_FRAMECNT    0xc34
+#define ES1370_REG_DAC2_FRAMEADR    0xc38
+#define ES1370_REG_DAC2_FRAMECNT    0xc3c
+#define ES1370_REG_ADC_FRAMEADR     0xd30
+#define ES1370_REG_ADC_FRAMECNT     0xd34
+#define ES1370_REG_PHANTOM_FRAMEADR 0xd38
+#define ES1370_REG_PHANTOM_FRAMECNT 0xd3c
 
 #define ES1370_FMT_U8_MONO     0
 #define ES1370_FMT_U8_STEREO   1
@@ -360,6 +372,13 @@
 
 static struct es1370_state *devs = NULL;
 
+/*
+ * The following buffer is used to point the phantom write channel to,
+ * so that it cannot wreak havoc. The attribute makes sure it doesn't
+ * cross a page boundary and ensures dword alignment for the DMA engine
+ */
+static unsigned char bugbuf[16] __attribute__ ((aligned (16)));
+
 /* --------------------------------------------------------------------- */
 
 extern inline unsigned ld2(unsigned int x)
@@ -779,10 +798,36 @@
 	[SOUND_MIXER_OGAIN]  = { 9, 0xf, 0x0, 0, 0x0000, 1 }    /* mono out */
 };
 
+static void set_recsrc(struct es1370_state *s, unsigned int val)
+{
+	unsigned int i, j;
+
+	for (j = i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
+		if (!(val & (1 << i)))
+			continue;
+		if (!mixtable[i].recmask) {
+			val &= ~(1 << i);
+			continue;
+		}
+		j |= mixtable[i].recmask;
+	}
+	s->mix.recsrc = val;
+	wrcodec(s, 0x12, j & 0xd5);
+	wrcodec(s, 0x13, j & 0xaa);
+	wrcodec(s, 0x14, (j >> 8) & 0x17);
+	wrcodec(s, 0x15, (j >> 8) & 0x0f);
+	i = (j & 0x37f) | ((j << 1) & 0x3000) | 0xc60;
+	if (!s->mix.imix) {
+		i &= 0xff60;  /* mute record and line monitor */
+	}
+	wrcodec(s, 0x10, i);
+	wrcodec(s, 0x11, i >> 8);
+}
+
 static int mixer_ioctl(struct es1370_state *s, unsigned int cmd, unsigned long arg)
 {
 	unsigned long flags;
-	int i, val, j;
+	int i, val;
 	unsigned char l, r, rl, rr;
 
 	VALIDATE_STATE(s);
@@ -887,34 +932,13 @@
 	switch (_IOC_NR(cmd)) {
 
 	case SOUND_MIXER_IMIX:
-		if (arg == 0) 
-			return -EFAULT;
-		get_user_ret(s->mix.imix,(int *)arg, -EFAULT);
-		val = s->mix.recsrc;
-		/* fall through */
+		get_user_ret(s->mix.imix, (int *)arg, -EFAULT);
+		set_recsrc(s, s->mix.recsrc);
+		return 0;
 
 	case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
 		get_user_ret(val, (int *)arg, -EFAULT);
-		for (j = i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
-			if (!(val & (1 << i)))
-				continue;
-			if (!mixtable[i].recmask) {
-				val &= ~(1 << i);
-				continue;
-			}
-			j |= mixtable[i].recmask;
-		}
-		s->mix.recsrc = val;
-		wrcodec(s, 0x12, j & 0xd5);
-		wrcodec(s, 0x13, j & 0xaa);
-		wrcodec(s, 0x14, (j >> 8) & 0x17);
-		wrcodec(s, 0x15, (j >> 8) & 0x0f);
-		i = (j & 0x37f) | ((j << 1) & 0x3000) | 0xc60;
-		if (!s->mix.imix) {
-		     i &= 0xff60;  /* mute record and line monitor */
-		}
-		wrcodec(s, 0x10, i);
-		wrcodec(s, 0x11, i >> 8);
+		set_recsrc(s, val);
 		return 0;
 
 	default:
@@ -1033,7 +1057,7 @@
 
 static int drain_dac1(struct es1370_state *s, int nonblock)
 {
-        struct wait_queue wait = { current, NULL };
+	struct wait_queue wait = { current, NULL };
 	unsigned long flags;
 	int count, tmo;
 	
@@ -1054,9 +1078,10 @@
                         current->state = TASK_RUNNING;
                         return -EBUSY;
                 }
-		tmo = (count * HZ) / dac1_samplerate[(s->ctrl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL];
+		tmo = 3 * HZ * (count + s->dma_dac1.fragsize) / 2
+			/ dac1_samplerate[(s->ctrl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL];
 		tmo >>= sample_shift[(s->sctrl & SCTRL_P1FMT) >> SCTRL_SH_P1FMT];
-		if (!schedule_timeout(tmo ? : 1) && tmo)
+		if (!schedule_timeout(tmo + 1))
 			DBG(printk(KERN_DEBUG "es1370: dma timed out??\n");)
         }
         remove_wait_queue(&s->dma_dac1.wait, &wait);
@@ -1089,9 +1114,10 @@
                         current->state = TASK_RUNNING;
                         return -EBUSY;
                 }
-		tmo = (count * HZ) / DAC2_DIVTOSR((s->ctrl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV);
+		tmo = 3 * HZ * (count + s->dma_dac2.fragsize) / 2
+			/ DAC2_DIVTOSR((s->ctrl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV);
 		tmo >>= sample_shift[(s->sctrl & SCTRL_P2FMT) >> SCTRL_SH_P2FMT];
-		if (!schedule_timeout(tmo ? : 1) && tmo)
+		if (!schedule_timeout(tmo + 1))
 			DBG(printk(KERN_DEBUG "es1370: dma timed out??\n");)
         }
         remove_wait_queue(&s->dma_dac2.wait, &wait);
@@ -2049,6 +2075,7 @@
 static ssize_t es1370_midi_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
 {
 	struct es1370_state *s = (struct es1370_state *)file->private_data;
+	struct wait_queue wait = { current, NULL };
 	ssize_t ret;
 	unsigned long flags;
 	unsigned ptr;
@@ -2059,7 +2086,10 @@
 		return -ESPIPE;
 	if (!access_ok(VERIFY_WRITE, buffer, count))
 		return -EFAULT;
+	if (count == 0)
+		return 0;
 	ret = 0;
+        add_wait_queue(&s->midi.iwait, &wait);
 	while (count > 0) {
 		spin_lock_irqsave(&s->lock, flags);
 		ptr = s->midi.ird;
@@ -2070,15 +2100,25 @@
 		if (cnt > count)
 			cnt = count;
 		if (cnt <= 0) {
-			if (file->f_flags & O_NONBLOCK)
-				return ret ? ret : -EAGAIN;
-			interruptible_sleep_on(&s->midi.iwait);
-			if (signal_pending(current))
-				return ret ? ret : -ERESTARTSYS;
+			if (file->f_flags & O_NONBLOCK) {
+				if (!ret)
+					ret = -EAGAIN;
+				break;
+			}
+			current->state = TASK_INTERRUPTIBLE;
+			schedule();
+			if (signal_pending(current)) {
+				if (!ret)
+					ret = -ERESTARTSYS;
+				break;
+			}
 			continue;
 		}
-		if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt))
-			return ret ? ret : -EFAULT;
+		if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) {
+			if (!ret)
+				ret = -EFAULT;
+			break;
+		}
 		ptr = (ptr + cnt) % MIDIINBUF;
 		spin_lock_irqsave(&s->lock, flags);
 		s->midi.ird = ptr;
@@ -2087,13 +2127,17 @@
 		count -= cnt;
 		buffer += cnt;
 		ret += cnt;
+		break;
 	}
+	current->state = TASK_RUNNING;
+        remove_wait_queue(&s->midi.iwait, &wait);
 	return ret;
 }
 
 static ssize_t es1370_midi_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
 {
 	struct es1370_state *s = (struct es1370_state *)file->private_data;
+	struct wait_queue wait = { current, NULL };
 	ssize_t ret;
 	unsigned long flags;
 	unsigned ptr;
@@ -2104,7 +2148,10 @@
 		return -ESPIPE;
 	if (!access_ok(VERIFY_READ, buffer, count))
 		return -EFAULT;
+	if (count == 0)
+		return 0;
 	ret = 0;
+        add_wait_queue(&s->midi.owait, &wait);
 	while (count > 0) {
 		spin_lock_irqsave(&s->lock, flags);
 		ptr = s->midi.owr;
@@ -2117,15 +2164,25 @@
 		if (cnt > count)
 			cnt = count;
 		if (cnt <= 0) {
-			if (file->f_flags & O_NONBLOCK)
-				return ret ? ret : -EAGAIN;
-			interruptible_sleep_on(&s->midi.owait);
-			if (signal_pending(current))
-				return ret ? ret : -ERESTARTSYS;
+			if (file->f_flags & O_NONBLOCK) {
+				if (!ret)
+					ret = -EAGAIN;
+				break;
+			}
+			current->state = TASK_INTERRUPTIBLE;
+			schedule();
+			if (signal_pending(current)) {
+				if (!ret)
+					ret = -ERESTARTSYS;
+				break;
+			}
 			continue;
 		}
-		if (copy_from_user(s->midi.obuf + ptr, buffer, cnt))
-			return ret ? ret : -EFAULT;
+		if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) {
+			if (!ret)
+				ret = -EFAULT;
+			break;
+		}
 		ptr = (ptr + cnt) % MIDIOUTBUF;
 		spin_lock_irqsave(&s->lock, flags);
 		s->midi.owr = ptr;
@@ -2138,6 +2195,8 @@
 		es1370_handle_midi(s);
 		spin_unlock_irqrestore(&s->lock, flags);
 	}
+	current->state = TASK_RUNNING;
+        remove_wait_queue(&s->midi.owait, &wait);
 	return ret;
 }
 
@@ -2217,7 +2276,7 @@
 static int es1370_midi_release(struct inode *inode, struct file *file)
 {
 	struct es1370_state *s = (struct es1370_state *)file->private_data;
-        struct wait_queue wait = { current, NULL };
+	struct wait_queue wait = { current, NULL };
 	unsigned long flags;
 	unsigned count, tmo;
 
@@ -2321,7 +2380,7 @@
 
 	if (!pci_present())   /* No PCI bus in this machine! */
 		return -ENODEV;
-	printk(KERN_INFO "es1370: version v0.24 time " __TIME__ " " __DATE__ "\n");
+	printk(KERN_INFO "es1370: version v0.30 time " __TIME__ " " __DATE__ "\n");
 	while (index < NR_DEVICE && 
 	       (pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1370, pcidev))) {
 		if (pcidev->base_address[0] == 0 || 
@@ -2341,6 +2400,7 @@
 		init_waitqueue(&s->midi.iwait);
 		init_waitqueue(&s->midi.owait);
 		s->open_sem = MUTEX;
+		spin_lock_init(&s->lock);
 		s->magic = ES1370_MAGIC;
 		s->io = pcidev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
 		s->irq = pcidev->irq;
@@ -2385,6 +2445,10 @@
 		/* initialize the chips */
 		outl(s->ctrl, s->io+ES1370_REG_CONTROL);
 		outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
+		/* point phantom write channel to "bugbuf" */
+		outl((ES1370_REG_PHANTOM_FRAMEADR >> 8) & 15, s->io+ES1370_REG_MEMPAGE);
+		outl(virt_to_bus(bugbuf), s->io+(ES1370_REG_PHANTOM_FRAMEADR & 0xff));
+		outl(0, s->io+(ES1370_REG_PHANTOM_FRAMECNT & 0xff));
 		pci_set_master(pcidev);  /* enable bus mastering */
 		wrcodec(s, 0x16, 3); /* no RST, PD */
 		wrcodec(s, 0x17, 0); /* CODEC ADC and CODEC DAC use {LR,B}CLK2 and run off the LRCLK2 PLL; program DAC_SYNC=0!!  */
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/drivers/sound/es1371.c linux.14p1/drivers/sound/es1371.c
--- linux.vanilla/drivers/sound/es1371.c	Sat Aug 14 02:27:34 1999
+++ linux.14p1/drivers/sound/es1371.c	Fri Oct 22 22:34:18 1999
@@ -3,7 +3,7 @@
 /*
  *      es1371.c  --  Creative Ensoniq ES1371.
  *
- *      Copyright (C) 1998  Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *      Copyright (C) 1998-1999  Thomas Sailer (sailer@ife.ee.ethz.ch)
  *
  *      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
@@ -68,14 +68,31 @@
  *    15.06.99   0.12  Fix bad allocation bug.
  *                     Thanks to Deti Fliegl <fliegl@in.tum.de>
  *    28.06.99   0.13  Add pci_set_master
- *    21.07.99   0.14  S/PDIF module option for cards revision >= 4. Initial version
- *                     by Dave Platt <dplatt@snulbug.mtview.ca.us>.
+ *    03.08.99   0.14  adapt to Linus' new __setup/__initcall
+ *                     added kernel command line option "es1371=joystickaddr"
+ *                     removed CONFIG_SOUND_ES1371_JOYPORT_BOOT kludge
+ *    10.08.99   0.15  (Re)added S/PDIF module option for cards revision >= 4.
+ *                     Initial version by Dave Platt <dplatt@snulbug.mtview.ca.us>.
+ *                     module_init/__setup fixes
+ *    08.16.99   0.16  Joe Cotellese <joec@ensoniq.com>
+ *                     Added detection for ES1371 revision ID so that we can
+ *                     detect the ES1373 and later parts.
+ *                     added AC97 #defines for readability
+ *                     added a /proc file system for dumping hardware state
+ *                     updated SRC and CODEC w/r functions to accomodate bugs
+ *                     in some versions of the ES137x chips.
+ *    31.08.99   0.17  add spin_lock_init
+ *                     __initlocaldata to fix gcc 2.7.x problems
+ *                     replaced current->state = x with set_current_state(x)
+ *    03.09.99   0.18  change read semantics for MIDI to match
+ *                     OSS more closely; remove possible wakeup race
+ *    21.10.99   0.19  Round sampling rates, requested by
+ *                     Kasamatsu Kenichi <t29w0267@ip.media.kyoto-u.ac.jp>
  *
  */
 
 /*****************************************************************************/
       
-#include <linux/config.h>
 #include <linux/version.h>
 #include <linux/module.h>
 #include <linux/string.h>
@@ -86,17 +103,21 @@
 #include <linux/malloc.h>
 #include <linux/soundcard.h>
 #include <linux/pci.h>
-#include <asm/io.h>
-#include <asm/dma.h>
 #include <linux/init.h>
 #include <linux/poll.h>
+#include <linux/bitops.h>
+#include <linux/proc_fs.h>
 #include <asm/spinlock.h>
+#include <asm/io.h>
+#include <asm/dma.h>
 #include <asm/uaccess.h>
 #include <asm/hardirq.h>
+#include "ac97.h"
 
 /* --------------------------------------------------------------------- */
 
 #undef OSS_DOCUMENTED_MIXER_SEMANTICS
+#undef ES1371_DEBUG
 
 /* --------------------------------------------------------------------- */
 
@@ -107,6 +128,18 @@
 #define PCI_DEVICE_ID_ENSONIQ_ES1371 0x1371
 #endif
 
+/* ES1371 chip ID */
+/* This is a little confusing because all ES1371 compatible chips have the
+   same DEVICE_ID, the only thing differentiating them is the REV_ID field.
+   This is only significant if you want to enable features on the later parts.
+   Yes, I know it's stupid and why didn't we use the sub IDs?
+*/
+#define ES1371REV_ES1373_A  0x04
+#define ES1371REV_ES1373_B  0x06
+#define ES1371REV_CT5880_A  0x07
+#define ES1371REV_ES1371_B  0x09
+
+
 #define ES1371_MAGIC  ((PCI_VENDOR_ID_ENSONIQ<<16)|PCI_DEVICE_ID_ENSONIQ_ES1371)
 
 #define ES1371_EXTENT             0x40
@@ -206,14 +239,22 @@
 #define UCTRL_CNTRL_SWR 0x03        /* software reset command */
 
 /* sample rate converter */
+#define SRC_OKSTATE        1
+
 #define SRC_RAMADDR_MASK   0xfe000000
 #define SRC_RAMADDR_SHIFT  25
+#define SRC_DAC1FREEZE     (1UL << 21)
+#define SRC_DAC2FREEZE      (1UL << 20)
+#define SRC_ADCFREEZE      (1UL << 19)
+
+
 #define SRC_WE             0x01000000  /* read/write control for SRC RAM */
 #define SRC_BUSY           0x00800000  /* SRC busy */
 #define SRC_DIS            0x00400000  /* 1 = disable SRC */
 #define SRC_DDAC1          0x00200000  /* 1 = disable accum update for DAC1 */
 #define SRC_DDAC2          0x00100000  /* 1 = disable accum update for DAC2 */
 #define SRC_DADC           0x00080000  /* 1 = disable accum update for ADC2 */
+#define SRC_CTLMASK        0x00780000
 #define SRC_RAMDATA_MASK   0x0000ffff
 #define SRC_RAMDATA_SHIFT  0
 
@@ -293,7 +334,7 @@
 
 
 /* misc stuff */
-
+#define POLL_COUNT   0x1000
 #define FMODE_DAC         4           /* slight misuse of mode_t */
 
 /* MIDI buffer sizes */
@@ -352,8 +393,13 @@
 	/* hardware resources */
 	unsigned long io; /* long for SPARC */
 	unsigned int irq;
-
-	/* mixer registers; there is no HW readback */
+        u8 rev; /* the chip revision */
+        
+#ifdef ES1371_DEBUG
+        /* debug /proc entry */
+	struct proc_dir_entry *ps;
+#endif /* ES1371_DEBUG */
+        /* mixer registers; there is no HW readback */
 	struct {
 		unsigned short codec_id;
 		unsigned int modcnt;
@@ -438,31 +484,12 @@
 }
 
 /* --------------------------------------------------------------------- */
-/*
- * hweightN: returns the hamming weight (i.e. the number
- * of bits set) of a N-bit word
- */
-
-#ifdef hweight32
-#undef hweight32
-#endif
-
-extern __inline__ unsigned int hweight32(unsigned int w)
-{
-        unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);
-        res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
-        res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F);
-        res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF);
-        return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);
-}
-
-/* --------------------------------------------------------------------- */
 
 static unsigned wait_src_ready(struct es1371_state *s)
 {
 	unsigned int t, r;
 
-	for (t = 0; t < 1000; t++) {
+	for (t = 0; t < POLL_COUNT; t++) {
 		if (!((r = inl(s->io + ES1371_REG_SRCONV)) & SRC_BUSY))
 			return r;
 		udelay(1);
@@ -473,29 +500,53 @@
 
 static unsigned src_read(struct es1371_state *s, unsigned reg)
 {
-	unsigned int r;
+        unsigned int temp,i,orig;
 
-	r = wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC);
-	r |= (reg << SRC_RAMADDR_SHIFT) & SRC_RAMADDR_MASK;
-	outl(r, s->io + ES1371_REG_SRCONV);
-	return (wait_src_ready(s) & SRC_RAMDATA_MASK) >> SRC_RAMDATA_SHIFT;
-}
+        /* wait for ready */
+        temp = wait_src_ready (s);
+
+        /* we can only access the SRC at certain times, make sure
+           we're allowed to before we read */
+           
+        orig = temp;
+        /* expose the SRC state bits */
+        outl ( (temp & SRC_CTLMASK) | (reg << SRC_RAMADDR_SHIFT) | 0x10000UL,
+               s->io + ES1371_REG_SRCONV);
+
+        /* now, wait for busy and the correct time to read */
+        temp = wait_src_ready (s);
+
+        if ( (temp & 0x00870000UL ) != ( SRC_OKSTATE << 16 )){
+                /* wait for the right state */
+                for (i=0; i<POLL_COUNT; i++){
+                        temp = inl (s->io + ES1371_REG_SRCONV);
+                        if ( (temp & 0x00870000UL ) == ( SRC_OKSTATE << 16 ))
+                                break;
+                }
+        }
 
+        /* hide the state bits */
+        outl ((orig & SRC_CTLMASK) | (reg << SRC_RAMADDR_SHIFT), s->io + ES1371_REG_SRCONV);
+        return temp;
+                        
+                
+}
 
 static void src_write(struct es1371_state *s, unsigned reg, unsigned data)
 {
+      
 	unsigned int r;
 
 	r = wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC);
 	r |= (reg << SRC_RAMADDR_SHIFT) & SRC_RAMADDR_MASK;
 	r |= (data << SRC_RAMDATA_SHIFT) & SRC_RAMDATA_MASK;
 	outl(r | SRC_WE, s->io + ES1371_REG_SRCONV);
+
 }
 
 /* --------------------------------------------------------------------- */
 
 /* most of the following here is black magic */
-
 static void set_adc_rate(struct es1371_state *s, unsigned rate)
 {
 	unsigned long flags;
@@ -532,6 +583,7 @@
 	spin_unlock_irqrestore(&s->lock, flags);
 }
 
+
 static void set_dac1_rate(struct es1371_state *s, unsigned rate)
 {
 	unsigned long flags;
@@ -541,8 +593,8 @@
 		rate = 48000;
 	if (rate < 4000)
 		rate = 4000;
-        freq = (rate << 15) / 3000;
-	s->dac1rate = (freq * 3000) >> 15;
+        freq = ((rate << 15) + 1500) / 3000;
+	s->dac1rate = (freq * 3000 + 16384) >> 15;
 	spin_lock_irqsave(&s->lock, flags);
 	r = (wait_src_ready(s) & (SRC_DIS | SRC_DDAC2 | SRC_DADC)) | SRC_DDAC1;
 	outl(r, s->io + ES1371_REG_SRCONV);
@@ -564,8 +616,8 @@
 		rate = 48000;
 	if (rate < 4000)
 		rate = 4000;
-        freq = (rate << 15) / 3000;
-	s->dac2rate = (freq * 3000) >> 15;
+        freq = ((rate << 15) + 1500) / 3000;
+	s->dac2rate = (freq * 3000 + 16384) >> 15;
 	spin_lock_irqsave(&s->lock, flags);
 	r = (wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DADC)) | SRC_DDAC2;
 	outl(r, s->io + ES1371_REG_SRCONV);
@@ -580,26 +632,80 @@
 
 /* --------------------------------------------------------------------- */
 
+static void __init src_init(struct es1371_state *s)
+{
+        unsigned int i;
+
+        /* before we enable or disable the SRC we need
+           to wait for it to become ready */
+        wait_src_ready(s);
+
+        outl(SRC_DIS, s->io + ES1371_REG_SRCONV);
+
+        for (i = 0; i < 0x80; i++)
+                src_write(s, i, 0);
+
+        src_write(s, SRCREG_DAC1+SRCREG_TRUNC_N, 16 << 4);
+        src_write(s, SRCREG_DAC1+SRCREG_INT_REGS, 16 << 10);
+        src_write(s, SRCREG_DAC2+SRCREG_TRUNC_N, 16 << 4);
+        src_write(s, SRCREG_DAC2+SRCREG_INT_REGS, 16 << 10);
+        src_write(s, SRCREG_VOL_ADC, 1 << 12);
+        src_write(s, SRCREG_VOL_ADC+1, 1 << 12);
+        src_write(s, SRCREG_VOL_DAC1, 1 << 12);
+        src_write(s, SRCREG_VOL_DAC1+1, 1 << 12);
+        src_write(s, SRCREG_VOL_DAC2, 1 << 12);
+        src_write(s, SRCREG_VOL_DAC2+1, 1 << 12);
+        set_adc_rate(s, 22050);
+        set_dac1_rate(s, 22050);
+        set_dac2_rate(s, 22050);
+
+        /* WARNING:
+         * enabling the sample rate converter without properly programming
+         * its parameters causes the chip to lock up (the SRC busy bit will
+         * be stuck high, and I've found no way to rectify this other than
+         * power cycle)
+         */
+        wait_src_ready(s);
+        outl(0, s->io+ES1371_REG_SRCONV);
+}
+
+/* --------------------------------------------------------------------- */
+
 static void wrcodec(struct es1371_state *s, unsigned addr, unsigned data)
 {
 	unsigned long flags;
 	unsigned t, x;
-
-	for (t = 0; t < 0x1000; t++)
+        
+	for (t = 0; t < POLL_COUNT; t++)
 		if (!(inl(s->io+ES1371_REG_CODEC) & CODEC_WIP))
 			break;
 	spin_lock_irqsave(&s->lock, flags);
-	/* save the current state for later */
-	x = inl(s->io+ES1371_REG_SRCONV);
-	/* enable SRC state data in SRC mux */
-	outl((wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC)) | 0x00010000,
+
+        /* save the current state for later */
+        x = wait_src_ready(s);
+
+        /* enable SRC state data in SRC mux */
+	outl(( x & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC)) | 0x00010000,
 	     s->io+ES1371_REG_SRCONV);
-	/* wait for a SAFE time to write addr/data and then do it, dammit */
-	for (t = 0; t < 0x1000; t++)
-		if ((inl(s->io+ES1371_REG_SRCONV) & 0x00070000) == 0x00010000)
-			break;
+
+        /* wait for not busy (state 0) first to avoid
+           transition states */
+        for (t=0; t<POLL_COUNT; t++){
+                if((inl(s->io+ES1371_REG_SRCONV) & 0x00870000) ==0 )
+                    break;
+                udelay(1);
+        }
+        
+        /* wait for a SAFE time to write addr/data and then do it, dammit */
+        for (t=0; t<POLL_COUNT; t++){
+                if((inl(s->io+ES1371_REG_SRCONV) & 0x00870000) ==0x00010000)
+                    break;
+                udelay(1);
+        }
+
 	outl(((addr << CODEC_POADD_SHIFT) & CODEC_POADD_MASK) |
 	     ((data << CODEC_PODAT_SHIFT) & CODEC_PODAT_MASK), s->io+ES1371_REG_CODEC);
+
 	/* restore SRC reg */
 	wait_src_ready(s);
 	outl(x, s->io+ES1371_REG_SRCONV);
@@ -611,28 +717,50 @@
 	unsigned long flags;
 	unsigned t, x;
 
+        /* wait for WIP to go away */
 	for (t = 0; t < 0x1000; t++)
 		if (!(inl(s->io+ES1371_REG_CODEC) & CODEC_WIP))
 			break;
 	spin_lock_irqsave(&s->lock, flags);
+
 	/* save the current state for later */
-	x = inl(s->io+ES1371_REG_SRCONV);
+	x = (wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC));
+
 	/* enable SRC state data in SRC mux */
-	outl((wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC)) | 0x00010000,
-	     s->io+ES1371_REG_SRCONV);
-	/* wait for a SAFE time to write addr/data and then do it, dammit */
-	for (t = 0; t < 0x1000; t++)
-		if ((inl(s->io+ES1371_REG_SRCONV) & 0x00070000) == 0x00010000)
-			break;
+	outl( x | 0x00010000,
+              s->io+ES1371_REG_SRCONV);
+
+        /* wait for not busy (state 0) first to avoid
+           transition states */
+        for (t=0; t<POLL_COUNT; t++){
+                if((inl(s->io+ES1371_REG_SRCONV) & 0x00870000) ==0 )
+                    break;
+                udelay(1);
+        }
+        
+        /* wait for a SAFE time to write addr/data and then do it, dammit */
+        for (t=0; t<POLL_COUNT; t++){
+                if((inl(s->io+ES1371_REG_SRCONV) & 0x00870000) ==0x00010000)
+                    break;
+                udelay(1);
+        }
+
 	outl(((addr << CODEC_POADD_SHIFT) & CODEC_POADD_MASK) | CODEC_PORD, s->io+ES1371_REG_CODEC);
 	/* restore SRC reg */
 	wait_src_ready(s);
 	outl(x, s->io+ES1371_REG_SRCONV);
 	spin_unlock_irqrestore(&s->lock, flags);
-	/* now wait for the stinkin' data (RDY) */
+
+        /* wait for WIP again */
 	for (t = 0; t < 0x1000; t++)
+		if (!(inl(s->io+ES1371_REG_CODEC) & CODEC_WIP))
+			break;
+        
+	/* now wait for the stinkin' data (RDY) */
+	for (t = 0; t < POLL_COUNT; t++)
 		if ((x = inl(s->io+ES1371_REG_CODEC)) & CODEC_RDY)
 			break;
+        
 	return ((x & CODEC_PIDAT_MASK) >> CODEC_PIDAT_SHIFT);
 }
 
@@ -993,6 +1121,21 @@
 
 /* --------------------------------------------------------------------- */
 
+/*
+ * AC97 Mixer Register to Connections mapping of the Concert 97 board
+ *
+ * AC97_MASTER_VOL_STEREO   Line Out
+ * AC97_MASTER_VOL_MONO     TAD Output
+ * AC97_PCBEEP_VOL          none
+ * AC97_PHONE_VOL           TAD Input (mono)
+ * AC97_MIC_VOL             MIC Input (mono)
+ * AC97_LINEIN_VOL          Line Input (stereo)
+ * AC97_CD_VOL              CD Input (stereo)
+ * AC97_VIDEO_VOL           none
+ * AC97_AUX_VOL             Aux Input (stereo)
+ * AC97_PCMOUT_VOL          Wave Output (stereo)
+ */
+
 #define AC97_PESSIMISTIC
 
 /*
@@ -1018,25 +1161,25 @@
 static const unsigned char volreg[SOUND_MIXER_NRDEVICES] = 
 {
 	/* 5 bit stereo */
-	[SOUND_MIXER_LINE] = 0x10,
-	[SOUND_MIXER_CD] = 0x12,
-	[SOUND_MIXER_VIDEO] = 0x14,
-	[SOUND_MIXER_LINE1] = 0x16,
-	[SOUND_MIXER_PCM] = 0x18,
+	[SOUND_MIXER_LINE] = AC97_LINEIN_VOL,
+	[SOUND_MIXER_CD] = AC97_CD_VOL,
+	[SOUND_MIXER_VIDEO] = AC97_VIDEO_VOL,
+	[SOUND_MIXER_LINE1] = AC97_AUX_VOL,
+	[SOUND_MIXER_PCM] = AC97_PCMOUT_VOL,
 	/* 6 bit stereo */
-	[SOUND_MIXER_VOLUME] = 0x02,
-	[SOUND_MIXER_PHONEOUT] = 0x04,
+	[SOUND_MIXER_VOLUME] = AC97_MASTER_VOL_STEREO,
+	[SOUND_MIXER_PHONEOUT] = AC97_HEADPHONE_VOL,
 	/* 6 bit mono */
-	[SOUND_MIXER_OGAIN] = 0x06,
-	[SOUND_MIXER_PHONEIN] = 0x0c,
+	[SOUND_MIXER_OGAIN] = AC97_MASTER_VOL_MONO,
+	[SOUND_MIXER_PHONEIN] = AC97_PHONE_VOL,
 	/* 4 bit mono but shifted by 1 */
-	[SOUND_MIXER_SPEAKER] = 0x08,
+	[SOUND_MIXER_SPEAKER] = AC97_MASTER_TONE,
 	/* 6 bit mono + preamp */
-	[SOUND_MIXER_MIC] = 0x0e,
+	[SOUND_MIXER_MIC] = AC97_MIC_VOL,
 	/* 4 bit stereo */
-	[SOUND_MIXER_RECLEV] = 0x1c,
+	[SOUND_MIXER_RECLEV] = AC97_RECORD_GAIN,
 	/* 4 bit mono */
-	[SOUND_MIXER_IGAIN] = 0x1e
+	[SOUND_MIXER_IGAIN] = AC97_RECORD_GAIN_MIC
 };
 
 #ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
@@ -1049,8 +1192,8 @@
 
 	switch (ch) {
 	case SOUND_MIXER_MIC:
-		j = rdcodec(s, 0x0e);
-		if (j & 0x8000)
+		j = rdcodec(s, AC97_MIC_VOL);
+		if (j & AC97_MUTE)
 			return put_user(0, (int *)arg);
 #ifdef AC97_PESSIMISTIC
 		return put_user(0x4949 - 0x202 * (j & 0x1f) + ((j & 0x40) ? 0x1b1b : 0), (int *)arg);
@@ -1061,7 +1204,7 @@
 	case SOUND_MIXER_OGAIN:
 	case SOUND_MIXER_PHONEIN:
 		j = rdcodec(s, volreg[ch]);
-		if (j & 0x8000)
+		if (j & AC97_MUTE)
 			return put_user(0, (int *)arg);
 #ifdef AC97_PESSIMISTIC
 		return put_user(0x6464 - 0x303 * (j & 0x1f), (int *)arg);
@@ -1075,7 +1218,7 @@
 		/* fall through */
 	case SOUND_MIXER_VOLUME:
 		j = rdcodec(s, volreg[ch]);
-		if (j & 0x8000)
+		if (j & AC97_MUTE)
 			return put_user(0, (int *)arg);
 #ifdef AC97_PESSIMISTIC
 		return put_user(0x6464 - (swab(j) & 0x1f1f) * 3, (int *)arg);
@@ -1084,8 +1227,8 @@
 #endif /* AC97_PESSIMISTIC */
 		
 	case SOUND_MIXER_SPEAKER:
-		j = rdcodec(s, 0x0a);
-		if (j & 0x8000)
+		j = rdcodec(s, AC97_PCBEEP_VOL);
+		if (j & AC97_MUTE
 			return put_user(0, (int *)arg);
 		return put_user(0x6464 - ((j >> 1) & 0xf) * 0x606, (int *)arg);
 		
@@ -1095,7 +1238,7 @@
 	case SOUND_MIXER_LINE1:
 	case SOUND_MIXER_PCM:
 		j = rdcodec(s, volreg[ch]);
-		if (j & 0x8000)
+		if (j & AC97_MUTE)
 			return put_user(0, (int *)arg);
 		return put_user(0x6464 - (swab(j) & 0x1f1f) * 3, (int *)arg);
 
@@ -1103,23 +1246,23 @@
 	case SOUND_MIXER_TREBLE:
 		if (!(s->mix.codec_id & CODEC_ID_BASSTREBLE))
 			return -EINVAL;
-		j = rdcodec(s, 0x08);
+		j = rdcodec(s, AC97_MASTER_TONE);
 		if (ch == SOUND_MIXER_BASS)
 			j >>= 8;
 		return put_user((((j & 15) * 100) / 15) * 0x101, (int *)arg);
 	
 		/* SOUND_MIXER_RECLEV and SOUND_MIXER_IGAIN specify gain */
 	case SOUND_MIXER_RECLEV:
-		j = rdcodec(s, 0x1c);
-		if (j & 0x8000)
+		j = rdcodec(s, AC97_RECORD_GAIN);
+		if (j & AC97_MUTE)
 			return put_user(0, (int *)arg);
 		return put_user((swab(j)  & 0xf0f) * 6 + 0xa0a, (int *)arg);
 		
 	case SOUND_MIXER_IGAIN:
 		if (!(s->mix.codec_id & CODEC_ID_DEDICATEDMIC))
 			return -EINVAL;
-		j = rdcodec(s, 0x1e);
-		if (j & 0x8000)
+		j = rdcodec(s, AC97_RECORD_GAIN_MIC);
+		if (j & AC97_MUTE)
 			return put_user(0, (int *)arg);
 		return put_user((j & 0xf) * 0x606 + 0xa0a, (int *)arg);
 	
@@ -1174,7 +1317,7 @@
 	case SOUND_MIXER_LINE1:
 	case SOUND_MIXER_PCM:
 		if (l1 < 7 && r1 < 7) {
-			wrcodec(s, volreg[ch], 0x8000);
+			wrcodec(s, volreg[ch], AC97_MUTE);
 			return 0;
 		}
 		if (l1 < 7)
@@ -1191,7 +1334,7 @@
 	case SOUND_MIXER_VOLUME:
 #ifdef AC97_PESSIMISTIC
 		if (l1 < 7 && r1 < 7) {
-			wrcodec(s, volreg[ch], 0x8000);
+			wrcodec(s, volreg[ch], AC97_MUTE);
 			return 0;
 		}
 		if (l1 < 7)
@@ -1202,7 +1345,7 @@
 		return 0;
 #else /* AC97_PESSIMISTIC */
 		if (l1 < 4 && r1 < 4) {
-			wrcodec(s, volreg[ch], 0x8000);
+			wrcodec(s, volreg[ch], AC97_MUTE);
 			return 0;
 		}
 		if (l1 < 4)
@@ -1216,21 +1359,21 @@
 	case SOUND_MIXER_OGAIN:
 	case SOUND_MIXER_PHONEIN:
 #ifdef AC97_PESSIMISTIC
-		wrcodec(s, volreg[ch], (l1 < 7) ? 0x8000 : (100 - l1) / 3);
+		wrcodec(s, volreg[ch], (l1 < 7) ? AC97_MUTE : (100 - l1) / 3);
 		return 0;
 #else /* AC97_PESSIMISTIC */
-		wrcodec(s, volreg[ch], (l1 < 4) ? 0x8000 : (2 * (100 - l1) / 3));
+		wrcodec(s, volreg[ch], (l1 < 4) ? AC97_MUTE : (2 * (100 - l1) / 3));
 		return 0;
 #endif /* AC97_PESSIMISTIC */
 			
 	case SOUND_MIXER_SPEAKER:
-		wrcodec(s, 0x0a, (l1 < 10) ? 0x8000 : ((100 - l1) / 6) << 1);
+		wrcodec(s, AC97_PCBEEP_VOL, (l1 < 10) ? AC97_MUTE : ((100 - l1) / 6) << 1);
 		return 0;
 
 	case SOUND_MIXER_MIC:
 #ifdef AC97_PESSIMISTIC
 		if (l1 < 11) {
-			wrcodec(s, 0x0e, 0x8000);
+			wrcodec(s, AC97_MIC_VOL, AC97_MUTE);
 			return 0;
 		}
 		i = 0;
@@ -1240,11 +1383,11 @@
 		}
 		if (l1 < 11) 
 			l1 = 11;
-		wrcodec(s, 0x0e, ((73 - l1) / 2) | i);
+		wrcodec(s, AC97_MIC_VOL, ((73 - l1) / 2) | i);
 		return 0;
 #else /* AC97_PESSIMISTIC */
 		if (l1 < 9) {
-			wrcodec(s, 0x0e, 0x8000);
+			wrcodec(s, AC97_MIC_VOL, AC97_MUTE);
 			return 0;
 		}
 		i = 0;
@@ -1254,37 +1397,37 @@
 		}
 		if (l1 < 9) 
 			l1 = 9;
-		wrcodec(s, 0x0e, (((87 - l1) * 4) / 5) | i);
+		wrcodec(s, AC97_MIC_VOL, (((87 - l1) * 4) / 5) | i);
 		return 0;
 #endif /* AC97_PESSIMISTIC */
 		
 	case SOUND_MIXER_BASS:
 		val = ((l1 * 15) / 100) & 0xf;
-		wrcodec(s, 0x08, (rdcodec(s, 0x08) & 0x00ff) | (val << 8));
+		wrcodec(s, AC97_MASTER_TONE, (rdcodec(s, AC97_MASTER_TONE) & 0x00ff) | (val << 8));
 		return 0;
 
 	case SOUND_MIXER_TREBLE:
 		val = ((l1 * 15) / 100) & 0xf;
-		wrcodec(s, 0x08, (rdcodec(s, 0x08) & 0xff00) | val);
+		wrcodec(s, AC97_MASTER_TONE, (rdcodec(s, AC97_MASTER_TONE) & 0xff00) | val);
 		return 0;
 		
 		/* SOUND_MIXER_RECLEV and SOUND_MIXER_IGAIN specify gain */
 	case SOUND_MIXER_RECLEV:
 		if (l1 < 10 || r1 < 10) {
-			wrcodec(s, 0x1c, 0x8000);
+			wrcodec(s, AC97_RECORD_GAIN, AC97_MUTE);
 			return 0;
 		}
 		if (l1 < 10)
 			l1 = 10;
 		if (r1 < 10)
 			r1 = 10;
-		wrcodec(s, 0x1c, (((l1 - 10) / 6) << 8) | ((r1 - 10) / 6));
+		wrcodec(s, AC97_RECORD_GAIN, (((l1 - 10) / 6) << 8) | ((r1 - 10) / 6));
 		return 0;
 
 	case SOUND_MIXER_IGAIN:
 		if (!(s->mix.codec_id & CODEC_ID_DEDICATEDMIC))
 			return -EINVAL;
-		wrcodec(s, 0x1e, (l1 < 10) ? 0x8000 : ((l1 - 10) / 6) & 0xf);
+		wrcodec(s, AC97_RECORD_GAIN_MIC, (l1 < 10) ? AC97_MUTE : ((l1 - 10) / 6) & 0xf);
 		return 0;
 		
 	default:
@@ -1302,8 +1445,8 @@
 			return -EINVAL;
 		get_user_ret(val, (int *)arg, -EFAULT);
 		if (val & 1)
-			wrcodec(s, 0x22, ((val << 3) & 0xf00) | ((val >> 1) & 0xf));
-		val = rdcodec(s, 0x22);
+			wrcodec(s, AC97_3D_CONTROL, ((val << 3) & 0xf00) | ((val >> 1) & 0xf));
+		val = rdcodec(s, AC97_3D_CONTROL);
 		return put_user(((val & 0xf) << 1) | ((val & 0xf00) >> 3), (int *)arg);
 	}
         if (cmd == SOUND_MIXER_INFO) {
@@ -1330,7 +1473,7 @@
         if (_IOC_DIR(cmd) == _IOC_READ) {
                 switch (_IOC_NR(cmd)) {
                 case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
-			return put_user(recsrc[rdcodec(s, 0x1a) & 7], (int *)arg);
+			return put_user(recsrc[rdcodec(s, AC97_RECORD_SELECT) & 7], (int *)arg);
 			
                 case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */
 			return put_user(SOUND_MASK_LINE | SOUND_MASK_CD | SOUND_MASK_VIDEO |
@@ -1377,10 +1520,10 @@
                 if (i == 0)
                         return 0; /*val = mixer_recmask(s);*/
                 else if (i > 1) 
-                        val &= ~recsrc[rdcodec(s, 0x1a) & 7];
+                        val &= ~recsrc[rdcodec(s, AC97_RECORD_SELECT) & 7];
                 for (i = 0; i < 8; i++) {
 			if (val & recsrc[i]) {
-				wrcodec(s, 0x1a, 0x101 * i);
+				wrcodec(s, AC97_RECORD_SELECT, 0x101 * i);
 				return 0;
 			}
 		}
@@ -1485,10 +1628,10 @@
                         current->state = TASK_RUNNING;
                         return -EBUSY;
                 }
-		tmo = (count * HZ) / s->dac1rate;
+		tmo = 3 * HZ * (count + s->dma_dac1.fragsize) / 2 / s->dac1rate;
 		tmo >>= sample_shift[(s->sctrl & SCTRL_P1FMT) >> SCTRL_SH_P1FMT];
-		if (!schedule_timeout(tmo ? : 1) && tmo)
-			printk(KERN_DEBUG "es1371: dma timed out??\n");
+		if (!schedule_timeout(tmo + 1))
+			printk(KERN_DEBUG "es1371: dac1 dma timed out??\n");
         }
         remove_wait_queue(&s->dma_dac1.wait, &wait);
         current->state = TASK_RUNNING;
@@ -1520,10 +1663,10 @@
                         current->state = TASK_RUNNING;
                         return -EBUSY;
                 }
-		tmo = (count * HZ) / s->dac2rate;
+		tmo = 3 * HZ * (count + s->dma_dac2.fragsize) / 2 / s->dac2rate;
 		tmo >>= sample_shift[(s->sctrl & SCTRL_P2FMT) >> SCTRL_SH_P2FMT];
-		if (!schedule_timeout(tmo ? : 1) && tmo)
-			printk(KERN_DEBUG "es1371: dma timed out??\n");
+		if (!schedule_timeout(tmo + 1))
+			printk(KERN_DEBUG "es1371: dac2 dma timed out??\n");
         }
         remove_wait_queue(&s->dma_dac2.wait, &wait);
         current->state = TASK_RUNNING;
@@ -2467,6 +2610,7 @@
 static ssize_t es1371_midi_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
 {
 	struct es1371_state *s = (struct es1371_state *)file->private_data;
+	struct wait_queue wait = { current, NULL };
 	ssize_t ret;
 	unsigned long flags;
 	unsigned ptr;
@@ -2477,7 +2621,10 @@
 		return -ESPIPE;
 	if (!access_ok(VERIFY_WRITE, buffer, count))
 		return -EFAULT;
+	if (count == 0)
+		return 0;
 	ret = 0;
+        add_wait_queue(&s->midi.iwait, &wait);
 	while (count > 0) {
 		spin_lock_irqsave(&s->lock, flags);
 		ptr = s->midi.ird;
@@ -2488,15 +2635,25 @@
 		if (cnt > count)
 			cnt = count;
 		if (cnt <= 0) {
-			if (file->f_flags & O_NONBLOCK)
-				return ret ? ret : -EAGAIN;
-			interruptible_sleep_on(&s->midi.iwait);
-			if (signal_pending(current))
-				return ret ? ret : -ERESTARTSYS;
+			if (file->f_flags & O_NONBLOCK) {
+				if (!ret)
+					ret = -EAGAIN;
+				break;
+			}
+			current->state = TASK_INTERRUPTIBLE;
+			schedule();
+			if (signal_pending(current)) {
+				if (!ret)
+					ret = -ERESTARTSYS;
+				break;
+			}
 			continue;
 		}
-		if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt))
-			return ret ? ret : -EFAULT;
+		if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) {
+			if (!ret)
+				ret = -EFAULT;
+			break;
+		}
 		ptr = (ptr + cnt) % MIDIINBUF;
 		spin_lock_irqsave(&s->lock, flags);
 		s->midi.ird = ptr;
@@ -2505,13 +2662,17 @@
 		count -= cnt;
 		buffer += cnt;
 		ret += cnt;
+		break;
 	}
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&s->midi.iwait, &wait);
 	return ret;
 }
 
 static ssize_t es1371_midi_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
 {
 	struct es1371_state *s = (struct es1371_state *)file->private_data;
+	struct wait_queue wait = { current, NULL };
 	ssize_t ret;
 	unsigned long flags;
 	unsigned ptr;
@@ -2522,7 +2683,10 @@
 		return -ESPIPE;
 	if (!access_ok(VERIFY_READ, buffer, count))
 		return -EFAULT;
+	if (count == 0)
+		return 0;
 	ret = 0;
+        add_wait_queue(&s->midi.owait, &wait);
 	while (count > 0) {
 		spin_lock_irqsave(&s->lock, flags);
 		ptr = s->midi.owr;
@@ -2535,15 +2699,25 @@
 		if (cnt > count)
 			cnt = count;
 		if (cnt <= 0) {
-			if (file->f_flags & O_NONBLOCK)
-				return ret ? ret : -EAGAIN;
-			interruptible_sleep_on(&s->midi.owait);
-			if (signal_pending(current))
-				return ret ? ret : -ERESTARTSYS;
+			if (file->f_flags & O_NONBLOCK) {
+				if (!ret)
+					ret = -EAGAIN;
+				break;
+			}
+			current->state = TASK_INTERRUPTIBLE;
+			schedule();
+			if (signal_pending(current)) {
+				if (!ret)
+					ret = -ERESTARTSYS;
+				break;
+			}
 			continue;
 		}
-		if (copy_from_user(s->midi.obuf + ptr, buffer, cnt))
-			return ret ? ret : -EFAULT;
+		if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) {
+			if (!ret)
+				ret = -EFAULT;
+			break;
+		}
 		ptr = (ptr + cnt) % MIDIOUTBUF;
 		spin_lock_irqsave(&s->lock, flags);
 		s->midi.owr = ptr;
@@ -2556,6 +2730,8 @@
 		es1371_handle_midi(s);
 		spin_unlock_irqrestore(&s->lock, flags);
 	}
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&s->midi.owait, &wait);
 	return ret;
 }
 
@@ -2697,6 +2873,44 @@
 
 /* --------------------------------------------------------------------- */
 
+/*
+ * for debugging purposes, we'll create a proc device that dumps the
+ *  CODEC chipstate
+ */
+
+#ifdef ES1371_DEBUG
+static int proc_es1371_dump (char *buf, char **start, off_t fpos, int length, int *eof, void *data)
+{
+        int len = 0;
+
+        struct es1371_state *s = devs;
+        int cnt;
+
+        /* print out header */
+        len += sprintf(buf + len, "\t\tCreative ES137x Debug Dump-o-matic\n");
+
+        /* print out CODEC state */
+        len += sprintf (buf + len, "AC97 CODEC state\n");
+        
+        for (cnt=0; cnt <= 0x7e; cnt = cnt +2)
+                len+= sprintf (buf + len, "reg:0x%02x  val:0x%04x\n", cnt, rdcodec(s , cnt));
+                
+        if (fpos >=len){
+                *start = buf;
+                *eof =1;
+                return 0;
+        }
+        *start = buf + fpos;
+        if ((len -= fpos) > length)
+                return length;
+        *eof =1;
+        return len;
+
+}
+#endif /* ES1371_DEBUG */
+
+/* --------------------------------------------------------------------- */
+
 /* maximum number of devices */
 #define NR_DEVICE 5
 
@@ -2740,12 +2954,11 @@
 	struct pci_dev *pcidev = NULL;
 	mm_segment_t fs;
 	int i, val, val2, index = 0;
-	u8 revision;
 	unsigned cssr;
 
 	if (!pci_present())   /* No PCI bus in this machine! */
 		return -ENODEV;
-	printk(KERN_INFO "es1371: version v0.13 time " __TIME__ " " __DATE__ "\n");
+	printk(KERN_INFO "es1371: version v0.19 time " __TIME__ " " __DATE__ "\n");
 	while (index < NR_DEVICE && 
 	       (pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1371, pcidev))) {
 		if (pcidev->base_address[0] == 0 || 
@@ -2765,9 +2978,11 @@
 		init_waitqueue(&s->midi.iwait);
 		init_waitqueue(&s->midi.owait);
 		s->open_sem = MUTEX;
+		spin_lock_init(&s->lock);
 		s->magic = ES1371_MAGIC;
 		s->io = pcidev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
 		s->irq = pcidev->irq;
+		pci_read_config_byte(pcidev, PCI_REVISION_ID, &s->rev);
 		if (check_region(s->io, ES1371_EXTENT)) {
 			printk(KERN_ERR "es1371: io ports %#lx-%#lx in use\n", s->io, s->io+ES1371_EXTENT-1);
 			goto err_region;
@@ -2788,6 +3003,13 @@
 			goto err_dev3;
 		if ((s->dev_midi = register_sound_midi(&es1371_midi_fops, -1)) < 0)
 			goto err_dev4;
+#ifdef ES1371_DEBUG
+                /* intialize the debug proc device */
+                s->ps = create_proc_entry("es1371", S_IFREG | S_IRUGO, NULL);
+                if (s->ps)
+                        s->ps->read_proc = proc_es1371_dump;
+#endif /* ES1371_DEBUG */
+
 		/* initialize codec registers */
 		s->ctrl = 0;
 		if ((joystick[index] & ~0x18) == 0x200) {
@@ -2800,14 +3022,13 @@
 		s->sctrl = 0;
 		cssr = 0;
 		/* check to see if s/pdif mode is being requested */
-		pci_read_config_byte(pcidev, PCI_REVISION_ID, &revision);
 		if (spdif[index]) {
-			if (revision >= 4) {
+			if (s->rev >= 4) {
 				printk(KERN_INFO "es1371: enabling S/PDIF output\n");
 				cssr |= STAT_EN_SPDIF;
 				s->ctrl |= CTRL_SPDIFEN_B;
 			} else {
-				printk(KERN_ERR "es1371: revision %d does not support S/PDIF\n", revision);
+				printk(KERN_ERR "es1371: revision %d does not support S/PDIF\n", s->rev);
 			}
 		}
 		/* initialize the chips */
@@ -2820,35 +3041,12 @@
 		udelay(2);
 		outl(s->ctrl, s->io+ES1371_REG_CONTROL);
 		/* init the sample rate converter */
-		outl(SRC_DIS, s->io + ES1371_REG_SRCONV);
-		for (val = 0; val < 0x80; val++)
-			src_write(s, val, 0);
-		src_write(s, SRCREG_DAC1+SRCREG_TRUNC_N, 16 << 4);
-		src_write(s, SRCREG_DAC1+SRCREG_INT_REGS, 16 << 10);
-		src_write(s, SRCREG_DAC2+SRCREG_TRUNC_N, 16 << 4);
-		src_write(s, SRCREG_DAC2+SRCREG_INT_REGS, 16 << 10);
-		src_write(s, SRCREG_VOL_ADC, 1 << 12);
-		src_write(s, SRCREG_VOL_ADC+1, 1 << 12);
-		src_write(s, SRCREG_VOL_DAC1, 1 << 12);
-		src_write(s, SRCREG_VOL_DAC1+1, 1 << 12);
-		src_write(s, SRCREG_VOL_DAC2, 1 << 12);
-		src_write(s, SRCREG_VOL_DAC2+1, 1 << 12);
-		set_adc_rate(s, 22050);
-		set_dac1_rate(s, 22050);
-		set_dac2_rate(s, 22050);
-		/* WARNING:
-		 * enabling the sample rate converter without properly programming
-		 * its parameters causes the chip to lock up (the SRC busy bit will
-		 * be stuck high, and I've found no way to rectify this other than
-		 * power cycle)
-		 */
-		wait_src_ready(s);
-		outl(0, s->io+ES1371_REG_SRCONV);
+                src_init(s);
 		/* codec init */
-		wrcodec(s, 0x00, 0); /* reset codec */
-		s->mix.codec_id = rdcodec(s, 0x00);  /* get codec ID */
-		val = rdcodec(s, 0x7c);
-		val2 = rdcodec(s, 0x7e);
+		wrcodec(s, AC97_RESET, 0); /* reset codec */
+		s->mix.codec_id = rdcodec(s, AC97_RESET);  /* get codec ID */
+		val = rdcodec(s, AC97_VENDOR_ID1);
+		val2 = rdcodec(s, AC97_VENDOR_ID2);
 		printk(KERN_INFO "es1371: codec vendor %c%c%c revision %d\n", 
 		       (val >> 8) & 0xff, val & 0xff, (val2 >> 8) & 0xff, val2 & 0xff);
 		printk(KERN_INFO "es1371: codec features");
@@ -2875,6 +3073,7 @@
 		printk("%s\n", (s->mix.codec_id & 0x3ff) ? "" : " none");
 		val = (s->mix.codec_id >> CODEC_ID_SESHIFT) & CODEC_ID_SEMASK;
 		printk(KERN_INFO "es1371: stereo enhancement: %s\n", (val <= 20) ? stereo_enhancement[val] : "unknown");
+
 		fs = get_fs();
 		set_fs(KERNEL_DS);
 		val = SOUND_MASK_LINE;
@@ -2929,6 +3128,10 @@
 
 	while ((s = devs)) {
 		devs = devs->next;
+#ifdef ES1371_DEBUG
+		if (s->ps)
+			remove_proc_entry("es1371", NULL);
+#endif /* ES1371_DEBUG */
 		outl(0, s->io+ES1371_REG_CONTROL); /* switch everything off */
 		outl(0, s->io+ES1371_REG_SERIAL_CONTROL); /* clear serial interrupts */
 		synchronize_irq();
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/drivers/sound/esssolo1.c linux.14p1/drivers/sound/esssolo1.c
--- linux.vanilla/drivers/sound/esssolo1.c	Wed Oct 20 01:12:48 1999
+++ linux.14p1/drivers/sound/esssolo1.c	Fri Oct 22 22:34:17 1999
@@ -54,12 +54,17 @@
  *                     The fun part is that the Windows Solo1 driver doesn't
  *                     seem to do these tricks.
  *                     Bugs remaining: plops and clicks when starting/stopping playback
+ *    31.08.99   0.7   add spin_lock_init
+ *                     replaced current->state = x with set_current_state(x)
+ *    03.09.99   0.8   change read semantics for MIDI to match
+ *                     OSS more closely; remove possible wakeup race
+ *    07.10.99   0.9   Fix initialization; complain if sequencer writes time out
+ *                     Revised resource grabbing for the FM synthesizer
  *
  */
 
 /*****************************************************************************/
       
-#include <linux/config.h>
 #include <linux/version.h>
 #include <linux/module.h>
 #include <linux/string.h>
@@ -96,7 +101,7 @@
 
 #define SOLO1_MAGIC  ((PCI_VENDOR_ID_ESS<<16)|PCI_DEVICE_ID_ESS_SOLO1)
 
-#define DDMABASE_OFFSET           0x10    /* chip bug workaround kludge */
+#define DDMABASE_OFFSET           0    /* chip bug workaround kludge */
 #define DDMABASE_EXTENT           16
 
 #define IOBASE_EXTENT             16
@@ -105,6 +110,7 @@
 #define MPUBASE_EXTENT            4
 #define GPBASE_EXTENT             4
 
+#define FMSYNTH_EXTENT            4
 
 /* MIDI buffer sizes */
 
@@ -137,6 +143,8 @@
 #define wait_queue_head_t struct wait_queue *
 #define init_waitqueue_head(w) *(w) = 0
 #define init_MUTEX(m) *(m) = MUTEX
+#define __set_current_state(x) do { current->state = (x); } while (0)
+#define set_current_state(x) __set_current_state(x)
 #endif
 
 /* --------------------------------------------------------------------- */
@@ -226,7 +234,7 @@
 {
         int i;
 	unsigned long flags;
-        
+
 	/* the __cli stunt is to send the data within the command window */
         for (i = 0; i < 0xffff; i++) {
 		__save_flags(flags);
@@ -238,6 +246,8 @@
                 }
 		__restore_flags(flags);
 	}
+	printk(KERN_ERR "esssolo1: write_seq timeout\n");
+	outb(data, s->sbbase+0xc);
 }
 
 extern inline int read_seq(struct solo1_state *s, unsigned char *data)
@@ -251,6 +261,7 @@
                         *data = inb(s->sbbase+0xa);
                         return 1;
                 }
+	printk(KERN_ERR "esssolo1: read_seq timeout\n");
         return 0;
 }
 
@@ -952,7 +963,7 @@
 	
 	if (s->dma_dac.mapped)
 		return 0;
-        current->state = TASK_INTERRUPTIBLE;
+        __set_current_state(TASK_INTERRUPTIBLE);
         add_wait_queue(&s->dma_dac.wait, &wait);
         for (;;) {
                 spin_lock_irqsave(&s->lock, flags);
@@ -964,7 +975,7 @@
                         break;
                 if (nonblock) {
                         remove_wait_queue(&s->dma_dac.wait, &wait);
-                        current->state = TASK_RUNNING;
+                        set_current_state(TASK_RUNNING);
                         return -EBUSY;
                 }
 		tmo = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->rate;
@@ -976,7 +987,7 @@
                         printk(KERN_DEBUG "solo1: dma timed out??\n");
         }
         remove_wait_queue(&s->dma_dac.wait, &wait);
-        current->state = TASK_RUNNING;
+        set_current_state(TASK_RUNNING);
         if (signal_pending(current))
                 return -ERESTARTSYS;
         return 0;
@@ -1622,6 +1633,7 @@
 static ssize_t solo1_midi_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
 {
 	struct solo1_state *s = (struct solo1_state *)file->private_data;
+	DECLARE_WAITQUEUE(wait, current);
 	ssize_t ret;
 	unsigned long flags;
 	unsigned ptr;
@@ -1632,7 +1644,10 @@
 		return -ESPIPE;
 	if (!access_ok(VERIFY_WRITE, buffer, count))
 		return -EFAULT;
+	if (count == 0)
+		return 0;
 	ret = 0;
+	add_wait_queue(&s->midi.iwait, &wait);
 	while (count > 0) {
 		spin_lock_irqsave(&s->lock, flags);
 		ptr = s->midi.ird;
@@ -1643,15 +1658,25 @@
 		if (cnt > count)
 			cnt = count;
 		if (cnt <= 0) {
-			if (file->f_flags & O_NONBLOCK)
-				return ret ? ret : -EAGAIN;
-			interruptible_sleep_on(&s->midi.iwait);
-			if (signal_pending(current))
-				return ret ? ret : -ERESTARTSYS;
+			if (file->f_flags & O_NONBLOCK) {
+				if (!ret)
+					ret = -EAGAIN;
+				break;
+			}
+			__set_current_state(TASK_INTERRUPTIBLE);
+			schedule();
+			if (signal_pending(current)) {
+				if (!ret)
+					ret = -ERESTARTSYS;
+				break;
+			}
 			continue;
 		}
-		if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt))
-			return ret ? ret : -EFAULT;
+		if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) {
+			if (!ret)
+				ret = -EFAULT;
+			break;
+		}
 		ptr = (ptr + cnt) % MIDIINBUF;
 		spin_lock_irqsave(&s->lock, flags);
 		s->midi.ird = ptr;
@@ -1660,13 +1685,17 @@
 		count -= cnt;
 		buffer += cnt;
 		ret += cnt;
+		break;
 	}
+	__set_current_state(TASK_RUNNING);
+	remove_wait_queue(&s->midi.iwait, &wait);
 	return ret;
 }
 
 static ssize_t solo1_midi_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
 {
 	struct solo1_state *s = (struct solo1_state *)file->private_data;
+	DECLARE_WAITQUEUE(wait, current);
 	ssize_t ret;
 	unsigned long flags;
 	unsigned ptr;
@@ -1677,7 +1706,10 @@
 		return -ESPIPE;
 	if (!access_ok(VERIFY_READ, buffer, count))
 		return -EFAULT;
+	if (count == 0)
+		return 0;
 	ret = 0;
+        add_wait_queue(&s->midi.owait, &wait);
 	while (count > 0) {
 		spin_lock_irqsave(&s->lock, flags);
 		ptr = s->midi.owr;
@@ -1690,15 +1722,25 @@
 		if (cnt > count)
 			cnt = count;
 		if (cnt <= 0) {
-			if (file->f_flags & O_NONBLOCK)
-				return ret ? ret : -EAGAIN;
-			interruptible_sleep_on(&s->midi.owait);
-			if (signal_pending(current))
-				return ret ? ret : -ERESTARTSYS;
+			if (file->f_flags & O_NONBLOCK) {
+				if (!ret)
+					ret = -EAGAIN;
+				break;
+			}
+			__set_current_state(TASK_INTERRUPTIBLE);
+			schedule();
+			if (signal_pending(current)) {
+				if (!ret)
+					ret = -ERESTARTSYS;
+				break;
+			}
 			continue;
 		}
-		if (copy_from_user(s->midi.obuf + ptr, buffer, cnt))
-			return ret ? ret : -EFAULT;
+		if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) {
+			if (!ret)
+				ret = -EFAULT;
+			break;
+		}
 		ptr = (ptr + cnt) % MIDIOUTBUF;
 		spin_lock_irqsave(&s->lock, flags);
 		s->midi.owr = ptr;
@@ -1711,6 +1753,8 @@
 		solo1_handle_midi(s);
 		spin_unlock_irqrestore(&s->lock, flags);
 	}
+	__set_current_state(TASK_RUNNING);
+	remove_wait_queue(&s->midi.owait, &wait);
 	return ret;
 }
 
@@ -1979,6 +2023,12 @@
 			return -ERESTARTSYS;
 		down(&s->open_sem);
 	}
+	if (check_region(s->sbbase, FMSYNTH_EXTENT)) {
+		up(&s->open_sem);
+		printk(KERN_ERR "solo1: FM synth io ports in use, opl3 loaded?\n");
+		return -EBUSY;
+	}
+	request_region(s->sbbase, FMSYNTH_EXTENT, "ESS Solo1");
 	/* init the stuff */
 	outb(1, s->sbbase);
 	outb(0x20, s->sbbase+1); /* enable waveforms */
@@ -2006,6 +2056,7 @@
 		outb(regb, s->sbbase+2);
 		outb(0, s->sbbase+3);
 	}
+	release_region(s->sbbase, FMSYNTH_EXTENT);
 	up(&s->open_sem);
 	wake_up(&s->open_wait);
 	MOD_DEC_USE_COUNT;
@@ -2062,7 +2113,7 @@
 
 	if (!pci_present())   /* No PCI bus in this machine! */
 		return -ENODEV;
-	printk(KERN_INFO "solo1: version v0.6 time " __TIME__ " " __DATE__ "\n");
+	printk(KERN_INFO "solo1: version v0.9 time " __TIME__ " " __DATE__ "\n");
 	while (index < NR_DEVICE && 
 	       (pcidev = pci_find_device(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_SOLO1, pcidev))) {
 		if (pcidev->base_address[0] == 0 ||
@@ -2087,6 +2138,7 @@
 		init_waitqueue_head(&s->midi.iwait);
 		init_waitqueue_head(&s->midi.owait);
 		init_MUTEX(&s->open_sem);
+		spin_lock_init(&s->lock);
 		s->magic = SOLO1_MAGIC;
 		s->pcidev = pcidev;
 		s->iobase = pcidev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
@@ -2097,14 +2149,14 @@
 		s->gpbase = pcidev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK;
 		s->irq = pcidev->irq;
 		if (check_region(s->iobase, IOBASE_EXTENT) ||
-		    check_region(s->sbbase+4, SBBASE_EXTENT-4) ||
+		    check_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT) ||
 		    check_region(s->ddmabase, DDMABASE_EXTENT) ||
 		    check_region(s->mpubase, MPUBASE_EXTENT)) {
 			printk(KERN_ERR "solo1: io ports in use\n");
 			goto err_region;
 		}
 		request_region(s->iobase, IOBASE_EXTENT, "ESS Solo1");
-		request_region(s->sbbase+4, SBBASE_EXTENT-4, "ESS Solo1");  /* allow OPL3 synth module */
+		request_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT, "ESS Solo1");  /* allow OPL3 synth module */
 		request_region(s->ddmabase, DDMABASE_EXTENT, "ESS Solo1");
 		request_region(s->mpubase, MPUBASE_EXTENT, "ESS Solo1");
 		if (request_irq(s->irq, solo1_interrupt, SA_SHIRQ, "ESS Solo1", s)) {
@@ -2131,6 +2183,10 @@
 		if ((s->dev_dmfm = register_sound_special(&solo1_dmfm_fops, 15 /* ?? */)) < 0)
 			goto err_dev4;
 		/* initialize the chips */
+		if (!reset_ctrl(s)) {
+			printk(KERN_ERR "esssolo1: cannot reset controller\n");
+			goto err;
+		}
 		outb(0xb0, s->iobase+7); /* enable A1, A2, MPU irq's */
 
 		/* initialize mixer regs */
@@ -2165,6 +2221,8 @@
 		index++;
 		continue;
 
+	err:
+		unregister_sound_dsp(s->dev_dmfm);
 	err_dev4:
 		unregister_sound_dsp(s->dev_midi);
 	err_dev3:
@@ -2176,7 +2234,7 @@
 		free_irq(s->irq, s);
 	err_irq:
 		release_region(s->iobase, IOBASE_EXTENT);
-		release_region(s->sbbase+4, SBBASE_EXTENT-4);
+		release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT);
 		release_region(s->ddmabase, DDMABASE_EXTENT);
 		release_region(s->mpubase, MPUBASE_EXTENT);
 	err_region:
@@ -2206,7 +2264,7 @@
 		pci_write_config_word(s->pcidev, 0x60, 0); /* turn off DDMA controller address space */
 		free_irq(s->irq, s);
 		release_region(s->iobase, IOBASE_EXTENT);
-		release_region(s->sbbase+4, SBBASE_EXTENT-4);
+		release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT);
 		release_region(s->ddmabase, DDMABASE_EXTENT);
 		release_region(s->mpubase, MPUBASE_EXTENT);
 		unregister_sound_dsp(s->dev_audio);
@@ -2222,5 +2280,4 @@
 
 module_init(init_solo1);
 module_exit(cleanup_solo1);
-
 
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/drivers/sound/lowlevel/miroaci.h linux.14p1/drivers/sound/lowlevel/miroaci.h
--- linux.vanilla/drivers/sound/lowlevel/miroaci.h	Sun Aug 23 21:32:25 1998
+++ linux.14p1/drivers/sound/lowlevel/miroaci.h	Fri Oct 22 22:19:05 1999
@@ -1,6 +1,11 @@
+#ifdef CONFIG_ACI_MIXER
 extern int aci_implied_cmd(unsigned char opcode);
 extern int aci_write_cmd(unsigned char opcode, unsigned char parameter);
 extern int aci_write_cmd_d(unsigned char opcode, unsigned char parameter, unsigned char parameter2);
 extern int aci_read_cmd(unsigned char opcode, int length, unsigned char *parameter);
 extern int aci_indexed_cmd(unsigned char opcode, unsigned char index, unsigned char *parameter);
+#else
 
+#error Compiling a driver that needs the ACI-mixer but without ACI-mixer support
+
+#endif
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/drivers/sound/msnd_pinnacle.c linux.14p1/drivers/sound/msnd_pinnacle.c
--- linux.vanilla/drivers/sound/msnd_pinnacle.c	Wed Oct 20 01:12:48 1999
+++ linux.14p1/drivers/sound/msnd_pinnacle.c	Fri Oct 22 21:25:36 1999
@@ -46,6 +46,7 @@
 #  include <linux/init.h>
 #endif
 #include <asm/irq.h>
+#include <asm/io.h>
 #include "sound_config.h"
 #include "sound_firmware.h"
 #ifdef MSND_CLASSIC
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/drivers/sound/nm256_audio.c linux.14p1/drivers/sound/nm256_audio.c
--- linux.vanilla/drivers/sound/nm256_audio.c	Wed Oct 20 01:12:48 1999
+++ linux.14p1/drivers/sound/nm256_audio.c	Fri Oct 22 21:25:36 1999
@@ -14,6 +14,8 @@
 #include <linux/config.h>
 #include <linux/pci.h>
 #include <linux/module.h>
+#include <linux/delay.h>
+
 #include "sound_config.h"
 #include "soundmodule.h"
 #include "nm256.h"
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/drivers/sound/opl3.c linux.14p1/drivers/sound/opl3.c
--- linux.vanilla/drivers/sound/opl3.c	Wed Aug 19 22:48:30 1998
+++ linux.14p1/drivers/sound/opl3.c	Fri Oct 22 22:52:53 1999
@@ -32,8 +32,6 @@
 #include "sound_config.h"
 #include "soundmodule.h"
 
-#ifdef CONFIG_YM3812
-
 #include "opl3.h"
 
 #define MAX_VOICE	18
@@ -1223,5 +1221,3 @@
 EXPORT_SYMBOL(opl3_init);
 EXPORT_SYMBOL(opl3_detect);
 MODULE_PARM(io, "i");
-
-#endif
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/drivers/sound/sonicvibes.c linux.14p1/drivers/sound/sonicvibes.c
--- linux.vanilla/drivers/sound/sonicvibes.c	Wed Oct 20 01:12:48 1999
+++ linux.14p1/drivers/sound/sonicvibes.c	Fri Oct 22 22:34:17 1999
@@ -71,6 +71,14 @@
  *    15.06.99   0.15  Fix bad allocation bug.
  *                     Thanks to Deti Fliegl <fliegl@in.tum.de>
  *    28.06.99   0.16  Add pci_set_master
+ *    03.08.99   0.17  adapt to Linus' new __setup/__initcall
+ *                     added kernel command line options "sonicvibes=reverb" and "sonicvibesdmaio=dmaioaddr"
+ *    12.08.99   0.18  module_init/__setup fixes
+ *    24.08.99   0.19  get rid of the dmaio kludge, replace with allocate_resource
+ *    31.08.99   0.20  add spin_lock_init
+ *                     __initlocaldata to fix gcc 2.7.x problems
+ *    03.09.99   0.21  change read semantics for MIDI to match
+ *                     OSS more closely; remove possible wakeup race
  *
  */
 
@@ -1265,9 +1273,9 @@
                         current->state = TASK_RUNNING;
                         return -EBUSY;
                 }
-		tmo = (count * HZ) / s->ratedac;
+		tmo = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->ratedac;
 		tmo >>= sample_shift[(s->fmt >> SV_CFMT_ASHIFT) & SV_CFMT_MASK];
-		if (!schedule_timeout(tmo ? : 1) && tmo)
+		if (!schedule_timeout(tmo + 1))
 			printk(KERN_DEBUG "sv: dma timed out??\n");
         }
         remove_wait_queue(&s->dma_dac.wait, &wait);
@@ -1870,6 +1878,7 @@
 static ssize_t sv_midi_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
 {
 	struct sv_state *s = (struct sv_state *)file->private_data;
+	struct wait_queue wait = { current, NULL };
 	ssize_t ret;
 	unsigned long flags;
 	unsigned ptr;
@@ -1880,7 +1889,10 @@
 		return -ESPIPE;
 	if (!access_ok(VERIFY_WRITE, buffer, count))
 		return -EFAULT;
+	if (count == 0)
+		return 0;
 	ret = 0;
+	add_wait_queue(&s->midi.iwait, &wait);
 	while (count > 0) {
 		spin_lock_irqsave(&s->lock, flags);
 		ptr = s->midi.ird;
@@ -1891,15 +1903,25 @@
 		if (cnt > count)
 			cnt = count;
 		if (cnt <= 0) {
-			if (file->f_flags & O_NONBLOCK)
-				return ret ? ret : -EAGAIN;
-			interruptible_sleep_on(&s->midi.iwait);
-			if (signal_pending(current))
-				return ret ? ret : -ERESTARTSYS;
+                      if (file->f_flags & O_NONBLOCK) {
+                              if (!ret)
+                                      ret = -EAGAIN;
+                              break;
+                      }
+                      current->state = TASK_INTERRUPTIBLE;
+                      schedule();
+                      if (signal_pending(current)) {
+                              if (!ret)
+                                      ret = -ERESTARTSYS;
+                              break;
+                      }
 			continue;
 		}
-		if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt))
-			return ret ? ret : -EFAULT;
+		if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) {
+			if (!ret)
+				ret = -EFAULT;
+			break;
+		}
 		ptr = (ptr + cnt) % MIDIINBUF;
 		spin_lock_irqsave(&s->lock, flags);
 		s->midi.ird = ptr;
@@ -1908,13 +1930,17 @@
 		count -= cnt;
 		buffer += cnt;
 		ret += cnt;
+		break;
 	}
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&s->midi.iwait, &wait);
 	return ret;
 }
 
 static ssize_t sv_midi_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
 {
 	struct sv_state *s = (struct sv_state *)file->private_data;
+	struct wait_queue wait = { current, NULL };
 	ssize_t ret;
 	unsigned long flags;
 	unsigned ptr;
@@ -1925,7 +1951,10 @@
 		return -ESPIPE;
 	if (!access_ok(VERIFY_READ, buffer, count))
 		return -EFAULT;
+	if (count == 0)
+		return 0;
 	ret = 0;
+        add_wait_queue(&s->midi.owait, &wait);
 	while (count > 0) {
 		spin_lock_irqsave(&s->lock, flags);
 		ptr = s->midi.owr;
@@ -1938,15 +1967,25 @@
 		if (cnt > count)
 			cnt = count;
 		if (cnt <= 0) {
-			if (file->f_flags & O_NONBLOCK)
-				return ret ? ret : -EAGAIN;
-			interruptible_sleep_on(&s->midi.owait);
-			if (signal_pending(current))
-				return ret ? ret : -ERESTARTSYS;
+			if (file->f_flags & O_NONBLOCK) {
+				if (!ret)
+					ret = -EAGAIN;
+				break;
+			}
+			current->state = TASK_INTERRUPTIBLE;
+			schedule();
+			if (signal_pending(current)) {
+				if (!ret)
+					ret = -ERESTARTSYS;
+				break;
+			}
 			continue;
 		}
-		if (copy_from_user(s->midi.obuf + ptr, buffer, cnt))
-			return ret ? ret : -EFAULT;
+		if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) {
+			if (!ret)
+				ret = -EFAULT;
+			break;
+		}
 		ptr = (ptr + cnt) % MIDIOUTBUF;
 		spin_lock_irqsave(&s->lock, flags);
 		s->midi.owr = ptr;
@@ -1959,6 +1998,8 @@
 		sv_handle_midi(s);
 		spin_unlock_irqrestore(&s->lock, flags);
 	}
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&s->midi.owait, &wait);
 	return ret;
 }
 
@@ -2324,7 +2365,7 @@
 
 	if (!pci_present())   /* No PCI bus in this machine! */
 		return -ENODEV;
-	printk(KERN_INFO "sv: version v0.16 time " __TIME__ " " __DATE__ "\n");
+	printk(KERN_INFO "sv: version v0.21 time " __TIME__ " " __DATE__ "\n");
 #if 0
 	if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT)))
 		printk(KERN_INFO "sv: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n");
@@ -2353,6 +2394,7 @@
 		init_waitqueue(&s->midi.iwait);
 		init_waitqueue(&s->midi.owait);
 		s->open_sem = MUTEX;
+		spin_lock_init(&s->lock);
 		s->magic = SV_MAGIC;
 		s->iosb = pcidev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
 		s->ioenh = pcidev->base_address[1] & PCI_BASE_ADDRESS_IO_MASK;
@@ -2423,8 +2465,8 @@
 		wrindir(s, SV_CIDRIVECONTROL, 0);  /* drive current 16mA */
 		wrindir(s, SV_CIENABLE, s->enable = 0);  /* disable DMAA and DMAC */
 		outb(~(SV_CINTMASK_DMAA | SV_CINTMASK_DMAC), s->ioenh + SV_CODEC_INTMASK);
-		//outb(0xff, s->iodmaa + SV_DMA_RESET);
-		//outb(0xff, s->iodmac + SV_DMA_RESET);
+		/* outb(0xff, s->iodmaa + SV_DMA_RESET); */
+		/* outb(0xff, s->iodmac + SV_DMA_RESET); */
 		inb(s->ioenh + SV_CODEC_STATUS); /* ack interrupts */
 		wrindir(s, SV_CIADCCLKSOURCE, 0); /* use pll as ADC clock source */
 		wrindir(s, SV_CIANALOGPWRDOWN, 0); /* power up the analog parts of the device */
@@ -2524,8 +2566,8 @@
 		synchronize_irq();
 		inb(s->ioenh + SV_CODEC_STATUS); /* ack interrupts */
 		wrindir(s, SV_CIENABLE, 0);     /* disable DMAA and DMAC */
-		//outb(0, s->iodmaa + SV_DMA_RESET);
-		//outb(0, s->iodmac + SV_DMA_RESET);
+		/*outb(0, s->iodmaa + SV_DMA_RESET);*/
+		/*outb(0, s->iodmac + SV_DMA_RESET);*/
 		free_irq(s->irq, s);
 		release_region(s->iodmac, SV_EXTENT_DMA);
 		release_region(s->iodmaa, SV_EXTENT_DMA);
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/fs/binfmt_aout.c linux.14p1/fs/binfmt_aout.c
--- linux.vanilla/fs/binfmt_aout.c	Wed Oct 20 01:12:49 1999
+++ linux.14p1/fs/binfmt_aout.c	Fri Oct 22 22:12:15 1999
@@ -311,6 +311,7 @@
 	unsigned long fd_offset;
 	unsigned long rlim;
 	int retval;
+	static int warnings = 0;
 
 	ex = *((struct exec *) bprm->buf);		/* exec-header */
 	if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC &&
@@ -322,6 +323,23 @@
 
 	fd_offset = N_TXTOFF(ex);
 
+#ifdef __i386__
+	if (N_MAGIC(ex) == ZMAGIC && fd_offset != BLOCK_SIZE) {
+		if(warnings++<10)
+			printk(KERN_NOTICE "N_TXTOFF != BLOCK_SIZE. See a.out.h.\n");
+		return -ENOEXEC;
+	}
+
+	if (N_MAGIC(ex) == ZMAGIC && ex.a_text &&
+	    bprm->dentry->d_inode->i_op &&
+	    bprm->dentry->d_inode->i_op->bmap &&
+	    (fd_offset < bprm->dentry->d_inode->i_sb->s_blocksize)) {
+		if(warnings++<10)
+			printk(KERN_NOTICE "N_TXTOFF < BLOCK_SIZE. Please convert binary.\n");
+		return -ENOEXEC;
+	}
+#endif
+
 	/* Check initial limits. This avoids letting people circumvent
 	 * size limits imposed on them by creating programs with large
 	 * arrays in the data or bss.
@@ -389,33 +407,19 @@
 		flush_icache_range((unsigned long) 0,
 				   (unsigned long) ex.a_text+ex.a_data);
 	} else {
-		static unsigned long error_time, error_time2;
 		if ((ex.a_text & 0xfff || ex.a_data & 0xfff) &&
-		    (N_MAGIC(ex) != NMAGIC) && (jiffies-error_time2) > 5*HZ)
-		{
-			printk(KERN_NOTICE "executable not page aligned\n");
-			error_time2 = jiffies;
-		}
+		    (N_MAGIC(ex) != NMAGIC))
+			if(warnings++<10)
+				printk(KERN_NOTICE "executable not page aligned\n");
 
 		fd = open_dentry(bprm->dentry, O_RDONLY);
 		if (fd < 0)
 			return fd;
-		file = fget(fd);
+		file = fcheck(fd);
 
-		if ((fd_offset & ~PAGE_MASK) != 0 &&
-		    (jiffies-error_time) > 5*HZ)
-		{
-			printk(KERN_WARNING 
-			       "fd_offset is not page aligned. Please convert program: %s\n",
-			       file->f_dentry->d_name.name
-			       );
-			error_time = jiffies;
-		}
-
-		if (!file->f_op || !file->f_op->mmap || ((fd_offset & ~PAGE_MASK) != 0)) {
-			fput(file);
+		if (!file->f_op || !file->f_op->mmap) {
 			sys_close(fd);
-			do_mmap(NULL, N_TXTADDR(ex), ex.a_text+ex.a_data,
+			do_mmap(NULL, 0, ex.a_text+ex.a_data,
 				PROT_READ|PROT_WRITE|PROT_EXEC,
 				MAP_FIXED|MAP_PRIVATE, 0);
 			read_exec(bprm->dentry, fd_offset,
@@ -432,7 +436,6 @@
 			fd_offset);
 
 		if (error != N_TXTADDR(ex)) {
-			fput(file);
 			sys_close(fd);
 			send_sig(SIGKILL, current, 0);
 			return error;
@@ -442,7 +445,6 @@
 				PROT_READ | PROT_WRITE | PROT_EXEC,
 				MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
 				fd_offset + ex.a_text);
-		fput(file);
 		sys_close(fd);
 		if (error != N_DATADDR(ex)) {
 			send_sig(SIGKILL, current, 0);
@@ -497,6 +499,7 @@
 	unsigned long error;
 	int retval;
 	loff_t offset = 0;
+	static int warnings = 0;
 	struct exec ex;
 
 	retval = -EACCES;
@@ -522,6 +525,13 @@
 		goto out_putf;
 	}
 
+	if (N_MAGIC(ex) == ZMAGIC && N_TXTOFF(ex) &&
+	    (N_TXTOFF(ex) < inode->i_sb->s_blocksize)) {
+	    	if(warnings++<10)
+			printk("N_TXTOFF < BLOCK_SIZE. Please convert library\n");
+		goto out_putf;
+	}
+
 	if (N_FLAGS(ex))
 		goto out_putf;
 
@@ -530,26 +540,6 @@
 
 	start_addr =  ex.a_entry & 0xfffff000;
 
-	if ((N_TXTOFF(ex) & ~PAGE_MASK) != 0) {
-		static unsigned long error_time;
-
-		if ((jiffies-error_time) > 5*HZ)
-		{
-			printk(KERN_WARNING 
-			       "N_TXTOFF is not page aligned. Please convert library: %s\n",
-			       file->f_dentry->d_name.name);
-			error_time = jiffies;
-		}
-		do_mmap(NULL, start_addr, ex.a_text + ex.a_data,
-			PROT_READ | PROT_WRITE | PROT_EXEC,
-			MAP_FIXED| MAP_PRIVATE, 0);
-		read_exec(file->f_dentry, N_TXTOFF(ex),
-			  (char *)start_addr, ex.a_text + ex.a_data, 0);
-		flush_icache_range((unsigned long) start_addr,
-				   (unsigned long) start_addr + ex.a_text + ex.a_data);
-		retval = 0;
-		goto out_putf;
-	}
 	/* Now use mmap to map the library into memory. */
 	error = do_mmap(file, start_addr, ex.a_text + ex.a_data,
 			PROT_READ | PROT_WRITE | PROT_EXEC,
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/fs/buffer.c linux.14p1/fs/buffer.c
--- linux.vanilla/fs/buffer.c	Sat Aug 14 02:27:35 1999
+++ linux.14p1/fs/buffer.c	Fri Oct 22 21:26:49 1999
@@ -58,11 +58,12 @@
 /*
  * Hash table mask..
  */
-static unsigned long bh_hash_mask = 0;
+static unsigned int bh_hash_mask = 0;
+static unsigned int bh_hash_shift = 0;
+static struct buffer_head ** hash_table = NULL;
 
 static int grow_buffers(int size);
 
-static struct buffer_head ** hash_table;
 static struct buffer_head * lru_list[NR_LIST] = {NULL, };
 static struct buffer_head * free_list[NR_SIZES] = {NULL, };
 
@@ -420,8 +421,13 @@
 	}
 }
 
-#define _hashfn(dev,block) (((unsigned)(HASHDEV(dev)^block)) & bh_hash_mask)
-#define hash(dev,block) hash_table[_hashfn(dev,block)]
+/* After several hours of tedious analysis, the following hash
+ * function won.  Do not mess with it... -DaveM
+ */
+#define _hashfn(dev,block)	\
+	((((dev)<<(bh_hash_shift - 6)) ^ ((dev)<<(bh_hash_shift - 9))) ^ \
+	 (((block)<<(bh_hash_shift - 6)) ^ ((block) >> 13) ^ ((block) << (bh_hash_shift - 12))))
+#define hash(dev,block) hash_table[_hashfn(dev,block) & bh_hash_mask]
 
 static inline void remove_from_hash_queue(struct buffer_head * bh)
 {
@@ -1512,16 +1518,26 @@
            for something that is really too small */
 
 	do {
+		unsigned long tmp;
+
 		nr_hash = (1UL << order) * PAGE_SIZE /
 		    sizeof(struct buffer_head *);
+		bh_hash_mask = (nr_hash - 1);
+
+		tmp = nr_hash;
+		bh_hash_shift = 0;
+		while((tmp >>= 1UL) != 0UL)
+			bh_hash_shift++;
+
 		hash_table = (struct buffer_head **)
 		    __get_free_pages(GFP_ATOMIC, order);
-	} while (hash_table == NULL && --order > 4);
+	} while (hash_table == NULL && --order >= 0);
+	printk("Buffer-cache hash table entries: %d (order: %d, %ld bytes)\n",
+	       nr_hash, order, (1UL<<order) * PAGE_SIZE);
 	
 	if (!hash_table)
 		panic("Failed to allocate buffer hash table\n");
 	memset(hash_table, 0, nr_hash * sizeof(struct buffer_head *));
-	bh_hash_mask = nr_hash-1;
 
 	bh_cachep = kmem_cache_create("buffer_head",
 				      sizeof(struct buffer_head),
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/fs/dcache.c linux.14p1/fs/dcache.c
--- linux.vanilla/fs/dcache.c	Sat Aug 14 02:25:58 1999
+++ linux.14p1/fs/dcache.c	Fri Oct 22 21:27:00 1999
@@ -22,6 +22,7 @@
 #include <linux/init.h>
 
 #include <asm/uaccess.h>
+#include <asm/cache.h>
 
 #define DCACHE_PARANOIA 1
 /* #define DCACHE_DEBUG 1 */
@@ -41,11 +42,12 @@
  * This hash-function tries to avoid losing too many bits of hash
  * information, yet avoid using a prime hash-size or similar.
  */
-#define D_HASHBITS     10
-#define D_HASHSIZE     (1UL << D_HASHBITS)
-#define D_HASHMASK     (D_HASHSIZE-1)
+#define D_HASHBITS     d_hash_shift
+#define D_HASHMASK     d_hash_mask
 
-static struct list_head dentry_hashtable[D_HASHSIZE];
+static unsigned int d_hash_mask = 0;
+static unsigned int d_hash_shift = 0;
+static struct list_head *dentry_hashtable = NULL;
 static LIST_HEAD(dentry_unused);
 
 struct {
@@ -563,7 +565,7 @@
 
 static inline struct list_head * d_hash(struct dentry * parent, unsigned long hash)
 {
-	hash += (unsigned long) parent;
+	hash += (unsigned long) parent / L1_CACHE_BYTES;
 	hash = hash ^ (hash >> D_HASHBITS) ^ (hash >> D_HASHBITS*2);
 	return dentry_hashtable + (hash & D_HASHMASK);
 }
@@ -902,8 +904,10 @@
 
 void __init dcache_init(void)
 {
-	int i;
-	struct list_head *d = dentry_hashtable;
+	int i, order;
+	struct list_head *d;
+	unsigned int nr_hash;
+	unsigned long memory_size;
 
 	/* 
 	 * A constructor could be added for stable state like the lists,
@@ -921,7 +925,33 @@
 	if (!dentry_cache)
 		panic("Cannot create dentry cache");
 
-	i = D_HASHSIZE;
+	memory_size = num_physpages << PAGE_SHIFT;
+	for (order = 5; (1UL << order) < memory_size; order++)
+		;
+
+	do {
+		unsigned long tmp;
+
+		nr_hash = (1UL << order) * PAGE_SIZE /
+			sizeof(struct list_head);
+		d_hash_mask = (nr_hash - 1);
+
+		tmp = nr_hash;
+		d_hash_shift = 0;
+		while((tmp >>= 1UL) != 0UL)
+			d_hash_shift++;
+
+		dentry_hashtable = (struct list_head *)
+			__get_free_pages(GFP_ATOMIC, order);
+	} while(dentry_hashtable == NULL && --order >= 0);
+	printk("DENTRY hash table entries: %d (order: %d, %ld bytes)\n",
+	       nr_hash, order, (1UL<<order) * PAGE_SIZE);
+
+	if (!dentry_hashtable)
+		panic("Failed to allocate dcache hash table\n");
+
+	d = dentry_hashtable;
+	i = nr_hash;
 	do {
 		INIT_LIST_HEAD(d);
 		d++;
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/fs/ext2/ialloc.c linux.14p1/fs/ext2/ialloc.c
--- linux.vanilla/fs/ext2/ialloc.c	Tue Oct 20 22:08:14 1998
+++ linux.14p1/fs/ext2/ialloc.c	Fri Oct 22 21:27:20 1999
@@ -268,21 +268,6 @@
 }
 
 /*
- * This function increments the inode version number
- *
- * This may be used one day by the NFS server
- */
-static void inc_inode_version (struct inode * inode,
-			       struct ext2_group_desc *gdp,
-			       int mode)
-{
-	inode->u.ext2_i.i_version++;
-	mark_inode_dirty(inode);
-
-	return;
-}
-
-/*
  * There are two policies for allocating an inode.  If the new inode is
  * a directory, then a forward search is made for a block group with both
  * free space and a low directory-to-inode ratio; if that fails, then of
@@ -493,8 +478,9 @@
 	if (inode->u.ext2_i.i_flags & EXT2_SYNC_FL)
 		inode->i_flags |= MS_SYNCHRONOUS;
 	insert_inode_hash(inode);
+	inode->i_generation = inode_generation_count++;
+	inode->u.ext2_i.i_version = inode->i_generation;
 	mark_inode_dirty(inode);
-	inc_inode_version (inode, gdp, mode);
 
 	unlock_super (sb);
 	if(DQUOT_ALLOC_INODE(sb, inode)) {
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/fs/ext2/inode.c linux.14p1/fs/ext2/inode.c
--- linux.vanilla/fs/ext2/inode.c	Wed Oct 20 01:12:49 1999
+++ linux.14p1/fs/ext2/inode.c	Fri Oct 22 21:27:20 1999
@@ -51,6 +51,10 @@
 	    inode->i_ino == EXT2_ACL_DATA_INO)
 		return;
 	inode->u.ext2_i.i_dtime	= CURRENT_TIME;
+	/* When we delete an inode, we increment its i_version. If it
+	   is ever read in from disk again, it will have a different
+	   i_version. */
+	inode->u.ext2_i.i_version++;
 	mark_inode_dirty(inode);
 	ext2_update_inode(inode, IS_SYNC(inode));
 	inode->i_size = 0;
@@ -538,6 +542,7 @@
 #endif
 	}
 	inode->u.ext2_i.i_version = le32_to_cpu(raw_inode->i_version);
+	inode->i_generation = inode->u.ext2_i.i_version;
 	inode->u.ext2_i.i_block_group = block_group;
 	inode->u.ext2_i.i_next_alloc_block = 0;
 	inode->u.ext2_i.i_next_alloc_goal = 0;
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/fs/ext2/ioctl.c linux.14p1/fs/ext2/ioctl.c
--- linux.vanilla/fs/ext2/ioctl.c	Sat Aug 14 02:27:37 1999
+++ linux.14p1/fs/ext2/ioctl.c	Fri Oct 22 21:27:20 1999
@@ -76,6 +76,7 @@
 			return -EROFS;
 		if (get_user(inode->u.ext2_i.i_version, (int *) arg))
 			return -EFAULT;	
+		inode->i_generation = inode->u.ext2_i.i_version;
 		inode->i_ctime = CURRENT_TIME;
 		mark_inode_dirty(inode);
 		return 0;
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/fs/filesystems.c linux.14p1/fs/filesystems.c
--- linux.vanilla/fs/filesystems.c	Sat Aug 14 02:27:37 1999
+++ linux.14p1/fs/filesystems.c	Fri Oct 22 21:27:34 1999
@@ -37,6 +37,7 @@
 #endif
 #include <linux/lockd/bind.h>
 #include <linux/lockd/xdr.h>
+#include <linux/lockd/syscall.h>
 #include <linux/init.h>
 #include <linux/nls.h>
 
@@ -159,28 +160,48 @@
 #ifdef CONFIG_NFSD_MODULE
 int (*do_nfsservctl)(int, void *, void *) = NULL;
 #endif
+
+#ifdef CONFIG_LOCKD_MODULE
+int (*do_lockdctl)(int, void *, void *) = NULL;
+#endif
+
 int
 asmlinkage sys_nfsservctl(int cmd, void *argp, void *resp)
 {
-#ifndef CONFIG_NFSD_MODULE
-	return -ENOSYS;
-#else
 	int ret = -ENOSYS;
 	
+	if (cmd >= NFSCTL_LOCKD) {
+#if defined(CONFIG_LOCKD) || defined(CONFIG_LOCKD_MODULE)
+		lock_kernel();
+#ifdef CONFIG_LOCKD
+		ret = lockdctl(cmd, argp, resp);
+#else
+		if (do_lockdctl) 
+			ret = do_lockdctl(cmd, argp, resp);
+#ifdef CONFIG_KMOD
+		else if (request_module ("lockd") == 0) {
+			if (do_lockdctl)
+				ret = do_lockdctl(cmd, argp, resp);
+		}
+#endif
+#endif
+		unlock_kernel();
+#endif
+		return ret;
+	}
+
+#ifdef CONFIG_NFSD_MODULE
 	lock_kernel();
-	if (do_nfsservctl) {
+	if (do_nfsservctl)
 		ret = do_nfsservctl(cmd, argp, resp);
-		goto out;
-	}
 #ifdef CONFIG_KMOD
-	if (request_module ("nfsd") == 0) {
+	else if (request_module ("nfsd") == 0) {
 		if (do_nfsservctl)
 			ret = do_nfsservctl(cmd, argp, resp);
 	}
 #endif /* CONFIG_KMOD */
-out:
 	unlock_kernel();
-	return ret;
 #endif /* CONFIG_NFSD_MODULE */
+	return ret;
 }
 #endif /* CONFIG_NFSD */
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/fs/inode.c linux.14p1/fs/inode.c
--- linux.vanilla/fs/inode.c	Sat Aug 14 02:27:37 1999
+++ linux.14p1/fs/inode.c	Fri Oct 22 21:27:51 1999
@@ -10,6 +10,7 @@
 #include <linux/dcache.h>
 #include <linux/init.h>
 #include <linux/quotaops.h>
+#include <linux/random.h>
 
 /*
  * New inode.c implementation.
@@ -48,6 +49,8 @@
 static LIST_HEAD(inode_unused);
 static struct list_head inode_hashtable[HASH_SIZE];
 
+__u32 inode_generation_count = 0;
+
 /*
  * A simple spinlock to protect the list manipulations.
  *
@@ -809,6 +812,10 @@
 	if (max > MAX_INODE)
 		max = MAX_INODE;
 	max_inodes = max;
+
+	/* Get a random number. */
+	get_random_bytes (&inode_generation_count,
+			  sizeof (inode_generation_count));
 }
 
 /* This belongs in file_table.c, not here... */
@@ -844,3 +851,48 @@
     inode->i_atime = CURRENT_TIME;
     mark_inode_dirty (inode);
 }   /*  End Function update_atime  */
+
+/* This function is called by nfsd. */
+struct inode *iget_in_use(struct super_block *sb, unsigned long ino)
+{
+	struct list_head * head = inode_hashtable + hash(sb,ino);
+	struct inode * inode;
+
+	spin_lock(&inode_lock);
+	inode = find_inode(sb, ino, head);
+	if (inode) {
+		spin_unlock(&inode_lock);
+		wait_on_inode(inode);
+	}
+	else
+		inode = get_new_inode (sb, ino, head);
+
+	/* When we get the inode, we have to check if it is in use. We
+	   have to release it if it is not. */
+	if (inode) {
+		spin_lock(&inode_lock);
+		if (inode->i_nlink == 0 && inode->i_count == 1) {
+			--inode->i_count;
+			list_del(&inode->i_hash);
+			INIT_LIST_HEAD(&inode->i_hash);
+			list_del(&inode->i_list);
+			INIT_LIST_HEAD(&inode->i_list);
+			if (list_empty(&inode->i_hash)) {
+				list_del(&inode->i_list);
+				INIT_LIST_HEAD(&inode->i_list);
+				spin_unlock(&inode_lock);
+				clear_inode(inode);
+				spin_lock(&inode_lock);
+				list_add(&inode->i_list, &inode_unused);
+				inodes_stat.nr_free_inodes++;
+			}
+			else if (!(inode->i_state & I_DIRTY)) {
+				list_del(&inode->i_list);
+				list_add(&inode->i_list, &inode_in_use);
+			}
+			inode = NULL;
+		}
+		spin_unlock(&inode_lock);
+	}
+	return inode;
+}
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/fs/lockd/lockd_syms.c linux.14p1/fs/lockd/lockd_syms.c
--- linux.vanilla/fs/lockd/lockd_syms.c	Mon Apr  7 19:35:30 1997
+++ linux.14p1/fs/lockd/lockd_syms.c	Fri Oct 22 21:28:11 1999
@@ -23,6 +23,7 @@
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/svc.h>
 #include <linux/lockd/lockd.h>
+#include <linux/lockd/syscall.h>
 
 /* Start/stop the daemon */
 EXPORT_SYMBOL(lockd_up);
@@ -34,6 +35,7 @@
 /* NFS server entry points/hooks */
 EXPORT_SYMBOL(nlmsvc_invalidate_client);
 EXPORT_SYMBOL(nlmsvc_ops);
+EXPORT_SYMBOL(lockdctl);
 
 /* Configuration at insmod time */
 EXPORT_SYMBOL(nlmsvc_grace_period);
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/fs/lockd/svc.c linux.14p1/fs/lockd/svc.c
--- linux.vanilla/fs/lockd/svc.c	Sat Feb  6 20:46:21 1999
+++ linux.14p1/fs/lockd/svc.c	Fri Oct 22 21:28:11 1999
@@ -32,6 +32,7 @@
 #include <linux/sunrpc/svc.h>
 #include <linux/sunrpc/svcsock.h>
 #include <linux/lockd/lockd.h>
+#include <linux/lockd/syscall.h>
 #include <linux/nfs.h>
 
 #define NLMDBG_FACILITY		NLMDBG_SVC
@@ -315,6 +316,9 @@
   MODULE_PARM(nlm_grace_period, "10-240l");
   MODULE_PARM(nlm_timeout, "3-20l");
 #endif
+
+extern int (*do_lockdctl)(int, void *, void *);
+
 int
 init_module(void)
 {
@@ -324,6 +328,7 @@
 	nlmsvc_pid = 0;
 	lockd_exit = NULL;
 	nlmxdr_init();
+	do_lockdctl = lockdctl;
 	return 0;
 }
 
@@ -332,6 +337,7 @@
 {
 	/* FIXME: delete all NLM clients */
 	nlm_shutdown_hosts();
+	do_lockdctl = NULL;
 }
 #endif
 
@@ -370,3 +376,23 @@
 	"lockd",		/* service name */
 	&nlmsvc_stats,		/* stats table */
 };
+
+int
+lockdctl(int cmd, void *opaque_argp, void *opaque_resp)
+{
+	int err;
+
+	MOD_INC_USE_COUNT;
+
+	switch(cmd) {
+	case LOCKDCTL_SVC:
+		err = lockd_up ();
+		break;
+	default:
+		err = -EINVAL;
+	}
+
+	MOD_DEC_USE_COUNT;
+
+	return err;
+}
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/fs/locks.c linux.14p1/fs/locks.c
--- linux.vanilla/fs/locks.c	Sat Aug 14 02:27:37 1999
+++ linux.14p1/fs/locks.c	Fri Oct 22 21:28:11 1999
@@ -688,8 +688,11 @@
 
 	if (((start += l->l_start) < 0) || (l->l_len < 0))
 		return (0);
+	fl->fl_end = start + l->l_len - 1;
+	if (l->l_len > 0 && fl->fl_end < 0)
+		return (0);
 	fl->fl_start = start;	/* we record the absolute position */
-	if ((l->l_len == 0) || ((fl->fl_end = start + l->l_len - 1) < 0))
+	if (l->l_len == 0)
 		fl->fl_end = OFFSET_MAX;
 	
 	fl->fl_file = filp;
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/fs/nfs/inode.c linux.14p1/fs/nfs/inode.c
--- linux.vanilla/fs/nfs/inode.c	Wed Oct 20 01:12:49 1999
+++ linux.14p1/fs/nfs/inode.c	Fri Oct 22 21:28:40 1999
@@ -134,8 +134,10 @@
 	if ((rpc = server->client) != NULL)
 		rpc_shutdown_client(rpc);
 
+#if 0
 	if (!(server->flags & NFS_MOUNT_NONLM))
 		lockd_down();	/* release rpc.lockd */
+#endif
 	rpciod_down();		/* release rpciod */
 	/*
 	 * Invalidate the dircache for this superblock.
@@ -311,9 +313,11 @@
 	/* We're airborne */
 	unlock_super(sb);
 
+#if 0
 	/* Check whether to start the lockd process */
 	if (!(server->flags & NFS_MOUNT_NONLM))
 		lockd_up();
+#endif
 	return sb;
 
 	/* Yargs. It didn't work out. */
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/fs/nfsd/nfsctl.c linux.14p1/fs/nfsd/nfsctl.c
--- linux.vanilla/fs/nfsd/nfsctl.c	Wed Oct 20 01:12:49 1999
+++ linux.14p1/fs/nfsd/nfsctl.c	Fri Oct 22 21:29:04 1999
@@ -11,7 +11,7 @@
 #include <linux/module.h>
 #include <linux/version.h>
 
-#include <linux/linkage.h>
+#include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
@@ -29,6 +29,7 @@
 #include <linux/nfsd/cache.h>
 #include <linux/nfsd/xdr.h>
 #include <linux/nfsd/syscall.h>
+#include <linux/lockd/syscall.h>
 
 #if LINUX_VERSION_CODE >= 0x020100
 #include <asm/uaccess.h>
@@ -40,7 +41,6 @@
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 
-extern void nfsd_fh_init(void);
 extern long sys_call_table[];
 
 static int	nfsctl_svc(struct nfsctl_svc *data);
@@ -57,15 +57,72 @@
 int exp_procfs_exports(char *buffer, char **start, off_t offset,
                              int length, int *eof, void *data);
 
-void proc_export_init(void)
+struct long_maxmin
 {
-	struct proc_dir_entry *nfs_export_ent = NULL;
+	long *value;
+	long min_value;
+	long max_value;
+};
+
+/* In seconds. */
+#define TIME_DIFF_MARGIN	10
+#define MIN_TIME_DIFF_MARGIN	0
+#define MAX_TIME_DIFF_MARGIN	600
+
+long nfsd_time_diff_margin = TIME_DIFF_MARGIN;
+
+static struct long_maxmin time_diff_margin =
+{
+	&nfsd_time_diff_margin,
+	MIN_TIME_DIFF_MARGIN,
+	MAX_TIME_DIFF_MARGIN
+};
+
+static int
+nfsd_proc_read_long_maxmin(char *buffer, char **start, off_t offset,
+			  int length, int *eof, void *data)
+{
+	int len;
+	struct long_maxmin *x = (struct long_maxmin *) data;
+	len = sprintf(buffer, "%ld\n", *x->value) - offset;
+	if (len < length) {
+		*eof = 1;
+		if (len <= 0)
+			 return 0;
+	} else
+		len = length;
+	*start = buffer + offset;
+	return len;
+}
+
+static int
+nfsd_proc_write_long_maxmin(struct file *file, const char *buffer,
+			   unsigned long count, void *data)
+{
+	long v;
+	struct long_maxmin *x = (struct long_maxmin *) data;
+	v = simple_strtoul(buffer, NULL, 10);
+	if (v < x->min_value || v > x->max_value)
+		return -EINVAL;
+	*x->value = v;
+	return count;
+}
+
+static void nfsd_proc_init(void)
+{
+	struct proc_dir_entry *nfsd_ent = NULL;
 
-	if (!(nfs_export_ent = create_proc_entry("fs/nfs", S_IFDIR, 0)))
+	if (!(nfsd_ent = create_proc_entry("fs/nfs", S_IFDIR, 0)))
 		return;
-	if (!(nfs_export_ent = create_proc_entry("fs/nfs/exports", 0, 0)))
+	if (!(nfsd_ent = create_proc_entry("fs/nfs/exports", 0, 0)))
 		return;
-	nfs_export_ent->read_proc = exp_procfs_exports;
+	nfsd_ent->read_proc = exp_procfs_exports;
+	if (!(nfsd_ent = create_proc_entry("fs/nfs/time-diff-margin",
+					   S_IFREG|S_IRUGO|S_IWUSR, 0)))
+		return;
+	nfsd_ent->read_proc = nfsd_proc_read_long_maxmin;
+	nfsd_ent->write_proc = nfsd_proc_write_long_maxmin;
+	nfsd_ent->data = (void *) &time_diff_margin;
 }
 
 
@@ -80,8 +137,7 @@
 	nfsd_cache_init();	/* RPC reply cache */
 	nfsd_export_init();	/* Exports table */
 	nfsd_lockd_init();	/* lockd->nfsd callbacks */
-	nfsd_fh_init();		/* FH table */
-	proc_export_init();
+	nfsd_proc_init();
 	initialized = 1;
 }
 
@@ -209,6 +265,11 @@
 		goto done;
 	}
 
+	if (cmd >= NFSCTL_LOCKD) {
+		err = lockdctl(cmd, argp, resp);
+		goto done;
+	}
+
 	switch(cmd) {
 	case NFSCTL_SVC:
 		err = nfsctl_svc(&arg->ca_svc);
@@ -303,6 +364,7 @@
 	nfsd_export_shutdown();
 	nfsd_cache_shutdown();
 	nfsd_fh_free();
+	remove_proc_entry("fs/nfs/time-diff-margin", NULL);
 	remove_proc_entry("fs/nfs/exports", NULL);
 	remove_proc_entry("fs/nfs", NULL);
 	nfsd_stat_shutdown();
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/fs/nfsd/nfsfh.c linux.14p1/fs/nfsd/nfsfh.c
--- linux.vanilla/fs/nfsd/nfsfh.c	Wed Oct 20 01:12:49 1999
+++ linux.14p1/fs/nfsd/nfsfh.c	Fri Oct 22 21:29:04 1999
@@ -22,6 +22,7 @@
 #define NFSDDBG_FACILITY		NFSDDBG_FH
 #define NFSD_PARANOIA 1
 /* #define NFSD_DEBUG_VERBOSE 1 */
+/* #define NFSD_DEBUG_VERY_VERBOSE 1 */
 
 extern unsigned long max_mapnr;
 
@@ -34,16 +35,16 @@
 	kdev_t	dev;
 };
 
-#define NFSD_MAXFH PAGE_SIZE/sizeof(struct fh_entry)
-static struct fh_entry filetable[NFSD_MAXFH];
-static struct fh_entry dirstable[NFSD_MAXFH];
+#define NFSD_MAXFH \
+  (((nfsd_nservers + 1) >> 1) * PAGE_SIZE/sizeof(struct fh_entry))
+static struct fh_entry *filetable = NULL;
+static struct fh_entry *dirstable = NULL;
 
 static int nfsd_nr_verified = 0;
 static int nfsd_nr_put = 0;
 static unsigned long nfsd_next_expire = 0;
 
 static int add_to_fhcache(struct dentry *, int);
-static int nfsd_d_validate(struct dentry *);
 struct dentry * lookup_inode(kdev_t, ino_t, ino_t);
 
 static LIST_HEAD(fixup_head);
@@ -51,15 +52,16 @@
 static int nfsd_nr_fixups = 0;
 static int nfsd_nr_paths = 0;
 #define NFSD_MAX_PATHS 500
-#define NFSD_MAX_FIXUPAGE 60*HZ
+#define NFSD_MAX_FIXUPS 500
+#define NFSD_MAX_FIXUP_AGE 30*HZ
 
 struct nfsd_fixup {
 	struct list_head lru;
-	ino_t	dir;
+	unsigned long reftime;
+	ino_t	dirino;
 	ino_t	ino;
 	kdev_t	dev;
-	struct dentry *dentry;
-	unsigned long reftime;
+	ino_t	new_dirino;
 };
 
 struct nfsd_path {
@@ -71,7 +73,8 @@
 	char	name[1];
 };
 
-static struct nfsd_fixup * find_cached_lookup(kdev_t dev, ino_t dir, ino_t ino)
+static struct nfsd_fixup *
+find_cached_lookup(kdev_t dev, ino_t dirino, ino_t ino)
 {
 	struct list_head *tmp = fixup_head.next;
 
@@ -79,32 +82,43 @@
 		struct nfsd_fixup *fp;
 
 		fp = list_entry(tmp, struct nfsd_fixup, lru);
+#ifdef NFSD_DEBUG_VERY_VERBOSE
+printk("fixup %lu %lu, %lu %lu %s %s\n",
+        fp->ino, ino,
+	fp->dirino, dirino,
+	kdevname(fp->dev), kdevname(dev));
+#endif
 		if (fp->ino != ino)
 			continue;
-		if (fp->dir != dir)
+		if (fp->dirino != dirino)
 			continue;
 		if (fp->dev != dev)
 			continue;
+		fp->reftime = jiffies;	
 		list_del(tmp);
 		list_add(tmp, &fixup_head);
-		fp->reftime = jiffies;
 		return fp;
 	}
 	return NULL;
 }
 
 /*
- * Save the dentry pointer from a successful lookup.
+ * Save the dirino from a rename.
  */
-static void add_to_lookup_cache(struct dentry *dentry, struct knfs_fh *fh)
+void
+add_to_rename_cache(ino_t new_dirino,
+                    kdev_t dev, ino_t dirino, ino_t ino)
 {
 	struct nfsd_fixup *fp;
 
-	fp = find_cached_lookup(u32_to_kdev_t(fh->fh_dev), 
-				u32_to_ino_t(fh->fh_dirino),
-				u32_to_ino_t(fh->fh_ino));
+	if (dirino == new_dirino)
+		return;
+
+	fp = find_cached_lookup(dev, 
+				dirino,
+				ino);
 	if (fp) {
-		fp->dentry = dentry;
+		fp->new_dirino = new_dirino;
 		return;
 	}
 
@@ -115,19 +129,30 @@
 	 */
 	fp = kmalloc(sizeof(struct nfsd_fixup), GFP_KERNEL);
 	if (fp) {
-		fp->dir = u32_to_kdev_t(fh->fh_dirino);
-		fp->ino = u32_to_ino_t(fh->fh_ino);
-		fp->dev = u32_to_ino_t(fh->fh_dev);
-		fp->dentry = dentry;
-		fp->reftime = jiffies;
+		fp->dirino = dirino;
+		fp->ino = ino;
+		fp->dev = dev;
+		fp->new_dirino = new_dirino;
 		list_add(&fp->lru, &fixup_head);
 		nfsd_nr_fixups++;
 	}
 }
 
+/*
+ * Save the dentry pointer from a successful lookup.
+ */
+
 static void free_fixup_entry(struct nfsd_fixup *fp)
 {
 	list_del(&fp->lru);
+#ifdef NFSD_DEBUG_VERY_VERBOSE
+printk("free_rename_entry: %lu->%lu %lu/%s\n",
+		fp->dirino,
+		fp->new_dirino,
+		fp->ino,
+		kdevname(fp->dev),
+		(jiffies - fp->reftime));
+#endif
 	kfree(fp);
 	nfsd_nr_fixups--;
 }
@@ -212,9 +237,9 @@
 	if (new) {
 		new->users = 0;	
 		new->reftime = jiffies;	
-		new->ino = inode->i_ino;	
-		new->dev = inode->i_dev;	
-		result = copy_path(new->name, dentry, len);	
+		new->ino = inode->i_ino;
+		new->dev = inode->i_dev;
+		result = copy_path(new->name, dentry, len);
 		if (!result)
 			goto retry;
 		list_add(&new->lru, &path_inuse);
@@ -301,8 +326,8 @@
 	int result = 0;
 
 	buf->sequence++;
-#ifdef NFSD_DEBUG_VERBOSE
-printk("filldir_one: seq=%d, ino=%ld, name=%s\n", buf->sequence, ino, name);
+#ifdef NFSD_DEBUG_VERY_VERBOSE
+printk("filldir_one: seq=%d, ino=%lu, name=%s\n", buf->sequence, ino, name);
 #endif
 	if (buf->sequence == 2) {
 		buf->dirino = ino;
@@ -311,7 +336,7 @@
 	if (dirent->ino == ino) {
 		dirent->len = len;
 		memcpy(dirent->name, name, len);
-		dirent->name[len] = 0;
+		dirent->name[len] = '\0';
 		buf->found = 1;
 		result = -1;
 	}
@@ -431,7 +456,7 @@
 		}
 
 		result = ERR_PTR(-ENOENT);
-		dir = iget(sb, dirino);
+		dir = iget_in_use(sb, dirino);
 		if (!dir)
 			goto out_root;
 		dentry = d_alloc_root(dir, NULL);
@@ -483,7 +508,7 @@
 	iput(dir);
 out_root:
 	dput(root);
-	goto out;
+	goto out_page;
 }
 
 /*
@@ -521,7 +546,8 @@
 	struct dentry *dentry = empty->dentry;
 
 #ifdef NFSD_DEBUG_VERBOSE
-printk("expire_fhe: expiring %s/%s, d_count=%d, ino=%ld\n",
+printk("expire_fhe: expiring %s %s/%s, d_count=%d, ino=%lu\n",
+(cache == NFSD_FILE_CACHE) ? "file" : "dir",
 dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count,empty->ino);
 #endif
 	empty->dentry = NULL;	/* no dentry */
@@ -576,11 +602,10 @@
  */
 static void expire_old(int cache, int age)
 {
-	struct list_head *tmp;
 	struct fh_entry *fhe;
 	int i;
 
-#ifdef NFSD_DEBUG_VERBOSE
+#ifdef NFSD_DEBUG_VERY_VERBOSE
 printk("expire_old: expiring %s older than %d\n",
 (cache == NFSD_FILE_CACHE) ? "file" : "dir", age);
 #endif
@@ -593,12 +618,12 @@
 	}
 
 	/*
-	 * Remove old entries from the patch-up cache.
+	 * Trim the fixup cache ...
 	 */
-	while ((tmp = fixup_head.prev) != &fixup_head) {
+	while (nfsd_nr_fixups > NFSD_MAX_FIXUPS) {
 		struct nfsd_fixup *fp;
-		fp = list_entry(tmp, struct nfsd_fixup, lru);
-		if ((jiffies - fp->reftime) < NFSD_MAX_FIXUPAGE)
+		fp = list_entry(fixup_head.prev, struct nfsd_fixup, lru);
+		if ((jiffies - fp->reftime) < NFSD_MAX_FIXUP_AGE)
 			break;
 		free_fixup_entry(fp);
 	}
@@ -736,15 +761,21 @@
 					dget(dentry);
 					nfsd_nr_verified++;
 				}
+				put_path(pe);
 			} else {
 				dput(res);
+				put_path(pe);
+				/* We should delete it from the cache. */
+				free_path_entry(pe);
 			}
 		} else {
 #ifdef NFSD_PARANOIA
 printk("find_dentry_by_ino: %s lookup failed\n", pe->name);
 #endif
+			put_path(pe);
+			/* We should delete it from the cache. */
+			free_path_entry(pe);
 		}
-		put_path(pe);
 	}
 out:
 	return dentry;
@@ -757,6 +788,8 @@
  */
 static struct dentry *find_dentry_in_fhcache(struct knfs_fh *fh)
 {
+/* FIXME: this must use the dev/ino/dir_ino triple. */ 
+#if 0
 	struct fh_entry * fhe;
 
 	fhe = find_fhe(fh->fh_dcookie, NFSD_FILE_CACHE, NULL);
@@ -794,6 +827,7 @@
 		return dentry;
 	}
 out:
+#endif
 	return NULL;
 }
 
@@ -822,7 +856,7 @@
 printk("lookup_by_inode: found %s\n", dirent.name);
 #endif
 
-	dentry = lookup_dentry(dirent.name, dget(parent), 0);
+	dentry = lookup_dentry(dirent.name, parent, 0);
 	if (!IS_ERR(dentry)) {
 		if (dentry->d_inode && dentry->d_inode->i_ino == ino)
 			goto out;
@@ -842,13 +876,12 @@
 	dentry = NULL;
 out:
 	return dentry;
-
 }
 
 /*
  * Search the fix-up list for a dentry from a prior lookup.
  */
-static struct dentry *nfsd_cached_lookup(struct knfs_fh *fh)
+static ino_t nfsd_cached_lookup(struct knfs_fh *fh)
 {
 	struct nfsd_fixup *fp;
 
@@ -856,8 +889,8 @@
 				u32_to_ino_t(fh->fh_dirino),
 				u32_to_ino_t(fh->fh_ino));
 	if (fp)
-		return fp->dentry;
-	return NULL;
+		return fp->new_dirino;
+	return 0;
 }
 
 void
@@ -916,8 +949,12 @@
 static struct dentry *
 find_fh_dentry(struct knfs_fh *fh)
 {
+	struct super_block *sb;
 	struct dentry *dentry, *parent;
+	struct inode * inode;
+	struct list_head *lst;
 	int looked_up = 0, retry = 0;
+	ino_t dirino;
 
 	/*
 	 * Stage 1: Look for the dentry in the short-term fhcache.
@@ -927,50 +964,73 @@
 		nfsdstats.fh_cached++;
 		goto out;
 	}
-
 	/*
-	 * Stage 2: Attempt to validate the dentry in the file handle.
+	 * Stage 2: Attempt to find the inode.
 	 */
-	dentry = fh->fh_dcookie;
+	sb = get_super(fh->fh_dev);
+	if (NULL == sb) {
+		printk("find_fh_dentry: No SuperBlock for device %s.",
+		       kdevname(fh->fh_dev));
+		dentry = NULL;
+		goto out;
+	}
+
+	dirino = u32_to_ino_t(fh->fh_dirino);
+	inode = iget_in_use(sb, fh->fh_ino);
+	if (!inode) {
+		dprintk("find_fh_dentry: No inode found.\n");
+		goto out_five;
+	}
+	goto check;
 recheck:
-	if (nfsd_d_validate(dentry)) {
-		struct inode * dir = dentry->d_parent->d_inode;
+	if (!inode) {
+		dprintk("find_fh_dentry: No inode found.\n");
+		goto out_three;
+	}
+check:
+	for (lst = inode->i_dentry.next;
+	     lst != &inode->i_dentry;
+	     lst = lst->next) {
+		dentry = list_entry(lst, struct dentry, d_alias);
+
+/* if we are looking up a directory then we don't need the parent! */
+		if (!dentry ||
+		    !dentry->d_parent ||
+		    !dentry->d_parent->d_inode) {
+printk("find_fh_dentry: Found a useless inode %lu\n", inode->i_ino);
+			continue;
+		}
+		if (dentry->d_parent->d_inode->i_ino != dirino)
+			continue;
 
-		if (dir->i_ino == u32_to_ino_t(fh->fh_dirino) && 
-		    dir->i_dev == u32_to_kdev_t(fh->fh_dev)) {
-			struct inode * inode = dentry->d_inode;
-			/*
-			 * NFS file handles must always have an inode,
-			 * so we won't accept a negative dentry.
-			 */
-			if (inode && inode->i_ino == u32_to_ino_t(fh->fh_ino)) {
-				dget(dentry);
-#ifdef NFSD_DEBUG_VERBOSE
-printk("find_fh_dentry: validated %s/%s, ino=%ld\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, inode->i_ino);
-#endif
-				if (!retry)
-					nfsdstats.fh_valid++;
-				else {
-					nfsdstats.fh_fixup++;
+		dget(dentry);
+		iput(inode);
 #ifdef NFSD_DEBUG_VERBOSE
-printk("find_fh_dentry: retried validation successful\n");
+		printk("find_fh_dentry: Found%s %s/%s filehandle dirino = %lu, %lu\n",
+		       retry ? " Renamed" : "",
+		       dentry->d_parent->d_name.name,
+		       dentry->d_name.name,
+		       dentry->d_parent->d_inode->i_ino,
+		       dirino);
 #endif
-				}
-				goto out;
-			}
-		}
-	}
+		goto out;
+	} /* for inode->i_dentry */
 
 	/*
-	 * Before proceeding to a lookup, check whether we cached a
-	 * prior lookup. If so, try to validate that dentry ...
+	 * Before proceeding to a lookup, check for a rename
 	 */
-	if (!retry && (dentry = nfsd_cached_lookup(fh)) != NULL) {
+	if (!retry && (dirino = nfsd_cached_lookup(fh))) {
+		dprintk("find_fh_dentry: retry with %lu\n", dirino);
 		retry = 1;
 		goto recheck;
 	}
 
+	iput(inode);
+
+	dprintk("find_fh_dentry: dirino not found %lu\n", dirino);
+
+out_three:
+
 	/*
 	 * Stage 3: Look up the dentry based on the inode and parent inode
 	 * numbers. This should work for all Unix-like filesystems.
@@ -983,7 +1043,7 @@
 		struct inode * inode = dentry->d_inode;
 #ifdef NFSD_DEBUG_VERBOSE
 printk("find_fh_dentry: looked up %s/%s\n",
-dentry->d_parent->d_name.name, dentry->d_name.name);
+       dentry->d_parent->d_name.name, dentry->d_name.name);
 #endif
 		if (inode && inode->i_ino == u32_to_ino_t(fh->fh_ino)) {
 			nfsdstats.fh_lookup++;
@@ -991,7 +1051,7 @@
 		}
 #ifdef NFSD_PARANOIA
 printk("find_fh_dentry: %s/%s lookup mismatch!\n",
-dentry->d_parent->d_name.name, dentry->d_name.name);
+       dentry->d_parent->d_name.name, dentry->d_name.name);
 #endif
 		dput(dentry);
 	}
@@ -1005,29 +1065,27 @@
 		/*
 		 * ... then search for the inode in the parent directory.
 		 */
+		dget(parent);
 		dentry = lookup_by_inode(parent, u32_to_ino_t(fh->fh_ino));
 		dput(parent);
 		if (dentry)
 			goto out;
 	}
 
+out_five:
+
 	/*
-	 * Stage 5: Search the whole volume.
+	 * Stage 5: Search the whole volume, Yea Right.
 	 */
 #ifdef NFSD_PARANOIA
-printk("find_fh_dentry: %s, %u/%u not found -- need full search!\n",
-kdevname(u32_to_kdev_t(fh->fh_dev)), fh->fh_dirino, fh->fh_ino);
+printk("find_fh_dentry: %s/%u dir/%u not found!\n",
+       kdevname(u32_to_kdev_t(fh->fh_dev)), fh->fh_ino, fh->fh_dirino);
 #endif
 	dentry = NULL;
 	nfsdstats.fh_stale++;
 	
 out:
-	if (looked_up && dentry) {
-		add_to_lookup_cache(dentry, fh);
-	}
-
 	expire_all();
-
 	return dentry;
 }
 
@@ -1046,8 +1104,12 @@
 	struct inode	*inode;
 	u32		error = 0;
 
-	dprintk("nfsd: fh_verify(exp %x/%u cookie %p)\n",
-		fh->fh_xdev, fh->fh_xino, fh->fh_dcookie);
+	dprintk("nfsd: fh_verify(exp %s/%u file (%s/%u dir %u)\n",
+		kdevname(fh->fh_xdev),
+		fh->fh_xino,
+		kdevname(fh->fh_dev),
+		fh->fh_ino,
+		fh->fh_dirino);
 
 	if (fhp->fh_dverified)
 		goto check_type;
@@ -1056,10 +1118,13 @@
 	 */
 	error = nfserr_stale;
 	exp = exp_get(rqstp->rq_client,
-			u32_to_kdev_t(fh->fh_xdev),
-			u32_to_ino_t(fh->fh_xino));
-	if (!exp) /* export entry revoked */
+		      u32_to_kdev_t(fh->fh_xdev),
+		      u32_to_ino_t(fh->fh_xino));
+	if (!exp) {
+		/* export entry revoked */
+		nfsdstats.fh_stale++;
 		goto out;
+	}
 
 	/* Check if the request originated from a secure port. */
 	error = nfserr_perm;
@@ -1079,8 +1144,13 @@
 	 */
 	error = nfserr_noent;
 	dentry = find_fh_dentry(fh);
-	if (!dentry)
+	if (!dentry) {
+		goto out;
+	}
+	if (IS_ERR(dentry)) {
+		error = nfserrno(-PTR_ERR(dentry));
 		goto out;
+	}
 
 	/*
 	 * Note:  it's possible the returned dentry won't be the one in the
@@ -1102,6 +1172,35 @@
 check_type:
 	dentry = fhp->fh_dentry;
 	inode = dentry->d_inode;
+	error = nfserr_stale;
+	/* On a heavily loaded SMP machine, more than one identical
+	   requests may run at the same time on different processors.
+	   One thread may get here with unfinished fh after another
+	   thread just fetched the inode. It doesn't make any senses
+	   to check fh->fh_generation here since it has not been set
+	   yet. In that case, we shouldn't send back the stale
+	   filehandle to the client. We use fh->fh_dcookie to indicate
+	   if fh->fh_generation is set or not. If fh->fh_dcookie is
+	   not set, don't return stale filehandle. */
+	if (inode->i_generation != fh->fh_generation) {
+		if (fh->fh_dcookie) {
+			dprintk("fh_verify: Bad version %u %u %u: 0x%x, 0x%x\n",
+				inode->i_ino,
+				inode->i_generation,
+				fh->fh_generation,
+				type, access);
+			nfsdstats.fh_stale++;
+			goto out;
+		}
+		else {
+			/* We get here when inode is fetched by other
+			   threads. We just use what is in there. */
+			fh->fh_ino = ino_t_to_u32(inode->i_ino);
+			fh->fh_generation = inode->i_generation;
+			fh->fh_dcookie = (struct dentry *)0xfeebbaca;
+			nfsdstats.fh_concurrent++;
+		}
+	}
 	exp = fhp->fh_export;
 	if (type > 0 && (inode->i_mode & S_IFMT) != type) {
 		error = (type == S_IFDIR)? nfserr_notdir : nfserr_isdir;
@@ -1117,9 +1216,10 @@
 	 */
 	error = 0;
 	if (fh->fh_dev != fh->fh_xdev) {
-		printk("fh_verify: Security: export on other device"
-		       " (%d, %d).\n", fh->fh_dev, fh->fh_xdev);
+		printk("fh_verify: Security: export on other device (%s, %s).\n",
+		       kdevname(fh->fh_dev), kdevname(fh->fh_xdev));
 		error = nfserr_stale;
+		nfsdstats.fh_stale++;
 	} else if (exp->ex_dentry != dentry) {
 		struct dentry *tdentry = dentry;
 
@@ -1128,19 +1228,21 @@
 			if (exp->ex_dentry == tdentry)
 				break;
 			/* executable only by root and we can't be root */
-			if (current->fsuid &&
-			    !(tdentry->d_inode->i_uid  &&
-			        (tdentry->d_inode->i_mode & S_IXUSR)) &&
-			    !(tdentry->d_inode->i_gid &&
-			        (tdentry->d_inode->i_mode & S_IXGRP)) &&
-			    !(tdentry->d_inode->i_mode & S_IXOTH) && 
-			    (exp->ex_flags & NFSEXP_ROOTSQUASH)) {
+			if (current->fsuid
+			    && !(tdentry->d_inode->i_uid
+			         && (tdentry->d_inode->i_mode & S_IXUSR))
+			    && !(tdentry->d_inode->i_gid
+				 && (tdentry->d_inode->i_mode & S_IXGRP))
+			    && !(tdentry->d_inode->i_mode & S_IXOTH)
+			    && (exp->ex_flags & NFSEXP_ROOTSQUASH)) {
 				error = nfserr_stale;
+				nfsdstats.fh_stale++;
 dprintk("fh_verify: no root_squashed access.\n");
 			}
 		} while ((tdentry != tdentry->d_parent));
 		if (exp->ex_dentry != tdentry) {
 			error = nfserr_stale;
+			nfsdstats.fh_stale++;
 			printk("nfsd Security: %s/%s bad export.\n",
 			       dentry->d_parent->d_name.name,
 			       dentry->d_name.name);
@@ -1194,6 +1296,7 @@
 	if (inode) {
 		fhp->fh_handle.fh_ino = ino_t_to_u32(inode->i_ino);
 		fhp->fh_handle.fh_generation = inode->i_generation;
+		fhp->fh_handle.fh_dcookie = (struct dentry *)0xfeebbaca;
 	}
 	fhp->fh_handle.fh_dirino = ino_t_to_u32(parent->d_inode->i_ino);
 	fhp->fh_handle.fh_dev	 = kdev_t_to_u32(parent->d_inode->i_dev);
@@ -1226,7 +1329,8 @@
 		goto out_negative;
 	fhp->fh_handle.fh_ino = ino_t_to_u32(inode->i_ino);
 	fhp->fh_handle.fh_generation = inode->i_generation;
-out:
+	fhp->fh_handle.fh_dcookie = (struct dentry *)0xfeebbaca;
+ out:
 	return;
 
 out_bad:
@@ -1265,51 +1369,6 @@
 }
 
 /*
- * Verify that the FH dentry is still a valid dentry pointer.
- * After making some preliminary checks, we ask VFS to verify
- * that it is indeed a dentry.
- */
-static int nfsd_d_validate(struct dentry *dentry)
-{
-	unsigned long dent_addr = (unsigned long) dentry;
-	unsigned long min_addr = PAGE_OFFSET;
-	unsigned long max_addr = min_addr + (max_mapnr << PAGE_SHIFT);
-	unsigned long align_mask = 0x0F;
-	unsigned int len;
-	int valid = 0;
-
-	if (dent_addr < min_addr)
-		goto bad_addr;
-	if (dent_addr > max_addr - sizeof(struct dentry))
-		goto bad_addr;
-	if ((dent_addr & ~align_mask) != dent_addr)
-		goto bad_align;
-	if (!kern_addr_valid(dent_addr))
-		goto bad_addr;
-	/*
-	 * Looks safe enough to dereference ...
-	 */
-	len = dentry->d_name.len;
-	if (len > NFS_MAXNAMLEN)
-		goto out;
-	/*
-	 * Note: d_validate doesn't dereference the parent pointer ...
-	 * just combines it with the name hash to find the hash chain.
-	 */
-	valid = d_validate(dentry, dentry->d_parent, dentry->d_name.hash, len);
-
-out:
-	return valid;
-
-bad_addr:
-	printk(KERN_DEBUG "nfsd_d_validate: invalid address %lx\n", dent_addr);
-	goto out;
-bad_align:
-	printk(KERN_DEBUG "nfsd_d_validate: unaligned address %lx\n", dent_addr);
-	goto out;
-}
-
-/*
  * Flush any cached dentries for the specified device
  * or for all devices.
  *
@@ -1338,7 +1397,7 @@
 }
 
 /*
- * Free the dentry and path caches.
+ * Free the rename and path caches.
  */
 void nfsd_fh_free(void)
 {
@@ -1375,18 +1434,33 @@
 
 void nfsd_fh_init(void)
 {
-	/* Sanity check */ 
 	extern void __my_nfsfh_is_too_big(void); 
+
+	if (filetable)
+		return;
+
+	/* Sanity check */ 
 	if (sizeof(struct nfs_fhbase) > 32) 
 		__my_nfsfh_is_too_big(); 
 
+	filetable = kmalloc(sizeof(struct fh_entry) * NFSD_MAXFH,
+			    GFP_KERNEL);
+	dirstable = kmalloc(sizeof(struct fh_entry) * NFSD_MAXFH,
+			    GFP_KERNEL);
+
+	if (filetable == NULL || dirstable == NULL) {
+		printk(KERN_WARNING "nfsd_fh_init : Could not allocate fhcache\n");
+		nfsd_nservers = 0;
+		return;
+	}
+
 	memset(filetable, 0, NFSD_MAXFH*sizeof(struct fh_entry));
 	memset(dirstable, 0, NFSD_MAXFH*sizeof(struct fh_entry));
 	INIT_LIST_HEAD(&path_inuse);
 	INIT_LIST_HEAD(&fixup_head);
 
 	printk(KERN_DEBUG 
-		"nfsd_init: initialized fhcache, entries=%lu\n", NFSD_MAXFH);
+		"nfsd_fh_init : initialized fhcache, entries=%lu\n", NFSD_MAXFH);
 	/*
 	 * Display a warning if the ino_t is larger than 32 bits.
 	 */
@@ -1394,4 +1468,16 @@
 		printk(KERN_INFO 
 			"NFSD: ino_t is %d bytes, using lower 4 bytes\n",
 			sizeof(ino_t));
+}
+
+void
+nfsd_fh_shutdown(void)
+{
+	if (!filetable)
+		return;
+	printk(KERN_DEBUG 
+		"nfsd_fh_shutdown : freeing %d fhcache entries.\n", NFSD_MAXFH);
+	kfree(filetable);
+	kfree(dirstable);
+	filetable = dirstable = NULL;
 }
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/fs/nfsd/nfsproc.c linux.14p1/fs/nfsd/nfsproc.c
--- linux.vanilla/fs/nfsd/nfsproc.c	Wed Oct 20 01:12:49 1999
+++ linux.14p1/fs/nfsd/nfsproc.c	Fri Oct 22 21:29:04 1999
@@ -270,7 +270,7 @@
 		rdev = (dev_t) size;
 		if (type != S_IFBLK && type != S_IFCHR) {
 			rdev = 0;
-		} else if (type == S_IFCHR && size == ~(u32) 0) {
+		} else if (type == S_IFCHR && !(attr->ia_valid & ATTR_SIZE)) {
 			/* If you think you've seen the worst, grok this. */
 			attr->ia_mode = S_IFIFO | mode;
 			type = S_IFIFO;
@@ -288,6 +288,10 @@
 		if (inode && (type != (inode->i_mode & S_IFMT) || 
 		    (is_borc && inode->i_rdev != rdev)))
 			goto out_unlock;
+
+		/* invalidate size because only (type == S_IFREG) has
+		   size. */
+		attr->ia_valid &= ~ATTR_SIZE;
 	}
 	
 	nfserr = 0;
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/fs/nfsd/nfssvc.c linux.14p1/fs/nfsd/nfssvc.c
--- linux.vanilla/fs/nfsd/nfssvc.c	Sat Mar 20 20:28:14 1999
+++ linux.14p1/fs/nfsd/nfssvc.c	Fri Oct 22 21:29:05 1999
@@ -5,7 +5,7 @@
  *
  * Authors:	Olaf Kirch (okir@monad.swb.de)
  *
- * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
+ * Copyright (C) 1995-1999 Olaf Kirch <okir@monad.swb.de>
  */
 
 #define __NO_VERSION__
@@ -64,6 +64,11 @@
 	nfsd_nservers = nrservs;
 
 	error = -ENOMEM;
+	nfsd_fh_init();		/* NFS dentry cache */
+	if (nfsd_nservers == 0)
+		goto out;
+	  
+	error = -ENOMEM;
 	nfsd_racache_init();     /* Readahead param cache */
 	if (nfsd_nservers == 0)
 		goto out;
@@ -119,7 +124,9 @@
 		nfssvc_boot = xtime;		/* record boot time */
 		first = 1;
 	}
+#if 0
 	lockd_up();				/* start lockd */
+#endif
 
 	/*
 	 * The main request loop
@@ -177,12 +184,16 @@
 		printk(KERN_WARNING "nfsd: terminating on signal %d\n", signo);
 	}
 
+#if 0
 	/* Release lockd */
 	lockd_down();
+#endif
 	if (!--nfsd_active) {
 		printk("nfsd: last server exiting\n");
 		/* revoke all exports */
 		nfsd_export_shutdown();
+		/* release fhcache */
+		nfsd_fh_shutdown ();
 		/* release read-ahead cache */
 	        nfsd_racache_shutdown();
 	}
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/fs/nfsd/stats.c linux.14p1/fs/nfsd/stats.c
--- linux.vanilla/fs/nfsd/stats.c	Thu Jan  7 17:28:47 1999
+++ linux.14p1/fs/nfsd/stats.c	Fri Oct 22 21:29:05 1999
@@ -32,7 +32,7 @@
 {
 	int	len;
 
-	len = sprintf(buffer, "rc %d %d %d  %d %d %d %d %d\n",
+	len = sprintf(buffer, "rc %d %d %d  %d %d %d %d %d %d\n",
 			nfsdstats.rchits,
 			nfsdstats.rcmisses,
 			nfsdstats.rcnocache,
@@ -40,7 +40,8 @@
 			nfsdstats.fh_valid,
 			nfsdstats.fh_fixup,
 			nfsdstats.fh_lookup,
-			nfsdstats.fh_stale);
+			nfsdstats.fh_stale,
+			nfsdstats.fh_concurrent);
 
 	/* Assume we haven't hit EOF yet. Will be set by svc_proc_read. */
 	*eof = 0;
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/fs/nfsd/vfs.c linux.14p1/fs/nfsd/vfs.c
--- linux.vanilla/fs/nfsd/vfs.c	Wed Oct 20 01:12:49 1999
+++ linux.14p1/fs/nfsd/vfs.c	Fri Oct 22 21:29:05 1999
@@ -21,7 +21,6 @@
 #include <linux/locks.h>
 #include <linux/fs.h>
 #include <linux/major.h>
-#include <linux/ext2_fs.h>
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
 #include <linux/fcntl.h>
@@ -48,9 +47,15 @@
 
 /* Hack until we have a macro check for mandatory locks. */
 #ifndef IS_ISMNDLK
-#define IS_ISMNDLK(i)	(((i)->i_mode & (S_ISGID|S_IXGRP)) == S_ISGID)
+#define IS_ISMNDLK(i)	(((i)->i_mode & (S_ISGID|S_IXGRP|S_IFMT)) \
+			 == (S_ISGID|S_IFREG))
 #endif
 
+/* Time difference margin in seconds for comparison. It is a
+   dynamically-tunable parameter via /proc/fs/nfs/time-diff-margin.
+ */
+extern long nfsd_time_diff_margin;
+
 /* Check for dir entries '.' and '..' */
 #define isdotent(n, l)	(l < 3 && n[0] == '.' && (l == 1 || n[1] == '.'))
 
@@ -236,8 +241,30 @@
 	inode = dentry->d_inode;
 
 	err = inode_change_ok(inode, iap);
-	if (err)
+	if (err) {
+		/* It is very tricky. When you are not the file owner,
+		   but have the write permission, you should be allowed
+		   to set atime and mtime to the current time on the
+		   server. However, the NFS V2 protocol doesn't support
+		   it. It has been fixed in V3. Here we do this: if the
+		   current server time and atime/mtime are close enough,
+		   we use the current server time. */
+#define CURRENT_TIME_SET	(ATTR_ATIME_SET | ATTR_MTIME_SET)
+		if (iap->ia_mtime == iap->ia_atime
+		    && ((iap->ia_valid & (CURRENT_TIME_SET))
+			== CURRENT_TIME_SET)) {
+			time_t now = CURRENT_TIME;
+			time_t delta = iap->ia_atime - now;
+			if (delta < 0) delta = -delta;
+			if (delta <= nfsd_time_diff_margin) {
+				iap->ia_valid &= ~CURRENT_TIME_SET;
+				goto current_time_ok;
+			}
+		}
 		goto out_nfserr;
+	}
+
+current_time_ok:
 
 	/* The size case is special... */
 	if (iap->ia_valid & ATTR_SIZE) {
@@ -248,15 +275,19 @@
 			if (err)
 				goto out;
 		}
+		DQUOT_INIT(inode);
 		err = get_write_access(inode);
-		if (err)
+		if (err) {
+			DQUOT_DROP(inode);
 			goto out_nfserr;
+		}
 		/* N.B. Should we update the inode cache here? */
 		inode->i_size = iap->ia_size;
 		if (inode->i_op && inode->i_op->truncate)
 			inode->i_op->truncate(inode);
 		mark_inode_dirty(inode);
 		put_write_access(inode);
+		DQUOT_DROP(inode);
 		iap->ia_valid &= ~ATTR_SIZE;
 		iap->ia_valid |= ATTR_MTIME;
 		iap->ia_mtime = CURRENT_TIME;
@@ -554,7 +585,7 @@
 	/* clear setuid/setgid flag after write */
 	if (err >= 0 && (inode->i_mode & (S_ISUID | S_ISGID))) {
 		struct iattr	ia;
-		kernel_cap_t	saved_cap;
+		kernel_cap_t	saved_cap = 0;
 
 		ia.ia_valid = ATTR_MODE;
 		ia.ia_mode  = inode->i_mode & ~(S_ISUID | S_ISGID);
@@ -658,10 +689,6 @@
 		if (IS_ERR(dchild))
 			goto out_nfserr;
 		fh_compose(resfhp, fhp->fh_export, dchild);
-		/* Lock the parent and check for errors ... */
-		err = fh_lock_parent(fhp, dchild);
-		if (err)
-			goto out;
 	} else {
 		dchild = resfhp->fh_dentry;
 		if (!fhp->fh_locked)
@@ -670,6 +697,15 @@
 				dentry->d_parent->d_name.name,
 				dentry->d_name.name);
 	}
+	err = nfserr_exist;
+	if (dchild->d_inode)
+		goto out;
+	if (!fhp->fh_locked) {
+		/* Lock the parent and check for errors ... */
+		err = fh_lock_parent(fhp, dchild);
+		if (err)
+			goto out;
+	}
 	/*
 	 * Make sure the child dentry is still negative ...
 	 */
@@ -695,8 +731,7 @@
 	case S_IFCHR:
 	case S_IFBLK:
 		/* The client is _NOT_ required to do security enforcement */
-		if(!capable(CAP_SYS_ADMIN))
-		{
+		if(!capable(CAP_SYS_ADMIN)) {
 			err = -EPERM;
 			goto out;
 		}
@@ -759,7 +794,7 @@
 	struct inode	*inode;
 	struct iattr	newattrs;
 	int		err;
-	kernel_cap_t	saved_cap;
+	kernel_cap_t	saved_cap = 0;
 
 	err = fh_verify(rqstp, fhp, S_IFREG, MAY_WRITE | MAY_TRUNC);
 	if (err)
@@ -899,6 +934,7 @@
 	/* Compose the fh so the dentry will be freed ... */
 out_compose:
 	fh_compose(resfhp, fhp->fh_export, dnew);
+
 out:
 	return err;
 
@@ -1091,6 +1127,15 @@
 	DQUOT_DROP(tdir);
 
 	nfsd_double_up(&tdir->i_sem, &fdir->i_sem);
+
+	if (!err && odentry->d_inode) {
+		add_to_rename_cache(tdir->i_ino,
+				    odentry->d_inode->i_dev,
+				    fdir->i_ino,
+				    odentry->d_inode->i_ino);
+	} else {
+		printk(": no inode in rename or err: %d.\n", err);
+	}
 	dput(ndentry);
 
 out_dput_old:
@@ -1132,7 +1177,6 @@
 	err = PTR_ERR(rdentry);
 	if (IS_ERR(rdentry))
 		goto out_nfserr;
-
 	if (!rdentry->d_inode) {
 		dput(rdentry);
 		err = nfserr_noent;
@@ -1154,7 +1198,7 @@
 		fh_unlock(fhp);
 
 		dput(rdentry);
-
+		expire_by_dentry(rdentry);
 	} else {
 		/* It's RMDIR */
 		/* See comments in fs/namei.c:do_rmdir */
@@ -1183,6 +1227,7 @@
 		goto out_nfserr;
 	if (EX_ISSYNC(fhp->fh_export))
 		write_inode_now(dirp);
+
 out:
 	return err;
 
@@ -1314,7 +1359,7 @@
 {
 	struct inode	*inode = dentry->d_inode;
 	int		err;
-	kernel_cap_t	saved_cap;
+	kernel_cap_t	saved_cap = 0;
 
 	if (acc == MAY_NOP)
 		return 0;
@@ -1334,7 +1379,7 @@
 		inode->i_uid, inode->i_gid, current->fsuid, current->fsgid);
 #endif
 #ifndef CONFIG_NFSD_SUN
-        if (dentry->d_mounts != dentry) {
+	if (dentry->d_mounts != dentry) {
 		return nfserr_perm;
 	}
 #endif
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/include/asm-alpha/delay.h linux.14p1/include/asm-alpha/delay.h
--- linux.vanilla/include/asm-alpha/delay.h	Tue Dec 29 21:56:15 1998
+++ linux.14p1/include/asm-alpha/delay.h	Fri Oct 22 21:29:12 1999
@@ -9,12 +9,18 @@
  * Delay routines, using a pre-computed "loops_per_second" value.
  */
 
+/* We can make the delay loop inline, but we have to be very careful
+ * WRT scheduling for EV6 machines, to keep it consistent for all locations
+ * of invocations. This is a reasonable compromise.
+ */
+
 extern __inline__ void
 __delay(unsigned long loops)
 {
-	__asm__ __volatile__(".align 3\n"
-		"1:\tsubq %0,1,%0\n\t"
-		"bge %0,1b": "=r" (loops) : "0" (loops));
+	__asm__ __volatile__(".align 4\n"
+		     "1:\tsubq %0,1,%0\n\t"
+		     "bge %0,1b\n\t"
+		     "nop": "=r" (loops) : "0" (loops));
 }
 
 /*
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/include/asm-alpha/io.h linux.14p1/include/asm-alpha/io.h
--- linux.vanilla/include/asm-alpha/io.h	Sat Aug 14 02:27:37 1999
+++ linux.14p1/include/asm-alpha/io.h	Fri Oct 22 21:29:12 1999
@@ -261,6 +261,8 @@
 {
 }
 
+#define ioremap_nocache(offset, size) ioremap((offset),(size))
+
 #ifndef readb
 # define readb(a)	_readb((unsigned long)(a))
 #endif
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/include/asm-i386/fixmap.h linux.14p1/include/asm-i386/fixmap.h
--- linux.vanilla/include/asm-i386/fixmap.h	Sun Mar 28 19:03:26 1999
+++ linux.14p1/include/asm-i386/fixmap.h	Fri Oct 22 23:25:13 1999
@@ -45,7 +45,10 @@
 	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,	/* IF YOU CHANGE THIS, PLEASE ALSO CHANGE */
+	FIX_IO_APIC_BASE_1,     /* MAX_IO_APICS in arch/i386/irq.h        */
+	FIX_IO_APIC_BASE_2,
+	FIX_IO_APIC_BASE_3,
 #endif
 #ifdef CONFIG_X86_VISWS_APIC
 	FIX_CO_CPU,	/* Cobalt timer */
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/include/linux/fs.h linux.14p1/include/linux/fs.h
--- linux.vanilla/include/linux/fs.h	Wed Oct 20 01:12:50 1999
+++ linux.14p1/include/linux/fs.h	Fri Oct 22 23:25:13 1999
@@ -837,6 +837,7 @@
 extern struct inode * igrab(struct inode *inode);
 extern ino_t iunique(struct super_block *, ino_t);
 extern struct inode * iget(struct super_block *, unsigned long);
+extern struct inode * iget_in_use (struct super_block *, unsigned long);
 extern void clear_inode(struct inode *);
 extern struct inode * get_empty_inode(void);
 
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/include/linux/genhd.h linux.14p1/include/linux/genhd.h
--- linux.vanilla/include/linux/genhd.h	Sat Aug 14 02:27:39 1999
+++ linux.14p1/include/linux/genhd.h	Fri Oct 22 23:25:10 1999
@@ -42,7 +42,7 @@
 #endif
 
 #define DM6_PARTITION		0x54	/* has DDO: use xlated geom & offset */
-#define EZD_PARTITION		0x55	/* EZ-DRIVE:  same as DM6 (we think) */
+#define EZD_PARTITION		0x55	/* EZ-DRIVE: remap sector 1 to 0 */
 #define DM6_AUX1PARTITION	0x51	/* no DDO:  use xlated geom */
 #define DM6_AUX3PARTITION	0x53	/* no DDO:  use xlated geom */
 	
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/include/linux/lockd/syscall.h linux.14p1/include/linux/lockd/syscall.h
--- linux.vanilla/include/linux/lockd/syscall.h	Thu Jan  1 01:00:00 1970
+++ linux.14p1/include/linux/lockd/syscall.h	Fri Oct 22 23:27:44 1999
@@ -0,0 +1,26 @@
+/*
+ * include/linux/lockd/syscall.h
+ *
+ * This file holds all declarations for the knfsd/lockd syscall
+ * interface.
+ *
+ */
+
+#ifndef LOCKD_SYSCALL_H
+#define LOCKD_SYSCALL_H
+
+#include <linux/nfsd/syscall.h>
+
+#define LOCKDCTL_SVC NFSCTL_LOCKD
+
+#ifdef __KERNEL__
+/*
+ * Kernel syscall implementation.
+ */
+#if defined(CONFIG_LOCKD) || defined(CONFIG_LOCKD_MODULE)
+extern int	lockdctl(int, void *, void *);
+#endif
+
+#endif /* __KERNEL__ */
+
+#endif /* LOCKD_SYSCALL_H */
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/include/linux/netdevice.h linux.14p1/include/linux/netdevice.h
--- linux.vanilla/include/linux/netdevice.h	Sat Aug 28 20:00:59 1999
+++ linux.14p1/include/linux/netdevice.h	Fri Oct 22 23:26:18 1999
@@ -266,6 +266,9 @@
 	struct Qdisc		*qdisc_list;
 	unsigned long		tx_queue_len;	/* Max frames per queue allowed */
 
+	/* Bridge stuff */
+	int			bridge_port_id;		
+	
 	/* Pointers to interface service routines.	*/
 	int			(*open)(struct device *dev);
 	int			(*stop)(struct device *dev);
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/include/linux/nfsd/nfsfh.h linux.14p1/include/linux/nfsd/nfsfh.h
--- linux.vanilla/include/linux/nfsd/nfsfh.h	Wed Oct 20 01:12:51 1999
+++ linux.14p1/include/linux/nfsd/nfsfh.h	Fri Oct 22 23:27:44 1999
@@ -107,6 +107,7 @@
 void	fh_put(struct svc_fh *);
 void	nfsd_fh_flush(kdev_t);
 void	nfsd_fh_init(void);
+void	nfsd_fh_shutdown(void);
 void	nfsd_fh_free(void);
 
 void	expire_all(void);
@@ -181,6 +182,11 @@
 		up(&inode->i_sem);
 	}
 }
+
+/*
+ * This is a long term cache to help find renamed files.
+ */
+void add_to_rename_cache(ino_t new_dirino, kdev_t dev, ino_t dirino, ino_t ino);
 
 #endif /* __KERNEL__ */
 
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/include/linux/nfsd/stats.h linux.14p1/include/linux/nfsd/stats.h
--- linux.vanilla/include/linux/nfsd/stats.h	Wed Nov 26 21:08:38 1997
+++ linux.14p1/include/linux/nfsd/stats.h	Fri Oct 22 21:31:59 1999
@@ -18,6 +18,7 @@
 	unsigned int	fh_fixup;	/* dentry fixup validated */
 	unsigned int	fh_lookup;	/* new lookup required */
 	unsigned int	fh_stale;	/* FH stale error */
+	unsigned int    fh_concurrent;	/* concurrent request */
 };
 
 #ifdef __KERNEL__
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/include/linux/nfsd/syscall.h linux.14p1/include/linux/nfsd/syscall.h
--- linux.vanilla/include/linux/nfsd/syscall.h	Mon Dec 28 22:10:01 1998
+++ linux.14p1/include/linux/nfsd/syscall.h	Fri Oct 22 23:27:44 1999
@@ -35,6 +35,9 @@
 #define NFSCTL_GETFH		6	/* get an fh by ino (used by mountd) */
 #define NFSCTL_GETFD		7	/* get an fh by path (used by mountd) */
 
+/* Above this is for lockd. */
+#define NFSCTL_LOCKD		0x10000
+
 /* SVC */
 struct nfsctl_svc {
 	unsigned short		svc_port;
@@ -121,11 +124,7 @@
 /*
  * Kernel syscall implementation.
  */
-#if defined(CONFIG_NFSD) || defined(CONFIG_NFSD_MODULE)
 extern asmlinkage int	sys_nfsservctl(int, void *, void *);
-#else
-#define sys_nfsservctl		sys_ni_syscall
-#endif
 extern int		exp_addclient(struct nfsctl_client *ncp);
 extern int		exp_delclient(struct nfsctl_client *ncp);
 extern int		exp_export(struct nfsctl_export *nxp);
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/include/linux/pagemap.h linux.14p1/include/linux/pagemap.h
--- linux.vanilla/include/linux/pagemap.h	Wed Oct 20 01:12:51 1999
+++ linux.14p1/include/linux/pagemap.h	Fri Oct 22 23:25:15 1999
@@ -38,11 +38,15 @@
  */
 #define page_cache_entry(x)	(mem_map + MAP_NR(x))
 
-#define PAGE_HASH_BITS 12
-#define PAGE_HASH_SIZE (1 << PAGE_HASH_BITS)
+#define PAGE_HASH_BITS page_hash_bits
+#define PAGE_HASH_MASK page_hash_mask
 
 extern unsigned long page_cache_size; /* # of pages currently in the hash table */
-extern struct page * page_hash_table[PAGE_HASH_SIZE];
+extern unsigned int page_hash_bits;
+extern unsigned int page_hash_mask;
+extern struct page **page_hash_table;
+
+extern void page_cache_init(unsigned long);
 
 /*
  * We use a power-of-two hash table to avoid a modulus,
@@ -53,12 +57,10 @@
 static inline unsigned long _page_hashfn(struct inode * inode, unsigned long offset)
 {
 #define i (((unsigned long) inode)/(sizeof(struct inode) & ~ (sizeof(struct inode) - 1)))
-#define o (offset >> PAGE_SHIFT)
-#define s(x) ((x)+((x)>>PAGE_HASH_BITS))
-	return s(i+o) & (PAGE_HASH_SIZE-1);
+#define o ((offset >> PAGE_SHIFT) + (offset & ~PAGE_MASK))
+	return ((i+o) & PAGE_HASH_MASK);
 #undef i
 #undef o
-#undef s
 }
 
 #define page_hash(inode,offset) (page_hash_table+_page_hashfn(inode,offset))
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/include/linux/pci.h linux.14p1/include/linux/pci.h
--- linux.vanilla/include/linux/pci.h	Wed Oct 20 01:12:51 1999
+++ linux.14p1/include/linux/pci.h	Fri Oct 22 23:25:10 1999
@@ -1067,6 +1067,7 @@
 #define PCI_DEVICE_ID_INTEL_82441	0x1237
 #define PCI_DEVICE_ID_INTEL_82380FB	0x124b
 #define PCI_DEVICE_ID_INTEL_82439	0x1250
+#define PCI_DEVICE_ID_INTEL_MEGARAID	0x1960
 #define PCI_DEVICE_ID_INTEL_82371SB_0	0x7000
 #define PCI_DEVICE_ID_INTEL_82371SB_1	0x7010
 #define PCI_DEVICE_ID_INTEL_82371SB_2	0x7020
@@ -1076,17 +1077,19 @@
 #define PCI_DEVICE_ID_INTEL_82371AB	0x7111
 #define PCI_DEVICE_ID_INTEL_82371AB_2	0x7112
 #define PCI_DEVICE_ID_INTEL_82371AB_3	0x7113
-#define PCI_VENDOR_ID_COMPUTONE		0x8e0e
-#define PCI_DEVICE_ID_COMPUTONE_IP2EX	0x0291
-
 #define PCI_DEVICE_ID_INTEL_82443LX_0	0x7180
 #define PCI_DEVICE_ID_INTEL_82443LX_1	0x7181
 #define PCI_DEVICE_ID_INTEL_82443BX_0	0x7190
 #define PCI_DEVICE_ID_INTEL_82443BX_1	0x7191
 #define PCI_DEVICE_ID_INTEL_82443BX_2	0x7192
 #define PCI_DEVICE_ID_INTEL_P6		0x84c4
-#define PCI_DEVICE_ID_INTEL_82450GX	0x84c5
+#define PCI_DEVICE_ID_INTEL_82450GX	0x84c4
+#define PCI_DEVICE_ID_INTEL_82453GX	0x84c5
 #define PCI_DEVICE_ID_INTEL_82451NX	0x84ca
+#define PCI_DEVICE_ID_INTEL_82454NX	0x84cb
+
+#define PCI_VENDOR_ID_COMPUTONE		0x8e0e
+#define PCI_DEVICE_ID_COMPUTONE_IP2EX	0x0291
 
 #define PCI_VENDOR_ID_KTI		0x8e2e
 #define PCI_DEVICE_ID_KTI_ET32P2	0x3000
@@ -1317,6 +1320,9 @@
 
 extern inline struct pci_dev *pci_find_slot(unsigned int bus, unsigned int devfn)
 { return NULL; }
+
+extern inline void pci_set_master(struct pci_dev *dev)
+{ return; }
 
 #endif /* !CONFIG_PCI */
 
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/include/linux/proc_fs.h linux.14p1/include/linux/proc_fs.h
--- linux.vanilla/include/linux/proc_fs.h	Wed Oct 20 01:12:51 1999
+++ linux.14p1/include/linux/proc_fs.h	Fri Oct 22 23:25:15 1999
@@ -466,6 +466,7 @@
 extern inline void proc_tty_register_driver(struct tty_driver *driver) {};
 extern inline void proc_tty_unregister_driver(struct tty_driver *driver) {};
 
+extern struct proc_dir_entry proc_root;
 
-#endif
+#endif /* CONFIG_PROC_FS */
 #endif /* _LINUX_PROC_FS_H */
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/include/linux/sunrpc/svc.h linux.14p1/include/linux/sunrpc/svc.h
--- linux.vanilla/include/linux/sunrpc/svc.h	Sun Mar 28 19:03:50 1999
+++ linux.14p1/include/linux/sunrpc/svc.h	Fri Oct 22 23:27:44 1999
@@ -13,6 +13,7 @@
 #include <linux/sunrpc/types.h>
 #include <linux/sunrpc/xdr.h>
 #include <linux/sunrpc/svcauth.h>
+#include <asm/atomic.h>
 
 /*
  * RPC service.
@@ -29,7 +30,7 @@
 	struct svc_sock *	sv_sockets;	/* pending sockets */
 	struct svc_program *	sv_program;	/* RPC program */
 	struct svc_stat *	sv_stats;	/* RPC statistics */
-	unsigned int		sv_nrthreads;	/* # of server threads */
+	atomic_t		sv_nrthreads;	/* # of server threads */
 	unsigned int		sv_bufsz;	/* datagram buffer size */
 	unsigned int		sv_xdrsize;	/* XDR buffer size */
 
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/include/linux/sunrpc/svcsock.h linux.14p1/include/linux/sunrpc/svcsock.h
--- linux.vanilla/include/linux/sunrpc/svcsock.h	Sun Mar 28 19:03:53 1999
+++ linux.14p1/include/linux/sunrpc/svcsock.h	Fri Oct 22 23:27:48 1999
@@ -10,6 +10,7 @@
 #define SUNRPC_SVCSOCK_H
 
 #include <linux/sunrpc/svc.h>
+#include <asm/atomic.h>
 
 /*
  * RPC server socket.
@@ -23,7 +24,7 @@
 	struct sock *		sk_sk;		/* INET layer */
 
 	struct svc_serv *	sk_server;	/* service for this socket */
-	unsigned char		sk_inuse;	/* use count */
+	atomic_t		sk_inuse;	/* use count */
 	unsigned char		sk_busy;	/* enqueued/receiving */
 	unsigned char		sk_conn;	/* conn pending */
 	unsigned char		sk_close;	/* dead or dying */
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/include/net/br.h linux.14p1/include/net/br.h
--- linux.vanilla/include/net/br.h	Sat Aug 14 02:27:40 1999
+++ linux.14p1/include/net/br.h	Fri Oct 22 23:28:35 1999
@@ -19,7 +19,16 @@
 #define Forwarding	3			  /* (4 4 4)	 */
 #define Blocking	4			  /* (4.4.1)	 */
 
-#define No_of_ports 8
+
+/* MAG Yich! Easiest way of giving a configurable number of ports
+ * If you want more than 32, change BR_MAX_PORTS and recompile brcfg!
+ */
+#define BR_MAX_PORTS (32)
+#if CONFIG_BRIDGE_NUM_PORTS > BR_MAX_PORTS
+#undef CONFIG_BRIDGE_NUM_PORTS
+#define CONFIG_BRIDGE_NUM_PORTS BR_MAX_PORTS
+#endif
+#define No_of_ports CONFIG_BRIDGE_NUM_PORTS
 /* arbitrary choice, to allow the code below to compile */
 
 #define All_ports (No_of_ports + 1)
@@ -147,6 +156,7 @@
 	unsigned int     top_change;		  /* (4.5.3.12)	 */
 	unsigned short   topology_change_time;	  /* (4.5.3.13)	 */
 	unsigned short   hold_time;		  /* (4.5.3.14)	 */
+	unsigned int	 instance;
 } Bridge_data;
 
 /** Port Parameters (4.5.5) **/
@@ -160,7 +170,10 @@
 	unsigned short   designated_port;	  /* (4.5.5.7)	 */
 	unsigned int     top_change_ack;	  /* (4.5.5.8)	 */
 	unsigned int     config_pending;	  /* (4.5.5.9)	 */
-	struct device *dev;	
+        bridge_id_t      ifmac; 
+        unsigned int     admin_state;
+	char             ifname[IFNAMSIZ]; /* Make life easier for brcfg */
+        struct device *dev;	
 	struct fdb *fdb;	/* head of per port fdb chain */
 } Port_data;
 
@@ -245,13 +258,14 @@
 struct br_stat {
 	unsigned int flags;
 	Bridge_data bridge_data;
-	Port_data port_data[No_of_ports];
 	unsigned int policy;
 	unsigned int exempt_protocols;
 	unsigned short protocols[BR_MAX_PROTOCOLS];
 	unsigned short prot_id[BR_MAX_PROT_STATS];	/* Protocol encountered */
 	unsigned int prot_counter[BR_MAX_PROT_STATS];	/* How many packets ? */
 	br_stats_counter packet_cnts;
+	unsigned int	num_ports;
+	Port_data port_data[BR_MAX_PORTS + 1];
 };
 
 /* defined flags for br_stat.flags */
@@ -274,7 +288,7 @@
 #define	BRCMD_SET_BRIDGE_PRIORITY	5	/* arg1 = priority */
 #define	BRCMD_SET_PORT_PRIORITY	6	/* arg1 = port, arg2 = priority */
 #define	BRCMD_SET_PATH_COST	7	/* arg1 = port, arg2 = cost */
-#define	BRCMD_DISPLAY_FDB	8	/* arg1 = port */
+#define	BRCMD_DISPLAY_FDB	8
 #define	BRCMD_ENABLE_DEBUG	9
 #define	BRCMD_DISABLE_DEBUG	10
 #define BRCMD_SET_POLICY	11	/* arg1 = default policy (1==bridge all) */
@@ -283,14 +297,19 @@
 #define BRCMD_DISABLE_PROT_STATS 14
 #define BRCMD_ZERO_PROT_STATS	15
 #define BRCMD_TOGGLE_STP	16
+#define BRCMD_IF_ENABLE		17	/* arg1 = if_index */
+#define BRCMD_IF_DISABLE	18	/* arg1 = if_index */
+#define BRCMD_SET_IF_PRIORITY	19	/* arg1 = if_index, arg2 = priority */
+#define	BRCMD_SET_IF_PATH_COST	20	/* arg1 = if_index, arg2 = cost */
 
 /* prototypes of exported bridging functions... */
 
+#ifdef __KERNEL__
 void br_init(void);
 int br_receive_frame(struct sk_buff *skb);	/* 3.5 */
 int br_tx_frame(struct sk_buff *skb);
+int brg_init(void);
 int br_ioctl(unsigned int cmd, void *arg);
-int br_protocol_ok(unsigned short protocol);
 void requeue_fdb(struct fdb *node, int new_port);
 
 struct fdb *br_avl_find_addr(unsigned char addr[6]);
@@ -298,8 +317,15 @@
 void sprintf_avl (char **pbuffer, struct fdb * tree, off_t *pos,int* len, off_t offset, int length);
 int br_tree_get_info(char *buffer, char **start, off_t offset, int length, int dummy);
 void br_avl_delete_by_port(int port);
+int br_call_bridge(struct sk_buff *skb, unsigned short type);
+void br_spacedevice_register(void);
+
 /* externs */
 
 extern struct br_stat br_stats;
 extern Port_data port_info[];
 
+#endif
+
+
+ 
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/include/net/tcp.h linux.14p1/include/net/tcp.h
--- linux.vanilla/include/net/tcp.h	Sat Aug 28 20:00:59 1999
+++ linux.14p1/include/net/tcp.h	Fri Oct 22 23:28:26 1999
@@ -24,22 +24,18 @@
 #include <net/checksum.h>
 
 /* This is for all connections with a full identity, no wildcards.
- * New scheme, half the table is for TIME_WAIT, the other half is
- * for the rest.  I'll experiment with dynamic table growth later.
+ * Half of the table is for TIME_WAIT, the other half is for the
+ * rest.
+ *
+ * This needs to be shared by v4 and v6 because the lookup and hashing
+ * code needs to work with different AF's yet the port space is
+ * shared.
  */
-#define TCP_HTABLE_SIZE		512
+extern unsigned int tcp_ehash_size;
+extern struct sock **tcp_ehash;
 
 /* This is for listening sockets, thus all sockets which possess wildcards. */
 #define TCP_LHTABLE_SIZE	32	/* Yes, really, this is all you need. */
-
-/* This is for all sockets, to keep track of the local port allocations. */
-#define TCP_BHTABLE_SIZE	512
-
-/* tcp_ipv4.c: These need to be shared by v4 and v6 because the lookup
- *             and hashing code needs to work with different AF's yet
- *             the port space is shared.
- */
-extern struct sock *tcp_established_hash[TCP_HTABLE_SIZE];
 extern struct sock *tcp_listening_hash[TCP_LHTABLE_SIZE];
 
 /* There are a few simple rules, which allow for local port reuse by
@@ -81,7 +77,8 @@
 	struct tcp_bind_bucket	**pprev;
 };
 
-extern struct tcp_bind_bucket *tcp_bound_hash[TCP_BHTABLE_SIZE];
+extern unsigned int tcp_bhash_size;
+extern struct tcp_bind_bucket **tcp_bhash;
 extern kmem_cache_t *tcp_bucket_cachep;
 extern struct tcp_bind_bucket *tcp_bucket_create(unsigned short snum);
 extern void tcp_bucket_unlock(struct sock *sk);
@@ -109,7 +106,7 @@
 /* These are AF independent. */
 static __inline__ int tcp_bhashfn(__u16 lport)
 {
-	return (lport & (TCP_BHTABLE_SIZE - 1));
+	return (lport & (tcp_bhash_size - 1));
 }
 
 /* This is a TIME_WAIT bucket.  It works around the memory consumption
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/init/main.c linux.14p1/init/main.c
--- linux.vanilla/init/main.c	Wed Oct 20 01:12:51 1999
+++ linux.14p1/init/main.c	Fri Oct 22 23:31:19 1999
@@ -1211,6 +1211,7 @@
 	dcache_init();
 	vma_init();
 	buffer_init(memory_end-memory_start);
+ 	page_cache_init(memory_end-memory_start);
 	signals_init();
 	inode_init();
 	file_table_init();
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/ipc/sem.c linux.14p1/ipc/sem.c
--- linux.vanilla/ipc/sem.c	Sun Jan 10 03:16:44 1999
+++ linux.14p1/ipc/sem.c	Fri Oct 22 22:15:21 1999
@@ -694,7 +694,7 @@
                 interruptible_sleep_on(&queue.sleeper);
 
                 /*
-                 * If queue.status == 1 we where woken up and
+                 * If queue.status == 1 we were woken up and
                  * have to retry else we simply return.
                  * If an interrupt occurred we have to clean up the
                  * queue
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/kernel/ksyms.c linux.14p1/kernel/ksyms.c
--- linux.vanilla/kernel/ksyms.c	Wed Oct 20 01:12:51 1999
+++ linux.14p1/kernel/ksyms.c	Fri Oct 22 21:34:26 1999
@@ -54,6 +54,9 @@
 #if !defined(CONFIG_NFSD) && defined(CONFIG_NFSD_MODULE)
 extern int (*do_nfsservctl)(int, void *, void *);
 #endif
+#if !defined(CONFIG_LOCKD) && defined(CONFIG_LOCKD_MODULE)
+extern int (*do_lockdctl)(int, void *, void *);
+#endif
 
 extern void *sys_call_table;
 
@@ -121,6 +124,7 @@
 EXPORT_SYMBOL(igrab);
 EXPORT_SYMBOL(iunique);
 EXPORT_SYMBOL(iget);
+EXPORT_SYMBOL(iget_in_use);
 EXPORT_SYMBOL(iput);
 EXPORT_SYMBOL(__namei);
 EXPORT_SYMBOL(lookup_dentry);
@@ -192,6 +196,9 @@
 
 #if !defined(CONFIG_NFSD) && defined(CONFIG_NFSD_MODULE)
 EXPORT_SYMBOL(do_nfsservctl);
+#endif
+#if !defined(CONFIG_LOCKD) && defined(CONFIG_LOCKD_MODULE)
+EXPORT_SYMBOL(do_lockdctl);
 #endif
 
 /* device registration */
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/kernel/sysctl.c linux.14p1/kernel/sysctl.c
--- linux.vanilla/kernel/sysctl.c	Wed Oct 20 01:12:51 1999
+++ linux.14p1/kernel/sysctl.c	Fri Oct 22 22:19:05 1999
@@ -169,8 +169,10 @@
 	 0644, NULL, &proc_doutsstring, &sysctl_string},
 	{KERN_PANIC, "panic", &panic_timeout, sizeof(int),
 	 0644, NULL, &proc_dointvec},
+#ifdef CONFIG_PROC_FS	 
 	{KERN_CAP_BSET, "cap-bound", &cap_bset, sizeof(kernel_cap_t),
 	 0600, NULL, &proc_dointvec_bset},
+#endif	 
 #ifdef CONFIG_BLK_DEV_INITRD
 	{KERN_REALROOTDEV, "real-root-dev", &real_root_dev, sizeof(int),
 	 0644, NULL, &proc_dointvec},
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/mm/filemap.c linux.14p1/mm/filemap.c
--- linux.vanilla/mm/filemap.c	Wed Oct 20 01:12:51 1999
+++ linux.14p1/mm/filemap.c	Fri Oct 22 21:34:42 1999
@@ -20,6 +20,7 @@
 #include <linux/file.h>
 #include <linux/swapctl.h>
 #include <linux/slab.h>
+#include <linux/init.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
@@ -32,7 +33,8 @@
  */
 
 unsigned long page_cache_size = 0;
-struct page * page_hash_table[PAGE_HASH_SIZE];
+unsigned int page_hash_bits, page_hash_mask;
+struct page **page_hash_table;
 
 /* 
  * Define a request structure for outstanding page write requests
@@ -1756,4 +1758,35 @@
 			kmem_cache_free(pio_request_cache, p);
 		}
 	}
+}
+
+void __init page_cache_init(unsigned long memory_size)
+{
+	unsigned long htable_size;
+	long order;
+
+	htable_size  = memory_size >> PAGE_SHIFT;
+	htable_size *= sizeof(struct page *);
+	for(order = 0; (PAGE_SIZE << order) < htable_size; order++)
+		;
+
+	do {
+		unsigned long tmp = (PAGE_SIZE << order) / sizeof(struct page *);
+
+		page_hash_mask = (tmp - 1UL);
+
+		page_hash_bits = 0;
+		while((tmp >>= 1UL) != 0UL)
+			page_hash_bits++;
+
+		page_hash_table = (struct page **)
+			__get_free_pages(GFP_ATOMIC, order);
+	} while(page_hash_table == NULL && --order >= 0L);
+
+	printk("Page-cache hash table entries: %d (order: %ld, %ld bytes)\n",
+	       (1 << page_hash_bits), order, (PAGE_SIZE << order));
+	if (!page_hash_table)
+		panic("Failed to allocate page hash table\n");
+	memset(page_hash_table, 0,
+	       (PAGE_HASH_MASK + 1UL) * sizeof(struct page *));
 }
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/net/802/fc.c linux.14p1/net/802/fc.c
--- linux.vanilla/net/802/fc.c	Sat Aug 28 20:00:59 1999
+++ linux.14p1/net/802/fc.c	Fri Oct 22 22:17:19 1999
@@ -90,7 +90,10 @@
 		printk("fc_rebuild_header: Don't know how to resolve type %04X addresses ?\n",(unsigned int)htons(fcllc->ethertype));
 		return 0;
 	}
-
+#ifdef CONFIG_INET
 	return arp_find(fch->daddr, skb);
+#else
+	return 0; /* Cannot happen because of ETH_P_IP test */
+#endif	
 }
 	
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/net/Config.in linux.14p1/net/Config.in
--- linux.vanilla/net/Config.in	Thu Feb 25 18:46:47 1999
+++ linux.14p1/net/Config.in	Fri Oct 22 22:39:35 1999
@@ -39,6 +39,9 @@
   tristate 'CCITT X.25 Packet Layer (EXPERIMENTAL)' CONFIG_X25
   tristate 'LAPB Data Link Driver (EXPERIMENTAL)' CONFIG_LAPB
   bool 'Bridging (EXPERIMENTAL)' CONFIG_BRIDGE
+  if [ "$CONFIG_BRIDGE" != "n" ]; then
+	int '  Maximum number of bridged interfaces' CONFIG_BRIDGE_NUM_PORTS 8
+  fi
   bool '802.2 LLC (EXPERIMENTAL)' CONFIG_LLC
 #  if [ "$CONFIG_LLC" = "y" ]; then
 #   bool 'Netbeui (EXPERIMENTAL)' CONFIG_NETBEUI
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/net/bridge/br.c linux.14p1/net/bridge/br.c
--- linux.vanilla/net/bridge/br.c	Sat Aug 14 02:27:41 1999
+++ linux.14p1/net/bridge/br.c	Fri Oct 22 22:39:35 1999
@@ -40,10 +40,19 @@
  *			so blame me first if its broken ;)
  *
  *	Robert Pintarelli:	fixed bug in bpdu time values
+ *
+ *      Matthew Grant:  start ports disabled.  
+ *                      auto-promiscuous mode on port enable/disable
+ *                      fleshed out interface event handling, interfaces 
+ *                        now register with bridge on module load as well as ifup
+ *                      port control ioctls with ifindex support
+ *                      brg0 logical ethernet interface
+ *                      reworked brcfg to take interface arguments
+ *                      added support for changing the hardware address
+ *                      generally made bridge a lot more usable.
  *	
  *	Todo:
- *		Don't bring up devices automatically. Start ports disabled
- *	and use a netlink notifier so a daemon can maintain the bridge
+ *	Use a netlink notifier so a daemon can maintain the bridge
  *	port group (could we also do multiple groups ????).
  *		A nice /proc file interface.
  *		Put the path costs in the port info and devices.
@@ -53,6 +62,7 @@
  */
  
 #include <linux/config.h>
+#include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/socket.h>
@@ -61,10 +71,13 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/timer.h>
+#include <linux/malloc.h>
 #include <linux/string.h>
 #include <linux/net.h>
 #include <linux/inet.h>
 #include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/if_arp.h>
 #include <linux/ip.h>
@@ -72,6 +85,7 @@
 #include <linux/init.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
+#include <linux/rtnetlink.h>
 #include <net/br.h>
 #include <linux/proc_fs.h>
 
@@ -145,11 +159,20 @@
 static int br_flood(struct sk_buff *skb, int port);
 static int br_drop(struct sk_buff *skb);
 static int br_learn(struct sk_buff *skb, int port);	/* 3.8 */
+static int br_protocol_ok(unsigned short protocol);
+static int br_find_port(int ifindex);
+static void br_get_ifnames(void);
+static int brg_rx(struct sk_buff *skb, int port);
 
 static unsigned char bridge_ula[ETH_ALEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
 static Bridge_data     bridge_info;			  /* (4.5.3)	 */
 Port_data       port_info[All_ports];		  /* (4.5.5)	 */
 
+/* MAG: Maximum port registered - used to speed up flooding and to make
+ * have a large ports array more efficient
+ */
+static int max_port_used = 0; 
+
 /* JRP: fdb cache 1/port save kmalloc/kfree on every frame */
 struct fdb	*newfdb[All_ports];
 int allocated_fdb_cnt = 0;
@@ -190,6 +213,30 @@
 	0
 };
 
+
+/* 
+ * the following data is for the bridge network device
+ */
+struct brg_if {
+  struct device dev;
+  char name[IFNAMSIZ];
+};
+static struct brg_if brg_if;
+
+/* 
+ * Here to save linkage? problems
+ */
+
+static inline int find_port(struct device *dev)
+{
+	int i;
+
+	for (i = One; i <= No_of_ports; i++)
+		if (port_info[i].dev == dev)
+			return(i);
+	return(0);
+}
+
 /*
  * Implementation of Protocol specific bridging
  *
@@ -202,7 +249,7 @@
 
 /* Checks if that protocol type is to be bridged */
 
-int br_protocol_ok(unsigned short protocol)
+static int inline br_protocol_ok(unsigned short protocol)
 {
 	unsigned x;
 	
@@ -843,8 +890,14 @@
 {						  /* (4.8.1)	 */
 	int port_no;
 
-	printk(KERN_INFO "NET4: Ethernet Bridge 005 for NET4.0\n");
+	printk(KERN_INFO "NET4: Ethernet Bridge 007 for NET4.0\n");
+
+	/* Set up brg device information */
+	bridge_info.instance = 0;
+	brg_init();
 
+	max_port_used = 0;
+	
 	/*
 	 * Form initial topology change time.
 	 * The topology change timer is only used if this is the root bridge.
@@ -874,8 +927,8 @@
 	stop_topology_change_timer();
 	memset(newfdb, 0, sizeof(newfdb));
 	for (port_no = One; port_no <= No_of_ports; port_no++) {	/* (4.8.1.4) */
-		/* initial state = Enable */
-		user_port_state[port_no] = ~Disabled;
+		/* initial state = Disable */
+		user_port_state[port_no] = Disabled;
 		port_priority[port_no] = 128;
 		br_init_port(port_no);
 		disable_port(port_no);
@@ -1306,6 +1359,9 @@
 	if (dev->flags & IFF_LOOPBACK)
 		return(NOTIFY_DONE);
 
+	if (dev == &brg_if.dev)
+	  return(NOTIFY_DONE);	/* Don't attach the brg device to a port! */
+	
 	switch (event) 
 	{
 		case NETDEV_DOWN:
@@ -1335,6 +1391,9 @@
 				{
 					port_info[i].dev = dev;
 					port_info[i].port_id = i;
+					dev->bridge_port_id = i;
+					if( i > max_port_used ) 
+						max_port_used = i;
 					/* set bridge addr from 1st device addr */
 					if (((htonl(bridge_info.bridge_id.BRIDGE_ID[0])&0xffff) == 0) &&
 						(bridge_info.bridge_id.BRIDGE_ID[1] == 0)) 
@@ -1344,7 +1403,10 @@
 							bridge_info.bridge_id.BRIDGE_PRIORITY = htons(32768);
 						set_bridge_priority(&bridge_info.bridge_id);
 					}
+					/* Add local MAC address */
 					br_add_local_mac(dev->dev_addr);
+					/* Save MAC address for latter change address events */
+					memcpy(port_info[i].ifmac.BRIDGE_ID_ULA, dev->dev_addr, 6);
 					if((br_stats.flags & BR_UP) &&
 				   		(user_port_state[i] != Disabled)) 
 				   	{
@@ -1362,19 +1424,122 @@
 				}
 			}
 			break;
+	        case NETDEV_REGISTER:
+		        if (br_stats.flags & BR_DEBUG) 
+				printk(KERN_DEBUG "br_device_event: NETDEV_REGISTER...\n");
+			/* printk(KERN_ERR "br_device_event: NETDEV_REGISTER...\n"); */
+			/* printk(KERN_ERR "br_device_event: dev->type: 0x%X\n", dev->type); */
+			/* Only handle ethernet ports */
+			if(dev->type!=ARPHRD_ETHER && dev->type!=ARPHRD_LOOPBACK)
+				return NOTIFY_DONE;
+			/* printk(KERN_ERR "br_device_event: Looking for port...\n"); */
+			for (i = One; i <= No_of_ports; i++) 
+			{
+				if (port_info[i].dev == NULL || port_info[i].dev == dev) 
+				{
+				        /* printk(KERN_ERR "br_device_event: Found port %d\n", i); */
+					port_info[i].dev = dev;
+					port_info[i].port_id = i;
+					dev->bridge_port_id = i;
+					if( i > max_port_used )
+						max_port_used = i;
+					/* handle local MAC address minuplations */
+					br_add_local_mac(dev->dev_addr);
+					memcpy(port_info[i].ifmac.BRIDGE_ID_ULA, dev->dev_addr, 6);
+					return NOTIFY_DONE;
+					break;
+				}
+			}
+			break;
 		case NETDEV_UNREGISTER:
 			if (br_stats.flags & BR_DEBUG)
 				printk(KERN_DEBUG "br_device_event: NETDEV_UNREGISTER...\n");
                         i = find_port(dev);
                         if (i > 0) {
 				br_avl_delete_by_port(i);
+				memset(port_info[i].ifmac.BRIDGE_ID_ULA, 0, 6);
 				port_info[i].dev = NULL;
 			}
 			break;
+		case NETDEV_CHANGEADDR:
+			if (br_stats.flags & BR_DEBUG)
+				printk(KERN_DEBUG "br_device_event: NETDEV_CHANGEADDR...\n");
+                        i = find_port(dev);
+                        if (i <= 0)  
+			  break;
+			if (memcmp(port_info[i].ifmac.BRIDGE_ID_ULA, dev->dev_addr, 6) != 0)
+			  break; /* Don't worry about a change of hardware broadcast address! */
+			if (dev->start) {
+			  printk(KERN_CRIT "br_device_event: NETDEV_CHANGEADDR on busy device %s - FIX DRIVER!\n", 
+				 dev->name);
+			/*  return NOTIFY_BAD;  It SHOULD be this, but I want to be friendly... */
+			  return NOTIFY_DONE;
+			}
+			br_avl_delete_by_port(i);
+			memset(port_info[i].ifmac.BRIDGE_ID_ULA, 0, 6);
+			break;
 	}
 	return NOTIFY_DONE;
 }
 
+/* Routine to loop over device list and register 
+ * interfaces to bridge.  Called from last part of net_dev_init just before
+ * bootp/rarp interface setup
+ */
+void br_spacedevice_register(void) 
+{
+	struct device *dev;
+	for( dev = dev_base; dev != NULL; dev = dev->next)
+	{
+		br_device_event(NULL, NETDEV_REGISTER, dev);
+	}
+}	
+
+
+/* This is for SPEED in the kernel in net_bh.c */
+
+int br_call_bridge(struct sk_buff *skb, unsigned short type)
+{
+	int port;
+	struct device *dev;
+  
+#if 0  /* Checked first in handle_bridge to save expense of function call */ 
+	if(!(br_stats.flags & BR_UP))
+		return 0;
+#endif
+  
+	dev = skb->dev;
+
+	/* Check for brg0 device
+	 */
+	if (dev == &brg_if.dev)
+		return 0;
+		 
+	port = dev->bridge_port_id;
+
+	if(!port)
+		return 0;
+
+	/* Sanity - make sure we are not leaping off into fairy space! */
+	if ( port < 0 || port > max_port_used || port_info[port].dev != dev) {
+		if (net_ratelimit())
+			printk(KERN_CRIT "br_call_bridge: device %s has invalid port ID %d!\n",
+				dev->name,
+				dev->bridge_port_id);
+		return 0;
+	}
+
+	if(user_port_state[port] == Disabled)
+		return 0;
+  
+	if (!br_protocol_ok(ntohs(type)))
+		return 0;
+
+	return 1;
+
+}
+
+
 /*
  * following routine is called when a frame is received
  * from an interface, it returns 1 when it consumes the
@@ -1383,9 +1548,10 @@
 
 int br_receive_frame(struct sk_buff *skb)	/* 3.5 */
 {
-	int port;
+	int port, ret;
 	Port_data  *p;
 	struct ethhdr *eth;
+	struct device *dev;
 	
 	/* sanity */
 	if (!skb) {
@@ -1393,17 +1559,32 @@
 		return(1);
 	}
 
+	dev = skb->dev;
+
+	/* Check for brg0 device 
+	 */
+	if (dev == &brg_if.dev)
+		return 0;
+
 	skb->pkt_bridged = IS_BRIDGED;
 
 	/* check for loopback */
-	if (skb->dev->flags & IFF_LOOPBACK)
+	if (dev->flags & IFF_LOOPBACK)
 		return 0 ;
 
-	port = find_port(skb->dev);
+#if 0
+	port = find_port(dev);
+#else
+	port = dev->bridge_port_id;
+#endif
 	
 	if(!port)
 		return 0;
 	
+	/* Hand off to brg_rx BEFORE we screw up the skb */
+	if(brg_rx(skb, port))
+	  return(1);
+
 	skb->nh.raw = skb->mac.raw;
 	eth = skb->mac.ethernet;
 	p = &port_info[port];
@@ -1435,9 +1616,9 @@
 	switch (p->state) 
 	{
 		case Learning:
-			if(br_learn(skb, port)) 
+			if((ret = br_learn(skb, port))) 
 			{	/* 3.8 */
-				++br_stats_cnt.drop_multicast;
+				if (ret > 0) ++br_stats_cnt.drop_multicast;
 				return br_drop(skb);
 			}
 			/* fall through */
@@ -1452,8 +1633,8 @@
 		 */
 			break;
 		case Forwarding:
-			if(br_learn(skb, port)) {	/* 3.8 */
-				++br_stats_cnt.drop_multicast;
+			if((ret = br_learn(skb, port))) {	/* 3.8 */
+				if (ret > 0) ++br_stats_cnt.drop_multicast;
 				return br_drop(skb);
 			}
 			/* Now this frame came from one of bridged
@@ -1577,7 +1758,11 @@
 
 /*
  * this routine returns 0 when it learns (or updates) from the
- * frame, and 1 if we must dropped the frame.
+ * frame, and 1 if we must dropped the frame due to multicast
+ * limitations, or -1 because of not enough memory.
+ *
+ * NB Can be called when skb->nh.raw is NOT set up when
+ * receiving frames on brg0 via brg_rx
  */
 
 static int br_learn(struct sk_buff *skb, int port)	/* 3.8 */
@@ -1600,8 +1785,8 @@
 		newfdb[port] = f = (struct fdb *)kmalloc(sizeof(struct fdb), GFP_ATOMIC);
 		if (!f) 
 		{
-			printk(KERN_DEBUG "br_learn: unable to malloc fdb\n");
-			return(-1); /* this drop the frame */
+			printk(KERN_WARNING "br_learn: unable to malloc fdb\n");
+			return(-1); /* this drops the frame */
 		}
 	}
 	f->port = port;	/* source port */
@@ -1819,6 +2004,9 @@
 	{
 		if (i == port)	/* don't send back where we got it */
 			continue;
+		if (i > max_port_used)
+			/* Don't go scanning empty port entries */
+			break;
 		if (port_info[i].state == Forwarding) 
 		{
 			nskb = skb_clone(skb, GFP_ATOMIC);
@@ -1840,16 +2028,6 @@
 	return(0);
 }
 
-static int find_port(struct device *dev)
-{
-	int i;
-
-	for (i = One; i <= No_of_ports; i++)
-		if (port_info[i].dev == dev)
-			return(i);
-	return(0);
-}
-
 /*
  *	FIXME: This needs to come from the device structs, eg for
  *	10,100,1Gbit ethernet.
@@ -1956,17 +2134,62 @@
 	return fdbis;
 }
 
+
+/* Fill in interface names in port_info structure
+ */
+static void br_get_ifdata(void) {
+	int i;
+
+  	for(i=One;i<=No_of_ports; i++) {
+
+		port_info[i].admin_state = user_port_state[i]; 
+		
+		/* memset IS needed.  Kernel strncpy does NOT NULL terminate 
+		 * strings when limit reached 
+	 	 */
+		memset(port_info[i].ifname, 0, IFNAMSIZ); 
+		if( port_info[i].dev == 0 )
+			continue;
+		strncpy(port_info[i].ifname, port_info[i].dev->name, IFNAMSIZ-1);
+		/* Being paranoid */
+		port_info[i].ifname[IFNAMSIZ-1] = '\0';
+	}
+}
+
+/* Given an interface index, loop over port array to see if configured.  If
+   so, return port number, otherwise error */ 
+static int br_find_port(int ifindex) 
+{
+  int i;
+  
+  for(i=1; i <= No_of_ports; i++) {
+    if (port_info[i].dev == 0)
+      continue;
+    if (port_info[i].dev->ifindex == ifindex)
+      return(i);
+  }
+  
+  return -EUNATCH;  /* Tell me if this is incorrect error code for this case */
+} 
+
+
 int br_ioctl(unsigned int cmd, void *arg)
 {
-	int err, i;
+	int err, i, ifflags;
 	struct br_cf bcf;
 	bridge_id_t new_id;
-
+	struct device *dev;
+	
 	switch(cmd)
 	{
 		case SIOCGIFBR:	/* get bridging control blocks */
 			memcpy(&br_stats.bridge_data, &bridge_info, sizeof(Bridge_data));
-			memcpy(&br_stats.port_data, &port_info, sizeof(Port_data)*No_of_ports);
+
+			/* Fill in interface names in port_info*/
+			br_get_ifdata();
+			
+			br_stats.num_ports = No_of_ports;
+			memcpy(&br_stats.port_data, &port_info, sizeof(Port_data)*All_ports);
 
 			err = copy_to_user(arg, &br_stats, sizeof(struct br_stat));
 			if (err)
@@ -2032,16 +2255,28 @@
 					}
 					br_stats.flags ^= BR_STP_DISABLED;
 					break;
+			        case BRCMD_IF_ENABLE:
+				        bcf.arg1 = br_find_port(bcf.arg1);
+					if (bcf.arg1 < 0)
+						return(bcf.arg1);
 				case BRCMD_PORT_ENABLE:
 					if (port_info[bcf.arg1].dev == 0)
 						return(-EINVAL);
 					if (user_port_state[bcf.arg1] != Disabled)
 						return(-EALREADY);
 					printk(KERN_DEBUG "br: enabling port %i\n",bcf.arg1);
+					dev = port_info[bcf.arg1].dev;
+					ifflags = (dev->flags&~(IFF_PROMISC|IFF_ALLMULTI))
+					  |(dev->gflags&(IFF_PROMISC|IFF_ALLMULTI)); 
+					dev_change_flags(dev, ifflags|IFF_PROMISC);
 					user_port_state[bcf.arg1] = ~Disabled;
 					if(br_stats.flags & BR_UP)
 						enable_port(bcf.arg1);
 					break;
+			        case BRCMD_IF_DISABLE:
+				        bcf.arg1 = br_find_port(bcf.arg1);
+					if (bcf.arg1 < 0)
+						return(bcf.arg1);
 				case BRCMD_PORT_DISABLE:
 					if (port_info[bcf.arg1].dev == 0)
 						return(-EINVAL);
@@ -2051,12 +2286,20 @@
 					user_port_state[bcf.arg1] = Disabled;
 					if(br_stats.flags & BR_UP)
 						disable_port(bcf.arg1);
+					dev = port_info[bcf.arg1].dev;
+					ifflags = (dev->flags&~(IFF_PROMISC|IFF_ALLMULTI))
+					  |(dev->gflags&(IFF_PROMISC|IFF_ALLMULTI)); 
+					dev_change_flags(port_info[bcf.arg1].dev, ifflags & ~IFF_PROMISC);
 					break;
 				case BRCMD_SET_BRIDGE_PRIORITY:
 					new_id = bridge_info.bridge_id;
 					new_id.BRIDGE_PRIORITY = htons(bcf.arg1);
 					set_bridge_priority(&new_id);
 					break;
+			        case BRCMD_SET_IF_PRIORITY:
+				        bcf.arg1 = br_find_port(bcf.arg1);
+					if (bcf.arg1 < 0)
+						return(bcf.arg1);
 				case BRCMD_SET_PORT_PRIORITY:
 					if((port_info[bcf.arg1].dev == 0)
 					    || (bcf.arg2 & ~0xff))
@@ -2064,6 +2307,10 @@
 					port_priority[bcf.arg1] = bcf.arg2;
 					set_port_priority(bcf.arg1);
 					break;
+			        case BRCMD_SET_IF_PATH_COST:
+				        bcf.arg1 = br_find_port(bcf.arg1);
+					if (bcf.arg1 < 0)
+						return(bcf.arg1);
 				case BRCMD_SET_PATH_COST:
 					if (port_info[bcf.arg1].dev == 0)
 						return(-EINVAL);
@@ -2145,3 +2392,385 @@
 	}
 	return(0);
 }
+
+
+
+
+/* --------------------------------------------------------------------------------
+ *
+ *
+ *  Bridge network device here for future modularization - device structures
+ *  must be 'static' inside bridge instance
+ *  Modelled after sch_teql.c
+ * 
+ */
+
+
+
+/*
+ *	Index to functions.
+ */
+
+int	    brg_probe(struct device *dev);
+static int  brg_open(struct device *dev);
+static int  brg_start_xmit(struct sk_buff *skb, struct device *dev);
+static int  brg_close(struct device *dev);
+static struct net_device_stats *brg_get_stats(struct device *dev);
+static void brg_set_multicast_list(struct device *dev);
+
+/*
+ *	Board-specific info in dev->priv.
+ */
+
+struct net_local
+{
+	__u32		groups;
+	struct net_device_stats stats;
+};
+
+
+
+
+/*
+ *	To call this a probe is a bit misleading, however for real
+ *	hardware it would have to check what was present.
+ */
+ 
+__initfunc(int brg_probe(struct device *dev))
+{
+  unsigned int bogomips;
+  struct timeval utime;
+
+  printk(KERN_INFO "%s: network interface for Ethernet Bridge 007/NET4.0\n", dev->name);
+
+  /*
+   *	Initialize the device structure.
+   */
+  
+  dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
+  if (dev->priv == NULL)
+    return -ENOMEM;
+  memset(dev->priv, 0, sizeof(struct net_local));
+
+  /* Set up MAC address based on BogoMIPs figure for first CPU and time
+   */ 
+  bogomips = (boot_cpu_data.loops_per_sec+2500)/500000 ;
+  get_fast_time(&utime);
+
+  /* Ummmm....  YES! */
+  dev->dev_addr[0] = '\xFE';
+  dev->dev_addr[1] = '\xFD';
+  dev->dev_addr[2] = (bridge_info.instance & 0x0F) << 4;
+  dev->dev_addr[2] |= ((utime.tv_sec & 0x000F0000) >> 16);
+  dev->dev_addr[3] = bogomips & 0xFF;
+  dev->dev_addr[4] = (utime.tv_sec & 0x0000FF00) >> 8;
+  dev->dev_addr[5] = (utime.tv_sec & 0x000000FF);
+  
+  printk(KERN_INFO "%s: generated MAC address %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n", 
+	 dev->name,
+	 dev->dev_addr[0],
+	 dev->dev_addr[1],
+	 dev->dev_addr[2],
+	 dev->dev_addr[3],
+	 dev->dev_addr[4],
+	 dev->dev_addr[5]);
+
+  
+  printk(KERN_INFO "%s: attached to bridge instance %lu\n", dev->name, dev->base_addr);
+
+  /*
+   *	The brg specific entries in the device structure.
+   */
+
+  dev->open = brg_open;
+  dev->hard_start_xmit = brg_start_xmit;
+  dev->stop = brg_close;
+  dev->get_stats = brg_get_stats;
+  dev->set_multicast_list = brg_set_multicast_list;
+
+  /*
+   *	Setup the generic properties
+   */
+
+  ether_setup(dev);
+
+  dev->tx_queue_len = 0;
+
+  return 0;
+}
+
+/*
+ *	Open/initialize the board.
+ */
+
+static int brg_open(struct device *dev)
+{
+        if (br_stats.flags & BR_DEBUG)
+		printk(KERN_DEBUG "%s: Doing brg_open()...", dev->name);
+
+	if (memcmp(dev->dev_addr, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0)
+	  return -EFAULT;
+
+	dev->start = 1;
+	dev->tbusy = 0;
+	return 0;
+}
+
+static unsigned brg_mc_hash(__u8 *dest)
+{
+	unsigned idx = 0;
+	idx ^= dest[0];
+	idx ^= dest[1];
+	idx ^= dest[2];
+	idx ^= dest[3];
+	idx ^= dest[4];
+	idx ^= dest[5];
+	return 1U << (idx&0x1F);
+}
+
+static void brg_set_multicast_list(struct device *dev)
+{
+	unsigned groups = ~0;
+	struct net_local *lp = (struct net_local *)dev->priv;
+
+	if (!(dev->flags&(IFF_PROMISC|IFF_ALLMULTI))) {
+		struct dev_mc_list *dmi;
+
+		groups = brg_mc_hash(dev->broadcast);
+
+		for (dmi=dev->mc_list; dmi; dmi=dmi->next) {
+			if (dmi->dmi_addrlen != 6)
+				continue;
+			groups |= brg_mc_hash(dmi->dmi_addr);
+		}
+	}
+	lp->groups = groups;
+}
+
+/*
+ *	We transmit by throwing the packet at the bridge.
+ */
+ 
+static int brg_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+	struct ethhdr *eth = (struct ethhdr*)skb->data;
+	int port;
+
+	/* Deal with the bridge being disabled */
+	if(!(br_stats.flags & BR_UP)) {
+		/* Either this */
+		/* lp->stats.tx_errors++; */ /* this condition is NOT an error */
+		/* or this  (implied by RFC 2233) */
+		lp->stats.tx_dropped++;
+		dev_kfree_skb(skb);
+		return 0;
+	}
+
+	lp->stats.tx_bytes+=skb->len;
+	lp->stats.tx_packets++;
+
+#if 0
+	++br_stats_cnt.port_not_disable;
+#endif
+	skb->mac.raw = skb->nh.raw = skb->data;
+	eth = skb->mac.ethernet;
+	port = 0;	/* an impossible port (locally generated) */	
+
+	 if (br_stats.flags & BR_DEBUG)
+		printk("%s: brg_start_xmit - src %02x:%02x:%02x:%02x:%02x:%02x"
+	  		" dest %02x:%02x:%02x:%02x:%02x:%02x\n", 
+		       dev->name,
+		       eth->h_source[0],
+		       eth->h_source[1],
+		       eth->h_source[2],
+		       eth->h_source[3],
+		       eth->h_source[4],
+		       eth->h_source[5],
+		       eth->h_dest[0],
+		       eth->h_dest[1],
+		       eth->h_dest[2],
+		       eth->h_dest[3],
+		       eth->h_dest[4],
+		       eth->h_dest[5]);
+	
+	/* Forward the packet ! */
+	if(br_forward(skb, port))
+	  return(0);
+    
+	/* Throw packet initially */
+	dev_kfree_skb(skb);
+	return 0;
+}
+
+
+/*
+ *	The typical workload of the driver:
+ *	Handle the ether interface interrupts.
+ *
+ *	(In this case handle the packets posted from the bridge)
+ */
+
+static int brg_rx(struct sk_buff *skb, int port)
+{
+        struct device *dev = &brg_if.dev;
+	struct net_local *lp = (struct net_local *)dev->priv;
+	struct ethhdr *eth = (struct ethhdr*)(skb->data);
+	int len = skb->len;
+	int clone = 0;
+
+	if (br_stats.flags & BR_DEBUG)
+		printk(KERN_DEBUG "%s: brg_rx()\n", dev->name);
+
+	/* Get out of here if the bridge interface is not up
+	 */
+	if(!(dev->flags & IFF_UP))
+	  return(0);
+	
+	/* Check that the port that this thing came off is in the forwarding state 
+	 * We sould only listen to the same address scope we will transmit to.
+	 */
+	if(port_info[port].state != Forwarding)
+	  return(0);
+
+	/* Is this for us? - broadcast/mulitcast/promiscuous packets need cloning,
+         * with uni-cast we eat the packet
+	 */
+	clone = 0;
+	if (dev->flags & IFF_PROMISC) {
+	  clone = 1;
+	}
+	else if (eth->h_dest[0]&1) {
+	  if (!(dev->flags&(IFF_ALLMULTI))
+	      && !(brg_mc_hash(eth->h_dest)&lp->groups))
+	    return(0);
+	  clone = 1;
+	}
+	else if (memcmp(eth->h_dest, dev->dev_addr, ETH_ALEN) != 0) {
+	  return(0);
+	}
+
+	/* Clone things here - we want to be transparent before we check packet data 
+	 * integrity
+	 */
+	if(clone) {
+	  struct sk_buff *skb2 = skb;
+	  skb = skb_clone(skb2, GFP_KERNEL);
+	  if (skb == NULL) {
+	    return(0);
+	  }
+	  
+	}
+	else {
+		/* Learn source addresses for unicast non-promiscuous 
+		 * frames for brg0
+		 */
+		if(br_learn(skb, port)) {
+			return br_drop(skb);
+		}
+	}
+
+	/* Check packet length 
+	 */
+	if (len < 16) {
+		printk(KERN_DEBUG "%s : rx len = %d\n", dev->name, len);
+		kfree_skb(skb);
+		return(!clone);
+	}
+
+	if (br_stats.flags & BR_DEBUG)
+	  printk("%s: brg_rx - src %02x:%02x:%02x:%02x:%02x:%02x"
+		 " dest %02x:%02x:%02x:%02x:%02x:%02x\n", 
+		 dev->name,
+		 eth->h_source[0],
+		 eth->h_source[1],
+		 eth->h_source[2],
+		 eth->h_source[3],
+		 eth->h_source[4],
+		 eth->h_source[5],
+		 eth->h_dest[0],
+		 eth->h_dest[1],
+		 eth->h_dest[2],
+		 eth->h_dest[3],
+		 eth->h_dest[4],
+		 eth->h_dest[5]);
+
+	/* Do it */
+	skb->pkt_type = PACKET_HOST;
+	skb->dev = dev;
+	skb->protocol=eth_type_trans(skb,dev);
+	memset(skb->cb, 0, sizeof(skb->cb));
+	lp->stats.rx_packets++;
+	lp->stats.rx_bytes+=len;
+	netif_rx(skb);
+	return(!clone);
+}
+
+static int brg_close(struct device *dev)
+{
+	if (br_stats.flags & BR_DEBUG)
+		printk(KERN_DEBUG "%s: Shutting down.\n", dev->name);
+
+	dev->tbusy = 1;
+	dev->start = 0;
+
+	return 0;
+}
+
+static struct net_device_stats *brg_get_stats(struct device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+	return &lp->stats;
+}
+
+/* 
+ *      
+ */
+
+__initfunc(int brg_init(void))
+{
+        int err;
+
+	memset(&brg_if, 0, sizeof(brg_if));
+
+        rtnl_lock();
+
+	brg_if.dev.base_addr = bridge_info.instance;
+	sprintf (brg_if.name, "brg%d", bridge_info.instance);
+	brg_if.dev.name = (void*)&brg_if.name;
+        if(dev_get(brg_if.name)) {
+               printk(KERN_INFO "%s already loaded.\n", brg_if.name);
+	       return -EBUSY;
+	}
+        brg_if.dev.init = brg_probe;
+
+        err = register_netdevice(&brg_if.dev);
+        rtnl_unlock();
+        return err;
+}
+
+
+#if 0				/* Its here if we ever need it... */
+#ifdef MODULE
+
+void cleanup_module(void)
+{
+
+  /* 
+   * Unregister the device
+   */
+  rtnl_lock();
+  unregister_netdevice(&the_master.dev);
+  rtnl_unlock();
+
+  /*
+   *	Free up the private structure.
+   */
+  
+  kfree(brg_if.dev.priv);
+  brg_if.dev.priv = NULL;	/* gets re-allocated by brg_probe */
+}
+
+#endif /* MODULE */
+
+#endif
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/net/bridge/br_tree.c linux.14p1/net/bridge/br_tree.c
--- linux.vanilla/net/bridge/br_tree.c	Sun Mar  7 23:25:23 1999
+++ linux.14p1/net/bridge/br_tree.c	Fri Oct 22 22:39:35 1999
@@ -492,7 +492,8 @@
         port_info[port].fdb = NULL;
 
         /* remove the local mac too */
-        next = br_avl_find_addr(port_info[port].dev->dev_addr);
+/*        next = br_avl_find_addr(port_info[port].dev->dev_addr); */
+        next = br_avl_find_addr(port_info[port].ifmac.BRIDGE_ID_ULA);
         if (next != NULL)
                 br_avl_remove(next);
 
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/net/core/dev.c linux.14p1/net/core/dev.c
--- linux.vanilla/net/core/dev.c	Wed Oct 20 01:12:52 1999
+++ linux.14p1/net/core/dev.c	Fri Oct 22 22:39:35 1999
@@ -796,7 +796,11 @@
 #ifdef CONFIG_BRIDGE
 static inline void handle_bridge(struct sk_buff *skb, unsigned short type)
 {
-	if (br_stats.flags & BR_UP && br_protocol_ok(ntohs(type)))
+	/* 
+	 * The br_stats.flags is checked here to save the expense of a 
+	 * function call.
+	 */
+	if ((br_stats.flags & BR_UP) && br_call_bridge(skb, type))
 	{
 		/*
 		 *	We pass the bridge a complete frame. This means
@@ -820,7 +824,6 @@
 }
 #endif
 
-
 /*
  *	When we are called the queue is ready to grab, the interrupts are
  *	on and hardware can interrupt and queue to the receive queue as we
@@ -2017,6 +2020,13 @@
 	dev_boot_phase = 0;
 
 	dev_mcast_init();
+
+#ifdef CONFIG_BRIDGE
+	/*
+	 * Register any statically linked ethernet devices with the bridge
+	 */
+	br_spacedevice_register();
+#endif
 
 #ifdef CONFIG_IP_PNP
 	ip_auto_config();
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/net/ipv4/ip_forward.c linux.14p1/net/ipv4/ip_forward.c
--- linux.vanilla/net/ipv4/ip_forward.c	Sun Mar 21 15:22:00 1999
+++ linux.14p1/net/ipv4/ip_forward.c	Fri Oct 22 22:43:30 1999
@@ -176,7 +176,7 @@
 			    (icmph->type==ICMP_TIME_EXCEEDED))
 			{
 #endif
-				maddr = inet_select_addr(dev2, rt->rt_gateway, RT_SCOPE_UNIVERSE);
+				maddr = rt->rt_src;
 				fw_res = ip_fw_masq_icmp(&skb, maddr);
 			        if (fw_res < 0) {
 					kfree_skb(skb);
@@ -226,7 +226,7 @@
 
 		if (maddr == 0)
 #endif
-			maddr = inet_select_addr(dev2, rt->rt_gateway, RT_SCOPE_UNIVERSE);
+			maddr = rt->rt_src;
 
 			if (ip_fw_masquerade(&skb, maddr) < 0) {
 				kfree_skb(skb);
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/net/ipv4/ip_fw.c linux.14p1/net/ipv4/ip_fw.c
--- linux.vanilla/net/ipv4/ip_fw.c	Wed Oct 20 01:12:52 1999
+++ linux.14p1/net/ipv4/ip_fw.c	Fri Oct 22 22:22:20 1999
@@ -488,7 +488,10 @@
                 static int enabled = 0;
 
                 if(!enabled)
+                {
+                	enabled=1;
                         sysctl_ip_always_defrag++;
+                }
 		*answer = FW_REDIRECT;
 		return 1;
 #endif
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/net/ipv4/tcp.c linux.14p1/net/ipv4/tcp.c
--- linux.vanilla/net/ipv4/tcp.c	Sat Aug 14 02:27:41 1999
+++ linux.14p1/net/ipv4/tcp.c	Fri Oct 22 21:35:49 1999
@@ -1798,6 +1798,8 @@
 void __init tcp_init(void)
 {
 	struct sk_buff *skb = NULL;
+	unsigned long goal;
+	int order;
 
 	if(sizeof(struct tcp_skb_cb) > sizeof(skb->cb))
 		__skb_cb_too_small_for_tcp(sizeof(struct tcp_skb_cb),
@@ -1823,4 +1825,43 @@
 						NULL, NULL);
 	if(!tcp_timewait_cachep)
 		panic("tcp_init: Cannot alloc tcp_tw_bucket cache.");
+
+	/* Size and allocate TCP hash tables. */
+	goal = num_physpages >> (20 - PAGE_SHIFT);
+	for (order = 0; (1UL << order) < goal; order++)
+		;
+	do {
+		tcp_ehash_size = (1UL << order) * PAGE_SIZE /
+			sizeof(struct sock *);
+		tcp_ehash = (struct sock **)
+			__get_free_pages(GFP_ATOMIC, order);
+	} while (tcp_ehash == NULL && --order >= 0);
+
+	if (!tcp_ehash)
+		panic("Failed to allocate TCP established hash table\n");
+	memset(tcp_ehash, 0, tcp_ehash_size * sizeof(struct sock *));
+
+	goal = (((1UL << order) * PAGE_SIZE) / sizeof(struct tcp_bind_bucket *));
+	if (goal > (64 * 1024)) {
+		/* Don't size the bind-hash larger than the port
+		 * space, that is just silly.
+		 */
+		goal = (((64 * 1024) * sizeof(struct tcp_bind_bucket *)) / PAGE_SIZE);
+		for (order = 0; (1UL << order) < goal; order++)
+			;
+	}
+
+	do {
+		tcp_bhash_size = (1UL << order) * PAGE_SIZE /
+			sizeof(struct tcp_bind_bucket *);
+		tcp_bhash = (struct tcp_bind_bucket **)
+			__get_free_pages(GFP_ATOMIC, order);
+	} while (tcp_bhash == NULL && --order >= 0);
+
+	if (!tcp_bhash)
+		panic("Failed to allocate TCP bind hash table\n");
+	memset(tcp_bhash, 0, tcp_bhash_size * sizeof(struct tcp_bind_bucket *));
+
+	printk("TCP: Hash tables configured (ehash %d bhash %d)\n",
+	       tcp_ehash_size, tcp_bhash_size);
 }
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/net/ipv4/tcp_input.c linux.14p1/net/ipv4/tcp_input.c
--- linux.vanilla/net/ipv4/tcp_input.c	Sat Aug 28 20:00:59 1999
+++ linux.14p1/net/ipv4/tcp_input.c	Fri Oct 22 21:36:08 1999
@@ -1043,7 +1043,7 @@
 	sk->prot->inuse--;
 
 	/* Step 4: Hash TW into TIMEWAIT half of established hash table. */
-	head = &tcp_established_hash[sk->hashent + (TCP_HTABLE_SIZE/2)];
+	head = &tcp_ehash[sk->hashent + (tcp_ehash_size/2)];
 	sktw = (struct sock *)tw;
 	if((sktw->next = *head) != NULL)
 		(*head)->pprev = &sktw->next;
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/net/ipv4/tcp_ipv4.c linux.14p1/net/ipv4/tcp_ipv4.c
--- linux.vanilla/net/ipv4/tcp_ipv4.c	Wed Oct 20 01:12:52 1999
+++ linux.14p1/net/ipv4/tcp_ipv4.c	Fri Oct 22 21:36:08 1999
@@ -90,12 +90,14 @@
  * First half of the table is for sockets not in TIME_WAIT, second half
  * is for TIME_WAIT sockets only.
  */
-struct sock *tcp_established_hash[TCP_HTABLE_SIZE];
+unsigned int tcp_ehash_size;
+struct sock **tcp_ehash;
 
 /* Ok, let's try this, I give up, we do need a local binding
  * TCP hash as well as the others for fast bind/connect.
  */
-struct tcp_bind_bucket *tcp_bound_hash[TCP_BHTABLE_SIZE];
+unsigned int tcp_bhash_size;
+struct tcp_bind_bucket **tcp_bhash;
 
 /* All sockets in TCP_LISTEN state will be in here.  This is the only table
  * where wildcard'd TCP sockets can exist.  Hash function here is just local
@@ -117,7 +119,7 @@
 static __inline__ int tcp_hashfn(__u32 laddr, __u16 lport,
 				 __u32 faddr, __u16 fport)
 {
-	return ((laddr ^ lport) ^ (faddr ^ fport)) & ((TCP_HTABLE_SIZE/2) - 1);
+	return ((laddr ^ lport) ^ (faddr ^ fport)) & ((tcp_ehash_size/2) - 1);
 }
 
 static __inline__ int tcp_sk_hashfn(struct sock *sk)
@@ -140,7 +142,7 @@
 	tb = kmem_cache_alloc(tcp_bucket_cachep, SLAB_ATOMIC);
 	if(tb != NULL) {
 		struct tcp_bind_bucket **head =
-			&tcp_bound_hash[tcp_bhashfn(snum)];
+			&tcp_bhash[tcp_bhashfn(snum)];
 		tb->port = snum;
 		tb->fastreuse = 0;
 		tb->owners = NULL;
@@ -162,7 +164,7 @@
 {
 	struct tcp_bind_bucket *tb;
 
-	tb = tcp_bound_hash[tcp_bhashfn(snum)];
+	tb = tcp_bhash[tcp_bhashfn(snum)];
 	for( ; (tb && (tb->port != snum)); tb = tb->next)
 		;
 	if (tb == NULL) {
@@ -181,7 +183,7 @@
 #ifdef CONFIG_IP_TRANSPARENT_PROXY
 	if (child->num != sk->num) {
 		unsigned short snum = ntohs(child->num);
-		for(tb = tcp_bound_hash[tcp_bhashfn(snum)];
+		for(tb = tcp_bhash[tcp_bhashfn(snum)];
 		    tb && tb->port != snum;
 		    tb = tb->next)
 			;
@@ -220,7 +222,7 @@
 		do {	rover++;
 			if ((rover < low) || (rover > high))
 				rover = low;
-			tb = tcp_bound_hash[tcp_bhashfn(rover)];
+			tb = tcp_bhash[tcp_bhashfn(rover)];
 			for ( ; tb; tb = tb->next)
 				if (tb->port == rover)
 					goto next;
@@ -237,7 +239,7 @@
 		snum = rover;
 		tb = NULL;
 	} else {
-		for (tb = tcp_bound_hash[tcp_bhashfn(snum)];
+		for (tb = tcp_bhash[tcp_bhashfn(snum)];
 		     tb != NULL;
 		     tb = tb->next)
 			if (tb->port == snum)
@@ -328,7 +330,7 @@
 	if(sk->state == TCP_LISTEN)
 		skp = &tcp_listening_hash[tcp_sk_listen_hashfn(sk)];
 	else
-		skp = &tcp_established_hash[(sk->hashent = tcp_sk_hashfn(sk))];
+		skp = &tcp_ehash[(sk->hashent = tcp_sk_hashfn(sk))];
 
 	if((sk->next = *skp) != NULL)
 		(*skp)->pprev = &sk->next;
@@ -421,7 +423,7 @@
 	 * have wildcards anyways.
 	 */
 	hash = tcp_hashfn(daddr, hnum, saddr, sport);
-	for(sk = tcp_established_hash[hash]; sk; sk = sk->next) {
+	for(sk = tcp_ehash[hash]; sk; sk = sk->next) {
 		if(TCP_IPV4_MATCH(sk, acookie, saddr, daddr, ports, dif)) {
 			if (sk->state == TCP_ESTABLISHED)
 				TCP_RHASH(sport) = sk;
@@ -429,7 +431,7 @@
 		}
 	}
 	/* Must check for a TIME_WAIT'er before going to listener hash. */
-	for(sk = tcp_established_hash[hash+(TCP_HTABLE_SIZE/2)]; sk; sk = sk->next)
+	for(sk = tcp_ehash[hash+(tcp_ehash_size/2)]; sk; sk = sk->next)
 		if(TCP_IPV4_MATCH(sk, acookie, saddr, daddr, ports, dif))
 			goto hit;
 	sk = tcp_v4_lookup_listener(daddr, hnum, dif);
@@ -469,7 +471,7 @@
 
 	/* This code must run only from NET_BH. */
 	{
-		struct tcp_bind_bucket *tb = tcp_bound_hash[tcp_bhashfn(hnum)];
+		struct tcp_bind_bucket *tb = tcp_bhash[tcp_bhashfn(hnum)];
 		for( ; (tb && tb->port != hnum); tb = tb->next)
 			;
 		if(tb == NULL)
@@ -510,7 +512,7 @@
 	}
 next:
 	if(firstpass--) {
-		struct tcp_bind_bucket *tb = tcp_bound_hash[tcp_bhashfn(hpnum)];
+		struct tcp_bind_bucket *tb = tcp_bhash[tcp_bhashfn(hpnum)];
 		for( ; (tb && tb->port != hpnum); tb = tb->next)
 			;
 		if(tb) {
@@ -547,7 +549,7 @@
 
 	/* Freeze the hash while we snoop around. */
 	SOCKHASH_LOCK();
-	tb = tcp_bound_hash[tcp_bhashfn(snum)];
+	tb = tcp_bhash[tcp_bhashfn(snum)];
 	for(; tb; tb = tb->next) {
 		if(tb->port == snum && tb->owners != NULL) {
 			/* Almost certainly the re-use port case, search the real hashes
@@ -1793,7 +1795,7 @@
 
 static void __tcp_v4_rehash(struct sock *sk)
 {
-	struct sock **skp = &tcp_established_hash[(sk->hashent = tcp_sk_hashfn(sk))];
+	struct sock **skp = &tcp_ehash[(sk->hashent = tcp_sk_hashfn(sk))];
 
 	SOCKHASH_LOCK();
 	if(sk->pprev) {
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/net/ipv4/tcp_timer.c linux.14p1/net/ipv4/tcp_timer.c
--- linux.vanilla/net/ipv4/tcp_timer.c	Sat Aug 14 02:27:41 1999
+++ linux.14p1/net/ipv4/tcp_timer.c	Fri Oct 22 21:36:08 1999
@@ -363,8 +363,8 @@
 	int count = 0;
 	int i;
 	
-	for(i = chain_start; i < (chain_start + ((TCP_HTABLE_SIZE/2) >> 2)); i++) {
-		struct sock *sk = tcp_established_hash[i];
+	for(i = chain_start; i < (chain_start + ((tcp_ehash_size/2) >> 2)); i++) {
+		struct sock *sk = tcp_ehash[i];
 		while(sk) {
 			if(!atomic_read(&sk->sock_readers) && sk->keepopen) {
 				count += tcp_keepopen_proc(sk);
@@ -375,8 +375,8 @@
 		}
 	}
 out:
-	chain_start = ((chain_start + ((TCP_HTABLE_SIZE/2)>>2)) &
-		       ((TCP_HTABLE_SIZE/2) - 1));
+	chain_start = ((chain_start + ((tcp_ehash_size/2)>>2)) &
+		       ((tcp_ehash_size/2) - 1));
 }
 
 /*
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/net/ipv6/tcp_ipv6.c linux.14p1/net/ipv6/tcp_ipv6.c
--- linux.vanilla/net/ipv6/tcp_ipv6.c	Sat Aug 28 20:00:59 1999
+++ linux.14p1/net/ipv6/tcp_ipv6.c	Fri Oct 22 21:36:09 1999
@@ -67,7 +67,7 @@
 	int hashent = (lport ^ fport);
 
 	hashent ^= (laddr->s6_addr32[3] ^ faddr->s6_addr32[3]);
-	return (hashent & ((TCP_HTABLE_SIZE/2) - 1));
+	return (hashent & ((tcp_ehash_size/2) - 1));
 }
 
 static __inline__ int tcp_v6_sk_hashfn(struct sock *sk)
@@ -98,7 +98,7 @@
 		do {	rover++;
 			if ((rover < low) || (rover > high))
 				rover = low;
-			tb = tcp_bound_hash[tcp_bhashfn(rover)];
+			tb = tcp_bhash[tcp_bhashfn(rover)];
 			for ( ; tb; tb = tb->next)
 				if (tb->port == rover)
 					goto next;
@@ -115,7 +115,7 @@
 		snum = rover;
 		tb = NULL;
 	} else {
-		for (tb = tcp_bound_hash[tcp_bhashfn(snum)];
+		for (tb = tcp_bhash[tcp_bhashfn(snum)];
 		     tb != NULL;
 		     tb = tb->next)
 			if (tb->port == snum)
@@ -194,7 +194,7 @@
 		if(sk->state == TCP_LISTEN)
 			skp = &tcp_listening_hash[tcp_sk_listen_hashfn(sk)];
 		else
-			skp = &tcp_established_hash[(sk->hashent = tcp_v6_sk_hashfn(sk))];
+			skp = &tcp_ehash[(sk->hashent = tcp_v6_sk_hashfn(sk))];
 
 		SOCKHASH_LOCK();
 		if((sk->next = *skp) != NULL)
@@ -276,7 +276,7 @@
 	 * have wildcards anyways.
 	 */
 	hash = tcp_v6_hashfn(daddr, hnum, saddr, sport);
-	for(sk = tcp_established_hash[hash]; sk; sk = sk->next) {
+	for(sk = tcp_ehash[hash]; sk; sk = sk->next) {
 		/* For IPV6 do the cheaper port and family tests first. */
 		if(TCP_IPV6_MATCH(sk, saddr, daddr, ports, dif)) {
 			if (sk->state == TCP_ESTABLISHED)
@@ -285,7 +285,7 @@
 		}
 	}
 	/* Must check for a TIME_WAIT'er before going to listener hash. */
-	for(sk = tcp_established_hash[hash+(TCP_HTABLE_SIZE/2)]; sk; sk = sk->next) {
+	for(sk = tcp_ehash[hash+(tcp_ehash_size/2)]; sk; sk = sk->next) {
 		if(*((__u32 *)&(sk->dport))	== ports	&&
 		   sk->family			== PF_INET6) {
 			struct tcp_tw_bucket *tw = (struct tcp_tw_bucket *)sk;
@@ -336,7 +336,7 @@
 
 	/* Freeze the hash while we snoop around. */
 	SOCKHASH_LOCK();
-	tb = tcp_bound_hash[tcp_bhashfn(snum)];
+	tb = tcp_bhash[tcp_bhashfn(snum)];
 	for(; tb; tb = tb->next) {
 		if(tb->port == snum && tb->owners != NULL) {
 			/* Almost certainly the re-use port case, search the real hashes
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/net/irda/irlan/irlan_eth.c linux.14p1/net/irda/irlan/irlan_eth.c
--- linux.vanilla/net/irda/irlan/irlan_eth.c	Sat Aug 14 02:26:52 1999
+++ linux.14p1/net/irda/irlan/irlan_eth.c	Fri Oct 22 22:17:19 1999
@@ -345,6 +345,7 @@
 	 * is useful if we have changed access points on the same
 	 * subnet.  
 	 */
+#ifdef CONFIG_INET	 
 	DEBUG(4, "IrLAN: Sending gratuitous ARP\n");
 	in_dev = dev->ip_ptr;
 	arp_send(ARPOP_REQUEST, ETH_P_ARP, 
@@ -352,6 +353,7 @@
 		 dev, 
 		 in_dev->ifa_list->ifa_address,
 		 NULL, dev->dev_addr, NULL);
+#endif /* CONFIG_INET */		 
 }
 
 /*
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/net/netsyms.c linux.14p1/net/netsyms.c
--- linux.vanilla/net/netsyms.c	Wed Oct 20 01:12:52 1999
+++ linux.14p1/net/netsyms.c	Fri Oct 22 22:17:19 1999
@@ -277,9 +277,11 @@
 EXPORT_SYMBOL(inet_recvmsg);
 
 /* Socket demultiplexing. */
-EXPORT_SYMBOL(tcp_established_hash);
+EXPORT_SYMBOL(tcp_ehash_size);
+EXPORT_SYMBOL(tcp_ehash);
 EXPORT_SYMBOL(tcp_listening_hash);
-EXPORT_SYMBOL(tcp_bound_hash);
+EXPORT_SYMBOL(tcp_bhash_size);
+EXPORT_SYMBOL(tcp_bhash);
 EXPORT_SYMBOL(udp_hash);
 
 EXPORT_SYMBOL(destroy_sock);
@@ -496,8 +498,10 @@
 EXPORT_SYMBOL(unregister_hipdev);
 #endif
 
+#ifdef CONFIG_INET
 EXPORT_SYMBOL(sysctl_wmem_max);
 EXPORT_SYMBOL(sysctl_rmem_max);
+#endif
 
 #if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE) 
 #include<linux/if_ltalk.h>
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/net/sunrpc/clnt.c linux.14p1/net/sunrpc/clnt.c
--- linux.vanilla/net/sunrpc/clnt.c	Tue Oct  6 17:39:44 1998
+++ linux.14p1/net/sunrpc/clnt.c	Fri Oct 22 22:46:31 1999
@@ -467,6 +467,9 @@
 		return;
 	}
 
+	/* Zero buffer so we have automatic zero-padding of opaque & string */
+	memset(task->tk_buffer, 0, bufsiz);
+
 	/* Encode header and provided arguments */
 	encode = rpcproc_encode(clnt, task->tk_proc);
 	if (!(p = call_header(task))) {
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/net/sunrpc/svc.c linux.14p1/net/sunrpc/svc.c
--- linux.vanilla/net/sunrpc/svc.c	Wed Oct 20 01:12:52 1999
+++ linux.14p1/net/sunrpc/svc.c	Fri Oct 22 21:36:09 1999
@@ -38,7 +38,7 @@
 
 	memset(serv, 0, sizeof(*serv));
 	serv->sv_program   = prog;
-	serv->sv_nrthreads = 1;
+	atomic_set(&serv->sv_nrthreads, 1);
 	serv->sv_stats     = prog->pg_stats;
 	serv->sv_bufsz	   = bufsize? bufsize : 4096;
 	serv->sv_xdrsize   = xdrsize;
@@ -61,10 +61,10 @@
 
 	dprintk("RPC: svc_destroy(%s, %d)\n",
 				serv->sv_program->pg_name,
-				serv->sv_nrthreads);
+				atomic_read (&serv->sv_nrthreads));
 
-	if (serv->sv_nrthreads) {
-		if (--(serv->sv_nrthreads) != 0)
+	if (atomic_read (&serv->sv_nrthreads)) {
+		if (!atomic_dec_and_test (&serv->sv_nrthreads))
 			return;
 	} else
 		printk("svc_destroy: no threads for serv=%p!\n", serv);
@@ -128,7 +128,7 @@
 	 || !svc_init_buffer(&rqstp->rq_defbuf, serv->sv_bufsz))
 		goto out_thread;
 
-	serv->sv_nrthreads++;
+	atomic_inc(&serv->sv_nrthreads);
 	rqstp->rq_server = serv;
 	error = kernel_thread((int (*)(void *)) func, rqstp, 0);
 	if (error < 0)
diff -u --new-file --exclude-from ../exclude --recursive linux.vanilla/net/sunrpc/svcsock.c linux.14p1/net/sunrpc/svcsock.c
--- linux.vanilla/net/sunrpc/svcsock.c	Wed Oct 20 01:12:52 1999
+++ linux.14p1/net/sunrpc/svcsock.c	Fri Oct 22 21:36:09 1999
@@ -124,7 +124,7 @@
 				"svc_sock_enqueue: server %p, rq_sock=%p!\n",
 				rqstp, rqstp->rq_sock);
 		rqstp->rq_sock = svsk;
-		svsk->sk_inuse++;
+		atomic_inc(&svsk->sk_inuse);
 		wake_up(&rqstp->rq_wait);
 	} else {
 		dprintk("svc: socket %p put into queue\n", svsk->sk_sk);
@@ -148,7 +148,7 @@
 
 	if (svsk) {
 		dprintk("svc: socket %p dequeued, inuse=%d\n",
-			svsk->sk_sk, svsk->sk_inuse);
+			svsk->sk_sk, atomic_read(&svsk->sk_inuse));
 		svsk->sk_qued = 0;
 	}
 
@@ -206,7 +206,7 @@
 		return;
 	svc_release_skb(rqstp);
 	rqstp->rq_sock = NULL;
-	if (!--(svsk->sk_inuse) && svsk->sk_dead) {
+	if (atomic_dec_and_test(&svsk->sk_inuse) && svsk->sk_dead) {
 		dprintk("svc: releasing dead socket\n");
 		sock_release(svsk->sk_sock);
 		kfree(svsk);
@@ -766,7 +766,7 @@
 	start_bh_atomic();
 	if ((svsk = svc_sock_dequeue(serv)) != NULL) {
 		rqstp->rq_sock = svsk;
-		svsk->sk_inuse++;
+		atomic_inc(&svsk->sk_inuse);
 	} else {
 		/* No data pending. Go to sleep */
 		svc_serv_enqueue(serv, rqstp);
@@ -793,7 +793,7 @@
 	end_bh_atomic();
 
 	dprintk("svc: server %p, socket %p, inuse=%d\n",
-		 rqstp, svsk, svsk->sk_inuse);
+		 rqstp, svsk, atomic_read(&svsk->sk_inuse));
 	len = svsk->sk_recvfrom(rqstp);
 	dprintk("svc: got len=%d\n", len);
 
@@ -988,11 +988,12 @@
 		rpc_remove_list(&serv->sv_sockets, svsk);
 	svsk->sk_dead = 1;
 
-	if (!svsk->sk_inuse) {
+	if (!atomic_read(&svsk->sk_inuse)) {
 		sock_release(svsk->sk_sock);
 		kfree(svsk);
 	} else {
-		printk(KERN_NOTICE "svc: server socket destroy delayed\n");
+		printk(KERN_NOTICE "svc: server socket destroy delayed (sk_inuse: %d)\n",
+		       atomic_read(&svsk->sk_inuse));
 		/* svsk->sk_server = NULL; */
 	}
 }
