diff -u --recursive --new-file v2.1.120/linux/COPYING linux/COPYING
--- v2.1.120/linux/COPYING	Sun Jun  7 11:16:25 1998
+++ linux/COPYING	Sun Sep  6 09:53:05 1998
@@ -14,7 +14,7 @@
 		       Version 2, June 1991
 
  Copyright (C) 1989, 1991 Free Software Foundation, Inc.
-                          675 Mass Ave, Cambridge, MA 02139, USA
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  Everyone is permitted to copy and distribute verbatim copies
  of this license document, but changing it is not allowed.
 
@@ -291,7 +291,7 @@
 
 		     END OF TERMS AND CONDITIONS
 
-	Appendix: How to Apply These Terms to Your New Programs
+	    How to Apply These Terms to Your New Programs
 
   If you develop a new program, and you want it to be of the greatest
 possible use to the public, the best way to achieve this is to make it
@@ -317,7 +317,8 @@
 
     You should have received a copy of the GNU General Public License
     along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
 
 Also add information on how to contact you by electronic and paper mail.
 
diff -u --recursive --new-file v2.1.120/linux/CREDITS linux/CREDITS
--- v2.1.120/linux/CREDITS	Sat Sep  5 16:46:40 1998
+++ linux/CREDITS	Tue Sep  8 16:24:40 1998
@@ -61,7 +61,7 @@
 S: USA
 
 N: Andrea Arcangeli
-E: arcangeli@mbox.queen.it
+E: andrea@e-mind.com
 W: http://e-mind.com/~andrea/
 P: 1024/CB4660B9 CC A0 71 81 F4 A0 63 AC  C0 4B 81 1D 8C 15 C8 E5
 D: Parport hacker
@@ -129,6 +129,12 @@
 S: Provo, Utah 84606
 S: USA
 
+N: Paul Barton-Davis
+E: pbd@op.net
+D: Driver for WaveFront soundcards (Turtle Beach Maui, Tropez, Tropez+)
+D: Various bugfixes and changes to sound drivers
+S: USA 
+
 M: Krzysztof G. Baranowski
 E: kgb@manjak.knm.org.pl
 P: 1024/FA6F16D1 96 D1 1A CF 5F CA 69 EC  F9 4F 36 1F 6D 60 7B DA
@@ -158,7 +164,7 @@
 N: Donald Becker
 E: becker@cesdis.gsfc.nasa.gov
 D: General low-level networking hacker
-D: Most of the Ethernet drivers
+D: Most of the ethercard drivers
 D: Original author of the NFS server
 S: USRA Center of Excellence in Space Data and Information Sciences
 S: Code 930.5, Goddard Space Flight Center
@@ -248,6 +254,15 @@
 S: Pittsburgh, Pennsylvania 15213
 S: USA
 
+N: Derrick J. Brashear
+E: shadow@dementia.org
+W: http://www.dementia.org/~shadow
+P: 512/71EC9367 C5 29 0F BC 83 51 B9 F0  BC 05 89 A0 4F 1F 30 05
+D: Author of Sparc CS4231 audio driver, random Sparc work
+S: 403 Gilmore Avenue
+S: Trafford, Pennsylvania 15085
+S: USA
+
 N: Andries Brouwer
 E: aeb@cwi.nl
 D: random Linux hacker
@@ -711,8 +726,8 @@
 E: rth@cygnus.com
 E: richard@gnu.org
 D: Alpha/ELF, gcc, binutils, and glibc
-S: 5450 Mayme #25
-S: San Jose, California 95129
+S: 50 E. Middlefield #10
+S: Mountain View, California 94043
 S: USA
 
 N: Sebastian Hetze
@@ -1073,9 +1088,10 @@
 N: Jamie Lokier
 E: jamie@imbolc.ucc.ie
 D: Reboot-through-BIOS for broken 486 motherboards
-S: 26 Oatlands Road
+S: 11 Goodson Walk
+S: Marston
 S: Oxford
-S: OX2 0ET
+S: OX3 0HX
 S: United Kingdom
 
 N: Warner Losh
@@ -1711,6 +1727,13 @@
 S: 1050 Woodduck Avenue
 S: Santa Clara, California 95051
 S: USA
+
+N: Stefan Traby
+E: stefan@quant-x.com
+D: Minor Alpha kernel hacks
+S: Mitterlasznitzstr. 13
+S: 8302 Nestelbach
+S: Austria
 
 N: Jeff Tranter
 E: Jeff_Tranter@Mitel.COM
diff -u --recursive --new-file v2.1.120/linux/Documentation/Changes linux/Documentation/Changes
--- v2.1.120/linux/Documentation/Changes	Thu Aug 27 19:56:28 1998
+++ linux/Documentation/Changes	Sat Sep  5 17:14:54 1998
@@ -33,8 +33,8 @@
    Also, don't forget http://www.linuxhq.com/ for all your Linux kernel
 needs.
 
-Last updated: May 31, 1998
-Current Author: Chris Ricker (kaboom@gatech.edu).
+Last updated: September 3, 1998
+Current Author: Chris Ricker (kaboom@gatech.edu or chris.ricker@m.cc.utah.edu).
 
 Current Minimal Requirements
 ****************************
@@ -43,14 +43,15 @@
 encountered a bug!  If you're unsure what version you're currently
 running, the suggested command should tell you.
 
-- Kernel modules	 modutils-2.1.85         ; insmod -V
+- Kernel modules	 2.1.85                  ; insmod -V
 - Gnu C 		 2.7.2.3                 ; gcc --version
 - Binutils		 2.8.1.0.23              ; ld -v
-- Linux C Library	 5.4.44                  ; ls -l /lib/libc.so.*
+- Linux C Library	 5.4.46                  ; ls -l /lib/libc.so.*
 - Dynamic Linker (ld.so) 1.9.9                   ; ldd --version or ldd -v
 - Linux C++ Library	 2.7.2.8                 ; ls -l /usr/lib/libg++.so.*
-- Procps		 1.2.7                   ; ps --version
+- Procps		 1.2.8                   ; ps --version
 - Procinfo               14                      ; procinfo -v
+- Psmisc		 17			 ; pstree -V
 - Mount                  2.7l                    ; mount --version
 - Net-tools              1.45                    ; hostname -V
 - Loadlin                1.6a
@@ -59,7 +60,7 @@
 - NFS                    0.4.21                  ; showmount --version
 - Bash                   1.14.7                  ; bash -version
 - Ncpfs                  2.2.0                   ; ncpmount -v
-- Pcmcia-cs              3.0.1
+- Pcmcia-cs              3.0.5                   ; cardmgr -V
 - PPP                    2.3.5                   ; pppd -v
 
 Upgrade notes
@@ -83,6 +84,36 @@
 compiled under 2.0 or earlier kernels should be replaced with ones
 compiled under 2.1, for example.
 
+   As of 2.1.115, Unix98 pty support was added as an option, and
+support for the deprecated major 4 /dev/ttyp* devices was removed.  If
+necessary (eg, you get "out of pty" error messages when you obviously
+are not out of pty's), create major 3 /dev/tty* and major 2 /dev/pty*
+devices (see Documentation/devices.txt for more information).  If you
+want to use the Unix98 ptys, you should be running at least
+glibc-2.0.9x, and you must switch completely to Unix98 pty's.  The
+general procedure for configuring Unix98 pty support is:
+
+- Compile your kernel with CONFIG_UNIX98_PTYS and CONFIG_DEVPTS_FS.
+- mknod /dev/ptmx c 5 2
+  chmod 666 /dev/ptmx
+  mkdir /dev/pts
+- Add to /etc/fstab:
+
+  none            /dev/pts        devpts	gid=5,mode=620    0 0
+
+   (Note:  gid=5 is applicable for RedHat systems for which group "tty" has
+   gid 5.  Adjust according to your distribution.  Use mode=600 if you want
+   "mesg n" to be default.)
+- Mount /dev/pts
+
+   Frame buffer consoles ("fbcon") are now in the kernel for all
+platforms, not just those non-Intel ones for which VGA text mode is
+impossible.  VGAcon is still available for those who want it, but fbcon
+has the advantage of providing a uniform graphical subsystem across all
+Linux ports, and it displays a spiffy penguin logo on boot-up ;-).  For
+more information, see the files in Documentation/fb/ ; you may also
+need to download the fbset utilities.
+
 Libc
 ====
 
@@ -95,12 +126,12 @@
    For modules to work, you need to be running libc-5.4.x or greater.
 Since updates to libc fix other problems as well (security flaws, for
 example) and since 5.4.7 is missing a few needed symbols, try to get
-the latest 5.4.x you can.  Currently, libc-5.4.44 is the latest public
+the latest 5.4.x you can.  Currently, libc-5.4.46 is the latest public
 release.
 
    If you upgrade to libc-5.4.x, you also have to upgrade your dynamic
-linker (ld.so) to at least 1.9.5, or all sorts of weirdness will
-happen.  Actually, ld.so-1.8.2 and later will work, but 1.9.5 is widely
+linker (ld.so) to at least 1.9.9, or all sorts of weirdness will
+happen.  Actually, ld.so-1.8.2 and later will work, but 1.9.9 is widely
 available, so if you need to upgrade, use it.  If you get a release
 later than 1.8.5, avoid 1.8.10 as it introduces a few bugs that are
 fixed in later releases.  Please make sure you don't install ld.so-2.x
@@ -109,7 +140,7 @@
    If you upgrade to libc-5.4.x, you may also need to upgrade ypbind if
 you're using NIS.
 
-   If you upgrade to libc-5.4.44, please read and pay attention to its
+   If you upgrade to libc-5.4.46, please read and pay attention to its
 accompanying release notes.  The section about it breaking make is not
 a joke.
 
@@ -135,8 +166,8 @@
    The last public release of the binutils 2.8.x series was 2.8.1.0.23.
 Binutils 2.8.1.0.25 to 2.9.1.0.2 are beta releases, and are known to be
 very buggy.  Binutils 2.9.1 (note the absence of a suffix) from the FSF
-should work, and binutils 2.9.1.0.3 and later releases are also good.
-Either use binutils-2.8.1.0.23 or binutils-2.9.1.0.4 or later.  Glibc2
+should work, and binutils 2.9.1.0.7 and later releases are also good.
+Either use binutils-2.8.1.0.23 or binutils-2.9.1.0.7 or later.  Glibc2
 users should especially try to use the 2.9.1.0.x releases, as they
 resolve known issues with glibc2 and binutils-2.8.x releases.
 
@@ -185,15 +216,15 @@
 something appears broken, check the /proc/sys/net/ipv4/ directory.  "1"
 generally denotes enabled, while "0" generally denotes disabled.
 
-   For support for new features like IPv6, upgrade to the latest
-net-tools.  This will also fix other problems.  For example, the format
-of /proc/net/dev changed; as a result, an older ifconfig will
-incorrectly report errors.
-
-   The IP firewalling code has been replaced: ipfwadm will no longer
-work.  You need to obtain `ipchains', available from
-http://www.adelaide.net.au/~rustcorp/ipfwchains/ipfwchains.html
-which includes an ipfwadm wrapper.
+   If you're experiencing reports of lots of network errors, chances
+are you need to upgrade to a more recent net-tools that understands the
+new /proc/net/dev format.  This will also provide support for new
+features like IPv6.
+
+   As of 2.1.102, the IP firewalling code has been replaced; ipfwadm
+will no longer work.  You need to optain "ipchains," available from
+http://www.adelaide.net.au/~rustcorp/ipfwchains/ipfwchains.html, and use
+that instead of ipfwadm.
 
 Memory
 ======
@@ -209,7 +240,8 @@
 much-improved performance.  As a result, you'll need to upgrade mount
 to a recent 2.6 release.  Also, amd is being phased out in favor of the
 much better autofs.  You'll also have to get the appropriate utils to
-use autofs as well as the new NFS utils.
+use autofs as well as the new NFS utils.  In addition, you have the
+choice of user-land NFS or kernel-level NFS (knfs).
 
 RPM
 ===
@@ -267,6 +299,13 @@
    To mount NetWare shares, you'll need to upgrade to a more recent
 version of the ncpfs utils.
 
+SMBfs
+=====
+
+   To mount SMB (Samba / Windows) shares, you'll need to use the
+smbmount utility included with recent Samba releases.
+Documentation/filesystems/smbfs.txt has more information about this.
+
 Pcmcia-cs
 =========
 
@@ -279,6 +318,23 @@
    Due to changes in the routing code, those of you using PPP
 networking will need to upgrade your pppd.
 
+iBCS
+====
+
+   A new version of iBCS is necessary for 2.1 kernels.
+
+AppleTalk
+=========
+
+   Use the Asun version of netatalk for AppleTalk support, as Umich's
+version is not compatible with 2.1 kernels.
+
+Psmisc
+======
+
+   fuser, which comes with psmisc, reads /proc/*/fd/* to do its job.
+Upgrade psmisc if 2.1 changes to /proc broke the version you're using.
+
 Where to get the files
 **********************
 
@@ -292,16 +348,16 @@
 ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.binutils-2.8.1.0.23
 ftp://sunsite.unc.edu/pub/Linux/GCC/release.binutils-2.8.1.0.23
 
-The 2.9.1.0.4 release:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.9.1.0.4-glibc.x86.tar.gz
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.9.1.0.4-libc5.x86.tar.gz
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.9.1.0.4.tar.gz
-ftp://sunsite.unc.edu/pub/Linux/GCC/binutils-2.9.1.0.4-glibc.x86.tar.gz
-ftp://sunsite.unc.edu/pub/Linux/GCC/binutils-2.9.1.0.4-libc5.x86.tar.gz
-ftp://sunsite.unc.edu/pub/Linux/GCC/binutils-2.9.1.0.4.tar.gz
+The 2.9.1.0.7 release:
+ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.9.1.0.7-glibc.x86.tar.gz
+ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.9.1.0.7-libc5.x86.tar.gz
+ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.9.1.0.7.tar.gz
+ftp://sunsite.unc.edu/pub/Linux/GCC/binutils-2.9.1.0.7-glibc.x86.tar.gz
+ftp://sunsite.unc.edu/pub/Linux/GCC/binutils-2.9.1.0.7-libc5.x86.tar.gz
+ftp://sunsite.unc.edu/pub/Linux/GCC/binutils-2.9.1.0.7.tar.gz
 Installation notes:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.binutils-2.9.1.0.4
-ftp://sunsite.unc.edu/pub/Linux/GCC/release.binutils-2.9.1.0.4
+ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.binutils-2.9.1.0.7
+ftp://sunsite.unc.edu/pub/Linux/GCC/release.binutils-2.9.1.0.7
 
 Gnu C
 =====
@@ -329,12 +385,12 @@
 Linux C Library
 ===============
 
-The 5.4.44 release:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/libc-5.4.44.bin.tar.gz
-ftp://sunsite.unc.edu/pub/Linux/GCC/libc-5.4.44.bin.tar.gz
-Installation notes for 5.4.44:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.libc-5.4.44
-ftp://sunsite.unc.edu/pub/Linux/GCC/release.libc-5.4.44
+The 5.4.46 release:
+ftp://tsx-11.mit.edu/pub/linux/packages/GCC/libc-5.4.46.bin.tar.gz
+ftp://sunsite.unc.edu/pub/Linux/GCC/libc-5.4.46.bin.tar.gz
+Installation notes for 5.4.46:
+ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.libc-5.4.46
+ftp://sunsite.unc.edu/pub/Linux/GCC/release.libc-5.4.46
 
 Linux C++ Library
 =================
@@ -363,8 +419,8 @@
 ================
 
 The 1.2 release:
-ftp://tsx-11.mit.edu/pub/linux/sources/usr.bin/procps-1.2.7.tar.gz
-ftp://sunsite.unc.edu/pub/Linux/system/status/ps/procps-1.2.7.tgz
+ftp://tsx-11.mit.edu/pub/linux/sources/usr.bin/procps-1.2.8.tar.gz
+ftp://sunsite.unc.edu/pub/Linux/system/status/ps/procps-1.2.8.tgz
 
 Procinfo utilities
 ==================
@@ -372,6 +428,13 @@
 The 14 release:
 ftp://ftp.cistron.nl/pub/people/svm/procinfo-14.tar.gz
 
+Psmisc utilities
+================
+
+The 17 release:
+ftp://lrcftp.epfl.ch/pub/linux/local/psmisc/psmisc-17.tar.gz
+ftp://sunsite.unc.edu/pub/Linux/system/status/ps/psmisc-17.tar.gz
+
 RPM utilities
 =============
 
@@ -414,16 +477,19 @@
 Autofs
 ======
 
-The 0.3.11 release:
-ftp://ftp.kernel.org/pub/linux/daemons/autofs/autofs-0.3.11.tar.gz
+The 3.1.1 release:
+ftp://ftp.kernel.org/pub/linux/daemons/autofs/autofs-3.1.1.tar.gz
 
 NFS
 ===
 
-The 0.4.21 release:
+The user-land 0.4.21 release:
 ftp://ftp.mathematik.th-darmstadt.de/pub/linux/okir/linux-nfs-0.4.21.tar.gz
 ftp://linux.nrao.edu/mirrors/fb0429.mathematik.th-darmstadt.de/pub/linux/okir/linux-nfs-0.4.21.tar.gz
 
+The kernel-level 8/30/98 release:
+ftp://ftp.yggdrasil.com/private/hjl/knfsd-980830.tar.gz
+
 Net-tools
 =========
 
@@ -449,11 +515,17 @@
 The 2.2.0 release:
 ftp://ftp.gwdg.de/pub/linux/misc/ncpfs/ncpfs-2.2.0.tgz
 
+SMBfs
+=====
+
+The 1.9.18p10 release of Samba:
+ftp://samba.anu.edu.au/pub/samba/samba-1.9.18p10.tar.gz
+
 Pcmcia-cs
 =========
 
-The 3.0.1 release:
-ftp://hyper.stanford.edu/pub/pcmcia/pcmcia-cs.3.0.1.tar.gz
+The 3.0.5 release:
+ftp://hyper.stanford.edu/pub/pcmcia/pcmcia-cs.3.0.5.tar.gz
 
 PPP
 ===
@@ -468,6 +540,24 @@
 http://www.adelaide.net.au/~rustcorp/ipfwchains/ipchains-source-1.3.3.tar.gz
 http://www.adelaide.net.au/~rustcorp/ipfwchains/ipchains-source-1.3.3.tar.bz2
 
+iBCS
+====
+
+The 8/30/98 release:
+ftp://tsx-11.mit.edu/pub/linux/BETA/ibcs2/ibcs-2.1-980830-ALPHA.tar.gz
+
+Asun netatalk
+=============
+
+The 2.0a18.2 release:
+ftp://ftp.u.washington.edu/pub/user-supported/asun/netatalk-1.4b2+asun2.0a18.2.tar.gz
+
+Fbset
+=====
+
+The 7/13/98 release:
+http://www.cs.kuleuven.ac.be/~geert/bin/fbset-2.0-pre-19980713.tar.gz
+
 Other Info
 ==========
 
@@ -497,5 +587,5 @@
 
 Please send info about any other packages that 2.1.x "broke" or about
 any new features of 2.1.x that require extra or new packages for use to
-Chris Ricker (kaboom@gatech.edu).
+Chris Ricker (kaboom@gatech.edu or chris.ricker@m.cc.utah.edu).
 
diff -u --recursive --new-file v2.1.120/linux/MAINTAINERS linux/MAINTAINERS
--- v2.1.120/linux/MAINTAINERS	Sat Sep  5 16:46:40 1998
+++ linux/MAINTAINERS	Tue Sep  8 10:39:27 1998
@@ -471,7 +471,7 @@
 P:	David Campbell
 M:	campbell@torque.net
 P:	Andrea Arcangeli
-M:	arcangeli@mbox.queen.it
+M:	andrea@e-mind.com
 L:	linux-parport@torque.net
 L:	pnp-list@redhat.com
 W:	http://www.cyberelk.demon.co.uk/parport.html
diff -u --recursive --new-file v2.1.120/linux/Makefile linux/Makefile
--- v2.1.120/linux/Makefile	Sat Sep  5 16:46:40 1998
+++ linux/Makefile	Sat Sep  5 17:17:27 1998
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 1
-SUBLEVEL = 120
+SUBLEVEL = 121
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/Makefile linux/arch/alpha/Makefile
--- v2.1.120/linux/arch/alpha/Makefile	Tue Aug 18 22:02:01 1998
+++ linux/arch/alpha/Makefile	Sun Sep  6 10:34:33 1998
@@ -10,7 +10,7 @@
 
 NM := nm -B
 
-LINKFLAGS = -static -T arch/alpha/vmlinux.lds -N
+LINKFLAGS = -static -T arch/alpha/vmlinux.lds #-N -relax
 CFLAGS := $(CFLAGS) -pipe -mno-fp-regs -ffixed-8
 
 # Determine if we can use the BWX instructions with GAS.
@@ -79,6 +79,7 @@
 	@$(MAKEBOOT) srmboot
 
 archclean:
+	@$(MAKE) -C arch/$(ARCH)/kernel clean
 	@$(MAKEBOOT) clean
 
 archmrproper:
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/boot/Makefile linux/arch/alpha/boot/Makefile
--- v2.1.120/linux/arch/alpha/boot/Makefile	Mon Jan 12 14:51:14 1998
+++ linux/arch/alpha/boot/Makefile	Sun Sep  6 10:34:33 1998
@@ -8,17 +8,7 @@
 # Copyright (C) 1994 by Linus Torvalds
 #
 
-ifdef CONFIG_CROSSCOMPILE
-# enable this for linking under OSF/1:
-LINKFLAGS = -non_shared -T 0x20000000 -N
-else
- elf=$(shell if $(LD) --help | grep elf64alpha >/dev/null; then echo yes; fi)
- ifeq ($(elf),yes)
-  LINKFLAGS = -static -Ttext 0x20000000 -N
- else
-  LINKFLAGS = -static -T bootloader.lds -N
- endif
-endif
+LINKFLAGS = -static -T bootloader.lds #-N -relax
 
 .S.s:
 	$(CC) -D__ASSEMBLY__ -traditional -E -o $*.o $<
@@ -56,7 +46,7 @@
 	@test "$(BOOTDEV)" != ""  || (echo You must specify BOOTDEV ; exit -1)
 
 vmlinux.gz: vmlinux
-	gzip -fv vmlinux
+	gzip -fv9 vmlinux
 
 #
 # A raw binary without header.  Used by raw boot.
@@ -69,18 +59,10 @@
 	echo "#define KERNEL_SIZE `$(OBJSTRIP) -p vmlinux.nh /dev/null`" > $@
 
 vmlinux.nh: $(VMLINUX) $(OBJSTRIP)
-ifeq ($(elf),yes)
-	cp $(VMLINUX) vmlinux.stripped
-	strip vmlinux.stripped		# work around ELF binutils bug...
-	$(OBJSTRIP) -v vmlinux.stripped vmlinux.nh
-	rm -f vmlinux.stripped
-else
 	$(OBJSTRIP) -v $(VMLINUX) vmlinux.nh
-endif
 
 vmlinux: $(TOPDIR)/vmlinux
-	cp $(TOPDIR)/vmlinux vmlinux
-	strip vmlinux
+	strip -o vmlinux $(VMLINUX)
 
 tools/lxboot: $(OBJSTRIP) bootloader
 	$(OBJSTRIP) -p bootloader tools/lxboot
@@ -98,21 +80,14 @@
 	$(HOSTCC) tools/mkbb.c -o tools/mkbb
 
 bootloader: $(OBJECTS)
-	$(LD) $(LINKFLAGS) \
-		$(OBJECTS) \
-		$(LIBS) \
-		-o bootloader && strip bootloader || \
-		(rm -f bootloader && exit 1)
+	$(LD) $(LINKFLAGS) $(OBJECTS) $(LIBS) -o bootloader
 
 bootpheader: $(BPOBJECTS)
-	$(LD) $(LINKFLAGS) \
-		$(BPOBJECTS) \
-		$(LIBS) \
-		-o bootpheader && strip bootpheader || \
-		(rm -f bootpheader && exit 1)
+	$(LD) $(LINKFLAGS) $(BPOBJECTS) $(LIBS) -o bootpheader
 
 clean:
-	rm -f $(TARGETS) bootloader bootimage vmlinux.nh \
-		tools/mkbb tools/bootlx tools/lxboot ksize.h
+	rm -f $(TARGETS) bootloader bootimage bootpfile bootpheader
+	rm -f tools/mkbb tools/bootlx tools/lxboot tools/bootph
+	rm -f vmlinux.nh ksize.h
 
 dep:
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/boot/bootloader.lds linux/arch/alpha/boot/bootloader.lds
--- v2.1.120/linux/arch/alpha/boot/bootloader.lds	Tue Aug 29 00:15:48 1995
+++ linux/arch/alpha/boot/bootloader.lds	Sun Sep  6 10:34:33 1998
@@ -1,50 +1,23 @@
-OUTPUT_FORMAT("ecoff-littlealpha")
+OUTPUT_FORMAT("elf64-alpha")
 ENTRY(__start)
 SECTIONS
 {
-  .text 0x20000000: {
-     _ftext = . ;
-     __istart = . ;
-     eprol  =  .;
-    *(.text)
-     __fstart = . ;
-     _etext  =  .;
-  }
-  .rdata : {
-    *(.rdata)
-  }
-  .pdata : {
-     _fpdata = .;
-    *(.pdata)
-  }
-  .data : {
-     _fdata = .;
-    *(.data)
-    CONSTRUCTORS
-  }
-  .xdata : {
-    *(.xdata)
-  }
-   _gp = ALIGN (16) + 0x8000;
-  .lit8 : {
-    *(.lit8)
-  }
-  .lita : {
-    *(.lita)
-  }
-  .sdata : {
-    *(.sdata)
-  }
-   _EDATA  =  .;
-   _FBSS = .;
-  .sbss : {
-    *(.sbss)
-    *(.scommon)
-    . = ALIGN(16);
-  }
-  .bss : {
-    *(.bss)
-    *(COMMON)
-  }
-   _end = .;
+  . = 0x20000000;
+  .text : { *(.text) }
+  _etext = .;
+  PROVIDE (etext = .);
+  .rodata : { *(.rodata) }
+  .data : { *(.data) CONSTRUCTORS }
+  .got : { *(.got) }
+  .sdata : { *(.sdata) }
+  _edata = .;
+  PROVIDE (edata = .);
+  .sbss : { *(.sbss) *(.scommon) }
+  .bss : { *(.bss) *(COMMON) }
+  _end = . ;
+  PROVIDE (end = .);
+
+  .mdebug 0 : { *(.mdebug) }
+  .note 0 : { *(.note) }
+  .comment 0 : { *(.comment) }
 }
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/boot/bootp.c linux/arch/alpha/boot/bootp.c
--- v2.1.120/linux/arch/alpha/boot/bootp.c	Wed Apr  8 19:36:24 1998
+++ linux/arch/alpha/boot/bootp.c	Sun Sep  6 10:34:33 1998
@@ -27,12 +27,27 @@
 	struct pcb_struct * pcb_va, struct pcb_struct * pcb_pa,
 	unsigned long vptb, unsigned long *kstk);
 
+extern long dispatch(long code, ...);
+
+static void
+puts(const char *str, int len)
+{
+	long written;
+
+	while (len > 0) {
+		written = dispatch(CCB_PUTS, 0, str, len);
+		if (written < 0)
+			break;
+		len -= (unsigned int) written;
+		str += (unsigned int) written;
+	}
+}
+
 int printk(const char * fmt, ...)
 {
 	va_list args;
-	int i, j, written, remaining, num_nl;
+	int i, j, remaining, num_nl;
 	static char buf[1024];
-	char * str;
 
 	va_start(args, fmt);
 	i = vsprintf(buf, fmt, args);
@@ -54,12 +69,7 @@
 	    }
 	}
 
-	str = buf;
-	do {
-	    written = puts(str, remaining);
-	    remaining -= written;
-	    str += written;
-	} while (remaining > 0);
+	puts(buf, remaining);
 	return i;
 }
 
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/defconfig linux/arch/alpha/defconfig
--- v2.1.120/linux/arch/alpha/defconfig	Tue Aug 18 22:02:01 1998
+++ linux/arch/alpha/defconfig	Wed Sep  9 14:06:48 1998
@@ -201,6 +201,7 @@
 # CONFIG_SLIP is not set
 # CONFIG_NET_RADIO is not set
 # CONFIG_TR is not set
+# CONFIG_HOSTESS_SV11 is not set
 # CONFIG_WAN_DRIVERS is not set
 # CONFIG_LAPBETHER is not set
 # CONFIG_X25_ASY is not set
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/kernel/Makefile linux/arch/alpha/kernel/Makefile
--- v2.1.120/linux/arch/alpha/kernel/Makefile	Tue Aug 18 22:02:01 1998
+++ linux/arch/alpha/kernel/Makefile	Sun Sep  6 10:34:33 1998
@@ -8,9 +8,9 @@
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
 .S.s:
-	$(CPP) -D__ASSEMBLY__ $(AFLAGS) -traditional    $< -o $*.s
+	$(CC) -D__ASSEMBLY__ $(AFLAGS) -E -o $*.s $<
 .S.o:
-	$(CC)  -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
+	$(CC) -D__ASSEMBLY__ $(AFLAGS) -c -o $*.o $<
 
 all: kernel.o head.o
 
@@ -116,5 +116,14 @@
 endif
 
 all: kernel.o head.o
+
+asm_offsets: check_asm
+	./check_asm > $(TOPDIR)/include/asm-alpha/asm_offsets.h
+
+check_asm: check_asm.c
+	gcc -o $@ $< -I$(TOPDIR)/include -D__KERNEL__ -ffixed-8
+
+clean::
+	rm -f check_asm
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/kernel/bios32.c linux/arch/alpha/kernel/bios32.c
--- v2.1.120/linux/arch/alpha/kernel/bios32.c	Tue Aug 18 22:02:02 1998
+++ linux/arch/alpha/kernel/bios32.c	Sun Sep  6 10:34:33 1998
@@ -23,6 +23,7 @@
  * Manuals are $25 each or $50 for all three, plus $7 shipping
  * within the United States, $35 abroad.
  */
+
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/tasks.h>
@@ -38,6 +39,7 @@
 #include "bios32.h"
 
 #define DEBUG_DEVS 0
+#define DEBUG_HOSE 0
 
 #if DEBUG_DEVS
 # define DBG_DEVS(args)		printk args
@@ -45,6 +47,12 @@
 # define DBG_DEVS(args)
 #endif
 
+#if DEBUG_HOSE
+# define DBG_HOSE(args)		printk args
+#else
+# define DBG_HOSE(args)
+#endif
+
 #ifndef CONFIG_PCI
 
 asmlinkage int sys_pciconfig_read() { return -ENOSYS; }
@@ -68,21 +76,28 @@
 #define MAJOR_REV	0
 #define MINOR_REV	4	/* minor revision 4, add multi-PCI handling */
 
+struct linux_hose_info *bus2hose[256];
+struct linux_hose_info *hose_head, **hose_tail = &hose_head;
+int hose_count;
+int pci_probe_enabled;
+
+static void layout_hoses(void);
 
 int
 pcibios_present(void)
 {
-	return alpha_mv.pci_read_config_byte != NULL;
+	return alpha_mv.hose_read_config_byte != NULL;
 }
 
 void __init
 pcibios_init(void)
 {
-	printk("Alpha PCI BIOS32 revision %x.%02x\n", MAJOR_REV, MINOR_REV);
+	if (!pcibios_present())
+		return;
+
+	printk("Alpha PCI BIOS32 revision %d.%02d\n", MAJOR_REV, MINOR_REV);
 	if (alpha_use_srm_setup)
 		printk("   NOT modifying existing (SRM) PCI configuration\n");
-
-	/* FIXME: Scan for multiple PCI busses here.  */
 }
 
 char * __init
@@ -106,8 +121,11 @@
 pcibios_read_config_byte (u8 bus, u8 dev, u8 where, u8 *value)
 {
 	int r = PCIBIOS_FUNC_NOT_SUPPORTED;
-	if (alpha_mv.pci_read_config_byte)
-		r = alpha_mv.pci_read_config_byte(bus, dev, where, value);
+	*value = 0xff;
+	if (alpha_mv.hose_read_config_byte) {
+		r = (alpha_mv.hose_read_config_byte
+		     (bus, dev, where, value, bus2hose[bus]));
+	}
 	return r;
 }
 
@@ -115,8 +133,13 @@
 pcibios_read_config_word (u8 bus, u8 dev, u8 where, u16 *value)
 {
 	int r = PCIBIOS_FUNC_NOT_SUPPORTED;
-	if (alpha_mv.pci_read_config_word)
-		r = alpha_mv.pci_read_config_word(bus, dev, where, value);
+	*value = 0xffff;
+	if (alpha_mv.hose_read_config_word) {
+		r = PCIBIOS_BAD_REGISTER_NUMBER;
+		if (!(where & 1))
+			r = (alpha_mv.hose_read_config_word
+			     (bus, dev, where, value, bus2hose[bus]));
+	}
 	return r;
 }
 
@@ -124,8 +147,13 @@
 pcibios_read_config_dword (u8 bus, u8 dev, u8 where, u32 *value)
 {
 	int r = PCIBIOS_FUNC_NOT_SUPPORTED;
-	if (alpha_mv.pci_read_config_dword)
-		r = alpha_mv.pci_read_config_dword(bus, dev, where, value);
+	*value = 0xffffffff;
+	if (alpha_mv.hose_read_config_dword) {
+		r = PCIBIOS_BAD_REGISTER_NUMBER;
+		if (!(where & 3))
+			r = (alpha_mv.hose_read_config_dword
+			     (bus, dev, where, value, bus2hose[bus]));
+	}
 	return r;
 }
 
@@ -133,8 +161,10 @@
 pcibios_write_config_byte (u8 bus, u8 dev, u8 where, u8 value)
 {
 	int r = PCIBIOS_FUNC_NOT_SUPPORTED;
-	if (alpha_mv.pci_write_config_byte)
-		r = alpha_mv.pci_write_config_byte(bus, dev, where, value);
+	if (alpha_mv.hose_write_config_byte) {
+		r = (alpha_mv.hose_write_config_byte
+		     (bus, dev, where, value, bus2hose[bus]));
+	}
 	return r;
 }
 
@@ -142,8 +172,12 @@
 pcibios_write_config_word (u8 bus, u8 dev, u8 where, u16 value)
 {
 	int r = PCIBIOS_FUNC_NOT_SUPPORTED;
-	if (alpha_mv.pci_write_config_word)
-		r = alpha_mv.pci_write_config_word(bus, dev, where, value);
+	if (alpha_mv.hose_write_config_word) {
+		r = PCIBIOS_BAD_REGISTER_NUMBER;
+		if (!(where & 1))
+			r = (alpha_mv.hose_write_config_word
+			     (bus, dev, where, value, bus2hose[bus]));
+	}
 	return r;
 }
 
@@ -151,8 +185,12 @@
 pcibios_write_config_dword (u8 bus, u8 dev, u8 where, u32 value)
 {
 	int r = PCIBIOS_FUNC_NOT_SUPPORTED;
-	if (alpha_mv.pci_write_config_dword)
-		r = alpha_mv.pci_write_config_dword(bus, dev, where, value);
+	if (alpha_mv.hose_write_config_dword) {
+		r = PCIBIOS_BAD_REGISTER_NUMBER;
+		if (!(where & 3))
+			r = (alpha_mv.hose_write_config_dword
+			     (bus, dev, where, value, bus2hose[bus]));
+	}
 	return r;
 }
 
@@ -171,31 +209,23 @@
 	if (!pcibios_present())
 		return -ENOSYS;
 	
-	lock_kernel();
 	switch (len) {
 	case 1:
 		err = pcibios_read_config_byte(bus, dfn, off, &ubyte);
-		if (err != PCIBIOS_SUCCESSFUL)
-			ubyte = 0xff;
 		put_user(ubyte, buf);
 		break;
 	case 2:
 		err = pcibios_read_config_word(bus, dfn, off, &ushort);
-		if (err != PCIBIOS_SUCCESSFUL)
-			ushort = 0xffff;
 		put_user(ushort, (unsigned short *)buf);
 		break;
 	case 4:
 		err = pcibios_read_config_dword(bus, dfn, off, &uint);
-		if (err != PCIBIOS_SUCCESSFUL)
-			uint = 0xffffffff;
 		put_user(uint, (unsigned int *)buf);
 		break;
 	default:
 		err = -EINVAL;
 		break;
 	}
-	unlock_kernel();
 	return err;
 }
 
@@ -214,7 +244,6 @@
 	if (!pcibios_present())
 		return -ENOSYS;
 
-	lock_kernel();
 	switch (len) {
 	case 1:
 		err = get_user(ubyte, buf);
@@ -247,7 +276,6 @@
 		err = -EINVAL;
 		break;
 	}
-	unlock_kernel();
 	return err;
 }
 
@@ -256,8 +284,6 @@
  * Gory details start here...
  */
 
-struct linux_hose_info *bus2hose[256];
-
 /*
  * Align VAL to ALIGN, which must be a power of two.
  */
@@ -715,18 +741,7 @@
 {
 	struct pci_bus *cur;
 
-#if defined(CONFIG_ALPHA_GENERIC)
-	static struct linux_hose_info dummy_hose;
-	int i;
-
-	/*
-	 * HACK: Emulate a multi-bus machine to a limited extent
-	 * by initializing bus2hose to point to something that
-	 * has pci_hose_index & pci_first_busno zero.
-	 */
-	for (i = 0; i <= 0xff; i++)
-		bus2hose[i] = &dummy_hose;
-#endif
+	layout_hoses();
 
 	/*
 	 * Scan the tree, allocating PCI memory and I/O space.
@@ -869,6 +884,18 @@
 			continue;
 
 		/*
+		 * We don't have code that will init the CYPRESS bridge
+		 * correctly so we do the next best thing, and depend on
+		 * the previous console code to do the right thing, and
+		 * ignore it here... :-\
+		 */
+		if (dev->vendor == PCI_VENDOR_ID_CONTAQ &&
+		    dev->device == PCI_DEVICE_ID_CONTAQ_82C693) {
+			DBG_DEVS(("common_pci_fixup: ignoring CYPRESS bridge...\n"));
+			continue;
+		}
+
+		/*
 		 * This device is not on the primary bus, we need
 		 * to figure out which interrupt pin it will come
 		 * in on.   We know which slot it will come in on
@@ -997,4 +1024,259 @@
 	/* The slot is the slot of the last bridge. */
 	return PCI_SLOT(dev->devfn);
 }
+
+/*
+ * On multiple bus machines, in order to cope with a somewhat deficient
+ * API, we must map the 8-bit bus identifier so that it is unique across
+ * multiple interfaces (hoses).  At the same time we do this, chain the
+ * other hoses off of pci_root so that they will be found during normal
+ * PCI probing and layout.
+ */
+
+#define PRIMARY(b)	((b)&0xff)
+#define SECONDARY(b)	(((b)>>8)&0xff)
+#define SUBORDINATE(b)	(((b)>>16)&0xff)
+
+static int __init
+hose_scan_bridges(struct linux_hose_info *hose, unsigned char bus)
+{
+	unsigned int devfn, l, class;
+	unsigned char hdr_type = 0;
+	unsigned int found = 0;
+
+	for (devfn = 0; devfn < 0xff; ++devfn) {
+		if (PCI_FUNC(devfn) == 0) {
+			alpha_mv.hose_read_config_byte(bus, devfn,
+						       PCI_HEADER_TYPE,
+						       &hdr_type, hose);
+		} else if (!(hdr_type & 0x80)) {
+			/* not a multi-function device */
+			continue;
+		}
+
+		/* Check if there is anything here. */
+		alpha_mv.hose_read_config_dword(bus, devfn, PCI_VENDOR_ID,
+						&l, hose);
+		if (l == 0xffffffff || l == 0x00000000) {
+			hdr_type = 0;
+			continue;
+		}
+
+		/* See if this is a bridge device. */
+		alpha_mv.hose_read_config_dword(bus, devfn, PCI_CLASS_REVISION,
+						&class, hose);
+
+		if ((class >> 16) == PCI_CLASS_BRIDGE_PCI) {
+			unsigned int busses;
+
+			found++;
+
+			alpha_mv.hose_read_config_dword(bus, devfn,
+							PCI_PRIMARY_BUS,
+							&busses, hose);
+
+			DBG_HOSE(("hose_scan_bridges: hose %d bus %d "
+				  "slot %d busses 0x%x\n",
+				  hose->pci_hose_index, bus, PCI_SLOT(devfn),
+				  busses));
+
+			/*
+			 * Do something with first_busno and last_busno
+			 */
+			if (hose->pci_first_busno > PRIMARY(busses)) {
+				hose->pci_first_busno = PRIMARY(busses);
+				DBG_HOSE(("hose_scan_bridges: hose %d bus %d "
+					  "slot %d change first to %d\n",
+					  hose->pci_hose_index, bus,
+					 PCI_SLOT(devfn), PRIMARY(busses)));
+			}
+			if (hose->pci_last_busno < SUBORDINATE(busses)) {
+				hose->pci_last_busno = SUBORDINATE(busses);
+				DBG_HOSE(("hose_scan_bridges: hose %d bus %d "
+					  "slot %d change last to %d\n",
+					  hose->pci_hose_index, bus,
+					  PCI_SLOT(devfn),
+					  SUBORDINATE(busses)));
+			}
+			/*
+			 * Now scan everything underneath the bridge.
+			 */
+			hose_scan_bridges(hose, SECONDARY(busses));
+		}
+	}
+	return found;
+}
+
+static void __init
+hose_reconfigure_bridges(struct linux_hose_info *hose, unsigned char bus)
+{
+	unsigned int devfn, l, class;
+	unsigned char hdr_type = 0;
+
+	for (devfn = 0; devfn < 0xff; ++devfn) {
+		if (PCI_FUNC(devfn) == 0) {
+			alpha_mv.hose_read_config_byte(bus, devfn,
+						       PCI_HEADER_TYPE,
+						       &hdr_type, hose);
+		} else if (!(hdr_type & 0x80)) {
+			/* not a multi-function device */
+			continue;
+		}
+
+		/* Check if there is anything here. */
+		alpha_mv.hose_read_config_dword(bus, devfn, PCI_VENDOR_ID,
+						&l, hose);
+		if (l == 0xffffffff || l == 0x00000000) {
+			hdr_type = 0;
+			continue;
+		}
+
+		/* See if this is a bridge device. */
+		alpha_mv.hose_read_config_dword(bus, devfn, PCI_CLASS_REVISION,
+						&class, hose);
+
+		if ((class >> 16) == PCI_CLASS_BRIDGE_PCI) {
+			unsigned int busses;
+
+			alpha_mv.hose_read_config_dword(bus, devfn,
+							PCI_PRIMARY_BUS,
+							&busses, hose);
+
+			/*
+			 * First reconfigure everything underneath the bridge.
+			 */
+			hose_reconfigure_bridges(hose, (busses >> 8) & 0xff);
+
+			/*
+			 * Unconfigure this bridges bus numbers,
+			 * pci_scan_bus() will fix this up properly.
+			 */
+			busses &= 0xff000000;
+			alpha_mv.hose_write_config_dword(bus, devfn,
+							 PCI_PRIMARY_BUS,
+							 busses, hose);
+		}
+	}
+}
+
+static void __init
+hose_fixup_busno(struct linux_hose_info *hose, unsigned char bus)
+{
+	int nbus;
+
+	/*
+	 * First, scan for all bridge devices underneath this hose,
+	 * to determine the first and last busnos.
+	 */
+	DBG_HOSE(("hose_fixup_busno: before hose_scan_bridges()\n"));
+
+	if (!hose_scan_bridges(hose, 0)) {
+		/* none found, exit */
+		hose->pci_first_busno = bus;
+		hose->pci_last_busno = bus;
+	} else {
+		/*
+		 * Reconfigure all bridge devices underneath this hose.
+		 */
+		DBG_HOSE(("hose_fixup_busno: before hose_reconfigure_bridges\n"));
+		hose_reconfigure_bridges(hose, hose->pci_first_busno);
+	}
+
+	/*
+	 * Now reconfigure the hose to it's new bus number and set up
+	 * our bus2hose mapping for this hose.
+	 */
+	nbus = hose->pci_last_busno - hose->pci_first_busno;
+
+	hose->pci_first_busno = bus;
+
+	DBG_HOSE(("hose_fixup_busno: hose %d startbus %d nbus %d\n",
+		  hose->pci_hose_index, bus, nbus));
+
+	do {
+		bus2hose[bus++] = hose;
+	} while (nbus-- > 0);
+	DBG_HOSE(("hose_fixup_busno: returning...\n"));
+}
+
+static void __init
+layout_one_hose(struct linux_hose_info *hose)
+{
+	static struct pci_bus *pchain = NULL;
+	struct pci_bus *pbus = &hose->pci_bus;
+	static unsigned char busno = 0;
+
+	DBG_HOSE(("layout_one_hose: entry\n"));
+
+	/*
+	 * Hoses include child PCI bridges in bus-range property,
+	 * but we don't scan each of those ourselves, Linux generic PCI
+	 * probing code will find child bridges and link them into this
+	 * hose's root PCI device hierarchy.
+	 */
+
+	pbus->number = pbus->secondary = busno;
+	pbus->sysdata = hose;
+
+	DBG_HOSE(("layout_one_hose: before hose_fixup_busno()\n"));
+
+	hose_fixup_busno(hose, busno);
+
+	DBG_HOSE(("layout_one_hose: before pci_scan_bus()\n"));
+
+	pbus->subordinate = pci_scan_bus(pbus); /* the original! */
+
+	/*
+	 * Set the maximum subordinate bus of this hose.
+	 */
+	hose->pci_last_busno = pbus->subordinate;
+#if 0
+	alpha_mv.hose_write_config_byte(busno, 0, 0x41, hose->pci_last_busno,
+					hose);
+#endif
+	busno = pbus->subordinate + 1;
+
+	/*
+	 * Fixup the chain of primary PCI busses.
+	 */
+	if (pchain) {
+		pchain->next = &hose->pci_bus;
+		pchain = pchain->next;
+	} else {
+		pchain = &pci_root;
+		memcpy(pchain, &hose->pci_bus, sizeof(pci_root));
+	}
+	DBG_HOSE(("layout_one_hose: returning...\n"));
+}
+
+static void __init
+layout_hoses(void)
+{
+	struct linux_hose_info * hose;
+	int i;
+
+	/* On multiple bus machines, we play games with pci_root in order
+	   that all of the busses are probed as part of the normal PCI
+	   setup.  The existance of the busses was determined in init_arch.  */
+
+	if (hose_head) {
+		/* Multi-bus machines did not yet wish to allow bus
+		   accesses.  We now do our own thing after the normal
+		   pci_scan_bus is over.  This mechanism is relatively
+		   broken but will be fixed later.  */
+		pci_probe_enabled = 1;
+
+		for (hose = hose_head; hose; hose = hose->next)
+			layout_one_hose(hose);
+	} else {
+		/* For the benefit of single-bus machines, emulate a
+		   multi-bus machine to the (limited) extent necessary. 
+		   Init all bus2hose entries to point to a dummy.  */
+		hose = kmalloc(sizeof(*hose), GFP_KERNEL);
+		memset(hose, 0, sizeof(*hose));
+		for (i = 0; i < 256; ++i)
+			bus2hose[i] = hose;
+	}
+}
+
 #endif /* CONFIG_PCI */
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/kernel/bios32.h linux/arch/alpha/kernel/bios32.h
--- v2.1.120/linux/arch/alpha/kernel/bios32.h	Tue Aug 18 22:02:02 1998
+++ linux/arch/alpha/kernel/bios32.h	Sun Sep  6 10:34:33 1998
@@ -153,3 +153,9 @@
    if (slot >= min_idsel && slot <= max_idsel && pin < irqs_per_slot)	\
      _ctl_ = irq_tab[slot - min_idsel][pin];				\
    _ctl_; })
+
+
+/* The hose list.  */
+extern struct linux_hose_info *hose_head, **hose_tail;
+extern int hose_count;
+extern int pci_probe_enabled;
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/kernel/check_asm.c linux/arch/alpha/kernel/check_asm.c
--- v2.1.120/linux/arch/alpha/kernel/check_asm.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/alpha/kernel/check_asm.c	Tue Sep  8 23:20:40 1998
@@ -0,0 +1,32 @@
+#include <linux/types.h>
+#include <linux/stddef.h>
+#include <linux/sched.h>
+#include <asm/io.h>
+
+int main()
+{
+	printf("#ifndef __ASM_OFFSETS_H__\n#define __ASM_OFFSETS_H__\n");
+
+	printf("#define TASK_STATE %ld\n",
+	       (long)offsetof(struct task_struct, state));
+	printf("#define TASK_FLAGS %ld\n",
+	       (long)offsetof(struct task_struct, flags));
+	printf("#define TASK_SIGPENDING %ld\n",
+	       (long)offsetof(struct task_struct, sigpending));
+	printf("#define TASK_ADDR_LIMIT %ld\n",
+	       (long)offsetof(struct task_struct, addr_limit));
+	printf("#define TASK_EXEC_DOMAIN %ld\n",
+	       (long)offsetof(struct task_struct, exec_domain));
+	printf("#define TASK_NEED_RESCHED %ld\n",
+	       (long)offsetof(struct task_struct, need_resched));
+	printf("#define TASK_SIZE %ld\n", sizeof(struct task_struct));
+	printf("#define STACK_SIZE %ld\n", sizeof(union task_union));
+
+	printf("#define HAE_CACHE %ld\n",
+	       (long)offsetof(struct alpha_machine_vector, hae_cache));
+	printf("#define HAE_REG %ld\n",
+	       (long)offsetof(struct alpha_machine_vector, hae_register));
+
+	printf("#endif /* __ASM_OFFSETS_H__ */\n");
+	return 0;
+}
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/kernel/core_apecs.c linux/arch/alpha/kernel/core_apecs.c
--- v2.1.120/linux/arch/alpha/kernel/core_apecs.c	Tue Aug 18 22:02:02 1998
+++ linux/arch/alpha/kernel/core_apecs.c	Sun Sep  6 10:34:33 1998
@@ -130,8 +130,7 @@
 	unsigned int stat0, value;
 	unsigned int haxr2 = 0;
 
-	save_flags(flags);	/* avoid getting hit by machine check */
-	cli();
+	__save_and_cli(flags);	/* avoid getting hit by machine check */
 
 	DBG(("conf_read(addr=0x%lx, type1=%d)\n", addr, type1));
 
@@ -201,7 +200,7 @@
 		*(vuip)APECS_IOC_HAXR2 = haxr2 & ~1;
 		mb();
 	}
-	restore_flags(flags);
+	__restore_flags(flags);
 
 	return value;
 }
@@ -213,8 +212,8 @@
 	unsigned int stat0;
 	unsigned int haxr2 = 0;
 
-	save_flags(flags);	/* avoid getting hit by machine check */
-	cli();
+	__save_and_cli(flags);	/* avoid getting hit by machine check */
+
 
 	/* Reset status register to avoid losing errors.  */
 	stat0 = *(vuip)APECS_IOC_DCSR;
@@ -270,18 +269,17 @@
 		*(vuip)APECS_IOC_HAXR2 = haxr2 & ~1;
 		mb();
 	}
-	restore_flags(flags);
+	__restore_flags(flags);
 }
 
 int
-apecs_pcibios_read_config_byte (u8 bus, u8 device_fn, u8 where, u8 *value)
+apecs_hose_read_config_byte (u8 bus, u8 device_fn, u8 where, u8 *value,
+			     struct linux_hose_info *hose)
 {
 	unsigned long addr = APECS_CONF;
 	unsigned long pci_addr;
 	unsigned char type1;
 
-	*value = 0xff;
-
 	if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1))
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
@@ -293,16 +291,13 @@
 }
 
 int 
-apecs_pcibios_read_config_word (u8 bus, u8 device_fn, u8 where, u16 *value)
+apecs_hose_read_config_word (u8 bus, u8 device_fn, u8 where, u16 *value,
+			     struct linux_hose_info *hose)
 {
 	unsigned long addr = APECS_CONF;
 	unsigned long pci_addr;
 	unsigned char type1;
 
-	*value = 0xffff;
-
-	if (where & 0x1)
-		return PCIBIOS_BAD_REGISTER_NUMBER;
 	if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1))
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
@@ -313,15 +308,13 @@
 }
 
 int
-apecs_pcibios_read_config_dword (u8 bus, u8 device_fn, u8 where, u32 *value)
+apecs_hose_read_config_dword (u8 bus, u8 device_fn, u8 where, u32 *value,
+			      struct linux_hose_info *hose)
 {
 	unsigned long addr = APECS_CONF;
 	unsigned long pci_addr;
 	unsigned char type1;
 
-	*value = 0xffffffff;
-	if (where & 0x3)
-		return PCIBIOS_BAD_REGISTER_NUMBER;
 	if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1))
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
@@ -331,7 +324,8 @@
 }
 
 int
-apecs_pcibios_write_config_byte (u8 bus, u8 device_fn, u8 where, u8 value)
+apecs_hose_write_config_byte (u8 bus, u8 device_fn, u8 where, u8 value,
+			      struct linux_hose_info *hose)
 {
 	unsigned long addr = APECS_CONF;
 	unsigned long pci_addr;
@@ -346,7 +340,8 @@
 }
 
 int 
-apecs_pcibios_write_config_word (u8 bus, u8 device_fn, u8 where, u16 value)
+apecs_hose_write_config_word (u8 bus, u8 device_fn, u8 where, u16 value,
+			      struct linux_hose_info *hose)
 {
 	unsigned long addr = APECS_CONF;
 	unsigned long pci_addr;
@@ -361,7 +356,8 @@
 }
 
 int 
-apecs_pcibios_write_config_dword (u8 bus, u8 device_fn, u8 where, u32 value)
+apecs_hose_write_config_dword (u8 bus, u8 device_fn, u8 where, u32 value,
+			       struct linux_hose_info *hose)
 {
 	unsigned long addr = APECS_CONF;
 	unsigned long pci_addr;
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/kernel/core_cia.c linux/arch/alpha/kernel/core_cia.c
--- v2.1.120/linux/arch/alpha/kernel/core_cia.c	Tue Aug 18 22:02:02 1998
+++ linux/arch/alpha/kernel/core_cia.c	Sun Sep  6 10:34:33 1998
@@ -30,8 +30,6 @@
  * handle the system transaction.  Another involves timing.  Ho hum.
  */
 
-extern asmlinkage void wrmces(unsigned long mces);
-
 /*
  * Machine check reasons.  Defined according to PALcode sources
  * (osf.h and platform.h).
@@ -155,8 +153,7 @@
 	value = 0xffffffffU;
 	mb();
 
-	save_flags(flags);	/* avoid getting hit by machine check */
-	cli();
+	__save_and_cli(flags);	/* avoid getting hit by machine check */
 
 	DBGC(("conf_read(addr=0x%lx, type1=%d)\n", addr, type1));
 
@@ -224,7 +221,7 @@
 
 	DBGC(("conf_read(): finished\n"));
 
-	restore_flags(flags);
+	__restore_flags(flags);
 	return value;
 }
 
@@ -235,8 +232,7 @@
 	unsigned int stat0;
 	unsigned int cia_cfg = 0;
 
-	save_flags(flags);	/* avoid getting hit by machine check */
-	cli();
+	__save_and_cli(flags);	/* avoid getting hit by machine check */
 
 	/* Reset status register to avoid losing errors.  */
 	stat0 = *(vuip)CIA_IOC_CIA_ERR;
@@ -295,18 +291,17 @@
 	}
 
 	DBGC(("conf_write(): finished\n"));
-	restore_flags(flags);
+	__restore_flags(flags);
 }
 
 int
-cia_pcibios_read_config_byte (u8 bus, u8 device_fn, u8 where, u8 *value)
+cia_hose_read_config_byte (u8 bus, u8 device_fn, u8 where, u8 *value,
+			   struct linux_hose_info *hose)
 {
 	unsigned long addr = CIA_CONF;
 	unsigned long pci_addr;
 	unsigned char type1;
 
-	*value = 0xff;
-
 	if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1))
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
@@ -316,16 +311,13 @@
 }
 
 int 
-cia_pcibios_read_config_word (u8 bus, u8 device_fn, u8 where, u16 *value)
+cia_hose_read_config_word (u8 bus, u8 device_fn, u8 where, u16 *value,
+			   struct linux_hose_info *hose)
 {
 	unsigned long addr = CIA_CONF;
 	unsigned long pci_addr;
 	unsigned char type1;
 
-	*value = 0xffff;
-
-	if (where & 0x1)
-		return PCIBIOS_BAD_REGISTER_NUMBER;
 	if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1))
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
@@ -335,15 +327,13 @@
 }
 
 int 
-cia_pcibios_read_config_dword (u8 bus, u8 device_fn, u8 where, u32 *value)
+cia_hose_read_config_dword (u8 bus, u8 device_fn, u8 where, u32 *value,
+			    struct linux_hose_info *hose)
 {
 	unsigned long addr = CIA_CONF;
 	unsigned long pci_addr;
 	unsigned char type1;
 
-	*value = 0xffffffff;
-	if (where & 0x3)
-		return PCIBIOS_BAD_REGISTER_NUMBER;
 	if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1))
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
@@ -353,7 +343,8 @@
 }
 
 int 
-cia_pcibios_write_config_byte (u8 bus, u8 device_fn, u8 where, u8 value)
+cia_hose_write_config_byte (u8 bus, u8 device_fn, u8 where, u8 value,
+			    struct linux_hose_info *hose)
 {
 	unsigned long addr = CIA_CONF;
 	unsigned long pci_addr;
@@ -368,14 +359,13 @@
 }
 
 int 
-cia_pcibios_write_config_word (u8 bus, u8 device_fn, u8 where, u16 value)
+cia_hose_write_config_word (u8 bus, u8 device_fn, u8 where, u16 value,
+			    struct linux_hose_info *hose)
 {
 	unsigned long addr = CIA_CONF;
 	unsigned long pci_addr;
 	unsigned char type1;
 
-	if (where & 0x1)
-		return PCIBIOS_BAD_REGISTER_NUMBER;
 	if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1))
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
@@ -385,14 +375,13 @@
 }
 
 int 
-cia_pcibios_write_config_dword (u8 bus, u8 device_fn, u8 where, u32 value)
+cia_hose_write_config_dword (u8 bus, u8 device_fn, u8 where, u32 value,
+			     struct linux_hose_info *hose)
 {
 	unsigned long addr = CIA_CONF;
 	unsigned long pci_addr;
 	unsigned char type1;
 
-	if (where & 0x3)
-		return PCIBIOS_BAD_REGISTER_NUMBER;
 	if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1))
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/kernel/core_lca.c linux/arch/alpha/kernel/core_lca.c
--- v2.1.120/linux/arch/alpha/kernel/core_lca.c	Sat Sep  5 16:46:40 1998
+++ linux/arch/alpha/kernel/core_lca.c	Sun Sep  6 10:34:33 1998
@@ -128,8 +128,7 @@
 	unsigned long flags, code, stat0;
 	unsigned int value;
 
-	save_flags(flags);
-	cli();
+	__save_and_cli(flags);
 
 	/* Reset status register to avoid loosing errors.  */
 	stat0 = *(vulp)LCA_IOC_STAT0;
@@ -157,7 +156,7 @@
 
 		value = 0xffffffff;
 	}
-	restore_flags(flags);
+	__restore_flags(flags);
 	return value;
 }
 
@@ -166,8 +165,7 @@
 {
 	unsigned long flags, code, stat0;
 
-	save_flags(flags);	/* avoid getting hit by machine check */
-	cli();
+	__save_and_cli(flags);	/* avoid getting hit by machine check */
 
 	/* Reset status register to avoid loosing errors.  */
 	stat0 = *(vulp)LCA_IOC_STAT0;
@@ -193,17 +191,16 @@
 		/* Reset machine check. */
 		wrmces(0x7);
 	}
-	restore_flags(flags);
+	__restore_flags(flags);
 }
 
 int
-lca_pcibios_read_config_byte (u8 bus, u8 device_fn, u8 where, u8 *value)
+lca_hose_read_config_byte (u8 bus, u8 device_fn, u8 where, u8 *value,
+			   struct linux_hose_info *hose)
 {
 	unsigned long addr = LCA_CONF;
 	unsigned long pci_addr;
 
-	*value = 0xff;
-
 	if (mk_conf_addr(bus, device_fn, where, &pci_addr))
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
@@ -213,15 +210,12 @@
 }
 
 int 
-lca_pcibios_read_config_word (u8 bus, u8 device_fn, u8 where, u16 *value)
+lca_hose_read_config_word (u8 bus, u8 device_fn, u8 where, u16 *value,
+			   struct linux_hose_info *hose)
 {
 	unsigned long addr = LCA_CONF;
 	unsigned long pci_addr;
 
-	*value = 0xffff;
-
-	if (where & 0x1)
-		return PCIBIOS_BAD_REGISTER_NUMBER;
 	if (mk_conf_addr(bus, device_fn, where, &pci_addr))
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
@@ -231,14 +225,12 @@
 }
 
 int
-lca_pcibios_read_config_dword (u8 bus, u8 device_fn, u8 where, u32 *value)
+lca_hose_read_config_dword (u8 bus, u8 device_fn, u8 where, u32 *value,
+			    struct linux_hose_info *hose)
 {
 	unsigned long addr = LCA_CONF;
 	unsigned long pci_addr;
 
-	*value = 0xffffffff;
-	if (where & 0x3)
-		return PCIBIOS_BAD_REGISTER_NUMBER;
 	if (mk_conf_addr(bus, device_fn, where, &pci_addr))
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
@@ -248,7 +240,8 @@
 }
 
 int 
-lca_pcibios_write_config_byte (u8 bus, u8 device_fn, u8 where, u8 value)
+lca_hose_write_config_byte (u8 bus, u8 device_fn, u8 where, u8 value,
+			    struct linux_hose_info *hose)
 {
 	unsigned long addr = LCA_CONF;
 	unsigned long pci_addr;
@@ -262,13 +255,12 @@
 }
 
 int
-lca_pcibios_write_config_word (u8 bus, u8 device_fn, u8 where, u16 value)
+lca_hose_write_config_word (u8 bus, u8 device_fn, u8 where, u16 value,
+			    struct linux_hose_info *hose)
 {
 	unsigned long addr = LCA_CONF;
 	unsigned long pci_addr;
 
-	if (where & 0x1)
-		return PCIBIOS_BAD_REGISTER_NUMBER;
 	if (mk_conf_addr(bus, device_fn, where, &pci_addr))
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
@@ -278,13 +270,12 @@
 }
 
 int 
-lca_pcibios_write_config_dword (u8 bus, u8 device_fn, u8 where, u32 value)
+lca_hose_write_config_dword (u8 bus, u8 device_fn, u8 where, u32 value,
+			     struct linux_hose_info *hose)
 {
 	unsigned long addr = LCA_CONF;
 	unsigned long pci_addr;
 
-	if (where & 0x3)
-		return PCIBIOS_BAD_REGISTER_NUMBER;
 	if (mk_conf_addr(bus, device_fn, where, &pci_addr))
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/kernel/core_mcpcia.c linux/arch/alpha/kernel/core_mcpcia.c
--- v2.1.120/linux/arch/alpha/kernel/core_mcpcia.c	Tue Aug 18 22:02:02 1998
+++ linux/arch/alpha/kernel/core_mcpcia.c	Sun Sep  6 10:34:33 1998
@@ -12,10 +12,13 @@
 #include <linux/pci.h>
 #include <linux/sched.h>
 #include <linux/init.h>
+#include <linux/delay.h>
 
 #include <asm/ptrace.h>
 #include <asm/system.h>
 #include <asm/pci.h>
+#include <asm/hwrpb.h>
+#include <asm/mmu_context.h>
 
 #define __EXTERN_INLINE inline
 #include <asm/io.h>
@@ -23,6 +26,7 @@
 #undef __EXTERN_INLINE
 
 #include "proto.h"
+#include "bios32.h"
 
 /*
  * NOTE: Herein lie back-to-back mb instructions.  They are magic. 
@@ -30,8 +34,6 @@
  * handle the system transaction.  Another involves timing.  Ho hum.
  */
 
-extern asmlinkage void wrmces(unsigned long mces);
-
 /*
  * BIOS32-style PCI interface:
  */
@@ -44,42 +46,20 @@
 # define DBG_CFG(args)
 #endif
 
-#undef DEBUG_PCI
-
-#ifdef DEBUG_PCI
-# define DBG_PCI(args)	printk args
-#else
-# define DBG_PCI(args)
-#endif
 
 #define DEBUG_MCHECK
 
 #ifdef DEBUG_MCHECK
 # define DBG_MCK(args)	printk args
-# define DEBUG_MCHECK_DUMP
 #else
 # define DBG_MCK(args)
 #endif
 
-#define vuip	volatile unsigned int  *
-#define vulp	volatile unsigned long  *
-
 static volatile unsigned int MCPCIA_mcheck_expected[NR_CPUS];
 static volatile unsigned int MCPCIA_mcheck_taken[NR_CPUS];
 static unsigned int MCPCIA_jd[NR_CPUS];
 
 #define MCPCIA_MAX_HOSES 2
-static int mcpcia_num_hoses = 0;
-
-static int pci_probe_enabled = 0; /* disable to start */
-
-static struct linux_hose_info *mcpcia_root = NULL, *mcpcia_last_hose;
-
-static inline unsigned long long_align(unsigned long addr)
-{
-	return ((addr + (sizeof(unsigned long) - 1)) &
-		~(sizeof(unsigned long) - 1));
-}
 
 
 /*
@@ -134,7 +114,7 @@
 
 	cpu = smp_processor_id();
 
-	save_and_cli(flags);
+	__save_and_cli(flags);
 
 	DBG_CFG(("conf_read(addr=0x%lx, type1=%d, hose=%d)\n",
 		 addr, type1, hoseno));
@@ -166,7 +146,7 @@
 
 	DBG_CFG(("conf_read(): finished\n"));
 
-	restore_flags(flags);
+	__restore_flags(flags);
 	return value;
 }
 
@@ -180,7 +160,7 @@
 
 	cpu = smp_processor_id();
 
-	save_and_cli(flags);	/* avoid getting hit by machine check */
+	__save_and_cli(flags);	/* avoid getting hit by machine check */
 
 	/* Reset status register to avoid losing errors.  */
 	stat0 = *(vuip)MCPCIA_CAP_ERR(hoseno);
@@ -201,7 +181,7 @@
 	mb();
 
 	DBG_CFG(("conf_write(): finished\n"));
-	restore_flags(flags);
+	__restore_flags(flags);
 }
 
 static int
@@ -211,7 +191,7 @@
 {
 	unsigned long addr;
 
-	if (!pci_probe_enabled) /* if doing standard pci_init(), ignore */
+	if (!pci_probe_enabled)
 		return -1;
 
 	DBG_CFG(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x,"
@@ -232,18 +212,13 @@
 	return 0;
 }
 
-/* FIXME: At some point we should update these routines to use the new
-   PCI interface, which can jump through these hoops for us.  */
-
-static inline int
-hose_read_config_byte (u8 bus, u8 device_fn, u8 where, u8 *value,
-		       struct linux_hose_info *hose)
+int
+mcpcia_hose_read_config_byte (u8 bus, u8 device_fn, u8 where, u8 *value,
+			      struct linux_hose_info *hose)
 {
 	unsigned long addr;
 	unsigned char type1;
 
-	*value = 0xff;
-
 	if (mk_conf_addr(hose, bus, device_fn, where, &addr, &type1))
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
@@ -252,17 +227,13 @@
 	return PCIBIOS_SUCCESSFUL;
 }
 
-static inline int
-hose_read_config_word (u8 bus, u8 device_fn, u8 where, u16 *value,
-		       struct linux_hose_info *hose)
+int
+mcpcia_hose_read_config_word (u8 bus, u8 device_fn, u8 where, u16 *value,
+			      struct linux_hose_info *hose)
 {
 	unsigned long addr;
 	unsigned char type1;
 
-	*value = 0xffff;
-
-	if (where & 0x1)
-		return PCIBIOS_BAD_REGISTER_NUMBER;
 	if (mk_conf_addr(hose, bus, device_fn, where, &addr, &type1))
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
@@ -271,17 +242,13 @@
 	return PCIBIOS_SUCCESSFUL;
 }
 
-static inline int
-hose_read_config_dword (u8 bus, u8 device_fn, u8 where, u32 *value,
-			struct linux_hose_info *hose)
+int
+mcpcia_hose_read_config_dword (u8 bus, u8 device_fn, u8 where, u32 *value,
+			       struct linux_hose_info *hose)
 {
 	unsigned long addr;
 	unsigned char type1;
 
-	*value = 0xffffffff;
-
-	if (where & 0x3)
-		return PCIBIOS_BAD_REGISTER_NUMBER;
 	if (mk_conf_addr(hose, bus, device_fn, where, &addr, &type1))
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
@@ -290,9 +257,9 @@
 	return PCIBIOS_SUCCESSFUL;
 }
 
-static inline int
-hose_write_config_byte (u8 bus, u8 device_fn, u8 where, u8 value,
-			struct linux_hose_info *hose)
+int
+mcpcia_hose_write_config_byte (u8 bus, u8 device_fn, u8 where, u8 value,
+			       struct linux_hose_info *hose)
 {
 	unsigned long addr;
 	unsigned char type1;
@@ -305,9 +272,9 @@
 	return PCIBIOS_SUCCESSFUL;
 }
 
-static inline int
-hose_write_config_word (u8 bus, u8 device_fn, u8 where, u16 value,
-			struct linux_hose_info *hose)
+int
+mcpcia_hose_write_config_word (u8 bus, u8 device_fn, u8 where, u16 value,
+			       struct linux_hose_info *hose)
 {
 	unsigned long addr;
 	unsigned char type1;
@@ -320,9 +287,9 @@
 	return PCIBIOS_SUCCESSFUL;
 }
 
-static inline int
-hose_write_config_dword (u8 bus, u8 device_fn, u8 where, u32 value,
-			 struct linux_hose_info *hose)
+int
+mcpcia_hose_write_config_dword (u8 bus, u8 device_fn, u8 where, u32 value,
+				struct linux_hose_info *hose)
 {
 	unsigned long addr;
 	unsigned char type1;
@@ -335,77 +302,64 @@
 	return PCIBIOS_SUCCESSFUL;
 }
 
-int
-mcpcia_pcibios_read_config_byte (u8 bus, u8 devfn, u8 where, u8 *value)
-{
-	return hose_read_config_byte(bus, devfn, where, value, bus2hose[bus]);
-}
-
-int
-mcpcia_pcibios_read_config_word (u8 bus, u8 devfn, u8 where, u16 *value)
-{
-	return hose_read_config_word(bus, devfn, where, value, bus2hose[bus]);
-}
-
-int 
-mcpcia_pcibios_read_config_dword (u8 bus, u8 devfn, u8 where, u32 *value)
-{
-	return hose_read_config_dword(bus, devfn, where, value, bus2hose[bus]);
-}
-
-int 
-mcpcia_pcibios_write_config_byte (u8 bus, u8 devfn, u8 where, u8 value)
-{
-	return hose_write_config_byte(bus, devfn, where, value, bus2hose[bus]);
-}
-
-int 
-mcpcia_pcibios_write_config_word (u8 bus, u8 devfn, u8 where, u16 value)
-{
-	return hose_write_config_word(bus, devfn, where, value, bus2hose[bus]);
-}
-
-int 
-mcpcia_pcibios_write_config_dword (u8 bus, u8 devfn, u8 where, u32 val)
-{
-	return hose_write_config_dword(bus, devfn, where, val, bus2hose[bus]);
-}
-
 void __init
 mcpcia_init_arch(unsigned long *mem_start, unsigned long *mem_end)
 {
+	extern asmlinkage void entInt(void);
 	struct linux_hose_info *hose;
 	unsigned int mcpcia_err;
 	unsigned int pci_rev;
-	int h;
+	int h, cpu;
 
-	*mem_start = long_align(*mem_start);
+	/* Ho hum.. init_arch is called before init_IRQ, but we need to be
+	   able to handle machine checks.  So install the handler now.  */
+	wrent(entInt, 0);
 
-	for (h = 0; h < NR_CPUS; h++) {
-		MCPCIA_mcheck_expected[h] = 0;
-		MCPCIA_mcheck_taken[h] = 0;
-	}
+	/* Align memory to cache line; we'll be allocating from it.  */
+	*mem_start = (*mem_start | 31) + 1;
+
+	cpu = smp_processor_id();
 
 	/* First, find how many hoses we have.  */
 	for (h = 0; h < MCPCIA_MAX_HOSES; h++) {
+
+		/* Gotta be REAL careful.  If hose is absent, we get a
+		   machine check.  */
+
+		mb();
+		mb();
+		draina();
+		MCPCIA_mcheck_expected[cpu] = 1;
+		MCPCIA_mcheck_taken[cpu]    = 0;
+		mb();
+
+		/* Access the bus revision word. */
 		pci_rev = *(vuip)MCPCIA_REV(h);
+
+		mb();
+		mb();  /* magic */
+		if (MCPCIA_mcheck_taken[cpu]) {
+			MCPCIA_mcheck_taken[cpu] = 0;
+			pci_rev = 0xffffffff;
+			mb();
+		}
+		MCPCIA_mcheck_expected[cpu] = 0;
+		mb();
+
 #if 0
-		printk("mcpcia_init: got 0x%x for PCI_REV for hose %d\n",
+		printk("mcpcia_init_arch: got 0x%x for PCI_REV for hose %d\n",
 		       pci_rev, h);
 #endif
 		if ((pci_rev >> 16) == PCI_CLASS_BRIDGE_HOST) {
-			mcpcia_num_hoses++;
+			hose_count++;
 
 			hose = (struct linux_hose_info *)*mem_start;
-			*mem_start = long_align(*mem_start + sizeof(*hose));
+			*mem_start = (unsigned long)(hose + 1);
 
 			memset(hose, 0, sizeof(*hose));
 
-			if (mcpcia_root)
-				mcpcia_last_hose->next = hose;
-			else
-				mcpcia_root = hose;
-			mcpcia_last_hose = hose;
+			*hose_tail = hose;
+			hose_tail = &hose->next;
 
 			hose->pci_io_space = MCPCIA_IO(h);
 			hose->pci_mem_space = MCPCIA_DENSE(h);
@@ -418,14 +372,14 @@
 	}
 
 #if 1
-	printk("mcpcia_init: found %d hoses\n", mcpcia_num_hoses);
+	printk("mcpcia_init_arch: found %d hoses\n", hose_count);
 #endif
 
 	/* Now do init for each hose.  */
-	for (hose = mcpcia_root; hose; hose = hose->next) {
+	for (hose = hose_head; hose; hose = hose->next) {
 		h = hose->pci_hose_index;
 #if 0
-		printk("mcpcia_init: -------- hose %d --------\n",h);
+		printk("mcpcia_init_arch: -------- hose %d --------\n",h);
 		printk("MCPCIA_REV 0x%x\n", *(vuip)MCPCIA_REV(h));
 		printk("MCPCIA_WHOAMI 0x%x\n", *(vuip)MCPCIA_WHOAMI(h));
 		printk("MCPCIA_HAE_MEM 0x%x\n", *(vuip)MCPCIA_HAE_MEM(h));
@@ -470,8 +424,8 @@
 				MCPCIA_DMA_WIN_SIZE = *(vuip)MCPCIA_W0_MASK(h) & 0xfff00000U;
 				MCPCIA_DMA_WIN_SIZE += 0x00100000U;
 #if 1
-				printk("mcpcia_init: using Window 0 settings\n");
-				printk("mcpcia_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n",
+				printk("mcpcia_init_arch: using Window 0 settings\n");
+				printk("mcpcia_init_arch: BASE 0x%x MASK 0x%x TRANS 0x%x\n",
 				       *(vuip)MCPCIA_W0_BASE(h),
 				       *(vuip)MCPCIA_W0_MASK(h),
 				       *(vuip)MCPCIA_T0_BASE(h));
@@ -487,8 +441,8 @@
 				MCPCIA_DMA_WIN_SIZE = *(vuip)MCPCIA_W1_MASK(h) & 0xfff00000U;
 				MCPCIA_DMA_WIN_SIZE += 0x00100000U;
 #if 1
-				printk("mcpcia_init: using Window 1 settings\n");
-				printk("mcpcia_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n",
+				printk("mcpcia_init_arch: using Window 1 settings\n");
+				printk("mcpcia_init_arch: BASE 0x%x MASK 0x%x TRANS 0x%x\n",
 				       *(vuip)MCPCIA_W1_BASE(h),
 				       *(vuip)MCPCIA_W1_MASK(h),
 				       *(vuip)MCPCIA_T1_BASE(h));
@@ -504,8 +458,8 @@
 				MCPCIA_DMA_WIN_SIZE = *(vuip)MCPCIA_W2_MASK(h) & 0xfff00000U;
 				MCPCIA_DMA_WIN_SIZE += 0x00100000U;
 #if 1
-				printk("mcpcia_init: using Window 2 settings\n");
-				printk("mcpcia_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n",
+				printk("mcpcia_init_arch: using Window 2 settings\n");
+				printk("mcpcia_init_arch: BASE 0x%x MASK 0x%x TRANS 0x%x\n",
 				       *(vuip)MCPCIA_W2_BASE(h),
 				       *(vuip)MCPCIA_W2_MASK(h),
 				       *(vuip)MCPCIA_T2_BASE(h));
@@ -521,8 +475,8 @@
 				MCPCIA_DMA_WIN_SIZE = *(vuip)MCPCIA_W3_MASK(h) & 0xfff00000U;
 				MCPCIA_DMA_WIN_SIZE += 0x00100000U;
 #if 1
-				printk("mcpcia_init: using Window 3 settings\n");
-				printk("mcpcia_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n",
+				printk("mcpcia_init_arch: using Window 3 settings\n");
+				printk("mcpcia_init_arch: BASE 0x%x MASK 0x%x TRANS 0x%x\n",
 				       *(vuip)MCPCIA_W3_BASE(h),
 				       *(vuip)MCPCIA_W3_MASK(h),
 				       *(vuip)MCPCIA_T3_BASE(h));
@@ -541,7 +495,7 @@
 			 * future, we may want to use them to do scatter/
 			 * gather DMA.
 			 *
-			 * Window 0 goes at 1 GB and is 1 GB large.
+			 * Window 0 goes at 2 GB and is 2 GB large.
 			 */
 
 			*(vuip)MCPCIA_W0_BASE(h) = 1U | (MCPCIA_DMA_WIN_BASE_DEFAULT & 0xfff00000U);
@@ -559,7 +513,7 @@
 #if 0
 		{
 			unsigned int mcpcia_int_ctl = *((vuip)MCPCIA_INT_CTL(h));
-			printk("mcpcia_init: INT_CTL was 0x%x\n", mcpcia_int_ctl);
+			printk("mcpcia_init_arch: INT_CTL was 0x%x\n", mcpcia_int_ctl);
 			*(vuip)MCPCIA_INT_CTL(h) = 1U; mb();
 			mcpcia_int_ctl = *(vuip)MCPCIA_INT_CTL(h);
 		}
@@ -750,221 +704,9 @@
 		else if (type == 0x630)
 			printk("MCPCIA machine check: processor CORRECTABLE!\n");
 		else
-			mcpcia_print_uncorrectable(mchk_logout);
 #endif /* DEBUG_MCHECK_DUMP */
+			mcpcia_print_uncorrectable(mchk_logout);
 	}
 #endif
 #endif
-}
-
-/*==========================================================================*/
-
-#define PRIMARY(b) ((b)&0xff)
-#define SECONDARY(b) (((b)>>8)&0xff)
-#define SUBORDINATE(b) (((b)>>16)&0xff)
-
-static int __init
-hose_scan_bridges(struct linux_hose_info *hose, unsigned char bus)
-{
-	unsigned int devfn, l, class;
-	unsigned char hdr_type = 0;
-	unsigned int found = 0;
-
-	for (devfn = 0; devfn < 0xff; ++devfn) {
-		if (PCI_FUNC(devfn) == 0) {
-			hose_read_config_byte(bus, devfn, PCI_HEADER_TYPE,
-					      &hdr_type, hose);
-		} else if (!(hdr_type & 0x80)) {
-			/* not a multi-function device */
-			continue;
-		}
-
-		/* Check if there is anything here. */
-		hose_read_config_dword(bus, devfn, PCI_VENDOR_ID, &l, hose);
-		if (l == 0xffffffff || l == 0x00000000) {
-			hdr_type = 0;
-			continue;
-		}
-
-		/* See if this is a bridge device. */
-		hose_read_config_dword(bus, devfn, PCI_CLASS_REVISION,
-				       &class, hose);
-
-		if ((class >> 16) == PCI_CLASS_BRIDGE_PCI) {
-			unsigned int busses;
-
-			found++;
-
-			hose_read_config_dword(bus, devfn, PCI_PRIMARY_BUS,
-					       &busses, hose);
-
-			DBG_PCI(("hose_scan_bridges: hose %d bus %d "
-				 "slot %d busses 0x%x\n",
-				 hose->pci_hose_index, bus, PCI_SLOT(devfn),
-				 busses));
-
-			/*
-			 * Do something with first_busno and last_busno
-			 */
-			if (hose->pci_first_busno > PRIMARY(busses)) {
-				hose->pci_first_busno = PRIMARY(busses);
-				DBG_PCI(("hose_scan_bridges: hose %d bus %d "
-					 "slot %d change first to %d\n",
-					 hose->pci_hose_index, bus,
-					 PCI_SLOT(devfn), PRIMARY(busses)));
-			}
-			if (hose->pci_last_busno < SUBORDINATE(busses)) {
-				hose->pci_last_busno = SUBORDINATE(busses);
-				DBG_PCI(("hose_scan_bridges: hose %d bus %d "
-					 "slot %d change last to %d\n",
-					 hose->pci_hose_index, bus,
-					 PCI_SLOT(devfn),
-					 SUBORDINATE(busses)));
-			}
-			/*
-			 * Now scan everything underneath the bridge.
-			 */
-			hose_scan_bridges(hose, SECONDARY(busses));
-		}
-	}
-	return found;
-}
-
-static void __init
-hose_reconfigure_bridges(struct linux_hose_info *hose, unsigned char bus)
-{
-	unsigned int devfn, l, class;
-	unsigned char hdr_type = 0;
-
-	for (devfn = 0; devfn < 0xff; ++devfn) {
-		if (PCI_FUNC(devfn) == 0) {
-			hose_read_config_byte(bus, devfn, PCI_HEADER_TYPE,
-					      &hdr_type, hose);
-		} else if (!(hdr_type & 0x80)) {
-			/* not a multi-function device */
-			continue;
-		}
-
-		/* Check if there is anything here. */
-		hose_read_config_dword(bus, devfn, PCI_VENDOR_ID, &l, hose);
-		if (l == 0xffffffff || l == 0x00000000) {
-			hdr_type = 0;
-			continue;
-		}
-
-		/* See if this is a bridge device. */
-		hose_read_config_dword(bus, devfn, PCI_CLASS_REVISION,
-				       &class, hose);
-
-		if ((class >> 16) == PCI_CLASS_BRIDGE_PCI) {
-			unsigned int busses;
-
-			hose_read_config_dword(bus, devfn, PCI_PRIMARY_BUS,
-					       &busses, hose);
-
-			/*
-			 * First reconfigure everything underneath the bridge.
-			 */
-			hose_reconfigure_bridges(hose, (busses >> 8) & 0xff);
-
-			/*
-			 * Unconfigure this bridges bus numbers,
-			 * pci_scan_bus() will fix this up properly.
-			 */
-			busses &= 0xff000000;
-			hose_write_config_dword(bus, devfn, PCI_PRIMARY_BUS,
-						busses, hose);
-		}
-	}
-}
-
-static void __init
-mcpcia_fixup_busno(struct linux_hose_info *hose, unsigned char bus)
-{
-	unsigned int nbus;
-
-	/*
-	 * First, scan for all bridge devices underneath this hose,
-	 * to determine the first and last busnos.
-	 */
-	if (!hose_scan_bridges(hose, 0)) {
-		/* none found, exit */
-		hose->pci_first_busno = bus;
-		hose->pci_last_busno = bus;
-	} else {
-		/*
-		 * Reconfigure all bridge devices underneath this hose.
-		 */
-		hose_reconfigure_bridges(hose, hose->pci_first_busno);
-	}
-
-	/*
-	 * Now reconfigure the hose to it's new bus number and set up
-	 * our bus2hose mapping for this hose.
-	 */
-	nbus = hose->pci_last_busno - hose->pci_first_busno;
-
-	hose->pci_first_busno = bus;
-
-	DBG_PCI(("mcpcia_fixup_busno: hose %d startbus %d nbus %d\n",
-		 hose->pci_hose_index, bus, nbus));
-
-	do {
-		bus2hose[bus++] = hose;
-	} while (nbus-- > 0);
-}
-
-static void __init
-mcpcia_probe(struct linux_hose_info *hose)
-{
-	static struct pci_bus *pchain = NULL;
-	struct pci_bus *pbus = &hose->pci_bus;
-	static unsigned char busno = 0;
-
-	/*
-	 * Hoses include child PCI bridges in bus-range property,
-	 * but we don't scan each of those ourselves, Linux generic PCI
-	 * probing code will find child bridges and link them into this
-	 * hose's root PCI device hierarchy.
-	 */
-
-	pbus->number = pbus->secondary = busno;
-	pbus->sysdata = hose;
-
-	mcpcia_fixup_busno(hose, busno);
-
-	pbus->subordinate = pci_scan_bus(pbus); /* the original! */
-
-	/*
-	 * Set the maximum subordinate bus of this hose.
-	 */
-	hose->pci_last_busno = pbus->subordinate;
-#if 0
-	hose_write_config_byte(busno, 0, 0x41, hose->pci_last_busno, hose);
-#endif
-	busno = pbus->subordinate + 1;
-
-	/*
-	 * Fixup the chain of primary PCI busses.
-	 */
-	if (pchain) {
-		pchain->next = &hose->pci_bus;
-		pchain = pchain->next;
-	} else {
-		pchain = &pci_root;
-		memcpy(pchain, &hose->pci_bus, sizeof(pci_root));
-	}
-}
-
-void __init
-mcpcia_pci_fixup(void)
-{
-	struct linux_hose_info *hose;
-
-	/* Turn on Config space access finally! */
-	pci_probe_enabled = 1;
-
-	/* For each hose, probe and setup the devices on the hose.  */
-	for (hose = mcpcia_root; hose; hose = hose->next)
-		mcpcia_probe(hose);
 }
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/kernel/core_pyxis.c linux/arch/alpha/kernel/core_pyxis.c
--- v2.1.120/linux/arch/alpha/kernel/core_pyxis.c	Tue Aug 18 22:02:02 1998
+++ linux/arch/alpha/kernel/core_pyxis.c	Sun Sep  6 10:34:33 1998
@@ -27,22 +27,22 @@
    One plausible explanation is that the I/O controller does not properly
    handle the system transaction.  Another involves timing.  Ho hum.  */
 
-extern asmlinkage void wrmces(unsigned long mces);
-
 /*
  * BIOS32-style PCI interface:
  */
 
-#ifdef DEBUG 
-# define DBG(args)	printk args
+#define DEBUG_CONFIG 0
+#define DEBUG_MCHECK 0
+
+#if DEBUG_CONFIG
+# define DBG_CNF(args)	printk args
 #else
-# define DBG(args)
+# define DBG_CNF(args)
 #endif
 
-#define DEBUG_MCHECK
-#ifdef DEBUG_MCHECK
+#if DEBUG_MCHECK
 # define DBG_MCK(args)	printk args
-#define DEBUG_MCHECK_DUMP
+# define DEBUG_MCHECK_DUMP
 #else
 # define DBG_MCK(args)
 #endif
@@ -101,9 +101,9 @@
 {
 	unsigned long addr;
 
-	DBG(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x,"
-	     " pci_addr=0x%p, type1=0x%p)\n",
-	     bus, device_fn, where, pci_addr, type1));
+	DBG_CNF(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x,"
+		 " pci_addr=0x%p, type1=0x%p)\n",
+		 bus, device_fn, where, pci_addr, type1));
 
 	if (bus == 0) {
 		int device;
@@ -112,8 +112,8 @@
 		/* Type 0 configuration cycle. */
 #if NOT_NOW
 		if (device > 20) {
-			DBG(("mk_conf_addr: device (%d) > 20, returning -1\n",
-			     device));
+			DBG_CNF(("mk_conf_addr: device (%d) > 20, return -1\n",
+				 device));
 			return -1;
 		}
 #endif
@@ -125,7 +125,7 @@
 		addr = (bus << 16) | (device_fn << 8) | (where);
 	}
 	*pci_addr = addr;
-	DBG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr));
+	DBG_CNF(("mk_conf_addr: returning pci_addr 0x%lx\n", addr));
 	return 0;
 }
 
@@ -136,22 +136,19 @@
 	unsigned int stat0, value, temp;
 	unsigned int pyxis_cfg = 0;
 
-	save_and_cli(flags);	/* avoid getting hit by machine check */
-
-	DBG(("conf_read(addr=0x%lx, type1=%d)\n", addr, type1));
+	__save_and_cli(flags);	/* avoid getting hit by machine check */
 
 	/* Reset status register to avoid losing errors.  */
 	stat0 = *(vuip)PYXIS_ERR;
 	*(vuip)PYXIS_ERR = stat0; mb();
 	temp = *(vuip)PYXIS_ERR;  /* re-read to force write */
-	DBG(("conf_read: PYXIS ERR was 0x%x\n", stat0));
+	DBG_CNF(("conf_read: PYXIS ERR was 0x%x\n", stat0));
 
 	/* If Type1 access, must set PYXIS CFG.  */
 	if (type1) {
 		pyxis_cfg = *(vuip)PYXIS_CFG;
 		*(vuip)PYXIS_CFG = pyxis_cfg | 1; mb();
 		temp = *(vuip)PYXIS_CFG;  /* re-read to force write */
-		DBG(("conf_read: TYPE1 access\n"));
 	}
 
 	mb();
@@ -179,9 +176,10 @@
 		temp = *(vuip)PYXIS_CFG;  /* re-read to force write */
 	}
 
-	DBG(("conf_read(): finished\n"));
+	DBG_CNF(("conf_read(addr=0x%lx, type1=%d) = %#x\n",
+		 addr, type1, value));
 
-	restore_flags(flags);
+	__restore_flags(flags);
 	return value;
 }
 
@@ -192,24 +190,27 @@
 	unsigned int stat0, temp;
 	unsigned int pyxis_cfg = 0;
 
-	save_and_cli(flags);	/* avoid getting hit by machine check */
+	DBG_CNF(("conf_write(addr=%#lx, value=%#x, type1=%d)\n",
+		 addr, value, type1));
+
+	__save_and_cli(flags);	/* avoid getting hit by machine check */
 
 	/* Reset status register to avoid losing errors.  */
 	stat0 = *(vuip)PYXIS_ERR;
 	*(vuip)PYXIS_ERR = stat0; mb();
 	temp = *(vuip)PYXIS_ERR;  /* re-read to force write */
-	DBG(("conf_write: PYXIS ERR was 0x%x\n", stat0));
 
 	/* If Type1 access, must set PYXIS CFG.  */
 	if (type1) {
 		pyxis_cfg = *(vuip)PYXIS_CFG;
 		*(vuip)PYXIS_CFG = pyxis_cfg | 1; mb();
 		temp = *(vuip)PYXIS_CFG;  /* re-read to force write */
-		DBG(("conf_read: TYPE1 access\n"));
 	}
 
+	mb();
 	draina();
 	PYXIS_mcheck_expected = 1;
+	PYXIS_mcheck_taken = 0;
 	mb();
 
 	/* Access configuration space.  */
@@ -226,18 +227,17 @@
 		temp = *(vuip)PYXIS_CFG;  /* re-read to force write */
 	}
 
-	DBG(("conf_write(): finished\n"));
-	restore_flags(flags);
+	__restore_flags(flags);
 }
 
 int
-pyxis_pcibios_read_config_byte (u8 bus, u8 device_fn, u8 where, u8 *value)
+pyxis_hose_read_config_byte (u8 bus, u8 device_fn, u8 where, u8 *value,
+			     struct linux_hose_info *hose)
 {
 	unsigned long addr = PYXIS_CONF;
 	unsigned long pci_addr;
 	unsigned char type1;
 
-	*value = 0xff;
 	if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1))
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
@@ -247,15 +247,13 @@
 }
 
 int
-pyxis_pcibios_read_config_word (u8 bus, u8 device_fn, u8 where, u16 *value)
+pyxis_hose_read_config_word (u8 bus, u8 device_fn, u8 where, u16 *value,
+			     struct linux_hose_info *hose)
 {
 	unsigned long addr = PYXIS_CONF;
 	unsigned long pci_addr;
 	unsigned char type1;
 
-	*value = 0xffff;
-	if (where & 0x1)
-		return PCIBIOS_BAD_REGISTER_NUMBER;
 	if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1))
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
@@ -265,15 +263,13 @@
 }
 
 int
-pyxis_pcibios_read_config_dword (u8 bus, u8 device_fn, u8 where, u32 *value)
+pyxis_hose_read_config_dword (u8 bus, u8 device_fn, u8 where, u32 *value,
+			      struct linux_hose_info *hose)
 {
 	unsigned long addr = PYXIS_CONF;
 	unsigned long pci_addr;
 	unsigned char type1;
 
-	*value = 0xffffffff;
-	if (where & 0x3)
-		return PCIBIOS_BAD_REGISTER_NUMBER;
 	if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1))
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
@@ -283,7 +279,8 @@
 }
 
 int 
-pyxis_pcibios_write_config_byte (u8 bus, u8 device_fn, u8 where, u8 value)
+pyxis_hose_write_config_byte (u8 bus, u8 device_fn, u8 where, u8 value,
+			      struct linux_hose_info *hose)
 {
 	unsigned long addr = PYXIS_CONF;
 	unsigned long pci_addr;
@@ -298,14 +295,13 @@
 }
 
 int 
-pyxis_pcibios_write_config_word (u8 bus, u8 device_fn, u8 where, u16 value)
+pyxis_hose_write_config_word (u8 bus, u8 device_fn, u8 where, u16 value,
+			      struct linux_hose_info *hose)
 {
 	unsigned long addr = PYXIS_CONF;
 	unsigned long pci_addr;
 	unsigned char type1;
 
-	if (where & 0x1)
-		return PCIBIOS_BAD_REGISTER_NUMBER;
 	if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1))
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
@@ -315,14 +311,13 @@
 }
 
 int 
-pyxis_pcibios_write_config_dword (u8 bus, u8 device_fn, u8 where, u32 value)
+pyxis_hose_write_config_dword (u8 bus, u8 device_fn, u8 where, u32 value,
+			       struct linux_hose_info *hose)
 {
 	unsigned long addr = PYXIS_CONF;
 	unsigned long pci_addr;
 	unsigned char type1;
 
-	if (where & 0x3)
-		return PCIBIOS_BAD_REGISTER_NUMBER;
 	if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1))
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
@@ -555,7 +550,7 @@
 pyxis_pci_clr_err(void)
 {
 	PYXIS_jd = *(vuip)PYXIS_ERR;
-	DBG(("PYXIS_pci_clr_err: PYXIS ERR after read 0x%x\n", PYXIS_jd));
+	DBG_MCK(("PYXIS_pci_clr_err: PYXIS ERR after read 0x%x\n", PYXIS_jd));
 	*(vuip)PYXIS_ERR = 0x0180; mb();
 	PYXIS_jd = *(vuip)PYXIS_ERR;  /* re-read to force write */
 	return 0;
@@ -583,17 +578,6 @@
 		 PYXIS_mcheck_expected, mchk_sysdata->epic_dcsr,
 		 mchk_sysdata->epic_pear));
 #endif
-#ifdef DEBUG_MCHECK_DUMP
-	{
-		unsigned long *ptr;
-		int i;
-
-		ptr = (unsigned long *)la_ptr;
-		for (i = 0; i < mchk_header->size / sizeof(long); i += 2) {
-			printk(" +%lx %lx %lx\n", i*sizeof(long), ptr[i], ptr[i+1]);
-		}
-	}
-#endif /* DEBUG_MCHECK_DUMP */
 
 	/*
 	 * Check if machine check is due to a badaddr() and if so,
@@ -602,7 +586,7 @@
 	mb();
 	mb();  /* magic */
 	if (PYXIS_mcheck_expected) {
-		DBG(("PYXIS machine check expected\n"));
+		DBG_MCK(("PYXIS machine check expected\n"));
 		PYXIS_mcheck_expected = 0;
 		PYXIS_mcheck_taken = 1;
 		mb();
@@ -612,7 +596,6 @@
 		wrmces(0x7);
 		mb();
 	}
-#if 1
 	else {
 		printk("PYXIS machine check NOT expected\n") ;
 		DBG_MCK(("pyxis_machine_check: vector=0x%lx la_ptr=0x%lx\n",
@@ -629,6 +612,17 @@
 		pyxis_pci_clr_err();
 		wrmces(0x7);
 		mb();
-	}
+
+#ifdef DEBUG_MCHECK_DUMP
+		{
+			unsigned long *ptr = (unsigned long *)la_ptr;;
+			long n = mchk_header->size / (2*sizeof(long));
+
+			do
+				printk(" +%lx %lx %lx\n", i*sizeof(long),
+				       ptr[i], ptr[i+1]);
+			while (--i);
+		}
 #endif
+	}
 }
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/kernel/core_t2.c linux/arch/alpha/kernel/core_t2.c
--- v2.1.120/linux/arch/alpha/kernel/core_t2.c	Tue Aug 18 22:02:02 1998
+++ linux/arch/alpha/kernel/core_t2.c	Sun Sep  6 10:34:33 1998
@@ -148,8 +148,7 @@
 
 	cpu = smp_processor_id();
 
-	save_flags(flags);	/* avoid getting hit by machine check */
-	cli();
+	__save_and_cli(flags);	/* avoid getting hit by machine check */
 
 	DBG(("conf_read(addr=0x%lx, type1=%d)\n", addr, type1));
 
@@ -195,7 +194,7 @@
 	}
 	DBG(("conf_read(): finished\n"));
 
-	restore_flags(flags);
+	__restore_flags(flags);
 	return value;
 }
 
@@ -208,8 +207,7 @@
 
 	cpu = smp_processor_id();
 
-	save_flags(flags);	/* avoid getting hit by machine check */
-	cli();
+	__save_and_cli(flags);	/* avoid getting hit by machine check */
 
 #if 0
 	/* Reset status register to avoid losing errors.  */
@@ -246,18 +244,17 @@
 		mb();
 	}
 	DBG(("conf_write(): finished\n"));
-	restore_flags(flags);
+	__restore_flags(flags);
 }
 
-
 int
-t2_pcibios_read_config_byte (u8 bus, u8 device_fn, u8 where, u8 *value)
+t2_hose_read_config_byte (u8 bus, u8 device_fn, u8 where, u8 *value,
+			  struct linux_hose_info *hose)
 {
 	unsigned long addr = T2_CONF;
 	unsigned long pci_addr;
 	unsigned char type1;
 
-	*value = 0xff;
 	if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1))
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
@@ -267,15 +264,13 @@
 }
 
 int 
-t2_pcibios_read_config_word (u8 bus, u8 device_fn, u8 where, u16 *value)
+t2_hose_read_config_word (u8 bus, u8 device_fn, u8 where, u16 *value,
+			  struct linux_hose_info *hose)
 {
 	unsigned long addr = T2_CONF;
 	unsigned long pci_addr;
 	unsigned char type1;
 
-	*value = 0xffff;
-	if (where & 0x1)
-		return PCIBIOS_BAD_REGISTER_NUMBER;
 	if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1))
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
@@ -285,15 +280,13 @@
 }
 
 int 
-t2_pcibios_read_config_dword (u8 bus, u8 device_fn, u8 where, u32 *value)
+t2_hose_read_config_dword (u8 bus, u8 device_fn, u8 where, u32 *value,
+			   struct linux_hose_info *hose)
 {
 	unsigned long addr = T2_CONF;
 	unsigned long pci_addr;
 	unsigned char type1;
 
-	*value = 0xffffffff;
-	if (where & 0x3)
-		return PCIBIOS_BAD_REGISTER_NUMBER;
 	if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1))
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
@@ -303,7 +296,8 @@
 }
 
 int 
-t2_pcibios_write_config_byte (u8 bus, u8 device_fn, u8 where, u8 value)
+t2_hose_write_config_byte (u8 bus, u8 device_fn, u8 where, u8 value,
+			   struct linux_hose_info *hose)
 {
 	unsigned long addr = T2_CONF;
 	unsigned long pci_addr;
@@ -318,14 +312,13 @@
 }
 
 int
-t2_pcibios_write_config_word (u8 bus, u8 device_fn, u8 where, u16 value)
+t2_hose_write_config_word (u8 bus, u8 device_fn, u8 where, u16 value,
+			   struct linux_hose_info *hose)
 {
 	unsigned long addr = T2_CONF;
 	unsigned long pci_addr;
 	unsigned char type1;
 
-	if (where & 0x1)
-		return PCIBIOS_BAD_REGISTER_NUMBER;
 	if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1))
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
@@ -335,14 +328,13 @@
 }
 
 int 
-t2_pcibios_write_config_dword (u8 bus, u8 device_fn, u8 where, u32 value)
+t2_hose_write_config_dword (u8 bus, u8 device_fn, u8 where, u32 value,
+			    struct linux_hose_info *hose)
 {
 	unsigned long addr = T2_CONF;
 	unsigned long pci_addr;
 	unsigned char type1;
 
-	if (where & 0x3)
-		return PCIBIOS_BAD_REGISTER_NUMBER;
 	if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1))
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/kernel/core_tsunami.c linux/arch/alpha/kernel/core_tsunami.c
--- v2.1.120/linux/arch/alpha/kernel/core_tsunami.c	Tue Aug 18 22:02:02 1998
+++ linux/arch/alpha/kernel/core_tsunami.c	Sun Sep  6 10:34:33 1998
@@ -6,6 +6,8 @@
  * Based on code written by David A. Rusling (david.rusling@reo.mts.dec.com).
  *
  */
+
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/config.h>
 #include <linux/types.h>
@@ -15,6 +17,7 @@
 
 #include <asm/ptrace.h>
 #include <asm/system.h>
+#include <asm/pci.h>
 
 #define __EXTERN_INLINE inline
 #include <asm/io.h>
@@ -22,6 +25,7 @@
 #undef __EXTERN_INLINE
 
 #include "proto.h"
+#include "bios32.h"
 
 /*
  * NOTE: Herein lie back-to-back mb instructions.  They are magic. 
@@ -33,10 +37,10 @@
  * BIOS32-style PCI interface:
  */
 
-#ifdef DEBUG 
-# define DBG(args)	printk args
+#ifdef DEBUG_CONFIG
+# define DBG_CFG(args)	printk args
 #else
-# define DBG(args)
+# define DBG_CFG(args)
 #endif
 
 #define DEBUG_MCHECK
@@ -50,7 +54,7 @@
 static volatile unsigned int TSUNAMI_mcheck_expected[NR_CPUS];
 static volatile unsigned int TSUNAMI_mcheck_taken[NR_CPUS];
 static unsigned int TSUNAMI_jd[NR_CPUS];
-
+int TSUNAMI_bootcpu;
 
 /*
  * Given a bus, device, and function number, compute resulting
@@ -87,249 +91,205 @@
  */
 
 static int
-mk_conf_addr(u8 bus, u8 device_fn, u8 where, unsigned long *pci_addr,
-	     unsigned char *type1)
+mk_conf_addr(u8 bus, u8 device_fn, u8 where, struct linux_hose_info *hose,
+	     unsigned long *pci_addr, unsigned char *type1)
 {
 	unsigned long addr;
 
-	DBG(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x, "
-	     "pci_addr=0x%p, type1=0x%p)\n",
-	     bus, device_fn, where, pci_addr, type1));
-
-	if (bus == 0) {
-		*type1 = 0;
-	} else {
-		/* Type 1 configuration cycle.  */
-		*type1 = 1;
-	}
-	addr = (bus << 16) | (device_fn << 8) | (where);
+	if (!pci_probe_enabled)
+		return -1;
+
+	DBG_CFG(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x, "
+		 "pci_addr=0x%p, type1=0x%p)\n",
+		 bus, device_fn, where, pci_addr, type1));
+
+        *type1 = (bus != 0);
+
+        if (hose->pci_first_busno == bus)
+		bus = 0;
+
+        addr = (bus << 16) | (device_fn << 8) | where;
+	addr |= hose->pci_config_space;
+		
 	*pci_addr = addr;
-	DBG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr));
+	DBG_CFG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr));
 	return 0;
 }
 
 int 
-tsunami_pcibios_read_config_byte (u8 bus, u8 device_fn, u8 where, u8 *value)
+tsunami_hose_read_config_byte (u8 bus, u8 device_fn, u8 where, u8 *value,
+			       struct linux_hose_info *hose)
 {
 	unsigned long addr;
 	unsigned char type1;
 
-	*value = 0xff;
-	if (mk_conf_addr(bus, device_fn, where, &addr, &type1))
+	if (mk_conf_addr(bus, device_fn, where, hose, &addr, &type1))
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
-	*value = __kernel_ldbu(*(vucp)(addr+TSUNAMI_PCI0_CONF));
+	*value = __kernel_ldbu(*(vucp)addr);
 	return PCIBIOS_SUCCESSFUL;
 }
 
 int
-tsunami_pcibios_read_config_word (u8 bus, u8 device_fn, u8 where, u16 *value)
+tsunami_hose_read_config_word (u8 bus, u8 device_fn, u8 where, u16 *value,
+			       struct linux_hose_info *hose)
 {
 	unsigned long addr;
 	unsigned char type1;
 
-	*value = 0xffff;
-	if (where & 0x1)
-		return PCIBIOS_BAD_REGISTER_NUMBER;
-	if (mk_conf_addr(bus, device_fn, where, &addr, &type1))
+	if (mk_conf_addr(bus, device_fn, where, hose, &addr, &type1))
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
-	*value = __kernel_ldwu(*(vusp)(addr+TSUNAMI_PCI0_CONF));
+	*value = __kernel_ldwu(*(vusp)addr);
 	return PCIBIOS_SUCCESSFUL;
 }
 
 int
-tsunami_pcibios_read_config_dword (u8 bus, u8 device_fn, u8 where, u32 *value)
+tsunami_hose_read_config_dword (u8 bus, u8 device_fn, u8 where, u32 *value,
+				struct linux_hose_info *hose)
 {
 	unsigned long addr;
 	unsigned char type1;
 
-	*value = 0xffffffff;
-	if (where & 0x3)
-		return PCIBIOS_BAD_REGISTER_NUMBER;
-	if (mk_conf_addr(bus, device_fn, where, &addr, &type1))
+	if (mk_conf_addr(bus, device_fn, where, hose, &addr, &type1))
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
-	*value = *(vuip)(addr+TSUNAMI_PCI0_CONF);
+	*value = *(vuip)addr;
 	return PCIBIOS_SUCCESSFUL;
 }
 
 int 
-tsunami_pcibios_write_config_byte (u8 bus, u8 device_fn, u8 where, u8 value)
+tsunami_hose_write_config_byte (u8 bus, u8 device_fn, u8 where, u8 value,
+				struct linux_hose_info *hose)
 {
 	unsigned long addr;
 	unsigned char type1;
 
-	if (mk_conf_addr(bus, device_fn, where, &addr, &type1))
+	if (mk_conf_addr(bus, device_fn, where, hose, &addr, &type1))
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
-	__kernel_stb(value, *(vucp)(addr+TSUNAMI_PCI0_CONF));
+	__kernel_stb(value, *(vucp)addr);
 	return PCIBIOS_SUCCESSFUL;
 }
 
 int 
-tsunami_pcibios_write_config_word (u8 bus, u8 device_fn, u8 where, u16 value)
+tsunami_hose_write_config_word (u8 bus, u8 device_fn, u8 where, u16 value,
+				struct linux_hose_info *hose)
 {
 	unsigned long addr;
 	unsigned char type1;
 
-	if (where & 0x1)
-		return PCIBIOS_BAD_REGISTER_NUMBER;
-	if (mk_conf_addr(bus, device_fn, where, &addr, &type1))
+	if (mk_conf_addr(bus, device_fn, where, hose, &addr, &type1))
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
-	__kernel_stw(value, *(vusp)(addr+TSUNAMI_PCI0_CONF));
+	__kernel_stw(value, *(vusp)addr);
 	return PCIBIOS_SUCCESSFUL;
 }
 
 int
-tsunami_pcibios_write_config_dword (u8 bus, u8 device_fn, u8 where, u32 value)
+tsunami_hose_write_config_dword (u8 bus, u8 device_fn, u8 where, u32 value,
+				 struct linux_hose_info *hose)
 {
 	unsigned long addr;
 	unsigned char type1;
 
-	if (where & 0x3)
-		return PCIBIOS_BAD_REGISTER_NUMBER;
-	if (mk_conf_addr(bus, device_fn, where, &addr, &type1))
+	if (mk_conf_addr(bus, device_fn, where, hose, &addr, &type1))
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
-	*(vuip)(addr+TSUNAMI_PCI0_CONF) = value;
+	*(vuip)addr = value;
 	return PCIBIOS_SUCCESSFUL;
 }
 
-void __init
-tsunami_init_arch(unsigned long *mem_start, unsigned long *mem_end)
+#ifdef NXM_MACHINE_CHECKS_ON_TSUNAMI
+static long
+tsunami_probe_read(volatile unsigned long *vaddr)
 {
-        unsigned long tsunami_err;
-	unsigned int i;
+	long dont_care, probe_result;
+	int cpu = smp_processor_id();
+	int s = swpipl(6);	/* Block everything but machine checks. */
+
+	TSUNAMI_mcheck_taken[cpu] = 0;
+	TSUNAMI_mcheck_expected[cpu] = 1;
+	dont_care = *vaddr;
+	draina();
+	TSUNAMI_mcheck_expected[cpu] = 0;
+	probe_result = !TSUNAMI_mcheck_taken[cpu];
+	TSUNAMI_mcheck_taken[cpu] = 0;
+	setipl(s);
 
-#if 0
-	printk("tsunami_init: CChip registers:\n");
-	printk("CSR_CSC 0x%lx\n", *(vulp)TSUNAMI_CSR_CSC);
-	printk("CSR_MTR 0x%lx\n", *(vulp)TSUNAMI_CSR_MTR);
-	printk("CSR_MISC 0x%lx\n", *(vulp)TSUNAMI_CSR_MISC);
-	printk("CSR_DIM0 0x%lx\n", *(vulp)TSUNAMI_CSR_DIM0);
-	printk("CSR_DIM1 0x%lx\n", *(vulp)TSUNAMI_CSR_DIM1);
-	printk("CSR_DIR0 0x%lx\n", *(vulp)TSUNAMI_CSR_DIR0);
-	printk("CSR_DIR1 0x%lx\n", *(vulp)TSUNAMI_CSR_DIR1);
-	printk("CSR_DRIR 0x%lx\n", *(vulp)TSUNAMI_CSR_DRIR);
-
-	printk("tsunami_init: DChip registers:\n");
-	printk("CSR_DSC 0x%lx\n", *(vulp)TSUNAMI_CSR_DSC);
-	printk("CSR_STR 0x%lx\n", *(vulp)TSUNAMI_CSR_STR);
-	printk("CSR_DREV 0x%lx\n", *(vulp)TSUNAMI_CSR_DREV);
-
-	printk("tsunami_init: PChip registers:\n");
-	printk("PCHIP0_WSBA0 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_WSBA0);
-	printk("PCHIP0_WSBA1 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_WSBA1);
-	printk("PCHIP0_WSBA2 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_WSBA2);
-	printk("PCHIP0_WSBA3 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_WSBA3);
-	printk("PCHIP0_WSM0 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_WSM0);
-	printk("PCHIP0_WSM1 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_WSM1);
-	printk("PCHIP0_WSM2 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_WSM2);
-	printk("PCHIP0_WSM3 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_WSM3);
-	printk("PCHIP0_TBA0 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_TBA0);
-	printk("PCHIP0_TBA1 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_TBA1);
-	printk("PCHIP0_TBA2 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_TBA2);
-	printk("PCHIP0_TBA3 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_TBA3);
-	printk("PCHIP0_PCTL 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_PCTL);
-	printk("PCHIP0_PLAT 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_PLAT);
-	printk("PCHIP0_PERROR 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_PERROR);
-	printk("PCHIP0_PERRMASK 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_PERRMASK);
-#endif
+	printk("dont_care == 0x%lx\n", dont_care);
+
+	return probe_result;
+}
 
-	for (i = 0; i < NR_CPUS; i++) {
-		TSUNAMI_mcheck_expected[i] = 0;
-		TSUNAMI_mcheck_taken[i] = 0;
+static long
+tsunami_probe_write(volatile unsigned long *vaddr)
+{
+	long true_contents, probe_result = 1;
+
+	TSUNAMI_cchip->misc.csr |= (1L << 28); /* clear NXM... */
+	true_contents = *vaddr;
+	*vaddr = 0;
+	draina();
+	if (TSUNAMI_cchip->misc.csr & (1L << 28)) {
+		int source = (TSUNAMI_cchip->misc.csr >> 29) & 7;
+		TSUNAMI_cchip->misc.csr |= (1L << 28); /* ...and unlock NXS. */
+		probe_result = 0;
+		printk("tsunami_probe_write: unit %d at 0x%016lx\n", source,
+		       (unsigned long)vaddr);
 	}
+	if (probe_result)
+		*vaddr = true_contents;
+	return probe_result;
+}
+#else
+#define tsunami_probe_read(ADDR) 1
+#endif /* NXM_MACHINE_CHECKS_ON_TSUNAMI */
 
-#ifdef NOT_YET
-        /* 
-	 * Set up error reporting. Make sure CPU_PE is OFF in the mask.
-	 */
-	tsunami_err = *(vulp)TSUNAMI_PCHIP0_PERRMASK;
-	tsunami_err &= ~20;   
-	*(vulp)TSUNAMI_PCHIP0_PERRMASK = tsunami_err;
-	mb();
-	tsunami_err = *(vulp)TSUNAMI_PCHIP0_PERRMASK;
+#define FN __FUNCTION__
 
-	tsunami_err = *(vulp)TSUNAMI_PCHIP0_PERROR ;
-	tsunami_err |= 0x40;   /* master/target abort */
-	*(vulp)TSUNAMI_PCHIP0_PERROR = tsunami_err ;
-	mb() ;
-	tsunami_err = *(vulp)TSUNAMI_PCHIP0_PERROR ;
-#endif /* NOT_YET */
+static void __init
+tsunami_init_one_pchip(tsunami_pchip *pchip, int index,
+		       unsigned long *mem_start)
+{
+	struct linux_hose_info *hose;
+	int i;
+
+	if (tsunami_probe_read(&pchip->pctl.csr) == 0)
+		return;
+
+	hose = (struct linux_hose_info *)*mem_start;
+	*mem_start = (unsigned long)(hose + 1);
+	memset(hose, 0, sizeof(*hose));
+
+	*hose_tail = hose;
+	hose_tail = &hose->next;
+
+	hose->pci_io_space = TSUNAMI_IO(index);
+	hose->pci_mem_space = TSUNAMI_MEM(index);
+	hose->pci_config_space = TSUNAMI_CONF(index);
+	hose->pci_sparse_space = 0;
+	hose->pci_hose_index = index;
 
 	switch (alpha_use_srm_setup)
 	{
 	default:
 #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM_SETUP)
-		/* Check window 0 for enabled and mapped to 0.  */
-		if (((*(vulp)TSUNAMI_PCHIP0_WSBA0 & 3) == 1)
-		    && (*(vulp)TSUNAMI_PCHIP0_TBA0 == 0)
-		    && ((*(vulp)TSUNAMI_PCHIP0_WSM0 & 0xfff00000U) > 0x0ff00000U)) {
-			TSUNAMI_DMA_WIN_BASE = *(vulp)TSUNAMI_PCHIP0_WSBA0 & 0xfff00000U;
-			TSUNAMI_DMA_WIN_SIZE = *(vulp)TSUNAMI_PCHIP0_WSM0 & 0xfff00000U;
-			TSUNAMI_DMA_WIN_SIZE += 0x00100000U;
-#if 1
-			printk("tsunami_init: using Window 0 settings\n");
-			printk("tsunami_init: BASE 0x%lx MASK 0x%lx TRANS 0x%lx\n",
-			       *(vulp)TSUNAMI_PCHIP0_WSBA0,
-			       *(vulp)TSUNAMI_PCHIP0_WSM0,
-			       *(vulp)TSUNAMI_PCHIP0_TBA0);
-#endif
-			break;
-		}
-
-		/* Check window 1 for enabled and mapped to 0.  */
-		if (((*(vulp)TSUNAMI_PCHIP0_WSBA1 & 3) == 1)
-		    && (*(vulp)TSUNAMI_PCHIP0_TBA1 == 0)
-		    && ((*(vulp)TSUNAMI_PCHIP0_WSM1 & 0xfff00000U) > 0x0ff00000U)) {
-			TSUNAMI_DMA_WIN_BASE = *(vulp)TSUNAMI_PCHIP0_WSBA1 & 0xfff00000U;
-			TSUNAMI_DMA_WIN_SIZE = *(vulp)TSUNAMI_PCHIP0_WSM1 & 0xfff00000U;
-			TSUNAMI_DMA_WIN_SIZE += 0x00100000U;
+		for (i = 0; i < 4; ++i) {
+			if ((pchip->wsba[i].csr & 3) == 1
+			    && pchip->tba[i].csr == 0
+			    && (pchip->wsm[i].csr & 0xfff00000) > 0x0ff00000) {
+				TSUNAMI_DMA_WIN_BASE = pchip->wsba[i].csr & 0xfff00000;
+				TSUNAMI_DMA_WIN_SIZE = pchip->wsm[i].csr & 0xfff00000;
+				TSUNAMI_DMA_WIN_SIZE += 0x00100000;
 #if 1
-			printk("tsunami_init: using Window 1 settings\n");
-			printk("tsunami_init: BASE 0x%lx MASK 0x%lx TRANS 0x%lx\n",
-			       *(vulp)TSUNAMI_PCHIP0_WSBA1,
-			       *(vulp)TSUNAMI_PCHIP0_WSM1,
-			       *(vulp)TSUNAMI_PCHIP0_TBA1);
+				printk("%s: using Window %d settings\n", FN, i);
+				printk("%s: BASE 0x%lx MASK 0x%lx TRANS 0x%lx\n",
+				       FN, pchip->wsba[i].csr, pchip->wsm[i].csr,
+				       pchip->tba[i].csr);
 #endif
-			break;
-		}
-
-		/* Check window 2 for enabled and mapped to 0.  */
-		if (((*(vulp)TSUNAMI_PCHIP0_WSBA2 & 3) == 1)
-		    && (*(vulp)TSUNAMI_PCHIP0_TBA2 == 0)
-		    && ((*(vulp)TSUNAMI_PCHIP0_WSM2 & 0xfff00000U) > 0x0ff00000U)) {
-			TSUNAMI_DMA_WIN_BASE = *(vulp)TSUNAMI_PCHIP0_WSBA2 & 0xfff00000U;
-			TSUNAMI_DMA_WIN_SIZE = *(vulp)TSUNAMI_PCHIP0_WSM2 & 0xfff00000U;
-			TSUNAMI_DMA_WIN_SIZE += 0x00100000U;
-#if 1
-			printk("tsunami_init: using Window 2 settings\n");
-			printk("tsunami_init: BASE 0x%lx MASK 0x%lx TRANS 0x%lx\n",
-			       *(vulp)TSUNAMI_PCHIP0_WSBA2,
-			       *(vulp)TSUNAMI_PCHIP0_WSM2,
-			       *(vulp)TSUNAMI_PCHIP0_TBA2);
-#endif
-			break;
-		}
-
-		/* Check window 3 for enabled and mapped to 0.  */
-		if (((*(vulp)TSUNAMI_PCHIP0_WSBA3 & 3) == 1)
-		    && (*(vulp)TSUNAMI_PCHIP0_TBA3 == 0)
-		    && ((*(vulp)TSUNAMI_PCHIP0_WSM3 & 0xfff00000U) > 0x0ff00000U)) {
-			TSUNAMI_DMA_WIN_BASE = *(vulp)TSUNAMI_PCHIP0_WSBA3 & 0xfff00000U;
-			TSUNAMI_DMA_WIN_SIZE = *(vulp)TSUNAMI_PCHIP0_WSM3 & 0xfff00000U;
-			TSUNAMI_DMA_WIN_SIZE += 0x00100000U;
-#if 1
-			printk("tsunami_init: using Window 3 settings\n");
-			printk("tsunami_init: BASE 0x%lx MASK 0x%lx TRANS 0x%lx\n",
-			       *(vulp)TSUNAMI_PCHIP0_WSBA3,
-			       *(vulp)TSUNAMI_PCHIP0_WSM3,
-			       *(vulp)TSUNAMI_PCHIP0_TBA3);
-#endif
-			break;
+				goto found;
+			}
 		}
 
 		/* Otherwise, we must use our defaults.  */
@@ -345,28 +305,80 @@
 		 * Window 0 goes at 1 GB and is 1 GB large.
 		 */
 
-		*(vulp)TSUNAMI_PCHIP0_WSBA0
-			= 1L | (TSUNAMI_DMA_WIN_BASE_DEFAULT & 0xfff00000U);
-		*(vulp)TSUNAMI_PCHIP0_WSM0
-			= (TSUNAMI_DMA_WIN_SIZE_DEFAULT - 1) & 0xfff00000UL;
-		*(vulp)TSUNAMI_PCHIP0_TBA0 = 0UL;
-
-		*(vulp)TSUNAMI_PCHIP0_WSBA1 = 0UL;
-		*(vulp)TSUNAMI_PCHIP0_WSBA2 = 0UL;
-		*(vulp)TSUNAMI_PCHIP0_WSBA3 = 0UL;
+		pchip->wsba[0].csr = 1L | (TSUNAMI_DMA_WIN_BASE_DEFAULT & 0xfff00000U);
+		pchip->wsm[0].csr = (TSUNAMI_DMA_WIN_SIZE_DEFAULT - 1) & 0xfff00000UL;
+		pchip->tba[0].csr = 0;
+
+		pchip->wsba[1].csr = 0;
+		pchip->wsba[2].csr = 0;
+		pchip->wsba[3].csr = 0;
 		mb();
 	}
+found:;
+}
+
+void __init
+tsunami_init_arch(unsigned long *mem_start, unsigned long *mem_end)
+{
+#ifdef NXM_MACHINE_CHECKS_ON_TSUNAMI
+	extern asmlinkage void entInt(void);
+        unsigned long tmp;
+	
+	/* Ho hum.. init_arch is called before init_IRQ, but we need to be
+	   able to handle machine checks.  So install the handler now.  */
+	wrent(entInt, 0);
+
+	/* NXMs just don't matter to Tsunami--unless they make it
+	   choke completely. */
+	tmp = (unsigned long)(TSUNAMI_cchip - 1);
+	printk("%s: probing bogus address:  0x%016lx\n", FN, bogus_addr);
+	printk("\tprobe %s\n",
+	       tsunami_probe_write((unsigned long *)bogus_addr)
+	       ? "succeeded" : "failed");
+#endif /* NXM_MACHINE_CHECKS_ON_TSUNAMI */
+
+#if 0
+	printk("%s: CChip registers:\n", FN);
+	printk("%s: CSR_CSC 0x%lx\n", FN, TSUNAMI_cchip->csc.csr);
+	printk("%s: CSR_MTR 0x%lx\n", FN, TSUNAMI_cchip.mtr.csr);
+	printk("%s: CSR_MISC 0x%lx\n", FN, TSUNAMI_cchip->misc.csr);
+	printk("%s: CSR_DIM0 0x%lx\n", FN, TSUNAMI_cchip->dim0.csr);
+	printk("%s: CSR_DIM1 0x%lx\n", FN, TSUNAMI_cchip->dim1.csr);
+	printk("%s: CSR_DIR0 0x%lx\n", FN, TSUNAMI_cchip->dir0.csr);
+	printk("%s: CSR_DIR1 0x%lx\n", FN, TSUNAMI_cchip->dir1.csr);
+	printk("%s: CSR_DRIR 0x%lx\n", FN, TSUNAMI_cchip->drir.csr);
+
+	printk("%s: DChip registers:\n");
+	printk("%s: CSR_DSC 0x%lx\n", FN, TSUNAMI_dchip->dsc.csr);
+	printk("%s: CSR_STR 0x%lx\n", FN, TSUNAMI_dchip->str.csr);
+	printk("%s: CSR_DREV 0x%lx\n", FN, TSUNAMI_dchip->drev.csr);
+#endif
+
+	/* Align memory to cache line; we'll be allocating from it.  */
+	*mem_start = (*mem_start | 31) + 1;
+
+	/* Find how many hoses we have, and initialize them.  */
+	tsunami_init_one_pchip(TSUNAMI_pchip0, 0, mem_start);
+	tsunami_init_one_pchip(TSUNAMI_pchip1, 1, mem_start);
+}
+
+static inline void
+tsunami_pci_clr_err_1(tsunami_pchip *pchip, int cpu)
+{
+	TSUNAMI_jd[cpu] = pchip->perror.csr;
+	DBG_MCK(("TSUNAMI_pci_clr_err: PERROR after read 0x%x\n",
+		 TSUNAMI_jd[cpu]));
+	pchip->perror.csr = 0x040;
+	mb();
+	TSUNAMI_jd[cpu] = pchip->perror.csr;
 }
 
 static int
 tsunami_pci_clr_err(void)
 {
-	unsigned int cpu = smp_processor_id();
-
-	TSUNAMI_jd[cpu] = *((vulp)TSUNAMI_PCHIP0_PERROR);
-	DBG(("TSUNAMI_pci_clr_err: PERROR after read 0x%x\n",TSUNAMI_jd[cpu]));
-	*((vulp)TSUNAMI_PCHIP0_PERROR) = 0x040; mb();
-	TSUNAMI_jd[cpu] = *((vulp)TSUNAMI_PCHIP0_PERROR);
+	int cpu = smp_processor_id();
+	tsunami_pci_clr_err_1(TSUNAMI_pchip0, cpu);
+	tsunami_pci_clr_err_1(TSUNAMI_pchip1, cpu);
 	return 0;
 }
 
@@ -374,13 +386,14 @@
 tsunami_machine_check(unsigned long vector, unsigned long la_ptr,
 		      struct pt_regs * regs)
 {
-#if 1
+#if 0
         printk("TSUNAMI machine check ignored\n") ;
 #else
 	struct el_common *mchk_header;
 	struct el_TSUNAMI_sysdata_mcheck *mchk_sysdata;
 	unsigned int cpu = smp_processor_id();
 
+	mb();
 	mchk_header = (struct el_common *)la_ptr;
 
 	mchk_sysdata = (struct el_TSUNAMI_sysdata_mcheck *)
@@ -414,7 +427,7 @@
 	mb();
 	mb();  /* magic */
 	if (TSUNAMI_mcheck_expected[cpu]) {
-		DBG(("TSUNAMI machine check expected\n"));
+		DBG_MCK(("TSUNAMI machine check expected\n"));
 		TSUNAMI_mcheck_expected[cpu] = 0;
 		TSUNAMI_mcheck_taken[cpu] = 1;
 		mb();
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S
--- v2.1.120/linux/arch/alpha/kernel/entry.S	Tue Aug 18 22:02:02 1998
+++ linux/arch/alpha/kernel/entry.S	Tue Sep  8 23:20:41 1998
@@ -4,7 +4,6 @@
  * kernel entry-points
  */
 
-#include <linux/config.h>
 #include <asm/system.h>
 
 #define halt	.long PAL_halt
@@ -51,56 +50,7 @@
  * JRP - Save regs 16-18 in a special area of the stack, so that
  * the palcode-provided values are available to the signal handler.
  */
-#if defined(CONFIG_ALPHA_TSUNAMI)
-/* TSUNAMI has no HAE register to save/restore */
-#define SAVE_ALL			\
-	subq	$30,184,$30;		\
-	stq	$0,0($30);		\
-	stq	$1,8($30);		\
-	stq	$2,16($30);		\
-	stq	$3,24($30);		\
-	stq	$4,32($30);		\
-	stq	$5,40($30);		\
-	stq	$6,48($30);		\
-	stq	$7,56($30);		\
-	stq	$8,64($30);		\
-	stq	$19,72($30);		\
-	stq	$20,80($30);		\
-	stq	$21,88($30);		\
-	stq	$22,96($30);		\
-	stq	$23,104($30);		\
-	stq	$24,112($30);		\
-	stq	$25,120($30);		\
-	stq	$26,128($30);		\
-	stq	$27,136($30);		\
-	stq	$28,144($30);		\
-	stq	$16,160($30);		\
-	stq	$17,168($30);		\
-	stq	$18,176($30)
 
-#define RESTORE_ALL			\
-	ldq	$0,0($30);		\
-	ldq	$1,8($30);		\
-	ldq	$2,16($30);		\
-	ldq	$3,24($30);		\
-	ldq	$4,32($30);		\
-	ldq	$5,40($30);		\
-	ldq	$6,48($30);		\
-	ldq	$7,56($30);		\
-	ldq	$8,64($30);		\
-	ldq	$19,72($30);		\
-	ldq	$20,80($30);		\
-	ldq	$21,88($30);		\
-	ldq	$22,96($30);		\
-	ldq	$23,104($30);		\
-	ldq	$24,112($30);		\
-	ldq	$25,120($30);		\
-	ldq	$26,128($30);		\
-	ldq	$27,136($30);		\
-	ldq	$28,144($30);		\
-	addq	$30,184,$30
-
-#else /* TSUNAMI */
 #define SAVE_ALL			\
 	subq	$30,184,$30;		\
 	stq	$0,0($30);		\
@@ -166,8 +116,6 @@
 	ldq	$28,144($30);		\
 	addq	$30,184,$30
 
-#endif /* TSUNAMI */
-
 .text
 .set noat
 #if defined(__linux__) && !defined(__ELF__)
@@ -181,8 +129,8 @@
 	SAVE_ALL
 	lda	$8,0x3fff
 	bic	$30,$8,$8
-	jsr	$26,do_entInt
-	br	$31,ret_from_sys_call
+	lda	$26,ret_from_sys_call
+	jsr	$31,do_entInt
 .end entInt
 
 .align 3
@@ -224,11 +172,8 @@
 	SAVE_ALL
 	lda	$8,0x3fff
 	bic	$30,$8,$8
-	/* How much of a win is this clockwise?  We are, after all, messing
-	   up the call/return prefetch stack.  -- rth */
-	lda	$27,do_entArith
 	lda	$26,ret_from_sys_call
-	jsr	$31,($27),do_entArith
+	jsr	$31,do_entArith
 .end entArith
 
 .align 3
@@ -238,9 +183,8 @@
 	SAVE_ALL
 	lda	$8,0x3fff
 	bic	$30,$8,$8
-	lda	$27,do_entIF
 	lda	$26,ret_from_sys_call
-	jsr	$31,($27),do_entIF
+	jsr	$31,do_entIF
 .end entIF
 
 /*
@@ -373,7 +317,7 @@
 	stt $f29,296($30)
 	stt $f30,304($30)
 	stt $f0,312($30)	# save fpcr in slot of $f31
-	ldt $f0,64($30)		# don't let "do_switch_stack" change any fp state.
+	ldt $f0,64($30)		# dont let "do_switch_stack" change fp state.
 	ret $31,($1),1
 .end do_switch_stack
 
@@ -744,8 +688,8 @@
 .ent ret_from_smpfork
 ret_from_smpfork:
 	.set at
+	mb	/* Make the changed data visible before the freed lock. */
 	stq	$31,scheduler_lock	
-	mb	/* ?????????????????? */
 	br	ret_from_sys_call
 	.set noat
 .end ret_from_smpfork
@@ -834,7 +778,7 @@
 	.quad sys_lseek
 	.quad sys_getxpid			/* 20 */
 	.quad osf_mount
-	.quad osf_umount
+	.quad sys_umount
 	.quad sys_setuid
 	.quad sys_getxuid
 	.quad alpha_ni_syscall			/* 25 */
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/kernel/irq.c linux/arch/alpha/kernel/irq.c
--- v2.1.120/linux/arch/alpha/kernel/irq.c	Tue Aug 18 22:02:02 1998
+++ linux/arch/alpha/kernel/irq.c	Sun Sep  6 10:34:33 1998
@@ -20,6 +20,7 @@
 #include <linux/malloc.h>
 #include <linux/random.h>
 #include <linux/init.h>
+#include <linux/delay.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -35,7 +36,7 @@
 
 unsigned int local_irq_count[NR_CPUS];
 unsigned int local_bh_count[NR_CPUS];
-
+unsigned long hardirq_no[NR_CPUS];
 
 #define RTC_IRQ    8
 #ifdef CONFIG_RTC
@@ -100,7 +101,7 @@
 #elif defined(CONFIG_ALPHA_PYXIS)
 # define IACK_SC	PYXIS_IACK_SC
 #elif defined(CONFIG_ALPHA_TSUNAMI)
-# define IACK_SC	TSUNAMI_PCI0_IACK_SC
+# define IACK_SC	TSUNAMI_IACK_SC
 #else
   /* This is bogus but necessary to get it to compile on all platforms. */
 # define IACK_SC	1L
@@ -159,13 +160,9 @@
 srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
 {
 	int irq, ack;
-	unsigned long flags;
 
-	__save_and_cli(flags);
 	ack = irq = (vector - 0x800) >> 4;
-
 	handle_irq(irq, ack, regs);
-	__restore_flags(flags);
 }
 
 
@@ -338,7 +335,7 @@
 
 #ifdef __SMP__
 /* Who has global_irq_lock. */
-unsigned char global_irq_holder = NO_PROC_ID;
+int global_irq_holder = NO_PROC_ID;
 
 /* This protects IRQ's. */
 spinlock_t global_irq_lock = SPIN_LOCK_UNLOCKED;
@@ -350,74 +347,66 @@
 atomic_t global_bh_lock = ATOMIC_INIT(0);
 atomic_t global_bh_count = ATOMIC_INIT(0);
 
-static unsigned long previous_irqholder = NO_PROC_ID;
+static void *previous_irqholder = NULL;
 
-#undef INIT_STUCK
-#define INIT_STUCK 100000000
+#define MAXCOUNT 100000000
 
-#undef STUCK
-#define STUCK						\
-  if (!--stuck) {					\
-    printk("wait_on_irq CPU#%d stuck at %08lx, "	\
-	   "waiting for %08lx (local=%d, global=%d)\n",	\
-	   cpu, where, previous_irqholder, local_count,	\
-	   atomic_read(&global_irq_count));		\
-    stuck = INIT_STUCK;					\
-  }
+static void show(char * str, void *where);
 
 static inline void
-wait_on_irq(int cpu, unsigned long where)
+wait_on_irq(int cpu, void *where)
 {
-	int stuck = INIT_STUCK;
-	int local_count = local_irq_count[cpu];
+	int count = MAXCOUNT;
+
+	for (;;) {
 
-	/* Are we the only one in an interrupt context? */
-	while (local_count != atomic_read(&global_irq_count)) {
 		/*
-		 * No such luck. Now we need to release the lock,
-		 * _and_ release our interrupt context, because
-		 * otherwise we'd have dead-locks and live-locks
-		 * and other fun things.
+		 * Wait until all interrupts are gone. Wait
+		 * for bottom half handlers unless we're
+		 * already executing in one..
 		 */
-		atomic_sub(local_count, &global_irq_count);
+		if (!atomic_read(&global_irq_count)) {
+			if (local_bh_count[cpu] ||
+			    !atomic_read(&global_bh_count))
+				break;
+		}
+
+		/* Duh, we have to loop. Release the lock to avoid deadlocks */
 		spin_unlock(&global_irq_lock);
+		mb();
 
-		/*
-		 * Wait for everybody else to go away and release
-		 * their things before trying to get the lock again.
-		 */
 		for (;;) {
-			STUCK;
+			if (!--count) {
+				show("wait_on_irq", where);
+				count = MAXCOUNT;
+			}
+			__sti();
+#if 0
+			SYNC_OTHER_CORES(cpu);
+#else
+			udelay(cpu+1);
+#endif
+			__cli();
+
 			if (atomic_read(&global_irq_count))
 				continue;
 			if (global_irq_lock.lock)
 				continue;
+			if (!local_bh_count[cpu] &&
+			    atomic_read(&global_bh_count))
+				continue;
 			if (spin_trylock(&global_irq_lock))
 				break;
 		}
-		atomic_add(local_count, &global_irq_count);
 	}
 }
 
-#undef INIT_STUCK
-#define INIT_STUCK 10000000
-
-#undef STUCK
-#define STUCK							\
-  if (!--stuck) {						\
-    printk("get_irqlock stuck at %08lx, waiting for %08lx\n",	\
-	   where, previous_irqholder);				\
-    stuck = INIT_STUCK;						\
-  }
-
 static inline void
-get_irqlock(int cpu, unsigned long where)
+get_irqlock(int cpu, void* where)
 {
-	int stuck = INIT_STUCK;
-
 	if (!spin_trylock(&global_irq_lock)) {
 		/* do we already hold the lock? */
-		if ((unsigned char) cpu == global_irq_holder) {
+		if (cpu == global_irq_holder) {
 #if 0
 			printk("get_irqlock: already held at %08lx\n",
 			       previous_irqholder);
@@ -425,12 +414,7 @@
 			return;
 		}
 		/* Uhhuh.. Somebody else got it. Wait.. */
-		do {
-			do {
-				STUCK;
-				barrier();
-			} while (global_irq_lock.lock);
-		} while (!spin_trylock(&global_irq_lock));
+		spin_lock(&global_irq_lock);
 	}
 	/*
 	 * Ok, we got the lock bit.
@@ -443,6 +427,8 @@
 	/*
 	 * Finally.
 	 */
+	global_irq_lock.task = current;
+	global_irq_lock.previous = where;
 	global_irq_holder = cpu;
 	previous_irqholder = where;
 }
@@ -450,14 +436,15 @@
 void
 __global_cli(void)
 {
-	int cpu = smp_processor_id();
-	unsigned long where;
+	int cpu;
+	void *where = __builtin_return_address(0);
 
-        __asm__("mov $26, %0" : "=r" (where));
-	__cli();
-
-	if (!local_irq_count[cpu])
-		get_irqlock(smp_processor_id(), where);
+	/*
+	 * Maximize ipl.  If ipl was previously 0 and if this thread
+	 * is not in an irq, then take global_irq_lock.
+	 */
+	if ((swpipl(7) == 0) && !local_irq_count[cpu = smp_processor_id()])
+		get_irqlock(cpu, where);
 }
 
 void
@@ -465,38 +452,66 @@
 {
         int cpu = smp_processor_id();
 
-        if (!local_irq_count[cpu])
-		release_irqlock(smp_processor_id());
-
+        if (!local_irq_count[cpu]) {
+		release_irqlock(cpu);
+	}
 	__sti();
 }
 
-#if 0
+/*
+ * SMP flags value to restore to:
+ * 0 - global cli
+ * 1 - global sti
+ * 2 - local cli
+ * 3 - local sti
+ */
 unsigned long
 __global_save_flags(void)
 {
-	return global_irq_holder == (unsigned char) smp_processor_id();
+        int retval;
+        int local_enabled;
+        unsigned long flags;
+	int cpu = smp_processor_id();
+
+        __save_flags(flags);
+        local_enabled = (!(flags & 7));
+        /* default to local */
+        retval = 2 + local_enabled;
+
+        /* Check for global flags if we're not in an interrupt.  */
+        if (!local_irq_count[cpu]) {
+                if (local_enabled)
+                        retval = 1;
+                if (global_irq_holder == cpu)
+                        retval = 0;
+	}
+	return retval;
 }
-#endif
 
 void
 __global_restore_flags(unsigned long flags)
 {
-	if (flags & 1) {
-		__global_cli();
-	} else {
-		/* release_irqlock() */
-		if (global_irq_holder == smp_processor_id()) {
-			global_irq_holder = NO_PROC_ID;
-			spin_unlock(&global_irq_lock);
-		}
-		if (!(flags & 2))
-			__sti();
-	}
+        switch (flags) {
+        case 0:
+                __global_cli();
+                break;
+        case 1:
+                __global_sti();
+                break;
+        case 2:
+                __cli();
+                break;
+        case 3:
+                __sti();
+                break;
+        default:
+                printk("global_restore_flags: %08lx (%p)\n",
+                        flags, __builtin_return_address(0));
+        }
 }
 
 #undef INIT_STUCK
-#define INIT_STUCK 200000000
+#define INIT_STUCK (1<<26)
 
 #undef STUCK
 #define STUCK							\
@@ -516,10 +531,10 @@
 #endif
 	int stuck = INIT_STUCK;
 
-	hardirq_enter(cpu);
+	hardirq_enter(cpu, irq);
 	barrier();
 	while (global_irq_lock.lock) {
-		if ((unsigned char) cpu == global_irq_holder) {
+		if (cpu == global_irq_holder) {
 			int globl_locked = global_irq_lock.lock;
 			int globl_icount = atomic_read(&global_irq_count);
 			int local_count = local_irq_count[cpu];
@@ -529,11 +544,7 @@
 			   printk() as printk() could end up changing
 			   them...  */
 
-#if 0
-			printk("CPU[%d]: BAD! Local IRQ's enabled,"
-			       " global disabled interrupt\n", cpu);
-#endif
-			printk("CPU[%d]: where [%08lx] glocked[%d] gicnt[%d]"
+			printk("CPU[%d]: where [%p] glocked[%d] gicnt[%d]"
 			       " licnt[%d]\n",
 			       cpu, previous_irqholder, globl_locked,
 			       globl_icount, local_count);
@@ -552,12 +563,12 @@
 void
 irq_exit(int cpu, int irq)
 {
-	hardirq_exit(cpu);
+	hardirq_exit(cpu, irq);
 	release_irqlock(cpu);
 }
 
 static void
-show(char * str)
+show(char * str, void *where)
 {
 #if 0
 	int i;
@@ -565,10 +576,16 @@
 #endif
         int cpu = smp_processor_id();
 
-        printk("\n%s, CPU %d:\n", str, cpu);
-        printk("irq:  %d [%d %d]\n",
-	       atomic_read(&global_irq_count), local_irq_count[0],
-	       local_irq_count[1]);
+	int global_count = atomic_read(&global_irq_count);
+        int local_count0 = local_irq_count[0];
+        int local_count1 = local_irq_count[1];
+        long hardirq_no0 = hardirq_no[0];
+        long hardirq_no1 = hardirq_no[1];
+
+        printk("\n%s, CPU %d: %p\n", str, cpu, where);
+        printk("irq:  %d [%d(0x%016lx) %d(0x%016lx)]\n", global_count,
+               local_count0, hardirq_no0, local_count1, hardirq_no1);
+
         printk("bh:   %d [%d %d]\n",
 	       atomic_read(&global_bh_count), local_bh_count[0],
 	       local_bh_count[1]);
@@ -584,15 +601,13 @@
 #endif
 }
         
-#define MAXCOUNT 100000000
-
 static inline void
 wait_on_bh(void)
 {
 	int count = MAXCOUNT;
         do {
 		if (!--count) {
-			show("wait_on_bh");
+			show("wait_on_bh", 0);
                         count = ~0;
                 }
                 /* nothing .. wait for the other bh's to go away */
@@ -618,20 +633,36 @@
         }
 }
 
-/* There has to be a better way. */
+/*
+ * From its use, I infer that synchronize_irq() stalls a thread until
+ * the effects of a command to an external device are known to have
+ * taken hold.  Typically, the command is to stop sending interrupts.
+ * The strategy here is wait until there is at most one processor
+ * (this one) in an irq.  The memory barrier serializes the write to
+ * the device and the subsequent accesses of global_irq_count.
+ * --jmartin
+ */
+#define DEBUG_SYNCHRONIZE_IRQ 0
+
 void
 synchronize_irq(void)
 {
 	int cpu = smp_processor_id();
-	int local_count = local_irq_count[cpu];
-
-	if (local_count != atomic_read(&global_irq_count)) {
-		unsigned long flags;
-
-		/* An infamously unpopular approach. */
-		save_and_cli(flags);
-		restore_flags(flags);
-	}
+	int local_count;
+	int global_count;
+	int countdown = 1<<24;
+	void *where = __builtin_return_address(0);
+
+	mb();
+	do {
+		local_count = local_irq_count[cpu];
+		global_count = atomic_read(&global_irq_count);
+		if (DEBUG_SYNCHRONIZE_IRQ && (--countdown == 0)) {
+			printk("%d:%d/%d\n", cpu, local_count, global_count);
+			show("synchronize_irq", where);
+			break;
+		}
+	} while (global_count != local_count);
 }
 
 #else /* !__SMP__ */
@@ -687,6 +718,26 @@
 		return;
 	}
 
+#if 0
+	/* A useful bit of code to find out if an interrupt is going wild.  */
+	{
+	  static unsigned int last_msg, last_cc;
+	  static int last_irq, count;
+	  unsigned int cc;
+
+	  __asm __volatile("rpcc %0" : "=r"(cc));
+	  ++count;
+	  if (cc - last_msg > 150000000 || irq != last_irq) {
+		printk("handle_irq: irq %d count %d cc %u @ %p\n",
+		       irq, count, cc-last_cc, regs->pc);
+		count = 0;
+		last_msg = cc;
+		last_irq = irq;
+	  }
+	  last_cc = cc;
+	}
+#endif
+
 	irq_enter(cpu, irq);
 	kstat.irqs[cpu][irq] += 1;
 	action = irq_action[irq];
@@ -784,23 +835,31 @@
 	  unsigned long a3, unsigned long a4, unsigned long a5,
 	  struct pt_regs regs)
 {
+	unsigned long flags;
+
 	switch (type) {
 	case 0:
 #ifdef __SMP__
+		__save_and_cli(flags);
 		handle_ipi(&regs);
+		__restore_flags(flags);
 		return;
 #else
 		printk("Interprocessor interrupt? You must be kidding\n");
 #endif
 		break;
 	case 1:
+		__save_and_cli(flags);
 		handle_irq(RTC_IRQ, -1, &regs);
+		__restore_flags(flags);
 		return;
 	case 2:
 		alpha_mv.machine_check(vector, la_ptr, &regs);
 		return;
 	case 3:
+		__save_and_cli(flags);
 		alpha_mv.device_interrupt(vector, &regs);
+		__restore_flags(flags);
 		return;
 	case 4:
 		printk("Performance counter interrupt\n");
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/kernel/irq.h linux/arch/alpha/kernel/irq.h
--- v2.1.120/linux/arch/alpha/kernel/irq.h	Tue Aug 18 22:02:02 1998
+++ linux/arch/alpha/kernel/irq.h	Sun Sep  6 10:34:33 1998
@@ -8,15 +8,15 @@
  * with the IRQ handling routines in irq.c.
  */
 
-
-/* FIXME FIXME FIXME FIXME FIXME */
-/* We need to figure out why these fail on the DP264 & SX164.  Otherwise
-   we'd just do this in init_IRQ().  */
 #define STANDARD_INIT_IRQ_PROLOG	\
 	outb(0, DMA1_RESET_REG);	\
 	outb(0, DMA2_RESET_REG);	\
+	outb(0, DMA1_MASK_REG);		\
+	outb(0, DMA2_MASK_REG);		\
 	outb(0, DMA1_CLR_MASK_REG);	\
-	outb(0, DMA2_CLR_MASK_REG)
+	outb(0, DMA2_CLR_MASK_REG);	\
+	outb(DMA_MODE_CASCADE, DMA2_MODE_REG)
+
 
 extern unsigned long alpha_irq_mask;
 
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/kernel/machvec.h linux/arch/alpha/kernel/machvec.h
--- v2.1.120/linux/arch/alpha/kernel/machvec.h	Tue Aug 18 22:02:02 1998
+++ linux/arch/alpha/kernel/machvec.h	Sun Sep  6 10:34:33 1998
@@ -28,7 +28,7 @@
 #define CAT(x,y)   CAT1(x,y)
 
 #define DO_DEFAULT_RTC				\
-	rtc_port: 0x70, rtc_addr: 0x80
+	rtc_port: 0x70, rtc_addr: 0x80, rtc_bcd: 0
 
 #define DO_EV4_MMU							\
 	max_asn:			EV4_MAX_ASN,			\
@@ -47,7 +47,7 @@
 	mv_flush_tlb_current_page:	ev5_flush_tlb_current_page
 
 #define DO_EV6_MMU							\
-	max_asn:			EV5_MAX_ASN,			\
+	max_asn:			EV6_MAX_ASN,			\
 	mmu_context_mask:		0xfffffffffful,			\
 	mv_get_mmu_context:		ev5_get_mmu_context,		\
 	mv_flush_tlb_current:		ev5_flush_tlb_current,		\
@@ -75,12 +75,12 @@
 
 #define IO(UP,low1,low2)						\
 	IO_LITE(UP,low1,low2),						\
-	pci_read_config_byte:	CAT(low2,_pcibios_read_config_byte),	\
-	pci_read_config_word:	CAT(low2,_pcibios_read_config_word),	\
-	pci_read_config_dword:	CAT(low2,_pcibios_read_config_dword),	\
-	pci_write_config_byte:	CAT(low2,_pcibios_write_config_byte),	\
-	pci_write_config_word:	CAT(low2,_pcibios_write_config_word),	\
-	pci_write_config_dword:	CAT(low2,_pcibios_write_config_dword),	\
+	hose_read_config_byte:	CAT(low2,_hose_read_config_byte),	\
+	hose_read_config_word:	CAT(low2,_hose_read_config_word),	\
+	hose_read_config_dword:	CAT(low2,_hose_read_config_dword),	\
+	hose_write_config_byte:	CAT(low2,_hose_write_config_byte),	\
+	hose_write_config_word:	CAT(low2,_hose_write_config_word),	\
+	hose_write_config_dword: CAT(low2,_hose_write_config_dword),	\
 	dma_win_base:		CAT(UP,_DMA_WIN_BASE_DEFAULT),		\
         dma_win_size:		CAT(UP,_DMA_WIN_SIZE_DEFAULT)
 
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/kernel/osf_sys.c linux/arch/alpha/kernel/osf_sys.c
--- v2.1.120/linux/arch/alpha/kernel/osf_sys.c	Tue Aug 18 22:02:02 1998
+++ linux/arch/alpha/kernel/osf_sys.c	Sun Sep  6 10:34:33 1998
@@ -47,7 +47,6 @@
 extern kdev_t get_unnamed_dev(void);
 extern void put_unnamed_dev(kdev_t);
 
-extern asmlinkage int sys_umount(char *, int);
 extern asmlinkage int sys_swapon(const char *specialfile, int swap_flags);
 extern asmlinkage unsigned long sys_brk(unsigned long);
 
@@ -535,16 +534,6 @@
 	}
 	unlock_kernel();
 	return retval;
-}
-
-asmlinkage int osf_umount(char *path, int flag)
-{
-	int ret;
-
-	lock_kernel();
-	ret = sys_umount(path,flag);
-	unlock_kernel();
-	return ret;
 }
 
 asmlinkage int osf_utsname(char *name)
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/kernel/process.c linux/arch/alpha/kernel/process.c
--- v2.1.120/linux/arch/alpha/kernel/process.c	Tue Aug 18 22:02:02 1998
+++ linux/arch/alpha/kernel/process.c	Sun Sep  6 10:34:33 1998
@@ -75,58 +75,34 @@
 	return 0;
 }
 
-#ifdef __SMP__
-/* This is being executed in task 0 'user space'. */
-#define resched_needed() 1
-int
-cpu_idle(void *unused)
+static void __attribute__((noreturn))
+do_cpu_idle(void)
 {
-	extern volatile int smp_commenced;
-
-	current->priority = -100;
+	/* An endless idle loop with no priority at all.  */
+	current->priority = 0;
 	while (1) {
+		check_pgt_cache();
 		run_task_queue(&tq_scheduler);
-		/* endless idle loop with no priority at all */
-		current->counter = -100;
-		if (!smp_commenced || resched_needed()) {
-			schedule();
-		}
+		current->counter = 0;
+		schedule();
 	}
 }
 
-asmlinkage int
-sys_idle(void)
+#ifdef __SMP__
+void
+cpu_idle(void *unused)
 {
-        if(current->pid != 0)
-                return -EPERM;
-
-        cpu_idle(NULL);
-        return 0;
+	do_cpu_idle();
 }
-
-#else /* __SMP__ */
+#endif
 
 asmlinkage int
 sys_idle(void)
 {
-	int ret = -EPERM;
-
-	lock_kernel();
-	if (current->pid != 0)
-		goto out;
-
-	/* endless idle loop with no priority at all */
-	current->counter = -100;
-	for (;;) {
-		check_pgt_cache();
-		schedule();
-	}
-	ret = 0;
-out:
-	unlock_kernel();
-	return ret;
+	if (current->pid == 0)
+        	do_cpu_idle();
+	return -EPERM;
 }
-#endif /* __SMP__ */
 
 void
 generic_kill_arch (int mode, char *restart_cmd)
@@ -154,7 +130,7 @@
 				cpup->ipc_buffer[0] = 0;
 			} else {
 				flags |=  0x00030000UL; /* "warm bootstrap" */
-				strncpy(cpup->ipc_buffer, restart_cmd,
+				strncpy((char *)cpup->ipc_buffer, restart_cmd,
 					sizeof(cpup->ipc_buffer));
 			}
 		}
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/kernel/proto.h linux/arch/alpha/kernel/proto.h
--- v2.1.120/linux/arch/alpha/kernel/proto.h	Tue Aug 18 22:02:02 1998
+++ linux/arch/alpha/kernel/proto.h	Sun Sep  6 10:34:33 1998
@@ -6,13 +6,21 @@
 #define vuip	volatile unsigned int   *
 #define vulp	volatile unsigned long  *
 
+struct linux_hose_info;
+
 /* core_apecs.c */
-extern int apecs_pcibios_read_config_byte (u8, u8, u8, u8 *value);
-extern int apecs_pcibios_read_config_word (u8, u8, u8, u16 *value);
-extern int apecs_pcibios_read_config_dword (u8, u8, u8, u32 *value);
-extern int apecs_pcibios_write_config_byte (u8, u8, u8, u8 value);
-extern int apecs_pcibios_write_config_word (u8, u8, u8, u16 value);
-extern int apecs_pcibios_write_config_dword (u8, u8, u8, u32 value);
+extern int apecs_hose_read_config_byte (u8, u8, u8, u8 *value,
+					struct linux_hose_info *hose);
+extern int apecs_hose_read_config_word (u8, u8, u8, u16 *value,
+					struct linux_hose_info *hose);
+extern int apecs_hose_read_config_dword (u8, u8, u8, u32 *value,
+					 struct linux_hose_info *hose);
+extern int apecs_hose_write_config_byte (u8, u8, u8, u8 value,
+					 struct linux_hose_info *hose);
+extern int apecs_hose_write_config_word (u8, u8, u8, u16 value,
+					 struct linux_hose_info *hose);
+extern int apecs_hose_write_config_dword (u8, u8, u8, u32 value,
+					  struct linux_hose_info *hose);
 extern void apecs_init_arch(unsigned long *, unsigned long *);
 
 extern volatile unsigned int apecs_mcheck_expected;
@@ -21,43 +29,66 @@
 extern void apecs_machine_check(u64, u64, struct pt_regs *);
 
 /* core_cia.c */
-extern int cia_pcibios_read_config_byte (u8, u8, u8, u8 *value);
-extern int cia_pcibios_read_config_word (u8, u8, u8, u16 *value);
-extern int cia_pcibios_read_config_dword (u8, u8, u8, u32 *value);
-extern int cia_pcibios_write_config_byte (u8, u8, u8, u8 value);
-extern int cia_pcibios_write_config_word (u8, u8, u8, u16 value);
-extern int cia_pcibios_write_config_dword (u8, u8, u8, u32 value);
+extern int cia_hose_read_config_byte (u8, u8, u8, u8 *value,
+				      struct linux_hose_info *hose);
+extern int cia_hose_read_config_word (u8, u8, u8, u16 *value,
+				      struct linux_hose_info *hose);
+extern int cia_hose_read_config_dword (u8, u8, u8, u32 *value,
+				       struct linux_hose_info *hose);
+extern int cia_hose_write_config_byte (u8, u8, u8, u8 value,
+				       struct linux_hose_info *hose);
+extern int cia_hose_write_config_word (u8, u8, u8, u16 value,
+				       struct linux_hose_info *hose);
+extern int cia_hose_write_config_dword (u8, u8, u8, u32 value,
+					struct linux_hose_info *hose);
 extern void cia_init_arch(unsigned long *, unsigned long *);
 extern void cia_machine_check(u64, u64, struct pt_regs *);
 
 /* core_lca.c */
-extern int lca_pcibios_read_config_byte (u8, u8, u8, u8 *value);
-extern int lca_pcibios_read_config_word (u8, u8, u8, u16 *value);
-extern int lca_pcibios_read_config_dword (u8, u8, u8, u32 *value);
-extern int lca_pcibios_write_config_byte (u8, u8, u8, u8 value);
-extern int lca_pcibios_write_config_word (u8, u8, u8, u16 value);
-extern int lca_pcibios_write_config_dword (u8, u8, u8, u32 value);
+extern int lca_hose_read_config_byte (u8, u8, u8, u8 *value,
+				      struct linux_hose_info *hose);
+extern int lca_hose_read_config_word (u8, u8, u8, u16 *value,
+				      struct linux_hose_info *hose);
+extern int lca_hose_read_config_dword (u8, u8, u8, u32 *value,
+				       struct linux_hose_info *hose);
+extern int lca_hose_write_config_byte (u8, u8, u8, u8 value,
+				       struct linux_hose_info *hose);
+extern int lca_hose_write_config_word (u8, u8, u8, u16 value,
+				       struct linux_hose_info *hose);
+extern int lca_hose_write_config_dword (u8, u8, u8, u32 value,
+					struct linux_hose_info *hose);
 extern void lca_init_arch(unsigned long *, unsigned long *);
 extern void lca_machine_check(u64, u64, struct pt_regs *);
 
 /* core_mcpcia.c */
-extern int mcpcia_pcibios_read_config_byte (u8, u8, u8, u8 *value);
-extern int mcpcia_pcibios_read_config_word (u8, u8, u8, u16 *value);
-extern int mcpcia_pcibios_read_config_dword (u8, u8, u8, u32 *value);
-extern int mcpcia_pcibios_write_config_byte (u8, u8, u8, u8 value);
-extern int mcpcia_pcibios_write_config_word (u8, u8, u8, u16 value);
-extern int mcpcia_pcibios_write_config_dword (u8, u8, u8, u32 value);
+extern int mcpcia_hose_read_config_byte (u8, u8, u8, u8 *value,
+					 struct linux_hose_info *hose);
+extern int mcpcia_hose_read_config_word (u8, u8, u8, u16 *value,
+					 struct linux_hose_info *hose);
+extern int mcpcia_hose_read_config_dword (u8, u8, u8, u32 *value,
+					  struct linux_hose_info *hose);
+extern int mcpcia_hose_write_config_byte (u8, u8, u8, u8 value,
+					  struct linux_hose_info *hose);
+extern int mcpcia_hose_write_config_word (u8, u8, u8, u16 value,
+					  struct linux_hose_info *hose);
+extern int mcpcia_hose_write_config_dword (u8, u8, u8, u32 value,
+					   struct linux_hose_info *hose);
 extern void mcpcia_init_arch(unsigned long *, unsigned long *);
 extern void mcpcia_machine_check(u64, u64, struct pt_regs *);
-extern void mcpcia_pci_fixup(void);
 
 /* core_pyxis.c */
-extern int pyxis_pcibios_read_config_byte (u8, u8, u8, u8 *value);
-extern int pyxis_pcibios_read_config_word (u8, u8, u8, u16 *value);
-extern int pyxis_pcibios_read_config_dword (u8, u8, u8, u32 *value);
-extern int pyxis_pcibios_write_config_byte (u8, u8, u8, u8 value);
-extern int pyxis_pcibios_write_config_word (u8, u8, u8, u16 value);
-extern int pyxis_pcibios_write_config_dword (u8, u8, u8, u32 value);
+extern int pyxis_hose_read_config_byte (u8, u8, u8, u8 *value,
+					struct linux_hose_info *hose);
+extern int pyxis_hose_read_config_word (u8, u8, u8, u16 *value,
+					struct linux_hose_info *hose);
+extern int pyxis_hose_read_config_dword (u8, u8, u8, u32 *value,
+					 struct linux_hose_info *hose);
+extern int pyxis_hose_write_config_byte (u8, u8, u8, u8 value,
+					 struct linux_hose_info *hose);
+extern int pyxis_hose_write_config_word (u8, u8, u8, u16 value,
+					 struct linux_hose_info *hose);
+extern int pyxis_hose_write_config_dword (u8, u8, u8, u32 value,
+					  struct linux_hose_info *hose);
 extern void pyxis_enable_errors (void);
 extern int pyxis_srm_window_setup (void);
 extern void pyxis_native_window_setup(void);
@@ -66,22 +97,34 @@
 extern void pyxis_machine_check(u64, u64, struct pt_regs *);
 
 /* core_t2.c */
-extern int t2_pcibios_read_config_byte (u8, u8, u8, u8 *value);
-extern int t2_pcibios_read_config_word (u8, u8, u8, u16 *value);
-extern int t2_pcibios_read_config_dword (u8, u8, u8, u32 *value);
-extern int t2_pcibios_write_config_byte (u8, u8, u8, u8 value);
-extern int t2_pcibios_write_config_word (u8, u8, u8, u16 value);
-extern int t2_pcibios_write_config_dword (u8, u8, u8, u32 value);
+extern int t2_hose_read_config_byte (u8, u8, u8, u8 *value,
+				     struct linux_hose_info *hose);
+extern int t2_hose_read_config_word (u8, u8, u8, u16 *value,
+				     struct linux_hose_info *hose);
+extern int t2_hose_read_config_dword (u8, u8, u8, u32 *value,
+				      struct linux_hose_info *hose);
+extern int t2_hose_write_config_byte (u8, u8, u8, u8 value,
+				      struct linux_hose_info *hose);
+extern int t2_hose_write_config_word (u8, u8, u8, u16 value,
+				      struct linux_hose_info *hose);
+extern int t2_hose_write_config_dword (u8, u8, u8, u32 value,
+				       struct linux_hose_info *hose);
 extern void t2_init_arch(unsigned long *, unsigned long *);
 extern void t2_machine_check(u64, u64, struct pt_regs *);
 
 /* core_tsunami.c */
-extern int tsunami_pcibios_read_config_byte (u8, u8, u8, u8 *value);
-extern int tsunami_pcibios_read_config_word (u8, u8, u8, u16 *value);
-extern int tsunami_pcibios_read_config_dword (u8, u8, u8, u32 *value);
-extern int tsunami_pcibios_write_config_byte (u8, u8, u8, u8 value);
-extern int tsunami_pcibios_write_config_word (u8, u8, u8, u16 value);
-extern int tsunami_pcibios_write_config_dword (u8, u8, u8, u32 value);
+extern int tsunami_hose_read_config_byte (u8, u8, u8, u8 *value,
+					  struct linux_hose_info *hose);
+extern int tsunami_hose_read_config_word (u8, u8, u8, u16 *value,
+					  struct linux_hose_info *hose);
+extern int tsunami_hose_read_config_dword (u8, u8, u8, u32 *value,
+					   struct linux_hose_info *hose);
+extern int tsunami_hose_write_config_byte (u8, u8, u8, u8 value,
+					   struct linux_hose_info *hose);
+extern int tsunami_hose_write_config_word (u8, u8, u8, u16 value,
+					   struct linux_hose_info *hose);
+extern int tsunami_hose_write_config_dword (u8, u8, u8, u32 value,
+					    struct linux_hose_info *hose);
 extern void tsunami_init_arch(unsigned long *, unsigned long *);
 extern void tsunami_machine_check(u64, u64, struct pt_regs *);
 
@@ -92,14 +135,14 @@
 
 /* smp.c */
 extern void setup_smp(void);
-extern char *smp_info(void);
+extern int smp_info(char *buffer);
 extern void handle_ipi(struct pt_regs *);
 
 /* bios32.c */
 extern void reset_for_srm(void);
 
 /* time.c */
-extern void timer_interrupt(struct pt_regs * regs);
+extern void timer_interrupt(int irq, void *dev, struct pt_regs * regs);
 
 /* smc37c93x.c */
 extern void SMC93x_Init(void);
@@ -118,6 +161,7 @@
 extern void wrmces(unsigned long mces);
 extern void cserve_ena(unsigned long);
 extern void cserve_dis(unsigned long);
+extern void __start_cpu(unsigned long);
 
 /* entry.S */
 extern void entArith(void);
@@ -129,3 +173,4 @@
 
 /* process.c */
 void generic_kill_arch (int mode, char *reboot_cmd);
+void cpu_idle(void *) __attribute__((noreturn));
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/kernel/ptrace.c linux/arch/alpha/kernel/ptrace.c
--- v2.1.120/linux/arch/alpha/kernel/ptrace.c	Tue Aug 18 22:02:02 1998
+++ linux/arch/alpha/kernel/ptrace.c	Wed Sep  9 08:56:58 1998
@@ -4,7 +4,6 @@
 /* mangled further by Bob Manson (manson@santafe.edu) */
 /* more mutilation by David Mosberger (davidm@azstarnet.com) */
 
-#include <linux/head.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/kernel/setup.c linux/arch/alpha/kernel/setup.c
--- v2.1.120/linux/arch/alpha/kernel/setup.c	Tue Aug 18 22:02:02 1998
+++ linux/arch/alpha/kernel/setup.c	Sun Sep  6 10:36:35 1998
@@ -20,7 +20,6 @@
 #include <linux/tty.h>
 #include <linux/delay.h>
 #include <linux/config.h>	/* CONFIG_ALPHA_LCA etc */
-#include <linux/ioport.h>
 #include <linux/mc146818rtc.h>
 #include <linux/console.h>
 #include <linux/errno.h>
@@ -30,6 +29,9 @@
 #ifdef CONFIG_RTC
 #include <linux/timex.h>
 #endif
+#ifdef CONFIG_BLK_DEV_INITRD
+#include <linux/blk.h>
+#endif
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -73,11 +75,12 @@
 #define PARAM			ZERO_PAGE
 #define COMMAND_LINE		((char*)(PARAM + 0x0000))
 #define COMMAND_LINE_SIZE	256
+#define INITRD_START		(*(unsigned long *) (PARAM+0x100))
+#define INITRD_SIZE		(*(unsigned long *) (PARAM+0x108))
 
 static char command_line[COMMAND_LINE_SIZE];
 char saved_command_line[COMMAND_LINE_SIZE];
 
-
 /*
  * The format of "screen_info" is strange, and due to early
  * i386-setup code. This is just enough to make the console
@@ -93,68 +96,6 @@
 	orig_video_points: 16
 };
 
-
-/*
- * Initialize Programmable Interval Timers with standard values.  Some
- * drivers depend on them being initialized (e.g., joystick driver).
- */
-
-/* It is (normally) only counter 1 that presents config problems, so
-   provide this support function to do the rest of the job.  */
-
-void inline
-init_pit_rest(void)
-{
-#if 0
-	/* Leave refresh timer alone---nobody should depend on a
-	   particular value anyway. */
-	outb(0x54, 0x43);	/* counter 1: refresh timer */
-	outb(0x18, 0x41);
-#endif
-
-	outb(0xb6, 0x43);	/* counter 2: speaker */
-	outb(0x31, 0x42);
-	outb(0x13, 0x42);
-
-	if ((CMOS_READ(RTC_FREQ_SELECT) & 0x3f) != 0x26) {
-		printk("Setting RTC_FREQ to 1024 Hz\n");
-		CMOS_WRITE(0x26, RTC_FREQ_SELECT);
-	}
-}
-
-#ifdef CONFIG_RTC
-static inline void
-rtc_init_pit (void)
-{
-	/* Setup interval timer if /dev/rtc is being used */
-	outb(0x34, 0x43);		/* binary, mode 2, LSB/MSB, ch 0 */
-	outb(LATCH & 0xff, 0x40);	/* LSB */
-	outb(LATCH >> 8, 0x40);		/* MSB */
-	request_region(0x40, 0x20, "timer"); /* reserve pit */
-
-	init_pit_rest();
-}
-#endif
-
-void
-generic_init_pit (void)
-{
-	outb(0x36, 0x43);	/* counter 0: system timer */
-	outb(0x00, 0x40);
-	outb(0x00, 0x40);
-	request_region(RTC_PORT(0), 0x10, "timer"); /* reserve rtc */
-
-	init_pit_rest();
-}
-
-/* This probably isn't Right, but it is what the old code did.  */
-#if defined(CONFIG_RTC)
-# define init_pit	rtc_init_pit
-#else
-# define init_pit	alpha_mv.init_pit
-#endif
-
-
 /*
  * Declare all of the machine vectors.
  */
@@ -278,6 +219,11 @@
 	}
 #endif
 
+	printk("Booting on %s%s%s using machine vector %s\n",
+	       type_name, (*var_name ? " variation " : ""),
+	       var_name, alpha_mv.vector_name);
+	printk("Command line: %s\n", command_line);
+
 	/* 
 	 * Sync with the HAE
 	 */
@@ -293,17 +239,27 @@
 	*memory_end_p = find_end_memory();
 	*memory_start_p = (unsigned long) _end;
 
+#ifdef CONFIG_BLK_DEV_INITRD
+	initrd_start = INITRD_START;
+	if (initrd_start) {
+		initrd_end = initrd_start+INITRD_SIZE;
+		printk("Initial ramdisk at: 0x%p (%lu bytes)\n",
+		       (void *) initrd_start, INITRD_SIZE);
+
+		if (initrd_end > *memory_end_p) {
+			printk("initrd extends beyond end of memory "
+			       "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
+			       initrd_end, memory_end_p);
+			initrd_start = initrd_end = 0;
+		}
+	}
+#endif
+
 	/* Initialize the machine.  Usually has to do with setting up
 	   DMA windows and the like.  */
 	if (alpha_mv.init_arch)
 		alpha_mv.init_arch(memory_start_p, memory_end_p);
 
-	/* Initialize the timers.  */
-	init_pit();
-
-	/* Default root filesystem to sda2.  */
-	ROOT_DEV = to_kdev_t(0x0802);
-
 	/* 
 	 * Give us a default console.  TGA users will see nothing until
 	 * chr_dev_init is called, rather late in the boot sequence.
@@ -317,11 +273,8 @@
 #endif
 #endif
 
-	/* Delayed so that we've initialized the machine first.  */
-	printk("Booting on %s%s%s using machine vector %s\n",
-	       type_name, (*var_name ? " variation " : ""),
-	       var_name, alpha_mv.vector_name);
-	printk("Command line: %s\n", command_line);
+	/* Default root filesystem to sda2.  */
+	ROOT_DEV = to_kdev_t(0x0802);
 
  	/*
 	 * Check ASN in HWRPB for validity, report if bad.
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/kernel/smc37c93x.c linux/arch/alpha/kernel/smc37c93x.c
--- v2.1.120/linux/arch/alpha/kernel/smc37c93x.c	Mon Apr  6 17:40:59 1998
+++ linux/arch/alpha/kernel/smc37c93x.c	Sun Sep  6 10:34:33 1998
@@ -13,7 +13,9 @@
 #include <asm/io.h>
 #include <asm/segment.h>
 
-#if 0
+#define SMC_DEBUG 0
+
+#if SMC_DEBUG
 # define DBG_DEVS(args)         printk args
 #else
 # define DBG_DEVS(args)
@@ -75,8 +77,6 @@
 #define PARP_BASE		0x3bc
 #define PARP_INTERRUPT		7
 
-#define SMC_DEBUG 0
-
 static unsigned long __init SMCConfigState(unsigned long baseAddr)
 {
 	unsigned char devId;
@@ -241,12 +241,17 @@
 		SMCReportDeviceStatus(SMCUltraBase);
 #endif
 		SMCEnableDevice(SMCUltraBase, SER1, COM1_BASE, COM1_INTERRUPT);
+		DBG_DEVS(("SMC FDC37C93X: SER1 done\n"));
 		SMCEnableDevice(SMCUltraBase, SER2, COM2_BASE, COM2_INTERRUPT);
+		DBG_DEVS(("SMC FDC37C93X: SER2 done\n"));
 		SMCEnableDevice(SMCUltraBase, PARP, PARP_BASE, PARP_INTERRUPT);
+		DBG_DEVS(("SMC FDC37C93X: PARP done\n"));
 		/* On PC164, IDE on the SMC is not enabled;
 		   CMD646 (PCI) on MB */
 		SMCEnableKYBD(SMCUltraBase);
+		DBG_DEVS(("SMC FDC37C93X: KYB done\n"));
 		SMCEnableFDC(SMCUltraBase);
+		DBG_DEVS(("SMC FDC37C93X: FDC done\n"));
 #if SMC_DEBUG
 		SMCReportDeviceStatus(SMCUltraBase);
 #endif
@@ -254,9 +259,7 @@
 		return 1;
 	}
 	else {
-#if SMC_DEBUG
-		printk("No SMC FDC37C93X Ultra I/O Controller found\n");
-#endif
+		DBG_DEVS(("No SMC FDC37C93X Ultra I/O Controller found\n"));
 		return 0;
 	}
 }
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/kernel/smp.c linux/arch/alpha/kernel/smp.c
--- v2.1.120/linux/arch/alpha/kernel/smp.c	Tue Aug 18 22:02:02 1998
+++ linux/arch/alpha/kernel/smp.c	Sun Sep  6 10:34:33 1998
@@ -1,3 +1,7 @@
+/*
+ *	linux/arch/alpha/kernel/smp.c
+ */
+
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/kernel_stat.h>
@@ -30,10 +34,8 @@
 
 struct cpuinfo_alpha cpu_data[NR_CPUS];
 
-/* Processor holding kernel spinlock */
-klock_info_t klock_info = { KLOCK_CLEAR, 0 };
-
 spinlock_t ticker_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
 
 unsigned int boot_cpu_id = 0;
 static int smp_activated = 0;
@@ -63,11 +65,8 @@
 volatile int cpu_number_map[NR_CPUS];
 volatile int cpu_logical_map[NR_CPUS];
 
-extern int cpu_idle(void *unused);
 extern void calibrate_delay(void);
-extern struct hwrpb_struct *hwrpb;
 extern struct thread_struct * original_pcb_ptr;
-extern void __start_cpu(unsigned long);
 
 static void smp_setup_percpu_timer(void);
 static void secondary_cpu_start(int, struct task_struct *);
@@ -170,7 +169,7 @@
 printk("start_secondary: commencing CPU %d current %p\n",
        hard_smp_processor_id(), current);
 #endif
-        return cpu_idle(NULL);
+        cpu_idle(NULL);
 }
 
 /*
@@ -198,7 +197,6 @@
 	cpu_number_map[boot_cpu_id] = 0;
 	cpu_logical_map[0] = boot_cpu_id;
 	current->processor = boot_cpu_id; /* ??? */
-        klock_info.akp = boot_cpu_id;
 
         smp_store_cpu_info(boot_cpu_id);
 #ifdef NOT_YET
@@ -739,9 +737,8 @@
 
 int smp_info(char *buffer)
 {
-        return sprintf(buffer, "CPUs probed %d active %d map 0x%x AKP %d\n",
-		       smp_num_probed, smp_num_cpus, cpu_present_map,
-		       klock_info.akp);
+        return sprintf(buffer, "CPUs probed %d active %d map 0x%x\n",
+		       smp_num_probed, smp_num_cpus, cpu_present_map);
 }
 
 /* wrapper for call from panic() */
@@ -766,12 +763,6 @@
 	unsigned int to_whom = cpu_present_map ^ (1 << smp_processor_id());
 	int timeout = 10000;
 
-#if 1
-	if (!kernel_lock_held()) {
-	  printk("flush_tlb_all: kernel_flag %d (cpu %d akp %d)!\n",
-		 klock_info.kernel_flag, smp_processor_id(), klock_info.akp);
-	}
-#endif
 	ipi_msg_flush_tb.flush_tb_mask = to_whom;
 	send_ipi_message(to_whom, TLB_ALL);
 	tbia();
@@ -794,12 +785,6 @@
 	unsigned int to_whom = cpu_present_map ^ (1 << smp_processor_id());
 	int timeout = 10000;
 
-#if 1
-	if (!kernel_lock_held()) {
-	  printk("flush_tlb_mm: kernel_flag %d (cpu %d akp %d)!\n",
-		 klock_info.kernel_flag, smp_processor_id(), klock_info.akp);
-	}
-#endif
 	ipi_msg_flush_tb.p.flush_mm = mm;
 	ipi_msg_flush_tb.flush_tb_mask = to_whom;
 	send_ipi_message(to_whom, TLB_MM);
@@ -829,12 +814,6 @@
 	struct mm_struct * mm = vma->vm_mm;
 	int timeout = 10000;
 
-#if 1
-	if (!kernel_lock_held()) {
-	  printk("flush_tlb_page: kernel_flag %d (cpu %d akp %d)!\n",
-		 klock_info.kernel_flag, cpu, klock_info.akp);
-	}
-#endif
 	ipi_msg_flush_tb.p.flush_vma = vma;
 	ipi_msg_flush_tb.flush_addr = addr;
 	ipi_msg_flush_tb.flush_tb_mask = to_whom;
@@ -847,9 +826,9 @@
 
 	while (ipi_msg_flush_tb.flush_tb_mask) {
 	  if (--timeout < 0) {
-	    printk("flush_tlb_page: STUCK on CPU %d [0x%x,0x%lx,%d,%d]\n",
+	    printk("flush_tlb_page: STUCK on CPU %d [0x%x,0x%lx,%d]\n",
 		   cpu, ipi_msg_flush_tb.flush_tb_mask, addr,
-		   klock_info.akp, global_irq_holder);
+		   global_irq_holder);
 	    ipi_msg_flush_tb.flush_tb_mask = 0;
 	    break;
 	  }
@@ -866,20 +845,10 @@
 #else
 	unsigned int to_whom;
 	int timeout;
-        unsigned long where;
-
-        __asm__("mov $26, %0" : "=r" (where));
 
 	timeout = 10000;
 	to_whom = cpu_present_map ^ (1 << smp_processor_id());
 
-#if 1
-	if (!kernel_lock_held()) {
-	  printk("flush_tlb_range: kernel_flag %d (cpu %d akp %d) @ 0x%lx\n",
-		 klock_info.kernel_flag, smp_processor_id(), klock_info.akp,
-		 where);
-	}
-#endif
 	ipi_msg_flush_tb.p.flush_mm = mm;
 	ipi_msg_flush_tb.flush_tb_mask = to_whom;
 	send_ipi_message(to_whom, TLB_MM);
@@ -896,68 +865,17 @@
 	    ipi_msg_flush_tb.flush_tb_mask = 0;
 	    break;
 	  }
-	  udelay(100);
-		; /* Wait for all clear from other CPUs. */
+	  udelay(100); /* Wait for all clear from other CPUs. */
 	}
 #endif
 }
 
-#ifdef DEBUG_KERNEL_LOCK
-void ___lock_kernel(klock_info_t *klip, int cpu, long ipl)
-{
-	long regx;
-	int stuck_lock;
-	unsigned long inline_pc;
-
-        __asm__("mov $26, %0" : "=r" (inline_pc));
-
- try_again:
-
-	stuck_lock = 1<<26;
-
-	__asm__ __volatile__(
-	"1:	ldl_l	%1,%0;"
-	"	blbs	%1,6f;"
-	"	or	%1,1,%1;"
-	"	stl_c	%1,%0;"
-	"	beq	%1,6f;"
-	"4:	mb\n"
-	".section .text2,\"ax\"\n"
-	"6:	mov	%5,$16;"
-	"	call_pal %4;"
-	"7:	ldl	%1,%0;"
-	"	blt	%2,4b	# debug\n"
-	"	subl	%2,1,%2	# debug\n"
-	"	blbs	%1,7b;"
-	"	bis	$31,7,$16;"
-	"	call_pal %4;"
-	"	br	1b\n"
-	".previous"
-	: "=m,=m" (__dummy_lock(klip)), "=&r,=&r" (regx),
-	  "=&r,=&r" (stuck_lock)
-	: "0,0" (__dummy_lock(klip)), "i,i" (PAL_swpipl),
-	  "i,r" (ipl), "2,2" (stuck_lock)
-	: "$0", "$1", "$16", "$22", "$23", "$24", "$25", "memory");
-
-	if (stuck_lock < 0) {
-		printk("___kernel_lock stuck at %lx(%d) held %lx(%d)\n",
-		       inline_pc, cpu, klip->pc, klip->cpu);
-		goto try_again;
-	} else {
-		klip->pc = inline_pc;
-		klip->cpu = cpu;
-	}
-}
-#endif
-
-#ifdef DEBUG_SPINLOCK
+#if DEBUG_SPINLOCK
 void spin_lock(spinlock_t * lock)
 {
 	long tmp;
 	long stuck;
-	unsigned long inline_pc;
-
-        __asm__("mov $26, %0" : "=r" (inline_pc));
+	void *inline_pc = __builtin_return_address(0);
 
  try_again:
 
@@ -987,30 +905,22 @@
 	: "2" (stuck));
 
 	if (stuck < 0) {
-		printk("spinlock stuck at %lx (cur=%lx, own=%lx)\n",
-		       inline_pc,
-#if 0
-		       lock->previous, lock->task
-#else
-		       (unsigned long) current, lock->task
-#endif
-		       );
+		printk("spinlock stuck at %p (cur=%p, own=%p, prev=%p)\n",
+		       inline_pc, current, lock->task, lock->previous);
 		goto try_again;
 	} else {
-		lock->previous = (unsigned long) inline_pc;
-		lock->task = (unsigned long) current;
+		lock->previous = inline_pc;
+		lock->task = current;
 	}
 }
 #endif /* DEBUG_SPINLOCK */
 
-#ifdef DEBUG_RWLOCK
+#if DEBUG_RWLOCK
 void write_lock(rwlock_t * lock)
 {
 	long regx, regy;
 	int stuck_lock, stuck_reader;
-	unsigned long inline_pc;
-
-        __asm__("mov $26, %0" : "=r" (inline_pc));
+	void *inline_pc = __builtin_return_address(0);
 
  try_again:
 
@@ -1018,24 +928,24 @@
 	stuck_reader = 1<<26;
 
 	__asm__ __volatile__(
-	"1:	ldl_l	%1,%0;"
-	"	blbs	%1,6f;"
-	"	or	%1,1,%2;"
-	"	stl_c	%2,%0;"
-	"	beq	%2,6f;"
-	"	blt	%1,8f;"
+	"1:	ldl_l	%1,%0\n"
+	"	blbs	%1,6f\n"
+	"	or	%1,1,%2\n"
+	"	stl_c	%2,%0\n"
+	"	beq	%2,6f\n"
+	"	blt	%1,8f\n"
 	"4:	mb\n"
 	".section .text2,\"ax\"\n"
-	"6:	ldl	%1,%0;"
+	"6:	ldl	%1,%0\n"
 	"	blt	%3,4b	# debug\n"
 	"	subl	%3,1,%3	# debug\n"
-	"	blbs	%1,6b;"
-	"	br	1b;"
-	"8:	ldl	%1,%0;"
+	"	blbs	%1,6b\n"
+	"	br	1b\n"
+	"8:	ldl	%1,%0\n"
 	"	blt	%4,4b	# debug\n"
 	"	subl	%4,1,%4	# debug\n"
-	"	blt	%1,8b;"
-	"9:	br	4b\n"
+	"	blt	%1,8b\n"
+	"	br	4b\n"
 	".previous"
 	: "=m" (__dummy_lock(lock)), "=&r" (regx), "=&r" (regy)
 	, "=&r" (stuck_lock), "=&r" (stuck_reader)
@@ -1044,22 +954,20 @@
 	);
 
 	if (stuck_lock < 0) {
-		printk("write_lock stuck at %lx\n", inline_pc);
+		printk("write_lock stuck at %p\n", inline_pc);
 		goto try_again;
 	}
 	if (stuck_reader < 0) {
-		printk("write_lock stuck on readers at %lx\n", inline_pc);
+		printk("write_lock stuck on readers at %p\n", inline_pc);
 		goto try_again;
 	}
 }
 
-void _read_lock(rwlock_t * lock)
+void read_lock(rwlock_t * lock)
 {
 	long regx;
 	int stuck_lock;
-	unsigned long inline_pc;
-
-        __asm__("mov $26, %0" : "=r" (inline_pc));
+	void *inline_pc = __builtin_return_address(0);
 
  try_again:
 
@@ -1084,7 +992,7 @@
 	);
 
 	if (stuck_lock < 0) {
-		printk("_read_lock stuck at %lx\n", inline_pc);
+		printk("read_lock stuck at %p\n", inline_pc);
 		goto try_again;
 	}
 }
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/kernel/sys_alcor.c linux/arch/alpha/kernel/sys_alcor.c
--- v2.1.120/linux/arch/alpha/kernel/sys_alcor.c	Tue Aug 18 22:02:02 1998
+++ linux/arch/alpha/kernel/sys_alcor.c	Sun Sep  6 10:34:33 1998
@@ -75,9 +75,6 @@
 {
 	unsigned long pld;
 	unsigned int i;
-	unsigned long flags;
-
-	save_and_cli(flags);
 
 	/* Read the interrupt summary register of the GRU */
 	pld = (*(vuip)GRU_INT_REQ) & GRU_INT_REQ_BITS;
@@ -95,7 +92,6 @@
 			handle_irq(16 + i, 16 + i, regs);
 		}
 	}
-	restore_flags(flags);
 }
 
 static void
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/kernel/sys_cabriolet.c linux/arch/alpha/kernel/sys_cabriolet.c
--- v2.1.120/linux/arch/alpha/kernel/sys_cabriolet.c	Tue Aug 18 22:02:02 1998
+++ linux/arch/alpha/kernel/sys_cabriolet.c	Sun Sep  6 10:34:33 1998
@@ -72,9 +72,6 @@
 {
 	unsigned long pld;
 	unsigned int i;
-	unsigned long flags;
-
-	save_and_cli(flags);
 
 	/* Read the interrupt summary registers */
 	pld = inb(0x804) | (inb(0x805) << 8) | (inb(0x806) << 16);
@@ -92,7 +89,6 @@
 			handle_irq(16 + i, 16 + i, r);
 		}
 	}
-	restore_flags(flags);
 }
 
 static void
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/kernel/sys_dp264.c linux/arch/alpha/kernel/sys_dp264.c
--- v2.1.120/linux/arch/alpha/kernel/sys_dp264.c	Tue Aug 18 22:02:02 1998
+++ linux/arch/alpha/kernel/sys_dp264.c	Sun Sep  6 10:34:33 1998
@@ -22,6 +22,7 @@
 #include <asm/bitops.h>
 #include <asm/mmu_context.h>
 #include <asm/io.h>
+#include <asm/pci.h>
 #include <asm/pgtable.h>
 #include <asm/core_tsunami.h>
 
@@ -39,12 +40,22 @@
 dp264_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
 {
 	if (irq >= 16) {
-		/* Make CERTAIN none of the bogus ints get enabled */
-		*(vulp)TSUNAMI_CSR_DIM0 =
-			~(mask) & ~0x0000000000000000UL;
+		volatile unsigned long *csr;
+
+		if (TSUNAMI_bootcpu < 2)
+			if (!TSUNAMI_bootcpu)
+				csr = &TSUNAMI_cchip->dim0.csr;
+			else
+				csr = &TSUNAMI_cchip->dim1.csr;
+		else
+			if (TSUNAMI_bootcpu == 2)
+				csr = &TSUNAMI_cchip->dim2.csr;
+			else
+				csr = &TSUNAMI_cchip->dim3.csr;
+		
+		*csr = ~mask;
 		mb();
-		/* ... and read it back to make sure it got written.  */
-		*(vulp)TSUNAMI_CSR_DIM0;
+		*csr;
 	}
 	else if (irq >= 8)
 		outb(mask >> 8, 0xA1);	/* ISA PIC2 */
@@ -55,14 +66,14 @@
 static void
 dp264_device_interrupt(unsigned long vector, struct pt_regs * regs)
 {
+#if 1
+	printk("dp264_device_interrupt: NOT IMPLEMENTED YET!! \n");
+#else
         unsigned long pld;
         unsigned int i;
-        unsigned long flags;
-
-	__save_and_cli(flags);
 
         /* Read the interrupt summary register of TSUNAMI */
-        pld = (*(vulp)TSUNAMI_CSR_DIR0);
+        pld = TSUNAMI_cchip->dir0.csr;
 
         /*
          * Now for every possible bit set, work through them and call
@@ -77,20 +88,18 @@
                         handle_irq(16 + i, 16 + i, regs);
                 }
 #if 0
-		*(vulp)TSUNAMI_CSR_DIR0 = 1UL << i; mb();
-		tmp = *(vulp)TSUNAMI_CSR_DIR0;
+		TSUNAMI_cchip->dir0.csr = 1UL << i; mb();
+		tmp = TSUNAMI_cchip->dir0.csr;
 #endif
         }
-	__restore_flags(flags);
+#endif
 }
 
 static void 
 dp264_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
 {
 	int irq, ack;
-	unsigned long flags;
 
-	__save_and_cli(flags);
 	ack = irq = (vector - 0x800) >> 4;
 
         /*
@@ -104,20 +113,35 @@
                 ack = irq = irq - 16;
 
 	handle_irq(irq, ack, regs);
-	__restore_flags(flags);
 }
 
 static void __init
 dp264_init_irq(void)
 {
-	STANDARD_INIT_IRQ_PROLOG;
+	volatile unsigned long *csr;
+
+	outb(0, DMA1_RESET_REG);
+	outb(0, DMA2_RESET_REG);
+	outb(DMA_MODE_CASCADE, DMA2_MODE_REG);
 
 	if (alpha_using_srm)
 		alpha_mv.device_interrupt = dp264_srm_device_interrupt;
 
+	if (TSUNAMI_bootcpu < 2)
+		if (!TSUNAMI_bootcpu)
+			csr = &TSUNAMI_cchip->dim0.csr;
+		else
+			csr = &TSUNAMI_cchip->dim1.csr;
+	else
+		if (TSUNAMI_bootcpu == 2)
+			csr = &TSUNAMI_cchip->dim2.csr;
+		else
+			csr = &TSUNAMI_cchip->dim3.csr;
+		
 	/* Note invert on MASK bits.  */
-        *(vulp)TSUNAMI_CSR_DIM0 = ~(alpha_irq_mask) & ~0UL; mb();
-        *(vulp)TSUNAMI_CSR_DIM0;
+        *csr = ~(alpha_irq_mask);
+	mb();
+        *csr;
 
         enable_irq(55);     /* Enable CYPRESS interrupt controller (ISA).  */
 	enable_irq(2);
@@ -173,25 +197,29 @@
  * IdSel	
  *   5	 Cypress Bridge I/O
  *   6	 SCSI Adaptec builtin
- *   7	 64 bit PCI option slot 0
- *   8	 64 bit PCI option slot 1
- *   9	 64 bit PCI option slot 2
- * 
+ *   7	 64 bit PCI option slot 0 (all busses)
+ *   8	 64 bit PCI option slot 1 (all busses)
+ *   9	 64 bit PCI option slot 2 (all busses)
+ *  10	 64 bit PCI option slot 3 (not bus 0)
  */
 
 static int __init
 dp264_map_irq(struct pci_dev *dev, int slot, int pin)
 {
-	static char irq_tab[5][5] __initlocaldata = {
+	static char irq_tab[6][5] __initlocaldata = {
 		/*INT    INTA   INTB   INTC   INTD */
 		{    -1,    -1,    -1,    -1,    -1}, /* IdSel 5 ISA Bridge */
-		{ 16+ 2, 16+ 2, 16+ 2, 16+ 2, 16+ 2}, /* IdSel 6 SCSI builtin*/
+		{ 16+ 3, 16+ 3, 16+ 2, 16+ 2, 16+ 2}, /* IdSel 6 SCSI builtin*/
 		{ 16+15, 16+15, 16+14, 16+13, 16+12}, /* IdSel 7 slot 0 */
 		{ 16+11, 16+11, 16+10, 16+ 9, 16+ 8}, /* IdSel 8 slot 1 */
-		{ 16+ 7, 16+ 7, 16+ 6, 16+ 5, 16+ 4}  /* IdSel 9 slot 2 */
+		{ 16+ 7, 16+ 7, 16+ 6, 16+ 5, 16+ 4}, /* IdSel 9 slot 2 */
+		{ 16+ 3, 16+ 3, 16+ 2, 16+ 1, 16+ 0}  /* IdSel 10 slot 3 */
 	};
-	const long min_idsel = 5, max_idsel = 9, irqs_per_slot = 5;
-	return COMMON_TABLE_LOOKUP;
+	const long min_idsel = 5, max_idsel = 10, irqs_per_slot = 5;
+	int irq = COMMON_TABLE_LOOKUP;
+	if (irq >= 0)
+		irq += 16 * bus2hose[dev->bus->number]->pci_hose_index;
+	return irq;
 }
 
 static void __init
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/kernel/sys_eb64p.c linux/arch/alpha/kernel/sys_eb64p.c
--- v2.1.120/linux/arch/alpha/kernel/sys_eb64p.c	Tue Aug 18 22:02:02 1998
+++ linux/arch/alpha/kernel/sys_eb64p.c	Sun Sep  6 10:34:33 1998
@@ -52,9 +52,6 @@
 {
 	unsigned long pld;
 	unsigned int i;
-	unsigned long flags;
-
-	save_and_cli(flags);
 
 	/* Read the interrupt summary registers */
 	pld = inb(0x26) | (inb(0x27) << 8);
@@ -72,12 +69,28 @@
 			handle_irq(16 + i, 16 + i, regs);
 		}
 	}
-	restore_flags(flags);
 }
 
 static void __init
 eb64p_init_irq(void)
 {
+#ifdef CONFIG_ALPHA_GENERIC
+	/*
+	 * CABRIO SRM may not set variation correctly, so here we test
+	 * the high word of the interrupt summary register for the RAZ
+	 * bits, and hope that a true EB64+ would read all ones...
+	 */
+	if (inw(0x806) != 0xffff) {
+		extern struct alpha_machine_vector cabriolet_mv;
+#if 1
+		printk("eb64p_init_irq: resetting for CABRIO\n");
+#endif
+		alpha_mv = cabriolet_mv;
+		alpha_mv.init_irq();
+		return;
+	}
+#endif /* GENERIC */
+
 	STANDARD_INIT_IRQ_PROLOG;
 
 	outb(alpha_irq_mask >> 16, 0x26);
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/kernel/sys_jensen.c linux/arch/alpha/kernel/sys_jensen.c
--- v2.1.120/linux/arch/alpha/kernel/sys_jensen.c	Tue Aug 18 22:02:02 1998
+++ linux/arch/alpha/kernel/sys_jensen.c	Sun Sep  6 10:34:33 1998
@@ -76,9 +76,7 @@
 jensen_device_interrupt(unsigned long vector, struct pt_regs * regs)
 {
 	int irq, ack;
-	unsigned long flags;
 
-	__save_and_cli(flags);
 	ack = irq = (vector - 0x800) >> 4;
 
 	switch (vector) {
@@ -102,7 +100,6 @@
 	}
 
 	handle_irq(irq, ack, regs);
-	__restore_flags(flags);
 }
 
 static void
@@ -131,6 +128,7 @@
 	BUS(jensen),
 	machine_check:		jensen_machine_check,
 	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
+	rtc_port: 0x170, rtc_addr: 0, rtc_bcd: 1,
 
 	nr_irqs:		16,
 	irq_probe_mask:		_PROBE_MASK(16),
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/kernel/sys_miata.c linux/arch/alpha/kernel/sys_miata.c
--- v2.1.120/linux/arch/alpha/kernel/sys_miata.c	Tue Aug 18 22:02:02 1998
+++ linux/arch/alpha/kernel/sys_miata.c	Sun Sep  6 10:34:33 1998
@@ -52,9 +52,6 @@
 {
 	unsigned long pld, tmp;
 	unsigned int i;
-	unsigned long flags;
-
-	save_and_cli(flags);
 
 	/* Read the interrupt summary register of PYXIS */
 	pld = *(vulp)PYXIS_INT_REQ;
@@ -85,16 +82,13 @@
 		*(vulp)PYXIS_INT_REQ = 1UL << i; mb();
 		tmp = *(vulp)PYXIS_INT_REQ;
 	}
-	restore_flags(flags);
 }
 
 static void 
 miata_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
 {
 	int irq, ack;
-	unsigned long flags;
 
-	__save_and_cli(flags);
 	ack = irq = (vector - 0x800) >> 4;
 
 	/*
@@ -115,7 +109,6 @@
 		ack = irq = irq + 8;
 
 	handle_irq(irq, ack, regs);
-	__restore_flags(flags);
 }
 
 static void __init
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/kernel/sys_mikasa.c linux/arch/alpha/kernel/sys_mikasa.c
--- v2.1.120/linux/arch/alpha/kernel/sys_mikasa.c	Tue Aug 18 22:02:02 1998
+++ linux/arch/alpha/kernel/sys_mikasa.c	Sun Sep  6 10:34:33 1998
@@ -48,9 +48,6 @@
 {
 	unsigned long pld;
 	unsigned int i;
-	unsigned long flags;
-
-	save_and_cli(flags);
 
 	/* Read the interrupt summary registers */
 	pld = (((unsigned long) (~inw(0x534)) & 0x0000ffffUL) << 16) |
@@ -70,7 +67,6 @@
 			handle_irq(i, i, regs);
 		}
 	}
-	restore_flags(flags);
 }
 
 static void __init
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/kernel/sys_noritake.c linux/arch/alpha/kernel/sys_noritake.c
--- v2.1.120/linux/arch/alpha/kernel/sys_noritake.c	Tue Aug 18 22:02:02 1998
+++ linux/arch/alpha/kernel/sys_noritake.c	Sun Sep  6 10:34:33 1998
@@ -53,9 +53,6 @@
 {
 	unsigned long pld;
 	unsigned int i;
-	unsigned long flags;
-
-	save_and_cli(flags);
 
 	/* Read the interrupt summary registers of NORITAKE */
 	pld = ((unsigned long) inw(0x54c) << 32) |
@@ -76,16 +73,13 @@
 			handle_irq(i, i, regs);
 		}
 	}
-	restore_flags(flags);
 }
 
 static void 
 noritake_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
 {
 	int irq, ack;
-	unsigned long flags;
 
-	__save_and_cli(flags);
 	ack = irq = (vector - 0x800) >> 4;
 
 	/*
@@ -101,7 +95,6 @@
 		ack = irq = irq + 1;
 
 	handle_irq(irq, ack, regs);
-	__restore_flags(flags);
 }
 
 static void __init
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/kernel/sys_rawhide.c linux/arch/alpha/kernel/sys_rawhide.c
--- v2.1.120/linux/arch/alpha/kernel/sys_rawhide.c	Tue Aug 18 22:02:02 1998
+++ linux/arch/alpha/kernel/sys_rawhide.c	Sun Sep  6 10:34:33 1998
@@ -60,9 +60,7 @@
 rawhide_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
 {
 	int irq, ack;
-	unsigned long flags;
 
-	__save_and_cli(flags);
 	ack = irq = (vector - 0x800) >> 4;
 
         /*
@@ -84,7 +82,6 @@
 	}
 
 	handle_irq(irq, ack, regs);
-	__restore_flags(flags);
 }
 
 static void __init
@@ -162,7 +159,7 @@
 static void __init
 rawhide_pci_fixup(void)
 {
-	mcpcia_pci_fixup();
+	layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE);
 	common_pci_fixup(rawhide_map_irq, common_swizzle);
 }
 
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/kernel/sys_ruffian.c linux/arch/alpha/kernel/sys_ruffian.c
--- v2.1.120/linux/arch/alpha/kernel/sys_ruffian.c	Tue Aug 18 22:02:02 1998
+++ linux/arch/alpha/kernel/sys_ruffian.c	Tue Sep  8 23:20:41 1998
@@ -8,7 +8,6 @@
  * Code supporting the RUFFIAN.
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/mm.h>
@@ -31,7 +30,6 @@
 #include "bios32.h"
 #include "machvec.h"
 
-
 static void
 ruffian_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
 {
@@ -75,9 +73,6 @@
 {
 	unsigned long pld;
 	unsigned int i;
-	unsigned long flags;
-
-        save_and_cli(flags);
 
 	/* Read the interrupt summary register of PYXIS */
 	pld = *(vulp)PYXIS_INT_REQ;
@@ -112,7 +107,7 @@
 			if (j == 7 && !(inb(0x20) & 0x80)) {
 				/* It's only a passive release... */
 			} else if (j == 0) {
-				timer_interrupt(regs);
+				timer_interrupt(0, NULL, regs);
 				ruffian_ack_irq(0);
 			} else {
 				handle_irq(j, j, regs);
@@ -125,7 +120,6 @@
                 *(vulp)PYXIS_INT_REQ = 1UL << i; mb();
                 *(vulp)PYXIS_INT_REQ; /* read to force the write */
 	}
-	restore_flags(flags);
 }
 
 static void __init
@@ -167,13 +161,13 @@
 
 /*
  * For RUFFIAN, we do not want to make any modifications to the PCI
- * setup.  So just scan the busses.
+ * setup.  But we may need to do some kind of init.
  */
 
 static void __init
 ruffian_pci_fixup(void)
 {
-	layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE);
+	/* layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE); */
 }
 
 
@@ -194,7 +188,7 @@
     
 	/* Check BANK_ENABLE */
 	if (bank & 0x01) {
-		static unsigned long size[] __initdata = {
+		static unsigned long size[] __initlocaldata = {
 			0x40000000UL, /* 0x00,   1G */ 
 			0x20000000UL, /* 0x02, 512M */
 			0x10000000UL, /* 0x04, 256M */
@@ -227,7 +221,6 @@
 	pyxis_finish_init_arch();
 }
 
-
 static void
 ruffian_init_pit (void)
 {
@@ -236,20 +229,31 @@
 	init_pit_rest();
 }
 
+static void
+ruffian_kill_arch (int mode, char *reboot_cmd)
+{
+	/* Perhaps this works for other PYXIS as well?  */
+	*(vuip) PYXIS_RESET = 0x0000dead;
+	mb();
+
+	generic_kill_arch(mode, reboot_cmd);
+}
+
 
 /*
  * The System Vector
  */
 
-#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_RUFFIAN)
 struct alpha_machine_vector ruffian_mv __initmv = {
 	vector_name:		"Ruffian",
 	DO_EV5_MMU,
-	DO_DEFAULT_RTC,
-	DO_PYXIS_IO,
+	/* RUFFIAN always uses BCD, like a PeeCee.  */
+	rtc_port: 0x70, rtc_addr: 0x80, rtc_bcd: 1,
+	/* For the moment, do not use BWIO on RUFFIAN.  */
+	IO(PYXIS,pyxis,pyxis),
 	DO_PYXIS_BUS,
 	machine_check:		pyxis_machine_check,
-	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
+	max_dma_address:	ALPHA_RUFFIAN_MAX_DMA_ADDRESS,
 
 	nr_irqs:		48,
 	irq_probe_mask:		RUFFIAN_PROBE_MASK,
@@ -261,7 +265,6 @@
 	init_irq:		ruffian_init_irq,
 	init_pit:		ruffian_init_pit,
 	pci_fixup:		ruffian_pci_fixup,
-	kill_arch:		generic_kill_arch,
+	kill_arch:		ruffian_kill_arch,
 };
 ALIAS_MV(ruffian)
-#endif
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/kernel/sys_sable.c linux/arch/alpha/kernel/sys_sable.c
--- v2.1.120/linux/arch/alpha/kernel/sys_sable.c	Tue Aug 18 22:02:02 1998
+++ linux/arch/alpha/kernel/sys_sable.c	Sun Sep  6 10:34:33 1998
@@ -117,9 +117,7 @@
 	   normal IRQs.  */
 
 	int irq, ack;
-	unsigned long flags;
 
-	__save_and_cli(flags);
 	ack = irq = (vector - 0x800) >> 4;
 
 	irq = sable_irq_swizzle.mask_to_irq[(ack)];
@@ -131,7 +129,6 @@
 #endif
 
 	handle_irq(irq, ack, regs);
-	__restore_flags(flags);
 }
 
 static void __init
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/kernel/sys_sx164.c linux/arch/alpha/kernel/sys_sx164.c
--- v2.1.120/linux/arch/alpha/kernel/sys_sx164.c	Tue Aug 18 22:02:02 1998
+++ linux/arch/alpha/kernel/sys_sx164.c	Sun Sep  6 10:34:33 1998
@@ -68,9 +68,6 @@
 {
 	unsigned long pld, tmp;
 	unsigned int i;
-	unsigned long flags;
-
-	save_and_cli(flags);
 
 	/* Read the interrupt summary register of PYXIS */
 	pld = *(vulp)PYXIS_INT_REQ;
@@ -101,14 +98,12 @@
 		*(vulp)PYXIS_INT_REQ = 1UL << i; mb();
 		tmp = *(vulp)PYXIS_INT_REQ;
 	}
-	restore_flags(flags);
 }
 
 static void
 sx164_init_irq(void)
 {
-	outb(0, DMA1_RESET_REG);
-	outb(0, DMA2_RESET_REG);
+	STANDARD_INIT_IRQ_PROLOG;
 
 	if (alpha_using_srm) {
 		alpha_mv.update_irq_hw = sx164_srm_update_irq_hw;
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/kernel/sys_takara.c linux/arch/alpha/kernel/sys_takara.c
--- v2.1.120/linux/arch/alpha/kernel/sys_takara.c	Tue Aug 18 22:02:02 1998
+++ linux/arch/alpha/kernel/sys_takara.c	Sun Sep  6 10:34:33 1998
@@ -39,11 +39,8 @@
 static void
 takara_device_interrupt(unsigned long vector, struct pt_regs *regs)
 {
-	unsigned long flags;
 	unsigned intstatus;
 
-	save_and_cli(flags);
-
 	/*
 	 * The PALcode will have passed us vectors 0x800 or 0x810,
 	 * which are fairly arbitrary values and serve only to tell
@@ -73,8 +70,6 @@
 		if (intstatus & 1) handle_irq(16+0, 16+0, regs);
 	} else
 		isa_device_interrupt (vector, regs);
-
-	restore_flags(flags);
 }
 
 static void __init
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/kernel/time.c linux/arch/alpha/kernel/time.c
--- v2.1.120/linux/arch/alpha/kernel/time.c	Wed Jun 24 22:54:03 1998
+++ linux/arch/alpha/kernel/time.c	Sun Sep  6 10:34:33 1998
@@ -25,6 +25,7 @@
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/delay.h>
+#include <linux/ioport.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -33,14 +34,14 @@
 #include <linux/mc146818rtc.h>
 #include <linux/timex.h>
 
+#include "proto.h"
+
 #ifdef CONFIG_RTC 
 #define TIMER_IRQ 0  /* using pit for timer */
 #else 
 #define TIMER_IRQ 8  /* using rtc for timer */
 #endif
 
-extern struct hwrpb_struct *hwrpb;
-
 static int set_rtc_mmss(unsigned long);
 
 
@@ -156,7 +157,71 @@
 	  )*60 + sec; /* finally seconds */
 }
 
-void time_init(void)
+/*
+ * Initialize Programmable Interval Timers with standard values.  Some
+ * drivers depend on them being initialized (e.g., joystick driver).
+ */
+
+/* It is (normally) only counter 1 that presents config problems, so
+   provide this support function to do the rest of the job.  */
+
+void inline
+init_pit_rest(void)
+{
+#if 0
+	/* Leave refresh timer alone---nobody should depend on a
+	   particular value anyway. */
+	outb(0x54, 0x43);	/* counter 1: refresh timer */
+	outb(0x18, 0x41);
+#endif
+
+	outb(0xb6, 0x43);	/* counter 2: speaker */
+	outb(0x31, 0x42);
+	outb(0x13, 0x42);
+}
+
+#ifdef CONFIG_RTC
+static inline void
+rtc_init_pit (void)
+{
+	/* Setup interval timer if /dev/rtc is being used */
+	outb(0x34, 0x43);		/* binary, mode 2, LSB/MSB, ch 0 */
+	outb(LATCH & 0xff, 0x40);	/* LSB */
+	outb(LATCH >> 8, 0x40);		/* MSB */
+	request_region(0x40, 0x20, "timer"); /* reserve pit */
+
+	init_pit_rest();
+}
+#endif
+
+void
+generic_init_pit (void)
+{
+	int x;
+	if ((x = (CMOS_READ(RTC_FREQ_SELECT) & 0x3f)) != 0x26) {
+		printk("Setting RTC_FREQ to 1024 Hz (%x)\n", x);
+		CMOS_WRITE(0x26, RTC_FREQ_SELECT);
+	}
+	request_region(RTC_PORT(0), 0x10, "timer"); /* reserve rtc */
+
+	/* Turn off the PIT.  */
+	outb(0x36, 0x43);	/* counter 0: system timer */
+	outb(0x00, 0x40);
+	outb(0x00, 0x40);
+
+	init_pit_rest();
+}
+
+/* This probably isn't Right, but it is what the old code did.  */
+#if defined(CONFIG_RTC)
+# define init_pit	rtc_init_pit
+#else
+# define init_pit	alpha_mv.init_pit
+#endif
+
+
+void
+time_init(void)
 {
 #ifdef CONFIG_RTC
 	unsigned char save_control;
@@ -164,6 +229,9 @@
         void (*irq_handler)(int, void *, struct pt_regs *);
 	unsigned int year, mon, day, hour, min, sec, cc1, cc2;
 
+	/* Initialize the timers.  */
+	init_pit();
+
 	/*
 	 * The Linux interpretation of the CMOS clock register contents:
 	 * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
@@ -179,7 +247,7 @@
 	/* If our cycle frequency isn't valid, go another round and give
 	   a guess at what it should be.  */
 	if (hwrpb->cycle_freq == 0) {
-		printk("HWPRB cycle frequency bogus.  Estimating... ");
+		printk("HWRPB cycle frequency bogus.  Estimating... ");
 
 		do { } while (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP));
 		do { } while (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
@@ -258,7 +326,8 @@
  * part.  So we can't do the "find absolute time in terms of cycles" thing
  * that the other ports do.
  */
-void do_gettimeofday(struct timeval *tv)
+void
+do_gettimeofday(struct timeval *tv)
 {
 	unsigned long flags, now, delta_cycles, delta_usec;
 	unsigned long sec, usec;
@@ -296,7 +365,8 @@
 	tv->tv_usec = usec;
 }
 
-void do_settimeofday(struct timeval *tv)
+void
+do_settimeofday(struct timeval *tv)
 {
 	cli();
 	xtime = *tv;
@@ -314,7 +384,8 @@
  * jump to the next second precisely 500 ms later. Check the Motorola
  * MC146818A or Dallas DS12887 data sheet for details.
  */
-static int set_rtc_mmss(unsigned long nowtime)
+static int
+set_rtc_mmss(unsigned long nowtime)
 {
 	int retval = 0;
 	int real_seconds, real_minutes, cmos_minutes;
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/lib/io.c linux/arch/alpha/lib/io.c
--- v2.1.120/linux/arch/alpha/lib/io.c	Tue Aug 18 22:02:02 1998
+++ linux/arch/alpha/lib/io.c	Sun Sep  6 10:34:33 1998
@@ -477,7 +477,8 @@
 		count -= 4;
 	}
 
-	/* Handle all full-sized quadwords: we're aligned (or have a small count) */
+	/* Handle all full-sized quadwords: we're aligned
+	   (or have a small count) */
 	count -= 8;
 	if (count >= 0) {
 		do {
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/lib/stackcheck.S linux/arch/alpha/lib/stackcheck.S
--- v2.1.120/linux/arch/alpha/lib/stackcheck.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/alpha/lib/stackcheck.S	Sun Sep  6 10:34:33 1998
@@ -0,0 +1,27 @@
+/*
+ * arch/alpha/lib/stackcheck.S
+ * Contributed by Richard Henderson (rth@tamu.edu)
+ *
+ * Verify that we have not overflowed the stack.  Oops if we have.
+ */
+
+#include <asm/asm_offsets.h>
+
+	.text
+	.set noat
+
+	.align 3
+	.globl _mcount
+	.ent _mcount
+_mcount:
+	.frame $30, 0, $28, 0
+	.prologue 0
+
+	lda	$0, TASK_SIZE($8)
+	cmpult	$30, $0, $0
+	bne	$0, 1f
+	ret	($28)
+1:	stq	$31, -8($31)	# oops me, damn it.
+	br	1b
+
+	.end _mcount
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/lib/stackkill.S linux/arch/alpha/lib/stackkill.S
--- v2.1.120/linux/arch/alpha/lib/stackkill.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/alpha/lib/stackkill.S	Sun Sep  6 10:34:33 1998
@@ -0,0 +1,35 @@
+/*
+ * arch/alpha/lib/killstack.S
+ * Contributed by Richard Henderson (rth@cygnus.com)
+ *
+ * Clobber the balance of the kernel stack, hoping to catch
+ * uninitialized local variables in the act.
+ */
+
+#include <asm/asm_offsets.h>
+
+	.text
+	.set noat
+
+	.align 5
+	.globl _mcount
+	.ent _mcount
+_mcount:
+	.frame $30, 0, $28, 0
+	.prologue 0
+
+	ldi	$0, 0xdeadbeef
+	lda	$2, -STACK_SIZE
+	sll	$0, 32, $1
+	and	$30, $2, $2
+	or	$0, $1, $0
+	lda	$2, TASK_SIZE($2)
+	cmpult	$2, $30, $1
+	beq	$1, 2f
+1:	stq	$0, 0($2)
+	addq	$2, 8, $2
+	cmpult	$2, $30, $1
+	bne	$1, 1b
+2:	ret	($28)
+
+	.end _mcount
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/lib/stacktrace.c linux/arch/alpha/lib/stacktrace.c
--- v2.1.120/linux/arch/alpha/lib/stacktrace.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/alpha/lib/stacktrace.c	Sun Sep  6 10:34:33 1998
@@ -0,0 +1,103 @@
+#include <linux/kernel.h>
+#include <asm/system.h>
+
+typedef unsigned int instr;
+
+#define MAJOR_OP	0xfc000000
+#define LDA_OP		0x20000000
+#define STQ_OP		0xb4000000
+#define BR_OP		0xc0000000
+
+#define STK_ALLOC_1	0x23de8000 /* lda $30,-X($30) */
+#define STK_ALLOC_1M	0xffff8000
+#define STK_ALLOC_2	0x43c0153e /* subq $30,X,$30 */
+#define STK_ALLOC_2M	0xffe01fff
+
+#define MEM_REG		0x03e00000
+#define MEM_BASE	0x001f0000
+#define MEM_OFF		0x0000ffff
+#define MEM_OFF_SIGN	0x00008000
+#define	BASE_SP		0x001e0000
+
+#define STK_ALLOC_MATCH(INSTR)			\
+  (((INSTR) & STK_ALLOC_1M) == STK_ALLOC_1	\
+   || ((INSTR) & STK_ALLOC_2M) == STK_ALLOC_2)
+#define STK_PUSH_MATCH(INSTR) \
+  (((INSTR) & (MAJOR_OP | MEM_BASE | MEM_OFF_SIGN)) == (STQ_OP | BASE_SP))
+#define MEM_OP_OFFSET(INSTR) \
+  (((long)((INSTR) & MEM_OFF) << 48) >> 48)
+#define MEM_OP_REG(INSTR) \
+  (((INSTR) & MEM_REG) >> 22)
+
+/* Branches, jumps, PAL calls, and illegal opcodes end a basic block. */
+#define BB_END(INSTR)						\
+  (((instr)(INSTR) >= BR_OP) | ((instr)(INSTR) < LDA_OP) |	\
+   ((((instr)(INSTR) ^ 0x60000000) < 0x20000000) &		\
+    (((instr)(INSTR) & 0x0c000000) != 0)))
+
+#define IS_KERNEL_TEXT(PC) ((unsigned long)(PC) > START_ADDR)
+
+static char reg_name[][4] = {
+	"v0 ", "t0 ", "t1 ", "t2 ", "t3 ", "t4 ", "t5 ", "t6 ", "t7 ",
+	"s0 ", "s1 ", "s2 ", "s3 ", "s4 ", "s5 ", "s6 ", "a0 ", "a1 ",
+	"a2 ", "a3 ", "a4 ", "a5 ", "t8 ", "t9 ", "t10", "t11", "ra ",
+	"pv ", "at ", "gp ", "sp ", "0"
+};
+
+
+static instr *
+display_stored_regs(instr * pro_pc, unsigned char * sp)
+{
+	instr * ret_pc = 0;
+	int reg;
+	unsigned long value;
+
+	printk("Prologue [<%p>], Frame %p:\n", pro_pc, sp);
+	while (!BB_END(*pro_pc))
+		if (STK_PUSH_MATCH(*pro_pc)) {
+			reg = (*pro_pc & MEM_REG) >> 21;
+			value = *(unsigned long *)(sp + (*pro_pc & MEM_OFF));
+			if (reg == 26)
+				ret_pc = (instr *)value;
+			printk("\t\t%s / 0x%016lx\n", reg_name[reg], value);
+		}
+	return ret_pc;
+}
+
+static instr *
+seek_prologue(instr * pc)
+{
+	while (!STK_ALLOC_MATCH(*pc))
+		--pc;
+	while (!BB_END(*(pc - 1)))
+		--pc;
+	return pc;
+}
+
+static long
+stack_increment(instr * prologue_pc)
+{
+	while (!STK_ALLOC_MATCH(*prologue_pc))
+		++prologue_pc;
+
+	/* Count the bytes allocated. */
+	if ((*prologue_pc & STK_ALLOC_1M) == STK_ALLOC_1M)
+		return -(((long)(*prologue_pc) << 48) >> 48);
+	else
+		return (*prologue_pc >> 13) & 0xff;
+}
+
+void
+stacktrace(void)
+{
+	instr * ret_pc;
+	instr * prologue = (instr *)stacktrace;
+	register unsigned char * sp __asm__ ("$30");
+
+	printk("\tstack trace:\n");
+	do {
+		ret_pc = display_stored_regs(prologue, sp);
+		sp += stack_increment(prologue);
+		prologue = seek_prologue(ret_pc);
+	} while (IS_KERNEL_TEXT(ret_pc));
+}
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/math-emu/ieee-math.c linux/arch/alpha/math-emu/ieee-math.c
--- v2.1.120/linux/arch/alpha/math-emu/ieee-math.c	Sat May  2 14:19:52 1998
+++ linux/arch/alpha/math-emu/ieee-math.c	Sun Sep  6 10:34:33 1998
@@ -786,13 +786,11 @@
 		break;
 
 	      case ROUND_PINF:
-		if ((temp.f[0] & 0x007fffffffffffff) != 0)
-			++b;
+		b += ((temp.f[0] & 0x007fffffffffffff) != 0 && !temp.s);
 		break;
 
 	      case ROUND_NINF:
-		if ((temp.f[0] & 0x007fffffffffffff) != 0)
-			--b;
+		b += ((temp.f[0] & 0x007fffffffffffff) != 0 && temp.s);
 		break;
 
 	      case ROUND_CHOP:
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/mm/fault.c linux/arch/alpha/mm/fault.c
--- v2.1.120/linux/arch/alpha/mm/fault.c	Tue Aug 18 22:02:02 1998
+++ linux/arch/alpha/mm/fault.c	Wed Sep  9 08:56:58 1998
@@ -14,7 +14,6 @@
 #undef  __EXTERN_INLINE
 
 #include <linux/signal.h>
-#include <linux/head.h>
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/types.h>
diff -u --recursive --new-file v2.1.120/linux/arch/alpha/mm/init.c linux/arch/alpha/mm/init.c
--- v2.1.120/linux/arch/alpha/mm/init.c	Tue Aug 18 22:02:02 1998
+++ linux/arch/alpha/mm/init.c	Wed Sep  9 08:56:58 1998
@@ -7,7 +7,6 @@
 #include <linux/config.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
-#include <linux/head.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/string.h>
@@ -16,6 +15,9 @@
 #include <linux/mman.h>
 #include <linux/mm.h>
 #include <linux/swap.h>
+#ifdef CONFIG_BLK_DEV_INITRD
+#include <linux/blk.h>
+#endif
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -23,6 +25,8 @@
 #include <asm/hwrpb.h>
 #include <asm/dma.h>
 
+#define DEBUG_POISON 0
+
 extern void die_if_kernel(char *,struct pt_regs *,long);
 extern void show_net_buffers(void);
 
@@ -259,6 +263,29 @@
 }
 #endif /* __SMP__ */
 
+#if DEBUG_POISON
+static void
+kill_page(unsigned long pg)
+{
+	unsigned long *p = (unsigned long *)pg;
+	unsigned long i = PAGE_SIZE, v = 0xdeadbeefdeadbeef;
+	do {
+		p[0] = v;
+		p[1] = v;
+		p[2] = v;
+		p[3] = v;
+		p[4] = v;
+		p[5] = v;
+		p[6] = v;
+		p[7] = v;
+		i -= 64;
+		p += 8;
+	} while (i != 0);
+}
+#else
+#define kill_page(pg)
+#endif
+
 void
 mem_init(unsigned long start_mem, unsigned long end_mem)
 {
@@ -284,6 +311,11 @@
 		if (PageReserved(mem_map+MAP_NR(tmp)))
 			continue;
 		atomic_set(&mem_map[MAP_NR(tmp)].count, 1);
+#ifdef CONFIG_BLK_DEV_INITRD
+		if (initrd_start && tmp >= initrd_start && tmp < initrd_end)
+			continue;
+#endif
+		kill_page(tmp);
 		free_page(tmp);
 	}
 	tmp = nr_free_pages << PAGE_SHIFT;
@@ -301,6 +333,7 @@
 	for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
 		mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
 		atomic_set(&mem_map[MAP_NR(addr)].count, 1);
+		kill_page(addr);
 		free_page(addr);
 	}
 	printk ("Freeing unused kernel memory: %ldk freed\n",
diff -u --recursive --new-file v2.1.120/linux/arch/arm/Makefile linux/arch/arm/Makefile
--- v2.1.120/linux/arch/arm/Makefile	Tue Jul 21 00:15:29 1998
+++ linux/arch/arm/Makefile	Sun Sep  6 10:44:47 1998
@@ -157,13 +157,17 @@
 CORE_FILES	:= arch/arm/kernel/kernel.o arch/arm/mm/mm.o $(CORE_FILES)
 LIBS		:= arch/arm/lib/lib.a $(LIBS) $(GCCLIB)
 
-BLOCK_DRIVERS	:= arch/arm/drivers/block/block.a
+BLOCK_DRIVERS	:= drivers/block/block.a
 CDROM_DRIVERS	:= drivers/cdrom/cdrom.a
 ifeq ($(CONFIG_FB),y)
 CHAR_DRIVERS	:= arch/arm/drivers/char1/char.a
 else
+ifeq ($(CONFIG_VGA_CONSOLE),y)
+CHAR_DRIVERS	:= arch/arm/drivers/char1/char.a
+else
 CHAR_DRIVERS	:= arch/arm/drivers/char/char.a
 endif
+endif
 MISC_DRIVERS	:= drivers/misc/misc.a
 NET_DRIVERS	:= drivers/net/net.a
 PARIDE_DRIVERS	:= drivers/block/paride/paride.a
@@ -171,6 +175,7 @@
 SCSI_DRIVERS	:= drivers/scsi/scsi.a
 SOUND_DRIVERS	:= drivers/sound/sound.a
 VIDEO_DRIVERS	:= drivers/video/video.a
+PNP_DRIVERS	:= drivers/pnp/pnp.a
 
 ifeq ($(CONFIG_ARCH_ACORN),y)
 BLOCK_DRIVERS	+= drivers/acorn/block/acorn-block.a
@@ -183,6 +188,10 @@
 
 ifeq ($(CONFIG_FB),y)
 DRIVERS		:= $(DRIVERS) $(VIDEO_DRIVERS)
+else
+ifeq ($(CONFIG_VGA_CONSOLE),y)
+DRIVERS		:= $(DRIVERS) $(VIDEO_DRIVERS)
+endif
 endif
 ifeq ($(CONFIG_SCSI),y)
 DRIVERS		:= $(DRIVERS) $(SCSI_DRIVERS)
@@ -198,6 +207,9 @@
 endif
 ifeq ($(CONFIG_PARIDE),y)
 DRIVERS		:= $(DRIVERS) $(PARIDE_DRIVERS)
+endif
+ifdef CONFIG_PNP
+DRIVERS		:= $(DRIVERS) $(PNP_DRIVERS)
 endif
 
 symlinks::
diff -u --recursive --new-file v2.1.120/linux/arch/arm/boot/compressed/misc.c linux/arch/arm/boot/compressed/misc.c
--- v2.1.120/linux/arch/arm/boot/compressed/misc.c	Tue Jul 21 00:15:30 1998
+++ linux/arch/arm/boot/compressed/misc.c	Sun Sep  6 10:44:47 1998
@@ -203,11 +203,13 @@
 
 static void gzip_mark(void **ptr)
 {
+	arch_decomp_wdog();
 	*ptr = (void *) free_mem_ptr;
 }
 
 static void gzip_release(void **ptr)
 {
+	arch_decomp_wdog();
 	free_mem_ptr = (long) *ptr;
 }
 #else
diff -u --recursive --new-file v2.1.120/linux/arch/arm/config.in linux/arch/arm/config.in
--- v2.1.120/linux/arch/arm/config.in	Thu Aug  6 14:06:28 1998
+++ linux/arch/arm/config.in	Sun Sep  6 10:44:47 1998
@@ -8,19 +8,40 @@
 
 mainmenu_option next_comment
 comment 'System and processor type'
+
 choice 'ARM system type'	\
 	"Archimedes		CONFIG_ARCH_ARC \
 	 A5000			CONFIG_ARCH_A5K \
 	 RiscPC			CONFIG_ARCH_RPC \
 	 EBSA-110		CONFIG_ARCH_EBSA110 \
 	 EBSA-285		CONFIG_ARCH_EBSA285 \
-	 NexusPCI		CONFIG_ARCH_NEXUSPCI" RiscPC
-if [ "$CONFIG_ARCH_ARC" = "y" -o "$CONFIG_ARCH_A5K" = "y" -o "$CONFIG_ARCH_RPC" = "y" ]; then
+	 NexusPCI		CONFIG_ARCH_NEXUSPCI \
+	 Corel-VNC		CONFIG_ARCH_VNC \
+	 Tbox			CONFIG_ARCH_TBOX" RiscPC
+
+if [ "$CONFIG_ARCH_EBSA285" = "y" ]; then
+  bool '  Include support for CATS boards' CONFIG_CATS
+fi
+
+# Select various configuration options depending on the machine type
+#  Easy check for Acorn-style architectures
+
+if [ "$CONFIG_ARCH_ARC" = "y" -o \
+     "$CONFIG_ARCH_A5K" = "y" -o \
+     "$CONFIG_ARCH_RPC" = "y" ]; then
   define_bool CONFIG_ARCH_ACORN y
 else
   define_bool CONFIG_ARCH_ACORN n
 fi
-if [ "$CONFIG_ARCH_NEXUSPCI" = "y" ]; then
+
+if [ "$CONFIG_ARCH_TBOX" = "y" ]; then
+  define_bool CONFIG_BUS_I2C y
+fi
+
+#  These machines have PCI/may have PCI
+
+if [ "$CONFIG_ARCH_NEXUSPCI" = "y" -o \
+     "$CONFIG_ARCH_VNC" = "y" ]; then
   define_bool CONFIG_PCI y
 else
   if [ "$CONFIG_ARCH_EBSA285" = "y" ]; then
@@ -32,20 +53,19 @@
 # ever built a machine that can take both, and now that ARM3 is obsolete
 # nobody is likely to either.
 
-if [ "$CONFIG_ARCH_RPC" = "y" -o "$CONFIG_ARCH_NEXUSPCI" = "y" -o "$CONFIG_ARCH_EBSA110" = "y" -o "$CONFIG_ARCH_EBSA285" = "y" ]; then
+if [ "$CONFIG_ARCH_ARC" = "y" -o \
+     "$CONFIG_ARCH_A5K" = "y" ]; then
+  define_bool CONFIG_CPU_32 n
+  define_bool CONFIG_CPU_26 y
+else
   define_bool CONFIG_CPU_32 y
   define_bool CONFIG_CPU_26 n
-else
-  if [ "$CONFIG_ARCH_ARC" = "y" -o "$CONFIG_ARCH_A5K" = "y" ]; then
-    define_bool CONFIG_CPU_32 n
-    define_bool CONFIG_CPU_26 y
-  fi
 fi
 
 # Now allow the user to choose a more precise CPU.  This is only used to set
 # the flags we pass to GCC, not in any code.
 
-choice 'Optimise for CPU'		\
+choice 'Optimise for CPU'				\
 	"ARM2		CONFIG_CPU_ARM2 \
 	 ARM3		CONFIG_CPU_ARM3 \
 	 ARM6		CONFIG_CPU_ARM6 \
@@ -92,8 +112,8 @@
 
 tristate 'Parallel port support' CONFIG_PARPORT
 if [ "$CONFIG_PARPORT" != "n" ]; then
-  dep_tristate '  PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT
   dep_tristate '  Archimedes hardware' CONFIG_PARPORT_ARC $CONFIG_PARPORT
+  dep_tristate '  PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT
 # If exactly one hardware type is selected then parport will optimise away
 # support for loading any others.  Defeat this if the user is keen.
   if [ "$CONFIG_PARPORT_PC" = "n" -o "$CONFIG_PARPORT_ARC" = "n" ]; then
@@ -104,16 +124,29 @@
 fi
 endmenu
 
-source arch/arm/drivers/block/Config.in
-source drivers/acorn/block/Config.in
+source drivers/pnp/Config.in
+
+source drivers/block/Config.in
+
+if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
+  source drivers/acorn/block/Config.in
+fi
 
 source arch/arm/drivers/char/Config.in
 
-mainmenu_option next_comment
-comment 'Console drivers'
-bool 'Support Frame buffer devices' CONFIG_FB
-source drivers/video/Config.in
-endmenu
+if [ "$CONFIG_VT" = "y" ]; then
+  mainmenu_option next_comment
+  comment 'Console drivers'
+  if [ "$CONFIG_ARCH_ACORN" != "y" -a "$CONFIG_ARCH_EBSA110" != "y" ]; then
+    bool 'VGA text console' CONFIG_VGA_CONSOLE
+    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      bool 'Video mode selection support' CONFIG_VIDEO_SELECT
+    fi
+  fi
+  bool 'Support Frame buffer devices' CONFIG_FB
+  source drivers/video/Config.in
+  endmenu
+fi
 
 if [ "$CONFIG_NET" = "y" ]; then
   source net/Config.in
@@ -140,7 +173,7 @@
 fi
 endmenu
 
-if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
+if [ "$CONFIG_ARCH_ACORN" = "y" -o "$CONFIG_PCI" = "y" ]; then
   mainmenu_option next_comment
   comment 'Sound'
 
diff -u --recursive --new-file v2.1.120/linux/arch/arm/kernel/Makefile linux/arch/arm/kernel/Makefile
--- v2.1.120/linux/arch/arm/kernel/Makefile	Fri May  8 23:14:41 1998
+++ linux/arch/arm/kernel/Makefile	Sun Sep  6 10:44:47 1998
@@ -9,7 +9,8 @@
 ENTRY_OBJ = entry-$(PROCESSOR).o
 
 O_TARGET := kernel.o
-O_OBJS   := $(ENTRY_OBJ) ioport.o irq.o process.o ptrace.o signal.o sys_arm.o time.o traps.o
+O_OBJS   := $(ENTRY_OBJ) ioport.o irq.o process.o ptrace.o setup.o \
+	    signal.o sys_arm.o time.o traps.o fiq.o
 
 all: lib kernel.o $(HEAD_OBJ) init_task.o
 
@@ -20,7 +21,7 @@
 endif
 
 ifdef CONFIG_ARCH_ACORN
-  O_OBJS += setup.o ecard.o iic.o
+  O_OBJS += ecard.o iic.o
   ifdef CONFIG_ARCH_ARC
     O_OBJS += oldlatches.o
   endif
@@ -29,25 +30,26 @@
 endif
 
 ifeq ($(MACHINE),ebsa110)
-  O_OBJS += setup-ebsa110.o dma-dummy.o
+  O_OBJS += dma-dummy.o leds-ebsa110.o
 endif
 
 ifeq ($(MACHINE),ebsa285)
-  O_OBJS += dma-dummy.o leds-ebsa285.o setup-ebsa110.o
+  OX_OBJS += dma.o
+  O_OBJS += dma-ebsa285.o leds-ebsa285.o
   ifdef CONFIG_PCI
     O_OBJS += dec21285.o
   endif
 endif
 
 ifeq ($(MACHINE),nexuspci)
-  O_OBJS += setup-ebsa110.o dma-dummy.o
+  O_OBJS += dma-dummy.o
   ifdef CONFIG_PCI
     O_OBJS += plx9080.o
   endif
 endif
 
 $(HEAD_OBJ): $(HEAD_OBJ:.o=.S)
-	$(CC) -D__ASSEMBLY__ -traditional -c $(HEAD_OBJ:.o=.S) -o $@
+	$(CC) -D__ASSEMBLY__ -DTEXTADDR=$(TEXTADDR) -traditional -c $(HEAD_OBJ:.o=.S) -o $@
 
 $(ENTRY_OBJ): $(ENTRY_OBJ:.o=.S)
 	$(CC) $(CFLAGS) -D__ASSEMBLY__ -c $(ENTRY_OBJ:.o=.S) -o $@
diff -u --recursive --new-file v2.1.120/linux/arch/arm/kernel/armksyms.c linux/arch/arm/kernel/armksyms.c
--- v2.1.120/linux/arch/arm/kernel/armksyms.c	Tue Jul 21 00:15:30 1998
+++ linux/arch/arm/kernel/armksyms.c	Sun Sep  6 10:44:47 1998
@@ -12,10 +12,13 @@
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/pgtable.h>
+#include <asm/system.h>
 #include <asm/uaccess.h>
 
 extern void dump_thread(struct pt_regs *, struct user *);
 extern int dump_fpu(struct pt_regs *, struct user_fp_struct *);
+extern void inswb(unsigned int port, void *to, int len);
+extern void outswb(unsigned int port, const void *to, int len);
 
 /*
  * libgcc functions - functions that are used internally by the
@@ -40,33 +43,27 @@
 extern void __umoddi3(void);
 extern void __umodsi3(void);
 
-extern void inswb(unsigned int port, void *to, int len);
-extern void outswb(unsigned int port, const void *to, int len);
-
-/*
- * floating point math emulator support.
- * These will not change.  If they do, then a new version
- * of the emulator will have to be compiled...
- * fp_current is never actually dereferenced - it is just
- * used as a pointer to pass back for send_sig().
- */
-extern void (*fp_save)(unsigned char *);
-extern void (*fp_restore)(unsigned char *);
-extern void fp_setup(void);
-extern void fpreturn(void);
-extern void fpundefinstr(void);
 extern void fp_enter(void);
-extern void fp_printk(void);
-extern struct task_struct *fp_current;
-extern void fp_send_sig(int);
+#define EXPORT_SYMBOL_ALIAS(sym,orig) \
+ const char __kstrtab_##sym##[] __attribute__((section(".kstrtab"))) = \
+    __MODULE_STRING(##sym##); \
+ const struct module_symbol __ksymtab_##sym __attribute__((section("__ksymtab"))) = \
+    { (unsigned long)&##orig, __kstrtab_##sym };
+	/*
+	 * floating point math emulator support.
+	 * These symbols will never change their calling convention...
+	 */
+EXPORT_SYMBOL_ALIAS(kern_fp_enter,fp_enter);
+EXPORT_SYMBOL_ALIAS(fp_printk,printk);
+EXPORT_SYMBOL_ALIAS(fp_send_sig,send_sig);
 
-/* platform dependent support */
+	/* platform dependent support */
 EXPORT_SYMBOL(dump_thread);
 EXPORT_SYMBOL(dump_fpu);
 EXPORT_SYMBOL(udelay);
 EXPORT_SYMBOL(xchg_str);
 
-/* expansion card support */
+	/* expansion card support */
 #ifdef CONFIG_ARCH_ACORN
 EXPORT_SYMBOL(ecard_startfind);
 EXPORT_SYMBOL(ecard_find);
@@ -77,16 +74,17 @@
 EXPORT_SYMBOL(enable_irq);
 EXPORT_SYMBOL(disable_irq);
 
-/* processor dependencies */
+	/* processor dependencies */
 EXPORT_SYMBOL(processor);
+EXPORT_SYMBOL(machine_type);
 
-/* io */
+	/* io */
 EXPORT_SYMBOL(outswb);
 EXPORT_SYMBOL(outsw);
 EXPORT_SYMBOL(inswb);
 EXPORT_SYMBOL(insw);
 
-/* address translation */
+	/* address translation */
 #ifndef __virt_to_phys__is_a_macro
 EXPORT_SYMBOL(__virt_to_phys);
 #endif
@@ -104,27 +102,7 @@
 EXPORT_SYMBOL(__bad_pmd);
 EXPORT_SYMBOL(__bad_pmd_kernel);
 
-#define EXPORT_VERS0(sym,orig) \
- const char __kstrtab_##sym##[] __attribute__((section(".kstrtab"))) = \
-    __MODULE_STRING(##sym##_R00000000); \
- const struct module_symbol __ksymtab_##sym __attribute__((section("__ksymtab"))) = \
-    { (unsigned long)&##orig, __kstrtab_##sym };
-/*
- * floating point math emulator support.
- * These symbols will never change their calling convention...
- */
-EXPORT_VERS0(fpreturn,fpreturn);
-EXPORT_VERS0(fpundefinstr,fpundefinstr);
-EXPORT_VERS0(fp_enter,fp_enter);
-EXPORT_VERS0(fp_save,fp_save);
-EXPORT_VERS0(fp_restore,fp_restore);
-EXPORT_VERS0(fp_setup,fp_setup);
-EXPORT_VERS0(fp_printk,printk);
-EXPORT_VERS0(fp_send_sig,send_sig);
-
-	/*
-	 * string / mem functions
-	 */
+	/* string / mem functions */
 EXPORT_SYMBOL_NOVERS(strcpy);
 EXPORT_SYMBOL_NOVERS(strncpy);
 EXPORT_SYMBOL_NOVERS(strcat);
diff -u --recursive --new-file v2.1.120/linux/arch/arm/kernel/dec21285.c linux/arch/arm/kernel/dec21285.c
--- v2.1.120/linux/arch/arm/kernel/dec21285.c	Thu Aug  6 14:06:28 1998
+++ linux/arch/arm/kernel/dec21285.c	Sun Sep  6 10:44:47 1998
@@ -1,31 +1,42 @@
 /*
  * arch/arm/kernel/dec21285.c: PCI functions for DEC 21285
  *
- * Copyright (C) 1998 Russell King
+ * Copyright (C) 1998 Russell King, Phil Blundell
  */
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/init.h>
 
-int pcibios_present(void)
+#include <asm/system.h>
+
+#define MAX_SLOTS		20
+
+int
+pcibios_present(void)
 {
 	return 1;
 }
 
-static unsigned long pcibios_base_address(unsigned char dev_fn)
+static unsigned long
+pcibios_base_address(unsigned char bus, unsigned char dev_fn)
 {
-	int slot = PCI_SLOT(dev_fn);
-
-	if (slot < 4)
-		return 0xf8000000 + (1 << (19 - slot));
-	else
-		return 0;
+	if (bus == 0) {
+		int slot = PCI_SLOT(dev_fn);
+		
+		if (slot < MAX_SLOTS)
+			return 0xf8c00000 + (slot << 11);
+		else
+			return 0;
+	} else {
+		return 0xf9000000 | (bus << 16) | (dev_fn << 8);
+	}
 }
 
-int pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
-			     unsigned char where, unsigned char *val)
+int
+pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+			 unsigned char where, unsigned char *val)
 {
-	unsigned long addr = pcibios_base_address(dev_fn);
+	unsigned long addr = pcibios_base_address(bus, dev_fn);
 	unsigned char v;
 
 	if (addr)
@@ -38,10 +49,11 @@
 	return PCIBIOS_SUCCESSFUL;
 }
 
-int pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
-			     unsigned char where, unsigned short *val)
+int
+pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+			 unsigned char where, unsigned short *val)
 {
-	unsigned long addr = pcibios_base_address(dev_fn);
+	unsigned long addr = pcibios_base_address(bus, dev_fn);
 	unsigned short v;
 
 	if (addr)
@@ -54,10 +66,11 @@
 	return PCIBIOS_SUCCESSFUL;
 }
 
-int pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
-			      unsigned char where, unsigned int *val)
+int
+pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+			  unsigned char where, unsigned int *val)
 {
-	unsigned long addr = pcibios_base_address(dev_fn);
+	unsigned long addr = pcibios_base_address(bus, dev_fn);
 	unsigned int v;
 
 	if (addr)
@@ -70,10 +83,11 @@
 	return PCIBIOS_SUCCESSFUL;
 }
 
-int pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
-			     unsigned char where, unsigned char val)
+int
+pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+			  unsigned char where, unsigned char val)
 {
-	unsigned long addr = pcibios_base_address(dev_fn);
+	unsigned long addr = pcibios_base_address(bus, dev_fn);
 
 	if (addr)
 		__asm__("str%?b	%0, [%1, %2]"
@@ -81,10 +95,11 @@
 	return PCIBIOS_SUCCESSFUL;
 }
 
-int pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
-			      unsigned char where, unsigned short val)
+int
+pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+			  unsigned char where, unsigned short val)
 {
-	unsigned long addr = pcibios_base_address(dev_fn);
+	unsigned long addr = pcibios_base_address(bus, dev_fn);
 
 	if (addr)
 		__asm__("str%?h	%0, [%1, %2]"
@@ -92,10 +107,11 @@
 	return PCIBIOS_SUCCESSFUL;
 }
 
-int pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
-			       unsigned char where, unsigned int val)
+int
+pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+			   unsigned char where, unsigned int val)
 {
-	unsigned long addr = pcibios_base_address(dev_fn);
+	unsigned long addr = pcibios_base_address(bus, dev_fn);
 
 	if (addr)
 		__asm__("str%?	%0, [%1, %2]"
@@ -103,35 +119,72 @@
 	return PCIBIOS_SUCCESSFUL;
 }
 
-static int irq[] = { 18, 8, 9, 11 };
+static int irqmap_ebsa[] __initdata = { 9, 8, 18, 11 };
+static int irqmap_cats[] __initdata = { 18, 8, 9, 11 };
+
+__initfunc(static int ebsa_irqval(struct pci_dev *dev))
+{
+	unsigned char pin;
+	
+	pcibios_read_config_byte(dev->bus->number,
+				 dev->devfn,
+				 PCI_INTERRUPT_PIN,
+				 &pin);
+	
+	return irqmap_ebsa[(PCI_SLOT(dev->devfn) + pin) & 3];
+}
+
+__initfunc(static int cats_irqval(struct pci_dev *dev))
+{
+	if (dev->irq >= 128)
+		return 32 + (dev->irq & 0x1f);
+
+	switch (dev->irq) {
+	case 1:
+	case 2:
+	case 3:
+	case 4:
+		return irqmap_cats[dev->irq - 1];
+	case 0:
+		return 0;
+	}
+
+	printk("PCI: device %02x:%02x has unknown irq line %x\n",
+	       dev->bus->number, dev->devfn, dev->irq);
+	return 0;
+}
 
 __initfunc(void pcibios_fixup(void))
 {
 	struct pci_dev *dev;
-	unsigned char pin;
-	unsigned int cmd;
+	unsigned char cmd;
 
 	for (dev = pci_devices; dev; dev = dev->next) {
-		pcibios_read_config_byte(dev->bus->number,
-					 dev->devfn,
-					 PCI_INTERRUPT_PIN,
-					 &pin);
-
-		dev->irq = irq[(PCI_SLOT(dev->devfn) + pin) & 3];
-
-		pcibios_write_config_byte(dev->bus->number,
-					  dev->devfn,
-					  PCI_INTERRUPT_LINE,
-					  dev->irq);
+		/* sort out the irq mapping for this device */
+		switch (machine_type) {
+		case MACH_TYPE_EBSA285:
+			dev->irq = ebsa_irqval(dev);
+			break;
+		case MACH_TYPE_CATS:
+			dev->irq = cats_irqval(dev);
+			break;
+		}
+		pcibios_write_config_byte(dev->bus->number, dev->devfn,
+					  PCI_INTERRUPT_LINE, dev->irq);
 
-		printk("PCI: %02x:%02x [%04x/%04x] pin %d irq %d\n",
+		printk(KERN_DEBUG
+		       "PCI: %02x:%02x [%04x/%04x] on irq %d\n",
 			dev->bus->number, dev->devfn,
-			dev->vendor, dev->device,
-			pin, dev->irq);
+			dev->vendor, dev->device, dev->irq);
 
-		/* Turn on bus mastering - boot loader doesn't - perhaps it should! */
-		pcibios_read_config_byte(dev->bus->number, dev->devfn, PCI_COMMAND, &cmd);
-		pcibios_write_config_byte(dev->bus->number, dev->devfn, PCI_COMMAND, cmd | PCI_COMMAND_MASTER);
+		/* Turn on bus mastering - boot loader doesn't
+		 * - perhaps it should! - dag
+		 */
+		pcibios_read_config_byte(dev->bus->number, dev->devfn,
+					 PCI_COMMAND, &cmd);
+		cmd |= PCI_COMMAND_MASTER;
+		pcibios_write_config_byte(dev->bus->number, dev->devfn,
+					  PCI_COMMAND, cmd);
 	}
 }
 
@@ -141,10 +194,16 @@
 
 	rev = *(unsigned char *)0xfe000008;
 	printk("DEC21285 PCI revision %02X\n", rev);
-}
 
-__initfunc(void pcibios_fixup_bus(struct pci_bus *bus))
-{
+	/*
+	 * Map our SDRAM at a known address in PCI space, just in case
+	 * the firmware had other ideas.  Using a nonzero base is slightly
+	 * bizarre but apparently necessary to avoid problems with some
+	 * video cards.
+	 *
+	 * We should really only do this if we are the configuration master.
+	 */
+	*((unsigned long *)0xfe000018) = 0x10000000;
 }
 
 __initfunc(void pcibios_fixup_bus(struct pci_bus *bus))
diff -u --recursive --new-file v2.1.120/linux/arch/arm/kernel/dma-ebsa285.c linux/arch/arm/kernel/dma-ebsa285.c
--- v2.1.120/linux/arch/arm/kernel/dma-ebsa285.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/kernel/dma-ebsa285.c	Tue Sep  8 23:20:41 1998
@@ -0,0 +1,184 @@
+/*
+ * arch/arm/kernel/dma-ebsa285.c
+ *
+ * Copyright (C) 1998 Phil Blundell
+ *
+ * DMA functions specific to EBSA-285/CATS architectures
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/mman.h>
+#include <linux/init.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+
+#include "dma.h"
+
+/* 8237 DMA controllers */
+#define IO_DMA1_BASE	0x00	/* 8 bit slave DMA, channels 0..3 */
+#define IO_DMA2_BASE	0xC0	/* 16 bit master DMA, ch 4(=slave input)..7 */
+
+/* 8237 DMA controller registers */
+#define DMA1_CMD_REG		0x08	/* command register (w) */
+#define DMA1_STAT_REG		0x08	/* status register (r) */
+#define DMA1_REQ_REG            0x09    /* request register (w) */
+#define DMA1_MASK_REG		0x0A	/* single-channel mask (w) */
+#define DMA1_MODE_REG		0x0B	/* mode register (w) */
+#define DMA1_CLEAR_FF_REG	0x0C	/* clear pointer flip-flop (w) */
+#define DMA1_TEMP_REG           0x0D    /* Temporary Register (r) */
+#define DMA1_RESET_REG		0x0D	/* Master Clear (w) */
+#define DMA1_CLR_MASK_REG       0x0E    /* Clear Mask */
+#define DMA1_MASK_ALL_REG       0x0F    /* all-channels mask (w) */
+
+#define DMA2_CMD_REG		0xD0	/* command register (w) */
+#define DMA2_STAT_REG		0xD0	/* status register (r) */
+#define DMA2_REQ_REG            0xD2    /* request register (w) */
+#define DMA2_MASK_REG		0xD4	/* single-channel mask (w) */
+#define DMA2_MODE_REG		0xD6	/* mode register (w) */
+#define DMA2_CLEAR_FF_REG	0xD8	/* clear pointer flip-flop (w) */
+#define DMA2_TEMP_REG           0xDA    /* Temporary Register (r) */
+#define DMA2_RESET_REG		0xDA	/* Master Clear (w) */
+#define DMA2_CLR_MASK_REG       0xDC    /* Clear Mask */
+#define DMA2_MASK_ALL_REG       0xDE    /* all-channels mask (w) */
+
+int arch_request_dma(dmach_t channel, dma_t *dma, const char *dev_name)
+{
+	/* 21285 internal channels */
+	if (channel == 0 || channel == 1)
+		return 0;
+
+	/* ISA channels */
+//	if (machine_is_cats() && ((channel >= 2 && channel <= 5) ||
+//		(channel >= 7 && channel <= 9)))
+//		return 0;
+
+	return -EINVAL;
+}
+
+void arch_free_dma(dmach_t channel, dma_t *dma)
+{
+	/* nothing to do */
+}
+
+int arch_get_dma_residue(dmach_t channel, dma_t *dma)
+{
+	int residue = 0;
+
+	switch (channel) {
+	case 0:
+	case 1:
+		break;
+#ifdef CONFIG_CATS
+	case 2:
+	case 3:
+	case 4:
+	case 5:
+	case 6:
+	case 7:
+	case 8:
+	case 9:
+#endif
+	}
+	return residue;
+}
+
+void arch_enable_dma(dmach_t channel, dma_t *dma)
+{
+	switch (channel) {
+	case 0:
+	case 1:
+		/*
+		 * Not yet implemented
+		 */
+		break;
+#ifdef CONFIG_CATS
+	case 2:
+	case 3:
+	case 4:
+	case 5:
+	case 7:
+	case 8:
+	case 9:
+		if (dma->invalid) {
+			static unsigned char dma_page[] = { 0x87, 0x83, 0x81, 0x82,
+							    0x00, 0x8b, 0x89, 0x8a };
+			unsigned long int address = dma->buf.address,
+				length = dma->buf.length - 1;
+			outb(address >> 24, dma_page[channel - DMA_ISA_BASE] | 0x400);
+			outb(address >> 16, dma_page[channel - DMA_ISA_BASE]);
+			if (channel >= DMA_ISA_BASE + 5) {
+				outb(0, DMA2_CLEAR_FF_REG);
+				outb(address >> 1, 
+				     IO_DMA2_BASE + ((channel - DMA_ISA_BASE - 4) << 2));
+				outb(address >> 9, 
+				     IO_DMA2_BASE + ((channel - DMA_ISA_BASE - 4) << 2));
+				outb((length >> 1) & 0xfe,
+				     IO_DMA2_BASE + 1 + ((channel - DMA_ISA_BASE - 4) << 2));
+				outb(length >> 9,
+				     IO_DMA2_BASE + 1 + ((channel - DMA_ISA_BASE - 4) << 2));
+				outb(dma->dma_mode | (channel - DMA_ISA_BASE - 4), DMA2_MODE_REG);
+			} else {
+				outb(0, DMA1_CLEAR_FF_REG);
+				outb(address >> 0, IO_DMA1_BASE + ((channel - DMA_ISA_BASE) << 1));
+				outb(address >> 8, IO_DMA1_BASE + ((channel - DMA_ISA_BASE) << 1));
+				outb(length >> 0,
+				     IO_DMA1_BASE + 1 + ((channel - DMA_ISA_BASE) << 1));
+				outb(length >> 8,
+				     IO_DMA1_BASE + 1 + ((channel - DMA_ISA_BASE) << 1));
+				outb(dma->dma_mode | (channel - DMA_ISA_BASE), DMA1_MODE_REG);
+			}
+			switch (dma->dma_mode) {
+			case DMA_MODE_READ:
+				dma_cache_inv(__bus_to_virt(address), length + 1);
+				break;
+			case DMA_MODE_WRITE:
+				dma_cache_wback(__bus_to_virt(address), length + 1);
+				break;
+			}
+			dma->invalid = 0;
+		}
+
+		if (channel >= DMA_ISA_BASE + 5)
+			outb(channel - DMA_ISA_BASE - 4, DMA2_MASK_REG);
+		else
+			outb(channel - DMA_ISA_BASE, DMA1_MASK_REG);
+#endif
+	}
+}
+
+void arch_disable_dma(dmach_t channel, dma_t *dma)
+{
+	switch (channel) {
+	case 0:
+	case 1:
+		/*
+		 * Not yet implemented
+		 */
+		break;
+#ifdef CONFIG_CATS
+	case 2:
+	case 3:
+	case 4:
+	case 5:
+	case 6:
+	case 7:
+	case 8:
+	case 9:
+		if (channel >= DMA_ISA_BASE + 5)
+			outb(channel - DMA_ISA_BASE, DMA2_MASK_REG);
+		else
+			outb((channel - DMA_ISA_BASE) | 4, DMA1_MASK_REG);
+#endif
+	}
+}
+
+__initfunc(void arch_dma_init(dma_t *dma))
+{
+	/* Nothing to do */
+}
diff -u --recursive --new-file v2.1.120/linux/arch/arm/kernel/dma-rpc.c linux/arch/arm/kernel/dma-rpc.c
--- v2.1.120/linux/arch/arm/kernel/dma-rpc.c	Tue Jul 21 00:15:30 1998
+++ linux/arch/arm/kernel/dma-rpc.c	Sun Sep  6 10:44:47 1998
@@ -20,7 +20,7 @@
 
 #include "dma.h"
 
-static struct fiq_handler fh = { "floppydma", NULL };
+static struct fiq_handler fh = { NULL, "floppydma", NULL, NULL };
 
 #if 0
 typedef enum {
@@ -155,8 +155,8 @@
 		}
 	} while (dma->sg && (status & DMA_ST_INT));
 
-	if (!no_buffer)
-		enable_irq(irq);
+	if (no_buffer)
+		disable_irq(irq);
 }
 
 int arch_request_dma(dmach_t channel, dma_t *dma, const char *dev_name)
@@ -172,7 +172,8 @@
 	case DMA_S0:
 	case DMA_S1:
 		save_flags_cli(flags);
-		ret = request_irq(dma->dma_irq, arch_dma_handle, SA_INTERRUPT, dev_name, dma);
+		ret = request_irq(dma->dma_irq, arch_dma_handle,
+				  SA_INTERRUPT, dev_name, dma);
 		if (!ret)
 			disable_irq(dma->dma_irq);
 		restore_flags(flags);
@@ -261,8 +262,7 @@
 	case DMA_VIRTUAL_FLOPPY: {
 		void *fiqhandler_start;
 		unsigned int fiqhandler_length;
-		extern void floppy_fiqsetup(unsigned long len, unsigned long addr,
-					     unsigned long port);
+		struct pt_regs regs;
 
 		if (dma->dma_mode == DMA_MODE_READ) {
 			extern unsigned char floppy_fiqin_start, floppy_fiqin_end;
@@ -273,21 +273,20 @@
 			fiqhandler_start = &floppy_fiqout_start;
 			fiqhandler_length = &floppy_fiqout_end - &floppy_fiqout_start;
 		}
+
+		regs.ARM_r9  = dma->buf.length;
+		regs.ARM_r10 = __bus_to_virt(dma->buf.address);
+		regs.ARM_fp  = (int)PCIO_FLOPPYDMABASE;
+
 		if (claim_fiq(&fh)) {
 			printk("floppydma: couldn't claim FIQ.\n");
 			return;
 		}
-		/* Allow access to page 0 via domains */
-		__asm__ __volatile__("mcr	p15, 0, %0, c3, c0" :
-					: "r" (DOMAIN_USER_MANAGER |
-					       DOMAIN_KERNEL_CLIENT |
-					       DOMAIN_IO_CLIENT));
-		memcpy((void *)0x1c, fiqhandler_start, fiqhandler_length);
-		/* set domain register to normal */
-		set_fs(get_fs());
-		flush_page_to_ram(0);
-		floppy_fiqsetup(dma->buf.length, __bus_to_virt(dma->buf.address), (int)PCIO_FLOPPYDMABASE);
+
+		set_fiq_handler(fiqhandler_start, fiqhandler_length);
+		set_fiq_regs(&regs);
 		enable_irq(dma->dma_irq);
+
 		}
 		break;
 
@@ -315,6 +314,7 @@
 
 	case DMA_VIRTUAL_FLOPPY:
 		disable_irq(dma->dma_irq);
+		release_fiq(&fh);
 		break;
 	}
 }
diff -u --recursive --new-file v2.1.120/linux/arch/arm/kernel/ecard.c linux/arch/arm/kernel/ecard.c
--- v2.1.120/linux/arch/arm/kernel/ecard.c	Tue Apr 14 14:29:19 1998
+++ linux/arch/arm/kernel/ecard.c	Sun Sep  6 10:44:47 1998
@@ -29,7 +29,6 @@
 
 #include <asm/io.h>
 #include <asm/hardware.h>
-#include <asm/arch/irq.h>
 #include <asm/ecard.h>
 #include <asm/irq.h>
 #include <asm/dma.h>
@@ -46,7 +45,7 @@
 #define BUS_ADDR(x) ((((unsigned long)(x)) << 2) + IO_BASE)
 
 extern unsigned long atomwide_serial_loader[], oak_scsi_loader[], noloader[];
-static const char blacklisted_str[] = "*loader blacklisted - not 32-bit compliant*";
+static const char blacklisted_str[] = "*loader s/w is not 32-bit compliant*";
 
 static const struct expcard_blacklist {
 	unsigned short	 manufacturer;
@@ -62,7 +61,7 @@
   BLACKLIST_LOADER(MANU_OAK,		PROD_OAK_SCSI,		oak_scsi_loader),
 
 /* Supported cards with broken loader */
-  { MANU_ALSYSTEMS, PROD_ALSYS_SCSIATAPI, noloader, "AlSystems PowerTec SCSI (loader blacklisted)" },
+  { MANU_ALSYSTEMS, PROD_ALSYS_SCSIATAPI, noloader, "AlSystems PowerTec SCSI" },
 
 /* Unsupported cards with no loader */
   BLACKLIST_NOLOADER(MANU_MCS,		PROD_MCS_CONNECT32)
@@ -125,6 +124,7 @@
  */
 void ecard_enableirq (unsigned int irqnr)
 {
+	irqnr &= 7;
 	if (irqnr < MAX_ECARDS && irqno_to_expcard[irqnr] != -1) {
 		ecard_t *ec = expcard + irqno_to_expcard[irqnr];
 
@@ -141,6 +141,7 @@
 
 void ecard_disableirq (unsigned int irqnr)
 {
+	irqnr &= 7;
 	if (irqnr < MAX_ECARDS && irqno_to_expcard[irqnr] != -1) {
 		ecard_t *ec = expcard + irqno_to_expcard[irqnr];
 
@@ -154,6 +155,7 @@
 
 void ecard_enablefiq (unsigned int fiqnr)
 {
+	fiqnr &= 7;
 	if (fiqnr < MAX_ECARDS && irqno_to_expcard[fiqnr] != -1) {
 		ecard_t *ec = expcard + irqno_to_expcard[fiqnr];
 
@@ -170,6 +172,7 @@
 
 void ecard_disablefiq (unsigned int fiqnr)
 {
+	fiqnr &= 7;
 	if (fiqnr < MAX_ECARDS && irqno_to_expcard[fiqnr] != -1) {
 		ecard_t *ec = expcard + irqno_to_expcard[fiqnr];
 
@@ -186,7 +189,6 @@
 	const int num_cards = ecard_numirqcards;
 	int i, called = 0;
 
-	mask_irq (IRQ_EXPANSIONCARD);
 	for (i = 0; i < num_cards; i++) {
 		if (expcard[i].claimed && expcard[i].irq &&
 		    (!expcard[i].irqmask ||
@@ -195,8 +197,7 @@
 			called ++;
 		}
 	}
-	cli ();
-	unmask_irq (IRQ_EXPANSIONCARD);
+	cli();
 	if (called == 0)
 		printk (KERN_WARNING "Wild interrupt from backplane?\n");
 }
@@ -433,10 +434,7 @@
 unsigned int ecard_address (ecard_t *ec, card_type_t type, card_speed_t speed)
 {
 	switch (ec->slot_no) {
-	case 0:
-	case 1:
-	case 2:
-	case 3:
+	case 0 ... 3:
 		switch (type) {
 		case ECARD_MEMC:
 			return MEMCECIO_BASE + (ec->slot_no << 12);
@@ -449,20 +447,11 @@
 		}
 
 #ifdef IOCEC4IO_BASE
-	case 4:
-	case 5:
-	case 6:
-	case 7:
-		switch (type) {
-		case ECARD_MEMC:
+	case 4 ... 7:
+		if (type != ECARD_IOC)
 			return 0;
 
-		case ECARD_IOC:
-			return IOCEC4IO_BASE + (speed << 17) + ((ec->slot_no - 4) << 12);
-
-		default:
-			return 0;
-		}
+		return IOCEC4IO_BASE + (speed << 17) + ((ec->slot_no - 4) << 12);
 #endif
 #ifdef MEMCEC8IO_BASE
 	case 8:
@@ -558,7 +547,14 @@
 	return 1;
 }
 
-static struct irqaction irqexpansioncard = { ecard_irq_noexpmask, SA_INTERRUPT, 0, "expansion cards", NULL, NULL };
+static struct irqaction irqexpansioncard = {
+	ecard_irq_noexpmask,
+	SA_INTERRUPT,
+	0,
+	"expansion cards",
+	NULL,
+	NULL
+};
 
 /*
  * Initialise the expansion card system.
@@ -575,6 +571,7 @@
 	if (ecard_checkirqhw()) {
 		printk (KERN_DEBUG "Expansion card interrupt management hardware found\n");
 		irqexpansioncard.handler = ecard_irq_expmask;
+		irqexpansioncard.flags |= SA_IRQNOMASK;
 		have_expmask = -1;
 	}
 #endif
diff -u --recursive --new-file v2.1.120/linux/arch/arm/kernel/entry-armv.S linux/arch/arm/kernel/entry-armv.S
--- v2.1.120/linux/arch/arm/kernel/entry-armv.S	Tue Jul 21 00:15:30 1998
+++ linux/arch/arm/kernel/entry-armv.S	Sun Sep  6 10:44:47 1998
@@ -320,11 +320,19 @@
 		.macro	mask_pc, rd, rm
 		.endm
 
+		/* If we're optimising for StrongARM the resulting code won't 
+		   run on an ARM7 and we can save a couple of instructions.  
+									--pb */
+#ifdef __ARM_ARCH_4__
+		.macro	arm700_bug_check, instr, temp
+		.endm
+#else
 		.macro	arm700_bug_check, instr, temp
 		and	\temp, \instr, #0x0f000000	@ check for SWI
 		teq	\temp, #0x0f000000
 		bne	.Larm700bug
 		.endm
+#endif
 
 		.macro	enable_irqs, temp
 		mrs	\temp, cpsr
@@ -340,6 +348,7 @@
 		.endm
 
 
+#ifndef __ARM_ARCH_4__
 .Larm700bug:	str	lr, [r8]
 		ldr	r0, [sp, #S_PSR]		@ Get calling cpsr
 		msr	spsr, r0
@@ -348,7 +357,7 @@
 		add	sp, sp, #S_PC
 		ldr	lr, [sp], #S_FRAME_SIZE - S_PC	@ Get PC and jump over PC, PSR, OLD_R0
 		movs	pc, lr
-
+#endif
 
 		.macro	get_current_task, rd
 		mov	\rd, sp, lsr #13
@@ -672,6 +681,8 @@
  *-----------------------------------------------------------------------------
  * Handles floating point instructions
  */
+.LC2:		.word	SYMBOL_NAME(fp_enter)
+
 __und_usr:	sub	sp, sp, #S_FRAME_SIZE		@ Allocate frame size in one go
 		stmia	sp, {r0 - r12}			@ Save r0 - r12
 		add	r8, sp, #S_PC
@@ -681,25 +692,15 @@
 		stmia	r8, {r5 - r7}			@ Save USR pc, cpsr, old_r0
 		mov	fp, #0
 
-		adr	r1, .LC2
-		ldmia	r1, {r1, r4}
-		ldr	r1, [r1]
-		get_current_task r2
-		teq	r1, r2
-		blne	SYMBOL_NAME(math_state_restore)
-		adrsvc	al, r9, SYMBOL_NAME(fpreturn)
-		adrsvc	al, lr, SYMBOL_NAME(fpundefinstr)
-		ldr	pc, [r4]			@ Call FP module USR entry point
+		adrsvc	al, r9, ret_from_exception	@ r9  = normal FP return
+		adrsvc	al, lr, fpundefinstr		@ lr  = undefined instr return
 
-		.globl	SYMBOL_NAME(fpundefinstr)
-SYMBOL_NAME(fpundefinstr):				@ Called by FP module on undefined instr
-		mov	r0, lr
-		mov	r1, sp
-		mrs	r4, cpsr			@ Enable interrupts
-		bic	r4, r4, #I_BIT
-		msr	cpsr, r4
-		bl	SYMBOL_NAME(do_undefinstr)
-		b	ret_from_exception		@ Normal FP exit
+1:		get_current_task r10
+		mov	lr, #1
+		strb	lr, [r10, #TSK_USED_MATH]	@ set current->used_math
+		add	r10, r10, #TSS_FPESAVE		@ r10 = workspace
+		ldr	r4, .LC2
+		ldr	pc, [r4]			@ Call FP module USR entry point
 
 __und_svc:	sub	sp, sp, #S_FRAME_SIZE
 		stmia	sp, {r0 - r12}			@ save r0 - r12
@@ -710,31 +711,24 @@
 		add	r4, sp, #S_SP
 		stmia	r4, {r5 - r9}			@ save sp_SVC, lr_SVC, pc, cpsr, old_ro
 
-		adr	r1, .LC2
-		ldmia	r1, {r1, r4}
-		ldr	r1, [r1]
-		mov	r2, sp, lsr #13
-		mov	r2, r2, lsl #13
-		teq	r1, r2
-		blne	SYMBOL_NAME(math_state_restore)
-		adrsvc	al, r9, SYMBOL_NAME(fpreturnsvc)
-		adrsvc	al, lr, SYMBOL_NAME(fpundefinstrsvc)
-		ldr	pc, [r4]			@ Call FP module SVC entry point
+		adrsvc	al, r9, 3f			@ r9  = normal FP return
+		bl	1b				@ lr  = undefined instr return
 
-		.globl	SYMBOL_NAME(fpundefinstrsvc)
-SYMBOL_NAME(fpundefinstrsvc):
 		mov	r0, r5				@ unsigned long pc
 		mov	r1, sp				@ struct pt_regs *regs
 		bl	SYMBOL_NAME(do_undefinstr)
 
-		.globl	SYMBOL_NAME(fpreturnsvc)
-SYMBOL_NAME(fpreturnsvc):
-		ldr	lr, [sp, #S_PSR]		@ Get SVC cpsr
+3:		ldr	lr, [sp, #S_PSR]		@ Get SVC cpsr
 		msr	spsr, lr
 		ldmia	sp, {r0 - pc}^			@ Restore SVC registers
 
-.LC2:		.word	SYMBOL_NAME(last_task_used_math)
-		.word	SYMBOL_NAME(fp_enter)
+fpundefinstr:	mov	r0, lr
+		mov	r1, sp
+		mrs	r4, cpsr			@ Enable interrupts
+		bic	r4, r4, #I_BIT
+		msr	cpsr, r4
+		adrsvc	al, lr, ret_from_exception
+		b	SYMBOL_NAME(do_undefinstr)
 
 __und_invalid:	sub	sp, sp, #S_FRAME_SIZE
 		stmia	sp, {r0 - lr}
diff -u --recursive --new-file v2.1.120/linux/arch/arm/kernel/entry-common.S linux/arch/arm/kernel/entry-common.S
--- v2.1.120/linux/arch/arm/kernel/entry-common.S	Tue Jul 21 00:15:30 1998
+++ linux/arch/arm/kernel/entry-common.S	Sun Sep  6 10:44:47 1998
@@ -6,8 +6,6 @@
 
 		.globl	ret_from_sys_call
 
-		.globl	SYMBOL_NAME(fpreturn)
-SYMBOL_NAME(fpreturn):
 ret_from_exception:
 		adr	r0, 1f
 		ldmia	r0, {r0, r1}
@@ -36,12 +34,10 @@
 		bne	SYMBOL_NAME(do_bottom_half)
 
 ret_with_reschedule:
-		ldr	r0, 1f + 8
-		ldr	r0, [r0]
+		get_current_task r1
+		ldr	r0, [r1, #TSK_NEED_RESCHED]
 		teq	r0, #0
 		bne	2b
-
-		get_current_task r1
 		ldr	r1, [r1, #TSK_SIGPENDING]
 		teq	r1, #0
 		bne	ret_signal
@@ -50,7 +46,6 @@
 
 1:		.word	SYMBOL_NAME(bh_mask)
 		.word	SYMBOL_NAME(bh_active)
-		.word	SYMBOL_NAME(need_resched)
 
 /*=============================================================================
  * SWI handler
@@ -211,8 +206,11 @@
  * What we need to put into 0-0x1c are ldrs to branch to 0xC0000000
  * (the kernel).
  * 0x1c onwards is reserved for FIQ, so I think that I will allocate 0xe0 onwards for
- * the actuall address to jump to.
+ * the actual address to jump to.
  */
+
+		.section ".text.init",#alloc,#execinstr
+
 #if defined(CONFIG_CPU_32)
 /*
  * these go into 0x00
@@ -281,39 +279,13 @@
 		ldmfd	sp!, {r4 - r7, pc}^
 #endif
 
+		.previous
+
 /*============================================================================
  * FP support
  */
 
-1:		.word	SYMBOL_NAME(fp_save)
-		.word	SYMBOL_NAME(fp_restore)
-
-.Lfpnull:	mov	pc, lr
-
-
-/*
- * Function to call when switching tasks to save FP state
- */
-ENTRY(fpe_save)
-		ldr	r1, 1b
-		ldr	pc, [r1]
-
-/*
- * Function to call when switching tasks to restore FP state
- */
-ENTRY(fpe_restore)
-		ldr	r1, 1b + 4
-		ldr	pc, [r1]
-
-
 		.data
 
 ENTRY(fp_enter)
-		.word	SYMBOL_NAME(fpundefinstr)
-		.word	SYMBOL_NAME(fpundefinstrsvc)
-
-ENTRY(fp_save)
-		.word	.Lfpnull
-ENTRY(fp_restore)
-		.word	.Lfpnull
-
+		.word	fpundefinstr
diff -u --recursive --new-file v2.1.120/linux/arch/arm/kernel/fiq.c linux/arch/arm/kernel/fiq.c
--- v2.1.120/linux/arch/arm/kernel/fiq.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/kernel/fiq.c	Sun Sep  6 10:44:47 1998
@@ -0,0 +1,179 @@
+/*
+ *  linux/arch/arm/kernel/fiq.c
+ *
+ *  Copyright (C) 1998 Russell King
+ *  FIQ support written by Philip Blundell <philb@gnu.org>, 1998.
+ *
+ *  FIQ support re-written by Russell King to be more generic
+ *
+ * We now properly support a method by which the FIQ handlers can
+ * be stacked onto the vector.  We still do not support sharing
+ * the FIQ vector itself.
+ *
+ * Operation is as follows:
+ *  1. Owner A claims FIQ:
+ *     - default_fiq relinquishes control.
+ *  2. Owner A:
+ *     - inserts code.
+ *     - sets any registers,
+ *     - enables FIQ.
+ *  3. Owner B claims FIQ:
+ *     - if owner A has a relinquish function.
+ *       - disable FIQs.
+ *       - saves any registers.
+ *       - returns zero.
+ *  4. Owner B:
+ *     - inserts code.
+ *     - sets any registers,
+ *     - enables FIQ.
+ *  5. Owner B releases FIQ:
+ *     - Owner A is asked to reacquire FIQ:
+ *	 - inserts code.
+ *	 - restores saved registers.
+ *	 - enables FIQ.
+ *  6. Goto 3
+ */
+#include <linux/config.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/init.h>
+
+#include <asm/fiq.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#define FIQ_VECTOR 0x1c
+
+static unsigned long no_fiq_insn;
+
+#ifdef CONFIG_CPU_32
+static inline void unprotect_page_0(void)
+{
+	__asm__ __volatile__("mcr	p15, 0, %0, c3, c0" :
+			: "r" (DOMAIN_USER_MANAGER |
+			       DOMAIN_KERNEL_CLIENT |
+			       DOMAIN_IO_CLIENT));
+}
+
+static inline void protect_page_0(void)
+{
+	set_fs(get_fs());
+}
+#else
+
+#define unprotect_page_0()
+#define protect_page_0()
+
+#endif
+
+/* Default reacquire function
+ * - we always relinquish FIQ control
+ * - we always reacquire FIQ control
+ */
+int fiq_def_op(void *ref, int relinquish)
+{
+	if (!relinquish) {
+		unprotect_page_0();
+		*(unsigned long *)FIQ_VECTOR = no_fiq_insn;
+		protect_page_0();
+		__flush_entry_to_ram(FIQ_VECTOR);
+	}
+
+	return 0;
+}
+
+static struct fiq_handler default_owner =
+	{ NULL, "default", fiq_def_op, NULL };
+static struct fiq_handler *current_fiq = &default_owner;
+
+int get_fiq_list(char *buf)
+{
+	char *p = buf;
+
+	if (current_fiq != &default_owner)
+		p += sprintf(p, "FIQ:              %s\n",
+			     current_fiq->name);
+
+	return p - buf;
+}
+
+void set_fiq_handler(void *start, unsigned int length)
+{
+	unprotect_page_0();
+
+	memcpy((void *)FIQ_VECTOR, start, length);
+
+	protect_page_0();
+#if 0
+	/* This doesn'w work correctly.  Ok, it's a misuse
+	 * of the DMA flushing code, but it ought to work.
+	 * More investigation required.  Maybe it really
+	 * needs the cache flushed.
+	 */
+	dma_cache_wback(FIQ_VECTOR, length);
+#else
+	processor.u.armv3v4._flush_cache_area(FIQ_VECTOR, FIQ_VECTOR + length, 1);
+#endif
+}
+
+void set_fiq_regs(struct pt_regs *regs)
+{
+	/* not yet -
+	 * this is temporary to get the floppy working
+	 * again on RiscPC.  It *will* become more
+	 * generic.
+	 */
+#ifdef CONFIG_ARCH_ACORN
+	extern void floppy_fiqsetup(unsigned long len, unsigned long addr,
+					     unsigned long port);
+	floppy_fiqsetup(regs->ARM_r9, regs->ARM_r10, regs->ARM_fp);
+#endif
+}
+
+void get_fiq_regs(struct pt_regs *regs)
+{
+	/* not yet */
+}
+
+int claim_fiq(struct fiq_handler *f)
+{
+	int ret = 0;
+
+	if (current_fiq) {
+		ret = -EBUSY;
+
+		if (current_fiq->fiq_op != NULL)
+			ret = current_fiq->fiq_op(current_fiq->dev_id, 1);
+	}
+
+	if (!ret) {
+		f->next = current_fiq;
+		current_fiq = f;
+	}
+
+	return ret;
+}
+
+void release_fiq(struct fiq_handler *f)
+{
+	if (current_fiq != f) {
+		printk(KERN_ERR "%s FIQ trying to release %s FIQ\n",
+		       f->name, current_fiq->name);
+#ifdef CONFIG_DEBUG_ERRORS
+		__backtrace();
+#endif
+		return;
+	}
+
+	do
+		current_fiq = current_fiq->next;
+	while (current_fiq->fiq_op(current_fiq->dev_id, 0));
+}
+
+__initfunc(void init_FIQ(void))
+{
+	no_fiq_insn = *(unsigned long *)FIQ_VECTOR;
+	set_fs(get_fs());
+}
diff -u --recursive --new-file v2.1.120/linux/arch/arm/kernel/head-armo.S linux/arch/arm/kernel/head-armo.S
--- v2.1.120/linux/arch/arm/kernel/head-armo.S	Tue Apr 14 14:29:19 1998
+++ linux/arch/arm/kernel/head-armo.S	Sun Sep  6 10:44:47 1998
@@ -43,7 +43,7 @@
 
 LC1:		.word	SYMBOL_NAME(_stext)
 LC0:		.word	SYMBOL_NAME(__bss_start)
-		.word	SYMBOL_NAME(arm_id)
+		.word	SYMBOL_NAME(processor_id)
 		.word	SYMBOL_NAME(_end)
 		.word	SYMBOL_NAME(init_task_union)+8192
 Larm2_id:	.long	0x41560200
diff -u --recursive --new-file v2.1.120/linux/arch/arm/kernel/head-armv.S linux/arch/arm/kernel/head-armv.S
--- v2.1.120/linux/arch/arm/kernel/head-armv.S	Tue Jul 21 00:15:30 1998
+++ linux/arch/arm/kernel/head-armv.S	Sun Sep  6 10:44:47 1998
@@ -1,58 +1,54 @@
 /*
  * linux/arch/arm/kernel/head32.S
  *
- * Copyright (C) 1994, 1995, 1996, 1997 Russell King
+ * Copyright (C) 1994-1998 Russell King
  *
  * Kernel 32 bit startup code for ARM6 / ARM7 / StrongARM
  */
 #include <linux/config.h>
 #include <linux/linkage.h>
 
-#define DEBUG
+#if (TEXTADDR & 0xffff) != 0x8000
+#error TEXTADDR must start at 0xXXXX8000
+#endif
 
-		.text
-		.align
+#define DEBUG
 
 		.globl	SYMBOL_NAME(swapper_pg_dir)
-		.equ	SYMBOL_NAME(swapper_pg_dir),	0xc0004000
+		.equ	SYMBOL_NAME(swapper_pg_dir),	TEXTADDR - 0x4000
 
-		.globl	__stext
+		.text
 /*
  * Entry point and restart point.  Entry *must* be called with r0 == 0,
  * MMU off.  Note! These should be unique!!! Please read Documentation/ARM-README
  * for more information.
  *
- *  r1 = 0 -> ebsa110
- *  r1 = 1 -> RPC
+ *  r1 = 0 -> DEC EBSA-110
+ *  r1 = 1 -> Acorn RiscPC
  *  r1 = 2 -> ebsit
  *  r1 = 3 -> nexuspci
- *  r1 = 4 -> ebsa285
- *  r1 = 5 -> vnc
+ *  r1 = 4 -> DEC EBSA-285
+ *  r1 = 5 -> Corel Netwinder
  *  r1 = 6 -> CATS
+ *  r1 = 7 -> tbox
  */
+
 ENTRY(stext)
 ENTRY(_stext)
-__entry:
-		teq	r0, #0					@ check for illegal entry...
+__entry:	teq	r0, #0					@ check for illegal entry...
 		bne	.Lerror					@ loop indefinitely
-		cmp	r1, #7					@ Unknown machine architecture
+		cmp	r1, #8					@ Unknown machine architecture
 		bge	.Lerror
-@
-@ First thing to do is to get the page tables set up so that we can call the kernel
-@ in the correct place.  This is relocatable code...
-@
+/* First thing to do is to get the page tables set up so that we can call the kernel
+ * in the correct place.  This is relocatable code...
+ * - Read processor ID register (CP#15, CR0).
+ */
 		mrc	p15, 0, r9, c0, c0			@ get Processor ID
-@
-@ Read processor ID register (CP#15, CR0).
-@ NOTE: ARM2 & ARM250 cause an undefined instruction exception...
-@ Values are:
-@		XX01XXXX = ARMv4 architecture (StrongARM)
-@		XX00XXXX = ARMv3 architecture
-@		4156061X = ARM 610
-@ 		4156030X = ARM 3
-@		4156025X = ARM 250
-@		4156020X = ARM 2
-@
+/* Values are:
+ *		XX01XXXX = ARMv4 architecture (StrongARM)
+ *		XX00XXXX = ARMv3 architecture
+ *		4156061X = ARM 610
+ */
 		adr	r10, .LCProcTypes
 1:		ldmia	r10!, {r5, r6, r8}			@ Get Set, Mask, MMU Flags
 		teq	r5, #0					@ End of list?
@@ -71,44 +67,51 @@
  * r6 = I/O address
  */
 		mov	r0, r4
-		mov	r1, #0
+		mov	r3, #0
 		add	r2, r0, #0x4000
-1:		str	r1, [r0], #4				@ Clear page table
+1:		str	r3, [r0], #4				@ Clear page table
 		teq	r0, r2
 		bne	1b
 /*
  * Add enough entries to allow the kernel to be called.
  * It will sort out the real mapping in paging_init.
- * We map in 2MB of memory into 0xC0000000 - 0xC0200000
+ * We map in 2MB of memory into (TEXTADDR-0x8000) + 2MB
+ */
+		add	r0, r4, #(TEXTADDR - 0x8000) >> 18
+		mov	r3, #0x0000000c				@ SECT_CACHEABLE | SECT_BUFFERABLE
+		orr	r3, r3, r8
+		add	r3, r3, r5
+		str	r3, [r0], #4
+		add	r3, r3, #1 << 20
+		str	r3, [r0], #4
+		add	r3, r3, #1 << 20
+#ifdef DEBUG
+/* Map in IO space
+ * This allows debug messages to be output via a serial
+ * before/while paging_init.
  */
-		add	r0, r4, #0x3000
-		mov	r1, #0x0000000c				@ SECT_CACHEABLE | SECT_BUFFERABLE
-		orr	r1, r1, r8
-		add	r1, r1, r5
-		str	r1, [r0], #4
-		add	r1, r1, #1 << 20
-		str	r1, [r0], #4
-		add	r1, r1, #1 << 20
-@
-@ Map in IO space
-@
 		add	r0, r4, #0x3800
-		orr	r1, r6, r8
+		orr	r3, r6, r8
 		add	r2, r0, #0x0800
-1:		str	r1, [r0], #4
-		add	r1, r1, #1 << 20
+1:		str	r3, [r0], #4
+		add	r3, r3, #1 << 20
 		teq	r0, r2
 		bne	1b
-@
-@ Map in screen at 0x02000000 & SCREEN2_BASE
-@
+#endif
+#ifdef CONFIG_ARCH_RPC
+/* Map in screen at 0x02000000 & SCREEN2_BASE
+ * Similar reasons here - for debug, and when things go
+ * wrong to a certain extent.  This is of limited use to
+ * non-Acorn RiscPC architectures though.
+ */
 		teq	r5, #0
 		addne	r0, r4, #0x80				@ 02000000
-		movne	r1, #0x02000000
-		orrne	r1, r1, r8
-		strne	r1, [r0]
+		movne	r3, #0x02000000
+		orrne	r3, r3, r8
+		strne	r3, [r0]
 		addne	r0, r4, #0x3600				@ d8000000
-		strne	r1, [r0]
+		strne	r3, [r0]
+#endif
 @
 @ The following should work on both v3 and v4 implementations
 @
@@ -122,25 +125,29 @@
 		mov	pc, lr
 
 .Lerror:
+#ifdef CONFIG_ARCH_RPC
+/* Turn the screen red on a error - RiscPC only.
+ */
 1:		mov	r0, #0x02000000
-		mov	r1, #0x11
-		orr	r1, r1, r1, lsl #8
-		orr	r1, r1, r1, lsl #16
-		str	r1, [r0], #4
-		str	r1, [r0], #4
-		str	r1, [r0], #4
-		str	r1, [r0], #4
+		mov	r3, #0x11
+		orr	r3, r3, r3, lsl #8
+		orr	r3, r3, r3, lsl #16
+		str	r3, [r0], #4
+		str	r3, [r0], #4
+		str	r3, [r0], #4
+		str	r3, [r0], #4
+#endif
 		b	1b
 
 .Lbranch:	.long	.Lalready_done_mmap			@ Real address of routine
 
-		@ EBSA110 (pg dir phys, phys ram start, phys i/o)
+		@ DEC EBSA110 (pg dir phys, phys ram start, phys i/o)
 .LCMachTypes:	.long	SYMBOL_NAME(swapper_pg_dir) - 0xc0000000	@ Address of page tables (physical)
 		.long	0					@ Address of RAM
 		.long	0xe0000000				@ I/O address
 		.long	0
 
-		@ RPC
+		@ Acorn RiscPC
 		.long	SYMBOL_NAME(swapper_pg_dir) - 0xc0000000 + 0x10000000
 		.long	0x10000000
 		.long	0x03000000
@@ -158,7 +165,7 @@
 		.long	0x10000000
 		.long	0
 
-		@ EBSA285
+		@ DEC EBSA285
 		.long	SYMBOL_NAME(swapper_pg_dir) - 0xc0000000 @ Address of page tables (physical)
 		.long	0					@ Address of RAM
 		.long	0x24000000				@ I/O base address (0x42000000 -> 0xFE000000)
@@ -176,6 +183,12 @@
 		.long	0x24000000				@ I/O base address (0x42000000 -> 0xfe000000)
 		.long	0
 
+		@ tbox
+		.long	SYMBOL_NAME(swapper_pg_dir) - 0xc0000000 + 0x80000000
+		.long	0x80000000				@ Address of RAM
+		.long	0x00400000				@ Uart
+		.long	0
+
 .LCProcTypes:	@ ARM6 / 610
 		.long	0x41560600
 		.long	0xffffff00
@@ -205,11 +218,6 @@
 		b	.Lsa_fastclock
 
 		.long	0
-
-.LC0:		.long	SYMBOL_NAME(__bss_start)
-		.long	SYMBOL_NAME(arm_id)
-		.long	SYMBOL_NAME(_end)
-		.long	SYMBOL_NAME(init_task_union)+8192
 		.align
 
 .Larmv3_flush_early:
@@ -249,25 +257,36 @@
 		orr	r0, r0, #0x1100				@ v4 supports separate I cache
 		mov	pc, lr
 
+		.section ".text.init",#alloc,#execinstr
+
 .Lsa_fastclock:	mcr	p15, 0, r4, c15, c1, 2			@ Enable clock switching
 		mov	pc, lr
 
+.LC0:		.long	SYMBOL_NAME(__entry)
+		.long	SYMBOL_NAME(machine_type)
+		.long	SYMBOL_NAME(__bss_start)
+		.long	SYMBOL_NAME(processor_id)
+		.long	SYMBOL_NAME(_end)
+		.long	SYMBOL_NAME(init_task_union)+8192
+		.align
+
 .Lalready_done_mmap:
-		adr	r5, __entry				@ Add base back in
-		add	r10, r10, r5
-		adr	r5, .LC0
-		ldmia	r5, {r5, r6, r8, sp}			@ Setup stack
-		mov	r4, #0
+		adr	r4, .LC0
+		ldmia	r4, {r3, r4, r5, r6, r8, sp}		@ Setup stack
+		add	r10, r10, r3				@ Add base back in
+		mov	fp, #0
 1:		cmp	r5, r8					@ Clear BSS
-		strcc	r4, [r5],#4
+		strcc	fp, [r5],#4
 		bcc	1b
 
+		str	r1, [r4]				@ Save machine type
 		str	r9, [r6]				@ Save processor ID
 		mov	lr, pc
 		add	pc, r10, #4				@ Call post-processor init
 		mov	fp, #0
 		b	SYMBOL_NAME(start_kernel)
 
+		.text
 #ifdef DEBUG
 /*
  * Some debugging routines (useful if you've got MM problems and
@@ -385,6 +404,9 @@
 		teq	r3, r2
 		bne	1b
 		mov	r0, r2
+		b	printascii
+
+		.ltorg
 
 ENTRY(printascii)
 		addruart r3
@@ -413,7 +435,3 @@
 hexbuf:		.space 16
 
 #endif
-
-		.text
-		.align	13
-ENTRY(this_must_match_init_task)
diff -u --recursive --new-file v2.1.120/linux/arch/arm/kernel/init_task.c linux/arch/arm/kernel/init_task.c
--- v2.1.120/linux/arch/arm/kernel/init_task.c	Tue Mar 17 22:18:13 1998
+++ linux/arch/arm/kernel/init_task.c	Sun Sep  6 10:44:47 1998
@@ -6,7 +6,7 @@
 
 static struct vm_area_struct init_mmap = INIT_MMAP;
 static struct fs_struct init_fs = INIT_FS;
-static struct files * init_fd_array[NR_OPEN] = { NULL, };
+static struct file * init_fd_array[NR_OPEN] = { NULL, };
 static struct files_struct init_files = INIT_FILES;
 static struct signal_struct init_signals = INIT_SIGNALS;
 struct mm_struct init_mm = INIT_MM;
@@ -21,4 +21,4 @@
  *
  * The things we do for performance..
  */
-union task_union init_task_union __attribute__((__section__(".text"))) = { INIT_TASK };
+union task_union init_task_union __attribute__((__section__(".init.task"))) = { INIT_TASK };
diff -u --recursive --new-file v2.1.120/linux/arch/arm/kernel/ioport.c linux/arch/arm/kernel/ioport.c
--- v2.1.120/linux/arch/arm/kernel/ioport.c	Thu May  7 22:51:46 1998
+++ linux/arch/arm/kernel/ioport.c	Sun Sep  6 10:44:47 1998
@@ -1,10 +1,7 @@
 /*
  * linux/arch/arm/kernel/ioport.c
  *
- * This contains the io-permission bitmap code - written by obz, with changes
- * by Linus.
- *
- * Modifications for ARM processor Copyright (C) 1995, 1996 Russell King
+ * Io-port support is not used for ARM
  */
 
 #include <linux/sched.h>
@@ -14,85 +11,19 @@
 #include <linux/ioport.h>
 
 /* Set EXTENT bits starting at BASE in BITMAP to value TURN_ON. */
-asmlinkage void set_bitmap(unsigned long *bitmap, short base, short extent, int new_value)
+/*asmlinkage void set_bitmap(unsigned long *bitmap, short base, short extent, int new_value)
 {
-	int mask;
-	unsigned long *bitmap_base = bitmap + (base >> 5);
-	unsigned short low_index = base & 0x1f;
-	int length = low_index + extent;
+}*/
 
-	if (low_index != 0) {
-		mask = (~0 << low_index);
-		if (length < 32)
-				mask &= ~(~0 << length);
-		if (new_value)
-			*bitmap_base++ |= mask;
-		else
-			*bitmap_base++ &= ~mask;
-		length -= 32;
-	}
-
-	mask = (new_value ? ~0 : 0);
-	while (length >= 32) {
-		*bitmap_base++ = mask;
-		length -= 32;
-	}
-
-	if (length > 0) {
-		mask = ~(~0 << length);
-		if (new_value)
-			*bitmap_base++ |= mask;
-		else
-			*bitmap_base++ &= ~mask;
-	}
-}
-
-/*
- * this changes the io permissions bitmap in the current task.
- */
 asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on)
 {
-	if (from + num <= from)
-		return -EINVAL;
-#ifndef __arm__
-	if (from + num > IO_BITMAP_SIZE*32)
-		return -EINVAL;
-#endif
-	if (!capable(CAP_SYS_RAWIO))
-		return -EPERM;
-
-#ifdef IODEBUG
-	printk("io: from=%d num=%d %s\n", from, num, (turn_on ? "on" : "off"));
-#endif
-#ifndef __arm__
-	set_bitmap((unsigned long *)current->tss.io_bitmap, from, num, !turn_on);
-#endif
-	return 0;
+	return -ENOSYS;
 }
 
-unsigned int *stack;
-
-/*
- * sys_iopl has to be used when you want to access the IO ports
- * beyond the 0x3ff range: to get the full 65536 ports bitmapped
- * you'd need 8kB of bitmaps/process, which is a bit excessive.
- *
- * Here we just change the eflags value on the stack: we allow
- * only the super-user to do it. This depends on the stack-layout
- * on system-call entry - see also fork() and the signal handling
- * code.
- */
 asmlinkage int sys_iopl(long ebx,long ecx,long edx,
 	     long esi, long edi, long ebp, long eax, long ds,
 	     long es, long fs, long gs, long orig_eax,
 	     long eip,long cs,long eflags,long esp,long ss)
 {
-	unsigned int level = ebx;
-
-	if (level > 3)
-		return -EINVAL;
-	if (!capable(CAP_SYS_RAWIO))
-		return -EPERM;
-	*(&eflags) = (eflags & 0xffffcfff) | (level << 12);
-	return 0;
+	return -ENOSYS;
 }
diff -u --recursive --new-file v2.1.120/linux/arch/arm/kernel/irq.c linux/arch/arm/kernel/irq.c
--- v2.1.120/linux/arch/arm/kernel/irq.c	Tue Jul 21 00:15:30 1998
+++ linux/arch/arm/kernel/irq.c	Sun Sep  6 10:44:47 1998
@@ -3,7 +3,6 @@
  *
  *  Copyright (C) 1992 Linus Torvalds
  *  Modifications for ARM processor Copyright (C) 1995-1998 Russell King.
- *  FIQ support written by Philip Blundell <philb@gnu.org>, 1998.
  *
  * This file contains the code used by various IRQ handling routines:
  * asking for different IRQ's should be done through these routines
@@ -31,20 +30,10 @@
 #include <linux/smp_lock.h>
 #include <linux/init.h>
 
-#include <asm/fiq.h>
 #include <asm/hardware.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
-#include <asm/arch/irq.h>
-
-unsigned int local_bh_count[NR_CPUS];
-unsigned int local_irq_count[NR_CPUS];
-spinlock_t irq_controller_lock;
-static struct fiq_handler *current_fiq;
-static unsigned long no_fiq_insn;
-
-#define FIQ_VECTOR ((unsigned long *)0x1c)
 
 #ifndef SMP
 #define irq_enter(cpu, irq)	(++local_irq_count[cpu])
@@ -53,48 +42,65 @@
 #error SMP not supported
 #endif
 
-#ifdef CONFIG_ARCH_ACORN
-/* Bitmask indicating valid interrupt numbers
- * (to be moved to include/asm-arm/arch-*)
- */
-unsigned long validirqs[NR_IRQS / 32] = {
-	0x003ffe7f,	0x000001ff,	0x000000ff,	0x00000000
+#ifndef cliIF
+#define cliIF()
+#endif
+
+unsigned int local_bh_count[NR_CPUS];
+unsigned int local_irq_count[NR_CPUS];
+spinlock_t irq_controller_lock;
+
+extern int get_fiq_list(char *);
+extern void init_FIQ(void);
+
+struct irqdesc {
+	unsigned int	 nomask   : 1;		/* IRQ does not mask in IRQ   */
+	unsigned int	 enabled  : 1;		/* IRQ is currently enabled   */
+	unsigned int	 triggered: 1;		/* IRQ has occurred	      */
+	unsigned int	 probing  : 1;		/* IRQ in use for a probe     */
+	unsigned int	 probe_ok : 1;		/* IRQ can be used for probe  */
+	unsigned int	 valid    : 1;		/* IRQ claimable	      */
+	unsigned int	 unused   :26;
+	void (*mask_ack)(unsigned int irq);	/* Mask and acknowledge IRQ   */
+	void (*mask)(unsigned int irq);		/* Mask IRQ		      */
+	void (*unmask)(unsigned int irq);	/* Unmask IRQ		      */
+	struct irqaction *action;
+	unsigned int	 unused2[3];
 };
 
-#define valid_irq(x) ((x) < NR_IRQS && validirqs[(x) >> 5] & (1 << ((x) & 31)))
-#else
+static struct irqdesc irq_desc[NR_IRQS];
 
-#define valid_irq(x) ((x) < NR_IRQS)
-#endif
+/*
+ * Dummy mask/unmask handler
+ */
+static void dummy_mask_unmask_irq(unsigned int irq)
+{
+}
 
-void disable_irq(unsigned int irq_nr)
+void disable_irq(unsigned int irq)
 {
 	unsigned long flags;
 
 	spin_lock_irqsave(&irq_controller_lock, flags);
-#ifdef cliIF
-	save_flags(flags);
 	cliIF();
-#endif
-	mask_irq(irq_nr);
+	irq_desc[irq].enabled = 0;
+	irq_desc[irq].mask(irq);
 	spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
 
-void enable_irq(unsigned int irq_nr)
+void enable_irq(unsigned int irq)
 {
 	unsigned long flags;
 
 	spin_lock_irqsave(&irq_controller_lock, flags);
-#ifdef cliIF
-	save_flags (flags);
 	cliIF();
-#endif
-	unmask_irq(irq_nr);
+	irq_desc[irq].enabled = 1;
+	irq_desc[irq].probing = 0;
+	irq_desc[irq].triggered = 0;
+	irq_desc[irq].unmask(irq);
 	spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
 
-struct irqaction *irq_action[NR_IRQS];
-
 int get_irq_list(char *buf)
 {
 	int i;
@@ -102,7 +108,7 @@
 	char *p = buf;
 
 	for (i = 0 ; i < NR_IRQS ; i++) {
-	    	action = irq_action[i];
+	    	action = irq_desc[i].action;
 		if (!action)
 			continue;
 		p += sprintf(p, "%3d: %10u   %s",
@@ -112,8 +118,8 @@
 		}
 		*p++ = '\n';
 	}
-	p += sprintf(p, "FIQ:              %s\n",
-		     current_fiq?current_fiq->name:"unused");
+
+	p += get_fiq_list(p);
 	return p - buf;
 }
 
@@ -122,26 +128,30 @@
  */
 asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
 {
+	struct irqdesc * desc = irq_desc + irq;
 	struct irqaction * action;
 	int status, cpu;
 
-#if defined(HAS_IOMD) || defined(HAS_IOC)
-	if (irq != IRQ_EXPANSIONCARD)
-#endif
-	{
-		spin_lock(&irq_controller_lock);
-		mask_and_ack_irq(irq);
-		spin_unlock(&irq_controller_lock);
-	}
+	spin_lock(&irq_controller_lock);
+	desc->mask_ack(irq);
+	spin_unlock(&irq_controller_lock);
 
 	cpu = smp_processor_id();
 	irq_enter(cpu, irq);
 	kstat.irqs[cpu][irq]++;
+	desc->triggered = 1;
 
 	/* Return with this interrupt masked if no action */
 	status = 0;
-	action = *(irq + irq_action);
+	action = desc->action;
+
 	if (action) {
+		if (desc->nomask) {
+			spin_lock(&irq_controller_lock);
+			desc->unmask(irq);
+			spin_unlock(&irq_controller_lock);
+		}
+
 		if (!(action->flags & SA_INTERRUPT))
 			__sti();
 
@@ -150,33 +160,20 @@
 			action->handler(irq, action->dev_id, regs);
 			action = action->next;
 		} while (action);
+
 		if (status & SA_SAMPLE_RANDOM)
 			add_interrupt_randomness(irq);
 		__cli();
 
-		switch (irq) {
-#if defined(HAS_IOMD) || defined(HAS_IOC)
-		case IRQ_KEYBOARDTX:
-		case IRQ_EXPANSIONCARD:
-			break;
-#endif
-#ifdef HAS_IOMD
-		case IRQ_DMA0:
-		case IRQ_DMA1:
-		case IRQ_DMA2:
-		case IRQ_DMA3:
-			break;
-#endif
-
-		default:
+		if (!desc->nomask && desc->enabled) {
 			spin_lock(&irq_controller_lock);
-			unmask_irq(irq);
+			desc->unmask(irq);
 			spin_unlock(&irq_controller_lock);
-			break;
 		}
 	}
 
 	irq_exit(cpu, irq);
+
 	/*
 	 * This should be conditional: we should really get
 	 * a return code from the irq handler to tell us
@@ -197,9 +194,18 @@
 #if defined(CONFIG_ARCH_ACORN)
 void do_ecard_IRQ(int irq, struct pt_regs *regs)
 {
+	struct irqdesc * desc;
 	struct irqaction * action;
+	int cpu;
+
+	desc = irq_desc + irq;
+
+	cpu = smp_processor_id();
+	kstat.irqs[cpu][irq]++;
+	desc->triggered = 1;
+
+	action = desc->action;
 
-	action = *(irq + irq_action);
 	if (action) {
 		do {
 			action->handler(irq, action->dev_id, regs);
@@ -207,7 +213,7 @@
 		} while (action);
 	} else {
 		spin_lock(&irq_controller_lock);
-		mask_irq (irq);
+		desc->mask(irq);
 		spin_unlock(&irq_controller_lock);
 	}
 }
@@ -219,11 +225,18 @@
 	struct irqaction *old, **p;
 	unsigned long flags;
 
-	p = irq_action + irq;
+	if (new->flags & SA_SAMPLE_RANDOM)
+	        rand_initialize_irq(irq);
+
+	spin_lock_irqsave(&irq_controller_lock, flags);
+
+	p = &irq_desc[irq].action;
 	if ((old = *p) != NULL) {
 		/* Can't share interrupts unless both agree to */
-		if (!(old->flags & new->flags & SA_SHIRQ))
+		if (!(old->flags & new->flags & SA_SHIRQ)) {
+			spin_unlock_irqrestore(&irq_controller_lock, flags);
 			return -EBUSY;
+		}
 
 		/* add new interrupt at end of irq queue */
 		do {
@@ -233,18 +246,16 @@
 		shared = 1;
 	}
 
-	if (new->flags & SA_SAMPLE_RANDOM)
-	        rand_initialize_irq(irq);
-
-	save_flags_cli(flags);
 	*p = new;
 
 	if (!shared) {
-		spin_lock(&irq_controller_lock);
-		unmask_irq(irq);
-		spin_unlock(&irq_controller_lock);
+		irq_desc[irq].nomask = (new->flags & SA_IRQNOMASK) ? 1 : 0;
+		irq_desc[irq].enabled = 1;
+		irq_desc[irq].probing = 0;
+		irq_desc[irq].unmask(irq);
 	}
-	restore_flags(flags);
+
+	spin_unlock_irqrestore(&irq_controller_lock, flags);
 	return 0;
 }
 
@@ -257,8 +268,8 @@
 {
 	unsigned long retval;
 	struct irqaction *action;
-        
-	if (!valid_irq(irq))
+
+	if (!irq_desc[irq].valid)
 		return -EINVAL;
 	if (!handler)
 		return -EINVAL;
@@ -286,14 +297,14 @@
 	struct irqaction * action, **p;
 	unsigned long flags;
 
-	if (!valid_irq(irq)) {
+	if (!irq_desc[irq].valid) {
 		printk(KERN_ERR "Trying to free IRQ%d\n",irq);
 #ifdef CONFIG_DEBUG_ERRORS
 		__backtrace();
 #endif
 		return;
 	}
-	for (p = irq + irq_action; (action = *p) != NULL; p = &action->next) {
+	for (p = &irq_desc[irq].action; (action = *p) != NULL; p = &action->next) {
 		if (action->dev_id != dev_id)
 			continue;
 
@@ -310,75 +321,109 @@
 #endif
 }
 
-unsigned long probe_irq_on (void)
+/* Start the interrupt probing.  Unlike other architectures,
+ * we don't return a mask of interrupts from probe_irq_on,
+ * but return the number of interrupts enabled for the probe.
+ * The interrupts which have been enabled for probing is
+ * instead recorded in the irq_desc structure.
+ */
+unsigned long probe_irq_on(void)
 {
 	unsigned int i, irqs = 0;
 	unsigned long delay;
 
-	/* first snaffle up any unassigned irqs */
-	for (i = 15; i > 0; i--) {
-		if (!irq_action[i] && valid_irq(i)) {
-			enable_irq(i);
-			irqs |= 1 << i;
-		}
+	/*
+	 * first snaffle up any unassigned but
+	 * probe-able interrupts
+	 */
+	spin_lock_irq(&irq_controller_lock);
+	for (i = 0; i < NR_IRQS; i++) {
+		if (!irq_desc[i].valid ||
+		    !irq_desc[i].probe_ok ||
+		    irq_desc[i].action)
+			continue;
+
+		irq_desc[i].probing = 1;
+		irq_desc[i].enabled = 1;
+		irq_desc[i].triggered = 0;
+		irq_desc[i].unmask(i);
+		irqs += 1;
 	}
+	spin_unlock_irq(&irq_controller_lock);
 
-	/* wait for spurious interrupts to mask themselves out again */
+	/*
+	 * wait for spurious interrupts to mask themselves out again
+	 */
 	for (delay = jiffies + HZ/10; delay > jiffies; )
 		/* min 100ms delay */;
 
+	/*
+	 * now filter out any obviously spurious interrupts
+	 */
+	spin_lock_irq(&irq_controller_lock);
+	for (i = 0; i < NR_IRQS; i++) {
+		if (irq_desc[i].probing && irq_desc[i].triggered) {
+			irq_desc[i].probing = 0;
+			irqs -= 1;
+		}
+	}
+	spin_unlock_irq(&irq_controller_lock);
+
 	/* now filter out any obviously spurious interrupts */
-	return irqs & get_enabled_irqs();
+	return irqs;
 }
 
-int probe_irq_off (unsigned long irqs)
+/*
+ * Possible return values:
+ *  >= 0 - interrupt number
+ *    -1 - no interrupt/many interrupts
+ */
+int probe_irq_off(unsigned long irqs)
 {
 	unsigned int i;
+	int irq_found = -1;
 
-	irqs &= ~get_enabled_irqs();
-	if (!irqs)
-		return 0;
-	i = ffz (~irqs);
-	if (irqs != (irqs & (1 << i)))
-		i = -i;
-	return i;
-}
-
-int claim_fiq(struct fiq_handler *f)
-{
-	if (current_fiq) {
-		if (current_fiq->callback == NULL || (*current_fiq->callback)())
-			return -EBUSY;
-	}
-	current_fiq = f;
-	return 0;
-}
-
-void release_fiq(struct fiq_handler *f)
-{
-	if (current_fiq != f) {
-		printk(KERN_ERR "%s tried to release FIQ when not owner!\n",
-		       f->name);
-#ifdef CONFIG_DEBUG_ERRORS
-		__backtrace();
-#endif
-		return;
+	/*
+	 * look at the interrupts, and find exactly one
+	 * that we were probing has been triggered
+	 */
+	spin_lock_irq(&irq_controller_lock);
+	for (i = 0; i < NR_IRQS; i++) {
+		if (irq_desc[i].probing &&
+		    irq_desc[i].triggered) {
+			if (irq_found != -1) {
+				irq_found = NO_IRQ;
+				goto out;
+			}
+			irq_found = i;
+		}
 	}
-	current_fiq = NULL;
 
-	*FIQ_VECTOR = no_fiq_insn;
-	__flush_entry_to_ram(FIQ_VECTOR);
+	if (irq_found == -1)
+		irq_found = NO_IRQ;
+out:
+	spin_unlock_irq(&irq_controller_lock);
+	return irq_found;
 }
 
+/*
+ * Get architecture specific interrupt handlers
+ * and interrupt initialisation.
+ */
+#include <asm/arch/irq.h>
+
 __initfunc(void init_IRQ(void))
 {
 	extern void init_dma(void);
+	int irq;
 
-	irq_init_irq();
-
-	current_fiq = NULL;
-	no_fiq_insn = *FIQ_VECTOR;
+	for (irq = 0; irq < NR_IRQS; irq++) {
+		irq_desc[irq].mask_ack = dummy_mask_unmask_irq;
+		irq_desc[irq].mask     = dummy_mask_unmask_irq;
+		irq_desc[irq].unmask   = dummy_mask_unmask_irq;
+	}
 
+	irq_init_irq();
+	init_FIQ();
 	init_dma();
 }
-
diff -u --recursive --new-file v2.1.120/linux/arch/arm/kernel/leds-ebsa110.c linux/arch/arm/kernel/leds-ebsa110.c
--- v2.1.120/linux/arch/arm/kernel/leds-ebsa110.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/kernel/leds-ebsa110.c	Sun Sep  6 10:44:47 1998
@@ -0,0 +1,30 @@
+/*
+ * arch/arm/kernel/leds-ebsa110.c
+ *
+ * Copyright (C) 1998 Russell King
+ *
+ * EBSA-110 LED control routines.  We use the led as follows:
+ *
+ *  - Red - toggles state every 50 timer interrupts
+ */
+#include <asm/hardware.h>
+#include <asm/leds.h>
+#include <asm/system.h>
+
+void leds_event(led_event_t ledevt)
+{
+	unsigned long flags;
+
+	save_flags_cli(flags);
+
+	switch(ledevt) {
+	case led_timer:
+		*(volatile unsigned char *)0xf2400000 ^= 128;
+		break;
+
+	default:
+		break;
+	}
+
+	restore_flags(flags);
+}
diff -u --recursive --new-file v2.1.120/linux/arch/arm/kernel/leds-ebsa285.c linux/arch/arm/kernel/leds-ebsa285.c
--- v2.1.120/linux/arch/arm/kernel/leds-ebsa285.c	Tue Apr 14 14:29:19 1998
+++ linux/arch/arm/kernel/leds-ebsa285.c	Sun Sep  6 10:44:47 1998
@@ -1,5 +1,5 @@
 /*
- * arch/arm/kernel/leds-285.c
+ * arch/arm/kernel/leds-ebsa285.c
  *
  * Copyright (C) 1998 Russell King
  *
diff -u --recursive --new-file v2.1.120/linux/arch/arm/kernel/process.c linux/arch/arm/kernel/process.c
--- v2.1.120/linux/arch/arm/kernel/process.c	Thu Aug  6 14:06:28 1998
+++ linux/arch/arm/kernel/process.c	Sun Sep  6 10:44:47 1998
@@ -38,9 +38,6 @@
 #include <asm/system.h>
 #include <asm/io.h>
 
-struct task_struct *last_task_used_math;
-
-extern void fpe_save(struct fp_soft_struct *);
 extern char *processor_modes[];
 
 asmlinkage void ret_from_sys_call(void) __asm__("ret_from_sys_call");
@@ -108,7 +105,6 @@
 {
 }
 
-
 void show_regs(struct pt_regs * regs)
 {
 	unsigned long flags;
@@ -158,18 +154,14 @@
  */
 void exit_thread(void)
 {
-	if (last_task_used_math == current)
-    		last_task_used_math = NULL;
 }
 
 void flush_thread(void)
 {
 	int i;
 
-	for (i = 0; i < 8; i++)
-		current->debugreg[i] = 0;
-	if (last_task_used_math == current)
-		last_task_used_math = NULL;
+	for (i = 0; i < NR_DEBUGS; i++)
+		current->tss.debug[i] = 0;
 	current->used_math = 0;
 	current->flags &= ~PF_USEDFPU;
 }
@@ -189,13 +181,8 @@
 	childregs->ARM_r0 = 0;
 
 	save = ((struct context_save_struct *)(childregs)) - 1;
-	copy_thread_css (save);
+	copy_thread_css(save);
 	p->tss.save = save;
-	/*
-	 * Save current math state in p->tss.fpe_save if not already there.
-	 */
-	if (last_task_used_math == current)
-		fpe_save (&p->tss.fpstate.soft);
 
 	return 0;
 }
@@ -207,12 +194,8 @@
 {
 	int fpvalid = 0;
 
-	if (current->used_math) {
-		if (last_task_used_math == current)
-			fpe_save (&current->tss.fpstate.soft);
-
+	if (current->used_math)
 		memcpy (fp, &current->tss.fpstate.soft, sizeof (fp));
-	}
 
 	return fpvalid;
 }
@@ -232,8 +215,8 @@
 	dump->u_dsize = (current->mm->brk - current->mm->start_data + PAGE_SIZE - 1) >> PAGE_SHIFT;
 	dump->u_ssize = 0;
 
-	for (i = 0; i < 8; i++)
-		dump->u_debugreg[i] = current->debugreg[i];  
+	for (i = 0; i < NR_DEBUGS; i++)
+		dump->u_debugreg[i] = current->tss.debug[i];  
 
 	if (dump->start_stack < 0x04000000)
 		dump->u_ssize = (0x04000000 - dump->start_stack) >> PAGE_SHIFT;
diff -u --recursive --new-file v2.1.120/linux/arch/arm/kernel/ptrace.c linux/arch/arm/kernel/ptrace.c
--- v2.1.120/linux/arch/arm/kernel/ptrace.c	Thu May  7 22:51:46 1998
+++ linux/arch/arm/kernel/ptrace.c	Wed Sep  9 08:56:58 1998
@@ -3,7 +3,6 @@
 /* edited by Linus Torvalds */
 /* edited for ARM by Russell King */
 
-#include <linux/head.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
@@ -376,7 +375,7 @@
 	if (res < 0)
 		return res;
 
-	child->debugreg[nsaved++] = alt = pc + 4;
+	child->tss.debug[nsaved++] = alt = pc + 4;
 printk ("ptrace_set_bpt: insn=%08lX pc=%08lX ", insn, pc);
 	switch (insn & 0x0e100000) {
 	case 0x00000000:
@@ -515,20 +514,20 @@
 	}
 printk ("=%08lX\n", alt);
 	if (alt != pc + 4)
-		child->debugreg[nsaved++] = alt;
+		child->tss.debug[nsaved++] = alt;
 
 	for (i = 0; i < nsaved; i++) {
-		res = read_long (child, child->debugreg[i], &insn);
+		res = read_long (child, child->tss.debug[i], &insn);
 		if (res >= 0) {
-			child->debugreg[i + 2] = insn;
-			res = write_long (child, child->debugreg[i], BREAKINST);
+			child->tss.debug[i + 2] = insn;
+			res = write_long (child, child->tss.debug[i], BREAKINST);
 		}
 		if (res < 0) {
-			child->debugreg[4] = 0;
+			child->tss.debug[4] = 0;
 			return res;
 		}
 	}
-	child->debugreg[4] = nsaved;
+	child->tss.debug[4] = nsaved;
 	return 0;
 }
 
@@ -537,16 +536,16 @@
  */
 int ptrace_cancel_bpt (struct task_struct *child)
 {
-	int i, nsaved = child->debugreg[4];
+	int i, nsaved = child->tss.debug[4];
 
-	child->debugreg[4] = 0;
+	child->tss.debug[4] = 0;
 
 	if (nsaved > 2) {
 		printk ("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved);
 		nsaved = 2;
 	}
 	for (i = 0; i < nsaved; i++)
-		write_long (child, child->debugreg[i], child->debugreg[i + 2]);
+		write_long (child, child->tss.debug[i], child->tss.debug[i + 2]);
 	return nsaved != 0;
 }
 
@@ -680,7 +679,7 @@
 			ret = -EIO;
 			if ((unsigned long) data > _NSIG)
 				goto out;
-			child->debugreg[4] = -1;
+			child->tss.debug[4] = -1;
 			child->flags &= ~PF_TRACESYS;
 			wake_up_process(child);
 			child->exit_code = data;
diff -u --recursive --new-file v2.1.120/linux/arch/arm/kernel/setup-ebsa110.c linux/arch/arm/kernel/setup-ebsa110.c
--- v2.1.120/linux/arch/arm/kernel/setup-ebsa110.c	Tue Jul 21 00:15:30 1998
+++ linux/arch/arm/kernel/setup-ebsa110.c	Wed Dec 31 16:00:00 1969
@@ -1,191 +0,0 @@
-/*
- *  linux/arch/arm/kernel/setup-sa.c
- *
- *  Copyright (C) 1995, 1996 Russell King
- */
-
-/*
- * This file obtains various parameters about the system that the kernel
- * is running on.
- */
-
-#include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/stddef.h>
-#include <linux/unistd.h>
-#include <linux/ptrace.h>
-#include <linux/malloc.h>
-#include <linux/user.h>
-#include <linux/a.out.h>
-#include <linux/tty.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/major.h>
-#include <linux/utsname.h>
-#include <linux/init.h>
-#include <linux/console.h>
-
-#include <asm/hardware.h>
-#include <asm/pgtable.h>
-#include <asm/procinfo.h>
-#include <asm/segment.h>
-#include <asm/setup.h>
-#include <asm/system.h>
-
-#ifndef CONFIG_CMDLINE
-#define CONFIG_CMDLINE	"root=nfs rw console=ttyS1,38400n8"
-#endif
-#define COMMAND_LINE_SIZE 256
-
-#define MEM_SIZE	(16*1024*1024)
-
-struct screen_info screen_info;
-struct processor processor;
-unsigned char aux_device_present;
-
-extern const struct processor sa110_processor_functions;
-
-struct armversions armidlist[] = {
-	{ 0x4401a100, 0xfffffff0, F_MMU|F_32BIT	, "DEC",	"sa110"		, &sa110_processor_functions  , "sa1x"},
-	{ 0x00000000, 0x00000000, 0		, "***",	"*unknown*"	, NULL			      , NULL  }
-};
-
-unsigned long arm_id;
-int armidindex;
-
-extern int root_mountflags;
-extern int _etext, _edata, _end;
-
-static char command_line[COMMAND_LINE_SIZE] __initdata = { 0, };
-       char saved_command_line[COMMAND_LINE_SIZE];
-
-#ifdef CONFIG_BLK_DEV_RAM
-extern int rd_doload;		/* 1 = load ramdisk, 0 = don't load */
-extern int rd_prompt;		/* 1 = prompt for ramdisk, 0 = don't prompt */
-extern int rd_image_start;	/* starting block # of image */
-
-static inline void setup_ramdisk(int start, int prompt, int load)
-{
-	rd_image_start	= start;
-	rd_prompt	= prompt;
-	rd_doload	= load;
-}
-#else
-#define setup_ramdisk(start,prompt,load)
-#endif
-
-#ifdef PARAMS_BASE
-static struct param_struct *params = (struct param_struct *)PARAMS_BASE;
-
-static inline char *setup_params(unsigned long *mem_end_p)
-{
-	ROOT_DEV	  = to_kdev_t(params->u1.s.rootdev);
-	ORIG_X		  = params->u1.s.video_x;
-	ORIG_Y		  = params->u1.s.video_y;
-	ORIG_VIDEO_COLS	  = params->u1.s.video_num_cols;
-	ORIG_VIDEO_LINES  = params->u1.s.video_num_rows;
-
-	setup_ramdisk(params->u1.s.rd_start,
-		      (params->u1.s.flags & FLAG_RDPROMPT) == 0,
-		      (params->u1.s.flags & FLAG_RDLOAD) == 0);
-
-	*mem_end_p = 0xc0000000 + MEM_SIZE;
-
-	return params->commandline;
-}
-#else
-static char default_command_line[] = CONFIG_CMDLINE;
-
-static inline char *setup_params(unsigned long *mem_end_p)
-{
-	ROOT_DEV	  = 0x00ff;
-
-	setup_ramdisk(0, 1, 1);
-
-	*mem_end_p = 0xc0000000 + MEM_SIZE;
-
-	return default_command_line;
-}
-#endif
-
-__initfunc(void setup_arch(char **cmdline_p,
-	unsigned long * memory_start_p, unsigned long * memory_end_p))
-{
-	unsigned long memory_start, memory_end;
-	char c = ' ', *to = command_line, *from;
-	int len = 0;
-
-	memory_start = (unsigned long)&_end;
-
-	armidindex = 0;
-
-	processor = sa110_processor_functions;
-	processor._proc_init();
-
-	from = setup_params(&memory_end);
-
-	init_task.mm->start_code = TASK_SIZE;
-	init_task.mm->end_code	 = TASK_SIZE + (unsigned long) &_etext;
-	init_task.mm->end_data	 = TASK_SIZE + (unsigned long) &_edata;
-	init_task.mm->brk	 = TASK_SIZE + (unsigned long) &_end;
-
-	/* Save unparsed command line copy for /proc/cmdline */
-	memcpy(saved_command_line, from, COMMAND_LINE_SIZE);
-	saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
-
-	for (;;) {
-		if (c == ' ' &&
-		    from[0] == 'm' &&
-		    from[1] == 'e' &&
-		    from[2] == 'm' &&
-		    from[3] == '=') {
-			memory_end = simple_strtoul(from+4, &from, 0);
-			if ( *from == 'K' || *from == 'k' ) {
-				memory_end = memory_end << 10;
-				from++;
-			} else if ( *from == 'M' || *from == 'm' ) {
-				memory_end = memory_end << 20;
-				from++;
-			}
-			memory_end = memory_end + PAGE_OFFSET;
-		}
-		c = *from++;
-		if (!c)
-			break;
-		if (COMMAND_LINE_SIZE <= ++len)
-			break;
-		*to++ = c;
-	}
-
-	*to = '\0';
-	*cmdline_p = command_line;
-	*memory_start_p = memory_start;
-	*memory_end_p = memory_end;
-	strcpy (system_utsname.machine, "sa110");
-
-#ifdef CONFIG_FB
-	conswitchp = &fb_con;
-#endif
-}
-
-int get_cpuinfo(char * buffer)
-{
-	int len;
-
-	len = sprintf (buffer,  "CPU:\n"
-				"Type\t\t: %s\n"
-				"Revision\t: %d\n"
-				"Manufacturer\t: %s\n"
-				"32bit modes\t: %s\n"
-				"BogoMips\t: %lu.%02lu\n",
-				"sa110",
-				(int)arm_id & 15,
-				"DEC",
-				"yes",
-				(loops_per_sec+2500) / 500000,
-				((loops_per_sec+2500) / 5000) % 100);
-	return len;
-}
diff -u --recursive --new-file v2.1.120/linux/arch/arm/kernel/setup.c linux/arch/arm/kernel/setup.c
--- v2.1.120/linux/arch/arm/kernel/setup.c	Tue Jul 21 00:15:30 1998
+++ linux/arch/arm/kernel/setup.c	Sun Sep  6 10:44:47 1998
@@ -1,7 +1,7 @@
 /*
  *  linux/arch/arm/kernel/setup.c
  *
- *  Copyright (C) 1995, 1996, 1997 Russell King
+ *  Copyright (C) 1995-1998 Russell King
  */
 
 /*
@@ -37,11 +37,37 @@
 #include <asm/segment.h>
 #include <asm/setup.h>
 #include <asm/system.h>
-#include <asm/arch/mmu.h>
+
+/* Work out which CPUs to support */
+#ifdef CONFIG_ARCH_ACORN
+#define SUPPORT_CPU_ARM6
+#define SUPPORT_CPU_ARM7
+#define SUPPORT_CPU_SA110
+#else
+#define SUPPORT_CPU_SA110
+#endif
+#ifdef CONFIG_CPU_ARM6
+#define SUPPORT_CPU_ARM6
+#endif
+#ifdef CONFIG_CPU_ARM7
+#define SUPPORT_CPU_ARM7
+#endif
+#ifdef CONFIG_CPU_SA110
+#define SUPPORT_CPU_SA110
+#endif
+
+#ifndef CONFIG_CMDLINE
+#define CONFIG_CMDLINE	"root=nfs rw console=ttyS1,38400n8"
+#endif
+#define MEM_SIZE	(16*1024*1024)
+#define COMMAND_LINE_SIZE 256
 
 struct drive_info_struct { char dummy[32]; } drive_info;
 struct screen_info screen_info = {
-  0, 0,  0,  0, 0, 0,  0,  0,  0,  0, 1, 8
+ orig_video_mode:	0,
+ orig_video_ega_bx:	0,
+ orig_video_isVGA:	1,
+ orig_video_points:	8
 };
 struct processor processor;
 unsigned char aux_device_present;
@@ -66,35 +92,36 @@
   { 0x41560300, 0xfffffff0, "ARM/VLSI",	"arm3"	 , "armv2"  , "v2", HWCAP_SWP,
 	&arm3_processor_functions   },
 #elif defined(CONFIG_CPU_32)
+#ifdef SUPPORT_CPU_ARM6
   { 0x41560600, 0xfffffff0, "ARM/VLSI",	"arm6"	 , "armv3"  , "v3", HWCAP_SWP,
 	&arm6_processor_functions   },
   { 0x41560610, 0xfffffff0, "ARM/VLSI",	"arm610" , "armv3"  , "v3", HWCAP_SWP,
 	&arm6_processor_functions   },
+#endif
+#ifdef SUPPORT_CPU_ARM7
   { 0x41007000, 0xffffff00, "ARM/VLSI",	"arm7"	 , "armv3"  , "v3", HWCAP_SWP,
 	&arm7_processor_functions   },
   /* ARM710 IDs are non-standard */
   { 0x41007100, 0xfff8ff00, "ARM/VLSI",	"arm710" , "armv3"  , "v3", HWCAP_SWP,
 	&arm7_processor_functions   },
+#endif
+#ifdef SUPPORT_CPU_SA110
   { 0x4401a100, 0xfffffff0, "DEC",	"sa110"	 , "armv4"  , "v3", HWCAP_SWP|HWCAP_HALF,
 	&sa110_processor_functions  },
 #endif
+#endif
   { 0x00000000, 0x00000000, "***", "unknown", "unknown", "**", 0, NULL }
 };
 
-static const struct param_struct *params = (struct param_struct *)PARAMS_BASE;
-
-unsigned long arm_id;
-unsigned int vram_half_sam;
+/*
+ * From head-armv.S
+ */
+unsigned int processor_id;
+unsigned int machine_type;
 int armidindex;
-int memc_ctrl_reg;
-int number_ide_drives;
-int number_mfm_drives;
 
-extern int bytes_per_char_h;
-extern int bytes_per_char_v;
 extern int root_mountflags;
 extern int _etext, _edata, _end;
-extern unsigned long real_end_mem;
 
 /*-------------------------------------------------------------------------
  * Early initialisation routines for various configurable items in the
@@ -107,12 +134,15 @@
  */
 #ifdef CONFIG_ARCH_RPC
 
-extern void
-init_dram_banks(const struct param_struct *params);
+#include <asm/arch/mmu.h>
+
+unsigned int vram_half_sam;
 
 static void
-setup_rpc(const struct param_struct *params)
+setup_rpc(struct param_struct *params)
 {
+	extern void init_dram_banks(const struct param_struct *params);
+
 	init_dram_banks(params);
 
 	switch (params->u1.s.pages_in_vram) {
@@ -123,41 +153,103 @@
 	default:
 		vram_half_sam = 2048;
 	}
-
-	/*
-	 * Set ROM speed to maximum
-	 */
-	outb (0x1d, IOMD_ROMCR0);
 }
 #else
 #define setup_rpc(x)
 #endif
 
-/*
- * ram disk
- */
-#ifdef CONFIG_BLK_DEV_RAM
-extern int rd_doload;		/* 1 = load ramdisk, 0 = don't load */
-extern int rd_prompt;		/* 1 = prompt for ramdisk, 0 = don't prompt */
-extern int rd_image_start;	/* starting block # of image */
+#ifdef PARAMS_BASE
 
-static void
-setup_ramdisk(const struct param_struct *params)
+#ifdef CONFIG_ARCH_ACORN
+int memc_ctrl_reg;
+int number_ide_drives;
+int number_mfm_drives;
+#endif
+
+static struct param_struct *params = (struct param_struct *)PARAMS_BASE;
+
+__initfunc(static char *
+setup_params(unsigned long *mem_end_p))
 {
-	rd_image_start	= params->u1.s.rd_start;
-	rd_prompt	= (params->u1.s.flags & FLAG_RDPROMPT) == 0;
-	rd_doload	= (params->u1.s.flags & FLAG_RDLOAD) == 0;
+	ROOT_DEV	  = to_kdev_t(params->u1.s.rootdev);
+	ORIG_X		  = params->u1.s.video_x;
+	ORIG_Y		  = params->u1.s.video_y;
+	ORIG_VIDEO_COLS	  = params->u1.s.video_num_cols;
+	ORIG_VIDEO_LINES  = params->u1.s.video_num_rows;
+
+#ifdef CONFIG_ARCH_ACORN
+#ifndef CONFIG_FB
+	{
+		extern int bytes_per_char_h;
+		extern int bytes_per_char_v;
+
+		bytes_per_char_h  = params->u1.s.bytes_per_char_h;
+		bytes_per_char_v  = params->u1.s.bytes_per_char_v;
+	}
+#endif
+	memc_ctrl_reg	  = params->u1.s.memc_control_reg;
+	number_ide_drives = (params->u1.s.adfsdrives >> 6) & 3;
+	number_mfm_drives = (params->u1.s.adfsdrives >> 3) & 3;
+
+	setup_rpc(params);
+
+	if (!(params->u1.s.flags & FLAG_READONLY))
+		root_mountflags &= ~MS_RDONLY;
+#endif
+#ifdef CONFIG_BLK_DEV_RAM
+	{
+		extern int rd_doload;
+		extern int rd_prompt;
+		extern int rd_image_start;
+
+		rd_image_start = params->u1.s.rd_start;
+		rd_prompt = (params->u1.s.flags & FLAG_RDPROMPT) == 0;
+		rd_doload = (params->u1.s.flags & FLAG_RDLOAD) == 0;
+	}
+#endif
+
+#ifdef CONFIG_ARCH_ACORN
+	*mem_end_p = GET_MEMORY_END(params);
+#else
+	*mem_end_p = PAGE_OFFSET + MEM_SIZE;
+#endif
+
+	return params->commandline;
 }
+
 #else
-#define setup_ramdisk(p)
+
+static char default_command_line[] __initdata = CONFIG_CMDLINE;
+
+__initfunc(static char *
+setup_params(unsigned long *mem_end_p))
+{
+	ROOT_DEV	  = 0x00ff;
+
+#ifdef CONFIG_BLK_DEV_RAM
+	{
+		extern int rd_doload;
+		extern int rd_prompt;
+		extern int rd_image_start;
+
+		rd_image_start = 0;
+		rd_prompt = 1;
+		rd_doload = 1;
+	}
+#endif
+
+	*mem_end_p = PAGE_OFFSET + MEM_SIZE;
+
+	return default_command_line;
+}
 #endif
 
 /*
  * initial ram disk
  */
 #ifdef CONFIG_BLK_DEV_INITRD
-static void
-setup_initrd(const struct param_struct *params, unsigned long memory_end)
+__initfunc(static void
+setup_initrd(const struct param_struct *params))
 {
 	if (params->u1.s.initrd_start) {
 		initrd_start = params->u1.s.initrd_start;
@@ -166,130 +258,130 @@
 		initrd_start = 0;
 		initrd_end   = 0;
 	}
+}
 
-	if (initrd_end > memory_end) {
+__initfunc(static void
+check_initrd(unsigned long mem_start, unsigned long mem_end))
+{
+	if (initrd_end > mem_end) {
 		printk ("initrd extends beyond end of memory "
 			"(0x%08lx > 0x%08lx) - disabling initrd\n",
-			initrd_end, memory_end);
+			initrd_end, mem_end);
 		initrd_start = 0;
 	}
 }
+
 #else
-#define setup_initrd(p,m)
+#define setup_initrd(p)
+#define check_initrd(ms,me)
 #endif
 
-static inline void
-get_processor_type(void)
+__initfunc(void
+setup_processor(void))
 {
-	for (armidindex = 0; ; armidindex ++)
-		if (!((armidlist[armidindex].id ^ arm_id) &
-		      armidlist[armidindex].mask))
-			break;
+	armidindex = 0;
+
+	while ((armidlist[armidindex].id ^ processor_id) &
+	       armidlist[armidindex].mask)
+		armidindex += 1;
 
 	if (armidlist[armidindex].id == 0) {
+#ifdef CONFIG_ARCH_ACORN
 		int i;
 
 		for (i = 0; i < 3200; i++)
 			((unsigned long *)SCREEN2_BASE)[i] = 0x77113322;
-
+#endif
 		while (1);
 	}
+
 	processor = *armidlist[armidindex].proc;
+	processor._proc_init();
 }
 
-#define COMMAND_LINE_SIZE 256
-
-/* Can this be initdata?  --pb
- *  command_line can be, saved_command_line can't though
- */
-static char command_line[COMMAND_LINE_SIZE] __initdata = { 0, };
+static char command_line[COMMAND_LINE_SIZE] = { 0, };
        char saved_command_line[COMMAND_LINE_SIZE];
 
-__initfunc(void setup_arch(char **cmdline_p,
-	unsigned long * memory_start_p, unsigned long * memory_end_p))
+__initfunc(static void
+setup_mem(char *cmd_line, unsigned long *mem_start, unsigned long *mem_end))
+{
+	char c = ' ', *to = command_line;
+	int len = 0;
+
+	*mem_start = (unsigned long)&_end;
+
+	for (;;) {
+		if (c == ' ' &&
+		    cmd_line[0] == 'm' &&
+		    cmd_line[1] == 'e' &&
+		    cmd_line[2] == 'm' &&
+		    cmd_line[3] == '=') {
+			*mem_end = simple_strtoul(cmd_line+4, &cmd_line, 0);
+			switch(*cmd_line) {
+			case 'M':
+			case 'm':
+				*mem_end <<= 10;
+			case 'K':
+			case 'k':
+				*mem_end <<= 10;
+				cmd_line++;
+			}
+			*mem_end = *mem_end + PAGE_OFFSET;
+		}
+		c = *cmd_line++;
+		if (!c)
+			break;
+		if (COMMAND_LINE_SIZE <= ++len)
+			break;
+		*to++ = c;
+	}
+
+	*to = '\0';		
+}
+
+__initfunc(void
+setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * memory_end_p))
 {
 	static unsigned char smptrap;
-	unsigned long memory_start, memory_end;
-	char endian = 'l', c = ' ', *to = command_line;
+	unsigned long memory_end;
+	char endian = 'l';
 	char *from;
-	int len = 0;
 
 	if (smptrap == 1)
 		return;
 	smptrap = 1;
 
-	get_processor_type ();
-	processor._proc_init ();
+	setup_processor();
 
-#ifndef CONFIG_FB
-	bytes_per_char_h  = params->u1.s.bytes_per_char_h;
-	bytes_per_char_v  = params->u1.s.bytes_per_char_v;
-#endif
-	from		  = (char *)params->commandline;
-	ROOT_DEV	  = to_kdev_t (params->u1.s.rootdev);
-	ORIG_X		  = params->u1.s.video_x;
-	ORIG_Y		  = params->u1.s.video_y;
-	ORIG_VIDEO_COLS	  = params->u1.s.video_num_cols;
-	ORIG_VIDEO_LINES  = params->u1.s.video_num_rows;
-	memc_ctrl_reg	  = params->u1.s.memc_control_reg;
-	number_ide_drives = (params->u1.s.adfsdrives >> 6) & 3;
-	number_mfm_drives = (params->u1.s.adfsdrives >> 3) & 3;
+	from = setup_params(&memory_end);
+	setup_initrd(params);
 
-	setup_rpc(params);
-	setup_ramdisk(params);
-
-	if (!(params->u1.s.flags & FLAG_READONLY))
-		root_mountflags &= ~MS_RDONLY;
+	/* Save unparsed command line copy for /proc/cmdline */
+	memcpy(saved_command_line, from, COMMAND_LINE_SIZE);
+	saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
 
-	memory_start = MAPTOPHYS((unsigned long)&_end);
-	memory_end   = GET_MEMORY_END(params);
+	setup_mem(from, memory_start_p, &memory_end);
+	check_initrd(*memory_start_p, memory_end);
 
 	init_task.mm->start_code = TASK_SIZE;
 	init_task.mm->end_code	 = TASK_SIZE + (unsigned long) &_etext;
 	init_task.mm->end_data	 = TASK_SIZE + (unsigned long) &_edata;
 	init_task.mm->brk	 = TASK_SIZE + (unsigned long) &_end;
 
-	/* Save unparsed command line copy for /proc/cmdline */
-	memcpy(saved_command_line, from, COMMAND_LINE_SIZE);
-	saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
-
-	for (;;) {
-		if (c == ' ' &&
-		    from[0] == 'm' &&
-		    from[1] == 'e' &&
-		    from[2] == 'm' &&
-		    from[3] == '=') {
-			memory_end = simple_strtoul(from+4, &from, 0);
-			if (*from == 'K' || *from == 'k') {
-				memory_end = memory_end << 10;
-				from++;
-			} else if (*from == 'M' || *from == 'm') {
-				memory_end = memory_end << 20;
-				from++;
-			}
-			memory_end = memory_end + PAGE_OFFSET;
-		}
-		c = *from++;
-		if (!c)
-			break;
-		if (COMMAND_LINE_SIZE <= ++len)
-			break;
-		*to++ = c;
-	}
-
-	*to = '\0';
 	*cmdline_p = command_line;
-	*memory_start_p = memory_start;
 	*memory_end_p = memory_end;
 
-	setup_initrd(params, memory_end);
-
 	sprintf(system_utsname.machine, "%s%c", armidlist[armidindex].arch_vsn, endian);
 	sprintf(elf_platform, "%s%c", armidlist[armidindex].elf_vsn, endian);
 
-#ifdef CONFIG_FB
-	conswitchp = &fb_con;
+#ifdef CONFIG_VT
+#if defined(CONFIG_VGA_CONSOLE)
+	conswitchp = &vga_con;
+#elif defined(CONFIG_DUMMY_CONSOLE)
+	conswitchp = &dummy_con;
+#endif
 #endif
+printascii("setup_arch done\n");
 }
 
 #if defined(CONFIG_ARCH_ARC)
@@ -341,10 +433,10 @@
 		"BogoMips\t: %lu.%02lu\n"
 		"Hardware\t: %s\n"
 		"Optimisation\t: %s\n"
-		"IO Bus\t: %s\n",
+		"IO Bus\t\t: %s\n",
 		armidlist[armidindex].manu,
 		armidlist[armidindex].name,
-		(int)arm_id & 15,
+		(int)processor_id & 15,
 		(loops_per_sec+2500) / 500000,
 		((loops_per_sec+2500) / 5000) % 100,
 		HARDWARE,
diff -u --recursive --new-file v2.1.120/linux/arch/arm/kernel/signal.c linux/arch/arm/kernel/signal.c
--- v2.1.120/linux/arch/arm/kernel/signal.c	Tue Jul 21 00:15:30 1998
+++ linux/arch/arm/kernel/signal.c	Sun Sep  6 10:44:47 1998
@@ -21,6 +21,17 @@
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 
+void checksignals(void)
+{
+	sigset_t *blocked = &current->blocked;
+	unsigned long mask = blocked->sig[0] | sigmask(SIGKILL) | sigmask(SIGINT) | sigmask(SIGQUIT);
+	mask &= blocked->sig[1];
+	if (~mask) {
+		printk("Bad signal mask\n");
+		__backtrace();
+	}
+}
+
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
 #define SWI_SYS_SIGRETURN (0xef000000|(__NR_sigreturn))
@@ -137,31 +148,35 @@
 static int
 restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc)
 {
-	__get_user(regs->ARM_r0, &sc->arm_r0);
-	__get_user(regs->ARM_r1, &sc->arm_r1);
-	__get_user(regs->ARM_r2, &sc->arm_r2);
-	__get_user(regs->ARM_r3, &sc->arm_r3);
-	__get_user(regs->ARM_r4, &sc->arm_r4);
-	__get_user(regs->ARM_r5, &sc->arm_r5);
-	__get_user(regs->ARM_r6, &sc->arm_r6);
-	__get_user(regs->ARM_r7, &sc->arm_r7);
-	__get_user(regs->ARM_r8, &sc->arm_r8);
-	__get_user(regs->ARM_r9, &sc->arm_r9);
-	__get_user(regs->ARM_r10, &sc->arm_r10);
-	__get_user(regs->ARM_fp, &sc->arm_fp);
-	__get_user(regs->ARM_ip, &sc->arm_ip);
-	__get_user(regs->ARM_sp, &sc->arm_sp);
-	__get_user(regs->ARM_lr, &sc->arm_lr);
-	__get_user(regs->ARM_pc, &sc->arm_pc);		/* security! */
+	int err = 0;
+
+	err |= __get_user(regs->ARM_r0, &sc->arm_r0);
+	err |= __get_user(regs->ARM_r1, &sc->arm_r1);
+	err |= __get_user(regs->ARM_r2, &sc->arm_r2);
+	err |= __get_user(regs->ARM_r3, &sc->arm_r3);
+	err |= __get_user(regs->ARM_r4, &sc->arm_r4);
+	err |= __get_user(regs->ARM_r5, &sc->arm_r5);
+	err |= __get_user(regs->ARM_r6, &sc->arm_r6);
+	err |= __get_user(regs->ARM_r7, &sc->arm_r7);
+	err |= __get_user(regs->ARM_r8, &sc->arm_r8);
+	err |= __get_user(regs->ARM_r9, &sc->arm_r9);
+	err |= __get_user(regs->ARM_r10, &sc->arm_r10);
+	err |= __get_user(regs->ARM_fp, &sc->arm_fp);
+	err |= __get_user(regs->ARM_ip, &sc->arm_ip);
+	err |= __get_user(regs->ARM_sp, &sc->arm_sp);
+	err |= __get_user(regs->ARM_lr, &sc->arm_lr);
+	err |= __get_user(regs->ARM_pc, &sc->arm_pc);
 #ifdef CONFIG_CPU_32
-	__get_user(regs->ARM_cpsr, &sc->arm_cpsr);	/* security! */
+	err |= __get_user(regs->ARM_cpsr, &sc->arm_cpsr);
 #endif
+	if (!valid_user_regs(regs))
+		return 1;
 
 	/* send SIGTRAP if we're single-stepping */
 	if (ptrace_cancel_bpt (current))
 		send_sig (SIGTRAP, current, 1);
 
-	return regs->ARM_r0;
+	return err;
 }
 
 asmlinkage int sys_sigreturn(struct pt_regs *regs)
@@ -185,11 +200,14 @@
 	recalc_sigpending(current);
 	spin_unlock_irq(&current->sigmask_lock);
 
-	return restore_sigcontext(regs, &frame->sc);
+	if (restore_sigcontext(regs, &frame->sc))
+		goto badframe;
+
+	return regs->ARM_r0;
 
 badframe:
-	lock_kernel();
-	do_exit(SIGSEGV);
+	force_sig(SIGSEGV, current);
+	return 0;
 }
 
 asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
@@ -210,40 +228,47 @@
 	recalc_sigpending(current);
 	spin_unlock_irq(&current->sigmask_lock);
 
-	return restore_sigcontext(regs, &frame->uc.uc_mcontext);
+	if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
+		goto badframe;
+
+	return regs->ARM_r0;
 
 badframe:
-	lock_kernel();
-	do_exit(SIGSEGV);
+	force_sig(SIGSEGV, current);
+	return 0;
 }
 
-static void
+static int
 setup_sigcontext(struct sigcontext *sc, /*struct _fpstate *fpstate,*/
 		 struct pt_regs *regs, unsigned long mask)
 {
-	__put_user (regs->ARM_r0, &sc->arm_r0);
-	__put_user (regs->ARM_r1, &sc->arm_r1);
-	__put_user (regs->ARM_r2, &sc->arm_r2);
-	__put_user (regs->ARM_r3, &sc->arm_r3);
-	__put_user (regs->ARM_r4, &sc->arm_r4);
-	__put_user (regs->ARM_r5, &sc->arm_r5);
-	__put_user (regs->ARM_r6, &sc->arm_r6);
-	__put_user (regs->ARM_r7, &sc->arm_r7);
-	__put_user (regs->ARM_r8, &sc->arm_r8);
-	__put_user (regs->ARM_r9, &sc->arm_r9);
-	__put_user (regs->ARM_r10, &sc->arm_r10);
-	__put_user (regs->ARM_fp, &sc->arm_fp);
-	__put_user (regs->ARM_ip, &sc->arm_ip);
-	__put_user (regs->ARM_sp, &sc->arm_sp);
-	__put_user (regs->ARM_lr, &sc->arm_lr);
-	__put_user (regs->ARM_pc, &sc->arm_pc);		/* security! */
+	int err = 0;
+
+	err |= __put_user (regs->ARM_r0, &sc->arm_r0);
+	err |= __put_user (regs->ARM_r1, &sc->arm_r1);
+	err |= __put_user (regs->ARM_r2, &sc->arm_r2);
+	err |= __put_user (regs->ARM_r3, &sc->arm_r3);
+	err |= __put_user (regs->ARM_r4, &sc->arm_r4);
+	err |= __put_user (regs->ARM_r5, &sc->arm_r5);
+	err |= __put_user (regs->ARM_r6, &sc->arm_r6);
+	err |= __put_user (regs->ARM_r7, &sc->arm_r7);
+	err |= __put_user (regs->ARM_r8, &sc->arm_r8);
+	err |= __put_user (regs->ARM_r9, &sc->arm_r9);
+	err |= __put_user (regs->ARM_r10, &sc->arm_r10);
+	err |= __put_user (regs->ARM_fp, &sc->arm_fp);
+	err |= __put_user (regs->ARM_ip, &sc->arm_ip);
+	err |= __put_user (regs->ARM_sp, &sc->arm_sp);
+	err |= __put_user (regs->ARM_lr, &sc->arm_lr);
+	err |= __put_user (regs->ARM_pc, &sc->arm_pc);
 #ifdef CONFIG_CPU_32
-	__put_user (regs->ARM_cpsr, &sc->arm_cpsr);	/* security! */
+	err |= __put_user (regs->ARM_cpsr, &sc->arm_cpsr);
 #endif
 
-	__put_user (current->tss.trap_no, &sc->trap_no);
-	__put_user (current->tss.error_code, &sc->error_code);
-	__put_user (mask, &sc->oldmask);
+	err |= __put_user (current->tss.trap_no, &sc->trap_no);
+	err |= __put_user (current->tss.error_code, &sc->error_code);
+	err |= __put_user (mask, &sc->oldmask);
+
+	return err;
 }
 
 static void setup_frame(int sig, struct k_sigaction *ka,
@@ -251,41 +276,47 @@
 {
 	struct sigframe *frame;
 	unsigned long retcode;
+	int err = 0;
 
 	frame = (struct sigframe *)regs->ARM_sp - 1;
 
 	if (!access_ok(VERIFT_WRITE, frame, sizeof (*frame)))
 		goto segv_and_exit;
 
-	setup_sigcontext(&frame->sc, /*&frame->fpstate,*/ regs, set->sig[0]);
+	err |= setup_sigcontext(&frame->sc, /*&frame->fpstate,*/ regs, set->sig[0]);
 
 	if (_NSIG_WORDS > 1) {
-		__copy_to_user(frame->extramask, &set->sig[1],
-			       sizeof(frame->extramask));
+		err |= __copy_to_user(frame->extramask, &set->sig[1],
+				      sizeof(frame->extramask));
 	}
 
 	/* Set up to return from userspace.  If provided, use a stub
 	   already in userspace.  */
 	if (ka->sa.sa_flags & SA_RESTORER) {
-		retcode = (unsigned long)ka->sa.sa_restorer; /* security! */
+		retcode = (unsigned long)ka->sa.sa_restorer;
 	} else {
 		retcode = (unsigned long)&frame->retcode;
-		__put_user(SWI_SYS_SIGRETURN, &frame->retcode);
+		err |= __put_user(SWI_SYS_SIGRETURN, &frame->retcode);
 		__flush_entry_to_ram (&frame->retcode);
 	}
 
+	if (err)
+		goto segv_and_exit;
+
 	if (current->exec_domain && current->exec_domain->signal_invmap && sig < 32)
 		regs->ARM_r0 = current->exec_domain->signal_invmap[sig];
 	else
 		regs->ARM_r0 = sig;
 	regs->ARM_sp = (unsigned long)frame;
 	regs->ARM_lr = retcode;
-	regs->ARM_pc = (unsigned long)ka->sa.sa_handler;		/* security! */
-	return;
+	regs->ARM_pc = (unsigned long)ka->sa.sa_handler;
+	if (valid_user_regs(regs))
+		return;
 
 segv_and_exit:
-	lock_kernel();
-	do_exit (SIGSEGV);
+	if (sig == SIGSEGV)
+		ka->sa.sa_handler = SIG_DFL;
+	force_sig(SIGSEGV, current);
 }
 
 static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
@@ -293,44 +324,50 @@
 {
 	struct rt_sigframe *frame;
 	unsigned long retcode;
+	int err = 0;
 
 	frame = (struct rt_sigframe *)regs->ARM_sp - 1;
 	if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
 		goto segv_and_exit;
 
-	__put_user(&frame->info, &frame->pinfo);
-	__put_user(&frame->uc, &frame->puc);
-	__copy_to_user(&frame->info, info, sizeof(*info));
+	err |= __put_user(&frame->info, &frame->pinfo);
+	err |= __put_user(&frame->uc, &frame->puc);
+	err |= __copy_to_user(&frame->info, info, sizeof(*info));
 
 	/* Clear all the bits of the ucontext we don't use.  */
-	__clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));
+	err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));
 
-	setup_sigcontext(&frame->uc.uc_mcontext, /*&frame->fpstate,*/
-			 regs, set->sig[0]);
-	__copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+	err |= setup_sigcontext(&frame->uc.uc_mcontext, /*&frame->fpstate,*/
+				regs, set->sig[0]);
+	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
 
 	/* Set up to return from userspace.  If provided, use a stub
 	   already in userspace.  */
 	if (ka->sa.sa_flags & SA_RESTORER) {
-		retcode = (unsigned long)ka->sa.sa_restorer; /* security! */
+		retcode = (unsigned long)ka->sa.sa_restorer;
 	} else {
 		retcode = (unsigned long)&frame->retcode;
-		__put_user(SWI_SYS_RT_SIGRETURN, &frame->retcode);
+		err |= __put_user(SWI_SYS_RT_SIGRETURN, &frame->retcode);
 		__flush_entry_to_ram (&frame->retcode);
 	}
 
+	if (err)
+		goto segv_and_exit;
+
 	if (current->exec_domain && current->exec_domain->signal_invmap && sig < 32)
 		regs->ARM_r0 = current->exec_domain->signal_invmap[sig];
 	else
 		regs->ARM_r0 = sig;
 	regs->ARM_sp = (unsigned long)frame;
 	regs->ARM_lr = retcode;
-	regs->ARM_pc = (unsigned long)ka->sa.sa_handler;		/* security! */
-	return;
+	regs->ARM_pc = (unsigned long)ka->sa.sa_handler;
+	if (valid_user_regs(regs))
+		return;
 
 segv_and_exit:
-	lock_kernel();
-	do_exit (SIGSEGV);
+	if (sig == SIGSEGV)
+		ka->sa.sa_handler = SIG_DFL;
+	force_sig(SIGSEGV, current);
 }
 
 /*
diff -u --recursive --new-file v2.1.120/linux/arch/arm/kernel/sys_arm.c linux/arch/arm/kernel/sys_arm.c
--- v2.1.120/linux/arch/arm/kernel/sys_arm.c	Tue Jul 21 00:15:30 1998
+++ linux/arch/arm/kernel/sys_arm.c	Sun Sep  6 10:44:47 1998
@@ -363,14 +363,6 @@
 
 asmlinkage int sys_pause(void)
 {
-	static int warned = 0;
-
-	if (warned == 0) {
-		warned ++;
-		printk (KERN_NOTICE "%s (%d): obsolete pause call\n",
-			current->comm, current->pid);
-	}
-
 	current->state = TASK_INTERRUPTIBLE;
 	schedule();
 	return -ERESTARTNOHAND;
diff -u --recursive --new-file v2.1.120/linux/arch/arm/kernel/time.c linux/arch/arm/kernel/time.c
--- v2.1.120/linux/arch/arm/kernel/time.c	Tue Jul 21 00:15:30 1998
+++ linux/arch/arm/kernel/time.c	Sun Sep  6 10:44:47 1998
@@ -62,7 +62,7 @@
  * machines were long is 32-bit! (However, as time_t is signed, we
  * will already get problems at other places on 2038-01-19 03:14:08)
  */
-static inline unsigned long mktime(unsigned int year, unsigned int mon,
+unsigned long mktime(unsigned int year, unsigned int mon,
 	unsigned int day, unsigned int hour,
 	unsigned int min, unsigned int sec)
 {
diff -u --recursive --new-file v2.1.120/linux/arch/arm/kernel/traps.c linux/arch/arm/kernel/traps.c
--- v2.1.120/linux/arch/arm/kernel/traps.c	Tue Jul 21 00:15:30 1998
+++ linux/arch/arm/kernel/traps.c	Sun Sep  6 10:44:47 1998
@@ -24,9 +24,6 @@
 #include <asm/atomic.h>
 #include <asm/pgtable.h>
 
-extern struct task_struct *last_task_used_math;
-extern void fpe_save(struct fp_soft_struct *);
-extern void fpe_restore(struct fp_soft_struct *);
 extern void die_if_kernel(char *str, struct pt_regs *regs, int err, int ret);
 extern void c_backtrace (unsigned long fp, int pmode);
 extern int ptrace_cancel_bpt (struct task_struct *);
@@ -252,26 +249,7 @@
  */
 asmlinkage void math_state_restore (void)
 {
-	if (last_task_used_math == current)
-		return;
-	if (last_task_used_math)
-		/*
-		 * Save current fp state into last_task_used_math->tss.fpe_save
-		 */
-		fpe_save (&last_task_used_math->tss.fpstate.soft);
-	last_task_used_math = current;
-	if (current->used_math) {
-	    	/*
-    		 * Restore current fp state from current->tss.fpe_save
-	    	 */
-    		fpe_restore (&current->tss.fpstate.soft);
-	} else {
-    		/*
-	    	 * initialise fp state
-    		 */
-	    	fpe_restore (&init_task.tss.fpstate.soft);
-	    	current->used_math = 1;
-	}
+    	current->used_math = 1;
 }
 
 asmlinkage void arm_syscall (int no, struct pt_regs *regs)
diff -u --recursive --new-file v2.1.120/linux/arch/arm/lib/Makefile linux/arch/arm/lib/Makefile
--- v2.1.120/linux/arch/arm/lib/Makefile	Tue Jul 21 00:15:30 1998
+++ linux/arch/arm/lib/Makefile	Sun Sep  6 10:44:47 1998
@@ -5,15 +5,15 @@
 #
 
 L_TARGET := lib.a
-L_OBJS   := backtrace.o bitops.o checksum.o delay.o fp_support.o \
-	    loaders.o memcpy.o system.o string.o uaccess.o io.o
+L_OBJS   := backtrace.o bitops.o checksum.o delay.o io.o memcpy.o \
+	    system.o string.o uaccess.o
 
 ifeq ($(PROCESSOR),armo)
   L_OBJS += uaccess-armo.o
 endif
 
 ifdef CONFIG_ARCH_ACORN
-  L_OBJS += ll_char_wr.o io-acorn.o
+  L_OBJS += loaders.o ll_char_wr.o io-acorn.o
   ifdef CONFIG_ARCH_A5K
     L_OBJS += floppydma.o
   endif
diff -u --recursive --new-file v2.1.120/linux/arch/arm/lib/checksum.S linux/arch/arm/lib/checksum.S
--- v2.1.120/linux/arch/arm/lib/checksum.S	Sun Jun  7 11:16:26 1998
+++ linux/arch/arm/lib/checksum.S	Sun Sep  6 10:44:47 1998
@@ -1,5 +1,5 @@
 /*
- * linux/arch/arm/lib/iputils.S
+ * linux/arch/arm/lib/checksum.S
  *
  * Copyright (C) 1995, 1996, 1997, 1998 Russell King
  */
@@ -71,11 +71,11 @@
 #if defined(CONFIG_CPU_32)
 
 		.macro	save_regs
-		stmfd	sp!, {r4 - r8, fp, ip, lr, pc}
+		stmfd	sp!, {r1 - r2, r4 - r8, fp, ip, lr, pc}
 		.endm
 
 #define LOAD_REGS(cond)					\
-		LOADREGS(##cond##ea,fp,{r4 - r8, fp, sp, pc})
+		LOADREGS(##cond##ea,fp,{r1 - r2, r4 - r8, fp, sp, pc})
 
 		.macro	load1b,	reg1
 9999:		ldrbt	\reg1, [r0], $1
@@ -127,7 +127,7 @@
 #elif defined(CONFIG_CPU_26)
 
 		.macro	save_regs
-		stmfd	sp!, {r4 - r9, fp, ip, lr, pc}
+		stmfd	sp!, {r1 - r2, r4 - r9, fp, ip, lr, pc}
 		mov	r9, sp, lsr #13
 		mov	r9, r9, lsl #13
 		ldr	r9, [r9, #TSK_ADDR_LIMIT]
@@ -135,7 +135,7 @@
 		.endm
 
 #define LOAD_REGS(cond)					\
-		LOADREGS(##cond##ea,fp,{r4 - r9, fp, sp, pc})
+		LOADREGS(##cond##ea,fp,{r1 - r2, r4 - r9, fp, sp, pc})
 
 		.macro	load1b,	reg1
 		tst	r9, #0x01
@@ -448,13 +448,23 @@
 		mov	r4, r4, lsr #8
 		b	.exit
 
+#if defined(CONFIG_CPU_32)
 		.section .fixup,"ax"
+#endif
 		.align	4
 6001:		mov	r4, #-EFAULT
 		ldr	r5, [fp, #4]
 		str	r4, [r5]
+		ldmia	sp, {r1, r2}		@ retrieve original arguments
+		add	r2, r2, r1
+		mov	r3, #0			@ zero the buffer
+6002:		teq	r2, r1
+		strneb	r3, [r1], #1
+		bne	6002b
 		LOAD_REGS(al)
+#if defined(CONFIG_CPU_32)
 		.previous
+#endif
 
 /* Function: __u32 csum_partial_copy (const char *src, char *dst, int len, __u32 sum)
  * Params  : r0 = src, r1 = dst, r2 = len, r3 = checksum
@@ -701,7 +711,7 @@
 		mov	r4, r4, lsr #8
 		b	Lexit
 
-ENTRY(csum_ipv6_magic)
+ENTRY(__csum_ipv6_magic)
 		stmfd	sp!, {lr}
 		adds	ip, r2, r3
 		ldmia	r1, {r1 - r3, lr}
diff -u --recursive --new-file v2.1.120/linux/arch/arm/lib/fp_support.c linux/arch/arm/lib/fp_support.c
--- v2.1.120/linux/arch/arm/lib/fp_support.c	Tue Jan 20 16:39:41 1998
+++ linux/arch/arm/lib/fp_support.c	Wed Dec 31 16:00:00 1969
@@ -1,22 +0,0 @@
-/*
- * linux/arch/arm/lib/fp_support.c
- *
- * Copyright (C) 1995, 1996 Russell King
- */
-
-#include <linux/sched.h>
-#include <linux/linkage.h>
-
-extern void (*fp_save)(struct fp_soft_struct *);
-
-asmlinkage void fp_setup(void)
-{
-	struct task_struct *p;
-
-	p = &init_task;
-	do {
-		fp_save(&p->tss.fpstate.soft);
-		p = p->next_task;
-	}
-	while (p != &init_task);
-}
diff -u --recursive --new-file v2.1.120/linux/arch/arm/lib/getconsdata.c linux/arch/arm/lib/getconsdata.c
--- v2.1.120/linux/arch/arm/lib/getconsdata.c	Fri May  8 23:14:42 1998
+++ linux/arch/arm/lib/getconsdata.c	Sun Sep  6 10:44:47 1998
@@ -24,8 +24,10 @@
 
 unsigned long TSK_STATE = OFF_TSK(state);
 unsigned long TSK_FLAGS = OFF_TSK(flags);
+unsigned long TSK_NEED_RESCHED = OFF_TSK(need_resched);
 unsigned long TSK_SIGPENDING = OFF_TSK(sigpending);
 unsigned long TSK_ADDR_LIMIT = OFF_TSK(addr_limit);
+unsigned long TSK_USED_MATH = OFF_TSK(used_math);
 
 unsigned long MM = OFF_TSK(mm);
 unsigned long PGD = OFF_MM(pgd);
diff -u --recursive --new-file v2.1.120/linux/arch/arm/lib/io-acorn.S linux/arch/arm/lib/io-acorn.S
--- v2.1.120/linux/arch/arm/lib/io-acorn.S	Wed May 20 19:10:37 1998
+++ linux/arch/arm/lib/io-acorn.S	Sun Sep  6 10:44:47 1998
@@ -166,6 +166,13 @@
 		bgt	3b
 		LOADREGS(ea, fp, {r4 - r8, fp, sp, pc})
 
+/*
+ * These make no sense on Acorn machines atm.
+ */
+ENTRY(insl)
+ENTRY(outsl)
+		RETINSTR(mov,pc,lr)
+
 @ Purpose: write a memc register
 @ Proto  : void memc_write(int register, int value);
 @ Returns: nothing
diff -u --recursive --new-file v2.1.120/linux/arch/arm/lib/io.c linux/arch/arm/lib/io.c
--- v2.1.120/linux/arch/arm/lib/io.c	Tue Jul 21 00:15:30 1998
+++ linux/arch/arm/lib/io.c	Sun Sep  6 10:44:47 1998
@@ -40,4 +40,3 @@
 		dst++;
 	}
 }
-
diff -u --recursive --new-file v2.1.120/linux/arch/arm/lib/system.S linux/arch/arm/lib/system.S
--- v2.1.120/linux/arch/arm/lib/system.S	Mon Feb 23 18:12:02 1998
+++ linux/arch/arm/lib/system.S	Sun Sep  6 10:44:47 1998
@@ -16,5 +16,5 @@
 		b	SYMBOL_NAME(panic)
 
 .abort_msg:	.ascii	"Eek! Got to an abort() from %p! "
-		.ascii	"(Please report to rmk@ecs.soton.ac.uk)\n\0"
+		.ascii	"(Please report to rmk@arm.uk.linux.org)\n\0"
 		.align
diff -u --recursive --new-file v2.1.120/linux/arch/arm/lib/testm.c linux/arch/arm/lib/testm.c
--- v2.1.120/linux/arch/arm/lib/testm.c	Tue Jan 20 16:39:42 1998
+++ linux/arch/arm/lib/testm.c	Wed Dec 31 16:00:00 1969
@@ -1,81 +0,0 @@
-char buffer[1036];
-char buffer2[1036];
-
-int main ()
-{
-	char *p;
-	int i, o, o2, l;
-
-	printf ("Testing memset\n");
-	for (l = 1; l < 1020; l ++) {
-		for (o = 0; o < 4; o++) {
-			p = buffer + o + 4;
-			for (i = 0; i < l + 12; i++)
-				buffer[i] = 0x55;
-
-			memset (p, 0xaa, l);
-	
-			for (i = 0; i < l; i++)
-				if (p[i] != 0xaa)
-					printf ("Error: %X+%d\n", p, i);
-			if (p[-1] != 0x55 || p[-2] != 0x55 || p[-3] != 0x55 || p[-4] != 0x55)
-				printf ("Error before %X\n", p);
-			if (p[l] != 0x55 || p[l+1] != 0x55 || p[l+2] != 0x55 || p[l+3] != 0x55)
-				printf ("Error at end: %p: %02X %02X %02X %02X\n", p+l, p[l], p[l+1], p[l+2], p[l+3]);
-		}
-	}
-
-	printf ("Testing memcpy s > d\n");
-	for (l = 1; l < 1020; l++) {
-		for (o = 0; o < 4; o++) {
-			for (o2 = 0; o2 < 4; o2++) {
-				char *d, *s;
-
-				for (i = 0; i < l + 12; i++)
-					buffer[i] = (i & 0x3f) + 0x40;
-				for (i = 0; i < 1036; i++)
-					buffer2[i] = 0;
-
-				s = buffer + o;
-				d = buffer2 + o2 + 4;
-
-				memcpy (d, s, l);
-
-				for (i = 0; i < l; i++)
-					if (s[i] != d[i])
-						printf ("Error at %X+%d -> %X+%d (%02X != %02X)\n", s, i, d, i, s[i], d[i]);
-				if (d[-1] || d[-2] || d[-3] || d[-4])
-					printf ("Error before %X\n", d);
-				if (d[l] || d[l+1] || d[l+2] || d[l+3])
-					printf ("Error after %X\n", d+l);
-			}
-		}
-	}
-
-	printf ("Testing memcpy s < d\n");
-	for (l = 1; l < 1020; l++) {
-		for (o = 0; o < 4; o++) {
-			for (o2 = 0; o2 < 4; o2++) {
-				char *d, *s;
-
-				for (i = 0; i < l + 12; i++)
-					buffer2[i] = (i & 0x3f) + 0x40;
-				for (i = 0; i < 1036; i++)
-					buffer[i] = 0;
-
-				s = buffer2 + o;
-				d = buffer + o2 + 4;
-
-				memcpy (d, s, l);
-
-				for (i = 0; i < l; i++)
-					if (s[i] != d[i])
-						printf ("Error at %X+%d -> %X+%d (%02X != %02X)\n", s, i, d, i, s[i], d[i]);
-				if (d[-1] || d[-2] || d[-3] || d[-4])
-					printf ("Error before %X\n", d);
-				if (d[l] || d[l+1] || d[l+2] || d[l+3])
-					printf ("Error after %X\n", d+l);
-			}
-		}
-	}
-}
diff -u --recursive --new-file v2.1.120/linux/arch/arm/lib/uaccess.S linux/arch/arm/lib/uaccess.S
--- v2.1.120/linux/arch/arm/lib/uaccess.S	Wed May 20 19:10:37 1998
+++ linux/arch/arm/lib/uaccess.S	Sun Sep  6 10:44:47 1998
@@ -312,7 +312,7 @@
 		b	.cfu_dest_aligned
 
 ENTRY(__arch_copy_from_user)
-		stmfd	sp!, {r2, r4 - r7, lr}
+		stmfd	sp!, {r0, r2, r4 - r7, lr}
 		cmp	r2, #4
 		blt	.cfu_not_enough
 		ands	ip, r0, #3
@@ -375,7 +375,8 @@
 		movs	ip, r2
 		bne	.cfu_nowords
 .cfu_finished:	mov	r0, #0
-		LOADREGS(fd,sp!,{r2, r4 - r7, pc})
+		add	sp, sp, #8
+		LOADREGS(fd,sp!,{r4 - r7, pc})
 
 .cfu_src_not_aligned:
 		bic	r1, r1, #3
@@ -548,7 +549,12 @@
 #ifndef TESTING
 		.section .fixup,"ax"
 		.align	0
-9001:		LOADREGS(fd,sp!, {r0, r4 - r7, pc})
+		/* We took an exception.  Zero out the buffer and pretend no
+		   data was copied.  */
+9001:		ldr	r0, [sp], #4
+		ldr	r1, [sp]
+		bl	SYMBOL_NAME(memzero)
+		LOADREGS(fd,sp!, {r0, r4 - r7, pc})
 		.previous
 #endif
 
@@ -636,7 +642,11 @@
 
 		.section .fixup,"ax"
 		.align	0
-9001:		mov	r0, #-EFAULT
+9001:		mov	ip, #0
+1:		strb	ip, [r0], #1
+		subs	r2, r2, #1
+		bpl	1b
+		mov	r0, #-EFAULT
 		LOADREGS(fd, sp!, {pc})
 		.previous
 
diff -u --recursive --new-file v2.1.120/linux/arch/arm/mm/fault-armo.c linux/arch/arm/mm/fault-armo.c
--- v2.1.120/linux/arch/arm/mm/fault-armo.c	Tue Jul 21 00:15:30 1998
+++ linux/arch/arm/mm/fault-armo.c	Wed Sep  9 08:56:58 1998
@@ -8,7 +8,6 @@
 #include <linux/config.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
-#include <linux/head.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/string.h>
diff -u --recursive --new-file v2.1.120/linux/arch/arm/mm/fault-armv.c linux/arch/arm/mm/fault-armv.c
--- v2.1.120/linux/arch/arm/mm/fault-armv.c	Fri May  8 23:14:42 1998
+++ linux/arch/arm/mm/fault-armv.c	Wed Sep  9 08:56:58 1998
@@ -7,7 +7,6 @@
 
 #include <linux/signal.h>
 #include <linux/sched.h>
-#include <linux/head.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/string.h>
@@ -24,8 +23,6 @@
 
 #define FAULT_CODE_READ		0x02
 #define FAULT_CODE_USER		0x01
-
-#define USER_PTRS_PER_PGD (TASK_SIZE / PGDIR_SIZE)
 
 struct pgtable_cache_struct quicklists;
 
diff -u --recursive --new-file v2.1.120/linux/arch/arm/mm/init.c linux/arch/arm/mm/init.c
--- v2.1.120/linux/arch/arm/mm/init.c	Thu Aug  6 14:06:28 1998
+++ linux/arch/arm/mm/init.c	Wed Sep  9 08:56:58 1998
@@ -7,7 +7,6 @@
 #include <linux/config.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
-#include <linux/head.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/string.h>
diff -u --recursive --new-file v2.1.120/linux/arch/arm/mm/mm-armv.c linux/arch/arm/mm/mm-armv.c
--- v2.1.120/linux/arch/arm/mm/mm-armv.c	Tue Jul 21 00:15:30 1998
+++ linux/arch/arm/mm/mm-armv.c	Sun Sep  6 10:44:47 1998
@@ -68,4 +68,3 @@
 
 	return start_mem;
 }
-
diff -u --recursive --new-file v2.1.120/linux/arch/arm/mm/mm-ebsa110.c linux/arch/arm/mm/mm-ebsa110.c
--- v2.1.120/linux/arch/arm/mm/mm-ebsa110.c	Tue Jul 21 00:15:30 1998
+++ linux/arch/arm/mm/mm-ebsa110.c	Sun Sep  6 10:44:47 1998
@@ -5,8 +5,14 @@
  *
  * Copyright (C) 1998 Russell King
  */
+#include <linux/sched.h>
+#include <linux/mm.h>
 #include <linux/init.h>
+
+#include <asm/pgtable.h>
+#include <asm/page.h>
 #include <asm/io.h>
+#include <asm/proc/mm-init.h>
  
 #define MAPPING \
 	{ IO_BASE - PGDIR_SIZE	, 0xc0000000	, PGDIR_SIZE	, DOMAIN_IO, 0, 1 }, \
diff -u --recursive --new-file v2.1.120/linux/arch/arm/mm/mm-rpc.c linux/arch/arm/mm/mm-rpc.c
--- v2.1.120/linux/arch/arm/mm/mm-rpc.c	Tue Jul 21 00:15:30 1998
+++ linux/arch/arm/mm/mm-rpc.c	Sun Sep  6 10:44:47 1998
@@ -68,7 +68,8 @@
 	return phys + rambank[bank].phys_offset;
 }
 
-void init_dram_banks(struct param_struct *params)
+__initfunc(void
+init_dram_banks(struct param_struct *params))
 {
 	unsigned int bank;
 	unsigned int bytes = 0;
diff -u --recursive --new-file v2.1.120/linux/arch/arm/mm/proc-arm6,7.S linux/arch/arm/mm/proc-arm6,7.S
--- v2.1.120/linux/arch/arm/mm/proc-arm6,7.S	Tue Jul 21 00:15:30 1998
+++ linux/arch/arm/mm/proc-arm6,7.S	Sun Sep  6 10:44:47 1998
@@ -431,6 +431,8 @@
 		.word	_arm6_7_flush_tlb_all		@ 44
 		.word	_arm6_7_flush_tlb_area		@ 48
 		.word	_arm7_set_pmd			@ 52
-		.word	_arm6_7_reset			@ 54
-		.word	_arm6_7_flush_cache		@ 58
+		.word	_arm6_7_reset			@ 56
+		.word	_arm6_7_flush_cache		@ 60
 
+		.word	_arm6_7_flush_cache		@ 64
+		.word	_arm6_7_flush_cache		@ 68
diff -u --recursive --new-file v2.1.120/linux/arch/arm/mm/proc-sa110.S linux/arch/arm/mm/proc-sa110.S
--- v2.1.120/linux/arch/arm/mm/proc-sa110.S	Tue Apr 14 14:29:20 1998
+++ linux/arch/arm/mm/proc-sa110.S	Sun Sep  6 10:44:47 1998
@@ -21,19 +21,22 @@
  */
 		.align	5
 _sa110_flush_cache_all:					@ preserves r0
+		mov	r2, #1
+_sa110_flush_cache_all_r2:
 		ldr	r3, =Lclean_switch
-		ldr	r2, [r3]
-		ands	r2, r2, #1
-		eor	r2, r2, #1
-		str	r2, [r3]
+		ldr	r1, [r3]
+		ands	r1, r1, #1
+		eor	r1, r1, #1
+		str	r1, [r3]
 		ldr	ip, =0xdf000000
 		addne	ip, ip, #32768
 		add	r1, ip, #16384			@ only necessary for 16k
-1:		ldr	r2, [ip], #32
+1:		ldr	r3, [ip], #32
 		teq	r1, ip
 		bne	1b
 		mov	ip, #0
-		mcr	p15, 0, ip, c7, c5, 0		@ flush I cache
+		tst	r2, #1
+		mcrne	p15, 0, ip, c7, c5, 0		@ flush I cache
 		mcr	p15, 0, ip, c7, c10, 4		@ drain WB
 		mov	pc, lr
 
@@ -50,7 +53,7 @@
 _sa110_flush_cache_area:
 		sub	r3, r1, r0
 		cmp	r3, #32768
-		bgt	_sa110_flush_cache_all
+		bgt	_sa110_flush_cache_all_r2
 1:		mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
 		mcr	p15, 0, r0, c7, c6, 1		@ flush D entry
 		add	r0, r0, #32
@@ -65,6 +68,55 @@
 		mov	pc, lr
 
 /*
+ * Function: sa110_cache_wback_area(unsigned long address, unsigned long end)
+ *
+ * Params  : address	Area start address
+ *	   : end	Area end address
+ *
+ * Purpose : ensure all dirty cachelines in the specified area have been
+ *	     written out to memory (for DMA)
+ */
+		.align	5
+_sa110_cache_wback_area:
+		sub	r3, r1, r0
+		cmp	r3, #32768
+		movgt	r2, #0
+		bgt	_sa110_flush_cache_all
+1:		mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
+		add	r0, r0, #32
+		mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
+		add	r0, r0, #32
+		cmp	r0, r1
+		blt	1b
+		mcr	p15, 0, r0, c7, c10, 4		@ drain WB
+		mov	pc, lr
+
+/*
+ * Function: sa110_cache_purge_area(unsigned long address, unsigned long end)
+ *
+ * Params  : address	Area start address
+ *	   : end	Area end address
+ *
+ * Purpose : throw away all D-cached data in specified region without
+ *	     an obligation to write it ack.
+ *
+ * Note    : Must clean the D-cached entries around the boundaries if the
+ *	     start and/or end address are not cache aligned.
+ */
+		.align	5
+_sa110_cache_purge_area:
+		tst	r0, #31
+		bic	r0, r0, #31
+		mcrne	p15, 0, r0, c7, c10, 1		@ clean D entry
+		tst	r1, #31
+		mcrne	p15, 0, r1, c7, c10, 1		@ clean D entry
+1:		mcr	p15, 0, r0, c7, c6, 1		@ flush D entry
+		add	r0, r0, #32
+		cmp	r0, r1
+		blt	1b
+		mov	pc, lr
+
+/*
  * Function: sa110_flush_cache_entry (unsigned long address)
  *
  * Params  : address	Address of cache line to flush
@@ -129,7 +181,7 @@
 		mov	pc, lr
 
 /*
- * Function: sa110_flush_tlb_area (unsigned long address, int end, int flags)
+ * Function: sa110_flush_tlb_area (unsigned long address, unsigned long end, int flags)
  *
  * Params  : address	Area start address
  *	   : end	Area end address
@@ -266,6 +318,7 @@
 		orr	r1, r1, #F_BIT | I_BIT
 		msr	cpsr, r1
 		stmfd	sp!, {r1, lr}
+		mov	r2, #1
 		bl	_sa110_flush_cache_all
 		bl	_sa110_flush_tlb_all
 		mcr	p15, 0, ip, c7, c7, 0		@ flush I,D caches
@@ -297,5 +350,8 @@
 		.word	_sa110_flush_tlb_area		@ 48
 
 		.word	_sa110_set_pmd			@ 52
-		.word	_sa110_reset			@ 54
-		.word	_sa110_flush_icache_area	@ 58
+		.word	_sa110_reset			@ 56
+		.word	_sa110_flush_icache_area	@ 60
+
+		.word	_sa110_cache_wback_area		@ 64
+		.word	_sa110_cache_purge_area		@ 68
diff -u --recursive --new-file v2.1.120/linux/arch/arm/mm/small_page.c linux/arch/arm/mm/small_page.c
--- v2.1.120/linux/arch/arm/mm/small_page.c	Tue Jan 20 16:39:42 1998
+++ linux/arch/arm/mm/small_page.c	Wed Sep  9 08:56:58 1998
@@ -9,7 +9,6 @@
 
 #include <linux/signal.h>
 #include <linux/sched.h>
-#include <linux/head.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/string.h>
diff -u --recursive --new-file v2.1.120/linux/arch/arm/vmlinux-armo.lds linux/arch/arm/vmlinux-armo.lds
--- v2.1.120/linux/arch/arm/vmlinux-armo.lds	Tue Jul 21 00:15:30 1998
+++ linux/arch/arm/vmlinux-armo.lds	Sun Sep  6 10:44:47 1998
@@ -1,5 +1,5 @@
 /* ld script to make ARM Linux kernel
- * taken from the i386 version
+ * taken from the i386 version by Russell King
  * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>
  */
 OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")
@@ -28,17 +28,15 @@
 
   _etext = .;			/* End of text section */
 
+  . = ALIGN(8192);
   .data : {			/* Data */
+	*(.init.task)
 	*(.data)
 	CONSTRUCTORS
 	}
 
   _edata = .;			/* End of data section */
 
-  /* This has to be aligned to a page boundary to do us any good.  This
-     alignment is overkill for ARM6 up but needed for ARM3.  Since all this
-     data will be thrown away I don't think the extra padding will hurt.
-       -- pb */
   . = ALIGN(32768);		/* Init code and data */
   __init_begin = .;
   .text.init : { *(.text.init) }
diff -u --recursive --new-file v2.1.120/linux/arch/arm/vmlinux-armv.lds linux/arch/arm/vmlinux-armv.lds
--- v2.1.120/linux/arch/arm/vmlinux-armv.lds	Tue Jul 21 00:15:30 1998
+++ linux/arch/arm/vmlinux-armv.lds	Sun Sep  6 10:44:47 1998
@@ -1,5 +1,5 @@
 /* ld script to make ARM Linux kernel
- * taken from the i386 version
+ * taken from the i386 version by Russell King
  * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>
  */
 OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")
@@ -28,17 +28,15 @@
 
   _etext = .;			/* End of text section */
 
+  . = ALIGN(8192);
   .data : {			/* Data */
+	*(.init.task)
 	*(.data)
 	CONSTRUCTORS
 	}
 
   _edata = .;			/* End of data section */
 
-  /* This has to be aligned to a page boundary to do us any good.  This
-     alignment is overkill for ARM6 up but needed for ARM3.  Since all this
-     data will be thrown away I don't think the extra padding will hurt.
-       -- pb */
   . = ALIGN(4096);		/* Init code and data */
   __init_begin = .;
   .text.init : { *(.text.init) }
diff -u --recursive --new-file v2.1.120/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.1.120/linux/arch/i386/defconfig	Thu Aug  6 14:06:28 1998
+++ linux/arch/i386/defconfig	Sun Sep  6 11:06:34 1998
@@ -198,6 +198,7 @@
 # CONFIG_SLIP is not set
 # CONFIG_NET_RADIO is not set
 # CONFIG_TR is not set
+# CONFIG_HOSTESS_SV11 is not set
 # CONFIG_WAN_DRIVERS is not set
 # CONFIG_LAPBETHER is not set
 # CONFIG_X25_ASY is not set
diff -u --recursive --new-file v2.1.120/linux/arch/i386/kernel/bios32.c linux/arch/i386/kernel/bios32.c
--- v2.1.120/linux/arch/i386/kernel/bios32.c	Wed Aug 26 11:37:33 1998
+++ linux/arch/i386/kernel/bios32.c	Tue Sep  8 13:46:33 1998
@@ -1044,24 +1044,20 @@
 #ifdef __SMP__
 		/*
 		 * Recalculate IRQ numbers if we use the I/O APIC
-		 *
-		 * NOTE! If the "original" interrupt is marked as an old-fashioned
-		 * irq, we have to keep it old-fashioned even if it's a PCI device
-		 * and we could have found it in the MP-table transform.
 		 */
-		if (IO_APIC_IRQ(dev->irq)) {
+		{
 			int irq;
 			unsigned char pin;
 
 			pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
 			if (pin) {
 				pin--;		/* interrupt pins are numbered starting from 1 */
-				irq = IO_APIC_get_PCI_irq_vector (dev->bus->number, PCI_SLOT(dev->devfn), pin);
+				irq = IO_APIC_get_PCI_irq_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin);
 				if (irq >= 0) {
 					printk("PCI->APIC IRQ transform: (B%d,I%d,P%d) -> %d\n",
 						dev->bus->number, PCI_SLOT(dev->devfn), pin, irq);
 					dev->irq = irq;
-					}
+				}
 			}
 		}
 #endif
diff -u --recursive --new-file v2.1.120/linux/arch/i386/kernel/desc.h linux/arch/i386/kernel/desc.h
--- v2.1.120/linux/arch/i386/kernel/desc.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/i386/kernel/desc.h	Wed Sep  9 08:56:58 1998
@@ -0,0 +1,61 @@
+#ifndef __ARCH_DESC_H
+#define __ARCH_DESC_H
+
+struct desc_struct {
+	unsigned long a,b;
+};
+
+extern struct desc_struct gdt_table[];
+extern struct desc_struct *idt, *gdt;
+
+struct Xgt_desc_struct {
+	unsigned short size;
+	unsigned long address __attribute__((packed));
+};
+
+#define idt_descr (*(struct Xgt_desc_struct *)((char *)&idt - 2))
+#define gdt_descr (*(struct Xgt_desc_struct *)((char *)&gdt - 2))
+
+/*
+ * Entry into gdt where to find first TSS. GDT layout:
+ *   0 - null
+ *   1 - not used
+ *   2 - kernel code segment
+ *   3 - kernel data segment
+ *   4 - user code segment
+ *   5 - user data segment
+ *   6 - not used
+ *   7 - not used
+ *   8 - APM BIOS support
+ *   9 - APM BIOS support
+ *  10 - APM BIOS support
+ *  11 - APM BIOS support
+ *  12 - TSS #0
+ *  13 - LDT #0
+ *  14 - TSS #1
+ *  15 - LDT #1
+ */
+#define FIRST_TSS_ENTRY 12
+#define FIRST_LDT_ENTRY (FIRST_TSS_ENTRY+1)
+#define _TSS(n) ((((unsigned long) n)<<4)+(FIRST_TSS_ENTRY<<3))
+#define _LDT(n) ((((unsigned long) n)<<4)+(FIRST_LDT_ENTRY<<3))
+#define load_TR(n) __asm__ __volatile__("ltr %%ax": /* no output */ :"a" (_TSS(n)))
+#define load_ldt(n) __asm__ __volatile__("lldt %%ax": /* no output */ :"a" (_LDT(n)))
+#define store_TR(n) \
+__asm__("str %%ax\n\t" \
+	"subl %2,%%eax\n\t" \
+	"shrl $4,%%eax" \
+	:"=a" (n) \
+	:"0" (0),"i" (FIRST_TSS_ENTRY<<3))
+
+extern void set_intr_gate(unsigned int irq, void * addr);
+extern void set_ldt_desc(unsigned int n, void *addr, unsigned int size);
+extern void set_tss_desc(unsigned int n, void *addr);
+
+/*
+ * This is the ldt that every process will get unless we need
+ * something other than this.
+ */
+extern struct desc_struct default_ldt;
+
+#endif
diff -u --recursive --new-file v2.1.120/linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S
--- v2.1.120/linux/arch/i386/kernel/entry.S	Sat Sep  5 16:46:40 1998
+++ linux/arch/i386/kernel/entry.S	Sun Sep  6 13:04:57 1998
@@ -364,7 +364,7 @@
 
 .data
 ENTRY(sys_call_table)
-	.long SYMBOL_NAME(sys_setup)		/* 0 */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* 0  -  old "setup()" system call*/
 	.long SYMBOL_NAME(sys_exit)
 	.long SYMBOL_NAME(sys_fork)
 	.long SYMBOL_NAME(sys_read)
diff -u --recursive --new-file v2.1.120/linux/arch/i386/kernel/head.S linux/arch/i386/kernel/head.S
--- v2.1.120/linux/arch/i386/kernel/head.S	Tue Aug 18 22:02:02 1998
+++ linux/arch/i386/kernel/head.S	Wed Sep  9 08:56:58 1998
@@ -509,7 +509,6 @@
 ENTRY(empty_zero_page)
 
 .org 0x6000
-ENTRY(this_must_match_init_task)
 
 /*
  * This starts the data section. Note that the above is all
@@ -519,10 +518,6 @@
 .data
 
 ALIGN
-/* 256 quadwords - 2048 bytes of idt */
-ENTRY(idt_table)
-	.fill 256,8,0		# idt is uninitialized
-
 /*
  * This contains up to 8192 quadwords depending on NR_TASKS - 64kB of
  * gdt entries.  Ugh. 
diff -u --recursive --new-file v2.1.120/linux/arch/i386/kernel/init_task.c linux/arch/i386/kernel/init_task.c
--- v2.1.120/linux/arch/i386/kernel/init_task.c	Tue Mar 17 22:18:13 1998
+++ linux/arch/i386/kernel/init_task.c	Wed Sep  9 08:56:58 1998
@@ -4,6 +4,8 @@
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 
+#include "desc.h"
+
 static struct vm_area_struct init_mmap = INIT_MMAP;
 static struct fs_struct init_fs = INIT_FS;
 static struct file * init_fd_array[NR_OPEN] = { NULL, };
@@ -15,10 +17,9 @@
  * Initial task structure.
  *
  * We need to make sure that this is 8192-byte aligned due to the
- * way process stacks are handled. This is done by making sure
- * the linker maps this in the .text segment right after head.S,
- * and making head.S ensure the proper alignment.
- *
- * The things we do for performance..
+ * way process stacks are handled. This is done by having a special
+ * "init_task" linker map entry..
  */
-union task_union init_task_union __attribute__((__section__(".text"))) = { INIT_TASK };
+union task_union init_task_union 
+	__attribute__((__section__(".data.init_task"))) = { INIT_TASK };
+ 
diff -u --recursive --new-file v2.1.120/linux/arch/i386/kernel/io_apic.c linux/arch/i386/kernel/io_apic.c
--- v2.1.120/linux/arch/i386/kernel/io_apic.c	Sat Sep  5 16:46:40 1998
+++ linux/arch/i386/kernel/io_apic.c	Tue Sep  8 14:46:50 1998
@@ -514,6 +514,8 @@
 	return 0;
 }
 
+int irq_vector[NR_IRQS] = { IRQ0_TRAP_VECTOR , 0 };
+
 static int __init assign_irq_vector(int irq)
 {
 	static int current_vector = IRQ0_TRAP_VECTOR, offset = 0;
@@ -957,7 +959,7 @@
 	mask_IO_APIC_irq(irq);
 }
 
-static void do_edge_ioapic_IRQ(unsigned int irq, int cpu, struct pt_regs * regs)
+static void do_edge_ioapic_IRQ(unsigned int irq, struct pt_regs * regs)
 {
 	irq_desc_t *desc = irq_desc + irq;
 	struct irqaction * action;
@@ -991,14 +993,12 @@
 	if (!action)
 		return;
 
-	irq_enter(cpu, irq);
-
 	/*
 	 * Edge triggered interrupts need to remember
 	 * pending events.
 	 */
 	for (;;) {
-		handle_IRQ_event(irq, regs);
+		handle_IRQ_event(irq, regs, action);
 
 		spin_lock(&irq_controller_lock);
 		if (!(desc->status & IRQ_PENDING))
@@ -1008,12 +1008,9 @@
 	}
 	desc->status &= ~IRQ_INPROGRESS;
 	spin_unlock(&irq_controller_lock);
-
-	irq_exit(cpu, irq);
 }
 
-static void do_level_ioapic_IRQ(unsigned int irq, int cpu,
-				struct pt_regs * regs)
+static void do_level_ioapic_IRQ(unsigned int irq, struct pt_regs * regs)
 {
 	irq_desc_t *desc = irq_desc + irq;
 	struct irqaction * action;
@@ -1048,17 +1045,13 @@
 	if (!action)
 		return;
 
-	irq_enter(cpu, irq);
-
-	handle_IRQ_event(irq, regs);
+	handle_IRQ_event(irq, regs, action);
 
 	spin_lock(&irq_controller_lock);
 	desc->status &= ~IRQ_INPROGRESS;
 	if (!(desc->status & IRQ_DISABLED))
 		unmask_IO_APIC_irq(irq);
 	spin_unlock(&irq_controller_lock);
-
-	irq_exit(cpu, irq);
 }
 
 /*
diff -u --recursive --new-file v2.1.120/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c
--- v2.1.120/linux/arch/i386/kernel/irq.c	Sat Sep  5 16:46:40 1998
+++ linux/arch/i386/kernel/irq.c	Wed Sep  9 08:56:58 1998
@@ -39,6 +39,7 @@
 #include <asm/delay.h>
 
 #include "irq.h"
+#include "desc.h"
 
 unsigned int local_bh_count[NR_CPUS];
 unsigned int local_irq_count[NR_CPUS];
@@ -79,14 +80,14 @@
  */
 unsigned long long io_apic_irqs = 0;
 
-static void do_8259A_IRQ (unsigned int irq, int cpu, struct pt_regs * regs);
+static void do_8259A_IRQ(unsigned int irq, struct pt_regs * regs);
 static void enable_8259A_irq(unsigned int irq);
 void disable_8259A_irq(unsigned int irq);
 
 /*
  * Dummy controller type for unused interrupts
  */
-static void do_none(unsigned int irq, int cpu, struct pt_regs * regs) { }
+static void do_none(unsigned int irq, struct pt_regs * regs) { }
 static void enable_none(unsigned int irq) { }
 static void disable_none(unsigned int irq) { }
 
@@ -105,12 +106,10 @@
 };
 
 irq_desc_t irq_desc[NR_IRQS] = {
-	[0 ... 15] = { 0, &i8259A_irq_type, },	/* default to standard ISA IRQs */
-	[16 ... 63] = { 0, &no_irq_type, },	/* 'high' PCI IRQs filled in on demand */
+	[0 ... 15] = { 0, &i8259A_irq_type, },		/* default to standard ISA IRQs */
+	[16 ... NR_IRQS-1] = { 0, &no_irq_type, },	/* 'high' PCI IRQs filled in on demand */
 };
 
-int irq_vector[NR_IRQS] = { IRQ0_TRAP_VECTOR , 0 };
-
 
 /*
  * These have to be protected by the irq controller spinlock
@@ -150,52 +149,29 @@
 
 BUILD_COMMON_IRQ()
 /*
- * ISA PIC or IO-APIC triggered (INTA-cycle or APIC) interrupts:
+ * ISA PIC or low IO-APIC triggered (INTA-cycle or APIC) interrupts:
  */
-BUILD_IRQ(0) BUILD_IRQ(1) BUILD_IRQ(2) BUILD_IRQ(3)
-BUILD_IRQ(4) BUILD_IRQ(5) BUILD_IRQ(6) BUILD_IRQ(7)
-BUILD_IRQ(8) BUILD_IRQ(9) BUILD_IRQ(10) BUILD_IRQ(11)
+BUILD_IRQ(0)  BUILD_IRQ(1)  BUILD_IRQ(2)  BUILD_IRQ(3)
+BUILD_IRQ(4)  BUILD_IRQ(5)  BUILD_IRQ(6)  BUILD_IRQ(7)
+BUILD_IRQ(8)  BUILD_IRQ(9)  BUILD_IRQ(10) BUILD_IRQ(11)
 BUILD_IRQ(12) BUILD_IRQ(13) BUILD_IRQ(14) BUILD_IRQ(15)
 
 #ifdef __SMP__
 
 /*
- * The IO-APIC (present only in SMP boards) has 8 more hardware
- * interrupt pins, for all of them we define an IRQ vector:
- *
- * raw PCI interrupts 0-3, basically these are the ones used
- * heavily:
+ * The IO-APIC gives us many more interrupt sources..
  */
 BUILD_IRQ(16) BUILD_IRQ(17) BUILD_IRQ(18) BUILD_IRQ(19)
-
-/*
- * [FIXME: anyone with 2 separate PCI buses and 2 IO-APICs, please
- *	   speak up if problems and request experimental patches.
- *         --mingo ]
- */
-
-/*
- * MIRQ (motherboard IRQ) interrupts 0-1:
- */
-BUILD_IRQ(20) BUILD_IRQ(21)
-
-/*
- * 'nondefined general purpose interrupt'.
- */
-BUILD_IRQ(22)
-/*
- * optionally rerouted SMI interrupt:
- */
-BUILD_IRQ(23)
-
-BUILD_IRQ(24)
-BUILD_IRQ(25) BUILD_IRQ(26) BUILD_IRQ(27) BUILD_IRQ(28) BUILD_IRQ(29)
-BUILD_IRQ(30) BUILD_IRQ(31) BUILD_IRQ(32) BUILD_IRQ(33) BUILD_IRQ(34)
-BUILD_IRQ(35) BUILD_IRQ(36) BUILD_IRQ(37) BUILD_IRQ(38) BUILD_IRQ(39)
-BUILD_IRQ(40) BUILD_IRQ(41) BUILD_IRQ(42) BUILD_IRQ(43) BUILD_IRQ(44)
-BUILD_IRQ(45) BUILD_IRQ(46) BUILD_IRQ(47) BUILD_IRQ(48) BUILD_IRQ(49)
-BUILD_IRQ(50) BUILD_IRQ(51) BUILD_IRQ(52) BUILD_IRQ(53) BUILD_IRQ(54)
-BUILD_IRQ(55) BUILD_IRQ(56) BUILD_IRQ(57) BUILD_IRQ(58) BUILD_IRQ(59)
+BUILD_IRQ(20) BUILD_IRQ(21) BUILD_IRQ(22) BUILD_IRQ(23)
+BUILD_IRQ(24) BUILD_IRQ(25) BUILD_IRQ(26) BUILD_IRQ(27)
+BUILD_IRQ(28) BUILD_IRQ(29) BUILD_IRQ(30) BUILD_IRQ(31)
+BUILD_IRQ(32) BUILD_IRQ(33) BUILD_IRQ(34) BUILD_IRQ(35)
+BUILD_IRQ(36) BUILD_IRQ(37) BUILD_IRQ(38) BUILD_IRQ(39)
+BUILD_IRQ(40) BUILD_IRQ(41) BUILD_IRQ(42) BUILD_IRQ(43)
+BUILD_IRQ(44) BUILD_IRQ(45) BUILD_IRQ(46) BUILD_IRQ(47)
+BUILD_IRQ(48) BUILD_IRQ(49) BUILD_IRQ(50) BUILD_IRQ(51)
+BUILD_IRQ(52) BUILD_IRQ(53) BUILD_IRQ(54) BUILD_IRQ(55)
+BUILD_IRQ(56) BUILD_IRQ(57) BUILD_IRQ(58) BUILD_IRQ(59)
 BUILD_IRQ(60) BUILD_IRQ(61) BUILD_IRQ(62) BUILD_IRQ(63)
 
 /*
@@ -586,29 +562,35 @@
 
 #endif
 
-int handle_IRQ_event(unsigned int irq, struct pt_regs * regs)
+/*
+ * This should really return information about whether
+ * we should do bottom half handling etc. Right now we
+ * end up _always_ checking the bottom half, which is a
+ * waste of time and is not what some drivers would
+ * prefer.
+ */
+int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * action)
 {
-	struct irqaction * action;
 	int status;
+	int cpu = smp_processor_id();
 
-	status = 0;
-	action = irq_desc[irq].action;
+	irq_enter(cpu, irq);
 
-	if (action) {
-		status |= 1;
+	status = 1;	/* Force the "do bottom halves" bit */
 
-		if (!(action->flags & SA_INTERRUPT))
-			__sti();
+	if (!(action->flags & SA_INTERRUPT))
+		__sti();
 
-		do {
-			status |= action->flags;
-			action->handler(irq, action->dev_id, regs);
-			action = action->next;
-		} while (action);
-		if (status & SA_SAMPLE_RANDOM)
-			add_interrupt_randomness(irq);
-		__cli();
-	}
+	do {
+		status |= action->flags;
+		action->handler(irq, action->dev_id, regs);
+		action = action->next;
+	} while (action);
+	if (status & SA_SAMPLE_RANDOM)
+		add_interrupt_randomness(irq);
+	__cli();
+
+	irq_exit(cpu, irq);
 
 	return status;
 }
@@ -625,9 +607,9 @@
 
 void make_8259A_irq(unsigned int irq)
 {
+	disable_irq(irq);
 	__long(0,io_apic_irqs) &= ~(1<<irq);
 	irq_desc[irq].handler = &i8259A_irq_type;
-	disable_irq(irq);
 	enable_irq(irq);
 }
 
@@ -639,8 +621,6 @@
  */
 static inline void mask_and_ack_8259A(unsigned int irq)
 {
-	spin_lock(&irq_controller_lock);
-	irq_desc[irq].status |= IRQ_INPROGRESS;
 	cached_irq_mask |= 1 << irq;
 	if (irq & 8) {
 		inb(0xA1);	/* DUMMY */
@@ -652,24 +632,39 @@
 		outb(cached_21,0x21);
 		outb(0x20,0x20);
 	}
-	spin_unlock(&irq_controller_lock);
 }
 
-static void do_8259A_IRQ(unsigned int irq, int cpu, struct pt_regs * regs)
+static void do_8259A_IRQ(unsigned int irq, struct pt_regs * regs)
 {
-	mask_and_ack_8259A(irq);
+	struct irqaction * action;
+	irq_desc_t *desc = irq_desc + irq;
 
-	irq_enter(cpu, irq);
+	spin_lock(&irq_controller_lock);
+	{
+		unsigned int status;
+		mask_and_ack_8259A(irq);
+		status = desc->status & ~IRQ_REPLAY;
+		action = NULL;
+		if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+			action = desc->action;
+		desc->status = status | IRQ_INPROGRESS;
+	}
+	spin_unlock(&irq_controller_lock);
 
-	if (handle_IRQ_event(irq, regs)) {
-		spin_lock(&irq_controller_lock);
-		irq_desc[irq].status &= ~IRQ_INPROGRESS;
-		if (!(irq_desc[irq].status & IRQ_DISABLED))
+	/* Exit early if we had no action or it was disabled */
+	if (!action)
+		return;
+
+	handle_IRQ_event(irq, regs, action);
+
+	spin_lock(&irq_controller_lock);
+	{
+		unsigned int status = desc->status & ~IRQ_INPROGRESS;
+		desc->status = status;
+		if (!(status & IRQ_DISABLED))
 			enable_8259A_irq(irq);
-		spin_unlock(&irq_controller_lock);
 	}
-
-	irq_exit(cpu, irq);
+	spin_unlock(&irq_controller_lock);
 }
 
 
@@ -730,7 +725,7 @@
 	int cpu = smp_processor_id();
 
 	kstat.irqs[cpu][irq]++;
-	irq_desc[irq].handler->handle(irq, cpu, &regs);
+	irq_desc[irq].handler->handle(irq, &regs);
 
 	/*
 	 * This should be conditional: we should really get
@@ -986,9 +981,6 @@
 	 * while so far it was a kind of broadcasted timer interrupt,
 	 * in the future it should become a CPU-to-CPU rescheduling IPI,
 	 * driven by schedule() ?
-	 *
-	 * [ It has to be here .. it doesn't work if you put
-	 *   it down the bottom - assembler explodes 8) ]
 	 */
 
 	/* IPI for rescheduling */
@@ -1013,9 +1005,9 @@
 	request_region(0xa0,0x20,"pic2");
 	setup_x86_irq(2, &irq2);
 	setup_x86_irq(13, &irq13);
-} 
+}
 
-#ifdef __SMP__	
+#ifdef __SMP__
 
 __initfunc(void init_IRQ_SMP(void))
 {
diff -u --recursive --new-file v2.1.120/linux/arch/i386/kernel/irq.h linux/arch/i386/kernel/irq.h
--- v2.1.120/linux/arch/i386/kernel/irq.h	Sat Sep  5 16:46:40 1998
+++ linux/arch/i386/kernel/irq.h	Tue Sep  8 12:51:20 1998
@@ -9,7 +9,7 @@
  */
 struct hw_interrupt_type {
 	const char * typename;
-	void (*handle)(unsigned int irq, int cpu, struct pt_regs * regs);
+	void (*handle)(unsigned int irq, struct pt_regs * regs);
 	void (*enable)(unsigned int irq);
 	void (*disable)(unsigned int irq);
 };
@@ -42,9 +42,10 @@
 
 extern irq_desc_t irq_desc[NR_IRQS];
 extern int irq_vector[NR_IRQS];
+#define IO_APIC_VECTOR(irq)	irq_vector[irq]
 
 extern void init_IRQ_SMP(void);
-extern int handle_IRQ_event(unsigned int, struct pt_regs *);
+extern int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
 
 /*
  * Various low-level irq details needed by irq.c, process.c,
@@ -56,19 +57,17 @@
 void mask_irq(unsigned int irq);
 void unmask_irq(unsigned int irq);
 void disable_8259A_irq(unsigned int irq);
-int i8259A_irq_pending (unsigned int irq);
-void ack_APIC_irq (void);
-void setup_IO_APIC (void);
-int IO_APIC_get_PCI_irq_vector (int bus, int slot, int fn);
-void make_8259A_irq (unsigned int irq);
-void send_IPI (int dest, int vector);
-void init_pic_mode (void);
-void print_IO_APIC (void);
+int i8259A_irq_pending(unsigned int irq);
+void ack_APIC_irq(void);
+void setup_IO_APIC(void);
+int IO_APIC_get_PCI_irq_vector(int bus, int slot, int fn);
+void make_8259A_irq(unsigned int irq);
+void send_IPI(int dest, int vector);
+void init_pic_mode(void);
+void print_IO_APIC(void);
 
 extern unsigned long long io_apic_irqs;
 
-#define IO_APIC_VECTOR(irq)	irq_vector[irq]
-
 #define MAX_IRQ_SOURCES 128
 #define MAX_MP_BUSSES 32
 enum mp_bustype {
@@ -101,7 +100,6 @@
 static inline void irq_exit(int cpu, unsigned int irq)
 {
 	hardirq_exit(cpu);
-	release_irqlock(cpu);
 }
 
 #define IO_APIC_IRQ(x) ((1<<x) & io_apic_irqs)
diff -u --recursive --new-file v2.1.120/linux/arch/i386/kernel/ldt.c linux/arch/i386/kernel/ldt.c
--- v2.1.120/linux/arch/i386/kernel/ldt.c	Tue Aug 18 22:02:02 1998
+++ linux/arch/i386/kernel/ldt.c	Wed Sep  9 08:56:58 1998
@@ -16,6 +16,8 @@
 #include <asm/system.h>
 #include <asm/ldt.h>
 
+#include "desc.h"
+
 static int read_ldt(void * ptr, unsigned long bytecount)
 {
 	void * address = current->mm->segments;
@@ -23,11 +25,9 @@
 
 	if (!ptr)
 		return -EINVAL;
+	if (!address)
+		return 0;
 	size = LDT_ENTRIES*LDT_ENTRY_SIZE;
-	if (!address) {
-		address = &default_ldt;
-		size = sizeof(default_ldt);
-	}
 	if (size > bytecount)
 		size = bytecount;
 	return copy_to_user(ptr, address, size) ? -EFAULT : size;
@@ -81,7 +81,8 @@
 		if (!mm->segments) {
 			int i = current->tarray_ptr - &task[0];
 			mm->segments = ldt;
-			set_ldt_desc(gdt+(i<<1)+FIRST_LDT_ENTRY, ldt, LDT_ENTRIES);
+			set_ldt_desc(i, ldt, LDT_ENTRIES);
+			current->tss.ldt = _LDT(i);
 			load_ldt(i);
 			if (atomic_read(&mm->count) > 1)
 				printk(KERN_WARNING
diff -u --recursive --new-file v2.1.120/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c
--- v2.1.120/linux/arch/i386/kernel/process.c	Sat Sep  5 16:46:40 1998
+++ linux/arch/i386/kernel/process.c	Wed Sep  9 08:56:58 1998
@@ -44,7 +44,9 @@
 #ifdef CONFIG_MATH_EMULATION
 #include <asm/math_emu.h>
 #endif
+
 #include "irq.h"
+#include "desc.h"
 
 spinlock_t semaphore_wake_lock = SPIN_LOCK_UNLOCKED;
 
@@ -553,9 +555,8 @@
 {
 	struct mm_struct * old_mm = current->mm;
 	void * old_ldt = old_mm->segments, * ldt = old_ldt;
-	int ldt_size = LDT_ENTRIES;
 
-	/* "default_ldt" - use the one from init_task */
+	/* default LDT - use the one from init_task */
 	p->tss.ldt = _LDT(0);
 	if (old_ldt) {
 		if (new_mm) {
@@ -568,7 +569,7 @@
 			memcpy(ldt, old_ldt, LDT_ENTRIES*LDT_ENTRY_SIZE);
 		}
 		p->tss.ldt = _LDT(nr);
-		set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY, ldt, ldt_size);
+		set_ldt_desc(nr, ldt, LDT_ENTRIES);
 		return;
 	}
 }
@@ -595,7 +596,7 @@
 	p->tss.ss0 = __KERNEL_DS;
 
 	p->tss.tr = _TSS(nr);
-	set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY,&(p->tss));
+	set_tss_desc(nr,&(p->tss));
 	p->tss.eip = (unsigned long) ret_from_fork;
 
 	savesegment(fs,p->tss.fs);
diff -u --recursive --new-file v2.1.120/linux/arch/i386/kernel/ptrace.c linux/arch/i386/kernel/ptrace.c
--- v2.1.120/linux/arch/i386/kernel/ptrace.c	Mon Aug  3 12:45:43 1998
+++ linux/arch/i386/kernel/ptrace.c	Wed Sep  9 08:56:58 1998
@@ -3,7 +3,6 @@
 /* edited by Linus Torvalds */
 
 #include <linux/config.h> /* for CONFIG_MATH_EMULATION */
-#include <linux/head.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
diff -u --recursive --new-file v2.1.120/linux/arch/i386/kernel/signal.c linux/arch/i386/kernel/signal.c
--- v2.1.120/linux/arch/i386/kernel/signal.c	Sat Sep  5 16:46:40 1998
+++ linux/arch/i386/kernel/signal.c	Sat Sep  5 17:14:29 1998
@@ -22,17 +22,6 @@
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 
-void checksignals(void)
-{
-	sigset_t *blocked = &current->blocked;
-	unsigned long mask = blocked->sig[0] | sigmask(SIGKILL) | sigmask(SIGINT) | sigmask(SIGQUIT);
-	mask &= blocked->sig[1];
-	if (~mask) {
-		printk("Bad signal mask\n");
-		*(int *) 0 = 0;
-	}
-}
-
 #define DEBUG_SIG 0
 
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
diff -u --recursive --new-file v2.1.120/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c
--- v2.1.120/linux/arch/i386/kernel/smp.c	Sat Sep  5 16:46:40 1998
+++ linux/arch/i386/kernel/smp.c	Sun Sep  6 11:49:01 1998
@@ -113,7 +113,7 @@
 
 extern __inline int max(int a,int b)
 {
-	if(a>b)
+	if (a>b)
 		return a;
 	return b;
 }
@@ -179,7 +179,7 @@
  *	SMP mode to <NUM>.
  */
 
-__initfunc(void smp_setup(char *str, int *ints))
+void __init smp_setup(char *str, int *ints)
 {
 	if (ints && ints[0] > 0)
 		max_cpus = ints[1];
@@ -187,7 +187,7 @@
 		max_cpus = 0;
 }
 
-void ack_APIC_irq (void)
+void ack_APIC_irq(void)
 {
 	/* Clear the IPI */
 
@@ -225,13 +225,13 @@
 		"Unknown","Unknown",
 		"80486DX/4"
 	};
-	if(family==0x6)
+	if (family==0x6)
 		return("Pentium(tm) Pro");
-	if(family==0x5)
+	if (family==0x5)
 		return("Pentium(tm)");
-	if(family==0x0F && model==0x0F)
+	if (family==0x0F && model==0x0F)
 		return("Special controller");
-	if(family==0x04 && model<9)
+	if (family==0x04 && model<9)
 		return model_defs[model];
 	sprintf(n,"Unknown CPU [%d:%d]",family, model);
 	return n;
@@ -241,14 +241,14 @@
  *	Read the MPC
  */
 
-__initfunc(static int smp_read_mpc(struct mp_config_table *mpc))
+static int __init smp_read_mpc(struct mp_config_table *mpc)
 {
 	char str[16];
 	int count=sizeof(*mpc);
 	int ioapics = 0;
 	unsigned char *mpt=((unsigned char *)mpc)+count;
 
-	if(memcmp(mpc->mpc_signature,MPC_SIGNATURE,4))
+	if (memcmp(mpc->mpc_signature,MPC_SIGNATURE,4))
 	{
 		printk("Bad signature [%c%c%c%c].\n",
 			mpc->mpc_signature[0],
@@ -257,12 +257,12 @@
 			mpc->mpc_signature[3]);
 		return 1;
 	}
-	if(mpf_checksum((unsigned char *)mpc,mpc->mpc_length))
+	if (mpf_checksum((unsigned char *)mpc,mpc->mpc_length))
 	{
 		printk("Checksum error.\n");
 		return 1;
 	}
-	if(mpc->mpc_spec!=0x01 && mpc->mpc_spec!=0x04)
+	if (mpc->mpc_spec!=0x01 && mpc->mpc_spec!=0x04)
 	{
 		printk("Bad Config Table version (%d)!!\n",mpc->mpc_spec);
 		return 1;
@@ -294,7 +294,7 @@
 			{
 				struct mpc_config_processor *m=
 					(struct mpc_config_processor *)mpt;
-				if(m->mpc_cpuflag&CPU_ENABLED)
+				if (m->mpc_cpuflag&CPU_ENABLED)
 				{
 					printk("Processor #%d %s APIC version %d\n",
 						m->mpc_apicid,
@@ -304,16 +304,16 @@
 								CPU_MODEL_MASK)>>4),
 						m->mpc_apicver);
 #ifdef SMP_DEBUG
-					if(m->mpc_featureflag&(1<<0))
+					if (m->mpc_featureflag&(1<<0))
 						printk("    Floating point unit present.\n");
-					if(m->mpc_featureflag&(1<<7))
+					if (m->mpc_featureflag&(1<<7))
 						printk("    Machine Exception supported.\n");
-					if(m->mpc_featureflag&(1<<8))
+					if (m->mpc_featureflag&(1<<8))
 						printk("    64 bit compare & exchange supported.\n");
-					if(m->mpc_featureflag&(1<<9))
+					if (m->mpc_featureflag&(1<<9))
 						printk("    Internal APIC present.\n");
 #endif
-					if(m->mpc_cpuflag&CPU_BOOTPROCESSOR)
+					if (m->mpc_cpuflag&CPU_BOOTPROCESSOR)
 					{
 						SMP_PRINTK(("    Bootup CPU\n"));
 						boot_cpu_id=m->mpc_apicid;
@@ -321,7 +321,7 @@
 					else	/* Boot CPU already counted */
 						num_processors++;
 
-					if(m->mpc_apicid>NR_CPUS)
+					if (m->mpc_apicid>NR_CPUS)
 						printk("Processor #%d unused. (Max %d processors).\n",m->mpc_apicid, NR_CPUS);
 					else
 					{
@@ -362,7 +362,7 @@
 			{
 				struct mpc_config_ioapic *m=
 					(struct mpc_config_ioapic *)mpt;
-				if(m->mpc_flags&MPC_APIC_USABLE)
+				if (m->mpc_flags&MPC_APIC_USABLE)
 				{
 					ioapics++;
 					printk("I/O APIC #%d Version %d at 0x%lX.\n",
@@ -413,28 +413,28 @@
  *	Scan the memory blocks for an SMP configuration block.
  */
 
-__initfunc(int smp_scan_config(unsigned long base, unsigned long length))
+int __init smp_scan_config(unsigned long base, unsigned long length)
 {
 	unsigned long *bp=phys_to_virt(base);
 	struct intel_mp_floating *mpf;
 
 	SMP_PRINTK(("Scan SMP from %p for %ld bytes.\n",
 		bp,length));
-	if(sizeof(*mpf)!=16)
+	if (sizeof(*mpf)!=16)
 		printk("Error: MPF size\n");
 
-	while(length>0)
+	while (length>0)
 	{
-		if(*bp==SMP_MAGIC_IDENT)
+		if (*bp==SMP_MAGIC_IDENT)
 		{
 			mpf=(struct intel_mp_floating *)bp;
-			if(mpf->mpf_length==1 &&
+			if (mpf->mpf_length==1 &&
 				!mpf_checksum((unsigned char *)bp,16) &&
 				(mpf->mpf_specification == 1
 				 || mpf->mpf_specification == 4) )
 			{
 				printk("Intel MultiProcessor Specification v1.%d\n", mpf->mpf_specification);
-				if(mpf->mpf_feature2&(1<<7))
+				if (mpf->mpf_feature2&(1<<7))
 					printk("    IMCR and PIC compatibility mode.\n");
 				else
 					printk("    Virtual Wire compatibility mode.\n");
@@ -442,7 +442,7 @@
 				/*
 				 *	Now see if we need to read further.
 				 */
-				if(mpf->mpf_feature1!=0)
+				if (mpf->mpf_feature1!=0)
 				{
 					unsigned long cfg;
 
@@ -524,7 +524,7 @@
 							mpf->mpf_feature1);
 						return 1;
 				}
-				if(mpf->mpf_feature1>4)
+				if (mpf->mpf_feature1>4)
 				{
 					printk("Bus #1 is PCI\n");
 
@@ -543,7 +543,7 @@
 				 *	Anything here will override the
 				 *	defaults.
 				 */
-				if(mpf->mpf_physptr)
+				if (mpf->mpf_physptr)
 					smp_read_mpc((void *)mpf->mpf_physptr);
 
 				__cpu_logical_map[0] = boot_cpu_id;
@@ -578,7 +578,7 @@
  *	has made sure it's suitably aligned.
  */
 
-__initfunc(static unsigned long setup_trampoline(void))
+static unsigned long __init setup_trampoline(void)
 {
 	memcpy(trampoline_base, trampoline_data, trampoline_end - trampoline_data);
 	return virt_to_phys(trampoline_base);
@@ -588,7 +588,7 @@
  *	We are called very early to get the low memory for the
  *	SMP bootup trampoline page.
  */
-__initfunc(unsigned long smp_alloc_memory(unsigned long mem_base))
+unsigned long __init smp_alloc_memory(unsigned long mem_base)
 {
 	if (virt_to_phys((void *)mem_base) >= 0x9F000)
 		panic("smp_alloc_memory: Insufficient low memory for kernel trampoline 0x%lx.", mem_base);
@@ -601,7 +601,7 @@
  *	a given CPU
  */
 
-__initfunc(void smp_store_cpu_info(int id))
+void __init smp_store_cpu_info(int id)
 {
 	struct cpuinfo_x86 *c=&cpu_data[id];
 
@@ -630,7 +630,7 @@
  *	we use to track CPUs as they power up.
  */
 
-__initfunc(void smp_commence(void))
+void __init smp_commence(void)
 {
 	/*
 	 *	Lets the callins below out of their loop.
@@ -639,7 +639,7 @@
 	smp_commenced=1;
 }
 
-__initfunc(void enable_local_APIC(void))
+void __init enable_local_APIC(void)
 {
 	unsigned long value;
 
@@ -658,7 +658,7 @@
 	udelay(100);
 }
 
-__initfunc(unsigned long init_smp_mappings(unsigned long memory_start))
+unsigned long __init init_smp_mappings(unsigned long memory_start)
 {
 	unsigned long apic_phys, ioapic_phys;
 
@@ -688,7 +688,7 @@
 	return memory_start;
 }
 
-__initfunc(void smp_callin(void))
+void __init smp_callin(void)
 {
 	extern void calibrate_delay(void);
 	int cpuid=GET_APIC_ID(apic_read(APIC_ID));
@@ -730,7 +730,7 @@
 /*
  *	Activate a secondary processor.
  */
-__initfunc(int start_secondary(void *unused))
+int __init start_secondary(void *unused)
 {
 #ifdef CONFIG_MTRR
 	/*  Must be done before calibration delay is computed  */
@@ -747,7 +747,7 @@
  * CPUs - they just need to reload everything
  * from the task structure
  */
-__initfunc(void initialize_secondary(void))
+void __init initialize_secondary(void)
 {
 	struct thread_struct * p = &current->tss;
 
@@ -773,7 +773,7 @@
 	unsigned short ss;
 } stack_start;
 
-__initfunc(static void do_boot_cpu(int i))
+static void __init do_boot_cpu(int i)
 {
 	unsigned long cfg;
 	pgd_t maincfg;
@@ -925,15 +925,15 @@
 	if (accept_status)		/* Send accept error */
 		printk("APIC delivery error (%lx).\n", accept_status);
 
-	if( !(send_status || accept_status) )
+	if ( !(send_status || accept_status) )
 	{
 		for(timeout=0;timeout<50000;timeout++)
 		{
-			if(cpu_callin_map[0]&(1<<i))
+			if (cpu_callin_map[0]&(1<<i))
 				break;				/* It has booted */
 			udelay(100);				/* Wait 5s total for a response */
 		}
-		if(cpu_callin_map[0]&(1<<i))
+		if (cpu_callin_map[0]&(1<<i))
 		{
 			/* number CPUs logically, starting from 1 (BSP is 0) */
 #if 0
@@ -946,7 +946,7 @@
 		}
 		else
 		{
-			if(*((volatile unsigned char *)phys_to_virt(8192))==0xA5)
+			if (*((volatile unsigned char *)phys_to_virt(8192))==0xA5)
 				printk("Stuck ??\n");
 			else
 				printk("Not responding.\n");
@@ -974,7 +974,7 @@
  *	Cycle through the processors sending APIC IPIs to boot each.
  */
 
-__initfunc(void smp_boot_cpus(void))
+void __init smp_boot_cpus(void)
 {
 	int i;
 	unsigned long cfg;
@@ -1135,7 +1135,7 @@
 	 */
 
 	SMP_PRINTK(("Before bogomips.\n"));
-	if(cpucount==0)
+	if (cpucount==0)
 	{
 		printk(KERN_ERR "Error: only one processor found.\n");
 		cpu_present_map=(1<<hard_smp_processor_id());
@@ -1145,7 +1145,7 @@
 		unsigned long bogosum=0;
 		for(i=0;i<32;i++)
 		{
-			if(cpu_present_map&(1<<i))
+			if (cpu_present_map&(1<<i))
 				bogosum+=cpu_data[i].loops_per_sec;
 		}
 		printk(KERN_INFO "Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
@@ -1156,7 +1156,7 @@
 		smp_activated=1;
 		smp_num_cpus=cpucount+1;
 	}
-	if(smp_b_stepping)
+	if (smp_b_stepping)
 		printk(KERN_WARNING "WARNING: SMP operation may be unreliable with B stepping processors.\n");
 	SMP_PRINTK(("Boot done.\n"));
 
@@ -1170,7 +1170,7 @@
 }
 
 
-void send_IPI (int dest, int vector)
+void send_IPI(int dest, int vector)
 {
 	unsigned long cfg;
 	unsigned long flags;
@@ -1225,7 +1225,7 @@
 	 *	During boot up send no messages
 	 */
 	
-	if(!smp_activated || !smp_commenced)
+	if (!smp_activated || !smp_commenced)
 		return;
 
 
@@ -1285,7 +1285,7 @@
 	while (ct<1000)
 	{
 		cfg=apic_read(APIC_ICR);
-		if(!(cfg&(1<<12)))
+		if (!(cfg&(1<<12)))
 			break;
 		ct++;
 		udelay(10);
@@ -1295,20 +1295,20 @@
 	 *	Just pray... there is nothing more we can do
 	 */
 	
-	if(ct==1000)
+	if (ct==1000)
 		printk("CPU #%d: previous IPI still not cleared after 10mS\n", p);
 
 	/*
 	 *	Set the target requirement
 	 */
 	
-	if(target==MSG_ALL_BUT_SELF)
+	if (target==MSG_ALL_BUT_SELF)
 	{
 		dest=APIC_DEST_ALLBUT;
 		target_map=cpu_present_map;
 		cpu_callin_map[0]=(1<<p);
 	}
-	else if(target==MSG_ALL)
+	else if (target==MSG_ALL)
 	{
 		dest=APIC_DEST_ALLINC;
 		target_map=cpu_present_map;
@@ -1444,7 +1444,7 @@
 	 * useful with a profiling multiplier != 1
 	 */
 	if (!user_mode(regs))
-		x86_do_profile (regs->eip);
+		x86_do_profile(regs->eip);
 
 	if (!--prof_counter[cpu]) {
 		int user=0,system=0;
@@ -1537,7 +1537,7 @@
 	if (test_and_clear_bit(smp_processor_id(), &smp_invalidate_needed))
 		local_flush_tlb();
 
-	ack_APIC_irq ();
+	ack_APIC_irq();
 }
 
 /*
@@ -1547,15 +1547,15 @@
 {
 	if (cpu_data[smp_processor_id()].hlt_works_ok)
 		for(;;) __asm__("hlt");
-	for  (;;) ;
+	for (;;) ;
 }
 
 void (*mtrr_hook) (void) = NULL;
 
 asmlinkage void smp_mtrr_interrupt(void)
 {
-	ack_APIC_irq ();
-	if (mtrr_hook) (*mtrr_hook) ();
+	ack_APIC_irq();
+	if (mtrr_hook) (*mtrr_hook)();
 }
 
 /*
@@ -1563,7 +1563,7 @@
  */
 asmlinkage void smp_spurious_interrupt(void)
 {
-	/* ack_APIC_irq ();   see sw-dev-man vol 3, chapter 7.4.13.5 */
+	/* ack_APIC_irq();   see sw-dev-man vol 3, chapter 7.4.13.5 */
 	printk("spurious APIC interrupt, ayiee, should never happen.\n");
 }
 
@@ -1585,7 +1585,7 @@
  * but we do not accept timer interrupts yet. We only allow the BP
  * to calibrate.
  */
-__initfunc(static unsigned int get_8254_timer_count (void))
+static unsigned int __init get_8254_timer_count(void)
 {
 	unsigned int count;
 
@@ -1612,7 +1612,7 @@
 
 #define APIC_DIVISOR 16
 
-void setup_APIC_timer (unsigned int clocks)
+void setup_APIC_timer(unsigned int clocks)
 {
 	unsigned long lvtt1_value;
 	unsigned int tmp_value;
@@ -1640,7 +1640,7 @@
 	apic_write(APIC_TMICT, clocks/APIC_DIVISOR);
 }
 
-__initfunc(void wait_8254_wraparound (void))
+void __init wait_8254_wraparound(void)
 {
 	unsigned int curr_count, prev_count=~0;
 	int delta;
@@ -1674,7 +1674,7 @@
  * APIC irq that way.
  */
 
-__initfunc(int calibrate_APIC_clock (void))
+int __init calibrate_APIC_clock(void)
 {
 	unsigned long long t1,t2;
 	long tt1,tt2;
@@ -1745,7 +1745,7 @@
 
 static unsigned int calibration_result;
 
-__initfunc(void setup_APIC_clock (void))
+void __init setup_APIC_clock(void)
 {
 	unsigned long flags;
 
@@ -1800,7 +1800,7 @@
  *
  * usually you want to run this on all CPUs ;)
  */
-int setup_profiling_timer (unsigned int multiplier)
+int setup_profiling_timer(unsigned int multiplier)
 {
 	int cpu = smp_processor_id();
 	unsigned long flags;
@@ -1815,7 +1815,7 @@
 
 	save_flags(flags);
 	cli();
-	setup_APIC_timer (calibration_result/multiplier);
+	setup_APIC_timer(calibration_result/multiplier);
 	prof_multiplier[cpu]=multiplier;
 	restore_flags(flags);
 
diff -u --recursive --new-file v2.1.120/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c
--- v2.1.120/linux/arch/i386/kernel/traps.c	Tue Aug 18 22:02:02 1998
+++ linux/arch/i386/kernel/traps.c	Wed Sep  9 08:56:58 1998
@@ -9,7 +9,6 @@
  * state in 'asm.s'.
  */
 #include <linux/config.h>
-#include <linux/head.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
@@ -29,10 +28,20 @@
 #include <asm/atomic.h>
 #include <asm/debugreg.h>
 
+#include "desc.h"
+
 asmlinkage int system_call(void);
 asmlinkage void lcall7(void);
+
 struct desc_struct default_ldt = { 0, 0 };
 
+/*
+ * The IDT has to be page-aligned to simplify the Pentium
+ * F0 0F bug workaround.. We have a special link segment
+ * for this.
+ */
+struct desc_struct idt_table[256] __attribute__((__section__(".data.idt"))) = { {0, 0}, };
+
 static inline void console_verbose(void)
 {
 	extern int console_loglevel;
@@ -467,12 +476,11 @@
 	 * move the IDT into it and write protect this page.
 	 */
 	page = (unsigned long) vmalloc(PAGE_SIZE);
-	memcpy((void *) page, idt_table, 256*8);
-
 	pgd = pgd_offset(&init_mm, page);
 	pmd = pmd_offset(pgd, page);
 	pte = pte_offset(pmd, page);
-	*pte = pte_wrprotect(*pte);
+	free_page(pte_page(*pte));
+	*pte = mk_pte(&idt_table, PAGE_KERNEL_RO);
 	local_flush_tlb();
 
 	/*
@@ -484,12 +492,77 @@
 	__asm__ __volatile__("lidt %0": "=m" (idt_descr));
 }
 
+#define _set_gate(gate_addr,type,dpl,addr) \
+__asm__ __volatile__ ("movw %%dx,%%ax\n\t" \
+	"movw %2,%%dx\n\t" \
+	"movl %%eax,%0\n\t" \
+	"movl %%edx,%1" \
+	:"=m" (*((long *) (gate_addr))), \
+	 "=m" (*(1+(long *) (gate_addr))) \
+	:"i" ((short) (0x8000+(dpl<<13)+(type<<8))), \
+	 "d" ((char *) (addr)),"a" (__KERNEL_CS << 16) \
+	:"ax","dx")
+
+/*
+ * This needs to use 'idt_table' rather than 'idt', and
+ * thus use the _nonmapped_ version of the IDT, as the
+ * Pentium F0 0F bugfix can have resulted in the mapped
+ * IDT being write-protected.
+ */
+void set_intr_gate(unsigned int n, void *addr)
+{
+	_set_gate(idt_table+n,14,0,addr);
+}
+
+static void __init set_trap_gate(unsigned int n, void *addr)
+{
+	_set_gate(idt_table+n,15,0,addr);
+}
+
+static void __init set_system_gate(unsigned int n, void *addr)
+{
+	_set_gate(idt_table+n,15,3,addr);
+}
+
+static void __init set_call_gate(void *a, void *addr)
+{
+	_set_gate(a,12,3,addr);
+}
+
+#define _set_seg_desc(gate_addr,type,dpl,base,limit) {\
+	*((gate_addr)+1) = ((base) & 0xff000000) | \
+		(((base) & 0x00ff0000)>>16) | \
+		((limit) & 0xf0000) | \
+		((dpl)<<13) | \
+		(0x00408000) | \
+		((type)<<8); \
+	*(gate_addr) = (((base) & 0x0000ffff)<<16) | \
+		((limit) & 0x0ffff); }
 
+#define _set_tssldt_desc(n,addr,limit,type) \
+__asm__ __volatile__ ("movw %3,0(%2)\n\t" \
+	"movw %%ax,2(%2)\n\t" \
+	"rorl $16,%%eax\n\t" \
+	"movb %%al,4(%2)\n\t" \
+	"movb %4,5(%2)\n\t" \
+	"movb $0,6(%2)\n\t" \
+	"movb %%ah,7(%2)\n\t" \
+	"rorl $16,%%eax" \
+	: "=m"(*(n)) : "a" (addr), "r"(n), "ir"(limit), "i"(type))
+
+void set_tss_desc(unsigned int n, void *addr)
+{
+	_set_tssldt_desc(gdt_table+FIRST_TSS_ENTRY+(n<<1), (int)addr, 235, 0x89);
+}
+
+void set_ldt_desc(unsigned int n, void *addr, unsigned int size)
+{
+	_set_tssldt_desc(gdt_table+FIRST_LDT_ENTRY+(n<<1), (int)addr, ((size << 3) - 1), 0x82);
+}
 
 void __init trap_init(void)
 {
 	int i;
-	struct desc_struct * p;
 
 	if (readl(0x0FFFD9) == 'E' + ('I'<<8) + ('S'<<16) + ('A'<<24))
 		EISA_bus = 1;
@@ -515,19 +588,12 @@
 	for (i=18;i<48;i++)
 		set_trap_gate(i,&reserved);
 	set_system_gate(0x80,&system_call);
-/* set up GDT task & ldt entries */
-	p = gdt+FIRST_TSS_ENTRY;
-	set_tss_desc(p, &init_task.tss);
-	p++;
-	set_ldt_desc(p, &default_ldt, 1);
-	p++;
-	for(i=1 ; i<NR_TASKS ; i++) {
-		p->a=p->b=0;
-		p++;
-		p->a=p->b=0;
-		p++;
-	}
-/* Clear NT, so that we won't have troubles with that later on */
+
+	/* set up GDT task & ldt entries */
+	set_tss_desc(0, &init_task.tss);
+	set_ldt_desc(0, &default_ldt, 1);
+
+	/* Clear NT, so that we won't have troubles with that later on */
 	__asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl");
 	load_TR(0);
 	load_ldt(0);
diff -u --recursive --new-file v2.1.120/linux/arch/i386/math-emu/get_address.c linux/arch/i386/math-emu/get_address.c
--- v2.1.120/linux/arch/i386/math-emu/get_address.c	Fri Jan 30 11:28:06 1998
+++ linux/arch/i386/math-emu/get_address.c	Wed Sep  9 08:56:58 1998
@@ -19,7 +19,6 @@
 
 
 #include <linux/stddef.h>
-#include <linux/head.h>
 
 #include <asm/uaccess.h>
 
diff -u --recursive --new-file v2.1.120/linux/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c
--- v2.1.120/linux/arch/i386/mm/fault.c	Mon Aug  3 17:48:26 1998
+++ linux/arch/i386/mm/fault.c	Wed Sep  9 08:56:58 1998
@@ -6,7 +6,6 @@
 
 #include <linux/signal.h>
 #include <linux/sched.h>
-#include <linux/head.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/string.h>
@@ -76,7 +75,8 @@
 	return 0;
 }
 
-asmlinkage void do_invalid_op (struct pt_regs *, unsigned long);
+asmlinkage void do_invalid_op(struct pt_regs *, unsigned long);
+extern unsigned long idt;
 
 /*
  * This routine handles page faults.  It determines the address,
@@ -186,7 +186,7 @@
 	if (boot_cpu_data.f00f_bug) {
 		unsigned long nr;
 		
-		nr = (address - (unsigned long) idt) >> 3;
+		nr = (address - idt) >> 3;
 
 		if (nr == 6) {
 			do_invalid_op(regs, 0);
diff -u --recursive --new-file v2.1.120/linux/arch/i386/mm/init.c linux/arch/i386/mm/init.c
--- v2.1.120/linux/arch/i386/mm/init.c	Wed Aug 26 11:37:33 1998
+++ linux/arch/i386/mm/init.c	Wed Sep  9 08:56:58 1998
@@ -7,7 +7,6 @@
 #include <linux/config.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
-#include <linux/head.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/string.h>
diff -u --recursive --new-file v2.1.120/linux/arch/i386/vmlinux.lds linux/arch/i386/vmlinux.lds
--- v2.1.120/linux/arch/i386/vmlinux.lds	Wed Apr  8 19:36:25 1998
+++ linux/arch/i386/vmlinux.lds	Tue Sep  8 23:10:10 1998
@@ -35,12 +35,18 @@
 
   _edata = .;			/* End of data section */
 
+  . = ALIGN(8192);		/* init_task */
+  .data.init_task : { *(.data.init_task) }
+
   . = ALIGN(4096);		/* Init code and data */
   __init_begin = .;
   .text.init : { *(.text.init) }
   .data.init : { *(.data.init) }
   . = ALIGN(4096);
   __init_end = .;
+
+  . = ALIGN(4096);
+  .data.page_aligned : { *(.data.idt) }
 
   __bss_start = .;		/* BSS */
   .bss : {
diff -u --recursive --new-file v2.1.120/linux/arch/mips/kernel/ptrace.c linux/arch/mips/kernel/ptrace.c
--- v2.1.120/linux/arch/mips/kernel/ptrace.c	Fri May  8 23:14:43 1998
+++ linux/arch/mips/kernel/ptrace.c	Wed Sep  9 08:56:58 1998
@@ -3,7 +3,6 @@
 /* edited by Linus Torvalds */
 /* further hacked for MIPS by David S. Miller (dm@engr.sgi.com) */
 
-#include <linux/head.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
diff -u --recursive --new-file v2.1.120/linux/arch/mips/mm/fault.c linux/arch/mips/mm/fault.c
--- v2.1.120/linux/arch/mips/mm/fault.c	Fri May  8 23:14:43 1998
+++ linux/arch/mips/mm/fault.c	Wed Sep  9 08:56:58 1998
@@ -5,7 +5,6 @@
  */
 #include <linux/signal.h>
 #include <linux/sched.h>
-#include <linux/head.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/string.h>
diff -u --recursive --new-file v2.1.120/linux/arch/mips/mm/init.c linux/arch/mips/mm/init.c
--- v2.1.120/linux/arch/mips/mm/init.c	Thu Aug  6 14:06:28 1998
+++ linux/arch/mips/mm/init.c	Wed Sep  9 08:56:58 1998
@@ -11,7 +11,6 @@
 #include <linux/init.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
-#include <linux/head.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/string.h>
diff -u --recursive --new-file v2.1.120/linux/arch/ppc/kernel/mk_defs.c linux/arch/ppc/kernel/mk_defs.c
--- v2.1.120/linux/arch/ppc/kernel/mk_defs.c	Thu Aug  6 14:06:29 1998
+++ linux/arch/ppc/kernel/mk_defs.c	Wed Sep  9 08:56:58 1998
@@ -11,7 +11,6 @@
 #include <stddef.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
-#include <linux/head.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/string.h>
diff -u --recursive --new-file v2.1.120/linux/arch/ppc/mm/fault.c linux/arch/ppc/mm/fault.c
--- v2.1.120/linux/arch/ppc/mm/fault.c	Fri May  8 23:14:45 1998
+++ linux/arch/ppc/mm/fault.c	Wed Sep  9 08:56:58 1998
@@ -18,7 +18,6 @@
 #include <linux/config.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
-#include <linux/head.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/string.h>
diff -u --recursive --new-file v2.1.120/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c
--- v2.1.120/linux/arch/ppc/mm/init.c	Thu Aug  6 14:06:29 1998
+++ linux/arch/ppc/mm/init.c	Wed Sep  9 08:56:58 1998
@@ -22,7 +22,6 @@
 #include <linux/config.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
-#include <linux/head.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/string.h>
diff -u --recursive --new-file v2.1.120/linux/arch/sparc/mm/asyncd.c linux/arch/sparc/mm/asyncd.c
--- v2.1.120/linux/arch/sparc/mm/asyncd.c	Mon Jan 12 15:15:43 1998
+++ linux/arch/sparc/mm/asyncd.c	Wed Sep  9 08:56:58 1998
@@ -11,7 +11,6 @@
 #include <linux/mm.h>
 #include <linux/malloc.h>
 #include <linux/sched.h>
-#include <linux/head.h>
 #include <linux/kernel.h>
 #include <linux/kernel_stat.h>
 #include <linux/errno.h>
diff -u --recursive --new-file v2.1.120/linux/arch/sparc/mm/init.c linux/arch/sparc/mm/init.c
--- v2.1.120/linux/arch/sparc/mm/init.c	Thu Apr 23 20:21:31 1998
+++ linux/arch/sparc/mm/init.c	Wed Sep  9 08:56:58 1998
@@ -9,7 +9,6 @@
 #include <linux/config.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
-#include <linux/head.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/string.h>
diff -u --recursive --new-file v2.1.120/linux/arch/sparc64/mm/asyncd.c linux/arch/sparc64/mm/asyncd.c
--- v2.1.120/linux/arch/sparc64/mm/asyncd.c	Thu Aug  6 14:06:31 1998
+++ linux/arch/sparc64/mm/asyncd.c	Wed Sep  9 08:56:58 1998
@@ -11,7 +11,6 @@
 #include <linux/mm.h>
 #include <linux/malloc.h>
 #include <linux/sched.h>
-#include <linux/head.h>
 #include <linux/kernel.h>
 #include <linux/kernel_stat.h>
 #include <linux/errno.h>
diff -u --recursive --new-file v2.1.120/linux/drivers/acorn/block/ide-ics.c linux/drivers/acorn/block/ide-ics.c
--- v2.1.120/linux/drivers/acorn/block/ide-ics.c	Mon Feb 23 18:12:03 1998
+++ linux/drivers/acorn/block/ide-ics.c	Sun Sep  6 10:46:07 1998
@@ -163,6 +163,23 @@
 	return iftype;
 }
 
+static int icside_register_port(unsigned long dataport, unsigned long ctrlport, int stepping, int irq)
+{
+	hw_regs_t hw;
+	int i;
+
+	memset(&hw, 0, sizeof(hw));
+
+	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+		hw.io_ports[i] = (ide_ioreg_t)dataport;
+		dataport += 1 << stepping;
+	}
+	hw.io_ports[IDE_CONTROL_OFFSET] = ctrlport;
+	hw.irq = irq;
+
+	return ide_register_hw(&hw, NULL);
+}
+
 /* Prototype: icside_register (struct expansion_card *ec)
  * Purpose  : register an ICS IDE card with the IDE driver
  * Notes    : we make sure that interrupts are disabled from the card
@@ -189,11 +206,10 @@
 		 * Be on the safe side - disable interrupts
 		 */
 		inb (port + ICS_ARCIN_V5_INTROFFSET);
-		result[index][0] =
-			ide_register_port (port + ICS_ARCIN_V5_IDEOFFSET,
-					   port + ICS_ARCIN_V5_IDEALTOFFSET,
-					   ICS_ARCIN_V5_IDESTEPPING,
-					   ec->irq);
+		result[index][0] = icside_register_port(port + ICS_ARCIN_V5_IDEOFFSET,
+							port + ICS_ARCIN_V5_IDEALTOFFSET,
+							ICS_ARCIN_V5_IDESTEPPING,
+							ec->irq);
 		break;
 
 	case ics_if_arcin_v6:
@@ -206,16 +222,15 @@
 		 */
 		inb (port + ICS_ARCIN_V6_INTROFFSET_1);
 		inb (port + ICS_ARCIN_V6_INTROFFSET_2);
-		result[index][0] =
-			ide_register_port (port + ICS_ARCIN_V6_IDEOFFSET_1,
-					   port + ICS_ARCIN_V6_IDEALTOFFSET_1,
-					   ICS_ARCIN_V6_IDESTEPPING,
-					   ec->irq);
-		result[index][1] =
-			ide_register_port (port + ICS_ARCIN_V6_IDEOFFSET_2,
-					   port + ICS_ARCIN_V6_IDEALTOFFSET_2,
-					   ICS_ARCIN_V6_IDESTEPPING,
-					   ec->irq);
+
+		result[index][0] = icside_register_port(port + ICS_ARCIN_V6_IDEOFFSET_1,
+							port + ICS_ARCIN_V6_IDEALTOFFSET_1,
+							ICS_ARCIN_V6_IDESTEPPING,
+							ec->irq);
+		result[index][1] = icside_register_port(port + ICS_ARCIN_V6_IDEOFFSET_2,
+							port + ICS_ARCIN_V6_IDEALTOFFSET_2,
+							ICS_ARCIN_V6_IDESTEPPING,
+							ec->irq);
 		break;
 	}		
 }
diff -u --recursive --new-file v2.1.120/linux/drivers/acorn/block/ide-rapide.c linux/drivers/acorn/block/ide-rapide.c
--- v2.1.120/linux/drivers/acorn/block/ide-rapide.c	Fri May  8 23:14:46 1998
+++ linux/drivers/acorn/block/ide-rapide.c	Sun Sep  6 10:46:07 1998
@@ -13,6 +13,7 @@
 #include <linux/blkdev.h>
 #include <linux/errno.h>
 #include <asm/ecard.h>
+#include <asm/ide.h>
 
 #include "../../block/ide.h"
 
@@ -27,8 +28,14 @@
 static inline int rapide_register(struct expansion_card *ec)
 {
 	unsigned long port = ecard_address (ec, ECARD_MEMC, 0);
+	ide_ioregspec_t spec;
 
-	return ide_register_port(port, port + 0x206, 4, ec->irq);
+	spec.base = port;
+	spec.ctrl = port + 0x206;
+	spec.offset = 1 << 4;
+	spec.irq = ec->irq;
+
+	return ide_register_port(&spec);
 }
 
 int rapide_init(void)
diff -u --recursive --new-file v2.1.120/linux/drivers/acorn/char/serial-card.c linux/drivers/acorn/char/serial-card.c
--- v2.1.120/linux/drivers/acorn/char/serial-card.c	Tue Jul 21 00:15:30 1998
+++ linux/drivers/acorn/char/serial-card.c	Sun Sep  6 10:46:07 1998
@@ -1,5 +1,5 @@
 /*
- * linux/arch/arm/drivers/char/serial-module.c
+ * linux/arch/arm/drivers/char/serial-card.c
  *
  * Copyright (c) 1996 Russell King.
  *
diff -u --recursive --new-file v2.1.120/linux/drivers/acorn/net/Makefile linux/drivers/acorn/net/Makefile
--- v2.1.120/linux/drivers/acorn/net/Makefile	Mon Feb 23 18:12:03 1998
+++ linux/drivers/acorn/net/Makefile	Sun Sep  6 10:46:07 1998
@@ -4,7 +4,7 @@
 #
 
 L_TARGET := acorn-net.a
-L_OBJS   := net-probe.o
+L_OBJS   :=
 M_OBJS   :=
 MOD_LIST_NAME := ACORN_NET_MODULES
 
diff -u --recursive --new-file v2.1.120/linux/drivers/acorn/net/ether3.c linux/drivers/acorn/net/ether3.c
--- v2.1.120/linux/drivers/acorn/net/ether3.c	Tue Jul 21 00:15:30 1998
+++ linux/drivers/acorn/net/ether3.c	Sun Sep  6 10:46:07 1998
@@ -35,7 +35,6 @@
  *				never updates the transmit status correctly.
  * TODO:
  *  When we detect a fatal error on the interface, we should restart it.
- *  Reap transmit packets after some time even if the buffer never filled.
  */
 
 static char *version = "ether3 ethernet driver (c) 1995-1998 R.M.King v1.13\n";
@@ -98,15 +97,25 @@
 	buffer_read
 } buffer_rw_t;
 
+/*
+ * ether3 read/write.  Slow things down a bit...
+ */
+#define ether3_outb(v,r)	{ outb((v),(r)); udelay(1); }
+#define ether3_outw(v,r)	{ outw((v),(r)); udelay(1); }
+
+#define ether3_inb(r)		({ unsigned int __v = inb((r)); udelay(1); __v; })
+#define ether3_inw(r)		({ unsigned int __v = inw((r)); udelay(1); __v; })
+
 static int
 ether3_setbuffer(struct device *dev, buffer_rw_t read, int start)
 {
 	struct dev_priv *priv = (struct dev_priv *)dev->priv;
 	int timeout = 1000;
 
-	outw(priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
-	outw(priv->regs.command | CMD_FIFOWRITE, REG_COMMAND);
-	while ((inw(REG_STATUS) & STAT_FIFOEMPTY) == 0) {
+	ether3_outw(priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
+	ether3_outw(priv->regs.command | CMD_FIFOWRITE, REG_COMMAND);
+
+	while ((ether3_inw(REG_STATUS) & STAT_FIFOEMPTY) == 0) {
 		if (!timeout--) {
 			printk("%s: setbuffer broken\n", dev->name);
 			priv->broken = 1;
@@ -114,12 +123,13 @@
 		}
 		udelay(1);
 	}
+
 	if (read == buffer_read) {
-		outw(start, REG_DMAADDR);
-		outw(priv->regs.command | CMD_FIFOREAD, REG_COMMAND);
+		ether3_outw(start, REG_DMAADDR);
+		ether3_outw(priv->regs.command | CMD_FIFOREAD, REG_COMMAND);
 	} else {
-		outw(priv->regs.command | CMD_FIFOWRITE, REG_COMMAND);
-		outw(start, REG_DMAADDR);
+		ether3_outw(priv->regs.command | CMD_FIFOWRITE, REG_COMMAND);
+		ether3_outw(start, REG_DMAADDR);
 	}
 	return 0;
 }
@@ -159,7 +169,7 @@
 {
 	struct device *dev = (struct device *)data;
 	struct dev_priv *priv = (struct dev_priv *)dev->priv;
-	outw(priv->regs.config2 |= CFG2_CTRLO, REG_CONFIG2);
+	ether3_outw(priv->regs.config2 |= CFG2_CTRLO, REG_CONFIG2);
 }
 
 /*
@@ -174,7 +184,7 @@
 	priv->timer.function = ether3_ledoff;
 	add_timer(&priv->timer);
 	if (priv->regs.config2 & CFG2_CTRLO)
-		outw(priv->regs.config2 &= ~CFG2_CTRLO, REG_CONFIG2);
+		ether3_outw(priv->regs.config2 &= ~CFG2_CTRLO, REG_CONFIG2);
 }
 
 /*
@@ -240,7 +250,7 @@
 		} else {
 			if (bad != -1) {
 			    	if (bad != i - 1)
-					printk(" - 0x%04X", i - 1);
+					printk(" - 0x%04X\n", i - 1);
 				printk("\n");
 				bad = -1;
 			}
@@ -268,9 +278,9 @@
 	/*
 	 * Set up our hardware address
 	 */
-	outw(priv->regs.config1 | CFG1_BUFSELSTAT0, REG_CONFIG1);
+	ether3_outw(priv->regs.config1 | CFG1_BUFSELSTAT0, REG_CONFIG1);
 	for (i = 0; i < 6; i++)
-		outb(dev->dev_addr[i], REG_BUFWIN);
+		ether3_outb(dev->dev_addr[i], REG_BUFWIN);
 
 	if (dev->flags & IFF_PROMISC)
 		priv->regs.config1 |= CFG1_RECVPROMISC;
@@ -284,14 +294,14 @@
 	 * last two bytes.  To get round this problem, we receive the CRC as
 	 * well.  That way, if we do loose the last two, then it doesn't matter.
 	 */
-	outw(priv->regs.config1 | CFG1_TRANSEND, REG_CONFIG1);
-	outw((TX_END>>8) - 1, REG_BUFWIN);
-	outw(priv->rx_head, REG_RECVPTR);
-	outw(0, REG_TRANSMITPTR);
-	outw(priv->rx_head >> 8, REG_RECVEND);
-	outw(priv->regs.config2, REG_CONFIG2);
-	outw(priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
-	outw(priv->regs.command, REG_COMMAND);
+	ether3_outw(priv->regs.config1 | CFG1_TRANSEND, REG_CONFIG1);
+	ether3_outw((TX_END>>8) - 1, REG_BUFWIN);
+	ether3_outw(priv->rx_head, REG_RECVPTR);
+	ether3_outw(0, REG_TRANSMITPTR);
+	ether3_outw(priv->rx_head >> 8, REG_RECVEND);
+	ether3_outw(priv->regs.config2, REG_CONFIG2);
+	ether3_outw(priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
+	ether3_outw(priv->regs.command, REG_COMMAND);
 
 	i = ether3_ramtest(dev, 0x5A);
 	if(i)
@@ -314,16 +324,16 @@
 	memset(&priv->stats, 0, sizeof(struct enet_statistics));
 
 	/* Reset the chip */
-	outw(CFG2_RESET, REG_CONFIG2);
+	ether3_outw(CFG2_RESET, REG_CONFIG2);
 	udelay(4);
 
 	priv->regs.command = 0;
-	outw(CMD_RXOFF|CMD_TXOFF, REG_COMMAND);
-	while (inw(REG_STATUS) & (STAT_RXON|STAT_TXON));
+	ether3_outw(CMD_RXOFF|CMD_TXOFF, REG_COMMAND);
+	while (ether3_inw(REG_STATUS) & (STAT_RXON|STAT_TXON));
 
-	outw(priv->regs.config1 | CFG1_BUFSELSTAT0, REG_CONFIG1);
+	ether3_outw(priv->regs.config1 | CFG1_BUFSELSTAT0, REG_CONFIG1);
 	for (i = 0; i < 6; i++)
-		outb(dev->dev_addr[i], REG_BUFWIN);
+		ether3_outb(dev->dev_addr[i], REG_BUFWIN);
 
 	priv->tx_used	= 0;
 	priv->tx_head	= 0;
@@ -331,36 +341,53 @@
 	priv->regs.config2 |= CFG2_CTRLO;
 	priv->rx_head	= RX_START;
 
-	outw(priv->regs.config1 | CFG1_TRANSEND, REG_CONFIG1);
-	outw((TX_END>>8) - 1, REG_BUFWIN);
-	outw(priv->rx_head, REG_RECVPTR);
-	outw(priv->rx_head >> 8, REG_RECVEND);
-	outw(0, REG_TRANSMITPTR);
-	outw(priv->regs.config2, REG_CONFIG2);
-	outw(priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
+	ether3_outw(priv->regs.config1 | CFG1_TRANSEND, REG_CONFIG1);
+	ether3_outw((TX_END>>8) - 1, REG_BUFWIN);
+	ether3_outw(priv->rx_head, REG_RECVPTR);
+	ether3_outw(priv->rx_head >> 8, REG_RECVEND);
+	ether3_outw(0, REG_TRANSMITPTR);
+	ether3_outw(priv->regs.config2, REG_CONFIG2);
+	ether3_outw(priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
 
 	ether3_setbuffer(dev, buffer_write, 0);
 	ether3_writelong(dev, 0);
 
-	priv->regs.command = CMD_ENINTRX;
-	outw(priv->regs.command | CMD_RXON, REG_COMMAND);
+	priv->regs.command = CMD_ENINTRX | CMD_ENINTTX;
+	ether3_outw(priv->regs.command | CMD_RXON, REG_COMMAND);
 }
 
 static inline int
 ether3_probe_bus_8(struct device *dev, int val)
 {
-	outb(val & 255, REG_RECVPTR);
-	outb(val >> 8, REG_RECVPTR + 1);
+	int write_low, write_high, read_low, read_high;
 
-	return inb(REG_RECVPTR) == (val & 255) && inb(REG_RECVPTR + 1) == (val >> 8);
+	write_low = val & 255;
+	write_high = val >> 8;
+
+	printk(KERN_DEBUG "ether3_probe: write8 [%02X:%02X]", write_high, write_low);
+
+	ether3_outb(write_low, REG_RECVPTR);
+	ether3_outb(write_high, REG_RECVPTR + 1);
+
+	read_low = ether3_inb(REG_RECVPTR);
+	read_high = ether3_inb(REG_RECVPTR + 1);
+
+	printk(", read8 [%02X:%02X]\n", read_high, read_low);
+
+	return read_low == write_low && read_high == write_high;
 }
 
 static inline int
 ether3_probe_bus_16(struct device *dev, int val)
 {
-	outw(val, REG_RECVPTR);
+	int read_val;
+
+	ether3_outw(val, REG_RECVPTR);
+	read_val = ether3_inw(REG_RECVPTR);
 
-	return inw(REG_RECVPTR) == val;
+	printk(KERN_DEBUG "ether3_probe: write16 [%04X], read16 [%04X]\n", val, read_val);
+
+	return read_val == val;
 }
 
 /*
@@ -373,13 +400,15 @@
 	struct dev_priv *priv;
 	unsigned int i, bus_type, error = ENODEV;
 
-	if (net_debug  &&  version_printed++ == 0)
+	if (net_debug && version_printed++ == 0)
 		printk(version);
 
 	if (!dev->priv) {
 		dev->priv = kmalloc(sizeof (struct dev_priv), GFP_KERNEL);
-		if (!dev->priv)
+		if (!dev->priv) {
+			printk(KERN_ERR "ether3_probe1: no memory\n");
 			return -ENOMEM;
+		}
 	}
 
 	priv = (struct dev_priv *) dev->priv;
@@ -389,7 +418,7 @@
 
 	/* Reset card...
 	 */
-	outb(0x80, REG_CONFIG2 + 1);
+	ether3_outb(0x80, REG_CONFIG2 + 1);
 	bus_type = BUS_UNKNOWN;
 	udelay(4);
 
@@ -506,11 +535,11 @@
 
 	disable_irq(dev->irq);
 
-	outw(CMD_RXOFF|CMD_TXOFF, REG_COMMAND);
+	ether3_outw(CMD_RXOFF|CMD_TXOFF, REG_COMMAND);
 	priv->regs.command = 0;
-	while (inw(REG_STATUS) & (STAT_RXON|STAT_TXON));
-	outb(0x80, REG_CONFIG2 + 1);
-	outw(0, REG_COMMAND);
+	while (ether3_inw(REG_STATUS) & (STAT_RXON|STAT_TXON));
+	ether3_outb(0x80, REG_CONFIG2 + 1);
+	ether3_outw(0, REG_COMMAND);
 
 	free_irq(dev->irq, dev);
 
@@ -548,7 +577,34 @@
 	} else
 		priv->regs.config1 |= CFG1_RECVSPECBROAD;
 
-	outw(priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
+	ether3_outw(priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
+}
+
+/*
+ * Allocate memory in transmitter ring buffer.
+ */
+static int
+ether3_alloc_tx(struct dev_priv *priv, int length, int alloc)
+{
+	int start, head, tail;
+
+	tail = priv->tx_tail;
+	start = priv->tx_head;
+	head = start + length + 4;
+
+	if (head >= TX_END) {
+		if (tail > priv->tx_head)
+			return -1;
+		head -= TX_END - TX_START;
+		if (tail < head)
+			return -1;
+	} else if (start < tail && tail < head)
+		return -1;
+
+	if (alloc)
+		priv->tx_head = head;
+
+	return start;
 }
 
 /*
@@ -566,9 +622,9 @@
 		if (!test_and_set_bit(0, (void *)&dev->tbusy)) {
 			unsigned long flags;
 			unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
-			unsigned int ptr, nextptr;
+			int ptr;
 
-			length = (length + 3) & ~3;
+			length = (length + 1) & ~1;
 
 			if (priv->broken) {
 				dev_kfree_skb(skb);
@@ -577,43 +633,32 @@
 				return 0;
 			}
 
-			ptr = priv->tx_head;
-			nextptr = ptr + 0x600;
-			if (nextptr >= TX_END)
-				nextptr = 0;
-			if (nextptr == priv->tx_tail)
-				return 1;		/* unable to queue */
-			priv->tx_head = nextptr;
-
 			save_flags_cli(flags);
 
+			ptr = ether3_alloc_tx(priv, length, 1);
+			if (ptr == -1)
+				return 1;	/* unable to queue */
+
 #define TXHDR_FLAGS (TXHDR_TRANSMIT|TXHDR_CHAINCONTINUE|TXHDR_DATAFOLLOWS|TXHDR_ENSUCCESS)
 
-			ether3_setbuffer(dev, buffer_write, nextptr);
+			ether3_setbuffer(dev, buffer_write, priv->tx_head);
 			ether3_writelong(dev, 0);
 
-			ether3_setbuffer(dev, buffer_write, ptr + 4);
+			ether3_setbuffer(dev, buffer_write, ptr);
+			ether3_writelong(dev, 0);
 			ether3_writebuffer(dev, skb->data, length);
-			ether3_writeword(dev, htons(nextptr));
-			ether3_writeword(dev, (TXHDR_TRANSMIT|TXHDR_CHAINCONTINUE) >> 16);
 
 			ether3_setbuffer(dev, buffer_write, ptr);
-			ether3_writeword(dev, htons(ptr + length + 4));
+			ether3_writeword(dev, htons(priv->tx_head));
 			ether3_writeword(dev, TXHDR_FLAGS >> 16);
 			ether3_ledon(dev, priv);
 
-			priv->tx_used ++;
-			if (priv->tx_used >= (MAX_TX_BUFFERED * 3 / 4)) {
-				priv->regs.command |= CMD_ENINTTX;
-				outw(priv->regs.command, REG_COMMAND);
-			}
-
-			if (!(inw(REG_STATUS) & STAT_TXON)) {
-				outw(ptr, REG_TRANSMITPTR);
-				outw(priv->regs.command | CMD_TXON, REG_COMMAND);
+			if (!(ether3_inw(REG_STATUS) & STAT_TXON)) {
+				ether3_outw(ptr, REG_TRANSMITPTR);
+				ether3_outw(priv->regs.command | CMD_TXON, REG_COMMAND);
 			}
 
-			if (priv->tx_used < MAX_TX_BUFFERED)
+			if (ether3_alloc_tx(priv, 2044, 0) != -1)
 				dev->tbusy = 0;
 
 			dev->trans_start = jiffies;
@@ -641,9 +686,9 @@
 		save_flags_cli(flags);
 		printk(KERN_ERR "%s: transmit timed out, network cable problem?\n", dev->name);
 		printk(KERN_ERR "%s: state: { status=%04X cfg1=%04X cfg2=%04X }\n", dev->name,
-			inw(REG_STATUS), inw(REG_CONFIG1), inw(REG_CONFIG2));
+			ether3_inw(REG_STATUS), ether3_inw(REG_CONFIG1), ether3_inw(REG_CONFIG2));
 		printk(KERN_ERR "%s: { rpr=%04X rea=%04X tpr=%04X }\n", dev->name,
-			inw(REG_RECVPTR), inw(REG_RECVEND), inw(REG_TRANSMITPTR));
+			ether3_inw(REG_RECVPTR), ether3_inw(REG_RECVEND), ether3_inw(REG_TRANSMITPTR));
 		printk(KERN_ERR "%s: tx head=%04X tx tail=%04X\n", dev->name,
 			priv->tx_head, priv->tx_tail);
 		ether3_setbuffer(dev, buffer_read, priv->tx_tail);
@@ -653,7 +698,7 @@
 		dev->tbusy = 0;
 		priv->regs.config2 |= CFG2_CTRLO;
 		priv->stats.tx_errors += 1;
-		outw(priv->regs.config2 , REG_CONFIG2);
+		ether3_outw(priv->regs.config2 , REG_CONFIG2);
 		dev->trans_start = jiffies;
 		goto retry;
 	}
@@ -674,31 +719,19 @@
 	priv = (struct dev_priv *)dev->priv;
 
 	dev->interrupt = 1;
-	status = inw(REG_STATUS);
-	/*
-	 * Dispite we disable the TX interrupt when the packet buffer is
-	 * mostly empty, if we happen to get a RX interrupt, we might as
-	 * well handle the TX packets as well.
-	 */
-	if (status & STAT_INTTX) { /* Packets transmitted */
-		outw(CMD_ACKINTTX | priv->regs.command, REG_COMMAND);
-		ether3_tx(dev, priv);
+
+	status = ether3_inw(REG_STATUS);
+
+	if (status & STAT_INTRX) {
+		ether3_outw(CMD_ACKINTRX | priv->regs.command, REG_COMMAND);
+		ether3_rx(dev, priv, 12);
 	}
 
-	status = inw(REG_STATUS);
-	if (status & STAT_INTRX && ether3_rx(dev, priv, 12)) { /* Got packet(s). */
-		/*
-		 * We only acknowledge the interrupt if we have received all packets
-		 * in the buffer or else we run out of memory. This is to allow the
-		 * bh routines to run.
-		 */
-		outw(CMD_ACKINTRX | priv->regs.command, REG_COMMAND);
-		/*
-		 * Receive again if some have become available - we may have cleared
-		 * a pending IRQ
-		 */
-		ether3_rx(dev, priv, 4);
+	if (status & STAT_INTTX) {
+		ether3_outw(CMD_ACKINTTX | priv->regs.command, REG_COMMAND);
+		ether3_tx(dev, priv);
 	}
+
 	dev->interrupt = 0;
 
 #if NET_DEBUG > 1
@@ -741,13 +774,23 @@
 		ether3_setbuffer(dev, buffer_read, this_ptr);
 		ether3_readbuffer(dev, addrs+2, 12);
 
+if (next_ptr < RX_START || next_ptr >= RX_END) {
+ int i;
+ printk("%s: bad next pointer @%04X: ", dev->name, priv->rx_head);
+ printk("%02X %02X %02X %02X ", next_ptr >> 8, next_ptr & 255, status & 255, status >> 8);
+ for (i = 2; i < 14; i++)
+   printk("%02X ", addrs[i]);
+ printk("\n");
+ next_ptr = priv->rx_head;
+ break;
+}
 		/*
  		 * ignore our own packets...
 	 	 */
 		if (!(*(unsigned long *)&dev->dev_addr[0] ^ *(unsigned long *)&addrs[2+6]) &&
 		    !(*(unsigned short *)&dev->dev_addr[4] ^ *(unsigned short *)&addrs[2+10])) {
 			maxcnt ++; /* compensate for loopedback packet */
-			outw(next_ptr >> 8, REG_RECVEND);
+			ether3_outw(next_ptr >> 8, REG_RECVEND);
 		} else
 		if (!(status & (RXSTAT_OVERSIZE|RXSTAT_CRCERROR|RXSTAT_DRIBBLEERROR|RXSTAT_SHORTPACKET))) {
 			unsigned int length = next_ptr - this_ptr;
@@ -764,7 +807,7 @@
 				skb_reserve(skb, 2);
 				buf = skb_put(skb, length);
 				ether3_readbuffer(dev, buf + 12, length - 12);
-				outw(next_ptr >> 8, REG_RECVEND);
+				ether3_outw(next_ptr >> 8, REG_RECVEND);
 				*(unsigned short *)(buf + 0)	= *(unsigned short *)(addrs + 2);
 				*(unsigned long *)(buf + 2)	= *(unsigned long *)(addrs + 4);
 				*(unsigned long *)(buf + 6)	= *(unsigned long *)(addrs + 8);
@@ -776,7 +819,7 @@
 				goto dropping;
 		} else {
 			struct enet_statistics *stats = &priv->stats;
-			outw(next_ptr >> 8, REG_RECVEND);
+			ether3_outw(next_ptr >> 8, REG_RECVEND);
 			if (status & RXSTAT_OVERSIZE)	  stats->rx_over_errors ++;
 			if (status & RXSTAT_CRCERROR)	  stats->rx_crc_errors ++;
 			if (status & RXSTAT_DRIBBLEERROR) stats->rx_fifo_errors ++;
@@ -793,10 +836,10 @@
 	 * If rx went off line, then that means that the buffer may be full.  We
 	 * have dropped at least one packet.
 	 */
-	if (!(inw(REG_STATUS) & STAT_RXON)) {
+	if (!(ether3_inw(REG_STATUS) & STAT_RXON)) {
 		priv->stats.rx_dropped ++;
-    		outw(next_ptr, REG_RECVPTR);
-		outw(priv->regs.command | CMD_RXON, REG_COMMAND);
+    		ether3_outw(next_ptr, REG_RECVPTR);
+		ether3_outw(priv->regs.command | CMD_RXON, REG_COMMAND);
 	}
 
 	return maxcnt;
@@ -804,7 +847,7 @@
 dropping:{
 	static unsigned long last_warned;
 
-	outw(next_ptr >> 8, REG_RECVEND);
+	ether3_outw(next_ptr >> 8, REG_RECVEND);
 	/*
 	 * Don't print this message too many times...
 	 */
@@ -852,15 +895,13 @@
 			if (status & TXSTAT_BABBLED) priv->stats.tx_fifo_errors ++;
 		}
 
-		/*
-		 * Get next packet address
-		 */
-		tx_tail += 0x600;
-		if (tx_tail >= TX_END)
-			tx_tail = 0;
-
-		if (priv->tx_used)
-			priv->tx_used--;
+		tx_tail = htons(status & TX_NEXT);
+		if (tx_tail < TX_START || tx_tail >= TX_END) {
+			printk("%s: transmit error: next pointer = %04X\n", dev->name, tx_tail);
+			tx_tail = TX_START;
+			priv->tx_head = TX_START;
+			priv->tx_tail = TX_END;
+		}
 	} while (1);
 
 	if (priv->tx_tail != tx_tail) {
@@ -870,8 +911,6 @@
 			mark_bh(NET_BH);	/* Inform upper layers. */
 		}
 	}
-	priv->regs.command &= ~CMD_ENINTTX;
-	outw(priv->regs.command, REG_COMMAND);
 }
 
 #ifdef MODULE
diff -u --recursive --new-file v2.1.120/linux/drivers/acorn/net/ether3.h linux/drivers/acorn/net/ether3.h
--- v2.1.120/linux/drivers/acorn/net/ether3.h	Mon Feb 23 18:12:03 1998
+++ linux/drivers/acorn/net/ether3.h	Sun Sep  6 10:46:07 1998
@@ -64,6 +64,12 @@
 #define CFG1_TRANSEND		0x0007
 #define CFG1_LOCBUFMEM		0x0008
 #define CFG1_INTVECTOR		0x0009
+#define CFG1_RECVSPECONLY	0x0000
+#define CFG1_RECVSPECBROAD	0x4000
+#define CFG1_RECVSPECBRMULTI	0x8000
+#define CFG1_RECVPROMISC	0xC000
+
+/* The following aren't in 8004 */
 #define CFG1_DMABURSTCONT	0x0000
 #define CFG1_DMABURST800NS	0x0010
 #define CFG1_DMABURST1600NS	0x0020
@@ -78,10 +84,6 @@
 #define CFG1_RECVCOMPSTAT3	0x0800
 #define CFG1_RECVCOMPSTAT4	0x1000
 #define CFG1_RECVCOMPSTAT5	0x2000
-#define CFG1_RECVSPECONLY	0x0000
-#define CFG1_RECVSPECBROAD	0x4000
-#define CFG1_RECVSPECBRMULTI	0x8000
-#define CFG1_RECVPROMISC	0xC000
 
 /* configuration register 2 */
 #define REG_CONFIG2		(dev->base_addr + 0x20)
@@ -134,6 +136,7 @@
 #define RXSTAT_DONE		(1 << 15)
 
 
+#define TX_START	0x0000
 #define TX_END		0x6000
 #define RX_START	0x6000
 #define RX_LEN		0xA000
diff -u --recursive --new-file v2.1.120/linux/drivers/acorn/scsi/cumana_2.c linux/drivers/acorn/scsi/cumana_2.c
--- v2.1.120/linux/drivers/acorn/scsi/cumana_2.c	Tue Jul 21 00:15:30 1998
+++ linux/drivers/acorn/scsi/cumana_2.c	Sun Sep  6 10:46:07 1998
@@ -9,6 +9,7 @@
  *  15-04-1998	RMK	0.0.1	Only do PIO if FAS216 will allow it.
  *  02-05-1998	RMK	0.0.2	Updated & added DMA support
  *  27-06-1998	RMK		Changed asm/delay.h to linux/delay.h
+ *  18-08-1998	RMK	0.0.3	Fixed synchronous transfer depth
  */
 
 #include <linux/module.h>
@@ -35,7 +36,7 @@
 /* Configuration */
 #define CUMANASCSI2_XTALFREQ		40
 #define CUMANASCSI2_ASYNC_PERIOD	200
-#define CUMANASCSI2_SYNC_DEPTH		8
+#define CUMANASCSI2_SYNC_DEPTH		7
 
 /*
  * List of devices that the driver will recognise
@@ -69,7 +70,7 @@
  */
 #define VER_MAJOR	0
 #define VER_MINOR	0
-#define VER_PATCH	2
+#define VER_PATCH	3
 
 static struct expansion_card *ecs[MAX_ECARDS];
 
@@ -157,13 +158,10 @@
 {
 	unsigned int page;
 
-	if (direction == DMA_OUT) {
-		for (page = (unsigned int) addr; len > 0;
-		     page += PAGE_SIZE, len -= PAGE_SIZE)
-			flush_page_to_ram(page);
-	} else
-		flush_cache_range(current->mm, (unsigned long)addr,
-				  (unsigned long)addr + len);
+	if (direction == DMA_OUT)
+		dma_cache_wback((unsigned long)addr, (unsigned long)len);
+	else
+		dma_cache_inv((unsigned long)addr, (unsigned long)len);
 }
 
 /* Prototype: fasdmatype_t cumanascsi_2_dma_setup(host, SCpnt, direction, min_type)
diff -u --recursive --new-file v2.1.120/linux/drivers/acorn/scsi/eesox.c linux/drivers/acorn/scsi/eesox.c
--- v2.1.120/linux/drivers/acorn/scsi/eesox.c	Tue Jul 21 00:15:30 1998
+++ linux/drivers/acorn/scsi/eesox.c	Sun Sep  6 10:46:07 1998
@@ -166,13 +166,10 @@
 {
 	unsigned int page;
 
-	if (direction == DMA_OUT) {
-		for(page = (unsigned int) addr; len > 0;
-		     page += PAGE_SIZE, len -= PAGE_SIZE)
-			flush_page_to_ram(page);
-	} else
-		flush_cache_range(current->mm, (unsigned long)addr,
-				  (unsigned long)addr + len);
+	if (direction == DMA_OUT)
+		dma_cache_wback((unsigned long)addr, (unsigned long)len);
+	else
+		dma_cache_inv((unsigned long)addr, (unsigned long)len);
 }
 
 /* Prototype: fasdmatype_t eesoxscsi_dma_setup(host, SCpnt, direction, min_type)
diff -u --recursive --new-file v2.1.120/linux/drivers/acorn/scsi/powertec.c linux/drivers/acorn/scsi/powertec.c
--- v2.1.120/linux/drivers/acorn/scsi/powertec.c	Tue Jul 21 00:15:30 1998
+++ linux/drivers/acorn/scsi/powertec.c	Sun Sep  6 10:46:07 1998
@@ -154,13 +154,10 @@
 {
 	unsigned int page;
 
-	if (direction == DMA_OUT) {
-		for (page = (unsigned int) addr; len > 0;
-		     page += PAGE_SIZE, len -= PAGE_SIZE)
-			flush_page_to_ram(page);
-	} else
-		flush_cache_range(current->mm, (unsigned long)addr,
-				  (unsigned long)addr + len);
+	if (direction == DMA_OUT)
+		dma_cache_wback((unsigned long)addr, (unsigned long)len);
+	else
+		dma_cache_inv((unsigned long)addr, (unsigned long)len);
 }
 
 /* Prototype: fasdmatype_t powertecscsi_dma_setup(host, SCpnt, direction, min_type)
diff -u --recursive --new-file v2.1.120/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- v2.1.120/linux/drivers/block/floppy.c	Wed Aug 26 11:37:35 1998
+++ linux/drivers/block/floppy.c	Tue Sep  8 16:20:19 1998
@@ -233,7 +233,7 @@
 
 /* End dma memory related stuff */
 
-static unsigned int fake_change = 0;
+static unsigned long fake_change = 0;
 static int initialising=1;
 
 static inline int TYPE(kdev_t x) {
diff -u --recursive --new-file v2.1.120/linux/drivers/block/ide-probe.c linux/drivers/block/ide-probe.c
--- v2.1.120/linux/drivers/block/ide-probe.c	Tue Aug 18 22:02:03 1998
+++ linux/drivers/block/ide-probe.c	Tue Sep  8 10:39:27 1998
@@ -13,7 +13,7 @@
  * Version 1.00		move drive probing code from ide.c to ide-probe.c
  * Version 1.01		fix compilation problem for m68k
  * Version 1.02		increase WAIT_PIDENTIFY to avoid CD-ROM locking at boot
- *			 by Andrea Arcangeli <arcangeli@mbox.queen.it>
+ *			 by Andrea Arcangeli
  * Version 1.03		fix for (hwif->chipset == ide_4drives)
  */
 
diff -u --recursive --new-file v2.1.120/linux/drivers/block/ide-tape.c linux/drivers/block/ide-tape.c
--- v2.1.120/linux/drivers/block/ide-tape.c	Thu May  7 22:51:48 1998
+++ linux/drivers/block/ide-tape.c	Sat Sep  5 17:01:45 1998
@@ -3708,6 +3708,7 @@
 	idetape_chrdev_ioctl,	/* ioctl */
 	NULL,			/* mmap */
 	idetape_chrdev_open,	/* open */
+	NULL,			/* flush */
 	idetape_chrdev_release,	/* release */
 	NULL,			/* fsync */
 	NULL,			/* fasync */
diff -u --recursive --new-file v2.1.120/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c
--- v2.1.120/linux/drivers/cdrom/cdrom.c	Wed Aug 26 11:37:36 1998
+++ linux/drivers/cdrom/cdrom.c	Tue Sep  8 10:39:27 1998
@@ -76,7 +76,7 @@
   of the drive.  Thanks to Tobias Ringstr|m <tori@prosolvia.se> for pointing
   this out and providing a simple fix.
   -- Fixed the procfs-unload-module bug with the fill_inode procfs callback.
-  thanks to Andrea Arcangeli <arcangeli@mbox.queen.it>
+  thanks to Andrea Arcangeli
   -- Fixed it so that the /proc entry now also shows up when cdrom is
   compiled into the kernel.  Before it only worked when loaded as a module.
 
diff -u --recursive --new-file v2.1.120/linux/drivers/char/bttv.c linux/drivers/char/bttv.c
--- v2.1.120/linux/drivers/char/bttv.c	Sat Sep  5 16:46:40 1998
+++ linux/drivers/char/bttv.c	Sat Sep  5 18:33:41 1998
@@ -1801,6 +1801,9 @@
 	        case VIDIOCSYNC:
 			if(copy_from_user((void *)&i,arg,sizeof(int)))
 				return -EFAULT;
+                        if(i>1 || i<0)
+                                return -EINVAL;
+
                         switch (btv->frame_stat[i]) {
                         case GBUFFER_UNUSED:
                                 return -EINVAL;
diff -u --recursive --new-file v2.1.120/linux/drivers/char/cyclades.c linux/drivers/char/cyclades.c
--- v2.1.120/linux/drivers/char/cyclades.c	Sat Sep  5 16:46:40 1998
+++ linux/drivers/char/cyclades.c	Sat Sep  5 17:01:45 1998
@@ -4974,7 +4974,7 @@
 
 	if (info->count)
 	    size = sprintf(buf+len,
-			"%3d %8lu %10lu %8lu %10lu %8lu %9lu %6d\n",
+			"%3d %8lu %10lu %8lu %10lu %8lu %9lu %6ld\n",
 			info->line,
 			JIFFIES_DIFF(info->idle_stats.in_use, cur_jifs) / HZ,
 			info->idle_stats.xmit_bytes,
diff -u --recursive --new-file v2.1.120/linux/drivers/char/lp.c linux/drivers/char/lp.c
--- v2.1.120/linux/drivers/char/lp.c	Wed Aug 26 11:37:37 1998
+++ linux/drivers/char/lp.c	Tue Sep  8 10:39:27 1998
@@ -13,7 +13,7 @@
  * lp_read (Status readback) support added by Carsten Gross,
  *                                             carsten@sol.wohnheim.uni-ulm.de
  * Support for parport by Philip Blundell <Philip.Blundell@pobox.com>
- * Parport sharing hacking by Andrea Arcangeli <arcangeli@mbox.queen.it>
+ * Parport sharing hacking by Andrea Arcangeli
  * Fixed kernel_(to/from)_user memory copy to check for errors
  * 				by Riccardo Facchetti <fizban@tin.it>
  * Interrupt handling workaround for printers with buggy handshake
diff -u --recursive --new-file v2.1.120/linux/drivers/char/pc110pad.c linux/drivers/char/pc110pad.c
--- v2.1.120/linux/drivers/char/pc110pad.c	Wed Aug 26 11:37:37 1998
+++ linux/drivers/char/pc110pad.c	Sat Sep  5 17:01:45 1998
@@ -18,7 +18,6 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/busmouse.h>
 #include <linux/signal.h>
 #include <linux/errno.h>
 #include <linux/mm.h>
diff -u --recursive --new-file v2.1.120/linux/drivers/char/pc_keyb.c linux/drivers/char/pc_keyb.c
--- v2.1.120/linux/drivers/char/pc_keyb.c	Sat Sep  5 16:46:40 1998
+++ linux/drivers/char/pc_keyb.c	Sun Sep  6 13:39:09 1998
@@ -43,194 +43,6 @@
 	"\r\000/";					/* 0x60 - 0x6f */
 #endif
 
-/*
- * In case we run on a non-x86 hardware we need to initialize both the keyboard
- * controller and the keyboard. On a x86, the BIOS will already have initialized
- * them.
- */
-
-/*
- * Some x86 BIOSes do not correctly initialize the keyboard, so the
- * "kbd-reset" command line options can be given to force a reset.
- * [Ranger]
- */
-#ifdef __i386__
- int kbd_startup_reset __initdata = 0;
-#else
- int kbd_startup_reset __initdata = 1;
-#endif
-
-__initfunc(static int kbd_wait_for_input(void))
-{
-	long timeout = KBD_INIT_TIMEOUT;
-	int retval = -1;
-
-	goto in_loop;
-	for (;;) {
-		unsigned char status, data;
-		if (--timeout < 0)
-			break;
-		mdelay(1);
-in_loop:
-		status = inb(KBD_STATUS_REG);
-
-		/*
-		 * Wait for input data to become available.  This bit will
-		 * then be cleared by the following read of the DATA
-		 * register.
-		 */
-		if (!(status & KBD_STAT_OBF))
-			continue;
-
-		data = inb(KBD_DATA_REG);
-
-		/*
-		 * Check to see if a timeout error has occurred.  This means
-		 * that transmission was started but did not complete in the
-		 * normal time cycle.  PERR is set when a parity error occurred
-		 * in the last transmission.
-		 */
-		if (status & (KBD_STAT_GTO | KBD_STAT_PERR))
-			continue;
-
-		retval = data;
-		break;
-	}
-	return retval;
-}
-
-__initfunc(static void kbd_write(int address, int data))
-{
-	int status;
-
-	do {
-		status = inb(KBD_STATUS_REG);
-	} while (status & KBD_STAT_IBF);
-	outb(data, address);
-}
-
-__initfunc(static char *initialize_kbd2(void))
-{
-	int status;
-
-	/* Flush any pending input. */
-
-	while (kbd_wait_for_input() != -1)
-		;
-
-	/*
-	 * Test the keyboard interface.
-	 * This seems to be the only way to get it going.
-	 * If the test is successful a x55 is placed in the input buffer.
-	 */
-
-	kbd_write(KBD_CNTL_REG, KBD_CCMD_SELF_TEST);
-	if (kbd_wait_for_input() != 0x55)
-		return "Keyboard failed self test";
-
-	/*
-	 * Perform a keyboard interface test.  This causes the controller
-	 * to test the keyboard clock and data lines.  The results of the
-	 * test are placed in the input buffer.
-	 */
-
-	kbd_write(KBD_CNTL_REG, KBD_CCMD_KBD_TEST);
-	if (kbd_wait_for_input() != 0x00)
-		return "Keyboard interface failed self test";
-
-	/* Enable the keyboard by allowing the keyboard clock to run. */
-
-	kbd_write(KBD_CNTL_REG, KBD_CCMD_KBD_ENABLE);
-
-	/*
-	 * Reset keyboard. If the read times out
-	 * then the assumption is that no keyboard is
-	 * plugged into the machine.
-	 * This defaults the keyboard to scan-code set 2.
-	 *
-	 * Set up to try again if the keyboard asks for RESEND.
-	 */
-
-	do {
-		kbd_write(KBD_DATA_REG, KBD_CMD_RESET);
-		status = kbd_wait_for_input();
-		if (status == KBD_REPLY_ACK)
-			break;
-		else if (status != KBD_REPLY_RESEND)
-			return "Keyboard reset failed, no ACK";
-	} while (1);
-
-	if (kbd_wait_for_input() != KBD_REPLY_POR)
-		return "Keyboard reset failed, no POR";
-
-	/*
-	 * Set keyboard controller mode. During this, the keyboard should be
-	 * in the disabled state.
-	 *
-	 * Set up to try again if the keyboard asks for RESEND.
-	 */
-
-	do {
-		kbd_write(KBD_DATA_REG, KBD_CMD_DISABLE);
-		status = kbd_wait_for_input();
-		if (status == KBD_REPLY_ACK)
-			break;
-		else if (status != KBD_REPLY_RESEND)
-			return "Disable keyboard: no ACK";
-	} while (1);
-
-	kbd_write(KBD_CNTL_REG, KBD_CCMD_WRITE_MODE);
-	kbd_write(KBD_DATA_REG, KBD_MODE_KBD_INT
-			      | KBD_MODE_SYS
-			      | KBD_MODE_DISABLE_MOUSE
-			      | KBD_MODE_KCC);
-
-	/* ibm powerpc portables need this to use scan-code set 1 -- Cort */
-	kbd_write(KBD_CNTL_REG, KBD_CCMD_READ_MODE);
-	if (!(kbd_wait_for_input() & KBD_MODE_KCC)) {
-		/*
-		 * If the controller does not support conversion,
-		 * Set the keyboard to scan-code set 1.
-		 */
-		kbd_write(KBD_DATA_REG, 0xF0);
-		kbd_wait_for_input();
-		kbd_write(KBD_DATA_REG, 0x01);
-		kbd_wait_for_input();
-	}
-
-	
-	kbd_write(KBD_DATA_REG, KBD_CMD_ENABLE);
-	if (kbd_wait_for_input() != KBD_REPLY_ACK)
-		return "Enable keyboard: no ACK";
-
-	/*
-	 * Finally, set the typematic rate to maximum.
-	 */
-
-	kbd_write(KBD_DATA_REG, KBD_CMD_SET_RATE);
-	if (kbd_wait_for_input() != KBD_REPLY_ACK)
-		return "Set rate: no ACK";
-	kbd_write(KBD_DATA_REG, 0x00);
-	if (kbd_wait_for_input() != KBD_REPLY_ACK)
-		return "Set rate: no ACK";
-
-	return NULL;
-}
-
-__initfunc(static void initialize_kbd(void))
-{
-	char *msg;
-
-	disable_irq(KEYBOARD_IRQ);
-	msg = initialize_kbd2();
-	enable_irq(KEYBOARD_IRQ);
-
-	if (msg)
-		printk(KERN_WARNING "initialize_kbd: %s\n", msg);
-}
-
-
-
 unsigned char pckbd_read_mask = KBD_STAT_OBF; /* Modified by psaux.c */
 
 /* used only by send_data - set by keyboard_interrupt */
@@ -625,15 +437,189 @@
 	    send_data(KBD_CMD_ENABLE);	/* re-enable kbd if any errors */
 }
 
-__initfunc(void pckbd_init_hw(void))
-{
-	request_irq(KEYBOARD_IRQ, keyboard_interrupt, 0, "keyboard", NULL);
-	request_region(0x60, 16, "keyboard");
-	if (kbd_startup_reset) initialize_kbd();
-}
+/*
+ * In case we run on a non-x86 hardware we need to initialize both the
+ * keyboard controller and the keyboard.  On a x86, the BIOS will
+ * already have initialized them.
+ *
+ * Some x86 BIOSes do not correctly initialize the keyboard, so the
+ * "kbd-reset" command line options can be given to force a reset.
+ * [Ranger]
+ */
+#ifdef __i386__
+ int kbd_startup_reset __initdata = 0;
+#else
+ int kbd_startup_reset __initdata = 1;
+#endif
 
 /* for "kbd-reset" cmdline param */
-__initfunc(void kbd_reset_setup(char *str, int *ints))
+void __init kbd_reset_setup(char *str, int *ints)
 {
 	kbd_startup_reset = 1;
+}
+
+#define KBD_NO_DATA	(-1)	/* No data */
+#define KBD_BAD_DATA	(-2)	/* Parity or other error */
+
+static int __init kbd_read_input(void)
+{
+	int retval = KBD_NO_DATA;
+	unsigned char status;
+
+	status = inb(KBD_STATUS_REG);
+	if (status & KBD_STAT_OBF) {
+		unsigned char data = inb(KBD_DATA_REG);
+
+		retval = data;
+		if (status & (KBD_STAT_GTO | KBD_STAT_PERR))
+			retval = KBD_BAD_DATA;
+	}
+	return retval;
+}
+
+static void __init kbd_clear_input(void)
+{
+	int maxread = 100;	/* Random number */
+
+	do {
+		if (kbd_read_input() == KBD_NO_DATA)
+			break;
+	} while (--maxread);
+}
+
+static int __init kbd_wait_for_input(void)
+{
+	long timeout = KBD_INIT_TIMEOUT;
+
+	do {
+		int retval = kbd_read_input();
+		if (retval >= 0)
+			return retval;
+		mdelay(1);
+	} while (--timeout);
+	return -1;
+}
+
+static void __init kbd_write(int address, int data)
+{
+	int status;
+
+	do {
+		status = inb(KBD_STATUS_REG);
+	} while (status & KBD_STAT_IBF);
+	outb(data, address);
+}
+
+static char * __init initialize_kbd(void)
+{
+	int status;
+
+	/*
+	 * Test the keyboard interface.
+	 * This seems to be the only way to get it going.
+	 * If the test is successful a x55 is placed in the input buffer.
+	 */
+	kbd_write(KBD_CNTL_REG, KBD_CCMD_SELF_TEST);
+	if (kbd_wait_for_input() != 0x55)
+		return "Keyboard failed self test";
+
+	/*
+	 * Perform a keyboard interface test.  This causes the controller
+	 * to test the keyboard clock and data lines.  The results of the
+	 * test are placed in the input buffer.
+	 */
+	kbd_write(KBD_CNTL_REG, KBD_CCMD_KBD_TEST);
+	if (kbd_wait_for_input() != 0x00)
+		return "Keyboard interface failed self test";
+
+	/*
+	 * Enable the keyboard by allowing the keyboard clock to run.
+	 */
+	kbd_write(KBD_CNTL_REG, KBD_CCMD_KBD_ENABLE);
+
+	/*
+	 * Reset keyboard. If the read times out
+	 * then the assumption is that no keyboard is
+	 * plugged into the machine.
+	 * This defaults the keyboard to scan-code set 2.
+	 *
+	 * Set up to try again if the keyboard asks for RESEND.
+	 */
+	do {
+		kbd_write(KBD_DATA_REG, KBD_CMD_RESET);
+		status = kbd_wait_for_input();
+		if (status == KBD_REPLY_ACK)
+			break;
+		if (status != KBD_REPLY_RESEND)
+			return "Keyboard reset failed, no ACK";
+	} while (1);
+
+	if (kbd_wait_for_input() != KBD_REPLY_POR)
+		return "Keyboard reset failed, no POR";
+
+	/*
+	 * Set keyboard controller mode. During this, the keyboard should be
+	 * in the disabled state.
+	 *
+	 * Set up to try again if the keyboard asks for RESEND.
+	 */
+	do {
+		kbd_write(KBD_DATA_REG, KBD_CMD_DISABLE);
+		status = kbd_wait_for_input();
+		if (status == KBD_REPLY_ACK)
+			break;
+		if (status != KBD_REPLY_RESEND)
+			return "Disable keyboard: no ACK";
+	} while (1);
+
+	kbd_write(KBD_CNTL_REG, KBD_CCMD_WRITE_MODE);
+	kbd_write(KBD_DATA_REG, KBD_MODE_KBD_INT
+			      | KBD_MODE_SYS
+			      | KBD_MODE_DISABLE_MOUSE
+			      | KBD_MODE_KCC);
+
+	/* ibm powerpc portables need this to use scan-code set 1 -- Cort */
+	kbd_write(KBD_CNTL_REG, KBD_CCMD_READ_MODE);
+	if (!(kbd_wait_for_input() & KBD_MODE_KCC)) {
+		/*
+		 * If the controller does not support conversion,
+		 * Set the keyboard to scan-code set 1.
+		 */
+		kbd_write(KBD_DATA_REG, 0xF0);
+		kbd_wait_for_input();
+		kbd_write(KBD_DATA_REG, 0x01);
+		kbd_wait_for_input();
+	}
+
+	
+	kbd_write(KBD_DATA_REG, KBD_CMD_ENABLE);
+	if (kbd_wait_for_input() != KBD_REPLY_ACK)
+		return "Enable keyboard: no ACK";
+
+	/*
+	 * Finally, set the typematic rate to maximum.
+	 */
+	kbd_write(KBD_DATA_REG, KBD_CMD_SET_RATE);
+	if (kbd_wait_for_input() != KBD_REPLY_ACK)
+		return "Set rate: no ACK";
+	kbd_write(KBD_DATA_REG, 0x00);
+	if (kbd_wait_for_input() != KBD_REPLY_ACK)
+		return "Set rate: no ACK";
+
+	return NULL;
+}
+
+void __init pckbd_init_hw(void)
+{
+	/* Flush any pending input. */
+	kbd_clear_input();
+
+	if (kbd_startup_reset) {
+		char *msg = initialize_kbd();
+		if (msg)
+			printk(KERN_WARNING "initialize_kbd: %s\n", msg);
+	}
+
+	request_irq(KEYBOARD_IRQ, keyboard_interrupt, 0, "keyboard", NULL);
+	request_region(0x60, 16, "keyboard");
 }
diff -u --recursive --new-file v2.1.120/linux/drivers/misc/parport_pc.c linux/drivers/misc/parport_pc.c
--- v2.1.120/linux/drivers/misc/parport_pc.c	Tue Jul 21 00:15:31 1998
+++ linux/drivers/misc/parport_pc.c	Tue Sep  8 10:39:27 1998
@@ -4,7 +4,7 @@
  *          Tim Waugh <tim@cyberelk.demon.co.uk>
  *	    Jose Renau <renau@acm.org>
  *          David Campbell <campbell@torque.net>
- *          Andrea Arcangeli <arcangeli@mbox.queen.it>
+ *          Andrea Arcangeli
  *
  * based on work by Grant Guenther <grant@torque.net> and Phil Blundell.
  */
diff -u --recursive --new-file v2.1.120/linux/drivers/misc/parport_procfs.c linux/drivers/misc/parport_procfs.c
--- v2.1.120/linux/drivers/misc/parport_procfs.c	Thu Aug  6 14:06:32 1998
+++ linux/drivers/misc/parport_procfs.c	Tue Sep  8 10:39:27 1998
@@ -3,7 +3,7 @@
  * Authors: David Campbell <campbell@torque.net>
  *          Tim Waugh <tim@cyberelk.demon.co.uk>
  *          Philip Blundell <philb@gnu.org>
- *          Andrea Arcangeli <arcangeli@mbox.queen.it>
+ *          Andrea Arcangeli
  *          Riccardo Facchetti <fizban@tin.it>
  *
  * based on work by Grant Guenther <grant@torque.net>
diff -u --recursive --new-file v2.1.120/linux/drivers/misc/parport_share.c linux/drivers/misc/parport_share.c
--- v2.1.120/linux/drivers/misc/parport_share.c	Tue Jul 21 00:15:31 1998
+++ linux/drivers/misc/parport_share.c	Tue Sep  8 10:39:27 1998
@@ -5,7 +5,7 @@
  *          Tim Waugh <tim@cyberelk.demon.co.uk>
  *          Jose Renau <renau@acm.org>
  *          Philip Blundell <philb@gnu.org>
- *	    Andrea Arcangeli <arcangeli@mbox.queen.it>
+ *	    Andrea Arcangeli
  *
  * based on work by Grant Guenther <grant@torque.net>
  *          and Philip Blundell
diff -u --recursive --new-file v2.1.120/linux/drivers/net/3c59x.c linux/drivers/net/3c59x.c
--- v2.1.120/linux/drivers/net/3c59x.c	Sat Sep  5 16:46:40 1998
+++ linux/drivers/net/3c59x.c	Tue Sep  8 23:33:19 1998
@@ -15,14 +15,14 @@
 */
 
 static char *version =
-"3c59x.c:v0.99F 8/7/98 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n";
+"3c59x.c:v0.99E 5/12/98 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n";
 
 /* "Knobs" that adjust features and parameters. */
 /* Set the copy breakpoint for the copy-only-tiny-frames scheme.
    Setting to > 1512 effectively disables this feature. */
-static const int rx_copybreak = 200;
+static const rx_copybreak = 200;
 /* Allow setting MTU to a larger size, bypassing the normal ethernet setup. */
-static const int mtu = 1500;
+static const mtu = 1500;
 /* Maximum events (Rx packets, etc.) to handle at each interrupt. */
 static int max_interrupt_work = 20;
 
@@ -37,6 +37,9 @@
    debugging. */
 static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0, rx_csumhits;
 
+/* Enable the automatic media selection code -- usually set. */
+#define AUTOMEDIA 1
+
 /* Allow the use of fragment bus master transfers instead of only
    programmed-I/O for Vortex cards.  Full-bus-master transfers are always
    enabled by default on Boomerang cards.  If VORTEX_BUS_MASTER is defined,
@@ -74,9 +77,7 @@
 #include <linux/malloc.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
-#if LINUX_VERSION_CODE < 0x20155  ||  defined(CARDBUS)
 #include <linux/bios32.h>
-#endif
 #include <linux/timer.h>
 #include <asm/irq.h>			/* For NR_IRQS only. */
 #include <asm/bitops.h>
@@ -104,6 +105,11 @@
 #define RUN_AT(x) (jiffies + (x))
 #define DEV_ALLOC_SKB(len) dev_alloc_skb(len)
 #endif
+#if LINUX_VERSION_CODE < 0x20159
+#define DEV_FREE_SKB(skb) dev_kfree_skb (skb, FREE_WRITE);
+#else  /* Grrr, unneeded incompatible change. */
+#define DEV_FREE_SKB(skb) dev_kfree_skb(skb);
+#endif
 
 #ifdef SA_SHIRQ
 #define FREE_IRQ(irqnum, dev) free_irq(irqnum, dev)
@@ -122,27 +128,9 @@
 #define udelay(microsec)	do { int _i = 4*microsec; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0)
 #endif
 
-#if LINUX_VERSION_CODE <= 0x20139
-#define	net_device_stats enet_statistics
-#define NETSTATS_VER2
-#endif
 #if LINUX_VERSION_CODE < 0x20138
 #define test_and_set_bit(val, addr) set_bit(val, addr)
-#define le32_to_cpu(val) (val)
-#define cpu_to_le32(val) (val)
 #endif
-#if LINUX_VERSION_CODE < 0x20155
-#define PCI_SUPPORT_VER1
-#else
-#define PCI_SUPPORT_VER2
-#endif
-#if LINUX_VERSION_CODE < 0x20159
-#define DEV_FREE_SKB(skb) dev_kfree_skb (skb, FREE_WRITE);
-#else  /* Grrr, unneeded incompatible change. */
-#define DEV_FREE_SKB(skb) dev_kfree_skb(skb);
-#endif
-
-
 #if defined(MODULE) && (LINUX_VERSION_CODE >= 0x20115)
 MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
 MODULE_DESCRIPTION("3Com 3c590/3c900 series Vortex/Boomerang driver");
@@ -153,7 +141,7 @@
 MODULE_PARM(max_interrupt_work, "i");
 MODULE_PARM(compaq_ioaddr, "i");
 MODULE_PARM(compaq_irq, "i");
-MODULE_PARM(compaq_device_id, "i");
+MODULE_PARM(compaq_prod_id, "i");
 #endif
 
 /* Operational parameter that usually are not changed. */
@@ -178,7 +166,7 @@
 /* Caution!  These entries must be consistent. */
 static const int product_ids[] = {
 	0x5900, 0x5920, 0x5970, 0x5950, 0x5951, 0x5952, 0x9000, 0x9001,
-	0x9050, 0x9051, 0x9055,	0x5057, 0x5175, 0 };
+	0x9050, 0x9051, 0x9055,	0x5057, 0 };
 static const char *product_names[] = {
 	"3c590 Vortex 10Mbps",
 	"3c592 EISA 10mbps Demon/Vortex",
@@ -192,7 +180,6 @@
 	"3c905 Boomerang 100baseT4",
 	"3c905B Cyclone 100baseTx",
 	"3c575",						/* Cardbus Boomerang */
-	"3CCFE575",						/* Cardbus ?Cyclone? */
 };
 
 /*
@@ -205,16 +192,17 @@
 versions of the FastEtherLink cards.  The supported product IDs are
   3c590, 3c592, 3c595, 3c597, 3c900, 3c905
 
-The related ISA 3c515 is supported with a separate driver, 3c515.c, included
-with the kernel source or available from
+The ISA 3c515 is supported with a seperate driver, 3c515.c, included with
+the kernel source or available from
     cesdis.gsfc.nasa.gov:/pub/linux/drivers/3c515.html
 
 II. Board-specific settings
 
 PCI bus devices are configured by the system at boot time, so no jumpers
 need to be set on the board.  The system BIOS should be set to assign the
-PCI INTA signal to an otherwise unused system IRQ line.  Note: The 1.2.*
-kernels did not support PCI interrupt sharing.
+PCI INTA signal to an otherwise unused system IRQ line.  While it's
+physically possible to shared PCI interrupt lines, the 1.2.0 kernel doesn't
+support it.
 
 III. Driver operation
 
@@ -222,10 +210,10 @@
 series.  The primary interface is two programmed-I/O FIFOs, with an
 alternate single-contiguous-region bus-master transfer (see next).
 
-The 3c900 "Boomerang" series uses a full-bus-master interface with separate
+The 3c900 "Boomerang" series uses a full-bus-master interface with seperate
 lists of transmit and receive descriptors, similar to the AMD LANCE/PCnet,
 DEC Tulip and Intel Speedo3.  The first chip version retains a compatible
-programmed-I/O interface that has been removed in 'B' and subsequent board
+programmed-I/O interface that will be removed in the 'B' and subsequent
 revisions.
 
 One extension that is advertised in a very large font is that the adapters
@@ -243,7 +231,7 @@
 single frame.
 
 With full-bus-master support, this driver uses a "RX_COPYBREAK" scheme.
-Rather than a fixed intermediate receive buffer, this scheme allocates
+Tather than a fixed intermediate receive buffer, this scheme allocates
 full-sized skbuffs as receive buffers.  The value RX_COPYBREAK is used as
 the copying breakpoint: it is chosen to trade-off the memory wasted by
 passing the full-sized skbuff to the queue layer for all frames vs. the
@@ -416,7 +404,7 @@
 	struct sk_buff* tx_skbuff[TX_RING_SIZE];
 	unsigned int cur_rx, cur_tx;		/* The next free ring entry */
 	unsigned int dirty_rx, dirty_tx;	/* The ring entries to be free()ed. */
-	struct net_device_stats stats;
+	struct enet_statistics stats;
 	struct sk_buff *tx_skb;		/* Packet being eaten by bus master ctrl.  */
 
 	/* PCI configuration space information. */
@@ -424,16 +412,17 @@
 	u16 pci_device_id;
 
 	/* The remainder are related to chip state, mostly media selection. */
-	unsigned long in_interrupt;
+	int in_interrupt;
 	struct timer_list timer;	/* Media selection timer. */
 	int options;				/* User-settable misc. driver options. */
-	unsigned int media_override:3, 			/* Passed-in media type. */
-		default_media:4,				/* Read from the EEPROM/Wn3_Config. */
-		full_duplex:1, force_fd:1, autoselect:1,
-		bus_master:1,				/* Vortex can only do a fragment bus-m. */
-		full_bus_master_tx:1, full_bus_master_rx:2, /* Boomerang  */
-		hw_csums:1,				/* Has hardware checksums. */
-		tx_full:1;
+	unsigned int
+	  media_override:3, 			/* Passed-in media type. */
+	  default_media:3,				/* Read from the EEPROM/Wn3_Config. */
+	  full_duplex:1, autoselect:1,
+	  bus_master:1,				/* Vortex can only do a fragment bus-m. */
+	  full_bus_master_tx:1, full_bus_master_rx:2, /* Boomerang  */
+	  hw_csums:1,				/* Has hardware checksums. */
+      tx_full:1;
 	u16 status_enable;
 	u16 available_media;				/* From Wn3_Options. */
 	u16 capabilities, info1, info2;		/* Various, from EEPROM. */
@@ -470,15 +459,15 @@
 };
 
 static int vortex_scan(struct device *dev);
-static struct device *vortex_found_device(struct device *dev, long ioaddr,
+static struct device *vortex_found_device(struct device *dev, int ioaddr,
 										  int irq, int device_id,
 										  int options, int card_idx);
 static int vortex_probe1(struct device *dev);
 static int vortex_open(struct device *dev);
-static void mdio_sync(long ioaddr, int bits);
-static int mdio_read(long ioaddr, int phy_id, int location);
+static void mdio_sync(int ioaddr, int bits);
+static int mdio_read(int ioaddr, int phy_id, int location);
 #ifdef HAVE_PRIVATE_IOCTL
-static void mdio_write(long ioaddr, int phy_id, int location, int value);
+static void mdio_write(int ioaddr, int phy_id, int location, int value);
 #endif
 static void vortex_timer(unsigned long arg);
 static int vortex_start_xmit(struct sk_buff *skb, struct device *dev);
@@ -487,8 +476,8 @@
 static int boomerang_rx(struct device *dev);
 static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs);
 static int vortex_close(struct device *dev);
-static void update_stats(long ioaddr, struct device *dev);
-static struct net_device_stats *vortex_get_stats(struct device *dev);
+static void update_stats(int addr, struct device *dev);
+static struct enet_statistics *vortex_get_stats(struct device *dev);
 static void set_rx_mode(struct device *dev);
 #ifdef HAVE_PRIVATE_IOCTL
 static int vortex_ioctl(struct device *dev, struct ifreq *rq, int cmd);
@@ -671,24 +660,6 @@
 			if (vendor != TCOM_VENDOR_ID)
 				continue;
 
-			/* Power-up the card. */
-			pcibios_read_config_word(pci_bus, pci_device_fn,
-										 0xe0, &pci_command);
-			if (pci_command & 0x3) {
-				/* Save the ioaddr and IRQ info! */
-				printk(KERN_INFO "  A 3Com network adapter is powered down!"
-					   "  Setting the power state %4.4x->%4.4x.\n",
-					   pci_command, pci_command & ~3);
-				pcibios_write_config_word(pci_bus, pci_device_fn,
-										  0xe0, pci_command & ~3);
-				printk(KERN_INFO "  Setting the IRQ to %d, IOADDR to %#lx.\n",
-					   irq, ioaddr);
-				pcibios_write_config_byte(pci_bus, pci_device_fn,
-										 PCI_INTERRUPT_LINE, irq);
-				pcibios_write_config_dword(pci_bus, pci_device_fn,
-										  PCI_BASE_ADDRESS_0, ioaddr);
-			}
-
 			if (ioaddr == 0) {
 				printk(KERN_WARNING "  A 3Com network adapter has been found, "
 					   "however it has not been assigned an I/O address.\n"
@@ -744,7 +715,7 @@
 
 	/* Now check all slots of the EISA bus. */
 	if (EISA_bus) {
-		static long ioaddr = 0x1000;
+		static int ioaddr = 0x1000;
 		for ( ; ioaddr < 0x9000; ioaddr += 0x1000) {
 			int device_id;
 			if (check_region(ioaddr, VORTEX_TOTAL_SIZE))
@@ -782,7 +753,7 @@
 }
 
 static struct device *
-vortex_found_device(struct device *dev, long ioaddr, int irq,
+vortex_found_device(struct device *dev, int ioaddr, int irq,
 					int device_id, int option, int card_idx)
 {
 	struct vortex_private *vp;
@@ -868,7 +839,6 @@
 		vp->full_duplex = 0;
 		vp->bus_master = 0;
 	}
-	vp->force_fd = vp->full_duplex;
 
 	vortex_probe1(dev);
 #endif /* MODULE */
@@ -877,13 +847,13 @@
 
 static int vortex_probe1(struct device *dev)
 {
-	long ioaddr = dev->base_addr;
+	int ioaddr = dev->base_addr;
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
 	u16 *ether_addr = (u16 *)dev->dev_addr;
 	unsigned int eeprom[0x40], checksum = 0;		/* EEPROM contents */
 	int i;
 
-	printk(KERN_INFO "%s: 3Com %s at %#3lx,",
+	printk(KERN_INFO "%s: 3Com %s at %#3x,",
 		   dev->name, vp->product_name, ioaddr);
 
 	/* Read the station address from the EEPROM. */
@@ -918,15 +888,11 @@
 		ether_addr[i] = htons(eeprom[i + 10]);
 	for (i = 0; i < 6; i++)
 		printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]);
-#ifdef __sparc__
-	printk(", IRQ %s\n", __irq_itoa(dev->irq));
-#else
 	printk(", IRQ %d\n", dev->irq);
 	/* Tell them about an invalid IRQ. */
 	if (vortex_debug && (dev->irq <= 0 || dev->irq >= NR_IRQS))
 		printk(KERN_WARNING " *** Warning: IRQ %d is unlikely to work! ***\n",
 			   dev->irq);
-#endif
 
 	/* Extract our information from the EEPROM data. */
 	vp->info1 = eeprom[13];
@@ -952,7 +918,7 @@
 			   config.u.ram_width ? "word" : "byte",
 			   ram_split[config.u.ram_split],
 			   config.u.autoselect ? "autoselect/" : "",
-			   config.u.xcvr > XCVR_ExtMII ? "<invalid transceiver>" :
+			   config.u.xcvr ? "NWay Autonegotiation" :
 			   media_tbl[config.u.xcvr].name);
 		vp->default_media = config.u.xcvr;
 		vp->autoselect = config.u.autoselect;
@@ -965,7 +931,7 @@
 	} else
 		dev->if_port = vp->default_media;
 
-	if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) {
+	if (dev->if_port == XCVR_MII) {
 		int phy, phy_idx = 0;
 		EL3WINDOW(4);
 		for (phy = 0; phy < 32 && phy_idx < sizeof(vp->phys); phy++) {
@@ -1025,7 +991,7 @@
 static int
 vortex_open(struct device *dev)
 {
-	long ioaddr = dev->base_addr;
+	int ioaddr = dev->base_addr;
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
 	union wn3_config config;
 	int i;
@@ -1045,8 +1011,6 @@
 		dev->if_port = XCVR_100baseTx;
 		while (! (vp->available_media & media_tbl[dev->if_port].mask))
 			dev->if_port = media_tbl[dev->if_port].next;
-		if (vp->phys[0])
-			dev->if_port = XCVR_NWAY;
 
 		if (vortex_debug > 1)
 			printk(KERN_DEBUG "%s: Initial media type %s.\n",
@@ -1055,16 +1019,15 @@
 		init_timer(&vp->timer);
 		vp->timer.expires = RUN_AT(media_tbl[dev->if_port].wait);
 		vp->timer.data = (unsigned long)dev;
-		vp->timer.function = &vortex_timer;		/* timer handler */
+		vp->timer.function = &vortex_timer;    /* timer handler */
 		add_timer(&vp->timer);
 	} else
 		dev->if_port = vp->default_media;
 
-	vp->full_duplex = vp->force_fd;
 	config.u.xcvr = dev->if_port;
 	outl(config.i, ioaddr + Wn3_Config);
 
-	if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) {
+	if (dev->if_port == XCVR_MII) {
 		int mii_reg1, mii_reg5;
 		EL3WINDOW(4);
 		/* Read BMSR (reg1) only to clear old status. */
@@ -1164,9 +1127,9 @@
 			printk(KERN_DEBUG "%s:  Filling in the Rx ring.\n", dev->name);
 		for (i = 0; i < RX_RING_SIZE; i++) {
 			struct sk_buff *skb;
-			vp->rx_ring[i].next = cpu_to_le32(virt_to_bus(&vp->rx_ring[i+1]));
+			vp->rx_ring[i].next = virt_to_bus(&vp->rx_ring[i+1]);
 			vp->rx_ring[i].status = 0;	/* Clear complete bit. */
-			vp->rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ | LAST_FRAG);
+			vp->rx_ring[i].length = PKT_BUF_SZ | LAST_FRAG;
 			skb = DEV_ALLOC_SKB(PKT_BUF_SZ);
 			vp->rx_skbuff[i] = skb;
 			if (skb == NULL)
@@ -1174,13 +1137,12 @@
 			skb->dev = dev;			/* Mark as being used by this device. */
 #if LINUX_VERSION_CODE >= 0x10300
 			skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
-			vp->rx_ring[i].addr = cpu_to_le32(virt_to_bus(skb->tail));
+			vp->rx_ring[i].addr = virt_to_bus(skb->tail);
 #else
 			vp->rx_ring[i].addr = virt_to_bus(skb->data);
 #endif
 		}
-		/* Wrap the ring. */
-		vp->rx_ring[i-1].next = cpu_to_le32(virt_to_bus(&vp->rx_ring[0]));
+		vp->rx_ring[i-1].next = virt_to_bus(&vp->rx_ring[0]); /* Wrap the ring. */
 		outl(virt_to_bus(&vp->rx_ring[0]), ioaddr + UpListPtr);
 	}
 	if (vp->full_bus_master_tx) { 		/* Boomerang bus master Tx. */
@@ -1224,25 +1186,24 @@
 
 static void vortex_timer(unsigned long data)
 {
+#ifdef AUTOMEDIA
 	struct device *dev = (struct device *)data;
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
-	long ioaddr = dev->base_addr;
+	int ioaddr = dev->base_addr;
 	unsigned long flags;
-	int next_tick = 0;
 	int ok = 0;
-	int media_status, old_window;
 
 	if (vortex_debug > 1)
 		printk(KERN_DEBUG "%s: Media selection timer tick happened, %s.\n",
 			   dev->name, media_tbl[dev->if_port].name);
 
-	save_flags(flags);
-	cli();
-	old_window = inw(ioaddr + EL3_CMD) >> 13;
-	EL3WINDOW(4);
-	media_status = inw(ioaddr + Wn4_Media);
-	switch (dev->if_port) {
-	case XCVR_10baseT:  case XCVR_100baseTx:  case XCVR_100baseFx:
+	save_flags(flags);	cli(); {
+	  int old_window = inw(ioaddr + EL3_CMD) >> 13;
+	  int media_status;
+	  EL3WINDOW(4);
+	  media_status = inw(ioaddr + Wn4_Media);
+	  switch (dev->if_port) {
+	  case XCVR_10baseT:  case XCVR_100baseTx:  case XCVR_100baseFx:
 		if (media_status & Media_LnkBeat) {
 		  ok = 1;
 		  if (vortex_debug > 1)
@@ -1251,27 +1212,18 @@
 		} else if (vortex_debug > 1)
 		  printk(KERN_DEBUG "%s: Media %s is has no link beat, %x.\n",
 				   dev->name, media_tbl[dev->if_port].name, media_status);
+
 		break;
-	  case XCVR_MII: case XCVR_NWAY:
-		  if (mdio_read(ioaddr, vp->phys[0], 1) & 0x0004) {
+	  case XCVR_MII:
+		  {
+			  int mii_reg1 = mdio_read(ioaddr, vp->phys[0], 1);
 			  int mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5);
-			  ok = 1;
-			  if (! vp->force_fd  &&  mii_reg5 != 0xffff) {
-				  int duplex = (mii_reg5&0x0100) ||
-					  (mii_reg5 & 0x01C0) == 0x0040;
-				  if (vp->full_duplex != duplex) {
-					  vp->full_duplex = duplex;
-					  printk(KERN_INFO "%s: Setting %s-duplex based on MII "
-							 "#%d link partner capability of %4.4x.\n",
-							 dev->name, vp->full_duplex ? "full" : "half",
-							 vp->phys[0], mii_reg5);
-					  /* Set the full-duplex bit. */
-					  outb((vp->full_duplex ? 0x20 : 0) |
-						   (dev->mtu > 1500 ? 0x40 : 0),
-						   ioaddr + Wn3_MAC_Ctrl);
-				  }
-				  next_tick = 60*HZ;
-			  }
+			  if (vortex_debug > 1)
+				  printk(KERN_DEBUG "%s: MII #%d status register is %4.4x, "
+						 "link partner capability %4.4x.\n",
+						 dev->name, vp->phys[0], mii_reg1, mii_reg5);
+			  if (mii_reg1 & 0x0004)
+				  ok = 1;
 			  break;
 		  }
 	  default:					/* Other media types handled by Tx timeouts. */
@@ -1279,8 +1231,8 @@
 		  printk(KERN_DEBUG "%s: Media %s is has no indication, %x.\n",
 				 dev->name, media_tbl[dev->if_port].name, media_status);
 		ok = 1;
-	}
-	if ( ! ok) {
+	  }
+	  if ( ! ok) {
 		union wn3_config config;
 
 		do {
@@ -1297,7 +1249,8 @@
 			printk(KERN_DEBUG "%s: Media selection failed, now trying "
 				   "%s port.\n",
 				   dev->name, media_tbl[dev->if_port].name);
-		  next_tick = RUN_AT(media_tbl[dev->if_port].wait);
+		  vp->timer.expires = RUN_AT(media_tbl[dev->if_port].wait);
+		  add_timer(&vp->timer);
 		}
 		outw((media_status & ~(Media_10TP|Media_SQE)) |
 			 media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media);
@@ -1309,25 +1262,21 @@
 
 		outw(dev->if_port == XCVR_10base2 ? StartCoax : StopCoax,
 			 ioaddr + EL3_CMD);
-	}
-	EL3WINDOW(old_window);
-	restore_flags(flags);
-
+	  }
+	  EL3WINDOW(old_window);
+	}   restore_flags(flags);
 	if (vortex_debug > 1)
 	  printk(KERN_DEBUG "%s: Media selection timer finished, %s.\n",
 			 dev->name, media_tbl[dev->if_port].name);
 
-	if (next_tick) {
-		vp->timer.expires = RUN_AT(next_tick);
-		add_timer(&vp->timer);
-	}
+#endif /* AUTOMEDIA*/
 	return;
 }
 
 static void vortex_tx_timeout(struct device *dev)
 {
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
-	long ioaddr = dev->base_addr;
+	int ioaddr = dev->base_addr;
 	int j;
 
 	printk(KERN_ERR "%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
@@ -1360,8 +1309,8 @@
 		for (i = 0; i < TX_RING_SIZE; i++) {
 			printk(KERN_DEBUG "  %d: @%p  length %8.8x status %8.8x\n", i,
 				   &vp->tx_ring[i],
-				   le32_to_cpu(vp->tx_ring[i].length),
-				   le32_to_cpu(vp->tx_ring[i].status));
+				   vp->tx_ring[i].length,
+				   vp->tx_ring[i].status);
 		}
 	}
 #endif
@@ -1391,14 +1340,14 @@
 }
 
 /*
- * Handle uncommon interrupt sources.  This is a separate routine to minimize
+ * Handle uncommon interrupt sources.  This is a seperate routine to minimize
  * the cache impact.
  */
 static void
 vortex_error(struct device *dev, int status)
 {
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
-	long ioaddr = dev->base_addr;
+	int ioaddr = dev->base_addr;
 	int do_tx_reset = 0;
 	int i;
 
@@ -1485,7 +1434,7 @@
 vortex_start_xmit(struct sk_buff *skb, struct device *dev)
 {
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
-	long ioaddr = dev->base_addr;
+	int ioaddr = dev->base_addr;
 
 	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
 		if (jiffies - dev->trans_start >= TX_TIMEOUT)
@@ -1557,7 +1506,7 @@
 boomerang_start_xmit(struct sk_buff *skb, struct device *dev)
 {
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
-	long ioaddr = dev->base_addr;
+	int ioaddr = dev->base_addr;
 
 	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
 		if (jiffies - dev->trans_start >= TX_TIMEOUT)
@@ -1579,13 +1528,13 @@
 				printk(KERN_WARNING "%s: Tx Ring full, refusing to send buffer.\n",
 					   dev->name);
 			return 1;
-		}
+		} 
 		/* end change 06/25/97 M. Sievers */	
 		vp->tx_skbuff[entry] = skb;
 		vp->tx_ring[entry].next = 0;
-		vp->tx_ring[entry].addr = cpu_to_le32(virt_to_bus(skb->data));
-		vp->tx_ring[entry].length = cpu_to_le32(skb->len | LAST_FRAG);
-		vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded);
+		vp->tx_ring[entry].addr = virt_to_bus(skb->data);
+		vp->tx_ring[entry].length = skb->len | LAST_FRAG;
+		vp->tx_ring[entry].status = skb->len | TxIntrUploaded;
 
 		save_flags(flags);
 		cli();
@@ -1594,7 +1543,7 @@
 		for (i = 600; i >= 0 ; i--)
 			if ( (inw(ioaddr + EL3_STATUS) & CmdInProgress) == 0)
 				break;
-		prev_entry->next = cpu_to_le32(virt_to_bus(&vp->tx_ring[entry]));
+		prev_entry->next = virt_to_bus(&vp->tx_ring[entry]);
 		if (inl(ioaddr + DownListPtr) == 0) {
 			outl(virt_to_bus(&vp->tx_ring[entry]), ioaddr + DownListPtr);
 			queued_packet++;
@@ -1606,7 +1555,7 @@
 		if (vp->cur_tx - vp->dirty_tx > TX_RING_SIZE - 1)
 			vp->tx_full = 1;
 		else {					/* Clear previous interrupt enable. */
-			prev_entry->status &= cpu_to_le32(~TxIntrUploaded);
+			prev_entry->status &= ~TxIntrUploaded;
 			clear_bit(0, (void*)&dev->tbusy);
 		}
 		dev->trans_start = jiffies;
@@ -1624,8 +1573,8 @@
 	struct device *dev = (struct device *)(irq2dev_map[irq]);
 #endif
 	struct vortex_private *vp;
-	long ioaddr;
-	int latency, status;
+	int ioaddr, status;
+	int latency;
 	int work_done = max_interrupt_work;
 
 	vp = (struct vortex_private *)dev->priv;
@@ -1637,6 +1586,7 @@
 	dev->interrupt = 1;
 	ioaddr = dev->base_addr;
 	latency = inb(ioaddr + Timer);
+
 	status = inw(ioaddr + EL3_STATUS);
 
 	if (vortex_debug > 4)
@@ -1731,7 +1681,7 @@
 vortex_rx(struct device *dev)
 {
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
-	long ioaddr = dev->base_addr;
+	int ioaddr = dev->base_addr;
 	int i;
 	short rx_status;
 
@@ -1801,7 +1751,7 @@
 {
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
 	int entry = vp->cur_rx % RX_RING_SIZE;
-	long ioaddr = dev->base_addr;
+	int ioaddr = dev->base_addr;
 	int rx_status;
 	int rx_work_limit = vp->dirty_rx + RX_RING_SIZE - vp->cur_rx;
 
@@ -1809,7 +1759,8 @@
 		printk(KERN_DEBUG "  In boomerang_rx(), status %4.4x, rx_status "
 			   "%4.4x.\n",
 			   inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus));
-	while ((rx_status = le32_to_cpu(vp->rx_ring[entry].status)) & RxDComplete) {
+	while ((--rx_work_limit >= 0) &&
+			((rx_status = vp->rx_ring[entry].status) & RxDComplete)) {
 		if (rx_status & RxDError) { /* Error, update stats. */
 			unsigned char rx_error = rx_status >> 16;
 			if (vortex_debug > 2)
@@ -1838,18 +1789,21 @@
 				skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
 				/* 'skb_put()' points to the start of sk_buff data area. */
 				memcpy(skb_put(skb, pkt_len),
-					   bus_to_virt(le32_to_cpu(vp->rx_ring[entry].addr)),
+					   bus_to_virt(vp->rx_ring[entry].addr),
 					   pkt_len);
 #else
-				memcpy(skb->data, bus_to_virt(vp->rx_ring[entry].addr),
-					   pkt_len);
+				memcpy(skb->data, bus_to_virt(vp->rx_ring[entry].addr), pkt_len);
 				skb->len = pkt_len;
 #endif
 				rx_copy++;
-			} else {
+			} else{
 				void *temp;
 				/* Pass up the skbuff already on the Rx ring. */
 				skb = vp->rx_skbuff[entry];
+				if (skb == NULL) {
+					printk(KERN_WARNING "%s: in boomerang_rx -- attempt to use NULL skb caught\n", dev->name);
+					break;
+				}
 				vp->rx_skbuff[entry] = NULL;
 #if LINUX_VERSION_CODE >= 0x10300
 				temp = skb_put(skb, pkt_len);
@@ -1857,11 +1811,10 @@
 				temp = skb->data;
 #endif
 				/* Remove this checking code for final release. */
-				if (bus_to_virt(le32_to_cpu(vp->rx_ring[entry].addr)) != temp)
+				if (bus_to_virt(vp->rx_ring[entry].addr) != temp)
 					printk(KERN_ERR "%s: Warning -- the skbuff addresses do not match"
 						   " in boomerang_rx: %p vs. %p.\n", dev->name,
-						   bus_to_virt(le32_to_cpu(vp->rx_ring[entry].addr)),
-						   temp);
+						   bus_to_virt(vp->rx_ring[entry].addr), temp);
 				rx_nocopy++;
 			}
 #if LINUX_VERSION_CODE > 0x10300
@@ -1883,8 +1836,6 @@
 			vp->stats.rx_packets++;
 		}
 		entry = (++vp->cur_rx) % RX_RING_SIZE;
-		if (--rx_work_limit < 0)
-			break;
 	}
 	/* Refill the Rx ring buffers. */
 	for (; vp->dirty_rx < vp->cur_rx; vp->dirty_rx++) {
@@ -1892,12 +1843,14 @@
 		entry = vp->dirty_rx % RX_RING_SIZE;
 		if (vp->rx_skbuff[entry] == NULL) {
 			skb = DEV_ALLOC_SKB(PKT_BUF_SZ);
-			if (skb == NULL)
+			if (skb == NULL) {
+				printk(KERN_DEBUG "%s: in boomerang_rx -- could not allocate skbuff\n", dev->name);
 				break;			/* Bad news!  */
+			}
 			skb->dev = dev;			/* Mark as being used by this device. */
 #if LINUX_VERSION_CODE > 0x10300
 			skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
-			vp->rx_ring[entry].addr = cpu_to_le32(virt_to_bus(skb->tail));
+			vp->rx_ring[entry].addr = virt_to_bus(skb->tail);
 #else
 			vp->rx_ring[entry].addr = virt_to_bus(skb->data);
 #endif
@@ -1906,6 +1859,12 @@
 		vp->rx_ring[entry].status = 0;	/* Clear complete bit. */
 		outw(UpUnstall, ioaddr + EL3_CMD);
 	}
+
+	if (vp->dirty_rx >= RX_RING_SIZE ) {
+		vp->cur_rx -= RX_RING_SIZE;
+		vp->dirty_rx -= RX_RING_SIZE;
+	}
+
 	return 0;
 }
 
@@ -1913,7 +1872,7 @@
 vortex_close(struct device *dev)
 {
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
-	long ioaddr = dev->base_addr;
+	int ioaddr = dev->base_addr;
 	int i;
 
 	dev->start = 0;
@@ -1975,7 +1934,8 @@
 	return 0;
 }
 
-static struct net_device_stats *vortex_get_stats(struct device *dev)
+static struct enet_statistics *
+vortex_get_stats(struct device *dev)
 {
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
 	unsigned long flags;
@@ -1996,7 +1956,7 @@
 	table.  This is done by checking that the ASM (!) code generated uses
 	atomic updates with '+='.
 	*/
-static void update_stats(long ioaddr, struct device *dev)
+static void update_stats(int ioaddr, struct device *dev)
 {
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
 
@@ -2031,7 +1991,7 @@
 static int vortex_ioctl(struct device *dev, struct ifreq *rq, int cmd)
 {
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
-	long ioaddr = dev->base_addr;
+	int ioaddr = dev->base_addr;
 	u16 *data = (u16 *)&rq->ifr_data;
 	int phy = vp->phys[0] & 0x1f;
 
@@ -2040,7 +2000,7 @@
 			   dev->name, rq->ifr_ifrn.ifrn_name, cmd,
 			   data[0], data[1], data[2], data[3]);
 
-	switch(cmd) {
+    switch(cmd) {
 	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */
 		data[0] = phy;
 	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */
@@ -2065,7 +2025,7 @@
 static void
 set_rx_mode(struct device *dev)
 {
-	long ioaddr = dev->base_addr;
+	int ioaddr = dev->base_addr;
 	int new_mode;
 
 	if (dev->flags & IFF_PROMISC) {
@@ -2108,11 +2068,11 @@
 
 /* Generate the preamble required for initial synchronization and
    a few older transceivers. */
-static void mdio_sync(long ioaddr, int bits)
+static void mdio_sync(int ioaddr, int bits)
 {
-	long mdio_addr = ioaddr + Wn4_PhysicalMgmt;
+	int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
 
-	/* Establish sync by sending at least 32 logic ones. */
+	/* Establish sync by sending at least 32 logic ones. */ 
 	while (-- bits >= 0) {
 		outw(MDIO_DATA_WRITE1, mdio_addr);
 		mdio_delay();
@@ -2121,12 +2081,12 @@
 	}
 }
 
-static int mdio_read(long ioaddr, int phy_id, int location)
+static int mdio_read(int ioaddr, int phy_id, int location)
 {
 	int i;
 	int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
 	unsigned int retval = 0;
-	long mdio_addr = ioaddr + Wn4_PhysicalMgmt;
+	int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
 
 	if (mii_preamble_required)
 		mdio_sync(ioaddr, 32);
@@ -2150,10 +2110,10 @@
 	return retval>>1 & 0xffff;
 }
 
-static void mdio_write(long ioaddr, int phy_id, int location, int value)
+static void mdio_write(int ioaddr, int phy_id, int location, int value)
 {
 	int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value;
-	long mdio_addr = ioaddr + Wn4_PhysicalMgmt;
+	int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
 	int i;
 
 	if (mii_preamble_required)
@@ -2206,7 +2166,7 @@
  * Local variables:
  *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
  *  SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c"
- *  cardbus-compile-command: "gcc -DCARDBUS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c -o 3c575_cb.o -I/usr/src/pcmcia-cs-3.0.5/include/"
+ *  compile-command-alt1: "gcc -DCARDBUS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c -o 3c59x_cb.o"
  *  c-indent-level: 4
  *  c-basic-offset: 4
  *  tab-width: 4
diff -u --recursive --new-file v2.1.120/linux/drivers/net/Config.in linux/drivers/net/Config.in
--- v2.1.120/linux/drivers/net/Config.in	Mon Aug  3 12:45:45 1998
+++ linux/drivers/net/Config.in	Sun Sep  6 10:47:01 1998
@@ -203,6 +203,10 @@
 #
 # WAN drivers support
 #
+# There is no way to detect a comtrol sv11 - force it modular for now.
+#
+dep_tristate 'Comtrol Hostess SV-11 support' CONFIG_HOSTESS_SV11 m
+#
 if [ "$CONFIG_WAN_ROUTER" != "n" ]; then
   bool 'WAN drivers' CONFIG_WAN_DRIVERS
   if [ "$CONFIG_WAN_DRIVERS" = "y" ]; then
diff -u --recursive --new-file v2.1.120/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v2.1.120/linux/drivers/net/Makefile	Mon Aug  3 12:45:45 1998
+++ linux/drivers/net/Makefile	Sun Sep  6 10:47:01 1998
@@ -24,6 +24,10 @@
 CONFIG_7990_MODULE :=
 CONFIG_82596_BUILTIN :=
 CONFIG_82596_MODULE :=
+CONFIG_85230_BUILTIN :=
+CONFIG_85230_MODULE  :=
+CONFIG_SYNCPPP_BUILTIN :=
+CONFIG_SYNCPPP_MODULE  :=
 
 ifeq ($(CONFIG_ISDN),y)
   ifeq ($(CONFIG_ISDN_PPP),y)
@@ -283,8 +287,8 @@
   endif
 endif
 
-# bsd_comp.o is *always* a module, for some undocumented reason
-# (perhaps licensing).
+# bsd_comp.o is *always* a module, for some documented reason
+# (licensing).
 ifeq ($(CONFIG_PPP),y)
 LX_OBJS += ppp.o
 M_OBJS += bsd_comp.o
@@ -689,6 +693,40 @@
 else
   ifeq ($(CONFIG_EPIC100),m)
   M_OBJS += epic100.o
+  endif
+endif
+
+ifeq ($(CONFIG_HOSTESS_SV11),y)
+L_OBJS += hostess_sv11.o
+CONFIG_85230_BUILTIN = y
+CONFIG_SYNCPPP_BUILTIN = y
+else
+  ifeq ($(CONFIG_HOSTESS_SV11),m)
+  CONFIG_85230_MODULE = y
+  CONFIG_SYNCPPP_MODULE = y
+  M_OBJS += hostess_sv11.o
+  endif
+endif
+
+# If anything built-in uses syncppp, then build it into the kernel also.
+# If not, but a module uses it, build as a module.
+
+ifdef CONFIG_SYNCPPP_BUILTIN
+LX_OBJS += syncppp.o
+else
+  ifdef CONFIG_SYNCPPP_MODULE
+  MX_OBJS += syncppp.o
+  endif
+endif
+
+# If anything built-in uses Z85230, then build it into the kernel also.
+# If not, but a module uses it, build as a module.
+
+ifdef CONFIG_85230_BUILTIN
+LX_OBJS += z85230.o
+else
+  ifdef CONFIG_85230_MODULE
+  MX_OBJS += z85230.o
   endif
 endif
 
diff -u --recursive --new-file v2.1.120/linux/drivers/net/hostess_sv11.c linux/drivers/net/hostess_sv11.c
--- v2.1.120/linux/drivers/net/hostess_sv11.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/hostess_sv11.c	Tue Sep  8 23:20:41 1998
@@ -0,0 +1,385 @@
+/*
+ *	Comtrol SV11 card driver
+ *
+ *	This is a slightly odd Z85230 synchronous driver. All you need to
+ *	know basically is
+ *
+ *	Its a genuine Z85230
+ *
+ *	It supports DMA using two DMA channels in SYNC mode. The driver doesn't
+ *	use these facilities (yet).
+ *	
+ *	The control port is at io+1, the data at io+3 and turning off the DMA
+ *	is done by writing 0 to io+4
+ *
+ *	The hardware does the bus handling to avoid the need for delays between
+ *	touching control registers.
+ *
+ *	Port B isnt wired (why - beats me)
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/net.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <net/arp.h>
+
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/byteorder.h>
+#include "syncppp.h"
+#include "z85230.h"
+
+static int dma;
+
+struct sv11_device
+{
+	struct z8530_dev sync;
+	struct ppp_device netdev;
+	char name[16];
+};
+
+/*
+ *	Network driver support routines
+ */
+
+/*
+ *	Frame receive. Simple for our card as we do sync ppp and there
+ *	is no funny garbage involved. This is very timing sensitive.
+ */
+ 
+static void hostess_input(struct z8530_channel *c, struct sk_buff *skb)
+{
+	/* Drop the CRC - its not a good idea to try and negotiate it ;) */
+	skb_trim(skb, skb->len-2);
+	skb->protocol=htons(ETH_P_WAN_PPP);
+	skb->dev=c->netdevice;
+	/*
+	 *	Send it to the PPP layer. We dont have time to process
+	 *	it right now.
+	 */
+	skb->mac.raw = skb->data;
+	
+	netif_rx(skb);
+}
+ 
+/*
+ *	We've been placed in the UP state
+ */ 
+ 
+static int hostess_open(struct device *d)
+{
+	struct sv11_device *sv11=d->priv;
+	int err;
+	
+	/*
+	 *	Link layer up
+	 */
+	if(dma)
+		err=z8530_sync_dma_open(d, &sv11->sync.chanA);
+	else
+		err=z8530_sync_open(d, &sv11->sync.chanA);
+	if(err)
+		return err;
+	/*
+	 *	Begin PPP
+	 */
+	err=sppp_open(d);
+	if(err)
+	{
+		if(dma)
+			z8530_sync_dma_close(d, &sv11->sync.chanA);
+		else
+			z8530_sync_close(d, &sv11->sync.chanA);
+		return err;
+	}
+	sv11->sync.chanA.rx_function=hostess_input;
+	
+	/*
+	 *	Go go go
+	 */
+	d->tbusy=0;
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int hostess_close(struct device *d)
+{
+	struct sv11_device *sv11=d->priv;
+	/*
+	 *	Discard new frames
+	 */
+	sv11->sync.chanA.rx_function=z8530_null_rx;
+	/*
+	 *	PPP off
+	 */
+	sppp_close(d);
+	/*
+	 *	Link layer down
+	 */
+	d->tbusy=1;
+	if(dma)
+		z8530_sync_dma_close(d, &sv11->sync.chanA);
+	else
+		z8530_sync_close(d, &sv11->sync.chanA);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int hostess_ioctl(struct device *d, struct ifreq *ifr, int cmd)
+{
+	struct sv11_device *sv11=d->priv;
+	/* z8530_ioctl(d,&sv11->sync.chanA,ifr,cmd) */
+	return sppp_do_ioctl(d, ifr, cmd);
+}
+
+static struct net_device_stats *hostess_get_stats(struct device *d)
+{
+	struct sv11_device *sv11=d->priv;
+	if(sv11)
+		return z8530_get_stats(&sv11->sync.chanA);
+	else
+		return NULL;
+}
+
+/*
+ *	Passed PPP frames, fire them downwind.
+ */
+ 
+static int hostess_queue_xmit(struct sk_buff *skb, struct device *d)
+{
+	struct sv11_device *sv11=d->priv;
+	return z8530_queue_xmit(&sv11->sync.chanA, skb);
+}
+
+static int hostess_neigh_setup(struct neighbour *n)
+{
+	if (n->nud_state == NUD_NONE) {
+		n->ops = &arp_broken_ops;
+		n->output = n->ops->output;
+	}
+	return 0;
+}
+
+static int hostess_neigh_setup_dev(struct device *dev, struct neigh_parms *p)
+{
+	if (p->tbl->family == AF_INET) {
+		p->neigh_setup = hostess_neigh_setup;
+		p->ucast_probes = 0;
+		p->mcast_probes = 0;
+	}
+	return 0;
+}
+
+/*
+ *	Description block for a Comtrol Hostess SV11 card
+ */
+ 
+static struct sv11_device *sv11_init(int iobase, int irq)
+{
+	struct z8530_dev *dev;
+	struct sv11_device *sv;
+	int i;
+	unsigned long flags;
+	
+	/*
+	 *	Get the needed I/O space
+	 */
+	 
+	if(check_region(iobase, 8))
+	{	
+		printk(KERN_WARNING "hostess: I/O 0x%X already in use.\n", iobase);
+		return NULL;
+	}
+	request_region(iobase, 8, "Comtrol SV11");
+	
+	sv=(struct sv11_device *)kmalloc(sizeof(struct sv11_device), GFP_KERNEL);
+	if(!sv)
+		goto fail3;
+			
+	memset(sv, 0, sizeof(*sv));
+	
+	dev=&sv->sync;
+	
+	/*
+	 *	Stuff in the I/O addressing
+	 */
+	 
+	dev->active = 0;
+	
+	dev->chanA.ctrlio=iobase+1;
+	dev->chanA.dataio=iobase+3;
+	dev->chanB.ctrlio=-1;
+	dev->chanB.dataio=-1;
+	dev->chanA.irqs=&z8530_nop;
+	dev->chanB.irqs=&z8530_nop;
+	
+	outb(0, iobase+4);		/* DMA off */
+	
+	/* We want a fast IRQ for this device. Actually we'd like an even faster
+	   IRQ ;) - This is one driver RtLinux is made for */
+	   
+	if(request_irq(irq, &z8530_interrupt, SA_INTERRUPT, "Hostess SV/11", dev)<0)
+	{
+		printk(KERN_WARNING "hostess: IRQ %d already in use.\n", irq);
+		goto fail2;
+	}
+	
+	dev->irq=irq;
+	dev->chanA.private=sv;
+	dev->chanA.netdevice=&sv->netdev.dev;
+	dev->chanA.dev=dev;
+	dev->chanB.dev=dev;
+	dev->name=sv->name;
+	
+	if(dma)
+	{
+		/*
+		 *	You can have DMA off or 1 and 3 thats the lot
+		 *	on the Comtrol.
+		 */
+		dev->chanA.txdma=1;
+		dev->chanA.rxdma=3;
+		outb(14, iobase+4);		/* DMA on */
+		if(request_dma(dev->chanA.txdma, "Hostess SV/11 (TX)")!=0)
+			goto fail;
+		if(request_dma(dev->chanA.rxdma, "Hostess SV/11 (RX)")!=0)
+			goto dmafail;
+	}
+	save_flags(flags);
+	cli();
+	
+	/*
+	 *	Begin normal initialise
+	 */
+	 
+	if(z8530_init(dev)!=0)
+		goto dmafail2;
+	z8530_channel_load(&dev->chanB, z8530_dead_port);
+	if(dev->type==Z85C30)
+		z8530_channel_load(&dev->chanA, z8530_hdlc_kilostream);
+	else
+		z8530_channel_load(&dev->chanA, z8530_hdlc_kilostream_85230);
+	
+	restore_flags(flags);
+
+
+	printk(KERN_INFO "begin loading hdlc\n");
+	
+	/*
+	 *	Now we can take the IRQ
+	 */
+	
+	for(i=0;i<999;i++)
+	{
+		sprintf(sv->name,"hdlc%d", i);
+		if(dev_get(sv->name)==NULL)
+		{
+			struct device *d=dev->chanA.netdevice;
+	
+			/* 
+			 *	Initialise the PPP components
+			 */
+			sppp_attach(&sv->netdev);
+			
+			/*
+			 *	Local fields
+			 */	
+			sprintf(sv->name,"hdlc%d", i);
+			printk("Filling in device '%s' at %p\n", sv->name, d);
+			
+			d->name = sv->name;
+			d->base_addr = iobase;
+			d->irq = irq;
+			d->priv = sv;
+			d->init = NULL;
+			
+			d->open = hostess_open;
+			d->stop = hostess_close;
+			d->hard_start_xmit = hostess_queue_xmit;
+			d->get_stats = hostess_get_stats;
+			d->set_multicast_list = NULL;
+			d->do_ioctl = hostess_ioctl;
+			d->neigh_setup = hostess_neigh_setup_dev;
+			dev_init_buffers(d);
+			d->set_mac_address = NULL;
+			
+			if(register_netdev(d)==-1)
+			{
+				printk(KERN_ERR "%s: unable to register device.\n",
+					sv->name);
+				goto fail;
+			}				
+
+			z8530_describe(dev, "I/O", iobase);
+			dev->active=1;
+		 	return sv;	
+		}
+	}
+dmafail2:
+	if(!dma)
+		goto fail;
+	free_dma(dev->chanA.rxdma);
+dmafail:
+	free_dma(dev->chanA.txdma);
+fail:
+	free_irq(irq, dev);
+fail2:
+	kfree(sv);
+fail3:
+	release_region(iobase,8);
+	return NULL;
+}
+
+static void sv11_shutdown(struct sv11_device *dev)
+{
+	sppp_detach(&dev->netdev.dev);
+	z8530_shutdown(&dev->sync);
+	unregister_netdev(&dev->netdev.dev);
+	free_irq(dev->sync.irq, dev);
+	free_dma(dev->sync.chanA.rxdma);
+	free_dma(dev->sync.chanA.txdma);
+	release_region(dev->sync.chanA.ctrlio-1, 8);
+}
+
+#ifdef MODULE
+
+static int io=0x200;
+static int irq=9;
+
+MODULE_PARM(io,"i");
+MODULE_PARM_DESC(io, "The I/O base of the Comtrol Hostess SV11 card");
+MODULE_PARM(dma,"i");
+MODULE_PARM_DESC(dma, "Set this to 1 to use DMA1/DMA3 for TX/RX");
+MODULE_PARM(irq,"i");
+MODULE_PARM_DESC(irq, "The interrupt line setting for the Comtrol Hostess SV11 card");
+
+MODULE_AUTHOR("Bulding Number Three Ltd");
+MODULE_DESCRIPTION("Modular driver for the Comtrol Hostess SV11");
+
+static struct sv11_device *sv11_unit;
+
+int init_module(void)
+{
+	printk(KERN_INFO "SV-11 Z85230 Synchronous Driver v 0.02.\n");
+	printk(KERN_INFO "(c) Copyright 1998, Building Number Three Ltd.\n");	
+	if(dma)
+		printk(KERN_WARNING "DMA mode probably wont work right now.\n");
+	if((sv11_unit=sv11_init(io,irq))==NULL)
+		return -ENODEV;
+	return 0;
+}
+
+void cleanup_module(void)
+{
+	if(sv11_unit)
+		sv11_shutdown(sv11_unit);
+}
+
+#endif
+
diff -u --recursive --new-file v2.1.120/linux/drivers/net/plip.c linux/drivers/net/plip.c
--- v2.1.120/linux/drivers/net/plip.c	Sat Sep  5 16:46:40 1998
+++ linux/drivers/net/plip.c	Sun Sep  6 10:09:22 1998
@@ -1178,7 +1178,7 @@
 			/* disable driver on "parport=" or "parport=0" */
 			parport[0] = -2;
 		} else {
-			printk(KERN_WARNINGING "warning: 'plip=0x%x' ignored\n", 
+			printk(KERN_WARNING "warning: 'plip=0x%x' ignored\n", 
 			       ints[1]);
 		}
 	}
diff -u --recursive --new-file v2.1.120/linux/drivers/net/sdladrv.c linux/drivers/net/sdladrv.c
--- v2.1.120/linux/drivers/net/sdladrv.c	Sat Sep  5 16:46:40 1998
+++ linux/drivers/net/sdladrv.c	Sat Sep  5 17:01:45 1998
@@ -437,7 +437,7 @@
 		return -EINVAL;
 	} 
 	printk(KERN_INFO "%s: dual-port memory window is set at 0x%lX.\n",
-		modname, virt_to_phys(hw->dpmbase))
+		modname, virt_to_phys((void *)hw->dpmbase))
 	;
 	printk(KERN_INFO "%s: found %luK bytes of on-board memory.\n",
 		modname, hw->memory / 1024)
diff -u --recursive --new-file v2.1.120/linux/drivers/net/strip.c linux/drivers/net/strip.c
--- v2.1.120/linux/drivers/net/strip.c	Thu Feb 12 20:56:09 1998
+++ linux/drivers/net/strip.c	Sat Sep  5 17:01:45 1998
@@ -2430,7 +2430,6 @@
     dev->tx_queue_len       = 30;         /* Drop after 30 frames queued */
 
     dev->flags              = 0;
-    dev->metric             = 0;
     dev->mtu                = DEFAULT_STRIP_MTU;
     dev->type               = ARPHRD_METRICOM;        /* dtang */
     dev->hard_header_len    = sizeof(STRIP_Header);
diff -u --recursive --new-file v2.1.120/linux/drivers/net/syncppp.c linux/drivers/net/syncppp.c
--- v2.1.120/linux/drivers/net/syncppp.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/syncppp.c	Sun Sep  6 10:47:01 1998
@@ -0,0 +1,1277 @@
+/*
+ *	NET3:	A (fairly minimal) implementation of synchronous PPP for Linux
+ *		as well as a CISCO HDLC implementation. See the copyright 
+ *		message below for the original source.
+ *
+ *	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.
+ *
+ *	Note however. This code is also used in a different form by FreeBSD.
+ *	Therefore when making any non OS specific change please consider
+ *	contributing it back to the original author under the terms
+ *	below in addition.
+ *		-- Alan
+ *
+ *	Port for Linux-2.1 by Jan "Yenya" Kasprzak <kas@fi.muni.cz>
+ */
+
+/*
+ * Synchronous PPP/Cisco link level subroutines.
+ * Keepalive protocol implemented in both Cisco and PPP modes.
+ *
+ * Copyright (C) 1994 Cronyx Ltd.
+ * Author: Serge Vakulenko, <vak@zebub.msk.su>
+ *
+ * This software is distributed with NO WARRANTIES, not even the implied
+ * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Authors grant any other persons or organisations permission to use
+ * or modify this software as long as this message is kept with the software,
+ * all derivative works or modified versions.
+ *
+ * Version 1.9, Wed Oct  4 18:58:15 MSK 1995
+ *
+ * $Id: if_spppsubr.c,v 1.12 1996/06/10 23:17:45 gpalmer Exp $
+ */
+#undef DEBUG
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/if_arp.h>
+#include <linux/skbuff.h>
+#include <linux/route.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/random.h>
+#include <asm/byteorder.h>
+#include "syncppp.h"
+
+#define MAXALIVECNT     3               /* max. alive packets */
+
+#define PPP_ALLSTATIONS 0xff            /* All-Stations broadcast address */
+#define PPP_UI          0x03            /* Unnumbered Information */
+#define PPP_IP          0x0021          /* Internet Protocol */
+#define PPP_ISO         0x0023          /* ISO OSI Protocol */
+#define PPP_XNS         0x0025          /* Xerox NS Protocol */
+#define PPP_IPX         0x002b          /* Novell IPX Protocol */
+#define PPP_LCP         0xc021          /* Link Control Protocol */
+#define PPP_IPCP        0x8021          /* Internet Protocol Control Protocol */
+
+#define LCP_CONF_REQ    1               /* PPP LCP configure request */
+#define LCP_CONF_ACK    2               /* PPP LCP configure acknowledge */
+#define LCP_CONF_NAK    3               /* PPP LCP configure negative ack */
+#define LCP_CONF_REJ    4               /* PPP LCP configure reject */
+#define LCP_TERM_REQ    5               /* PPP LCP terminate request */
+#define LCP_TERM_ACK    6               /* PPP LCP terminate acknowledge */
+#define LCP_CODE_REJ    7               /* PPP LCP code reject */
+#define LCP_PROTO_REJ   8               /* PPP LCP protocol reject */
+#define LCP_ECHO_REQ    9               /* PPP LCP echo request */
+#define LCP_ECHO_REPLY  10              /* PPP LCP echo reply */
+#define LCP_DISC_REQ    11              /* PPP LCP discard request */
+
+#define LCP_OPT_MRU             1       /* maximum receive unit */
+#define LCP_OPT_ASYNC_MAP       2       /* async control character map */
+#define LCP_OPT_AUTH_PROTO      3       /* authentication protocol */
+#define LCP_OPT_QUAL_PROTO      4       /* quality protocol */
+#define LCP_OPT_MAGIC           5       /* magic number */
+#define LCP_OPT_RESERVED        6       /* reserved */
+#define LCP_OPT_PROTO_COMP      7       /* protocol field compression */
+#define LCP_OPT_ADDR_COMP       8       /* address/control field compression */
+
+#define IPCP_CONF_REQ   LCP_CONF_REQ    /* PPP IPCP configure request */
+#define IPCP_CONF_ACK   LCP_CONF_ACK    /* PPP IPCP configure acknowledge */
+#define IPCP_CONF_NAK   LCP_CONF_NAK    /* PPP IPCP configure negative ack */
+#define IPCP_CONF_REJ   LCP_CONF_REJ    /* PPP IPCP configure reject */
+#define IPCP_TERM_REQ   LCP_TERM_REQ    /* PPP IPCP terminate request */
+#define IPCP_TERM_ACK   LCP_TERM_ACK    /* PPP IPCP terminate acknowledge */
+#define IPCP_CODE_REJ   LCP_CODE_REJ    /* PPP IPCP code reject */
+
+#define CISCO_MULTICAST         0x8f    /* Cisco multicast address */
+#define CISCO_UNICAST           0x0f    /* Cisco unicast address */
+#define CISCO_KEEPALIVE         0x8035  /* Cisco keepalive protocol */
+#define CISCO_ADDR_REQ          0       /* Cisco address request */
+#define CISCO_ADDR_REPLY        1       /* Cisco address reply */
+#define CISCO_KEEPALIVE_REQ     2       /* Cisco keepalive request */
+
+struct ppp_header {
+	u8 address;
+	u8 control;
+	u16 protocol;
+};
+#define PPP_HEADER_LEN          sizeof (struct ppp_header)
+
+struct lcp_header {
+	u8 type;
+	u8 ident;
+	u16 len;
+};
+#define LCP_HEADER_LEN          sizeof (struct lcp_header)
+
+struct cisco_packet {
+	u32 type;
+	u32 par1;
+	u32 par2;
+	u16 rel;
+	u16 time0;
+	u16 time1;
+};
+#define CISCO_PACKET_LEN 18
+
+static struct sppp *spppq;
+static struct timer_list sppp_keepalive_timer;
+
+static void sppp_keepalive (unsigned long dummy);
+static void sppp_cp_send (struct sppp *sp, u16 proto, u8 type,
+	u8 ident, u16 len, void *data);
+static void sppp_cisco_send (struct sppp *sp, int type, long par1, long par2);
+static void sppp_lcp_input (struct sppp *sp, struct sk_buff *m);
+static void sppp_cisco_input (struct sppp *sp, struct sk_buff *m);
+static void sppp_ipcp_input (struct sppp *sp, struct sk_buff *m);
+static void sppp_lcp_open (struct sppp *sp);
+static void sppp_ipcp_open (struct sppp *sp);
+static int sppp_lcp_conf_parse_options (struct sppp *sp, struct lcp_header *h,
+	int len, u32 *magic);
+static void sppp_cp_timeout (unsigned long arg);
+static char *sppp_lcp_type_name (u8 type);
+static char *sppp_ipcp_type_name (u8 type);
+static void sppp_print_bytes (u8 *p, u16 len);
+
+static int debug = 0;
+
+/*
+ *	Interface down stub
+ */	
+
+static void if_down(struct device *dev)
+{
+	;
+}
+
+/*
+ * Timeout routine activations.
+ */
+
+static void sppp_set_timeout(struct sppp *p,int s) 
+{
+	if (! (p->pp_flags & PP_TIMO)) 
+	{
+		init_timer(&p->pp_timer);
+		p->pp_timer.function=sppp_cp_timeout;
+		p->pp_timer.expires=jiffies+s*HZ;
+		p->pp_timer.data=(unsigned long)p;
+		p->pp_flags |= PP_TIMO;
+		add_timer(&p->pp_timer);
+	}
+}
+
+static void sppp_clear_timeout(struct sppp *p)
+{
+	if (p->pp_flags & PP_TIMO) 
+	{
+		del_timer(&p->pp_timer);
+		p->pp_flags &= ~PP_TIMO; 
+	}
+}
+
+/*
+ * Process the received packet.
+ */
+ 
+void sppp_input (struct device *dev, struct sk_buff *skb)
+{
+	struct ppp_header *h;
+	struct sppp *sp = &((struct ppp_device *)dev)->sppp;
+	
+	skb->dev=dev;
+	skb->mac.raw=skb->data;
+	
+	if (dev->flags & IFF_UP)
+	{
+		/* Count received bytes, add FCS and one flag */
+		sp->ibytes+= skb->len + 3;
+		sp->ipkts++;
+	}
+
+	if (skb->len <= PPP_HEADER_LEN) {
+		/* Too small packet, drop it. */
+		if (sp->pp_flags & PP_DEBUG)
+			printk (KERN_DEBUG "%s: input packet is too small, %d bytes\n",
+				dev->name, skb->len);
+drop:           kfree_skb(skb);
+		return;
+	}
+
+	/* Get PPP header. */
+	h = (struct ppp_header *)skb->data;
+	skb_pull(skb,sizeof(struct ppp_header));
+
+	switch (h->address) {
+	default:        /* Invalid PPP packet. */
+invalid:        if (sp->pp_flags & PP_DEBUG)
+			printk (KERN_WARNING "%s: invalid input packet <0x%x 0x%x 0x%x>\n",
+				dev->name,
+				h->address, h->control, ntohs (h->protocol));
+		goto drop;
+	case PPP_ALLSTATIONS:
+		if (h->control != PPP_UI)
+			goto invalid;
+		if (sp->pp_flags & PP_CISCO) {
+			if (sp->pp_flags & PP_DEBUG)
+				printk (KERN_WARNING "%s: PPP packet in Cisco mode <0x%x 0x%x 0x%x>\n",
+					dev->name,
+					h->address, h->control, ntohs (h->protocol));
+			goto drop;
+		}
+		switch (ntohs (h->protocol)) {
+		default:
+			if (sp->lcp.state == LCP_STATE_OPENED)
+				sppp_cp_send (sp, PPP_LCP, LCP_PROTO_REJ,
+					++sp->pp_seq, skb->len + 2,
+					&h->protocol);
+			if (sp->pp_flags & PP_DEBUG)
+				printk (KERN_WARNING "%s: invalid input protocol <0x%x 0x%x 0x%x>\n",
+					dev->name,
+					h->address, h->control, ntohs (h->protocol));
+			goto drop;
+		case PPP_LCP:
+			sppp_lcp_input (sp, skb);
+			kfree_skb(skb);
+			return;
+		case PPP_IPCP:
+			if (sp->lcp.state == LCP_STATE_OPENED)
+				sppp_ipcp_input (sp, skb);
+			else
+				printk(KERN_DEBUG "IPCP when still waiting LCP finish.\n");
+			kfree_skb(skb);
+			return;
+		case PPP_IP:
+			if (sp->ipcp.state == IPCP_STATE_OPENED) {
+				if(sp->pp_flags&PP_DEBUG)
+					printk(KERN_DEBUG "Yow an IP frame.\n");
+				skb->protocol=htons(ETH_P_IP);
+				netif_rx(skb);
+				return;
+			}
+			break;
+#ifdef IPX
+		case PPP_IPX:
+			/* IPX IPXCP not implemented yet */
+			if (sp->lcp.state == LCP_STATE_OPENED) {
+				skb->protocol=htons(ETH_P_IPX);
+				netif_rx(skb);
+				return;
+			}
+			break;
+#endif
+		}
+		break;
+	case CISCO_MULTICAST:
+	case CISCO_UNICAST:
+		/* Don't check the control field here (RFC 1547). */
+		if (! (sp->pp_flags & PP_CISCO)) {
+			if (sp->pp_flags & PP_DEBUG)
+				printk (KERN_WARNING "%s: Cisco packet in PPP mode <0x%x 0x%x 0x%x>\n",
+					dev->name,
+					h->address, h->control, ntohs (h->protocol));
+			goto drop;
+		}
+		switch (ntohs (h->protocol)) {
+		default:
+			goto invalid;
+		case CISCO_KEEPALIVE:
+			sppp_cisco_input (sp, skb);
+			kfree_skb(skb);
+			return;
+#ifdef CONFIG_INET
+		case ETH_P_IP:
+			skb->protocol=htons(ETH_P_IP);
+			netif_rx(skb);
+			return;
+#endif
+#ifdef CONFIG_IPX
+		case ETH_P_IPX:
+			skb->protocol=htons(ETH_P_IPX);
+			netif_rx(skb);
+			return;
+#endif
+		}
+		break;
+	}
+	kfree_skb(skb);
+}
+
+EXPORT_SYMBOL(sppp_input);
+
+/*
+ *	Handle transmit packets.
+ */
+ 
+static int sppp_hard_header(struct sk_buff *skb, struct device *dev, __u16 type,
+		void *daddr, void *saddr, unsigned int len)
+{
+	struct sppp *sp = &((struct ppp_device *)dev)->sppp;
+	struct ppp_header *h;
+	skb_push(skb,sizeof(struct ppp_header));
+	h=(struct ppp_header *)skb->data;
+	if(sp->pp_flags&PP_CISCO)
+	{
+		h->address = CISCO_MULTICAST;
+		h->control = 0;
+	}
+	else
+	{
+		h->address = PPP_ALLSTATIONS;
+		h->control = PPP_UI;
+	}
+	if(sp->pp_flags & PP_CISCO)
+	{
+		h->protocol = htons(type);
+	}
+	else switch(type)
+	{
+		case ETH_P_IP:
+			h->protocol = htons(PPP_IP);
+			break;
+		case ETH_P_IPX:
+			h->protocol = htons(PPP_IPX);
+			break;
+	}
+	return sizeof(struct ppp_header);
+}
+
+static int sppp_rebuild_header(struct sk_buff *skb)
+{
+	return 0;
+}
+
+/*
+ * Send keepalive packets, every 10 seconds.
+ */
+
+static void sppp_keepalive (unsigned long dummy)
+{
+	struct sppp *sp;
+	unsigned long flags;
+	save_flags(flags);
+	cli();
+
+	for (sp=spppq; sp; sp=sp->pp_next) 
+	{
+		struct device *dev = sp->pp_if;
+
+		/* Keepalive mode disabled or channel down? */
+		if (! (sp->pp_flags & PP_KEEPALIVE) ||
+		    ! (dev->flags & IFF_RUNNING))
+			continue;
+
+		/* No keepalive in PPP mode if LCP not opened yet. */
+		if (! (sp->pp_flags & PP_CISCO) &&
+		    sp->lcp.state != LCP_STATE_OPENED)
+			continue;
+
+		if (sp->pp_alivecnt == MAXALIVECNT) {
+			/* No keepalive packets got.  Stop the interface. */
+			printk (KERN_WARNING "%s: down\n", dev->name);
+			if_down (dev);
+			if (! (sp->pp_flags & PP_CISCO)) {
+				/* Shut down the PPP link. */
+				sp->lcp.state = LCP_STATE_CLOSED;
+				sp->ipcp.state = IPCP_STATE_CLOSED;
+				sppp_clear_timeout (sp);
+				/* Initiate negotiation. */
+				sppp_lcp_open (sp);
+			}
+		}
+		if (sp->pp_alivecnt <= MAXALIVECNT)
+			++sp->pp_alivecnt;
+		if (sp->pp_flags & PP_CISCO)
+			sppp_cisco_send (sp, CISCO_KEEPALIVE_REQ, ++sp->pp_seq,
+				sp->pp_rseq);
+		else if (sp->lcp.state == LCP_STATE_OPENED) {
+			long nmagic = htonl (sp->lcp.magic);
+			sp->lcp.echoid = ++sp->pp_seq;
+			sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REQ,
+				sp->lcp.echoid, 4, &nmagic);
+		}
+	}
+	restore_flags(flags);
+	sppp_keepalive_timer.expires=jiffies+10*HZ;
+	add_timer(&sppp_keepalive_timer);
+}
+
+/*
+ * Handle incoming PPP Link Control Protocol packets.
+ */
+ 
+static void sppp_lcp_input (struct sppp *sp, struct sk_buff *skb)
+{
+	struct lcp_header *h;
+	struct device *dev = sp->pp_if;
+	int len = skb->len;
+	u8 *p, opt[6];
+	u32 rmagic;
+
+	if (len < 4) {
+		if (sp->pp_flags & PP_DEBUG)
+			printk (KERN_WARNING "%s: invalid lcp packet length: %d bytes\n",
+				dev->name, len);
+		return;
+	}
+	h = (struct lcp_header *)skb->data;
+	skb_pull(skb,sizeof(struct lcp_header *));
+	
+	if (sp->pp_flags & PP_DEBUG) 
+	{
+		char state = '?';
+		switch (sp->lcp.state) {
+		case LCP_STATE_CLOSED:   state = 'C'; break;
+		case LCP_STATE_ACK_RCVD: state = 'R'; break;
+		case LCP_STATE_ACK_SENT: state = 'S'; break;
+		case LCP_STATE_OPENED:   state = 'O'; break;
+		}
+		printk (KERN_WARNING "%s: lcp input(%c): %d bytes <%s id=%xh len=%xh",
+			dev->name, state, len,
+			sppp_lcp_type_name (h->type), h->ident, ntohs (h->len));
+		if (len > 4)
+			sppp_print_bytes ((u8*) (h+1), len-4);
+		printk (">\n");
+	}
+	if (len > ntohs (h->len))
+		len = ntohs (h->len);
+	switch (h->type) {
+	default:
+		/* Unknown packet type -- send Code-Reject packet. */
+		sppp_cp_send (sp, PPP_LCP, LCP_CODE_REJ, ++sp->pp_seq,
+			skb->len, h);
+		break;
+	case LCP_CONF_REQ:
+		if (len < 4) {
+			if (sp->pp_flags & PP_DEBUG)
+				printk (KERN_DEBUG"%s: invalid lcp configure request packet length: %d bytes\n",
+					dev->name, len);
+			break;
+		}
+		if (len>4 && !sppp_lcp_conf_parse_options (sp, h, len, &rmagic))
+			goto badreq;
+		if (rmagic == sp->lcp.magic) {
+			/* Local and remote magics equal -- loopback? */
+			if (sp->pp_loopcnt >= MAXALIVECNT*5) {
+				printk (KERN_WARNING "%s: loopback\n",
+					dev->name);
+				sp->pp_loopcnt = 0;
+				if (dev->flags & IFF_UP) {
+					if_down (dev);
+				}
+			} else if (sp->pp_flags & PP_DEBUG)
+				printk (KERN_DEBUG "%s: conf req: magic glitch\n",
+					dev->name);
+			++sp->pp_loopcnt;
+
+			/* MUST send Conf-Nack packet. */
+			rmagic = ~sp->lcp.magic;
+			opt[0] = LCP_OPT_MAGIC;
+			opt[1] = sizeof (opt);
+			opt[2] = rmagic >> 24;
+			opt[3] = rmagic >> 16;
+			opt[4] = rmagic >> 8;
+			opt[5] = rmagic;
+			sppp_cp_send (sp, PPP_LCP, LCP_CONF_NAK,
+				h->ident, sizeof (opt), &opt);
+badreq:
+			switch (sp->lcp.state) {
+			case LCP_STATE_OPENED:
+				/* Initiate renegotiation. */
+				sppp_lcp_open (sp);
+				/* fall through... */
+			case LCP_STATE_ACK_SENT:
+				/* Go to closed state. */
+				sp->lcp.state = LCP_STATE_CLOSED;
+				sp->ipcp.state = IPCP_STATE_CLOSED;
+			}
+			break;
+		}
+		/* Send Configure-Ack packet. */
+		sp->pp_loopcnt = 0;
+		sppp_cp_send (sp, PPP_LCP, LCP_CONF_ACK,
+				h->ident, len-4, h+1);
+		/* Change the state. */
+		switch (sp->lcp.state) {
+		case LCP_STATE_CLOSED:
+			sp->lcp.state = LCP_STATE_ACK_SENT;
+			break;
+		case LCP_STATE_ACK_RCVD:
+			sp->lcp.state = LCP_STATE_OPENED;
+			sppp_ipcp_open (sp);
+			break;
+		case LCP_STATE_OPENED:
+#if 0		
+			/* Remote magic changed -- close session. */
+			sp->lcp.state = LCP_STATE_CLOSED;
+			sp->ipcp.state = IPCP_STATE_CLOSED;
+			/* Initiate renegotiation. */
+			sppp_lcp_open (sp);
+			/* An ACK has already been sent. */
+			sp->lcp.state = LCP_STATE_ACK_SENT;
+#endif			
+			break;
+		}
+		break;
+	case LCP_CONF_ACK:
+		if (h->ident != sp->lcp.confid)
+			break;
+		sppp_clear_timeout (sp);
+		if (! (dev->flags & IFF_UP) &&
+		    (dev->flags & IFF_RUNNING)) {
+			/* Coming out of loopback mode. */
+			dev->flags |= IFF_UP;
+			printk (KERN_INFO "%s: up\n", dev->name);
+		}
+		switch (sp->lcp.state) {
+		case LCP_STATE_CLOSED:
+			sp->lcp.state = LCP_STATE_ACK_RCVD;
+			sppp_set_timeout (sp, 5);
+			break;
+		case LCP_STATE_ACK_SENT:
+			sp->lcp.state = LCP_STATE_OPENED;
+			sppp_ipcp_open (sp);
+			break;
+		}
+		break;
+	case LCP_CONF_NAK:
+		if (h->ident != sp->lcp.confid)
+			break;
+		p = (u8*) (h+1);
+		if (len>=10 && p[0] == LCP_OPT_MAGIC && p[1] >= 4) {
+			rmagic = (u32)p[2] << 24 |
+				(u32)p[3] << 16 | p[4] << 8 | p[5];
+			if (rmagic == ~sp->lcp.magic) {
+				int newmagic;
+				if (sp->pp_flags & PP_DEBUG)
+					printk (KERN_DEBUG "%s: conf nak: magic glitch\n",
+						dev->name);
+				get_random_bytes(&newmagic, sizeof(newmagic));
+				sp->lcp.magic += newmagic;
+			} else
+				sp->lcp.magic = rmagic;
+			}
+		if (sp->lcp.state != LCP_STATE_ACK_SENT) {
+			/* Go to closed state. */
+			sp->lcp.state = LCP_STATE_CLOSED;
+			sp->ipcp.state = IPCP_STATE_CLOSED;
+		}
+		/* The link will be renegotiated after timeout,
+		 * to avoid endless req-nack loop. */
+		sppp_clear_timeout (sp);
+		sppp_set_timeout (sp, 2);
+		break;
+	case LCP_CONF_REJ:
+		if (h->ident != sp->lcp.confid)
+			break;
+		sppp_clear_timeout (sp);
+		/* Initiate renegotiation. */
+		sppp_lcp_open (sp);
+		if (sp->lcp.state != LCP_STATE_ACK_SENT) {
+			/* Go to closed state. */
+			sp->lcp.state = LCP_STATE_CLOSED;
+			sp->ipcp.state = IPCP_STATE_CLOSED;
+		}
+		break;
+	case LCP_TERM_REQ:
+		sppp_clear_timeout (sp);
+		/* Send Terminate-Ack packet. */
+		sppp_cp_send (sp, PPP_LCP, LCP_TERM_ACK, h->ident, 0, 0);
+		/* Go to closed state. */
+		sp->lcp.state = LCP_STATE_CLOSED;
+		sp->ipcp.state = IPCP_STATE_CLOSED;
+		/* Initiate renegotiation. */
+		sppp_lcp_open (sp);
+		break;
+	case LCP_TERM_ACK:
+	case LCP_CODE_REJ:
+	case LCP_PROTO_REJ:
+		/* Ignore for now. */
+		break;
+	case LCP_DISC_REQ:
+		/* Discard the packet. */
+		break;
+	case LCP_ECHO_REQ:
+		if (sp->lcp.state != LCP_STATE_OPENED)
+			break;
+		if (len < 8) {
+			if (sp->pp_flags & PP_DEBUG)
+				printk (KERN_WARNING "%s: invalid lcp echo request packet length: %d bytes\n",
+					dev->name, len);
+			break;
+		}
+		if (ntohl (*(long*)(h+1)) == sp->lcp.magic) {
+			/* Line loopback mode detected. */
+			printk (KERN_WARNING "%s: loopback\n", dev->name);
+			if_down (dev);
+
+			/* Shut down the PPP link. */
+			sp->lcp.state = LCP_STATE_CLOSED;
+			sp->ipcp.state = IPCP_STATE_CLOSED;
+			sppp_clear_timeout (sp);
+			/* Initiate negotiation. */
+			sppp_lcp_open (sp);
+			break;
+		}
+		*(long*)(h+1) = htonl (sp->lcp.magic);
+		sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REPLY, h->ident, len-4, h+1);
+		break;
+	case LCP_ECHO_REPLY:
+		if (h->ident != sp->lcp.echoid)
+			break;
+		if (len < 8) {
+			if (sp->pp_flags & PP_DEBUG)
+				printk (KERN_WARNING "%s: invalid lcp echo reply packet length: %d bytes\n",
+					dev->name, len);
+			break;
+		}
+		if (ntohl (*(long*)(h+1)) != sp->lcp.magic)
+		sp->pp_alivecnt = 0;
+		break;
+	}
+}
+
+/*
+ * Handle incoming Cisco keepalive protocol packets.
+ */
+
+static void sppp_cisco_input (struct sppp *sp, struct sk_buff *skb)
+{
+	struct cisco_packet *h;
+	struct device *dev = sp->pp_if;
+
+	if (skb->len != CISCO_PACKET_LEN) {
+		if (sp->pp_flags & PP_DEBUG)
+			printk (KERN_WARNING "%s: invalid cisco packet length: %d bytes\n",
+				dev->name,  skb->len);
+		return;
+	}
+	h = (struct cisco_packet *)skb->data;
+	skb_pull(skb, sizeof(struct cisco_packet*));
+	if (sp->pp_flags & PP_DEBUG)
+		printk (KERN_WARNING "%s: cisco input: %d bytes <%lxh %xh %xh %xh %xh-%xh>\n",
+			dev->name,  skb->len,
+			ntohl (h->type), h->par1, h->par2, h->rel,
+			h->time0, h->time1);
+	switch (ntohl (h->type)) {
+	default:
+		if (sp->pp_flags & PP_DEBUG)
+			printk (KERN_WARNING "%s: unknown cisco packet type: 0x%lx\n",
+				dev->name,  ntohl (h->type));
+		break;
+	case CISCO_ADDR_REPLY:
+		/* Reply on address request, ignore */
+		break;
+	case CISCO_KEEPALIVE_REQ:
+		sp->pp_alivecnt = 0;
+		sp->pp_rseq = ntohl (h->par1);
+		if (sp->pp_seq == sp->pp_rseq) {
+			/* Local and remote sequence numbers are equal.
+			 * Probably, the line is in loopback mode. */
+			int newseq;
+			if (sp->pp_loopcnt >= MAXALIVECNT) {
+				printk (KERN_WARNING "%s: loopback\n",
+					dev->name);
+				sp->pp_loopcnt = 0;
+				if (dev->flags & IFF_UP) {
+					if_down (dev);
+				}
+			}
+			++sp->pp_loopcnt;
+
+			/* Generate new local sequence number */
+			get_random_bytes(&newseq, sizeof(newseq));
+			sp->pp_seq ^= newseq;
+			break;
+		}
+		sp->pp_loopcnt = 0;
+		if (! (dev->flags & IFF_UP) &&
+		    (dev->flags & IFF_RUNNING)) {
+			dev->flags |= IFF_UP;
+			printk (KERN_INFO "%s: up\n", dev->name);
+		}
+		break;
+	case CISCO_ADDR_REQ:
+		/* Stolen from net/ipv4/devinet.c -- SIOCGIFADDR ioctl */
+		{
+		struct in_device *in_dev;
+		struct in_ifaddr *ifa, **ifap;
+		u32 addr = 0, mask = ~0; /* FIXME: is the mask correct? */
+
+		if ((in_dev=dev->ip_ptr) != NULL)
+		{
+			for (ifap=&in_dev->ifa_list; (ifa=*ifap) != NULL;
+				ifap=&ifa->ifa_next)
+				if (strcmp(dev->name, ifa->ifa_label) == 0) 
+				{
+					addr = ifa->ifa_local;
+					mask = ifa->ifa_mask;
+					break;
+				}
+		}
+		/* I hope both addr and mask are in the net order */
+		sppp_cisco_send (sp, CISCO_ADDR_REPLY, addr, mask);
+		break;
+		}
+	}
+}
+
+/*
+ * Send PPP LCP packet.
+ */
+
+static void sppp_cp_send (struct sppp *sp, u16 proto, u8 type,
+	u8 ident, u16 len, void *data)
+{
+	struct ppp_header *h;
+	struct lcp_header *lh;
+	struct sk_buff *skb;
+	struct device *dev = sp->pp_if;
+
+	skb=alloc_skb(dev->hard_header_len+PPP_HEADER_LEN+LCP_HEADER_LEN+len,
+		GFP_ATOMIC);
+	if (skb==NULL)
+		return;
+
+	skb_reserve(skb,dev->hard_header_len);
+	
+	h = (struct ppp_header *)skb_put(skb, sizeof(struct ppp_header));
+	h->address = PPP_ALLSTATIONS;        /* broadcast address */
+	h->control = PPP_UI;                 /* Unnumbered Info */
+	h->protocol = htons (proto);         /* Link Control Protocol */
+
+	lh = (struct lcp_header *)skb_put(skb, sizeof(struct lcp_header));
+	lh->type = type;
+	lh->ident = ident;
+	lh->len = htons (LCP_HEADER_LEN + len);
+
+	if (len)
+		memcpy(skb_put(skb,len),data, len);
+
+	if (sp->pp_flags & PP_DEBUG) {
+		printk (KERN_WARNING "%s: %s output <%s id=%xh len=%xh",
+			dev->name, 
+			proto==PPP_LCP ? "lcp" : "ipcp",
+			proto==PPP_LCP ? sppp_lcp_type_name (lh->type) :
+			sppp_ipcp_type_name (lh->type), lh->ident,
+			ntohs (lh->len));
+		if (len)
+			sppp_print_bytes ((u8*) (lh+1), len);
+		printk (">\n");
+	}
+	sp->obytes += skb->len;
+	/* Control is high priority so it doesnt get queued behind data */
+	skb->priority=1;
+	dev_queue_xmit(skb);
+}
+
+/*
+ * Send Cisco keepalive packet.
+ */
+
+static void sppp_cisco_send (struct sppp *sp, int type, long par1, long par2)
+{
+	struct ppp_header *h;
+	struct cisco_packet *ch;
+	struct sk_buff *skb;
+	struct device *dev = sp->pp_if;
+	u32 t = jiffies * 1000/HZ;
+
+	skb=alloc_skb(dev->hard_header_len+PPP_HEADER_LEN+CISCO_PACKET_LEN,
+		GFP_ATOMIC);
+
+	if(skb==NULL)
+		return;
+		
+	skb_reserve(skb, dev->hard_header_len);
+	h = (struct ppp_header *)skb_put (skb, sizeof(struct ppp_header));
+	h->address = CISCO_MULTICAST;
+	h->control = 0;
+	h->protocol = htons (CISCO_KEEPALIVE);
+
+	ch = (struct cisco_packet*)skb_put(skb, CISCO_PACKET_LEN);
+	ch->type = htonl (type);
+	ch->par1 = htonl (par1);
+	ch->par2 = htonl (par2);
+	ch->rel = -1;
+	ch->time0 = htons ((u16) (t >> 16));
+	ch->time1 = htons ((u16) t);
+
+	if (sp->pp_flags & PP_DEBUG)
+		printk (KERN_WARNING "%s: cisco output: <%lxh %xh %xh %xh %xh-%xh>\n",
+			dev->name,  ntohl (ch->type), ch->par1,
+			ch->par2, ch->rel, ch->time0, ch->time1);
+	sp->obytes += skb->len;
+	skb->priority=1;
+	dev_queue_xmit(skb);
+}
+
+
+int sppp_close (struct device *dev)
+{
+	struct sppp *sp = &((struct ppp_device *)dev)->sppp;
+	dev->flags &= ~IFF_RUNNING;
+	sp->lcp.state = LCP_STATE_CLOSED;
+	sp->ipcp.state = IPCP_STATE_CLOSED;
+	sppp_clear_timeout (sp);
+	return 0;
+}
+
+EXPORT_SYMBOL(sppp_close);
+
+
+int sppp_open (struct device *dev)
+{
+	struct sppp *sp = &((struct ppp_device *)dev)->sppp;
+	sppp_close(dev);
+	dev->flags |= IFF_RUNNING;
+	if (!(sp->pp_flags & PP_CISCO))
+		sppp_lcp_open (sp);
+	return 0;
+}
+
+EXPORT_SYMBOL(sppp_open);
+
+int sppp_change_mtu(struct device *dev, int new_mtu)
+{
+	if(new_mtu<128||new_mtu>PPP_MTU||(dev->flags&IFF_UP))
+		return -EINVAL;
+	dev->mtu=new_mtu;
+	return 0;
+}
+
+EXPORT_SYMBOL(sppp_change_mtu);
+
+int sppp_do_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
+{
+	struct sppp *sp = &((struct ppp_device *)dev)->sppp;
+
+	if(dev->flags&IFF_UP)
+		return -EBUSY;
+		
+	switch(cmd)
+	{
+		case SPPPIOCCISCO:
+			sp->pp_flags|=PP_CISCO;
+			break;
+		case SPPPIOCPPP:
+			sp->pp_flags&=~PP_CISCO;
+			break;
+		default:
+			return -EINVAL;
+	}
+	return 0;
+}
+
+EXPORT_SYMBOL(sppp_do_ioctl);
+
+void sppp_attach(struct ppp_device *pd)
+{
+	struct device *dev=&pd->dev;
+	struct sppp *sp = &pd->sppp;
+	
+	/* Initialize keepalive handler. */
+	if (! spppq)
+	{
+		init_timer(&sppp_keepalive_timer);
+		sppp_keepalive_timer.expires=jiffies+10*HZ;
+		sppp_keepalive_timer.function=sppp_keepalive;
+		add_timer(&sppp_keepalive_timer);
+	}
+	/* Insert new entry into the keepalive list. */
+	sp->pp_next = spppq;
+	spppq = sp;
+
+	sp->pp_loopcnt = 0;
+	sp->pp_alivecnt = 0;
+	sp->pp_seq = 0;
+	sp->pp_rseq = 0;
+	sp->pp_flags = PP_KEEPALIVE|PP_CISCO|debug;/*PP_DEBUG;*/
+	sp->lcp.magic = 0;
+	sp->lcp.state = LCP_STATE_CLOSED;
+	sp->ipcp.state = IPCP_STATE_CLOSED;
+	sp->pp_if = dev;
+	
+	/* 
+	 *	Device specific setup. All but interrupt handler and
+	 *	hard_start_xmit.
+	 */
+	 
+	dev->hard_header = sppp_hard_header;
+	dev->rebuild_header = sppp_rebuild_header;
+	dev->tx_queue_len = 10;
+	dev->type = ARPHRD_PPP;
+	dev->addr_len = 0;
+	dev->hard_header_len = sizeof(struct ppp_header);
+	dev->mtu = PPP_MTU;
+	/*
+	 *	These 4 are callers but MUST also call sppp_ functions
+	 */
+	dev->do_ioctl = sppp_do_ioctl;
+#if 0
+	dev->get_stats = NULL;		/* Let the driver override these */
+	dev->open = sppp_open;
+	dev->stop = sppp_close;
+#endif	
+	dev->change_mtu = sppp_change_mtu;
+	dev->hard_header_cache = NULL;
+	dev->header_cache_update = NULL;
+	dev->flags = IFF_MULTICAST;
+	dev_init_buffers(dev);
+}
+
+EXPORT_SYMBOL(sppp_attach);
+
+void sppp_detach (struct device *dev)
+{
+	struct sppp **q, *p, *sp = &((struct ppp_device *)dev)->sppp;
+
+
+	/* Remove the entry from the keepalive list. */
+	for (q = &spppq; (p = *q); q = &p->pp_next)
+		if (p == sp) {
+			*q = p->pp_next;
+			break;
+		}
+
+	/* Stop keepalive handler. */
+	if (! spppq)
+		del_timer(&sppp_keepalive_timer);
+	sppp_clear_timeout (sp);
+}
+
+EXPORT_SYMBOL(sppp_detach);
+
+/*
+ * Analyze the LCP Configure-Request options list
+ * for the presence of unknown options.
+ * If the request contains unknown options, build and
+ * send Configure-reject packet, containing only unknown options.
+ */
+static int
+sppp_lcp_conf_parse_options (struct sppp *sp, struct lcp_header *h,
+	int len, u32 *magic)
+{
+	u8 *buf, *r, *p;
+	int rlen;
+
+	len -= 4;
+	buf = r = kmalloc (len, GFP_ATOMIC);
+	if (! buf)
+		return (0);
+
+	p = (void*) (h+1);
+	for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) {
+		switch (*p) {
+		case LCP_OPT_MAGIC:
+			/* Magic number -- extract. */
+			if (len >= 6 && p[1] == 6) {
+				*magic = (u32)p[2] << 24 |
+					(u32)p[3] << 16 | p[4] << 8 | p[5];
+				continue;
+			}
+			break;
+		case LCP_OPT_ASYNC_MAP:
+			/* Async control character map -- check to be zero. */
+			if (len >= 6 && p[1] == 6 && ! p[2] && ! p[3] &&
+			    ! p[4] && ! p[5])
+				continue;
+			break;
+		case LCP_OPT_MRU:
+			/* Maximum receive unit -- always OK. */
+			continue;
+		default:
+			/* Others not supported. */
+			break;
+		}
+		/* Add the option to rejected list. */
+		memcpy(r, p, p[1]);
+		r += p[1];
+		rlen += p[1];
+	}
+	if (rlen)
+		sppp_cp_send (sp, PPP_LCP, LCP_CONF_REJ, h->ident, rlen, buf);
+	kfree(buf);
+	return (rlen == 0);
+}
+
+static void sppp_ipcp_input (struct sppp *sp, struct sk_buff *skb)
+{
+	struct lcp_header *h;
+	struct device *dev = sp->pp_if;
+	int len = skb->len;
+
+	if (len < 4) 
+	{
+		if (sp->pp_flags & PP_DEBUG)
+			printk (KERN_WARNING "%s: invalid ipcp packet length: %d bytes\n",
+				dev->name,  len);
+		return;
+	}
+	h = (struct lcp_header *)skb->data;
+	skb_pull(skb,sizeof(struct lcp_header));
+	if (sp->pp_flags & PP_DEBUG) {
+		printk (KERN_WARNING "%s: ipcp input: %d bytes <%s id=%xh len=%xh",
+			dev->name,  len,
+			sppp_ipcp_type_name (h->type), h->ident, ntohs (h->len));
+		if (len > 4)
+			sppp_print_bytes ((u8*) (h+1), len-4);
+		printk (">\n");
+	}
+	if (len > ntohs (h->len))
+		len = ntohs (h->len);
+	switch (h->type) {
+	default:
+		/* Unknown packet type -- send Code-Reject packet. */
+		sppp_cp_send (sp, PPP_IPCP, IPCP_CODE_REJ, ++sp->pp_seq, len, h);
+		break;
+	case IPCP_CONF_REQ:
+		if (len < 4) {
+			if (sp->pp_flags & PP_DEBUG)
+				printk (KERN_WARNING "%s: invalid ipcp configure request packet length: %d bytes\n",
+					dev->name, len);
+			return;
+		}
+		if (len > 4) {
+			sppp_cp_send (sp, PPP_IPCP, LCP_CONF_REJ, h->ident,
+				len-4, h+1);
+
+			switch (sp->ipcp.state) {
+			case IPCP_STATE_OPENED:
+				/* Initiate renegotiation. */
+				sppp_ipcp_open (sp);
+				/* fall through... */
+			case IPCP_STATE_ACK_SENT:
+				/* Go to closed state. */
+				sp->ipcp.state = IPCP_STATE_CLOSED;
+			}
+		} else {
+			/* Send Configure-Ack packet. */
+			sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_ACK, h->ident,
+				0, 0);
+			/* Change the state. */
+			if (sp->ipcp.state == IPCP_STATE_ACK_RCVD)
+				sp->ipcp.state = IPCP_STATE_OPENED;
+			else
+				sp->ipcp.state = IPCP_STATE_ACK_SENT;
+		}
+		break;
+	case IPCP_CONF_ACK:
+		if (h->ident != sp->ipcp.confid)
+			break;
+		sppp_clear_timeout (sp);
+		switch (sp->ipcp.state) {
+		case IPCP_STATE_CLOSED:
+			sp->ipcp.state = IPCP_STATE_ACK_RCVD;
+			sppp_set_timeout (sp, 5);
+			break;
+		case IPCP_STATE_ACK_SENT:
+			sp->ipcp.state = IPCP_STATE_OPENED;
+			break;
+		}
+		break;
+	case IPCP_CONF_NAK:
+	case IPCP_CONF_REJ:
+		if (h->ident != sp->ipcp.confid)
+			break;
+		sppp_clear_timeout (sp);
+			/* Initiate renegotiation. */
+		sppp_ipcp_open (sp);
+		if (sp->ipcp.state != IPCP_STATE_ACK_SENT)
+			/* Go to closed state. */
+			sp->ipcp.state = IPCP_STATE_CLOSED;
+		break;
+	case IPCP_TERM_REQ:
+		/* Send Terminate-Ack packet. */
+		sppp_cp_send (sp, PPP_IPCP, IPCP_TERM_ACK, h->ident, 0, 0);
+		/* Go to closed state. */
+		sp->ipcp.state = IPCP_STATE_CLOSED;
+		/* Initiate renegotiation. */
+		sppp_ipcp_open (sp);
+		break;
+	case IPCP_TERM_ACK:
+		/* Ignore for now. */
+	case IPCP_CODE_REJ:
+		/* Ignore for now. */
+		break;
+	}
+}
+
+static void sppp_lcp_open (struct sppp *sp)
+{
+	char opt[6];
+
+	if (! sp->lcp.magic)
+		sp->lcp.magic = jiffies;
+	opt[0] = LCP_OPT_MAGIC;
+	opt[1] = sizeof (opt);
+	opt[2] = sp->lcp.magic >> 24;
+	opt[3] = sp->lcp.magic >> 16;
+	opt[4] = sp->lcp.magic >> 8;
+	opt[5] = sp->lcp.magic;
+	sp->lcp.confid = ++sp->pp_seq;
+	sppp_cp_send (sp, PPP_LCP, LCP_CONF_REQ, sp->lcp.confid,
+		sizeof (opt), &opt);
+	sppp_set_timeout (sp, 2);
+}
+
+static void sppp_ipcp_open (struct sppp *sp)
+{
+	sp->ipcp.confid = ++sp->pp_seq;
+	sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_REQ, sp->ipcp.confid, 0, 0);
+	sppp_set_timeout (sp, 2);
+}
+
+/*
+ * Process PPP control protocol timeouts.
+ */
+ 
+static void sppp_cp_timeout (unsigned long arg)
+{
+	struct sppp *sp = (struct sppp*) arg;
+	unsigned long flags;
+	save_flags(flags);
+	cli();
+
+	sp->pp_flags &= ~PP_TIMO;
+	if (! (sp->pp_if->flags & IFF_RUNNING) || (sp->pp_flags & PP_CISCO)) {
+		restore_flags(flags);
+		return;
+	}
+	switch (sp->lcp.state) {
+	case LCP_STATE_CLOSED:
+		/* No ACK for Configure-Request, retry. */
+		sppp_lcp_open (sp);
+		break;
+	case LCP_STATE_ACK_RCVD:
+		/* ACK got, but no Configure-Request for peer, retry. */
+		sppp_lcp_open (sp);
+		sp->lcp.state = LCP_STATE_CLOSED;
+		break;
+	case LCP_STATE_ACK_SENT:
+		/* ACK sent but no ACK for Configure-Request, retry. */
+		sppp_lcp_open (sp);
+		break;
+	case LCP_STATE_OPENED:
+		/* LCP is already OK, try IPCP. */
+		switch (sp->ipcp.state) {
+		case IPCP_STATE_CLOSED:
+			/* No ACK for Configure-Request, retry. */
+			sppp_ipcp_open (sp);
+			break;
+		case IPCP_STATE_ACK_RCVD:
+			/* ACK got, but no Configure-Request for peer, retry. */
+			sppp_ipcp_open (sp);
+			sp->ipcp.state = IPCP_STATE_CLOSED;
+			break;
+		case IPCP_STATE_ACK_SENT:
+			/* ACK sent but no ACK for Configure-Request, retry. */
+			sppp_ipcp_open (sp);
+			break;
+		case IPCP_STATE_OPENED:
+			/* IPCP is OK. */
+			break;
+		}
+		break;
+	}
+	restore_flags(flags);
+}
+
+static char *sppp_lcp_type_name (u8 type)
+{
+	static char buf [8];
+	switch (type) {
+	case LCP_CONF_REQ:   return ("conf-req");
+	case LCP_CONF_ACK:   return ("conf-ack");
+	case LCP_CONF_NAK:   return ("conf-nack");
+	case LCP_CONF_REJ:   return ("conf-rej");
+	case LCP_TERM_REQ:   return ("term-req");
+	case LCP_TERM_ACK:   return ("term-ack");
+	case LCP_CODE_REJ:   return ("code-rej");
+	case LCP_PROTO_REJ:  return ("proto-rej");
+	case LCP_ECHO_REQ:   return ("echo-req");
+	case LCP_ECHO_REPLY: return ("echo-reply");
+	case LCP_DISC_REQ:   return ("discard-req");
+	}
+	sprintf (buf, "%xh", type);
+	return (buf);
+}
+
+static char *sppp_ipcp_type_name (u8 type)
+{
+	static char buf [8];
+	switch (type) {
+	case IPCP_CONF_REQ:   return ("conf-req");
+	case IPCP_CONF_ACK:   return ("conf-ack");
+	case IPCP_CONF_NAK:   return ("conf-nack");
+	case IPCP_CONF_REJ:   return ("conf-rej");
+	case IPCP_TERM_REQ:   return ("term-req");
+	case IPCP_TERM_ACK:   return ("term-ack");
+	case IPCP_CODE_REJ:   return ("code-rej");
+	}
+	sprintf (buf, "%xh", type);
+	return (buf);
+}
+
+static void sppp_print_bytes (u_char *p, u16 len)
+{
+	printk (" %x", *p++);
+	while (--len > 0)
+		printk ("-%x", *p++);
+}
+
+/*
+ *	Protocol glue. This drives the deferred processing mode the poorer
+ *	cards use.
+ */
+
+int sppp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *p)
+{
+	sppp_input(dev,skb);
+	return 0;
+}
+
+EXPORT_SYMBOL(sppp_rcv);
+
+struct packet_type sppp_packet_type=
+{
+	0,
+	NULL,
+	sppp_rcv,
+	NULL,
+	NULL
+};
+
+
+void sync_ppp_init(void)
+{
+	printk(KERN_INFO "Cronyx Ltd, Synchronous PPP and CISCO HDLC (c) 1994\n");
+	printk(KERN_INFO "Linux port (c) 1998 Building Number Three Ltd & Jan 'Yenya' Kasprzak.\n");
+	sppp_packet_type.type=htons(ETH_P_WAN_PPP);	
+	dev_add_pack(&sppp_packet_type);
+}
+
+#ifdef MODULE
+
+int init_module(void)
+{
+	if(debug)
+		debug=PP_DEBUG;
+	sync_ppp_init();
+	return 0;
+}
+
+void cleanup_module(void)
+{
+	dev_remove_pack(&sppp_packet_type);
+}
+
+#endif
diff -u --recursive --new-file v2.1.120/linux/drivers/net/syncppp.h linux/drivers/net/syncppp.h
--- v2.1.120/linux/drivers/net/syncppp.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/syncppp.h	Sun Sep  6 10:47:01 1998
@@ -0,0 +1,89 @@
+/*
+ * Defines for synchronous PPP/Cisco link level subroutines.
+ *
+ * Copyright (C) 1994 Cronyx Ltd.
+ * Author: Serge Vakulenko, <vak@zebub.msk.su>
+ *
+ * This software is distributed with NO WARRANTIES, not even the implied
+ * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Authors grant any other persons or organizations permission to use
+ * or modify this software as long as this message is kept with the software,
+ * all derivative works or modified versions.
+ *
+ * Version 1.7, Wed Jun  7 22:12:02 MSD 1995
+ *
+ *
+ *
+ */
+
+#ifndef _SYNCPPP_H_
+#define _SYNCPPP_H_ 1
+
+struct slcp {
+	u16	state;          /* state machine */
+	u32	magic;          /* local magic number */
+	u_char	echoid;         /* id of last keepalive echo request */
+	u_char	confid;         /* id of last configuration request */
+};
+
+struct sipcp {
+	u16	state;          /* state machine */
+	u_char  confid;         /* id of last configuration request */
+};
+
+struct sppp 
+{
+	struct sppp *	pp_next;	/* next interface in keepalive list */
+	u32		pp_flags;	/* use Cisco protocol instead of PPP */
+	u16		pp_alivecnt;	/* keepalive packets counter */
+	u16		pp_loopcnt;	/* loopback detection counter */
+	u32		pp_seq;		/* local sequence number */
+	u32		pp_rseq;	/* remote sequence number */
+	struct slcp	lcp;		/* LCP params */
+	struct sipcp	ipcp;		/* IPCP params */
+	u32		ibytes,obytes;	/* Bytes in/out */
+	u32		ipkts,opkts;	/* Packets in/out */
+	struct timer_list	pp_timer;
+	struct device	*pp_if;
+};
+
+struct ppp_device
+{	
+	struct device dev;	/* Network device */
+	struct sppp sppp;	/* Synchronous PPP */
+};
+
+#define PP_KEEPALIVE    0x01    /* use keepalive protocol */
+#define PP_CISCO        0x02    /* use Cisco protocol instead of PPP */
+#define PP_TIMO         0x04    /* cp_timeout routine active */
+#define PP_DEBUG	0x08
+
+#define PPP_MTU          1500    /* max. transmit unit */
+
+#define LCP_STATE_CLOSED        0       /* LCP state: closed (conf-req sent) */
+#define LCP_STATE_ACK_RCVD      1       /* LCP state: conf-ack received */
+#define LCP_STATE_ACK_SENT      2       /* LCP state: conf-ack sent */
+#define LCP_STATE_OPENED        3       /* LCP state: opened */
+
+#define IPCP_STATE_CLOSED       0       /* IPCP state: closed (conf-req sent) */
+#define IPCP_STATE_ACK_RCVD     1       /* IPCP state: conf-ack received */
+#define IPCP_STATE_ACK_SENT     2       /* IPCP state: conf-ack sent */
+#define IPCP_STATE_OPENED       3       /* IPCP state: opened */
+
+#ifdef __KERNEL__
+void sppp_attach (struct ppp_device *pd);
+void sppp_detach (struct device *dev);
+void sppp_input (struct device *dev, struct sk_buff *m);
+int sppp_do_ioctl (struct device *dev, struct ifreq *ifr, int cmd);
+struct sk_buff *sppp_dequeue (struct device *dev);
+int sppp_isempty (struct device *dev);
+void sppp_flush (struct device *dev);
+int sppp_open (struct device *dev);
+int sppp_close (struct device *dev);
+#endif
+
+#define SPPPIOCCISCO	(SIOCDEVPRIVATE)
+#define SPPPIOCPPP	(SIOCDEVPRIVATE+1)
+
+#endif /* _SYNCPPP_H_ */
diff -u --recursive --new-file v2.1.120/linux/drivers/net/z85230.c linux/drivers/net/z85230.c
--- v2.1.120/linux/drivers/net/z85230.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/z85230.c	Tue Sep  8 23:20:41 1998
@@ -0,0 +1,1204 @@
+/*
+ *	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.
+ *
+ *	(c) Copyright 1998 Building Number Three Ltd
+ *
+ *	Development of this driver was funded by Equiinet Ltd
+ *			http://www.equiinet.com
+ *
+ *	ChangeLog:
+ *
+ *	Asynchronous mode dropped for 2.2. For 2.3 we will attempt the
+ *	unification of all the Z85x30 asynchronous drivers for real.
+ *
+ *	To Do:
+ *	
+ *	Finish DMA mode support.
+ *
+ *	Performance
+ *
+ *	Z85230:
+ *	Non DMA you want a 486DX50 or better to do 64Kbits. 9600 baud
+ *	X.25 is not unrealistic on all machines. DMA mode can in theory
+ *	handle T1/E1 quite nicely.
+ *
+ *	Z85C30:
+ *	64K will take DMA, 9600 baud X.25 should be ok.
+ *
+ *	Z8530:
+ *	Synchronous mode without DMA is unlikely to pass about 2400 baud.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/net.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#define RT_LOCK
+#define RT_UNLOCK
+#include <asm/spinlock.h>
+
+#include "z85230.h"
+
+
+static spinlock_t z8530_buffer_lock = SPIN_LOCK_UNLOCKED;
+
+/*
+ *	Provided port access methods. The Comtrol SV11 requires no delays
+ *	between accesses and uses PC I/O. Some drivers may need a 5uS delay
+ */
+
+extern __inline__ int z8530_read_port(int p)
+{
+	u8 r=inb(Z8530_PORT_OF(p));
+	if(p&Z8530_PORT_SLEEP)	/* gcc should figure this out efficiently ! */
+		udelay(5);
+	return r;
+}
+
+extern __inline__ void z8530_write_port(int p, u8 d)
+{
+	outb(d,Z8530_PORT_OF(p));
+	if(p&Z8530_PORT_SLEEP)
+		udelay(5);
+}
+
+
+
+static void z8530_rx_done(struct z8530_channel *c);
+static void z8530_tx_done(struct z8530_channel *c);
+
+
+/*
+ *	Port accesses
+ */
+ 
+extern inline u8 read_zsreg(struct z8530_channel *c, u8 reg)
+{
+	u8 r;
+	unsigned long flags;
+	save_flags(flags);
+	cli();
+	if(reg)
+		z8530_write_port(c->ctrlio, reg);
+	r=z8530_read_port(c->ctrlio);
+	restore_flags(flags);
+	return r;
+}
+
+extern inline u8 read_zsdata(struct z8530_channel *c)
+{
+	u8 r;
+	r=z8530_read_port(c->dataio);
+	return r;
+}
+
+extern inline void write_zsreg(struct z8530_channel *c, u8 reg, u8 val)
+{
+	unsigned long flags;
+	save_flags(flags);
+	cli();
+	if(reg)
+		z8530_write_port(c->ctrlio, reg);
+	z8530_write_port(c->ctrlio, val);
+	restore_flags(flags);
+}
+
+extern inline void write_zsctrl(struct z8530_channel *c, u8 val)
+{
+	z8530_write_port(c->ctrlio, val);
+}
+
+extern inline void write_zsdata(struct z8530_channel *c, u8 val)
+{
+	z8530_write_port(c->dataio, val);
+}
+
+/*
+ *	Register loading parameters for a dead port
+ */
+ 
+u8 z8530_dead_port[]=
+{
+	255
+};
+
+EXPORT_SYMBOL(z8530_dead_port);
+
+/*
+ *	Register loading parameters for currently supported circuit types
+ */
+
+
+/*
+ *	Data clocked by telco end. This is the correct data for the UK
+ *	"kilostream" service, and most other similar services.
+ */
+ 
+u8 z8530_hdlc_kilostream[]=
+{
+	4,	SYNC_ENAB|SDLC|X1CLK,
+	2,	0,	/* No vector */
+	1,	0,
+	3,	ENT_HM|RxCRC_ENAB|Rx8,
+	5,	TxCRC_ENAB|RTS|TxENAB|Tx8|DTR,
+	9,	0,		/* Disable interrupts */
+	7,	FLAG,
+	10,	ABUNDER|MARKIDLE|NRZ|CRCPS,
+	11,	TCTRxCP,
+	14,	DISDPLL,
+	15,	DCDIE|SYNCIE|CTSIE|TxUIE|BRKIE,
+	1,	EXT_INT_ENAB|TxINT_ENAB|INT_ALL_Rx,
+	9,	NV|MIE|NORESET,
+	255
+};
+
+EXPORT_SYMBOL(z8530_hdlc_kilostream);
+
+/*
+ *	As above but for enhanced chips.
+ */
+
+u8 z8530_hdlc_kilostream_85230[]=
+{
+	4,	SYNC_ENAB|SDLC|X1CLK,
+	2,	0,	/* No vector */
+	1,	0,
+	3,	ENT_HM|RxCRC_ENAB|Rx8,
+	5,	TxCRC_ENAB|RTS|TxENAB|Tx8|DTR,
+	9,	0,		/* Disable interrupts */
+	7,	FLAG,
+	10,	ABUNDER|MARKIDLE|NRZ|CRCPS,
+	11,	TCTRxCP,
+	14,	DISDPLL,
+	15,	DCDIE|SYNCIE|CTSIE|TxUIE|BRKIE,
+	1,	EXT_INT_ENAB|TxINT_ENAB|INT_ALL_Rx,
+	9,	NV|MIE|NORESET,
+	23,	3,		/* Extended mode AUTO TX and EOM*/
+	31,	3,		/* Extended mode AUTO TX and EOM*/
+	
+	255
+};
+
+EXPORT_SYMBOL(z8530_hdlc_kilostream_85230);
+
+/*
+ *	Flush the FIFO
+ */
+ 
+static void z8530_flush_fifo(struct z8530_channel *c)
+{
+	read_zsreg(c, R1);
+	read_zsreg(c, R1);
+	read_zsreg(c, R1);
+	read_zsreg(c, R1);
+	if(c->dev->type==Z85230)
+	{
+		read_zsreg(c, R1);
+		read_zsreg(c, R1);
+		read_zsreg(c, R1);
+		read_zsreg(c, R1);
+	}
+}	
+
+/* Sets or clears DTR/RTS on the requested line */
+
+static void z8530_rtsdtr(struct z8530_channel *c, int set)
+{
+	if (set)
+		c->regs[5] |= (RTS | DTR);
+	else
+		c->regs[5] &= ~(RTS | DTR);
+	write_zsreg(c, R5, c->regs[5]);
+}
+
+/*
+ *	Receive handler. This is much like the async one but not quite the
+ *	same or as complex
+ *
+ *	Note: Its intended that this handler can easily be seperated from
+ *	the main code to run realtime. That'll be needed for some machines
+ *	(eg to ever clock 64kbits on a sparc ;)).
+ *
+ *	The RT_LOCK macros don't do anything now. Keep the code covered
+ *	by them as short as possible in all circumstances - clocks cost
+ *	baud. The interrupt handler is assumed to be atomic w.r.t. to
+ *	other code - this is true in the RT case too.
+ *
+ *	We only cover the sync cases for this. If you want 2Mbit async
+ *	do it yourself but consider medical assistance first.
+ *
+ *	This non DMA synchronous mode is portable code.
+ */
+ 
+static void z8530_rx(struct z8530_channel *c)
+{
+	u8 ch,stat;
+	 
+	while(1)
+	{
+		/* FIFO empty ? */
+		if(!(read_zsreg(c, R0)&1))
+			break;
+		ch=read_zsdata(c);
+		stat=read_zsreg(c, R1);
+	
+		/*
+		 *	Overrun ?
+		 */
+		if(c->count < c->max)
+		{
+			*c->dptr++=ch;
+			c->count++;
+		}
+
+		if(stat&END_FR)
+		{
+		
+			/*
+			 *	Error ?
+			 */
+			if(stat&(Rx_OVR|CRC_ERR))
+			{
+				/* Rewind the buffer and return */
+				if(c->skb)
+					c->dptr=c->skb->data;
+				c->count=0;
+				if(stat&Rx_OVR)
+				{
+					printk(KERN_WARNING "%s: overrun\n", c->dev->name);
+					c->rx_overrun++;
+				}
+				if(stat&CRC_ERR)
+				{
+					c->rx_crc_err++;
+					/* printk("crc error\n"); */
+				}
+				/* Shove the frame upstream */
+			}
+			else
+			{
+				z8530_rx_done(c);
+				write_zsctrl(c, RES_Rx_CRC);
+			}
+		}
+	}
+	/*
+	 *	Clear irq
+	 */
+	write_zsctrl(c, ERR_RES);
+	write_zsctrl(c, RES_H_IUS);
+}
+
+
+/*
+ *	Z8530 transmit interrupt handler
+ */
+ 
+static void z8530_tx(struct z8530_channel *c)
+{
+	while(c->txcount)
+	{
+		/* FIFO full ? */
+		if(!(read_zsreg(c, R0)&4))
+			break;
+		c->txcount--;
+		/*
+		 *	Shovel out the byte
+		 */
+		write_zsreg(c, R8, *c->tx_ptr++);
+		write_zsctrl(c, RES_H_IUS);
+		/* We are about to underflow */
+		if(c->txcount==0)
+		{
+			write_zsctrl(c, RES_EOM_L);
+			write_zsreg(c, R10, c->regs[10]&~ABUNDER);
+		}
+		return;
+	}
+	
+	/*
+	 *	End of frame TX - fire another one
+	 */
+	 
+	write_zsctrl(c, RES_Tx_P);
+
+	z8530_tx_done(c);	 
+/*	write_zsreg(c, R8, *c->tx_ptr++); */
+	write_zsctrl(c, RES_H_IUS);
+}
+
+static void z8530_status(struct z8530_channel *chan)
+{
+	u8 status=read_zsreg(chan, R0);
+	u8 altered=chan->status^status;
+	
+	chan->status=status;
+	
+	if(status&TxEOM)
+	{
+/*		printk("%s: Tx underrun.\n", chan->dev->name); */
+		write_zsctrl(chan, ERR_RES);
+		z8530_tx_done(chan);
+	}
+		
+	if(altered&DCD)
+	{
+		if(status&DCD)
+		{
+			printk(KERN_INFO "%s: DCD raised\n", chan->dev->name);
+			write_zsreg(chan, R3, chan->regs[3]|RxENABLE);
+		}
+		else
+		{
+			printk(KERN_INFO "%s: DCD lost\n", chan->dev->name);
+			write_zsreg(chan, R3, chan->regs[3]&~RxENABLE);
+			z8530_flush_fifo(chan);
+		}
+		
+	}	
+	write_zsctrl(chan, RES_EXT_INT);
+	write_zsctrl(chan, RES_H_IUS);
+}
+
+struct z8530_irqhandler z8530_sync=
+{
+	z8530_rx,
+	z8530_tx,
+	z8530_status
+};
+
+EXPORT_SYMBOL(z8530_sync);
+
+/*
+ *	Non bus mastering DMA interfaces for the Z8x30 devices. This
+ *	is really pretty PC specific.
+ */
+ 
+static void z8530_dma_rx(struct z8530_channel *chan)
+{
+	if(chan->rxdma_on)
+	{
+		/* Special condition check only */
+		u8 status=read_zsreg(chan, R1);
+		if(status&END_FR)
+		{
+			z8530_rx_done(chan);	/* Fire up the next one */
+		}		
+		write_zsctrl(chan, ERR_RES);
+		write_zsctrl(chan, RES_H_IUS);
+	}
+	else
+	{
+		/* DMA is off right now, drain the slow way */
+		z8530_rx(chan);
+	}	
+}
+
+static void z8530_dma_tx(struct z8530_channel *chan)
+{
+	if(!chan->txdma_on)
+	{
+		z8530_tx(chan);
+		return;
+	}
+	/* This shouldnt occur in DMA mode */
+	printk(KERN_ERR "DMA tx ??\n");
+	z8530_tx(chan);
+}
+
+static void z8530_dma_status(struct z8530_channel *chan)
+{
+	u8 status=read_zsreg(chan, R0);
+	u8 altered=chan->status^status;
+	
+	chan->status=status;
+
+	if(chan->txdma_on)
+	{
+		if(status&TxEOM)
+		{
+			/* Transmit underrun */
+			disable_dma(chan->txdma);
+			clear_dma_ff(chan->txdma);	
+			chan->txdma_on=0;
+			z8530_tx_done(chan);
+		}
+	}
+	if(altered&DCD)
+	{
+		if(status&DCD)
+		{
+			printk(KERN_INFO "%s: DCD raised\n", chan->dev->name);
+			write_zsreg(chan, R3, chan->regs[3]|RxENABLE);
+		}
+		else
+		{
+			printk(KERN_INFO "%s:DCD lost\n", chan->dev->name);
+			write_zsreg(chan, R3, chan->regs[3]&~RxENABLE);
+			z8530_flush_fifo(chan);
+		}
+	}	
+	write_zsctrl(chan, RES_EXT_INT);
+	write_zsctrl(chan, RES_H_IUS);
+}
+
+struct z8530_irqhandler z8530_dma_sync=
+{
+	z8530_dma_rx,
+	z8530_dma_tx,
+	z8530_dma_status
+};
+
+EXPORT_SYMBOL(z8530_dma_sync);
+
+/*
+ *	Interrupt vectors for a Z8530 that is in 'parked' mode.
+ *	For machines with PCI Z85x30 cards, or level triggered interrupts
+ *	(eg the MacII) we must clear the interrupt cause or die.
+ */
+
+
+static void z8530_rx_clear(struct z8530_channel *c)
+{
+	/*
+	 *	Data and status bytes
+	 */
+	u8 stat;
+
+	read_zsdata(c);
+	stat=read_zsreg(c, R1);
+	
+	if(stat&END_FR)
+		write_zsctrl(c, RES_Rx_CRC);
+	/*
+	 *	Clear irq
+	 */
+	write_zsctrl(c, ERR_RES);
+	write_zsctrl(c, RES_H_IUS);
+}
+
+static void z8530_tx_clear(struct z8530_channel *c)
+{
+	write_zsctrl(c, RES_Tx_P);
+	write_zsctrl(c, RES_H_IUS);
+}
+
+static void z8530_status_clear(struct z8530_channel *chan)
+{
+	u8 status=read_zsreg(chan, R0);
+	if(status&TxEOM)
+		write_zsctrl(chan, ERR_RES);
+	write_zsctrl(chan, RES_EXT_INT);
+	write_zsctrl(chan, RES_H_IUS);
+}
+
+struct z8530_irqhandler z8530_nop=
+{
+	z8530_rx_clear,
+	z8530_tx_clear,
+	z8530_status_clear
+};
+
+
+EXPORT_SYMBOL(z8530_nop);
+
+/*
+ *	A Z85[2]30 device has stuck its hand in the air for attention
+ */
+
+void z8530_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct z8530_dev *dev=dev_id;
+	u8 intr;
+	static volatile int locker=0;
+	int work=0;
+	
+	if(locker)
+	{
+		printk(KERN_ERR "IRQ re-enter\n");
+		return;
+	}
+	locker=1;
+	
+	while(++work<5000)
+	{
+		struct z8530_irqhandler *irqs=dev->chanA.irqs;
+		
+		intr = read_zsreg(&dev->chanA, R3);
+		if(!(intr & (CHARxIP|CHATxIP|CHAEXT|CHBRxIP|CHBTxIP|CHBEXT)))
+			break;
+	
+		/* This holds the IRQ status. On the 8530 you must read it from chan 
+		   A even though it applies to the whole chip */
+		
+		/* Now walk the chip and see what it is wanting - it may be
+		   an IRQ for someone else remember */
+		   
+		if(intr & (CHARxIP|CHATxIP|CHAEXT))
+		{
+			if(intr&CHARxIP)
+				irqs->rx(&dev->chanA);
+			if(intr&CHATxIP)
+				irqs->tx(&dev->chanA);
+			if(intr&CHAEXT)
+				irqs->status(&dev->chanA);
+		}
+
+		irqs=dev->chanB.irqs;
+
+		if(intr & (CHBRxIP|CHBTxIP|CHBEXT))
+		{
+			if(intr&CHBRxIP)
+				irqs->rx(&dev->chanB);
+			if(intr&CHBTxIP)
+				irqs->tx(&dev->chanB);
+			if(intr&CHBEXT)
+				irqs->status(&dev->chanB);
+		}
+	}
+	if(work==200)
+		printk(KERN_ERR "%s: interrupt jammed - abort(0x%X)!\n", dev->name, intr);
+	/* Ok all done */
+	locker=0;
+}
+
+EXPORT_SYMBOL(z8530_interrupt);
+
+static char reg_init[16]=
+{
+	0,0,0,0,
+	0,0,0,0,
+	0,0,0,0,
+	0x55,0,0,0
+};
+
+
+int z8530_sync_open(struct device *dev, struct z8530_channel *c)
+{
+	c->sync = 1;
+	c->mtu = dev->mtu;
+	c->count = 0;
+	c->skb = NULL;
+	c->skb2 = NULL;
+	c->irqs = &z8530_sync;
+	/* This loads the double buffer up */
+	z8530_rx_done(c);	/* Load the frame ring */
+	z8530_rx_done(c);	/* Load the backup frame */
+	z8530_rtsdtr(c,1);
+	write_zsreg(c, R3, c->regs[R3]|RxENABLE);
+	return 0;
+}
+
+
+EXPORT_SYMBOL(z8530_sync_open);
+
+int z8530_sync_close(struct device *dev, struct z8530_channel *c)
+{
+	u8 chk;
+	c->irqs = &z8530_nop;
+	c->max = 0;
+	c->sync = 0;
+	
+	chk=read_zsreg(c,R0);
+	write_zsreg(c, R3, c->regs[R3]);
+	z8530_rtsdtr(c,0);
+	return 0;
+}
+
+EXPORT_SYMBOL(z8530_sync_close);
+
+int z8530_sync_dma_open(struct device *dev, struct z8530_channel *c)
+{
+	c->sync = 1;
+	c->mtu = dev->mtu;
+	c->count = 0;
+	c->skb = NULL;
+	c->skb2 = NULL;
+	/*
+	 *	Load the DMA interfaces up
+	 */
+	c->rxdma_on = 0;
+	c->txdma_on = 0;
+	
+	/*
+	 *	Allocate the DMA flip buffers
+	 */
+	 
+	c->rx_buf[0]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA);
+	if(c->rx_buf[0]==NULL)
+		return -ENOBUFS;
+	c->rx_buf[1]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA);
+	if(c->rx_buf[1]==NULL)
+	{
+		kfree(c->rx_buf[0]);
+		c->rx_buf[0]=NULL;
+		return -ENOBUFS;
+	}
+	
+	c->tx_dma_buf[0]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA);
+	if(c->tx_dma_buf[0]==NULL)
+	{
+		kfree(c->rx_buf[0]);
+		kfree(c->rx_buf[1]);
+		c->rx_buf[0]=NULL;
+		return -ENOBUFS;
+	}
+	c->tx_dma_buf[1]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA);
+	if(c->tx_dma_buf[1]==NULL)
+	{
+		kfree(c->tx_dma_buf[0]);
+		kfree(c->rx_buf[0]);
+		kfree(c->rx_buf[1]);
+		c->rx_buf[0]=NULL;
+		c->rx_buf[1]=NULL;
+		c->tx_dma_buf[0]=NULL;
+		return -ENOBUFS;
+	}
+	c->tx_dma_used=0;
+	c->dma_num=0;
+	c->dma_ready=1;
+	
+	/*
+	 *	Enable DMA control mode
+	 */
+	 
+	c->regs[R1]|= WT_RDY_RT|WT_FN_RDYFN;
+	c->regs[R1]|= INT_ERR_Rx;
+	write_zsreg(c, R1, c->regs[R1]);
+	c->regs[R1]|= WT_RDY_ENAB;
+	write_zsreg(c, R1, c->regs[R1]);            
+	c->regs[R14]|= DTRREQ;
+	write_zsreg(c, R14, c->regs[R14]);     
+	
+	/*
+	 *	DMA interrupts
+	 */
+	 
+	/*
+	 *	Set up the DMA configuration
+	 */	
+	 
+	disable_dma(c->rxdma);
+	clear_dma_ff(c->rxdma);
+	set_dma_mode(c->rxdma, DMA_MODE_READ);
+	set_dma_addr(c->rxdma, virt_to_bus(c->rx_buf[0]));
+	set_dma_count(c->rxdma, c->mtu);
+	enable_dma(c->rxdma);
+
+	disable_dma(c->txdma);
+	clear_dma_ff(c->txdma);
+	set_dma_mode(c->txdma, DMA_MODE_WRITE);
+	disable_dma(c->txdma);
+	
+	/*
+	 *	Select the DMA interrupt handlers
+	 */
+
+	c->rxdma_on = 1;
+	c->txdma_on = 1;
+	c->tx_dma_used = 1;
+	 
+	c->irqs = &z8530_dma_sync;
+	z8530_rtsdtr(c,1);
+	write_zsreg(c, R3, c->regs[R3]|RxENABLE);
+	return 0;
+}
+
+EXPORT_SYMBOL(z8530_sync_dma_open);
+
+int z8530_sync_dma_close(struct device *dev, struct z8530_channel *c)
+{
+	u8 chk;
+	c->irqs = &z8530_nop;
+	c->max = 0;
+	c->sync = 0;
+	
+	/*
+	 *	Disable the PC DMA channels
+	 */
+	 
+	disable_dma(c->rxdma);
+	clear_dma_ff(c->rxdma);
+	c->rxdma_on = 0;
+	disable_dma(c->txdma);
+	clear_dma_ff(c->txdma);
+	c->txdma_on = 0;
+	c->tx_dma_used = 0;
+
+	/*
+	 *	Disable DMA control mode
+	 */
+	 
+	c->regs[R1]&= ~WT_RDY_ENAB;
+	write_zsreg(c, R1, c->regs[R1]);            
+	c->regs[R1]&= ~(WT_RDY_RT|WT_FN_RDYFN|INT_ERR_Rx);
+	c->regs[R1]|= INT_ALL_Rx;
+	write_zsreg(c, R1, c->regs[R1]);
+	c->regs[R14]&= ~DTRREQ;
+	write_zsreg(c, R14, c->regs[R14]);   
+	
+	if(c->rx_buf[0])
+	{
+		kfree(c->rx_buf[0]);
+		c->rx_buf[0]=NULL;
+	}
+	if(c->rx_buf[1])
+	{
+		kfree(c->rx_buf[1]);
+		c->rx_buf[1]=NULL;
+	}
+	if(c->tx_dma_buf[0])
+	{
+		kfree(c->tx_dma_buf[0]);
+		c->tx_dma_buf[0]=NULL;
+	}
+	if(c->tx_dma_buf[1])
+	{
+		kfree(c->tx_dma_buf[1]);
+		c->tx_dma_buf[1]=NULL;
+	}
+	chk=read_zsreg(c,R0);
+	write_zsreg(c, R3, c->regs[R3]);
+	z8530_rtsdtr(c,0);
+	return 0;
+}
+
+EXPORT_SYMBOL(z8530_sync_dma_close);
+
+/*
+ *	Describe a Z8530 in a standard format. We must pass the I/O as
+ *	the port offset isnt predictable. The main reason for this function
+ *	is to try and get a common format of report.
+ */
+
+static char *z8530_type_name[]={
+	"Z8530",
+	"Z85C30",
+	"Z85230"
+};
+
+void z8530_describe(struct z8530_dev *dev, char *mapping, int io)
+{
+	printk(KERN_INFO "%s: %s found at %s 0x%X, IRQ %d.\n",
+		dev->name, 
+		z8530_type_name[dev->type],
+		mapping,
+		io,
+		dev->irq);
+}
+
+EXPORT_SYMBOL(z8530_describe);
+
+/*
+ *	Configure up a Z8530
+ */
+
+ 
+int z8530_init(struct z8530_dev *dev)
+{
+	/* NOP the interrupt handlers first - we might get a
+	   floating IRQ transition when we reset the chip */
+	dev->chanA.irqs=&z8530_nop;
+	dev->chanB.irqs=&z8530_nop;
+	/* Reset the chip */
+	write_zsreg(&dev->chanA, R9, 0xC0);
+	udelay(100);
+	/* Now check its valid */
+	write_zsreg(&dev->chanA, R12, 0xAA);
+	if(read_zsreg(&dev->chanA, R12)!=0xAA)
+		return -ENODEV;
+	write_zsreg(&dev->chanA, R12, 0x55);
+	if(read_zsreg(&dev->chanA, R12)!=0x55)
+		return -ENODEV;
+		
+	dev->type=Z8530;
+	
+	/*
+	 *	See the application note.
+	 */
+	 
+	write_zsreg(&dev->chanA, R15, 0x01);
+	
+	/*
+	 *	If we can set the low bit of R15 then
+	 *	the chip is enhanced.
+	 */
+	 
+	if(read_zsreg(&dev->chanA, R15)==0x01)
+	{
+		/* This C30 versus 230 detect is from Klaus Kudielka's dmascc */
+		/* Put a char in the fifo */
+		write_zsreg(&dev->chanA, R8, 0);
+		if(read_zsreg(&dev->chanA, R0)&Tx_BUF_EMP)
+			dev->type = Z85230;	/* Has a FIFO */
+		else
+			dev->type = Z85C30;	/* Z85C30, 1 byte FIFO */
+	}
+		
+	/*
+	 *	The code assumes R7' and friends are
+	 *	off. Use write_zsext() for these and keep
+	 *	this bit clear.
+	 */
+	 
+	write_zsreg(&dev->chanA, R15, 0);
+		
+	/*
+	 *	At this point it looks like the chip is behaving
+	 */
+	 
+	memcpy(dev->chanA.regs, reg_init, 16);
+	memcpy(dev->chanB.regs, reg_init ,16);
+	
+	return 0;
+}
+
+
+EXPORT_SYMBOL(z8530_init);
+
+int z8530_shutdown(struct z8530_dev *dev)
+{
+	/* Reset the chip */
+	dev->chanA.irqs=&z8530_nop;
+	dev->chanB.irqs=&z8530_nop;
+	write_zsreg(&dev->chanA, R9, 0xC0);
+	udelay(100);
+	return 0;
+}
+
+EXPORT_SYMBOL(z8530_shutdown);
+
+/*
+ *	Load a Z8530 channel up from the system data
+ *	We use +16 to indicate the 'prime' registers
+ */
+
+int z8530_channel_load(struct z8530_channel *c, u8 *rtable)
+{
+	while(*rtable!=255)
+	{
+		int reg=*rtable++;
+		if(reg>0x0F)
+			write_zsreg(c, R15, c->regs[15]|1);
+		write_zsreg(c, reg&0x0F, *rtable);
+		if(reg>0x0F)
+			write_zsreg(c, R15, c->regs[15]&~1);
+		c->regs[reg]=*rtable++;
+	}
+	c->rx_function=z8530_null_rx;
+	c->skb=NULL;
+	c->tx_skb=NULL;
+	c->tx_next_skb=NULL;
+	c->mtu=1500;
+	c->max=0;
+	c->count=0;
+	c->status=0;	/* Fixme - check DCD now */
+	c->sync=1;
+	write_zsreg(c, R3, c->regs[R3]|RxENABLE);
+	return 0;
+}
+
+EXPORT_SYMBOL(z8530_channel_load);
+
+
+/*
+ *	Higher level shovelling - transmit chains
+ */
+
+static void z8530_tx_begin(struct z8530_channel *c)
+{
+	unsigned long flags;
+	if(c->tx_skb)
+		return;
+		
+	c->tx_skb=c->tx_next_skb;
+	c->tx_next_skb=NULL;
+	c->tx_ptr=c->tx_next_ptr;
+	
+	mark_bh(NET_BH);
+	if(c->tx_skb==NULL)
+	{
+		/* Idle on */
+		disable_dma(c->txdma);
+		c->txcount=0;
+	}
+	else
+	{
+		c->tx_ptr=c->tx_next_ptr;
+		c->txcount=c->tx_skb->len;
+		
+		
+		if(c->tx_dma_used)
+		{
+			/*
+			 *	FIXME. DMA is broken for the non 85230,
+			 *	on the older parts we need to set a flag and
+			 *	wait for a further TX interrupt to fire this
+			 *	stage off	
+			 */
+			disable_dma(c->txdma);
+			clear_dma_ff(c->txdma);
+			set_dma_addr(c->txdma, virt_to_bus(c->tx_ptr));
+			set_dma_count(c->txdma, c->txcount);
+			enable_dma(c->txdma);
+			write_zsreg(c, R5, c->regs[R5]|TxENAB);
+		}
+		else
+		{
+			save_flags(flags);
+			cli();
+			/* ABUNDER off */
+			write_zsreg(c, R10, c->regs[10]);
+			write_zsctrl(c, RES_Tx_CRC);
+			write_zsctrl(c, RES_EOM_L);
+	
+			while(c->txcount && (read_zsreg(c,R0)&Tx_BUF_EMP))
+			{		
+				write_zsreg(c, R8, *c->tx_ptr++);
+				c->txcount--;
+			}
+			restore_flags(flags);
+		}
+	}
+}
+ 
+ 
+static void z8530_tx_done(struct z8530_channel *c)
+{
+	unsigned long flags;
+	struct sk_buff *skb;
+
+	spin_lock_irqsave(&z8530_buffer_lock, flags);
+	c->netdevice->tbusy=0;
+	/* Can't happen */
+	if(c->tx_skb==NULL)
+	{
+		spin_unlock_irqrestore(&z8530_buffer_lock, flags);
+		printk(KERN_WARNING "%s: spurious tx done\n", c->dev->name);
+		return;
+	}
+	skb=c->tx_skb;
+	c->tx_skb=NULL;
+	z8530_tx_begin(c);
+	spin_unlock_irqrestore(&z8530_buffer_lock, flags);
+	dev_kfree_skb(skb);
+}
+
+/*
+ *	Higher level shovelling - receive chains
+ */
+ 
+void z8530_null_rx(struct z8530_channel *c, struct sk_buff *skb)
+{
+	kfree_skb(skb);
+}
+
+EXPORT_SYMBOL(z8530_null_rx);
+
+static void z8530_rx_done(struct z8530_channel *c)
+{
+	struct sk_buff *skb;
+	int ct;
+	
+	/*
+	 *	Is our receive engine in DMA mode
+	 */
+	 
+	if(c->rxdma_on)
+	{
+		/*
+		 *	Save the ready state and the buffer currently
+		 *	being used as the DMA target
+		 */
+		int ready=c->dma_ready;
+		char *rxb=c->rx_buf[c->dma_num];
+		
+		/*
+		 *	Complete this DMA. Neccessary to find the length
+		 */		
+		disable_dma(c->rxdma);
+		clear_dma_ff(c->rxdma);
+		c->rxdma_on=0;
+		ct=c->mtu-get_dma_residue(c->rxdma)-4;
+		if(ct<0)
+			ct=2;	/* Shit happens.. */
+		c->dma_ready=0;
+		
+		/*
+		 *	Normal case: the other slot is free, start the next DMA
+		 *	into it immediately.
+		 */
+		 
+		if(ready)
+		{
+			c->dma_num^=1;
+			set_dma_mode(c->rxdma, DMA_MODE_READ);
+			set_dma_addr(c->rxdma, virt_to_bus(c->rx_buf[c->dma_num]));
+			set_dma_count(c->rxdma, c->mtu);
+			c->rxdma_on = 1;
+			enable_dma(c->rxdma);
+		}
+		else
+			/* Can't occur as we dont reenable the DMA irq until
+			   after the flip is done */
+			printk("DMA flip overrun!\n");
+		
+		/*
+		 *	Shove the old buffer into an sk_buff. We can't DMA
+		 *	directly into one on a PC - it might be above the 16Mb
+		 *	boundary. Optimisation - we could check to see if we
+		 *	can avoid the copy. Optimisation 2 - make the memcpy
+		 *	a copychecksum.
+		 */
+		 
+		skb=dev_alloc_skb(ct);
+		if(skb==NULL)
+			printk("%s: Memory squeeze.\n", c->netdevice->name);
+		else
+		{
+			skb_put(skb, ct);
+			memcpy(skb->data, rxb, ct);
+			skb_pull(skb,2);
+		}
+		c->dma_ready=1;
+	}
+	else
+	{
+		RT_LOCK;	
+		skb=c->skb;
+		
+		/*
+		 *	The game we play for non DMA is similar. We want to
+		 *	get the controller set up for the next packet as fast
+		 *	as possible. We potentially only have one byte + the
+		 *	fifo length for this. Thus we want to flip to the new
+		 *	buffer and then mess around copying and allocating
+		 *	things. For the current case it doesn't matter but
+		 *	if you build a system where the sync irq isnt blocked
+		 *	by the kernel IRQ disable then you need only block the
+		 *	sync IRQ for the RT_LOCK area.
+		 *	
+		 */
+		ct=c->count;
+		
+		c->skb = c->skb2;
+		c->count = 0;
+		c->max = c->mtu;
+		if(c->skb)
+		{
+			c->dptr = c->skb->data;
+			c->max = c->mtu;
+		}
+		else
+		{
+			c->count= 0;
+			c->max = 0;
+		}
+		RT_UNLOCK;
+
+		c->skb2 = dev_alloc_skb(c->mtu);
+		if(c->skb2==NULL)
+			printk(KERN_WARNING "%s: memory squeeze.\n",
+				c->netdevice->name);
+		else
+		{
+			skb_put(c->skb2,c->mtu);
+		}
+	}
+	/*
+	 *	If we received a frame we must now process it.
+	 */
+	if(skb)
+	{
+		skb_trim(skb, ct);
+		c->rx_function(c,skb);
+	}
+	else
+		printk("Lost a frame\n");
+}
+
+
+/*
+ *	Queue a packet for transmission. Because we have rather
+ *	hard to hit interrupt latencies for the Z85230 per packet 
+ *	even in DMA mode we do the flip to DMA buffer if needed here
+ *	not in the IRQ.
+ */
+
+int z8530_queue_xmit(struct z8530_channel *c, struct sk_buff *skb)
+{
+	unsigned long flags;
+	if(c->tx_next_skb)
+	{
+		skb->dev->tbusy=1;
+		return 1;
+	}
+	
+	/* PC SPECIFIC - DMA limits */
+	
+	/*
+	 *	If we will DMA the transmit and its gone over the ISA bus
+	 *	limit, then copy to the flip buffer
+	 */
+	 
+	if(c->dma_tx && (unsigned long)(virt_to_bus(skb->data+skb->len))>=16*1024*1024)
+	{
+		/* 
+		 *	Send the flip buffer, and flip the flippy bit.
+		 *	We don't care which is used when just so long as
+		 *	we never use the same buffer twice in a row. Since
+		 *	only one buffer can be going out at a time the other
+		 *	has to be safe.
+		 */
+		c->tx_next_ptr=c->tx_dma_buf[c->tx_dma_used];
+		c->tx_dma_used^=1;	/* Flip temp buffer */
+		memcpy(c->tx_next_ptr, skb->data, skb->len);
+	}
+	else
+		c->tx_next_ptr=skb->data;	
+	RT_LOCK;
+	c->tx_next_skb=skb;
+	RT_UNLOCK;
+	
+	spin_lock_irqsave(&z8530_buffer_lock, flags);
+	z8530_tx_begin(c);
+	spin_unlock_irqrestore(&z8530_buffer_lock, flags);
+	return 0;
+}
+
+EXPORT_SYMBOL(z8530_queue_xmit);
+
+struct net_device_stats *z8530_get_stats(struct z8530_channel *c)
+{
+	return &c->stats;
+}
+
+EXPORT_SYMBOL(z8530_get_stats);
+
+#ifdef MODULE
+
+/*
+ *	Module support
+ */
+ 
+int init_module(void)
+{
+	printk(KERN_INFO "Generic Z85C30/Z85230 interface driver v0.02\n");
+	return 0;
+}
+
+void cleanup_module(void)
+{
+}
+
+#endif
diff -u --recursive --new-file v2.1.120/linux/drivers/net/z85230.h linux/drivers/net/z85230.h
--- v2.1.120/linux/drivers/net/z85230.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/z85230.h	Sun Sep  6 10:47:01 1998
@@ -0,0 +1,444 @@
+/*
+ *	Description of Z8530 Z85C30 and Z85230 communications chips
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1998 Alan Cox <alan@redhat.com>
+ */
+
+#ifndef _Z8530_H
+#define _Z8530_H
+
+/* Conversion routines to/from brg time constants from/to bits
+ * per second.
+ */
+#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
+#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
+
+/* The Zilog register set */
+
+#define	FLAG	0x7e
+
+/* Write Register 0 */
+#define	R0	0		/* Register selects */
+#define	R1	1
+#define	R2	2
+#define	R3	3
+#define	R4	4
+#define	R5	5
+#define	R6	6
+#define	R7	7
+#define	R8	8
+#define	R9	9
+#define	R10	10
+#define	R11	11
+#define	R12	12
+#define	R13	13
+#define	R14	14
+#define	R15	15
+
+#define RPRIME	16		/* Indicate a prime register access on 230 */
+
+#define	NULLCODE	0	/* Null Code */
+#define	POINT_HIGH	0x8	/* Select upper half of registers */
+#define	RES_EXT_INT	0x10	/* Reset Ext. Status Interrupts */
+#define	SEND_ABORT	0x18	/* HDLC Abort */
+#define	RES_RxINT_FC	0x20	/* Reset RxINT on First Character */
+#define	RES_Tx_P	0x28	/* Reset TxINT Pending */
+#define	ERR_RES		0x30	/* Error Reset */
+#define	RES_H_IUS	0x38	/* Reset highest IUS */
+
+#define	RES_Rx_CRC	0x40	/* Reset Rx CRC Checker */
+#define	RES_Tx_CRC	0x80	/* Reset Tx CRC Checker */
+#define	RES_EOM_L	0xC0	/* Reset EOM latch */
+
+/* Write Register 1 */
+
+#define	EXT_INT_ENAB	0x1	/* Ext Int Enable */
+#define	TxINT_ENAB	0x2	/* Tx Int Enable */
+#define	PAR_SPEC	0x4	/* Parity is special condition */
+
+#define	RxINT_DISAB	0	/* Rx Int Disable */
+#define	RxINT_FCERR	0x8	/* Rx Int on First Character Only or Error */
+#define	INT_ALL_Rx	0x10	/* Int on all Rx Characters or error */
+#define	INT_ERR_Rx	0x18	/* Int on error only */
+
+#define	WT_RDY_RT	0x20	/* Wait/Ready on R/T */
+#define	WT_FN_RDYFN	0x40	/* Wait/FN/Ready FN */
+#define	WT_RDY_ENAB	0x80	/* Wait/Ready Enable */
+
+/* Write Register #2 (Interrupt Vector) */
+
+/* Write Register 3 */
+
+#define	RxENABLE	0x1	/* Rx Enable */
+#define	SYNC_L_INH	0x2	/* Sync Character Load Inhibit */
+#define	ADD_SM		0x4	/* Address Search Mode (SDLC) */
+#define	RxCRC_ENAB	0x8	/* Rx CRC Enable */
+#define	ENT_HM		0x10	/* Enter Hunt Mode */
+#define	AUTO_ENAB	0x20	/* Auto Enables */
+#define	Rx5		0x0	/* Rx 5 Bits/Character */
+#define	Rx7		0x40	/* Rx 7 Bits/Character */
+#define	Rx6		0x80	/* Rx 6 Bits/Character */
+#define	Rx8		0xc0	/* Rx 8 Bits/Character */
+
+/* Write Register 4 */
+
+#define	PAR_ENA		0x1	/* Parity Enable */
+#define	PAR_EVEN	0x2	/* Parity Even/Odd* */
+
+#define	SYNC_ENAB	0	/* Sync Modes Enable */
+#define	SB1		0x4	/* 1 stop bit/char */
+#define	SB15		0x8	/* 1.5 stop bits/char */
+#define	SB2		0xc	/* 2 stop bits/char */
+
+#define	MONSYNC		0	/* 8 Bit Sync character */
+#define	BISYNC		0x10	/* 16 bit sync character */
+#define	SDLC		0x20	/* SDLC Mode (01111110 Sync Flag) */
+#define	EXTSYNC		0x30	/* External Sync Mode */
+
+#define	X1CLK		0x0	/* x1 clock mode */
+#define	X16CLK		0x40	/* x16 clock mode */
+#define	X32CLK		0x80	/* x32 clock mode */
+#define	X64CLK		0xC0	/* x64 clock mode */
+
+/* Write Register 5 */
+
+#define	TxCRC_ENAB	0x1	/* Tx CRC Enable */
+#define	RTS		0x2	/* RTS */
+#define	SDLC_CRC	0x4	/* SDLC/CRC-16 */
+#define	TxENAB		0x8	/* Tx Enable */
+#define	SND_BRK		0x10	/* Send Break */
+#define	Tx5		0x0	/* Tx 5 bits (or less)/character */
+#define	Tx7		0x20	/* Tx 7 bits/character */
+#define	Tx6		0x40	/* Tx 6 bits/character */
+#define	Tx8		0x60	/* Tx 8 bits/character */
+#define	DTR		0x80	/* DTR */
+
+/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
+
+/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
+
+/* Write Register 8 (transmit buffer) */
+
+/* Write Register 9 (Master interrupt control) */
+#define	VIS	1	/* Vector Includes Status */
+#define	NV	2	/* No Vector */
+#define	DLC	4	/* Disable Lower Chain */
+#define	MIE	8	/* Master Interrupt Enable */
+#define	STATHI	0x10	/* Status high */
+#define	NORESET	0	/* No reset on write to R9 */
+#define	CHRB	0x40	/* Reset channel B */
+#define	CHRA	0x80	/* Reset channel A */
+#define	FHWRES	0xc0	/* Force hardware reset */
+
+/* Write Register 10 (misc control bits) */
+#define	BIT6	1	/* 6 bit/8bit sync */
+#define	LOOPMODE 2	/* SDLC Loop mode */
+#define	ABUNDER	4	/* Abort/flag on SDLC xmit underrun */
+#define	MARKIDLE 8	/* Mark/flag on idle */
+#define	GAOP	0x10	/* Go active on poll */
+#define	NRZ	0	/* NRZ mode */
+#define	NRZI	0x20	/* NRZI mode */
+#define	FM1	0x40	/* FM1 (transition = 1) */
+#define	FM0	0x60	/* FM0 (transition = 0) */
+#define	CRCPS	0x80	/* CRC Preset I/O */
+
+/* Write Register 11 (Clock Mode control) */
+#define	TRxCXT	0	/* TRxC = Xtal output */
+#define	TRxCTC	1	/* TRxC = Transmit clock */
+#define	TRxCBR	2	/* TRxC = BR Generator Output */
+#define	TRxCDP	3	/* TRxC = DPLL output */
+#define	TRxCOI	4	/* TRxC O/I */
+#define	TCRTxCP	0	/* Transmit clock = RTxC pin */
+#define	TCTRxCP	8	/* Transmit clock = TRxC pin */
+#define	TCBR	0x10	/* Transmit clock = BR Generator output */
+#define	TCDPLL	0x18	/* Transmit clock = DPLL output */
+#define	RCRTxCP	0	/* Receive clock = RTxC pin */
+#define	RCTRxCP	0x20	/* Receive clock = TRxC pin */
+#define	RCBR	0x40	/* Receive clock = BR Generator output */
+#define	RCDPLL	0x60	/* Receive clock = DPLL output */
+#define	RTxCX	0x80	/* RTxC Xtal/No Xtal */
+
+/* Write Register 12 (lower byte of baud rate generator time constant) */
+
+/* Write Register 13 (upper byte of baud rate generator time constant) */
+
+/* Write Register 14 (Misc control bits) */
+#define	BRENABL	1	/* Baud rate generator enable */
+#define	BRSRC	2	/* Baud rate generator source */
+#define	DTRREQ	4	/* DTR/Request function */
+#define	AUTOECHO 8	/* Auto Echo */
+#define	LOOPBAK	0x10	/* Local loopback */
+#define	SEARCH	0x20	/* Enter search mode */
+#define	RMC	0x40	/* Reset missing clock */
+#define	DISDPLL	0x60	/* Disable DPLL */
+#define	SSBR	0x80	/* Set DPLL source = BR generator */
+#define	SSRTxC	0xa0	/* Set DPLL source = RTxC */
+#define	SFMM	0xc0	/* Set FM mode */
+#define	SNRZI	0xe0	/* Set NRZI mode */
+
+/* Write Register 15 (external/status interrupt control) */
+#define PRIME	1	/* R5' etc register access (Z85C30/230 only) */
+#define	ZCIE	2	/* Zero count IE */
+#define FIFOE	4	/* Z85230 only */
+#define	DCDIE	8	/* DCD IE */
+#define	SYNCIE	0x10	/* Sync/hunt IE */
+#define	CTSIE	0x20	/* CTS IE */
+#define	TxUIE	0x40	/* Tx Underrun/EOM IE */
+#define	BRKIE	0x80	/* Break/Abort IE */
+
+
+/* Read Register 0 */
+#define	Rx_CH_AV	0x1	/* Rx Character Available */
+#define	ZCOUNT		0x2	/* Zero count */
+#define	Tx_BUF_EMP	0x4	/* Tx Buffer empty */
+#define	DCD		0x8	/* DCD */
+#define	SYNC_HUNT	0x10	/* Sync/hunt */
+#define	CTS		0x20	/* CTS */
+#define	TxEOM		0x40	/* Tx underrun */
+#define	BRK_ABRT	0x80	/* Break/Abort */
+
+/* Read Register 1 */
+#define	ALL_SNT		0x1	/* All sent */
+/* Residue Data for 8 Rx bits/char programmed */
+#define	RES3		0x8	/* 0/3 */
+#define	RES4		0x4	/* 0/4 */
+#define	RES5		0xc	/* 0/5 */
+#define	RES6		0x2	/* 0/6 */
+#define	RES7		0xa	/* 0/7 */
+#define	RES8		0x6	/* 0/8 */
+#define	RES18		0xe	/* 1/8 */
+#define	RES28		0x0	/* 2/8 */
+/* Special Rx Condition Interrupts */
+#define	PAR_ERR		0x10	/* Parity error */
+#define	Rx_OVR		0x20	/* Rx Overrun Error */
+#define	CRC_ERR		0x40	/* CRC/Framing Error */
+#define	END_FR		0x80	/* End of Frame (SDLC) */
+
+/* Read Register 2 (channel b only) - Interrupt vector */
+
+/* Read Register 3 (interrupt pending register) ch a only */
+#define	CHBEXT	0x1		/* Channel B Ext/Stat IP */
+#define	CHBTxIP	0x2		/* Channel B Tx IP */
+#define	CHBRxIP	0x4		/* Channel B Rx IP */
+#define	CHAEXT	0x8		/* Channel A Ext/Stat IP */
+#define	CHATxIP	0x10		/* Channel A Tx IP */
+#define	CHARxIP	0x20		/* Channel A Rx IP */
+
+/* Read Register 8 (receive data register) */
+
+/* Read Register 10  (misc status bits) */
+#define	ONLOOP	2		/* On loop */
+#define	LOOPSEND 0x10		/* Loop sending */
+#define	CLK2MIS	0x40		/* Two clocks missing */
+#define	CLK1MIS	0x80		/* One clock missing */
+
+/* Read Register 12 (lower byte of baud rate generator constant) */
+
+/* Read Register 13 (upper byte of baud rate generator constant) */
+
+/* Read Register 15 (value of WR 15) */
+
+
+/*
+ *	Interrupt handling functions for this SCC
+ */
+
+struct z8530_channel;
+ 
+struct z8530_irqhandler
+{
+	void (*rx)(struct z8530_channel *);
+	void (*tx)(struct z8530_channel *);
+	void (*status)(struct z8530_channel *);
+};
+
+/*
+ *	A channel of the Z8530
+ */
+
+struct z8530_channel
+{
+	struct		z8530_irqhandler *irqs;		/* IRQ handlers */
+	/*
+	 *	Synchronous
+	 */
+	u16		count;		/* Buyes received */
+	u16		max;		/* Most we can receive this frame */
+	u16		mtu;		/* MTU of the device */
+	u8		*dptr;		/* Pointer into rx buffer */
+	struct sk_buff	*skb;		/* Buffer dptr points into */
+	struct sk_buff	*skb2;		/* Pending buffer */
+	u8		status;		/* Current DCD */
+	u8		sync;		/* Set if in sync mode */
+
+	u8		regs[16];	/* Register map for the chip */
+	u8		pendregs[16];	/* Pending register values */
+	
+	struct sk_buff 	*tx_skb;	/* Buffer being transmitted */
+	struct sk_buff  *tx_next_skb;	/* Next transmit buffer */
+	u8		*tx_ptr;	/* Byte pointer into the buffer */
+	u8		*tx_next_ptr;	/* Next pointer to use */
+	u8		*tx_dma_buf[2];	/* TX flip buffers for DMA */
+	u8		tx_dma_used;	/* Flip buffer usage toggler */
+	u16		txcount;	/* Count of bytes to transmit */
+	
+	void		(*rx_function)(struct z8530_channel *, struct sk_buff *);
+	
+	/*
+	 *	Sync DMA
+	 */
+	
+	u8		rxdma;		/* DMA channels */
+	u8		txdma;		
+	u8		rxdma_on;	/* DMA active if flag set */
+	u8		txdma_on;
+	u8		dma_num;	/* Buffer we are DMAing into */
+	u8		dma_ready;	/* Is the other buffer free */
+	u8		dma_tx;		/* TX is to use DMA */
+	u8		*rx_buf[2];	/* The flip buffers */
+	
+	/*
+	 *	System
+	 */
+	 
+	struct z8530_dev *dev;		/* Z85230 chip instance we are from */
+	int		ctrlio;		/* I/O ports */
+	int		dataio;
+
+	/*
+	 *	For PC we encode this way.
+	 */	
+#define Z8530_PORT_SLEEP	0x80000000
+#define Z8530_PORT_OF(x)	((x)&0xFFFF)
+
+	u32		rx_overrun;		/* Overruns - not done yet */
+	u32		rx_crc_err;
+
+	/*
+	 *	Bound device pointers
+	 */
+
+	void		*private;	/* For our owner */
+	struct device	*netdevice;	/* Network layer device */
+	struct net_device_stats stats;	/* Network layer statistics */
+
+	/*
+	 *	Async features
+	 */
+
+	struct tty_struct 	*tty;		/* Attached terminal */
+	int			line;		/* Minor number */
+	struct termios		normal_termios;	/* Terminal settings */
+	struct termios		callout_termios;
+	struct wait_queue	*open_wait;	/* Tasks waiting to open */
+	struct wait_queue	*close_wait;	/* and for close to end */
+	unsigned long		event;		/* Pending events */
+	int			fdcount;    	/* # of fd on device */
+	int			blocked_open;	/* # of blocked opens */
+	long			session; 	/* Session of opening process */
+	long			pgrp; 		/* pgrp of opening process */
+	int			x_char;		/* XON/XOF char */
+	unsigned char 		*xmit_buf;	/* Transmit pointer */
+	int			xmit_head;	/* Transmit ring */
+	int			xmit_tail;
+	int			xmit_cnt;
+	int			flags;	
+	int			timeout;
+	int			xmit_fifo_size;	/* Transmit FIFO info */
+
+	int			close_delay;	/* Do we wait for drain on close ? */
+	unsigned short		closing_wait;
+
+	/* We need to know the current clock divisor
+	 * to read the bps rate the chip has currently
+	 * loaded.
+	 */
+
+	unsigned char		clk_divisor;  /* May be 1, 16, 32, or 64 */
+	int			zs_baud;
+
+	int			magic;
+	int			baud_base;		/* Baud parameters */
+	int			custom_divisor;
+
+
+	unsigned char		tx_active; /* character is being xmitted */
+	unsigned char		tx_stopped; /* output is suspended */
+};	
+
+/*
+ *	Each Z853x0 device.
+ */	
+ 
+struct z8530_dev
+{
+	char *name;	/* Device instance name */
+	struct z8530_channel chanA;	/* SCC channel A */
+	struct z8530_channel chanB;	/* SCC channel B */
+	int type;
+#define Z8530	0	/* NMOS dinosaur */	
+#define Z85C30	1	/* CMOS - better */
+#define Z85230	2	/* CMOS with real FIFO */
+	int irq;	/* Interrupt for the device */
+	int active;	/* Soft interrupt enable - the Mac doesn't 
+			   always have a hard disable on its 8530s... */
+};
+
+
+/*
+ *	Functions
+ */
+ 
+extern u8 z8530_dead_port[];
+extern u8 z8530_hdlc_kilostream_85230[];
+extern u8 z8530_hdlc_kilostream[];
+extern void z8530_interrupt(int, void *, struct pt_regs *);
+extern void z8530_describe(struct z8530_dev *, char *mapping,int io);
+extern int z8530_init(struct z8530_dev *);
+extern int z8530_shutdown(struct z8530_dev *);
+extern int z8530_sync_open(struct device *, struct z8530_channel *);
+extern int z8530_sync_close(struct device *, struct z8530_channel *);
+extern int z8530_sync_dma_open(struct device *, struct z8530_channel *);
+extern int z8530_sync_dma_close(struct device *, struct z8530_channel *);
+extern int z8530_channel_load(struct z8530_channel *, u8 *);
+extern int z8530_queue_xmit(struct z8530_channel *c, struct sk_buff *skb);
+extern struct net_device_stats *z8530_get_stats(struct z8530_channel *c);
+extern void z8530_null_rx(struct z8530_channel *c, struct sk_buff *skb);
+
+
+/*
+ *	Standard interrupt vector sets
+ */
+ 
+struct z8530_irqhandler z8530_sync, z8530_async, z8530_nop;
+
+/*
+ *	Asynchronous Interfacing
+ */
+
+#define SERIAL_MAGIC 0x5301
+
+/*
+ * The size of the serial xmit buffer is 1 page, or 4096 bytes
+ */
+
+#define SERIAL_XMIT_SIZE 4096
+#define WAKEUP_CHARS	256
+
+/*
+ * Events are used to schedule things to happen at timer-interrupt
+ * time, instead of at rs interrupt time.
+ */
+#define RS_EVENT_WRITE_WAKEUP	0
+
+/* Internal flags used only by kernel/chr_drv/serial.c */
+#define ZILOG_INITIALIZED	0x80000000 /* Serial port was initialized */
+#define ZILOG_CALLOUT_ACTIVE	0x40000000 /* Call out device is active */
+#define ZILOG_NORMAL_ACTIVE	0x20000000 /* Normal device is active */
+#define ZILOG_BOOT_AUTOCONF	0x10000000 /* Autoconfigure port on bootup */
+#define ZILOG_CLOSING		0x08000000 /* Serial port is closing */
+#define ZILOG_CTS_FLOW		0x04000000 /* Do CTS flow control */
+#define ZILOG_CHECK_CD		0x02000000 /* i.e., CLOCAL */
+
+#endif /* !(_Z8530_H) */
diff -u --recursive --new-file v2.1.120/linux/drivers/pci/pci.c linux/drivers/pci/pci.c
--- v2.1.120/linux/drivers/pci/pci.c	Wed Aug 26 11:37:38 1998
+++ linux/drivers/pci/pci.c	Sat Sep  5 18:33:41 1998
@@ -1,5 +1,5 @@
 /*
- *	$Id: pci.c,v 1.88 1998/08/15 10:37:12 mj Exp $
+ *	$Id: pci.c,v 1.90 1998/09/05 12:39:39 mj Exp $
  *
  *	PCI Bus Services, see include/linux/pci.h for further explanation.
  *
@@ -138,7 +138,8 @@
 		if (l == 0xffffffff)
 			continue;
 		dev->base_address[reg] = l;
-		if ((l & PCI_MEMORY_RANGE_TYPE_MASK) == PCI_BASE_ADDRESS_MEM_TYPE_64) {
+		if ((l & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK))
+		    == (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)) {
 			reg++;
 			pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + (reg << 2), &l);
 			if (l) {
diff -u --recursive --new-file v2.1.120/linux/drivers/scsi/NCR5380.c linux/drivers/scsi/NCR5380.c
--- v2.1.120/linux/drivers/scsi/NCR5380.c	Sat Sep  5 16:46:41 1998
+++ linux/drivers/scsi/NCR5380.c	Sat Sep  5 17:01:45 1998
@@ -1628,14 +1628,18 @@
 	NCR5380_local_declare();
 	struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
 	unsigned char tmp[3], phase;
-	unsigned char *data, value;
+	unsigned char *data;
 	int len;
 	unsigned long timeout;
 	unsigned long flags;
+#ifdef USLEEP
+	unsigned char value;
+#endif
 
-	 NCR5380_setup(instance);
+	NCR5380_setup(instance);
 
 #ifdef USLEEP
+
 	if (hostdata->selecting) 
 	{
 		goto part2;	/* RvC: sorry prof. Dijkstra, but it keeps the
@@ -2250,8 +2254,8 @@
 	register unsigned char p = *phase;
 	register unsigned char *d = *data;
 	unsigned char tmp;
-	int foo;
 	unsigned long flags;
+	int foo;
 #if defined(REAL_DMA_POLL)
 	int cnt, toPIO;
 	unsigned char saved_data = 0, overrun = 0, residue;
diff -u --recursive --new-file v2.1.120/linux/drivers/scsi/README.st linux/drivers/scsi/README.st
--- v2.1.120/linux/drivers/scsi/README.st	Wed May 28 10:51:32 1997
+++ linux/drivers/scsi/README.st	Sun Sep  6 09:48:30 1998
@@ -2,7 +2,7 @@
 The driver is currently maintained by Kai M{kisara (email
 Kai.Makisara@metla.fi)
 
-Last modified: Tue May 27 22:29:24 1997 by makisara@home
+Last modified: Sun Sep  6 10:03:47 1998 by makisara@home
 
 
 BASICS
@@ -117,9 +117,9 @@
 The buffer size is defined (in 1024 byte units) by ST_BUFFER_BLOCKS or
 at boot time. If this size is not enough, the driver tries to allocate
 a large enough temporary buffer that is released when the device is
-closed. The maximum buffer size is defined by the kernel memory
-allocation (currently 256 kB for Alphas and 128 kB for other
-architectures).
+closed. Buffer allocation uses chunks of memory having sizes
+2^n * (page size). Because of this the actual buffer size may be
+larger than the buffer size specified with ST_BUFFER_BLOCKS.
 
 Allocation of the buffers is done at run-time when they are
 needed. Allocation of the specified number of buffers can be done at
@@ -143,6 +143,31 @@
 use pattern. The default triggers asynchronous write after three
 default sized writes (10 kB) from tar.
 
+Scatter/gather buffers (buffers that consist of chunks non-contiguous
+in the physical memory) are used if contiguous buffers can't be
+allocated. To support all SCSI adapters (including those not
+supporting scatter/gather), buffer allocation is using the following
+three kinds of chunks:
+1. The initial segment that is used for all SCSI adapters including
+those not supporting scatter/gather. The size of this buffer will be
+(PAGE_SIZE << ST_FIRST_ORDER) bytes if the system can give a chunk of
+this size (and it is not larger than the buffer size specified by
+ST_BUFFER_BLOCKS). If this size is not available, the driver halves
+the size and tries again until the size of one page. The default
+settings in st_options.h make the driver to try to allocate all of the
+buffer as one chunk.
+2. The scatter/gather segments to fill the specified buffer size are
+allocated so that as many segments as possible are used but the number
+of segments does not exceed ST_FIRST_SG.
+3. The remaining segments between ST_MAX_SG (or the module parameter
+max_sg_segs) and the number of segments used in phases 1 and 2
+are used to extend the buffer at run-time if this is necessary. The
+number of scatter/gather segments allowed for the SCSI adapter is not
+exceeded if it is smaller than the maximum number of scatter/gather
+segments specified. If the maximum number allowed for the SCSI adapter
+is smaller than the number of segments used in phases 1 and 2,
+extending the buffer will always fail.
+
 
 BOOT TIME CONFIGURATION
 
@@ -167,6 +192,9 @@
 buffer_kbs=xxx             the buffer size in kilobytes is set to xxx
 write_threshold_kbs=xxx    the write threshold in kilobytes set to xxx
 max_buffers=xxx            the maximum number of tape buffer set to xxx
+max_sg_segs=xxx		   the maximum number of scatter/gather
+			   segments
+
 
 IOCTLS
 
@@ -357,7 +385,7 @@
 
 To enable debugging messages, edit st.c and #define DEBUG 1. As seen
 above, debugging can be switched off with an ioctl if debugging is
-compiled into the driver. The debugging output is not not voluminuous.
+compiled into the driver. The debugging output is not voluminuous.
 
 If the tape seems to hang, I would be very interested to hear where
 the driver is waiting. With the command 'ps -l' you can see the state
diff -u --recursive --new-file v2.1.120/linux/drivers/scsi/advansys.c linux/drivers/scsi/advansys.c
--- v2.1.120/linux/drivers/scsi/advansys.c	Sun Jun  7 11:16:33 1998
+++ linux/drivers/scsi/advansys.c	Wed Sep  9 08:56:58 1998
@@ -660,7 +660,6 @@
 #include <linux/string.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
-#include <linux/head.h>
 #include <linux/types.h>
 #include <linux/ioport.h>
 #include <linux/delay.h>
diff -u --recursive --new-file v2.1.120/linux/drivers/scsi/aha152x.c linux/drivers/scsi/aha152x.c
--- v2.1.120/linux/drivers/scsi/aha152x.c	Sun Jun  7 11:16:33 1998
+++ linux/drivers/scsi/aha152x.c	Wed Sep  9 08:58:40 1998
@@ -555,6 +555,7 @@
 } signatures[] =
 {
   { "Adaptec AHA-1520 BIOS",      0x102e, 21 },  /* Adaptec 152x */
+  { "Adaptec AHA-1520B",            0x0b, 19 },  /* Adaptec 152x rev B */
   { "Adaptec ASW-B626 BIOS",      0x1029, 21 },  /* on-board controller */
   { "Adaptec BIOS: ASW-B626",       0x0f, 22 },  /* on-board controller */
   { "Adaptec ASW-B626 S2",        0x2e6c, 19 },  /* on-board controller */
diff -u --recursive --new-file v2.1.120/linux/drivers/scsi/aha1542.c linux/drivers/scsi/aha1542.c
--- v2.1.120/linux/drivers/scsi/aha1542.c	Tue Jul 21 00:15:31 1998
+++ linux/drivers/scsi/aha1542.c	Wed Sep  9 08:56:58 1998
@@ -21,7 +21,6 @@
 #include <linux/module.h>
 
 #include <linux/kernel.h>
-#include <linux/head.h>
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/ioport.h>
diff -u --recursive --new-file v2.1.120/linux/drivers/scsi/aha1740.c linux/drivers/scsi/aha1740.c
--- v2.1.120/linux/drivers/scsi/aha1740.c	Sun Jun  7 11:16:34 1998
+++ linux/drivers/scsi/aha1740.c	Wed Sep  9 08:56:58 1998
@@ -27,7 +27,6 @@
 #endif
 
 #include <linux/kernel.h>
-#include <linux/head.h>
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/ioport.h>
diff -u --recursive --new-file v2.1.120/linux/drivers/scsi/gdth.c linux/drivers/scsi/gdth.c
--- v2.1.120/linux/drivers/scsi/gdth.c	Sun Jun  7 11:16:34 1998
+++ linux/drivers/scsi/gdth.c	Wed Sep  9 08:56:58 1998
@@ -82,7 +82,6 @@
 
 #include <linux/version.h>
 #include <linux/kernel.h>
-#include <linux/head.h>
 #include <linux/types.h>
 #include <linux/pci.h>
 #include <linux/string.h>
diff -u --recursive --new-file v2.1.120/linux/drivers/scsi/ibmmca.c linux/drivers/scsi/ibmmca.c
--- v2.1.120/linux/drivers/scsi/ibmmca.c	Thu Aug  6 14:06:33 1998
+++ linux/drivers/scsi/ibmmca.c	Wed Sep  9 08:56:58 1998
@@ -287,7 +287,6 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/head.h>
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/ioport.h>
diff -u --recursive --new-file v2.1.120/linux/drivers/scsi/ncr53c8xx.c linux/drivers/scsi/ncr53c8xx.c
--- v2.1.120/linux/drivers/scsi/ncr53c8xx.c	Tue Jul 21 00:15:31 1998
+++ linux/drivers/scsi/ncr53c8xx.c	Sun Sep  6 10:34:33 1998
@@ -587,8 +587,12 @@
 #define remap_pci_mem(base, size)	((vm_offset_t) __va(base))
 #define unmap_pci_mem(vaddr, size)
 #define pcivtophys(p)			((p) & pci_dvma_mask)
-#else	/* __sparc__ */
+#else
+#if defined(__alpha__)
+#define pcivtophys(p)			((p) & 0xfffffffful)
+#else
 #define pcivtophys(p)			(p)
+#endif
 
 #ifndef NCR_IOMAPPED
 __initfunc(
diff -u --recursive --new-file v2.1.120/linux/drivers/scsi/pci2000.c linux/drivers/scsi/pci2000.c
--- v2.1.120/linux/drivers/scsi/pci2000.c	Tue Apr 14 14:29:23 1998
+++ linux/drivers/scsi/pci2000.c	Wed Sep  9 08:56:58 1998
@@ -25,7 +25,6 @@
 #include <linux/module.h>
 
 #include <linux/kernel.h>
-#include <linux/head.h>
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/pci.h>
diff -u --recursive --new-file v2.1.120/linux/drivers/scsi/pci2220i.c linux/drivers/scsi/pci2220i.c
--- v2.1.120/linux/drivers/scsi/pci2220i.c	Tue Apr 14 14:29:23 1998
+++ linux/drivers/scsi/pci2220i.c	Wed Sep  9 08:56:58 1998
@@ -27,7 +27,6 @@
 #include <linux/module.h>
 
 #include <linux/kernel.h>
-#include <linux/head.h>
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/pci.h>
diff -u --recursive --new-file v2.1.120/linux/drivers/scsi/ppa.h linux/drivers/scsi/ppa.h
--- v2.1.120/linux/drivers/scsi/ppa.h	Fri Jul 31 17:08:24 1998
+++ linux/drivers/scsi/ppa.h	Wed Sep  9 13:28:14 1998
@@ -53,12 +53,12 @@
  *
  * Fixed all problems in the parport sharing scheme. Now ppa can be safe
  * used with lp or other parport devices on the same parallel port.
- *		1997 by Andrea Arcangeli <arcangeli@mbox.queen.it>
+ *		1997 by Andrea Arcangeli
  *							[1.39]
  *
  * Little fix in ppa engine to ensure that ppa don' t release parport
  * or disconnect in wrong cases.
- *		1997 by Andrea Arcangeli <arcangeli@mbox.queen.it>
+ *		1997 by Andrea Arcangeli
  *							[1.39a]
  */
 /* ------ END OF USER CONFIGURABLE PARAMETERS ----- */
diff -u --recursive --new-file v2.1.120/linux/drivers/scsi/psi240i.c linux/drivers/scsi/psi240i.c
--- v2.1.120/linux/drivers/scsi/psi240i.c	Tue Apr 14 14:29:23 1998
+++ linux/drivers/scsi/psi240i.c	Wed Sep  9 08:56:58 1998
@@ -27,7 +27,6 @@
 #include <linux/module.h>
 
 #include <linux/kernel.h>
-#include <linux/head.h>
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/ioport.h>
diff -u --recursive --new-file v2.1.120/linux/drivers/scsi/qlogicisp.c linux/drivers/scsi/qlogicisp.c
--- v2.1.120/linux/drivers/scsi/qlogicisp.c	Fri May  8 23:14:50 1998
+++ linux/drivers/scsi/qlogicisp.c	Sun Sep  6 10:34:33 1998
@@ -1106,6 +1106,10 @@
 	DEBUG(printk("qlogicisp : loading risc ram\n"));
 
 #if RELOAD_FIRMWARE
+	/* Do not reload firmware if 1040B, i.e. revision 5 chip.  */
+	if (((struct isp1020_hostdata *) host->hostdata)->revision == 5)
+		printk("qlogicisp : 1040B chip, firmware not (re)loaded\n");
+	else
 	{
 		int i;
 		for (i = 0; i < risc_code_length01; i++) {
@@ -1213,7 +1217,8 @@
 	if (inw(io_base + PCI_ID_LOW) != PCI_VENDOR_ID_QLOGIC
 	    || inw(io_base + PCI_ID_HIGH) != PCI_DEVICE_ID_QLOGIC_ISP1020)
 	{
-		printk("qlogicisp : can't decode i/o address space\n");
+		printk("qlogicisp : can't decode i/o address space 0x%lx\n",
+		       io_base);
 		return 1;
 	}
 
diff -u --recursive --new-file v2.1.120/linux/drivers/scsi/scsi_debug.c linux/drivers/scsi/scsi_debug.c
--- v2.1.120/linux/drivers/scsi/scsi_debug.c	Sun Dec 21 17:04:49 1997
+++ linux/drivers/scsi/scsi_debug.c	Wed Sep  9 08:56:58 1998
@@ -13,7 +13,6 @@
 #include <linux/sched.h>
 #include <linux/errno.h>
 #include <linux/timer.h>
-#include <linux/head.h>
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/genhd.h>
diff -u --recursive --new-file v2.1.120/linux/drivers/scsi/scsi_ioctl.c linux/drivers/scsi/scsi_ioctl.c
--- v2.1.120/linux/drivers/scsi/scsi_ioctl.c	Sun Jun  7 11:16:35 1998
+++ linux/drivers/scsi/scsi_ioctl.c	Tue Sep  8 10:32:46 1998
@@ -226,7 +226,9 @@
     if(buf_needed){
 	buf_needed = (buf_needed + 511) & ~511;
 	if (buf_needed > MAX_BUF) buf_needed = MAX_BUF;
+        spin_lock_irqsave(&io_request_lock, flags);
 	buf = (char *) scsi_malloc(buf_needed);
+        spin_unlock_irqrestore(&io_request_lock, flags);
 	if (!buf) return -ENOMEM;
 	memset(buf, 0, buf_needed);
     } else
diff -u --recursive --new-file v2.1.120/linux/drivers/scsi/sr_ioctl.c linux/drivers/scsi/sr_ioctl.c
--- v2.1.120/linux/drivers/scsi/sr_ioctl.c	Tue Jun 23 10:01:24 1998
+++ linux/drivers/scsi/sr_ioctl.c	Tue Sep  8 10:32:46 1998
@@ -55,8 +55,10 @@
     int result, err = 0, retries = 0;
     unsigned long flags;
 
+    spin_lock_irqsave(&io_request_lock, flags);
     SDev  = scsi_CDs[target].device;
     SCpnt = scsi_allocate_device(NULL, scsi_CDs[target].device, 1);
+    spin_unlock_irqrestore(&io_request_lock, flags);
 
 retry:
     if( !scsi_block_when_processing_errors(SDev) )
@@ -137,12 +139,14 @@
             err = -EIO;
 	}
     }
-    
+   
+    spin_lock_irqsave(&io_request_lock, flags);
     result = SCpnt->result;
     /* Wake up a process waiting for device*/
     wake_up(&SCpnt->device->device_wait);
     scsi_release_command(SCpnt);
     SCpnt = NULL;
+    spin_unlock_irqrestore(&io_request_lock, flags);
     return err;
 }
 
@@ -235,6 +239,7 @@
         u_char  sr_cmd[10];
 	char * buffer;
         int result;
+        unsigned long flags;
         	
 	sr_cmd[0] = SCMD_READ_SUBCHANNEL;
 	sr_cmd[1] = ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5);
@@ -245,8 +250,10 @@
 	sr_cmd[7] = 0;
 	sr_cmd[8] = 24;
 	sr_cmd[9] = 0;
-	
+
+        spin_lock_irqsave(&io_request_lock, flags);
 	buffer = (unsigned char*) scsi_malloc(512);
+        spin_unlock_irqrestore(&io_request_lock, flags);
 	if(!buffer) return -ENOMEM;
 	
 	result = sr_do_ioctl(MINOR(cdi->dev), sr_cmd, buffer, 24, 0);
@@ -254,7 +261,9 @@
 	memcpy (mcn->medium_catalog_number, buffer + 9, 13);
         mcn->medium_catalog_number[13] = 0;
 
+        spin_lock_irqsave(&io_request_lock, flags);
 	scsi_free(buffer, 512);
+        spin_unlock_irqrestore(&io_request_lock, flags);
 	
 	return result;
 }
@@ -384,6 +393,7 @@
     {
 	struct cdrom_tochdr* tochdr = (struct cdrom_tochdr*)arg;
 	char * buffer;
+        unsigned long flags;
 	
 	sr_cmd[0] = SCMD_READ_TOC;
 	sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5);
@@ -393,7 +403,9 @@
 	sr_cmd[8] = 12;             /* LSB of length */
 	sr_cmd[9] = 0;
 	
+        spin_lock_irqsave(&io_request_lock, flags);
 	buffer = (unsigned char *) scsi_malloc(512);
+        spin_unlock_irqrestore(&io_request_lock, flags);
 	if(!buffer) return -ENOMEM;
 	
 	result = sr_do_ioctl(target, sr_cmd, buffer, 12, 0);
@@ -401,7 +413,9 @@
 	tochdr->cdth_trk0 = buffer[2];
 	tochdr->cdth_trk1 = buffer[3];
 	
+        spin_lock_irqsave(&io_request_lock, flags);
 	scsi_free(buffer, 512);
+        spin_unlock_irqrestore(&io_request_lock, flags);
         break;
     }
 	
@@ -409,6 +423,7 @@
     {
 	struct cdrom_tocentry* tocentry = (struct cdrom_tocentry*)arg;
 	unsigned char * buffer;
+        unsigned long flags;
 	
 	sr_cmd[0] = SCMD_READ_TOC;
 	sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) |
@@ -419,7 +434,9 @@
 	sr_cmd[8] = 12;            /* LSB of length */
 	sr_cmd[9] = 0;
 	
+        spin_lock_irqsave(&io_request_lock, flags);
 	buffer = (unsigned char *) scsi_malloc(512);
+        spin_unlock_irqrestore(&io_request_lock, flags);
 	if(!buffer) return -ENOMEM;
 	
 	result = sr_do_ioctl (target, sr_cmd, buffer, 12, 0);
@@ -435,7 +452,9 @@
 	    tocentry->cdte_addr.lba = (((((buffer[8] << 8) + buffer[9]) << 8)
                                        + buffer[10]) << 8) + buffer[11];
 	
+        spin_lock_irqsave(&io_request_lock, flags);
 	scsi_free(buffer, 512);
+        spin_unlock_irqrestore(&io_request_lock, flags);
         break;
     }
 	
@@ -461,6 +480,7 @@
     {
 	char * buffer, * mask;
 	struct cdrom_volctrl* volctrl = (struct cdrom_volctrl*)arg;
+        unsigned long flags;
 	
 	/* First we get the current params so we can just twiddle the volume */
 	
@@ -471,12 +491,16 @@
 	sr_cmd[4] = 28;
 	sr_cmd[5] = 0;
 	
+        spin_lock_irqsave(&io_request_lock, flags);
 	buffer = (unsigned char *) scsi_malloc(512);
+        spin_unlock_irqrestore(&io_request_lock, flags);
 	if(!buffer) return -ENOMEM;
 	
 	if ((result = sr_do_ioctl (target, sr_cmd, buffer, 28, 0))) {
 	    printk ("Hosed while obtaining audio mode page\n");
+            spin_lock_irqsave(&io_request_lock, flags);
 	    scsi_free(buffer, 512);
+            spin_unlock_irqrestore(&io_request_lock, flags);
             break;
 	}
 	
@@ -487,17 +511,23 @@
 	sr_cmd[4] = 28;
 	sr_cmd[5] = 0;
 	
+        spin_lock_irqsave(&io_request_lock, flags);
 	mask = (unsigned char *) scsi_malloc(512);
+        spin_unlock_irqrestore(&io_request_lock, flags);
 	if(!mask) {
+            spin_lock_irqsave(&io_request_lock, flags);
 	    scsi_free(buffer, 512);
+            spin_unlock_irqrestore(&io_request_lock, flags);
 	    result = -ENOMEM;
             break;
 	};
 
 	if ((result = sr_do_ioctl (target, sr_cmd, mask, 28, 0))) {
 	    printk ("Hosed while obtaining mask for audio mode page\n");
+            spin_lock_irqsave(&io_request_lock, flags);
 	    scsi_free(buffer, 512);
 	    scsi_free(mask, 512);
+            spin_unlock_irqrestore(&io_request_lock, flags);
 	    break;
 	}
 	
@@ -516,8 +546,10 @@
 	sr_cmd[5] = 0;
 	
 	result = sr_do_ioctl (target, sr_cmd, buffer, 28, 0);
+        spin_lock_irqsave(&io_request_lock, flags);
 	scsi_free(buffer, 512);
 	scsi_free(mask, 512);
+        spin_unlock_irqrestore(&io_request_lock, flags);
         break;
     }
 	
@@ -525,6 +557,7 @@
     {
 	char * buffer;
 	struct cdrom_volctrl* volctrl = (struct cdrom_volctrl*)arg;
+        unsigned long flags;
 	
 	/* Get the current params */
 	
@@ -535,12 +568,16 @@
 	sr_cmd[4] = 28;
 	sr_cmd[5] = 0;
 	
+        spin_lock_irqsave(&io_request_lock, flags);
 	buffer = (unsigned char *) scsi_malloc(512);
+        spin_unlock_irqrestore(&io_request_lock, flags);
 	if(!buffer) return -ENOMEM;
 	
 	if ((result = sr_do_ioctl (target, sr_cmd, buffer, 28, 0))) {
 	    printk ("(CDROMVOLREAD) Hosed while obtaining audio mode page\n");
+            spin_lock_irqsave(&io_request_lock, flags);
 	    scsi_free(buffer, 512);
+            spin_unlock_irqrestore(&io_request_lock, flags);
             break;
 	}
 
@@ -549,7 +586,9 @@
 	volctrl->channel2 = buffer[25];
 	volctrl->channel3 = buffer[27];
 
+        spin_lock_irqsave(&io_request_lock, flags);
 	scsi_free(buffer, 512);
+        spin_unlock_irqrestore(&io_request_lock, flags);
         break;
     }
 	
@@ -557,6 +596,7 @@
     {
 	struct cdrom_subchnl* subchnl = (struct cdrom_subchnl*)arg;
 	char * buffer;
+        unsigned long flags;
 	
 	sr_cmd[0] = SCMD_READ_SUBCHANNEL;
 	sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 0x02;    /* MSF format */
@@ -568,7 +608,9 @@
 	sr_cmd[8] = 16;
 	sr_cmd[9] = 0;
 	
-	buffer = (unsigned char*) scsi_malloc(512);
+        spin_lock_irqsave(&io_request_lock, flags);
+	buffer = (unsigned char *) scsi_malloc(512);
+        spin_unlock_irqrestore(&io_request_lock, flags);
 	if(!buffer) return -ENOMEM;
 	
 	result = sr_do_ioctl(target, sr_cmd, buffer, 16, 0);
@@ -586,7 +628,9 @@
 	subchnl->cdsc_absaddr.msf.second = buffer[10];
 	subchnl->cdsc_absaddr.msf.frame = buffer[11];
 	
+        spin_lock_irqsave(&io_request_lock, flags);
 	scsi_free(buffer, 512);
+        spin_unlock_irqrestore(&io_request_lock, flags);
         break;
     }
     default:
@@ -694,11 +738,14 @@
 {
     unsigned char *raw_sector;
     int is_xa;
+    unsigned long flags;
     
     if (!xa_test)
         return 0;
-    
+   
+    spin_lock_irqsave(&io_request_lock, flags);
     raw_sector = (unsigned char *) scsi_malloc(2048+512);
+    spin_unlock_irqrestore(&io_request_lock, flags);
     if (!raw_sector) return -ENOMEM;
     if (0 == sr_read_sector(minor,scsi_CDs[minor].ms_offset+16,
                             CD_FRAMESIZE_RAW1,raw_sector)) {
@@ -707,7 +754,9 @@
         /* read a raw sector failed for some reason. */
         is_xa = -1;
     }
+    spin_lock_irqsave(&io_request_lock, flags);
     scsi_free(raw_sector, 2048+512);
+    spin_unlock_irqrestore(&io_request_lock, flags);
 #ifdef DEBUG
     printk("sr%d: sr_is_xa: %d\n",minor,is_xa);
 #endif
@@ -730,6 +779,7 @@
         struct cdrom_msf   msf;
         int                lba, rc;
 	int                blocksize = 2048;
+        unsigned long flags;
 
         switch (cmd) {
         case CDROMREADMODE2: blocksize = CD_FRAMESIZE_RAW0; break; /* 2336 */
@@ -738,7 +788,10 @@
 
 	if (copy_from_user(&msf,(void*)arg,sizeof(msf)))
 		return -EFAULT;
-	if (!(raw = scsi_malloc(2048+512)))
+        spin_lock_irqsave(&io_request_lock, flags);
+        raw = scsi_malloc(2048+512);
+        spin_unlock_irqrestore(&io_request_lock, flags);
+	if (!(raw))
                 return -ENOMEM;
 
 	lba = (((msf.cdmsf_min0 * CD_SECS) + msf.cdmsf_sec0)
@@ -751,7 +804,9 @@
 		if (copy_to_user((void*)arg, raw, blocksize))
 			rc = -EFAULT;
 
+        spin_lock_irqsave(&io_request_lock, flags);
 	scsi_free(raw,2048+512);
+        spin_unlock_irqrestore(&io_request_lock, flags);
 	return rc;
     }
     case CDROMREADAUDIO:
@@ -759,6 +814,7 @@
 	unsigned char      *raw;
         int                lba, rc=0;
         struct cdrom_read_audio ra;
+        unsigned long flags;
 
         if (!scsi_CDs[target].readcd_known || !scsi_CDs[target].readcd_cdda)
             return -EINVAL;  /* -EDRIVE_DOES_NOT_SUPPORT_THIS ? */
@@ -774,7 +830,10 @@
 
         if (lba < 0 || lba >= scsi_CDs[target].capacity)
             return -EINVAL;
-	if (!(raw = scsi_malloc(2048+512)))
+        spin_lock_irqsave(&io_request_lock, flags);
+        raw = scsi_malloc(2048+512);
+        spin_unlock_irqrestore(&io_request_lock, flags);
+	if (!(raw))
             return -ENOMEM;
 
         while (ra.nframes > 0) {
@@ -789,7 +848,9 @@
             ra.nframes -= 1;
             lba++;
         }
+        spin_lock_irqsave(&io_request_lock, flags);
 	scsi_free(raw,2048+512);
+        spin_unlock_irqrestore(&io_request_lock, flags);
         return rc;
     }
     case BLKRAGET:
diff -u --recursive --new-file v2.1.120/linux/drivers/scsi/st.c linux/drivers/scsi/st.c
--- v2.1.120/linux/drivers/scsi/st.c	Wed Aug 26 11:37:38 1998
+++ linux/drivers/scsi/st.c	Sun Sep  6 09:48:30 1998
@@ -8,10 +8,10 @@
   order) Klaus Ehrenfried, Wolfgang Denk, Steve Hirsch, Andreas Koppenh"ofer,
   Michael Leodolter, Eyal Lebedinsky, J"org Weule, and Eric Youngdale.
 
-  Copyright 1992 - 1997 Kai Makisara
+  Copyright 1992 - 1998 Kai Makisara
 		 email Kai.Makisara@metla.fi
 
-  Last modified: Wed Nov  5 23:39:52 1997 by makisara@home
+  Last modified: Sun Sep  6 09:34:49 1998 by root@home
   Some small formal changes - aeb, 950809
 */
 
@@ -47,24 +47,27 @@
 #include "scsi.h"
 #include "hosts.h"
 #include <scsi/scsi_ioctl.h>
+
+#define ST_KILOBYTE 1024
+
+#include "st_options.h"
 #include "st.h"
+
 #include "constants.h"
 
 #ifdef MODULE
 MODULE_PARM(buffer_kbs, "i");
 MODULE_PARM(write_threshold_kbs, "i");
 MODULE_PARM(max_buffers, "i");
+MODULE_PARM(max_sg_segs, "i");
 static int buffer_kbs = 0;
 static int write_threshold_kbs = 0;
 static int max_buffers = 0;
+static int max_sg_segs = 0;
 #endif
 
 /* The default definitions have been moved to st_options.h */
 
-#define ST_KILOBYTE 1024
-
-#include "st_options.h"
-
 #define ST_BUFFER_SIZE (ST_BUFFER_BLOCKS * ST_KILOBYTE)
 #define ST_WRITE_THRESHOLD (ST_WRITE_THRESHOLD_BLOCKS * ST_KILOBYTE)
 
@@ -98,6 +101,7 @@
 static int st_buffer_size = ST_BUFFER_SIZE;
 static int st_write_threshold = ST_WRITE_THRESHOLD;
 static int st_max_buffers = ST_MAX_BUFFERS;
+static int st_max_sg_segs = ST_MAX_SG;
 
 static Scsi_Tape * scsi_tapes = NULL;
 
@@ -106,6 +110,8 @@
 static ST_buffer *new_tape_buffer(int, int);
 static int enlarge_buffer(ST_buffer *, int, int);
 static void normalize_buffer(ST_buffer *);
+static int append_to_buffer(const char *, ST_buffer *, int);
+static int from_buffer(ST_buffer *, char *, int);
 
 static int st_init(void);
 static int st_attach(Scsi_Device *);
@@ -142,7 +148,12 @@
   if (!result /* && SCpnt->sense_buffer[0] == 0 */ )
     return 0;
 
-  scode = sense[2] & 0x0f;
+  if (driver_byte(result) & DRIVER_SENSE)
+      scode = sense[2] & 0x0f;
+  else {
+      sense[0] = 0;    /* We don't have sense data if this byte is zero */
+      scode = 0;
+  }
 
 #if DEBUG
   if (debugging) {
@@ -172,7 +183,10 @@
       print_sense("st", SCpnt);
     }
     else
-      printk(KERN_WARNING "st%d: Error %x.\n", dev, result);
+      printk(KERN_WARNING
+	     "st%d: Error %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n",
+	     dev, result, suggestion(result), driver_byte(result),
+	     host_byte(result));
   }
 
   if ((sense[0] & 0x70) == 0x70 &&
@@ -246,39 +260,54 @@
 }
 
 
-/* Do the scsi command */
+/* Do the scsi command. Waits until command performed if do_wait is true.
+   Otherwise write_behind_check() is used to check that the command
+   has finished. */
 	static Scsi_Cmnd *
 st_do_scsi(Scsi_Cmnd *SCpnt, Scsi_Tape *STp, unsigned char *cmd, int bytes,
-	   int timeout, int retries)
+	   int timeout, int retries, int do_wait)
 {
   unsigned long flags;
+  unsigned char *bp;
 
   spin_lock_irqsave(&io_request_lock, flags);
   if (SCpnt == NULL)
     if ((SCpnt = scsi_allocate_device(NULL, STp->device, 1)) == NULL) {
       printk(KERN_ERR "st%d: Can't get SCSI request.\n", TAPE_NR(STp->devt));
+      spin_unlock_irqrestore(&io_request_lock, flags);
       return NULL;
     }
 
   cmd[1] |= (SCpnt->lun << 5) & 0xe0;
   STp->sem = MUTEX_LOCKED;
+  SCpnt->use_sg = (bytes > (STp->buffer)->sg[0].length) ?
+      (STp->buffer)->use_sg : 0;
+  if (SCpnt->use_sg) {
+      bp = (char *)&((STp->buffer)->sg[0]);
+      if ((STp->buffer)->sg_segs < SCpnt->use_sg)
+	  SCpnt->use_sg = (STp->buffer)->sg_segs;
+  }
+  else
+      bp = (STp->buffer)->b_data;
   SCpnt->request.sem = &(STp->sem);
   SCpnt->request.rq_status = RQ_SCSI_BUSY;
   SCpnt->request.rq_dev = STp->devt;
 
-  scsi_do_cmd(SCpnt, (void *)cmd, (STp->buffer)->b_data, bytes,
+  scsi_do_cmd(SCpnt, (void *)cmd, bp, bytes,
 	      st_sleep_done, timeout, retries);
   spin_unlock_irqrestore(&io_request_lock, flags);
 
-  down(SCpnt->request.sem);
+  if (do_wait) {
+      down(SCpnt->request.sem);
 
-  (STp->buffer)->last_result_fatal = st_chk_result(SCpnt);
+      (STp->buffer)->last_result_fatal = st_chk_result(SCpnt);
+  }
 
   return SCpnt;
 }
 
 
-/* Handle the write-behind checking */
+/* Handle the write-behind checking (downs the semaphore) */
 	static void
 write_behind_check(Scsi_Tape *STp)
 {
@@ -300,9 +329,13 @@
   scsi_release_command((STp->buffer)->last_SCpnt);
 
   if (STbuffer->writing < STbuffer->buffer_bytes)
+#if 0
     memcpy(STbuffer->b_data,
 	   STbuffer->b_data + STbuffer->writing,
 	   STbuffer->buffer_bytes - STbuffer->writing);
+#else
+  printk(KERN_WARNING "st: write_behind_check: something left in buffer!\n");
+#endif
   STbuffer->buffer_bytes -= STbuffer->writing;
   STps = &(STp->ps[STp->partition]);
   if (STps->drv_block >= 0) {
@@ -340,7 +373,7 @@
 	   TAPE_NR(STp->devt), forward ? "forward" : "backward");
 #endif
 
-  SCpnt = st_do_scsi(NULL, STp, cmd, 0, STp->timeout, MAX_RETRIES);
+  SCpnt = st_do_scsi(NULL, STp, cmd, 0, STp->timeout, MAX_RETRIES, TRUE);
   if (!SCpnt)
     return (-EBUSY);
 
@@ -402,7 +435,8 @@
     cmd[3] = blks >> 8;
     cmd[4] = blks;
 
-    SCpnt = st_do_scsi(NULL, STp, cmd, transfer, STp->timeout, MAX_WRITE_RETRIES);
+    SCpnt = st_do_scsi(NULL, STp, cmd, transfer, STp->timeout, MAX_WRITE_RETRIES,
+		       TRUE);
     if (!SCpnt)
       return (-EBUSY);
 
@@ -551,10 +585,9 @@
     if (dev >= st_template.dev_max || !scsi_tapes[dev].device)
       return (-ENXIO);
 
-    if( !scsi_block_when_processing_errors(scsi_tapes[dev].device) )
-      {
+    if( !scsi_block_when_processing_errors(scsi_tapes[dev].device) ) {
         return -ENXIO;
-      }
+    }
 
     STp = &(scsi_tapes[dev]);
     if (STp->in_use) {
@@ -576,7 +609,7 @@
     }
     STm = &(STp->modes[STp->current_mode]);
 
-    /* Allocate buffer for this user */
+    /* Allocate a buffer for this user */
     need_dma_buffer = STp->restr_dma;
     for (i=0; i < st_nbr_buffers; i++)
       if (!st_buffers[i]->in_use &&
@@ -594,6 +627,16 @@
     (STp->buffer)->in_use = 1;
     (STp->buffer)->writing = 0;
     (STp->buffer)->last_result_fatal = 0;
+    (STp->buffer)->use_sg = STp->device->host->sg_tablesize;
+
+    /* Compute the usable buffer size for this SCSI adapter */
+    if (!(STp->buffer)->use_sg)
+	(STp->buffer)->buffer_size = (STp->buffer)->sg[0].length;
+    else {
+	for (i=0, (STp->buffer)->buffer_size = 0; i < (STp->buffer)->use_sg &&
+		 i < (STp->buffer)->sg_segs; i++)
+	    (STp->buffer)->buffer_size += (STp->buffer)->sg[i].length;
+    }
 
     flags = filp->f_flags;
     STp->write_prot = ((flags & O_ACCMODE) == O_RDONLY);
@@ -617,7 +660,8 @@
     memset ((void *) &cmd[0], 0, 10);
     cmd[0] = TEST_UNIT_READY;
 
-    SCpnt = st_do_scsi(NULL, STp, cmd, 0, STp->long_timeout, MAX_READY_RETRIES);
+    SCpnt = st_do_scsi(NULL, STp, cmd, 0, STp->long_timeout, MAX_READY_RETRIES,
+		       TRUE);
     if (!SCpnt) {
 	if (scsi_tapes[dev].device->host->hostt->module)
 	    __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
@@ -631,7 +675,8 @@
       memset ((void *) &cmd[0], 0, 10);
       cmd[0] = TEST_UNIT_READY;
 
-      SCpnt = st_do_scsi(SCpnt, STp, cmd, 0, STp->long_timeout, MAX_READY_RETRIES);
+      SCpnt = st_do_scsi(SCpnt, STp, cmd, 0, STp->long_timeout, MAX_READY_RETRIES,
+			 TRUE);
 
       (STp->device)->was_reset = 0;
       STp->partition = STp->new_partition = 0;
@@ -675,7 +720,7 @@
       memset ((void *) &cmd[0], 0, 10);
       cmd[0] = READ_BLOCK_LIMITS;
 
-      SCpnt = st_do_scsi(SCpnt, STp, cmd, 6, STp->timeout, MAX_READY_RETRIES);
+      SCpnt = st_do_scsi(SCpnt, STp, cmd, 6, STp->timeout, MAX_READY_RETRIES, TRUE);
 
       if (!SCpnt->result && !SCpnt->sense_buffer[0]) {
 	STp->max_block = ((STp->buffer)->b_data[1] << 16) |
@@ -701,7 +746,7 @@
     cmd[0] = MODE_SENSE;
     cmd[4] = 12;
 
-    SCpnt = st_do_scsi(SCpnt, STp, cmd, 12, STp->timeout, MAX_READY_RETRIES);
+    SCpnt = st_do_scsi(SCpnt, STp, cmd, 12, STp->timeout, MAX_READY_RETRIES, TRUE);
 
     if ((STp->buffer)->last_result_fatal != 0) {
 #if DEBUG
@@ -754,7 +799,7 @@
     SCpnt = NULL;
 
     if (STp->block_size > 0)
-      (STp->buffer)->buffer_blocks = st_buffer_size / STp->block_size;
+      (STp->buffer)->buffer_blocks = (STp->buffer)->buffer_size / STp->block_size;
     else
       (STp->buffer)->buffer_blocks = 1;
     (STp->buffer)->buffer_bytes = (STp->buffer)->read_pointer = 0;
@@ -830,9 +875,9 @@
 }
 
 
-/* Close the device*/
+/* Flush the tape buffer before close */
 	static int
-scsi_tape_close(struct inode * inode, struct file * filp)
+scsi_tape_flush(struct file * filp)
 {
     int result = 0, result2;
     static unsigned char cmd[10];
@@ -841,6 +886,7 @@
     ST_mode * STm;
     ST_partstat * STps;
 
+    struct inode *inode = filp->f_dentry->d_inode;
     kdev_t devt = inode->i_rdev;
     int dev;
 
@@ -877,7 +923,8 @@
 	cmd[0] = WRITE_FILEMARKS;
 	cmd[4] = 1 + STp->two_fm;
 
-	SCpnt = st_do_scsi(NULL, STp, cmd, 0, STp->timeout, MAX_WRITE_RETRIES);
+	SCpnt = st_do_scsi(NULL, STp, cmd, 0, STp->timeout, MAX_WRITE_RETRIES,
+			   TRUE);
 	if (!SCpnt)
 	  goto out;
 
@@ -947,6 +994,23 @@
 	  result = result2;
     }
 
+    return result;
+}
+
+
+/* Close the device and release it */
+	static int
+scsi_tape_close(struct inode * inode, struct file * filp)
+{
+    int result = 0;
+    Scsi_Tape * STp;
+
+    kdev_t devt = inode->i_rdev;
+    int dev;
+
+    dev = TAPE_NR(devt);
+    STp = &(scsi_tapes[dev]);
+
     if (STp->door_locked == ST_LOCKED_AUTO)
       st_int_ioctl(inode, MTUNLOCK, 0);
 
@@ -981,7 +1045,6 @@
     ST_mode * STm;
     ST_partstat * STps;
     int dev = TAPE_NR(inode->i_rdev);
-    unsigned long flags;
 
     STp = &(scsi_tapes[dev]);
 
@@ -991,10 +1054,9 @@
      * may try and take the device offline, in which case all further
      * access to the device is prohibited.
      */
-    if( !scsi_block_when_processing_errors(STp->device) )
-      {
+    if( !scsi_block_when_processing_errors(STp->device) ) {
         return -ENXIO;
-      }
+    }
     
     if (ppos != &filp->f_pos) {
       /* "A request was outside the capabilities of the device." */
@@ -1027,6 +1089,10 @@
     }
 #endif
 
+    /* Write must be integral number of blocks */
+    if (STp->block_size != 0 && (count % STp->block_size) != 0)
+	return (-EIO);
+
     if (STp->can_partitions &&
 	(retval = update_partition(inode)) < 0)
       return retval;
@@ -1092,8 +1158,10 @@
 	return (-EFAULT);
 
     if (!STm->do_buffer_writes) {
+#if 0
       if (STp->block_size != 0 && (count % STp->block_size) != 0)
 	return (-EIO);   /* Write must be integral number of blocks */
+#endif
       write_threshold = 1;
     }
     else
@@ -1110,9 +1178,9 @@
     STps->rw = ST_WRITING;
 
     b_point = buf;
-    while((STp->block_size == 0 && !STm->do_async_writes && count > 0) ||
-	  (STp->block_size != 0 &&
-	   (STp->buffer)->buffer_bytes + count > write_threshold))
+    while ((STp->block_size == 0 && !STm->do_async_writes && count > 0) ||
+	   (STp->block_size != 0 &&
+	    (STp->buffer)->buffer_bytes + count > write_threshold))
     {
       doing_write = 1;
       if (STp->block_size == 0)
@@ -1124,21 +1192,19 @@
 	  do_count = count;
       }
 
-      i = copy_from_user((STp->buffer)->b_data +
-			 (STp->buffer)->buffer_bytes, b_point, do_count);
+      i = append_to_buffer(b_point, STp->buffer, do_count);
       if (i) {
-	  if (SCpnt != NULL)
-	    {
+	  if (SCpnt != NULL) {
 	      scsi_release_command(SCpnt);
 	      SCpnt = NULL;
-	    }
-	  return (-EFAULT);
+	  }
+	  return i;
       }
 
       if (STp->block_size == 0)
 	blks = transfer = do_count;
       else {
-	blks = ((STp->buffer)->buffer_bytes + do_count) /
+	blks = (STp->buffer)->buffer_bytes /
 	  STp->block_size;
 	transfer = blks * STp->block_size;
       }
@@ -1146,7 +1212,8 @@
       cmd[3] = blks >> 8;
       cmd[4] = blks;
 
-      SCpnt = st_do_scsi(SCpnt, STp, cmd, transfer, STp->timeout, MAX_WRITE_RETRIES);
+      SCpnt = st_do_scsi(SCpnt, STp, cmd, transfer, STp->timeout,
+			 MAX_WRITE_RETRIES, TRUE);
       if (!SCpnt)
 	return (-EBUSY);
 
@@ -1223,18 +1290,15 @@
     }
     if (count != 0) {
       STp->dirty = 1;
-      i = copy_from_user((STp->buffer)->b_data +
-			 (STp->buffer)->buffer_bytes, b_point, count);
+      i = append_to_buffer(b_point, STp->buffer, count);
       if (i) {
-	  if (SCpnt != NULL)
-	    {
+	  if (SCpnt != NULL) {
 	      scsi_release_command(SCpnt);
 	      SCpnt = NULL;
-	    }
-	  return (-EFAULT);
+	  }
+	  return i;
       }
       filp->f_pos += count;
-      (STp->buffer)->buffer_bytes += count;
       count = 0;
     }
 
@@ -1249,11 +1313,6 @@
 	  (STp->buffer)->buffer_bytes >= STp->block_size) ||
 	 STp->block_size == 0) ) {
       /* Schedule an asynchronous write */
-      if (!SCpnt) {
-	SCpnt = scsi_allocate_device(NULL, STp->device, 1);
-	if (!SCpnt)
-	  return (-EBUSY);
-      }
       if (STp->block_size == 0)
 	(STp->buffer)->writing = (STp->buffer)->buffer_bytes;
       else
@@ -1269,26 +1328,19 @@
       cmd[2] = blks >> 16;
       cmd[3] = blks >> 8;
       cmd[4] = blks;
-      STp->sem = MUTEX_LOCKED;
-      SCpnt->request.sem = &(STp->sem);
-      SCpnt->request.rq_status = RQ_SCSI_BUSY;
-      SCpnt->request.rq_dev = STp->devt;
 #if DEBUG
       STp->write_pending = 1;
 #endif
 
-      spin_lock_irqsave(&io_request_lock, flags);
-      scsi_do_cmd (SCpnt,
-		   (void *) cmd, (STp->buffer)->b_data,
-		   (STp->buffer)->writing,
-		   st_sleep_done, STp->timeout, MAX_WRITE_RETRIES);
-      spin_unlock_irqrestore(&io_request_lock, flags);
+      SCpnt = st_do_scsi(SCpnt, STp, cmd, (STp->buffer)->writing, STp->timeout,
+			 MAX_WRITE_RETRIES, FALSE);
+      if (SCpnt == NULL)
+	  return (-EIO);
     }
-    else if (SCpnt != NULL)
-      {
+    else if (SCpnt != NULL) {
 	scsi_release_command(SCpnt);
 	SCpnt = NULL;
-      }
+    }
     STps->at_sm &= (total == 0);
     if (total > 0)
 	STps->eof = ST_NOEOF;
@@ -1343,7 +1395,7 @@
     cmd[4] = blks;
 
     SCpnt = *aSCpnt;
-    SCpnt = st_do_scsi(SCpnt, STp, cmd, bytes, STp->timeout, MAX_RETRIES);
+    SCpnt = st_do_scsi(SCpnt, STp, cmd, bytes, STp->timeout, MAX_RETRIES, TRUE);
     *aSCpnt = SCpnt;
     if (!SCpnt)
 	return (-EBUSY);
@@ -1351,7 +1403,6 @@
     (STp->buffer)->read_pointer = 0;
     STps->at_sm = 0;
 
-
     /* Something to check */
     if ((STp->buffer)->last_result_fatal) {
 	retval = 1;
@@ -1507,10 +1558,9 @@
      * may try and take the device offline, in which case all further
      * access to the device is prohibited.
      */
-    if( !scsi_block_when_processing_errors(STp->device) )
-      {
+    if( !scsi_block_when_processing_errors(STp->device) ) {
         return -ENXIO;
-      }
+    }
     
     if (ppos != &filp->f_pos) {
       /* "A request was outside the capabilities of the device." */
@@ -1590,10 +1640,9 @@
       if ((STp->buffer)->buffer_bytes == 0) {
 	  special = read_tape(inode, count - total, &SCpnt);
 	  if (special < 0) { /* No need to continue read */
-	      if (SCpnt != NULL)
-		{
+	      if (SCpnt != NULL) {
 		  scsi_release_command(SCpnt);
-		}
+	      }
 	      return special;
 	  }
       }
@@ -1607,21 +1656,17 @@
 #endif
 	transfer = (STp->buffer)->buffer_bytes < count - total ?
 	  (STp->buffer)->buffer_bytes : count - total;
-	i = copy_to_user(buf, (STp->buffer)->b_data +
-			 (STp->buffer)->read_pointer, transfer);
+	i = from_buffer(STp->buffer, buf, transfer);
 	if (i) {
-	    if (SCpnt != NULL)
-	      {
+	    if (SCpnt != NULL) {
 		scsi_release_command(SCpnt);
 		SCpnt = NULL;
-	      }
-	    return (-EFAULT);
+	    }
+	    return i;
 	}
 	filp->f_pos += transfer;
 	buf += transfer;
 	total += transfer;
-	(STp->buffer)->buffer_bytes -= transfer;
-	(STp->buffer)->read_pointer += transfer;
       }
 
       if (STp->block_size == 0)
@@ -1629,11 +1674,10 @@
 
     } /* for (total = 0, special = 0; total < count && !special; ) */
 
-    if (SCpnt != NULL)
-      {
+    if (SCpnt != NULL) {
 	scsi_release_command(SCpnt);
 	SCpnt = NULL;
-      }
+    }
 
     /* Change the eof state if no data from tape or buffer */
     if (total == 0) {
@@ -1867,7 +1911,7 @@
   cmd[2] = COMPRESSION_PAGE;
   cmd[4] = COMPRESSION_PAGE_LENGTH + MODE_HEADER_LENGTH;
 
-  SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], STp->timeout, 0);
+  SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], STp->timeout, 0, TRUE);
   if (SCpnt == NULL)
     return (-EBUSY);
   dev = TAPE_NR(SCpnt->request.rq_dev);
@@ -1912,7 +1956,7 @@
   (STp->buffer)->b_data[0] = 0;  /* Reserved data length */
   (STp->buffer)->b_data[1] = 0;  /* Reserved media type byte */
   (STp->buffer)->b_data[MODE_HEADER_LENGTH] &= 0x3f;
-  SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], STp->timeout, 0);
+  SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], STp->timeout, 0, TRUE);
 
   if ((STp->buffer)->last_result_fatal != 0) {
 #if DEBUG
@@ -2298,7 +2342,7 @@
        return (-ENOSYS);
      }
 
-   SCpnt = st_do_scsi(NULL, STp, cmd, datalen, timeout, MAX_RETRIES);
+   SCpnt = st_do_scsi(NULL, STp, cmd, datalen, timeout, MAX_RETRIES, TRUE);
    if (!SCpnt)
      return (-EBUSY);
 
@@ -2472,7 +2516,7 @@
       if (!logical && !STp->scsi2_logical)
 	scmd[1] = 1;
     }
-    SCpnt = st_do_scsi(NULL, STp, scmd, 20, STp->timeout, MAX_READY_RETRIES);
+    SCpnt = st_do_scsi(NULL, STp, scmd, 20, STp->timeout, MAX_READY_RETRIES, TRUE);
     if (!SCpnt)
       return (-EBUSY);
 
@@ -2596,7 +2640,7 @@
     timeout = STp->timeout;
 #endif
 
-    SCpnt = st_do_scsi(NULL, STp, scmd, 20, timeout, MAX_READY_RETRIES);
+    SCpnt = st_do_scsi(NULL, STp, scmd, 20, timeout, MAX_READY_RETRIES, TRUE);
     if (!SCpnt)
       return (-EBUSY);
 
@@ -2692,7 +2736,7 @@
     cmd[2] = PART_PAGE;
     cmd[4] = 200;
 
-    SCpnt = st_do_scsi(SCpnt, STp, cmd, 200, STp->timeout, MAX_READY_RETRIES);
+    SCpnt = st_do_scsi(SCpnt, STp, cmd, 200, STp->timeout, MAX_READY_RETRIES, TRUE);
     if (SCpnt == NULL)
       return (-EBUSY);
     scsi_release_command(SCpnt);
@@ -2767,7 +2811,8 @@
     cmd[1] = 0x10;
     cmd[4] = length + MODE_HEADER_LENGTH;
 
-    SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], STp->long_timeout, MAX_READY_RETRIES);
+    SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], STp->long_timeout,
+		       MAX_READY_RETRIES, TRUE);
     if (SCpnt == NULL)
       return (-EBUSY);
     scsi_release_command(SCpnt);
@@ -2815,10 +2860,9 @@
      * may try and take the device offline, in which case all further
      * access to the device is prohibited.
      */
-    if( !scsi_block_when_processing_errors(STp->device) )
-      {
+    if( !scsi_block_when_processing_errors(STp->device) ) {
         return -ENXIO;
-      }
+    }
 
    cmd_type = _IOC_TYPE(cmd_in);
    cmd_nr   = _IOC_NR(cmd_in);
@@ -3034,29 +3078,69 @@
 	static ST_buffer *
 new_tape_buffer( int from_initialization, int need_dma )
 {
-  int priority, a_size;
+  int i, priority, b_size, got = 0, segs = 0;
   ST_buffer *tb;
 
   if (st_nbr_buffers >= st_template.dev_max)
     return NULL;  /* Should never happen */
 
-  if (from_initialization) {
+  if (from_initialization)
     priority = GFP_ATOMIC;
-    a_size = st_buffer_size;
-  }
-  else {
+  else
     priority = GFP_KERNEL;
-    for (a_size = PAGE_SIZE; a_size < st_buffer_size; a_size <<= 1)
-      ; /* Make sure we allocate efficiently */
-  }
-  tb = (ST_buffer *)scsi_init_malloc(sizeof(ST_buffer), priority);
+
+  i = sizeof(ST_buffer) + (st_max_sg_segs - 1) * sizeof(struct scatterlist);
+  tb = (ST_buffer *)scsi_init_malloc(i, priority);
   if (tb) {
+    tb->this_size = i;
     if (need_dma)
       priority |= GFP_DMA;
-    tb->b_data = (unsigned char *)scsi_init_malloc(a_size, priority);
-    if (!tb->b_data) {
-      scsi_init_free((char *)tb, sizeof(ST_buffer));
-      tb = NULL;
+
+    /* Try to allocate the first segment up to ST_FIRST_ORDER and the
+       others big enough to reach the goal */
+    for (b_size = PAGE_SIZE << ST_FIRST_ORDER;
+	 b_size / 2 >= st_buffer_size && b_size > PAGE_SIZE; )
+	b_size /= 2;
+    for ( ; b_size >= PAGE_SIZE; b_size /= 2) {
+	tb->sg[0].address =
+	    (unsigned char *)scsi_init_malloc(b_size, priority);
+	if (tb->sg[0].address != NULL) {
+	    tb->sg[0].alt_address = NULL;
+	    tb->sg[0].length = b_size;
+	    break;
+	}
+    }
+    if (tb->sg[segs].address == NULL) {
+	scsi_init_free((char *)tb, tb->this_size);
+	tb = NULL;
+    }
+    else {  /* Got something, continue */
+
+	for (b_size = PAGE_SIZE;
+	     st_buffer_size > tb->sg[0].length + (ST_FIRST_SG - 1) * b_size; )
+	    b_size *= 2;
+
+	for (segs=1, got=tb->sg[0].length;
+	     got < st_buffer_size && segs < ST_FIRST_SG; ) {
+	    tb->sg[segs].address =
+		(unsigned char *)scsi_init_malloc(b_size, priority);
+	    if (tb->sg[segs].address == NULL) {
+		if (st_buffer_size - got <=
+		    (ST_FIRST_SG - segs) * b_size / 2) {
+		    b_size /= 2; /* Large enough for the rest of the buffers */
+		    continue;
+		}
+		for (i=0; i < segs - 1; i++)
+		    scsi_init_free(tb->sg[i].address, tb->sg[i].length);
+		scsi_init_free((char *)tb, tb->this_size);
+		tb = NULL;
+		break;
+	    }
+	    tb->sg[segs].alt_address = NULL;
+	    tb->sg[segs].length = b_size;
+	    got += b_size;
+	    segs++;
+	}
     }
   }
   if (!tb) {
@@ -3064,18 +3148,25 @@
 	   st_nbr_buffers);
     return NULL;
   }
+  tb->sg_segs = tb->orig_sg_segs = segs;
+  tb->b_data = tb->sg[0].address;
+
 #if DEBUG
-  if (debugging)
+  if (debugging) {
+    printk(ST_DEB_MSG
+    "st: Allocated tape buffer %d (%d bytes, %d segments, dma: %d, a: %p).\n",
+	   st_nbr_buffers, got, tb->sg_segs, need_dma, tb->b_data);
     printk(ST_DEB_MSG
-	   "st: Allocated tape buffer %d (%d bytes, dma: %d, a: %p).\n",
-	   st_nbr_buffers, a_size, need_dma, tb->b_data);
+	   "st: segment sizes: first %d, last %d bytes.\n",
+	   tb->sg[0].length, tb->sg[segs-1].length);
+  }
 #endif
   tb->in_use = 0;
   tb->dma = need_dma;
-  tb->buffer_size = a_size;
+  tb->buffer_size = got;
   tb->writing = 0;
-  tb->orig_b_data = NULL;
   st_buffers[st_nbr_buffers++] = tb;
+
   return tb;
 }
 
@@ -3084,31 +3175,51 @@
 	static int
 enlarge_buffer(ST_buffer *STbuffer, int new_size, int need_dma)
 {
-  int a_size, priority;
-  unsigned char *tbd;
+  int segs, nbr, max_segs, b_size, priority, got;
 
   normalize_buffer(STbuffer);
 
-  for (a_size = PAGE_SIZE; a_size < new_size; a_size <<= 1)
-    ;  /* Make sure that we allocate efficiently */
+  max_segs = STbuffer->use_sg;
+  if (max_segs > st_max_sg_segs)
+      max_segs = st_max_sg_segs;
+  nbr = max_segs - STbuffer->sg_segs;
+  if (nbr <= 0)
+      return FALSE;
 
   priority = GFP_KERNEL;
   if (need_dma)
     priority |= GFP_DMA;
-  tbd = (unsigned char *)scsi_init_malloc(a_size, priority);
-  if (!tbd)
-    return FALSE;
+  for (b_size = PAGE_SIZE; b_size * nbr < new_size - STbuffer->buffer_size; )
+      b_size *= 2;
+
+  for (segs=STbuffer->sg_segs, got=STbuffer->buffer_size;
+       segs < max_segs && got < new_size; ) {
+      STbuffer->sg[segs].address =
+	  (unsigned char *)scsi_init_malloc(b_size, priority);
+      if (STbuffer->sg[segs].address == NULL) {
+	  if (new_size - got <= (max_segs - segs) * b_size / 2) {
+	      b_size /= 2;  /* Large enough for the rest of the buffers */
+	      continue;
+	  }
+	  printk(KERN_NOTICE "st: failed to enlarge buffer to %d bytes.\n",
+		 new_size);
+	  normalize_buffer(STbuffer);
+	  return FALSE;
+      }
+      STbuffer->sg[segs].alt_address = NULL;
+      STbuffer->sg[segs].length = b_size;
+      STbuffer->sg_segs += 1;
+      got += b_size;
+      STbuffer->buffer_size = got;
+      segs++;
+  }
 #if DEBUG
   if (debugging)
-    printk(ST_DEB_MSG
-	   "st: Buffer at %p enlarged to %d bytes (dma: %d, a: %p).\n",
-	   STbuffer->b_data, a_size, need_dma, tbd);
+      printk(ST_DEB_MSG
+	     "st: Succeeded to enlarge buffer to %d bytes (segs %d->%d, %d).\n",
+	     got, STbuffer->orig_sg_segs, STbuffer->sg_segs, b_size);
 #endif
 
-  STbuffer->orig_b_data = STbuffer->b_data;
-  STbuffer->orig_size = STbuffer->buffer_size;
-  STbuffer->b_data = tbd;
-  STbuffer->buffer_size = a_size;
   return TRUE;
 }
 
@@ -3117,19 +3228,87 @@
 	static void
 normalize_buffer(ST_buffer *STbuffer)
 {
-  if (STbuffer->orig_b_data == NULL)
-    return;
-
-  scsi_init_free(STbuffer->b_data, STbuffer->buffer_size);
-  STbuffer->b_data = STbuffer->orig_b_data;
-  STbuffer->orig_b_data = NULL;
-  STbuffer->buffer_size = STbuffer->orig_size;
+  int i;
 
+  for (i=STbuffer->orig_sg_segs; i < STbuffer->sg_segs; i++) {
+      scsi_init_free(STbuffer->sg[i].address, STbuffer->sg[i].length);
+      STbuffer->buffer_size -= STbuffer->sg[i].length;
+  }
 #if DEBUG
-  if (debugging)
-    printk(ST_DEB_MSG "st: Buffer at %p normalized to %d bytes.\n",
-	   STbuffer->b_data, STbuffer->buffer_size);
+  if (debugging && STbuffer->orig_sg_segs < STbuffer->sg_segs)
+      printk(ST_DEB_MSG "st: Buffer at %p normalized to %d bytes (segs %d).\n",
+	     STbuffer->b_data, STbuffer->buffer_size, STbuffer->sg_segs);
 #endif
+  STbuffer->sg_segs = STbuffer->orig_sg_segs;
+}
+
+
+/* Move data from the user buffer to the tape buffer. Returns zero (success) or
+   negative error code. */
+	static int
+append_to_buffer(const char *ubp, ST_buffer *st_bp, int do_count)
+{
+    int i, cnt, res, offset;
+
+    for (i=0, offset=st_bp->buffer_bytes;
+	 i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
+	offset -= st_bp->sg[i].length;
+    if (i == st_bp->sg_segs) {  /* Should never happen */
+	printk(KERN_WARNING "st: append_to_buffer offset overflow.\n");
+	return (-EIO);
+    }
+    for ( ; i < st_bp->sg_segs && do_count > 0; i++) {
+	cnt = st_bp->sg[i].length - offset < do_count ?
+	    st_bp->sg[i].length - offset : do_count;
+	res = copy_from_user(st_bp->sg[i].address + offset, ubp, cnt);
+	if (res)
+	    return (-EFAULT);
+	do_count -= cnt;
+	st_bp->buffer_bytes += cnt;
+	ubp += cnt;
+	offset = 0;
+    }
+    if (do_count) {  /* Should never happen */
+	printk(KERN_WARNING "st: append_to_buffer overflow (left %d).\n",
+	       do_count);
+	return (-EIO);
+    }
+    return 0;
+}
+
+
+/* Move data from the tape buffer to the user buffer. Returns zero (success) or
+   negative error code. */
+	static int
+from_buffer(ST_buffer *st_bp, char *ubp, int do_count)
+{
+    int i, cnt, res, offset;
+
+    for (i=0, offset=st_bp->read_pointer;
+	 i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
+	offset -= st_bp->sg[i].length;
+    if (i == st_bp->sg_segs) {  /* Should never happen */
+	printk(KERN_WARNING "st: from_buffer offset overflow.\n");
+	return (-EIO);
+    }
+    for ( ; i < st_bp->sg_segs && do_count > 0; i++) {
+	cnt = st_bp->sg[i].length - offset < do_count ?
+	    st_bp->sg[i].length - offset : do_count;
+	res = copy_to_user(ubp, st_bp->sg[i].address + offset, cnt);
+	if (res)
+	    return (-EFAULT);
+	do_count -= cnt;
+	st_bp->buffer_bytes -= cnt;
+	st_bp->read_pointer += cnt;
+	ubp += cnt;
+	offset = 0;
+    }
+    if (do_count) {  /* Should never happen */
+	printk(KERN_WARNING "st: from_buffer overflow (left %d).\n",
+	       do_count);
+	return (-EIO);
+    }
+    return 0;
 }
 
 
@@ -3162,7 +3341,7 @@
    st_ioctl,        /* ioctl */
    NULL,            /* mmap */
    scsi_tape_open,  /* open */
-   NULL,	    /* flush */
+   scsi_tape_flush, /* flush */
    scsi_tape_close, /* release */
    NULL		    /* fsync */
 };
@@ -3173,13 +3352,13 @@
    ST_partstat * STps;
    int i;
 
-   if(SDp->type != TYPE_TAPE) return 1;
+   if (SDp->type != TYPE_TAPE)
+       return 1;
 
-   if(st_template.nr_dev >= st_template.dev_max)
-     {
-     	SDp->attached--;
-     	return 1;
-     }
+   if (st_template.nr_dev >= st_template.dev_max) {
+       SDp->attached--;
+       return 1;
+   }
 
    for(tpnt = scsi_tapes, i=0; i<st_template.dev_max; i++, tpnt++)
      if(!tpnt->device) break;
@@ -3250,7 +3429,7 @@
 {
   if(SDp->type != TYPE_TAPE) return 0;
 
-  printk(KERN_INFO
+  printk(KERN_WARNING
 	 "Detected scsi tape st%d at scsi%d, channel %d, id %d, lun %d\n",
 	 st_template.dev_noticed++,
 	 SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
@@ -3376,11 +3555,6 @@
 int init_module(void) {
   int result;
 
-  st_template.module = &__this_module;
-  result = scsi_register_module(MODULE_SCSI_DEV, &st_template);
-  if (result)
-      return result;
-
   if (buffer_kbs > 0)
       st_buffer_size = buffer_kbs * ST_KILOBYTE;
   if (write_threshold_kbs > 0)
@@ -3389,15 +3563,22 @@
       st_write_threshold = st_buffer_size;
   if (max_buffers > 0)
       st_max_buffers = max_buffers;
-printk(KERN_INFO "st: bufsize %d, wrt %d, max buffers %d.\n",
-st_buffer_size, st_write_threshold, st_max_buffers);
+  if (max_sg_segs >= ST_FIRST_SG)
+      st_max_sg_segs = max_sg_segs;
+  printk(KERN_INFO "st: bufsize %d, wrt %d, max buffers %d, s/g segs %d.\n",
+	 st_buffer_size, st_write_threshold, st_max_buffers, st_max_sg_segs);
+
+  st_template.module = &__this_module;
+  result = scsi_register_module(MODULE_SCSI_DEV, &st_template);
+  if (result)
+      return result;
 
   return 0;
 }
 
 void cleanup_module( void)
 {
-  int i;
+  int i, j;
 
   scsi_unregister_module(MODULE_SCSI_DEV, &st_template);
   unregister_chrdev(SCSI_TAPE_MAJOR, "st");
@@ -3409,9 +3590,10 @@
     if (st_buffers != NULL) {
       for (i=0; i < st_nbr_buffers; i++)
 	if (st_buffers[i] != NULL) {
-	  scsi_init_free((char *) st_buffers[i]->b_data,
-			 st_buffers[i]->buffer_size);
-	  scsi_init_free((char *) st_buffers[i], sizeof(ST_buffer));
+	  for (j=0; j < st_buffers[i]->sg_segs; j++)
+	      scsi_init_free((char *) st_buffers[i]->sg[j].address,
+			     st_buffers[i]->sg[j].length);
+	  scsi_init_free((char *) st_buffers[i], st_buffers[i]->this_size);
 	}
 
       scsi_init_free((char *) st_buffers,
diff -u --recursive --new-file v2.1.120/linux/drivers/scsi/st.h linux/drivers/scsi/st.h
--- v2.1.120/linux/drivers/scsi/st.h	Thu Nov 13 07:23:32 1997
+++ linux/drivers/scsi/st.h	Sun Sep  6 09:48:30 1998
@@ -13,6 +13,7 @@
 typedef struct {
   unsigned char in_use;
   unsigned char dma;	/* DMA-able buffer */
+  int this_size;        /* allocated size of the structure */
   int buffer_size;
   int buffer_blocks;
   int buffer_bytes;
@@ -22,8 +23,10 @@
   int last_result_fatal;
   Scsi_Cmnd *last_SCpnt;
   unsigned char *b_data;
-  int orig_size;
-  unsigned char *orig_b_data;
+  unsigned short   use_sg;     /* zero or number of segments for this adapter */
+  unsigned short sg_segs;      /* total number of allocated segments */
+  unsigned short orig_sg_segs; /* number of segments allocated at first try */
+  struct scatterlist sg[1];    /* MUST BE last item */
 } ST_buffer;
 
 
diff -u --recursive --new-file v2.1.120/linux/drivers/scsi/st_options.h linux/drivers/scsi/st_options.h
--- v2.1.120/linux/drivers/scsi/st_options.h	Wed May 28 10:51:32 1997
+++ linux/drivers/scsi/st_options.h	Sun Sep  6 09:48:30 1998
@@ -3,7 +3,7 @@
 
    Copyright 1995 Kai Makisara.
 
-   Last modified: Tue May 27 22:29:15 1997 by makisara@home
+   Last modified: Wed Sep  2 21:24:07 1998 by root@home
 */
 
 #ifndef _ST_OPTIONS_H
@@ -53,6 +53,18 @@
    is also constrained by the number of drives detected. Determines the
    maximum number of concurrently active tape drives. */
 #define ST_MAX_BUFFERS (2 + ST_EXTRA_DEVS)
+
+/* Maximum number of scatter/gather segments */
+#define ST_MAX_SG      16
+
+/* The number of scatter/gather segments to allocate at first try (must be
+   smaller or equal to the maximum). */
+#define ST_FIRST_SG    8
+
+/* The size of the first scatter/gather segments (determines the maximum block
+   size for SCSI adapters not supporting scatter/gather). The default is set
+   to try to allocate the buffer as one chunk. */
+#define ST_FIRST_ORDER  5
 
 
 /* The following lines define defaults for properties that can be set
diff -u --recursive --new-file v2.1.120/linux/drivers/scsi/t128.c linux/drivers/scsi/t128.c
--- v2.1.120/linux/drivers/scsi/t128.c	Tue Apr 14 14:29:24 1998
+++ linux/drivers/scsi/t128.c	Sat Sep  5 17:01:45 1998
@@ -240,7 +240,7 @@
 	    break;
 
 	instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
-	instance->base = base;
+	instance->base = phys_to_virt((unsigned int)base);
 
 	NCR5380_init(instance, 0);
 
diff -u --recursive --new-file v2.1.120/linux/drivers/scsi/wd7000.c linux/drivers/scsi/wd7000.c
--- v2.1.120/linux/drivers/scsi/wd7000.c	Thu Aug  6 14:06:33 1998
+++ linux/drivers/scsi/wd7000.c	Wed Sep  9 08:56:59 1998
@@ -148,7 +148,6 @@
 
 #include <stdarg.h>
 #include <linux/kernel.h>
-#include <linux/head.h>
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/sched.h>
diff -u --recursive --new-file v2.1.120/linux/drivers/video/fbcon.c linux/drivers/video/fbcon.c
--- v2.1.120/linux/drivers/video/fbcon.c	Tue Jul 28 14:21:09 1998
+++ linux/drivers/video/fbcon.c	Wed Sep  9 13:59:30 1998
@@ -399,7 +399,7 @@
     int old_rows, old_cols;
     unsigned short *save = NULL, *r, *q;
     /* Only if not module */
-    extern int initmem_freed;
+    int initmem_freed = 1;
     struct fbcon_font_desc *font;
     if (con != fg_console || initmem_freed || p->type == FB_TYPE_TEXT)
     	logo = 0;
diff -u --recursive --new-file v2.1.120/linux/fs/filesystems.c linux/fs/filesystems.c
--- v2.1.120/linux/fs/filesystems.c	Sat Sep  5 16:46:41 1998
+++ linux/fs/filesystems.c	Sun Sep  6 12:55:38 1998
@@ -47,16 +47,8 @@
 extern int init_devpts_fs(void);
 #endif
 
-extern void device_setup(void);
-extern void binfmt_setup(void);
-extern void free_initmem(void);
-
-static void __init do_sys_setup(void)
+void __init filesystem_setup(void)
 {
-	device_setup();
-
-	binfmt_setup();
-
 #ifdef CONFIG_EXT2_FS
 	init_ext2_fs();
 #endif
@@ -156,32 +148,6 @@
 #ifdef CONFIG_NLS
 	init_nls();
 #endif
-
-	mount_root();
-}
-
-int initmem_freed = 0;
-
-/* This may be used only twice, enforced by 'static int callable' */
-asmlinkage int sys_setup(int magic)
-{
-	static int callable = 1;
-	int err = -1;
-
-	lock_kernel();
-	if (magic) {
-		if (!initmem_freed) {
-			initmem_freed = 1;
-			free_initmem ();
-			err = 0;
-		}
-	} else if (callable) {
-		callable = 0;
-		do_sys_setup();
-		err = 0;
-	}
-	unlock_kernel();
-	return err;
 }
 
 #ifndef CONFIG_NFSD
diff -u --recursive --new-file v2.1.120/linux/fs/inode.c linux/fs/inode.c
--- v2.1.120/linux/fs/inode.c	Sat Sep  5 16:46:41 1998
+++ linux/fs/inode.c	Tue Sep  8 14:51:03 1998
@@ -8,6 +8,7 @@
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/dcache.h>
+#include <linux/init.h>
 #include <linux/quotaops.h>
 
 /*
@@ -734,11 +735,11 @@
 
 /*
  * Initialize the hash tables and default
- * value for max inodes..
+ * value for max inodes
  */
 #define MAX_INODE (8192)
 
-void inode_init(void)
+void __init inode_init(void)
 {
 	int i, max;
 	struct list_head *head = inode_hashtable;
diff -u --recursive --new-file v2.1.120/linux/fs/isofs/inode.c linux/fs/isofs/inode.c
--- v2.1.120/linux/fs/isofs/inode.c	Sat Sep  5 16:46:41 1998
+++ linux/fs/isofs/inode.c	Sun Sep  6 10:10:47 1998
@@ -128,30 +128,6 @@
 	unsigned char utf8;
 };
 
-static int strnicmp(const char *s1, const char *s2, int len)
-{
-	/* Yes, Virginia, it had better be unsigned */
-	unsigned char c1, c2;
-
-	c1 = 0;	c2 = 0;
-	while (len > 0) {
-		c1 = *s1; c2 = *s2;
-		s1++; s2++;
-		if (!c1)
-			break;
-		if (!c2)
-			break;
-		if (c1 == c2)
-			continue;
-		c1 = tolower(c1);
-		c2 = tolower(c2);
-		if (c1 != c2)
-			break;
-		len--;
-	}
-	return (int)c1 - (int)c2;
-}
-
 /*
  * Compute the hash for the isofs name corresponding to the dentry.
  */
diff -u --recursive --new-file v2.1.120/linux/fs/nfs/dir.c linux/fs/nfs/dir.c
--- v2.1.120/linux/fs/nfs/dir.c	Sat Sep  5 16:46:41 1998
+++ linux/fs/nfs/dir.c	Sat Sep  5 17:17:01 1998
@@ -446,14 +446,14 @@
  */
 static void nfs_dentry_delete(struct dentry *dentry)
 {
+	dfprintk(VFS, "NFS: dentry_delete(%s/%s, %x)\n",
+		dentry->d_parent->d_name.name, dentry->d_name.name,
+		dentry->d_flags);
+
 	if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
 		int error;
 		
 		dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
-#ifdef NFS_DEBUG_VERBOSE
-printk("nfs_dentry_delete: unlinking %s/%s\n",
-dentry->d_parent->d_name.name, dentry->d_name.name);
-#endif
 		/* Unhash it first */
 		d_drop(dentry);
 		error = nfs_safe_remove(dentry);
@@ -486,6 +486,10 @@
  */
 static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode)
 {
+	dfprintk(VFS, "NFS: dentry_iput(%s/%s, cnt=%d, ino=%ld)\n",
+		dentry->d_parent->d_name.name, dentry->d_name.name,
+		dentry->d_count, inode->i_ino);
+
 	if (NFS_WRITEBACK(inode)) {
 #ifdef NFS_PARANOIA
 printk("nfs_dentry_iput: pending writes for %s/%s, i_count=%d\n",
@@ -859,6 +863,10 @@
 	struct dentry *sdentry;
 	int            error = -EIO;
 
+	dfprintk(VFS, "NFS: silly-rename(%s/%s, ct=%d)\n",
+		dentry->d_parent->d_name.name, dentry->d_name.name, 
+		dentry->d_count);
+
 	/*
 	 * Note that a silly-renamed file can be deleted once it's
 	 * no longer in use -- it's just an ordinary file now.
@@ -931,6 +939,10 @@
 	struct inode *inode = dentry->d_inode;
 	int error, rehash = 0;
 		
+	dfprintk(VFS, "NFS: safe_remove(%s/%s, %ld)\n",
+		dentry->d_parent->d_name.name, dentry->d_name.name,
+		inode->i_ino);
+
 	/* N.B. not needed now that d_delete is done in advance? */
 	error = -EBUSY;
 	if (inode) {
@@ -1130,22 +1142,13 @@
 {
 	struct inode *old_inode = old_dentry->d_inode;
 	struct inode *new_inode = new_dentry->d_inode;
+	struct dentry *dentry = NULL;
 	int error, rehash = 0, update = 1;
 
-#ifdef NFS_DEBUG_VERBOSE
-printk("nfs_rename: old %s/%s, count=%d, new %s/%s, count=%d\n",
-old_dentry->d_parent->d_name.name,old_dentry->d_name.name,old_dentry->d_count,
-new_dentry->d_parent->d_name.name,new_dentry->d_name.name,new_dentry->d_count);
-#endif
-	if (!old_dir || !S_ISDIR(old_dir->i_mode)) {
-		printk("nfs_rename: old inode is NULL or not a directory\n");
-		return -ENOENT;
-	}
-
-	if (!new_dir || !S_ISDIR(new_dir->i_mode)) {
-		printk("nfs_rename: new inode is NULL or not a directory\n");
-		return -ENOENT;
-	}
+	dfprintk(VFS, "NFS: rename(%s/%s -> %s/%s, ct=%d)\n",
+		old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
+		new_dentry->d_parent->d_name.name, new_dentry->d_name.name,
+		new_dentry->d_count);
 
 	error = -ENAMETOOLONG;
 	if (old_dentry->d_name.len > NFS_MAXNAMLEN ||
@@ -1155,16 +1158,43 @@
 	/*
 	 * First check whether the target is busy ... we can't
 	 * safely do _any_ rename if the target is in use.
+	 *
+	 * For files, make a copy of the dentry and then do a 
+	 * silly-rename. If the silly-rename succeeds, the
+	 * copied dentry is hashed and becomes the new target.
+	 *
+	 * For directories, prune any unused children.
 	 */
-	if (new_dentry->d_count > 1 && !list_empty(&new_dentry->d_subdirs))
-		shrink_dcache_parent(new_dentry);
 	error = -EBUSY;
-	if (new_dentry->d_count > 1) {
+	if (new_dentry->d_count > 1 && new_inode) {
+		if (S_ISREG(new_inode->i_mode)) {
+			int err;
+			/* copy the target dentry's name */
+			dentry = d_alloc(new_dentry->d_parent,
+					 &new_dentry->d_name);
+			if (!dentry)
+				goto out;
+
+			/* silly-rename the existing target ... */
+			err = nfs_sillyrename(new_dir, new_dentry);
+			if (!err) {
+				new_dentry = dentry;
+				new_inode = NULL;
+				/* hash the replacement target */
+				d_add(new_dentry, NULL);
+			}
+		} else if (!list_empty(&new_dentry->d_subdirs)) {
+			shrink_dcache_parent(new_dentry);
+		}
+
+		/* dentry still busy? */
+		if (new_dentry->d_count > 1) {
 #ifdef NFS_PARANOIA
 printk("nfs_rename: target %s/%s busy, d_count=%d\n",
 new_dentry->d_parent->d_name.name,new_dentry->d_name.name,new_dentry->d_count);
 #endif
-		goto out;
+			goto out;
+		}
 	}
 
 	/*
@@ -1208,7 +1238,7 @@
 #endif
 		goto out;
 	}
-	if (new_dentry->d_count > 1) {
+	if (new_dentry->d_count > 1 && new_inode) {
 #ifdef NFS_PARANOIA
 printk("nfs_rename: new dentry %s/%s busy, d_count=%d\n",
 new_dentry->d_parent->d_name.name,new_dentry->d_name.name,new_dentry->d_count);
@@ -1251,7 +1281,11 @@
 		if (update)
 			d_move(old_dentry, new_dentry);
 	}
+
 out:
+	/* new dentry created? */
+	if (dentry)
+		dput(dentry);
 	return error;
 }
 
diff -u --recursive --new-file v2.1.120/linux/fs/nfs/write.c linux/fs/nfs/write.c
--- v2.1.120/linux/fs/nfs/write.c	Sat Sep  5 16:46:41 1998
+++ linux/fs/nfs/write.c	Sat Sep  5 17:13:21 1998
@@ -475,7 +475,6 @@
 		if (!PageLocked(page))
 			break;
 		retval = -ERESTARTSYS;
-		checksignals();
 		if (signalled())
 			break;
 		schedule();
diff -u --recursive --new-file v2.1.120/linux/fs/nfsd/nfssvc.c linux/fs/nfsd/nfssvc.c
--- v2.1.120/linux/fs/nfsd/nfssvc.c	Fri Jan 30 11:28:08 1998
+++ linux/fs/nfsd/nfssvc.c	Sat Sep  5 16:50:15 1998
@@ -36,8 +36,8 @@
 #define NFSDDBG_FACILITY	NFSDDBG_SVC
 #define NFSD_BUFSIZE		(1024 + NFSSVC_MAXBLKSIZE)
 
-#define ALLOWED_SIGS	(sigmask(SIGKILL) | sigmask(SIGSTOP))
-#define SHUTDOWN_SIGS	(sigmask(SIGKILL) | sigmask(SIGINT) | sigmask(SIGTERM))
+#define ALLOWED_SIGS	(sigmask(SIGKILL))
+#define SHUTDOWN_SIGS	(sigmask(SIGKILL) | sigmask(SIGINT) | sigmask(SIGQUIT))
 
 extern struct svc_program	nfsd_program;
 static void			nfsd(struct svc_rqst *rqstp);
diff -u --recursive --new-file v2.1.120/linux/fs/qnx4/inode.c linux/fs/qnx4/inode.c
--- v2.1.120/linux/fs/qnx4/inode.c	Sat Sep  5 16:46:41 1998
+++ linux/fs/qnx4/inode.c	Sat Sep  5 17:01:45 1998
@@ -134,11 +134,12 @@
 #else
 	NULL,
 #endif
-	qnx4_put_inode,
 #ifdef CONFIG_QNX4FS_RW
+	qnx4_put_inode,
 	qnx4_delete_inode,
 	NULL,			/* notify_change */
 #else
+	NULL,			/* put_inode */
 	NULL,			/* delete_inode */
 	NULL,			/* notify_change */
 #endif
diff -u --recursive --new-file v2.1.120/linux/fs/umsdos/Makefile linux/fs/umsdos/Makefile
--- v2.1.120/linux/fs/umsdos/Makefile	Sat Sep  5 16:46:41 1998
+++ linux/fs/umsdos/Makefile	Wed Sep  9 09:01:19 1998
@@ -9,9 +9,7 @@
 O_TARGET := umsdos.o
 
 O_OBJS   := dir.o  file.o inode.o ioctl.o mangle.o namei.o \
-		rdir.o symlink.o emd.o 
-
-#check.o
+		rdir.o symlink.o emd.o check.o
 
 M_OBJS   := $(O_TARGET)
 
diff -u --recursive --new-file v2.1.120/linux/fs/umsdos/check.c linux/fs/umsdos/check.c
--- v2.1.120/linux/fs/umsdos/check.c	Sat Sep  5 16:46:41 1998
+++ linux/fs/umsdos/check.c	Wed Sep  9 09:01:20 1998
@@ -1,10 +1,11 @@
 /*
  * linux/fs/umsdos/check.c
+ *
+ * Sanity-checking code
  */
 
 #include <linux/signal.h>
 #include <linux/sched.h>
-#include <linux/head.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/string.h>
@@ -15,6 +16,7 @@
 
 #include <asm/system.h>
 
+#ifdef CHECK_PAGE_TABLES
 static int check_one_table (struct pde *page_dir)
 {
 	if (pgd_none (*page_dir))
@@ -52,3 +54,181 @@
 			printk ("\nError MM %d\n", err);
 	}
 }
+#endif
+
+
+#if UMS_DEBUG
+/*
+ * check a superblock
+ */
+
+void check_sb (struct super_block *sb, const char c)
+{
+	if (sb) {
+		Printk ((" (has %c_sb=%d, %d)", 
+			c, MAJOR (sb->s_dev), MINOR (sb->s_dev)));
+	} else {
+		Printk ((" (%c_sb is NULL)", c));
+	}
+} 
+
+/*
+ * check an inode
+ */
+
+void check_inode (struct inode *inode)
+{
+	if (inode) {
+		Printk ((KERN_DEBUG "*   inode is %lu (i_count=%d)",
+			 inode->i_ino, inode->i_count));
+		check_sb (inode->i_sb, 'i');
+		
+		if (inode->i_dentry.next) {	/* FIXME: does this work ? */
+			Printk ((" (has i_dentry)"));
+		} else {
+			Printk ((" (NO i_dentry)"));
+		}
+		
+		if (inode->i_op == NULL) {
+			Printk ((" (i_op is NULL)\n"));
+		} else if (inode->i_op == &umsdos_dir_inode_operations) {
+			Printk ((" (i_op is umsdos_dir_inode_operations)\n"));
+		} else if (inode->i_op == &umsdos_file_inode_operations) {
+			Printk ((" (i_op is umsdos_file_inode_operations)\n"));
+		} else if (inode->i_op == &umsdos_file_inode_operations_no_bmap) {
+			Printk ((" (i_op is umsdos_file_inode_operations_no_bmap)\n"));
+		} else if (inode->i_op == &umsdos_file_inode_operations_readpage) {
+			Printk ((" (i_op is umsdos_file_inode_operations_readpage)\n"));
+		} else if (inode->i_op == &umsdos_rdir_inode_operations) {
+			Printk ((" (i_op is umsdos_rdir_inode_operations)\n"));
+		} else if (inode->i_op == &umsdos_symlink_inode_operations) {
+			Printk ((" (i_op is umsdos_symlink_inode_operations)\n"));
+		} else {
+			Printk ((" (i_op is UNKNOWN: %p)\n", inode->i_op));
+		}
+	} else {
+		Printk ((KERN_DEBUG "*   inode is NULL\n"));
+	}
+}
+
+/*
+ * checks all inode->i_dentry
+ *
+ */
+void checkd_inode (struct inode *inode)
+{
+	struct dentry *ret;
+	struct list_head *cur;
+	int count = 0;
+	if (!inode) {
+		printk (KERN_ERR "checkd_inode: inode is NULL!\n");
+		return;
+	}
+
+	Printk ((KERN_DEBUG "checkd_inode:  inode %lu\n", inode->i_ino));
+	cur = inode->i_dentry.next;
+	while (count++ < 10) {
+		PRINTK (("1..."));
+		if (!cur) {
+			Printk ((KERN_ERR "checkd_inode: *** NULL reached. exit.\n"));
+			return;
+		}
+		PRINTK (("2..."));
+		ret = list_entry (cur, struct dentry, d_alias);
+		PRINTK (("3..."));
+		if (cur == cur->next) {
+			Printk ((KERN_DEBUG "checkd_inode: *** cur=cur->next: normal exit.\n"));
+			return;
+		}
+		PRINTK (("4..."));
+		if (!ret) {
+			Printk ((KERN_ERR "checkd_inode: *** ret dentry is NULL. exit.\n"));
+			return;
+		}
+		PRINTK (("5... (ret=%p)...", ret));
+		PRINTK (("5.1.. (ret->d_dname=%p)...", &(ret->d_name)));
+		PRINTK (("5.1.1. (ret->d_dname.len=%d)...", (int) ret->d_name.len));
+		PRINTK (("5.1.2. (ret->d_dname.name=%c)...", ret->d_name.name));
+		Printk ((KERN_DEBUG "checkd_inode:   i_dentry is %.*s\n", (int) ret->d_name.len, ret->d_name.name));
+		PRINTK (("6..."));
+		cur = cur->next;
+		PRINTK (("7..."));
+#if 1
+		Printk ((KERN_DEBUG "checkd_inode: *** finished after count 1 (operator forced)\n"));
+		return;
+#endif		
+	}
+	Printk ((KERN_ERR "checkd_inode: *** OVER LIMIT (loop?) !\n"));
+	return;
+}
+
+/*
+ * internal part of check_dentry. does the real job.
+ *
+ */
+
+void check_dent_int (struct dentry *dentry, int parent)
+{
+	if (parent) {
+		Printk ((KERN_DEBUG "*  parent(%d) dentry: %.*s\n", 
+			parent, (int) dentry->d_name.len, dentry->d_name.name));
+	} else {
+		Printk ((KERN_DEBUG "*  checking dentry: %.*s\n",
+			 (int) dentry->d_name.len, dentry->d_name.name));
+	}
+	check_inode (dentry->d_inode);
+	Printk ((KERN_DEBUG "*   d_count=%d", dentry->d_count));
+	check_sb (dentry->d_sb, 'd');
+	if (dentry->d_op == NULL) {
+		Printk ((" (d_op is NULL)\n"));
+	} else {
+		Printk ((" (d_op is UNKNOWN: %p)\n", dentry->d_op));
+	}
+}
+
+/*
+ * checks dentry with full traceback to root and prints info. Limited to 10 recursive depths to avoid infinite loops.
+ *
+ */
+
+void check_dentry_path (struct dentry *dentry, const char *desc)
+{
+	int count=0;
+	Printk ((KERN_DEBUG "*** check_dentry_path: %.60s\n", desc));
+
+	if (!dentry) {
+		Printk ((KERN_DEBUG "*** checking dentry... it is NULL !\n"));
+		return;
+	}
+	if (IS_ERR(dentry)) {
+		Printk ((KERN_DEBUG "*** checking dentry... it is ERR(%ld) !\n",
+			 PTR_ERR(dentry)));
+		return;
+	}
+	
+	while (dentry && count < 10) {
+		check_dent_int (dentry, count++);
+		if (dentry == dentry->d_parent) {
+			Printk ((KERN_DEBUG "*** end checking dentry (root reached ok)\n"));
+			break;
+		}
+		dentry = dentry->d_parent;
+	}
+
+	if (count >= 10) {	/* if infinite loop detected */
+		Printk ((KERN_ERR 
+			"*** WARNING ! INFINITE LOOP ! check_dentry_path aborted !\n"));
+	}
+	
+	if (!dentry) {
+		Printk ((KERN_ERR 
+			"*** WARNING ! NULL dentry ! check_dentry_path aborted !\n"));
+	}
+}
+#else
+void check_sb (struct super_block *sb, const char c) {};
+void check_inode (struct inode *inode) {};
+void checkd_inode (struct inode *inode) {};
+void check_dentry_path (struct dentry *dentry, const char *desc) {};
+#endif	/* UMS_DEBUG */
+
diff -u --recursive --new-file v2.1.120/linux/fs/umsdos/dir.c linux/fs/umsdos/dir.c
--- v2.1.120/linux/fs/umsdos/dir.c	Sat Sep  5 16:46:41 1998
+++ linux/fs/umsdos/dir.c	Wed Sep  9 09:01:20 1998
@@ -23,65 +23,41 @@
 extern struct inode *pseudo_root;
 
 
-/* P.T.Waltenberg
- * I've retained this to facilitate the lookup of some of the hard-wired files/directories UMSDOS
- * uses. It's easier to do once than hack all the other instances. Probably safer as well
- */
-   
-/* 
- * d_dir is directory to search for file, name&len define the file.
- * compat_umsdos_real_lookup returns dentry pointing to wanted file,
- * or NULL if not found. Calling code is respondible to call fin_dentry (result) 
- */
-
-struct dentry *compat_umsdos_real_lookup (struct dentry *d_dir, const char *name, int len)
-{
-	int rv;
-	struct dentry *dentry;
-
-	PRINTK ((KERN_DEBUG "compat_umsdos_real_lookup !!CNTx!!: start\n"));
-	
-	check_dentry_path (d_dir, "compat_umsdos_real_lookup B4 dir");
-	dentry = creat_dentry (name, len, NULL, d_dir);
-
-/*	check_dentry_path (dentry, "compat_umsdos_real_lookup B4");*/
-
-	rv = umsdos_real_lookup (d_dir->d_inode, dentry);
-	check_dentry_path (dentry, "compat_umsdos_real_lookup END");
-
-	if (rv) {
-		printk (KERN_WARNING "compat_umsdos_real_lookup failed with %d\n", rv);
-		return NULL;
-	}
-
 
-	PRINTK ((KERN_DEBUG "compat_umsdos_real_lookup !!CNTx!!: end\n"));
-
-	if (dentry->d_inode) return dentry;	/* all OK */
-	
-	/* otherwise, we have a negative dentry. return NULL */
-	Printk ((KERN_DEBUG "compat_umsdos_real_lookup: negative dentry - file not found\n"));
-	fin_dentry (dentry);
-	return NULL;
-}
-
-
-int compat_msdos_create (struct inode *dir, const char *name, int len, int mode, struct inode **inode)
+/*
+ * This needs to have the parent dentry passed to it.
+ * N.B. Try to get rid of this soon!
+ */
+int compat_msdos_create (struct inode *dir, const char *name, int len, 
+			int mode, struct inode **inode)
 {
-	int rv;
+	int ret;
 	struct dentry *dentry, *d_dir;
 
 	check_inode (dir);
+	ret = -ENOMEM;
 	d_dir = geti_dentry (dir);
+	if (!d_dir) {
+printk(KERN_ERR "compat_msdos_create: flaky i_dentry didn't work\n");
+		goto out;
+	}
+	dget(d_dir);
 	dentry = creat_dentry (name, len, NULL, d_dir);
+	dput(d_dir);
+	if (!dentry)
+		goto out;
+
 	check_dentry_path (dentry, "compat_msdos_create START");
-	rv = msdos_create (dir, dentry, mode);
+	ret = msdos_create (dir, dentry, mode);
 	check_dentry_path (dentry, "compat_msdos_create END");
+	if (ret)
+		goto out;
 	if (inode != NULL)
 		*inode = dentry->d_inode;
 
 	check_inode (dir);
-	return rv;
+out:
+	return ret;
 }
 
 
@@ -118,7 +94,8 @@
 	struct UMSDOS_DIR_ONCE *d = (struct UMSDOS_DIR_ONCE *) buf;
 
 	if (d->count == 0) {
-		PRINTK ((KERN_DEBUG "dir_once :%.*s: offset %Ld\n", len, name, offset));
+		PRINTK ((KERN_DEBUG "dir_once :%.*s: offset %Ld\n", 
+			len, name, offset));
 		ret = d->filldir (d->dirbuf, name, len, offset, ino);
 		d->stop = ret < 0;
 		d->count = 1;
@@ -130,32 +107,29 @@
 /*
  * Read count directory entries from directory filp
  * Return a negative value from linux/errno.h.
- * Return > 0 if success (The amount of byte written by filldir).
+ * Return > 0 if success (the number of bytes written by filldir).
  * 
  * This function is used by the normal readdir VFS entry point and by
  * some function who try to find out info on a file from a pure MSDOS
  * inode. See umsdos_locate_ancestor() below.
  */
  
-static int umsdos_readdir_x (	    struct inode *dir,	/* Point to a description of the super block */
-				    struct file *filp,	/* Point to a directory which is read */
-				    void *dirbuf,	/* Will hold count directory entry */
-							/* but filled by the filldir function */
-				    int internal_read,	/* Called for internal purpose */
-				    struct umsdos_dirent *u_entry,	/* Optional umsdos entry */
-				    int follow_hlink,
-				    filldir_t filldir)
+static int umsdos_readdir_x (struct inode *dir, struct file *filp,
+				void *dirbuf, int internal_read,
+				struct umsdos_dirent *u_entry,
+				int follow_hlink, filldir_t filldir)
 {
+	struct dentry *demd;
+	off_t start_fpos;
 	int ret = 0;
-	struct dentry *old_dent;
+	struct file new_filp;
 
 	umsdos_startlookup (dir);
-	if (filp->f_pos == UMSDOS_SPECIAL_DIRFPOS
-	    && pseudo_root
-	    && dir == pseudo_root
-	    && !internal_read) {
 
-		Printk (("umsdos_readdir_x: what UMSDOS_SPECIAL_DIRFPOS /mn/?\n"));
+	if (filp->f_pos == UMSDOS_SPECIAL_DIRFPOS &&
+	    dir == pseudo_root && !internal_read) {
+
+Printk (("umsdos_readdir_x: what UMSDOS_SPECIAL_DIRFPOS /mn/?\n"));
 		/*
 		 * We don't need to simulate this pseudo directory
 		 * when umsdos_readdir_x is called for internal operation
@@ -166,55 +140,16 @@
 		 * linux root), it simulate a directory /DOS which points to
 		 * the real root of the file system.
 		 */
-		if (filldir (dirbuf, "DOS", 3, UMSDOS_SPECIAL_DIRFPOS, UMSDOS_ROOT_INO) == 0) {
+		if (filldir (dirbuf, "DOS", 3, 
+				UMSDOS_SPECIAL_DIRFPOS, UMSDOS_ROOT_INO) == 0) {
 			filp->f_pos++;
 		}
-	} else if (filp->f_pos < 2 || (dir->i_ino != UMSDOS_ROOT_INO && filp->f_pos == 32)) {
-	
-	/* FIXME: that was in 2.0.x: else if (filp->f_pos < 2 || (dir != dir->i_sb->s_mounted && filp->f_pos == 32))
-	 * I'm probably screwing up pseudo-root and stuff with this. It needs proper fix.
-	 */
-	                
+		goto out_end;
+	}
+
+	if (filp->f_pos < 2 || 
+	    (dir->i_ino != UMSDOS_ROOT_INO && filp->f_pos == 32)) {
 	
-		/* #Specification: readdir / . and ..
-		 * The msdos filesystem manages the . and .. entry properly
-		 * so the EMD file won't hold any info about it.
-		 * 
-		 * In readdir, we assume that for the root directory
-		 * the read position will be 0 for ".", 1 for "..". For
-		 * a non root directory, the read position will be 0 for "."
-		 * and 32 for "..".
-		 */
-		/*
-		 * This is a trick used by the msdos file system (fs/msdos/dir.c)
-		 * to manage . and .. for the root directory of a file system.
-		 * Since there is no such entry in the root, fs/msdos/dir.c
-		 * use the following:
-		 * 
-		 * if f_pos == 0, return ".".
-		 * if f_pos == 1, return "..".
-		 * 
-		 * So let msdos handle it
-		 * 
-		 * Since umsdos entries are much larger, we share the same f_pos.
-		 * if f_pos is 0 or 1 or 32, we are clearly looking at . and
-		 * ..
-		 * 
-		 * As soon as we get f_pos == 2 or f_pos == 64, then back to
-		 * 0, but this time we are reading the EMD file.
-		 * 
-		 * Well, not so true. The problem, is that UMSDOS_REC_SIZE is
-		 * also 64, so as soon as we read the first record in the
-		 * EMD, we are back at offset 64. So we set the offset
-		 * to UMSDOS_SPECIAL_DIRFPOS(3) as soon as we have read the
-		 * .. entry from msdos.
-		 * 
-		 * Now (linux 1.3), umsdos_readdir can read more than one
-		 * entry even if we limit (umsdos_dir_once) to only one:
-		 * It skips over hidden file. So we switch to
-		 * UMSDOS_SPECIAL_DIRFPOS as soon as we have read successfully
-		 * the .. entry.
-		 */
 		int last_f_pos = filp->f_pos;
 		struct UMSDOS_DIR_ONCE bufk;
 
@@ -229,112 +164,113 @@
 			filp->f_pos = UMSDOS_SPECIAL_DIRFPOS;
 		if (u_entry != NULL)
 			u_entry->flags = 0;
-	} else {
-		Printk (("umsdos_readdir_x: normal file /mn/?\n"));
-		old_dent = filp->f_dentry;	/* save dentry of directory */
+		goto out_end;
+	}
 
-		if (fix_emd_filp (filp) == 0) {
-			off_t start_fpos = filp->f_pos;
+	Printk (("umsdos_readdir_x: normal file /mn/?\n"));
 
-			Printk (("umsdos_readdir_x: emd_dir->i_ino=%ld\n", filp->f_dentry->d_inode->i_ino));
-			if (filp->f_pos <= UMSDOS_SPECIAL_DIRFPOS + 1)
-				filp->f_pos = 0;
-			Printk (("f_pos %Ld i_size %ld\n", filp->f_pos, filp->f_dentry->d_inode->i_size));
-			ret = 0;
-			while (filp->f_pos < filp->f_dentry->d_inode->i_size) {
-				struct umsdos_dirent entry;
-				off_t cur_f_pos = filp->f_pos;
-
-				if (umsdos_emd_dir_readentry (filp, &entry) != 0) {
-					ret = -EIO;
-					break;
-				} else if (entry.name_len != 0) {
-					/* #Specification: umsdos / readdir
-					 * umsdos_readdir() should fill a struct dirent with
-					 * an inode number. The cheap way to get it is to
-					 * do a lookup in the MSDOS directory for each
-					 * entry processed by the readdir() function.
-					 * This is not very efficient, but very simple. The
-					 * other way around is to maintain a copy of the inode
-					 * number in the EMD file. This is a problem because
-					 * this has to be maintained in sync using tricks.
-					 * Remember that MSDOS (the OS) does not update the
-					 * modification time (mtime) of a directory. There is
-					 * no easy way to tell that a directory was modified
-					 * during a DOS session and synchronise the EMD file.
-					 * 
-					 * Suggestion welcome.
-					 * 
-					 * So the easy way is used!
-					 */
-					struct umsdos_info info;
-					struct dentry *d_dir, *dret;
-
-					umsdos_parse (entry.name, entry.name_len, &info);
-					info.f_pos = cur_f_pos;
-					umsdos_manglename (&info);
-					d_dir = geti_dentry (dir);
-					dret = compat_umsdos_real_lookup (d_dir, info.fake.fname, info.fake.len);
-
-					Printk (("Looking for inode of %s dret %p flags %d\n", info.fake.fname, dret, entry.flags));
-					if (dret && !IS_ERR(dret)
-					   && (entry.flags & UMSDOS_HLINK)
-					   && follow_hlink) {
-						dret = umsdos_solve_hlink (dret);
-					}
+	/* get the EMD dentry */
+	demd = umsdos_get_emd_dentry(filp->f_dentry);
+	ret = PTR_ERR(demd);
+	if (IS_ERR(demd))
+		goto out_end;
+	ret = 0;
+	if (!demd->d_inode)
+		goto out_dput;
+
+	/* set up our private filp ... */
+	fill_new_filp(&new_filp, demd);
+	new_filp.f_pos = filp->f_pos;
+	start_fpos = filp->f_pos;
+
+	if (new_filp.f_pos <= UMSDOS_SPECIAL_DIRFPOS + 1)
+		new_filp.f_pos = 0;
+Printk (("f_pos %Ld i_size %ld\n", new_filp.f_pos, demd->d_inode->i_size));
+	ret = 0;
+	while (new_filp.f_pos < demd->d_inode->i_size) {
+		off_t cur_f_pos = new_filp.f_pos;
+		struct umsdos_info info;
+		struct dentry *dret;
+		struct umsdos_dirent entry;
+
+		ret = -EIO;
+		if (umsdos_emd_dir_readentry (&new_filp, &entry) != 0)
+			break;
+
+		if (entry.name_len == 0)
+			goto remove_name;
+
+		umsdos_parse (entry.name, entry.name_len, &info);
+		info.f_pos = cur_f_pos;
+		umsdos_manglename (&info);
+		dret = umsdos_lookup_dentry(filp->f_dentry, info.fake.fname,
+						 info.fake.len);
+		ret = PTR_ERR(dret);
+		if (IS_ERR(dret))
+			break;
+
+Printk (("Looking for inode of %s/%s, flags=%x\n",
+dret->d_parent->d_name.name, info.fake.fname, entry.flags));
+		if ((entry.flags & UMSDOS_HLINK) && follow_hlink) {
+			dret = umsdos_solve_hlink (dret);
+			ret = PTR_ERR(dret);
+			if (IS_ERR(dret))
+				break;
+		}
 					
-					if (dret && !IS_ERR(dret)) {
-						/* #Specification:  pseudo root / reading real root
-						 * The pseudo root (/linux) is logically
-						 * erased from the real root.  This means that
-						 * ls /DOS, won't show "linux". This avoids
-						 * infinite recursion (/DOS/linux/DOS/linux/...) while
-						 * walking the file system.
-						 */
-						if (dret->d_inode != pseudo_root
-						    && (internal_read || !(entry.flags & UMSDOS_HIDDEN))) {
-							Printk ((KERN_DEBUG "filldir now\n"));
-							if (filldir (dirbuf, entry.name, entry.name_len, cur_f_pos, dret->d_inode->i_ino) < 0) {
-								filp->f_pos = cur_f_pos;
-							}
-							Printk (("Found ino %ld ", dret->d_inode->i_ino));
-							if (u_entry != NULL)
-								*u_entry = entry;
-							fin_dentry (dret);
-							break;
-						}
-						fin_dentry (dret);
-					} else {
-						/* #Specification:  umsdos / readdir / not in MSDOS
-						 * During a readdir operation, if the file is not
-						 * in the MS-DOS directory any more, the entry is
-						 * removed from the EMD file silently.
-						 */
-						Printk (("'Silently' removing EMD for file\n"));
-						ret = umsdos_writeentry (dir, filp->f_dentry->d_inode, &info, 1);
-						if (ret != 0) {
-							break;
-						}
-					}
-				}
+		/* #Specification:  pseudo root / reading real root
+		 * The pseudo root (/linux) is logically
+		 * erased from the real root.  This means that
+		 * ls /DOS, won't show "linux". This avoids
+		 * infinite recursion (/DOS/linux/DOS/linux/...) while
+		 * walking the file system.
+		 */
+		if (dret->d_inode != pseudo_root &&
+		    (internal_read || !(entry.flags & UMSDOS_HIDDEN))) {
+			Printk ((KERN_DEBUG "filldir now\n"));
+			if (filldir (dirbuf, entry.name, entry.name_len,
+				 cur_f_pos, dret->d_inode->i_ino) < 0) {
+				new_filp.f_pos = cur_f_pos;
 			}
-			/*
-			 * If the fillbuf has failed, f_pos is back to 0.
-			 * To avoid getting back into the . and .. state
-			 * (see comments at the beginning), we put back
-			 * the special offset.
-			 */
-			if (filp->f_pos == 0)
-				filp->f_pos = start_fpos;
-			Printk ((KERN_DEBUG "dir.c:  putting emd_dir %lu with i_count=%d\n", filp->f_dentry->d_inode->i_ino, filp->f_dentry->d_inode->i_count));
-
-			fin_dentry (filp->f_dentry);
-			filp->f_dentry = old_dent;	/* restore dentry of directory */
+Printk (("Found %s/%s(%ld)\n",
+dret->d_parent->d_name.name, dret->d_name.name, dret->d_inode->i_ino));
+			if (u_entry != NULL)
+				*u_entry = entry;
+			dput(dret);
+			break;
 		}
+		dput(dret);
+		continue;
+
+	remove_name:
+		/* #Specification:  umsdos / readdir / not in MSDOS
+		 * During a readdir operation, if the file is not
+		 * in the MS-DOS directory any more, the entry is
+		 * removed from the EMD file silently.
+		 */
+		Printk (("'Silently' removing EMD for file\n"));
+		ret = umsdos_delentry(filp->f_dentry, &info, 1);
+		if (ret)
+			break;
+		continue;
 	}
+	/*
+	 * If the fillbuf has failed, f_pos is back to 0.
+	 * To avoid getting back into the . and .. state
+	 * (see comments at the beginning), we put back
+	 * the special offset.
+	 */
+	filp->f_pos = new_filp.f_pos;
+	if (filp->f_pos == 0)
+		filp->f_pos = start_fpos;
+out_dput:
+	dput(demd);
+
+out_end:
 	umsdos_endlookup (dir);
 	
-	Printk ((KERN_DEBUG "read dir %p pos %Ld ret %d\n", dir, filp->f_pos, ret));
+	Printk ((KERN_DEBUG "read dir %p pos %Ld ret %d\n",
+		dir, filp->f_pos, ret));
 	return ret;
 }
 
@@ -345,13 +281,10 @@
  * Return 0 or positive if successful.
  */
  
-static int UMSDOS_readdir (	  struct file *filp,	/* Point to a directory which is read. */
-				  void *dirbuf,		/* Will hold directory entries  */
-				  filldir_t filldir)
+static int UMSDOS_readdir (struct file *filp, void *dirbuf, filldir_t filldir)
 {
 	struct inode *dir = filp->f_dentry->d_inode;
-	int ret = 0;
-	int count = 0;
+	int ret = 0, count = 0;
 	struct UMSDOS_DIR_ONCE bufk;
 
 	bufk.dirbuf = dirbuf;
@@ -363,148 +296,112 @@
 		struct umsdos_dirent entry;
 
 		bufk.count = 0;
-		PRINTK (("UMSDOS_readdir: calling _x (%p,%p,%p,%d,%p,%d,%p)\n", dir, filp, &bufk, 0, &entry, 1, umsdos_dir_once));
-		ret = umsdos_readdir_x (dir, filp, &bufk, 0, &entry, 1, umsdos_dir_once);
+		PRINTK (("UMSDOS_readdir: calling _x (%p,%p,%p,%d,%p,%d,%p)\n",
+			dir, filp, &bufk, 0, &entry, 1, umsdos_dir_once));
+		ret = umsdos_readdir_x (dir, filp, &bufk, 0, &entry, 1, 
+					umsdos_dir_once);
 		if (bufk.count == 0)
 			break;
 		count += bufk.count;
 	}
-	/* FIXME: do we first need to deallocate old dentry ? look/check. see also all other instances of fix_emd_filp */
-	Printk (("UMSDOS_readdir out %d count %d pos %Ld\n", ret, count, filp->f_pos));
+	Printk (("UMSDOS_readdir out %d count %d pos %Ld\n", 
+		ret, count, filp->f_pos));
 	return count ? : ret;
 }
 
 
 /*
  * Complete the inode content with info from the EMD file.
- */
-
-void umsdos_lookup_patch (	 struct inode *dir,
-				 struct inode *inode,
-				 struct umsdos_dirent *entry,
-				 off_t emd_pos)
-{
-	/*
-	 * This function modifies the state of a dir inode.  It decides
-	 * whether the dir is a UMSDOS or DOS directory.  This is done
-	 * deeper in umsdos_patch_inode() called at the end of this function.
-	 * 
-	 * Because it is does disk access, umsdos_patch_inode() may block.
-	 * At the same time, another process may get here to initialise
-	 * the same directory inode. There are three cases.
-	 * 
-	 * 1) The inode is already initialised.  We do nothing.
-	 * 2) The inode is not initialised.  We lock access and do it.
-	 * 3) Like 2 but another process has locked the inode, so we try
-	 * to lock it and check right afterward check whether
-	 * initialisation is still needed.
-	 * 
-	 * 
-	 * Thanks to the "mem" option of the kernel command line, it was
-	 * possible to consistently reproduce this problem by limiting
-	 * my memory to 4 MB and running X.
-	 */
-	/*
-	 * Do this only if the inode is freshly read, because we will lose
-	 * the current (updated) content.
-	 */
-	/*
-	 * A lookup of a mount point directory yield the inode into
-	 * the other fs, so we don't care about initialising it. iget()
-	 * does this automatically.
+ *
+ * This function modifies the state of a dir inode.  It decides
+ * whether the dir is a UMSDOS or DOS directory.  This is done
+ * deeper in umsdos_patch_inode() called at the end of this function.
+ * 
+ * Because it is does disk access, umsdos_patch_inode() may block.
+ * At the same time, another process may get here to initialise
+ * the same directory inode. There are three cases.
+ * 
+ * 1) The inode is already initialised.  We do nothing.
+ * 2) The inode is not initialised.  We lock access and do it.
+ * 3) Like 2 but another process has locked the inode, so we try
+ * to lock it and check right afterward check whether
+ * initialisation is still needed.
+ * 
+ * 
+ * Thanks to the "mem" option of the kernel command line, it was
+ * possible to consistently reproduce this problem by limiting
+ * my memory to 4 MB and running X.
+ *
+ * Do this only if the inode is freshly read, because we will lose
+ * the current (updated) content.
+ *
+ * A lookup of a mount point directory yield the inode into
+ * the other fs, so we don't care about initialising it. iget()
+ * does this automatically.
+ */
+
+void umsdos_lookup_patch (struct inode *dir, struct inode *inode,
+			 struct umsdos_dirent *entry, off_t emd_pos)
+{
+	if (inode->i_sb != dir->i_sb)
+		goto out;
+	if (umsdos_isinit (inode))
+		goto out;
+
+	if (S_ISDIR (inode->i_mode))
+		umsdos_lockcreate (inode);
+	if (umsdos_isinit (inode))
+		goto out_unlock;
+
+	if (S_ISREG (entry->mode))
+		entry->mtime = inode->i_mtime;
+	inode->i_mode = entry->mode;
+	inode->i_rdev = to_kdev_t (entry->rdev);
+	inode->i_atime = entry->atime;
+	inode->i_ctime = entry->ctime;
+	inode->i_mtime = entry->mtime;
+	inode->i_uid = entry->uid;
+	inode->i_gid = entry->gid;
+
+	MSDOS_I (inode)->i_binary = 1;
+	/* #Specification: umsdos / i_nlink
+	 * The nlink field of an inode is maintained by the MSDOS file system
+	 * for directory and by UMSDOS for other files.  The logic is that
+	 * MSDOS is already figuring out what to do for directories and
+	 * does nothing for other files.  For MSDOS, there are no hard links
+	 * so all file carry nlink==1.  UMSDOS use some info in the
+	 * EMD file to plug the correct value.
 	 */
-
-	if (inode->i_sb == dir->i_sb && !umsdos_isinit (inode)) {
-		if (S_ISDIR (inode->i_mode))
-			umsdos_lockcreate (inode);
-		if (!umsdos_isinit (inode)) {
-			/* #Specification: umsdos / lookup / inode info
-			 * After successfully reading an inode from the MSDOS
-			 * filesystem, we use the EMD file to complete it.
-			 * We update the following field.
-			 * 
-			 * uid, gid, atime, ctime, mtime, mode.
-			 * 
-			 * We rely on MSDOS for mtime. If the file
-			 * was modified during an MSDOS session, at least
-			 * mtime will be meaningful. We do this only for regular
-			 * file.
-			 * 
-			 * We don't rely on MS-DOS for mtime for directories
-			 * because the MS-DOS date on a directory is its
-			 * creation time (strange MSDOS behavior) which
-			 * corresponds to none of the three Unix time stamps.
-			 */
-			if (S_ISREG (entry->mode))
-				entry->mtime = inode->i_mtime;
-			inode->i_mode = entry->mode;
-			inode->i_rdev = to_kdev_t (entry->rdev);
-			inode->i_atime = entry->atime;
-			inode->i_ctime = entry->ctime;
-			inode->i_mtime = entry->mtime;
-			inode->i_uid = entry->uid;
-			inode->i_gid = entry->gid;
-			/* #Specification: umsdos / conversion mode
-			 * The msdos filesystem can do some inline conversion
-			 * of the data of a file.  It can translate silently
-			 * from the MS-DOS text file format to the Unix one
-			 * (CRLF -> LF) while reading, and the reverse
-			 * while writing. This is activated using the mount
-			 * option conv=....
-			 * 
-			 * This is not useful for Linux files in a promoted
-			 * directory.  It can even be harmful.  For this
-			 * reason, the binary (no conversion) mode is
-			 * always activated.
-			 */
-			/* #Specification: umsdos / conversion mode / todo
-			 * A flag could be added to file and directories
-			 * forcing an automatic conversion mode (as
-			 * done with the msdos filesystem).
-			 * 
-			 * This flag could be setup on a directory basis
-			 * (instead of file) and all files in it would
-			 * logically inherit it.  If the conversion mode
-			 * is active (conv=) then the i_binary flag would
-			 * be left untouched in those directories.
-			 * 
-			 * It was proposed that the sticky bit be used to set
-			 * this.  A problem with that is that new files would
-			 * be written incorrectly.  The other problem is that
-			 * the sticky bit has a meaning for directories. So
-			 * another bit should be used (there is some space
-			 * in the EMD file for it) and a special utility
-			 * would be used to assign the flag to a directory).
-			 * I don't think it is useful to assign this flag
-			 * on a single file.
-			 */
-
-			MSDOS_I (inode)->i_binary = 1;
-			/* #Specification: umsdos / i_nlink
-			 * The nlink field of an inode is maintained by the MSDOS file system
-			 * for directory and by UMSDOS for other files.  The logic is that
-			 * MSDOS is already figuring out what to do for directories and
-			 * does nothing for other files.  For MSDOS, there are no hard links
-			 * so all file carry nlink==1.  UMSDOS use some info in the
-			 * EMD file to plug the correct value.
-			 */
-			if (!S_ISDIR (entry->mode)) {
-				if (entry->nlink > 0) {
-					inode->i_nlink = entry->nlink;
-				} else {
-					printk (KERN_ERR "UMSDOS:  lookup_patch entry->nlink < 1 ???\n");
-				}
-			}
-			umsdos_patch_inode (inode, dir, emd_pos);
+	if (!S_ISDIR (entry->mode)) {
+		if (entry->nlink > 0) {
+			inode->i_nlink = entry->nlink;
+		} else {
+			printk (KERN_ERR 
+				"UMSDOS:  lookup_patch entry->nlink < 1 ???\n");
 		}
-		if (S_ISDIR (inode->i_mode))
-			umsdos_unlockcreate (inode);
-		if (inode->u.umsdos_i.i_emd_owner == 0)
-			printk (KERN_WARNING "UMSDOS:  emd_owner still 0?\n");
 	}
+	umsdos_patch_inode (inode, dir, emd_pos);
+
+out_unlock:
+	if (S_ISDIR (inode->i_mode))
+		umsdos_unlockcreate (inode);
+	if (inode->u.umsdos_i.i_emd_owner == 0)
+		printk (KERN_WARNING "UMSDOS:  emd_owner still 0?\n");
+out:
+	return;
 }
 
 
+/*
+ * The preferred interface to the above routine ...
+ */
+void umsdos_lookup_patch_new(struct dentry *dentry, struct umsdos_dirent *entry,
+				off_t emd_pos)
+{
+	umsdos_lookup_patch(dentry->d_parent->d_inode, dentry->d_inode, entry,
+				emd_pos);
+}
+
 
 struct UMSDOS_DIRENT_K {
 	off_t f_pos;		/* will hold the offset of the entry in EMD */
@@ -557,18 +454,21 @@
 
 
 /*
- * Locate entry of an inode in a directory.
+ * Locate the directory entry for a dentry in its parent directory.
  * Return 0 or a negative error code.
  * 
  * Normally, this function must succeed.  It means a strange corruption
  * in the file system if not.
  */
 
-int umsdos_inode2entry (       struct inode *dir,
-			       struct inode *inode,
-			       struct umsdos_dirent *entry)	/* Will hold the entry */
+int umsdos_dentry_to_entry(struct dentry *dentry, struct umsdos_dirent *entry)
 {
-	int ret = -ENOENT;
+	struct dentry *parent = dentry->d_parent;
+	struct inode *inode = dentry->d_inode;
+	int ret = -ENOENT, err;
+	struct file filp;
+	struct UMSDOS_DIR_SEARCH bufsrch;
+	struct UMSDOS_DIRENT_K bufk;
 
 	if (pseudo_root && inode == pseudo_root) {
 		/*
@@ -578,155 +478,115 @@
 		memcpy (entry->name, UMSDOS_PSDROOT_NAME, UMSDOS_PSDROOT_LEN + 1);
 		entry->name_len = UMSDOS_PSDROOT_LEN;
 		ret = 0;
-	} else {
-		struct inode *emddir = umsdos_emd_dir_lookup (dir, 0);
+		goto out;
+	}
 
-		/* iput (emddir); / * FIXME? */
-		if (emddir == NULL) {
-			/* This is a DOS directory. */
-			struct UMSDOS_DIR_SEARCH bufk;
-			struct file filp;
-			struct dentry *i2e;
-			
-			i2e = creat_dentry ("@i2e.nul@", 9, dir, NULL);
-
-			fill_new_filp (&filp, i2e);
-
-			Printk ((KERN_ERR "umsdos_inode2entry emddir==NULL: WARNING: Known filp problem. segfaulting :) fixed ?/mn/\n"));
-			filp.f_reada = 1;
-			filp.f_pos = 0;
-			bufk.entry = entry;
-			bufk.search_ino = inode->i_ino;
-			fat_readdir (&filp, &bufk, umsdos_dir_search);
-			if (bufk.found) {
-				ret = 0;
-				inode->u.umsdos_i.i_dir_owner = dir->i_ino;
-				inode->u.umsdos_i.i_emd_owner = 0;
-				umsdos_setup_dir_inode (inode);
-			}
-		} else {
-			/* skip . and .. see umsdos_readdir_x() */
-			struct file filp;
-			struct dentry *i2e;
-
-			i2e = creat_dentry ("@i2e.nn@", 8, dir, NULL);
-			fill_new_filp (&filp, i2e);
-
-			filp.f_reada = 1;
-			filp.f_pos = UMSDOS_SPECIAL_DIRFPOS;
-			Printk ((KERN_ERR "umsdos_inode2entry skip...: WARNING: Known filp problem. segfaulting :) fixed ?/mn/\n"));
-			while (1) {
-				struct UMSDOS_DIRENT_K bufk;
-				struct dentry *old_dent;
-
-				old_dent = filp.f_dentry;
-				if (umsdos_readdir_x (dir, &filp, &bufk, 1, entry, 0, umsdos_filldir_k) < 0) {
-					printk ("UMSDOS: can't locate inode %ld in EMD file???\n", inode->i_ino);
-					break;
-				} else if (bufk.ino == inode->i_ino) {
-					ret = 0;
-					filp.f_dentry = old_dent;
-					umsdos_lookup_patch (dir, inode, entry, bufk.f_pos);
-					break;
-				}
-			}
+	/* initialize the file */
+	fill_new_filp (&filp, parent);
+
+	if (!umsdos_have_emd(parent)) {
+		/* This is a DOS directory. */
+		filp.f_pos = 0;
+		bufsrch.entry = entry;
+		bufsrch.search_ino = inode->i_ino;
+		fat_readdir (&filp, &bufsrch, umsdos_dir_search);
+		if (bufsrch.found) {
+			ret = 0;
+			inode->u.umsdos_i.i_dir_owner = parent->d_inode->i_ino;
+			inode->u.umsdos_i.i_emd_owner = 0;
+if (!S_ISDIR(inode->i_mode))
+printk("UMSDOS: %s/%s not a directory!\n",
+dentry->d_parent->d_name.name, dentry->d_name.name);
+			/* N.B. why call this? not always a dir ... */
+			umsdos_setup_dir(dentry);
+		}
+		goto out;
+	}
+
+	/* skip . and .. see umsdos_readdir_x() */
+	filp.f_pos = UMSDOS_SPECIAL_DIRFPOS;
+	while (1) {
+		err = umsdos_readdir_x (parent->d_inode, &filp, &bufk, 1, 
+				entry, 0, umsdos_filldir_k);
+		if (err < 0) { 
+			printk ("UMSDOS: can't locate inode %ld in EMD??\n",
+				inode->i_ino);
+			break;
+		}
+		if (bufk.ino == inode->i_ino) {
+			ret = 0;
+			umsdos_lookup_patch_new(dentry, entry, bufk.f_pos);
+			break;
 		}
 	}
+out:
 	return ret;
 }
 
-
 /*
- * Locate the parent of a directory and the info on that directory
- * Return 0 or a negative error code.
+ * Deprecated. Try to get rid of this soon!
  */
-
-static int umsdos_locate_ancestor (	  struct inode *dir,
-					  struct inode **result,
-					  struct umsdos_dirent *entry)
+int umsdos_inode2entry (struct inode *dir, struct inode *inode,
+			       struct umsdos_dirent *entry)
 {
-	int ret=-99;
-	struct dentry *dret, *d_dir = creat_dentry ("@d_dir2@", 7, dir, NULL);
-
-	umsdos_patch_inode (dir, NULL, 0);
-	/* FIXME */
-	dret = compat_umsdos_real_lookup (d_dir, "..", 2);
-	Printk (("result %p %p ", dret, *result));
-	if (dret) {
-		struct inode *adir;
-		*result = dret->d_inode;
-		adir = *result;
+	int ret = -ENOENT;
+	struct inode *emddir;
+	struct dentry *i2e;
+	struct file filp;
+	struct UMSDOS_DIR_SEARCH bufsrch;
+	struct UMSDOS_DIRENT_K bufk;
 
-		ret = umsdos_inode2entry (adir, dir, entry);
-		fin_dentry (dret);
+	if (pseudo_root && inode == pseudo_root) {
+		/*
+		 * Quick way to find the name.
+		 * Also umsdos_readdir_x won't show /linux anyway
+		 */
+		memcpy (entry->name, UMSDOS_PSDROOT_NAME, UMSDOS_PSDROOT_LEN + 1);
+		entry->name_len = UMSDOS_PSDROOT_LEN;
+		ret = 0;
+		goto out;
 	}
-	Printk (("\n"));
-	return ret;
-}
-
-
-/*
- * Build the path name of an inode (relative to the file system.
- * This function is need to set (pseudo) hard link.
- * 
- * It uses the same strategy as the standard getcwd().
- */
 
-int umsdos_locate_path (       struct inode *inode,
-			       char *path)
-{
-	int ret = 0;
-	struct inode *dir = inode;
-	struct inode *root_inode;
-	char *bpath = (char *) kmalloc (PATH_MAX, GFP_KERNEL);
+	emddir = umsdos_emd_dir_lookup (dir, 0);
+	if (emddir == NULL) {
+		/* This is a DOS directory. */
+		i2e = creat_dentry ("@i2e.nul@", 9, dir, NULL);
+		fill_new_filp (&filp, i2e);
+		filp.f_reada = 1;
+		filp.f_pos = 0;
+		bufsrch.entry = entry;
+		bufsrch.search_ino = inode->i_ino;
+		fat_readdir (&filp, &bufsrch, umsdos_dir_search);
+		if (bufsrch.found) {
+			ret = 0;
+			inode->u.umsdos_i.i_dir_owner = dir->i_ino;
+			inode->u.umsdos_i.i_emd_owner = 0;
+			umsdos_setup_dir_inode (inode);
+		}
+		goto out;
+	}
 
-	root_inode = iget (inode->i_sb, UMSDOS_ROOT_INO);
-	if (bpath == NULL) {
-		ret = -ENOMEM;
-	} else {
-		struct umsdos_dirent entry;
-		char *ptbpath = bpath + PATH_MAX - 1;
+	/* skip . and .. see umsdos_readdir_x() */
 
-		*ptbpath = '\0';
-		Printk (("locate_path mode %x ", inode->i_mode));
-		if (!S_ISDIR (inode->i_mode)) {
-			ret = umsdos_get_dirowner (inode, &dir);
-			Printk (("locate_path ret %d ", ret));
-			if (ret == 0) {
-				ret = umsdos_inode2entry (dir, inode, &entry);
-				if (ret == 0) {
-					ptbpath -= entry.name_len;
-					memcpy (ptbpath, entry.name, entry.name_len);
-					Printk (("ptbpath :%.*s: ", entry.name_len, ptbpath));
-				}
-			}
-		} else {
-			inc_count (dir);
+	i2e = creat_dentry ("@i2e.nn@", 8, dir, NULL);
+	fill_new_filp (&filp, i2e);
+	filp.f_reada = 1;
+	filp.f_pos = UMSDOS_SPECIAL_DIRFPOS;
+	while (1) {
+		if (umsdos_readdir_x (dir, &filp, &bufk, 1, 
+				entry, 0, umsdos_filldir_k) < 0) {
+			printk ("UMSDOS: can't locate inode %ld in EMD??\n",
+				inode->i_ino);
+			break;
 		}
-		if (ret == 0) {
-			while (dir != root_inode) {
-				struct inode *adir;
-
-				ret = umsdos_locate_ancestor (dir, &adir, &entry);
-				/* iput (dir); FIXME */
-				dir = NULL;
-				Printk (("ancestor %d ", ret));
-				if (ret == 0) {
-					*--ptbpath = '/';
-					ptbpath -= entry.name_len;
-					memcpy (ptbpath, entry.name, entry.name_len);
-					dir = adir;
-					Printk (("ptbpath :%.*s: ", entry.name_len, ptbpath));
-				} else {
-					break;
-				}
-			}
+		if (bufk.ino == inode->i_ino) {
+			ret = 0;
+			umsdos_lookup_patch (dir, inode, entry, bufk.f_pos);
+			break;
 		}
-		strcpy (path, ptbpath);
-		kfree (bpath);
 	}
-	Printk (("\n"));
-	/* iput (dir); / * FIXME?? */
+	iput (emddir);
+out:
 	return ret;
 }
 
@@ -735,8 +595,7 @@
  * Return != 0 if an entry is the pseudo DOS entry in the pseudo root.
  */
 
-int umsdos_is_pseudodos (	struct inode *dir,
-				struct dentry *dentry)
+int umsdos_is_pseudodos (struct inode *dir, struct dentry *dentry)
 {
 	/* #Specification: pseudo root / DOS hard coded
 	 * The pseudo sub-directory DOS in the pseudo root is hard coded.
@@ -745,8 +604,7 @@
 	 * a reserved path and nobody will think of using such a path
 	 * for a package.
 	 */
-	return pseudo_root
-	    && dir == pseudo_root
+	return dir == pseudo_root
 	    && dentry->d_name.len == 3
 	    && dentry->d_name.name[0] == 'D'
 	    && dentry->d_name.name[1] == 'O'
@@ -755,150 +613,126 @@
 
 
 /*
- * Check if a file exists in the current directory.
+ * Check whether a file exists in the current directory.
  * Return 0 if OK, negative error code if not (ex: -ENOENT).
  *
  * fills dentry->d_inode with found inode, and increments its count.
  * if not found, return -ENOENT.
  */
+/* #Specification: umsdos / lookup
+ * A lookup for a file is done in two steps.  First, we
+ * locate the file in the EMD file.  If not present, we
+ * return an error code (-ENOENT).  If it is there, we
+ * repeat the operation on the msdos file system. If
+ * this fails, it means that the file system is not in
+ * sync with the EMD file.   We silently remove this
+ * entry from the EMD file, and return ENOENT.
+ */
 
-int umsdos_lookup_x (	    struct inode *dir,
-			    struct dentry *dentry,
-			    int nopseudo)	/* Don't care about pseudo root mode */
+int umsdos_lookup_x (struct inode *dir, struct dentry *dentry, int nopseudo)
 {				
-	int ret = -ENOENT;
-	struct inode *root_inode;
-	int len = dentry->d_name.len;
 	const char *name = dentry->d_name.name;
-	
-
-#if UMS_DEBUG
-	Printk ((KERN_DEBUG "umsdos_lookup_x: /mn/ name=%.*s, dir=%lu (i_count=%d), d_parent=%p\n", (int) dentry->d_name.len, dentry->d_name.name, dir->i_ino, dir->i_count, dentry->d_parent));		/* FIXME /mn/ debug only */
-	if (dentry->d_parent)
-		Printk ((KERN_DEBUG "   d_parent is %.*s\n", (int) dentry->d_parent->d_name.len, dentry->d_parent->d_name.name));	/* FIXME : delme /mn/ */
-#endif
-
-	root_inode = iget (dir->i_sb, UMSDOS_ROOT_INO);
-	Printk ((KERN_ERR "umsdos_lookup_x (CNT!): entering root_count+1=%d, dir %lu _count=%d\n", root_inode->i_count, dir->i_ino, dir->i_count));	/* FIXME: DEBUG, DELME */
+	int len = dentry->d_name.len;
+	struct dentry *dret = NULL;
+	struct inode *inode;
+	int ret = -ENOENT;
+	struct umsdos_info info;
 
-	dentry->d_inode = NULL;
 	umsdos_startlookup (dir);
+	/* this shouldn't happen ... */
 	if (len == 1 && name[0] == '.') {
-		d_add (dentry, dir);
-		inc_count (dir);
-		ret = 0;
-	} else if (len == 2 && name[0] == '.' && name[1] == '.') {
-		if (pseudo_root && dir == pseudo_root) {
-			/* #Specification: pseudo root / .. in real root
-			 * Whenever a lookup is those in the real root for
-			 * the directory .., and pseudo root is active, the
-			 * pseudo root is returned.
-			 */
-			ret = 0;
-			d_add (dentry, pseudo_root);
-			inc_count (pseudo_root);
-		} else {
-			/* #Specification: locating .. / strategy
-			 * We use the msdos filesystem to locate the parent directory,
-			 * but it is more complicated than that:
-			 * 
-			 * we have to step back even further to
-			 * get the parent of the parent, so we can get the EMD
-			 * of the parent of the parent.  Using the EMD file, we
-			 * can locate all the info on the parent, such as
-			 * permissions and ownership.
-			 */
-			struct dentry *dret, *d_dir = creat_dentry ("@d_dir3@", 5, dir, NULL);
-
-
-			dret = compat_umsdos_real_lookup (d_dir, "..", 2);
-			Printk (("ancestor ret %p dir %p *result %p ", dret, dir, dentry->d_inode));
-			if (dret
-			    && dentry->d_inode != root_inode
-			    && dentry->d_inode != pseudo_root) {
-				struct inode *aadir;
-				struct umsdos_dirent entry;
-				
-				Printk ((KERN_ERR "WARNING: umsdos_lookup_x: this won't work!\n"));
-				
-				dentry->d_inode = dret->d_inode;	/* FIXME! this should be rewritten ! it won't work this way! */
+		printk("umsdos_lookup_x: UMSDOS broken, please report!\n");
+		goto out;
+	}
 
-				ret = umsdos_locate_ancestor (dentry->d_inode, &aadir, &entry);
-				fin_dentry (dret);
-			}
-		}
-	} else if (umsdos_is_pseudodos (dir, dentry)) {
+	/* this shouldn't happen ... */
+	if (len == 2 && name[0] == '.' && name[1] == '.') {
+		printk("umsdos_lookup_x: UMSDOS broken, please report!\n");
+		goto out;
+	}
+
+	if (umsdos_is_pseudodos (dir, dentry)) {
 		/* #Specification: pseudo root / lookup(DOS)
 		 * A lookup of DOS in the pseudo root will always succeed
 		 * and return the inode of the real root.
 		 */
-		d_add (dentry, root_inode);
-		inc_count (dentry->d_inode); /* FIXME?! */
-		ret = 0;
-	} else {
-		struct umsdos_info info;
+		inode = iget(dir->i_sb, UMSDOS_ROOT_INO);
+		if (inode)
+			goto out_add;
+		ret = -ENOMEM;
+		goto out;
+	}
 
-		ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
-		if (ret == 0)
-			ret = umsdos_findentry (dir, &info, 0);
-		Printk (("lookup %.*s pos %lu ret %d len %d ", info.fake.len, info.fake.fname, info.f_pos, ret, info.fake.len));
-		if (ret == 0) {
-			/* #Specification: umsdos / lookup
-			 * A lookup for a file is done in two steps.  First, we
-			 * locate the file in the EMD file.  If not present, we
-			 * return an error code (-ENOENT).  If it is there, we
-			 * repeat the operation on the msdos file system. If
-			 * this fails, it means that the file system is not in
-			 * sync with the EMD file.   We silently remove this
-			 * entry from the EMD file, and return ENOENT.
-			 */
-			struct dentry *dret, *dir_dentry;
-		
-			dir_dentry = geti_dentry (dir);
-			dret = compat_umsdos_real_lookup (dir_dentry, info.fake.fname, info.fake.len);
-			
-
-			PRINTK ((KERN_DEBUG "umsdos_lookup_x: compat_umsdos_real_lookup for %.*s returned %p\n", info.fake.len, info.fake.fname, dret));
-
-			if (dret == NULL) {
-				printk (KERN_WARNING "UMSDOS:  Erase entry %.*s, out of sync with MS-DOS\n", info.fake.len, info.fake.fname);
-				umsdos_delentry (dir, &info, S_ISDIR (info.entry.mode));
-			} else {
-				Printk ((KERN_DEBUG "umsdos_lookup_x /mn/ debug: ino=%li\n", dret->d_inode->i_ino));
-
-				umsdos_lookup_patch (dir, dret->d_inode, &info.entry, info.f_pos);
-				Printk (("lookup ino %ld flags %d\n", dret->d_inode->i_ino, info.entry.flags));
-				if (info.entry.flags & UMSDOS_HLINK) {
-					dret = umsdos_solve_hlink (dret);
-				}
-				if (pseudo_root && dret->d_inode == pseudo_root && !nopseudo) {
-					/* #Specification: pseudo root / dir lookup
-					 * For the same reason as readdir, a lookup in /DOS for
-					 * the pseudo root directory (linux) will fail.
-					 */
-					/*
-					 * This has to be allowed for resolving hard links
-					 * which are recorded independently of the pseudo-root
-					 * mode.
-					 */
-					Printk ((KERN_ERR "umsdos_lookup_x: warning: untested /mn/ Pseudo_root thingy\n"));
-					/* iput (pseudo_root); / * FIXME?? */
-					d_instantiate (dentry, NULL);		/* negative lookup */
-					ret = -ENOENT;
-				} else {
-					/* We've found it OK.  Now put inode in dentry. */
-					inc_count (dret->d_inode);	/* lookup should return incremented i_count */
-					d_add (dentry, dret->d_inode);
-				}
-				fin_dentry (dret);
-			}
-		}
+	ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
+	if (ret)
+		goto out;
+	ret = umsdos_findentry (dentry->d_parent, &info, 0);
+Printk (("lookup %.*s pos %lu ret %d len %d ", 
+info.fake.len, info.fake.fname, info.f_pos, ret, info.fake.len));
+	if (ret)
+		goto out;
+
+
+	dret = umsdos_lookup_dentry(dentry->d_parent, info.fake.fname,
+					info.fake.len);
+	ret = PTR_ERR(dret);
+	if (IS_ERR(dret))
+		goto out;
+	if (!dret->d_inode)
+		goto out_remove;
+
+	umsdos_lookup_patch_new(dret, &info.entry, info.f_pos);
+
+	/* Check for a hard link */
+	if (info.entry.flags & UMSDOS_HLINK) {
+Printk (("checking hard link %s/%s, ino=%ld, flags=%x\n", 
+dret->d_parent->d_name.name, dret->d_name.name,
+dret->d_inode->i_ino, info.entry.flags));
+		dret = umsdos_solve_hlink (dret);
+		ret = PTR_ERR(dret);
+		if (IS_ERR(dret))
+			goto out;
+	}
+	/* N.B. can dentry be negative after resolving hlinks? */
+
+	if (pseudo_root && dret->d_inode == pseudo_root && !nopseudo) {
+		/* #Specification: pseudo root / dir lookup
+		 * For the same reason as readdir, a lookup in /DOS for
+		 * the pseudo root directory (linux) will fail.
+		 */
+		/*
+		 * This has to be allowed for resolving hard links
+		 * which are recorded independently of the pseudo-root
+		 * mode.
+		 */
+		Printk (("umsdos_lookup_x: untested Pseudo_root\n"));
+		ret = -ENOENT;
+		goto out_dput;
+	} else {
+		/* We've found it OK.  Now put inode in dentry. */
+		inode = dret->d_inode;
 	}
+
+	/*
+	 * Hash the dentry with the inode.
+	 */
+out_add:
+	inode->i_count++;
+	d_add (dentry, inode);
+	ret = 0;
+
+out_dput:
+	dput(dret);
+out:
 	umsdos_endlookup (dir);
-	iput (root_inode);	/* pair to iget() above.WHY is it not needed ?! */
-	PRINTK ((KERN_DEBUG "umsdos_lookup_x: returning %d : name=%.*s (i_count=%d), dir=%lu (i_count=%d)\n", ret, (int) dentry->d_name.len, dentry->d_name.name, dentry->d_inode->i_count, dir->i_ino, dir->i_count));
-	Printk ((KERN_ERR "umsdos_lookup_x (CNT!): exiting root_count=%d, dir %lu _count=%d\n", root_inode->i_count, dir->i_ino, dir->i_count));	/* FIXME: DEBUG, DELME */
 	return ret;
+
+out_remove:
+	printk(KERN_WARNING "UMSDOS:  entry %s/%s out of sync, erased\n",
+		dentry->d_name.name, info.fake.fname);
+	umsdos_delentry (dentry->d_parent, &info, S_ISDIR (info.entry.mode));
+	ret = -ENOENT;
+	goto out;
 }
 
 
@@ -911,118 +745,164 @@
  *
  */
 
-int UMSDOS_lookup (	  struct inode *dir,
-			  struct dentry *dentry)
+int UMSDOS_lookup (struct inode *dir, struct dentry *dentry)
 {
 	int ret;
 
 	ret = umsdos_lookup_x (dir, dentry, 0);
 
+	/* Create negative dentry if not found. */
 	if (ret == -ENOENT) {
-		Printk ((KERN_DEBUG "UMSDOS_lookup: converting -ENOENT to negative dentry !\n"));
-		d_add (dentry, NULL);	/* Create negative dentry if not found. */
+		Printk ((KERN_DEBUG 
+			"UMSDOS_lookup: converting -ENOENT to negative\n"));
+		d_add (dentry, NULL);
 		ret = 0;
 	}
-
 	return ret;
 }
 
 
 /*
+ * Lookup or create a dentry from within the filesystem.
+ *
+ * We need to use this instead of lookup_dentry, as the 
+ * directory semaphore lock is already held.
+ */
+struct dentry *umsdos_lookup_dentry(struct dentry *parent, char *name, int len)
+{
+	struct dentry *result, *dentry;
+	int error;
+	struct qstr qstr;
+
+	qstr.name = name;
+	qstr.len  = len;
+	qstr.hash = full_name_hash(name, len);
+	result = d_lookup(parent, &qstr);
+	if (!result) {
+		result = ERR_PTR(-ENOMEM);
+		dentry = d_alloc(parent, &qstr);
+		if (dentry) {
+			result = dentry;
+			error = umsdos_real_lookup(parent->d_inode, result);
+			if (error)
+				goto out_fail;
+		}
+	}
+out:
+	return result;
+
+out_fail:
+	dput(result);
+	result = ERR_PTR(error);
+	goto out;
+}
+
+
+/*
  * gets dentry which points to pseudo-hardlink
  *
  * it should try to find file it points to
- * if file is found, it should dput() original dentry and return new one (with d_count = i_count = 1)
+ * if file is found, it should dput() original dentry and return new one
+ * (with d_count = i_count = 1)
  * Otherwise, it should return with error, with dput()ed original dentry.
  *
  */
 
 struct dentry *umsdos_solve_hlink (struct dentry *hlink)
 {
-	struct dentry *base = hlink->d_sb->s_root;	/* root is our root for resolving pseudo-hardlink */
-	struct dentry *final = NULL;
-	struct inode *result;
+	/* root is our root for resolving pseudo-hardlink */
+	struct dentry *base = hlink->d_sb->s_root;
+	struct dentry *final, *dir, *dentry_dst;
+	char *path, *pt;
+	unsigned long len;
 	int ret = -EIO;
-	struct dentry *dentry_dst, *d_dir;
-	char *path;
+	struct file filp;
 
   	check_dentry_path (hlink, "HLINK BEGIN hlink");
 
+	final = ERR_PTR (-ENOMEM);
 	path = (char *) kmalloc (PATH_MAX, GFP_KERNEL);
+	if (path == NULL)
+		goto out;
 
-	result = NULL;
-
-	if (path == NULL) {
-		final = ERR_PTR (-ENOMEM);
-	} else {
-		struct file filp;
-		fill_new_filp (&filp, hlink);
-		filp.f_flags = O_RDONLY;
-		filp.f_pos = 0;
+	fill_new_filp (&filp, hlink);
+	filp.f_flags = O_RDONLY;
+	filp.f_pos = 0;
+
+	Printk (("hlink2inode "));
+	len = umsdos_file_read_kmem (&filp, path, hlink->d_inode->i_size);
+	if (len != hlink->d_inode->i_size)
+		goto out_noread;
+
+	/* start at root dentry */
+	dir = dget(base);
+	path[hlink->d_inode->i_size] = '\0';
+	pt = path;
+	while (1) {
+		char *start = pt;
+		int len;
+
+		while (*pt != '\0' && *pt != '/') pt++;
+		len = (int) (pt - start);
+		if (*pt == '/') *pt++ = '\0';
 
-		Printk (("hlink2inode "));
-		if (umsdos_file_read_kmem (&filp, path, hlink->d_inode->i_size) == hlink->d_inode->i_size) {
-			struct inode *dir;
-			char *pt = path;
-
-			dir = base->d_inode;	/* start at root inode */
-			path[hlink->d_inode->i_size] = '\0';
-			inc_count (dir);	/* since we're going to iput() it in the loop below... */
-
-			while (1) {
-				char *start = pt;
-				int len;
-
-				while (*pt != '\0' && *pt != '/') pt++;
-				len = (int) (pt - start);
-				if (*pt == '/') *pt++ = '\0';
-
-				d_dir = geti_dentry (dir);
-				dentry_dst = creat_dentry (start, len, NULL, d_dir);
-				if (dir->u.umsdos_i.i_emd_dir == 0) {
-					/* This is a DOS directory */
-
-					Printk (("hlink2inode /mn/: doing umsdos_rlookup_x on %.*s\n", (int) dentry_dst->d_name.len, dentry_dst->d_name.name));
-					ret = umsdos_rlookup_x (dir, dentry_dst, 1);
-				} else {
-					Printk (("hlink2inode /mn/: doing umsdos_lookup_x on %.*s\n", (int) dentry_dst->d_name.len, dentry_dst->d_name.name));
-					ret = umsdos_lookup_x (dir, dentry_dst, 1);
-				}
-				
-				iput (dir);	/* dir no longer needed */
-				Printk (("  returned %d\n", ret));
-				result = dentry_dst->d_inode;
-				inc_count (result);	/* we need inode to survive. We'll iput it in next loop */
-
-				fin_dentry (dentry_dst);	/* no longer needed - this is pair to creat_dentry */
-
-				Printk (("h2n lookup :%s: -> %d ", start, ret));
-				
-				if (ret != 0) {
-					iput (result);			/* we have no longer any use for it... */
-					final = ERR_PTR (ret);		/* path componenet not found ! */
-					break;
-				} else {
-					if (*pt != '\0') {
-						dir = result;
-					} else {			/* we're finished! */
-						final = creat_dentry (hlink->d_name.name, hlink->d_name.len, result, hlink->d_parent);
-						break;
-					}
-				}
-			} /* end while */
+		dentry_dst = umsdos_lookup_dentry(dir, start, len);
+		if (IS_ERR(dentry_dst))
+			break;
+		if (dir->d_inode->u.umsdos_i.i_emd_dir == 0) {
+			/* This is a DOS directory */
+			ret = umsdos_rlookup_x (dir->d_inode, dentry_dst, 1);
 		} else {
-			Printk (("umsdos_solve_hlink: failed reading pseudolink!\n"));
+			ret = umsdos_lookup_x (dir->d_inode, dentry_dst, 1);
 		}
-
-		Printk (("hlink2inode ret = %d %p -> %p\n", ret, hlink, result));
-		kfree (path);
+		Printk (("  returned %d\n", ret));
+		dput (dir);	/* dir no longer needed */
+		dir = dentry_dst;
+
+		Printk (("h2n lookup :%s: -> %d ", start, ret));
+		final = ERR_PTR (ret);
+		if (ret != 0) {
+			/* path component not found! */
+			break;
+		}
+		if (*pt == '\0') {	/* we're finished! */
+			final = umsdos_lookup_dentry(hlink->d_parent,
+						(char *) hlink->d_name.name,
+					 	hlink->d_name.len);
+			break;
+		}
+	} /* end while */
+	/*
+	 * See whether we found the path ...
+	 */
+	if (!IS_ERR(final)) {
+		if (!final->d_inode) {
+			d_instantiate(final, dir->d_inode);
+			/* we need inode to survive. */
+			dir->d_inode->i_count++;	
+		} else {
+			printk ("umsdos_solve_hlink: %s/%s already exists\n",
+				final->d_parent->d_name.name,
+				final->d_name.name);
+		}
+printk ("umsdos_solve_hlink: ret = %d, %s/%s -> %s/%s\n",
+ret, hlink->d_parent->d_name.name, hlink->d_name.name,
+final->d_parent->d_name.name, final->d_name.name);
 	}
+	dput(dir);
 
-	fin_dentry (hlink);	/* original hlink no longer needed */
+out_free:
+	kfree (path);
+
+out:
+	dput(hlink);	/* original hlink no longer needed */
   	check_dentry_path (hlink, "HLINK FIN hlink");
   	check_dentry_path (final, "HLINK RET final");
 	return final;
+
+out_noread:
+	printk("umsdos_solve_hlink: failed reading pseudolink!\n");
+	goto out_free;
 }	
 
 
@@ -1038,7 +918,7 @@
 	NULL,			/* no special open code */
 	NULL,			/* flush */
 	NULL,			/* no special release code */
-	NULL			/* fsync *//* in original NULL. changed to file_fsync. FIXME? /mn/ */
+	NULL			/* fsync */
 };
 
 struct inode_operations umsdos_dir_inode_operations =
@@ -1055,9 +935,9 @@
 	UMSDOS_rename,		/* rename */
 	NULL,			/* readlink */
 	NULL,			/* followlink */
-	generic_readpage,	/* readpage *//* in original NULL. changed to generic_readpage. FIXME? /mn/ */
+	generic_readpage,	/* readpage */
 	NULL,			/* writepage */
-	fat_bmap,		/* bmap *//* in original NULL. changed to fat_bmap. FIXME? /mn/ */
+	fat_bmap,		/* bmap */
 	NULL,			/* truncate */
 	NULL,			/* permission */
 	NULL,			/* smap */
diff -u --recursive --new-file v2.1.120/linux/fs/umsdos/emd.c linux/fs/umsdos/emd.c
--- v2.1.120/linux/fs/umsdos/emd.c	Sat Sep  5 16:46:41 1998
+++ linux/fs/umsdos/emd.c	Wed Sep  9 09:01:19 1998
@@ -129,27 +129,22 @@
 
 	Printk ((KERN_DEBUG " STARTED WRITE_KMEM /mn/\n"));
 	ret = umsdos_file_write_kmem_real (filp, buf, count);
-
-#warning Should d_drop be here ?
-#if 0
-	d_drop (filp->f_dentry);
-#endif
-
 	return ret;
 }
 
 
 
-
 /*
  * Write a block of bytes into one EMD file.
  * The block of data is NOT in user space.
  * 
  * Return 0 if OK, a negative error code if not.
+ *
+ * Note: buffer is in kernel memory, not in user space.
  */
 
 ssize_t umsdos_emd_dir_write (	struct file *filp,
-				char *buf,	/* buffer in kernel memory, not in user space */
+				char *buf,	
 				size_t count)
 {
 	int written;
@@ -168,7 +163,8 @@
 #endif
 
 	filp->f_flags = 0;
-	Printk (("umsdos_emd_dir_write /mn/: calling write_kmem with %p, %p, %d, %Ld\n", filp, buf, count, filp->f_pos));
+Printk (("umsdos_emd_dir_write /mn/: calling write_kmem with %p, %p, %d, %Ld\n",
+filp, buf, count, filp->f_pos));
 	written = umsdos_file_write_kmem (filp, buf, count);
 	Printk (("umsdos_emd_dir_write /mn/: write_kmem returned\n"));
 
@@ -184,11 +180,11 @@
 #endif
 
 #if UMS_DEBUG
-	if (written != count)
-		Printk ((KERN_ERR "umsdos_emd_dir_write: ERROR: written (%d) != count (%d)\n", written, count));
+if (written != count)
+printk(KERN_ERR "umsdos_emd_dir_write: ERROR: written (%d) != count (%d)\n",
+written, count);
 #endif
 
-
 	return written != count ? -EIO : 0;
 }
 
@@ -199,10 +195,9 @@
  *      The block of data is NOT in user space.
  *      Return 0 if OK, -EIO if any error.
  */
+/* buffer in kernel memory, not in user space */
 
-ssize_t umsdos_emd_dir_read (struct file *filp,
-			     char *buf,		/* buffer in kernel memory, not in user space */
-			     size_t count)
+ssize_t umsdos_emd_dir_read (struct file *filp, char *buf, size_t count)
 {
 	long int ret = 0;
 	int sizeread;
@@ -216,7 +211,8 @@
 	filp->f_flags = 0;
 	sizeread = umsdos_file_read_kmem (filp, buf, count);
 	if (sizeread != count) {
-		printk ("UMSDOS:  problem with EMD file:  can't read pos = %Ld (%d != %d)\n", filp->f_pos, sizeread, count);
+printk ("UMSDOS:  problem with EMD file:  can't read pos = %Ld (%d != %d)\n",
+filp->f_pos, sizeread, count);
 		ret = -EIO;
 	}
 #ifdef __BIG_ENDIAN
@@ -234,40 +230,72 @@
 }
 
 
+/*
+ * Create the EMD dentry for a directory.
+ */
+struct dentry *umsdos_get_emd_dentry(struct dentry *parent)
+{
+	struct dentry *demd;
+
+	demd = umsdos_lookup_dentry (parent, UMSDOS_EMD_FILE, 
+					UMSDOS_EMD_NAMELEN);
+	return demd;
+}
 
 /*
- * this checks weather filp points to directory or file,
- * and if directory, it assumes that it has not yet been
- * converted to point to EMD_FILE, and fixes it
- *
- * calling code should save old filp->f_dentry, call fix_emd_filp
- * and if it succeeds (return code 0), do fin_dentry (filp->f_dentry)
- * when it is over. It should also restore old filp->f_dentry.
- *
+ * Check whether a directory has an EMD file.
  */
+int umsdos_have_emd(struct dentry *dir)
+{
+	struct dentry *demd = umsdos_get_emd_dentry (dir);
+	int found = 0;
 
-int fix_emd_filp (struct file *filp)
+	if (!IS_ERR(demd)) {
+		if (demd->d_inode)
+			found = 1;
+		dput(demd);
+	}
+	return found;
+}
+
+/*
+ * Create the EMD file for a directory if it doesn't
+ * already exist. Returns 0 or and error code.
+ */
+int umsdos_make_emd(struct dentry *parent)
 {
-	struct inode *dir=filp->f_dentry->d_inode;
-	struct inode *emd_dir;
-  
-	/* is current file (which should be EMD or directory) EMD? */
-	if (dir->u.umsdos_i.i_emd_owner == 0xffffffff) {
-		dget (filp->f_dentry);
-		Printk ((KERN_WARNING "\nfix_emd_filp: EMD already done (should not be !)\n\n"));
-		return 0;
+	struct dentry *demd = umsdos_get_emd_dentry(parent);
+	struct inode *inode;
+	int err = PTR_ERR(demd);
+
+	if (IS_ERR(demd))
+		goto out;
+
+	/* already created? */
+	inode = demd->d_inode;
+	if (inode) {
+		parent->d_inode->u.umsdos_i.i_emd_dir = inode->i_ino;
+		err = 0;
+		goto out_dput;
 	}
-	/* it is not, we need to make it so */
-	
-	emd_dir = umsdos_emd_dir_lookup (dir, 0);
-	if (emd_dir == NULL) {
-		Printk ((KERN_ERR "\nfix_emd_filp: EMD not found (should never happen)!!!\n\n"));
-		return -99;
+
+printk("umsdos_make_emd: creating %s/%s\n",
+parent->d_name.name, demd->d_name.name);
+
+	err = msdos_create(parent->d_inode, demd, S_IFREG | 0777);
+	if (err) {
+		printk (KERN_WARNING "UMSDOS: Can't create EMD file\n");
+		goto out_dput;
 	}
-  
-	filp->f_dentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, emd_dir, filp->f_dentry);	/* filp->f_dentry is dir containing EMD file, so it IS the parent dentry... */
+	inode = demd->d_inode;
+	parent->d_inode->u.umsdos_i.i_emd_dir = inode->i_ino;
+	/* Disable UMSDOS_notify_change() for EMD file */
+	inode->u.umsdos_i.i_emd_owner = 0xffffffff;
 
-	return 0;
+out_dput:
+	dput(demd);
+out:
+	return err;
 }
 
 
@@ -275,7 +303,8 @@
  * Locate the EMD file in a directory.
  * 
  * Return NULL if error, dir->u.umsdos_i.emd_inode if OK. 
- * caller must iput() returned inode when finished with it!
+ * Caller must iput() returned inode when finished with it!
+ * Note: deprecated; get rid of this soon!
  */
 
 struct inode *umsdos_emd_dir_lookup (struct inode *dir, int creat)
@@ -285,102 +314,77 @@
 	int rv;
 
 	Printk ((KERN_DEBUG "Entering umsdos_emd_dir_lookup\n"));
-	if (!dir) printk (KERN_CRIT "umsdos FATAL: should never happen: dir=NULL!\n");
+	if (!dir) {
+		printk (KERN_CRIT "umsdos_emd_dir_lookup: FATAL, dir=NULL!\n");
+		goto out;
+	}
 	check_inode (dir);
 	
 	if (dir->u.umsdos_i.i_emd_dir != 0) {
 		ret = iget (dir->i_sb, dir->u.umsdos_i.i_emd_dir);
-		Printk (("umsdos_emd_dir_lookup: deja trouve %ld %p\n", dir->u.umsdos_i.i_emd_dir, ret));
-	} else {
-		PRINTK ((KERN_DEBUG "umsdos /mn/: Looking for %.*s -", UMSDOS_EMD_NAMELEN, UMSDOS_EMD_FILE));
-
-		d_dir = geti_dentry (dir);
-		dlook = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL, d_dir);
-		rv = umsdos_real_lookup (dir, dlook);
+		Printk (("umsdos_emd_dir_lookup: deja trouve %ld %p\n",
+			dir->u.umsdos_i.i_emd_dir, ret));
+		goto out;
+	}
+
+	PRINTK ((KERN_DEBUG "umsdos /mn/: Looking for %.*s -",
+		UMSDOS_EMD_NAMELEN, UMSDOS_EMD_FILE));
+
+	d_dir = geti_dentry (dir);
+	if (!d_dir) {
+printk("UMSDOS: flaky i_dentry hack failed\n");
+		goto out;
+	}
+	dlook = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL, d_dir);
+	if (!dlook)
+		goto out;
+	rv = umsdos_real_lookup (dir, dlook);
 		
-		PRINTK ((KERN_DEBUG "-returned %d\n", rv));
-		Printk ((KERN_INFO "emd_dir_lookup "));
-		
-		ret = dlook->d_inode;
-		if (ret) {
-			Printk (("Found --linux "));
-			dir->u.umsdos_i.i_emd_dir = ret->i_ino;
-			inc_count (ret);	/* we'll need the inode */
-			fin_dentry (dlook);	/* but not dentry */
-			check_inode (ret);
-		} else if (creat) {
-			int code;
-			
-			Printk ((" * ERROR * /mn/: creat not yet implemented? not fixed? "));
-			Printk (("avant create "));
-			inc_count (dir);
-
-			check_inode (ret);
-			code = compat_msdos_create (dir, UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, S_IFREG | 0777, &ret);
-			check_inode (ret);
-			Printk (("Creat EMD code %d ret %p ", code, ret));
-			if (ret != NULL) {
-				Printk ((" ino=%lu", ret->i_ino));
-				dir->u.umsdos_i.i_emd_dir = ret->i_ino;
-			} else {
-				printk (KERN_WARNING "UMSDOS: Can't create EMD file\n");
-			}
-		}
+	PRINTK ((KERN_DEBUG "-returned %d\n", rv));
+	Printk ((KERN_INFO "emd_dir_lookup "));
 		
-		if (ret != NULL) {
-			/* Disable UMSDOS_notify_change() for EMD file */
-			/* inc_count (ret); // we need to return with incremented inode. FIXME: didn't umsdos_real_lookup already did that? and compat_msdos_create ? */
-			ret->u.umsdos_i.i_emd_owner = 0xffffffff;
-		}
-	}
-
-#if UMS_DEBUG
-	Printk ((KERN_DEBUG "umsdos_emd_dir_lookup returning %p /mn/\n", ret));
-	if (ret != NULL)
-		Printk ((KERN_DEBUG " returning ino=%lu\n", ret->i_ino));
-#endif
-	return ret;
-}
-
-
-
-/*
- * creates an EMD file
- * 
- * Return NULL if error, dir->u.umsdos_i.emd_inode if OK. 
- */
-
-struct inode *umsdos_emd_dir_create (struct inode *dir, struct dentry *dentry, int mode)
-{
-	struct inode *ret = NULL;
-
-	if (dir->u.umsdos_i.i_emd_dir != 0) {
-		ret = iget (dir->i_sb, dir->u.umsdos_i.i_emd_dir);
-		Printk (("deja trouve %lu %p", dir->u.umsdos_i.i_emd_dir, ret));
-	} else {
-
+	ret = dlook->d_inode;
+	if (ret) {
+		Printk (("Found --linux "));
+		dir->u.umsdos_i.i_emd_dir = ret->i_ino;
+		ret->i_count++;	/* we'll need the inode */
+		check_inode (ret);
+	} else if (creat) {
 		int code;
-
+			
+		Printk ((" * ERROR * /mn/: creat not yet implemented? not fixed? "));
 		Printk (("avant create "));
-		inc_count (dir);
-		code = compat_msdos_create (dir, UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, S_IFREG | 0777, &ret);
+
+		check_inode (ret);
+		code = compat_msdos_create (dir, UMSDOS_EMD_FILE, 
+						UMSDOS_EMD_NAMELEN, 
+						S_IFREG | 0777, &ret);
+		check_inode (ret);
 		Printk (("Creat EMD code %d ret %p ", code, ret));
 		if (ret != NULL) {
+			Printk ((" ino=%lu", ret->i_ino));
 			dir->u.umsdos_i.i_emd_dir = ret->i_ino;
 		} else {
-			printk ("UMSDOS: Can't create EMD file\n");
+			printk (KERN_WARNING "UMSDOS: Can't create EMD file\n");
 		}
 	}
-
+	dput(dlook);
+		
 	if (ret != NULL) {
 		/* Disable UMSDOS_notify_change() for EMD file */
 		ret->u.umsdos_i.i_emd_owner = 0xffffffff;
 	}
+
+out:
+#if UMS_DEBUG
+	Printk ((KERN_DEBUG "umsdos_emd_dir_lookup returning %p /mn/\n", ret));
+	if (ret != NULL)
+		Printk ((KERN_DEBUG " returning ino=%lu\n", ret->i_ino));
+#endif
 	return ret;
 }
 
 
-
 /*
  * Read an entry from the EMD file.
  * Support variable length record.
@@ -389,13 +393,11 @@
  * does not change {d,i}_count
  */
 
-int umsdos_emd_dir_readentry (	     struct file *filp,
-				     struct umsdos_dirent *entry)
+int umsdos_emd_dir_readentry (struct file *filp, struct umsdos_dirent *entry)
 {
 	int ret;
 
 	Printk ((KERN_DEBUG "umsdos_emd_dir_readentry /mn/: entering.\n"));
-	Printk (("umsdos_emd_dir_readentry /mn/: reading EMD %.*s (ino=%lu) at pos=%d\n", (int) filp->f_dentry->d_name.len, filp->f_dentry->d_name.name, filp->f_dentry->d_inode->i_ino, (int) filp->f_pos));
 
 	ret = umsdos_emd_dir_read (filp, (char *) entry, UMSDOS_REC_SIZE);
 	if (ret == 0) {	/* if no error */
@@ -403,41 +405,48 @@
 		int recsize = umsdos_evalrecsize (entry->name_len);
 
 		if (recsize > UMSDOS_REC_SIZE) {
-			Printk ((KERN_DEBUG "umsdos_emd_dir_readentry /mn/: %d > %d!\n", recsize, UMSDOS_REC_SIZE));
-			ret = umsdos_emd_dir_read (filp, ((char *) entry) + UMSDOS_REC_SIZE, recsize - UMSDOS_REC_SIZE);
+Printk ((KERN_DEBUG "umsdos_emd_dir_readentry /mn/: %d > %d!\n",
+recsize, UMSDOS_REC_SIZE));
+			ret = umsdos_emd_dir_read (filp, 
+					((char *) entry) + UMSDOS_REC_SIZE,
+					recsize - UMSDOS_REC_SIZE);
 		}
 	}
 	Printk (("umsdos_emd_dir_readentry /mn/: ret=%d.\n", ret));
 	if (entry && ret == 0) {
-		Printk (("umsdos_emd_dir_readentry /mn/: returning len=%d,name=%.*s\n", (int) entry->name_len, (int) entry->name_len, entry->name));
+Printk (("umsdos_emd_dir_readentry /mn/: returning len=%d,name=%.*s\n",
+(int) entry->name_len, (int) entry->name_len, entry->name));
 	}
 	return ret;
 }
 
 
 
-
 /*
  * Write an entry in the EMD file.
  * Return 0 if OK, -EIO if some error.
  */
-
-int umsdos_writeentry (	      struct inode *dir,
-			      struct inode *emd_dir,
-			      struct umsdos_info *info,
-			      int free_entry)
-
-{				/* This entry is deleted, so write all 0's. */
-	int ret = 0;
-	struct dentry *emd_dentry;
-	struct file filp;
+static int umsdos_writeentry (struct dentry *parent, struct umsdos_info *info,
+				int free_entry)
+{
+	struct inode *dir = parent->d_inode;
 	struct umsdos_dirent *entry = &info->entry;
+	struct dentry *emd_dentry;
+	int ret;
 	struct umsdos_dirent entry0;
+	struct file filp;
 
-	fill_new_filp (&filp, NULL);
-
-	Printk (("umsdos_writeentry /mn/: entering...\n"));
-	emd_dentry = geti_dentry (emd_dir);
+	emd_dentry = umsdos_get_emd_dentry(parent);
+	ret = PTR_ERR(emd_dentry);
+	if (IS_ERR(emd_dentry))
+		goto out;
+	/* make sure there's an EMD file */
+	ret = -EIO;
+	if (!emd_dentry->d_inode) {
+printk("umsdos_writeentry: no EMD file in %s/%s\n",
+parent->d_parent->d_name.name, parent->d_name.name);
+		goto out_dput;
+	}
 
 	if (free_entry) {
 		/* #Specification: EMD file / empty entries
@@ -449,7 +458,8 @@
 		memset (&entry0, 0, sizeof (entry0));
 		entry = &entry0;
 	} else if (entry->name_len > 0) {
-		memset (entry->name + entry->name_len, '\0', sizeof (entry->name) - entry->name_len);
+		memset (entry->name + entry->name_len, '\0', 
+			sizeof (entry->name) - entry->name_len);
 		/* #Specification: EMD file / spare bytes
 		 * 10 bytes are unused in each record of the EMD. They
 		 * are set to 0 all the time, so it will be possible
@@ -458,25 +468,23 @@
 		 */
 		memset (entry->spare, 0, sizeof (entry->spare));
 	}
-	Printk (("umsdos_writeentry /mn/: if passed...\n"));
 
-	if (!info)
-		printk (KERN_ERR "UMSDOS:  /mn/ info is empty!  Oops!\n");
+	fill_new_filp (&filp, emd_dentry);
 	filp.f_pos = info->f_pos;
 	filp.f_reada = 0;
 	filp.f_flags = O_RDWR;
-	filp.f_dentry = emd_dentry;
-	filp.f_op = &umsdos_file_operations;	/* /mn/ - We have to fill it with dummy values so we won't segfault. */
 
+	/* write the entry and update the parent timestamps */
 	ret = umsdos_emd_dir_write (&filp, (char *) entry, info->recsize);
-	Printk (("emd_dir_write returned with %d!\n", ret));
-	if (ret != 0) {
-		printk ("UMSDOS:  problem with EMD file:  can't write\n");
-	} else {
+	if (!ret) {
 		dir->i_ctime = dir->i_mtime = CURRENT_TIME;
-		/* dir->i_dirt = 1; FIXME iput/dput ??? */
-	}
+		mark_inode_dirty(dir);
+	} else
+		printk ("UMSDOS:  problem with EMD file:  can't write\n");
 
+out_dput:
+	dput(emd_dentry);
+out:
 	Printk (("umsdos_writeentry /mn/: returning %d...\n", ret));
 	return ret;
 }
@@ -493,26 +501,19 @@
 
 
 
-
-
 /*
- * Fill the read buffer and take care of the byte remaining inside.
- * Unread bytes are simply move to the beginning.
+ * Fill the read buffer and take care of the bytes remaining inside.
+ * Unread bytes are simply moved to the beginning.
  * 
  * Return -ENOENT if EOF, 0 if OK, a negative error code if any problem.
  */
 
-static int umsdos_fillbuf (
-				  struct inode *inode,
-				  struct find_buffer *buf)
+static int umsdos_fillbuf (struct find_buffer *buf)
 {
-	int ret = -ENOENT;
+	struct inode *inode = buf->filp.f_dentry->d_inode;
 	int mustmove = buf->size - buf->pos;
-	int mustread;
-	int remain;
-	struct inode *old_ino;
-
-	PRINTK ((KERN_DEBUG "Entering umsdos_fillbuf, for inode %lu, buf=%p\n", inode->i_ino, buf));
+	int mustread, remain;
+	int ret = -ENOENT;
 
 	if (mustmove > 0) {
 		memcpy (buf->buffer, buf->buffer + buf->pos, mustmove);
@@ -523,10 +524,8 @@
 	if (remain < mustread)
 		mustread = remain;
 	if (mustread > 0) {
-		old_ino = buf->filp.f_dentry->d_inode;	/* FIXME: do we need to save/restore it ? */
-		buf->filp.f_dentry->d_inode = inode;
-		ret = umsdos_emd_dir_read (&buf->filp, buf->buffer + mustmove, mustread);
-		buf->filp.f_dentry->d_inode = old_ino;
+		ret = umsdos_emd_dir_read (&buf->filp, buf->buffer + mustmove,
+					 mustread);
 		if (ret == 0)
 			buf->size = mustmove + mustread;
 	} else if (mustmove) {
@@ -543,8 +542,6 @@
  * store it. if info->entry.name_len == 0, search the first empty
  * slot (of the proper size).
  * 
- * Caller must do iput on *pt_emd_dir.
- * 
  * Return 0 if found, -ENOENT if not found, another error code if
  * other problem.
  * 
@@ -556,144 +553,121 @@
  * To delete an entry, you find it, zero out the entry (memset)
  * and call umsdos_writeentry().
  * 
- * All this to say that umsdos_writeentry must be call after this
- * function since it rely on the f_pos field of info.
- *
- * calling code is expected to iput() returned *pt_emd_dir
+ * All this to say that umsdos_writeentry must be called after this
+ * function since it relies on the f_pos field of info.
  *
  */
+/* #Specification: EMD file structure
+ * The EMD file uses a fairly simple layout.  It is made of records
+ * (UMSDOS_REC_SIZE == 64).  When a name can't be written in a single
+ * record, multiple contiguous records are allocated.
+ */
 
-static int umsdos_find (       struct inode *dir,
-			       struct umsdos_info *info,	/* Hold name and name_len */
-								/* Will hold the entry found */
-			       struct inode **pt_emd_dir)	/* Will hold the emd_dir inode or NULL if not found */
-
+static int umsdos_find (struct dentry *parent, struct umsdos_info *info)
 {
-	/* #Specification: EMD file structure
-	 * The EMD file uses a fairly simple layout.  It is made of records
-	 * (UMSDOS_REC_SIZE == 64).  When a name can't be written in a single
-	 * record, multiple contiguous records are allocated.
-	 */
-	int ret = -ENOENT;
-	struct inode *emd_dir;
 	struct umsdos_dirent *entry = &info->entry;
+	int recsize = info->recsize;
+	struct dentry *demd;
+	struct inode *emd_dir;
+	int ret = -ENOENT;
+	struct find_buffer buf;
+	struct {
+		off_t posok;	/* Position available to store the entry */
+		int found;	/* A valid empty position has been found. */
+		off_t one;	/* One empty position -> maybe <- large enough */
+		int onesize;	/* size of empty region starting at one */
+	} empty;
 
-	Printk (("umsdos_find: locating %.*s in dir %lu\n", entry->name_len, entry->name, dir->i_ino));
-	check_inode (dir);
-
-	emd_dir = umsdos_emd_dir_lookup (dir, 1);
-	if (emd_dir != NULL) {
-		int recsize = info->recsize;
-		struct {
-			off_t posok;	/* Position available to store the entry */
-			int found;	/* A valid empty position has been found. */
-			off_t one;	/* One empty position -> maybe <- large enough */
-			int onesize;	/* size of empty region starting at one */
-		} empty;
-
-		/* Read several entries at a time to speed up the search. */
-		struct find_buffer buf;
-		struct dentry *demd;
+Printk (("umsdos_find: locating %s in %s/%s\n",
+entry->name, parent->d_parent->d_name.name, parent->d_name.name));
 
-		Printk (("umsdos_find: check emd_dir...\n"));
-		check_inode (emd_dir);
-		
-#if 0		/* FIXME! not needed. but there are count wraps. somewhere before umsdos_find there should be inc_count/iput pair around umsdos_find call.... */
-		inc_count (emd_dir);	/* since we are going to fin_dentry, and need emd_dir afterwards -- caling code will iput() it */
-#endif		
-		demd = geti_dentry (emd_dir);
-		if (demd) {
-			dget (demd);	/* because we'll have to dput it */
+	/*
+	 * Lookup the EMD file in the parent directory.
+	 */
+	demd = umsdos_get_emd_dentry(parent);
+	ret = PTR_ERR(demd);
+	if (IS_ERR(demd))
+		goto out;
+	/* make sure there's an EMD file ... */
+	ret = -ENOENT;
+	emd_dir = demd->d_inode;
+	if (!emd_dir)
+		goto out_dput;
+
+Printk(("umsdos_find: found EMD file %s/%s, ino=%p\n",
+demd->d_parent->d_name.name, demd->d_name.name, emd_dir));
+
+	fill_new_filp (&buf.filp, demd);
+
+	buf.pos = 0;
+	buf.size = 0;
+
+	empty.found = 0;
+	empty.posok = emd_dir->i_size;
+	empty.onesize = 0;
+	while (1) {
+		struct umsdos_dirent *rentry = (struct umsdos_dirent *)
+						(buf.buffer + buf.pos);
+		int file_pos = buf.filp.f_pos - buf.size + buf.pos;
+
+		if (buf.pos == buf.size) {
+			ret = umsdos_fillbuf (&buf);
+			if (ret < 0) {
+				/* Not found, so note where it can be added */
+				info->f_pos = empty.posok;
+				break;
+			}
+		} else if (rentry->name_len == 0) {
+			/* We are looking for an empty section at least */
+			/* as large as recsize. */
+			if (entry->name_len == 0) {
+				info->f_pos = file_pos;
+				ret = 0;
+				break;
+			} else if (!empty.found) {
+				if (empty.onesize == 0) {
+					/* This is the first empty record of a section. */
+					empty.one = file_pos;
+				}
+				/* grow the empty section */
+				empty.onesize += UMSDOS_REC_SIZE;
+				if (empty.onesize == recsize) {
+					/* Here is a large enough section. */
+					empty.posok = empty.one;
+					empty.found = 1;
+				}
+			}
+			buf.pos += UMSDOS_REC_SIZE;
 		} else {
-			/*
-			 * We don't have dentry alias for this inode. Too bad.
-			 * So we'll fake something (as best as we can).
-			 * (maybe we should do it in any case just to keep it simple?)
-			 *
-			 * Note that this is legal for EMD file, since in some places
-			 * we keep inode, but discard dentry (since we would have no way
-			 * to discard it later). Yes, this probably should be fixed somehow,
-			 * it is just that I don't have idea how right now, and I've spent
-			 * quite some time to track it down why it dies here. Maybe new emd_dir_lookup
-			 * which returns dentry ? hmmmm... FIXME...
-			 *
-			 */
-		 	Printk ((KERN_WARNING "umsdos_find: inode has no alias for EMD inode, fake it\n"));
-		 	demd = creat_dentry ("@emd_find@", 10, emd_dir, NULL);
-		}
-		
-		check_dentry_path (demd, " EMD_DIR_DENTRY umsdos_find");
-		
-		fill_new_filp (&buf.filp, demd);
+			int entry_size = umsdos_evalrecsize (rentry->name_len);
 
-		buf.pos = 0;
-		buf.size = 0;
-
-		empty.found = 0;
-		empty.posok = emd_dir->i_size;
-		empty.onesize = 0;
-		while (1) {
-			struct umsdos_dirent *rentry = (struct umsdos_dirent *)
-			(buf.buffer + buf.pos);
-			int file_pos = buf.filp.f_pos - buf.size + buf.pos;
-
-			if (buf.pos == buf.size) {
-				ret = umsdos_fillbuf (emd_dir, &buf);
+			if (buf.pos + entry_size > buf.size) {
+				ret = umsdos_fillbuf (&buf);
 				if (ret < 0) {
 					/* Not found, so note where it can be added */
 					info->f_pos = empty.posok;
 					break;
 				}
-			} else if (rentry->name_len == 0) {
-				/* We are looking for an empty section at least */
-				/* as large as recsize. */
-				if (entry->name_len == 0) {
+			} else {
+				empty.onesize = 0;	/* Reset the free slot search. */
+				if (entry->name_len == rentry->name_len
+				    && memcmp (entry->name, rentry->name, rentry->name_len) == 0) {
 					info->f_pos = file_pos;
+					*entry = *rentry;
 					ret = 0;
 					break;
-				} else if (!empty.found) {
-					if (empty.onesize == 0) {
-						/* This is the first empty record of a section. */
-						empty.one = file_pos;
-					}
-					/* grow the empty section */
-					empty.onesize += UMSDOS_REC_SIZE;
-					if (empty.onesize == recsize) {
-						/* Here is a large enough section. */
-						empty.posok = empty.one;
-						empty.found = 1;
-					}
-				}
-				buf.pos += UMSDOS_REC_SIZE;
-			} else {
-				int entry_size = umsdos_evalrecsize (rentry->name_len);
-
-				if (buf.pos + entry_size > buf.size) {
-					ret = umsdos_fillbuf (emd_dir, &buf);
-					if (ret < 0) {
-						/* Not found, so note where it can be added */
-						info->f_pos = empty.posok;
-						break;
-					}
 				} else {
-					empty.onesize = 0;	/* Reset the free slot search. */
-					if (entry->name_len == rentry->name_len
-					    && memcmp (entry->name, rentry->name, rentry->name_len) == 0) {
-						info->f_pos = file_pos;
-						*entry = *rentry;
-						ret = 0;
-						break;
-					} else {
-						buf.pos += entry_size;
-					}
+					buf.pos += entry_size;
 				}
 			}
 		}
-		umsdos_manglename (info);
-		fin_dentry (demd);
 	}
-	*pt_emd_dir = emd_dir;
+	umsdos_manglename (info);
+
+out_dput:
+	dput(demd);
 
+out:
 	Printk (("umsdos_find: returning %d\n", ret));
 	return ret;
 }
@@ -703,23 +677,21 @@
  * Add a new entry in the EMD file.
  * Return 0 if OK or a negative error code.
  * Return -EEXIST if the entry already exists.
- * 
+ *
  * Complete the information missing in info.
+ * 
+ * N.B. What if the EMD file doesn't exist?
  */
 
-int umsdos_newentry (	    struct inode *dir,
-			    struct umsdos_info *info)
+int umsdos_newentry (struct dentry *parent, struct umsdos_info *info)
 {
-	struct inode *emd_dir;
-	int ret = umsdos_find (dir, info, &emd_dir);
+	int err, ret = -EEXIST;
 
-	if (ret == 0) {
-		ret = -EEXIST;
-	} else if (ret == -ENOENT) {
-		ret = umsdos_writeentry (dir, emd_dir, info, 0);
+	err = umsdos_find (parent, info);
+	if (err && err == -ENOENT) {
+		ret = umsdos_writeentry (parent, info, 0);
 		Printk (("umsdos_writeentry EMD ret = %d\n", ret));
 	}
-	iput (emd_dir);
 	return ret;
 }
 
@@ -729,27 +701,27 @@
  * Return 0 if OK, an error code if not.
  */
 
-int umsdos_newhidden (	     struct inode *dir,
-			     struct umsdos_info *info)
+/* #Specification: hard link / hidden name
+ * When a hard link is created, the original file is renamed
+ * to a hidden name. The name is "..LINKNNN" where NNN is a
+ * number define from the entry offset in the EMD file.
+ */
+int umsdos_newhidden (struct dentry *parent, struct umsdos_info *info)
 {
-	struct inode *emd_dir;
 	int ret;
 
 	umsdos_parse ("..LINK", 6, info);
 	info->entry.name_len = 0;
-	ret = umsdos_find (dir, info, &emd_dir);
-	iput (emd_dir);
+	ret = umsdos_find (parent, info);
 	if (ret == -ENOENT || ret == 0) {
-		/* #Specification: hard link / hidden name
-		 * When a hard link is created, the original file is renamed
-		 * to a hidden name. The name is "..LINKNNN" where NNN is a
-		 * number define from the entry offset in the EMD file.
-		 */
-		info->entry.name_len = sprintf (info->entry.name, "..LINK%ld", info->f_pos);
+		info->entry.name_len = sprintf (info->entry.name,
+						"..LINK%ld", info->f_pos);
 		ret = 0;
 	}
 	return ret;
 }
+
+
 /*
  * Remove an entry from the EMD file.
  * Return 0 if OK, a negative error code otherwise.
@@ -757,72 +729,75 @@
  * Complete the information missing in info.
  */
 
-int umsdos_delentry (	    struct inode *dir,
-			    struct umsdos_info *info,
-			    int isdir)
+int umsdos_delentry (struct dentry *parent, struct umsdos_info *info, int isdir)
 {
-	struct inode *emd_dir;
-	int ret = umsdos_find (dir, info, &emd_dir);
+	int ret;
 
-	if (ret == 0) {
-		if (info->entry.name_len != 0) {
-			if ((isdir != 0) != (S_ISDIR (info->entry.mode) != 0)) {
-				if (S_ISDIR (info->entry.mode)) {
-					ret = -EISDIR;
-				} else {
-					ret = -ENOTDIR;
-				}
-			} else {
-				ret = umsdos_writeentry (dir, emd_dir, info, 1);
-			}
+	ret = umsdos_find (parent, info);
+	if (ret)
+		goto out;
+	if (info->entry.name_len == 0)
+		goto out;
+
+	if ((isdir != 0) != (S_ISDIR (info->entry.mode) != 0)) {
+		if (S_ISDIR (info->entry.mode)) {
+			ret = -EISDIR;
+		} else {
+			ret = -ENOTDIR;
 		}
+		goto out;
 	}
-	iput (emd_dir);
+	ret = umsdos_writeentry (parent, info, 1);
+
+out:
 	return ret;
 }
 
 
 /*
- * Verify that a EMD directory is empty. Return 
+ * Verify that an EMD directory is empty.
+ * Return: 
  * 0 if not empty,
- * 1 if empty,
+ * 1 if empty (except for EMD file),
  * 2 if empty or no EMD file.
  */
 
-int umsdos_isempty (struct inode *dir)
+int umsdos_isempty (struct dentry *dentry)
 {
-	struct dentry *dentry, *d_dir;
-
+	struct dentry *demd;
 	int ret = 2;
-	struct inode *emd_dir = umsdos_emd_dir_lookup (dir, 0);
+	struct file filp;
 
+	demd = umsdos_get_emd_dentry(dentry);
+	if (IS_ERR(demd))
+		goto out;
 	/* If the EMD file does not exist, it is certainly empty. :-) */
-	if (emd_dir != NULL) {
-		struct file filp;
+	if (!demd->d_inode)
+		goto out_dput;
 
-		d_dir = geti_dentry (dir);
-		dentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, emd_dir, d_dir);
-		check_dentry_path (dentry, "umsdos_isempty BEGIN");
-		fill_new_filp (&filp, dentry);
-		filp.f_pos = 0;
-		filp.f_flags = O_RDONLY;
-
-		ret = 1;
-		while (filp.f_pos < emd_dir->i_size) {
-			struct umsdos_dirent entry;
+	fill_new_filp (&filp, demd);
+	filp.f_flags = O_RDONLY;
 
-			if (umsdos_emd_dir_readentry (&filp, &entry) != 0) {
-				ret = 0;
-				break;
-			} else if (entry.name_len != 0) {
-				ret = 0;
-				break;
-			}
+	ret = 1;
+	while (filp.f_pos < demd->d_inode->i_size) {
+		struct umsdos_dirent entry;
+
+		if (umsdos_emd_dir_readentry (&filp, &entry) != 0) {
+			ret = 0;
+			break;
+		}
+		if (entry.name_len != 0) {
+			ret = 0;
+			break;
 		}
-		fin_dentry (dentry);
-		check_dentry_path (dentry, "umsdos_isempty END");
-		iput (emd_dir);
 	}
+
+out_dput:
+	dput(demd);
+out:
+printk("umsdos_isempty: checked %s/%s, empty=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, ret);
+
 	return ret;
 }
 
@@ -832,28 +807,28 @@
  *
  * does not change i_count
  */
+/* 0: anything */
+/* 1: file */
+/* 2: directory */
 
-int umsdos_findentry (	     struct inode *dir,
-			     struct umsdos_info *info,
-			     int expect)
-				/* 0: anything */
-				/* 1: file */
-				/* 2: directory */
+int umsdos_findentry (struct dentry *parent, struct umsdos_info *info,
+			int expect)
 {		
-	struct inode *emd_dir=NULL;
-	int ret = umsdos_find (dir, info, &emd_dir);
+	int ret;
 
-	if (ret == 0) {
-		if (expect != 0) {
-			if (S_ISDIR (info->entry.mode)) {
-				if (expect != 2)
-					ret = -EISDIR;
-			} else if (expect == 2) {
-				ret = -ENOTDIR;
-			}
+	ret = umsdos_find (parent, info);
+	if (ret)
+		goto out;
+
+	if (expect != 0) {
+		if (S_ISDIR (info->entry.mode)) {
+			if (expect != 2)
+				ret = -EISDIR;
+		} else if (expect == 2) {
+			ret = -ENOTDIR;
 		}
 	}
-	iput (emd_dir);
+out:
 	Printk (("umsdos_findentry: returning %d\n", ret));
 	return ret;
 }
diff -u --recursive --new-file v2.1.120/linux/fs/umsdos/inode.c linux/fs/umsdos/inode.c
--- v2.1.120/linux/fs/umsdos/inode.c	Sat Sep  5 16:46:41 1998
+++ linux/fs/umsdos/inode.c	Wed Sep  9 09:01:19 1998
@@ -28,244 +28,55 @@
 
 /*
  * returns inode->i_dentry
- *
+ * Note: Deprecated; won't work reliably
  */
 
-inline struct dentry *geti_dentry (struct inode *inode)
+struct dentry *geti_dentry (struct inode *inode)
 {
 	struct dentry *ret;
+
 	if (!inode) {
 		printk (KERN_ERR "geti_dentry: ERROR: inode is NULL!\n");
 		return NULL;
 	}
-	if (inode->i_dentry.next == inode->i_dentry.next->next) {
-		printk (KERN_WARNING "geti_dentry: WARNING: inode does not have an dentry. returning NULL.\n");
+	if (list_empty(&inode->i_dentry)) {
+		printk (KERN_WARNING 
+			"geti_dentry: WARNING: no dentry for inode %ld\n",
+			inode->i_ino);
 		return NULL;
 	}
 	ret = list_entry (inode->i_dentry.next, struct dentry, d_alias);
 
-	if (IS_ERR(ret)) {
-		Printk ((KERN_WARNING "geti_dentry: checking dentry... it is ERR(%ld) !\n", PTR_ERR(ret)));
-	}
-	
-	PRINTK ((KERN_DEBUG "geti_dentry : inode %lu: i_dentry is %p\n", inode->i_ino, ret));
+	PRINTK ((KERN_DEBUG "geti_dentry : inode %lu, dentry is %s/%s\n", 
+		inode->i_ino, ret->d_parent->d_name.name, ret->d_name.name));
 	return ret;
 }
 
 
-
-/*
- * makes inode->i_count++
- *
- */
-
-inline void inc_count (struct inode *inode)
-{
-	inode->i_count++;
-	PRINTK ((KERN_DEBUG "inc_count: inode %lu incremented count to %d\n", inode->i_ino, inode->i_count));
-}
-
-
 /*
- * makes empty filp
- *
+ * Initialize a private filp
  */
-
 void fill_new_filp (struct file *filp, struct dentry *dentry)
 {
-	Printk (("/mn/ fill_new_filp: filling empty filp at %p\n", filp));
-	if (dentry)
-		Printk (("     dentry=%.*s\n", (int) dentry->d_name.len, dentry->d_name.name));
-	else
-		Printk (("     dentry is NULL ! you must fill it later...\n"));
+	if (!dentry)
+		printk("fill_new_filp: NULL dentry!\n");
 
 	memset (filp, 0, sizeof (struct file));
-
-	filp->f_pos = 0;
 	filp->f_reada = 1;
 	filp->f_flags = O_RDWR;
 	filp->f_dentry = dentry;
-	filp->f_op = &umsdos_file_operations;	/* /mn/ - we have to fill it with SOMETHING */
+	filp->f_op = &umsdos_file_operations;
 }
 
 
-
-#if UMS_DEBUG
-/*
- * check a superblock
- */
-
-void check_sb (struct super_block *sb, const char c)
-{
-	if (sb) {
-		Printk ((" (has %c_sb=%d, %d)", c, MAJOR (sb->s_dev), MINOR (sb->s_dev)));
-	} else {
-		Printk ((" (%c_sb is NULL)", c));
-	}
-} 
-
-/*
- * check an inode
- */
-
-void check_inode (struct inode *inode)
-{
-	if (inode) {
-		Printk ((KERN_DEBUG "*   inode is %lu (i_count=%d)", inode->i_ino, inode->i_count));
-		check_sb (inode->i_sb, 'i');
-		
-		if (inode->i_dentry.next) {	/* FIXME: does this work ? */
-			Printk ((" (has i_dentry)"));
-		} else {
-			Printk ((" (NO i_dentry)"));
-		}
-		
-		if (inode->i_op == NULL) {
-			Printk ((" (i_op is NULL)\n"));
-		} else if (inode->i_op == &umsdos_dir_inode_operations) {
-			Printk ((" (i_op is umsdos_dir_inode_operations)\n"));
-		} else if (inode->i_op == &umsdos_file_inode_operations) {
-			Printk ((" (i_op is umsdos_file_inode_operations)\n"));
-		} else if (inode->i_op == &umsdos_file_inode_operations_no_bmap) {
-			Printk ((" (i_op is umsdos_file_inode_operations_no_bmap)\n"));
-		} else if (inode->i_op == &umsdos_file_inode_operations_readpage) {
-			Printk ((" (i_op is umsdos_file_inode_operations_readpage)\n"));
-		} else if (inode->i_op == &umsdos_rdir_inode_operations) {
-			Printk ((" (i_op is umsdos_rdir_inode_operations)\n"));
-		} else if (inode->i_op == &umsdos_symlink_inode_operations) {
-			Printk ((" (i_op is umsdos_symlink_inode_operations)\n"));
-		} else {
-			Printk ((" (i_op is UNKNOWN: %p)\n", inode->i_op));
-		}
-	} else {
-		Printk ((KERN_DEBUG "*   inode is NULL\n"));
-	}
-}
-
-/*
- * checks all inode->i_dentry
- *
- */
-void checkd_inode (struct inode *inode)
-{
-	struct dentry *ret;
-	struct list_head *cur;
-	int count = 0;
-	if (!inode) {
-		printk (KERN_ERR "checkd_inode: inode is NULL!\n");
-		return;
-	}
-
-	Printk ((KERN_DEBUG "checkd_inode:  inode %lu\n", inode->i_ino));
-	cur = inode->i_dentry.next;
-	while (count++ < 10) {
-		PRINTK (("1..."));
-		if (!cur) {
-			Printk ((KERN_ERR "checkd_inode: *** NULL reached. exit.\n"));
-			return;
-		}
-		PRINTK (("2..."));
-		ret = list_entry (cur, struct dentry, d_alias);
-		PRINTK (("3..."));
-		if (cur == cur->next) {
-			Printk ((KERN_DEBUG "checkd_inode: *** cur=cur->next: normal exit.\n"));
-			return;
-		}
-		PRINTK (("4..."));
-		if (!ret) {
-			Printk ((KERN_ERR "checkd_inode: *** ret dentry is NULL. exit.\n"));
-			return;
-		}
-		PRINTK (("5... (ret=%p)...", ret));
-		PRINTK (("5.1.. (ret->d_dname=%p)...", &(ret->d_name)));
-		PRINTK (("5.1.1. (ret->d_dname.len=%d)...", (int) ret->d_name.len));
-		PRINTK (("5.1.2. (ret->d_dname.name=%c)...", ret->d_name.name));
-		Printk ((KERN_DEBUG "checkd_inode:   i_dentry is %.*s\n", (int) ret->d_name.len, ret->d_name.name));
-		PRINTK (("6..."));
-		cur = cur->next;
-		PRINTK (("7..."));
-#if 1
-		Printk ((KERN_DEBUG "checkd_inode: *** finished after count 1 (operator forced)\n"));
-		return;
-#endif		
-	}
-	Printk ((KERN_ERR "checkd_inode: *** OVER LIMIT (loop?) !\n"));
-	return;
-}
-
-/*
- * internal part of check_dentry. does the real job.
- *
- */
-
-void check_dent_int (struct dentry *dentry, int parent)
-{
-	if (parent) {
-		Printk ((KERN_DEBUG "*  parent(%d) dentry: %.*s\n", parent, (int) dentry->d_name.len, dentry->d_name.name));
-	} else {
-		Printk ((KERN_DEBUG "*  checking dentry: %.*s\n", (int) dentry->d_name.len, dentry->d_name.name));
-	}
-	check_inode (dentry->d_inode);
-	Printk ((KERN_DEBUG "*   d_count=%d", dentry->d_count));
-	check_sb (dentry->d_sb, 'd');
-	if (dentry->d_op == NULL) {
-		Printk ((" (d_op is NULL)\n"));
-	} else {
-		Printk ((" (d_op is UNKNOWN: %p)\n", dentry->d_op));
-	}
-}
-
-/*
- * checks dentry with full traceback to root and prints info. Limited to 10 recursive depths to avoid infinite loops.
- *
- */
-
-void check_dentry_path (struct dentry *dentry, const char *desc)
-{
-	int count=0;
-	Printk ((KERN_DEBUG "*** check_dentry_path: %.60s\n", desc));
-
-	if (!dentry) {
-		Printk ((KERN_DEBUG "*** checking dentry... it is NULL !\n"));
-		return;
-	}
-	if (IS_ERR(dentry)) {
-		Printk ((KERN_DEBUG "*** checking dentry... it is ERR(%ld) !\n", PTR_ERR(dentry)));
-		return;
-	}
-	
-	while (dentry && count < 10) {
-		check_dent_int (dentry, count++);
-		if (dentry == dentry->d_parent) {
-			Printk ((KERN_DEBUG "*** end checking dentry (root reached ok)\n"));
-			break;
-		}
-		dentry = dentry->d_parent;
-	}
-
-	if (count >= 10) {	/* if infinite loop detected */
-		Printk ((KERN_ERR "*** WARNING ! INFINITE LOOP ! check_dentry_path aborted !\n"));
-	}
-	
-	if (!dentry) {
-		Printk ((KERN_ERR "*** WARNING ! found NULL dentry ! check_dentry_path aborted !\n"));
-	}
-}
-#else
-void check_sb (struct super_block *sb, const char c) {};
-void check_inode (struct inode *inode) {};
-void checkd_inode (struct inode *inode) {};
-void check_dentry_path (struct dentry *dentry, const char *desc) {};
-#endif	/* UMS_DEBUG */
-
-
-
 /*
  * makes dentry. for name name with length len.
  * if inode is not NULL, puts it also.
+ * Note: Deprecated; use umsdos_lookup_dentry
  */
 
-struct dentry *creat_dentry (const char *name, const int len, struct inode *inode, struct dentry *parent)
+struct dentry *creat_dentry (const char *name, const int len, 
+				struct inode *inode, struct dentry *parent)
 {
 /* FIXME /mn/: parent is not passed many times... if it is not, dentry should be destroyed before someone else gets to use it */
 
@@ -279,15 +90,9 @@
 
 	qname.name = name;
 	qname.len = len;
-#if 1
-	#warning is full_name_hash OK for normal filenames? And for MSDOSFS accessed EMD files?
 	qname.hash = full_name_hash (name, len);
-#else
-	qname.hash = 0;
-#endif	
 
 	ret = d_alloc (parent, &qname);		/* create new dentry */
-	ret->d_inode = NULL;
 
 	if (parent) {
 #if 0
@@ -303,7 +108,10 @@
 
 
 	if (inode) {
-		if (!ret->d_sb)	ret->d_sb = inode->i_sb;	/* try to fill it in if available. If available in parent->d_sb, d_alloc will add it automatically */
+		/* try to fill it in if available. If available in 
+		 * parent->d_sb, d_alloc will add it automatically
+		 */
+		if (!ret->d_sb)	ret->d_sb = inode->i_sb;
 		d_add (ret, inode);
 	}
 
@@ -317,72 +125,17 @@
 }
 
 
-/*
- * removes temporary dentry created by creat_dentry
- * it must have d_count of 1, and associated inode i_count of 1
- * to be completely cleared.
- *
- */
-
-void kill_dentry (struct dentry *dentry)
-{
-	if (dentry) {
-		check_dentry_path (dentry, "KILL_DENTRY B4");
-		/* this idea for killing dentry (d_drop/dput pair) from NFS code. dcache.c code&comments seems to agree */
-#if 0
-		d_drop (dentry);
-		dput (dentry);	/* we are done with it */
-#endif		
-		check_dentry_path (dentry, "KILL_DENTRY AFT");
-	} else {
-		Printk (("kill_dentry: dentry is NULL ?!\n"));
-	}
-
-
-	Printk ((KERN_DEBUG "kill_dentry: exiting...\n"));
-	return;
-}
-
-
-/*
- * finishes work with dentry
- * it must have d_count of 1, and associated inode i_count of 1
- * to be completely cleared.
- *
- * Currently, this is same as kill_dentry, but this may (will) change.
- * kill_dentry will eventualy be killed (he who lives by the sword, dies
- * by the sword :-) when all faked dentries are nuked out...
- *
- */
-
-void fin_dentry (struct dentry *dentry)
-{
-	if (dentry) {
-		if (IS_ERR(dentry)) {
-			Printk ((KERN_WARNING "fin_dentry: dentry is IS_ERR (%ld)?!\n", PTR_ERR (dentry)));
-		} else {
-			/* this idea for killing dentry (d_drop/dput pair) from NFS code. dcache.c code&comments seems to agree */
-			d_drop (dentry);
-			dput (dentry);	/* we are done with it */
-		}
-	} else {
-		Printk ((KERN_WARNING "fin_dentry: dentry is NULL ?!\n"));
-	}
-
-	PRINTK ((KERN_DEBUG "fin_dentry: exiting...\n"));
-	return;
-}
-
-
 void UMSDOS_put_inode (struct inode *inode)
 {
-	PRINTK ((KERN_DEBUG "put inode %p (%lu) owner %lu pos %lu dir %lu count=%d\n", inode
-		 ,inode->i_ino
+	PRINTK ((KERN_DEBUG 
+		"put inode %p (%lu) owner %lu pos %lu dir %lu count=%d\n"
+		 ,inode, inode->i_ino
 		 ,inode->u.umsdos_i.i_emd_owner, inode->u.umsdos_i.pos
 		 ,inode->u.umsdos_i.i_emd_dir, inode->i_count));
 
 	if (inode && pseudo_root && inode == pseudo_root) {
-		printk (KERN_ERR "Umsdos: Oops releasing pseudo_root. Notify jacques@solucorp.qc.ca\n");
+		printk (KERN_ERR "Umsdos: Oops releasing pseudo_root."
+			" Notify jacques@solucorp.qc.ca\n");
 	}
 
 	fat_put_inode (inode);
@@ -392,61 +145,84 @@
 void UMSDOS_put_super (struct super_block *sb)
 {
 	Printk ((KERN_DEBUG "UMSDOS_put_super: entering\n"));
-	check_dentry_path (sb->s_root, "put_super: START");
 	msdos_put_super (sb);
 	MOD_DEC_USE_COUNT;
 }
 
 
-
 /*
  * Call msdos_lookup, but set back the original msdos function table.
  * Return 0 if OK, or a negative error code if not.
+ * Dentry will hold inode of the file, if successful
  */
-int umsdos_real_lookup (       struct inode *dir,
-			       struct dentry *dentry)	/* Will hold inode of the file, if successful */
+int umsdos_real_lookup (struct inode *dir, struct dentry *dentry)
 {
 	int ret;
 
-	PRINTK ((KERN_DEBUG "umsdos_real_lookup: looking for %.*s /", dentry->d_name.len, dentry->d_name.name));
-	inc_count (dir);
+	PRINTK ((KERN_DEBUG "umsdos_real_lookup: looking for %s/%s /",
+		dentry->d_parent->d_name.name, dentry->d_name.name));
 	ret = msdos_lookup (dir, dentry);
-	dentry->d_op = NULL;	/* FIXME: Not needed? - if it was good once for MSDOS, it will be good any other time also. I hope :) */
-	iput (dir);		/* pair to inc_count(dir) above */
 	PRINTK (("/ returned %d\n", ret));
 
 	return ret;
 }
 
 /*
+ * Complete the setup of an directory dentry.
+ * First, it completes the function pointers, then
+ * it locates the EMD file. If the EMD is there, then plug the
+ * umsdos function table. If not, use the msdos one.
+ *
+ * {i,d}_counts are untouched by this function.
+ */
+void umsdos_setup_dir(struct dentry *dir)
+{
+	struct inode *inode = dir->d_inode;
+
+	if (!S_ISDIR(inode->i_mode))
+		printk(KERN_ERR "umsdos_setup_dir: %s/%s not a dir!\n",
+			dir->d_parent->d_name.name, dir->d_name.name);
+
+	inode->u.umsdos_i.i_emd_dir = 0;
+	inode->i_op = &umsdos_rdir_inode_operations;
+	if (umsdos_have_emd(dir)) {
+Printk((KERN_DEBUG "umsdos_setup_dir: %s/%s using EMD\n",
+dir->d_parent->d_name.name, dir->d_name.name));
+		inode->i_op = &umsdos_dir_inode_operations;
+	}
+}
+
+/*
  * Complete the setup of an directory inode.
  * First, it completes the function pointers, then
  * it locates the EMD file. If the EMD is there, then plug the
  * umsdos function table. If not, use the msdos one.
  *
  * {i,d}_counts are untouched by this function.
+ * Note: Deprecated; use above function if possible.
  */
 void umsdos_setup_dir_inode (struct inode *inode)
 {
+	struct inode *emd_dir;
+
 	inode->u.umsdos_i.i_emd_dir = 0;
-	{
-		struct inode *emd_dir;
 
-		Printk ((KERN_DEBUG "umsdos_setup_dir_inode: Entering for inode=%lu\n", inode->i_ino));
-		check_inode (inode);
-		emd_dir = umsdos_emd_dir_lookup (inode, 0);
-		Printk ((KERN_DEBUG "umsdos_setup_dir_inode: umsdos_emd_dir_lookup for inode=%lu returned %p\n", inode->i_ino, emd_dir));
-		check_inode (inode);
-		check_inode (emd_dir);
-
-		if (emd_dir == NULL) {
-			Printk ((KERN_DEBUG "umsdos_setup_dir_inode /mn/: Setting up rdir_inode_ops --> eg. NOT using EMD.\n"));
-			inode->i_op = &umsdos_rdir_inode_operations;
-		} else {
-			Printk ((KERN_DEBUG "umsdos_setup_dir_inode /mn/: Setting up dir_inode_ops --> eg. using EMD.\n"));
-			inode->i_op = &umsdos_dir_inode_operations;
-			iput (emd_dir);
-		}
+	Printk ((KERN_DEBUG 
+		"umsdos_setup_dir_inode: Entering for inode=%lu\n",
+		 inode->i_ino));
+	check_inode (inode);
+	emd_dir = umsdos_emd_dir_lookup (inode, 0);
+	Printk ((KERN_DEBUG "umsdos_setup_dir_inode: "
+		"umsdos_emd_dir_lookup for inode=%lu returned %p\n",
+		inode->i_ino, emd_dir));
+	check_inode (inode);
+	check_inode (emd_dir);
+
+	inode->i_op = &umsdos_rdir_inode_operations;
+	if (emd_dir) {
+		Printk ((KERN_DEBUG "umsdos_setup_dir_inode: using EMD.\n"));
+		inode->i_op = &umsdos_dir_inode_operations;
+		iput (emd_dir);
 	}
 }
 
@@ -454,20 +230,20 @@
 /*
  * Add some info into an inode so it can find its owner quickly
  */
-void umsdos_set_dirinfo (	struct inode *inode,
-				struct inode *dir,
-				off_t f_pos)
-{
-	struct inode *emd_owner;
-
-	/* FIXME, I don't have a clue on this one - /mn/ Hmmm?  OK? */
-/*    Printk ((KERN_WARNING "umsdos_set_dirinfo: /mn/ FIXME: no clue. inode=%lu dir=%lu\n", inode->i_ino, dir->i_ino)); */
-	emd_owner = umsdos_emd_dir_lookup (dir, 1);
-	Printk (("umsdos_set_dirinfo: emd_owner is %lu for dir %lu\n", emd_owner->i_ino, dir->i_ino));
+void umsdos_set_dirinfo (struct inode *inode, struct inode *dir, off_t f_pos)
+{
+	struct inode *emd_owner = umsdos_emd_dir_lookup (dir, 1);
+
+	if (!emd_owner)
+		goto out;
+	Printk (("umsdos_set_dirinfo: emd_owner is %lu for dir %lu\n", 
+		emd_owner->i_ino, dir->i_ino));
 	inode->u.umsdos_i.i_dir_owner = dir->i_ino;
 	inode->u.umsdos_i.i_emd_owner = emd_owner->i_ino;
-	/* iput (emd_owner); / * FIXME? */
 	inode->u.umsdos_i.pos = f_pos;
+	iput (emd_owner);
+out:
+	return;
 }
 
 
@@ -477,150 +253,143 @@
  */
 int umsdos_isinit (struct inode *inode)
 {
-#if	1
 	return inode->u.umsdos_i.i_emd_owner != 0;
-#elif 0
-	return inode->i_atime != 0;
-#else
-	return atomic_read (&inode->i_count) > 1;
-#endif
 }
 
 
 /*
  * Connect the proper tables in the inode and add some info.
  * i_counts is not changed.
+ *
+ * This function is called very early to setup the inode, somewhat
+ * too early (called by UMSDOS_read_inode). At this point, we can't
+ * do too much, such as lookup up EMD files and so on. This causes
+ * confusion in the kernel. This is why some initialisation
+ * will be done when dir != NULL only.
+ * 
+ * UMSDOS do run piggy back on top of msdos fs. It looks like something
+ * is missing in the VFS to accommodate stacked fs. Still unclear what
+ * (quite honestly).
+ * 
+ * Well, maybe one! A new entry "may_unmount" which would allow
+ * the stacked fs to allocate some inode permanently and release
+ * them at the end. Doing that now introduce a problem. unmount
+ * always fail because some inodes are in use.
+ */
+/* #Specification: inode / umsdos info
+ * The first time an inode is seen (inode->i_count == 1),
+ * the inode number of the EMD file which controls this inode
+ * is tagged to this inode. It allows operations such as
+ * notify_change to be handled.
  */
- 
-void umsdos_patch_inode (	struct inode *inode,
-				struct inode *dir,	/* May be NULL */
-				off_t f_pos)
+void umsdos_patch_inode (struct inode *inode, struct inode *dir, off_t f_pos)
 {
-	/*
-	 * This function is called very early to setup the inode, somewhat
-	 * too early (called by UMSDOS_read_inode). At this point, we can't
-	 * do too much, such as lookup up EMD files and so on. This causes
-	 * confusion in the kernel. This is why some initialisation
-	 * will be done when dir != NULL only.
-	 * 
-	 * UMSDOS do run piggy back on top of msdos fs. It looks like something
-	 * is missing in the VFS to accommodate stacked fs. Still unclear what
-	 * (quite honestly).
-	 * 
-	 * Well, maybe one! A new entry "may_unmount" which would allow
-	 * the stacked fs to allocate some inode permanently and release
-	 * them at the end. Doing that now introduce a problem. unmount
-	 * always fail because some inodes are in use.
-	 */
+	Printk ((KERN_DEBUG "Entering umsdos_patch_inode for inode=%lu\n",
+		inode->i_ino));
 
-	Printk ((KERN_DEBUG "Entering umsdos_patch_inode for inode=%lu\n", inode->i_ino));
+	if (umsdos_isinit (inode))
+		goto already_init;
 
-	if (!umsdos_isinit (inode)) {
-		inode->u.umsdos_i.i_emd_dir = 0;
-		if (S_ISREG (inode->i_mode)) {
-			if (MSDOS_SB (inode->i_sb)->cvf_format) {
-				if (MSDOS_SB (inode->i_sb)->cvf_format->flags & CVF_USE_READPAGE) {
-					Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: setting i_op = umsdos_file_inode_operations_readpage\n"));
-					inode->i_op = &umsdos_file_inode_operations_readpage;
-				} else {
-					Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: setting i_op = umsdos_file_inode_operations_no_bmap\n"));
-					inode->i_op = &umsdos_file_inode_operations_no_bmap;
-				}
+	inode->u.umsdos_i.i_emd_dir = 0;
+	if (S_ISREG (inode->i_mode)) {
+		if (MSDOS_SB (inode->i_sb)->cvf_format) {
+			if (MSDOS_SB (inode->i_sb)->cvf_format->flags & CVF_USE_READPAGE) {
+Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: setting i_op = umsdos_file_inode_operations_readpage\n"));
+				inode->i_op = &umsdos_file_inode_operations_readpage;
 			} else {
-				if (inode->i_op->bmap != NULL) {
-					Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: setting i_op = umsdos_file_inode_operations\n"));
-					inode->i_op = &umsdos_file_inode_operations;
-				} else {
-					Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: setting i_op = umsdos_file_inode_operations_no_bmap\n"));
-					inode->i_op = &umsdos_file_inode_operations_no_bmap;
-				}
+Printk ((KERN_DEBUG "umsdos_patch_inode: umsdos_file_inode_ops_no_bmap\n"));
+				inode->i_op = &umsdos_file_inode_operations_no_bmap;
 			}
-		} else if (S_ISDIR (inode->i_mode)) {
-			if (dir != NULL) {
-				umsdos_setup_dir_inode (inode);
+		} else {
+			if (inode->i_op->bmap != NULL) {
+Printk ((KERN_DEBUG "umsdos_patch_inode: umsdos_file_inode_ops\n"));
+				inode->i_op = &umsdos_file_inode_operations;
+			} else {
+Printk ((KERN_DEBUG "umsdos_patch_inode: umsdos_file_inode_ops_no_bmap\n"));
+				inode->i_op = &umsdos_file_inode_operations_no_bmap;
 			}
-		} else if (S_ISLNK (inode->i_mode)) {
-			Printk ((KERN_DEBUG "umsdos_patch_inode /mn/:  setting i_op = umsdos_symlink_inode_operations\n"));
-			inode->i_op = &umsdos_symlink_inode_operations;
-		} else if (S_ISCHR (inode->i_mode)) {
-			Printk ((KERN_DEBUG "umsdos_patch_inode /mn/:  setting i_op = chrdev_inode_operations\n"));
-			inode->i_op = &chrdev_inode_operations;
-		} else if (S_ISBLK (inode->i_mode)) {
-			Printk ((KERN_DEBUG "umsdos_patch_inode /mn/:  setting i_op = blkdev_inode_operations\n"));
-			inode->i_op = &blkdev_inode_operations;
-		} else if (S_ISFIFO (inode->i_mode)) {
-			Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: uhm, init_fifo\n"));
-			init_fifo (inode);
 		}
+	} else if (S_ISDIR (inode->i_mode)) {
 		if (dir != NULL) {
-			/* #Specification: inode / umsdos info
-			 * The first time an inode is seen (inode->i_count == 1),
-			 * the inode number of the EMD file which control this inode
-			 * is tagged to this inode. It allows operation such
-			 * as notify_change to be handled.
-			 */
-			/*
-			 * This is done last because it also control the
-			 * status of umsdos_isinit()
-			 */
-			Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: here we go: calling umsdos_set_dirinfo (%p,%p,%lu)\n", inode, dir, f_pos));
-			umsdos_set_dirinfo (inode, dir, f_pos);
+			umsdos_setup_dir_inode (inode);
 		}
-	} else if (dir != NULL) {
+	} else if (S_ISLNK (inode->i_mode)) {
+		Printk ((KERN_DEBUG 
+			"umsdos_patch_inode: umsdos_symlink_inode_ops\n"));
+		inode->i_op = &umsdos_symlink_inode_operations;
+	} else if (S_ISCHR (inode->i_mode)) {
+		Printk ((KERN_DEBUG "umsdos_patch_inode: chrdev_inode_ops\n"));
+		inode->i_op = &chrdev_inode_operations;
+	} else if (S_ISBLK (inode->i_mode)) {
+		Printk ((KERN_DEBUG "umsdos_patch_inode: blkdev_inode_ops\n"));
+		inode->i_op = &blkdev_inode_operations;
+	} else if (S_ISFIFO (inode->i_mode)) {
+		Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: uhm, init_fifo\n"));
+		init_fifo (inode);
+	}
+	if (dir != NULL) {
+		/*
+		 * This is done last because it also control the
+		 * status of umsdos_isinit()
+		 */
+		Printk ((KERN_DEBUG 
+			"umsdos_patch_inode: call x_set_dirinfo(%p,%p,%lu)\n",
+			 inode, dir, f_pos));
+		umsdos_set_dirinfo (inode, dir, f_pos);
+	}
+	return;
+
+already_init:
+	if (dir != NULL) {
 		/*
 		 * Test to see if the info is maintained.
 		 * This should be removed when the file system will be proven.
 		 */
-		/* FIXME, again, not a clue */
-		struct inode *emd_owner;
-
-		Printk ((KERN_WARNING "umsdos_patch_inode: /mn/ Warning: untested emd_owner thingy...\n"));
-		emd_owner = umsdos_emd_dir_lookup (dir, 1);
-		/* iput (emd_owner); / * FIXME? */
+		struct inode *emd_owner = umsdos_emd_dir_lookup (dir, 1);
+		if (!emd_owner)
+			goto out;
 		if (emd_owner->i_ino != inode->u.umsdos_i.i_emd_owner) {
-			printk ("UMSDOS: *** EMD_OWNER ??? *** ino = %ld %ld <> %ld "
-				,inode->i_ino, emd_owner->i_ino, inode->u.umsdos_i.i_emd_owner);
+printk ("UMSDOS: *** EMD_OWNER ??? *** ino = %ld %ld <> %ld ",
+inode->i_ino, emd_owner->i_ino, inode->u.umsdos_i.i_emd_owner);
 		}
+		iput (emd_owner);
+	out:
+		return;
 	}
 }
 
-
 /*
- * Get the inode of the directory which owns this inode.
- * Return 0 if OK, -EIO if error.
+ * Patch the inode in a dentry.
  */
-int umsdos_get_dirowner (	struct inode *inode,
-				struct inode **result)	/* Hold NULL if any error */
-{				
-	/* else, the inode of the directory */
-	int ret = -EIO;
-	unsigned long ino = inode->u.umsdos_i.i_dir_owner;
-
-	*result = NULL;
-	if (ino == 0) {
-		printk ("UMSDOS: umsdos_get_dirowner ino == 0\n");
-	} else {
-		struct inode *dir = *result = iget (inode->i_sb, ino);
-
-		if (dir != NULL) {
-			umsdos_patch_inode (dir, NULL, 0);
-			/* iput (dir);	/ * FIXME: /mn/ added this. Is it OK? */
-			ret = 0;
-		}
-	}
-	return ret;
+void umsdos_patch_dentry_inode(struct dentry *dentry, off_t f_pos)
+{
+	umsdos_patch_inode(dentry->d_inode, dentry->d_parent->d_inode, f_pos);
 }
 
 
-
 /*
  * Load an inode from disk.
  */
+/* #Specification: Inode / post initialisation
+ * To completely initialise an inode, we need access to the owner
+ * directory, so we can locate more info in the EMD file. This is
+ * not available the first time the inode is access, we use
+ * a value in the inode to tell if it has been finally initialised.
+ * 
+ * At first, we have tried testing i_count but it was causing
+ * problem. It is possible that two or more process use the
+ * newly accessed inode. While the first one block during
+ * the initialisation (probably while reading the EMD file), the
+ * others believe all is well because i_count > 1. They go banana
+ * with a broken inode. See umsdos_lookup_patch and umsdos_patch_inode.
+ */
 void UMSDOS_read_inode (struct inode *inode)
 {
-	PRINTK ((KERN_DEBUG "UMSDOS_read_inode %p ino = %lu ", inode, inode->i_ino));
+	PRINTK ((KERN_DEBUG "UMSDOS_read_inode %p ino = %lu ",
+		inode, inode->i_ino));
 	msdos_read_inode (inode);
-	PRINTK (("ino after msdos_read_inode= %lu i_count=%d\n", inode->i_ino, inode->i_count));
+	PRINTK (("ino after msdos_read_inode= %lu i_count=%d\n",
+		inode->i_ino, inode->i_count));
 	if (S_ISDIR (inode->i_mode)
 	    && (inode->u.umsdos_i.u.dir_info.creating != 0
 		|| inode->u.umsdos_i.u.dir_info.looking != 0
@@ -630,116 +399,92 @@
 			 ,inode->u.umsdos_i.u.dir_info.looking
 			 ,inode->u.umsdos_i.u.dir_info.p));
 	}
-	/* #Specification: Inode / post initialisation
-	 * To completely initialise an inode, we need access to the owner
-	 * directory, so we can locate more info in the EMD file. This is
-	 * not available the first time the inode is access, we use
-	 * a value in the inode to tell if it has been finally initialised.
-	 * 
-	 * At first, we have tried testing i_count but it was causing
-	 * problem. It is possible that two or more process use the
-	 * newly accessed inode. While the first one block during
-	 * the initialisation (probably while reading the EMD file), the
-	 * others believe all is well because i_count > 1. They go banana
-	 * with a broken inode. See umsdos_lookup_patch and umsdos_patch_inode.
-	 */
+
+	/* N.B. Defer this until we have a dentry ... */
 	umsdos_patch_inode (inode, NULL, 0);
 }
 
 
-int internal_notify_change (struct inode *inode, struct iattr *attr)
+/* #Specification: notify_change / i_nlink > 0
+ * notify change is only done for inode with nlink > 0. An inode
+ * with nlink == 0 is no longer associated with any entry in
+ * the EMD file, so there is nothing to update.
+ */
+static int internal_notify_change (struct inode *inode, struct iattr *attr)
 {
-	int ret = 0;
-	struct inode *root;
+	unsigned long i_emd_owner = inode->u.umsdos_i.i_emd_owner;
+	int ret;
 
 	Printk ((KERN_DEBUG "UMSDOS_notify_change: entering\n"));
 
 	if ((ret = inode_change_ok (inode, attr)) != 0)
-		return ret;
+		goto out;
 
-	if (inode->i_nlink > 0) {
-		/* #Specification: notify_change / i_nlink > 0
-		 * notify change is only done for inode with nlink > 0. An inode
-		 * with nlink == 0 is no longer associated with any entry in
-		 * the EMD file, so there is nothing to update.
-		 */
-		unsigned long i_emd_owner = inode->u.umsdos_i.i_emd_owner;
+	if (inode->i_nlink == 0)
+		goto out_nolink;
 
-		root = iget (inode->i_sb, UMSDOS_ROOT_INO);
-		if (inode == root) {
-			/* #Specification: root inode / attributes
-			 * I don't know yet how this should work. Normally
-			 * the attributes (permissions bits, owner, times) of
-			 * a directory are stored in the EMD file of its parent.
-			 * 
-			 * One thing we could do is store the attributes of the root
-			 * inode in its own EMD file. A simple entry named "." could
-			 * be used for this special case. It would be read once
-			 * when the file system is mounted and update in
-			 * UMSDOS_notify_change() (right here).
-			 * 
-			 * I am not sure of the behavior of the root inode for
-			 * a real Unix file system. For now, this is a nop.
-			 */
-		} else if (i_emd_owner != 0xffffffff && i_emd_owner != 0) {
-			/* This inode is not a EMD file nor an inode used internally
-			 * by MSDOS, so we can update its status.
-			 * See emd.c
-			 */
-			struct inode *emd_owner;
+	if (inode->i_ino == UMSDOS_ROOT_INO)
+		goto out_nolink;
 
-			emd_owner = iget (inode->i_sb, i_emd_owner);
-			Printk (("notify change %p ", inode));
-			if (emd_owner == NULL) {
-				printk ("UMSDOS: emd_owner = NULL ???");
-				ret = -EPERM;
-			} else {
-				struct file filp;
-				struct umsdos_dirent entry;
-				struct dentry *emd_dentry;
-
-				emd_dentry = geti_dentry (emd_owner); /* FIXME? */
-				fill_new_filp (&filp, emd_dentry);
-
-				filp.f_pos = inode->u.umsdos_i.pos;
-				filp.f_reada = 0;
-				Printk (("pos = %Lu ", filp.f_pos));
-				/* Read only the start of the entry since we don't touch */
-				/* the name */
-				ret = umsdos_emd_dir_read (&filp, (char *) &entry, UMSDOS_REC_SIZE);
-				if (ret == 0) {
-					if (attr->ia_valid & ATTR_UID)
-						entry.uid = attr->ia_uid;
-					if (attr->ia_valid & ATTR_GID)
-						entry.gid = attr->ia_gid;
-					if (attr->ia_valid & ATTR_MODE)
-						entry.mode = attr->ia_mode;
-					if (attr->ia_valid & ATTR_ATIME)
-						entry.atime = attr->ia_atime;
-					if (attr->ia_valid & ATTR_MTIME)
-						entry.mtime = attr->ia_mtime;
-					if (attr->ia_valid & ATTR_CTIME)
-						entry.ctime = attr->ia_ctime;
-
-					entry.nlink = inode->i_nlink;
-					filp.f_pos = inode->u.umsdos_i.pos;
-					ret = umsdos_emd_dir_write (&filp, (char *) &entry, UMSDOS_REC_SIZE);
-
-					Printk (("notify pos %lu ret %d nlink %d ", inode->u.umsdos_i.pos, ret, entry.nlink));
-					/* #Specification: notify_change / msdos fs
-					 * notify_change operation are done only on the
-					 * EMD file. The msdos fs is not even called.
-					 */
-				}
-				/* iput (emd_owner);	/ * FIXME? /mn/ */
-			}
-			Printk (("\n"));
+	if (i_emd_owner != 0xffffffff && i_emd_owner != 0) {
+		/* This inode is not a EMD file nor an inode used internally
+		 * by MSDOS, so we can update its status.
+		 * See emd.c
+		 */
+		struct inode *emd_owner;
+		struct file filp;
+		struct umsdos_dirent entry;
+		struct dentry *emd_dentry;
+
+		Printk (("notify change %p ", inode));
+		ret = -EPERM;
+		emd_owner = iget (inode->i_sb, i_emd_owner);
+		if (!emd_owner) {
+			printk ("UMSDOS: emd_owner = NULL ???");
+			goto out_nolink;
+		}
+		emd_dentry = geti_dentry (emd_owner); /* FIXME? */
+		fill_new_filp (&filp, emd_dentry);
+
+		filp.f_pos = inode->u.umsdos_i.pos;
+		filp.f_reada = 0;
+		Printk (("pos = %Lu ", filp.f_pos));
+		/* Read only the start of the entry since we don't touch */
+		/* the name */
+		ret = umsdos_emd_dir_read (&filp, (char *) &entry, 
+						UMSDOS_REC_SIZE);
+		if (!ret) {
+			if (attr->ia_valid & ATTR_UID)
+				entry.uid = attr->ia_uid;
+			if (attr->ia_valid & ATTR_GID)
+				entry.gid = attr->ia_gid;
+			if (attr->ia_valid & ATTR_MODE)
+				entry.mode = attr->ia_mode;
+			if (attr->ia_valid & ATTR_ATIME)
+				entry.atime = attr->ia_atime;
+			if (attr->ia_valid & ATTR_MTIME)
+				entry.mtime = attr->ia_mtime;
+			if (attr->ia_valid & ATTR_CTIME)
+				entry.ctime = attr->ia_ctime;
+
+			entry.nlink = inode->i_nlink;
+			filp.f_pos = inode->u.umsdos_i.pos;
+			ret = umsdos_emd_dir_write (&filp, (char *) &entry,
+							 UMSDOS_REC_SIZE);
+
+			Printk (("notify pos %lu ret %d nlink %d ",
+				inode->u.umsdos_i.pos, ret, entry.nlink));
+			/* #Specification: notify_change / msdos fs
+			 * notify_change operation are done only on the
+			 * EMD file. The msdos fs is not even called.
+			 */
 		}
-		/* iput (root);	/ * FIXME - /mn/ This is should be OK. */
+		iput(emd_owner);
 	}
+out_nolink:
 	if (ret == 0)
 		inode_setattr (inode, attr);
-
+out:
 	return ret;
 }
 
@@ -756,7 +501,8 @@
 {
 	struct iattr newattrs;
 
-	PRINTK (("UMSDOS_write_inode emd %d (FIXME: missing notify_change)\n", inode->u.umsdos_i.i_emd_owner));
+	PRINTK (("UMSDOS_write_inode emd %d (FIXME: missing notify_change)\n",
+		inode->u.umsdos_i.i_emd_owner));
 	fat_write_inode (inode);
 	newattrs.ia_mtime = inode->i_mtime;
 	newattrs.ia_atime = inode->i_atime;
@@ -767,26 +513,12 @@
 	 * to update the EMD entry associated with this inode.
 	 * But it has the side effect to re"dirt" the inode.
 	 */
-
 /*      
  * internal_notify_change (inode, &newattrs);
  * inode->i_state &= ~I_DIRTY; / * FIXME: this doesn't work.  We need to remove ourselves from list on dirty inodes. /mn/ */
 }
 
 
-
-
-
-/* #Specification: function name / convention
- * A simple convention for function names has been used in
- * the UMSDOS filesystem. First, all functions use the prefix
- * umsdos_ to avoid name clashes with other parts of the kernel.
- * 
- * Standard VFS entry points use the prefix UMSDOS (upper case)
- * so it's easier to tell them apart.
- * N.B. (FIXME) PTW, the order and contents of this struct changed.
- */
-
 static struct super_operations umsdos_sops =
 {
 	UMSDOS_read_inode,	/* read_inode */
@@ -803,169 +535,127 @@
 /*
  * Read the super block of an Extended MS-DOS FS.
  */
-struct super_block *UMSDOS_read_super (	      struct super_block *sb,
-					      void *data,
-					      int silent)
-{
-	/* #Specification: mount / options
-	 * Umsdos run on top of msdos. Currently, it supports no
-	 * mount option, but happily pass all option received to
-	 * the msdos driver. I am not sure if all msdos mount option
-	 * make sense with Umsdos. Here are at least those who
-	 * are useful.
-	 * uid=
-	 * gid=
-	 * 
-	 * These options affect the operation of umsdos in directories
-	 * which do not have an EMD file. They behave like normal
-	 * msdos directory, with all limitation of msdos.
-	 */
+struct super_block *UMSDOS_read_super (struct super_block *sb, void *data,
+				      int silent)
+{
 	struct super_block *res;
 	struct inode *pseudo = NULL;
 
-	Printk ((KERN_DEBUG "UMSDOS /mn/: starting UMSDOS_read_super\n"));
 	MOD_INC_USE_COUNT;
-	Printk ((KERN_DEBUG "UMSDOS /mn/: sb = %p\n", sb));
-
 	MSDOS_SB(sb)->options.isvfat = 0;
+	/*
+	 * Call msdos-fs to mount the disk.
+	 * Note: this returns res == sb or NULL
+	 */
 	res = msdos_read_super (sb, data, silent);
-	sb->s_op = &umsdos_sops;
-	Printk ((KERN_DEBUG "UMSDOS /mn/: res = %p\n", res));
-	printk (KERN_INFO "UMSDOS dentry-WIP-Beta 0.82-7 (compatibility level %d.%d, fast msdos)\n", UMSDOS_VERSION, UMSDOS_RELEASE);
+	if (!res)
+		goto out_fail;
 
-	if (res == NULL) {
-		sb->s_dev = 0;
-		MOD_DEC_USE_COUNT;
-		Printk ((KERN_DEBUG "UMSDOS: msdos_read_super failed ! mount aborted.\n"));
-		return NULL;
-	}
-	
-	MSDOS_SB (res)->options.dotsOK = 0;	/* disable hidden==dotfile */
-#if 1
-	res->s_root->d_op = NULL;	/* FIXME:?? clear d_op on root so it will not be inherited */
-#endif	
-	
-	Printk ((KERN_DEBUG "umsdos /mn/: here goes the iget ROOT_INO\n"));
+	printk (KERN_INFO "UMSDOS dentry-WIP-Beta 0.82-7 "
+		"(compatibility level %d.%d, fast msdos)\n", 
+		UMSDOS_VERSION, UMSDOS_RELEASE);
 
-/*	pseudo = iget (res, UMSDOS_ROOT_INO);	// we probably could do it as below (and remove iput() below), but we want use_count to go up. Do we ? :) */
-	pseudo = res->s_root->d_inode;	/* msdos_read_super already did iget() it */
-	
-	Printk ((KERN_DEBUG "umsdos_read_super pseudo=%p\n", pseudo));
+	sb->s_op = &umsdos_sops;
+	MSDOS_SB(sb)->options.dotsOK = 0;	/* disable hidden==dotfile */
+
+	/* FIXME:?? clear d_op on root so it will not be inherited */
+	sb->s_root->d_op = NULL;
 
-	umsdos_setup_dir_inode (pseudo);
-	Printk ((KERN_DEBUG "umsdos_setup_dir_inode passed. pseudo i_count=%d\n", pseudo->i_count));
+	pseudo = sb->s_root->d_inode;
+	umsdos_setup_dir(sb->s_root);
 
-	/* if (s == super_blocks){ FIXME, super_blocks no longer exported */
+#if 0
 	if (pseudo) {
-#if 0	/* FIXME URGENT: disable pseudo root-for the moment of testing. re-enable this before release ! */
-		/* #Specification: pseudo root / mount
-		 * When a umsdos fs is mounted, a special handling is done
-		 * if it is the root partition. We check for the presence
-		 * of the file /linux/etc/init or /linux/etc/rc or
-		 * /linux/sbin/init. If one is there, we do a chroot("/linux").
-		 * 
-		 * We check both because (see init/main.c) the kernel
-		 * try to exec init at different place and if it fails
-		 * it tries /bin/sh /etc/rc. To be consistent with
-		 * init/main.c, many more test would have to be done
-		 * to locate init. Any complain ?
-		 * 
-		 * The chroot is done manually in init/main.c but the
-		 * info (the inode) is located at mount time and store
-		 * in a global variable (pseudo_root) which is used at
-		 * different place in the umsdos driver. There is no
-		 * need to store this variable elsewhere because it
-		 * will always be one, not one per mount.
-		 * 
-		 * This feature allows the installation
-		 * of a linux system within a DOS system in a subdirectory.
-		 * 
-		 * A user may install its linux stuff in c:\linux
-		 * avoiding any clash with existing DOS file and subdirectory.
-		 * When linux boots, it hides this fact, showing a normal
-		 * root directory with /etc /bin /tmp ...
-		 * 
-		 * The word "linux" is hardcoded in /usr/include/linux/umsdos_fs.h
-		 * in the macro UMSDOS_PSDROOT_NAME.
-		 */
-		struct dentry *root, *etc, *etc_rc, *sbin, *init = NULL;
+		pseudo_root_stuff();
+	}
+#endif
+
+	/* if d_count is not 1, mount will fail with -EBUSY! */
+	if (sb->s_root->d_count > 1) {
+		shrink_dcache_sb(sb);
+	}
+	return sb;
+
+out_fail:
+	printk(KERN_INFO "UMSDOS: msdos_read_super failed, mount aborted.\n");
+	sb->s_dev = 0;
+	MOD_DEC_USE_COUNT;
+	return NULL;
+}
+
+/*
+ * FIXME URGENT:
+ * disable pseudo root-for the moment of testing. 
+ * re-enable this before release !
+ */
+#if 0
+void pseudo_root_stuff(void)
+{
+	struct dentry *root, *etc, *etc_rc, *sbin, *init = NULL;
 
-		root = creat_dentry (UMSDOS_PSDROOT_NAME, strlen (UMSDOS_PSDROOT_NAME), NULL, res->s_root);
-		sbin = creat_dentry ("sbin", 4, NULL, NULL); /* FIXME: should last NULL be root or res->s_root ?  Not NULL in any case.. */
+	root = creat_dentry (UMSDOS_PSDROOT_NAME, 
+				strlen (UMSDOS_PSDROOT_NAME),
+			 	NULL, res->s_root);
+	sbin = creat_dentry ("sbin", 4, NULL, root);
 
-		Printk ((KERN_DEBUG "Mounting root\n"));
-		if (umsdos_real_lookup (pseudo, root) == 0
-		    && (root->d_inode != NULL)
-		    && S_ISDIR (root->d_inode->i_mode)) {
+	Printk ((KERN_DEBUG "Mounting root\n"));
+	if (umsdos_real_lookup (pseudo, root) == 0
+	    && (root->d_inode != NULL)
+	    && S_ISDIR (root->d_inode->i_mode)) {
 
-			int pseudo_ok = 0;
+		int pseudo_ok = 0;
 
-			Printk ((KERN_DEBUG "/%s is there\n", UMSDOS_PSDROOT_NAME));
-			etc = creat_dentry ("etc", 3, NULL, root);
+Printk ((KERN_DEBUG "/%s is there\n", UMSDOS_PSDROOT_NAME));
+		etc = creat_dentry ("etc", 3, NULL, root);
 
 
-			if (umsdos_real_lookup (pseudo, etc) == 0
-			    && S_ISDIR (etc->d_inode->i_mode)) {
+		if (umsdos_real_lookup (pseudo, etc) == 0
+		    && S_ISDIR (etc->d_inode->i_mode)) {
 
-				Printk ((KERN_DEBUG "/%s/etc is there\n", UMSDOS_PSDROOT_NAME));
+Printk ((KERN_DEBUG "/%s/etc is there\n", UMSDOS_PSDROOT_NAME));
 
-				init = creat_dentry ("init", 4, NULL, etc);
-				etc_rc = creat_dentry ("rc", 2, NULL, etc);
+			init = creat_dentry ("init", 4, NULL, etc);
+			etc_rc = creat_dentry ("rc", 2, NULL, etc);
 
-				if ((umsdos_real_lookup (pseudo, init) == 0
-				     && S_ISREG (init->d_inode->i_mode))
-				    || (umsdos_real_lookup (pseudo, etc_rc) == 0
-				 && S_ISREG (etc_rc->d_inode->i_mode))) {
-					pseudo_ok = 1;
-				}
-				/* iput (pseudo); iput (pseudo);	/ * because msdos_real_lookup does inc_count (pseudo) */
+			if ((umsdos_real_lookup (pseudo, init) == 0
+			     && S_ISREG (init->d_inode->i_mode))
+			    || (umsdos_real_lookup (pseudo, etc_rc) == 0
+			 && S_ISREG (etc_rc->d_inode->i_mode))) {
+				pseudo_ok = 1;
+			}
 
 				/* FIXME !!!!!! */
-				/* iput(init); */
-				/* iput(rc); */
-			}
-			if (!pseudo_ok
-			/* && umsdos_real_lookup (pseudo, "sbin", 4, sbin)==0 */
-			    && umsdos_real_lookup (pseudo, sbin) == 0
-			    && S_ISDIR (sbin->d_inode->i_mode)) {
-
-				Printk ((KERN_DEBUG "/%s/sbin is there\n", UMSDOS_PSDROOT_NAME));
-				if (umsdos_real_lookup (pseudo, init) == 0
-				    && S_ISREG (init->d_inode->i_mode)) {
-					pseudo_ok = 1;
-				}
-				/*iput (pseudo);*/
-				/* FIXME !!! 
-				 * iput (init); */
-			}
-			if (pseudo_ok) {
-				umsdos_setup_dir_inode (pseudo);
-				Printk ((KERN_INFO "Activating pseudo root /%s\n", UMSDOS_PSDROOT_NAME));
-				pseudo_root = pseudo;
-				inc_count (pseudo);
-				pseudo = NULL;
+			/* iput(init); */
+			/* iput(rc); */
+		}
+		if (!pseudo_ok
+		/* && umsdos_real_lookup (pseudo, "sbin", 4, sbin)==0 */
+		    && umsdos_real_lookup (pseudo, sbin) == 0
+		    && S_ISDIR (sbin->d_inode->i_mode)) {
+
+Printk ((KERN_DEBUG "/%s/sbin is there\n", UMSDOS_PSDROOT_NAME));
+			if (umsdos_real_lookup (pseudo, init) == 0
+			    && S_ISREG (init->d_inode->i_mode)) {
+				pseudo_ok = 1;
 			}
-			/* FIXME 
-			 * 
-			 * iput (sbin);
-			 * iput (etc);
-			 */
+			/* FIXME !!! 
+			 * iput (init); */
 		}
-#endif	
-		/*iput (pseudo); // iget was removed... so this no longer needed ? */
-	}
-#if 1
-	#warning UMSDOS: using ugly mount kludge only if necessary (DEBUG)
-	if (res->s_root->d_count != 1) {	/* if it is not 1, mount will fail with -EBUSY! */
-		printk (KERN_ERR "UMSDOS: mount kludge activated: root d_count was %d !\n", res->s_root->d_count);
-		res->s_root->d_count = 1;
+		if (pseudo_ok) {
+			umsdos_setup_dir_inode (pseudo);
+Printk ((KERN_INFO "Activating pseudo root /%s\n", UMSDOS_PSDROOT_NAME));
+			pseudo_root = pseudo;
+			inc_count (pseudo);
+			pseudo = NULL;
+		}
+		/* FIXME 
+		 * 
+		 * iput (sbin);
+		 * iput (etc);
+		 */
 	}
-#endif	
-	check_dentry_path (res->s_root, "ROOT dentry check");
-	Printk ((KERN_DEBUG "umsdos_read_super /mn/: (pseudo=%lu, i_count=%d) returning %p\n", pseudo->i_ino, pseudo->i_count, res));
-	return res;
 }
-
+#endif	
 
 
 static struct file_system_type umsdos_fs_type =
diff -u --recursive --new-file v2.1.120/linux/fs/umsdos/ioctl.c linux/fs/umsdos/ioctl.c
--- v2.1.120/linux/fs/umsdos/ioctl.c	Sat Sep  5 16:46:41 1998
+++ linux/fs/umsdos/ioctl.c	Wed Sep  9 09:01:20 1998
@@ -50,14 +50,33 @@
 /*
  * Perform special function on a directory
  */
-int UMSDOS_ioctl_dir (	     struct inode *dir,
-			     struct file *filp,
-			     unsigned int cmd,
-			     unsigned long data)
+/* #Specification: ioctl / prototypes
+ * The official prototype for the umsdos ioctl on directory
+ * is:
+ * 
+ * int ioctl (
+ * int fd,          // File handle of the directory
+ * int cmd, // command
+ * struct umsdos_ioctl *data)
+ * 
+ * The struct and the commands are defined in linux/umsdos_fs.h.
+ * 
+ * umsdos_progs/umsdosio.c provide an interface in C++ to all
+ * these ioctl. umsdos_progs/udosctl is a small utility showing
+ * all this.
+ * 
+ * These ioctl generally allow one to work on the EMD or the
+ * DOS directory independently. These are essential to implement
+ * the synchronise.
+ */
+int UMSDOS_ioctl_dir(struct inode *dir, struct file *filp, unsigned int cmd,
+			unsigned long data_ptr)
 {
-	int ret = -EPERM;
-	int err;
-	struct dentry *old_dent;
+	struct dentry *dentry = filp->f_dentry;
+	struct umsdos_ioctl *idata = (struct umsdos_ioctl *) data_ptr;
+	int ret;
+	struct file new_filp;
+	struct umsdos_ioctl data;
 
 	/* forward non-umsdos ioctls - this hopefully doesn't cause conflicts */
 	if (cmd != UMSDOS_GETVERSION
@@ -71,7 +90,7 @@
 	    && cmd != UMSDOS_RMDIR_DOS
 	    && cmd != UMSDOS_STAT_DOS
 	    && cmd != UMSDOS_DOS_SETUP)
-		return fat_dir_ioctl (dir, filp, cmd, data);
+		return fat_dir_ioctl (dir, filp, cmd, data_ptr);
 
 	/* #Specification: ioctl / acces
 	 * Only root (effective id) is allowed to do IOCTL on directory
@@ -82,278 +101,315 @@
 	 * the code, and let's face it, there is only one client (umssync)
 	 * for all this.
 	 */
-	if ((err = verify_area (VERIFY_WRITE, (void *) data, sizeof (struct umsdos_ioctl))) < 0) {
-		ret = err;
-	} else if (current->euid == 0
-		   || cmd == UMSDOS_GETVERSION) {
-		struct umsdos_ioctl *idata = (struct umsdos_ioctl *) data;
-
-		ret = -EINVAL;
-		/* #Specification: ioctl / prototypes
-		 * The official prototype for the umsdos ioctl on directory
-		 * is:
-		 * 
-		 * int ioctl (
-		 * int fd,          // File handle of the directory
-		 * int cmd, // command
-		 * struct umsdos_ioctl *data)
-		 * 
-		 * The struct and the commands are defined in linux/umsdos_fs.h.
-		 * 
-		 * umsdos_progs/umsdosio.c provide an interface in C++ to all
-		 * these ioctl. umsdos_progs/udosctl is a small utility showing
-		 * all this.
-		 * 
-		 * These ioctl generally allow one to work on the EMD or the
-		 * DOS directory independently. These are essential to implement
-		 * the synchronise.
-		 */
-		Printk (("ioctl %d ", cmd));
-		if (cmd == UMSDOS_GETVERSION) {
-			/* #Specification: ioctl / UMSDOS_GETVERSION
-			 * The field version and release of the structure
-			 * umsdos_ioctl are filled with the version and release
-			 * number of the fs code in the kernel. This will allow
-			 * some form of checking. Users won't be able to run
-			 * incompatible utility such as the synchroniser (umssync).
-			 * umsdos_progs/umsdosio.c enforce this checking.
-			 * 
-			 * Return always 0.
-			 */
-			put_user (UMSDOS_VERSION, &idata->version);
-			put_user (UMSDOS_RELEASE, &idata->release);
+	ret = verify_area (VERIFY_WRITE, (void *) data_ptr, 
+				sizeof (struct umsdos_ioctl));
+	if (ret < 0)
+		goto out;
+
+	ret = -EPERM;
+	if (current->euid != 0 && cmd != UMSDOS_GETVERSION)
+		goto out;
+
+	ret = -EINVAL;
+	if (cmd == UMSDOS_GETVERSION) {
+		/* #Specification: ioctl / UMSDOS_GETVERSION
+		 * The field version and release of the structure
+		 * umsdos_ioctl are filled with the version and release
+		 * number of the fs code in the kernel. This will allow
+		 * some form of checking. Users won't be able to run
+		 * incompatible utility such as the synchroniser (umssync).
+		 * umsdos_progs/umsdosio.c enforce this checking.
+		 * 
+		 * Return always 0.
+		 */
+		put_user (UMSDOS_VERSION, &idata->version);
+		put_user (UMSDOS_RELEASE, &idata->release);
+		ret = 0;
+		goto out;
+	}
+	if (cmd == UMSDOS_READDIR_DOS) {
+		/* #Specification: ioctl / UMSDOS_READDIR_DOS
+		 * One entry is read from the DOS directory at the current
+		 * file position. The entry is put as is in the dos_dirent
+		 * field of struct umsdos_ioctl.
+		 * 
+		 * Return > 0 if success.
+		 */
+		struct UMSDOS_DIR_ONCE bufk;
+
+		bufk.count = 0;
+		bufk.ent = &idata->dos_dirent;
+
+		fat_readdir (filp, &bufk, umsdos_ioctl_fill);
+
+		ret = bufk.count == 1 ? 1 : 0;
+		goto out;
+	}
+	if (cmd == UMSDOS_READDIR_EMD) {
+		/* #Specification: ioctl / UMSDOS_READDIR_EMD
+		 * One entry is read from the EMD at the current
+		 * file position. The entry is put as is in the umsdos_dirent
+		 * field of struct umsdos_ioctl. The corresponding mangled
+		 * DOS entry name is put in the dos_dirent field.
+		 * 
+		 * All entries are read including hidden links. Blank
+		 * entries are skipped.
+		 * 
+		 * Return > 0 if success.
+		 */
+		struct dentry *demd;
+
+		/* The absence of the EMD is simply seen as an EOF */
+		demd = umsdos_get_emd_dentry(dentry);
+		ret = PTR_ERR(demd);
+		if (IS_ERR(demd))
+			goto out;
+		fill_new_filp(&new_filp, demd);
+		new_filp.f_pos = filp->f_pos;
+
+		while (1) {
+			off_t f_pos = new_filp.f_pos;
+			struct umsdos_dirent entry;
+			struct umsdos_info info;
+
 			ret = 0;
-		} else if (cmd == UMSDOS_READDIR_DOS) {
-			/* #Specification: ioctl / UMSDOS_READDIR_DOS
-			 * One entry is read from the DOS directory at the current
-			 * file position. The entry is put as is in the dos_dirent
-			 * field of struct umsdos_ioctl.
-			 * 
-			 * Return > 0 if success.
-			 */
-			struct UMSDOS_DIR_ONCE bufk;
-
-			bufk.count = 0;
-			bufk.ent = &idata->dos_dirent;
-
-			fat_readdir (filp, &bufk, umsdos_ioctl_fill);
-
-			ret = bufk.count == 1 ? 1 : 0;
-		} else if (cmd == UMSDOS_READDIR_EMD) {
-			/* #Specification: ioctl / UMSDOS_READDIR_EMD
-			 * One entry is read from the EMD at the current
-			 * file position. The entry is put as is in the umsdos_dirent
-			 * field of struct umsdos_ioctl. The corresponding mangled
-			 * DOS entry name is put in the dos_dirent field.
-			 * 
-			 * All entries are read including hidden links. Blank
-			 * entries are skipped.
-			 * 
-			 * Return > 0 if success.
-			 */
-
-			old_dent = filp->f_dentry;
-			if (fix_emd_filp (filp) == 0) {
-				while (1) {
-					if (filp->f_pos >= filp->f_dentry->d_inode->i_size) {
-						ret = 0;
-						break;
-					} else {
-						struct umsdos_dirent entry;
-						off_t f_pos = filp->f_pos;
-
-						ret = umsdos_emd_dir_readentry (filp, &entry);
-						if (ret < 0) {
-							break;
-						} else if (entry.name_len > 0) {
-							struct umsdos_info info;
-
-							ret = entry.name_len;
-							umsdos_parse (entry.name, entry.name_len, &info);
-							info.f_pos = f_pos;
-							umsdos_manglename (&info);
-							copy_to_user (&idata->umsdos_dirent, &entry, sizeof (entry));
-							copy_to_user (&idata->dos_dirent.d_name, info.fake.fname, info.fake.len + 1);
-							break;
-						}
-					}
-				}
-				fin_dentry (filp->f_dentry);
-				filp->f_dentry = old_dent;
-				/* iput (filp->f_dentry->d_inode); / * FIXME? */
-			} else {
-				/* The absence of the EMD is simply seen as an EOF */
-				ret = 0;
-			}
-		} else if (cmd == UMSDOS_INIT_EMD) {
-			/* #Specification: ioctl / UMSDOS_INIT_EMD
-			 * The UMSDOS_INIT_EMD command make sure the EMD
-			 * exist for a directory. If it does not, it is
-			 * created. Also, it makes sure the directory functions
-			 * table (struct inode_operations) is set to the UMSDOS
-			 * semantic. This mean that umssync may be applied to
-			 * an "opened" msdos directory, and it will change behavior
-			 * on the fly.
-			 * 
-			 * Return 0 if success.
-			 */
-			extern struct inode_operations umsdos_rdir_inode_operations;
-			struct inode *emd_dir = umsdos_emd_dir_lookup (dir, 1);
-
-			ret = emd_dir != NULL;
-			/* iput (emd_dir); / * FIXME?? */
-
-			dir->i_op = ret
-			    ? &umsdos_dir_inode_operations
-			    : &umsdos_rdir_inode_operations;
-		} else {
-			struct umsdos_ioctl data;
-
-			copy_from_user (&data, idata, sizeof (data));
-			if (cmd == UMSDOS_CREAT_EMD) {
-				/* #Specification: ioctl / UMSDOS_CREAT_EMD
-				 * The umsdos_dirent field of the struct umsdos_ioctl is used
-				 * as is to create a new entry in the EMD of the directory.
-				 * The DOS directory is not modified.
-				 * No validation is done (yet).
-				 * 
-				 * Return 0 if success.
-				 */
-				struct umsdos_info info;
-
-				/* This makes sure info.entry and info in general is correctly */
-				/* initialised */
-				memcpy (&info.entry, &data.umsdos_dirent
-					,sizeof (data.umsdos_dirent));
-				umsdos_parse (data.umsdos_dirent.name
-				    ,data.umsdos_dirent.name_len, &info);
-				ret = umsdos_newentry (dir, &info);
-			} else if (cmd == UMSDOS_RENAME_DOS) {
-				struct dentry *old_dentry, *new_dentry;		/* FIXME */
-
-				/* #Specification: ioctl / UMSDOS_RENAME_DOS
-				 * A file or directory is rename in a DOS directory
-				 * (not moved across directory). The source name
-				 * is in the dos_dirent.name field and the destination
-				 * is in umsdos_dirent.name field.
-				 * 
-				 * This ioctl allows umssync to rename a mangle file
-				 * name before syncing it back in the EMD.
-				 */
-				inc_count (dir);
-				inc_count (dir);
-				/*
-				 * ret = msdos_rename (dir
-				 * ,data.dos_dirent.d_name,data.dos_dirent.d_reclen
-				 * ,dir
-				 * ,data.umsdos_dirent.name,data.umsdos_dirent.name_len);
-				 */
-				old_dentry = creat_dentry (data.dos_dirent.d_name, data.dos_dirent.d_reclen, NULL, geti_dentry (dir));	/* FIXME: probably should fill inode part */
-				new_dentry = creat_dentry (data.umsdos_dirent.name, data.umsdos_dirent.name_len, NULL, geti_dentry (dir));
-				ret = msdos_rename (dir, old_dentry, dir, new_dentry);
-			} else if (cmd == UMSDOS_UNLINK_EMD) {
-				/* #Specification: ioctl / UMSDOS_UNLINK_EMD
-				 * The umsdos_dirent field of the struct umsdos_ioctl is used
-				 * as is to remove an entry from the EMD of the directory.
-				 * No validation is done (yet). The mode field is used
-				 * to validate S_ISDIR or S_ISREG.
-				 * 
-				 * Return 0 if success.
-				 */
-				struct umsdos_info info;
-
-				/* This makes sure info.entry and info in general is correctly */
-				/* initialised */
-				memcpy (&info.entry, &data.umsdos_dirent
-					,sizeof (data.umsdos_dirent));
-				umsdos_parse (data.umsdos_dirent.name
-				    ,data.umsdos_dirent.name_len, &info);
-				ret = umsdos_delentry (dir, &info
-				     ,S_ISDIR (data.umsdos_dirent.mode));
-			} else if (cmd == UMSDOS_UNLINK_DOS) {
-				struct dentry *dentry, *dp;
-
-				/* #Specification: ioctl / UMSDOS_UNLINK_DOS
-				 * The dos_dirent field of the struct umsdos_ioctl is used to
-				 * execute a msdos_unlink operation. The d_name and d_reclen
-				 * fields are used.
-				 * 
-				 * Return 0 if success.
-				 */
-				dp = geti_dentry (dir);
-				dentry = compat_umsdos_real_lookup (dp, data.dos_dirent.d_name, data.dos_dirent.d_reclen);
-				ret = msdos_unlink (dir, dentry);
-				dput (dentry);	/* FIXME: is this OK now? */
-
-			} else if (cmd == UMSDOS_RMDIR_DOS) {
-				struct dentry *dentry, *dp;
-
-				/* #Specification: ioctl / UMSDOS_RMDIR_DOS
-				 * The dos_dirent field of the struct umsdos_ioctl is used to
-				 * execute a msdos_unlink operation. The d_name and d_reclen
-				 * fields are used.
-				 * 
-				 * Return 0 if success.
-				 */
-				dp = geti_dentry (dir);
-				dentry = compat_umsdos_real_lookup (dp, data.dos_dirent.d_name, data.dos_dirent.d_reclen);
-				ret = msdos_rmdir (dir, dentry);
-				dput (dentry);	/* FIXME: is this OK now? */
-
-			} else if (cmd == UMSDOS_STAT_DOS) {
-				/* #Specification: ioctl / UMSDOS_STAT_DOS
-				 * The dos_dirent field of the struct umsdos_ioctl is
-				 * used to execute a stat operation in the DOS directory.
-				 * The d_name and d_reclen fields are used.
-				 * 
-				 * The following field of umsdos_ioctl.stat are filled.
-				 * 
-				 * st_ino,st_mode,st_size,st_atime,st_mtime,st_ctime,
-				 * Return 0 if success.
-				 */
-				struct inode *inode;
-				struct dentry *d_dir, *dret;
-
-				d_dir = geti_dentry (dir);
-				dret = compat_umsdos_real_lookup (d_dir, data.dos_dirent.d_name, data.dos_dirent.d_reclen);
-				if (dret) {
-					inode = dret->d_inode;
-					data.stat.st_ino = inode->i_ino;
-					data.stat.st_mode = inode->i_mode;
-					data.stat.st_size = inode->i_size;
-					data.stat.st_atime = inode->i_atime;
-					data.stat.st_ctime = inode->i_ctime;
-					data.stat.st_mtime = inode->i_mtime;
-					copy_to_user (&idata->stat, &data.stat, sizeof (data.stat));
-					fin_dentry (dret);
-				}
-			} else if (cmd == UMSDOS_DOS_SETUP) {
-				/* #Specification: ioctl / UMSDOS_DOS_SETUP
-				 * The UMSDOS_DOS_SETUP ioctl allow changing the
-				 * default permission of the MS-DOS filesystem driver
-				 * on the fly.  The MS-DOS driver applies global permissions
-				 * to every file and directory. Normally these permissions
-				 * are controlled by a mount option. This is not
-				 * available for root partition, so a special utility
-				 * (umssetup) is provided to do this, normally in
-				 * /etc/rc.local.
-				 * 
-				 * Be aware that this applies ONLY to MS-DOS directories
-				 * (those without EMD --linux-.---). Umsdos directory
-				 * have independent (standard) permission for each
-				 * and every file.
-				 * 
-				 * The field umsdos_dirent provide the information needed.
-				 * umsdos_dirent.uid and gid sets the owner and group.
-				 * umsdos_dirent.mode set the permissions flags.
-				 */
-				dir->i_sb->u.msdos_sb.options.fs_uid = data.umsdos_dirent.uid;
-				dir->i_sb->u.msdos_sb.options.fs_gid = data.umsdos_dirent.gid;
-				dir->i_sb->u.msdos_sb.options.fs_umask = data.umsdos_dirent.mode;
+			if (new_filp.f_pos >= demd->d_inode->i_size)
+				break;
+
+			ret = umsdos_emd_dir_readentry (&new_filp, &entry);
+			if (ret < 0)
+				break;
+			if (entry.name_len <= 0)
+				continue;
+
+			umsdos_parse (entry.name, entry.name_len, &info);
+			info.f_pos = f_pos;
+			umsdos_manglename (&info);
+			ret = -EFAULT;
+			if (copy_to_user (&idata->umsdos_dirent, &entry,
+							sizeof (entry)))
+				break;
+			if (copy_to_user (&idata->dos_dirent.d_name,
+							info.fake.fname,
+				 			info.fake.len + 1))
+				break;
+			ret = entry.name_len;
+			break;
+		}
+		/* update the original f_pos */
+		filp->f_pos = new_filp.f_pos;
+		d_drop(demd);
+		dput(demd);
+		goto out;
+	}
+	if (cmd == UMSDOS_INIT_EMD) {
+		/* #Specification: ioctl / UMSDOS_INIT_EMD
+		 * The UMSDOS_INIT_EMD command makes sure the EMD
+		 * exists for a directory. If it does not, it is
+		 * created. Also, it makes sure the directory function
+		 * table (struct inode_operations) is set to the UMSDOS
+		 * semantic. This mean that umssync may be applied to
+		 * an "opened" msdos directory, and it will change behavior
+		 * on the fly.
+		 * 
+		 * Return 0 if success.
+		 */
+		extern struct inode_operations umsdos_rdir_inode_operations;
+
+		ret = umsdos_make_emd(dentry);
+		dir->i_op = (ret == 0)
+		    ? &umsdos_dir_inode_operations
+		    : &umsdos_rdir_inode_operations;
+		goto out;
+	}
+
+	ret = -EFAULT;
+	if (copy_from_user (&data, idata, sizeof (data)))
+		goto out;
+
+	if (cmd == UMSDOS_CREAT_EMD) {
+		/* #Specification: ioctl / UMSDOS_CREAT_EMD
+		 * The umsdos_dirent field of the struct umsdos_ioctl is used
+		 * as is to create a new entry in the EMD of the directory.
+		 * The DOS directory is not modified.
+		 * No validation is done (yet).
+		 * 
+		 * Return 0 if success.
+		 */
+		struct umsdos_info info;
+
+		/* This makes sure info.entry and info in general
+		 * is correctly initialised
+		 */
+		memcpy (&info.entry, &data.umsdos_dirent,
+			sizeof (data.umsdos_dirent));
+		umsdos_parse (data.umsdos_dirent.name
+		    ,data.umsdos_dirent.name_len, &info);
+		ret = umsdos_newentry (dentry, &info);
+		goto out;
+	}
+	else if (cmd == UMSDOS_RENAME_DOS) {
+		struct dentry *old_dentry, *new_dentry;		/* FIXME */
+
+		/* #Specification: ioctl / UMSDOS_RENAME_DOS
+		 * A file or directory is renamed in a DOS directory
+		 * (not moved across directory). The source name
+		 * is in the dos_dirent.name field and the destination
+		 * is in umsdos_dirent.name field.
+		 * 
+		 * This ioctl allows umssync to rename a mangle file
+		 * name before syncing it back in the EMD.
+		 */
+		old_dentry = umsdos_lookup_dentry (dentry, 
+						data.dos_dirent.d_name,
+						data.dos_dirent.d_reclen);
+		ret = PTR_ERR(old_dentry);
+		if (IS_ERR(old_dentry))
+			goto out;
+		new_dentry = umsdos_lookup_dentry (dentry,
+						data.umsdos_dirent.name,
+						data.umsdos_dirent.name_len);
+		ret = PTR_ERR(new_dentry);
+		if (!IS_ERR(new_dentry)) {
+printk("umsdos_ioctl: renaming %s/%s to %s/%s\n",
+old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
+new_dentry->d_parent->d_name.name, new_dentry->d_name.name);
+			ret = msdos_rename (dir, old_dentry, dir, new_dentry);
+			dput(new_dentry);
+		}
+		d_drop(old_dentry);
+		dput(old_dentry);
+		goto out;
+	}
+	else if (cmd == UMSDOS_UNLINK_EMD) {
+		/* #Specification: ioctl / UMSDOS_UNLINK_EMD
+		 * The umsdos_dirent field of the struct umsdos_ioctl is used
+		 * as is to remove an entry from the EMD of the directory.
+		 * No validation is done (yet). The mode field is used
+		 * to validate S_ISDIR or S_ISREG.
+		 * 
+		 * Return 0 if success.
+		 */
+		struct umsdos_info info;
+
+		/* This makes sure info.entry and info in general
+		 * is correctly initialised
+		 */
+		memcpy (&info.entry, &data.umsdos_dirent,
+			sizeof (data.umsdos_dirent));
+		umsdos_parse (data.umsdos_dirent.name,
+				data.umsdos_dirent.name_len, &info);
+		ret = umsdos_delentry (dentry, &info,
+				S_ISDIR (data.umsdos_dirent.mode));
+		goto out;
+	}
+	else if (cmd == UMSDOS_UNLINK_DOS) {
+		struct dentry *temp;
+
+		/* #Specification: ioctl / UMSDOS_UNLINK_DOS
+		 * The dos_dirent field of the struct umsdos_ioctl is used to
+		 * execute a msdos_unlink operation. The d_name and d_reclen
+		 * fields are used.
+		 * 
+		 * Return 0 if success.
+		 */
+		temp = umsdos_lookup_dentry(dentry, data.dos_dirent.d_name,
+						    data.dos_dirent.d_reclen);
+		ret = PTR_ERR(temp);
+		if (IS_ERR(temp))
+			goto out;
+		ret = -ENOENT;
+		if (temp->d_inode)
+			ret = msdos_unlink (dir, temp);
+		d_drop(temp);
+		dput (temp);
+		goto out;
+	}
+	else if (cmd == UMSDOS_RMDIR_DOS) {
+		struct dentry *temp;
+
+		/* #Specification: ioctl / UMSDOS_RMDIR_DOS
+		 * The dos_dirent field of the struct umsdos_ioctl is used to
+		 * execute a msdos_rmdir operation. The d_name and d_reclen
+		 * fields are used.
+		 * 
+		 * Return 0 if success.
+		 */
+		temp = umsdos_lookup_dentry(dentry, data.dos_dirent.d_name,
+						    data.dos_dirent.d_reclen);
+		ret = PTR_ERR(temp);
+		if (IS_ERR(temp))
+			goto out;
+		ret = -ENOENT;
+		if (temp->d_inode)
+			ret = msdos_rmdir (dir, temp);
+		d_drop(temp);
+		dput (temp);
+		goto out;
+
+	} else if (cmd == UMSDOS_STAT_DOS) {
+		/* #Specification: ioctl / UMSDOS_STAT_DOS
+		 * The dos_dirent field of the struct umsdos_ioctl is
+		 * used to execute a stat operation in the DOS directory.
+		 * The d_name and d_reclen fields are used.
+		 * 
+		 * The following field of umsdos_ioctl.stat are filled.
+		 * 
+		 * st_ino,st_mode,st_size,st_atime,st_mtime,st_ctime,
+		 * Return 0 if success.
+		 */
+		struct dentry *dret;
+		struct inode *inode;
+
+		dret = umsdos_lookup_dentry(dentry, data.dos_dirent.d_name,
+						    data.dos_dirent.d_reclen);
+		ret = PTR_ERR(dret);
+		if (IS_ERR(dret))
+			goto out;
+		ret = -ENOENT;
+		inode = dret->d_inode;
+		if (inode) {
+			data.stat.st_ino = inode->i_ino;
+			data.stat.st_mode = inode->i_mode;
+			data.stat.st_size = inode->i_size;
+			data.stat.st_atime = inode->i_atime;
+			data.stat.st_ctime = inode->i_ctime;
+			data.stat.st_mtime = inode->i_mtime;
+			ret = -EFAULT;
+			if (!copy_to_user (&idata->stat, &data.stat, 
+						sizeof (data.stat)))
 				ret = 0;
-			}
 		}
+		d_drop(dret);
+		dput(dret);
+		goto out;
+	}
+	else if (cmd == UMSDOS_DOS_SETUP) {
+		/* #Specification: ioctl / UMSDOS_DOS_SETUP
+		 * The UMSDOS_DOS_SETUP ioctl allow changing the
+		 * default permission of the MS-DOS filesystem driver
+		 * on the fly.  The MS-DOS driver applies global permissions
+		 * to every file and directory. Normally these permissions
+		 * are controlled by a mount option. This is not
+		 * available for root partition, so a special utility
+		 * (umssetup) is provided to do this, normally in
+		 * /etc/rc.local.
+		 * 
+		 * Be aware that this applies ONLY to MS-DOS directories
+		 * (those without EMD --linux-.---). Umsdos directory
+		 * have independent (standard) permission for each
+		 * and every file.
+		 * 
+		 * The field umsdos_dirent provide the information needed.
+		 * umsdos_dirent.uid and gid sets the owner and group.
+		 * umsdos_dirent.mode set the permissions flags.
+		 */
+		dir->i_sb->u.msdos_sb.options.fs_uid = data.umsdos_dirent.uid;
+		dir->i_sb->u.msdos_sb.options.fs_gid = data.umsdos_dirent.gid;
+		dir->i_sb->u.msdos_sb.options.fs_umask = data.umsdos_dirent.mode;
+		ret = 0;
 	}
-	Printk (("ioctl return %d\n", ret));
+out:
+	Printk (("ioctl %d, returning %d\n", cmd, ret));
 	return ret;
 }
diff -u --recursive --new-file v2.1.120/linux/fs/umsdos/mangle.c linux/fs/umsdos/mangle.c
--- v2.1.120/linux/fs/umsdos/mangle.c	Sat Sep  5 16:46:41 1998
+++ linux/fs/umsdos/mangle.c	Wed Sep  9 09:01:20 1998
@@ -12,6 +12,11 @@
 #include <linux/kernel.h>
 #include <linux/umsdos_fs.h>
 
+/* (This file is used outside of the kernel) */
+#ifndef __KERNEL__
+#define KERN_WARNING
+#endif
+
 /*
  * Complete the mangling of the MSDOS fake name
  * based on the position of the entry in the EMD file.
diff -u --recursive --new-file v2.1.120/linux/fs/umsdos/namei.c linux/fs/umsdos/namei.c
--- v2.1.120/linux/fs/umsdos/namei.c	Sat Sep  5 16:46:41 1998
+++ linux/fs/umsdos/namei.c	Wed Sep  9 09:01:19 1998
@@ -51,36 +51,36 @@
 /*
  * Lock all other process out of this directory.
  */
+/* #Specification: file creation / not atomic
+ * File creation is a two step process. First we create (allocate)
+ * an entry in the EMD file and then (using the entry offset) we
+ * build a unique name for MSDOS. We create this name in the msdos
+ * space.
+ * 
+ * We have to use semaphore (sleep_on/wake_up) to prevent lookup
+ * into a directory when we create a file or directory and to
+ * prevent creation while a lookup is going on. Since many lookup
+ * may happen at the same time, the semaphore is a counter.
+ * 
+ * Only one creation is allowed at the same time. This protection
+ * may not be necessary. The problem arise mainly when a lookup
+ * or a readdir is done while a file is partially created. The
+ * lookup process see that as a "normal" problem and silently
+ * erase the file from the EMD file. Normal because a file
+ * may be erased during a MSDOS session, but not removed from
+ * the EMD file.
+ * 
+ * The locking is done on a directory per directory basis. Each
+ * directory inode has its wait_queue.
+ * 
+ * For some operation like hard link, things even get worse. Many
+ * creation must occur at once (atomic). To simplify the design
+ * a process is allowed to recursively lock the directory for
+ * creation. The pid of the locking process is kept along with
+ * a counter so a second level of locking is granted or not.
+ */
 void umsdos_lockcreate (struct inode *dir)
 {
-	/* #Specification: file creation / not atomic
-	 * File creation is a two step process. First we create (allocate)
-	 * an entry in the EMD file and then (using the entry offset) we
-	 * build a unique name for MSDOS. We create this name in the msdos
-	 * space.
-	 * 
-	 * We have to use semaphore (sleep_on/wake_up) to prevent lookup
-	 * into a directory when we create a file or directory and to
-	 * prevent creation while a lookup is going on. Since many lookup
-	 * may happen at the same time, the semaphore is a counter.
-	 * 
-	 * Only one creation is allowed at the same time. This protection
-	 * may not be necessary. The problem arise mainly when a lookup
-	 * or a readdir is done while a file is partially created. The
-	 * lookup process see that as a "normal" problem and silently
-	 * erase the file from the EMD file. Normal because a file
-	 * may be erased during a MSDOS session, but not removed from
-	 * the EMD file.
-	 * 
-	 * The locking is done on a directory per directory basis. Each
-	 * directory inode has its wait_queue.
-	 * 
-	 * For some operation like hard link, things even get worse. Many
-	 * creation must occur at once (atomic). To simplify the design
-	 * a process is allowed to recursively lock the directory for
-	 * creation. The pid of the locking process is kept along with
-	 * a counter so a second level of locking is granted or not.
-	 */
 	/*
 	 * Wait for any creation process to finish except
 	 * if we (the process) own the lock
@@ -171,11 +171,21 @@
 
 #endif
 
-static int umsdos_nevercreat (
-				     struct inode *dir,
-				     struct dentry *dentry,
-				     int errcod)
-{				/* Length of the name */
+/*
+ * Check whether we can delete from the directory.
+ */
+static int is_sticky(struct inode *dir, int uid)
+{
+	return !((dir->i_mode & S_ISVTX) == 0 || 
+		capable (CAP_FOWNER) ||
+		current->fsuid == uid ||
+		current->fsuid == dir->i_uid);
+}
+
+
+static int umsdos_nevercreat (struct inode *dir, struct dentry *dentry,
+				int errcod)
+{
 	const char *name = dentry->d_name.name;
 	int len = dentry->d_name.len;
 	int ret = 0;
@@ -210,100 +220,127 @@
 /*
  * Add a new file (ordinary or special) into the alternate directory.
  * The file is added to the real MSDOS directory. If successful, it
- * is then added to the EDM file.
+ * is then added to the EMD file.
  * 
  * Return the status of the operation. 0 mean success.
+ *
+ * #Specification: create / file exist in DOS
+ * Here is a situation. Trying to create a file with
+ * UMSDOS. The file is unknown to UMSDOS but already
+ * exists in the DOS directory.
+ * 
+ * Here is what we are NOT doing:
+ * 
+ * We could silently assume that everything is fine
+ * and allows the creation to succeed.
+ * 
+ * It is possible not all files in the partition
+ * are meant to be visible from linux. By trying to create
+ * those file in some directory, one user may get access
+ * to those file without proper permissions. Looks like
+ * a security hole to me. Off course sharing a file system
+ * with DOS is some kind of security hole :-)
+ * 
+ * So ?
+ * 
+ * We return EEXIST in this case.
+ * The same is true for directory creation.
  */
-static int umsdos_create_any (
-				     struct inode *dir,
-				     struct dentry *dentry,	/* name/length etc */
-				     int mode,	/* Permission bit + file type ??? */
-				     int rdev,	/* major, minor or 0 for ordinary file and symlinks */
-				     char flags
-)
-{				/* Will hold the inode of the newly created file */
-
-	int ret;
+static int umsdos_create_any (struct inode *dir, struct dentry *dentry,
+				int mode, int rdev, char flags)
+{
 	struct dentry *fake;
+	struct inode *inode;
+	int ret;
+	struct umsdos_info info;
+
+if (dentry->d_inode)
+printk("umsdos_create_any: %s/%s not negative!\n",
+dentry->d_parent->d_name.name, dentry->d_name.name);
+
+Printk (("umsdos_create_any /mn/: create %.*s in dir=%lu - nevercreat=/",
+(int) dentry->d_name.len, dentry->d_name.name, dir->i_ino));
 
-	Printk (("umsdos_create_any /mn/: create %.*s in dir=%lu - nevercreat=/", (int) dentry->d_name.len, dentry->d_name.name, dir->i_ino));
 	check_dentry_path (dentry, "umsdos_create_any");
 	ret = umsdos_nevercreat (dir, dentry, -EEXIST);
-	Printk (("%d/\n", ret));
-	if (ret == 0) {
-		struct umsdos_info info;
+	if (ret) {
+Printk (("%d/\n", ret));
+		goto out;
+	}
+
+	ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
+	if (ret)
+		goto out;
+
+	info.entry.mode = mode;
+	info.entry.rdev = rdev;
+	info.entry.flags = flags;
+	info.entry.uid = current->fsuid;
+	info.entry.gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
+	info.entry.ctime = info.entry.atime = info.entry.mtime = CURRENT_TIME;
+	info.entry.nlink = 1;
+	umsdos_lockcreate (dir);
+	ret = umsdos_newentry (dentry->d_parent, &info);
+	if (ret)
+		goto out_unlock;
+
+	/* create short name dentry */
+	fake = umsdos_lookup_dentry(dentry->d_parent, info.fake.fname, 
+					info.fake.len);
+	ret = PTR_ERR(fake);
+	if (IS_ERR(fake))
+		goto out_unlock;
+
+	/* should not exist yet ... */
+	ret = -EEXIST;
+	if (fake->d_inode)
+		goto out_remove;
+
+	ret = msdos_create (dir, fake, S_IFREG | 0777);
+	if (ret)
+		goto out_remove;
+
+	inode = fake->d_inode;
+	umsdos_lookup_patch_new(fake, &info.entry, info.f_pos);
+
+Printk (("inode %p[%lu], count=%d ", inode, inode->i_ino, inode->i_count));
+Printk (("Creation OK: [dir %lu] %.*s pid=%d pos %ld\n",
+dir->i_ino, info.fake.len, info.fake.fname, current->pid, info.f_pos));
 
-		ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
+	check_dentry_path (dentry, "umsdos_create_any: BEG dentry");
+	check_dentry_path (fake, "umsdos_create_any: BEG fake");
 
-		if (ret == 0) {
-			info.entry.mode = mode;
-			info.entry.rdev = rdev;
-			info.entry.flags = flags;
-			info.entry.uid = current->fsuid;
-			info.entry.gid = (dir->i_mode & S_ISGID)
-			    ? dir->i_gid : current->fsgid;
-			info.entry.ctime = info.entry.atime = info.entry.mtime
-			    = CURRENT_TIME;
-			info.entry.nlink = 1;
-			umsdos_lockcreate (dir);
-			ret = umsdos_newentry (dir, &info);
-			if (ret == 0) {
-				inc_count (dir);
-				fake = creat_dentry (info.fake.fname, info.fake.len, NULL, dentry->d_parent);	/* create short name dentry */
-				ret = msdos_create (dir, fake, S_IFREG | 0777);
-				if (ret == 0) {
-					struct inode *inode = fake->d_inode;
-
-					umsdos_lookup_patch (dir, inode, &info.entry, info.f_pos);
-					Printk (("inode %p[%lu], count=%d ", inode, inode->i_ino, inode->i_count));
-					Printk (("Creation OK: [dir %lu] %.*s pid=%d pos %ld\n", dir->i_ino,
-						 info.fake.len, info.fake.fname, current->pid, info.f_pos));
-
-					check_dentry_path (dentry, "umsdos_create_any: BEG dentry");
-					check_dentry_path (fake, "umsdos_create_any: BEG fake");
-					d_instantiate (dentry, inode);	/* long name also gets inode info */
-					inc_count (fake->d_inode); /* we must do it, since dput(fake) will iput(our_inode) which we still need for long name (dentry) */
-					/* dput (fake);	/ * FIXME: is this OK ? we try to kill short name dentry that we don't need */
-					check_dentry_path (dentry, "umsdos_create_any: END dentry");
-					check_dentry_path (fake, "umsdos_create_any: END fake");
-
-				} else {
-					/* #Specification: create / file exist in DOS
-					 * Here is a situation. Trying to create a file with
-					 * UMSDOS. The file is unknown to UMSDOS but already
-					 * exist in the DOS directory.
-					 * 
-					 * Here is what we are NOT doing:
-					 * 
-					 * We could silently assume that everything is fine
-					 * and allows the creation to succeed.
-					 * 
-					 * It is possible not all files in the partition
-					 * are mean to be visible from linux. By trying to create
-					 * those file in some directory, one user may get access
-					 * to those file without proper permissions. Looks like
-					 * a security hole to me. Off course sharing a file system
-					 * with DOS is some kind of security hole :-)
-					 * 
-					 * So ?
-					 * 
-					 * We return EEXIST in this case.
-					 * The same is true for directory creation.
-					 */
-					if (ret == -EEXIST) {
-						printk ("UMSDOS: out of sync, Creation error [%ld], "
-							"deleting %.*s %d %d pos %ld\n", dir->i_ino
-							,info.fake.len, info.fake.fname, -ret, current->pid, info.f_pos);
-					}
-					umsdos_delentry (dir, &info, 0);
-				}
-				Printk (("umsdos_create %.*s ret = %d pos %ld\n",
-					 info.fake.len, info.fake.fname, ret, info.f_pos));
-			}
-			umsdos_unlockcreate (dir);
-		}
-	}
-	/* d_add(dentry,dir); /mn/ FIXME: msdos_create already did this for short name ! */
+	/*
+	 * Note! The long and short name might be the same,
+	 * so check first before doing the instantiate ...
+	 */
+	if (dentry != fake) {
+		/* long name also gets inode info */
+		inode->i_count++;
+		d_instantiate (dentry, inode);
+	}
+
+	check_dentry_path (dentry, "umsdos_create_any: END dentry");
+	check_dentry_path (fake, "umsdos_create_any: END fake");
+	goto out_dput;
+
+out_remove:
+if (ret == -EEXIST)
+printk("UMSDOS: out of sync, error [%ld], deleting %.*s %d %d pos %ld\n",
+dir->i_ino ,info.fake.len, info.fake.fname, -ret, current->pid, info.f_pos);
+	umsdos_delentry (dentry->d_parent, &info, 0);
+
+out_dput:
+Printk (("umsdos_create %.*s ret = %d pos %ld\n",
+info.fake.len, info.fake.fname, ret, info.f_pos));
+	/* N.B. any value in keeping short name dentries? */
+	if (dentry != fake)
+		d_drop(fake);
+	dput(fake);
+
+out_unlock:
+	umsdos_unlockcreate (dir);
+out:
 	return ret;
 }
 
@@ -311,11 +348,9 @@
  * Initialise the new_entry from the old for a rename operation.
  * (Only useful for umsdos_rename_f() below).
  */
-static void umsdos_ren_init (
-				    struct umsdos_info *new_info,
-				    struct umsdos_info *old_info,
-				    int flags)
-{				/* 0 == copy flags from old_name */
+static void umsdos_ren_init (struct umsdos_info *new_info,
+			     struct umsdos_info *old_info, int flags)
+{
 	/* != 0, this is the value of flags */
 	new_info->entry.mode = old_info->entry.mode;
 	new_info->entry.rdev = old_info->entry.rdev;
@@ -343,204 +378,193 @@
  * Rename a file (move) in the file system.
  */
  
-static int umsdos_rename_f (
-				   struct inode *old_dir,
-				   struct dentry *old_dentry,
-				   struct inode *new_dir,
-				   struct dentry *new_dentry,
-				   int flags)
-{				/* 0 == copy flags from old_name */
-				/* != 0, this is the value of flags */
+static int umsdos_rename_f (struct inode *old_dir, struct dentry *old_dentry,
+			    struct inode *new_dir, struct dentry *new_dentry,
+			    int flags)
+{
+	int old_ret, new_ret;
+	struct dentry *old, *new, *dret;
+	struct inode *oldid = NULL;
 	int ret = -EPERM;
 	struct umsdos_info old_info;
-	int old_ret = umsdos_parse (old_dentry->d_name.name, old_dentry->d_name.len, &old_info);
 	struct umsdos_info new_info;
-	int new_ret = umsdos_parse (new_dentry->d_name.name, new_dentry->d_name.len, &new_info);
+
+	old_ret = umsdos_parse (old_dentry->d_name.name,
+				old_dentry->d_name.len, &old_info);
+	if (old_ret)
+		goto out;
+	new_ret = umsdos_parse (new_dentry->d_name.name,
+				new_dentry->d_name.len, &new_info);
+	if (new_ret)
+		goto out;
 
 	check_dentry_path (old_dentry, "umsdos_rename_f OLD");
 	check_dentry_path (new_dentry, "umsdos_rename_f OLD");
 
 	chkstk ();
-	Printk (("umsdos_rename %d %d ", old_ret, new_ret));
-	if (old_ret == 0 && new_ret == 0) {
-		umsdos_lockcreate2 (old_dir, new_dir);
-		chkstk ();
-		Printk (("old findentry "));
-		ret = umsdos_findentry (old_dir, &old_info, 0);
+Printk (("umsdos_rename %d %d ", old_ret, new_ret));
+	umsdos_lockcreate2 (old_dir, new_dir);
+	chkstk ();
+
+	ret = umsdos_findentry(old_dentry->d_parent, &old_info, 0);
+	chkstk ();
+	if (ret) {
+Printk (("ret %d ", ret));
+		goto out_unlock;
+	}
+
+	/* check sticky bit on old_dir */
+	ret = -EPERM;
+	if (is_sticky(old_dir, old_info.entry.uid)) {
+		Printk (("sticky set on old "));
+		goto out_unlock;
+	}
+
+	/* Does new_name already exist? */
+	new_ret = umsdos_findentry(new_dentry->d_parent, &new_info, 0);
+	/* if destination file exists, are we allowed to replace it ? */
+	if (new_ret == 0 && is_sticky(new_dir, new_info.entry.uid)) {
+		Printk (("sticky set on new "));
+		goto out_unlock;
+	}
+
+	Printk (("new newentry "));
+	umsdos_ren_init (&new_info, &old_info, flags);
+	ret = umsdos_newentry (new_dentry->d_parent, &new_info);
+	chkstk ();
+	if (ret) {
+Printk (("ret %d %d ", ret, new_info.fake.len));
+		goto out_unlock;
+	}
+
+	dret = umsdos_lookup_dentry(old_dentry->d_parent, old_info.fake.fname, 
+					old_info.fake.len);
+	ret = PTR_ERR(dret);
+	if (IS_ERR(dret))
+		goto out_unlock;
+#if 0
+	/* This is the same as dret */
+	oldid = dret->d_inode;
+	old = creat_dentry (old_info.fake.fname, old_info.fake.len,
+				oldid, old_dentry->d_parent);
+#endif
+	old = dret;
+	new = umsdos_lookup_dentry(new_dentry->d_parent, new_info.fake.fname, 
+					new_info.fake.len);
+	ret = PTR_ERR(new);
+	if (IS_ERR(new))
+		goto out_dput;
+
+	Printk (("msdos_rename "));
+	check_dentry_path (old, "umsdos_rename_f OLD2");
+	check_dentry_path (new, "umsdos_rename_f NEW2");
+	ret = msdos_rename (old_dir, old, new_dir, new);
+	chkstk ();
+printk("after m_rename ret %d ", ret);
+	/* dput(old); */
+	dput(new);
+
+	if (ret != 0) {
+		umsdos_delentry (new_dentry->d_parent, &new_info,
+				 S_ISDIR (new_info.entry.mode));
 		chkstk ();
-		Printk (("ret %d ", ret));
-		if (ret == 0) {
-			/* check sticky bit on old_dir */
-			if (!(old_dir->i_mode & S_ISVTX) || capable (CAP_FOWNER) ||
-			    current->fsuid == old_info.entry.uid ||
-			    current->fsuid == old_dir->i_uid) {
-				/* Does new_name already exist? */
-				Printk (("new findentry "));
-				ret = umsdos_findentry (new_dir, &new_info, 0);
-				if (ret != 0 ||		/* if destination file exists, are we allowed to replace it ? */
-				    !(new_dir->i_mode & S_ISVTX) || capable (CAP_FOWNER) ||
-				  current->fsuid == new_info.entry.uid ||
-				    current->fsuid == new_dir->i_uid) {
-					Printk (("new newentry "));
-					umsdos_ren_init (&new_info, &old_info, flags);
-					ret = umsdos_newentry (new_dir, &new_info);
-					chkstk ();
-					Printk (("ret %d %d ", ret, new_info.fake.len));
-					if (ret == 0) {
-						struct dentry *old, *new, *d_old_dir, *dret;
-						struct inode *oldid = NULL;
-
-						d_old_dir = creat_dentry ("@d_old_dir@", 11, old_dir, NULL);
-						dret = compat_umsdos_real_lookup (d_old_dir, old_info.fake.fname, old_info.fake.len);
-						if (dret) oldid = dret->d_inode;
-						old = creat_dentry (old_info.fake.fname, old_info.fake.len, oldid, old_dentry->d_parent);
-
-						new = creat_dentry (new_info.fake.fname, new_info.fake.len, NULL, new_dentry->d_parent);
-
-						Printk (("msdos_rename "));
-						inc_count (old_dir);
-						inc_count (new_dir);	/* Both inode are needed later */
-						
-						check_dentry_path (old, "umsdos_rename_f OLD2");
-						check_dentry_path (new, "umsdos_rename_f NEW2");
-						
-						ret = msdos_rename (old_dir, old, new_dir, new);
-						chkstk ();
-						Printk (("after m_rename ret %d ", ret));
-						kill_dentry (old);
-						kill_dentry (new);
-
-						if (ret != 0) {
-							umsdos_delentry (new_dir, &new_info, S_ISDIR (new_info.entry.mode));
-							chkstk ();
-						} else {
-							ret = umsdos_delentry (old_dir, &old_info, S_ISDIR (old_info.entry.mode));
-							chkstk ();
-							if (ret == 0) {
-								/*
-								 * This umsdos_lookup_x does not look very useful.
-								 * It makes sure that the inode of the file will
-								 * be correctly setup (umsdos_patch_inode()) in
-								 * case it is already in use.
-								 * 
-								 * Not very efficient ...
-								 */
-								struct inode *inode;
-
-								inc_count (new_dir);
-								PRINTK ((KERN_DEBUG "rename lookup len %d %d -- ", new_len, new_info.entry.flags));
-								ret = umsdos_lookup_x (new_dir, new_dentry, 0);
-								inode = new_dentry->d_inode;
-								chkstk ();
-								if (ret != 0) {
-									printk ("UMSDOS: partial rename for file %.*s\n"
-										,new_info.entry.name_len, new_info.entry.name);
-								} else {
-									/*
-									 * Update f_pos so notify_change will succeed
-									 * if the file was already in use.
-									 */
-									umsdos_set_dirinfo (inode, new_dir, new_info.f_pos);
-									d_move (old_dentry, new_dentry);
-									chkstk ();
-									/* iput (inode); FIXME */
-								}
-							}
-							fin_dentry (dret);
-						}
-					}
-				} else {
-					/* sticky bit set on new_dir */
-					Printk (("sticky set on new "));
-					ret = -EPERM;
-				}
-			} else {
-				/* sticky bit set on old_dir */
-				Printk (("sticky set on old "));
-				ret = -EPERM;
-			}
-		}
-		Printk ((KERN_DEBUG "umsdos_rename_f: unlocking dirs...\n"));
-		umsdos_unlockcreate (old_dir);
-		umsdos_unlockcreate (new_dir);
+		goto out_dput;
+	}
+
+	ret = umsdos_delentry (old_dentry->d_parent, &old_info,
+				 S_ISDIR (old_info.entry.mode));
+	chkstk ();
+	if (ret)
+		goto out_dput;
+#if 0
+	/*
+	 * Update f_pos so notify_change will succeed
+	 * if the file was already in use.
+	 */
+	umsdos_set_dirinfo (new_dentry->d_inode, new_dir, new_info.f_pos);
+#endif
+	if (old_dentry == dret) {
+printk("umsdos_rename_f: old dentries match -- skipping d_move\n");
+		goto out_dput;
 	}
+	d_move (old_dentry, new_dentry);
+
+out_dput:
+	dput(dret);
+
+out_unlock:
+	Printk ((KERN_DEBUG "umsdos_rename_f: unlocking dirs...\n"));
+	umsdos_unlockcreate (old_dir);
+	umsdos_unlockcreate (new_dir);
+
+out:
 	check_dentry_path (old_dentry, "umsdos_rename_f OLD3");
 	check_dentry_path (new_dentry, "umsdos_rename_f NEW3");
-
 	Printk ((" _ret=%d\n", ret));
 	return ret;
 }
 
 /*
- * Setup un Symbolic link or a (pseudo) hard link
+ * Setup a Symbolic link or a (pseudo) hard link
  * Return a negative error code or 0 if OK.
  */
-static int umsdos_symlink_x (
-				    struct inode *dir,
-				    struct dentry *dentry,
-				    const char *symname,	/* name will point to this path */
-				    int mode,
-				    char flags)
-{
-	/* #Specification: symbolic links / strategy
-	 * A symbolic link is simply a file which hold a path. It is
-	 * implemented as a normal MSDOS file (not very space efficient :-()
-	 * 
-	 * I see 2 different way to do it. One is to place the link data
-	 * in unused entry of the EMD file. The other is to have a separate
-	 * file dedicated to hold all symbolic links data.
-	 * 
-	 * Let's go for simplicity...
-	 */
-
+/* #Specification: symbolic links / strategy
+ * A symbolic link is simply a file which hold a path. It is
+ * implemented as a normal MSDOS file (not very space efficient :-()
+ * 
+ * I see 2 different way to do it. One is to place the link data
+ * in unused entry of the EMD file. The other is to have a separate
+ * file dedicated to hold all symbolic links data.
+ * 
+ * Let's go for simplicity...
+ */
 
-	int ret;
+static int umsdos_symlink_x (struct inode *dir, struct dentry *dentry,
+			const char *symname, int mode, char flags)
+{
+	int ret, len;
+	struct file filp;
 
-	inc_count (dir);	/* We keep the inode in case we need it */
-	/* later */
 	ret = umsdos_create_any (dir, dentry, mode, 0, flags);
-	Printk (("umsdos_symlink ret %d ", ret));
-	if (ret == 0) {
-		int len = strlen (symname);
-		struct file filp;
+	if (ret) {
+Printk (("umsdos_symlink ret %d ", ret));
+		goto out;
+	}
 
-		fill_new_filp (&filp, dentry);
-		filp.f_pos = 0;
+	len = strlen (symname);
 
-		/* Make the inode acceptable to MSDOS FIXME */
-		Printk ((KERN_WARNING "umsdos_symlink_x:  /mn/ is this OK?\n"));
-		Printk ((KERN_WARNING "   symname=%s ; dentry name=%.*s (ino=%lu)\n", symname, (int) dentry->d_name.len, dentry->d_name.name, dentry->d_inode->i_ino));
-		ret = umsdos_file_write_kmem_real (&filp, symname, len);
-		/* dput(dentry); ?? where did this come from FIXME */
-		
-		if (ret >= 0) {
-			if (ret != len) {
-				ret = -EIO;
-				printk ("UMSDOS: "
-				     "Can't write symbolic link data\n");
-			} else {
-				ret = 0;
-			}
-		}
-		if (ret != 0) {
-			UMSDOS_unlink (dir, dentry);
-			dir = NULL;
+	fill_new_filp (&filp, dentry);
+	filp.f_pos = 0;
+
+	/* Make the inode acceptable to MSDOS FIXME */
+Printk ((KERN_WARNING "   symname=%s ; dentry name=%.*s (ino=%lu)\n",
+symname, (int) dentry->d_name.len, dentry->d_name.name, dentry->d_inode->i_ino));
+	ret = umsdos_file_write_kmem_real (&filp, symname, len);
+	
+	if (ret >= 0) {
+		if (ret != len) {
+			ret = -EIO;
+			printk ("UMSDOS: "
+			     "Can't write symbolic link data\n");
+		} else {
+			ret = 0;
 		}
 	}
-	/* d_instantiate(dentry,dir);   //already done in umsdos_create_any. */
+	if (ret != 0) {
+		UMSDOS_unlink (dir, dentry);
+	}
+
+out:
 	Printk (("\n"));
 	return ret;
 }
 
 /*
- * Setup un Symbolic link.
+ * Setup a Symbolic link.
  * Return a negative error code or 0 if OK.
  */
-int UMSDOS_symlink (
-			   struct inode *dir,
-			   struct dentry *dentry,
-			   const char *symname
-)
+int UMSDOS_symlink ( struct inode *dir, struct dentry *dentry,
+		 const char *symname)
 {
 	return umsdos_symlink_x (dir, dentry, symname, S_IFLNK | 0777, 0);
 }
@@ -548,167 +572,78 @@
 /*
  * Add a link to an inode in a directory
  */
-int UMSDOS_link (
-			struct dentry *olddentry,
-			struct inode *dir,
-			struct dentry *dentry)
+int UMSDOS_link (struct dentry *olddentry, struct inode *dir,
+		 struct dentry *dentry)
 {
 	struct inode *oldinode = olddentry->d_inode;
+	struct inode *olddir;
+	char *path;
+	struct dentry *temp;
+	unsigned long buffer;
+	int ret;
+	struct umsdos_dirent entry;
 
-	/* #Specification: hard link / strategy
-	 * Hard links are difficult to implement on top of an MS-DOS FAT file
-	 * system. Unlike Unix file systems, there are no inodes. A directory
-	 * entry holds the functionality of the inode and the entry.
-	 * 
-	 * We will used the same strategy as a normal Unix file system
-	 * (with inodes) except we will do it symbolically (using paths).
-	 * 
-	 * Because anything can happen during a DOS session (defragment,
-	 * directory sorting, etc.), we can't rely on an MS-DOS pseudo
-	 * inode number to record the link. For this reason, the link
-	 * will be done using hidden symbolic links. The following
-	 * scenario illustrates how it works.
-	 * 
-	 * Given a file /foo/file
-	 * 
-	 * #
-	 * ln /foo/file /tmp/file2
-	 * 
-	 * become internally
-	 * 
-	 * mv /foo/file /foo/-LINK1
-	 * ln -s /foo/-LINK1 /foo/file
-	 * ln -s /foo/-LINK1 /tmp/file2
-	 * #
-	 * 
-	 * Using this strategy, we can operate on /foo/file or /foo/file2.
-	 * We can remove one and keep the other, like a normal Unix hard link.
-	 * We can rename /foo/file or /tmp/file2 independently.
-	 * 
-	 * The entry -LINK1 will be hidden. It will hold a link count.
-	 * When all link are erased, the hidden file is erased too.
-	 */
-	/* #Specification: weakness / hard link
-	 * The strategy for hard link introduces a side effect that
-	 * may or may not be acceptable. Here is the sequence
-	 * 
-	 * #
-	 * mkdir subdir1
-	 * touch subdir1/file
-	 * mkdir subdir2
-	 * ln    subdir1/file subdir2/file
-	 * rm    subdir1/file
-	 * rmdir subdir1
-	 * rmdir: subdir1: Directory not empty
-	 * #
-	 * 
-	 * This happen because there is an invisible file (--link) in
-	 * subdir1 which is referenced by subdir2/file.
-	 * 
-	 * Any idea ?
-	 */
-	/* #Specification: weakness / hard link / rename directory
-	 * Another weakness of hard link come from the fact that
-	 * it is based on hidden symbolic links. Here is an example.
-	 * 
-	 * #
-	 * mkdir /subdir1
-	 * touch /subdir1/file
-	 * mkdir /subdir2
-	 * ln    /subdir1/file subdir2/file
-	 * mv    /subdir1 subdir3
-	 * ls -l /subdir2/file
-	 * #
-	 * 
-	 * Since /subdir2/file is a hidden symbolic link
-	 * to /subdir1/..hlinkNNN, accessing it will fail since
-	 * /subdir1 does not exist anymore (has been renamed).
-	 */
-	int ret = 0;
+	ret = -EPERM;
+	if (S_ISDIR (oldinode->i_mode))
+		goto out;
 
-	if (S_ISDIR (oldinode->i_mode)) {
-		/* #Specification: hard link / directory
-		 * A hard link can't be made on a directory. EPERM is returned
-		 * in this case.
-		 */
-		ret = -EPERM;
-	} else if ((ret = umsdos_nevercreat (dir, dentry, -EPERM)) == 0) {
-		struct inode *olddir;
+	ret = umsdos_nevercreat (dir, dentry, -EPERM);
+	if (ret)
+		goto out;
 
-		ret = umsdos_get_dirowner (oldinode, &olddir);
-		Printk (("umsdos_link dir_owner = %lu -> %p [%d] ",
-			 oldinode->u.umsdos_i.i_dir_owner, olddir, olddir->i_count));
-		if (ret == 0) {
-			struct umsdos_dirent entry;
+	ret = -ENOMEM;
+	buffer = get_free_page(GFP_KERNEL);
+	if (!buffer)
+		goto out;
+
+	olddir = olddentry->d_parent->d_inode;
+	umsdos_lockcreate2 (dir, olddir);
+
+	/* get the entry for the old name */
+	ret = umsdos_dentry_to_entry(olddentry, &entry);
+	if (ret)
+		goto out_unlock;
+Printk (("umsdos_link :%.*s: ino %lu flags %d ",
+entry.name_len, entry.name ,oldinode->i_ino, entry.flags));
 
-			umsdos_lockcreate2 (dir, olddir);
-			ret = umsdos_inode2entry (olddir, oldinode, &entry);
-			if (ret == 0) {
-				Printk (("umsdos_link :%.*s: ino %lu flags %d "
-					 ,entry.name_len, entry.name
-					 ,oldinode->i_ino, entry.flags));
-				if (!(entry.flags & UMSDOS_HIDDEN)) {
-					/* #Specification: hard link / first hard link
-					 * The first time a hard link is done on a file, this
-					 * file must be renamed and hidden. Then an internal
-					 * symbolic link must be done on the hidden file.
-					 * 
-					 * The second link is done after on this hidden file.
-					 * 
-					 * It is expected that the Linux MSDOS file system
-					 * keeps the same pseudo inode when a rename operation
-					 * is done on a file in the same directory.
-					 */
-					struct umsdos_info info;
-
-					ret = umsdos_newhidden (olddir, &info);
-					if (ret == 0) {
-						Printk (("olddir[%d] ", olddir->i_count));
-						ret = umsdos_rename_f (olddentry->d_inode, olddentry, dir, dentry, UMSDOS_HIDDEN);
-						if (ret == 0) {
-							char *path = (char *) kmalloc (PATH_MAX, GFP_KERNEL);
-
-							if (path == NULL) {
-								ret = -ENOMEM;
-							} else {
-								struct dentry *temp;
-
-								temp = creat_dentry (entry.name, entry.name_len, NULL, NULL);
-								Printk (("olddir[%d] ", olddir->i_count));
-								ret = umsdos_locate_path (oldinode, path);
-								Printk (("olddir[%d] ", olddir->i_count));
-								if (ret == 0) {
-									inc_count (olddir);
-									ret = umsdos_symlink_x (olddir, temp, path, S_IFREG | 0777, UMSDOS_HLINK);
-									if (ret == 0) {
-										inc_count (dir);
-										ret = umsdos_symlink_x (dir, dentry, path, S_IFREG | 0777, UMSDOS_HLINK);
-									}
-								}
-								kfree (path);
-							}
-						}
-					}
-				} else {
-					char *path = (char *) kmalloc (PATH_MAX, GFP_KERNEL);
-
-					if (path == NULL) {
-						ret = -ENOMEM;
-					} else {
-						ret = umsdos_locate_path (oldinode, path);
-						if (ret == 0) {
-							inc_count (dir);
-							ret = umsdos_symlink_x (dir, dentry, path, S_IFREG | 0777, UMSDOS_HLINK);
-						}
-						kfree (path);
-					}
-				}
-			}
-			umsdos_unlockcreate (olddir);
-			umsdos_unlockcreate (dir);
+	if (!(entry.flags & UMSDOS_HIDDEN)) {
+		struct umsdos_info info;
+
+		ret = umsdos_newhidden (olddentry->d_parent, &info);
+		if (ret)
+			goto out_unlock;
+
+		ret = umsdos_rename_f (olddentry->d_inode, olddentry, 
+					dir, dentry, UMSDOS_HIDDEN);
+		if (ret)
+			goto out_unlock;
+		path = d_path(olddentry, (char *) buffer, PAGE_SIZE);
+		if (!path)
+			goto out_unlock;
+		temp = umsdos_lookup_dentry(olddentry->d_parent, entry.name,
+						entry.name_len); 
+		if (IS_ERR(temp))
+			goto out_unlock;
+		ret = umsdos_symlink_x (olddir, temp, path, 
+					S_IFREG | 0777, UMSDOS_HLINK);
+		if (ret == 0) {
+			ret = umsdos_symlink_x (dir, dentry, path,
+					S_IFREG | 0777, UMSDOS_HLINK);
 		}
-		/* iput (olddir); FIXME */
+		dput(temp);
+		goto out_unlock;
+	}
+	path = d_path(olddentry, (char *) buffer, PAGE_SIZE);
+	if (path) {
+		ret = umsdos_symlink_x (dir, dentry, path, 
+				S_IFREG | 0777, UMSDOS_HLINK);
 	}
+
+out_unlock:
+	umsdos_unlockcreate (olddir);
+	umsdos_unlockcreate (dir);
+	free_page(buffer);
+out:
 	if (ret == 0) {
 		struct iattr newattrs;
 
@@ -716,28 +651,20 @@
 		newattrs.ia_valid = 0;
 		ret = UMSDOS_notify_change (olddentry, &newattrs);
 	}
-/*  dput (olddentry);
- * dput (dentry); FIXME.... */
-
 	Printk (("umsdos_link %d\n", ret));
 	return ret;
 }
 
 
-
 /*
  * Add a new file into the alternate directory.
  * The file is added to the real MSDOS directory. If successful, it
- * is then added to the EDM file.
+ * is then added to the EMD file.
  * 
  * Return the status of the operation. 0 mean success.
  */
-int UMSDOS_create (
-			  struct inode *dir,
-			  struct dentry *dentry,
-			  int mode	/* Permission bit + file type ??? */
-)
-{				/* Will hold the inode of the newly created file */
+int UMSDOS_create (struct inode *dir, struct dentry *dentry, int mode)
+{
 	int ret;
 	Printk ((KERN_ERR "UMSDOS_create: entering\n"));
 	check_dentry_path (dentry, "UMSDOS_create START");
@@ -747,507 +674,405 @@
 }
 
 
-
 /*
  * Add a sub-directory in a directory
  */
-int UMSDOS_mkdir (
-			 struct inode *dir,
-			 struct dentry *dentry,
-			 int mode)
-{
-	int ret = umsdos_nevercreat (dir, dentry, -EEXIST);
+/* #Specification: mkdir / Directory already exist in DOS
+ * We do the same thing as for file creation.
+ * For all user it is an error.
+ */
+/* #Specification: mkdir / umsdos directory / create EMD
+ * When we created a new sub-directory in a UMSDOS
+ * directory (one with full UMSDOS semantics), we
+ * create immediately an EMD file in the new
+ * sub-directory so it inherits UMSDOS semantics.
+ */
+int UMSDOS_mkdir (struct inode *dir, struct dentry *dentry, int mode)
+{
+	struct dentry *temp;
+	struct inode *inode;
+	int ret, err;
+	struct umsdos_info info;
 
-	if (ret == 0) {
-		struct umsdos_info info;
+	ret = umsdos_nevercreat (dir, dentry, -EEXIST);
+	if (ret)
+		goto out;
 
-		ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
-		Printk (("umsdos_mkdir %d\n", ret));
-		if (ret == 0) {
-			info.entry.mode = mode | S_IFDIR;
-			info.entry.rdev = 0;
-			info.entry.uid = current->fsuid;
-			info.entry.gid = (dir->i_mode & S_ISGID)
-			    ? dir->i_gid : current->fsgid;
-			info.entry.ctime = info.entry.atime = info.entry.mtime
-			    = CURRENT_TIME;
-			info.entry.flags = 0;
-			umsdos_lockcreate (dir);
-			info.entry.nlink = 1;
-			ret = umsdos_newentry (dir, &info);
-			Printk (("newentry %d ", ret));
-			if (ret == 0) {
-				struct dentry *temp, *tdir;
+	ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
+	if (ret) {
+Printk (("umsdos_mkdir %d\n", ret));
+		goto out;
+	}
+
+	umsdos_lockcreate (dir);
+	info.entry.mode = mode | S_IFDIR;
+	info.entry.rdev = 0;
+	info.entry.uid = current->fsuid;
+	info.entry.gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
+	info.entry.ctime = info.entry.atime = info.entry.mtime = CURRENT_TIME;
+	info.entry.flags = 0;
+	info.entry.nlink = 1;
+	ret = umsdos_newentry (dentry->d_parent, &info);
+	if (ret) {
+Printk (("newentry %d ", ret));
+		goto out_unlock;
+	}
+
+	/* lookup the short name dentry */
+	temp = umsdos_lookup_dentry(dentry->d_parent, info.fake.fname, 
+					info.fake.len);
+	ret = PTR_ERR(temp);
+	if (IS_ERR(temp))
+		goto out_unlock;
+
+	/* Make sure the short name doesn't exist */
+	ret = -EEXIST;
+	if (temp->d_inode) {
+printk("umsdos_mkdir: short name %s/%s exists\n",
+dentry->d_parent->d_name.name, info.fake.fname);
+		goto out_remove;
+	}
+
+	ret = msdos_mkdir (dir, temp, mode);
+	if (ret)
+		goto out_remove;
 
-				tdir = creat_dentry ("@mkd-dir@", 9, dir, NULL);
-				temp = creat_dentry (info.fake.fname, info.fake.len, NULL, tdir);
-				inc_count (dir);
-				ret = msdos_mkdir (dir, temp, mode);
-
-				if (ret != 0) {
-					umsdos_delentry (dir, &info, 1);
-					/* #Specification: mkdir / Directory already exist in DOS
-					 * We do the same thing as for file creation.
-					 * For all user it is an error.
-					 */
-				} else {
-					/* #Specification: mkdir / umsdos directory / create EMD
-					 * When we created a new sub-directory in a UMSDOS
-					 * directory (one with full UMSDOS semantic), we
-					 * create immediately an EMD file in the new
-					 * sub-directory so it inherit UMSDOS semantic.
-					 */
-					struct inode *subdir=NULL;
-					struct dentry *d_dir, *dret;
-
-					d_dir = creat_dentry ("@d_dir5@", 7, dir, NULL);
-					dret = compat_umsdos_real_lookup (d_dir, info.fake.fname, info.fake.len);
-					if (dret) {
-						struct dentry *tdentry,	*tdsub;
-
-						subdir = dret->d_inode;
-
-						tdsub = creat_dentry ("@mkd-emd@", 9, subdir, NULL);
-						tdentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL, tdsub);
-						ret = msdos_create (subdir, tdentry, S_IFREG | 0777);
-						kill_dentry (tdentry);	/* we don't want empty EMD file to be visible ! too bad kill_dentry does nothing at the moment :-)  FIXME */
-						kill_dentry (tdsub);
-						umsdos_setup_dir_inode (subdir);	/* this should setup dir so it is promoted to EMD, and EMD file is not visible inside it */
-						subdir = NULL;
-						d_instantiate (dentry, temp->d_inode);
-						/* iput (result); FIXME */
-						fin_dentry (dret);
-					}
-					if (ret < 0) {
-						printk ("UMSDOS: Can't create empty --linux-.---\n");
-					}
-					/*iput (subdir); FIXME*/
-				}
-			}
-			umsdos_unlockcreate (dir);
+	inode = temp->d_inode;
+	umsdos_lookup_patch_new(temp, &info.entry, info.f_pos);
+
+	/*
+	 * Note! The long and short name might be the same,
+	 * so check first before doing the instantiate ...
+	 */
+	if (dentry != temp) {
+		if (!dentry->d_inode) {
+			inode->i_count++;
+			d_instantiate(dentry, inode);
+		} else {
+			printk("umsdos_mkdir: not negative??\n");
 		}
+	} else {
+		printk("umsdos_mkdir: dentries match, skipping inst\n");
 	}
+
+	/* create the EMD file */
+	err = umsdos_make_emd(dentry);
+
+	/* 
+	 * set up the dir so it is promoted to EMD,
+	 * with the EMD file invisible inside it.
+	 */
+	umsdos_setup_dir(temp);
+	goto out_dput;
+
+out_remove:
+	umsdos_delentry (dentry->d_parent, &info, 1);
+
+out_dput:
+	/* kill off the short name dentry */ 
+	if (temp != dentry)
+		d_drop(temp);
+	dput(temp);
+
+out_unlock:
+	umsdos_unlockcreate (dir);
 	Printk (("umsdos_mkdir %d\n", ret));
-	/* dput (dentry); / * FIXME /mn/ */
+out:
 	return ret;
 }
 
 /*
  * Add a new device special file into a directory.
+ *
+ * #Specification: Special files / strategy
+ * Device special file, pipes, etc ... are created like normal
+ * file in the msdos file system. Of course they remain empty.
+ * 
+ * One strategy was to create those files only in the EMD file
+ * since they were not important for MSDOS. The problem with
+ * that, is that there were not getting inode number allocated.
+ * The MSDOS filesystems is playing a nice game to fake inode
+ * number, so why not use it.
+ * 
+ * The absence of inode number compatible with those allocated
+ * for ordinary files was causing major trouble with hard link
+ * in particular and other parts of the kernel I guess.
  */
-int UMSDOS_mknod (
-			 struct inode *dir,
-			 struct dentry *dentry,
-			 int mode,
-			 int rdev)
-{
-	/* #Specification: Special files / strategy
-	 * Device special file, pipes, etc ... are created like normal
-	 * file in the msdos file system. Of course they remain empty.
-	 * 
-	 * One strategy was to create those files only in the EMD file
-	 * since they were not important for MSDOS. The problem with
-	 * that, is that there were not getting inode number allocated.
-	 * The MSDOS filesystems is playing a nice game to fake inode
-	 * number, so why not use it.
-	 * 
-	 * The absence of inode number compatible with those allocated
-	 * for ordinary files was causing major trouble with hard link
-	 * in particular and other parts of the kernel I guess.
-	 */
-
+int UMSDOS_mknod (struct inode *dir, struct dentry *dentry,
+		 int mode, int rdev)
+{
 	int ret;
-	
 	check_dentry_path (dentry, "UMSDOS_mknod START");
 	ret = umsdos_create_any (dir, dentry, mode, rdev, 0);
 	check_dentry_path (dentry, "UMSDOS_mknod END");
-
-	/* dput(dentry); / * /mn/ FIXME! */
 	return ret;
 }
 
 /*
  * Remove a sub-directory.
  */
-int UMSDOS_rmdir (
-			 struct inode *dir,
-			 struct dentry *dentry)
-{
-	/* #Specification: style / iput strategy
-	 * In the UMSDOS project, I am trying to apply a single
-	 * programming style regarding inode management.  Many
-	 * entry points are receiving an inode to act on, and must
-	 * do an iput() as soon as they are finished with
-	 * the inode.
-	 * 
-	 * For simple cases, there is no problem.  When you introduce
-	 * error checking, you end up with many iput() calls in the
-	 * code.
-	 * 
-	 * The coding style I use all around is one where I am trying
-	 * to provide independent flow logic (I don't know how to
-	 * name this).  With this style, code is easier to understand
-	 * but you must do iput() everywhere.  Here is an example
-	 * of what I am trying to avoid.
-	 * 
-	 * #
-	 * if (a){
-	 * ...
-	 * if(b){
-	 * ...
-	 * }
-	 * ...
-	 * if (c){
-	 * // Complex state. Was b true? 
-	 * ...
-	 * }
-	 * ...
-	 * }
-	 * // Weird state
-	 * if (d){
-	 * // ...
-	 * }
-	 * // Was iput finally done?
-	 * return status;
-	 * #
-	 * 
-	 * Here is the style I am using.  Still sometimes I do the
-	 * first when things are very simple (or very complicated :-( ).
-	 * 
-	 * #
-	 * if (a){
-	 * if (b){
-	 * ...
-	 * }else if (c){
-	 * // A single state gets here.
-	 * }
-	 * }else if (d){
-	 * ...
-	 * }
-	 * return status;
-	 * #
-	 * 
-	 * Again, while this help clarifying the code, I often get a lot
-	 * of iput(), unlike the first style, where I can place few 
-	 * "strategic" iput(). "strategic" also mean, more difficult
-	 * to place.
-	 * 
-	 * So here is the style I will be using from now on in this project.
-	 * There is always an iput() at the end of a function (which has
-	 * to do an iput()). One iput by inode. There is also one iput()
-	 * at the places where a successful operation is achieved. This
-	 * iput() is often done by a sub-function (often from the msdos
-	 * file system).  So I get one too many iput()?  At the place
-	 * where an iput() is done, the inode is simply nulled, disabling
-	 * the last one.
-	 * 
-	 * #
-	 * if (a){
-	 * if (b){
-	 * ...
-	 * }else if (c){
-	 * msdos_rmdir(dir,...);
-	 * dir = NULL;
-	 * }
-	 * }else if (d){
-	 * ...
-	 * }
-	 * iput (dir);
-	 * return status;
-	 * #
-	 * 
-	 * Note that the umsdos_lockcreate() and umsdos_unlockcreate() function
-	 * pair goes against this practice of "forgetting" the inode as soon
-	 * as possible.
-	 */
-
-	int ret;
+int UMSDOS_rmdir (struct inode *dir, struct dentry *dentry)
+{
+	struct dentry *temp;
+	int ret, err, empty;
+	struct umsdos_info info;
 
 	ret = umsdos_nevercreat (dir, dentry, -EPERM);
-	if (ret == 0) {
-		/* volatile - DELME: I see no reason vor volatile /mn/ */ struct inode *sdir;
+	if (ret)
+		goto out;
 
-		inc_count (dir);
-		ret = umsdos_lookup_x (dir, dentry, 0);
-		sdir = dentry->d_inode;
-		Printk (("rmdir lookup %d ", ret));
-		if (ret == 0) {
-			int empty;
-
-			umsdos_lockcreate (dir);
+#if 0	/* no need for lookup ... we have a dentry ... */
+	ret = umsdos_lookup_x (dir, dentry, 0);
+	Printk (("rmdir lookup %d ", ret));
+	if (ret != 0)
+		goto out;
+#endif
 
-			Printk ((" /mn/ rmdir: FIXME EBUSY TEST: hmmm, i_count is %d > 1 -- FAKING!\n", sdir->i_count));
-			sdir->i_count = 1;	/* /mn/ FIXME! DELME! FOR TEST ONLY ! */
+	umsdos_lockcreate (dir);
+	ret = -EBUSY;
+	if (dentry->d_count > 1) {
+		shrink_dcache_parent(dentry);
+		if (dentry->d_count > 1) {
+printk("umsdos_rmdir: %s/%s busy\n",
+dentry->d_parent->d_name.name, dentry->d_name.name);
+			goto out_unlock;
+		}
+	}
 
-			if (sdir->i_count > 1) {
-				Printk ((" /mn/ rmdir: FIXME EBUSY: hmmm, i_count is %d > 1 -- FAKING!\n", sdir->i_count));
-				ret = -EBUSY;
-			} else if ((empty = umsdos_isempty (sdir)) != 0) {
-				struct dentry *tdentry, *tedir;
-
-				tedir = creat_dentry ("@emd-rmd@", 9, dir, NULL);
-				tdentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL, tedir);
-				umsdos_real_lookup (dir, tdentry);	/* fill inode part */
-				Printk (("isempty %d i_count %d ", empty, sdir->i_count));
-				/* check sticky bit */
-				if (!(dir->i_mode & S_ISVTX) || capable (CAP_FOWNER) ||
-				    current->fsuid == sdir->i_uid ||
-				    current->fsuid == dir->i_uid) {
-					if (empty == 1) {
-						/* We have to remove the EMD file */
-						ret = msdos_unlink (sdir, tdentry);
-						Printk (("UMSDOS_rmdir: unlinking empty EMD ret=%d", ret));
-						sdir = NULL;
-					}
-					/* sdir must be free before msdos_rmdir() */
-					/* iput (sdir); FIXME */
-					sdir = NULL;
-					Printk (("isempty ret %d nlink %d ", ret, dir->i_nlink));
-					if (ret == 0) {
-						struct umsdos_info info;
-						struct dentry *temp, *tdir;
-
-						inc_count (dir);
-						umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
-						/* The findentry is there only to complete */
-						/* the mangling */
-						umsdos_findentry (dir, &info, 2);
-
-						tdir = creat_dentry ("@dir-rmd@", 9, dir, NULL);
-						temp = creat_dentry (info.fake.fname, info.fake.len, NULL, tdir);
-						umsdos_real_lookup (dir, temp);		/* fill inode part */
-
-						Printk ((KERN_ERR "  rmdir start dir=%lu, dir->sb=%p\n", dir->i_ino, dir->i_sb));	/* FIXME: /mn/ debug only */
-						Printk ((KERN_ERR "    dentry=%.*s d_count=%d ino=%lu\n", (int) temp->d_name.len, temp->d_name.name, temp->d_count, temp->d_inode->i_ino));
-						Printk ((KERN_ERR "    d_parent=%.*s d_count=%d ino=%lu\n", (int) temp->d_parent->d_name.len, temp->d_parent->d_name.name, temp->d_parent->d_count, temp->d_parent->d_inode->i_ino));
-
-						ret = msdos_rmdir (dir, temp);
-
-						Printk ((KERN_ERR "  rmdir passed %d\n", ret));		/* FIXME: /mn/ debug only */
-						Printk ((KERN_ERR "  rmdir end dir=%lu, dir->sb=%p\n", dir->i_ino, dir->i_sb));
-						Printk ((KERN_ERR "    dentry=%.*s d_count=%d ino=%p\n", (int) temp->d_name.len, temp->d_name.name, temp->d_count, temp->d_inode));
-						Printk ((KERN_ERR "    d_parent=%.*s d_count=%d ino=%lu\n", (int) temp->d_parent->d_name.len, temp->d_parent->d_name.name, temp->d_parent->d_count, temp->d_parent->d_inode->i_ino));
-
-						kill_dentry (tdir);
-						kill_dentry (temp);
-
-						if (ret == 0) {
-							ret = umsdos_delentry (dir, &info, 1);
-							d_delete (dentry);
-						}
-					}
-				} else {
-					/* sticky bit set and we don't have permission */
-					Printk (("sticky set "));
-					ret = -EPERM;
-				}
-			} else {
-				/*
-				 * The subdirectory is not empty, so leave it there
-				 */
-				ret = -ENOTEMPTY;
-			}
-			/* iput(sdir); FIXME */
-			umsdos_unlockcreate (dir);
+	/* check whether the EMD is empty */
+	empty = umsdos_isempty (dentry);
+	ret = -ENOTEMPTY;
+	if (empty == 0)
+		goto out_unlock;
+
+	/* Have to remove the EMD file? */
+	if (empty == 1) {
+		struct dentry *demd;
+		/* check sticky bit */
+		ret = -EPERM;
+		if (is_sticky(dir, dentry->d_inode->i_uid)) {
+printk("umsdos_rmdir: %s/%s is sticky\n",
+dentry->d_parent->d_name.name, dentry->d_name.name);
+			goto out_unlock;
 		}
+
+		ret = -ENOTEMPTY;
+		/* see if there's an EMD file ... */
+		demd = umsdos_get_emd_dentry(dentry);
+		if (IS_ERR(demd))
+			goto out_unlock;
+printk("umsdos_rmdir: got EMD dentry %s/%s, inode=%p\n",
+demd->d_parent->d_name.name, demd->d_name.name, demd->d_inode);
+
+		err = msdos_unlink (dentry->d_inode, demd);
+Printk (("UMSDOS_rmdir: unlinking empty EMD err=%d", err));
+		dput(demd);
+		if (err)
+			goto out_unlock;
+	}
+
+	umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
+	/* Call findentry to complete the mangling */
+	umsdos_findentry (dentry->d_parent, &info, 2);
+	temp = umsdos_lookup_dentry(dentry->d_parent, info.fake.fname, 
+					info.fake.len);
+	ret = PTR_ERR(temp);
+	if (IS_ERR(temp))
+		goto out_unlock;
+	/*
+	 * If the short name matches the dentry, dput() it now.
+	 */
+	if (temp == dentry) {
+		dput(temp);
+printk("umsdos_rmdir: %s/%s, short matches long\n",
+dentry->d_parent->d_name.name, dentry->d_name.name);
 	}
-	/*  dput(dentry); FIXME /mn/ */
+
+	/*
+	 * Attempt to remove the msdos name.
+	 */
+	ret = msdos_rmdir (dir, temp);
+	if (ret && ret != -ENOENT)
+		goto out_dput;
+
+	/* OK so far ... remove the name from the EMD */
+	ret = umsdos_delentry (dentry->d_parent, &info, 1);
+
+out_dput:
+	/* dput() temp if we didn't do it above */
+	if (temp != dentry) {
+		d_drop(temp);
+		dput(temp);
+		if (!ret)
+			d_delete (dentry);
+printk("umsdos_rmdir: %s/%s, short=%s dput\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, info.fake.fname);
+	}
+
+out_unlock:
+	umsdos_unlockcreate (dir);
+
+out:
 	Printk (("umsdos_rmdir %d\n", ret));
 	return ret;
 }
 
 
-
 /*
  * Remove a file from the directory.
+ *
+ * #Specification: hard link / deleting a link
+ * When we delete a file, and this file is a link
+ * we must subtract 1 to the nlink field of the
+ * hidden link.
+ * 
+ * If the count goes to 0, we delete this hidden
+ * link too.
  */
-int UMSDOS_unlink (
-			  struct inode *dir,
-			  struct dentry *dentry)
+int UMSDOS_unlink (struct inode *dir, struct dentry *dentry)
 {
+	struct dentry *temp;
+	struct inode *inode;
 	int ret;
+	struct umsdos_info info;
 
-	Printk ((" *** UMSDOS_unlink entering /mn/ *** \n"));
+Printk (("UMSDOS_unlink: entering %s/%s\n",
+dentry->d_parent->d_name.name, dentry->d_name.name));
 
 	ret = umsdos_nevercreat (dir, dentry, -EPERM);
+	if (ret)
+		goto out;
 
-	Printk (("UMSDOS_unlink /mn/: nevercreat=%d\n", ret));
+	ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
+	if (ret)
+		goto out;
+
+	umsdos_lockcreate (dir);
+	ret = umsdos_findentry (dentry->d_parent, &info, 1);
+	if (ret) {
+printk("UMSDOS_unlink: findentry returned %d\n", ret);
+		goto out_unlock;
+	}
+
+Printk (("UMSDOS_unlink %.*s ", info.fake.len, info.fake.fname));
+	ret = -EPERM;
+	/* check sticky bit */
+	if (is_sticky(dir, info.entry.uid)) {
+printk("umsdos_unlink: %s/%s is sticky\n",
+dentry->d_parent->d_name.name, dentry->d_name.name);
+		goto out_unlock;
+	}
+
+	ret = 0;
+	if (info.entry.flags & UMSDOS_HLINK) {
+printk("UMSDOS_unlink: hard link %s/%s, fake=%s\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, info.fake.fname);
+		/*
+		 * First, get the inode of the hidden link
+		 * using the standard lookup function.
+		 */
 
-	if (ret == 0) {
-		struct umsdos_info info;
+		ret = umsdos_lookup_x (dir, dentry, 0);
+		inode = dentry->d_inode;
+		if (ret)
+			goto out_unlock;
+
+		Printk (("unlink nlink = %d ", inode->i_nlink));
+		inode->i_nlink--;
+		if (inode->i_nlink == 0) {
+			struct umsdos_dirent entry;
 
-		ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
-		if (ret == 0) {
-			umsdos_lockcreate (dir);
-			ret = umsdos_findentry (dir, &info, 1);
-			Printk (("UMSDOS_unlink: findentry returned %d\n", ret));
+			ret = umsdos_dentry_to_entry (dentry, &entry);
 			if (ret == 0) {
-				Printk (("UMSDOS_unlink %.*s ", info.fake.len, info.fake.fname));
-				/* check sticky bit */
-				if (!(dir->i_mode & S_ISVTX) || capable (CAP_FOWNER) ||
-				    current->fsuid == info.entry.uid ||
-				    current->fsuid == dir->i_uid) {
-					if (info.entry.flags & UMSDOS_HLINK) {
-						/* #Specification: hard link / deleting a link
-						 * When we delete a file, and this file is a link
-						 * we must subtract 1 to the nlink field of the
-						 * hidden link.
-						 * 
-						 * If the count goes to 0, we delete this hidden
-						 * link too.
-						 */
-						/*
-						 * First, get the inode of the hidden link
-						 * using the standard lookup function.
-						 */
-						struct inode *inode;
-
-						inc_count (dir);
-						ret = umsdos_lookup_x (dir, dentry, 0);
-						inode = dentry->d_inode;
-						if (ret == 0) {
-							Printk (("unlink nlink = %d ", inode->i_nlink));
-							inode->i_nlink--;
-							if (inode->i_nlink == 0) {
-								struct inode *hdir = iget (inode->i_sb
-											   ,inode->u.umsdos_i.i_dir_owner);
-								struct umsdos_dirent entry;
-
-								ret = umsdos_inode2entry (hdir, inode, &entry);
-								if (ret == 0) {
-									ret = UMSDOS_unlink (hdir, dentry);
-								} else {
-									/* iput (hdir); FIXME */
-								}
-							} else {
-								struct iattr newattrs;
-
-								newattrs.ia_valid = 0;
-								ret = UMSDOS_notify_change (dentry, &newattrs);
-							}
-							/* iput (inode); FIXME */
-						}
-					}
-					if (ret == 0) {
-						ret = umsdos_delentry (dir, &info, 0);
-						if (ret == 0) {
-							struct dentry *temp,
-							*tdir;
-
-							Printk (("Before msdos_unlink %.*s ", info.fake.len, info.fake.fname));
-							/* inc_count (dir);	/ * FIXME /mn/ is this needed any more now that msdos_unlink locks directories using d_parent ? */
-							tdir = creat_dentry ("@dir-del@", 9, dir, NULL);	/* FIXME /mn/: do we need iget(dir->i_ino) or would dir itself suffice ? */
-							temp = creat_dentry (info.fake.fname, info.fake.len, NULL, tdir);
-							umsdos_real_lookup (dir, temp);		/* fill inode part */
-
-							ret = msdos_unlink_umsdos (dir, temp);
-							Printk (("msdos_unlink %.*s %o ret %d ", info.fake.len, info.fake.fname
-								 ,info.entry.mode, ret));
-
-							d_delete (dentry);
-
-							kill_dentry (tdir);
-							kill_dentry (temp);
-						}
-					}
-				} else {
-					/* sticky bit set and we've not got permission */
-					Printk (("Sticky bit set. "));
-					ret = -EPERM;
-				}
+				ret = UMSDOS_unlink (dentry->d_parent->d_inode,
+							dentry);
 			}
-			umsdos_unlockcreate (dir);
+		} else {
+			struct iattr newattrs;
+			newattrs.ia_valid = 0;
+			ret = UMSDOS_notify_change (dentry, &newattrs);
 		}
 	}
-	/* dput(dentry); FIXME: shouldn't this be done in msdos_unlink ? */
+	if (ret)
+		goto out_unlock;
+
+	/* get the short name dentry */
+	temp = umsdos_lookup_dentry(dentry->d_parent, info.fake.fname, 
+					info.fake.len);
+	if (IS_ERR(temp))
+		goto out_unlock;
+
+	/*
+	 * If the short name matches the long,
+	 * dput() it now so it's not busy.
+	 */
+	if (temp == dentry) {
+printk("UMSDOS_unlink: %s/%s, short matches long\n",
+dentry->d_parent->d_name.name, dentry->d_name.name);
+		dput(temp);
+	}
+
+	ret = umsdos_delentry (dentry->d_parent, &info, 0);
+	if (ret && ret != -ENOENT)
+		goto out_dput;
+
+printk("UMSDOS: Before msdos_unlink %.*s ",
+info.fake.len, info.fake.fname);
+	ret = msdos_unlink_umsdos (dir, temp);
+
+Printk (("msdos_unlink %.*s %o ret %d ",
+info.fake.len, info.fake.fname ,info.entry.mode, ret));
+
+	/* dput() temp if we didn't do it above */
+out_dput:
+	if (temp != dentry) {
+		d_drop(temp);
+		dput(temp);
+		if (!ret)
+			d_delete (dentry);
+printk("umsdos_unlink: %s/%s, short=%s dput\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, info.fake.fname);
+	}
+
+out_unlock:
+	umsdos_unlockcreate (dir);
+out:
 	Printk (("umsdos_unlink %d\n", ret));
 	return ret;
 }
 
 
-
 /*
  * Rename (move) a file.
  */
-int UMSDOS_rename (
-			  struct inode *old_dir,
-			  struct dentry *old_dentry,
-			  struct inode *new_dir,
-			  struct dentry *new_dentry)
-{
-	/* #Specification: weakness / rename
-	 * There is a case where UMSDOS rename has a different behavior
-	 * than a normal Unix file system.  Renaming an open file across
-	 * directory boundary does not work.  Renaming an open file within
-	 * a directory does work, however.
-	 * 
-	 * The problem may is in Linux VFS driver for msdos.
-	 * I believe this is not a bug but a design feature, because
-	 * an inode number represents some sort of directory address
-	 * in the MSDOS directory structure, so moving the file into
-	 * another directory does not preserve the inode number.
-	 */
-	int ret = umsdos_nevercreat (new_dir, new_dentry, -EEXIST);
+int UMSDOS_rename (struct inode *old_dir, struct dentry *old_dentry,
+		   struct inode *new_dir, struct dentry *new_dentry)
+{
+	int ret;
 
-	if (ret == 0) {
-		/* umsdos_rename_f eat the inode and we may need those later */
-		inc_count (old_dir);
-		inc_count (new_dir);
-		ret = umsdos_rename_f (old_dir, old_dentry, new_dir, new_dentry, 0);
-		if (ret == -EEXIST) {
-			/* #Specification: rename / new name exist
-			 * If the destination name already exists, it will
-			 * silently be removed.  EXT2 does it this way
-			 * and this is the spec of SunOS.  So does UMSDOS.
-			 * 
-			 * If the destination is an empty directory it will
-			 * also be removed.
-			 */
-			/* #Specification: rename / new name exist / possible flaw
-			 * The code to handle the deletion of the target (file
-			 * and directory) use to be in umsdos_rename_f, surrounded
-			 * by proper directory locking.  This was ensuring that only
-			 * one process could achieve a rename (modification) operation
-			 * in the source and destination directory.  This was also
-			 * ensuring the operation was "atomic".
-			 * 
-			 * This has been changed because this was creating a
-			 * stack overflow (the stack is only 4 kB) in the kernel.  To avoid
-			 * the code doing the deletion of the target (if exist) has
-			 * been moved to a upper layer. umsdos_rename_f is tried
-			 * once and if it fails with EEXIST, the target is removed
-			 * and umsdos_rename_f is done again.
-			 * 
-			 * This makes the code cleaner and may solve a
-			 * deadlock problem one tester was experiencing.
-			 * 
-			 * The point is to mention that possibly, the semantic of
-			 * "rename" may be wrong. Anyone dare to check that :-)
-			 * Be aware that IF it is wrong, to produce the problem you
-			 * will need two process trying to rename a file to the
-			 * same target at the same time. Again, I am not sure it
-			 * is a problem at all.
-			 */
-			/* This is not terribly efficient but should work. */
-			inc_count (new_dir);
-			ret = UMSDOS_unlink (new_dir, new_dentry);
-			chkstk ();
-			Printk (("rename unlink ret %d -- ", ret));
-			if (ret == -EISDIR) {
-				inc_count (new_dir);
-				ret = UMSDOS_rmdir (new_dir, new_dentry);
-				chkstk ();
-				Printk (("rename rmdir ret %d -- ", ret));
-			}
-			if (ret == 0) {
-				ret = umsdos_rename_f (old_dir, old_dentry,
-						 new_dir, new_dentry, 0);
-				new_dir = old_dir = NULL;
-			}
-		}
+	ret = umsdos_nevercreat (new_dir, new_dentry, -EEXIST);
+	if (ret)
+		goto out;
+
+	ret = umsdos_rename_f(old_dir, old_dentry, new_dir, new_dentry, 0);
+	if (ret != -EEXIST)
+		goto out;
+
+	/* This is not terribly efficient but should work. */
+	ret = UMSDOS_unlink (new_dir, new_dentry);
+	chkstk ();
+	Printk (("rename unlink ret %d -- ", ret));
+	if (ret == -EISDIR) {
+		ret = UMSDOS_rmdir (new_dir, new_dentry);
+		chkstk ();
+		Printk (("rename rmdir ret %d -- ", ret));
 	}
-	/*
-	 * dput (new_dentry);
-	 * dput (old_dentry); FIXME /mn/ */
+	if (ret)
+		goto out;
+
+	/* this time the rename should work ... */
+	ret = umsdos_rename_f (old_dir, old_dentry, new_dir, new_dentry, 0);
+
+out:
 	return ret;
 }
diff -u --recursive --new-file v2.1.120/linux/fs/umsdos/rdir.c linux/fs/umsdos/rdir.c
--- v2.1.120/linux/fs/umsdos/rdir.c	Sat Sep  5 16:46:41 1998
+++ linux/fs/umsdos/rdir.c	Wed Sep  9 09:01:20 1998
@@ -18,9 +18,6 @@
 
 #include <asm/uaccess.h>
 
-#define PRINTK(x)
-#define Printk(x) printk x
-
 
 extern struct inode *pseudo_root;
 
@@ -39,16 +36,13 @@
 	int ret = 0;
 	struct RDIR_FILLDIR *d = (struct RDIR_FILLDIR *) buf;
 
-	PRINTK ((KERN_DEBUG "rdir_filldir /mn/: entering\n"));
 	if (d->real_root) {
 		PRINTK ((KERN_DEBUG "rdir_filldir /mn/: real root!\n"));
 		/* real root of a pseudo_rooted partition */
 		if (name_len != UMSDOS_PSDROOT_LEN
 		    || memcmp (name, UMSDOS_PSDROOT_NAME, UMSDOS_PSDROOT_LEN) != 0) {
 			/* So it is not the /linux directory */
-			if (name_len == 2
-			    && name[0] == '.'
-			    && name[1] == '.') {
+			if (name_len == 2 && name[0] == '.' && name[1] == '.') {
 				/* Make sure the .. entry points back to the pseudo_root */
 				ino = pseudo_root->i_ino;
 			}
@@ -56,30 +50,22 @@
 		}
 	} else {
 		/* Any DOS directory */
-		PRINTK ((KERN_DEBUG "rdir_filldir /mn/: calling d->filldir (%p) for %.*s (%lu)\n", d->filldir, name_len, name, ino));
 		ret = d->filldir (d->dirbuf, name, name_len, offset, ino);
 	}
 	return ret;
 }
 
 
-static int UMSDOS_rreaddir (
-				   struct file *filp,
-				   void *dirbuf,
-				   filldir_t filldir)
+static int UMSDOS_rreaddir (struct file *filp, void *dirbuf, filldir_t filldir)
 {
-	struct RDIR_FILLDIR bufk;
 	struct inode *dir = filp->f_dentry->d_inode;
-
-	PRINTK ((KERN_DEBUG "UMSDOS_rreaddir /mn/: entering %p %p\n", filldir, dirbuf));
-
+	struct RDIR_FILLDIR bufk;
 
 	bufk.filldir = filldir;
 	bufk.dirbuf = dirbuf;
-	bufk.real_root = pseudo_root
-	    && dir == iget (dir->i_sb, UMSDOS_ROOT_INO)
-	    && dir == iget (pseudo_root->i_sb, UMSDOS_ROOT_INO);
-	PRINTK ((KERN_DEBUG "UMSDOS_rreaddir /mn/: calling fat_readdir with filldir=%p and exiting\n", filldir));
+	bufk.real_root = pseudo_root &&
+			 dir->i_ino == UMSDOS_ROOT_INO && 
+			 dir->i_sb == pseudo_root->i_sb;
 	return fat_readdir (filp, &bufk, rdir_filldir);
 }
 
@@ -89,157 +75,138 @@
  * If the result is a directory, make sure we find out if it is
  * a promoted one or not (calling umsdos_setup_dir_inode(inode)).
  */
-int umsdos_rlookup_x (
-			     struct inode *dir,
-			     struct dentry *dentry,
-			     int nopseudo)
-{				/* Don't care about pseudo root mode */
+/* #Specification: pseudo root / DOS/..
+ * In the real root directory (c:\), the directory ..
+ * is the pseudo root (c:\linux).
+ */
+int umsdos_rlookup_x ( struct inode *dir, struct dentry *dentry, int nopseudo)
+{
 	/* so locating "linux" will work */
-	int len = dentry->d_name.len;
 	const char *name = dentry->d_name.name;
+	int len = dentry->d_name.len;
 	struct inode *inode;
 	int ret;
 
-	if (pseudo_root
-	    && len == 2
-	    && name[0] == '.'
-	    && name[1] == '.'
-	    && dir == iget (dir->i_sb, UMSDOS_ROOT_INO)
-	    && dir == iget (pseudo_root->i_sb, UMSDOS_ROOT_INO)) {
-		/*    *result = pseudo_root; */
-		Printk ((KERN_WARNING "umsdos_rlookup_x: we are at pseudo-root thingy?\n"));
-		inc_count (pseudo_root);
+	if (pseudo_root && len == 2 && name[0] == '.' && name[1] == '.' &&
+	    dir->i_ino == UMSDOS_ROOT_INO && dir->i_sb == pseudo_root->i_sb) {
+printk (KERN_WARNING "umsdos_rlookup_x: we are at pseudo-root thingy?\n");
+		pseudo_root->i_count++;
+		d_add(dentry, pseudo_root);
 		ret = 0;
-		/* #Specification: pseudo root / DOS/..
-		 * In the real root directory (c:\), the directory ..
-		 * is the pseudo root (c:\linux).
-		 */
-	} else {
-		inc_count (dir);
-		ret = umsdos_real_lookup (dir, dentry);
-		inode = dentry->d_inode;
-
-#if 0
-		Printk ((KERN_DEBUG "umsdos_rlookup_x: umsdos_real_lookup for %.*s in %lu returned %d\n", len, name, dir->i_ino, ret));
-		Printk ((KERN_DEBUG "umsdos_rlookup_x: umsdos_real_lookup: inode is %p resolving to ", inode));
-		if (inode) {	/* /mn/ FIXME: DEL_ME */
-			Printk ((KERN_DEBUG "i_ino=%lu\n", inode->i_ino));
-		} else {
-			Printk ((KERN_DEBUG "NONE!\n"));
-		}
-#endif
-
-		if ((ret == 0) && inode) {
+		goto out;
+	}
 
-			if (pseudo_root && inode == pseudo_root && !nopseudo) {
-				/* #Specification: pseudo root / DOS/linux
-				 * Even in the real root directory (c:\), the directory
-				 * /linux won't show
-				 */
-				Printk ((KERN_WARNING "umsdos_rlookup_x: do the pseudo-thingy...\n"));
-				ret = -ENOENT;
-				iput (pseudo_root); /* FIXME? */
-
-			} else if (S_ISDIR (inode->i_mode)) {
-				/* We must place the proper function table */
-				/* depending on whether this is an MS-DOS or a UMSDOS directory */
-				Printk ((KERN_DEBUG "umsdos_rlookup_x: setting up setup_dir_inode %lu...\n", inode->i_ino));
-				umsdos_setup_dir_inode (inode);
-			}
+	ret = umsdos_real_lookup (dir, dentry);
+	inode = dentry->d_inode;
+	if ((ret == 0) && inode) {
+		if (inode == pseudo_root && !nopseudo) {
+			/* #Specification: pseudo root / DOS/linux
+			 * Even in the real root directory (c:\), the directory
+			 * /linux won't show
+			 */
+printk(KERN_WARNING "umsdos_rlookup_x: do the pseudo-thingy...\n");
+			/* make the dentry negative */
+			d_delete(dentry);
+		}
+		else if (S_ISDIR (inode->i_mode)) {
+			/* We must place the proper function table
+			 * depending on whether this is an MS-DOS or 
+			 * a UMSDOS directory
+			 */
+Printk ((KERN_DEBUG "umsdos_rlookup_x: setting up setup_dir_inode %lu...\n",
+inode->i_ino));
+			umsdos_setup_dir(dentry);
 		}
-		iput (dir);
 	}
+out:
 	PRINTK ((KERN_DEBUG "umsdos_rlookup_x: returning %d\n", ret));
 	return ret;
 }
 
 
-int UMSDOS_rlookup (
-			   struct inode *dir,
-			   struct dentry *dentry
-)
+int UMSDOS_rlookup ( struct inode *dir, struct dentry *dentry)
 {
-	PRINTK ((KERN_DEBUG "UMSDOS_rlookup /mn/: executing umsdos_rlookup_x for ino=%lu in %.*s\n", dir->i_ino, (int) dentry->d_name.len, dentry->d_name.name));
 	return umsdos_rlookup_x (dir, dentry, 0);
 }
 
 
-static int UMSDOS_rrmdir (
-				 struct inode *dir,
-				 struct dentry *dentry)
+/* #Specification: dual mode / rmdir in a DOS directory
+ * In a DOS (not EMD in it) directory, we use a reverse strategy
+ * compared with a UMSDOS directory. We assume that a subdirectory
+ * of a DOS directory is also a DOS directory. This is not always
+ * true (umssync may be used anywhere), but makes sense.
+ * 
+ * So we call msdos_rmdir() directly. If it failed with a -ENOTEMPTY
+ * then we check if it is a Umsdos directory. We check if it is
+ * really empty (only . .. and --linux-.--- in it). If it is true
+ * we remove the EMD and do a msdos_rmdir() again.
+ * 
+ * In a Umsdos directory, we assume all subdirectories are also
+ * Umsdos directories, so we check the EMD file first.
+ */
+/* #Specification: pseudo root / rmdir /DOS
+ * The pseudo sub-directory /DOS can't be removed!
+ * This is done even if the pseudo root is not a Umsdos
+ * directory anymore (very unlikely), but an accident (under
+ * MS-DOS) is always possible.
+ * 
+ * EPERM is returned.
+ */
+static int UMSDOS_rrmdir ( struct inode *dir, struct dentry *dentry)
 {
-	/* #Specification: dual mode / rmdir in a DOS directory
-	 * In a DOS (not EMD in it) directory, we use a reverse strategy
-	 * compared with a UMSDOS directory. We assume that a subdirectory
-	 * of a DOS directory is also a DOS directory. This is not always
-	 * true (umssync may be used anywhere), but make sense.
-	 * 
-	 * So we call msdos_rmdir() directly. If it failed with a -ENOTEMPTY
-	 * then we check if it is a Umsdos directory. We check if it is
-	 * really empty (only . .. and --linux-.--- in it). If it is true
-	 * we remove the EMD and do a msdos_rmdir() again.
-	 * 
-	 * In a Umsdos directory, we assume all subdirectory are also
-	 * Umsdos directory, so we check the EMD file first.
-	 */
-	int ret;
+	int ret, empty;
 
-	if (umsdos_is_pseudodos (dir, dentry)) {
-		/* #Specification: pseudo root / rmdir /DOS
-		 * The pseudo sub-directory /DOS can't be removed!
-		 * This is done even if the pseudo root is not a Umsdos
-		 * directory anymore (very unlikely), but an accident (under
-		 * MS-DOS) is always possible.
-		 * 
-		 * EPERM is returned.
-		 */
-		ret = -EPERM;
-	} else {
-		umsdos_lockcreate (dir);
-		inc_count (dir);
-		ret = msdos_rmdir (dir, dentry);
-		if (ret == -ENOTEMPTY) {
-			struct inode *sdir;
-
-			inc_count (dir);
-
-			ret = UMSDOS_rlookup (dir, dentry);
-			sdir = dentry->d_inode;
-			PRINTK (("rrmdir lookup %d ", ret));
-			if (ret == 0) {
-				int empty;
-
-				if ((empty = umsdos_isempty (sdir)) != 0) {
-					PRINTK (("isempty %d i_count %d ", empty,
-					  atomic_read (&sdir->i_count)));
-					if (empty == 2) {
-						/*
-						 * Not a Umsdos directory, so the previous msdos_rmdir
-						 * was not lying :-)
-						 */
-						ret = -ENOTEMPTY;
-					} else if (empty == 1) {
-						/* We have to remove the EMD file. */
-						struct dentry *temp;
-
-						Printk ((KERN_WARNING "UMSDOS_rmdir: hmmm... what about inode? FIXME\n"));
-						temp = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL, NULL);	/* FIXME: probably should fill inode part ? */
-						ret = msdos_unlink (sdir, temp);
-						sdir = NULL;
-						if (ret == 0) {
-							inc_count (dir);
-							ret = msdos_rmdir (dir, dentry);
-						}
-					}
-				} else {
-					ret = -ENOTEMPTY;
-				}
-				/* iput (sdir); FIXME */
-			}
+	ret = -EPERM;
+	if (umsdos_is_pseudodos (dir, dentry))
+		goto out;
+
+	umsdos_lockcreate (dir);
+	ret = -EBUSY;
+	if (dentry->d_count > 1) {
+		shrink_dcache_parent(dentry);
+		if (dentry->d_count > 1)
+			goto out_unlock;
+	}
+
+	ret = msdos_rmdir (dir, dentry);
+	if (ret != -ENOTEMPTY)
+		goto out_check;
+
+#if 0	/* why do this? we have the dentry ... */
+	ret = UMSDOS_rlookup (dir, dentry);
+	PRINTK (("rrmdir lookup %d ", ret));
+	if (ret)
+		goto out_unlock;
+	ret = -ENOTEMPTY;
+#endif
+
+	empty = umsdos_isempty (dentry);
+	if (empty == 1) {
+		struct dentry *temp;
+		/* We have to remove the EMD file. */
+		temp = umsdos_lookup_dentry(dentry, UMSDOS_EMD_FILE, 
+						UMSDOS_EMD_NAMELEN);
+		ret = PTR_ERR(temp);
+		if (!IS_ERR(temp)) {
+			ret = 0;
+			if (temp->d_inode)
+				ret = msdos_unlink (dentry->d_inode, temp);
+			dput(temp);
 		}
-		umsdos_unlockcreate (dir);
+		if (ret)
+			goto out_unlock;
 	}
-	/* iput (dir); FIXME */
+	/* now retry the original ... */
+	ret = msdos_rmdir (dir, dentry);
+
+out_check:
+	/* Check whether we succeeded ... */
+	if (!ret)
+		d_delete(dentry);
+
+out_unlock:
+	umsdos_unlockcreate (dir);
+out:
 	check_inode (dir);
 	return ret;
 }
diff -u --recursive --new-file v2.1.120/linux/fs/umsdos/specs linux/fs/umsdos/specs
--- v2.1.120/linux/fs/umsdos/specs	Wed Dec 31 16:00:00 1969
+++ linux/fs/umsdos/specs	Wed Sep  9 09:01:20 1998
@@ -0,0 +1,287 @@
+/* #Specification: umsdos / readdir
+ * umsdos_readdir() should fill a struct dirent with
+ * an inode number. The cheap way to get it is to
+ * do a lookup in the MSDOS directory for each
+ * entry processed by the readdir() function.
+ * This is not very efficient, but very simple. The
+ * other way around is to maintain a copy of the inode
+ * number in the EMD file. This is a problem because
+ * this has to be maintained in sync using tricks.
+ * Remember that MSDOS (the OS) does not update the
+ * modification time (mtime) of a directory. There is
+ * no easy way to tell that a directory was modified
+ * during a DOS session and synchronise the EMD file.
+ */
+		/* #Specification: readdir / . and ..
+		 * The msdos filesystem manages the . and .. entry properly
+		 * so the EMD file won't hold any info about it.
+		 * 
+		 * In readdir, we assume that for the root directory
+		 * the read position will be 0 for ".", 1 for "..". For
+		 * a non root directory, the read position will be 0 for "."
+		 * and 32 for "..".
+		 */
+		/*
+		 * This is a trick used by the msdos file system (fs/msdos/dir.c)
+		 * to manage . and .. for the root directory of a file system.
+		 * Since there is no such entry in the root, fs/msdos/dir.c
+		 * use the following:
+		 * 
+		 * if f_pos == 0, return ".".
+		 * if f_pos == 1, return "..".
+		 * 
+		 * So let msdos handle it
+		 * 
+		 * Since umsdos entries are much larger, we share the same f_pos.
+		 * if f_pos is 0 or 1 or 32, we are clearly looking at . and
+		 * ..
+		 * 
+		 * As soon as we get f_pos == 2 or f_pos == 64, then back to
+		 * 0, but this time we are reading the EMD file.
+		 * 
+		 * Well, not so true. The problem, is that UMSDOS_REC_SIZE is
+		 * also 64, so as soon as we read the first record in the
+		 * EMD, we are back at offset 64. So we set the offset
+		 * to UMSDOS_SPECIAL_DIRFPOS(3) as soon as we have read the
+		 * .. entry from msdos.
+		 * 
+		 * Now (linux 1.3), umsdos_readdir can read more than one
+		 * entry even if we limit (umsdos_dir_once) to only one:
+		 * It skips over hidden file. So we switch to
+		 * UMSDOS_SPECIAL_DIRFPOS as soon as we have read successfully
+		 * the .. entry.
+		 */
+			/* #Specification: umsdos / lookup / inode info
+			 * After successfully reading an inode from the MSDOS
+			 * filesystem, we use the EMD file to complete it.
+			 * We update the following field.
+			 * 
+			 * uid, gid, atime, ctime, mtime, mode.
+			 * 
+			 * We rely on MSDOS for mtime. If the file
+			 * was modified during an MSDOS session, at least
+			 * mtime will be meaningful. We do this only for regular
+			 * file.
+			 * 
+			 * We don't rely on MS-DOS for mtime for directories
+			 * because the MS-DOS date on a directory is its
+			 * creation time (strange MSDOS behavior) which
+			 * corresponds to none of the three Unix time stamps.
+			 */
+	/* #Specification: umsdos / conversion mode
+	 * The msdos filesystem can do some inline conversion
+	 * of the data of a file.  It can translate silently
+	 * from the MS-DOS text file format to the Unix one
+	 * (CRLF -> LF) while reading, and the reverse
+	 * while writing. This is activated using the mount
+	 * option conv=....
+	 * 
+	 * This is not useful for Linux files in a promoted
+	 * directory.  It can even be harmful.  For this
+	 * reason, the binary (no conversion) mode is
+	 * always activated.
+	 */
+	/* #Specification: umsdos / conversion mode / todo
+	 * A flag could be added to file and directories
+	 * forcing an automatic conversion mode (as
+	 * done with the msdos filesystem).
+	 * 
+	 * This flag could be setup on a directory basis
+	 * (instead of file) and all files in it would
+	 * logically inherit it.  If the conversion mode
+	 * is active (conv=) then the i_binary flag would
+	 * be left untouched in those directories.
+	 * 
+	 * It was proposed that the sticky bit be used to set
+	 * this.  A problem with that is that new files would
+	 * be written incorrectly.  The other problem is that
+	 * the sticky bit has a meaning for directories. So
+	 * another bit should be used (there is some space
+	 * in the EMD file for it) and a special utility
+	 * would be used to assign the flag to a directory).
+	 * I don't think it is useful to assign this flag
+	 * on a single file.
+	 */
+ * #Specification: weakness / rename
+ * There is a case where UMSDOS rename has a different behavior
+ * than a normal Unix file system.  Renaming an open file across
+ * directory boundary does not work.  Renaming an open file within
+ * a directory does work, however.
+ * 
+ * The problem may is in Linux VFS driver for msdos.
+ * I believe this is not a bug but a design feature, because
+ * an inode number represents some sort of directory address
+ * in the MSDOS directory structure, so moving the file into
+ * another directory does not preserve the inode number.
+ */
+/* #Specification: rename / new name exist
+ * If the destination name already exists, it will
+ * silently be removed.  EXT2 does it this way
+ * and this is the spec of SunOS.  So does UMSDOS.
+ * 
+ * If the destination is an empty directory it will
+ * also be removed.
+ */
+/* #Specification: rename / new name exist / possible flaw
+ * The code to handle the deletion of the target (file
+ * and directory) use to be in umsdos_rename_f, surrounded
+ * by proper directory locking.  This was ensuring that only
+ * one process could achieve a rename (modification) operation
+ * in the source and destination directory.  This was also
+ * ensuring the operation was "atomic".
+ * 
+ * This has been changed because this was creating a
+ * stack overflow (the stack is only 4 kB) in the kernel.  To avoid
+ * the code doing the deletion of the target (if exist) has
+ * been moved to a upper layer. umsdos_rename_f is tried
+ * once and if it fails with EEXIST, the target is removed
+ * and umsdos_rename_f is done again.
+ * 
+ * This makes the code cleaner and may solve a
+ * deadlock problem one tester was experiencing.
+ * 
+ * The point is to mention that possibly, the semantic of
+ * "rename" may be wrong. Anyone dare to check that :-)
+ * Be aware that IF it is wrong, to produce the problem you
+ * will need two process trying to rename a file to the
+ * same target at the same time. Again, I am not sure it
+ * is a problem at all.
+ */
+/* #Specification: hard link / strategy
+ * Hard links are difficult to implement on top of an MS-DOS FAT file
+ * system. Unlike Unix file systems, there are no inodes. A directory
+ * entry holds the functionality of the inode and the entry.
+ * 
+ * We will used the same strategy as a normal Unix file system
+ * (with inodes) except we will do it symbolically (using paths).
+ * 
+ * Because anything can happen during a DOS session (defragment,
+ * directory sorting, etc.), we can't rely on an MS-DOS pseudo
+ * inode number to record the link. For this reason, the link
+ * will be done using hidden symbolic links. The following
+ * scenario illustrates how it works.
+ * 
+ * Given a file /foo/file
+ * 
+ * #
+ * ln /foo/file /tmp/file2
+ * 
+ * become internally
+ * 
+ * mv /foo/file /foo/-LINK1
+ * ln -s /foo/-LINK1 /foo/file
+ * ln -s /foo/-LINK1 /tmp/file2
+ * #
+ * 
+ * Using this strategy, we can operate on /foo/file or /foo/file2.
+ * We can remove one and keep the other, like a normal Unix hard link.
+ * We can rename /foo/file or /tmp/file2 independently.
+ * 
+ * The entry -LINK1 will be hidden. It will hold a link count.
+ * When all link are erased, the hidden file is erased too.
+ */
+/* #Specification: weakness / hard link
+ * The strategy for hard link introduces a side effect that
+ * may or may not be acceptable. Here is the sequence
+ * 
+ * #
+ * mkdir subdir1
+ * touch subdir1/file
+ * mkdir subdir2
+ * ln    subdir1/file subdir2/file
+ * rm    subdir1/file
+ * rmdir subdir1
+ * rmdir: subdir1: Directory not empty
+ * #
+ * 
+ * This happen because there is an invisible file (--link) in
+ * subdir1 which is referenced by subdir2/file.
+ * 
+ * Any idea ?
+ */
+/* #Specification: weakness / hard link / rename directory
+ * Another weakness of hard link come from the fact that
+ * it is based on hidden symbolic links. Here is an example.
+ * 
+ * #
+ * mkdir /subdir1
+ * touch /subdir1/file
+ * mkdir /subdir2
+ * ln    /subdir1/file subdir2/file
+ * mv    /subdir1 subdir3
+ * ls -l /subdir2/file
+ * #
+ * 
+ * Since /subdir2/file is a hidden symbolic link
+ * to /subdir1/..hlinkNNN, accessing it will fail since
+ * /subdir1 does not exist anymore (has been renamed).
+ */
+/* #Specification: hard link / directory
+ * A hard link can't be made on a directory. EPERM is returned
+ * in this case.
+ */
+/* #Specification: hard link / first hard link
+ * The first time a hard link is done on a file, this
+ * file must be renamed and hidden. Then an internal
+ * symbolic link must be done on the hidden file.
+ * 
+ * The second link is done after on this hidden file.
+ * 
+ * It is expected that the Linux MSDOS file system
+ * keeps the same pseudo inode when a rename operation
+ * is done on a file in the same directory.
+ */
+/* #Specification: function name / convention
+ * A simple convention for function names has been used in
+ * the UMSDOS filesystem. First, all functions use the prefix
+ * umsdos_ to avoid name clashes with other parts of the kernel.
+ * 
+ * Standard VFS entry points use the prefix UMSDOS (upper case)
+ * so it's easier to tell them apart.
+ * N.B. (FIXME) PTW, the order and contents of this struct changed.
+ */
+
+/* #Specification: mount / options
+ * Umsdos run on top of msdos. Currently, it supports no
+ * mount option, but happily pass all option received to
+ * the msdos driver. I am not sure if all msdos mount option
+ * make sense with Umsdos. Here are at least those who
+ * are useful.
+ * uid=
+ * gid=
+ * 
+ * These options affect the operation of umsdos in directories
+ * which do not have an EMD file. They behave like normal
+ * msdos directory, with all limitation of msdos.
+ */
+
+/* #Specification: pseudo root / mount
+ * When a umsdos fs is mounted, a special handling is done
+ * if it is the root partition. We check for the presence
+ * of the file /linux/etc/init or /linux/etc/rc or
+ * /linux/sbin/init. If one is there, we do a chroot("/linux").
+ * 
+ * We check both because (see init/main.c) the kernel
+ * try to exec init at different place and if it fails
+ * it tries /bin/sh /etc/rc. To be consistent with
+ * init/main.c, many more test would have to be done
+ * to locate init. Any complain ?
+ * 
+ * The chroot is done manually in init/main.c but the
+ * info (the inode) is located at mount time and store
+ * in a global variable (pseudo_root) which is used at
+ * different place in the umsdos driver. There is no
+ * need to store this variable elsewhere because it
+ * will always be one, not one per mount.
+ * 
+ * This feature allows the installation
+ * of a linux system within a DOS system in a subdirectory.
+ * 
+ * A user may install its linux stuff in c:\linux
+ * avoiding any clash with existing DOS file and subdirectory.
+ * When linux boots, it hides this fact, showing a normal
+ * root directory with /etc /bin /tmp ...
+ * 
+ * The word "linux" is hardcoded in /usr/include/linux/umsdos_fs.h
+ * in the macro UMSDOS_PSDROOT_NAME.
+ */
diff -u --recursive --new-file v2.1.120/linux/fs/vfat/namei.c linux/fs/vfat/namei.c
--- v2.1.120/linux/fs/vfat/namei.c	Thu Aug 20 17:05:17 1998
+++ linux/fs/vfat/namei.c	Tue Sep  8 22:26:29 1998
@@ -100,22 +100,6 @@
 	}
 };
 
-static int strnicmp(const char *s1, const char *s2, int len)
-{
-	int n = 0;
-	while (*s1 && *s2 && (tolower(*s1) == tolower(*s2))) {
-		s1++; s2++; n++;
-		if (n == len) return 0;
-	}
-	if (*s1 == 0 && *s2 == 0) return 0;
-	if (*s1 && *s2) {
-		if (*s1 > *s2) return 1;
-		return -1;
-	}
-	if (*s1) return 1;
-	return -1;
-}
-
 void vfat_put_super(struct super_block *sb)
 {
 	fat_put_super(sb);
diff -u --recursive --new-file v2.1.120/linux/include/asm-alpha/asm_offsets.h linux/include/asm-alpha/asm_offsets.h
--- v2.1.120/linux/include/asm-alpha/asm_offsets.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-alpha/asm_offsets.h	Sun Sep  6 10:34:33 1998
@@ -0,0 +1,13 @@
+#ifndef __ASM_OFFSETS_H__
+#define __ASM_OFFSETS_H__
+#define TASK_STATE 0
+#define TASK_FLAGS 8
+#define TASK_SIGPENDING 16
+#define TASK_ADDR_LIMIT 24
+#define TASK_EXEC_DOMAIN 32
+#define TASK_NEED_RESCHED 40
+#define TASK_SIZE 1120
+#define STACK_SIZE 16384
+#define HAE_CACHE 0
+#define HAE_REG 8
+#endif /* __ASM_OFFSETS_H__ */
diff -u --recursive --new-file v2.1.120/linux/include/asm-alpha/bitops.h linux/include/asm-alpha/bitops.h
--- v2.1.120/linux/include/asm-alpha/bitops.h	Tue Aug 18 22:02:06 1998
+++ linux/include/asm-alpha/bitops.h	Sun Sep  6 10:34:33 1998
@@ -176,6 +176,7 @@
 	/* Whee.  EV6 can calculate it directly.  */
 	unsigned long result;
 	__asm__("ctlz %1,%0" : "=r"(result) : "r"(~word));
+	return result;
 #else
 	unsigned long bits, qofs, bofs;
 
diff -u --recursive --new-file v2.1.120/linux/include/asm-alpha/console.h linux/include/asm-alpha/console.h
--- v2.1.120/linux/include/asm-alpha/console.h	Fri Jun  2 03:51:16 1995
+++ linux/include/asm-alpha/console.h	Sun Sep  6 10:34:33 1998
@@ -41,7 +41,4 @@
 #define ENV_LANGUAGE		0x0E
 #define ENV_TTY_DEV		0x0F
 
-extern unsigned long dispatch(unsigned long code, ...);
-#define puts(x,l) dispatch(CCB_PUTS,0,x,l)
-
 #endif
diff -u --recursive --new-file v2.1.120/linux/include/asm-alpha/core_mcpcia.h linux/include/asm-alpha/core_mcpcia.h
--- v2.1.120/linux/include/asm-alpha/core_mcpcia.h	Tue Aug 18 22:02:06 1998
+++ linux/include/asm-alpha/core_mcpcia.h	Sun Sep  6 10:34:33 1998
@@ -130,6 +130,8 @@
 /*
  * Error registers
  */
+#define MCPCIA_MC_ERR0(h)	(IDENT_ADDR + 0xf9e0000800UL + HOSE(h))
+#define MCPCIA_MC_ERR1(h)	(IDENT_ADDR + 0xf9e0000840UL + HOSE(h))
 #define MCPCIA_CAP_ERR(h)	(IDENT_ADDR + 0xf9e0000880UL + HOSE(h))
 #define MCPCIA_PCI_ERR1(h)	(IDENT_ADDR + 0xf9e0001040UL + HOSE(h))
 
diff -u --recursive --new-file v2.1.120/linux/include/asm-alpha/core_pyxis.h linux/include/asm-alpha/core_pyxis.h
--- v2.1.120/linux/include/asm-alpha/core_pyxis.h	Tue Aug 18 22:02:06 1998
+++ linux/include/asm-alpha/core_pyxis.h	Sun Sep  6 10:34:33 1998
@@ -182,6 +182,7 @@
 #define PYXIS_RT_COUNT			(IDENT_ADDR + 0x87A0000200UL)
 #define PYXIS_INT_TIME			(IDENT_ADDR + 0x87A0000240UL)
 #define PYXIS_IIC_CTRL			(IDENT_ADDR + 0x87A00002C0UL)
+#define PYXIS_RESET			(IDENT_ADDR + 0x8780000900UL)
 
 /*
  * Bit definitions for I/O Controller status register 0:
@@ -258,18 +259,6 @@
  * a kernel virtual address and vv.
  */
 
-/* Ruffian doesn't do 1G PCI window */
-
-static inline unsigned long pyxis_ruffian_virt_to_bus(void * address)
-{
-	return virt_to_phys(address);
-}
-
-static inline void * pyxis_ruffian_bus_to_virt(unsigned long address)
-{
-	return phys_to_virt(address);
-}
-
 __EXTERN_INLINE unsigned long pyxis_virt_to_bus(void * address)
 {
 	return virt_to_phys(address) + PYXIS_DMA_WIN_BASE;
@@ -600,15 +589,10 @@
 
 #ifdef __WANT_IO_DEF
 
-#ifdef CONFIG_ALPHA_RUFFIAN
-#define virt_to_bus	pyxis_ruffian_virt_to_bus
-#define bus_to_virt	pyxis_ruffian_bus_to_virt
-#else
 #define virt_to_bus	pyxis_virt_to_bus
 #define bus_to_virt	pyxis_bus_to_virt
-#endif
 
-#ifdef BWIO_ENABLED
+#if defined(BWIO_ENABLED) && !defined(CONFIG_ALPHA_RUFFIAN)
 # define __inb		pyxis_bw_inb
 # define __inw		pyxis_bw_inw
 # define __inl		pyxis_bw_inl
@@ -649,7 +633,7 @@
 
 #define dense_mem	pyxis_dense_mem
 
-#ifdef BWIO_ENABLED
+#if defined(BWIO_ENABLED) && !defined(CONFIG_ALPHA_RUFFIAN)
 # define inb(port) __inb((port))
 # define inw(port) __inw((port))
 # define inl(port) __inl((port))
diff -u --recursive --new-file v2.1.120/linux/include/asm-alpha/core_tsunami.h linux/include/asm-alpha/core_tsunami.h
--- v2.1.120/linux/include/asm-alpha/core_tsunami.h	Tue Aug 18 22:02:06 1998
+++ linux/include/asm-alpha/core_tsunami.h	Sun Sep  6 10:34:33 1998
@@ -35,91 +35,77 @@
 #endif
 
 /*
- * CChip and DChip registers
+ * CChip, DChip, and PChip registers
  */
-#define	TSUNAMI_CSR_CSC		(IDENT_ADDR + TS_BIAS + 0x1A0000000UL)
-#define	TSUNAMI_CSR_MTR		(IDENT_ADDR + TS_BIAS + 0x1A0000040UL)
-#define	TSUNAMI_CSR_MISC	(IDENT_ADDR + TS_BIAS + 0x1A0000080UL)
-#define	TSUNAMI_CSR_MPD		(IDENT_ADDR + TS_BIAS + 0x1A00000C0UL)
-#define	TSUNAMI_CSR_AAR0	(IDENT_ADDR + TS_BIAS + 0x1A0000100UL)
-#define	TSUNAMI_CSR_AAR1	(IDENT_ADDR + TS_BIAS + 0x1A0000140UL)
-#define	TSUNAMI_CSR_AAR2	(IDENT_ADDR + TS_BIAS + 0x1A0000180UL)
-#define	TSUNAMI_CSR_AAR3	(IDENT_ADDR + TS_BIAS + 0x1A00001C0UL)
-#define	TSUNAMI_CSR_DIM0	(IDENT_ADDR + TS_BIAS + 0x1A0000200UL)
-#define	TSUNAMI_CSR_DIM1	(IDENT_ADDR + TS_BIAS + 0x1A0000240UL)
-#define	TSUNAMI_CSR_DIR0	(IDENT_ADDR + TS_BIAS + 0x1A0000280UL)
-#define	TSUNAMI_CSR_DIR1	(IDENT_ADDR + TS_BIAS + 0x1A00002C0UL)
-
-#define	TSUNAMI_CSR_DRIR	(IDENT_ADDR + TS_BIAS + 0x1A0000300UL)
-#define	TSUNAMI_CSR_PRBEN	(IDENT_ADDR + TS_BIAS + 0x1A0000340UL)
-#define	TSUNAMI_CSR_IIC	       	(IDENT_ADDR + TS_BIAS + 0x1A0000380UL)
-#define	TSUNAMI_CSR_WDR	       	(IDENT_ADDR + TS_BIAS + 0x1A00003C0UL)
-#define	TSUNAMI_CSR_MPR0	(IDENT_ADDR + TS_BIAS + 0x1A0000400UL)
-#define	TSUNAMI_CSR_MPR1	(IDENT_ADDR + TS_BIAS + 0x1A0000440UL)
-#define	TSUNAMI_CSR_MPR2	(IDENT_ADDR + TS_BIAS + 0x1A0000480UL)
-#define	TSUNAMI_CSR_MPR3	(IDENT_ADDR + TS_BIAS + 0x1A00004C0UL)
-#define	TSUNAMI_CSR_TTR		(IDENT_ADDR + TS_BIAS + 0x1A0000580UL)
-#define	TSUNAMI_CSR_TDR		(IDENT_ADDR + TS_BIAS + 0x1A00005C0UL)
-#define	TSUNAMI_CSR_DSC	       	(IDENT_ADDR + TS_BIAS + 0x1B0000800UL)
-#define	TSUNAMI_CSR_STR		(IDENT_ADDR + TS_BIAS + 0x1B0000840UL)
-#define	TSUNAMI_CSR_DREV	(IDENT_ADDR + TS_BIAS + 0x1B0000880UL)
+
+typedef struct {
+	volatile unsigned long csr __attribute__((aligned(64)));
+} tsunami_64;
+
+typedef struct {
+	tsunami_64	csc;
+	tsunami_64	mtr;
+	tsunami_64	misc;
+	tsunami_64	mpd;
+	tsunami_64	aar0;
+	tsunami_64	aar1;
+	tsunami_64	aar2;
+	tsunami_64	aar3;
+	tsunami_64	dim0;
+	tsunami_64	dim1;
+	tsunami_64	dir0;
+	tsunami_64	dir1;
+	tsunami_64	drir;
+	tsunami_64	prben;
+	tsunami_64	iic;	/* a.k.a. iic0 */
+	tsunami_64	wdr;	/* a.k.a. iic1 */
+	tsunami_64	mpr0;
+	tsunami_64	mpr1;
+	tsunami_64	mpr2;
+	tsunami_64	mpr3;
+	tsunami_64	mctl;
+	tsunami_64	ttr;
+	tsunami_64	tdr;
+	tsunami_64	dim2;
+	tsunami_64	dim3;
+	tsunami_64	dir2;
+	tsunami_64	dir3;
+	tsunami_64	iic2;
+	tsunami_64	iic3;
+} tsunami_cchip;
+
+typedef struct {
+	tsunami_64	dsc;
+	tsunami_64	str;
+	tsunami_64	drev;
+} tsunami_dchip;
+
+typedef struct {
+	tsunami_64	wsba[4];
+	tsunami_64	wsm[4];
+	tsunami_64	tba[4];
+	tsunami_64	pctl;
+	tsunami_64	plat;
+	tsunami_64	reserved;
+	tsunami_64	perror;
+	tsunami_64	perrmask;
+	tsunami_64	perrset;
+	tsunami_64	tlbiv;
+	tsunami_64	tlbia;
+	tsunami_64	pmonctl;
+	tsunami_64	pmoncnt;
+} tsunami_pchip;
+
+#define TSUNAMI_cchip  ((tsunami_cchip *)(IDENT_ADDR+TS_BIAS+0x1A0000000UL))
+#define TSUNAMI_dchip  ((tsunami_dchip *)(IDENT_ADDR+TS_BIAS+0x1B0000800UL))
+#define TSUNAMI_pchip0 ((tsunami_pchip *)(IDENT_ADDR+TS_BIAS+0x180000000UL))
+#define TSUNAMI_pchip1 ((tsunami_pchip *)(IDENT_ADDR+TS_BIAS+0x380000000UL))
+extern int TSUNAMI_bootcpu;
 
 /*
- * PChip registers
+ * TSUNAMI Pchip Error register.
  */
-#define	TSUNAMI_PCHIP0_WSBA0  	(IDENT_ADDR + TS_BIAS + 0x180000000UL)
-#define	TSUNAMI_PCHIP0_WSBA1  	(IDENT_ADDR + TS_BIAS + 0x180000040UL)
-#define	TSUNAMI_PCHIP0_WSBA2  	(IDENT_ADDR + TS_BIAS + 0x180000080UL)
-#define	TSUNAMI_PCHIP0_WSBA3  	(IDENT_ADDR + TS_BIAS + 0x1800000C0UL)
-
-#define	TSUNAMI_PCHIP0_WSM0  	(IDENT_ADDR + TS_BIAS + 0x180000100UL)
-#define	TSUNAMI_PCHIP0_WSM1  	(IDENT_ADDR + TS_BIAS + 0x180000140UL)
-#define	TSUNAMI_PCHIP0_WSM2  	(IDENT_ADDR + TS_BIAS + 0x180000180UL)
-#define	TSUNAMI_PCHIP0_WSM3  	(IDENT_ADDR + TS_BIAS + 0x1800001C0UL)
-#define	TSUNAMI_PCHIP0_TBA0  	(IDENT_ADDR + TS_BIAS + 0x180000200UL)
-#define	TSUNAMI_PCHIP0_TBA1  	(IDENT_ADDR + TS_BIAS + 0x180000240UL)
-#define	TSUNAMI_PCHIP0_TBA2  	(IDENT_ADDR + TS_BIAS + 0x180000280UL)
-#define	TSUNAMI_PCHIP0_TBA3  	(IDENT_ADDR + TS_BIAS + 0x1800002C0UL)
-
-#define	TSUNAMI_PCHIP0_PCTL  	(IDENT_ADDR + TS_BIAS + 0x180000300UL)
-#define	TSUNAMI_PCHIP0_PLAT  	(IDENT_ADDR + TS_BIAS + 0x180000340UL)
-#define	TSUNAMI_PCHIP0_RESERVED	(IDENT_ADDR + TS_BIAS + 0x180000380UL)
-#define	TSUNAMI_PCHIP0_PERROR	(IDENT_ADDR + TS_BIAS + 0x1800003c0UL)
-#define	TSUNAMI_PCHIP0_PERRMASK	(IDENT_ADDR + TS_BIAS + 0x180000400UL)
-#define	TSUNAMI_PCHIP0_PERRSET 	(IDENT_ADDR + TS_BIAS + 0x180000440UL)
-#define	TSUNAMI_PCHIP0_TLBIV  	(IDENT_ADDR + TS_BIAS + 0x180000480UL)
-#define	TSUNAMI_PCHIP0_TLBIA 	(IDENT_ADDR + TS_BIAS + 0x1800004C0UL)
-#define	TSUNAMI_PCHIP0_PMONCTL	(IDENT_ADDR + TS_BIAS + 0x180000500UL)
-#define	TSUNAMI_PCHIP0_PMONCNT	(IDENT_ADDR + TS_BIAS + 0x180000540UL)
-
-#define	TSUNAMI_PCHIP1_WSBA0  	(IDENT_ADDR + TS_BIAS + 0x380000000UL)
-#define	TSUNAMI_PCHIP1_WSBA1  	(IDENT_ADDR + TS_BIAS + 0x380000040UL)
-#define	TSUNAMI_PCHIP1_WSBA2  	(IDENT_ADDR + TS_BIAS + 0x380000080UL)
-#define	TSUNAMI_PCHIP1_WSBA3  	(IDENT_ADDR + TS_BIAS + 0x3800000C0UL)
-#define	TSUNAMI_PCHIP1_WSM0  	(IDENT_ADDR + TS_BIAS + 0x380000100UL)
-#define	TSUNAMI_PCHIP1_WSM1  	(IDENT_ADDR + TS_BIAS + 0x380000140UL)
-#define	TSUNAMI_PCHIP1_WSM2  	(IDENT_ADDR + TS_BIAS + 0x380000180UL)
-#define	TSUNAMI_PCHIP1_WSM3  	(IDENT_ADDR + TS_BIAS + 0x3800001C0UL)
-
-#define	TSUNAMI_PCHIP1_TBA0  	(IDENT_ADDR + TS_BIAS + 0x380000200UL)
-#define	TSUNAMI_PCHIP1_TBA1  	(IDENT_ADDR + TS_BIAS + 0x380000240UL)
-#define	TSUNAMI_PCHIP1_TBA2  	(IDENT_ADDR + TS_BIAS + 0x380000280UL)
-#define	TSUNAMI_PCHIP1_TBA3  	(IDENT_ADDR + TS_BIAS + 0x3800002C0UL)
-
-#define	TSUNAMI_PCHIP1_PCTL  	(IDENT_ADDR + TS_BIAS + 0x380000300UL)
-#define	TSUNAMI_PCHIP1_PLAT  	(IDENT_ADDR + TS_BIAS + 0x380000340UL)
-#define	TSUNAMI_PCHIP1_RESERVED	(IDENT_ADDR + TS_BIAS + 0x380000380UL)
-#define	TSUNAMI_PCHIP1_PERROR	(IDENT_ADDR + TS_BIAS + 0x3800003c0UL)
-#define	TSUNAMI_PCHIP1_PERRMASK	(IDENT_ADDR + TS_BIAS + 0x380000400UL)
-#define	TSUNAMI_PCHIP1_PERRSET	(IDENT_ADDR + TS_BIAS + 0x380000440UL)
-#define	TSUNAMI_PCHIP1_TLBIV  	(IDENT_ADDR + TS_BIAS + 0x380000480UL)
-#define	TSUNAMI_PCHIP1_TLBIA	(IDENT_ADDR + TS_BIAS + 0x3800004C0UL)
-#define	TSUNAMI_PCHIP1_PMONCTL	(IDENT_ADDR + TS_BIAS + 0x380000500UL)
-#define	TSUNAMI_PCHIP1_PMONCNT	(IDENT_ADDR + TS_BIAS + 0x380000540UL)
-
-/*                                                                          */
-/* TSUNAMI Pchip Error register.                                            */
-/*                                                                          */
+
 #define perror_m_lost 0x1
 #define perror_m_serr 0x2
 #define perror_m_perr 0x4
@@ -137,50 +123,52 @@
 #define perror_m_cmd 0xF0000000000000UL
 #define perror_m_syn 0xFF00000000000000UL
 union TPchipPERROR {   
-    struct  {
-        unsigned int perror_v_lost : 1;
-        unsigned perror_v_serr : 1;
-        unsigned perror_v_perr : 1;
-        unsigned perror_v_dcrto : 1;
-        unsigned perror_v_sge : 1;
-        unsigned perror_v_ape : 1;
-        unsigned perror_v_ta : 1;
-        unsigned perror_v_rdpe : 1;
-        unsigned perror_v_nds : 1;
-        unsigned perror_v_rto : 1;
-        unsigned perror_v_uecc : 1;
-        unsigned perror_v_cre : 1;                 
-        unsigned perror_v_rsvd1 : 4;
-        unsigned perror_v_addrl : 32;
-        unsigned perror_v_addrh : 3;
-        unsigned perror_v_rsvd2 : 1;
-        unsigned perror_v_cmd : 4;
-        unsigned perror_v_syn : 8;
+	struct  {
+		unsigned int perror_v_lost : 1;
+		unsigned perror_v_serr : 1;
+		unsigned perror_v_perr : 1;
+		unsigned perror_v_dcrto : 1;
+		unsigned perror_v_sge : 1;
+		unsigned perror_v_ape : 1;
+		unsigned perror_v_ta : 1;
+		unsigned perror_v_rdpe : 1;
+		unsigned perror_v_nds : 1;
+		unsigned perror_v_rto : 1;
+		unsigned perror_v_uecc : 1;
+		unsigned perror_v_cre : 1;                 
+		unsigned perror_v_rsvd1 : 4;
+		unsigned perror_v_addrl : 32;
+		unsigned perror_v_addrh : 3;
+		unsigned perror_v_rsvd2 : 1;
+		unsigned perror_v_cmd : 4;
+		unsigned perror_v_syn : 8;
         } perror_r_bits;
-    int perror_q_whole [2];
-    } ;                       
-/*                                                                          */
-/* TSUNAMI Pchip Window Space Base Address register.                        */
-/*                                                                          */
+	int perror_q_whole [2];
+};                       
+
+/*
+ * TSUNAMI Pchip Window Space Base Address register.
+ */
 #define wsba_m_ena 0x1                
 #define wsba_m_sg 0x2
 #define wsba_m_ptp 0x4
 #define wsba_m_addr 0xFFF00000  
 #define wmask_k_sz1gb 0x3FF00000                   
 union TPchipWSBA {
-    struct  {
-        unsigned wsba_v_ena : 1;
-        unsigned wsba_v_sg : 1;
-        unsigned wsba_v_ptp : 1;
-        unsigned wsba_v_rsvd1 : 17;
-        unsigned wsba_v_addr : 12;
-        unsigned wsba_v_rsvd2 : 32;
+	struct  {
+		unsigned wsba_v_ena : 1;
+		unsigned wsba_v_sg : 1;
+		unsigned wsba_v_ptp : 1;
+		unsigned wsba_v_rsvd1 : 17;
+		unsigned wsba_v_addr : 12;
+		unsigned wsba_v_rsvd2 : 32;
         } wsba_r_bits;
-    int wsba_q_whole [2];
-    } ;
-/*									    */
-/* TSUNAMI Pchip Control Register					    */
-/*									    */
+	int wsba_q_whole [2];
+};
+
+/*
+ * TSUNAMI Pchip Control Register
+ */
 #define pctl_m_fdsc 0x1
 #define pctl_m_fbtb 0x2
 #define pctl_m_thdis 0x4
@@ -207,37 +195,38 @@
 #define pctl_m_rsvd2 0xFFFF000000000000UL
 
 union TPchipPCTL {
-    struct {
-	unsigned pctl_v_fdsc : 1;
-	unsigned pctl_v_fbtb : 1;
-	unsigned pctl_v_thdis : 1;
-	unsigned pctl_v_chaindis : 1;
-	unsigned pctl_v_tgtlat : 1;
-	unsigned pctl_v_hole : 1;
-	unsigned pctl_v_mwin : 1;
-	unsigned pctl_v_arbena : 1;
-	unsigned pctl_v_prigrp : 7;
-	unsigned pctl_v_ppri : 1;
-	unsigned pctl_v_rsvd1 : 2;
-	unsigned pctl_v_eccen : 1;
-	unsigned pctl_v_padm : 1;
-	unsigned pctl_v_cdqmax : 4;
-	unsigned pctl_v_rev : 8;
-	unsigned pctl_v_crqmax : 4;
-	unsigned pctl_v_ptpmax : 4;
-	unsigned pctl_v_pclkx : 2;
-	unsigned pctl_v_fdsdis : 1;
-	unsigned pctl_v_fdwdis : 1;
-	unsigned pctl_v_ptevrfy : 1;
-	unsigned pctl_v_rpp : 1;
-	unsigned pctl_v_pid : 2;
-	unsigned pctl_v_rsvd2 : 16;
+	struct {
+		unsigned pctl_v_fdsc : 1;
+		unsigned pctl_v_fbtb : 1;
+		unsigned pctl_v_thdis : 1;
+		unsigned pctl_v_chaindis : 1;
+		unsigned pctl_v_tgtlat : 1;
+		unsigned pctl_v_hole : 1;
+		unsigned pctl_v_mwin : 1;
+		unsigned pctl_v_arbena : 1;
+		unsigned pctl_v_prigrp : 7;
+		unsigned pctl_v_ppri : 1;
+		unsigned pctl_v_rsvd1 : 2;
+		unsigned pctl_v_eccen : 1;
+		unsigned pctl_v_padm : 1;
+		unsigned pctl_v_cdqmax : 4;
+		unsigned pctl_v_rev : 8;
+		unsigned pctl_v_crqmax : 4;
+		unsigned pctl_v_ptpmax : 4;
+		unsigned pctl_v_pclkx : 2;
+		unsigned pctl_v_fdsdis : 1;
+		unsigned pctl_v_fdwdis : 1;
+		unsigned pctl_v_ptevrfy : 1;
+		unsigned pctl_v_rpp : 1;
+		unsigned pctl_v_pid : 2;
+		unsigned pctl_v_rsvd2 : 16;
 	} pctl_r_bits;
-    int pctl_q_whole [2];
-} ;
-/*                                                                          */
-/* TSUNAMI Pchip Error Mask Register.                                       */
-/*                                                                          */
+	int pctl_q_whole [2];
+};
+
+/*
+ * TSUNAMI Pchip Error Mask Register.
+ */
 #define perrmask_m_lost 0x1
 #define perrmask_m_serr 0x2
 #define perrmask_m_perr 0x4
@@ -252,37 +241,37 @@
 #define perrmask_m_cre 0x800
 #define perrmask_m_rsvd 0xFFFFFFFFFFFFF000UL
 union TPchipPERRMASK {   
-    struct  {
-        unsigned int perrmask_v_lost : 1;
-        unsigned perrmask_v_serr : 1;
-        unsigned perrmask_v_perr : 1;
-        unsigned perrmask_v_dcrto : 1;
-        unsigned perrmask_v_sge : 1;
-        unsigned perrmask_v_ape : 1;
-        unsigned perrmask_v_ta : 1;
-        unsigned perrmask_v_rdpe : 1;
-        unsigned perrmask_v_nds : 1;
-        unsigned perrmask_v_rto : 1;
-        unsigned perrmask_v_uecc : 1;
-        unsigned perrmask_v_cre : 1;                 
-        unsigned perrmask_v_rsvd1 : 20;
-	unsigned perrmask_v_rsvd2 : 32;
+	struct  {
+		unsigned int perrmask_v_lost : 1;
+		unsigned perrmask_v_serr : 1;
+		unsigned perrmask_v_perr : 1;
+		unsigned perrmask_v_dcrto : 1;
+		unsigned perrmask_v_sge : 1;
+		unsigned perrmask_v_ape : 1;
+		unsigned perrmask_v_ta : 1;
+		unsigned perrmask_v_rdpe : 1;
+		unsigned perrmask_v_nds : 1;
+		unsigned perrmask_v_rto : 1;
+		unsigned perrmask_v_uecc : 1;
+		unsigned perrmask_v_cre : 1;                 
+		unsigned perrmask_v_rsvd1 : 20;
+		unsigned perrmask_v_rsvd2 : 32;
         } perrmask_r_bits;
-    int perrmask_q_whole [2];
-    } ;                       
+	int perrmask_q_whole [2];
+};                       
 
 /*
  * Memory spaces:
  */
-#define TSUNAMI_PCI0_MEM		(IDENT_ADDR + TS_BIAS + 0x000000000UL)
-#define TSUNAMI_PCI0_IACK_SC		(IDENT_ADDR + TS_BIAS + 0x1F8000000UL)
-#define TSUNAMI_PCI0_IO			(IDENT_ADDR + TS_BIAS + 0x1FC000000UL)
-#define TSUNAMI_PCI0_CONF		(IDENT_ADDR + TS_BIAS + 0x1FE000000UL)
-
-#define TSUNAMI_PCI1_MEM		(IDENT_ADDR + TS_BIAS + 0x200000000UL)
-#define TSUNAMI_PCI1_IACK_SC		(IDENT_ADDR + TS_BIAS + 0x3F8000000UL)
-#define TSUNAMI_PCI1_IO			(IDENT_ADDR + TS_BIAS + 0x3FC000000UL)
-#define TSUNAMI_PCI1_CONF		(IDENT_ADDR + TS_BIAS + 0x3FE000000UL)
+#define HOSE(h) (((unsigned long)(h)) << 33)
+
+#define TSUNAMI_MEM(h)	     (IDENT_ADDR + TS_BIAS + 0x000000000UL + HOSE(h))
+#define _TSUNAMI_IACK_SC(h)  (IDENT_ADDR + TS_BIAS + 0x1F8000000UL + HOSE(h))
+#define TSUNAMI_IO(h)	     (IDENT_ADDR + TS_BIAS + 0x1FC000000UL + HOSE(h))
+#define TSUNAMI_CONF(h)	     (IDENT_ADDR + TS_BIAS + 0x1FE000000UL + HOSE(h))
+
+#define TSUNAMI_IACK_SC	     _TSUNAMI_IACK_SC(0) /* hack! */
+
 
 /*
  * Data structure for handling TSUNAMI machine checks:
@@ -319,51 +308,44 @@
  * can only use linear accesses to get at PCI memory and I/O spaces.
  */
 
-/* HACK ALERT! HACK ALERT! */
-/* HACK ALERT! HACK ALERT! */
-
-/* Only using PCI bus 0 for now in all routines.  */
-
-#define TSUNAMI_IACK_SC  TSUNAMI_PCI0_IACK_SC
-
-/* HACK ALERT! HACK ALERT! */
-/* HACK ALERT! HACK ALERT! */
-
 #define vucp	volatile unsigned char *
 #define vusp	volatile unsigned short *
 #define vuip	volatile unsigned int *
 #define vulp	volatile unsigned long *
 
+#define XADDR	((addr) & 0xffffffffUL)
+#define XHOSE	(((addr) >> 32) & 3UL)
+
 __EXTERN_INLINE unsigned int tsunami_inb(unsigned long addr)
 {
-	return __kernel_ldbu(*(vucp)(addr + TSUNAMI_PCI0_IO));
+	return __kernel_ldbu(*(vucp)(XADDR + TSUNAMI_IO(XHOSE)));
 }
 
 __EXTERN_INLINE void tsunami_outb(unsigned char b, unsigned long addr)
 {
-	__kernel_stb(b, *(vucp)(addr + TSUNAMI_PCI0_IO));
+	__kernel_stb(b, *(vucp)(XADDR + TSUNAMI_IO(XHOSE)));
 	mb();
 }
 
 __EXTERN_INLINE unsigned int tsunami_inw(unsigned long addr)
 {
-	return __kernel_ldwu(*(vusp)(addr+TSUNAMI_PCI0_IO));
+	return __kernel_ldwu(*(vusp)(XADDR + TSUNAMI_IO(XHOSE)));
 }
 
 __EXTERN_INLINE void tsunami_outw(unsigned short b, unsigned long addr)
 {
-	__kernel_stw(b, *(vusp)(addr+TSUNAMI_PCI0_IO));
+	__kernel_stw(b, *(vusp)(XADDR + TSUNAMI_IO(XHOSE)));
 	mb();
 }
 
 __EXTERN_INLINE unsigned int tsunami_inl(unsigned long addr)
 {
-	return *(vuip)(addr+TSUNAMI_PCI0_IO);
+	return *(vuip)(XADDR + TSUNAMI_IO(XHOSE));
 }
 
 __EXTERN_INLINE void tsunami_outl(unsigned int b, unsigned long addr)
 {
-	*(vuip)(addr+TSUNAMI_PCI0_IO) = b;
+	*(vuip)(XADDR + TSUNAMI_IO(XHOSE)) = b;
 	mb();
 }
 
@@ -373,45 +355,45 @@
 
 __EXTERN_INLINE unsigned long tsunami_readb(unsigned long addr)
 {
-	return __kernel_ldbu(*(vucp)(addr+TSUNAMI_PCI0_MEM));
+	return __kernel_ldbu(*(vucp)(XADDR + TSUNAMI_MEM(XHOSE)));
 }
 
 __EXTERN_INLINE unsigned long tsunami_readw(unsigned long addr)
 {
-	return __kernel_ldwu(*(vusp)(addr+TSUNAMI_PCI0_MEM));
+	return __kernel_ldwu(*(vusp)(XADDR + TSUNAMI_MEM(XHOSE)));
 }
 
 __EXTERN_INLINE unsigned long tsunami_readl(unsigned long addr)
 {
-	return *(vuip)(addr+TSUNAMI_PCI0_MEM);
+	return *(vuip)(XADDR + TSUNAMI_MEM(XHOSE));
 }
 
 __EXTERN_INLINE unsigned long tsunami_readq(unsigned long addr)
 {
-	return *(vulp)(addr+TSUNAMI_PCI0_MEM);
+	return *(vulp)(XADDR + TSUNAMI_MEM(XHOSE));
 }
 
 __EXTERN_INLINE void tsunami_writeb(unsigned char b, unsigned long addr)
 {
-	__kernel_stb(b, *(vucp)(addr+TSUNAMI_PCI0_MEM));
+	__kernel_stb(b, *(vucp)(XADDR + TSUNAMI_MEM(XHOSE)));
 	mb();
 }
 
 __EXTERN_INLINE void tsunami_writew(unsigned short b, unsigned long addr)
 {
-	__kernel_stw(b, *(vusp)(addr+TSUNAMI_PCI0_MEM));
+	__kernel_stw(b, *(vusp)(XADDR + TSUNAMI_MEM(XHOSE)));
 	mb();
 }
 
 __EXTERN_INLINE void tsunami_writel(unsigned int b, unsigned long addr)
 {
-	*(vuip)(addr+TSUNAMI_PCI0_MEM) = b;
+	*(vuip)(XADDR + TSUNAMI_MEM(XHOSE)) = b;
 	mb();
 }
 
 __EXTERN_INLINE void tsunami_writeq(unsigned long b, unsigned long addr)
 {
-	*(vulp)(addr+TSUNAMI_PCI0_MEM) = b;
+	*(vulp)(XADDR + TSUNAMI_MEM(XHOSE)) = b;
 	mb();
 }
 
@@ -419,13 +401,16 @@
 
 __EXTERN_INLINE unsigned long tsunami_dense_mem(unsigned long addr)
 {
-	return TSUNAMI_PCI0_MEM;
+	return TSUNAMI_MEM(XHOSE);
 }
 
 #undef vucp
 #undef vusp
 #undef vuip
 #undef vulp
+
+#undef XADDR
+#undef XHOSE
 
 #ifdef __WANT_IO_DEF
 
diff -u --recursive --new-file v2.1.120/linux/include/asm-alpha/dma.h linux/include/asm-alpha/dma.h
--- v2.1.120/linux/include/asm-alpha/dma.h	Tue Aug 18 22:02:06 1998
+++ linux/include/asm-alpha/dma.h	Sun Sep  6 10:34:33 1998
@@ -78,13 +78,18 @@
    due to a hardware SIO (PCI<->ISA bus bridge) chip limitation, is 64MB.
    See <asm/apecs.h> for more info.
 */
+/* The maximum address that we can perform a DMA transfer to on RUFFIAN,
+   due to a hardware SIO (PCI<->ISA bus bridge) chip limitation, is 16MB.
+   See <asm/pyxis.h> for more info.
+*/
 /* NOTE: we must define the maximum as something less than 64Mb, to prevent 
    virt_to_bus() from returning an address in the first window, for a
    data area that goes beyond the 64Mb first DMA window. Sigh...
    We MUST coordinate the maximum with <asm/apecs.h> for consistency.
    For now, this limit is set to 48Mb...
 */
-#define ALPHA_XL_MAX_DMA_ADDRESS	(0xfffffc0003000000UL)
+#define ALPHA_XL_MAX_DMA_ADDRESS	(IDENT_ADDR+0x3000000UL)
+#define ALPHA_RUFFIAN_MAX_DMA_ADDRESS	(IDENT_ADDR+0x1000000UL)
 #define ALPHA_MAX_DMA_ADDRESS		(~0UL)
 
 #ifdef CONFIG_ALPHA_GENERIC
@@ -92,6 +97,8 @@
 #else
 # ifdef CONFIG_ALPHA_XL
 #  define MAX_DMA_ADDRESS		ALPHA_XL_MAX_DMA_ADDRESS
+# elif defined(CONFIG_ALPHA_RUFFIAN)
+#  define MAX_DMA_ADDRESS		ALPHA_RUFFIAN_MAX_DMA_ADDRESS
 # else
 #  define MAX_DMA_ADDRESS		ALPHA_MAX_DMA_ADDRESS
 # endif
diff -u --recursive --new-file v2.1.120/linux/include/asm-alpha/floppy.h linux/include/asm-alpha/floppy.h
--- v2.1.120/linux/include/asm-alpha/floppy.h	Tue Aug 18 22:02:07 1998
+++ linux/include/asm-alpha/floppy.h	Sun Sep  6 10:34:33 1998
@@ -52,8 +52,8 @@
 
 /*
  * Most Alphas have no problems with floppy DMA crossing 64k borders,
- * except for XL.  It is also the only one with DMA limits, so we use
- * that to test in the generic kernel.
+ * except for XL and RUFFIAN.  They are also the only one with DMA
+ * limits, so we use that to test in the generic kernel.
  */
 
 #define __CROSS_64KB(a,s)					\
@@ -64,7 +64,7 @@
 #ifdef CONFIG_ALPHA_GENERIC
 # define CROSS_64KB(a,s)   (__CROSS_64KB(a,s) && ~alpha_mv.max_dma_address)
 #else
-# ifdef CONFIG_ALPHA_XL
+# if defined(CONFIG_ALPHA_XL) || defined(CONFIG_ALPHA_RUFFIAN)
 #  define CROSS_64KB(a,s)  __CROSS_64KB(a,s)
 # else
 #  define CROSS_64KB(a,s)  (0)
diff -u --recursive --new-file v2.1.120/linux/include/asm-alpha/hardirq.h linux/include/asm-alpha/hardirq.h
--- v2.1.120/linux/include/asm-alpha/hardirq.h	Fri May  8 23:14:54 1998
+++ linux/include/asm-alpha/hardirq.h	Sun Sep  6 10:34:33 1998
@@ -1,51 +1,58 @@
 #ifndef _ALPHA_HARDIRQ_H
 #define _ALPHA_HARDIRQ_H
 
+/* Initially just a straight copy of the i386 code.  */
+
 #include <linux/tasks.h>
 
 extern unsigned int local_irq_count[NR_CPUS];
-#define in_interrupt() (local_irq_count[smp_processor_id()] + local_bh_count[smp_processor_id()] != 0)
+
+/*
+ * Are we in an interrupt context? Either doing bottom half
+ * or hardware interrupt processing?
+ */
+
+#define in_interrupt()						\
+({								\
+	int __cpu = smp_processor_id();				\
+	(local_irq_count[__cpu] + local_bh_count[__cpu]) != 0;	\
+})
 
 #ifndef __SMP__
 
 #define hardirq_trylock(cpu)	(local_irq_count[cpu] == 0)
-#define hardirq_endlock(cpu)	do { } while (0)
+#define hardirq_endlock(cpu)	((void) 0)
 
-#define hardirq_enter(cpu)	(local_irq_count[cpu]++)
-#define hardirq_exit(cpu)	(local_irq_count[cpu]--)
+#define hardirq_enter(cpu, irq)	(local_irq_count[cpu]++)
+#define hardirq_exit(cpu, irq)	(local_irq_count[cpu]--)
 
-#define synchronize_irq()	do { } while (0)
+#define synchronize_irq()	barrier()
 
 #else
 
-/* initially just a straight copy if the i386 code */
-
 #include <asm/atomic.h>
 #include <asm/spinlock.h>
-#include <asm/system.h>
-#include <asm/smp.h>
 
-extern unsigned char global_irq_holder;
+extern int global_irq_holder;
 extern spinlock_t global_irq_lock;
 extern atomic_t global_irq_count;
 
 static inline void release_irqlock(int cpu)
 {
 	/* if we didn't own the irq lock, just ignore.. */
-	if (global_irq_holder == (unsigned char) cpu) {
+	if (global_irq_holder == cpu) {
 		global_irq_holder = NO_PROC_ID;
 		spin_unlock(&global_irq_lock);
         }
 }
 
-/* Ordering of the counter bumps is _deadly_ important. */
-static inline void hardirq_enter(int cpu)
+static inline void hardirq_enter(int cpu, int irq)
 {
 	++local_irq_count[cpu];
         atomic_inc(&global_irq_count);
 }
 
-static inline void hardirq_exit(int cpu)
+static inline void hardirq_exit(int cpu, int irq)
 {
 	atomic_dec(&global_irq_count);
         --local_irq_count[cpu];
@@ -53,28 +60,10 @@
 
 static inline int hardirq_trylock(int cpu)
 {
-	unsigned long flags;
-	int ret = 1;
-
-        __save_and_cli(flags);
-        if ((atomic_add_return(1, &global_irq_count) != 1) ||
-	    (global_irq_lock.lock != 0)) {
-		atomic_dec(&global_irq_count);
-                __restore_flags(flags);
-                ret = 0;
-        } else {
-		++local_irq_count[cpu];
-                __sti();
-        }
-        return ret;
+	return !atomic_read(&global_irq_count) && !global_irq_lock.lock;
 }
 
-#define hardirq_endlock(cpu) \
-	do { \
-	       __cli(); \
-		hardirq_exit(cpu); \
-		__sti(); \
-	} while (0)
+#define hardirq_endlock(cpu)  ((void)0)
 
 extern void synchronize_irq(void);
 
diff -u --recursive --new-file v2.1.120/linux/include/asm-alpha/hwrpb.h linux/include/asm-alpha/hwrpb.h
--- v2.1.120/linux/include/asm-alpha/hwrpb.h	Tue Aug 18 22:02:07 1998
+++ linux/include/asm-alpha/hwrpb.h	Sun Sep  6 10:34:33 1998
@@ -93,7 +93,7 @@
 	unsigned long halt_pv;
 	unsigned long halt_reason;
 	unsigned long res;
-	char ipc_buffer[168];
+	unsigned long ipc_buffer[21];
 	unsigned long palcode_avail[16];
 	unsigned long compatibility;
 };
diff -u --recursive --new-file v2.1.120/linux/include/asm-alpha/io.h linux/include/asm-alpha/io.h
--- v2.1.120/linux/include/asm-alpha/io.h	Tue Aug 18 22:02:07 1998
+++ linux/include/asm-alpha/io.h	Sun Sep  6 10:34:33 1998
@@ -12,11 +12,10 @@
 /*
  * Virtual -> physical identity mapping starts at this offset
  */
-/* XXX: Do we need to conditionalize on this?  */
 #ifdef USE_48_BIT_KSEG
-#define IDENT_ADDR	(0xffff800000000000UL)
+#define IDENT_ADDR     0xffff800000000000
 #else
-#define IDENT_ADDR	(0xfffffc0000000000UL)
+#define IDENT_ADDR     0xfffffc0000000000
 #endif
 
 #ifdef __KERNEL__
@@ -52,7 +51,10 @@
  */
 static inline unsigned long virt_to_phys(volatile void * address)
 {
-	return 0xffffffffUL & (unsigned long) address;
+	/* Conditionalize this on the CPU?  This here is 40 bits,
+	   whereas EV4 only supports 34.  But KSEG is farther out
+	   so it shouldn't _really_ matter.  */
+	return 0xffffffffffUL & (unsigned long) address;
 }
 
 static inline void * phys_to_virt(unsigned long address)
@@ -322,6 +324,7 @@
 #ifdef CONFIG_ALPHA_GENERIC
 # define RTC_PORT(x)	((x) + alpha_mv.rtc_port)
 # define RTC_ADDR(x)	((x) | alpha_mv.rtc_addr)
+# define RTC_ALWAYS_BCD	(alpha_mv.rtc_bcd)
 #else
 # ifdef CONFIG_ALPHA_JENSEN
 #  define RTC_PORT(x)	(0x170+(x))
@@ -330,9 +333,13 @@
 #  define RTC_PORT(x)	(0x70 + (x))
 #  define RTC_ADDR(x)	(0x80 | (x))
 # endif
+# ifdef CONFIG_ALPHA_RUFFIAN
+#  define RTC_ALWAYS_BCD	1
+# else
+#  define RTC_ALWAYS_BCD	0
+# endif
 #endif
 
-#define RTC_ALWAYS_BCD	0
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.1.120/linux/include/asm-alpha/machvec.h linux/include/asm-alpha/machvec.h
--- v2.1.120/linux/include/asm-alpha/machvec.h	Tue Aug 18 22:02:07 1998
+++ linux/include/asm-alpha/machvec.h	Sun Sep  6 10:34:33 1998
@@ -12,6 +12,7 @@
 struct mm_struct;
 struct pt_regs;
 struct vm_area_struct;
+struct linux_hose_info;
 
 struct alpha_machine_vector
 {
@@ -21,10 +22,12 @@
 	unsigned long hae_cache;
 	unsigned long *hae_register;
 
+	unsigned int nr_irqs  : 16;
+	unsigned int rtc_port : 16;
+	unsigned int rtc_addr : 15;
+	unsigned int rtc_bcd  : 1;
+	unsigned int max_asn  : 16;
 	unsigned long max_dma_address;
-	unsigned int nr_irqs;
-	unsigned int rtc_port, rtc_addr;
-	unsigned int max_asn;
 	unsigned long mmu_context_mask;
 	unsigned long irq_probe_mask;
 	unsigned long iack_sc;
@@ -52,13 +55,19 @@
 
 	unsigned long (*mv_dense_mem)(unsigned long);
 
-	int (*pci_read_config_byte)(u8, u8, u8, u8 *value);
-	int (*pci_read_config_word)(u8, u8, u8, u16 *value);
-	int (*pci_read_config_dword)(u8, u8, u8, u32 *value);
-
-	int (*pci_write_config_byte)(u8, u8, u8, u8 value);
-	int (*pci_write_config_word)(u8, u8, u8, u16 value);
-	int (*pci_write_config_dword)(u8, u8, u8, u32 value);
+	int (*hose_read_config_byte)(u8, u8, u8, u8 *value,
+				     struct linux_hose_info *);
+	int (*hose_read_config_word)(u8, u8, u8, u16 *value,
+				     struct linux_hose_info *);
+	int (*hose_read_config_dword)(u8, u8, u8, u32 *value,
+				      struct linux_hose_info *);
+
+	int (*hose_write_config_byte)(u8, u8, u8, u8 value,
+				      struct linux_hose_info *);
+	int (*hose_write_config_word)(u8, u8, u8, u16 value,
+				      struct linux_hose_info *);
+	int (*hose_write_config_dword)(u8, u8, u8, u32 value,
+				       struct linux_hose_info *);
 	
 	void (*mv_get_mmu_context)(struct task_struct *);
 	void (*mv_flush_tlb_current)(struct mm_struct *);
diff -u --recursive --new-file v2.1.120/linux/include/asm-alpha/mmu_context.h linux/include/asm-alpha/mmu_context.h
--- v2.1.120/linux/include/asm-alpha/mmu_context.h	Tue Aug 18 22:02:07 1998
+++ linux/include/asm-alpha/mmu_context.h	Sun Sep  6 10:34:33 1998
@@ -35,14 +35,17 @@
  */
 #define EV4_MAX_ASN 63
 #define EV5_MAX_ASN 127
+#define EV6_MAX_ASN 255
 
 #ifdef CONFIG_ALPHA_GENERIC
 # define MAX_ASN	(alpha_mv.max_asn)
 #else
 # ifdef CONFIG_ALPHA_EV4
 #  define MAX_ASN	EV4_MAX_ASN
-# else
+# elif defined(CONFIG_ALPHA_EV5)
 #  define MAX_ASN	EV5_MAX_ASN
+# else
+#  define MAX_ASN	EV6_MAX_ASN
 # endif
 #endif
 
@@ -155,7 +158,8 @@
 	a0 = MASK_CONTEXT(tss);
 
 	__asm__ __volatile__(
-		"call_pal %2" : "=r"(v0), "=r"(a0)
+		"call_pal %2 #__reload_tss"
+		: "=r"(v0), "=r"(a0)
 		: "i"(PAL_swpctx), "r"(a0)
 		: "$1", "$16", "$22", "$23", "$24", "$25");
 
diff -u --recursive --new-file v2.1.120/linux/include/asm-alpha/page.h linux/include/asm-alpha/page.h
--- v2.1.120/linux/include/asm-alpha/page.h	Sun Jul 26 11:57:18 1998
+++ linux/include/asm-alpha/page.h	Sun Sep  6 10:34:33 1998
@@ -8,6 +8,8 @@
 
 #ifdef __KERNEL__
 
+#ifndef __ASSEMBLY__
+
 #define STRICT_MM_TYPECHECKS
 
 /*
@@ -102,12 +104,18 @@
 #define __pgd(x)	(x)
 #define __pgprot(x)	(x)
 
-#endif
+#endif /* STRICT_MM_TYPECHECKS */
+#endif /* !ASSEMBLY */
 
 /* to align the pointer to the (next) page boundary */
-#define PAGE_ALIGN(addr)		(((addr)+PAGE_SIZE-1)&PAGE_MASK)
+#define PAGE_ALIGN(addr)	(((addr)+PAGE_SIZE-1)&PAGE_MASK)
+
+#ifdef USE_48_BIT_KSEG
+#define PAGE_OFFSET		0xffff800000000000
+#else
+#define PAGE_OFFSET		0xfffffc0000000000
+#endif
 
-#define PAGE_OFFSET		0xFFFFFC0000000000UL
 #define __pa(x)			((unsigned long) (x) - PAGE_OFFSET)
 #define __va(x)			((void *)((unsigned long) (x) + PAGE_OFFSET))
 #define MAP_NR(addr)		(__pa(addr) >> PAGE_SHIFT)
diff -u --recursive --new-file v2.1.120/linux/include/asm-alpha/pgtable.h linux/include/asm-alpha/pgtable.h
--- v2.1.120/linux/include/asm-alpha/pgtable.h	Tue Aug 18 22:02:07 1998
+++ linux/include/asm-alpha/pgtable.h	Sun Sep  6 10:34:33 1998
@@ -311,7 +311,7 @@
 
 #define BAD_PAGETABLE	__bad_pagetable()
 #define BAD_PAGE	__bad_page()
-#define ZERO_PAGE	0xfffffc000030A000
+#define ZERO_PAGE	(PAGE_OFFSET+0x30A000)
 
 /* number of bits that fit into a memory pointer */
 #define BITS_PER_PTR			(8*sizeof(unsigned long))
@@ -327,6 +327,24 @@
   ((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK)
 
 /*
+ * On certain platforms whose physical address space can overlap KSEG,
+ * namely EV6 and above, we must re-twiddle the physaddr to restore the
+ * correct high-order bits.
+ */
+
+#if defined(CONFIG_ALPHA_GENERIC) && defined(USE_48_BIT_KSEG)
+#error "EV6-only feature in a generic kernel"
+#endif
+#if defined(CONFIG_ALPHA_GENERIC) || \
+    (defined(CONFIG_ALPHA_EV6) && !defined(USE_48_BIT_KSEG))
+#define PHYS_TWIDDLE(phys) \
+  ((((phys) & 0xc0000000000UL) == 0x40000000000UL) \
+  ? ((phys) ^= 0xc0000000000UL) : (phys))
+#else
+#define PHYS_TWIDDLE(phys) (phys)
+#endif
+
+/*
  * Conversion functions:  convert a page and protection to a page entry,
  * and a page entry and page directory to the page they refer to.
  */
@@ -334,7 +352,7 @@
 { pte_t pte; pte_val(pte) = ((page-PAGE_OFFSET) << (32-PAGE_SHIFT)) | pgprot_val(pgprot); return pte; }
 
 extern inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot)
-{ pte_t pte; pte_val(pte) = (physpage << (32-PAGE_SHIFT)) | pgprot_val(pgprot); return pte; }
+{ pte_t pte; pte_val(pte) = (PHYS_TWIDDLE(physpage) << (32-PAGE_SHIFT)) | pgprot_val(pgprot); return pte; }
 
 extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 { pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; }
diff -u --recursive --new-file v2.1.120/linux/include/asm-alpha/processor.h linux/include/asm-alpha/processor.h
--- v2.1.120/linux/include/asm-alpha/processor.h	Tue Aug 18 22:02:07 1998
+++ linux/include/asm-alpha/processor.h	Sun Sep  6 10:34:33 1998
@@ -62,7 +62,7 @@
 	long debugreg[8];
 };
 
-#define INIT_MMAP { &init_mm, 0xfffffc0000000000,  0xfffffc0010000000, \
+#define INIT_MMAP { &init_mm, PAGE_OFFSET,  PAGE_OFFSET+0x10000000, \
 	PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
 
 #define INIT_TSS  { \
diff -u --recursive --new-file v2.1.120/linux/include/asm-alpha/smp.h linux/include/asm-alpha/smp.h
--- v2.1.120/linux/include/asm-alpha/smp.h	Thu Aug  6 14:06:33 1998
+++ linux/include/asm-alpha/smp.h	Sun Sep  6 10:34:33 1998
@@ -4,6 +4,7 @@
 #ifdef __SMP__
 
 #include <linux/tasks.h>
+#include <asm/pal.h>
 
 struct cpuinfo_alpha {
 	unsigned long loops_per_sec;
@@ -15,38 +16,28 @@
 
 extern struct cpuinfo_alpha cpu_data[NR_CPUS];
 
-typedef volatile struct {
-  unsigned int kernel_flag; /* 4 bytes, please */
-  unsigned int akp; /* 4 bytes, please */
-  unsigned long pc;
-  unsigned int cpu;
-} klock_info_t;
-
-extern klock_info_t klock_info;
-
-#define KLOCK_HELD	0xff
-#define KLOCK_CLEAR	0x00
-
-extern int task_lock_depth;
-
 #define PROC_CHANGE_PENALTY     20
 
 extern __volatile__ int cpu_number_map[NR_CPUS];
 
 /* HACK: Cabrio WHAMI return value is bogus if more than 8 bits used.. :-( */
-#define hard_smp_processor_id() \
-({ \
-	register unsigned char __r0 __asm__("$0"); \
-	__asm__ __volatile__( \
-		"call_pal %0" \
-		: /* no output (bound to the template) */ \
-		:"i" (PAL_whami) \
-		:"$0", "$1", "$22", "$23", "$24", "$25", "memory"); \
-	__r0; \
-})
 
-#define smp_processor_id()	hard_smp_processor_id()
+static __inline__ unsigned char hard_smp_processor_id(void)
+{
+	register unsigned char __r0 __asm__("$0");
+	__asm__ __volatile__(
+		"call_pal %1 #whami"
+		: "=r"(__r0)
+		:"i" (PAL_whami)
+		: "$1", "$22", "$23", "$24", "$25");
+	return __r0;
+}
+
+#define smp_processor_id()	(current->processor)
 #define cpu_logical_map(cpu)	(cpu)
+
+/* For the benefit of panic.  */
+void smp_message_pass(int target, int msg, unsigned long data, int wait);
 
 #endif /* __SMP__ */
 
diff -u --recursive --new-file v2.1.120/linux/include/asm-alpha/smplock.h linux/include/asm-alpha/smplock.h
--- v2.1.120/linux/include/asm-alpha/smplock.h	Mon Aug  3 17:48:27 1998
+++ linux/include/asm-alpha/smplock.h	Sun Sep  6 10:34:33 1998
@@ -3,6 +3,8 @@
  *
  * Default SMP lock implementation
  */
+
+#include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <asm/spinlock.h>
 
@@ -11,23 +13,22 @@
 /*
  * Release global kernel lock and global interrupt lock
  */
-#define release_kernel_lock(task, cpu) \
-do { \
-	if (task->lock_depth >= 0) \
-		spin_unlock(&kernel_flag); \
-	release_irqlock(cpu); \
-	__sti(); \
-} while (0)
+static __inline__ void release_kernel_lock(struct task_struct *task, int cpu)
+{
+	if (task->lock_depth >= 0)
+		spin_unlock(&kernel_flag);
+	release_irqlock(cpu);
+	__sti();
+}
 
 /*
  * Re-acquire the kernel lock
  */
-#define reacquire_kernel_lock(task) \
-do { \
-	if (task->lock_depth >= 0) \
-		spin_lock(&kernel_flag); \
-} while (0)
-
+static __inline__ void reacquire_kernel_lock(struct task_struct *task)
+{
+	if (task->lock_depth >= 0)
+		spin_lock(&kernel_flag);
+}
 
 /*
  * Getting the big kernel lock.
@@ -36,13 +37,13 @@
  * so we only need to worry about other
  * CPU's.
  */
-extern __inline__ void lock_kernel(void)
+static __inline__ void lock_kernel(void)
 {
 	if (!++current->lock_depth)
 		spin_lock(&kernel_flag);
 }
 
-extern __inline__ void unlock_kernel(void)
+static __inline__ void unlock_kernel(void)
 {
 	if (--current->lock_depth < 0)
 		spin_unlock(&kernel_flag);
diff -u --recursive --new-file v2.1.120/linux/include/asm-alpha/softirq.h linux/include/asm-alpha/softirq.h
--- v2.1.120/linux/include/asm-alpha/softirq.h	Wed Apr  1 20:11:53 1998
+++ linux/include/asm-alpha/softirq.h	Sun Sep  6 10:34:33 1998
@@ -1,6 +1,7 @@
 #ifndef _ALPHA_SOFTIRQ_H
 #define _ALPHA_SOFTIRQ_H
 
+#include <linux/stddef.h>
 #include <asm/atomic.h>
 #include <asm/hardirq.h>
 
diff -u --recursive --new-file v2.1.120/linux/include/asm-alpha/spinlock.h linux/include/asm-alpha/spinlock.h
--- v2.1.120/linux/include/asm-alpha/spinlock.h	Wed Apr  1 20:11:53 1998
+++ linux/include/asm-alpha/spinlock.h	Sun Sep  6 10:34:33 1998
@@ -1,22 +1,24 @@
 #ifndef _ALPHA_SPINLOCK_H
 #define _ALPHA_SPINLOCK_H
 
+#include <asm/system.h>
+
 #ifndef __SMP__
 
 /* gcc 2.7.2 can crash initializing an empty structure.  */
 typedef struct { int dummy; } spinlock_t;
 #define SPIN_LOCK_UNLOCKED { 0 }
 
-#define spin_lock_init(lock)			do { } while(0)
-#define spin_lock(lock)				do { } while(0)
-#define spin_trylock(lock)			do { } while(0)
-#define spin_unlock_wait(lock)			do { } while(0)
-#define spin_unlock(lock)			do { } while(0)
-#define spin_lock_irq(lock)			setipl(7)
-#define spin_unlock_irq(lock)			setipl(0)
+#define spin_lock_init(lock)			((void) 0)
+#define spin_lock(lock)				((void) 0)
+#define spin_trylock(lock)			((void) 0)
+#define spin_unlock_wait(lock)			((void) 0)
+#define spin_unlock(lock)			((void) 0)
+#define spin_lock_irq(lock)			cli()
+#define spin_unlock_irq(lock)			sti()
 
-#define spin_lock_irqsave(lock, flags)		do { (flags) = swpipl(7); } while (0)
-#define spin_unlock_irqrestore(lock, flags)	setipl(flags)
+#define spin_lock_irqsave(lock, flags)		save_and_cli(flags)
+#define spin_unlock_irqrestore(lock, flags)	restore_flags(flags)
 
 /*
  * Read-write spinlocks, allowing multiple readers
@@ -31,26 +33,30 @@
 typedef struct { int dummy; } rwlock_t;
 #define RW_LOCK_UNLOCKED { 0 }
 
-#define read_lock(lock)		do { } while(0)
-#define read_unlock(lock)	do { } while(0)
-#define write_lock(lock)	do { } while(0)
-#define write_unlock(lock)	do { } while(0)
-#define read_lock_irq(lock)	cli()
-#define read_unlock_irq(lock)	sti()
-#define write_lock_irq(lock)	cli()
-#define write_unlock_irq(lock)	sti()
-
-#define read_lock_irqsave(lock, flags)		do { (flags) = swpipl(7); } while (0)
-#define read_unlock_irqrestore(lock, flags)	setipl(flags)
-#define write_lock_irqsave(lock, flags)		do { (flags) = swpipl(7); } while (0)
-#define write_unlock_irqrestore(lock, flags)	setipl(flags)
+#define read_lock(lock)				((void) 0)
+#define read_unlock(lock)			((void) 0)
+#define write_lock(lock)			((void) 0)
+#define write_unlock(lock)			((void) 0)
+#define read_lock_irq(lock)			cli()
+#define read_unlock_irq(lock)			sti()
+#define write_lock_irq(lock)			cli()
+#define write_unlock_irq(lock)			sti()
+
+#define read_lock_irqsave(lock, flags)		save_and_cli(flags)
+#define read_unlock_irqrestore(lock, flags)	restore_flags(flags)
+#define write_lock_irqsave(lock, flags)		save_and_cli(flags)
+#define write_unlock_irqrestore(lock, flags)	restore_flags(flags)
 
 #else /* __SMP__ */
 
 #include <linux/kernel.h>
 #include <asm/current.h>
 
-/* Simple spin lock operations.  There are two variants, one clears IRQ's
+#define DEBUG_SPINLOCK 1
+#define DEBUG_RWLOCK 1
+
+/*
+ * Simple spin lock operations.  There are two variants, one clears IRQ's
  * on the local processor, one does not.
  *
  * We make no fairness assumptions. They have a cost.
@@ -58,34 +64,21 @@
 
 typedef struct {
 	volatile unsigned long lock;
-	unsigned long previous;
-	unsigned long task;
+	void *previous;
+	struct task_struct * task;
 } spinlock_t;
 
-#define SPIN_LOCK_UNLOCKED { 0, 0 }
+#define SPIN_LOCK_UNLOCKED { 0, 0, 0 }
 
 #define spin_lock_init(x) \
-	do { (x)->lock = 0; (x)->previous = 0; } while(0)
+	((x)->lock = 0, (x)->previous = 0, (x)->task = 0)
 #define spin_unlock_wait(x) \
-	do { barrier(); } while(((volatile spinlock_t *)x)->lock)
+	({ do { barrier(); } while(((volatile spinlock_t *)x)->lock); })
 
 typedef struct { unsigned long a[100]; } __dummy_lock_t;
 #define __dummy_lock(lock) (*(__dummy_lock_t *)(lock))
 
-static inline void spin_unlock(spinlock_t * lock)
-{
-	__asm__ __volatile__(
-	"mb; stq $31,%0"
-	:"=m" (__dummy_lock(lock)));
-}
-
-#if 1
-#define DEBUG_SPINLOCK
-#else
-#undef DEBUG_SPINLOCK
-#endif
-
-#ifdef DEBUG_SPINLOCK
+#if DEBUG_SPINLOCK
 extern void spin_lock(spinlock_t * lock);
 #else
 static inline void spin_lock(spinlock_t * lock)
@@ -101,94 +94,79 @@
 	"	or	%0,1,%0\n"
 	"	stq_c	%0,%1\n"
 	"	beq	%0,2f\n"
-	"4:	mb\n"
+	"	mb\n"
 	".section .text2,\"ax\"\n"
 	"2:	ldq	%0,%1\n"
 	"	blbs	%0,2b\n"
 	"	br	1b\n"
 	".previous"
-	: "=r" (tmp),
-	  "=m" (__dummy_lock(lock)));
+	: "=r" (tmp), "=m" (__dummy_lock(lock))
+	: "m"(__dummy_lock(lock)));
 }
 #endif /* DEBUG_SPINLOCK */
 
+static inline void spin_unlock(spinlock_t * lock)
+{
+	mb();
+	lock->lock = 0;
+}
+
 #define spin_trylock(lock) (!test_and_set_bit(0,(lock)))
 
 #define spin_lock_irq(lock) \
-	do { __cli(); spin_lock(lock); } while (0)
-
+  (__cli(), spin_lock(lock))
 #define spin_unlock_irq(lock) \
-	do { spin_unlock(lock); __sti(); } while (0)
-
+  (spin_unlock(lock), __sti())
 #define spin_lock_irqsave(lock, flags) \
-	do { __save_and_cli(flags); spin_lock(lock); } while (0)
-
+  (__save_and_cli(flags), spin_lock(lock))
 #define spin_unlock_irqrestore(lock, flags) \
-	do { spin_unlock(lock); __restore_flags(flags); } while (0)
+  (spin_unlock(lock), __restore_flags(flags))
 
 /***********************************************************/
 
-#if 1
-#define DEBUG_RWLOCK
-#else
-#undef DEBUG_RWLOCK
-#endif
-
 typedef struct { volatile int write_lock:1, read_counter:31; } rwlock_t;
 
 #define RW_LOCK_UNLOCKED { 0, 0 }
 
-#ifdef DEBUG_RWLOCK
+#if DEBUG_RWLOCK
 extern void write_lock(rwlock_t * lock);
+extern void read_lock(rwlock_t * lock);
 #else
 static inline void write_lock(rwlock_t * lock)
 {
-	long regx, regy;
+	long regx;
 
 	__asm__ __volatile__(
-	"1:	ldl_l	%1,%0;"
-	"	blbs	%1,6f;"
-	"	or	%1,1,%2;"
-	"	stl_c	%2,%0;"
-	"	beq	%2,6f;"
-	"	blt	%1,8f;"
-	"4:	mb\n"
+	"1:	ldl_l	%1,%0\n"
+	"	bne	%1,6f\n"
+	"	or	$31,1,%1\n"
+	"	stl_c	%1,%0\n"
+	"	beq	%1,6f\n"
+	"	mb\n"
 	".section .text2,\"ax\"\n"
-	"6:	ldl	%1,%0;"
-	"	blbs	%1,6b;"
-	"	br	1b;"
-	"8:	ldl	%1,%0;"
-	"	blt	%1,8b;"
-	"9:	br	4b\n"
+	"6:	ldl	%1,%0\n"
+	"	bne	%1,6b\n"
+	"	br	1b\n"
 	".previous"
-	: "=m" (__dummy_lock(lock)), "=&r" (regx), "=&r" (regy)
+	: "=m" (__dummy_lock(lock)), "=&r" (regx)
 	: "0" (__dummy_lock(lock))
 	);
 }
-#endif /* DEBUG_RWLOCK */
-
-static inline void write_unlock(rwlock_t * lock)
-{
-	__asm__ __volatile__("mb; stl $31,%0" : "=m" (__dummy_lock(lock)));
-}
 
-#ifdef DEBUG_RWLOCK
-extern void _read_lock(rwlock_t * lock);
-#else
-static inline void _read_lock(rwlock_t * lock)
+static inline void read_lock(rwlock_t * lock)
 {
 	long regx;
 
 	__asm__ __volatile__(
-	"1:	ldl_l	%1,%0;"
-	"	blbs	%1,6f;"
-	"	subl	%1,2,%1;"
-	"	stl_c	%1,%0;"
-	"	beq	%1,6f;"
+	"1:	ldl_l	%1,%0\n"
+	"	blbs	%1,6f\n"
+	"	subl	%1,2,%1\n"
+	"	stl_c	%1,%0\n"
+	"	beq	%1,6f\n"
 	"4:	mb\n"
 	".section .text2,\"ax\"\n"
-	"6:	ldl	%1,%0;"
-	"	blbs	%1,6b;"
+	"6:	ldl	%1,%0\n"
+	"	blbs	%1,6b\n"
 	"	br	1b\n"
 	".previous"
 	: "=m" (__dummy_lock(lock)), "=&r" (regx)
@@ -197,21 +175,20 @@
 }
 #endif /* DEBUG_RWLOCK */
 
-#define read_lock(lock) \
-do {	unsigned long flags; \
-	__save_and_cli(flags); \
-	_read_lock(lock); \
-	__restore_flags(flags); \
-} while(0)
+static inline void write_unlock(rwlock_t * lock)
+{
+	mb();
+	*(volatile int *)lock = 0;
+}
 
-static inline void _read_unlock(rwlock_t * lock)
+static inline void read_unlock(rwlock_t * lock)
 {
 	long regx;
 	__asm__ __volatile__(
-	"1:	ldl_l	%1,%0;"
-	"	addl	%1,2,%1;"
-	"	stl_c	%1,%0;"
-	"	beq	%1,6f;"
+	"1:	ldl_l	%1,%0\n"
+	"	addl	%1,2,%1\n"
+	"	stl_c	%1,%0\n"
+	"	beq	%1,6f\n"
 	".section .text2,\"ax\"\n"
 	"6:	br	1b\n"
 	".previous"
@@ -219,26 +196,19 @@
 	: "0" (__dummy_lock(lock)));
 }
 
-#define read_unlock(lock) \
-do {	unsigned long flags; \
-	__save_and_cli(flags); \
-	_read_unlock(lock); \
-	__restore_flags(flags); \
-} while(0)
-
-#define read_lock_irq(lock)	do { __cli(); _read_lock(lock); } while (0)
-#define read_unlock_irq(lock)	do { _read_unlock(lock); __sti(); } while (0)
-#define write_lock_irq(lock)	do { __cli(); write_lock(lock); } while (0)
-#define write_unlock_irq(lock)	do { write_unlock(lock); __sti(); } while (0)
+#define read_lock_irq(lock)	(__cli(), read_lock(lock))
+#define read_unlock_irq(lock)	(read_unlock(lock), __sti())
+#define write_lock_irq(lock)	(__cli(), write_lock(lock))
+#define write_unlock_irq(lock)	(write_unlock(lock), __sti())
 
 #define read_lock_irqsave(lock, flags)	\
-	do { __save_and_cli(flags); _read_lock(lock); } while (0)
+	(__save_and_cli(flags), read_lock(lock))
 #define read_unlock_irqrestore(lock, flags) \
-	do { _read_unlock(lock); __restore_flags(flags); } while (0)
+	(read_unlock(lock), __restore_flags(flags))
 #define write_lock_irqsave(lock, flags)	\
-	do { __save_and_cli(flags); write_lock(lock); } while (0)
+	(__save_and_cli(flags), write_lock(lock))
 #define write_unlock_irqrestore(lock, flags) \
-	do { write_unlock(lock); __restore_flags(flags); } while (0)
+	(write_unlock(lock), __restore_flags(flags))
 
 #endif /* SMP */
 #endif /* _ALPHA_SPINLOCK_H */
diff -u --recursive --new-file v2.1.120/linux/include/asm-alpha/system.h linux/include/asm-alpha/system.h
--- v2.1.120/linux/include/asm-alpha/system.h	Tue Aug 18 22:02:07 1998
+++ linux/include/asm-alpha/system.h	Sun Sep  6 10:34:33 1998
@@ -1,7 +1,8 @@
 #ifndef __ALPHA_SYSTEM_H
 #define __ALPHA_SYSTEM_H
 
-#include <asm/pal.h>	/* for backwards compatibility... */
+#include <asm/pal.h>
+#include <asm/page.h>
 
 /*
  * System defines.. Note that this is included both from .c and .S
@@ -13,23 +14,21 @@
  * the initial process structure. Also, the console eats 3 MB for
  * the initial bootloader (one of which we can reclaim later).
  * With a few other pages for various reasons, we'll use an initial
- * load address of 0xfffffc0000310000UL
+ * load address of PAGE_OFFSET+0x310000UL
  */
 #define BOOT_PCB	0x20000000
 #define BOOT_ADDR	0x20000000
 /* Remove when official MILO sources have ELF support: */
 #define BOOT_SIZE	(16*1024)
 
-#define KERNEL_START	0xfffffc0000300000
-#define SWAPPER_PGD	0xfffffc0000300000
-#define INIT_STACK	0xfffffc0000302000
-#define EMPTY_PGT	0xfffffc0000304000
-#define EMPTY_PGE	0xfffffc0000308000
-#define ZERO_PGE	0xfffffc000030A000
+#define KERNEL_START	(PAGE_OFFSET+0x300000)
+#define SWAPPER_PGD	(PAGE_OFFSET+0x300000)
+#define INIT_STACK	(PAGE_OFFSET+0x302000)
+#define EMPTY_PGT	(PAGE_OFFSET+0x304000)
+#define EMPTY_PGE	(PAGE_OFFSET+0x308000)
+#define ZERO_PGE	(PAGE_OFFSET+0x30A000)
 
-#define START_ADDR	0xfffffc0000310000
-/* Remove when official MILO sources have ELF support: */
-#define START_SIZE	(2*1024*1024)
+#define START_ADDR	(PAGE_OFFSET+0x310000)
 
 #ifndef __ASSEMBLY__
 
@@ -96,11 +95,12 @@
 extern unsigned long whami(void);
 extern void wripir(unsigned long);
 
-#define halt() __asm__ __volatile__ ("call_pal %0" : : "i" (PAL_halt) : "memory")
+#define halt() \
+__asm__ __volatile__ ("call_pal %0 #halt" : : "i" (PAL_halt) : "memory")
 
-#define switch_to(prev,next) do { \
-	current = next; \
-	alpha_switch_to((unsigned long) &current->tss - IDENT_ADDR); \
+#define switch_to(prev,next) do {					\
+	current = next;							\
+	alpha_switch_to((unsigned long) &current->tss - IDENT_ADDR);	\
 } while (0)
 
 extern void alpha_switch_to(unsigned long pctxp);
@@ -112,127 +112,101 @@
 __asm__ __volatile__("wmb": : :"memory")
 
 #define imb() \
-__asm__ __volatile__ ("call_pal %0" : : "i" (PAL_imb) : "memory")
+__asm__ __volatile__ ("call_pal %0 #imb" : : "i" (PAL_imb) : "memory")
 
 #define draina() \
-__asm__ __volatile__ ("call_pal %0" : : "i" (PAL_draina) : "memory")
+__asm__ __volatile__ ("call_pal %0 #draina" : : "i" (PAL_draina) : "memory")
 
-#define call_pal1(palno,arg) \
-({ \
-	register unsigned long __r0 __asm__("$0"); \
-	register unsigned long __r16 __asm__("$16"); __r16 = arg; \
-	__asm__ __volatile__( \
-		"call_pal %3" \
-		:"=r" (__r0),"=r" (__r16) \
-		:"1" (__r16),"i" (palno) \
-		:"$1", "$22", "$23", "$24", "$25", "memory"); \
-	__r0; \
+#define call_pal1(palno,arg)						\
+({									\
+	register unsigned long __r0 __asm__("$0");			\
+	register unsigned long __r16 __asm__("$16"); __r16 = arg;	\
+	__asm__ __volatile__(						\
+		"call_pal %3 #call_pal1"				\
+		:"=r" (__r0),"=r" (__r16)				\
+		:"1" (__r16),"i" (palno)				\
+		:"$1", "$22", "$23", "$24", "$25", "memory");		\
+	__r0;								\
 })
 
-#define getipl() \
-({ \
-	register unsigned long r0 __asm__("$0"); \
-	__asm__ __volatile__( \
-		"call_pal %1" \
-		:"=r" (r0) \
-		:"i" (PAL_rdps) \
-		:"$1", "$16", "$22", "$23", "$24", "$25", "memory"); \
-	r0; \
+#define getipl()							\
+({									\
+	register unsigned long r0 __asm__("$0");			\
+	__asm__ __volatile__(						\
+		"call_pal %1 #getipl"					\
+		:"=r" (r0)						\
+		:"i" (PAL_rdps)						\
+		:"$1", "$16", "$22", "$23", "$24", "$25", "memory");	\
+	r0;								\
 })
 
-#ifdef THE_OLD_VERSION
-#define setipl(ipl) \
-do { \
-	register unsigned long __r16 __asm__("$16") = (ipl); \
-	__asm__ __volatile__( \
-		"call_pal %2" \
-		:"=r" (__r16) \
-		:"0" (__r16),"i" (PAL_swpipl) \
-		:"$0", "$1", "$22", "$23", "$24", "$25", "memory"); \
-} while (0)
-
-#define swpipl(ipl) \
-({ \
-	register unsigned long __r0 __asm__("$0"); \
-	register unsigned long __r16 __asm__("$16") = (ipl); \
-	__asm__ __volatile__( \
-		"call_pal %3" \
-		:"=r" (__r0),"=r" (__r16) \
-		:"1" (__r16),"i" (PAL_swpipl) \
-		:"$1", "$22", "$23", "$24", "$25", "memory"); \
-	__r0; \
+#define setipl(ipl)							\
+({									\
+	register unsigned long __r16 __asm__("$16"); __r16 = (ipl);	\
+	__asm__ __volatile__(						\
+		"call_pal %2 #setipl"					\
+		:"=r" (__r16)						\
+		:"0" (__r16),"i" (PAL_swpipl)				\
+		:"$0", "$1", "$22", "$23", "$24", "$25", "memory");	\
 })
-#else
-#define setipl(ipl) \
-do { \
-	__asm__ __volatile__( \
-		"mov %0,$16; call_pal %1" \
-		: /* no output */ \
-		:"i,r" (ipl), "i,i" (PAL_swpipl) \
-		:"$0", "$1", "$16", "$22", "$23", "$24", "$25", "memory"); \
-} while (0)
 
-#define swpipl(ipl) \
-({ \
-	register unsigned long __r0 __asm__("$0"); \
-	__asm__ __volatile__( \
-		"mov %0,$16; call_pal %1" \
-		: /* no output (bound to the template) */ \
-		: "i,r" (ipl), "i,i" (PAL_swpipl) \
-		: "$0", "$1", "$16", "$22", "$23", "$24", "$25", "memory"); \
-	__r0; \
+#define swpipl(ipl)						\
+({								\
+	register unsigned long __r0 __asm__("$0");		\
+	register unsigned long __r16 __asm__("$16") = (ipl);	\
+	__asm__ __volatile__(					\
+		"call_pal %3 #swpipl"				\
+		:"=r" (__r0),"=r" (__r16)			\
+		:"1" (__r16),"i" (PAL_swpipl)			\
+		:"$1", "$22", "$23", "$24", "$25", "memory");	\
+	__r0;							\
 })
-#endif
 
 #define __cli()			setipl(7)
 #define __sti()			setipl(0)
-#define __save_flags(flags)	do { (flags) = getipl(); } while (0)
-#define __save_and_cli(flags)	do { (flags) = swpipl(7); } while (0)
+#define __save_flags(flags)	((flags) = getipl())
+#define __save_and_cli(flags)	((flags) = swpipl(7))
 #define __restore_flags(flags)	setipl(flags)
 
 #ifdef __SMP__
 
-extern unsigned char global_irq_holder;
-
-#define save_flags(x) \
-do { \
-	(x) = ((global_irq_holder == (unsigned char) smp_processor_id()) \
-		? 1 \
-		: ((getipl() & 7) ? 2 : 0)); \
-} while (0)
+extern int global_irq_holder;
 
-#define save_and_cli(flags)   do { save_flags(flags); cli(); } while(0)
+#define save_and_cli(flags)     (save_flags(flags), cli())
 
 extern void __global_cli(void);
 extern void __global_sti(void);
+extern unsigned long __global_save_flags(void);
 extern void __global_restore_flags(unsigned long flags);
 
 #define cli()                   __global_cli()
 #define sti()                   __global_sti()
+#define save_flags(flags)	((flags) = __global_save_flags())
 #define restore_flags(flags)    __global_restore_flags(flags)
 
 #else /* __SMP__ */
 
-#define cli()			setipl(7)
-#define sti()			setipl(0)
-#define save_flags(flags)	do { (flags) = getipl(); } while (0)
-#define save_and_cli(flags)	do { (flags) = swpipl(7); } while (0)
-#define restore_flags(flags)	setipl(flags)
+#define cli()			__cli()
+#define sti()			__sti()
+#define save_flags(flags)	__save_flags(flags)
+#define save_and_cli(flags)	__save_and_cli(flags)
+#define restore_flags(flags)	__restore_flags(flags)
 
 #endif /* __SMP__ */
 
 /*
  * TB routines..
  */
-#define __tbi(nr,arg,arg1...) do { \
-	register unsigned long __r16 __asm__("$16") = (nr); \
-	register unsigned long __r17 __asm__("$17"); arg; \
-	__asm__ __volatile__( \
-		"call_pal %3" \
-		:"=r" (__r16),"=r" (__r17) \
-		:"0" (__r16),"i" (PAL_tbi) ,##arg1 \
-		:"$0", "$1", "$22", "$23", "$24", "$25"); \
-} while (0)
+#define __tbi(nr,arg,arg1...)					\
+({								\
+	register unsigned long __r16 __asm__("$16") = (nr);	\
+	register unsigned long __r17 __asm__("$17"); arg;	\
+	__asm__ __volatile__(					\
+		"call_pal %3 #__tbi"				\
+		:"=r" (__r16),"=r" (__r17)			\
+		:"0" (__r16),"i" (PAL_tbi) ,##arg1		\
+		:"$0", "$1", "$22", "$23", "$24", "$25");	\
+})
 
 #define tbi(x,y)	__tbi(x,__r17=(y),"1" (__r17))
 #define tbisi(x)	__tbi(1,__r17=(x),"1" (__r17))
@@ -244,10 +218,10 @@
 /*
  * Give prototypes to shut up gcc.
  */
-extern __inline__ unsigned long xchg_u32 (volatile int * m, unsigned long val);
-extern __inline__ unsigned long xchg_u64 (volatile long * m, unsigned long val);
+extern __inline__ unsigned long xchg_u32(volatile int *m, unsigned long val);
+extern __inline__ unsigned long xchg_u64(volatile long *m, unsigned long val);
 
-extern __inline__ unsigned long xchg_u32(volatile int * m, unsigned long val)
+extern __inline__ unsigned long xchg_u32(volatile int *m, unsigned long val)
 {
 	unsigned long dummy;
 
@@ -283,9 +257,6 @@
 	return val;
 }
 
-#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
-#define tas(ptr) (xchg((ptr),1))
-
 /*
  * This function doesn't exist, so you'll get a linker error
  * if something tries to do an invalid xchg().
@@ -296,7 +267,8 @@
  */
 extern void __xchg_called_with_bad_pointer(void);
 
-static __inline__ unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
+static __inline__ unsigned long
+__xchg(unsigned long x, volatile void * ptr, int size)
 {
 	switch (size) {
 		case 4:
@@ -307,6 +279,10 @@
 	__xchg_called_with_bad_pointer();
 	return x;
 }
+
+#define xchg(ptr,x) \
+  ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
+#define tas(ptr) (xchg((ptr),1))
 
 #endif /* __ASSEMBLY__ */
 
diff -u --recursive --new-file v2.1.120/linux/include/asm-alpha/unistd.h linux/include/asm-alpha/unistd.h
--- v2.1.120/linux/include/asm-alpha/unistd.h	Tue Jun 23 10:01:25 1998
+++ linux/include/asm-alpha/unistd.h	Sun Sep  6 13:06:04 1998
@@ -23,7 +23,7 @@
 #define __NR_lseek		 19
 #define __NR_getxpid		 20
 #define __NR_osf_mount		 21
-#define __NR_osf_umount		 22
+#define __NR_umount		 22
 #define __NR_setuid		 23
 #define __NR_getxuid		 24
 #define __NR_exec_with_loader	 25	/* not implemented */
@@ -258,7 +258,7 @@
 #define __NR_sysinfo		318
 #define __NR__sysctl		319
 #define __NR_idle		320
-#define __NR_umount		321
+#define __NR_oldumount		321
 #define __NR_swapon		322
 #define __NR_times		323
 #define __NR_personality	324
@@ -506,12 +506,6 @@
 static inline void idle(void)
 {
 	sys_idle();
-}
-
-extern int sys_setup(int);
-static inline int setup(int magic)
-{
-	return sys_setup(magic);
 }
 
 extern int sys_open(const char *, int, int);
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/arch-arc/irq.h linux/include/asm-arm/arch-arc/irq.h
--- v2.1.120/linux/include/asm-arm/arch-arc/irq.h	Tue Apr 14 14:29:25 1998
+++ linux/include/asm-arm/arch-arc/irq.h	Sun Sep  6 10:45:30 1998
@@ -8,123 +8,138 @@
  *   10-10-1996	RMK	Brought up to date with arch-sa110eval
  *   22-10-1996	RMK	Changed interrupt numbers & uses new inb/outb macros
  *   11-01-1998	RMK	Added mask_and_ack_irq
+ *   22-08-1998	RMK	Restructured IRQ routines
  */
 
-#define BUILD_IRQ(s,n,m) \
-	void IRQ##n##_interrupt(void); \
-	void fast_IRQ##n##_interrupt(void); \
-	void bad_IRQ##n##_interrupt(void); \
-	void probe_IRQ##n##_interrupt(void);
+static void arc_mask_irq_ack_a(unsigned int irq)
+{
+	unsigned int temp;
 
-/*
- * The timer is a special interrupt
- */
-#define IRQ5_interrupt		timer_IRQ_interrupt
+	__asm__ __volatile__(
+	"ldrb	%0, [%2]\n"
+"	bic	%0, %0, %1\n"
+"	strb	%0, [%2]\n"
+"	strb	%1, [%3]"
+	: "=&r" (temp)
+	: "r" (1 << (irq & 7)), "r" (ioaddr(IOC_IRQMASKA)),
+	  "r" (ioaddr(IOC_IRQCLRA)));
+}
 
-#define IRQ_INTERRUPT(n)	IRQ##n##_interrupt
-#define FAST_INTERRUPT(n)	fast_IRQ##n##_interrupt
-#define BAD_INTERRUPT(n)	bad_IRQ##n##_interrupt
-#define PROBE_INTERRUPT(n)	probe_IRQ##n##_interrupt
-
-#define X(x) (x)|0x01, (x)|0x02, (x)|0x04, (x)|0x08, (x)|0x10, (x)|0x20, (x)|0x40, (x)|0x80
-#define Z(x) (x), (x), (x), (x), (x), (x), (x), (x)
-
-static __inline__ void mask_and_ack_irq(unsigned int irq)
-{
-	static const int addrmasks[] = {
-		X((IOC_IRQMASKA - IOC_BASE)<<18 | (1 << 15)),
-		X((IOC_IRQMASKB - IOC_BASE)<<18),
-		Z(0),
-		Z(0),
-		Z(0),
-		Z(0),
-		Z(0),
-		Z(0),
-		X((IOC_FIQMASK - IOC_BASE)<<18),
-		Z(0),
-		Z(0),
-		Z(0),
-		Z(0),
-		Z(0),
-		Z(0),
-		Z(0)
-	};
-	unsigned int temp1, temp2;
-
-	__asm__ __volatile__(
-"	ldr	%1, [%5, %3, lsl #2]\n"
-"	teq	%1, #0\n"
-"	beq	2f\n"
-"	ldrb	%0, [%2, %1, lsr #16]\n"
+static void arc_mask_irq_a(unsigned int irq)
+{
+	unsigned int temp;
+
+	__asm__ __volatile__(
+	"ldrb	%0, [%2]\n"
 "	bic	%0, %0, %1\n"
-"	strb	%0, [%2, %1, lsr #16]\n"
-"	tst	%1, #0x8000\n"			/* do we need an IRQ clear? */
-"	strneb	%1, [%2, %4]\n"
-"2:"
-	: "=&r" (temp1), "=&r" (temp2)
-	: "r" (ioaddr(IOC_BASE)), "r" (irq),
-	  "I" ((IOC_IRQCLRA - IOC_BASE) << 2), "r" (addrmasks));
-}
-
-#undef X
-#undef Z
-
-static __inline__ void mask_irq(unsigned int irq)
-{
-	extern void ecard_disableirq (unsigned int);
-	extern void ecard_disablefiq (unsigned int);
-	unsigned char mask = 1 << (irq & 7);
-
-	switch (irq >> 3) {
-	case 0:
-		outb(inb(IOC_IRQMASKA) & ~mask, IOC_IRQMASKA);
-		break;
-	case 1:
-		outb(inb(IOC_IRQMASKB) & ~mask, IOC_IRQMASKB);
-		break;
-	case 4:
-		ecard_disableirq (irq & 7);
-		break;
-	case 8:
-		outb(inb(IOC_FIQMASK) & ~mask, IOC_FIQMASK);
-		break;
-	case 12:
-		ecard_disablefiq (irq & 7);
-	}
+"	strb	%0, [%2]"
+	: "=&r" (temp)
+	: "r" (1 << (irq & 7)), "r" (ioaddr(IOC_IRQMASKA)));
 }
 
-static __inline__ void unmask_irq(unsigned int irq)
+static void arc_unmask_irq_a(unsigned int irq)
 {
-	extern void ecard_enableirq (unsigned int);
-	extern void ecard_enablefiq (unsigned int);
-	unsigned char mask = 1 << (irq & 7);
-
-	switch (irq >> 3) {
-	case 0:
-		outb(inb(IOC_IRQMASKA) | mask, IOC_IRQMASKA);
-		break;
-	case 1:
-		outb(inb(IOC_IRQMASKB) | mask, IOC_IRQMASKB);
-		break;
-	case 4:
-		ecard_enableirq (irq & 7);
-		break;
-	case 8:
-		outb(inb(IOC_FIQMASK) | mask, IOC_FIQMASK);
-		break;
-	case 12:
-		ecard_enablefiq (irq & 7);
-	}
+	unsigned int temp;
+
+	__asm__ __volatile__(
+	"ldrb	%0, [%2]\n"
+"	orr	%0, %0, %1\n"
+"	strb	%0, [%2]"
+	: "=&r" (temp)
+	: "r" (1 << (irq & 7)), "r" (ioaddr(IOC_IRQMASKA)));
+}
+
+static void arc_mask_irq_b(unsigned int irq)
+{
+	unsigned int temp;
+
+	__asm__ __volatile__(
+	"ldrb	%0, [%2]\n"
+"	bic	%0, %0, %1\n"
+"	strb	%0, [%2]"
+	: "=&r" (temp)
+	: "r" (1 << (irq & 7)), "r" (ioaddr(IOC_IRQMASKB)));
 }
 
-static __inline__ unsigned long get_enabled_irqs(void)
+static void arc_unmask_irq_b(unsigned int irq)
 {
-	return inb(IOC_IRQMASKA) | inb(IOC_IRQMASKB) << 8;
+	unsigned int temp;
+
+	__asm__ __volatile__(
+	"ldrb	%0, [%2]\n"
+"	orr	%0, %0, %1\n"
+"	strb	%0, [%2]"
+	: "=&r" (temp)
+	: "r" (1 << (irq & 7)), "r" (ioaddr(IOC_IRQMASKB)));
+}
+
+static void arc_mask_irq_fiq(unsigned int irq)
+{
+	unsigned int temp;
+
+	__asm__ __volatile__(
+	"ldrb	%0, [%2]\n"
+"	bic	%0, %0, %1\n"
+"	strb	%0, [%2]"
+	: "=&r" (temp)
+	: "r" (1 << (irq & 7)), "r" (ioaddr(IOC_FIQMASK)));
+}
+
+static void arc_unmask_irq_fiq(unsigned int irq)
+{
+	unsigned int temp;
+
+	__asm__ __volatile__(
+	"ldrb	%0, [%2]\n"
+"	orr	%0, %0, %1\n"
+"	strb	%0, [%2]"
+	: "=&r" (temp)
+	: "r" (1 << (irq & 7)), "r" (ioaddr(IOC_FIQMASK)));
 }
 
 static __inline__ void irq_init_irq(void)
 {
+	extern void ecard_disableirq(unsigned int irq);
+	extern void ecard_enableirq(unsigned int irq);
+	int irq;
+
 	outb(0, IOC_IRQMASKA);
 	outb(0, IOC_IRQMASKB);
 	outb(0, IOC_FIQMASK);
+
+	for (irq = 0; irq < NR_IRQS; irq++) {
+		switch (irq & 0xf8) {
+		case 0 ... 6:
+			irq_desc[irq].probe_ok = 1;
+		case 7:
+			irq_desc[irq].valid    = 1;
+			irq_desc[irq].mask_ack = arc_mask_irq_ack_a;
+			irq_desc[irq].mask     = arc_mask_irq_a;
+			irq_desc[irq].unmask   = arc_unmask_irq_a;
+			break;
+
+		case 9 ... 15:
+			irq_desc[irq].probe_ok = 1;
+		case 8:
+			irq_desc[irq].valid    = 1;
+			irq_desc[irq].mask_ack = arc_mask_irq_b;
+			irq_desc[irq].mask     = arc_mask_irq_b;
+			irq_desc[irq].unmask   = arc_unmask_irq_b;
+			break;
+
+		case 32 ... 40:
+			irq_desc[irq].valid    = 1;
+			irq_desc[irq].mask_ack = ecard_disableirq;
+			irq_desc[irq].mask     = ecard_disableirq;
+			irq_desc[irq].unmask   = ecard_enableirq;
+			break;
+
+		case 64 ... 72:
+			irq_desc[irq].valid    = 1;
+			irq_desc[irq].mask_ack = arc_mask_irq_fiq;
+			irq_desc[irq].mask     = arc_mask_irq_fiq;
+			irq_desc[irq].unmask   = arc_unmask_irq_fiq;
+			break;
+		}
+	}
 }
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/arch-arc/uncompress.h linux/include/asm-arm/arch-arc/uncompress.h
--- v2.1.120/linux/include/asm-arm/arch-arc/uncompress.h	Fri May  8 23:14:54 1998
+++ linux/include/asm-arm/arch-arc/uncompress.h	Sun Sep  6 10:45:30 1998
@@ -102,3 +102,8 @@
 
 	if (params->nr_pages * params->page_size < 4096*1024) error("<4M of mem\n");
 }
+
+/*
+ * nothing to do
+ */
+#define arch_decomp_wdog()
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/arch-ebsa110/irq.h linux/include/asm-arm/arch-ebsa110/irq.h
--- v2.1.120/linux/include/asm-arm/arch-ebsa110/irq.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-ebsa110/irq.h	Sun Sep  6 10:45:30 1998
@@ -1,39 +1,35 @@
 /*
  * include/asm-arm/arch-ebsa110/irq.h
  *
- * Copyright (C) 1996,1997,1998 Russell King
+ * Copyright (C) 1996-1998 Russell King
+ *
+ * Changelog:
+ *   22-08-1998	RMK	Restructured IRQ routines
  */
 
 #define IRQ_MCLR	((volatile unsigned char *)0xf3000000)
 #define IRQ_MSET	((volatile unsigned char *)0xf2c00000)
 #define IRQ_MASK	((volatile unsigned char *)0xf2c00000)
 
-static __inline__ void mask_and_ack_irq(unsigned int irq)
+static void ebsa110_mask_and_ack_irq(unsigned int irq)
 {
-	if (irq < 8)
-		*IRQ_MCLR = 1 << irq;
+	*IRQ_MCLR = 1 << irq;
 }
 
-static __inline__ void mask_irq(unsigned int irq)
+static void ebsa110_mask_irq(unsigned int irq)
 {
-	if (irq < 8)
-		*IRQ_MCLR = 1 << irq;
+	*IRQ_MCLR = 1 << irq;
 }
 
-static __inline__ void unmask_irq(unsigned int irq)
+static void ebsa110_unmask_irq(unsigned int irq)
 {
-	if (irq < 8)
-		*IRQ_MSET = 1 << irq;
+	*IRQ_MSET = 1 << irq;
 }
  
-static __inline__ unsigned long get_enabled_irqs(void)
-{
-	return 0;
-}
-
 static __inline__ void irq_init_irq(void)
 {
 	unsigned long flags;
+	int irq;
 
 	save_flags_cli (flags);
 	*IRQ_MCLR = 0xff;
@@ -43,4 +39,12 @@
 		while (1);
 	*IRQ_MCLR = 0xff;		/* clear all interrupt enables */
 	restore_flags (flags);
+
+	for (irq = 0; irq < NR_IRQS; irq++) {
+		irq_desc[irq].valid	= 1;
+		irq_desc[irq].probe_ok	= 1;
+		irq_desc[irq].mask_ack	= ebsa110_mask_and_ack_irq;
+		irq_desc[irq].mask	= ebsa110_mask_irq;
+		irq_desc[irq].unmask	= ebsa110_unmask_irq;
+	}
 }
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/arch-ebsa110/irqs.h linux/include/asm-arm/arch-ebsa110/irqs.h
--- v2.1.120/linux/include/asm-arm/arch-ebsa110/irqs.h	Fri May  8 23:14:54 1998
+++ linux/include/asm-arm/arch-ebsa110/irqs.h	Sun Sep  6 10:45:30 1998
@@ -4,16 +4,13 @@
  * Copyright (C) 1996 Russell King
  */
 
-#define IRQ_PRINTER		0
-#define IRQ_COM1		1
-#define IRQ_COM2		2
-#define IRQ_ETHERNET		3
-#define IRQ_TIMER0		4
-#define IRQ_TIMER1		5
-#define IRQ_PCMCIA		6
-#define IRQ_IMMEDIATE		7
-
-#define IRQ_TIMER		IRQ_TIMER0
-
-#define irq_cannonicalize(i)	(i)
+#define NR_IRQS			8
 
+#define IRQ_EBSA110_PRINTER	0
+#define IRQ_EBSA110_COM1	1
+#define IRQ_EBSA110_COM2	2
+#define IRQ_EBSA110_ETHERNET	3
+#define IRQ_EBSA110_TIMER0	4
+#define IRQ_EBSA110_TIMER1	5
+#define IRQ_EBSA110_PCMCIA	6
+#define IRQ_EBSA110_IMMEDIATE	7
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/arch-ebsa110/mm-init.h linux/include/asm-arm/arch-ebsa110/mm-init.h
--- v2.1.120/linux/include/asm-arm/arch-ebsa110/mm-init.h	Tue Apr 14 14:29:25 1998
+++ linux/include/asm-arm/arch-ebsa110/mm-init.h	Sun Sep  6 10:45:30 1998
@@ -3,4 +3,3 @@
  *
  * Copyright (C) 1996,1997,1998 Russell King
  */
-
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/arch-ebsa110/mmu.h linux/include/asm-arm/arch-ebsa110/mmu.h
--- v2.1.120/linux/include/asm-arm/arch-ebsa110/mmu.h	Tue Apr 14 14:29:25 1998
+++ linux/include/asm-arm/arch-ebsa110/mmu.h	Sun Sep  6 10:45:30 1998
@@ -10,9 +10,6 @@
 #ifndef __ASM_ARCH_MMU_H
 #define __ASM_ARCH_MMU_H
 
-/*
- * On ebsa, the dram is contiguous
- */
 #define __virt_to_phys__is_a_macro
 #define __virt_to_phys(vpage) ((vpage) - PAGE_OFFSET)
 #define __phys_to_virt__is_a_macro
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/arch-ebsa110/param.h linux/include/asm-arm/arch-ebsa110/param.h
--- v2.1.120/linux/include/asm-arm/arch-ebsa110/param.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-ebsa110/param.h	Sun Sep  6 10:45:30 1998
@@ -0,0 +1,8 @@
+/*
+ * linux/include/asm-arm/arch-ebsa110/param.h
+ *
+ * Copyright (C) 1996 Russell King
+ * Copyright (C) 1998 Philip Blundell
+ */
+
+#define HZ 100
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/arch-ebsa110/system.h linux/include/asm-arm/arch-ebsa110/system.h
--- v2.1.120/linux/include/asm-arm/arch-ebsa110/system.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-ebsa110/system.h	Sun Sep  6 10:45:30 1998
@@ -1,7 +1,7 @@
 /*
  * linux/include/asm-arm/arch-ebsa110/system.h
  *
- * Copyright (c) 1996,1997,1998 Russell King.
+ * Copyright (c) 1996-1998 Russell King.
  */
 #ifndef __ASM_ARCH_SYSTEM_H
 #define __ASM_ARCH_SYSTEM_H
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/arch-ebsa110/time.h linux/include/asm-arm/arch-ebsa110/time.h
--- v2.1.120/linux/include/asm-arm/arch-ebsa110/time.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-ebsa110/time.h	Sun Sep  6 10:45:30 1998
@@ -7,9 +7,14 @@
  *
  * Changelog:
  *  10-Oct-1996	RMK	Created
- *  04-Dec-1997	RMK	Updated for new arch/arm/time.c
+ *  04-Dec-1997	RMK	Updated for new arch/arm/kernel/time.c
+ *  07-Aug-1998	RMK	Updated for arch/arm/kernel/leds.c
  */
 
+#include <asm/leds.h>
+
+#define IRQ_TIMER IRQ_EBSA110_TIMER0
+
 #define MCLK_47_8
 
 #if defined(MCLK_42_3)
@@ -49,7 +54,7 @@
 
 	if (--count == 0) {
 		count = 50;
-		*(volatile unsigned char *)0xf2400000 ^= 128;
+		leds_event(led_timer);
 	}
 
 	if (divisor == 0) {
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/arch-ebsa110/timex.h linux/include/asm-arm/arch-ebsa110/timex.h
--- v2.1.120/linux/include/asm-arm/arch-ebsa110/timex.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-ebsa110/timex.h	Sun Sep  6 10:45:30 1998
@@ -1,7 +1,7 @@
 /*
  * linux/include/asm-arm/arch-ebsa110/timex.h
  *
- * RiscPC architecture timex specifications
+ * EBSA110 architecture timex specifications
  *
  * Copyright (C) 1997, 1998 Russell King
  */
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/arch-ebsa110/uncompress.h linux/include/asm-arm/arch-ebsa110/uncompress.h
--- v2.1.120/linux/include/asm-arm/arch-ebsa110/uncompress.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-ebsa110/uncompress.h	Sun Sep  6 10:45:30 1998
@@ -31,3 +31,4 @@
  * nothing to do
  */
 #define arch_decomp_setup()
+#define arch_decomp_wdog()
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/arch-ebsa285/dma.h linux/include/asm-arm/arch-ebsa285/dma.h
--- v2.1.120/linux/include/asm-arm/arch-ebsa285/dma.h	Tue Apr 14 14:29:25 1998
+++ linux/include/asm-arm/arch-ebsa285/dma.h	Sun Sep  6 10:45:30 1998
@@ -1,29 +1,35 @@
 /*
- * linux/include/asm-arm/arch-ebsa110/dma.h
+ * linux/include/asm-arm/arch-ebsa285/dma.h
  *
- * Architecture DMA routes
+ * Architecture DMA routines
  *
- * Copyright (C) 1997.1998 Russell King
+ * Copyright (C) 1998 Russell King
+ * Copyright (C) 1998 Philip Blundell
  */
 #ifndef __ASM_ARCH_DMA_H
 #define __ASM_ARCH_DMA_H
 
 /*
  * This is the maximum DMA address that can be DMAd to.
- * There should not be more than (0xd0000000 - 0xc0000000)
- * bytes of RAM.
  */
-#define MAX_DMA_ADDRESS		0xd0000000
+#define MAX_DMA_ADDRESS		0xffffffff
 
 /*
  * DMA modes - we have two, IN and OUT
  */
-typedef enum {
-	DMA_MODE_READ,
-	DMA_MODE_WRITE
-} dmamode_t;
 
-#define MAX_DMA_CHANNELS	8
+typedef int dmamode_t;
+#define DMA_MODE_READ		0x44
+#define DMA_MODE_WRITE		0x48
 
-#endif /* _ASM_ARCH_DMA_H */
+/*
+ * The 21285 has two internal DMA channels; we call these 0 and 1.
+ * On CATS hardware we have an additional eight ISA dma channels
+ * numbered 2..9.
+ */
+#define MAX_DMA_CHANNELS	10
 
+#define DMA_ISA_BASE		2
+#define DMA_FLOPPY		(DMA_ISA_BASE + 2)
+
+#endif /* _ASM_ARCH_DMA_H */
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/arch-ebsa285/irq.h linux/include/asm-arm/arch-ebsa285/irq.h
--- v2.1.120/linux/include/asm-arm/arch-ebsa285/irq.h	Tue Apr 14 14:29:25 1998
+++ linux/include/asm-arm/arch-ebsa285/irq.h	Sun Sep  6 10:45:30 1998
@@ -1,34 +1,34 @@
 /*
- * include/asm-arm/arch-ebsa110/irq.h
+ * include/asm-arm/arch-ebsa285/irq.h
  *
- * Copyright (C) 1996,1997,1998 Russell King
+ * Copyright (C) 1996-1998 Russell King
+ *
+ * Changelog:
+ *   22-08-1998	RMK	Restructured IRQ routines
  */
 
-static __inline__ void mask_and_ack_irq(unsigned int irq)
+static void ebsa285_mask_irq(unsigned int irq)
 {
-	if (irq < 32)
-		*CSR_IRQ_DISABLE = 1 << irq;
+	*CSR_IRQ_DISABLE = 1 << irq;
 }
 
-static __inline__ void mask_irq(unsigned int irq)
+static void ebsa285_unmask_irq(unsigned int irq)
 {
-	if (irq < 32)
-		*CSR_IRQ_DISABLE = 1 << irq;
-}
-
-static __inline__ void unmask_irq(unsigned int irq)
-{
-	if (irq < 32)
-		*CSR_IRQ_ENABLE = 1 << irq;
+	*CSR_IRQ_ENABLE = 1 << irq;
 }
  
-static __inline__ unsigned long get_enabled_irqs(void)
-{
-	return 0;
-}
-
 static __inline__ void irq_init_irq(void)
 {
+	int irq;
+
 	*CSR_IRQ_DISABLE = -1;
 	*CSR_FIQ_DISABLE = -1;
+
+	for (irq = 0; irq < NR_IRQS; irq++) {
+		irq_desc[irq].valid	= 1;
+		irq_desc[irq].probe_ok	= 1;
+		irq_desc[irq].mask_ack	= ebsa285_mask_irq;
+		irq_desc[irq].mask	= ebsa285_mask_irq;
+		irq_desc[irq].unmask	= ebsa285_unmask_irq;
+	}
 }
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/arch-ebsa285/param.h linux/include/asm-arm/arch-ebsa285/param.h
--- v2.1.120/linux/include/asm-arm/arch-ebsa285/param.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-ebsa285/param.h	Sun Sep  6 10:45:30 1998
@@ -0,0 +1,8 @@
+/*
+ * linux/include/asm-arm/arch-ebsa285/param.h
+ *
+ * Copyright (C) 1996 Russell King
+ * Copyright (C) 1998 Philip Blundell
+ */
+
+#define HZ 100
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/arch-ebsa285/serial.h linux/include/asm-arm/arch-ebsa285/serial.h
--- v2.1.120/linux/include/asm-arm/arch-ebsa285/serial.h	Tue Jul 21 00:15:32 1998
+++ linux/include/asm-arm/arch-ebsa285/serial.h	Sun Sep  6 10:45:30 1998
@@ -38,4 +38,3 @@
 	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS13 */
 
 #endif
-
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/arch-ebsa285/uncompress.h linux/include/asm-arm/arch-ebsa285/uncompress.h
--- v2.1.120/linux/include/asm-arm/arch-ebsa285/uncompress.h	Tue Apr 14 14:29:25 1998
+++ linux/include/asm-arm/arch-ebsa285/uncompress.h	Sun Sep  6 10:45:30 1998
@@ -31,3 +31,4 @@
  * nothing to do
  */
 #define arch_decomp_setup()
+#define arch_decomp_wdog()
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/arch-nexuspci/irq.h linux/include/asm-arm/arch-nexuspci/irq.h
--- v2.1.120/linux/include/asm-arm/arch-nexuspci/irq.h	Tue Jul 21 00:15:32 1998
+++ linux/include/asm-arm/arch-nexuspci/irq.h	Sun Sep  6 10:45:30 1998
@@ -2,6 +2,9 @@
  * include/asm-arm/arch-nexuspci/irq.h
  *
  * Copyright (C) 1998 Philip Blundell
+ *
+ * Changelog:
+ *   22-08-1998	RMK	Restructured IRQ routines
  */
 
 #include <asm/io.h>
@@ -10,29 +13,28 @@
 
 extern unsigned long soft_irq_mask;
 
-static __inline__ void mask_irq(unsigned int irq)
+static void nexuspci_mask_irq(unsigned int irq)
 {
 	writel((irq << 1), INTCONT);
 	soft_irq_mask &= ~(1<<irq);
 }
 
-#define mask_and_ack_irq(_x)	mask_irq(_x)
-
-static __inline__ void unmask_irq(unsigned int irq)
+static void nexuspci_unmask_irq(unsigned int irq)
 {
 	writel((irq << 1) + 1, INTCONT);
 	soft_irq_mask |= (1<<irq);
 }
  
-static __inline__ unsigned long get_enabled_irqs(void)
-{
-	return soft_irq_mask;
-}
-
 static __inline__ void irq_init_irq(void)
 {
 	unsigned int i;
 	/* Disable all interrupts initially. */
-	for (i = 0; i < NR_IRQS; i++)
+	for (i = 0; i < NR_IRQS; i++) {
+		irq_desc[i].valid	= 1;
+		irq_desc[i].probe_ok	= 1;
+		irq_desc[i].mask_ack	= nexuspci_mask_irq;
+		irq_desc[i].mask	= nexuspci_mask_irq;
+		irq_desc[i].unmask	= nexuspci_unmask_irq;
 		mask_irq(i);
+	}
 }
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/arch-nexuspci/param.h linux/include/asm-arm/arch-nexuspci/param.h
--- v2.1.120/linux/include/asm-arm/arch-nexuspci/param.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-nexuspci/param.h	Sun Sep  6 10:45:30 1998
@@ -0,0 +1,8 @@
+/*
+ * linux/include/asm-arm/arch-nexuspci/param.h
+ *
+ * Copyright (C) 1996 Russell King
+ * Copyright (C) 1998 Philip Blundell
+ */
+
+#define HZ 100
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/arch-rpc/irq.h linux/include/asm-arm/arch-rpc/irq.h
--- v2.1.120/linux/include/asm-arm/arch-rpc/irq.h	Tue Apr 14 14:29:25 1998
+++ linux/include/asm-arm/arch-rpc/irq.h	Sun Sep  6 10:45:30 1998
@@ -5,130 +5,170 @@
  *
  * Changelog:
  *   10-10-1996	RMK	Brought up to date with arch-sa110eval
+ *   22-08-1998	RMK	Restructured IRQ routines
  */
 
-#define BUILD_IRQ(s,n,m) \
-	void IRQ##n##_interrupt(void); \
-	void fast_IRQ##n##_interrupt(void); \
-	void bad_IRQ##n##_interrupt(void); \
-	void probe_IRQ##n##_interrupt(void);
+static void rpc_mask_irq_ack_a(unsigned int irq)
+{
+	unsigned int temp;
 
-/*
- * The timer is a special interrupt
- */
-#define IRQ5_interrupt		timer_IRQ_interrupt
+	__asm__ __volatile__(
+	"ldrb	%0, [%2]\n"
+"	bic	%0, %0, %1\n"
+"	strb	%0, [%2]\n"
+"	strb	%1, [%3]"
+	: "=&r" (temp)
+	: "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKA)),
+	  "r" (ioaddr(IOMD_IRQCLRA)));
+}
+
+static void rpc_mask_irq_a(unsigned int irq)
+{
+	unsigned int temp;
 
-#define IRQ_INTERRUPT(n)	IRQ##n##_interrupt
-#define FAST_INTERRUPT(n)	fast_IRQ##n##_interrupt
-#define BAD_INTERRUPT(n)	bad_IRQ##n##_interrupt
-#define PROBE_INTERRUPT(n)	probe_IRQ##n##_interrupt
-
-#define X(x) (x)|0x01, (x)|0x02, (x)|0x04, (x)|0x08, (x)|0x10, (x)|0x20, (x)|0x40, (x)|0x80
-#define Z(x) (x), (x), (x), (x), (x), (x), (x), (x)
-
-static __inline__ void mask_and_ack_irq(unsigned int irq)
-{
-	static const int addrmasks[] = {
-		X((IOMD_IRQMASKA - IOMD_BASE)<<18 | (1 << 15)),
-		X((IOMD_IRQMASKB - IOMD_BASE)<<18),
-		X((IOMD_DMAMASK - IOMD_BASE)<<18),
-		Z(0),
-		Z(0),
-		Z(0),
-		Z(0),
-		Z(0),
-		X((IOMD_FIQMASK - IOMD_BASE)<<18),
-		Z(0),
-		Z(0),
-		Z(0),
-		Z(0),
-		Z(0),
-		Z(0),
-		Z(0)
-	};
-	unsigned int temp1, temp2;
-
-	__asm__ __volatile__(
-"	ldr	%1, [%5, %3, lsl #2]\n"
-"	teq	%1, #0\n"
-"	beq	2f\n"
-"	ldrb	%0, [%2, %1, lsr #16]\n"
+	__asm__ __volatile__(
+	"ldrb	%0, [%2]\n"
 "	bic	%0, %0, %1\n"
-"	strb	%0, [%2, %1, lsr #16]\n"
-"	tst	%1, #0x8000\n"			/* do we need an IRQ clear? */
-"	strneb	%1, [%2, %4]\n"
-"2:"
-	: "=&r" (temp1), "=&r" (temp2)
-	: "r" (ioaddr(IOMD_BASE)), "r" (irq),
-	  "I" ((IOMD_IRQCLRA - IOMD_BASE) << 2), "r" (addrmasks));
-}
-
-#undef X
-#undef Z
-
-static __inline__ void mask_irq(unsigned int irq)
-{
-	extern void ecard_disableirq (unsigned int);
-	extern void ecard_disablefiq (unsigned int);
-	unsigned char mask = 1 << (irq & 7);
-
-	switch (irq >> 3) {
-	case 0:
-		outb(inb(IOMD_IRQMASKA) & ~mask, IOMD_IRQMASKA);
-		break;
-	case 1:
-		outb(inb(IOMD_IRQMASKB) & ~mask, IOMD_IRQMASKB);
-		break;
-	case 2:
-		outb(inb(IOMD_DMAMASK) & ~mask, IOMD_DMAMASK);
-		break;
-	case 4:
-		ecard_disableirq (irq & 7);
-		break;
-	case 8:
-		outb(inb(IOMD_FIQMASK) & ~mask, IOMD_FIQMASK);
-		break;
-	case 12:
-		ecard_disablefiq (irq & 7);
-	}
+"	strb	%0, [%2]"
+	: "=&r" (temp)
+	: "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKA)));
 }
 
-static __inline__ void unmask_irq(unsigned int irq)
+static void rpc_unmask_irq_a(unsigned int irq)
 {
-	extern void ecard_enableirq (unsigned int);
-	extern void ecard_enablefiq (unsigned int);
-	unsigned char mask = 1 << (irq & 7);
-
-	switch (irq >> 3) {
-	case 0:
-		outb(inb(IOMD_IRQMASKA) | mask, IOMD_IRQMASKA);
-		break;
-	case 1:
-		outb(inb(IOMD_IRQMASKB) | mask, IOMD_IRQMASKB);
-		break;
-	case 2:
-		outb(inb(IOMD_DMAMASK) | mask, IOMD_DMAMASK);
-		break;
-	case 4:
-		ecard_enableirq (irq & 7);
-		break;
-	case 8:
-		outb(inb(IOMD_FIQMASK) | mask, IOMD_FIQMASK);
-		break;
-	case 12:
-		ecard_enablefiq (irq & 7);
-	}
+	unsigned int temp;
+
+	__asm__ __volatile__(
+	"ldrb	%0, [%2]\n"
+"	orr	%0, %0, %1\n"
+"	strb	%0, [%2]"
+	: "=&r" (temp)
+	: "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKA)));
 }
 
-static __inline__ unsigned long get_enabled_irqs(void)
+static void rpc_mask_irq_b(unsigned int irq)
 {
-	return inb(IOMD_IRQMASKA) | inb(IOMD_IRQMASKB) << 8 | inb(IOMD_DMAMASK) << 16;
+	unsigned int temp;
+
+	__asm__ __volatile__(
+	"ldrb	%0, [%2]\n"
+"	bic	%0, %0, %1\n"
+"	strb	%0, [%2]"
+	: "=&r" (temp)
+	: "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKB)));
+}
+
+static void rpc_unmask_irq_b(unsigned int irq)
+{
+	unsigned int temp;
+
+	__asm__ __volatile__(
+	"ldrb	%0, [%2]\n"
+"	orr	%0, %0, %1\n"
+"	strb	%0, [%2]"
+	: "=&r" (temp)
+	: "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_IRQMASKB)));
+}
+
+static void rpc_mask_irq_dma(unsigned int irq)
+{
+	unsigned int temp;
+
+	__asm__ __volatile__(
+	"ldrb	%0, [%2]\n"
+"	bic	%0, %0, %1\n"
+"	strb	%0, [%2]"
+	: "=&r" (temp)
+	: "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_DMAMASK)));
+}
+
+static void rpc_unmask_irq_dma(unsigned int irq)
+{
+	unsigned int temp;
+
+	__asm__ __volatile__(
+	"ldrb	%0, [%2]\n"
+"	orr	%0, %0, %1\n"
+"	strb	%0, [%2]"
+	: "=&r" (temp)
+	: "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_DMAMASK)));
+}
+
+static void rpc_mask_irq_fiq(unsigned int irq)
+{
+	unsigned int temp;
+
+	__asm__ __volatile__(
+	"ldrb	%0, [%2]\n"
+"	bic	%0, %0, %1\n"
+"	strb	%0, [%2]"
+	: "=&r" (temp)
+	: "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_FIQMASK)));
+}
+
+static void rpc_unmask_irq_fiq(unsigned int irq)
+{
+	unsigned int temp;
+
+	__asm__ __volatile__(
+	"ldrb	%0, [%2]\n"
+"	orr	%0, %0, %1\n"
+"	strb	%0, [%2]"
+	: "=&r" (temp)
+	: "r" (1 << (irq & 7)), "r" (ioaddr(IOMD_FIQMASK)));
 }
 
 static __inline__ void irq_init_irq(void)
 {
+	extern void ecard_disableirq(unsigned int irq);
+	extern void ecard_enableirq(unsigned int irq);
+	int irq;
+
 	outb(0, IOMD_IRQMASKA);
 	outb(0, IOMD_IRQMASKB);
 	outb(0, IOMD_FIQMASK);
 	outb(0, IOMD_DMAMASK);
+
+	for (irq = 0; irq < NR_IRQS; irq++) {
+		switch (irq) {
+		case 0 ... 6:
+			irq_desc[irq].probe_ok = 1;
+		case 7:
+			irq_desc[irq].valid    = 1;
+			irq_desc[irq].mask_ack = rpc_mask_irq_ack_a;
+			irq_desc[irq].mask     = rpc_mask_irq_a;
+			irq_desc[irq].unmask   = rpc_unmask_irq_a;
+			break;
+
+		case 9 ... 15:
+			irq_desc[irq].probe_ok = 1;
+		case 8:
+			irq_desc[irq].valid    = 1;
+			irq_desc[irq].mask_ack = rpc_mask_irq_b;
+			irq_desc[irq].mask     = rpc_mask_irq_b;
+			irq_desc[irq].unmask   = rpc_unmask_irq_b;
+			break;
+
+		case 16 ... 22:
+			irq_desc[irq].valid    = 1;
+			irq_desc[irq].mask_ack = rpc_mask_irq_dma;
+			irq_desc[irq].mask     = rpc_mask_irq_dma;
+			irq_desc[irq].unmask   = rpc_unmask_irq_dma;
+			break;
+
+		case 32 ... 40:
+			irq_desc[irq].valid    = 1;
+			irq_desc[irq].mask_ack = ecard_disableirq;
+			irq_desc[irq].mask     = ecard_disableirq;
+			irq_desc[irq].unmask   = ecard_enableirq;
+			break;
+
+		case 64 ... 72:
+			irq_desc[irq].valid    = 1;
+			irq_desc[irq].mask_ack = rpc_mask_irq_fiq;
+			irq_desc[irq].mask     = rpc_mask_irq_fiq;
+			irq_desc[irq].unmask   = rpc_unmask_irq_fiq;
+			break;
+		}
+	}
 }
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/arch-rpc/irqs.h linux/include/asm-arm/arch-rpc/irqs.h
--- v2.1.120/linux/include/asm-arm/arch-rpc/irqs.h	Fri May  8 23:14:54 1998
+++ linux/include/asm-arm/arch-rpc/irqs.h	Sun Sep  6 10:45:30 1998
@@ -35,5 +35,3 @@
 
 #define IRQ_TIMER		IRQ_TIMER0
 
-#define irq_cannonicalize(i)	(i)
-
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/arch-rpc/param.h linux/include/asm-arm/arch-rpc/param.h
--- v2.1.120/linux/include/asm-arm/arch-rpc/param.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-rpc/param.h	Sun Sep  6 10:45:30 1998
@@ -0,0 +1,8 @@
+/*
+ * linux/include/asm-arm/arch-rpc/param.h
+ *
+ * Copyright (C) 1996 Russell King
+ * Copyright (C) 1998 Philip Blundell
+ */
+
+#define HZ 100
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/arch-rpc/uncompress.h linux/include/asm-arm/arch-rpc/uncompress.h
--- v2.1.120/linux/include/asm-arm/arch-rpc/uncompress.h	Tue Apr 14 14:29:25 1998
+++ linux/include/asm-arm/arch-rpc/uncompress.h	Sun Sep  6 10:45:30 1998
@@ -141,3 +141,7 @@
 }
 #endif
 
+/*
+ * nothing to do
+ */
+#define arch_decomp_wdog()
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/arch-vnc/a.out.h linux/include/asm-arm/arch-vnc/a.out.h
--- v2.1.120/linux/include/asm-arm/arch-vnc/a.out.h	Tue Jul 21 00:15:32 1998
+++ linux/include/asm-arm/arch-vnc/a.out.h	Sun Sep  6 10:45:30 1998
@@ -13,4 +13,3 @@
 #endif
 
 #endif
-
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/arch-vnc/dma.h linux/include/asm-arm/arch-vnc/dma.h
--- v2.1.120/linux/include/asm-arm/arch-vnc/dma.h	Tue Jul 21 00:15:32 1998
+++ linux/include/asm-arm/arch-vnc/dma.h	Sun Sep  6 10:45:30 1998
@@ -26,4 +26,3 @@
 #define MAX_DMA_CHANNELS	8
 
 #endif /* _ASM_ARCH_DMA_H */
-
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/arch-vnc/hardware.h linux/include/asm-arm/arch-vnc/hardware.h
--- v2.1.120/linux/include/asm-arm/arch-vnc/hardware.h	Tue Jul 21 00:15:32 1998
+++ linux/include/asm-arm/arch-vnc/hardware.h	Sun Sep  6 10:45:30 1998
@@ -118,4 +118,3 @@
 #define PARAMS_BASE		(PAGE_OFFSET + PARAMS_OFFSET)
 
 #define SAFE_ADDR		0x50000000
-
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/arch-vnc/irq.h linux/include/asm-arm/arch-vnc/irq.h
--- v2.1.120/linux/include/asm-arm/arch-vnc/irq.h	Tue Jul 21 00:15:32 1998
+++ linux/include/asm-arm/arch-vnc/irq.h	Sun Sep  6 10:45:30 1998
@@ -2,6 +2,9 @@
  * include/asm-arm/arch-vnc/irq.h
  *
  * Copyright (C) 1998 Russell King
+ *
+ * Changelog:
+ *   22-08-1998	RMK	Restructured IRQ routines
  */
 
 #include <asm/irq.h>
@@ -29,67 +32,48 @@
 	IRQ_MASK_PCI_ERR
 };
 
-static __inline__ void mask_and_ack_irq(unsigned int irq)
+static void vnc_mask_csr_irq(unsigned int irq)
 {
-	if (irq < 16)
-		*CSR_IRQ_DISABLE = fb_irq_mask[irq];
-	else {
-		unsigned int pic_mask, mask;
-
-		if (irq < 24)
-			pic_mask = PIC_MASK_LO;
-		else
-			pic_mask = PIC_MASK_HI;
-
-		mask = 1 << (irq & 7);
-
-		outb(inb(pic_mask) | mask, pic_mask);
-	}
+	*CSR_IRQ_DISABLE = fb_irq_mask[irq];
 }
 
-static __inline__ void mask_irq(unsigned int irq)
+static void vnc_unmask_csr_irq(unsigned int irq)
 {
-	if (irq < 16)
-		*CSR_IRQ_DISABLE = fb_irq_mask[irq];
-	else {
-		unsigned int pic_mask, mask;
-
-		if (irq < 24)
-			pic_mask = PIC_MASK_LO;
-		else
-			pic_mask = PIC_MASK_HI;
+	*CSR_IRQ_DISABLE = fb_irq_mask[irq];
+}
 
-		mask = 1 << (irq & 7);
+static void vnc_mask_pic_lo_irq(unsigned int irq)
+{
+	unsigned int mask = 1 << (irq & 7);
 
-		outb(inb(pic_mask) | mask, pic_mask);
-	}
+	outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO);
 }
 
-static __inline__ void unmask_irq(unsigned int irq)
+static void vnc_unmask_pic_lo_irq(unsigned int irq)
 {
-	if (irq < 16)
-		*CSR_IRQ_ENABLE = fb_irq_mask[irq];
-	else {
-		unsigned int pic_mask, mask;
+	unsigned int mask = 1 << (irq & 7);
 
-		if (irq < 24)
-			pic_mask = PIC_MASK_LO;
-		else
-			pic_mask = PIC_MASK_HI;
+	outb(inb(PIC_MASK_LO) & ~mask, PIC_MASK_LO);
+}
 
-		mask = 1 << (irq & 7);
+static void vnc_mask_pic_hi_irq(unsigned int irq)
+{
+	unsigned int mask = 1 << (irq & 7);
 
-		outb(inb(pic_mask) & ~mask, pic_mask);
-	}
+	outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI);
 }
- 
-static __inline__ unsigned long get_enabled_irqs(void)
+
+static void vnc_unmask_pic_hi_irq(unsigned int irq)
 {
-	return 0;
+	unsigned int mask = 1 << (irq & 7);
+
+	outb(inb(PIC_MASK_HI) & ~mask, PIC_MASK_HI);
 }
 
 static __inline__ void irq_init_irq(void)
 {
+	unsigned int irq;
+
 	outb(0x11, PIC_LO);
 	outb(0x10, PIC_MASK_LO);
 	outb(0x04, PIC_MASK_LO);
@@ -103,4 +87,23 @@
 	*CSR_IRQ_DISABLE = ~IRQ_MASK_EXTERN_IRQ;
 	*CSR_IRQ_ENABLE  = IRQ_MASK_EXTERN_IRQ;
 	*CSR_FIQ_DISABLE = -1;
+
+	for (irq = 0; irq < NR_IRQS; irq++) {
+		irq_desc[irq].valid	= 1;
+		irq_desc[irq].probe_ok	= 1;
+
+		if (irq < 16) {
+			irq_desc[irq].mask_ack	= vnc_mask_csr_irq;
+			irq_desc[irq].mask	= vnc_mask_csr_irq;
+			irq_desc[irq].unmask	= vnc_unmask_csr_irq;
+		} else if (irq < 24) {
+			irq_desc[irq].mask_ack	= vnc_mask_pic_lo_irq;
+			irq_desc[irq].mask	= vnc_mask_pic_lo_irq;
+			irq_desc[irq].unmask	= vnc_unmask_pic_lo_irq;
+		} else {
+			irq_desc[irq].mask_ack	= vnc_mask_pic_hi_irq;
+			irq_desc[irq].mask	= vnc_mask_pic_hi_irq;
+			irq_desc[irq].unmask	= vnc_unmask_pic_hi_irq;
+		}
+	}
 }
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/arch-vnc/irqs.h linux/include/asm-arm/arch-vnc/irqs.h
--- v2.1.120/linux/include/asm-arm/arch-vnc/irqs.h	Tue Jul 21 00:15:32 1998
+++ linux/include/asm-arm/arch-vnc/irqs.h	Sun Sep  6 10:45:30 1998
@@ -60,4 +60,3 @@
 #define IRQ_TIMER		IRQ_TIMER0
 
 #define irq_cannonicalize(i)	(i)
-
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/arch-vnc/keyboard.h linux/include/asm-arm/arch-vnc/keyboard.h
--- v2.1.120/linux/include/asm-arm/arch-vnc/keyboard.h	Tue Jul 21 00:15:32 1998
+++ linux/include/asm-arm/arch-vnc/keyboard.h	Sun Sep  6 10:45:30 1998
@@ -34,4 +34,3 @@
 //#define kbd_sysrq_xlate			ps2kbd_sysrq_xlate
 #define kbd_disable_irq()
 #define kbd_enable_irq()
-
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/arch-vnc/param.h linux/include/asm-arm/arch-vnc/param.h
--- v2.1.120/linux/include/asm-arm/arch-vnc/param.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-vnc/param.h	Sun Sep  6 10:45:30 1998
@@ -0,0 +1,8 @@
+/*
+ * linux/include/asm-arm/arch-vnc/param.h
+ *
+ * Copyright (C) 1996 Russell King
+ * Copyright (C) 1998 Philip Blundell
+ */
+
+#define HZ 100
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/arch-vnc/uncompress.h linux/include/asm-arm/arch-vnc/uncompress.h
--- v2.1.120/linux/include/asm-arm/arch-vnc/uncompress.h	Tue Jul 21 00:15:32 1998
+++ linux/include/asm-arm/arch-vnc/uncompress.h	Sun Sep  6 10:45:30 1998
@@ -31,3 +31,4 @@
  * nothing to do
  */
 #define arch_decomp_setup()
+#define arch_decomp_wdog()
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/atomic.h linux/include/asm-arm/atomic.h
--- v2.1.120/linux/include/asm-arm/atomic.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/atomic.h	Sun Sep  6 10:45:30 1998
@@ -7,20 +7,22 @@
  *  27-06-1996	RMK	Created
  *  13-04-1997	RMK	Made functions atomic!
  *  07-12-1997	RMK	Upgraded for v2.1.
+ *  26-08-1998	PJB	Added #ifdef __KERNEL__
  */
 #ifndef __ASM_ARM_ATOMIC_H
 #define __ASM_ARM_ATOMIC_H
 
+typedef struct { int counter; } atomic_t;
+
+#define ATOMIC_INIT(i)	{ (i) }
+
+#ifdef __KERNEL__
 #include <asm/system.h>
 
 #ifdef __SMP__
 #error SMP not supported
 #endif
 
-typedef struct { int counter; } atomic_t;
-
-#define ATOMIC_INIT(i)	{ (i) }
-
 #define atomic_read(v)	((v)->counter)
 #define atomic_set(v,i)	(((v)->counter) = (i))
 
@@ -82,4 +84,5 @@
 	restore_flags (flags);
 }
 
+#endif
 #endif
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/elf.h linux/include/asm-arm/elf.h
--- v2.1.120/linux/include/asm-arm/elf.h	Tue Jul 21 00:15:32 1998
+++ linux/include/asm-arm/elf.h	Sun Sep  6 10:45:30 1998
@@ -30,7 +30,7 @@
 #define ELF_ARCH	EM_ARM
 
 #define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE	32768
+#define ELF_EXEC_PAGESIZE	4096
 
 /* This is the location that an ET_DYN program is loaded if exec'ed.  Typical
    use of this is to invoke "./ld.so someprog" to test out a new version of
@@ -39,6 +39,11 @@
 
 #define ELF_ET_DYN_BASE	(2 * TASK_SIZE / 3)
 
+/* When the program starts, a1 contains a pointer to a function to be 
+   registered with atexit, as per the SVR4 ABI.  A value of 0 means we 
+   have no such handler.  */
+#define ELF_PLAT_INIT(_r)	(_r)->ARM_r0 = 0
+
 /* This yields a mask that user programs can use to figure out what
    instruction set this cpu supports. */
 
@@ -64,18 +69,5 @@
 #define SET_PERSONALITY(ex,ibcs2) \
 	current->personality = PER_LINUX_32BIT
 #endif
-
-#define R_ARM_NONE	(0)
-#define R_ARM_32	(1)	/* => ld 32 */
-#define R_ARM_PC26	(2)	/* => ld b/bl branches */
-#define R_ARM_PC32	(3)
-#define R_ARM_GOT32	(4)	/* -> object relocation into GOT */
-#define R_ARM_PLT32	(5)
-#define R_ARM_COPY	(6)	/* => dlink copy object */
-#define R_ARM_GLOB_DAT	(7)	/* => dlink 32bit absolute address for .got */
-#define R_ARM_JUMP_SLOT	(8)	/* => dlink 32bit absolute address for .got.plt */
-#define R_ARM_RELATIVE	(9)	/* => ld resolved 32bit absolute address requiring load address adjustment */
-#define R_ARM_GOTOFF	(10)	/* => ld calculates offset of data from base of GOT */
-#define R_ARM_GOTPC	(11)	/* => ld 32-bit relative offset */
 
 #endif
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/fiq.h linux/include/asm-arm/fiq.h
--- v2.1.120/linux/include/asm-arm/fiq.h	Tue Jul 21 00:15:32 1998
+++ linux/include/asm-arm/fiq.h	Sun Sep  6 10:45:30 1998
@@ -1,32 +1,34 @@
-/* Support for FIQ on ARM architectures.
+/*
+ *  linux/include/asm-arm/fiq.h
+ *
+ * Support for FIQ on ARM architectures.
  * Written by Philip Blundell <philb@gnu.org>, 1998
+ * Re-written by Russell King
  */
 
 #ifndef __ASM_FIQ_H
 #define __ASM_FIQ_H
 
-struct fiq_handler {
-	 const char *name;
-	 int (*callback)(void);
-};
-
-extern int claim_fiq(struct fiq_handler *f);
-extern void release_fiq(struct fiq_handler *f);
-
-#endif
-/* Support for FIQ on ARM architectures.
- * Written by Philip Blundell <philb@gnu.org>, 1998
- */
-
-#ifndef __ASM_FIQ_H
-#define __ASM_FIQ_H
+#include <asm/ptrace.h>
 
 struct fiq_handler {
-	 const char *name;
-	 int (*callback)(void);
+	struct fiq_handler *next;
+	/* Name
+	 */
+	const char *name;
+	/* Called to ask driver to relinquish/
+	 * reacquire FIQ
+	 * return zero to accept, or -<errno>
+	 */
+	int (*fiq_op)(void *, int relinquish);
+	/* data for the relinquish/reacquire functions
+	 */
+	void *dev_id;
 };
 
 extern int claim_fiq(struct fiq_handler *f);
 extern void release_fiq(struct fiq_handler *f);
+extern void set_fiq_handler(void *start, unsigned int length);
+extern void set_fiq_regs(struct pt_regs *regs);
 
 #endif
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/io.h linux/include/asm-arm/io.h
--- v2.1.120/linux/include/asm-arm/io.h	Tue Jul 21 00:15:32 1998
+++ linux/include/asm-arm/io.h	Sun Sep  6 10:45:30 1998
@@ -15,6 +15,7 @@
 #include <asm/hardware.h>
 #include <asm/arch/mmu.h>
 #include <asm/arch/io.h>
+#include <asm/proc/io.h>
 
 /* unsigned long virt_to_phys(void *x) */
 #define virt_to_phys(x)		(__virt_to_phys((unsigned long)(x)))
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/irq.h linux/include/asm-arm/irq.h
--- v2.1.120/linux/include/asm-arm/irq.h	Tue Apr 14 14:29:25 1998
+++ linux/include/asm-arm/irq.h	Sun Sep  6 10:45:30 1998
@@ -3,6 +3,8 @@
 
 #include <asm/arch/irqs.h>
 
+#define irq_cannonicalize(i)	(i)
+
 #ifndef NR_IRQS
 #define NR_IRQS	128
 #endif
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/linux_logo.h linux/include/asm-arm/linux_logo.h
--- v2.1.120/linux/include/asm-arm/linux_logo.h	Thu Jul 16 18:09:28 1998
+++ linux/include/asm-arm/linux_logo.h	Sun Sep  6 10:45:30 1998
@@ -11,17 +11,26 @@
 
 #define linux_logo_banner "ARM Linux version " UTS_RELEASE
 
-#define LINUX_LOGO_COLORS	0
+#define LINUX_LOGO_COLORS	221
 
-unsigned char linux_logo_red[] __initdata = { };
-unsigned char linux_logo_green[] __initdata = { };
-unsigned char linux_logo_blue[] __initdata = { };
-
-unsigned char linux_logo16_red[] __initdata = { };
-unsigned char linux_logo16_green[] __initdata = { };
-unsigned char linux_logo16_blue[] __initdata = { };
-
-unsigned char linux_logo[] __initdata = { };
-unsigned char linux_logo16[] __initdata = { };
-unsigned char linux_logo_bw[] __initdata = { };
+#ifdef INCLUDE_LINUX_LOGO_DATA
 
+#define INCLUDE_LINUX_LOGO16
+#include <linux/linux_logo.h>
+
+
+/* prototypes only */
+extern unsigned char linux_logo_red[];
+extern unsigned char linux_logo_green[];
+extern unsigned char linux_logo_blue[];
+extern unsigned char linux_logo[];
+extern unsigned char linux_logo_bw[];
+extern unsigned char linux_logo16_red[];
+extern unsigned char linux_logo16_green[];
+extern unsigned char linux_logo16_blue[];
+extern unsigned char linux_logo16[];
+extern unsigned char *linux_serial_image;
+
+extern int (*console_show_logo)(void);
+
+#endif
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/pgtable.h linux/include/asm-arm/pgtable.h
--- v2.1.120/linux/include/asm-arm/pgtable.h	Thu Aug  6 14:06:33 1998
+++ linux/include/asm-arm/pgtable.h	Sun Sep  6 10:45:30 1998
@@ -9,4 +9,7 @@
 
 extern int do_check_pgt_cache(int, int);
 
+/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
+#define PageSkip(page)			(0)
+
 #endif /* _ASMARM_PGTABLE_H */
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/proc-armo/io.h linux/include/asm-arm/proc-armo/io.h
--- v2.1.120/linux/include/asm-arm/proc-armo/io.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/proc-armo/io.h	Sun Sep  6 10:45:30 1998
@@ -0,0 +1,8 @@
+/*
+ * linux/include/asm-arm/proc-armo/io.h
+ */
+
+/* Nothing to do */
+#define dma_cache_inv(_start,_size)		do { } while (0)
+#define dma_cache_wback(_start,_size)		do { } while (0)
+#define dma_cache_wback_inv(_start,_size)	do { } while (0)
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/proc-armo/pgtable.h linux/include/asm-arm/proc-armo/pgtable.h
--- v2.1.120/linux/include/asm-arm/proc-armo/pgtable.h	Tue Jul 21 00:15:32 1998
+++ linux/include/asm-arm/proc-armo/pgtable.h	Sun Sep  6 10:45:30 1998
@@ -128,6 +128,7 @@
  */
 #define VMALLOC_START	0x01a00000
 #define VMALLOC_VMADDR(x) ((unsigned long)(x))
+#define VMALLOC_END	0x01c00000
 
 #define _PAGE_PRESENT		0x01
 #define _PAGE_READONLY		0x02
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/proc-armo/ptrace.h linux/include/asm-arm/proc-armo/ptrace.h
--- v2.1.120/linux/include/asm-arm/proc-armo/ptrace.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/proc-armo/ptrace.h	Sun Sep  6 10:45:30 1998
@@ -44,12 +44,12 @@
 #define CC_Z_BIT	(1 << 30)
 #define CC_N_BIT	(1 << 31)
 
-#define user_mode(regs) \
-	(((regs)->ARM_pc & MODE_MASK) == USR26_MODE)
-
 #define processor_mode(regs) \
 	((regs)->ARM_pc & MODE_MASK)
 
+#define user_mode(regs) \
+	(processor_mode(regs) == USR26_MODE)
+
 #define interrupts_enabled(regs) \
 	(!((regs)->ARM_pc & I_BIT))
 
@@ -59,7 +59,17 @@
 #define condition_codes(regs) \
 	((regs)->ARM_pc & (CC_V_BIT|CC_C_BIT|CC_Z_BIT|CC_N_BIT))
 
-#define instruction_pointer(regs)	((regs)->ARM_pc & 0x03fffffc)
-#define pc_pointer(v)			((v) & 0x03fffffc)
+#define pc_pointer(v) \
+	((v) & 0x03fffffc)
+
+#define instruction_pointer(regs) \
+	(pc_pointer((regs)->ARM_pc))
+
+/* Are the current registers suitable for user mode?
+ * (used to maintain security in signal handlers)
+ */
+#define valid_user_regs(regs) \
+	(user_mode(regs) && ((regs)->ARM_sp & 3) == 0)
+
 #endif
 
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/proc-armv/io.h linux/include/asm-arm/proc-armv/io.h
--- v2.1.120/linux/include/asm-arm/proc-armv/io.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/proc-armv/io.h	Sun Sep  6 10:45:30 1998
@@ -0,0 +1,38 @@
+/*
+ * linux/include/asm-arm/proc-armv/io.h
+ */
+
+/*
+ * The caches on some architectures aren't dma-coherent and have need to
+ * handle this in software.  There are two types of operations that
+ * can be applied to dma buffers.
+ *
+ *  - dma_cache_wback_inv(start, size) makes caches and RAM coherent by
+ *    writing the content of the caches back to memory, if necessary.
+ *    The function also invalidates the affected part of the caches as
+ *    necessary before DMA transfers from outside to memory.
+ *  - dma_cache_inv(start, size) invalidates the affected parts of the
+ *    caches.  Dirty lines of the caches may be written back or simply
+ *    be discarded.  This operation is necessary before dma operations
+ *    to the memory.
+ *  - dma_cache_wback(start, size) writes back any dirty lines but does
+ *    not invalidate the cache.  This can be used before DMA reads from
+ *    memory,
+ */
+
+#include <asm/proc-fns.h>
+
+#define dma_cache_inv(_start,_size)						\
+	do {									\
+		processor.u.armv3v4._cache_purge_area(_start,(_start+_size));	\
+	} while (0)
+
+#define dma_cache_wback(_start,_size)						\
+	do {									\
+		processor.u.armv3v4._cache_wback_area(_start,(_start+_size));	\
+	} while (0)
+
+#define dma_cache_wback_inv(_start,_size)					\
+	do {									\
+		processor.u.armv3v4._flush_cache_area(_start,(_start+_size),0);	\
+	} while (0)
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/proc-armv/param.h linux/include/asm-arm/proc-armv/param.h
--- v2.1.120/linux/include/asm-arm/proc-armv/param.h	Tue Jan 20 16:39:43 1998
+++ linux/include/asm-arm/proc-armv/param.h	Sun Sep  6 10:45:30 1998
@@ -7,9 +7,7 @@
 #ifndef __ASM_PROC_PARAM_H
 #define __ASM_PROC_PARAM_H
 
-#ifndef HZ
-#define HZ 100
-#endif
+#include <asm/arch/param.h>		/* for HZ */
 
 #define EXEC_PAGESIZE   4096
 
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/proc-armv/pgtable.h linux/include/asm-arm/proc-armv/pgtable.h
--- v2.1.120/linux/include/asm-arm/proc-armv/pgtable.h	Tue Jul 21 00:15:32 1998
+++ linux/include/asm-arm/proc-armv/pgtable.h	Sun Sep  6 10:45:30 1998
@@ -145,6 +145,7 @@
 #define VMALLOC_OFFSET	  (8*1024*1024)
 #define VMALLOC_START	  (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
 #define VMALLOC_VMADDR(x) ((unsigned long)(x))
+#define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
 
 /* PMD types (actually level 1 descriptor) */
 #define PMD_TYPE_MASK		0x0003
@@ -199,7 +200,7 @@
 #define PAGE_SHARED     __pgprot(PTE_TYPE_SMALL | _PTE_YOUNG | _PTE_READ | _PTE_WRITE)
 #define PAGE_COPY       __pgprot(PTE_TYPE_SMALL | _PTE_YOUNG | _PTE_READ)
 #define PAGE_READONLY   __pgprot(PTE_TYPE_SMALL | _PTE_YOUNG | _PTE_READ)
-#define PAGE_KERNEL     __pgprot(PTE_TYPE_SMALL | _PTE_YOUNG | _PTE_DIRTY | _PTE_WRITE)
+#define PAGE_KERNEL     __pgprot(PTE_TYPE_SMALL | _PTE_READ  | _PTE_DIRTY | _PTE_WRITE)
 
 #define _PAGE_USER_TABLE	(PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_USER))
 #define _PAGE_KERNEL_TABLE	(PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_KERNEL))
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/proc-armv/ptrace.h linux/include/asm-arm/proc-armv/ptrace.h
--- v2.1.120/linux/include/asm-arm/proc-armv/ptrace.h	Tue Jan 20 16:39:43 1998
+++ linux/include/asm-arm/proc-armv/ptrace.h	Sun Sep  6 10:45:30 1998
@@ -71,5 +71,11 @@
 #define instruction_pointer(regs)	((regs)->ARM_pc)
 #define pc_pointer(v)			(v)
 
+/* Are the current registers suitable for user mode?
+ * (used to maintain security in signal handlers)
+ */
+#define valid_user_regs(regs) \
+	(user_mode(regs) && ((regs)->ARM_sp & 3) == 0)
+
 #endif
 
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/proc-fns.h linux/include/asm-arm/proc-fns.h
--- v2.1.120/linux/include/asm-arm/proc-fns.h	Tue Jan 20 16:39:43 1998
+++ linux/include/asm-arm/proc-fns.h	Sun Sep  6 10:45:30 1998
@@ -83,6 +83,14 @@
 			 * flush an icached page
 			 */
 			void (*_flush_icache_area)(unsigned long start, unsigned long end);
+			/*
+			 * write back dirty cached data
+			 */
+			void (*_cache_wback_area)(unsigned long start, unsigned long end);
+			/*
+			 * purge cached data without (necessarily) writing it back
+			 */
+			void (*_cache_purge_area)(unsigned long start, unsigned long end);
 		} armv3v4;
 		struct {
 			/* MEMC
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/processor.h linux/include/asm-arm/processor.h
--- v2.1.120/linux/include/asm-arm/processor.h	Fri May  8 23:14:54 1998
+++ linux/include/asm-arm/processor.h	Sun Sep  6 10:45:30 1998
@@ -22,12 +22,15 @@
 
 typedef unsigned long mm_segment_t;		/* domain register	*/
 
+#define NR_DEBUGS	5
+
 #define DECLARE_THREAD_STRUCT							\
 struct thread_struct {								\
 	unsigned long	address;		/* Address of fault	*/	\
 	unsigned long	trap_no;		/* Trap number		*/	\
 	unsigned long	error_code;		/* Error code of trap	*/	\
 	union fp_state	fpstate;		/* FPE save state	*/	\
+	unsigned long	debug[NR_DEBUGS];	/* Debug/ptrace		*/	\
 	EXTRA_THREAD_STRUCT							\
 }
 
@@ -39,6 +42,7 @@
 	0,				\
 	0,				\
 	{ { { 0, }, }, },		\
+	{ 0, },				\
 	EXTRA_THREAD_STRUCT_INIT	\
 }
 
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/signal.h linux/include/asm-arm/signal.h
--- v2.1.120/linux/include/asm-arm/signal.h	Tue Jul 21 00:15:32 1998
+++ linux/include/asm-arm/signal.h	Sun Sep  6 10:45:30 1998
@@ -115,8 +115,9 @@
  * SA_INTERRUPT is also used by the irq handling routines.
  * SA_SHIRQ is for shared interrupt support on PCI and EISA.
  */
-#define SA_PROBE		SA_ONESHOT
-#define SA_SAMPLE_RANDOM	SA_RESTART
+#define SA_PROBE		0x80000000
+#define SA_SAMPLE_RANDOM	0x10000000
+#define SA_IRQNOMASK		0x08000000
 #define SA_SHIRQ		0x04000000
 #endif
 
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/spinlock.h linux/include/asm-arm/spinlock.h
--- v2.1.120/linux/include/asm-arm/spinlock.h	Tue Jul 21 00:15:32 1998
+++ linux/include/asm-arm/spinlock.h	Sun Sep  6 10:45:30 1998
@@ -6,8 +6,13 @@
 /*
  * Your basic spinlocks, allowing only a single CPU anywhere
  */
-typedef struct { } spinlock_t;
-#define SPIN_LOCK_UNLOCKED { }
+#if (__GNUC__ > 2) || (__GNUC_MINOR__ >= 8)
+  typedef struct { } spinlock_t;
+# define SPIN_LOCK_UNLOCKED { }
+#else
+  typedef unsigned char spinlock_t;
+# define SPIN_LOCK_UNLOCKED 0
+#endif
 
 #define spin_lock_init(lock)	do { } while(0)
 #define spin_lock(lock)		do { } while(0)
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/system.h linux/include/asm-arm/system.h
--- v2.1.120/linux/include/asm-arm/system.h	Tue Jul 21 00:15:32 1998
+++ linux/include/asm-arm/system.h	Sun Sep  6 10:45:30 1998
@@ -1,6 +1,16 @@
 #ifndef __ASM_ARM_SYSTEM_H
 #define __ASM_ARM_SYSTEM_H
 
+/* The type of machine we're running on */
+extern unsigned int machine_type;
+#define MACH_TYPE_EBSA110	0
+#define MACH_TYPE_RISCPC	1
+#define MACH_TYPE_NEXUSPCI	3
+#define MACH_TYPE_EBSA285	4
+#define MACH_TYPE_NETWINDER	5
+#define MACH_TYPE_CATS		6
+#define MACH_TYPE_TBOX		7
+
 #include <linux/kernel.h>
 #include <asm/proc-fns.h>
 
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/unistd.h linux/include/asm-arm/unistd.h
--- v2.1.120/linux/include/asm-arm/unistd.h	Wed Apr  8 19:36:28 1998
+++ linux/include/asm-arm/unistd.h	Sun Sep  6 10:45:30 1998
@@ -319,6 +319,7 @@
 static inline _syscall0(pid_t,setsid);
 static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count);
 static inline _syscall3(int,read,int,fd,char *,buf,off_t,count)
+static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count);
 static inline _syscall1(int,dup,int,fd);
 static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp);
 static inline _syscall3(int,open,const char *,file,int,flag,int,mode);
diff -u --recursive --new-file v2.1.120/linux/include/asm-arm/vga.h linux/include/asm-arm/vga.h
--- v2.1.120/linux/include/asm-arm/vga.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/vga.h	Sun Sep  6 10:45:30 1998
@@ -0,0 +1,11 @@
+#ifndef ASMARM_VGA_H
+#define ASMARM_VGA_H
+
+#include <asm/io.h>
+
+#define VGA_MAP_MEM(x)	(0xe0000000 + (x))
+
+#define vga_readb(x)	(*(x))
+#define vga_writeb(x,y)	(*(y) = (x))
+
+#endif
diff -u --recursive --new-file v2.1.120/linux/include/asm-i386/pgtable.h linux/include/asm-i386/pgtable.h
--- v2.1.120/linux/include/asm-i386/pgtable.h	Tue Aug 18 22:02:07 1998
+++ linux/include/asm-i386/pgtable.h	Wed Sep  9 09:07:08 1998
@@ -240,6 +240,7 @@
 #define PAGE_COPY	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
 #define PAGE_READONLY	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
 #define PAGE_KERNEL	__pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
+#define PAGE_KERNEL_RO	__pgprot(_PAGE_PRESENT | _PAGE_DIRTY | _PAGE_ACCESSED)
 
 /*
  * The i386 can't do page protection for execute, and considers that the same are read.
diff -u --recursive --new-file v2.1.120/linux/include/asm-i386/system.h linux/include/asm-i386/system.h
--- v2.1.120/linux/include/asm-i386/system.h	Tue Aug 18 22:02:07 1998
+++ linux/include/asm-i386/system.h	Wed Sep  9 08:56:59 1998
@@ -4,38 +4,6 @@
 #include <linux/kernel.h>
 #include <asm/segment.h>
 
-/*
- * Entry into gdt where to find first TSS. GDT layout:
- *   0 - null
- *   1 - not used
- *   2 - kernel code segment
- *   3 - kernel data segment
- *   4 - user code segment
- *   5 - user data segment
- *   6 - not used
- *   7 - not used
- *   8 - APM BIOS support
- *   9 - APM BIOS support
- *  10 - APM BIOS support
- *  11 - APM BIOS support
- *  12 - TSS #0
- *  13 - LDT #0
- *  14 - TSS #1
- *  15 - LDT #1
- */
-#define FIRST_TSS_ENTRY 12
-#define FIRST_LDT_ENTRY (FIRST_TSS_ENTRY+1)
-#define _TSS(n) ((((unsigned long) n)<<4)+(FIRST_TSS_ENTRY<<3))
-#define _LDT(n) ((((unsigned long) n)<<4)+(FIRST_LDT_ENTRY<<3))
-#define load_TR(n) __asm__ __volatile__("ltr %%ax": /* no output */ :"a" (_TSS(n)))
-#define load_ldt(n) __asm__ __volatile__("lldt %%ax": /* no output */ :"a" (_LDT(n)))
-#define store_TR(n) \
-__asm__("str %%ax\n\t" \
-	"subl %2,%%eax\n\t" \
-	"shrl $4,%%eax" \
-	:"=a" (n) \
-	:"0" (0),"i" (FIRST_TSS_ENTRY<<3))
-
 #ifdef __KERNEL__
 
 struct task_struct;	/* one of the stranger aspects of C forward declarations.. */
@@ -226,61 +194,6 @@
 #define restore_flags(x) __restore_flags(x)
 
 #endif
-
-#define _set_gate(gate_addr,type,dpl,addr) \
-__asm__ __volatile__ ("movw %%dx,%%ax\n\t" \
-	"movw %2,%%dx\n\t" \
-	"movl %%eax,%0\n\t" \
-	"movl %%edx,%1" \
-	:"=m" (*((long *) (gate_addr))), \
-	 "=m" (*(1+(long *) (gate_addr))) \
-	:"i" ((short) (0x8000+(dpl<<13)+(type<<8))), \
-	 "d" ((char *) (addr)),"a" (__KERNEL_CS << 16) \
-	:"ax","dx")
-
-#define set_intr_gate(n,addr) \
-	_set_gate(idt+(n),14,0,addr)
-
-#define set_trap_gate(n,addr) \
-	_set_gate(idt+(n),15,0,addr)
-
-#define set_system_gate(n,addr) \
-	_set_gate(idt+(n),15,3,addr)
-
-#define set_call_gate(a,addr) \
-	_set_gate(a,12,3,addr)
-
-#define _set_seg_desc(gate_addr,type,dpl,base,limit) {\
-	*((gate_addr)+1) = ((base) & 0xff000000) | \
-		(((base) & 0x00ff0000)>>16) | \
-		((limit) & 0xf0000) | \
-		((dpl)<<13) | \
-		(0x00408000) | \
-		((type)<<8); \
-	*(gate_addr) = (((base) & 0x0000ffff)<<16) | \
-		((limit) & 0x0ffff); }
-
-#define _set_tssldt_desc(n,addr,limit,type) \
-__asm__ __volatile__ ("movw %3,0(%2)\n\t" \
-	"movw %%ax,2(%2)\n\t" \
-	"rorl $16,%%eax\n\t" \
-	"movb %%al,4(%2)\n\t" \
-	"movb %4,5(%2)\n\t" \
-	"movb $0,6(%2)\n\t" \
-	"movb %%ah,7(%2)\n\t" \
-	"rorl $16,%%eax" \
-	: "=m"(*(n)) : "a" (addr), "r"(n), "ir"(limit), "i"(type))
-
-#define set_tss_desc(n,addr) \
-	_set_tssldt_desc(((char *) (n)),((int)(addr)),235,0x89)
-#define set_ldt_desc(n,addr,size) \
-	_set_tssldt_desc(((char *) (n)),((int)(addr)),((size << 3) - 1),0x82)
-
-/*
- * This is the ldt that every process will get unless we need
- * something other than this.
- */
-extern struct desc_struct default_ldt;
 
 /*
  * disable hlt during certain critical i/o operations
diff -u --recursive --new-file v2.1.120/linux/include/asm-i386/unistd.h linux/include/asm-i386/unistd.h
--- v2.1.120/linux/include/asm-i386/unistd.h	Wed Aug 26 11:37:44 1998
+++ linux/include/asm-i386/unistd.h	Sun Sep  6 13:05:22 1998
@@ -5,7 +5,6 @@
  * This file contains the system call numbers.
  */
 
-#define __NR_setup		  0	/* used only by init, to get system going */
 #define __NR_exit		  1
 #define __NR_fork		  2
 #define __NR_read		  3
@@ -289,7 +288,6 @@
 #define __NR__exit __NR_exit
 static inline _syscall0(int,idle)
 static inline _syscall0(int,pause)
-static inline _syscall1(int,setup,int,magic)
 static inline _syscall0(int,sync)
 static inline _syscall0(pid_t,setsid)
 static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count)
diff -u --recursive --new-file v2.1.120/linux/include/linux/adfs_fs_fs.h linux/include/linux/adfs_fs_fs.h
--- v2.1.120/linux/include/linux/adfs_fs_fs.h	Fri Jan 30 11:28:10 1998
+++ linux/include/linux/adfs_fs_fs.h	Wed Dec 31 16:00:00 1969
@@ -1,177 +0,0 @@
-#ifndef _ADFS_FS_H
-#define _ADFS_FS_H
-
-#include <linux/types.h>
-/*
- * Structures of data on the disk
- */
-
-/*
- * Disc Record at disc address 0xc00
- */
-struct adfs_discrecord {
-    unsigned char  log2secsize;
-    unsigned char  secspertrack;
-    unsigned char  heads;
-    unsigned char  density;
-    unsigned char  idlen;
-    unsigned char  log2bpmb;
-    unsigned char  skew;
-    unsigned char  bootoption;
-    unsigned char  lowsector;
-    unsigned char  nzones;
-    unsigned short zone_spare;
-    unsigned long  root;
-    unsigned long  disc_size;
-    unsigned short disc_id;
-    unsigned char  disc_name[10];
-    unsigned long  disc_type;
-    unsigned long  disc_size_high;
-    unsigned char  log2sharesize:4;
-    unsigned char  unused:4;
-    unsigned char  big_flag:1;
-};
-
-#define ADFS_DISCRECORD		(0xc00)
-#define ADFS_DR_OFFSET		(0x1c0)
-#define ADFS_DR_SIZE		 60
-#define ADFS_SUPER_MAGIC	 0xadf5
-#define ADFS_FREE_FRAG		 0
-#define ADFS_BAD_FRAG		 1
-#define ADFS_ROOT_FRAG		 2
-
-/*
- * Directory header
- */
-struct adfs_dirheader {
-	unsigned char startmasseq;
-	unsigned char startname[4];
-};
-
-#define ADFS_NEWDIR_SIZE	2048
-#define ADFS_OLDDIR_SIZE	1024
-#define ADFS_NUM_DIR_ENTRIES	77
-
-/*
- * Directory entries
- */
-struct adfs_direntry {
-	char dirobname[10];
-#define ADFS_NAME_LEN 10
-	__u8 dirload[4];
-	__u8 direxec[4];
-	__u8 dirlen[4];
-	__u8 dirinddiscadd[3];
-	__u8 newdiratts;
-#define ADFS_NDA_OWNER_READ	(1 << 0)
-#define ADFS_NDA_OWNER_WRITE	(1 << 1)
-#define ADFS_NDA_LOCKED		(1 << 2)
-#define ADFS_NDA_DIRECTORY	(1 << 3)
-#define ADFS_NDA_EXECUTE	(1 << 4)
-#define ADFS_NDA_PUBLIC_READ	(1 << 5)
-#define ADFS_NDA_PUBLIC_WRITE	(1 << 6)
-};
-
-#define ADFS_MAX_NAME_LEN	255
-struct adfs_idir_entry {
-	__u32		inode_no;			/* Address		*/
-	__u32		file_id;			/* file id		*/
-	__u32		name_len;			/* name length		*/
-	__u32		size;				/* size			*/
-	__u32		mtime;				/* modification time	*/
-	__u32		filetype;			/* RiscOS file type	*/
-	__u8		mode;				/* internal mode	*/
-	char		name[ADFS_MAX_NAME_LEN];	/* file name		*/
-};
-
-/*
- * Directory tail
- */
-union adfs_dirtail {
-	struct {
-		unsigned char dirlastmask;
-		char dirname[10];
-		unsigned char dirparent[3];
-		char dirtitle[19];
-		unsigned char reserved[14];
-		unsigned char endmasseq;
-		unsigned char endname[4];
-		unsigned char dircheckbyte;
-	} old;
-	struct {
-		unsigned char dirlastmask;
-		unsigned char reserved[2];
-		unsigned char dirparent[3];
-		char dirtitle[19];
-		char dirname[10];
-		unsigned char endmasseq;
-		unsigned char endname[4];
-		unsigned char dircheckbyte;
-	} new;
-};
-
-#ifdef __KERNEL__
-/*
- * Calculate the boot block checksum on an ADFS drive.  Note that this will
- * appear to be correct if the sector contains all zeros, so also check that
- * the disk size is non-zero!!!
- */
-extern inline int adfs_checkbblk (unsigned char *ptr)
-{
-    unsigned int result = 0;
-    unsigned char *p = ptr + 511;
-
-    do {
-	result = (result & 0xff) + (result >> 8);
-	result = result + *--p;
-    } while (p != ptr);
-
-    return (result & 0xff) != ptr[511];
-}
-
-/* dir.c */
-extern unsigned int adfs_val (unsigned char *p, int len);
-extern int adfs_dir_read_parent (struct inode *inode, struct buffer_head **bhp);
-extern int adfs_dir_read (struct inode *inode, struct buffer_head **bhp);
-extern int adfs_dir_check (struct inode *inode, struct buffer_head **bhp,
-			   int buffers, union adfs_dirtail *dtp);
-extern void adfs_dir_free (struct buffer_head **bhp, int buffers);
-extern int adfs_dir_get (struct super_block *sb, struct buffer_head **bhp,
-			 int buffers, int pos, unsigned long parent_object_id,
-			 struct adfs_idir_entry *ide);
-extern int adfs_dir_find_entry (struct super_block *sb, struct buffer_head **bhp,
-				int buffers, unsigned int index,
-				struct adfs_idir_entry *ide);
-
-/* inode.c */
-extern int adfs_inode_validate (struct inode *inode);
-extern unsigned long adfs_inode_generate (unsigned long parent_id, int diridx);
-extern unsigned long adfs_inode_objid (struct inode *inode);
-extern unsigned int adfs_parent_bmap (struct inode *inode, int block);
-extern int adfs_bmap (struct inode *inode, int block);
-extern void adfs_read_inode (struct inode *inode);
-
-/* map.c */
-extern int adfs_map_lookup (struct super_block *sb, int frag_id, int offset);
-
-/* namei.c */
-extern int adfs_lookup (struct inode * dir, const char * name, int len,
-			struct inode ** result);
-
-/* super.c */
-extern int init_adfs_fs (void);
-extern void adfs_error (struct super_block *, const char *, const char *, ...);
-
-/*
- * Inodes and file operations
- */
-
-/* dir.c */
-extern struct inode_operations adfs_dir_inode_operations;
-
-/* file.c */
-extern struct inode_operations adfs_file_inode_operations;
-#endif
-
-#endif
-
diff -u --recursive --new-file v2.1.120/linux/include/linux/head.h linux/include/linux/head.h
--- v2.1.120/linux/include/linux/head.h	Fri Nov 14 18:39:55 1997
+++ linux/include/linux/head.h	Wed Dec 31 16:00:00 1969
@@ -1,28 +0,0 @@
-#ifndef _LINUX_HEAD_H
-#define _LINUX_HEAD_H
-
-struct desc_struct {
-	unsigned long a,b;
-};
-
-extern struct desc_struct idt_table[],gdt_table[];
-extern struct desc_struct *idt, *gdt;
-
-struct Xgt_desc_struct {
-	unsigned short size;
-	unsigned long address __attribute__((packed));
-};
-
-#define idt_descr (*(struct Xgt_desc_struct *)((char *)&idt - 2))
-#define gdt_descr (*(struct Xgt_desc_struct *)((char *)&gdt - 2))
-
-#define GDT_NUL 0
-#define GDT_CODE 1
-#define GDT_DATA 2
-#define GDT_TMP 3
-
-#define LDT_NUL 0
-#define LDT_CODE 1
-#define LDT_DATA 2
-
-#endif
diff -u --recursive --new-file v2.1.120/linux/include/linux/sched.h linux/include/linux/sched.h
--- v2.1.120/linux/include/linux/sched.h	Sat Sep  5 16:46:41 1998
+++ linux/include/linux/sched.h	Wed Sep  9 09:10:16 1998
@@ -1,8 +1,6 @@
 #ifndef _LINUX_SCHED_H
 #define _LINUX_SCHED_H
 
-extern void checksignals(void);
-
 #include <asm/param.h>	/* for HZ */
 
 extern unsigned long event;
@@ -66,7 +64,6 @@
 extern int nr_running, nr_tasks;
 extern int last_pid;
 
-#include <linux/head.h>
 #include <linux/fs.h>
 #include <linux/signal.h>
 #include <linux/time.h>
diff -u --recursive --new-file v2.1.120/linux/include/linux/sound.h linux/include/linux/sound.h
--- v2.1.120/linux/include/linux/sound.h	Tue Jun  9 11:57:31 1998
+++ linux/include/linux/sound.h	Sat Sep  5 17:01:45 1998
@@ -6,8 +6,10 @@
 extern int register_sound_mixer(struct file_operations *fops);
 extern int register_sound_midi(struct file_operations *fops);
 extern int register_sound_dsp(struct file_operations *fops);
+extern int register_sound_synth(struct file_operations *fops);
 
 extern void unregister_sound_special(int unit);
 extern void unregister_sound_mixer(int unit);
 extern void unregister_sound_midi(int unit);
 extern void unregister_sound_dsp(int unit);
+extern void unregister_sound_synth(int unit);
diff -u --recursive --new-file v2.1.120/linux/include/linux/string.h linux/include/linux/string.h
--- v2.1.120/linux/include/linux/string.h	Fri Jul 31 17:05:52 1998
+++ linux/include/linux/string.h	Sun Sep  6 10:11:15 1998
@@ -26,6 +26,7 @@
 extern __kernel_size_t strspn(const char *,const char *);
 extern int strcmp(const char *,const char *);
 extern int strncmp(const char *,const char *,__kernel_size_t);
+extern int strnicmp(const char *, const char *, __kernel_size_t);
 
 extern void * memset(void *,int,__kernel_size_t);
 extern void * memcpy(void *,const void *,__kernel_size_t);
diff -u --recursive --new-file v2.1.120/linux/include/linux/umsdos_fs.h linux/include/linux/umsdos_fs.h
--- v2.1.120/linux/include/linux/umsdos_fs.h	Sat Sep  5 16:46:41 1998
+++ linux/include/linux/umsdos_fs.h	Wed Sep  9 13:29:11 1998
@@ -1,7 +1,8 @@
 #ifndef LINUX_UMSDOS_FS_H
 #define LINUX_UMSDOS_FS_H
 
-#define UMS_DEBUG 1
+/* #define UMSDOS_DEBUG 1 */
+#define UMSDOS_PARANOIA 1
 
 #define UMSDOS_VERSION	0
 #define UMSDOS_RELEASE	4
@@ -17,6 +18,9 @@
 #ifndef _LINUX_TYPES_H
 #include <linux/types.h>
 #endif
+#ifndef _LINUX_LIMITS_H
+#include <linux/limits.h>
+#endif
 #ifndef _LINUX_DIRENT_H
 #include <linux/dirent.h>
 #endif
@@ -38,7 +42,7 @@
  * to shut off.
  */
 #	define PRINTK(x)
-#	ifdef UMS_DEBUG
+#	ifdef UMSDOS_DEBUG
 #		define Printk(x) printk x
 #	else
 #		define Printk(x)
diff -u --recursive --new-file v2.1.120/linux/include/linux/umsdos_fs.p linux/include/linux/umsdos_fs.p
--- v2.1.120/linux/include/linux/umsdos_fs.p	Sat Sep  5 16:46:41 1998
+++ linux/include/linux/umsdos_fs.p	Wed Sep  9 09:01:19 1998
@@ -1,5 +1,6 @@
 /* check.c 23/01/95 03.38.30 */
 void check_page_tables (void);
+
 /* dir.c 22/06/95 00.22.12 */
 int compat_msdos_create(struct inode *dir,
 			const char *name,
@@ -10,10 +11,12 @@
 	 char *buf,
 	 size_t size,
 	 loff_t *count);
+void umsdos_lookup_patch_new(struct dentry *, struct umsdos_dirent *, off_t);
 void umsdos_lookup_patch (struct inode *dir,
 	 struct inode *inode,
 	 struct umsdos_dirent *entry,
 	 off_t emd_pos);
+int umsdos_dentry_to_entry (struct dentry *, struct umsdos_dirent *);
 int umsdos_inode2entry (struct inode *dir,
 	 struct inode *inode,
 	 struct umsdos_dirent *entry);
@@ -23,16 +26,16 @@
 			    struct inode *dir,
 			    struct dentry *dentry,
 			    int nopseudo);
-int UMSDOS_lookup(struct inode *dir,struct dentry *dentry);
+int UMSDOS_lookup(struct inode *, struct dentry *);
+struct dentry *umsdos_lookup_dentry(struct dentry *, char *, int);
 
 struct dentry *umsdos_solve_hlink (struct dentry *hlink);
+
 /* emd.c 22/06/95 00.22.04 */
 ssize_t umsdos_file_write_kmem_real (struct file *filp,
 				const char *buf,
 				size_t  count);
 
-int fix_emd_filp (struct file *filp);
-
 ssize_t umsdos_file_read_kmem (struct file *filp,
 	 char *buf,
 	 size_t count);
@@ -45,61 +48,52 @@
 ssize_t umsdos_emd_dir_read (struct file *filp,
 	 char *buf,
 	 size_t count);
+struct dentry *umsdos_get_emd_dentry(struct dentry *);
+int umsdos_have_emd(struct dentry *);
+int umsdos_make_emd(struct dentry *);
 struct inode *umsdos_emd_dir_lookup (struct inode *dir, int creat);
-int umsdos_emd_dir_readentry (struct file *filp,
-	 struct umsdos_dirent *entry);
-int umsdos_writeentry (struct inode *dir,
-	 struct inode *emd_dir,
-	 struct umsdos_info *info,
-	 int free_entry);
-int umsdos_newentry (struct inode *dir, struct umsdos_info *info);
-int umsdos_newhidden (struct inode *dir, struct umsdos_info *info);
-int umsdos_delentry (struct inode *dir,
-	 struct umsdos_info *info,
-	 int isdir);
-int umsdos_isempty (struct inode *dir);
-int umsdos_findentry (struct inode *dir,
-	 struct umsdos_info *info,
-	 int expect);
+int umsdos_emd_dir_readentry (struct file *, struct umsdos_dirent *);
+int umsdos_newentry (struct dentry *, struct umsdos_info *);
+int umsdos_newhidden (struct dentry *, struct umsdos_info *);
+int umsdos_delentry (struct dentry *, struct umsdos_info *, int);
+int umsdos_findentry (struct dentry *, struct umsdos_info *, int);
+int umsdos_isempty (struct dentry *);
+
 /* file.c 25/01/95 02.25.38 */
+
 /* inode.c 12/06/95 09.49.40 */
 inline struct dentry *geti_dentry (struct inode *inode);
 void checkd_inode (struct inode *inode);
-inline void inc_count (struct inode *inode);
 void check_inode (struct inode *inode);
 void check_dentry (struct dentry *dentry);
 void check_dentry_path (struct dentry *dentry, const char *desc);
 void fill_new_filp (struct file *filp, struct dentry *dentry);
-void kill_dentry (struct dentry *dentry);
-void fin_dentry (struct dentry *dentry);
 struct dentry *creat_dentry (const char *name,
 			     const int len,
 			     struct inode *inode,
 			     struct dentry *parent);
-void UMSDOS_put_inode (struct inode *inode);
-void UMSDOS_put_super (struct super_block *sb);
-int UMSDOS_statfs (struct super_block *sb,
-	 struct statfs *buf,
-	 int bufsiz);
+void UMSDOS_read_inode (struct inode *);
+void UMSDOS_write_inode (struct inode *);
+int UMSDOS_notify_change (struct dentry *, struct iattr *attr);
+void UMSDOS_put_inode (struct inode *);
+int UMSDOS_statfs (struct super_block *, struct statfs *, int);
+struct super_block *UMSDOS_read_super (struct super_block *, void *, int);
+void UMSDOS_put_super (struct super_block *);
+
 struct dentry *compat_umsdos_real_lookup (struct dentry *d_dir,
 	 const char *name,
 	 int len);
-int umsdos_real_lookup(struct inode *inode,struct dentry *dentry);	 
+int umsdos_real_lookup(struct inode *, struct dentry *);	 
+void umsdos_setup_dir(struct dentry *);
 void umsdos_setup_dir_inode (struct inode *inode);
 void umsdos_set_dirinfo (struct inode *inode,
 	 struct inode *dir,
 	 off_t f_pos);
 int umsdos_isinit (struct inode *inode);
-void umsdos_patch_inode (struct inode *inode,
-	 struct inode *dir,
-	 off_t f_pos);
+void umsdos_patch_dentry_inode (struct dentry *, off_t);
+void umsdos_patch_inode (struct inode *, struct inode *, off_t);
 int umsdos_get_dirowner (struct inode *inode, struct inode **result);
-void UMSDOS_read_inode (struct inode *inode);
-void UMSDOS_write_inode (struct inode *inode);
-int UMSDOS_notify_change (struct dentry *dentry, struct iattr *attr);
-struct super_block *UMSDOS_read_super (struct super_block *s,
-	 void *data,
-	 int silent);
+
 /* ioctl.c 22/06/95 00.22.08 */
 int UMSDOS_ioctl_dir (struct inode *dir,
 	 struct file *filp,
@@ -109,6 +103,7 @@
 void umsdos_manglename (struct umsdos_info *info);
 int umsdos_evalrecsize (int len);
 int umsdos_parse (const char *name,int len, struct umsdos_info *info);
+
 /* namei.c 25/01/95 02.25.38 */
 void umsdos_lockcreate (struct inode *dir);
 void umsdos_startlookup (struct inode *dir);
@@ -141,6 +136,7 @@
 		   struct dentry *old_dentry,
 		   struct inode *new_dir,
 		   struct dentry *new_dentry);
+
 /* rdir.c 22/03/95 03.31.42 */
 int umsdos_rlookup_x (struct inode *dir,
 	 struct dentry *dentry,
diff -u --recursive --new-file v2.1.120/linux/init/main.c linux/init/main.c
--- v2.1.120/linux/init/main.c	Sat Sep  5 16:46:42 1998
+++ linux/init/main.c	Wed Sep  9 08:56:59 1998
@@ -17,7 +17,6 @@
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/tty.h>
-#include <linux/head.h>
 #include <linux/unistd.h>
 #include <linux/string.h>
 #include <linux/timer.h>
@@ -84,6 +83,11 @@
 extern void filescache_init(void);
 extern void signals_init(void);
 
+extern void device_setup(void);
+extern void binfmt_setup(void);
+extern void free_initmem(void);
+extern void filesystem_setup(void);
+
 #ifdef CONFIG_ARCH_ACORN
 extern void ecard_init(void);
 #endif
@@ -1109,6 +1113,14 @@
 
 	smp_init();
 
+	/*
+	 * Ok, the machine is now initialized. None of the devices
+	 * have been touched yet, but the CPU subsystem is up and
+	 * running, and memory management works.
+	 *
+	 * Now we can finally start doing some real work..
+	 */
+
 #if defined(CONFIG_MTRR)	/* Do this after SMP initialization */
 /*
  * We should probably create some architecture-dependent "fixup after
@@ -1182,7 +1194,7 @@
 }
 #endif
 
-static int init(void * unused)
+static void __init do_basic_setup(void)
 {
 #ifdef CONFIG_BLK_DEV_INITRD
 	int real_root_mountflags;
@@ -1211,7 +1223,18 @@
 	if (initrd_start && mount_initrd) root_mountflags &= ~MS_RDONLY;
 	else mount_initrd =0;
 #endif
-	setup(0);
+
+	/* Set up devices .. */
+	device_setup();
+
+	/* .. executable formats .. */
+	binfmt_setup();
+
+	/* .. filesystems .. */
+	filesystem_setup();
+
+	/* Mount the root filesystem.. */
+	mount_root();
 
 #ifdef CONFIG_UMSDOS_FS
 	{
@@ -1247,9 +1270,19 @@
 		}
 	}
 #endif
+}
+
+static int init(void * unused)
+{
+	do_basic_setup();
+
+	/*
+	 * Ok, we have completed the initial bootup, and
+	 * we're essentially up and running. Get rid of the
+	 * initmem segments and start the user-mode stuff..
+	 */
+	free_initmem();
 
-	setup(1);
-	
 	if (open("/dev/console", O_RDWR, 0) < 0)
 		printk("Warning: unable to open an initial console.\n");
 
diff -u --recursive --new-file v2.1.120/linux/kernel/panic.c linux/kernel/panic.c
--- v2.1.120/linux/kernel/panic.c	Wed Aug 26 11:37:45 1998
+++ linux/kernel/panic.c	Sun Sep  6 10:34:34 1998
@@ -19,6 +19,10 @@
 #include <linux/sysrq.h>
 #include <linux/interrupt.h>
 
+#ifdef __alpha__
+#include <asm/machvec.h>
+#endif
+
 asmlinkage void sys_sync(void);	/* it's really int */
 extern void unblank_console(void);
 extern int C_A_D;
@@ -70,9 +74,12 @@
 #ifdef __sparc__
 	printk("Press L1-A to return to the boot prom\n");
 #endif
+#ifdef __alpha__
+	if (alpha_using_srm)
+		halt();
+#endif
 	sti();
 	for(;;) {
 		CHECK_EMERGENCY_SYNC
 	}
 }
-
diff -u --recursive --new-file v2.1.120/linux/lib/string.c linux/lib/string.c
--- v2.1.120/linux/lib/string.c	Tue Apr 23 03:24:52 1996
+++ linux/lib/string.c	Sun Sep  6 11:19:15 1998
@@ -13,6 +13,34 @@
  
 #include <linux/types.h>
 #include <linux/string.h>
+#include <linux/ctype.h>
+
+#ifndef __HAVE_ARCH_STRNICMP
+int strnicmp(const char *s1, const char *s2, size_t len)
+{
+	/* Yes, Virginia, it had better be unsigned */
+	unsigned char c1, c2;
+
+	c1 = 0;	c2 = 0;
+	if (len) {
+		do {
+			c1 = *s1; c2 = *s2;
+			s1++; s2++;
+			if (!c1)
+				break;
+			if (!c2)
+				break;
+			if (c1 == c2)
+				continue;
+			c1 = tolower(c1);
+			c2 = tolower(c2);
+			if (c1 != c2)
+				break;
+		} while (--len);
+	}
+	return (int)c1 - (int)c2;
+}
+#endif
 
 char * ___strtok = NULL;
 
diff -u --recursive --new-file v2.1.120/linux/mm/memory.c linux/mm/memory.c
--- v2.1.120/linux/mm/memory.c	Thu Aug  6 14:06:34 1998
+++ linux/mm/memory.c	Wed Sep  9 08:56:59 1998
@@ -35,7 +35,6 @@
 
 #include <linux/signal.h>
 #include <linux/sched.h>
-#include <linux/head.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/string.h>
diff -u --recursive --new-file v2.1.120/linux/mm/page_alloc.c linux/mm/page_alloc.c
--- v2.1.120/linux/mm/page_alloc.c	Wed Aug 26 11:37:45 1998
+++ linux/mm/page_alloc.c	Wed Sep  9 08:56:59 1998
@@ -8,7 +8,6 @@
 #include <linux/config.h>
 #include <linux/mm.h>
 #include <linux/sched.h>
-#include <linux/head.h>
 #include <linux/kernel.h>
 #include <linux/kernel_stat.h>
 #include <linux/errno.h>
diff -u --recursive --new-file v2.1.120/linux/mm/page_io.c linux/mm/page_io.c
--- v2.1.120/linux/mm/page_io.c	Tue Jul 21 00:15:33 1998
+++ linux/mm/page_io.c	Wed Sep  9 08:56:59 1998
@@ -11,7 +11,6 @@
 
 #include <linux/mm.h>
 #include <linux/sched.h>
-#include <linux/head.h>
 #include <linux/kernel.h>
 #include <linux/kernel_stat.h>
 #include <linux/errno.h>
diff -u --recursive --new-file v2.1.120/linux/mm/swap.c linux/mm/swap.c
--- v2.1.120/linux/mm/swap.c	Thu Aug 20 17:05:19 1998
+++ linux/mm/swap.c	Wed Sep  9 08:56:59 1998
@@ -15,7 +15,6 @@
 
 #include <linux/mm.h>
 #include <linux/sched.h>
-#include <linux/head.h>
 #include <linux/kernel.h>
 #include <linux/kernel_stat.h>
 #include <linux/errno.h>
diff -u --recursive --new-file v2.1.120/linux/mm/swap_state.c linux/mm/swap_state.c
--- v2.1.120/linux/mm/swap_state.c	Sat Sep  5 16:46:42 1998
+++ linux/mm/swap_state.c	Wed Sep  9 08:56:59 1998
@@ -9,7 +9,6 @@
 
 #include <linux/mm.h>
 #include <linux/sched.h>
-#include <linux/head.h>
 #include <linux/kernel.h>
 #include <linux/kernel_stat.h>
 #include <linux/errno.h>
diff -u --recursive --new-file v2.1.120/linux/mm/swapfile.c linux/mm/swapfile.c
--- v2.1.120/linux/mm/swapfile.c	Sat Sep  5 16:46:42 1998
+++ linux/mm/swapfile.c	Wed Sep  9 08:56:59 1998
@@ -9,7 +9,6 @@
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/sched.h>
-#include <linux/head.h>
 #include <linux/kernel.h>
 #include <linux/kernel_stat.h>
 #include <linux/errno.h>
diff -u --recursive --new-file v2.1.120/linux/mm/vmscan.c linux/mm/vmscan.c
--- v2.1.120/linux/mm/vmscan.c	Wed Aug 26 11:37:45 1998
+++ linux/mm/vmscan.c	Wed Sep  9 08:56:59 1998
@@ -12,7 +12,6 @@
 
 #include <linux/mm.h>
 #include <linux/sched.h>
-#include <linux/head.h>
 #include <linux/kernel.h>
 #include <linux/kernel_stat.h>
 #include <linux/errno.h>
diff -u --recursive --new-file v2.1.120/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- v2.1.120/linux/net/ipv4/tcp_input.c	Sat Sep  5 16:46:42 1998
+++ linux/net/ipv4/tcp_input.c	Tue Sep  8 23:30:35 1998
@@ -292,7 +292,7 @@
 			/* The retransmission queue is always in order, so
 			 * we can short-circuit the walk early.
 			 */
-			if(!before(start_seq, TCP_SKB_CB(skb)->end_seq))
+			if(after(TCP_SKB_CB(skb)->end_seq, end_seq))
 				break;
 
 			/* We play conservative, we don't allow SACKS to partially
@@ -471,10 +471,9 @@
                  * to one half the current congestion window, but no less 
                  * than two segments. Retransmit the missing segment.
                  */
+                tp->dup_acks++;
 		if (tp->high_seq == 0 || after(ack, tp->high_seq)) {
-			tp->dup_acks++;
 			if ((tp->fackets_out > 3) || (tp->dup_acks == 3)) {
-				tp->dup_acks++;
                                 tp->snd_ssthresh = max(tp->snd_cwnd >> (TCP_CWND_SHIFT + 1), 2);
                                 tp->snd_cwnd = (tp->snd_ssthresh + 3) << TCP_CWND_SHIFT;
 				tp->high_seq = tp->snd_nxt;
@@ -1712,6 +1711,10 @@
 	 */
 
 	if (flg == tp->pred_flags && TCP_SKB_CB(skb)->seq == tp->rcv_nxt) {
+		if (!tcp_sequence(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq)) {
+			tcp_send_ack(sk);
+			goto discard;
+		}
 		if (len <= th->doff*4) {
 			/* Bulk data transfer: sender */
 			if (len == th->doff*4) {
@@ -1726,13 +1729,8 @@
 			}
 		} else if (TCP_SKB_CB(skb)->ack_seq == tp->snd_una) {
 			/* Bulk data transfer: receiver */
-			if (atomic_read(&sk->rmem_alloc) > sk->rcvbuf) {
-				/* We must send an ACK for zero window probes. */
-				if (!before(TCP_SKB_CB(skb)->seq,
-						tp->rcv_wup + tp->rcv_wnd))
-					tcp_send_ack(sk);
+			if (atomic_read(&sk->rmem_alloc) > sk->rcvbuf)
 				goto discard;
-			}
 			
 			__skb_pull(skb,th->doff*4);
 
diff -u --recursive --new-file v2.1.120/linux/net/sunrpc/clnt.c linux/net/sunrpc/clnt.c
--- v2.1.120/linux/net/sunrpc/clnt.c	Sat Sep  5 16:46:42 1998
+++ linux/net/sunrpc/clnt.c	Sat Sep  5 17:13:38 1998
@@ -413,7 +413,6 @@
 		return;
 	printk("RPC: buffer allocation failed for task %p\n", task); 
 
-	checksignals();
 	if (!signalled()) {
 		xprt_release(task);
 		task->tk_action = call_reserve;
diff -u --recursive --new-file v2.1.120/linux/net/sunrpc/sched.c linux/net/sunrpc/sched.c
--- v2.1.120/linux/net/sunrpc/sched.c	Sat Sep  5 16:46:42 1998
+++ linux/net/sunrpc/sched.c	Sat Sep  5 17:14:17 1998
@@ -420,7 +420,6 @@
 			 * When the task received a signal, remove from
 			 * any queues etc, and make runnable again.
 			 */
-			checksignals();
 			if (signalled())
 				__rpc_wake_up(task);
 
@@ -435,7 +434,6 @@
 		 * clean up after sleeping on some queue, we don't
 		 * break the loop here, but go around once more.
 		 */
-		checksignals();
 		if (!RPC_IS_ASYNC(task) && signalled()) {
 			dprintk("RPC: %4d got signal\n", task->tk_pid);
 			rpc_exit(task, -ERESTARTSYS);
@@ -555,7 +553,6 @@
 		if (flags & RPC_TASK_ASYNC)
 			return NULL;
 		current->timeout = jiffies + (HZ >> 4);
-		checksignals();
 		current->state = TASK_INTERRUPTIBLE;
 		schedule();
 	} while (!signalled());
@@ -802,7 +799,6 @@
 
 	dprintk("RPC: rpciod starting (pid %d)\n", rpciod_pid);
 	while (rpciod_users) {
-		checksignals();
 		if (signalled()) {
 			rpciod_killall();
 			flush_signals(current);
@@ -931,7 +927,6 @@
 	 */
 	while (rpciod_pid) {
 		dprintk("rpciod_down: waiting for pid %d to exit\n", rpciod_pid);
-		checksignals();
 		if (signalled()) {
 			dprintk("rpciod_down: caught signal\n");
 			break;
diff -u --recursive --new-file v2.1.120/linux/net/sunrpc/svcsock.c linux/net/sunrpc/svcsock.c
--- v2.1.120/linux/net/sunrpc/svcsock.c	Sat Sep  5 16:46:42 1998
+++ linux/net/sunrpc/svcsock.c	Sat Sep  5 17:13:49 1998
@@ -736,7 +736,6 @@
 	rqstp->rq_argbuf = rqstp->rq_defbuf;
 	rqstp->rq_resbuf = rqstp->rq_defbuf;
 
-	checksignals();
 	if (signalled())
 		return -EINTR;
 
@@ -755,7 +754,6 @@
 		 * We have to be able to interrupt this wait
 		 * to bring down the daemons ...
 		 */
-		checksignals();
 		current->state = TASK_INTERRUPTIBLE;
 		add_wait_queue(&rqstp->rq_wait, &wait);
 		end_bh_atomic();
