diff -u --recursive --new-file v1.3.70/linux/CREDITS linux/CREDITS
--- v1.3.70/linux/CREDITS	Sat Mar  2 10:43:20 1996
+++ linux/CREDITS	Mon Mar  4 09:33:51 1996
@@ -344,6 +344,13 @@
 S: Oak Park, Illinois 60302
 S: USA
 
+N: Bob Frey
+E: bobf@advansys.com
+D: AdvanSys SCSI driver
+S: 1150 Ringwood Court
+S: San Jose, California 95131
+S: USA
+
 N: Nigel Gamble
 E: nigel@nrg.org
 E: nigel@sgi.com
@@ -608,6 +615,10 @@
 S: Am Muehlenweg 38
 S: D53424 Remagen
 S: Germany
+
+N: Martin von Loewis
+E: loewis@informatik.hu-berlin.de
+D: script binary format
 
 N: Mark Lord
 E: mlord@pobox.com
diff -u --recursive --new-file v1.3.70/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v1.3.70/linux/Documentation/Configure.help	Sat Mar  2 10:43:20 1996
+++ linux/Documentation/Configure.help	Sat Mar  2 13:18:49 1996
@@ -1654,22 +1654,45 @@
   linux, read the Multiple-Ethernet-mini-HOWTO, available from
   sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
 
-Arcnet support
+ARCnet support
 CONFIG_ARCNET
   If you have a network card of this type, say Y and check out the
-  beautiful poetry in Documentation/networking/arcnet.txt in the
-  kernel source. If you get this driver to work or not, either way,
-  send mail to the author. You might also want to have a look at the
-  Ethernet-HOWTO, available via ftp (user: anonymous) in
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO (even though arcnet is no true
-  ethernet). This driver is also available as a module ( = code which
-  can be inserted in and removed from the running kernel whenever you
-  want). If you want to compile it as a module, say M here and read
-  Documentation/modules.txt as well as
+  (arguably) beautiful poetry in Documentation/networking/arcnet.txt. 
+  You might also want to have a look at the Ethernet-HOWTO, available
+  via ftp (user: anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO
+  (even though ARCnet is not really ethernet). This driver is also
+  available as a module ( = code which can be inserted in and removed
+  from the running kernel whenever you want). If you want to compile it
+  as a module, say M here and read Documentation/modules.txt as well as
   Documentation/networking/net-modules.txt. If you plan to use more
   than one network card under linux, read the
   Multiple-Ethernet-mini-HOWTO, available from
   sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
+  
+Enable arc0e (ARCnet "ether-encap" packet format)
+CONFIG_ARCNET_ETH
+  This allows you to use "ethernet encapsulation" with your ARCnet card
+  via the virtual arc0e device.  You only need arc0e if you want to
+  talk to nonstandard ARCnet software, specifically, DOS/Windows-style
+  "NDIS" drivers.  You do not need to enable this option to communicate
+  with industry-standard RFC1201 implementations, like the arcether.com
+  packet driver or most DOS/Windows ODI drivers.  RFC1201 is included
+  automatically as the arc0 device.  Please read the ARCnet
+  documentation in Documentation/networking/arcnet.txt for more
+  information about using arc0e and arc0s.
+
+Enable arc0s (ARCnet RFC1051 packet format)
+CONFIG_ARCNET_1051
+  This allows you to use RFC1051 with your ARCnet card via the virtual
+  arc0s device.  You only need arc0s if you want to talk to ARCnet
+  software complying with the "old" standard, specifically, the DOS
+  arcnet.com packet driver, Amigas running AmiTCP, and some variants of
+  NetBSD.  You do not need to enable this option to communicate with
+  industry-standard RFC1201 implementations, like the arcether.com
+  packet driver or most DOS/Windows ODI drivers.  RFC1201 is included
+  automatically as the arc0 device.  Please read the ARCnet
+  documentation in Documentation/networking/arcnet.txt for more
+  information about using arc0e and arc0s.
 
 Cabletron E21xx support
 CONFIG_E2100
diff -u --recursive --new-file v1.3.70/linux/Documentation/devices.tex linux/Documentation/devices.tex
--- v1.3.70/linux/Documentation/devices.tex	Sat Mar  2 10:43:20 1996
+++ linux/Documentation/devices.tex	Sun Mar  3 09:51:40 1996
@@ -41,8 +41,8 @@
  {\end{tabbing}}
 %
 \title{{\bf Linux Allocated Devices}}
-\author{Maintained by H. Peter Anvin $<$hpa@storm.net$>$}
-\date{Last revised: February 24, 1996}
+\author{Maintained by H. Peter Anvin $<$hpa@zytor.com$>$}
+\date{Last revised: March 2, 1996}
 \maketitle
 %
 \noindent
@@ -88,12 +88,13 @@
 \major{ 5}{}{char }{Alternate TTY devices}
 \major{ 6}{}{char }{Parallel printer devices}
 \major{ 7}{}{char }{Virtual console access devices}
-\major{  }{}{block}{Loopback devices}
 \major{ 8}{}{block}{SCSI disk devices}
 \major{ 9}{}{char }{SCSI tape devices}
 \major{  }{}{block}{Metadisk (RAID) devices}
 \major{10}{}{char }{Non-serial mice, misc features}
-\major{11}{}{block}{SCSI CD-ROM devices}
+\major{  }{}{block}{Loopback devices}
+\major{11}{}{char }{Raw keyboard device}
+\major{  }{}{block}{SCSI CD-ROM devices}
 \major{12}{}{char }{QIC-02 tape}
 \major{  }{}{block}{MSCDEX CD-ROM callback support}
 \major{13}{}{char }{PC speaker}
@@ -352,17 +353,6 @@
 \noindent
 NOTE: These devices permit both read and write access.
 
-\major{  }{}{block}{Loopback devices}
-	\minor{0}{/dev/loop0}{First loopback device}
-	\minor{1}{/dev/loop1}{Second loopback device}
-	\minordots
-\end{devicelist}
-
-\noindent
-The loopback devices are used to mount filesystems not associated with
-block devices.  The binding to the loopback devices is usually handled
-by mount(1).
-
 \begin{devicelist}
 \major{ 8}{}{block}{SCSI disk devices}
 	\minor{0}{/dev/sda}{First SCSI disk whole disk}
@@ -403,18 +393,37 @@
 	\minor{2}{/dev/inportbm}{Microsoft Inport bus mouse}
 	\minor{3}{/dev/atibm}{ATI XL bus mouse}
 	\minor{4}{/dev/jbm}{J-mouse}
-	\minor{4}{/dev/amigamouse}{Amiga Mouse (68k/Amiga)}
-	\minor{5}{/dev/atarimouse}{Atari Mouse}
+	\minor{4}{/dev/amigamouse}{Amiga mouse (68k/Amiga)}
+	\minor{5}{/dev/atarimouse}{Atari mouse}
+	\minor{6}{/dev/sunmouse}{Sun mouse}
 	\minor{128}{/dev/beep}{Fancy beep device}
 	\minor{129}{/dev/modreq}{Kernel module load request}
 	\minor{130}{/dev/watchdog}{Watchdog timer port}
 	\minor{131}{/dev/temperature}{Machine internal temperature}
 	\minor{132}{/dev/hwtrap}{Hardware fault trap}
 	\minor{133}{/dev/exttrp}{External device trap}
+\\
+\major{  }{}{block}{Loopback devices}
+	\minor{0}{/dev/loop0}{First loopback device}
+	\minor{1}{/dev/loop1}{Second loopback device}
+	\minordots
+\end{devicelist}
+
+\noindent
+The loopback devices are used to mount filesystems not associated with
+block devices.  The binding to the loopback devices is usually handled
+by mount(1).
+
+\begin{devicelist}
+\major{11}{}{char }{Raw keyboard device}
+	\minor{0}{/dev/kbd}{Raw keyboard device}
 \end{devicelist}
 
+\noindent
+The raw keyboard device is used on Linux/SPARC only.
+
 \begin{devicelist}
-\major{11}{}{block}{SCSI CD-ROM devices}
+\major{  }{}{block}{SCSI CD-ROM devices}
 	\minor{0}{/dev/sr0}{First SCSI CD-ROM}
 	\minor{1}{/dev/sr1}{Second SCSI CD-ROM}
 	\minordots
@@ -693,12 +702,12 @@
 
 \begin{devicelist}
 \major{29}{}{char }{Universal frame buffer}
-	\minor{0}{/dev/fb0current}{First frame buffer}
+	\minor{0}{/dev/fb0}{First frame buffer}
 	\minor{1}{/dev/fb0autodetect}{}
 	\minor{24}{/dev/fb0user0}{}
 	\minordots
 	\minor{31}{/dev/fb0user7}{}
-	\minor{32}{/dev/fb1current}{Second frame buffer}
+	\minor{32}{/dev/fb1}{Second frame buffer}
 	\minor{33}{/dev/fb1autodetect}{}
 	\minor{56}{/dev/fb1user0}{}
 	\minordots
@@ -708,13 +717,15 @@
 
 \noindent
 The universal frame buffer device is currently supported only on
-Linux/68k.  The {\file current} device accesses the frame buffer at
-current resolution; the {\file autodetect} one at bootup (default)
-resolution.  Minor numbers 2--23 within each frame buffer assignment
-are used for specific device-dependent resolutions.  There appears to
-be no standard naming for these devices.  Finally, 24--31 within each
-device are reserved for user-selected modes, usually entered at boot
-time.
+Linux/68k and Linux/SPARC.  The plain device accesses the frame
+buffer at current resolution (Linux/68k calls this file {\file
+current}, e.g. {\file /dev/fb0current}); the {\file autodetect} one at
+bootup (default) resolution.  Minor numbers 2--23 within each frame
+buffer assignment are used for specific device-dependent resolutions.
+There appears to be no standard naming for these devices.  Finally,
+24--31 within each device are reserved for user-selected modes,
+usually entered at boot time.  Currently only Linux/68k uses the
+mode-specific devices.
 
 \begin{devicelist}
 \major{  }{}{block}{Aztech/Orchid/Okano/Wearnes CD-ROM}
@@ -1057,7 +1068,7 @@
 /dev/scanner} should point to the appropriate generic SCSI devices
 ({\file /dev/sg*}.)
 
-{\file /dev/mouse} may point to a dialout (alternate) TTY device, a
+{\file /dev/mouse} may point to a primary serial TTY device, a
 hardware mouse device, or a socket for a mouse driver program
 (e.g. {\file /dev/gpmdata}.)
 
diff -u --recursive --new-file v1.3.70/linux/Documentation/devices.txt linux/Documentation/devices.txt
--- v1.3.70/linux/Documentation/devices.txt	Sat Mar  2 10:43:20 1996
+++ linux/Documentation/devices.txt	Sun Mar  3 09:51:40 1996
@@ -1,8 +1,8 @@
 		       LINUX ALLOCATED DEVICES
 
-	     Maintained by H. Peter Anvin <hpa@storm.net>
+	     Maintained by H. Peter Anvin <hpa@zytor.com>
 
-		   Last revised: February 24, 1996
+		     Last revised: March 2, 1996
 
 This list is the successor to Rick Miller's Linux Device List, which
 he stopped maintaining when he got busy with other things in 1993.  It
@@ -131,7 +131,7 @@
 		  1 = /dev/hd?1		First partition
 		  2 = /dev/hd?2		Second partition
 		    ...
-		 63 = /dev/hd?63	63rd logical partition
+		 63 = /dev/hd?63	63rd partition
 
 		For Linux/i386, partitions 1-4 are the primary
 		partitions, and 5 and above are logical partitions.
@@ -187,15 +187,6 @@
 	
 		NOTE: These devices permit both read and write access.
 
-    block	Loopback devices
-		  0 = /dev/loop0	First loopback device
-		  1 = /dev/loop1	Second loopback device
-		      ...
-
-		The loopback devices are used to mount filesystems not
-		associated with block devices.  The binding to the
-		loopback devices is usually handled by mount(1).
-
   8 block	SCSI disk devices
     		  0 = /dev/sda		First SCSI disk whole disk
 		 16 = /dev/sdb		Second SCSI disk whole disk
@@ -228,8 +219,9 @@
 		  2 = /dev/inportbm	Microsoft Inport bus mouse
 		  3 = /dev/atibm	ATI XL bus mouse
 		  4 = /dev/jbm		J-mouse
-		  4 = /dev/amigamouse	Amiga Mouse (68k/Amiga)
-		  5 = /dev/atarimouse	Atari Mouse
+		  4 = /dev/amigamouse	Amiga mouse (68k/Amiga)
+		  5 = /dev/atarimouse	Atari mouse
+		  6 = /dev/sunmouse	Sun mouse
 		128 = /dev/beep		Fancy beep device
 		129 = /dev/modreq	Kernel module load request
 		130 = /dev/watchdog	Watchdog timer port
@@ -237,7 +229,21 @@
 		132 = /dev/hwtrap	Hardware fault trap
 		133 = /dev/exttrp	External device trap
 
- 11 block	SCSI CD-ROM devices
+    block	Loopback devices
+		  0 = /dev/loop0	First loopback device
+		  1 = /dev/loop1	Second loopback device
+		      ...
+
+		The loopback devices are used to mount filesystems not
+		associated with block devices.  The binding to the
+		loopback devices is usually handled by mount(1).
+
+ 11 char	Raw keyboard device
+		  0 = /dev/kbd		Raw keyboard device
+
+		The raw keyboard device is used on Linux/SPARC only.
+
+    block	SCSI CD-ROM devices
     		  0 = /dev/sr0		First SCSI CD-ROM
 		  1 = /dev/sr1		Second SCSI CD-ROM
 		      ...
@@ -450,28 +456,32 @@
 		partitions is 15, like SCSI.
 
  29 char	Universal frame buffer
-		  0 = /dev/fb0current	First frame buffer
+		  0 = /dev/fb0		First frame buffer
 		  1 = /dev/fb0autodetect
 		 24 = /dev/fb0user0
 	              ...
 		 31 = /dev/fb0user7
-		 32 = /dev/fb1current	Second frame buffer
+		 32 = /dev/fb1		Second frame buffer
 		 33 = /dev/fb1autodetect
 		 56 = /dev/fb1user0
 		      ...
 		 63 = /dev/fb1user7
-    block	Aztech/Orchid/Okano/Wearnes CD-ROM
-		  0 = /dev/aztcd	Aztech CD-ROM
 
 		The universal frame buffer device is currenly only
-		supported on Linux/68k.  The "current" device accesses
-		the fame buffer at current resolution; the
-		"autodetect" one at bootup (default) resolution.
-		Minor numbers 2-23 within each frame buffer assignment
-		are used for specific device-dependent resolutions.
-		There appears to be no standard naming for these devices.
-		Finally, 2-31 within each device are reserved for
-		user-selected modes, usually entered at boot time.
+		supported on Linux/68k and Linux/SPARC.  The plain
+		device accesses the frame buffer at current resolution
+		(Linux/68k calls this device "current",
+		e.g. /dev/fb0current); the "autodetect" one at bootup
+		(default) resolution.  Minor numbers 2-23 within each
+		frame buffer assignment are used for specific
+		device-dependent resolutions.  There appears to be no
+		standard naming for these devices.  Finally, 2-31
+		within each device are reserved for user-selected
+		modes, usually entered at boot time.  Currently only
+		Linux/68k uses the mode-specific devices.
+
+    block	Aztech/Orchid/Okano/Wearnes CD-ROM
+		  0 = /dev/aztcd	Aztech CD-ROM
 
  30 char	iBCS-2 compatibility devices
 		  0 = /dev/socksys	Socket access
@@ -615,6 +625,7 @@
 		 49 = /dev/ml16pb-c0	Second card, first counter/timer
 		 50 = /dev/ml16pb-c1	Second card, second counter/timer
 		 51 = /dev/ml16pb-c2	Second card, third counter/timer
+		      ...
 
  40		UNALLOCATED
 
@@ -732,8 +743,8 @@
 /dev/cdwriter and /dev/scanner should point to the appropriate generic
 SCSI devices (/dev/sg*).
 
-/dev/mouse may point to a dialout (alternate) TTY device, a hardware
-mouse device, or a socket for a mouse driver program (e.g. /dev/gpmdata).
+/dev/mouse may point to a primary serial TTY device, a hardware mouse
+device, or a socket for a mouse driver program (e.g. /dev/gpmdata).
 
 	Sockets and pipes
 
diff -u --recursive --new-file v1.3.70/linux/Documentation/unicode.txt linux/Documentation/unicode.txt
--- v1.3.70/linux/Documentation/unicode.txt	Tue Nov 21 13:22:04 1995
+++ linux/Documentation/unicode.txt	Sat Mar  2 13:18:47 1996
@@ -53,7 +53,7 @@
 
 Unfortunately, Unicode/ISO 10646 does not allocate code points for the
 language Klingon, probably fearing the potential code point explosion
-if many fictional lanugages were submitted for inclusion.  There are
+if many fictional languages were submitted for inclusion.  There are
 also political reasons (the Japanese, for example, are not too happy
 about the whole 16-bit concept to begin with.)  However, with Linux
 being a hacker-driven OS it seems this is a brilliant linguistic hack
diff -u --recursive --new-file v1.3.70/linux/MAGIC linux/MAGIC
--- v1.3.70/linux/MAGIC	Wed Feb 28 11:49:59 1996
+++ linux/MAGIC	Mon Mar  4 11:25:48 1996
@@ -80,6 +80,7 @@
 'C'	linux/soundcard.h
 'I'	linux/isdn.h
 'K'	linux/kd.h
+'L'	linux/loop.h
 'M'	linux/soundcard.h
 'P'	linux/soundcard.h
 'Q'	linux/soundcard.h
diff -u --recursive --new-file v1.3.70/linux/Makefile linux/Makefile
--- v1.3.70/linux/Makefile	Sat Mar  2 10:43:20 1996
+++ linux/Makefile	Sun Mar  3 09:22:24 1996
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 3
-SUBLEVEL = 70
+SUBLEVEL = 71
 
 ARCH = i386
 
@@ -196,7 +196,6 @@
 menuconfig: include/linux/version.h symlinks 
 	$(MAKE) -C scripts/lxdialog all
 	$(CONFIG_SHELL) scripts/Menuconfig arch/$(ARCH)/config.in
-	
 
 config: symlinks
 	$(CONFIG_SHELL) scripts/Configure arch/$(ARCH)/config.in
@@ -314,7 +313,7 @@
 
 clean:	archclean
 	rm -f kernel/ksyms.lst include/linux/compile.h
-	rm -f core `find . -name '*.[oas]' ! -regex '.*lxdialog' -print`
+	rm -f core `find . -name '*.[oas]' ! -regex '.*lxdialog/.*' -print`
 	rm -f core `find . -type f -name 'core' -print`
 	rm -f vmlinux System.map
 	rm -f .tmp* drivers/sound/configure
@@ -329,7 +328,7 @@
 	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
-	rm -f .menuconfig.in
+	rm -f .menuconfig .menuconfig.log
 	rm -f include/asm
 	rm -f .depend `find . -name .depend -print`
 	rm -f .hdepend
diff -u --recursive --new-file v1.3.70/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S
--- v1.3.70/linux/arch/alpha/kernel/entry.S	Sat Feb 17 16:02:44 1996
+++ linux/arch/alpha/kernel/entry.S	Mon Mar  4 11:46:31 1996
@@ -639,7 +639,7 @@
 	.quad sys_fsync, sys_setpriority, sys_socket, sys_connect, sys_accept
 /*100*/	.quad osf_getpriority, sys_send, sys_recv, sys_sigreturn, sys_bind
 	.quad sys_setsockopt, sys_listen, do_entSys, do_entSys, do_entSys
-	.quad do_entSys, sys_sigsuspend, do_entSys, do_entSys, do_entSys
+	.quad do_entSys, sys_sigsuspend, do_entSys, sys_recvmsg, sys_sendmsg
 	.quad do_entSys, sys_gettimeofday, sys_getrusage, sys_getsockopt, do_entSys
 	.quad sys_readv, sys_writev, sys_settimeofday, sys_fchown, sys_fchmod
 	.quad sys_recvfrom, sys_setreuid, sys_setregid, sys_rename, sys_truncate
@@ -686,5 +686,5 @@
 	.quad sys_setfsuid, sys_setfsgid, sys_ustat, sys_statfs, sys_fstatfs
 	.quad sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler, sys_sched_yield
 	.quad sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, do_entSys /* sys_afs_syscall */, sys_newuname
-	.quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
+	.quad sys_nanosleep, do_entSys, do_entSys, do_entSys, do_entSys
 	.quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
diff -u --recursive --new-file v1.3.70/linux/arch/alpha/kernel/irq.c linux/arch/alpha/kernel/irq.c
--- v1.3.70/linux/arch/alpha/kernel/irq.c	Sat Mar  2 10:43:21 1996
+++ linux/arch/alpha/kernel/irq.c	Mon Mar  4 11:47:36 1996
@@ -32,85 +32,95 @@
 static unsigned char cache_A1 = 0xff;
 
 #if NR_IRQS == 33
-  static unsigned char cache_804 = 0xef;
-  static unsigned char cache_805 = 0xff;
-  static unsigned char cache_806 = 0xff;
+  static unsigned int  cache_804 = 0x00ffffef;
 #elif NR_IRQS == 32
   static unsigned char cache_26 = 0xdf;
   static unsigned char cache_27 = 0xff;
 #endif
 
-void disable_irq(unsigned int irq_nr)
+static void mask_irq(int irq)
 {
-	unsigned long flags;
-	unsigned char mask;
-
-	save_flags(flags);
-	cli();
-	mask = 1 << (irq_nr & 7);
+	unsigned long mask;
 
-	if (irq_nr < 8) {
-		cache_21 |= mask;
-		outb(cache_21,0x21);
-	} else if (irq_nr < 16) {
-		cache_A1 |= mask;
-		outb(cache_A1,0xA1);
+	if (irq < 16) {
+		mask = 1 << (irq & 7);
+		if (irq < 8) {
+			cache_21 |= mask;
+			outb(cache_21, 0x21);
+		} else {
+			cache_A1 |= mask;
+			outb(cache_A1, 0xA1);
+		}
 #if NR_IRQS == 33
-	} else if (irq_nr < 24) {
-		cache_804 |= mask;
-		outb(cache_804, 0x804);
-	} else if (irq_nr < 32) {
-		cache_805 |= mask;
-		outb(cache_805, 0x805);
 	} else {
-		cache_806 |= mask;
-		outb(cache_806, 0x806);
-#elif NR_IRQS == 32 
-	} else if (irq_nr < 24) {
-		cache_26 |= mask;
-		outb(cache_26, 0x26);
+		mask = 1 << (irq - 16);
+		cache_804 |= mask;
+		outl(cache_804, 0x804);
+#elif NR_IRQS == 32
 	} else {
-		cache_27 |= mask;
-		outb(cache_27, 0x27);
+		mask = 1 << (irq & 7);
+		if (irq < 24) {
+			cache_26 |= mask;
+			outb(cache_26, 0x26);
+		} else {
+			cache_27 |= mask;
+			outb(cache_27, 0x27);
+		}
 #endif
 	}
-	restore_flags(flags);
 }
 
-void enable_irq(unsigned int irq_nr)
+static void unmask_irq(unsigned long irq)
 {
-	unsigned long flags;
-	unsigned char mask;
-
-	mask = ~(1 << (irq_nr & 7));
-	save_flags(flags);
-	cli();
+	unsigned long mask;
 
-	if (irq_nr < 8) {
-		cache_21 &= mask;
-		outb(cache_21,0x21);
-	} else if (irq_nr < 16) {
-		cache_A1 &= mask;
-		outb(cache_A1,0xA1);
+	if (irq < 16) {
+		mask = ~(1 << (irq & 7));
+		if (irq < 8) {
+			cache_21 &= mask;
+			outb(cache_21, 0x21);
+		} else {
+			cache_A1 &= mask;
+			outb(cache_A1, 0xA1);
+		}
 #if NR_IRQS == 33
-	} else if (irq_nr < 24) {
-		cache_804 &= mask;
-		outb(cache_804, 0x804);
-	} else if (irq_nr < 32) {
-		cache_805 &= mask;
-		outb(cache_805, 0x805);
 	} else {
-		cache_806 &= mask;
-		outb(cache_806, 0x806);
+		mask = ~(1 << (irq - 16));
+		cache_804 &= mask;
+		outl(cache_804, 0x804);
 #elif NR_IRQS == 32
-	} else if (irq_nr < 24) {
-		cache_26 &= mask;
-		outb(cache_26, 0x26);
 	} else {
-		cache_27 &= mask;
-		outb(cache_27, 0x27);
+		mask = ~(1 << (irq & 7));
+
+		if (irq < 24) {
+			cache_26 &= mask;
+			outb(cache_26, 0x26);
+		} else {
+			cache_27 &= mask;
+			outb(cache_27, 0x27);
+		}
 #endif
 	}
+}
+
+void disable_irq(unsigned int irq_nr)
+{
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	mask_irq(irq_nr);
+	restore_flags(flags);
+}
+
+void enable_irq(unsigned int irq_nr)
+{
+	unsigned long flags, mask;
+
+	mask = ~(1 << (irq_nr & 7));
+	save_flags(flags);
+	cli();
+	unmask_irq(irq_nr);
 	restore_flags(flags);
 }
 
@@ -125,7 +135,7 @@
 	struct irqaction * action;
 
 	for (i = 0 ; i < NR_IRQS ; i++) {
-	        action = *(i + irq_action);
+	        action = irq_action[i];
 		if (!action) 
 		        continue;
 		len += sprintf(buf+len, "%2d: %8d %c %s",
@@ -156,69 +166,6 @@
 	}
 }
 
-static inline void mask_irq(int irq)
-{
-	unsigned char mask;
-
-	mask = 1 << (irq & 7);
-	if (irq < 8) {
-		cache_21 |= mask;
-		outb(cache_21, 0x21);
-	} else if (irq < 16) {
-		cache_A1 |= mask;
-		outb(cache_A1, 0xA1);
-#if NR_IRQS == 33
-	} else if (irq < 24) {
-		cache_804 |= mask;
-		outb(cache_804, 0x804);
-	} else if (irq < 32) {
-	        cache_805 |= mask;
-		outb(cache_805, 0x805);
-	} else {
-		cache_806 |= mask;
-		outb(cache_806, 0x806);
-#elif NR_IRQS == 32
-	} else if (irq < 24) {
-		cache_26 |= mask;
-		outb(cache_26, 0x26);
-	} else {
-		cache_27 |= mask;
-		outb(cache_27, 0x27);
-#endif
-	}
-}
-
-static inline void unmask_irq(unsigned long irq)
-{
-	unsigned char mask = ~(1 << (irq & 7));
-
-	if (irq < 8) {
-		cache_21 &= mask;
-		outb(cache_21, 0x21);
-	} else if (irq < 16) {
-		cache_A1 &= mask;
-		outb(cache_A1, 0xA1);
-#if NR_IRQS == 33
-	} else if (irq < 24) {
-		cache_804 &= mask;
-		outb(cache_804, 0x804);
-	} else if (irq < 32) {
-	        cache_805 &= mask;
-		outb(cache_805, 0x805);
-	} else {
-		cache_806 &= mask;
-		outb(cache_806, 0x806);
-#elif NR_IRQS == 32
-	} else if (irq < 24) {
-		cache_26 &= mask;
-		outb(cache_26, 0x26);
-	} else {
-		cache_27 &= mask;
-		outb(cache_27, 0x27);
-#endif
-	}
-}
-
 int request_irq(unsigned int irq, 
 		void (*handler)(int, void *, struct pt_regs *),
 		unsigned long irqflags, 
@@ -235,7 +182,7 @@
 		return -EINVAL;
 	if (!handler)
 	    return -EINVAL;
-	action = *(irq + irq_action);
+	action = irq_action[irq];
 	if (action) {
 	    if ((action->flags & SA_SHIRQ) && (irqflags & SA_SHIRQ)) {
 		for (tmp = action; tmp->next; tmp = tmp->next);
@@ -265,7 +212,7 @@
 	if (tmp) {
 	    tmp->next = action;
 	} else {
-	    *(irq + irq_action) = action;
+	    irq_action[irq] = action;
 	    enable_irq(irq);
 	    if (irq >= 8 && irq < 16) {
 		enable_irq(2);	/* ensure cascade is enabled too */
@@ -278,7 +225,7 @@
 
 void free_irq(unsigned int irq, void *dev_id)
 {
-	struct irqaction * action = *(irq + irq_action);
+	struct irqaction * action = irq_action[irq];
 	struct irqaction * tmp = NULL;
 	unsigned long flags;
 
@@ -286,7 +233,7 @@
 		printk("Trying to free IRQ%d\n", irq);
 		return;
 	}
-	if (!action->handler) {
+	if (!action || !action->handler) {
 		printk("Trying to free free IRQ%d\n", irq);
 		return;
 	}
@@ -308,11 +255,11 @@
 	if (action && tmp) {
 	    tmp->next = action->next;
 	} else {
-	    *(irq + irq_action) = action->next;
+	    irq_action[irq] = action->next;
 	}
 	kfree_s(action, sizeof(struct irqaction));
 
-	if (!(*(irq + irq_action))) {
+	if (!irq_action[irq]) {
 	    mask_irq(irq);
 	}
 
@@ -325,7 +272,7 @@
 	printk("61=%02x, 461=%02x\n", inb(0x61), inb(0x461));
 }
 
-static void unexpected_irq(int irq, void *dev_id, struct pt_regs * regs)
+static void unexpected_irq(int irq, struct pt_regs * regs)
 {
 	struct irqaction *action;
 	int i;
@@ -334,7 +281,7 @@
 	printk("PC = %016lx PS=%04lx\n", regs->pc, regs->ps);
 	printk("Expecting: ");
 	for (i = 0; i < 16; i++)
-	        if ((action = *(i + irq_action)))
+	        if ((action = irq_action[i]))
 		        while (action->handler) {
 			        printk("[%s:%d] ", action->name, i);
 				action = action->next;
@@ -352,17 +299,17 @@
 
 static inline void handle_irq(int irq, void *dev_id, struct pt_regs * regs)
 {
-	struct irqaction * action = *(irq + irq_action);
+	struct irqaction * action = irq_action[irq];
 
 	kstat.interrupts[irq]++;
 	if (!action) {
-	    unexpected_irq(irq, action->dev_id, regs);
+	    unexpected_irq(irq, regs);
 	    return;
 	}
-	while (action) {
+	do {
 	    action->handler(irq, action->dev_id, regs);
 	    action = action->next;
-	}
+	} while (action);
 }
 
 static inline void device_interrupt(int irq, int ack, struct pt_regs * regs)
@@ -375,17 +322,17 @@
 	}
 
 	kstat.interrupts[irq]++;
-	action = *(irq_action + irq);
-	if (action->flags & SA_SAMPLE_RANDOM)
-		add_interrupt_randomness(irq);
-	/* quick interrupts get executed with no extra overhead */
-	if (action->flags & SA_INTERRUPT) {
-	        while (action) {
-		        action->handler(irq, action->dev_id, regs);
-		        action = action->next;
-	        }
-		ack_irq(ack);
-		return;
+	action = irq_action[irq];
+	if (action) {
+		/* quick interrupts get executed with no extra overhead */
+		if (action->flags & SA_INTERRUPT) {
+		        while (action) {
+			        action->handler(irq, action->dev_id, regs);
+			        action = action->next;
+		        }
+			ack_irq(ack);
+			return;
+		}
 	}
 	/*
 	 * For normal interrupts, we mask it out, and then ACK it.
@@ -400,9 +347,11 @@
 	ack_irq(ack);
 	if (!action)
 		return;
+	if (action->flags & SA_SAMPLE_RANDOM)
+		add_interrupt_randomness(irq);
 	while (action) {
-	    action->handler(irq, action->dev_id, regs);
-	    action = action->next;
+		action->handler(irq, action->dev_id, regs);
+		action = action->next;
 	}
 	unmask_irq(ack);
 }
@@ -609,8 +558,8 @@
 	unsigned int i;
 
 	for (i = NR_IRQS - 1; i > 0; i--) {
-	        action = *(i + irq_action);
-		if (!action->handler) {
+	        action = irq_action[i];
+		if (!action) {
 			enable_irq(i);
 			irqs |= (1 << i);
 		}
@@ -623,9 +572,7 @@
 	/* now filter out any obviously spurious interrupts */
 	irqmask = (((unsigned long)cache_A1)<<8) | (unsigned long) cache_21;
 #if NR_IRQS == 33
-	irqmask |= ((((unsigned long)cache_804)<<16) |
-		    (((unsigned long)cache_805)<<24) |
-		    (((unsigned long)cache_806)<<24));
+	irqmask |= (unsigned long) cache_804 << 16;
 #elif NR_IRQS == 32
 	irqmask |= ((((unsigned long)cache_26)<<16) |
 		    (((unsigned long)cache_27)<<24));
@@ -646,9 +593,7 @@
 	
 	irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
 #if NR_IRQS == 33
-	irqmask |= ((((unsigned long)cache_804)<<16) |
-		    (((unsigned long)cache_805)<<24) |
-		    (((unsigned long)cache_806)<<24));
+	irqmask |= (unsigned long) cache_804 << 16;
 #elif NR_IRQS == 32
 	irqmask |= ((((unsigned long)cache_26)<<16) |
 		    (((unsigned long)cache_27)<<24));
@@ -729,9 +674,7 @@
 	dma_outb(0, DMA1_CLR_MASK_REG);
 	dma_outb(0, DMA2_CLR_MASK_REG);
 #if NR_IRQS == 33
-	outb(cache_804, 0x804);
-	outb(cache_805, 0x805);
-	outb(cache_806, 0x806);
+	outl(cache_804, 0x804);
 #elif NR_IRQS == 32
 	outb(cache_26, 0x26);
 	outb(cache_27, 0x27);
diff -u --recursive --new-file v1.3.70/linux/arch/alpha/kernel/ksyms.c linux/arch/alpha/kernel/ksyms.c
--- v1.3.70/linux/arch/alpha/kernel/ksyms.c	Sat Feb 17 16:02:45 1996
+++ linux/arch/alpha/kernel/ksyms.c	Mon Mar  4 11:46:31 1996
@@ -49,6 +49,8 @@
 	X(strncpy),
 	X(strnlen),
 	X(strstr),
+	X(strtok),
+	X(strchr),
 	X(hwrpb),
 	X(memcmp),
 	X(memmove),
@@ -72,6 +74,9 @@
 	XNOVERS(__remlu),
 	XNOVERS(__remq),
 	XNOVERS(__remqu),
+	XNOVERS(memcpy),
+	XNOVERS(memset),
+	/* these shouldn't be necessary---they should be versioned: */
 	XNOVERS(__memcpy),
 	XNOVERS(__memset),
 #include <linux/symtab_end.h>
diff -u --recursive --new-file v1.3.70/linux/arch/alpha/math-emu/fp-emul.c linux/arch/alpha/math-emu/fp-emul.c
--- v1.3.70/linux/arch/alpha/math-emu/fp-emul.c	Sat Jan  6 19:10:38 1996
+++ linux/arch/alpha/math-emu/fp-emul.c	Mon Mar  4 11:46:31 1996
@@ -32,10 +32,10 @@
  */
 #define FLTI_FUNC_ADDS			0x000
 #define FLTI_FUNC_ADDT			0x020
-#define FLTI_FUNC_CMPTEQ		0x0a5
-#define FLTI_FUNC_CMPTLT		0x0a6
-#define FLTI_FUNC_CMPTLE		0x0a7
-#define FLTI_FUNC_CMPTUN		0x0a4
+#define FLTI_FUNC_CMPTEQ		0x025
+#define FLTI_FUNC_CMPTLT		0x026
+#define FLTI_FUNC_CMPTLE		0x027
+#define FLTI_FUNC_CMPTUN		0x024
 #define FLTI_FUNC_CVTTS_or_CVTST	0x02c
 #define FLTI_FUNC_CVTTQ			0x02f
 #define FLTI_FUNC_CVTQS			0x03c
@@ -288,8 +288,8 @@
 		break;
 
 	      default:
-		printk("alpha_fp_emul: unexpected function code %#lx at %#lx",
-		       opcode, pc);
+		printk("alpha_fp_emul: unexpected function code %#lx at %#lx\n",
+		       func & 0x3f, pc);
 		return 0;
 	}
 	/*
diff -u --recursive --new-file v1.3.70/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c
--- v1.3.70/linux/arch/i386/kernel/smp.c	Sat Mar  2 10:43:21 1996
+++ linux/arch/i386/kernel/smp.c	Mon Mar  4 09:16:35 1996
@@ -7,8 +7,8 @@
  *	Much of the core SMP work is based on previous work by Thomas Radke, to
  *	whom a great many thanks are extended.
  *
- *	Thanks to Intel for testing against several Pentium and Pentium Pro
- *	MP machines.
+ *	Thanks to Intel for making available several different Pentium and
+ *	Pentium Pro MP machines.
  *
  *	This code is released under the GNU public license version 2 or
  *	later.
@@ -543,7 +543,7 @@
 	 *	Map the local APIC into kernel space
 	 */
 
-	apic_reg = vremap(0xFEE00000,4096);
+	apic_reg = vremap(apic_addr,4096);
 	
 	if(apic_reg == NULL)
 		panic("Unable to map local apic.\n");
@@ -638,17 +638,19 @@
 			 *	Install a writable page 0 entry.
 			 */
 			 
+			cfg=pg0[0];
+			
 			CMOS_WRITE(0xa, 0xf);
 			pg0[0]=7;
 			local_invalidate();
-			*((volatile unsigned short *) 0x467) = ((unsigned long)stack)>>4;
-			*((volatile unsigned short *) 0x469) = 0;
+			*((volatile unsigned short *) 0x469) = ((unsigned long)stack)>>4;
+			*((volatile unsigned short *) 0x467) = 0;
 			
 			/*
 			 *	Protect it again
 			 */
 			 
-			pg0[0]= pte_val(mk_pte(0, PAGE_READONLY));
+			pg0[0]= cfg;
 			local_invalidate();
 
 			/*
@@ -1048,7 +1050,7 @@
  *	Reschedule call back
  */
 
-void smp_reschedule_irq(int cpl, void *dev_id, struct pt_regs *regs)
+void smp_reschedule_irq(int cpl, struct pt_regs *regs)
 {
 #ifdef DEBUGGING_SMP_RESCHED
 	static int ct=0;
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/boot/bare.S linux/arch/sparc/boot/bare.S
--- v1.3.70/linux/arch/sparc/boot/bare.S	Sat Nov 25 19:04:36 1995
+++ linux/arch/sparc/boot/bare.S	Mon Mar  4 08:49:53 1996
@@ -1,4 +1,4 @@
-/* $Id: bare.S,v 1.2 1995/11/25 00:57:39 davem Exp $
+/* $Id: bare.S,v 1.3 1995/11/27 02:42:50 davem Exp $
  * base.S:      Ugly low-level boot program entry code.  The job of this
  *              module is to parse the boot flags, try to mount the remote
  *              root filesystem and load the kernel into virtual memory.
@@ -51,7 +51,7 @@
 start_of_execution:
 	sethi	%hi(C_LABEL(first_adr_in_text)), %o1		! This is our top
 	or	%o1, %lo(C_LABEL(first_adr_in_text)), %o1	! of stack too.
-	sub	%o1, STACKFRAME_SZ, %o1
+	sub	%o1, REGWIN_SZ, %o1
 	add	%o1, 0x7, %o1
 	andn	%o1, 0x7, %o1
 	save	%o1, 0x0, %sp					! save is an add
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/config.in linux/arch/sparc/config.in
--- v1.3.70/linux/arch/sparc/config.in	Fri Feb  9 17:52:58 1996
+++ linux/arch/sparc/config.in	Mon Mar  4 08:49:54 1996
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.5 1995/11/25 00:57:32 davem Exp $
+# $Id: config.in,v 1.8 1996/03/01 07:15:47 davem Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
@@ -10,14 +10,16 @@
 # Global things across all Sparc machines.
 define_bool CONFIG_SBUS y
 define_bool CONFIG_SUN_MOUSE y
+define_bool CONFIG_SERIAL y
 define_bool CONFIG_SUN_SERIAL y
 define_bool CONFIG_SUN_KEYBOARD y
 define_bool CONFIG_SUN_CONSOLE y
+define_bool CONFIG_NET_ALIAS n
+define_bool CONFIG_BINFMT_AOUT y
 
 bool 'Networking support' CONFIG_NET
 bool 'System V IPC' CONFIG_SYSVIPC
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
-tristate 'Kernel support for A.OUT binaries' CONFIG_BINFMT_AOUT
 endmenu
 
 source drivers/block/Config.in
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/defconfig linux/arch/sparc/defconfig
--- v1.3.70/linux/arch/sparc/defconfig	Fri Feb  9 17:52:58 1996
+++ linux/arch/sparc/defconfig	Mon Mar  4 08:49:54 1996
@@ -10,13 +10,14 @@
 CONFIG_SUN_SERIAL=y
 CONFIG_SUN_KEYBOARD=y
 CONFIG_SUN_CONSOLE=y
+# CONFIG_NET_ALIAS is not set
+CONFIG_BINFMT_AOUT=y
 CONFIG_NET=y
 CONFIG_SYSVIPC=y
 # CONFIG_BINFMT_ELF is not set
-CONFIG_BINFMT_AOUT=y
 
 #
-# block devices
+# Floppy, IDE, and other block devices
 #
 # CONFIG_BLK_DEV_FD is not set
 
@@ -38,6 +39,10 @@
 # CONFIG_TCP_NAGLE_OFF is not set
 CONFIG_IP_NOSR=y
 # CONFIG_SKB_LARGE is not set
+
+#
+#  
+#
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
 # CONFIG_AX25 is not set
@@ -52,8 +57,8 @@
 # SCSI support type (disk, tape, CDrom)
 #
 CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_ST=y
-CONFIG_BLK_DEV_SR=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_BLK_DEV_SR is not set
 # CONFIG_CHR_DEV_SG is not set
 
 #
@@ -79,19 +84,22 @@
 #
 # Filesystems
 #
+# CONFIG_QUOTA is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_EXT_FS is not set
 CONFIG_EXT2_FS=y
 # CONFIG_XIA_FS is not set
-CONFIG_MSDOS_FS=y
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
 # CONFIG_UMSDOS_FS is not set
 CONFIG_PROC_FS=y
 CONFIG_NFS_FS=y
 CONFIG_ROOT_NFS=y
-CONFIG_ISO9660_FS=y
+# CONFIG_SMB_FS is not set
+# CONFIG_ISO9660_FS is not set
 # CONFIG_HPFS_FS is not set
 # CONFIG_SYSV_FS is not set
-# CONFIG_SMB_FS is not set
 
 #
 # Kernel hacking
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/kernel/Makefile linux/arch/sparc/kernel/Makefile
--- v1.3.70/linux/arch/sparc/kernel/Makefile	Sat Nov 25 19:04:36 1995
+++ linux/arch/sparc/kernel/Makefile	Mon Mar  4 08:49:54 1996
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.18 1995/11/25 00:57:48 davem Exp $
+# $Id: Makefile,v 1.22 1996/03/01 07:15:52 davem Exp $
 # Makefile for the linux kernel.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
@@ -12,21 +12,18 @@
 .S.o:
 	$(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o
 
-OBJS  = entry.o wof.o wuf.o etrap.o rtrap.o switch.o traps.o irq.o \
-	process.o signal.o ioport.o setup.o idprom.o probe.o mp.o  \
-	c_mp.o sys_sparc.o sunos_asm.o sparc-stub.o systbls.o      \
-	sys_sunos.o sunos_ioctl.o time.o
+all: kernel.o head.o
+
+O_TARGET := kernel.o
+O_OBJS   := entry.o wof.o wuf.o etrap.o rtrap.o switch.o traps.o irq.o  \
+	    process.o signal.o ioport.o setup.o idprom.o mp.o c_mp.o    \
+	    sys_sparc.o sunos_asm.o sparc-stub.o systbls.o sys_sunos.o  \
+	    sunos_ioctl.o time.o windows.o cpu.o auxio.o devices.o ksyms.o \
+	    sclow.o
 
 all: kernel.o head.o
 
 head.o: head.S
 	$(CC) -D__ASSEMBLY__ -ansi -c $*.S -o $*.o
-
-kernel.o: $(OBJS)
-	$(LD) -r -o kernel.o $(OBJS)
-	sync
-
-dep:
-	$(CPP) -M *.c > .depend
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/kernel/auxio.c linux/arch/sparc/kernel/auxio.c
--- v1.3.70/linux/arch/sparc/kernel/auxio.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/kernel/auxio.c	Mon Mar  4 08:49:54 1996
@@ -0,0 +1,40 @@
+/* auxio.c: Probing for the Sparc AUXIO register at boot time.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/oplib.h>
+#include <asm/io.h>
+
+/* Probe and map in the Auxiliary I/O register */
+unsigned char *auxio_register;
+
+void
+auxio_probe(void)
+{
+	int node, auxio_nd;
+	struct linux_prom_registers auxregs[1];
+
+	node = prom_getchild(prom_root_node);
+	auxio_nd = prom_searchsiblings(node, "auxiliary-io");
+	if(!auxio_nd) {
+		node = prom_searchsiblings(node, "obio");
+		node = prom_getchild(node);
+		auxio_nd = prom_searchsiblings(node, "auxio");
+		if(!auxio_nd) {
+			prom_printf("Cannot find auxio node, cannot continue...\n");
+			prom_halt();
+		}
+	}
+	prom_getproperty(auxio_nd, "reg", (char *) auxregs, sizeof(auxregs));
+	prom_apply_obio_ranges(auxregs, 0x1);
+	/* Map the register both read and write */
+	auxio_register = (unsigned char *) sparc_alloc_io(auxregs[0].phys_addr, 0,
+							  auxregs[0].reg_size,
+							  "auxilliaryIO",
+							  auxregs[0].which_io, 0x0);
+	/* Fix the address on sun4m and sun4c. */
+	if((((unsigned long) auxregs[0].phys_addr) & 3) == 3 ||
+	   sparc_cpu_model == sun4c)
+		auxio_register = (unsigned char *) ((int)auxio_register | 3);
+}
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/kernel/cpu.c linux/arch/sparc/kernel/cpu.c
--- v1.3.70/linux/arch/sparc/kernel/cpu.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/kernel/cpu.c	Mon Mar  4 08:49:54 1996
@@ -0,0 +1,156 @@
+/* cpu.c: Dinky routines to look for the kind of Sparc cpu
+ *        we are on.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/kernel.h>
+
+#include <asm/oplib.h>
+#include <asm/head.h>
+#include <asm/psr.h>
+#include <asm/mbus.h>
+
+struct cpu_iu_info {
+  int psr_impl;
+  int psr_vers;
+  char* cpu_name;   /* should be enough I hope... */
+};
+
+struct cpu_fp_info {
+  int psr_impl;
+  int fp_vers;
+  char* fp_name;
+};
+
+/* In order to get the fpu type correct, you need to take the IDPROM's
+ * machine type value into consideration too.  I will fix this.
+ */
+struct cpu_fp_info linux_sparc_fpu[] = {
+  { 0, 0, "Fujitsu MB86910 or Weitek WTL1164/5"},
+  { 0, 1, "Fujitsu MB86911 or Weitek WTL1164/5 or LSI L64831"},
+  { 0, 2, "LSI Logic L64802 or Texas Instruments ACT8847"},
+  /* SparcStation SLC, SparcStation1 */
+  { 0, 3, "Weitek WTL3170/2"},
+  /* SPARCstation-5 */
+  { 0, 4, "Lsi Logic/Meiko L64804 or compatible"},
+  { 0, 5, "reserved"},
+  { 0, 6, "reserved"},
+  { 0, 7, "No FPU"},
+  { 1, 0, "ROSS HyperSparc combined IU/FPU"},
+  { 1, 1, "Lsi Logic L64814"},
+  { 1, 2, "Texas Instruments TMS390-C602A"},
+  { 1, 3, "Cypress CY7C602 FPU"},
+  { 1, 4, "reserved"},
+  { 1, 5, "reserved"},
+  { 1, 6, "reserved"},
+  { 1, 7, "No FPU"},
+  { 2, 0, "BIT B5010 or B5110/20 or B5210"},
+  { 2, 1, "reserved"},
+  { 2, 2, "reserved"},
+  { 2, 3, "reserved"},
+  { 2, 4, "reserved"},
+  { 2, 5, "reserved"},
+  { 2, 6, "reserved"},
+  { 2, 7, "No FPU"},
+  /* SuperSparc 50 module */
+  { 4, 0, "SuperSparc on-chip FPU"},
+  /* SparcClassic */
+  { 4, 4, "TI MicroSparc on chip FPU"},
+  { 5, 0, "Matsushita MN10501"},
+  { 5, 1, "reserved"},
+  { 5, 2, "reserved"},
+  { 5, 3, "reserved"},
+  { 5, 4, "reserved"},
+  { 5, 5, "reserved"},
+  { 5, 6, "reserved"},
+  { 5, 7, "No FPU"},
+};
+
+#define NSPARCFPU  (sizeof(linux_sparc_fpu)/sizeof(struct cpu_fp_info))
+
+struct cpu_iu_info linux_sparc_chips[] = {
+  /* Sun4/100, 4/200, SLC */
+  { 0, 0, "Fujitsu  MB86900/1A or LSI L64831 SparcKIT-40"},
+  /* borned STP1012PGA */
+  { 0, 4, "Fujitsu  MB86904"},
+  /* SparcStation2, SparcServer 490 & 690 */
+  { 1, 0, "LSI Logic Corporation - L64811"},
+  /* SparcStation2 */
+  { 1, 1, "Cypress/ROSS CY7C601"},
+  /* Embedded controller */
+  { 1, 3, "Cypress/ROSS CY7C611"},
+  /* Ross Technologies HyperSparc */
+  { 1, 0xf, "ROSS HyperSparc RT620"},
+  { 1, 0xe, "ROSS HyperSparc RT625"},
+  /* ECL Implementation, CRAY S-MP Supercomputer... AIEEE! */
+  /* Someone please write the code to support this beast! ;) */
+  { 2, 0, "Bipolar Integrated Technology - B5010"},
+  { 3, 0, "LSI Logic Corporation - unknown-type"},
+  { 4, 0, "Texas Instruments, Inc. - SuperSparc 50"},
+  /* SparcClassic  --  borned STP1010TAB-50*/
+  { 4, 1, "Texas Instruments, Inc. - MicroSparc"},
+  { 4, 2, "Texas Instruments, Inc. - MicroSparc II"},
+  { 4, 3, "Texas Instruments, Inc. - SuperSparc 51"},
+  { 4, 4, "Texas Instruments, Inc. - SuperSparc 61"},
+  { 4, 5, "Texas Instruments, Inc. - unknown"},
+  { 5, 0, "Matsushita - MN10501"},
+  { 6, 0, "Philips Corporation - unknown"},
+  { 7, 0, "Harvest VLSI Design Center, Inc. - unknown"},
+  /* Gallium arsenide 200MHz, BOOOOGOOOOMIPS!!! */
+  { 8, 0, "Systems and Processes Engineering Corporation (SPEC)"},
+  { 9, 0, "Fujitsu #3"},
+  { 0xa, 0, "UNKNOWN CPU-VENDOR/TYPE"},
+  { 0xb, 0, "UNKNOWN CPU-VENDOR/TYPE"},
+  { 0xc, 0, "UNKNOWN CPU-VENDOR/TYPE"},
+  { 0xd, 0, "UNKNOWN CPU-VENDOR/TYPE"},
+  { 0xe, 0, "UNKNOWN CPU-VENDOR/TYPE"},
+  { 0xf, 0, "UNKNOWN CPU-VENDOR/TYPE"},
+};
+
+#define NSPARCCHIPS  (sizeof(linux_sparc_chips)/sizeof(struct cpu_iu_info))
+
+char *sparc_cpu_type[NCPUS] = { "cpu-oops", "cpu-oops1", "cpu-oops2", "cpu-oops3" };
+char *sparc_fpu_type[NCPUS] = { "fpu-oops", "fpu-oops1", "fpu-oops2", "fpu-oops3" };
+
+unsigned int fsr_storage;
+
+void
+cpu_probe(void)
+{
+	int psr_impl, psr_vers, fpu_vers;
+	int i, cpuid;
+
+	cpuid = get_cpuid();
+
+	psr_impl = ((get_psr()>>28)&0xf);
+	psr_vers = ((get_psr()>>24)&0xf);
+
+	fpu_vers = ((get_fsr()>>17)&0x7);
+
+	for(i = 0; i<NSPARCCHIPS; i++) {
+		if(linux_sparc_chips[i].psr_impl == psr_impl)
+			if(linux_sparc_chips[i].psr_vers == psr_vers) {
+				sparc_cpu_type[cpuid] = linux_sparc_chips[i].cpu_name;
+				break;
+			}
+	}
+
+	if(i==NSPARCCHIPS)
+		printk("DEBUG: psr.impl = 0x%x   psr.vers = 0x%x\n", psr_impl, 
+			    psr_vers);
+
+	for(i = 0; i<NSPARCFPU; i++) {
+		if(linux_sparc_fpu[i].psr_impl == psr_impl)
+			if(linux_sparc_fpu[i].fp_vers == fpu_vers) {
+				sparc_fpu_type[cpuid] = linux_sparc_fpu[i].fp_name;
+				break;
+			}
+	}
+
+	if(i == NSPARCFPU) {
+		printk("DEBUG: psr.impl = 0x%x  fsr.vers = 0x%x\n", psr_impl,
+			    fpu_vers);
+		sparc_fpu_type[cpuid] = linux_sparc_fpu[31].fp_name;
+	}
+}
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/kernel/devices.c linux/arch/sparc/kernel/devices.c
--- v1.3.70/linux/arch/sparc/kernel/devices.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/kernel/devices.c	Mon Mar  4 08:49:54 1996
@@ -0,0 +1,61 @@
+/* devices.c: Initial scan of the prom device tree for important
+ *            Sparc device nodes which we need to find.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/kernel.h>
+
+#include <asm/page.h>
+#include <asm/oplib.h>
+#include <asm/mp.h>
+#include <asm/system.h>
+
+struct prom_cpuinfo linux_cpus[NCPUS];
+int linux_num_cpus;
+
+extern void cpu_probe(void);
+extern void auxio_probe(void);
+
+unsigned long
+device_scan(unsigned long mem_start)
+{
+	char node_str[128];
+	int nd, prom_node_cpu, thismid;
+	int cpu_nds[NCPUS];  /* One node for each cpu */
+	int cpu_ctr = 0;
+
+	prom_getstring(prom_root_node, "device_type", node_str, sizeof(node_str));
+	if(strcmp(node_str, "cpu") == 0) {
+		cpu_nds[0] = prom_root_node;
+		cpu_ctr++;
+	} else {
+		int scan;
+		scan = prom_getchild(prom_root_node);
+		nd = 0;
+		while((scan = prom_getsibling(scan)) != 0) {
+			prom_getstring(scan, "device_type", node_str, sizeof(node_str));
+			if(strcmp(node_str, "cpu") == 0) {
+				cpu_nds[cpu_ctr] = scan;
+				linux_cpus[cpu_ctr].prom_node = scan;
+				prom_getproperty(scan, "mid", (char *) &thismid, sizeof(thismid));
+				linux_cpus[cpu_ctr].mid = thismid;
+				cpu_ctr++;
+			}
+		};
+		if(cpu_ctr == 0) {
+			printk("No CPU nodes found, cannot continue.\n");
+			/* Probably a sun4d or sun4e, Sun is trying to trick us ;-) */
+			halt();
+		}
+		printk("Found %d CPU prom device tree node(s).\n", cpu_ctr);
+	};
+	prom_node_cpu = cpu_nds[0];
+
+	linux_num_cpus = cpu_ctr;
+
+	cpu_probe();
+	auxio_probe();
+
+	return mem_start;
+}
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/kernel/entry.S linux/arch/sparc/kernel/entry.S
--- v1.3.70/linux/arch/sparc/kernel/entry.S	Mon Nov 27 12:48:27 1995
+++ linux/arch/sparc/kernel/entry.S	Mon Mar  4 08:49:54 1996
@@ -1,10 +1,11 @@
-/* $Id: entry.S,v 1.65 1995/11/25 14:36:22 zaitcev Exp $
+/* $Id: entry.S,v 1.79 1996/03/01 07:15:54 davem Exp $
  * arch/sparc/kernel/entry.S:  Sparc trap low-level entry points.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  */
 
 #include <linux/config.h>
+#include <linux/errno.h>
 
 #include <asm/head.h>
 #include <asm/asi.h>
@@ -18,7 +19,6 @@
 #include <asm/page.h>
 #include <asm/winmacro.h>
 #include <asm/signal.h>
-#include <asm/errno.h>
 
 #define NR_SYSCALLS 255      /* Each OS is different... */
 
@@ -72,11 +72,11 @@
 	/* Make sure kgdb sees the same state we just saved. */
 	LOAD_PT_GLOBALS(sp)
 	LOAD_PT_INS(sp)
-	ld	[%sp + STACKFRAME_SZ + PT_Y], %l4
-	ld	[%sp + STACKFRAME_SZ + PT_WIM], %l3
-	ld	[%sp + STACKFRAME_SZ + PT_PSR], %l0
-	ld	[%sp + STACKFRAME_SZ + PT_PC], %l1
-	ld	[%sp + STACKFRAME_SZ + PT_NPC], %l2
+	ld	[%sp + REGWIN_SZ + PT_Y], %l4
+	ld	[%sp + REGWIN_SZ + PT_WIM], %l3
+	ld	[%sp + REGWIN_SZ + PT_PSR], %l0
+	ld	[%sp + REGWIN_SZ + PT_PC], %l1
+	ld	[%sp + REGWIN_SZ + PT_NPC], %l2
 	rd	%tbr, %l5	/* Never changes... */
 
 	/* Make kgdb exception frame. */	
@@ -95,13 +95,12 @@
 	WRITE_PAUSE
 
 	call	C_LABEL(handle_exception)
-	 add	%sp, STACKFRAME_SZ, %o0	! Pass address of registers
+	 add	%sp, REGWIN_SZ, %o0	! Pass address of registers
 
 	/* Load new kgdb register set. */
 	LOAD_KGDB_GLOBALS(sp)
 	LOAD_KGDB_INS(sp)
 	LOAD_KGDB_SREGS(sp, l0, l2)
-	ld	[%sp + STACKFRAME_SZ + KGDB_WIM], %l6
 	wr	%l0, 0x0, %y
 
 	sethi	%hi(in_trap_handler), %l4
@@ -117,9 +116,8 @@
 	STORE_PT_INS(sp)
 	STORE_PT_GLOBALS(sp)
 	STORE_PT_YREG(sp, g2)
-	STORE_PT_PRIV(sp, l1, l2, l3, l6)
+	STORE_PT_PRIV(sp, l1, l2, l3)
 
-	/* Cross your fingers... */
 	RESTORE_ALL
 
 
@@ -228,19 +226,20 @@
 	sethi	%hi(C_LABEL(pdma_size)), %l5
 	st	%l6, [%l5 + %lo(C_LABEL(pdma_size))]
 	/* Flip terminal count pin */
-	sethi	%hi(AUXIO_VADDR), %l4
-	ldub	[%l4 + %lo(AUXIO_VADDR) + 0x3], %l5
+	set	C_LABEL(auxio_register), %l4
+	ld	[%l4], %l4
+	ldub	[%l4], %l5
 	or	%l5, 0xf4, %l5
-	stb	%l5, [%l4 + %lo(AUXIO_VADDR) + 0x3]
+	stb	%l5, [%l4]
 
 	/* Kill some time so the bits set */
 	WRITE_PAUSE
 	WRITE_PAUSE
 
-	ldub	[%l4 + %lo(AUXIO_VADDR) + 0x3], %l5
+	ldub	[%l4], %l5
 	andn	%l5, 0x04, %l5
 	or	%l5, 0xf0, %l5
-	stb	%l5, [%l4 + %lo(AUXIO_VADDR) + 0x3]
+	stb	%l5, [%l4]
 
 	/* Prevent recursion */
 	sethi	%hi(C_LABEL(doing_pdma)), %l4
@@ -287,7 +286,7 @@
 
 	mov	11, %o0			! floppy irq level
 	call	C_LABEL(floppy_interrupt)
-	 add	%sp, STACKFRAME_SZ, %o1	! struct pt_regs *regs
+	 add	%sp, REGWIN_SZ, %o1	! struct pt_regs *regs
 
 	RESTORE_ALL
 	
@@ -297,6 +296,7 @@
 	.globl	bad_trap_handler
 bad_trap_handler:
 	SAVE_ALL
+
 	wr	%l0, PSR_ET, %psr
 	WRITE_PAUSE
 
@@ -304,6 +304,7 @@
 	mov	%l0, %o1		! psr
 	call	C_LABEL(do_hw_interrupt)
 	 mov	%l1, %o2		! pc
+
 	RESTORE_ALL
 	
 /* For now all IRQ's not registered get sent here. handler_irq() will
@@ -333,7 +334,7 @@
 
 	mov	%l7, %o0		! irq level
 	call	C_LABEL(handler_irq)
-	 add	%sp, STACKFRAME_SZ, %o1	! pt_regs ptr
+	 add	%sp, REGWIN_SZ, %o1	! pt_regs ptr
 
 rie_checkbh:
 	sethi	%hi(C_LABEL(intr_count)), %l4
@@ -341,6 +342,7 @@
 	subcc	%l5, 0x1, %l5
 	bne	2f	/* IRQ within IRQ, get out of here... */
 	 nop
+
 	sethi	%hi(C_LABEL(bh_active)), %l3
 	ld	[%l3 + %lo(C_LABEL(bh_active))], %g2
 	sethi	%hi(C_LABEL(bh_mask)), %l3
@@ -348,64 +350,23 @@
 	andcc	%g2, %g3, %g0
 	be	2f
 	 nop
+
+	/* do_bottom_half must run at normal kernel priority, ie. all
+	 * IRQ's on.
+	 */
+	rd	%psr, %g4
+	andn	%g4, PSR_PIL, %g4
+	wr	%g4, 0x0, %psr
+	WRITE_PAUSE
 	call	C_LABEL(do_bottom_half)	
 	 nop
+
 	/* Try again... */
 	b	rie_checkbh
 	 nop
 	
 2:
 	st	%l5, [%l4 + %lo(C_LABEL(intr_count))]
-	RESTORE_ALL
-
-/* Soft IRQ's are handled just like hard IRQ's except that we
- * need to clear the IRQ line ourselves (in the interrupt reg)
- * and we don't take care of bottom-half handlers here.  We'll
- * just deal with it at the next clock tick, and since software
- * IRQ's relatively don't happen that often....
- * XXX BIG XXX Turn the software IRQ bit we need to clear into
- * XXX BIG XXX an element reference in an array that we can set
- * XXX BIG XXX a boot time based upon arch type
- * XXX BIG XXX OR... rewrite the appropriate IRQ trap table
- * XXX BIG XXX entries once the arch is detected (sun4/4c or sun4m)
- *
- * XXX EVEN BIGGER XXX Linux has bh_handlers for software interrupts
- * XXX EVEN BIGGER XXX so we do not even have to worry about this
- * XXX EVEN BIGGER XXX brain damaged software interrupt mechanism.
- */
-
-	.align	4
-	.globl	soft_irq_entry
-soft_irq_entry:
-	SAVE_ALL
-
-	/* We have tucked the bit to clear in the int reg into
-	 * %l4, take care of it now before we do anything else.
-	 */
-	sethi	%hi(INTREG_VADDR), %l5
-	ldsb	[%l5 + %lo(INTREG_VADDR)], %l6
-	andn	%l6, %l4, %l6
-	stb	%l6, [%l5 + %lo(INTREG_VADDR)]
-
-	/* start atomic operation with respect to software interrupts */
-	sethi	%hi(C_LABEL(intr_count)), %l4
-	ld	[%l4 + %lo(C_LABEL(intr_count))], %l5
-	add	%l5, 0x1, %l5
-	st	%l5, [%l4 + %lo(C_LABEL(intr_count))]
-
-	or	%l0, PSR_PIL, %l4
-	wr	%l4, 0x0, %psr		! grrr!
-	wr	%l4, PSR_ET, %psr	! double grrr!
-
-	mov	%l7, %o0	
-	add	%sp, STACKFRAME_SZ, %o1
-	call	C_LABEL(handler_irq)
-	 nop
-
-	sethi	%hi(C_LABEL(intr_count)), %l4
-	ld	[%l4 + %lo(C_LABEL(intr_count))], %l5
-	subcc	%l5, 0x1, %l5
-	st	%l5, [%l4 + %lo(C_LABEL(intr_count))]
 
 	RESTORE_ALL
 
@@ -416,10 +377,11 @@
 	.globl	bad_instruction
 bad_instruction:
 	SAVE_ALL
+
 	wr	%l0, PSR_ET, %psr		! re-enable traps
 	WRITE_PAUSE
 
-	add	%sp, STACKFRAME_SZ, %o0
+	add	%sp, REGWIN_SZ, %o0
 	mov	%l1, %o1
 	mov	%l2, %o2
 	call	C_LABEL(do_illegal_instruction)
@@ -430,14 +392,16 @@
 	.globl	priv_instruction
 priv_instruction:
 	SAVE_ALL
+
 	wr	%l0, PSR_ET, %psr
 	WRITE_PAUSE
 
-	add	%sp, STACKFRAME_SZ, %o0
+	add	%sp, REGWIN_SZ, %o0
 	mov	%l1, %o1
 	mov	%l2, %o2
 	call	C_LABEL(do_priv_instruction)
 	 mov	%l0, %o3
+
 	RESTORE_ALL
 
 	/* This routine handles unaligned data accesses.
@@ -446,14 +410,16 @@
 	.globl	mna_handler
 mna_handler:
 	SAVE_ALL
+
 	wr	%l0, PSR_ET, %psr		! re-enable traps
 	WRITE_PAUSE
 
-	add	%sp, STACKFRAME_SZ, %o0
+	add	%sp, REGWIN_SZ, %o0
 	mov	%l1, %o1
 	mov	%l2, %o2
 	call	C_LABEL(do_memaccess_unaligned)
 	 mov	%l0, %o3
+
 	RESTORE_ALL
 
 	/* This routine handles floating point disabled traps. */
@@ -461,29 +427,44 @@
 	.globl	fpd_trap_handler
 fpd_trap_handler:
 	SAVE_ALL
+
 	wr	%l0, PSR_ET, %psr		! re-enable traps
 	WRITE_PAUSE
 
-	add	%sp, STACKFRAME_SZ, %o0
+	add	%sp, REGWIN_SZ, %o0
 	mov	%l1, %o1
 	mov	%l2, %o2
 	call	C_LABEL(do_fpd_trap)
 	 mov	%l0, %o3
+
 	RESTORE_ALL
 
 	/* This routine handles Floating Point Exceptions. */
 	.align	4
 	.globl	fpe_trap_handler
 fpe_trap_handler:
+	set	fpsave_magic, %l5
+	cmp	%l1, %l5
+	bne	1f
+	 sethi	%hi(fpsave_catch), %l5
+	or	%l5, %lo(fpsave_catch), %l5
+	wr	%l0, 0x0, %psr
+	WRITE_PAUSE
+	jmp	%l5
+	 rett	%l5 + 4
+
+1:
 	SAVE_ALL
+
 	wr	%l0, PSR_ET, %psr		! re-enable traps
 	WRITE_PAUSE
 
-	add	%sp, STACKFRAME_SZ, %o0
+	add	%sp, REGWIN_SZ, %o0
 	mov	%l1, %o1
 	mov	%l2, %o2
 	call	C_LABEL(do_fpe_trap)
 	 mov	%l0, %o3
+
 	RESTORE_ALL
 
 	/* This routine handles Tag Overflow Exceptions. */
@@ -491,14 +472,16 @@
 	.globl	do_tag_overflow
 do_tag_overflow:
 	SAVE_ALL
+
 	wr	%l0, PSR_ET, %psr		! re-enable traps
 	WRITE_PAUSE
 
-	add	%sp, STACKFRAME_SZ, %o0
+	add	%sp, REGWIN_SZ, %o0
 	mov	%l1, %o1
 	mov	%l2, %o2
 	call	C_LABEL(handle_tag_overflow)
 	 mov	%l0, %o3
+
 	RESTORE_ALL
 
 	/* This routine handles Watchpoint Exceptions. */
@@ -506,14 +489,16 @@
 	.globl	do_watchpoint
 do_watchpoint:
 	SAVE_ALL
+
 	wr	%l0, PSR_ET, %psr		! re-enable traps
 	WRITE_PAUSE
 
-	add	%sp, STACKFRAME_SZ, %o0
+	add	%sp, REGWIN_SZ, %o0
 	mov	%l1, %o1
 	mov	%l2, %o2
 	call	C_LABEL(handle_watchpoint)
 	 mov	%l0, %o3
+
 	RESTORE_ALL
 
 	/* This routine handles Register Access Exceptions. */
@@ -521,14 +506,16 @@
 	.globl	do_reg_access
 do_reg_access:
 	SAVE_ALL
+
 	wr	%l0, PSR_ET, %psr		! re-enable traps
 	WRITE_PAUSE
 
-	add	%sp, STACKFRAME_SZ, %o0
+	add	%sp, REGWIN_SZ, %o0
 	mov	%l1, %o1
 	mov	%l2, %o2
 	call	C_LABEL(handle_reg_access)
 	 mov	%l0, %o3
+
 	RESTORE_ALL
 
 	/* This routine handles Co-Processor Disabled Exceptions. */
@@ -536,14 +523,16 @@
 	.globl	do_cp_disabled
 do_cp_disabled:
 	SAVE_ALL
+
 	wr	%l0, PSR_ET, %psr		! re-enable traps
 	WRITE_PAUSE
 
-	add	%sp, STACKFRAME_SZ, %o0
+	add	%sp, REGWIN_SZ, %o0
 	mov	%l1, %o1
 	mov	%l2, %o2
 	call	C_LABEL(handle_cp_disabled)
 	 mov	%l0, %o3
+
 	RESTORE_ALL
 
 	/* This routine handles Unimplemented FLUSH Exceptions. */
@@ -551,14 +540,16 @@
 	.globl	do_bad_flush
 do_bad_flush:
 	SAVE_ALL
+
 	wr	%l0, PSR_ET, %psr		! re-enable traps
 	WRITE_PAUSE
 
-	add	%sp, STACKFRAME_SZ, %o0
+	add	%sp, REGWIN_SZ, %o0
 	mov	%l1, %o1
 	mov	%l2, %o2
 	call	C_LABEL(handle_bad_flush)
 	 mov	%l0, %o3
+
 	RESTORE_ALL
 
 	/* This routine handles Co-Processor Exceptions. */
@@ -566,14 +557,16 @@
 	.globl	do_cp_exception
 do_cp_exception:
 	SAVE_ALL
+
 	wr	%l0, PSR_ET, %psr		! re-enable traps
 	WRITE_PAUSE
 
-	add	%sp, STACKFRAME_SZ, %o0
+	add	%sp, REGWIN_SZ, %o0
 	mov	%l1, %o1
 	mov	%l2, %o2
 	call	C_LABEL(handle_cp_exception)
 	 mov	%l0, %o3
+
 	RESTORE_ALL
 
 	/* This routine handles Hardware Divide By Zero Exceptions. */
@@ -581,14 +574,16 @@
 	.globl	do_hw_divzero
 do_hw_divzero:
 	SAVE_ALL
+
 	wr	%l0, PSR_ET, %psr		! re-enable traps
 	WRITE_PAUSE
 
-	add	%sp, STACKFRAME_SZ, %o0
+	add	%sp, REGWIN_SZ, %o0
 	mov	%l1, %o1
 	mov	%l2, %o2
 	call	C_LABEL(handle_hw_divzero)
 	 mov	%l0, %o3
+
 	RESTORE_ALL
 
 	.align	4
@@ -599,15 +594,24 @@
 	wr	%l0, PSR_ET, %psr
 	WRITE_PAUSE
 
+	andcc	%l0, PSR_PS, %g0
+	bne	dfw_kernel
+	 nop
+
 	call	C_LABEL(flush_user_windows)
 	 nop
 
 	/* Advance over the trap instruction. */
-	ld	[%sp + STACKFRAME_SZ + PT_NPC], %l1
+	ld	[%sp + REGWIN_SZ + PT_NPC], %l1
 	add	%l1, 0x4, %l2
-	st	%l1, [%sp + STACKFRAME_SZ + PT_PC]
-	st	%l2, [%sp + STACKFRAME_SZ + PT_NPC]
+	st	%l1, [%sp + REGWIN_SZ + PT_PC]
+	st	%l2, [%sp + REGWIN_SZ + PT_NPC]
+
+	RESTORE_ALL
 
+	/* We get these for debugging routines using __builtin_return_address() */
+dfw_kernel:
+	FLUSH_ALL_KERNEL_WINDOWS
 	RESTORE_ALL
 
 	/* The getcc software trap.  The user wants the condition codes from
@@ -635,6 +639,7 @@
 	andn	%l0, %l5, %l0	! clear ICC bits in current %psr
 	and	%l4, %l5, %l4	! clear non-ICC bits in user value
 	or	%l4, %l0, %l4	! or them in... mix mix mix
+
 	wr	%l4, 0x0, %psr	! set new %psr
 	WRITE_PAUSE		! TI scumbags...
 
@@ -642,9 +647,10 @@
 	rett	%l2 + 0x4	! like this...
 
 	.align	4
-	.globl	linux_trap_nmi
-linux_trap_nmi:
+	.globl	linux_trap_nmi_sun4c
+linux_trap_nmi_sun4c:
 	SAVE_ALL
+
 	/* Ugh, we need to clear the IRQ line.  This is now
 	 * a very sun4c specific trap hanler...
 	 */
@@ -673,20 +679,116 @@
 	sub	%o0, 0x4, %o0
 	lda	[%o0] ASI_CONTROL, %o3	! async error
 	call	C_LABEL(sparc_lvl15_nmi)
-	 add	%sp, STACKFRAME_SZ, %o0
+	 add	%sp, REGWIN_SZ, %o0
 
 	RESTORE_ALL
 
+#if 0 /* WIP */
+	/* Inter-Processor Interrupts on the Sun4m. */
 	.align	4
-	.globl	sparc_fault
-sparc_fault:
+	.globl	sun4m_ipi
+sun4m_ipi:
+	SAVE_ALL_IPI4M
+
+	set	MAILBOX_ADDRESS, %l4
+	ldub	[%l4], %l5
+	subcc	%l5, MBOX_STOPCPU, %g0
+	bne,a	1f
+	 subcc	%l5, MBOX_STOPCPU2, %g0
+
+	call	C_LABEL(prom_stopcpu)
+	 mov	0, %o0
+	ba,a	2f	
+
+1:
+	bne,a	1f
+	 subcc	%l5, MBOX_IDLECPU, %g0
+
+	call	C_LABEL(prom_stopcpu)
+	 mov	0, %o0
+	ba,a	2f	
+
+1:
+	bne,a	1f
+	 subcc	%l5, MBOX_IDLECPU2, %g0
+
+	call	C_LABEL(prom_idlecpu)
+	 mov	0, %o0
+	ba,a	2f	
+
+1:
+	bne,a	2f
+	 nop
+
+	call	C_LABEL(prom_idlecpu)
+	 mov	0, %o0
+	ba,a	2f	
+
+2:
+	call	C_LABEL(smp_callin)
+
+	RESTORE_ALL_IPI4M
+#endif
+
+	.align	4
+	.globl	sun4c_fault
+sun4c_fault:
 	SAVE_ALL
-	rd	%tbr, %o1
+
+	/* XXX This needs to be scheduled better */
+	sethi	%hi(AC_SYNC_ERR), %l4
+	add	%l4, 0x4, %l5		! AC_SYNC_VA in %l5
+	lda	[%l5] ASI_CONTROL, %o3		/* Address */
+	lda	[%l4] ASI_CONTROL, %l6
+	srl	%l6, 15, %l6
+	and	%l6, 1, %o2	/* Write? */
+
 	wr	%l0, PSR_ET, %psr
 	WRITE_PAUSE
 
+	mov	%l7, %o1			/* Text fault? */
 	call	C_LABEL(do_sparc_fault)
-	 add	%sp, STACKFRAME_SZ, %o0
+	 add	%sp, REGWIN_SZ, %o0		/* pt_regs */
+
+	RESTORE_ALL
+
+	.align	4
+	.globl	C_LABEL(srmmu_fault)
+C_LABEL(srmmu_fault):
+	/* Slot 1 */
+	mov	0x400, %l5
+	mov	0x300, %l4
+
+	/* Slot 2 */
+	lda	[%l5] ASI_M_MMUREGS, %l6	! read sfar first
+	lda	[%l4] ASI_M_MMUREGS, %l5	! read sfsr last
+
+	/* Slot 3 */
+	andn	%l6, 0xfff, %l6
+	srl	%l5, 6, %l5			! and encode all info into l7
+
+	/* Slot 4 */
+	and	%l5, 2, %l5
+	or	%l5, %l6, %l6
+
+	/* Slot 5 */
+	or	%l6, %l7, %l7			! l7 = [addr,write,txtfault]
+
+	SAVE_ALL
+
+	mov	%l7, %o1
+	mov	%l7, %o2
+	and	%o1, 1, %o1		! arg2 = text_faultp
+	mov	%l7, %o3
+	and	%o2, 2, %o2		! arg3 = writep
+	andn	%o3, 0xfff, %o3		! arg4 = faulting address
+
+	wr	%l0, PSR_ET, %psr
+	WRITE_PAUSE
+
+	call	C_LABEL(do_sparc_fault)
+	 add	%sp, REGWIN_SZ, %o0	! arg1 = pt_regs ptr
+
 	RESTORE_ALL
 
 	/* SunOS uses syscall zero as the 'indirect syscall' it looks
@@ -695,9 +797,9 @@
 	 */
 	.globl	C_LABEL(sunos_indir)
 C_LABEL(sunos_indir):
-	ld	[%sp + STACKFRAME_SZ + PT_I0], %g1
+	ld	[%sp + REGWIN_SZ + PT_I0], %g1
 	cmp	%g1, NR_SYSCALLS
-	bleu,a	1f
+	blu,a	1f
 	 sll	%g1, 0x2, %g1
 
 	set	C_LABEL(sunos_nosys), %l6
@@ -709,21 +811,31 @@
 	ld	[%l7 + %g1], %l6
 
 2:	
-	ld	[%sp + STACKFRAME_SZ + PT_I1], %o0
-	ld	[%sp + STACKFRAME_SZ + PT_I2], %o1
-	ld	[%sp + STACKFRAME_SZ + PT_I3], %o2
-	ld	[%sp + STACKFRAME_SZ + PT_I4], %o3
+	ld	[%sp + REGWIN_SZ + PT_I1], %o0
+	ld	[%sp + REGWIN_SZ + PT_I2], %o1
+	ld	[%sp + REGWIN_SZ + PT_I3], %o2
+	ld	[%sp + REGWIN_SZ + PT_I4], %o3
 	call	%l6
-	 ld	[%sp + STACKFRAME_SZ + PT_I5], %o4
+	 ld	[%sp + REGWIN_SZ + PT_I5], %o4
 
 	b	scall_store_args		/* so stupid... */
 	 nop
 
+#if 0 /* work in progress */
+	.align 4
+	.globl	C_LABEL(sys_ptrace)
+C_LABEL(sys_ptrace):
+	call	C_LABEL(do_ptrace)
+	 add	%sp, REGWIN_SZ, %o0
+
+	RESTORE_ALL
+#endif
+
 	.align	4
 	.globl	C_LABEL(sys_execve)
 C_LABEL(sys_execve):
 	call	C_LABEL(sparc_execve)
-	 add	%sp, STACKFRAME_SZ, %o0		! pt_regs *regs arg
+	 add	%sp, REGWIN_SZ, %o0		! pt_regs *regs arg
 
 	b	scall_store_args
 	 nop
@@ -732,16 +844,38 @@
 	.globl	C_LABEL(sys_pipe)
 C_LABEL(sys_pipe):
 	call	C_LABEL(sparc_pipe)
-	 add	%sp, STACKFRAME_SZ, %o0		! pt_regs *regs arg
+	 add	%sp, REGWIN_SZ, %o0		! pt_regs *regs arg
 
 	b	C_LABEL(ret_sys_call)
 	 nop
 
 	.align	4
+	.globl	C_LABEL(sys_sigpause)
+C_LABEL(sys_sigpause):
+	ld	[%sp + REGWIN_SZ + PT_I0], %o0
+	call	C_LABEL(do_sigpause)
+	 add	%sp, REGWIN_SZ, %o1
+
+	/* We are returning to a signal handler. */
+
+	RESTORE_ALL
+
+	.align	4
+	.globl	C_LABEL(sys_sigsuspend)
+C_LABEL(sys_sigsuspend):
+	ld	[%sp + REGWIN_SZ + PT_I0], %o0
+	call	C_LABEL(do_sigsuspend)
+	 add	%sp, REGWIN_SZ, %o1
+
+	/* We are returning to a signal handler. */
+
+	RESTORE_ALL
+
+	.align	4
 	.globl	C_LABEL(sys_sigreturn)
 C_LABEL(sys_sigreturn):
 	call	C_LABEL(do_sigreturn)
-	 add	%sp, STACKFRAME_SZ, %o0
+	 add	%sp, REGWIN_SZ, %o0
 
 	/* We don't want to muck with user registers like a
 	 * normal syscall, just return.
@@ -759,16 +893,15 @@
 	/* Save the kernel state as of now. */
 	FLUSH_ALL_KERNEL_WINDOWS;
 	STORE_WINDOW(sp)
-	LOAD_CURRENT(g6)
+	LOAD_CURRENT(g6, g5)
 	rd	%psr, %g4
 	rd	%wim, %g5
-	std	%g4, [%g6 + THREAD_KPSR]
-	std	%sp, [%g6 + THREAD_KSP]
+	std	%g4, [%g6 + THREAD_FORK_KPSR]
 
 	mov	SIGCHLD, %o0			! arg0:	clone flags
-	mov	%fp, %o1			! arg1:	usp
+	ld	[%sp + REGWIN_SZ + PT_FP], %o1	! arg1:	usp
 	call	C_LABEL(do_fork)
-	 add	%sp, STACKFRAME_SZ, %o2		! arg2:	pt_regs ptr
+	 add	%sp, REGWIN_SZ, %o2		! arg2:	pt_regs ptr
 
 	b	scall_store_args
 	 nop
@@ -779,151 +912,210 @@
 	/* Save the kernel state as of now. */
 	FLUSH_ALL_KERNEL_WINDOWS;
 	STORE_WINDOW(sp)
-	LOAD_CURRENT(g6)
+	LOAD_CURRENT(g6, g5)
 	rd	%psr, %g4
 	rd	%wim, %g5
-	std	%g4, [%g6 + THREAD_KPSR]
-	std	%sp, [%g6 + THREAD_KSP]
+	std	%g4, [%g6 + THREAD_FORK_KPSR]
 
-	ldd	[%sp + STACKFRAME_SZ + PT_I0], %o0	! arg0,1: flags,usp
-	cmp	%o1, 0x0				! Is new_usp NULL?
+	ldd	[%sp + REGWIN_SZ + PT_I0], %o0	! arg0,1: flags,usp
+	cmp	%o1, 0x0			! Is new_usp NULL?
 	be,a	1f
-	 mov	%fp, %o1				! yes, use current usp
-1:
-	call	C_LABEL(do_fork)
-	 add	%sp, STACKFRAME_SZ, %o2			! arg2:	pt_regs ptr
-
-	b	scall_store_args
-	 nop
-
-#if 0 /* XXX Much later... XXX */
-	/* Whee, vfork... */
-	.globl	C_LABEL(sys_vfork)
-C_LABEL(sys_vfork):
-	/* Save the kernel state as of now. */
-	FLUSH_ALL_KERNEL_WINDOWS;
-	STORE_WINDOW(sp)
-	LOAD_CURRENT(g6)
-	rd	%psr, %g4
-	rd	%wim, %g5
-	std	%g4, [%g6 + THREAD_KPSR]
-	std	%sp, [%g6 + THREAD_KSP]
-
-	set	(0x2100 | SIGCHLD), %o0			! CLONE_VFORK,CLONE_VM,SIGCHLD
-	mov	%fp, %o1				! use current usp
+	 ld	[%sp + REGWIN_SZ + PT_FP], %o1	! yes, use current usp
 1:
 	call	C_LABEL(do_fork)
-	 add	%sp, STACKFRAME_SZ, %o2			! arg2:	pt_regs ptr
+	 add	%sp, REGWIN_SZ, %o2		! arg2:	pt_regs ptr
 
 	b	scall_store_args
 	 nop
-#endif
 
 	/* All system calls enter here... */
 	.align	4
 	.globl	linux_sparc_syscall
 linux_sparc_syscall:
-	/* Don't dork with %l7, it holds the pointer to the
-	 * system call vector table.  SAVE_ALL does not
-	 * modify its value.
+	/* While we are here trying to optimize our lives
+	 * away, handle the easy bogus cases like a
+	 * ni_syscall or sysnum > NR_SYSCALLS etc.
+	 * In the cases where we cannot optimize the
+	 * call inline we don't really lose anything
+	 * performance wise because we are doing here
+	 * things which we did anyway in the original
+	 * routine.  The only added complexity is a
+	 * bit test, compare, and branch to decide
+	 * if we need to save process state or not.
 	 */
-	rd	%wim, %l3
-	SAVE_ALL
 
-	wr	%l0, PSR_ET, %psr	/* Turn on traps + interrupts */
-	WRITE_PAUSE
-
-#if 0 /* Trace all system calls... */
-	add	%sp, STACKFRAME_SZ, %o0
-	call	C_LABEL(syscall_trace_entry)
-	 nop
-#endif
+	/* XXX TODO: When we have ptrace working test
+	 * XXX       test for PF_TRACESYS in task flags.
+	 */
 
-	/* SAVE_ALL may have blown away %g1, reload it. */
-	ld	[%sp + STACKFRAME_SZ + PT_G1], %g1
+	/* Direct access to user regs, must faster. */
 	cmp	%g1, NR_SYSCALLS
-	bleu,a	1f
-	 sll	%g1, 0x2, %g1
+	blu,a	1f
+	 sll	%g1, 2, %l4
 
-	set	C_LABEL(sys_ni_syscall), %l6
-	b	2f
-	 nop
+	b	syscall_is_too_hard
+	 set	C_LABEL(sys_ni_syscall), %l7
 
 1:
-	/* Syscall table ptr is in %l7. */
-	ld	[%l7 + %g1], %l6	! load up ptr to syscall handler
+	ld	[%l7 + %l4], %l7
 
-	/* Pt_regs is your friend... Make the syscall... */
-2:
-	ldd	[%sp + STACKFRAME_SZ + PT_I0], %o0
-	ldd	[%sp + STACKFRAME_SZ + PT_I2], %o2
-	ldd	[%sp + STACKFRAME_SZ + PT_I4], %o4
-	call	%l6
+	/* If bit-1 is set, this is a "fast" syscall.
+	 * This is the _complete_ overhead of this optimization,
+	 * and we save ourselves a load, so it evens out to nothing.
+	 */
+	andcc	%l7, 0x1, %g0
+	be	syscall_is_too_hard
+	 andn	%l7, 0x1, %l7
+
+	jmpl	%l7, %g0
 	 nop
 
+	.globl	syscall_is_too_hard
+syscall_is_too_hard:
+	rd	%wim, %l3
+	SAVE_ALL
+
+	wr	%l0, PSR_ET, %psr
+	WRITE_PAUSE
+
+2:
+	ldd	[%sp + REGWIN_SZ + PT_I0], %o0
+	st	%o0, [%sp + REGWIN_SZ + PT_G0]	! for restarting syscalls
+	ldd	[%sp + REGWIN_SZ + PT_I2], %o2
+	call	%l7
+	 ldd	[%sp + REGWIN_SZ + PT_I4], %o4
+
 scall_store_args:
-	st	%o0, [%sp + STACKFRAME_SZ + PT_I0]
+	st	%o0, [%sp + REGWIN_SZ + PT_I0]
 
 	.globl	C_LABEL(ret_sys_call)
 C_LABEL(ret_sys_call):
-	ld	[%sp + STACKFRAME_SZ + PT_I0], %o0
+	ld	[%sp + REGWIN_SZ + PT_I0], %o0
 	set	PSR_C, %l6
-	cmp	%o0, -ELIBSCN
+	cmp	%o0, -ENOIOCTLCMD
 	bgeu	1f
-	 ld	[%sp + STACKFRAME_SZ + PT_PSR], %l5
+	 ld	[%sp + REGWIN_SZ + PT_PSR], %l5
 
 	/* System call success, clear Carry condition code. */		
 	andn	%l5, %l6, %l5
 	b	2f
-	 st	%l5, [%sp + STACKFRAME_SZ + PT_PSR]	
+	 st	%l5, [%sp + REGWIN_SZ + PT_PSR]	
 
 1:
 	/* System call failure, set Carry condition code.
 	 * Also, get abs(errno) to return to the process.
 	 */
 	sub	%g0, %o0, %o0
-	st	%o0, [%sp + STACKFRAME_SZ + PT_I0]
+	st	%o0, [%sp + REGWIN_SZ + PT_I0]
 	or	%l5, %l6, %l5
-	st	%l5, [%sp + STACKFRAME_SZ + PT_PSR]
+	st	%l5, [%sp + REGWIN_SZ + PT_PSR]
 
-	/* %i6 is our frame pointer, the restore done by the rett
-	 * instruction will automatically put us back on the users
-	 * stack.  Advance the pc and npc past the trap instruction.
-	 */
+	/* Advance the pc and npc over the trap instruction. */
 2:
-	ld	[%sp + STACKFRAME_SZ + PT_NPC], %l1	/* pc  = npc   */
-	add	%l1, 0x4, %l2				/* npc = npc+4 */
-	st	%l1, [%sp + STACKFRAME_SZ + PT_PC]
-	st	%l2, [%sp + STACKFRAME_SZ + PT_NPC]
-
-#if 0 /* Trace all system calls... */
-	add	%sp, STACKFRAME_SZ, %o0
-	call	C_LABEL(syscall_trace_exit)
-	 nop
-#endif
+	ld	[%sp + REGWIN_SZ + PT_NPC], %l1	/* pc  = npc   */
+	add	%l1, 0x4, %l2			/* npc = npc+4 */
+	st	%l1, [%sp + REGWIN_SZ + PT_PC]
+	st	%l2, [%sp + REGWIN_SZ + PT_NPC]
 
 	RESTORE_ALL
 
-	.globl	C_LABEL(flush_user_windows)
-C_LABEL(flush_user_windows):
-	LOAD_CURRENT(g2)
-	ld	[%g2 + THREAD_UMASK], %g1
-	orcc	%g0, %g1, %g0
-	be	3f
-	 clr	%g3
+/* Saving and restoring the FPU state is best done from lowlevel code.
+ *
+ * void fpsave(unsigned long *fpregs, unsigned long *fsr,
+ *             void *fpqueue, unsigned long *fpqdepth)
+ */
+
+	.globl	C_LABEL(fpsave)
+C_LABEL(fpsave):
+	st	%fsr, [%o1]
+	ld	[%o1], %g1
+	set	0x2000, %g4
+	andcc	%g1, %g4, %g0
+	be	2f
+	 mov	0, %g2
+
+	/* We have an fpqueue to save. */
 1:
-	_SV
-	LOAD_CURRENT(g2)
-	ld	[%g2 + THREAD_UMASK], %g1
-	orcc	%g0, %g1, %g0
+	std	%fq, [%o2]
+fpsave_magic:
+	st	%fsr, [%o1]
+	ld	[%o1], %g3
+	andcc	%g3, %g4, %g0
+	add	%g2, 1, %g2
 	bne	1b
-	 add	%g3, 1, %g3
+	 add	%o2, 8, %o2
+
 2:
-	subcc	%g3, 1, %g3
-	bne	2b
-	 _RS
-3:
-	jmp	%o7 + 0x8
+	st	%g2, [%o3]
+
+	std	%f0, [%o0 + 0x00]
+	std	%f2, [%o0 + 0x08]
+	std	%f4, [%o0 + 0x10]
+	std	%f6, [%o0 + 0x18]
+	std	%f8, [%o0 + 0x20]
+	std	%f10, [%o0 + 0x28]
+	std	%f12, [%o0 + 0x30]
+	std	%f14, [%o0 + 0x38]
+	std	%f16, [%o0 + 0x40]
+	std	%f18, [%o0 + 0x48]
+	std	%f20, [%o0 + 0x50]
+	std	%f22, [%o0 + 0x58]
+	std	%f24, [%o0 + 0x60]
+	std	%f26, [%o0 + 0x68]
+	std	%f28, [%o0 + 0x70]
+	retl
+	 std	%f30, [%o0 + 0x78]
+
+	/* Thanks for Theo Deraadt and the authors of the Sprite/netbsd/openbsd
+	 * code for pointing out this possible deadlock, while we save state
+	 * above we could trap on the fsr store so our low level fpu trap
+	 * code has to know how to deal with this.
+	 */
+fpsave_catch:
+	b	fpsave_magic + 4
+	 st	%fsr, [%o1]
+
+	/* void fpload(unsigned long *fpregs, unsigned long *fsr); */
+
+	.globl	C_LABEL(fpload)
+C_LABEL(fpload):
+	ldd	[%o0 + 0x00], %f0
+	ldd	[%o0 + 0x08], %f2
+	ldd	[%o0 + 0x10], %f4
+	ldd	[%o0 + 0x18], %f6
+	ldd	[%o0 + 0x20], %f8
+	ldd	[%o0 + 0x28], %f10
+	ldd	[%o0 + 0x30], %f12
+	ldd	[%o0 + 0x38], %f14
+	ldd	[%o0 + 0x40], %f16
+	ldd	[%o0 + 0x48], %f18
+	ldd	[%o0 + 0x50], %f20
+	ldd	[%o0 + 0x58], %f22
+	ldd	[%o0 + 0x60], %f24
+	ldd	[%o0 + 0x68], %f26
+	ldd	[%o0 + 0x70], %f28
+	ldd	[%o0 + 0x78], %f30
+	ld	[%o1], %fsr
+	retl
 	 nop
+
+	.globl	C_LABEL(udelay)
+C_LABEL(udelay):
+	save	%sp, -REGWIN_SZ, %sp
+	mov	%i0, %o0
+	sethi	%hi(0x10c6), %o1
+	call	.umul
+	 or	%o1, %lo(0x10c6), %o1
+	sethi	%hi(C_LABEL(loops_per_sec)), %o3
+	call	.umul
+	 ld	[%o3 + %lo(C_LABEL(loops_per_sec))], %o1
+
+	cmp	%o1, 0x0
+1:
+	bne	1b
+	 subcc	%o1, 1, %o1
+	
+	ret
+	restore
 
 /* End of entry.S */
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/kernel/etrap.S linux/arch/sparc/kernel/etrap.S
--- v1.3.70/linux/arch/sparc/kernel/etrap.S	Sat Nov 25 19:04:36 1995
+++ linux/arch/sparc/kernel/etrap.S	Mon Mar  4 08:49:55 1996
@@ -1,4 +1,4 @@
-/* $Id: etrap.S,v 1.10 1995/11/25 00:57:58 davem Exp $
+/* $Id: etrap.S,v 1.16 1996/02/20 07:45:01 davem Exp $
  * etrap.S: Sparc trap window preparation for entry into the
  *          Linux kernel.
  *
@@ -7,6 +7,8 @@
 
 #include <asm/cprefix.h>
 #include <asm/head.h>
+#include <asm/asi.h>
+#include <asm/contregs.h>
 #include <asm/page.h>
 #include <asm/psr.h>
 #include <asm/ptrace.h>
@@ -84,8 +86,8 @@
 	/* From kernel, allocate more kernel stack and
 	 * build a pt_regs trap frame.
 	 */
-	sub	%fp, (STACKFRAME_SZ + TRACEREG_SZ), %t_kstack
-	STORE_PT_ALL(t_kstack, t_psr, t_pc, t_npc, t_wim, g2)
+	sub	%fp, (REGWIN_SZ + TRACEREG_SZ), %t_kstack
+	STORE_PT_ALL(t_kstack, t_psr, t_pc, t_npc, g2)
 
 	/* See if we are in the trap window. */
 	andcc	%t_twinmask, %t_wim, %g0
@@ -99,12 +101,11 @@
 	 * Just do it...
 	 */
 1:
-	mov	%t_kstack, %sp		! jump onto new stack
 	jmpl	%t_retpc + 0x8, %g0	! return to caller
-	 nop
+	 mov	%t_kstack, %sp		! jump onto new stack
 
 trap_setup_kernel_spill:
-	LOAD_CURRENT(curptr)
+	LOAD_CURRENT(curptr, g1)
 	ld	[%curptr + THREAD_UMASK], %g1
 	orcc	%g0, %g1, %g0
 	bne	trap_setup_user_spill	! there are some user windows, yuck
@@ -129,21 +130,21 @@
 
 	restore	%g0, %g0, %g0
 
-	mov	%t_kstack, %sp		! and onto new kernel stack
 	jmpl	%t_retpc + 0x8, %g0	! return to caller
-	 nop
+	 mov	%t_kstack, %sp		! and onto new kernel stack
 
 trap_setup_from_user:
 	/* We can't use %curptr yet. */
-	LOAD_CURRENT(t_kstack)
-	ld	[%t_kstack + TASK_KSTACK_PG], %t_kstack
+	LOAD_CURRENT(t_kstack, t_twinmask)
+	mov	1, %t_twinmask
+	ld	[%t_kstack + TASK_SAVED_KSTACK], %t_kstack
+	sll	%t_twinmask, %t_psr, %t_twinmask ! t_twinmask = (1 << psr)
 
 	/* Build pt_regs frame. */
-	add	%t_kstack, (PAGE_SIZE - STACKFRAME_SZ - TRACEREG_SZ), %t_kstack
-	STORE_PT_ALL(t_kstack, t_psr, t_pc, t_npc, t_wim, g2)
+	STORE_PT_ALL(t_kstack, t_psr, t_pc, t_npc, g2)
 
 	/* Clear current->tss.w_saved */
-	LOAD_CURRENT(curptr)
+	LOAD_CURRENT(curptr, g1)
 	st	%g0, [%curptr + THREAD_W_SAVED]
 
 	/* See if we are in the trap window. */
@@ -176,9 +177,8 @@
 tsetup_patch3:	and	%g2, 0xff, %g2			! patched on 7win Sparcs
 		st	%g2, [%curptr + THREAD_UMASK]	! store new umask
 
-		mov	%t_kstack, %sp			! and onto kernel stack
 		jmpl	%t_retpc + 0x8, %g0		! return to caller
-		 nop
+		 mov	%t_kstack, %sp			! and onto kernel stack
 
 trap_setup_user_spill:
 		/* A spill occured from either kernel or user mode
@@ -213,18 +213,18 @@
 	 */
 	SAVE_BOLIXED_USER_STACK(curptr, g3)
 	restore	%g0, %g0, %g0
-	mov	%t_kstack, %sp
+
 	jmpl	%t_retpc + 0x8, %g0
-	 nop
+	 mov	%t_kstack, %sp
 
 trap_setup_good_ustack:
 	STORE_WINDOW(sp)
 
 trap_setup_finish_up:
 	restore %g0, %g0, %g0
-	mov	%t_kstack, %sp
+
 	jmpl	%t_retpc + 0x8, %g0
-	 nop
+	 mov	%t_kstack, %sp
 
 	/* Architecture specific stack checking routines.  When either
 	 * of these routines are called, the globals are free to use
@@ -234,7 +234,6 @@
 #define glob_tmp     g1
 
 	.globl	C_LABEL(tsetup_sun4c_stackchk)
-	.globl	C_LABEL(tsetup_srmmu_stackchk)
 C_LABEL(tsetup_sun4c_stackchk):
 	/* Done by caller: andcc %sp, 0x7, %g0 */
 	be	1f
@@ -293,6 +292,7 @@
 	b	trap_setup_user_stack_is_bolixed
 	 nop
 
+	.globl	C_LABEL(tsetup_srmmu_stackchk)
 C_LABEL(tsetup_srmmu_stackchk):
 	/* Check results of callers andcc %sp, 0x7, %g0 */
 	bne	trap_setup_user_stack_is_bolixed
@@ -302,8 +302,6 @@
 	 nop
 
 	/* Clear the fault status and turn on the no_fault bit. */
-	mov	AC_M_SFSR, %glob_tmp			! delay from above...
-	lda	[%glob_tmp] ASI_M_MMUREGS, %g0		! eat SFSR
 	lda	[%g0] ASI_M_MMUREGS, %glob_tmp		! read MMU control
 	or	%glob_tmp, 0x2, %glob_tmp		! or in no_fault bit
 	sta	%glob_tmp, [%g0] ASI_M_MMUREGS		! set it
@@ -317,10 +315,11 @@
 	mov	AC_M_SFAR, %glob_tmp
 	lda	[%glob_tmp] ASI_M_MMUREGS, %g0
 	mov	AC_M_SFSR, %glob_tmp
-	lda	[%glob_tmp] ASI_M_MMUREGS, %glob_tmp
+	lda	[%glob_tmp] ASI_M_MMUREGS, %glob_tmp	! save away status of winstore
 	andcc	%glob_tmp, 0x2, %g0			! did we fault?
 	be	trap_setup_finish_up			! cool beans, success
 	 nop
 
 	b	trap_setup_user_stack_is_bolixed	! we faulted, ugh
 	 nop
+
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/kernel/head.S linux/arch/sparc/kernel/head.S
--- v1.3.70/linux/arch/sparc/kernel/head.S	Sat Nov 25 19:04:36 1995
+++ linux/arch/sparc/kernel/head.S	Mon Mar  4 08:49:55 1996
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.39 1995/11/25 00:58:01 davem Exp $
+/* $Id: head.S,v 1.47 1996/02/15 09:11:57 davem Exp $
  * head.S: The initial boot code for the Sparc port of Linux.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -49,7 +49,7 @@
 C_LABEL(cputypvar):
 	.asciz "compatability"
 
-/* Tested on SS-5, SS-10. Probably someone at Sun applied a spell-checker. --P3 */
+/* Tested on SS-5, SS-10. Probably someone at Sun applied a spell-checker. */
 	.align 4
 C_LABEL(cputypvar_sun4m):
 	.asciz "compatible"
@@ -82,7 +82,7 @@
 C_LABEL(trapbase):
 /* We get control passed to us here at t_zero. */
 t_zero:	b gokernel; nop; nop; nop;
-t_tflt:	TRAP_ENTRY(0x1, sparc_fault)        /* Inst. Access Exception        */
+t_tflt:	SPARC_TFAULT                        /* Inst. Access Exception        */
 t_bins:	TRAP_ENTRY(0x2, bad_instruction)    /* Illegal Instruction           */
 t_pins:	TRAP_ENTRY(0x3, priv_instruction)   /* Privileged Instruction        */
 t_fpd:	TRAP_ENTRY(0x4, fpd_trap_handler)   /* Floating Point Disabled       */
@@ -90,16 +90,16 @@
 t_wunf:	WINDOW_FILL                         /* Window Underflow              */
 t_mna:	TRAP_ENTRY(0x7, mna_handler)        /* Memory Address Not Aligned    */
 t_fpe:	TRAP_ENTRY(0x8, fpe_trap_handler)   /* Floating Point Exception      */
-t_dflt:	TRAP_ENTRY(0x9, sparc_fault)        /* Data Miss Exception           */
+t_dflt:	SPARC_DFAULT                        /* Data Miss Exception           */
 t_tio:	TRAP_ENTRY(0xa, do_tag_overflow)    /* Tagged Instruction Ovrflw     */
 t_wpt:	TRAP_ENTRY(0xb, do_watchpoint)      /* Watchpoint Detected           */
 t_badc:	BAD_TRAP(0xc) BAD_TRAP(0xd) BAD_TRAP(0xe) BAD_TRAP(0xf) BAD_TRAP(0x10)
-t_irq1:	TRAP_ENTRY_SOFTINT(1)               /* IRQ Software/SBUS Level 1     */
+t_irq1:	TRAP_ENTRY_INTERRUPT(1)             /* IRQ Software/SBUS Level 1     */
 t_irq2:	TRAP_ENTRY_INTERRUPT(2)             /* IRQ SBUS Level 2              */
 t_irq3:	TRAP_ENTRY_INTERRUPT(3)             /* IRQ SCSI/DMA/SBUS Level 3     */
-t_irq4:	TRAP_ENTRY_SOFTINT(4)               /* IRQ Software Level 4          */
+t_irq4:	TRAP_ENTRY_INTERRUPT(4)             /* IRQ Software Level 4          */
 t_irq5:	TRAP_ENTRY_INTERRUPT(5)             /* IRQ SBUS/Ethernet Level 5     */
-t_irq6:	TRAP_ENTRY_SOFTINT(6)               /* IRQ Software Level 6          */
+t_irq6:	TRAP_ENTRY_INTERRUPT(6)             /* IRQ Software Level 6          */
 t_irq7:	TRAP_ENTRY_INTERRUPT(7)             /* IRQ Video/SBUS Level 5        */
 t_irq8:	TRAP_ENTRY_INTERRUPT(8)             /* IRQ SBUS Level 6              */
 t_irq9:	TRAP_ENTRY_INTERRUPT(9)             /* IRQ SBUS Level 7              */
@@ -110,20 +110,20 @@
 t_irq14:TRAP_ENTRY_INTERRUPT(14)            /* IRQ Timer #2                  */
 t_nmi:	NMI_TRAP                            /* Level 15 (NMI)                */
 t_racc:	TRAP_ENTRY(0x20, do_reg_access)     /* General Register Access Error */
-t_iacce:TRAP_ENTRY(0x21, sparc_fault)       /* Instr Access Error    */
+t_iacce:BAD_TRAP(0x21)                      /* Instr Access Error            */
 t_bad22:BAD_TRAP(0x22) BAD_TRAP(0x23)
 t_cpdis:TRAP_ENTRY(0x24, do_cp_disabled)    /* Co-Processor Disabled         */
 t_uflsh:TRAP_ENTRY(0x25, do_bad_flush)      /* Unimplemented FLUSH inst.     */
 t_bad26:BAD_TRAP(0x26) BAD_TRAP(0x27)
 t_cpexc:TRAP_ENTRY(0x28, do_cp_exception)   /* Co-Processor Exception        */
-t_dacce:TRAP_ENTRY(0x29, sparc_fault)       /* Data Access Error     */
+t_dacce:BAD_TRAP(0x29)                      /* Data Access Error             */
 t_hwdz:	TRAP_ENTRY(0x2a, do_hw_divzero)     /* Division by zero, you lose... */
-t_dserr:TRAP_ENTRY(0x2b, sparc_fault)       /* Data Store Error      */
-t_daccm:TRAP_ENTRY(0x2c, sparc_fault)       /* Data Access MMU-Miss  */
+t_dserr:BAD_TRAP(0x2b)                      /* Data Store Error              */
+t_daccm:BAD_TRAP(0x2c)                      /* Data Access MMU-Miss          */
 t_bad2d:BAD_TRAP(0x2d) BAD_TRAP(0x2e) BAD_TRAP(0x2f) BAD_TRAP(0x30) BAD_TRAP(0x31)
 t_bad32:BAD_TRAP(0x32) BAD_TRAP(0x33) BAD_TRAP(0x34) BAD_TRAP(0x35) BAD_TRAP(0x36)
 t_bad37:BAD_TRAP(0x37) BAD_TRAP(0x38) BAD_TRAP(0x39) BAD_TRAP(0x3a) BAD_TRAP(0x3b)
-t_iaccm:TRAP_ENTRY(0x3c, sparc_fault)       /* Instr Access MMU-Miss */
+t_iaccm:BAD_TRAP(0x3c)                      /* Instr Access MMU-Miss         */
 t_bad3d:BAD_TRAP(0x3d) BAD_TRAP(0x3e) BAD_TRAP(0x3f) BAD_TRAP(0x40) BAD_TRAP(0x41)
 t_bad42:BAD_TRAP(0x42) BAD_TRAP(0x43) BAD_TRAP(0x44) BAD_TRAP(0x45) BAD_TRAP(0x46)
 t_bad47:BAD_TRAP(0x47) BAD_TRAP(0x48) BAD_TRAP(0x49) BAD_TRAP(0x4a) BAD_TRAP(0x4b)
@@ -186,16 +186,6 @@
 /* This was the only reasonable way I could think of to properly align
  * these page-table data structures.
  */
-
-	.globl C_LABEL(auxio_reg_addr)
-C_LABEL(auxio_reg_addr):	.skip	(PAGE_SIZE)
-
-	.globl C_LABEL(clock_reg_addr)
-C_LABEL(clock_reg_addr):	.skip	(PAGE_SIZE*5)
-
-	.globl C_LABEL(int_reg_addr)
-C_LABEL(int_reg_addr):		.skip	(PAGE_SIZE*5)
-
 	.globl C_LABEL(bootup_user_stack)
 	.globl C_LABEL(bootup_kernel_stack)
 	.globl C_LABEL(pg0)
@@ -279,21 +269,6 @@
 		ldd	[%g2 + 0x8], %g4
 		std	%g4, [%g3 + 0x8]	! Copy proms handler
 
-		/* Copy over the Prom/debugger's trap entry points. */
-copy_prom_bpoint:
-		or	%g0, (0xfe<<4), %g2
-		or	%g1, %g2, %g2
-		set	dbtrap, %g3
-		sub	%g3, %l6, %g3
-		ldd	[%g2], %g4
-		std	%g4, [%g3]
-		ldd	[%g2 + 0x8], %g4
-		std	%g4, [%g3 + 0x8]
-		ldd	[%g2 + 0x10], %g4
-		std	%g4, [%g3 + 0x10]
-		ldd	[%g2 + 0x18], %g4
-		std	%g4, [%g3 + 0x18]
-
 /* Must determine whether we are on a sun4c MMU, SRMMU, or SUN4/400 MUTANT
  * MMU so we can remap ourselves properly.  DONT TOUCH %l0 thru %l5 in these
  * remapping routines, we need their values afterwards!
@@ -652,7 +627,7 @@
 
 		/* I want a kernel stack NOW! */
 		set	C_LABEL(bootup_user_stack), %g1
-		add	%g1, (PAGE_SIZE - STACKFRAME_SZ - TRACEREG_SZ), %sp
+		add	%g1, (PAGE_SIZE - REGWIN_SZ), %sp
 		mov	0, %fp			/* And for good luck */
 
 		/* Zero out our BSS section. */
@@ -673,7 +648,7 @@
 		st	%g4, [%g2]
 
 		/* So now this should work. */
-		LOAD_CURRENT(g2)
+		LOAD_CURRENT(g2, g4)
 		set	C_LABEL(bootup_kernel_stack), %g4
 		st	%g4, [%g2 + TASK_KSTACK_PG]
 		st	%g0, [%g2 + THREAD_UMASK]
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/kernel/ioport.c linux/arch/sparc/kernel/ioport.c
--- v1.3.70/linux/arch/sparc/kernel/ioport.c	Sat Nov 25 19:04:36 1995
+++ linux/arch/sparc/kernel/ioport.c	Mon Mar  4 08:49:55 1996
@@ -1,4 +1,4 @@
-/* $Id: ioport.c,v 1.12 1995/11/25 00:58:07 davem Exp $
+/* $Id: ioport.c,v 1.14 1996/01/03 03:34:41 davem Exp $
  * ioport.c:  Simple io mapping allocator.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -54,20 +54,19 @@
 	unsigned long addr = (unsigned long) address;
 	unsigned long offset = (addr & (~PAGE_MASK));
 
-	if (virtual){
+	if (virtual)
 		vaddr = (unsigned long) virtual;
-	} else {
+	else
 		vaddr = next_free_region;
-	}
 		
 	len += offset;
-	if (((unsigned long) virtual + len) > (IOBASE_VADDR + IOBASE_LEN)){
-		printk ("alloc_io: Mapping ouside IOBASE area\n");
-		prom_halt ();
+	if(((unsigned long) virtual + len) > (IOBASE_VADDR + IOBASE_LEN)) {
+		prom_printf("alloc_io: Mapping ouside IOBASE area\n");
+		prom_halt();
 	}
-	if (check_region ((vaddr | offset), len)){
-		printk ("alloc_io: 0x%lx is already in use\n", vaddr);
-		prom_halt ();
+	if(check_region ((vaddr | offset), len)) {
+		prom_printf("alloc_io: 0x%lx is already in use\n", vaddr);
+		prom_halt();
 	}
 
 	/* Tell Linux resource manager about the mapping */
@@ -75,10 +74,10 @@
 
 	base_address = vaddr;
 	/* Do the actual mapping */
-	for (; len > 0; len -= PAGE_SIZE){
-		mapioaddr (addr, vaddr, bus_type, rdonly);
+	for (; len > 0; len -= PAGE_SIZE) {
+		mapioaddr(addr, vaddr, bus_type, rdonly);
 		vaddr += PAGE_SIZE;
-		addr  += PAGE_SIZE;
+		addr += PAGE_SIZE;
 		if (!virtual)
 			next_free_region += PAGE_SIZE;
 	}
@@ -99,13 +98,13 @@
 	unsigned long vaddr, base_address;
 
 	vaddr = dvma_next_free;
-	if (check_region (vaddr, len)){
-		printk ("alloc_dma: 0x%lx is already in use\n", vaddr);
-		prom_halt ();
+	if(check_region (vaddr, len)) {
+		prom_printf("alloc_dma: 0x%lx is already in use\n", vaddr);
+		prom_halt();
 	}
-	if (vaddr + len > (DVMA_VADDR + DVMA_LEN)){
-		printk ("alloc_dvma: out of dvma memory\n");
-		prom_halt ();
+	if(vaddr + len > (DVMA_VADDR + DVMA_LEN)) {
+		prom_printf("alloc_dvma: out of dvma memory\n");
+		prom_halt();
 	}
 
 	/* Basically these can be mapped just like any old
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/kernel/irq.c linux/arch/sparc/kernel/irq.c
--- v1.3.70/linux/arch/sparc/kernel/irq.c	Sat Mar  2 10:43:21 1996
+++ linux/arch/sparc/kernel/irq.c	Mon Mar  4 08:49:55 1996
@@ -1,4 +1,4 @@
-/*  $Id: irq.c,v 1.29 1995/11/25 00:58:08 davem Exp $
+/*  $Id: irq.c,v 1.34 1996/02/20 07:45:04 davem Exp $
  *  arch/sparc/kernel/irq.c:  Interrupt request handling routines. On the
  *                            Sparc the IRQ's are basically 'cast in stone'
  *                            and you are supposed to probe the prom's device
@@ -34,8 +34,7 @@
 unsigned char *interrupt_enable = 0;
 struct sun4m_intregs *sun4m_interrupts;
 
-void
-sun4c_disable_irq(unsigned int irq_nr)
+void sun4c_disable_irq(unsigned int irq_nr)
 {
 	unsigned long flags;
 	unsigned char current_mask, new_mask;
@@ -60,21 +59,20 @@
 	default:
 		restore_flags(flags);
 		return;
-	};
-  
+	}
 	*interrupt_enable = new_mask;
 	restore_flags(flags);
 }
 
-void
-sun4m_disable_irq(unsigned int irq_nr)
+void sun4m_disable_irq(unsigned int irq_nr)
 {
+#if 0
 	printk("IRQ routines not yet written for the sun4m\n");
 	panic("disable_irq: Unsupported arch.");
+#endif
 }
 
-void
-disable_irq(unsigned int irq_nr)
+void disable_irq(unsigned int irq_nr)
 {
 	switch(sparc_cpu_model) {
 	case sun4c:
@@ -82,13 +80,13 @@
 		break;
 	case sun4m:
 		sun4m_disable_irq(irq_nr);
+		break;
 	default:
 		panic("disable_irq: Unsupported arch.");
 	}
 }
 
-void
-sun4c_enable_irq(unsigned int irq_nr)
+void sun4c_enable_irq(unsigned int irq_nr)
 {
 	unsigned long flags;
 	unsigned char current_mask, new_mask;
@@ -113,21 +111,20 @@
 	default:
 		restore_flags(flags);
 		return;
-	};
-
+	}
 	*interrupt_enable = new_mask;
 	restore_flags(flags);
 }
 
-void
-sun4m_enable_irq(unsigned int irq_nr)
+void sun4m_enable_irq(unsigned int irq_nr)
 {
+#if 0
 	printk("IRQ routines not written for the sun4m yet.\n");
 	panic("IRQ unsupported arch.");
+#endif
 }
 
-void
-enable_irq(unsigned int irq_nr)
+void enable_irq(unsigned int irq_nr)
 {
 	switch(sparc_cpu_model) {
 	case sun4c:
@@ -144,17 +141,30 @@
 /*
  * Initial irq handlers.
  */
-static struct irqaction timer_irq = { NULL, 0, 0, NULL, NULL, NULL};
-static struct irqaction cascade_irq = { NULL, 0, 0, NULL, NULL, NULL};
-static struct irqaction math_irq = { NULL, 0, 0, NULL, NULL, NULL};
+extern void timer_interrupt(int, void *, struct pt_regs *);
+extern void rs_interrupt(int, void *, struct pt_regs *);
+
+static struct irqaction timer_irq = {
+	timer_interrupt,
+	SA_INTERRUPT,
+	0, "timer",
+	NULL, NULL
+};
+
+static struct irqaction serial_irq = {
+	rs_interrupt,
+	SA_INTERRUPT,
+	0, "zilog serial",
+	NULL, NULL
+};
 
 static struct irqaction *irq_action[16] = {
 	  NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL,
-	  NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL
+	  NULL, NULL, &timer_irq, NULL, &serial_irq, NULL , NULL, NULL
 };
 
-int
-get_irq_list(char *buf)
+
+int get_irq_list(char *buf)
 {
 	int i, len = 0;
 	struct irqaction * action;
@@ -177,8 +187,7 @@
 	return len;
 }
 
-void
-free_irq(unsigned int irq, void *dev_id)
+void free_irq(unsigned int irq, void *dev_id)
 {
 	struct irqaction * action = *(irq + irq_action);
 	struct irqaction * tmp = NULL;
@@ -193,35 +202,33 @@
 		return;
 	}
 	if (dev_id) {
-	    for (; action; action = action->next) {
-	        if (action->dev_id == dev_id) break;
-		tmp = action;
-	    }
-	    if (!action) {
-		printk("Trying to free free shared IRQ%d\n",irq);
-		return;
-	    }
+		for (; action; action = action->next) {
+			if (action->dev_id == dev_id) break;
+			tmp = action;
+		}
+		if (!action) {
+			printk("Trying to free free shared IRQ%d\n",irq);
+			return;
+		}
 	} else if (action->flags & SA_SHIRQ) {
-	    printk("Trying to free shared IRQ%d with NULL device ID\n", irq);
-	    return;
+		printk("Trying to free shared IRQ%d with NULL device ID\n", irq);
+		return;
 	}
         save_flags(flags); cli();
-	if (action && tmp) {
-	    tmp->next = action->next;
-	} else {
-	    *(irq + irq_action) = action->next;
-	}
+	if (action && tmp)
+		tmp->next = action->next;
+	else
+		*(irq + irq_action) = action->next;
+
 	kfree_s(action, sizeof(struct irqaction));
 
-	if (!(*(irq + irq_action))) {
-	    disable_irq(irq);
-	}
+	if (!(*(irq + irq_action)))
+		disable_irq(irq);
 
         restore_flags(flags);
 }
 
-void
-unexpected_irq(int irq, struct pt_regs * regs)
+void unexpected_irq(int irq, void *dev_id, struct pt_regs * regs)
 {
         int i;
 	struct irqaction * action = *(irq + irq_action);
@@ -233,23 +240,22 @@
         for (i = 0; i < 16; i++)
                 if (action->handler)
                         prom_printf("[%s:%d:0x%x] ", action->name, (int) i,
-			       (unsigned int) action->handler);
+				    (unsigned int) action->handler);
         printk("AIEEE\n");
 	panic("bogus interrupt received");
 }
 
-void
-handler_irq(int irq, struct pt_regs * regs)
+void handler_irq(int irq, struct pt_regs * regs)
 {
 	struct irqaction * action = *(irq + irq_action);
 
 	kstat.interrupts[irq]++;
 	while (action) {
-	    if (!action->handler)
-	        unexpected_irq(irq, action->dev_id, regs);
-	    else
-		action->handler(irq, action->dev_id, regs);
-	    action = action->next;
+		if (!action->handler)
+			unexpected_irq(irq, action->dev_id, regs);
+		else
+			action->handler(irq, action->dev_id, regs);
+		action = action->next;
 	}
 }
 
@@ -260,17 +266,15 @@
  * IRQ's should use this format: notably the keyboard/timer
  * routines.
  */
-asmlinkage void
-do_IRQ(int irq, struct pt_regs * regs)
+asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
 {
 	struct irqaction * action = *(irq + irq_action);
 
 	kstat.interrupts[irq]++;
 	while (action) {
-	    action->handler(irq, action->dev_id, regs);
-	    action = action->next;
+		action->handler(irq, action->dev_id, regs);
+		action = action->next;
 	}
-	return;
 }
 
 /*
@@ -278,37 +282,35 @@
  * stuff - the handler is also running with interrupts disabled unless
  * it explicitly enables them later.
  */
-asmlinkage void
-do_fast_IRQ(int irq)
+asmlinkage void do_fast_IRQ(int irq)
 {
 	kstat.interrupts[irq]++;
 	printk("Got FAST_IRQ number %04lx\n", (long unsigned int) irq);
 	return;
 }
 
-int
-request_fast_irq(unsigned int irq, void (*handler)(int, struct pt_regs *),
-		 unsigned long irqflags, const char *devname, void *dev_id)
-)
+/* Fast IRQ's on the Sparc can only have one routine attached to them,
+ * thus no sharing possible.
+ */
+int request_fast_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+		     unsigned long irqflags, const char *devname)
 {
-	struct irqaction * action, *tmp = NULL;
+	struct irqaction *action;
 	unsigned long flags;
 
 	if(irq > 14)
 		return -EINVAL;
-	if (!handler)
-	    return -EINVAL;
+	if(!handler)
+		return -EINVAL;
 	action = *(irq + irq_action);
-	if (action) {
-	    if ((action->flags & SA_SHIRQ) && (irqflags & SA_SHIRQ)) {
-		for (tmp = action; tmp->next; tmp = tmp->next);
-	    } else {
+	if(action) {
+		if(action->flags & SA_SHIRQ)
+			panic("Trying to register fast irq when already shared.\n");
+		if(irqflags & SA_SHIRQ)
+			panic("Trying to register fast irq as shared.\n");
+
+		/* Anyway, someone already owns it so cannot be made fast. */
 		return -EBUSY;
-	    }
-	    if ((action->flags & SA_INTERRUPT) ^ (irqflags & SA_INTERRUPT)) {
-	      printk("Attempt to mix fast and slow interrupts on IRQ%d denied\n", irq);
-	      return -EBUSY;
-	    }   
 	}
 
 	save_flags(flags); cli();
@@ -316,8 +318,8 @@
 	action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL);
 
 	if (!action) { 
-	    restore_flags(flags);
-	    return -ENOMEM;
+		restore_flags(flags);
+		return -ENOMEM;
 	}
 
 	/* Dork with trap table if we get this far. */
@@ -332,23 +334,16 @@
 	action->flags = irqflags;
 	action->mask = 0;
 	action->name = devname;
-	action->dev_id = dev_id;
+	action->dev_id = NULL;
 
-	if (tmp) {
-	    tmp->next = action;
-	} else {
-	    *(irq + irq_action) = action;
-	}
+	*(irq + irq_action) = action;
 
 	restore_flags(flags);
 	return 0;
 }
 
-extern void probe_clock(void);
-		
-int
-request_irq(unsigned int irq, void (*handler)(int, struct pt_regs *),
-	    unsigned long irqflags, const char * devname, void *dev_id)
+int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+		unsigned long irqflags, const char * devname, void *dev_id)
 {
 	struct irqaction * action, *tmp = NULL;
 	unsigned long flags;
@@ -360,22 +355,23 @@
 	    return -EINVAL;
 	action = *(irq + irq_action);
 	if (action) {
-	    if ((action->flags & SA_SHIRQ) && (irqflags & SA_SHIRQ)) {
-		for (tmp = action; tmp->next; tmp = tmp->next);
-	    } else {
-		return -EBUSY;
-	    }
-	    if ((action->flags & SA_INTERRUPT) ^ (irqflags & SA_INTERRUPT)) {
-	      printk("Attempt to mix fast and slow interrupts on IRQ%d denied\n", irq);
-	      return -EBUSY;
-	    }   
+		if ((action->flags & SA_SHIRQ) && (irqflags & SA_SHIRQ)) {
+			for (tmp = action; tmp->next; tmp = tmp->next);
+		} else {
+			return -EBUSY;
+		}
+		if ((action->flags & SA_INTERRUPT) ^ (irqflags & SA_INTERRUPT)) {
+			printk("Attempt to mix fast and slow interrupts on IRQ%d denied\n", irq);
+			return -EBUSY;
+		}   
 	}
+
 	save_flags(flags); cli();
 	action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL);
 
 	if (!action) { 
-	    restore_flags(flags);
-	    return -ENOMEM;
+		restore_flags(flags);
+		return -ENOMEM;
 	}
 
 	action->handler = handler;
@@ -385,14 +381,12 @@
 	action->next = NULL;
 	action->dev_id = dev_id;
 
-	if (tmp) {
-	    tmp->next = action;
-	} else {
-	    *(irq + irq_action) = action;
-	}
+	if (tmp)
+		tmp->next = action;
+	else
+		*(irq + irq_action) = action;
+
 	enable_irq(irq);
-	if(irq == 10)
-		probe_clock();
 	restore_flags(flags);
 	return 0;
 }
@@ -410,8 +404,7 @@
   return 0;
 }
 
-void
-sun4c_init_IRQ(void)
+void sun4c_init_IRQ(void)
 {
 	struct linux_prom_registers int_regs[2];
 	int ie_node;
@@ -422,19 +415,15 @@
 		panic("Cannot find /interrupt-enable node");
 	/* Depending on the "address" property is bad news... */
 	prom_getproperty(ie_node, "reg", (char *) int_regs, sizeof(int_regs));
-	sparc_alloc_io(int_regs[0].phys_addr, (void *) INTREG_VADDR,
-		       int_regs[0].reg_size, "sun4c_interrupts",
-		       int_regs[0].which_io, 0x0);
-
-	interrupt_enable = (char *) INTREG_VADDR;
-
-	/* Default value, accept interrupts, but no one is actually active */
+	interrupt_enable = (char *) sparc_alloc_io(int_regs[0].phys_addr, 0,
+						   int_regs[0].reg_size,
+						   "sun4c_interrupts",
+						   int_regs[0].which_io, 0x0);
 	*interrupt_enable = (SUN4C_INT_ENABLE);
-	sti(); /* Turn irq's on full-blast. */
+	sti();
 }
 
-void
-sun4m_init_IRQ(void)
+void sun4m_init_IRQ(void)
 {
 	int ie_node;
 
@@ -442,7 +431,6 @@
 	int num_regs;
 
 	cli();
-
 	if((ie_node = prom_searchsiblings(prom_getchild(prom_root_node), "obio")) == 0 ||
 	   (ie_node = prom_getchild (ie_node)) == 0 ||
 	   (ie_node = prom_searchsiblings (ie_node, "interrupt")) == 0)
@@ -455,22 +443,18 @@
 	prom_apply_obio_ranges(int_regs, num_regs);
 
 	/* Map the interrupt registers for all possible cpus. */
-	sparc_alloc_io(int_regs[0].phys_addr, (void *) INTREG_VADDR,
-		       PAGE_SIZE*NCPUS, "interrupts_percpu",
-		       int_regs[0].which_io, 0x0);
+	sun4m_interrupts = sparc_alloc_io(int_regs[0].phys_addr, 0,
+					  PAGE_SIZE*NCPUS, "interrupts_percpu",
+					  int_regs[0].which_io, 0x0);
 
 	/* Map the system interrupt control registers. */
-	sparc_alloc_io(int_regs[num_regs-1].phys_addr,
-		       (void *) INTREG_VADDR+(NCPUS*PAGE_SIZE),
+	sparc_alloc_io(int_regs[num_regs-1].phys_addr, 0,
 		       int_regs[num_regs-1].reg_size, "interrupts_system",
 		       int_regs[num_regs-1].which_io, 0x0);
-
-	sun4m_interrupts = (struct sun4m_intregs *) INTREG_VADDR;
 	sti();
 }
 
-void
-init_IRQ(void)
+void init_IRQ(void)
 {
 	switch(sparc_cpu_model) {
 	case sun4c:
@@ -480,7 +464,7 @@
 		sun4m_init_IRQ();
 		break;
 	default:
-		panic("Cannot initialize IRQ's on this Sun machine...");
+		prom_printf("Cannot initialize IRQ's on this Sun machine...");
 		break;
-	};
+	}
 }
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/kernel/ksyms.c linux/arch/sparc/kernel/ksyms.c
--- v1.3.70/linux/arch/sparc/kernel/ksyms.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/kernel/ksyms.c	Mon Mar  4 08:49:55 1996
@@ -0,0 +1,34 @@
+/* $Id: ksyms.c,v 1.1 1996/02/25 06:30:18 davem Exp $
+ * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+
+/* We really haven't played around with modules at all in our
+ * port, but this is here as a starting point for when we do.
+ * One thing to note is that the way the symbols of the mul/div
+ * support routines are named is a mess, they all start with
+ * a '.' which makes it a bitch to export, we'll see.
+ */
+
+extern void bcopy (const char *src, char *dst, int len);
+extern void * memmove(void *,const void *,size_t);
+extern void * memcpy(void *,const void *,size_t);
+
+static struct symbol_table arch_symbol_table = {
+#include <linux/symtab_begin.h>
+	/* platform dependent support */
+	X(bcopy),
+	X(memmove),
+	X(memcpy),
+#include <linux/symtab_end.h>
+};
+
+void arch_syms_export(void)
+{
+	register_symtab(&arch_symbol_table);
+}
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/kernel/probe.c linux/arch/sparc/kernel/probe.c
--- v1.3.70/linux/arch/sparc/kernel/probe.c	Mon Nov 27 12:48:27 1995
+++ linux/arch/sparc/kernel/probe.c	Mon Mar  4 08:49:55 1996
@@ -1,4 +1,4 @@
-/* $Id: probe.c,v 1.39 1995/11/26 00:54:37 davem Exp $
+/* $Id: probe.c,v 1.42 1995/12/26 01:38:08 davem Exp $
  * probe.c: Preliminary device tree probing routines...
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -187,9 +187,6 @@
 			    fpu_vers);
 		sparc_fpu_type[cpuid] = linux_sparc_fpu[31].fp_name;
 	}
-
-	printk("cpu%d CPU: %s \n", cpuid, sparc_cpu_type[cpuid]);
-	printk("cpu%d FPU: %s \n", cpuid, sparc_fpu_type[cpuid]);
 }
 
 void
@@ -212,8 +209,9 @@
 		sun4c_vacinfo.log2lsize = 5;
 		break;
 	default:
-		printk("probe_vac: Didn't expect vac-linesize of %d, halting\n",
+		prom_printf("probe_vac: Didn't expect vac-linesize of %d, halting\n",
 			    sun4c_vacinfo.linesize);
+		prom_halt();
 	};
 
 	propval = prom_getintdefault(prom_root_node, "vac_hwflush", -1);
@@ -222,49 +220,13 @@
 							 "vac-hwflush", 0) :
 				      propval);
 
-	printk("SUN4C: VAC size %d line size %d using %s flushes ",
-	       sun4c_vacinfo.num_bytes, sun4c_vacinfo.linesize,
-	       (sun4c_vacinfo.do_hwflushes ? "hardware" : "software"));
 	if(sun4c_vacinfo.num_bytes != 65536) {
-		printk("WEIRD Sun4C VAC cache size, tell davem");
+		prom_printf("WEIRD Sun4C VAC cache size, tell davem");
 		prom_halt();
 	}
 
-	/* setup the low-level assembly routine ptrs */
-	if(sun4c_vacinfo.do_hwflushes) {
-		if(sun4c_vacinfo.linesize == 16) {
-			sun4c_ctxflush = (unsigned long)sun4c_ctxflush_hw64KB16B;
-			sun4c_segflush = (unsigned long)sun4c_segflush_hw64KB16B;
-			sun4c_pgflush = (unsigned long)sun4c_pgflush_hw64KB16B;
-		} else if(sun4c_vacinfo.linesize == 32) {
-			sun4c_ctxflush = (unsigned long)sun4c_ctxflush_hw64KB32B;
-			sun4c_segflush = (unsigned long)sun4c_segflush_hw64KB32B;
-			sun4c_pgflush = (unsigned long)sun4c_pgflush_hw64KB32B;
-		} else {
-			printk("WEIRD Sun4C VAC cache line size, tell davem\n");
-			prom_halt();
-		}
-	} else {
-		if(sun4c_vacinfo.linesize == 16) {
-			sun4c_ctxflush = (unsigned long)sun4c_ctxflush_sw64KB16B;
-			sun4c_segflush = (unsigned long)sun4c_segflush_sw64KB16B;
-			sun4c_pgflush = (unsigned long)sun4c_pgflush_sw64KB16B;
-		} else if(sun4c_vacinfo.linesize == 32) {
-			sun4c_ctxflush = (unsigned long)sun4c_ctxflush_sw64KB32B;
-			sun4c_segflush = (unsigned long)sun4c_segflush_sw64KB32B;
-			sun4c_pgflush = (unsigned long)sun4c_pgflush_sw64KB32B;
-		} else {
-			printk("WEIRD Sun4C VAC cache line size, tell davem\n");
-			prom_halt();
-		}
-	}
-
-
 	sun4c_flush_all();
 	sun4c_enable_vac();
-	printk("enabled\n");
-
-	return;
 }
 
 extern int num_segmaps, num_contexts;
@@ -284,9 +246,6 @@
 		/* A sun4, sun4c or sun4e. */
 		num_segmaps = prom_getintdefault(prom_root_node, "mmu-npmg", 128);
 		num_contexts = find_mmu_num_contexts(prom_root_node);
-
-		printk("cpu%d MMU segmaps: %d     MMU contexts: %d\n", cpuid,
-			    num_segmaps, num_contexts);
 		break;
 	default:
 		printk("cpu%d probe_mmu: sparc_cpu_model botch\n", cpuid);
@@ -444,9 +403,6 @@
 	/* Map the register both read and write */
 	sparc_alloc_io(auxregs[0].phys_addr, (void *) AUXIO_VADDR,
 		       auxregs[0].reg_size, "auxilliaryIO", auxregs[0].which_io, 0x0);
-	printk("Mapped AUXIO at paddr %08lx vaddr %08lx\n",
-		    (unsigned long) auxregs[0].phys_addr,
-		    (unsigned long) AUXIO_VADDR);
 }
 
 extern unsigned long probe_memory(void);
@@ -495,7 +451,9 @@
 	linux_num_cpus = cpu_ctr;
 	for(i=0; i<cpu_ctr; i++) {
 		prom_getstring(cpu_nds[i], "name", node_str, sizeof(node_str));
+#if 0
 		printk("cpu%d: %s \n", i, node_str);
+#endif
 	}
 
 	probe_cpu();
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/kernel/process.c linux/arch/sparc/kernel/process.c
--- v1.3.70/linux/arch/sparc/kernel/process.c	Sat Nov 25 19:04:36 1995
+++ linux/arch/sparc/kernel/process.c	Mon Mar  4 08:49:55 1996
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.29 1995/11/25 00:58:17 davem Exp $
+/*  $Id: process.c,v 1.42 1996/02/20 07:45:08 davem Exp $
  *  linux/arch/sparc/kernel/process.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -26,10 +26,13 @@
 #include <asm/system.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
+#include <asm/delay.h>
 #include <asm/processor.h>
 #include <asm/psr.h>
 
-int current_user_segment = USER_DS; /* the return value from get_fs */
+extern void fpsave(unsigned long *, unsigned long *, void *, unsigned long *);
+
+int active_ds = USER_DS;
 
 /*
  * the idle loop on a Sparc... ;)
@@ -46,9 +49,15 @@
 	}
 }
 
+extern char saved_command_line[];
+
 void hard_reset_now(void)
 {
-	prom_halt();
+	sti();
+	udelay(8000);
+	cli();
+	prom_feval("reset");
+	panic("Reboot failed!");
 }
 
 void show_regwindow(struct reg_window *rw)
@@ -84,9 +93,15 @@
  */
 void exit_thread(void)
 {
-	if(last_task_used_math == current)
+	flush_user_windows();
+	if(last_task_used_math == current) {
+		/* Keep process from leaving FPU in a bogon state. */
+		put_psr(get_psr() | PSR_EF);
+		fpsave(&current->tss.float_regs[0], &current->tss.fsr,
+		       &current->tss.fpqueue[0], &current->tss.fpqdepth);
 		last_task_used_math = NULL;
-	mmu_exit_hook(current);
+	}
+	mmu_exit_hook();
 }
 
 /*
@@ -94,29 +109,33 @@
  */
 void release_thread(struct task_struct *dead_task)
 {
-	mmu_release_hook(dead_task);
 }
 
 void flush_thread(void)
 {
 	/* Make sure old user windows don't get in the way. */
-	mmu_flush_hook(current);
 	flush_user_windows();
-	current->signal &= ~(1<<(SIGILL-1));
 	current->tss.w_saved = 0;
 	current->tss.uwinmask = 0;
-
 	current->tss.sig_address = 0;
 	current->tss.sig_desc = 0;
-
-	/* Signal stack state does not inherit. XXX Really? XXX */
 	current->tss.sstk_info.cur_status = 0;
 	current->tss.sstk_info.the_stack = 0;
 
+	if(last_task_used_math == current) {
+		/* Clean the fpu. */
+		put_psr(get_psr() | PSR_EF);
+		fpsave(&current->tss.float_regs[0], &current->tss.fsr,
+		       &current->tss.fpqueue[0], &current->tss.fpqdepth);
+	}
+
 	memset(&current->tss.reg_window[0], 0,
 	       (sizeof(struct reg_window) * NSWINS));
 	memset(&current->tss.rwbuf_stkptrs[0], 0,
 	       (sizeof(unsigned long) * NSWINS));
+	mmu_flush_hook();
+	/* Now, this task is no longer a kernel thread. */
+	current->tss.flags &= ~SPARC_FLAG_KTHREAD;
 }
 
 /*
@@ -125,7 +144,12 @@
  * Parent -->  %o0 == childs  pid, %o1 == 0
  * Child  -->  %o0 == parents pid, %o1 == 1
  *
- * I'm feeling sick...
+ * NOTE: We have a seperate fork kpsr/kwim because
+ *       the parent could change these values between
+ *       sys_fork invocation and when we reach here
+ *       if the parent should sleep while trying to
+ *       allocate the task_struct and kernel stack in
+ *       do_fork().
  */
 extern void ret_sys_call(void);
 
@@ -133,34 +157,37 @@
 		 struct task_struct *p, struct pt_regs *regs)
 {
 	struct pt_regs *childregs;
-	struct sparc_stackf *old_stack, *new_stack;
-	unsigned long stack_offset, kthread_usp = 0;
+	struct reg_window *old_stack, *new_stack;
+	unsigned long stack_offset;
 
-	mmu_task_cacheflush(current);
-	p->tss.context = -1;
+	if(last_task_used_math == current) {
+		put_psr(get_psr() | PSR_EF);
+		fpsave(&p->tss.float_regs[0], &p->tss.fsr,
+		       &p->tss.fpqueue[0], &p->tss.fpqdepth);
+	}
 
 	/* Calculate offset to stack_frame & pt_regs */
-	stack_offset = (PAGE_SIZE - TRACEREG_SZ);
+	stack_offset = ((PAGE_SIZE*2) - TRACEREG_SZ);
+	if(regs->psr & PSR_PS)
+		stack_offset -= REGWIN_SZ;
 	childregs = ((struct pt_regs *) (p->kernel_stack_page + stack_offset));
 	*childregs = *regs;
-	new_stack = (((struct sparc_stackf *) childregs) - 1);
-	old_stack = (((struct sparc_stackf *) regs) - 1);
+	new_stack = (((struct reg_window *) childregs) - 1);
+	old_stack = (((struct reg_window *) regs) - 1);
 	*new_stack = *old_stack;
-	p->tss.ksp = (unsigned long) new_stack;
+	p->tss.ksp = p->saved_kernel_stack = (unsigned long) new_stack;
 	p->tss.kpc = (((unsigned long) ret_sys_call) - 0x8);
+	p->tss.kpsr = current->tss.fork_kpsr;
+	p->tss.kwim = current->tss.fork_kwim;
+	p->tss.kregs = childregs;
+	childregs->u_regs[UREG_FP] = sp;
 
-	/* As a special case, if this is a kernel fork we need
-	 * to give the child a new fresh stack for when it returns
-	 * from the syscall. (ie. the "user" stack)  This happens
-	 * only once and we count on the page acquisition happening
-	 * successfully.
-	 */
 	if(regs->psr & PSR_PS) {
-		 unsigned long n_stack = get_free_page(GFP_KERNEL);
-		 childregs->u_regs[UREG_FP] = (n_stack | (sp & 0xfff));
-		 memcpy((char *)n_stack,(char *)(sp & PAGE_MASK),PAGE_SIZE);
-		 kthread_usp = n_stack;
-	}
+		stack_offset += TRACEREG_SZ;
+		childregs->u_regs[UREG_FP] = p->kernel_stack_page + stack_offset;
+		p->tss.flags |= SPARC_FLAG_KTHREAD;
+	} else
+		p->tss.flags &= ~SPARC_FLAG_KTHREAD;
 
 	/* Set the return value for the child. */
 	childregs->u_regs[UREG_I0] = current->pid;
@@ -168,8 +195,6 @@
 
 	/* Set the return value for the parent. */
 	regs->u_regs[UREG_I1] = 0;
-
-	mmu_fork_hook(p, kthread_usp);
 }
 
 /*
@@ -177,6 +202,31 @@
  */
 void dump_thread(struct pt_regs * regs, struct user * dump)
 {
+	unsigned long first_stack_page;
+
+	dump->magic = SUNOS_CORE_MAGIC;
+	dump->len = sizeof(struct user);
+	dump->regs.psr = regs->psr;
+	dump->regs.pc = regs->pc;
+	dump->regs.npc = regs->npc;
+	dump->regs.y = regs->y;
+	/* fuck me plenty */
+	memcpy(&dump->regs.regs[0], &regs->u_regs[1], (sizeof(unsigned long) * 15));
+	dump->uexec = current->tss.core_exec;
+	dump->u_tsize = (((unsigned long) current->mm->end_code) -
+		((unsigned long) current->mm->start_code)) & ~(PAGE_SIZE - 1);
+	dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1)));
+	dump->u_dsize -= dump->u_tsize;
+	dump->u_dsize &= ~(PAGE_SIZE - 1);
+	first_stack_page = (regs->u_regs[UREG_FP] & ~(PAGE_SIZE - 1));
+	dump->u_ssize = (TASK_SIZE - first_stack_page) & ~(PAGE_SIZE - 1);
+	memcpy(&dump->fpu.fpstatus.fregs.regs[0], &current->tss.float_regs[0], (sizeof(unsigned long) * 32));
+	dump->fpu.fpstatus.fsr = current->tss.fsr;
+	dump->fpu.fpstatus.flags = dump->fpu.fpstatus.extra = 0;
+	dump->fpu.fpstatus.fpq_count = current->tss.fpqdepth;
+	memcpy(&dump->fpu.fpstatus.fpq[0], &current->tss.fpqueue[0],
+	       ((sizeof(unsigned long) * 2) * 16));
+	dump->sigcode = current->tss.sig_desc;
 }
 
 /*
@@ -198,7 +248,6 @@
 	char *filename;
 
 	flush_user_windows();
-	mmu_task_cacheflush(current);
 	error = getname((char *) regs->u_regs[UREG_I0], &filename);
 	if(error)
 		return error;
@@ -206,28 +255,4 @@
 			  (char **) regs->u_regs[UREG_I2], regs);
 	putname(filename);
 	return error;
-}
-
-void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp)
-{
-	unsigned long saved_psr = (regs->psr & (PSR_CWP)) | PSR_S;
-
-	memset(regs, 0, sizeof(struct pt_regs));
-	regs->pc = ((pc & (~3)) - 4); /* whee borken a.out header fields... */
-	regs->npc = regs->pc + 4;
-	regs->psr = saved_psr;
-	regs->u_regs[UREG_G1] = sp; /* Base of arg/env stack area */
-
-	/* XXX More mysterious netbsd garbage... XXX */
-	regs->u_regs[UREG_G2] = regs->u_regs[UREG_G7] = regs->npc;
-
-	/* Allocate one reg window because the first jump into
-	 * user mode will restore one register window by definition
-	 * of the 'rett' instruction.  Also, SunOS crt.o code
-	 * depends upon the arg/envp area being _exactly_ one
-	 * register window above %sp when the process begins
-	 * execution.
-	 */
-	sp -= REGWIN_SZ;
-	regs->u_regs[UREG_FP] = sp;
 }
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/kernel/rtrap.S linux/arch/sparc/kernel/rtrap.S
--- v1.3.70/linux/arch/sparc/kernel/rtrap.S	Sat Nov 25 19:04:36 1995
+++ linux/arch/sparc/kernel/rtrap.S	Mon Mar  4 08:49:55 1996
@@ -1,4 +1,4 @@
-/* $Id: rtrap.S,v 1.11 1995/11/25 00:58:19 davem Exp $
+/* $Id: rtrap.S,v 1.21 1996/02/20 07:45:11 davem Exp $
  * rtrap.S: Return from Sparc trap low-level code.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -45,16 +45,15 @@
 	.globl	ret_trap_entry, rtrap_patch1, rtrap_patch2
 	.globl	rtrap_patch3, rtrap_patch4, rtrap_patch5
 ret_trap_entry:
-	ld	[%sp + STACKFRAME_SZ + PT_PSR], %t_psr
+	ld	[%sp + REGWIN_SZ + PT_PSR], %t_psr
 	andcc	%t_psr, PSR_PS, %g0
 	bne	ret_trap_kernel
 	 nop
 
 	sethi	%hi(C_LABEL(need_resched)), %twin_tmp1
 	ld	[%twin_tmp1 + %lo(C_LABEL(need_resched))], %twin_tmp2
-	LOAD_CURRENT(twin_tmp1)
 
-	cmp	%twin_tmp2, 0x0
+	cmp	%twin_tmp2, 0
 	be	signal_p
 	 nop
 
@@ -70,41 +69,51 @@
 
 signal_p:
 	/* No signals for swapper. */
-	sethi	%hi(C_LABEL(init_task)), %twin_tmp3
-	or	%twin_tmp3, %lo(C_LABEL(init_task)), %twin_tmp3
+	LOAD_CURRENT(twin_tmp1, twin_tmp3)
+	set	C_LABEL(init_task), %twin_tmp3
 	cmp	%twin_tmp3, %twin_tmp1
 	be	ret_trap_continue
 	 nop
 
 	ld	[%twin_tmp1 + TASK_SIGNAL], %twin_tmp2
-	ld	[%twin_tmp1 + TASK_BLOCKED], %twin_tmp3
-	andncc	%twin_tmp2, %twin_tmp3, %twin_tmp2
+	ld	[%twin_tmp1 + TASK_BLOCKED], %o0
+	andncc	%twin_tmp2, %o0, %g0
 	be	ret_trap_continue
 	 nop
 
-	mov	%twin_tmp2, %o0		! oldmask
-	add	%sp, STACKFRAME_SZ, %o1	! pt_regs ptr
 	call	C_LABEL(do_signal)
-	 nop
+	 add	%sp, REGWIN_SZ, %o1	! pt_regs ptr
 
 	/* Fall through... */
 ret_trap_continue:
+	ld	[%sp + REGWIN_SZ + PT_PSR], %t_psr
 	wr	%t_psr, 0x0, %psr
 	WRITE_PAUSE
 
-	LOAD_CURRENT(twin_tmp2)
+	/* If not current fpu proc, disable fp-ops */
+	LOAD_CURRENT(twin_tmp2, twin_tmp1)
+	set	C_LABEL(last_task_used_math), %twin_tmp1
+	ld	[%twin_tmp1], %twin_tmp1
+	cmp	%twin_tmp2, %twin_tmp1
+	be	1f
+	 nop
+
+	set	PSR_EF, %twin_tmp1
+	andn	%t_psr, %twin_tmp1, %t_psr
+	st	%t_psr, [%sp + REGWIN_SZ + PT_PSR]
+
+1:
 	ld	[%twin_tmp2 + THREAD_W_SAVED], %twin_tmp1
 	orcc	%g0, %twin_tmp1, %g0
 	be	ret_trap_nobufwins
 	 nop
 
-	wr	%t_psr, 0x0, %psr
 	wr	%t_psr, PSR_ET, %psr
 	WRITE_PAUSE
 
 	mov	1, %o1
-	call	C_LABEL(do_sparc_winfault)
-	 add	%sp, STACKFRAME_SZ, %o0
+	call	C_LABEL(try_to_clear_window_buffer)
+	 add	%sp, REGWIN_SZ, %o0
 
 	b	ret_trap_entry
 	 nop
@@ -126,6 +135,7 @@
 		/* Calculate new %wim, we have to pull a register
 		 * window from the users stack.
 		 */
+ret_trap_pull_one_window:
 		rd	%wim, %t_wim
 		sll	%t_wim, 0x1, %twin_tmp1
 rtrap_patch1:	srl	%t_wim, 0x7, %twin_tmp2
@@ -159,23 +169,36 @@
 	jmp	%t_pc
 	rett	%t_npc
 	
+	/* HyperSparc special nop patching, if we are on a hypersparc
+	 * we nop the top two instructions and the first nop coming
+	 * up to be:
+	 * rd	%iccr, %g0  <-- flush on-chip instruction cache
+	 * jmp	%t_pc
+	 * rett	%t_npc
+	 */
+	nop
+	nop
+
 ret_trap_unaligned_pc:
-	add	%sp, STACKFRAME_SZ, %o0
-	ld	[%sp + STACKFRAME_SZ + PT_PC], %o1
-	ld	[%sp + STACKFRAME_SZ + PT_NPC], %o2
-	ld	[%sp + STACKFRAME_SZ + PT_PSR], %o3
+	add	%sp, REGWIN_SZ, %o0
+	ld	[%sp + REGWIN_SZ + PT_PC], %o1
+	ld	[%sp + REGWIN_SZ + PT_NPC], %o2
+	ld	[%sp + REGWIN_SZ + PT_PSR], %o3
+
+	wr	%t_wim, 0x0, %wim		! or else...
+	WRITE_PAUSE
 
-	wr	%t_psr, 0x0, %psr
 	wr	%t_psr, PSR_ET, %psr
 	WRITE_PAUSE
 
 	call	C_LABEL(do_memaccess_unaligned)
 	 nop
 
-	b	ret_trap_entry
+	b	ret_trap_entry			! maybe signal posted
 	 nop
 
 ret_trap_kernel:
+	ld	[%sp + REGWIN_SZ + PT_PSR], %t_psr
 	wr	%t_psr, 0x0, %psr
 	WRITE_PAUSE
 
@@ -218,15 +241,12 @@
 	wr	%t_wim, 0x0, %wim
 	WRITE_PAUSE
 
-	wr	%t_psr, 0x0, %psr
 	wr	%t_psr, PSR_ET, %psr
 	WRITE_PAUSE
 
-	mov	0, %o1
-	call	C_LABEL(do_sparc_winfault)
-	 add	%sp, STACKFRAME_SZ, %o0
+	call	C_LABEL(window_ret_fault)
+	 add	%sp, REGWIN_SZ, %o0
 
-	/* Try it all again. */
 	b	ret_trap_entry
 	 nop
 
@@ -297,7 +317,7 @@
 	b	ret_trap_userwins_ok
 	 nop
 
-	.globl	C_LABEL(sun4c_rett_stackchk)
+	.globl	C_LABEL(srmmu_rett_stackchk)
 C_LABEL(srmmu_rett_stackchk):
 	bne	ret_trap_user_stack_is_bolixed
 	 sethi	%hi(KERNBASE), %g1
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/kernel/sclow.S linux/arch/sparc/kernel/sclow.S
--- v1.3.70/linux/arch/sparc/kernel/sclow.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/kernel/sclow.S	Mon Mar  4 08:49:55 1996
@@ -0,0 +1,191 @@
+/* sclow.S: Low level special syscall handling.
+ *          Basically these are cases where we can completly
+ *          handle the system call without saving any state
+ *          because we know that the process will not sleep.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/cprefix.h>
+#include <asm/ptrace.h>
+#include <asm/errno.h>
+#include <asm/winmacro.h>
+#include <asm/psr.h>
+
+#define CC_AND_RETT  \
+	set	PSR_C, %l4; \
+	andn	%l0, %l4, %l4; \
+	wr	%l4, 0x0, %psr; \
+	nop; nop; nop; \
+	jmp	%l2; \
+	rett	%l2 + 4;
+
+#define SC_AND_RETT  \
+	set	PSR_C, %l4; \
+	or	%l0, %l4, %l4; \
+	wr	%l4, 0x0, %psr; \
+	nop; nop; nop; \
+	jmp	%l2; \
+	rett	%l2 + 4;
+
+#define LABEL(func)  CONCAT(func, _low)
+
+	.globl	LABEL(sunosnop)
+LABEL(sunosnop):
+	CC_AND_RETT
+
+	.globl	LABEL(sunosgetpid)
+LABEL(sunosgetpid):
+	LOAD_CURRENT(l4, l5)
+	ld	[%l4 + 108], %i0
+	ld	[%l4 + 256], %l5
+	ld	[%l5 + 108], %i1
+	CC_AND_RETT
+
+	.globl	LABEL(sunosgetuid)
+LABEL(sunosgetuid):
+	LOAD_CURRENT(l4, l5)
+	lduh	[%l4 + 280], %i0
+	lduh	[%l4 + 282], %i1
+	CC_AND_RETT
+
+	.globl	LABEL(sunosgetgid)
+LABEL(sunosgetgid):
+	LOAD_CURRENT(l4, l5)
+	lduh	[%l4 + 288], %i0
+	lduh	[%l4 + 290], %i1
+	CC_AND_RETT
+
+	.globl	LABEL(sunosmctl)
+LABEL(sunosmctl):
+	mov	0, %i0
+	CC_AND_RETT
+
+	.globl	LABEL(sunosgdtsize)
+LABEL(sunosgdtsize):	
+	mov	256, %i0
+	CC_AND_RETT
+
+	.globl	LABEL(sunossblock)
+LABEL(sunossblock):
+	LOAD_CURRENT(l4, l5)
+	set	-65793, %l5
+	and	%i0, %l5, %l5
+	ld	[%l4 + TASK_BLOCKED], %i0
+	or	%i0, %l5, %l5
+	st	%l5, [%l4 + TASK_BLOCKED]
+	CC_AND_RETT
+
+	.globl	LABEL(sunossmask)
+LABEL(sunossmask):
+	LOAD_CURRENT(l4, l5)
+	set	-65793, %l5
+	and	%i0, %l5, %l5
+	ld	[%l4 + TASK_BLOCKED], %i0
+	st	%l5, [%l4 + TASK_BLOCKED]
+	CC_AND_RETT
+
+	.globl	LABEL(getpagesize)
+LABEL(getpagesize):
+	set	4096, %i0
+	CC_AND_RETT
+
+	.globl	LABEL(umask)
+LABEL(umask):
+	LOAD_CURRENT(l4, l5)
+	ld	[%l4 + 1560], %l5
+	and	%i0, 511, %l4
+	lduh	[%l5 + 4], %i0
+	sth	%l4, [%l5 + 4]
+	CC_AND_RETT
+
+	.globl	LABEL(write)
+LABEL(write):
+	cmp	%i0, 255		/* fd >= NR_OPEN */
+	bgu,a	write_error_return
+	 mov	EBADF, %i0
+
+	LOAD_CURRENT(l4, l5)
+	ld	[%l4 + 1564], %l5
+	sll	%i0, 2, %l6
+	add	%l5, %l6, %l5
+	ld	[%l5 + 36], %l6
+	cmp	%l6, 0			/* !(file=current->files->fd[fd]) */
+	be,a	write_error_return
+	 mov	EBADF, %i0	
+
+	ld	[%l6 + 36], %l5
+	cmp	%l5, 0			/* !(inode=file->f_inode) */
+	be,a	write_error_return
+	 mov	EBADF, %i0
+
+	lduh	[%l6], %l5		/* !(file->f_mode & 2) */
+	andcc	%l5, 2, %g0
+	be,a	write_error_return
+	 mov	EBADF, %i0
+
+	ld	[%l6 + 40], %l5
+	cmp	%l5, 0			/* !file->f_op */
+	be,a	write_error_return
+	 mov	EINVAL, %i0
+
+	ld	[%l5 + 8], %l5		/* !file->f_op->write */
+	cmp	%l5, 0
+	be,a	write_error_return
+	 mov	EINVAL, %i0
+
+	cmp	%i2, 0			/* count == 0 */
+	bne	1f
+	 nop
+
+	mov	0, %i0
+	CC_AND_RETT
+
+1:
+	/* See if we can do the optimization... */
+	ld	[%l6 + 36], %l5
+	lduh	[%l5 + 16], %l5
+	srl	%l5, 8, %l6
+	cmp	%l6, 1			/* MEM_MAJOR */
+	bne,a	write_is_too_hard
+	 sethi	%hi(C_LABEL(quick_sys_write)), %l7
+
+	and	%l5, 0xff, %l5
+	cmp	%l5, 3			/* NULL_MINOR */
+	bne,a	write_is_too_hard
+	 sethi	%hi(C_LABEL(quick_sys_write)), %l7
+
+	/* We only optimize for the /dev/null case currently,
+	 * however to stay POSIX4 compliant we must check the
+	 * validity of the passed buffer.  Blowlaris2.x does not
+	 * do this and is therefore not POSIX4 compliant!
+	 * If you are going to optimize for benchmarks, fine,
+	 * but to break behavior of a system call in the process
+	 * is complete brain damage...
+	 */
+
+	/* XXX write verify_area thingy for full POSIX conformance! XXX */
+
+	mov	%i2, %i0
+	CC_AND_RETT
+
+write_is_too_hard:
+	b	syscall_is_too_hard
+	 or	%l7, %lo(C_LABEL(quick_sys_write)), %l7
+
+write_error_return:
+	SC_AND_RETT
+
+	/* XXX sys_nice() XXX */
+	/* XXX sys_setpriority() XXX */
+	/* XXX sys_getpriority() XXX */
+	/* XXX sys_setregid() XXX */
+	/* XXX sys_setgid() XXX */
+	/* XXX sys_setreuid() XXX */
+	/* XXX sys_setuid() XXX */
+	/* XXX sys_setfsuid() XXX */
+	/* XXX sys_setfsgid() XXX */
+	/* XXX sys_setpgid() XXX */
+	/* XXX sys_getpgid() XXX */
+	/* XXX sys_setsid() XXX */
+	/* XXX sys_getsid() XXX */
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/kernel/setup.c linux/arch/sparc/kernel/setup.c
--- v1.3.70/linux/arch/sparc/kernel/setup.c	Tue Dec 26 04:45:35 1995
+++ linux/arch/sparc/kernel/setup.c	Mon Mar  4 08:49:56 1996
@@ -1,4 +1,4 @@
-/*  $Id: setup.c,v 1.41 1995/11/25 00:58:21 davem Exp $
+/*  $Id: setup.c,v 1.54 1996/02/25 06:49:18 davem Exp $
  *  linux/arch/sparc/kernel/setup.c
  *
  *  Copyright (C) 1995  David S. Miller (davem@caip.rutgers.edu)
@@ -16,6 +16,11 @@
 #include <linux/user.h>
 #include <linux/a.out.h>
 #include <linux/tty.h>
+#include <linux/delay.h>
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/kdev_t.h>
+#include <linux/major.h>
 
 #include <asm/segment.h>
 #include <asm/system.h>
@@ -28,6 +33,7 @@
 #include <asm/traps.h>
 #include <asm/vaddrs.h>
 #include <asm/kdebug.h>
+#include <asm/mbus.h>
 
 struct screen_info screen_info = {
 	0, 0,			/* orig-x, orig-y */
@@ -42,6 +48,7 @@
 };
 
 char wp_works_ok = 0;
+unsigned int phys_bytes_of_ram, end_of_phys_memory;
 
 unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end)
 {
@@ -55,6 +62,9 @@
  */
 
 extern unsigned long trapbase;
+extern void breakpoint(void);
+extern void console_restore_palette(void);
+asmlinkage void sys_sync(void);	/* it's really int */
 
 /* Pretty sick eh? */
 void prom_sync_me(void)
@@ -68,8 +78,14 @@
 			     "nop\n\t"
 			     "nop\n\t" : : "r" (&trapbase));
 
+        console_restore_palette ();
 	prom_printf("PROM SYNC COMMAND...\n");
 	show_free_areas();
+	if(current != task[0]) {
+		sti();
+		sys_sync();
+		cli();
+	}
 	prom_printf("Returning to prom\n");
 
 	__asm__ __volatile__("wr %0, 0x0, %%tbr\n\t"
@@ -145,23 +161,30 @@
 
 extern void load_mmu(void);
 extern int prom_probe_memory(void);
-extern void probe_vac(void);
+extern void sun4c_probe_vac(void);
 extern void get_idprom(void);
-extern unsigned int end_of_phys_memory;
 extern char cputypval;
-extern unsigned long start, end, bootup_stack, bootup_kstack;
-
+extern unsigned long start, end;
+extern void panic_setup(char *, int *);
 
-char sparc_command_line[256];  /* Should be enough */
 char saved_command_line[256];
 enum sparc_cpu sparc_cpu_model;
 
 struct tt_entry *sparc_ttable;
 
+static struct pt_regs fake_swapper_regs = { 0, 0, 0, 0, { 0, } };
+
 void setup_arch(char **cmdline_p,
 	unsigned long * memory_start_p, unsigned long * memory_end_p)
 {
-	int total, i;
+	int total, i, panic_stuff[2];
+
+	/* Always reboot on panic, but give 5 seconds to hit L1-A
+	 * and look at debugging info if desired.
+	 */
+	panic_stuff[0] = 1;
+	panic_stuff[1] = 5;
+	panic_setup(0, panic_stuff);
 
 	sparc_ttable = (struct tt_entry *) &start;
 
@@ -181,7 +204,7 @@
 	  {
 	  case sun4c:
 		  printk("SUN4C\n");
-		  probe_vac();
+		  sun4c_probe_vac();
 		  break;
           case sun4m:
 		  printk("SUN4M\n");
@@ -215,8 +238,10 @@
 	load_mmu();
 	total = prom_probe_memory();
 	*memory_start_p = (((unsigned long) &end));
-	printk("Physical Memory: %d bytes (in hex %08lx)\n", (int) total,
+#if 0
+	prom_printf("Physical Memory: %d bytes (in hex %08lx)\n", (int) total,
 		    (unsigned long) total);
+#endif
 
 	for(i=0; sp_banks[i].num_bytes != 0; i++) {
 #if 0
@@ -229,10 +254,15 @@
 
 	prom_setsync(prom_sync_me);
 
+	*memory_end_p = (end_of_phys_memory + PAGE_OFFSET);
+	if(*memory_end_p > IOBASE_VADDR)
+		*memory_end_p = IOBASE_VADDR;
+
 	/* Due to stack alignment restrictions and assumptions... */
 	init_task.mm->mmap->vm_page_prot = PAGE_SHARED;
-
-	*memory_end_p = (end_of_phys_memory + PAGE_OFFSET);
+	init_task.mm->mmap->vm_start = KERNBASE;
+	init_task.mm->mmap->vm_end = *memory_end_p;
+	init_task.tss.kregs = &fake_swapper_regs;
 
 	{
 		extern int serial_console;  /* in console.c, of course */
@@ -250,6 +280,15 @@
 			prom_halt();
 		}
 	}
+#if 1
+	/* XXX ROOT_DEV hack for kgdb - davem XXX */
+#if 1
+	ROOT_DEV = MKDEV(UNNAMED_MAJOR, 255); /* NFS */
+#else
+	ROOT_DEV = 0x801; /* SCSI DISK */
+#endif
+
+#endif
 }
 
 asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
@@ -257,12 +296,35 @@
 	return -EIO;
 }
 
-/*
- * BUFFER is PAGE_SIZE bytes long.
- *
- * XXX Need to do better than this! XXX
- */
+/* BUFFER is PAGE_SIZE bytes long. */
+
+extern char *sparc_cpu_type[];
+extern char *sparc_fpu_type[];
+
 int get_cpuinfo(char *buffer)
 {
-	return sprintf(buffer, "Sparc RISC\n");
+	int cpuid=get_cpuid();
+
+	return sprintf(buffer, "cpu\t\t: %s\n"
+            "fpu\t\t: %s\n"
+            "promlib\t\t: Version %d Revision %d\n"
+            "wp\t\t: %s\n"
+            "type\t\t: %s\n"
+            "Elf Support\t: %s\n"   /* I can't remember when I do --ralp */
+            "BogoMips\t: %lu.%02lu\n"
+	    "%s",
+            sparc_cpu_type[cpuid],
+            sparc_fpu_type[cpuid],
+            romvec->pv_romvers, prom_rev,
+            wp_works_ok ? "yes" : "no",
+            &cputypval,
+#if CONFIG_BINFMT_ELF
+            "yes",
+#else
+            "no",
+#endif
+            loops_per_sec/500000, (loops_per_sec/5000) % 100,
+	    mmu_info()
+            );
+
 }
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/kernel/signal.c linux/arch/sparc/kernel/signal.c
--- v1.3.70/linux/arch/sparc/kernel/signal.c	Mon Nov 27 12:48:27 1995
+++ linux/arch/sparc/kernel/signal.c	Mon Mar  4 08:49:56 1996
@@ -1,4 +1,4 @@
-/*  $Id: signal.c,v 1.20 1995/11/26 02:29:09 davem Exp $
+/*  $Id: signal.c,v 1.28 1995/12/29 21:47:18 davem Exp $
  *  linux/arch/sparc/kernel/signal.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -28,81 +28,76 @@
  * atomically swap in the new signal mask, and wait for a signal.
  * This is really tricky on the Sparc, watch out...
  */
-asmlinkage inline int _sigpause_common(unsigned int set, struct pt_regs *regs)
+asmlinkage inline void _sigpause_common(unsigned int set, struct pt_regs *regs)
 {
 	unsigned long mask;
 
 	mask = current->blocked;
 	current->blocked = set & _BLOCKABLE;
+
 	/* Advance over the syscall instruction for when
 	 * we return.  We want setup_frame to save the proper
-	 * state, but then below we set ourselves backwards
-	 * to compensate for what ret_sys_call does. Ick!
+	 * state, including the error return number & condition
+	 * codes.
 	 */
-	regs->pc += 4;
+	regs->pc = regs->npc;
 	regs->npc += 4;
+	regs->psr |= PSR_C;
+	regs->u_regs[UREG_I0] = EINTR;
 
 	while (1) {
 		current->state = TASK_INTERRUPTIBLE;
 		schedule();
-		if (do_signal(mask, regs)) {
-			/* If we actually post the signal then we
-			 * will get our PCs advanced in entry.S, to
-			 * compensate we throw the PCs back one insn.
-			 */
-			regs->pc -= 4;
-			regs->npc -= 4;
-			return -EINTR;
-		}
+		if (do_signal(mask, regs))
+			return;
 	}
 }
 
-asmlinkage int sys_sigpause(unsigned int set)
+asmlinkage void do_sigpause(unsigned int set, struct pt_regs *regs)
 {
-	struct pt_regs *regs;
-	unsigned long fp;
-
-	__asm__ __volatile__("mov %%fp, %0\n\t" :
-			     "=r" (fp));
-	regs = ((struct pt_regs *) (fp + STACKFRAME_SZ));
-	return _sigpause_common(set, regs);
+	_sigpause_common(set, regs);
 }
 
-asmlinkage int sys_sigsuspend(unsigned int *sigmaskp)
+asmlinkage void do_sigsuspend(unsigned int *sigmaskp, struct pt_regs *regs)
 {
-	struct pt_regs *regs;
-	unsigned long fp;
 	unsigned int set;
 
-	__asm__ __volatile__("mov %%fp, %0\n\t" :
-			     "=r" (fp));
-	regs = ((struct pt_regs *) (fp + STACKFRAME_SZ));
-	if(verify_area(VERIFY_READ, sigmaskp, sizeof(unsigned int)))
-		return -EFAULT;
+	/* Manual does not state what is supposed to happen if
+	 * the sigmask ptr is bogus.  It does state that EINTR
+	 * is the only valid return value and it indicates
+	 * successful signal delivery.  Must investigate.
+	 */
+	if(verify_area(VERIFY_READ, sigmaskp, sizeof(unsigned int))) {
+		regs->pc = regs->npc;
+		regs->npc += 4;
+		regs->u_regs[UREG_I0] = EFAULT;
+		regs->psr |= PSR_C;
+		return;
+	}
 	set = *sigmaskp;
-	return _sigpause_common(set, regs);
+	_sigpause_common(set, regs);
 }
 
-extern unsigned long nwindows;
-
 asmlinkage void do_sigreturn(struct pt_regs *regs)
 {
 	struct sigcontext_struct *scptr =
 		(struct sigcontext_struct *) regs->u_regs[UREG_I0];
 
-	/* Make the stack consistant. */
-	flush_user_windows();
+	synchronize_user_stack();
 
 	/* Check sanity of the user arg. */
 	if(verify_area(VERIFY_READ, scptr, sizeof(struct sigcontext_struct)) ||
-	   ((((unsigned long) scptr)) & 0x3))
+	   ((((unsigned long) scptr)) & 0x3)) {
+		printk("%s [%d]: do_sigreturn, scptr is invalid at pc<%08lx> scptr<%p>\n",
+		       current->comm, current->pid, regs->pc, scptr);
 		do_exit(SIGSEGV);
+	}
 
 	if((scptr->sigc_pc | scptr->sigc_npc) & 3)
 		return; /* Nice try. */
 
 	current->blocked = scptr->sigc_mask & _BLOCKABLE;
-	current->tss.sstk_info.cur_status = (scptr->sigc_onstack & 0x1);
+	current->tss.sstk_info.cur_status = (scptr->sigc_onstack & 1);
 	regs->pc = scptr->sigc_pc;
 	regs->npc = scptr->sigc_npc;
 	regs->u_regs[UREG_FP] = scptr->sigc_sp;
@@ -114,38 +109,6 @@
 	regs->psr |= (scptr->sigc_psr & PSR_ICC);
 }
 
-/* I love register windows...
- * Basically, this tries to get as many of the current user
- * windows on the stack as possible, even if unaligned.  Failing
- * that the windows end up in the per-task window save buffer
- * in the thread struct, these will be copied onto the signal
- * stack for possible inspection by the process.
- */
-static inline void
-do_magic_sparc_stuff(void)
-{
-	unsigned long sp;
-	int this_win;
-
-	flush_user_windows();
-	this_win = (current->tss.w_saved - 1);
-	while(this_win >= 0) {
-		sp = current->tss.rwbuf_stkptrs[this_win];
-		if(!(sp & 7) && !verify_area(VERIFY_WRITE, (char *)sp,
-		                             sizeof(struct reg_window))) {
-			memcpy((char *)sp,
-			       (char *)&current->tss.reg_window[this_win],
-			       sizeof(struct reg_window));
-			current->tss.w_saved--;
-			memcpy((char *)&current->tss.reg_window[this_win],
-			       (char *)&current->tss.reg_window[this_win+1],
-			       (sizeof(struct reg_window) *
-			       (current->tss.w_saved-this_win)));
-		}
-		this_win -= 1;
-	}
-}
-
 /*
  * Set up a signal frame... Make the stack look the way SunOS
  * expects it to look which is basically:
@@ -172,25 +135,27 @@
 
 static inline void
 setup_frame(struct sigaction *sa, struct sigcontext_struct **fp,
-	    unsigned long pc, struct pt_regs *regs, int signr,
-	    unsigned long oldmask)
+	    unsigned long pc, unsigned long npc, struct pt_regs *regs,
+	    int signr, unsigned long oldmask)
 {
 	struct signal_sframe *sframep;
 	struct sigcontext_struct *sc;
 	int window = 0;
 	int old_status = current->tss.sstk_info.cur_status;
 
+	synchronize_user_stack();
 	sframep = (struct signal_sframe *) *fp;
 	sframep = (struct signal_sframe *) (((unsigned long) sframep)-SF_ALIGNEDSZ);
 	sc = &sframep->sig_context;
 	if(verify_area(VERIFY_WRITE, sframep, sizeof(*sframep)) ||
 	   (((unsigned long) sframep) & 7) ||
-	   (((unsigned long) sframep) >= KERNBASE)) {
+	   (((unsigned long) sframep) >= KERNBASE) ||
+	   ((sparc_cpu_model == sun4 || sparc_cpu_model == sun4c) &&
+	    ((unsigned long) sframep < 0xe0000000 && (unsigned long) sframep >= 0x20000000))) {
 		printk("%s [%d]: User has trashed signal stack\n",
 		       current->comm, current->pid);
 		printk("Sigstack ptr %p handler at pc<%08lx> for sig<%d>\n",
 		       sframep, pc, signr);
-		show_regs(regs);
 		/* Don't change signal code and address, so that
 		 * post mortem debuggers can have a look.
 		 */
@@ -200,13 +165,12 @@
 		return;
 	}
 	*fp = (struct sigcontext_struct *) sframep;
-	do_magic_sparc_stuff();
 
 	sc->sigc_onstack = old_status;
 	sc->sigc_mask = oldmask;
 	sc->sigc_sp = regs->u_regs[UREG_FP];
-	sc->sigc_pc = regs->pc;
-	sc->sigc_npc = regs->npc;
+	sc->sigc_pc = pc;
+	sc->sigc_npc = npc;
 	sc->sigc_psr = regs->psr;
 	sc->sigc_g1 = regs->u_regs[UREG_G1];
 	sc->sigc_o0 = regs->u_regs[UREG_I0];
@@ -220,12 +184,6 @@
 			       sizeof(struct reg_window));
 		}
 	else
-		/* This is so that gdb and friends can trace back
-		 * through the stack properly.  An alternative
-		 * is to set the fp in this new window to the
-		 * sp of the frame at the time of the signal and
-		 * I see some problems with that maneuver.
-		 */
 		memcpy(sframep, (char *)regs->u_regs[UREG_FP],
 		       sizeof(struct reg_window));
 
@@ -243,6 +201,7 @@
 		sframep->sig_address = 0;
 	}
 	sframep->sig_scptr = sc;
+	regs->u_regs[UREG_FP] = (unsigned long) *fp;
 }
 
 /*
@@ -261,6 +220,7 @@
 	unsigned long handler_signal = 0;
 	struct sigcontext_struct *frame = NULL;
 	unsigned long pc = 0;
+	unsigned long npc = 0;
 	unsigned long signr;
 	struct sigaction *sa;
 
@@ -269,22 +229,6 @@
 		clear_bit(signr, &current->signal);
 		sa = current->sig->action + signr;
 		signr++;
-		if((current->flags & PF_PTRACED) && signr != SIGKILL) {
-			current->exit_code = signr;
-			current->state = TASK_STOPPED;
-			notify_parent(current);
-			schedule();
-			if(!(signr = current->exit_code))
-				continue;
-			current->exit_code = 0;
-			if(signr == SIGSTOP)
-				continue;
-			if(_S(signr) & current->blocked) {
-				current->signal |= _S(signr);
-				continue;
-			}
-			sa = current->sig->action + signr - 1;
-		}
 		if(sa->sa_handler == SIG_IGN) {
 			if(signr != SIGCHLD)
 				continue;
@@ -299,8 +243,6 @@
 				continue;
 
 			case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:
-				if(current->flags & PF_PTRACED)
-					continue;
 				current->state = TASK_STOPPED;
 				current->exit_code = signr;
 				if(!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
@@ -322,12 +264,27 @@
 			}
 		}
 		/* OK, we're invoking a handler. */
+		if(regs->psr & PSR_C) {
+			if(regs->u_regs[UREG_I0] == ERESTARTNOHAND ||
+			   (regs->u_regs[UREG_I0] == ERESTARTSYS && !(sa->sa_flags & SA_RESTART)))
+				regs->u_regs[UREG_I0] = EINTR;
+		}
 		handler_signal |= 1 << (signr - 1);
 		mask &= ~sa->sa_mask;
 	}
+	if((regs->psr & PSR_C) &&
+	   (regs->u_regs[UREG_I0] == ERESTARTNOHAND ||
+	    regs->u_regs[UREG_I0] == ERESTARTSYS ||
+	    regs->u_regs[UREG_I0] == ERESTARTNOINTR)) {
+		/* replay the system call when we are done */
+		regs->u_regs[UREG_I0] = regs->u_regs[UREG_G0];
+		regs->pc -= 4;
+		regs->npc -= 4;
+	}
 	if(!handler_signal)
 		return 0;
 	pc = regs->pc;
+	npc = regs->npc;
 	frame = (struct sigcontext_struct *) regs->u_regs[UREG_FP];
 	signr = 1;
 	sa = current->sig->action;
@@ -336,15 +293,16 @@
 			break;
 		if(!(mask & handler_signal))
 			continue;
-		setup_frame(sa, &frame, pc, regs, signr, oldmask);
+		setup_frame(sa, &frame, pc, npc, regs, signr, oldmask);
 		pc = (unsigned long) sa->sa_handler;
+		npc = pc + 4;
 		if(sa->sa_flags & SA_ONESHOT)
 			sa->sa_handler = NULL;
 		current->blocked |= sa->sa_mask;
 		oldmask |= sa->sa_mask;
 	}
-	regs->u_regs[UREG_FP] = (unsigned long) frame;
-	regs->npc = (regs->pc = pc) + 4;
+	regs->pc = pc;
+	regs->npc = npc;
 	return 1;
 }
 
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/kernel/smp.c linux/arch/sparc/kernel/smp.c
--- v1.3.70/linux/arch/sparc/kernel/smp.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/kernel/smp.c	Mon Mar  4 08:49:56 1996
@@ -0,0 +1,243 @@
+/* smp.c: Sparc SMP support.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/kernel.h>
+#include <linux/smp.h>
+
+int smp_num_cpus;
+int smp_threads_ready;
+volatile unsigned long smp_msg_data;
+volatile int smp_src_cpu;
+volatile int smp_msg_id;
+
+static volatile int smp_commenced = 0;
+
+/* The only guarenteed locking primitive available on all Sparc
+ * processors is 'ldstub [%addr_reg + imm], %dest_reg' which atomicly
+ * places the current byte at the effective address into dest_reg and
+ * places 0xff there afterwards.  Pretty lame locking primitive
+ * compared to the Alpha and the intel no?  Most Sparcs have 'swap'
+ * instruction which is muct better...
+ */
+klock_t kernel_lock;
+
+void smp_commence(void)
+{
+	/*
+	 *	Lets the callin's below out of their loop.
+	 */
+	smp_commenced = 1;
+}
+
+void smp_callin(void)
+{
+	int cpuid = smp_get_processor_id();
+
+	/* XXX Clear the software interrupts _HERE_. */
+
+	sti();
+	calibrate_delay();
+	smp_store_cpu_info(cpuid);
+	set_bit(cpuid, (unsigned long *)&cpu_callin_map[0]);
+	local_invalidate_all();
+	while(!smp_commenced);
+	if(cpu_number_map[cpuid] == -1)
+		while(1);
+	local_invalidate_all();
+}
+
+void smp_boot_cpus(void)
+{
+}
+
+void smp_message_pass(int target, int msg, unsigned long data, int wait)
+{
+	struct sparc_ipimsg *msg = (struct sparc_ipimsg *) data;
+	unsigned long target_map;
+	int p = smp_processor_id();
+	static volatile int message_cpu = NO_PROC_ID;
+
+	if(!smp_activated || !smp_commenced)
+		return;
+
+	if(msg == MSG_RESCHEDULE) {
+		if(smp_cpu_in_msg[p])
+			return;
+	}
+
+	if(message_cpu != NO_PROC_ID && msg != MSG_STOP_CPU) {
+		panic("CPU #%d: Message pass %d but pass in progress by %d of %d\n",
+		      smp_processor_id(),msg,message_cpu, smp_msg_id);
+	}
+	message_cpu = smp_processor_id();
+	smp_cpu_in_msg[p]++;
+	if(msg != MSG_RESCHEDULE) {
+		smp_src_cpu = p;
+		smp_msg_id = msg;
+		smp_msg_data = data;
+	}
+
+	if(target == MSG_ALL_BUT_SELF) {
+		target_map = cpu_present_map;
+		cpu_callin_map[0] = (1<<smp_src_cpu);
+	} else if(target == MSG_ALL) {
+		target_map = cpu_present_map;
+		cpu_callin_map[0] = 0;
+	} else {
+		target_map = (1<<target);
+		cpu_callin_map[0] = 0;
+	}
+
+	/* XXX Send lvl15 soft interrupt to cpus here XXX */
+
+	switch(wait) {
+	case 1:
+		while(cpu_callin_map[0] != target_map);
+		break;
+	case 2:
+		while(smp_invalidate_needed);
+		break;
+	}
+	smp_cpu_in_msg[p]--;
+	message_cpu = NO_PROC_ID;
+}
+
+inline void smp_invalidate(int type, unsigned long a, unsigned long b, unsigned long c)
+{
+	unsigned long flags;
+
+	smp_invalidate_needed = cpu_present_map & ~(1<<smp_processor_id());
+	save_flags(flags); cli();
+	smp_message_pass(MSG_ALL_BUT_SELF, MSG_INVALIDATE_TLB, 0L, 2);
+	local_invalidate();
+	restore_flags(flags);
+}
+
+void smp_invalidate_all(void)
+{
+	smp_invalidate(0, 0, 0, 0);
+}
+
+void smp_invalidate_mm(struct mm_struct *mm)
+{
+	smp_invalidate(1, (unsigned long) mm, 0, 0);
+}
+
+void smp_invalidate_range(struct mm_struct *mm, unsigned long start, unsigned long end)
+{
+	smp_invalidate(2, (unsigned long) mm, start, end);
+}
+
+void smp_invalidate_page(struct vm_area_struct *vmap, unsigned long page)
+{
+	smp_invalidate(3, (unsigned long)vmap->vm_mm, page, 0);
+}
+
+void smp_reschedule_irq(int cpl, struct pt_regs *regs)
+{
+	if(smp_processor_id() != active_kernel_processor)
+		panic("SMP Reschedule on CPU #%d, but #%d is active.\n",
+		      smp_processor_id(), active_kernel_processor);
+	if(user_mode(regs)) {
+		current->utime++;
+		if (current->pid) {
+			if (current->priority < 15)
+				kstat.cpu_nice++;
+			else
+				kstat.cpu_user++;
+		}
+		/* Update ITIMER_VIRT for current task if not in a system call */
+		if (current->it_virt_value && !(--current->it_virt_value)) {
+			current->it_virt_value = current->it_virt_incr;
+			send_sig(SIGVTALRM,current,1);
+		}
+	} else {
+		current->stime++;
+		if(current->pid)
+			kstat.cpu_system++;
+#ifdef CONFIG_PROFILE
+		if (prof_buffer && current->pid) {
+			extern int _stext;
+			unsigned long eip = regs->eip - (unsigned long) &_stext;
+			eip >>= CONFIG_PROFILE_SHIFT;
+			if (eip < prof_len)
+				prof_buffer[eip]++;
+		}
+#endif
+	}
+
+	/*
+	 * check the cpu time limit on the process.
+	 */
+	if ((current->rlim[RLIMIT_CPU].rlim_max != RLIM_INFINITY) &&
+	    (((current->stime + current->utime) / HZ) >= current->rlim[RLIMIT_CPU].rlim_max))
+		send_sig(SIGKILL, current, 1);
+	if ((current->rlim[RLIMIT_CPU].rlim_cur != RLIM_INFINITY) &&
+	    (((current->stime + current->utime) % HZ) == 0)) {
+		unsigned long psecs = (current->stime + current->utime) / HZ;
+		/* send when equal */
+		if (psecs == current->rlim[RLIMIT_CPU].rlim_cur)
+			send_sig(SIGXCPU, current, 1);
+		/* and every five seconds thereafter. */
+		else if ((psecs > current->rlim[RLIMIT_CPU].rlim_cur) &&
+			 ((psecs - current->rlim[RLIMIT_CPU].rlim_cur) % 5) == 0)
+			send_sig(SIGXCPU, current, 1);
+	}
+
+	/* Update ITIMER_PROF for the current task */
+	if (current->it_prof_value && !(--current->it_prof_value)) {
+		current->it_prof_value = current->it_prof_incr;
+		send_sig(SIGPROF,current,1);
+	}
+
+	if(0 > --current->counter || current->pid == 0) {
+		current->counter = 0;
+		need_resched = 1;
+	}
+}
+
+void smp_message_irq(int cpl, struct pt_regs *regs)
+{
+	int i=smp_processor_id();
+/*	static int n=0;
+	if(n++<NR_CPUS)
+		printk("IPI %d->%d(%d,%ld)\n",smp_src_cpu,i,smp_msg_id,smp_msg_data);*/
+	switch(smp_msg_id)
+	{
+		case 0:	/* IRQ 13 testing - boring */
+			return;
+			
+		/*
+		 *	A TLB flush is needed.
+		 */
+		 
+		case MSG_INVALIDATE_TLB:
+			if(clear_bit(i,(unsigned long *)&smp_invalidate_needed))
+				local_invalidate();
+			set_bit(i, (unsigned long *)&cpu_callin_map[0]);
+			cpu_callin_map[0]|=1<<smp_processor_id();
+			break;
+			
+		/*
+		 *	Halt other CPU's for a panic or reboot
+		 */
+		case MSG_STOP_CPU:
+			while(1)
+			{
+				if(cpu_data[smp_processor_id()].hlt_works_ok)
+					__asm__("hlt");
+			}
+		default:
+			printk("CPU #%d sent invalid cross CPU message to CPU #%d: %X(%lX).\n",
+				smp_src_cpu,smp_processor_id(),smp_msg_id,smp_msg_data);
+			break;
+	}
+	/*
+	 *	Clear the IPI, so we can receive future IPI's
+	 */
+	 
+	apic_read(APIC_SPIV);		/* Dummy read */
+	apic_write(APIC_EOI, 0);	/* Docs say use 0 for future compatibility */
+}
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/kernel/sparc-stub.c linux/arch/sparc/kernel/sparc-stub.c
--- v1.3.70/linux/arch/sparc/kernel/sparc-stub.c	Sat Nov 25 19:04:37 1995
+++ linux/arch/sparc/kernel/sparc-stub.c	Mon Mar  4 08:49:56 1996
@@ -1,4 +1,4 @@
-/* $Id: sparc-stub.c,v 1.7 1995/11/25 00:58:26 davem Exp $
+/* $Id: sparc-stub.c,v 1.10 1996/02/15 09:12:09 davem Exp $
  * sparc-stub.c:  KGDB support for the Linux kernel.
  *
  * Modifications to run under Linux
@@ -636,7 +636,6 @@
  * breakpoint, and the icache probably has no way of knowing that a data ref to
  * some location may have changed something that is in the instruction cache.
  */
-
 			/* Only instruction cache flushing on the sun4c/sun4
 			 * for now.  We assume control flow during the kgdb
 			 * transaction has not left the context in which it
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/kernel/sunos_asm.S linux/arch/sparc/kernel/sunos_asm.S
--- v1.3.70/linux/arch/sparc/kernel/sunos_asm.S	Sat Nov 25 19:04:37 1995
+++ linux/arch/sparc/kernel/sunos_asm.S	Mon Mar  4 08:49:56 1996
@@ -1,4 +1,4 @@
-/* $Id: sunos_asm.S,v 1.8 1995/11/25 00:58:29 davem Exp $
+/* $Id: sunos_asm.S,v 1.10 1995/12/26 04:09:33 davem Exp $
  * sunos_asm.S: SunOS system calls which must have a low-level
  *              entry point to operate correctly.
  *
@@ -12,79 +12,69 @@
 #include <asm/cprefix.h>
 #include <asm/ptrace.h>
 
-	/* Note that for dual value returning system calls we
-	 * need to store the second one ourselves in the pt_regs
-	 * trap-frame.  linux_sparc_syscall does %o0 for us
-	 * however.
-	 */
-
 	.text
 	.align 4
 
 	/* SunOS getpid() returns pid in %o0 and ppid in %o1 */
 	.globl	C_LABEL(sunos_getpid)
 C_LABEL(sunos_getpid):
-	save	%sp, -STACKFRAME_SZ, %sp
 	call	C_LABEL(sys_getpid)
-	nop
+	 nop
 
-	mov	%o0, %i0
+	st	%o0, [%sp + REGWIN_SZ + PT_I0]
 
 	call	C_LABEL(sys_getppid)
-	nop	
+	 nop	
 
-	st	%o0, [%fp + STACKFRAME_SZ + PT_I1]
+	st	%o0, [%sp + REGWIN_SZ + PT_I1]
 
-	ret
-	restore
+	b	C_LABEL(ret_sys_call)
+	 nop
 
 	/* SunOS getuid() returns uid in %o0 and euid in %o1 */
 	.globl	C_LABEL(sunos_getuid)
 C_LABEL(sunos_getuid):
-	save	%sp, -STACKFRAME_SZ, %sp
 	call	C_LABEL(sys_getuid)
-	nop
+	 nop
 
-	mov	%o0, %i0
+	st	%o0, [%sp + REGWIN_SZ + PT_I0]
 
 	call	C_LABEL(sys_geteuid)
-	nop
+	 nop
 
-	st	%o0, [%fp + STACKFRAME_SZ + PT_I1]
+	st	%o0, [%sp + REGWIN_SZ + PT_I1]
 
-	ret
-	restore
+	b	C_LABEL(ret_sys_call)
+	 nop
 
 	/* SunOS getgid() returns gid in %o0 and egid in %o1 */
 	.globl	C_LABEL(sunos_getgid)
 C_LABEL(sunos_getgid):
-	save	%sp, -STACKFRAME_SZ, %sp
 	call	C_LABEL(sys_getgid)
-	nop
+	 nop
 
-	mov	%o0, %i0
+	st	%o0, [%sp + REGWIN_SZ + PT_I0]
 
 	call	C_LABEL(sys_getegid)
-	nop
+	 nop
 
-	st	%o0, [%fp + STACKFRAME_SZ + PT_I1]
+	st	%o0, [%sp + REGWIN_SZ + PT_I1]
 
-	ret
-	restore
+	b	C_LABEL(ret_sys_call)
+	 nop
 
 	/* SunOS's execv() call only specifies the argv argument, the
 	 * environment settings are the same as the calling processes.
 	 */
 	.globl	C_LABEL(sunos_execv)
 C_LABEL(sunos_execv):
-	save	%sp, -STACKFRAME_SZ, %sp
+	st	%g0, [%sp + REGWIN_SZ + PT_I2]
 
-	st	%g0, [%fp + STACKFRAME_SZ + PT_I2]
 	call	C_LABEL(sparc_execve)
-	add	%fp, STACKFRAME_SZ, %o0
+	 add	%sp, REGWIN_SZ, %o0
 
-	st	%o0, [%fp + STACKFRAME_SZ + PT_I1]
+	st	%o0, [%sp + REGWIN_SZ + PT_I0]
 
-	ret
-	restore
+	b	C_LABEL(ret_sys_call)
+	 nop
 
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/kernel/sunos_ioctl.c linux/arch/sparc/kernel/sunos_ioctl.c
--- v1.3.70/linux/arch/sparc/kernel/sunos_ioctl.c	Mon Nov 27 12:48:27 1995
+++ linux/arch/sparc/kernel/sunos_ioctl.c	Mon Mar  4 08:49:56 1996
@@ -1,4 +1,4 @@
-/* $Id: sunos_ioctl.c,v 1.8 1995/11/26 04:07:39 davem Exp $
+/* $Id: sunos_ioctl.c,v 1.17 1996/02/10 04:29:20 davem Exp $
  * sunos_ioctl.c: The Linux Operating system: SunOS ioctl compatibility.
  * 
  * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -17,16 +17,45 @@
 #include <linux/if.h>
 #include <linux/if_arp.h>
 #include <linux/fs.h>
+#include <linux/mm.h>
+#include <asm/kbio.h>
+
+#if 0
+extern char sunkbd_type;
+extern char sunkbd_layout;
+#endif
 
 extern asmlinkage int sys_ioctl(unsigned int, unsigned int, unsigned long);
+extern asmlinkage int sys_setsid(void);
 
 asmlinkage int sunos_ioctl (int fd, unsigned long cmd, unsigned long arg)
 {
 	struct file *filp;
-	
+	int foo;
+
 	if (fd >= NR_OPEN || !(filp = current->files->fd [fd]))
 		return -EBADF;
 
+	/* First handle an easy compat. case for tty ldisc. */
+	if(cmd == TIOCSETD) {
+		int *p, ntty = N_TTY, old_fs;
+
+		p = (int *) arg;
+		foo = verify_area(VERIFY_WRITE, p, sizeof(int));
+		if(foo) return foo;
+		if(*p == 2) {
+			old_fs = get_fs();
+			set_fs(KERNEL_DS);
+			foo = sys_ioctl(fd, cmd, (int) &ntty);
+			set_fs(old_fs);
+			return (foo == -EINVAL ? -EOPNOTSUPP : foo);
+		}
+	}
+
+	/* Binary compatability is good American knowhow fuckin' up. */
+	if(cmd == TIOCNOTTY)
+		return sys_setsid();
+
 	/* SunOS networking ioctls. */
 	switch (cmd) {
 	case _IOW('r', 10, struct rtentry):
@@ -49,7 +78,7 @@
 		return sys_ioctl(fd, SIOCSIFMEM, arg);
 	case _IORW('i', 19, struct ifreq):
 		return sys_ioctl(fd, SIOCGIFMEM, arg);
-	case _IORW('i', 20, struct ifreq):
+	case _IORW('i', 20, struct ifconf):
 		return sys_ioctl(fd, SIOCGIFCONF, arg);
 	case _IOW('i', 21, struct ifreq): /* SIOCSIFMTU */
 		return sys_ioctl(fd, SIOCSIFMTU, arg);
@@ -83,7 +112,7 @@
 	case _IOW('i', 46, struct ifreq): /* SIOCSSDSTATS */
 	case _IOW('i', 47, struct ifreq): /* SIOCSSESTATS */
 	case _IOW('i', 48, struct ifreq): /* SIOCSPROMISC */
-		return -EINVAL;
+		return -EOPNOTSUPP;
 
 	case _IOW('i', 49, struct ifreq):
 		return sys_ioctl(fd, SIOCADDMULTI, arg);
@@ -91,6 +120,7 @@
 		return sys_ioctl(fd, SIOCDELMULTI, arg);
 
 	/* FDDI interface ioctls, unsupported. */
+		
 	case _IOW('i', 51, struct ifreq): /* SIOCFDRESET */
 	case _IOW('i', 52, struct ifreq): /* SIOCFDSLEEP */
 	case _IOW('i', 53, struct ifreq): /* SIOCSTRTFMWAR */
@@ -100,10 +130,27 @@
 	case _IOW('i', 57, struct ifreq): /* SIOCFDEXUSER */
 	case _IOW('i', 58, struct ifreq): /* SIOCFDGNETMAP */
 	case _IOW('i', 59, struct ifreq): /* SIOCFDGIOCTL */
-		return -EINVAL;
+		printk("FDDI ioctl, returning EOPNOTSUPP\n");
+		return -EOPNOTSUPP;
+	case _IOW('t', 125, int):
+		/* More stupid tty sunos ioctls, just
+		 * say it worked.
+		 */
+		return 0;
+	/* Non posix grp */
+	case _IOR('t', 119, int):
+		return -EIO;
+	}
+
+#if 0
+	if (cmd & 0xff00 == ('k' << 8)){
+		printk ("[[KBIO: %8.8x\n", (unsigned int) cmd);
 	}
+#endif
 
-	return sys_ioctl (fd, cmd, arg);
+	foo = sys_ioctl(fd, cmd, arg);
+	/* so stupid... */
+	return (foo == -EINVAL ? -EOPNOTSUPP : foo);
 }
 
 
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/kernel/switch.S linux/arch/sparc/kernel/switch.S
--- v1.3.70/linux/arch/sparc/kernel/switch.S	Sat Nov 25 19:04:37 1995
+++ linux/arch/sparc/kernel/switch.S	Mon Mar  4 08:49:56 1996
@@ -1,4 +1,4 @@
-/* $Id: switch.S,v 1.9 1995/11/25 00:58:32 davem Exp $
+/* $Id: switch.S,v 1.14 1995/12/29 21:47:22 davem Exp $
  * switch.S: Sparc task switch code.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -13,8 +13,6 @@
 #include <asm/winmacro.h>
 
 #define sw_ntask     g1
-#define sw_sp        g2
-#define sw_pc        g3
 #define sw_psr       g4
 #define sw_wim       g5
 #define sw_tmp       g6
@@ -26,7 +24,7 @@
  * First successful task switch 05/13/95 21:52:37
  */
 	.align 4
-	.globl	C_LABEL(sparc_switch_to), C_LABEL(mmu_switch_lowlevel)
+	.globl	C_LABEL(sparc_switch_to)
 C_LABEL(sparc_switch_to):
 	mov	%o0, %sw_ntask
 
@@ -34,37 +32,24 @@
 	FLUSH_ALL_KERNEL_WINDOWS; 
 	STORE_WINDOW(sp)
 	rd	%psr, %sw_psr
-	sethi	%hi(PSR_EF), %sw_tmp
-	andn	%sw_psr, %sw_tmp, %sw_psr
-	LOAD_CURRENT(sw_tmp)
+	LOAD_CURRENT(sw_tmp, sw_wim)
 	rd	%wim, %sw_wim
 	std	%sw_psr, [%sw_tmp + THREAD_KPSR]
 	std	%sp, [%sw_tmp + THREAD_KSP]
 
 	/* Load new kernel state. */
 	wr	%sw_psr, PSR_ET, %psr
+	WRITE_PAUSE
 	sethi	%hi(C_LABEL(current_set)), %sw_tmp
 	st	%sw_ntask, [%sw_tmp + %lo(C_LABEL(current_set))]
 	ldd	[%sw_ntask + THREAD_KPSR], %sw_psr
-	ldd	[%sw_ntask + THREAD_KSP], %sw_sp
 	wr	%sw_psr, PSR_ET, %psr
 	WRITE_PAUSE
 	wr	%sw_wim, 0x0, %wim
 	WRITE_PAUSE
-	mov	%sw_sp, %sp
+	ldd	[%sw_ntask + THREAD_KSP], %sp
 	LOAD_WINDOW(sp)
-	mov	%sw_pc, %o7
 
-	/* Jump into the proper context. */
-	ld	[%sw_ntask + THREAD_CONTEXT], %sw_ctx
-	tst	%sw_ctx
-	bneg	1f			! this must be swapper
-	 nop
-
-C_LABEL(mmu_switch_lowlevel):
-	sethi	%hi(AC_CONTEXT), %sw_tmp	! else set new context
-	stba	%sw_ctx, [%sw_tmp] ASI_CONTROL
-1:
 	wr	%sw_psr, 0x0, %psr		! traps back on
 	WRITE_PAUSE
 
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/kernel/sys_bsd.c linux/arch/sparc/kernel/sys_bsd.c
--- v1.3.70/linux/arch/sparc/kernel/sys_bsd.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/kernel/sys_bsd.c	Mon Mar  4 08:49:56 1996
@@ -0,0 +1,48 @@
+/* sys_bsd.c: {net, open}bsd specific system call handling.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caipfs.rutgers.edu)
+ */
+#include <linux/kernel.h>
+
+#include <asm/ptrace.h>
+#include <asm/bsderrno.h>
+
+static int errno_trans[] = {
+	0,
+	BSD_EPERM, BSD_ENOENT, BSD_ESRCH, BSD_EINTR, BSD_EIO,
+	BSD_ENXIO, BSD_E2BIG, BSD_ENOEXEC, BSD_EBADF, BSD_ECHILD,
+	BSD_EAGAIN, BSD_ENOMEM, BSD_EACCES, BSD_EFAULT, BSD_ENOTBLK,
+	BSD_EBUSY, BSD_EEXIST, BSD_EXDEV, BSD_ENODEV, BSD_ENOTDIR,
+	BSD_EISDIR, BSD_EINVAL, BSD_ENFILE, BSD_EMFILE, BSD_ENOTTY,
+	BSD_ETXTBSY, BSD_EFBIG, BSD_ENOSPC, BSD_ESPIPE, BSD_EROFS,
+	BSD_EMLINK, BSD_EPIPE, BSD_EDOM, BSD_ERANGE, BSD_EWOULDBLOCK,
+	BSD_EINPROGRESS, BSD_EALREADY, BSD_ENOTSOCK, BSD_EDESTADDRREQ,
+	BSD_EMSGSIZE, BSD_EPROTOTYPE, BSD_ENOPROTOOPT, BSD_EPROTONOSUPPORT,
+	BSD_ESOCKTNOSUPPORT, BSD_EOPNOTSUPP, BSD_EPFNOSUPPORT, BSD_EAFNOSUPPORT,
+	BSD_EADDRINUSE,
+	BSD_EADDRNOTAVAIL, BSD_ENETDOWN, BSD_ENETUNREACH, BSD_ENETRESET,
+	BSD_ECONNABORTED, BSD_ECONNRESET, BSD_ENOBUFS, BSD_EISCONN,
+	BSD_ENOTCONN, BSD_ESHUTDOWN, BSD_ETOOMANYREFS, BSD_ETIMEDOUT,
+	BSD_ECONNREFUSED, BSD_ELOOP, BSD_ENAMETOOLONG, BSD_EHOSTDOWN,
+	BSD_EHOSTUNREACH, BSD_ENOTEMPTY, BSD_EPROCLIM, BSD_EUSERS,
+	BSD_EDQUOT, BSD_ESTALE, BSD_EREMOTE, BSD_ENOSTR, BSD_ETIME,
+	BSD_ENOSR, BSD_ENOMSG, BSD_EBADMSG, BSD_EIDRM, BSD_EDEADLK,
+	BSD_ENOLCK, BSD_ENONET, BSD_ERREMOTE, BSD_ENOLINK, BSD_EADV,
+	BSD_ESRMNT, BSD_ECOMM, BSD_EPROTO, BSD_EMULTIHOP, BSD_EDOTDOT,
+	BSD_EREMCHG, BSD_ENOSYS
+};
+
+asmlinkage int netbsd_nosys(void)
+{
+	struct pt_regs *regs;
+
+	regs = (struct pt_regs *) (current->saved_kernel_stack +
+				   sizeof(struct reg_window));
+	current->tss.sig_address = regs->pc;
+	current->tss.sig_desc = regs->u_regs[UREG_G1];
+	send_sig(SIGSYS, current, 1);
+	printk("Process makes ni_syscall number %d, register dump:\n",
+	       (int) regs->u_regs[UREG_G1]);
+	show_regs(regs);
+	return -BSD_ENOSYS;
+}
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/kernel/sys_sparc.c linux/arch/sparc/kernel/sys_sparc.c
--- v1.3.70/linux/arch/sparc/kernel/sys_sparc.c	Sat Nov 25 19:04:37 1995
+++ linux/arch/sparc/kernel/sys_sparc.c	Mon Mar  4 08:49:56 1996
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.6 1995/11/25 00:58:34 davem Exp $
+/* $Id: sys_sparc.c,v 1.7 1996/03/01 07:15:58 davem Exp $
  * linux/arch/sparc/kernel/sys_sparc.c
  *
  * This file contains various random system calls that
@@ -42,6 +42,38 @@
 		regs->u_regs[UREG_I1] = fd[1];
 	}
 }
+
+/* Note most sanity checking already done in sclow.S code. */
+asmlinkage int quick_sys_write(unsigned int fd, char *buf, unsigned int count)
+{
+	struct file *file = current->files->fd[fd];
+	struct inode *inode = file->f_inode;
+	int error;
+
+	error = verify_area(VERIFY_READ, buf, count);
+	if(error)
+		return error;
+	/*
+	 * If data has been written to the file, remove the setuid and
+	 * the setgid bits. We do it anyway otherwise there is an
+	 * extremely exploitable race - does your OS get it right |->
+	 *
+	 * Set ATTR_FORCE so it will always be changed.
+	 */
+	if (!suser() && (inode->i_mode & (S_ISUID | S_ISGID))) {
+		struct iattr newattrs;
+		newattrs.ia_mode = inode->i_mode & ~(S_ISUID | S_ISGID);
+		newattrs.ia_valid = ATTR_CTIME | ATTR_MODE | ATTR_FORCE;
+		notify_change(inode, &newattrs);
+	}
+
+	down(&inode->i_sem);
+	error = file->f_op->write(inode,file,buf,count);
+	up(&inode->i_sem);
+	return error;
+}
+
+/* XXX do we need this crap? XXX */
 
 /*
  * sys_ipc() is the de-multiplexer for the SysV IPC calls..
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c
--- v1.3.70/linux/arch/sparc/kernel/sys_sunos.c	Sat Nov 25 19:04:37 1995
+++ linux/arch/sparc/kernel/sys_sunos.c	Mon Mar  4 08:49:56 1996
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos.c,v 1.20 1995/11/25 00:58:37 davem Exp $
+/* $Id: sys_sunos.c,v 1.33 1996/03/01 07:16:00 davem Exp $
  * sys_sunos.c: SunOS specific syscall compatability support.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -15,6 +15,7 @@
 #include <linux/mman.h>
 #include <linux/errno.h>
 #include <linux/mm.h>
+#include <linux/swap.h>
 #include <linux/fs.h>
 #include <linux/resource.h>
 #include <linux/signal.h>
@@ -26,6 +27,8 @@
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/pconf.h>
+#include <asm/idprom.h> /* for gethostid() */
+#include <asm/unistd.h>
 
 /* For the nfs mount emulation */
 #include <linux/socket.h>
@@ -39,24 +42,18 @@
 
 static unsigned long get_sparc_unmapped_area(unsigned long len)
 {
-	unsigned long addr;
+	unsigned long addr = 0xE8000000UL;
 	struct vm_area_struct * vmm;
 
 	if (len > TASK_SIZE)
 		return 0;
-	addr = 0xE8000000UL;    /* To make it work on a sun4c. */
-	for (vmm = current->mm->mmap; ; vmm = vmm->vm_next) {
+	for (vmm = find_vma(current, addr); ; vmm = vmm->vm_next) {
+		/* At this point:  (!vmm || addr < vmm->vm_end). */
 		if (TASK_SIZE - len < addr)
 			return 0;
-		if (!vmm)
+		if (!vmm || addr + len <= vmm->vm_start)
 			return addr;
-		if (addr > vmm->vm_end)
-			continue;
-		if (addr + len > vmm->vm_start) {
-			addr = vmm->vm_end;
-			continue;
-		}
-		return addr;
+		addr = vmm->vm_end;
 	}
 }
 
@@ -99,22 +96,10 @@
 		return ((retval < KERNBASE) ? 0 : retval);
 }
 
-/* Weird SunOS mm control function.. */
+/* lmbench calls this, just say "yeah, ok" */
 asmlinkage int sunos_mctl(unsigned long addr, unsigned long len, int function, char *arg)
 {
-	printk("%s: Call to sunos_mctl(addr<%08lx>, len<%08lx>, function<%d>, arg<%p>) "
-	       "is unsupported\n", current->comm, addr, len, function, arg);
-	return -EAGAIN;
-}
-
-/* XXX This won't be necessary when I sync up to never kernel in 1.3.x series
- * XXX which has the sys_msync() system call implemented properly.
- */
-asmlinkage int sunos_msync(unsigned long addr, unsigned long len, unsigned long flags)
-{
-	printk("%s: Call to sunos_msync(addr<%08lx>, len<%08lx>, flags<%08lx>) "
-	       "is unsupported\n", current->comm, addr, len, flags);
-	return -EINVAL;
+	return 0;
 }
 
 /* SunOS is completely broken... it returns 0 on success, otherwise
@@ -188,10 +173,10 @@
 
 	/* This should do it hopefully... */
 	error = sunos_brk(((int) current->mm->brk) + increment);
-	if(error == 0)
-		return current->mm->brk;
-	else
+	if(error)
 		return error;
+	else
+		return current->mm->brk;
 }
 
 /* XXX Completely undocumented, and completely magic...
@@ -316,12 +301,28 @@
 
 asmlinkage unsigned long sunos_sigblock(unsigned long blk_mask)
 {
-	unsigned long old = current->blocked;
+	unsigned long flags;
+	unsigned long old;
 
+	save_flags(flags); cli();
+	old = current->blocked;
 	current->blocked |= (blk_mask & _BLOCKABLE);
+	restore_flags(flags);
 	return old;
 }
 
+asmlinkage unsigned long sunos_sigsetmask(unsigned long newmask)
+{
+	unsigned long flags;
+	unsigned long retval;
+
+	save_flags(flags); cli();
+	retval = current->blocked;
+	current->blocked = newmask & _BLOCKABLE;
+	restore_flags(flags);
+	return retval;
+}
+
 /* SunOS getdents is very similar to the newer Linux (iBCS2 compliant)    */
 /* getdents system call, the format of the structure just has a different */
 /* layout (d_off+d_ino instead of d_ino+d_off) */
@@ -359,7 +360,7 @@
 	dirent = buf->curr;
 	buf->previous = dirent;
 	put_user(ino, &dirent->d_ino);
-	put_user((strlen(name)), &dirent->d_namlen);
+	put_user(namlen, &dirent->d_namlen);
 	put_user(reclen, &dirent->d_reclen);
 	memcpy_tofs(dirent->d_name, name, namlen);
 	put_user(0, dirent->d_name + namlen);
@@ -399,6 +400,76 @@
 	return cnt - buf.count;
 }
 
+/* Old sunos getdirentries, severely broken compatability stuff here. */
+struct sunos_direntry {
+    unsigned long  d_ino;
+    unsigned short d_reclen;
+    unsigned short d_namlen;
+    char           d_name[1];
+};
+
+struct sunos_direntry_callback {
+    struct sunos_direntry *curr;
+    struct sunos_direntry *previous;
+    int count;
+    int error;
+};
+
+static int sunos_filldirentry(void * __buf, const char * name, int namlen,
+			      off_t offset, ino_t ino)
+{
+	struct sunos_direntry * dirent;
+	struct sunos_direntry_callback * buf = (struct sunos_direntry_callback *) __buf;
+	int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
+
+	buf->error = -EINVAL;	/* only used if we fail.. */
+	if (reclen > buf->count)
+		return -EINVAL;
+	dirent = buf->previous;
+	dirent = buf->curr;
+	buf->previous = dirent;
+	put_user(ino, &dirent->d_ino);
+	put_user(namlen, &dirent->d_namlen);
+	put_user(reclen, &dirent->d_reclen);
+	memcpy_tofs(dirent->d_name, name, namlen);
+	put_user(0, dirent->d_name + namlen);
+	((char *) dirent) += reclen;
+	buf->curr = dirent;
+	buf->count -= reclen;
+	return 0;
+}
+
+asmlinkage int sunos_getdirentries(unsigned int fd, void * dirent, int cnt, unsigned int *basep)
+{
+	struct file * file;
+	struct sunos_direntry * lastdirent;
+	struct sunos_direntry_callback buf;
+	int error;
+
+	if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+		return -EBADF;
+	if (!file->f_op || !file->f_op->readdir)
+		return -ENOTDIR;
+	if(verify_area(VERIFY_WRITE, dirent, cnt) ||
+	   verify_area(VERIFY_WRITE, basep, sizeof(unsigned int)))
+		return -EFAULT;
+	if(cnt < (sizeof(struct sunos_direntry) + 255))
+		return -EINVAL;
+
+	buf.curr = (struct sunos_direntry *) dirent;
+	buf.previous = NULL;
+	buf.count = cnt;
+	buf.error = 0;
+	error = file->f_op->readdir(file->f_inode, file, &buf, sunos_filldirentry);
+	if (error < 0)
+		return error;
+	lastdirent = buf.previous;
+	if (!lastdirent)
+		return buf.error;
+	put_user(file->f_pos, basep);
+	return cnt - buf.count;
+}
+
 asmlinkage int sunos_getdomainname(char *name, int len)
 {
 	int error;
@@ -430,18 +501,16 @@
 	if(error)
 		return error;
 	memcpy_tofs(&name->sname[0], &system_utsname.sysname[0],
-		    sizeof(name->sname));
+		    sizeof(name->sname) - 1);
 	memcpy_tofs(&name->nname[0], &system_utsname.nodename[0],
-		    sizeof(name->nname));
+		    sizeof(name->nname) - 1);
 	name->nname[8] = '\0';
-	memcpy_tofs(&name->nnext[0], &system_utsname.nodename[9],
-		    sizeof(name->nnext));
 	memcpy_tofs(&name->rel[0], &system_utsname.release[0],
-		    sizeof(name->rel));
+		    sizeof(name->rel) - 1);
 	memcpy_tofs(&name->ver[0], &system_utsname.version[0],
-		    sizeof(name->ver));
+		    sizeof(name->ver) - 1);
 	memcpy_tofs(&name->mach[0], &system_utsname.machine[0],
-		    sizeof(name->mach));
+		    sizeof(name->mach) - 1);
 	return 0;
 }
 
@@ -449,8 +518,8 @@
 {
 	struct pt_regs *regs;
 
-	regs = (struct pt_regs *) (((current->tss.ksp) & PAGE_MASK) +
-				   (PAGE_SIZE - TRACEREG_SZ));
+	regs = (struct pt_regs *) (current->saved_kernel_stack +
+				   sizeof(struct reg_window));
 	current->tss.sig_address = regs->pc;
 	current->tss.sig_desc = regs->u_regs[UREG_G1];
 	send_sig(SIGSYS, current, 1);
@@ -500,9 +569,9 @@
 
 asmlinkage int sunos_select(int width, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp)
 {
-    /* SunOS binaries expect that select won't change the tvp contents */
-    current->personality |= STICKY_TIMEOUTS;
-    return sys_select (width, inp, outp, exp, tvp);
+	/* SunOS binaries expect that select won't change the tvp contents */
+	current->personality |= STICKY_TIMEOUTS;
+	return sys_select (width, inp, outp, exp, tvp);
 }
 
 asmlinkage void sunos_nop(void)
@@ -520,38 +589,6 @@
 #define SMNT_MULTI        64
 #define SMNT_SYS5         128
 
-struct ufs_mntargs {
-	char *dev_name;
-};
-
-struct lo_mntargs {
-	char *dev_name;
-};
-
-struct ext2_mntargs {
-	char *dev_name;
-};
-
-struct iso9660_mntargs {
-	char *dev_name;
-};
-
-struct minix_mntargs {
-	char *dev_name;
-};
-
-struct ext_mntargs {
-	char *dev_name;
-};
-
-struct msdos_mntargs {
-	char *dev_name;
-};
-
-struct xiafs_mntargs {
-	char *dev_name;
-};
-
 struct sunos_fh_t {
 	char fh_data [NFS_FHSIZE];
 };
@@ -572,23 +609,14 @@
 	char       *netname;   /* server's netname */
 };
 
-extern asmlinkage int sys_mount(char *, char *, char *, unsigned long, void *);
 
-extern int do_mount(dev_t, const char *, char *, int, void *);
+extern int do_mount(kdev_t, const char *, const char *, char *, int, void *);
 extern dev_t get_unnamed_dev(void);
 extern void put_unnamed_dev(dev_t);
-
-extern sys_mount (char * dev_name, char * dir_name, char * type,
-		  unsigned long new_flags, void * data);
-
-extern asmlinkage int
-sys_connect(int fd, struct sockaddr *uservaddr, int addrlen);
-
-extern asmlinkage int
-sys_socket(int family, int type, int protocol);
-
-asmlinkage int
-sys_bind(int fd, struct sockaddr *umyaddr, int addrlen);
+extern asmlinkage int sys_mount(char *, char *, char *, unsigned long, void *);
+extern asmlinkage int sys_connect(int fd, struct sockaddr *uservaddr, int addrlen);
+extern asmlinkage int sys_socket(int family, int type, int protocol);
+extern asmlinkage int sys_bind(int fd, struct sockaddr *umyaddr, int addrlen);
 
 
 /* Bind the socket on a local reserved port and connect it to the
@@ -654,7 +682,6 @@
 	struct nfs_mount_data linux_nfs_mount;
 	struct sunos_nfs_mount_args *sunos_mount = data;
 	dev_t dev;
-	struct pt_regs *regs;
 
 	error = verify_area(VERIFY_READ, data, sizeof (struct sunos_nfs_mount_args));
 	if (error)
@@ -700,18 +727,10 @@
 
 	dev = get_unnamed_dev ();
 	
-	ret = do_mount (dev, dir_name, "nfs", linux_flags, &linux_nfs_mount);
+	ret = do_mount (dev, "", dir_name, "nfs", linux_flags, &linux_nfs_mount);
 	if (ret)
 	    put_unnamed_dev(dev);
 
-#if 0
-	/* Kill the process: the nfs directory is already mounted */
-	regs = (struct pt_regs *) (((current->tss.ksp) & PAGE_MASK) +
-				   (PAGE_SIZE - TRACEREG_SZ));
-	current->tss.sig_address = regs->pc;
-	current->tss.sig_desc = regs->u_regs[UREG_G1];
-	send_sig(SIGSYS, current, 1);
-#endif
 	return ret;
 }
 
@@ -740,7 +759,7 @@
 	if(error)
 		return error;
 	if(strcmp(type, "ext2") == 0) {
-		dev_fname = (char *) data;;
+		dev_fname = (char *) data;
 	} else if(strcmp(type, "iso9660") == 0) {
 		dev_fname = (char *) data;
 	} else if(strcmp(type, "minix") == 0) {
@@ -761,8 +780,6 @@
 	if(error)
 		return error;
 	error = sys_mount(dev_fname, dir, type, linux_flags, NULL);
-	printk("sys_mount(type<%s>, device<%s>) returns %d\n",
-	       type, dev_fname, error);
 	return error;
 }
 
@@ -794,8 +811,39 @@
 	return kill_pg(pgrp, sig, 0);
 }
 
-extern asmlinkage sunos_audit ()
+asmlinkage int sunos_audit(void)
 {
 	printk ("sys_audit\n");
+	return -1;
+}
+
+extern asmlinkage unsigned long sunos_gethostid(void)
+{
+	return (unsigned long) idprom->id_sernum;
+}
+
+extern asmlinkage long sunos_sysconf (int name)
+{
+	switch (name){
+	case _SC_ARG_MAX:
+		return ARG_MAX;
+	case _SC_CHILD_MAX:
+		return CHILD_MAX;
+	case _SC_CLK_TCK:
+		return HZ;
+	case _SC_NGROUPS_MAX:
+		return NGROUPS_MAX;
+	case _SC_OPEN_MAX:
+		return OPEN_MAX;
+	case _SC_JOB_CONTROL:
+		return 1;	/* yes, we do support job control */
+	case _SC_SAVED_IDS:
+		return 1;	/* yes, we do support saved uids  */
+	case _SC_VERSION:
+		/* mhm, POSIX_VERSION is in /usr/include/unistd.h
+		 * should it go on /usr/include/linux?
+		 */
+		return  199009L; 
+	}
 	return -1;
 }
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/kernel/systbls.S linux/arch/sparc/kernel/systbls.S
--- v1.3.70/linux/arch/sparc/kernel/systbls.S	Sat Nov 25 19:04:37 1995
+++ linux/arch/sparc/kernel/systbls.S	Mon Mar  4 08:49:56 1996
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.22 1995/11/25 00:58:42 davem Exp $
+/* $Id: systbls.S,v 1.29 1996/03/01 07:16:02 davem Exp $
  * systbls.S: System call entry point tables for OS compatability.
  *            The native Linux system call table lives here also.
  *
@@ -11,6 +11,30 @@
 
 #include <asm/cprefix.h>
 
+	/* READ THIS BEFORE DICKING WITH THIS TABLE...
+	 *
+	 * The format of these entries is kind of peculiar
+	 * to optimize non-blocking easy syscalls.  If
+	 * it is a difficult call or it will sleep the entry
+	 * is just to word aligned address of the function
+	 * routine to call.  If the lowest bit of the entry
+	 * is set then (entry & ~1) is the address of the low
+	 * in-trap-window assembler routine which will handle
+	 * the system call at the lowest possible level.  For
+	 * these low level optimized routines no state is saved
+	 * at all and the usual restrictions reply.  Act as
+	 * if you got called directly from the trap table.
+	 * Some of these optimized routines try really hard
+	 * to get around a state save, if you run into trouble
+	 * you can still survive by branching to the label
+	 * syscall_is_too_hard which is in entry.S  If you
+	 * have to back out like this you _must_ preserve the
+	 * value of %l0, %l1, %l2, and %l7 when you were called
+	 * so be _careful_.
+	 */
+
+#define LOWSYS(func) (CONCAT(func, _low) + 1)
+
 	.data
 	.align 4
 
@@ -18,521 +42,327 @@
 
 	.globl C_LABEL(sys_call_table)
 C_LABEL(sys_call_table):
-	.long C_LABEL(sys_setup)		/* 0 */
-	.long C_LABEL(sys_exit)
-	.long C_LABEL(sys_fork)
-	.long C_LABEL(sys_read)
-	.long C_LABEL(sys_write)
-	.long C_LABEL(sys_open)			/* 5 */
-	.long C_LABEL(sys_close)
-	.long C_LABEL(sys_wait4)
-	.long C_LABEL(sys_creat)
-	.long C_LABEL(sys_link)
-	.long C_LABEL(sys_unlink)		/* 10 */
-	.long C_LABEL(sunos_execv)
-	.long C_LABEL(sys_chdir)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_mknod)
-	.long C_LABEL(sys_chmod)		/* 15 */
-	.long C_LABEL(sys_chown)
-	.long C_LABEL(sys_brk)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_lseek)
-	.long C_LABEL(sys_getpid)		/* 20 */
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_setuid)
-	.long C_LABEL(sys_getuid)
-	.long C_LABEL(sys_ni_syscall)		/* 25 */
-	.long C_LABEL(sys_ni_syscall)		/* this will be sys_ptrace() */
-	.long C_LABEL(sys_alarm)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_pause)
-	.long C_LABEL(sys_utime)		/* 30 */
-	.long C_LABEL(sys_stty)
-	.long C_LABEL(sys_gtty)
-	.long C_LABEL(sys_access)
-	.long C_LABEL(sys_nice)
-	.long C_LABEL(sys_ftime)		/* 35 */
-	.long C_LABEL(sys_sync)
-	.long C_LABEL(sys_kill)
-	.long C_LABEL(sys_newstat)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_newlstat)		/* 40 */
-	.long C_LABEL(sys_dup)
-	.long C_LABEL(sys_pipe)
-	.long C_LABEL(sys_times)
-	.long C_LABEL(sys_profil)
-	.long C_LABEL(sys_ni_syscall)		/* 45 */
-	.long C_LABEL(sys_setgid)
-	.long C_LABEL(sys_getgid)
-	.long C_LABEL(sys_signal)
-	.long C_LABEL(sys_geteuid)
-	.long C_LABEL(sys_getegid)		/* 50 */
-	.long C_LABEL(sys_acct)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ioctl)
-	.long C_LABEL(sys_reboot)		/* 55 */
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_symlink)
-	.long C_LABEL(sys_readlink)
-	.long C_LABEL(sys_execve)
-	.long C_LABEL(sys_umask)		/* 60 */
-	.long C_LABEL(sys_chroot)
-	.long C_LABEL(sys_newfstat)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_getpagesize)
-	.long C_LABEL(sys_ni_syscall)		/* 65 */
-	.long C_LABEL(sys_vfork)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)		/* 70 */
-	.long C_LABEL(sunos_mmap)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_munmap)
-	.long C_LABEL(sys_mprotect)
-	.long C_LABEL(sys_ni_syscall)		/* 75 */
-	.long C_LABEL(sys_vhangup)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_getgroups)
-	.long C_LABEL(sys_setgroups)		/* 80 */
-	.long C_LABEL(sys_getpgrp)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_setitimer)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_swapon)		/* 85 */
-	.long C_LABEL(sys_getitimer)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_sethostname)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_dup2)			/* 90 */
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_fcntl)
-	.long C_LABEL(sys_select)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_fsync)		/* 95 */
-	.long C_LABEL(sys_setpriority)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_getpriority)		/* 100 */
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)		/* 105 */
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)		/* 110 */
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)		/* 115 */
-	.long C_LABEL(sys_gettimeofday)
-	.long C_LABEL(sys_getrusage)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)		/* 120 */
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_settimeofday)
-	.long C_LABEL(sys_fchown)
-	.long C_LABEL(sys_fchmod)
-	.long C_LABEL(sys_ni_syscall)		/* 125 */
-	.long C_LABEL(sys_setreuid)
-	.long C_LABEL(sys_setregid)
-	.long C_LABEL(sys_rename)
-	.long C_LABEL(sys_truncate)
-	.long C_LABEL(sys_ftruncate)		/* 130 */
-	.long C_LABEL(sys_flock)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)		/* 135 */
-	.long C_LABEL(sys_mkdir)
-	.long C_LABEL(sys_rmdir)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)		/* 140 */
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_getrlimit)
-	.long C_LABEL(sys_setrlimit)		/* 145 */
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)		/* 150 */
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)		/* 155 */
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_statfs)
-	.long C_LABEL(sys_fstatfs)
-	.long C_LABEL(sys_umount)
-	.long C_LABEL(sys_ni_syscall)		/* 160 */
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_setdomainname)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)		/* sys_quotactl -- 165 */
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_mount)
-	.long C_LABEL(sys_ustat)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)		/* 170 */
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_getdents)
-	.long C_LABEL(sys_setsid)		/* 175 */
-	.long C_LABEL(sys_fchdir)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)		/* 180 */
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_sigpending)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_setpgid)		/* 185 */
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_uname)
-	.long C_LABEL(sys_init_module)		/* 190 */
-	.long C_LABEL(sys_personality)
-	.long C_LABEL(sys_prof)
-	.long C_LABEL(sys_break)
-	.long C_LABEL(sys_lock)
-	.long C_LABEL(sys_mpx)			/* 195 */
-	.long C_LABEL(sys_ulimit)
-	.long C_LABEL(sys_getppid)
-	.long C_LABEL(sys_sigaction)
-	.long C_LABEL(sys_sgetmask)
-	.long C_LABEL(sys_ssetmask)		/* 200 */
-	.long C_LABEL(sys_sigsuspend)
-	.long C_LABEL(sys_newlstat)
-	.long C_LABEL(sys_uselib)
-	.long C_LABEL(old_readdir)
-	.long C_LABEL(sys_ni_syscall)		/* 205 */
-	.long C_LABEL(sys_socketcall)
-	.long C_LABEL(sys_syslog)
-	.long C_LABEL(sys_olduname)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_idle)			/* 210 */
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_waitpid)
-	.long C_LABEL(sys_swapoff)
-	.long C_LABEL(sys_sysinfo)
-	.long C_LABEL(sys_ipc)			/* 215 */
-	.long C_LABEL(sys_sigreturn)
-	.long C_LABEL(sys_clone)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_adjtimex)
-	.long C_LABEL(sys_sigprocmask)		/* 220 */
-	.long C_LABEL(sys_create_module)
-	.long C_LABEL(sys_delete_module)
-	.long C_LABEL(sys_get_kernel_syms)
-	.long C_LABEL(sys_getpgid)
-	.long C_LABEL(sys_bdflush)		/* 225 */
-	.long C_LABEL(sys_sysfs)
-	.long C_LABEL(sys_ni_syscall)		/* Andrew Filesystem Syscall */
-	.long C_LABEL(sys_setfsuid)
-	.long C_LABEL(sys_setfsgid)
-	.long C_LABEL(sys_llseek)		/* 230 Should be newselect... */
-	.long C_LABEL(sys_time)
-	.long C_LABEL(sys_ni_syscall) 		/* Should be oldstat... */
-	.long C_LABEL(sys_stime)
-	.long C_LABEL(sys_ni_syscall)           /* Should be oldfstat */
-	.long C_LABEL(sys_ni_syscall)		/* 235 - sys_phys */
-	.long C_LABEL(sys_llseek)
-
+/*0*/	.long C_LABEL(sys_setup), C_LABEL(sys_exit), C_LABEL(sys_fork)
+	.long C_LABEL(sys_read), C_LABEL(sys_write), C_LABEL(sys_open)
+	.long C_LABEL(sys_close), C_LABEL(sys_wait4), C_LABEL(sys_creat)
+	.long C_LABEL(sys_link), C_LABEL(sys_unlink), C_LABEL(sunos_execv)
+	.long C_LABEL(sys_chdir), C_LABEL(sys_ni_syscall), C_LABEL(sys_mknod)
+	.long C_LABEL(sys_chmod), C_LABEL(sys_chown), C_LABEL(sys_brk)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_lseek), C_LABEL(sys_getpid)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_setuid)
+	.long C_LABEL(sys_getuid), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_alarm), C_LABEL(sys_ni_syscall), C_LABEL(sys_pause)
+	.long C_LABEL(sys_utime), C_LABEL(sys_stty), C_LABEL(sys_gtty)
+	.long C_LABEL(sys_access), C_LABEL(sys_nice), C_LABEL(sys_ftime)
+	.long C_LABEL(sys_sync), C_LABEL(sys_kill), C_LABEL(sys_newstat)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_newlstat), C_LABEL(sys_dup)
+	.long C_LABEL(sys_pipe), C_LABEL(sys_times), C_LABEL(sys_profil)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_setgid), C_LABEL(sys_getgid)
+	.long C_LABEL(sys_signal), C_LABEL(sys_geteuid)
+/*50*/	.long C_LABEL(sys_getegid), C_LABEL(sys_acct), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ioctl), C_LABEL(sys_reboot)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_symlink), C_LABEL(sys_readlink)
+	.long C_LABEL(sys_execve), C_LABEL(sys_umask), C_LABEL(sys_chroot)
+	.long C_LABEL(sys_newfstat), C_LABEL(sys_ni_syscall), C_LABEL(sys_getpagesize)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_vfork), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sunos_mmap), C_LABEL(sys_ni_syscall), C_LABEL(sys_munmap)
+	.long C_LABEL(sys_mprotect), C_LABEL(sys_ni_syscall), C_LABEL(sys_vhangup)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_getgroups)
+	.long C_LABEL(sys_setgroups), C_LABEL(sys_getpgrp), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_setitimer), C_LABEL(sys_ni_syscall), C_LABEL(sys_swapon)
+	.long C_LABEL(sys_getitimer), C_LABEL(sys_ni_syscall), C_LABEL(sys_sethostname)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_dup2), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_fcntl), C_LABEL(sys_select), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_fsync), C_LABEL(sys_setpriority), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+/*100*/	.long C_LABEL(sys_getpriority), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_gettimeofday), C_LABEL(sys_getrusage)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_settimeofday), C_LABEL(sys_fchown)
+	.long C_LABEL(sys_fchmod), C_LABEL(sys_ni_syscall), C_LABEL(sys_setreuid)
+	.long C_LABEL(sys_setregid), C_LABEL(sys_rename), C_LABEL(sys_truncate)
+	.long C_LABEL(sys_ftruncate), C_LABEL(sys_flock), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_mkdir), C_LABEL(sys_rmdir), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_getrlimit)
+	.long C_LABEL(sys_setrlimit), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+/*150*/	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_statfs), C_LABEL(sys_fstatfs)
+	.long C_LABEL(sys_umount), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_setdomainname)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_quotactl), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_mount), C_LABEL(sys_ustat), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_getdents), C_LABEL(sys_setsid)
+	.long C_LABEL(sys_fchdir), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_sigpending), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_setpgid), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_uname), C_LABEL(sys_init_module)
+	.long C_LABEL(sys_personality), C_LABEL(sys_prof), C_LABEL(sys_break)
+	.long C_LABEL(sys_lock), C_LABEL(sys_mpx), C_LABEL(sys_ulimit)
+	.long C_LABEL(sys_getppid), C_LABEL(sys_sigaction), C_LABEL(sys_sgetmask)
+/*200*/	.long C_LABEL(sys_ssetmask), C_LABEL(sys_sigsuspend), C_LABEL(sys_newlstat)
+	.long C_LABEL(sys_uselib), C_LABEL(old_readdir), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_socketcall), C_LABEL(sys_syslog), C_LABEL(sys_olduname)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_idle), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_waitpid), C_LABEL(sys_swapoff), C_LABEL(sys_sysinfo)
+	.long C_LABEL(sys_ipc), C_LABEL(sys_sigreturn), C_LABEL(sys_clone)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_adjtimex), C_LABEL(sys_sigprocmask)
+	.long C_LABEL(sys_create_module), C_LABEL(sys_delete_module)
+	.long C_LABEL(sys_get_kernel_syms), C_LABEL(sys_getpgid), C_LABEL(sys_bdflush)
+	.long C_LABEL(sys_sysfs), C_LABEL(sys_ni_syscall), C_LABEL(sys_setfsuid)
+	.long C_LABEL(sys_setfsgid), C_LABEL(sys_llseek), C_LABEL(sys_time)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_stime), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_llseek)
 	/* "We are the Knights of the Forest of Ni!!" */
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
 	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)		/* 240 */
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)		/* 245 */
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)		/* 250 */
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)
-	.long C_LABEL(sys_ni_syscall)		/* 255 */
+/*250*/	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
+	.long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
 
 	/* Now the SunOS syscall table. */
 
 	.align 4
 	.globl C_LABEL(sunos_sys_table)
 C_LABEL(sunos_sys_table):
-	.long C_LABEL(sunos_indir)		/* so stupid... */
-	.long C_LABEL(sys_exit)
-	.long C_LABEL(sys_fork)
-	.long C_LABEL(sys_read)
-	.long C_LABEL(sys_write)
-	.long C_LABEL(sys_open)			/* 5 */
-	.long C_LABEL(sys_close)
-	.long C_LABEL(sunos_wait4)		/* broken... */
-	.long C_LABEL(sys_creat)
-	.long C_LABEL(sys_link)
-	.long C_LABEL(sys_unlink)		/* 10 */
-	.long C_LABEL(sunos_execv)
-	.long C_LABEL(sys_chdir)
-	.long C_LABEL(sunos_nosys)		/* Obsolete sys_time(), unused */
-	.long C_LABEL(sys_mknod)
-	.long C_LABEL(sys_chmod)		/* 15 */
-	.long C_LABEL(sys_chown)
-	.long C_LABEL(sunos_brk)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sys_lseek)
-	.long C_LABEL(sunos_getpid)		/* 20 */
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_getuid)
-	.long C_LABEL(sunos_nosys)		/* 25 */
-	.long C_LABEL(sunos_nosys)		/* this will be sys_ptrace() */
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)		/* Old SunOS fstat, unsupported */
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)		/* 30 */
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sys_access)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)		/* 35 */
-	.long C_LABEL(sys_sync)
-	.long C_LABEL(sys_kill)
-	.long C_LABEL(sys_newstat)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sys_newlstat)		/* 40 */
-	.long C_LABEL(sys_dup)
-	.long C_LABEL(sys_pipe)
-	.long C_LABEL(sunos_nosys)		/* SunOS sys_times() */
-	.long C_LABEL(sys_profil)
-	.long C_LABEL(sunos_nosys)		/* 45 */
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_getgid)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)		/* 50 */
-	.long C_LABEL(sys_acct)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_mctl)
-	.long C_LABEL(sunos_ioctl)
-	.long C_LABEL(sys_reboot)		/* 55 */
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sys_symlink)
-	.long C_LABEL(sys_readlink)
-	.long C_LABEL(sys_execve)
-	.long C_LABEL(sys_umask)		/* 60 */
-	.long C_LABEL(sys_chroot)
-	.long C_LABEL(sys_newfstat)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sys_getpagesize)
-	.long C_LABEL(sunos_msync)		/* 65 */
-	.long C_LABEL(sys_vfork)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_sbrk)
-	.long C_LABEL(sunos_sstk)		/* 70 */
-	.long C_LABEL(sunos_mmap)
-	.long C_LABEL(sunos_vadvise)
-	.long C_LABEL(sys_munmap)
-	.long C_LABEL(sys_mprotect)
-	.long C_LABEL(sunos_madvise)		/* 75 */
-	.long C_LABEL(sys_vhangup)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_mincore)
-	.long C_LABEL(sys_getgroups)
-	.long C_LABEL(sys_setgroups)		/* 80 */
-	.long C_LABEL(sys_getpgrp)
-	.long C_LABEL(sunos_setpgrp)
-	.long C_LABEL(sys_setitimer)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sys_swapon)		/* 85 */
-	.long C_LABEL(sys_getitimer)
-	.long C_LABEL(sys_gethostname)
-	.long C_LABEL(sys_sethostname)
-	.long C_LABEL(sunos_getdtablesize)
-	.long C_LABEL(sys_dup2)			/* 90 */
-	.long C_LABEL(sunos_nop)		/* getdopt() does nothing */
-	.long C_LABEL(sys_fcntl)
-	.long C_LABEL(sys_select)
-	.long C_LABEL(sunos_nop)		/* setdopt() also does nothing */
-	.long C_LABEL(sys_fsync)		/* 95 */
-	.long C_LABEL(sys_setpriority)
-	.long C_LABEL(sys_socket)
-	.long C_LABEL(sys_connect)
-	.long C_LABEL(sys_accept)
-	.long C_LABEL(sys_getpriority)		/* 100 */
-	.long C_LABEL(sys_send)
-	.long C_LABEL(sys_recv)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sys_bind)
-	.long C_LABEL(sys_setsockopt)		/* 105 */
-	.long C_LABEL(sys_listen)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sys_sigaction)		/* sigvec */
-	.long C_LABEL(sunos_sigblock)		/* sigblock */
-	.long C_LABEL(sys_ssetmask)		/* sigsetmask -- 110 */
-	.long C_LABEL(sys_sigpause)		/* sigpause */
-	.long C_LABEL(sys_sigstack)		/* sigstack */
-	.long C_LABEL(sunos_nosys)		/* recvmsg */
-	.long C_LABEL(sunos_nosys)		/* sendmsg */
-	.long C_LABEL(sunos_nosys)		/* vtrace -- 115 */
-	.long C_LABEL(sys_gettimeofday)
-	.long C_LABEL(sys_getrusage)
-	.long C_LABEL(sys_getsockopt)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sys_readv)		/* 120 */
-	.long C_LABEL(sys_writev)
-	.long C_LABEL(sys_settimeofday)
-	.long C_LABEL(sys_fchown)
-	.long C_LABEL(sys_fchmod)
-	.long C_LABEL(sys_recvfrom)		/* recvfrom -- 125 */
-	.long C_LABEL(sys_setreuid)
-	.long C_LABEL(sys_setregid)
-	.long C_LABEL(sys_rename)
-	.long C_LABEL(sys_truncate)
-	.long C_LABEL(sys_ftruncate)		/* 130 */
-	.long C_LABEL(sys_flock)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sys_sendto)		/* sendto */
-	.long C_LABEL(sys_shutdown)		/* shutdown */
-	.long C_LABEL(sunos_nosys)		/* socketpair -- 135 */
-	.long C_LABEL(sys_mkdir)
-	.long C_LABEL(sys_rmdir)
-	.long C_LABEL(sys_utimes)		/* utimes */
-	.long C_LABEL(sys_sigreturn)
-	.long C_LABEL(sunos_nosys)		/* adjtime -- 140 */
-	.long C_LABEL(sys_getpeername)		/* getpeername */
-	.long C_LABEL(sunos_nosys)		/* gethostid */
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sys_getrlimit)
-	.long C_LABEL(sys_setrlimit)		/* 145 */
-	.long C_LABEL(sunos_killpg)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sys_getsockname)		/* getsockname -- 150 */
-	.long C_LABEL(sunos_nosys)		/* getmsg */
-	.long C_LABEL(sunos_nosys)		/* putmsg */
-	.long C_LABEL(sunos_nosys)		/* poll */
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)		/* nfssvc -- 155 */
-	.long C_LABEL(sunos_nosys)		/* getdirectries */
-	.long C_LABEL(sys_statfs)
-	.long C_LABEL(sys_fstatfs)
-	.long C_LABEL(sys_umount)
-	.long C_LABEL(sunos_nosys)		/* async_daemon -- 160 */
-	.long C_LABEL(sunos_nosys)		/* getfh */
-	.long C_LABEL(sunos_getdomainname)	/* getdomainname */
-	.long C_LABEL(sys_setdomainname)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)		/* quotactl -- 165 */
-	.long C_LABEL(sunos_nosys)		/* exportfs */
-	.long C_LABEL(sunos_mount)
-	.long C_LABEL(sys_ustat)
-	.long C_LABEL(sunos_nosys)		/* semsys */
-	.long C_LABEL(sunos_nosys)		/* msgsys -- 170 */
-	.long C_LABEL(sunos_nosys)		/* shmsys */
-	.long C_LABEL(sunos_audit)		/* auditsys */
-	.long C_LABEL(sunos_nosys)		/* rfssys */
-	.long C_LABEL(sunos_getdents)
-	.long C_LABEL(sys_setsid)		/* 175 */
-	.long C_LABEL(sys_fchdir)
-	.long C_LABEL(sunos_nosys)		/* fchroot */
-	.long C_LABEL(sunos_nosys)		/* vpixsys ???XXX */
-	.long C_LABEL(sunos_nosys)		/* aioread */
-	.long C_LABEL(sunos_nosys)		/* aiowrite -- 180 */
-	.long C_LABEL(sunos_nosys)		/* aiowait */
-	.long C_LABEL(sunos_nosys)		/* aiocancel */
-	.long C_LABEL(sys_sigpending)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sys_setpgid)		/* 185 */
-	.long C_LABEL(sunos_pathconf)		/* pathconf */
-	.long C_LABEL(sunos_fpathconf)		/* fpathconf */
-	.long C_LABEL(sunos_nosys)		/* sysconf */
-	.long C_LABEL(sunos_uname)
-	.long C_LABEL(sunos_nosys)		/* 190 */
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)		/* 195 */
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)		/* 200 */
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)		/* 205 */
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)		/* 210 */
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)		/* 215 */
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)		/* 220 */
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)		/* 225 */
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)		/* 230 */
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)		/* 235 */
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)		/* 240 */
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)		/* 245 */
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)		/* 250 */
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)
-	.long C_LABEL(sunos_nosys)		/* 255 */
+/*0*/	.long C_LABEL(sunos_indir), C_LABEL(sys_exit), C_LABEL(sys_fork)
+	.long C_LABEL(sys_read), C_LABEL(sys_write), C_LABEL(sys_open)
+	.long C_LABEL(sys_close), C_LABEL(sunos_wait4), C_LABEL(sys_creat)
+	.long C_LABEL(sys_link), C_LABEL(sys_unlink), C_LABEL(sunos_execv)
+	.long C_LABEL(sys_chdir), C_LABEL(sunos_nosys), C_LABEL(sys_mknod)
+	.long C_LABEL(sys_chmod), C_LABEL(sys_chown), C_LABEL(sunos_brk)
+	.long C_LABEL(sunos_nosys), C_LABEL(sys_lseek), LOWSYS(sunosgetpid)
+	.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+	.long LOWSYS(sunosgetuid), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+	.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+	.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+	.long C_LABEL(sys_access), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+	.long C_LABEL(sys_sync), C_LABEL(sys_kill), C_LABEL(sys_newstat)
+	.long C_LABEL(sunos_nosys), C_LABEL(sys_newlstat), C_LABEL(sys_dup)
+	.long C_LABEL(sys_pipe), C_LABEL(sunos_nosys), C_LABEL(sys_profil)
+	.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), LOWSYS(sunosgetgid)
+	.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+/*50*/	.long C_LABEL(sunos_nosys), C_LABEL(sys_acct), C_LABEL(sunos_nosys)
+	.long LOWSYS(sunosmctl), C_LABEL(sunos_ioctl), C_LABEL(sys_reboot)
+	.long C_LABEL(sunos_nosys), C_LABEL(sys_symlink), C_LABEL(sys_readlink)
+	.long C_LABEL(sys_execve), LOWSYS(umask), C_LABEL(sys_chroot)
+	.long C_LABEL(sys_newfstat), C_LABEL(sunos_nosys), LOWSYS(getpagesize)
+	.long C_LABEL(sys_msync), C_LABEL(sys_vfork), C_LABEL(sunos_nosys)
+	.long C_LABEL(sunos_nosys), C_LABEL(sunos_sbrk), C_LABEL(sunos_sstk)
+	.long C_LABEL(sunos_mmap), C_LABEL(sunos_vadvise), C_LABEL(sys_munmap)
+	.long C_LABEL(sys_mprotect), C_LABEL(sunos_madvise), C_LABEL(sys_vhangup)
+	.long C_LABEL(sunos_nosys), C_LABEL(sunos_mincore), C_LABEL(sys_getgroups)
+	.long C_LABEL(sys_setgroups), C_LABEL(sys_getpgrp), C_LABEL(sunos_setpgrp)
+	.long C_LABEL(sys_setitimer), C_LABEL(sunos_nosys), C_LABEL(sys_swapon)
+	.long C_LABEL(sys_getitimer), C_LABEL(sys_gethostname), C_LABEL(sys_sethostname)
+	.long LOWSYS(sunosgdtsize), C_LABEL(sys_dup2), LOWSYS(sunosnop)
+	.long C_LABEL(sys_fcntl), C_LABEL(sunos_select), LOWSYS(sunosnop)
+	.long C_LABEL(sys_fsync), C_LABEL(sys_setpriority), C_LABEL(sys_socket)
+	.long C_LABEL(sys_connect), C_LABEL(sys_accept)
+/*100*/	.long C_LABEL(sys_getpriority), C_LABEL(sys_send), C_LABEL(sys_recv)
+	.long C_LABEL(sunos_nosys), C_LABEL(sys_bind), C_LABEL(sys_setsockopt)
+	.long C_LABEL(sys_listen), C_LABEL(sunos_nosys), C_LABEL(sys_sigaction)
+	.long LOWSYS(sunossblock), LOWSYS(sunossmask), C_LABEL(sys_sigpause)
+	.long C_LABEL(sys_sigstack), C_LABEL(sys_recvmsg), C_LABEL(sys_sendmsg)
+	.long C_LABEL(sunos_nosys), C_LABEL(sys_gettimeofday), C_LABEL(sys_getrusage)
+	.long C_LABEL(sys_getsockopt), C_LABEL(sunos_nosys), C_LABEL(sys_readv)
+	.long C_LABEL(sys_writev), C_LABEL(sys_settimeofday), C_LABEL(sys_fchown)
+	.long C_LABEL(sys_fchmod), C_LABEL(sys_recvfrom), C_LABEL(sys_setreuid)
+	.long C_LABEL(sys_setregid), C_LABEL(sys_rename), C_LABEL(sys_truncate)
+	.long C_LABEL(sys_ftruncate), C_LABEL(sys_flock), C_LABEL(sunos_nosys)
+	.long C_LABEL(sys_sendto), C_LABEL(sys_shutdown), C_LABEL(sys_socketpair)
+	.long C_LABEL(sys_mkdir), C_LABEL(sys_rmdir), C_LABEL(sys_utimes)
+	.long C_LABEL(sys_sigreturn), C_LABEL(sunos_nosys), C_LABEL(sys_getpeername)
+	.long C_LABEL(sunos_gethostid), C_LABEL(sunos_nosys), C_LABEL(sys_getrlimit)
+	.long C_LABEL(sys_setrlimit), C_LABEL(sunos_killpg), C_LABEL(sunos_nosys)
+	.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+/*150*/	.long C_LABEL(sys_getsockname), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+	.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+	.long C_LABEL(sunos_getdirentries), C_LABEL(sys_statfs), C_LABEL(sys_fstatfs)
+	.long C_LABEL(sys_umount), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+	.long C_LABEL(sunos_getdomainname), C_LABEL(sys_setdomainname)
+	.long C_LABEL(sunos_nosys), C_LABEL(sys_quotactl), C_LABEL(sunos_nosys)
+	.long C_LABEL(sunos_mount), C_LABEL(sys_ustat), C_LABEL(sunos_nosys)
+	.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_audit)
+	.long C_LABEL(sunos_nosys), C_LABEL(sunos_getdents), C_LABEL(sys_setsid)
+	.long C_LABEL(sys_fchdir), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+	.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+	.long C_LABEL(sunos_nosys), C_LABEL(sys_sigpending), C_LABEL(sunos_nosys)
+	.long C_LABEL(sys_setpgid), C_LABEL(sunos_pathconf), C_LABEL(sunos_fpathconf)
+	.long C_LABEL(sunos_sysconf), C_LABEL(sunos_uname), C_LABEL(sunos_nosys)
+	.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+	.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+	.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+/*200*/	.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+	.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+	.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+	.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+	.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+	.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+	.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+	.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+	.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+	.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+	.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+	.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+	.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+	.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+	.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+	.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+	.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+/*250*/	.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+	.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
+
+	/* {net, open}bsd system call table. */
+
+	.align	4
+	.globl	C_LABEL(bsd_sys_table)
+C_LABEL(bsd_sys_table):
+	.long C_LABEL(sunos_nosys)/*SYSCALL*/, C_LABEL(sunos_nosys)/*EXIT*/
+	.long C_LABEL(sunos_nosys)/*FORK*/, C_LABEL(sunos_nosys)/*READ*/
+	.long C_LABEL(sunos_nosys)/*WRITE*/, C_LABEL(sunos_nosys)/*OPEN*/
+	.long C_LABEL(sunos_nosys)/*CLOSE*/, C_LABEL(sunos_nosys)/*WAIT4*/
+	.long C_LABEL(sunos_nosys)/*CREAT*/, C_LABEL(sunos_nosys)/*LINK*/
+	.long C_LABEL(sunos_nosys)/*UNLINK*/, C_LABEL(sunos_nosys)/*EXECV*/
+	.long C_LABEL(sunos_nosys)/*CHDIR*/, C_LABEL(sunos_nosys)/*FCHDIR*/
+	.long C_LABEL(sunos_nosys)/*MKNOD*/, C_LABEL(sunos_nosys)/*CHMOD*/
+	.long C_LABEL(sunos_nosys)/*CHOWN*/, C_LABEL(sunos_nosys)/*BREAK*/
+	.long C_LABEL(sunos_nosys)/*GETFSSTAT*/, C_LABEL(sunos_nosys)/*OLSEEK*/
+	.long C_LABEL(sunos_nosys)/*GETPID*/, C_LABEL(sunos_nosys)/*MOUNT*/
+	.long C_LABEL(sunos_nosys)/*UNMOUNT*/, C_LABEL(sunos_nosys)/*SETUID*/
+	.long C_LABEL(sunos_nosys)/*GETUID*/, C_LABEL(sunos_nosys)/*GETEUID*/
+	.long C_LABEL(sunos_nosys)/*PTRACE*/, C_LABEL(sunos_nosys)/*RECVMSG*/
+	.long C_LABEL(sunos_nosys)/*SENDMSG*/, C_LABEL(sunos_nosys)/*RECVFROM*/
+	.long C_LABEL(sunos_nosys)/*ACCEPT*/, C_LABEL(sunos_nosys)/*GETPEERNAME*/
+	.long C_LABEL(sunos_nosys)/*GETSOCKNAME*/, C_LABEL(sunos_nosys)/*ACCESS*/
+	.long C_LABEL(sunos_nosys)/*CHFLAGS*/, C_LABEL(sunos_nosys)/*FCHFLAGS*/
+	.long C_LABEL(sunos_nosys)/*SYNC*/, C_LABEL(sunos_nosys)/*KILL*/
+	.long C_LABEL(sunos_nosys)/*OSTAT*/, C_LABEL(sunos_nosys)/*GETPPID*/
+	.long C_LABEL(sunos_nosys)/*OLSTAT*/, C_LABEL(sunos_nosys)/*DUP*/
+	.long C_LABEL(sunos_nosys)/*PIPE*/, C_LABEL(sunos_nosys)/*GETEGID*/
+	.long C_LABEL(sunos_nosys)/*PROFIL*/, C_LABEL(sunos_nosys)/*KTRACE*/
+	.long C_LABEL(sunos_nosys)/*SIGACTION*/, C_LABEL(sunos_nosys)/*GETGID*/
+	.long C_LABEL(sunos_nosys)/*SIGPROCMASK*/, C_LABEL(sunos_nosys)/*GETLOGIN*/
+	.long C_LABEL(sunos_nosys)/*SETLOGIN*/, C_LABEL(sunos_nosys)/*ACCT*/
+	.long C_LABEL(sunos_nosys)/*SIGPENDING*/, C_LABEL(sunos_nosys)/*SIGALTSTACK*/
+	.long C_LABEL(sunos_nosys)/*IOCTL*/, C_LABEL(sunos_nosys)/*REBOOT*/
+	.long C_LABEL(sunos_nosys)/*REVOKE*/, C_LABEL(sunos_nosys)/*SYMLINK*/
+	.long C_LABEL(sunos_nosys)/*READLINK*/, C_LABEL(sunos_nosys)/*EXECVE*/
+	.long C_LABEL(sunos_nosys)/*UMASK*/, C_LABEL(sunos_nosys)/*CHROOT*/
+	.long C_LABEL(sunos_nosys)/*OFSTAT*/, C_LABEL(sunos_nosys)/*OGETKERNINFO*/
+	.long C_LABEL(sunos_nosys)/*OGETPAGESIZE*/, C_LABEL(sunos_nosys)/*MSYNC*/
+	.long C_LABEL(sunos_nosys)/*VFORK*/, C_LABEL(sunos_nosys)/*VREAD*/
+	.long C_LABEL(sunos_nosys)/*VWRITE*/, C_LABEL(sunos_nosys)/*SBRK*/
+	.long C_LABEL(sunos_nosys)/*SSTK*/, C_LABEL(sunos_nosys)/*OMMAP*/
+	.long C_LABEL(sunos_nosys)/*VADVISE*/, C_LABEL(sunos_nosys)/*MUNMAP*/
+	.long C_LABEL(sunos_nosys)/*MPROTECT*/, C_LABEL(sunos_nosys)/*MADVISE*/
+	.long C_LABEL(sunos_nosys)/*VHANGUP*/, C_LABEL(sunos_nosys)/*VLIMIT*/
+	.long C_LABEL(sunos_nosys)/*MINCORE*/, C_LABEL(sunos_nosys)/*GETGROUPS*/
+	.long C_LABEL(sunos_nosys)/*SETGROUPS*/, C_LABEL(sunos_nosys)/*GETPGRP*/
+	.long C_LABEL(sunos_nosys)/*SETPGID*/, C_LABEL(sunos_nosys)/*SETITIMER*/
+	.long C_LABEL(sunos_nosys)/*OWAIT*/, C_LABEL(sunos_nosys)/*SWAPON*/
+	.long C_LABEL(sunos_nosys)/*GETITIMER*/, C_LABEL(sunos_nosys)/*OGETHOSTNAME*/
+	.long C_LABEL(sunos_nosys)/*OSETHOSTNAME*/, C_LABEL(sunos_nosys)/*OGETDTABLESIZE*/
+	.long C_LABEL(sunos_nosys)/*DUP2*/, C_LABEL(sunos_nosys)/*GETDOPT*/
+	.long C_LABEL(sunos_nosys)/*FCNTL*/, C_LABEL(sunos_nosys)/*SELECT*/
+	.long C_LABEL(sunos_nosys)/*SETDOPT*/, C_LABEL(sunos_nosys)/*FSYNC*/
+	.long C_LABEL(sunos_nosys)/*SETPRIORITY*/, C_LABEL(sunos_nosys)/*SOCKET*/
+	.long C_LABEL(sunos_nosys)/*CONNECT*/, C_LABEL(sunos_nosys)/*OACCEPT*/
+	.long C_LABEL(sunos_nosys)/*GETPRIORITY*/, C_LABEL(sunos_nosys)/*OSEND*/
+	.long C_LABEL(sunos_nosys)/*ORECV*/, C_LABEL(sunos_nosys)/*SIGRETURN*/
+	.long C_LABEL(sunos_nosys)/*BIND*/, C_LABEL(sunos_nosys)/*SETSOCKOPT*/
+	.long C_LABEL(sunos_nosys)/*LISTEN*/, C_LABEL(sunos_nosys)/*VTIMES*/
+	.long C_LABEL(sunos_nosys)/*OSIGVEC*/, C_LABEL(sunos_nosys)/*OSIGBLOCK*/
+	.long C_LABEL(sunos_nosys)/*OSIGSETMASK*/, C_LABEL(sunos_nosys)/*SIGSUSPEND*/
+	.long C_LABEL(sunos_nosys)/*OSIGSTACK*/, C_LABEL(sunos_nosys)/*ORECVMSG*/
+	.long C_LABEL(sunos_nosys)/*OSENDMSG*/, C_LABEL(sunos_nosys)/*VTRACE*/
+	.long C_LABEL(sunos_nosys)/*GETTIMEOFDAY*/, C_LABEL(sunos_nosys)/*GETRUSAGE*/
+	.long C_LABEL(sunos_nosys)/*GETSOCKOPT*/, C_LABEL(sunos_nosys)/*ORESUBA*/
+	.long C_LABEL(sunos_nosys)/*READV*/, C_LABEL(sunos_nosys)/*WRITEV*/
+	.long C_LABEL(sunos_nosys)/*SETTIMEOFDAY*/, C_LABEL(sunos_nosys)/*FCHOWN*/
+	.long C_LABEL(sunos_nosys)/*FCHMOD*/, C_LABEL(sunos_nosys)/*ORECVFROM*/
+	.long C_LABEL(sunos_nosys)/*OSETREUID*/, C_LABEL(sunos_nosys)/*OSETREGID*/
+	.long C_LABEL(sunos_nosys)/*RENAME*/, C_LABEL(sunos_nosys)/*OTRUNCATE*/
+	.long C_LABEL(sunos_nosys)/*OFTRUNCATE*/, C_LABEL(sunos_nosys)/*FLOCK*/
+	.long C_LABEL(sunos_nosys)/*MKFIFO*/, C_LABEL(sunos_nosys)/*SENDTO*/
+	.long C_LABEL(sunos_nosys)/*SHUTDOWN*/, C_LABEL(sunos_nosys)/*SOCKETPAIR*/
+	.long C_LABEL(sunos_nosys)/*MKDIR*/, C_LABEL(sunos_nosys)/*RMDIR*/
+	.long C_LABEL(sunos_nosys)/*UTIMES*/, C_LABEL(sunos_nosys)/*OSIGRETURN*/
+	.long C_LABEL(sunos_nosys)/*ADJTIME*/, C_LABEL(sunos_nosys)/*OGETPEERNAME*/
+	.long C_LABEL(sunos_nosys)/*OGETHOSTID*/, C_LABEL(sunos_nosys)/*OSETHOSTID*/
+	.long C_LABEL(sunos_nosys)/*OGETRLIMIT*/, C_LABEL(sunos_nosys)/*OSETRLIMIT*/
+	.long C_LABEL(sunos_nosys)/*OKILLPG*/, C_LABEL(sunos_nosys)/*SETSID*/
+	.long C_LABEL(sunos_nosys)/*QUOTACTL*/, C_LABEL(sunos_nosys)/*OQUOTA*/
+	.long C_LABEL(sunos_nosys)/*OGETSOCKNAME*/, C_LABEL(sunos_nosys)/*NOTHING*/
+	.long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+	.long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NFSSVC*/
+	.long C_LABEL(sunos_nosys)/*OGETDIRENTRIES*/, C_LABEL(sunos_nosys)/*STATFS*/
+	.long C_LABEL(sunos_nosys)/*FSTATFS*/, C_LABEL(sunos_nosys)/*NOTHING*/
+	.long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*GETFH*/
+	.long C_LABEL(sunos_nosys)/*OGETDOMAINNAME*/
+	.long C_LABEL(sunos_nosys)/*OSETDOMAINNAME*/
+	.long C_LABEL(sunos_nosys)/*OUNAME*/, C_LABEL(sunos_nosys)/*SYSARCH*/
+	.long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+	.long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*OSEMSYS*/
+	.long C_LABEL(sunos_nosys)/*OMSGSYS*/, C_LABEL(sunos_nosys)/*OSHMSYS*/
+	.long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+	.long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+	.long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+	.long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+	.long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*SETGID*/
+	.long C_LABEL(sunos_nosys)/*SETEGID*/, C_LABEL(sunos_nosys)/*SETEUID*/
+	.long C_LABEL(sunos_nosys)/*LFS_BMAPV*/, C_LABEL(sunos_nosys)/*LFS_MARKV*/
+	.long C_LABEL(sunos_nosys)/*LFS_SEGCLEAN*/, C_LABEL(sunos_nosys)/*LFS_SEGWAIT*/
+	.long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+	.long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+	.long C_LABEL(sunos_nosys)/*STAT*/, C_LABEL(sunos_nosys)/*FSTAT*/
+	.long C_LABEL(sunos_nosys)/*LSTAT*/, C_LABEL(sunos_nosys)/*PATHCONF*/
+	.long C_LABEL(sunos_nosys)/*FPATHCONF*/, C_LABEL(sunos_nosys)/*NOTHING*/
+	.long C_LABEL(sunos_nosys)/*GETRLIMIT*/, C_LABEL(sunos_nosys)/*SETRLIMIT*/
+	.long C_LABEL(sunos_nosys)/*GETDIRENTRIES*/, C_LABEL(sunos_nosys)/*MMAP*/
+	.long C_LABEL(sunos_nosys)/*__SYSCALL*/, C_LABEL(sunos_nosys)/*LSEEK*/
+	.long C_LABEL(sunos_nosys)/*TRUNCATE*/, C_LABEL(sunos_nosys)/*FTRUNCATE*/
+	.long C_LABEL(sunos_nosys)/*__SYSCTL*/, C_LABEL(sunos_nosys)/*MLOCK*/
+	.long C_LABEL(sunos_nosys)/*MUNLOCK*/, C_LABEL(sunos_nosys)/*UNDELETE*/
+	.long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+	.long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+	.long C_LABEL(sunos_nosys)/*LKMNOSYS*/, C_LABEL(sunos_nosys)/*LKMNOSYS*/
+	.long C_LABEL(sunos_nosys)/*LKMNOSYS*/, C_LABEL(sunos_nosys)/*LKMNOSYS*/
+	.long C_LABEL(sunos_nosys)/*LKMNOSYS*/, C_LABEL(sunos_nosys)/*LKMNOSYS*/
+	.long C_LABEL(sunos_nosys)/*LKMNOSYS*/, C_LABEL(sunos_nosys)/*LKMNOSYS*/
+	.long C_LABEL(sunos_nosys)/*LKMNOSYS*/, C_LABEL(sunos_nosys)/*LKMNOSYS*/
+	.long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+	.long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+	.long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+	.long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+	.long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+	.long C_LABEL(sunos_nosys)/*__SEMCTL*/, C_LABEL(sunos_nosys)/*SEMGET*/
+	.long C_LABEL(sunos_nosys)/*SEMOP*/, C_LABEL(sunos_nosys)/*SEMCONFIG*/
+	.long C_LABEL(sunos_nosys)/*MSGCTL*/, C_LABEL(sunos_nosys)/*MSGGET*/
+	.long C_LABEL(sunos_nosys)/*MSGSND*/, C_LABEL(sunos_nosys)/*MSGRCV*/
+	.long C_LABEL(sunos_nosys)/*SHMAT*/, C_LABEL(sunos_nosys)/*SHMCTL*/
+	.long C_LABEL(sunos_nosys)/*SHMDT*/, C_LABEL(sunos_nosys)/*SHMGET*/
+	.long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+	.long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+	.long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+	.long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+	.long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+	.long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+	.long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+	.long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+	.long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
+	.long C_LABEL(sunos_nosys)/*MINHERIT*/, C_LABEL(sunos_nosys)/*RFORK*/
+
+	/* One thing left, Solaris syscall table, TODO */
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/kernel/time.c linux/arch/sparc/kernel/time.c
--- v1.3.70/linux/arch/sparc/kernel/time.c	Mon Nov 27 12:48:27 1995
+++ linux/arch/sparc/kernel/time.c	Mon Mar  4 08:49:56 1996
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.4 1995/11/25 03:29:31 davem Exp $
+/* $Id: time.c,v 1.7 1996/03/01 07:16:05 davem Exp $
  * linux/arch/sparc/kernel/time.c
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -17,16 +17,26 @@
 #include <asm/segment.h>
 #include <asm/timer.h>
 #include <asm/mostek.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/io.h>
 
 #define TIMER_IRQ  10    /* Also at level 14, but we ignore that one. */
 
+enum sparc_clock_type sp_clock_typ;
+struct mostek48t02 *mstk48t02_regs = 0;
+struct mostek48t08 *mstk48t08_regs = 0;
+volatile unsigned int *master_l10_limit = 0;
+volatile unsigned int *master_l10_counter = 0;
+struct sun4m_timer_regs *sun4m_timers;
+
 static int set_rtc_mmss(unsigned long);
 
 /*
  * timer_interrupt() needs to keep up the real-time clock,
  * as well as call the "do_timer()" routine every clocktick
  */
-void timer_interrupt(int irq, struct pt_regs * regs)
+void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
 	/* last time the cmos clock got updated */
 	static long last_rtc_update=0;
@@ -78,6 +88,141 @@
 	  )*60 + sec; /* finally seconds */
 }
 
+/* Clock probing, we probe the timers here also. */
+volatile unsigned int foo_limit;
+
+static void clock_probe(void)
+{
+	char node_str[128];
+	register int node, type;
+	struct linux_prom_registers clk_reg[2];
+
+	/* This will basically traverse the node-tree of the prom to see
+	 * which timer chip is on this machine.
+	 */
+
+	node = 0;
+	if(sparc_cpu_model == sun4) {
+		printk("clock_probe: No SUN4 Clock/Timer support yet...\n");
+		return;
+	}
+	if(sparc_cpu_model == sun4c) node=prom_getchild(prom_root_node);
+	else
+		if(sparc_cpu_model == sun4m)
+			node=prom_getchild(prom_searchsiblings(prom_getchild(prom_root_node), "obio"));
+	type = 0;
+	sp_clock_typ = MSTK_INVALID;
+	for(;;) {
+		prom_getstring(node, "model", node_str, sizeof(node_str));
+		if(strcmp(node_str, "mk48t02") == 0) {
+			sp_clock_typ = MSTK48T02;
+			if(prom_getproperty(node, "reg", (char *) clk_reg, sizeof(clk_reg)) == -1) {
+				printk("clock_probe: FAILED!\n");
+				halt();
+			}
+			prom_apply_obio_ranges(clk_reg, 1);
+			/* Map the clock register io area read-only */
+			mstk48t02_regs = (struct mostek48t02 *) 
+				sparc_alloc_io((void *) clk_reg[0].phys_addr,
+					       (void *) 0, sizeof(*mstk48t02_regs),
+					       "clock", clk_reg[0].which_io, 0x0);
+			mstk48t08_regs = 0;  /* To catch weirdness */
+			break;
+		}
+
+		if(strcmp(node_str, "mk48t08") == 0) {
+			sp_clock_typ = MSTK48T08;
+			if(prom_getproperty(node, "reg", (char *) clk_reg,
+					    sizeof(clk_reg)) == -1) {
+				printk("clock_probe: FAILED!\n");
+				halt();
+			}
+			prom_apply_obio_ranges(clk_reg, 1);
+			/* Map the clock register io area read-only */
+			mstk48t08_regs = (struct mostek48t08 *)
+				sparc_alloc_io((void *) clk_reg[0].phys_addr,
+					       (void *) 0, sizeof(*mstk48t08_regs),
+					       "clock", clk_reg[0].which_io, 0x0);
+
+			mstk48t02_regs = &mstk48t08_regs->regs;
+			break;
+		}
+
+		node = prom_getsibling(node);
+		if(node == 0) {
+			printk("Aieee, could not find timer chip type\n");
+			return;
+		}
+	}
+
+	if(sparc_cpu_model == sun4c) {
+		/* Map the Timer chip, this is implemented in hardware inside
+		 * the cache chip on the sun4c.
+		 */
+		sun4c_timers = sparc_alloc_io ((void *) SUN4C_TIMER_PHYSADDR, 0,
+					       sizeof(struct sun4c_timer_info),
+					       "timer", 0x0, 0x0);
+
+		/* Have the level 10 timer tick at 100HZ.  We don't touch the
+		 * level 14 timer limit since we are letting the prom handle
+		 * them until we have a real console driver so L1-A works.
+		 */
+		sun4c_timers->timer_limit10 = (((1000000/HZ) + 1) << 10);
+		master_l10_limit = &(sun4c_timers->timer_limit10);
+		master_l10_counter = &(sun4c_timers->cur_count10);
+	} else {
+		/* XXX FIx this SHIT... UP and MP sun4m configurations
+		 * XXX have completely different layouts for the counter
+		 * XXX registers. AIEEE!!!
+		 */
+
+		int reg_count;
+		struct linux_prom_registers cnt_regs[PROMREG_MAX];
+		volatile unsigned long *real_limit;
+		int obio_node, cnt_node;
+
+		cnt_node = 0;
+		if((obio_node =
+		    prom_searchsiblings (prom_getchild(prom_root_node), "obio")) == 0 ||
+		   (obio_node = prom_getchild (obio_node)) == 0 ||
+		   (cnt_node = prom_searchsiblings (obio_node, "counter")) == 0) {
+			prom_printf("Cannot find /obio/counter node\n");
+			prom_halt();
+		}
+		reg_count = prom_getproperty(cnt_node, "reg",
+					     (void *) cnt_regs, sizeof(cnt_regs));
+		reg_count = (reg_count/sizeof(struct linux_prom_registers));
+
+		/* Apply the obio ranges to the timer registers. */
+		prom_apply_obio_ranges(cnt_regs, reg_count);
+
+		/* Map the per-cpu Counter registers. */
+		sparc_alloc_io(cnt_regs[0].phys_addr, 0,
+			       PAGE_SIZE*NCPUS, "counters_percpu",
+			       cnt_regs[0].which_io, 0x0);
+
+		/* Map the system Counter register. */
+		sun4m_timers = sparc_alloc_io(cnt_regs[reg_count-1].phys_addr, 0,
+					      cnt_regs[reg_count-1].reg_size,
+					      "counters_system",
+					      cnt_regs[reg_count-1].which_io, 0x0);
+
+		real_limit = &sun4m_timers->l10_timer_limit;
+		if(reg_count < 4) {
+			/* Uniprocessor timers, ugh. */
+			real_limit = (volatile unsigned long *) sun4m_timers;
+		}
+
+		/* Avoid interrupt bombs... */
+		foo_limit = (volatile) *real_limit;
+
+		/* Must set the master pointer first or we will lose badly. */
+		master_l10_limit = real_limit;
+		master_l10_counter = real_limit + 1;
+		*master_l10_limit =  (((1000000/HZ) + 1) << 10);
+	}
+}
+
 #ifndef BCD_TO_BIN
 #define BCD_TO_BIN(val) (((val)&15) + ((val)>>4)*10)
 #endif
@@ -91,7 +236,9 @@
 	unsigned int year, mon, day, hour, min, sec;
 	struct mostek48t02 *mregs;
 
-	request_irq(TIMER_IRQ, timer_interrupt, SA_INTERRUPT, "timer");
+	clock_probe();
+	/*	request_irq(TIMER_IRQ, timer_interrupt, SA_INTERRUPT, "timer", NULL); */
+	enable_irq(TIMER_IRQ);
 	mregs = mstk48t02_regs;
 	if(!mregs) {
 		prom_printf("Something wrong, clock regs not mapped yet.\n");
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/kernel/traps.c linux/arch/sparc/kernel/traps.c
--- v1.3.70/linux/arch/sparc/kernel/traps.c	Sat Nov 25 19:04:37 1995
+++ linux/arch/sparc/kernel/traps.c	Mon Mar  4 08:49:57 1996
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.18 1995/11/25 00:58:47 davem Exp $
+/* $Id: traps.c,v 1.32 1996/03/01 07:16:08 davem Exp $
  * arch/sparc/kernel/traps.c
  *
  * Copyright 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -10,6 +10,7 @@
 
 #include <linux/sched.h>  /* for jiffies */
 #include <linux/kernel.h>
+#include <linux/signal.h>
 
 #include <asm/delay.h>
 #include <asm/system.h>
@@ -19,229 +20,183 @@
 #include <asm/pgtable.h>
 #include <asm/mp.h>
 #include <asm/kdebug.h>
+#include <asm/unistd.h>
 
-void
-syscall_trace_entry(struct pt_regs *regs)
-{
-	printk("%s[%d]: sys[%d](%d, %d, %d, %d) ",
-	       current->comm, current->pid,
-	       regs->u_regs[UREG_G1], regs->u_regs[UREG_I0],
-	       regs->u_regs[UREG_I1], regs->u_regs[UREG_I2],
-	       regs->u_regs[UREG_I3]);
-	return;
-}
+struct trap_trace_entry {
+	unsigned long pc;
+	unsigned long type;
+};
 
-void
-syscall_trace_exit(struct pt_regs *regs)
+int trap_curbuf = 0;
+struct trap_trace_entry trapbuf[1024];
+
+void syscall_trace_entry(struct pt_regs *regs)
 {
-	printk("retvals[%d,%d] at pc<%08lx>\n",
-	       regs->u_regs[UREG_I0], regs->u_regs[UREG_I1],
-	       regs->pc, regs->npc);
-	return;
+	printk("%s[%d]: ", current->comm, current->pid);
+	printk("scall<%d> (could be %d)\n", (int) regs->u_regs[UREG_G1],
+	       (int) regs->u_regs[UREG_I0]);
 }
 
-void
-do_cwp_assertion_failure(struct pt_regs *regs, unsigned long psr)
+void syscall_trace_exit(struct pt_regs *regs)
 {
-	printk("CWP return from trap assertion fails:\n");
-	printk("Current psr %08lx, new psr %08lx\n", psr, regs->psr);
-	show_regs(regs);
-	panic("bogus CWP");
 }
 
-void
-do_hw_interrupt(unsigned long type, unsigned long psr, unsigned long pc)
+void die_if_kernel(char *str, struct pt_regs *regs)
 {
+	unsigned long i;
+	unsigned long *pc;
 
-  printk("Unimplemented Sparc TRAP, type = %02lx psr = %08lx pc = %08lx\n",
-	 type, psr, pc);
-  halt();
-
-  return;
+	if(regs->psr & PSR_PS)
+		do_exit(SIGKILL);
+	printk("%s(%d): %s\n", current->comm, current->pid, str);
+	show_regs(regs);
+	printk("Instruction DUMP:");
+	pc = (unsigned long *) regs->pc;
+	for(i = -3; i < 6; i++)
+		printk("%c%08lx%c",i?' ':'<',pc[i],i?' ':'>');
+	printk("\n");
+	do_exit(SIGSEGV);
+}
+
+void do_hw_interrupt(unsigned long type, unsigned long psr, unsigned long pc)
+{
+	if(type < 0x80) {
+		/* Sun OS's puke from bad traps, Linux survives! */
+		printk("Unimplemented Sparc TRAP, type = %02lx\n", type);
+		panic("Whee... Hello Mr. Penguin");
+	}	
+	current->tss.sig_desc = SUBSIG_BADTRAP(type - 0x80);
+	current->tss.sig_address = pc;
+	send_sig(SIGILL, current, 1);
 }
 
-void
-do_illegal_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
-		       unsigned long psr)
+void do_illegal_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+			    unsigned long psr)
 {
-	printk("Illegal instruction at PC %08lx NPC %08lx PSR %08lx\n",
-	       pc, npc, psr);
 	if(psr & PSR_PS)
-		panic("Kernel illegal instruction, how are ya!");
+		die_if_kernel("Kernel illegal instruction", regs);
 	current->tss.sig_address = pc;
 	current->tss.sig_desc = SUBSIG_ILLINST;
 	send_sig(SIGILL, current, 1);
-	return;
 }
 
-void
-do_priv_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
-		       unsigned long psr)
+void do_priv_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+			 unsigned long psr)
 {
-	printk("Privileged instruction at PC %08lx NPC %08lx PSR %08lx\n",
-	       pc, npc, psr);
+	if(psr & PSR_PS)
+		die_if_kernel("Penguin instruction from Penguin mode??!?!", regs);
 	current->tss.sig_address = pc;
 	current->tss.sig_desc = SUBSIG_PRIVINST;
 	send_sig(SIGILL, current, 1);
-	return;
 }
 
 /* XXX User may want to be allowed to do this. XXX */
 
-void
-do_memaccess_unaligned(struct pt_regs *regs, unsigned long pc, unsigned long npc,
-		       unsigned long psr)
+void do_memaccess_unaligned(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+			    unsigned long psr)
 {
-	printk("Unaligned memory access at PC %08lx NPC %08lx PSR %08lx\n",
-	       pc, npc, psr);
 	if(regs->psr & PSR_PS)
-		panic("Kernel does unaligned memory access, yuck!");
+		die_if_kernel("Kernel MNA access", regs);
 	current->tss.sig_address = pc;
 	current->tss.sig_desc = SUBSIG_PRIVINST;
 	send_sig(SIGBUS, current, 1);
-	return;
 }
 
-void
-do_fpd_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
-		       unsigned long psr)
+extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
+		   void *fpqueue, unsigned long *fpqdepth);
+extern void fpload(unsigned long *fpregs, unsigned long *fsr);
+
+static unsigned long init_fsr = 0x0UL;
+static unsigned long init_fregs[32] __attribute__ ((aligned (8))) =
+                { ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL,
+		  ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL,
+		  ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL,
+		  ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL };
+
+void do_fpd_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+		 unsigned long psr)
 {
 	/* Sanity check... */
 	if(psr & PSR_PS)
-		panic("FPE disabled trap from kernel, die die die...");
+		die_if_kernel("Kernel gets Penguin-FPU disabled trap", regs);
 
 	put_psr(get_psr() | PSR_EF);    /* Allow FPU ops. */
-	if(last_task_used_math == current) {
-		/* No state save necessary */
-		regs->psr |= PSR_EF;
+	regs->psr |= PSR_EF;
+	if(last_task_used_math == current)
 		return;
-	}
 	if(last_task_used_math) {
 		/* Other processes fpu state, save away */
-		__asm__ __volatile__("st %%fsr, [%0]\n\t" : :
-				     "r" (&current->tss.fsr) : "memory");
-
-		/* Save away the floating point queue if necessary. */
-		if(current->tss.fsr & 0x2000)
-			__asm__ __volatile__("mov 0x0, %%g2\n\t"
-					     "1: std %%fq, [%2 + %%g2]\n\t"
-					     "st %%fsr, [%0]\n\t"
-					     "ld [%0], %%g3\n\t"
-					     "andcc %%g3, %1, %%g0\n\t"
-					     "bne 1b\n\t"
-					     "add %%g2, 0x8, %%g2\n\t"
-					     "srl %%g2, 0x3, %%g2\n\t"
-					     "st %%g2, [%3]\n\t" : :
-					     "r" (&current->tss.fsr), "r" (0x2000),
-					     "r" (&current->tss.fpqueue[0]),
-					     "r" (&current->tss.fpqdepth) :
-					     "g2", "g3", "memory");
-		else
-			current->tss.fpqdepth = 0;
-
-		__asm__ __volatile__("std %%f0, [%0 + 0x00]\n\t"
-				     "std %%f2, [%0 + 0x08]\n\t"
-				     "std %%f4, [%0 + 0x10]\n\t"
-				     "std %%f6, [%0 + 0x18]\n\t"
-				     "std %%f8, [%0 + 0x20]\n\t"
-				     "std %%f10, [%0 + 0x28]\n\t"
-				     "std %%f12, [%0 + 0x30]\n\t"
-				     "std %%f14, [%0 + 0x38]\n\t"
-				     "std %%f16, [%0 + 0x40]\n\t"
-				     "std %%f18, [%0 + 0x48]\n\t"
-				     "std %%f20, [%0 + 0x50]\n\t"
-				     "std %%f22, [%0 + 0x58]\n\t"
-				     "std %%f24, [%0 + 0x60]\n\t"
-				     "std %%f26, [%0 + 0x68]\n\t"
-				     "std %%f28, [%0 + 0x70]\n\t"
-				     "std %%f30, [%0 + 0x78]\n\t" : :
-				     "r" (&current->tss.float_regs[0]) :
-				     "memory");
+		struct task_struct *fptask = last_task_used_math;
+		fpsave(&fptask->tss.float_regs[0], &fptask->tss.fsr,
+		       &fptask->tss.fpqueue[0], &fptask->tss.fpqdepth);
 	}
 	last_task_used_math = current;
 	if(current->used_math) {
-		/* Restore the old state. */
-		__asm__ __volatile__("ldd [%0 + 0x00], %%f0\n\t"
-				     "ldd [%0 + 0x08], %%f2\n\t"
-				     "ldd [%0 + 0x10], %%f4\n\t"
-				     "ldd [%0 + 0x18], %%f6\n\t"
-				     "ldd [%0 + 0x20], %%f8\n\t"
-				     "ldd [%0 + 0x28], %%f10\n\t"
-				     "ldd [%0 + 0x30], %%f12\n\t"
-				     "ldd [%0 + 0x38], %%f14\n\t"
-				     "ldd [%0 + 0x40], %%f16\n\t"
-				     "ldd [%0 + 0x48], %%f18\n\t"
-				     "ldd [%0 + 0x50], %%f20\n\t"
-				     "ldd [%0 + 0x58], %%f22\n\t"
-				     "ldd [%0 + 0x60], %%f24\n\t"
-				     "ldd [%0 + 0x68], %%f26\n\t"
-				     "ldd [%0 + 0x70], %%f28\n\t"
-				     "ldd [%0 + 0x78], %%f30\n\t"
-				     "ld  [%1], %%fsr\n\t" : :
-				     "r" (&current->tss.float_regs[0]),
-				     "r" (&current->tss.fsr));
+		fpload(&current->tss.float_regs[0], &current->tss.fsr);
 	} else {
 		/* Set initial sane state. */
-		auto unsigned long init_fsr = 0x0UL;
-		auto unsigned long init_fregs[32] __attribute__ ((aligned (8))) =
-		{ ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL,
-		  ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL,
-		  ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL,
-		  ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL };
-		__asm__ __volatile__("ldd [%0 + 0x00], %%f0\n\t"
-				     "ldd [%0 + 0x08], %%f2\n\t"
-				     "ldd [%0 + 0x10], %%f4\n\t"
-				     "ldd [%0 + 0x18], %%f6\n\t"
-				     "ldd [%0 + 0x20], %%f8\n\t"
-				     "ldd [%0 + 0x28], %%f10\n\t"
-				     "ldd [%0 + 0x30], %%f12\n\t"
-				     "ldd [%0 + 0x38], %%f14\n\t"
-				     "ldd [%0 + 0x40], %%f16\n\t"
-				     "ldd [%0 + 0x48], %%f18\n\t"
-				     "ldd [%0 + 0x50], %%f20\n\t"
-				     "ldd [%0 + 0x58], %%f22\n\t"
-				     "ldd [%0 + 0x60], %%f24\n\t"
-				     "ldd [%0 + 0x68], %%f26\n\t"
-				     "ldd [%0 + 0x70], %%f28\n\t"
-				     "ldd [%0 + 0x78], %%f30\n\t"
-				     "ld  [%1], %%fsr\n\t" : :
-				     "r" (&init_fregs[0]),
-				     "r" (&init_fsr) : "memory");
+		fpload(&init_fregs[0], &init_fsr);
 		current->used_math = 1;
 	}
 }
 
-void
-do_fpe_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
-		       unsigned long psr)
-{
-	if(psr & PSR_PS)
-		panic("FPE exception trap from kernel, die die die...");
-	/* XXX Do something real... XXX */
+static unsigned long fake_regs[32] __attribute__ ((aligned (8)));
+static unsigned long fake_fsr;
+static unsigned long fake_queue[32] __attribute__ ((aligned (8)));
+static unsigned long fake_depth;
+
+void do_fpe_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+		 unsigned long psr)
+{
+	static calls = 0;
+	struct task_struct *fpt = last_task_used_math;
+
+	put_psr(get_psr() | PSR_EF);
+	/* If nobody owns the fpu right now, just clear the
+	 * error into our fake static buffer and hope it don't
+	 * happen again.  Thank you crashme...
+	 */
+	if(!fpt) {
+		fpsave(&fake_regs[0], &fake_fsr, &fake_queue[0], &fake_depth);
+		regs->psr &= ~PSR_EF;
+		return;
+	}
+	fpsave(&fpt->tss.float_regs[0], &fpt->tss.fsr,
+	       &fpt->tss.fpqueue[0], &fpt->tss.fpqdepth);
+	last_task_used_math->tss.sig_address = pc;
+	last_task_used_math->tss.sig_desc = SUBSIG_FPERROR; /* as good as any */
+	if(psr & PSR_PS) {
+		/* The first fsr store/load we tried trapped,
+		 * the second one will not (we hope).
+		 */
+		printk("WARNING: FPU exception from kernel mode. at pc=%08lx\n",
+		       regs->pc);
+		regs->pc = regs->npc;
+		regs->npc += 4;
+		calls++;
+		if(calls > 2)
+			die_if_kernel("Too many Penguin-FPU traps from kernel mode",
+				      regs);
+		return;
+	}
+	send_sig(SIGFPE, last_task_used_math, 1);
+	last_task_used_math = NULL;
 	regs->psr &= ~PSR_EF;
-	last_task_used_math = (struct task_struct *) 0;
-	current->tss.sig_address = pc;
-	current->tss.sig_desc = SUBSIG_FPERROR; /* as good as any */
-	send_sig(SIGFPE, current, 1);
-	return;
+	if(calls > 0)
+		calls=0;
 }
 
-void
-handle_tag_overflow(struct pt_regs *regs, unsigned long pc, unsigned long npc,
-		       unsigned long psr)
+void handle_tag_overflow(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+			 unsigned long psr)
 {
-	printk("Tag overflow trap at PC %08lx NPC %08lx PSR %08lx\n",
-	       pc, npc, psr);
 	if(psr & PSR_PS)
-		panic("KERNEL tag overflow trap, wowza!");
+		die_if_kernel("Penguin overflow trap from kernel mode", regs);
 	current->tss.sig_address = pc;
 	current->tss.sig_desc = SUBSIG_TAG; /* as good as any */
 	send_sig(SIGEMT, current, 1);
-	return;
 }
 
-void
-handle_watchpoint(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+void handle_watchpoint(struct pt_regs *regs, unsigned long pc, unsigned long npc,
 		       unsigned long psr)
 {
 	printk("Watchpoint detected at PC %08lx NPC %08lx PSR %08lx\n",
@@ -249,63 +204,44 @@
 	if(psr & PSR_PS)
 		panic("Tell me what a watchpoint trap is, and I'll then deal "
 		      "with such a beast...");
-	return;
 }
 
-void
-handle_reg_access(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+void handle_reg_access(struct pt_regs *regs, unsigned long pc, unsigned long npc,
 		       unsigned long psr)
 {
 	printk("Register Access Exception at PC %08lx NPC %08lx PSR %08lx\n",
 	       pc, npc, psr);
-	halt();
-	return;
+	send_sig(SIGILL, current, 1);
 }
 
-void
-handle_cp_disabled(struct pt_regs *regs, unsigned long pc, unsigned long npc,
-		       unsigned long psr)
+void handle_cp_disabled(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+			unsigned long psr)
 {
-	printk("Co-Processor disabled trap at PC %08lx NPC %08lx PSR %08lx\n",
-	       pc, npc, psr);
-	halt();
-	return;
+	send_sig(SIGILL, current, 1);
 }
 
-void
-handle_bad_flush(struct pt_regs *regs, unsigned long pc, unsigned long npc,
-		       unsigned long psr)
+void handle_bad_flush(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+		      unsigned long psr)
 {
 	printk("Unimplemented FLUSH Exception at PC %08lx NPC %08lx PSR %08lx\n",
 	       pc, npc, psr);
-	halt();
-	return;
+	send_sig(SIGILL, current, 1);
 }
 
-void
-handle_cp_exception(struct pt_regs *regs, unsigned long pc, unsigned long npc,
-		       unsigned long psr)
+void handle_cp_exception(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+			 unsigned long psr)
 {
 	printk("Co-Processor Exception at PC %08lx NPC %08lx PSR %08lx\n",
 	       pc, npc, psr);
-	halt();
-	return;
+	send_sig(SIGILL, current, 1);
 }
 
-void
-handle_hw_divzero(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+void handle_hw_divzero(struct pt_regs *regs, unsigned long pc, unsigned long npc,
 		       unsigned long psr)
 {
 	printk("Divide By Zero Exception at PC %08lx NPC %08lx PSR %08lx\n",
 	       pc, npc, psr);
-	halt();
-	return;
-}
-
-void do_ast(struct pt_regs *regs)
-{
-	panic("Don't know how to handle AST traps yet ;-(\n");
-	return;
+	send_sig(SIGILL, current, 1);
 }
 
 /* Since we have our mappings set up, on multiprocessors we can spin them
@@ -315,14 +251,13 @@
 extern void sparc_cpu_startup(void);
 
 extern int linux_num_cpus;
-extern pgd_t *lnx_root;
+extern pgd_t **srmmu_context_table;
 
 int linux_smp_still_initting;
 unsigned int thiscpus_tbr;
 int thiscpus_mid;
 
-void
-trap_init(void)
+void trap_init(void)
 {
 	struct linux_prom_registers ctx_reg;
 	int i;
@@ -341,7 +276,7 @@
 	       linux_num_cpus);
 	linux_smp_still_initting = 1;
 	ctx_reg.which_io = 0x0;  /* real ram */
-	ctx_reg.phys_addr = (char *) (((unsigned long) lnx_root) - PAGE_OFFSET);
+	ctx_reg.phys_addr = (char *) (((unsigned long) srmmu_context_table) - PAGE_OFFSET);
 	ctx_reg.reg_size = 0x0;
 	/* This basically takes every cpu, loads up our Linux context table
 	 * into it's context table pointer register, inits it at the low level
@@ -369,12 +304,4 @@
 	}
 
 	linux_smp_still_initting = 1;
-
-	return;
-}
-
-void
-die_if_kernel(char * str, struct pt_regs * regs, long err)
-{
-  return;
 }
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/kernel/windows.c linux/arch/sparc/kernel/windows.c
--- v1.3.70/linux/arch/sparc/kernel/windows.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/kernel/windows.c	Mon Mar  4 08:49:57 1996
@@ -0,0 +1,108 @@
+/* windows.c: Routines to deal with register window management
+ *            at the C-code level.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+
+/* Do save's until all user register windows are out of the cpu. */
+void flush_user_windows(void)
+{
+	if(current->tss.uwinmask)
+		flush_user_windows();
+}
+
+static inline void shift_window_buffer(int first_win, int last_win, struct thread_struct *tp)
+{
+	int i;
+
+	for(i = first_win; i < last_win; i++) {
+		tp->rwbuf_stkptrs[i] = tp->rwbuf_stkptrs[i+1];
+		memcpy(&tp->reg_window[i], &tp->reg_window[i+1], sizeof(struct reg_window));
+	}
+}
+
+/* Place as many of the user's current register windows 
+ * on the stack that we can.  Even if the %sp is unaligned
+ * we still copy the window there, the only case that we don't
+ * succeed is if the %sp points to a bum mapping altogether.
+ * setup_frame() and do_sigreturn() use this before shifting
+ * the user stack around.  Future instruction and hardware
+ * bug workaround routines will need this functionality as
+ * well.
+ */
+void synchronize_user_stack(void)
+{
+	struct thread_struct *tp = &current->tss;
+	int window;
+
+	flush_user_windows();
+
+	if(!tp->w_saved)
+		return;
+
+	/* Ok, there is some dirty work to do. */
+	for(window = tp->w_saved - 1; window >= 0; window--) {
+		unsigned long sp = tp->rwbuf_stkptrs[window];
+
+		/* See if %sp is reasonable at all. */
+		if(verify_area(VERIFY_WRITE, (char *) sp, sizeof(struct reg_window)))
+			continue;
+
+		/* Ok, let it rip. */
+		memcpy((char *) sp, &tp->reg_window[window], sizeof(struct reg_window));
+		shift_window_buffer(window, tp->w_saved - 1, tp);
+		tp->w_saved--;
+	}
+}
+
+/* An optimization. */
+static inline void copy_aligned_window(void *dest, const void *src)
+{
+	__asm__ __volatile__("ldd [%1], %%g2\n\t"
+			     "ldd [%1 + 0x8], %%g4\n\t"
+			     "std %%g2, [%0]\n\t"
+			     "std %%g4, [%0 + 0x8]\n\t"
+			     "ldd [%1 + 0x10], %%g2\n\t"
+			     "ldd [%1 + 0x18], %%g4\n\t"
+			     "std %%g2, [%0 + 0x10]\n\t"
+			     "std %%g4, [%0 + 0x18]\n\t"
+			     "ldd [%1 + 0x20], %%g2\n\t"
+			     "ldd [%1 + 0x28], %%g4\n\t"
+			     "std %%g2, [%0 + 0x20]\n\t"
+			     "std %%g4, [%0 + 0x28]\n\t"
+			     "ldd [%1 + 0x30], %%g2\n\t"
+			     "ldd [%1 + 0x38], %%g4\n\t"
+			     "std %%g2, [%0 + 0x30]\n\t"
+			     "std %%g4, [%0 + 0x38]\n\t" : :
+			     "r" (dest), "r" (src) :
+			     "g2", "g3", "g4", "g5");
+}
+
+/* Try to push the windows in a threads window buffer to the
+ * user stack.  Unaligned %sp's are not allowed here.
+ */
+
+#define stack_is_bad(sp, rw) \
+  (((sp) & 7) || verify_area(rw, (char *) (sp), sizeof(struct reg_window)))
+
+void try_to_clear_window_buffer(struct pt_regs *regs, int who)
+{
+	struct thread_struct *tp = &current->tss;
+	int window;
+
+	flush_user_windows();
+	for(window = 0; window < tp->w_saved; window++) {
+		unsigned long sp = tp->rwbuf_stkptrs[window];
+
+		if(stack_is_bad(sp, VERIFY_WRITE))
+			do_exit(SIGILL);
+		else
+			copy_aligned_window((char *) sp, &tp->reg_window[window]);
+	}
+	tp->w_saved = 0;
+}
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/kernel/wof.S linux/arch/sparc/kernel/wof.S
--- v1.3.70/linux/arch/sparc/kernel/wof.S	Sat Nov 25 19:04:37 1995
+++ linux/arch/sparc/kernel/wof.S	Mon Mar  4 08:49:57 1996
@@ -1,4 +1,4 @@
-/* $Id: wof.S,v 1.14 1995/11/25 00:58:49 davem Exp $
+/* $Id: wof.S,v 1.20 1996/02/20 07:45:18 davem Exp $
  * wof.S: Sparc window overflow handler.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -87,14 +87,14 @@
 	 * up for us to see if this is from user or kernel.
 	 * Get the load of 'curptr' out of the way.
 	 */
-	LOAD_CURRENT(curptr)
+	LOAD_CURRENT(curptr, twin_tmp)
 
 	andcc	%t_psr, PSR_PS, %g0
 	be	spwin_fromuser				! all user wins, branch
 	 nop
 	
 	/* See if any user windows are active in the set. */
-	ld	[%curptr + THREAD_UMASK], %twin_tmp	! grab currents win mask
+	ld	[%curptr + THREAD_UMASK], %twin_tmp	! grab win mask
 	orcc	%g0, %twin_tmp, %g0			! check for set bits
 	bne	spwin_exist_uwins			! yep, there are some
 	 nop
@@ -237,22 +237,25 @@
 		st	%twin_tmp, [%curptr + THREAD_UMASK]
 
 	/* Jump onto kernel stack for this process... */
-	ld	[%curptr + TASK_KSTACK_PG], %sp
-	add	%sp, (PAGE_SIZE - TRACEREG_SZ - STACKFRAME_SZ), %sp
+	ld	[%curptr + TASK_SAVED_KSTACK], %sp
 
 	/* Restore the saved globals and build a pt_regs frame. */
 	mov	%saved_g5, %g5
 	mov	%saved_g6, %g6
-	rd	%wim, %twin_tmp
-	STORE_PT_ALL(sp, t_psr, t_pc, t_npc, twin_tmp, g1)
+	STORE_PT_ALL(sp, t_psr, t_pc, t_npc, g1)
 
 	/* Turn on traps and call c-code to deal with it. */
 	wr	%t_psr, PSR_ET, %psr
 	WRITE_PAUSE
 
-	mov	1, %o1
-	call	C_LABEL(do_sparc_winfault)
-	 add	%sp, STACKFRAME_SZ, %o0
+#if 0
+	mov	0, %o1
+	call	C_LABEL(try_to_clear_window_buffer)
+	 add	%sp, REGWIN_SZ, %o0
+#else
+	call	C_LABEL(window_overflow_fault)
+	 nop
+#endif
 
 	/* Return from trap if C-code actually fixes things, if it
 	 * doesn't then we never get this far as the process will
@@ -388,7 +391,7 @@
 	 */
 	/* Check results of callers andcc %sp, 0x7, %g0 */
 	bne	spwin_user_stack_is_bolixed
-	sethi	%hi(KERNBASE), %glob_tmp
+	 sethi	%hi(KERNBASE), %glob_tmp
 	cmp	%glob_tmp, %sp
 	bleu	spwin_user_stack_is_bolixed
 	 mov	AC_M_SFSR, %glob_tmp
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/kernel/wuf.S linux/arch/sparc/kernel/wuf.S
--- v1.3.70/linux/arch/sparc/kernel/wuf.S	Sat Nov 25 19:04:37 1995
+++ linux/arch/sparc/kernel/wuf.S	Mon Mar  4 08:49:57 1996
@@ -1,4 +1,4 @@
-/* $Id: wuf.S,v 1.13 1995/11/25 00:58:51 davem Exp $
+/* $Id: wuf.S,v 1.20 1996/02/20 07:45:22 davem Exp $
  * wuf.S: Window underflow trap handler for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller
@@ -19,7 +19,7 @@
 #define t_pc        l1
 #define t_npc       l2
 #define t_wim       l3
-/* Don`t touch the above registers or else you die horribly... */
+/* Don't touch the above registers or else you die horribly... */
 
 /* Now macros for the available scratch registers in this routine. */
 #define twin_tmp1    l4
@@ -141,15 +141,14 @@
 	/* Place a pt_regs frame on the kernel stack, save back
 	 * to the trap window and call c-code to deal with this.
 	 */
-	LOAD_CURRENT(l4)
-	ld	[%l4 + TASK_KSTACK_PG], %l5
-	add	%l5, (PAGE_SIZE - TRACEREG_SZ - STACKFRAME_SZ), %l5
+	LOAD_CURRENT(l4, l5)
+	ld	[%l4 + TASK_SAVED_KSTACK], %l5
 
 	/* Store globals into pt_regs frame. */
 	STORE_PT_GLOBALS(l5)
 	STORE_PT_YREG(l5, g3)
 
-	/* Save kernel %sp in global while we change windows */
+	/* Save kernel %sp in global while we change windows. */
 	mov	%l5, %g2
 
 	save	%g0, %g0, %g0
@@ -157,6 +156,7 @@
 	/* LOCATION: Window 'O' */
 
 	rd	%psr, %g3		/* Read %psr in live user window */
+	mov	%fp, %g6		/* Save bogus frame pointer. */
 
 	save	%g0, %g0, %g0
 
@@ -166,7 +166,7 @@
 
 	/* Build rest of pt_regs. */
 	STORE_PT_INS(sp)
-	STORE_PT_PRIV(sp, t_psr, t_pc, t_npc, t_wim)
+	STORE_PT_PRIV(sp, t_psr, t_pc, t_npc)
 
 	/* re-set trap time %wim value */
 	wr	%t_wim, 0x0, %wim
@@ -174,22 +174,16 @@
 	/* Fix users window mask and buffer save count. */
 	mov	0x1, %g5
 	sll	%g5, %g3, %g5
-	LOAD_CURRENT(twin_tmp1)
+	LOAD_CURRENT(twin_tmp1, g1)
 	st	%g5, [%twin_tmp1 + THREAD_UMASK]	! one live user window still
 	st	%g0, [%twin_tmp1 + THREAD_W_SAVED]	! no windows in the buffer
 
-	wr	%t_psr, 0x0, %psr
 	wr	%t_psr, PSR_ET, %psr			! enable traps
 	WRITE_PAUSE
 
-	mov	2, %o1
-	call	C_LABEL(do_sparc_winfault)		! call c-code
-	 add	%sp, STACKFRAME_SZ, %o0			! pt_regs ptr is arg0
-
-	/* Return from trap if C-code actually fixes things, if it
-	 * doesn't then we never get this far as the process will
-	 * be given the look of death from Commander Peanut.
-	 */
+	call	C_LABEL(window_underflow_fault)
+	 mov	%g6, %o0
+
 	b	ret_trap_entry
 	 nop
 
@@ -347,5 +341,11 @@
 	be	fwin_user_finish_up
 	 nop
 
+	/* Did I ever tell you about my window labotomy?
+	 * anyways... fwin_user_stack_is_bolixed expects
+	 * to be in window 'W' so make it happy or else
+	 * we watchdog badly.
+	 */
+	restore	%g0, %g0, %g0
 	b	fwin_user_stack_is_bolixed	! oh well
-	 nop
+	 restore	%g0, %g0, %g0
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/lib/Makefile linux/arch/sparc/lib/Makefile
--- v1.3.70/linux/arch/sparc/lib/Makefile	Sat Nov 25 19:04:37 1995
+++ linux/arch/sparc/lib/Makefile	Mon Mar  4 08:49:57 1996
@@ -1,14 +1,17 @@
-# $Id: Makefile,v 1.5 1995/11/25 00:58:56 davem Exp $
+# $Id: Makefile,v 1.7 1995/12/10 06:25:02 davem Exp $
 # Makefile for Sparc library files..
 #
 
 CFLAGS := $(CFLAGS) -ansi
 
-OBJS  = mul.o rem.o sdiv.o udiv.o umul.o urem.o ashrdi3.o
+OBJS  = mul.o rem.o sdiv.o udiv.o umul.o urem.o ashrdi3.o memcpy.o
 
 lib.a: $(OBJS)
 	$(AR) rcs lib.a $(OBJS)
 	sync
+
+memcpy.o: memcpy.S
+	$(CC) -ansi -c -o memcpy.o memcpy.S
 
 mul.o: mul.S
 	$(CC) -c -o mul.o mul.S
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/lib/memcpy.S linux/arch/sparc/lib/memcpy.S
--- v1.3.70/linux/arch/sparc/lib/memcpy.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/lib/memcpy.S	Mon Mar  4 08:49:57 1996
@@ -0,0 +1,520 @@
+! Fast memmove/memcpy/bcopy
+! Copyright Australian National University, 1995
+! This file may be used under the terms of the GNU Public License
+! Author: Paul Mackerras, September 95
+! Minor beautifications David S. Miller
+
+#include <asm/cprefix.h>
+
+	.globl	C_LABEL(bcopy)
+C_LABEL(bcopy):
+	mov	%o0,%o3
+	mov	%o1,%o0
+	mov	%o3,%o1
+
+	.globl	C_LABEL(amemmove)
+C_LABEL(amemmove):
+	.globl	C_LABEL(memmove)
+	.globl	C_LABEL(memcpy)
+C_LABEL(memmove):
+C_LABEL(memcpy):
+	save	%sp,-96,%sp
+	mov	%i0,%l7
+
+	cmp	%i0,%i1		! check for dest within source area
+	bleu,a	1f
+	andcc	%i0,3,%l1
+	add	%i1,%i2,%l0
+	cmp	%i0,%l0
+	blu,a	Lback
+	mov	%l0,%i1
+
+	! copying forwards
+	! first get dest to be word-aligned
+	andcc	%i0,3,%l1
+1:
+	be,a	Lwalign		! if dest already word-aligned
+	cmp	%i2,4
+	mov	4,%l2
+	sub	%l2,%l1,%l2	! #bytes until word-aligned
+	subcc	%i2,%l2,%i2
+	ble,a	Lend		! not copying enough to get past word bdry
+	addcc	%i2,%l2,%i2
+
+1:
+	ldub	[%i1],%o0	! copy single bytes until word-aligned
+	add	%i1,1,%i1
+	subcc	%l2,1,%l2
+	stb	%o0,[%i0]
+	bgt	1b
+	add	%i0,1,%i0
+	cmp	%i2,4
+
+Lwalign:			! dest now word aligned
+	blt,a	Lend
+	orcc	%i2,%g0,%g0
+
+	andcc	%i1,3,%l0
+	be,a	Ldoword		! if dest word aligned wrt src
+	andcc	%i0,4,%g0
+
+	! yucky cases where we have to shift
+
+	mov	4,%l2
+	sub	%l2,%l0,%l2	! address adjustment, used at Lendn
+	sll	%l0,3,%l0	! bit offset = shift left count
+	sll	%l2,3,%l1	! shift right count
+	add	%i1,%l2,%i1	! round up to next word
+	ld	[%i1-4],%o0	! get first word
+
+	andcc	%i0,4,%g0	! get destination double-word aligned
+	be,a	1f
+	andcc	%i1,4,%g0
+	ld	[%i1],%o1	! by constructing and storing one word
+	add	%i0,4,%i0
+	add	%i1,4,%i1
+	sub	%i2,4,%i2
+	sll	%o0,%l0,%o0
+	srl	%o1,%l1,%l6
+	or	%o0,%l6,%o0
+	st	%o0,[%i0-4]
+	mov	%o1,%o0
+
+	andcc	%i1,4,%g0	! now construct & store pairs of double-words
+1:
+	bne,a	3f		! if source now not double-word aligned
+	subcc	%i2,4,%i2
+	subcc	%i2,16,%i2
+	blt	2f
+	mov	%o0,%o1
+4:
+	ldd	[%i1],%o2
+	sll	%o1,%l0,%o4
+	ldd	[%i1+8],%o0
+	add	%i0,16,%i0
+	add	%i1,16,%i1
+	subcc	%i2,16,%i2
+	srl	%o2,%l1,%l6
+	or	%l6,%o4,%o4
+	sll	%o2,%l0,%o5
+	srl	%o3,%l1,%l6
+	or	%l6,%o5,%o5
+	std	%o4,[%i0-16]
+	sll	%o3,%l0,%o4
+	srl	%o0,%l1,%l6
+	or	%l6,%o4,%o4
+	sll	%o0,%l0,%o5
+	srl	%o1,%l1,%l6
+	or	%l6,%o5,%o5
+	bge	4b
+	std	%o4,[%i0-8]
+2:
+	addcc	%i2,12,%i2
+	blt,a	Lendn
+	addcc	%i2,4,%i2
+5:
+	ld	[%i1],%o2
+	add	%i0,4,%i0
+	add	%i1,4,%i1
+	subcc	%i2,4,%i2
+	sll	%o1,%l0,%o0
+	srl	%o2,%l1,%o1
+	or	%o1,%o0,%o0
+	st	%o0,[%i0-4]
+	bge	5b
+	mov	%o2,%o1
+	ba	Lendn
+	addcc	%i2,4,%i2
+
+3:
+	blt,a	Lendn
+	addcc	%i2,4,%i2
+	ld	[%i1],%o1
+	add	%i1,4,%i1
+	subcc	%i2,16,%i2
+	blt,a	8f
+	addcc	%i2,16,%i2
+7:
+	ldd	[%i1],%o2
+	sll	%o0,%l0,%o4
+	srl	%o1,%l1,%l6
+	or	%l6,%o4,%o4
+	sll	%o1,%l0,%o5
+	ldd	[%i1+8],%o0
+	add	%i0,16,%i0
+	add	%i1,16,%i1
+	subcc	%i2,16,%i2
+	srl	%o2,%l1,%l6
+	or	%l6,%o5,%o5
+	std	%o4,[%i0-16]
+	sll	%o2,%l0,%o4
+	srl	%o3,%l1,%l6
+	or	%l6,%o4,%o4
+	sll	%o3,%l0,%o5
+	srl	%o0,%l1,%l6
+	or	%l6,%o5,%o5
+	bge	7b
+	std	%o4,[%i0-8]
+	addcc	%i2,16,%i2
+8:
+	sll	%o0,%l0,%o4
+	srl	%o1,%l1,%l6
+	or	%l6,%o4,%o4
+	st	%o4,[%i0]
+	add	%i0,4,%i0
+	subcc	%i2,4,%i2
+	blt,a	Lendn
+	addcc	%i2,4,%i2
+	mov	%o1,%o0
+	ld	[%i1],%o1
+	ba	8b
+	add	%i1,4,%i1
+
+
+Ldoword:
+	! here both dest and src are word-aligned
+	! make dest double-word aligned
+	be,a	1f
+	andcc	%i1,4,%g0
+	ld	[%i1],%o0
+	add	%i0,4,%i0
+	add	%i1,4,%i1
+	sub	%i2,4,%i2
+	st	%o0,[%i0-4]
+	cmp	%i2,4
+	blt,a	Lend
+	orcc	%i2,%g0,%g0
+	andcc	%i1,4,%g0
+
+1:
+	be,a	Ldodble		! if source double-word aligned now
+	subcc	%i2,32,%i2
+	ld	[%i1],%o5
+	add	%i1,4,%i1
+	subcc	%i2,36,%i2
+	blt,a	3f
+	add	%i2,32,%i2
+2:
+	ldd	[%i1],%o2
+	add	%i1,32,%i1
+	subcc	%i2,32,%i2
+	mov	%o5,%o0
+	ldd	[%i1-24],%o4
+	mov	%o2,%o1
+	std	%o0,[%i0]
+	mov	%o3,%o2
+	ldd	[%i1-16],%o0
+	mov	%o4,%o3
+	std	%o2,[%i0+8]
+	mov	%o5,%o2
+	ldd	[%i1-8],%o4
+	mov	%o0,%o3
+	std	%o2,[%i0+16]
+	mov	%o1,%o0
+	mov	%o4,%o1
+	std	%o0,[%i0+24]
+	bge	2b
+	add	%i0,32,%i0
+	add	%i2,32,%i2
+3:
+	st	%o5,[%i0]
+	add	%i0,4,%i0
+	subcc	%i2,4,%i2
+	blt,a	Lend
+	addcc	%i2,4,%i2
+	ld	[%i1],%o5
+	ba	3b
+	add	%i1,4,%i1
+
+Ldodble:
+	! dest and source are both double-word aligned
+	blt,a	2f
+	addcc	%i2,28,%i2
+1:
+	ldd	[%i1],%o0	! copy sets of 4 double-words
+	subcc	%i2,32,%i2
+	ldd	[%i1+8],%o2
+	add	%i1,32,%i1
+	ldd	[%i1-16],%o4
+	add	%i0,32,%i0
+	std	%o0,[%i0-32]
+	ldd	[%i1-8],%o0
+	std	%o2,[%i0-24]
+	std	%o4,[%i0-16]
+	bge	1b
+	std	%o0,[%i0-8]
+	addcc	%i2,28,%i2
+2:
+	blt,a	Lend
+	addcc	%i2,4,%i2
+3:
+	ld	[%i1],%o0	! copy words
+	add	%i1,4,%i1
+	add	%i0,4,%i0
+	subcc	%i2,4,%i2
+	bge	3b
+	st	%o0,[%i0-4]
+	ba	Lend
+	addcc	%i2,4,%i2
+
+Lendn:
+	sub	%i1,%l2,%i1
+Lend:
+	ble	Lout
+	nop
+1:
+	ldub	[%i1],%o0
+	add	%i1,1,%i1
+	subcc	%i2,1,%i2
+	stb	%o0,[%i0]
+	bgt	1b
+	add	%i0,1,%i0
+
+	ba	Lout
+	nop
+
+Lback:	! Here we have to copy backwards
+	add	%i0,%i2,%i0
+	! first get dest to be word-aligned
+	andcc	%i0,3,%l2	! #bytes until word-aligned
+	be,a	Lbwal		! if dest already word-aligned
+	cmp	%i2,4
+	subcc	%i2,%l2,%i2
+	ble,a	Lbend		! not copying enough to get past word bdry
+	addcc	%i2,%l2,%i2
+
+1:
+	ldub	[%i1-1],%o0	! copy single bytes until word-aligned
+	sub	%i1,1,%i1
+	subcc	%l2,1,%l2
+	stb	%o0,[%i0-1]
+	bgt	1b
+	sub	%i0,1,%i0
+	cmp	%i2,4
+
+Lbwal:				! dest now word aligned
+	blt,a	Lbend
+	orcc	%i2,%g0,%g0
+
+	andcc	%i1,3,%l2
+	be,a	Lbword		! if dest word aligned wrt src
+	andcc	%i0,4,%g0
+
+	! yucky cases where we have to shift
+	! note %l2 used below at Lbendn
+
+	mov	4,%l0
+	sub	%l0,%l2,%l0	! # bytes to right of src in word
+	sll	%l0,3,%l0	! bit offset = shift right count
+	sll	%l2,3,%l1	! shift left count
+	sub	%i1,%l2,%i1	! round down to word boundary
+	ld	[%i1],%o1	! get first word
+
+	andcc	%i0,4,%g0	! get destination double-word aligned
+	be,a	1f
+	andcc	%i1,4,%g0
+	ld	[%i1-4],%o0	! by constructing and storing one word
+	sub	%i0,4,%i0
+	sub	%i1,4,%i1
+	sub	%i2,4,%i2
+	srl	%o1,%l0,%o1
+	sll	%o0,%l1,%l6
+	or	%o1,%l6,%o1
+	st	%o1,[%i0]
+	mov	%o0,%o1
+
+	andcc	%i1,4,%g0	! now construct & store pairs of double-words
+1:
+	bne,a	3f		! if source now not double-word aligned
+	subcc	%i2,4,%i2
+	subcc	%i2,16,%i2
+	blt	2f
+	mov	%o1,%o0
+4:
+	ldd	[%i1-8],%o2
+	srl	%o0,%l0,%o5
+	ldd	[%i1-16],%o0
+	sub	%i0,16,%i0
+	sub	%i1,16,%i1
+	subcc	%i2,16,%i2
+	sll	%o3,%l1,%l6
+	or	%l6,%o5,%o5
+	srl	%o3,%l0,%o4
+	sll	%o2,%l1,%l6
+	or	%l6,%o4,%o4
+	std	%o4,[%i0+8]
+	srl	%o2,%l0,%o5
+	sll	%o1,%l1,%l6
+	or	%l6,%o5,%o5
+	srl	%o1,%l0,%o4
+	sll	%o0,%l1,%l6
+	or	%l6,%o4,%o4
+	bge	4b
+	std	%o4,[%i0]
+2:
+	addcc	%i2,12,%i2
+	blt,a	Lbendn
+	addcc	%i2,4,%i2
+5:
+	ld	[%i1-4],%o2
+	sub	%i0,4,%i0
+	sub	%i1,4,%i1
+	subcc	%i2,4,%i2
+	srl	%o0,%l0,%o0
+	sll	%o2,%l1,%o1
+	or	%o1,%o0,%o0
+	st	%o0,[%i0]
+	bge	5b
+	mov	%o2,%o0
+	ba	Lbendn
+	addcc	%i2,4,%i2
+
+3:
+	blt,a	Lbendn
+	addcc	%i2,4,%i2
+	ld	[%i1-4],%o0
+	sub	%i1,4,%i1
+	subcc	%i2,16,%i2
+	blt,a	8f
+	addcc	%i2,16,%i2
+7:
+	ldd	[%i1-8],%o2
+	srl	%o1,%l0,%o5
+	sll	%o0,%l1,%l6
+	or	%l6,%o5,%o5
+	srl	%o0,%l0,%o4
+	ldd	[%i1-16],%o0
+	sub	%i0,16,%i0
+	sub	%i1,16,%i1
+	subcc	%i2,16,%i2
+	sll	%o3,%l1,%l6
+	or	%l6,%o4,%o4
+	std	%o4,[%i0+8]
+	srl	%o3,%l0,%o5
+	sll	%o2,%l1,%l6
+	or	%l6,%o5,%o5
+	srl	%o2,%l0,%o4
+	sll	%o1,%l1,%l6
+	or	%l6,%o4,%o4
+	bge	7b
+	std	%o4,[%i0]
+	addcc	%i2,16,%i2
+8:
+	srl	%o1,%l0,%o5
+	sll	%o0,%l1,%l6
+	or	%l6,%o5,%o5
+	st	%o5,[%i0-4]
+	sub	%i0,4,%i0
+	subcc	%i2,4,%i2
+	blt,a	Lbendn
+	addcc	%i2,4,%i2
+	mov	%o0,%o1
+	ld	[%i1-4],%o0
+	ba	8b
+	sub	%i1,4,%i1
+
+
+Lbword:
+	! here both dest and src are word-aligned
+	! make dest double-word aligned
+	be,a	1f
+	andcc	%i1,4,%g0
+	ld	[%i1-4],%o0
+	sub	%i0,4,%i0
+	sub	%i1,4,%i1
+	sub	%i2,4,%i2
+	st	%o0,[%i0]
+	cmp	%i2,4
+	blt,a	Lbend
+	orcc	%i2,%g0,%g0
+	andcc	%i1,4,%g0
+
+1:
+	be,a	Lbdble		! if source double-word aligned now
+	subcc	%i2,32,%i2
+	ld	[%i1-4],%o4
+	sub	%i1,4,%i1
+	subcc	%i2,36,%i2
+	blt,a	3f
+	add	%i2,32,%i2
+2:
+	ldd	[%i1-8],%o2
+	sub	%i1,32,%i1
+	subcc	%i2,32,%i2
+	mov	%o4,%o1
+	ldd	[%i1+16],%o4
+	mov	%o3,%o0
+	std	%o0,[%i0-8]
+	mov	%o2,%o3
+	ldd	[%i1+8],%o0
+	mov	%o5,%o2
+	std	%o2,[%i0-16]
+	mov	%o4,%o3
+	ldd	[%i1],%o4
+	mov	%o1,%o2
+	std	%o2,[%i0-24]
+	mov	%o0,%o1
+	mov	%o5,%o0
+	std	%o0,[%i0-32]
+	bge	2b
+	sub	%i0,32,%i0
+	add	%i2,32,%i2
+3:
+	st	%o4,[%i0-4]
+	sub	%i0,4,%i0
+	subcc	%i2,4,%i2
+	blt,a	Lbend
+	addcc	%i2,4,%i2
+	ld	[%i1-4],%o4
+	ba	3b
+	sub	%i1,4,%i1
+
+Lbdble:
+	! dest and source are both double-word aligned
+	blt,a	2f
+	addcc	%i2,28,%i2
+1:
+	ldd	[%i1-8],%o0	! copy sets of 4 double-words
+	subcc	%i2,32,%i2
+	ldd	[%i1-16],%o2
+	sub	%i1,32,%i1
+	ldd	[%i1+8],%o4
+	sub	%i0,32,%i0
+	std	%o0,[%i0+24]
+	ldd	[%i1],%o0
+	std	%o2,[%i0+16]
+	std	%o4,[%i0+8]
+	bge	1b
+	std	%o0,[%i0]
+	addcc	%i2,28,%i2
+2:
+	blt,a	Lbend
+	addcc	%i2,4,%i2
+3:
+	ld	[%i1-4],%o0	! copy words
+	sub	%i1,4,%i1
+	sub	%i0,4,%i0
+	subcc	%i2,4,%i2
+	bge	3b
+	st	%o0,[%i0]
+	ba	Lbend
+	addcc	%i2,4,%i2
+
+Lbendn:
+	add	%i1,%l2,%i1
+Lbend:
+	ble	Lout
+	nop
+1:
+	ldub	[%i1-1],%o0
+	sub	%i1,1,%i1
+	subcc	%i2,1,%i2
+	stb	%o0,[%i0-1]
+	bgt	1b
+	sub	%i0,1,%i0
+
+Lout:
+	ret
+	restore	%l7,0,%o0
+
+
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/mm/Makefile linux/arch/sparc/mm/Makefile
--- v1.3.70/linux/arch/sparc/mm/Makefile	Sat Nov 25 19:04:38 1995
+++ linux/arch/sparc/mm/Makefile	Mon Mar  4 08:49:57 1996
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.14 1995/11/25 00:59:17 davem Exp $
+# $Id: Makefile,v 1.17 1996/01/03 03:35:15 davem Exp $
 # Makefile for the linux Sparc-specific parts of the memory manager.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
@@ -7,21 +7,7 @@
 #
 # Note 2! The CFLAGS definition is now in the main makefile...
 
-# Also note that s4ctlb.o _must_ be the last object file
-
-#.S.s:
-#	$(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s
-.S.o:
-	$(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o
-
-all: mm.o
 O_TARGET := mm.o
-O_OBJS   := fault.o sun4c_vac.o init.o sun4c.o srmmu.o loadmmu.o mbus.o \
-            s4cflush.o
-
-#s4cflush.o: s4cflush.s
-
-s4cflush.o: s4cflush.S
-	$(CC) -D__ASSEMBLY__ -ansi -c $*.S -o $*.o
+O_OBJS   := fault.o init.o sun4c.o srmmu.o loadmmu.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/mm/fault.c linux/arch/sparc/mm/fault.c
--- v1.3.70/linux/arch/sparc/mm/fault.c	Sat Nov 25 19:04:38 1995
+++ linux/arch/sparc/mm/fault.c	Mon Mar  4 08:49:57 1996
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.42 1995/11/25 00:59:20 davem Exp $
+/* $Id: fault.c,v 1.53 1996/03/01 07:16:17 davem Exp $
  * fault.c:  Page fault handlers for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -28,14 +28,10 @@
 extern struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS];
 extern int prom_node_root;
 
-extern void die_if_kernel(char *,struct pt_regs *,long);
+extern void die_if_kernel(char *,struct pt_regs *);
 
 struct linux_romvec *romvec;
 
-/* foo */
-
-int tbase_needs_unmapping;
-
 /* At boot time we determine these two values necessary for setting
  * up the segment maps and page table entries (pte's).
  */
@@ -49,13 +45,6 @@
 int vac_entries_per_context, vac_entries_per_segment;
 int vac_entries_per_page;
 
-/*
- * Define this if things work differently on a i386 and a i486:
- * it will (on a i486) warn about kernel memory accesses that are
- * done without a 'verify_area(VERIFY_WRITE,..)'
- */
-#undef CONFIG_TEST_VERIFY_AREA
-
 /* Nice, simple, prom library does all the sweating for us. ;) */
 int prom_probe_memory (void)
 {
@@ -109,11 +98,14 @@
 	return total;
 }
 
+extern void sun4c_complete_all_stores(void);
+
 /* Whee, a level 15 NMI interrupt memory error.  Let's have fun... */
 asmlinkage void sparc_lvl15_nmi(struct pt_regs *regs, unsigned long serr,
 				unsigned long svaddr, unsigned long aerr,
 				unsigned long avaddr)
 {
+	sun4c_complete_all_stores();
 	printk("FAULT: NMI received\n");
 	printk("SREGS: Synchronous Error %08lx\n", serr);
 	printk("       Synchronous Vaddr %08lx\n", svaddr);
@@ -124,33 +116,22 @@
 	prom_halt();
 }
 
-/* Whee, looks like an i386 to me ;-) */
-asmlinkage void do_sparc_fault(struct pt_regs *regs, unsigned long tbr)
+asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,
+			       unsigned long address)
 {
 	struct vm_area_struct *vma;
-	unsigned long address, error_code, trap_type;
-	unsigned long from_user;
+	int from_user = !(regs->psr & PSR_PS);
 
-	from_user = (((regs->psr & PSR_PS) >> 4) ^ FAULT_CODE_USER);
-	if(get_fault_info(&address, &error_code, from_user))
-		goto bad_area;
-	trap_type = ((tbr>>4)&0xff);
-	if(trap_type == SP_TRAP_TFLT) {
-		/* We play it 'safe'... */
+	if(text_fault)
 		address = regs->pc;
-		error_code = (from_user); /* no page, read */
-	} else if(trap_type != SP_TRAP_DFLT)
-		panic("Bad sparc trap, trap_type not data or text fault...");
 
 	/* Now actually handle the fault.  Do kernel faults special,
 	 * because on the sun4c we could have faulted trying to read
 	 * the vma area of the task and without the following code
 	 * we'd fault recursively until all our stack is gone. ;-(
-	 *
-	 * XXX I think there are races with this maneuver. XXX
 	 */
 	if(!from_user && address >= KERNBASE) {
-		update_mmu_cache(0, address, __pte(0));
+		quick_kernel_fault(address);
 		return;
 	}
 
@@ -168,7 +149,7 @@
 	 * we can handle it..
 	 */
 good_area:
-	if(error_code & FAULT_CODE_WRITE) {
+	if(write) {
 		if(!(vma->vm_flags & VM_WRITE))
 			goto bad_area;
 	} else {
@@ -176,14 +157,14 @@
 		if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
 			goto bad_area;
 	}
-	handle_mm_fault(vma, address, error_code & FAULT_CODE_WRITE);
+	handle_mm_fault(vma, address, write);
 	return;
 	/*
 	 * Something tried to access memory that isn't in our memory map..
 	 * Fix it, but check if it's kernel or user first..
 	 */
 bad_area:
-	if(error_code & FAULT_CODE_USER) {
+	if(from_user) {
 		current->tss.sig_address = address;
 		current->tss.sig_desc = SUBSIG_NOMAPPING;
 		send_sig(SIGSEGV, current, 1);
@@ -204,100 +185,64 @@
 	} else
 		printk(KERN_ALERT "Unable to handle kernel paging request");
 	printk(" at virtual address %08lx\n",address);
-	printk("At PC %08lx nPC %08lx\n", (unsigned long) regs->pc,
-	       (unsigned long) regs->npc);
-	printk(KERN_ALERT "current->tss.pgd_ptr = %08lx\n",
-	       (unsigned long) current->tss.pgd_ptr);
-	show_regs(regs);
-	panic("KERNAL FAULT");
+	printk(KERN_ALERT "current->mm->context = %08lx\n",
+	       (unsigned long) current->mm->context);
+	printk(KERN_ALERT "current->mm->pgd = %08lx\n",
+	       (unsigned long) current->mm->pgd);
+	die_if_kernel("Oops", regs);
 }
 
-/* When the user does not have a mapped stack and we either
- * need to read the users register window from that stack or
- * we need to save a window to that stack, control flow
- * ends up here to investigate the situation.  This is a
- * very odd situation where a 'user fault' happens from
- * kernel space.
- */
+/* This always deals with user addresses. */
+inline void force_user_fault(unsigned long address, int write)
+{
+	struct vm_area_struct *vma;
 
-/* #define DEBUG_WINFAULT */
-extern void show_regwindow(struct reg_window *);
-asmlinkage void do_sparc_winfault(struct pt_regs *regs, int push)
+	vma = find_vma(current, address);
+	if(!vma)
+		goto bad_area;
+	if(vma->vm_start <= address)
+		goto good_area;
+	if(!(vma->vm_flags & VM_GROWSDOWN))
+		goto bad_area;
+	if(expand_stack(vma, address))
+		goto bad_area;
+good_area:
+	if(write)
+		if(!(vma->vm_flags & VM_WRITE))
+			goto bad_area;
+	else
+		if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
+			goto bad_area;
+	handle_mm_fault(vma, address, write);
+	return;
+bad_area:
+	current->tss.sig_address = address;
+	current->tss.sig_desc = SUBSIG_NOMAPPING;
+	send_sig(SIGSEGV, current, 1);
+	return;
+}
+
+void window_overflow_fault(void)
 {
-	int wincount = 0;
-	int signal = 0;
-	struct thread_struct *tsp = &current->tss;
-
-	flush_user_windows();
-#ifdef DEBUG_WINFAULT
-	{
-		int i;
-		printk("%s[%d]wfault<%d>: WINDOW DUMP --> ", current->comm,
-		       current->pid, push);
-		if(push==1)
-			for(i = 0; i < tsp->w_saved; i++)
-				printk("w[%d]sp<%08lx>, ",
-				       i, tsp->rwbuf_stkptrs[i]);
-		else
-			printk("w[0]sp<%08lx>", regs->u_regs[UREG_FP]);
-		if(push!=2)
-			printk("\n");
-	}
-#endif
-	if(push==1) {
-		/* We failed to push a window to users stack. */
-		while(wincount < tsp->w_saved) {
-			if ((tsp->rwbuf_stkptrs[wincount] & 7) ||
-			    (tsp->rwbuf_stkptrs[wincount] > KERNBASE) ||
-			    verify_area(VERIFY_WRITE,
-					(char *) tsp->rwbuf_stkptrs[wincount],
-					sizeof(struct reg_window))) {
-				signal = SIGILL;
-				break;
-			}			
-			/* Do it! */
-			memcpy((char *) tsp->rwbuf_stkptrs[wincount],
-			       (char *)&tsp->reg_window[wincount],
-			       sizeof(struct reg_window));
-			wincount++;
-		}
-	} else {
-		/* We failed to pull a window from users stack.
-		 * For a window underflow from userland we need
-		 * to verify two stacks, for a return from trap
-		 * we need only inspect the one at UREG_FP.
-		 */
-		if((regs->u_regs[UREG_FP] & 7) ||
-		   (regs->u_regs[UREG_FP] > KERNBASE) ||
-		   verify_area(VERIFY_READ,
-			       (char *) regs->u_regs[UREG_FP],
-			       sizeof(struct reg_window)))
-			signal = SIGILL;
-		else
-			memcpy((char *)&tsp->reg_window[0],
-			       (char *) regs->u_regs[UREG_FP],
-			       sizeof(struct reg_window));
-		if(push==2 && !signal) {
-			unsigned long sp = tsp->reg_window[0].ins[6];
-#ifdef DEBUG_WINFAULT
-			printk(", w[1]sp<%08lx>\n", sp);
-			show_regwindow(&tsp->reg_window[0]);
-#endif
-			if((sp & 7) || (sp > KERNBASE) ||
-			   verify_area(VERIFY_READ, (char *) sp,
-				       sizeof(struct reg_window)))
-				signal = SIGILL;
-			else
-				memcpy((char *)&tsp->reg_window[1],
-				       (char *) sp, sizeof(struct reg_window));
-		}
-	}
-	if(signal) {
-		printk("%s[%d]: User has trashed stack pointer pc<%08lx>sp<%08lx>\n",
-		       current->comm, current->pid, regs->pc, regs->u_regs[UREG_FP]);
-		tsp->sig_address = regs->pc;
-		tsp->sig_desc = SUBSIG_STACK;
-		send_sig(signal, current, 1);
-	} else
-		tsp->w_saved = 0;
+	unsigned long sp = current->tss.rwbuf_stkptrs[0];
+
+	if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
+		force_user_fault(sp + 0x38, 1);
+	force_user_fault(sp, 1);
+}
+
+void window_underflow_fault(unsigned long sp)
+{
+	if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
+		force_user_fault(sp + 0x38, 0);
+	force_user_fault(sp, 0);
+}
+
+void window_ret_fault(struct pt_regs *regs)
+{
+	unsigned long sp = regs->u_regs[UREG_FP];
+
+	if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
+		force_user_fault(sp + 0x38, 0);
+	force_user_fault(sp, 0);
 }
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/mm/init.c linux/arch/sparc/mm/init.c
--- v1.3.70/linux/arch/sparc/mm/init.c	Sat Nov 25 19:04:38 1995
+++ linux/arch/sparc/mm/init.c	Mon Mar  4 08:49:57 1996
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.26 1995/11/25 00:59:22 davem Exp $
+/*  $Id: init.c,v 1.33 1996/03/01 07:16:20 davem Exp $
  *  linux/arch/sparc/mm/init.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -15,6 +15,7 @@
 #include <linux/ptrace.h>
 #include <linux/mman.h>
 #include <linux/mm.h>
+#include <linux/swap.h>
 
 #include <asm/system.h>
 #include <asm/segment.h>
@@ -52,12 +53,6 @@
 	return pte_mkdirty(mk_pte((unsigned long) EMPTY_PGE, PAGE_SHARED));
 }
 
-unsigned long __zero_page(void)
-{
-	memset((void *) ZERO_PGE, 0, PAGE_SIZE);
-	return (unsigned long) ZERO_PGE;
-}
-
 void show_mem(void)
 {
 	int i,free = 0,total = 0,reserved = 0;
@@ -88,6 +83,26 @@
 
 extern pgprot_t protection_map[16];
 
+unsigned long sparc_context_init(unsigned long start_mem, int numctx)
+{
+	int ctx;
+
+	ctx_list_pool = (struct ctx_list *) start_mem;
+	start_mem += (numctx * sizeof(struct ctx_list));
+	for(ctx = 0; ctx < numctx; ctx++) {
+		struct ctx_list *clist;
+
+		clist = (ctx_list_pool + ctx);
+		clist->ctx_number = ctx;
+		clist->ctx_mm = 0;
+	}
+	ctx_free.next = ctx_free.prev = &ctx_free;
+	ctx_used.next = ctx_used.prev = &ctx_used;
+	for(ctx = 0; ctx < numctx; ctx++)
+		add_to_free_ctxlist(ctx_list_pool + ctx);
+	return start_mem;
+}
+
 /*
  * paging_init() sets up the page tables: We call the MMU specific
  * init routine based upon the Sun model type on the Sparc.
@@ -95,7 +110,7 @@
  */
 extern unsigned long sun4c_paging_init(unsigned long, unsigned long);
 extern unsigned long srmmu_paging_init(unsigned long, unsigned long);
-extern unsigned long probe_devices(unsigned long);
+extern unsigned long device_scan(unsigned long);
 
 unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
 {
@@ -109,10 +124,10 @@
 		start_mem = srmmu_paging_init(start_mem, end_mem);
 		break;
 	default:
-		printk("paging_init: Cannot init paging on this Sparc\n");
-		printk("paging_init: sparc_cpu_model = %d\n", sparc_cpu_model);
-		printk("paging_init: Halting...\n");
-		panic("paging_init");
+		prom_printf("paging_init: Cannot init paging on this Sparc\n");
+		prom_printf("paging_init: sparc_cpu_model = %d\n", sparc_cpu_model);
+		prom_printf("paging_init: Halting...\n");
+		prom_halt();
 	};
 
 	/* Initialize the protection map with non-constant values
@@ -134,13 +149,18 @@
 	protection_map[13] = PAGE_READONLY;
 	protection_map[14] = PAGE_SHARED;
 	protection_map[15] = PAGE_SHARED;
-	return probe_devices(start_mem);
+	return device_scan(start_mem);
 }
 
 extern void sun4c_test_wp(void);
-extern void sun4c_lock_entire_kernel(unsigned long start_mem);
 extern void srmmu_test_wp(void);
 
+struct cache_palias *sparc_aliases;
+
+extern int min_free_pages;
+extern int free_pages_low;
+extern int free_pages_high;
+
 void mem_init(unsigned long start_mem, unsigned long end_mem)
 {
 	int codepages = 0;
@@ -148,6 +168,9 @@
 	unsigned long tmp2, addr;
 	extern char etext;
 
+	/* Saves us work later. */
+	memset((void *) ZERO_PAGE, 0, PAGE_SIZE);
+
 	end_mem &= PAGE_MASK;
 	high_memory = end_mem;
 
@@ -189,10 +212,15 @@
 	       codepages << (PAGE_SHIFT-10),
 	       datapages << (PAGE_SHIFT-10));
 
+	min_free_pages = nr_free_pages >> 7;
+	if(min_free_pages < 16)
+		min_free_pages = 16;
+	free_pages_low = min_free_pages + (min_free_pages >> 1);
+	free_pages_high = min_free_pages + min_free_pages;
+
 	switch(sparc_cpu_model) {
 	case sun4c:
 	case sun4e:
-		sun4c_lock_entire_kernel(start_mem);
 		sun4c_test_wp();
 		break;
 	case sun4m:
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/mm/loadmmu.c linux/arch/sparc/mm/loadmmu.c
--- v1.3.70/linux/arch/sparc/mm/loadmmu.c	Sat Nov 25 19:04:38 1995
+++ linux/arch/sparc/mm/loadmmu.c	Mon Mar  4 08:49:57 1996
@@ -1,4 +1,4 @@
-/* $Id: loadmmu.c,v 1.13 1995/11/25 00:59:24 davem Exp $
+/* $Id: loadmmu.c,v 1.23 1996/02/21 17:56:35 miguel Exp $
  * loadmmu.c:  This code loads up all the mm function pointers once the
  *             machine type has been determined.  It also sets the static
  *             mmu values such as PAGE_NONE, etc.
@@ -16,22 +16,29 @@
 struct ctx_list ctx_free;
 struct ctx_list ctx_used;
 
-void (*mmu_exit_hook)(void *);
-void (*mmu_fork_hook)(void *, unsigned long);
-void (*mmu_release_hook)(void *);
-void (*mmu_flush_hook)(void *);
-void (*mmu_task_cacheflush)(void *);
+unsigned long (*alloc_kernel_stack)(struct task_struct *tsk);
+void (*free_kernel_stack)(unsigned long stack);
+struct task_struct *(*alloc_task_struct)(void);
+void (*free_task_struct)(struct task_struct *tsk);
+
+void (*quick_kernel_fault)(unsigned long);
+
+void (*mmu_exit_hook)(void);
+void (*mmu_flush_hook)(void);
 
 char *(*mmu_lockarea)(char *, unsigned long);
 void  (*mmu_unlockarea)(char *, unsigned long);
-char *(*mmu_get_scsi_buffer)(char *, unsigned long);
-void  (*mmu_release_scsi_buffer)(char *, unsigned long);
+char *(*mmu_get_scsi_buffer)(char *, unsigned long, struct linux_sbus *sbus);
+void  (*mmu_release_scsi_buffer)(char *, unsigned long, struct linux_sbus *sbus);
 
 
-int (*get_fault_info)(unsigned long *, unsigned long *, unsigned long);
 void (*update_mmu_cache)(struct vm_area_struct *vma, unsigned long address, pte_t pte);
 
-void (*invalidate)(void);
+void (*invalidate_all)(void);
+void (*invalidate_mm)(struct mm_struct *);
+void (*invalidate_range)(struct mm_struct *, unsigned long start, unsigned long end);
+void (*invalidate_page)(struct vm_area_struct *, unsigned long address);
+
 void (*set_pte)(pte_t *pteptr, pte_t pteval);
 
 unsigned int pmd_shift, pmd_size, pmd_mask;
@@ -39,9 +46,9 @@
 unsigned int pgdir_shift, pgdir_size, pgdir_mask;
 unsigned int (*pgdir_align)(unsigned int);
 unsigned int ptrs_per_pte, ptrs_per_pmd, ptrs_per_pgd;
+unsigned int pg_iobits;
 
 pgprot_t page_none, page_shared, page_copy, page_readonly, page_kernel;
-pgprot_t page_invalid;
 
 unsigned long (*pte_page)(pte_t);
 unsigned long (*pmd_page)(pmd_t);
@@ -49,7 +56,7 @@
 
 void (*sparc_update_rootmmu_dir)(struct task_struct *, pgd_t *pgdir);
 unsigned long (*(vmalloc_start))(void);
-void (*switch_to_context)(void *vtask);
+void (*switch_to_context)(struct task_struct *tsk);
 
 int (*pte_none)(pte_t);
 int (*pte_present)(pte_t);
@@ -72,6 +79,7 @@
 void (*pgd_reuse)(pgd_t *);
 
 pte_t (*mk_pte)(unsigned long, pgprot_t);
+pte_t (*mk_pte_io)(unsigned long, pgprot_t);
 void (*pgd_set)(pgd_t *, pmd_t *);
 pte_t (*pte_modify)(pte_t, pgprot_t);
 pgd_t * (*pgd_offset)(struct mm_struct *, unsigned long);
@@ -91,28 +99,18 @@
 
 pgd_t * (*pgd_alloc)(void);
 
-int (*pte_read)(pte_t);
 int (*pte_write)(pte_t);
-int (*pte_exec)(pte_t);
 int (*pte_dirty)(pte_t);
 int (*pte_young)(pte_t);
-int (*pte_cow)(pte_t);
 
 pte_t (*pte_wrprotect)(pte_t);
-pte_t (*pte_rdprotect)(pte_t);
-pte_t (*pte_exprotect)(pte_t);
 pte_t (*pte_mkclean)(pte_t);
 pte_t (*pte_mkold)(pte_t);
-pte_t (*pte_uncow)(pte_t);
 pte_t (*pte_mkwrite)(pte_t);
-pte_t (*pte_mkread)(pte_t);
-pte_t (*pte_mkexec)(pte_t);
 pte_t (*pte_mkdirty)(pte_t);
 pte_t (*pte_mkyoung)(pte_t);
-pte_t (*pte_mkcow)(pte_t);
 
-unsigned long (*sparc_virt_to_phys)(unsigned long);
-unsigned long (*sparc_phys_to_virt)(unsigned long);
+char *(*mmu_info)(void);
 
 extern void ld_mmu_sun4c(void);
 extern void ld_mmu_srmmu(void);
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/mm/s4cflsh.S linux/arch/sparc/mm/s4cflsh.S
--- v1.3.70/linux/arch/sparc/mm/s4cflsh.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/mm/s4cflsh.S	Mon Mar  4 08:49:58 1996
@@ -0,0 +1,49 @@
+/* s4cflsh.S: Low-level segment cache flush routines, shared by
+ *            the kernel and user in-window tlb refill routines.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caipfs.rutgers.edu)
+ */
+
+#include "s4clow.h"
+
+/* %g1 -- base address of segment to flush
+ * %g4 -- pc of caller
+ */
+	.text
+	.align	4
+	.globl	sun4c_segment_cache_flush
+sun4c_segment_cache_flush:
+	std	%g0, [REGSAVE_BASE + FLUSHREGS + 0x0]
+	std	%g2, [REGSAVE_BASE + FLUSHREGS + 0x8]
+	set	C_LABEL(sun4c_vacinfo), %g2
+	ld	[%g2 + VACINFO_HWFLSH], %g3
+	cmp	%g3, 0x0
+	ld	[%g2 + VACINFO_SIZE], %g3
+	add	%g1, %g3, %g3
+	be,a	sw_flush
+	 ld	[%g2 + VACINFO_LSIZE], %g2
+
+	/* Hardware flush */
+	sethi	%hi(PAGE_SIZE), %g2
+	sta	%g0, [%g1] 0x05
+1:
+	add	%g1, %g2, %g1
+	cmp	%g1, %g3
+	blu,a	1b
+	 sta	%g0, [%g1] 0x05
+
+	ldd	[REGSAVE_BASE + FLUSHREGS + 0x0], %g0
+	jmpl	%g4, %g0
+	 ldd	[REGSAVE_BASE + FLUSHREGS + 0x8], %g2
+
+sw_flush:
+	sta	%g0, [%g1] 0x0c
+2:
+	add	%g1, %g2, %g1
+	cmp	%g1, %g3
+	blu,a	2b
+	 sta	%g0, [%g1] 0x0c
+
+	ldd	[REGSAVE_BASE + FLUSHREGS + 0x0], %g0
+	jmpl	%g4, %g0
+	 ldd	[REGSAVE_BASE + FLUSHREGS + 0x8], %g2
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/mm/s4cflush.S linux/arch/sparc/mm/s4cflush.S
--- v1.3.70/linux/arch/sparc/mm/s4cflush.S	Sat Nov 25 19:04:38 1995
+++ linux/arch/sparc/mm/s4cflush.S	Thu Jan  1 02:00:00 1970
@@ -1,575 +0,0 @@
-/* $Id: s4cflush.S,v 1.8 1995/11/25 00:59:29 davem Exp $
- * s4cflush.S: Inline management of the sun4c cache.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#include <asm/head.h>
-#include <asm/cprefix.h>
-#include <asm/asi.h>
-#include <asm/page.h>
-
-/* We need to be able to call a routine which will in low-level
- * assembly flush an entire segment from the virtual cache using
- * a base virtual address and that will use as few registers as
- * possible.  The address of that function is stored here.
- * The register usage for this routine is defined as
- * %l2 -- Address of Segment to flush
- * %l4 -- Return address
- * %l6 -- scratch
- * %l7 -- scratch
- */
-	.align	4
-	.globl	C_LABEL(sun4c_ctxflush), C_LABEL(sun4c_segflush)
-	.globl	C_LABEL(sun4c_pgflush)
-C_LABEL(sun4c_ctxflush):	.word	C_LABEL(sun4c_ctxflush_sw64KB16B)
-C_LABEL(sun4c_segflush):	.word	C_LABEL(sun4c_segflush_sw64KB16B)
-C_LABEL(sun4c_pgflush):		.word	C_LABEL(sun4c_pgflush_sw64KB16B)
-
-	.text
-
-	/* Here are the assembly in-line virtual cache flushing
-	 * routines on the sun4c.
-	 */
-
-	.align 4
-	.globl C_LABEL(sun4c_ctxflush_hw64KB16B)
-
-	/* Flush an entire context using hardware assisted flushes
-	 * for a cache of size 64KB with 16B lines.
-	 */
-C_LABEL(sun4c_ctxflush_hw64KB16B):
-	sethi	%hi(PAGE_SIZE), %l6
-	/* Now flush 16 pages starting at virtual address zero */
-	or	%g0, %g0, %l7	
-	sta	%g0, [%l7] ASI_HWFLUSHCONTEXT   /* One */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHCONTEXT   /* Two */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHCONTEXT   /* Three */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHCONTEXT   /* Four */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHCONTEXT   /* Five */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHCONTEXT   /* Six */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHCONTEXT   /* Seven */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHCONTEXT   /* Eight */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHCONTEXT   /* Nine */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHCONTEXT   /* Ten */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHCONTEXT   /* Eleven */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHCONTEXT   /* Twelve */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHCONTEXT   /* Thirteen */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHCONTEXT   /* Fourteen */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHCONTEXT   /* Fifteen */
-	add	%l7, %l6, %l7
-
-	/* Return to caller and flush the last page */
-	jmpl	%l4 + 0x8, %g0
-	sta	%g0, [%l7] ASI_HWFLUSHCONTEXT   /* Sixteen */
-
-
-	.globl C_LABEL(sun4c_ctxflush_sw64KB16B)
-
-	/* Flush an entire context using software flushes
-	 * for a cache of size 64KB with 16B lines.
-	 */
-C_LABEL(sun4c_ctxflush_sw64KB16B):
-	/* Starting at virtual address zero, software flush
-	 * 4096 lines at 16 byte intervals.
-	 */
-#define SWFLUSHCTX16_2LINES \
-	sta	%g0, [%l7] ASI_FLUSHCTX; \
-	add	%l7, 0x10, %l7; \
-	sta	%g0, [%l7] ASI_FLUSHCTX; \
-	add	%l7, 0x10, %l7; \
-
-#define SWFLUSHCTX16_4LINES \
-	SWFLUSHCTX16_2LINES \
-	SWFLUSHCTX16_2LINES \
-	
-#define SWFLUSHCTX16_8LINES \
-	SWFLUSHCTX16_4LINES \
-	SWFLUSHCTX16_4LINES \
-	
-#define SWFLUSHCTX16_16LINES \
-	SWFLUSHCTX16_8LINES \
-	SWFLUSHCTX16_8LINES \
-	
-#define SWFLUSHCTX16_32LINES \
-	SWFLUSHCTX16_16LINES \
-	SWFLUSHCTX16_16LINES \
-	
-#define SWFLUSHCTX16_64LINES \
-	SWFLUSHCTX16_32LINES \
-	SWFLUSHCTX16_32LINES \
-	
-#define SWFLUSHCTX16_128LINES \
-	SWFLUSHCTX16_64LINES \
-	SWFLUSHCTX16_64LINES \
-	
-#define SWFLUSHCTX16_256LINES \
-	SWFLUSHCTX16_128LINES \
-	SWFLUSHCTX16_128LINES \
-	
-	/* WHEE! */
-	or	%g0, %g0, %l7		/* Base register */
-	SWFLUSHCTX16_256LINES
-	SWFLUSHCTX16_256LINES
-	SWFLUSHCTX16_256LINES
-	SWFLUSHCTX16_256LINES
-	SWFLUSHCTX16_256LINES
-	SWFLUSHCTX16_256LINES
-	SWFLUSHCTX16_256LINES
-	SWFLUSHCTX16_256LINES
-	SWFLUSHCTX16_256LINES
-	SWFLUSHCTX16_256LINES
-	SWFLUSHCTX16_256LINES
-	SWFLUSHCTX16_256LINES
-	SWFLUSHCTX16_256LINES
-	SWFLUSHCTX16_256LINES
-	SWFLUSHCTX16_256LINES
-	SWFLUSHCTX16_256LINES
-
-	/* Done, return to caller */
-	jmpl	%l4 + 0x8, %g0
-	nop
-
-	.globl C_LABEL(sun4c_ctxflush_hw64KB32B)
-	/* Flush an entire context using hardware assisted flushes
-	 * for a cache of size 64KB with 32B lines.
-	 */
-C_LABEL(sun4c_ctxflush_hw64KB32B):
-	sethi	%hi(PAGE_SIZE), %l6
-	/* Now flush 16 pages starting at virtual address zero */
-	or	%g0, %g0, %l7	
-	sta	%g0, [%l7] ASI_HWFLUSHCONTEXT   /* One */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHCONTEXT   /* Two */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHCONTEXT   /* Three */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHCONTEXT   /* Four */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHCONTEXT   /* Five */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHCONTEXT   /* Six */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHCONTEXT   /* Seven */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHCONTEXT   /* Eight */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHCONTEXT   /* Nine */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHCONTEXT   /* Ten */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHCONTEXT   /* Eleven */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHCONTEXT   /* Twelve */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHCONTEXT   /* Thirteen */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHCONTEXT   /* Fourteen */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHCONTEXT   /* Fifteen */
-	add	%l7, %l6, %l7
-
-	/* Return to caller and flush the last page */
-	jmpl	%l4 + 0x8, %g0
-	sta	%g0, [%l7] ASI_HWFLUSHCONTEXT   /* Sixteen */
-
-	.globl C_LABEL(sun4c_ctxflush_sw64KB32B)
-
-	/* Flush an entire context using software flushes
-	 * for a cache of size 64KB with 32B lines.
-	 */
-C_LABEL(sun4c_ctxflush_sw64KB32B):
-	/* Starting at virtual address zero, software flush
-	 * 2048 lines at 32 byte intervals.
-	 */
-#define SWFLUSHCTX32_2LINES \
-	sta	%g0, [%l7] ASI_FLUSHCTX; \
-	add	%l7, 0x20, %l7; \
-	sta	%g0, [%l7] ASI_FLUSHCTX; \
-	add	%l7, 0x20, %l7; \
-	
-#define SWFLUSHCTX32_4LINES \
-	SWFLUSHCTX32_2LINES \
-	SWFLUSHCTX32_2LINES \
-
-#define SWFLUSHCTX32_8LINES \
-	SWFLUSHCTX32_4LINES \
-	SWFLUSHCTX32_4LINES \
-
-#define SWFLUSHCTX32_16LINES \
-	SWFLUSHCTX32_8LINES \
-	SWFLUSHCTX32_8LINES \
-
-#define SWFLUSHCTX32_32LINES \
-	SWFLUSHCTX32_16LINES \
-	SWFLUSHCTX32_16LINES \
-
-#define SWFLUSHCTX32_64LINES \
-	SWFLUSHCTX32_32LINES \
-	SWFLUSHCTX32_32LINES \
-
-#define SWFLUSHCTX32_128LINES \
-	SWFLUSHCTX32_64LINES \
-	SWFLUSHCTX32_64LINES \
-
-	/* WHEE! */
-	or	%g0, %g0, %l7		/* Base register */
-	SWFLUSHCTX32_128LINES
-	SWFLUSHCTX32_128LINES
-	SWFLUSHCTX32_128LINES
-	SWFLUSHCTX32_128LINES
-	SWFLUSHCTX32_128LINES
-	SWFLUSHCTX32_128LINES
-	SWFLUSHCTX32_128LINES
-	SWFLUSHCTX32_128LINES
-	SWFLUSHCTX32_128LINES
-	SWFLUSHCTX32_128LINES
-	SWFLUSHCTX32_128LINES
-	SWFLUSHCTX32_128LINES
-	SWFLUSHCTX32_128LINES
-	SWFLUSHCTX32_128LINES
-	SWFLUSHCTX16_256LINES
-	SWFLUSHCTX16_256LINES
-
-	jmpl	%l4 + 0x8, %g0
-	nop
-
-	.align 4
-	.globl C_LABEL(sun4c_segflush_hw64KB16B)
-
-	/* Flush an entire segment using hardware assisted flushes
-	 * for a cache of size 64KB with 16B lines.
-	 */
-C_LABEL(sun4c_segflush_hw64KB16B):
-	sethi	%hi(PAGE_SIZE), %l6	/* Increment */
-	sethi	%hi(0xfffc0000), %l7
-	and	%l2, %l7, %l7		/* Base address */
-
-	/* Now flush 16 pages starting at beginning of vseg */
-	sta	%g0, [%l7] ASI_HWFLUSHSEG   /* One */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHSEG   /* Two */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHSEG   /* Three */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHSEG   /* Four */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHSEG   /* Five */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHSEG   /* Six */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHSEG   /* Seven */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHSEG   /* Eight */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHSEG   /* Nine */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHSEG   /* Ten */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHSEG   /* Eleven */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHSEG   /* Twelve */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHSEG   /* Thirteen */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHSEG   /* Fourteen */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHSEG   /* Fifteen */
-	add	%l7, %l6, %l7
-
-	/* Return to caller and flush the last page */
-	jmpl	%l4 + 0x8, %g0
-	sta	%g0, [%l7] ASI_HWFLUSHSEG   /* Sixteen */
-
-	.globl C_LABEL(sun4c_segflush_sw64KB16B)
-
-	/* Flush an entire segment using software flushes
-	 * for a cache of size 64KB with 16B lines.
-	 */
-C_LABEL(sun4c_segflush_sw64KB16B):
-	/* Starting at virtual address in %l2, software flush
-	 * 4096 lines at 16 byte intervals.
-	 */
-#define SWFLUSHSEG16_2LINES \
-	sta	%g0, [%l7] ASI_FLUSHSEG; \
-	add	%l7, 0x10, %l7; \
-	sta	%g0, [%l7] ASI_FLUSHSEG; \
-	add	%l7, 0x10, %l7; \
-
-#define SWFLUSHSEG16_4LINES \
-	SWFLUSHSEG16_2LINES \
-	SWFLUSHSEG16_2LINES \
-
-#define SWFLUSHSEG16_8LINES \
-	SWFLUSHSEG16_4LINES \
-	SWFLUSHSEG16_4LINES \
-
-#define SWFLUSHSEG16_16LINES \
-	SWFLUSHSEG16_8LINES \
-	SWFLUSHSEG16_8LINES \
-
-#define SWFLUSHSEG16_32LINES \
-	SWFLUSHSEG16_16LINES \
-	SWFLUSHSEG16_16LINES \
-
-#define SWFLUSHSEG16_64LINES \
-	SWFLUSHSEG16_32LINES \
-	SWFLUSHSEG16_32LINES \
-
-#define SWFLUSHSEG16_128LINES \
-	SWFLUSHSEG16_64LINES \
-	SWFLUSHSEG16_64LINES \
-
-#define SWFLUSHSEG16_256LINES \
-	SWFLUSHSEG16_128LINES \
-	SWFLUSHSEG16_128LINES \
-
-	sethi	%hi(0xfffc0000), %l7
-	and	%l2, %l7, %l7		/* Base register */
-	SWFLUSHSEG16_256LINES
-	SWFLUSHSEG16_256LINES
-	SWFLUSHSEG16_256LINES
-	SWFLUSHSEG16_256LINES
-	SWFLUSHSEG16_256LINES
-	SWFLUSHSEG16_256LINES
-	SWFLUSHSEG16_256LINES
-	SWFLUSHSEG16_256LINES
-	SWFLUSHSEG16_256LINES
-	SWFLUSHSEG16_256LINES
-	SWFLUSHSEG16_256LINES
-	SWFLUSHSEG16_256LINES
-	SWFLUSHSEG16_256LINES
-	SWFLUSHSEG16_256LINES
-	SWFLUSHSEG16_256LINES
-	SWFLUSHSEG16_256LINES
-
-	/* Done, return to caller */
-	jmpl	%l4 + 0x8, %g0
-	nop
-
-	.globl C_LABEL(sun4c_segflush_hw64KB32B)
-
-	/* Flush an entire segment using hardware assisted flushes
-	 * for a cache of size 64KB with 32B lines.
-	 */
-C_LABEL(sun4c_segflush_hw64KB32B):
-	sethi	%hi(PAGE_SIZE), %l6	/* Increment */
-	sethi	%hi(0xfffc0000), %l7
-	and	%l2, %l7, %l7		/* Base register */
-
-	/* Now flush 16 pages starting at virtual address in %l7 */
-	sta	%g0, [%l7] ASI_HWFLUSHSEG   /* One */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHSEG   /* Two */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHSEG   /* Three */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHSEG   /* Four */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHSEG   /* Five */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHSEG   /* Six */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHSEG   /* Seven */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHSEG   /* Eight */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHSEG   /* Nine */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHSEG   /* Ten */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHSEG   /* Eleven */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHSEG   /* Twelve */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHSEG   /* Thirteen */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHSEG   /* Fourteen */
-	add	%l7, %l6, %l7
-	sta	%g0, [%l7] ASI_HWFLUSHSEG   /* Fifteen */
-	add	%l7, %l6, %l7
-
-	/* Return to caller and flush the last page */
-	jmpl	%l4 + 0x8, %g0
-	sta	%g0, [%l7] ASI_HWFLUSHSEG   /* Sixteen */
-	
-	.globl C_LABEL(sun4c_segflush_sw64KB32B)
-
-	/* Flush an entire segment using software flushes
-	 * for a cache of size 64KB with 32B lines.
-	 */
-C_LABEL(sun4c_segflush_sw64KB32B):
-	/* Starting at virtual address passed in %l2, software
-	 * flush 2048 lines at 32 byte intervals.
-	 */
-#define SWFLUSHSEG32_2LINES \
-	sta	%g0, [%l7] ASI_FLUSHSEG; \
-	add	%l7, 0x20, %l7; \
-	sta	%g0, [%l7] ASI_FLUSHSEG; \
-	add	%l7, 0x20, %l7; \
-
-#define SWFLUSHSEG32_4LINES \
-	SWFLUSHSEG32_2LINES \
-	SWFLUSHSEG32_2LINES \
-
-#define SWFLUSHSEG32_8LINES \
-	SWFLUSHSEG32_4LINES \
-	SWFLUSHSEG32_4LINES \
-
-#define SWFLUSHSEG32_16LINES \
-	SWFLUSHSEG32_8LINES \
-	SWFLUSHSEG32_8LINES \
-
-#define SWFLUSHSEG32_32LINES \
-	SWFLUSHSEG32_16LINES \
-	SWFLUSHSEG32_16LINES \
-
-#define SWFLUSHSEG32_64LINES \
-	SWFLUSHSEG32_32LINES \
-	SWFLUSHSEG32_32LINES \
-
-#define SWFLUSHSEG32_128LINES \
-	SWFLUSHSEG32_64LINES \
-	SWFLUSHSEG32_64LINES \
-
-	/* WHEE! */
-	sethi	%hi(0xfffc0000), %l7
-	and	%l2, %l7, %l7		/* Base register */
-	SWFLUSHSEG32_128LINES
-	SWFLUSHSEG32_128LINES
-	SWFLUSHSEG32_128LINES
-	SWFLUSHSEG32_128LINES
-	SWFLUSHSEG32_128LINES
-	SWFLUSHSEG32_128LINES
-	SWFLUSHSEG32_128LINES
-	SWFLUSHSEG32_128LINES
-	SWFLUSHSEG32_128LINES
-	SWFLUSHSEG32_128LINES
-	SWFLUSHSEG32_128LINES
-	SWFLUSHSEG32_128LINES
-	SWFLUSHSEG32_128LINES
-	SWFLUSHSEG32_128LINES
-	SWFLUSHSEG32_128LINES
-	SWFLUSHSEG32_128LINES
-
-	jmpl	%l4 + 0x8, %g0
-	nop
-
-	.align 4
-	.globl C_LABEL(sun4c_pgflush_hw64KB16B)
-	.globl C_LABEL(sun4c_pgflush_hw64KB32B)
-
-	/* Flush a page using hardware assisted flushes
-	 * for a cache of size 64KB with 16B or 32B lines.
-	 */
-C_LABEL(sun4c_pgflush_hw64KB16B):
-C_LABEL(sun4c_pgflush_hw64KB32B):
-	/* Easiest flush possible on sun4c */
-	jmpl	%l4 + 0x8, %g0
-	sta	%g0, [%l2] ASI_HWFLUSHPAGE
-
-	.globl	C_LABEL(sun4c_pgflush_sw64KB16B)
-	/* Flush a page using software flushes for a cache
-	 * of size 64KB with 16B lines.
-	 */
-C_LABEL(sun4c_pgflush_sw64KB16B):
-	/* Flush every line within the page */
-#define SWFLUSHPG16_2LINES \
-	sta	%g0, [%l7] ASI_FLUSHPG; \
-	add	%l7, 0x10, %l7; \
-	sta	%g0, [%l7] ASI_FLUSHPG; \
-	add	%l7, 0x10, %l7; \
-
-#define SWFLUSHPG16_4LINES \
-	SWFLUSHPG16_2LINES \
-	SWFLUSHPG16_2LINES \
-
-#define SWFLUSHPG16_8LINES \
-	SWFLUSHPG16_4LINES \
-	SWFLUSHPG16_4LINES \
-
-#define SWFLUSHPG16_16LINES \
-	SWFLUSHPG16_8LINES \
-	SWFLUSHPG16_8LINES \
-
-#define SWFLUSHPG16_32LINES \
-	SWFLUSHPG16_16LINES \
-	SWFLUSHPG16_16LINES \
-
-#define SWFLUSHPG16_64LINES \
-	SWFLUSHPG16_32LINES \
-	SWFLUSHPG16_32LINES \
-
-#define SWFLUSHPG16_128LINES \
-	SWFLUSHPG16_64LINES \
-	SWFLUSHPG16_64LINES \
-
-#define SWFLUSHPG16_256LINES \
-	SWFLUSHPG16_128LINES \
-	SWFLUSHPG16_128LINES \
-
-	or	%l2, %g0, %l7		/* Base address of page */
-	SWFLUSHPG16_256LINES
-
-	/* Return to caller and flush last line */
-	jmpl	%l4 + 0x8, %g0
-	nop
-
-	.globl	C_LABEL(sun4c_pgflush_sw64KB32B)
-	/* Flush a page using software flushes for a cache
-	 * of size 64KB with 32B lines.
-	 */
-C_LABEL(sun4c_pgflush_sw64KB32B):
-	/* Flush every line within the page */
-#define SWFLUSHPG32_2LINES \
-	sta	%g0, [%l7] ASI_FLUSHPG; \
-	add	%l7, 0x20, %l7; \
-	sta	%g0, [%l7] ASI_FLUSHPG; \
-	add	%l7, 0x20, %l7; \
-
-#define SWFLUSHPG32_4LINES \
-	SWFLUSHPG32_2LINES \
-	SWFLUSHPG32_2LINES \
-
-#define SWFLUSHPG32_8LINES \
-	SWFLUSHPG32_4LINES \
-	SWFLUSHPG32_4LINES \
-
-#define SWFLUSHPG32_16LINES \
-	SWFLUSHPG32_8LINES \
-	SWFLUSHPG32_8LINES \
-
-#define SWFLUSHPG32_32LINES \
-	SWFLUSHPG32_16LINES \
-	SWFLUSHPG32_16LINES \
-
-#define SWFLUSHPG32_64LINES \
-	SWFLUSHPG32_32LINES \
-	SWFLUSHPG32_32LINES \
-
-#define SWFLUSHPG32_128LINES \
-	SWFLUSHPG32_64LINES \
-	SWFLUSHPG32_64LINES \
-
-	or	%l2, %g0, %l7		/* Base address of page */
-	SWFLUSHPG32_128LINES
-
-	/* Return to caller and flush last line */
-	jmpl	%l4 + 0x8, %g0
-	nop
-
-/* All that crap just to flush a fucking virtual cache, sheesh... */
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/mm/s4ckflt.S linux/arch/sparc/mm/s4ckflt.S
--- v1.3.70/linux/arch/sparc/mm/s4ckflt.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/mm/s4ckflt.S	Mon Mar  4 08:49:58 1996
@@ -0,0 +1,105 @@
+/* s4ckflt.S:  Quick in window kernel faults on the sun4c.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caipfs.rutgers.edu)
+ */
+
+#include "s4clow.h"
+
+	.text
+	.align 8
+	.globl	sun4c_quick_kernel_fault
+sun4c_quick_kernel_fault:
+	sethi	%hi(REAL_PGDIR_MASK), %l5
+	and	%l7, %l5, %l7
+	sethi	%hi(C_LABEL(invalid_segment)), %l5
+	lduba	[%l7] 0x3, %l4
+	ld	[%l5 + %lo(C_LABEL(invalid_segment))], %l5
+	cmp	%l4, %l5
+	bne	segment_loaded
+	 nop
+
+	/* We need some breathing room to pull this off, save
+	 * away some globals.
+	 */
+	std	%g0, [REGSAVE_BASE + KFLTREGS + 0x00]
+	std	%g2, [REGSAVE_BASE + KFLTREGS + 0x08]
+	std	%g4, [REGSAVE_BASE + KFLTREGS + 0x10]
+	std	%g6, [REGSAVE_BASE + KFLTREGS + 0x18]
+	std	%l0, [REGSAVE_BASE + KFLTREGS + 0x20]
+	std	%l2, [REGSAVE_BASE + KFLTREGS + 0x28]
+
+	set	C_LABEL(sun4c_kfree_ring), %g1
+	ld	[%g1 + RING_NENTRIES], %g2
+	cmp	%g2, 0x0
+	be,a	pseg_steal
+	 nop
+
+	b	distribute_segmap
+	 ld	[%g1 + RING_RINGHD + MMU_ENTRY_NEXT], %g2
+
+pseg_steal:
+	/* This is the hard case. */	
+	set	C_LABEL(sun4c_kernel_ring), %g1
+	ld	[%g1 + RING_RINGHD + MMU_ENTRY_PREV], %g2
+	b	kernel_segment_cache_flush
+	 ld	[%g2 + MMU_ENTRY_VADDR], %l0
+
+pseg_steal_after_flush:
+	ld	[%g2 + MMU_ENTRY_VADDR], %l0
+	sethi	%hi(0x30000000), %l1
+	lduba	[%l1] 0x02, %g7
+	sethi	%hi(C_LABEL(num_contexts)), %g6
+	mov	0, %g5
+	ld	[%g6 + %lo(C_LABEL(num_contexts))], %g6
+1:
+	stba	%g5, [%l1] 0x02
+	add	%g5, 1, %g5
+	cmp	%g5, %g6
+	bl	1b
+	 stba	%l5, [%l0] 0x03
+
+	stba	%g7, [%l1] 0x02
+
+	
+
+distribute_segmap:
+	st	%l7, [%g2 + MMU_ENTRY_VADDR]
+	ldub	[%g2 + MMU_ENTRY_PSEG], %g3
+	sethi	%hi(0x30000000), %l0
+	lduba	[%l0] 0x02, %g7
+	sethi	%hi(C_LABEL(num_contexts)), %g6
+	mov	0, %g5
+	ld	[%g6 + %lo(C_LABEL(num_contexts))], %g6
+1:
+	stba	%g5, [%l0] 0x02
+	add	%g5, 1, %g5
+	cmp	%g5, %g6
+	bl	1b
+	 stba	%g3, [%l7] 0x03
+
+	stba	%g7, [%l0] 0x02
+
+segment_loaded:
+	sethi	%hi(VMALLOC_START), %l4
+	cmp	%l7, %l4
+	bge	vmalloc_kernel_fault
+	 nop
+
+
+
+
+
+vmalloc_kernel_fault:
+
+
+qkf_exit:
+	/* Fault serviced, return from trap, but reload
+	 * registers first.
+	 */
+	ldd	[REGSAVE_BASE + KFLTREGS + 0x00], %g0
+	ldd	[REGSAVE_BASE + KFLTREGS + 0x08], %g2
+	ldd	[REGSAVE_BASE + KFLTREGS + 0x10], %g4
+	ldd	[REGSAVE_BASE + KFLTREGS + 0x18], %g6
+	ldd	[REGSAVE_BASE + KFLTREGS + 0x20], %l0
+	ldd	[REGSAVE_BASE + KFLTREGS + 0x28], %l2
+
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/mm/s4clow.h linux/arch/sparc/mm/s4clow.h
--- v1.3.70/linux/arch/sparc/mm/s4clow.h	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/mm/s4clow.h	Mon Mar  4 08:49:58 1996
@@ -0,0 +1,48 @@
+/* s4clow.h: Defines for in-window low level tlb refill code.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caipfs.rutgers.edu)
+ */
+#ifndef _SPARC_S4CLOW_H
+#define _SPARC_S4CLOW_H
+
+#define         PAGE_SIZE       0x00001000
+#define		REAL_PGDIR_MASK	0xfffc0000
+#define		VMALLOC_START	0xfe100000
+
+#define		RING_RINGHD	0x00
+#define		RING_NENTRIES   0x10
+
+#define		MMU_ENTRY_NEXT	0x00
+#define		MMU_ENTRY_PREV	0x04
+#define		MMU_ENTRY_VADDR	0x08
+#define		MMU_ENTRY_PSEG	0x0c
+#define		MMU_ENTRY_LCK	0x0d
+
+#define		VACINFO_SIZE	0x00
+#define		VACINFO_HWFLSH	0x08
+#define		VACINFO_LSIZE	0x0c
+
+/* Each of the routines could get called by any of the
+ * other low level sun4c tlb routines.  Well... at least
+ * we code it that way.  Because we are in window we need
+ * a way to make a routine completely self contained and
+ * only need to worry about saving it's own set of registers
+ * which it in fact uses.  With traps off this is difficult
+ * ... however...
+ *
+ * The Sparc can address anywhere in the two ranges
+ * 0 --> PAGE_SIZE and -PAGE_SIZE --> -1 without any
+ * address calculation registers.  So we pull a trick,
+ * we map a special page for these low level tlb routines
+ * since they must be as quick as possible.  Since the low
+ * page is the NULL unmapped page and in user space we use
+ * the high one for simplicity.  Kids, do not try this at
+ * home.
+ */
+#define          REGSAVE_BASE   (-PAGE_SIZE)
+
+#define          FLUSHREGS      0
+#define          KFLTREGS       256
+#define          UFLTREGS       512
+
+#endif /* !(_SPARC_S4CLOW_H) */
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/mm/s4cuflt.S linux/arch/sparc/mm/s4cuflt.S
--- v1.3.70/linux/arch/sparc/mm/s4cuflt.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/mm/s4cuflt.S	Mon Mar  4 08:49:58 1996
@@ -0,0 +1,20 @@
+/* s4cuflt.S:  Quick in window user tlb faults on the sun4c.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caipfs.rutgers.edu)
+ */
+
+	.data
+
+	.align	8
+.g0g1:	.quad	0
+.g2g3:	.quad	0
+.g4g5:	.quad	0
+.g6g7:	.quad	0
+
+#include "srclow.h"
+
+	.text
+
+	.align	8
+	.globl	sun4c_quick_user_fault
+sun4c_quick_user_fault:
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/mm/srmmu.c linux/arch/sparc/mm/srmmu.c
--- v1.3.70/linux/arch/sparc/mm/srmmu.c	Sat Nov 25 19:04:38 1995
+++ linux/arch/sparc/mm/srmmu.c	Mon Mar  4 08:49:58 1996
@@ -1,210 +1,231 @@
-/* $Id: srmmu.c,v 1.22 1995/11/25 00:59:33 davem Exp $
+/* $Id: srmmu.c,v 1.34 1996/03/01 07:16:23 davem Exp $
  * srmmu.c:  SRMMU specific routines for memory management.
  *
  * Copyright (C) 1995 David S. Miller  (davem@caip.rutgers.edu)
- * Copyright (C) 1995 Peter A. Zaitcev (zaitcev@lab.ipmce.su)
+ * Copyright (C) 1995 Peter A. Zaitcev (zaitcev@ithil.mcst.ru)
  */
 
-#include <linux/kernel.h>  /* for printk */
+#include <linux/kernel.h>
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
+#include <asm/io.h>
 #include <asm/kdebug.h>
 #include <asm/vaddrs.h>
 #include <asm/traps.h>
 #include <asm/mp.h>
+#include <asm/mbus.h>
 #include <asm/cache.h>
 #include <asm/oplib.h>
+#include <asm/sbus.h>
+#include <asm/iommu.h>
 
-extern unsigned long free_area_init(unsigned long, unsigned long);
+/* Now the cpu specific definitions. */
+#include <asm/viking.h>
+#include <asm/ross.h>
+#include <asm/tsunami.h>
+#include <asm/swift.h>
+
+enum mbus_module srmmu_modtype;
+unsigned int hwbug_bitmask;
+
+int hyper_cache_size;
 
-unsigned int srmmu_pmd_align(unsigned int addr) { return SRMMU_PMD_ALIGN(addr); }
-unsigned int srmmu_pgdir_align(unsigned int addr) { return SRMMU_PGDIR_ALIGN(addr); }
+ctxd_t *srmmu_context_table;
 
-unsigned long
-srmmu_vmalloc_start(void)
+/* In general all page table modifications should use the V8 atomic
+ * swap instruction.  This insures the mmu and the cpu are in sync
+ * with respect to ref/mod bits in the page tables.
+ */
+static inline unsigned long srmmu_swap(unsigned long *addr, unsigned long value)
 {
-	return ((high_memory + SRMMU_VMALLOC_OFFSET) & ~(SRMMU_VMALLOC_OFFSET-1));
+	__asm__ __volatile__("swap [%1], %0\n\t" :
+			     "=&r" (value), "=&r" (addr) :
+			     "0" (value), "1" (addr));
+	return value;
 }
 
-unsigned long 
-srmmu_pmd_page(pmd_t pmd)
+/* Functions really use this, not srmmu_swap directly. */
+#define srmmu_set_entry(ptr, newentry) \
+        srmmu_swap((unsigned long *) (ptr), (newentry))
+
+/* We still don't use these at all, perhaps we don't need them
+ * at all.
+ */
+unsigned long (*srmmu_read_physical)(unsigned long paddr);
+void (*srmmu_write_physical)(unsigned long paddr, unsigned long word);
+
+static unsigned long gensrmmu_read_physical(unsigned long paddr)
 {
-	unsigned long page;
+	unsigned long word;
 
-	page = (pmd_val(pmd) & (SRMMU_PTD_PTP_MASK)) << SRMMU_PTD_PTP_PADDR_SHIFT;
-	return (page + PAGE_OFFSET);
+	__asm__ __volatile__("lda [%1] %2, %0\n\t" :
+			     "=r" (word) :
+			     "r" (paddr), "i" (ASI_M_BYPASS) :
+			     "memory");
+	return word;
 }
 
-unsigned long
-srmmu_pgd_page(pgd_t pgd)
+static unsigned long msparc_read_physical(unsigned long paddr)
 {
-	unsigned long page;
+	unsigned long word, flags;
 
-	page = (pgd_val(pgd) & (SRMMU_PTD_PTP_MASK)) << SRMMU_PTD_PTP_PADDR_SHIFT;
-	return (page + PAGE_OFFSET);
+	save_flags(flags); cli();
+	__asm__ __volatile__("lda [%%g0] %3, %%g1\n\t"
+			     "or  %%g1, %4, %%g2\n\t"
+			     "sta %%g2, [%%g0] %3\n\t"
+			     "lda [%1] %2, %0\n\t"
+			     "sta %%g1, [%%g0] %3\n\t" :
+			     "=r" (word) :
+			     "r" (paddr), "i" (ASI_M_BYPASS),
+			     "i" (ASI_M_MMUREGS), "r" (VIKING_ACENABLE) :
+			     "g1", "g2", "memory");
+	restore_flags(flags);
+	return word;
 }
 
-unsigned long 
-srmmu_pte_page(pte_t pte)
+static void gensrmmu_write_physical(unsigned long paddr, unsigned long word)
 {
-	unsigned long page;
-
-	page = (pte_val(pte) & (SRMMU_PTE_PPN_MASK)) << SRMMU_PTE_PPN_PADDR_SHIFT;
-	return (page + PAGE_OFFSET);
+	__asm__ __volatile__("sta %0, [%1] %2\n\t" : :
+			     "r" (word), "r" (paddr), "i" (ASI_M_BYPASS) :
+			     "memory");
 }
 
-int srmmu_pte_none(pte_t pte)		{ return !pte_val(pte); }
-int srmmu_pte_present(pte_t pte)	{ return pte_val(pte) & SRMMU_ET_PTE; }
-int srmmu_pte_inuse(pte_t *ptep)        { return mem_map[MAP_NR(ptep)].reserved || mem_map[MAP_NR(ptep)].count != 1; }
-void srmmu_pte_clear(pte_t *ptep)	{ pte_val(*ptep) = 0; }
-void srmmu_pte_reuse(pte_t *ptep)
+static void msparc_write_physical(unsigned long paddr, unsigned long word)
 {
-  if(!mem_map[MAP_NR(ptep)].reserved)
-    mem_map[MAP_NR(ptep)].count++;
+	unsigned long flags;
+
+	save_flags(flags); cli();
+	__asm__ __volatile__("lda [%%g0] %3, %%g1\n\t"
+			     "or  %%g1, %4, %%g2\n\t"
+			     "sta %%g2, [%%g0] %3\n\t"
+			     "sta %0, [%1] %2\n\t"
+			     "sta %%g1, [%%g0] %3\n\t" : :
+			     "r" (word), "r" (paddr), "i" (ASI_M_BYPASS),
+			     "i" (ASI_M_MMUREGS), "r" (VIKING_ACENABLE) :
+			     "g1", "g2", "memory");
+	restore_flags(flags);
 }
 
-int srmmu_pmd_none(pmd_t pmd)		{ return !pmd_val(pmd); }
-int srmmu_pmd_bad(pmd_t pmd)
+static unsigned int srmmu_pmd_align(unsigned int addr) { return SRMMU_PMD_ALIGN(addr); }
+static unsigned int srmmu_pgdir_align(unsigned int addr) { return SRMMU_PGDIR_ALIGN(addr); }
+
+static unsigned long srmmu_vmalloc_start(void)
 {
-	return ((pmd_val(pmd)&SRMMU_ET_PTDBAD)==SRMMU_ET_PTDBAD) ||
-		(srmmu_pmd_page(pmd) > high_memory);
+	return SRMMU_VMALLOC_START;
 }
 
-int srmmu_pmd_present(pmd_t pmd)	{ return pmd_val(pmd) & SRMMU_ET_PTD; }
-int srmmu_pmd_inuse(pmd_t *pmdp)        { return mem_map[MAP_NR(pmdp)].reserved || mem_map[MAP_NR(pmdp)].count != 1; }
-void srmmu_pmd_clear(pmd_t *pmdp)	{ pmd_val(*pmdp) = 0; }
-void srmmu_pmd_reuse(pmd_t * pmdp)
+static unsigned long srmmu_pgd_page(pgd_t pgd)
+{ return PAGE_OFFSET + ((pgd_val(pgd) & SRMMU_PTD_PMASK) << 4); }
+
+static unsigned long srmmu_pmd_page(pmd_t pmd)
+{ return PAGE_OFFSET + ((pmd_val(pmd) & SRMMU_PTD_PMASK) << 4); }
+
+static unsigned long srmmu_pte_page(pte_t pte)
+{ return PAGE_OFFSET + ((pte_val(pte) & SRMMU_PTE_PMASK) << 4); }
+
+static int srmmu_pte_none(pte_t pte)          { return !pte_val(pte); }
+static int srmmu_pte_present(pte_t pte)
+{ return ((pte_val(pte) & SRMMU_ET_MASK) == SRMMU_ET_PTE); }
+
+static int srmmu_pte_inuse(pte_t *ptep)
+{ return mem_map[MAP_NR(ptep)].reserved || mem_map[MAP_NR(ptep)].count != 1; }
+
+static void srmmu_pte_clear(pte_t *ptep)      { pte_val(*ptep) = 0; }
+static void srmmu_pte_reuse(pte_t *ptep)
 {
-        if (!mem_map[MAP_NR(pmdp)].reserved)
-                mem_map[MAP_NR(pmdp)].count++;
+	if(!mem_map[MAP_NR(ptep)].reserved)
+		mem_map[MAP_NR(ptep)].count++;
 }
 
-int srmmu_pgd_none(pgd_t pgd)		{ return !pgd_val(pgd); }
-int srmmu_pgd_bad(pgd_t pgd)
+static int srmmu_pmd_none(pmd_t pmd)          { return !pmd_val(pmd); }
+static int srmmu_pmd_bad(pmd_t pmd)
+{ return (pmd_val(pmd) & SRMMU_ET_MASK) != SRMMU_ET_PTD; }
+
+static int srmmu_pmd_present(pmd_t pmd)
+{ return ((pmd_val(pmd) & SRMMU_ET_MASK) == SRMMU_ET_PTD); }
+
+static int srmmu_pmd_inuse(pmd_t *pmdp)
+{ return mem_map[MAP_NR(pmdp)].reserved || mem_map[MAP_NR(pmdp)].count != 1; }
+
+static void srmmu_pmd_clear(pmd_t *pmdp)      { pmd_val(*pmdp) = 0; }
+static void srmmu_pmd_reuse(pmd_t * pmdp)
 {
-	return ((pgd_val(pgd)&SRMMU_ET_PTDBAD)==SRMMU_ET_PTDBAD) ||
-		(srmmu_pgd_page(pgd) > high_memory);
+	if (!mem_map[MAP_NR(pmdp)].reserved)
+		mem_map[MAP_NR(pmdp)].count++;
 }
-int srmmu_pgd_present(pgd_t pgd)	{ return pgd_val(pgd) & SRMMU_ET_PTD; }
-int srmmu_pgd_inuse(pgd_t *pgdp)        { return mem_map[MAP_NR(pgdp)].reserved; }
-void srmmu_pgd_clear(pgd_t * pgdp)	{ pgd_val(*pgdp) = 0; }
-void srmmu_pgd_reuse(pgd_t *pgdp)
+
+static int srmmu_pgd_none(pgd_t pgd)          { return !pgd_val(pgd); }
+static int srmmu_pgd_bad(pgd_t pgd)
+{ return (pgd_val(pgd) & SRMMU_ET_MASK) != SRMMU_ET_PTD; }
+
+static int srmmu_pgd_present(pgd_t pgd)
+{ return ((pgd_val(pgd) & SRMMU_ET_MASK) == SRMMU_ET_PTD); }
+
+static int srmmu_pgd_inuse(pgd_t *pgdp)       { return mem_map[MAP_NR(pgdp)].reserved; }
+static void srmmu_pgd_clear(pgd_t * pgdp)     { pgd_val(*pgdp) = 0; }
+static void srmmu_pgd_reuse(pgd_t *pgdp)
 {
-  if (!mem_map[MAP_NR(pgdp)].reserved)
-    mem_map[MAP_NR(pgdp)].count++;
+	if (!mem_map[MAP_NR(pgdp)].reserved)
+		mem_map[MAP_NR(pgdp)].count++;
 }
 
-/*
- * The following only work if pte_present() is true.
- * Undefined behaviour if not..
- */
-int srmmu_pte_read(pte_t pte)		{ return (pte_val(pte) & _SRMMU_PAGE_RDONLY) || (pte_val(pte) & _SRMMU_PAGE_WRITE_USR); }
-int srmmu_pte_write(pte_t pte)		{ return pte_val(pte) & _SRMMU_PAGE_WRITE_USR; }
-int srmmu_pte_exec(pte_t pte)		{ return pte_val(pte) & _SRMMU_PAGE_EXEC; }
-int srmmu_pte_dirty(pte_t pte)		{ return pte_val(pte) & _SRMMU_PAGE_DIRTY; }
-int srmmu_pte_young(pte_t pte)		{ return pte_val(pte) & _SRMMU_PAGE_REF; }
-int srmmu_pte_cow(pte_t pte)		{ return pte_val(pte) & _SRMMU_PAGE_COW; }
-
-/* When we change permissions, we first clear all bits in the ACCESS field
- * then apply the wanted bits.
- */
-pte_t srmmu_pte_wrprotect(pte_t pte)	{ pte_val(pte) &= ~SRMMU_PTE_ACC_MASK; pte_val(pte) |= _SRMMU_PAGE_EXEC; return pte; }
-pte_t srmmu_pte_rdprotect(pte_t pte)	{ pte_val(pte) &= ~SRMMU_PTE_ACC_MASK; pte_val(pte) |= _SRMMU_PAGE_NOREAD; return pte; }
-pte_t srmmu_pte_exprotect(pte_t pte)	{ pte_val(pte) &= ~SRMMU_PTE_ACC_MASK; pte_val(pte) |= _SRMMU_PAGE_WRITE_USR; return pte; }
-pte_t srmmu_pte_mkclean(pte_t pte)	{ pte_val(pte) &= ~_SRMMU_PAGE_DIRTY; return pte; }
-pte_t srmmu_pte_mkold(pte_t pte)	{ pte_val(pte) &= ~_SRMMU_PAGE_REF; return pte; }
-pte_t srmmu_pte_uncow(pte_t pte)	{ pte_val(pte) &= ~SRMMU_PTE_ACC_MASK; pte_val(pte) |= _SRMMU_PAGE_UNCOW; return pte; }
-pte_t srmmu_pte_mkwrite(pte_t pte)	{ pte_val(pte) &= ~SRMMU_PTE_ACC_MASK; pte_val(pte) |= _SRMMU_PAGE_WRITE_USR; return pte; }
-pte_t srmmu_pte_mkread(pte_t pte)	{ pte_val(pte) &= ~SRMMU_PTE_ACC_MASK; pte_val(pte) |= _SRMMU_PAGE_RDONLY; return pte; }
-pte_t srmmu_pte_mkexec(pte_t pte)	{ pte_val(pte) &= ~SRMMU_PTE_ACC_MASK; pte_val(pte) |= _SRMMU_PAGE_EXEC; return pte; }
-pte_t srmmu_pte_mkdirty(pte_t pte)	{ pte_val(pte) |= _SRMMU_PAGE_DIRTY; return pte; }
-pte_t srmmu_pte_mkyoung(pte_t pte)	{ pte_val(pte) |= _SRMMU_PAGE_REF; return pte; }
-pte_t srmmu_pte_mkcow(pte_t pte)	{ pte_val(pte) &= ~SRMMU_PTE_ACC_MASK; pte_val(pte) |= _SRMMU_PAGE_COW; return pte; }
+static int srmmu_pte_write(pte_t pte)         { return pte_val(pte) & SRMMU_WRITE; }
+static int srmmu_pte_dirty(pte_t pte)         { return pte_val(pte) & SRMMU_DIRTY; }
+static int srmmu_pte_young(pte_t pte)         { return pte_val(pte) & SRMMU_REF; }
+
+static pte_t srmmu_pte_wrprotect(pte_t pte)   { pte_val(pte) &= ~SRMMU_WRITE; return pte;}
+static pte_t srmmu_pte_mkclean(pte_t pte)     { pte_val(pte) &= ~SRMMU_DIRTY; return pte; }
+static pte_t srmmu_pte_mkold(pte_t pte)       { pte_val(pte) &= ~SRMMU_REF; return pte; }
+static pte_t srmmu_pte_mkwrite(pte_t pte)     { pte_val(pte) |= SRMMU_WRITE; return pte; }
+static pte_t srmmu_pte_mkdirty(pte_t pte)     { pte_val(pte) |= SRMMU_DIRTY; return pte; }
+static pte_t srmmu_pte_mkyoung(pte_t pte)     { pte_val(pte) |= SRMMU_REF; return pte; }
 
 /*
  * Conversion functions: convert a page and protection to a page entry,
  * and a page entry and page directory to the page they refer to.
  */
-pte_t
-srmmu_mk_pte(unsigned long page, pgprot_t pgprot)
-{
-	pte_t pte;
-
-	if(page & (~PAGE_MASK)) panic("srmmu_mk_pte() called with unaligned page");
-	page = ((page - PAGE_OFFSET) >> SRMMU_PTE_PPN_PADDR_SHIFT);
-	pte_val(pte) = (page & SRMMU_PTE_PPN_MASK);
-	pte_val(pte) |= pgprot_val(pgprot);
-	return pte;
-}
+static pte_t srmmu_mk_pte(unsigned long page, pgprot_t pgprot)
+{ pte_t pte; pte_val(pte) = ((page - PAGE_OFFSET) >> 4) | pgprot_val(pgprot); return pte; }
 
-void
-srmmu_pgd_set(pgd_t * pgdp, pmd_t * pmdp)
-{
-	unsigned long page = (unsigned long) pmdp;
-
-	page = ((page - PAGE_OFFSET) >> SRMMU_PTD_PTP_PADDR_SHIFT);
+static pte_t srmmu_mk_pte_io(unsigned long page, pgprot_t pgprot)
+{ pte_t pte; pte_val(pte) = ((page) >> 4) | pgprot_val(pgprot); return pte; }
 
-	pgd_val(*pgdp) = ((page & SRMMU_PTD_PTP_MASK) | SRMMU_ET_PTD);
-}
-
-void
-srmmu_pmd_set(pmd_t * pmdp, pte_t * ptep)
-{
-	unsigned long page = (unsigned long) ptep;
+static void srmmu_ctxd_set(ctxd_t *ctxp, pgd_t *pgdp)
+{ srmmu_set_entry(ctxp, (SRMMU_ET_PTD | ((((unsigned long) pgdp) - PAGE_OFFSET) >> 4))); }
 
-	page = ((page - PAGE_OFFSET) >> SRMMU_PTD_PTP_PADDR_SHIFT);
+static void srmmu_pgd_set(pgd_t * pgdp, pmd_t * pmdp)
+{ srmmu_set_entry(pgdp, (SRMMU_ET_PTD | ((((unsigned long) pmdp) - PAGE_OFFSET) >> 4))); }
 
-	pmd_val(*pmdp) = ((page & SRMMU_PTD_PTP_MASK) | SRMMU_ET_PTD);
-}
+static void srmmu_pmd_set(pmd_t * pmdp, pte_t * ptep)
+{ srmmu_set_entry(pmdp, (SRMMU_ET_PTD | ((((unsigned long) ptep) - PAGE_OFFSET) >> 4))); }
 
-pte_t
-srmmu_pte_modify(pte_t pte, pgprot_t newprot)
-{
-	pte_val(pte) = (pte_val(pte) & (~SRMMU_PTE_ACC_MASK)) | pgprot_val(newprot);
-	return pte;
-}
+static pte_t srmmu_pte_modify(pte_t pte, pgprot_t newprot)
+{ pte_val(pte) = (pte_val(pte) & ~0xff) | pgprot_val(newprot); return pte; }
 
 /* to find an entry in a top-level page table... */
-pgd_t *
-srmmu_pgd_offset(struct mm_struct * mm, unsigned long address)
+static pgd_t *srmmu_pgd_offset(struct mm_struct * mm, unsigned long address)
 {
 	return mm->pgd + ((address >> SRMMU_PGDIR_SHIFT) & (SRMMU_PTRS_PER_PGD - 1));
 }
 
 /* Find an entry in the second-level page table.. */
-pmd_t *
-srmmu_pmd_offset(pgd_t * dir, unsigned long address)
+static pmd_t *srmmu_pmd_offset(pgd_t * dir, unsigned long address)
 {
-	return ((pmd_t *) pgd_page(*dir)) +
-		((address >> SRMMU_PMD_SHIFT) & (SRMMU_PTRS_PER_PMD - 1));
+	return (pmd_t *) pgd_page(*dir) + ((address >> SRMMU_PMD_SHIFT) & (SRMMU_PTRS_PER_PMD - 1));
 }
 
 /* Find an entry in the third-level page table.. */ 
-pte_t *
-srmmu_pte_offset(pmd_t * dir, unsigned long address)
+static pte_t *srmmu_pte_offset(pmd_t * dir, unsigned long address)
 {
-	return ((pte_t *) pmd_page(*dir)) +
-		((address >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1));
+	return (pte_t *) pmd_page(*dir) + ((address >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1));
 }
 
-/* This must update the context register for this process. */
-void
-srmmu_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdir) 
+/* This must update the context table entry for this process. */
+static void srmmu_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdp) 
 {
-	/* See if this process has a context entry already, like after execve() */
-	if(tsk->tss.context != -1) {
-		pgd_t *ctable_ptr = 0;
-		ctable_ptr = (pgd_t *) (srmmu_get_ctable_ptr() + PAGE_OFFSET);
-		ctable_ptr += tsk->tss.context;
-		srmmu_pgd_set(ctable_ptr, (pmd_t *) pgdir);
-		/* Should flush caches here too... */
-		srmmu_flush_whole_tlb();
-	}
-
-	tsk->tss.pgd_ptr = (unsigned long) pgdir;
-
-	return;
+	if(tsk->mm->context != NO_CONTEXT)
+		srmmu_ctxd_set(&srmmu_context_table[tsk->mm->context], pgdp);
 }
 
 /*
@@ -212,346 +233,705 @@
  * used to allocate a kernel page table - this turns on ASN bits
  * if any, and marks the page tables reserved.
  */
-void
-srmmu_pte_free_kernel(pte_t *pte)
+static void srmmu_pte_free_kernel(pte_t *pte)
 {
 	mem_map[MAP_NR(pte)].reserved = 0;
 	free_page((unsigned long) pte);
 }
 
-pte_t *
-srmmu_pte_alloc_kernel(pmd_t *pmd, unsigned long address)
+static pte_t *srmmu_pte_alloc_kernel(pmd_t *pmd, unsigned long address)
 {
-	pte_t *page;
-
 	address = (address >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1);
-	if (srmmu_pmd_none(*pmd)) {
-		page = (pte_t *) get_free_page(GFP_KERNEL);
-		if (srmmu_pmd_none(*pmd)) {
-			if (page) {
+	if(srmmu_pmd_none(*pmd)) {
+		pte_t *page = (pte_t *) get_free_page(GFP_KERNEL);
+		if(srmmu_pmd_none(*pmd)) {
+			if(page) {
 				srmmu_pmd_set(pmd, page);
 				mem_map[MAP_NR(page)].reserved = 1;
 				return page + address;
 			}
-			srmmu_pmd_set(pmd, (pte_t *) SRMMU_ET_PTDBAD);
+			srmmu_pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
 			return NULL;
 		}
 		free_page((unsigned long) page);
 	}
-	if (srmmu_pmd_bad(*pmd)) {
-		printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd));
-		srmmu_pmd_set(pmd, (pte_t *) SRMMU_ET_PTDBAD);
+	if(srmmu_pmd_bad(*pmd)) {
+		printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
+		srmmu_pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
 		return NULL;
 	}
 	return (pte_t *) srmmu_pmd_page(*pmd) + address;
 }
 
-/* Full three level on SRMMU */
-void
-srmmu_pmd_free_kernel(pmd_t *pmd)
+static void srmmu_pmd_free_kernel(pmd_t *pmd)
 {
 	mem_map[MAP_NR(pmd)].reserved = 0;
 	free_page((unsigned long) pmd);
 }
 
-pmd_t *
-srmmu_pmd_alloc_kernel(pgd_t *pgd, unsigned long address)
+static pmd_t *srmmu_pmd_alloc_kernel(pgd_t *pgd, unsigned long address)
 {
-	pmd_t *page;
-
 	address = (address >> SRMMU_PMD_SHIFT) & (SRMMU_PTRS_PER_PMD - 1);
-	if (srmmu_pgd_none(*pgd)) {
-		page = (pmd_t *) get_free_page(GFP_KERNEL);
-		if (srmmu_pgd_none(*pgd)) {
-			if (page) {
+	if(srmmu_pgd_none(*pgd)) {
+		pmd_t *page = (pmd_t *) get_free_page(GFP_KERNEL);
+		if(srmmu_pgd_none(*pgd)) {
+			if(page) {
 				srmmu_pgd_set(pgd, page);
 				mem_map[MAP_NR(page)].reserved = 1;
 				return page + address;
 			}
-			srmmu_pgd_set(pgd, (pmd_t *) SRMMU_ET_PTDBAD);
+			srmmu_pgd_set(pgd, (pmd_t *) BAD_PAGETABLE);
 			return NULL;
 		}
 		free_page((unsigned long) page);
 	}
-	if (srmmu_pgd_bad(*pgd)) {
-		printk("Bad pgd in pmd_alloc_kernel: %08lx\n", pgd_val(*pgd));
-		srmmu_pgd_set(pgd, (pmd_t *) SRMMU_ET_PTDBAD);
+	if(srmmu_pgd_bad(*pgd)) {
+		printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd));
+		srmmu_pgd_set(pgd, (pmd_t *) BAD_PAGETABLE);
 		return NULL;
 	}
-	return (pmd_t *) srmmu_pgd_page(*pgd) + address;
+	return (pmd_t *) pgd_page(*pgd) + address;
 }
 
-void
-srmmu_pte_free(pte_t *pte)
+static void srmmu_pte_free(pte_t *pte)
 {
 	free_page((unsigned long) pte);
 }
 
-pte_t *
-srmmu_pte_alloc(pmd_t * pmd, unsigned long address)
+static pte_t *srmmu_pte_alloc(pmd_t * pmd, unsigned long address)
 {
-	pte_t *page;
-
 	address = (address >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1);
-	if (srmmu_pmd_none(*pmd)) {
-		page = (pte_t *) get_free_page(GFP_KERNEL);
-		if (srmmu_pmd_none(*pmd)) {
-			if (page) {
+	if(srmmu_pmd_none(*pmd)) {
+		pte_t *page = (pte_t *) get_free_page(GFP_KERNEL);
+		if(srmmu_pmd_none(*pmd)) {
+			if(page) {
 				srmmu_pmd_set(pmd, page);
 				return page + address;
 			}
-			srmmu_pmd_set(pmd, (pte_t *) SRMMU_ET_PTDBAD);
+			srmmu_pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
 			return NULL;
 		}
 		free_page((unsigned long) page);
 	}
-	if (srmmu_pmd_bad(*pmd)) {
-		printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd));
-		srmmu_pmd_set(pmd, (pte_t *) SRMMU_ET_PTDBAD);
+	if(srmmu_pmd_bad(*pmd)) {
+		printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
+		srmmu_pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
 		return NULL;
 	}
-	return (pte_t *) srmmu_pmd_page(*pmd) + address;
+	return (pte_t *) pmd_page(*pmd) + address;
 }
 
-/*
- * allocating and freeing a pmd is trivial: the 1-entry pmd is
- * inside the pgd, so has no extra memory associated with it.
- */
-void 
-srmmu_pmd_free(pmd_t * pmd)
+/* Real three-level page tables on SRMMU. */
+static void srmmu_pmd_free(pmd_t * pmd)
 {
 	free_page((unsigned long) pmd);
 }
 
-pmd_t *
-srmmu_pmd_alloc(pgd_t * pgd, unsigned long address)
+static pmd_t *srmmu_pmd_alloc(pgd_t * pgd, unsigned long address)
 {
-	pmd_t *page;
-
 	address = (address >> SRMMU_PMD_SHIFT) & (SRMMU_PTRS_PER_PMD - 1);
-	if (srmmu_pgd_none(*pgd)) {
-		page = (pmd_t *) get_free_page(GFP_KERNEL);
-		if (srmmu_pgd_none(*pgd)) {
-			if (page) {
+	if(srmmu_pgd_none(*pgd)) {
+		pmd_t *page = (pmd_t *) get_free_page(GFP_KERNEL);
+		if(srmmu_pgd_none(*pgd)) {
+			if(page) {
 				srmmu_pgd_set(pgd, page);
 				return page + address;
 			}
-			srmmu_pgd_set(pgd, (pmd_t *) SRMMU_ET_PTDBAD);
+			srmmu_pgd_set(pgd, (pmd_t *) BAD_PAGETABLE);
 			return NULL;
 		}
 		free_page((unsigned long) page);
 	}
-	if (srmmu_pgd_bad(*pgd)) {
-		printk("Bad pgd in pmd_alloc_kernel: %08lx\n", pgd_val(*pgd));
-		srmmu_pgd_set(pgd, (pmd_t *) SRMMU_ET_PTDBAD);
+	if(srmmu_pgd_bad(*pgd)) {
+		printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd));
+		srmmu_pgd_set(pgd, (pmd_t *) BAD_PAGETABLE);
 		return NULL;
 	}
 	return (pmd_t *) srmmu_pgd_page(*pgd) + address;
 }
 
-void
-srmmu_pgd_free(pgd_t *pgd)
+static void srmmu_pgd_free(pgd_t *pgd)
 {
 	free_page((unsigned long) pgd);
 }
 
-/* A page directory on the srmmu needs 1k, but for now to simplify the
- * alignment constraints and allocation we just grab a whole page.
+static pgd_t *srmmu_pgd_alloc(void)
+{
+	return (pgd_t *) get_free_page(GFP_KERNEL);
+}
+
+/* Tsunami invalidates.  It's page level tlb invalidation is not very
+ * useful at all, you must be in the context that page exists in to
+ * get a match.  It might be worthwhile to try someday though...
  */
+/* static */ inline void tsunami_invalidate_all(void)
+{
+	tsunami_invalidate_icache();
+	tsunami_invalidate_dcache();
+	srmmu_flush_whole_tlb();
+}
+static void tsunami_invalidate_mm(struct mm_struct *mm)
+{
+	tsunami_invalidate_all();
+}
 
-pgd_t *
-srmmu_pgd_alloc(void)
+static void tsunami_invalidate_range(struct mm_struct *mm, unsigned long start, unsigned long end)
 {
-	return (pgd_t *) get_free_page(GFP_KERNEL);
+	tsunami_invalidate_all();
 }
 
-/* Just flush the whole thing for now. We will need module
- * specific invalidate routines in certain circumstances,
- * because of different flushing facilities and hardware
- * bugs.
+/* XXX do page level tlb flushes at some point XXX */
+static void tsunami_invalidate_page(struct vm_area_struct *vmp, unsigned long page)
+{
+	tsunami_invalidate_all();
+}
+
+/* Swift invalidates.  It has the recommended SRMMU specification flushing
+ * facilities, so we can do things in a more fine grained fashion than we
+ * could on the tsunami.  Let's watch out for HARDWARE BUGS...
  */
-void
-srmmu_invalidate(void)
+static inline void swift_invalidate_all(void)
 {
+	unsigned long addr = 0;
+
+	/* Invalidate all cache tags */
+	for(addr = 0; addr < (PAGE_SIZE << 2); addr += 16) {
+		swift_inv_insn_tag(addr); /* whiz- */
+		swift_inv_data_tag(addr); /* bang */
+	}
 	srmmu_flush_whole_tlb();
-	return;
 }
 
-/* XXX Needs to be written */
-void srmmu_set_pte(pte_t *ptep, pte_t pteval)
+static void swift_invalidate_mm(struct mm_struct *mm)
 {
-	/* More than this is needed. */
-	*ptep = pteval;
+	unsigned long flags;
+	int cc, ncc = mm->context;
+
+	if(ncc == NO_CONTEXT)
+		return;
+
+	/* have context will travel... */
+	save_flags(flags); cli();
+	cc = srmmu_get_context();
+	if(cc != ncc)
+		srmmu_set_context(ncc);
+
+	swift_flush_context(); /* POOF! */
+	srmmu_flush_tlb_ctx(); /* POW! */
+
+	if(cc != ncc)
+		srmmu_set_context(cc);
+	restore_flags(flags);
 }
 
-/* XXX Needs to be written */
-void
-srmmu_switch_to_context(void *vtask)
+static void swift_invalidate_range(struct mm_struct *mm, unsigned long start, unsigned long end)
 {
-	struct task_struct *tsk = vtask;
-	printk("switching to context %d\n", tsk->tss.context);
+	unsigned long flags, addr;
+	int cc, ncc = mm->context;
+
+	if(ncc == NO_CONTEXT)
+		return;
+
+	save_flags(flags); cli();
+	cc = srmmu_get_context();
+	if(cc != ncc)
+		srmmu_set_context(ncc);
 
-	return;
+	/* XXX Inefficient, we don't do the best we can... XXX */
+	addr = start & SRMMU_PGDIR_MASK;
+	while(addr < end) {
+		swift_flush_region(addr);
+		srmmu_flush_tlb_region(addr);
+		addr += SRMMU_PGDIR_SIZE;
+	}
+
+	if(cc != ncc)
+		srmmu_set_context(cc);
+	restore_flags(flags);
 }
 
-/* Low level IO area allocation on the SRMMU.
- *
- * I think we can get away with just using a regular page translation,
- * just making sure the cacheable bit is off.  I would like to avoid
- * having to mess with the IOMMU if at all possible at first.
+static void swift_invalidate_page(struct vm_area_struct *vmp, unsigned long page)
+{
+	unsigned long flags;
+	int cc, ncc = vmp->vm_mm->context;
+
+	if(ncc == NO_CONTEXT)
+		return;
+
+	save_flags(flags); cli();
+	cc = srmmu_get_context();
+	if(cc != ncc)
+		srmmu_set_context(ncc);
+
+	swift_flush_page(page);
+	srmmu_flush_tlb_page(page);
+
+	if(cc != ncc)
+		srmmu_set_context(cc);
+	restore_flags(flags);
+}
+
+/* The following are all MBUS based SRMMU modules, and therefore could
+ * be found in a multiprocessor configuration.
+ */
+
+/* Viking invalidates.  For Sun's mainline MBUS processor it is pretty much
+ * a crappy mmu.  The on-chip I&D caches only have full flushes, no fine
+ * grained cache invalidations.  It only has these "flash clear" things
+ * just like the MicroSparcI.  Added to this many revs of the chip are
+ * teaming with hardware buggery.
  *
- * Aparently IOMMU is only necessary for SBus devices, maybe VME too.
- * We'll see...
+ * XXX need to handle SMP broadcast invalidations! XXX
  */
-void
-srmmu_mapioaddr(unsigned long physaddr, unsigned long virt_addr,
-		int bus_type, int rdonly)
+static inline void viking_invalidate_all(void)
+{
+	viking_flush_icache();
+	viking_flush_dcache();
+	srmmu_flush_whole_tlb();
+}
+static void viking_invalidate_mm(struct mm_struct *mm)
 {
-  pgd_t *pgdp;
-  pmd_t *pmdp;
-  pte_t *ptep;
+	unsigned long flags;
+	int cc, ncc = mm->context;
 
-  pgdp = srmmu_pgd_offset(init_task.mm, virt_addr);
-  pmdp = srmmu_pmd_offset(pgdp, virt_addr);
-  ptep = srmmu_pte_offset(pmdp, virt_addr);
-  pte_val(*ptep) = (physaddr >> SRMMU_PTE_PPN_PADDR_SHIFT) & SRMMU_PTE_PPN_MASK;
+	if(ncc == NO_CONTEXT)
+		return;
 
-  if(!rdonly)
-	  pte_val(*ptep) |= (SRMMU_ACC_S_RDWREXEC | SRMMU_ET_PTE);
-  else
-	  pte_val(*ptep) |= (SRMMU_ACC_S_RDEXEC | SRMMU_ET_PTE);
+	save_flags(flags); cli();
+	cc = srmmu_get_context();
+	if(cc != ncc)
+		srmmu_set_context(ncc);
 
-  pte_val(*ptep) |= (bus_type << 28);
-  pte_val(*ptep) &= ~(SRMMU_PTE_C_MASK); /* Make sure cacheable bit is off. */
-  srmmu_flush_whole_tlb();
-  flush_ei_ctx(0x0);
+	viking_flush_icache();
+	viking_flush_dcache();
+	srmmu_flush_tlb_ctx();
 
-  return;
+	if(cc != ncc)
+		srmmu_set_context(cc);
+	restore_flags(flags);
 }
 
-char *srmmu_lockarea(char *vaddr, unsigned long len)
+static void viking_invalidate_range(struct mm_struct *mm, unsigned long start, unsigned long end)
 {
-	return vaddr;
+	unsigned long flags, addr;
+	int cc, ncc = mm->context;
+
+	if(ncc == NO_CONTEXT)
+		return;
+
+	save_flags(flags); cli();
+	cc = srmmu_get_context();
+	if(cc != ncc)
+		srmmu_set_context(ncc);
+
+	/* XXX Inefficient, we don't do the best we can... XXX */
+	viking_flush_icache();
+	viking_flush_dcache();
+	addr = start & SRMMU_PGDIR_MASK;
+	while(addr < end) {
+		srmmu_flush_tlb_region(addr);
+		addr += SRMMU_PGDIR_SIZE;
+	}
+
+	if(cc != ncc)
+		srmmu_set_context(cc);
+	restore_flags(flags);
+}
+static void viking_invalidate_page(struct vm_area_struct *vmp, unsigned long page)
+{
+	unsigned long flags;
+	int cc, ncc = vmp->vm_mm->context;
+
+	if(ncc == NO_CONTEXT)
+		return;
+
+	save_flags(flags); cli();
+	cc = srmmu_get_context();
+	if(cc != ncc)
+		srmmu_set_context(ncc);
+
+	viking_flush_icache();
+	viking_flush_dcache();
+	srmmu_flush_tlb_page(page);
+
+	if(cc != ncc)
+		srmmu_set_context(cc);
+	restore_flags(flags);
 }
 
-void srmmu_unlockarea(char *vaddr, unsigned long len)
+/* Cypress invalidates. */
+static inline void cypress_invalidate_all(void)
 {
+	srmmu_flush_whole_tlb();
 }
+static void cypress_invalidate_mm(struct mm_struct *mm)
+{
+	unsigned long flags;
+	int cc, ncc = mm->context;
 
-char *srmmu_get_scsi_buffer(char *vaddr, unsigned long len)
+	if(ncc == NO_CONTEXT)
+		return;
+
+	/* have context will travel... */
+	save_flags(flags); cli();
+	cc = srmmu_get_context();
+	if(cc != ncc)
+		srmmu_set_context(ncc);
+
+	cypress_flush_context(); /* POOF! */
+	srmmu_flush_whole_tlb(); /* POW! */
+
+	if(cc != ncc)
+		srmmu_set_context(cc);
+	restore_flags(flags);
+}
+static void cypress_invalidate_range(struct mm_struct *mm, unsigned long start, unsigned long end)
 {
-	panic("sun4m: get_scsi_buffer() not implemented yet.");
+	unsigned long flags, addr;
+	int cc, ncc = mm->context;
+
+	if(ncc == NO_CONTEXT)
+		return;
+
+	save_flags(flags); cli();
+	cc = srmmu_get_context();
+	if(cc != ncc)
+		srmmu_set_context(ncc);
+
+	/* XXX Inefficient, we don't do the best we can... XXX */
+	addr = start & SRMMU_PGDIR_MASK;
+	while(addr < end) {
+		cypress_flush_region(addr);
+		addr += SRMMU_PGDIR_SIZE;
+	}
+	srmmu_flush_whole_tlb();
+
+	if(cc != ncc)
+		srmmu_set_context(cc);
+	restore_flags(flags);
 }
 
-void srmmu_release_scsi_buffer(char *vaddr, unsigned long len)
+static void cypress_invalidate_page(struct vm_area_struct *vmp, unsigned long page)
 {
-	panic("sun4m: release_scsi_buffer() not implemented yet.");
+	unsigned long flags;
+	int cc, ncc = vmp->vm_mm->context;
+
+	if(ncc == NO_CONTEXT)
+		return;
+
+	save_flags(flags); cli();
+	cc = srmmu_get_context();
+	if(cc != ncc)
+		srmmu_set_context(ncc);
+
+	swift_flush_page(page);
+	srmmu_flush_whole_tlb();
+
+	if(cc != ncc)
+		srmmu_set_context(cc);
+	restore_flags(flags);
 }
 
-/* Perfom a some soft of MMU tablewalk.
- * Long contiguous mappings are not supported (yet ?).
- *
- * Origionally written by Peter Zaitcev, modified by David S.
- * Miller.  This is only used to copy over the PROM/KADB mappings
- * in srmmu_paging_init().
- *
- * The return value encodes at what level the entry was found,
- * basically this is found in the lower 2 bits of the return
- * value.  If the return value is zero, there was no valid mapping
- * found at all, the low bits for a non-zero return value
- * are:
- *         0 -- Level 1 PTE
- *         1 -- Level 2 PTE
- *         2 -- Normal level 3 PTE
- *         3 -- Context Table PTE (unlikely, but still)
- * 
- * Also note that this is called before the context table pointer
- * register is changed, so the PROMs entry is still in there.  Also,
- * it is safe to assume that the context 0 contains the mappings.
- */
-/* TODO chop out 'trace' when stable */
-unsigned int
-srmmu_init_twalk(unsigned virt, int trace)
-{
-	unsigned int wh, root;
-
-	root = (unsigned int) srmmu_get_ctable_ptr();
-	if(trace) printk(":0x%x >> ", virt);
-
-	if(trace) printk(" 0x%x :", root);
-	wh = ldw_sun4m_bypass(root);
-	if ((wh & SRMMU_PTE_ET_MASK) == SRMMU_ET_INVALID) {
-		if(trace) printk("\n");
-		return 0;
-	}
-	if((wh & SRMMU_PTE_ET_MASK) == SRMMU_ET_PTE) {
-		wh &= ~SRMMU_PTE_ET_MASK;
-		wh |= 0x3;
-		if(trace) printk("\n");
-		printk("AIEEE context table level pte prom mapping!\n");
-		prom_halt();
-		return 0;
-	}
-		
-	if(trace) printk(" 0x%x .", wh);
-	wh = ldw_sun4m_bypass(
-			      ((wh & SRMMU_PTD_PTP_MASK) << 4)
-			      + ((virt & SRMMU_IDX1_MASK) >> SRMMU_IDX1_SHIFT)*sizeof(pte_t));
+/* Hypersparc invalidates. */
+static inline void hypersparc_invalidate_all(void)
+{
 
-	if ((wh & SRMMU_PTE_ET_MASK) == SRMMU_ET_INVALID) {
-		if(trace) printk("\n");
-		return 0;
-	}
-	if((wh & SRMMU_PTE_ET_MASK) == SRMMU_ET_PTE) {
-		wh &= ~SRMMU_PTE_ET_MASK;
-		if(trace) printk("\n");
-		return wh;
+	hyper_flush_whole_icache();
+	srmmu_flush_whole_tlb();
+}
+
+static void hypersparc_invalidate_mm(struct mm_struct *mm)
+{
+
+}
+
+static void hypersparc_invalidate_range(struct mm_struct *mm, unsigned long start, unsigned long end)
+{
+
+}
+
+static void hypersparc_invalidate_page(struct vm_area_struct *vmp, unsigned long page)
+{
+
+}
+
+static void srmmu_set_pte(pte_t *ptep, pte_t pteval)
+{
+	srmmu_set_entry(ptep, pte_val(pteval));
+}
+
+static void srmmu_quick_kernel_fault(unsigned long address)
+{
+	printk("SRMMU: quick_kernel_fault called for %08lx\n", address);
+	panic("Srmmu bolixed...");
+}
+
+static inline void alloc_context(struct mm_struct *mm)
+{
+	struct ctx_list *ctxp;
+
+	ctxp = ctx_free.next;
+	if(ctxp != &ctx_free) {
+		remove_from_ctx_list(ctxp);
+		add_to_used_ctxlist(ctxp);
+		mm->context = ctxp->ctx_number;
+		ctxp->ctx_mm = mm;
+		return;
 	}
+	ctxp = ctx_used.next;
+	if(ctxp->ctx_mm == current->mm)
+		ctxp = ctxp->next;
+	if(ctxp == &ctx_used)
+		panic("out of mmu contexts");
+	remove_from_ctx_list(ctxp);
+	add_to_used_ctxlist(ctxp);
+	ctxp->ctx_mm->context = NO_CONTEXT;
+	ctxp->ctx_mm = mm;
+	mm->context = ctxp->ctx_number;
+}
 
-	if(trace) printk(" 0x%x .", wh);
-	wh = ldw_sun4m_bypass(
-			      ((wh & SRMMU_PTD_PTP_MASK) << 4)
-			      + ((virt & SRMMU_IDX2_MASK) >> SRMMU_IDX2_SHIFT)*sizeof(pte_t));
-	if ((wh & SRMMU_PTE_ET_MASK) == SRMMU_ET_INVALID) {
-		if(trace) printk("\n");
-		return 0;
+static void srmmu_switch_to_context(struct task_struct *tsk)
+{
+	/* Kernel threads can execute in any context and so can tasks
+	 * sleeping in the middle of exiting. If this task has already
+	 * been allocated a piece of the mmu realestate, just jump to
+	 * it.
+	 */
+	if((tsk->tss.flags & SPARC_FLAG_KTHREAD) ||
+	   (tsk->flags & PF_EXITING))
+		return;
+	if(tsk->mm->context == NO_CONTEXT) {
+		alloc_context(tsk->mm);
+		srmmu_ctxd_set(&srmmu_context_table[tsk->mm->context], tsk->mm->pgd);
 	}
-	if((wh & SRMMU_PTE_ET_MASK) == SRMMU_ET_PTE) {
-		wh &= ~SRMMU_PTE_ET_MASK;
-		wh |= 0x1;
-		if(trace) printk("\n");
-		return wh;
+	srmmu_set_context(tsk->mm->context);
+}
+
+/* Low level IO area allocation on the SRMMU. */
+void srmmu_mapioaddr(unsigned long physaddr, unsigned long virt_addr, int bus_type, int rdonly)
+{
+	pgd_t *pgdp;
+	pmd_t *pmdp;
+	pte_t *ptep;
+	unsigned long tmp;
+
+	physaddr &= PAGE_MASK;
+	pgdp = srmmu_pgd_offset(init_task.mm, virt_addr);
+	pmdp = srmmu_pmd_offset(pgdp, virt_addr);
+	ptep = srmmu_pte_offset(pmdp, virt_addr);
+	tmp = (physaddr >> 4) | SRMMU_ET_PTE;
+
+	/* I need to test whether this is consistant over all
+	 * sun4m's.  The bus_type represents the upper 4 bits of
+	 * 36-bit physical address on the I/O space lines...
+	 */
+	tmp |= (bus_type << 28);
+	if(rdonly)
+		tmp |= SRMMU_PRIV_RDONLY;
+	else
+		tmp |= SRMMU_PRIV;
+	srmmu_set_entry(ptep, tmp);
+	invalidate_all();
+}
+
+static char *srmmu_lockarea(char *vaddr, unsigned long len)
+{
+	return vaddr;
+}
+
+static void srmmu_unlockarea(char *vaddr, unsigned long len)
+{
+}
+
+/* IOMMU things go here. */
+
+#define LONG_ALIGN(x) (((x)+(sizeof(long))-1)&~((sizeof(long))-1))
+static unsigned long first_dvma_page, last_dvma_page;
+
+static inline void srmmu_map_dvma_pages_for_iommu(struct iommu_struct *iommu)
+{
+	unsigned long first = first_dvma_page;
+	unsigned long last = last_dvma_page;
+	iopte_t *iopte;
+
+	iopte = iommu->page_table;
+	iopte += ((DVMA_VADDR - iommu->start) >> PAGE_SHIFT);
+	while(first <= last) {
+		iopte_val(*iopte++) = ((((first - PAGE_OFFSET) >> 4) & IOPTE_PAGE) |
+				       (IOPTE_WRITE | IOPTE_VALID)) & ~(IOPTE_WAZ);
+		first += PAGE_SIZE;
 	}
+}
+
+void srmmu_uncache_iommu_page_table(unsigned long start, int size)
+{
+	pgd_t *pgdp;
+	pmd_t *pmdp;
+	pte_t *ptep;
+	unsigned long end = start + size;
+
+	while(start < end) {
+		pgdp = srmmu_pgd_offset(init_task.mm, start);
+		pmdp = srmmu_pmd_offset(pgdp, start);
+		ptep = srmmu_pte_offset(pmdp, start);
+		pte_val(*ptep) &= ~SRMMU_CACHE;
+		start += PAGE_SIZE;
+	}
+}
+
+unsigned long iommu_init(int iommund, unsigned long memory_start,
+			 unsigned long memory_end, struct linux_sbus *sbus)
+{
+	int impl, vers, ptsize;
+	unsigned long tmp;
+	struct iommu_struct *iommu;
+	struct linux_prom_registers iommu_promregs[PROMREG_MAX];
+
+	memory_start = LONG_ALIGN(memory_start);
+	iommu = (struct iommu_struct *) memory_start;
+	memory_start += sizeof(struct iommu_struct);
+	prom_getproperty(iommund, "reg", (void *) iommu_promregs, sizeof(iommu_promregs));
+	iommu->regs = (struct iommu_regs *)
+		sparc_alloc_io(iommu_promregs[0].phys_addr, 0, (PAGE_SIZE * 3),
+			       "IOMMU registers", iommu_promregs[0].which_io, 0x0);
+	if(!iommu->regs)
+		panic("Cannot map IOMMU registers.");
+	impl = (iommu->regs->control & IOMMU_CTRL_IMPL) >> 28;
+	vers = (iommu->regs->control & IOMMU_CTRL_VERS) >> 24;
+	tmp = iommu->regs->control;
+	tmp &= ~(IOMMU_CTRL_RNGE);
+	tmp |= (IOMMU_RNGE_64MB | IOMMU_CTRL_ENAB);
+	iommu->regs->control = tmp;
+	iommu_invalidate(iommu->regs);
+	iommu->start = 0xfc000000;
+	iommu->end = 0xffffffff;
+
+	/* Allocate IOMMU page table */
+	ptsize = iommu->end - iommu->start + 1;
+	ptsize = (ptsize >> PAGE_SHIFT) * sizeof(iopte_t);
+
+	/* Stupid alignment constraints give me a headache. */
+	memory_start = PAGE_ALIGN(memory_start);
+	memory_start = (((memory_start) + (ptsize - 1)) & ~(ptsize - 1));
+	iommu->page_table = (iopte_t *) memory_start;
+	memory_start += ptsize;
+
+	/* Initialize new table. */
+	memset(iommu->page_table, 0, ptsize);
+	srmmu_map_dvma_pages_for_iommu(iommu);
+	iommu->regs->base = (((unsigned long) iommu->page_table) - PAGE_OFFSET) >> 4;
+	srmmu_uncache_iommu_page_table((unsigned long) iommu->page_table, ptsize);
+	iommu_invalidate(iommu->regs);
+	invalidate_all();
+
+	sbus->iommu = iommu;
+	printk("IOMMU: impl %d vers %d page table at %p of size %d bytes\n",
+	       impl, vers, iommu->page_table, ptsize);
+	return memory_start;
+}
+
+
+static char *srmmu_get_scsi_buffer(char *vaddr, unsigned long len, struct linux_sbus *sbus)
+{
+	struct iommu_struct *iommu = sbus->iommu;
+	unsigned long page = (unsigned long) vaddr;
+	unsigned long start, end, offset;
+	iopte_t *iopte;
+
+	if(len > PAGE_SIZE)
+		panic("Can only handle page sized iommu mappings.");
+	offset = page & ~PAGE_MASK;
+	page &= PAGE_MASK;
+
+	start = iommu->start;
+	end = KADB_DEBUGGER_BEGVM; /* Don't step on kadb/prom. */
+	iopte = iommu->page_table;
+	while(start < end) {
+		if(!(iopte_val(*iopte) & IOPTE_VALID))
+			break;
+		iopte++;
+		start += PAGE_SIZE;
+	}
+	if(start == KADB_DEBUGGER_BEGVM)
+		panic("Could not find free iommu entry in get_scsi_buffer.");
+
+	vaddr = (char *) (start | offset);
+	iopte_val(*iopte) = ((((page - PAGE_OFFSET) >> 4) & IOPTE_PAGE) |
+		(IOPTE_WRITE | IOPTE_VALID)) & ~(IOPTE_WAZ);
+	iommu_invalidate(iommu->regs);
+	invalidate_all();
+
+	return vaddr;
+}
+
+static void srmmu_release_scsi_buffer(char *vaddr, unsigned long len, struct linux_sbus *sbus)
+{
+	struct iommu_struct *iommu = sbus->iommu;
+	unsigned long page = (unsigned long) vaddr;
+	iopte_t *iopte;
+
+	if(len > PAGE_SIZE)
+		panic("Can only handle page sized IOMMU mappings.");
+	page &= PAGE_MASK;
+	iopte = iommu->page_table + ((page - iommu->start) >> PAGE_SHIFT);
+	iopte_val(*iopte) = 0;
+	iommu_invalidate(iommu->regs);
+	invalidate_all();
+}
+
+/* On the SRMMU we do not have the problems with limited tlb entries
+ * for mapping kernel pages, so we just take things from the free page
+ * pool.  As a side effect we are putting a little too much pressure
+ * on the gfp() subsystem and we don't catch stack overflow like we
+ * did on the sun4c with virtual kstack mappings.  This setup also
+ * makes the logic of the iommu mapping code a lot easier as we can
+ * transparently handle mappings on the kernel stack without any
+ * special code as we did need on the sun4c.
+ */
+struct task_struct *srmmu_alloc_task_struct(void)
+{
+	unsigned long page;
+
+	page = get_free_page(GFP_KERNEL);
+	if(!page)
+		return (struct task_struct *) 0;
+	return (struct task_struct *) page;
+}
+
+unsigned long srmmu_alloc_kernel_stack(struct task_struct *tsk)
+{
+	unsigned long pages;
 
-	if(trace) printk(" 0x%x .", wh);
-	wh = ldw_sun4m_bypass(
-			      ((wh & SRMMU_PTD_PTP_MASK) << 4)
-			      + ((virt & SRMMU_IDX3_MASK) >> SRMMU_IDX3_SHIFT)*sizeof(pte_t));
-	if ((wh & SRMMU_PTE_ET_MASK) == SRMMU_ET_INVALID) {
-		if(trace) printk("\n");
+	pages = __get_free_pages(GFP_KERNEL, 1, ~0UL);
+	if(!pages)
 		return 0;
-	}
-	if(trace) printk(" 0x%x\n", wh);
-	return wh;
+	memset((void *) pages, 0, (PAGE_SIZE << 1));
+	return pages;
+}
+
+static void srmmu_free_task_struct(struct task_struct *tsk)
+{
+	free_page((unsigned long) tsk);
+}
+
+static void srmmu_free_kernel_stack(unsigned long stack)
+{
+	free_pages(stack, 1);
 }
 
+static unsigned long mempool;
 
 /* Allocate a block of RAM which is aligned to its size.
  * This procedure can be used until the call to mem_init().
- *
- * To get around the elf bootloader nastyness we have a
- * early-on page table pool allocation area starting at
- * C_LABEL(pg0) which is 256k, this should be enough for now.
  */
-static void *
-srmmu_init_alloc(unsigned long *kbrk, unsigned size)
+static void *srmmu_init_alloc(unsigned long *kbrk, unsigned size)
 {
 	register unsigned mask = size - 1;
 	register unsigned long ret;
 
 	if(size==0) return 0x0;
 	if(size & mask) {
-		printk("panic: srmmu_init_alloc botch\n");
+		prom_printf("panic: srmmu_init_alloc botch\n");
 		prom_halt();
 	}
 	ret = (*kbrk + mask) & ~mask;
@@ -560,228 +940,166 @@
 	return (void*) ret;
 }
 
-/* Get fault information on an SRMMU. */
-int
-srmmu_get_fault_info(unsigned long *address, unsigned long *error_code,
-		     unsigned long from_user)
+static inline void srmmu_allocate_ptable_skeleton(unsigned long start, unsigned long end)
 {
-	/* XXX Foo, write this... XXX */
-	return 0;
-}
-
-/* Paging initialization on the Sparc Reference MMU. */
-
-/* This is all poorly designed, we cannot assume any pages are valid
- * past _end until *after* this routine runs, thus we can't use the
- * start_mem mechanism during initialization...
- */
-static unsigned long mempool;
-
-/* The following is global because trap_init needs it to fire up
- * the other cpu's on multiprocessors.
- */
-pgd_t *lnx_root;      /* Pointer to the new root table */
-
-extern char start[];
-
-unsigned long
-srmmu_paging_init(unsigned long start_mem, unsigned long end_mem)
-{
-	unsigned long vaddr;  /* Virtual counter */
-	int i;
-
-	pte_t *ptep = 0;
-	pmd_t *pmdp = 0;
-	pgd_t *pgdp = 0;
-
-	mempool = start_mem;
-	lnx_root = srmmu_init_alloc(&mempool, num_contexts*sizeof(pgd_t));
-
-	memset(swapper_pg_dir, 0, PAGE_SIZE);
-
-	/* For every entry in the new Linux context table, put in
-	 * an entry which points to swapper_pg_dir .
-	 */
-	pmdp = (pmd_t *) swapper_pg_dir;
-	for(i = 0; i < num_contexts; i++)
-		srmmu_pgd_set(&lnx_root[i], pmdp);
+	pgd_t *pgdp;
+	pmd_t *pmdp;
+	pte_t *ptep;
 
-	/* Make Linux physical page tables. */
-	for(vaddr = KERNBASE; vaddr < end_mem; vaddr+=PAGE_SIZE) {
-		pgdp = srmmu_pgd_offset(init_task.mm, vaddr);
+	while(start < end) {
+		pgdp = srmmu_pgd_offset(init_task.mm, start);
 		if(srmmu_pgd_none(*pgdp)) {
-			pmdp = srmmu_init_alloc(&mempool,
-						SRMMU_PTRS_PER_PMD*sizeof(pmd_t));
+			pmdp = srmmu_init_alloc(&mempool, SRMMU_PMD_TABLE_SIZE);
 			srmmu_pgd_set(pgdp, pmdp);
 		}
-
-		pmdp = srmmu_pmd_offset(pgdp, vaddr);
+		pmdp = srmmu_pmd_offset(pgdp, start);
 		if(srmmu_pmd_none(*pmdp)) {
-			ptep = srmmu_init_alloc(&mempool,
-						SRMMU_PTRS_PER_PTE*sizeof(pte_t));
+			ptep = srmmu_init_alloc(&mempool, SRMMU_PTE_TABLE_SIZE);
 			srmmu_pmd_set(pmdp, ptep);
 		}
-
-		ptep = srmmu_pte_offset(pmdp, vaddr);
-		*ptep = srmmu_mk_pte(vaddr, SRMMU_PAGE_KERNEL);
+		start = (start + SRMMU_PMD_SIZE) & SRMMU_PMD_MASK;
 	}
+}
 
-	/* Map IO areas. */
-	for(vaddr = IOBASE_VADDR; vaddr < (IOBASE_VADDR+IOBASE_LEN);
-	    vaddr += SRMMU_PMD_SIZE) {
-		pgdp = srmmu_pgd_offset(init_task.mm, vaddr);
-		if(srmmu_pgd_none(*pgdp)) {
-			pmdp = srmmu_init_alloc(&mempool,
-						SRMMU_PTRS_PER_PMD*sizeof(pmd_t));
-			srmmu_pgd_set(pgdp, pmdp);
-		}
-		pmdp = srmmu_pmd_offset(pgdp, vaddr);
-		if(srmmu_pmd_none(*pmdp)) {
-			ptep = srmmu_init_alloc(&mempool,
-						SRMMU_PTRS_PER_PTE*sizeof(pte_t));
-			srmmu_pmd_set(pmdp, ptep);
+/* This is much cleaner than poking around physical address space
+ * looking at the prom's page table directly which is what most
+ * other OS's do.  Yuck... this is much better.
+ */
+static inline void srmmu_inherit_prom_mappings(void)
+{
+	pgd_t *pgdp;
+	pmd_t *pmdp;
+	pte_t *ptep;
+	unsigned long start, end;
+	unsigned long prompte;
+
+	start = KADB_DEBUGGER_BEGVM;
+	end = LINUX_OPPROM_ENDVM;
+	while(start < end) {
+		/* Something going wrong here on some ss5's... */
+		prompte = srmmu_hwprobe(start);
+
+		if((prompte & SRMMU_ET_MASK) == SRMMU_ET_PTE) {
+			pgdp = srmmu_pgd_offset(init_task.mm, start);
+			if(srmmu_pgd_none(*pgdp)) {
+				pmdp = srmmu_init_alloc(&mempool, SRMMU_PMD_TABLE_SIZE);
+				srmmu_pgd_set(pgdp, pmdp);
+			}
+			pmdp = srmmu_pmd_offset(pgdp, start);
+			if(srmmu_pmd_none(*pmdp)) {
+				ptep = srmmu_init_alloc(&mempool, SRMMU_PTE_TABLE_SIZE);
+				srmmu_pmd_set(pmdp, ptep);
+			}
+			ptep = srmmu_pte_offset(pmdp, start);
+			pte_val(*ptep) = prompte;
 		}
+		start += PAGE_SIZE;
 	}
+}
 
-	/* Map DVMA areas. */
-	for(vaddr = (DVMA_VADDR); vaddr < (DVMA_VADDR + DVMA_LEN);
-	    vaddr += PAGE_SIZE) {
-		pgdp = srmmu_pgd_offset(init_task.mm, vaddr);
-		if(srmmu_pgd_none(*pgdp)) {
-			pmdp = srmmu_init_alloc(&mempool,
-						SRMMU_PTRS_PER_PMD*sizeof(pmd_t));
-			srmmu_pgd_set(pgdp, pmdp);
-		}
-		pmdp = srmmu_pmd_offset(pgdp, vaddr);
-		if(srmmu_pmd_none(*pmdp)) {
-			ptep = srmmu_init_alloc(&mempool,
-						SRMMU_PTRS_PER_PTE*sizeof(pte_t));
-			srmmu_pmd_set(pmdp, ptep);
-		}
+static inline void srmmu_map_dvma_pages_for_cpu(unsigned long first, unsigned long last)
+{
+	unsigned long start;
+	pgprot_t dvma_prot;
+	pgd_t *pgdp;
+	pmd_t *pmdp;
+	pte_t *ptep;
 
-		ptep = srmmu_pte_offset(pmdp, vaddr);
-		*ptep = srmmu_mk_pte((unsigned int) srmmu_init_alloc(&mempool, PAGE_SIZE), SRMMU_PAGE_KERNEL);
-		pte_val(*ptep) &= ~(SRMMU_PTE_C_MASK);
+	start = DVMA_VADDR;
+	dvma_prot = __pgprot(SRMMU_ET_PTE | SRMMU_PRIV);
+	while(first <= last) {
+		pgdp = srmmu_pgd_offset(init_task.mm, start);
+		pmdp = srmmu_pmd_offset(pgdp, start);
+		ptep = srmmu_pte_offset(pmdp, start);
+
+		/* Map with cacheable bit clear. */
+		srmmu_set_entry(ptep, pte_val(srmmu_mk_pte(first, dvma_prot)));
+
+		first += PAGE_SIZE;
+		start += PAGE_SIZE;
 	}
-	srmmu_flush_whole_tlb();
-	flush_ei_ctx(0x0);
+}
+
+static void srmmu_map_kernel(unsigned long start, unsigned long end)
+{
+	pgd_t *pgdp;
+	pmd_t *pmdp;
+	pte_t *ptep;
 
-	/* Map in the PERCPU areas in virtual address space. */
-#if 0
-	prom_printf("PERCPU_VADDR + PERCPU_LEN = %08lx\n",
-		    (PERCPU_VADDR + PERCPU_LEN));
-#endif
-	for(vaddr = PERCPU_VADDR; vaddr < (PERCPU_VADDR + PERCPU_LEN);
-	    vaddr += PERCPU_ENTSIZE) {
-		pgdp = srmmu_pgd_offset(init_task.mm, vaddr);
+	end = (PAGE_ALIGN(end) + PAGE_SIZE);
+	while(start < end) {
+		pgdp = srmmu_pgd_offset(init_task.mm, start);
 		if(srmmu_pgd_none(*pgdp)) {
-			pmdp = srmmu_init_alloc(&mempool,
-						SRMMU_PTRS_PER_PMD*sizeof(pmd_t));
+			pmdp = srmmu_init_alloc(&mempool, SRMMU_PMD_TABLE_SIZE);
 			srmmu_pgd_set(pgdp, pmdp);
 		}
-		pmdp = srmmu_pmd_offset(pgdp, vaddr);
+		pmdp = srmmu_pmd_offset(pgdp, start);
 		if(srmmu_pmd_none(*pmdp)) {
-			ptep = srmmu_init_alloc(&mempool,
-						SRMMU_PTRS_PER_PTE*sizeof(pte_t));
+			ptep = srmmu_init_alloc(&mempool, SRMMU_PTE_TABLE_SIZE);
 			srmmu_pmd_set(pmdp, ptep);
 		}
-		ptep = srmmu_pte_offset(pmdp, vaddr);
-		/* Per-cpu trap table page. */
-		*ptep++ = srmmu_mk_pte((unsigned int) start, SRMMU_PAGE_KERNEL);
-		/* Per-cpu kernel stack page. */
-		*ptep++ = srmmu_mk_pte((unsigned int) srmmu_init_alloc(&mempool, PAGE_SIZE),
-				       SRMMU_PAGE_KERNEL);
-		/* Per-cpu Prom MBox. */
-		*ptep++ = srmmu_mk_pte((unsigned int) srmmu_init_alloc(&mempool, PAGE_SIZE),
-				       SRMMU_PAGE_KERNEL);
-		/* Per-cpu state variables. */
-		*ptep = srmmu_mk_pte((unsigned int) srmmu_init_alloc(&mempool, PAGE_SIZE),
-				     SRMMU_PAGE_KERNEL);
-	}
-	percpu_table = (struct sparc_percpu *) PERCPU_VADDR;
-
-	/* Ugh, have to map DVMA that the prom has mapped too or else
-	 * you will lose with video cards when we take over the ctx table.
-	 * Also, must take into consideration that prom might be using level
-	 * two or one PTE's. TODO
-	 *
-	 * XXX This still isn't right, the cg* graphics cards get their
-	 * XXX mapped screens all fucked up when I jump onto Linux's
-	 * XXX page tables.  Must investigate...
-	 */
-	for(vaddr = KADB_DEBUGGER_BEGVM; vaddr != 0x0;) {
-		unsigned int prom_pte;
-
-		prom_pte = srmmu_init_twalk(vaddr, 0);
+		ptep = srmmu_pte_offset(pmdp, start);
+		*ptep = srmmu_mk_pte(start, SRMMU_PAGE_KERNEL);
+		start += PAGE_SIZE;
+	}
+}
 
-		if(prom_pte) {
-			pgdp = srmmu_pgd_offset(init_task.mm, vaddr);
-			if((prom_pte&0x3) == 0x0) {
-				prom_pte &= ~0x3;
-				prom_pte |= SRMMU_ET_PTE;
-				pgd_val(*pgdp) = prom_pte;
-				vaddr = SRMMU_PGDIR_ALIGN(vaddr+1);
-				continue;
-			}
-			if(srmmu_pgd_none(*pgdp)) {
-				pmdp = srmmu_init_alloc(&mempool,
-							SRMMU_PTRS_PER_PMD*sizeof(pmd_t));
-				srmmu_pgd_set(pgdp, pmdp);
-			}
+/* Paging initialization on the Sparc Reference MMU. */
+extern unsigned long free_area_init(unsigned long, unsigned long);
+extern unsigned long sparc_context_init(unsigned long, int);
 
-			pmdp = srmmu_pmd_offset(pgdp, vaddr);
-			if((prom_pte&0x3) == 0x1) {
-				prom_pte &= ~0x3;
-				prom_pte |= SRMMU_ET_PTE;
-				pgd_val(*pgdp) = prom_pte;
-				vaddr = SRMMU_PMD_ALIGN(vaddr+1);
-				continue;
-			}
-			if(srmmu_pmd_none(*pmdp)) {
-				ptep = srmmu_init_alloc(&mempool,
-							SRMMU_PTRS_PER_PTE*sizeof(pte_t));
-				srmmu_pmd_set(pmdp, ptep);
-			}
-			/* A normal 3rd level PTE, no need to change ET bits. */
-			ptep = srmmu_pte_offset(pmdp, vaddr);
-			pte_val(*ptep) = prom_pte;
+unsigned long srmmu_paging_init(unsigned long start_mem, unsigned long end_mem)
+{
+	int i, cpunode;
+	char node_str[128];
 
+	/* Find the number of contexts on the srmmu. */
+	cpunode = prom_getchild(prom_root_node);
+	num_contexts = 0;
+	while((cpunode = prom_getsibling(cpunode)) != 0) {
+		prom_getstring(cpunode, "device_type", node_str, sizeof(node_str));
+		if(!strcmp(node_str, "cpu")) {
+			num_contexts = prom_getintdefault(cpunode, "mmu-nctx", 0x8);
+			break;
 		}
-		vaddr += PAGE_SIZE;
 	}
+	if(!num_contexts) {
+		prom_printf("Something wrong, cant find cpu node in paging_init.\n");
+		prom_halt();
+	}
+		
+	prom_printf("Number of MMU contexts %d\n", num_contexts);
+	mempool = start_mem;
+	memset(swapper_pg_dir, 0, PAGE_SIZE);
+	srmmu_map_kernel(KERNBASE, end_mem);
+	srmmu_allocate_ptable_skeleton(IOBASE_VADDR, IOBASE_END);
+	srmmu_allocate_ptable_skeleton(DVMA_VADDR, DVMA_END);
+	mempool = PAGE_ALIGN(mempool);
+	first_dvma_page = mempool;
+	last_dvma_page = (mempool + (DVMA_LEN) - PAGE_SIZE);
+	mempool = last_dvma_page + PAGE_SIZE;
+	srmmu_map_dvma_pages_for_cpu(first_dvma_page, last_dvma_page);
 
-	/* I believe I do not need to flush VAC here since my stores  */
-        /* probably already reached the physical RAM.             --P3 */
-
-	/* We probably do, and should do it just to be safe... -Davem */
+	srmmu_inherit_prom_mappings();
+	srmmu_context_table = srmmu_init_alloc(&mempool, num_contexts*sizeof(ctxd_t));
+	for(i = 0; i < num_contexts; i++)
+		srmmu_ctxd_set(&srmmu_context_table[i], swapper_pg_dir);
 
-	/* Take the MMU over from the PROM */
 	prom_printf("Taking over MMU from PROM.\n");
-
-	srmmu_set_ctable_ptr(((unsigned)lnx_root) - PAGE_OFFSET);
-
+	srmmu_flush_whole_tlb();
+	srmmu_set_ctable_ptr(((unsigned)srmmu_context_table) - PAGE_OFFSET);
 	srmmu_flush_whole_tlb();
 
-	/* Now it is ok to use memory at start_mem. */
 	start_mem = PAGE_ALIGN(mempool);
+	start_mem = sparc_context_init(start_mem, num_contexts);
 	start_mem = free_area_init(start_mem, end_mem);
-	start_mem = PAGE_ALIGN(start_mem);
-
-#if 0
-	prom_printf("Testing context switches...\n");
-	for(i=0; i<num_contexts; i++)
-		srmmu_set_context(i);
-	prom_printf("done...\n");
-	srmmu_set_context(0);
-#endif
 
 	prom_printf("survived...\n");
-	return start_mem;
+	return PAGE_ALIGN(start_mem);
 }
 
 /* Test the WP bit on the Sparc Reference MMU. */
-void
-srmmu_test_wp(void)
+void srmmu_test_wp(void)
 {
 	pgd_t *pgdp;
 	
@@ -798,50 +1116,350 @@
 
 	pgdp = srmmu_pgd_offset(init_task.mm, 0x0);
 	pgd_val(*pgdp) = 0x0;
+}
 
-	return;
+static char *srmmu_mmu_info(void)
+{
+	return "";
+}
+
+static void srmmu_update_mmu_cache(struct vm_area_struct * vma, unsigned long address, pte_t pte)
+{
+}
+
+static void srmmu_exit_hook(void)
+{
+	struct ctx_list *ctx_old;
+	struct mm_struct *mm = current->mm;
+
+	if(mm->context != NO_CONTEXT) {
+		srmmu_ctxd_set(&srmmu_context_table[mm->context], swapper_pg_dir);
+		ctx_old = ctx_list_pool + mm->context;
+		remove_from_ctx_list(ctx_old);
+		add_to_free_ctxlist(ctx_old);
+		mm->context = NO_CONTEXT;
+	}
 }
 
-void srmmu_update_mmu_cache(struct vm_area_struct * vma,
-			    unsigned long address, pte_t pte)
+static void
+srmmu_flush_hook(void)
 {
-	printk("WHOOPS, update_mmu_cache called on a SRMMU!\n");
-	panic("SRMMU bolixed...");
+	if(current->tss.flags & SPARC_FLAG_KTHREAD) {
+		alloc_context(current->mm);
+		srmmu_ctxd_set(&srmmu_context_table[current->mm->context], current->mm->pgd);
+		srmmu_set_context(current->mm->context);
+	}
 }
 
-void
-srmmu_fork_hook(void *vtask, unsigned long kthread_usp)
+/* Init various srmmu chip types. */
+void srmmu_is_bad(void)
 {
-	return; /* XXX */
+	prom_printf("Could not determine SRMMU chip type.\n");
+	prom_halt();
 }
 
-void
-srmmu_exit_hook(void *vtask)
+void init_hypersparc(void)
 {
-	return; /* XXX */
+	unsigned long mreg = srmmu_get_mmureg();
+
+	prom_printf("HyperSparc MMU detected.\n");
+	if(mreg & HYPERSPARC_CSIZE)
+		hyper_cache_size = (256 * 1024);
+	else
+		hyper_cache_size = (128 * 1024);
+
+	srmmu_modtype = HyperSparc;
+	hwbug_bitmask |= HWBUG_VACFLUSH_BITROT;
+
+	hyper_flush_whole_icache();
+	hyper_flush_all_combined();
+
+	/* Keep things sane for now, cache in write-through mode. */
+	mreg &= ~(HYPERSPARC_CWENABLE | HYPERSPARC_CMODE | HYPERSPARC_WBENABLE);
+	mreg |= HYPERSPARC_CENABLE;
+	srmmu_set_mmureg(mreg);
+	put_ross_icr(get_ross_icr() | 0x3);
+	invalidate_all = hypersparc_invalidate_all;
+	invalidate_mm = hypersparc_invalidate_mm;
+	invalidate_page = hypersparc_invalidate_page;
+	invalidate_range = hypersparc_invalidate_range;
 }
 
-void
-srmmu_release_hook(void *vtask)
+void init_cypress_common(void)
 {
-	return; /* XXX */
+	unsigned long mreg = srmmu_get_mmureg();
+
+	mreg &= ~CYPRESS_CMODE;
+	mreg |= CYPRESS_CENABLE;
+	srmmu_set_mmureg(mreg);
+	invalidate_all = cypress_invalidate_all;
+	invalidate_mm = cypress_invalidate_mm;
+	invalidate_page = cypress_invalidate_page;
+	invalidate_range = cypress_invalidate_range;
 }
 
-void
-srmmu_flush_hook(void *vtask)
+void init_cypress_604(void)
 {
-	return; /* XXX */
+	prom_printf("Cypress 604(UP) MMU detected.\n");
+	srmmu_modtype = Cypress;
+	init_cypress_common();
 }
 
-void
-srmmu_task_cacheflush(void *vtask)
+void init_cypress_605(unsigned long mrev)
 {
-	return; /* XXX */
+	prom_printf("Cypress 605(MP) MMU detected.\n");
+	if(mrev == 0xe) {
+		srmmu_modtype = Cypress_vE;
+		hwbug_bitmask |= HWBUG_COPYBACK_BROKEN;
+	} else {
+		if(mrev == 0xd) {
+			srmmu_modtype = Cypress_vD;
+			hwbug_bitmask |= HWBUG_ASIFLUSH_BROKEN;
+		} else {
+			srmmu_modtype = Cypress;
+		}
+	}
+	init_cypress_common();
+}
+
+#define SWIFT_REVISION_ADDR  0x10003000
+void init_swift(void)
+{
+	unsigned long swift_rev, addr;
+	unsigned long mreg = srmmu_get_mmureg();
+
+	prom_printf("Swift MMU detected.\n");
+	__asm__ __volatile__("lda [%1] %2, %0\n\t"
+			     "srl %0, 0x18, %0\n\t" :
+			     "=r" (swift_rev) :
+			     "r" (SWIFT_REVISION_ADDR), "i" (0x20));
+	switch(swift_rev) {
+	case 0x11:
+	case 0x20:
+	case 0x23:
+	case 0x30:
+		srmmu_modtype = Swift_lots_o_bugs;
+		hwbug_bitmask |= (HWBUG_KERN_ACCBROKEN | HWBUG_KERN_CBITBROKEN);
+		/* Gee george, I wonder why Sun is so hush hush about
+		 * this hardware bug... really braindamage stuff going
+		 * on here.  However I think we can find a way to avoid
+		 * all of the workaround overhead under Linux.  Basically,
+		 * any page fault can cause kernel pages to become user
+		 * accessible (the mmu gets confused and clears some of
+		 * the ACC bits in kernel ptes).  Aha, sounds pretty
+		 * horrible eh?  But wait, after extensive testing it appears
+		 * that if you use pgd_t level large kernel pte's (like the
+		 * 4MB pages on the Pentium) the bug does not get tripped
+		 * at all.  This avoids almost all of the major overhead.
+		 * Welcome to a world where your vendor tells you to,
+		 * "apply this kernel patch" instead of "sorry for the
+		 * broken hardware, send it back and we'll give you
+		 * properly functioning parts"
+		 */
+		break;
+	case 0x25:
+	case 0x31:
+		srmmu_modtype = Swift_bad_c;
+		hwbug_bitmask |= HWBUG_KERN_CBITBROKEN;
+		/* You see Sun allude to this hardware bug but never
+		 * admit things directly, they'll say things like,
+		 * "the Swift chip cache problems" or similar.
+		 */
+		break;
+	default:
+		srmmu_modtype = Swift_ok;
+		break;
+	};
+	/* Clear any crap from the cache or else... */
+	for(addr = 0; addr < (PAGE_SIZE * 4); addr += 16) {
+		swift_inv_insn_tag(addr); /* whiz- */
+		swift_inv_data_tag(addr); /* bang */
+	}
+	mreg |= (SWIFT_IE | SWIFT_DE); /* I & D caches on */
+
+	/* The Swift branch folding logic is completely broken.  At
+	 * trap time, if things are just right, if can mistakedly
+	 * thing that a trap is coming from kernel mode when in fact
+	 * it is coming from user mode (it misexecutes the branch in
+	 * the trap code).  So you see things like crashme completely
+	 * hosing your machine which is completely unacceptable.  Turn
+	 * this crap off... nice job Fujitsu.
+	 */
+	mreg &= ~(SWIFT_BF);
+	srmmu_set_mmureg(mreg);
+
+	invalidate_all = swift_invalidate_all;
+	invalidate_mm = swift_invalidate_mm;
+	invalidate_page = swift_invalidate_page;
+	invalidate_range = swift_invalidate_range;
+
+	/* Are you now convinced that the Swift is one of the
+	 * biggest VLSI abortions of all time?  Bravo Fujitsu!
+	 */
+}
+
+void init_tsunami(unsigned long mreg)
+{
+	/* Tsunami's pretty sane, Sun and TI actually got it
+	 * somewhat right this time.  Fujitsu should have
+	 * taken some lessons from them.
+	 */
+
+	prom_printf("Tsunami MMU detected.\n");
+	srmmu_modtype = Tsunami;
+	tsunami_invalidate_icache();
+	tsunami_invalidate_dcache();
+	mreg &= ~TSUNAMI_ITD;
+	mreg |= (TSUNAMI_IENAB | TSUNAMI_DENAB);
+	srmmu_set_mmureg(mreg);
+	invalidate_all = tsunami_invalidate_all;
+	invalidate_mm = tsunami_invalidate_mm;
+	invalidate_page = tsunami_invalidate_page;
+	invalidate_range = tsunami_invalidate_range;
+}
+
+void init_viking(unsigned long psr_vers, unsigned long mod_rev)
+{
+	unsigned long mreg = srmmu_get_mmureg();
+
+	/* Ahhh, the viking.  SRMMU VLSI abortion number two... */
+
+	prom_printf("Viking MMU detected.\n");
+	if(!psr_vers && ! mod_rev) {
+		srmmu_modtype = Viking_12;
+		hwbug_bitmask |= (HWBUG_MODIFIED_BITROT | HWBUG_PC_BADFAULT_ADDR);
+
+		/* On a fault, the chip gets entirely confused.  It will
+		 * do one of two things.  Either it will set the modified
+		 * bit for a read-only page (!!!) or it will improperly
+		 * report a fault when a dcti/loadstore sequence is the
+		 * last two instructions on a page.  Oh baby...
+		 */
+	} else {
+		if(psr_vers) {
+			srmmu_modtype = Viking_2x;
+			hwbug_bitmask |= HWBUG_PC_BADFAULT_ADDR; /* see above */
+		} else {
+			if(mod_rev == 1) {
+				srmmu_modtype = Viking_30;
+				hwbug_bitmask |= HWBUG_PACINIT_BITROT;
+
+				/* At boot time the physical cache
+				 * has cherry bombs in it, so you
+				 * have to scrape it by hand before
+				 * enabling it.  Nice CAD tools guys.
+				 */
+			} else {
+				if(mod_rev < 8)
+					srmmu_modtype = Viking_35;
+				else
+					srmmu_modtype = Viking_new;
+			}
+		}
+	}
+	/* XXX Dave, play with the MXCC you pinhead XXX */
+	viking_flush_icache();
+	viking_flush_dcache();
+	mreg |= (VIKING_DCENABLE | VIKING_ICENABLE | VIKING_SBENABLE |
+		 VIKING_TCENABLE | VIKING_DPENABLE);
+	srmmu_set_mmureg(mreg);
+	invalidate_all = viking_invalidate_all;
+	invalidate_mm = viking_invalidate_mm;
+	invalidate_page = viking_invalidate_page;
+	invalidate_range = viking_invalidate_range;
+}
+
+/* Probe for the srmmu chip version. */
+static void get_srmmu_type(void)
+{
+	unsigned long mreg, psr;
+	unsigned long mod_typ, mod_rev, psr_typ, psr_vers;
+
+	srmmu_modtype = SRMMU_INVAL_MOD;
+	hwbug_bitmask = 0;
+
+	mreg = srmmu_get_mmureg(); psr = get_psr();
+	mod_typ = (mreg & 0xf0000000) >> 28;
+	mod_rev = (mreg & 0x0f000000) >> 24;
+	psr_typ = (psr >> 28) & 0xf;
+	psr_vers = (psr >> 24) & 0xf;
+
+	/* First, check for HyperSparc or Cypress. */
+	if(mod_typ == 1) {
+		switch(mod_rev) {
+		case 7:
+			/* UP or MP Hypersparc */
+			init_hypersparc();
+			break;
+		case 0:
+			/* Uniprocessor Cypress */
+			init_cypress_604();
+			break;
+		case 13:
+		case 14:
+		case 15:
+			/* MP Cypress mmu/cache-controller */
+			init_cypress_605(mod_rev);
+			break;
+		default:
+			srmmu_is_bad();
+			break;
+		};
+		return;
+	}
+
+	/* Next check for Fujitsu Swift. */
+	if(psr_typ == 0 && psr_vers == 4) {
+		init_swift();
+		return;
+	}
+
+	/* Now the Viking family of srmmu. */
+	if(psr_typ == 4 &&
+	   ((psr_vers == 0) ||
+	    ((psr_vers == 1) && (mod_typ == 0) && (mod_rev == 0)))) {
+		init_viking(psr_vers, mod_rev);
+		return;
+	}
+
+	/* Finally the Tsunami. */
+	if(psr_typ == 4 && psr_vers == 1 && (mod_typ || mod_rev)) {
+		init_tsunami(mreg);
+		return;
+	}
+
+	/* Oh well */
+	srmmu_is_bad();
+}
+
+extern unsigned long spwin_mmu_patchme, fwin_mmu_patchme,
+	tsetup_mmu_patchme, rtrap_mmu_patchme;
+
+extern unsigned long spwin_srmmu_stackchk, srmmu_fwin_stackchk,
+	tsetup_srmmu_stackchk, srmmu_rett_stackchk;
+
+extern unsigned long srmmu_fault;
+
+#define PATCH_BRANCH(insn, dest) do { \
+		iaddr = &(insn); \
+		daddr = &(dest); \
+		*iaddr = SPARC_BRANCH((unsigned long) daddr, (unsigned long) iaddr); \
+        } while(0);
+
+static void patch_window_trap_handlers(void)
+{
+	unsigned long *iaddr, *daddr;
+	
+	PATCH_BRANCH(spwin_mmu_patchme, spwin_srmmu_stackchk);
+	PATCH_BRANCH(fwin_mmu_patchme, srmmu_fwin_stackchk);
+	PATCH_BRANCH(tsetup_mmu_patchme, tsetup_srmmu_stackchk);
+	PATCH_BRANCH(rtrap_mmu_patchme, srmmu_rett_stackchk);
+	PATCH_BRANCH(sparc_ttable[SP_TRAP_TFLT].inst_three, srmmu_fault);
+	PATCH_BRANCH(sparc_ttable[SP_TRAP_DFLT].inst_three, srmmu_fault);
 }
 
 /* Load up routines and constants for sun4m mmu */
-void
-ld_mmu_srmmu(void)
+void ld_mmu_srmmu(void)
 {
 	prom_printf("Loading srmmu MMU routines\n");
 
@@ -860,12 +1478,11 @@
 	page_none = SRMMU_PAGE_NONE;
 	page_shared = SRMMU_PAGE_SHARED;
 	page_copy = SRMMU_PAGE_COPY;
-	page_readonly = SRMMU_PAGE_READONLY;
+	page_readonly = SRMMU_PAGE_RDONLY;
 	page_kernel = SRMMU_PAGE_KERNEL;
-	page_invalid = SRMMU_PAGE_INVALID;
-	
+	pg_iobits = SRMMU_VALID | SRMMU_WRITE | SRMMU_REF;
+	    
 	/* Functions */
-	invalidate = srmmu_invalidate;
 	set_pte = srmmu_set_pte;
 	switch_to_context = srmmu_switch_to_context;
 	pmd_align = srmmu_pmd_align;
@@ -900,6 +1517,7 @@
 
 	mk_pte = srmmu_mk_pte;
 	pgd_set = srmmu_pgd_set;
+	mk_pte_io = srmmu_mk_pte_io;
 	pte_modify = srmmu_pte_modify;
 	pgd_offset = srmmu_pgd_offset;
 	pmd_offset = srmmu_pmd_offset;
@@ -915,33 +1533,39 @@
 	pgd_free = srmmu_pgd_free;
 	pgd_alloc = srmmu_pgd_alloc;
 
-	pte_read = srmmu_pte_read;
 	pte_write = srmmu_pte_write;
-	pte_exec = srmmu_pte_exec;
 	pte_dirty = srmmu_pte_dirty;
 	pte_young = srmmu_pte_young;
-	pte_cow = srmmu_pte_cow;
 	pte_wrprotect = srmmu_pte_wrprotect;
-	pte_rdprotect = srmmu_pte_rdprotect;
-	pte_exprotect = srmmu_pte_exprotect;
 	pte_mkclean = srmmu_pte_mkclean;
 	pte_mkold = srmmu_pte_mkold;
-	pte_uncow = srmmu_pte_uncow;
 	pte_mkwrite = srmmu_pte_mkwrite;
-	pte_mkread = srmmu_pte_mkread;
-	pte_mkexec = srmmu_pte_mkexec;
 	pte_mkdirty = srmmu_pte_mkdirty;
 	pte_mkyoung = srmmu_pte_mkyoung;
-	pte_mkcow = srmmu_pte_mkcow;
-	get_fault_info = srmmu_get_fault_info;
 	update_mmu_cache = srmmu_update_mmu_cache;
 	mmu_exit_hook = srmmu_exit_hook;
-	mmu_fork_hook = srmmu_fork_hook;
-	mmu_release_hook = srmmu_release_hook;
 	mmu_flush_hook = srmmu_flush_hook;
-	mmu_task_cacheflush = srmmu_task_cacheflush;
 	mmu_lockarea = srmmu_lockarea;
 	mmu_unlockarea = srmmu_unlockarea;
 	mmu_get_scsi_buffer = srmmu_get_scsi_buffer;
 	mmu_release_scsi_buffer = srmmu_release_scsi_buffer;
+	mmu_info = srmmu_mmu_info;
+
+	/* Task struct and kernel stack allocating/freeing. */
+	alloc_kernel_stack = srmmu_alloc_kernel_stack;
+	alloc_task_struct = srmmu_alloc_task_struct;
+	free_kernel_stack = srmmu_free_kernel_stack;
+	free_task_struct = srmmu_free_task_struct;
+
+	quick_kernel_fault = srmmu_quick_kernel_fault;
+
+	get_srmmu_type();
+	if(!(srmmu_get_mmureg() & 0x800)) {
+		srmmu_read_physical = msparc_read_physical;
+		srmmu_write_physical = msparc_write_physical;
+	} else {
+		srmmu_read_physical = gensrmmu_read_physical;
+		srmmu_write_physical = gensrmmu_write_physical;
+	}
+	patch_window_trap_handlers();
 }
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/mm/sun4c.c linux/arch/sparc/mm/sun4c.c
--- v1.3.70/linux/arch/sparc/mm/sun4c.c	Mon Nov 27 12:48:27 1995
+++ linux/arch/sparc/mm/sun4c.c	Mon Mar  4 08:49:58 1996
@@ -1,384 +1,1222 @@
-/* $Id: sun4c.c,v 1.56 1995/11/25 00:59:39 davem Exp $
- * sun4c.c:  Sun4C specific mm routines.
+/* sun4c.c: Doing in software what should be done in hardware.
  *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-
-/* The SUN4C has an MMU based upon a Translation Lookaside Buffer scheme
- * where only so many translations can be loaded at once.  As Linus said
- * in Boston, this is a broken way of doing things.
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
  */
 
 #include <linux/kernel.h>
-#include <linux/sched.h>
+#include <linux/mm.h>
 
-#include <asm/processor.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
-#include <asm/vac-ops.h>
 #include <asm/vaddrs.h>
-#include <asm/asi.h>
-#include <asm/system.h>
-#include <asm/contregs.h>
-#include <asm/oplib.h>
 #include <asm/idprom.h>
 #include <asm/machines.h>
 #include <asm/memreg.h>
-#include <asm/kdebug.h>
+#include <asm/processor.h>
 
-/* Pseg allocation structures. */
-static struct pseg_list s4cpseg_pool[256];
+extern int num_segmaps, num_contexts;
 
-struct pseg_list s4cpseg_free;
-struct pseg_list s4cpseg_used;
-static struct pseg_list s4cpseg_locked;
-static struct pseg_list s4cpseg_per_context[16];
+/* Flushing the cache. */
+struct sun4c_vac_props sun4c_vacinfo;
+static int ctxflushes, segflushes, pageflushes;
 
-static unsigned char pseg_count_per_context[16];
+/* Invalidate every sun4c cache line tag. */
+void sun4c_flush_all(void)
+{
+	unsigned long begin, end;
 
-unsigned int sun4c_pmd_align(unsigned int addr) { return SUN4C_PMD_ALIGN(addr); }
-unsigned int sun4c_pgdir_align(unsigned int addr) { return SUN4C_PGDIR_ALIGN(addr); }
+	if(sun4c_vacinfo.on)
+		panic("SUN4C: AIEEE, trying to invalidate vac while"
+                      " it is on.");
 
-extern int num_segmaps, num_contexts;
+	/* Clear 'valid' bit in all cache line tags */
+	begin = AC_CACHETAGS;
+	end = (AC_CACHETAGS + sun4c_vacinfo.num_bytes);
+	while(begin < end) {
+		__asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+				     "r" (begin), "i" (ASI_CONTROL));
+		begin += sun4c_vacinfo.linesize;
+	}
+}
 
-/* First the functions which the mid-level code uses to directly
- * manipulate the software page tables.  Some defines since we are
- * emulating the i386 page directory layout.
+/* Blow the entire current context out of the virtual cache. */
+/* static */ inline void sun4c_flush_context(void)
+{
+	unsigned long vaddr;
+
+	ctxflushes++;
+	if(sun4c_vacinfo.do_hwflushes) {
+		for(vaddr=0; vaddr < sun4c_vacinfo.num_bytes; vaddr+=PAGE_SIZE)
+			__asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+					     "r" (vaddr), "i" (ASI_HWFLUSHCONTEXT));
+	} else {
+		int incr = sun4c_vacinfo.linesize;
+		for(vaddr=0; vaddr < sun4c_vacinfo.num_bytes; vaddr+=incr)
+			__asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+					     "r" (vaddr), "i" (ASI_FLUSHCTX));
+	}
+}
+
+/* Scrape the segment starting at ADDR from the virtual cache. */
+static inline void sun4c_flush_segment(unsigned long addr)
+{
+	unsigned long end;
+
+	segflushes++;
+	addr &= SUN4C_REAL_PGDIR_MASK;
+	end = (addr + sun4c_vacinfo.num_bytes);
+	if(sun4c_vacinfo.do_hwflushes) {
+		for( ; addr < end; addr += PAGE_SIZE)
+			__asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+					     "r" (addr), "i" (ASI_HWFLUSHSEG));
+	} else {
+		int incr = sun4c_vacinfo.linesize;
+		for( ; addr < end; addr += incr)
+			__asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+					     "r" (addr), "i" (ASI_FLUSHSEG));
+	}
+}
+
+/* Bolix one page from the virtual cache. */
+static inline void sun4c_flush_page(unsigned long addr)
+{
+	addr &= PAGE_MASK;
+
+	pageflushes++;
+	if(sun4c_vacinfo.do_hwflushes) {
+		__asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+				     "r" (addr), "i" (ASI_HWFLUSHPAGE));
+	} else {
+		unsigned long end = addr + PAGE_SIZE;
+		int incr = sun4c_vacinfo.linesize;
+
+		for( ; addr < end; addr += incr)
+			__asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+					     "r" (addr), "i" (ASI_FLUSHPG));
+	}
+}
+
+/* The sun4c's do have an on chip store buffer.  And the way you
+ * clear them out isn't so obvious.  The only way I can think of
+ * to accomplish this is to read the current context register,
+ * store the same value there, then do a bunch of nops for the
+ * pipeline to clear itself completely.  This is only used for
+ * dealing with memory errors, so it is not that critical.
  */
-#define PGD_PRESENT  0x001
-#define PGD_RW       0x002
-#define PGD_USER     0x004
-#define PGD_ACCESSED 0x020
-#define PGD_DIRTY    0x040
-#define PGD_TABLE    (PGD_PRESENT | PGD_RW | PGD_USER | PGD_ACCESSED | PGD_DIRTY)
+void sun4c_complete_all_stores(void)
+{
+	volatile int _unused;
+
+	_unused = sun4c_get_context();
+	sun4c_set_context(_unused);
+	nop(); nop(); nop(); nop();
+	nop(); nop(); nop(); nop();
+	/* Is that enough? */
+}
 
-unsigned long sun4c_vmalloc_start(void)
+/* Bootup utility functions. */
+static inline void sun4c_init_clean_segmap(unsigned char pseg)
 {
-	return SUN4C_VMALLOC_START;
+	unsigned long vaddr;
+
+	sun4c_put_segmap(0, pseg);
+	for(vaddr = 0; vaddr < SUN4C_REAL_PGDIR_SIZE; vaddr+=PAGE_SIZE)
+		sun4c_put_pte(vaddr, 0);
+	sun4c_put_segmap(0, invalid_segment);
 }
 
-/* Update the root mmu directory on the sun4c mmu. */
-void sun4c_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdir)
+static inline void sun4c_init_clean_mmu(unsigned long kernel_end)
 {
-	(tsk)->tss.pgd_ptr = (unsigned long) (pgdir);
+	unsigned long vaddr;
+	unsigned char savectx, ctx;
+
+	savectx = sun4c_get_context();
+	kernel_end = SUN4C_REAL_PGDIR_ALIGN(kernel_end);
+	for(ctx = 0; ctx < num_contexts; ctx++) {
+		sun4c_set_context(ctx);
+		for(vaddr = 0; vaddr < 0x20000000; vaddr += SUN4C_REAL_PGDIR_SIZE)
+			sun4c_put_segmap(vaddr, invalid_segment);
+		for(vaddr = 0xe0000000; vaddr < KERNBASE; vaddr += SUN4C_REAL_PGDIR_SIZE)
+			sun4c_put_segmap(vaddr, invalid_segment);
+		for(vaddr = kernel_end; vaddr < KADB_DEBUGGER_BEGVM; vaddr += SUN4C_REAL_PGDIR_SIZE)
+			sun4c_put_segmap(vaddr, invalid_segment);
+		for(vaddr = LINUX_OPPROM_ENDVM; vaddr; vaddr += SUN4C_REAL_PGDIR_SIZE)
+			sun4c_put_segmap(vaddr, invalid_segment);
+	}
+	sun4c_set_context(ctx);
+}
+
+void sun4c_probe_vac(void)
+{
+	int propval;
+
+	sun4c_disable_vac();
+	sun4c_vacinfo.num_bytes = prom_getintdefault(prom_root_node,
+						     "vac-size", 65536);
+	sun4c_vacinfo.linesize = prom_getintdefault(prom_root_node,
+						    "vac-linesize", 16);
+	sun4c_vacinfo.num_lines =
+		(sun4c_vacinfo.num_bytes / sun4c_vacinfo.linesize);
+	switch(sun4c_vacinfo.linesize) {
+	case 16:
+		sun4c_vacinfo.log2lsize = 4;
+		break;
+	case 32:
+		sun4c_vacinfo.log2lsize = 5;
+		break;
+	default:
+		prom_printf("probe_vac: Didn't expect vac-linesize of %d, halting\n",
+			    sun4c_vacinfo.linesize);
+		prom_halt();
+	};
+
+	propval = prom_getintdefault(prom_root_node, "vac_hwflush", -1);
+	sun4c_vacinfo.do_hwflushes = (propval == -1 ?
+				      prom_getintdefault(prom_root_node,
+							 "vac-hwflush", 0) :
+				      propval);
+
+	if(sun4c_vacinfo.num_bytes != 65536) {
+		prom_printf("WEIRD Sun4C VAC cache size, tell davem");
+		prom_halt();
+	}
+
+	sun4c_flush_all();
+	sun4c_enable_vac();
 }
 
-int sun4c_pte_none(pte_t pte)		{ return !pte_val(pte); }
-int sun4c_pte_present(pte_t pte)	{ return pte_val(pte) & _SUN4C_PAGE_VALID; }
-int sun4c_pte_inuse(pte_t *ptep)        { return mem_map[MAP_NR(ptep)].reserved || mem_map[MAP_NR(ptep)].count != 1; }
-void sun4c_pte_clear(pte_t *ptep)	{ pte_val(*ptep) = 0; }
-void sun4c_pte_reuse(pte_t *ptep)
+static void sun4c_probe_mmu(void)
 {
-	if(!mem_map[MAP_NR(ptep)].reserved)
-		mem_map[MAP_NR(ptep)].count++;
+	num_segmaps = prom_getintdefault(prom_root_node, "mmu-npmg", 128);
+	num_contexts = prom_getintdefault(prom_root_node, "mmu-nctx", 0x8);
 }
 
-int sun4c_pmd_none(pmd_t pmd)		{ return !pmd_val(pmd); }
-int sun4c_pmd_bad(pmd_t pmd)
+static inline void sun4c_init_ss2_cache_bug(void)
 {
-	return (pmd_val(pmd) & ~PAGE_MASK) != PGD_TABLE || pmd_val(pmd) > high_memory;
+	extern unsigned long start;
+
+	if(idprom->id_machtype == (SM_SUN4C | SM_4C_SS2)) {
+		/* Whee.. */
+		printk("SS2 cache bug detected, uncaching trap table page\n");
+		sun4c_flush_page((unsigned int) &start);
+		sun4c_put_pte(((unsigned long) &start),
+			(sun4c_get_pte((unsigned long) &start) | _SUN4C_PAGE_NOCACHE));
+	}
 }
 
-int sun4c_pmd_present(pmd_t pmd)	{ return pmd_val(pmd) & PGD_PRESENT; }
-int sun4c_pmd_inuse(pmd_t *pmdp)        { return 0; }
-void sun4c_pmd_clear(pmd_t *pmdp)	{ pmd_val(*pmdp) = 0; }
-void sun4c_pmd_reuse(pmd_t * pmdp)      { }
-
-int sun4c_pgd_none(pgd_t pgd)		{ return 0; }
-int sun4c_pgd_bad(pgd_t pgd)		{ return 0; }
-int sun4c_pgd_present(pgd_t pgd)	{ return 1; }
-int sun4c_pgd_inuse(pgd_t *pgdp)        { return mem_map[MAP_NR(pgdp)].reserved; }
-void sun4c_pgd_clear(pgd_t * pgdp)	{ }
+static inline unsigned long sun4c_init_alloc_dvma_pages(unsigned long start_mem)
+{
+	unsigned long addr, pte;
 
-/*
- * The following only work if pte_present() is true.
- * Undefined behaviour if not..
+	for(addr = DVMA_VADDR; addr < DVMA_END; addr += PAGE_SIZE) {
+		pte = (start_mem - PAGE_OFFSET) >> PAGE_SHIFT;
+		pte |= (_SUN4C_PAGE_VALID | _SUN4C_PAGE_WRITE | _SUN4C_PAGE_NOCACHE);
+		sun4c_put_pte(addr, pte);
+		start_mem += PAGE_SIZE;
+	}
+	return start_mem;
+}
+
+/* TLB management. */
+struct sun4c_mmu_entry {
+	struct sun4c_mmu_entry *next;
+	struct sun4c_mmu_entry *prev;
+	unsigned long vaddr;
+	unsigned char pseg;
+	unsigned char locked;
+};
+static struct sun4c_mmu_entry mmu_entry_pool[256];
+
+static void sun4c_init_mmu_entry_pool(void)
+{
+	int i;
+
+	for(i=0; i < 256; i++) {
+		mmu_entry_pool[i].pseg = i;
+		mmu_entry_pool[i].next = 0;
+		mmu_entry_pool[i].prev = 0;
+		mmu_entry_pool[i].vaddr = 0;
+		mmu_entry_pool[i].locked = 0;
+	}
+	mmu_entry_pool[invalid_segment].locked = 1;
+}
+
+static inline void fix_permissions(unsigned long vaddr, unsigned long bits_on,
+				   unsigned long bits_off)
+{
+	unsigned long start, end;
+
+	end = vaddr + SUN4C_REAL_PGDIR_SIZE;
+	for(start = vaddr; start < end; start += PAGE_SIZE)
+		if(sun4c_get_pte(start) & _SUN4C_PAGE_VALID)
+			sun4c_put_pte(start, (sun4c_get_pte(start) | bits_on) &
+				      ~bits_off);
+}
+
+static inline void sun4c_init_map_kernelprom(unsigned long kernel_end)
+{
+	unsigned long vaddr;
+	unsigned char pseg, ctx;
+
+	for(vaddr = KADB_DEBUGGER_BEGVM;
+	    vaddr < LINUX_OPPROM_ENDVM;
+	    vaddr += SUN4C_REAL_PGDIR_SIZE) {
+		pseg = sun4c_get_segmap(vaddr);
+		if(pseg != invalid_segment) {
+			mmu_entry_pool[pseg].locked = 1;
+			for(ctx = 0; ctx < num_contexts; ctx++)
+				prom_putsegment(ctx, vaddr, pseg);
+			fix_permissions(vaddr, _SUN4C_PAGE_PRIV, 0);
+		}
+	}
+	for(vaddr = KERNBASE; vaddr < kernel_end; vaddr += SUN4C_REAL_PGDIR_SIZE) {
+		pseg = sun4c_get_segmap(vaddr);
+		mmu_entry_pool[pseg].locked = 1;
+		for(ctx = 0; ctx < num_contexts; ctx++)
+			prom_putsegment(ctx, vaddr, pseg);
+		fix_permissions(vaddr, _SUN4C_PAGE_PRIV, _SUN4C_PAGE_NOCACHE);
+	}
+}
+
+static void sun4c_init_lock_area(unsigned long start, unsigned long end)
+{
+	int i, ctx;
+
+	while(start < end) {
+		for(i=0; i < invalid_segment; i++)
+			if(!mmu_entry_pool[i].locked)
+				break;
+		mmu_entry_pool[i].locked = 1;
+		sun4c_init_clean_segmap(i);
+		for(ctx = 0; ctx < num_contexts; ctx++)
+			prom_putsegment(ctx, start, mmu_entry_pool[i].pseg);
+		start += SUN4C_REAL_PGDIR_SIZE;
+	}
+}
+
+struct sun4c_mmu_ring {
+	struct sun4c_mmu_entry ringhd;
+	int num_entries;
+};
+static struct sun4c_mmu_ring sun4c_context_ring[16]; /* used user entries */
+static struct sun4c_mmu_ring sun4c_ufree_ring;       /* free user entries */
+static struct sun4c_mmu_ring sun4c_kernel_ring;      /* used kernel entries */
+static struct sun4c_mmu_ring sun4c_kfree_ring;       /* free kernel entries */
+
+static inline void sun4c_init_rings(void)
+{
+	int i;
+	for(i=0; i<16; i++) {
+		sun4c_context_ring[i].ringhd.next =
+			sun4c_context_ring[i].ringhd.prev =
+			&sun4c_context_ring[i].ringhd;
+		sun4c_context_ring[i].num_entries = 0;
+	}
+	sun4c_ufree_ring.ringhd.next = sun4c_ufree_ring.ringhd.prev =
+		&sun4c_ufree_ring.ringhd;
+	sun4c_kernel_ring.ringhd.next = sun4c_kernel_ring.ringhd.prev =
+		&sun4c_kernel_ring.ringhd;
+	sun4c_kfree_ring.ringhd.next = sun4c_kfree_ring.ringhd.prev =
+		&sun4c_kfree_ring.ringhd;
+	sun4c_ufree_ring.num_entries = sun4c_kernel_ring.num_entries =
+		sun4c_kfree_ring.num_entries = 0;
+}
+
+static inline void add_ring(struct sun4c_mmu_ring *ring, struct sun4c_mmu_entry *entry)
+{
+	struct sun4c_mmu_entry *head = &ring->ringhd;
+
+	entry->prev = head;
+	(entry->next = head->next)->prev = entry;
+	head->next = entry;
+	ring->num_entries++;
+}
+
+static inline void remove_ring(struct sun4c_mmu_ring *ring, struct sun4c_mmu_entry *entry)
+{
+	struct sun4c_mmu_entry *next = entry->next;
+
+	(next->prev = entry->prev)->next = next;
+	ring->num_entries--;
+}
+
+static inline void recycle_ring(struct sun4c_mmu_ring *ring, struct sun4c_mmu_entry *entry)
+{
+	struct sun4c_mmu_entry *head = &ring->ringhd;
+	struct sun4c_mmu_entry *next = entry->next;
+
+	(next->prev = entry->prev)->next = next;
+	entry->prev = head; (entry->next = head->next)->prev = entry;
+	head->next = entry;
+	/* num_entries stays the same */
+}
+
+static inline void free_user_entry(int ctx, struct sun4c_mmu_entry *entry)
+{
+        remove_ring(sun4c_context_ring+ctx, entry);
+        add_ring(&sun4c_ufree_ring, entry);
+}
+
+static inline void assign_user_entry(int ctx, struct sun4c_mmu_entry *entry) 
+{
+        remove_ring(&sun4c_ufree_ring, entry);
+        add_ring(sun4c_context_ring+ctx, entry);
+}
+
+static inline void free_kernel_entry(struct sun4c_mmu_entry *entry, struct sun4c_mmu_ring *ring)
+{
+        remove_ring(ring, entry);
+        add_ring(&sun4c_kfree_ring, entry);
+}
+
+static inline void assign_kernel_entry(struct sun4c_mmu_entry *entry, struct sun4c_mmu_ring *ring) 
+{
+        remove_ring(ring, entry);
+        add_ring(&sun4c_kernel_ring, entry);
+}
+
+static inline void reassign_kernel_entry(struct sun4c_mmu_entry *entry)
+{
+	recycle_ring(&sun4c_kernel_ring, entry);
+}
+
+static void sun4c_init_fill_kernel_ring(int howmany)
+{
+	int i;
+
+	while(howmany) {
+		for(i=0; i < invalid_segment; i++)
+			if(!mmu_entry_pool[i].locked)
+				break;
+		mmu_entry_pool[i].locked = 1;
+		sun4c_init_clean_segmap(i);
+		add_ring(&sun4c_kfree_ring, &mmu_entry_pool[i]);
+		howmany--;
+	}
+}
+
+static void sun4c_init_fill_user_ring(void)
+{
+	int i;
+
+	for(i=0; i < invalid_segment; i++) {
+		if(mmu_entry_pool[i].locked)
+			continue;
+		sun4c_init_clean_segmap(i);
+		add_ring(&sun4c_ufree_ring, &mmu_entry_pool[i]);
+	}
+}
+
+static inline void sun4c_kernel_unmap(struct sun4c_mmu_entry *kentry)
+{
+	int savectx, ctx;
+
+	savectx = sun4c_get_context();
+	flush_user_windows();
+	sun4c_flush_segment(kentry->vaddr);
+	for(ctx = 0; ctx < num_contexts; ctx++) {
+		sun4c_set_context(ctx);
+		sun4c_put_segmap(kentry->vaddr, invalid_segment);
+	}
+	sun4c_set_context(savectx);
+}
+
+static inline void sun4c_kernel_map(struct sun4c_mmu_entry *kentry)
+{
+	int savectx, ctx;
+
+	savectx = sun4c_get_context();
+	flush_user_windows();
+	for(ctx = 0; ctx < num_contexts; ctx++) {
+		sun4c_set_context(ctx);
+		sun4c_put_segmap(kentry->vaddr, kentry->pseg);
+	}
+	sun4c_set_context(savectx);
+}
+
+static inline void sun4c_user_unmap(struct sun4c_mmu_entry *uentry)
+{
+	sun4c_flush_segment(uentry->vaddr);
+	sun4c_put_segmap(uentry->vaddr, invalid_segment);
+}
+
+static inline void sun4c_user_map(struct sun4c_mmu_entry *uentry)
+{
+	unsigned long start = uentry->vaddr;
+	unsigned long end = start + SUN4C_REAL_PGDIR_SIZE;
+
+	sun4c_put_segmap(uentry->vaddr, uentry->pseg);
+	while(start < end) {
+		sun4c_put_pte(start, 0);
+		start += PAGE_SIZE;
+	}
+}
+
+static inline void sun4c_demap_context(struct sun4c_mmu_ring *crp, unsigned char ctx)
+{
+	struct sun4c_mmu_entry *this_entry, *next_entry;
+	int savectx = sun4c_get_context();
+
+	this_entry = crp->ringhd.next;
+	flush_user_windows();
+	sun4c_set_context(ctx);
+	while(crp->num_entries) {
+		next_entry = this_entry->next;
+		sun4c_user_unmap(this_entry);
+		free_user_entry(ctx, this_entry);
+		this_entry = next_entry;
+	}
+	sun4c_set_context(savectx);
+}
+
+static inline void sun4c_demap_one(struct sun4c_mmu_ring *crp, unsigned char ctx)
+{
+	struct sun4c_mmu_entry *entry = crp->ringhd.next;
+	int savectx = sun4c_get_context();
+
+	flush_user_windows();
+	sun4c_set_context(ctx);
+	sun4c_user_unmap(entry);
+	free_user_entry(ctx, entry);
+	sun4c_set_context(savectx);
+}
+
+/* Using this method to free up mmu entries eliminates a lot of
+ * potention races since we have a kernel that incurs tlb
+ * replacement faults.  There may be performance penalties.
+ */
+static inline struct sun4c_mmu_entry *sun4c_user_strategy(void)
+{
+	struct sun4c_mmu_ring *rp = 0;
+	unsigned char mmuhog, i, ctx = 0;
+
+	/* If some are free, return first one. */
+	if(sun4c_ufree_ring.num_entries)
+		return sun4c_ufree_ring.ringhd.next;
+
+	/* Else free one up. */
+	mmuhog = 0;
+	for(i=0; i < num_contexts; i++) {
+		if(sun4c_context_ring[i].num_entries > mmuhog) {
+			rp = &sun4c_context_ring[i];
+			mmuhog = rp->num_entries;
+			ctx = i;
+		}
+	}
+	sun4c_demap_one(rp, ctx);
+	return sun4c_ufree_ring.ringhd.next;
+}
+
+static inline struct sun4c_mmu_entry *sun4c_kernel_strategy(void)
+{
+	struct sun4c_mmu_entry *this_entry;
+
+	/* If some are free, return first one. */
+	if(sun4c_kfree_ring.num_entries)
+		return sun4c_kfree_ring.ringhd.next;
+
+	/* Else free one up. */
+	this_entry = sun4c_kernel_ring.ringhd.prev;
+	sun4c_kernel_unmap(this_entry);
+	free_kernel_entry(this_entry, &sun4c_kernel_ring);
+	return sun4c_kfree_ring.ringhd.next;
+}
+
+static inline void alloc_user_segment(unsigned long address, unsigned char ctx)
+{
+	struct sun4c_mmu_entry *entry;
+
+	address &= SUN4C_REAL_PGDIR_MASK;
+	entry = sun4c_user_strategy();
+	assign_user_entry(ctx, entry);
+	entry->vaddr = address;
+	sun4c_user_map(entry);
+}
+
+static inline void alloc_kernel_segment(unsigned long address)
+{
+	struct sun4c_mmu_entry *entry;
+
+	address &= SUN4C_REAL_PGDIR_MASK;
+	entry = sun4c_kernel_strategy();
+
+	assign_kernel_entry(entry, &sun4c_kfree_ring);
+	entry->vaddr = address;
+	sun4c_kernel_map(entry);
+}
+
+/* XXX Just like kernel tlb replacement we'd like to have a low level
+ * XXX equivalent for user faults which need not go through the mm
+ * XXX subsystem just to load a mmu entry.  But this might not be as
+ * XXX feasible since we need to go through the kernel page tables
+ * XXX for this process, which we currently don't lock into the mmu
+ * XXX so we would fault with traps off... must think about this...
+ */
+static void sun4c_update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte)
+{
+	unsigned long flags;
+
+	save_flags(flags); cli();
+	address &= PAGE_MASK;
+	if(sun4c_get_segmap(address) == invalid_segment)
+		alloc_user_segment(address, sun4c_get_context());
+	sun4c_put_pte(address, pte_val(pte));
+	restore_flags(flags);
+}
+
+/* READ THIS:  If you put any diagnostic printing code in any of the kernel
+ *             fault handling code you will lose badly.  This is the most
+ *             delicate piece of code in the entire kernel, atomicity of
+ *             kernel tlb replacement must be guarenteed.  This is why we
+ *             have seperate user and kernel allocation rings to alleviate
+ *             as many bad interactions as possible.
+ *
+ * XXX Someday make this into a fast in-window trap handler to avoid
+ * XXX any and all races.  *High* priority, also for performance.
  */
-int sun4c_pte_read(pte_t pte)		{ return !(pte_val(pte) & _SUN4C_PAGE_PRIV); }
-int sun4c_pte_write(pte_t pte)		{ return pte_val(pte) & _SUN4C_PAGE_WRITE; }
-int sun4c_pte_exec(pte_t pte)		{ return !(pte_val(pte) & _SUN4C_PAGE_PRIV); }
-int sun4c_pte_dirty(pte_t pte)		{ return pte_val(pte) & _SUN4C_PAGE_DIRTY; }
-int sun4c_pte_young(pte_t pte)		{ return pte_val(pte) & _SUN4C_PAGE_REF; }
-int sun4c_pte_cow(pte_t pte)		{ return pte_val(pte) & _SUN4C_PAGE_COW; }
-
-pte_t sun4c_pte_wrprotect(pte_t pte)	{ pte_val(pte) &= ~_SUN4C_PAGE_WRITE; return pte; }
-pte_t sun4c_pte_rdprotect(pte_t pte)	{ pte_val(pte) |= _SUN4C_PAGE_PRIV; return pte; }
-pte_t sun4c_pte_exprotect(pte_t pte)	{ pte_val(pte) |= _SUN4C_PAGE_PRIV; return pte; }
-pte_t sun4c_pte_mkclean(pte_t pte)	{ pte_val(pte) &= ~_SUN4C_PAGE_DIRTY; return pte; }
-pte_t sun4c_pte_mkold(pte_t pte)	{ pte_val(pte) &= ~_SUN4C_PAGE_REF; return pte; }
-pte_t sun4c_pte_uncow(pte_t pte)	{ pte_val(pte) &= ~_SUN4C_PAGE_COW; return pte; }
-pte_t sun4c_pte_mkwrite(pte_t pte)	{ pte_val(pte) |= _SUN4C_PAGE_WRITE; return pte; }
-pte_t sun4c_pte_mkread(pte_t pte)	{ pte_val(pte) &= ~_SUN4C_PAGE_PRIV; return pte; }
-pte_t sun4c_pte_mkexec(pte_t pte)	{ pte_val(pte) &= ~_SUN4C_PAGE_PRIV; return pte; }
-pte_t sun4c_pte_mkdirty(pte_t pte)	{ pte_val(pte) |= _SUN4C_PAGE_DIRTY; return pte; }
-pte_t sun4c_pte_mkyoung(pte_t pte)	{ pte_val(pte) |= _SUN4C_PAGE_REF; return pte; }
-pte_t sun4c_pte_mkcow(pte_t pte)	{ pte_val(pte) |= _SUN4C_PAGE_COW; return pte; }
+static void sun4c_quick_kernel_fault(unsigned long address)
+{
+	unsigned long end, flags;
+
+	save_flags(flags); cli();
+	address &= SUN4C_REAL_PGDIR_MASK;
+	end = address + SUN4C_REAL_PGDIR_SIZE;
+	if(sun4c_get_segmap(address) == invalid_segment)
+		alloc_kernel_segment(address);
+
+	if(address < SUN4C_VMALLOC_START) {
+		unsigned long pte;
+		pte = (address - PAGE_OFFSET) >> PAGE_SHIFT;
+		pte |= pgprot_val(SUN4C_PAGE_KERNEL);
+		/* Stupid pte tricks... */
+		while(address < end) {
+			sun4c_put_pte(address, pte++);
+			address += PAGE_SIZE;
+		}
+	} else {
+		pte_t *ptep;
+
+		ptep = (pte_t *) (PAGE_MASK & pgd_val(swapper_pg_dir[address>>SUN4C_PGDIR_SHIFT]));
+		ptep = (ptep + ((address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1)));
+		while(address < end) {
+			sun4c_put_pte(address, pte_val(*ptep++));
+			address += PAGE_SIZE;
+		}
+	}
+	restore_flags(flags);
+}
 
 /*
- * Conversion functions: convert a page and protection to a page entry,
- * and a page entry and page directory to the page they refer to.
+ * 4 page buckets for task struct and kernel stack allocation.
+ *
+ * TASK_STACK_BEGIN
+ * bucket[0]
+ * bucket[1]
+ *   [ ... ]
+ * bucket[NR_TASKS-1]
+ * TASK_STACK_BEGIN + (sizeof(struct task_bucket) * NR_TASKS)
+ *
+ * Each slot looks like:
+ *
+ *  page 1   --  task struct
+ *  page 2   --  unmapped, for stack redzone (maybe use for pgd)
+ *  page 3/4 --  kernel stack
  */
-pte_t sun4c_mk_pte(unsigned long page, pgprot_t pgprot)
+
+struct task_bucket {
+	struct task_struct task;
+	char _unused1[PAGE_SIZE - sizeof(struct task_struct)];
+	char _unused2[PAGE_SIZE];
+	char kstack[(PAGE_SIZE<<1)];
+};
+
+struct task_bucket *sun4c_bucket[NR_TASKS];
+
+#define BUCKET_EMPTY     ((struct task_bucket *) 0)
+#define BUCKET_SIZE      (PAGE_SIZE << 2)
+#define BUCKET_SHIFT     14        /* log2(sizeof(struct task_bucket)) */
+#define BUCKET_NUM(addr) ((((addr) - SUN4C_LOCK_VADDR) >> BUCKET_SHIFT))
+#define BUCKET_ADDR(num) (((num) << BUCKET_SHIFT) + SUN4C_LOCK_VADDR)
+#define BUCKET_PTE(page)       \
+        ((((page) - PAGE_OFFSET) >> PAGE_SHIFT) | pgprot_val(SUN4C_PAGE_KERNEL))
+#define BUCKET_PTE_PAGE(pte)   \
+        (PAGE_OFFSET + (((pte) & 0xffff) << PAGE_SHIFT))
+
+static inline void get_task_segment(unsigned long addr)
 {
-	return __pte(((page - PAGE_OFFSET) >> PAGE_SHIFT) | pgprot_val(pgprot));
+	struct sun4c_mmu_entry *stolen;
+	unsigned long flags;
+
+	save_flags(flags); cli();
+	addr &= SUN4C_REAL_PGDIR_MASK;
+	stolen = sun4c_user_strategy();
+	remove_ring(&sun4c_ufree_ring, stolen);
+	stolen->vaddr = addr;
+	sun4c_kernel_map(stolen);
+	restore_flags(flags);
 }
 
-pte_t sun4c_pte_modify(pte_t pte, pgprot_t newprot)
+static inline void free_task_segment(unsigned long addr)
 {
-	return __pte((pte_val(pte) & _SUN4C_PAGE_CHG_MASK) | pgprot_val(newprot));
+	struct sun4c_mmu_entry *entry;
+	unsigned long flags;
+	unsigned char pseg;
+
+	save_flags(flags); cli();
+	addr &= SUN4C_REAL_PGDIR_MASK;
+	pseg = sun4c_get_segmap(addr);
+	entry = &mmu_entry_pool[pseg];
+	sun4c_flush_segment(addr);
+	sun4c_kernel_unmap(entry);
+	add_ring(&sun4c_ufree_ring, entry);
+	restore_flags(flags);
 }
 
-unsigned long sun4c_pte_page(pte_t pte)
+static inline void garbage_collect(int entry)
 {
-	return (PAGE_OFFSET + ((pte_val(pte) & 0xffff) << (PAGE_SHIFT)));
+	int start, end;
+
+	/* 16 buckets per segment... */
+	entry &= ~15;
+	start = entry;
+	for(end = (start + 16); start < end; start++)
+		if(sun4c_bucket[start] != BUCKET_EMPTY)
+			return;
+	/* Entire segment empty, release it. */
+	free_task_segment(BUCKET_ADDR(entry));
+}
+
+static struct task_struct *sun4c_alloc_task_struct(void)
+{
+	unsigned long addr, page;
+	int entry;
+
+	page = get_free_page(GFP_KERNEL);
+	if(!page)
+		return (struct task_struct *) 0;
+	/* XXX Bahh, linear search too slow, use hash
+	 * XXX table in final implementation.  Or
+	 * XXX keep track of first free when we free
+	 * XXX a bucket... anything but this.
+	 */
+	for(entry = 0; entry < NR_TASKS; entry++)
+		if(sun4c_bucket[entry] == BUCKET_EMPTY)
+			break;
+	if(entry == NR_TASKS) {
+		free_page(page);
+		return (struct task_struct *) 0;
+	}
+	addr = BUCKET_ADDR(entry);
+	sun4c_bucket[entry] = (struct task_bucket *) addr;
+	if(sun4c_get_segmap(addr) == invalid_segment)
+		get_task_segment(addr);
+	sun4c_put_pte(addr, BUCKET_PTE(page));
+	return (struct task_struct *) addr;
 }
 
-unsigned long sun4c_pmd_page(pmd_t pmd)
+static unsigned long sun4c_alloc_kernel_stack(struct task_struct *tsk)
 {
-	return (pmd_val(pmd) & PAGE_MASK);
+	unsigned long saddr = (unsigned long) tsk;
+	unsigned long page[2];
+
+	if(!saddr)
+		return 0;
+	page[0] = get_free_page(GFP_KERNEL);
+	if(!page[0])
+		return 0;
+	page[1] = get_free_page(GFP_KERNEL);
+	if(!page[1]) {
+		free_page(page[0]);
+		return 0;
+	}
+	saddr += (PAGE_SIZE << 1);
+	sun4c_put_pte(saddr - PAGE_SIZE, 0);
+	sun4c_put_pte(saddr, BUCKET_PTE(page[0]));
+	sun4c_put_pte(saddr + PAGE_SIZE, BUCKET_PTE(page[1]));
+	return saddr;
 }
 
-/* to find an entry in a page-table-directory */
-pgd_t *sun4c_pgd_offset(struct mm_struct * mm, unsigned long address)
+static void sun4c_free_kernel_stack(unsigned long stack)
 {
-	return mm->pgd + (address >> SUN4C_PGDIR_SHIFT);
+	unsigned long page[2];
+
+	page[0] = BUCKET_PTE_PAGE(sun4c_get_pte(stack));
+	page[1] = BUCKET_PTE_PAGE(sun4c_get_pte(stack+PAGE_SIZE));
+	sun4c_flush_segment(stack & SUN4C_REAL_PGDIR_MASK);
+	sun4c_put_pte(stack, 0);
+	sun4c_put_pte(stack + PAGE_SIZE, 0);
+	free_page(page[0]);
+	free_page(page[1]);
 }
 
-/* Find an entry in the second-level page table.. */
-pmd_t *sun4c_pmd_offset(pgd_t * dir, unsigned long address)
+static void sun4c_free_task_struct(struct task_struct *tsk)
 {
-	return (pmd_t *) dir;
+	unsigned long tsaddr = (unsigned long) tsk;
+	unsigned long page = BUCKET_PTE_PAGE(sun4c_get_pte(tsaddr));
+	int entry = BUCKET_NUM(tsaddr);
+
+	sun4c_flush_segment(tsaddr & SUN4C_REAL_PGDIR_MASK);
+	sun4c_put_pte(tsaddr, 0);
+	sun4c_bucket[entry] = BUCKET_EMPTY;
+	free_page(page);
+	garbage_collect(entry);
 }
 
-/* Find an entry in the third-level page table.. */ 
-pte_t *sun4c_pte_offset(pmd_t * dir, unsigned long address)
+static void sun4c_init_buckets(void)
 {
-	return (pte_t *) sun4c_pmd_page(*dir) +	((address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1));
+	int entry;
+
+	if(sizeof(struct task_bucket) != (PAGE_SIZE << 2)) {
+		prom_printf("task bucket not 4 pages!\n");
+		prom_halt();
+	}
+	for(entry = 0; entry < NR_TASKS; entry++)
+		sun4c_bucket[entry] = BUCKET_EMPTY;
+}
+
+static unsigned long sun4c_iobuffer_start;
+static unsigned long sun4c_iobuffer_end;
+static unsigned long *sun4c_iobuffer_map;
+static int iobuffer_map_size;
+
+static char *sun4c_lockpage(char *vaddr, unsigned long _unused)
+{
+	unsigned long vpage, voffset, search, pte;
+	unsigned long npage;
+
+	vpage = ((unsigned long) vaddr) & PAGE_MASK;
+	voffset = ((unsigned long) vaddr) & ~PAGE_MASK;
+	pte = ((vpage-PAGE_OFFSET) >> PAGE_SHIFT) | pgprot_val(SUN4C_PAGE_KERNEL);
+	pte |= _SUN4C_PAGE_NOCACHE;
+	search = find_first_zero_bit(sun4c_iobuffer_map, iobuffer_map_size);
+	set_bit(search, sun4c_iobuffer_map);
+	npage = (search << PAGE_SHIFT) + sun4c_iobuffer_start;
+	sun4c_flush_page(vpage);
+	sun4c_put_pte(npage, pte);
+	return (char *) (npage + voffset);
+}
+
+static void sun4c_unlockpage(char *vaddr, unsigned long _unused)
+{
+	unsigned long vpage, nr;
+
+	vpage = (unsigned long) vaddr;
+	vpage &= PAGE_MASK;
+	nr = (vpage - sun4c_iobuffer_start) >> PAGE_SHIFT;
+	sun4c_put_pte(vpage, 0);
+	clear_bit(nr, sun4c_iobuffer_map);
+}
+
+/* Note the scsi code at init time passes to here buffers
+ * which sit on the kernel stack, those are already locked
+ * by implication and fool the page locking code above
+ * if passed to by mistake.
+ */
+static char *sun4c_get_scsi_buffer(char *bufptr, unsigned long len, struct linux_sbus *sbus)
+{
+	unsigned long page1, page2;
+
+	page1 = ((unsigned long) bufptr) & PAGE_MASK;
+	page2 = (((unsigned long) bufptr) + len - 1) & PAGE_MASK;
+	if(page1 != page2) {
+		printk("Problem, trying to lock multipage scsi buffer.\n");
+		printk("page1<%08lx> page2<%08lx>\n", page1, page2);
+		panic("Scsi buffer too big.");
+	}
+	if(page1 > high_memory)
+		return bufptr; /* already locked */
+	return sun4c_lockpage(bufptr, PAGE_SIZE);
+}
+
+static void sun4c_release_scsi_buffer(char *bufptr, unsigned long len, struct linux_sbus *sbus)
+{
+	unsigned long page = (unsigned long) bufptr;
+
+	if(page < sun4c_iobuffer_start)
+		return; /* On kernel stack or similar, see above */
+	sun4c_unlockpage(bufptr, PAGE_SIZE);
+}
+
+#define TASK_ENTRY_SIZE    (3 * PAGE_SIZE)
+#define LONG_ALIGN(x) (((x)+(sizeof(long))-1)&~((sizeof(long))-1))
+
+struct vm_area_struct sun4c_kstack_vma;
+
+static unsigned long sun4c_init_lock_areas(unsigned long start_mem)
+{
+	unsigned long sun4c_taskstack_start;
+	unsigned long sun4c_taskstack_end;
+	int bitmap_size;
+
+	sun4c_init_buckets();
+	sun4c_taskstack_start = SUN4C_LOCK_VADDR;
+	sun4c_taskstack_end = (sun4c_taskstack_start +
+			       (TASK_ENTRY_SIZE * NR_TASKS));
+	if(sun4c_taskstack_end >= SUN4C_LOCK_END) {
+		prom_printf("Too many tasks, decrease NR_TASKS please.\n");
+		prom_halt();
+	}
+
+	sun4c_iobuffer_start = SUN4C_REAL_PGDIR_ALIGN(sun4c_taskstack_end);
+	sun4c_iobuffer_end = sun4c_iobuffer_start + SUN4C_REAL_PGDIR_SIZE;
+	bitmap_size = (sun4c_iobuffer_end - sun4c_iobuffer_start) >> PAGE_SHIFT;
+	bitmap_size = (bitmap_size + 7) >> 3;
+	bitmap_size = LONG_ALIGN(bitmap_size);
+	iobuffer_map_size = bitmap_size << 3;
+	sun4c_iobuffer_map = (unsigned long *) start_mem;
+	memset((void *) start_mem, 0, bitmap_size);
+	start_mem += bitmap_size;
+
+	/* Now get us some mmu entries for I/O maps. */
+	sun4c_init_lock_area(sun4c_iobuffer_start, sun4c_iobuffer_end);
+	sun4c_kstack_vma.vm_mm = init_task.mm;
+	sun4c_kstack_vma.vm_start = sun4c_taskstack_start;
+	sun4c_kstack_vma.vm_end = sun4c_taskstack_end;
+	sun4c_kstack_vma.vm_page_prot = PAGE_SHARED;
+	sun4c_kstack_vma.vm_flags = VM_READ | VM_WRITE | VM_EXEC;
+	insert_vm_struct(&init_task, &sun4c_kstack_vma);
+	return start_mem;
+}
+
+static void sun4c_invalidate_all(void)
+{
+	struct sun4c_mmu_entry *this_entry, *next_entry;
+
+	this_entry = sun4c_kernel_ring.ringhd.next;
+	while(sun4c_kernel_ring.num_entries) {
+		next_entry = this_entry->next;
+		sun4c_kernel_unmap(this_entry);
+		free_kernel_entry(this_entry, &sun4c_kernel_ring);
+		this_entry = next_entry;
+	}
+}
+
+static void sun4c_invalidate_mm(struct mm_struct *mm)
+{
+	if(mm->context == NO_CONTEXT)
+		return;
+	sun4c_demap_context(&sun4c_context_ring[mm->context], mm->context);
+}
+
+static void sun4c_invalidate_range(struct mm_struct *mm, unsigned long start, unsigned long end)
+{
+	struct sun4c_mmu_entry *this_entry;
+	unsigned char pseg, savectx;
+
+	if(mm->context == NO_CONTEXT)
+		return;
+	flush_user_windows();
+	savectx = sun4c_get_context();
+	sun4c_set_context(mm->context);
+	start &= SUN4C_REAL_PGDIR_MASK;
+	while(start < end) {
+		pseg = sun4c_get_segmap(start);
+		if(pseg == invalid_segment)
+			goto next_one;
+		this_entry = &mmu_entry_pool[pseg];
+		sun4c_user_unmap(this_entry);
+		free_user_entry(mm->context, this_entry);
+	next_one:
+		start += SUN4C_REAL_PGDIR_SIZE;
+	}
+	sun4c_set_context(savectx);
+}
+
+static void sun4c_invalidate_page(struct vm_area_struct *vma, unsigned long page)
+{
+	struct mm_struct *mm = vma->vm_mm;
+	unsigned char savectx;
+
+	if(mm->context == NO_CONTEXT)
+		return;
+	flush_user_windows();
+	savectx = sun4c_get_context();
+	sun4c_set_context(mm->context);
+	page &= PAGE_MASK;
+	if(sun4c_get_pte(page) & _SUN4C_PAGE_VALID) {
+		sun4c_flush_page(page);
+		sun4c_put_pte(page, 0);
+	}
+	sun4c_set_context(savectx);
+}
+
+/* Sun4c mmu hardware doesn't update the dirty bit in the pte's
+ * for us, so we do it in software.
+ */
+static void sun4c_set_pte(pte_t *ptep, pte_t pte)
+{
+
+	if((pte_val(pte) & (_SUN4C_PAGE_WRITE|_SUN4C_PAGE_DIRTY)) ==
+	   _SUN4C_PAGE_WRITE)
+		pte_val(pte) |= _SUN4C_PAGE_DIRTY;
+
+	*ptep = pte;
+}
+
+/* static */ void sun4c_mapioaddr(unsigned long physaddr, unsigned long virt_addr,
+		     int bus_type, int rdonly)
+{
+	unsigned long page_entry;
+
+	page_entry = ((physaddr >> PAGE_SHIFT) & 0xffff);
+	page_entry |= (_SUN4C_PAGE_VALID | _SUN4C_PAGE_WRITE |
+		       _SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_IO);
+	if(rdonly)
+		page_entry &= (~_SUN4C_PAGE_WRITE);
+	sun4c_flush_page(virt_addr);
+	sun4c_put_pte(virt_addr, page_entry);
+}
+
+static inline void sun4c_alloc_context(struct mm_struct *mm)
+{
+	struct ctx_list *ctxp;
+
+	ctxp = ctx_free.next;
+	if(ctxp != &ctx_free) {
+		remove_from_ctx_list(ctxp);
+		add_to_used_ctxlist(ctxp);
+		mm->context = ctxp->ctx_number;
+		ctxp->ctx_mm = mm;
+		return;
+	}
+	ctxp = ctx_used.next;
+	if(ctxp->ctx_mm == current->mm)
+		ctxp = ctxp->next;
+	if(ctxp == &ctx_used)
+		panic("out of mmu contexts");
+	remove_from_ctx_list(ctxp);
+	add_to_used_ctxlist(ctxp);
+	ctxp->ctx_mm->context = NO_CONTEXT;
+	ctxp->ctx_mm = mm;
+	mm->context = ctxp->ctx_number;
+	sun4c_demap_context(&sun4c_context_ring[ctxp->ctx_number], ctxp->ctx_number);
+}
+
+#if some_day_soon /* We need some tweaking to start using this */
+extern void force_user_fault(unsigned long, int);
+
+void sun4c_switch_heuristic(struct pt_regs *regs)
+{
+	unsigned long sp = regs->u_regs[UREG_FP];
+	unsigned long sp2 = sp + REGWIN_SZ - 0x8;
+
+	force_user_fault(regs->pc, 0);
+	force_user_fault(sp, 0);
+	if((sp&PAGE_MASK) != (sp2&PAGE_MASK))
+		force_user_fault(sp2, 0);
 }
+#endif
+
+static void sun4c_switch_to_context(struct task_struct *tsk)
+{
+	/* Kernel threads can execute in any context and so can tasks
+	 * sleeping in the middle of exiting. If this task has already
+	 * been allocated a piece of the mmu realestate, just jump to
+	 * it.
+	 */
+	if((tsk->tss.flags & SPARC_FLAG_KTHREAD) ||
+	   (tsk->flags & PF_EXITING))
+		return;
+	if(tsk->mm->context == NO_CONTEXT)
+		sun4c_alloc_context(tsk->mm);
+
+	sun4c_set_context(tsk->mm->context);
+}
+
+static void sun4c_flush_hook(void)
+{
+	if(current->tss.flags & SPARC_FLAG_KTHREAD) {
+		sun4c_alloc_context(current->mm);
+		sun4c_set_context(current->mm->context);
+	}
+}
+
+static void sun4c_exit_hook(void)
+{
+	struct ctx_list *ctx_old;
+	struct mm_struct *mm = current->mm;
+
+	if(mm->context != NO_CONTEXT) {
+		sun4c_demap_context(&sun4c_context_ring[mm->context], mm->context);
+		ctx_old = ctx_list_pool + mm->context;
+		remove_from_ctx_list(ctx_old);
+		add_to_free_ctxlist(ctx_old);
+		mm->context = NO_CONTEXT;
+	}
+}
+
+void sun4c_test_wp(void)
+{
+	wp_works_ok = -1;
+
+	/* Let it rip... */
+	sun4c_put_pte((unsigned long) 0x0, (_SUN4C_PAGE_VALID | _SUN4C_PAGE_PRIV));
+	__asm__ __volatile__("st %%g0, [0x0]\n\t": : :"memory");
+	sun4c_put_pte((unsigned long) 0x0, 0x0);
+	if (wp_works_ok < 0)
+		wp_works_ok = 0;
+}
+
+static char s4cinfo[512];
+
+static char *sun4c_mmu_info(void)
+{
+	int used_user_entries, i;
+
+	used_user_entries = 0;
+	for(i=0; i < num_contexts; i++)
+		used_user_entries += sun4c_context_ring[i].num_entries;
+
+	sprintf(s4cinfo, "vacsize: %d bytes\n"
+		"vachwflush\t: %s\n"
+		"vaclinesize\t: %d bytes\n"
+		"mmuctxs\t\t: %d\n"
+		"mmupsegs\t: %d\n"
+		"usedpsegs\t: %d\n"
+		"ufreepsegs\t: %d\n"
+		"context\t\t: %d flushes\n"
+		"segment\t\t: %d flushes\n"
+		"page\t\t: %d flushes\n",
+		sun4c_vacinfo.num_bytes,
+		(sun4c_vacinfo.do_hwflushes ? "yes" : "no"),
+		sun4c_vacinfo.linesize,
+		num_contexts,
+		(invalid_segment + 1),
+		used_user_entries,
+		sun4c_ufree_ring.num_entries,
+		ctxflushes, segflushes, pageflushes);
+
+	return s4cinfo;
+}
+
+/* Nothing below here should touch the mmu hardware nor the mmu_entry
+ * data structures.
+ */
+
+static unsigned int sun4c_pmd_align(unsigned int addr) { return SUN4C_PMD_ALIGN(addr); }
+static unsigned int sun4c_pgdir_align(unsigned int addr) { return SUN4C_PGDIR_ALIGN(addr); }
+
+/* First the functions which the mid-level code uses to directly
+ * manipulate the software page tables.  Some defines since we are
+ * emulating the i386 page directory layout.
+ */
+#define PGD_PRESENT  0x001
+#define PGD_RW       0x002
+#define PGD_USER     0x004
+#define PGD_ACCESSED 0x020
+#define PGD_DIRTY    0x040
+#define PGD_TABLE    (PGD_PRESENT | PGD_RW | PGD_USER | PGD_ACCESSED | PGD_DIRTY)
 
-/* Here comes the sun4c mmu-tlb management engine.  It is here because
- * some of the mid-level mm support needs to be able to lock down
- * critical areas of kernel memory into the tlb.
- */
-static inline void add_pseg_list(struct pseg_list *head, struct pseg_list *entry)
+static unsigned long sun4c_vmalloc_start(void)
 {
-	entry->next = head;
-	(entry->prev = head->prev)->next = entry;
-	head->prev = entry;
+	return SUN4C_VMALLOC_START;
 }
-#define add_to_used_pseg_list(entry) add_pseg_list(&s4cpseg_used, entry)
-#define add_to_free_pseg_list(entry) add_pseg_list(&s4cpseg_free, entry)
-#define add_to_locked_pseg_list(entry) add_pseg_list(&s4cpseg_locked, entry)
 
-static inline void remove_pseg_list(struct pseg_list *entry)
+static int sun4c_pte_none(pte_t pte)		{ return !pte_val(pte); }
+static int sun4c_pte_present(pte_t pte)	        { return pte_val(pte) & _SUN4C_PAGE_VALID; }
+static int sun4c_pte_inuse(pte_t *ptep)         { return mem_map[MAP_NR(ptep)].reserved || mem_map[MAP_NR(ptep)].count != 1; }
+static void sun4c_pte_clear(pte_t *ptep)	{ pte_val(*ptep) = 0; }
+static void sun4c_pte_reuse(pte_t *ptep)
 {
-	entry->next->prev = entry->prev;
-	entry->prev->next = entry->next;
+	if(!mem_map[MAP_NR(ptep)].reserved)
+		mem_map[MAP_NR(ptep)].count++;
 }
 
-static inline void add_pseg_ctxlist(struct pseg_list *entry, int ctx)
+static int sun4c_pmd_none(pmd_t pmd)		{ return !pmd_val(pmd); }
+static int sun4c_pmd_bad(pmd_t pmd)
 {
-	struct pseg_list *head = &s4cpseg_per_context[ctx];
-
-	entry->ctx_next = head;
-	(entry->ctx_prev = head->ctx_prev)->ctx_next = entry;
-	head->ctx_prev = entry;
-	pseg_count_per_context[ctx]++;
+	return (pmd_val(pmd) & ~PAGE_MASK) != PGD_TABLE || pmd_val(pmd) > high_memory;
 }
 
-static inline void remove_pseg_ctxlist(struct pseg_list *entry, int ctx)
-{
-	entry->ctx_next->ctx_prev = entry->ctx_prev;
-	entry->ctx_prev->ctx_next = entry->ctx_next;
-	pseg_count_per_context[ctx]--;
-}
+static int sun4c_pmd_present(pmd_t pmd)	        { return pmd_val(pmd) & PGD_PRESENT; }
+static int sun4c_pmd_inuse(pmd_t *pmdp)         { return 0; }
+static void sun4c_pmd_clear(pmd_t *pmdp)	{ pmd_val(*pmdp) = 0; }
+static void sun4c_pmd_reuse(pmd_t * pmdp)       { }
+
+static int sun4c_pgd_none(pgd_t pgd)		{ return 0; }
+static int sun4c_pgd_bad(pgd_t pgd)		{ return 0; }
+static int sun4c_pgd_present(pgd_t pgd)	        { return 1; }
+static int sun4c_pgd_inuse(pgd_t *pgdp)         { return mem_map[MAP_NR(pgdp)].reserved; }
+static void sun4c_pgd_clear(pgd_t * pgdp)	{ }
 
-static inline void sun4c_init_pseg_lists(void)
-{
-	int i;
+/*
+ * The following only work if pte_present() is true.
+ * Undefined behaviour if not..
+ */
+static int sun4c_pte_write(pte_t pte)		{ return pte_val(pte) & _SUN4C_PAGE_WRITE; }
+static int sun4c_pte_dirty(pte_t pte)		{ return pte_val(pte) & _SUN4C_PAGE_DIRTY; }
+static int sun4c_pte_young(pte_t pte)		{ return pte_val(pte) & _SUN4C_PAGE_REF; }
+
+static pte_t sun4c_pte_wrprotect(pte_t pte)	{ pte_val(pte) &= ~_SUN4C_PAGE_WRITE; return pte; }
+static pte_t sun4c_pte_mkclean(pte_t pte)	{ pte_val(pte) &= ~_SUN4C_PAGE_DIRTY; return pte; }
+static pte_t sun4c_pte_mkold(pte_t pte)	        { pte_val(pte) &= ~_SUN4C_PAGE_REF; return pte; }
+static pte_t sun4c_pte_mkwrite(pte_t pte)	{ pte_val(pte) |= _SUN4C_PAGE_WRITE; return pte; }
+static pte_t sun4c_pte_mkdirty(pte_t pte)	{ pte_val(pte) |= _SUN4C_PAGE_DIRTY; return pte; }
+static pte_t sun4c_pte_mkyoung(pte_t pte)	{ pte_val(pte) |= _SUN4C_PAGE_REF; return pte; }
 
-	s4cpseg_free.prev = s4cpseg_free.next = &s4cpseg_free;
-	s4cpseg_used.prev = s4cpseg_used.next = &s4cpseg_used;
-	s4cpseg_locked.prev = s4cpseg_locked.next = &s4cpseg_locked;
-	for(i = 0; i < num_contexts; i++) {
-		s4cpseg_per_context[i].ctx_prev = s4cpseg_per_context[i].ctx_next =
-			&s4cpseg_per_context[i];
-	}
-	for(i = 0; i <= invalid_segment; i++) {
-		s4cpseg_pool[i].vaddr = 0;
-		s4cpseg_pool[i].context = 0;
-		s4cpseg_pool[i].ref_cnt = 0;
-		s4cpseg_pool[i].hardlock = 0;
-		s4cpseg_pool[i].pseg = i;
-	}
-	s4cpseg_pool[invalid_segment].hardlock = 1;
+/*
+ * Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ */
+static pte_t sun4c_mk_pte(unsigned long page, pgprot_t pgprot)
+{
+	return __pte(((page - PAGE_OFFSET) >> PAGE_SHIFT) | pgprot_val(pgprot));
 }
 
-static inline void sun4c_distribute_kernel_mapping(unsigned long address,
-						   unsigned char pseg)
+static pte_t sun4c_mk_pte_io(unsigned long page, pgprot_t pgprot)
 {
-	unsigned int flags;
-	int ctx, save_ctx;
-
-	save_flags(flags); cli();
-	save_ctx = get_context();
-	flush_user_windows();
-	for(ctx = 0; ctx < num_contexts; ctx++) {
-		set_context(ctx);
-		put_segmap(address, pseg);
-	}
-	set_context(save_ctx);
-	restore_flags(flags);
+	return __pte(((page - PAGE_OFFSET) >> PAGE_SHIFT) | pgprot_val(pgprot));
 }
 
-static inline void sun4c_delete_kernel_mapping(unsigned long address)
+static pte_t sun4c_pte_modify(pte_t pte, pgprot_t newprot)
 {
-	unsigned int flags;
-	int ctx, save_ctx;
-
-	save_flags(flags); cli();
-	save_ctx = get_context();
-	flush_user_windows();
-
-	/* Flush only needed in one context for kernel mappings. */
-	sun4c_flush_segment(address);
-	for(ctx = 0; ctx < num_contexts; ctx++) {
-		set_context(ctx);
-		put_segmap(address, invalid_segment);
-	}
-	set_context(save_ctx);
-	restore_flags(flags);
+	return __pte((pte_val(pte) & _SUN4C_PAGE_CHG_MASK) | pgprot_val(newprot));
 }
 
-/* NOTE: You can only lock kernel tlb entries, attempts to lock
- *       pages in user vm will bolix the entire system.
- */
-static inline void sun4c_lock_tlb_entry(unsigned long address)
+static unsigned long sun4c_pte_page(pte_t pte)
 {
-	unsigned long flags;
-	unsigned char pseg;
-
-	save_flags(flags); cli();
-	/* Fault it in. */
-	__asm__ __volatile__("ldub [%0], %%g0\n\t" : : "r" (address));
-	address &= SUN4C_REAL_PGDIR_MASK;
-	pseg = get_segmap(address);
-	if(address < KERNBASE)
-		panic("locking user address space into tlb!");
-	if(pseg == invalid_segment)
-		panic("cannot lock kernel tlb entry...");
-	if(!s4cpseg_pool[pseg].ref_cnt++ && !s4cpseg_pool[pseg].hardlock) {
-		/* Move from used to locked list. */
-		remove_pseg_list(&s4cpseg_pool[pseg]);
-		add_to_locked_pseg_list(&s4cpseg_pool[pseg]);
-	}
-	restore_flags(flags);
+	return (PAGE_OFFSET + ((pte_val(pte) & 0xffff) << (PAGE_SHIFT)));
 }
 
-static inline void sun4c_unlock_tlb_entry(unsigned long address)
+static unsigned long sun4c_pmd_page(pmd_t pmd)
 {
-	unsigned long flags;
-	struct pseg_list *psegp;
-	unsigned char pseg;
-
-	save_flags(flags); cli();
-	address &= SUN4C_REAL_PGDIR_MASK;
-	pseg = get_segmap(address);
-	if(address < KERNBASE)
-		panic("unlocking user tlb entry!");
-	if(pseg == invalid_segment)
-		panic("unlocking non-locked kernel tlb entry...");
-	psegp = &s4cpseg_pool[pseg];
-	if(!--psegp->ref_cnt && !psegp->hardlock) {
-		/* Move from locked list to used list. */
-		remove_pseg_list(psegp);
-		add_to_used_pseg_list(psegp);
-	}
-	restore_flags(flags);
+	return (pmd_val(pmd) & PAGE_MASK);
 }
 
-/* Anyone who calls this must turn _all_ interrupts off and flush
- * any necessary user windows beforehand.
- */
-static inline void sun4c_unload_context_from_tlb(unsigned char ctx)
+/* to find an entry in a page-table-directory */
+static pgd_t *sun4c_pgd_offset(struct mm_struct * mm, unsigned long address)
 {
-	struct pseg_list *psegp, *pnextp;
-
-	if(pseg_count_per_context[ctx]) {
-		sun4c_flush_context(); /* Most efficient */
-		psegp = s4cpseg_per_context[ctx].ctx_next;
-		while(psegp != &s4cpseg_per_context[ctx]) {
-			pnextp = psegp->ctx_next;
-			if(psegp->vaddr >= KERNBASE)
-				panic("Unloading kernel from tlb, not good.");
-			put_segmap(psegp->vaddr, invalid_segment);
-			remove_pseg_ctxlist(psegp, ctx);
-			remove_pseg_list(psegp);
-			add_to_free_pseg_list(psegp);
-			psegp = pnextp;
-		}
-		if(pseg_count_per_context[ctx])
-			panic("pseg_count_per_context inconsistant after "
-			      "invalidate.");
-	}
+	return mm->pgd + (address >> SUN4C_PGDIR_SHIFT);
 }
 
-/* This page must be a page in user vma... again all IRQ's gotta be off. */
-static inline void sun4c_unload_page_from_tlb(unsigned long addr,
-					      struct task_struct *tsk)
+/* Find an entry in the second-level page table.. */
+static pmd_t *sun4c_pmd_offset(pgd_t * dir, unsigned long address)
 {
-	unsigned char save_ctx;
-
-	if(tsk->tss.context != -1) {
-		save_ctx = get_context();
-		flush_user_windows();
-		set_context(tsk->tss.context);
-		sun4c_flush_page(addr);
-		put_pte(addr, 0);
-		set_context(save_ctx);
-	}
+	return (pmd_t *) dir;
 }
 
-/* NOTE: When we have finer grained invalidate()'s (RSN) this
- *       whole scheme will be much more efficient and need to
- *       be re-written.  Also note that this routine only
- *       unloads user page translations, this may need to
- *       be changed at some point.
- */
-void sun4c_invalidate(void)
+/* Find an entry in the third-level page table.. */ 
+static pte_t *sun4c_pte_offset(pmd_t * dir, unsigned long address)
 {
-	int orig_ctx, cur_ctx, flags;
-
-	save_flags(flags); cli();
-	flush_user_windows();
-	orig_ctx = get_context();
-	for(cur_ctx = 0; cur_ctx < num_contexts; cur_ctx++) {
-		set_context(cur_ctx);
-		sun4c_unload_context_from_tlb(cur_ctx);
-	}
-	set_context(orig_ctx);
-	restore_flags(flags);
+	return (pte_t *) sun4c_pmd_page(*dir) +	((address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1));
 }
 
-/* We're only updating software tables on the sun4c. */
-void sun4c_set_pte(pte_t *ptep, pte_t pteval)
+/* Update the root mmu directory. */
+static void sun4c_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdir)
 {
-	*ptep = pteval;
 }
 
-/* Now back to the mid-level interface code:
- *
- * Allocate and free page tables. The xxx_kernel() versions are
+/* Allocate and free page tables. The xxx_kernel() versions are
  * used to allocate a kernel page table - this turns on ASN bits
  * if any, and marks the page tables reserved.
  */
-void sun4c_pte_free_kernel(pte_t *pte)
+static void sun4c_pte_free_kernel(pte_t *pte)
 {
 	mem_map[MAP_NR(pte)].reserved = 0;
 	free_page((unsigned long) pte);
 }
 
-pte_t *sun4c_pte_alloc_kernel(pmd_t *pmd, unsigned long address)
+static pte_t *sun4c_pte_alloc_kernel(pmd_t *pmd, unsigned long address)
 {
 	address = (address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1);
 	if (sun4c_pmd_none(*pmd)) {
@@ -406,22 +1244,22 @@
  * allocating and freeing a pmd is trivial: the 1-entry pmd is
  * inside the pgd, so has no extra memory associated with it.
  */
-void sun4c_pmd_free_kernel(pmd_t *pmd)
+static void sun4c_pmd_free_kernel(pmd_t *pmd)
 {
 	pmd_val(*pmd) = 0;
 }
 
-pmd_t *sun4c_pmd_alloc_kernel(pgd_t *pgd, unsigned long address)
+static pmd_t *sun4c_pmd_alloc_kernel(pgd_t *pgd, unsigned long address)
 {
 	return (pmd_t *) pgd;
 }
 
-void sun4c_pte_free(pte_t *pte)
+static void sun4c_pte_free(pte_t *pte)
 {
 	free_page((unsigned long) pte);
 }
 
-pte_t *sun4c_pte_alloc(pmd_t * pmd, unsigned long address)
+static pte_t *sun4c_pte_alloc(pmd_t * pmd, unsigned long address)
 {
 	address = (address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1);
 	if (sun4c_pmd_none(*pmd)) {
@@ -448,606 +1286,70 @@
  * allocating and freeing a pmd is trivial: the 1-entry pmd is
  * inside the pgd, so has no extra memory associated with it.
  */
-void sun4c_pmd_free(pmd_t * pmd)
+static void sun4c_pmd_free(pmd_t * pmd)
 {
 	pmd_val(*pmd) = 0;
 }
 
-pmd_t *sun4c_pmd_alloc(pgd_t * pgd, unsigned long address)
+static pmd_t *sun4c_pmd_alloc(pgd_t * pgd, unsigned long address)
 {
 	return (pmd_t *) pgd;
 }
 
-void sun4c_pgd_free(pgd_t *pgd)
+static void sun4c_pgd_free(pgd_t *pgd)
 {
 	free_page((unsigned long) pgd);
 }
 
-pgd_t *sun4c_pgd_alloc(void)
-{
-	unsigned long new_pgd = get_free_page(GFP_KERNEL);
-	return (pgd_t *) new_pgd;
-}
-
-/* Jumping to and fro different contexts, the modifying of the pseg lists
- * must be atomic during the switch, or else...
- */
-void sun4c_switch_to_context(void *new_task)
-{
-	struct task_struct *tsk = (struct task_struct *) new_task;
-	struct task_struct *old_tsk;
-	struct ctx_list *ctxp;
-	unsigned long flags;
-	int ctx = tsk->tss.context;
-
-	/* Swapper can execute in any context, or this task
-	 * has already been allocated a piece of the mmu real-
-	 * estate.
-	 */
-	if(tsk->pid == 0 || ctx != -1)
-		return;
-	ctxp = ctx_free.next;
-	if(ctxp != &ctx_free) {
-		save_flags(flags); cli();
-		ctx = ctxp->ctx_number;
-		remove_from_ctx_list(ctxp);
-		add_to_used_ctxlist(ctxp);
-		tsk->tss.context = ctx;
-		ctxp->ctx_task = tsk;
-		restore_flags(flags);
-		return;
-	}
-	save_flags(flags); cli();
-	ctxp = ctx_used.prev;
-	/* Don't steal from current, thank you. */
-	if(ctxp->ctx_task == current)
-		ctxp = ctxp->prev;
-	if(ctxp == &ctx_used)
-		panic("out of contexts");
-	remove_from_ctx_list(ctxp);
-	old_tsk = ctxp->ctx_task;
-	old_tsk->tss.context = -1;
-	ctxp->ctx_task = tsk;
-	tsk->tss.context = ctxp->ctx_number;
-	add_to_used_ctxlist(ctxp);
-	/* User windows flushed already by switch_to(p) macro. */
-	set_context(ctxp->ctx_number);
-	sun4c_unload_context_from_tlb(ctxp->ctx_number);
-	restore_flags(flags);
-}
-
-/* Low level IO area allocation on the Sun4c MMU.  This function is called
- * for each page of IO area you need.  Kernel code should not call this
- * routine directly, use sparc_alloc_io() instead.
- */
-void sun4c_mapioaddr(unsigned long physaddr, unsigned long virt_addr,
-		     int bus_type, int rdonly)
-{
-	unsigned long page_entry;
-
-	page_entry = ((physaddr >> PAGE_SHIFT) & 0xffff);
-	page_entry |= (_SUN4C_PAGE_VALID | _SUN4C_PAGE_WRITE |
-		       _SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_IO);
-	if(rdonly)
-		page_entry &= (~_SUN4C_PAGE_WRITE);
-	sun4c_flush_page(virt_addr);
-	put_pte(virt_addr, page_entry);
-}
-
-/* These routines are used to lock down and unlock data transfer
- * areas in the sun4c tlb.  If the pages need to be uncached the
- * caller must do that himself.
- */
-inline char *sun4c_lockarea(char *vaddr, unsigned long size)
-{
-	unsigned long flags;
-	unsigned long orig_addr = (unsigned long) vaddr;
-	unsigned long first_seg = (orig_addr & SUN4C_REAL_PGDIR_MASK);
-	unsigned long last_seg = ((orig_addr + size) & SUN4C_REAL_PGDIR_MASK);
-
-	save_flags(flags); cli();
-	for(; first_seg <= last_seg; first_seg += SUN4C_REAL_PGDIR_SIZE)
-		sun4c_lock_tlb_entry(first_seg);
-
-	restore_flags(flags);
-	return vaddr;
-}
-
-/* Note that when calling unlockarea you pass as 'vaddr' the address that
- * was returned to you by lockarea for this pool above.
- */
-inline void sun4c_unlockarea(char *vaddr, unsigned long size)
-{
-	unsigned long flags;
-	unsigned long orig_addr = (unsigned long) vaddr;
-	unsigned long first_seg = (orig_addr & SUN4C_REAL_PGDIR_MASK);
-	unsigned long last_seg = ((orig_addr + size) & SUN4C_REAL_PGDIR_MASK);
-
-	save_flags(flags); cli();
-	for(; first_seg <= last_seg; first_seg += SUN4C_REAL_PGDIR_SIZE)
-		sun4c_unlock_tlb_entry(first_seg);
-
-	restore_flags(flags);
-}
-
-/* Getting and Releasing scsi dvma buffers. */
-char *sun4c_get_scsi_buffer(char *bufptr, unsigned long len)
-{
-	unsigned long first_page = ((unsigned long) bufptr) & PAGE_MASK;
-	unsigned long last_page = (((unsigned long) bufptr) + len) & PAGE_MASK;
-
-	/* First lock down the area. */
-	bufptr = sun4c_lockarea(bufptr, len);
-
-	/* Uncache and flush all the pages. */
-	for(; first_page <= last_page; first_page += PAGE_SIZE) {
-		sun4c_flush_page(first_page);
-		put_pte(first_page, get_pte(first_page) | PTE_NC);
-	}
-	return bufptr;
-}
-
-void sun4c_release_scsi_buffer(char *bufptr, unsigned long len)
-{
-	unsigned long first_page = ((unsigned long) bufptr) & PAGE_MASK;
-	unsigned long last_page = (((unsigned long) bufptr) + len) & PAGE_MASK;
-
-
-	/* Recache all the pages. */
-	for(; first_page <= last_page; first_page += PAGE_SIZE)
-		put_pte(first_page, get_pte(first_page) & ~PTE_NC);
-
-	sun4c_unlockarea(bufptr, len);
-}
-
-/* Code to fill the sun4c tlb during a fault.  Plus fault helper routine. */
-int sun4c_get_fault_info(unsigned long *address, unsigned long *error_code,
-			 unsigned long from_user)
-{
-	unsigned long faddr, fstatus, new_code;
-
-	faddr = sun4c_get_synchronous_address();
-	*address = faddr;
-	if(faddr >= 0x20000000 && faddr < 0xe0000000) {
-		printk("SUN4C: Fault in vm hole at %08lx\n", faddr);
-		*error_code = from_user;
-		return 1;
-	}
-	fstatus = sun4c_get_synchronous_error();
-	if(fstatus & SUN4C_SYNC_BOLIXED)
-		panic("SUN4C: Unrecoverable fault type.");
-	new_code = 0;
-	if(fstatus & SUN4C_SYNC_PROT)
-		new_code |= FAULT_CODE_PROT;
-	if(fstatus & SUN4C_SYNC_BADWRITE)
-		new_code |= FAULT_CODE_WRITE;
-	*error_code = (new_code | from_user);
-	return 0;
-}
-
-static inline void sun4c_alloc_pseg(unsigned long address)
-{
-	struct pseg_list *psegp;
-	unsigned char cur_ctx = get_context();
-	int kernel_address = (address >= KERNBASE);
-	int user_address = !kernel_address;
-
-	psegp = s4cpseg_free.next;
-	if(psegp != &s4cpseg_free) {
-		remove_pseg_list(psegp);
-		add_to_used_pseg_list(psegp);
-		if(user_address)
-			add_pseg_ctxlist(psegp, cur_ctx);
-		psegp->vaddr = address;
-		psegp->context = cur_ctx;
-		/* No cache flush needed */
-		if(kernel_address)
-			sun4c_distribute_kernel_mapping(address, psegp->pseg);
-		else
-			put_segmap(address, psegp->pseg);
-		return;
-	}
-	psegp = s4cpseg_used.prev; /* Take last used list entry. */
-	if(psegp == &s4cpseg_used)
-		panic("Sun4c psegs have disappeared...");
-	if(psegp->vaddr >= KERNBASE) {
-		sun4c_delete_kernel_mapping(psegp->vaddr);
-	} else {
-		flush_user_windows();
-		set_context(psegp->context);
-		sun4c_flush_segment(psegp->vaddr);
-		put_segmap(psegp->vaddr, invalid_segment);
-		set_context(cur_ctx);
-	}
-	remove_pseg_list(psegp);
-	if(psegp->vaddr < KERNBASE)
-		remove_pseg_ctxlist(psegp, psegp->context);
-	psegp->vaddr = address;
-	psegp->context = cur_ctx;
-	if(kernel_address)
-		sun4c_distribute_kernel_mapping(address, psegp->pseg);
-	else
-		put_segmap(address, psegp->pseg);
-	add_to_used_pseg_list(psegp);
-	if(user_address)
-		add_pseg_ctxlist(psegp, cur_ctx);
-}
-
-/*
- * handle_mm_fault() gets here so that we can update our 'view'
- * of a new address translation.  A lot of the time, mappings
- * don't change and we are just 'working the tlb cache'.
- */
-void sun4c_update_mmu_cache(struct vm_area_struct * vma,
-			    unsigned long address, pte_t pte)
-{
-	unsigned long flags, segmap, segaddr, clean;
-
-	save_flags(flags); cli();
-	address &= PAGE_MASK;
-	segaddr = address & SUN4C_REAL_PGDIR_MASK;
-	segmap = get_segmap(segaddr);
-	if(segmap == invalid_segment) {
-		sun4c_alloc_pseg(segaddr);
-		/* XXX make segmap freeing routines do this. XXX */
-		for(clean = segaddr; clean < (segaddr + SUN4C_REAL_PGDIR_SIZE);
-		    clean += PAGE_SIZE)
-			put_pte(clean, 0);
-	}
-
-	/* If this is a user fault, only load the one pte so that
-	 * the kernel's ref/mod bits accurately reflect what is
-	 * in the tlb.  handle_pte_fault() causes this to work.
-	 */
-	if(address < TASK_SIZE)
-		put_pte(address, pte_val(pte));
-	else {
-		/* We have a kernel fault here, load entire segment. */
-		pgd_t *pgdp;
-		pte_t *ptable;
-		int pnum = 64;
-
-		pgdp = sun4c_pgd_offset(&init_mm, segaddr);
-		ptable = sun4c_pte_offset((pmd_t *)pgdp, segaddr);
-		while(pnum--) {
-			put_pte(segaddr, pte_val(*ptable++));
-			segaddr += PAGE_SIZE;
-		};
-	}
-	restore_flags(flags);
-}
-
-/* Paging initialization on the Sun4c. */
-static inline void sun4c_free_all_nonlocked_psegs(void)
-{
-	struct pseg_list *plp;
-	int i;
-
-	for(i=0; i < invalid_segment; i++)
-		if(!s4cpseg_pool[i].hardlock)
-			add_to_free_pseg_list(&s4cpseg_pool[i]);
-	/* Now for every free pseg, make all the ptes invalid. */
-	plp = s4cpseg_free.next;
-	while(plp != &s4cpseg_free) {
-		put_segmap(0x0, plp->pseg);
-		for(i=0; i<64; i++)
-			put_pte((i * PAGE_SIZE), 0x0);
-		plp = plp->next;
-	}
-	put_segmap(0x0, invalid_segment);
-}
-
-static inline struct pseg_list *sun4c_alloc_pseg_from_free_list(void)
-{
-	struct pseg_list *psegp;
-
-	psegp = s4cpseg_free.next;
-	if(psegp != &s4cpseg_free) {
-		remove_pseg_list(psegp);
-		return psegp;
-	}
-	return 0;
-}
-
-static inline void sun4c_init_lock_area(unsigned long start_addr,
-					unsigned long end_addr)
-{
-	struct pseg_list *psegp;
-	unsigned long a;
-	int ctx;
-
-	for(a = start_addr; a < end_addr; a += SUN4C_REAL_PGDIR_SIZE) {
-		psegp = sun4c_alloc_pseg_from_free_list();
-		if(!psegp) {
-			prom_printf("whoops...");
-			prom_halt();
-		}
-		for(ctx=0;ctx<num_contexts;ctx++)
-			prom_putsegment(ctx,a,psegp->pseg);
-		add_to_locked_pseg_list(psegp);
-		psegp->hardlock = 1;
-	}
-}
-
-static inline void sun4c_check_for_ss2_cache_bug(void)
+static pgd_t *sun4c_pgd_alloc(void)
 {
-	extern unsigned long start;
-
-	/* Well we've now got a problem, on the SS2 a cache bug
-	 * causes line entries to get severely corrupted if the
-	 * trap table is able to be cached.  A sane and simple
-	 * workaround, at least for now, is to mark the trap
-	 * table page as uncacheable.
-	 *
-	 * XXX Investigate other possible workarounds and see
-	 * XXX if they help performance enough to warrant using
-	 * XXX them.                      -- 8/6/95 davem
-	 */
-	if(idprom->id_machtype == (SM_SUN4C | SM_4C_SS2)) {
-		/* Whee.. */
-		printk("SS2 cache bug detected, uncaching trap table page\n");
-		sun4c_flush_page((unsigned int) &start);
-		put_pte(((unsigned long) &start),
-			(get_pte((unsigned long) &start) | PTE_NC));
-	}
+	return (pgd_t *) get_free_page(GFP_KERNEL);
 }
 
+#define SUN4C_KERNEL_BUCKETS   16
 extern unsigned long free_area_init(unsigned long, unsigned long);
-
-/* Whee, this is now *ultra* clean and more managable */
+extern unsigned long sparc_context_init(unsigned long, int);
 extern unsigned long end;
-extern void probe_mmu(void);
 
 unsigned long sun4c_paging_init(unsigned long start_mem, unsigned long end_mem)
 {
-	unsigned long addr, vaddr, kern_begin, kern_end;
-	unsigned long prom_begin, prom_end, kadb_begin;
-	pgd_t *pgdp;
-	pte_t *pg_table;
-	int phys_seg, i, ctx;
-
-	start_mem = PAGE_ALIGN(start_mem);
+	int i, cnt;
+	unsigned long kernel_end;
 
-	probe_mmu();
+	kernel_end = (unsigned long) &end;
+	kernel_end += (SUN4C_REAL_PGDIR_SIZE * 3);
+	kernel_end = SUN4C_REAL_PGDIR_ALIGN(kernel_end);
+	sun4c_probe_mmu();
 	invalid_segment = (num_segmaps - 1);
-	sun4c_init_pseg_lists();
-	for(kern_begin = KERNBASE;
-	    kern_begin < (unsigned long) &end;
-	    kern_begin += SUN4C_REAL_PGDIR_SIZE) {
-		unsigned char pseg = get_segmap(kern_begin);
-
-		s4cpseg_pool[pseg].hardlock=1;
-		for(ctx=0; ctx<num_contexts;ctx++)
-			prom_putsegment(ctx,kern_begin,pseg);
-	}
-	for(kern_begin = SUN4C_REAL_PGDIR_ALIGN((unsigned long) &end);
-	    kern_begin < KADB_DEBUGGER_BEGVM;
-	    kern_begin += SUN4C_REAL_PGDIR_SIZE)
-		for(ctx=0; ctx<num_contexts;ctx++)
-			prom_putsegment(ctx, kern_begin, invalid_segment);
-	for(prom_begin = KADB_DEBUGGER_BEGVM;
-	    prom_begin < LINUX_OPPROM_ENDVM;
-	    prom_begin += SUN4C_REAL_PGDIR_SIZE) {
-		unsigned long pseg = get_segmap(prom_begin);
-
-		if(pseg != invalid_segment) {
-			s4cpseg_pool[pseg].hardlock=1;
-			for(ctx=0; ctx<num_contexts; ctx++)
-				prom_putsegment(ctx,prom_begin,pseg);
-		}
-	}
-	/* Clean the MMU of excess garbage... */
-	for(ctx=0; ctx<num_contexts;ctx++) {
-		set_context(ctx);
-		for(vaddr = 0; vaddr < 0x20000000;
-		    vaddr += SUN4C_REAL_PGDIR_SIZE)
-			put_segmap(vaddr,invalid_segment);
-		for(vaddr = 0xe0000000; vaddr < KERNBASE;
-		    vaddr += SUN4C_REAL_PGDIR_SIZE)
-			put_segmap(vaddr,invalid_segment);
-		for(vaddr = LINUX_OPPROM_ENDVM; vaddr != 0;
-		    vaddr += SUN4C_REAL_PGDIR_SIZE)
-			put_segmap(vaddr,invalid_segment);
-	}
-	set_context(0);
-	sun4c_free_all_nonlocked_psegs();
-	/* Lock I/O and DVMA areas for the system. */
+	sun4c_init_mmu_entry_pool();
+	sun4c_init_rings();
+	sun4c_init_map_kernelprom(kernel_end);
+	sun4c_init_clean_mmu(kernel_end);
+	sun4c_init_fill_kernel_ring(SUN4C_KERNEL_BUCKETS);
 	sun4c_init_lock_area(IOBASE_VADDR, IOBASE_END);
 	sun4c_init_lock_area(DVMA_VADDR, DVMA_END);
-	/* Zero out swapper_pg_dir and pg0 */
+	start_mem = sun4c_init_lock_areas(start_mem);
+	sun4c_init_fill_user_ring();
+
+	sun4c_set_context(0);
 	memset(swapper_pg_dir, 0, PAGE_SIZE);
 	memset(pg0, 0, PAGE_SIZE);
-	/* This makes us Solaris boot-loader 'safe' */
-	pgd_val(swapper_pg_dir[KERNBASE>>SUN4C_PGDIR_SHIFT]) =
+	/* Save work later. */
+	pgd_val(swapper_pg_dir[SUN4C_VMALLOC_START>>SUN4C_PGDIR_SHIFT]) =
 		PGD_TABLE | (unsigned long) pg0;
-
-	/* Initialize swapper_pg_dir to map the kernel
-	 * addresses in high memory.  Note that as soon as we get past
-	 * the 4MB lower mapping and start using dynamic memory from
-	 * start_mem we can start faulting and this is ok since our
-	 * pseg free list and the lower 4MB of the kernel is mapped
-	 * properly in the software page tables.
-	 */
-	pgdp = swapper_pg_dir;
-	kern_end = PAGE_ALIGN(end_mem);
-	kern_begin = KERNBASE;
-	while(kern_begin < kern_end) {
-		unsigned long pte, tmp;
-
-		/* We only need _one_ mapping, the high address one. */
-		pg_table = (pte_t *) (PAGE_MASK & pgd_val(pgdp[KERNBASE>>SUN4C_PGDIR_SHIFT]));
-		if(!pg_table) {
-			pg_table = (pte_t *) start_mem;
-			start_mem += PAGE_SIZE;
-		}
-		pgd_val(pgdp[KERNBASE>>SUN4C_PGDIR_SHIFT]) =
-			PGD_TABLE | (unsigned long) pg_table;
-		pgdp++;
-		for(tmp = 0; tmp < SUN4C_PTRS_PER_PTE; tmp++, pg_table++) {
-			if(kern_begin < kern_end)
-				sun4c_set_pte(pg_table,
-					      mk_pte(kern_begin,
-						     SUN4C_PAGE_SHARED));
-			else
-				sun4c_pte_clear(pg_table);
-			pte = get_pte(kern_begin);
-			if(pte & _SUN4C_PAGE_VALID) {
-				pte &= ~(_SUN4C_PAGE_NOCACHE);
-				pte |= (_SUN4C_PAGE_PRIV | _SUN4C_PAGE_WRITE |
-					_SUN4C_PAGE_REF | _SUN4C_PAGE_DIRTY);
-				put_pte(kern_begin, pte);
-			}
-			kern_begin += PAGE_SIZE;
-		}
-	}
-	sun4c_check_for_ss2_cache_bug();
-	/* Fix kadb/prom permissions. */
-	kadb_begin = KADB_DEBUGGER_BEGVM;
-	prom_end = LINUX_OPPROM_ENDVM;
-	for(; kadb_begin < prom_end; kadb_begin += PAGE_SIZE) {
-		unsigned long pte = get_pte(kadb_begin);
-		if(pte & _SUN4C_PAGE_VALID)
-			put_pte(kadb_begin, (pte | _SUN4C_PAGE_PRIV));
-	}
-	/* Allocate the DVMA pages */
-	addr = DVMA_VADDR;
-	start_mem = PAGE_ALIGN(start_mem);
-	while(addr < DVMA_END) {
-		unsigned long dvmapte = start_mem - PAGE_OFFSET;
-
-		start_mem += PAGE_SIZE;
-		dvmapte = ((dvmapte>>PAGE_SHIFT) & 0xffff);
-		dvmapte |= (_SUN4C_PAGE_VALID |
-			    _SUN4C_PAGE_WRITE |
-			    _SUN4C_PAGE_NOCACHE);
-		put_pte(addr, dvmapte);
-		addr += PAGE_SIZE;
-	}
-	/* Tell the user our allocations */
-	for(phys_seg=0, i=0; i<=invalid_segment; i++)
-		if(s4cpseg_pool[i].hardlock)
-			phys_seg++;
-	printk("SUN4C: Hard locked %d boot-up psegs\n", phys_seg);
-	/* Init the context pool and lists */
-	ctx_list_pool = (struct ctx_list *) start_mem;
-	start_mem += (num_contexts * sizeof(struct ctx_list));
-	for(ctx = 0; ctx < num_contexts; ctx++) {
-		struct ctx_list *clist;
-
-		clist = (ctx_list_pool + ctx);
-		clist->ctx_number = ctx;
-		clist->ctx_task = 0;
-	}
-	ctx_free.next = ctx_free.prev = &ctx_free;
-	ctx_used.next = ctx_used.prev = &ctx_used;
-	for(ctx = 0; ctx < num_contexts; ctx++)
-		add_to_free_ctxlist(ctx_list_pool + ctx);
+	sun4c_init_ss2_cache_bug();
 	start_mem = PAGE_ALIGN(start_mem);
+	start_mem = sun4c_init_alloc_dvma_pages(start_mem);
+	start_mem = sparc_context_init(start_mem, num_contexts);
 	start_mem = free_area_init(start_mem, end_mem);
-	start_mem = PAGE_ALIGN(start_mem);
+	cnt = 0;
+	for(i = 0; i < num_segmaps; i++)
+		if(mmu_entry_pool[i].locked)
+			cnt++;
+	printk("SUN4C: %d mmu entries for the kernel\n", cnt);
 	return start_mem;
 }
 
-/* Test the WP bit on the sun4c. */
-void sun4c_test_wp(void)
-{
-	wp_works_ok = -1;
-
-	/* Let it rip... */
-	put_pte((unsigned long) 0x0, (PTE_V | PTE_P));
-	__asm__ __volatile__("st %%g0, [0x0]\n\t": : :"memory");
-	put_pte((unsigned long) 0x0, 0x0);
-	if (wp_works_ok < 0)
-		wp_works_ok = 0;
-}
-
-void sun4c_lock_entire_kernel(unsigned long start_mem)
-{
-	unsigned long addr = (unsigned long) &end;
-
-	addr = (addr & SUN4C_REAL_PGDIR_MASK);
-	start_mem = SUN4C_REAL_PGDIR_ALIGN(start_mem);
-	while(addr < start_mem) {
-		int pseg;
-
-		sun4c_lock_tlb_entry(addr);
-		pseg = get_segmap(addr);
-		if(!s4cpseg_pool[pseg].hardlock) {
-			s4cpseg_pool[pseg].hardlock = 1;
-			remove_pseg_list(&s4cpseg_pool[pseg]);
-		}
-		addr += SUN4C_REAL_PGDIR_SIZE;
-	}
-}
-
-static void sun4c_fork_hook(void *vtask, unsigned long kthread_usp)
-{
-	struct task_struct *new_task = vtask;
-
-	/* These pages must not cause a fault when traps
-	 * are off (such as in a window spill/fill) so
-	 * lock them down for the life of the task.
-	 */
-	sun4c_lock_tlb_entry((unsigned long) new_task);
-	sun4c_lock_tlb_entry(new_task->kernel_stack_page);
-	if(kthread_usp)
-		sun4c_lock_tlb_entry(kthread_usp);
-}
-
-static void sun4c_release_hook(void *vtask)
-{
-	struct task_struct *old_task = vtask;
-	struct ctx_list *ctx_old;
-	struct pt_regs *regs;
-	unsigned char this_ctx = get_context();
-	unsigned long flags;
-
-	save_flags(flags); cli();
-	if(old_task == &init_task)
-		panic("AIEEE releasing swapper");
-	if(old_task->tss.context != -1) {
-
-		/* Clear from the mmu, all notions of this dead task. */
-		flush_user_windows();
-		set_context(old_task->tss.context);
-		sun4c_unload_context_from_tlb(old_task->tss.context);
-		set_context(this_ctx);
-
-		ctx_old = ctx_list_pool + old_task->tss.context;
-		remove_from_ctx_list(ctx_old);
-		add_to_free_ctxlist(ctx_old);
-		old_task->tss.context = -1;
-	}
-	regs = (struct pt_regs *) 
-		(((old_task->tss.ksp & ~0xfff)) + (0x1000 - TRACEREG_SZ));
-	if(regs->u_regs[UREG_FP] > KERNBASE)
-		sun4c_unlock_tlb_entry(regs->u_regs[UREG_FP] & PAGE_MASK);
-	sun4c_unlock_tlb_entry(old_task->kernel_stack_page);
-	sun4c_unlock_tlb_entry((unsigned long) old_task);
-	restore_flags(flags);
-	/* bye bye... */
-}
-
-static void sun4c_flush_hook(void *vtask)
-{
-	struct task_struct *dead_task = vtask;
-
-	if(dead_task->tss.context != -1)
-		sun4c_flush_context();
-}
-
-static void sun4c_task_cacheflush(void *vtask)
-{
-	struct task_struct *flush_task = vtask;
-
-	if(flush_task->tss.context != -1)
-		sun4c_flush_context();
-}
-
-static void sun4c_exit_hook(void *vtask)
-{
-}
-
 /* Load up routines and constants for sun4c mmu */
 void ld_mmu_sun4c(void)
 {
@@ -1070,10 +1372,14 @@
 	page_copy = SUN4C_PAGE_COPY;
 	page_readonly = SUN4C_PAGE_READONLY;
 	page_kernel = SUN4C_PAGE_KERNEL;
-	page_invalid = SUN4C_PAGE_INVALID;
+	pg_iobits = _SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_IO | _SUN4C_PAGE_VALID
+	    | _SUN4C_PAGE_WRITE | _SUN4C_PAGE_DIRTY;
 	
 	/* Functions */
-	invalidate = sun4c_invalidate;
+	invalidate_all = sun4c_invalidate_all;
+	invalidate_mm = sun4c_invalidate_mm;
+	invalidate_range = sun4c_invalidate_range;
+	invalidate_page = sun4c_invalidate_page;
 	set_pte = sun4c_set_pte;
 	switch_to_context = sun4c_switch_to_context;
 	pmd_align = sun4c_pmd_align;
@@ -1105,6 +1411,7 @@
 	pgd_clear = sun4c_pgd_clear;
 
 	mk_pte = sun4c_mk_pte;
+	mk_pte_io = sun4c_mk_pte_io;
 	pte_modify = sun4c_pte_modify;
 	pgd_offset = sun4c_pgd_offset;
 	pmd_offset = sun4c_pmd_offset;
@@ -1120,35 +1427,31 @@
 	pgd_free = sun4c_pgd_free;
 	pgd_alloc = sun4c_pgd_alloc;
 
-	pte_read = sun4c_pte_read;
 	pte_write = sun4c_pte_write;
-	pte_exec = sun4c_pte_exec;
 	pte_dirty = sun4c_pte_dirty;
 	pte_young = sun4c_pte_young;
-	pte_cow = sun4c_pte_cow;
 	pte_wrprotect = sun4c_pte_wrprotect;
-	pte_rdprotect = sun4c_pte_rdprotect;
-	pte_exprotect = sun4c_pte_exprotect;
 	pte_mkclean = sun4c_pte_mkclean;
 	pte_mkold = sun4c_pte_mkold;
-	pte_uncow = sun4c_pte_uncow;
 	pte_mkwrite = sun4c_pte_mkwrite;
-	pte_mkread = sun4c_pte_mkread;
-	pte_mkexec = sun4c_pte_mkexec;
 	pte_mkdirty = sun4c_pte_mkdirty;
 	pte_mkyoung = sun4c_pte_mkyoung;
-	pte_mkcow = sun4c_pte_mkcow;
-	get_fault_info = sun4c_get_fault_info;
 	update_mmu_cache = sun4c_update_mmu_cache;
 	mmu_exit_hook = sun4c_exit_hook;
-	mmu_fork_hook = sun4c_fork_hook;
-	mmu_release_hook = sun4c_release_hook;
 	mmu_flush_hook = sun4c_flush_hook;
-	mmu_task_cacheflush = sun4c_task_cacheflush;
-	mmu_lockarea = sun4c_lockarea;
-	mmu_unlockarea = sun4c_unlockarea;
+	mmu_lockarea = sun4c_lockpage;
+	mmu_unlockarea = sun4c_unlockpage;
 	mmu_get_scsi_buffer = sun4c_get_scsi_buffer;
 	mmu_release_scsi_buffer = sun4c_release_scsi_buffer;
+	
+	/* Task struct and kernel stack allocating/freeing. */
+	alloc_kernel_stack = sun4c_alloc_kernel_stack;
+	alloc_task_struct = sun4c_alloc_task_struct;
+	free_kernel_stack = sun4c_free_kernel_stack;
+	free_task_struct = sun4c_free_task_struct;
+
+	quick_kernel_fault = sun4c_quick_kernel_fault;
+	mmu_info = sun4c_mmu_info;
 
 	/* These should _never_ get called with two level tables. */
 	pgd_set = 0;
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/mm/sun4c_vac.c linux/arch/sparc/mm/sun4c_vac.c
--- v1.3.70/linux/arch/sparc/mm/sun4c_vac.c	Sat Nov 25 19:04:38 1995
+++ linux/arch/sparc/mm/sun4c_vac.c	Thu Jan  1 02:00:00 1970
@@ -1,37 +0,0 @@
-/* $Id: sun4c_vac.c,v 1.5 1995/11/25 00:59:43 davem Exp $
- * vac.c:   Routines for flushing various amount of the Sparc VAC
- *          (virtual address cache) on the sun4c.
- *
- * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#include <linux/kernel.h>
-
-#include <asm/asi.h>
-#include <asm/contregs.h>
-#include <asm/vac-ops.h>
-#include <asm/page.h>
-
-struct sun4c_vac_props sun4c_vacinfo;
-
-/* Invalidate the entire sun4c VAC, it must be off at this point */
-void
-sun4c_flush_all(void)
-{
-	unsigned long begin, end;
-
-	if(sun4c_vacinfo.on)
-		panic("SUN4C: AIEEE, trying to invalidate vac while"
-                      " it is on.");
-
-	/* Clear 'valid' bit in all cache line tags */
-	begin = AC_CACHETAGS;
-	end = (AC_CACHETAGS + sun4c_vacinfo.num_bytes);
-	while(begin < end) {
-		__asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
-				     "r" (begin), "i" (ASI_CONTROL));
-		begin += sun4c_vacinfo.linesize;
-	}
-	return;
-}
-
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/prom/bootstr.c linux/arch/sparc/prom/bootstr.c
--- v1.3.70/linux/arch/sparc/prom/bootstr.c	Sat Nov 25 19:04:38 1995
+++ linux/arch/sparc/prom/bootstr.c	Mon Mar  4 08:49:58 1996
@@ -1,4 +1,4 @@
-/* $Id: bootstr.c,v 1.3 1995/11/25 00:59:51 davem Exp $
+/* $Id: bootstr.c,v 1.4 1996/02/08 07:06:43 zaitcev Exp $
  * bootstr.c:  Boot string/argument acquisition from the PROM.
  *
  * Copyright(C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -6,7 +6,7 @@
 
 #include <asm/oplib.h>
 
-static char barg_buf[128];
+static char barg_buf[256];
 
 char *
 prom_getbootargs(void)
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/prom/console.c linux/arch/sparc/prom/console.c
--- v1.3.70/linux/arch/sparc/prom/console.c	Sat Nov 25 19:04:38 1995
+++ linux/arch/sparc/prom/console.c	Mon Mar  4 08:49:58 1996
@@ -1,4 +1,4 @@
-/* $Id: console.c,v 1.5 1995/11/25 00:59:54 davem Exp $
+/* $Id: console.c,v 1.6 1996/01/01 02:46:27 davem Exp $
  * console.c: Routines that deal with sending and receiving IO
  *            to/from the current console device using the PROM.
  *
@@ -77,11 +77,38 @@
 enum prom_input_device
 prom_query_input_device()
 {
-	switch(*romvec->pv_stdin) {
-	case PROMDEV_KBD:	return PROMDEV_IKBD;
-	case PROMDEV_TTYA:	return PROMDEV_ITTYA;
-	case PROMDEV_TTYB:	return PROMDEV_ITTYB;
+	int st_p;
+	char propb[64];
+	char *p;
+
+	switch(prom_vers) {
+	case PROM_V0:
+	case PROM_V2:
 	default:
+		switch(*romvec->pv_stdin) {
+		case PROMDEV_KBD:	return PROMDEV_IKBD;
+		case PROMDEV_TTYA:	return PROMDEV_ITTYA;
+		case PROMDEV_TTYB:	return PROMDEV_ITTYB;
+		default:
+			return PROMDEV_I_UNK;
+		};
+	case PROM_V3:
+	case PROM_P1275:
+		st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdin);
+		if(prom_node_has_property(st_p, "keyboard"))
+			return PROMDEV_IKBD;
+		prom_getproperty(st_p, "device_type", propb, sizeof(propb));
+		if(strncmp(propb, "serial", sizeof("serial")))
+			return PROMDEV_I_UNK;
+		prom_getproperty(prom_root_node, "stdin-path", propb, sizeof(propb));
+		p = propb;
+		while(*p) p++; p -= 2;
+		if(p[0] == ':') {
+			if(p[1] == 'a')
+				return PROMDEV_ITTYA;
+			else if(p[1] == 'b')
+				return PROMDEV_ITTYB;
+		}
 		return PROMDEV_I_UNK;
 	};
 }
@@ -92,7 +119,8 @@
 prom_query_output_device()
 {
 	int st_p;
-	char propb[ sizeof("display") ];
+	char propb[64];
+	char *p;
 	int propl;
 
 	switch(prom_vers) {
@@ -113,12 +141,26 @@
 		{
 			return PROMDEV_OSCREEN;
 		}
-		/* This works on SS-2 (an early OpenFirmware) still. */
-		/* XXX fix for serial cases at SS-5.                 */
-		switch(*romvec->pv_stdin) {
-		case PROMDEV_TTYA:	return PROMDEV_OTTYA;
-		case PROMDEV_TTYB:	return PROMDEV_OTTYB;
-		};
+		if(prom_vers == PROM_V3) {
+			if(strncmp("serial", propb, sizeof("serial")))
+				return PROMDEV_O_UNK;
+			prom_getproperty(prom_root_node, "stdout-path", propb, sizeof(propb));
+			p = propb;
+			while(*p) p++; p -= 2;
+			if(p[0]==':') {
+				if(p[1] == 'a')
+					return PROMDEV_OTTYA;
+				else if(p[1] == 'b')
+					return PROMDEV_OTTYB;
+			}
+			return PROMDEV_O_UNK;
+		} else {
+			/* This works on SS-2 (an early OpenFirmware) still. */
+			switch(*romvec->pv_stdin) {
+			case PROMDEV_TTYA:	return PROMDEV_OTTYA;
+			case PROMDEV_TTYB:	return PROMDEV_OTTYB;
+			};
+		}
 		break;
 	};
 	return PROMDEV_O_UNK;
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/prom/devtree.c linux/arch/sparc/prom/devtree.c
--- v1.3.70/linux/arch/sparc/prom/devtree.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/prom/devtree.c	Mon Mar  4 08:49:58 1996
@@ -0,0 +1,114 @@
+/* devtree.c: Build a copy of the prom device tree in kernel
+ *            memory for easier access and cleaner interface.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+
+/* Add more as appropriate. */
+enum bus_t {
+	OBIO_BUS,
+	SBUS_BUS,
+	PCI_BUS,
+	PMEM_BUS,
+	CPU_BUS,
+};
+
+struct sdevmapping {
+	unsigned long physpage;
+	int mapsz;
+	enum bus_t where;
+};
+
+/* limitation of sparc arch. */
+#define NUM_SPARC_IRQS    15
+
+struct sdev_irqs {
+	int level;
+	int vector; /* For vme/sbus irq sharing methinks. */
+};
+
+struct sparcdev {
+	struct sparcdev *next;
+	struct sparcdev *prev;
+	int node;
+	char *name;
+	int num_mappings;
+	struct sdevmapping *maps;
+	int num_irqs;
+	struct sdev_irqs irqinfo[NUM_SPARC_IRQS];
+};
+
+struct sparcbus {
+	struct sparcbus *next;
+	enum bus_t type;
+	struct sparcdev *device_list;
+};
+
+/* Add more as appropriate. */
+struct sparcbus obiobus_info = { 0, OBIO_BUS, { 0, 0}, };
+struct sparcbus sbusbus_info = { 0, SBUS_BUS, { 0, 0}, };
+struct sparcbus pcibus_info = { 0, PCI_BUS, { 0, 0}, };
+struct sparcbus pmembus_info = { 0, PMEM_BUS, { 0, 0}, };
+struct sparcbus cpubus_info = { 0, CPU_BUS, { 0, 0}, };
+
+struct sparcbus *sparcbus_list = 0;
+
+/* This is called at boot time to build the prom device tree. */
+int prom_build_devtree(unsigned long start_mem, unsigned long end_mem)
+{
+}
+
+/* Search the bus device list for a device which matches one of the
+ * names in NAME_VECTOR which is an array or NUM_NAMES strings, given
+ * the passed BUSTYPE.  Return ptr to the matching sparcdev structure
+ * or NULL if no matches found.
+ */
+struct sparcdev *prom_find_dev_on_bus(bus_t bustype, char **name_vector, int num_names)
+{
+	struct sparcdev *sdp;
+	struct sparcbus *thebus;
+	int niter;
+
+	if(!num_names)
+		return 0;
+
+	if(!sparcbus_list) {
+		prom_printf("prom_find_dev_on_bus: Device list not initted yet!\n");
+		prom_halt();
+	}
+
+	while(thebus = sparcbus_list; thebus; thebus = thebus->next)
+		if(thebus->type == bustype)
+			break;
+	if(!thebus || !thebus->device_list)
+		return 0;
+
+	for(sdp = thebus->device_list; sdp; sdp = sdp->next) {
+		for(niter = 0; niter < num_names; niter++)
+			if(!strcmp(sdp->name, name_vector[niter]))
+				break;
+	}
+	return sdp;
+}
+
+/* Continue searching on a device list, starting at START_DEV for the next
+ * instance whose name matches one of the elements of NAME_VECTOR which is
+ * of length NUM_NAMES.
+ */
+struct sparcdev *prom_find_next_dev(struct sparcdev *start_dev, char **name_vector, int num_names)
+{
+	struct sparcdev *sdp;
+	int niter;
+
+	if(!start_dev->next || !num_names)
+		return 0;
+	for(sdp = start_dev->next; sdp; sdp = sdp->next) {
+		for(niter = 0; niter < num_names; niter++)
+			if(!strcmp(sdp->name, name_vector[niter]))
+				break;
+	}
+	return sdp;
+}
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/prom/misc.c linux/arch/sparc/prom/misc.c
--- v1.3.70/linux/arch/sparc/prom/misc.c	Sat Nov 25 19:04:38 1995
+++ linux/arch/sparc/prom/misc.c	Mon Mar  4 08:49:58 1996
@@ -1,4 +1,4 @@
-/* $Id: misc.c,v 1.3 1995/11/25 01:00:04 davem Exp $
+/* $Id: misc.c,v 1.5 1996/02/02 03:37:44 davem Exp $
  * misc.c:  Miscellaneous prom functions that don't belong
  *          anywhere else.
  *
@@ -29,13 +29,19 @@
 	return;
 }
 
+/* We want to do this more nicely some day. */
+extern void console_restore_palette(void);
+extern void set_palette(void);
+
 /* Drop into the prom, with the chance to continue with the 'go'
  * prom command.
  */
 void
 prom_halt(void)
 {
+        console_restore_palette ();
 	(*(romvec->pv_abort))();
+	set_palette ();
 	return;
 }
 
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/prom/tree.c linux/arch/sparc/prom/tree.c
--- v1.3.70/linux/arch/sparc/prom/tree.c	Sat Nov 25 19:04:38 1995
+++ linux/arch/sparc/prom/tree.c	Mon Mar  4 08:49:59 1996
@@ -1,4 +1,4 @@
-/* $Id: tree.c,v 1.6 1995/11/25 01:00:16 davem Exp $
+/* $Id: tree.c,v 1.7 1996/01/01 02:46:24 davem Exp $
  * tree.c: Basic device tree traversal/scanning for the Linux
  *         prom library.
  *
@@ -172,6 +172,19 @@
 {
 	if(node == -1) return "";
 	return prom_nodeops->no_nextprop(node, oprop);
+}
+
+int
+prom_node_has_property(int node, char *prop)
+{
+	char *current_property = "";
+
+	do {
+		current_property = prom_nextprop(node, current_property);
+		if(!strcmp(current_property, prop))
+		   return 1;
+	} while (*current_property);
+	return 0;
 }
 
 /* Set property 'pname' at node 'node' to value 'value' which has a length
diff -u --recursive --new-file v1.3.70/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- v1.3.70/linux/drivers/block/floppy.c	Sat Mar  2 10:43:22 1996
+++ linux/drivers/block/floppy.c	Mon Mar  4 11:46:31 1996
@@ -4021,7 +4021,7 @@
 
 static void mod_setup(char *pattern, void (*setup)(char *, int *))
 {
-	int i;
+	unsigned long i;
 	char c;
 	int j;
 	int match;
diff -u --recursive --new-file v1.3.70/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- v1.3.70/linux/drivers/block/ll_rw_blk.c	Sat Mar  2 10:43:22 1996
+++ linux/drivers/block/ll_rw_blk.c	Mon Mar  4 09:40:52 1996
@@ -357,8 +357,10 @@
 	     || major == IDE3_MAJOR)
 	    && (req = blk_dev[major].current_request))
 	{
-		if (major != SCSI_DISK_MAJOR && major != SCSI_CDROM_MAJOR)
-			req = req->next;
+		if (major != SCSI_DISK_MAJOR &&
+		    major != SCSI_CDROM_MAJOR &&
+		    major != MD_MAJOR)
+		        req = req->next;
 
 		while (req) {
 			if (req->rq_dev == bh->b_dev &&
diff -u --recursive --new-file v1.3.70/linux/drivers/block/loop.c linux/drivers/block/loop.c
--- v1.3.70/linux/drivers/block/loop.c	Wed Feb 28 11:50:00 1996
+++ linux/drivers/block/loop.c	Mon Mar  4 11:25:48 1996
@@ -15,23 +15,17 @@
 
 #include <linux/module.h>
 
-#include <linux/mm.h>
-#include <linux/sched.h>
 #include <linux/fs.h>
 #include <linux/stat.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
 #include <linux/errno.h>
-#include <asm/segment.h>
-#include "loop.h"
+#include <linux/major.h>
 
 #ifdef DES_AVAILABLE
 #include "des.h"
 #endif
+#include <linux/loop.h>		/* must follow des.h */
 
-#define DEFAULT_MAJOR_NR 10
-int loop_major = DEFAULT_MAJOR_NR;
-#define MAJOR_NR loop_major	/* not necessarily constant */
+#define MAJOR_NR LOOP_MAJOR
 
 #define DEVICE_NAME "loop"
 #define DEVICE_REQUEST do_lo_request
@@ -219,6 +213,7 @@
 		size = blksize - offset;
 		if (size > len)
 			size = len;
+			   
 		if ((lo->transfer)(lo, CURRENT->cmd, bh->b_data + offset,
 				   dest_addr, size)) {
 			printk("loop: transfer error block %d\n", block);
@@ -260,10 +255,12 @@
 			lo->lo_device = inode->i_rdev;
 		else
 			return -EINVAL;
+	invalidate_inode_pages (inode);
 	lo->lo_inode = inode;
 	lo->lo_inode->i_count++;
 	lo->transfer = NULL;
 	figure_loop_size(lo);
+	MOD_INC_USE_COUNT;
 	return 0;
 }
 
@@ -283,6 +280,7 @@
 	memset(lo->lo_name, 0, LO_NAME_SIZE);
 	loop_sizes[lo->lo_number] = 0;
 	invalidate_buffers(dev);
+	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
@@ -362,8 +360,8 @@
 
 	if (!inode)
 		return -EINVAL;
-	if (MAJOR(inode->i_rdev) != loop_major) {
-		printk("lo_ioctl: pseudo-major != %d\n", loop_major);
+	if (MAJOR(inode->i_rdev) != MAJOR_NR) {
+		printk("lo_ioctl: pseudo-major != %d\n", MAJOR_NR);
 		return -ENODEV;
 	}
 	dev = MINOR(inode->i_rdev);
@@ -401,8 +399,8 @@
 
 	if (!inode)
 		return -EINVAL;
-	if (MAJOR(inode->i_rdev) != loop_major) {
-		printk("lo_open: pseudo-major != %d\n", loop_major);
+	if (MAJOR(inode->i_rdev) != MAJOR_NR) {
+		printk("lo_open: pseudo-major != %d\n", MAJOR_NR);
 		return -ENODEV;
 	}
 	dev = MINOR(inode->i_rdev);
@@ -421,14 +419,14 @@
 
 	if (!inode)
 		return;
-	if (MAJOR(inode->i_rdev) != loop_major) {
-		printk("lo_release: pseudo-major != %d\n", loop_major);
+	if (MAJOR(inode->i_rdev) != MAJOR_NR) {
+		printk("lo_release: pseudo-major != %d\n", MAJOR_NR);
 		return;
 	}
 	dev = MINOR(inode->i_rdev);
 	if (dev >= MAX_LOOP)
 		return;
-	sync_dev(inode->i_rdev);
+	fsync_dev(inode->i_rdev);
 	lo = &loop_dev[dev];
 	if (lo->lo_refcnt <= 0)
 		printk("lo_release: refcount(%d) <= 0\n", lo->lo_refcnt);
@@ -461,26 +459,24 @@
 
 int
 loop_init( void ) {
-	int	i = (loop_major ? loop_major : DEFAULT_MAJOR_NR);
+	int	i;
 
-	if (register_blkdev(i, "loop", &lo_fops) &&
-	    (i = register_blkdev(0, "loop", &lo_fops)) <= 0) {
-		printk("Unable to get major number for loop device\n");
+	if (register_blkdev(MAJOR_NR, "loop", &lo_fops)) {
+		printk("Unable to get major number %d for loop device\n",
+		       MAJOR_NR);
 		return -EIO;
 	}
-	loop_major = i;
-#ifdef MODULE
-	if (i != DEFAULT_MAJOR_NR)
+#ifndef MODULE
+	printk("loop: registered device at major %d\n", MAJOR_NR);
 #endif
-	  printk("loop: registered device at major %d\n",loop_major);
 
-	blk_dev[loop_major].request_fn = DEVICE_REQUEST;
+	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
 	for (i=0; i < MAX_LOOP; i++) {
 		memset(&loop_dev[i], 0, sizeof(struct loop_device));
 		loop_dev[i].lo_number = i;
 	}
 	memset(&loop_sizes, 0, sizeof(loop_sizes));
-	blk_size[loop_major] = loop_sizes;
+	blk_size[MAJOR_NR] = loop_sizes;
 
 	return 0;
 }
@@ -488,7 +484,7 @@
 #ifdef MODULE
 void
 cleanup_module( void ) {
-  if (unregister_blkdev(loop_major, "loop") != 0)
+  if (unregister_blkdev(MAJOR_NR, "loop") != 0)
     printk("loop: cleanup_module failed\n");
 }
 #endif
diff -u --recursive --new-file v1.3.70/linux/drivers/block/loop.h linux/drivers/block/loop.h
--- v1.3.70/linux/drivers/block/loop.h	Wed Feb 28 11:50:00 1996
+++ linux/drivers/block/loop.h	Thu Jan  1 02:00:00 1970
@@ -1,77 +0,0 @@
-#ifndef _LINUX_LOOP_H
-#define _LINUX_LOOP_H
-
-/*
- * include/linux/loop.h
- *
- * Written by Theodore Ts'o, 3/29/93.
- *
- * Copyright 1993 by Theodore Ts'o.  Redistribution of this file is
- * permitted under the GNU Public License.
- */
-
-#define LO_NAME_SIZE	64
-#define LO_KEY_SIZE	32
-       
-struct loop_device {
-	int		lo_number;
-	struct inode	*lo_inode;
-	int		lo_refcnt;
-	kdev_t		lo_device;
-	int		lo_offset;
-	int		lo_encrypt_type;
-	int		lo_encrypt_key_size;
-	int		lo_flags;
-	int		(*transfer)(struct loop_device *, int cmd,
-				    char *raw_buf, char *loop_buf, int size);
-	char		lo_name[LO_NAME_SIZE];
-	char		lo_encrypt_key[LO_KEY_SIZE];
-#ifdef DES_AVAILABLE
-	des_key_schedule lo_des_key;
-	unsigned long	lo_des_init[2];
-#endif
-};
-
-typedef	int (* transfer_proc_t)(struct loop_device *, int cmd,
-				char *raw_buf, char *loop_buf, int size);
-
-/*
- * Loop flags
- */
-#define LO_FLAGS_DO_BMAP	0x00000001
-
-struct loop_info {
-	int		lo_number;	/* ioctl r/o */
-	dev_t		lo_device; 	/* ioctl r/o */
-	unsigned long	lo_inode; 	/* ioctl r/o */
-	dev_t		lo_rdevice; 	/* ioctl r/o */
-	int		lo_offset;
-	int		lo_encrypt_type;
-	int		lo_encrypt_key_size; 	/* ioctl w/o */
-	int		lo_flags;	/* ioctl r/o */
-	char		lo_name[LO_NAME_SIZE];
-	unsigned char	lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */
-	unsigned long	lo_init[2];
-	char		reserved[4];
-};
-
-/*
- * Loop encryption types --- LO_CRYPT_IDEA isn't supported yet
- */
-
-#define LO_CRYPT_NONE	0
-#define LO_CRYPT_XOR	1
-#define LO_CRYPT_DES	2
-#define LO_CRYPT_IDEA	3
-#define MAX_LO_CRYPT	4
-
-/*
- * IOCTL commands --- we will commandeer 0x4C ('L')
- */
-
-#define LOOP_SET_FD	0x4C00
-#define LOOP_CLR_FD	0x4C01
-#define LOOP_SET_STATUS	0x4C02
-#define LOOP_GET_STATUS	0x4C03
-
-#endif
diff -u --recursive --new-file v1.3.70/linux/drivers/block/md.c linux/drivers/block/md.c
--- v1.3.70/linux/drivers/block/md.c	Sat Mar  2 10:43:22 1996
+++ linux/drivers/block/md.c	Mon Mar  4 11:32:41 1996
@@ -175,7 +175,7 @@
        paging). This is NOT done by fdisk when partitionning,
        but that's a DOS thing anyway... */
     
-    devices[minor][index].size=gen_real->sizes[MINOR(dev)] & (PAGE_MASK>>10);
+    devices[minor][index].size=gen_real->sizes[MINOR(dev)] & ~((PAGE_SIZE >> 10)-1);
     devices[minor][index].offset=index ?
       (devices[minor][index-1].offset + devices[minor][index-1].size) : 0;
 
@@ -461,10 +461,12 @@
 	 || major == IDE3_MAJOR)
 	&& (req = blk_dev[major].current_request))
     {
-#ifdef CONFIG_BLK_DEV_HD
-      if (major == HD_MAJOR)
+      /*
+       * Thanx to Gadi Oxman <gadio@netvision.net.il>
+       * (He reads my own code better than I do... ;-)
+       */
+      if (major != SCSI_DISK_MAJOR)
 	req = req->next;
-#endif CONFIG_BLK_DEV_HD
 
       while (req && !found)
       {
diff -u --recursive --new-file v1.3.70/linux/drivers/cdrom/cm206.c linux/drivers/cdrom/cm206.c
--- v1.3.70/linux/drivers/cdrom/cm206.c	Sat Mar  2 10:43:23 1996
+++ linux/drivers/cdrom/cm206.c	Sun Mar  3 15:23:54 1996
@@ -479,7 +479,7 @@
    4 c_stop waits for receive_buffer_full: 0xff
 */
 
-void cm206_bh(void * unused)
+void cm206_bh(void)
 {
   debug(("bh: %d\n", cd->background));
   switch (cd->background) {
@@ -1169,8 +1169,7 @@
   }
   blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
   read_ahead[MAJOR_NR] = 16;	/* reads ahead what? */
-  bh_base[CM206_BH].routine = cm206_bh;
-  enable_bh(CM206_BH);
+  init_bh(CM206_BH, cm206_bh);
 
   memset(cd, 0, sizeof(*cd));	/* give'm some reasonable value */
   cd->sector_last = -1;		/* flag no data buffered */
diff -u --recursive --new-file v1.3.70/linux/drivers/cdrom/mcd.c linux/drivers/cdrom/mcd.c
--- v1.3.70/linux/drivers/cdrom/mcd.c	Sat Mar  2 10:43:23 1996
+++ linux/drivers/cdrom/mcd.c	Mon Mar  4 11:15:22 1996
@@ -90,6 +90,7 @@
 #if 0
 static int mcd_sizes[] = { 0 };
 #endif
+static int mcd_blocksizes[1] = { 0, };
 
 /* I know putting defines in this file is probably stupid, but it should be */
 /* the only place that they are really needed... I HOPE! :) */
@@ -1184,7 +1185,8 @@
 		 mcd_port);
           return -EIO;
 	}
-	  
+
+	blksize_size[MAJOR_NR] = mcd_blocksizes;
 	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
 	read_ahead[MAJOR_NR] = 4;
 
@@ -1253,7 +1255,7 @@
 
 	mcd_invalidate_buffers();
 	mcdPresent = 1;
-        return 0;
+	return 0;
 }
 
 
diff -u --recursive --new-file v1.3.70/linux/drivers/cdrom/mcdx.c linux/drivers/cdrom/mcdx.c
--- v1.3.70/linux/drivers/cdrom/mcdx.c	Sat Mar  2 10:43:23 1996
+++ linux/drivers/cdrom/mcdx.c	Mon Mar  4 11:15:22 1996
@@ -1,7 +1,7 @@
 /*
  * The Mitsumi CDROM interface
  * Copyright (C) 1995 Heiko Schlittermann <heiko@lotte.sax.de>
- * VERSION: 1.5a
+ * VERSION: 1.7
  * 
  * 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
@@ -27,6 +27,7 @@
  *  Daniel v. Mosnenck (he sent me the Technical and Programming Reference)
  *  Gerd Knorr (he lent me his PhotoCD)
  *  Nils Faerber and Roger E. Wolff (extensivly tested the LU portion)
+ *  Andreas Kies (testing the mysterious hang up's)
  *  ... somebody forgotten?
  *  
  */
@@ -34,14 +35,13 @@
 
 #if RCS
 static const char *mcdx_c_version
-		= "mcdx.c,v 1.19.2.1 1996/01/13 21:25:55 heiko Exp";
+		= "mcdx.c,v 1.31 1996/03/02 00:21:18 heiko Exp";
 #endif
 
 #include <linux/version.h>
 #include <linux/module.h>
 
 #include <linux/errno.h>
-#include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/timer.h>
 #include <linux/fs.h>
@@ -77,14 +77,13 @@
 enum datamodes { MODE0, MODE1, MODE2 };
 enum resetmodes { SOFT, HARD };
 
-const int SINGLE = 0x01;
-const int DOUBLE = 0x02;
-const int DOOR   = 0x04;
-const int MULTI  = 0x08;
-const int READY  = 0x70;
+const int SINGLE = 0x01;		/* single speed drive (FX001S, LU) */
+const int DOUBLE = 0x02;		/* double speed drive (FX001D, ..? */
+const int DOOR   = 0x04;		/* door locking capability */
+const int MULTI  = 0x08;		/* multi session capability */
 
-const unsigned char READSSPEED = 0xc0;
-const unsigned char READDSPEED = 0xc1;
+const unsigned char READ1X = 0xc0;
+const unsigned char READ2X = 0xc1;
 
 
 /* DECLARATIONS ****************************************************/ 
@@ -161,14 +160,15 @@
     int irq;			/* irq used by this drive */
     int minor;			/* minor number of this drive */
     int present;	    /* drive present and its capabilities */
-    char readcmd;		/* read cmd depends on single/double speed */
-    char playcmd;       /* play should always be single speed */
-    unsigned long changed;	/* last jiff the media was changed */
-    unsigned long xxx;      /* last jiff it was asked for media change */
+    unsigned char readcmd;	/* read cmd depends on single/double speed */
+    unsigned char playcmd;  /* play should always be single speed */
+    unsigned int xxx;      /* set if changed, reset while open */
+    unsigned int yyy;      /* set if changed, reset by media_changed */
     unsigned long ejected;  /* time we called the eject function */
     int users;				/* keeps track of open/close */
     int lastsector;			/* last block accessible */
-    int errno;				/* last operation's error */
+    int status;				/* last operation's error / status */
+	int readerrs;			/* # of blocks read w/o error */
 };
 
 
@@ -211,6 +211,7 @@
 static int irq(int*);
 static void mcdx_delay(struct s_drive_stuff*, long jifs);
 static int mcdx_transfer(struct s_drive_stuff*, char* buf, int sector, int nr_sectors);
+static int mcdx_xfer(struct s_drive_stuff*, char* buf, int sector, int nr_sectors);
 
 static int mcdx_config(struct s_drive_stuff*, int);
 static int mcdx_closedoor(struct s_drive_stuff*, int);
@@ -238,6 +239,7 @@
 
 /* static variables ************************************************/
 
+static int mcdx_blocksizes[MCDX_NDRIVES];
 static int mcdx_drive_map[][2] = MCDX_DRIVEMAP;
 static struct s_drive_stuff* mcdx_stuffp[MCDX_NDRIVES];
 static struct s_drive_stuff* mcdx_irq_map[16] =
@@ -468,7 +470,7 @@
 				ms.addr.lba = msf2log(&stuffp->multi.msf_last);
 			else
 				return -EINVAL;
-			ms.xa_flag = stuffp->xa;
+			ms.xa_flag = !!stuffp->multi.multi;
 
 			if (0 != (ans = verify_area(VERIFY_WRITE, (void*) arg,
 					sizeof(struct cdrom_multisession))))
@@ -571,7 +573,7 @@
 	  break;
 
       case READ:
-	  stuffp->errno = 0;
+	  stuffp->status = 0;
 	  while (CURRENT->nr_sectors) {
 	      int i;
 
@@ -580,12 +582,13 @@
 				      CURRENT->buffer,
 				      CURRENT->sector,
 				      CURRENT->nr_sectors))) {
-              WARN(("do_request() read error\n"));
-              if (stuffp->errno == MCDX_EOM) {
+              INFO(("do_request() read error\n"));
+              if (stuffp->status & MCDX_ST_EOM) {
                   CURRENT->sector += CURRENT->nr_sectors;
                   CURRENT->nr_sectors = 0;
-              }
+              } 
               end_request(0);
+			  /* return; */
               goto again;
 	      }
 	      CURRENT->sector += i;
@@ -627,38 +630,36 @@
 	if (inb((unsigned int) stuffp->rreg_status) & MCDX_RBIT_DOOR) {
         if (jiffies - stuffp->ejected < ACLOSE_INHIBIT) return -EIO;
         if (stuffp->autoclose) mcdx_closedoor(stuffp, 1);
-        else return -EIO;
+		else return -EIO;
     }
 
 	/* if the media changed we will have to do a little more */
-	if (stuffp->xxx < stuffp->changed) {
+	if (stuffp->xxx) {
 
 		TRACE((OPENCLOSE, "open() media changed\n"));
         /* but wait - the time of media change will be set at the 
-        very last of this block - it seems, some of the following
-        talk() will detect a media change ... (I think, config()
-        is the reason. */
+           very last of this block - it seems, some of the following
+           talk() will detect a media change ... (I think, config()
+           is the reason. */
 
         stuffp->audiostatus = CDROM_AUDIO_INVALID;
 
 		/* get the multisession information */
-		{
-            int ans;
-
-			TRACE((OPENCLOSE, "open() Request multisession info\n"));
-            ans = mcdx_requestmultidiskinfo(stuffp, &stuffp->multi, 6);
-            if (ans == -1) {
-                stuffp->autoclose = 0;
-                mcdx_eject(stuffp, 1);
-                return -EIO;
-            }
-
-            /* we succeeded, so on next open(2) we could try auto close
-            again */
-            stuffp->autoclose = 1;
+		TRACE((OPENCLOSE, "open() Request multisession info\n"));
+		if (-1 == mcdx_requestmultidiskinfo(
+				stuffp, &stuffp->multi, 6)) {
+			INFO(("No multidiskinfo\n"));
+			stuffp->autoclose = 0;
+		} else {
+			/* we succeeded, so on next open(2) we could try auto close
+			again */
+			stuffp->autoclose = 1;
 		
+#if !MCDX_QUIET
 			if (stuffp->multi.multi > 2)
-				WARN(("open() unknown multisession value (%d)\n", stuffp->multi.multi));
+				INFO(("open() unknown multisession value (%d)\n", 
+						stuffp->multi.multi));
+#endif
 
 			/* multisession ? */
 			if (!stuffp->multi.multi)
@@ -669,38 +670,54 @@
 					stuffp->multi.msf_last.minute,
 					stuffp->multi.msf_last.second,
 					stuffp->multi.msf_last.frame));
+
 		} /* got multisession information */
 
 		/* request the disks table of contents (aka diskinfo) */
-		if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) return -EIO;
+		if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) {
 
-		stuffp->lastsector = (CD_FRAMESIZE / 512) 
-                * msf2log(&stuffp->di.msf_leadout) - 1;
+			stuffp->lastsector = -1;
+
+		} else {
 
-		TRACE((OPENCLOSE, "open() start %d (%02x:%02x.%02x) %d\n",
-				stuffp->di.n_first,
-				stuffp->di.msf_first.minute,
-				stuffp->di.msf_first.second,
-				stuffp->di.msf_first.frame,
-				msf2log(&stuffp->di.msf_first)));
-		TRACE((OPENCLOSE, "open() last %d (%02x:%02x.%02x) %d\n",
-				stuffp->di.n_last,
-				stuffp->di.msf_leadout.minute,
-				stuffp->di.msf_leadout.second,
-				stuffp->di.msf_leadout.frame,
-				msf2log(&stuffp->di.msf_leadout)));
+			stuffp->lastsector = (CD_FRAMESIZE / 512) 
+					* msf2log(&stuffp->di.msf_leadout) - 1;
+
+			TRACE((OPENCLOSE, "open() start %d (%02x:%02x.%02x) %d\n",
+					stuffp->di.n_first,
+					stuffp->di.msf_first.minute,
+					stuffp->di.msf_first.second,
+					stuffp->di.msf_first.frame,
+					msf2log(&stuffp->di.msf_first)));
+			TRACE((OPENCLOSE, "open() last %d (%02x:%02x.%02x) %d\n",
+					stuffp->di.n_last,
+					stuffp->di.msf_leadout.minute,
+					stuffp->di.msf_leadout.second,
+					stuffp->di.msf_leadout.frame,
+					msf2log(&stuffp->di.msf_leadout)));
+		}
 
 		if (stuffp->toc) {
-			TRACE((MALLOC, "open() free toc @ %p\n", stuffp->toc));
+			TRACE((MALLOC, "open() free old toc @ %p\n", stuffp->toc));
 			kfree(stuffp->toc);
+		
+			stuffp->toc = NULL;
 		}
-		stuffp->toc = NULL;
 
 		TRACE((OPENCLOSE, "open() init irq generation\n"));
 		if (-1 == mcdx_config(stuffp, 1)) return -EIO;
 
-		/* try to get the first sector ... */
-		{
+#if FALLBACK
+		/* Set the read speed */
+		WARN(("AAA %x AAA\n", stuffp->readcmd));
+		if (stuffp->readerrs) stuffp->readcmd = READ1X;
+		else stuffp->readcmd = 
+				stuffp->present | SINGLE ? READ1X : READ2X;
+		WARN(("XXX %x XXX\n", stuffp->readcmd));
+#endif
+
+		/* try to get the first sector, iff any ... */
+		if (stuffp->lastsector >= 0) {
 			char buf[512];
 			int ans;
 			int tries;
@@ -709,13 +726,19 @@
 			stuffp->audio = 0;
 
 			for (tries = 6; tries; tries--) {
+
+				stuffp->introk = 1;
+
 				TRACE((OPENCLOSE, "open() try as %s\n",
 					stuffp->xa ? "XA" : "normal"));
 
 				/* set data mode */
 				if (-1 == (ans = mcdx_setdatamode(stuffp, 
-						stuffp->xa ? MODE2 : MODE1, 1)))
-					return -EIO;
+						stuffp->xa ? MODE2 : MODE1, 1))) {
+					/* return -EIO; */
+					stuffp->xa = 0;
+					break;
+				}
 
 				if ((stuffp->audio = e_audio(ans))) break; 
 
@@ -725,7 +748,7 @@
 				if (ans == 1) break;
 				stuffp->xa = !stuffp->xa; 
 			}
-			if (!tries) return -EIO;
+			/* if (!tries) return -EIO; */
 		}
 
 		/* xa disks will be read in raw mode, others not */
@@ -735,13 +758,13 @@
 
 		if (stuffp->audio) {
 			INFO(("open() audio disk found\n"));
-		} else {
+		} else if (stuffp->lastsector >= 0) {
 			INFO(("open() %s%s disk found\n",
 					stuffp->xa ? "XA / " : "",
 					stuffp->multi.multi ? "Multi Session" : "Single Session"));
-		}
+		} 
 
-        stuffp->xxx = jiffies;
+        stuffp->xxx = 0;
 	}
 
     /* lock the door if not already done */
@@ -768,9 +791,12 @@
 		/* invalidate_inodes(ip->i_rdev); */
 		invalidate_buffers(ip->i_rdev);
 
+
 #if !MCDX_QUIET
 		if (-1 == mcdx_lockdoor(stuffp, 0, 3))
 				INFO(("close() Cannot unlock the door\n"));
+#else
+		mcdx_lockdoor(stuffp, 0, 3);
 #endif
 
         /* eject if wished */
@@ -783,15 +809,25 @@
 }
 
 int check_mcdx_media_change(kdev_t full_dev)
-/*	Return: 1 if media changed since last call to 
-			  this function
-			0 else
-	Setting flag to 0 resets the changed state. */
-
+/*	Return: 1 if media changed since last call to this function
+			0 otherwise */
 {
+    struct s_drive_stuff *stuffp; 
+
     INFO(("check_mcdx_media_change called for device %s\n",
 	  kdevname(full_dev)));
-    return 0;
+
+	stuffp = mcdx_stuffp[MINOR(full_dev)];
+	mcdx_getstatus(stuffp, 1);
+
+	if (stuffp->yyy == 0) {
+		INFO((" ... not changed\n"));
+		return 0;
+	}
+
+	INFO((" ... changed\n"));
+	stuffp->yyy = 0;
+	return 1;
 }
 
 void mcdx_setup(char *str, int *pi)
@@ -803,22 +839,15 @@
 /* DIRTY PART ******************************************************/ 
 
 static void mcdx_delay(struct s_drive_stuff *stuff, long jifs)
-/*	This routine is used for sleeping while initialisation - it seems that
- 	there are no other means available. May be we could use a simple count
- 	loop w/ jumps to itself, but I wanna make this independend of cpu
- 	speed. [1 jiffie is 1/HZ sec */
+/*	This routine is used for sleeping.
+	May be we could use a simple count loop w/ jumps to itself, but 
+	I wanna make this independend of cpu speed. [1 jiffie is 1/HZ] sec */
 {
     unsigned long tout = jiffies + jifs;
 
-    TRACE((INIT, "mcdx_delay %d\n", jifs));
-    if (jifs < 0) return;
+    /* TRACE((INIT, "mcdx_delay %d\n", jifs)); */
+    if (jifs <= 0) return;
 
-#if 1
-    while (jiffies < tout) {
-        current->timeout = jiffies;
-        schedule();
-    }
-#else
     if (current->pid == 0) {        /* no sleep allowed */
 		while (jiffies < tout) {
             current->timeout = jiffies;
@@ -826,37 +855,50 @@
         }
     } else {                        /* sleeping is allowed */
         current->timeout = tout;
-        current->state = TASK_INTERRUPTIBLE;
+        /* current->state = TASK_INTERRUPTIBLE; */
+		/* And perhaps we should remove the while() { ... } */
         while (current->timeout) {
             interruptible_sleep_on(&stuff->sleepq);
+			TRACE((SLEEP, "delay: to is %d\n", current->timeout));
         }
     }
-#endif
 }
 
 static void 
 mcdx_intr(int irq, void *dev_id, struct pt_regs* regs)
 {
     struct s_drive_stuff *stuffp;
-	unsigned char x;
+	unsigned char b;
 
     stuffp = mcdx_irq_map[irq];
 
-    if (stuffp == NULL || !stuffp->busy) {
-		TRACE((IRQ, "intr() unexpected interrupt @ irq %d\n", irq));
+    if (stuffp == NULL ) {
+		WARN(("mcdx: no device for intr %d\n", irq));
 		return;
     }
 
-	/* if not ok read the next byte as the drives status */
-	if (0 == (stuffp->introk = 
-			(~(x = inb((unsigned int) stuffp->rreg_status)) & MCDX_RBIT_DTEN))) 
-		TRACE((IRQ, "intr() irq %d failed, status %02x %02x\n",
-				irq, x, inb((unsigned int) stuffp->rreg_data)));
-	else
-	  {
-	    TRACE((IRQ, "irq() irq %d ok, status %02x\n", irq, x));
+	/* get the interrupt status */
+	b = inb((unsigned int) stuffp->rreg_status);
+	stuffp->introk = ~b & MCDX_RBIT_DTEN;
+
+	/* NOTE: We only should get interrupts if data were requested.
+	   But the drive seems to generate ``asynchronous'' interrupts
+	   on several error conditions too.  (Despite the err int enable
+	   setting during initialisation) */
+
+	/* if not ok, read the next byte as the drives status */
+	if (!stuffp->introk) {
+		TRACE((IRQ, "intr() irq %d hw status 0x%02x\n", irq, b));
+		if (~b & MCDX_RBIT_STEN) {
+			INFO((  "intr() irq %d    status 0x%02x\n", 
+					irq, inb((unsigned int) stuffp->rreg_data)));
+		} else {
+			INFO((  "intr() irq %d ambigous hw status\n", irq));
+		}
+	} else {
+		TRACE((IRQ, "irq() irq %d ok, status %02x\n", irq, b));
+    }
 
-	  }
     stuffp->busy = 0;
     wake_up_interruptible(&stuffp->busyq);
 }
@@ -881,13 +923,11 @@
 
     if ((disgard = (buffer == NULL))) buffer = &c;
 
-    while (stuffp->lock)
-		interruptible_sleep_on(&stuffp->lockq);
-
-    if (current->signal && ~current->blocked) {
-        WARN(("talk() got signal %d\n", current->signal));
-        return -1;
-    }
+    while (stuffp->lock) {
+		interruptible_sleep_on(&stuffp->lockq); 
+		TRACE((SLEEP, "talk: lock = %d\n",
+				stuffp->lock));
+	}
 
     stuffp->lock = 1;
     stuffp->valid = 0;	
@@ -906,8 +946,8 @@
      *  st != -1 (good) */
 	for (st = -1; st == -1 && tries; tries--) {
 
-        size_t sz = size;
-        char* bp = buffer;
+		char *bp = (char*) buffer;
+		size_t sz = size;
 
 		outsb((unsigned int) stuffp->wreg_data, cmd, cmdlen);
         TRACE((TALK, "talk() command sent\n"));
@@ -930,7 +970,7 @@
                     cmd[0], cmdlen > 1 ? "..." : ""));
             st = -1;
             continue;
-        }
+		}
 
         /* audio status? */
         if (stuffp->audiostatus == CDROM_AUDIO_INVALID)
@@ -943,7 +983,7 @@
         /* media change? */
         if (e_changed(st)) {
             INFO(("talk() media changed\n"));
-            stuffp->changed = jiffies;
+            stuffp->xxx = stuffp->yyy = 1;
         }
 
         /* now actually get the data */
@@ -958,7 +998,9 @@
         }
     }
 
-    if (!tries && st == -1) WARN(("talk() giving up\n"));
+#if !MCDX_QUIET
+    if (!tries && st == -1) INFO(("talk() giving up\n"));
+#endif
 
     stuffp->lock = 0;
     wake_up_interruptible(&stuffp->lockq);
@@ -995,7 +1037,7 @@
 {
     int i;
 
-	WARN(("cleanup_module called\n"));
+	INFO(("cleanup_module called\n"));
 	
     for (i = 0; i < MCDX_NDRIVES; i++) {
 		struct s_drive_stuff *stuffp;
@@ -1012,9 +1054,12 @@
 		kfree(stuffp);
     }
 
-    if (unregister_blkdev(MAJOR_NR, DEVICE_NAME) != 0) 
+    if (unregister_blkdev(MAJOR_NR, DEVICE_NAME) != 0) {
         WARN(("cleanup() unregister_blkdev() failed\n"));
-    else INFO(("cleanup() succeeded\n"));
+    } 
+#if !MCDX_QUIET
+	else INFO(("cleanup() succeeded\n"));
+#endif
 }
 
 #endif MODULE
@@ -1046,15 +1091,12 @@
 	va_end(args);
 }
 
-
 int mcdx_init(void)
 {
 	int drive;
 
-	WARN(("Version 1.5a "
-			"mcdx.c,v 1.19.2.1 1996/01/13 21:25:55 heiko Exp\n"));
-	INFO((": Version 1.5a "
-			"mcdx.c,v 1.19.2.1 1996/01/13 21:25:55 heiko Exp\n"));
+	WARN(("Version 1.7 for %s\n", kernel_version));
+	WARN(("mcdx.c,v 1.31 1996/03/02 00:21:18 heiko Exp\n"));
 
 	/* zero the pointer array */
 	for (drive = 0; drive < MCDX_NDRIVES; drive++)
@@ -1066,6 +1108,8 @@
 		struct s_drive_stuff* stuffp;
         int size;
 
+		mcdx_blocksizes[drive] = 0;
+
         size = sizeof(*stuffp);
 		
 		TRACE((INIT, "init() try drive %d\n", drive));
@@ -1085,7 +1129,6 @@
 
 		stuffp->present = 0;		/* this should be 0 already */
 		stuffp->toc = NULL;			/* this should be NULL already */
-		stuffp->changed = jiffies;
 
 		/* setup our irq and i/o addresses */
 		stuffp->irq = irq(mcdx_drive_map[drive]);
@@ -1096,9 +1139,8 @@
 
 		/* check if i/o addresses are available */
 		if (0 != check_region((unsigned int) stuffp->wreg_data, MCDX_IO_SIZE)) {
-            WARN(("%s=0x%3p,%d: "
-                    "Init failed. I/O ports (0x%3p..0x3p) already in use.\n"
-                    MCDX, 
+            WARN(("0x%3p,%d: "
+                    "Init failed. I/O ports (0x%3p..0x%3p) already in use.\n",
                     stuffp->wreg_data, stuffp->irq,
                     stuffp->wreg_data, 
                     stuffp->wreg_data + MCDX_IO_SIZE - 1));
@@ -1127,22 +1169,22 @@
 
 		switch (version.code) {
 		case 'D': 
-                stuffp->readcmd = READDSPEED; 
+                stuffp->readcmd = READ2X; 
                 stuffp->present = DOUBLE | DOOR | MULTI; 
                 break;
 		case 'F': 
-                stuffp->readcmd = READSSPEED; 
+                stuffp->readcmd = READ1X; 
                 stuffp->present = SINGLE | DOOR | MULTI;
                 break;
 		case 'M': 
-                stuffp->readcmd = READSSPEED;
+                stuffp->readcmd = READ1X;
                 stuffp->present = SINGLE;
                 break;
 		default: 
                 stuffp->present = 0; break;
 		}
 
-        stuffp->playcmd = READSSPEED;
+        stuffp->playcmd = READ1X;
 
 
 		if (!stuffp->present) {
@@ -1164,9 +1206,7 @@
 		blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
 		read_ahead[MAJOR_NR] = READ_AHEAD;
 
-#if WE_KNOW_WHY
-		 blksize_size[MAJOR_NR] = BLKSIZES;
-#endif
+		blksize_size[MAJOR_NR] = mcdx_blocksizes;
 
 		TRACE((INIT, "init() subscribe irq and i/o\n"));
 		mcdx_irq_map[stuffp->irq] = stuffp;
@@ -1210,8 +1250,38 @@
 	return 0;
 }
 
+static int 
+mcdx_transfer(struct s_drive_stuff *stuffp,
+		char *p, int sector, int nr_sectors)
+/*	This seems to do the actually transfer.  But it does more.  It
+	keeps track of errors ocurred and will (if possible) fall back
+	to single speed on error. 
+	Return:	-1 on timeout or other error
+			else status byte (as in stuff->st) */
+{
+	int ans;
+
+	ans = mcdx_xfer(stuffp, p, sector, nr_sectors);
+	return ans;
+#if FALLBACK
+	if (-1 == ans) stuffp->readerrs++;
+	else return ans;
 
-static int mcdx_transfer(struct s_drive_stuff *stuffp,
+	if (stuffp->readerrs && stuffp->readcmd == READ1X) {
+		WARN(("XXX Alrady reading 1x -- no chance\n"));
+		return -1;
+	}
+
+	WARN(("XXX Fallback to 1x\n"));
+
+	stuffp->readcmd = READ1X;
+	return mcdx_transfer(stuffp, p, sector, nr_sectors);
+#endif
+	
+}
+
+
+static int mcdx_xfer(struct s_drive_stuff *stuffp,
 		char *p, int sector, int nr_sectors)
 /*	This does actually the transfer from the drive.
 	Return:	-1 on timeout or other error
@@ -1228,11 +1298,11 @@
 		return -1;
 	}
 
-    while (stuffp->lock)
+    while (stuffp->lock) {
 		interruptible_sleep_on(&stuffp->lockq);
-    if (current->signal && ~current->blocked) {
-        WARN(("talk() got signal %d\n", current->signal));
-    }
+		TRACE((SLEEP, "xfer: lock = %d\n",
+			stuffp->lock));
+	}
 
     if (stuffp->valid
 			&& (sector >= stuffp->pending)
@@ -1245,29 +1315,32 @@
 	stuffp->lock = current->pid;
 
 	do {
-	    /* int sig = 0; */
-	    int to = 0;
+		/* wait for the drive become idle, but first
+		   check for possible occured errors --- the drive
+		   seems to report them asynchronously */
 
-		/* wait for the drive become idle */
-	    current->timeout = jiffies + 5*HZ;
-	    while (stuffp->busy) {
+	    current->timeout = jiffies + 5 * HZ;
+	    while (stuffp->introk && stuffp->busy && current->timeout) {
 			interruptible_sleep_on(&stuffp->busyq);
+			TRACE((SLEEP, "request: busy = %d, timeout = %d\n",
+				stuffp->busy, current->timeout));
 		}
 
-	    current->timeout = 0;
-
 		/* test for possible errors */
-	    if (((stuffp->busy == 0) && !stuffp->introk)
-				|| to) {
-			if ((stuffp->busy == 0) && !stuffp->introk)
-                WARN(("mcdx_transfer() failure in data request\n"));
-			else if (to)
-                WARN(("mcdx_transfer(): timeout\n"));
+		if (current->timeout == 0 || !stuffp->introk) {
+			if (current->timeout == 0)  {
+				WARN(("mcdx_transfer() timeout\n"));
+			} else if (!stuffp->introk) { 
+				WARN(("mcdx_transfer() error via irq reported\n"));
+			} else {
+				WARN(("mcdx_transfer() unknown failure in data request\n"));
+			}
+
 			stuffp->lock = 0;
 			stuffp->busy = 0;
+			stuffp->valid = 0;
+
 			wake_up_interruptible(&stuffp->lockq);
-			wake_up_interruptible(&stuffp->busyq);
-			stuffp->errno = MCDX_E;
 			TRACE((TRANSFER, "transfer() done (-1)\n"));
 			return -1;
 	    }
@@ -1301,8 +1374,7 @@
 			done++;
 			sector++;
 	    }
-	}
-	while (++(stuffp->pending) < off);
+	} while (++(stuffp->pending) < off);
 
 	stuffp->lock = 0;
 	wake_up_interruptible(&stuffp->lockq);
@@ -1325,7 +1397,8 @@
 		if (stuffp->pending > stuffp->lastsector) {
 			WARN(("transfer() sector %d from nirvana requested.\n",
 				stuffp->pending));
-			stuffp->errno = MCDX_EOM;
+			stuffp->status = MCDX_ST_EOM;
+			stuffp->valid = 0;
 			TRACE((TRANSFER, "transfer() done (-1)\n"));
 			return -1;
 		}
@@ -1507,7 +1580,7 @@
 
     outsb((unsigned int) stuffp->wreg_data, cmd, sizeof cmd);
 
-    if (-1 == mcdx_getval(stuffp, 3*HZ, 0, NULL)) {
+    if (-1 == mcdx_getval(stuffp, 3 * HZ, 0, NULL)) {
         WARN(("playmsf() timeout\n")); 
         return -1;
     }
@@ -1550,25 +1623,25 @@
 mcdx_closedoor(struct s_drive_stuff *stuffp, int tries)
 {
 	if (stuffp->present & DOOR)
-		return mcdx_talk(stuffp, "\xf8", 1, NULL, 1, 5*HZ, tries);
+		return mcdx_talk(stuffp, "\xf8", 1, NULL, 1, 5 * HZ, tries);
 	else
 		return 0;
 }
 
 static int 
 mcdx_stop(struct s_drive_stuff *stuffp, int tries)
-{ return mcdx_talk(stuffp, "\xf0", 1, NULL, 1, 2*HZ, tries); }
+{ return mcdx_talk(stuffp, "\xf0", 1, NULL, 1, 2 * HZ, tries); }
 
 static int
 mcdx_hold(struct s_drive_stuff *stuffp, int tries)
-{ return mcdx_talk(stuffp, "\x70", 1, NULL, 1, 2*HZ, tries); }
+{ return mcdx_talk(stuffp, "\x70", 1, NULL, 1, 2 * HZ, tries); }
 
 static int
 mcdx_eject(struct s_drive_stuff *stuffp, int tries)
 {
 	if (stuffp->present & DOOR) {
         stuffp->ejected = jiffies;
-		return mcdx_talk(stuffp, "\xf6", 1, NULL, 1, 5*HZ, tries);
+		return mcdx_talk(stuffp, "\xf6", 1, NULL, 1, 5 * HZ, tries);
     } else return 0;
 }
 
@@ -1582,7 +1655,7 @@
 
 	if (-1 == (ans = mcdx_talk(
             stuffp, "\x20", 1, buf, sizeof(buf),
-            2*HZ, tries))) 
+            2 * HZ, tries))) 
         return -1;
 	sub->control = buf[1];
 	sub->tno = buf[2];
@@ -1604,8 +1677,8 @@
 	int ans;
 
     if (stuffp->present & MULTI) {
-        ans = mcdx_talk(stuffp, "\x11", 1, buf, sizeof(buf), 2*HZ, tries);
-        multi->multi = buf[1];
+		ans = mcdx_talk(stuffp, "\x11", 1, buf, sizeof(buf), 1 * HZ, tries);
+		multi->multi = buf[1];
         multi->msf_last.minute = buf[2];
         multi->msf_last.second = buf[3];
         multi->msf_last.frame = buf[4];
@@ -1621,15 +1694,20 @@
 {
 	char buf[9];
 	int ans;
-	ans = mcdx_talk(stuffp, "\x10", 1, buf, sizeof(buf), 2*HZ, tries);
-	info->n_first = bcd2uint(buf[1]);
-	info->n_last = bcd2uint(buf[2]);
-	info->msf_leadout.minute = buf[3];
-	info->msf_leadout.second = buf[4];
-	info->msf_leadout.frame = buf[5];
-	info->msf_first.minute = buf[6];
-	info->msf_first.second = buf[7];
-	info->msf_first.frame = buf[8];
+	ans = mcdx_talk(stuffp, "\x10", 1, buf, sizeof(buf), 1 * HZ, tries);
+	if (ans == -1) {
+		info->n_first = 0;
+		info->n_last = 0;
+	} else {
+		info->n_first = bcd2uint(buf[1]);
+		info->n_last = bcd2uint(buf[2]);
+		info->msf_leadout.minute = buf[3];
+		info->msf_leadout.second = buf[4];
+		info->msf_leadout.frame = buf[5];
+		info->msf_first.minute = buf[6];
+		info->msf_first.second = buf[7];
+		info->msf_first.frame = buf[8];
+	}
 	return ans;
 }
 
@@ -1641,7 +1719,7 @@
 
 	TRACE((HW, "setdrivemode() %d\n", mode));
 
-	if (-1 == (ans = mcdx_talk(stuffp, "\xc2", 1, cmd, sizeof(cmd), 5*HZ, tries)))
+	if (-1 == (ans = mcdx_talk(stuffp, "\xc2", 1, cmd, sizeof(cmd), 5 * HZ, tries)))
 		return -1;
 
 	switch (mode) {
@@ -1652,10 +1730,9 @@
 	  default: break;
 	}
 	cmd[0] = 0x50;
-	return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5*HZ, tries);
+	return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries);
 }
 
-
 static int
 mcdx_setdatamode(struct s_drive_stuff *stuffp, enum datamodes mode, int tries)
 {
@@ -1667,7 +1744,7 @@
 	  case MODE2: cmd[1] = 0x02; break;
 	  default: return -EINVAL;
 	}
-	return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5*HZ, tries);
+	return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries);
 }
 
 static int
@@ -1682,13 +1759,13 @@
 	cmd[1] = 0x10;		/* irq enable */
 	cmd[2] = 0x05;		/* pre, err irq enable */
 
-	if (-1 == mcdx_talk(stuffp, cmd, 3, NULL, 1, 1*HZ, tries))
+	if (-1 == mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries))
 		return -1;
 
 	cmd[1] = 0x02;		/* dma select */
 	cmd[2] = 0x00;		/* no dma */
 
-	return mcdx_talk(stuffp, cmd, 3, NULL, 1, 1*HZ, tries);
+	return mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries);
 }
 
 static int
@@ -1697,7 +1774,8 @@
 	char buf[3];
 	int ans;
 
-	if (-1 == (ans = mcdx_talk(stuffp, "\xdc", 1, buf, sizeof(buf), 2*HZ, tries)))
+	if (-1 == (ans = mcdx_talk(stuffp, "\xdc", 
+			1, buf, sizeof(buf), 1 * HZ, tries)))
 		return ans;
 
 	ver->code = buf[1];
@@ -1713,7 +1791,7 @@
 		outb(0, (unsigned int) stuffp->wreg_chn);		/* no dma, no irq -> hardware */
 		outb(0, (unsigned int) stuffp->wreg_reset);		/* hw reset */
 		return 0;
-	} else return mcdx_talk(stuffp, "\x60", 1, NULL, 1, 5*HZ, tries);
+	} else return mcdx_talk(stuffp, "\x60", 1, NULL, 1, 5 * HZ, tries);
 }
 
 static int
@@ -1722,14 +1800,13 @@
 	char cmd[2] = { 0xfe };
     if (stuffp->present & DOOR) {
         cmd[1] = lock ? 0x01 : 0x00;
-        return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 1, 5*HZ, tries);
-    } else 
-        return 0;
+        return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 1, 5 * HZ, tries);
+    } else return 0;
 }
 
 static int
 mcdx_getstatus(struct s_drive_stuff *stuffp, int tries)
-{ return mcdx_talk(stuffp, "\x40", 1, NULL, 1, 5*HZ, tries); }
+{ return mcdx_talk(stuffp, "\x40", 1, NULL, 1, 5 * HZ, tries); }
 
 static int
 mcdx_getval(struct s_drive_stuff *stuffp, int to, int delay, char* buf)
@@ -1765,3 +1842,4 @@
     return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 5, 200, tries);
 }
 
+/* ex:set ts=4 sw=4: */
diff -u --recursive --new-file v1.3.70/linux/drivers/char/apm_bios.c linux/drivers/char/apm_bios.c
--- v1.3.70/linux/drivers/char/apm_bios.c	Sun Feb 11 15:32:44 1996
+++ linux/drivers/char/apm_bios.c	Mon Mar  4 09:46:02 1996
@@ -742,6 +742,9 @@
 #ifndef ALWAYS_CALL_BUSY
 	if (!clock_slowed)
 		return;
+#else
+	if (!apm_enabled)
+		return;
 #endif
 
 	APM_SET_CPU_BUSY(error);
diff -u --recursive --new-file v1.3.70/linux/drivers/char/console.c linux/drivers/char/console.c
--- v1.3.70/linux/drivers/char/console.c	Sat Mar  2 10:43:23 1996
+++ linux/drivers/char/console.c	Sun Mar  3 15:53:23 1996
@@ -1958,7 +1958,7 @@
  * us the option to easily disable it to avoid races when we
  * need to write to the console.
  */
-static void console_bh(void * unused)
+static void console_bh(void)
 {
 	if (want_console >= 0) {
 		if (want_console != fg_console) {
@@ -2101,9 +2101,7 @@
 	if (video_type != VIDEO_TYPE_TGAC)
 		register_console(console_print);
 
-	bh_base[CONSOLE_BH].routine = console_bh;
-	enable_bh(CONSOLE_BH);
-
+	init_bh(CONSOLE_BH, console_bh);
 	return kmem_start;
 }
 
diff -u --recursive --new-file v1.3.70/linux/drivers/char/cyclades.c linux/drivers/char/cyclades.c
--- v1.3.70/linux/drivers/char/cyclades.c	Sat Mar  2 10:43:23 1996
+++ linux/drivers/char/cyclades.c	Sun Mar  3 15:21:51 1996
@@ -989,7 +989,7 @@
  * had to poll every port to see if that port needed servicing.
  */
 static void
-do_cyclades_bh(void *unused)
+do_cyclades_bh(void)
 {
     run_task_queue(&tq_cyclades);
 } /* do_cyclades_bh */
@@ -2816,8 +2816,7 @@
     if (tty_register_driver(&cy_callout_driver))
 	    panic("Couldn't register Cyclom callout driver\n");
 
-    bh_base[CYCLADES_BH].routine = do_cyclades_bh;
-    enable_bh(CYCLADES_BH);
+    init_bh(CYCLADES_BH, do_cyclades_bh);
 
     for (i = 0; i < 16; i++) {
 	    IRQ_cards[i] = 0;
diff -u --recursive --new-file v1.3.70/linux/drivers/char/keyboard.c linux/drivers/char/keyboard.c
--- v1.3.70/linux/drivers/char/keyboard.c	Sat Mar  2 10:43:24 1996
+++ linux/drivers/char/keyboard.c	Sun Mar  3 15:31:52 1996
@@ -1153,7 +1153,7 @@
  * used, but this allows for easy and efficient race-condition
  * prevention later on.
  */
-static void kbd_bh(void * unused)
+static void kbd_bh(void)
 {
 	unsigned char leds = getleds();
 
@@ -1182,14 +1182,13 @@
 
 	ttytab = console_driver.table;
 
-	bh_base[KEYBOARD_BH].routine = kbd_bh;
 	request_irq(KEYBOARD_IRQ, keyboard_interrupt, 0, "keyboard", NULL);
 	request_region(0x60,16,"kbd");
 #ifdef INIT_KBD
 	initialize_kbd();
 #endif
+	init_bh(KEYBOARD_BH, kbd_bh);
 	mark_bh(KEYBOARD_BH);
-	enable_bh(KEYBOARD_BH);
 	return 0;
 }
 
diff -u --recursive --new-file v1.3.70/linux/drivers/char/selection.h linux/drivers/char/selection.h
--- v1.3.70/linux/drivers/char/selection.h	Fri Jan 26 01:37:05 1996
+++ linux/drivers/char/selection.h	Mon Mar  4 11:46:31 1996
@@ -86,10 +86,10 @@
  */
 static inline void scr_writew(unsigned short val, unsigned short * addr)
 {
-        /*
-        * always deposit the char/attr, then see if it was to "screen" mem.
+	/*
+	 * always deposit the char/attr, then see if it was to "screen" mem.
 	 * if so, then render the char/attr onto the real screen.
-        */
+	 */
         *addr = val;
         if ((unsigned long)addr < video_mem_term &&
 	    (unsigned long)addr >= video_mem_base) {
diff -u --recursive --new-file v1.3.70/linux/drivers/char/serial.c linux/drivers/char/serial.c
--- v1.3.70/linux/drivers/char/serial.c	Sat Mar  2 10:43:25 1996
+++ linux/drivers/char/serial.c	Sun Mar  3 15:31:32 1996
@@ -723,7 +723,7 @@
  * interrupt driver proper are done; the interrupt driver schedules
  * them using rs_sched_event(), and they get done here.
  */
-static void do_serial_bh(void *unused)
+static void do_serial_bh(void)
 {
 	run_task_queue(&tq_serial);
 }
@@ -2665,8 +2665,7 @@
 	int i;
 	struct async_struct * info;
 	
-	bh_base[SERIAL_BH].routine = do_serial_bh;
-	enable_bh(SERIAL_BH);
+	init_bh(SERIAL_BH, do_serial_bh);
 	timer_table[RS_TIMER].fn = rs_timer;
 	timer_table[RS_TIMER].expires = 0;
 #ifdef CONFIG_AUTO_IRQ
diff -u --recursive --new-file v1.3.70/linux/drivers/isdn/teles/card.c linux/drivers/isdn/teles/card.c
--- v1.3.70/linux/drivers/isdn/teles/card.c	Sat Mar  2 10:43:25 1996
+++ linux/drivers/isdn/teles/card.c	Sat Mar  2 12:37:45 1996
@@ -668,7 +668,7 @@
 }
 
 static void
-teles_interrupt(int intno, struct pt_regs *regs)
+teles_interrupt(int intno, void *dev_id, struct pt_regs *regs)
 {
 	byte                 val, val2, r;
 	struct IsdnCardState *sp;
@@ -1530,7 +1530,7 @@
 	save_flags(flags);
 	cli();
 	if (request_irq(card->interrupt, &teles_interrupt,
-			SA_INTERRUPT, "teles")) {
+			SA_INTERRUPT, "teles", NULL)) {
 		printk(KERN_WARNING "Teles couldn't get interrupt %d\n",
                        card->interrupt);
 		restore_flags(flags);
@@ -1547,7 +1547,7 @@
 	struct IsdnCard *card = cards + cardnr;
 
 	irq2dev_map[card->interrupt] = NULL;
-	free_irq(card->interrupt);
+	free_irq(card->interrupt, NULL);
 }
 
 void
diff -u --recursive --new-file v1.3.70/linux/drivers/net/3c503.c linux/drivers/net/3c503.c
--- v1.3.70/linux/drivers/net/3c503.c	Sat Mar  2 10:43:26 1996
+++ linux/drivers/net/3c503.c	Sat Mar  2 13:18:47 1996
@@ -45,6 +45,7 @@
 
 #include <asm/io.h>
 #include <asm/system.h>
+#include <asm/byteorder.h>
 
 #include "8390.h"
 #include "3c503.h"
@@ -435,7 +436,7 @@
 {
     unsigned short int *wrd;
     int boguscount;		/* timeout counter */
-    unsigned shor tmp_rev;	/* temporary for reversed values */
+    unsigned short tmp_rev;	/* temporary for reversed values */
 
     if (ei_status.word16)      /* Tx packets go into bank 0 on EL2/16 card */
 	outb(EGACFR_RSEL|EGACFR_TCM, E33G_GACFR);
diff -u --recursive --new-file v1.3.70/linux/drivers/net/Config.in linux/drivers/net/Config.in
--- v1.3.70/linux/drivers/net/Config.in	Wed Feb 28 11:50:04 1996
+++ linux/drivers/net/Config.in	Sat Mar  2 13:18:49 1996
@@ -82,4 +82,8 @@
 if [ "$CONFIG_TR" = "y" ]; then
   tristate 'IBM Tropic chipset based adaptor support' CONFIG_IBMTR
 fi
-tristate 'Arcnet support' CONFIG_ARCNET
+tristate 'ARCnet support' CONFIG_ARCNET
+if [ "$CONFIG_ARCNET" != "n" ]; then
+  bool '  Enable arc0e (ARCnet "Ether-Encap" packet format)' CONFIG_ARCNET_ETH
+  bool '  Enable arc0s (ARCnet RFC1051 packet format)' CONFIG_ARCNET_1051
+fi
diff -u --recursive --new-file v1.3.70/linux/drivers/net/arcnet.c linux/drivers/net/arcnet.c
--- v1.3.70/linux/drivers/net/arcnet.c	Sat Mar  2 10:43:31 1996
+++ linux/drivers/net/arcnet.c	Sat Mar  2 13:18:49 1996
@@ -17,9 +17,31 @@
          
 	**********************
 	
-	This is ONLY A SUMMARY.  The complete ChangeLog is available in
-	the full Linux-ARCnet package.
-	
+	v2.51 (96/02/29)
+	  - Inserted a rather important missing "volatile" in autoprobe.
+	  - arc0e and arc0s are now options in drivers/net/Config.in.
+	
+	v2.50 (96/02/24)
+	  - Increased IRQ autoprobe delay.  Thanks to Andrew J. Kroll for
+	    noticing the problem, which seems to only affect certain cards.
+	  - Errors reserving ports and IRQ's now clean up after themselves.
+	  - We now replace the TESTvalue byte from unused shmem addresses.
+	  - You can now use "irq=" as well as "irqnum=" to set the IRQ
+	    during module autoprobe.  This doesn't seem to crash insmod
+	    anymore. (?)
+	  - You can now define the name of the ARCnet device more easily
+	    when loading the module: insmod arcnet.o device=test1
+	    A new option, CONFIG_ARCNET_ETHNAME, allows the kernel to
+	    choose one of the standard eth?-style device names
+	    automatically.  This currently only works as a module.
+	  - printk's now try to make some use of the KERN_xxx priority level
+	    macros (though they may not be perfect yet).
+	  - Packet and skb dump loops are now separate functions.
+	  - Removed D_INIT from default debug level, because I am (finally)
+	    pretty confident that autoprobe shouldn't toast anyone's
+	    computer.
+	  - This version is no longer ALPHA.
+
 	v2.41 ALPHA (96/02/10)
 	  - Incorporated changes someone made to arcnet_setup in 1.3.60.
 	  - Increased reset timeout to 3/10 of a second because some cards
@@ -72,37 +94,32 @@
 	    still a horrible mess and will be cleaned up further as time
 	    passes.
 	    
+	The following has been SUMMARIZED.  The complete ChangeLog is
+	available in the full Linux-ARCnet package.
+	
 	v2.22 (95/12/08)
 	  - Major cleanups, speedups, and better code-sharing.
 	  - Eliminated/changed many useless/meaningless/scary debug messages
 	    (and, in most cases, the bugs that caused them).
 	  - Better IPX support.
 	  - lp->stats updated properly.
-	  - RECON checking now by default only bugs you if there are an
-	    excessive number (ie. your cable is probably broken).
+	  - RECON checking now by default only prints a message if there are
+	    excessive errors (ie. your cable is probably broken).
 	  - New RFC1051-compliant "arc0s" virtual device by Tomasz
 	    Motylewski.
-	  - Excess debug messages can be compiled out for maximum
-	    efficiency.
+	  - Excess debug messages can be compiled out to reduce code size.
 
 	v2.00 (95/09/06)
-	  - ARCnet RECON messages are now detected and logged.  These occur
-	    when a new computer is powered up on the network, or in a
-	    constant stream when the network cable is broken.  Thanks to
-	    Tomasz Motylewski for this.  You must have D_EXTRA enabled
-	    if you want these messages sent to syslog, otherwise they will
-	    only show up in the network statistics (/proc/net/dev).
-	  - The TX Acknowledge flag is now checked, and a log message is sent
-	    if a completed transmit is not ACK'd.  (I have yet to have this
-	    happen to me.)
+	  - ARCnet RECON messages are now detected and logged as "carrier"
+	    errors.
+	  - The TXACK flag is now checked, and errors are logged.
 	  - Debug levels are now completely different.  See the README.
-	  - Many code cleanups, with several no-longer-necessary and some
+	  - Massive code cleanups, with several no-longer-necessary and some
 	    completely useless options removed.
 	  - Multiprotocol support.  You can now use the "arc0e" device to
 	    send "Ethernet-Encapsulation" packets, which are compatible with
 	    Windows for Workgroups and LAN Manager, and possibly other
 	    software.  See the README for more information.
-	  - Documentation updates and improvements.
 	  
 	v1.02 (95/06/21)
           - A fix to make "exception" packets sent from Linux receivable
@@ -119,16 +136,13 @@
 	  - Initial non-alpha release.
 	
          
-	TO DO: (it it just me, or does this list only get longer?)
+	TO DO: (semi-prioritized)
 	
-	 - Make sure autoprobe puts TESTvalue back into shmem locations
-	   that it determines aren't ARCnet cards.
-	 - Probe for multiple devices in one shot (there's supposed to
-	   be a way to do that now, but I can't remember what it is!)
-         - Support printk's priority levels.
-         - Have people test the new autoprobe a bit more - then remove
-           D_INIT from the default debug level.
-         - Move the SKB and memory dump code into separate functions.
+         - Make arcnetE_send_packet use arcnet_prepare_tx for loading the
+           packet into ARCnet memory.
+	 - Probe for multiple devices in one shot (trying to decide whether
+	   to do it the "ugly" way or not).
+         - Add support for the new 1.3.x IP header cache features.
 	 - Debug level should be changed with a system call, not a hack to
 	   the "metric" flag.
          - What about cards with shared memory that can be "turned off?"
@@ -139,9 +153,6 @@
          - Try to implement promiscuous (receive-all-packets) mode available
            on some newer cards with COM20020 and similar chips.  I don't have
            one, but SMC sent me the specs.
-         - Add support for the new 1.3.x IP header cache features.
-         - Make arcnetE_send_packet use arcnet_prepare_tx for loading the
-           packet into ARCnet memory.
          - ATA protocol support?? 
          - VINES TCP/IP encapsulation?? (info needed)
 
@@ -164,7 +175,7 @@
 */
 
 static const char *version =
- "arcnet.c: v2.41 ALPHA 96/02/10 Avery Pennarun <apenwarr@foxnet.net>\n";
+ "arcnet.c: v2.51 96/02/29 Avery Pennarun <apenwarr@foxnet.net>\n";
 
  
 
@@ -199,19 +210,12 @@
 
 /**************************************************************************/
 
-/* This driver supports three different "virtual ARCnet devices" running
- * on the same adapter, in order to communicate with various different
- * TCP/IP-over-ARCnet implementations.  They are:
- *	arc0	- RFC1201 Internet-standard protocol
- *	arc0e	- Ethernet-encapsulation protocol (as used by Windows)
- *	arc0s	- "Simpler" (but outdated) RFC1051 internet standard.
- *
- * arc0e and arc0s are created when arc0 is ifconfig'ed up.  You can disable
- * either or both of them by undefining CONFIG_ARCNET_ETH and/or
- * CONFIG_ARCNET_1051.
+/* Normally, the ARCnet device needs to be assigned a name (default arc0). 
+ * Ethernet devices have a fucntion to automatically try eth0, eth1, etc
+ * until a free name is found.  To name the ARCnet device using an "eth?"
+ * device name, define this option.
  */
-#define CONFIG_ARCNET_ETH
-#define CONFIG_ARCNET_1051
+#undef CONFIG_ARCNET_ETHNAME
 
 /* On a fast computer, the buffer copy from memory to the ARCnet card during
  * a transmit can hog the bus just a little too long.  SLOW_XMIT_COPY
@@ -270,9 +274,10 @@
  * shmem are left in the list at Stage 5, they must correspond to each
  * other.
  *
- * This is undefined by default because it might not always be true.  Speed
- * demons can turn it on - I think it should be fine if you only have one
- * ARCnet card installed.
+ * This is undefined by default because it might not always be true, and the
+ * extra check makes the autoprobe even more careful.  Speed demons can turn
+ * it on - I think it should be fine if you only have one ARCnet card
+ * installed.
  *
  * If no ARCnet cards are installed, this delay never happens anyway and thus
  * the option has no effect.
@@ -321,21 +326,22 @@
 #define D_SKB		128	/* show skb's				*/
 
 #ifndef ARCNET_DEBUG_MAX
-#define ARCNET_DEBUG_MAX (~0)		/* enable ALL debug messages */
-/*#define ARCNET_DEBUG_MAX (D_NORMAL|D_EXTRA|D_INIT|D_INIT_REASONS) */
-/*#define ARCNET_DEBUG_MAX 0	*/	/* enable NO debug messages */
+#define ARCNET_DEBUG_MAX (~0)		/* enable ALL debug messages	 */
+/*#define ARCNET_DEBUG_MAX (D_NORMAL|D_EXTRA|D_INIT|D_INIT_REASONS) 	 */
+/*#define ARCNET_DEBUG_MAX 0	*/	/* enable NO messages (bad idea) */
 #endif
 
 #ifndef ARCNET_DEBUG
-#define ARCNET_DEBUG (D_NORMAL|D_EXTRA|D_INIT)
-/*#define ARCNET_DEBUG (D_NORMAL)*/
+#define ARCNET_DEBUG (D_NORMAL|D_EXTRA)
 #endif
 int arcnet_debug = ARCNET_DEBUG;
 
 /* macros to simplify debug checking */
 #define BUGLVL(x) if ((ARCNET_DEBUG_MAX)&arcnet_debug&(x))
-#define BUGMSG2(x,msg,args...) BUGLVL(x) printk(msg , ## args)
-#define BUGMSG(x,msg,args...) BUGMSG2(x,"%6s: " msg, dev->name , ## args)
+#define BUGMSG2(x,msg,args...) BUGLVL(x) printk(msg, ## args)
+#define BUGMSG(x,msg,args...) BUGMSG2(x,"%s%6s: " msg, \
+	x==D_NORMAL ? "" : x<=D_INIT_REASONS ? KERN_INFO : KERN_DEBUG , \
+	dev->name , ## args)
 
 /* Some useful multiprotocol macros.  The idea here is that GCC will
  * optimize away multiple tests or assignments to lp->adev.  Relying on this
@@ -575,6 +581,21 @@
 
 
 /* Index to functions, as function prototypes. */
+
+#if ARCNET_DEBUG_MAX & D_SKB
+static void arcnet_dump_skb(struct device *dev,struct sk_buff *skb,
+	char *desc);
+#else
+#	define arcnet_dump_skb(dev,skb,desc) ;
+#endif
+
+#if (ARCNET_DEBUG_MAX & D_RX) || (ARCNET_DEBUG_MAX & D_TX)
+static void arcnet_dump_packet(struct device *dev,u_char *buffer,int ext,
+	char *desc);
+#else
+#	define arcnet_dump_packet(dev,buffer,ext,desc) ;
+#endif
+
 extern int arcnet_probe(struct device *dev);
 static int arcnet_found(struct device *dev,int port,int airq,u_long shmem);
 
@@ -634,7 +655,59 @@
 #define tx_done(dev) 1
 
 #define JIFFER(time) for (delayval=jiffies+time; jiffies<delayval;) ;
-		
+
+
+/****************************************************************************
+ *                                                                          *
+ * Packet dumps for debugging                                               *
+ *                                                                          *
+ ****************************************************************************/
+
+/* Dump the contents of an sk_buff
+ */ 
+#if ARCNET_DEBUG_MAX & D_SKB
+void arcnet_dump_skb(struct device *dev,struct sk_buff *skb,char *desc)
+{
+	int i;
+	long flags;
+	
+	save_flags(flags);
+	cli();
+	printk(KERN_DEBUG "%6s: skb dump (%s) follows:",dev->name,desc);
+        for(i=0; i<skb->len; i++)
+        {
+		if (i%16==0)
+			printk("\n" KERN_DEBUG "[%04X] ",i);
+		else
+                       	printk("%02X ",((u_char *)skb->data)[i]);
+	}
+        printk("\n");
+        restore_flags(flags);
+}
+#endif
+
+/* Dump the contents of an ARCnet buffer
+ */
+#if (ARCNET_DEBUG_MAX & D_RX) || (ARCNET_DEBUG_MAX & D_TX)
+void arcnet_dump_packet(struct device *dev,u_char *buffer,int ext,char *desc)
+{
+	int i;
+	long flags;
+	
+	save_flags(flags);
+	cli();
+	printk(KERN_DEBUG "%6s: packet dump (%s) follows:",dev->name,desc);
+	for (i=0; i<256+(ext!=0)*256; i++)
+	{
+		if (i%16==0)
+			printk("\n" KERN_DEBUG "[%04X] ",i);
+		else
+			printk("%02X ",buffer[i]);
+	}
+	printk("\n");
+	restore_flags(flags);
+}
+#endif 
 
 /****************************************************************************
  *                                                                          *
@@ -660,7 +733,8 @@
 	static int numports=sizeof(ports)/sizeof(ports[0]),
 	    	   numshmems=sizeof(shmems)/sizeof(shmems[0]);
 
-	int count,status,delayval,ioaddr,numprint,airq;
+	int count,status,delayval,ioaddr,numprint,airq,retval=-ENODEV,
+		openparen=0;
 	unsigned long airqmask;
 	int *port;
 	u_long *shmem;
@@ -682,7 +756,7 @@
 		sizeof(ports)+sizeof(shmems));
 
 	
-#if 1
+#if 0
 	BUGLVL(D_EXTRA)
 	{
 		printk("arcnet: ***\n");
@@ -795,7 +869,7 @@
 	numprint=0;
 	for (shmem = &shmems[0]; shmem-shmems<numshmems; shmem++)
 	{
-		u_char *cptr;
+		volatile u_char *cptr;
 	
 		numprint++;
 		if (numprint>8)
@@ -810,7 +884,7 @@
 		
 		if (*cptr != TESTvalue)
 		{
-			BUGMSG2(D_INIT_REASONS,"(mem=%Xh, not %Xh)\n",
+			BUGMSG2(D_INIT_REASONS,"(mem=%02Xh, not %02Xh)\n",
 				*cptr,TESTvalue);
 			BUGMSG(D_INIT_REASONS,"Stage 3: ");
 			BUGLVL(D_INIT_REASONS) numprint=0;
@@ -916,8 +990,8 @@
 			continue;
 		}
 
-		/* skip this if an IRQ was given, because maybe we're on a
-		 * machine that locks during autoirq!
+		/* skip this completely if an IRQ was given, because maybe
+		 * we're on a machine that locks during autoirq!
 		 */
 		if (!dev->irq)
 		{
@@ -927,7 +1001,7 @@
 			 */
 			airqmask = probe_irq_on();
 			outb(NORXflag,INTMASK);
-			/*udelay(1);*/
+			udelay(1);
 			outb(0,INTMASK);
 			airq = probe_irq_off(airqmask);
 	
@@ -948,6 +1022,7 @@
 		}
 		
 		BUGMSG2(D_INIT,"(%d,", airq);
+		openparen=1;
 		
 		/* Everything seems okay.  But which shmem, if any, puts
 		 * back its signature byte when the card is reset?
@@ -979,17 +1054,17 @@
 			if (*cptr == TESTvalue)	/* found one */
 			{
 				BUGMSG2(D_INIT,"%lXh)\n", *shmem);
+				openparen=0;
 
 				/* register the card */
-				status=arcnet_found(dev,*port,airq,*shmem);
+				retval=arcnet_found(dev,*port,airq,*shmem);
+				if (retval) openparen=0;
 
-				/* remove port and shmem from the lists */
-				*port=ports[numports-1];
-				numports--;
+				/* remove shmem from the list */
 				*shmem=shmems[numshmems-1];
 				numshmems--;
 				
-				return status;
+				break;
 			}
 			else
 			{
@@ -997,16 +1072,27 @@
 			}
 		}
 
-		BUGMSG2(D_INIT,"no matching shmem)\n");
-		BUGMSG(D_INIT_REASONS,"Stage 5: ");
-		BUGLVL(D_INIT_REASONS) numprint=0;
+		if (openparen)
+		{
+			BUGMSG2(D_INIT,"no matching shmem)\n");
+			BUGMSG(D_INIT_REASONS,"Stage 5: ");
+			BUGLVL(D_INIT_REASONS) numprint=0;
+		}
+
 		*port=ports[numports-1];
 		numports--;
 		port--;
+
+		if (!retval) break;
 	}
 	BUGMSG(D_INIT_REASONS,"\n");
 
-	return -ENODEV;
+	/* Now put back TESTvalue on all leftover shmems.
+	 */
+	for (shmem = &shmems[0]; shmem-shmems<numshmems; shmem++)
+		*(u_char *)(*shmem) = TESTvalue;
+
+	return retval;
 }
 
 /* Set up the struct device associated with this card.  Called after
@@ -1014,7 +1100,6 @@
  */
 int arcnet_found(struct device *dev,int port,int airq, u_long shmem)
 {
-	int irqval;
 	u_char *first_mirror,*last_mirror;
 	struct arcnet_local *lp;
 	
@@ -1023,11 +1108,10 @@
 	dev->base_addr=port;
 
 	/* reserve the irq */
-	irqval = request_irq(airq,&arcnet_interrupt,0,"arcnet",NULL);
-	if (irqval)
+	if (request_irq(airq,&arcnet_interrupt,0,"arcnet",NULL))
 	{
-		BUGMSG(D_NORMAL,"unable to get IRQ %d (irqval=%d).\n",
-			airq, irqval);
+		BUGMSG(D_NORMAL,"Can't get IRQ %d!\n",airq);
+		release_region(port,ARCNET_TOTAL_SIZE);
 		return -ENODEV;
 	}
 	irq2dev_map[airq]=dev;
@@ -1054,7 +1138,12 @@
 	
 	dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL);
 	if (dev->priv == NULL)
+	{
+		irq2dev_map[airq] = NULL;
+		free_irq(airq,NULL);
+		release_region(port,ARCNET_TOTAL_SIZE);
 		return -ENOMEM;
+	}
 	memset(dev->priv,0,sizeof(struct arcnet_local));
 	lp=(struct arcnet_local *)(dev->priv);
 	
@@ -1223,7 +1312,7 @@
 	if (dev->metric>=1000)
 	{
 		arcnet_debug=dev->metric-1000;
-		printk("%6s: debug level set to %d\n",dev->name,arcnet_debug);
+		printk(KERN_INFO "%6s: debug level set to %d\n",dev->name,arcnet_debug);
 		dev->metric=1;
 	}
 
@@ -1503,16 +1592,7 @@
 	out->hdr=(struct ClientData*)skb->data;
 	out->skb=skb;
 		
-	BUGLVL(D_SKB)
-	{
-		short i;
-		for(i=0; i<skb->len; i++)
-		{
-			if(i%16 == 0) printk("\n[%04hX] ",i);
-			printk("%02hX ",((unsigned char*)skb->data)[i]);
-		}
-		printk("\n");
-	}
+	BUGLVL(D_SKB) arcnet_dump_skb(dev,skb,"tx");
 
 	out->hdr->sequence=(lp->sequence++);
 	
@@ -1739,23 +1819,7 @@
 	BUGMSG(D_DURING,"transmitting packet to station %02Xh (%d bytes)\n",
 			daddr,length);
 			
-	BUGLVL(D_TX)
-	{
-		int countx,county;
-		
-		printk("%6s: packet dump [tx] follows:",dev->name);
-
- 		for (county=0; county<16+(length>MTU)*16; county++)
-		{
-			printk("\n[%04X] ",county*16);
-			for (countx=0; countx<16; countx++)
-				printk("%02X ",
-					arcpacket->raw[county*16+countx]);
-		}
-		
-		printk("\n");
-	}
-
+	BUGLVL(D_TX) arcnet_dump_packet(dev,arcpacket->raw,length>MTU,"tx");
 	lp->lastload_dest=daddr;
 	lp->txready=lp->txbuf;	/* packet is ready for sending */
 }
@@ -1828,7 +1892,7 @@
 	if (dev==NULL)
 	{
 		BUGLVL(D_DURING)
-			printk("arcnet: irq %d for unknown device.\n", irq);
+			printk(KERN_DEBUG "arcnet: irq %d for unknown device.\n", irq);
 		return;
 	}
 	
@@ -2075,8 +2139,9 @@
 #endif /* DETECT_RECONFIGS */
 	} while (--boguscount && didsomething);
 
-	BUGMSG(D_DURING,"net_interrupt complete (status=%Xh, count=%d)\n\n",
+	BUGMSG(D_DURING,"net_interrupt complete (status=%Xh, count=%d)\n",
 			inb(STATUS),boguscount);
+	BUGMSG(D_DURING,"\n");
 
 	SETMASK;	/* put back interrupt mask */
 
@@ -2168,22 +2233,7 @@
 		break;
 	}
 
-        BUGLVL(D_RX)
-	{
-        	int countx,county;
-        	
-        	printk("%6s: packet dump [rx] follows:",dev->name);
-
-       		for (county=0; county<16+(length>240)*16; county++)
-       		{
-       			printk("\n[%04X] ",county*16);
-       			for (countx=0; countx<16; countx++)
-       				printk("%02X ",
-       					arcpacket->raw[county*16+countx]);
-       		}
-       		
-       		printk("\n");
-       	}
+        BUGLVL(D_RX) arcnet_dump_packet(dev,arcpacket->raw,length>240,"rx");
 
 
 #ifndef SLOW_XMIT_COPY
@@ -2303,16 +2353,7 @@
          		}
          	}
          	
-		BUGLVL(D_SKB)
-		{
-	            short i;
-	               	for(i=0; i< skb->len; i++)
-               		{
-                       		if( i%16 == 0 ) printk("\n[%04hX] ",i);
-                       		printk("%02hX ",((unsigned char*)skb->data)[i]);
-               		}
-               		printk("\n");
-            	}
+		BUGLVL(D_SKB) arcnet_dump_skb(dev,skb,"rx");
 
 		skb->protocol=arcnetA_type_trans(skb,dev);
 
@@ -2473,17 +2514,7 @@
 	         		in->skb=NULL;
         	 		in->lastpacket=in->numpackets=0;
 			
-				BUGLVL(D_SKB)
-				{
-					short i;
-		        	       	for(i=0; i<skb->len; i++)
-               				{
-                		       		if( i%16 == 0 ) printk("\n[%04hX] ",i);
-                	       			printk("%02hX ",((unsigned char*)skb->data)[i]);
-	               			}
-        	       			printk("\n");
-	            		}
-
+				BUGLVL(D_SKB) arcnet_dump_skb(dev,skb,"rx");
 			
 				skb->protocol=arcnetA_type_trans(skb,dev);
 				
@@ -2808,22 +2839,7 @@
 	BUGMSG(D_DURING,"transmitting packet to station %02Xh (%d bytes)\n",
 			daddr,length);
 				
-	BUGLVL(D_TX)
-	{
-		int countx,county;
-			
-		printk("%6s: packet dump [tx] follows:",dev->name);
-
- 		for (county=0; county<16+(length>=240)*16; county++)
-		{
-			printk("\n[%04X] ",county*16);
-			for (countx=0; countx<16; countx++)
-				printk("%02X ",
-					arcpacket->raw[county*16+countx]);
-		}
-		
-		printk("\n");
-	}
+	BUGLVL(D_TX) arcnet_dump_packet(dev,arcpacket->raw,length>=240,"tx");
 
 	lp->lastload_dest=daddr;
 	lp->txready=lp->txbuf;	/* packet is ready for sending */
@@ -2872,20 +2888,8 @@
        	
        	memcpy(skb->data,(u_char *)arcsoft+1,length-1);
 
-        BUGLVL(D_SKB)
-        {
-		short i;
-		printk("%6s: rx skb dump follows:\n",dev->name);
-                for(i=0; i<skb->len; i++)
-                {
-			if (i%16==0)
-				printk("\n[%04hX] ",i);
-			else
-                        	printk("%02hX ",((u_char *)skb->data)[i]);
-		}
-                printk("\n");
-        }
-        
+        BUGLVL(D_SKB) arcnet_dump_skb(dev,skb,"rx");
+
 	skb->protocol=eth_type_trans(skb,dev);
         
         netif_rx(skb);
@@ -2946,16 +2950,7 @@
 
 	length = 1 < skb->len ? skb->len : 1;
 
-	BUGLVL(D_SKB)
-	{
-		short i;
-		for(i=0; i<skb->len; i++)
-		{
-			if (i%16 == 0) printk("\n[%04hX] ",i);
-			printk("%02hX ",((unsigned char*)skb->data)[i]);
-		}
-		printk("\n");
-	}
+	BUGLVL(D_SKB) arcnet_dump_skb(dev,skb,"tx");
 
 	/* fits in one packet? */
 	if (length-S_EXTRA_CLIENTDATA<=XMTU)
@@ -3037,16 +3032,7 @@
          	soft->saddr=saddr;
          	skb->dev = dev;  /* is already lp->sdev */
          	
-		BUGLVL(D_SKB)
-		{
-	        	short i;
-	               	for(i=0; i<skb->len; i++)
-               		{
-                       		if( i%16 == 0 ) printk("\n[%04hX] ",i);
-                       		printk("%02hX ",((unsigned char*)skb->data)[i]);
-               		}
-               		printk("\n");
-            	}
+		BUGLVL(D_SKB) arcnet_dump_skb(dev,skb,"rx");
 
 		skb->protocol=arcnetS_type_trans(skb,dev);
 
@@ -3198,7 +3184,8 @@
 
 
 #ifdef MODULE
-static char devicename[9] = { 0, };
+
+static char devicename[9] = "";
 static struct device thiscard = {
   devicename, /* device name is inserted by linux/drivers/net/net_init.c */
   0, 0, 0, 0,
@@ -3209,15 +3196,22 @@
 	
 static int io=0x0;	/* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */
 static int irqnum=0;	/* or use the insmod io= irqnum= shmem= options */
+static int irq=0;
 static int shmem=0;
-static int num=0;	/* number of device (ie for 0 for arc0, 1 for arc1...) */
+static char *device = NULL;
 
 int
 init_module(void)
 {
-	sprintf(thiscard.name,"arc%d",num);
+	if (device)
+		strcpy(thiscard.name,device);
+#ifndef CONFIG_ARCNET_ETHNAME
+	else if (!thiscard.name[0]) strcpy(thiscard.name,"arc0");
+#endif
 
 	thiscard.base_addr=io;
+	
+	if (irq) irqnum=irq;
 
 	thiscard.irq=irqnum;
 	if (thiscard.irq==2) thiscard.irq=9;
@@ -3252,9 +3246,8 @@
 
 	if (thiscard.irq)
 	{
-		free_irq(thiscard.irq,NULL);
-		/* very important! */
 		irq2dev_map[thiscard.irq] = NULL;
+		free_irq(thiscard.irq,NULL);
 	}
 	
 	if (thiscard.base_addr) release_region(thiscard.base_addr,
diff -u --recursive --new-file v1.3.70/linux/drivers/net/eexpress.c linux/drivers/net/eexpress.c
--- v1.3.70/linux/drivers/net/eexpress.c	Sat Mar  2 10:43:32 1996
+++ linux/drivers/net/eexpress.c	Mon Mar  4 10:24:13 1996
@@ -1,39 +1,105 @@
-/* eexpress.c: Intel EtherExpress device driver for Linux. */
 /*
-	Written 1993 by Donald Becker.
-	Copyright 1993 United States Government as represented by the Director,
-	National Security Agency.  This software may only be used and distributed
-	according to the terms of the GNU Public License as modified by SRC,
-	incorporated herein by reference.
-
-	The author may be reached as becker@super.org or
-	C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
-
-	Things remaining to do:
-	Check that the 586 and ASIC are reset/unreset at the right times.
-	Check tx and rx buffer setup.
-	The current Tx is single-buffer-only.
-	Move the theory of operation and memory map documentation.
-	Rework the board error reset
-	The statistics need to be updated correctly.
-
-        Modularized by Pauline Middelink <middelin@polyware.iaf.nl>
-        Changed to support io= irq= by Alan Cox <Alan.Cox@linux.org>
-*/
-
-static const char *version =
-	"eexpress.c:v0.07 1/19/94 Donald Becker (becker@super.org)\n";
-
-/*
-  Sources:
-	This driver wouldn't have been written with the availability of the
-	Crynwr driver source code.	It provided a known-working implementation
-	that filled in the gaping holes of the Intel documentation.  Three cheers
-	for Russ Nelson.
-
-	Intel Microcommunications Databook, Vol. 1, 1990. It provides just enough
-	info that the casual reader might think that it documents the i82586.
-*/
+ * eexpress2.c: Intel EtherExpress device driver for Linux
+ *
+ * Original version written 1993 by Donald Becker
+ * Modularized by Pauline Middelink <middelin@polyware.iaf.nl>
+ * Changed to support io= irq= by Alan Cox <Alan.Cox@linux.org>
+ * Reworked 1995 by John Sullivan <js10039@cam.ac.uk>
+ * 
+ *  31jan96 Philip Blundell <pjb27@cam.ac.uk>
+ *     - Tidy up
+ *     - Some debugging.  Now works with 1.3 kernels.
+ *
+ *     Still to do:
+ *     - rationalise debugging
+ *     - fix detect/autoprobe and module routines
+ *     - test under high load, try to chase CU lockups
+ *     - look at RAM size check
+ *
+ * ToDo:
+ *   Move private globals into net_local structure
+ *   Multicast/Promiscuous mode handling
+ *   Put back debug reporting?
+ *   More documentation
+ *   Some worry about whether statistics are reported accurately
+ *
+ */
+
+/*
+ * The original EtherExpress driver was just about useable, but
+ * suffered from a long startup delay, a hard limit of 16k memory
+ * usage on the card (EtherExpress 16s have either 32k or 64k),
+ * and random locks under load. The last was particularly annoying
+ * and made running eXceed/W preferable to Linux/XFree. After hacking
+ * through the driver for a couple of days, I had fixed most of the
+ * card handling errors, at the expense of turning the code into
+ * a complete jungle, but still hadn't tracked down the lock-ups.
+ * I had hoped these would be an IP bug, but failed to reproduce them
+ * under other drivers, so decided to start from scratch and rewrite
+ * the driver cleanly. And here it is.
+ *
+ * It's still not quite there, but self-corrects a lot more problems.
+ * the 'CU wedged, resetting...' message shouldn't happen at all, but
+ * at least we recover. It still locks occasionally, any ideas welcome.
+ *
+ * The original startup delay experienced by some people was due to the
+ * first ARP request for the address of the default router getting lost.
+ * (mostly the reply we were getting back was arriving before our
+ * hardware address was set up, or before the configuration sequence
+ * had told the card NOT to strip of the frame header). If you a long
+ * startup delay, you may have lost this ARP request/reply, although
+ * the original cause has been fixed. However, it is more likely that
+ * you've just locked under this version.
+ *
+ * The main changes are in the 586 initialization procedure (which was
+ * just broken before - the EExp is a strange beasty and needs careful
+ * handling) the receive buffer handling (we now use a non-terminating
+ * circular list of buffers, which stops the card giving us out-of-
+ * resources errors), and the transmit code. The driver is also more
+ * structured, and I have tried to keep the kernel interface separate
+ * from the hardware interface (although some routines naturally want
+ * to do both).
+ *
+ * John Sullivan
+ *
+ * 18/5/95:
+ *
+ * The lock-ups seem to happen when you access card memory after a 586
+ * reset. This happens only 1 in 12 resets, on a random basis, and
+ * completely locks the machine. As far as I can see there is no
+ * workaround possible - the only thing to be done is make sure we
+ * never reset the card *after* booting the kernel - once at probe time
+ * must be sufficient, and we'll just have to put up with that failing
+ * occasionally (or buy a new NIC). By the way, this looks like a 
+ * definate card bug, since Intel's own driver for DOS does exactly the
+ * same.
+ */
+
+/*
+ * Sources:
+ *
+ * The original eexpress.c by Donald Becker
+ *   Sources: the Crynwr EtherExpress driver source.
+ *            the Intel Microcommunications Databook Vol.1 1990
+ *
+ * wavelan.c and i82586.h
+ *   This was invaluable for the complete '586 configuration details
+ *   and command format.
+ *
+ * The Crynwr sources (again)
+ *   Not as useful as the Wavelan driver, but then I had eexpress.c to
+ *   go off.
+ *
+ * The Intel EtherExpress 16 ethernet card
+ *   Provided the only reason I want to see a working etherexpress driver.
+ *   A lot of fixes came from just observing how the card (mis)behaves when
+ *   you prod it.
+ *
+ */
+
+static char version[] = 
+"eexpress.c: v0.07 1/19/94 Donald Becker <becker@super.org>\n"
+"            v0.10 4th May 1995 John Sullivan <js10039@cam.ac.uk>\n";
 
 #include <linux/module.h>
 
@@ -57,978 +123,1108 @@
 #include <linux/skbuff.h>
 #include <linux/malloc.h>
 
-/* use 0 for production, 1 for verification, 2..7 for debug */
+/*
+ * Not actually used yet - may be implemented when the driver has
+ * been debugged!
+ *
+ * Debug Level		Driver Status
+ *	0		Final release
+ *	1		Beta test
+ *	2
+ *	3
+ * 	4		Report timeouts & 586 errors (normal debug level)
+ *	5		Report all major events
+ *	6		Dump sent/received packet contents
+ *	7		Report function entry/exit
+ */
+
+#undef NET_DEBUG
+
 #ifndef NET_DEBUG
-#define NET_DEBUG 2
+#define NET_DEBUG 4
 #endif
 static unsigned int net_debug = NET_DEBUG;
 
-/*
-  			Details of the i82586.
-
-   You'll really need the databook to understand the details of this part,
-   but the outline is that the i82586 has two separate processing units.
-
-   The Rx unit uses a list of frame descriptors and a list of data buffer
-   descriptors.  We use full-sized (1518 byte) data buffers, so there is
-   a one-to-one pairing of frame descriptors to buffer descriptors.
+#undef F_DEB
 
-   The Tx ("command") unit executes a list of commands that look like:
-		Status word		Written by the 82586 when the command is done.
-		Command word	Command in lower 3 bits, post-command action in upper 3
-		Link word		The address of the next command.
-		Parameters		(as needed).
+#include "eth82586.h"
 
-	Some definitions related to the Command Word are:
+/*
+ * Private data declarations
  */
-#define CMD_EOL		0x8000			/* The last command of the list, stop. */
-#define CMD_SUSP	0x4000			/* Suspend after doing cmd. */
-#define CMD_INTR	0x2000			/* Interrupt after doing cmd. */
-
-enum commands {
-	CmdNOp = 0, CmdSASetup = 1, CmdConfigure = 2, CmdMulticastList = 3,
-	CmdTx = 4, CmdTDR = 5, CmdDump = 6, CmdDiagnose = 7};
 
-/* Information that need to be kept for each board. */
-struct net_local {
+struct net_local 
+{
 	struct enet_statistics stats;
-	int last_restart;
-	short rx_head;
-	short rx_tail;
-	short tx_head;
-	short tx_cmd_link;
-	short tx_reap;
+	unsigned long init_time;        /* jiffies when eexp_hw_init586 called */
+	unsigned short rx_first;        /* first rx buf, same as RX_BUF_START */
+	unsigned short rx_last;         /* last rx buf */
+	unsigned short tx_head;         /* next free tx buf */
+	unsigned short tx_reap;         /* first in-use tx buf */
+	unsigned short tx_tail;         /* previous tx buf to tx_head */
+	unsigned short tx_link;         /* last known-executing tx buf */
+	unsigned short last_tx_restart; /* set to tx_link when we restart the CU */
 };
 
-/*
-  		Details of the EtherExpress Implementation
-  The EtherExpress takes an unusual approach to host access to packet buffer
-  memory.  The host can use either the Dataport, with independent
-  autoincrementing read and write pointers, or it can I/O map 32 bytes of the
-  memory using the "Shadow Memory Pointer" (SMB) as follows:
-			ioaddr						Normal EtherExpress registers
-			ioaddr+0x4000...0x400f		Buffer Memory at SMB...SMB+15
-			ioaddr+0x8000...0x800f		Buffer Memory at SMB+16...SMB+31
-			ioaddr+0xC000...0xC007		"" SMB+16...SMB+23 (hardware flaw?)
-			ioaddr+0xC008...0xC00f		Buffer Memory at 0x0008...0x000f
-  The last I/O map set is useful if you put the i82586 System Command Block
-  (the command mailbox) exactly at 0x0008.  (There seems to be some
-  undocumented init structure at 0x0000-7, so I had to use the Crywnr memory
-  setup verbatim for those four words anyway.)
-
-  A problem with using either one of these mechanisms is that you must run
-  single-threaded, or the interrupt handler must restore a changed value of
-  the read, write, or SMB pointers.
-
-  Unlike the Crynwr driver, my driver mostly ignores the I/O mapped "feature"
-  and relies heavily on the dataport for buffer memory access.  To minimize
-  switching, the read_pointer is dedicated to the Rx interrupt handler, and
-  the write_pointer is used by the send_packet() routine (it's carefully saved
-  and restored when it's needed by the interrupt handler).
-  */
-
-/* Offsets from the base I/O address. */
-#define DATAPORT	0	/* Data Transfer Register. */
-#define WRITE_PTR	2	/* Write Address Pointer. */
-#define READ_PTR	4	/* Read Address Pointer. */
-#define SIGNAL_CA	6	/* Frob the 82586 Channel Attention line. */
-#define SET_IRQ		7	/* IRQ Select. */
-#define SHADOW_PTR	8	/* Shadow Memory Bank Pointer. */
-#define MEM_Ctrl	11
-#define MEM_Page_Ctrl	12
-#define Config		13
-#define EEPROM_Ctrl		14
-#define ID_PORT		15
-
-#define EEXPRESS_IO_EXTENT 16
-
-/*	EEPROM_Ctrl bits. */
-
-#define EE_SHIFT_CLK	0x01	/* EEPROM shift clock. */
-#define EE_CS			0x02	/* EEPROM chip select. */
-#define EE_DATA_WRITE	0x04	/* EEPROM chip data in. */
-#define EE_DATA_READ	0x08	/* EEPROM chip data out. */
-#define EE_CTRL_BITS	(EE_SHIFT_CLK | EE_CS | EE_DATA_WRITE | EE_DATA_READ)
-#define ASIC_RESET		0x40
-#define _586_RESET		0x80
-
-/* Offsets to elements of the System Control Block structure. */
-#define SCB_STATUS	0xc008
-#define SCB_CMD		0xc00A
-#define	 CUC_START	 0x0100
-#define	 CUC_RESUME	 0x0200
-#define	 CUC_SUSPEND 0x0300
-#define	 RX_START	 0x0010
-#define	 RX_RESUME	 0x0020
-#define	 RX_SUSPEND	 0x0030
-#define SCB_CBL		0xc00C	/* Command BLock offset. */
-#define SCB_RFA		0xc00E	/* Rx Frame Area offset. */
-
-/*
-  What follows in 'init_words[]' is the "program" that is downloaded to the
-  82586 memory.	 It's mostly tables and command blocks, and starts at the
-  reset address 0xfffff6.
-
-  Even with the additional "don't care" values, doing it this way takes less
-  program space than initializing the individual tables, and I feel it's much
-  cleaner.
-
-  The databook is particularly useless for the first two structures; they are
-  completely undocumented.  I had to use the Crynwr driver as an example.
-
-   The memory setup is as follows:
-   */
-
-#define CONFIG_CMD	0x0018
-#define SET_SA_CMD	0x0024
-#define SA_OFFSET	0x002A
-#define IDLELOOP	0x30
-#define TDR_CMD		0x38
-#define TDR_TIME	0x3C
-#define DUMP_CMD	0x40
-#define DIAG_CMD	0x48
-#define SET_MC_CMD	0x4E
-#define DUMP_DATA	0x56	/* A 170 byte buffer for dump and Set-MC into. */
-
-#define TX_BUF_START	0x0100
-#define NUM_TX_BUFS 	4
-#define TX_BUF_SIZE		0x0680	/* packet+header+TBD+extra (1518+14+20+16) */
-#define TX_BUF_END		0x2000
-
-#define RX_BUF_START	0x2000
-#define RX_BUF_SIZE 	(0x640)	/* packet+header+RBD+extra */
-#define RX_BUF_END		0x4000
-
-/*
-  That's it: only 86 bytes to set up the beast, including every extra
-  command available.  The 170 byte buffer at DUMP_DATA is shared between the
-  Dump command (called only by the diagnostic program) and the SetMulticastList
-  command.
-
-  To complete the memory setup you only have to write the station address at
-  SA_OFFSET and create the Tx & Rx buffer lists.
-
-  The Tx command chain and buffer list is setup as follows:
-  A Tx command table, with the data buffer pointing to...
-  A Tx data buffer descriptor.  The packet is in a single buffer, rather than
-     chaining together several smaller buffers.
-  A NoOp command, which initially points to itself,
-  And the packet data.
-
-  A transmit is done by filling in the Tx command table and data buffer,
-  re-writing the NoOp command, and finally changing the offset of the last
-  command to point to the current Tx command.  When the Tx command is finished,
-  it jumps to the NoOp, when it loops until the next Tx command changes the
-  "link offset" in the NoOp.  This way the 82586 never has to go through the
-  slow restart sequence.
-
-  The Rx buffer list is set up in the obvious ring structure.  We have enough
-  memory (and low enough interrupt latency) that we can avoid the complicated
-  Rx buffer linked lists by alway associating a full-size Rx data buffer with
-  each Rx data frame.
-
-  I current use four transmit buffers starting at TX_BUF_START (0x0100), and
-  use the rest of memory, from RX_BUF_START to RX_BUF_END, for Rx buffers.
-
-  */
-
-static short init_words[] = {
-	0x0000,					/* Set bus size to 16 bits. */
-	0x0000,0x0000,			/* Set control mailbox (SCB) addr. */
-	0,0,					/* pad to 0x000000. */
-	0x0001,					/* Status word that's cleared when init is done. */
-	0x0008,0,0,				/* SCB offset, (skip, skip) */
-
-	0,0xf000|RX_START|CUC_START,	/* SCB status and cmd. */
-	CONFIG_CMD,				/* Command list pointer, points to Configure. */
-	RX_BUF_START,				/* Rx block list. */
-	0,0,0,0,				/* Error count: CRC, align, buffer, overrun. */
-
-	/* 0x0018: Configure command.  Change to put MAC data with packet. */
-	0, CmdConfigure,		/* Status, command.		*/
-	SET_SA_CMD,				/* Next command is Set Station Addr. */
-	0x0804,					/* "4" bytes of config data, 8 byte FIFO. */
-	0x2e40,					/* Magic values, including MAC data location. */
-	0,						/* Unused pad word. */
-
-	/* 0x0024: Setup station address command. */
-	0, CmdSASetup,
-	SET_MC_CMD,				/* Next command. */
-	0xaa00,0xb000,0x0bad,	/* Station address (to be filled in) */
-
-	/* 0x0030: NOP, looping back to itself.	 Point to first Tx buffer to Tx. */
-	0, CmdNOp, IDLELOOP, 0 /* pad */,
-
-	/* 0x0038: A unused Time-Domain Reflectometer command. */
-	0, CmdTDR, IDLELOOP, 0,
-
-	/* 0x0040: An unused Dump State command. */
-	0, CmdDump, IDLELOOP, DUMP_DATA,
-
-	/* 0x0048: An unused Diagnose command. */
-	0, CmdDiagnose, IDLELOOP,
-
-	/* 0x004E: An empty set-multicast-list command. */
-#ifdef initial_text_tx
-	0, CmdMulticastList, DUMP_DATA, 0,
-#else
-	0, CmdMulticastList, IDLELOOP, 0,
-#endif
+unsigned short start_code[] = {
+	0x0000,                 /* SCP: set bus to 16 bits */
+	0x0000,0x0000,          /* junk */
+	0x0000,0x0000,          /* address of ISCP (lo,hi) */
+
+	0x0001,                 /* ISCP: busy - cleared after reset */
+	0x0008,0x0000,0x0000,   /* offsett,address (lo,hi) of SCB */
+
+	0x0000,0x0000,          /* SCB: status, commands */
+	0x0000,0x0000,          /* links to first command block, first receive descriptor */
+	0x0000,0x0000,          /* CRC error, alignment error counts */
+	0x0000,0x0000,          /* out of resources, overrun error counts */
+
+	0x0000,0x0000,          /* pad */
+	0x0000,0x0000,
+
+	0x0000,Cmd_Config,      /* startup configure sequence, at 0x0020 */
+	0x0032,                 /* link to next command */
+	0x080c,                 /* 12 bytes follow : fifo threshold=8 */
+	0x2e40,                 /* don't rx bad frames : SRDY/ARDY => ext. sync. : preamble len=8
+	                         * take addresses from data buffers : 6 bytes/address */
+	0x6000,                 /* default backoff method & priority : interframe spacing = 0x60 */
+	0xf200,                 /* slot time=0x200 : max collision retry = 0xf */
+	0x0000,                 /* no HDLC : normal CRC : enable broadcast : disable promiscuous/multicast modes */
+	0x003c,                 /* minimum frame length = 60 octets) */
+
+	0x0000,Cmd_INT|Cmd_SetAddr,
+	0x003e,                 /* link to next command */
+	0x0000,0x0000,0x0000,   /* hardware address placed here, 0x0038 */
+	0x0000,Cmd_END|Cmd_Nop, /* end of configure sequence */
+	0x003e,
 
-	/* 0x0056: A continuous transmit command, only here for testing. */
-	0, CmdTx, DUMP_DATA, DUMP_DATA+8, 0x83ff, -1, DUMP_DATA, 0,
-};
+	0x0000
 
-/* Index to functions, as function prototypes. */
+};
 
-extern int express_probe(struct device *dev);	/* Called from Space.c */
+#define CONF_LINK 0x0020
+#define CONF_HW_ADDR 0x0038
 
-static int	eexp_probe1(struct device *dev, short ioaddr);
-static int	eexp_open(struct device *dev);
-static int	eexp_send_packet(struct sk_buff *skb, struct device *dev);
-static void	eexp_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static void eexp_rx(struct device *dev);
-static int	eexp_close(struct device *dev);
-static struct enet_statistics *eexp_get_stats(struct device *dev);
-static void set_multicast_list(struct device *dev);
-
-static int read_eeprom(int ioaddr, int location);
-static void hardware_send_packet(struct device *dev, void *buf, short length);
-static void init_82586_mem(struct device *dev);
-static void init_rx_bufs(struct device *dev);
-
-
-/* Check for a network adaptor of this type, and return '0' iff one exists.
-   If dev->base_addr == 0, probe all likely locations.
-   If dev->base_addr == 1, always return failure.
-   If dev->base_addr == 2, (detachable devices only) allocate space for the
-   device and return success.
-   */
-int
-express_probe(struct device *dev)
-{
-	/* Don't probe all settable addresses, 0x[23][0-7]0, just common ones. */
-	int *port, ports[] = {0x300, 0x270, 0x320, 0x340, 0};
-	int base_addr = dev->base_addr;
-
-	if (base_addr > 0x1ff)	/* Check a single specified location. */
-		return eexp_probe1(dev, base_addr);
-	else if (base_addr > 0)
-		return ENXIO;		/* Don't probe at all. */
+/* maps irq number to EtherExpress magic value */
+static char irqrmap[] = { 0,0,1,2,3,4,0,0,0,1,5,6,0,0,0,0 };
 
-	for (port = &ports[0]; *port; port++) {
-		short id_addr = *port + ID_PORT;
-		unsigned short sum = 0;
-		int i;
-#ifdef notdef
-		for (i = 16; i > 0; i--)
-			sum += inb(id_addr);
-		printk("EtherExpress ID checksum is %04x.\n", sum);
-#else
-		for (i = 4; i > 0; i--) {
-			short id_val = inb(id_addr);
-			sum |= (id_val >> 4) << ((id_val & 3) << 2);
-		}
-#endif
-		if (sum == 0xbaba
-			&& eexp_probe1(dev, *port) == 0)
-			return 0;
-	}
-
-	return ENODEV;
-}
-
-int eexp_probe1(struct device *dev, short ioaddr)
-{
-	unsigned short station_addr[3];
-	int i;
+static unsigned char started=0;
 
-	printk("%s: EtherExpress at %#x,", dev->name, ioaddr);
+/*
+ * Prototypes for Linux interface
+ */
 
-	/* The station address is stored !backwards! in the EEPROM, reverse
-	   after reading.  (Hmmm, a little brain-damage there at Intel, eh?) */
-	station_addr[0] = read_eeprom(ioaddr, 2);
-	station_addr[1] = read_eeprom(ioaddr, 3);
-	station_addr[2] = read_eeprom(ioaddr, 4);
-
-	/* Check the first three octets of the S.A. for the manufacturer's code. */
-	if (station_addr[2] != 0x00aa || (station_addr[1] & 0xff00) != 0x0000) {
-		printk(" rejected (invalid address %04x%04x%04x).\n",
-			   station_addr[2], station_addr[1], station_addr[0]);
-		return ENODEV;
-	}
+extern int                  express_probe(struct device *dev);
+static int                     eexp_open (struct device *dev);
+static int                     eexp_close(struct device *dev);
+static struct enet_statistics *eexp_stats(struct device *dev);
+static int                     eexp_xmit (struct sk_buff *buf, struct device *dev);
 
-	/* We've committed to using the board, and can start filling in *dev. */
-	request_region(ioaddr, EEXPRESS_IO_EXTENT, "eexpress");
-	dev->base_addr = ioaddr;
+static void                    eexp_irq  (int irq, void *dev_addr, struct pt_regs *regs);
 
-	for (i = 0; i < 6; i++) {
-		dev->dev_addr[i] = ((unsigned char*)station_addr)[5-i];
-		printk(" %02x", dev->dev_addr[i]);
-	}
-
-	/* There is no reason for the driver to care, but I print out the
-	   interface to minimize bogus bug reports. */
-	{
-		char irqmap[] = {0, 9, 3, 4, 5, 10, 11, 0};
-		const char *ifmap[] = {"AUI", "BNC", "10baseT"};
-		enum iftype {AUI=0, BNC=1, TP=2};
-		unsigned short setupval = read_eeprom(ioaddr, 0);
+/*
+ * Prototypes for hardware access functions
+ */
 
-		dev->irq = irqmap[setupval >> 13];
-		dev->if_port = (setupval & 0x1000) == 0 ? AUI :
-			read_eeprom(ioaddr, 5) & 0x1 ? TP : BNC;
-		printk(", IRQ %d, Interface %s.\n", dev->irq, ifmap[dev->if_port]);
-		/* Release the IRQ line so that it can be shared if we don't use the
-		   ethercard. */
-		outb(0x00, ioaddr + SET_IRQ);
-	}
+static void           eexp_hw_rx        (struct device *dev);
+static void           eexp_hw_tx        (struct device *dev, unsigned short *buf, unsigned short len);
+static int            eexp_hw_probe     (struct device *dev,unsigned short ioaddr);
+static unsigned short eexp_hw_readeeprom(unsigned short ioaddr, unsigned char location);
+
+static unsigned short eexp_hw_lasttxstat(struct device *dev);
+static void           eexp_hw_txrestart (struct device *dev);
+
+static void           eexp_hw_txinit    (struct device *dev);
+static void           eexp_hw_rxinit    (struct device *dev);
+static void           eexp_hw_rxmap     (struct device *dev,unsigned short rx_buf);
 
-	/* It's now OK to leave the board in reset, pending the open(). */
-	outb(ASIC_RESET, ioaddr + EEPROM_Ctrl);
+static void           eexp_hw_init586   (struct device *dev);
+static void           eexp_hw_ASICrst   (struct device *dev);
 
-	if ((dev->mem_start & 0xf) > 0)
-		net_debug = dev->mem_start & 7;
+/*
+ * Linux interface
+ */
 
-	if (net_debug)
-		printk(version);
+/*
+ * checks for presence of EtherExpress card
+ */
 
-	/* 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));
+int express_probe(struct device *dev)
+{
+	unsigned short *port,ports[] = { 0x0300,0x0270,0x0320,0x0340,0 };
+	unsigned short ioaddr = dev->base_addr;
 
-	dev->open		= eexp_open;
-	dev->stop		= eexp_close;
-	dev->hard_start_xmit = eexp_send_packet;
-	dev->get_stats	= eexp_get_stats;
-	dev->set_multicast_list = &set_multicast_list;
+	if (ioaddr&0xfe00)
+		return eexp_hw_probe(dev,ioaddr);
+	else if (ioaddr)
+		return ENXIO;
 
-	/* Fill in the fields of the device structure with ethernet-generic values. */
-	
-	ether_setup(dev);
-	
-	dev->flags&=~IFF_MULTICAST;
-		
-	return 0;
+	for ( port=&ports[0] ; *port ; port++ ) 
+	{
+		unsigned short sum = 0;
+		int i;
+		for ( i=0 ; i<4 ; i++ ) 
+		{
+			unsigned short t;
+			t = inb(*port + ID_PORT);
+			sum |= (t>>4) << ((t & 0x03)<<2);
+		}
+		if (sum==0xbaba && !eexp_hw_probe(dev,*port)) 
+			return 0;
+	}
+	return ENODEV;
 }
 
-
-/* Reverse IRQ map: the value to put in the SET_IRQ reg. for IRQ<index>. */
-static char irqrmap[]={0,0,1,2,3,4,0,0,0,1,5,6,0,0,0,0};
+/*
+ * open and initialize the adapter, ready for use
+ */
 
-static int
-eexp_open(struct device *dev)
+static int eexp_open(struct device *dev)
 {
-	int ioaddr = dev->base_addr;
+	int irq = dev->irq;
+	unsigned short ioaddr = dev->base_addr;
+
+#if NET_DEBUG > 6
+	printk("%s: eexp_open()\n", dev->name);
+#endif
 
-	if (dev->irq == 0  ||  irqrmap[dev->irq] == 0)
+	if (!irq || !irqrmap[irq]) 
 		return -ENXIO;
 
-	if (irq2dev_map[dev->irq] != 0
-		/* This is always true, but avoid the false IRQ. */
-		|| (irq2dev_map[dev->irq] = dev) == 0
-		|| request_irq(dev->irq, &eexp_interrupt, 0, "EExpress", NULL)) {
+	if (irq2dev_map[irq] ||
+	      /* more consistent, surely? */
+	   ((irq2dev_map[irq]=dev),0) ||
+	     request_irq(irq,&eexp_irq,0,"EExpress",NULL)) 
 		return -EAGAIN;
-	}
-
-	/* Initialize the 82586 memory and start it. */
-	init_82586_mem(dev);
-
-	/* Enable the interrupt line. */
-	outb(irqrmap[dev->irq] | 0x08, ioaddr + SET_IRQ);
 
+	request_region(ioaddr,16,"EExpress");
 	dev->tbusy = 0;
 	dev->interrupt = 0;
+	eexp_hw_init586(dev);
 	dev->start = 1;
-	MOD_INC_USE_COUNT;
 	return 0;
 }
 
-static int
-eexp_send_packet(struct sk_buff *skb, struct device *dev)
+/*
+ * close and disable the interface, leaving
+ * the 586 in reset
+ */
+static int eexp_close(struct device *dev)
+{
+	unsigned short ioaddr = dev->base_addr;
+	int irq = dev->irq;
+
+	dev->tbusy = 1; 
+	dev->start = 0;
+  
+	outb(SIRQ_dis|irqrmap[irq],ioaddr+SET_IRQ);
+	started = 0;
+	outw(SCB_CUsuspend|SCB_RUsuspend,ioaddr+SCB_CMD);
+	outb(0,ioaddr+SIGNAL_CA);
+	free_irq(irq,NULL);
+	irq2dev_map[irq] = NULL;
+	outb(i586_RST,ioaddr+EEPROM_Ctrl);
+	release_region(ioaddr,16);
+	return 0;
+}
+
+/*
+ * Return interface stats
+ */
+
+static struct enet_statistics *eexp_stats(struct device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+
+	/* 
+	 * Hmmm, this looks a little too easy... The card maintains
+	 * some stats in the SCB, and I'm not convinced we're
+	 * incrementing the most sensible statistics when the card
+	 * returns an error (esp. slow DMA, out-of-resources)
+	 */
+	return &lp->stats;
+}
+
+/*
+ * Called to transmit a packet, or to allow us to right ourselves
+ * if the kernel thinks we've died.
+ */
+
+static int eexp_xmit(struct sk_buff *buf, struct device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
-	int ioaddr = dev->base_addr;
+	unsigned short ioaddr = dev->base_addr;
+
+#if NET_DEBUG > 6
+	printk("%s: eexp_xmit()\n", dev->name);
+#endif
 
-	if (dev->tbusy) {
-		/* If we get here, some higher level has decided we are broken.
-		   There should really be a "kick me" function call instead. */
-		int tickssofar = jiffies - dev->trans_start;
-		if (tickssofar < 5)
-			return 1;
-		if (net_debug > 1)
-			printk("%s: transmit timed out, %s?  ", dev->name,
-				   inw(ioaddr+SCB_STATUS) & 0x8000 ? "IRQ conflict" :
-				   "network cable problem");
-		lp->stats.tx_errors++;
-		/* Try to restart the adaptor. */
-		if (lp->last_restart == lp->stats.tx_packets) {
-			if (net_debug > 1) printk("Resetting board.\n");
-			/* Completely reset the adaptor. */
-			init_82586_mem(dev);
-		} else {
-			/* Issue the channel attention signal and hope it "gets better". */
-			if (net_debug > 1) printk("Kicking board.\n");
-			outw(0xf000|CUC_START|RX_START, ioaddr + SCB_CMD);
-			outb(0, ioaddr + SIGNAL_CA);
-			lp->last_restart = lp->stats.tx_packets;
+	outb(SIRQ_dis|irqrmap[dev->irq],ioaddr+SET_IRQ);
+	if (dev->tbusy) 
+	{
+		/* This will happen, but hopefully not as often as when
+		 * tbusy==0. If it happens too much, we probably ought
+		 * to think about unwedging ourselves...
+		 */
+		if (test_bit(0,(void *)&started)) 
+		{
+			if ((jiffies - dev->trans_start)>5) 
+			{
+				if (lp->tx_link==lp->last_tx_restart) 
+				{
+					unsigned short boguscount=200,rsst;
+					printk("%s: Retransmit timed out, status %04x, resetting...\n",
+						dev->name,inw(ioaddr+SCB_STATUS));
+					eexp_hw_txinit(dev);
+					lp->last_tx_restart = 0;
+					outw(lp->tx_link,ioaddr+SCB_CBL);
+					outw(0,ioaddr+SCB_STATUS);
+					outw(SCB_CUstart,ioaddr+SCB_CMD);
+					outb(0,ioaddr+SIGNAL_CA);
+					while (!SCB_complete(rsst=inw(ioaddr+SCB_STATUS))) 
+					{
+						if (!--boguscount) 
+						{
+							boguscount=200;
+							printk("%s: Reset timed out status %04x, retrying...\n",
+								dev->name,rsst);
+							outw(lp->tx_link,ioaddr+SCB_CBL);
+							outw(0,ioaddr+SCB_STATUS);
+							outw(SCB_CUstart,ioaddr+SCB_CMD);
+							outb(0,ioaddr+SIGNAL_CA);
+						}
+					}
+					dev->tbusy = 0;
+					mark_bh(NET_BH);
+				}
+				else
+				{
+					unsigned short status = inw(ioaddr+SCB_STATUS);
+					if (SCB_CUdead(status)) 
+					{
+						unsigned short txstatus = eexp_hw_lasttxstat(dev);
+						printk("%s: Transmit timed out, CU not active status %04x %04x, restarting...\n",
+							dev->name, status, txstatus);
+						eexp_hw_txrestart(dev);
+					}
+					else
+					{
+						unsigned short txstatus = eexp_hw_lasttxstat(dev);
+						if (dev->tbusy && !txstatus) 
+						{
+							printk("%s: CU wedged, status %04x %04x, resetting...\n",
+								dev->name,status,txstatus);
+							eexp_hw_init586(dev); 
+							dev->tbusy = 0;
+							mark_bh(NET_BH);
+						}
+					}
+				}
+			}
+		}
+		else
+		{
+			if ((jiffies-lp->init_time)>10)
+			{
+				unsigned short status = inw(ioaddr+SCB_STATUS);
+				printk("%s: i82586 startup timed out, status %04x, resetting...\n",
+					dev->name, status);
+				eexp_hw_init586(dev);
+				dev->tbusy = 0;
+				mark_bh(NET_BH);
+			}
 		}
-		dev->tbusy=0;
-		dev->trans_start = jiffies;
 	}
 
-	/* If some higher layer thinks we've missed an tx-done interrupt
-	   we are passed NULL. Caution: dev_tint() handles the cli()/sti()
-	   itself. */
-	if (skb == NULL) {
+	if (buf==NULL) 
+	{
+		unsigned short status = inw(ioaddr+SCB_STATUS);
+		unsigned short txstatus = eexp_hw_lasttxstat(dev);
+		if (SCB_CUdead(status)) 
+		{
+			printk("%s: CU has died! status %04x %04x, attempting to restart...\n",
+				dev->name, status, txstatus);
+			lp->stats.tx_errors++;
+			eexp_hw_txrestart(dev);
+		}
 		dev_tint(dev);
+		outb(SIRQ_en|irqrmap[dev->irq],ioaddr+SET_IRQ);
 		return 0;
 	}
 
-	/* Block a timer-based transmit from overlapping. */
-	if (set_bit(0, (void*)&dev->tbusy) != 0)
-		printk("%s: Transmitter access conflict.\n", dev->name);
-	else {
-		short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
-		unsigned char *buf = skb->data;
-
-		/* Disable the 82586's input to the interrupt line. */
-		outb(irqrmap[dev->irq], ioaddr + SET_IRQ);
-		hardware_send_packet(dev, buf, length);
-		dev->trans_start = jiffies;
-		/* Enable the 82586 interrupt input. */
-		outb(0x08 | irqrmap[dev->irq], ioaddr + SET_IRQ);
+	if (set_bit(0,(void *)&dev->tbusy)) 
+	{
+/*    printk("%s: Transmitter busy or access conflict\n",dev->name); */
+		lp->stats.tx_dropped++;
 	}
+	else
+	{
+		unsigned short length = (ETH_ZLEN < buf->len) ? buf->len : ETH_ZLEN;
+		unsigned short *data = (unsigned short *)buf->data;
 
-	dev_kfree_skb (skb, FREE_WRITE);
-
-	/* You might need to clean up and record Tx statistics here. */
-	lp->stats.tx_aborted_errors++;
-
+		outb(SIRQ_dis|irqrmap[dev->irq],ioaddr+SET_IRQ);
+		eexp_hw_tx(dev,data,length);
+		outb(SIRQ_en|irqrmap[dev->irq],ioaddr+SET_IRQ);
+	}
+	dev_kfree_skb(buf, FREE_WRITE);
+	outb(SIRQ_en|irqrmap[dev->irq],ioaddr+SET_IRQ);
 	return 0;
 }
-
-/*	The typical workload of the driver:
-	Handle the network interface interrupts. */
-static void
-eexp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+
+/*
+ * Handle an EtherExpress interrupt
+ * If we've finished initializing, start the RU and CU up.
+ * If we've already started, reap tx buffers, handle any received packets,
+ * check to make sure we've not become wedged.
+ */
+
+static void eexp_irq(int irq, void *dev_info, struct pt_regs *regs)
 {
-	struct device *dev = (struct device *)(irq2dev_map[irq]);
+	struct device *dev = irq2dev_map[irq];
 	struct net_local *lp;
-	int ioaddr, status, boguscount = 0;
-	short ack_cmd;
+	unsigned short ioaddr,status,ack_cmd;
+	unsigned short old_rp,old_wp;
 
-	if (dev == NULL) {
-		printk ("net_interrupt(): irq %d for unknown device.\n", irq);
+	if (dev==NULL) 
+	{
+		printk("net_interrupt(): irq %d for unknown device caught by EExpress\n",irq);
 		return;
 	}
-	dev->interrupt = 1;
-	
-	ioaddr = dev->base_addr;
-	lp = (struct net_local *)dev->priv;
-	
-	status = inw(ioaddr + SCB_STATUS);
-	
-    if (net_debug > 4) {
-		printk("%s: EExp interrupt, status %4.4x.\n", dev->name, status);
-    }
-
-	/* Disable the 82586's input to the interrupt line. */
-	outb(irqrmap[dev->irq], ioaddr + SET_IRQ);
-
-	/* Reap the Tx packet buffers. */
-	while (lp->tx_reap != lp->tx_head) { 	/* if (status & 0x8000) */
-		unsigned short tx_status;
-		outw(lp->tx_reap, ioaddr + READ_PTR);
-		tx_status = inw(ioaddr);
-		if (tx_status == 0) {
-			if (net_debug > 5)  printk("Couldn't reap %#x.\n", lp->tx_reap);
-			break;
-		}
-		if (tx_status & 0x2000) {
-			lp->stats.tx_packets++;
-			lp->stats.collisions += tx_status & 0xf;
-			dev->tbusy = 0;
-			mark_bh(NET_BH);	/* Inform upper layers. */
-		} else {
-			lp->stats.tx_errors++;
-			if (tx_status & 0x0600)  lp->stats.tx_carrier_errors++;
-			if (tx_status & 0x0100)  lp->stats.tx_fifo_errors++;
-			if (!(tx_status & 0x0040))  lp->stats.tx_heartbeat_errors++;
-			if (tx_status & 0x0020)  lp->stats.tx_aborted_errors++;
-		}
-		if (net_debug > 5)
-			printk("Reaped %x, Tx status %04x.\n" , lp->tx_reap, tx_status);
-		lp->tx_reap += TX_BUF_SIZE;
-		if (lp->tx_reap > TX_BUF_END - TX_BUF_SIZE)
-			lp->tx_reap = TX_BUF_START;
-		if (++boguscount > 4)
-			break;
-	}
 
-	if (status & 0x4000) { /* Packet received. */
-		if (net_debug > 5)
-			printk("Received packet, rx_head %04x.\n", lp->rx_head);
-		eexp_rx(dev);
-	}
+#if NET_DEBUG > 6
+	printk("%s: interrupt\n", dev->name);
+#endif
 
-	/* Acknowledge the interrupt sources. */
-	ack_cmd = status & 0xf000;
+	dev->interrupt = 1; /* should this be reset on exit? */
+  
+	lp = (struct net_local *)dev->priv;
+	ioaddr = dev->base_addr;
+
+	outb(SIRQ_dis|irqrmap[irq],ioaddr+SET_IRQ);
+	old_rp = inw(ioaddr+READ_PTR);
+	old_wp = inw(ioaddr+WRITE_PTR);
+	status = inw(ioaddr+SCB_STATUS);
+	ack_cmd = SCB_ack(status);
 
-	if ((status & 0x0700) != 0x0200  &&  dev->start) {
-		short saved_write_ptr = inw(ioaddr + WRITE_PTR);
-		if (net_debug > 1)
-			printk("%s: Command unit stopped, status %04x, restarting.\n",
-				   dev->name, status);
-		/* If this ever occurs we must re-write the idle loop, reset
-		   the Tx list, and do a complete restart of the command unit. */
-		outw(IDLELOOP, ioaddr + WRITE_PTR);
-		outw(0, ioaddr);
-		outw(CmdNOp, ioaddr);
-		outw(IDLELOOP, ioaddr);
-		outw(IDLELOOP, SCB_CBL);
-		lp->tx_cmd_link = IDLELOOP + 4;
-		lp->tx_head = lp->tx_reap = TX_BUF_START;
-		/* Restore the saved write pointer. */
-		outw(saved_write_ptr, ioaddr + WRITE_PTR);
-		ack_cmd |= CUC_START;
+	if (started==0 && SCB_complete(status)) 
+	{
+		if (SCB_CUstat(status)==2) 
+			while (SCB_CUstat(inw(ioaddr+SCB_STATUS))==2);
+		started=1;
+		outw(lp->tx_link,ioaddr+SCB_CBL);
+		outw(RX_BUF_START,ioaddr+SCB_RFA);
+		ack_cmd |= SCB_CUstart | SCB_RUstart;
+	}
+	else if (started) 
+	{
+		unsigned short txstatus;
+		txstatus = eexp_hw_lasttxstat(dev);
+	}
+  
+	if (SCB_rxdframe(status)) 
+	{
+		eexp_hw_rx(dev);
 	}
 
-	if ((status & 0x0070) != 0x0040  &&  dev->start) {
-		short saved_write_ptr = inw(ioaddr + WRITE_PTR);
-		/* The Rx unit is not ready, it must be hung.  Restart the receiver by
-		   initializing the rx buffers, and issuing an Rx start command. */
+	if ((started&2)!=0 && SCB_RUstat(status)!=4) 
+	{
+		printk("%s: RU stopped status %04x, restarting...\n",
+			dev->name,status);
 		lp->stats.rx_errors++;
-		if (net_debug > 1) {
-			int cur_rxbuf = RX_BUF_START;
-			printk("%s: Rx unit stopped status %04x rx head %04x tail %04x.\n",
-				   dev->name, status, lp->rx_head, lp->rx_tail);
-			while (cur_rxbuf <= RX_BUF_END - RX_BUF_SIZE) {
-				int i;
-				printk("  Rx buf at %04x:", cur_rxbuf);
-				outw(cur_rxbuf, ioaddr + READ_PTR);
-				for (i = 0; i < 0x20; i += 2)
-					printk(" %04x", inw(ioaddr));
-				printk(".\n");
-				cur_rxbuf += RX_BUF_SIZE;
+		eexp_hw_rxinit(dev);
+		outw(RX_BUF_START,ioaddr+SCB_RFA);
+		ack_cmd |= SCB_RUstart;
+	} 
+	else if (started==1 && SCB_RUstat(status)==4) 
+		started|=2;
+
+	outw(ack_cmd,ioaddr+SCB_CMD);
+	outb(0,ioaddr+SIGNAL_CA);
+	outw(old_rp,ioaddr+READ_PTR);
+	outw(old_wp,ioaddr+WRITE_PTR);
+	outb(SIRQ_en|irqrmap[irq],ioaddr+SET_IRQ);
+	return;
+}
+
+/*
+ * Hardware access functions
+ */
+
+/*
+ * Check all the receive buffers, and hand any received packets
+ * to the upper levels. Basic sanity check on each frame
+ * descriptor
+ */
+ 
+static void eexp_hw_rx(struct device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+	unsigned short ioaddr = dev->base_addr;
+	unsigned short old_wp = inw(ioaddr+WRITE_PTR);
+	unsigned short old_rp = inw(ioaddr+READ_PTR);
+	unsigned short rx_block = lp->rx_first;
+	unsigned short boguscount = NUM_RX_BUFS;
+
+#if NET_DEBUG > 6
+	printk("%s: eexp_hw_rx()\n", dev->name);
+#endif
+
+	while (outw(rx_block,ioaddr+READ_PTR),boguscount--) 
+	{
+		unsigned short status = inw(ioaddr);
+		unsigned short rfd_cmd = inw(ioaddr);
+		unsigned short rx_next = inw(ioaddr);
+		unsigned short pbuf = inw(ioaddr);
+		unsigned short pkt_len;
+
+		if (FD_Done(status)) 
+		{
+			outw(pbuf,ioaddr+READ_PTR);
+			pkt_len = inw(ioaddr);
+
+			if (rfd_cmd!=0x0000 || pbuf!=rx_block+0x16
+				|| (pkt_len & 0xc000)!=0xc000) 
+			{
+				printk("%s: Rx frame at %04x corrupted, status %04x, cmd %04x, "
+					"next %04x, pbuf %04x, len %04x\n",dev->name,rx_block,
+					status,rfd_cmd,rx_next,pbuf,pkt_len);
+				eexp_hw_rxmap(dev,rx_block);
+				boguscount++;
+				continue;
+			}
+			else if (!FD_OK(status)) 
+			{
+				lp->stats.rx_errors++;
+				if (FD_CRC(status)) 
+					lp->stats.rx_crc_errors++;
+				if (FD_Align(status))
+					lp->stats.rx_frame_errors++;
+				if (FD_Resrc(status))
+					lp->stats.rx_fifo_errors++;
+				if (FD_DMA(status))
+					lp->stats.rx_over_errors++;
+				if (FD_Short(status))
+					lp->stats.rx_length_errors++;
 			}
+			else
+			{
+				struct sk_buff *skb;
+				pkt_len &= 0x3fff;
+				skb = dev_alloc_skb(pkt_len+16);
+				if (skb == NULL) 
+				{
+					printk("%s: Memory squeeze, dropping packet\n",dev->name);
+					lp->stats.rx_dropped++;
+					break;
+				}
+				skb->dev = dev;
+				skb_reserve(skb, 2);
+				outw(pbuf+10,ioaddr+READ_PTR);
+				insw(ioaddr,skb_put(skb,pkt_len),(pkt_len+1)>>1);
+				skb->protocol = eth_type_trans(skb,dev);
+				netif_rx(skb);
+				lp->stats.rx_packets++;
+			}
+			outw(rx_block,ioaddr+WRITE_PTR);
+			outw(0x0000,ioaddr);
+			outw(0x0000,ioaddr);
 		}
-		init_rx_bufs(dev);
-		outw(RX_BUF_START, SCB_RFA);
-		outw(saved_write_ptr, ioaddr + WRITE_PTR);
-		ack_cmd |= RX_START;
+		rx_block = rx_next;
 	}
+	outw(old_rp,ioaddr+READ_PTR);
+	outw(old_wp,ioaddr+WRITE_PTR);
+}
 
-	outw(ack_cmd, ioaddr + SCB_CMD);
-	outb(0, ioaddr + SIGNAL_CA);
+/*
+ * Hand a packet to the card for transmission
+ * If we get here, we MUST have already checked
+ * to make sure there is room in the transmit
+ * buffer region
+ */
 
-    if (net_debug > 5) {
-		printk("%s: EExp exiting interrupt, status %4.4x.\n", dev->name,
-			   inw(ioaddr + SCB_CMD));
-    }
-	/* Enable the 82586's input to the interrupt line. */
-	outb(irqrmap[dev->irq] | 0x08, ioaddr + SET_IRQ);
-	return;
+static void eexp_hw_tx(struct device *dev, unsigned short *buf, unsigned short len)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+	unsigned short ioaddr = dev->base_addr;
+	unsigned short old_wp = inw(ioaddr+WRITE_PTR);
+
+	outw(lp->tx_head,ioaddr+WRITE_PTR);
+	outw(0x0000,ioaddr);
+	outw(Cmd_INT|Cmd_Xmit,ioaddr);
+	outw(lp->tx_head+0x08,ioaddr);
+	outw(lp->tx_head+0x0e,ioaddr);
+	outw(0x0000,ioaddr);
+	outw(0x0000,ioaddr);
+	outw(lp->tx_head+0x08,ioaddr);
+	outw(0x8000|len,ioaddr);
+	outw(-1,ioaddr);
+	outw(lp->tx_head+0x16,ioaddr);
+	outw(0,ioaddr);
+	outsw(ioaddr,buf,(len+1)>>1);
+	outw(lp->tx_tail+0x0c,ioaddr+WRITE_PTR);
+	outw(lp->tx_head,ioaddr);
+	dev->trans_start = jiffies;
+	lp->tx_tail = lp->tx_head;
+	if (lp->tx_head==TX_BUF_START+((NUM_TX_BUFS-1)*TX_BUF_SIZE)) 
+		lp->tx_head = TX_BUF_START;
+	else 
+		lp->tx_head += TX_BUF_SIZE;
+	if (lp->tx_head != lp->tx_reap) 
+		dev->tbusy = 0;
+	outw(old_wp,ioaddr+WRITE_PTR);
 }
 
-static int
-eexp_close(struct device *dev)
+/*
+ * Sanity check the suspected EtherExpress card
+ * Read hardware address, reset card, size memory and
+ * initialize buffer memory pointers. These should
+ * probably be held in dev->priv, incase someone has 2
+ * differently configured cards in their box (Arghhh!)
+ */
+
+static int eexp_hw_probe(struct device *dev, unsigned short ioaddr)
 {
-	int ioaddr = dev->base_addr;
+	unsigned short hw_addr[3];
+	int i;
+	unsigned char *chw_addr = (unsigned char *)hw_addr;
 
-	dev->tbusy = 1;
-	dev->start = 0;
+	printk("%s: EtherExpress at %#x, ",dev->name,ioaddr);
 
-	/* Flush the Tx and disable Rx. */
-	outw(RX_SUSPEND | CUC_SUSPEND, ioaddr + SCB_CMD);
-	outb(0, ioaddr + SIGNAL_CA);
+	hw_addr[0] = eexp_hw_readeeprom(ioaddr,2);
+	hw_addr[1] = eexp_hw_readeeprom(ioaddr,3);
+	hw_addr[2] = eexp_hw_readeeprom(ioaddr,4);
 
-	/* Disable the physical interrupt line. */
-	outb(0, ioaddr + SET_IRQ);
+	if (hw_addr[2]!=0x00aa || ((hw_addr[1] & 0xff00)!=0x0000)) 
+	{
+		printk("rejected: invalid address %04x%04x%04x\n",
+			hw_addr[2],hw_addr[1],hw_addr[0]);
+		return ENODEV;
+	}
 
-	free_irq(dev->irq, NULL);
+	dev->base_addr = ioaddr;
+	for ( i=0 ; i<6 ; i++ ) 
+		dev->dev_addr[i] = chw_addr[5-i];
 
-	irq2dev_map[dev->irq] = 0;
+	{
+		char irqmap[]={0, 9, 3, 4, 5, 10, 11, 0};
+		char *ifmap[]={"AUI", "BNC", "10baseT"};
+		enum iftype {AUI=0, BNC=1, TP=2};
+		unsigned short setupval = eexp_hw_readeeprom(ioaddr,0);
 
-	/* Update the statistics here. */
+		dev->irq = irqmap[setupval>>13];
+		dev->if_port = !(setupval & 0x1000) ? AUI :
+			eexp_hw_readeeprom(ioaddr,5) & 0x1 ? TP : BNC;
 
-	MOD_DEC_USE_COUNT;
-	return 0;
-}
+		printk("IRQ %d, Interface %s, ",dev->irq,ifmap[dev->if_port]);
 
-/* Get the current statistics.	This may be called with the card open or
-   closed. */
-static struct enet_statistics *
-eexp_get_stats(struct device *dev)
-{
-	struct net_local *lp = (struct net_local *)dev->priv;
+		outb(SIRQ_dis|irqrmap[dev->irq],ioaddr+SET_IRQ);
+		outb(0,ioaddr+SET_IRQ);
+	}
 
-	/* ToDo: decide if there are any useful statistics from the SCB. */
+	eexp_hw_ASICrst(dev);
 
-	return &lp->stats;
-}
+	{
+		unsigned short i586mso = 0x023e;
+		unsigned short old_wp,old_rp,old_a0,old_a1;
+		unsigned short a0_0,a1_0,a0_1,a1_1;
+
+		old_wp = inw(ioaddr+WRITE_PTR);
+		old_rp = inw(ioaddr+READ_PTR);
+		outw(0x8000+i586mso,ioaddr+READ_PTR);
+		old_a1 = inw(ioaddr);
+		outw(i586mso,ioaddr+READ_PTR);
+		old_a0 = inw(ioaddr);
+		outw(i586mso,ioaddr+WRITE_PTR);
+		outw(0x55aa,ioaddr);
+		outw(i586mso,ioaddr+READ_PTR);
+		a0_0 = inw(ioaddr);
+		outw(0x8000+i586mso,ioaddr+WRITE_PTR);
+		outw(0x5a5a,ioaddr);
+		outw(0x8000+i586mso,ioaddr+READ_PTR);
+		a1_0 = inw(ioaddr);
+		outw(i586mso,ioaddr+READ_PTR);
+		a0_1 = inw(ioaddr);
+		outw(i586mso,ioaddr+WRITE_PTR);
+		outw(0x1234,ioaddr);
+		outw(0x8000+i586mso,ioaddr+READ_PTR);
+		a1_1 = inw(ioaddr);
+
+		if ((a0_0 != a0_1) || (a1_0 != a1_1) ||
+			(a1_0 != 0x5a5a) || (a0_0 != 0x55aa)) 
+		{
+			printk("32k\n");
+			RX_BUF_END = 0x7ff6;
+		}
+		else
+		{
+			printk("64k\n");
+			NUM_TX_BUFS = 8;
+			RX_BUF_START = TX_BUF_START + (NUM_TX_BUFS*TX_BUF_SIZE);
+			RX_BUF_END = 0xfff6;
+		}
 
-/* Set or clear the multicast filter for this adaptor.
- */
-static void
-set_multicast_list(struct device *dev)
-{
-/* This doesn't work yet */
-#if 0
-	short ioaddr = dev->base_addr;
-	if (num_addrs < 0) {
-		/* Not written yet, this requires expanding the init_words config
-		   cmd. */
-	} else if (num_addrs > 0) {
-		/* Fill in the SET_MC_CMD with the number of address bytes, followed
-		   by the list of multicast addresses to be accepted. */
-		outw(SET_MC_CMD + 6, ioaddr + WRITE_PTR);
-		outw(num_addrs * 6, ioaddr);
-		outsw(ioaddr, addrs, num_addrs*3);		/* 3 = addr len in words */
-		/* We must trigger a whole 586 reset due to a bug. */
-	} else {
-		/* Not written yet, this requires expanding the init_words config
-		   cmd. */
-		outw(99, ioaddr);		/* Disable promiscuous mode, use normal mode */
+		outw(0x8000+i586mso,ioaddr+WRITE_PTR);
+		outw(old_a1,ioaddr);
+		outw(i586mso,ioaddr+WRITE_PTR);
+		outw(old_a0,ioaddr);
+		outw(old_wp,ioaddr+WRITE_PTR);
+		outw(old_rp,ioaddr+READ_PTR);
 	}
-#endif
-}
-
-/* The horrible routine to read a word from the serial EEPROM. */
+  
+	if (net_debug) 
+		printk(version);
 
-/* The delay between EEPROM clock transitions. */
-#define eeprom_delay()	{ int _i = 40; while (--_i > 0) { __SLOW_DOWN_IO; }}
-#define EE_READ_CMD (6 << 6)
+	dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
+	memset(dev->priv, 0, sizeof(struct net_local));
+	dev->open = eexp_open;
+	dev->stop = eexp_close;
+	dev->hard_start_xmit = eexp_xmit;
+	dev->get_stats = eexp_stats;
+	ether_setup(dev);
+	return 0;
+}
 
-int
-read_eeprom(int ioaddr, int location)
+/*
+ *	Read a word from eeprom location (0-63?)
+ */
+static unsigned short eexp_hw_readeeprom(unsigned short ioaddr, unsigned char location)
 {
+	unsigned short cmd = 0x180|(location&0x7f);
+	unsigned short rval = 0,wval = EC_CS|i586_RST;
 	int i;
-	unsigned short retval = 0;
-	short ee_addr = ioaddr + EEPROM_Ctrl;
-	int read_cmd = location | EE_READ_CMD;
-	short ctrl_val = EE_CS | _586_RESET;
-	
-	outb(ctrl_val, ee_addr);
-	
-	/* Shift the read command bits out. */
-	for (i = 8; i >= 0; i--) {
-		short outval = (read_cmd & (1 << i)) ? ctrl_val | EE_DATA_WRITE
-			: ctrl_val;
-		outb(outval, ee_addr);
-		outb(outval | EE_SHIFT_CLK, ee_addr);	/* EEPROM clock tick. */
+ 
+	outb(EC_CS|i586_RST,ioaddr+EEPROM_Ctrl);
+	for ( i=0x100 ; i ; i>>=1 ) 
+	{
+		if (cmd&i) 
+			wval |= EC_Wr;
+		else 
+			wval &= ~EC_Wr;
+
+		outb(wval,ioaddr+EEPROM_Ctrl);
+		outb(wval|EC_Clk,ioaddr+EEPROM_Ctrl);
 		eeprom_delay();
-		outb(outval, ee_addr);	/* Finish EEPROM a clock tick. */
+		outb(wval,ioaddr+EEPROM_Ctrl);
+		eeprom_delay();
+	}	
+	wval &= ~EC_Wr;
+	outb(wval,ioaddr+EEPROM_Ctrl);
+	for ( i=0x8000 ; i ; i>>=1 ) 
+	{
+		outb(wval|EC_Clk,ioaddr+EEPROM_Ctrl);
+		eeprom_delay();
+		if (inb(ioaddr+EEPROM_Ctrl)&EC_Rd) 
+			rval |= i;
+		outb(wval,ioaddr+EEPROM_Ctrl);
 		eeprom_delay();
 	}
-	outb(ctrl_val, ee_addr);
-	
-	for (i = 16; i > 0; i--) {
-		outb(ctrl_val | EE_SHIFT_CLK, ee_addr);	 eeprom_delay();
-		retval = (retval << 1) | ((inb(ee_addr) & EE_DATA_READ) ? 1 : 0);
-		outb(ctrl_val, ee_addr);  eeprom_delay();
-	}
-
-	/* Terminate the EEPROM access. */
-	ctrl_val &= ~EE_CS;
-	outb(ctrl_val | EE_SHIFT_CLK, ee_addr);
+	wval &= ~EC_CS;
+	outb(wval|EC_Clk,ioaddr+EEPROM_Ctrl);
 	eeprom_delay();
-	outb(ctrl_val, ee_addr);
+	outb(wval,ioaddr+EEPROM_Ctrl);
 	eeprom_delay();
-	return retval;
+	return rval;
 }
 
-static void
-init_82586_mem(struct device *dev)
+/*
+ * Reap tx buffers and return last transmit status.
+ * if ==0 then either:
+ *    a) we're not transmitting anything, so why are we here?
+ *    b) we've died.
+ * otherwise, Stat_Busy(return) means we've still got some packets
+ * to transmit, Stat_Done(return) means our buffers should be empty
+ * again
+ */
+
+static unsigned short eexp_hw_lasttxstat(struct device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
-	short ioaddr = dev->base_addr;
+	unsigned short ioaddr = dev->base_addr;
+	unsigned short old_rp = inw(ioaddr+READ_PTR);
+	unsigned short old_wp = inw(ioaddr+WRITE_PTR);
+	unsigned short tx_block = lp->tx_reap;
+	unsigned short status;
+  
+	if (!test_bit(0,(void *)&dev->tbusy) && lp->tx_head==lp->tx_reap) 
+		return 0x0000;
 
-	/* Enable loopback to protect the wire while starting up.
-	   This is Superstition From Crynwr. */
-	outb(inb(ioaddr + Config) | 0x02, ioaddr + Config);
-
-	/* Hold the 586 in reset during the memory initialization. */
-	outb(_586_RESET, ioaddr + EEPROM_Ctrl);
-
-	/* Place the write pointer at 0xfff6 (address-aliased to 0xfffff6). */
-	outw(0xfff6, ioaddr + WRITE_PTR);
-	outsw(ioaddr, init_words, sizeof(init_words)>>1);
-
-	/* Fill in the station address. */
-	outw(SA_OFFSET, ioaddr + WRITE_PTR);
-	outsw(ioaddr, dev->dev_addr, 3);
-
-	/* The Tx-block list is written as needed.  We just set up the values. */
-#ifdef initial_text_tx
-	lp->tx_cmd_link = DUMP_DATA + 4;
-#else
-	lp->tx_cmd_link = IDLELOOP + 4;
-#endif
-	lp->tx_head = lp->tx_reap = TX_BUF_START;
+	do
+	{
+		outw(tx_block,ioaddr+READ_PTR);
+		status = inw(ioaddr);
+		if (!Stat_Done(status)) 
+		{
+			lp->tx_link = tx_block;
+			outw(old_rp,ioaddr+READ_PTR);
+			outw(old_wp,ioaddr+WRITE_PTR);
+			return status;
+		}
+		else 
+		{
+			lp->last_tx_restart = 0;
+			lp->stats.collisions += Stat_NoColl(status);
+			if (!Stat_OK(status)) 
+			{
+				if (Stat_Abort(status)) 
+					lp->stats.tx_aborted_errors++;
+				if (Stat_TNoCar(status) || Stat_TNoCTS(status)) 
+					lp->stats.tx_carrier_errors++;
+				if (Stat_TNoDMA(status)) 
+					lp->stats.tx_fifo_errors++;
+			}
+			else
+				lp->stats.tx_packets++;
+		}
+		if (tx_block == TX_BUF_START+((NUM_TX_BUFS-1)*TX_BUF_SIZE)) 
+			lp->tx_reap = tx_block = TX_BUF_START;
+		else
+			lp->tx_reap = tx_block += TX_BUF_SIZE;
+		dev->tbusy = 0;
+		mark_bh(NET_BH);
+	}
+	while (lp->tx_reap != lp->tx_head);
 
-	init_rx_bufs(dev);
+	lp->tx_link = lp->tx_tail + 0x08;
+	outw(old_rp,ioaddr+READ_PTR);
+	outw(old_wp,ioaddr+WRITE_PTR);
 
-	/* Start the 586 by releasing the reset line. */
-	outb(0x00, ioaddr + EEPROM_Ctrl);
+	return status;
+}
 
-	/* This was time consuming to track down: you need to give two channel
-	   attention signals to reliably start up the i82586. */
-	outb(0, ioaddr + SIGNAL_CA);
+/* 
+ * This should never happen. It is called when some higher
+ * routine detects the CU has stopped, to try and restart
+ * it from the last packet we knew we were working on,
+ * or the idle loop if we had finished for the time.
+ */
+
+static void eexp_hw_txrestart(struct device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+	unsigned short ioaddr = dev->base_addr;
+  
+	lp->last_tx_restart = lp->tx_link;
+	outw(lp->tx_link,ioaddr+SCB_CBL);
+	outw(SCB_CUstart,ioaddr+SCB_CMD);
+	outw(0,ioaddr+SCB_STATUS);
+	outb(0,ioaddr+SIGNAL_CA);
 
 	{
-		int boguscnt = 50;
-		while (inw(ioaddr + SCB_STATUS) == 0)
-			if (--boguscnt == 0) {
-				printk("%s: i82586 initialization timed out with status %04x, cmd %04x.\n",
-					   dev->name, inw(ioaddr + SCB_STATUS), inw(ioaddr + SCB_CMD));
-				break;
+		unsigned short boguscount=50,failcount=5;
+		while (!inw(ioaddr+SCB_STATUS)) 
+		{
+			if (!--boguscount) 
+			{
+				if (--failcount) 
+				{
+					printk("%s: CU start timed out, status %04x, cmd %04x\n",
+						dev->name, inw(ioaddr+SCB_STATUS), inw(ioaddr+SCB_CMD));
+					outw(lp->tx_link,ioaddr+SCB_CBL);
+					outw(0,ioaddr+SCB_STATUS);
+					outw(SCB_CUstart,ioaddr+SCB_CMD);
+					outb(0,ioaddr+SIGNAL_CA);
+					boguscount = 100;
+				}
+				else
+				{
+					printk("%s: Failed to restart CU, resetting board...\n",dev->name);
+					eexp_hw_init586(dev);
+					dev->tbusy = 0;
+					mark_bh(NET_BH);
+					return;
+				}
 			}
-		/* Issue channel-attn -- the 82586 won't start without it. */
-		outb(0, ioaddr + SIGNAL_CA);
+		}
 	}
-
-	/* Disable loopback. */
-	outb(inb(ioaddr + Config) & ~0x02, ioaddr + Config);
-	if (net_debug > 4)
-		printk("%s: Initialized 82586, status %04x.\n", dev->name,
-			   inw(ioaddr + SCB_STATUS));
-	return;
 }
 
-/* Initialize the Rx-block list. */
-static void init_rx_bufs(struct device *dev)
+/*
+ * Writes down the list of transmit buffers into card
+ * memory. Initial seperate, repeated transmits link
+ * them into a circular list, such that the CU can
+ * be constantly active, and unlink them as we reap
+ * transmitted packet buffers, so the CU doesn't loop
+ * and endlessly transmit packets. (Try hacking the driver
+ * to send continuous broadcast messages, say ARP requests
+ * on a subnet with Windows boxes running on Novell and
+ * LAN Workplace with EMM386. Amusing to watch them all die
+ * horribly leaving the Linux boxes up!)
+ */
+
+static void eexp_hw_txinit(struct device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
-	short ioaddr = dev->base_addr;
+	unsigned short ioaddr = dev->base_addr;
+	unsigned short old_wp = inw(ioaddr+WRITE_PTR);
+	unsigned short tx_block = TX_BUF_START;
+	unsigned short curtbuf;
 
-	int cur_rxbuf = lp->rx_head = RX_BUF_START;
-	
-	/* Initialize each Rx frame + data buffer. */
-	do {	/* While there is room for one more. */
-		outw(cur_rxbuf, ioaddr + WRITE_PTR);
-		outw(0x0000, ioaddr); 				/* Status */
-		outw(0x0000, ioaddr);				/* Command */
-		outw(cur_rxbuf + RX_BUF_SIZE, ioaddr); /* Link */
-		outw(cur_rxbuf + 22, ioaddr);		/* Buffer offset */
-		outw(0xFeed, ioaddr); 				/* Pad for dest addr. */
-		outw(0xF00d, ioaddr);
-		outw(0xF001, ioaddr);
-		outw(0x0505, ioaddr); 				/* Pad for source addr. */
-		outw(0x2424, ioaddr);
-		outw(0x6565, ioaddr);
-		outw(0xdeaf, ioaddr);				/* Pad for protocol. */
-
-		outw(0x0000, ioaddr);				/* Buffer: Actual count */
-		outw(-1, ioaddr);					/* Buffer: Next (none). */
-		outw(cur_rxbuf + 0x20, ioaddr);		/* Buffer: Address low */
-		outw(0x0000, ioaddr);
-		/* Finally, the number of bytes in the buffer. */
-		outw(0x8000 + RX_BUF_SIZE-0x20, ioaddr);
-		
-		lp->rx_tail = cur_rxbuf;
-		cur_rxbuf += RX_BUF_SIZE;
-	} while (cur_rxbuf <= RX_BUF_END - RX_BUF_SIZE);
-	
-	/* Terminate the list by setting the EOL bit, and wrap the pointer to make
-	   the list a ring. */
-	outw(lp->rx_tail + 2, ioaddr + WRITE_PTR);
-	outw(0xC000, ioaddr);					/* Command, mark as last. */
-	outw(lp->rx_head, ioaddr);				/* Link */
+	for ( curtbuf=0 ; curtbuf<NUM_TX_BUFS ; curtbuf++ ) 
+	{
+		outw(tx_block,ioaddr+WRITE_PTR);
+		outw(0x0000,ioaddr);
+		outw(Cmd_INT|Cmd_Xmit,ioaddr);
+		outw(tx_block+0x08,ioaddr);
+		outw(tx_block+0x0e,ioaddr);
+		outw(0x0000,ioaddr);
+		outw(0x0000,ioaddr);
+		outw(tx_block+0x08,ioaddr);
+		outw(0x8000,ioaddr);
+		outw(-1,ioaddr);
+		outw(tx_block+0x16,ioaddr);
+		outw(0x0000,ioaddr);
+		tx_block += TX_BUF_SIZE;
+	}
+	lp->tx_head = TX_BUF_START;
+	lp->tx_reap = TX_BUF_START;
+	lp->tx_tail = tx_block - TX_BUF_SIZE;
+	lp->tx_link = lp->tx_tail + 0x08;
+	RX_BUF_START = tx_block;
+	outw(old_wp,ioaddr+WRITE_PTR);
 }
 
-static void
-hardware_send_packet(struct device *dev, void *buf, short length)
+/* is this a standard test pattern, or dbecker randomness? */
+
+unsigned short rx_words[] = 
+{
+	0xfeed,0xf00d,0xf001,0x0505,0x2424,0x6565,0xdeaf
+};
+
+/*
+ * Write the circular list of receive buffer descriptors to
+ * card memory. Note, we no longer mark the end of the list,
+ * so if all the buffers fill up, the 82586 will loop until
+ * we free one. This may sound dodgy, but it works, and
+ * it makes the error detection in the interrupt handler
+ * a lot simpler.
+ */
+
+static void eexp_hw_rxinit(struct device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
-	short ioaddr = dev->base_addr;
-	short tx_block = lp->tx_head;
+	unsigned short ioaddr = dev->base_addr;
+	unsigned short old_wp = inw(ioaddr+WRITE_PTR);
+	unsigned short rx_block = RX_BUF_START;
+
+	NUM_RX_BUFS = 0;
+	lp->rx_first = rx_block;
+	do 
+	{
+		NUM_RX_BUFS++;
+		outw(rx_block,ioaddr+WRITE_PTR);
+		outw(0x0000,ioaddr);
+		outw(0x0000,ioaddr);
+		outw(rx_block+RX_BUF_SIZE,ioaddr);
+		outw(rx_block+0x16,ioaddr);
+		outsw(ioaddr, rx_words, sizeof(rx_words)>>1);
+		outw(0x8000,ioaddr);
+		outw(-1,ioaddr);
+		outw(rx_block+0x20,ioaddr);
+		outw(0x0000,ioaddr);
+		outw(0x8000|(RX_BUF_SIZE-0x20),ioaddr);
+		lp->rx_last = rx_block;
+		rx_block += RX_BUF_SIZE;
+	} while (rx_block <= RX_BUF_END-RX_BUF_SIZE);
 
-	/* Set the write pointer to the Tx block, and put out the header. */
-	outw(tx_block, ioaddr + WRITE_PTR);
-	outw(0x0000, ioaddr);		/* Tx status */
-	outw(CMD_INTR|CmdTx, ioaddr);		/* Tx command */
-	outw(tx_block+16, ioaddr);	/* Next command is a NoOp. */
-	outw(tx_block+8, ioaddr);	/* Data Buffer offset. */
-
-	/* Output the data buffer descriptor. */
-	outw(length | 0x8000, ioaddr); /* Byte count parameter. */
-	outw(-1, ioaddr);			/* No next data buffer. */
-	outw(tx_block+22, ioaddr);	/* Buffer follows the NoOp command. */
-	outw(0x0000, ioaddr);		/* Buffer address high bits (always zero). */
-
-	/* Output the Loop-back NoOp command. */
-	outw(0x0000, ioaddr);		/* Tx status */
-	outw(CmdNOp, ioaddr);		/* Tx command */
-	outw(tx_block+16, ioaddr);	/* Next is myself. */
-
-	/* Output the packet using the write pointer.
-	   Hmmm, it feels a little like a 3c501! */
-	outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);
-
-	/* Set the old command link pointing to this send packet. */
-	outw(lp->tx_cmd_link, ioaddr + WRITE_PTR);
-	outw(tx_block, ioaddr);
-	lp->tx_cmd_link = tx_block + 20;
-
-	/* Set the next free tx region. */
-	lp->tx_head = tx_block + TX_BUF_SIZE;
-	if (lp->tx_head > TX_BUF_END - TX_BUF_SIZE)
-		lp->tx_head = TX_BUF_START;
+	outw(lp->rx_last+4,ioaddr+WRITE_PTR);
+	outw(lp->rx_first,ioaddr);
 
-    if (net_debug > 4) {
-		printk("%s: EExp @%x send length = %d, tx_block %3x, next %3x, "
-			   "reap %4x status %4.4x.\n", dev->name, ioaddr, length,
-			   tx_block, lp->tx_head, lp->tx_reap, inw(ioaddr + SCB_STATUS));
-    }
+	outw(old_wp,ioaddr+WRITE_PTR);
+}
 
-	if (lp->tx_head != lp->tx_reap)
-		dev->tbusy = 0;
+/*
+ * This really ought not to be necessary now. Repairs a single
+ * damaged receive buffer. If buffer memory is getting bashed
+ * enough to call this, we probably have bigger problems that can
+ * be fixed here.
+ */
+static void eexp_hw_rxmap(struct device *dev, unsigned short rx_buf)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+	unsigned short ioaddr = dev->base_addr;
+	unsigned short old_wp = inw(ioaddr+WRITE_PTR);
+
+	outw(rx_buf,ioaddr+WRITE_PTR);
+	outw(0x0000,ioaddr);
+	outw(0x0000,ioaddr);
+	outw((rx_buf==lp->rx_last)?lp->rx_first:(rx_buf+RX_BUF_SIZE),ioaddr);
+	outw(rx_buf+0x16,ioaddr);
+	outsw(ioaddr, rx_words, sizeof(rx_words)>>1);
+	outw(0x8000,ioaddr);
+	outw(-1,ioaddr);
+	outw(rx_buf+0x20,ioaddr);
+	outw(0x0000,ioaddr);
+	outw(0x8000|(RX_BUF_SIZE-0x20),ioaddr);
+	outw(old_wp,ioaddr+WRITE_PTR);
 }
 
-static void
-eexp_rx(struct device *dev)
+/*
+ * Reset the 586, fill memory (including calls to
+ * eexp_hw_[(rx)(tx)]init()) unreset, and start
+ * the configuration sequence. We don't wait for this
+ * to finish, but allow the interrupt handler to start
+ * the CU and RU for us. We can't start the receive/
+ * transmission system up before we know that the
+ * hardware is configured correctly
+ */
+static void eexp_hw_init586(struct device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
-	short ioaddr = dev->base_addr;
-	short saved_write_ptr = inw(ioaddr + WRITE_PTR);
-	short rx_head = lp->rx_head;
-	short rx_tail = lp->rx_tail;
-	short boguscount = 10;
-	short frame_status;
-
-	/* Set the read pointer to the Rx frame. */
-	outw(rx_head, ioaddr + READ_PTR);
-	while ((frame_status = inw(ioaddr)) < 0) {		/* Command complete */
-		short rfd_cmd = inw(ioaddr);
-		short next_rx_frame = inw(ioaddr);
-		short data_buffer_addr = inw(ioaddr);
-		short pkt_len;
-		
-		/* Set the read pointer the data buffer. */
-		outw(data_buffer_addr, ioaddr + READ_PTR);
-		pkt_len = inw(ioaddr);
-
-		if (rfd_cmd != 0  ||  data_buffer_addr != rx_head + 22
-			||  (pkt_len & 0xC000) != 0xC000) {
-			printk("%s: Rx frame at %#x corrupted, status %04x cmd %04x"
-				   "next %04x data-buf @%04x %04x.\n", dev->name, rx_head,
-				   frame_status, rfd_cmd, next_rx_frame, data_buffer_addr,
-				   pkt_len);
-		} else if ((frame_status & 0x2000) == 0) {
-			/* Frame Rxed, but with error. */
-			lp->stats.rx_errors++;
-			if (frame_status & 0x0800) lp->stats.rx_crc_errors++;
-			if (frame_status & 0x0400) lp->stats.rx_frame_errors++;
-			if (frame_status & 0x0200) lp->stats.rx_fifo_errors++;
-			if (frame_status & 0x0100) lp->stats.rx_over_errors++;
-			if (frame_status & 0x0080) lp->stats.rx_length_errors++;
-		} else {
-			/* Malloc up new buffer. */
-			struct sk_buff *skb;
-
-			pkt_len &= 0x3fff;
-			skb = dev_alloc_skb(pkt_len+2);
-			if (skb == NULL) {
-				printk("%s: Memory squeeze, dropping packet.\n", dev->name);
-				lp->stats.rx_dropped++;
-				break;
-			}
-			skb->dev = dev;
-			skb_reserve(skb,2);
+	unsigned short ioaddr = dev->base_addr;
 
-			outw(data_buffer_addr + 10, ioaddr + READ_PTR);
+	started = 0;
+	set_loopback;
 
-			insw(ioaddr, skb_put(skb,pkt_len), (pkt_len + 1) >> 1);
-		
-			skb->protocol=eth_type_trans(skb,dev);
-			netif_rx(skb);
-			lp->stats.rx_packets++;
-		}
+	outb(SIRQ_dis|irqrmap[dev->irq],ioaddr+SET_IRQ);
+	outb(i586_RST,ioaddr+EEPROM_Ctrl);
 
-		/* Clear the status word and set End-of-List on the rx frame. */
-		outw(rx_head, ioaddr + WRITE_PTR);
-		outw(0x0000, ioaddr);
-		outw(0xC000, ioaddr);
-#ifndef final_version
-		if (next_rx_frame != rx_head + RX_BUF_SIZE
-			&& next_rx_frame != RX_BUF_START) {
-			printk("%s: Rx next frame at %#x is %#x instead of %#x.\n", dev->name,
-				   rx_head, next_rx_frame, rx_head + RX_BUF_SIZE);
-			next_rx_frame = rx_head + RX_BUF_SIZE;
-			if (next_rx_frame >= RX_BUF_END - RX_BUF_SIZE)
-				next_rx_frame = RX_BUF_START;
+	{
+		unsigned short wcnt;
+		wcnt = 0;
+		outw(0,ioaddr+WRITE_PTR);
+		while ((wcnt+=2) != RX_BUF_END+12) 
+			outw(0,ioaddr);
+	} 
+  
+	outw(RX_BUF_END,ioaddr+WRITE_PTR);
+	outsw(ioaddr, start_code, sizeof(start_code)>>1);
+	outw(CONF_HW_ADDR,ioaddr+WRITE_PTR);
+	outsw(ioaddr,dev->dev_addr,3);
+	eexp_hw_txinit(dev);
+	eexp_hw_rxinit(dev);
+	outw(0,ioaddr+WRITE_PTR);
+	outw(1,ioaddr);
+	outb(0,ioaddr+EEPROM_Ctrl);
+	outw(0,ioaddr+SCB_CMD);
+	outb(0,ioaddr+SIGNAL_CA);
+	{
+		unsigned short rboguscount=50,rfailcount=5;
+		while (outw(0,ioaddr+READ_PTR),inw(ioaddr)) 
+		{
+			if (!--rboguscount) 
+			{
+				printk("%s: i82586 reset timed out, kicking...\n",
+					dev->name);
+				outw(0,ioaddr+SCB_CMD);
+				outb(0,ioaddr+SIGNAL_CA);
+				rboguscount = 100;
+				if (!--rfailcount) 
+				{
+					printk("%s: i82586 not responding, giving up.\n",
+						dev->name);
+					return;
+				}
+			}
 		}
-#endif
-		outw(rx_tail+2, ioaddr + WRITE_PTR);
-		outw(0x0000, ioaddr);	/* Clear the end-of-list on the prev. RFD. */
+	}
 
-#ifndef final_version
-		outw(rx_tail+4, ioaddr + READ_PTR);
-		if (inw(ioaddr) != rx_head) {
-			printk("%s: Rx buf link mismatch, at %04x link %04x instead of %04x.\n",
-				   dev->name, rx_tail, (outw(rx_tail+4, ioaddr + READ_PTR),inw(ioaddr)),
-				   rx_head);
-			outw(rx_head, ioaddr);
+	outw(CONF_LINK,ioaddr+SCB_CBL);
+	outw(0,ioaddr+SCB_STATUS);
+	outw(0xf000|SCB_CUstart,ioaddr+SCB_CMD);
+	outb(0,ioaddr+SIGNAL_CA);
+	{
+		unsigned short iboguscount=50,ifailcount=5;
+		while (!inw(ioaddr+SCB_STATUS)) 
+		{
+			if (!--iboguscount) 
+			{
+				if (--ifailcount) 
+				{
+					printk("%s: i82586 initialization timed out, status %04x, cmd %04x\n",
+						dev->name, inw(ioaddr+SCB_STATUS), inw(ioaddr+SCB_CMD));
+					outw(CONF_LINK,ioaddr+SCB_CBL);
+					outw(0,ioaddr+SCB_STATUS);
+					outw(0xf000|SCB_CUstart,ioaddr+SCB_CMD);
+					outb(0,ioaddr+SIGNAL_CA);
+					iboguscount = 100;
+				}
+				else 
+				{
+					printk("%s: Failed to initialize i82586, giving up.\n",dev->name);
+					return;
+				}
+			}
 		}
-#endif
+	}
+  
+	outb(SIRQ_en|irqrmap[dev->irq],ioaddr+SET_IRQ);
+	clear_loopback;
+	lp->init_time = jiffies;
+	if (started) 
+		printk("%s: Uh? We haven't started yet\n",dev->name);
+	return;
+}
+
+/* 
+ * completely reset the EtherExpress hardware. We will most likely get
+ * an interrupt during this whether we want one or not. It is best,
+ * therefore, to call this while we don't have a request_irq() on.
+ */
 
-		rx_tail = rx_head;
-		rx_head = next_rx_frame;
-		if (--boguscount == 0)
-			break;
-		outw(rx_head, ioaddr + READ_PTR);
+static void eexp_hw_ASICrst(struct device *dev)
+{
+	unsigned short ioaddr = dev->base_addr;
+	unsigned short wrval = 0x0001,succount=0,boguscount=500;
+
+	outb(SIRQ_dis|irqrmap[dev->irq],ioaddr+SET_IRQ);
+
+	set_loopback;  /* yet more paranoia - since we're resetting the ASIC
+			* that controls this function, how can it possibly work?
+                        */
+	started = 0;
+	outb(ASIC_RST|i586_RST,ioaddr+EEPROM_Ctrl);
+	while (succount<20) 
+	{
+		if (wrval == 0xffff) 
+			wrval = 0x0001;
+		outw(0,ioaddr+WRITE_PTR);
+		outw(wrval,ioaddr);
+		outw(0,ioaddr+READ_PTR);
+		if (wrval++ == inw(ioaddr)) 
+			succount++;
+		else 
+		{
+			succount = 0;
+			if (!boguscount--) 
+			{
+				boguscount = 500;
+				printk("%s: Having problems resetting EtherExpress ASIC, continuing...\n",
+					dev->name);
+				wrval = 0x0001;
+				outb(ASIC_RST|i586_RST,ioaddr+EEPROM_Ctrl);
+			}
+		}
 	}
-	
-	lp->rx_head = rx_head;
-	lp->rx_tail = rx_tail;
-	
-	/* Restore the original write pointer. */
-	outw(saved_write_ptr, ioaddr + WRITE_PTR);
+	outb(i586_RST,ioaddr+EEPROM_Ctrl);
 }
-
+
+/*
+ * MODULE stuff
+ */
+
 #ifdef MODULE
-static char devicename[9] = { 0, };
-static struct device dev_eexpress = {
-	devicename, /* device name is inserted by linux/drivers/net/net_init.c */
-	0, 0, 0, 0,
-	0, 0,
-	0, 0, 0, NULL, express_probe };
-	
-
-static int irq=0x300;
-static int io=0;	
-
-int
-init_module(void)
-{
-	if (io == 0)
-		printk("eexpress: You should not use auto-probing with insmod!\n");
-	dev_eexpress.base_addr=io;
-	dev_eexpress.irq=irq;
-	if (register_netdev(&dev_eexpress) != 0)
+
+static struct device dev_eexpress = 
+{
+	"EExpress", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, express_probe 
+};
+
+int irq = 0;
+int io = 0;
+
+int init_module(void)
+{
+	dev_eexpress.base_addr = io;
+	dev_eexpress.irq = irq;
+	if (register_netdev(&dev_eexpress) != 0) 
 		return -EIO;
 	return 0;
 }
 
-void
-cleanup_module(void)
+void cleanup_module(void)
 {
 	unregister_netdev(&dev_eexpress);
 	kfree_s(dev_eexpress.priv,sizeof(struct net_local));
-	dev_eexpress.priv=NULL;
-
-	/* If we don't do this, we can't re-insmod it later. */
-	release_region(dev_eexpress.base_addr, EEXPRESS_IO_EXTENT);
+	dev_eexpress.priv = NULL;
 }
-#endif /* MODULE */
-/*
- * Local variables:
- *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -I/usr/src/linux/drivers/net -Wall -Wstrict-prototypes -O6 -m486 -c eexpress.c"
- *  version-control: t
- *  kept-new-versions: 5
- *  tab-width: 4
- * End:
- */
+#endif
diff -u --recursive --new-file v1.3.70/linux/drivers/net/eth82586.h linux/drivers/net/eth82586.h
--- v1.3.70/linux/drivers/net/eth82586.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/eth82586.h	Mon Mar  4 09:16:36 1996
@@ -0,0 +1,176 @@
+/*
+ * eth82586.h: Intel EtherExpress defines
+ *
+ * Written 1995 by John Sullivan
+ * See eexpress.c for furthur details
+ * documentation and usage to do.
+ */
+
+/*
+ * EtherExpress card register addresses
+ * as offsets from the base IO region (dev->base_addr)
+ */
+
+#define DATAPORT 0x0000
+#define WRITE_PTR 0x0002
+#define READ_PTR 0x0004
+#define SIGNAL_CA 0x0006
+#define SET_IRQ 0x0007
+#define SM_PTR 0x0008
+#define MEM_Ctrl 0x000b
+#define MEM_Page_Ctrl 0x000c
+#define Config 0x000d
+#define EEPROM_Ctrl 0x000e
+#define ID_PORT 0x000f
+
+/*
+ * offset to shadowed memory, 0 <= x <= 31. We don't use this yet,
+ * but may in the future. Is shadow memory access any faster than
+ * dataport access?
+ */
+#define SM_ADDR(x) (0x4000+((x&0x10)<<10)+(x&0xf))
+
+/* Always mirrors eexp-memory at 0x0008-0x000f */
+#define SCB_STATUS 0xc008
+#define SCB_CMD 0xc00a
+#define SCB_CBL 0xc00c
+#define SCB_RFA 0xc00e
+
+
+
+/*
+ * card register defines
+ */
+
+/* SET_IRQ */
+#define SIRQ_en 0x08
+#define SIRQ_dis 0x00
+
+/* Config */
+#define set_loopback outb(inb(ioaddr+Config)|0x02,ioaddr+Config)
+#define clear_loopback outb(inb(ioaddr+Config)&0xfd,ioaddr+Config)
+
+/* EEPROM_Ctrl */
+#define EC_Clk 0x01
+#define EC_CS  0x02
+#define EC_Wr  0x04
+#define EC_Rd  0x08
+#define ASIC_RST 0x40
+#define i586_RST  0x80
+
+#define eeprom_delay() { int _i = 40; while (--_i>0) { __SLOW_DOWN_IO; }}
+
+/*
+ * i82586 Memory Configuration
+ */
+
+/* (System Configuration Pointer) System start up block, read after 586_RST */
+#define SCP_START 0xfff6
+
+
+/* Intermediate System Configuration Pointer */
+#define ISCP_START 0x0000
+/* System Command Block */
+#define SCB_START 0x0008
+
+/*
+ * Start of buffer region. If we have 64k memory, eexp_hw_probe() may raise
+ * NUM_TX_BUFS. RX_BUF_END is set to the end of memory, and all space between
+ * the transmit buffer region and end of memory used for as many receive buffers
+ * as we can fit. See eexp_hw_[(rx)(tx)]init().
+ */
+#define TX_BUF_START 0x0100
+#define TX_BUF_SIZE ((24+ETH_FRAME_LEN+31)&~0x1f)
+unsigned short NUM_TX_BUFS=4;
+unsigned short RX_BUF_START;
+#define RX_BUF_SIZE ((32+ETH_FRAME_LEN+31)&~0x1f)
+unsigned short RX_BUF_END=0x7ff6; /* updated automatically to 0xfff6 on 64k cards */
+unsigned short NUM_RX_BUFS = 4;
+
+
+
+/*
+ * SCB defines
+ */
+
+/* these functions take the SCB status word and test the relavent status bit */
+#define SCB_complete(s) ((s&0x8000)!=0)
+#define SCB_rxdframe(s) ((s&0x4000)!=0)
+#define SCB_CUdead(s) ((s&0x2000)!=0)
+#define SCB_RUdead(s) ((s&0x1000)!=0)
+#define SCB_ack(s) (s & 0xf000)
+
+/* Command unit status: 0=idle, 1=suspended, 2=active */
+#define SCB_CUstat(s) ((s&0x0300)>>8)
+
+/* Receive unit status: 0=idle, 1=suspended, 2=out of resources, 4=ready */
+#define SCB_RUstat(s) ((s&0x0070)>>4)
+
+/* SCB commands */
+#define SCB_CUnop     0x0000
+#define SCB_CUstart   0x0100
+#define SCB_CUresume  0x0200
+#define SCB_CUsuspend 0x0300
+#define SCB_CUabort   0x0400
+
+/* ? */
+#define SCB_resetchip 0x0080
+
+#define SCB_RUnop     0x0000
+#define SCB_RUstart   0x0010
+#define SCB_RUresume  0x0020
+#define SCB_RUsuspend 0x0030
+#define SCB_RUabort   0x0040
+
+
+/*
+ * Command block defines
+ */
+
+#define Stat_Done(s)   ((s&0x8000)!=0)
+#define Stat_Busy(s)   ((s&0x4000)!=0)
+#define Stat_OK(s)     ((s&0x2000)!=0)
+#define Stat_Abort(s)  ((s&0x1000)!=0)
+#define Stat_STFail    ((s&0x0800)!=0)
+#define Stat_TNoCar(s) ((s&0x0400)!=0)
+#define Stat_TNoCTS(s) ((s&0x0200)!=0)
+#define Stat_TNoDMA(s) ((s&0x0100)!=0)
+#define Stat_TDefer(s) ((s&0x0080)!=0)
+#define Stat_TColl(s)  ((s&0x0040)!=0)
+#define Stat_TXColl(s) ((s&0x0020)!=0)
+#define Stat_NoColl(s) (s&0x000f)
+
+/* Cmd_END will end AFTER the command if this is the first
+ * command block after an SCB_CUstart, but BEFORE the command
+ * for all subsequent commands. Best strategy is to place
+ * Cmd_INT on the last command in the sequence, followed by a
+ * dummy Cmd_Nop with Cmd_END after this.
+ */
+#define Cmd_END     0x8000
+#define Cmd_SUS     0x4000
+#define Cmd_INT     0x2000
+
+#define Cmd_Nop     0x0000
+#define Cmd_SetAddr 0x0001
+#define Cmd_Config  0x0002
+#define Cmd_MCast   0x0003
+#define Cmd_Xmit    0x0004
+#define Cmd_TDR     0x0005
+#define Cmd_Dump    0x0006
+#define Cmd_Diag    0x0007
+
+
+/*
+ * Frame Descriptor (Receive block) defines
+ */
+
+#define FD_Done(s)  ((s&0x8000)!=0)
+#define FD_Busy(s)  ((s&0x4000)!=0)
+#define FD_OK(s)    ((s&0x2000)!=0)
+
+#define FD_CRC(s)   ((s&0x0800)!=0)
+#define FD_Align(s) ((s&0x0400)!=0)
+#define FD_Resrc(s) ((s&0x0200)!=0)
+#define FD_DMA(s)   ((s&0x0100)!=0)
+#define FD_Short(s) ((s&0x0080)!=0)
+#define FD_NoEOF(s) ((s&0x0040)!=0)
diff -u --recursive --new-file v1.3.70/linux/drivers/net/lance.c linux/drivers/net/lance.c
--- v1.3.70/linux/drivers/net/lance.c	Sat Mar  2 10:43:32 1996
+++ linux/drivers/net/lance.c	Mon Mar  4 09:16:36 1996
@@ -940,9 +940,9 @@
 		}
 	}
 
-    /* Clear any other interrupt, and set interrupt enable. */
-    outw(0x0000, dev->base_addr + LANCE_ADDR);
-    outw(0x7940, dev->base_addr + LANCE_DATA);
+	/* Clear any other interrupt, and set interrupt enable. */
+	outw(0x0000, dev->base_addr + LANCE_ADDR);
+	outw(0x7940, dev->base_addr + LANCE_DATA);
 
 	if (lance_debug > 4)
 		printk("%s: exiting interrupt, csr%d=%#4.4x.\n",
@@ -979,7 +979,7 @@
 		}
 		else 
 		{
-			/* Malloc up new buffer, compatible with net-2e. */
+			/* Malloc up new buffer, compatible with net3. */
 			short pkt_len = (lp->rx_ring[entry].msg_length & 0xfff)-4;
 			struct sk_buff *skb;
 			
diff -u --recursive --new-file v1.3.70/linux/drivers/net/ppp.c linux/drivers/net/ppp.c
--- v1.3.70/linux/drivers/net/ppp.c	Wed Feb  7 15:11:25 1996
+++ linux/drivers/net/ppp.c	Mon Mar  4 09:16:36 1996
@@ -87,7 +87,7 @@
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/segment.h>
-#include <net/if.h>
+#include <linux/if.h>
 #include <linux/if_ether.h>
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
@@ -101,8 +101,8 @@
 #define skb_data(skb)	     ((unsigned char *) (skb)->data)
 #endif
 
-#include <netinet/ip.h>
-#include <netinet/tcp.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
 #include <linux/if_arp.h>
 #include "slhc.h"
 #include <linux/ppp_defs.h>
diff -u --recursive --new-file v1.3.70/linux/drivers/net/slip.c linux/drivers/net/slip.c
--- v1.3.70/linux/drivers/net/slip.c	Sat Mar  2 10:43:33 1996
+++ linux/drivers/net/slip.c	Mon Mar  4 11:25:48 1996
@@ -1402,7 +1402,7 @@
 {
 	struct slip *sl=(struct slip *)sls;
 
-	if(sls==NULL)
+	if(sl == NULL)
 		return;
 
 	if( sl->keepalive)
diff -u --recursive --new-file v1.3.70/linux/drivers/net/sunlance.c linux/drivers/net/sunlance.c
--- v1.3.70/linux/drivers/net/sunlance.c	Sat Mar  2 10:43:33 1996
+++ linux/drivers/net/sunlance.c	Mon Mar  4 08:49:59 1996
@@ -1,17 +1,22 @@
 /* lance.c: Linux/Sparc/Lance driver */
 /*
-	Written 1995 by Miguel de Icaza
+	Written 1995, 1996 by Miguel de Icaza
   Sources:
 	The Linux  depca driver
 	The Linux  lance driver.
 	The Linux  skeleton driver.
         The NetBSD Sparc/Lance driver.
-	Theo Deraadt (deraadt@theos.com)
+	Theo de Raadt (deraadt@openbsd.org)
 	NCR92C990 Lan Controller manual
-*/
 
+1.4:
+	Added support to run with a ledma on the Sun4m
+*/
+#undef DEBUG_DRIVER
 static char *version =
-	"lance.c:v1.2 29/Oct/95 Miguel de Icaza (miguel@nuclecu.unam.mx)\n";
+	"sunlance.c:v1.4 17/Feb/96 Miguel de Icaza (miguel@nuclecu.unam.mx)\n";
+
+static char *lancestr = "LANCE";
 
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -43,9 +48,6 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 
-#define MASK_INTERRUPTS   1
-#define UNMASK_INTERRUPTS 0
-
 /* Define: 2^2 Tx buffers and 2^4 Rx buffers */
 #ifndef LANCE_LOG_TX_BUFFERS
 #define LANCE_LOG_TX_BUFFERS 2
@@ -114,8 +116,8 @@
 #define RX_RING_LEN_BITS		((LANCE_LOG_RX_BUFFERS) << 29)
 
 #define PKT_BUF_SZ		1544
-#define RX_BUFF_SIZE            1536
-#define TX_BUFF_SIZE            1536
+#define RX_BUFF_SIZE            PKT_BUF_SZ
+#define TX_BUFF_SIZE            PKT_BUF_SZ
 
 struct lance_rx_desc {
     unsigned short rmd0;        /* low address of packet */
@@ -155,14 +157,15 @@
 };
 
 struct lance_private {
-	char *name;
-	volatile struct lance_regs *ll;
-	volatile struct lance_init_block *init_block;
-	
-	int rx_new, tx_new;
-	int rx_old, tx_old;
-
-	struct enet_statistics stats;
+    char *name;
+    volatile struct lance_regs *ll;
+    volatile struct lance_init_block *init_block;
+    
+    int rx_new, tx_new;
+    int rx_old, tx_old;
+    
+    struct enet_statistics stats;
+    struct Linux_SBus_DMA *ledma; /* if set this points to ledma and arch=4m */
 };
 
 #define TX_BUFFS_AVAIL ((lp->tx_old<=lp->tx_new)?\
@@ -178,7 +181,8 @@
 int sparc_lance_debug = 2;
 
 /* The Lance uses 24 bit addresses */
-/* The DVMA will provide the remaining bytes for us */
+/* On the Sun4c the DVMA will provide the remaining bytes for us */
+/* On the Sun4m we have to instruct the ledma to provide them    */
 #define LANCE_ADDR(x) ((int)(x) & ~0xff000000)
 
 /* Load the CSR registers */
@@ -277,7 +281,8 @@
     ib->filter [1] = 0;
 }
 
-static int init_restart_lance (struct lance_private *lp)
+static int
+init_restart_lance (struct lance_private *lp)
 {
     volatile struct lance_regs *ll = lp->ll;
     int i;
@@ -290,13 +295,19 @@
 	;
     if ((i == 100) || (ll->rdp & LE_C0_ERR)){
 	printk ("LANCE unopened after %d ticks, csr0=%4.4x.\n", i, ll->rdp);
+	if (lp->ledma)
+	    printk ("dcsr=%8.8x\n", (unsigned int) lp->ledma->regs->cond_reg);
 	return -1;
     }
 
     /* Clear IDON by writing a "1", enable interrupts and start lance */
     ll->rdp = LE_C0_IDON;
     ll->rdp = LE_C0_INEA | LE_C0_STRT;
-    printk ("LANCE opened after %d ticks, csr0=%4.4x\n", i, ll->rdp);
+
+    /* On the 4m, enable dma interrupts */
+    if (lp->ledma)
+	lp->ledma->regs->cond_reg |= DMA_INT_ENAB;
+
     return 0;
 }
 
@@ -307,8 +318,6 @@
     volatile struct lance_init_block *ib = lp->init_block;
     volatile struct lance_regs *ll = lp->ll;
     volatile struct lance_rx_desc *rd;
-    int i;
-    int entry;
     unsigned char bits;
 
 #ifdef TEST_HITS
@@ -322,71 +331,28 @@
     printk ("]");
 #endif
     
-#ifdef OLD_METHOD
-    ll->rdp = LE_C0_RINT|LE_C0_INEA;
-    /* FIXME: Add slot prediction */
-    for (rd = &ib->brx_ring [i = 0]; i < RX_RING_SIZE; i++, rd++){
-	int bits;
-	
-	bits = rd->rmd1_bits;
-
-	/* Check if we own the packet */
-	if (bits & LE_R1_OWN)
-	    continue;
-
-	/* We got an incomplete frame? */
-	if ((bits & LE_R1_POK) != LE_R1_POK){
-	    /* Count only the end frame as a tx error, not the beginning */
-	    if (bits & LE_R1_EOP) lp->stats.rx_errors++;
-	    if (bits & LE_R1_BUF) lp->stats.rx_fifo_errors++;
-	    if (bits & LE_R1_CRC) lp->stats.rx_crc_errors++;
-	    if (bits & LE_R1_OFL) lp->stats.rx_over_errors++;
-  	    if (bits & LE_R1_FRA) lp->stats.rx_frame_errors++;
-	} else {
-	    int pkt_len = rd->mblength;
-	    struct sk_buff *skb;
-	    char *buf;
-	    
-	    skb = dev_alloc_skb (pkt_len+2);
-	    if (skb == NULL){
-		printk ("%s: Memory squeeze, deferring packet.\n", dev->name);
-		lp->stats.rx_dropped++;
-		rd->rmd1_bits = LE_R1_OWN;
-		return 0;
-	    }
-	    
-	    skb->dev = dev;
-	    skb_reserve (skb, 2);               /* 16 byte align */
-	    buf = skb_put (skb, pkt_len);       /* make room */
-	    memcpy (buf, &(ib->rx_buf [i][0]), pkt_len);
-	    skb->protocol = eth_type_trans (skb,dev);
-	    netif_rx (skb);
-	    lp->stats.rx_packets++;
-	}
-
-	/* Return the packet to the pool */
-	rd->rmd1_bits = LE_R1_OWN;
-    }
-#else
     ll->rdp = LE_C0_RINT|LE_C0_INEA;
     for (rd = &ib->brx_ring [lp->rx_new];
 	 !((bits = rd->rmd1_bits) & LE_R1_OWN);
 	 rd = &ib->brx_ring [lp->rx_new]){
+	int pkt_len;
+	struct sk_buff *skb;
+	char *buf;
 
 	/* We got an incomplete frame? */
 	if ((bits & LE_R1_POK) != LE_R1_POK){
-	    printk ("Incomplete frame\n");
+	    lp->stats.rx_over_errors++;
+	    lp->stats.rx_errors++;
+	    continue;
+	} else if (bits & LE_R1_ERR){
 	    /* Count only the end frame as a tx error, not the beginning */
-	    if (bits & LE_R1_EOP) lp->stats.rx_errors++;
 	    if (bits & LE_R1_BUF) lp->stats.rx_fifo_errors++;
 	    if (bits & LE_R1_CRC) lp->stats.rx_crc_errors++;
 	    if (bits & LE_R1_OFL) lp->stats.rx_over_errors++;
   	    if (bits & LE_R1_FRA) lp->stats.rx_frame_errors++;
+	    if (bits & LE_R1_EOP) lp->stats.rx_errors++;
 	} else {
-	    int pkt_len = rd->mblength;
-	    struct sk_buff *skb;
-	    char *buf;
-
+	    pkt_len = rd->mblength;
 	    skb = dev_alloc_skb (pkt_len+2);
 	    if (skb == NULL){
 		printk ("%s: Memory squeeze, deferring packet.\n", dev->name);
@@ -409,7 +375,6 @@
 	rd->rmd1_bits = LE_R1_OWN;
 	lp->rx_new = (lp->rx_new + 1) & RX_RING_MOD_MASK;
     }
-#endif
     return 0;
 }
 
@@ -446,9 +411,13 @@
 		/* Stop the lance */
 		ll->rdp = LE_CSR0;
 		ll->rap = LE_C0_STOP;
+		lance_init_ring (dev);
+		load_csrs (lp);
 		init_restart_lance (lp);
+		return 0;
 	    }
-	}
+        } else
+		lp->stats.tx_packets++;
 	
 	j = (j + 1) & TX_RING_MOD_MASK;
     }
@@ -469,13 +438,19 @@
     lp = (struct lance_private *) dev->priv;
     ll = lp->ll;
 
+    if (lp->ledma)
+	if (lp->ledma->regs->cond_reg & DMA_HNDL_ERROR){
+	    printk ("%s: should reset my ledma (dmacsr=%8.8x, csr=%4.4x\n", dev->name,
+		    (unsigned int) lp->ledma->regs->cond_reg, ll->rdp); 
+	    printk ("send mail to miguel@nuclecu.unam.mx\n");
+	}
     if (dev->interrupt)
 	printk ("%s: again", dev->name);
     
     dev->interrupt = 1;
 
     csr0 = ll->rdp;
-    
+
     /* Acknowledge all the interrupt sources ASAP */
     ll->rdp = csr0 & 0x004f;
     
@@ -512,17 +487,21 @@
     int status = 0;
 
     last_dev = dev;
-    
-    /* Stop the Lance */
-    ll->rap = LE_CSR0;
-    ll->rdp = LE_C0_STOP;
 
-    if (request_irq (dev->irq, &lance_interrupt, 0, "LANCE", NULL)){
+    if (request_irq (dev->irq, &lance_interrupt, 0, lancestr, NULL)){
 	printk ("Lance: Can't get irq %d\n", dev->irq);
 	return -EAGAIN;
     }
+    /* Stop the Lance */
+    ll->rap = LE_CSR0;
+    ll->rdp = LE_C0_STOP;
+
     irq2dev_map [dev->irq] = dev;
 
+    /* On the 4m, setup the ledma to provide the upper bits for buffers */
+    if (lp->ledma)
+	lp->ledma->regs->dma_test = ((unsigned int) lp->init_block) & 0xff000000;
+
     lance_init_ring (dev);
     load_csrs (lp);
 
@@ -531,28 +510,15 @@
     dev->start = 1;
 
     status = init_restart_lance (lp);
-
-    /* To make life easier to us while Sparc Linux becomes self hosting: */
-    {
-	    struct rtentry server_route;
-	    struct sockaddr_in *sin;
-	    
-	    sin=(struct sockaddr_in *)&server_route.rt_dst;
-	    *sin=server;
-	    sin=(struct sockaddr_in *)&server_route.rt_genmask;
-	    sin->sin_family=AF_INET;
-	    sin->sin_addr.s_addr= ip_get_mask (dev->pa_addr);
-	    server_route.rt_dev[0]=dev;
-	    server_route.
-	    server_route.rt_flags=RTF_HOST|RTF_UP;
-
-	    if(ip_rt_new(&server_route)==-1)
-		    printk("Unable to add NFS server route.\n");
-    }
-    ip_rt_add (RTF_UP,
-	       dev->pa_addr & ip_get_mask (dev->pa_addr),
-	       ip_get_mask (dev->pa_addr),
-	       0, dev, dev->mtu, 0, 0);
+    if (lp->ledma)
+	lp->ledma->regs->cond_reg |= DMA_INT_ENAB;
+#if 0
+    /* To emulate SunOS, we add a route to the local network */
+    rt_add (RTF_UP,
+	    dev->pa_addr & ip_get_mask (dev->pa_addr),
+	    ip_get_mask (dev->pa_addr),
+	    0, dev, dev->mtu, 0, 0);
+#endif
     return status;
 }
 
@@ -575,7 +541,8 @@
     return 0;
 }
 
-inline static int lance_reset (struct device *dev)
+inline static int
+lance_reset (struct device *dev)
 {
     struct lance_private *lp = (struct lance_private *)dev->priv;
     volatile struct lance_regs *ll = lp->ll;
@@ -584,9 +551,15 @@
     /* Stop the lance */
     ll->rdp = LE_CSR0;
     ll->rap = LE_C0_STOP;
-#ifdef DEBUG_DRIVER
-    printk ("Lance stopped: csr0=%4.4x\n", ll->rdp);
-#endif
+
+    /* On the 4m, reset the dma too */
+    if (lp->ledma){
+	printk ("resetting ledma\n");
+	lp->ledma->regs->cond_reg |= DMA_RST_ENET;
+	udelay (200);
+	lp->ledma->regs->cond_reg &= ~DMA_RST_ENET;
+	lp->ledma->regs->cond_reg |= DMA_INT_ENAB;
+    }
     lance_init_ring (dev);
     load_csrs (lp);
     dev->trans_start = jiffies;
@@ -597,9 +570,11 @@
 #ifdef DEBUG_DRIVER
     printk ("Lance restart=%d\n", status);
 #endif
+    return status;
 }
 
-static int lance_start_xmit (struct sk_buff *skb, struct device *dev)
+static int
+lance_start_xmit (struct sk_buff *skb, struct device *dev)
 {
     struct lance_private *lp = (struct lance_private *)dev->priv;
     volatile struct lance_regs *ll = lp->ll;
@@ -649,9 +624,13 @@
 
 #ifdef DEBUG_DRIVER
     /* dump the packet */
-    for (i = 0; i < 64; i++){
-	if ((i % 16) == 0) printk ("\n");
-	printk ("%2.2x ", skb->data [i]);
+    {
+	int i;
+	
+	for (i = 0; i < 64; i++){
+	    if ((i % 16) == 0) printk ("\n");
+	    printk ("%2.2x ", skb->data [i]);
+	}
     }
 #endif
     len = (skblen < ETH_ZLEN) ? ETH_ZLEN : skblen;
@@ -692,7 +671,7 @@
 }
 
 static void
-lance_set_multicast (struct device *dev)
+lance_set_multicast (struct device *dev, int num_addrs, void *addrs)
 {
 #ifdef NOT_YET
     struct lance_private *lp = (struct lance_private *) dev->priv;
@@ -714,6 +693,19 @@
 #endif
 }
 
+/* On 4m, find the associated dma for the lance chip */
+static struct Linux_SBus_DMA *
+find_ledma (struct linux_sbus_device *dev)
+{
+    struct Linux_SBus_DMA *p;
+
+    for (p = dma_chain; p; p = p->next)
+	if (p->SBus_dev == dev)
+	    return p;
+    return 0;
+}
+
+/* FIXME: the probe code should be able to detect  */
 int sparc_lance_probe (struct device *dev)
 {
     static unsigned version_printed = 0;
@@ -721,6 +713,7 @@
     int    found = 0;
     struct linux_sbus *bus;
     struct linux_sbus_device *sdev = 0;
+    struct Linux_SBus_DMA *ledma = 0;
     struct lance_private *lp;
     volatile struct lance_regs *ll;
 
@@ -733,6 +726,12 @@
 		found = 1;
 		break;
 	    }
+	    if (strcmp (sdev->prom_name, "ledma") == 0){
+		ledma = find_ledma (sdev);
+		found = 1;
+		sdev = sdev->child;
+		break;
+	    }
 	}
     }
     if (!found)
@@ -743,6 +742,8 @@
 	dev = init_etherdev (0, sizeof (struct lance_private));
     } else {
 	dev->priv = kmalloc (sizeof (struct lance_private), GFP_KERNEL);
+	if (dev->priv == NULL)
+		return -ENOMEM;
     }
     if (sparc_lance_debug && version_printed++ == 0)
 	printk (version);
@@ -759,18 +760,22 @@
 	printk ("%2.2x%c", dev->dev_addr [i] = idprom->id_eaddr [i], i == 5 ? ' ': ':');
     }
     /* Get the IO region */
+    prom_apply_sbus_ranges (&sdev->reg_addrs [0], sdev->num_registers);
     ll = sparc_alloc_io (sdev->reg_addrs [0].phys_addr, 0,
-			 sizeof (struct lance_regs), "Lance driver", 0x0, 0x0);
-    
+			 sizeof (struct lance_regs), lancestr,
+			 sdev->reg_addrs[0].which_io, 0x0);
+
     /* Make certain the data structures used by the LANCE are aligned. */
     dev->priv = (void *)(((int)dev->priv + 7) & ~7);
     lp = (struct lance_private *) dev->priv;
+    memset ((char *)dev->priv, 0, sizeof (struct lance_private));
     
     lp->init_block = (void *)
-	sparc_dvma_malloc (sizeof (struct lance_init_block), "LANCE");
+	sparc_dvma_malloc (sizeof (struct lance_init_block), lancestr);
     
     lp->ll = ll;
-    lp->name = "LANCE";
+    lp->name = lancestr;
+    lp->ledma = ledma;
 
     /* This should never happen. */
     if ((int)(lp->init_block->brx_ring) & 0x07) {
@@ -787,7 +792,7 @@
     dev->irq = (unsigned char) sdev->irqs [0].pri;
     dev->dma = 0;
     ether_setup (dev);
-    
+
     return 0;
 }
 /*
diff -u --recursive --new-file v1.3.70/linux/drivers/net/tunnel.c linux/drivers/net/tunnel.c
--- v1.3.70/linux/drivers/net/tunnel.c	Wed Feb  7 15:11:27 1996
+++ linux/drivers/net/tunnel.c	Thu Jan  1 02:00:00 1970
@@ -1,313 +0,0 @@
-/* tunnel.c: an IP tunnel driver
-
-	The purpose of this driver is to provide an IP tunnel through
-	which you can tunnel network traffic transparently across subnets.
-
-	This was written by looking at Nick Holloway's dummy driver
-	Thanks for the great code!
-
-		-Sam Lantinga	(slouken@cs.ucdavis.edu)  02/01/95
-		
-	Minor tweaks:
-		Cleaned up the code a little and added some pre-1.3.0 tweaks.
-		dev->hard_header/hard_header_len changed to use no headers.
-		Comments/bracketing tweaked.
-		Made the tunnels use dev->name not tunnel: when error reporting.
-		Added tx_dropped stat
-		
-		-Alan Cox	(Alan.Cox@linux.org) 21 March 95
-*/
-
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <netinet/in.h>
-#include <linux/ip.h>
-#include <linux/string.h>
-#include <asm/system.h>
-#include <linux/errno.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/if_arp.h>
-#include <linux/skbuff.h>
-#include <net/ip.h>
-
-#include <net/checksum.h>		/* If using 1.3.0-pre net code */
-
-#define ip_header_len	sizeof(struct iphdr)
-
-static int tunnel_xmit(struct sk_buff *skb, struct device *dev);
-static struct enet_statistics *tunnel_get_stats(struct device *dev);
-
-#ifdef MODULE
-static int tunnel_open(struct device *dev)
-{
-	MOD_INC_USE_COUNT;
-	return 0;
-}
-
-static int tunnel_close(struct device *dev)
-{
-	MOD_DEC_USE_COUNT;
-	return 0;
-}
-
-#endif
-
-
-int tunnel_init(struct device *dev)
-{
-	static int tun_msg=0;
-	if(!tun_msg)
-	{
-		printk ( KERN_INFO "tunnel: version v0.1a\n" );
-		tun_msg=1;
-	}
-
-	/* Fill in fields of the dev structure with ethernet-generic values. */
-	ether_setup(dev);
-
-	/* Custom initialize the device structure. */
-	dev->hard_start_xmit = tunnel_xmit;
-	dev->get_stats = tunnel_get_stats;
-	dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL);
-	if (dev->priv == NULL)
-		return -ENOMEM;
-	memset(dev->priv, 0, sizeof(struct enet_statistics));
-#ifdef MODULE
-	dev->open = &tunnel_open;
-	dev->stop = &tunnel_close;
-#endif
-	/* Now stomp the bits that are different */
-	dev->type = ARPHRD_TUNNEL; 	/* IP tunnel hardware type (Linux 1.1.89) */
-	dev->flags |= IFF_NOARP;
-	dev->flags |= IFF_LOOPBACK; 	/* Why doesn't tunnel work without this? [ should do now - AC]*/
-	dev->addr_len=0;
-	dev->tx_queue_len=2;		/* Small queue - it should all run through */
-	dev->hard_header_len=0;
-	dev->hard_header=NULL;
-	dev->header_cache_bind=NULL;
-	dev->rebuild_header=NULL;
-	/* End of stomp 8) */
-	return 0;
-}
-
-#ifdef TUNNEL_DEBUG
-void print_ip(struct iphdr *ip)
-{
-	unsigned char *ipaddr;
-
-	printk("IP packet:\n");
-	printk("--- header len = %d\n", ip->ihl*4);
-	printk("--- ip version: %d\n", ip->version);
-	printk("--- ip protocol: %d\n", ip->protocol);
-	ipaddr=(unsigned char *)&ip->saddr;
-	printk("--- source address: %u.%u.%u.%u\n", 
-			*ipaddr, *(ipaddr+1), *(ipaddr+2), *(ipaddr+3));
-	ipaddr=(unsigned char *)&ip->daddr;
-	printk("--- destination address: %u.%u.%u.%u\n", 
-			*ipaddr, *(ipaddr+1), *(ipaddr+2), *(ipaddr+3));
-	printk("--- total packet len: %d\n", ntohs(ip->tot_len));
-}
-#endif
-
-/* This function assumes it is being called from dev_queue_xmit()
-   and that skb is filled properly by that function.
-   We also presume that if we return 0, we need to free skb, but
-   if we return 1, we don't free anything.  Right?  Wrong?
-*/
-
-static int tunnel_xmit(struct sk_buff *skb, struct device *dev)
-{
-	struct enet_statistics *stats;
-	struct sk_buff *skb2;		/* The output packet */
-	int newlen;			/* The length of skb2->data */
-	struct iphdr *iph;		/* Our new IP header */
-
-	/*
-	 *	Return if there is nothing to do 
-	 */
-	 
-	if (skb == NULL || dev == NULL)
-		return 0;
-
-	/* 
-	 *	Make sure we are not busy (check lock variable) 
-	 */
-	 
-	stats = (struct enet_statistics *)dev->priv;
-	cli();
-	if (dev->tbusy != 0) 
-	{
-		sti();
-		stats->tx_errors++;
-		return(1);
-	}
-	dev->tbusy = 1;
-	sti();
-  
-	/*
-	 *	Perform some sanity checks on the packet 
-	 */
-	 
-	if ( ! dev->pa_dstaddr ) 
-	{
-		printk("%s: packet sent through tunnel to never-never land!\n", dev->name);
-  		dev_kfree_skb(skb, FREE_WRITE);
-		dev->tbusy = 0;
-		return(1);
-	}
-
-	iph=(struct iphdr *)skb->data;
-	if ( iph->version != 4 ) 
-	{  
-		/* 
-		 *	Bad IP packet? Possibly an ARP packet 
-		 */
-		printk("%s: Bad IP packet: ip version %d\n", dev->name, iph->version);
-		dev_kfree_skb(skb, FREE_WRITE);
-		dev->tbusy = 0;
-		return(0);
-	}
-
-
-	/* 
-	 *	Check for routing loops 
-	 */
-	 
-	if ( iph->protocol == IPPROTO_IPIP && iph->saddr == dev->pa_addr ) 
-	{
-		/* 
-		 *	We really should do an ICMP reply here... 
-		 */
-		printk("%s: Warning: IP routing loop!\n", dev->name);
-		dev->tbusy = 0;
-		dev_kfree_skb(skb, FREE_WRITE);
-		return(0);
-	}
-
-	if ( iph->daddr == dev->pa_addr ) 
-	{
-		printk("%s: Received inbound packet -- not handled.\n",dev->name);
-  		dev_kfree_skb(skb, FREE_WRITE);
-		dev->tbusy = 0;
-		return(0);
-	}
-
-#ifdef TUNNEL_DEBUG
-printk("Old IP Header....\n");
-print_ip(iph);
-#endif
-	/*
-	 * Everything is okay: 
-	 *		See if we need to allocate memory for a new packet 
-	 */
-
-	newlen = (skb->len + ip_header_len);
-	if ( !(skb2 = dev_alloc_skb(newlen)) ) 
-	{
-		printk("%s: No free memory.\n",dev->name);
-  		dev_kfree_skb(skb, FREE_WRITE);
-  		dev->tbusy = 0;
-  		stats->tx_dropped++;
-		return(1);
-	}
-
-	/* Copy the packet to a new buffer, adding a new ip header */
-	skb2->free=1;
-	skb_put(skb2,newlen);
-	iph=skb2->h.iph=(struct iphdr *)skb2->data;
-	skb2->ip_hdr=iph;
-	memcpy(skb2->h.iph, skb->data, ip_header_len );
-	memcpy(skb2->data + ip_header_len, skb->data, skb->len);
-	/* Free the old packet, we no longer need it */
-	dev_kfree_skb(skb, FREE_WRITE);
-
-	/* Correct the fields in the new ip header */
-	++iph->ttl;	/* Note: ip_forward() decrements ttl, so compensate */
-	iph->saddr = dev->pa_addr;
-	iph->daddr = dev->pa_dstaddr;
-	iph->protocol = IPPROTO_IPIP;
-	iph->ihl = 5;
-	iph->tot_len = htons(skb2->len);
-	iph->frag_off = 0;
-
-	/* Here is where we compute the IP checksum */
-	/* ip_fast_csum() is an inline function from net/inet/ip.h/checksum.h */
-	iph->check = 0;
-	iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
-
-#ifdef TUNNEL_DEBUG
-printk("New IP Header....\n");
-print_ip(iph);
-#endif
-	/* Now send the packet on its way */
-#ifdef TUNNEL_DEBUG
-	printk("tunnel: calling ip_forward()\n");
-#endif
-	if(ip_forward(skb2, dev, 0, iph->daddr))
-		kfree_skb(skb2, FREE_WRITE);
-
- 
-#ifdef TUNNEL_DEBUG
-	printk("Packet sent through tunnel interface!\n");
-#endif
-	/* Record statistics */
-	stats->tx_packets++;
-
-#ifdef TUNNEL_DEBUG
-	printk("tunnel: Updated usage statistics.\n");
-#endif
-	dev->tbusy=0;
-	return 0;
-}
-
-static struct enet_statistics *
-tunnel_get_stats(struct device *dev)
-{
-	return((struct enet_statistics*) dev->priv);
-}
-
-#ifdef MODULE
-
-static int tunnel_probe(struct device *dev)
-{
-	tunnel_init(dev);
-	return 0;
-}
-
-static struct device dev_tunnel = {
-	"tunl0\0   ", 
-		0, 0, 0, 0,
-	 	0x0, 0,
-	 	0, 0, 0, NULL, tunnel_probe };
-
-int init_module(void)
-{
-	/* Find a name for this unit */
-	int ct= 1;
-	
-	while(dev_get(dev_tunnel.name)!=NULL && ct<100)
-	{
-		sprintf(dev_tunnel.name,"tunl%d",ct);
-		ct++;
-	}
-	
-#ifdef TUNNEL_DEBUG
-	printk("tunnel: registering device %s\n", dev_tunnel.name);
-#endif
-	if (register_netdev(&dev_tunnel) != 0)
-		return -EIO;
-	return 0;
-}
-
-void cleanup_module(void)
-{
-	unregister_netdev(&dev_tunnel);
-	kfree_s(dev_tunnel.priv,sizeof(struct enet_statistics));
-	dev_tunnel.priv=NULL;
-}
-#endif /* MODULE */
diff -u --recursive --new-file v1.3.70/linux/drivers/net/wavelan.c linux/drivers/net/wavelan.c
--- v1.3.70/linux/drivers/net/wavelan.c	Sat Mar  2 10:43:33 1996
+++ linux/drivers/net/wavelan.c	Mon Mar  4 09:16:36 1996
@@ -2023,7 +2023,7 @@
 	unsigned long	x;
 
 	if (wavelan_debug > 0)
-		printk("%s: ->wavelan_set_multicast_list(dev=0x%x)", dev->name, dev);
+		printk("%s: ->wavelan_set_multicast_list(dev=%p)", dev->name, dev);
 
 	lp = (net_local *)dev->priv;
 
diff -u --recursive --new-file v1.3.70/linux/drivers/scsi/ultrastor.c linux/drivers/scsi/ultrastor.c
--- v1.3.70/linux/drivers/scsi/ultrastor.c	Sat Mar  2 10:43:41 1996
+++ linux/drivers/scsi/ultrastor.c	Mon Mar  4 09:16:40 1996
@@ -640,14 +640,14 @@
     static char buf[64];
 
     if (config.slot)
-      sprintf(buf, "UltraStor 24F SCSI @ Slot %u IRQ%u\n",
+      sprintf(buf, "UltraStor 24F SCSI @ Slot %u IRQ%u",
 	      config.slot, config.interrupt);
     else if (config.subversion)
-      sprintf(buf, "UltraStor 34F SCSI @ Port %03X BIOS %05X IRQ%u\n",
+      sprintf(buf, "UltraStor 34F SCSI @ Port %03X BIOS %05X IRQ%u",
 	      config.port_address, (int)config.bios_segment,
 	      config.interrupt);
     else
-      sprintf(buf, "UltraStor 14F SCSI @ Port %03X BIOS %05X IRQ%u DMA%u\n",
+      sprintf(buf, "UltraStor 14F SCSI @ Port %03X BIOS %05X IRQ%u DMA%u",
 	      config.port_address, (int)config.bios_segment,
 	      config.interrupt, config.dma_channel);
     return buf;
@@ -884,7 +884,7 @@
 	printk("Ux4F: abort while completed command pending\n");
 	restore_flags(flags);
 	cli();
-	ultrastor_interrupt(0, NULL);
+	ultrastor_interrupt(0, NULL, NULL);
 	restore_flags(flags);
 	return SCSI_ABORT_SUCCESS;  /* FIXME - is this correct? -ERY */
       }
diff -u --recursive --new-file v1.3.70/linux/drivers/sound/.version linux/drivers/sound/.version
--- v1.3.70/linux/drivers/sound/.version	Wed Feb 28 11:50:06 1996
+++ linux/drivers/sound/.version	Fri Mar  1 19:20:17 1996
@@ -1,2 +1,2 @@
-3.5-beta7
+3.5-beta10
 0x030505
diff -u --recursive --new-file v1.3.70/linux/drivers/sound/CHANGELOG linux/drivers/sound/CHANGELOG
--- v1.3.70/linux/drivers/sound/CHANGELOG	Wed Feb 28 11:50:06 1996
+++ linux/drivers/sound/CHANGELOG	Fri Mar  1 19:20:16 1996
@@ -1,5 +1,19 @@
-Changelog for version 3.5-beta7
--------------------------------
+Changelog for version 3.5-beta10
+--------------------------------
+
+Since 3.5-beta8
+- Fixed for compatibility with Linux 1.3.70 and later.
+- Changed boot time passing of 16 bit DMA channel number to SB driver.
+
+Since 3.5-beta8
+- Minor changes
+
+Since 3.5-beta7
+- enhancements to configure program (by Jeff Tranter):
+  - prompts are in same format as 1.3.x Linux kernel config program
+  - on-line help for each question
+  - fixed some compile warnings detected by gcc/g++ -Wall
+  - minor grammatical changes to prompts
 
 Since 3.5-beta6
 - Fixed bugs in mmap() support.
@@ -28,8 +42,8 @@
 - Bugfixes.
 - Full duplex audio with MAD16+CS4231 may work now. The driver configures
   SB DMA of MAD16 so that it doesn't conflict with codec's DMA channels.
-  The side effect is that all 8 bit DMA channels (0,1,3) are populated in duplex
-  mode.
+  The side effect is that all 8 bit DMA channels (0,1,3) are populated in 
+  duplex mode.
 
 Since 3.5-alpha9
 - Bugfixes (mostly in Jazz16 and ESS1688/688 supports).
diff -u --recursive --new-file v1.3.70/linux/drivers/sound/Config.std linux/drivers/sound/Config.std
--- v1.3.70/linux/drivers/sound/Config.std	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sound/Config.std	Fri Mar  1 19:20:16 1996
@@ -0,0 +1,12 @@
+#
+# Sound driver configuration
+#
+#--------
+# There is another confic script which is compatible with rest of
+# the kernel. It can be activated by running 'make mkscript' in this
+# directory. Please note that this is an _experimental_ feature which
+# doesn't work with all cards (PSS, SM Wave, AudioTriX Pro).
+#--------
+#
+$MAKE -C drivers/sound config || exit 1
+
diff -u --recursive --new-file v1.3.70/linux/drivers/sound/Makefile linux/drivers/sound/Makefile
--- v1.3.70/linux/drivers/sound/Makefile	Wed Feb 28 11:50:06 1996
+++ linux/drivers/sound/Makefile	Sat Mar  2 13:09:26 1996
@@ -58,6 +58,7 @@
 CC	= gcc
 HOSTCC	= gcc
 CFLAGS	= -D__KERNEL__ -DMODULE -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -m486
+USE_DEPEND=y
 else
 include $(TOPDIR)/Rules.make
 endif
@@ -69,7 +70,7 @@
 
 clean:
 	rm -f core core.* *.o *.a tmp_make *~ x y z *%
-	rm -f configure sound_stub.c objects/*.o
+	rm -f configure sound_stub.c objects/*.o 
 
 indent:
 	for n in *.c;do echo indent $$n;indent $$n;done
@@ -144,9 +145,11 @@
 	ln -fs `pwd`/sound.o $(TOPDIR)/modules/sound.o
 
 
+ifdef USE_DEPEND
 #
 # include a dependency file if one exists
 #
 ifeq (.depend,$(wildcard .depend))
 include .depend
+endif
 endif
diff -u --recursive --new-file v1.3.70/linux/drivers/sound/Readme linux/drivers/sound/Readme
--- v1.3.70/linux/drivers/sound/Readme	Wed Feb 28 11:50:06 1996
+++ linux/drivers/sound/Readme	Fri Mar  1 19:20:14 1996
@@ -1,109 +1,40 @@
+Version 3.5-beta10 release notes
+--------------------------------
+
+Most up to date information about this driver is available from 
+http://personal.eunet.fi/pp/voxware.
+
 
-Version 3.5-beta6 release notes
--------------------------------
 
-IMPORTANT! This version of the driver is compatible only with Linux versions
-	   1.3.59 to 1.3.6x. It may work with few earlier ones as a loadable
-	   module but...
-
-	   This is a BETA test version. Most known bugs should have been fixed.
-	   However it's possible that there are still bugs. Please report them
-	   to me ASAP so that they can be fixed before Linux 1.4. But look
-	   at the web page (see below) before sending me a bug report. 
-
-	   Crashing with GUS should be fixed now.
-	   Recording is still disabled with ESS1688/688 cards since it
-	   causes a crash.
 
 Please read the SOUND-HOWTO (available from sunsite.unc.edu and other Linux ftp 
 sites). It gives instructions about using sound with Linux. It's bit out of
 date but still very useful. Information about bug fixes and such things
 is available from the web page (see below).
 
-*****************************************************************
-* NEW! Driver's home page is http://personal.eunet.fi/pp/voxware*
-* The file Readme.cards contains card specific instructions     *
-* about configuring various cards.				*
-*****************************************************************
-
-There are some programming information (little bit old) in the
-Hacker's Guide 
-(ftp://nic.funet.fi/pub/OS/Linux/ALPHA/sound/snd-sdk-doc-0.1.ps.gz).
-Believe me: The file is really there. The directory is just hidden and
-you have to cd into it before the file is visible. Note: This directory
-was accidently removed some time ago but it's now back.
-
-I have got many patches from various persons during last year. Some of
-them are still on my mailbox and they should be included in versions
-after v3.5 (I will not add aditional features before v3.5 is ready).
+New Programmer's Guide is currently under work (Feb/March 96). Please
+check http://personal.eunet.fi/pp/voxware for more info.
 
    ====================================================
--  THIS VERSION ____REQUIRES____ Linux 1.3.64 OR LATER.
+-  THIS VERSION ____REQUIRES____ Linux 1.3.70 OR LATER.
    ====================================================
 
--  THIS VERSION MAY NOT WORK WITH Linux VERSIONS RELEASED
-   AFTER end of Feb 1996. If this version doesn't compile with
-   your kernel version, please use the sound driver version
-   included in your kernel.
-
-You may need the snd-util-3.5.tar.gz and snd-data-0.1.tar.Z
-packages to use this driver. They should be in the same
-ftp site or BBS from where you got this driver. For
-example at nic.funet.fi:pub/OS/Linux/*.
+It's very likely that this driver version is incompatible with
+Linux versions later than 2.x.
+
+Packages "snd-util-3.5.tar.gz" and "snd-data-0.1.tar.Z"
+contain usefull utilities to be used with this driver.
 
 If you are looking for the installation instructions, please
-look at linux/Readme.
+look at Readme.linux.
 
 Supported soundcards
 --------------------
 
-Gravis Ultrasound (GUS)
-GUS MAX
-GUS with the 16 bit sampling daughtercard
-GUS ACE
-GUS PnP support should be available around May 1996.
-PAS16
-Windows Sound System compatible soundcards
-ECHO-PSS (cards based on the PSS architecture by Analog Devices.
-	Including Orchid SW32, Cardinal DSP16 among others).
-		(NOTE! WSS mode may not work (DMA channel setup problem)).
-MediaTriX AudioTriX Pro (OPL4 and the optional effect daughtercard
-	require special initialization. There is a program (setfx) in
-	the snd-util-3.0.tar.gz package which does it).
-Ensoniq SoundScape & SoundScape Elite
-Ensonig SoundScape PnP not supported yet (summer 1996?)
-MV Jazz16 based soundcards (ProSonic, 3D etc).
-SoundMan Wave
-Mozart (OAK OTI-601 interface chip) based soundcards.
-MAD16 (an interface chip by OPTi) based soundcards (TB Tropez ???).
-(NOTE! The MAD16 looks similar to the Mozart chip. It could be a good
-idea to configure MAD16 cards as Mozart ones. The MAD16 driver doesn't set
-up MPU401 which the Mozart one does.
-CS4232 based cards such as AcerMagic S23.
-ESS ES1688 based soundcards.
-
-
-In addition all Sound Blaster models and clones (up to AWE32) work if
-you want to use them. SB16/SB32/AWE32 PnP models don't work yet. See the web
-page for more info.
-
-The Emu synthesizer chip of AWE32 will not be supported soon. The same is
-true with the ASP chip also. Creative Technology will not release detailed
-information about them so it's not possible to support them.
-
-===========================================================================
-If your card is compatible with SB, MPU401 or Windows Sound System, it
-may work with the driver even if it's not listed in the above list. In this
-case it may require initialization using DOS. Just start DOS and cold
-boot to Linux (etc.) by hitting ctrl-alt-del. 
-===========================================================================
-
-Compatibility with the earlier versions
----------------------------------------
-
-There have been some changes in soundcard.h after v2.5 of the driver
-(v2.90 is compatible with this one). Binaries compiled with this version
-of soundcard.h will not work with v2.0 and earlier.
+See Readme.cards.
+
+Please check http://personal.eunet.fi/pp/voxware if you don't find
+your soundcard there.
 
 Contributors
 ------------
@@ -225,29 +156,15 @@
 It's possible that there are bugs in the sound driver but 99% of the problems
 reported to me are caused by somehow incorrect setup during "make config".
 
-For owners of TI TM4000M notebooks
-----------------------------------
-
-There appears to be some kind of conflict between the sound support
-(MV Jazz), mouse port and the sound driver. You could try to configure kernel
-with the C&T 82C710 mouse port support disabled.
+Best regards,
 
 Hannu
 
-Regards,
-
 Hannu Savolainen
-hannu@voxware.pp.fi
+hannu@voxware.pp.fi	
+(Please check http:/personal.eunet.fi/pp/voxware before mailing me).
 
 Snail mail:	Hannu Savolainen
 		Hiekkalaiturintie 3 A 8
 		00980 Helsinki
 		Finland
-
-NOTE!	I propably don't answer to Snail mail or FAX messages. Sending answer
-	to each of them is simply too expensive and time consuming. However I
-	try to reply every email message I get (within a week). If you don't 
-	get response, please check how your address is written in the message
-	header. I can't answer if I don't have a valid reply address.
-
-Sound driver's home page is http://personal.eunet.fi/pp/voxware
diff -u --recursive --new-file v1.3.70/linux/drivers/sound/Readme.cards linux/drivers/sound/Readme.cards
--- v1.3.70/linux/drivers/sound/Readme.cards	Wed Feb 28 11:50:06 1996
+++ linux/drivers/sound/Readme.cards	Fri Mar  1 19:20:15 1996
@@ -1,8 +1,10 @@
 Configuring version 3.5 (for Linux) with some most common soundcards
 ====================================================================
 
-NOTE! This document may contain some error. Please inform me
-      if you find any mistakes.
+IMPORTANT!	This document covers only cards that were "known" when
+		this driver version was released. Please look at
+		http://personal.eunet.fi/pp/voxware for info about
+		cards introduced recently.
 
 Cards that are not (fully) supported by this driver
 ---------------------------------------------------
@@ -164,10 +166,14 @@
 	Support for this card is made by Riccardo Faccetti
 	(riccardo@cdc8g5.cdc.polimi.it). See aedsp16.c for more info.
 	
-Crystal CS4232 based cards such as AcerMagic S23 and many PC motherboards.
+Crystal CS4232 based cards such as AcerMagic S23 and many PC motherboards
+	(Compaq, HP, Intel, ...).
 	CS4232 is a PnP multimedia chip which contains a CS3231A codec,
 	SB and MPU401 emulations. There is support for OPL3 too.
-	(Unfortunately the MPU401 mode doesn't work).
+	This is a temporary driver which uses the chip in non PnP mode
+	(The final driver should be included in version 3.6 of the driver).
+	Unfortunately the MPU401 mode doesn't work. The chip may also stop
+	working after it has been used few times (only cold boot resets it).
 
 Turtle Beach Maui and Tropez
 	This driver version supports sample, patch and program loading commands
@@ -527,11 +533,16 @@
 just one 8 bit DMA channel. Recording will not work with one DMA
 channel if it's a 16 bit one.
 
+Microphone input of GUS MAX is connected to mixer in little bit nonstandard
+way. There is actually two microphone volume controls. Normal "mic" controls
+only recording level. Mixer control "speaker" is used to control volume of
+microphone signal connected directly to line/speaker out. So just decrease
+volume of "speaker" if you have problems with microphone feedback.
 
 GUS ACE works too but any attempt to record or to use the MIDI port
 will fail.
 
-GUS PnP (with RAM) is supported but it needs to be initialized using
+GUS PnP (with RAM) is partially supported but it needs to be initialized using
 DOS before booting Linux. This may fail on machines having PnP BIOS.
 
 MPU401 and Windows Sound System
@@ -688,13 +699,10 @@
 It can be used by enabling the stand alone MPU401 support but you have
 to initialize it by using the MS-DOS SNDSETUP program.
 
-There are some other OPTi chips which may be used in soundcards such as
-82C930 and MAC32. These chips are not supported by the driver yet. Please
-contact me if you have a soundcard which uses these chips.
-
 Some MAD16 based cards may cause feedback, whistle or terrible noise if the
 line3 mixer channel is turned too high. This happens at least with Shuttle
-Sound System.
+Sound System. Current driver versions set volume of line3 low enough so
+this should not be a problem.
 
 If you have a MAD16 card which have an OPL4 (FM + Wave table) synthesizer
 chip (_not_ an OPL3), you have to apped line containing #define MAD16_OPL4
diff -u --recursive --new-file v1.3.70/linux/drivers/sound/Readme.linux linux/drivers/sound/Readme.linux
--- v1.3.70/linux/drivers/sound/Readme.linux	Wed Feb 14 14:37:13 1996
+++ linux/drivers/sound/Readme.linux	Fri Mar  1 19:20:14 1996
@@ -3,161 +3,39 @@
 
 IMPORTANT!	Read this if you are installing a separately
 		distributed version of this driver.
+
 		Check that your kernel version works with this
 		release of the driver (see Readme). Also verify
 		that your current kernel version doesn't have more
-		recent sound driver version than this one.
-
-- Since you are reading this, you have already installed the files so
-  let's skip this step. To be serious, the sound driver belongs
-  to linux/drivers/sound. 
+		recent sound driver version than this one. IT'S HIGHLY
+		RECOMMENDED THAT YOU USE THE SOUND DRIVER VERSION THAT
+		IS DISTRIBUTED WITH KERNEL SOURCES.
+
+- When installing separately distributed sound driver you should first
+  read the above notice. Then try to find proper directory where and how
+  to install the driver sources. You should not try to install a separately
+  distributed driver version if you are not able to find the proper way
+  yourself (in this case use the version that is distributed with kernel
+  sources). Remove old version of linux/drivers/sound directory before
+  installing new files.
 
 - To build the device files you need to run the enclosed shell scrip 
-  (see below).
-
-- If you are installing a separately distributed version, copy the
-  soundcard.h to /usr/include/linux. It may contain some new stuff.
-
-- Copy the sound/ultrasound.h  to /usr/include/sys
-  (Remove the old one from /usr/include/sys /usr/include/linux first).
-
-- Ensure you have the following symlink:
-  ln -s /usr/include/linux/soundcard.h /usr/include/sys/soundcard.h
+  (see below). You need to do this only when installing sound driver
+  first time or when upgrading to much recent version than the earlier
+  one.
 
 - Configure and compile Linux as normally (remember to include the
-  sound support during "make config").
+  sound support during "make config"). Please refer to kernel documentation
+  for instructions about configuring and compiling kernel. File Readme.cards
+  contains card spesific instructions for configuring this driver for
+  use with various soundcards.
 
 Boot time configuration (using lilo and insmod) 
 -----------------------------------------------
 
-NOTE!	This information is little bit obsolete since it doesn't cover
- 	some cards recently added to the driver. The following text
-	describes parameters just for some older cards. In addition
-	this method will not work with cards which have more than one
-	DMA channel or if the driver number is bigger than 15. (Driver
-	numbers are defined in soundcard.h).
-
--------------------------------------------------------------------
-NOTE2!	This method to configure the sound driver is not normally
-	required. All configuration information is entered when the
-	kernel/driver is compiled. This method just gives a way
-	to override some configuration parameters during boot.
-
-	So THE METHOD PRESENTED IN THIS CHAPTER IS NORMALLY COMPLETELY
-	USELESS. DON'T USE IT UNLESS YOU HAVE A VERY SPECIAL REASON TO
-	DO THAT.
-
-	!!!!!!!!!!!!!!!!!!!! PLEASE NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-	!!! Finding a working sound= command line is a difficult   !!!
-	!!! and timeconsuming task. For this reason I will not     !!!
-	!!! answer to messages asking about how to do it. So       !!!
-	!!! please don't use this method if you have any problems  !!!
-	!!! with it.                                               !!!
-	!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
--------------------------------------------------------------------
-
-This version of the sound driver has capability to accept the configuration
-parameters from the boot loader (for example lilo). By default the 
-driver is booted using the parameters given before compiling the driver
-('make config' or 'make soundconf'). If the kernel is booted using lilo and
-the boot command is given manually, it's possible to give the configuration
-parameters on the command line. Just hold down the <Alt> key when lilo
-starts. Then give the boot command manually and append a sound= argument
-to the boot command line. For example:
-
-lilo boot: linux sound=0x222071,0x138800
-
-The sound= argument could contain several configuration entries separated by a
-comma. Each option gives the configuration for one sound device.
-Give the options in the order given below. Other order of use is undefined.
-Each option is encoded as the following:
-
-	0xTaaaId, where
-          ||  ||
-          ||  |+----   d = DMA channel (0, 1, 3, 5, 6 or 7)
-          ||  +-----   I = IRQ (HEXADECIMAL!!! 1=1, ..., 9=9, 10=a, ..., 15=f)
-          |+-------- aaa = I/O address (hexadecimal)
-	  +----------  T = device type  1=FM Synth (YM3812 or OPL3)
-					2=SoundBlaster (1.0 to 2.0, Pro, 16)
-					3=ProAudioSpectrum16
-					4=Gravis UltraSound
-					5=MPU-401 UART midi
-					6=SB16 (16 bit DMA number)
-					7=SB16 Midi (MPU-401 emulation)
-			(There are some new ones also but they are currently
-			not documented. The card numbers are in soundcard.h).
-
-These are the configuration templates for various soundcards:
-
-	0)	Disable the sound driver
-		
-		sound=0
-
-	1)	AdLib
-
-		sound=0x138800
-
-	2)	SoundBlaster family and compatibles
-
-		sound=0x2220Id,0x138800	  (remember to set the IRQ and DMA)
-	or if you have SB16 or SB16ASP, you have to use the following:
-	        (use the same IRQ (the I colums) in all three places. The
-	         the D is the 16 bit DMA channel (5 to 7) and the d is 
-	         the 8 bit one (1 or 3). The X is the 2nd digit of the
-	         midi IO address (3 or 0)).
-		sound=0x2220Id,0x6220ID,0x73X0I0,0x138800
-
-	3)	ProAudioSpectrum16, ProAudioStudio16, Logitech Soundman16 etc.
-
-		sound=0x3388Id,0x2220Id,0x138800 (set the DMAs and IRQs)
-         
-	4)	Gravis UltraSound
-
-		sound=0x42X0Id	(X is 1, 2, 3 or 4. Set the DMA and IRQ)
-	
-	5)	MPU-401
-
-		sound=0x5aaaI0
-
-If you have more than one soundcards, you have to concatenate the options
-for each of the cards. There cannot be more than one sound= argument in the
-command line. For example use "sound=0x5aaaI0,0x138800" if you have AdLib
-and MPU-401 on your system. 
-If there are two or more sound= arguments
-in the boot command line, just the last one takes effect. The earlier ones
-will be ignored silently.
-
-The boot time configuration feature is intended mainly for distributors of
-precompiled kernels. When this feature is used, drivers for all of the
-cards have to be enabled before compiling the driver. The configurator program
-doesn't enable MPU-401 when the full driver option is selected. It must be
-enabled by uncommenting "#define EXCLUDE_MPU401" in the sound/local.h.
-
-Important note!
-
-The sound driver is enabled by default. If the kernel is booted without
-using the sound=0 option, the sound driver is initialized using the compile
-time parameters. This could be dangerous (specially if the MPU-401 driver
-is enabled with I/O address 0x330 (used by AHA-1542 also)). If you want to
-compile the driver to be inactive by default, you have to append a
-#define SND_DEFAULT_ENABLE	0
-to the sound/local.h before compiling the driver.
-
-Remember to check that the sound setup routine is included in the 
-bootparams structure in linux/init/main.c. It should contain the following
-lines:
-
-#ifdef CONFIG_SOUND
-	{ "sound=", sound_setup },
-#endif
-
-In case these lines were not there, you have to insert them (the driver works
-without them but it's not possible to give the boot time parameters for the
-sound driver). Add also the following line somewhere near the beginning of
-linux/init/main.c:
-
-extern void sound_setup(char *str, int *ints);
+This information has been removed. Too many users did't believe
+that it's really not necessary to use this method. Please look at
+Readme of sound driver version 3.0.1 if you still want to use this method.
 
 Problems
 --------
@@ -171,33 +49,25 @@
 and look at the output. It should display some usefull info about the
 driver configuration. If there is no /dev/sndstat 
 (/dev/sndstat: No such file or directory), ensure that you have executed the
-soundinstall script (at the end of this file). The message: 
-/dev/dsp: No such device means that you don't have the sound driver installed
-on your kernel or the driver version is earlier than 1.99.6.
+soundinstall script (at the end of this file).
 
+Common error messages:
 
 - /dev/???????: No such file or directory.
 Run the script at the end of this file.
 
 - /dev/???????: No such device.
-You have not booted with a kernel containing the driver or the I/O address
-configuration doesn't match your hardaware. 
-
-- The module player (str) plays just a second and then stops completely.
-You have incorrect IRQ settings (usual with SB cards).
+You are not running kernel which contains the sound driver. When using
+modularized sound driver this error means that the sound driver is not
+loaded.
+
+- /dev/????: No such device or address.
+Sound driver didn't detect suitable card when initializing. Please look at
+Readme.cards for info about configuring the driver with your card. Also
+check for possible boot (insmod) time error messages in /var/adm/messages.
 
-- There is pauses in the playback of the module player (str).
-The str program requires more than 40% of the speed of a 486/50 to play
-without pauses at 44 kHz speed. A 386/25 can hardly play faster than 22 kHz.
-You should use lower speed (-s speed), buy a faster computer or a Gravis 
-UltraSound card. (If you already have GUS, you should use gmod and not the
-str). If the DSP_BUFFSIZE in the sound/local.h is less than (nr_channels*
-speed_in_Hz * (bits/8))/2, it could explain the pausing problem. Also check
-that the turbo swich is on and don't run applications like weather forecasting
-on background. Sometimes (very rarely) an IRQ conflict can cause similar
-problems with SB cards.
-If you want to play modules on a 386sx while recompiling the world, buy a GUS.
-It runs without burning your CPU.
+- Other messages or problems
+Please check http://personal.eunet.fi/pp/voxware for more info.
 
 Hannu Savolainen
 hannu@voxware.pp.fi
diff -u --recursive --new-file v1.3.70/linux/drivers/sound/ad1848.c linux/drivers/sound/ad1848.c
--- v1.3.70/linux/drivers/sound/ad1848.c	Sat Mar  2 10:43:42 1996
+++ linux/drivers/sound/ad1848.c	Fri Mar  1 19:20:20 1996
@@ -39,6 +39,9 @@
  */
 #include <linux/config.h>
 
+
+#define DEB(x)
+#define DEB1(x)
 #include "sound_config.h"
 
 #if defined(CONFIG_AD1848)
@@ -151,7 +154,7 @@
 ad_write (ad1848_info * devc, int reg, int data)
 {
   unsigned long   flags;
-  int             timeout = 90000;
+  int             timeout = 900000;
 
   while (timeout > 0 &&
 	 inb (devc->base) == 0x80)	/*Are we initializing */
@@ -178,7 +181,7 @@
    */
 
   timeout = 100000;
-  while (timeout > 0 && inb (devc->base) & 0x80)
+  while (timeout > 0 && inb (devc->base) == 0x80)
     timeout--;
   if (inb (devc->base) & 0x80)
     printk ("ad1848: Auto calibration timed out(1).\n");
@@ -189,7 +192,7 @@
   if (!(ad_read (devc, 11) & 0x20))
     return;
 
-  timeout = 20000;
+  timeout = 40000;
   while (timeout > 0 && ad_read (devc, 11) & 0x20)
     timeout--;
   if (ad_read (devc, 11) & 0x20)
@@ -199,31 +202,11 @@
 static void
 ad_mute (ad1848_info * devc)
 {
-  int             i;
-  unsigned char   prev;
-
-  /*
-     * Save old register settings and mute output channels
-   */
-  for (i = 6; i < 8; i++)
-    {
-      prev = devc->saved_regs[i] = ad_read (devc, i);
-      ad_write (devc, i, prev | 0x80);
-    }
 }
 
 static void
 ad_unmute (ad1848_info * devc)
 {
-  int             i;
-
-  /*
-     * Restore back old volume registers (unmute)
-   */
-  for (i = 6; i < 8; i++)
-    {
-      ad_write (devc, i, devc->saved_regs[i] & ~0x80);
-    }
 }
 
 static void
@@ -440,6 +423,8 @@
   switch (devc->mode)
     {
     case MD_4231:
+    case MD_4231A:
+    case MD_1845:
       devc->supported_devices = MODE2_MIXER_DEVICES;
       break;
 
@@ -584,7 +569,7 @@
   ad1848_trigger (dev, 0);
   restore_flags (flags);
 /*
- * Mute output until the playback really starts. This decreases clicking.
+ * Mute output until the playback really starts. This decreases clicking (hope so).
  */
   ad_mute (devc);
 
@@ -597,7 +582,7 @@
   unsigned long   flags;
   ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;
 
-  DDB (printk ("ad1848_close(void)\n"));
+  DEB (printk ("ad1848_close(void)\n"));
 
   save_flags (flags);
   cli ();
@@ -1393,7 +1378,7 @@
    */
   static int      init_values[] =
   {
-    0xa8, 0xa8, 0x08, 0x08, 0x08, 0x08, 0x80, 0x80,
+    0xa8, 0xa8, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
     0x00, 0x0c, 0x02, 0x00, 0x8a, 0x01, 0x00, 0x00,
 
   /* Positions 16 to 31 just for CS4231 */
@@ -1525,13 +1510,11 @@
       if (!share_dma)
 	{
 	  if (sound_alloc_dma (dma_playback, "Sound System"))
-	    printk ("ad1848.c: Can't allocate DMA%d for playback\n",
-		    dma_playback);
+	    printk ("ad1848.c: Can't allocate DMA%d\n", dma_playback);
 
-	  if (dma_capture != dma_playback && dma_capture != -1)
+	  if (dma_capture != dma_playback)
 	    if (sound_alloc_dma (dma_capture, "Sound System (capture)"))
-	      printk ("ad1848.c: Can't allocate DMA%d for capture\n",
-		      dma_capture);
+	      printk ("ad1848.c: Can't allocate DMA%d\n", dma_capture);
 	}
 
       /*
@@ -1707,16 +1690,26 @@
 
   if ((tmp = inb (hw_config->io_base + 3)) == 0xff)	/* Bus float */
     {
+      int             ret;
+
       DDB (printk ("I/O address is inactive (%x)\n", tmp));
-      return 0;
+      if (!(ret = ad1848_detect (hw_config->io_base + 4, NULL, hw_config->osp)))
+	return 0;
+      return 1;
     }
   if ((tmp & 0x3f) != 0x04 &&
       (tmp & 0x3f) != 0x0f &&
       (tmp & 0x3f) != 0x00)
     {
+      int             ret;
+
       DDB (printk ("No MSS signature detected on port 0x%x (0x%x)\n",
 		   hw_config->io_base, inb (hw_config->io_base + 3)));
-      return 0;
+      DDB (printk ("Trying to detect codec anyway but IRQ/DMA may not work\n"));
+      if (!(ret = ad1848_detect (hw_config->io_base + 4, NULL, hw_config->osp)))
+	return 0;
+
+      return 1;
     }
 
   if (hw_config->irq > 11)
diff -u --recursive --new-file v1.3.70/linux/drivers/sound/audio.c linux/drivers/sound/audio.c
--- v1.3.70/linux/drivers/sound/audio.c	Wed Feb 28 11:50:07 1996
+++ linux/drivers/sound/audio.c	Fri Mar  1 19:20:22 1996
@@ -51,7 +51,7 @@
 static int      local_conversion[MAX_AUDIO_DEV];
 
 static int
-set_format (int dev, long fmt)
+set_format (int dev, int fmt)
 {
   if (fmt != AFMT_QUERY)
     {
@@ -80,7 +80,7 @@
 audio_open (int dev, struct fileinfo *file)
 {
   int             ret;
-  long            bits;
+  int             bits;
   int             dev_type = dev & 0x0f;
   int             mode = file->mode & O_ACCMODE;
 
diff -u --recursive --new-file v1.3.70/linux/drivers/sound/configure.c linux/drivers/sound/configure.c
--- v1.3.70/linux/drivers/sound/configure.c	Wed Feb 28 11:50:07 1996
+++ linux/drivers/sound/configure.c	Fri Mar  1 19:27:25 1996
@@ -37,6 +37,8 @@
 #include <stdio.h>
 #include <unistd.h>
 #include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
 
 #define B(x)	(1 << (x))
 
@@ -176,12 +178,12 @@
   "Support for MAD16 and/or Mozart based cards",
   "Support for Crystal CS4232 based (PnP) cards",
   "Support for Turtle Beach Wave Front (Maui, Tropez) synthesizers",
-  "Support for PnP soundcards (_EXPERIMENTAL_)",
+  "Support for PnP sound cards (_EXPERIMENTAL_)",
 
   "SoundBlaster Pro support",
   "SoundBlaster 16 support",
   "Audio Excel DSP 16 initialization support",
-  "/dev/dsp and /dev/audio supports (usually required)",
+  "/dev/dsp and /dev/audio support",
   "This should not be asked",
   "MIDI interface support",
   "This should not be asked",
@@ -190,6 +192,99 @@
   "Is the sky really falling"
 };
 
+/* help text for each option */
+char           *help[] =
+{
+  "Enable this option only if you have a Pro Audio Spectrum 16,\n"
+  "Pro Audio Studio 16, or Logitech SoundMan 16. Don't enable this if\n"
+  "you have some other card made by MediaVision or Logitech as\n"
+  "they are not PAS16 compatible.\n",
+
+  "Enable this if you have an original SoundBlaster card made by\n"
+  "Creative Labs or a 100%% hardware compatible clone. For an\n"
+  "unknown card you may want to try this if it claims to be\n"
+  "SoundBlaster compatible.\n",
+
+  "Enable this option if your sound card has a Yamaha OPL2 or OPL3\n"
+  "FM synthesizer chip.\n",
+
+  "Enable this option for any type of Gravis Ultrasound card\n"
+  "including the GUS or GUS MAX.\n",
+
+  "The MPU401 interface is supported by almost all sound cards. However,\n"
+  "some natively supported cards have their own driver for\n"
+  "MPU401. Enabling the MPU401 option with these cards will cause a\n"
+  "conflict. Also enabling MPU401 on a system that doesn't really have a\n"
+  "MPU401 could cause some trouble. It's safe to enable this if you have a\n"
+  "true MPU401 MIDI interface card.\n",
+
+  "This option enables support for MIDI interfaces based on the 6850\n"
+  "UART chip. This interface is rarely found on sound cards.\n",
+
+  "Enable this option if you have an Orchid SW32, Cardinal DSP16 or other\n"
+  "sound card based on the PSS chipset (AD1848 codec, ADSP-2115 DSP chip,\n"
+  "and Echo ESC614 ASIC CHIP).\n",
+
+  "Enable this if you have installed the 16-bit sampling daughtercard on\n"
+  "your GUS card. Do not use if you have a GUS MAX as enabling this option\n"
+  "disables GUS MAX support.\n",
+
+  "Enable this option if you have a Gravis Ultrasound MAX sound\n"
+  "card\n",
+
+  "Enable this option if you have the original Windows Sound System\n"
+  "card made by Microsoft or the Aztech SG 16 Pro or NX16 Pro.\n",
+
+  "Enable this if you have a sound card based on the Ensoniq\n"
+  "Soundscape chipset. Such cards are being manufactured by Ensoniq,\n"
+  "Spea and Reveal (Reveal makes other cards as well).\n",
+
+  "Enable this option if you have the AudioTriX Pro sound card\n"
+  "manufactured by MediaTrix.\n",
+
+  "Enable this if your card has a Mozart (OAK OTI-601) or MAD16 (OPTi\n"
+  "82C928 or 82C929) audio interface chip. These chips are currently\n"
+  "quite common so it's possible that many no-name cards have one of\n"
+  "them. In addition the MAD16 chip is used in some cards made by known\n"
+  "manufacturers such as Turtle Beach (Tropez), Reveal (some models) and\n"
+  "Diamond (latest ones).\n",
+
+  "Enable this if you have a card based on the Crystal CS4232 chip set.\n",
+
+  "Enable this option if you have a Turtle Beach Wave Front, Maui,\n"
+  "or Tropez sound card.\n",
+
+  "Use this option to enable experimental support for cards that\n"
+  "use the Plug and Play protocol.\n",
+
+  "Enable this option if your card is a SoundBlaster Pro or\n"
+  "SoundBlaster 16. It also works with many SoundBlaster Pro clones.\n",
+
+  "Enable this if you have a SoundBlaster 16, including the AWE32.\n",
+
+  "Enable this if you have an Audio Excel DSP16 card. See the file\n"
+  "Readme.aedsp16 for more information.\n",
+
+  "This option enables the A/D and D/A converter (PCM) devices\n"
+  "supported by almost all sound cards.\n",
+
+  "This should not be asked",
+
+  "This enables the dev/midixx devices and access to any MIDI ports\n"
+  "using /dev/sequencer and /dev/music. This option also affects any\n"
+  "MPU401 and/or General MIDI compatible devices.\n",
+
+  "This should not be asked",
+
+  "This enables the Yamaha FM synthesizer chip used on many sound\n"
+  "cards.\n",
+
+  "This enables the /dev/sequencer and /dev/music devices used for\n"
+  "playing computer music.\n",
+
+  "Is the sky really falling"
+};
+
 struct kludge
   {
     char           *name;
@@ -244,11 +339,18 @@
 }
 
 int
-think_positively (int def_answ)
+think_positively (char *prompt, int def_answ, char *help)
 {
   char            answ[512];
   int             len;
 
+response:
+  fprintf (stderr, prompt);
+  if (def_answ)
+    fprintf (stderr, " [Y/n/?] ");
+  else
+    fprintf (stderr, " [N/y/?] ");
+
   if ((len = read (0, answ, sizeof (answ))) < 1)
     {
       fprintf (stderr, "\n\nERROR! Cannot read stdin\n");
@@ -263,6 +365,14 @@
 				 */
     return def_answ;
 
+  if (answ[0] == '?')
+    {				/* display help message */
+      fprintf (stderr, "\n");
+      fprintf (stderr, help);
+      fprintf (stderr, "\n");
+      goto response;
+    }
+
   answ[len - 1] = 0;
 
   if (!strcmp (answ, "y") || !strcmp (answ, "Y"))
@@ -322,7 +432,7 @@
       for (i = 0; i < OPT_LAST; i++)
 	if (mask == B (i))
 	  {
-	    int             j;
+	    unsigned int    j;
 
 	    for (j = 0; j < strlen (choices); j++)
 	      if (choices[j] == '\'')
@@ -343,7 +453,8 @@
 	return;
 
       fprintf (stderr, "\n%s\n", question);
-      fprintf (stderr, "Possible values are: %s\n", choices);
+      if (strcmp (choices, ""))
+	fprintf (stderr, "Possible values are: %s\n", choices);
 
       if (format == FMT_INT)
 	{
@@ -375,7 +486,7 @@
 void
 rebuild_file (char *line)
 {
-  char           *method, *new, *old, *var, *p;
+  char           *method, *next, *old, *var, *p;
 
   method = p = line;
 
@@ -388,7 +499,7 @@
     p++;
   *p++ = 0;
 
-  new = p;
+  next = p;
   while (*p && *p != ' ')
     p++;
   *p++ = 0;
@@ -398,11 +509,11 @@
     p++;
   *p++ = 0;
 
-  fprintf (stderr, "Rebuilding file %s (%s %s)\n", new, method, old);
+  fprintf (stderr, "Rebuilding file `%s' (%s %s)\n", next, method, old);
 
   if (strcmp (method, "bin2hex") == 0)
     {
-      if (!bin2hex (old, new, var))
+      if (!bin2hex (old, next, var))
 	{
 	  fprintf (stderr, "Rebuild failed\n");
 	  exit (-1);
@@ -410,7 +521,7 @@
     }
   else if (strcmp (method, "hex2hex") == 0)
     {
-      if (!hex2hex (old, new, var))
+      if (!hex2hex (old, next, var))
 	{
 	  fprintf (stderr, "Rebuild failed\n");
 	  exit (-1);
@@ -418,8 +529,8 @@
     }
   else
     {
-      fprintf (stderr, "Failed to build '%s' - unknown method %s\n",
-	       new, method);
+      fprintf (stderr, "Failed to build `%s' - unknown method %s\n",
+	       next, method);
       exit (-1);
     }
 }
@@ -432,7 +543,7 @@
 
   FILE           *oldf;
 
-  fprintf (stderr, "Copying old configuration from %s\n", filename);
+  fprintf (stderr, "Copying old configuration from `%s'\n", filename);
 
   if ((oldf = fopen (filename, "r")) == NULL)
     {
@@ -638,74 +749,66 @@
 		  "I/O base for SB",
 		  FMT_HEX,
 		  0x220,
-		  "");
+		  "Check from manual of the card");
 
   ask_int_choice (B (OPT_SB), "SBC_IRQ",
 		  "SoundBlaster IRQ",
 		  FMT_INT,
 		  7,
-		  "");
+		  "Check from manual of the card");
 
   ask_int_choice (B (OPT_SB), "SBC_DMA",
 		  "SoundBlaster DMA",
 		  FMT_INT,
 		  1,
-		  "");
+		  "0, 1 or 3");
 
   ask_int_choice (B (OPT_SB), "SB_DMA2",
-		  "SoundBlaster 16 bit DMA (if required)",
+		"SoundBlaster 16 bit DMA (_REQUIRED_for SB16, Jazz16, SMW)",
 		  FMT_INT,
-		  -1,
+		  5,
 		  "5, 6 or 7");
 
   ask_int_choice (B (OPT_SB), "SB_MPU_BASE",
 		  "MPU401 I/O base of SB16, Jazz16 and ES1688",
 		  FMT_HEX,
 		  0,
-		  "");
+		  "Check from manual of the card");
 
   ask_int_choice (B (OPT_SB), "SB_MPU_IRQ",
 		  "SB MPU401 IRQ (SB16, Jazz16 and ES1688)",
 		  FMT_INT,
 		  -1,
-		  "");
+		  "Check from manual of the card");
 
   ask_int_choice (B (OPT_PAS), "PAS_IRQ",
 		  "PAS16 IRQ",
 		  FMT_INT,
 		  10,
-		  "");
+		  "3, 4, 5, 7, 9, 10, 11, 12, 14 or 15");
 
   ask_int_choice (B (OPT_PAS), "PAS_DMA",
 		  "PAS16 DMA",
 		  FMT_INT,
 		  3,
-		  "");
+		  "0, 1, 3, 5, 6 or 7");
 
   if (selected_options & B (OPT_PAS))
     {
-      fprintf (stderr, "\nEnable Joystick port on ProAudioSpectrum (y/N) ? ");
-      if (think_positively (0))
-	printf ("#define PAS_JOYSTICK_ENABLE\n");
-
-
-      fprintf (stderr, "PAS16 could be noisy with some mother boards\n"
-	       "There is a command line switch (was it :T?)\n"
-	       "in the DOS driver for PAS16 which solves this.\n"
-	       "Don't enable this feature unless you have problems!\n"
-	       "Do you have to use this switch with DOS (Y/n) ?");
-      if (think_positively (0))
+      if (think_positively ("Enable Joystick port on ProAudioSpectrum", 0,
+	"Enable this option if you want to use the joystick port provided\n"
+			    "on the PAS sound card.\n"));
+
+      printf ("#define PAS_JOYSTICK_ENABLE\n");
+
+      if (think_positively ("Enable PAS16 bus clock option", 0,
+       "The PAS16 can be noisy with some motherboards. There is a command\n"
+	"line switch (:T?) in the DOS driver for PAS16 which solves this.\n"
+      "Don't enable this feature unless you have problems and have to use\n"
+			    "this switch with DOS\n"))
 	printf ("#define BROKEN_BUS_CLOCK\n");
-
-      fprintf (stderr, "PAS16 has SoundBlaster emulation. You should disable\n"
-	       "this feature if you have another SB compatible card\n"
-	       "on the machine\n"
-	       "Do you want to disable SB emulation of PAS16 (y/N) ?");
-      if (think_positively (0))
-	printf ("#define DISABLE_SB_EMULATION\n");
     }
 
-
   ask_int_choice (B (OPT_GUS), "GUS_BASE",
 		  "I/O base for GUS",
 		  FMT_HEX,
@@ -717,19 +820,19 @@
 		  "GUS IRQ",
 		  FMT_INT,
 		  15,
-		  "");
+		  "3, 5, 7, 9, 11, 12 or 15");
 
   ask_int_choice (B (OPT_GUS), "GUS_DMA",
 		  "GUS DMA",
 		  FMT_INT,
 		  6,
-		  "");
+		  "1, 3, 5, 6 or 7");
 
   ask_int_choice (B (OPT_GUS), "GUS_DMA2",
 		  "Second DMA channel for GUS",
 		  FMT_INT,
 		  -1,
-		  "");
+		  "1, 3, 5, 6 or 7");
 
   ask_int_choice (B (OPT_GUS16), "GUS16_BASE",
 		  "I/O base for the 16 bit daughtercard of GUS",
@@ -754,13 +857,13 @@
 		  "I/O base for MPU401",
 		  FMT_HEX,
 		  0x330,
-		  "");
+		  "Check from manual of the card");
 
   ask_int_choice (B (OPT_MPU401), "MPU_IRQ",
 		  "MPU401 IRQ",
 		  FMT_INT,
 		  9,
-		  "");
+		  "Check from manual of the card");
 
   ask_int_choice (B (OPT_MAUI), "MAUI_BASE",
 		  "I/O base for Maui",
@@ -880,8 +983,11 @@
     {
       int             reveal_spea;
 
-      fprintf (stderr, "Is your SoundScape card made/marketed by Reveal or Spea? ");
-      reveal_spea = think_positively (0);
+      reveal_spea = think_positively (
+		  "Is your SoundScape card made/marketed by Reveal or Spea",
+				       0,
+		 "Enable if you have a SoundScape card with the Reveal or\n"
+				       "Spea name on it.\n");
       if (reveal_spea)
 	printf ("#define REVEAL_SPEA\n");
 
@@ -1081,7 +1187,7 @@
 
   while (extra_options[i].name != NULL)
     {
-      int             n = 0, j;
+      int             j;
 
       for (j = 0; j < OPT_LAST; j++)
 	if (!(DISABLED_OPTIONS & B (j)))
@@ -1099,8 +1205,7 @@
 int
 main (int argc, char *argv[])
 {
-  int             i, num, full_driver = 1;
-  char            answ[10];
+  int             i, full_driver = 1;
   char            old_config_file[200];
 
   if (getuid () != 0)		/* Not root */
@@ -1136,16 +1241,18 @@
 	}
     }
 
-  fprintf (stderr, "\nConfiguring the sound support\n\n");
+  fprintf (stderr, "\nConfiguring Sound Support\n\n");
 
   if (access (oldconf, R_OK) == 0)
     {
-      fprintf (stderr, "Old configuration exists in %s. Use it (Y/n) ? ",
-	       oldconf);
-      if (think_positively (1))
+      char            str[255];
+
+      sprintf (str, "Old configuration exists in `%s'. Use it", oldconf);
+      if (think_positively (str, 1,
+      "Enable this option to load the previously saved configuration file\n"
+			    "for all of the sound driver parameters.\n"))
 	if (use_old_config (oldconf))
 	  exit (0);
-
     }
 
   printf ("/*\tGenerated by configure. Don't edit!!!!\t*/\n");
@@ -1177,10 +1284,7 @@
 	      {
 		int             def_answ = hw_table[i].default_answ;
 
-		fprintf (stderr,
-			 def_answ ? "  %s (Y/n) ? " : "  %s (y/N) ? ",
-			 questions[i]);
-		if (think_positively (def_answ))
+		if (think_positively (questions[i], def_answ, help[i]))
 		  if (hw_table[i].alias)
 		    selected_options |= B (hw_table[i].alias);
 		  else
@@ -1191,30 +1295,29 @@
 
   if (selected_options & B (OPT_SBPRO))
     {
-      fprintf (stderr, "Do you want support for the mixer of SG NX Pro ? ");
-      if (think_positively (0))
+      if (think_positively (
+			     "Support for the SG NX Pro mixer", 0,
+       "Enable this if you want to support the additional mixer functions\n"
+			  "provided on Sound Galaxy NX Pro sound cards.\n"))
 	printf ("#define __SGNXPRO__\n");
     }
 
   if (selected_options & B (OPT_SB))
     {
-      fprintf (stderr, "Do you want support for the MV Jazz16 (ProSonic etc.) ? ");
-      if (think_positively (0))
+      if (think_positively ("Support for the MV Jazz16 (ProSonic etc.)", 0,
+	  "Enable this if you have an MV Jazz16 or ProSonic sound card.\n"))
 	{
-	  fprintf (stderr, "Do you have SoundMan Wave (y/N) ? ");
-
-	  if (think_positively (0))
+	  if (think_positively ("Do you have SoundMan Wave", 0,
+				"Enable this option of you have the Logitech SoundMan Wave sound card.\n"))
 	    {
 	      printf ("#define SM_WAVE\n");
 
 	    midi0001_again:
-	      fprintf
-		(stderr,
-		 "Logitech SoundMan Wave has a microcontroller which must be initialized\n"
-		 "before MIDI emulation works. This is possible only if the microcode\n"
-		 "file is compiled into the driver.\n"
-		 "Do you have access to the MIDI0001.BIN file (Y/n) ? ");
-	      if (think_positively (1))
+	      if (think_positively (
+			   "Do you have access to the MIDI0001.BIN file", 1,
+				     "The Logitech SoundMan Wave has a microcontroller which must be\n"
+				     "initialized before MIDI emulation works. This is possible only if the\n"
+			   "microcode file is compiled into the driver.\n"))
 		{
 		  char            path[512];
 
@@ -1225,10 +1328,11 @@
 
 		  if (!bin2hex (path, "smw-midi0001.h", "smw_ucode"))
 		    {
-		      fprintf (stderr, "couldn't open %s file\n",
+		      fprintf (stderr, "Couldn't open file %s\n",
 			       path);
-		      fprintf (stderr, "try again with correct path? ");
-		      if (think_positively (1))
+		      if (think_positively ("Try again with correct path", 1,
+					    "The specified file could not be opened. Enter the correct path to the\n"
+					    "file.\n"))
 			goto midi0001_again;
 		    }
 		  else
@@ -1241,19 +1345,16 @@
 	}
     }
 
-  if (selected_options & B (OPT_SBPRO))
+  if (selected_options & B (OPT_SB))
     {
-      fprintf (stderr, "\n\nThe Logitech SoundMan Games supports 44 kHz in stereo\n"
-	       "while the standard SB Pro supports just 22 kHz/stereo\n"
-	       "You have an option to enable the SM Games mode.\n"
-	       "However do enable it only if you are _sure_ that your\n"
-	       "card is a SM Games. Enabling this feature with a\n"
-	       "plain old SB Pro _will_ cause troubles with stereo mode.\n"
-	       "\n"
-	       "DANGER! Read the above once again before answering 'y'\n"
-	       "Answer 'n' in case you are unsure what to do!\n");
-      fprintf (stderr, "Do you have a Logitech SoundMan Games (y/N) ? ");
-      if (think_positively (0))
+      if (think_positively ("Do you have a Logitech SoundMan Games", 0,
+	 "The Logitech SoundMan Games supports 44 kHz in stereo while the\n"
+      "standard SB Pro supports just 22 kHz stereo. You have the option of\n"
+			    "enabling SM Games mode.  However, enable it only if you are sure that\n"
+      "your card is an SM Games. Enabling this feature with a plain old SB\n"
+			    "Pro will cause troubles with stereo mode.\n\n"
+		  "DANGER! Read the above once again before answering 'y'\n"
+			    "Answer 'n' if you are unsure what to do!\n"))
 	printf ("#define SM_GAMES\n");
     }
 
@@ -1266,8 +1367,12 @@
 
       if (selected_options & B (OPT_SBPRO))
 	{
-	  fprintf (stderr, "Do you want support for the Audio Excel SoundBlaster pro mode ? ");
-	  if (think_positively (1))
+
+	  if (think_positively (
+	    "Do you want support for the Audio Excel SoundBlaster Pro mode",
+				 1,
+				 "Enable this option if you want the Audio Excel sound card to operate\n"
+				 "in SoundBlaster Pro mode.\n"))
 	    {
 	      printf ("#define AEDSP16_SBPRO\n");
 	      sel1 = 1;
@@ -1276,8 +1381,12 @@
 
       if ((selected_options & B (OPT_MSS)) && (sel1 == 0))
 	{
-	  fprintf (stderr, "Do you want support for the Audio Excel Microsoft Sound System mode? ");
-	  if (think_positively (1))
+
+	  if (think_positively (
+				 "Do you want support for the Audio Excel Microsoft Sound System mode",
+				 1,
+				 "Enable this option if you want the Audio Excel sound card to operate\n"
+				 "in Microsoft Sound System mode.\n"))
 	    {
 	      printf ("#define AEDSP16_MSS\n");
 	      sel1 = 1;
@@ -1297,12 +1406,9 @@
   if (selected_options & B (OPT_PSS))
     {
     genld_again:
-      fprintf
-	(stderr,
-       "if you wish to emulate the soundblaster and you have a DSPxxx.LD.\n"
-	 "then you must include the LD in the kernel.\n"
-	 "Do you wish to include a LD (Y/n) ? ");
-      if (think_positively (1))
+      if (think_positively ("Do you wish to include an LD file", 1,
+			    "If you want to emulate the SoundBlaster card and you have a DSPxxx.LD\n"
+		      "file then you must include the LD in the kernel.\n"))
 	{
 	  char            path[512];
 
@@ -1313,10 +1419,9 @@
 
 	  if (!bin2hex (path, "synth-ld.h", "pss_synth"))
 	    {
-	      fprintf (stderr, "couldn't open %s as the ld file\n",
-		       path);
-	      fprintf (stderr, "try again with correct path? ");
-	      if (think_positively (1))
+	      fprintf (stderr, "couldn't open `%s' as the LD file\n", path);
+	      if (think_positively ("try again with correct path", 1,
+				    "The given LD file could not opened.\n"))
 		goto genld_again;
 	    }
 	  else
@@ -1339,24 +1444,21 @@
   if (selected_options & B (OPT_TRIX))
     {
     hex2hex_again:
-      fprintf (stderr, "MediaTriX audioTriX Pro has a onboard microcontroller\n"
-	       "which needs to be initialized by downloading\n"
-	       "the code from file TRXPRO.HEX in the DOS driver\n"
-	       "directory. If you don't have the TRXPRO.HEX handy\n"
-	       "you may skip this step. However SB and MPU-401\n"
-	       "modes of AudioTriX Pro will not work without\n"
-	       "this file!\n"
-	       "\n"
-	       "Do you want to include TRXPRO.HEX in your kernel (Y/n) ? ");
 
-      if (think_positively (1))
+      if (think_positively ("Do you want to include TRXPRO.HEX in your kernel",
+			    1,
+	"The MediaTriX AudioTrix Pro has an onboard microcontroller which\n"
+			    "needs to be initialized by downloading the code from the file TRXPRO.HEX\n"
+			    "in the DOS driver directory. If you don't have the TRXPRO.HEX file handy\n"
+			    "you may skip this step. However, the SB and MPU-401 modes of AudioTriX\n"
+			    "Pro will not work without this file!\n"))
 	{
 	  char            path[512];
 
 	  fprintf (stderr,
 		 "Enter the path to your TRXPRO.HEX file (pwd is sound): ");
 	  scanf ("%s", path);
-	  fprintf (stderr, "including HEX file %s\n", path);
+	  fprintf (stderr, "including HEX file `%s'\n", path);
 
 	  if (!hex2hex (path, "trix_boot.h", "trix_boot"))
 	    goto hex2hex_again;
@@ -1365,13 +1467,10 @@
 	}
     }
 
-  if (selected_options & B (OPT_SB))
-    selected_options |= B (OPT_SBPRO) | B (OPT_SB16);
-
   if (!(selected_options & ANY_DEVS))
     {
       printf ("invalid_configuration__run_make_config_again\n");
-      fprintf (stderr, "\n*** This combination is useless. Sound driver disabled!!! ***\n\n");
+      fprintf (stderr, "\n*** This combination is useless. Sound driver disabled!!! ***\n*** You need to enable support for at least one device    ***\n\n");
       exit (0);
     }
 
@@ -1382,7 +1481,6 @@
       else
 	printf ("#undef  CONFIG_%s\n", hw_table[i].macro);
 
-
   printf ("\n");
 
   i = 0;
@@ -1400,8 +1498,8 @@
 
   ask_parameters ();
 
-  printf ("#define SELECTED_SOUND_OPTIONS\t0x%08x\n", selected_options);
-  fprintf (stderr, "The sound driver is now configured.\n");
+  printf ("#define SELECTED_SOUND_OPTIONS\t0x%08lx\n", selected_options);
+  fprintf (stderr, "\nThe sound driver is now configured.\n");
 
 #if defined(SCO) || defined(ISC) || defined(SYSV)
   fprintf (stderr, "Remember to update the System file\n");
@@ -1409,8 +1507,13 @@
 
   if (!old_config_used)
     {
-      fprintf (stderr, "Save copy of this configuration to %s (Y/n)", oldconf);
-      if (think_positively (1))
+      char            str[255];
+
+      sprintf (str, "Save copy of this configuration to `%s'", oldconf);
+      if (think_positively (str, 1,
+	"If you enable this option then the sound driver configuration is\n"
+      "saved to a file. If you later need to recompile the kernel you have\n"
+			  "the option of using the saved configuration.\n"))
 	{
 	  char            cmd[200];
 
@@ -1436,7 +1539,7 @@
     {
       FILE           *sf = fopen (target, "w");
 
-      fprintf (sf, "/* automaticaly generated by configure */\n");
+      fprintf (sf, "/* automatically generated by configure */\n");
       fprintf (sf, "static unsigned char %s[] = {\n", varname);
       while (1)
 	{
@@ -1445,7 +1548,7 @@
 	    break;
 	  if (i != 0 && (i % 10) == 0)
 	    fprintf (sf, "\n");
-	  fprintf (sf, "0x%02x,", c & 0xFFL);
+	  fprintf (sf, "0x%02lx,", c & 0xFFL);
 	  i++;
 	}
       fprintf (sf, "};\n"
diff -u --recursive --new-file v1.3.70/linux/drivers/sound/cs4232.c linux/drivers/sound/cs4232.c
--- v1.3.70/linux/drivers/sound/cs4232.c	Wed Feb 28 11:50:07 1996
+++ linux/drivers/sound/cs4232.c	Fri Mar  1 19:20:25 1996
@@ -88,6 +88,10 @@
   int             base = hw_config->io_base, irq = hw_config->irq;
   int             dma1 = hw_config->dma, dma2 = hw_config->dma2;
 
+  static wait_handle *cs_sleeper = NULL;
+  static volatile struct snd_wait cs_sleep_flag =
+  {0};
+
   osp = hw_config->osp;
 
 /*
@@ -118,12 +122,31 @@
 
   for (n = 0; n < 4; n++)
     {
+      cs_sleep_flag.mode = WK_NONE;
 /*
  * Wake up the card by sending a 32 byte Crystal key to the key port.
  */
       for (i = 0; i < 32; i++)
 	CS_OUT (crystal_key[i]);
 
+
+      {
+	unsigned long   tl;
+
+	if (HZ / 10)
+	  current_set_timeout (tl = jiffies + (HZ / 10));
+	else
+	  tl = (unsigned long) -1;
+	cs_sleep_flag.mode = WK_SLEEP;
+	module_interruptible_sleep_on (&cs_sleeper);
+	if (!(cs_sleep_flag.mode & WK_WAKEUP))
+	  {
+	    if (jiffies >= tl)
+	      cs_sleep_flag.mode |= WK_TIMEOUT;
+	  }
+	cs_sleep_flag.mode &= ~WK_SLEEP;
+      };			/* Delay */
+
 /*
  * Now set the CSN (Card Select Number).
  */
@@ -154,6 +177,24 @@
 
       CS_OUT2 (0x33, 0x01);	/* Activate logical dev 0 */
 
+
+      {
+	unsigned long   tl;
+
+	if (HZ / 10)
+	  current_set_timeout (tl = jiffies + (HZ / 10));
+	else
+	  tl = (unsigned long) -1;
+	cs_sleep_flag.mode = WK_SLEEP;
+	module_interruptible_sleep_on (&cs_sleeper);
+	if (!(cs_sleep_flag.mode & WK_WAKEUP))
+	  {
+	    if (jiffies >= tl)
+	      cs_sleep_flag.mode |= WK_TIMEOUT;
+	  }
+	cs_sleep_flag.mode &= ~WK_SLEEP;
+      };			/* Delay */
+
 /*
  * Initialize logical device 3 (MPU)
  */
@@ -173,12 +214,48 @@
  */
       CS_OUT (0x79);
 
+
+      {
+	unsigned long   tl;
+
+	if (HZ / 5)
+	  current_set_timeout (tl = jiffies + (HZ / 5));
+	else
+	  tl = (unsigned long) -1;
+	cs_sleep_flag.mode = WK_SLEEP;
+	module_interruptible_sleep_on (&cs_sleeper);
+	if (!(cs_sleep_flag.mode & WK_WAKEUP))
+	  {
+	    if (jiffies >= tl)
+	      cs_sleep_flag.mode |= WK_TIMEOUT;
+	  }
+	cs_sleep_flag.mode &= ~WK_SLEEP;
+      };			/* Delay */
+
 /*
  * Then try to detect the codec part of the chip
  */
 
       if (ad1848_detect (hw_config->io_base, NULL, hw_config->osp))
 	return 1;
+
+
+      {
+	unsigned long   tl;
+
+	if (HZ)
+	  current_set_timeout (tl = jiffies + (HZ));
+	else
+	  tl = (unsigned long) -1;
+	cs_sleep_flag.mode = WK_SLEEP;
+	module_interruptible_sleep_on (&cs_sleeper);
+	if (!(cs_sleep_flag.mode & WK_WAKEUP))
+	  {
+	    if (jiffies >= tl)
+	      cs_sleep_flag.mode |= WK_TIMEOUT;
+	  }
+	cs_sleep_flag.mode &= ~WK_SLEEP;
+      };			/* Longer delay */
     }
 
   return 0;
diff -u --recursive --new-file v1.3.70/linux/drivers/sound/dev_table.h linux/drivers/sound/dev_table.h
--- v1.3.70/linux/drivers/sound/dev_table.h	Sat Mar  2 10:43:42 1996
+++ linux/drivers/sound/dev_table.h	Fri Mar  1 19:20:09 1996
@@ -26,7 +26,6 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
-#include <linux/config.h>
 
 
 #ifndef _DEV_TABLE_H_
@@ -411,12 +410,7 @@
 #endif
 
 #ifdef CONFIG_MSS
-	/* always define full MSS even for DEC Alphas, just in case... */
 		{SNDCARD_MSS, {MSS_BASE, MSS_IRQ, MSS_DMA, -1}, SND_DEFAULT_ENABLE},
-#	ifdef __alpha__
-	/* MSS without IRQ/DMA config registers (for DEC Alphas) */
-		{SNDCARD_PSEUDO_MSS, {MSS_BASE, MSS_IRQ, MSS_DMA, -1}, SND_DEFAULT_ENABLE},
-#	endif
 #	ifdef MSS2_BASE
 		{SNDCARD_MSS, {MSS2_BASE, MSS2_IRQ, MSS2_DMA, -1}, SND_DEFAULT_ENABLE},
 #	endif
@@ -430,7 +424,10 @@
 #	ifndef SBC_DMA
 #		define SBC_DMA		1
 #	endif
-		{SNDCARD_SB, {SBC_BASE, SBC_IRQ, SBC_DMA, -1}, SND_DEFAULT_ENABLE},
+#	ifndef SB_DMA2
+#		define SB_DMA2		-1
+#	endif
+		{SNDCARD_SB, {SBC_BASE, SBC_IRQ, SBC_DMA, SB_DMA2}, SND_DEFAULT_ENABLE},
 #endif
 #if defined(CONFIG_MAUI) 
 		{SNDCARD_MAUI, {MAUI_BASE, MAUI_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
@@ -451,9 +448,6 @@
 #endif
 
 #if defined(CONFIG_SB) 
-#if defined(CONFIG_AUDIO) && defined(SB_DMA2)
-		{SNDCARD_SB16, {SBC_BASE, SBC_IRQ, SB_DMA2, -1}, SND_DEFAULT_ENABLE},
-#endif
 #if defined(CONFIG_MIDI) && defined(SB_MPU_BASE)
 		{SNDCARD_SB16MIDI,{SB_MPU_BASE, SB_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
 #endif
diff -u --recursive --new-file v1.3.70/linux/drivers/sound/dmabuf.c linux/drivers/sound/dmabuf.c
--- v1.3.70/linux/drivers/sound/dmabuf.c	Wed Feb 28 11:50:07 1996
+++ linux/drivers/sound/dmabuf.c	Fri Mar  1 19:20:28 1996
@@ -738,7 +738,13 @@
 
     case SNDCTL_DSP_GETBLKSIZE:
       if (!(dmap_out->flags & DMA_ALLOC_DONE))
-	reorganize_buffers (dev, dmap_out, 0);
+	{
+	  reorganize_buffers (dev, dmap_out,
+			      (audio_devs[dev]->open_mode == OPEN_READ));
+	  if (audio_devs[dev]->flags & DMA_DUPLEX)
+	    reorganize_buffers (dev, dmap_in,
+				(audio_devs[dev]->open_mode == OPEN_READ));
+	}
 
       return snd_ioctl_return ((int *) arg, dmap_out->fragment_size);
       break;
@@ -1403,6 +1409,7 @@
 
 	      dmap->cfrag = -1;
 	      dmap->flags |= DMA_EMPTY;
+	      dmap->counts[dmap->qtail] = dmap->fragment_size;
 	    }
 	}
 
@@ -1410,6 +1417,10 @@
 	{
 	  if (!(audio_devs[dev]->flags & DMA_AUTOMODE))
 	    {
+
+	      if (dmap->counts[dmap->qhead] == 0)
+		dmap->counts[dmap->qhead] = dmap->fragment_size;
+
 	      audio_devs[dev]->output_block (dev, dmap->raw_buf_phys +
 					  dmap->qhead * dmap->fragment_size,
 					     dmap->counts[dmap->qhead], 1,
diff -u --recursive --new-file v1.3.70/linux/drivers/sound/gus_wave.c linux/drivers/sound/gus_wave.c
--- v1.3.70/linux/drivers/sound/gus_wave.c	Sat Mar  2 10:43:42 1996
+++ linux/drivers/sound/gus_wave.c	Fri Mar  1 19:20:33 1996
@@ -837,7 +837,7 @@
 
   gus_select_voice (0);		/* This disables writes to IRQ/DMA reg */
 
-  gusintr (0, NULL, NULL);      /* Serve pending interrupts */
+  gusintr (0, NULL, NULL);	/* Serve pending interrupts */
   restore_flags (flags);
 }
 
@@ -3537,10 +3537,16 @@
 static void
 gus_tmr_install (int io_base)
 {
+  struct sound_lowlev_timer *tmr;
+
   select_addr = io_base;
   data_addr = io_base + 1;
 
+  tmr = &gus_tmr;
+
+#ifdef THIS_GETS_FIXED
   sound_timer_init (&gus_tmr, "GUS");
+#endif
 }
 #endif
 
diff -u --recursive --new-file v1.3.70/linux/drivers/sound/hex2hex.h linux/drivers/sound/hex2hex.h
--- v1.3.70/linux/drivers/sound/hex2hex.h	Wed Feb 28 11:50:07 1996
+++ linux/drivers/sound/hex2hex.h	Fri Mar  1 19:20:09 1996
@@ -95,7 +95,7 @@
 
 
 	fprintf(outf, "/*\n *\t Computer generated file. Do not edit.\n */\n");
-        fprintf(outf, "static int %s_len = %d\n", varline, l);
+        fprintf(outf, "static int %s_len = %d;\n", varline, l);
 	fprintf(outf, "static unsigned char %s[] = {\n", varline);
 
 	for (i=0;i<l;i++)
diff -u --recursive --new-file v1.3.70/linux/drivers/sound/opl3.c linux/drivers/sound/opl3.c
--- v1.3.70/linux/drivers/sound/opl3.c	Wed Feb 28 11:50:08 1996
+++ linux/drivers/sound/opl3.c	Fri Mar  1 19:20:41 1996
@@ -1231,6 +1231,7 @@
 
       devc->v_alloc->max_voice = devc->nr_voice = 18;
       devc->fm_info.nr_drums = 0;
+      devc->fm_info.synth_subtype = FM_TYPE_OPL3;
       devc->fm_info.capabilities |= SYNTH_CAP_OPL3;
       strcpy (devc->fm_info.name, "Yamaha OPL-3");
 
diff -u --recursive --new-file v1.3.70/linux/drivers/sound/os.h linux/drivers/sound/os.h
--- v1.3.70/linux/drivers/sound/os.h	Wed Feb 14 14:37:15 1996
+++ linux/drivers/sound/os.h	Fri Mar  1 19:20:13 1996
@@ -30,6 +30,7 @@
 #include <linux/malloc.h>
 #include <linux/string.h>
 #include <linux/ioport.h>
+#include <linux/utsname.h>
 
 #include <linux/wrapper.h>
 
diff -u --recursive --new-file v1.3.70/linux/drivers/sound/pas2_pcm.c linux/drivers/sound/pas2_pcm.c
--- v1.3.70/linux/drivers/sound/pas2_pcm.c	Wed Feb 28 11:50:08 1996
+++ linux/drivers/sound/pas2_pcm.c	Fri Mar  1 19:20:44 1996
@@ -324,6 +324,9 @@
       pcm_count = count;
     }
   pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER | F_F_PCM_RATE_COUNTER, FILTER_FREQUENCY);
+#ifdef NO_TRIGGER
+  pas_write (pas_read (PCM_CONTROL) | P_C_PCM_ENABLE | P_C_PCM_DAC_MODE, PCM_CONTROL);
+#endif
 
   pcm_mode = PCM_DAC;
 
@@ -370,12 +373,16 @@
       pcm_count = count;
     }
   pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER | F_F_PCM_RATE_COUNTER, FILTER_FREQUENCY);
+#ifdef NO_TRIGGER
+  pas_write ((pas_read (PCM_CONTROL) | P_C_PCM_ENABLE) & ~P_C_PCM_DAC_MODE, PCM_CONTROL);
+#endif
 
   pcm_mode = PCM_ADC;
 
   restore_flags (flags);
 }
 
+#ifndef NO_TRIGGER
 static void
 pas_pcm_trigger (int dev, int state)
 {
@@ -394,6 +401,7 @@
 
   restore_flags (flags);
 }
+#endif
 
 static int
 pas_pcm_prepare_for_input (int dev, int bsize, int bcount)
@@ -426,7 +434,11 @@
   NULL,
   NULL,
   NULL,
+#ifndef NO_TRIGGER
   pas_pcm_trigger
+#else
+  NULL
+#endif
 };
 
 long
diff -u --recursive --new-file v1.3.70/linux/drivers/sound/sb16_dsp.c linux/drivers/sound/sb16_dsp.c
--- v1.3.70/linux/drivers/sound/sb16_dsp.c	Wed Feb 28 11:50:08 1996
+++ linux/drivers/sound/sb16_dsp.c	Fri Mar  1 19:20:48 1996
@@ -48,7 +48,7 @@
 static int      dsp_stereo = 0;
 static int      dsp_current_speed = 8000;
 static int      dsp_busy = 0;
-static int      dma16, dma8;
+static int      dma16 = -1, dma8 = -1;
 static int      trigger_bits = 0;
 static unsigned long dsp_count = 0;
 
@@ -157,7 +157,7 @@
     {
     case SOUND_PCM_WRITE_RATE:
       if (local)
-	return dsp_set_speed ((long) arg);
+	return dsp_set_speed ((int) arg);
       return snd_ioctl_return ((int *) arg, dsp_set_speed (get_fs_long ((long *) arg)));
 
     case SOUND_PCM_READ_RATE:
@@ -167,12 +167,12 @@
 
     case SNDCTL_DSP_STEREO:
       if (local)
-	return dsp_set_stereo ((long) arg);
+	return dsp_set_stereo ((int) arg);
       return snd_ioctl_return ((int *) arg, dsp_set_stereo (get_fs_long ((long *) arg)));
 
     case SOUND_PCM_WRITE_CHANNELS:
       if (local)
-	return dsp_set_stereo ((long) arg - 1) + 1;
+	return dsp_set_stereo ((int) arg - 1) + 1;
       return snd_ioctl_return ((int *) arg, dsp_set_stereo (get_fs_long ((long *) arg) - 1) + 1);
 
     case SOUND_PCM_READ_CHANNELS:
@@ -182,7 +182,7 @@
 
     case SNDCTL_DSP_SETFMT:
       if (local)
-	return dsp_set_bits ((long) arg);
+	return dsp_set_bits ((int) arg);
       return snd_ioctl_return ((int *) arg, dsp_set_bits (get_fs_long ((long *) arg)));
 
     case SOUND_PCM_READ_BITS:
@@ -521,6 +521,15 @@
   return mem_start;
 }
 
+static void
+set_dma (int dma)
+{
+  if (dma >= 0 && dma < 4)
+    dma8 = dma;
+  if (dma >= 5 && dma <= 7)
+    dma16 = dma;
+}
+
 int
 sb16_dsp_detect (struct address_info *hw_config)
 {
@@ -528,22 +537,38 @@
   extern int      sbc_major, Jazz16_detected;
 
   extern void     Jazz16_set_dma16 (int dma);
+  int             irq;
 
   if (sb16_dsp_ok)
-    return 1;			/* Can't drive two cards */
+    {
+      return 1;			/* Can't drive two cards */
+    }
+
+  irq = hw_config->irq;
+  set_dma (hw_config->dma);
+  set_dma (hw_config->dma2);
 
   if (Jazz16_detected)
     {
-      Jazz16_set_dma16 (hw_config->dma);
+      Jazz16_set_dma16 (dma16);
       sb16_dsp_ok = 1;
       return 1;
     }
 
-  if (!(sb_config = sound_getconf (SNDCARD_SB)))
-    {
-      printk ("SB16 Error: Plain SB not configured\n");
-      return 0;
-    }
+  if (dma8 == -1)
+    if (!(sb_config = sound_getconf (SNDCARD_SB)))
+      {
+	printk ("SB16 Error: Plain SB not configured\n");
+	return 0;
+      }
+    else
+      {
+	dma8 = sb_config->dma;
+	irq = sb_config->irq;
+      }
+
+  if (dma16 == -1)
+    dma16 = dma8;
 
   /*
    * sb_setmixer(OPSW,0xf); if(sb_getmixer(OPSW)!=0xf) return 0;
@@ -555,20 +580,18 @@
   if (sbc_major < 4)		/* Set by the plain SB driver */
     return 0;			/* Not a SB16 */
 
-  if (hw_config->dma < 4)
-    if (hw_config->dma != sb_config->dma)
+  if (dma16 < 4)
+    if (dma16 != dma8)
       {
 	printk ("SB16 Error: Invalid DMA channel %d/%d\n",
-		sb_config->dma, hw_config->dma);
+		dma8, dma16);
 	return 0;
       }
 
-  dma16 = hw_config->dma;
-  dma8 = sb_config->dma;
-  set_irq_hw (sb_config->irq);
-  sb_setmixer (DMA_NR, (1 << hw_config->dma) | (1 << sb_config->dma));
+  set_irq_hw (irq);
+  sb_setmixer (DMA_NR, (1 << dma16) | (1 << dma8));
 
-  DEB (printk ("SoundBlaster 16: IRQ %d DMA %d OK\n", sb_config->irq, hw_config->dma));
+  DEB (printk ("SoundBlaster 16: IRQ %d DMA %d OK\n", sb_config->irq, dma16));
 
   /*
      * dsp_showmessage(0xe3,99);
diff -u --recursive --new-file v1.3.70/linux/drivers/sound/sb16_midi.c linux/drivers/sound/sb16_midi.c
--- v1.3.70/linux/drivers/sound/sb16_midi.c	Sat Mar  2 10:43:42 1996
+++ linux/drivers/sound/sb16_midi.c	Fri Mar  1 19:20:48 1996
@@ -125,7 +125,9 @@
       return -EBUSY;
     }
 
-  sb16midi_input_loop ();
+  reset_sb16midi ();
+  while (input_avail ())
+    sb16midi_read ();
 
   midi_input_intr = input;
   sb16midi_opened = mode;
@@ -228,24 +230,16 @@
   NULL
 };
 
-long
-attach_sb16midi (long mem_start, struct address_info *hw_config)
+static void
+enter_uart_mode (void)
 {
   int             ok, timeout;
   unsigned long   flags;
 
-  sb16midi_base = hw_config->io_base;
-
-  if (!sb16midi_detected)
-    return mem_start;
-
-  request_region (hw_config->io_base, 4, "SB MIDI");
-
   save_flags (flags);
   cli ();
-  for (timeout = 30000; timeout < 0 && !output_ready (); timeout--);	/*
-									 * Wait
-									 */
+  for (timeout = 30000; timeout < 0 && !output_ready (); timeout--);
+
   input_byte = 0;
   sb16midi_cmd (UART_MODE_ON);
 
@@ -258,6 +252,18 @@
 	ok = 1;
 
   restore_flags (flags);
+}
+
+long
+attach_sb16midi (long mem_start, struct address_info *hw_config)
+{
+  sb16midi_base = hw_config->io_base;
+
+  if (!sb16midi_detected)
+    return mem_start;
+
+  request_region (hw_config->io_base, 4, "SB MIDI");
+  enter_uart_mode ();
 
   if (num_midis >= MAX_MIDI_DEV)
     {
@@ -280,9 +286,6 @@
   /*
    * Send the RESET command. Try again if no success at the first time.
    */
-
-  if (inb (STATPORT) == 0xff)
-    return 0;
 
   ok = 0;
 
diff -u --recursive --new-file v1.3.70/linux/drivers/sound/sb_card.c linux/drivers/sound/sb_card.c
--- v1.3.70/linux/drivers/sound/sb_card.c	Wed Feb 14 14:37:15 1996
+++ linux/drivers/sound/sb_card.c	Fri Mar  1 19:20:48 1996
@@ -65,7 +65,7 @@
 unload_sb (struct address_info *hw_config)
 {
   release_region (hw_config->io_base, 16);
-  sb_dsp_unload ();
+  sb_dsp_unload (hw_config);
 }
 
 #endif
diff -u --recursive --new-file v1.3.70/linux/drivers/sound/sb_dsp.c linux/drivers/sound/sb_dsp.c
--- v1.3.70/linux/drivers/sound/sb_dsp.c	Sat Mar  2 10:43:42 1996
+++ linux/drivers/sound/sb_dsp.c	Fri Mar  1 19:20:50 1996
@@ -55,6 +55,7 @@
 static int      dsp_count = 0;
 static int      trigger_bits;
 static int      mpu_base = 0, mpu_irq = 0;
+static int      sb16_inited = 0;
 
 /*
  * The DSP channel can be used either for input or output. Variable
@@ -1613,11 +1614,20 @@
 
   sb_dsp_ok = 1;
   sb_reset_dsp ();
+
+  if (sb16 || hw_config->dma2 >= 0)
+    {
+      if (sb16_dsp_detect (hw_config))
+	{
+	  sb16_inited = 1;
+	  return sb16_dsp_init (mem_start, hw_config);
+	}
+    }
   return mem_start;
 }
 
 void
-sb_dsp_unload (void)
+sb_dsp_unload (struct address_info *hw_config)
 {
   sound_free_dma (dma8);
 
@@ -1634,6 +1644,9 @@
     {
       snd_release_irq (ess_mpu_irq);
     }
+
+  if (sb16_inited)
+    unload_sb16 (hw_config);
 }
 
 void
diff -u --recursive --new-file v1.3.70/linux/drivers/sound/sound_calls.h linux/drivers/sound/sound_calls.h
--- v1.3.70/linux/drivers/sound/sound_calls.h	Sat Mar  2 10:43:42 1996
+++ linux/drivers/sound/sound_calls.h	Fri Mar  1 19:20:11 1996
@@ -83,7 +83,7 @@
 void request_sound_timer (int count);
 void sound_stop_timer(void);
 int snd_ioctl_return(int *addr, int value);
-int snd_set_irq_handler (int interrupt_level, void(*hndlr)(int, void *, struct pt_regs *), char *name, int *osp);
+int snd_set_irq_handler (int interrupt_level, void(*hndlr)(int, void*, struct pt_regs *), char *name, int *osp);
 void snd_release_irq(int vect);
 void sound_dma_malloc(int dev);
 void sound_dma_free(int dev);
@@ -106,7 +106,7 @@
 void sb_free_irq(void);
 int sb_dsp_command (unsigned char val);
 int sb_reset_dsp (void);
-void sb_dsp_unload(void);
+void sb_dsp_unload(struct address_info *);
 
 /*	From sb16_dsp.c	*/
 void sb16_dsp_interrupt (int irq);
diff -u --recursive --new-file v1.3.70/linux/drivers/sound/sound_switch.c linux/drivers/sound/sound_switch.c
--- v1.3.70/linux/drivers/sound/sound_switch.c	Wed Feb 28 11:50:09 1996
+++ linux/drivers/sound/sound_switch.c	Fri Mar  1 19:20:55 1996
@@ -115,6 +115,18 @@
 	      "\n");
 #endif
 
+  put_status ("Kernel: ");
+  put_status (system_utsname.sysname);
+  put_status (" ");
+  put_status (system_utsname.nodename);
+  put_status (" ");
+  put_status (system_utsname.release);
+  put_status (" ");
+  put_status (system_utsname.version);
+  put_status (" ");
+  put_status (system_utsname.machine);
+  put_status ("\n");
+
   if (!put_status ("Config options: "))
     return;
   if (!put_status_int (SELECTED_SOUND_OPTIONS, 16))
@@ -139,7 +151,7 @@
 	  return;
       }
 
-  if (!put_status ("\n\nCard config: \n"))
+  if (!put_status ("\nCard config: \n"))
     return;
 
   for (i = 0; i < num_sound_cards; i++)
@@ -418,6 +430,8 @@
       break;
 
     case SND_DEV_CTL:
+      if ((dev & 0xf0) && ((dev & 0xf0) >> 4) >= num_mixers)
+	return -ENXIO;
       return 0;
       break;
 
diff -u --recursive --new-file v1.3.70/linux/drivers/sound/soundvers.h linux/drivers/sound/soundvers.h
--- v1.3.70/linux/drivers/sound/soundvers.h	Wed Feb 28 11:50:09 1996
+++ linux/drivers/sound/soundvers.h	Fri Mar  1 19:20:13 1996
@@ -1,2 +1,2 @@
-#define SOUND_VERSION_STRING "3.5-beta7-960223"
+#define SOUND_VERSION_STRING "3.5-beta10-960301"
 #define SOUND_INTERNAL_VERSION 0x030505
diff -u --recursive --new-file v1.3.70/linux/drivers/sound/sscape.c linux/drivers/sound/sscape.c
--- v1.3.70/linux/drivers/sound/sscape.c	Sat Mar  2 10:43:42 1996
+++ linux/drivers/sound/sscape.c	Fri Mar  1 19:20:58 1996
@@ -269,7 +269,7 @@
 		 value ? 1 : 0);
   if (host_read (devc) != CMD_ACK)
     {
-      printk ("SNDSCAPE: Setting MT32 mode failed\n");
+      /* printk ("SNDSCAPE: Setting MT32 mode failed\n"); */
     }
   host_close (devc);
 }
diff -u --recursive --new-file v1.3.70/linux/fs/Makefile linux/fs/Makefile
--- v1.3.70/linux/fs/Makefile	Fri Feb  9 17:53:05 1996
+++ linux/fs/Makefile	Sat Mar  2 13:18:47 1996
@@ -157,4 +157,7 @@
   endif
 endif
 
+# binfmt_script is always there
+BINFMTS += binfmt_script.o
+
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.70/linux/fs/binfmt_aout.c linux/fs/binfmt_aout.c
--- v1.3.70/linux/fs/binfmt_aout.c	Wed Feb 28 11:50:09 1996
+++ linux/fs/binfmt_aout.c	Sat Mar  2 20:29:23 1996
@@ -197,6 +197,59 @@
 }
 
 /*
+ * create_aout_tables() parses the env- and arg-strings in new user
+ * memory and creates the pointer tables from them, and puts their
+ * addresses on the "stack", returning the new stack pointer value.
+ */
+static unsigned long * create_aout_tables(char * p, struct linux_binprm * bprm, int ibcs)
+{
+	unsigned long *argv,*envp;
+	unsigned long * sp;
+	int argc = bprm->argc;
+	int envc = bprm->envc;
+
+	sp = (unsigned long *) ((-(unsigned long)sizeof(char *)) & (unsigned long) p);
+#ifdef __alpha__
+/* whee.. test-programs are so much fun. */
+	put_user(0, --sp);
+	put_user(0, --sp);
+	if (bprm->loader) {
+		put_user(0, --sp);
+		put_user(0x3eb, --sp);
+		put_user(bprm->loader, --sp);
+		put_user(0x3ea, --sp);
+	}
+	put_user(bprm->exec, --sp);
+	put_user(0x3e9, --sp);
+#endif
+	sp -= envc+1;
+	envp = sp;
+	sp -= argc+1;
+	argv = sp;
+#ifdef __i386__
+	if (!ibcs) {
+		put_user(envp,--sp);
+		put_user(argv,--sp);
+	}
+#endif
+	put_user(argc,--sp);
+	current->mm->arg_start = (unsigned long) p;
+	while (argc-->0) {
+		put_user(p,argv++);
+		while (get_user(p++)) /* nothing */ ;
+	}
+	put_user(NULL,argv);
+	current->mm->arg_end = current->mm->env_start = (unsigned long) p;
+	while (envc-->0) {
+		put_user(p,envp++);
+		while (get_user(p++)) /* nothing */ ;
+	}
+	put_user(NULL,envp);
+	current->mm->env_end = (unsigned long) p;
+	return sp;
+}
+
+/*
  * These are the functions used to load a.out style executables and shared
  * libraries.  There is no binary dependent code anywhere else.
  */
@@ -328,13 +381,9 @@
 
 	set_brk(current->mm->start_brk, current->mm->brk);
 
-	fd_offset = setup_arg_pages(ex.a_text,bprm->page) - MAX_ARG_PAGES*PAGE_SIZE;
-	p += fd_offset;
-	if (bprm->loader)
-		bprm->loader += fd_offset;
-	bprm->exec += fd_offset;
+	p = setup_arg_pages(p, bprm);
 	
-	p = (unsigned long)create_tables((char *)p, bprm,
+	p = (unsigned long) create_aout_tables((char *)p, bprm,
 					current->personality != PER_LINUX);
 	current->mm->start_stack = p;
 #ifdef __alpha__
diff -u --recursive --new-file v1.3.70/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- v1.3.70/linux/fs/binfmt_elf.c	Fri Feb  9 17:53:05 1996
+++ linux/fs/binfmt_elf.c	Sat Mar  2 20:29:23 1996
@@ -94,22 +94,7 @@
 {
 	unsigned long *argv,*envp, *dlinfo;
 	unsigned long * sp;
-	struct vm_area_struct *mpnt;
 
-	mpnt = (struct vm_area_struct *)kmalloc(sizeof(*mpnt), GFP_KERNEL);
-	if (mpnt) {
-		mpnt->vm_mm = current->mm;
-		mpnt->vm_start = PAGE_MASK & (unsigned long) p;
-		mpnt->vm_end = TASK_SIZE;
-		mpnt->vm_page_prot = PAGE_COPY;
-		mpnt->vm_flags = VM_STACK_FLAGS;
-		mpnt->vm_pte = 0;
-		mpnt->vm_inode = NULL;
-		mpnt->vm_offset = 0;
-		mpnt->vm_ops = NULL;
-		insert_vm_struct(current, mpnt);
-		current->mm->total_vm += (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
-	}
 	sp = (unsigned long *) (0xfffffffc & (unsigned long) p);
 	sp -= exec ? DLINFO_ITEMS*2 : 2;
 	dlinfo = sp;
@@ -537,7 +522,7 @@
 	/* Do this so that we can load the interpreter, if need be.  We will
 	   change some of these later */
 	current->mm->rss = 0;
-	bprm->p += setup_arg_pages(0, bprm->page);
+	bprm->p = setup_arg_pages(bprm->p, bprm);
 	current->mm->start_stack = bprm->p;
 	
 	/* Now we do a little grungy work by mmaping the ELF image into
@@ -639,7 +624,6 @@
 #endif
 	current->suid = current->euid = current->fsuid = bprm->e_uid;
 	current->sgid = current->egid = current->fsgid = bprm->e_gid;
-	bprm->p -= MAX_ARG_PAGES*PAGE_SIZE;
 	bprm->p = (unsigned long) 
 	  create_elf_tables((char *)bprm->p,
 			bprm->argc,
diff -u --recursive --new-file v1.3.70/linux/fs/binfmt_script.c linux/fs/binfmt_script.c
--- v1.3.70/linux/fs/binfmt_script.c	Thu Jan  1 02:00:00 1970
+++ linux/fs/binfmt_script.c	Sat Mar  2 13:18:47 1996
@@ -0,0 +1,128 @@
+/*
+ *  linux/fs/binfmt_script.c
+ *
+ *  Copyright (C) 1996  Martin von Löwis
+ *  original #!-checking implemented by tytso.
+ */
+
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+#include <linux/malloc.h>
+#include <linux/binfmts.h>
+
+static int do_load_script(struct linux_binprm *bprm,struct pt_regs *regs)
+{
+	char *cp, *interp, *i_name, *i_arg, *page;
+	int retval, offset;
+	if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!') || (bprm->sh_bang)) 
+		return -ENOEXEC;
+	/*
+	 * This section does the #! interpretation.
+	 * Sorta complicated, but hopefully it will work.  -TYT
+	 */
+
+	bprm->sh_bang++;
+	iput(bprm->inode);
+	bprm->dont_iput=1;
+
+	bprm->buf[127] = '\0';
+	if ((cp = strchr(bprm->buf, '\n')) == NULL)
+		cp = bprm->buf+127;
+	*cp = '\0';
+	while (cp > bprm->buf) {
+		cp--;
+		if ((*cp == ' ') || (*cp == '\t'))
+			*cp = '\0';
+		else
+			break;
+	}
+	for (cp = bprm->buf+2; (*cp == ' ') || (*cp == '\t'); cp++);
+	if (!cp || *cp == '\0') 
+		return -ENOEXEC; /* No interpreter name found */
+	interp = i_name = cp;
+	i_arg = 0;
+	for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) {
+ 		if (*cp == '/')
+			i_name = cp+1;
+	}
+	while ((*cp == ' ') || (*cp == '\t'))
+		*cp++ = '\0';
+	if (*cp)
+		i_arg = cp;
+	/*
+	 * OK, we've parsed out the interpreter name and
+	 * (optional) argument.
+	 * Splice in (1) the interpreter's name for argv[0]
+	 *           (2) (optional) argument to interpreter
+	 *           (3) filename of shell script (replace argv[0])
+	 *
+	 * This is done in reverse order, because of how the
+	 * user environment and arguments are stored.
+	 */
+	if (bprm->argc) {
+		offset = bprm->p % PAGE_SIZE;
+		page = (char*)bprm->page[bprm->p/PAGE_SIZE];
+		while(bprm->p++,*(page+offset++))
+			if(offset==PAGE_SIZE){
+				offset=0;
+				page = (char*)bprm->page[bprm->p/PAGE_SIZE];
+			}
+		bprm->argc--;
+	}
+	bprm->p = copy_strings(1, &bprm->filename, bprm->page, bprm->p, 2);
+	bprm->argc++;
+	if (i_arg) {
+		bprm->p = copy_strings(1, &i_arg, bprm->page, bprm->p, 2);
+		bprm->argc++;
+	}
+	bprm->p = copy_strings(1, &i_name, bprm->page, bprm->p, 2);
+	bprm->argc++;
+	if (!bprm->p) 
+		return -E2BIG;
+	/*
+	 * OK, now restart the process with the interpreter's inode.
+	 * Note that we use open_namei() as the name is now in kernel
+	 * space, and we don't need to copy it.
+	 */
+	retval = open_namei(interp, 0, 0, &bprm->inode, NULL);
+	if (retval)
+		return retval;
+	bprm->dont_iput=0;
+	retval=prepare_binprm(bprm);
+	if(retval<0)
+		return retval;
+	return search_binary_handler(bprm,regs);
+}
+
+static int load_script(struct linux_binprm *bprm,struct pt_regs *regs)
+{
+	int retval;
+	MOD_INC_USE_COUNT;
+	retval = do_load_script(bprm,regs);
+	MOD_DEC_USE_COUNT;
+	return retval;
+}
+
+struct linux_binfmt script_format = {
+#ifndef MODULE
+	NULL, 0, load_script, NULL, NULL
+#else
+	NULL, &mod_use_count_, load_script, NULL, NULL
+#endif
+};
+
+int init_script_binfmt(void) {
+	return register_binfmt(&script_format);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	return init_script_binfmt();
+}
+
+void cleanup_module( void) {
+	unregister_binfmt(&script_format);
+}
+#endif
diff -u --recursive --new-file v1.3.70/linux/fs/block_dev.c linux/fs/block_dev.c
--- v1.3.70/linux/fs/block_dev.c	Wed Feb 28 11:50:09 1996
+++ linux/fs/block_dev.c	Mon Mar  4 11:25:48 1996
@@ -61,11 +61,8 @@
 	else
 		size = INT_MAX;
 	while (count>0) {
-		if (block >= size) {
-			if (!written)
-				written = -ENOSPC;
-			return written;
-		}
+		if (block >= size)
+			return written ? written : -ENOSPC;
 		chars = blocksize - offset;
 		if (chars > count)
 			chars=count;
@@ -105,7 +102,7 @@
 		      bhlist[i] = getblk (dev, block+i, blocksize);
 		      if(!bhlist[i]){
 			while(i >= 0) brelse(bhlist[i--]);
-			return written? written: -EIO;
+			return written ? written : -EIO;
 		      };
 		    };
 		    ll_rw_block(READ, blocks, bhlist);
@@ -117,7 +114,7 @@
 #endif
 		block++;
 		if (!bh)
-			return written?written:-EIO;
+			return written ? written : -EIO;
 		p = offset + bh->b_data;
 		offset = 0;
 		filp->f_pos += chars;
diff -u --recursive --new-file v1.3.70/linux/fs/buffer.c linux/fs/buffer.c
--- v1.3.70/linux/fs/buffer.c	Wed Feb 28 11:50:09 1996
+++ linux/fs/buffer.c	Mon Mar  4 11:25:49 1996
@@ -363,7 +363,7 @@
 		bh->b_next_free->b_prev_free = bh->b_prev_free;
 		if (free_list[isize] == bh)
 			 free_list[isize] = bh->b_next_free;
-	};
+	}
 	bh->b_next_free = bh->b_prev_free = NULL;
 }
 
@@ -398,7 +398,7 @@
 	if(!lru_list[bh->b_list]) {
 		lru_list[bh->b_list] = bh;
 		lru_list[bh->b_list]->b_prev_free = bh;
-	};
+	}
 	if (!next_to_age[bh->b_list])
 		next_to_age[bh->b_list] = bh;
 
@@ -1571,14 +1571,16 @@
 			protected++;
 		if (buffer_dirty(bh))
 			dirty++;
-		if(mem_map[MAP_NR(((unsigned long) bh->b_data))].count !=1) shared++;
+		if (mem_map[MAP_NR(((unsigned long) bh->b_data))].count != 1)
+			shared++;
 		if (bh->b_count)
 			used++, lastused = found;
 		bh = bh->b_next_free;
-	      } while (bh != lru_list[nlist]);
-	printk("Buffer[%d] mem: %d buffers, %d used (last=%d), %d locked, "
-	       "%d protected, %d dirty %d shrd\n",
-		nlist, found, used, lastused, locked, protected, dirty, shared);
+	  } while (bh != lru_list[nlist]);
+	  printk("Buffer[%d] mem: %d buffers, %d used (last=%d), "
+		 "%d locked, %d protected, %d dirty %d shrd\n",
+		 nlist, found, used, lastused,
+		 locked, protected, dirty, shared);
 	};
 	printk("Size    [LAV]     Free  Clean  Unshar     Lck    Lck1   Dirty  Shared \n");
 	for(isize = 0; isize<NR_SIZES; isize++){
diff -u --recursive --new-file v1.3.70/linux/fs/exec.c linux/fs/exec.c
--- v1.3.70/linux/fs/exec.c	Fri Feb 23 13:54:36 1996
+++ linux/fs/exec.c	Sat Mar  2 20:29:23 1996
@@ -70,6 +70,8 @@
 #ifdef CONFIG_BINFMT_AOUT
 	init_aout_binfmt();
 #endif
+	/* This cannot be configured out of the kernel */
+	init_script_binfmt();
 }
 
 int register_binfmt(struct linux_binfmt * fmt)
@@ -104,6 +106,11 @@
 	}
 	return -EINVAL;
 }
+
+struct linux_binfmt * get_binfmt_list()
+{
+	return formats;
+}
 #endif	/* CONFIG_MODULES */
 
 int open_inode(struct inode * inode, int mode)
@@ -178,74 +185,6 @@
 }
 
 /*
- * create_tables() parses the env- and arg-strings in new user
- * memory and creates the pointer tables from them, and puts their
- * addresses on the "stack", returning the new stack pointer value.
- */
-unsigned long * create_tables(char * p, struct linux_binprm * bprm, int ibcs)
-{
-	unsigned long *argv,*envp;
-	unsigned long * sp;
-	struct vm_area_struct *mpnt;
-	int argc = bprm->argc;
-	int envc = bprm->envc;
-
-	mpnt = (struct vm_area_struct *)kmalloc(sizeof(*mpnt), GFP_KERNEL);
-	if (mpnt) {
-		mpnt->vm_mm = current->mm;
-		mpnt->vm_start = PAGE_MASK & (unsigned long) p;
-		mpnt->vm_end = STACK_TOP;
-		mpnt->vm_page_prot = PAGE_COPY;
-		mpnt->vm_flags = VM_STACK_FLAGS;
-		mpnt->vm_ops = NULL;
-		mpnt->vm_offset = 0;
-		mpnt->vm_inode = NULL;
-		mpnt->vm_pte = 0;
-		insert_vm_struct(current, mpnt);
-		current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
-	}
-	sp = (unsigned long *) ((-(unsigned long)sizeof(char *)) & (unsigned long) p);
-#ifdef __alpha__
-/* whee.. test-programs are so much fun. */
-	put_user(0, --sp);
-	put_user(0, --sp);
-	if (bprm->loader) {
-		put_user(0, --sp);
-		put_user(0x3eb, --sp);
-		put_user(bprm->loader, --sp);
-		put_user(0x3ea, --sp);
-	}
-	put_user(bprm->exec, --sp);
-	put_user(0x3e9, --sp);
-#endif
-	sp -= envc+1;
-	envp = sp;
-	sp -= argc+1;
-	argv = sp;
-#ifdef __i386__
-	if (!ibcs) {
-		put_user(envp,--sp);
-		put_user(argv,--sp);
-	}
-#endif
-	put_user(argc,--sp);
-	current->mm->arg_start = (unsigned long) p;
-	while (argc-->0) {
-		put_user(p,argv++);
-		while (get_user(p++)) /* nothing */ ;
-	}
-	put_user(NULL,argv);
-	current->mm->arg_end = current->mm->env_start = (unsigned long) p;
-	while (envc-->0) {
-		put_user(p,envp++);
-		while (get_user(p++)) /* nothing */ ;
-	}
-	put_user(NULL,envp);
-	current->mm->env_end = (unsigned long) p;
-	return sp;
-}
-
-/*
  * count() counts the number of arguments/envelopes
  *
  * We also do some limited EFAULT checking: this isn't complete, but
@@ -344,20 +283,42 @@
 	return p;
 }
 
-unsigned long setup_arg_pages(unsigned long text_size, unsigned long * page)
+unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm)
 {
-	unsigned long data_base;
+	unsigned long stack_base;
+	struct vm_area_struct *mpnt;
 	int i;
 
-	data_base = STACK_TOP;
-	for (i=MAX_ARG_PAGES-1 ; i>=0 ; i--) {
-		data_base -= PAGE_SIZE;
-		if (page[i]) {
+	stack_base = STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE;
+
+	p += stack_base;
+	if (bprm->loader)
+		bprm->loader += stack_base;
+	bprm->exec += stack_base;
+
+	mpnt = (struct vm_area_struct *)kmalloc(sizeof(*mpnt), GFP_KERNEL);
+	if (mpnt) {
+		mpnt->vm_mm = current->mm;
+		mpnt->vm_start = PAGE_MASK & (unsigned long) p;
+		mpnt->vm_end = STACK_TOP;
+		mpnt->vm_page_prot = PAGE_COPY;
+		mpnt->vm_flags = VM_STACK_FLAGS;
+		mpnt->vm_ops = NULL;
+		mpnt->vm_offset = 0;
+		mpnt->vm_inode = NULL;
+		mpnt->vm_pte = 0;
+		insert_vm_struct(current, mpnt);
+		current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
+	}
+
+	for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
+		if (bprm->page[i]) {
 			current->mm->rss++;
-			put_dirty_page(current,page[i],data_base);
+			put_dirty_page(current,bprm->page[i],stack_base);
 		}
+		stack_base += PAGE_SIZE;
 	}
-	return STACK_TOP;
+	return p;
 }
 
 /*
@@ -485,195 +446,111 @@
 	current->used_math = 0;
 }
 
-/*
- * sys_execve() executes a new program.
+/* 
+ * Fill the binprm structure from the inode. 
+ * Check permissions, then read the first 512 bytes
  */
-int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs)
+int prepare_binprm(struct linux_binprm *bprm)
 {
-	struct linux_binprm bprm;
-	struct linux_binfmt * fmt;
-	int i;
-	int retval;
-	int sh_bang = 0;
-	int try;
-#ifdef __alpha__
-	int loader = 0;
-#endif
-
-	bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
-	for (i=0 ; i<MAX_ARG_PAGES ; i++)	/* clear page-table */
-		bprm.page[i] = 0;
-	retval = open_namei(filename, 0, 0, &bprm.inode, NULL);
-	if (retval)
-		return retval;
-	bprm.filename = filename;
-	bprm.loader = 0;
-	bprm.exec = 0;
-	if ((bprm.argc = count(argv)) < 0)
-		return bprm.argc;
-	if ((bprm.envc = count(envp)) < 0)
-		return bprm.envc;
-	
-restart_interp:
-	if (!S_ISREG(bprm.inode->i_mode)) {	/* must be regular file */
-		retval = -EACCES;
-		goto exec_error2;
-	}
-	if (IS_NOEXEC(bprm.inode)) {		/* FS mustn't be mounted noexec */
-		retval = -EPERM;
-		goto exec_error2;
-	}
-	if (!bprm.inode->i_sb) {
-		retval = -EACCES;
-		goto exec_error2;
-	}
-	i = bprm.inode->i_mode;
-	if (IS_NOSUID(bprm.inode) && (((i & S_ISUID) && bprm.inode->i_uid != current->
-	    euid) || ((i & S_ISGID) && !in_group_p(bprm.inode->i_gid))) && !suser()) {
-		retval = -EPERM;
-		goto exec_error2;
-	}
+	int retval,i;
+	if (!S_ISREG(bprm->inode->i_mode))  /* must be regular file */
+		return -EACCES;
+	if (IS_NOEXEC(bprm->inode))         /* FS mustn't be mounted noexec */
+		return -EACCES;
+	if (!bprm->inode->i_sb)
+		return -EACCES;
+	i = bprm->inode->i_mode;
+	if (IS_NOSUID(bprm->inode) && 
+		(((i & S_ISUID) && bprm->inode->i_uid != current->euid) 
+			|| ((i & S_ISGID) && !in_group_p(bprm->inode->i_gid))) && !suser())
+		return -EPERM;
 	/* make sure we don't let suid, sgid files be ptraced. */
 	if (current->flags & PF_PTRACED) {
-		bprm.e_uid = current->euid;
-		bprm.e_gid = current->egid;
+		bprm->e_uid = current->euid;
+		bprm->e_gid = current->egid;
 	} else {
-		bprm.e_uid = (i & S_ISUID) ? bprm.inode->i_uid : current->euid;
-		bprm.e_gid = (i & S_ISGID) ? bprm.inode->i_gid : current->egid;
-	}
-	if ((retval = permission(bprm.inode, MAY_EXEC)) != 0)
-		goto exec_error2;
-	if (!(bprm.inode->i_mode & 0111) && fsuser()) {
-		retval = -EACCES;
-		goto exec_error2;
+		bprm->e_uid = (i & S_ISUID) ? bprm->inode->i_uid : current->euid;
+		bprm->e_gid = (i & S_ISGID) ? bprm->inode->i_gid : current->egid;
 	}
+	if ((retval = permission(bprm->inode, MAY_EXEC)) != 0)
+		return retval;
+	if (!(bprm->inode->i_mode & 0111) && fsuser())
+		return -EACCES;
 	/* better not execute files which are being written to */
-	if (bprm.inode->i_writecount > 0) {
-		retval = -ETXTBSY;
-		goto exec_error2;
-	}
-	memset(bprm.buf,0,sizeof(bprm.buf));
-	retval = read_exec(bprm.inode,0,bprm.buf,128,1);
-	if (retval < 0)
-		goto exec_error2;
-	if ((bprm.buf[0] == '#') && (bprm.buf[1] == '!') && (!sh_bang)) {
-		/*
-		 * This section does the #! interpretation.
-		 * Sorta complicated, but hopefully it will work.  -TYT
-		 */
+	if (bprm->inode->i_writecount > 0)
+		return -ETXTBSY;
 
-		char *cp, *interp, *i_name, *i_arg;
+	memset(bprm->buf,0,sizeof(bprm->buf));
+	return read_exec(bprm->inode,0,bprm->buf,128,1);
+}
 
-		iput(bprm.inode);
-		bprm.buf[127] = '\0';
-		if ((cp = strchr(bprm.buf, '\n')) == NULL)
-			cp = bprm.buf+127;
-		*cp = '\0';
-		while (cp > bprm.buf) {
-			cp--;
-			if ((*cp == ' ') || (*cp == '\t'))
-				*cp = '\0';
-			else
-				break;
-		}
-		for (cp = bprm.buf+2; (*cp == ' ') || (*cp == '\t'); cp++);
-		if (!cp || *cp == '\0') {
-			retval = -ENOEXEC; /* No interpreter name found */
-			goto exec_error1;
-		}
-		interp = i_name = cp;
-		i_arg = 0;
-		for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) {
- 			if (*cp == '/')
-				i_name = cp+1;
-		}
-		while ((*cp == ' ') || (*cp == '\t'))
-			*cp++ = '\0';
-		if (*cp)
-			i_arg = cp;
-		/*
-		 * OK, we've parsed out the interpreter name and
-		 * (optional) argument.
-		 */
-		if (sh_bang++ == 0) {
-			bprm.p = copy_strings(bprm.envc, envp, bprm.page, bprm.p, 0);
-			bprm.p = copy_strings(--bprm.argc, argv+1, bprm.page, bprm.p, 0);
-		}
-		/*
-		 * Splice in (1) the interpreter's name for argv[0]
-		 *           (2) (optional) argument to interpreter
-		 *           (3) filename of shell script
-		 *
-		 * This is done in reverse order, because of how the
-		 * user environment and arguments are stored.
-		 */
-		bprm.p = copy_strings(1, &bprm.filename, bprm.page, bprm.p, 2);
-		bprm.argc++;
-		if (i_arg) {
-			bprm.p = copy_strings(1, &i_arg, bprm.page, bprm.p, 2);
-			bprm.argc++;
-		}
-		bprm.p = copy_strings(1, &i_name, bprm.page, bprm.p, 2);
-		bprm.argc++;
-		if (!bprm.p) {
-			retval = -E2BIG;
-			goto exec_error1;
-		}
-		/*
-		 * OK, now restart the process with the interpreter's inode.
-		 * Note that we use open_namei() as the name is now in kernel
-		 * space, and we don't need to copy it.
-		 */
-		retval = open_namei(interp, 0, 0, &bprm.inode, NULL);
-		if (retval)
-			goto exec_error1;
-		goto restart_interp;
+void remove_arg_zero(struct linux_binprm *bprm)
+{
+	if (bprm->argc) {
+		unsigned long offset;
+		char * page;
+		offset = bprm->p % PAGE_SIZE;
+		page = (char*)bprm->page[bprm->p/PAGE_SIZE];
+		while(bprm->p++,*(page+offset++))
+			if(offset==PAGE_SIZE){
+				offset=0;
+				page = (char*)bprm->page[bprm->p/PAGE_SIZE];
+			}
+		bprm->argc--;
 	}
+}
+
+/*
+ * cycle the list of binary formats handler, until one recognizes the image
+ */
+int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
+{
+	int try,retval=0;
+	struct linux_binfmt *fmt;
 #ifdef __alpha__
 	/* handle /sbin/loader.. */
 	{
-	    struct exec * eh = (struct exec *) bprm.buf;
+	    struct exec * eh = (struct exec *) bprm->buf;
 
-	    if (!loader && eh->fh.f_magic == 0x183 &&
+	    if (!bprm->loader && eh->fh.f_magic == 0x183 &&
 		(eh->fh.f_flags & 0x3000) == 0x3000)
 	    {
 		char * dynloader[] = { "/sbin/loader" };
-		iput(bprm.inode);
-		loader = 1;
-		bprm.p = copy_strings(1, dynloader, bprm.page, bprm.p, 2);
-		bprm.loader = bprm.p;
-		retval = open_namei(dynloader[0], 0, 0, &bprm.inode, NULL);
+		iput(bprm->inode);
+		bprm->dont_iput = 1;
+		remove_arg_zero(bprm);
+		bprm->p = copy_strings(1, dynloader, bprm->page, bprm->p, 2);
+		bprm->argc++;
+		bprm->loader = bprm->p;
+		retval = open_namei(dynloader[0], 0, 0, &bprm->inode, NULL);
 		if (retval)
-			goto exec_error1;
-		goto restart_interp;
+			return retval;
+		bprm->dont_iput = 0;
+		retval = prepare_binprm(bprm);
+		if (retval<0)
+			return retval;
+		/* should call search_binary_handler recursively here,
+		   but it does not matter */
 	    }
 	}
 #endif
-	if (!sh_bang) {
-		bprm.p = copy_strings(1, &bprm.filename, bprm.page, bprm.p, 2);
-		bprm.exec = bprm.p;
-		bprm.p = copy_strings(bprm.envc,envp,bprm.page,bprm.p,0);
-		bprm.p = copy_strings(bprm.argc,argv,bprm.page,bprm.p,0);
-		if (!bprm.p) {
-			retval = -E2BIG;
-			goto exec_error2;
-		}
-	}
-
-	bprm.sh_bang = sh_bang;
 	for (try=0; try<2; try++) {
-		for (fmt = formats ; fmt ; fmt = fmt->next) {
+		for (fmt = get_binfmt_list() ; fmt ; fmt = fmt->next) {
 			int (*fn)(struct linux_binprm *, struct pt_regs *) = fmt->load_binary;
 			if (!fn)
 				continue;
-			retval = fn(&bprm, regs);
+			retval = fn(bprm, regs);
 			if (retval >= 0) {
-				iput(bprm.inode);
+				if(!bprm->dont_iput)
+					iput(bprm->inode);
+				bprm->dont_iput=1;
 				current->did_exec = 1;
 				return retval;
 			}
 			if (retval != -ENOEXEC)
 				break;
+			if (bprm->dont_iput) /* We don't have the inode anymore*/
+				return retval;
 		}
 		if (retval != -ENOEXEC) {
 			break;
@@ -681,19 +558,65 @@
 		}else{
 #define printable(c) (((c)=='\t') || ((c)=='\n') || (0x20<=(c) && (c)<=0x7e))
 			char modname[20];
-			if (printable(bprm.buf[0]) &&
-			    printable(bprm.buf[1]) &&
-			    printable(bprm.buf[2]) &&
-			    printable(bprm.buf[3]))
+			if (printable(bprm->buf[0]) &&
+			    printable(bprm->buf[1]) &&
+			    printable(bprm->buf[2]) &&
+			    printable(bprm->buf[3]))
 				break; /* -ENOEXEC */
-			sprintf(modname, "binfmt-%hd", *(short*)(&bprm.buf));
+			sprintf(modname, "binfmt-%hd", *(short*)(&bprm->buf));
 			request_module(modname);
 #endif
 		}
 	}
-exec_error2:
-	iput(bprm.inode);
-exec_error1:
+	return retval;
+}
+
+
+/*
+ * sys_execve() executes a new program.
+ */
+int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs)
+{
+	struct linux_binprm bprm;
+	int retval;
+	int i;
+
+	bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
+	for (i=0 ; i<MAX_ARG_PAGES ; i++)	/* clear page-table */
+		bprm.page[i] = 0;
+	retval = open_namei(filename, 0, 0, &bprm.inode, NULL);
+	if (retval)
+		return retval;
+	bprm.filename = filename;
+	bprm.sh_bang = 0;
+	bprm.loader = 0;
+	bprm.exec = 0;
+	bprm.dont_iput = 0;
+	if ((bprm.argc = count(argv)) < 0)
+		return bprm.argc;
+	if ((bprm.envc = count(envp)) < 0)
+		return bprm.envc;
+
+	retval = prepare_binprm(&bprm);
+	
+	if(retval>=0) {
+		bprm.p = copy_strings(1, &bprm.filename, bprm.page, bprm.p, 2);
+		bprm.exec = bprm.p;
+		bprm.p = copy_strings(bprm.envc,envp,bprm.page,bprm.p,0);
+		bprm.p = copy_strings(bprm.argc,argv,bprm.page,bprm.p,0);
+		if (!bprm.p)
+			retval = -E2BIG;
+	}
+
+	if(retval>=0)
+		retval = search_binary_handler(&bprm,regs);
+	if(retval>=0)
+		/* execve success */
+		return retval;
+
+	/* Something went wrong, return the inode and free the argument pages*/
+	if(!bprm.dont_iput)
+		iput(bprm.inode);
 	for (i=0 ; i<MAX_ARG_PAGES ; i++)
 		free_page(bprm.page[i]);
 	return(retval);
diff -u --recursive --new-file v1.3.70/linux/fs/ncpfs/dir.c linux/fs/ncpfs/dir.c
--- v1.3.70/linux/fs/ncpfs/dir.c	Fri Feb 23 13:54:37 1996
+++ linux/fs/ncpfs/dir.c	Sat Mar  2 13:15:35 1996
@@ -1,7 +1,7 @@
 /*
  *  dir.c
  *
- *  Copyright (C) 1995 by Volker Lendecke
+ *  Copyright (C) 1995, 1996 by Volker Lendecke
  *
  */
 
@@ -41,7 +41,7 @@
 ncp_iget(struct inode *dir, struct nw_file_info *finfo);
 
 static struct ncp_inode_info *
-ncp_find_inode(struct inode *dir, const char *name);
+ncp_find_dir_inode(struct inode *dir, const char *name);
 
 static int
 ncp_lookup(struct inode *dir, const char *__name,
@@ -123,6 +123,60 @@
 };
 
 
+/* Here we encapsulate the inode number handling that depends upon the
+ * mount mode: When we mount a complete server, the memory address of
+ * the npc_inode_info is used as an inode. When only a single volume
+ * is mounted, then the DosDirNum is used as the inode number. As this
+ * is unique for the complete volume, this should enable the NFS
+ * exportability of a ncpfs-mounted volume.
+ */
+
+static inline int
+ncp_single_volume(struct ncp_server *server)
+{
+	return (server->m.mounted_vol[0] != '\0');
+}
+
+inline ino_t
+ncp_info_ino(struct ncp_server *server, struct ncp_inode_info *info)
+{
+	return ncp_single_volume(server)
+		? info->finfo.i.DosDirNum : (ino_t)info;
+}
+
+static inline int
+ncp_is_server_root(struct inode *inode)
+{
+	struct ncp_server *s = NCP_SERVER(inode);
+
+	return (   (!ncp_single_volume(s))
+		&& (inode->i_ino == ncp_info_ino(s, &(s->root))));
+}
+
+struct ncp_inode_info *
+ncp_find_inode(struct inode *inode)
+{
+	struct ncp_server *server = NCP_SERVER(inode);
+        struct ncp_inode_info *root = &(server->root);
+        struct ncp_inode_info *this = root;
+
+	ino_t ino = inode->i_ino;
+
+        do
+	{
+                if (ino == ncp_info_ino(server, this))
+		{
+			return this;
+		}
+		this = this->next;
+        }
+	while (this != root);
+
+	return NULL;
+}
+	
+
+
 static int 
 ncp_dir_read(struct inode *inode, struct file *filp, char *buf, int count)
 {
@@ -133,6 +187,7 @@
    all inodes that are in memory. That's why it's enough to index the
    directory cache by the inode number. */
 
+static kdev_t             c_dev = 0;
 static unsigned long      c_ino = 0;
 static int                c_size;
 static int                c_seen_eof;
@@ -147,7 +202,7 @@
         int index = 0;
 	struct ncp_dirent *entry = NULL;
         struct ncp_server *server = NCP_SERVER(inode);
-	struct ncp_inode_info *dir = (struct ncp_inode_info *)(inode->i_ino);
+	struct ncp_inode_info *dir = NCP_INOP(inode);
 
 	DDPRINTK("ncp_readdir: filp->f_pos = %d\n", (int)filp->f_pos);
 	DDPRINTK("ncp_readdir: inode->i_ino = %ld, c_ino = %ld\n",
@@ -159,7 +214,7 @@
 		return -EBADF;
 	}
 
-	if (!ncp_conn_valid(NCP_SERVER(inode)))
+	if (!ncp_conn_valid(server))
 	{
 		return -EIO;
 	}
@@ -177,8 +232,9 @@
 
         if (filp->f_pos == 0)
 	{
-                ncp_invalid_dir_cache(inode->i_ino);
-		if (filldir(dirent,".",1, filp->f_pos, (int)dir) < 0)
+                ncp_invalid_dir_cache(inode);
+		if (filldir(dirent,".",1, filp->f_pos,
+			    ncp_info_ino(server, dir)) < 0)
 		{
 			return 0;
 		}
@@ -187,14 +243,15 @@
 
 	if (filp->f_pos == 1)
 	{
-		if (filldir(dirent,"..",2, filp->f_pos, (int)(dir->dir)) < 0)
+		if (filldir(dirent,"..",2, filp->f_pos,
+			    ncp_info_ino(server, dir->dir)) < 0)
 		{
 			return 0;
 		}
 		filp->f_pos += 1;
 	}
 
-	if (inode->i_ino == c_ino)
+	if ((inode->i_dev == c_dev) && (inode->i_ino == c_ino))
 	{
 		for (i = 0; i < c_size; i++)
 		{
@@ -216,7 +273,7 @@
 	{
 		DDPRINTK("ncp_readdir: Not found in cache.\n");
 
-		if (inode->i_ino == (int)&(server->root))
+		if (ncp_is_server_root(inode))
 		{
 			result = ncp_read_volume_list(server, filp->f_pos,
 						      NCP_READDIR_CACHE_SIZE);
@@ -233,6 +290,7 @@
 
 		if (result < 0)
 		{
+			c_dev = 0;
 			c_ino = 0;
 			return result;
 		}
@@ -240,6 +298,7 @@
 		if (result > 0)
 		{
                         c_seen_eof = (result < NCP_READDIR_CACHE_SIZE);
+			c_dev  = inode->i_dev;
 			c_ino  = inode->i_ino;
 			c_size = result;
 			entry = c_entry;
@@ -264,29 +323,41 @@
                 /* We found it.  For getwd(), we have to return the
                    correct inode in d_ino if the inode is currently in
                    use. Otherwise the inode number does not
-                   matter. (You can argue a lot about this..) */ 
+                   matter. (You can argue a lot about this..) */
 
-                struct ncp_inode_info *ino_info;
-                ino_info = ncp_find_inode(inode, entry->i.entryName);
+		ino_t ino;
 
-                /* Some programs seem to be confused about a zero
-                   inode number, so we set it to one.  Thanks to
-                   Gordon Chaffee for this one. */
-                if (ino_info == NULL)
+		if (ncp_single_volume(server))
 		{
-                        ino_info = (struct ncp_inode_info *) 1;
-                }
+			ino = (ino_t)(entry->i.DosDirNum);
+		}
+		else
+		{
+			struct ncp_inode_info *ino_info;
+			ino_info = ncp_find_dir_inode(inode,
+						      entry->i.entryName);
+
+			/* Some programs seem to be confused about a
+			 * zero inode number, so we set it to one.
+			 * Thanks to Gordon Chaffee for this one. */
+			if (ino_info == NULL)
+			{
+				ino_info = (struct ncp_inode_info *) 1;
+			}
+			ino = (ino_t)(ino_info);
+		}
 
 		DDPRINTK("ncp_readdir: entry->path= %s\n", entry->i.entryName);
 		DDPRINTK("ncp_readdir: entry->f_pos = %ld\n", entry->f_pos);
 
                 if (filldir(dirent, entry->i.entryName, entry->i.nameLen,
-                            entry->f_pos, (ino_t)ino_info) < 0)
+                            entry->f_pos, ino) < 0)
 		{
 			break;
                 }
 
-		if (   (inode->i_ino != c_ino)
+		if (   (inode->i_dev != c_dev)
+		    || (inode->i_ino != c_ino)
 		    || (entry->f_pos != filp->f_pos))
 		{
 			/* Someone has destroyed the cache while we slept
@@ -341,9 +412,9 @@
 				DPRINTK("ncp_read_volumes: found vol: %s\n",
 					info.volume_name);
 
-				if (ncp_do_lookup(server, NULL,
-						  info.volume_name,
-						  &(entry->i)) != 0)
+				if (ncp_lookup_volume(server,
+						      info.volume_name,
+						      &(entry->i)) != 0)
 				{
 					printk("ncpfs: could not lookup vol "
 					       "%s\n", info.volume_name);
@@ -426,15 +497,17 @@
 void
 ncp_init_dir_cache(void)
 {
+	c_dev   = 0;
         c_ino   = 0;
         c_entry = NULL;
 }
 
 void
-ncp_invalid_dir_cache(unsigned long ino)
+ncp_invalid_dir_cache(struct inode *ino)
 {
-	if (ino == c_ino)
+	if ((ino->i_dev == c_dev) && (ino->i_ino == c_ino))
 	{
+		c_dev = 0;
                 c_ino = 0;
                 c_seen_eof = 0;
         }
@@ -505,7 +578,8 @@
         root->next->prev = new_inode_info;
         root->next = new_inode_info;
         
-	if (!(inode = iget(dir->i_sb, (int)new_inode_info)))
+	if (!(inode = iget(dir->i_sb, ncp_info_ino(NCP_SERVER(dir),
+						   new_inode_info))))
 	{
 		printk("ncp_iget: iget failed!");
 		return NULL;
@@ -556,12 +630,13 @@
         root->finfo.opened = 0;
 	i->attributes  = aDIR;
 	i->dataStreamSize = 1024;
+	i->DosDirNum = 0;
 	i->volNumber = NCP_NUMBER_OF_VOLUMES+1;	/* illegal volnum */
 	ncp_date_unix2dos(0, &(i->creationTime), &(i->creationDate));
 	ncp_date_unix2dos(0, &(i->modifyTime), &(i->modifyDate));
 	ncp_date_unix2dos(0, &dummy, &(i->lastAccessDate));
 	i->nameLen = 0;
-        i->entryName[0] = '\0';
+	i->entryName[0] = '\0';
 
         root->state = NCP_INODE_LOOKED_UP;
         root->nused = 1;
@@ -570,6 +645,25 @@
         return;
 }
 
+int
+ncp_conn_logged_in(struct ncp_server *server)
+{
+	if (server->m.mounted_vol[0] == '\0')
+	{
+		return 0;
+	}
+
+	str_upper(server->m.mounted_vol);
+	if (ncp_lookup_volume(server, server->m.mounted_vol,
+			      &(server->root.finfo.i)) != 0)
+	{
+		return -ENOENT;
+	}
+	str_lower(server->root.finfo.i.entryName);
+
+	return 0;
+}
+
 void
 ncp_free_all_inodes(struct ncp_server *server)
 {
@@ -600,7 +694,7 @@
    complete linear search through the inodes belonging to this
    filesystem. This has to be fixed. */
 static struct ncp_inode_info *
-ncp_find_inode(struct inode *dir, const char *name)
+ncp_find_dir_inode(struct inode *dir, const char *name)
 {
 	struct ncp_server *server = NCP_SERVER(dir);
 	struct nw_info_struct *dir_info = NCP_ISTRUCT(dir);
@@ -645,15 +739,16 @@
 		iput(dir);
 		return -ENOENT;
 	}
-	if (!ncp_conn_valid(NCP_SERVER(dir)))
+
+	server = NCP_SERVER(dir);
+
+	if (!ncp_conn_valid(server))
 	{
 		iput(dir);
 		return -EIO;
 	}
 
-        DDPRINTK("ncp_lookup: %s, len %d\n", __name, len);
-
-	server = NCP_SERVER(dir);
+	DPRINTK("ncp_lookup: %s, len %d\n", __name, len);
 
 	/* Fast cheat for . */
 	if (len == 0 || (len == 1 && __name[0] == '.'))
@@ -672,7 +767,7 @@
 			parent->state = NCP_INODE_LOOKED_UP;
 		}
 
-		*result = iget(dir->i_sb, (int)parent);
+		*result = iget(dir->i_sb, ncp_info_ino(server, parent));
 		iput(dir);
 		if (*result == 0)
 		{
@@ -686,7 +781,7 @@
 
 	memcpy(name, __name, len);
 	name[len] = 0;
-	result_info = ncp_find_inode(dir, name);
+	result_info = ncp_find_dir_inode(dir, name);
 
         if (result_info != 0)
 	{
@@ -698,7 +793,7 @@
                 /* Here we convert the inode_info address into an
                    inode number */
 
-                *result = iget(dir->i_sb, (int)result_info);
+                *result = iget(dir->i_sb, ncp_info_ino(server, result_info));
                 iput(dir);
 
                 if (*result == NULL)
@@ -713,8 +808,8 @@
            server. */
 
         found_in_cache = 0;
-        
-        if (dir->i_ino == c_ino)
+
+        if ((dir->i_dev == c_dev) && (dir->i_ino == c_ino))
 	{
                 int first = c_last_returned_index;
                 int i;
@@ -723,7 +818,7 @@
                 do
 		{
                         DDPRINTK("ncp_lookup: trying index: %d, name: %s\n",
-                                i, c_entry[i].i.entryName);
+				 i, c_entry[i].i.entryName);
 
                         if (strcmp(c_entry[i].i.entryName, name) == 0)
 			{
@@ -739,15 +834,24 @@
 
         if (found_in_cache == 0)
 	{
+		int res;
 		str_upper(name);
 
 		DDPRINTK("ncp_lookup: do_lookup on %s/%s\n",
 			 NCP_ISTRUCT(dir)->entryName, name);
 
-		if (ncp_do_lookup(server,
-				  dir->i_ino == (int)&(NCP_SERVER(dir)->root)
-				  ? NULL : NCP_ISTRUCT(dir),
-				  name, &(finfo.i)) != 0)
+		if (ncp_is_server_root(dir))
+		{
+			res = ncp_lookup_volume(server, name, &(finfo.i));
+		}
+		else
+		{
+			res = ncp_obtain_info(server,
+					      NCP_ISTRUCT(dir)->volNumber,
+					      NCP_ISTRUCT(dir)->DosDirNum,
+					      name, &(finfo.i));
+		}
+		if (res != 0)
 		{
                         iput(dir);
                         return -ENOENT;
@@ -803,7 +907,7 @@
 		return -EACCES;
 	}
 
-        ncp_invalid_dir_cache(dir->i_ino);
+	ncp_invalid_dir_cache(dir);
 
 	str_lower(finfo.i.entryName);
 	finfo.access = O_RDWR;
@@ -860,7 +964,7 @@
 	else
 	{
 		error = 0;
-                ncp_invalid_dir_cache(dir->i_ino);
+                ncp_invalid_dir_cache(dir);
         }
 
 	iput(dir);
@@ -884,7 +988,7 @@
 		iput(dir);
 		return -EIO;
 	}
-        if (ncp_find_inode(dir, name) != NULL)
+        if (ncp_find_dir_inode(dir, name) != NULL)
 	{
 		iput(dir);
                 error = -EBUSY;
@@ -900,7 +1004,7 @@
 						    NCP_ISTRUCT(dir),
 						    _name)) == 0)
 		{
-                        ncp_invalid_dir_cache(dir->i_ino);
+                        ncp_invalid_dir_cache(dir);
 		}
 		else
 		{
@@ -928,7 +1032,7 @@
 		iput(dir);
 		return -EIO;
 	}
-        if (ncp_find_inode(dir, name) != NULL)
+        if (ncp_find_dir_inode(dir, name) != NULL)
 	{
 		iput(dir);
                 error = -EBUSY;
@@ -943,7 +1047,7 @@
 						    NCP_ISTRUCT(dir),
 						    _name)) == 0)
 		{
-                        ncp_invalid_dir_cache(dir->i_ino);
+                        ncp_invalid_dir_cache(dir);
 		}
 		else
 		{
@@ -982,8 +1086,8 @@
                 goto finished;
 	}
 
-        if (   (ncp_find_inode(old_dir, old_name) != NULL)
-            || (ncp_find_inode(new_dir, new_name) != NULL))
+        if (   (ncp_find_dir_inode(old_dir, old_name) != NULL)
+            || (ncp_find_dir_inode(new_dir, new_name) != NULL))
 	{
                 res = -EBUSY;
                 goto finished;
@@ -1003,8 +1107,8 @@
 
         if (res == 0)
 	{
-                ncp_invalid_dir_cache(old_dir->i_ino);
-                ncp_invalid_dir_cache(new_dir->i_ino);
+                ncp_invalid_dir_cache(old_dir);
+                ncp_invalid_dir_cache(new_dir);
         }
 	else
 	{
diff -u --recursive --new-file v1.3.70/linux/fs/ncpfs/file.c linux/fs/ncpfs/file.c
--- v1.3.70/linux/fs/ncpfs/file.c	Fri Feb 23 13:54:37 1996
+++ linux/fs/ncpfs/file.c	Sat Mar  2 13:15:35 1996
@@ -1,7 +1,7 @@
 /*
  *  file.c
  *
- *  Copyright (C) 1995 by Volker Lendecke
+ *  Copyright (C) 1995, 1996 by Volker Lendecke
  *
  */
 
@@ -241,6 +241,7 @@
         if (pos > inode->i_size)
 	{
                 inode->i_size = pos;
+		ncp_invalid_dir_cache(NCP_INOP(inode)->dir->inode);
         }
 
         DPRINTK("ncp_file_write: exit %s\n", NCP_ISTRUCT(inode)->entryName);
diff -u --recursive --new-file v1.3.70/linux/fs/ncpfs/inode.c linux/fs/ncpfs/inode.c
--- v1.3.70/linux/fs/ncpfs/inode.c	Fri Feb 23 13:54:37 1996
+++ linux/fs/ncpfs/inode.c	Sat Mar  2 13:15:35 1996
@@ -1,7 +1,7 @@
 /*
  *  inode.c
  *
- *  Copyright (C) 1995 by Volker Lendecke
+ *  Copyright (C) 1995, 1996 by Volker Lendecke
  *
  */
 
@@ -58,50 +58,25 @@
            inode->i_ino. Just to make sure everything went well, we
            check it's there. */
 
-        struct ncp_inode_info *inode_info
-                = (struct ncp_inode_info *)(inode->i_ino);
+        struct ncp_inode_info *inode_info = ncp_find_inode(inode);
 
-#if 1
-        struct ncp_inode_info *root = &(NCP_SERVER(inode)->root);
-        struct ncp_inode_info *check_info = root;
-
-        do
+	if (inode_info == NULL)
 	{
-                if (inode_info == check_info)
-		{
-                        if (check_info->state == NCP_INODE_LOOKED_UP)
-			{
-                                DDPRINTK("ncp_read_inode: found it!\n");
-                                goto good;
-                        }
-                        else
-			{
-                                printk("ncp_read_inode: "
-                                       "state != NCP_INODE_LOOKED_UP\n");
-				goto good;
-                        }
-                }
-                check_info = check_info->next;
-        }
-	while (check_info != root);
+		/* Ok, now we're in trouble. The inode info is not there. What
+		   should we do now??? */
+		printk("ncp_read_inode: inode info not found\n");
+		return;
+	}
 
-        /* Ok, now we're in trouble. The inode info is not there. What
-           should we do now??? */
-        printk("ncp_read_inode: inode info not found\n");
-        return;
-
- good:
-	DDPRINTK("ncp_read_inode: read entry %s\n",
-		 inode_info->finfo.i.entryName);
-#endif
         inode_info->state = NCP_INODE_VALID;
 
         NCP_INOP(inode) = inode_info;
+	inode_info->inode = inode;
 
         if (NCP_ISTRUCT(inode)->attributes & aDIR)
 	{
                 inode->i_mode = NCP_SERVER(inode)->m.dir_mode;
-		/* for directories in dataStreamSize seems to be some
+		/* for directories dataStreamSize seems to be some
 		   Object ID ??? */
 		inode->i_size = 512;
 	}
@@ -173,7 +148,7 @@
 	{
                 DDPRINTK("ncp_put_inode: put directory %ld\n",
 			 inode->i_ino);
-                ncp_invalid_dir_cache(inode->i_ino);
+                ncp_invalid_dir_cache(inode);
         }                
 
 	clear_inode(inode);
@@ -286,8 +261,6 @@
 		goto fail;
 	}
    
-        ncp_init_root(server);
-
         /*
          * Make the connection to the server
          */
@@ -326,7 +299,9 @@
 
         DPRINTK("ncp_read_super: NCP_SBP(sb) = %x\n", (int)NCP_SBP(sb));
 
-	if (!(sb->s_mounted = iget(sb, (int)&(server->root))))
+	ncp_init_root(server);
+
+	if (!(sb->s_mounted = iget(sb, ncp_info_ino(server, &(server->root)))))
 	{
 		sb->s_dev = 0;
 		printk("ncp_read_super: get root inode failed\n");
@@ -537,7 +512,7 @@
 		result = 0;
 	}
 
-        ncp_invalid_dir_cache((unsigned long)(NCP_INOP(inode)->dir));
+        ncp_invalid_dir_cache(NCP_INOP(inode)->dir->inode);
 
 	return result;
 }
diff -u --recursive --new-file v1.3.70/linux/fs/ncpfs/ioctl.c linux/fs/ncpfs/ioctl.c
--- v1.3.70/linux/fs/ncpfs/ioctl.c	Thu Jan  4 21:54:58 1996
+++ linux/fs/ncpfs/ioctl.c	Sat Mar  2 13:15:35 1996
@@ -1,7 +1,7 @@
 /*
  *  ioctl.c
  *
- *  Copyright (C) 1995 by Volker Lendecke
+ *  Copyright (C) 1995, 1996 by Volker Lendecke
  *
  */
 
@@ -73,6 +73,16 @@
 
 		return server->reply_size;
 
+	case NCP_IOC_CONN_LOGGED_IN:
+
+		if (   (permission(inode, MAY_WRITE) != 0)
+		    && (current->uid != server->m.mounted_uid))
+		{
+			return -EACCES;
+		}
+
+		return ncp_conn_logged_in(server);
+		
 	case NCP_IOC_GET_FS_INFO:
 
 		if (   (permission(inode, MAY_WRITE) != 0)
diff -u --recursive --new-file v1.3.70/linux/fs/ncpfs/mmap.c linux/fs/ncpfs/mmap.c
--- v1.3.70/linux/fs/ncpfs/mmap.c	Fri Feb 23 13:54:37 1996
+++ linux/fs/ncpfs/mmap.c	Sat Mar  2 13:15:35 1996
@@ -1,7 +1,7 @@
 /*
  *  mmap.c
  *
- *  Copyright (C) 1995 by Volker Lendecke
+ *  Copyright (C) 1995, 1996 by Volker Lendecke
  *
  */
 
diff -u --recursive --new-file v1.3.70/linux/fs/ncpfs/ncplib_kernel.c linux/fs/ncpfs/ncplib_kernel.c
--- v1.3.70/linux/fs/ncpfs/ncplib_kernel.c	Fri Feb 23 13:54:37 1996
+++ linux/fs/ncpfs/ncplib_kernel.c	Sat Mar  2 13:15:35 1996
@@ -1,3 +1,10 @@
+/*
+ *  ncplib_kernel.c
+ *
+ *  Copyright (C) 1995, 1996 by Volker Lendecke
+ *
+ */
+
 #include "ncplib_kernel.h"
 
 typedef __u8  byte;
@@ -260,56 +267,19 @@
 	target->entryName[*name_len] = '\0';
 	return;
 }
-		
 
 int
-ncp_do_lookup(struct ncp_server *server,
-	      struct nw_info_struct *dir,
-	      char *path,	/* may only be one component */
-	      struct nw_info_struct *target)
+ncp_obtain_info(struct ncp_server *server,
+		__u8 vol_num, __u32 dir_base,
+		char *path, /* At most 1 component */
+		struct nw_info_struct *target)
 {
-	__u8  vol_num;
-	__u32 dir_base;
 	int result;
-	char *volname = NULL;
 
 	if (target == NULL)
 	{
 		return -EINVAL;
 	}
- 
-	if (dir == NULL)
-	{
-
-		DDPRINTK("ncp_do_lookup: looking up vol %s\n", path);
-
-		/* Access a volume's root directory */
-		ncp_init_request(server);
-		ncp_add_byte(server, 22); /* subfunction */
-		ncp_add_byte(server, 0); /* dos name space */
-		ncp_add_byte(server, 0); /* reserved */
-		ncp_add_byte(server, 0); /* reserved */
-		ncp_add_byte(server, 0); /* reserved */
-		ncp_add_handle_path(server, 0, 0, 0, /* no handle */
-				    path);
-
-		if ((result = ncp_request(server, 87)) != 0)
-		{
-			ncp_unlock_server(server);
-			return result;
-		}
-
-		dir_base = ncp_reply_dword(server, 4);
-		vol_num  = ncp_reply_byte (server, 8);
-		ncp_unlock_server(server);
-		volname = path;
-		path = NULL;
-	}
-	else
-	{
-		vol_num = dir->volNumber;
-		dir_base = dir->DosDirNum;
-	}
 
 	ncp_init_request(server);
 	ncp_add_byte(server, 6); /* subfunction */
@@ -317,8 +287,7 @@
 	ncp_add_byte(server, 0); /* dos name space as dest */
 	ncp_add_word(server, 0xff); /* get all */
 	ncp_add_dword(server, RIM_ALL);
-	ncp_add_handle_path(server, vol_num, dir_base, 1,
-			    path);
+	ncp_add_handle_path(server, vol_num, dir_base, 1, path);
 
 	if ((result = ncp_request(server, 87)) != 0)
 	{
@@ -327,14 +296,54 @@
 	}
 
 	ncp_extract_file_info(ncp_reply_data(server, 0), target);
+	ncp_unlock_server(server);
+	return 0;
+}
 
-	if (volname != NULL)
+int
+ncp_lookup_volume(struct ncp_server *server,
+		  char *volname,
+		  struct nw_info_struct *target)
+{
+	int result;
+	__u8  vol_num;
+	__u32 dir_base;
+
+	DPRINTK("ncp_lookup_volume: looking up vol %s\n", volname);
+
+	ncp_init_request(server);
+	ncp_add_byte(server, 22); /* Subfunction: Generate dir handle */
+	ncp_add_byte(server, 0); /* DOS name space */
+	ncp_add_byte(server, 0); /* reserved */
+	ncp_add_byte(server, 0); /* reserved */
+	ncp_add_byte(server, 0); /* reserved */
+
+	ncp_add_byte(server, 0); /* faked volume number */
+	ncp_add_dword(server, 0); /* faked dir_base */
+	ncp_add_byte(server, 0xff); /* Don't have a dir_base */
+	ncp_add_byte(server, 1); /* 1 path component */
+	ncp_add_pstring(server, volname);
+
+	if ((result = ncp_request(server, 87)) != 0)
 	{
-		target->nameLen = strlen(volname);
-		strcpy(target->entryName, volname);
+		ncp_unlock_server(server);
+		return result;
 	}
 
+	dir_base = ncp_reply_dword(server, 4);
+	vol_num  = ncp_reply_byte(server, 8);
 	ncp_unlock_server(server);
+
+	if ((result = ncp_obtain_info(server, vol_num, dir_base, NULL,
+				      target)) != 0)
+	{
+		return result;
+	}
+
+	DPRINTK("ncp_lookup_volume: attribs = %X\n", target->attributes);
+
+	target->nameLen = strlen(volname);
+	strcpy(target->entryName, volname);
 	return 0;
 }
 
diff -u --recursive --new-file v1.3.70/linux/fs/ncpfs/ncplib_kernel.h linux/fs/ncpfs/ncplib_kernel.h
--- v1.3.70/linux/fs/ncpfs/ncplib_kernel.h	Tue Jan  2 16:46:28 1996
+++ linux/fs/ncpfs/ncplib_kernel.h	Sat Mar  2 13:15:35 1996
@@ -1,3 +1,10 @@
+/*
+ *  ncplib_kernel.h
+ *
+ *  Copyright (C) 1995, 1996 by Volker Lendecke
+ *
+ */
+
 #ifndef _NCPLIB_H
 #define _NCPLIB_H
 
@@ -114,10 +121,16 @@
 	  const char *source, int *bytes_written);
 
 int
-ncp_do_lookup(struct ncp_server *server,
-	      struct nw_info_struct *dir,
-	      char *path,	/* may only be one component */
-	      struct nw_info_struct *target);
+ncp_obtain_info(struct ncp_server *server,
+		__u8 vol_num, __u32 dir_base,
+		char *path, /* At most 1 component */
+		struct nw_info_struct *target);
+
+int
+ncp_lookup_volume(struct ncp_server *server,
+		  char *volname,
+		  struct nw_info_struct *target);
+
 
 int
 ncp_modify_file_or_subdir_dos_info(struct ncp_server *server,
diff -u --recursive --new-file v1.3.70/linux/fs/ncpfs/sock.c linux/fs/ncpfs/sock.c
--- v1.3.70/linux/fs/ncpfs/sock.c	Sat Mar  2 10:43:43 1996
+++ linux/fs/ncpfs/sock.c	Sat Mar  2 13:15:35 1996
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 1992, 1993  Rick Sladkey
  *
- *  Modified 1995 by Volker Lendecke to be usable for ncp
+ *  Modified 1995, 1996 by Volker Lendecke to be usable for ncp
  *
  */
 
@@ -619,7 +619,7 @@
 
 	if (result != 0)
 	{
-		DPRINTK("ncp_completion_code: %d\n", result);
+		DPRINTK("ncp_completion_code: %x\n", result);
 	}
 	return result;	
 }
diff -u --recursive --new-file v1.3.70/linux/fs/super.c linux/fs/super.c
--- v1.3.70/linux/fs/super.c	Wed Feb 28 11:50:10 1996
+++ linux/fs/super.c	Mon Mar  4 11:25:49 1996
@@ -498,7 +498,7 @@
 			/*
 			 * Make sure all quotas are turned off on this device we need to mount
 			 * it readonly so no more writes by the quotasystem.
-			 * If later on the remount fails to bad there are no quotas running
+			 * If later on the remount fails too bad there are no quotas running
 			 * anymore. Turn them on again by hand.
 			 */
 			quota_off(dev, -1);
@@ -517,7 +517,7 @@
 	/*
 	 * Before checking if the filesystem is still busy make sure the kernel
 	 * doesn't hold any quotafiles open on that device. If the umount fails
-	 * to bad there are no quotas running anymore. Turn them on again by hand.
+	 * too bad there are no quotas running anymore. Turn them on again by hand.
 	 */
 	quota_off(dev, -1);
 	if (!fs_may_umount(dev, sb->s_mounted))
diff -u --recursive --new-file v1.3.70/linux/include/asm-alpha/system.h linux/include/asm-alpha/system.h
--- v1.3.70/linux/include/asm-alpha/system.h	Sat Mar  2 10:43:44 1996
+++ linux/include/asm-alpha/system.h	Sun Mar  3 13:15:40 1996
@@ -52,9 +52,9 @@
 
 #define halt() __asm__ __volatile__ ("call_pal %0" : : "i" (PAL_halt) : "memory")
 
-#define switch_to(p) do { \
-	current_set[0] = p; \
-	alpha_switch_to((unsigned long) &(p)->tss - 0xfffffc0000000000); \
+#define switch_to(prev,next) do { \
+	current_set[0] = next; \
+	alpha_switch_to((unsigned long) &(next)->tss - 0xfffffc0000000000); \
 } while (0)
 
 extern void alpha_switch_to(unsigned long pctxp);
diff -u --recursive --new-file v1.3.70/linux/include/asm-alpha/unistd.h linux/include/asm-alpha/unistd.h
--- v1.3.70/linux/include/asm-alpha/unistd.h	Sat Feb 17 16:02:53 1996
+++ linux/include/asm-alpha/unistd.h	Mon Mar  4 11:46:31 1996
@@ -70,6 +70,8 @@
 #define __NR_setsockopt		105
 #define __NR_listen		106
 #define __NR_sigsuspend		111
+#define __NR_recvmsg		113
+#define __NR_sendmsg		114
 #define __NR_gettimeofday	116
 #define __NR_getrusage		117
 #define __NR_getsockopt		118
@@ -161,6 +163,7 @@
 #define __NR_sched_rr_get_interval	337
 #define __NR_afs_syscall		338
 #define __NR_uname			339
+#define __NR_nanosleep			340
 
 #ifdef __LIBRARY__
 
diff -u --recursive --new-file v1.3.70/linux/include/asm-i386/smp.h linux/include/asm-i386/smp.h
--- v1.3.70/linux/include/asm-i386/smp.h	Sat Mar  2 10:43:44 1996
+++ linux/include/asm-i386/smp.h	Mon Mar  4 09:16:40 1996
@@ -186,7 +186,7 @@
 extern volatile unsigned long kernel_flag, kernel_counter;
 extern volatile unsigned char active_kernel_processor;
 extern void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs);
-extern void smp_reschedule_irq(int cpl, void *dev_id, struct pt_regs *regs);
+extern void smp_reschedule_irq(int cpl, struct pt_regs *regs);
 extern unsigned long ipi_count;
 extern void smp_invalidate_rcv(void);		/* Process an NMI */
 extern volatile unsigned long kernel_counter;
diff -u --recursive --new-file v1.3.70/linux/include/asm-i386/system.h linux/include/asm-i386/system.h
--- v1.3.70/linux/include/asm-i386/system.h	Wed Nov  8 07:11:41 1995
+++ linux/include/asm-i386/system.h	Sun Mar  3 13:14:50 1996
@@ -31,11 +31,11 @@
 
 /* This special macro can be used to load a debugging register */
 
-#define loaddebug(register) \
+#define loaddebug(tsk,register) \
 		__asm__("movl %0,%%edx\n\t" \
 			"movl %%edx,%%db" #register "\n\t" \
 			: /* no output */ \
-			:"m" (current->debugreg[register]) \
+			:"m" (tsk->debugreg[register]) \
 			:"dx");
 
 
@@ -65,61 +65,57 @@
 	 *	the wrong process.
 	 */
 
-#define switch_to(tsk) do { \
+#define switch_to(prev,next) do { \
 	cli();\
-	if(current->flags&PF_USEDFPU) \
+	if(prev->flags&PF_USEDFPU) \
 	{ \
-		__asm__ __volatile__("fnsave %0":"=m" (current->tss.i387.hard)); \
+		__asm__ __volatile__("fnsave %0":"=m" (prev->tss.i387.hard)); \
 		__asm__ __volatile__("fwait"); \
-		current->flags&=~PF_USEDFPU;	 \
+		prev->flags&=~PF_USEDFPU;	 \
 	} \
-	current->lock_depth=syscall_count; \
-	kernel_counter+=next->lock_depth-current->lock_depth; \
+	prev->lock_depth=syscall_count; \
+	kernel_counter+=next->lock_depth-prev->lock_depth; \
 	syscall_count=next->lock_depth; \
 __asm__("pushl %%edx\n\t" \
 	"movl "SYMBOL_NAME_STR(apic_reg)",%%edx\n\t" \
 	"movl 0x20(%%edx), %%edx\n\t" \
 	"shrl $22,%%edx\n\t" \
 	"and  $0x3C,%%edx\n\t" \
-	"xchgl %%ecx,"SYMBOL_NAME_STR(current_set)"(,%%edx)\n\t" \
+	"movl %%ecx,"SYMBOL_NAME_STR(current_set)"(,%%edx)\n\t" \
 	"popl %%edx\n\t" \
 	"ljmp %0\n\t" \
 	"sti\n\t" \
 	: /* no output */ \
-	:"m" (*(((char *)&tsk->tss.tr)-4)), \
-	 "c" (tsk) \
-	:"cx"); \
+	:"m" (*(((char *)&next->tss.tr)-4)), \
+	 "c" (next)); \
 	/* Now maybe reload the debug registers */ \
-	if(current->debugreg[7]){ \
-		loaddebug(0); \
-		loaddebug(1); \
-		loaddebug(2); \
-		loaddebug(3); \
-		loaddebug(6); \
+	if(prev->debugreg[7]){ \
+		loaddebug(prev,0); \
+		loaddebug(prev,1); \
+		loaddebug(prev,2); \
+		loaddebug(prev,3); \
+		loaddebug(prev,6); \
 	} \
 } while (0)
 
 #else
-#define switch_to(tsk) do { \
-__asm__("cli\n\t" \
-	"xchgl %%ecx,"SYMBOL_NAME_STR(current_set)"\n\t" \
+#define switch_to(prev,next) do { \
+__asm__("movl %2,"SYMBOL_NAME_STR(current_set)"\n\t" \
 	"ljmp %0\n\t" \
-	"sti\n\t" \
-	"cmpl %%ecx,"SYMBOL_NAME_STR(last_task_used_math)"\n\t" \
+	"cmpl %1,"SYMBOL_NAME_STR(last_task_used_math)"\n\t" \
 	"jne 1f\n\t" \
 	"clts\n" \
 	"1:" \
-	: /* no output */ \
-	:"m" (*(((char *)&tsk->tss.tr)-4)), \
-	 "c" (tsk) \
-	:"cx"); \
+	: /* no outputs */ \
+	:"m" (*(((char *)&next->tss.tr)-4)), \
+	 "r" (prev), "r" (next)); \
 	/* Now maybe reload the debug registers */ \
-	if(current->debugreg[7]){ \
-		loaddebug(0); \
-		loaddebug(1); \
-		loaddebug(2); \
-		loaddebug(3); \
-		loaddebug(6); \
+	if(prev->debugreg[7]){ \
+		loaddebug(prev,0); \
+		loaddebug(prev,1); \
+		loaddebug(prev,2); \
+		loaddebug(prev,3); \
+		loaddebug(prev,6); \
 	} \
 } while (0)
 #endif
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/asi.h linux/include/asm-sparc/asi.h
--- v1.3.70/linux/include/asm-sparc/asi.h	Sat Nov 25 19:04:48 1995
+++ linux/include/asm-sparc/asi.h	Mon Mar  4 08:49:59 1996
@@ -1,4 +1,4 @@
-/* $Id: asi.h,v 1.11 1995/11/25 02:31:11 davem Exp $ */
+/* $Id: asi.h,v 1.13 1996/03/01 07:20:51 davem Exp $ */
 #ifndef _SPARC_ASI_H
 #define _SPARC_ASI_H
 
@@ -96,6 +96,10 @@
 
 /* This is ROSS HyperSparc only. */
 #define ASI_M_FLUSH_IWHOLE 0x31   /* Flush entire ICACHE; wo, ss */
+
+/* Tsunami/Viking i/d cache flash clear. */
+#define ASI_M_IC_FLCLEAR   0x36
+#define ASI_M_DC_FLCLEAR   0x37
 
 #define ASI_M_DCDR         0x39   /* Data Cache Diagnostics Registerl rw, ss */
 
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/auxio.h linux/include/asm-sparc/auxio.h
--- v1.3.70/linux/include/asm-sparc/auxio.h	Sat Nov 25 19:04:48 1995
+++ linux/include/asm-sparc/auxio.h	Mon Mar  4 08:49:59 1996
@@ -1,4 +1,4 @@
-/* $Id: auxio.h,v 1.8 1995/11/25 02:31:13 davem Exp $
+/* $Id: auxio.h,v 1.10 1996/01/03 03:52:58 davem Exp $
  * auxio.h:  Definitons and code for the Auxiliary I/O register.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -9,12 +9,13 @@
 #include <asm/system.h>
 #include <asm/vaddrs.h>
 
+extern unsigned char *auxio_register;
+
 /* This register is an unsigned char in IO space.  It does two things.
  * First, it is used to control the front panel LED light on machines
  * that have it (good for testing entry points to trap handlers and irq's)
  * Secondly, it controls various floppy drive parameters.
  */
-
 #define AUXIO_ORMEIN      0xf0    /* All writes must set these bits. */
 #define AUXIO_ORMEIN4M    0xc0    /* sun4m - All writes must set these bits. */
 #define AUXIO_FLPY_DENS   0x20    /* Floppy density, high if set. Read only. */
@@ -29,8 +30,7 @@
 #define AUXIO_FLPY_EJCT   0x02    /* Eject floppy disk.  Write only. */
 #define AUXIO_LED         0x01    /* On if set, off if unset. Read/Write */
 
-#define AUXREG   ((volatile unsigned char *)(AUXIO_VADDR + 3))
-#define AUXREG4M ((volatile unsigned char *)(AUXIO_VADDR))
+#define AUXREG   ((volatile unsigned char *)(auxio_register))
 
 #define TURN_ON_LED   *AUXREG = (*AUXREG | AUXIO_ORMEIN | AUXIO_LED)
 #define TURN_OFF_LED  *AUXREG = ((*AUXREG | AUXIO_ORMEIN) & (~AUXIO_LED))
@@ -44,8 +44,9 @@
 extern inline void set_auxio(unsigned char bits_on, unsigned char bits_off)
 {
 	unsigned char regval;
+	unsigned long flags;
 
-	cli();
+	save_flags(flags); cli();
 
 	switch(sparc_cpu_model) {
 	case sun4c:
@@ -53,16 +54,14 @@
 		*AUXREG = ((regval | bits_on) & ~bits_off) | AUXIO_ORMEIN;
 		break;
 	case sun4m:
-		regval = *AUXREG4M;
-		*AUXREG4M = ((regval | bits_on) & ~bits_off) | AUXIO_ORMEIN4M;
+		regval = *AUXREG;
+		*AUXREG = ((regval | bits_on) & ~bits_off) | AUXIO_ORMEIN4M;
 		break;
 	default:
 		panic("Can't set AUXIO register on this machine.");
 	};
 
-	sti();
-
-	return;
+	restore_flags(flags);
 }
 #endif /* !(__ASSEMBLY__) */
 
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/bitops.h linux/include/asm-sparc/bitops.h
--- v1.3.70/linux/include/asm-sparc/bitops.h	Sat Nov 25 19:04:48 1995
+++ linux/include/asm-sparc/bitops.h	Mon Mar  4 08:50:00 1996
@@ -1,4 +1,4 @@
-/* $Id: bitops.h,v 1.17 1995/11/25 02:31:15 davem Exp $
+/* $Id: bitops.h,v 1.18 1996/01/03 03:53:00 davem Exp $
  * bitops.h: Bit string operations on the Sparc.
  *
  * Copyright 1995, David S. Miller (davem@caip.rutgers.edu).
@@ -67,7 +67,7 @@
 /* The following routine need not be atomic. */
 extern __inline__ unsigned long test_bit(int nr, const void *addr)
 {
-	return 1UL & (((int *) addr)[nr >> 5] >> (nr & 31));
+	return 1UL & (((const unsigned int *) addr)[nr >> 5] >> (nr & 31));
 }
 
 /* The easy/cheese version for now. */
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/cypress.h linux/include/asm-sparc/cypress.h
--- v1.3.70/linux/include/asm-sparc/cypress.h	Sat Nov 25 19:04:49 1995
+++ linux/include/asm-sparc/cypress.h	Mon Mar  4 08:50:00 1996
@@ -35,18 +35,41 @@
  * ME: MmuEnable -- Is the MMU doing translations? 0=no 1=yes
  */
 
-/* NEEDS TO BE FIXED */
-#define CYPRESS_MCABITS   0x01800000
-#define CYPRESS_MCMBITS   0x00600000
-#define CYPRESS_MVALID    0x00040000
-#define CYPRESS_MIDMASK   0x0003c000   /* Only on 605 */
-#define CYPRESS_BMODE     0x00002000
-#define CYPRESS_ACENABLE  0x00001000
+#define CYPRESS_MCA       0x00c00000
+#define CYPRESS_MCM       0x00300000
+#define CYPRESS_MVALID    0x00080000
+#define CYPRESS_MIDMASK   0x00078000   /* Only on 605 */
+#define CYPRESS_BMODE     0x00004000
+#define CYPRESS_ACENABLE  0x00002000
 #define CYPRESS_MRFLCT    0x00000800   /* Only on 605 */
 #define CYPRESS_CMODE     0x00000400
 #define CYPRESS_CLOCK     0x00000200   /* Only on 604 */
 #define CYPRESS_CENABLE   0x00000100
 #define CYPRESS_NFAULT    0x00000002
 #define CYPRESS_MENABLE   0x00000001
+
+extern inline void cypress_flush_page(unsigned long page)
+{
+	__asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+			     "r" (page), "i" (ASI_M_FLUSH_PAGE));
+}
+
+extern inline void cypress_flush_segment(unsigned long addr)
+{
+	__asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+			     "r" (addr), "i" (ASI_M_FLUSH_SEG));
+}
+
+extern inline void cypress_flush_region(unsigned long addr)
+{
+	__asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+			     "r" (addr), "i" (ASI_M_FLUSH_REGION));
+}
+
+extern inline void cypress_flush_context(void)
+{
+	__asm__ __volatile__("sta %%g0, [%%g0] %0\n\t" : :
+			     "i" (ASI_M_FLUSH_CTX));
+}
 
 #endif /* !(_SPARC_CYPRESS_H) */
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/delay.h linux/include/asm-sparc/delay.h
--- v1.3.70/linux/include/asm-sparc/delay.h	Sat Nov 25 19:04:49 1995
+++ linux/include/asm-sparc/delay.h	Mon Mar  4 08:50:00 1996
@@ -1,4 +1,4 @@
-/* $Id: delay.h,v 1.7 1995/11/25 02:31:32 davem Exp $
+/* $Id: delay.h,v 1.8 1996/01/28 02:09:21 davem Exp $
  * delay.h: Linux delay routines on the Sparc.
  *
  * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu).
@@ -7,6 +7,8 @@
 #ifndef __SPARC_DELAY_H
 #define __SPARC_DELAY_H
 
+extern unsigned long loops_per_sec;
+
 extern __inline__ void __delay(unsigned long loops)
 {
 	__asm__ __volatile__("cmp %0, 0\n\t"
@@ -16,23 +18,8 @@
 			     "0" (loops));
 }
 
-/* udelay(usecs) is used for very short delays up to 1 millisecond. On
- * the Sparc (both sun4c and sun4m) we have a free running usec counter
- * available to us already.
- */
-extern volatile unsigned int *master_l10_counter;
-
-extern __inline__ void udelay(unsigned int usecs)
-{
-	unsigned int ccnt;
-
-	if(!master_l10_counter)
-		return;
-	ccnt=*master_l10_counter;
-	for(usecs+=1; usecs; usecs--, ccnt=*master_l10_counter)
-		while(*master_l10_counter == ccnt)
-			__asm__("": : :"memory");
-}
+/* This is too messy with inline asm on the Sparc. */
+extern void udelay(unsigned long usecs);
 
 /* calibrate_delay() wants this... */
 #define muldiv(a, b, c)    (((a)*(b))/(c))
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/dma.h linux/include/asm-sparc/dma.h
--- v1.3.70/linux/include/asm-sparc/dma.h	Sat Nov 25 19:04:49 1995
+++ linux/include/asm-sparc/dma.h	Mon Mar  4 08:50:00 1996
@@ -1,4 +1,4 @@
-/* $Id: dma.h,v 1.12 1995/11/25 02:31:34 davem Exp $
+/* $Id: dma.h,v 1.13 1996/02/17 17:32:33 miguel Exp $
  * include/asm-sparc/dma.h
  *
  * Copyright 1995 (C) David S. Miller (davem@caip.rutgers.edu)
@@ -93,6 +93,7 @@
 #define DMA_ACC_SZ_ERR   0x00000040        /* The access size was bad */
 #define DMA_FIFO_STDRAIN 0x00000040        /* DMA_VERS1 Drain the FIFO */
 #define DMA_RST_SCSI     0x00000080        /* Reset the SCSI controller */
+#define DMA_RST_ENET     DMA_RST_SCSI      /* Reset the ENET controller */
 #define DMA_ST_WRITE     0x00000100        /* write from device to memory */
 #define DMA_ENABLE       0x00000200        /* Fire up DMA, handle requests */
 #define DMA_PEND_READ    0x00000400        /* DMA_VERS1/0/PLUS Pendind Read */
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/fbio.h linux/include/asm-sparc/fbio.h
--- v1.3.70/linux/include/asm-sparc/fbio.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/fbio.h	Mon Mar  4 08:50:00 1996
@@ -0,0 +1,133 @@
+#ifndef __LINUX_FBIO_H
+#define __LINUX_FBIO_H
+
+/* Constants used for fbio SunOS compatibility -miguel */
+
+/* Frame buffer types */
+#define FBTYPE_NOTYPE           -1
+#define FBTYPE_SUN1BW           0   /* mono */
+#define FBTYPE_SUN1COLOR        1 
+#define FBTYPE_SUN2BW           2 
+#define FBTYPE_SUN2COLOR        3 
+#define FBTYPE_SUN2GP           4 
+#define FBTYPE_SUN5COLOR        5 
+#define FBTYPE_SUN3COLOR        6 
+#define FBTYPE_MEMCOLOR         7 
+#define FBTYPE_SUN4COLOR        8 
+ 
+#define FBTYPE_NOTSUN1          9 
+#define FBTYPE_NOTSUN2          10
+#define FBTYPE_NOTSUN3          11
+ 
+#define FBTYPE_SUNFAST_COLOR    12  /* cg6 */
+#define FBTYPE_SUNROP_COLOR     13
+#define FBTYPE_SUNFB_VIDEO      14
+#define FBTYPE_SUNGIFB          15
+#define FBTYPE_SUNGPLAS         16
+#define FBTYPE_SUNGP3           17
+#define FBTYPE_SUNGT            18
+#define FBTYPE_SUNLEO           19      /* zx Leo card */
+#define FBTYPE_MDICOLOR         20      /* cg14 */
+#define FBTYPE_LASTPLUSONE      21
+
+/* fbio ioctls */
+/* Returned by FBIOGTYPE */
+struct  fbtype {
+        int     fb_type;        /* fb type, see above */
+        int     fb_height;      /* pixels */
+        int     fb_width;       /* pixels */
+        int     fb_depth;
+        int     fb_cmsize;      /* color map entries */
+        int     fb_size;        /* fb size in bytes */
+};
+#define FBIOGTYPE _IOR('F', 0, struct fbtype)
+
+/* Used by FBIOPUTCMAP */
+struct  fbcmap {
+        int             index;          /* first element (0 origin) */
+        int             count;
+        unsigned char   *red;
+        unsigned char   *green;
+        unsigned char   *blue;
+};
+
+#define FBIOPUTCMAP _IOW('F', 3, struct fbcmap)
+
+/* # of device specific values */
+#define FB_ATTR_NDEVSPECIFIC    8
+/* # of possible emulations */
+#define FB_ATTR_NEMUTYPES       4
+ 
+struct fbsattr {
+        int     flags;
+        int     emu_type;	/* -1 if none */
+        int     dev_specific[FB_ATTR_NDEVSPECIFIC];
+};
+ 
+struct fbgattr {
+        int     real_type;	/* real frame buffer type */
+        int     owner;		/* unknown */
+        struct fbtype fbtype;	/* real frame buffer fbtype */
+        struct fbsattr sattr;   
+        int     emu_types[FB_ATTR_NEMUTYPES]; /* supported emulations */
+};
+#define FBIOSATTR  _IOW('F', 5, struct fbgattr) /* Unsupported: */
+#define FBIOGATTR  _IOR('F', 6, struct fbgattr)	/* supporoted */
+
+#define FBIOSVIDEO _IOW('F', 7, int)
+#define FBIOGVIDEO _IOR('F', 8, int)
+
+/* Cursor position */
+struct fbcurpos {
+#ifdef __KERNEL__
+	short fbx, fby;
+#else
+        short x, y;
+#endif
+};
+
+/* Cursor operations */
+#define FB_CUR_SETCUR   0x01	/* Enable/disable cursor display */
+#define FB_CUR_SETPOS   0x02	/* set cursor position */
+#define FB_CUR_SETHOT   0x04	/* set cursor hotspot */
+#define FB_CUR_SETCMAP  0x08	/* set color map for the cursor */
+#define FB_CUR_SETSHAPE 0x10	/* set shape */
+#define FB_CUR_SETALL   0x1F	/* all of the above */
+
+struct fbcursor {
+        short set;              /* what to set, choose from the list above */
+        short enable;           /* cursor on/off */
+        struct fbcurpos pos;    /* cursor position */
+        struct fbcurpos hot;    /* cursor hot spot */
+        struct fbcmap cmap;     /* color map info */
+        struct fbcurpos size;   /* cursor bit map size */
+        char *image;            /* cursor image bits */
+        char *mask;             /* cursor mask bits */
+};
+
+/* set/get cursor attributes/shape */
+#define FBIOSCURSOR     _IOW('F', 24, struct fbcursor)
+#define FBIOGCURSOR     _IOWR('F', 25, struct fbcursor)
+ 
+/* set/get cursor position */
+#define FBIOSCURPOS     _IOW('F', 26, struct fbcurpos)
+#define FBIOGCURPOS     _IOW('F', 27, struct fbcurpos)
+ 
+/* get max cursor size */
+#define FBIOGCURMAX     _IOR('F', 28, struct fbcurpos)
+ 
+#ifdef __KERNEL__
+/* Addresses on the fd of a cgsix that are mappable */
+#define CG6_FBC    0x70000000
+#define CG6_TEC    0x70001000
+#define CG6_BTREGS 0x70002000
+#define CG6_FHC    0x70004000
+#define CG6_THC    0x70005000
+#define CG6_ROM    0x70006000
+#define CG6_RAM    0x70016000
+#define CG6_DHC    0x80000000
+
+#define CG3_MMAP_OFFSET 0x4000000
+#endif /* KERNEL */
+
+#endif /* __LINUX_FBIO_H */
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/fcntl.h linux/include/asm-sparc/fcntl.h
--- v1.3.70/linux/include/asm-sparc/fcntl.h	Sat Nov 25 19:04:49 1995
+++ linux/include/asm-sparc/fcntl.h	Mon Mar  4 08:50:00 1996
@@ -1,4 +1,4 @@
-/* $Id: fcntl.h,v 1.5 1995/11/25 02:31:43 davem Exp $ */
+/* $Id: fcntl.h,v 1.6 1996/01/28 02:09:23 davem Exp $ */
 #ifndef _SPARC_FCNTL_H
 #define _SPARC_FCNTL_H
 
@@ -12,11 +12,11 @@
 #define O_APPEND	0x0008
 #define FASYNC		0x0040	/* fcntl, for BSD compatibility */
 #define O_CREAT		0x0200	/* not fcntl */
-#define O_EXCL		0x0800	/* not fcntl */
-#define O_NOCTTY	0x8000	/* not fcntl */
 #define O_TRUNC		0x0400	/* not fcntl */
+#define O_EXCL		0x0800	/* not fcntl */
 #define O_SYNC		0x2000
 #define O_NONBLOCK	0x4000
+#define O_NOCTTY	0x8000	/* not fcntl */
 
 #define F_DUPFD		0	/* dup */
 #define F_GETFD		1	/* get f_flags */
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/floppy.h linux/include/asm-sparc/floppy.h
--- v1.3.70/linux/include/asm-sparc/floppy.h	Sat Mar  2 10:43:44 1996
+++ linux/include/asm-sparc/floppy.h	Mon Mar  4 08:50:00 1996
@@ -250,7 +250,7 @@
 }
 
 /* Our low-level entry point in arch/sparc/kernel/entry.S */
-extern void floppy_hardint(int irq, void *dev_id, struct pt_regs *regs);
+extern void floppy_hardint(int irq, void *unused, struct pt_regs *regs);
 
 static int sun_fd_request_irq(void)
 {
@@ -259,7 +259,7 @@
 
 	if(!once) {
 		once = 1;
-		error = request_fast_irq(FLOPPY_IRQ, floppy_hardint, SA_INTERRUPT, "floppy", NULL);
+		error = request_fast_irq(FLOPPY_IRQ, floppy_hardint, SA_INTERRUPT, "floppy");
 		return ((error == 0) ? 0 : -1);
 	} else return 0;
 }
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/head.h linux/include/asm-sparc/head.h
--- v1.3.70/linux/include/asm-sparc/head.h	Sat Nov 25 19:04:49 1995
+++ linux/include/asm-sparc/head.h	Mon Mar  4 08:50:00 1996
@@ -1,4 +1,4 @@
-/* $Id: head.h,v 1.19 1995/11/25 02:31:47 davem Exp $ */
+/* $Id: head.h,v 1.23 1996/02/15 09:12:55 davem Exp $ */
 #ifndef __SPARC_HEAD_H
 #define __SPARC_HEAD_H
 
@@ -22,6 +22,10 @@
 #define TRAP_ENTRY(type, label) \
 	rd %psr, %l0; b label; rd %wim, %l3; nop;
 
+/* Data/text faults. Defaults to sun4c version at boot time. */
+#define SPARC_TFAULT rd %psr, %l0; rd %wim, %l3; b sun4c_fault; mov 1, %l7;
+#define SPARC_DFAULT rd %psr, %l0; rd %wim, %l3; b sun4c_fault; mov 0, %l7;
+
 /* This is for traps we should NEVER get. */
 #define BAD_TRAP(num) \
         rd %psr, %l0; mov num, %l7; b bad_trap_handler; rd %wim, %l3;
@@ -41,10 +45,10 @@
 
 /* Software trap for SunOS4.1.x system calls. */
 #define SUNOS_SYSCALL_TRAP \
+        rd %psr, %l0; \
         sethi %hi(C_LABEL(sunos_sys_table)), %l7; \
-        or %l7, %lo(C_LABEL(sunos_sys_table)), %l7; \
         b linux_sparc_syscall; \
-        rd %psr, %l0;
+        or %l7, %lo(C_LABEL(sunos_sys_table)), %l7;
 
 /* Software trap for Slowaris system calls. */
 #define SOLARIS_SYSCALL_TRAP \
@@ -74,12 +78,6 @@
 #define TRAP_ENTRY_INTERRUPT(int_level) \
         mov int_level, %l7; rd %psr, %l0; b real_irq_entry; rd %wim, %l3;
 
-/* This is for software interrupts, which currently (atleast on the sun4c)
- * correspond to IRQ levels 1, 4, and 6.
- */
-#define TRAP_ENTRY_SOFTINT(int_level) \
-        mov int_level, %l7; rd %psr, %l0; b soft_irq_entry; rd %wim, %l3;
-
 /* NMI's (Non Maskable Interrupts) are special, you can't keep them
  * from coming in, and basically if you get one, the shows over. ;(
  * On the sun4c they are usually asyncronous memory errors, on the
@@ -88,7 +86,7 @@
  * command you to do CPU tricks, read your mailbox for more info."
  */
 #define NMI_TRAP \
-        rd %wim, %l3; b linux_trap_nmi; mov %psr, %l0; nop;
+        rd %wim, %l3; b linux_trap_nmi_sun4c; mov %psr, %l0; nop;
 
 /* Window overflows/underflows are special and we need to try and be as
  * efficient as possible here....
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/iommu.h linux/include/asm-sparc/iommu.h
--- v1.3.70/linux/include/asm-sparc/iommu.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/iommu.h	Mon Mar  4 08:50:00 1996
@@ -0,0 +1,117 @@
+/* iommu.h: Definitions for the sun4m IOMMU.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+#ifndef _SPARC_IOMMU_H
+#define _SPARC_IOMMU_H
+
+#include <asm/page.h>
+
+/* The iommu handles all virtual to physical address translations
+ * that occur between the SBUS and physical memory.  Access by
+ * the cpu to IO registers and similar go over the mbus so are
+ * translated by the on chip SRMMU.  The iommu and the srmmu do
+ * not need to have the same translations at all, in fact most
+ * of the time the translations they handle are a disjunct set.
+ * Basically the iommu handles all dvma sbus activity.
+ */
+
+/* The IOMMU registers occupy three pages in IO space. */
+struct iommu_regs {
+	/* First page */
+	volatile unsigned long control;    /* IOMMU control */
+	volatile unsigned long base;       /* Physical base of iopte page table */
+	volatile unsigned long _unused1[3];
+	volatile unsigned long tlbflush;   /* write only */
+	volatile unsigned long pageflush;  /* write only */
+	volatile unsigned long _unused2[1017];
+	/* Second page */
+	volatile unsigned long afsr;       /* Async-fault status register */
+	volatile unsigned long afar;       /* Async-fault physical address */
+	volatile unsigned long _unused3[2];
+	volatile unsigned long sbuscfg0;   /* SBUS configuration registers, per-slot */
+	volatile unsigned long sbuscfg1;
+	volatile unsigned long sbuscfg2;
+	volatile unsigned long sbuscfg3;
+	volatile unsigned long mfsr;       /* Memory-fault status register */
+	volatile unsigned long mfar;       /* Memory-fault physical address */
+	volatile unsigned long _unused4[1014];
+	/* Third page */
+	volatile unsigned long mid;        /* IOMMU module-id */
+};
+
+#define IOMMU_CTRL_IMPL     0xf0000000 /* Implementation */
+#define IOMMU_CTRL_VERS     0x0f000000 /* Version */
+#define IOMMU_CTRL_RNGE     0x0000001c /* Mapping RANGE */
+#define IOMMU_RNGE_16MB     0x00000000 /* 0xff000000 -> 0xffffffff */
+#define IOMMU_RNGE_32MB     0x00000004 /* 0xfe000000 -> 0xffffffff */
+#define IOMMU_RNGE_64MB     0x00000008 /* 0xfc000000 -> 0xffffffff */
+#define IOMMU_RNGE_128MB    0x0000000c /* 0xf8000000 -> 0xffffffff */
+#define IOMMU_RNGE_256MB    0x00000010 /* 0xf0000000 -> 0xffffffff */
+#define IOMMU_RNGE_512MB    0x00000014 /* 0xe0000000 -> 0xffffffff */
+#define IOMMU_RNGE_1GB      0x00000018 /* 0xc0000000 -> 0xffffffff */
+#define IOMMU_RNGE_2GB      0x0000001c /* 0x80000000 -> 0xffffffff */
+#define IOMMU_CTRL_ENAB     0x00000001 /* IOMMU Enable */
+
+#define IOMMU_AFSR_ERR      0x80000000 /* LE, TO, or BE asserted */
+#define IOMMU_AFSR_LE       0x40000000 /* SBUS reports error after transaction */
+#define IOMMU_AFSR_TO       0x20000000 /* Write access took more than 12.8 us. */
+#define IOMMU_AFSR_BE       0x10000000 /* Write access received error acknowledge */
+#define IOMMU_AFSR_SIZE     0x0e000000 /* Size of transaction causing error */
+#define IOMMU_AFSR_S        0x01000000 /* Sparc was in supervisor mode */
+#define IOMMU_AFSR_RESV     0x00f00000 /* Reserver, forced to 0x8 by hardware */
+#define IOMMU_AFSR_ME       0x00080000 /* Multiple errors occurred */
+#define IOMMU_AFSR_RD       0x00040000 /* A read operation was in progress */
+#define IOMMU_AFSR_FAV      0x00020000 /* IOMMU afar has valid contents */
+
+#define IOMMU_SBCFG_SAB30   0x00010000 /* Phys-address bit 30 when bypass enabled */
+#define IOMMU_SBCFG_BA16    0x00000004 /* Slave supports 16 byte bursts */
+#define IOMMU_SBCFG_BA8     0x00000002 /* Slave supports 8 byte bursts */
+#define IOMMU_SBCFG_BYPASS  0x00000001 /* Bypass IOMMU, treat all addresses
+					  produced by this device as pure
+					  physical. */
+
+#define IOMMU_MFSR_ERR      0x80000000 /* One or more of PERR1 or PERR0 */
+#define IOMMU_MFSR_S        0x01000000 /* Sparc was in supervisor mode */
+#define IOMMU_MFSR_CPU      0x00800000 /* CPU transaction caused parity error */
+#define IOMMU_MFSR_ME       0x00080000 /* Multiple parity errors occurred */
+#define IOMMU_MFSR_PERR     0x00006000 /* high bit indicates parity error occurred
+					  on the even word of the access, low bit
+					  indicated odd word caused the parity error */
+#define IOMMU_MFSR_BM       0x00001000 /* Error occurred while in boot mode */
+#define IOMMU_MFSR_C        0x00000800 /* Address causing error was marked cacheable */
+#define IOMMU_MFSR_RTYP     0x000000f0 /* Memory request transaction type */
+
+#define IOMMU_MID_SBAE      0x001f0000 /* SBus arbitration enable */
+#define IOMMU_MID_SE        0x00100000 /* Enables SCSI/ETHERNET arbitration */
+#define IOMMU_MID_SB3       0x00080000 /* Enable SBUS device 3 arbitration */
+#define IOMMU_MID_SB2       0x00040000 /* Enable SBUS device 2 arbitration */
+#define IOMMU_MID_SB1       0x00020000 /* Enable SBUS device 1 arbitration */
+#define IOMMU_MID_SB0       0x00010000 /* Enable SBUS device 0 arbitration */
+#define IOMMU_MID_MID       0x0000000f /* Module-id, hardcoded to 0x8 */
+
+/* The format of an iopte in the page tables */
+#define IOPTE_PAGE          0x07ffff00 /* Physical page number (PA[30:12]) */
+#define IOPTE_WRITE         0x00000004 /* Writeable */
+#define IOPTE_VALID         0x00000002 /* IOPTE is valid */
+#define IOPTE_WAZ           0x00000001 /* Write as zeros */
+
+struct iommu_struct {
+	struct iommu_regs *regs;
+	iopte_t *page_table;
+	/* For convenience */
+	unsigned long start; /* First managed virtual address */
+	unsigned long end;   /* Last managed virtual address */
+};
+
+extern inline void iommu_invalidate(struct iommu_regs *regs)
+{
+	regs->tlbflush = 0;
+}
+
+extern inline void iommu_invalidate_page(struct iommu_regs *regs, unsigned long page)
+{
+	regs->pageflush = (page & PAGE_MASK);
+}
+
+#endif /* !(_SPARC_IOMMU_H) */
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/irq.h linux/include/asm-sparc/irq.h
--- v1.3.70/linux/include/asm-sparc/irq.h	Sat Nov 25 19:04:49 1995
+++ linux/include/asm-sparc/irq.h	Mon Mar  4 08:50:00 1996
@@ -16,7 +16,7 @@
 extern void disable_irq(unsigned int);
 extern void enable_irq(unsigned int);
 
-extern int request_fast_irq(unsigned int irq, void (*handler)(int, struct pt_regs *), unsigned long flags, const char *devname);
+extern int request_fast_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname);
 
 /* On the sun4m, just like the timers, we have both per-cpu and master
  * interrupt registers.
@@ -68,5 +68,7 @@
 #define SUN4M_INT_ENABLE  0x80000000
 #define SUN4M_INT_E14     0x00000080
 #define SUN4M_INT_E10     0x00080000
+
+/* XXX add cross-cpu ipi functions XXX */
 
 #endif
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/kbio.h linux/include/asm-sparc/kbio.h
--- v1.3.70/linux/include/asm-sparc/kbio.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/kbio.h	Mon Mar  4 08:50:00 1996
@@ -0,0 +1,37 @@
+#ifndef __LINUX_KBIO_H
+#define __LINUX_KBIO_H
+
+/* Return keyboard type */
+#define KIOCTYPE    _IOR('k', 9, int)
+/* Return Keyboard layout */
+#define KIOCLAYOUT  _IOR('k', 20, int)
+
+enum {
+    TR_NONE,
+    TR_ASCII,			/* keyboard is in regular state */
+    TR_EVENT,			/* keystrokes sent as firm events */
+    TR_UNTRANS_EVENT		/* EVENT+up and down+no translation */
+};
+
+/* Return the current keyboard translation */
+#define KIOCGTRANS  _IOR('k', 5, int)
+/* Set the keyboard translation */
+#define KIOCTRANS   _IOW('k', 0, int)
+
+/* Send a keyboard command */
+#define KIOCCMD     _IOW('k', 8, int)
+
+/* Return if keystrokes are being sent to /dev/kbd */
+
+/* Set routing of keystrokes to /dev/kbd */
+#define KIOCSDIRECT _IOW('k', 10, int)
+
+/* Top bit records if the key is up or down */
+#define KBD_UP      0x80
+
+/* Usable information */
+#define KBD_KEYMASK 0x7f
+
+/* All keys up */
+#define KBD_IDLE    0x75
+#endif /* __LINUX_KBIO_H */
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/kdebug.h linux/include/asm-sparc/kdebug.h
--- v1.3.70/linux/include/asm-sparc/kdebug.h	Sat Nov 25 19:04:49 1995
+++ linux/include/asm-sparc/kdebug.h	Mon Mar  4 08:50:00 1996
@@ -1,4 +1,4 @@
-/* $Id: kdebug.h,v 1.7 1995/11/25 02:31:55 davem Exp $
+/* $Id: kdebug.h,v 1.8 1995/12/25 23:31:38 davem Exp $
  * kdebug.h:  Defines and definitions for debugging the Linux kernel
  *            under various kernel debuggers.
  *
@@ -71,5 +71,9 @@
 #define KDEBUG_DUNNO_OFF    0x4
 #define KDEBUG_DUNNO2_OFF   0x8
 #define KDEBUG_TEACH_OFF    0xc
+
+/* ugh... */
+#define TRAP_TRACE(reg1, reg2) \
+     
 
 #endif /* !(_SPARC_KDEBUG_H) */
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/kgdb.h linux/include/asm-sparc/kgdb.h
--- v1.3.70/linux/include/asm-sparc/kgdb.h	Sat Nov 25 19:04:49 1995
+++ linux/include/asm-sparc/kgdb.h	Mon Mar  4 08:50:01 1996
@@ -1,4 +1,4 @@
-/* $Id: kgdb.h,v 1.6 1995/11/25 02:31:57 davem Exp $
+/* $Id: kgdb.h,v 1.7 1995/11/27 02:43:18 davem Exp $
  * kgdb.h: Defines and declarations for serial line source level
  *         remote debugging of the Linux kernel using gdb.
  *
@@ -52,39 +52,39 @@
 #define KGDB_NPC    0x114
 
 #define SAVE_KGDB_GLOBALS(reg) \
-        std     %g0, [%reg + STACKFRAME_SZ + KGDB_G0]; \
-        std     %g2, [%reg + STACKFRAME_SZ + KGDB_G2]; \
-        std     %g4, [%reg + STACKFRAME_SZ + KGDB_G4]; \
-        std     %g6, [%reg + STACKFRAME_SZ + KGDB_G6];
+        std     %g0, [%reg + REGWIN_SZ + KGDB_G0]; \
+        std     %g2, [%reg + REGWIN_SZ + KGDB_G2]; \
+        std     %g4, [%reg + REGWIN_SZ + KGDB_G4]; \
+        std     %g6, [%reg + REGWIN_SZ + KGDB_G6];
 
 #define SAVE_KGDB_INS(reg) \
-        std     %i0, [%reg + STACKFRAME_SZ + KGDB_I0]; \
-        std     %i2, [%reg + STACKFRAME_SZ + KGDB_I2]; \
-        std     %i4, [%reg + STACKFRAME_SZ + KGDB_I4]; \
-        std     %i6, [%reg + STACKFRAME_SZ + KGDB_I6];
+        std     %i0, [%reg + REGWIN_SZ + KGDB_I0]; \
+        std     %i2, [%reg + REGWIN_SZ + KGDB_I2]; \
+        std     %i4, [%reg + REGWIN_SZ + KGDB_I4]; \
+        std     %i6, [%reg + REGWIN_SZ + KGDB_I6];
 
 #define SAVE_KGDB_SREGS(reg, reg_y, reg_psr, reg_wim, reg_tbr, reg_pc, reg_npc) \
-        st      %reg_y, [%reg + STACKFRAME_SZ + KGDB_Y]; \
-        st      %reg_psr, [%reg + STACKFRAME_SZ + KGDB_PSR]; \
-        st      %reg_wim, [%reg + STACKFRAME_SZ + KGDB_WIM]; \
-        st      %reg_tbr, [%reg + STACKFRAME_SZ + KGDB_TBR]; \
-        st      %reg_pc, [%reg + STACKFRAME_SZ + KGDB_PC]; \
-        st      %reg_npc, [%reg + STACKFRAME_SZ + KGDB_NPC];
+        st      %reg_y, [%reg + REGWIN_SZ + KGDB_Y]; \
+        st      %reg_psr, [%reg + REGWIN_SZ + KGDB_PSR]; \
+        st      %reg_wim, [%reg + REGWIN_SZ + KGDB_WIM]; \
+        st      %reg_tbr, [%reg + REGWIN_SZ + KGDB_TBR]; \
+        st      %reg_pc, [%reg + REGWIN_SZ + KGDB_PC]; \
+        st      %reg_npc, [%reg + REGWIN_SZ + KGDB_NPC];
 
 #define LOAD_KGDB_GLOBALS(reg) \
-        ld      [%reg + STACKFRAME_SZ + KGDB_G1], %g1; \
-        ldd     [%reg + STACKFRAME_SZ + KGDB_G2], %g2; \
-        ldd     [%reg + STACKFRAME_SZ + KGDB_G4], %g4; \
-        ldd     [%reg + STACKFRAME_SZ + KGDB_G6], %g6;
+        ld      [%reg + REGWIN_SZ + KGDB_G1], %g1; \
+        ldd     [%reg + REGWIN_SZ + KGDB_G2], %g2; \
+        ldd     [%reg + REGWIN_SZ + KGDB_G4], %g4; \
+        ldd     [%reg + REGWIN_SZ + KGDB_G6], %g6;
 
 #define LOAD_KGDB_INS(reg) \
-        ldd     [%reg + STACKFRAME_SZ + KGDB_I0], %i0; \
-        ldd     [%reg + STACKFRAME_SZ + KGDB_I2], %i2; \
-        ldd     [%reg + STACKFRAME_SZ + KGDB_I4], %i4; \
-        ldd     [%reg + STACKFRAME_SZ + KGDB_I6], %i6;
+        ldd     [%reg + REGWIN_SZ + KGDB_I0], %i0; \
+        ldd     [%reg + REGWIN_SZ + KGDB_I2], %i2; \
+        ldd     [%reg + REGWIN_SZ + KGDB_I4], %i4; \
+        ldd     [%reg + REGWIN_SZ + KGDB_I6], %i6;
 
 #define LOAD_KGDB_SREGS(reg, reg_y_and_psr, reg_pc_and_npc) \
-        ldd     [%reg + STACKFRAME_SZ + KGDB_Y], %reg_y_and_psr; \
-        ldd     [%reg + STACKFRAME_SZ + KGDB_PC], %reg_pc_and_npc;
+        ldd     [%reg + REGWIN_SZ + KGDB_Y], %reg_y_and_psr; \
+        ldd     [%reg + REGWIN_SZ + KGDB_PC], %reg_pc_and_npc;
 
 #endif /* !(_SPARC_KGDB_H) */
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/memreg.h linux/include/asm-sparc/memreg.h
--- v1.3.70/linux/include/asm-sparc/memreg.h	Sat Nov 25 19:04:49 1995
+++ linux/include/asm-sparc/memreg.h	Mon Mar  4 08:50:01 1996
@@ -1,4 +1,4 @@
-/* $Id: memreg.h,v 1.4 1995/11/25 02:32:02 davem Exp $ */
+/* $Id: memreg.h,v 1.5 1995/12/02 20:05:25 davem Exp $ */
 #ifndef _SPARC_MEMREG_H
 #define _SPARC_MEMREG_H
 /* memreg.h:  Definitions of the values found in the synchronous
@@ -22,7 +22,8 @@
 #define SUN4C_SYNC_BADWRITE  0x8000  /* while writing something went bogus */
 
 #define SUN4C_SYNC_BOLIXED  \
-        (SUN4C_SYNC_WDRESET|SUN4C_SYNC_SIZE|SUN4C_SYNC_SBUS|SUN4C_SYNC_NOMEM)
+        (SUN4C_SYNC_WDRESET | SUN4C_SYNC_SIZE | SUN4C_SYNC_SBUS | \
+         SUN4C_SYNC_NOMEM | SUN4C_SYNC_PARITY)
 
 /* Now the asynchronous error codes, these are almost always produced
  * by the cache writing things back to memory and getting a bad translation.
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/mman.h linux/include/asm-sparc/mman.h
--- v1.3.70/linux/include/asm-sparc/mman.h	Sat Nov 25 19:04:50 1995
+++ linux/include/asm-sparc/mman.h	Mon Mar  4 08:50:01 1996
@@ -1,4 +1,4 @@
-/* $Id: mman.h,v 1.5 1995/11/25 02:32:03 davem Exp $ */
+/* $Id: mman.h,v 1.6 1996/01/03 03:53:05 davem Exp $ */
 #ifndef __SPARC_MMAN_H__
 #define __SPARC_MMAN_H__
 
@@ -41,5 +41,9 @@
 #define MC_UNLOCK       3  /* Unlock pages locked via previous mctl() with MC_LOCK arg */
 #define MC_LOCKAS       5  /* Lock an entire address space of the calling process */
 #define MC_UNLOCKAS     6  /* Unlock entire address space of calling process */
+
+/* compatibility flags */
+#define MAP_ANON	MAP_ANONYMOUS
+#define MAP_FILE	0
 
 #endif /* __SPARC_MMAN_H__ */
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/mmu_context.h linux/include/asm-sparc/mmu_context.h
--- v1.3.70/linux/include/asm-sparc/mmu_context.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/mmu_context.h	Mon Mar  4 08:50:01 1996
@@ -0,0 +1,14 @@
+#ifndef __SPARC_MMU_CONTEXT_H
+#define __SPARC_MMU_CONTEXT_H
+
+/* For now I still leave the context handling in the
+ * switch_to() macro, I'll do it right soon enough.
+ */
+#define get_mmu_context(x) do { } while (0)
+
+/* Initialize the context related info for a new mm_struct
+ * instance.
+ */
+#define init_new_context(mm) ((mm)->context = NO_CONTEXT)
+
+#endif /* !(__SPARC_MMU_CONTEXT_H) */
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/oplib.h linux/include/asm-sparc/oplib.h
--- v1.3.70/linux/include/asm-sparc/oplib.h	Sat Nov 25 19:04:50 1995
+++ linux/include/asm-sparc/oplib.h	Mon Mar  4 08:50:01 1996
@@ -1,4 +1,4 @@
-/* $Id: oplib.h,v 1.5 1995/11/25 02:32:14 davem Exp $
+/* $Id: oplib.h,v 1.6 1996/01/01 02:47:19 davem Exp $
  * oplib.h:  Describes the interface and available routines in the
  *           Linux Prom library.
  *
@@ -257,6 +257,9 @@
  * node.  Returns null string on failure.
  */
 extern char *prom_nextprop(int node, char *prev_property);
+
+/* Returns 1 if the specified node has given property. */
+extern int prom_node_has_property(int node, char *property);
 
 /* Set the indicated property at the given node with the passed value.
  * Returns the number of bytes of your value that the prom took.
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/page.h linux/include/asm-sparc/page.h
--- v1.3.70/linux/include/asm-sparc/page.h	Sat Nov 25 19:04:50 1995
+++ linux/include/asm-sparc/page.h	Mon Mar  4 08:50:01 1996
@@ -1,4 +1,4 @@
-/* $Id: page.h,v 1.22 1995/11/25 02:32:16 davem Exp $
+/* $Id: page.h,v 1.26 1996/01/03 03:53:07 davem Exp $
  * page.h:  Various defines and such for MMU operations on the Sparc for
  *          the Linux kernel.
  *
@@ -8,22 +8,16 @@
 #ifndef _SPARC_PAGE_H
 #define _SPARC_PAGE_H
 
-#include <asm/asi.h>        /* for get/set segmap/pte routines */
-#include <asm/contregs.h>   /* for switch_to_context */
 #include <asm/head.h>       /* for KERNBASE */
 
-#define PAGE_SHIFT   12             /* This is the virtual page... */
+#define PAGE_SHIFT   12
 #define PAGE_OFFSET  KERNBASE
 #define PAGE_SIZE    (1 << PAGE_SHIFT)
-
-/* to mask away the intra-page address bits */
 #define PAGE_MASK    (~(PAGE_SIZE-1))
 
 #ifdef __KERNEL__
 #ifndef __ASSEMBLY__
 
-#include <asm/processor.h>
-
 /* The following structure is used to hold the physical
  * memory configuration of the machine.  This is filled in
  * probe_memory() and is later used by mem_init() to set up
@@ -41,6 +35,14 @@
 
 extern struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS];
 
+/* Cache alias structure.  Entry is valid if context != -1. */
+struct cache_palias {
+	unsigned long vaddr;
+	int context;
+};
+
+extern struct cache_palias *sparc_aliases;
+
 #define STRICT_MM_TYPECHECKS
 
 #ifdef STRICT_MM_TYPECHECKS
@@ -48,54 +50,59 @@
  * These are used to make use of C type-checking..
  */
 typedef struct { unsigned long pte; } pte_t;
+typedef struct { unsigned long iopte; } iopte_t;
 typedef struct { unsigned long pmd; } pmd_t;
 typedef struct { unsigned long pgd; } pgd_t;
+typedef struct { unsigned long ctxd; } ctxd_t;
 typedef struct { unsigned long pgprot; } pgprot_t;
+typedef struct { unsigned long iopgprot; } iopgprot_t;
 
 #define pte_val(x)	((x).pte)
+#define iopte_val(x)	((x).iopte)
 #define pmd_val(x)      ((x).pmd)
 #define pgd_val(x)	((x).pgd)
+#define ctxd_val(x)	((x).ctxd)
 #define pgprot_val(x)	((x).pgprot)
+#define iopgprot_val(x)	((x).iopgprot)
 
 #define __pte(x)	((pte_t) { (x) } )
+#define __iopte(x)	((iopte_t) { (x) } )
 #define __pmd(x)        ((pmd_t) { (x) } )
 #define __pgd(x)	((pgd_t) { (x) } )
+#define __ctxd(x)	((ctxd_t) { (x) } )
 #define __pgprot(x)	((pgprot_t) { (x) } )
+#define __iopgprot(x)	((iopgprot_t) { (x) } )
 
 #else
 /*
  * .. while these make it easier on the compiler
  */
 typedef unsigned long pte_t;
+typedef unsigned long iopte_t;
 typedef unsigned long pmd_t;
 typedef unsigned long pgd_t;
+typedef unsigned long ctxd_t;
 typedef unsigned long pgprot_t;
+typedef unsigned long iopgprot_t;
 
 #define pte_val(x)	(x)
+#define iopte_val(x)	(x)
 #define pmd_val(x)      (x)
 #define pgd_val(x)	(x)
+#define ctxd_val(x)	(x)
 #define pgprot_val(x)	(x)
+#define iopgprot_val(x)	(x)
 
 #define __pte(x)	(x)
+#define __iopte(x)	(x)
 #define __pmd(x)        (x)
 #define __pgd(x)	(x)
+#define __ctxd(x)	(x)
 #define __pgprot(x)	(x)
+#define __iopgprot(x)	(x)
 
 #endif
 
-/* The current va context is global and known, so all that is needed to
- * do an invalidate is flush the VAC on a sun4c or call the ASI flushing
- * routines on a SRMMU.
- */
-
-extern void (*invalidate)(void);
-
-/* Certain architectures need to do special things when pte's
- * within a page table are directly modified.  Thus, the following
- * hook is made available.
- */
-extern void (*set_pte)(pte_t *pteptr, pte_t pteval);
-
 /* to align the pointer to the (next) page boundary */
 #define PAGE_ALIGN(addr)  (((addr)+PAGE_SIZE-1)&PAGE_MASK)
 
@@ -105,214 +112,6 @@
 #define MAP_NR(addr) ((((unsigned long) (addr)) - PAGE_OFFSET) >> PAGE_SHIFT)
 
 #endif /* !(__ASSEMBLY__) */
-
-/* The rest is kind of funky because on the sparc, the offsets into the mmu 
- * entries are encoded in magic alternate address space tables. I will 
- * probably find some nifty inline assembly routines to do the equivalent. 
- * Much thought must go into this code.   (davem@caip.rutgers.edu)
- */
-
-/* Bitfields within a Sparc sun4c PTE (page table entry). */
-
-#define PTE_V     0x80000000   /* valid bit */
-#define PTE_ACC   0x60000000   /* access bits */
-#define PTE_W     0x40000000   /* writable bit */
-#define PTE_P     0x20000000   /* privileged page */
-#define PTE_NC    0x10000000   /* page is non-cacheable */
-#define PTE_TYP   0x0c000000   /* page type field */
-#define PTE_RMEM  0x00000000   /* type == on board real memory */
-#define PTE_IO    0x04000000   /* type == i/o area */
-#define PTE_VME16 0x08000000   /* type == 16-bit VME area */
-#define PTE_VME32 0x0c000000   /* type == 32-bit VME area */
-#define PTE_R     0x02000000   /* page has been referenced */
-#define PTE_M     0x01000000   /* page has been modified */
-#define PTE_RESV  0x00f80000   /* reserved bits */
-#define PTE_PHYPG 0x0007ffff   /* phys pg number, sun4c only uses 16bits */
-
-/* SRMMU defines */
-/* The fields in an srmmu virtual address when it gets translated.
- *
- *  -------------------------------------------------------------
- *  |   INDEX 1   |   INDEX 2   |   INDEX 3   |   PAGE OFFSET   |
- *  -------------------------------------------------------------
- *  31          24 23        18  17         12  11              0
- */
-#define SRMMU_IDX1_SHIFT      24
-#define SRMMU_IDX1_MASK       0xff000000
-#define SRMMU_IDX2_SHIFT      18
-#define SRMMU_IDX2_MASK       0x00fc0000
-#define SRMMU_IDX3_SHIFT      12
-#define SRMMU_IDX3_MASK       0x0003f000
-
-#define SRMMU_PGOFFSET_MASK   0x00000fff
-/* The page table sizes for the various levels in bytes. */
-#define SRMMU_LV1_PTSIZE      1024
-#define SRMMU_LV2_PTSIZE      256
-#define SRMMU_LV3_PTSIZE      256
-
-/* Definition of the values in the ET field of PTD's and PTE's */
-#define SRMMU_ET_INVALID      0x0
-#define SRMMU_ET_PTD          0x1
-#define SRMMU_ET_PTE          0x2
-#define SRMMU_ET_RESV         0x3
-#define SRMMU_ET_PTDBAD       0x3   /* Upward compatability my butt. */
-
-/* Page table directory bits.
- *
- * ----------------
- * |  PTP    | ET |
- * ----------------
- * 31       2 1  0
- *
- * PTP:  The physical page table pointer.  This value appears on
- *       bits 35->6 on the physical address bus during translation.
- *
- * ET:   Entry type field.  Must be 1 for a PTD.
- */
-
-#define SRMMU_PTD_PTP_SHIFT         0x2
-#define SRMMU_PTD_PTP_MASK          0xfffffffc
-#define SRMMU_PTD_PTP_PADDR_SHIFT   0x4
-#define SRMMU_PTD_ET_SHIFT          0x0
-#define SRMMU_PTD_ET_MASK           0x00000003
-
-/* Page table entry bits.
- *
- * -------------------------------------------------
- * |  Physical Page Number  | C | M | R | ACC | ET |
- * -------------------------------------------------
- * 31                     8   7   6   5  4   2  1  0
- *
- * PPN: Physical page number, high order 24 bits of the 36-bit
- *      physical address, thus is you mask off all the non
- *      PPN bits you have the physical address of your page.
- *      No shifting necessary.
- *
- * C:   Whether the page is cacheable in the mmu TLB or not.  If
- *      not set the CPU cannot cache values to these addresses. For
- *      IO space translations this bit should be clear.
- *
- * M:   Modified.  This tells whether the page has been written to
- *      since the bit was last cleared.  NOTE: this does not include
- *      accesses via the ASI physical page pass through since that does
- *      not use the MMU.
- *
- * R:   References.  This tells whether the page has been referenced
- *      in any way shape or form since the last clearing of the bit.
- *      NOTE: this does not include accesses via the ASI physical page
- *      pass through since that does not use the MMU.
- *
- * ACC: Access permissions for this page.  This is further explained below
- *      with appropriate macros.
- */
-
-#define SRMMU_PTE_PPN_SHIFT         0x8
-#define SRMMU_PTE_PPN_MASK          0xffffff00
-#define SRMMU_PTE_PPN_PADDR_SHIFT   0x4
-#define SRMMU_PTE_C_SHIFT           0x7
-#define SRMMU_PTE_C_MASK            0x00000080
-#define SRMMU_PTE_M_SHIFT           0x6
-#define SRMMU_PTE_M_MASK            0x00000040
-#define SRMMU_PTE_R_SHIFT           0x5
-#define SRMMU_PTE_R_MASK            0x00000020
-#define SRMMU_PTE_ACC_SHIFT         0x2
-#define SRMMU_PTE_ACC_MASK          0x0000001c
-#define SRMMU_PTE_ET_SHIFT          0x0
-#define SRMMU_PTE_ET_MASK           0x00000003
-
-/* SRMMU pte access bits.
- *
- * BIT    USER ACCESS          SUPERVISOR ACCESS
- * ---    --------------       -----------------
- * 0x0    read only            read only
- * 0x1    read&write           read&write
- * 0x2    read&execute         read&execute
- * 0x3    read&write&execute   read&write&execute
- * 0x4    execute only         execute only
- * 0x5    read only            read&write
- * 0x6    ACCESS DENIED        read&execute
- * 0x7    ACCESS DENIED        read&write&execute
- *
- * All these values are shifted left two bits.
- */
-
-#define SRMMU_ACC_US_RDONLY      0x00
-#define SRMMU_ACC_US_RDWR        0x04
-#define SRMMU_ACC_US_RDEXEC      0x08
-#define SRMMU_ACC_US_RDWREXEC    0x0c
-#define SRMMU_ACC_US_EXECONLY    0x10
-#define SRMMU_ACC_U_RDONLY       0x14
-#define SRMMU_ACC_S_RDWR         0x14
-#define SRMMU_ACC_U_ACCDENIED    0x18
-#define SRMMU_ACC_S_RDEXEC       0x18
-#define SRMMU_ACC_U_ACCDENIED2   0x1c
-#define SRMMU_ACC_S_RDWREXEC     0x1c
-
-#ifndef __ASSEMBLY__
-
-/* SUN4C pte, segmap, and context manipulation */
-extern __inline__ unsigned long get_segmap(unsigned long addr)
-{
-  register unsigned long entry;
-
-  __asm__ __volatile__("\n\tlduba [%1] %2, %0\n\t" : 
-		       "=r" (entry) :
-		       "r" (addr), "i" (ASI_SEGMAP));
-
-  return entry;
-}
-
-extern __inline__ void put_segmap(unsigned long addr, unsigned long entry)
-{
-
-  __asm__ __volatile__("\n\tstba %1, [%0] %2\n\t" : :
-		       "r" (addr), "r" (entry),
-		       "i" (ASI_SEGMAP));
-
-  return;
-}
-
-extern __inline__ unsigned long get_pte(unsigned long addr)
-{
-  register unsigned long entry;
-
-  __asm__ __volatile__("\n\tlda [%1] %2, %0\n\t" : 
-		       "=r" (entry) :
-		       "r" (addr), "i" (ASI_PTE));
-  return entry;
-}
-
-extern __inline__ void put_pte(unsigned long addr, unsigned long entry)
-{
-  __asm__ __volatile__("\n\tsta %1, [%0] %2\n\t" : :
-		       "r" (addr), 
-		       "r" (entry), "i" (ASI_PTE));
-
-  return;
-}
-
-extern void (*switch_to_context)(void *tsk);
-
-extern __inline__ int get_context(void)
-{
-  register int ctx;
-
-  __asm__ __volatile__("\n\tlduba [%1] %2, %0\n\t" :
-		       "=r" (ctx) :
-		       "r" (AC_CONTEXT), "i" (ASI_CONTROL));
-
-  return ctx;
-}
-
-extern __inline__ int set_context(int ctx)
-{
-  __asm__ __volatile__("\n\tstba %0, [%1] %2\n\t" : :
-		       "r" (ctx), "r" (AC_CONTEXT), "i" (ASI_CONTROL));
-
-  return ctx;
-}
-
-#endif /* __ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/pgtable.h linux/include/asm-sparc/pgtable.h
--- v1.3.70/linux/include/asm-sparc/pgtable.h	Sat Nov 25 19:04:51 1995
+++ linux/include/asm-sparc/pgtable.h	Mon Mar  4 08:50:01 1996
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.25 1995/11/25 02:32:22 davem Exp $ */
+/* $Id: pgtable.h,v 1.35 1996/02/21 17:57:30 miguel Exp $ */
 #ifndef _SPARC_PGTABLE_H
 #define _SPARC_PGTABLE_H
 
@@ -14,23 +14,23 @@
 #include <asm/pgtsrmmu.h>
 #include <asm/vac-ops.h>
 #include <asm/oplib.h>
+#include <asm/sbus.h>
 
 extern void load_mmu(void);
 
+extern void (*quick_kernel_fault)(unsigned long);
+
 /* mmu-specific process creation/cloning/etc hooks. */
-extern void (*mmu_exit_hook)(void *);
-extern void (*mmu_fork_hook)(void *, unsigned long);
-extern void (*mmu_release_hook)(void *);
-extern void (*mmu_flush_hook)(void *);
-extern void (*mmu_task_cacheflush)(void *);
+extern void (*mmu_exit_hook)(void);
+extern void (*mmu_flush_hook)(void);
 
 /* Routines for data transfer buffers. */
 extern char *(*mmu_lockarea)(char *, unsigned long);
 extern void  (*mmu_unlockarea)(char *, unsigned long);
 
 /* Routines for getting a dvma scsi buffer. */
-extern char *(*mmu_get_scsi_buffer)(char *, unsigned long);
-extern void  (*mmu_release_scsi_buffer)(char *, unsigned long);
+extern char *(*mmu_get_scsi_buffer)(char *, unsigned long, struct linux_sbus *sbus);
+extern void  (*mmu_release_scsi_buffer)(char *, unsigned long, struct linux_sbus *sbus);
 
 extern unsigned int pmd_shift;
 extern unsigned int pmd_size;
@@ -58,7 +58,6 @@
 extern pgprot_t page_copy;
 extern pgprot_t page_readonly;
 extern pgprot_t page_kernel;
-extern pgprot_t page_invalid;
 
 #define PMD_SHIFT      (pmd_shift)
 #define PMD_SIZE       (pmd_size)
@@ -127,11 +126,11 @@
 extern pte_t __bad_page(void);
 extern pte_t * __bad_pagetable(void);
 
-extern unsigned long __zero_page(void);
+extern unsigned long empty_zero_page;
 
 #define BAD_PAGETABLE __bad_pagetable()
 #define BAD_PAGE __bad_page()
-#define ZERO_PAGE __zero_page()
+#define ZERO_PAGE (&empty_zero_page)
 
 /* number of bits that fit into a memory pointer */
 #define BITS_PER_PTR      (8*sizeof(unsigned long))
@@ -145,17 +144,6 @@
 extern unsigned long (*pmd_page)(pmd_t);
 extern unsigned long (*pgd_page)(pgd_t);
 
-/* to set the page-dir
- *
- * On the Sparc the page segments hold 64 pte's which means 256k/segment.
- * Therefore there is no global idea of 'the' page directory, although we
- * make a virtual one in kernel memory so that we can keep the stats on
- * all the pages since not all can be loaded at once in the mmu.
- *
- * Actually on the SRMMU things do work exactly like the i386, the
- * page tables live in real physical ram, no funky TLB buisness.
- */
-
 extern void (*sparc_update_rootmmu_dir)(struct task_struct *, pgd_t *pgdir);
 
 #define SET_PAGE_DIR(tsk,pgdir) sparc_update_rootmmu_dir(tsk, pgdir)
@@ -190,31 +178,23 @@
  * The following only work if pte_present() is true.
  * Undefined behaviour if not..
  */
-extern int (*pte_read)(pte_t);
 extern int (*pte_write)(pte_t);
-extern int (*pte_exec)(pte_t);
 extern int (*pte_dirty)(pte_t);
 extern int (*pte_young)(pte_t);
-extern int (*pte_cow)(pte_t);
 
 extern pte_t (*pte_wrprotect)(pte_t);
-extern pte_t (*pte_rdprotect)(pte_t);
-extern pte_t (*pte_exprotect)(pte_t);
 extern pte_t (*pte_mkclean)(pte_t);
 extern pte_t (*pte_mkold)(pte_t);
-extern pte_t (*pte_uncow)(pte_t);
 extern pte_t (*pte_mkwrite)(pte_t);
-extern pte_t (*pte_mkread)(pte_t);
-extern pte_t (*pte_mkexec)(pte_t);
 extern pte_t (*pte_mkdirty)(pte_t);
 extern pte_t (*pte_mkyoung)(pte_t);
-extern pte_t (*pte_mkcow)(pte_t);
 
 /*
  * Conversion functions: convert a page and protection to a page entry,
  * and a page entry and page directory to the page they refer to.
  */
 extern pte_t (*mk_pte)(unsigned long, pgprot_t);
+extern pte_t (*mk_pte_io)(unsigned long, pgprot_t);
 
 extern void (*pgd_set)(pgd_t *, pmd_t *);
 
@@ -262,29 +242,50 @@
 
 extern pgd_t * (*pgd_alloc)(void);
 
+/* Fine grained invalidation. */
+extern void (*invalidate_all)(void);
+extern void (*invalidate_mm)(struct mm_struct *);
+extern void (*invalidate_range)(struct mm_struct *, unsigned long start, unsigned long end);
+extern void (*invalidate_page)(struct vm_area_struct *, unsigned long address);
+
+/* The permissions for pgprot_val to make a page mapped on the obio space */
+extern unsigned int pg_iobits;
+
+/* MMU context switching. */
+extern void (*switch_to_context)(struct task_struct *tsk);
+
+/* Certain architectures need to do special things when pte's
+ * within a page table are directly modified.  Thus, the following
+ * hook is made available.
+ */
+extern void (*set_pte)(pte_t *pteptr, pte_t pteval);
+
+extern char *(*mmu_info)(void);
+
 /* Fault handler stuff... */
 #define FAULT_CODE_PROT     0x1
 #define FAULT_CODE_WRITE    0x2
 #define FAULT_CODE_USER     0x4
-extern int (*get_fault_info)(unsigned long *, unsigned long *, unsigned long);
 extern void (*update_mmu_cache)(struct vm_area_struct *vma, unsigned long address, pte_t pte);
 
 extern int invalid_segment;
 
-#define SWP_TYPE(entry) (((entry) >> 1) & 0x7f)
-#define SWP_OFFSET(entry) ((entry) >> 8)
-#define SWP_ENTRY(type,offset) (((type) << 1) | ((offset) << 8))
+#define SWP_TYPE(entry) (((entry)>>2) & 0x7f)
+#define SWP_OFFSET(entry) ((entry) >> 9)
+#define SWP_ENTRY(type,offset) (((type) << 2) | ((offset) << 9))
 
 struct ctx_list {
 	struct ctx_list *next;
 	struct ctx_list *prev;
 	unsigned char ctx_number;
-	struct task_struct *ctx_task; /* Who has it now, if not free */
+	struct mm_struct *ctx_mm;
 };
 
 extern struct ctx_list *ctx_list_pool;  /* Dynamically allocated */
 extern struct ctx_list ctx_free;        /* Head of free list */
 extern struct ctx_list ctx_used;        /* Head of used contexts list */
+
+#define NO_CONTEXT     -1
 
 extern inline void remove_from_ctx_list(struct ctx_list *entry)
 {
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/pgtsrmmu.h linux/include/asm-sparc/pgtsrmmu.h
--- v1.3.70/linux/include/asm-sparc/pgtsrmmu.h	Sat Nov 25 19:04:51 1995
+++ linux/include/asm-sparc/pgtsrmmu.h	Mon Mar  4 08:50:02 1996
@@ -1,23 +1,19 @@
-/* $Id: pgtsrmmu.h,v 1.9 1995/11/25 02:32:24 davem Exp $
+/* $Id: pgtsrmmu.h,v 1.13 1996/03/01 07:20:54 davem Exp $
  * pgtsrmmu.h:  SRMMU page table defines and code.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  */
 
-#include <asm/page.h>  /* just in case */
-
 #ifndef _SPARC_PGTSRMMU_H
 #define _SPARC_PGTSRMMU_H
 
-#define SRMMU_PAGE_TABLE_SIZE 0x100 /* 64 entries, 4 bytes a piece */
-#define SRMMU_PMD_TABLE_SIZE  0x100 /* 64 entries, 4 bytes a piece */
-#define SRMMU_PGD_TABLE_SIZE  0x400 /* 256 entries, 4 bytes a piece */
+#include <asm/page.h>
 
 /* PMD_SHIFT determines the size of the area a second-level page table can map */
-#define SRMMU_PMD_SHIFT       18
-#define SRMMU_PMD_SIZE        (1UL << SRMMU_PMD_SHIFT)
-#define SRMMU_PMD_MASK        (~(SRMMU_PMD_SIZE-1))
-#define SRMMU_PMD_ALIGN(addr) (((addr)+SRMMU_PMD_SIZE-1)&SRMMU_PMD_MASK)
+#define SRMMU_PMD_SHIFT         18
+#define SRMMU_PMD_SIZE          (1UL << SRMMU_PMD_SHIFT)
+#define SRMMU_PMD_MASK          (~(SRMMU_PMD_SIZE-1))
+#define SRMMU_PMD_ALIGN(addr)   (((addr)+SRMMU_PMD_SIZE-1)&SRMMU_PMD_MASK)
 
 /* PGDIR_SHIFT determines what a third-level page table entry can map */
 #define SRMMU_PGDIR_SHIFT       24
@@ -25,195 +21,115 @@
 #define SRMMU_PGDIR_MASK        (~(SRMMU_PGDIR_SIZE-1))
 #define SRMMU_PGDIR_ALIGN(addr) (((addr)+SRMMU_PGDIR_SIZE-1)&SRMMU_PGDIR_MASK)
 
-/*
- * Three-level on SRMMU.
- */
-
-#define SRMMU_PTRS_PER_PTE    64
-#define SRMMU_PTRS_PER_PMD    64
-#define SRMMU_PTRS_PER_PGD    256
-
-/* Just any arbitrary offset to the start of the vmalloc VM area: the
- * current 8MB value just means that there will be a 8MB "hole" after the
- * physical memory until the kernel virtual memory starts.  That means that
- * any out-of-bounds memory accesses will hopefully be caught.
- * The vmalloc() routines leaves a hole of 4kB between each vmalloced
- * area for the same reason. ;)
- */
-#define SRMMU_VMALLOC_OFFSET  (8*1024*1024)
-#define SRMMU_VMALLOC_START ((high_memory + SRMMU_VMALLOC_OFFSET) & ~(SRMMU_VMALLOC_OFFSET-1))
-
-/*
- * Sparc SRMMU page table fields.
- */
+#define SRMMU_PTRS_PER_PTE      64
+#define SRMMU_PTRS_PER_PMD      64
+#define SRMMU_PTRS_PER_PGD      256
+
+#define SRMMU_PTE_TABLE_SIZE    0x100 /* 64 entries, 4 bytes a piece */
+#define SRMMU_PMD_TABLE_SIZE    0x100 /* 64 entries, 4 bytes a piece */
+#define SRMMU_PGD_TABLE_SIZE    0x400 /* 256 entries, 4 bytes a piece */
+
+#define SRMMU_VMALLOC_START   (0xfe100000)
+
+/* Definition of the values in the ET field of PTD's and PTE's */
+#define SRMMU_ET_MASK         0x3
+#define SRMMU_ET_INVALID      0x0
+#define SRMMU_ET_PTD          0x1
+#define SRMMU_ET_PTE          0x2
+#define SRMMU_ET_REPTE        0x3 /* AIEEE, SuperSparc II reverse endian page! */
+
+/* Physical page extraction from PTP's and PTE's. */
+#define SRMMU_CTX_PMASK    0xfffffff0
+#define SRMMU_PTD_PMASK    0xfffffff0
+#define SRMMU_PTE_PMASK    0xffffff00
+
+/* The pte non-page bits.  Some notes:
+ * 1) cache, dirty, valid, and ref are frobbable
+ *    for both supervisor and user pages.
+ * 2) exec and write will only give the desired effect
+ *    on user pages
+ * 3) use priv and priv_readonly for changing the
+ *    characteristics of supervisor ptes
+ */
+#define SRMMU_CACHE        0x80
+#define SRMMU_DIRTY        0x40
+#define SRMMU_REF          0x20
+#define SRMMU_EXEC         0x08
+#define SRMMU_WRITE        0x04
+#define SRMMU_VALID        0x02 /* SRMMU_ET_PTE */
+#define SRMMU_PRIV         0x1c
+#define SRMMU_PRIV_RDONLY  0x18
+
+#define SRMMU_CHG_MASK    (SRMMU_REF | SRMMU_DIRTY | SRMMU_ET_PTE)
+
+/* Some day I will implement true fine grained access bits for
+ * user pages because the SRMMU gives us the capabilities to
+ * enforce all the protection levels that vma's can have.
+ * XXX But for now...
+ */
+#define SRMMU_PAGE_NONE    __pgprot(SRMMU_VALID | SRMMU_CACHE | \
+				    SRMMU_PRIV | SRMMU_REF)
+#define SRMMU_PAGE_SHARED  __pgprot(SRMMU_VALID | SRMMU_CACHE | \
+				    SRMMU_EXEC | SRMMU_WRITE | SRMMU_REF)
+#define SRMMU_PAGE_COPY    __pgprot(SRMMU_VALID | SRMMU_CACHE | \
+				    SRMMU_EXEC | SRMMU_REF)
+#define SRMMU_PAGE_RDONLY  __pgprot(SRMMU_VALID | SRMMU_CACHE | \
+				    SRMMU_EXEC | SRMMU_REF)
+#define SRMMU_PAGE_KERNEL  __pgprot(SRMMU_VALID | SRMMU_CACHE | SRMMU_PRIV)
 
-#define _SRMMU_PAGE_VALID      (SRMMU_ET_PTE)
-#define _SRMMU_PMD_VALID       (SRMMU_ET_PTD)
-#define _SRMMU_PGD_VALID       (SRMMU_ET_PTD)
-#define _SRMMU_PAGE_WRITE_USR  (SRMMU_ACC_US_RDWR)
-#define _SRMMU_PAGE_WRITE_KERN (SRMMU_ACC_S_RDWR)
-#define _SRMMU_PAGE_EXEC       (SRMMU_ACC_US_RDEXEC)
-#define _SRMMU_PAGE_RDONLY     (SRMMU_ACC_US_RDONLY)
-#define _SRMMU_PAGE_NOREAD     (SRMMU_ACC_U_ACCDENIED)
-#define _SRMMU_PAGE_NOCACHE    (~SRMMU_PTE_C_MASK)
-#define _SRMMU_PAGE_PRIV       (SRMMU_ACC_S_RDWREXEC)
-#define _SRMMU_PAGE_REF        (SRMMU_PTE_R_MASK)
-#define _SRMMU_PAGE_DIRTY      (SRMMU_PTE_M_MASK)
-#define _SRMMU_PAGE_COW        (SRMMU_ACC_U_RDONLY)
-#define _SRMMU_PAGE_UNCOW      (SRMMU_ACC_US_RDWR)
-
-/* We want the swapper not to swap out page tables, thus dirty and writable
- * so that the kernel can change the entries as needed. Also valid for
- * obvious reasons.
+/* SRMMU Register addresses in ASI 0x4.  These are valid for all
+ * current SRMMU implementations that exist.
  */
-#define _SRMMU_PAGE_TABLE     (_SRMMU_PAGE_VALID | _SRMMU_PAGE_WRITE_KERN | _SRMMU_PAGE_REF | _SRMMU_PAGE_DIRTY)
-#define _SRMMU_PAGE_CHG_MASK  (_SRMMU_PAGE_REF | _SRMMU_PAGE_DIRTY | SRMMU_ET_PTE)
-#define _SRMMU_PMD_CHG_MASK   (SRMMU_ET_PTD)
-#define _SRMMU_PGD_CHG_MASK   (SRMMU_ET_PTD)
-
-#define SRMMU_PAGE_NONE       __pgprot(_SRMMU_PAGE_VALID | _SRMMU_PAGE_REF)
-#define SRMMU_PAGE_SHARED     __pgprot(_SRMMU_PAGE_VALID | _SRMMU_PAGE_WRITE_USR | _SRMMU_PAGE_REF)
-#define SRMMU_PAGE_COPY       __pgprot(_SRMMU_PAGE_VALID | _SRMMU_PAGE_REF | _SRMMU_PAGE_COW)
-#define SRMMU_PAGE_READONLY   __pgprot(_SRMMU_PAGE_VALID | _SRMMU_PAGE_REF | SRMMU_ACC_US_RDONLY)
-#define SRMMU_PAGE_KERNEL     __pgprot(_SRMMU_PAGE_VALID | _SRMMU_PAGE_PRIV | SRMMU_PTE_C_MASK)
-#define SRMMU_PAGE_INVALID    __pgprot(SRMMU_ET_INVALID)
-
-#define _SRMMU_PAGE_NORMAL(x) __pgprot(_SRMMU_PAGE_VALID | _SRMMU_PAGE_REF | (x))
-
-/* SRMMU Register addresses */
 #define SRMMU_CTRL_REG           0x00000000
 #define SRMMU_CTXTBL_PTR         0x00000100
 #define SRMMU_CTX_REG            0x00000200
 #define SRMMU_FAULT_STATUS       0x00000300
 #define SRMMU_FAULT_ADDR         0x00000400
-#define SRMMU_AFAULT_STATUS      0x00000500
-#define SRMMU_AFAULT_ADDR        0x00000600
 
-/* The SRMMU control register fields:
- * -------------------------------------------------------------------
- * | IMPL  |  VERS  |    SysControl | PSO | Resv | No Fault | Enable |
- * -------------------------------------------------------------------
- * 31    28 27    24 23            8   7    6   2      1        0
- *
- * IMPL:  Indicates the implementation of this SRMMU, read-only.
- * VERS:  The version of this implementation, again read-only.
- * SysControl:  This is an implementation specific field, the SRMMU
- *              specification does not define anything for this field.
- * PSO: This determines whether the memory model as seen by the CPU
- *      is Partial Store Order (PSO=1) or Total Store Ordering (PSO=0).
- * Resv: Don't touch these bits ;)
- * No Fault: If zero, any fault acts as expected where the fault status
- *           and address registers are updated and a trap hits the CPU.
- *           When this bit is one, on any fault other than in ASI 9, the
- *           MMU updates the status and address fault registers but does
- *           not signal the CPU with a trap.  This is useful to beat
- *           race conditions in low-level code when we have to throw
- *           a register window onto the stack in a spill/fill handler
- *           on multiprocessors.
- * Enable: If one the MMU is doing translations, if zero the addresses
- *         given to the bus are pure physical.
- */
-
-#define SRMMU_CTREG_IMPL_MASK        0xf0000000
-#define SRMMU_CTREG_IMPL_SHIFT       28
-#define SRMMU_CTREG_VERS_MASK        0x0f000000
-#define SRMMU_CTREG_VERS_SHIFT       24
-#define SRMMU_CTREG_SYSCNTRL_MASK    0x00ffff00
-#define SRMMU_CTREG_SYSCNTRL_SHIFT   8
-#define SRMMU_CTREG_PSO_MASK         0x00000080
-#define SRMMU_CTREG_PSO_SHIFT        7
-#define SRMMU_CTREG_RESV_MASK        0x0000007c
-#define SRMMU_CTREG_RESV_SHIFT       2
-#define SRMMU_CTREG_NOFAULT_MASK     0x00000002
-#define SRMMU_CTREG_NOFAULT_SHIFT    1
-#define SRMMU_CTREG_ENABLE_MASK      0x00000001
-#define SRMMU_CTREG_ENABLE_SHIFT     0
-
-/* Get the MMU control register */
+/* Accessing the MMU control register. */
 extern inline unsigned int srmmu_get_mmureg(void)
 {
-        register unsigned int retval;
+        unsigned int retval;
 	__asm__ __volatile__("lda [%%g0] %1, %0\n\t" :
 			     "=r" (retval) :
 			     "i" (ASI_M_MMUREGS));
 	return retval;
 }
 
-/* Set the MMU control register */
 extern inline void srmmu_set_mmureg(unsigned long regval)
 {
 	__asm__ __volatile__("sta %0, [%%g0] %1\n\t" : :
 			     "r" (regval), "i" (ASI_M_MMUREGS) : "memory");
 
-	return;
 }
 
-/* The SRMMU Context Table Pointer Register:
- * ---------------------------------
- * |  Context Table Pointer | Resv |
- * ---------------------------------
- * 31                      2 1    0
- *
- * This is where the MMU goes to in physical RAM to fetch the
- * elements in the context table.  The non-Resv bits of this
- * address appear in bits 6-35 of the physical bus during miss
- * processing, then indexed by the value in the Context Register.
- * This table must be aligned on a boundary equal to the size of
- * the table, we provide a nice macro for doing this based upon
- * the significant bits in the context register.
- */
-#define SRMMU_CTP_ADDR_MASK          0xfffffffc
-#define SRMMU_CTP_ADDR_PADDR_SHIFT   0x4
-#define SRMMU_CTP_RESV_MASK          0x00000003
-
-#define SRMMU_SIGBITS_TO_ALIGNMENT(numbits)  ((1 << (numbits + 2)))
-
-
-/* Set the address of the context table.  You pass this routine
- * the physical address, we do the magic shifting for you.
- */
 extern inline void srmmu_set_ctable_ptr(unsigned long paddr)
 {
-	unsigned long ctp;
-
-	ctp = (paddr >> SRMMU_CTP_ADDR_PADDR_SHIFT);
-	ctp &= SRMMU_CTP_ADDR_MASK;
-
+	paddr = ((paddr >> 4) & SRMMU_CTX_PMASK);
 	__asm__ __volatile__("sta %0, [%1] %2\n\t" : :
-			     "r" (ctp), "r" (SRMMU_CTXTBL_PTR),
+			     "r" (paddr), "r" (SRMMU_CTXTBL_PTR),
 			     "i" (ASI_M_MMUREGS) :
 			     "memory");
-	return;
 }
 
-
-/* Get the address of the context table.  We return the physical
- * address of the table, again we do the shifting here.
- */
 extern inline unsigned long srmmu_get_ctable_ptr(void)
 {
-	register unsigned int retval;
+	unsigned int retval;
 
 	__asm__ __volatile__("lda [%1] %2, %0\n\t" :
 			     "=r" (retval) :
 			     "r" (SRMMU_CTXTBL_PTR),
 			     "i" (ASI_M_MMUREGS));
-
-	retval &= SRMMU_CTP_ADDR_MASK;
-	retval = (retval << SRMMU_CTP_ADDR_PADDR_SHIFT);
-	return retval;
+	return (retval & SRMMU_CTX_PMASK) << 4;
 }
 
-/* Set the context on an SRMMU */
 extern inline void srmmu_set_context(int context)
 {
 	__asm__ __volatile__("sta %0, [%1] %2\n\t" : :
 			     "r" (context), "r" (SRMMU_CTX_REG),
 			     "i" (ASI_M_MMUREGS) : "memory");
-	return;
 }
 
-/* Get the context on an SRMMU */
 extern inline int srmmu_get_context(void)
 {
 	register int retval;
@@ -224,122 +140,9 @@
 	return retval;
 }
 
-/* SRMMU diagnostic register:
- * --------------------------------------------------------
- * |   Virtual Address   |   PDC entry   | DiagReg | Resv |
- * --------------------------------------------------------
- * 31                  12 11            4 3       2 1    0
- *
- * An SRMMU implementation has the choice of providing this register
- * and I don't know much about it.
- */
-
-#define SRMMU_DIAG_VADDR_MASK        0xfffff000
-#define SRMMU_DIAG_PDC_MASK          0x00000ff0
-#define SRMMU_DIAG_REG_MASK          0x0000000c
-#define SRMMU_DIAG_RESV_MASK         0x00000003
-
-/* SRMMU Fault Status Register:
- * -----------------------------------------------------------
- * | Reserved          | EBE  |  L  |  AT  |  FT  | FAV | OW |
- * -----------------------------------------------------------
- *  31               18 17  10  9  8 7    5  4   2   1     0
- *
- * WARNING!!! On certain VERY BROKEN Viking Sun4d modules this register
- * is complete TOAST!  During a fault you cannot trust the values
- * contained in this register, you must calculate them yourself
- * by first using the trap program counter to decode the
- * instruction the code tried to execute (ie. load or store) and
- * the address they tried to access.  I think the Fault Virtual
- * Address register may be ok on these chips, but who knows. Grrr.
- *
- * Reserved:  These bits must be zero.
- * EBE: External bus error bits, implementation dependant (at least
- *      we know what the bits mean on sun4d Viking modules) ;)
- * L: The level in tree traversal at which the fault occured. The
- *    values are... 0 = context table
- *                  1 = level-1 page table
- *                  2 = level-2 page table
- *                  3 = level-3 page table
- * AT: Access type field. This is decoded as follows...
- *     0 -- Load from user data space
- *     1 -- Load from supervisor data space
- *     2 -- Read/Execute from user instruction space
- *     3 -- Read/Execute from supervisor instruction space
- *     4 -- Store to user data space
- *     5 -- Store to supervisor data space
- *     6 -- Store to user instruction space
- *     7 -- Store to supervisor instruction space (emacs does this)
- *     On the Viking --  TOAST!
- * FT:  This is the fault type field.  It is used to determine what was
- *      wrong in the attempted translation. It can be one of...
- *     0 -- None
- *     1 -- Invalid address error
- *     2 -- Protection violation error
- *     3 -- Priviledge violation error
- *     4 -- Translation error (your tables are fucked up)
- *     5 -- Bus access error (you lose)
- *     6 -- Internal error (might as well have a Viking)
- *     7 -- Reserved (don't touch)
- * FAV: Fault Address Valid bit.  When set to one the fault address
- *      register contents are valid.  It need not be valid for text
- *      faults as the trapped PC tells us this anyway.
- * OW: The Overwrite Bit, if set to one, this register has been
- *     written to more than once by the hardware since software did
- *     a read.  This mean multiple faults have occurred and you have
- *     to a manual page table tree traversal to continue the handling
- *     of the first fault. And on the Viking module....
- *
- * The Fault Address Register is just a 32-bit register representing the
- * virtual address which caused the fault.  It's validity is determined
- * by the following equation:
- * if(module==VIKING || FSR.FAV==0) forget_it();
- * It's ok for the FAV to be invalid for a text fault because we can
- * use the trapped program counter, however for a data fault we are SOL.
- * I'll probably have to write a workaround for this situation too ;-(
- */
-
-#define SRMMU_FSR_RESV_MASK      0xfffc0000  /* Reserved bits */
-#define SRMMU_FSR_EBE_MASK       0x0003fc00  /* External Bus Error bits */
-#define SRMMU_FSR_EBE_BERR       0x00000400  /* Bus Error */
-#define SRMMU_FSR_EBE_BTIMEO     0x00000800  /* Bus Time Out */
-#define SRMMU_FSR_EBE_UNCOR      0x00001000  /* Uncorrectable Error */
-#define SRMMU_FSR_EBE_UNDEF      0x00002000  /* Undefined Error */
-#define SRMMU_FSR_EBE_PARITY     0x00004000  /* Parity error */
-#define SRMMU_FSR_EBE_TPARITY    0x00006000  /* Tsunami parity error */
-#define SRMMU_FSR_EBE_SBUF       0x00008000  /* Store Buffer error */
-#define SRMMU_FSR_EBE_CSA        0x00010000  /* Control space access error (bad ASI) */
-#define SRMMU_FSR_EBE_EMRT       0x00020000  /* Viking Emergency Response Team */
-#define SRMMU_FSR_L_MASK         0x00000300  /* Fault level bits */
-#define SRMMU_FSR_L_CTABLE       0x00000000  /* Context table level flt/err */
-#define SRMMU_FSR_L_ONE          0x00000100  /* Level1 ptable flt/err */
-#define SRMMU_FSR_L_TWO          0x00000200  /* Level2 ptable flt/err */
-#define SRMMU_FSR_L_THREE        0x00000300  /* Level3 ptable flt/err */
-#define SRMMU_FSR_AT_MASK        0x000000e0  /* Access Type bits */
-#define SRMMU_FSR_AT_LUD         0x00000000  /* Load from User Data space */
-#define SRMMU_FSR_AT_LSD         0x00000020  /* What I'll need after writing this code */
-#define SRMMU_FSR_AT_RXUI        0x00000040  /* Read/Execute from user text */
-#define SRMMU_FSR_AT_RXSI        0x00000060  /* Read/Execute from supv text */
-#define SRMMU_FSR_AT_SUD         0x00000080  /* Store to user data space */
-#define SRMMU_FSR_AT_SSD         0x000000a0  /* Store to supv data space */
-#define SRMMU_FSR_AT_SUI         0x000000c0  /* Store to user text */
-#define SRMMU_FSR_AT_SSI         0x000000e0  /* Store to supv text */
-#define SRMMU_FSR_FT_MASK        0x0000001c  /* Fault Type bits */
-#define SRMMU_FSR_FT_NONE        0x00000000  /* No fault occurred */
-#define SRMMU_FSR_FT_IADDR       0x00000002  /* Invalid address */
-#define SRMMU_FSR_FT_PROT        0x00000004  /* Protection violation */
-#define SRMMU_FSR_FT_PRIV        0x00000008  /* Privilege violation */
-#define SRMMU_FSR_FT_TRANS       0x0000000a  /* Translation error */
-#define SRMMU_FSR_FT_BACC        0x0000000c  /* Bus Access error */
-#define SRMMU_FSR_FT_IACC        0x0000000e  /* Internal error */
-#define SRMMU_FSR_FT_RESV        0x00000010  /* Reserved, should not get this */
-#define SRMMU_FSR_FAV_MASK       0x00000002  /* Fault Address Valid bits */
-#define SRMMU_FSR_OW_MASK        0x00000001  /* SFSR OverWritten bits */
-
-/* Read the Fault Status Register on the SRMMU */
 extern inline unsigned int srmmu_get_fstatus(void)
 {
-	register unsigned int retval;
+	unsigned int retval;
 
 	__asm__ __volatile__("lda [%1] %2, %0\n\t" :
 			     "=r" (retval) :
@@ -347,10 +150,9 @@
 	return retval;
 }
 
-/* Read the Fault Address Register on the SRMMU */
 extern inline unsigned int srmmu_get_faddr(void)
 {
-	register unsigned int retval;
+	unsigned int retval;
 
 	__asm__ __volatile__("lda [%1] %2, %0\n\t" :
 			     "=r" (retval) :
@@ -358,59 +160,52 @@
 	return retval;
 }
 
-/* SRMMU Asynchronous Fault Status Register:
- * -----------------------------------------
- * |  RESERVED |UCE|BTO|BERR|RSV|HFADDR|AFO|
- * -----------------------------------------
- *  31       13  12  11  10  9-8  7-4     0
- *
- * UCE: UnCorrectable Error
- * BTO: Bus TimeOut
- * BERR: Genreic Bus Error
- * HFADDR: High 4 bits of the faulting address
- * AFO: Asynchronous Fault Occurred
- */
-#define SRMMU_AFSR_RESVMASK  0xffffe000
-#define SRMMU_AFSR_UCE       0x00001000
-#define SRMMU_AFSR_BTO       0x00000800
-#define SRMMU_AFSR_BERR      0x00000400
-#define SRMMU_AFSR_HFADDR    0x000000f0
-#define SRMMU_AFSR_AFO       0x00000001
+/* This is guarenteed on all SRMMU's. */
+extern inline void srmmu_flush_whole_tlb(void)
+{
+	__asm__ __volatile__("sta %%g0, [%0] %1\n\t": :
+			     "r" (0x400),        /* Flush entire TLB!! */
+			     "i" (ASI_M_FLUSH_PROBE) : "memory");
+
+}
 
-/* Read the asynchronous fault register */
-extern inline unsigned int srmmu_get_afstatus(void)
+/* These flush types are not available on all chips... */
+extern inline void srmmu_flush_tlb_ctx(void)
 {
-	register unsigned int retval;
+	__asm__ __volatile__("sta %%g0, [%0] %1\n\t": :
+			     "r" (0x300),        /* Flush TLB ctx.. */
+			     "i" (ASI_M_FLUSH_PROBE) : "memory");
 
-	__asm__ __volatile__("lda [%1] %2, %0\n\t" :
-			     "=r" (retval) :
-			     "r" (SRMMU_AFAULT_STATUS), "i" (ASI_M_MMUREGS));
-	return retval;
 }
 
-/* Read the Asynchronous Fault Address Register on the SRMMU */
-extern inline unsigned int srmmu_get_afaddr(void)
+extern inline void srmmu_flush_tlb_region(unsigned long addr)
 {
-	register unsigned int retval;
+	addr &= SRMMU_PGDIR_MASK;
+	__asm__ __volatile__("sta %%g0, [%0] %1\n\t": :
+			     "r" (addr | 0x200), /* Flush TLB region.. */
+			     "i" (ASI_M_FLUSH_PROBE) : "memory");
 
-	__asm__ __volatile__("lda [%1] %2, %0\n\t" :
-			     "=r" (retval) :
-			     "r" (SRMMU_AFAULT_ADDR), "i" (ASI_M_MMUREGS));
-	return retval;
 }
 
 
-/* Flush the entire TLB cache on the SRMMU. */
-extern inline void srmmu_flush_whole_tlb(void)
+extern inline void srmmu_flush_tlb_segment(unsigned long addr)
 {
+	addr &= SRMMU_PMD_MASK;
 	__asm__ __volatile__("sta %%g0, [%0] %1\n\t": :
-			     "r" (0x400),        /* Flush entire TLB!! */
+			     "r" (addr | 0x100), /* Flush TLB segment.. */
+			     "i" (ASI_M_FLUSH_PROBE) : "memory");
+
+}
+
+extern inline void srmmu_flush_tlb_page(unsigned long page)
+{
+	page &= PAGE_MASK;
+	__asm__ __volatile__("sta %%g0, [%0] %1\n\t": :
+			     "r" (page),        /* Flush TLB page.. */
 			     "i" (ASI_M_FLUSH_PROBE) : "memory");
 
-	return;
 }
 
-/* Probe for an entry in the page-tables of the SRMMU. */
 extern inline unsigned long srmmu_hwprobe(unsigned long vaddr)
 {
 	unsigned long retval;
@@ -421,5 +216,8 @@
 
 	return retval;
 }
+
+extern unsigned long (*srmmu_read_physical)(unsigned long paddr);
+extern void (*srmmu_write_physical)(unsigned long paddr, unsigned long word);
 
 #endif /* !(_SPARC_PGTSRMMU_H) */
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/pgtsun4c.h linux/include/asm-sparc/pgtsun4c.h
--- v1.3.70/linux/include/asm-sparc/pgtsun4c.h	Sat Nov 25 19:04:51 1995
+++ linux/include/asm-sparc/pgtsun4c.h	Mon Mar  4 08:50:02 1996
@@ -1,4 +1,4 @@
-/* $Id: pgtsun4c.h,v 1.16 1995/11/25 02:32:28 davem Exp $
+/* $Id: pgtsun4c.h,v 1.22 1996/01/24 02:33:45 davem Exp $
  * pgtsun4c.h:  Sun4c specific pgtable.h defines and code.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -19,7 +19,7 @@
 #define SUN4C_PGDIR_ALIGN(addr) (((addr)+SUN4C_PGDIR_SIZE-1)&SUN4C_PGDIR_MASK)
 
 /* To represent how the sun4c mmu really lays things out. */
-#define SUN4C_REAL_PGDIR_SHIFT  18
+#define SUN4C_REAL_PGDIR_SHIFT       18
 #define SUN4C_REAL_PGDIR_SIZE        (1UL << SUN4C_REAL_PGDIR_SHIFT)
 #define SUN4C_REAL_PGDIR_MASK        (~(SUN4C_REAL_PGDIR_SIZE-1))
 #define SUN4C_REAL_PGDIR_ALIGN(addr) (((addr)+SUN4C_REAL_PGDIR_SIZE-1)&SUN4C_REAL_PGDIR_MASK)
@@ -50,12 +50,7 @@
 #define _SUN4C_PAGE_IO        0x04000000   /* I/O page */
 #define _SUN4C_PAGE_REF       0x02000000   /* Page has been accessed/referenced */
 #define _SUN4C_PAGE_DIRTY     0x01000000   /* Page has been modified, is dirty */
-#define _SUN4C_PAGE_COW       0x00800000   /* COW page */
 
-/* Note that the 'non-cacheable' bit is not set in any of these settings,
- * you may want to turn it on for debugging the flushing of the virtual
- * cache on the SUN4C MMU.
- */
 #define _SUN4C_PAGE_CHG_MASK  (0xffff | _SUN4C_PAGE_REF | _SUN4C_PAGE_DIRTY)
 
 #define SUN4C_PAGE_NONE     __pgprot(_SUN4C_PAGE_VALID | _SUN4C_PAGE_PRIV | \
@@ -63,25 +58,12 @@
 #define SUN4C_PAGE_SHARED   __pgprot(_SUN4C_PAGE_VALID | _SUN4C_PAGE_WRITE | \
 				     _SUN4C_PAGE_USER | _SUN4C_PAGE_REF)
 #define SUN4C_PAGE_COPY     __pgprot(_SUN4C_PAGE_VALID | _SUN4C_PAGE_USER | \
-				     _SUN4C_PAGE_REF | _SUN4C_PAGE_COW)
+				     _SUN4C_PAGE_REF)
 #define SUN4C_PAGE_READONLY __pgprot(_SUN4C_PAGE_VALID | _SUN4C_PAGE_USER | \
 				     _SUN4C_PAGE_REF)
 #define SUN4C_PAGE_KERNEL   __pgprot(_SUN4C_PAGE_VALID | _SUN4C_PAGE_WRITE | \
 				     _SUN4C_PAGE_PRIV | _SUN4C_PAGE_DIRTY | \
-				     _SUN4C_PAGE_REF)
-#define SUN4C_PAGE_INVALID  __pgprot(0)
-
-struct pseg_list {
-	struct pseg_list *next;
-	struct pseg_list *prev;
-	struct pseg_list *ctx_next;
-	struct pseg_list *ctx_prev;
-	unsigned long vaddr;    /* Where the pseg is mapped. */
-	unsigned char context;  /* The context in which it is mapped. */
-	unsigned char pseg;     /* The pseg itself. */
-        unsigned ref_cnt:21,
-                 hardlock:1;
-};
+				     _SUN4C_PAGE_REF | _SUN4C_PAGE_NOCACHE)
 
 extern char *sun4c_lockarea(char *vaddr, unsigned long size);
 extern void sun4c_unlockarea(char *vaddr, unsigned long size);
@@ -104,6 +86,66 @@
 			     "=r" (sync_addr) :
 			     "r" (AC_SYNC_VA), "i" (ASI_CONTROL));
 	return sync_addr;
+}
+
+/* SUN4C pte, segmap, and context manipulation */
+extern __inline__ unsigned long sun4c_get_segmap(unsigned long addr)
+{
+  register unsigned long entry;
+
+  __asm__ __volatile__("\n\tlduba [%1] %2, %0\n\t" : 
+		       "=r" (entry) :
+		       "r" (addr), "i" (ASI_SEGMAP));
+
+  return entry;
+}
+
+extern __inline__ void sun4c_put_segmap(unsigned long addr, unsigned long entry)
+{
+
+  __asm__ __volatile__("\n\tstba %1, [%0] %2\n\t" : :
+		       "r" (addr), "r" (entry),
+		       "i" (ASI_SEGMAP));
+
+  return;
+}
+
+extern __inline__ unsigned long sun4c_get_pte(unsigned long addr)
+{
+  register unsigned long entry;
+
+  __asm__ __volatile__("\n\tlda [%1] %2, %0\n\t" : 
+		       "=r" (entry) :
+		       "r" (addr), "i" (ASI_PTE));
+  return entry;
+}
+
+extern __inline__ void sun4c_put_pte(unsigned long addr, unsigned long entry)
+{
+  __asm__ __volatile__("\n\tsta %1, [%0] %2\n\t" : :
+		       "r" (addr), 
+		       "r" (entry), "i" (ASI_PTE));
+
+  return;
+}
+
+extern __inline__ int sun4c_get_context(void)
+{
+  register int ctx;
+
+  __asm__ __volatile__("\n\tlduba [%1] %2, %0\n\t" :
+		       "=r" (ctx) :
+		       "r" (AC_CONTEXT), "i" (ASI_CONTROL));
+
+  return ctx;
+}
+
+extern __inline__ int sun4c_set_context(int ctx)
+{
+  __asm__ __volatile__("\n\tstba %0, [%1] %2\n\t" : :
+		       "r" (ctx), "r" (AC_CONTEXT), "i" (ASI_CONTROL));
+
+  return ctx;
 }
 
 #endif /* !(_SPARC_PGTSUN4C_H) */
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/processor.h linux/include/asm-sparc/processor.h
--- v1.3.70/linux/include/asm-sparc/processor.h	Mon Nov 27 12:48:36 1995
+++ linux/include/asm-sparc/processor.h	Mon Mar  4 08:50:02 1996
@@ -1,4 +1,4 @@
-/* $Id: processor.h,v 1.29 1995/11/26 05:01:29 davem Exp $
+/* $Id: processor.h,v 1.40 1996/02/03 10:06:01 davem Exp $
  * include/asm-sparc/processor.h
  *
  * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
@@ -7,12 +7,13 @@
 #ifndef __ASM_SPARC_PROCESSOR_H
 #define __ASM_SPARC_PROCESSOR_H
 
-#include <linux/string.h>
+#include <linux/a.out.h>
 
 #include <asm/psr.h>
 #include <asm/ptrace.h>
 #include <asm/head.h>
 #include <asm/signal.h>
+#include <asm/segment.h>
 
 /*
  * Bus types
@@ -34,6 +35,7 @@
 /* The Sparc processor specific thread struct. */
 struct thread_struct {
 	unsigned long uwinmask __attribute__ ((aligned (8)));
+	struct pt_regs *kregs;
 
 	/* For signal handling */
 	unsigned long sig_address __attribute__ ((aligned (8)));
@@ -45,6 +47,10 @@
 	unsigned long kpsr;
 	unsigned long kwim;
 
+	/* Special child fork kpsr/kwim values. */
+	unsigned long fork_kpsr __attribute__ ((aligned (8)));
+	unsigned long fork_kwim;
+
 	/* A place to store user windows and stack pointers
 	 * when the stack needs inspection.
 	 */
@@ -53,15 +59,6 @@
 	unsigned long rwbuf_stkptrs[NSWINS] __attribute__ ((aligned (8)));
 	unsigned long w_saved;
 
-	/* Where our page table lives. */
-	unsigned long pgd_ptr;
-
-	/* The context currently allocated to this process
-	 * or -1 if no context has been allocated to this
-	 * task yet.
-	 */
-	int context;
-
 	/* Floating point regs */
 	unsigned long   float_regs[64] __attribute__ ((aligned (8)));
 	unsigned long   fsr;
@@ -71,20 +68,27 @@
 		unsigned long insn;
 	} fpqueue[16];
 	struct sigstack sstk_info;
+	unsigned long flags;
+	int current_ds;
+	struct exec core_exec;     /* just what it says. */
 };
 
-#define INIT_MMAP { &init_mm, (0xf0000000UL), (0xfe100000UL), \
+#define SPARC_FLAG_KTHREAD      0x1    /* task is a kernel thread */
+
+#define INIT_MMAP { &init_mm, (0), (0), \
 		    __pgprot(0x0) , VM_READ | VM_WRITE | VM_EXEC }
 
 #define INIT_TSS  { \
-/* uwinmask, sig_address, sig_desc, ksp, kpc, kpsr, kwim */ \
-   0,        0,           0,        0,   0,   0,    0, \
+/* uwinmask, kregs, sig_address, sig_desc, ksp, kpc, kpsr, kwim */ \
+   0,        0,     0,           0,        0,   0,   0,    0, \
+/* fork_kpsr, fork_kwim */ \
+   0,         0, \
 /* reg_window */  \
 { { { 0, }, { 0, } }, }, \
 /* rwbuf_stkptrs */  \
 { 0, 0, 0, 0, 0, 0, 0, 0, }, \
-/* w_saved, pgd_ptr,                context */  \
-   0,       (long) &swapper_pg_dir, -1, \
+/* w_saved */ \
+   0, \
 /* FPU regs */   { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
@@ -93,19 +97,39 @@
    0,          0,  { { 0, 0, }, }, \
 /* sstk_info */ \
 { 0, 0, }, \
+/* flags,              current_ds, */ \
+   SPARC_FLAG_KTHREAD, USER_DS, \
+/* core_exec */ \
+{ 0, }, \
 }
 
 /* Return saved PC of a blocked thread. */
 extern inline unsigned long thread_saved_pc(struct thread_struct *t)
 {
-	return ((struct pt_regs *)
-		((t->ksp&(~0xfff))+(0x1000-TRACEREG_SZ)))->pc;
+	return t->kregs->pc;
 }
 
 /*
  * Do necessary setup to start up a newly executed thread.
  */
-extern void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp);
+extern inline void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp)
+{
+	unsigned long saved_psr = (regs->psr & (PSR_CWP)) | PSR_S;
+	int i;
 
-#endif /* __ASM_SPARC_PROCESSOR_H */
+	for(i = 0; i < 16; i++) regs->u_regs[i] = 0;
+	regs->y = 0;
+	regs->pc = ((pc & (~3)) - 4);
+	regs->npc = regs->pc + 4;
+	regs->psr = saved_psr;
+	regs->u_regs[UREG_G1] = sp; /* Base of arg/env stack area */
+	regs->u_regs[UREG_G2] = regs->u_regs[UREG_G7] = regs->npc;
+	regs->u_regs[UREG_FP] = (sp - REGWIN_SZ);
+}
 
+extern unsigned long (*alloc_kernel_stack)(struct task_struct *tsk);
+extern void (*free_kernel_stack)(unsigned long stack);
+extern struct task_struct *(*alloc_task_struct)(void);
+extern void (*free_task_struct)(struct task_struct *tsk);
+
+#endif /* __ASM_SPARC_PROCESSOR_H */
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/psr.h linux/include/asm-sparc/psr.h
--- v1.3.70/linux/include/asm-sparc/psr.h	Sat Nov 25 19:04:51 1995
+++ linux/include/asm-sparc/psr.h	Mon Mar  4 08:50:03 1996
@@ -1,4 +1,4 @@
-/* $Id: psr.h,v 1.5 1995/11/25 02:32:31 davem Exp $
+/* $Id: psr.h,v 1.10 1996/03/01 07:20:57 davem Exp $
  * psr.h: This file holds the macros for masking off various parts of
  *        the processor status register on the Sparc. This is valid
  *        for Version 8. On the V9 this is renamed to the PSTATE
@@ -11,10 +11,6 @@
 #ifndef __LINUX_SPARC_PSR_H
 #define __LINUX_SPARC_PSR_H
 
-#define __LINUX_SPARC_V8  /* duh */
-
-#ifdef __LINUX_SPARC_V8
-
 /* The Sparc PSR fields are laid out as the following:
  *
  *  ------------------------------------------------------------------------
@@ -22,7 +18,6 @@
  *  | 31-28 | 27-24 | 23-20 | 19-14 | 13 | 12 | 11-8 | 7 | 6  | 5  |  4-0  |
  *  ------------------------------------------------------------------------
  */
-
 #define PSR_CWP     0x0000001f         /* current window pointer     */
 #define PSR_ET      0x00000020         /* enable traps field         */
 #define PSR_PS      0x00000040         /* previous privilege level   */
@@ -30,6 +25,7 @@
 #define PSR_PIL     0x00000f00         /* processor interrupt level  */
 #define PSR_EF      0x00001000         /* enable floating point      */
 #define PSR_EC      0x00002000         /* enable co-processor        */
+#define PSR_LE      0x00008000         /* SuperSparcII little-endian */
 #define PSR_ICC     0x00f00000         /* integer condition codes    */
 #define PSR_C       0x00100000         /* carry bit                  */
 #define PSR_V       0x00200000         /* overflow bit               */
@@ -38,6 +34,8 @@
 #define PSR_VERS    0x0f000000         /* cpu-version field          */
 #define PSR_IMPL    0xf0000000         /* cpu-implementation field   */
 
+#ifdef __KERNEL__
+
 #ifndef __ASSEMBLY__
 /* Get the %psr register. */
 extern inline unsigned int get_psr(void)
@@ -50,8 +48,9 @@
 
 extern inline void put_psr(unsigned int new_psr)
 {
-  __asm__("wr %0, 0x0, %%psr\n\t" : :
-	  "r" (new_psr));
+	__asm__ __volatile__("wr %0, 0x0, %%psr\n\t"
+			     "nop; nop; nop;\n\t" : :
+			     "r" (new_psr));
 }
 
 /* Get the %fsr register.  Be careful, make sure the floating point
@@ -74,101 +73,6 @@
 
 #endif /* !(__ASSEMBLY__) */
 
-#endif /* !(__LINUX_SPARC_V8) */
-
-#ifdef __LINUX_SPARC_V9
-
-/* The information available in the %psr on the V8 is spread amongst
- * a whole bunch of registers on the V9. The main one being PSTATE.
- *
- *   --------------------------------------------------------
- *   |  CLE  | TLE |  MM  | RED | PEF | AM | PRIV | IE | AG |
- *   |   9   |  8  |  7-6 |  5  |  4  |  3 |   2  |  1 |  0 |
- *   --------------------------------------------------------
- *
- * Writes and reads to PSTATE are done via 'wrpr' and 'rdpr' instructions.
- *
- * For example:  wrpr %o2, or'd_bit_pattern, %pstate
- *               rdpr %pstate, %o3
- */
-
-#define PSTATE_AG    0x001   /* Alternate Globals             */
-#define PSTATE_IE    0x002   /* Interrupt Enable              */
-#define PSTATE_PRIV  0x004   /* Current privilege level       */
-#define PSTATE_AM    0x008   /* Address mask (data reads can  */
-			     /* be chosen to be either big or */
-			     /* little endian on V9).         */
-#define PSTATE_PEF   0x010   /* enable floating point         */
-#define PSTATE_RED   0x020   /* RED trap state (set if trap   */
-                             /* trap_level == max_tl).        */
-#define PSTATE_MM    0x0c0   /* Memory model (Total Store     */
-                             /* Order=0, Partial Store Order  */
-                             /* =1 or Relaxed Memory Order=2) */
-#define PSTATE_TLE   0x100   /* Trap Little Endian            */
-#define PSTATE_CLE   0x200   /* Current Little Endian         */
-
-
-extern inline unsigned int get_v9_pstate(void)
-{
-	unsigned int pstate;
-	__asm__ __volatile__("rdpr %pstate, %0\n\t" :
-			     "=r" (pstate));
-	return pstate;
-}
-
-extern inline void put_v9_pstate(unsigned int pstate)
-{
-	__asm__ __volatile__("wrpr %0, 0x0, %pstate\n\t" : :
-			     "r" (pstate));
-	return;
-}
-
-/* The Version Register holds vendor information for the chip:
- *
- *  ---------------------------------------------------------------------------
- *  | manufacturer | implementation | mask | reserved | maxtl | resv | maxwin |
- *  |  63-48       |   47-32        | 31-24|   23-16  | 15-8  | 7-5  |  4-0   |
- *  ---------------------------------------------------------------------------
- *
- */
-
-#define VERS_MAXWIN  0x000000000000001f     /* 'nwindows' on this chip       */
-#define VERS_MAXTL   0x00000000000ff000     /* Maximum Trap-level supported  */
-#define VERS_MASK    0x0000000ff0000000     /* impl. dep. chip mask revision */
-#define VERS_MANUF   0xffff000000000000     /* Manufacturer ID code          */
-
-extern inline unsigned int get_v9_version(void)
-{
-	unsigned int vers;
-	__asm__ __volatile__("rdpr %ver, %0\n\t" :
-			     "=r" (vers));
-	return vers;
-}
-
-extern inline unsigned int get_v9_tstate(void)
-{
-	unsigned int tstate;
-	__asm__ __volatile__("rdpr %tstate, %0\n\t" :
-			     "=r" (pstate));
-	return tstate;
-}
-
-extern inline unsigned int get_v9_pil(void)
-{
-	unsigned int pil;
-	__asm__ __volatile__("rdpr %pil, %0\n\t" :
-			     "=r" (pstate));
-	return pil;
-}
-
-extern inline void put_v9_pil(unsigned int pil)
-{
-	__asm__ __volatile__("wrpr %0, 0x0, %pil\n\t" : :
-			     "r" (pil));
-	return;
-}
-
-
-#endif /* !(__LINUX_SPARC_V9) */
+#endif /* (__KERNEL__) */
 
 #endif /* !(__LINUX_SPARC_PSR_H) */
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/ptrace.h linux/include/asm-sparc/ptrace.h
--- v1.3.70/linux/include/asm-sparc/ptrace.h	Sat Nov 25 19:04:51 1995
+++ linux/include/asm-sparc/ptrace.h	Mon Mar  4 08:50:03 1996
@@ -1,4 +1,4 @@
-/* $Id: ptrace.h,v 1.14 1995/11/25 02:32:33 davem Exp $ */
+/* $Id: ptrace.h,v 1.19 1996/01/24 02:33:50 davem Exp $ */
 #ifndef _SPARC_PTRACE_H
 #define _SPARC_PTRACE_H
 
@@ -35,6 +35,7 @@
 #define UREG_I6        14
 #define UREG_I7        15
 #define UREG_WIM       UREG_G0
+#define UREG_FADDR     UREG_G0
 #define UREG_FP        UREG_I6
 #define UREG_RETPC     UREG_I7
 
@@ -73,7 +74,7 @@
 #define REGWIN_SZ         0x40
 #endif
 
-/* First generic task_struct offsets. sizeof(task_struct)=1536 */
+/* First generic task_struct offsets. sizeof(task_struct)=1576 */
 #define TASK_STATE        0x000
 #define TASK_PRIORITY     0x008
 #define TASK_SIGNAL       0x00c
@@ -90,14 +91,16 @@
 #define THREAD_KPC        0x224
 #define THREAD_KPSR       0x228
 #define THREAD_KWIM       0x22c
-#define THREAD_REG_WINDOW 0x230
-#define THREAD_STACK_PTRS 0x430
-#define THREAD_W_SAVED    0x450
-#define THREAD_PGD_PTR    0x454
-#define THREAD_CONTEXT    0x458
+#define THREAD_FORK_KPSR  0x230
+#define THREAD_FORK_KWIM  0x234
+#define THREAD_REG_WINDOW 0x238
+#define THREAD_STACK_PTRS 0x438
+#define THREAD_W_SAVED    0x458
 #define THREAD_FLOAT_REGS 0x460
 #define THREAD_FSR        0x560
 #define THREAD_SIGSTK     0x5e8
+#define THREAD_MM     0x620
+#define THREAD_MM_CTX     0x008
 
 /* These are for pt_regs. */
 #define PT_PSR    0x0
@@ -166,5 +169,26 @@
 #define SF_XARG4  0x54
 #define SF_XARG5  0x58
 #define SF_XXARG  0x5c
+
+/* Stuff for the ptrace system call */
+#if 0 /* Need to fix the header files a bit... */
+#undef PTRACE_ATTACH
+#undef PTRACE_DETACH
+#define PTRACE_ATTACH		  10
+#define PTRACE_DETACH		  11
+#endif
+#define PTRACE_GETREGS            12
+#define PTRACE_SETREGS            13
+#define PTRACE_GETFPREGS          14
+#define PTRACE_SETFPREGS          15
+#define PTRACE_READDATA           16
+#define PTRACE_WRITEDATA          17
+#define PTRACE_READTEXT           18
+#define PTRACE_WRITETEXT          19
+#define PTRACE_GETFPAREGS         20
+#define PTRACE_SETFPAREGS         21
+
+#define PTRACE_GETUCODE           29  /* stupid bsd-ism */
+
 
 #endif /* !(_SPARC_PTRACE_H) */
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/ross.h linux/include/asm-sparc/ross.h
--- v1.3.70/linux/include/asm-sparc/ross.h	Sat Nov 25 19:04:51 1995
+++ linux/include/asm-sparc/ross.h	Mon Mar  4 08:50:03 1996
@@ -1,4 +1,4 @@
-/* $Id: ross.h,v 1.3 1995/11/25 02:32:37 davem Exp $
+/* $Id: ross.h,v 1.4 1996/01/03 03:53:20 davem Exp $
  * ross.h: Ross module specific definitions and defines.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -7,6 +7,8 @@
 #ifndef _SPARC_ROSS_H
 #define _SPARC_ROSS_H
 
+#include <asm/asi.h>
+
 /* Ross made Hypersparcs have a %psr 'impl' field of '0001'.  The 'vers'
  * field has '1111'.
  */
@@ -51,7 +53,7 @@
 #define HYPERSPARC_MENABLE    0x00000001
 
 /* Flushes which clear out only the on-chip Ross HyperSparc ICACHE. */
-extern inline void flush_i_page(unsigned int addr)
+extern inline void hyper_flush_i_page(unsigned int addr)
 {
 	__asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
 			     "r" (addr), "i" (ASI_M_IFLUSH_PAGE) :
@@ -59,7 +61,7 @@
 	return;
 }
 
-extern inline void flush_i_seg(unsigned int addr)
+extern inline void hyper_flush_i_seg(unsigned int addr)
 {
 	__asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
 			     "r" (addr), "i" (ASI_M_IFLUSH_SEG) :
@@ -67,7 +69,7 @@
 	return;
 }
 
-extern inline void flush_i_region(unsigned int addr)
+extern inline void hyper_flush_i_region(unsigned int addr)
 {
 	__asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
 			     "r" (addr), "i" (ASI_M_IFLUSH_REGION) :
@@ -75,7 +77,7 @@
 	return;
 }
 
-extern inline void flush_i_ctx(unsigned int addr)
+extern inline void hyper_flush_i_ctx(unsigned int addr)
 {
 	__asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
 			     "r" (addr), "i" (ASI_M_IFLUSH_CTX) :
@@ -83,7 +85,7 @@
 	return;
 }
 
-extern inline void flush_i_user(unsigned int addr)
+extern inline void hyper_flush_i_user(unsigned int addr)
 {
 	__asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
 			     "r" (addr), "i" (ASI_M_IFLUSH_USER) :
@@ -92,7 +94,7 @@
 }
 
 /* Finally, flush the entire ICACHE. */
-extern inline void flush_whole_icache(void)
+extern inline void hyper_flush_whole_icache(void)
 {
 	__asm__ __volatile__("sta %%g0, [%%g0] %0\n\t" : :
 			     "i" (ASI_M_FLUSH_IWHOLE));
@@ -148,5 +150,20 @@
 
 	return;
 }
+
+/* HyperSparc specific cache flushing. */
+
+extern int hyper_cache_size;
+
+extern inline void hyper_flush_all_combined(void)
+{
+	unsigned long addr;
+
+	for(addr = 0; addr < hyper_cache_size; addr += 32)
+		__asm__ __volatile__("sta %%g0, [%0] 0xe\n\t" : :
+				     "r" (addr));
+}
+
+
 
 #endif /* !(_SPARC_ROSS_H) */
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/sbus.h linux/include/asm-sparc/sbus.h
--- v1.3.70/linux/include/asm-sparc/sbus.h	Sat Nov 25 19:04:51 1995
+++ linux/include/asm-sparc/sbus.h	Mon Mar  4 08:50:03 1996
@@ -1,4 +1,4 @@
-/* $Id: sbus.h,v 1.8 1995/11/25 02:32:38 davem Exp $
+/* $Id: sbus.h,v 1.9 1996/02/15 09:13:03 davem Exp $
  * sbus.h:  Defines for the Sun SBus.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -8,6 +8,7 @@
 #define _SPARC_SBUS_H
 
 #include <asm/oplib.h>
+#include <asm/iommu.h>
 
 /* We scan which devices are on the SBus using the PROM node device
  * tree.  SBus devices are described in two different ways.  You can
@@ -64,11 +65,12 @@
 
 /* This struct describes the SBus(s) found on this machine. */
 struct linux_sbus {
-  struct linux_sbus *next;             /* next SBus, if more than one SBus */
-  struct linux_sbus_device *devices;   /* Link to devices on this SBus */
-  int prom_node;                       /* PROM device tree node for this SBus */
-  char prom_name[64];                  /* Usually "sbus" */
-  int clock_freq;
+	struct linux_sbus *next;             /* next SBus, if more than one SBus */
+	struct linux_sbus_device *devices;   /* Link to devices on this SBus */
+	struct iommu_struct *iommu;          /* IOMMU for this sbus if applicable */
+	int prom_node;                       /* PROM device tree node for this SBus */
+	char prom_name[64];                  /* Usually "sbus" */
+	int clock_freq;
 };
 
 extern struct linux_sbus *SBus_chain;
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/segment.h linux/include/asm-sparc/segment.h
--- v1.3.70/linux/include/asm-sparc/segment.h	Sat Nov 25 19:04:51 1995
+++ linux/include/asm-sparc/segment.h	Mon Mar  4 08:50:03 1996
@@ -1,12 +1,7 @@
-/* $Id: segment.h,v 1.6 1995/11/25 02:32:40 davem Exp $ */
+/* $Id: segment.h,v 1.9 1996/01/14 00:05:33 davem Exp $ */
 #ifndef _ASM_SEGMENT_H
 #define _ASM_SEGMENT_H
 
-/* Sparc is not segmented, these are just place holders. */
-#define KERNEL_DS   0
-#define USER_DS     1
-
-#include <linux/string.h>
 #include <asm/vac-ops.h>
 
 #ifndef __ASSEMBLY__
@@ -109,21 +104,27 @@
 
 #define memcpy_tofs(to, from, n) memcpy((to),(from),(n))
 
-extern int current_user_segment;
+/* Sparc is not segmented, however we need to be able to fool verify_area()
+ * when doing system calls from kernel mode legitimately.
+ */
+#define KERNEL_DS   0
+#define USER_DS     1
+
+extern int active_ds;
 
-static inline unsigned long get_fs(void)
+static inline int get_fs(void)
 {
-	return current_user_segment;
+	return active_ds;
 }
 
-static inline unsigned long get_ds(void)
+static inline int get_ds(void)
 {
 	return KERNEL_DS;
 }
 
-static inline void set_fs(unsigned long val)
+static inline void set_fs(int val)
 {
-	current_user_segment = val;
+	active_ds = val;
 }
 
 #endif  /* __ASSEMBLY__ */
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/sigcontext.h linux/include/asm-sparc/sigcontext.h
--- v1.3.70/linux/include/asm-sparc/sigcontext.h	Sat Nov 25 19:04:51 1995
+++ linux/include/asm-sparc/sigcontext.h	Mon Mar  4 08:50:03 1996
@@ -1,9 +1,13 @@
-/* $Id: sigcontext.h,v 1.7 1995/11/25 02:32:44 davem Exp $ */
+/* $Id: sigcontext.h,v 1.8 1996/03/01 07:20:59 davem Exp $ */
 #ifndef _ASMsparc_SIGCONTEXT_H
 #define _ASMsparc_SIGCONTEXT_H
 
 #include <asm/ptrace.h>
 
+#define SUNOS_MAXWIN   31
+
+#ifndef __ASSEMBLY__
+
 /* SunOS system call sigstack() uses this arg. */
 struct sunos_sigstack {
 	unsigned long sig_sp;
@@ -11,7 +15,6 @@
 };
 
 /* This is what SunOS does, so shall I. */
-#define SUNOS_MAXWIN   31
 struct sigcontext_struct {
 	int sigc_onstack;      /* state to restore */
 	int sigc_mask;         /* sigmask to restore */
@@ -33,5 +36,7 @@
 	/* Windows to restore after signal */
 	struct reg_window sigc_wbuf[SUNOS_MAXWIN];
 };
+#endif /* !(__ASSEMBLY__) */
 
 #endif /* !(_ASMsparc_SIGCONTEXT_H) */
+
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/signal.h linux/include/asm-sparc/signal.h
--- v1.3.70/linux/include/asm-sparc/signal.h	Sat Mar  2 10:43:44 1996
+++ linux/include/asm-sparc/signal.h	Mon Mar  4 08:50:03 1996
@@ -1,7 +1,9 @@
-/* $Id: signal.h,v 1.14 1995/11/25 02:32:46 davem Exp $ */
+/* $Id: signal.h,v 1.17 1996/03/01 07:21:02 davem Exp $ */
 #ifndef _ASMSPARC_SIGNAL_H
 #define _ASMSPARC_SIGNAL_H
 
+#include <asm/sigcontext.h>
+
 /* On the Sparc the signal handlers get passed a 'sub-signal' code
  * for certain signal types, which we document here.
  */
@@ -15,7 +17,7 @@
 #define    SUBSIG_STACK       0
 #define    SUBSIG_ILLINST     2
 #define    SUBSIG_PRIVINST    3
-#define    SUBSIG_BADTRAP(t)  (0x80 + (n))
+#define    SUBSIG_BADTRAP(t)  (0x80 + (t))
 
 #define SIGTRAP		 5
 #define SIGABRT		 6
@@ -87,7 +89,7 @@
 
 /* Sigvec flags */
 #define SV_SSTACK    1     /* This signal handler should use sig-stack */
-#define SV_INTR      2     /* Sig return should not restart system ??? */
+#define SV_INTR      2     /* Sig return should not restart system call */
 #define SV_RESET     4     /* Set handler to SIG_DFL upon taken signal */
 #define SV_IGNCHILD  8     /* Do not send SIGCHLD */
 
@@ -102,15 +104,15 @@
  */
 #define SA_NOCLDSTOP	SV_IGNCHILD
 #define SA_STACK	SV_SSTACK
-#define SA_RESTART	SV_RESET
-#define SA_INTERRUPT	SV_INTR
-#define SA_NOMASK	0x10
-#define SA_ONESHOT	0x20
+#define SA_RESTART	SV_INTR
+#define SA_ONESHOT	SV_RESET
+#define SA_INTERRUPT	0x10
+#define SA_NOMASK	0x20
 #define SA_SHIRQ	0x40
 
-#define SIG_BLOCK          0x00	/* for blocking signals */
-#define SIG_UNBLOCK        0x40	/* for unblocking signals */
-#define SIG_SETMASK        0x80	/* for setting the signal mask */
+#define SIG_BLOCK          0x01	/* for blocking signals */
+#define SIG_UNBLOCK        0x02	/* for unblocking signals */
+#define SIG_SETMASK        0x04	/* for setting the signal mask */
 
 #ifdef __KERNEL__
 /*
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/smp.h linux/include/asm-sparc/smp.h
--- v1.3.70/linux/include/asm-sparc/smp.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/smp.h	Mon Mar  4 08:50:03 1996
@@ -0,0 +1,91 @@
+/* smp.h: Sparc specific SMP stuff.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _SPARC_SMP_H
+#define _SPARC_SMP_H
+
+#include <asm/bitops.h>
+#include <asm/ptrace.h>
+
+/* Per processor Sparc parameters. */
+
+struct cpuinfo_sparc {
+	unsigned char impl;
+	unsigned char vers;
+	unsigned long udelay_val;
+};
+
+extern struct cpuinfo_sparc cpu_data[NR_CPUS];
+
+typedef klock_t volatile unsigned char;
+extern klock_t kernel_lock;
+
+#define KLOCK_HELD       0xff
+#define KLOCK_CLEAR      0x00
+
+struct sparc_ipi_invalidate {
+	struct mm_struct *mm;
+	unsigned long addr;   /* page for inv_pg, start for inv_rnge */
+	unsigned long end;    /* Used for inv_rnge only. */
+};
+
+struct sparc_ipimsg {
+	union {
+		/* Add more here as we need them. */
+		struct sparc_ipi_invalidate invmsg;
+	};
+};
+
+extern void smp_scan_prom_for_cpus(unsigned long, unsigned long);
+extern unsigned long smp_alloc_memory(unsigned long mem_base);
+extern unsigned long *kernel_stacks[NR_CPUS];
+extern unsigned char boot_cpu_id;
+extern unsigned long cpu_present_map;
+extern volatile unsigned long smp_invalidate_needed;
+extern unsigned long kernel_counter;
+extern volatile unsigned char active_kernel_processor;
+extern void smp_message_irq(int cpl, struct pt_regs *regs);
+extern void smp_reschedule_irq(int cpl, struct pt_regs *regs);
+extern void smp_invalidate_rcv(void);
+extern volatils unsigned long syscall_count;
+
+extern void (*smp_invalidate_all)(void);
+extern void (*smp_invalidate_mm)(struct mm_struct *);
+extern void (*smp_invalidate_range)(struct mm_struct *, unsigned long, unsigned long);
+extern void (*smp_invalidate_page)(struct vm_area_struct *, unsigned long);
+
+extern void smp_callin(void);
+extern void smp_boot_cpus(void);
+extern void smp_store_cpu_info(int id);
+
+extern _inline_ int smp_processor_id(void)
+{
+	int cpuid;
+
+	__asm__ __volatile__("rd %%tbr, %0\n\t"
+			     "srl %0, 24, %0\n\t"
+			     "and %0, 3, %0\n\t" :
+			     "=&r" (cpuid) :
+			     "0" (cpuid));
+	return cpuid;
+}
+
+/* Imperical PROM processor mailbox constants.  If the per-cpu mailbox
+ * contains something other than one of these then the ipi is from
+ * Linux's active_kernel_processor.  This facility exists so that
+ * the boot monitor can capture all the other cpus when one catches
+ * a watchdog reset or the user enters the monitor using L1-A keys.
+ */
+#define MBOX_STOPCPU          0xFB
+#define MBOX_IDLECPU          0xFC
+#define MBOX_IDLECPU2         0xFD
+#define MBOX_STOPCPU2         0xFE
+
+
+#define NO_PROC_ID            0xFF
+
+#define PROC_CHANGE_PENALTY   0x23
+
+#endif /* !(_SPARC_SMP_H) */
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/smp_lock.h linux/include/asm-sparc/smp_lock.h
--- v1.3.70/linux/include/asm-sparc/smp_lock.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/smp_lock.h	Mon Mar  4 08:50:03 1996
@@ -0,0 +1,57 @@
+/* smp_lock.h: Locking and unlocking the kernel on the Sparc.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef __SPARC_SMPLOCK_H
+#define __SPARC_SMPLOCK_H
+
+#ifdef __SMP__
+
+extern _inline_ unsigned char ldstub(klock_t *lock)
+{
+	klock_t retval;
+
+	__asm__ __volatile__("ldstub [%1], %0\n\t" :
+			     "=r" (retval) :
+			     "r" (lock));
+	return retval;
+}
+
+/* Knock knock... */
+extern _inline_ void lock_kernel(void)
+{
+	unsigned long flags;
+	int proc = smp_processor_id();
+
+	save_flags(flags); cli(); /* need this on sparc? */
+	while(ldstub(&kernel_lock)) {
+		if(proc == active_kernel_processor)
+			break;
+		if(test_bit(proc, (unsigned long *)&smp_invalidate_needed))
+			if(clear_bit(proc, (unsigned long *)&smp_invalidate_needed))
+				local_invalidate();
+	}
+	active_kernel_processor = proc;
+	kernel_counter++;
+	restore_flags(flags);
+}
+
+/* I want out... */
+extern _inline_ void unlock_kernel(void)
+{
+	unsigned long flags;
+
+	save_flags(flags); cli(); /* need this on sparc? */
+	if(kernel_counter == 0)
+		panic("Bogus kernel counter.\n");
+	if(!--kernel_counter) {
+		active_kernel_processor = NO_PROC_ID;
+		kernel_lock = KLOCK_CLEAR;
+	}
+	restore_flag(flags);
+}
+
+#endif /* !(__SPARC_SMPLOCK_H) */
+
+#endif /* (__SMP__) */
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/string.h linux/include/asm-sparc/string.h
--- v1.3.70/linux/include/asm-sparc/string.h	Sat Nov 25 19:04:54 1995
+++ linux/include/asm-sparc/string.h	Mon Mar  4 08:50:03 1996
@@ -1,4 +1,4 @@
-/* $Id: string.h,v 1.15 1995/11/25 02:32:56 davem Exp $
+/* $Id: string.h,v 1.17 1995/12/10 06:25:48 davem Exp $
  * string.h: External definitions for optimized assembly string
  *           routines for the Linux Kernel.
  *
@@ -8,6 +8,8 @@
 #ifndef __SPARC_STRING_H__
 #define __SPARC_STRING_H__
 
-/* Nothing yet... */
+#define __HAVE_ARCH_BCOPY
+#define __HAVE_ARCH_MEMMOVE
+#define __HAVE_ARCH_MEMCPY
 
 #endif /* !(__SPARC_STRING_H__) */
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/swift.h linux/include/asm-sparc/swift.h
--- v1.3.70/linux/include/asm-sparc/swift.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/swift.h	Mon Mar  4 08:50:03 1996
@@ -0,0 +1,65 @@
+/* swift.h: Specific definitions for the _broken_ Swift SRMMU
+ *          MMU.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _SPARC_SWIFT_H
+#define _SPARC_SWIFT_H
+
+/* Swift is so brain damaged, here is the mmu control register. */
+#define SWIFT_ST       0x00800000   /* SW tablewalk enable */
+#define SWIFT_WP       0x00400000   /* Watchpoint enable   */
+
+/* Branch folding (buggy, disable on production systems!)  */
+#define SWIFT_BF       0x00200000
+#define SWIFT_PMC      0x00180000   /* Page mode control   */
+#define SWIFT_PE       0x00040000   /* Parity enable       */
+#define SWIFT_PC       0x00020000   /* Parity control      */
+#define SWIFT_AP       0x00010000   /* Graphics page mode control (TCX/SX) */
+#define SWIFT_AC       0x00008000   /* Alternate Cacheability (see viking.h) */
+#define SWIFT_BM       0x00004000   /* Boot mode */
+#define SWIFT_RC       0x00003c00   /* DRAM refresh control */
+#define SWIFT_IE       0x00000200   /* Instruction cache enable */
+#define SWIFT_DE       0x00000100   /* Data cache enable */
+#define SWIFT_SA       0x00000080   /* Store Allocate */
+#define SWIFT_NF       0x00000002   /* No fault mode */
+#define SWIFT_EN       0x00000001   /* MMU enable */
+
+extern inline void swift_inv_insn_tag(unsigned long addr)
+{
+	__asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+			     "r" (addr), "i" (ASI_M_TXTC_TAG));
+}
+
+extern inline void swift_inv_data_tag(unsigned long addr)
+{
+	__asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+			     "r" (addr), "i" (ASI_M_DATAC_TAG));
+}
+
+extern inline void swift_flush_page(unsigned long page)
+{
+	__asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+			     "r" (page), "i" (ASI_M_FLUSH_PAGE));
+}
+
+extern inline void swift_flush_segment(unsigned long addr)
+{
+	__asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+			     "r" (addr), "i" (ASI_M_FLUSH_SEG));
+}
+
+extern inline void swift_flush_region(unsigned long addr)
+{
+	__asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+			     "r" (addr), "i" (ASI_M_FLUSH_REGION));
+}
+
+extern inline void swift_flush_context(void)
+{
+	__asm__ __volatile__("sta %%g0, [%%g0] %0\n\t" : :
+			     "i" (ASI_M_FLUSH_CTX));
+}
+
+#endif /* !(_SPARC_SWIFT_H) */
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/system.h linux/include/asm-sparc/system.h
--- v1.3.70/linux/include/asm-sparc/system.h	Sat Nov 25 19:04:54 1995
+++ linux/include/asm-sparc/system.h	Mon Mar  4 08:50:03 1996
@@ -1,16 +1,16 @@
-/* $Id: system.h,v 1.19 1995/11/25 02:32:59 davem Exp $ */
+/* $Id: system.h,v 1.24 1996/02/11 00:42:39 davem Exp $ */
 #ifndef __SPARC_SYSTEM_H
 #define __SPARC_SYSTEM_H
 
-#include <asm/segment.h>
+#include <linux/kernel.h>
 
+#include <asm/segment.h>
 #include <asm/page.h>
-#include <asm/openprom.h>
+#include <asm/oplib.h>
 #include <asm/psr.h>
 
 #define EMPTY_PGT       (&empty_bad_page)
 #define EMPTY_PGE	(&empty_bad_page_table)
-#define ZERO_PGE	(&empty_zero_page)
 
 #ifndef __ASSEMBLY__
 
@@ -42,10 +42,13 @@
  * frames are up to date.
  */
 extern void flush_user_windows(void);
+extern void synchronize_user_stack(void);
 extern void sparc_switch_to(void *new_task);
 #define switch_to(p) do { \
 			  flush_user_windows(); \
 		          switch_to_context(p); \
+			  current->tss.current_ds = active_ds; \
+                          active_ds = p->tss.current_ds; \
                           sparc_switch_to(p); \
                      } while(0)
 
@@ -94,10 +97,13 @@
 	return retval;
 }
 
+extern char spdeb_buf[256];
+
 #define cli()			setipl(15)  /* 15 = no int's except nmi's */
 #define sti()			setipl(0)   /* I'm scared */
 #define save_flags(flags)	do { flags = getipl(); } while (0)
 #define restore_flags(flags)	setipl(flags)
+
 #define nop() __asm__ __volatile__ ("nop");
 
 extern inline unsigned long xchg_u32(volatile unsigned long *m, unsigned long val)
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/termios.h linux/include/asm-sparc/termios.h
--- v1.3.70/linux/include/asm-sparc/termios.h	Sat Nov 25 19:04:54 1995
+++ linux/include/asm-sparc/termios.h	Mon Mar  4 08:50:04 1996
@@ -1,4 +1,4 @@
-/* $Id: termios.h,v 1.10 1995/11/25 02:33:01 davem Exp $ */
+/* $Id: termios.h,v 1.11 1996/02/10 04:31:03 davem Exp $ */
 #ifndef _SPARC_TERMIOS_H
 #define _SPARC_TERMIOS_H
 
@@ -193,12 +193,11 @@
 
 #ifdef __KERNEL__
 /*	intr=^C		quit=^|		erase=del	kill=^U
-	eof=^D		vtime=\0	vmin=\1		sxtc=\0
-	start=^Q	stop=^S		susp=^Z		eol=\0
+	eof/vmin=\1	eol/vtime=\0	eol2=\0		sxtc=\0
+	start=^Q	stop=^S		susp=^Z		dsusp=^Y
 	reprint=^R	discard=^U	werase=^W	lnext=^V
-	eol2=\0
 */
-#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0"
+#define INIT_C_CC "\003\034\177\025\001\000\000\000\021\023\032\031\022\025\027\026"
 #endif
 
 /* c_iflag bits */
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/timer.h linux/include/asm-sparc/timer.h
--- v1.3.70/linux/include/asm-sparc/timer.h	Sat Nov 25 19:04:54 1995
+++ linux/include/asm-sparc/timer.h	Mon Mar  4 08:50:04 1996
@@ -1,4 +1,4 @@
-/* $Id: timer.h,v 1.10 1995/11/25 02:33:03 davem Exp $
+/* $Id: timer.h,v 1.11 1996/01/03 03:53:23 davem Exp $
  * timer.h:  Definitions for the timer chips on the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -32,8 +32,7 @@
 
 #define SUN4C_TIMER_PHYSADDR   0xf3000000
 
-/* All accesses to the sun4c timer registers should use this macro. */
-#define  SUN4C_TIMER_STRUCT  ((volatile struct sun4c_timer_info *) TIMER_VADDR)
+volatile struct sun4c_timer_info *sun4c_timers;
 
 /* A sun4m has two blocks of registers which are probably of the same
  * structure. LSI Logic's L64851 is told to _decrement_ from the limit
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/tsunami.h linux/include/asm-sparc/tsunami.h
--- v1.3.70/linux/include/asm-sparc/tsunami.h	Sat Nov 25 19:04:54 1995
+++ linux/include/asm-sparc/tsunami.h	Mon Mar  4 08:50:04 1996
@@ -1,4 +1,4 @@
-/* $Id: tsunami.h,v 1.2 1995/11/25 02:33:06 davem Exp $
+/* $Id: tsunami.h,v 1.3 1996/01/10 21:00:12 davem Exp $
  * tsunami.h:  Module specific definitions for Tsunami V8 Sparcs
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -7,6 +7,8 @@
 #ifndef _SPARC_TSUNAMI_H
 #define _SPARC_TSUNAMI_H
 
+#include <asm/asi.h>
+
 /* The MMU control register on the Tsunami:
  *
  * -----------------------------------------------------------------------
@@ -42,5 +44,17 @@
 #define TSUNAMI_DENAB     0x00000100
 #define TSUNAMI_NF        0x00000002
 #define TSUNAMI_ME        0x00000001
+
+extern inline void tsunami_invalidate_icache(void)
+{
+	__asm__ __volatile__("sta %%g0, [%%g0] %0\n\t" : :
+			     "i" (ASI_M_IC_FLCLEAR) : "memory");
+}
+
+extern inline void tsunami_invalidate_dcache(void)
+{
+	__asm__ __volatile__("sta %%g0, [%%g0] %0\n\t" : :
+			     "i" (ASI_M_DC_FLCLEAR) : "memory");
+}
 
 #endif /* !(_SPARC_TSUNAMI_H) */
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/unistd.h linux/include/asm-sparc/unistd.h
--- v1.3.70/linux/include/asm-sparc/unistd.h	Sat Nov 25 19:04:55 1995
+++ linux/include/asm-sparc/unistd.h	Mon Mar  4 08:50:04 1996
@@ -1,4 +1,4 @@
-/* $Id: unistd.h,v 1.15 1995/11/25 02:33:12 davem Exp $ */
+/* $Id: unistd.h,v 1.16 1995/12/29 23:14:26 miguel Exp $ */
 #ifndef _SPARC_UNISTD_H
 #define _SPARC_UNISTD_H
 
@@ -258,23 +258,22 @@
 #define __NR_mlockall           239
 #define __NR_munlockall         240
 
-/* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar.
- * XXX These need to be fixed to check the condition codes to see
- * XXX the return value is an errorno or success.
- */
 #define _syscall0(type,name) \
 type name(void) \
 { \
 long __res; \
 __asm__ volatile ("or %%g0, %0, %%g1\n\t" \
 		  "t 0x10\n\t" \
+		  "bcc 1f\n\t" \
 		  "or %%g0, %%o0, %0\n\t" \
-		  : "=r" (__res) \
+		  "sub %%g0, %%o0, %0\n\t" \
+		  "1:\n\t" \
+		  : "=r" (__res)\
 		  : "0" (__NR_##name) \
 		  : "g1"); \
 if (__res >= 0) \
     return (type) __res; \
-errno = __res; \
+errno = -__res; \
 return -1; \
 }
 
@@ -285,13 +284,16 @@
 __asm__ volatile ("or %%g0, %0, %%g1\n\t" \
 		  "or %%g0, %1, %%o0\n\t" \
 		  "t 0x10\n\t" \
+		  "bcc 1f\n\t" \
 		  "or %%g0, %%o0, %0\n\t" \
+		  "sub %%g0, %%o0, %0\n\t" \
+		  "1:\n\t" \
 		  : "=r" (__res), "=r" ((long)(arg1)) \
 		  : "0" (__NR_##name),"1" ((long)(arg1)) \
 		  : "g1", "o0"); \
 if (__res >= 0) \
 	return (type) __res; \
-errno = __res; \
+errno = -__res; \
 return -1; \
 }
 
@@ -303,13 +305,16 @@
 		  "or %%g0, %1, %%o0\n\t" \
 		  "or %%g0, %2, %%o1\n\t" \
 		  "t 0x10\n\t" \
+		  "bcc 1f\n\t" \
 		  "or %%g0, %%o0, %0\n\t" \
+		  "sub %%g0,%%o0,%0\n\t" \
+		  "1:\n\t" \
 		  : "=r" (__res), "=r" ((long)(arg1)), "=r" ((long)(arg2)) \
 		  : "0" (__NR_##name),"1" ((long)(arg1)),"2" ((long)(arg2)) \
 		  : "g1", "o0", "o1"); \
 if (__res >= 0) \
 	return (type) __res; \
-errno = __res; \
+errno = -__res; \
 return -1; \
 }
 
@@ -322,7 +327,10 @@
 		  "or %%g0, %2, %%o1\n\t" \
 		  "or %%g0, %3, %%o2\n\t" \
 		  "t 0x10\n\t" \
+		  "bcc 1f\n\t" \
 		  "or %%g0, %%o0, %0\n\t" \
+		  "sub %%g0, %%o0, %0\n\t" \
+		  "1:\n\t" \
 		  : "=r" (__res), "=r" ((long)(arg1)), "=r" ((long)(arg2)), \
 		    "=r" ((long)(arg3)) \
 		  : "0" (__NR_##name), "1" ((long)(arg1)), "2" ((long)(arg2)), \
@@ -330,7 +338,7 @@
 		  : "g1", "o0", "o1", "o2"); \
 if (__res>=0) \
 	return (type) __res; \
-errno = __res; \
+errno = -__res; \
 return -1; \
 }
 
@@ -344,7 +352,10 @@
 		  "or %%g0, %3, %%o2\n\t" \
 		  "or %%g0, %4, %%o3\n\t" \
 		  "t 0x10\n\t" \
+		  "bcc 1f\n\t" \
 		  "or %%g0, %%o0, %0\n\t" \
+		  "sub %%g0,%%o0, %0\n\t" \
+		  "1:\n\t" \
 		  : "=r" (__res), "=r" ((long)(arg1)), "=r" ((long)(arg2)), \
 		    "=r" ((long)(arg3)), "=r" ((long)(arg4)) \
 		  : "0" (__NR_##name),"1" ((long)(arg1)),"2" ((long)(arg2)), \
@@ -352,7 +363,7 @@
 		  : "g1", "o0", "o1", "o2", "o3"); \
 if (__res>=0) \
 	return (type) __res; \
-errno = __res; \
+errno = -__res; \
 return -1; \
 } 
 
@@ -376,10 +387,9 @@
 		  : "g1", "o0", "o1", "o2", "o3", "o4"); \
 if (__res>=0) \
 	return (type) __res; \
-errno = __res; \
+errno = -__res; \
 return -1; \
 }
-
 #ifdef __KERNEL_SYSCALLS__
 
 /*
@@ -465,5 +475,15 @@
 }
 
 #endif /* __KERNEL_SYSCALLS__ */
+
+/* sysconf options, for SunOS compatibility */
+#define   _SC_ARG_MAX             1
+#define   _SC_CHILD_MAX           2
+#define   _SC_CLK_TCK             3
+#define   _SC_NGROUPS_MAX         4
+#define   _SC_OPEN_MAX            5
+#define   _SC_JOB_CONTROL         6
+#define   _SC_SAVED_IDS           7
+#define   _SC_VERSION             8
 
 #endif /* _SPARC_UNISTD_H */
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/user.h linux/include/asm-sparc/user.h
--- v1.3.70/linux/include/asm-sparc/user.h	Sat Nov 25 19:04:55 1995
+++ linux/include/asm-sparc/user.h	Mon Mar  4 08:50:04 1996
@@ -1,4 +1,4 @@
-/* $Id: user.h,v 1.2 1995/11/25 02:33:15 davem Exp $
+/* $Id: user.h,v 1.3 1995/12/29 21:48:03 davem Exp $
  * asm-sparc/user.h: Core file definitions for the Sparc.
  *
  * Copyright (C) 1995 (davem@caip.rutgers.edu)
@@ -6,18 +6,45 @@
 #ifndef _SPARC_USER_H
 #define _SPARC_USER_H
 
+struct sunos_regs {
+	unsigned long psr, pc, npc, y;
+	unsigned long regs[15];
+};
+
+struct sunos_fpqueue {
+	unsigned long *addr;
+	unsigned long inst;
+};
+
+struct sunos_fp {
+	union {
+		unsigned long regs[32];
+		double reg_dbls[16];
+	} fregs;
+	unsigned long fsr;
+	unsigned long flags;
+	unsigned long extra;
+	unsigned long fpq_count;
+	struct sunos_fpqueue fpq[16];
+};
+
+struct sunos_fpu {
+	struct sunos_fp fpstatus;
+};
+
+/* The SunOS core file header layout. */
 struct user {
-	unsigned long regs[24 + 32]; /* locals, ins, globals + fpu regs */
-	size_t        u_tsize;
+	unsigned long magic;
+	unsigned long len;
+	struct sunos_regs regs;
+	struct exec uexec;
+	int           signal;
+	size_t        u_tsize; /* all of these in bytes! */
 	size_t        u_dsize;
 	size_t        u_ssize;
-	unsigned long start_code;
-	unsigned long start_data;
-	unsigned long start_stack;
-	int           signal;
-	unsigned long *u_ar0;
-	unsigned long magic;
-	char          u_comm[32];
+	char          u_comm[17];
+	struct sunos_fpu fpu;
+	unsigned long sigcode;   /* Special sigcontext subcode, if any */
 };
 
 #define NBPG                   PAGE_SIZE
@@ -25,5 +52,6 @@
 #define HOST_TEXT_START_ADDR   (u.start_code)
 #define HOST_DATA_START_ADDR   (u.start_data)
 #define HOST_STACK_END_ADDR    (u.start_stack + u.u_ssize * NBPG)
+#define SUNOS_CORE_MAGIC       0x080456
 
 #endif /* !(_SPARC_USER_H) */
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/vac-ops.h linux/include/asm-sparc/vac-ops.h
--- v1.3.70/linux/include/asm-sparc/vac-ops.h	Sat Nov 25 19:04:55 1995
+++ linux/include/asm-sparc/vac-ops.h	Mon Mar  4 08:50:04 1996
@@ -1,4 +1,4 @@
-/* $Id: vac-ops.h,v 1.7 1995/11/25 02:33:18 davem Exp $ */
+/* $Id: vac-ops.h,v 1.9 1995/12/17 09:02:00 davem Exp $ */
 #ifndef _SPARC_VAC_OPS_H
 #define _SPARC_VAC_OPS_H
 
@@ -122,50 +122,6 @@
   sun4c_vacinfo.on = 0;
 }
 
-extern unsigned long sun4c_ctxflush;
-extern unsigned long sun4c_segflush;
-extern unsigned long sun4c_pgflush;
-
-extern void sun4c_ctxflush_hw64KB16B(void);
-extern void sun4c_ctxflush_hw64KB32B(void);
-extern void sun4c_ctxflush_sw64KB16B(void);
-extern void sun4c_ctxflush_sw64KB32B(void);
-
-extern void sun4c_segflush_hw64KB16B(void);
-extern void sun4c_segflush_hw64KB32B(void);
-extern void sun4c_segflush_sw64KB16B(void);
-extern void sun4c_segflush_sw64KB32B(void);
-
-extern void sun4c_pgflush_hw64KB16B(void);
-extern void sun4c_pgflush_hw64KB32B(void);
-extern void sun4c_pgflush_sw64KB16B(void);
-extern void sun4c_pgflush_sw64KB32B(void);
-
-/* These do indirect calls to the in-line assembly routines
- * in s4ctlb.S, see that file for more answers.
- */
-extern inline void sun4c_flush_context(void)
-{
-	__asm__ __volatile__("jmpl %0, %%l4\n\t"
-			     "nop\n\t" : :
-			     "r" (sun4c_ctxflush) :
-			     "l4", "l6", "l7", "memory");
-}
-
-extern inline void sun4c_flush_segment(unsigned long segment)
-{
-	__asm__ __volatile__("jmpl %0, %%l4\n\t"
-			     "or %1, %%g0, %%l2\n\t" : :
-			     "r" (sun4c_segflush), "r" (segment) :
-			     "l2", "l4", "l6", "l7", "memory");
-}
-
-extern inline void sun4c_flush_page(unsigned long page)
-{
-	__asm__ __volatile__("jmpl %0, %%l4\n\t"
-			     "or %1, %%g0, %%l2\n\t" : :
-			     "r" (sun4c_pgflush), "r" (page) :
-			     "l2", "l4", "l6", "l7", "memory");
-}
+extern void sun4c_flush_context(void);
 
 #endif /* !(_SPARC_VAC_OPS_H) */
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/vaddrs.h linux/include/asm-sparc/vaddrs.h
--- v1.3.70/linux/include/asm-sparc/vaddrs.h	Sat Nov 25 19:04:56 1995
+++ linux/include/asm-sparc/vaddrs.h	Mon Mar  4 08:50:04 1996
@@ -1,4 +1,4 @@
-/* $Id: vaddrs.h,v 1.15 1995/11/25 02:33:20 davem Exp $ */
+/* $Id: vaddrs.h,v 1.17 1996/01/10 21:00:16 davem Exp $ */
 #ifndef _SPARC_VADDRS_H
 #define _SPARC_VADDRS_H
 
@@ -16,13 +16,6 @@
  * mappings for devices and is the speedup improvements of not loading
  * a pointer and then the value in the assembly code
  */
-
-#define  AUXIO_VADDR  (KERNBASE+0x6000)    /* Auxiliary IO register */
-#define  TIMER_VADDR  (AUXIO_VADDR+0x1000) /* One page after AUXIO, length is
-					    * 5 pages which is needed on sun4m.
-					    */
-#define  INTREG_VADDR (TIMER_VADDR+0x5000)
-
 #define  IOBASE_VADDR   0xfe000000  /* Base for mapping pages */
 #define  IOBASE_LEN     0x00100000  /* Length of the IO area */
 #define  IOBASE_END     0xfe100000
@@ -30,6 +23,31 @@
 #define  DVMA_LEN       0x00040000  /* Size of the DVMA address space */
 #define  DVMA_END       0xfff40000
 
+/* IOMMU Mapping area, must be on a 16MB boundry!  Note this
+ * doesn't count the DVMA areas, the prom lives between the
+ * iommu mapping area (for scsi transfer buffers) and the
+ * dvma upper range (for lance packet ring buffers).
+ */
+#define  IOMMU_VADDR    0xff000000
+#define  IOMMU_LEN      0x00c00000
+#define  IOMMU_END      0xffc00000 /* KADB debugger vm starts here */
+
+/* On the sun4/4c we don't need an IOMMU area, but we need a place
+ * to reliably map locked down kernel data.  This includes the
+ * task_struct and kernel stack pages of each process plus the
+ * scsi buffers during dvma IO transfers, also the floppy buffers
+ * during pseudo dma which runs with traps off (no faults allowed).
+ * Some quick calculations yield:
+ *       NR_TASKS <512> * (3 * PAGE_SIZE) == 0x600000
+ * Subtract this from 0xc00000 and you get 0x927C0 of vm left
+ * over to map SCSI dvma + floppy pseudo-dma buffers.  So be
+ * careful if you change NR_TASKS or else there won't be enough
+ * room for it all.
+ */
+#define  SUN4C_LOCK_VADDR  0xff000000
+#define  SUN4C_LOCK_LEN    0x00c00000
+#define  SUN4C_LOCK_END    0xffc00000
+
 /* On sun4m machines we need per-cpu virtual areas */
 #define  PERCPU_VADDR   0xff000000  /* Base for per-cpu virtual mappings */
 #define  PERCPU_ENTSIZE 0x00100000
@@ -44,3 +62,4 @@
 #define  PERCPU_ISIDLING_OFFSET 0x03008      /* Is CPU in idle loop spinning? */
 
 #endif /* !(_SPARC_VADDRS_H) */
+
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/viking.h linux/include/asm-sparc/viking.h
--- v1.3.70/linux/include/asm-sparc/viking.h	Sat Nov 25 19:04:56 1995
+++ linux/include/asm-sparc/viking.h	Mon Mar  4 08:50:04 1996
@@ -1,4 +1,4 @@
-/* $Id: viking.h,v 1.5 1995/11/25 02:33:21 davem Exp $
+/* $Id: viking.h,v 1.6 1996/03/01 07:21:05 davem Exp $
  * viking.h:  Defines specific to the TI Viking MBUS module.
  *            This is SRMMU stuff.
  *
@@ -7,6 +7,8 @@
 #ifndef _SPARC_VIKING_H
 #define _SPARC_VIKING_H
 
+#include <asm/mxcc.h>
+
 /* Bits in the SRMMU control register for TI Viking modules.
  *
  * -------------------------------------------------------------
@@ -49,4 +51,28 @@
 #define VIKING_TCENABLE     0x00010000   /* Enable table-walks to be cached */
 #define VIKING_DPENABLE     0x00040000   /* Enable the data prefetcher */
 
-#endif
+extern inline void viking_flush_icache(void)
+{
+	__asm__ __volatile__("sta %%g0, [%%g0] %0\n\t" : :
+			     "i" (ASI_M_IC_FLCLEAR));
+}
+
+extern inline void viking_flush_dcache(void)
+{
+	__asm__ __volatile__("sta %%g0, [%%g0] %0\n\t" : :
+			     "i" (ASI_M_DC_FLCLEAR));
+}
+
+/* MXCC stuff... */
+extern inline void viking_enable_mxcc(void)
+{
+}
+
+extern inline void viking_mxcc_scrape(void)
+{
+	/* David, what did you learn in school today? */
+
+
+}
+
+#endif /* !(_SPARC_VIKING_H) */
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/vuid_event.h linux/include/asm-sparc/vuid_event.h
--- v1.3.70/linux/include/asm-sparc/vuid_event.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc/vuid_event.h	Mon Mar  4 08:50:04 1996
@@ -0,0 +1,41 @@
+/* SunOS Virtual User Input Device (VUID) compatibility */
+
+
+typedef struct firm_event {
+	unsigned short id;	  /* tag for this event */
+	unsigned char  pair_type; /* unused by X11 */
+        unsigned char  pair;	  /* unused by X11 */
+        int            value;	  /* VKEY_UP, VKEY_DOWN or delta */
+        struct timeval time;
+} Firm_event;
+
+enum {
+    FE_PAIR_NONE,
+    FE_PAIR_SET,
+    FE_PAIR_DELTA,
+    FE_PAIR_ABSOLUTE
+};
+
+/* VUID stream formats */
+#define VUID_NATIVE     0	/* Native byte stream format */
+#define VUID_FIRM_EVENT 1	/* send firm_event structures */
+
+/* ioctls */
+    /* Set input device byte stream format (any of VUID_{NATIVE,FIRM_EVENT}) */
+#define VUIDSFORMAT   _IOW('v', 1, int)
+    /* Retrieve input device byte stream format */
+#define VUIDGFORMAT   _IOR(v, 2, int)
+
+/* Possible tag values */
+/*    mouse buttons: */
+#define MS_LEFT         0x7f20
+#define MS_MIDDLE       0x7f21
+#define MS_RIGHT        0x7f22
+/*    motion: */
+#define LOC_X_DELTA     0x7f80
+#define LOC_Y_DELTA     0x7f81
+#define LOC_X_ABSOLUTE  0x7f82  /* X compat, unsupported */
+#define LOC_Y_ABSOLUTE  0x7f83  /* X compat, unsupported */
+
+#define VKEY_UP   0
+#define VKEY_DOWN 1
diff -u --recursive --new-file v1.3.70/linux/include/asm-sparc/winmacro.h linux/include/asm-sparc/winmacro.h
--- v1.3.70/linux/include/asm-sparc/winmacro.h	Sat Nov 25 19:04:56 1995
+++ linux/include/asm-sparc/winmacro.h	Mon Mar  4 08:50:04 1996
@@ -1,4 +1,4 @@
-/* $Id: winmacro.h,v 1.11 1995/11/25 02:33:23 davem Exp $
+/* $Id: winmacro.h,v 1.13 1995/12/29 21:48:04 davem Exp $
  * winmacro.h: Window loading-unloading macros.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -44,25 +44,25 @@
 
 /* Loading and storing struct pt_reg trap frames. */
 #define LOAD_PT_INS(base_reg) \
-        ldd     [%base_reg + STACKFRAME_SZ + PT_I0], %i0; \
-        ldd     [%base_reg + STACKFRAME_SZ + PT_I2], %i2; \
-        ldd     [%base_reg + STACKFRAME_SZ + PT_I4], %i4; \
-        ldd     [%base_reg + STACKFRAME_SZ + PT_I6], %i6;
+        ldd     [%base_reg + REGWIN_SZ + PT_I0], %i0; \
+        ldd     [%base_reg + REGWIN_SZ + PT_I2], %i2; \
+        ldd     [%base_reg + REGWIN_SZ + PT_I4], %i4; \
+        ldd     [%base_reg + REGWIN_SZ + PT_I6], %i6;
 
 #define LOAD_PT_GLOBALS(base_reg) \
-        ld      [%base_reg + STACKFRAME_SZ + PT_G1], %g1; \
-        ldd     [%base_reg + STACKFRAME_SZ + PT_G2], %g2; \
-        ldd     [%base_reg + STACKFRAME_SZ + PT_G4], %g4; \
-        ldd     [%base_reg + STACKFRAME_SZ + PT_G6], %g6;
+        ld      [%base_reg + REGWIN_SZ + PT_G1], %g1; \
+        ldd     [%base_reg + REGWIN_SZ + PT_G2], %g2; \
+        ldd     [%base_reg + REGWIN_SZ + PT_G4], %g4; \
+        ldd     [%base_reg + REGWIN_SZ + PT_G6], %g6;
 
 #define LOAD_PT_YREG(base_reg, scratch) \
-        ld      [%base_reg + STACKFRAME_SZ + PT_Y], %scratch; \
+        ld      [%base_reg + REGWIN_SZ + PT_Y], %scratch; \
         wr      %scratch, 0x0, %y;
 
 #define LOAD_PT_PRIV(base_reg, pt_psr, pt_pc, pt_npc) \
-        ld      [%base_reg + STACKFRAME_SZ + PT_PSR], %pt_psr; \
-        ld      [%base_reg + STACKFRAME_SZ + PT_PC], %pt_pc; \
-        ld      [%base_reg + STACKFRAME_SZ + PT_NPC], %pt_npc;
+        ld      [%base_reg + REGWIN_SZ + PT_PSR], %pt_psr; \
+        ld      [%base_reg + REGWIN_SZ + PT_PC], %pt_pc; \
+        ld      [%base_reg + REGWIN_SZ + PT_NPC], %pt_npc;
 
 #define LOAD_PT_ALL(base_reg, pt_psr, pt_pc, pt_npc, scratch) \
         LOAD_PT_YREG(base_reg, scratch) \
@@ -71,29 +71,28 @@
         LOAD_PT_PRIV(base_reg, pt_psr, pt_pc, pt_npc)
 
 #define STORE_PT_INS(base_reg) \
-        std     %i0, [%base_reg + STACKFRAME_SZ + PT_I0]; \
-        std     %i2, [%base_reg + STACKFRAME_SZ + PT_I2]; \
-        std     %i4, [%base_reg + STACKFRAME_SZ + PT_I4]; \
-        std     %i6, [%base_reg + STACKFRAME_SZ + PT_I6];
+        std     %i0, [%base_reg + REGWIN_SZ + PT_I0]; \
+        std     %i2, [%base_reg + REGWIN_SZ + PT_I2]; \
+        std     %i4, [%base_reg + REGWIN_SZ + PT_I4]; \
+        std     %i6, [%base_reg + REGWIN_SZ + PT_I6];
 
 #define STORE_PT_GLOBALS(base_reg) \
-        st      %g1, [%base_reg + STACKFRAME_SZ + PT_G1]; \
-        std     %g2, [%base_reg + STACKFRAME_SZ + PT_G2]; \
-        std     %g4, [%base_reg + STACKFRAME_SZ + PT_G4]; \
-        std     %g6, [%base_reg + STACKFRAME_SZ + PT_G6];
+        st      %g1, [%base_reg + REGWIN_SZ + PT_G1]; \
+        std     %g2, [%base_reg + REGWIN_SZ + PT_G2]; \
+        std     %g4, [%base_reg + REGWIN_SZ + PT_G4]; \
+        std     %g6, [%base_reg + REGWIN_SZ + PT_G6];
 
 #define STORE_PT_YREG(base_reg, scratch) \
         rd      %y, %scratch; \
-        st      %scratch, [%base_reg + STACKFRAME_SZ + PT_Y];
+        st      %scratch, [%base_reg + REGWIN_SZ + PT_Y];
 
-#define STORE_PT_PRIV(base_reg, pt_psr, pt_pc, pt_npc, pt_wim) \
-        st      %pt_psr, [%base_reg + STACKFRAME_SZ + PT_PSR]; \
-        st      %pt_pc, [%base_reg + STACKFRAME_SZ + PT_PC]; \
-        st      %pt_npc, [%base_reg + STACKFRAME_SZ + PT_NPC]; \
-        st      %pt_wim, [%base_reg + STACKFRAME_SZ + PT_WIM];
+#define STORE_PT_PRIV(base_reg, pt_psr, pt_pc, pt_npc) \
+        st      %pt_psr, [%base_reg + REGWIN_SZ + PT_PSR]; \
+        st      %pt_pc,  [%base_reg + REGWIN_SZ + PT_PC]; \
+        st      %pt_npc, [%base_reg + REGWIN_SZ + PT_NPC];
 
-#define STORE_PT_ALL(base_reg, reg_psr, reg_pc, reg_npc, reg_wim, g_scratch) \
-        STORE_PT_PRIV(base_reg, reg_psr, reg_pc, reg_npc, reg_wim) \
+#define STORE_PT_ALL(base_reg, reg_psr, reg_pc, reg_npc, g_scratch) \
+        STORE_PT_PRIV(base_reg, reg_psr, reg_pc, reg_npc) \
         STORE_PT_GLOBALS(base_reg) \
         STORE_PT_YREG(base_reg, g_scratch) \
         STORE_PT_INS(base_reg)
@@ -113,8 +112,18 @@
         st       %scratch, [%cur_reg + THREAD_W_SAVED];
 
 /* For now on a uniprocessor this is ok. */
-#define LOAD_CURRENT(dest_reg) \
+#ifdef __SMP__
+#error SMP not yet
+#define LOAD_CURRENT(dest_reg, idreg) \
+        rd       %tbr, %idreg; \
+        srl      %idreg, 24, %idreg; \
+	sethi    %hi(C_LABEL(current_set)), %dest_reg; \
+	or       %dest_reg, %lo(C_LABEL(current_set)), %dest_reg; \
+	add      %dest_reg, %idreg, %dest_reg;
+#else
+#define LOAD_CURRENT(dest_reg, idreg) \
         sethi    %hi(C_LABEL(current_set)), %dest_reg; \
         ld       [%dest_reg + %lo(C_LABEL(current_set))], %dest_reg;
+#endif
 
 #endif /* !(_SPARC_WINMACRO_H) */
diff -u --recursive --new-file v1.3.70/linux/include/linux/binfmts.h linux/include/linux/binfmts.h
--- v1.3.70/linux/include/linux/binfmts.h	Fri Feb  9 17:53:07 1996
+++ linux/include/linux/binfmts.h	Sat Mar  2 20:29:23 1996
@@ -23,6 +23,7 @@
 	int argc, envc;
 	char * filename;	/* Name of binary */
 	unsigned long loader, exec;
+	int dont_iput;		/* binfmt handler has put inode */
 };
 
 /*
@@ -39,6 +40,7 @@
 
 extern int register_binfmt(struct linux_binfmt *);
 extern int unregister_binfmt(struct linux_binfmt *);
+extern struct linux_binfmt * get_binfmt_list(void);
 
 extern int read_exec(struct inode *inode, unsigned long offset,
 	char * addr, unsigned long count, int to_kmem);
@@ -47,10 +49,12 @@
 
 extern int init_elf_binfmt(void);
 extern int init_aout_binfmt(void);
+extern int init_script_binfmt(void);
 
+extern int prepare_binprm(struct linux_binprm *);
+extern int search_binary_handler(struct linux_binprm *,struct pt_regs *);
 extern void flush_old_exec(struct linux_binprm * bprm);
-extern unsigned long setup_arg_pages(unsigned long text_size,unsigned long * page);
-extern unsigned long * create_tables(char * p,struct linux_binprm * bprm,int ibcs);
+extern unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm);
 extern unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
 		unsigned long p, int from_kmem);
 
diff -u --recursive --new-file v1.3.70/linux/include/linux/interrupt.h linux/include/linux/interrupt.h
--- v1.3.70/linux/include/linux/interrupt.h	Sat Mar  2 10:43:45 1996
+++ linux/include/linux/interrupt.h	Sun Mar  3 15:19:02 1996
@@ -15,14 +15,10 @@
 };
 
 
-struct bh_struct {
-	void (*routine)(void *);
-	void *data;
-};
-
+extern int bh_mask_count[32];
 extern unsigned long bh_active;
 extern unsigned long bh_mask;
-extern struct bh_struct bh_base[32];
+extern void (*bh_base[32])(void);
 
 asmlinkage void do_bottom_half(void);
 
@@ -41,21 +37,38 @@
 	CM206_BH
 };
 
+extern inline void init_bh(int nr, void (*routine)(void))
+{
+	bh_base[nr] = routine;
+	bh_mask_count[nr] = 0;
+	bh_mask |= 1 << nr;
+}
+
 extern inline void mark_bh(int nr)
 {
 	set_bit(nr, &bh_active);
 }
 
+/*
+ * These use a mask count to correctly handle
+ * nested disable/enable calls
+ */
 extern inline void disable_bh(int nr)
 {
-	clear_bit(nr, &bh_mask);
+	bh_mask &= ~(1 << nr);
+	bh_mask_count[nr]++;
 }
 
 extern inline void enable_bh(int nr)
 {
-	set_bit(nr, &bh_mask);
+	if (!--bh_mask_count[nr])
+		bh_mask |= 1 << nr;
 }
 
+/*
+ * start_bh_atomic/end_bh_atomic also nest
+ * naturally by using a counter
+ */
 extern inline void start_bh_atomic(void)
 {
 	intr_count++;
diff -u --recursive --new-file v1.3.70/linux/include/linux/loop.h linux/include/linux/loop.h
--- v1.3.70/linux/include/linux/loop.h	Thu Jan  1 02:00:00 1970
+++ linux/include/linux/loop.h	Mon Mar  4 11:25:49 1996
@@ -0,0 +1,77 @@
+#ifndef _LINUX_LOOP_H
+#define _LINUX_LOOP_H
+
+/*
+ * include/linux/loop.h
+ *
+ * Written by Theodore Ts'o, 3/29/93.
+ *
+ * Copyright 1993 by Theodore Ts'o.  Redistribution of this file is
+ * permitted under the GNU Public License.
+ */
+
+#define LO_NAME_SIZE	64
+#define LO_KEY_SIZE	32
+       
+struct loop_device {
+	int		lo_number;
+	struct inode	*lo_inode;
+	int		lo_refcnt;
+	kdev_t		lo_device;
+	int		lo_offset;
+	int		lo_encrypt_type;
+	int		lo_encrypt_key_size;
+	int		lo_flags;
+	int		(*transfer)(struct loop_device *, int cmd,
+				    char *raw_buf, char *loop_buf, int size);
+	char		lo_name[LO_NAME_SIZE];
+	char		lo_encrypt_key[LO_KEY_SIZE];
+#ifdef DES_AVAILABLE
+	des_key_schedule lo_des_key;
+	unsigned long	lo_des_init[2];
+#endif
+};
+
+typedef	int (* transfer_proc_t)(struct loop_device *, int cmd,
+				char *raw_buf, char *loop_buf, int size);
+
+/*
+ * Loop flags
+ */
+#define LO_FLAGS_DO_BMAP	0x00000001
+
+struct loop_info {
+	int		lo_number;	/* ioctl r/o */
+	dev_t		lo_device; 	/* ioctl r/o */
+	unsigned long	lo_inode; 	/* ioctl r/o */
+	dev_t		lo_rdevice; 	/* ioctl r/o */
+	int		lo_offset;
+	int		lo_encrypt_type;
+	int		lo_encrypt_key_size; 	/* ioctl w/o */
+	int		lo_flags;	/* ioctl r/o */
+	char		lo_name[LO_NAME_SIZE];
+	unsigned char	lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */
+	unsigned long	lo_init[2];
+	char		reserved[4];
+};
+
+/*
+ * Loop encryption types --- LO_CRYPT_IDEA isn't supported yet
+ */
+
+#define LO_CRYPT_NONE	0
+#define LO_CRYPT_XOR	1
+#define LO_CRYPT_DES	2
+#define LO_CRYPT_IDEA	3
+#define MAX_LO_CRYPT	4
+
+/*
+ * IOCTL commands --- we will commandeer 0x4C ('L')
+ */
+
+#define LOOP_SET_FD	0x4C00
+#define LOOP_CLR_FD	0x4C01
+#define LOOP_SET_STATUS	0x4C02
+#define LOOP_GET_STATUS	0x4C03
+
+#endif
diff -u --recursive --new-file v1.3.70/linux/include/linux/major.h linux/include/linux/major.h
--- v1.3.70/linux/include/linux/major.h	Wed Feb 28 11:50:13 1996
+++ linux/include/linux/major.h	Mon Mar  4 11:25:49 1996
@@ -2,7 +2,8 @@
 #define _LINUX_MAJOR_H
 
 /*
- * This file has definitions for major device numbers
+ * This file has definitions for major device numbers.
+ * For the device number assignments, see Documentation/devices.txt.
  */
 
 /* limits */
@@ -10,49 +11,6 @@
 #define MAX_CHRDEV 64
 #define MAX_BLKDEV 64
 
-/*
- * assignments
- *
- * devices are as follows (same as minix, so we can use the minix fs):
- *
- *      character              block                  comments
- *      --------------------   --------------------   --------------------
- *  0 - unnamed                unnamed                minor 0 = true nodev
- *  1 - /dev/mem               ramdisk
- *  2 - /dev/ptyp*             floppy
- *  3 - /dev/ttyp*             ide0 or hd
- *  4 - /dev/tty*
- *  5 - /dev/tty; /dev/cua*
- *  6 - lp
- *  7 - /dev/vcs*
- *  8 -                        scsi disk
- *  9 - scsi tape              multiple devices driver
- * 10 - mice
- * 11 -                        scsi cdrom
- * 12 - qic02 tape
- * 13 -                        xt disk
- * 14 - sound card
- * 15 -                        cdu31a cdrom
- * 16 - sockets                goldstar cdrom
- * 17 - af_unix                optics cdrom
- * 18 - af_inet                sanyo cdrom
- * 19 - cyclades /dev/ttyC*
- * 20 - cyclades /dev/cub*     mitsumi (mcdx) cdrom
- * 21 - scsi generic
- * 22 -                        ide1
- * 23 -                        mitsumi cdrom
- * 24 -	                       sony535 cdrom
- * 25 -                        matsushita cdrom       minors 0..3
- * 26 -                        matsushita cdrom 2     minors 0..3
- * 27 - qic117 tape            matsushita cdrom 3     minors 0..3
- * 28 -                        matsushita cdrom 4     minors 0..3
- * 29 -                        aztech/orchid/okano/wearnes cdrom
- * 32 -                        philips/lms cm206 cdrom
- * 33 -                        ide2
- * 34 - z8530 driver           ide3
- * 36 - netlink
- */
-
 #define UNNAMED_MAJOR	0
 #define MEM_MAJOR	1
 #define RAMDISK_MAJOR	1
@@ -65,6 +23,7 @@
 #define TTYAUX_MAJOR	5
 #define LP_MAJOR	6
 #define VCS_MAJOR	7
+#define LOOP_MAJOR	7
 #define SCSI_DISK_MAJOR	8
 #define SCSI_TAPE_MAJOR	9
 #define MD_MAJOR        9
diff -u --recursive --new-file v1.3.70/linux/include/linux/mcdx.h linux/include/linux/mcdx.h
--- v1.3.70/linux/include/linux/mcdx.h	Tue Jan 23 21:15:52 1996
+++ linux/include/linux/mcdx.h	Mon Mar  4 11:15:22 1996
@@ -1,7 +1,7 @@
 /*
  * Definitions for the Mitsumi CDROM interface
  * Copyright (C) 1995 Heiko Schlittermann <heiko@lotte.sax.de>
- * VERSION: 1.5a
+ * VERSION: 1.7
  * 
  * 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
@@ -27,6 +27,7 @@
  *  Daniel v. Mosnenck (he sent me the Technical and Programming Reference)
  *  Gerd Knorr (he lent me his PhotoCD)
  *  Nils Faerber and Roger E. Wolff (extensivly tested the LU portion)
+ *  Andreas Kies (testing the mysterious hang up's)
  *  ... somebody forgotten?
  *  
  */
@@ -80,12 +81,13 @@
 #define MCDX "mcdx"	
 
 #if MCDX_QUIET == 1
-#define INFO(x)
+#define INFO(x)  
+#define WARN(x) warn x
 #else
 #define INFO(x) warn x
+#define WARN(x) warn x
 #endif
 
-#define WARN(x) warn x
 
 #if MCDX_DEBUG == 1
 #define TRACE(x) trace x
@@ -101,9 +103,10 @@
 #define OPENCLOSE 	0
 #define HW		    0
 #define TALK		0
-#define IRQ 		1
+#define IRQ 		0
 #define TRANSFER 	0
 #define REQUEST	 	0
+#define SLEEP		0
 #else
 #define TRACE(x)
 #endif
@@ -118,21 +121,25 @@
 #define MCDX_IO_SIZE		4
 
 /*
- *	The Ports & bits
+ *	Bits
  */
 
-#define MCDX_RBIT_OPEN       0x80
-#define MCDX_RBIT_DISKSET    0x40
-#define MCDX_RBIT_CHANGED    0x20
-#define MCDX_RBIT_CHECK      0x10
-#define MCDX_RBIT_AUDIOTR    0x08
-#define MCDX_RBIT_RDERR      0x04
-#define MCDX_RBIT_AUDIOBS    0x02
-#define MCDX_RBIT_CMDERR     0x01
-#define MCDX_RBIT_DOOR       0x10
-#define MCDX_RBIT_STEN       0x04
-#define MCDX_RBIT_DTEN       0x02
-
+/* The status byte, returned from every command, set if
+ * the description is true */
+#define MCDX_RBIT_OPEN       0x80	/* door is open */
+#define MCDX_RBIT_DISKSET    0x40	/* disk set (recognised) */
+#define MCDX_RBIT_CHANGED    0x20	/* disk was changed */
+#define MCDX_RBIT_CHECK      0x10	/* disk rotates, servo is on */
+#define MCDX_RBIT_AUDIOTR    0x08   /* current track is audio */
+#define MCDX_RBIT_RDERR      0x04	/* read error, refer SENSE KEY */
+#define MCDX_RBIT_AUDIOBS    0x02	/* currently playing audio */
+#define MCDX_RBIT_CMDERR     0x01	/* command, param or format error */
+
+/* The I/O Register holding the h/w status of the drive,
+ * can be read at i/o base + 1 */
+#define MCDX_RBIT_DOOR       0x10	/* door is open */
+#define MCDX_RBIT_STEN       0x04	/* if 0, i/o base contains drive status */
+#define MCDX_RBIT_DTEN       0x02	/* if 0, i/o base contains data */
 
 /*
  *	The commands.
@@ -177,9 +184,12 @@
  * Errors
  */
 #define MCDX_E		1			/* unspec error */
-#define MCDX_EOM	2			/* end of media */
+#define MCDX_ST_EOM 0x0100		/* end of media */
+#define MCDX_ST_DRV 0x00ff		/* mask to query the drive status */
 
 #ifndef I_WAS_HERE
 #warning You have not edited mcdx.h
 #warning Perhaps irq and i/o settings are wrong.
 #endif
+
+/* ex:set ts=4 sw=4: */
diff -u --recursive --new-file v1.3.70/linux/include/linux/md.h linux/include/linux/md.h
--- v1.3.70/linux/include/linux/md.h	Wed Feb 28 11:50:13 1996
+++ linux/include/linux/md.h	Sat Mar  2 21:21:51 1996
@@ -148,153 +148,3 @@
 
 #endif __KERNEL__
 #endif _MD_H
-
-/*
-   md.h : Multiple Devices driver for Linux
-          Copyright (C) 1994, 1995 Marc ZYNGIER
-	  <zyngier@amertume.ufr-info-p7.ibp.fr> or
-	  <maz@gloups.fdn.fr>
-	  
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
-   
-   You should have received a copy of the GNU General Public License
-   (for example /usr/src/linux/COPYING); if not, write to the Free
-   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
-*/
-
-#ifndef _MD_H
-#define _MD_H
-
-#include <linux/major.h>
-#include <linux/mm.h>
-#include <linux/ioctl.h>
-
-#define MD_VERSION "0.33"
-
-/* ioctls */
-#define REGISTER_DEV _IO (MD_MAJOR, 1)
-#define START_MD     _IO (MD_MAJOR, 2)
-#define STOP_MD      _IO (MD_MAJOR, 3)
-#define MD_INVALID   _IO (MD_MAJOR, 4)
-#define MD_VALID     _IO (MD_MAJOR, 5)
-
-/*
-   personalities :
-   Byte 0 : Chunk size factor
-   Byte 1 : Fault tolerance count for each physical device
-            (   0 means no fault tolerance,
-             0xFF means always tolerate faults)
-   Byte 2 : Personality
-   Byte 3 : Reserved.
- */
-
-#define FAULT_SHIFT       8
-#define PERSONALITY_SHIFT 16
-
-#define FACTOR_MASK       0xFFUL
-#define FAULT_MASK        0xFF00UL
-#define PERSONALITY_MASK  0xFF0000UL
-
-#define MD_RESERVED       0	/* Not used by now */
-#define LINEAR            (1UL << PERSONALITY_SHIFT)
-#define STRIPED           (2UL << PERSONALITY_SHIFT)
-#define STRIPPED          STRIPED /* Long lasting spelling mistake... */
-#define RAID0             STRIPED
-#define RAID1             (3UL << PERSONALITY_SHIFT)
-#define RAID5             (4UL << PERSONALITY_SHIFT)
-#define MAX_PERSONALITY   5
-
-#ifdef __KERNEL__
-
-#include <linux/config.h>
-#include <sys/types.h>
-#include <linux/fs.h>
-#include <linux/blkdev.h>
-
-#undef MD_COUNT_SIZE		/* Define this to have stats about
-				   chunk size in /proc/mdstat */
-#define MAX_REAL     8		/* Max number of physical dev per md dev */
-#define MAX_MD_DEV   4		/* Max number of md dev */
-
-#define FACTOR(a)         ((a)->repartition & FACTOR_MASK)
-#define MAX_FAULT(a)      (((a)->repartition & FAULT_MASK)>>8)
-#define PERSONALITY(a)    ((a)->repartition & PERSONALITY_MASK)
-
-#define FACTOR_SHIFT(a) (PAGE_SHIFT + (a) - 10)
-
-/* Invalidation modes */
-#define VALID          0
-#define INVALID_NEXT   1
-#define INVALID_ALWAYS 2
-#define INVALID        3	/* Only useful to md_valid_device */
-
-/* Return values from personalities to md driver */
-#define REDIRECTED_BHREQ 0 /* Redirected individual buffers
-			      (shouldn't be used anymore since 0.31) */
-#define REDIRECTED_REQ   1 /* Redirected whole request */
-#define REDIRECT_FAILED -1 /* For RAID-1 */
-
-struct real_dev
-{
-  kdev_t dev;			/* Device number */
-  int size;			/* Device size (in blocks) */
-  int offset;			/* Real device offset (in blocks) in md dev
-				   (only used in linear mode) */
-  struct inode *inode;		/* Lock inode */
-  int fault_count;		/* Fault counter for invalidation */
-  int invalid;			/* Indicate if the device is disabled :
-				   VALID          - valid
-				   INVALID_NEXT   - disabled for next access
-				   INVALID_ALWAYS - permanently disabled
-				   (for redundancy modes only) */
-};
-
-struct md_dev;
-
-struct md_personality
-{
-  char *name;
-  int (*map)(int minor, struct md_dev *md_dev, struct request *req);
-  int (*run)(int minor, struct md_dev *md_dev);
-  int (*stop)(int minor, struct md_dev *md_dev);
-  int (*status)(char *page, int minor, struct md_dev *md_dev);
-  int (*ioctl)(struct inode *inode, struct file *file,
-	       unsigned int cmd, unsigned long arg);
-  int max_invalid_dev;
-};
-
-struct md_dev
-{
-  struct md_personality *pers;
-  int repartition;
-  int invalid_dev_count;
-  int busy;
-  int nb_dev;
-  void *private;
-#ifdef MD_COUNT_SIZE
-  unsigned int smallest_count;
-  unsigned int biggest_count;
-  unsigned int equal_count;
-#endif
-};
-
-extern struct real_dev devices[MAX_MD_DEV][MAX_REAL];
-extern struct md_dev md_dev[MAX_MD_DEV];
-extern int md_size[MAX_MD_DEV];
-
-extern void make_md_request(struct request *pending, int n);
-extern char *partition_name (kdev_t dev);
-
-#if defined(CONFIG_MD_SUPPORT_RAID1) || defined(CONFIG_MD_SUPPORT_RAID5)
-extern int md_valid_device (int minor, kdev_t dev, int mode);
-extern int md_can_reemit (int minor);
-#endif
-
-extern int register_md_personality (int p_num, struct md_personality *p);
-extern int unregister_md_personality (int p_num);
-
-#endif __KERNEL__
-#endif _MD_H
diff -u --recursive --new-file v1.3.70/linux/include/linux/ncp.h linux/include/linux/ncp.h
--- v1.3.70/linux/include/linux/ncp.h	Tue Jan  2 16:46:30 1996
+++ linux/include/linux/ncp.h	Sat Mar  2 13:15:35 1996
@@ -1,5 +1,5 @@
 /*
- *  ncp_fs.h
+ *  ncp.h
  *
  *  Copyright (C) 1995 by Volker Lendecke
  *
diff -u --recursive --new-file v1.3.70/linux/include/linux/ncp_fs.h linux/include/linux/ncp_fs.h
--- v1.3.70/linux/include/linux/ncp_fs.h	Fri Feb 23 13:54:38 1996
+++ linux/include/linux/ncp_fs.h	Mon Mar  4 10:33:00 1996
@@ -1,7 +1,7 @@
 /*
  *  ncp_fs.h
  *
- *  Copyright (C) 1995 by Volker Lendecke
+ *  Copyright (C) 1995, 1996 by Volker Lendecke
  *
  */
 
@@ -42,6 +42,7 @@
 
 #define	NCP_IOC_NCPREQUEST		_IOR('n', 1, unsigned char *)
 #define	NCP_IOC_GETMOUNTUID		_IOR('u', 1, uid_t)
+#define NCP_IOC_CONN_LOGGED_IN          _IO('l', 1)
 
 #define NCP_GET_FS_INFO_VERSION (1)
 #define NCP_IOC_GET_FS_INFO             _IOWR('i', 1, unsigned char *)
@@ -128,10 +129,11 @@
 void ncp_free_inode_info(struct ncp_inode_info *i);
 void ncp_free_all_inodes(struct ncp_server *server);
 void ncp_init_root(struct ncp_server *server);
-int  ncp_stat_root(struct ncp_server *server);
+int  ncp_conn_logged_in(struct ncp_server *server);
 void ncp_init_dir_cache(void);
-void ncp_invalid_dir_cache(unsigned long ino);
-void ncp_invalidate_all_inodes(struct ncp_server *server);
+void ncp_invalid_dir_cache(struct inode *ino);
+struct ncp_inode_info *ncp_find_inode(struct inode *inode);
+ino_t ncp_info_ino(struct ncp_server *server, struct ncp_inode_info *info);
 void ncp_free_dir_cache(void);
 int  ncp_date_dos2unix(__u16 time, __u16 date);
 void ncp_date_unix2dos(int unix_date, __u16 *time, __u16 *date);
@@ -145,8 +147,6 @@
 struct super_block *ncp_read_super(struct super_block *sb,
                                    void *raw_data, int silent);
 extern int init_ncp_fs(void);
-void ncp_invalidate_connection(struct ncp_server *server);
-int ncp_conn_is_valid(struct ncp_server *server);
 void ncp_trigger_message(struct ncp_server *server);
 
 /* linux/fs/ncpfs/sock.c */
diff -u --recursive --new-file v1.3.70/linux/include/linux/ncp_fs_i.h linux/include/linux/ncp_fs_i.h
--- v1.3.70/linux/include/linux/ncp_fs_i.h	Wed Feb  7 15:11:38 1996
+++ linux/include/linux/ncp_fs_i.h	Sat Mar  2 13:15:35 1996
@@ -28,6 +28,7 @@
                                    number of references in memory */
         struct ncp_inode_info *dir;
         struct ncp_inode_info *next, *prev;
+	struct inode *inode;
 	struct nw_file_info finfo;
 };
 
diff -u --recursive --new-file v1.3.70/linux/include/linux/ncp_fs_sb.h linux/include/linux/ncp_fs_sb.h
--- v1.3.70/linux/include/linux/ncp_fs_sb.h	Fri Feb 23 13:54:38 1996
+++ linux/include/linux/ncp_fs_sb.h	Sat Mar  2 13:15:35 1996
@@ -1,7 +1,7 @@
 /*
  *  ncp_fs_sb.h
  *
- *  Copyright (C) 1995 by Volker Lendecke
+ *  Copyright (C) 1995, 1996 by Volker Lendecke
  *
  */
 
diff -u --recursive --new-file v1.3.70/linux/include/linux/ncp_mount.h linux/include/linux/ncp_mount.h
--- v1.3.70/linux/include/linux/ncp_mount.h	Fri Feb 23 13:54:38 1996
+++ linux/include/linux/ncp_mount.h	Sat Mar  2 13:15:35 1996
@@ -1,7 +1,7 @@
 /*
  *  ncp_mount.h
  *
- *  Copyright (C) 1995 by Volker Lendecke
+ *  Copyright (C) 1995, 1996 by Volker Lendecke
  *
  */
 
@@ -26,7 +26,7 @@
 	int version;
 	unsigned int ncp_fd;	/* The socket to the ncp port */
 	unsigned int wdog_fd;	/* Watchdog packets come here */
-	unsigned int message_fd; /* Not used yet, maybe for messages */
+	unsigned int message_fd; /* Message notifications come here */
         uid_t mounted_uid;      /* Who may umount() this filesystem? */
 
 	struct sockaddr_ipx serv_addr;
diff -u --recursive --new-file v1.3.70/linux/include/linux/netdevice.h linux/include/linux/netdevice.h
--- v1.3.70/linux/include/linux/netdevice.h	Fri Feb 23 13:54:38 1996
+++ linux/include/linux/netdevice.h	Mon Mar  4 10:24:55 1996
@@ -233,7 +233,7 @@
 extern void		netif_rx(struct sk_buff *skb);
 extern void		dev_transmit(void);
 extern int		in_net_bh(void);
-extern void		net_bh(void *tmp);
+extern void		net_bh(void);
 extern void		dev_tint(struct device *dev);
 extern int		dev_get_info(char *buffer, char **start, off_t offset, int length, int dummy);
 extern int		dev_ioctl(unsigned int cmd, void *);
diff -u --recursive --new-file v1.3.70/linux/include/linux/skbuff.h linux/include/linux/skbuff.h
--- v1.3.70/linux/include/linux/skbuff.h	Sat Feb 17 16:02:54 1996
+++ linux/include/linux/skbuff.h	Mon Mar  4 10:24:55 1996
@@ -33,8 +33,8 @@
 
 struct sk_buff_head 
 {
-	struct sk_buff	* volatile next;
-	struct sk_buff	* volatile prev;
+	struct sk_buff	* next;
+	struct sk_buff	* prev;
 	__u32		qlen;		/* Must be same length as a pointer
 					   for using debugging */
 #if CONFIG_SKB_CHECK
@@ -45,8 +45,8 @@
 
 struct sk_buff 
 {
-	struct sk_buff	* volatile next;	/* Next buffer in list 				*/
-	struct sk_buff	* volatile prev;	/* Previous buffer in list 			*/
+	struct sk_buff	* next;			/* Next buffer in list 				*/
+	struct sk_buff	* prev;			/* Previous buffer in list 			*/
 	struct sk_buff_head * list;		/* List we are on				*/
 #if CONFIG_SKB_CHECK
 	int		magic_debug_cookie;
@@ -63,8 +63,8 @@
 		struct iphdr	*iph;
 		struct udphdr	*uh;
 		unsigned char	*raw;
-		/* for passing an fd in a unix domain socket */
-		struct file *filp;
+		/* for passing file handles in a unix domain socket */
+		void *filp;
 	} h;
   
 	union 
@@ -160,6 +160,11 @@
 extern int			skb_tailroom(struct sk_buff *skb);
 extern void			skb_reserve(struct sk_buff *skb, int len);
 extern void 			skb_trim(struct sk_buff *skb, int len);
+
+extern __inline__ int skb_queue_empty(struct sk_buff_head *list)
+{
+	return (list->next == (struct sk_buff *) list);
+}
 
 /*
  *	Peek an sk_buff. Unlike most other operations you _MUST_
diff -u --recursive --new-file v1.3.70/linux/include/linux/socket.h linux/include/linux/socket.h
--- v1.3.70/linux/include/linux/socket.h	Wed Sep 27 16:00:00 1995
+++ linux/include/linux/socket.h	Mon Mar  4 09:16:40 1996
@@ -5,14 +5,15 @@
 #include <linux/sockios.h>		/* the SIOCxxx I/O controls	*/
 #include <linux/uio.h>			/* iovec support		*/
 
-struct sockaddr {
-  unsigned short	sa_family;	/* address family, AF_xxx	*/
-  char			sa_data[14];	/* 14 bytes of protocol address	*/
+struct sockaddr 
+{
+	unsigned short	sa_family;	/* address family, AF_xxx	*/
+	char		sa_data[14];	/* 14 bytes of protocol address	*/
 };
 
 struct linger {
-  int 			l_onoff;	/* Linger active		*/
-  int			l_linger;	/* How long to linger for	*/
+	int		l_onoff;	/* Linger active		*/
+	int		l_linger;	/* How long to linger for	*/
 };
 
 struct msghdr 
@@ -25,6 +26,17 @@
 	int		msg_accrightslen;	/* Length of rights list */
 };
 
+/*
+ *	4.4BSD changed to these new names for no apparent reason.
+ */
+ 
+#define msg_control	msg_accrights	
+#define msg_controllen	msg_accrightslen;	
+
+/* Control Messages */
+
+#define SCM_RIGHTS		1
+
 /* Socket types. */
 #define SOCK_STREAM	1		/* stream (connection) socket	*/
 #define SOCK_DGRAM	2		/* datagram (conn.less) socket	*/
@@ -73,6 +85,7 @@
 #define MSG_OOB		1
 #define MSG_PEEK	2
 #define MSG_DONTROUTE	4
+/*#define MSG_CTRUNC	8	- We need to support this for BSD oddments */
 
 /* Setsockoptions(2) level. Thanks to BSD these must match IPPROTO_xxx */
 #define SOL_IP		0
diff -u --recursive --new-file v1.3.70/linux/include/linux/tqueue.h linux/include/linux/tqueue.h
--- v1.3.70/linux/include/linux/tqueue.h	Tue Jul 18 16:28:59 1995
+++ linux/include/linux/tqueue.h	Sun Mar  3 13:20:16 1996
@@ -137,24 +137,20 @@
  */
 _INLINE_ void run_task_queue(task_queue *list)
 {
-	register struct tq_struct *save_p;
 	register struct tq_struct *p;
-	void *arg;
-	void (*f) (void *);
 
-	while(1) {
-		p = xchg(list,&tq_last);
-		if(p == &tq_last)
-			break;
+	p = xchg(list,&tq_last);
 
-		do {
-			arg    = p -> data;
-			f      = p -> routine;
-			save_p = p -> next;
-			p -> sync = 0;
-			(*f)(arg);
-			p = save_p;
-		} while(p != &tq_last);
+	while (p != &tq_last) {
+		void *arg;
+		void (*f) (void *);
+		register struct tq_struct *save_p;
+		arg    = p -> data;
+		f      = p -> routine;
+		save_p = p;
+		p      = p -> next;
+		save_p -> sync = 0;
+		(*f)(arg);
 	}
 }
 
diff -u --recursive --new-file v1.3.70/linux/include/linux/un.h linux/include/linux/un.h
--- v1.3.70/linux/include/linux/un.h	Fri Jun 17 07:53:56 1994
+++ linux/include/linux/un.h	Mon Mar  4 09:16:40 1996
@@ -8,4 +8,11 @@
 	char sun_path[UNIX_PATH_MAX];	/* pathname */
 };
 
+struct cmsghdr {
+	unsigned int cmsg_len;
+	int cmsg_level;
+	int cmsg_type;
+	unsigned char cmsg_data[0];
+};
+
 #endif /* _LINUX_UN_H */
diff -u --recursive --new-file v1.3.70/linux/include/net/af_unix.h linux/include/net/af_unix.h
--- v1.3.70/linux/include/net/af_unix.h	Tue Aug  8 12:31:42 1995
+++ linux/include/net/af_unix.h	Mon Mar  4 09:16:41 1996
@@ -2,3 +2,8 @@
 
 typedef struct sock unix_socket;
 
+extern int unix_gc_free;
+extern void unix_gc_add(struct sock *sk, struct file *fp);
+extern void unix_gc_remove(struct file *fp);
+
+#define UNIX_MAX_FD	8
diff -u --recursive --new-file v1.3.70/linux/include/net/ax25.h linux/include/net/ax25.h
--- v1.3.70/linux/include/net/ax25.h	Fri Feb 23 13:54:40 1996
+++ linux/include/net/ax25.h	Mon Mar  4 10:24:55 1996
@@ -38,7 +38,7 @@
 
 #define SSSID_SPARE	0x60	/* Unused bits in SSID for standard AX.25 */
 #define ESSID_SPARE	0x20	/* Unused bits in SSID for extended AX.25 */
-#define DAMA_FLAG	0x40	/* Well, it is *NOT* unused! (dl1bke 951121 */
+#define DAMA_FLAG	0x20	/* Well, it is *NOT* unused! (dl1bke 951121 */
 
 #define AX25_REPEATED	0x80
 
diff -u --recursive --new-file v1.3.70/linux/include/net/netlink.h linux/include/net/netlink.h
--- v1.3.70/linux/include/net/netlink.h	Mon Dec 11 15:42:06 1995
+++ linux/include/net/netlink.h	Mon Mar  4 10:33:57 1996
@@ -2,7 +2,8 @@
 #define __NET_NETLINK_H
 
 #define NET_MAJOR 36		/* Major 18 is reserved for networking 						*/
-#define MAX_LINKS 4		/* 18,0 for route updates, 18,1 for SKIP, 18,2 debug tap 18,3 PPP reserved 	*/
+#define MAX_LINKS 8		/* 18,0 for route updates, 18,1 for SKIP, 18,2 debug tap 18,3 PPP reserved 	*/
+				/* 4-7 are psi0-psi3 */
 #define MAX_QBYTES 32768	/* Maximum bytes in the queue 							*/
 
 #include <linux/config.h>
@@ -17,6 +18,7 @@
 #define NETLINK_SKIP		1	/* Reserved for ENskip  			*/
 #define NETLINK_USERSOCK	2	/* Reserved for user mode socket protocols 	*/
 #define NETLINK_FIREWALL	3	/* Firewalling hook				*/
+#define NETLINK_PSI		4	/* PSI devices - 4 to 7 */
 
 #ifdef CONFIG_RTNETLINK
 extern void ip_netlink_msg(unsigned long, __u32, __u32, __u32, short, short, char *);
diff -u --recursive --new-file v1.3.70/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v1.3.70/linux/kernel/ksyms.c	Wed Feb 28 11:50:15 1996
+++ linux/kernel/ksyms.c	Sat Mar  2 20:29:24 1996
@@ -246,6 +246,9 @@
 	/* executable format registration */
 	X(register_binfmt),
 	X(unregister_binfmt),
+	X(get_binfmt_list),
+	X(search_binary_handler),
+	X(prepare_binprm),
 
 	/* execution environment registration */
 	X(lookup_exec_domain),
@@ -326,7 +329,6 @@
 	/* Program loader interfaces */
 	X(setup_arg_pages),
 	X(copy_strings),
-	X(create_tables),
 	X(do_execve),
 	X(flush_old_exec),
 	X(open_inode),
diff -u --recursive --new-file v1.3.70/linux/kernel/printk.c linux/kernel/printk.c
--- v1.3.70/linux/kernel/printk.c	Thu Jan  4 21:54:59 1996
+++ linux/kernel/printk.c	Sat Mar  2 13:18:49 1996
@@ -30,11 +30,11 @@
 extern void console_print(const char *);
 
 /* printk's without a loglevel use this.. */
-#define DEFAULT_MESSAGE_LOGLEVEL 5 /* KERN_NOTICE */
+#define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */
 
-/* We show everything that is more important than this.. */
-#define MINIMUM_CONSOLE_LOGLEVEL 6 /* Minimum loglevel we let people use */
-#define DEFAULT_CONSOLE_LOGLEVEL 6 /* anything more serious than KERN_INFO */
+/* We show everything that is MORE important than this.. */
+#define MINIMUM_CONSOLE_LOGLEVEL 5 /* Minimum loglevel we let people use */
+#define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything MORE serious than KERN_NOTICE */
 
 unsigned long log_size = 0;
 struct wait_queue * log_wait = NULL;
diff -u --recursive --new-file v1.3.70/linux/kernel/sched.c linux/kernel/sched.c
--- v1.3.70/linux/kernel/sched.c	Tue Feb 20 14:37:29 1996
+++ linux/kernel/sched.c	Sun Mar  3 15:23:08 1996
@@ -194,7 +194,7 @@
  *	   +ve: "goodness" value (the larger, the better)
  *	 +1000: realtime process, select this.
  */
-static inline int goodness(struct task_struct * p, int this_cpu)
+static inline int goodness(struct task_struct * p, struct task_struct * prev, int this_cpu)
 {
 	int weight;
 
@@ -230,7 +230,7 @@
 #endif
 
 		/* .. and a slight advantage to the current process */
-		if (p == current)
+		if (p == prev)
 			weight += 1;
 	}
 
@@ -251,7 +251,7 @@
 {
 	int c;
 	struct task_struct * p;
-	struct task_struct * next;
+	struct task_struct * prev, * next;
 	unsigned long timeout = 0;
 	int this_cpu=smp_processor_id();
 
@@ -269,26 +269,27 @@
 	run_task_queue(&tq_scheduler);
 
 	need_resched = 0;
+	prev = current;
 	cli();
 	/* move an exhausted RR process to be last.. */
-	if (!current->counter && current->policy == SCHED_RR) {
-		current->counter = current->priority;
-		move_last_runqueue(current);
+	if (!prev->counter && prev->policy == SCHED_RR) {
+		prev->counter = prev->priority;
+		move_last_runqueue(prev);
 	}
-	switch (current->state) {
+	switch (prev->state) {
 		case TASK_INTERRUPTIBLE:
-			if (current->signal & ~current->blocked)
+			if (prev->signal & ~prev->blocked)
 				goto makerunnable;
-			timeout = current->timeout;
+			timeout = prev->timeout;
 			if (timeout && (timeout <= jiffies)) {
-				current->timeout = 0;
+				prev->timeout = 0;
 				timeout = 0;
 		makerunnable:
-				current->state = TASK_RUNNING;
+				prev->state = TASK_RUNNING;
 				break;
 			}
 		default:
-			del_from_runqueue(current);
+			del_from_runqueue(prev);
 		case TASK_RUNNING:
 	}
 	p = init_task.next_run;
@@ -298,7 +299,7 @@
 	/*
 	 *	This is safe as we do not permit re-entry of schedule()
 	 */
-	current->processor = NO_PROC_ID;	
+	prev->processor = NO_PROC_ID;	
 #endif	
 
 /*
@@ -310,7 +311,7 @@
 	c = -1000;
 	next = &init_task;
 	while (p != &init_task) {
-		int weight = goodness(p, this_cpu);
+		int weight = goodness(p, prev, this_cpu);
 		if (weight > c)
 			c = weight, next = p;
 		p = p->next_run;
@@ -326,8 +327,8 @@
 	/*
 	 *	Context switching between two idle threads is pointless.
 	 */
-	if(!current->pid && !next->pid)
-		next=current;
+	if(!prev->pid && !next->pid)
+		next=prev;
 	/*
 	 *	Allocate process to CPU
 	 */
@@ -343,19 +344,19 @@
 	else
 		clear_bit(this_cpu,&smp_idle_map);
 #endif
-	if (current != next) {
+	if (prev != next) {
 		struct timer_list timer;
 
 		kstat.context_swtch++;
 		if (timeout) {
 			init_timer(&timer);
 			timer.expires = timeout;
-			timer.data = (unsigned long) current;
+			timer.data = (unsigned long) prev;
 			timer.function = process_timeout;
 			add_timer(&timer);
 		}
 		get_mmu_context(next);
-		switch_to(next);
+		switch_to(prev,next);
 		if (timeout)
 			del_timer(&timer);
 	}
@@ -715,7 +716,7 @@
 /*
  * disregard lost ticks for now.. We don't care enough.
  */
-static void timer_bh(void * unused)
+static void timer_bh(void)
 {
 	unsigned long mask;
 	struct timer_struct *tp;
@@ -747,12 +748,12 @@
 	}
 }
 
-void tqueue_bh(void * unused)
+void tqueue_bh(void)
 {
 	run_task_queue(&tq_timer);
 }
 
-void immediate_bh(void * unused)
+void immediate_bh(void)
 {
 	run_task_queue(&tq_immediate);
 }
@@ -1290,10 +1291,7 @@
 #ifdef __SMP__	
 	init_task.processor=cpu;
 #endif
-	bh_base[TIMER_BH].routine = timer_bh;
-	bh_base[TQUEUE_BH].routine = tqueue_bh;
-	bh_base[IMMEDIATE_BH].routine = immediate_bh;
-	enable_bh(TIMER_BH);
-	enable_bh(TQUEUE_BH);
-	enable_bh(IMMEDIATE_BH);
+	init_bh(TIMER_BH, timer_bh);
+	init_bh(TQUEUE_BH, tqueue_bh);
+	init_bh(IMMEDIATE_BH, immediate_bh);
 }
diff -u --recursive --new-file v1.3.70/linux/kernel/softirq.c linux/kernel/softirq.c
--- v1.3.70/linux/kernel/softirq.c	Wed Feb  7 15:11:40 1996
+++ linux/kernel/softirq.c	Sun Mar  3 15:28:02 1996
@@ -27,27 +27,28 @@
 
 unsigned long intr_count = 0;
 
+int bh_mask_count[32];
 unsigned long bh_active = 0;
 unsigned long bh_mask = 0;
-struct bh_struct bh_base[32];
+void (*bh_base[32])(void);
 
 
 asmlinkage void do_bottom_half(void)
 {
 	unsigned long active;
 	unsigned long mask, left;
-	struct bh_struct *bh;
+	void (**bh)(void);
 
 	bh = bh_base;
 	active = bh_active & bh_mask;
 	for (mask = 1, left = ~0 ; left & active ; bh++,mask += mask,left += left) {
 		if (mask & active) {
-			void (*fn)(void *);
+			void (*fn)(void);
 			bh_active &= ~mask;
-			fn = bh->routine;
+			fn = *bh;
 			if (!fn)
 				goto bad_bh;
-			fn(bh->data);
+			fn();
 		}
 	}
 	return;
diff -u --recursive --new-file v1.3.70/linux/mm/kmalloc.c linux/mm/kmalloc.c
--- v1.3.70/linux/mm/kmalloc.c	Wed Feb 28 11:50:15 1996
+++ linux/mm/kmalloc.c	Mon Mar  4 11:46:32 1996
@@ -19,7 +19,7 @@
 #include <asm/system.h>
 #include <asm/dma.h>
 
-/* Define this is you want slow routines that try to trip errors */
+/* Define this if you want slow routines that try to trip errors */
 #undef SADISTIC_KMALLOC
 
 /* Private flags. */
@@ -89,8 +89,8 @@
 };
 
 /*
- * For now it is unsafe to allocate bucket sizes between n and n-16 where n is
- * 4096 * any power of two
+ * For now it is unsafe to allocate bucket sizes between n and
+ * n-sizeof(page_descriptor) where n is PAGE_SIZE * any power of two
  */
 #if PAGE_SIZE == 4096
 struct size_descriptor sizes[] =
diff -u --recursive --new-file v1.3.70/linux/net/ax25/ax25_subr.c linux/net/ax25/ax25_subr.c
--- v1.3.70/linux/net/ax25/ax25_subr.c	Fri Feb 23 13:54:41 1996
+++ linux/net/ax25/ax25_subr.c	Mon Mar  4 09:16:41 1996
@@ -348,7 +348,7 @@
 	}
 		
 	if (dama != NULL) 
-		*dama = !(buf[13] & DAMA_FLAG);
+		*dama = ~(buf[13] & DAMA_FLAG);
 		
 	/* Copy to, from */
 	if (dest != NULL) 
diff -u --recursive --new-file v1.3.70/linux/net/core/dev.c linux/net/core/dev.c
--- v1.3.70/linux/net/core/dev.c	Wed Feb 28 11:50:15 1996
+++ linux/net/core/dev.c	Mon Mar  4 11:25:49 1996
@@ -216,10 +216,10 @@
 
 extern __inline__ void dev_load(const char *name)
 {
-        const char *sptr;
- 
         if(!dev_get(name)) {
 #ifdef CONFIG_NET_ALIAS
+	        const char *sptr;
+ 
                 for (sptr=name ; *sptr ; sptr++) if(*sptr==':') break;
                 if (!(*sptr && *(sptr+1)))
 #endif
@@ -557,7 +557,7 @@
  *	mark_bh(NET_BH);
  */
  
-void net_bh(void *tmp)
+void net_bh(void)
 {
 	struct sk_buff *skb;
 	struct packet_type *ptype;
@@ -728,9 +728,11 @@
 	 */	 
 	for(i = 0;i < DEV_NUMBUFFS; i++,head++)
 	{
-		struct sk_buff *skb = skb_peek(head);
 
-		if (skb) {
+		while (!skb_queue_empty(head)) {
+			struct sk_buff *skb;
+
+			skb = head->next;
 			__skb_unlink(skb, head);
 			/*
 			 *	Stop anyone freeing the buffer while we retransmit it
@@ -1408,7 +1410,6 @@
 	net_alias_init();
 #endif
 
-	bh_base[NET_BH].routine = net_bh;
-	enable_bh(NET_BH);
+	init_bh(NET_BH, net_bh);
 	return 0;
 }
diff -u --recursive --new-file v1.3.70/linux/net/core/sock.c linux/net/core/sock.c
--- v1.3.70/linux/net/core/sock.c	Wed Feb 28 11:50:16 1996
+++ linux/net/core/sock.c	Sun Mar  3 09:59:16 1996
@@ -541,29 +541,18 @@
 void __release_sock(struct sock *sk)
 {
 #ifdef CONFIG_INET
-	struct sk_buff *skb;
-
-	if (!sk->prot)
+	if (!sk->prot || !sk->prot->rcv)
 		return;
 		
-	/*
-	 *	This is only ever called from a user process context, hence
-	 *	(until fine grained SMP) its safe. sk->users must be volatile
-	 *	so the compiler doesn't do anything unfortunate with it.
-	 *
-	 *	The "barrier()" stuff takes care of that. Note that the rcv
-	 *	function may not sleep, so "users" is not going to change there.
-	 */
-
 	/* See if we have any packets built up. */
 	start_bh_atomic();
-	while ((skb = __skb_dequeue(&sk->back_log)) != NULL) 
-	{
-		if (sk->prot->rcv) 
-			sk->prot->rcv(skb, skb->dev, (struct options*)skb->proto_priv,
-				 skb->saddr, skb->len, skb->daddr, 1,
-				/* Only used for/by raw sockets. */
-				(struct inet_protocol *)sk->pair); 
+	while (!skb_queue_empty(&sk->back_log)) {
+		struct sk_buff * skb = sk->back_log.next;
+		__skb_unlink(skb, &sk->back_log);
+		sk->prot->rcv(skb, skb->dev, (struct options*)skb->proto_priv,
+			      skb->saddr, skb->len, skb->daddr, 1,
+			      /* Only used for/by raw sockets. */
+			      (struct inet_protocol *)sk->pair); 
 	}
 	end_bh_atomic();
 #endif  
diff -u --recursive --new-file v1.3.70/linux/net/ipv4/arp.c linux/net/ipv4/arp.c
--- v1.3.70/linux/net/ipv4/arp.c	Wed Feb 28 11:50:17 1996
+++ linux/net/ipv4/arp.c	Mon Mar  4 09:38:20 1996
@@ -1390,9 +1390,10 @@
 			if (pos <= offset)
 				len=0;
 			if (pos >= offset+length)
-				break;
+				goto done;
 		}
 	}
+done:
 	arp_unlock();
   
 	*start = buffer+len-(pos-offset);	/* Start of wanted data */
diff -u --recursive --new-file v1.3.70/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- v1.3.70/linux/net/ipv4/tcp_input.c	Wed Feb 28 11:50:18 1996
+++ linux/net/ipv4/tcp_input.c	Sun Mar  3 10:27:55 1996
@@ -1625,10 +1625,12 @@
 		skb->saddr = daddr;
 		skb->daddr = saddr;
 
-		/* We may need to add it to the backlog here. */
+		/*
+		 * We may need to add it to the backlog here. 
+		 */
 		if (sk->users) 
 		{
-			skb_queue_tail(&sk->back_log, skb);
+			__skb_queue_tail(&sk->back_log, skb);
 			return(0);
 		}
 	}
diff -u --recursive --new-file v1.3.70/linux/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c
--- v1.3.70/linux/net/ipx/af_ipx.c	Sat Mar  2 10:43:47 1996
+++ linux/net/ipx/af_ipx.c	Mon Mar  4 09:16:41 1996
@@ -1087,7 +1087,7 @@
 		ipx_routes=rt;
 	}
 	else if (intrfc == ipx_internal_net)
-		return(-EINVAL);
+		return(-EEXIST);
 
 	rt->ir_net = network;
 	rt->ir_intrfc = intrfc;
diff -u --recursive --new-file v1.3.70/linux/net/protocols.c linux/net/protocols.c
--- v1.3.70/linux/net/protocols.c	Tue Aug  8 12:31:44 1995
+++ linux/net/protocols.c	Mon Mar  4 10:37:53 1996
@@ -8,7 +8,7 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/net.h>
-
+#include <linux/fs.h>
 
 #define CONFIG_UNIX		/* always present...	*/
 
diff -u --recursive --new-file v1.3.70/linux/net/unix/Makefile linux/net/unix/Makefile
--- v1.3.70/linux/net/unix/Makefile	Tue Aug 15 20:39:12 1995
+++ linux/net/unix/Makefile	Mon Mar  4 09:16:41 1996
@@ -8,7 +8,7 @@
 # Note 2! The CFLAGS definition is now in the main makefile...
 
 O_TARGET := unix.o
-O_OBJS	 := af_unix.o
+O_OBJS	 := af_unix.o garbage.o
 
 include $(TOPDIR)/Rules.make
 
diff -u --recursive --new-file v1.3.70/linux/net/unix/af_unix.c linux/net/unix/af_unix.c
--- v1.3.70/linux/net/unix/af_unix.c	Fri Feb 23 13:54:44 1996
+++ linux/net/unix/af_unix.c	Mon Mar  4 09:16:41 1996
@@ -21,6 +21,9 @@
  *		Alan Cox	:	Fixed the stupid socketpair bug.
  *		Alan Cox	:	BSD compatibility fine tuning.
  *		Alan Cox	:	Fixed a bug in connect when interrupted.
+ *		Alan Cox	:	Sorted out a proper draft version of
+ *					file descriptor passing hacked up from
+ *					Mike Shaver's work.
  *
  *
  * Known differences from reference BSD that was tested:
@@ -273,7 +276,6 @@
 static int unix_create(struct socket *sock, int protocol)
 {
 	unix_socket *sk;
-/*	printk("Unix create\n");*/
 	if(protocol && protocol != PF_UNIX)
 		return -EPROTONOSUPPORT;
 	sk=(unix_socket *)kmalloc(sizeof(*sk),GFP_KERNEL);
@@ -682,9 +684,194 @@
 	return 0;
 }
 
-/* if msg->accrights != NULL, we have fds to pass.
- * Current implementation passes at most one fd.
+/*
+ *	Support routines for struct cmsghdr handling
+ */
+ 
+static struct cmsghdr *unix_copyrights(void *userp, int len)
+{
+	struct cmsghdr *cm;
+	if(len>256|| len <=0)
+		return NULL;
+	cm=kmalloc(len, GFP_KERNEL);
+	memcpy_fromfs(cm, userp, len);
+	return cm;
+}
+
+/*
+ *	Return a header block
+ */
+ 
+static void unix_returnrights(void *userp, int len, struct cmsghdr *cm)
+{
+	memcpy_tofs(userp, cm, len);
+	kfree(cm);
+}
+
+/*
+ *	Copy file descriptors into system space.
+ */
+ 
+static int unix_fd_copy(struct sock *sk, struct cmsghdr *cmsg, struct file **fp)
+{
+	int num=cmsg->cmsg_len-sizeof(struct cmsghdr);
+	int i;
+	int *fdp=(int *)cmsg->cmsg_data;
+	num/=4;	/* Odd bytes are forgotten in BSD not errored */
+	
+	if(num>=UNIX_MAX_FD)
+		return -EINVAL;
+	
+	/*
+	 *	Verify the descriptors.
+	 */
+	 
+	for(i=0;i<=num;i++)
+	{
+		if(fdp[i]<0||fdp[i]>=NR_OPEN)
+			return -EINVAL;
+		if(current->files->fd[fdp[i]]==NULL)
+			return -EBADF;
+	}
+	
+	/*
+	 *	Make sure the garbage collector can cope.
+	 */
+	 
+	if(unix_gc_free<num)
+		return -ENOBUFS;
+	
+	for(i=0;i<=num;i++)
+	{
+		fp[i]=current->files->fd[fdp[i]];
+		fp[i]->f_count++;
+		unix_gc_add(sk, fp[i]);
+	}
+	
+	return num;
+}
+
+/*
+ *	Free the descriptors in the array
+ */
+
+static void unix_fd_free(struct sock *sk, struct file **fp, int num)
+{
+	int i;
+	for(i=0;i<num;i++)
+	{
+		close_fp(fp[i]);
+		unix_gc_remove(fp[i]);
+	}
+}
+
+/*
+ *	Count the free descriptors available to a process. 
+ *	Interpretation issue: Is the limit the highest descriptor (buggy
+ *	allowing passed fd's higher up to cause a limit to be exceeded) -
+ *	but how the old code did it - or like this...
+ */
+
+int unix_files_free(void)
+{
+	int i;
+	int n=0;
+	for (i=0;i<NR_OPEN;i++)
+	{
+		if(current->files->fd[i])
+			n++;
+	}
+	i=NR_OPEN;
+	if(i>current->rlim[RLIMIT_NOFILE].rlim_cur)
+		i=current->rlim[RLIMIT_NOFILE].rlim_cur;
+	if(n>=i)
+		return 0;
+	return i-n;
+}
+
+/*
+ *	Perform the AF_UNIX file descriptor pass out functionality. This
+ *	is nasty and messy as is the whole design of BSD file passing.
+ */
+
+static void unix_detach_fds(struct sk_buff *skb, struct cmsghdr *cmsg)
+{
+	int i;
+	int cmnum;
+	struct file **fp;
+	struct file **ufp;
+	int *cmfptr=NULL;	/* =NULL To keep gcc happy */
+	int fdnum;
+	int ffree;
+	int ufn=0;
+	if(cmsg==NULL)
+		cmnum=0;
+	else
+	{
+		cmnum=cmsg->cmsg_len-sizeof(struct cmsghdr);
+		cmnum/=sizeof(int);
+		cmfptr=(int *)&cmsg->cmsg_data;
+	}
+	
+	memcpy(&fdnum,skb->h.filp,sizeof(int));
+	fp=(struct file **)(skb->h.filp+sizeof(int));
+	if(cmnum>fdnum)
+		cmnum=fdnum;
+	ffree=unix_files_free();
+	if(cmnum>ffree)
+		cmnum=ffree;
+	ufp=&current->files->fd[0];
+	
+	/*
+	 *	Copy those that fit
+	 */
+	for(i=0;i<cmnum;i++)
+	{
+		/*
+		 *	Insert the fd
+		 */
+		while(ufp[ufn]!=NULL)
+			ufn++;
+		ufp[ufn]=fp[i];
+		*cmfptr++=ufn;
+		FD_CLR(ufn,&current->files->close_on_exec);
+		unix_gc_remove(fp[i]);
+	}
+	/*
+	 *	Dump those that don't
+	 */
+	for(;i<fdnum;i++)
+	{
+		close_fp(fp[i]);
+		unix_gc_remove(fp[i]);
+	}
+	kfree(skb->h.filp);
+	skb->h.filp=NULL;
+	
+}
+
+static void unix_destruct_fds(struct sk_buff *skb)
+{
+	unix_detach_fds(skb,NULL);
+}
+	
+/*
+ *	Attach the file descriptor array to an sk_buff
+ */
+ 
+static void unix_attach_fds(int fpnum,struct file **fp,struct sk_buff *skb)
+{
+	skb->h.filp=kmalloc(sizeof(int)+fpnum*sizeof(struct file *), 
+							GFP_KERNEL);
+	memcpy(skb->h.filp,&fpnum,sizeof(int));
+	memcpy(skb->h.filp+sizeof(int),fp,fpnum*sizeof(struct file *));
+	skb->destructor=unix_destruct_fds;
+}
+
+/*
+ *	Send AF_UNIX data.
  */
+		
 static int unix_sendmsg(struct socket *sock, struct msghdr *msg, int len, int nonblock, int flags)
 {
 	unix_socket *sk=sock->data;
@@ -694,8 +881,9 @@
 	struct sk_buff *skb;
 	int limit=0;
 	int sent=0;
-	/* for passing  fd, NULL indicates no fd */
-	struct file *filp;
+	struct file *fp[UNIX_MAX_FD];
+	int fpnum=0;
+	int fp_attached=0;
 
 	if(sk->err)
 		return sock_error(sk);
@@ -723,27 +911,27 @@
 			return -ENOTCONN;
 	}
 
-
-	/* see if we want to access rights (fd) -- at the moment, 
-	 * we can pass none or 1 fd
-         */
-	filp = NULL;
-	if(msg->msg_accrights) {
-		/* then accrightslen is meaningful */
-		if(msg->msg_accrightslen == sizeof(int)) {
-			int fd;
-
-			fd = get_user((int *) msg->msg_accrights);
-			filp = file_from_fd(fd);
-			if(!filp)
-				return -EBADF;
-		} else if(msg->msg_accrightslen != 0) {
-			/* if we have accrights, we fail here */
-			return -EINVAL;
-		}
+	/*
+	 *	A control message has been attached.
+	 */
+	if(msg->msg_accrights) 
+	{
+		struct cmsghdr *cm=unix_copyrights(msg->msg_accrights, 
+						msg->msg_accrightslen);
+		if(cm==NULL || msg->msg_accrightslen<sizeof(struct cmsghdr) ||
+		   cm->cmsg_type!=SCM_RIGHTS ||
+		   cm->cmsg_level!=SOL_SOCKET ||
+		   msg->msg_accrightslen!=cm->cmsg_len)
+		{
+			kfree(cm);
+		   	return -EINVAL;
+		}
+		fpnum=unix_fd_copy(sk,cm,fp);
+		kfree(cm);
+		if(fpnum<0)
+			return fpnum;
 	}
 
-	/* invariant -- flip points to a file to pass or NULL */
 	while(sent < len)
 	{
 		/*
@@ -756,7 +944,10 @@
 		if(size>(sk->sndbuf-sizeof(struct sk_buff))/2)	/* Keep two messages in the pipe so it schedules better */
 		{
 			if(sock->type==SOCK_DGRAM)
+			{
+				unix_fd_free(sk,fp,fpnum);
 				return -EMSGSIZE;
+			}
 			size=(sk->sndbuf-sizeof(struct sk_buff))/2;
 		}
 		/*
@@ -778,6 +969,7 @@
 		
 		if(skb==NULL)
 		{
+			unix_fd_free(sk,fp,fpnum);
 			if(sent)
 			{
 				sk->err=-err;
@@ -790,6 +982,14 @@
 		skb->sk=sk;
 		skb->free=1;
 		
+		if(fpnum && !fp_attached)
+		{
+			fp_attached=1;
+			unix_attach_fds(fpnum,fp,skb);
+			fpnum=0;
+		}
+		else
+			skb->h.filp=NULL;
 		memcpy_fromiovec(skb_put(skb,size),msg->msg_iov, size);
 
 		cli();
@@ -823,16 +1023,9 @@
 					return err;
 			}
 		}
-		/* at this point, we want to add an fd if we have one  */
-		skb->h.filp = filp;
-		if (filp) {
-			filp->f_count++;
-		}
-		
 		skb_queue_tail(&other->receive_queue, skb);
 		sti();
 		/* if we sent an fd, only do it once */
-		filp = NULL;	
 		other->data_ready(other,size);
 		sent+=size;
 	}
@@ -853,36 +1046,6 @@
 	}
 	sti();
 }
-		
-
-/*
- * return 0 if we can stick the fd, negative errno if we can't
- */
-static int stick_fd(struct file *filp, int *uaddr, int size)
-{
-	int slot;
-	int upper_bound;
-
-	if (!uaddr || size < sizeof(int))
-		return -EINVAL;
-
-	upper_bound = current->rlim[RLIMIT_NOFILE].rlim_cur;
-
-	if (upper_bound > NR_OPEN)
-		upper_bound = NR_OPEN;
-
-	for (slot = 0; slot < upper_bound;  slot++) {
-		if (current->files->fd[slot])
-			continue;
-		/* have an fd */
-		current->files->fd[slot] = filp;
-		FD_CLR(slot, &current->files->close_on_exec);
-		/* need verify area here? */
-		put_user(slot, uaddr);
-		return 0;
-	} 
-	return -EMFILE;
-}
 
 static int unix_recvmsg(struct socket *sock, struct msghdr *msg, int size, int noblock, int flags, int *addr_len)
 {
@@ -894,8 +1057,8 @@
 	int len;
 	int num;
 	struct iovec *iov=msg->msg_iov;
+	struct cmsghdr *cm=NULL;
 	int ct=msg->msg_iovlen;
-	struct file *filp;
 
 	if(flags&MSG_OOB)
 		return -EOPNOTSUPP;
@@ -905,6 +1068,20 @@
 		
 	if(sk->err)
 		return sock_error(sk);
+
+	if(msg->msg_accrights) 
+	{
+		cm=unix_copyrights(msg->msg_accrights, 
+			msg->msg_accrightslen);
+		if(msg->msg_accrightslen<sizeof(struct cmsghdr)||
+		   cm->cmsg_type!=SCM_RIGHTS ||
+		   cm->cmsg_level!=SOL_SOCKET ||
+		   msg->msg_accrightslen!=cm->cmsg_len)
+		{
+			kfree(cm);
+		   	return -EINVAL;
+		}
+	}
 	
 	down(&sk->protinfo.af_unix.readsem);		/* Lock the socket */
 	while(ct--)
@@ -953,11 +1130,8 @@
 			num=min(skb->len,size-copied);
 			memcpy_tofs(sp, skb->data, num);
 
-			if ((filp = skb->h.filp) != NULL) {
-				skb->h.filp = NULL;
-				if (stick_fd(filp, msg->msg_accrights, msg->msg_accrightslen) < 0)
-					close_fp(filp);
-			}
+			if (skb->h.filp!=NULL)
+				unix_detach_fds(skb,cm);
 
 			copied+=num;
 			done+=num;
@@ -970,12 +1144,14 @@
 				continue;
 			}
 			kfree_skb(skb, FREE_WRITE);
-			if(sock->type==SOCK_DGRAM)
+			if(sock->type==SOCK_DGRAM || cm)
 				goto out;
 		}
 	}
 out:
 	up(&sk->protinfo.af_unix.readsem);
+	if(cm)
+		unix_returnrights(msg->msg_accrights,msg->msg_accrightslen,cm);
 	return copied;
 }
 
@@ -1118,7 +1294,7 @@
 
 void unix_proto_init(struct net_proto *pro)
 {
-	printk("NET3: Unix domain sockets 0.10 BETA for Linux NET3.033.\n");
+	printk("NET3: Unix domain sockets 0.12 for Linux NET3.033.\n");
 	sock_register(unix_proto_ops.family, &unix_proto_ops);
 #ifdef CONFIG_PROC_FS
 	proc_net_register(&(struct proc_dir_entry) {
diff -u --recursive --new-file v1.3.70/linux/net/unix/garbage.c linux/net/unix/garbage.c
--- v1.3.70/linux/net/unix/garbage.c	Thu Jan  1 02:00:00 1970
+++ linux/net/unix/garbage.c	Mon Mar  4 10:28:47 1996
@@ -0,0 +1,53 @@
+/*
+ * NET3:	Garbage Collector For AF_UNIX sockets (STUB)
+ *
+ * Authors:	
+ *
+ *		This program is free software; you can redistribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ * Fixes:
+ *
+ */
+ 
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+#include <linux/socket.h>
+#include <linux/un.h>
+#include <linux/fcntl.h>
+#include <linux/termios.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/net.h>
+#include <linux/in.h>
+#include <linux/fs.h>
+#include <linux/malloc.h>
+#include <asm/segment.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <net/sock.h>
+#include <net/tcp.h>
+#include <net/af_unix.h>
+#include <linux/proc_fs.h>
+/*
+ *	Garbage Collector Stubs
+ */
+ 
+
+int unix_gc_free=128;		/* GC slots free */
+
+void unix_gc_remove(struct file *fp)
+{
+	;
+}
+
+void unix_gc_add(struct sock *sk, struct file *fp)
+{
+	;
+}
diff -u --recursive --new-file v1.3.70/linux/scripts/Menuconfig linux/scripts/Menuconfig
--- v1.3.70/linux/scripts/Menuconfig	Wed Feb 28 11:50:18 1996
+++ linux/scripts/Menuconfig	Sun Mar  3 09:22:24 1996
@@ -17,7 +17,7 @@
 # dialog is available at sunsite.unc.edu or a sunsite mirror.
 #
 # Portions of this script were borrowed from the original Configure
-# script used in linux-1.3.55.
+# script.
 #
 # Please send comments / questions / bug fixes to roadcapw@cfw.com
 #
@@ -28,14 +28,12 @@
 # Change this to TRUE if you prefer all kernel options listed
 # in a single menu rather than the standard menu hierarchy.
 #
-# Don't forget to remove linux/.menuconfig.in
-#
 single_menu_mode=
 
 #
 # Make sure we're really running bash.
 #
-[ -z "$BASH" ] && { echo "Configure requires bash" 1>&2; exit 1; }
+[ -z "$BASH" ] && { echo "Menuconfig requires bash" 1>&2; exit 1; }
 
 #
 # Cache function definitions
@@ -57,18 +55,19 @@
      #now pick out the right help text:
      text=$(sed -n "/^$var[ 	]*\$/,\${
                         /^$var[ 	]*\$/d
-                        /^#.*/d;/^[ 	]*\$/q
+                        /^#.*/d
+			/^[ 	]*\$/q
                         p
                     }" Documentation/Configure.help)
 
      if [ -z "$text" ]
      then
-	  echo "There is no help available for this setting."
+	  echo "There is no help available for kernel option."
      else
 	  echo "$text"
      fi
   else
-	 echo "There is no help available for this setting."
+	 echo "There is no help available for kernel option."
   fi
 }
 
@@ -76,29 +75,37 @@
 # Activate a help dialog.
 #
 function help () {
-	extract_help $2 >help.out
-	$DIALOG --backtitle "$backtitle" --title "$1" --textbox help.out 20 75
+	extract_help $1 >help.out
+	$DIALOG --backtitle "$backtitle" --title "$2" --textbox help.out 20 75
 	rm help.out
 }
 
+#
+# Show the README file.
+#
+function show_readme() {
+	$DIALOG --backtitle "$backtitle" \
+		--textbox scripts/README.Menuconfig 21 75
+}
 
 #
-# Init temporary scripts for the current menu.
+# Begin building the dialog menu command and Initialize the 
+# Radiolist function file.
 #
 function menu_name () {
 	echo -ne "$DIALOG --title '$1'\
 			--backtitle '$backtitle' \
 			--menu '$menu_instructions' \
-			21 75 11 '$default' " >submenu
-	>radiolists
+			21 75 11 '$default' " >MCmenu
+	>MCradiolists
 }
 
 #
-# Additional comments are currently semi-supported
+# Additional comments
 #
 function comment () {
 	comment_ctr=$[ comment_ctr + 1 ]
-	echo -ne "': $comment_ctr' '--- $1' " >>submenu
+	echo -ne "': $comment_ctr' '--- $1' " >>MCmenu
 }
 
 #
@@ -112,17 +119,28 @@
 # Add a submenu option to the menu currently under construction.
 #
 function submenu () {
-	echo -ne "'activate_menu $2' '$1  --->' " >>submenu
+	echo -ne "'activate_menu $2' '$1  --->' " >>MCmenu
 }
 
 #
-# This is to handle the Sound configuration.
+# Create a menu entry to handle the traditional sound configuration.
 #
-function yuck1 () {
-	echo -ne "'clear ; $MAKE $2' '$1' " >>submenu
+function soundcfg () {
+	echo -ne "'l_soundcfg' "\
+		 "'Old configuration script "\
+		 "(For: SM Wave, PSS & AudioTrix Pro) -->' " >>MCmenu
 }
 
 #
+# Startup the traditional sound configuration program.
+#
+function l_soundcfg () {
+	clear
+	$MAKE -C drivers/sound config
+}
+
+
+#
 # Create a boolean (Yes/No) function for our current menu
 # which calls our local bool function.
 #
@@ -136,10 +154,10 @@
 	   ;;
 	esac
 
-	echo -ne "'$2' '($flag) $1' " >>submenu
+	echo -ne "'$2' '($flag) $1' " >>MCmenu
 
 	echo -e "function $2 () { l_bool '$1' '$yes' '$no' '$2' }\n" \
-		>>radiolists
+		>>MCradiolists
 }
 
 #
@@ -148,16 +166,19 @@
 function l_bool () {
 	while true
 	do
-		if $DIALOG --title "$1" \
+		$DIALOG --title "$1" \
 			--backtitle "$backtitle" \
 			--radiolist "$radiolist_instructions" 12 70 2 \
-			'y' 'Yes' $2 'n' 'No' $3 2>dialog.out
-		then
-			eval $4=`cat dialog.out`
-			break
-		fi
-			
-		help "$1" "$4"
+			'y' 'Yes' $2 'n' 'No' $3 2>MCdialog.out
+
+		case "$?" in
+		0) eval $4=`cat MCdialog.out`
+		   break ;;
+
+		1) help "$4" "$1" ;;
+
+		*) break ;;
+		esac
 	done
 }
 
@@ -174,10 +195,10 @@
 	   ;;
 	esac
 
-	echo -ne "'$2' '($flag) $1' " >>submenu
+	echo -ne "'$2' '($flag) $1' " >>MCmenu
 
 	echo -e "function $2 () { l_mod_bool '$1' '$module' '$no' '$2' }\n" \
-		>>radiolists
+		>>MCradiolists
 }
 
 #
@@ -186,16 +207,20 @@
 function l_mod_bool() {
 	while true
 	do
-		if $DIALOG --title "$1" \
+		$DIALOG --title "$1" \
 			--backtitle "$backtitle" \
 			--radiolist "$radiolist_instructions" 12 70 2 \
-			'm' 'Module' $2 'n' 'No' $3 2>dialog.out
-		then
-			eval $4=`cat dialog.out`
-			break
-		fi
+			'm' 'Module' $2 'n' 'No' $3 2>MCdialog.out
+
+		case "$?" in
+		0) eval $4=`cat MCdialog.out`
+		   break ;;
+
+		1) help "$4" "$1" ;;
+
+		*) break ;;
+		esac
 			
-		help "$1" "$4"
 	done
 }
 
@@ -221,12 +246,12 @@
    		;;
 		esac
 	
-		echo -ne "'$2' '($flag) $1' " >>submenu
+		echo -ne "'$2' '($flag) $1' " >>MCmenu
 	
 		echo -e "
 		function $2 () { \
 			l_tristate '$1' '$yes' '$no' '$module' '$2'
-		}"  >>radiolists
+		}"  >>MCradiolists
 	fi
 }
 
@@ -236,17 +261,20 @@
 function l_tristate () {
 	while true
 	do
-		if $DIALOG --title "$1" \
+		$DIALOG --title "$1" \
 			--backtitle "$backtitle" \
 			--radiolist "$radiolist_instructions" 13 70 3 \
 			'y' 'Yes' $2 'n' 'No' $3 'm' 'Module' $4 \
-			2>dialog.out
-		then
-			eval $5=`cat dialog.out`
-			break
-		fi
-			
-		help "$1" "$5"
+			2>MCdialog.out
+
+		case "$?" in
+		0) eval $5=`cat MCdialog.out`
+		   break ;;
+
+		1) help "$5" "$1" ;;
+
+		*) break ;;
+		esac
 	done
 }
 
@@ -277,14 +305,14 @@
 }
 
 #
-# Create a function which will call our local int function.
+# Add a menu item which will call our local int function.
 # 
 function int () {
 	eval $2=\${$2:-"$3"} x=\$$2
 
-	echo -ne "'$2' '($x) $1' " >>submenu
+	echo -ne "'$2' '($x) $1' " >>MCmenu
 
-	echo -e "function $2 () { l_int '$1' '$2' '$3' '$x' }\n" >>radiolists
+	echo -e "function $2 () { l_int '$1' '$2' '$3' '$x' }\n" >>MCradiolists
 }
 
 #
@@ -296,9 +324,9 @@
 		if $DIALOG --title "$1" \
 			--backtitle "$backtitle" \
 			--inputbox "$inputbox_instructions_int" \
-			15 55 "$4" 2>dialog.out
+			15 55 "$4" 2>MCdialog.out
 		then
-			answer="`cat dialog.out`"
+			answer="`cat MCdialog.out`"
 			answer="${answer:-$3}"
 
 			if expr $answer : '0$\|-?[1-9][0-9]*$' >/dev/null
@@ -315,20 +343,20 @@
 			break
 		fi
 
-		help "$1" "$2"
+		help "$2" "$1"
 	done
 }
 
 
 #
-# Create a function which will call our local int function.
+# Add a menu item which will call our local int function.
 # 
 function hex () {
 	eval $2=\${$2:-"$3"} x=\${$2##*[x,X]}
 
-	echo -ne "'$2' '($x) $1' " >>submenu
+	echo -ne "'$2' '($x) $1' " >>MCmenu
 
-	echo -e "function $2 () { l_hex '$1' '$2' '$3' '$x' }\n" >>radiolists
+	echo -e "function $2 () { l_hex '$1' '$2' '$3' '$x' }\n" >>MCradiolists
 }
 
 #
@@ -340,9 +368,9 @@
 		if $DIALOG --title "$1" \
 			--backtitle "$backtitle" \
 			--inputbox "$inputbox_instructions_hex" \
-			15 55 "$4" 2>dialog.out
+			15 55 "$4" 2>MCdialog.out
 		then
-			answer="`cat dialog.out`"
+			answer="`cat MCdialog.out`"
 			answer="${answer:-$3}"
 			answer="${answer##*[x,X]}"
 
@@ -360,12 +388,12 @@
 			break
 		fi
 
-		help "$1" "$2"
+		help "$2" "$1"
 	done
 }
 
 #
-# Create a function which will call our local One-of-Many choice list.
+# Add a menu item which will call our local One-of-Many choice list.
 #
 function choice () {
 	#
@@ -395,12 +423,12 @@
 
 	: ${current:=$default}
 
-	echo -ne "'$firstchoice' '($current) $title' " >>submenu
+	echo -ne "'$firstchoice' '($current) $title' " >>MCmenu
 
 	echo -e "
 	function $firstchoice () {
 		l_choice '$title' \"$choices\" $current
-	}\n" >>radiolists
+	}\n" >>MCradiolists
 }
 
 
@@ -433,13 +461,13 @@
 		if $DIALOG --title "$title" \
 			--backtitle "$backtitle" \
 			--radiolist "$radiolist_instructions" \
-			22 70 11 $list 2>dialog.out
+			22 70 11 $list 2>MCdialog.out
 		then
-			choice=`cat dialog.out`
+			choice=`cat MCdialog.out`
 			break
 		fi
 
-		help "$title" "$firstchoice"
+		help "$firstchoice" "$title"
 	done
 
 	#
@@ -462,114 +490,130 @@
 
 
 #
-# Now parse the configuration files and create our mini scripts.
-# Each script represents a separate menu which when taken together
-# form a linked menu tree.  Since one configuration file
-# may source another elsewhere in the kernel source tree, this 
-# function is recursive.
+# A faster awk based recursive parser. (I hope)
 #
-function parse_config_files () {
-	if [ "_$single_menu_mode" = "_TRUE" ]
-	then
-		parse_single_menu $1
-		return
-	fi
-
-	while read command args
-	do
-		case $command in
-
-		#
-		# Will it ever happen that mainmenu_option will be followed
-		# by anything other then "next_comment"?  This assumes not..
-		#
-		mainmenu_option) 
-			comment_is_option=TRUE
-			;;
-
-		comment)
-			if [ "$comment_is_option" ]
-			then
-				comment_is_option=
-
-				stack="$submenu$stack"
-
-				menu_no=$[menu_no + 1]
-				x="submenu$menu_no"
-
-				echo "submenu $args $x" >> $submenu
-
-				submenu=$x
-				echo menu_name $args >$submenu
-			else
-				echo comment $args >> $submenu
-			fi
-			;;
-	
-		endmenu)
-			submenu="${stack%%*}"
-			stack="${stack#*}"
-			;;
-
-		mainmenu_name)
-			echo menu_name "'Main Menu'" > submenu0
-			;;
-
-		\$MAKE) echo "yuck1 'Configure (You must do this!)' '$args'"\
-				>>$submenu
-			;;
-
-		source)
-			parse_config_files "$args"
-			;;
-
-		'#'|'')  : ;;
-
-		*)	echo $command $args >> $submenu
-			;;
-		esac
-	done < $1
+function parser1 () {
+awk '
+BEGIN {
+	menu_no = 0
+	comment_is_option = 0
+	parser("'$CONFIG_IN'","MCmenu0")
+}
+
+function parser(ifile,menu) {
+
+	while (getline <ifile) {
+		if ($1 == "mainmenu_option") {
+			comment_is_option = "1"
+		}
+		else if ($1 == "comment" && comment_is_option == "1") {
+			comment_is_option= "0"
+			sub($1,"",$0)
+			++menu_no
+
+			printf("submenu %s MCmenu%s\n", $0, menu_no) >>menu
+
+			printf( "function MCmenu%s () {\n"\
+				"default=$1\n"\
+				"menu_name %s\n",\
+				 menu_no, $0) >"MCmenu"menu_no
+
+			parser(ifile, "MCmenu"menu_no)
+		}
+		else if ($1 ~ "endmenu") {
+			printf("}\n") >>menu
+			return
+		} 
+		else if ($0 ~ /^#|$MAKE|mainmenu_name/) {
+			printf("") >>menu
+		}
+		else if ($1 == "source") {
+			# Yuk!  Blah!  Phooey!
+			if ($2 ~ "drivers/sound") {
+				printf("soundcfg\n") >>menu
+			}
+
+			parser($2,menu)
+		}
+		else {
+			print >>menu
+		}
+	}
+}'
+}
+
+#
+# Secondary parser for single menu mode.
+#
+function parser2 () {
+awk '
+BEGIN {
+	parser("'$CONFIG_IN'","MCmenu0")
+}
+
+function parser(ifile,menu) {
+
+	while (getline <ifile) {
+		if ($1 ~ /mainmenu_option|endmenu/) {
+			printf("") >>menu
+		} 
+		else if ($0 ~ /^#|$MAKE|mainmenu_name/) {
+			printf("") >>menu
+		}
+		else if ($1 == "source") {
+			if ($2 ~ "drivers/sound") {
+				printf("soundcfg\n") >>menu
+			}
+			parser($2,menu)
+		}
+		else {
+			print >>menu
+		}
+	}
+}'
 }
 
 #
-# Parses configuration files into a single menu structure.
+# Parse all the config.in files into mini scripts.
 #
-function parse_single_menu () {
+function parse_config_files () {
+	rm -f MCmenu*
 
-	while read command args
-	do
-		case $command in
+	echo "function MCmenu0 () {" >MCmenu0
+	echo 'default=$1' >>MCmenu0
+	echo "menu_name 'Main Menu'" >>MCmenu0
 
-		mainmenu_option | \
-		endmenu)
-			: ;;
 
-		mainmenu_name)
-			echo menu_name "'Main Menu'" > submenu0
-			;;
-
-		\$MAKE) echo "yuck1 'Configure (You must do this!)' '$args'"\
-				>>$submenu
-			;;
+	if [ "_$single_menu_mode" = "_TRUE" ]
+	then
+		parser2
+	else
+		parser1
+	fi
 
-		source)
-			parse_single_menu "$args"
-			;;
+	echo "}" >>MCmenu0
 
-		'#'|'')  : ;;
+	#
+	# These mini scripts must be sourced into the current
+	# environment in order for all of this to work.  Leaving
+	# them on the disk as executables screws up the recursion
+	# in activate_menu(), among other things.  Once they are
+	# sourced we can disgard them.
+	#
+	for i in MCmenu*
+	do
+		source $i
+	done
 
-		*)	echo $command $args >> $submenu
-			;;
-		esac
-	done < $1
+	rm -f MCmenu*
 }
 
 #
 # This is the menu tree's bootstrap.
 #
-# Executes a mini script to create a set of functions, one per configuration
-# option.  These functions will in turn execute dialog commands or recursively
-# call other mini scripts.
+# Executes the parsed menus on demand and creates a set of functions,
+# one per configuration option.  These functions will in turn execute
+# dialog commands or recursively call other menus.
 #
 function activate_menu () {
 
@@ -577,23 +621,24 @@
 	do
 		comment_ctr=0
 		$1 "$default"		#Create the radiolists and dialog cmd
-		. radiolists		#Read in the dialog functions.
+		. MCradiolists		#Read in the dialog functions.
 
-		. submenu 2>dialog.out	#Activate this menu
+		. MCmenu 2>MCdialog.out	#Activate this menu
 
 		case "$?" in
 		0)
-			defaults="`cat dialog.out`$defaults"  #pseudo stack
-			source dialog.out
-			default="${defaults%%*}" defaults="${defaults#*}"
+			defaults="`cat MCdialog.out`$defaults"  #psuedo stack
+			. MCdialog.out
+			default="${defaults%%*}" defaults="${defaults#*}"
 			;;
 		2)	
-			echo >>dialog.out
-			read selection <dialog.out
-			default="${selection##* }"
+			echo >>MCdialog.out
+			read selection <MCdialog.out
+			default="${selection%% *}"
+
 			case "$selection" in
-			*"-->"*) : ;;
-			*)	 eval help "$selection" ;;
+			*"-->"*) show_readme ;;
+			*)	 eval help $selection ;;
 			esac
 			;;
 		255|1)
@@ -733,12 +778,6 @@
 		fi
 	}
 
-	#
-	# This will hopfully prevent the sound configuration from
-	# running again.  (blagh!)
-	#
-	MAKE=:
-
 	CONFIG=.tmpconfig
 	CONFIG_H=.tmpconfig.h
 
@@ -749,16 +788,33 @@
 	echo "/*" >$CONFIG_H
 	echo " * Automatically generated by make menuconfig: don't edit" >>$CONFIG_H
 	echo " */" >>$CONFIG_H
-	
-	. $CONFIG_IN
 
-	if [ -f .config ]
+	MAKE=:	#To prevent sound Makefile from running.
+	
+	if . $CONFIG_IN >>.menuconfig.log 2>&1
 	then
-		rm -f .config.old
-		mv .config .config.old
+		#
+		# Create the sound driver's config files for cards
+		# Which are compatible with the new config method.
+		#
+		if [ "_$CONFIG_TRIX"   != "_y" -a\
+		     "_$CONFIG_PSS"    != "_y" -a\
+		     "_$CONFIG_SMWAVE" != "_y"    ]
+		then
+			make -C drivers/sound kernelconfig >>.menuconfig.log 2>&1
+		fi
+
+		if [ -f .config ]
+		then
+			rm -f .config.old
+			mv .config .config.old
+		fi
+		mv .tmpconfig .config
+		mv .tmpconfig.h include/linux/autoconf.h
+		return 0
+	else
+		return 1
 	fi
-	mv .tmpconfig .config
-	mv .tmpconfig.h include/linux/autoconf.h
 }
 
 #
@@ -770,25 +826,24 @@
 }
 
 cleanup1 () {
-	rm -f submenu* radiolists dialog.out help.out
+	rm -f MCmenu* MCradiolists MCdialog.out help.out
 }
 
 cleanup2 () {
 	rm -f .tmpconfig .tmpconfig.h
 }
 
-
 menu_instructions="\
 Arrow keys navigate the menu.  \
-Highlighted letters are shortcuts. \
+Highlighted letters are hotkeys. \
 Select an item with <Space Bar> or <Enter>. \
-When finished press <E> or <X> or <Esc>.  \
+When finished press <Esc><Esc> or <X>.  \
 (*) indicates an option will be compiled into the kernel.  \
 (M) indicates an option will be compiled as a module."
 
 radiolist_instructions="\
-Use the arrow keys to navigate this radiolist or \
-press the first letter of the item you wish to select \
+Use the arrow keys to navigate this window or \
+press the hotkey of the item you wish to select \
 followed by the <SPACE BAR>.
 Press <H> for additional information about this option."
 
@@ -805,12 +860,9 @@
 
 DIALOG="./scripts/lxdialog/lxdialog"
 
-comment_is_option=
-menu_no=0
-submenu=submenu0
 kernel_version="${VERSION}.${PATCHLEVEL}.${SUBLEVEL}"
 
-trap "cleanup ; rm -f .menuconfig.in ; exit 1" 1 2 15
+trap "cleanup ; rm -f .menuconfig ; exit 1" 1 2 15
 
 #
 # Locate default files.
@@ -842,57 +894,50 @@
   echo "#"
 fi
 
+# Fresh new log.
+>.menuconfig.log
+
+
+$DIALOG	--backtitle "$backtitle" \
+	--infobox "Preparing configuration scripts..." 3 40
 
 #
-# Convert the configuration files into our mini scripts.
-# Then put all the mini scripts into a single file which should
-# stick around and act as a cache until the kernel release changes
-# or "make mrproper".
+# Check kernel version of previous menuconfig build.
+# If it's different then we should tell the sound driver
+# to rebuild it's Config.in file.
 #
-if [ -e .menuconfig.in ]
+rebuildsound=TRUE
+if [ -e .menuconfig ]
 then
-	read x <.menuconfig.in
-	if [ "$x" != "# $kernel_version" ]
+	read x <.menuconfig
+	if [ "$x" = "# $kernel_version" ]
 	then
-		rm -f .menuconfig.in
+		rebuildsound=
 	fi
 fi
 
-if [ ! -e .menuconfig.in ]
+if [ "$rebuildsound" ]
 then
-	$DIALOG	--backtitle "$backtitle" \
-		--infobox "Compiling configuration script..." 3 40
-
-	rm -f submenu*
-	parse_config_files $CONFIG_IN
-
-	#
-	# For handling Sound configuration. (Yuk!)
+	# Activate the Linux compatible sound configuration.
+	# This may not work for all sound cards.  (See sound docs)
 	#
-	echo '$MAKE $*' >submenu999
-
-	echo "# $kernel_version" >.menuconfig.in
-
-	for i in submenu*
-	do
-		echo "function $i () {"
-		echo 'default=$1'
-		cat $i
-		echo -e "}\n\n"
-	done >> .menuconfig.in
+	make -C drivers/sound mkscript >>.menuconfig.log 2>&1
 
-	rm -f submenu*
+	echo "# $kernel_version" >.menuconfig
 fi
 
-source .menuconfig.in
+#
+# Read config.in files and parse them into one shell function per menu.
+#
+parse_config_files $CONFIG_IN
 
 #
 # Start the ball rolling from the top.
 #
-activate_menu submenu0
+activate_menu MCmenu0
 
 #
-# We're done with the menu scripts.  Get rid of them.
+# All done!
 #
 cleanup1
 
@@ -905,15 +950,19 @@
 then
 	save_configuration
 
-	$DIALOG --backtitle "$backtitle" --infobox "\
-The linux kernel is now hopefully configured for your setup.  \
-Check the top-level Makefile for additional configuration, \
-and do a 'make dep ; make clean' if you want to be sure all \
-the files are correctly re-made." 7 60
+	clear
+	cat <<EOM
+
+
+The linux kernel is now hopefully configured for your setup.
+Check the top-level Makefile for additional configuration,
+and do a 'make dep ; make clean' if you want to be sure all
+the files are correctly re-made.
+
+EOM
 else
-	$DIALOG --backtitle "$backtitle" \
-		--infobox "Your new configuration was not saved." 3 42 
-	
+	clear
+	echo -e "Your kernel configuration changes where NOT saved.\n"
 fi
 
 
diff -u --recursive --new-file v1.3.70/linux/scripts/README.Menuconfig linux/scripts/README.Menuconfig
--- v1.3.70/linux/scripts/README.Menuconfig	Sat Feb 17 16:02:59 1996
+++ linux/scripts/README.Menuconfig	Sun Mar  3 09:22:24 1996
@@ -1,113 +1,130 @@
-This is the Linux kernel menuconfig README file.
+This is the Linux kernel Menuconfig README file.
 
-Menuconfig gives the linux kernel configuration a long needed face lift.
-It features text based color menus, radiolists and dialogs, but does
-not require X Windows.  With this utility you can easily select a
-kernel option to modify without having to sift through 100 other options.
+Menuconfig gives the Linux kernel configuration a long needed face
+lift.  Featuring text based color menus and dialogs, it does not
+require X Windows.  With this utility you can easily select a kernel
+option to modify without sifting through 100 other options.
+
+The windowing support utility (lxdialog) is a VERY modified version of
+the dialog utility by Savio Lam <lam836@cs.cuhk.hk>.  Although lxdialog
+is significantly different from dialog, I have left Savio's copyrights
+intact.  Please DO NOT contact Savio with questions about lxdialog.
+He will not be able to assist.
 
-The windowing support utility (lxdialog) is a VERY modified version of the
-dialog utility by Savio Lam <lam836@cs.cuhk.hk>.  Although lxdialog is 
-significantly different from dialog, I have left Savio's copyrights intact.
-Please DO NOT contact Savio with questions about lxdialog.  He will not be
-able to assist.
-
-
-Please feel free to send any questions or comments or suggestions to
+Please feel free to send any questions, comments or suggestions to
 William Roadcap <roadcapw@cfw.com>.
 
+READ ON! There are hints and notices below...
 
-Some menuconfig keyboard hints:
+
+Some Menuconfig keyboard hints:
 
 Menus
 ----------
 o  Use the Up/Down arrow keys (cursor keys) to highlight the item 
    or submenu you wish to select.  
-   Shortcut: Press the option's highlighted letter. (usually the first)
+   Shortcut: Press the option's highlighted letter (hotkey).
+             Pressing a hotkey more than once will sequence
+             through all items which use that hotkey.
 
 o  Use the cursor keys to highlight <Select> and press <ENTER>.  
-   Shortcut: Press <Space Bar> or <S> if there's no item beginning with <S>.
+   Shortcut: Press the <SPACE BAR> or <S> if there is no item using
+             <S> as it's hotkey.
 
-o  To exit a menu use the cursor keys to highlight the <Exit> button and 
-   press <ENTER>.  
-   Shortcut: Press <Esc> or <E> or <X> if there's no option beginning 
-             those letters.
+o  To exit a menu use the cursor keys to highlight the <Exit> button
+   and press <ENTER>.  
+   Shortcut: Press <ESC><ESC> or <E> or <X> if there is no hotkey
+             using those letters.  You may press a single <ESC>, but
+             there is a delayed response which you may find annoying.
 
-   Also, the <TAB> key will toggle between <Select>, <Exit> and <Help>
+   Also, the <TAB> and cursor keys will cycle between <Select>,
+   <Exit> and <Help>
 
-o  To get help with an item, use the cursor keys to highlight <Help> and
-   Press <ENTER>.
+o  To get help with an item, use the cursor keys to highlight <Help>
+   and Press <ENTER>.
    Shortcut: Press <H> or <?>.
 
 
 Radiolists  (Yes/No/Module)
 -----------
 o  Use the cursor keys to select the option you wish to set and press
-   <O> or the <SPACE BAR>.
+   <S> or the <SPACE BAR>.
    Shortcut: Press the first letter of the option you wish to set then
-             press <O> or <SPACE BAR>.
+             press <S> or <SPACE BAR>.
 
 o  To see available help for the item, use the cursor keys to highlight
    <Help> and Press <ENTER>.
    Shortcut: Press <H> or <?>.
 
-   Also, the <TAB> key will toggle between <Select> and <Help>
+   Also, the <TAB> and cursor keys will cycle between <Select> and
+   <Help>
 
 
 Data Entry
 -----------
 o  Enter the requested information and press <ENTER>
+   If you are entering hexidecimal values, it is not necessary to
+   add the '0x' prefix to the entry.
 
-o  For help, use the <TAB> key to highlight the help option and 
-   press <ENTER>.  You can try <TAB><H> as well.
+o  For help, use the <TAB> or cursor keys to highlight the help option
+   and press <ENTER>.  You can try <TAB><H> as well.
 
 
 Text Box    (Help Window)
 --------
-o  Use the cursor keys to scroll up/down/left/right.
+o  Use the cursor keys to scroll up/down/left/right.  The VI editor
+   keys h,j,k,l function here as do <SPACE BAR> and <B> for those
+   who are familiar with less and lynx.
 
-o  Press <E>, <X>, <Enter> or <Esc> to exit.
+o  Press <E>, <X>, <Enter> or <Esc><Esc> to exit.
 
 
 Final Acceptance
 ----------------
-With the exception of sound configuration, YOUR CHANGES ARE NOT FINAL.
-You will be given a last chance to confirm them prior to exiting menuconfig.
-
+With the exception of the old style sound configuration,
+YOUR CHANGES ARE NOT FINAL.  You will be given a last chance to
+confirm them prior to exiting Menuconfig.
+
+If Menuconfig quits with an error while saving your configuration,
+you may look in the file /usr/src/linux/.menuconfig.log for
+information which may help you determine the cause.
 
 
 Other information:
 
-Menuconfig attempts to reduce the amount of time it takes to reconfigure
-the kernel. 
-
-Menuconfig keeps a cache of it's compiled configuration scripts in 
-/usr/src/linux/.menuconfig.in.  This file will only be rebuilt if you
-do a 'make mrproper' or if the kernel version changes.  If you make manual 
-changes to any of the config.in files in the kernel source tree, you 
-must remove .menuconfig.in so that menuconfig will know to rebuild it.
-
 The windowing utility, lxdialog, will only be rebuilt if your kernel
-source tree is fresh, or changes are patched into it via a kernel patch
-or you do 'make mrproper'.  If changes to lxdialog are patched in, most
-likely the rebuild time will be short.  You may force a complete rebuild
-of lxdialog by changing to it's directory and doing 'make clean all'
+source tree is fresh, or changes are patched into it via a kernel
+patch or you do 'make mrproper'.  If changes to lxdialog are patched
+in, most likely the rebuild time will be short.  You may force a
+complete rebuild of lxdialog by changing to it's directory and doing
+'make clean all'
 
 NOTICE:  lxdialog requires the ncurses libraries to compile.  If you
          don't already have ncurses you really should get it.
 
-         The makefile for lxdialog attempts to find your ncurses header
-         file.  Although it should find the header for older versions of
-         ncurses, it is probably a good idea to get the latest ncurses
-         anyway.
-
-WARNING: It is not recommended that you change any defines in lxdialog's
-         header files.
-
+         The makefile for lxdialog attempts to find your ncurses
+         header file.  Although it should find the header for older
+         versions of ncurses, it is probably a good idea to get the
+         latest ncurses anyway.
+
+WARNING: It is not recommended that you change any defines in
+         lxdialog's header files.  If you have a grayscale display and
+         are brave, you may tinker with color.h to tune the colors to
+         your preference.
+
+COMPATABILITY ISSUE:
+         There have been some compatability problems reported with
+         older versions of bash and sed.  I am trying to work these
+         out but it is preferable that you upgrade those utilities.
+
+
+******** IMPORTANT, OPTIONAL ALTERNATE PERSONALITY AVAILABLE ********
+********                                                     ********
+If you prefer to have all of the kernel options listed in a single
+menu, rather than the default multimenu hierarchy, you may edit the
+Menuconfig script and change the line "single_menu_mode="  to 
+"single_menu_mode=TRUE".
 
-*** IMPORTANT, OPTIONAL ALTERNATE PERSONALITY AVAILABLE ***
-***                                                     ***
-If you prefer to have all of the kernel options listed in a single menu, 
-rather than the default multimenu hierarchy, you may edit the Menuconfig 
-script and change the line "single_menu_mode="  to "single_menu_mode=TRUE".  
-Don't forget to remove linux/.menuconfig.in afterwards.
+This mode is not recommended unless you have a fairly fast machine.
 
+<END OF README>
diff -u --recursive --new-file v1.3.70/linux/scripts/lxdialog/Makefile linux/scripts/lxdialog/Makefile
--- v1.3.70/linux/scripts/lxdialog/Makefile	Fri Feb  9 17:53:13 1996
+++ linux/scripts/lxdialog/Makefile	Sun Mar  3 09:22:24 1996
@@ -2,25 +2,24 @@
 CPP = gcc -E
 OPTIM = -O2 -Wall -fomit-frame-pointer
 
-CFLAGS = $(OPTIM) $(CURSES) -DLOCALE 
+CFLAGS = $(OPTIM) -DLOCALE 
 LDFLAGS = -s -L .
 LDLIBS = -lncurses
 
-CURSES =  -DCURSES_LOC="<curses.h>"
-
 ifeq (/usr/include/ncurses/ncurses.h, $(wildcard /usr/include/ncurses/ncurses.h))
-        CFLAGS += -I/usr/include/ncurses
-        CURSES =  -DCURSES_LOC="<ncurses.h>"
+        CFLAGS += -I/usr/include/ncurses -DCURSES_LOC="<ncurses.h>"
 else
 ifeq (/usr/include/ncurses/curses.h, $(wildcard /usr/include/ncurses/curses.h))
-        CFLAGS += -I/usr/include/ncurses
-        CURSES =  -DCURSES_LOC="<curses.h>"
+        CFLAGS += -I/usr/include/ncurses -DCURSES_LOC="<curses.h>"
 else
 ifeq (/usr/include/ncurses.h, $(wildcard /usr/include/ncurses.h))
-        CURSES =  -DCURSES_LOC="<ncurses.h>"
+        CFLAGS += -DCURSES_LOC="<ncurses.h>"
+else
+	CFLAGS += -DCURSES_LOC="<curses.h>"
 endif
 endif
 endif
+
 
 OBJS = checklist.o menubox.o textbox.o yesno.o inputbox.o \
        util.o lxdialog.o msgbox.o
diff -u --recursive --new-file v1.3.70/linux/scripts/lxdialog/checklist.c linux/scripts/lxdialog/checklist.c
--- v1.3.70/linux/scripts/lxdialog/checklist.c	Sat Mar  2 10:43:47 1996
+++ linux/scripts/lxdialog/checklist.c	Sun Mar  3 09:22:25 1996
@@ -96,14 +96,15 @@
  *  Display the termination buttons
  */
 static void
-print_buttons( WINDOW *dialog, int height, int width, int okval, int cancelval)
+print_buttons( WINDOW *dialog, int height, int width, int selected)
 {
     int x = width / 2 - 11;
     int y = height - 2;
 
-    print_button (dialog, "Select", y, x, okval);
-    print_button (dialog, " Help ", y, x + 14, cancelval);
+    print_button (dialog, "Select", y, x, selected == 0);
+    print_button (dialog, " Help ", y, x + 14, selected == 1);
 
+    wmove(dialog, y, x+1 + 14*selected);
     wrefresh (dialog);
 }
 
@@ -114,8 +115,9 @@
 int
 dialog_checklist (const char *title, const char *prompt, int height, int width,
 	int list_height, int item_no, const char * const * items, int flag)
+	
 {
-    int i, x, y, cur_x, cur_y, box_x, box_y;
+    int i, x, y, box_x, box_y;
     int key = 0, button = 0, choice = 0, scroll = 0, max_choice, *status;
     WINDOW *dialog, *list;
 
@@ -166,7 +168,6 @@
     print_autowrap (dialog, prompt, width - 2, 1, 3);
 
     list_width = width - 6;
-    getyx (dialog, cur_y, cur_x);
     box_y = height - list_height - 5;
     box_x = (width - list_width) / 2 - 1;
 
@@ -196,7 +197,7 @@
     print_arrows(dialog, choice, item_no, scroll,
 			box_y, box_x + check_x + 5, list_height);
 
-    print_buttons(dialog, height, width, TRUE, FALSE);
+    print_buttons(dialog, height, width, 0);
 
     while (key != ESC) {
 	key = wgetch (dialog);
@@ -213,7 +214,6 @@
 		    if (!scroll)
 			continue;
 		    /* Scroll list down */
-		    getyx (dialog, cur_y, cur_x);
 		    if (list_height > 1) {
 			/* De-highlight current first item */
 			print_item (list, items[scroll * 3 + 1],
@@ -230,7 +230,6 @@
     		    print_arrows(dialog, choice, item_no, scroll,
 				box_y, box_x + check_x + 5, list_height);
 
-		    wmove (dialog, cur_y, cur_x);
 		    wrefresh (dialog);
 
 		    continue;	/* wait for another key press */
@@ -241,7 +240,6 @@
 		    if (scroll + choice >= item_no - 1)
 			continue;
 		    /* Scroll list up */
-		    getyx (dialog, cur_y, cur_x);
 		    if (list_height > 1) {
 			/* De-highlight current last item before scrolling up */
 			print_item (list, items[(scroll + max_choice - 1) * 3 + 1],
@@ -260,7 +258,6 @@
     		    print_arrows(dialog, choice, item_no, scroll,
 				box_y, box_x + check_x + 5, list_height);
 
-		    wmove (dialog, cur_y, cur_x);
 		    wrefresh (dialog);
 
 		    continue;	/* wait for another key press */
@@ -269,7 +266,6 @@
 	    }
 	    if (i != choice) {
 		/* De-highlight current item */
-		getyx (dialog, cur_y, cur_x);
 		print_item (list, items[(scroll + choice) * 3 + 1],
 			    status[scroll + choice], choice, FALSE);
 		/* Highlight new item */
@@ -277,7 +273,6 @@
 		print_item (list, items[(scroll + choice) * 3 + 1],
 			    status[scroll + choice], choice, TRUE);
 		wnoutrefresh (list);
-		wmove (dialog, cur_y, cur_x);
 		wrefresh (dialog);
 	    }
 	    continue;		/* wait for another key press */
@@ -289,17 +284,13 @@
 	    delwin (dialog);
 	    free (status);
 	    return 1;
-	    return 1;
 	case TAB:
 	case KEY_LEFT:
 	case KEY_RIGHT:
-	    if (!button) {
-		button = 1;	/* "Help" button selected */
-		print_buttons(dialog, height, width, FALSE, TRUE);
-	    } else {
-		button = 0;	/* "OK" button selected */
-		print_buttons(dialog, height, width, TRUE, FALSE);
-	    }
+	    button = ((key == KEY_LEFT ? --button : ++button) < 0)
+			? 1 : (button > 1 ? 0 : button);
+
+	    print_buttons(dialog, height, width, button);
 	    wrefresh (dialog);
 	    break;
 	case 'S':
@@ -309,7 +300,6 @@
 	    if (!button) {
 		if (flag == FLAG_CHECK) {
 		    status[scroll + choice] = !status[scroll + choice];
-		    getyx (dialog, cur_y, cur_x);
 		    wmove (list, choice, check_x);
 		    wattrset (list, check_selected_attr);
 		    wprintw (list, "[%c]", status[scroll + choice] ? 'X' : ' ');
@@ -318,14 +308,12 @@
 			for (i = 0; i < item_no; i++)
 			    status[i] = 0;
 			status[scroll + choice] = 1;
-			getyx (dialog, cur_y, cur_x);
 			for (i = 0; i < max_choice; i++)
 			    print_item (list, items[(scroll + i) * 3 + 1],
 					status[scroll + i], i, i == choice);
 		    }
 		}
 		wnoutrefresh (list);
-		wmove (dialog, cur_y, cur_x);
 		wrefresh (dialog);
             
 		for (i = 0; i < item_no; i++) {
diff -u --recursive --new-file v1.3.70/linux/scripts/lxdialog/menubox.c linux/scripts/lxdialog/menubox.c
--- v1.3.70/linux/scripts/lxdialog/menubox.c	Sat Feb 17 16:02:59 1996
+++ linux/scripts/lxdialog/menubox.c	Sun Mar  3 09:22:25 1996
@@ -53,6 +53,10 @@
 print_arrows (WINDOW * win, int choice, int item_no, int scroll,
 		int y, int x, int height)
 {
+    int cur_y, cur_x;
+
+    getyx(win, cur_y, cur_x);
+
     wmove(win, y, x);
 
     if (scroll > 0) {
@@ -83,22 +87,24 @@
 	waddch (win, ACS_HLINE);
 	waddch (win, ACS_HLINE);
    }
+
+   wmove(win, cur_y, cur_x);
 }
 
 /*
  * Display the termination buttons.
  */
 static void
-print_buttons (WINDOW *win, int height, int width,
-		int okval, int exitval, int cancelval)
+print_buttons (WINDOW *win, int height, int width, int selected)
 {
     int x = width / 2 - 16;
     int y = height - 2;
 
-    print_button (win, "Select", y, x, okval);
-    print_button (win, " Exit ", y, x + 12, exitval);
-    print_button (win, " Help ", y, x + 24, cancelval);
+    print_button (win, "Select", y, x, selected == 0);
+    print_button (win, " Exit ", y, x + 12, selected == 1);
+    print_button (win, " Help ", y, x + 24, selected == 2);
 
+    wmove(win, y, x+1+12*selected);
     wrefresh (win);
 }
 
@@ -111,7 +117,7 @@
 		const char * const * items)
 
 {
-    int i, j, x, y, cur_x, cur_y, box_x, box_y;
+    int i, j, x, y, box_x, box_y;
     int key = 0, button = 0, scroll = 0, choice = 0, first_item = 0, max_choice;
     WINDOW *dialog, *menu;
 
@@ -145,7 +151,6 @@
     print_autowrap (dialog, prompt, width - 2, 1, 3);
 
     menu_width = width - 6;
-    getyx (dialog, cur_y, cur_x);
     box_y = height - menu_height - 5;
     box_x = (width - menu_width) / 2 - 1;
 
@@ -186,7 +191,7 @@
     print_arrows(dialog, choice, item_no, scroll,
 		 box_y, box_x+item_x+1, menu_height);
 
-    print_buttons (dialog, height, width, TRUE, FALSE, FALSE);
+    print_buttons (dialog, height, width, 0);
 
     while (key != ESC) {
 	key = wgetch (dialog);
@@ -209,8 +214,6 @@
 		    if (scroll) {
 
 			/* Scroll menu down */
-			getyx (dialog, cur_y, cur_x);
-
 			if (menu_height > 1) {
 			    /* De-highlight current first item */
 			    print_item (menu, items[scroll*2+1], 0, FALSE,
@@ -227,7 +230,6 @@
     			print_arrows(dialog, choice, item_no, scroll,
 		 			box_y, box_x+item_x+1, menu_height);
 
-			wmove (dialog, cur_y, cur_x);
 		    }
 		    continue;	/* wait for another key press */
 		} else
@@ -236,7 +238,6 @@
 		if (choice == max_choice - 1) {
 		    if (scroll + choice < item_no - 1) {
 			/* Scroll menu up */
-			getyx (dialog, cur_y, cur_x);
 			if (menu_height > 1) {
 			    /* De-highlight current last item */
 			    print_item (menu, items[(scroll + max_choice - 1)
@@ -256,7 +257,6 @@
     			print_arrows(dialog, choice, item_no, scroll,
 		 			box_y, box_x+item_x+1, menu_height);
 
-			wmove (dialog, cur_y, cur_x);
 			wrefresh (dialog);
 		    }
 		    continue;	/* wait for another key press */
@@ -265,7 +265,6 @@
 
 	    if (i != choice) {
 		/* De-highlight current item */
-		getyx (dialog, cur_y, cur_x);	/* Save cursor position */
 		print_item (menu, items[(scroll+choice)*2+1], choice, FALSE,
                                 (items[(scroll+choice)*2][0] != ':'));
 
@@ -274,30 +273,19 @@
 		print_item (menu, items[(scroll+choice)*2+1], choice, TRUE,
                                 (items[(scroll+choice)*2][0] != ':'));
 		wnoutrefresh (menu);
-		wmove (dialog, cur_y, cur_x);
 		wrefresh (dialog);
 	    }
 	    continue;		/* wait for another key press */
 	}
 
 	switch (key) {
-	case TAB:
 	case KEY_LEFT:
+	case TAB:
 	case KEY_RIGHT:
-	    switch (button) {
-	    case 0:
-		button = 1;
-		print_buttons(dialog, height, width, FALSE, TRUE, FALSE);
-		break;
-	    case 1:
-		button = 2;
-		print_buttons(dialog, height, width, FALSE, FALSE, TRUE);
-		break;
-	    case 2:
-		button = 0;
-		print_buttons(dialog, height, width, TRUE, FALSE, FALSE);
-		break;
-	    }
+	    button = ((key == KEY_LEFT ? --button : ++button) < 0)
+			? 2 : (button > 2 ? 0 : button);
+
+	    print_buttons(dialog, height, width, button);
 	    wrefresh (dialog);
 	    break;
 	case ' ':
@@ -313,10 +301,10 @@
 	case '\n':
 	    delwin (dialog);
 	    if (button == 2) 
-            	fprintf(stderr, "\"%s\" %s", 
+            	fprintf(stderr, "\"%s\" \"%s\"", 
+			items[(scroll + choice) * 2],
 			items[(scroll + choice) * 2 + 1] +
-			first_alpha(items[(scroll + choice) * 2 + 1]),
-			items[(scroll + choice) * 2]);
+			first_alpha(items[(scroll + choice) * 2 + 1]));
 	    else
             	fprintf(stderr, items[(scroll + choice) * 2]);
 
diff -u --recursive --new-file v1.3.70/linux/scripts/lxdialog/yesno.c linux/scripts/lxdialog/yesno.c
--- v1.3.70/linux/scripts/lxdialog/yesno.c	Wed Feb  7 15:11:46 1996
+++ linux/scripts/lxdialog/yesno.c	Sun Mar  3 09:22:25 1996
@@ -25,14 +25,15 @@
  * Display termination buttons
  */
 static void
-print_buttons(WINDOW *dialog, int height, int width, int okval, int cancelval)
+print_buttons(WINDOW *dialog, int height, int width, int selected)
 {
     int x = width / 2 - 10;
     int y = height - 2;
 
-    print_button (dialog, " Yes ", y, x, okval);
-    print_button (dialog, "  No  ", y, x + 13, cancelval);
+    print_button (dialog, " Yes ", y, x, selected == 0);
+    print_button (dialog, "  No  ", y, x + 13, selected == 1);
 
+    wmove(dialog, y, x+1 + 13*selected );
     wrefresh (dialog);
 }
 
@@ -72,7 +73,7 @@
     wattrset (dialog, dialog_attr);
     print_autowrap (dialog, prompt, width - 2, 1, 3);
 
-    print_buttons(dialog, height, width, TRUE, FALSE);
+    print_buttons(dialog, height, width, 0);
 
     while (key != ESC) {
 	key = wgetch (dialog);
@@ -87,17 +88,12 @@
 	    return 1;
 
 	case TAB:
-	case KEY_UP:
-	case KEY_DOWN:
 	case KEY_LEFT:
 	case KEY_RIGHT:
-	    if (!button) {
-		button = 1;	/* "No" button selected */
-    		print_buttons(dialog, height, width, FALSE, TRUE);
-	    } else {
-		button = 0;	/* "Yes" button selected */
-    		print_buttons(dialog, height, width, TRUE, FALSE);
-	    }
+	    button = ((key == KEY_LEFT ? --button : ++button) < 0)
+			? 1 : (button > 1 ? 0 : button);
+
+	    print_buttons(dialog, height, width, button);
 	    wrefresh (dialog);
 	    break;
 	case ' ':
