diff -u --recursive --new-file v2.1.44/linux/CREDITS linux/CREDITS
--- v2.1.44/linux/CREDITS	Mon Jul  7 08:19:59 1997
+++ linux/CREDITS	Wed Jul 16 19:22:50 1997
@@ -81,6 +81,14 @@
 S: Notre Dame, Indiana
 S: USA
 
+N: James Banks
+E: james.banks@caldera.com
+D: TLAN network driver
+S: Caldera, Inc.
+S: 633 South 550 East
+S: Provo, UT 84606
+S: USA
+
 N: Peter Bauer
 E: 100136.3530@compuserve.com
 D: Driver for depca-ethernet-board
@@ -107,7 +115,9 @@
 
 N: Randolph Bentson
 E: bentson@grieg.seaslug.org
-D: author of driver for Cyclades Cyclom-Y async mux
+D: author of driver for Cyclom-Y and Cyclades-Z async mux
+P: 1024/39ED5729 5C A8 7A F4 B2 7A D1 3E  B5 3B 81 CF 47 30 11 71
+W: http://www.aa.net/~bentson/
 S: 2322 37th Ave SW
 S: Seattle, Washington 98126-2010
 S: USA
@@ -793,6 +803,12 @@
 S: D-91080 Uttenreuth
 S: Germany
 
+N: Jaroslav Kysela
+E: perex@jcu.cz
+D: Original Author and Maintainer for HP 10/100 Mbit Network Adapters
+W: http://www.pf.jcu.cz/~perex
+S: Unix Centre of Pedagogical Faculty, University of South Bohemia
+
 N: Bas Laarhoven
 E: bas@vimec.nl
 D: Loadable modules and ftape driver
@@ -842,6 +858,13 @@
 S: North Little Rock, Arkansas 72115
 S: US
 
+N: Siegfried "Frieder" Loeffler (dg1sek)
+E: floeff@tunix.mathematik.uni-stuttgart.de, fl@LF.net
+W: http://www.mathematik.uni-stuttgart.de/~floeff
+D: Busmaster driver for HP 10/100 Mbit Network Adapters
+S: University of Stuttgart, Germany  and
+S: Ecole Nationale Superieure des Telecommunications, Paris
+
 N: Martin von Loewis
 E: loewis@informatik.hu-berlin.de
 D: script binary format
@@ -956,12 +979,13 @@
 S: Germany
 
 N: Michael Meskes
-E: meskes@informatik.rwth-aachen.de
+E: meskes@topsystem.de
+P: 1024/04B6E8F5 6C 77 33 CA CC D6 22 03  AB AB 15 A3 AE AD 39 7D
 D: Kernel hacker. Software watchdog daemon.
 D: Maintainer of several Debian packages
-S: Lehrstuhl fuer angewandte Mathematik insb. Informatik
-S: RWTH-Aachen
-S: D-52056 Aachen
+S: topsystem Systemhaus GmbH
+S: Europark A2, Adenauerstr. 20
+S: D-52146 Wuerselen
 S: Germany
 
 N: Nigel Metheringham
diff -u --recursive --new-file v2.1.44/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.1.44/linux/Documentation/Configure.help	Thu Jun 26 12:33:36 1997
+++ linux/Documentation/Configure.help	Wed Jul 16 19:22:50 1997
@@ -3308,6 +3308,14 @@
   Multiple-Ethernet-mini-HOWTO, available from
   sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
 
+TI ThunderLAN support (EXPERIMENTAL)
+CONFIG_TLAN
+  If you have a TLAN based network card which is supported by this
+  driver, say Y and read the Ethernet-HOWTO.  Devices currently supported
+  are the Compaq Netelligent 10, Netelligent 10/100, and Internal
+  NetFlex 3.  This driver is also available as a module.  Please email
+  feedback to james.banks@caldera.com.
+
 Zenith Z-Note support
 CONFIG_ZNET
   The Zenith Z-Note notebook computer has a built-in network
@@ -4384,6 +4392,12 @@
   you are unsure, try first to say N here and come back if the mouse
   doesn't work. Read the Busmouse-HOWTO, available via ftp (user:
   anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO.
+
+PC110 digitizer pad support
+CONFIG_PC110_PAD
+  This drives the digitizer pad on the IBM PC110 palmtop (see 
+  http://toy.cabi.net). It can turn the digitizer pad into a 
+  mouse emulation with tap gestures or into an absolute pad.
 
 Microsoft busmouse support
 CONFIG_MS_BUSMOUSE
diff -u --recursive --new-file v2.1.44/linux/Documentation/binfmt_misc.txt linux/Documentation/binfmt_misc.txt
--- v2.1.44/linux/Documentation/binfmt_misc.txt	Tue Jul  1 08:55:56 1997
+++ linux/Documentation/binfmt_misc.txt	Wed Jul 16 07:47:32 1997
@@ -1,26 +1,26 @@
-	Kernel Support for miscellaneous (your favourite) Binary Formats v1.1
-	=====================================================================
+     Kernel Support for miscellaneous (your favourite) Binary Formats v1.1
+     =====================================================================
 
 This Kernel feature allows to invoke almost (for restrictions see below) every
-program by simply typing it's name in the shell.
+program by simply typing its name in the shell.
 This includes for example compiled Java(TM), Python or Emacs programs.
 
-To achieve this you must tell binfmt_misc which interpreter has to be invoked with
-which binary. Binfmt_misc recognises the binary-type by matching some bytes at the
-beginning of the file with a magic byte sequence (masking out specified bits) you
-have supplied. Binfmt_misc can also recognise a filename extension (aka .com) and
-optionally strip it off.
+To achieve this you must tell binfmt_misc which interpreter has to be invoked
+with which binary. Binfmt_misc recognises the binary-type by matching some bytes
+at the beginning of the file with a magic byte sequence (masking out specified
+bits) you have supplied. Binfmt_misc can also recognise a filename extension
+(aka .com) and optionally strip it off.
 
 To actually register a new binary type, you have to set up a string looking like
-:name:type:offset:magic:mask:interpreter: (where you can choose the ':' upon your
-needs) and echo it to /proc/sys/fs/binfmt_misc/register.
+:name:type:offset:magic:mask:interpreter: (where you can choose the ':' upon
+your needs) and echo it to /proc/sys/fs/binfmt_misc/register.
 Here is what the fields mean:
  - 'name' is an identifier string. A new /proc file will be created with this
-   this name below /proc/sys/fs/binfmt_misc
+   name below /proc/sys/fs/binfmt_misc
  - 'type' is the type of recognition. Give 'M' for magic and 'E' for extension.
-   Give the corresponding lowercase letter to let binfmt_misc strip of the
+   Give the corresponding lowercase letter to let binfmt_misc strip off the
    filename extension.
- - 'offset' is the offset of the magic/mask in the file counted in bytes. This
+ - 'offset' is the offset of the magic/mask in the file, counted in bytes. This
    defaults to 0 if you omit it (i.e. you write ':name:type::magic...')
  - 'magic' is the byte sequence binfmt_misc is matching for. The magic string
    may contain hex-encoded characters like \x0a or \xA4. In a shell environment
@@ -28,26 +28,23 @@
    If you chose filename extension matching, this is the extension to be
    recognised (the \x0a specials are not allowed). Extension matching is case
    sensitive!
- - 'mask' is an (optional, defaults to all 0xff) mask. You can mask out some bits
-   from matching by supplying a string like magic and as long as magic. The
-   mask is anded with the byte sequence of the file.
+ - 'mask' is an (optional, defaults to all 0xff) mask. You can mask out some
+   bits from matching by supplying a string like magic and as long as magic.
+   The mask is anded with the byte sequence of the file.
  - 'interpreter' is the program that should be invoked with the binary as first
    argument (specify the full path)
 There are some restrictions:
  - the whole register string may not exceed 255 characters
- - the magic must resist in the first 128 bytes of the file, i.e. offset+size(magic)
-   has to be less than 128
+ - the magic must resist in the first 128 bytes of the file, i.e.
+   offset+size(magic) has to be less than 128
  - the interpreter string may not exceed 127 characters
-You may want to add the binary formats in one of your /etc/rc scripts during boot-up.
-Read the manual of your init program to figure out how to do this right.
+You may want to add the binary formats in one of your /etc/rc scripts during
+boot-up. Read the manual of your init program to figure out how to do this
+right.
 
 
 A few examples (assumed you are in /proc/sys/fs/binfmt_misc):
 
-- enable Java(TM)-support (like binfmt_java):
-  echo ":Java:M::\xca\xfe\xba\xbe::/usr/local/bin/java:" > register
-  echo :Applet:M::\<\!--applet::/usr/local/bin/appletviewer: > register
-
 - enable support for em86 (like binfmt_em86, for Alpha AXP only):
   echo ":i386:M::\x7fELF\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff:/bin/em86:" > register
   echo ":i486:M::\x7fELF\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff:/bin/em86:" > register
@@ -57,8 +54,9 @@
 
 - enable support for DOS/Windows executables (using mzloader and dosemu/wine):
   echo ":DOSWin:M::MZ::/usr/sbin/mzloader:" > register
-  echo ":DOS:E::com::/usr/sbin/mzloader:" > register
-  echo ":DOS2:E::exe::/usr/sbin/mzloader:" > register
+  echo ":DOScom:E::com::/usr/sbin/mzloader:" > register
+  echo ":DOSexe:E::exe::/usr/sbin/mzloader:" > register
+
 
 You can enable/disable binfmt_misc or one binary type by echoing 0 (to disable)
 or 1 (to enable) to /proc/sys/fs/binfmt_misc/status or /proc/.../the_name.
@@ -66,6 +64,25 @@
 
 You can remove one entry or all entries by echoing -1 to /proc/.../the_name
 or /proc/sys/fs/binfmt_misc/status.
+
+
+Emulating binfmt_java:
+======================
+
+To emulate binfmt_java the following register-strings are necessary
+(the first two for byte-compiled Java binaries, the third for applets
+contained in a html-file). Register exactly in this order!
+  ":Java:M::\xca\xfe\xba\xbe::/usr/local/java/bin/java:"
+  ":JavaC:e::class::/usr/local/java/bin/java:"
+  ":Applet:E::html::/usr/local/java/bin/appletviewer:"
+
+To add a Java-executable to your path you can either make a symbolic
+link to the .class file elsewhere in your path (cut the .class-extension
+in the destination name for convenience) or add the directory of your
+.class files to your PATH environment. In both cases, ensure that the
+.class files are in your CLASSPATH environment!
+
+This is sort of ugly - Javas filename handling is just broken.
 
 
 HINTS:
diff -u --recursive --new-file v2.1.44/linux/Documentation/networking/wan-router.txt linux/Documentation/networking/wan-router.txt
--- v2.1.44/linux/Documentation/networking/wan-router.txt	Sun Feb  2 05:18:29 1997
+++ linux/Documentation/networking/wan-router.txt	Wed Jul 16 19:22:50 1997
@@ -1,10 +1,11 @@
 ------------------------------------------------------------------------------
 WAN Router for Linux Operating System
 ------------------------------------------------------------------------------
-Version 1.0.0
-December 31, 1996
-Author: Gene Kozin <genek@compuserve.com>
-Copyright (c) 1995-1996 Sangoma Technologies Inc.
+Version 1.0.3 - June 3, 1997
+Version 1.0.1 - January 30, 1997
+Author: Jaspreet Singh <jaspreet@sangoma.com>
+	Gene Kozin <genek@compuserve.com>
+Copyright (c) 1995-1997 Sangoma Technologies Inc.
 ------------------------------------------------------------------------------
 
 INTRODUCTION
@@ -95,12 +96,6 @@
 
 
 
-KNOWN BUGS AND LIMITATIONS
-
-/proc user interface is not complete yet.
-
-
-
 ACKNOLEGEMENTS
 
 This product is based on the WANPIPE(tm) Multiprotocol WAN Router developed
@@ -122,9 +117,19 @@
 
 
 REVISION HISTORY
+1.0.3	June 3, 1997
+	o UDP port for multiple boards (Frame relay, PPP)
+	o Continuous Transmission of Configure Request Packet for PPP (this
+	  support is only added for 508 cards)
+	o Connection Timeout for PPP changed from 900 to 0
+	o Flow Control for multiple boards and multiple channels (Frame Relay)
+
+1.0.1	January 30, 1997
+
+	o Implemented user-readable status and statistics via /proc filesystem
+
+1.0.0	December 31, 1996
 
-1.0.0	 December 31, 1996
---------------------------
- o Initial version.
+	o Initial version
 
 >>>>>> END <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
diff -u --recursive --new-file v2.1.44/linux/MAINTAINERS linux/MAINTAINERS
--- v2.1.44/linux/MAINTAINERS	Thu Jun 26 12:33:36 1997
+++ linux/MAINTAINERS	Wed Jul 16 19:22:50 1997
@@ -95,6 +95,12 @@
 L:	linux-net@vger.rutgers.edu
 S:	Maintained
 
+TLAN NETWORK DRIVER
+P:	James Banks
+M:	james.banks@caldera.com
+L:	linux-net@vger.rutgers.edu
+S:	Supported
+
 DIGI RIGHTSWITCH NETWORK DRIVER
 P:	Rick Richardson
 M:	rick@dgii.com
@@ -107,6 +113,11 @@
 M:	jt@hplb.hpl.hp.com
 S:	Maintained
 
+HP100: Driver for HP 10/100 Mbit/s Network Adapter Series
+P:	Jarsolav Kysela
+M:	perex@jcu.cz
+S:	Maintained
+
 APM DRIVER
 P:	Rik Faith & Stephen Rothwell
 M:	faith@cs.unc.edu, Stephen.Rothwell@canb.auug.org.au
@@ -217,10 +228,10 @@
 S:	Maintained
 
 IPX NETWORK LAYER
-P:	Alan Cox [for the moment]
-M:	net-patches@lxorguk.ukuu.org.uk
-L:	linux-ipx@vger.rutgers.edu [will change]
-S:	Maintained
+P:	
+M:
+L:	
+S:	Orphan
 
 IDE DRIVER [GENERAL]
 P:	Mark Lord
@@ -280,10 +291,10 @@
 S:	Maintained
 
 NETWORKING [GENERAL]:
-P:	Alan Cox
-M:	net-patches@lxorguk.ukuu.org.uk
+P:	Networking Teak
+M:	netdev@nuclecu.unam.mx
 L:	linux-net@vger.rutgers.edu
-W:	http://www.uk.linux.org/NetNews.html
+W:	http://www.uk.linux.org/NetNews.html (2.0 only)
 S:	Maintained
 
 NETWORKING [IPv4/IPv6]:
@@ -326,8 +337,8 @@
 S:	Maintained
 
 SMP: (except SPARC)
-P:	Alan Cox
-M:	smp-patches@lxorguk.ukuu.org.uk
+P:	Linus Torvalds
+M:	torvalds@transmeta.com
 L:	linux-smp@vger.rutgers.edu
 S:	Maintained
 
diff -u --recursive --new-file v2.1.44/linux/Makefile linux/Makefile
--- v2.1.44/linux/Makefile	Thu Jun 26 12:33:36 1997
+++ linux/Makefile	Fri Jul 11 11:20:54 1997
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 1
-SUBLEVEL = 44
+SUBLEVEL = 45
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/)
 
diff -u --recursive --new-file v2.1.44/linux/arch/alpha/defconfig linux/arch/alpha/defconfig
--- v2.1.44/linux/arch/alpha/defconfig	Tue Jul  1 23:23:47 1997
+++ linux/arch/alpha/defconfig	Sun Jul 13 21:20:10 1997
@@ -66,7 +66,7 @@
 #
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_MD is not set
-CONFIG_BLK_DEV_RAM=y
+# CONFIG_BLK_DEV_RAM is not set
 # CONFIG_BLK_DEV_INITRD is not set
 # CONFIG_BLK_DEV_XD is not set
 # CONFIG_BLK_DEV_EZ is not set
@@ -195,9 +195,6 @@
 # Filesystems
 #
 # CONFIG_QUOTA is not set
-# CONFIG_DCACHE_PRELOAD is not set
-# CONFIG_OMIRR is not set
-# CONFIG_TRANS_NAMES is not set
 # CONFIG_MINIX_FS is not set
 CONFIG_EXT2_FS=y
 # CONFIG_FAT_FS is not set
@@ -205,12 +202,13 @@
 # CONFIG_VFAT_FS is not set
 # CONFIG_UMSDOS_FS is not set
 CONFIG_PROC_FS=y
-# CONFIG_NFS_FS is not set
+CONFIG_NFS_FS=y
+# CONFIG_ROOT_NFS is not set
 # CONFIG_NFSD is not set
-# CONFIG_SUNRPC is not set
-# CONFIG_LOCKD is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
 # CONFIG_SMB_FS is not set
-# CONFIG_ISO9660_FS is not set
+CONFIG_ISO9660_FS=y
 # CONFIG_HPFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_AFFS_FS is not set
diff -u --recursive --new-file v2.1.44/linux/arch/alpha/kernel/osf_sys.c linux/arch/alpha/kernel/osf_sys.c
--- v2.1.44/linux/arch/alpha/kernel/osf_sys.c	Tue Jul  1 23:23:47 1997
+++ linux/arch/alpha/kernel/osf_sys.c	Sun Jul 13 21:20:10 1997
@@ -135,30 +135,46 @@
 {
 	int error;
 	struct file *file;
+	struct dentry *dentry;
+	struct inode *inode;
 	struct osf_dirent_callback buf;
 
-	if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
-		return -EBADF;
-	if (!file->f_op || !file->f_op->readdir)
-		return -ENOTDIR;
-	error = verify_area(VERIFY_WRITE, dirent, count);
-	if (error)
-		return error;
-	if (basep) {
-		error = verify_area(VERIFY_WRITE, basep, sizeof(long));
-		if (error)
-			return error;
-	}
+	error = -EBADF;
+	if (fd >= NR_OPEN)
+		goto out;
+
+	file = current->files->fd[fd];
+	if (!file)
+		goto out;
+
+	dentry = file->f_dentry;
+	if (!dentry)
+		goto out;
+
+	inode = dentry->d_inode;
+	if (!inode)
+		goto out;
+
 	buf.dirent = dirent;
 	buf.basep = basep;
 	buf.count = count;
 	buf.error = 0;
-	error = file->f_op->readdir(file->f_inode, file, &buf, osf_filldir);
+
+	error = -ENOTDIR;
+	if (!file->f_op || !file->f_op->readdir)
+		goto out;
+
+	error = file->f_op->readdir(inode, file, &buf, osf_filldir);
 	if (error < 0)
-		return error;
+		goto out;
+
+	error = buf.error;
 	if (count == buf.count)
-		return buf.error;
-	return count - buf.count;
+		goto out;
+
+	error = count - buf.count;
+out:
+	return error;
 }
 
 /*
@@ -267,76 +283,73 @@
 	__kernel_fsid_t f_fsid;
 } *osf_stat;
 
-static void linux_to_osf_statfs(struct statfs *linux_stat, struct osf_statfs *osf_stat)
+static int linux_to_osf_statfs(struct statfs *linux_stat, struct osf_statfs *osf_stat, unsigned long bufsiz)
 {
-	osf_stat->f_type = linux_stat->f_type;
-	osf_stat->f_flags = 0;	/* mount flags */
+	struct osf_statfs tmp_stat;
+
+	tmp_stat.f_type = linux_stat->f_type;
+	tmp_stat.f_flags = 0;	/* mount flags */
 	/* Linux doesn't provide a "fundamental filesystem block size": */
-	osf_stat->f_fsize = linux_stat->f_bsize;
-	osf_stat->f_bsize = linux_stat->f_bsize;
-	osf_stat->f_blocks = linux_stat->f_blocks;
-	osf_stat->f_bfree = linux_stat->f_bfree;
-	osf_stat->f_bavail = linux_stat->f_bavail;
-	osf_stat->f_files = linux_stat->f_files;
-	osf_stat->f_ffree = linux_stat->f_ffree;
-	osf_stat->f_fsid = linux_stat->f_fsid;
+	tmp_stat.f_fsize = linux_stat->f_bsize;
+	tmp_stat.f_bsize = linux_stat->f_bsize;
+	tmp_stat.f_blocks = linux_stat->f_blocks;
+	tmp_stat.f_bfree = linux_stat->f_bfree;
+	tmp_stat.f_bavail = linux_stat->f_bavail;
+	tmp_stat.f_files = linux_stat->f_files;
+	tmp_stat.f_ffree = linux_stat->f_ffree;
+	tmp_stat.f_fsid = linux_stat->f_fsid;
+	if (bufsiz > sizeof(tmp_stat))
+		bufsiz = sizeof(tmp_stat);
+	return copy_to_user(osf_stat, &tmp_stat, bufsiz) ? -EFAULT : 0;
 }
 
+static int do_osf_statfs(struct dentry * dentry, struct osf_statfs *buffer, unsigned long bufsiz)
+{
+	struct statfs linux_stat;
+	struct inode * inode = dentry->d_inode;
+	struct super_block * sb = inode->i_sb;
+	int error;
+
+	error = -ENOSYS;
+	if (sb->s_op->statfs) {
+		set_fs(KERNEL_DS);
+		error = sb->s_op->statfs(sb, &linux_stat, sizeof(linux_stat));
+		set_fs(USER_DS);
+		if (!error)
+			error = linux_to_osf_statfs(&linux_stat, buffer, bufsiz);
+	}
+	return error;	
+}
 
 asmlinkage int osf_statfs(char *path, struct osf_statfs *buffer, unsigned long bufsiz)
 {
-	struct statfs linux_stat;
-	struct inode *inode;
+	struct dentry *dentry;
 	int retval;
 
 	lock_kernel();
-	if (bufsiz > sizeof(struct osf_statfs))
-		 bufsiz = sizeof(struct osf_statfs);
-	retval = verify_area(VERIFY_WRITE, buffer, bufsiz);
-	if (retval)
-		goto out;
-	retval = namei(path, &inode);
-	if (retval)
-		goto out;
-	retval = -ENOSYS;
-	if (!inode->i_sb->s_op->statfs) {
-		iput(inode);
-		goto out;
+	dentry = namei(path);
+	retval = PTR_ERR(dentry);
+	if (!IS_ERR(dentry)) {
+		retval = do_osf_statfs(dentry, buffer, bufsiz);
+		dput(dentry);
 	}
-	inode->i_sb->s_op->statfs(inode->i_sb, &linux_stat, sizeof(linux_stat));
-	linux_to_osf_statfs(&linux_stat, buffer);
-	iput(inode);
-	retval = 0;
-out:
 	unlock_kernel();
 	return retval;
 }
 
 asmlinkage int osf_fstatfs(unsigned long fd, struct osf_statfs *buffer, unsigned long bufsiz)
 {
-	struct statfs linux_stat;
 	struct file *file;
-	struct inode *inode;
+	struct dentry *dentry;
 	int retval;
 
 	lock_kernel();
-	retval = verify_area(VERIFY_WRITE, buffer, bufsiz);
-	if (retval)
-		goto out;
-	if (bufsiz > sizeof(struct osf_statfs))
-		 bufsiz = sizeof(struct osf_statfs);
 	retval = -EBADF;
 	if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
 		goto out;
-	retval = -ENOENT;
-	if (!(inode = file->f_inode))
-		goto out;
-	retval = -ENOSYS;
-	if (!inode->i_sb->s_op->statfs)
-		goto out;
-	inode->i_sb->s_op->statfs(inode->i_sb, &linux_stat, sizeof(linux_stat));
-	linux_to_osf_statfs(&linux_stat, buffer);
-	retval = 0;
+	dentry = file->f_dentry;
+	if (dentry)
+		retval = do_osf_statfs(dentry, buffer, bufsiz);
 out:
 	unlock_kernel();
 	return retval;
@@ -369,56 +382,60 @@
 	uid_t exroot;
 };
 
-static int getdev(const char *name, int rdonly, struct inode **ino)
+static int getdev(const char *name, int rdonly, struct dentry **dp)
 {
 	kdev_t dev;
+	struct dentry *dentry;
 	struct inode *inode;
 	struct file_operations *fops;
 	int retval;
 
-	retval = namei(name, &inode);
-	if (retval)
+	dentry = namei(name);
+	retval = PTR_ERR(dentry);
+	if (IS_ERR(dentry))
 		return retval;
+
+	inode = dentry->d_inode;
 	if (!S_ISBLK(inode->i_mode)) {
-		iput(inode);
+		dput(dentry);
 		return -ENOTBLK;
 	}
 	if (IS_NODEV(inode)) {
-		iput(inode);
+		dput(dentry);
 		return -EACCES;
 	}
 	dev = inode->i_rdev;
 	if (MAJOR(dev) >= MAX_BLKDEV) {
-		iput(inode);
+		dput(dentry);
 		return -ENXIO;
 	}
 	fops = get_blkfops(MAJOR(dev));
 	if (!fops) {
-		iput(inode);
+		dput(dentry);
 		return -ENODEV;
 	}
 	if (fops->open) {
 		struct file dummy;
 		memset(&dummy, 0, sizeof(dummy));
-		dummy.f_inode = inode;
+		dummy.f_dentry = dentry;
 		dummy.f_mode = rdonly ? 1 : 3;
 		retval = fops->open(inode, &dummy);
 		if (retval) {
-			iput(inode);
+			dput(dentry);
 			return retval;
 		}
 	}
-	*ino = inode;
+	*dp = dentry;
 	return 0;
 }
 
-static void putdev(struct inode *inode)
+static void putdev(struct dentry *dentry)
 {
 	struct file_operations *fops;
 
-	fops = get_blkfops(MAJOR(inode->i_rdev));
+	fops = get_blkfops(MAJOR(dentry->d_inode->i_rdev));
 	if (fops->release)
-		fops->release(inode, NULL);
+		fops->release(dentry->d_inode, NULL);
 }
 
 /*
@@ -429,40 +446,40 @@
 static int osf_ufs_mount(char *dirname, struct ufs_args *args, int flags)
 {
 	int retval;
-	struct inode *inode;
+	struct dentry *dentry;
 	struct cdfs_args tmp;
 
 	retval = verify_area(VERIFY_READ, args, sizeof(*args));
 	if (retval)
 		return retval;
 	copy_from_user(&tmp, args, sizeof(tmp));
-	retval = getdev(tmp.devname, 0, &inode);
+	retval = getdev(tmp.devname, 0, &dentry);
 	if (retval)
 		return retval;
-	retval = do_mount(inode->i_rdev, tmp.devname, dirname, "ext2", flags, NULL);
+	retval = do_mount(dentry->d_inode->i_rdev, tmp.devname, dirname, "ext2", flags, NULL);
 	if (retval)
-		putdev(inode);
-	iput(inode);
+		putdev(dentry);
+	dput(dentry);
 	return retval;
 }
 
 static int osf_cdfs_mount(char *dirname, struct cdfs_args *args, int flags)
 {
 	int retval;
-	struct inode *inode;
+	struct dentry * dentry;
 	struct cdfs_args tmp;
 
 	retval = verify_area(VERIFY_READ, args, sizeof(*args));
 	if (retval)
 		return retval;
 	copy_from_user(&tmp, args, sizeof(tmp));
-	retval = getdev(tmp.devname, 1, &inode);
+	retval = getdev(tmp.devname, 1, &dentry);
 	if (retval)
 		return retval;
-	retval = do_mount(inode->i_rdev, tmp.devname, dirname, "iso9660", flags, NULL);
+	retval = do_mount(dentry->d_inode->i_rdev, tmp.devname, dirname, "iso9660", flags, NULL);
 	if (retval)
-		putdev(inode);
-	iput(inode);
+		putdev(dentry);
+	dput(dentry);
 	return retval;
 }
 
diff -u --recursive --new-file v2.1.44/linux/arch/alpha/kernel/process.c linux/arch/alpha/kernel/process.c
--- v2.1.44/linux/arch/alpha/kernel/process.c	Tue May 13 22:41:00 1997
+++ linux/arch/alpha/kernel/process.c	Sun Jul 13 21:20:10 1997
@@ -308,8 +308,9 @@
 	char * filename;
 
 	lock_kernel();
-	error = getname((char *) a0, &filename);
-	if (error)
+	filename = getname((char *) a0);
+	error = PTR_ERR(filename);
+	if (IS_ERR(filename))
 		goto out;
 	error = do_execve(filename, (char **) a1, (char **) a2, &regs);
 	putname(filename);
diff -u --recursive --new-file v2.1.44/linux/arch/alpha/kernel/traps.c linux/arch/alpha/kernel/traps.c
--- v2.1.44/linux/arch/alpha/kernel/traps.c	Wed Apr 23 19:01:14 1997
+++ linux/arch/alpha/kernel/traps.c	Sun Jul 13 21:20:10 1997
@@ -24,13 +24,14 @@
 		   unsigned long *r9_15)
 {
 	long i;
-	unsigned long sp, ra;
+	unsigned long ra;
 	unsigned int * pc;
+	unsigned long * sp;
 
 	if (regs->ps & 8)
 		return;
 	printk("%s(%d): %s %ld\n", current->comm, current->pid, str, err);
-	sp = (unsigned long) (regs+1);
+	sp = (unsigned long *) (regs+1);
 	__get_user(ra, (unsigned long *)sp);
 	printk("pc = [<%016lx>] ps = %04lx\n", regs->pc, regs->ps);
 	printk("rp = [<%016lx>] ra = [<%016lx>]\n", regs->r26, ra);
@@ -54,7 +55,7 @@
 	printk("r22= %016lx  r23= %016lx\n", regs->r22, regs->r23);
 	printk("r24= %016lx  r25= %016lx\n", regs->r24, regs->r25);
 	printk("r27= %016lx  r28= %016lx\n", regs->r27, regs->r28);
-	printk("gp = %016lx  sp = %016lx\n", regs->gp, sp);
+	printk("gp = %016lx  sp = %p\n", regs->gp, sp);
 
 	printk("Code:");
 	pc = (unsigned int *) regs->pc;
@@ -65,6 +66,19 @@
 		printk("%c%08x%c",i?' ':'<',insn,i?' ':'>');
 	}
 	printk("\n");
+	printk("Trace:");
+	while (0x1ff8 & (unsigned long) sp) {
+		extern unsigned long _stext, _etext;
+		unsigned long tmp = *sp;
+		sp++;
+		if (tmp < (unsigned long) &_stext)
+			continue;
+		if (tmp >= (unsigned long) &_etext)
+			continue;
+		printk(" [<%lx>]", tmp);
+	}
+	printk("\n");
+		    
 	do_exit(SIGSEGV);
 }
 
diff -u --recursive --new-file v2.1.44/linux/arch/alpha/mm/fault.c linux/arch/alpha/mm/fault.c
--- v2.1.44/linux/arch/alpha/mm/fault.c	Thu May 15 16:48:01 1997
+++ linux/arch/alpha/mm/fault.c	Mon Jul 14 10:40:40 1997
@@ -67,8 +67,7 @@
 			      long cause, struct pt_regs *regs)
 {
 	struct vm_area_struct * vma;
-	struct task_struct *tsk = current;
-	struct mm_struct *mm = tsk->mm;
+	struct mm_struct *mm = current->mm;
 	unsigned fixup;
 
 	down(&mm->mmap_sem);
@@ -97,7 +96,7 @@
 		if (!(vma->vm_flags & VM_WRITE))
 			goto bad_area;
 	}
-	handle_mm_fault(tsk, vma, address, cause > 0);
+	handle_mm_fault(current, vma, address, cause > 0);
 	up(&mm->mmap_sem);
 	return;
 
@@ -108,23 +107,20 @@
 bad_area:
 	up(&mm->mmap_sem);
 
+	if (user_mode(regs)) {
+		force_sig(SIGSEGV, current);
+		return;
+	}
+
 	/* Are we prepared to handle this fault as an exception?  */
 	if ((fixup = search_exception_table(regs->pc)) != 0) {
 		unsigned long newpc;
 		newpc = fixup_exception(dpf_reg, fixup, regs->pc);
-		printk("Taking exception at [<%lx>] (%lx)\n", regs->pc, newpc);
+		printk("%s: Exception at [<%lx>] (%lx)\n", current->comm, regs->pc, newpc);
 		regs->pc = newpc;
 		return;
 	}
 
-	if (user_mode(regs)) {
-		printk("%s: memory violation at pc=%08lx ra=%08lx "
-		       "(bad address = %08lx)\n",
-			tsk->comm, regs->pc, regs->r26, address);
-		die_if_kernel("oops", regs, cause, (unsigned long*)regs - 16);
-		force_sig(SIGSEGV, tsk);
-		return;
-	}
 /*
  * Oops. The kernel tried to access some bad page. We'll have to
  * terminate things with extreme prejudice.
diff -u --recursive --new-file v2.1.44/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.1.44/linux/arch/i386/defconfig	Mon Jul  7 10:50:01 1997
+++ linux/arch/i386/defconfig	Wed Jul 16 20:04:35 1997
@@ -192,9 +192,6 @@
 # Filesystems
 #
 # CONFIG_QUOTA is not set
-# CONFIG_DCACHE_PRELOAD is not set
-# CONFIG_OMIRR is not set
-# CONFIG_TRANS_NAMES is not set
 # CONFIG_MINIX_FS is not set
 CONFIG_EXT2_FS=y
 # CONFIG_FAT_FS is not set
@@ -208,7 +205,7 @@
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 # CONFIG_SMB_FS is not set
-# CONFIG_ISO9660_FS is not set
+CONFIG_ISO9660_FS=y
 # CONFIG_HPFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_AFFS_FS is not set
@@ -230,12 +227,14 @@
 # CONFIG_MS_BUSMOUSE is not set
 CONFIG_PSMOUSE=y
 CONFIG_82C710_MOUSE=y
+# CONFIG_PC110_PAD is not set
 # CONFIG_UMISC is not set
 # CONFIG_QIC02_TAPE is not set
 # CONFIG_FTAPE is not set
 # CONFIG_APM is not set
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
+# CONFIG_JOYSTICK is not set
 
 #
 # Sound
diff -u --recursive --new-file v2.1.44/linux/arch/i386/kernel/bios32.c linux/arch/i386/kernel/bios32.c
--- v2.1.44/linux/arch/i386/kernel/bios32.c	Thu May 15 16:48:01 1997
+++ linux/arch/i386/kernel/bios32.c	Wed Jul 16 19:22:50 1997
@@ -1,7 +1,7 @@
 /*
  * bios32.c - BIOS32, PCI BIOS functions.
  *
- * $Id: bios32.c,v 1.11 1997/05/07 13:35:21 mj Exp $
+ * $Id: bios32.c,v 1.12 1997/06/26 13:33:46 mj Exp $
  *
  * Sponsored by
  *	iX Multiuser Multitasking Magazine
@@ -59,6 +59,8 @@
  *
  * May 7,  1997 : Added some missing cli()'s. [mj]
  * 
+ * Jun 20, 1997 : Corrected problems in "conf1" type accesses.
+ *      (paubert@iram.es)
  */
 
 #include <linux/config.h>
@@ -512,16 +514,7 @@
 
     save_flags(flags); cli();
     outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
-    switch (where & 3) {
-	case 0: *value = inb(0xCFC);
-		break;
-	case 1: *value = inb(0xCFD);
-		break;
-	case 2: *value = inb(0xCFE);
-		break;
-	case 3: *value = inb(0xCFF);
-		break;
-    }
+    *value = inb(0xCFC + (where&3));
     restore_flags(flags);
     return PCIBIOS_SUCCESSFUL;
 }
@@ -531,12 +524,10 @@
 {
     unsigned long flags;
 
+    if (where&1) return PCIBIOS_BAD_REGISTER_NUMBER;
     save_flags(flags); cli();
     outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);    
-    if (where & 2)
-    	*value = inw(0xCFE);
-    else
-    	*value = inw(0xCFC);
+    *value = inw(0xCFC + (where&2));
     restore_flags(flags);
     return PCIBIOS_SUCCESSFUL;    
 }
@@ -546,6 +537,7 @@
 {
     unsigned long flags;
 
+    if (where&3) return PCIBIOS_BAD_REGISTER_NUMBER;
     save_flags(flags); cli();
     outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
     *value = inl(0xCFC);
@@ -560,7 +552,7 @@
 
     save_flags(flags); cli();
     outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);    
-    outb(value, 0xCFC);
+    outb(value, 0xCFC + (where&3));
     restore_flags(flags);
     return PCIBIOS_SUCCESSFUL;
 }
@@ -570,9 +562,10 @@
 {
     unsigned long flags;
 
+    if (where&1) return PCIBIOS_BAD_REGISTER_NUMBER;
     save_flags(flags); cli();
     outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
-    outw(value, 0xCFC);
+    outw(value, 0xCFC + (where&2));
     restore_flags(flags);
     return PCIBIOS_SUCCESSFUL;
 }
@@ -582,6 +575,7 @@
 {
     unsigned long flags;
 
+    if (where&3) return PCIBIOS_BAD_REGISTER_NUMBER;
     save_flags(flags); cli();
     outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
     outl(value, 0xCFC);
diff -u --recursive --new-file v2.1.44/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c
--- v2.1.44/linux/arch/i386/kernel/process.c	Tue May 13 22:41:01 1997
+++ linux/arch/i386/kernel/process.c	Mon Jul 14 10:17:29 1997
@@ -623,8 +623,9 @@
 	char * filename;
 
 	lock_kernel();
-	error = getname((char *) regs.ebx, &filename);
-	if (error)
+	filename = getname((char *) regs.ebx);
+	error = PTR_ERR(filename);
+	if (IS_ERR(filename))
 		goto out;
 	error = do_execve(filename, (char **) regs.ecx, (char **) regs.edx, &regs);
 	putname(filename);
diff -u --recursive --new-file v2.1.44/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- v2.1.44/linux/arch/i386/kernel/setup.c	Mon Jun 30 15:57:14 1997
+++ linux/arch/i386/kernel/setup.c	Wed Jul 16 19:22:50 1997
@@ -244,6 +244,17 @@
 	return NULL;
 }
 
+static const char * k5model(unsigned int nr)
+{
+	static const char *model[] = {
+		"SSA5 (PR-75, PR-90, PR-100)", "5k86 (PR-120, PR-133)",
+		"5k86 (PR-166)", "5k86 (PR-200)", "", "", "K6"
+	};
+	if (nr < sizeof(model)/sizeof(char *))
+		return model[nr];
+	return NULL;
+}
+
 static const char * i686model(unsigned int nr)
 {
 	static const char *model[] = {
@@ -263,7 +274,11 @@
 			p = i486model(model);
 			break;
 		case 5:
-			p = i586model(model);
+			if(strcmp(x86_vendor_id, "AuthenticAMD") == 0){
+				p = k5model(model);
+			} else {
+				p = i586model(model);
+			}
 			break;
 		case 6:
 			p = i686model(model);
diff -u --recursive --new-file v2.1.44/linux/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c
--- v2.1.44/linux/arch/i386/mm/fault.c	Thu May 15 16:48:01 1997
+++ linux/arch/i386/mm/fault.c	Mon Jul 14 10:40:13 1997
@@ -161,23 +161,25 @@
 bad_area:
 	up(&mm->mmap_sem);
 
-	/* Are we prepared to handle this fault?  */
+	/* User mode accesses just cause a SIGSEGV */
+	if (error_code & 4) {
+		tsk->tss.cr2 = address;
+		tsk->tss.error_code = error_code;
+		tsk->tss.trap_no = 14;
+		force_sig(SIGSEGV, tsk);
+		goto out;
+	}
+
+	/* Are we prepared to handle this kernel fault?  */
 	if ((fixup = search_exception_table(regs->eip)) != 0) {
 		printk(KERN_DEBUG "%s: Exception at [<%lx>] (%lx)\n",
-			current->comm,
+			tsk->comm,
 			regs->eip,
 			fixup);
 		regs->eip = fixup;
 		goto out;
 	}
 
-	if (error_code & 4) {
-		tsk->tss.cr2 = address;
-		tsk->tss.error_code = error_code;
-		tsk->tss.trap_no = 14;
-		force_sig(SIGSEGV, tsk);
-		goto out;
-	}
 /*
  * Oops. The kernel tried to access some bad page. We'll have to
  * terminate things with extreme prejudice.
diff -u --recursive --new-file v2.1.44/linux/arch/sparc/Makefile linux/arch/sparc/Makefile
--- v2.1.44/linux/arch/sparc/Makefile	Tue May 13 22:41:03 1997
+++ linux/arch/sparc/Makefile	Wed Jul 16 19:22:50 1997
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.28 1997/05/01 01:41:21 davem Exp $
+# $Id: Makefile,v 1.29 1997/07/11 11:05:23 jj Exp $
 # sparc/Makefile
 #
 # Makefile for the architecture dependent flags and dependencies on the
@@ -45,3 +45,6 @@
 
 check_asm:
 	$(MAKE) -C arch/sparc/kernel check_asm
+
+tftpboot.img:
+	$(MAKE) -C arch/sparc/boot tftpboot.img
diff -u --recursive --new-file v2.1.44/linux/arch/sparc/boot/Makefile linux/arch/sparc/boot/Makefile
--- v2.1.44/linux/arch/sparc/boot/Makefile	Sat Nov  9 00:11:31 1996
+++ linux/arch/sparc/boot/Makefile	Wed Jul 16 19:22:50 1997
@@ -1,12 +1,23 @@
-# $Id: Makefile,v 1.3 1996/08/04 08:40:58 ecd Exp $
-# Makefile for the Sparc low level /boot module.
+# $Id: Makefile,v 1.4 1997/07/11 11:05:18 jj Exp $
+# Makefile for the Sparc boot stuff.
 #
 # Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+# Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+
+ROOT_IMG	=/usr/src/root.img
+ELFTOAOUT	=elftoaout
 
 all: boot
 
 boot:
 	@echo "Nothing special to be done for 'boot' on Linux/SPARC."
+
+tftpboot.img: piggyback
+	$(ELFTOAOUT) $(TOPDIR)/vmlinux -o tftpboot.img
+	./piggyback tftpboot.img $(TOPDIR)/System.map $(ROOT_IMG)
+
+piggyback: piggyback.c
+	$(HOSTCC) $(HOSTCFLAGS) -o piggyback piggyback.c
 
 dep:
 
diff -u --recursive --new-file v2.1.44/linux/arch/sparc/boot/piggyback.c linux/arch/sparc/boot/piggyback.c
--- v2.1.44/linux/arch/sparc/boot/piggyback.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sparc/boot/piggyback.c	Wed Jul 16 19:22:50 1997
@@ -0,0 +1,100 @@
+/* $Id: piggyback.c,v 1.1 1997/07/11 11:05:17 jj Exp $
+   Simple utility to make a single-image install kernel with initial ramdisk
+   for Sparc tftpbooting without need to set up nfs.
+   
+   Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+   
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+/* Note: run this on an a.out kernel (use elftoaout for it), as PROM looks for a.out image onlly
+   usage: piggyback vmlinux System.map tail, where tail is gzipped fs of the initial ramdisk */
+
+void die(char *str)
+{
+	perror (str);
+	exit(1);
+}
+
+int main(int argc,char **argv)
+{
+	char buffer [1024], *q, *r;
+	unsigned int i, j, k, start, end, offset;
+	FILE *map;
+	struct stat s;
+	int image, tail;
+	
+	if (stat (argv[3], &s) < 0) die (argv[3]);
+	map = fopen (argv[2], "r");
+	if (!map) die(argv[2]);
+	while (fgets (buffer, 1024, map)) {
+		if (!strcmp (buffer + 11, "start\n"))
+			start = strtoul (buffer, NULL, 16);
+		else if (!strcmp (buffer + 11, "end\n"))
+			end = strtoul (buffer, NULL, 16);
+	}
+	fclose (map);
+	if ((image = open(argv[1],O_RDWR)) < 0) die(argv[1]);
+	if (read(image,buffer,512) != 512) die(argv[1]);
+	if (!memcmp (buffer, "\177ELF", 4)) {
+		unsigned int *p = (unsigned int *)(buffer + *(unsigned int *)(buffer + 28));
+	    
+		i = p[1] + *(unsigned int *)(buffer + 24) - p[2];
+		if (lseek(image,i,0) < 0) die("lseek");
+		if (read(image,buffer,512) != 512) die(argv[1]);
+		j = 0;
+	} else if (*(unsigned int *)buffer == 0x01030107) {
+		i = j = 32;
+	} else {
+		fprintf (stderr, "Not ELF nor a.out. Don't blame me.\n");
+		exit(1);
+	}
+	k = i;
+	i += ((*(unsigned short *)(buffer + j + 2))<<2) - 512;
+	if (lseek(image,i,0) < 0) die("lseek");
+	if (read(image,buffer,1024) != 1024) die(argv[1]);
+	for (q = buffer, r = q + 512; q < r; q += 4) {
+		if (*q == 'H' && q[1] == 'd' && q[2] == 'r' && q[3] == 'S')
+			break;
+	}
+	if (q == r) {
+		fprintf (stderr, "Couldn't find headers signature in the kernel.\n");
+		exit(1);
+	}
+	offset = i + (q - buffer) + 10;
+	if (lseek(image, offset, 0) < 0) die ("lseek");
+	*(unsigned *)buffer = 0;
+	*(unsigned *)(buffer + 4) = 0x01000000;
+	*(unsigned *)(buffer + 8) = ((end + 32 + 4095) & ~4095);
+	*(unsigned *)(buffer + 12) = s.st_size;
+	if (write(image,buffer+2,14) != 14) die (argv[1]);
+	if (lseek(image, k - start + ((end + 32 + 4095) & ~4095), 0) < 0) die ("lseek");
+	if ((tail = open(argv[3],O_RDONLY)) < 0) die(argv[3]);
+	while ((i = read (tail,buffer,1024)) > 0)
+		if (write(image,buffer,i) != i) die (argv[1]);
+	if (close(image) < 0) die("close");
+	if (close(tail) < 0) die("close");
+    	return 0;
+}
diff -u --recursive --new-file v2.1.44/linux/arch/sparc/defconfig linux/arch/sparc/defconfig
--- v2.1.44/linux/arch/sparc/defconfig	Thu Jun 26 12:33:38 1997
+++ linux/arch/sparc/defconfig	Wed Jul 16 19:22:50 1997
@@ -42,7 +42,7 @@
 SUN_FB_BWTWO=y
 SUN_FB_LEO=y
 TADPOLE_FB_WEITEK=y
-SUN_FB_CREATOR=y
+#SUN_FB_CREATOR is not set
 
 #
 # Misc Linux/SPARC drivers
diff -u --recursive --new-file v2.1.44/linux/arch/sparc/kernel/process.c linux/arch/sparc/kernel/process.c
--- v2.1.44/linux/arch/sparc/kernel/process.c	Thu May 15 16:48:01 1997
+++ linux/arch/sparc/kernel/process.c	Wed Jul 16 20:37:21 1997
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.98 1997/05/14 20:44:54 davem Exp $
+/*  $Id: process.c,v 1.99 1997/07/17 02:20:13 davem Exp $
  *  linux/arch/sparc/kernel/process.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -594,8 +594,9 @@
 		base = 1;
 
 	lock_kernel();
-	error = getname((char *) regs->u_regs[base + UREG_I0], &filename);
-	if(error)
+	filename = getname((char *)regs->u_regs[base + UREG_I0]);
+	error = PTR_ERR(filename);
+	if(IS_ERR(filename))
 		goto out;
 	error = do_execve(filename, (char **) regs->u_regs[base + UREG_I1],
 			  (char **) regs->u_regs[base + UREG_I2], regs);
diff -u --recursive --new-file v2.1.44/linux/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c
--- v2.1.44/linux/arch/sparc/kernel/sys_sunos.c	Tue May 13 22:41:03 1997
+++ linux/arch/sparc/kernel/sys_sunos.c	Wed Jul 16 20:37:21 1997
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos.c,v 1.79 1997/04/23 23:01:15 ecd Exp $
+/* $Id: sys_sunos.c,v 1.80 1997/07/17 02:20:22 davem Exp $
  * sys_sunos.c: SunOS specific syscall compatibility support.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -90,10 +90,12 @@
 	 * of /dev/zero, transform it into an anonymous mapping.
 	 * SunOS is so stupid some times... hmph!
 	 */
-	if(MAJOR(file->f_inode->i_rdev) == MEM_MAJOR &&
-	   MINOR(file->f_inode->i_rdev) == 5) {
-		flags |= MAP_ANONYMOUS;
-		file = 0;
+	if(file->f_dentry && file->f_dentry->d_inode) {
+		if(MAJOR(file->f_dentry->d_inode->i_rdev) == MEM_MAJOR &&
+		   MINOR(file->f_dentry->d_inode->i_rdev) == 5) {
+			flags |= MAP_ANONYMOUS;
+			file = 0;
+		}
 	}
 	if(!(flags & MAP_FIXED))
 		addr = 0;
@@ -428,16 +430,32 @@
 asmlinkage int sunos_getdents(unsigned int fd, void * dirent, int cnt)
 {
 	struct file * file;
+	struct dentry * dentry;
+	struct inode * inode;
 	struct sunos_dirent * lastdirent;
 	struct sunos_dirent_callback buf;
 	int error = -EBADF;
 
 	lock_kernel();
-	if (fd >= SUNOS_NR_OPEN || !(file = current->files->fd[fd]))
+	if(fd >= SUNOS_NR_OPEN)
+		goto out;
+
+	file = current->files->fd[fd];
+	if(!file)
+		goto out;
+
+	dentry = file->f_dentry;
+	if(!dentry)
 		goto out;
+
+	inode = dentry->d_inode;
+	if(!inode)
+		goto out;
+
 	error = -ENOTDIR;
 	if (!file->f_op || !file->f_op->readdir)
 		goto out;
+
 	error = -EINVAL;
 	if(cnt < (sizeof(struct sunos_dirent) + 255))
 		goto out;
@@ -446,13 +464,12 @@
 	buf.previous = NULL;
 	buf.count = cnt;
 	buf.error = 0;
-	error = file->f_op->readdir(file->f_inode, file, &buf, sunos_filldir);
+	error = file->f_op->readdir(inode, file, &buf, sunos_filldir);
 	if (error < 0)
 		goto out;
 	lastdirent = buf.previous;
-	if (!lastdirent) {
-		error = buf.error;
-	} else {
+	error = buf.error;
+	if (lastdirent) {
 		put_user(file->f_pos, &lastdirent->d_off);
 		error = cnt - buf.count;
 	}
@@ -503,16 +520,32 @@
 asmlinkage int sunos_getdirentries(unsigned int fd, void * dirent, int cnt, unsigned int *basep)
 {
 	struct file * file;
+	struct dentry * dentry;
+	struct inode * inode;
 	struct sunos_direntry * lastdirent;
 	struct sunos_direntry_callback buf;
 	int error = -EBADF;
 
 	lock_kernel();
-	if (fd >= SUNOS_NR_OPEN || !(file = current->files->fd[fd]))
+	if(fd >= SUNOS_NR_OPEN)
 		goto out;
+
+	file = current->files->fd[fd];
+	if(!file)
+		goto out;
+
+	dentry = file->f_dentry;
+	if(!dentry)
+		goto out;
+
+	inode = dentry->d_inode;
+	if(!inode)
+		goto out;
+
 	error = -ENOTDIR;
 	if (!file->f_op || !file->f_op->readdir)
 		goto out;
+
 	error = -EINVAL;
 	if(cnt < (sizeof(struct sunos_direntry) + 255))
 		goto out;
@@ -521,13 +554,12 @@
 	buf.previous = NULL;
 	buf.count = cnt;
 	buf.error = 0;
-	error = file->f_op->readdir(file->f_inode, file, &buf, sunos_filldirentry);
+	error = file->f_op->readdir(inode, file, &buf, sunos_filldirentry);
 	if (error < 0)
 		goto out;
 	lastdirent = buf.previous;
-	if (!lastdirent) {
-		error = buf.error;
-	} else {
+	error = buf.error;
+	if (lastdirent) {
 		put_user(file->f_pos, basep);
 		error = cnt - buf.count;
 	}
@@ -725,12 +757,13 @@
 	int    try_port;
 	int    ret;
 	struct socket *socket;
+	struct dentry *dentry;
 	struct inode  *inode;
 	struct file   *file;
 
 	file = current->files->fd [fd];
-	inode = file->f_inode;
-	if (!inode || !inode->i_sock)
+	dentry = file->f_dentry;
+	if(!dentry || !(inode = dentry->d_inode))
 		return 0;
 
 	socket = &inode->u.socket_i;
diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/Makefile linux/arch/sparc64/Makefile
--- v2.1.44/linux/arch/sparc64/Makefile	Mon Jul  7 08:18:54 1997
+++ linux/arch/sparc64/Makefile	Wed Jul 16 19:22:50 1997
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.19 1997/06/26 12:48:45 jj Exp $
+# $Id: Makefile,v 1.20 1997/07/11 11:05:29 jj Exp $
 # sparc64/Makefile
 #
 # Makefile for the architecture dependent flags and dependencies on the
@@ -49,3 +49,6 @@
 
 check_asm:
 	$(MAKE) -C arch/sparc64/kernel check_asm
+
+tftpboot.img:
+	$(MAKE) -C arch/sparc64/boot tftpboot.img
diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/boot/Makefile linux/arch/sparc64/boot/Makefile
--- v2.1.44/linux/arch/sparc64/boot/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/arch/sparc64/boot/Makefile	Wed Jul 16 19:22:50 1997
@@ -0,0 +1,23 @@
+# $Id: Makefile,v 1.1 1997/07/11 11:05:25 jj Exp $
+# Makefile for the Sparc64 boot stuff.
+#
+# Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+# Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+
+ROOT_IMG	=/usr/src/root.img
+ELFTOAOUT	=elftoaout
+
+all: boot
+
+boot:
+	@echo "Nothing special to be done for 'boot' on Linux/UltraSPARC."
+
+tftpboot.img: piggyback
+	$(ELFTOAOUT) $(TOPDIR)/vmlinux -o tftpboot.img
+	./piggyback tftpboot.img $(TOPDIR)/System.map $(ROOT_IMG)
+
+piggyback: piggyback.c
+	$(HOSTCC) $(HOSTCFLAGS) -o piggyback piggyback.c
+
+dep:
+
diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/boot/piggyback.c linux/arch/sparc64/boot/piggyback.c
--- v2.1.44/linux/arch/sparc64/boot/piggyback.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sparc64/boot/piggyback.c	Wed Jul 16 19:22:50 1997
@@ -0,0 +1,109 @@
+/* $Id: piggyback.c,v 1.1 1997/07/11 11:05:26 jj Exp $
+   Simple utility to make a single-image install kernel with initial ramdisk
+   for Sparc64 tftpbooting without need to set up nfs.
+   
+   Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+   
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+/* Note: run this on an a.out kernel (use elftoaout for it), as PROM looks for a.out image onlly
+   usage: piggyback vmlinux System.map tail, where tail is gzipped fs of the initial ramdisk */
+
+void die(char *str)
+{
+	perror (str);
+	exit(1);
+}
+
+int main(int argc,char **argv)
+{
+	char buffer [1024], *q, *r;
+	unsigned int i, j, k, start, end, offset;
+	FILE *map;
+	struct stat s;
+	int image, tail;
+	
+	if (stat (argv[3], &s) < 0) die (argv[3]);
+	map = fopen (argv[2], "r");
+	if (!map) die(argv[2]);
+	while (fgets (buffer, 1024, map)) {
+		if (!strcmp (buffer + 19, "start\n"))
+		start = strtoul (buffer + 8, NULL, 16);
+		else if (!strcmp (buffer + 19, "end\n"))
+		end = strtoul (buffer + 8, NULL, 16);
+	}
+	fclose (map);
+	if ((image = open(argv[1],O_RDWR)) < 0) die(argv[1]);
+	if (read(image,buffer,512) != 512) die(argv[1]);
+	if (!memcmp (buffer, "\177ELF", 4)) {
+		unsigned int *p = (unsigned int *)(buffer + *(unsigned int *)(buffer + 28));
+		
+		i = p[1] + *(unsigned int *)(buffer + 24) - p[2];
+		if (lseek(image,i,0) < 0) die("lseek");
+		if (read(image,buffer,512) != 512) die(argv[1]);
+		j = 0;
+	} else if (*(unsigned int *)buffer == 0x01030107) {
+		i = j = 32;
+	} else {
+		fprintf (stderr, "Not ELF nor a.out. Don't blame me.\n");
+		exit(1);
+	}
+	k = i;
+	if (j == 32 && buffer[40] == 'H' && buffer[41] == 'd' && buffer[42] == 'r' && buffer[43] == 'S') {
+		offset = 40 + 10;
+	} else {
+		i += ((*(unsigned short *)(buffer + j + 2))<<2) - 512;
+		if (lseek(image,i,0) < 0) die("lseek");
+		if (read(image,buffer,1024) != 1024) die(argv[1]);
+		for (q = buffer, r = q + 512; q < r; q += 4) {
+			if (*q == 'H' && q[1] == 'd' && q[2] == 'r' && q[3] == 'S')
+				break;
+		}
+		if (q == r) {
+			fprintf (stderr, "Couldn't find headers signature in the kernel.\n");
+			exit(1);
+		}
+		offset = i + (q - buffer) + 10;
+	}
+	if (lseek(image, offset, 0) < 0) die ("lseek");
+	*(unsigned *)buffer = 0;
+	*(unsigned *)(buffer + 4) = 0x01000000;
+	*(unsigned *)(buffer + 8) = ((end + 32 + 8191) & ~8191);
+	*(unsigned *)(buffer + 12) = s.st_size;
+	if (write(image,buffer+2,14) != 14) die (argv[1]);
+	if (lseek(image, 4, 0) < 0) die ("lseek");
+	*(unsigned *)buffer = ((end + 32 + 8191) & ~8191) - (start & ~0x3fffffUL) + s.st_size;
+	*(unsigned *)(buffer + 4) = 0;
+	*(unsigned *)(buffer + 8) = 0;
+	if (write(image,buffer,12) != 12) die (argv[1]);
+	if (lseek(image, k - start + ((end + 32 + 8191) & ~8191), 0) < 0) die ("lseek");
+	if ((tail = open(argv[3],O_RDONLY)) < 0) die(argv[3]);
+	while ((i = read (tail,buffer,1024)) > 0)
+		if (write(image,buffer,i) != i) die (argv[1]);
+	if (close(image) < 0) die("close");
+	if (close(tail) < 0) die("close");
+    	return 0;
+}
diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig
--- v2.1.44/linux/arch/sparc64/defconfig	Mon Jul  7 08:18:54 1997
+++ linux/arch/sparc64/defconfig	Wed Jul 16 19:22:50 1997
@@ -94,7 +94,7 @@
 CONFIG_PATH_MTU_DISCOVERY=y
 CONFIG_IP_NOSR=y
 CONFIG_SKB_LARGE=y
-# CONFIG_IPV6 is not set
+CONFIG_IPV6=m
 
 #
 #  
@@ -120,7 +120,7 @@
 # SCSI support type (disk, tape, CDrom)
 #
 CONFIG_BLK_DEV_SD=y
-# CONFIG_CHR_DEV_ST is not set
+CONFIG_CHR_DEV_ST=y
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
@@ -141,13 +141,20 @@
 # Network device support
 #
 CONFIG_NETDEVICES=y
-CONFIG_DUMMY=y
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
+CONFIG_DUMMY=m
+CONFIG_PPP=m
+
+#
+# CCP compressors for PPP are only built as modules.
+#
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+# CONFIG_SLIP_MODE_SLIP6 is not set
 CONFIG_SUNLANCE=y
-CONFIG_HAPPYMEAL=m
+CONFIG_HAPPYMEAL=y
 CONFIG_SUNQE=m
-# CONFIG_MYRI_SBUS is not set
+CONFIG_MYRI_SBUS=m
 
 #
 # Filesystems
@@ -156,11 +163,11 @@
 # CONFIG_DCACHE_PRELOAD is not set
 # CONFIG_OMIRR is not set
 # CONFIG_TRANS_NAMES is not set
-# CONFIG_MINIX_FS is not set
+CONFIG_MINIX_FS=m
 CONFIG_EXT2_FS=y
-# CONFIG_FAT_FS is not set
-# CONFIG_MSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
 # CONFIG_UMSDOS_FS is not set
 CONFIG_PROC_FS=y
 CONFIG_NFS_FS=y
@@ -170,15 +177,17 @@
 CONFIG_NFSD=m
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
-# CONFIG_SMB_FS is not set
-# CONFIG_NCP_FS is not set
+CONFIG_SMB_FS=m
+CONFIG_SMB_WIN95=y
+CONFIG_NCP_FS=m
 CONFIG_ISO9660_FS=y
-# CONFIG_HPFS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_ROMFS_FS is not set
+CONFIG_HPFS_FS=m
+CONFIG_SYSV_FS=m
+CONFIG_AFFS_FS=m
+CONFIG_ROMFS_FS=m
 CONFIG_AUTOFS_FS=m
-CONFIG_UFS_FS=y
+CONFIG_AMIGA_PARTITION=y
+CONFIG_UFS_FS=m
 CONFIG_BSD_DISKLABEL=y
 CONFIG_SMD_DISKLABEL=y
 
diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/kernel/binfmt_aout32.c linux/arch/sparc64/kernel/binfmt_aout32.c
--- v2.1.44/linux/arch/sparc64/kernel/binfmt_aout32.c	Mon Jul  7 08:18:54 1997
+++ linux/arch/sparc64/kernel/binfmt_aout32.c	Wed Jul 16 19:22:50 1997
@@ -78,6 +78,7 @@
 static inline int
 do_aout32_core_dump(long signr, struct pt_regs * regs)
 {
+	struct dentry * dentry = NULL;
 	struct inode * inode = NULL;
 	struct file file;
 	unsigned short fs;
@@ -103,10 +104,12 @@
 #else
 	corefile[4] = '\0';
 #endif
-	if (open_namei(corefile,O_CREAT | 2 | O_TRUNC,0600,&inode,NULL)) {
-		inode = NULL;
+	dentry = open_namei(corefile,O_CREAT | 2 | O_TRUNC, 0600);
+	if (IS_ERR(dentry)) {
+		dentry = NULL;
 		goto end_coredump;
 	}
+	inode = dentry->d_inode;
 	if (!S_ISREG(inode->i_mode))
 		goto end_coredump;
 	if (!inode->i_op || !inode->i_op->default_file_ops)
@@ -116,7 +119,7 @@
 	file.f_mode = 3;
 	file.f_flags = 0;
 	file.f_count = 1;
-	file.f_inode = inode;
+	file.f_dentry = dentry;
 	file.f_pos = 0;
 	file.f_reada = 0;
 	file.f_op = inode->i_op->default_file_ops;
@@ -169,7 +172,6 @@
 /* Finally dump the task struct.  Not be used by gdb, but could be useful */
 	set_fs(KERNEL_DS);
 	DUMP_WRITE(current,sizeof(*current));
-	inode->i_status |= ST_MODIFIED;
 close_coredump:
 	if (file.f_op->release)
 		file.f_op->release(inode,&file);
@@ -177,7 +179,7 @@
 	put_write_access(inode);
 end_coredump:
 	set_fs(fs);
-	iput(inode);
+	dput(dentry);
 	return has_dumped;
 }
 
@@ -259,7 +261,7 @@
 	if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC &&
 	     N_MAGIC(ex) != QMAGIC && N_MAGIC(ex) != NMAGIC) ||
 	    N_TRSIZE(ex) || N_DRSIZE(ex) ||
-	    bprm->inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
+	    bprm->dentry->d_inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
 		return -ENOEXEC;
 	}
 
@@ -297,12 +299,12 @@
 		error = do_mmap(NULL, N_TXTADDR(ex), ex.a_text,
 				PROT_READ|PROT_WRITE|PROT_EXEC,
 				MAP_FIXED|MAP_PRIVATE, 0);
-		read_exec(bprm->inode, fd_offset, (char *) N_TXTADDR(ex),
+		read_exec(bprm->dentry, fd_offset, (char *) N_TXTADDR(ex),
 			  ex.a_text, 0);
 		error = do_mmap(NULL, N_DATADDR(ex), ex.a_data,
 				PROT_READ|PROT_WRITE|PROT_EXEC,
 				MAP_FIXED|MAP_PRIVATE, 0);
-		read_exec(bprm->inode, fd_offset + ex.a_text, (char *) N_DATADDR(ex),
+		read_exec(bprm->dentry, fd_offset + ex.a_text, (char *) N_DATADDR(ex),
 			  ex.a_data, 0);
 		goto beyond_if;
 	}
@@ -312,14 +314,14 @@
 			ex.a_text+ex.a_data + PAGE_SIZE - 1,
 			PROT_READ|PROT_WRITE|PROT_EXEC,
 			MAP_FIXED|MAP_PRIVATE, 0);
-		read_exec(bprm->inode, fd_offset, (char *) N_TXTADDR(ex),
+		read_exec(bprm->dentry, fd_offset, (char *) N_TXTADDR(ex),
 			  ex.a_text+ex.a_data, 0);
 	} else {
 		if ((ex.a_text & 0xfff || ex.a_data & 0xfff) &&
 		    (N_MAGIC(ex) != NMAGIC))
 			printk(KERN_NOTICE "executable not page aligned\n");
 
-		fd = open_inode(bprm->inode, O_RDONLY);
+		fd = open_dentry(bprm->dentry, O_RDONLY);
 
 		if (fd < 0)
 			return fd;
@@ -329,7 +331,7 @@
 			do_mmap(NULL, 0, ex.a_text+ex.a_data,
 				PROT_READ|PROT_WRITE|PROT_EXEC,
 				MAP_FIXED|MAP_PRIVATE, 0);
-			read_exec(bprm->inode, fd_offset,
+			read_exec(bprm->dentry, fd_offset,
 				  (char *) N_TXTADDR(ex), ex.a_text+ex.a_data, 0);
 			goto beyond_if;
 		}
@@ -396,17 +398,20 @@
 {
         struct file * file;
 	struct exec ex;
-	struct  inode * inode;
+	struct dentry * dentry;
+	struct inode * inode;
 	unsigned int len;
 	unsigned int bss;
 	unsigned int start_addr;
 	unsigned long error;
 
 	file = current->files->fd[fd];
-	inode = file->f_inode;
 
 	if (!file || !file->f_op)
 		return -EACCES;
+
+	dentry = file->f_dentry;
+	inode = dentry->d_inode;
 
 	/* Seek into the file */
 	if (file->f_op->llseek) {
diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/kernel/cpu.c linux/arch/sparc64/kernel/cpu.c
--- v2.1.44/linux/arch/sparc64/kernel/cpu.c	Mon Jul  7 08:18:54 1997
+++ linux/arch/sparc64/kernel/cpu.c	Wed Jul 16 19:22:50 1997
@@ -28,6 +28,7 @@
  */
 struct cpu_fp_info linux_sparc_fpu[] = {
   { 0x17, 0x10, 0, "UltraSparc I integrated FPU"},
+  { 0x22, 0x10, 0, "UltraSparc II integrated FPU"},
   { 0x17, 0x11, 0, "UltraSparc II integrated FPU"},
   { 0x17, 0x12, 0, "UltraSparc III integrated FPU"},
 };
@@ -36,6 +37,7 @@
 
 struct cpu_iu_info linux_sparc_chips[] = {
   { 0x17, 0x10, "TI UltraSparc I   (SpitFire)"},
+  { 0x22, 0x10, "TI UltraSparc II  (BlackBird)"},
   { 0x17, 0x11, "TI UltraSparc II  (BlackBird)"},
   { 0x17, 0x12, "TI UltraSparc III (Cheetah)"},  /* A guess... */
 };
diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/kernel/entry.S linux/arch/sparc64/kernel/entry.S
--- v2.1.44/linux/arch/sparc64/kernel/entry.S	Mon Jul  7 08:18:54 1997
+++ linux/arch/sparc64/kernel/entry.S	Wed Jul 16 19:22:50 1997
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.45 1997/07/05 09:52:25 davem Exp $
+/* $Id: entry.S,v 1.50 1997/07/15 16:53:00 davem Exp $
  * arch/sparc64/kernel/entry.S:  Sparc64 trap low-level entry points.
  *
  * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -7,6 +7,7 @@
  * Copyright (C) 1996,1997 Jakub Jelinek   (jj@sunsite.mff.cuni.cz)
  */
 
+#include <linux/config.h>
 #include <linux/errno.h>
 
 #include <asm/head.h>
@@ -191,16 +192,18 @@
 	wrpr		%g3, %tstate
 	retry
 
+#ifdef __SMP__
 	/* Note check out head.h, this code isn't even used for UP,
 	 * for SMP things will be different.  In particular the data
 	 * registers for cross calls will be:
 	 *
-	 * DATA 0: Address of function to call
-	 * DATA 1: Argument 1, place in %g6
-	 * DATA 2: Argument 2, place in %g7
+	 * DATA 0: [low 32-bits]  Address of function to call, jmp to this
+	 *         [high 32-bits] MMU Context Argument 0, place in %g5
+	 * DATA 1: Address Argument 1, place in %g6
+	 * DATA 2: Address Argument 2, place in %g7
 	 *
 	 * With this method we can do most of the cross-call tlb/cache
-	 * flushing in very quickly.
+	 * flushing very quickly.
 	 */
 	.align	32
 	.globl	do_ivec
@@ -211,12 +214,14 @@
 	 mov		0x40, %g2
 
 	/* Load up Interrupt Vector Data 0 register. */
+	sethi		%hi(KERNBASE), %g4
 	ldxa		[%g2] ASI_UDB_INTR_R, %g3
-	sethi		%hi(ivector_to_mask), %g5
+	cmp		%g3, %g4
+	bgeu,pn		%xcc, do_ivec_xcall
+	 nop
 	and		%g3, 0x7ff, %g3
-	orcc		%g5, %lo(ivector_to_mask), %g5
 	sllx		%g3, 3, %g3
-	ldx		[%g5 + %g3], %g2
+	ldx		[%g1 + %g3], %g2
 	brz,pn		%g2, do_ivec_spurious
 	 nop
 
@@ -231,7 +236,14 @@
 	stxa		%g0, [%g0] ASI_INTR_RECEIVE
 	membar		#Sync
 	retry
-
+do_ivec_xcall:
+	srlx		%g3, 32, %g5
+	add		%g2, 0x10, %g2
+	sra		%g3, 0, %g3
+	ldxa		[%g2] ASI_UDB_INTR_R, %g6
+	add		%g2, 0x10, %g2
+	jmpl		%g3, %g0
+	 ldxa		[%g2] ASI_UDB_INTR_R, %g7
 do_ivec_spurious:
 	stxa		%g0, [%g0] ASI_INTR_RECEIVE
 	membar		#Sync
@@ -243,6 +255,7 @@
 	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
 	ba,pt		%xcc, rtrap
 	 clr		%l6
+#endif /* __SMP__ */
 
 	.globl		getcc, setcc
 getcc:
@@ -263,10 +276,104 @@
 	retl
 	 stx		%o1, [%o0 + PT_V9_TSTATE]
 
-	/* XXX Here is stuff we still need to write... -DaveM XXX */
-	.globl		floppy_hardint, indirect_syscall, netbsd_syscall
-	.globl		solaris_syscall
+#ifdef CONFIG_BLK_DEV_FD
+	.globl		floppy_hardint
 floppy_hardint:
+	sethi		%hi(doing_pdma), %g1
+	ld		[%g1 + %lo(doing_pdma)], %g2
+	brz,pn		%g2, floppy_dosoftint
+	 sethi		%hi(fdc_status), %g3
+	ldx		[%g3 + %lo(fdc_status)], %g3
+	sethi		%hi(pdma_vaddr), %g5
+	ldx		[%g5 + %lo(pdma_vaddr)], %g4
+	sethi		%hi(pdma_size), %g5
+	ldx		[%g5 + %lo(pdma_size)], %g5
+
+next_byte:
+	ldub		[%g3], %g7
+	andcc		%g7, 0x80, %g0
+	be,pn		%icc, floppy_fifo_emptied
+	 andcc		%g7, 0x20, %g0
+	be,pn		%icc, floppy_overrun
+	 andcc		%g7, 0x40, %g0
+	be,pn		%icc, floppy_write
+	 sub		%g5, 1, %g5
+
+	ldub		[%g3 + 1], %g7
+	orcc		%g0, %g5, %g0
+	stb		%g7, [%g4]
+	bne,pn		%xcc, next_byte
+	 add		%g4, 1, %g4
+
+	b,pt		%xcc, floppy_tdone
+	 nop
+
+floppy_write:
+	ldub		[%g4], %g7
+	orcc		%g0, %g5, %g0
+	stb		%g7, [%g3 + 1]
+	bne,pn		%xcc, next_byte
+	 add		%g4, 1, %g4
+
+floppy_tdone:
+	sethi		%hi(pdma_vaddr), %g1
+	stx		%g4, [%g1 + %lo(pdma_vaddr)]
+	sethi		%hi(pdma_size), %g1
+	stx		%g5, [%g1 + %lo(pdma_size)]
+	sethi		%hi(auxio_register), %g1
+	ldx		[%g1 + %lo(auxio_register)], %g7
+	ldub		[%g7], %g5
+	or		%g5, 0xc2, %g5
+	stb		%g5, [%g7]
+	andn		%g5, 0x02, %g5
+
+	nop; nop;  nop; nop;  nop; nop;
+	nop; nop;  nop; nop;  nop; nop;
+
+	stb		%g5, [%g7]
+	sethi		%hi(doing_pdma), %g1
+	b,pt		%xcc, floppy_dosoftint
+	 st		%g0, [%g1 + %lo(doing_pdma)]
+
+floppy_fifo_emptied:
+	sethi		%hi(pdma_vaddr), %g1
+	stx		%g4, [%g1 + %lo(pdma_vaddr)]
+	sethi		%hi(pdma_size), %g1
+	stx		%g5, [%g1 + %lo(pdma_size)]
+	sethi		%hi(irq_action), %g1
+	or		%g1, %lo(irq_action), %g1
+	ldx		[%g1 + (11 << 3)], %g3		! irqaction[floppy_irq]
+	ldx		[%g3 + 0x10], %g4		! action->mask
+	st		%g0, [%g4]			! SYSIO_ICLR_IDLE
+	membar		#Sync				! probably not needed...
+	retry
+
+floppy_overrun:
+	sethi		%hi(pdma_vaddr), %g1
+	stx		%g4, [%g1 + %lo(pdma_vaddr)]
+	sethi		%hi(pdma_size), %g1
+	stx		%g5, [%g1 + %lo(pdma_size)]
+	sethi		%hi(doing_pdma), %g1
+	st		%g0, [%g1 + %lo(doing_pdma)]
+
+floppy_dosoftint:
+	rdpr		%pil, %g2
+	wrpr		%g0, 15, %pil
+	b,pt		%xcc, etrap_irq
+	 rd		%pc, %g7
+
+	mov		11, %o0
+	mov		0, %o1
+	call		sparc_floppy_irq
+	 add		%sp, STACK_BIAS + REGWIN_SZ, %o2
+
+	b,pt		%xcc, rtrap
+	 clr		%l6
+
+#endif /* CONFIG_BLK_DEV_FD */
+
+	/* XXX Here is stuff we still need to write... -DaveM XXX */
+	.globl		indirect_syscall, netbsd_syscall, solaris_syscall
 indirect_syscall:
 netbsd_syscall:
 solaris_syscall:
@@ -436,16 +543,39 @@
 		ba,pt		%xcc, rtrap
 		 clr		%l6
 	
-	/* This is how fork() was meant to be done, 12 instruction entry. -DaveM */
-	.globl	sys_fork, sys_vfork, sys_clone, ret_from_syscall
+	/* This is how fork() was meant to be done, 12 instruction entry.
+	 *
+	 * I questioned the following code briefly, let me clear things
+	 * up so you must not reason on it like I did.
+	 *
+	 * Know the fork_kpsr etc. we use in the sparc32 port?  We don't
+	 * need it here because the only piece of window state we copy to
+	 * the child is the CWP register.  Even if the parent sleeps,
+	 * we are safe because we stuck it into pt_regs of the parent
+	 * so it will not change.
+	 *
+	 * XXX This raises the question, whether we can do the same on
+	 * XXX sparc32 to get rid of fork_kpsr _and_ fork_kwim.  The
+	 * XXX answer is yes.  We stick fork_kpsr in UREG_G0 and
+	 * XXX fork_kwim in UREG_G1 (global registers are considered
+	 * XXX volatile across a system call in the sparc ABI I think
+	 * XXX if it isn't we can use regs->y instead, anyone who depends
+	 * XXX upon the Y register being preserved across a fork deserves
+	 * XXX to lose).
+	 *
+	 * In fact we should take advantage of that fact for other things
+	 * during system calls...
+	 */
+	.globl	sys_fork, sys_vfork, sys_clone
+	.globl	ret_from_syscall, ret_from_smpfork
 	.align	32
 sys_fork:
 sys_vfork:	mov		SIGCHLD, %o0
 		clr		%o1
 sys_clone:	mov		%o7, %l5
-		save		%sp, -REGWIN_SZ, %sp
+/*???*/		save		%sp, -REGWIN_SZ, %sp
 		flushw
-		restore		%g0, %g0, %g0
+/*???*/		restore		%g0, %g0, %g0
 		rdpr		%cwp, %o4
 		add		%sp, STACK_BIAS + REGWIN_SZ, %o2
 
@@ -453,10 +583,15 @@
 		stx		%o4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G0]
 		call		do_fork
 		 mov		%l5, %o7
-ret_from_syscall:b,pt		%xcc, ret_sys_call
-		  ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0
-		nop
-		nop
+#ifdef __SMP__
+ret_from_smpfork:
+		sethi		%hi(scheduler_lock), %o4
+		membar		#StoreStore | #LoadStore
+		stb		%g0, [%o4 + %lo(scheduler_lock)]
+#endif
+ret_from_syscall:
+		b,pt		%xcc, ret_sys_call
+		 ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0
 
 linux_syscall_trace:
 		call		syscall_trace
diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c
--- v2.1.44/linux/arch/sparc64/kernel/ioctl32.c	Thu Jun 26 12:33:38 1997
+++ linux/arch/sparc64/kernel/ioctl32.c	Wed Jul 16 20:37:21 1997
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.11 1997/06/16 11:05:00 jj Exp $
+/* $Id: ioctl32.c,v 1.13 1997/07/17 02:20:38 davem Exp $
  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -22,6 +22,7 @@
 #include <linux/netlink.h>
 #include <linux/vt.h>
 #include <linux/fs.h>
+#include <linux/fd.h>
 
 #include <asm/types.h>
 #include <asm/uaccess.h>
@@ -485,8 +486,13 @@
 	int error = -EBADF;
 
 	lock_kernel();
-	if (fd >= NR_OPEN || !(filp = current->files->fd[fd]))
+	if(fd >= NR_OPEN)
 		goto out;
+
+	filp = current->files->fd[fd];
+	if(!filp)
+		goto out;
+
 	if (!filp->f_op || !filp->f_op->ioctl) {
 		error = sys_ioctl (fd, cmd, (unsigned long)arg);
 		goto out;
@@ -612,6 +618,15 @@
 	case FIBMAP:
 	case FIGETBSZ:
 	
+	/* 0x02 -- Floppy ioctls */
+	case FDSETEMSGTRESH:
+	case FDFLUSH:
+	case FDSETMAXERRS:
+	case FDGETMAXERRS:
+	case FDGETDRVTYP:
+	case FDEJECT:
+	/* XXX The rest need struct floppy_* translations. */
+
 	/* 0x12 */
 	case BLKRRPART:
 	case BLKFLSBUF:
diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/kernel/irq.c linux/arch/sparc64/kernel/irq.c
--- v2.1.44/linux/arch/sparc64/kernel/irq.c	Mon Jul  7 08:18:54 1997
+++ linux/arch/sparc64/kernel/irq.c	Wed Jul 16 19:22:50 1997
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.14 1997/06/24 17:30:26 davem Exp $
+/* $Id: irq.c,v 1.16 1997/07/11 03:03:08 davem Exp $
  * irq.c: UltraSparc IRQ handling/init/registry.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -47,7 +47,8 @@
 static struct irqaction static_irqaction[MAX_STATIC_ALLOC];
 static int static_irq_count = 0;
 
-static struct irqaction *irq_action[NR_IRQS+1] = {
+/* XXX Must be exported so that fast IRQ handlers can get at it... -DaveM */
+struct irqaction *irq_action[NR_IRQS+1] = {
 	  NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL,
 	  NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL
 };
@@ -279,13 +280,13 @@
 	/* If this is flagged as statically allocated then we use our
 	 * private struct which is never freed.
 	 */
-	if(irqflags & SA_STATIC_ALLOC)
+	if(irqflags & SA_STATIC_ALLOC) {
 	    if(static_irq_count < MAX_STATIC_ALLOC)
 		action = &static_irqaction[static_irq_count++];
 	    else
 		printk("Request for IRQ%d (%s) SA_STATIC_ALLOC failed "
 		       "using kmalloc\n", irq, name);
-	
+	}	
 	if(action == NULL)
 	    action = (struct irqaction *)kmalloc(sizeof(struct irqaction),
 						 GFP_KERNEL);
@@ -464,14 +465,101 @@
 }
 #endif
 
-/* XXX This needs to be written for floppy driver, and soon will be necessary
- * XXX for serial driver as well.
+/* The following assumes that the branch lies before the place we
+ * are branching to.  This is the case for a trap vector...
+ * You have been warned.
  */
+#define SPARC_BRANCH(dest_addr, inst_addr) \
+          (0x10800000 | ((((dest_addr)-(inst_addr))>>2)&0x3fffff))
+
+#define SPARC_NOP (0x01000000)
+
+static void install_fast_irq(unsigned int cpu_irq,
+			     void (*handler)(int, void *, struct pt_regs *))
+{
+	extern unsigned long sparc64_ttable_tl0;
+	unsigned long ttent = (unsigned long) &sparc64_ttable_tl0;
+	unsigned int *insns;
+
+	ttent += 0x820;
+	ttent += (cpu_irq - 1) << 5;
+	insns = (unsigned int *) ttent;
+	insns[0] = SPARC_BRANCH(((unsigned long) handler),
+				((unsigned long)&insns[0]));
+	insns[1] = SPARC_NOP;
+	__asm__ __volatile__("flush %0" : : "r" (ttent));
+}
+
 int request_fast_irq(unsigned int irq,
 		     void (*handler)(int, void *, struct pt_regs *),
 		     unsigned long irqflags, const char *name)
 {
-	return -1;
+	struct irqaction *action;
+	unsigned long flags;
+	unsigned int cpu_irq, *imap, *iclr;
+
+	/* XXX This really is not the way to do it, the "right way"
+	 * XXX is to have drivers set SA_SBUS or something like that
+	 * XXX in irqflags and we base our decision here on whether
+	 * XXX that flag bit is set or not.
+	 *
+	 * In this case nobody can have a fast interrupt at the level
+	 * where TICK interrupts live.
+	 */
+	if(irq == 14)
+		return -EINVAL;
+	cpu_irq = ino_to_pil[irq];
+
+	if(!handler)
+		return -EINVAL;
+	imap = irq_to_imap(irq);
+	action = *(cpu_irq + irq_action);
+	if(action) {
+		if(action->flags & SA_SHIRQ)
+			panic("Trying to register fast irq when already shared.\n");
+		if(irqflags & SA_SHIRQ)
+			panic("Trying to register fast irq as shared.\n");
+		printk("request_fast_irq: Trying to register yet already owned.\n");
+		return -EBUSY;
+	}
+	save_and_cli(flags);
+	if(irqflags & SA_STATIC_ALLOC) {
+		if(static_irq_count < MAX_STATIC_ALLOC)
+			action = &static_irqaction[static_irq_count++];
+		else
+			printk("Request for IRQ%d (%s) SA_STATIC_ALLOC failed "
+			       "using kmalloc\n", irq, name);
+	}
+	if(action == NULL)
+		action = (struct irqaction *)kmalloc(sizeof(struct irqaction),
+						     GFP_KERNEL);
+	if(!action) {
+		restore_flags(flags);
+		return -ENOMEM;
+	}
+	install_fast_irq(cpu_irq, handler);
+
+	if(imap) {
+		int ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO));
+
+		ivector_to_mask[ivindex] = (1 << cpu_irq);
+		iclr = imap_to_iclr(imap);
+		action->mask = (unsigned long) iclr;
+		irqflags |= SA_SYSIO_MASKED;
+	} else
+		action->mask = 0;
+
+	action->handler = handler;
+	action->flags = irqflags;
+	action->dev_id = NULL;
+	action->name = name;
+	action->next = NULL;
+
+	*(cpu_irq + irq_action) = action;
+
+	enable_irq(irq);
+	restore_flags(flags);
+	return 0;
 }
 
 /* We really don't need these at all on the Sparc.  We only have
@@ -496,27 +584,31 @@
 /* XXX This doesn't belong here, just do this cruft in the timer.c handler code. */
 static void timer_handler(int irq, void *dev_id, struct pt_regs *regs)
 {
-	extern void timer_interrupt(int, void *, struct pt_regs *);
-	unsigned long compare;
-	
 	if (!(get_softint () & 1)) {
 		/* Just to be sure... */
 		clear_softint(1 << 14);
 		printk("Spurious level14 at %016lx\n", regs->tpc);
 		return;
-	}
+	} else {
+		unsigned long compare, tick;
 
-	timer_interrupt(irq, dev_id, regs);
+		do {
+			extern void timer_interrupt(int, void *, struct pt_regs *);
 
-	/* Acknowledge INT_TIMER */
-	clear_softint(1 << 0);
+			timer_interrupt(irq, dev_id, regs);
 
-	/* Set up for next timer tick. */
-	__asm__ __volatile__("rd	%%tick_cmpr, %0\n\t"
-			     "add	%0, %1, %0\n\t"
-			     "wr	%0, 0x0, %%tick_cmpr"
-			     : "=r" (compare)
-			     : "r" (tick_offset));
+			/* Acknowledge INT_TIMER */
+			clear_softint(1 << 0);
+
+			/* Set up for next timer tick. */
+			__asm__ __volatile__("rd	%%tick_cmpr, %0\n\t"
+					     "add	%0, %2, %0\n\t"
+					     "wr	%0, 0x0, %%tick_cmpr\n\t"
+					     "rd	%%tick, %1"
+					     : "=&r" (compare), "=r" (tick)
+					     : "r" (tick_offset));
+		} while(tick >= compare);
+	}
 }
 
 /* This is called from time_init() to get the jiffies timer going. */
@@ -584,7 +676,7 @@
 		prom_timers = (struct sun5_timer *) 0;
 		return;
 	}
-	prom_timers = (struct sun5_timer *) addr[0];
+	prom_timers = (struct sun5_timer *) ((unsigned long)addr[0]);
 }
 
 static void kill_prom_timer(void)
diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/kernel/process.c linux/arch/sparc64/kernel/process.c
--- v2.1.44/linux/arch/sparc64/kernel/process.c	Mon Jul  7 08:18:54 1997
+++ linux/arch/sparc64/kernel/process.c	Wed Jul 16 20:37:21 1997
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.26 1997/07/01 21:15:07 jj Exp $
+/*  $Id: process.c,v 1.29 1997/07/17 02:20:40 davem Exp $
  *  arch/sparc64/kernel/process.c
  *
  *  Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -17,6 +17,8 @@
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 #include <linux/stddef.h>
 #include <linux/unistd.h>
 #include <linux/ptrace.h>
@@ -263,9 +265,6 @@
 
 void show_regs(struct pt_regs * regs)
 {
-#if __MPP__
-	printk("CID: %d\n",mpp_cid());
-#endif
         printk("TSTATE: %016lx TPC: %016lx TNPC: %016lx Y: %08x\n", regs->tstate,
 	       regs->tpc, regs->tnpc, regs->y);
 	printk("g0: %016lx g1: %016lx g2: %016lx g3: %016lx\n",
@@ -285,9 +284,6 @@
 
 void show_regs32(struct pt_regs32 *regs)
 {
-#if __MPP__
-	printk("CID: %d\n",mpp_cid());
-#endif
         printk("PSR: %08x PC: %08x NPC: %08x Y: %08x\n", regs->psr,
 	       regs->pc, regs->npc, regs->y);
 	printk("g0: %08x g1: %08x g2: %08x g3: %08x\n",
@@ -365,26 +361,33 @@
 	__asm__ __volatile__("flush %g6");
 }
 
-static __inline__ struct sparc_stackf *
-clone_stackframe(struct sparc_stackf *dst, struct sparc_stackf *src)
+/* It's a bit more tricky when 64-bit tasks are involved... */
+static unsigned long clone_stackframe(unsigned long csp, unsigned long psp)
 {
-	struct sparc_stackf *sp;
-
-#if 0
-	unsigned long size;
-	size = ((unsigned long)src->fp) - ((unsigned long)src);
-	sp = (struct sparc_stackf *)(((unsigned long)dst) - size); 
+	unsigned long fp, distance, rval;
 
-	if (copy_to_user(sp, src, size))
+	if(!(current->tss.flags & SPARC_FLAG_32BIT)) {
+		csp += STACK_BIAS;
+		psp += STACK_BIAS;
+		__get_user(fp, &(((struct reg_window *)psp)->ins[6]));
+	} else
+		__get_user(fp, &(((struct reg_window32 *)psp)->ins[6]));
+	distance = fp - psp;
+	rval = (csp - distance);
+	if(copy_in_user(rval, psp, distance))
 		return 0;
-	if (put_user(dst, &sp->fp))
-		return 0;
-#endif		
-	return sp;
+	if(current->tss.flags & SPARC_FLAG_32BIT) {
+		if(put_user(((u32)csp), &(((struct reg_window32 *)rval)->ins[6])))
+			return 0;
+		return rval;
+	} else {
+		if(put_user(((u64)csp - STACK_BIAS),
+			    &(((struct reg_window *)rval)->ins[6])))
+			return 0;
+		return rval - STACK_BIAS;
+	}
 }
 
-/* #define DEBUG_WINFIXUPS */
-
 /* Standard stuff. */
 static inline void shift_window_buffer(int first_win, int last_win,
 				       struct thread_struct *tp)
@@ -408,9 +411,6 @@
 		int winsize = REGWIN_SZ;
 		int bias = 0;
 
-#ifdef DEBUG_WINFIXUPS
-		printk("sus(%d", (int)window);
-#endif
 		if(tp->flags & SPARC_FLAG_32BIT)
 			winsize = REGWIN32_SZ;
 		else
@@ -426,9 +426,6 @@
 				tp->w_saved--;
 			}
 		} while(window--);
-#ifdef DEBUG_WINFIXUPS
-		printk(")");
-#endif
 	}
 }
 
@@ -445,9 +442,6 @@
 		bias = STACK_BIAS;
 	flush_user_windows();
 	window = tp->w_saved;
-#ifdef DEBUG_WINFIXUPS
-	printk("fiuw(%d", (int)window);
-#endif
 	if(window != 0) {
 		window -= 1;
 		do {
@@ -459,9 +453,6 @@
 		} while(window--);
 	}
 	current->tss.w_saved = 0;
-#ifdef DEBUG_WINFIXUPS
-	printk(")");
-#endif
 }
 
 /* Copy a Sparc thread.  The fork() return value conventions
@@ -485,10 +476,6 @@
 	char *child_trap_frame;
 	int tframe_size;
 
-#if 0	/* Now all syscall entries flip off the fpu. */
-	if(regs->tstate & TSTATE_PRIV)
-		regs->fprs = 0;
-#endif
 	/* Calculate offset to stack_frame & pt_regs */
 	stack_offset = (((PAGE_SIZE << 1) -
 			((sizeof(unsigned int)*64) + (2*sizeof(unsigned long)))) &
@@ -512,23 +499,14 @@
 		p->tss.flags &= ~SPARC_FLAG_KTHREAD;
 		p->tss.current_ds = USER_DS;
 		p->tss.ctx = (p->mm->context & 0x1fff);
-#if 0
 		if (sp != regs->u_regs[UREG_FP]) {
-			struct sparc_stackf *childstack;
-			struct sparc_stackf *parentstack;
+			unsigned long csp;
 
-			/*
-			 * This is a clone() call with supplied user stack.
-			 * Set some valid stack frames to give to the child.
-			 */
-			childstack = (struct sparc_stackf *)sp;
-			parentstack = (struct sparc_stackf *)regs->u_regs[UREG_FP];
-			childstack = clone_stackframe(childstack, parentstack);
-			if (!childstack)
+			csp = clone_stackframe(sp, regs->u_regs[UREG_FP]);
+			if(!csp)
 				return -EFAULT;
-			childregs->u_regs[UREG_FP] = (unsigned long)childstack;
+			p->tss.kregs->u_regs[UREG_FP] = csp;
 		}
-#endif
 	}
 
 	/* Set the return value for the child. */
@@ -592,9 +570,11 @@
 	if(regs->u_regs[UREG_G1] == 0)
 		base = 1;
 
-	error = getname((char *) regs->u_regs[base + UREG_I0], &filename);
-	if(error)
-		return error;
+	lock_kernel();
+	filename = getname((char *)regs->u_regs[base + UREG_I0]);
+	error = PTR_ERR(filename);
+	if(IS_ERR(filename))
+		goto out;
 	error = do_execve(filename, (char **) regs->u_regs[base + UREG_I1],
 			  (char **) regs->u_regs[base + UREG_I2], regs);
 	putname(filename);
@@ -602,5 +582,7 @@
 		fprs_write(0);
 		regs->fprs = 0;
 	}
+out:
+	unlock_kernel();
 	return error;
 }
diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/kernel/ptrace.c linux/arch/sparc64/kernel/ptrace.c
--- v2.1.44/linux/arch/sparc64/kernel/ptrace.c	Mon Jul  7 08:18:54 1997
+++ linux/arch/sparc64/kernel/ptrace.c	Wed Jul 16 19:22:50 1997
@@ -742,7 +742,7 @@
 		cregs->tstate |= psr_to_tstate_icc(psr);
                	if(!((pc | npc) & 3)) {
 			cregs->tpc = pc;
-			cregs->tpc = npc;
+			cregs->tnpc = npc;
 		}
 		cregs->y = y;
 		for(i = 1; i < 16; i++)
diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/kernel/setup.c linux/arch/sparc64/kernel/setup.c
--- v2.1.44/linux/arch/sparc64/kernel/setup.c	Mon Jul  7 08:18:54 1997
+++ linux/arch/sparc64/kernel/setup.c	Wed Jul 16 19:22:50 1997
@@ -1,4 +1,4 @@
-/*  $Id: setup.c,v 1.9 1997/07/05 09:52:29 davem Exp $
+/*  $Id: setup.c,v 1.10 1997/07/08 11:07:47 jj Exp $
  *  linux/arch/sparc64/kernel/setup.c
  *
  *  Copyright (C) 1995,1996  David S. Miller (davem@caip.rutgers.edu)
@@ -35,6 +35,7 @@
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/idprom.h>
+#include <asm/head.h>
 
 struct screen_info screen_info = {
 	0, 0,			/* orig-x, orig-y */
@@ -288,7 +289,7 @@
 	*memory_start_p = PAGE_ALIGN(((unsigned long) &end));
 	*memory_end_p = (end_of_phys_memory + PAGE_OFFSET);
 
-#ifndef NO_DAVEM_DEBUGGING
+#ifdef DAVEM_DEBUGGING
 	prom_printf("phys_base[%016lx] memory_start[%016lx] memory_end[%016lx]\n",
 		    phys_base, *memory_start_p, *memory_end_p);
 #endif
@@ -303,8 +304,11 @@
 #endif
 #ifdef CONFIG_BLK_DEV_INITRD
 	if (ramdisk_image) {
-		initrd_start = ramdisk_image;
-		if (initrd_start < PAGE_OFFSET) initrd_start += PAGE_OFFSET;
+		unsigned long start = 0;
+		
+		if (ramdisk_image >= (unsigned long)&end - 2 * PAGE_SIZE)
+			ramdisk_image -= KERNBASE;
+		initrd_start = ramdisk_image + phys_base + PAGE_OFFSET;
 		initrd_end = initrd_start + ramdisk_size;
 		if (initrd_end > *memory_end_p) {
 			printk(KERN_CRIT "initrd extends beyond end of memory "
@@ -312,9 +316,11 @@
 		       			 initrd_end,*memory_end_p);
 			initrd_start = 0;
 		}
-		if (initrd_start >= *memory_start_p && initrd_start < *memory_start_p + 2 * PAGE_SIZE) {
+		if (initrd_start)
+			start = ramdisk_image + KERNBASE;
+		if (start >= *memory_start_p && start < *memory_start_p + 2 * PAGE_SIZE) {
 			initrd_below_start_ok = 1;
-			*memory_start_p = PAGE_ALIGN (initrd_end);
+			*memory_start_p = PAGE_ALIGN (start + ramdisk_size);
 		}
 	}
 #endif	
diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/kernel/signal.c linux/arch/sparc64/kernel/signal.c
--- v2.1.44/linux/arch/sparc64/kernel/signal.c	Mon Jul  7 08:18:54 1997
+++ linux/arch/sparc64/kernel/signal.c	Wed Jul 16 19:22:50 1997
@@ -1,4 +1,4 @@
-/*  $Id: signal.c,v 1.17 1997/07/05 09:52:31 davem Exp $
+/*  $Id: signal.c,v 1.20 1997/07/14 03:10:28 davem Exp $
  *  arch/sparc64/kernel/signal.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
@@ -317,8 +317,6 @@
 {
 	struct new_signal_frame *sf;
 	int sigframe_size;
-	unsigned long tmp;
-	int i;
 
 	/* 1. Make sure everything is clean */
 	synchronize_user_stack();
@@ -329,16 +327,13 @@
 	sf = (struct new_signal_frame *)
 		(regs->u_regs[UREG_FP] + STACK_BIAS - sigframe_size);
 	
-	if (invalid_frame_pointer (sf, sigframe_size)) {
-		lock_kernel ();
-		do_exit(SIGILL);
-	}
+	if (invalid_frame_pointer (sf, sigframe_size))
+		goto sigill;
 
 	if (current->tss.w_saved != 0) {
 		printk ("%s[%d]: Invalid user stack frame for "
 			"signal delivery.\n", current->comm, current->pid);
-		lock_kernel ();
-		do_exit (SIGILL);
+		goto sigill;
 	}
 
 	/* 2. Save the current process state */
@@ -352,10 +347,10 @@
 	}
 
 	__put_user(oldmask, &sf->info.si_mask);
-	for (i = 0; i < sizeof(struct reg_window)/sizeof(u64); i++) {
-		__get_user(tmp, (((u64 *)(regs->u_regs[UREG_FP]+STACK_BIAS))+i));
-		__put_user(tmp, (((u64 *)sf)+i));
-	}
+
+	copy_in_user((u64 *)sf,
+		     (u64 *)(regs->u_regs[UREG_FP]+STACK_BIAS),
+		     sizeof(struct reg_window));
 	
 	/* 3. return to kernel instructions */
 	__put_user(0x821020d8, &sf->insns[0]); /* mov __NR_sigreturn, %g1 */
@@ -388,6 +383,11 @@
 			: "memory");
 		}
 	}
+	return;
+
+sigill:
+	lock_kernel();
+	do_exit(SIGILL);
 }
 
 static inline void handle_signal(unsigned long signr, struct sigaction *sa,
@@ -396,8 +396,11 @@
 	new_setup_frame(sa, regs, signr, oldmask);
 	if(sa->sa_flags & SA_ONESHOT)
 		sa->sa_handler = NULL;
-	if(!(sa->sa_flags & SA_NOMASK))
+	if(!(sa->sa_flags & SA_NOMASK)) {
+		spin_lock_irq(&current->sigmask_lock);
 		current->blocked |= (sa->sa_mask | _S(signr)) & _BLOCKABLE;
+		spin_unlock_irq(&current->sigmask_lock);
+	}
 }
 
 static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs,
@@ -439,7 +442,11 @@
 #endif	
 	while ((signr = current->signal & mask) != 0) {
 		signr = ffz(~signr);
-		clear_bit(signr + 32, &current->signal);
+
+		spin_lock_irq(&current->sigmask_lock);
+		current->signal &= ~(1 << signr);
+		spin_unlock_irq(&current->sigmask_lock);
+
 		sa = current->sig->action + signr;
 		signr++;
 		if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
@@ -453,7 +460,9 @@
 			if (signr == SIGSTOP)
 				continue;
 			if (_S(signr) & current->blocked) {
+				spin_lock_irq(&current->sigmask_lock);
 				current->signal |= _S(signr);
+				spin_unlock_irq(&current->sigmask_lock);
 				continue;
 			}
 			sa = current->sig->action + signr - 1;
@@ -496,8 +505,10 @@
 			case SIGQUIT: case SIGILL: case SIGTRAP:
 			case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS:
 				if(current->binfmt && current->binfmt->core_dump) {
+					lock_kernel();
 					if(current->binfmt->core_dump(signr, regs))
 						signr |= 0x80;
+					unlock_kernel();
 				}
 #ifdef DEBUG_SIGNALS
 				/* Very useful to debug dynamic linker problems */
@@ -506,9 +517,15 @@
 #endif
 				/* fall through */
 			default:
+				spin_lock_irq(&current->sigmask_lock);
 				current->signal |= _S(signr & 0x7f);
+				spin_unlock_irq(&current->sigmask_lock);
+
 				current->flags |= PF_SIGNALED;
+
+				lock_kernel();
 				do_exit(signr);
+				unlock_kernel();
 			}
 		}
 		if(restart_syscall)
diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/kernel/signal32.c linux/arch/sparc64/kernel/signal32.c
--- v2.1.44/linux/arch/sparc64/kernel/signal32.c	Mon Jul  7 08:18:54 1997
+++ linux/arch/sparc64/kernel/signal32.c	Wed Jul 16 19:22:50 1997
@@ -1,4 +1,4 @@
-/*  $Id: signal32.c,v 1.23 1997/07/05 07:09:15 davem Exp $
+/*  $Id: signal32.c,v 1.26 1997/07/14 03:10:31 davem Exp $
  *  arch/sparc64/kernel/signal32.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
@@ -245,7 +245,6 @@
 #endif	
 	int old_status = current->tss.sstk_info.cur_status;
 	unsigned psr;
-	int i;
 
 	synchronize_user_stack();
 	regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
@@ -292,13 +291,9 @@
 		}
 	else
 #endif	
-		/* XXX Perhaps we need a copy_in_user()? -DaveM */
-		for (i = 0; i < 16; i++) {
-			u32 temp;
-
-			get_user (temp, (((u32 *)(regs->u_regs[UREG_FP]))+i));
-			put_user (temp, (((u32 *)sframep)+i));
-		}
+		copy_in_user((u32 *)sframep,
+			     (u32 *)(regs->u_regs[UREG_FP]),
+			     sizeof(struct reg_window32));
 		       
 	current->tss.w_saved = 0; /* So process is allowed to execute. */
 	__put_user(signr, &sframep->sig_num);
@@ -351,8 +346,7 @@
 		printk("new_setup_frame32(%s:%d): invalid_frame_pointer(%p, %d)\n",
 		       current->comm, current->pid, sf, sigframe_size);
 #endif
-		lock_kernel ();
-		do_exit(SIGILL);
+		goto sigill;
 	}
 
 	if (current->tss.w_saved != 0) {
@@ -360,8 +354,7 @@
 		printk ("%s[%d]: Invalid user stack frame for "
 			"signal delivery.\n", current->comm, current->pid);
 #endif
-		lock_kernel ();
-		do_exit (SIGILL);
+		goto sigill;
 	}
 
 	/* 2. Save the current process state */
@@ -384,13 +377,9 @@
 
 	__put_user(oldmask, &sf->info.si_mask);
 
-	/* XXX Perhaps we need a copy_in_user()? -DaveM */
-	for (i = 0; i < sizeof(struct reg_window32)/4; i++) {
-		u32 tmp;
-
-		__get_user(tmp, (((u32 *)regs->u_regs[UREG_FP])+i));
-		__put_user(tmp, (((u32 *)sf)+i));
-	}
+	copy_in_user((u32 *)sf,
+		     (u32 *)(regs->u_regs[UREG_FP]),
+		     sizeof(struct reg_window32));
 	
 	/* 3. return to kernel instructions */
 	__put_user(0x821020d8, &sf->insns[0]); /* mov __NR_sigreturn, %g1 */
@@ -423,6 +412,11 @@
 			: "memory");
 		}
 	}
+	return;
+
+sigill:
+	lock_kernel();
+	do_exit(SIGILL);
 }
 
 /* Setup a Solaris stack frame */
@@ -614,16 +608,16 @@
 	
 	if (tp->w_saved){
 		printk ("Uh oh, w_saved is: 0x%lx\n", tp->w_saved);
-		do_exit(SIGSEGV);
+		goto sigsegv;
 	}
 	if (((unsigned long) c) & 3){
 		printk ("Unaligned structure passed\n");
-		do_exit (SIGSEGV);
+		goto sigsegv;
 	}
 
 	if(!__access_ok((unsigned long)c, sizeof(*c))) {
 		/* Miguel, add nice debugging msg _here_. ;-) */
-		do_exit(SIGSEGV);
+		goto sigsegv;
 	}
 
 	/* Check for valid PC and nPC */
@@ -632,7 +626,7 @@
 	__get_user(npc, &((*gr)[SVR4_NPC]));
 	if((pc | npc) & 3) {
 	        printk ("setcontext, PC or nPC were bogus\n");
-		do_exit (SIGSEGV);
+		goto sigsegv;
 	}
 	/* Retrieve information from passed ucontext */
 	    /* note that nPC is ored a 1, this is used to inform entry.S */
@@ -655,6 +649,9 @@
 		__get_user(regs->u_regs[UREG_I0+i], (&(*gr)[SVR4_O0])+i);
 
 	return -EINTR;
+sigsegv:
+	lock_kernel();
+	do_exit(SIGSEGV);
 }
 
 static inline void handle_signal32(unsigned long signr, struct sigaction *sa,
@@ -671,8 +668,11 @@
 	}
 	if(sa->sa_flags & SA_ONESHOT)
 		sa->sa_handler = NULL;
-	if(!(sa->sa_flags & SA_NOMASK))
+	if(!(sa->sa_flags & SA_NOMASK)) {
+		spin_lock_irq(&current->sigmask_lock);
 		current->blocked |= (sa->sa_mask | _S(signr)) & _BLOCKABLE;
+		spin_unlock_irq(&current->sigmask_lock);
+	}
 }
 
 static inline void syscall_restart32(unsigned long orig_i0, struct pt_regs *regs,
@@ -708,7 +708,11 @@
 	
 	while ((signr = current->signal & mask) != 0) {
 		signr = ffz(~signr);
-		clear_bit(signr + 32, &current->signal);
+
+		spin_lock_irq(&current->sigmask_lock);
+		current->signal &= ~(1 << signr);
+		spin_unlock_irq(&current->sigmask_lock);
+
 		sa = current->sig->action + signr;
 		signr++;
 		if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
@@ -722,7 +726,9 @@
 			if (signr == SIGSTOP)
 				continue;
 			if (_S(signr) & current->blocked) {
+				spin_lock_irq(&current->sigmask_lock);
 				current->signal |= _S(signr);
+				spin_unlock_irq(&current->sigmask_lock);
 				continue;
 			}
 			sa = current->sig->action + signr - 1;
@@ -765,8 +771,10 @@
 			case SIGQUIT: case SIGILL: case SIGTRAP:
 			case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS:
 				if(current->binfmt && current->binfmt->core_dump) {
+					lock_kernel();
 					if(current->binfmt->core_dump(signr, regs))
 						signr |= 0x80;
+					unlock_kernel();
 				}
 #ifdef DEBUG_SIGNALS
 				/* Very useful to debug dynamic linker problems */
@@ -775,9 +783,15 @@
 #endif
 				/* fall through */
 			default:
+				spin_lock_irq(&current->sigmask_lock);
 				current->signal |= _S(signr & 0x7f);
+				spin_unlock_irq(&current->sigmask_lock);
+
 				current->flags |= PF_SIGNALED;
+
+				lock_kernel();
 				do_exit(signr);
+				unlock_kernel();
 			}
 		}
 		if(restart_syscall)
diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/kernel/smp.c linux/arch/sparc64/kernel/smp.c
--- v2.1.44/linux/arch/sparc64/kernel/smp.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sparc64/kernel/smp.c	Wed Jul 16 19:22:50 1997
@@ -0,0 +1,347 @@
+/* smp.c: Sparc64 SMP support.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#define __KERNEL_SYSCALLS__
+#include <linux/unistd.h>
+
+extern int linux_num_cpus;
+extern void calibrate_delay(void);
+
+volatile int smp_processors_ready = 0;
+unsigned long cpu_present_map = 0;
+int smp_num_cpus = 1;
+int smp_threads_ready = 0;
+
+struct cpuinfo_sparc64 cpu_data[NR_CPUS];
+static unsigned char boot_cpu_id = 0;
+static int smp_activated = 0;
+
+volatile int cpu_number_map[NR_CPUS];
+volatile int cpu_logical_map[NR_CPUS];
+
+struct klock_info klock_info = { KLOCK_CLEAR, 0 };
+
+static volatile int smp_commenced = 0;
+
+void smp_setup(char *str, int *ints)
+{
+	/* XXX implement me XXX */
+}
+
+static char smp_buf[512];
+
+char *smp_info(void)
+{
+	/* XXX not SMP safe and need to support up to 64 penguins */
+	sprintf(smp_buf,
+"        CPU0\t\tCPU1\t\tCPU2\t\tCPU3\n"
+"State:  %s\t\t%s\t\t%s\t\t%s\n",
+(cpu_present_map & 1) ? ((klock_info.akp == 0) ? "akp" : "online") : "offline",
+(cpu_present_map & 2) ? ((klock_info.akp == 1) ? "akp" : "online") : "offline",
+(cpu_present_map & 4) ? ((klock_info.akp == 2) ? "akp" : "online") : "offline",
+(cpu_present_map & 8) ? ((klock_info.akp == 3) ? "akp" : "online") : "offline");
+	return smp_buf;
+}
+
+void smp_store_cpu_info(int id)
+{
+	cpu_data[id].udelay_val = loops_per_sec;
+}
+
+void smp_commence(void)
+{
+	local_flush_cache_all();
+	local_flush_tlb_all();
+	smp_commenced = 1;
+	local_flush_cache_all();
+	local_flush_tlb_all();
+}
+
+static void smp_setup_percpu_timer(void);
+
+static volatile unsigned long callin_flag = 0;
+
+void smp_callin(void)
+{
+	int cpuid = hard_smp_processor_id();
+
+	local_flush_cache_all();
+	local_flush_tlb_all();
+
+	smp_setup_percpu_timer();
+
+	calibrate_delay();
+	smp_store_cpu_info(cpuid);
+	callin_flag = 1;
+	__asm__ __volatile__("membar #Sync\n\t"
+			     "flush  %g6" : : : "memory");
+
+	while(!task[cpuid])
+		barrier();
+	current = task[cpuid];
+
+	while(!smp_commenced)
+		barrier();
+
+	__sti();
+}
+
+extern int cpu_idle(void *unused);
+extern void init_IRQ(void);
+
+void initialize_secondary(void)
+{
+}
+
+int start_secondary(void *unused)
+{
+	trap_init();
+	init_IRQ();
+	smp_callin();
+	return cpu_idle(NULL);
+}
+
+extern struct prom_cpuinfo linux_cpus[NR_CPUS];
+
+void smp_boot_cpus(void)
+{
+	int cpucount = 0, i, first, prev;
+
+	printk("Entering UltraSMPenguin Mode...\n");
+	__sti();
+	cpu_present_map = 0;
+	for(i = 0; i < linux_num_cpus; i++)
+		cpu_present_map |= (1 << i);
+	for(i = 0; i < NR_CPUS; i++) {
+		cpu_number_map[i] = -1;
+		cpu_logical_map[i] = -1;
+	}
+	cpu_number_map[boot_cpu_id] = 0;
+	cpu_logical_map[0] = boot_cpu_id;
+	klock_info.akp = boot_cpu_id;
+	current->processor = boot_cpu_id;
+	smp_store_cpu_info(boot_cpu_id);
+	smp_setup_percpu_timer();
+
+	if(linux_num_cpus == 1)
+		return;
+
+	for(i = 0; i < NR_CPUS; i++) {
+		if(i == boot_cpu_id)
+			continue;
+
+		if(cpu_present_map & (1 << i)) {
+			extern unsigned long sparc64_cpu_startup;
+			unsigned long entry = (unsigned long)&sparc_cpu_startup;
+			struct task_struct *p;
+			int timeout;
+
+			kernel_thread(start_secondary, NULL, CLONE_PID);
+			p = task[++cpucount];
+			p->processor = i;
+			prom_startcpu(linux_cpus[i].prom_node, entry, i);
+			for(timeout = 0; timeout < 5000000; timeout++) {
+				if(cpu_callin_map[i])
+					break;
+				udelay(100);
+			}
+			if(cpu_callin_map[i]) {
+				/* XXX fix this */
+				cpu_number_map[i] = i;
+				cpu_logical_map[i] = i;
+			} else {
+				cpucount--;
+				printk("Processor %d is stuck.\n", i);
+			}
+		}
+		if(!(cpu_callin_map[i])) {
+			cpu_present_map &= ~(1 << i);
+			cpu_number_map[i] = -1;
+		}
+	}
+	if(cpucount == 0) {
+		printk("Error: only one processor found.\n");
+		cpu_present_map = (1 << smp_processor_id());
+	} else {
+		unsigned long bogosum = 0;
+
+		for(i = 0; i < NR_CPUS; i++) {
+			if(cpu_present_map & (1 << i))
+				bogosum += cpu_data[i].udelay_val;
+		}
+		printk("Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
+		       cpucount + 1,
+		       (bogosum + 2500)/500000,
+		       ((bogosum + 2500)/5000)%100);
+		smp_activated = 1;
+		smp_num_cpus = cpucount + 1;
+	}
+	smp_processors_ready = 1;
+}
+
+/* XXX deprecated interface... */
+void smp_message_pass(int target, int msg, unsigned long data, int wait)
+{
+	printk("smp_message_pass() called, this is bad, spinning.\n");
+	__sti();
+	while(1)
+		barrier();
+}
+
+/* XXX Make it fast later. */
+void smp_cross_call(unsigned long *func, u32 ctx, u64 data1, u64 data2)
+{
+	if(smp_processors_ready) {
+		unsigned long mask;
+		u64 data0 = (((unsigned long)ctx)<<32 |
+			     (((unsigned long)func) & 0xffffffff));
+		u64 pstate;
+		int i, ncpus = smp_num_cpus;
+
+		__asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate));
+		mask = (cpu_present_map & ~(1 << smp_processor_id()));
+		for(i = 0; i < ncpus; i++) {
+			if(mask & (1 << i)) {
+				u64 target = mid<<14 | 0x70;
+				u64 result;
+
+				__asm__ __volatile__("
+				wrpr	%0, %1, %%pstate
+				wrpr	%%g0, %2, %%asi
+				stxa	%3, [0x40] %%asi
+				stxa	%4, [0x50] %%asi
+				stxa	%5, [0x60] %%asi
+				stxa	%%g0, [%6] %7
+				membar	#Sync"
+				: /* No outputs */
+				: "r" (pstate), "i" (PSTATE_IE), "i" (ASI_UDB_INTR_W),
+				  "r" (data0), "r" (data1), "r" (data2),
+				  "r" (target), "i" (ASI_UDB_INTR_W));
+
+				/* NOTE: PSTATE_IE is still clear. */
+				do {
+					__asm__ __volatile__("ldxa [%%g0] %1, %0",
+						: "=r" (result)
+						: "i" (ASI_INTR_DISPATCH_STAT));
+				} while(result & 0x1);
+				__asm__ __volatile__("wrpr %0, 0x0, %%pstate"
+						     : : "r" (pstate));
+				if(result & 0x2)
+					panic("Penguin NACK's master!");
+			}
+		}
+
+		/* NOTE: Caller runs local copy on master. */
+	}
+}
+
+extern unsigned long xcall_flush_tlb_page;
+extern unsigned long xcall_flush_tlb_mm;
+extern unsigned long xcall_flush_tlb_range;
+extern unsigned long xcall_flush_tlb_all;
+extern unsigned long xcall_flush_cache_all;
+
+void smp_flush_cache_all(void)
+{
+	smp_cross_call(&xcall_flush_cache_all, 0, 0, 0);
+}
+
+void smp_flush_tlb_all(void)
+{
+	smp_cross_call(&xcall_flush_tlb_all, 0, 0, 0);
+}
+
+void smp_flush_tlb_mm(struct mm_struct *mm)
+{
+	u32 ctx = mm->context & 0x1fff;
+	if(mm->cpu_vm_mask != (1 << smp_processor_id()))
+		smp_cross_call(&xcall_flush_tlb_mm, ctx, 0, 0);
+	__flush_tlb_mm(ctx);
+}
+
+void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start,
+			 unsigned long end)
+{
+	u32 ctx = mm->context & 0x1fff;
+	if(mm->cpu_vm_mask != (1 << smp_processor_id()))
+		smp_cross_call(&xcall_flush_tlb_range, ctx, start, end);
+	__flush_tlb_range(ctx, start, end);
+}
+
+void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
+{
+	struct mm_struct *mm = vma->vm_mm;
+	u32 ctx = mm->context & 0x1fff;
+
+	if(mm->cpu_vm_mask != (1 << smp_processor_id()))
+		smp_cross_call(&xcall_flush_tlb_page, ctx, page, 0);
+	__flush_tlb_page(ctx, page);
+}
+
+static spinlock_t ticker_lock = SPIN_LOCK_UNLOCKED;
+
+static inline void sparc64_do_profile(unsigned long pc)
+{
+	if(prof_buffer && current->pid) {
+		extern int _stext;
+
+		pc -= (unsigned long) &_stext;
+		pc >>= prof_shift;
+
+		spin_lock(&ticker_lock);
+		if(pc < prof_len)
+			prof_buffer[pc]++;
+		else
+			prof_buffer[prof_len - 1]++;
+		spin_unlock(&ticker_lock);
+	}
+}
+
+unsigned int prof_multiplier[NR_CPUS];
+unsigned int prof_counter[NR_CPUS];
+
+extern void update_one_process(struct task_struct *p, unsigned long ticks,
+			       unsigned long user, unsigned long system);
+
+void smp_percpu_timer_interrupt(struct pt_regs *regs)
+{
+	int cpu = smp_processor_id();
+
+	clear_profile_irq(cpu);
+	if(!user_mode(regs))
+		sparc_do_profile(regs->pc);
+	if(!--prof_counter[cpu]) {
+		int user = user_mode(regs);
+		if(current->pid) {
+			update_one_process(current, 1, user, !user);
+			if(--current->counter < 0) {
+				current->counter = 0;
+				need_resched = 1;
+			}
+
+			spin_lock(&ticker_lock);
+			if(user) {
+				if(current->priority < DEF_PRIORITY)
+					kstat.cpu_nice++;
+				else
+					kstat.cpu_user++;
+			} else {
+				kstat.cpu_system++;
+			}
+			spin_unlock(&ticker_lock);
+		}
+		prof_counter[cpu] = prof_multiplier[cpu];
+	}
+}
+
+static void smp_setup_percpu_timer(void)
+{
+	/* XXX implement me */
+}
+
+int setup_profiling_timer(unsigned int multiplier)
+{
+	/* XXX implement me */
+}
diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/kernel/sparc64_ksyms.c linux/arch/sparc64/kernel/sparc64_ksyms.c
--- v2.1.44/linux/arch/sparc64/kernel/sparc64_ksyms.c	Mon Jul  7 08:18:54 1997
+++ linux/arch/sparc64/kernel/sparc64_ksyms.c	Wed Jul 16 19:22:50 1997
@@ -1,4 +1,4 @@
-/* $Id: sparc64_ksyms.c,v 1.8 1997/07/07 04:58:14 davem Exp $
+/* $Id: sparc64_ksyms.c,v 1.11 1997/07/14 23:58:20 davem Exp $
  * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -18,6 +18,8 @@
 #include <asm/pgtable.h>
 #include <asm/io.h>
 #include <asm/irq.h>
+#include <asm/softirq.h>
+#include <asm/hardirq.h>
 #include <asm/idprom.h>
 #include <asm/svr4.h>
 #include <asm/head.h>
@@ -79,20 +81,12 @@
 EXPORT_SYMBOL(request_fast_irq);
 EXPORT_SYMBOL(sparc_alloc_io);
 EXPORT_SYMBOL(sparc_free_io);
-#if 0
-EXPORT_SYMBOL(io_remap_page_range);
-EXPORT_SYMBOL(mmu_unlockarea);
-EXPORT_SYMBOL(mmu_lockarea);
+EXPORT_SYMBOL(local_irq_count);
+EXPORT_SYMBOL(__sparc64_bh_counter);
+EXPORT_SYMBOL(sparc_ultra_unmapioaddr);
 EXPORT_SYMBOL(mmu_get_scsi_sgl);
 EXPORT_SYMBOL(mmu_get_scsi_one);
-EXPORT_SYMBOL(mmu_release_scsi_sgl);
-EXPORT_SYMBOL(mmu_release_scsi_one);
-#endif
 EXPORT_SYMBOL(sparc_dvma_malloc);
-#if 0
-EXPORT_SYMBOL(sun4c_unmapioaddr);
-EXPORT_SYMBOL(srmmu_unmapioaddr);
-#endif
 #if CONFIG_SBUS
 EXPORT_SYMBOL(SBus_chain);
 EXPORT_SYMBOL(dma_chain);
diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/kernel/sunos_ioctl32.c linux/arch/sparc64/kernel/sunos_ioctl32.c
--- v2.1.44/linux/arch/sparc64/kernel/sunos_ioctl32.c	Mon Jul  7 08:18:54 1997
+++ linux/arch/sparc64/kernel/sunos_ioctl32.c	Wed Jul 16 20:37:21 1997
@@ -1,4 +1,4 @@
-/* $Id: sunos_ioctl32.c,v 1.2 1997/07/05 07:09:16 davem Exp $
+/* $Id: sunos_ioctl32.c,v 1.4 1997/07/17 02:20:43 davem Exp $
  * sunos_ioctl32.c: SunOS ioctl compatability on sparc64.
  *
  * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -86,14 +86,19 @@
 extern asmlinkage int sys32_ioctl(unsigned int, unsigned int, u32);
 extern asmlinkage int sys_setsid(void);
 
-asmlinkage int sunos_ioctl (int fd, unsigned long cmd, u32 arg)
+asmlinkage int sunos_ioctl (int fd, u32 cmd, u32 arg)
 {
 	struct file *filp;
 	int ret = -EBADF;
 
 	lock_kernel();
-	if(fd >= SUNOS_NR_OPEN || !(filp = current->files->fd[fd]))
+	if(fd >= SUNOS_NR_OPEN)
 		goto out;
+
+	filp = current->files->fd[fd];
+	if(!filp)
+		goto out;
+
 	if(cmd == TIOCSETD) {
 		unsigned long old_fs = get_fs();
 		int *p, ntty = N_TTY;
diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c
--- v2.1.44/linux/arch/sparc64/kernel/sys_sparc32.c	Mon Jul  7 08:18:54 1997
+++ linux/arch/sparc64/kernel/sys_sparc32.c	Wed Jul 16 20:37:21 1997
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.42 1997/07/05 09:52:36 davem Exp $
+/* $Id: sys_sparc32.c,v 1.43 1997/07/17 02:20:45 davem Exp $
  * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -759,14 +759,29 @@
 asmlinkage long sys32_readv(int fd, u32 vector, u32 count)
 {
 	struct file *file;
+	struct dentry *dentry;
 	struct inode *inode;
 	long err = -EBADF;
 
 	lock_kernel();
-	if (fd >= NR_OPEN || !(file = current->files->fd[fd]) || !(inode=file->f_inode))
+	if(fd >= NR_OPEN)
 		goto out;
-	if (!(file->f_mode & 1))
+
+	file = current->files->fd[fd];
+	if(!file)
+		goto out;
+
+	if(!(file->f_mode & 1))
+		goto out;
+
+	dentry = file->f_dentry;
+	if(!dentry)
+		goto out;
+
+	inode = dentry->d_inode;
+	if(!inode)
 		goto out;
+
 	err = do_readv_writev32(VERIFY_WRITE, inode, file,
 				(struct iovec32 *)A(vector), count);
 out:
@@ -778,13 +793,28 @@
 {
 	int error = -EBADF;
 	struct file *file;
+	struct dentry *dentry;
 	struct inode *inode;
 
 	lock_kernel();
-	if (fd >= NR_OPEN || !(file = current->files->fd[fd]) || !(inode=file->f_inode))
+	if(fd >= NR_OPEN)
+		goto out;
+
+	file = current->files->fd[fd];
+	if(!file)
+		goto out;
+
+	if(!(file->f_mode & 2))
+		goto out;
+
+	dentry = file->f_dentry;
+	if(!dentry)
 		goto out;
-	if (!(file->f_mode & 2))
+
+	inode = dentry->d_inode;
+	if(!inode)
 		goto out;
+
 	down(&inode->i_sem);
 	error = do_readv_writev32(VERIFY_READ, inode, file,
 				(struct iovec32 *)A(vector), count);
@@ -833,21 +863,34 @@
 {
 	int error = -EBADF;
 	struct file * file;
+	struct dentry * dentry;
+	struct inode * inode;
 	struct readdir_callback32 buf;
 
 	lock_kernel();
-	if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+	if(fd >= NR_OPEN)
 		goto out;
-	error = -ENOTDIR;
-	if (!file->f_op || !file->f_op->readdir)
+
+	file = current->files->fd[fd];
+	if(!file)
 		goto out;
-	error = verify_area(VERIFY_WRITE, (void *)A(dirent),
-			    sizeof(struct old_linux_dirent32));
-	if (error)
+
+	dentry = file->f_dentry;
+	if(!dentry)
 		goto out;
+
+	inode = dentry->d_inode;
+	if(!inode)
+		goto out;
+
 	buf.count = 0;
 	buf.dirent = (struct old_linux_dirent32 *)A(dirent);
-	error = file->f_op->readdir(file->f_inode, file, &buf, fillonedir);
+
+	error = -ENOTDIR;
+	if (!file->f_op || !file->f_op->readdir)
+		goto out;
+
+	error = file->f_op->readdir(inode, file, &buf, fillonedir);
 	if (error < 0)
 		goto out;
 	error = buf.count;
@@ -897,30 +940,43 @@
 asmlinkage int sys32_getdents(unsigned int fd, u32 dirent, unsigned int count)
 {
 	struct file * file;
+	struct dentry * dentry;
+	struct inode *inode;
 	struct linux_dirent32 * lastdirent;
 	struct getdents_callback32 buf;
 	int error = -EBADF;
 
 	lock_kernel();
-	if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+	if(fd >= NR_OPEN)
 		goto out;
-	error = -ENOTDIR;
-	if (!file->f_op || !file->f_op->readdir)
+
+	file = current->files->fd[fd];
+	if(!file)
 		goto out;
-	error = verify_area(VERIFY_WRITE, (void *)A(dirent), count);
-	if (error)
+
+	dentry = file->f_dentry;
+	if(!dentry)
 		goto out;
+
+	inode = dentry->d_inode;
+	if(!inode)
+		goto out;
+
 	buf.current_dir = (struct linux_dirent32 *) A(dirent);
 	buf.previous = NULL;
 	buf.count = count;
 	buf.error = 0;
-	error = file->f_op->readdir(file->f_inode, file, &buf, filldir);
+
+	error = -ENOTDIR;
+	if (!file->f_op || !file->f_op->readdir)
+		goto out;
+
+	error = file->f_op->readdir(inode, file, &buf, filldir);
 	if (error < 0)
 		goto out;
 	lastdirent = buf.previous;
-	if (!lastdirent) {
-		error = buf.error;
-	} else {
+	error = buf.error;
+	if(lastdirent) {
 		put_user(file->f_pos, &lastdirent->d_off);
 		error = count - buf.count;
 	}
@@ -1725,11 +1781,11 @@
 		return NULL;
 	}
 
-	inode = file->f_inode;
+	inode = file->f_dentry->d_inode;
 	if (!inode || !inode->i_sock || !socki_lookup(inode))
 	{
 		*err = -ENOTSOCK;
-		fput(file,inode);
+		fput(file);
 		return NULL;
 	}
 
@@ -1738,7 +1794,7 @@
 
 extern __inline__ void sockfd_put(struct socket *sock)
 {
-	fput(sock->file,sock->inode);
+	fput(sock->file);
 }
 
 struct msghdr32 {
@@ -2168,25 +2224,33 @@
 do_execve32(char * filename, u32 * argv, u32 * envp, struct pt_regs * regs)
 {
 	struct linux_binprm bprm;
+	struct dentry * dentry;
 	int retval;
 	int i;
 
 	bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
 	for (i=0 ; i<MAX_ARG_PAGES ; i++)	/* clear page-table */
 		bprm.page[i] = 0;
-	retval = open_namei(filename, 0, 0, &bprm.inode, NULL);
-	if (retval)
+
+	dentry = open_namei(filename, 0, 0);
+	retval = PTR_ERR(dentry);
+	if (IS_ERR(dentry))
 		return retval;
+
+	bprm.dentry = dentry;
 	bprm.filename = filename;
 	bprm.sh_bang = 0;
 	bprm.java = 0;
 	bprm.loader = 0;
 	bprm.exec = 0;
-	bprm.dont_iput = 0;
-	if ((bprm.argc = count32(argv)) < 0)
+	if ((bprm.argc = count32(argv)) < 0) {
+		dput(dentry);
 		return bprm.argc;
-	if ((bprm.envc = count32(envp)) < 0)
+	}
+	if ((bprm.envc = count32(envp)) < 0) {
+		dput(dentry);
 		return bprm.envc;
+	}
 
 	retval = prepare_binprm(&bprm);
 	
@@ -2206,8 +2270,9 @@
 		return retval;
 
 	/* Something went wrong, return the inode and free the argument pages*/
-	if(!bprm.dont_iput)
-		iput(bprm.inode);
+	if(bprm.dentry)
+		dput(bprm.dentry);
+
 	for (i=0 ; i<MAX_ARG_PAGES ; i++)
 		free_page(bprm.page[i]);
 	return(retval);
@@ -2226,17 +2291,22 @@
         if((u32)regs->u_regs[UREG_G1] == 0)
                 base = 1;
 
-        error = getname((char *)(unsigned long)(u32)regs->u_regs[base + UREG_I0], &filename);
-        if(error)
-                return error;
+	lock_kernel();
+        filename = getname((char *)(unsigned long)(u32)regs->u_regs[base + UREG_I0]);
+	error = PTR_ERR(filename);
+        if(IS_ERR(filename))
+                goto out;
         error = do_execve32(filename,
         	(u32 *)A((u32)regs->u_regs[base + UREG_I1]),
         	(u32 *)A((u32)regs->u_regs[base + UREG_I2]), regs);
         putname(filename);
+
 	if(!error) {
 		fprs_write(0);
 		regs->fprs = 0;
 	}
+out:
+	unlock_kernel();
         return error;
 }
 
diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/kernel/sys_sunos32.c linux/arch/sparc64/kernel/sys_sunos32.c
--- v2.1.44/linux/arch/sparc64/kernel/sys_sunos32.c	Mon Jul  7 08:18:54 1997
+++ linux/arch/sparc64/kernel/sys_sunos32.c	Wed Jul 16 20:37:21 1997
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos32.c,v 1.2 1997/07/05 07:09:16 davem Exp $
+/* $Id: sys_sunos32.c,v 1.3 1997/07/17 02:20:48 davem Exp $
  * sys_sunos32.c: SunOS binary compatability layer on sparc64.
  *
  * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -80,10 +80,12 @@
 			goto out;
 		addr = (u32) attempt;
 	}
-	if(MAJOR(file->f_inode->i_rdev) == MEM_MAJOR &&
-	   MINOR(file->f_inode->i_rdev) == 5) {
-		flags |= MAP_ANONYMOUS;
-		file = 0;
+	if(file->f_dentry && file->f_dentry->d_inode) {
+		if(MAJOR(file->f_dentry->d_inode->i_rdev) == MEM_MAJOR &&
+		   MINOR(file->f_dentry->d_inode->i_rdev) == 5) {
+			flags |= MAP_ANONYMOUS;
+			file = 0;
+		}
 	}
 	if(!(flags & MAP_FIXED))
 		addr = 0;
@@ -377,17 +379,33 @@
 asmlinkage int sunos_getdents(unsigned int fd, u32 u_dirent, int cnt)
 {
 	struct file * file;
+	struct dentry * dentry;
+	struct inode * inode;
 	struct sunos_dirent * lastdirent;
 	struct sunos_dirent_callback buf;
 	int error = -EBADF;
 	void *dirent = (void *)A(u_dirent);
 
 	lock_kernel();
-	if (fd >= SUNOS_NR_OPEN || !(file = current->files->fd[fd]))
+	if(fd >= SUNOS_NR_OPEN)
 		goto out;
+
+	file = current->files->fd[fd];
+	if(!file)
+		goto out;
+
+	dentry = file->f_dentry;
+	if(!dentry)
+		goto out;
+
+	inode = dentry->d_inode;
+	if(!inode)
+		goto out;
+
 	error = -ENOTDIR;
 	if (!file->f_op || !file->f_op->readdir)
 		goto out;
+
 	error = -EINVAL;
 	if(cnt < (sizeof(struct sunos_dirent) + 255))
 		goto out;
@@ -396,13 +414,13 @@
 	buf.previous = NULL;
 	buf.count = cnt;
 	buf.error = 0;
-	error = file->f_op->readdir(file->f_inode, file, &buf, sunos_filldir);
+
+	error = file->f_op->readdir(inode, file, &buf, sunos_filldir);
 	if (error < 0)
 		goto out;
 	lastdirent = buf.previous;
-	if (!lastdirent) {
-		error = buf.error;
-	} else {
+	error = buf.error;
+	if (lastdirent) {
 		put_user(file->f_pos, &lastdirent->d_off);
 		error = cnt - buf.count;
 	}
@@ -454,6 +472,8 @@
 				   int cnt, u32 u_basep)
 {
 	struct file * file;
+	struct dentry * dentry;
+	struct inode * inode;
 	struct sunos_direntry * lastdirent;
 	struct sunos_direntry_callback buf;
 	int error = -EBADF;
@@ -461,11 +481,25 @@
 	unsigned int *basep = (unsigned int *)A(u_basep);
 
 	lock_kernel();
-	if (fd >= SUNOS_NR_OPEN || !(file = current->files->fd[fd]))
+	if(fd >= SUNOS_NR_OPEN)
+		goto out;
+
+	file = current->files->fd[fd];
+	if(!file)
 		goto out;
+
+	dentry = file->f_dentry;
+	if(!dentry)
+		goto out;
+
+	inode = dentry->d_inode;
+	if(!inode)
+		goto out;
+
 	error = -ENOTDIR;
 	if (!file->f_op || !file->f_op->readdir)
 		goto out;
+
 	error = -EINVAL;
 	if(cnt < (sizeof(struct sunos_direntry) + 255))
 		goto out;
@@ -474,13 +508,13 @@
 	buf.previous = NULL;
 	buf.count = cnt;
 	buf.error = 0;
-	error = file->f_op->readdir(file->f_inode, file, &buf, sunos_filldirentry);
+
+	error = file->f_op->readdir(inode, file, &buf, sunos_filldirentry);
 	if (error < 0)
 		goto out;
 	lastdirent = buf.previous;
-	if (!lastdirent) {
-		error = buf.error;
-	} else {
+	error = buf.error;
+	if (lastdirent) {
 		put_user(file->f_pos, basep);
 		error = cnt - buf.count;
 	}
@@ -684,12 +718,20 @@
 	int    try_port;
 	int    ret;
 	struct socket *socket;
+	struct dentry *dentry;
 	struct inode  *inode;
 	struct file   *file;
 
 	file = current->files->fd [fd];
-	inode = file->f_inode;
-	if (!inode || !inode->i_sock)
+	if(!file)
+		return 0;
+
+	dentry = file->f_dentry;
+	if(!dentry)
+		return 0;
+
+	inode = dentry->d_inode;
+	if(!inode)
 		return 0;
 
 	socket = &inode->u.socket_i;
@@ -770,7 +812,8 @@
 	linux_nfs_mount.acdirmin = sunos_mount->acdirmin;
 	linux_nfs_mount.acdirmax = sunos_mount->acdirmax;
 
-	if (getname (sunos_mount->hostname, &the_name))
+	the_name = getname(sunos_mount->hostname);
+	if(IS_ERR(the_name))
 		return -EFAULT;
 
 	strncpy (linux_nfs_mount.hostname, the_name, 254);
diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/kernel/winfixup.S linux/arch/sparc64/kernel/winfixup.S
--- v2.1.44/linux/arch/sparc64/kernel/winfixup.S	Mon Jul  7 08:18:54 1997
+++ linux/arch/sparc64/kernel/winfixup.S	Wed Jul 16 19:22:50 1997
@@ -1,4 +1,4 @@
-/* $Id: winfixup.S,v 1.15 1997/07/04 01:41:07 davem Exp $
+/* $Id: winfixup.S,v 1.16 1997/07/13 20:02:42 davem Exp $
  *
  * winfixup.S: Handle cases where user stack pointer is found to be bogus.
  *
@@ -68,7 +68,7 @@
 	mov		%g5, %l5			! Fault address
 	clr		%l4				! It was a load, not a store
 	wrpr		%g0, 0x0, %tl			! Out of trap levels.
-	wrpr		%l1, (PSTATE_IE | PSTATE_AG), %pstate
+	wrpr		%l1, (PSTATE_IE | PSTATE_AG | PSTATE_RMO), %pstate
 	sethi		%uhi(PAGE_OFFSET), %g4		! Prepare page_offset global reg
 	mov		%o7, %g6
 	b,pt		%xcc, window_scheisse_merge	! And merge.
@@ -186,7 +186,7 @@
 	mov		%g5, %o4			! final call to do_sparc64_fault.
 	mov		%g6, %o7			! Stash away current.
 	wrpr		%g0, 0x0, %tl			! Out of trap levels.
-	wrpr		%l1, (PSTATE_IE | PSTATE_AG), %pstate
+	wrpr		%l1, (PSTATE_IE | PSTATE_AG | PSTATE_RMO), %pstate
 	sethi		%uhi(PAGE_OFFSET), %g4		! Set page_offset global reg.
 	mov		%o7, %g6			! Get current back.
 	b,pt		%xcc, window_mna_merge		! And merge.
diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/lib/Makefile linux/arch/sparc64/lib/Makefile
--- v2.1.44/linux/arch/sparc64/lib/Makefile	Mon Jul  7 08:18:55 1997
+++ linux/arch/sparc64/lib/Makefile	Wed Jul 16 20:37:21 1997
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.12 1997/06/25 10:12:18 jj Exp $
+# $Id: Makefile,v 1.13 1997/07/16 10:12:03 jj Exp $
 # Makefile for Sparc library files..
 #
 
@@ -6,7 +6,7 @@
 
 OBJS  = blockops.o locks.o strlen.o strncmp.o \
 	memscan.o strncpy_from_user.o strlen_user.o memcmp.o checksum.o \
-	VIScopy.o VISbzero.o VISmemset.o
+	VIScopy.o VISbzero.o VISmemset.o VIScsum.o
 
 lib.a: $(OBJS)
 	$(AR) rcs lib.a $(OBJS)
diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/lib/VIScopy.S linux/arch/sparc64/lib/VIScopy.S
--- v2.1.44/linux/arch/sparc64/lib/VIScopy.S	Mon Jul  7 08:18:55 1997
+++ linux/arch/sparc64/lib/VIScopy.S	Wed Jul 16 19:22:50 1997
@@ -1,4 +1,4 @@
-/* $Id: VIScopy.S,v 1.8 1997/06/28 17:21:22 jj Exp $
+/* $Id: VIScopy.S,v 1.9 1997/07/13 18:23:39 davem Exp $
  * VIScopy.S: High speed copy operations utilizing the UltraSparc
  *            Visual Instruction Set.
  *
@@ -315,6 +315,14 @@
 		.globl			__copy_to_user
 		.type			__copy_to_user,@function
 __copy_to_user:	mov		ASI_BLK_P, asi_src		! IEU0	Group
+		brnz,pt		%o2, __memcpy_entry		! CTI
+		 mov		ASI_BLK_S, asi_dest		! IEU1
+		retl						! CTI	Group
+		 clr		%o0				! IEU0	Group
+
+		.globl			__copy_in_user
+		.type			__copy_in_user,@function
+__copy_in_user:	mov		ASI_BLK_S, asi_src		! IEU0	Group
 		brnz,pt		%o2, __memcpy_entry		! CTI
 		 mov		ASI_BLK_S, asi_dest		! IEU1
 		retl						! CTI	Group
diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/lib/VIScsum.S linux/arch/sparc64/lib/VIScsum.S
--- v2.1.44/linux/arch/sparc64/lib/VIScsum.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/sparc64/lib/VIScsum.S	Wed Jul 16 20:37:21 1997
@@ -0,0 +1,436 @@
+/* $Id: VIScsum.S,v 1.1 1997/07/16 10:12:02 jj Exp $
+ * VIScsum.S: High bandwidth IP checksumming utilizing the UltraSparc
+ *            Visual Instruction Set.
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ *
+ * Based on older sparc32/sparc64 checksum.S, which is:
+ *
+ *      Copyright(C) 1995 Linus Torvalds
+ *      Copyright(C) 1995 Miguel de Icaza
+ *      Copyright(C) 1996,1997 David S. Miller
+ *    derived from:
+ *	  Linux/Alpha checksum c-code
+ *        Linux/ix86 inline checksum assembly
+ *        RFC1071 Computing the Internet Checksum (esp. Jacobsons m68k code)
+ *	  David Mosberger-Tang for optimized reference c-code
+ *	  BSD4.4 portable checksum routine
+ */
+
+#ifdef __sparc_v9__
+#define STACKOFF	2175
+#else
+#define STACKOFF	64
+#endif
+
+#ifdef __KERNEL__
+#include <asm/head.h>
+#include <asm/asi.h>
+#else
+#define ASI_BLK_P	0xf0
+#define FRPS_FEF	0x04
+#endif
+
+/* Dobrou noc, SunSoft engineers. Spete sladce.
+ * This has a couple of tricks in and those
+ * tricks are UltraLinux trade secrets :))
+ */
+
+#define START_THE_TRICK(fz,f0,f2,f4,f6,f8,f10)							\
+	fcmpgt32	%fz, %f0, %g1		/*  FPM		Group			*/;	\
+	fcmpgt32	%fz, %f2, %g2		/*  FPM		Group			*/;	\
+	fcmpgt32	%fz, %f4, %g3		/*  FPM		Group			*/;	\
+	fcmpgt32	%fz, %f6, %g5		/*  FPM		Group			*/;	\
+	inc		%g1			/*  IEU0				*/;	\
+	fcmpgt32	%fz, %f8, %g7		/*  FPM		Group			*/;	\
+	srl		%g1, 1, %g1		/*  IEU0				*/;	\
+	inc		%g2			/*  IEU1				*/;	\
+	fcmpgt32	%fz, %f10, %o3		/*  FPM		Group			*/;	\
+	srl		%g2, 1, %g2		/*  IEU0				*/;	\
+	add		%o2, %g1, %o2		/*  IEU1				*/;	\
+	add		%g3, 1, %g3		/*  IEU0	Group			*/;	\
+	srl		%g3, 1, %g3		/*  IEU0	Group			*/;	\
+	add		%o2, %g2, %o2		/*  IEU1				*/;	\
+	inc		%g5			/*  IEU0	Group			*/;	\
+	add		%o2, %g3, %o2		/*  IEU1				*/;
+
+#define DO_THE_TRICK(O12,O14,f0,f2,f4,f6,f8,f10,f12,f14,F0,F2,F4,F6,F8,F10,F12,F14)		\
+	fcmpgt32	%O12, %f12, %o4		/*  FPM		Group			*/;	\
+	srl		%g5, 1, %g5		/*  IEU0				*/;	\
+	inc		%g7			/*  IEU1				*/;	\
+	fpadd32		%F0, %f0, %F0		/*  FPA					*/;	\
+	fcmpgt32	%O14, %f14, %o5		/*  FPM		Group			*/;	\
+	srl		%g7, 1, %g7		/*  IEU0				*/;	\
+	add		%o2, %g5, %o2		/*  IEU1				*/;	\
+	fpadd32		%F2, %f2, %F2		/*  FPA					*/;	\
+	inc		%o3			/*  IEU0	Group			*/;	\
+	add		%o2, %g7, %o2		/*  IEU1				*/;	\
+	fcmpgt32	%f0, %F0, %g1		/*  FPM		Group			*/;	\
+	srl		%o3, 1, %o3		/*  IEU0				*/;	\
+	inc		%o4			/*  IEU1				*/;	\
+	fpadd32		%F4, %f4, %F4		/*  FPA					*/;	\
+	fcmpgt32	%f2, %F2, %g2		/*  FPM		Group			*/;	\
+	srl		%o4, 1, %o4		/*  IEU0				*/;	\
+	add		%o2, %o3, %o2		/*  IEU1				*/;	\
+	fpadd32		%F6, %f6, %F6		/*  FPA					*/;	\
+	inc		%o5			/*  IEU0	Group			*/;	\
+	add		%o2, %o4, %o2		/*  IEU1				*/;	\
+	fcmpgt32	%f4, %F4, %g3		/*  FPM		Group			*/;	\
+	srl		%o5, 1, %o5		/*  IEU0				*/;	\
+	inc		%g1			/*  IEU1				*/;	\
+	fpadd32		%F8, %f8, %F8		/*  FPA					*/;	\
+	fcmpgt32	%f6, %F6, %g5		/*  FPM		Group			*/;	\
+	srl		%g1, 1, %g1		/*  IEU0				*/;	\
+	add		%o2, %o5, %o2		/*  IEU1				*/;	\
+	fpadd32		%F10, %f10, %F10	/*  FPA					*/;	\
+	inc		%g2			/*  IEU0	Group			*/;	\
+	add		%o2, %g1, %o2		/*  IEU1				*/;	\
+	fcmpgt32	%f8, %F8, %g7		/*  FPM		Group			*/;	\
+	srl		%g2, 1, %g2		/*  IEU0				*/;	\
+	inc		%g3			/*  IEU1				*/;	\
+	fpadd32		%F12, %f12, %F12	/*  FPA					*/;	\
+	fcmpgt32	%f10, %F10, %o3		/*  FPM		Group			*/;	\
+	srl		%g3, 1, %g3		/*  IEU0				*/;	\
+	add		%o2, %g2, %o2		/*  IEU1				*/;	\
+	fpadd32		%F14, %f14, %F14	/*  FPA					*/;	\
+	inc		%g5			/*  IEU0	Group			*/;	\
+	add		%o2, %g3, %o2		/*  IEU1				*/;
+
+#define END_THE_TRICK(O12,O14,f0,f2,f4,f6,f8,f10,f12,f14,S0,S1,S2,S3,T0,T1,U0,fz)		\
+	fcmpgt32	%O12, %f12, %o4		/*  FPM		Group			*/;	\
+	srl		%g5, 1, %g5		/*  IEU0				*/;	\
+	inc		%g7			/*  IEU1				*/;	\
+	fpadd32		%f2, %f0, %S0		/*  FPA					*/;	\
+	fcmpgt32	%O14, %f14, %o5		/*  FPM		Group			*/;	\
+	srl		%g7, 1, %g7		/*  IEU0				*/;	\
+	add		%o2, %g5, %o2		/*  IEU1				*/;	\
+	fpadd32		%f6, %f4, %S1		/*  FPA					*/;	\
+	inc		%o3			/*  IEU0	Group			*/;	\
+	add		%o2, %g7, %o2		/*  IEU1				*/;	\
+	fcmpgt32	%f0, %S0, %g1		/*  FPM		Group			*/;	\
+	srl		%o3, 1, %o3		/*  IEU0				*/;	\
+	inc		%o4			/*  IEU1				*/;	\
+	fpadd32		%f10, %f8, %S2		/*  FPA					*/;	\
+	fcmpgt32	%f4, %S1, %g2		/*  FPM		Group			*/;	\
+	srl		%o4, 1, %o4		/*  IEU0				*/;	\
+	add		%o2, %o3, %o2		/*  IEU1				*/;	\
+	fpadd32		%f14, %f12, %S3		/*  FPA					*/;	\
+	inc		%o5			/*  IEU0	Group			*/;	\
+	add		%o2, %o4, %o2		/*  IEU1				*/;	\
+	fzero		%fz			/*  FPA					*/;	\
+	fcmpgt32	%f8, %S2, %g3		/*  FPM		Group			*/;	\
+	srl		%o5, 1, %o5		/*  IEU0				*/;	\
+	inc		%g1			/*  IEU1				*/;	\
+	fpadd32		%S0, %S1, %T0		/*  FPA					*/;	\
+	fcmpgt32	%f12, %S3, %g5		/*  FPM		Group			*/;	\
+	srl		%g1, 1, %g1		/*  IEU0				*/;	\
+	add		%o2, %o5, %o2		/*  IEU1				*/;	\
+	fpadd32		%S2, %S3, %T1		/*  FPA					*/;	\
+	inc		%g2			/*  IEU0	Group			*/;	\
+	add		%o2, %g1, %o2		/*  IEU1				*/;	\
+	fcmpgt32	%S0, %T0, %g7		/*  FPM		Group			*/;	\
+	srl		%g2, 1, %g2		/*  IEU0				*/;	\
+	inc		%g3			/*  IEU1				*/;	\
+	fcmpgt32	%S2, %T1, %o3		/*  FPM		Group			*/;	\
+	srl		%g3, 1, %g3		/*  IEU0				*/;	\
+	add		%o2, %g2, %o2		/*  IEU1				*/;	\
+	inc		%g5			/*  IEU0	Group			*/;	\
+	add		%o2, %g3, %o2		/*  IEU1				*/;	\
+	fcmpgt32	%fz, %f2, %o4		/*  FPM		Group			*/;	\
+	srl		%g5, 1, %g5		/*  IEU0				*/;	\
+	inc		%g7			/*  IEU1				*/;	\
+	fpadd32		%T0, %T1, %U0		/*  FPA					*/;	\
+	fcmpgt32	%fz, %f6, %o5		/*  FPM		Group			*/;	\
+	srl		%g7, 1, %g7		/*  IEU0				*/;	\
+	add		%o2, %g5, %o2		/*  IEU1				*/;	\
+	inc		%o3			/*  IEU0	Group			*/;	\
+	add		%o2, %g7, %o2		/*  IEU1				*/;	\
+	fcmpgt32	%fz, %f10, %g1		/*  FPM		Group			*/;	\
+	srl		%o3, 1, %o3		/*  IEU0				*/;	\
+	inc		%o4			/*  IEU1				*/;	\
+	fcmpgt32	%fz, %f14, %g2		/*  FPM		Group			*/;	\
+	srl		%o4, 1, %o4		/*  IEU0				*/;	\
+	add		%o2, %o3, %o2		/*  IEU1				*/;	\
+	std		%U0, [%sp + STACKOFF]	/*  Store	Group			*/;	\
+	inc		%o5			/*  IEU0				*/;	\
+	sub		%o2, %o4, %o2		/*  IEU1				*/;	\
+	fcmpgt32	%fz, %S1, %g3		/*  FPM		Group			*/;	\
+	srl		%o5, 1, %o5		/*  IEU0				*/;	\
+	inc		%g1			/*  IEU1				*/;	\
+	fcmpgt32	%fz, %S3, %g5		/*  FPM		Group			*/;	\
+	srl		%g1, 1, %g1		/*  IEU0				*/;	\
+	sub		%o2, %o5, %o2		/*  IEU1				*/;	\
+	ldx		[%sp + STACKOFF], %o5	/*  Load	Group			*/;	\
+	inc		%g2			/*  IEU0				*/;	\
+	sub		%o2, %g1, %o2		/*  IEU1				*/;	\
+	fcmpgt32	%fz, %T1, %g7		/*  FPM		Group			*/;	\
+	srl		%g2, 1, %g2		/*  IEU0				*/;	\
+	inc		%g3			/*  IEU1				*/;	\
+	fcmpgt32	%T0, %U0, %o3		/*  FPM		Group			*/;	\
+	srl		%g3, 1, %g3		/*  IEU0				*/;	\
+	sub		%o2, %g2, %o2		/*  IEU1				*/;	\
+	inc		%g5			/*  IEU0	Group			*/;	\
+	sub		%o2, %g3, %o2		/*  IEU1				*/;	\
+	fcmpgt32	%fz, %U0, %o4		/*  FPM		Group			*/;	\
+	srl		%g5, 1, %g5		/*  IEU0				*/;	\
+	inc		%g7			/*  IEU1				*/;	\
+	srl		%g7, 1, %g7		/*  IEU0	Group			*/;	\
+	sub		%o2, %g5, %o2		/*  IEU1				*/;	\
+	inc		%o3			/*  IEU0	Group			*/;	\
+	sub		%o2, %g7, %o2		/*  IEU1				*/;	\
+	srl		%o3, 1, %o3		/*  IEU0	Group			*/;	\
+	inc		%o4			/*  IEU1				*/;	\
+	srl		%o4, 1, %o4		/*  IEU0	Group			*/;	\
+	add		%o2, %o3, %o2		/*  IEU1				*/;	\
+	sub		%o2, %o4, %o2		/*  IEU0	Group			*/;	\
+	addcc		%o2, %o5, %o2		/*  IEU1	Group			*/;	\
+	bcs,a,pn	%xcc, 33f		/*  CTI					*/;	\
+	 add		%o2, 1, %o2		/*  IEU0				*/;	\
+33:						/*  That's it				*/;
+
+#define CSUM_LASTCHUNK(offset)									\
+        ldx             [%o0 - offset - 0x10], %g2;						\
+        ldx             [%o0 - offset - 0x08], %g3;						\
+        addcc           %g2, %o2, %o2;								\
+        bcs,a,pn        %xcc, 31f;								\
+         add            %o2, 1, %o2;								\
+31:     addcc           %g3, %o2, %o2;								\
+        bcs,a,pn        %xcc, 32f;								\
+         add            %o2, 1, %o2;								\
+32:
+
+	.text
+	.globl		csum_partial
+	.align		32
+csum_partial:
+	andcc		%o0, 7, %g0		/*  IEU1	Group			*/
+	be,pt		%icc, 4f		/*  CTI					*/
+	 andcc		%o0, 0x38, %g3		/*  IEU1				*/
+	mov		1, %g5			/*  IEU0	Group			*/
+	cmp		%o1, 6			/*  IEU1				*/
+	bl,pn		%icc, 21f		/*  CTI					*/
+	 andcc		%o0, 2, %g0		/*  IEU1	Group			*/
+	be,pt		%icc, 1f		/*  CTI					*/
+	 and		%o0, 4, %g7		/*  IEU0				*/
+	lduh		[%o0], %g2		/*  Load				*/
+	sub		%o1, 2, %o1		/*  IEU0	Group			*/
+	add		%o0, 2, %o0		/*  IEU1				*/
+	andcc		%o0, 4, %g7		/*  IEU1	Group			*/
+	sll		%g5, 16, %g5		/*  IEU0				*/
+	sll		%g2, 16, %g2		/*  IEU0	Group 			*/
+	addcc		%g2, %o2, %o2		/*  IEU1	Group (regdep)		*/
+	bcs,a,pn	%icc, 1f		/*  CTI					*/
+	 add		%o2, %g5, %o2		/*  IEU0				*/
+1:	ld		[%o0], %g2		/*  Load				*/
+	brz,a,pn	%g7, 4f			/*  CTI+IEU1	Group			*/
+	 and		%o0, 0x38, %g3		/*  IEU0				*/
+	add		%o0, 4, %o0		/*  IEU0	Group			*/
+	sub		%o1, 4, %o1		/*  IEU1				*/
+	addcc		%g2, %o2, %o2		/*  IEU1	Group			*/
+	bcs,a,pn	%icc, 1f		/*  CTI					*/
+	 add		%o2, 1, %o2		/*  IEU0				*/
+1:	and		%o0, 0x38, %g3		/*  IEU1	Group			*/
+4:	srl		%o2, 0, %o2		/*  IEU0	Group			*/
+	mov		0x40, %g1		/*  IEU1				*/
+	brz,pn		%g3, 3f			/*  CTI+IEU1	Group			*/
+	 sub		%g1, %g3, %g1		/*  IEU0				*/
+	cmp		%o1, 56			/*  IEU1	Group			*/
+	blu,pn		%icc, 20f		/*  CTI					*/
+	 andcc		%o0, 8, %g0		/*  IEU1	Group			*/
+	be,pn		%icc, 1f		/*  CTI					*/
+	 ldx		[%o0], %g2		/*  Load				*/
+	add		%o0, 8, %o0		/*  IEU0	Group			*/
+	sub		%o1, 8, %o1		/*  IEU1				*/
+	addcc		%g2, %o2, %o2		/*  IEU1	Group			*/
+	bcs,a,pn	%xcc, 1f		/*  CTI					*/
+	 add		%o2, 1, %o2		/*  IEU0				*/
+1:	andcc		%g1, 0x10, %g0		/*  IEU1	Group			*/
+	be,pn		%icc, 2f		/*  CTI					*/
+	 and		%g1, 0x20, %g1		/*  IEU0				*/
+	ldx		[%o0], %g2		/*  Load				*/
+	ldx		[%o0+8], %g3		/*  Load	Group			*/
+	add		%o0, 16, %o0		/*  IEU0				*/
+	sub		%o1, 16, %o1		/*  IEU1				*/
+	addcc		%g2, %o2, %o2		/*  IEU1	Group			*/
+	bcs,a,pn	%xcc, 1f		/*  CTI					*/
+	 add		%o2, 1, %o2		/*  IEU0				*/
+1:	addcc		%g3, %o2, %o2		/*  IEU1	Group			*/
+	bcs,a,pn	%xcc, 2f		/*  CTI					*/
+	 add		%o2, 1, %o2		/*  IEU0				*/
+2:	brz,pn		%g1, 3f			/*  CTI+IEU1	Group			*/
+	 ldx		[%o0], %g2		/*  Load				*/
+	ldx		[%o0+8], %g3		/*  Load	Group			*/
+	ldx		[%o0+16], %g5		/*  Load	Group			*/
+	ldx		[%o0+24], %g7		/*  Load	Group			*/
+	add		%o0, 32, %o0		/*  IEU0				*/
+	sub		%o1, 32, %o1		/*  IEU1				*/
+	addcc		%g2, %o2, %o2		/*  IEU1	Group			*/
+	bcs,a,pn	%xcc, 1f		/*  CTI					*/
+	 add		%o2, 1, %o2		/*  IEU0				*/
+1:	addcc		%g3, %o2, %o2		/*  IEU1	Group			*/
+	bcs,a,pn	%xcc, 1f		/*  CTI					*/
+	 add		%o2, 1, %o2		/*  IEU0				*/
+1:	addcc		%g5, %o2, %o2		/*  IEU1	Group			*/
+	bcs,a,pn	%xcc, 1f		/*  CTI					*/
+	 add		%o2, 1, %o2		/*  IEU0				*/
+1:	addcc		%g7, %o2, %o2		/*  IEU1	Group			*/
+	bcs,a,pn	%xcc, 3f		/*  CTI					*/
+	 add		%o2, 1, %o2		/*  IEU0				*/
+3:	cmp		%o1, 0xc0		/*  IEU1	Group			*/
+	blu,pn		%icc, 20f		/*  CTI					*/
+	 sllx		%o2, 32, %g1		/*  IEU0				*/
+	addcc		%o2, %g1, %o2		/*  IEU1	Group			*/
+	sub		%o1, 0xc0, %o1		/*  IEU0				*/
+	wr		%g0, ASI_BLK_P, %asi	/*  LSU		Group			*/
+#ifdef __KERNEL__
+	wr		%g0, FPRS_FEF, %fprs	/*  LSU		Group			*/
+#endif
+	membar		#StoreLoad		/*  LSU		Group			*/
+	srlx		%o2, 32, %o2		/*  IEU0	Group			*/
+	bcs,a,pn	%xcc, 1f		/*  CTI					*/
+	 add		%o2, 1, %o2		/*  IEU1				*/
+1:	andcc		%o1, 0x80, %g0		/*  IEU1	Group			*/
+	bne,pn		%icc, 7f		/*  CTI					*/
+	 andcc		%o1, 0x40, %g0		/*  IEU1	Group			*/
+	be,pn		%icc, 6f		/*  CTI					*/
+	 fzero		%f12			/*  FPA					*/
+	fzero		%f14			/*  FPA		Group			*/
+	ldda		[%o0 + 0x000] %asi, %f16
+	ldda		[%o0 + 0x040] %asi, %f32
+	ldda		[%o0 + 0x080] %asi, %f48
+	START_THE_TRICK(f12,f16,f18,f20,f22,f24,f26)
+	ba,a,pt		%xcc, 3f
+6:	sub		%o0, 0x40, %o0		/*  IEU0	Group			*/
+	fzero		%f28			/*  FPA					*/
+	fzero		%f30			/*  FPA		Group			*/
+	ldda		[%o0 + 0x040] %asi, %f32
+	ldda		[%o0 + 0x080] %asi, %f48
+	ldda		[%o0 + 0x0c0] %asi, %f0
+	START_THE_TRICK(f28,f32,f34,f36,f38,f40,f42)
+	ba,a,pt		%xcc, 4f
+7:	bne,pt		%icc, 8f		/*  CTI					*/
+	 fzero		%f44			/*  FPA					*/
+	add		%o0, 0x40, %o0		/*  IEU0	Group			*/
+	fzero		%f60			/*  FPA					*/
+	fzero		%f62			/*  FPA		Group			*/
+	ldda		[%o0 - 0x040] %asi, %f0
+	ldda		[%o0 + 0x000] %asi, %f16
+	ldda		[%o0 + 0x040] %asi, %f32
+	START_THE_TRICK(f60,f0,f2,f4,f6,f8,f10)
+	ba,a,pt		%xcc, 2f
+8:	add		%o0, 0x80, %o0		/*  IEU0	Group			*/
+	fzero		%f46			/*  FPA					*/
+	ldda		[%o0 - 0x080] %asi, %f48
+	ldda		[%o0 - 0x040] %asi, %f0
+	ldda		[%o0 + 0x000] %asi, %f16
+	START_THE_TRICK(f44,f48,f50,f52,f54,f56,f58)
+1:	DO_THE_TRICK(f44,f46,f48,f50,f52,f54,f56,f58,f60,f62,f0,f2,f4,f6,f8,f10,f12,f14)
+	ldda		[%o0 + 0x040] %asi, %f32
+2:	DO_THE_TRICK(f60,f62,f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30)
+	ldda		[%o0 + 0x080] %asi, %f48
+3:	DO_THE_TRICK(f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46)
+	ldda		[%o0 + 0x0c0] %asi, %f0
+4:	DO_THE_TRICK(f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,f48,f50,f52,f54,f56,f58,f60,f62)
+	add		%o0, 0x100, %o0		/*  IEU0	Group			*/
+	subcc		%o1, 0x100, %o1		/*  IEU1				*/
+	bgeu,a,pt	%icc, 1b		/*  CTI					*/
+	 ldda		[%o0 + 0x000] %asi, %f16
+	membar		#Sync			/*  LSU		Group			*/
+	DO_THE_TRICK(f44,f46,f48,f50,f52,f54,f56,f58,f60,f62,f0,f2,f4,f6,f8,f10,f12,f14)
+	END_THE_TRICK(f60,f62,f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30)
+	and		%o1, 0x3f, %o1		/*  IEU0	Group			*/
+#ifdef __KERNEL__
+	wr		%g0, 0, %fprs		/*  LSU		Group			*/
+#endif
+20:	andcc		%o1, 0xf0, %g1		/*  IEU1	Group			*/
+	be,pn		%icc, 23f		/*  CTI					*/
+	 and		%o1, 0xf, %o3		/*  IEU0				*/
+22:	rd		%pc, %g7		/*  LSU		Group			*/
+	sll		%g1, 1, %o4		/*  IEU0	Group			*/
+	sub		%g7, %o4, %g7		/*  IEU0	Group (regdep)		*/
+	jmpl		%g7 + (23f - 22b), %g0	/*  CTI		Group brk forced	*/
+	add		%o0, %g1, %o0		/*  IEU0				*/
+	CSUM_LASTCHUNK(0xe0)
+	CSUM_LASTCHUNK(0xd0)
+	CSUM_LASTCHUNK(0xc0)
+	CSUM_LASTCHUNK(0xb0)
+	CSUM_LASTCHUNK(0xa0)
+	CSUM_LASTCHUNK(0x90)
+	CSUM_LASTCHUNK(0x80)
+	CSUM_LASTCHUNK(0x70)
+	CSUM_LASTCHUNK(0x60)
+	CSUM_LASTCHUNK(0x50)
+	CSUM_LASTCHUNK(0x40)
+	CSUM_LASTCHUNK(0x30)
+	CSUM_LASTCHUNK(0x20)
+	CSUM_LASTCHUNK(0x10)
+	CSUM_LASTCHUNK(0x00)
+23:	brnz,pn		%o3, 26f		/*  CTI+IEU1	Group			*/
+24:	 sllx		%o2, 32, %g1		/*  IEU0				*/
+25:	addcc		%o2, %g1, %o0		/*  IEU1	Group			*/
+	srlx		%o0, 32, %o0		/*  IEU0	Group (regdep)		*/
+	bcs,a,pn	%xcc, 1f		/*  CTI					*/
+	 add		%o0, 1, %o0		/*  IEU1				*/
+1:	retl					/*  CTI		Group brk forced	*/
+	 srl		%o0, 0, %o0		/*  IEU0				*/
+26:	andcc		%o1, 8, %g0		/*  IEU1	Group			*/
+	be,pn		%icc, 1f		/*  CTI					*/
+	 ldx		[%o0], %g3		/*  Load				*/
+	add		%o0, 8, %o0		/*  IEU0	Group			*/
+	addcc		%g3, %o2, %o2		/*  IEU1	Group			*/
+	bcs,a,pn	%xcc, 1f		/*  CTI					*/
+	 add		%o2, 1, %o2		/*  IEU0				*/
+1:	andcc		%o1, 4, %g0		/*  IEU1	Group			*/
+	be,a,pn		%icc, 1f		/*  CTI					*/
+	 clr		%g2			/*  IEU0				*/
+	ld		[%o0], %g2		/*  Load				*/
+	add		%o0, 4, %o0		/*  IEU0	Group			*/
+	sllx		%g2, 32, %g2		/*  IEU0	Group			*/
+1:	andcc		%o1, 2, %g0		/*  IEU1				*/
+	be,a,pn		%icc, 1f		/*  CTI					*/
+	 clr		%o4			/*  IEU0	Group			*/
+	lduh		[%o0], %o4		/*  Load				*/
+	add		%o0, 2, %o0		/*  IEU1				*/
+	sll		%o4, 16, %o4		/*  IEU0	Group			*/
+1:	andcc		%o1, 1, %g0		/*  IEU1				*/
+	be,a,pn		%icc, 1f		/*  CTI					*/
+	 clr		%o5			/*  IEU0	Group			*/
+	ldub		[%o0], %o5		/*  Load				*/
+	sll		%o5, 8, %o5		/*  IEU0	Group			*/
+1:	or		%g2, %o4, %o4		/*  IEU1				*/
+	or		%o5, %o4, %o4		/*  IEU0	Group (regdep)		*/
+	addcc		%o4, %o2, %o2		/*  IEU1	Group (regdep)		*/
+	bcs,a,pn	%xcc, 1f		/*  CTI					*/
+	 add		%o2, 1, %o2		/*  IEU0				*/
+1:	ba,pt		%xcc, 25b		/*  CTI		Group			*/
+	 sllx		%o2, 32, %g1		/*  IEU0				*/
+21:	srl		%o2, 0, %o2		/*  IEU0	Group			*/
+	cmp		%o1, 0			/*  IEU1				*/
+	be,pn		%icc, 24b		/*  CTI					*/
+	 andcc		%o1, 4, %g0		/*  IEU1	Group			*/
+	be,a,pn		%icc, 1f		/*  CTI					*/
+	 clr		%g2			/*  IEU0				*/
+	lduh		[%o0], %g3		/*  Load				*/
+	lduh		[%o0+2], %g2		/*  Load	Group			*/
+	add		%o0, 4, %o0		/*  IEU0	Group			*/
+	sllx		%g3, 48, %g3		/*  IEU0	Group			*/
+	sllx		%g2, 32, %g2		/*  IEU0	Group			*/
+	or		%g3, %g2, %g2		/*  IEU0	Group			*/
+1:	andcc		%o1, 2, %g0		/*  IEU1				*/
+	be,a,pn		%icc, 1f		/*  CTI					*/
+	 clr		%o4			/*  IEU0	Group			*/
+	lduh		[%o0], %o4		/*  Load				*/
+	add		%o0, 2, %o0		/*  IEU1				*/
+	sll		%o4, 16, %o4		/*  IEU0	Group			*/
+1:	andcc		%o1, 1, %g0		/*  IEU1				*/
+	be,a,pn		%icc, 1f		/*  CTI					*/
+	 clr		%o5			/*  IEU0	Group			*/
+	ldub		[%o0], %o5		/*  Load				*/
+	sll		%o5, 8, %o5		/*  IEU0	Group			*/
+1:	or		%g2, %o4, %o4		/*  IEU1				*/
+	or		%o5, %o4, %o4		/*  IEU0	Group (regdep)		*/
+	addcc		%o4, %o2, %o2		/*  IEU1	Group (regdep)		*/
+	bcs,a,pn	%xcc, 1f		/*  CTI					*/
+	 add		%o2, 1, %o2		/*  IEU0				*/
+1:	ba,pt		%xcc, 25b		/*  CTI		Group			*/
+	 sllx		%o2, 32, %g1		/*  IEU0				*/
diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/lib/checksum.S linux/arch/sparc64/lib/checksum.S
--- v2.1.44/linux/arch/sparc64/lib/checksum.S	Mon Jul  7 08:18:55 1997
+++ linux/arch/sparc64/lib/checksum.S	Wed Jul 16 20:37:21 1997
@@ -25,223 +25,12 @@
 	 * into the accumulated sum.  The following is much better.
 	 *
 	 * This should run at max bandwidth for ecache hits, a better
-	 * technique is to use VIS and fpu operations somehow, but
-	 * this requires more reasoning on my part...
-	 *
-	 * Assuming ecache hits and branches predicted well, this
-	 * can be expected to run at a rate of 16 cycles per 64-bytes
-	 * of data summed.  (the old code summed 32 bytes in 20
-	 * cycles, with numerous bubbles and unnecessary stalls)
+	 * technique is to use VIS and fpu operations. This is already
+	 * done for csum_partial, needs to be written for the copy stuff
+	 * still.
 	 */
-#define CSUM_ECACHE_LOAD(buf, offset, t0, t1, t2, t3, t4, t5, t6, t7)			\
-	ldx	[buf + offset + 0x00], t0;						\
-	ldx	[buf + offset + 0x08], t1;						\
-	ldx	[buf + offset + 0x10], t2;						\
-	ldx	[buf + offset + 0x18], t3;						\
-	ldx	[buf + offset + 0x20], t4;						\
-	ldx	[buf + offset + 0x28], t5;						\
-	ldx	[buf + offset + 0x30], t6;						\
-	ldx	[buf + offset + 0x38], t7;						\
-	nop; nop;	/* THIS IS CRITICAL!!!!!!!!! */
-
-#define CSUM_ECACHE_BLOCK_LDNEXT(buf, offset, sum, t0, t1, t2, t3, t4, t5, t6, t7)	\
-	addcc		sum, t0, sum;							\
-	bcc,pt		%xcc, 11f;							\
-	 ldx		[buf + offset + 0x00], t0;					\
-	add		sum, 1, sum;							\
-11:	addcc		sum, t1, sum;							\
-	bcc,pt		%xcc, 12f;							\
-	 ldx		[buf + offset + 0x08], t1;					\
-	add		sum, 1, sum;							\
-12:	addcc		sum, t2, sum;							\
-	bcc,pt		%xcc, 13f;							\
-	 ldx		[buf + offset + 0x10], t2;					\
-	add		sum, 1, sum;							\
-13:	addcc		sum, t3, sum;							\
-	bcc,pt		%xcc, 14f;							\
-	 ldx		[buf + offset + 0x18], t3;					\
-	add		sum, 1, sum;							\
-14:	addcc		sum, t4, sum;							\
-	bcc,pt		%xcc, 15f;							\
-	 ldx		[buf + offset + 0x20], t4;					\
-	add		sum, 1, sum;							\
-15:	addcc		sum, t5, sum;							\
-	bcc,pt		%xcc, 16f;							\
-	 ldx		[buf + offset + 0x28], t5;					\
-	add		sum, 1, sum;							\
-16:	addcc		sum, t6, sum;							\
-	bcc,pt		%xcc, 17f;							\
-	 ldx		[buf + offset + 0x30], t6;					\
-	add		sum, 1, sum;							\
-17:	addcc		sum, t7, sum;							\
-	bcc,pt		%xcc, 18f;							\
-	 ldx		[buf + offset + 0x38], t7;					\
-	add		sum, 1, sum;							\
-18:	nop; nop;	/* DO NOT TOUCH! */
-
-#define CSUM_ECACHE_BLOCK(sum, t0, t1, t2, t3, t4, t5, t6, t7)				\
-	addcc		sum, t0, sum;							\
-	bcs,a,pn	%xcc, 21f;							\
-	 add		sum, 1, sum;							\
-21:	addcc		sum, t1, sum;							\
-	bcs,a,pn	%xcc, 22f;							\
-	 add		sum, 1, sum;							\
-22:	addcc		sum, t2, sum;							\
-	bcs,a,pn	%xcc, 23f;							\
-	 add		sum, 1, sum;							\
-23:	addcc		sum, t3, sum;							\
-	bcs,a,pn	%xcc, 24f;							\
-	 add		sum, 1, sum;							\
-24:	addcc		sum, t4, sum;							\
-	bcs,a,pn	%xcc, 25f;							\
-	 add		sum, 1, sum;							\
-25:	addcc		sum, t5, sum;							\
-	bcs,a,pn	%xcc, 26f;							\
-	 add		sum, 1, sum;							\
-26:	addcc		sum, t6, sum;							\
-	bcs,a,pn	%xcc, 27f;							\
-	 add		sum, 1, sum;							\
-27:	addcc		sum, t7, sum;							\
-	bcs,a,pn	%xcc, 28f;							\
-	 add		sum, 1, sum;							\
-28:
-
-#define CSUM_LASTCHUNK(buf, offset, sum, t0, t1)					\
-	ldx		[buf - offset - 0x08], t0;					\
-	ldx		[buf - offset - 0x00], t1;					\
-	addcc		t0, sum, sum;							\
-	bcs,a,pn	%xcc, 31f;							\
-	 add		sum, 1, sum;							\
-31:	addcc		t1, sum, sum;							\
-	bcs,a,pn	%xcc, 32f;							\
-	 add		sum, 1, sum;							\
-32:
 
 	.text
-	/* Keep this garbage from swiping the icache. */
-csum_partial_end_cruft:
-	andcc		%o1, 8, %g0			! IEU1	Group
-	be,pn		%icc, 1f			! CTI
-	 and		%o1, 4, %g5			! IEU0
-	ldx		[%o0 + 0x00], %g2		! Load	Group
-	add		%o0, 0x8, %o0			! IEU0
-	addcc		%g2, %o2, %o2			! IEU1	Group + 2 bubbles
-	bcs,a,pn	%xcc, 1f			! CTI
-	 add		%o2, 1, %o2			! IEU0	4 clocks (mispredict)
-1:	andcc		%o1, 2, %g0			! IEU1	Group
-	brz,pn		%g5, 1f				! CTI	Group (needs IEU1)
-	 clr		%g2				! IEU0
-	ld		[%o0], %g2			! Load
-	add		%o0, 4, %o0			! IEU0	Group
-	sllx		%g2, 32, %g2			! IEU0	Group + 2 bubbles
-1:	and		%o1, 1, %o1			! IEU1
-	be,pn		%icc, 1f			! CTI
-	 clr		%o4				! IEU0	Group
-	lduh		[%o0], %o4			! Load
-	add		%o0, 2, %o0			! IEU1
-	sll		%o4, 16, %o4			! IEU0	Group + 2 bubbles
-1:	brz,pn		%o1, 1f				! CTI
-	 clr		%o5				! IEU1
-	ldub		[%o0], %o5			! Load	Group
-	sll		%o5, 8, %o5			! IEU0	Group + 2 bubbles
-1:	or		%g2, %o4, %o4			! IEU1
-	or		%o5, %o4, %o4			! IEU0	Group
-	addcc		%o4, %o2, %o2			! IEU1	Group (regdep)
-	bcc,pt		%xcc, cfold			! CTI
-	 sethi		%uhi(PAGE_OFFSET), %g4		! IEU0
-1:	b,pt		%xcc, cfold			! CTI	Group
-	 add		%o2, 1, %o2			! IEU0
-
-csum_partial_fixit:
-	bl,pn		%icc, cpte			! CTI	Group
-	 and		%o1, 0xf, %o3			! IEU0
-	andcc		%o0, 0x2, %g0			! IEU1
-	be,pn		%icc, 1f			! CTI	Group
-	 and		%o0, 0x4, %g7			! IEU0
-	lduh		[%o0 + 0x00], %g2		! Load
-	sub		%o1, 2, %o1			! IEU0	Group
-	addcc		%o0, 2, %o0			! IEU1
-	and		%o0, 0x4, %g7			! IEU0	Group
-	sll		%g2, 16, %g2			! IEU0	Group (no load stall)
-	addcc		%g2, %o2, %o2			! IEU1	Group (regdep)
-	bcc,pt		%icc, 0f			! CTI
-	 andn		%o1, 0xff, %o3			! IEU0
-	srl		%o2, 16, %g2			! IEU0	Group
-	b,pt		%xcc, 9f			! CTI
-	 add		%g2, 1, %g2			! IEU1
-0:	srl		%o2, 16, %g2			! IEU0	Group 8-(
-9:	sll		%o2, 16, %o2			! IEU0	Group 8-(
-	sll		%g2, 16, %g3			! IEU0	Group 8-(
-	srl		%o2, 16, %o2			! IEU0	Group 8-(
-	or		%g3, %o2, %o2			! IEU1
-1:	brnz,pt		%g7, 2f				! CTI	Group
-	 sub		%o1, 4, %o1			! IEU0
-	b,pt		%xcc, csum_partial_aligned	! CTI	Group
-	 add		%o1, 4, %o1			! IEU0
-2:	ld		[%o0 + 0x00], %g2		! Load	Group
-	add		%o0, 4, %o0			! IEU0
-	andn		%o1, 0xff, %o3			! IEU1
-	addcc		%g2, %o2, %o2			! IEU1	Group + 2 bubbles
-	bcc,pt		%xcc, csum_partial_aligned	! CTI
-	 nop						! IEU0
-	b,pt		%xcc, csum_partial_aligned	! CTI	Group
-	 add		%o2, 1, %o2			! IEU0
-
-	.align		32
-	.globl		csum_partial
-csum_partial:						/* %o0=buf, %o1=len, %o2=sum */
-	andcc		%o0, 0x7, %g0			! IEU1	Group
-	srl		%o1, 0, %o1			! IEU0
-	srl		%o2, 0, %o2			! IEU0	Group
-	be,pt		%icc, csum_partial_aligned	! CTI
-	 andn		%o1, 0xff, %o3			! IEU1
-	b,pt		%xcc, csum_partial_fixit	! CTI	Group
-	 cmp		%o1, 6				! IEU0
-	nop
-csum_partial_aligned:
-	brz,pt		%o3, 3f				! CTI	Group
-	 and		%o1, 0xf0, %g1			! IEU0
-5:	CSUM_ECACHE_LOAD(        %o0, 0x000,      %o4, %o5, %g2, %g3, %g4, %g5, %g1, %g7)
-	CSUM_ECACHE_BLOCK_LDNEXT(%o0, 0x040, %o2, %o4, %o5, %g2, %g3, %g4, %g5, %g1, %g7)
-	CSUM_ECACHE_BLOCK_LDNEXT(%o0, 0x080, %o2, %o4, %o5, %g2, %g3, %g4, %g5, %g1, %g7)
-	CSUM_ECACHE_BLOCK_LDNEXT(%o0, 0x0c0, %o2, %o4, %o5, %g2, %g3, %g4, %g5, %g1, %g7)
-	CSUM_ECACHE_BLOCK(                   %o2, %o4, %o5, %g2, %g3, %g4, %g5, %g1, %g7)
-	subcc		%o3, 256, %o3			! IEU1	Group
-	bne,pt		%icc, 5b			! CTI
-	 add		%o0, 256, %o0			! IEU0
-	and		%o1, 0xf0, %g1			! IEU0	Group
-3:	brz,pn		%g1, cpte			! CTI
-	 and		%o1, 0xf, %o3			! IEU1	Group
-10:	rd		%pc, %g7			! LSU	Group + 4 clocks
-	sll		%g1, 1, %o4			! IEU0	Group
-	sub		%g7, %o4, %g7			! IEU1
-	jmp		%g7 + %lo(cpte - 10b)		! CTI	Group brk forced
-	 add		%o0, %g1, %o0			! IEU0
-cptbl:	CSUM_LASTCHUNK(%o0, 0xe8, %o2, %g2, %g3)
-	CSUM_LASTCHUNK(%o0, 0xd8, %o2, %g2, %g3)
-	CSUM_LASTCHUNK(%o0, 0xc8, %o2, %g2, %g3)
-	CSUM_LASTCHUNK(%o0, 0xb8, %o2, %g2, %g3)
-	CSUM_LASTCHUNK(%o0, 0xa8, %o2, %g2, %g3)
-	CSUM_LASTCHUNK(%o0, 0x98, %o2, %g2, %g3)
-	CSUM_LASTCHUNK(%o0, 0x88, %o2, %g2, %g3)
-	CSUM_LASTCHUNK(%o0, 0x78, %o2, %g2, %g3)
-	CSUM_LASTCHUNK(%o0, 0x68, %o2, %g2, %g3)
-	CSUM_LASTCHUNK(%o0, 0x58, %o2, %g2, %g3)
-	CSUM_LASTCHUNK(%o0, 0x48, %o2, %g2, %g3)
-	CSUM_LASTCHUNK(%o0, 0x38, %o2, %g2, %g3)
-	CSUM_LASTCHUNK(%o0, 0x28, %o2, %g2, %g3)
-	CSUM_LASTCHUNK(%o0, 0x18, %o2, %g2, %g3)
-	CSUM_LASTCHUNK(%o0, 0x08, %o2, %g2, %g3)
-cpte:	brnz,pn		%o3, csum_partial_end_cruft	! CTI	Group
-	 sethi		%uhi(PAGE_OFFSET), %g4		! IEU0
-cfold:	sllx		%o2, 32, %o0			! IEU0	Group
-	addcc		%o2, %o0, %o0			! IEU1	Group (regdep)
-	srlx		%o0, 32, %o0			! IEU0	Group (regdep)
-	bcs,a,pn	%xcc, 1f			! CTI
-	 add		%o0, 1, %o0			! IEU1	4 clocks (mispredict)
-1:	retl						! CTI	Group brk forced
-	 sllx		%g4, 32, %g4			! IEU0	Group
-
 	.globl __csum_partial_copy_start, __csum_partial_copy_end
 __csum_partial_copy_start:
 
diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/lib/strlen_user.S linux/arch/sparc64/lib/strlen_user.S
--- v2.1.44/linux/arch/sparc64/lib/strlen_user.S	Mon Jun 16 16:35:54 1997
+++ linux/arch/sparc64/lib/strlen_user.S	Wed Jul 16 19:22:50 1997
@@ -20,36 +20,27 @@
 	andcc	%o0, 3, %g0
 	be,pt	%icc, 9f
 	 sethi	%hi(HI_MAGIC), %o4
-10:
-	lduba	[%o0] ASI_S, %o5
+10:	lduba	[%o0] ASI_S, %o5
 	brz,pn	%o5, 21f
 	 add	%o0, 1, %o0
 	andcc	%o0, 3, %g0
 	be,pn	%icc, 4f
 	 or	%o4, %lo(HI_MAGIC), %o3
-11:
-	lduba	[%o0] ASI_S, %o5
+11:	lduba	[%o0] ASI_S, %o5
 	brz,pn	%o5, 22f
 	 add	%o0, 1, %o0
 	andcc	%o0, 3, %g0
-	be,pt	%icc, 5f
-	 sethi	%hi(LO_MAGIC), %o4
-12:
-	lduba	[%o0] ASI_S, %o5
+	be,pt	%icc, 13f
+	 srl	%o3, 7, %o2
+12:	lduba	[%o0] ASI_S, %o5
 	brz,pn	%o5, 23f
 	 add	%o0, 1, %o0
-	ba,pt	%icc, 13f
-	 or	%o4, %lo(LO_MAGIC), %o2
-9:
-	or	%o4, %lo(HI_MAGIC), %o3
-4:
-	sethi	%hi(LO_MAGIC), %o4
-5:
-	or	%o4, %lo(LO_MAGIC), %o2
-13:
-	lda	[%o0] ASI_S, %o5
-2:
-	sub	%o5, %o2, %o4
+	ba,pt	%icc, 2f
+15:	 lda	[%o0] ASI_S, %o5
+9:	or	%o4, %lo(HI_MAGIC), %o3
+4:	srl	%o3, 7, %o2
+13:	lda	[%o0] ASI_S, %o5
+2:	sub	%o5, %o2, %o4
 	andcc	%o4, %o3, %g0
 	be,pt	%icc, 13b
 	 add	%o0, 4, %o0
@@ -69,20 +60,15 @@
 	 add	%o4, 1, %o4
 	andcc	%o5, 0xff, %g0
 	bne,a,pt %icc, 2b
-14:
-	 lda	[%o0] ASI_S, %o5
+14:	 lda	[%o0] ASI_S, %o5
 	add	%o4, 1, %o4
-1:
-	retl
+1:	retl
 	 sub	%o4, %o1, %o0
-21:
-	retl
+21:	retl
 	 mov	1, %o0
-22:
-	retl
+22:	retl
 	 mov	2, %o0
-23:
-	retl
+23:	retl
 	 mov	3, %o0
 
         .section .fixup,#alloc,#execinstr
@@ -97,5 +83,6 @@
 	.xword	10b, 30b
 	.xword	11b, 30b
 	.xword	12b, 30b
+	.xword	15b, 30b
 	.xword	13b, 30b
 	.xword	14b, 30b
diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/mm/fault.c linux/arch/sparc64/mm/fault.c
--- v2.1.44/linux/arch/sparc64/mm/fault.c	Mon Jul  7 08:18:55 1997
+++ linux/arch/sparc64/mm/fault.c	Wed Jul 16 20:37:21 1997
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.17 1997/07/04 01:41:10 davem Exp $
+/* $Id: fault.c,v 1.18 1997/07/17 02:20:56 davem Exp $
  * arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -228,7 +228,7 @@
 	pte_t *ptep;
 	int alias_found = 0;
 
-	inode = vma->vm_inode;
+	inode = vma->vm_dentry->d_inode;
 	if(!inode)
 		return;
 
diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/mm/ultra.S linux/arch/sparc64/mm/ultra.S
--- v2.1.44/linux/arch/sparc64/mm/ultra.S	Mon Jul  7 08:18:55 1997
+++ linux/arch/sparc64/mm/ultra.S	Wed Jul 16 19:22:50 1997
@@ -1,4 +1,4 @@
-/* $Id: ultra.S,v 1.6 1997/06/30 10:31:43 jj Exp $
+/* $Id: ultra.S,v 1.8 1997/07/15 05:35:50 davem Exp $
  * ultra.S: Don't expand these all over the place...
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -97,5 +97,130 @@
 	retl
 	 flush		%g6
 
+#ifdef __SMP__
+	/* These are all called by the slaves of a cross call, at
+	 * trap level 1, with interrupts fully disabled.
+	 *
+	 * Register usage:
+	 *   %g5	mm->context	(all tlb flushes)
+	 *   %g6	address arg 1	(tlb page and range flushes)
+	 *   %g7	address arg 2	(tlb range flush only)
+	 *
+	 *   %g1	ivector table, don't touch
+	 *   %g2	scratch 1
+	 *   %g3	scratch 2
+	 *   %g4	scratch 3
+	 *
+	 * NOTE: We do not acknowledge the UPA until we are done
+	 *       with the service.  This is what tells the master
+	 *       that he can consider the effects of the flush
+	 *       "complete" on this cpu.
+	 */
+	.align		32
+	.globl		xcall_flush_tlb_page
+xcall_flush_tlb_page:
+	mov		SECONDARY_CONTEXT, %g2
+	nop
+	ldxa		[%g2] ASI_DMMU, %g3
+	cmp		%g3, %g5
+	be,pt		%icc, 1f
+	 or		%g6, 0x10, %g4
+	stxa		%g5, [%g2] ASI_DMMU
+1:	stxa		%g0, [%g4] ASI_DMMU_DEMAP
+
+	be,pt		%icc, 1f
+	 stxa		%g0, [%g4] ASI_IMMU_DEMAP
+	stxa		%g3, [%g2] ASI_DMMU
+1:	b,pt		%xcc, do_ivec_return
+	 flush		%g1
+
+	.align		32
+	.globl		xcall_flush_tlb_mm
+xcall_flush_tlb_mm:
+	mov		SECONDARY_CONTEXT, %g2
+	nop
+	ldxa		[%g2] ASI_DMMU, %g3
+	cmp		%g3, %g5
+	be,pt		%icc, 1f
+	 mov		0x50, %g4
+	stxa		%g5, [%g2] ASI_DMMU
+1:	stxa		%g0, [%g4] ASI_DMMU_DEMAP
 
-	
+	be,pt		%icc, 1f
+	 stxa		%g0, [%g4] ASI_IMMU_DEMAP
+	stxa		%g3, [%g2] ASI_DMMU
+1:	b,pt		%xcc, do_ivec_return
+	 flush		%g1
+
+	.align		32
+	.globl		xcall_flush_tlb_range
+xcall_flush_tlb_range:
+	sethi		%hi(8192 - 1), %g2
+	or		%g2, %lo(8192 - 1), %g2
+	andn		%g6, %g2, %g6
+	andn		%g7, %g2, %g7
+	sub		%g7, %g6, %g3
+	add		%g2, 1, %g2
+	orcc		%g6, 0x50, %g6
+	srlx		%g3, 13, %g4
+
+	cmp		%g4, 96
+	bgu,pn		%icc, xcall_flush_tlb_mm
+	 mov		SECONDARY_CONTEXT, %g4
+	ldxa		[%g4] ASI_DMMU, %g7
+	cmp		%g7, %g5
+	be,pt		%icc, 1f
+	 sub		%g3, %g2, %g3
+	stxa		%g5, [%g4] ASI_DMMU
+
+1:	stxa		%g0, [%g6 + %g3] ASI_DMMU_DEMAP
+	stxa		%g0, [%g6 + %g3] ASI_IMMU_DEMAP
+	brnz,pt		%g3, 1b
+	 sub		%g3, %g2, %g3
+	bne,a,pn	%icc, 1f
+	 stxa		%g7, [%g4] ASI_DMMU
+1:	b,pt		%xcc, do_ivec_return
+	 flush		%g1	
+
+	/* These two are not performance critical... */
+	.globl		xcall_flush_tlb_all
+xcall_flush_tlb_all:
+	clr		%g2
+	clr		%g3
+1:	ldxa		[%g3] ASI_DTLB_DATA_ACCESS, %g4
+	and		%g4, _PAGE_L, %g5
+	brnz,pn		%g5, 2f
+	 mov		TLB_TAG_ACCESS, %g7
+	stxa		%g0, [%g7] ASI_DMMU
+	membar		#Sync
+
+	stxa		%g0, [%g3] ASI_DTLB_DATA_ACCESS
+	membar		#Sync
+2:	ldxa		[%g3] ASI_ITLB_DATA_ACCESS, %g4
+	and		%g4, _PAGE_L, %g5
+	brnz,pn		%g5, 2f
+	 mov		TLB_TAG_ACCESS, %g7
+	stxa		%g0, [%g7] ASI_IMMU
+	membar		#Sync
+
+	stxa		%g0, [%g3] ASI_ITLB_DATA_ACCESS
+2:	add		%g2, 1, %g2
+	cmp		%g2, 63
+	ble,pt		%icc, 1b
+	 sll		%g2, 3, %g3
+	b,pt		%xcc, do_ivec_return
+	 flush		%g1
+
+	.globl		xcall_flush_cache_all
+xcall_flush_cache_all:
+	sethi		%hi(16383), %g2
+	or		%g2, %lo(16383), %g2
+	clr		%g3
+1:	stxa		%g0, [%g3] ASI_IC_TAG
+	add		%g3, 32, %g3
+	cmp		%g3, %g2
+	bleu,pt		%xcc, 1b
+	 nop
+	b,pt		%xcc, do_ivec_return
+	 flush		%g1
+#endif /* __SMP__ */
diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/prom/misc.c linux/arch/sparc64/prom/misc.c
--- v2.1.44/linux/arch/sparc64/prom/misc.c	Mon Jul  7 08:18:55 1997
+++ linux/arch/sparc64/prom/misc.c	Wed Jul 16 19:22:50 1997
@@ -1,4 +1,4 @@
-/* $Id: misc.c,v 1.7 1997/07/05 09:52:51 davem Exp $
+/* $Id: misc.c,v 1.8 1997/07/14 23:45:28 davem Exp $
  * misc.c:  Miscellaneous prom functions that don't belong
  *          anywhere else.
  *
@@ -133,3 +133,10 @@
 {
 	p1275_cmd("SUNW,set-trap-table", P1275_INOUT(1, 0), tba);
 }
+
+#ifdef __SMP__
+void prom_start_cpu(int cpunode, unsigned long pc, unsigned long o0)
+{
+	p1275_cmd("SUNW,start-cpu", P1275_INOUT(3, 0), cpunode, pc, o0);
+}
+#endif
diff -u --recursive --new-file v2.1.44/linux/drivers/block/loop.c linux/drivers/block/loop.c
--- v2.1.44/linux/drivers/block/loop.c	Mon Jun 16 16:35:54 1997
+++ linux/drivers/block/loop.c	Wed Jul 16 20:37:21 1997
@@ -292,7 +292,7 @@
 		return -EBADF;
 	if (lo->lo_inode)
 		return -EBUSY;
-	inode = file->f_inode;
+	inode = file->f_dentry->d_inode;
 	if (!inode) {
 		printk("loop_set_fd: NULL inode?!?\n");
 		return -EINVAL;
@@ -318,7 +318,7 @@
 	}
 
 	lo->lo_inode = inode;
-	atomic_inc(&lo->lo_inode->i_count);
+	lo->lo_inode->i_count++;
 	lo->transfer = NULL;
 	figure_loop_size(lo);
 	MOD_INC_USE_COUNT;
diff -u --recursive --new-file v2.1.44/linux/drivers/block/md.c linux/drivers/block/md.c
--- v2.1.44/linux/drivers/block/md.c	Mon Jun 16 16:35:54 1997
+++ linux/drivers/block/md.c	Wed Jul 16 19:22:50 1997
@@ -202,10 +202,10 @@
 {
   int i;
   
-  if (atomic_read(&inode->i_count)>1 || md_dev[minor].busy>1) /* ioctl : one open channel */
+  if (inode->i_count > 1 || md_dev[minor].busy>1) /* ioctl : one open channel */
   {
     printk ("STOP_MD md%x failed : i_count=%d, busy=%d\n", minor,
-	    atomic_read(&inode->i_count), md_dev[minor].busy);
+	    inode->i_count, md_dev[minor].busy);
     return -EBUSY;
   }
   
diff -u --recursive --new-file v2.1.44/linux/drivers/block/rd.c linux/drivers/block/rd.c
--- v2.1.44/linux/drivers/block/rd.c	Tue May 13 22:41:05 1997
+++ linux/drivers/block/rd.c	Mon Jul 14 11:33:24 1997
@@ -360,10 +360,10 @@
 	 * Read block 0 to test for gzipped kernel
 	 */
 	if (fp->f_op->llseek)
-		fp->f_op->llseek(fp->f_inode, fp, start_block * BLOCK_SIZE, 0);
+		fp->f_op->llseek(fp->f_dentry->d_inode, fp, start_block * BLOCK_SIZE, 0);
 	fp->f_pos = start_block * BLOCK_SIZE;
 	
-	fp->f_op->read(fp->f_inode, fp, buf, size);
+	fp->f_op->read(fp->f_dentry->d_inode, fp, buf, size);
 
 	/*
 	 * If it matches the gzip magic numbers, return -1
@@ -390,11 +390,11 @@
 	 * Read block 1 to test for minix and ext2 superblock
 	 */
 	if (fp->f_op->llseek)
-		fp->f_op->llseek(fp->f_inode, fp,
+		fp->f_op->llseek(fp->f_dentry->d_inode, fp,
 				(start_block+1) * BLOCK_SIZE, 0);
 	fp->f_pos = (start_block+1) * BLOCK_SIZE;
 
-	fp->f_op->read(fp->f_inode, fp, buf, size);
+	fp->f_op->read(fp->f_dentry->d_inode, fp, buf, size);
 		
 	/* Try minix */
 	if (minixsb->s_magic == MINIX_SUPER_MAGIC ||
@@ -421,7 +421,7 @@
 	
 done:
 	if (fp->f_op->llseek)
-		fp->f_op->llseek(fp->f_inode, fp, start_block * BLOCK_SIZE, 0);
+		fp->f_op->llseek(fp->f_dentry->d_inode, fp, start_block * BLOCK_SIZE, 0);
 	fp->f_pos = start_block * BLOCK_SIZE;	
 
 	if ((nblocks > 0) && blk_size[MAJOR(device)]) {
@@ -444,8 +444,9 @@
  */
 __initfunc(static void rd_load_image(kdev_t device,int offset))
 {
-	struct inode inode, out_inode;
+ 	struct inode inode, out_inode;
 	struct file infile, outfile;
+	struct dentry in_dentry, out_dentry;
 	unsigned short fs;
 	kdev_t ram_device;
 	int nblocks, i;
@@ -457,15 +458,19 @@
 
 	memset(&infile, 0, sizeof(infile));
 	memset(&inode, 0, sizeof(inode));
+	memset(&in_dentry, 0, sizeof(in_dentry));
 	inode.i_rdev = device;
 	infile.f_mode = 1; /* read only */
-	infile.f_inode = &inode;
+	infile.f_dentry = &in_dentry;
+	in_dentry.d_inode = &inode;
 
 	memset(&outfile, 0, sizeof(outfile));
 	memset(&out_inode, 0, sizeof(out_inode));
+	memset(&out_dentry, 0, sizeof(out_dentry));
 	out_inode.i_rdev = ram_device;
 	outfile.f_mode = 3; /* read/write */
-	outfile.f_inode = &out_inode;
+	outfile.f_dentry = &out_dentry;
+	out_dentry.d_inode = &out_inode;
 
 	if (blkdev_open(&inode, &infile) != 0) return;
 	if (blkdev_open(&out_inode, &outfile) != 0) return;
@@ -506,9 +511,9 @@
 
 	printk(KERN_NOTICE "RAMDISK: Loading %d blocks into ram disk... ", nblocks);
 	for (i=0; i < nblocks; i++) {
-		infile.f_op->read(infile.f_inode, &infile, buf,
+		infile.f_op->read(infile.f_dentry->d_inode, &infile, buf,
 				  BLOCK_SIZE);
-		outfile.f_op->write(outfile.f_inode, &outfile, buf,
+		outfile.f_op->write(outfile.f_dentry->d_inode, &outfile, buf,
 				    BLOCK_SIZE);
 		if (!(i % 16)) {
 			printk("%c\b", rotator[rotate & 0x3]);
@@ -637,7 +642,7 @@
 {
 	if (exit_code) return -1;
 	
-	insize = crd_infp->f_op->read(crd_infp->f_inode, crd_infp,
+	insize = crd_infp->f_op->read(crd_infp->f_dentry->d_inode, crd_infp,
 				      inbuf, INBUFSIZ);
 	if (insize == 0) return -1;
 
@@ -656,7 +661,7 @@
     unsigned n;
     uch *in, ch;
     
-    crd_outfp->f_op->write(crd_outfp->f_inode, crd_outfp, window,
+    crd_outfp->f_op->write(crd_outfp->f_dentry->d_inode, crd_outfp, window,
 			   outcnt);
     in = window;
     for (n = 0; n < outcnt; n++) {
diff -u --recursive --new-file v2.1.44/linux/drivers/char/Config.in linux/drivers/char/Config.in
--- v2.1.44/linux/drivers/char/Config.in	Tue May 13 22:41:06 1997
+++ linux/drivers/char/Config.in	Wed Jul 16 19:22:50 1997
@@ -52,6 +52,7 @@
 	if [ "$CONFIG_PSMOUSE" != "n" ]; then
 	  bool 'C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE
 	fi
+	tristate 'PC110 digitizer pad support' CONFIG_PC110_PAD
 fi
 
 if [ "$CONFIG_MODULES" = "y" ]; then
@@ -97,4 +98,5 @@
   tristate '   Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG
 fi
 bool 'Enhanced Real Time Clock Support' CONFIG_RTC
+tristate 'PC joystick support' CONFIG_JOYSTICK
 endmenu
diff -u --recursive --new-file v2.1.44/linux/drivers/char/Makefile linux/drivers/char/Makefile
--- v2.1.44/linux/drivers/char/Makefile	Mon Jun 16 16:35:54 1997
+++ linux/drivers/char/Makefile	Wed Jul 16 19:22:50 1997
@@ -143,6 +143,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_JOYSTICK),y)
+L_OBJS += joystick.o
+else
+  ifeq ($(CONFIG_JOYSTICK),m)
+  M_OBJS += joystick.o
+  endif
+endif
+
 ifeq ($(CONFIG_MS_BUSMOUSE),y)
 M = y
 L_OBJS += msbusmouse.o
@@ -210,6 +218,16 @@
 
 ifdef CONFIG_SUN_MOUSE
 M = y
+endif
+
+ifeq ($(CONFIG_PC110_PAD),y)
+M = y
+L_OBJS += pc110pad.o
+else
+  ifeq ($(CONFIG_PC110_PAD),m)
+    M_OBJS += pc110pad.o
+    MM = m
+  endif
 endif
 
 ifeq ($(CONFIG_SUN_OPENPROMIO),y)
diff -u --recursive --new-file v2.1.44/linux/drivers/char/cyclades.c linux/drivers/char/cyclades.c
--- v2.1.44/linux/drivers/char/cyclades.c	Tue May 13 22:41:06 1997
+++ linux/drivers/char/cyclades.c	Thu Jul 10 11:22:04 1997
@@ -1,6 +1,6 @@
 #define BLOCKMOVE
 static char rcsid[] =
-"$Revision: 1.36.4.27 $$Date: 1997/03/26 10:30:00 $";
+"$Revision: 1.36.4.33 $$Date: 1997/06/27 19:00:00 $";
 
 /*
  *  linux/drivers/char/cyclades.c
@@ -29,6 +29,50 @@
  *   void cleanup_module(void);
  *
  * $Log: cyclades.c,v $
+ * Revision 1.36.4.33  1997/06/27 19:00:00  ivan
+ * Fixes related to kernel version conditional 
+ * compilation.
+ *  
+ * Revision 1.36.4.32  1997/06/14 19:30:00  ivan
+ * Compatibility issues between kernels 2.0.x and 
+ * 2.1.x (mainly related to clear_bit function).
+ *  
+ * Revision 1.36.4.31  1997/06/03 15:30:00  ivan
+ * Changes to define the memory window according to the 
+ * board type.
+ *  
+ * Revision 1.36.4.30  1997/05/16 15:30:00  daniel
+ * Changes to suport new cycladesZ boards.
+ *
+ * Revision 1.36.4.29  1997/05/12 11:30:00  daniel
+ * Merge of Bentson's and Daniel's version 1.36.4.28.
+ * Corrects bug in cy_detect_pci: check if there are more
+ * ports than the number of static structs allocated.
+ * Warning message during initialization if this driver is
+ * used with the new generation of cycladesZ boards.  Those
+ * will be supported only in next release of the driver.
+ * Corrects bug in cy_detect_pci and cy_detect_isa that
+ * returned wrong number of VALID boards, when a cyclomY
+ * was found with no serial modules connected.
+ * Changes to use current (2.1.x) kernel subroutine names
+ * and created macros for compilation with 2.0.x kernel,
+ * instead of the other way around.
+ *
+ * Revision 1.36.4.28  1997/05/?? ??:00:00  bentson
+ * Change queue_task_irq_off to queue_task_irq.
+ * The inline function queue_task_irq_off (tqueue.h)
+ * was removed from latest releases of 2.1.x kernel.
+ * Use of macro __initfunc to mark the initialization
+ * routines, so memory can be reused.
+ * Also incorporate implementation of critical region
+ * in function cleanup_module() created by anonymous
+ * linuxer.
+ *
+ * Revision 1.36.4.28  1997/04/25 16:00:00  daniel
+ * Change to support new firmware that solves DCD problem:
+ * application could fail to receive SIGHUP signal when DCD
+ * varying too fast.
+ *
  * Revision 1.36.4.27  1997/03/26 10:30:00  daniel
  * Changed for suport linux versions 2.1.X.
  * Backward compatible with linux versions 2.0.X.
@@ -98,7 +142,7 @@
  * after -Y stuff (to make changes clearer)
  *
  * Revision 1.36.4.12  1996/07/11 15:40:55  bentson
- * Add code to poll Cyclom-Z.  Add code to get & set RS-232 control.
+ * Add code to poll Cyclades-Z.  Add code to get & set RS-232 control.
  * Add code to send break.  Clear firmware ID word at startup (so
  * that other code won't talk to inactive board).
  *
@@ -391,7 +435,13 @@
    constant in the definition below. No other change is necessary to
    support more boards/ports. */
 
-#define NR_PORTS        64
+//#define NR_PORTS        64
+#define NR_PORTS        128
+
+#define ZE_V1_NPORTS	64
+#define ZO_V1	0
+#define ZO_V2	1
+#define ZE_V1	2
 
 #define SERIAL_PARANOIA_CHECK
 #undef  SERIAL_DEBUG_OPEN
@@ -453,35 +503,51 @@
 #include <linux/kernel.h>
 #include <linux/bios32.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 
 #include <linux/version.h>
 
-#if LINUX_VERSION_CODE >= 131328
+#if (LINUX_VERSION_CODE >= 0x020100)
 
 #include <asm/uaccess.h>
+#include <linux/init.h>
 
-#define memcpy_fromfs	copy_from_user
-#define memcpy_tofs	copy_to_user
-#define put_fs_long	put_user
-#define vremap		ioremap
+#define cy_put_user	put_user
 
-static unsigned long get_fs_long(unsigned long *addr)
+static unsigned long cy_get_user(unsigned long *addr)
 {
 	unsigned long result = 0;
 	int error = get_user (result, addr);
 	if (error)
-		printk ("cyclades: get_fs_long: error == %d\n", error);
+		printk ("cyclades: cy_get_user: error == %d\n", error);
 	return result;
 }
 
+#else
+
+#define __initfunc(__arginit)	__arginit
+#define copy_from_user		memcpy_fromfs
+#define copy_to_user		memcpy_tofs
+#define cy_get_user		get_fs_long
+#define cy_put_user		put_fs_long
+#define ioremap			vremap
+
 #endif
 
 #ifndef MIN
 #define MIN(a,b)        ((a) < (b) ? (a) : (b))
 #endif
+
 #define IS_CYC_Z(card) ((card).num_chips == 1)
 
+#define Z_FPGA_CHECK(card) \
+    ((((struct RUNTIME_9060 *)((card).ctl_addr))->init_ctrl&(1<<17))!=0)
+
+#define ISZLOADED(card)	(((ZO_V1==((struct RUNTIME_9060 *) \
+			((card).ctl_addr))->mail_box_0) || \
+			Z_FPGA_CHECK(card)) && \
+			(ZFIRM_ID==((struct FIRM_ID *) \
+			((card).base_addr+ID_ADDRESS))->signature))
+
 #define WAKEUP_CHARS (SERIAL_XMIT_SIZE-256)
 
 #define STD_COM_FLAGS (0)
@@ -548,7 +614,7 @@
 
 /*
  * tmp_buf is used as a temporary buffer by serial_write.  We need to
- * lock it in case the memcpy_fromfs blocks while swapping in a page,
+ * lock it in case the copy_from_user blocks while swapping in a page,
  * and some other program tries to do a serial write at the same time.
  * Since the lock will only come under contention when the system is
  * swapping and available memory is low, it makes sense to share one
@@ -698,10 +764,12 @@
     { (data<10)?  CP(data+'0'): CP(data+'A'-10); }/* CP4 */
 static void CP8(int data)
     { CP4((data>>4) & 0x0f); CP4( data & 0x0f); }/* CP8 */
+#if 0
 static void CP16(int data)
     { CP8((data>>8) & 0xff); CP8(data & 0xff); }/* CP16 */
 static void CP32(long data)
     { CP16((data>>16) & 0xffff); CP16(data & 0xffff); }/* CP32 */
+#endif
 
 
 /*
@@ -758,6 +826,7 @@
     if (!tty)
         return;
 
+#if (LINUX_VERSION_CODE >= 0x020125)
     if (test_and_clear_bit(Cy_EVENT_HANGUP, &info->event)) {
         tty_hangup(info->tty);
         wake_up_interruptible(&info->open_wait);
@@ -774,6 +843,24 @@
         }
         wake_up_interruptible(&tty->write_wait);
     }
+#else
+    if (clear_bit(Cy_EVENT_HANGUP, &info->event)) {
+        tty_hangup(info->tty);
+        wake_up_interruptible(&info->open_wait);
+        info->flags &= ~(ASYNC_NORMAL_ACTIVE|
+                             ASYNC_CALLOUT_ACTIVE);
+    }
+    if (clear_bit(Cy_EVENT_OPEN_WAKEUP, &info->event)) {
+        wake_up_interruptible(&info->open_wait);
+    }
+    if (clear_bit(Cy_EVENT_WRITE_WAKEUP, &info->event)) {
+        if((tty->flags & (1<< TTY_DO_WRITE_WAKEUP))
+        && tty->ldisc.write_wakeup){
+            (tty->ldisc.write_wakeup)(tty);
+        }
+        wake_up_interruptible(&tty->write_wait);
+    }
+#endif
 } /* do_softint */
 
 
@@ -1351,7 +1438,7 @@
 
 /***********************************************************/
 /********* End of block of Cyclom-Y specific code **********/
-/******** Start of block of Cyclom-Z specific code *********/
+/******** Start of block of Cyclades-Z specific code *********/
 /***********************************************************/
 
 
@@ -1365,7 +1452,7 @@
   unsigned long loc_doorbell;
 
     firm_id = (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS);
-    if (firm_id->signature != ZFIRM_ID){
+    if (!ISZLOADED(*cinfo)){
 	return (-1);
     }
     zfw_ctrl = (struct ZFW_CTRL *)
@@ -1397,7 +1484,7 @@
   int index;
 
     firm_id = (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS);
-    if (firm_id->signature != ZFIRM_ID){
+    if (!ISZLOADED(*cinfo)){
 	return (-1);
     }
     zfw_ctrl = (struct ZFW_CTRL *)
@@ -1408,7 +1495,7 @@
     pci_doorbell = &((struct RUNTIME_9060 *)
                      (cinfo->ctl_addr))->pci_doorbell;
     while( (*pci_doorbell & 0xff) != 0){
-        if (index++ == 100){
+        if (index++ == 1000){
             return(-1);
         }
 	udelay(50L);
@@ -1421,6 +1508,7 @@
 } /* cyz_issue_cmd */
 
 
+#if 0
 static int
 cyz_update_channel( struct cyclades_card *cinfo,
 	    u_long channel, u_char mode, u_char cmd)
@@ -1430,7 +1518,7 @@
   struct ZFW_CTRL *zfw_ctrl;
   struct CH_CTRL *ch_ctrl;
 
-    if (firm_id->signature != ZFIRM_ID){
+    if (!ISZLOADED(*cinfo)){
 	return (-1);
     }
     zfw_ctrl =
@@ -1442,6 +1530,7 @@
     return cyz_issue_cmd(cinfo, channel, cmd, 0L);
 
 } /* cyz_update_channel */
+#endif
 
 
 static void
@@ -1467,6 +1556,7 @@
   u_long channel;
   u_char cmd;
   u_long *param;
+  u_long hw_ver, fw_ver;
 
     cyz_timerlist.expires = jiffies + 100;
 
@@ -1476,7 +1566,7 @@
 
 	firm_id = (struct FIRM_ID *)
 		    (cinfo->base_addr + ID_ADDRESS);
-        if (firm_id->signature != ZFIRM_ID){
+        if (!ISZLOADED(*cinfo)){
 	    continue;
 	}
 
@@ -1484,6 +1574,8 @@
 	    (struct ZFW_CTRL *)
 	    (cinfo->base_addr + firm_id->zfwctrl_addr);
 	board_ctrl = &zfw_ctrl->board_ctrl;
+	fw_ver = board_ctrl->fw_version;
+	hw_ver = ((struct RUNTIME_9060 *)(cinfo->ctl_addr))->mail_box_0;
 
 	while( cyz_fetch_msg( cinfo, &channel, &cmd, &param) == 1){
 	    char_count = 0;
@@ -1514,7 +1606,9 @@
 	        break;
 	    case C_CM_MDCD:
 		if (info->flags & ASYNC_CHECK_CD){
-		    if( ch_ctrl[channel].rs_status & C_RS_DCD){
+		    if (((hw_ver != 0 || fw_ver > 241)
+			? ((u_long)param)
+			: ch_ctrl[channel].rs_status) & C_RS_DCD) {
 			/* SP("Open Wakeup\n"); */
 			cy_sched_event(info,
 			    Cy_EVENT_OPEN_WAKEUP);
@@ -1709,7 +1803,7 @@
 } /* cyz_poll */
 
 
-/********** End of block of Cyclom-Z specific code *********/
+/********** End of block of Cyclades-Z specific code *********/
 /***********************************************************/
 
 
@@ -1794,7 +1888,7 @@
 	base_addr = (unsigned char*) (cy_card[card].base_addr);
 
         firm_id = (struct FIRM_ID *) (base_addr + ID_ADDRESS);
-        if (firm_id->signature != ZFIRM_ID){
+        if (!ISZLOADED(cy_card[card])){
 	    return -ENODEV;
 	}
 
@@ -1951,7 +2045,7 @@
 #endif
 
         firm_id = (struct FIRM_ID *) (base_addr + ID_ADDRESS);
-        if (firm_id->signature != ZFIRM_ID){
+        if (!ISZLOADED(cy_card[card])) {
 	    return;
 	}
 
@@ -2143,7 +2237,7 @@
 	base_addr = (char *)(cinfo->base_addr);
 	firm_id = (struct FIRM_ID *)
 			(base_addr + ID_ADDRESS);
-        if (firm_id->signature != ZFIRM_ID){
+        if (!ISZLOADED(*cinfo)){
 	    return -EINVAL;
 	}
 
@@ -2237,11 +2331,17 @@
        will make the user pay attention.
     */
     if (IS_CYC_Z(cy_card[info->card])) {
-      struct FIRM_ID *firm_id =
-                (struct FIRM_ID *)
-		(cy_card[info->card].base_addr + ID_ADDRESS);
-        if (firm_id->signature != ZFIRM_ID){
-	    printk("Cyclom-Z firmware not yet loaded\n");
+        if (!ISZLOADED(cy_card[info->card])) {
+	    if (((ZE_V1 ==((struct RUNTIME_9060 *)
+		((cy_card[info->card]).ctl_addr))->mail_box_0) &&
+		Z_FPGA_CHECK(cy_card[info->card])) &&
+		(ZFIRM_HLT==((struct FIRM_ID *)
+		((cy_card[info->card]).base_addr+ID_ADDRESS))->signature))
+	    {
+		printk ("Cyclades-Z Error: you need an external power supply for this number of ports.\n\rFirmware halted.\r\n");
+	    } else {
+		printk("Cyclades-Z firmware not yet loaded\n");
+	    }
 	    return -ENODEV;
 	}
     }
@@ -2448,7 +2548,7 @@
         }
 
         if (from_user) {
-            memcpy_fromfs(tmp_buf, buf, c);
+            copy_from_user(tmp_buf, buf, c);
             c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
                        SERIAL_XMIT_SIZE - info->xmit_head));
             memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
@@ -2816,7 +2916,7 @@
 
         firm_id = (struct FIRM_ID *)
 			(cy_card[card].base_addr + ID_ADDRESS);
-        if (firm_id->signature != ZFIRM_ID){
+        if (!ISZLOADED(cy_card[card])) {
 	    return;
 	}
 
@@ -2956,7 +3056,7 @@
     tmp.baud_base = info->baud;
     tmp.custom_divisor = 0;     /*!!!*/
     tmp.hub6 = 0;               /*!!!*/
-    memcpy_tofs(retinfo,&tmp,sizeof(*retinfo));
+    copy_to_user(retinfo,&tmp,sizeof(*retinfo));
     return 0;
 } /* get_serial_info */
 
@@ -2970,7 +3070,7 @@
 
     if (!new_info)
             return -EFAULT;
-    memcpy_fromfs(&new_serial,new_info,sizeof(new_serial));
+    copy_from_user(&new_serial,new_info,sizeof(new_serial));
     old_info = *info;
 
     if (!suser()) {
@@ -3051,7 +3151,7 @@
 
 	firm_id = (struct FIRM_ID *)
 		    (cy_card[card].base_addr + ID_ADDRESS);
-	if (firm_id->signature == ZFIRM_ID){
+        if (ISZLOADED(cy_card[card])) {
 	    zfw_ctrl =
 		(struct ZFW_CTRL *)
 		(cy_card[card].base_addr + firm_id->zfwctrl_addr);
@@ -3070,7 +3170,7 @@
 	}
 
     }
-    put_fs_long(result,(unsigned long *) value);
+    cy_put_user(result,(unsigned long *) value);
     return 0;
 } /* get_modem_info */
 
@@ -3082,7 +3182,7 @@
   int card,chip,channel,index;
   unsigned char *base_addr;
   unsigned long flags;
-  unsigned int arg = get_fs_long((unsigned long *) value);
+  unsigned int arg = cy_get_user((unsigned long *) value);
   struct FIRM_ID *firm_id;
   struct ZFW_CTRL *zfw_ctrl;
   struct BOARD_CTRL *board_ctrl;
@@ -3180,7 +3280,7 @@
 
 	firm_id = (struct FIRM_ID *)
 		    (cy_card[card].base_addr + ID_ADDRESS);
-	if (firm_id->signature == ZFIRM_ID){
+        if (ISZLOADED(cy_card[card])) {
 	    zfw_ctrl =
 		(struct ZFW_CTRL *)
 		(cy_card[card].base_addr + firm_id->zfwctrl_addr);
@@ -3281,7 +3381,7 @@
 get_mon_info(struct cyclades_port * info, struct cyclades_monitor * mon)
 {
 
-    memcpy_tofs(mon, &info->mon, sizeof(struct cyclades_monitor));
+    copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor));
     info->mon.int_count  = 0;
     info->mon.char_count = 0;
     info->mon.char_max   = 0;
@@ -3335,7 +3435,7 @@
 		       + (cy_chip_offset[chip]<<index));
 
 	tmp = base_addr[CyCOR3<<index] & CyREC_FIFO;
-	put_fs_long(tmp,value);
+	cy_put_user(tmp,value);
     } else {
 	// Nothing to do!
     }
@@ -3354,7 +3454,7 @@
 static int
 get_default_threshold(struct cyclades_port * info, unsigned long *value)
 {
-    put_fs_long(info->default_threshold,value);
+    cy_put_user(info->default_threshold,value);
     return 0;
 }/* get_default_threshold */
 
@@ -3401,7 +3501,7 @@
 		       + (cy_chip_offset[chip]<<index));
 
 	tmp = base_addr[CyRTPR<<index];
-	put_fs_long(tmp,value);
+	cy_put_user(tmp,value);
     } else {
 	// Nothing to do!
     }
@@ -3420,7 +3520,7 @@
 static int
 get_default_timeout(struct cyclades_port * info, unsigned long *value)
 {
-    put_fs_long(info->default_timeout,value);
+    cy_put_user(info->default_timeout,value);
     return 0;
 }/* get_default_timeout */
 
@@ -3530,7 +3630,7 @@
                 ret_val = error;
                 break;
             }
-            put_fs_long(C_CLOCAL(tty) ? 1 : 0,
+            cy_put_user(C_CLOCAL(tty) ? 1 : 0,
                         (unsigned long *) arg);
             break;
         case TIOCSSOFTCAR:
@@ -3541,7 +3641,7 @@
                 break;
            }
 
-            arg = get_fs_long((unsigned long *) arg);
+            arg = cy_get_user((unsigned long *) arg);
             tty->termios->c_cflag =
                     ((tty->termios->c_cflag & ~CLOCAL) |
                      (arg ? CLOCAL : 0));
@@ -3967,8 +4067,8 @@
                 }
 
                 /* probe for CD1400... */
-#if LINUX_VERSION_CODE >= 131328
-		cy_isa_address = vremap((unsigned int)cy_isa_address,0x2000);
+#if (LINUX_VERSION_CODE >= 0x020100)
+		cy_isa_address = ioremap((unsigned int)cy_isa_address,0x2000);
 #endif
                 cy_isa_nchan = 4 * cyy_init_card(cy_isa_address,0);
                 if (cy_isa_nchan == 0) {
@@ -3988,6 +4088,7 @@
                         printk("Cyclom-Y/ISA found at 0x%x ",
                                 (unsigned int) cy_isa_address);
                         printk("but no more channels are available.\n");
+                        printk("Change NR_PORTS in cyclades.c and recompile kernel.\n");
                         return(nboard);
                 }
                 /* fill the next cy_card structure available */
@@ -3998,6 +4099,7 @@
                         printk("Cyclom-Y/ISA found at 0x%x ",
                                 (unsigned int) cy_isa_address);
                         printk("but no more cards can be used .\n");
+                        printk("Change NR_CARDS in cyclades.c and recompile kernel.\n");
                         return(nboard);
                 }
 
@@ -4051,6 +4153,8 @@
   unsigned int          cy_pci_addr0, cy_pci_addr1, cy_pci_addr2;
   unsigned short        i,j,cy_pci_nchan;
   unsigned short        device_id,dev_index = 0,board_index = 0;
+  unsigned long         mailbox;
+  unsigned int          Ze_addr0[NR_CARDS], Ze_addr2[NR_CARDS], ZeIndex = 0;
 
         if(pcibios_present() == 0) {    /* PCI bus not present */
                 return(0);
@@ -4070,6 +4174,9 @@
                         }
                 }
 
+		if (device_id == 0)
+		    break;
+
                 /* read PCI configuration area */
                 pcibios_read_config_byte(cyy_bus, cyy_dev_fn,
                                  PCI_INTERRUPT_LINE, &cy_pci_irq);
@@ -4081,9 +4188,7 @@
                                   PCI_BASE_ADDRESS_2, &cy_pci_addr2);
                 pcibios_read_config_byte(cyy_bus, cyy_dev_fn,
                                   PCI_REVISION_ID, &cyy_rev_id);
-    if (device_id == 0){
-	break;
-    }else if ((device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo)
+    if ((device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo)
 	   || (device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi)){
 #ifdef CY_PCI_DEBUG
             printk("Cyclom-Y/PCI (bus=0x0%x, pci_id=0x%x, ",
@@ -4096,11 +4201,11 @@
                 cy_pci_addr1  &= 0xfffffffc;
                 cy_pci_addr2  &= 0xfffffff0;
 
-#if LINUX_VERSION_CODE < 131328
+#if (LINUX_VERSION_CODE < 0x020100)
                 if ((ulong)cy_pci_addr2 >= 0x100000)  /* above 1M? */
 #endif
 		    cy_pci_addr2 =
-			(unsigned int) vremap(cy_pci_addr2,CyPCI_Ywin);
+			(unsigned int) ioremap(cy_pci_addr2,CyPCI_Ywin);
 
 #ifdef CY_PCI_DEBUG
             printk("Cyclom-Y/PCI: relocate winaddr=0x%x ioaddr=0x%x\n",
@@ -4112,12 +4217,14 @@
                         printk("Cyclom-Y PCI host card with ");
                         printk("no Serial-Modules at 0x%x.\n",
 			    (unsigned int) cy_pci_addr2);
+                        i--;
                         continue;
                 }
                 if((cy_next_channel+cy_pci_nchan) > NR_PORTS) {
                         printk("Cyclom-Y/PCI found at 0x%x ",
 			    (unsigned int) cy_pci_addr2);
                         printk("but no channels are available.\n");
+                        printk("Change NR_PORTS in cyclades.c and recompile kernel.\n");
                         return(i);
                 }
                 /* fill the next cy_card structure available */
@@ -4128,6 +4235,7 @@
                         printk("Cyclom-Y/PCI found at 0x%x ",
 			    (unsigned int) cy_pci_addr2);
                         printk("but no more cards can be used.\n");
+                        printk("Change NR_CARDS in cyclades.c and recompile kernel.\n");
                         return(i);
                 }
 
@@ -4167,65 +4275,101 @@
                 cy_next_channel += cy_pci_nchan;
     }else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo){
 	    /* print message */
-		printk("Cyclom-Z/PCI (bus=0x0%x, pci_id=0x%x, ",
+		printk("Cyclades-Z/PCI (bus=0x0%x, pci_id=0x%x, ",
 		    cyy_bus, cyy_dev_fn);
 		printk("rev_id=%d) IRQ%d\n",
 		    cyy_rev_id, (int)cy_pci_irq);
-		printk("Cyclom-Z/PCI: found winaddr=0x%x ctladdr=0x%x\n",
+		printk("Cyclades-Z/PCI: found winaddr=0x%x ctladdr=0x%x\n",
 		    cy_pci_addr2, cy_pci_addr0);
-	    printk("Cyclom-Z/PCI not supported for low addresses\n");
+	    printk("Cyclades-Z/PCI not supported for low addresses\n");
 	    break;
     }else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi){
 #ifdef CY_PCI_DEBUG
-            printk("Cyclom-Z/PCI (bus=0x0%x, pci_id=0x%x, ",
+            printk("Cyclades-Z/PCI (bus=0x0%x, pci_id=0x%x, ",
 		cyy_bus, cyy_dev_fn);
             printk("rev_id=%d) IRQ%d\n",
 		cyy_rev_id, (int)cy_pci_irq);
-            printk("Cyclom-Z/PCI: found winaddr=0x%x ctladdr=0x%x\n",
+            printk("Cyclades-Z/PCI: found winaddr=0x%x ctladdr=0x%x\n",
                 cy_pci_addr2, cy_pci_addr0);
 #endif
-                cy_pci_addr2 &= 0xfffffff0;
-                cy_pci_addr2 = (unsigned int) vremap(
-                               cy_pci_addr2 & PAGE_MASK,
-                               PAGE_ALIGN(CyPCI_Zwin))
-                               + (cy_pci_addr2 & (PAGE_SIZE-1));
                 cy_pci_addr0 &= 0xfffffff0;
-                cy_pci_addr0 = (unsigned int) vremap(
+                cy_pci_addr0 = (unsigned int) ioremap(
                                cy_pci_addr0 & PAGE_MASK,
                                PAGE_ALIGN(CyPCI_Zctl))
                                + (cy_pci_addr0 & (PAGE_SIZE-1));
+
+		mailbox = ((struct RUNTIME_9060 *) cy_pci_addr0)->mail_box_0;
+                cy_pci_addr2 &= 0xfffffff0;
+		if (mailbox == ZE_V1) {
+               	    cy_pci_addr2 = (unsigned int) ioremap(
+	            	cy_pci_addr2 & PAGE_MASK,
+	            	PAGE_ALIGN(CyPCI_Ze_win))
+	            	+ (cy_pci_addr2 & (PAGE_SIZE-1));
+		    if (ZeIndex == NR_CARDS) {
+			printk("Cyclades-Z/PCI found at 0x%x ",
+				(unsigned int) cy_pci_addr2);
+			printk("but no more cards can be used.\n");
+                        printk("Change NR_CARDS in cyclades.c and recompile kernel.\n");
+		    } else {
+			Ze_addr0[ZeIndex] = cy_pci_addr0;
+			Ze_addr2[ZeIndex] = cy_pci_addr2;
+			ZeIndex++;
+		    }
+		    i--;
+		    continue;
+		} else {
+                    cy_pci_addr2 = (unsigned int) ioremap(
+			cy_pci_addr2 & PAGE_MASK,
+			PAGE_ALIGN(CyPCI_Zwin))
+			+ (cy_pci_addr2 & (PAGE_SIZE-1));
+		}
+
 #ifdef CY_PCI_DEBUG
-            printk("Cyclom-Z/PCI: relocate winaddr=0x%x ctladdr=0x%x\n",
+            printk("Cyclades-Z/PCI: relocate winaddr=0x%x ctladdr=0x%x\n",
                 cy_pci_addr2, cy_pci_addr0);
-	    ((struct RUNTIME_9060 *)(cy_pci_addr0))
+	    if (mailbox == ZO_V1) {
+		((struct RUNTIME_9060 *)(cy_pci_addr0))
 					    ->loc_addr_base = WIN_CREG;
-            PAUSE
-            printk("Cyclom-Z/PCI: FPGA id %lx, ver %lx\n",
-		0xff & ((struct CUSTOM_REG *)(cy_pci_addr2))->fpga_id,
-		0xff & ((struct CUSTOM_REG *)(cy_pci_addr2))->fpga_version);
-	    ((struct RUNTIME_9060 *)(cy_pci_addr0))
-					    ->loc_addr_base = WIN_RAM;
+		PAUSE
+		printk("Cyclades-Z/PCI: FPGA id %lx, ver %lx\n",
+		    0xff & ((struct CUSTOM_REG *)(cy_pci_addr2))->fpga_id,
+		    0xff & ((struct CUSTOM_REG *)(cy_pci_addr2))->fpga_version);
+		((struct RUNTIME_9060 *)(cy_pci_addr0))
+						->loc_addr_base = WIN_RAM;
+	    } else {
+		printk("Cyclades-Z/PCI: New Cyclades-Z board.  FPGA not loaded\n");
+	    }
 #endif
 	    /* The following clears the firmware id word.  This ensures
 	       that the driver will not attempt to talk to the board
 	       until it has been properly initialized.
 	     */
 		PAUSE
-		*(unsigned long *)(cy_pci_addr2+ID_ADDRESS) = 0L;
+		if (mailbox == ZO_V1)
+		    *(unsigned long *)(cy_pci_addr2+ID_ADDRESS) = 0L;
 
-                /* This must be a Cyclom-8Zo/PCI.  The extendable
+                /* This must be a Cyclades-8Zo/PCI.  The extendable
                    version will have a different device_id and will
                    be allocated its maximum number of ports. */
                 cy_pci_nchan = 8;
 
+                if((cy_next_channel+cy_pci_nchan) > NR_PORTS) {
+                        printk("Cyclades-Z/PCI found at 0x%x ",
+			    (unsigned int) cy_pci_addr2);
+                        printk("but no channels are available.\n");
+                        printk("Change NR_PORTS in cyclades.c and recompile kernel.\n");
+                        return(i);
+                }
+
                 /* fill the next cy_card structure available */
                 for (j = 0 ; j < NR_CARDS ; j++) {
                         if (cy_card[j].base_addr == 0)  break;
                 }
                 if (j == NR_CARDS) {    /* no more cy_cards available */
-		    printk("Cyclom-Z/PCI found at 0x%x ",
+		    printk("Cyclades-Z/PCI found at 0x%x ",
 			(unsigned int) cy_pci_addr2);
 		    printk("but no more cards can be used.\n");
+                    printk("Change NR_CARDS in cyclades.c and recompile kernel.\n");
 		    return(i);
                 }
 
@@ -4235,9 +4379,9 @@
 			SA_INTERRUPT,"cyclomZ",NULL))
 		    {
 			printk("Could not allocate IRQ%d ",
-			    (unsigned int) cy_pci_addr2);
-			printk("for Cyclom-Z/PCI at 0x%x.\n",
 			    cy_pci_irq);
+			printk("for Cyclades-Z/PCI at 0x%x.\n",
+			    (unsigned int) cy_pci_addr2);
 			return(i);
 		    }
 		}
@@ -4254,12 +4398,12 @@
                 /* print message */
 		/* don't report IRQ if board is no IRQ */
 		if( (cy_pci_irq < 15) && (cy_pci_irq > 1) ) {
-		    printk("Cyclom-Z/PCI #%d: 0x%x-0x%x, IRQ%d, ",
+		    printk("Cyclades-Z/PCI #%d: 0x%x-0x%x, IRQ%d, ",
 			j+1,cy_pci_addr2,
 			(cy_pci_addr2 + CyPCI_Zwin - 1),
 			(int)cy_pci_irq);
 		}else{
-		    printk("Cyclom-Z/PCI #%d: 0x%x-0x%x, ",
+		    printk("Cyclades-Z/PCI #%d: 0x%x-0x%x, ",
 			j+1,cy_pci_addr2,
 			(cy_pci_addr2 + CyPCI_Zwin - 1));
 		}
@@ -4268,6 +4412,93 @@
                 cy_next_channel += cy_pci_nchan;
     }
         }
+
+        for (; ZeIndex != 0 && i < NR_CARDS; i++) {
+	    cy_pci_addr0 = Ze_addr0[0];
+	    cy_pci_addr2 = Ze_addr2[0];
+	    for (j = 0 ; j < ZeIndex-1 ; j++) {
+		Ze_addr0[j] = Ze_addr0[j+1];
+		Ze_addr2[j] = Ze_addr2[j+1];
+	    }
+	    ZeIndex--;
+	    mailbox = ((struct RUNTIME_9060 *) cy_pci_addr0)->mail_box_0;
+#ifdef CY_PCI_DEBUG
+            printk("Cyclades-Z/PCI: relocate winaddr=0x%x ctladdr=0x%x\n",
+                cy_pci_addr2, cy_pci_addr0);
+	    printk("Cyclades-Z/PCI: New Cyclades-Z board.  FPGA not loaded\n");
+#endif
+	    /* The following clears the firmware id word.  This ensures
+	       that the driver will not attempt to talk to the board
+	       until it has been properly initialized.
+	     */
+		PAUSE
+                /* This must be the new Cyclades-Ze/PCI. */
+                cy_pci_nchan = ZE_V1_NPORTS;
+
+                if((cy_next_channel+cy_pci_nchan) > NR_PORTS) {
+                        printk("Cyclades-Z/PCI found at 0x%x ",
+			    (unsigned int) cy_pci_addr2);
+                        printk("but no channels are available.\n");
+                        printk("Change NR_PORTS in cyclades.c and recompile kernel.\n");
+                        return(i);
+                }
+
+                /* fill the next cy_card structure available */
+                for (j = 0 ; j < NR_CARDS ; j++) {
+                        if (cy_card[j].base_addr == 0)  break;
+                }
+                if (j == NR_CARDS) {    /* no more cy_cards available */
+		    printk("Cyclades-Z/PCI found at 0x%x ",
+			(unsigned int) cy_pci_addr2);
+		    printk("but no more cards can be used.\n");
+                    printk("Change NR_CARDS in cyclades.c and recompile kernel.\n");
+		    return(i);
+                }
+
+                /* allocate IRQ only if board has an IRQ */
+		if( (1 < cy_pci_irq) && (cy_pci_irq < 15) ) {
+		    if(request_irq(cy_pci_irq,cyz_interrupt,
+			SA_INTERRUPT,"cyclomZ",NULL))
+		    {
+			printk("Could not allocate IRQ%d ",
+			    cy_pci_irq);
+			printk("for Cyclades-Z/PCI at 0x%x.\n",
+			    (unsigned int) cy_pci_addr2);
+			return(i);
+		    }
+		}
+
+                /* set cy_card */
+                cy_card[j].base_addr = cy_pci_addr2;
+                cy_card[j].ctl_addr = cy_pci_addr0;
+                cy_card[j].irq = (int) cy_pci_irq;
+                cy_card[j].bus_index = 1;
+                cy_card[j].first_line = cy_next_channel;
+                cy_card[j].num_chips = 1;
+                IRQ_cards[cy_pci_irq] = &cy_card[j];
+
+                /* print message */
+		/* don't report IRQ if board is no IRQ */
+		if( (cy_pci_irq < 15) && (cy_pci_irq > 1) ) {
+		    printk("Cyclades-Z/PCI #%d: 0x%x-0x%x, IRQ%d, ",
+			j+1,cy_pci_addr2,
+			(cy_pci_addr2 + CyPCI_Ze_win - 1),
+			(int)cy_pci_irq);
+		}else{
+		    printk("Cyclades-Z/PCI #%d: 0x%x-0x%x, ",
+			j+1,cy_pci_addr2,
+			(cy_pci_addr2 + CyPCI_Ze_win - 1));
+		}
+                printk("%d channels starting from port %d.\n",
+		    cy_pci_nchan,cy_next_channel);
+                cy_next_channel += cy_pci_nchan;
+        }
+	if (ZeIndex != 0) {
+	    printk("Cyclades-Z/PCI found at 0x%x ",
+		(unsigned int) Ze_addr2[0]);
+	    printk("but no more cards can be used.\n");
+            printk("Change NR_CARDS in cyclades.c and recompile kernel.\n");
+	}
         return(i);
 #else
         return(0);
@@ -4319,6 +4550,8 @@
   struct cyclades_card *cinfo;
   int number_z_boards = 0;
   int board,port,i;
+  unsigned long mailbox;
+  int nports;
 
     show_version();
 
@@ -4416,10 +4649,13 @@
     /* initialize per-port data structures for each valid board found */
     for (board = 0 ; board < cy_nboard ; board++) {
             cinfo = &cy_card[board];
-            if (cinfo->num_chips == 1){ /* Cyclom-8Zo/PCI */
+            if (cinfo->num_chips == 1){ /* Cyclades-8Zo/PCI */
 		number_z_boards++;
+		mailbox = ((struct RUNTIME_9060 *)
+			cy_card[board].ctl_addr)->mail_box_0;
+		nports = (mailbox == ZE_V1) ? ZE_V1_NPORTS : 8;
                 for (port = cinfo->first_line ;
-                     port < cinfo->first_line + 8;
+                     port < cinfo->first_line + nports;
                      port++)
                 {
                     info = &cy_port[port];
@@ -4523,7 +4759,7 @@
 	cyz_timerlist.expires = jiffies + 1;
 	add_timer(&cyz_timerlist);
 #ifdef CY_PCI_DEBUG
-	printk("Cyclom-Z polling initialized\n");
+	printk("Cyclades-Z polling initialized\n");
 #endif
     }
 
diff -u --recursive --new-file v2.1.44/linux/drivers/char/joystick.c linux/drivers/char/joystick.c
--- v2.1.44/linux/drivers/char/joystick.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/joystick.c	Wed Jul 16 19:22:50 1997
@@ -0,0 +1,376 @@
+/*
+
+   linux/drivers/char/joystick.c
+   Copyright (C) 1992, 1993 Arthur C. Smith
+   Joystick driver for Linux running on an IBM compatible computer.
+
+VERSION INFO:
+01/08/93	ACS	0.1: Works but needs multi-joystick support
+01/13/93	ACS	0.2: Added multi-joystick support (minor 0 and 1)
+		  	     Added delay between measuring joystick axis
+		   	     Added scaling ioctl
+02/16/93	ACS	0.3: Modified scaling to use ints to prevent kernel
+			     panics 8-)
+02/28/93	ACS	0.4: Linux99.6 and fixed race condition in js_read.
+			     After looking at a schematic of a joystick card
+                             it became apparent that any write to the joystick
+			     port started ALL the joystick one shots. If the
+			     one that we are reading is short enough and the
+			     first one to be read, the second one will return
+			     bad data if it's one shot has not expired when
+			     the joystick port is written for the second time.
+			     Thus solves the mystery delay problem in 0.2!
+05/05/93       ACS/Eyal 0.5: Upgraded the driver to the 99.9 kernel, added
+			     joystick support to the make config options,
+			     updated the driver to return the buttons as
+			     positive logic, and read both axis at once
+			     (thanks Eyal!), and added some new ioctls.
+02/12/94   Jeff Tranter 0.6: Made necessary changes to work with 0.99pl15
+                             kernel (and hopefully 1.0). Also did some
+			     cleanup: indented code, fixed some typos, wrote
+			     man page, etc...
+05/17/95 Dan Fandrich 0.7.3: Added I/O port registration, cleaned up code
+04/03/96    Matt Rhoten 0.8: many minor changes:
+			     new read loop from Hal Maney <maney@norden.com>
+                             cleaned up #includes to allow #include of 
+                             joystick.h with gcc -Wall and from g++
+			     made js_init fail if it finds zero joysticks
+			     general source/comment cleanup
+			     use of MOD_(INC|DEC)_USE_COUNT
+			     changes from Bernd Schmidt <crux@Pool.Informatik.RWTH-Aachen.DE>
+			     to compile correctly under 1.3 in kernel or as module
+06/30/97       Alan Cox 0.9: Ported to 2.1.x
+			     Reformatted to resemble Linux coding standard
+			     Removed semaphore bug (we can dump the lot I think)
+			     Fixed xntp timer adjust during joystick timer0 bug
+			     Changed variable names to lower case. Kept binary
+			     	compatibility.
+			     Better ioctl names. Kept binary compatibility.
+			     Removed 'save_busy'. Just set busy to 1.
+*/
+
+#include <linux/module.h>
+#include <linux/joystick.h>
+#include <linux/mm.h>
+#include <linux/major.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+static struct js_config js_data[JS_MAX];	/* misc data */
+static int js_exist;			/* which joysticks' axis exist? */
+static int js_read_semaphore;	/* to prevent two processes from trying
+				   to read different joysticks at the
+				   same time */
+
+/* 
+ *	get_timer0():
+ *	returns the current value of timer 0. This is a 16 bit counter that starts
+ *	at LATCH and counts down to 0 
+ */
+   
+extern inline int get_timer0(void)
+{
+	unsigned long flags;
+	int t0, t1;
+	save_flags(flags);
+	cli();
+	outb (0, PIT_MODE);
+	t0 = (int) inb (PIT_COUNTER_0);
+	t1 = ((int) inb (PIT_COUNTER_0) << 8) + t0;
+	restore_flags(flags);
+	return (t1);
+}
+
+/*
+ *	find_axes():
+ *
+ *	returns which axes are hooked up, in a bitfield. 2^n is set if
+ *	axis n is hooked up, for 0 <= n < 4.
+ *
+ *	REVIEW: should update this to handle eight-axis (four-stick) game port
+ *	cards. anyone have one of these to test on? mattrh 3/23/96 
+ */
+ 
+extern inline int find_axes(void)
+{
+	int j;
+	outb (0xff, JS_PORT);		/* trigger oneshots */
+					/* and see what happens */
+	for (j = JS_DEF_TIMEOUT; (0x0f & inb (JS_PORT)) && j; j--);
+				/* do nothing; wait for the timeout */
+	js_exist = inb (JS_PORT) & 0x0f; /* get joystick status byte */
+	js_exist = (~js_exist) & 0x0f;
+/*	printk("find_axes: js_exist is %d (0x%04X)\n", js_exist, js_exist);*/
+	return js_exist;
+}
+
+static int js_ioctl (struct inode *inode,
+		     struct file *file,
+		     unsigned int cmd,
+		     unsigned long arg)
+{
+	unsigned int minor = MINOR (inode->i_rdev);
+	if (minor >= JS_MAX)
+		return -ENODEV;
+		
+	if ((((inb (JS_PORT) & 0x0f) >> (minor << 1)) & 0x03) == 0x03)	/*js minor exists?*/
+		return -ENODEV;
+	switch (cmd) 
+	{
+	
+		case JSIOCSCAL:	/*from struct *arg to js_data[minor]*/
+			if(copy_from_user(&js_data[minor].js_corr, 
+				(void *)arg, sizeof(struct js_status)))
+					return -EFAULT;
+			break;
+		case JSIOCGCAL:	/*to struct *arg from js_data[minor]*/
+			if(copy_to_user((void *) arg, &js_data[minor].js_corr, 
+				sizeof(struct js_status)))
+				return -EFAULT;
+			break;
+		case JSIOCSTIMEOUT:
+			if(copy_from_user(&js_data[minor].js_timeout,
+				(void *)arg, sizeof(js_data[0].js_timeout)))
+					return -EFAULT;
+			break;
+		case JSIOCGTIMEOUT:
+			if(copy_to_user((void *)arg, &js_data[minor].js_timeout,
+				sizeof(js_data[0].js_timeout)))
+					return -EFAULT;
+			break;
+		case JSIOCSTIMELIMIT:
+			if(copy_from_user(&js_data[minor].js_timelimit,
+				(void *)arg, sizeof(js_data[0].js_timelimit)))
+					return -EFAULT;
+			break;
+		case JSIOCGTIMELIMIT:
+			if(copy_to_user((void *)arg, &js_data[minor].js_timelimit,
+				sizeof(js_data[0].js_timelimit)))
+					return -EFAULT;
+			break;
+		case JSIOCGCONFIG:
+			if(copy_to_user((void *)arg, &js_data[minor],
+				sizeof(struct js_config)))
+					return -EFAULT;
+			break;
+		case JSIOCSCONFIG:
+			if(copy_from_user(&js_data[minor], (void *)arg, 
+				sizeof(struct js_config)))
+					return -EFAULT;
+			/* Must be busy to do this ioctl! */
+			js_data[minor].busy = 1;
+			break;
+		default:
+			return -EINVAL;
+	}
+	return 0;
+}
+
+/*
+ *	js_open():
+ *	device open routine. increments module usage count, initializes
+ *	data for that joystick.
+ *
+ *	returns: 0 or
+ *	-ENODEV: asked for joystick other than #0 or #1
+ *	-ENODEV: asked for joystick on axis where there is none
+ *	-EBUSY: attempt to open joystick already open
+ */
+ 
+static int js_open (struct inode *inode, struct file *file)
+{
+	unsigned int minor = MINOR (inode->i_rdev);
+	int j;
+
+	if (minor >= JS_MAX)
+		return -ENODEV;	/*check for joysticks*/
+
+	for (j = JS_DEF_TIMEOUT; (js_exist & inb (JS_PORT)) && j; j--);
+	cli();			/*block js_read while js_exist is being modified*/
+	/*js minor exists?*/
+	if ((((js_exist = inb (JS_PORT)) >> (minor << 1)) & 0x03) == 0x03) {
+		js_exist = (~js_exist) & 0x0f;
+		sti();
+		return -ENODEV;
+	}
+	js_exist = (~js_exist) & 0x0f;
+	sti();
+
+	if (js_data[minor].busy)
+		return -EBUSY;
+	js_data[minor].busy = JS_TRUE;
+	js_data[minor].js_corr.x = JS_DEF_CORR;	/*default scale*/
+	js_data[minor].js_corr.y = JS_DEF_CORR;
+	js_data[minor].js_timeout = JS_DEF_TIMEOUT;
+	js_data[minor].js_timelimit = JS_DEF_TIMELIMIT;
+	js_data[minor].js_expiretime = jiffies;
+
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int js_release (struct inode *inode, struct file *file)
+{
+	unsigned int minor = MINOR (inode->i_rdev);
+	inode->i_atime = CURRENT_TIME;
+	js_data[minor].busy = JS_FALSE;
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+/*
+ *	js_read() reads the buttons x, and y axis from both joysticks if a
+ *	given interval has expired since the last read or is equal to
+ *	-1l. The buttons are in port 0x201 in the high nibble. The axis are
+ *	read by writing to 0x201 and then measuring the time it takes the
+ *	one shots to clear.
+ */
+
+static long js_read (struct inode *inode, struct file *file, char *buf, unsigned long count)
+{
+	int j, chk, jsmask;
+	int t0, t_x0, t_y0, t_x1, t_y1;
+	unsigned int minor, minor2;
+	int buttons;
+
+	if (count != JS_RETURN)
+		return -EINVAL;
+	minor = MINOR (inode->i_rdev);
+	inode->i_atime = CURRENT_TIME;
+	if (jiffies >= js_data[minor].js_expiretime) 
+	{
+		minor2 = minor << 1;
+		j = js_data[minor].js_timeout;
+		for (; (js_exist & inb (JS_PORT)) && j; j--);
+		if (j == 0)
+			return -ENODEV;	/*no joystick here*/
+		/*Make sure no other proc is using port*/
+	
+		cli();
+		js_read_semaphore++;
+		sti();
+		
+		buttons = ~(inb (JS_PORT) >> 4);
+		js_data[0].js_save.buttons = buttons & 0x03;
+		js_data[1].js_save.buttons = (buttons >> 2) & 0x03;
+		j = js_data[minor].js_timeout;
+		jsmask = 0;
+
+		cli();		/*no interrupts!*/
+		outb (0xff, JS_PORT);	/*trigger one-shots*/
+		/*get init timestamp*/
+		t_x0 = t_y0 = t_x1 = t_y1 = t0 = get_timer0 ();
+		/*wait for an axis' bit to clear or timeout*/
+		while (j-- && (chk = (inb (JS_PORT) & js_exist ) | jsmask)) 
+		{
+			if (!(chk & JS_X_0)) {
+				t_x0 = get_timer0();
+				jsmask |= JS_X_0;
+			}
+			if (!(chk & JS_Y_0)) {
+				t_y0 = get_timer0();
+				jsmask |= JS_Y_0;
+			}
+			if (!(chk & JS_X_1)) {
+				t_x1 = get_timer0();
+				jsmask |= JS_X_1;
+			}
+			if (!(chk & JS_Y_1)) {
+				t_y1 = get_timer0();
+				jsmask |= JS_Y_1;
+			}
+		}
+		sti();					/* allow interrupts */
+
+		js_read_semaphore = 0;	/* allow other reads to progress */
+		if (j == 0)
+			return -ENODEV;	/*read timed out*/
+		js_data[0].js_expiretime = jiffies +
+			js_data[0].js_timelimit;	/*update data*/
+		js_data[1].js_expiretime = jiffies +
+			js_data[1].js_timelimit;
+		js_data[0].js_save.x = DELTA_TIME (t0, t_x0) >>
+			js_data[0].js_corr.x;
+		js_data[0].js_save.y = DELTA_TIME (t0, t_y0) >>
+			js_data[0].js_corr.y;
+		js_data[1].js_save.x = DELTA_TIME (t0, t_x1) >>
+			js_data[1].js_corr.x;
+		js_data[1].js_save.y = DELTA_TIME (t0, t_y1) >>
+			js_data[1].js_corr.y;
+	}
+
+	if(copy_to_user(buf, &js_data[minor].js_save, JS_RETURN))
+		return -EFAULT;
+	return JS_RETURN;
+}
+
+
+static struct file_operations js_fops =
+{
+	NULL,			/* js_lseek*/
+	js_read,		/* js_read */
+	NULL,			/* js_write*/
+	NULL,			/* js_readaddr*/
+	NULL,			/* js_select */
+	js_ioctl,		/* js_ioctl*/
+	NULL,			/* js_mmap */
+	js_open,		/* js_open*/
+	js_release,		/* js_release*/
+	NULL			/* js_fsync */
+};
+
+#ifdef MODULE
+
+#define joystick_init init_module
+
+void cleanup_module (void)
+{
+	if (unregister_chrdev (JOYSTICK_MAJOR, "joystick"))
+		printk ("joystick: cleanup_module failed\n");
+	release_region(JS_PORT, 1);
+}
+
+#endif /* MODULE */
+
+int joystick_init(void)
+{
+	int js_num;
+	int js_count;
+
+	if (check_region(JS_PORT, 1)) {
+		printk("js_init: port already in use\n");
+		return -EBUSY;
+	}
+
+	js_num = find_axes();
+	js_count = !!(js_num & 0x3) + !!(js_num & 0xC);
+
+
+	if (js_count == 0) 
+	{
+		printk("No joysticks found.\n");
+		return -ENODEV;
+		/* if the user boots the machine, which runs insmod, and THEN
+		   decides to hook up the joystick, well, then we do the wrong
+		   thing. But it's a good idea to avoid giving out a false sense
+		   of security by letting the module load otherwise. */
+	}
+
+	if (register_chrdev (JOYSTICK_MAJOR, "joystick", &js_fops)) {
+		printk ("Unable to get major=%d for joystick\n",
+					JOYSTICK_MAJOR);
+		return -EBUSY;
+	}
+	request_region(JS_PORT, 1, "joystick");
+		
+	for (js_num = 0; js_num < JS_MAX; js_num++)
+		  js_data[js_num].busy = JS_FALSE;
+	js_read_semaphore = 0;
+
+	printk (KERN_INFO "Found %d joystick%c.\n",
+			js_count,
+		    (js_num == 1) ? ' ' : 's');
+	return 0;
+}
+
diff -u --recursive --new-file v2.1.44/linux/drivers/char/lp.c linux/drivers/char/lp.c
--- v2.1.44/linux/drivers/char/lp.c	Thu May 29 21:53:05 1997
+++ linux/drivers/char/lp.c	Wed Jul 16 19:22:50 1997
@@ -724,7 +724,11 @@
   		return 0;
   
 	printk(KERN_INFO "lp: driver loaded but no devices found\n");
+#ifdef MODULE
+	return 0;
+#else	
 	return 1;
+#endif
 }
 
 #ifdef MODULE
diff -u --recursive --new-file v2.1.44/linux/drivers/char/mem.c linux/drivers/char/mem.c
--- v2.1.44/linux/drivers/char/mem.c	Mon Jun 16 16:35:55 1997
+++ linux/drivers/char/mem.c	Wed Jul 16 19:22:50 1997
@@ -20,6 +20,7 @@
 #include <linux/mm.h>
 #include <linux/random.h>
 #include <linux/init.h>
+#include <linux/joystick.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -134,8 +135,7 @@
 #endif
 	if (remap_page_range(vma->vm_start, offset, vma->vm_end - vma->vm_start, vma->vm_page_prot))
 		return -EAGAIN;
-	vma->vm_inode = inode;
-	atomic_inc(&inode->i_count);
+	vma->vm_dentry = dget(file->f_dentry);
 	return 0;
 }
 
@@ -532,6 +532,13 @@
 #ifdef CONFIG_SOUND
 	soundcard_init();
 #endif
+#ifdef CONFIG_JOYSTICK
+	/*
+	 *	Some joysticks only appear when the soundcard they are
+	 *	connected too is confgured. Keep the sound/joystick ordering.
+	 */
+	joystick_init();
+#endif	
 #if CONFIG_QIC02_TAPE
 	qic02_tape_init();
 #endif
diff -u --recursive --new-file v2.1.44/linux/drivers/char/misc.c linux/drivers/char/misc.c
--- v2.1.44/linux/drivers/char/misc.c	Mon Jun 16 16:35:55 1997
+++ linux/drivers/char/misc.c	Wed Jul 16 19:22:50 1997
@@ -215,6 +215,9 @@
 #ifdef CONFIG_SUN_MOUSE
 	sun_mouse_init();
 #endif
+#ifdef CONFIG_PC110_PAD
+	pc110pad_init();
+#endif
 /*
  *	Only one watchdog can succeed. We probe the pcwatchdog first,
  *	then the wdt cards and finally the software watchdog which always
diff -u --recursive --new-file v2.1.44/linux/drivers/char/n_tty.c linux/drivers/char/n_tty.c
--- v2.1.44/linux/drivers/char/n_tty.c	Thu Jun 26 12:33:38 1997
+++ linux/drivers/char/n_tty.c	Wed Jul 16 19:22:50 1997
@@ -706,7 +706,7 @@
 		return;
 	
 	tty->icanon = (L_ICANON(tty) != 0);
-	if (tty->flags & (1<<TTY_HW_COOK_IN)) {
+	if (test_bit(TTY_HW_COOK_IN, &tty->flags)) {
 		tty->raw = 1;
 		tty->real_raw = 1;
 		return;
@@ -854,7 +854,7 @@
 	/* NOTE: not yet done after every sleep pending a thorough
 	   check of the logic of this change. -- jlc */
 	/* don't stop on /dev/console */
-	if (file->f_inode->i_rdev != CONSOLE_DEV &&
+	if (file->f_dentry->d_inode->i_rdev != CONSOLE_DEV &&
 	    current->tty == tty) {
 		if (tty->pgrp <= 0)
 			printk("read_chan: tty->pgrp <= 0!\n");
@@ -912,7 +912,7 @@
 			tty->minimum_to_wake = (minimum - (b - buf));
 		
 		if (!input_available_p(tty, 0)) {
-			if (tty->flags & (1 << TTY_OTHER_CLOSED)) {
+			if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
 				retval = -EIO;
 				break;
 			}
@@ -1013,7 +1013,7 @@
 	int retval = 0;
 
 	/* Job control check -- must be done at start (POSIX.1 7.1.1.4). */
-	if (L_TOSTOP(tty) && file->f_inode->i_rdev != CONSOLE_DEV) {
+	if (L_TOSTOP(tty) && file->f_dentry->d_inode->i_rdev != CONSOLE_DEV) {
 		retval = tty_check_change(tty);
 		if (retval)
 			return retval;
@@ -1030,7 +1030,7 @@
 			retval = -EIO;
 			break;
 		}
-		if (O_OPOST(tty) && !(tty->flags & (1<<TTY_HW_COOK_OUT))) {
+		if (O_OPOST(tty) && !(test_bit(TTY_HW_COOK_OUT, &tty->flags))) {
 			while (nr > 0) {
 				num = opost_block(tty, b, nr);
 				b += num;
@@ -1072,7 +1072,7 @@
 		mask |= POLLIN | POLLRDNORM;
 	if (tty->packet && tty->link->ctrl_status)
 		mask |= POLLPRI | POLLIN | POLLRDNORM;
-	if (tty->flags & (1 << TTY_OTHER_CLOSED))
+	if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
 		mask |= POLLHUP;
 	if (tty_hung_up_p(file))
 		mask |= POLLHUP;
diff -u --recursive --new-file v2.1.44/linux/drivers/char/pc110pad.c linux/drivers/char/pc110pad.c
--- v2.1.44/linux/drivers/char/pc110pad.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/pc110pad.c	Wed Jul 16 19:22:50 1997
@@ -0,0 +1,690 @@
+/*
+ *	Linux driver for the PC110 pad
+ *
+ *	The pad provides triples of data. The first byte has
+ *	0x80=bit 8 X, 0x01=bit 7 X, 0x08=bit 8 Y, 0x01=still down
+ *	The second byte is bits 0-6 X
+ *	The third is bits 0-6 Y
+ *
+ *	This is read internally and used to synthesize a stream of
+ *	triples in the form expected from a PS/2 device.
+ *
+ *	0.0 1997-05-16 Alan Cox <alan@cymru.net> - Pad reader
+ *	0.1 1997-05-19 Robin O'Leary <robin@acm.org> - PS/2 emulation
+ *	0.2 1997-06-03 Robin O'Leary <robin@acm.org> - tap gesture
+ *	0.3 1997-06-27 Alan Cox <alan@cymru.net> - 2.1 commit
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/busmouse.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/miscdevice.h>
+#include <linux/ptrace.h>
+#include <linux/poll.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+
+#include <asm/signal.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+#include "pc110pad.h"
+
+
+static struct pc110pad_params default_params = {
+	PC110PAD_PS2,	/* read mode */
+	50 MS,		/* bounce interval */
+	200 MS,		/* tap interval */
+	10,		/* IRQ */
+	0x15E0,		/* I/O port */
+};
+
+
+static struct pc110pad_params current_params;
+
+
+/* driver/filesystem interface management */
+static struct wait_queue *queue;
+static struct fasync_struct *asyncptr;
+static int active=0;	/* number of concurrent open()s */
+
+
+/*
+ * Utility to reset a timer to go off some time in the future.
+ */
+
+static void set_timer_callback(struct timer_list *timer, int ticks)
+{
+	del_timer(timer);
+	timer->expires = jiffies+ticks;
+	add_timer(timer);
+}
+
+
+/*
+ * Take care of letting any waiting processes know that
+ * now would be a good time to do a read().  Called
+ * whenever a state transition occurs, real or synthetic.
+ */
+ 
+static void wake_readers(void)
+{
+	wake_up_interruptible(&queue);
+	if(asyncptr)
+		kill_fasync(asyncptr, SIGIO);
+}
+
+
+/*****************************************************************************/
+/*
+ * Deal with the messy business of synthesizing button tap and drag
+ * events.
+ *
+ * Exports:
+ *	notify_pad_up_down()
+ *		Must be called whenever debounced pad up/down state changes.
+ *	button_pending
+ *		Flag is set whenever read_button() has new values
+ *		to return.
+ *	read_button()
+ *		Obtains the current synthetic mouse button state.
+ */
+
+/*
+ * These keep track of up/down transitions needed to generate the
+ * synthetic mouse button events.  While recent_transition is set,
+ * up/down events cause transition_count to increment.  tap_timer
+ * turns off the recent_transition flag and may cause some synthetic
+ * up/down mouse events to be created by incrementing synthesize_tap.
+ */
+ 
+static int button_pending=0;
+static int recent_transition=0;
+static int transition_count=0;
+static int synthesize_tap=0;
+static void tap_timeout(unsigned long data);
+static struct timer_list tap_timer = { NULL, NULL, 0, 0, tap_timeout };
+
+
+/*
+ * This callback goes off a short time after an up/down transition;
+ * before it goes off, transitions will be considered part of a
+ * single PS/2 event and counted in transition_count.  Once the
+ * timeout occurs the recent_transition flag is cleared and
+ * any synthetic mouse up/down events are generated.
+ */
+ 
+static void tap_timeout(unsigned long data)
+{
+	if(!recent_transition)
+	{
+		printk("pc110pad: tap_timeout but no recent transition!\n");
+	}
+	if( transition_count==2 || transition_count==4 || transition_count==6 )
+	{
+		synthesize_tap+=transition_count;
+		button_pending = 1;
+		wake_readers();
+	}
+	recent_transition=0;
+}
+
+
+/*
+ * Called by the raw pad read routines when a (debounced) up/down
+ * transition is detected.
+ */
+ 
+void notify_pad_up_down(void)
+{
+	if(recent_transition)
+	{
+		transition_count++;
+	}
+	else
+	{
+		transition_count=1;
+		recent_transition=1;
+	}
+	set_timer_callback(&tap_timer, current_params.tap_interval);
+
+	/* changes to transition_count can cause reported button to change */
+	button_pending = 1;
+	wake_readers();
+}
+
+
+static void read_button(int *b)
+{
+	if(synthesize_tap)
+	{
+		*b=--synthesize_tap & 1;
+	}
+	else
+	{
+		*b=(!recent_transition && transition_count==3);	/* drag */
+	}
+	button_pending=(synthesize_tap>0);
+}
+
+
+/*****************************************************************************/
+/*
+ * Read pad absolute co-ordinates and debounced up/down state.
+ *
+ * Exports:
+ *	pad_irq()
+ *		Function to be called whenever the pad signals
+ *		that it has new data available.
+ *	read_raw_pad()
+ *		Returns the most current pad state.
+ *	xy_pending
+ *		Flag is set whenever read_raw_pad() has new values
+ *		to return.
+ * Imports:
+ *	wake_readers()
+ *		Called when movement occurs.
+ *	notify_pad_up_down()
+ *		Called when debounced up/down status changes.
+ */
+
+/*
+ * These are up/down state and absolute co-ords read directly from pad 
+ */
+
+static int raw_data[3];
+static int raw_data_count=0;
+static int raw_x=0, raw_y=0;	/* most recent absolute co-ords read */
+static int raw_down=0;		/* raw up/down state */
+static int debounced_down=0;	/* up/down state after debounce processing */
+static enum { NO_BOUNCE, JUST_GONE_UP, JUST_GONE_DOWN } bounce=NO_BOUNCE;
+				/* set just after an up/down transition */
+static int xy_pending=0;	/* set if new data have not yet been read */
+
+/* 
+ * Timer goes off a short while after an up/down transition and copies
+ * the value of raw_down to debounced_down.
+ */
+ 
+static void bounce_timeout(unsigned long data);
+static struct timer_list bounce_timer = { NULL, NULL, 0, 0, bounce_timeout };
+
+
+static void bounce_timeout(unsigned long data)
+{
+	/*
+	 * No further up/down transitions happened within the
+	 * bounce period, so treat this as a genuine transition.
+	 */
+	switch(bounce)
+	{
+		case NO_BOUNCE:
+		{
+			/*
+			 * Strange; the timer callback should only go off if
+			 * we were expecting to do bounce processing!
+			 */
+			printk("pc110pad, bounce_timeout: bounce flag not set!\n");
+			break;
+		}
+		case JUST_GONE_UP:
+		{
+			/*
+			 * The last up we spotted really was an up, so set
+			 * debounced state the same as raw state.
+			 */
+			bounce=NO_BOUNCE;
+			if(debounced_down==raw_down)
+			{
+				printk("pc110pad, bounce_timeout: raw already debounced!\n");
+			}
+			debounced_down=raw_down;
+
+			notify_pad_up_down();
+			break;
+		}
+		case JUST_GONE_DOWN:
+		{
+			/*
+			 * We don't debounce down events, but we still time
+			 * out soon after one occurs so we can avoid the (x,y)
+			 * skittering that sometimes happens.
+			 */
+			bounce=NO_BOUNCE;
+			break;
+		}
+	}
+}
+
+
+/*
+ * Callback when pad's irq goes off; copies values in to raw_* globals;
+ * initiates debounce processing.
+ */
+static void pad_irq(int irq, void *ptr, struct pt_regs *regs)
+{
+
+	/* Obtain byte from pad and prime for next byte */
+	{
+		int value=inb_p(current_params.io);
+		int handshake=inb_p(current_params.io+2);
+		outb_p(handshake | 1, current_params.io+2);
+		outb_p(handshake &~1, current_params.io+2);
+		inb_p(0x64);
+
+		raw_data[raw_data_count++]=value;
+	}
+
+	if(raw_data_count==3)
+	{
+		int new_down=raw_data[0]&0x01;
+		int new_x=raw_data[1];
+		int new_y=raw_data[2];
+		if(raw_data[0]&0x10) new_x+=128;
+		if(raw_data[0]&0x80) new_x+=256;
+		if(raw_data[0]&0x08) new_y+=128;
+
+		if( (raw_x!=new_x) || (raw_y!=new_y) )
+		{
+			raw_x=new_x;
+			raw_y=new_y;
+			xy_pending=1;
+		}
+
+		if(new_down != raw_down)
+		{
+			/* Down state has changed.  raw_down always holds
+			 * the most recently observed state.
+			 */
+			raw_down=new_down;
+
+			/* Forget any earlier bounce processing */
+			if(bounce)
+			{
+				del_timer(&bounce_timer);
+				bounce=NO_BOUNCE;
+			}
+
+			if(new_down)
+			{
+				if(debounced_down)
+				{
+					/* pad gone down, but we were reporting
+					 * it down anyway because we suspected
+					 * (correctly) that the last up was just
+					 * a bounce
+					 */
+				}
+				else
+				{
+					bounce=JUST_GONE_DOWN;
+					set_timer_callback(&bounce_timer,
+						current_params.bounce_interval);
+					/* start new stroke/tap */
+					debounced_down=new_down;
+					notify_pad_up_down();
+				}
+			}
+			else /* just gone up */
+			{
+				if(recent_transition)
+				{
+					/* early bounces are probably part of
+					 * a multi-tap gesture, so process
+					 * immediately
+					 */
+					debounced_down=new_down;
+					notify_pad_up_down();
+				}
+				else
+				{
+					/* don't trust it yet */
+					bounce=JUST_GONE_UP;
+					set_timer_callback(&bounce_timer,
+						current_params.bounce_interval);
+				}
+			}
+		}
+		wake_readers();
+		raw_data_count=0;
+	}
+}
+
+
+static void read_raw_pad(int *down, int *debounced, int *x, int *y)
+{
+	disable_irq(current_params.irq);
+	{
+		*down=raw_down;
+		*debounced=debounced_down;
+		*x=raw_x;
+		*y=raw_y;
+		xy_pending = 0;
+	}
+	enable_irq(current_params.irq);
+}
+
+/*****************************************************************************/
+/*
+ * Filesystem interface
+ */
+
+/* 
+ * Read returns byte triples, so we need to keep track of
+ * how much of a triple has been read.  This is shared across
+ * all processes which have this device open---not that anything
+ * will make much sense in that case.
+ */
+static int read_bytes[3];
+static int read_byte_count=0;
+
+
+
+static void sample_raw(int d[3])
+{
+	d[0]=raw_data[0];
+	d[1]=raw_data[1];
+	d[2]=raw_data[2];
+}
+
+
+static void sample_rare(int d[3])
+{
+	int thisd, thisdd, thisx, thisy;
+
+	read_raw_pad(&thisd, &thisdd, &thisx, &thisy);
+
+	d[0]=(thisd?0x80:0)
+	   | (thisx/256)<<4
+	   | (thisdd?0x08:0)
+	   | (thisy/256)
+	;
+	d[1]=thisx%256;
+	d[2]=thisy%256;
+}
+
+
+static void sample_debug(int d[3])
+{
+	int thisd, thisdd, thisx, thisy;
+	int b;
+	cli();
+	read_raw_pad(&thisd, &thisdd, &thisx, &thisy);
+	d[0]=(thisd?0x80:0) | (thisdd?0x40:0) | bounce;
+	d[1]=(recent_transition?0x80:0)+transition_count;
+	read_button(&b);
+	d[2]=(synthesize_tap<<4) | (b?0x01:0);
+	sti();
+}
+
+
+static void sample_ps2(int d[3])
+{
+	static int lastx, lasty, lastd;
+
+	int thisd, thisdd, thisx, thisy;
+	int dx, dy, b;
+
+	/*
+	 * Obtain the current mouse parameters and limit as appropriate for
+	 * the return data format.  Interrupts are only disabled while 
+	 * obtaining the parameters, NOT during the puts_fs_byte() calls,
+	 * so paging in put_user() does not affect mouse tracking.
+	 */
+	read_raw_pad(&thisd, &thisdd, &thisx, &thisy);
+	read_button(&b);
+
+	/* Now compare with previous readings.  Note that we use the
+	 * raw down flag rather than the debounced one.
+	 */
+	if( (thisd && !lastd) /* new stroke */
+	 || (bounce!=NO_BOUNCE) )
+	{
+		dx=0;
+		dy=0;
+	}
+	else
+	{
+		dx =  (thisx-lastx);
+		dy = -(thisy-lasty);
+	}
+	lastx=thisx;
+	lasty=thisy;
+	lastd=thisd;
+
+/*
+	d[0]= ((dy<0)?0x20:0)
+	    | ((dx<0)?0x10:0)
+	    | 0x08
+	    | (b? 0x01:0x00)
+	;
+*/
+	d[0]= ((dy<0)?0x20:0)
+	    | ((dx<0)?0x10:0)
+	    | (b? 0x00:0x08)
+	;
+	d[1]=dx;
+	d[2]=dy;
+}
+
+
+
+static int fasync_pad(struct inode *inode, struct file *filp, int on)
+{
+	int retval;
+
+	retval = fasync_helper(inode, filp, on, &asyncptr);
+	if (retval < 0)
+		return retval;
+	return 0;
+}
+
+
+/*
+ * close access to the pad
+ */
+static int close_pad(struct inode * inode, struct file * file)
+{
+	fasync_pad(inode, file, 0);
+	if (--active)
+		return;
+	outb(0x30, current_params.io+2);	/* switch off digitiser */
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+
+/*
+ * open access to the pad
+ */
+static int open_pad(struct inode * inode, struct file * file)
+{
+	if (active++)
+		return 0;
+	MOD_INC_USE_COUNT;
+
+	cli();
+	outb(0x30, current_params.io+2);	/* switch off digitiser */
+	pad_irq(0,0,0);		/* read to flush any pending bytes */
+	pad_irq(0,0,0);		/* read to flush any pending bytes */
+	pad_irq(0,0,0);		/* read to flush any pending bytes */
+	outb(0x38, current_params.io+2);	/* switch on digitiser */
+	current_params = default_params;
+	raw_data_count=0;		/* re-sync input byte counter */
+	read_byte_count=0;		/* re-sync output byte counter */
+	button_pending=0;
+	recent_transition=0;
+	transition_count=0;
+	synthesize_tap=0;
+	del_timer(&bounce_timer);
+	del_timer(&tap_timer);
+	sti();
+
+	return 0;
+}
+
+
+/*
+ * writes are disallowed
+ */
+static long write_pad(struct inode * inode, struct file * file, const char * buffer, unsigned long  count)
+{
+	return -EINVAL;
+}
+
+
+void new_sample(int d[3])
+{
+	switch(current_params.mode)
+	{
+		case PC110PAD_RAW:	sample_raw(d);		break;
+		case PC110PAD_RARE:	sample_rare(d);		break;
+		case PC110PAD_DEBUG:	sample_debug(d);	break;
+		case PC110PAD_PS2:	sample_ps2(d);		break;
+	}
+}
+
+
+/*
+ * Read pad data.  Currently never blocks.
+ */
+static long read_pad(struct inode * inode, struct file * file, char * buffer, unsigned long count)
+{
+	int r;
+
+	for(r=0; r<count; r++)
+	{
+		if(!read_byte_count)
+			new_sample(read_bytes);
+		if(put_user(read_bytes[read_byte_count], buffer+r))
+			return -EFAULT;
+		read_byte_count = (read_byte_count+1)%3;
+	}
+	return r;
+}
+
+
+/*
+ * select for pad input
+ */
+
+static unsigned int pad_poll(struct file *file, poll_table * wait)
+{
+	poll_wait(&queue, wait);
+    	if(button_pending || xy_pending)
+		return POLLIN | POLLRDNORM;
+	return 0;
+}
+
+
+static int pad_ioctl(struct inode *inode, struct file * file,
+	unsigned int cmd, unsigned long arg)
+{
+	struct pc110pad_params new;
+
+	if (!inode)
+		return -EINVAL;
+		
+	switch (cmd) {
+	case PC110PADIOCGETP:
+		new = current_params;
+		if(copy_to_user((void *)arg, &new, sizeof(new)))
+			return -EFAULT;
+		return 0;
+
+	case PC110PADIOCSETP:
+		if(copy_from_user(&new, (void *)arg, sizeof(new)))
+			return -EFAULT;
+
+		if( (new.mode<PC110PAD_RAW)
+		 || (new.mode>PC110PAD_PS2)
+		 || (new.bounce_interval<0)
+		 || (new.tap_interval<0)
+		)
+			return -EINVAL;
+
+		current_params.mode	= new.mode;
+		current_params.bounce_interval	= new.bounce_interval;
+		current_params.tap_interval	= new.tap_interval;
+		return 0;
+	}
+	return -ENOIOCTLCMD;
+}
+
+
+static struct file_operations pad_fops = {
+	NULL,		/* pad_seek */
+	read_pad,
+	write_pad,
+	NULL, 		/* pad_readdir */
+	pad_poll,
+	pad_ioctl,
+	NULL,		/* pad_mmap */
+	open_pad,
+	close_pad,
+	NULL,		/* fsync */
+	fasync_pad,
+	NULL,		/* check_media_change */
+	NULL,		/* revalidate */
+	NULL		/* lock */
+};
+
+
+static struct miscdevice pc110_pad = {
+	PC110PAD_MINOR, "pc110 pad", &pad_fops
+};
+
+
+static int pc110pad_init(void)
+{
+	current_params = default_params;
+
+	if(request_irq(current_params.irq, pad_irq, 0, "pc110pad", 0))
+	{
+		printk("pc110pad: Unable to get IRQ.\n");
+		return -EBUSY;
+	}
+	if(check_region(current_params.io, 4))
+	{
+		printk("pc110pad: I/O area in use.\n");
+		free_irq(current_params.irq,0);
+		return -EBUSY;
+	}
+	request_region(current_params.io, 4, "pc110pad");
+	printk("PC110 digitizer pad at 0x%X, irq %d.\n",
+		current_params.io,current_params.irq);
+	misc_register(&pc110_pad);
+	outb(0x30, current_params.io+2);	/* switch off digitiser */
+	
+	return 0;
+}
+
+#ifdef MODULE
+
+static void pc110pad_unload(void)
+{
+	outb(0x30, current_params.io+2);	/* switch off digitiser */
+	if(current_params.irq)
+		free_irq(current_params.irq, 0);
+	current_params.irq=0;
+	release_region(current_params.io, 4);
+	misc_deregister(&pc110_pad);
+}
+
+
+
+int init_module(void)
+{
+	return pc110pad_init();
+}
+
+void cleanup_module(void)
+{
+	pc110pad_unload();
+}
+#endif
diff -u --recursive --new-file v2.1.44/linux/drivers/char/pc110pad.h linux/drivers/char/pc110pad.h
--- v2.1.44/linux/drivers/char/pc110pad.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/pc110pad.h	Wed Jul 16 19:22:50 1997
@@ -0,0 +1,31 @@
+#ifndef _PC110PAD_H
+#define _PC110PAD_H
+
+#include <linux/ioctl.h>
+
+enum pc110pad_mode {
+	PC110PAD_RAW,		/* bytes as they come out of the hardware */
+	PC110PAD_RARE,		/* debounced up/down and absolute x,y */
+	PC110PAD_DEBUG,		/* up/down, debounced, transitions, button */
+	PC110PAD_PS2,		/* ps2 relative (default) */ 
+};
+
+
+struct pc110pad_params {
+	enum pc110pad_mode mode;
+	int	bounce_interval;
+	int	tap_interval;
+	int	irq;
+	int	io;
+};
+
+#define MS *HZ/1000
+
+/* Appears as device major=10 (MISC), minor=PC110_PAD */
+
+#define PC110PAD_IOCTL_TYPE		0x9a
+
+#define PC110PADIOCGETP _IOR(PC110PAD_IOCTL_TYPE, 0, struct pc110pad_params)
+#define PC110PADIOCSETP _IOR(PC110PAD_IOCTL_TYPE, 1, struct pc110pad_params)
+ 
+#endif /* _PC110PAD_H */
diff -u --recursive --new-file v2.1.44/linux/drivers/char/psaux.c linux/drivers/char/psaux.c
--- v2.1.44/linux/drivers/char/psaux.c	Fri Jul  4 23:33:56 1997
+++ linux/drivers/char/psaux.c	Thu Jul 10 17:06:47 1997
@@ -168,6 +168,11 @@
 	outb_p(val, KBD_DATA_REG);			    /* Write data */
 }
 
+/*
+ * Write to device & handle returned ack
+ */
+
+#ifdef INITIALIZE_DEVICE
 __initfunc(static void aux_write_dev_nosleep(int val))
 {
 	poll_aux_status_nosleep();
@@ -176,11 +181,6 @@
 	outb_p(val, KBD_DATA_REG);
 }
 
-/*
- * Write to device & handle returned ack
- */
-
-#ifdef INITIALIZE_DEVICE
 __initfunc(static int aux_write_ack(int val))
 {
 	aux_write_dev_nosleep(val);
diff -u --recursive --new-file v2.1.44/linux/drivers/char/random.c linux/drivers/char/random.c
--- v2.1.44/linux/drivers/char/random.c	Mon Jul  7 08:24:28 1997
+++ linux/drivers/char/random.c	Tue Jul  8 16:28:45 1997
@@ -1125,8 +1125,7 @@
 	 * update the access time.
 	 */
 	if (inode && count != 0) {
-		inode->i_atime = CURRENT_TIME;
-		inode->i_dirt = 1;
+		UPDATE_ATIME(inode);
 	}
 	
 	return (count ? count : retval);
@@ -1182,7 +1181,7 @@
 	}
 	if ((ret > 0) && inode) {
 		inode->i_mtime = CURRENT_TIME;
-		inode->i_dirt = 1;
+		mark_inode_dirty(inode);
 	}
 	return ret;
 }
diff -u --recursive --new-file v2.1.44/linux/drivers/char/rtc.c linux/drivers/char/rtc.c
--- v2.1.44/linux/drivers/char/rtc.c	Mon Jul  7 08:24:28 1997
+++ linux/drivers/char/rtc.c	Wed Jul 16 19:22:50 1997
@@ -180,7 +180,9 @@
 		data = rtc_irq_data;
 		rtc_irq_data = 0;
 		restore_flags(flags);
-		retval = put_user(data, (unsigned long *)buf) ?: sizeof(unsigned long);
+		retval = put_user(data, (unsigned long *)buf); 
+		if (!retval)
+			retval = sizeof(unsigned long); 
 	}
 
 	current->state = TASK_RUNNING;
@@ -262,7 +264,6 @@
 			 * "don't care" or "match all". Only the tm_hour,
 			 * tm_min and tm_sec are used.
 			 */
-			int retval;
 			unsigned char hrs, min, sec;
 			struct rtc_time alm_tm;
 
@@ -305,7 +306,6 @@
 		}
 		case RTC_SET_TIME:	/* Set the RTC */
 		{
-			int retval;
 			struct rtc_time rtc_tm;
 			unsigned char mon, day, hrs, min, sec, leap_yr;
 			unsigned char save_control, save_freq_select;
@@ -418,7 +418,7 @@
 		default:
 			return -EINVAL;
 	}
-	return copy_to_user(arg, &wtime, sizeof wtime) ? -EFAULT : 0;
+	return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0;
 }
 
 /*
diff -u --recursive --new-file v2.1.44/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- v2.1.44/linux/drivers/char/tty_io.c	Sat Jun 28 10:31:36 1997
+++ linux/drivers/char/tty_io.c	Wed Jul 16 19:22:50 1997
@@ -373,13 +373,15 @@
 	for (filp = inuse_filps; filp; filp = filp->f_next) {
 		if (filp->private_data != tty)
 			continue;
-		if (!filp->f_inode)
+		if (!filp->f_dentry)
 			continue;
-		if (filp->f_inode->i_rdev == CONSOLE_DEV)
+		if (!filp->f_dentry->d_inode)
+			continue;
+		if (filp->f_dentry->d_inode->i_rdev == CONSOLE_DEV)
 			continue;
 		if (filp->f_op != &tty_fops)
 			continue;
-		tty_fasync(filp->f_inode, filp, 0);
+		tty_fasync(filp->f_dentry->d_inode, filp, 0);
 		filp->f_op = fops;
 	}
 	
@@ -387,7 +389,7 @@
 		tty->ldisc.flush_buffer(tty);
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+	if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) &&
 	    tty->ldisc.write_wakeup)
 		(tty->ldisc.write_wakeup)(tty);
 	wake_up_interruptible(&tty->write_wait);
@@ -536,7 +538,7 @@
 	}
 	if (tty->driver.start)
 		(tty->driver.start)(tty);
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+	if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) &&
 	    tty->ldisc.write_wakeup)
 		(tty->ldisc.write_wakeup)(tty);
 	wake_up_interruptible(&tty->write_wait);
@@ -551,7 +553,7 @@
 	tty = (struct tty_struct *)file->private_data;
 	if (tty_paranoia_check(tty, inode->i_rdev, "tty_read"))
 		return -EIO;
-	if (!tty || (tty->flags & (1 << TTY_IO_ERROR)))
+	if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags)))
 		return -EIO;
 
 	/* This check not only needs to be done before reading, but also
@@ -633,7 +635,7 @@
 		tty = (struct tty_struct *)file->private_data;
 	if (tty_paranoia_check(tty, inode->i_rdev, "tty_write"))
 		return -EIO;
-	if (!tty || !tty->driver.write || (tty->flags & (1 << TTY_IO_ERROR)))
+	if (!tty || !tty->driver.write || (test_bit(TTY_IO_ERROR, &tty->flags)))
 		return -EIO;
 #if 0
 	if (!is_console && L_TOSTOP(tty) && (tty->pgrp > 0) &&
@@ -822,7 +824,7 @@
 	 * opens on a pty master.
 	 */
 fast_track:
-	if (tty->flags & (1 << TTY_CLOSING)) {
+	if (test_bit(TTY_CLOSING, &tty->flags)) {
 		retval = -EIO;
 		goto end_init;
 	}
@@ -919,12 +921,12 @@
 	int	idx;
 	
 	tty = (struct tty_struct *)filp->private_data;
-	if (tty_paranoia_check(tty, filp->f_inode->i_rdev, "release_dev"))
+	if (tty_paranoia_check(tty, filp->f_dentry->d_inode->i_rdev, "release_dev"))
 		return;
 
 	check_tty_count(tty, "release_dev");
 
-	tty_fasync(filp->f_inode, filp, 0);
+	tty_fasync(filp->f_dentry->d_inode, filp, 0);
 
 	idx = MINOR(tty->device) - tty->driver.minor_start;
 	pty_master = (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
@@ -1069,9 +1071,9 @@
 	 * to close, and TTY_CLOSING makes sure we can't be reopened.
 	 */
 	if(tty_closing)
-		tty->flags |= (1 << TTY_CLOSING);
+		set_bit(TTY_CLOSING, &tty->flags);
 	if(o_tty_closing)
-		o_tty->flags |= (1 << TTY_CLOSING);
+		set_bit(TTY_CLOSING, &o_tty->flags);
 
 	/*
 	 * If _either_ side is closing, make sure there aren't any
@@ -1248,7 +1250,7 @@
 	struct tty_struct * tty;
 
 	tty = (struct tty_struct *)filp->private_data;
-	if (tty_paranoia_check(tty, filp->f_inode->i_rdev, "tty_poll"))
+	if (tty_paranoia_check(tty, filp->f_dentry->d_inode->i_rdev, "tty_poll"))
 		return 0;
 
 	if (tty->ldisc.poll)
diff -u --recursive --new-file v2.1.44/linux/drivers/net/8390.c linux/drivers/net/8390.c
--- v2.1.44/linux/drivers/net/8390.c	Wed Apr 23 19:01:18 1997
+++ linux/drivers/net/8390.c	Sun Jul 13 09:28:11 1997
@@ -186,6 +186,7 @@
 
     /* Mask interrupts from the ethercard. */
     outb_p(0x00, e8390_base + EN0_IMR);
+    synchronize_irq();
     if (dev->interrupt) {
 	printk("%s: Tx request while isr active.\n",dev->name);
 	outb_p(ENISR_ALL, e8390_base + EN0_IMR);
diff -u --recursive --new-file v2.1.44/linux/drivers/net/Config.in linux/drivers/net/Config.in
--- v2.1.44/linux/drivers/net/Config.in	Mon Jul  7 08:19:59 1997
+++ linux/drivers/net/Config.in	Wed Jul 16 19:22:50 1997
@@ -84,6 +84,7 @@
     tristate 'Digi Intl. RightSwitch SE-X support' CONFIG_DGRS
     tristate 'EtherExpressPro/100 support' CONFIG_EEXPRESS_PRO100
     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      tristate 'TI ThunderLAN support (EXPERIMENTAL)' CONFIG_TLAN
       tristate 'Racal-Interlan EISA ES3210 support (EXPERIMENTAL)' CONFIG_ES3210
       bool 'Zenith Z-Note support (EXPERIMENTAL)' CONFIG_ZNET
     fi
@@ -151,12 +152,14 @@
       bool 'Soundmodem support for 2400 baud AFSK modulation (8MHz crystal)' CONFIG_SOUNDMODEM_AFSK2400_8
       bool 'Soundmodem support for 4800 baud HAPN-1 modulation' CONFIG_SOUNDMODEM_HAPN4800
       bool 'Soundmodem support for 9600 baud FSK G3RUH modulation' CONFIG_SOUNDMODEM_FSK9600
-      if [ -f drivers/net/soundmodem/sm_afsk2666.c ]; then
-        bool 'Soundmodem support for 2666 baud AFSK modulation' CONFIG_SOUNDMODEM_AFSK2666
-      fi
-      if [ -f drivers/net/soundmodem/sm_psk4800.c ]; then
-        bool 'Soundmodem support for 4800 baud PSK modulation' CONFIG_SOUNDMODEM_PSK4800
-      fi
+# if [ -f doesn't work with xconfig. Enable it again when the drivers are really
+# included.
+#      if [ -f drivers/net/soundmodem/sm_afsk2666.c ]; then
+#        bool 'Soundmodem support for 2666 baud AFSK modulation' CONFIG_SOUNDMODEM_AFSK2666
+#      fi
+#      if [ -f drivers/net/soundmodem/sm_psk4800.c ]; then
+#        bool 'Soundmodem support for 4800 baud PSK modulation' CONFIG_SOUNDMODEM_PSK4800
+#      fi
     fi
   fi
   tristate 'STRIP (Metricom starmode radio IP)' CONFIG_STRIP
diff -u --recursive --new-file v2.1.44/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v2.1.44/linux/drivers/net/Makefile	Thu Jun 26 12:33:39 1997
+++ linux/drivers/net/Makefile	Wed Jul 16 19:22:50 1997
@@ -391,6 +391,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_TLAN),y)
+L_OBJS += tlan.o
+else
+  ifeq ($(CONFIG_TLAN),m)
+  M_OBJS += tlan.o
+  endif
+endif
+
 ifeq ($(CONFIG_ZNET),y)
 L_OBJS += znet.o
 endif
@@ -793,7 +801,7 @@
 sdladrv.o: sdladrv.c CONFIG
 
 wanpipe.o: $(WANPIPE_OBJS)
-	ld -r -o $@ $^
+	ld -r -o $@ $(WANPIPE_OBJS)
 
 sdlamain.o: sdlamain.c CONFIG
 
diff -u --recursive --new-file v2.1.44/linux/drivers/net/README.wanpipe linux/drivers/net/README.wanpipe
--- v2.1.44/linux/drivers/net/README.wanpipe	Sun Feb  2 05:18:36 1997
+++ linux/drivers/net/README.wanpipe	Wed Jul 16 19:22:50 1997
@@ -1,10 +1,10 @@
 ------------------------------------------------------------------------------
 WANPIPE(tm) Multiprotocol WAN Driver for Linux WAN Router
 ------------------------------------------------------------------------------
-Release 3.0.0
-December 31, 1996
+Release 3.1.0
+January 30, 1997
 Author: Gene Kozin <genek@compuserve.com>
-Copyright (c) 1995-1996 Sangoma Technologies Inc.
+Copyright (c) 1995-1997 Sangoma Technologies Inc.
 ------------------------------------------------------------------------------
 
 INTRODUCTION
@@ -80,6 +80,12 @@
 
 
 REVISION HISTORY
+
+3.1.0	January 30, 1997
+
+	o Implemented IOCTL for executing adapter commands.
+	o Fixed a bug in frame relay code causing driver configured as a FR
+	  switch to be stuck in WAN_DISCONNECTED mode.
 
 3.0.0	December 31, 1996
 
diff -u --recursive --new-file v2.1.44/linux/drivers/net/Space.c linux/drivers/net/Space.c
--- v2.1.44/linux/drivers/net/Space.c	Thu Jun 26 12:33:39 1997
+++ linux/drivers/net/Space.c	Wed Jul 16 19:22:50 1997
@@ -89,6 +89,7 @@
 extern int a2065_probe(struct device *);
 extern int ariadne_probe(struct device *);
 extern int hydra_probe(struct device *);
+extern int tlan_probe(struct device *);
 extern int cs89x0_probe(struct device *dev);
 
 /* Detachable devices ("pocket adaptors") */
@@ -241,6 +242,9 @@
 #endif
 #ifdef CONFIG_SUNLANCE
 	&& sparc_lance_probe(dev)
+#endif
+#ifdef CONFIG_TLAN
+	&& tlan_probe(dev)
 #endif
 #ifdef CONFIG_HAPPYMEAL
 	&& happy_meal_probe(dev)
diff -u --recursive --new-file v2.1.44/linux/drivers/net/cops.c linux/drivers/net/cops.c
--- v2.1.44/linux/drivers/net/cops.c	Mon Jul  7 08:19:59 1997
+++ linux/drivers/net/cops.c	Wed Jul 16 19:22:50 1997
@@ -40,6 +40,7 @@
  *	  the driver figure it out.
  */
 
+#include <linux/config.h>
 #ifdef MODULE
 #include <linux/module.h>
 #include <linux/version.h>
diff -u --recursive --new-file v2.1.44/linux/drivers/net/ibmtr.c linux/drivers/net/ibmtr.c
--- v2.1.44/linux/drivers/net/ibmtr.c	Sat May 24 09:10:23 1997
+++ linux/drivers/net/ibmtr.c	Wed Jul 16 19:22:50 1997
@@ -55,7 +55,10 @@
  *	+ completed multiple adapter support. (November 20 1996)
  *	+ implemented csum_partial_copy in tr_rx and increased receive 
  *        buffer size and count. Minor fixes. (March 15, 1997)
-*/
+ *
+ *	Changes by Christopher Turcksin <wabbit@rtfc.demon.co.uk>
+ *	+ Now compiles ok as a module again.
+ */
 
 #ifdef PCMCIA
 #define MODULE
@@ -163,9 +166,9 @@
 
 int		ibmtr_probe(struct device *dev);
 static int	ibmtr_probe1(struct device *dev, int ioaddr);
-unsigned char	get_sram_size(struct tok_info *adapt_info);
+static unsigned char	get_sram_size(struct tok_info *adapt_info);
 static int	tok_init_card(struct device *dev);
-int		trdev_init(struct device *dev);
+static int	trdev_init(struct device *dev);
 void		tok_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void 	initial_tok_int(struct device *dev);
 static void 	open_sap(unsigned char type,struct device *dev);
@@ -1583,7 +1586,7 @@
 		dev_ibmtr[i]->init      = &ibmtr_probe;
 
 	        if (register_trdev(dev_ibmtr[i]) != 0) {
-			kfree_s(dev_ibmtr[i], sizeof(struct dev));
+			kfree_s(dev_ibmtr[i], sizeof(struct device));
 			dev_ibmtr[i] = NULL;
 		        if (i == 0) {
 			        printk("ibmtr: register_trdev() returned non-zero.\n");
diff -u --recursive --new-file v2.1.44/linux/drivers/net/sdla_fr.c linux/drivers/net/sdla_fr.c
--- v2.1.44/linux/drivers/net/sdla_fr.c	Tue May 13 22:41:09 1997
+++ linux/drivers/net/sdla_fr.c	Wed Jul 16 19:22:50 1997
@@ -10,6 +10,49 @@
 *		as published by the Free Software Foundation; either version
 *		2 of the License, or (at your option) any later version.
 * ============================================================================
+*
+* Jun 29, 1997  Alan Cox	 o Hacked up vendor source 1.0.3 to remove
+*				   C++ style comments, and a massive security
+*				   hole (the UDP management junk).
+*
+* May 29, 1997	Jaspreet Singh	 o Fixed major Flow Control Problem
+*				   With multiple boards a problem was seen where
+*				   the second board always stopped transmitting
+*				   packet after running for a while. The code
+*				   got into a stage where the interrupts were
+*				   disabled and dev->tbusy was set to 1.
+*				   This caused the If_send() routine to get into
+*				   the if clause for set_bit(0,dev->tbusy) 
+*				   forever.
+*				   The code got into this stage due to an 
+*				   interrupt occuring within the if clause for 
+*				   set_bit(0,dev->tbusy).  Since an interrupt 
+*				   disables furhter transmit interrupt and 
+* 				   makes dev->tbusy = 0, this effect was undone
+*                                  by making dev->tbusy = 1 in the if clause.
+*				   The Fix checks to see if Transmit interrupts
+*				   are disabled then do not make dev->tbusy = 1
+* 	   			   Introduced a global variable: int_occur and
+*				   added tx_int_enabled in the wan_device 
+*				   structure.	
+* May 21, 1997  Jaspreet Singh   o Fixed UDP Management for multiple
+*                                  boards.
+*
+* Apr 25, 1997  Farhan Thawar    o added UDP Management stuff
+*                                o fixed bug in if_send() and tx_intr() to
+*                                  sleep and wakeup all devices
+* Mar 11, 1997  Farhan Thawar   Version 3.1.1
+*                                o fixed (+1) bug in fr508_rx_intr()
+*                                o changed if_send() to return 0 if
+*                                  wandev.critical() is true
+*                                o free socket buffer in if_send() if
+*                                  returning 0 
+*                                o added tx_intr() routine
+* Jan 30, 1997	Gene Kozin	Version 3.1.0
+*				 o implemented exec() entry point
+*				 o fixed a bug causing driver configured as
+*				   a FR switch to be stuck in WAN_DISCONNECTED
+*				   mode
 * Jan 02, 1997	Gene Kozin	Initial version.
 *****************************************************************************/
 
@@ -22,12 +65,13 @@
 #include <linux/errno.h>	/* return codes */
 #include <linux/string.h>	/* inline memset(), etc. */
 #include <linux/malloc.h>	/* kmalloc(), kfree() */
-#include <linux/router.h>	/* WAN router definitions */
+#include <linux/wanrouter.h>	/* WAN router definitions */
 #include <linux/wanpipe.h>	/* WANPIPE common user API definitions */
 #include <linux/if_arp.h>	/* ARPHRD_* defines */
 #include <linux/init.h>		/* __initfunc et al. */
 #include <asm/byteorder.h>	/* htons(), etc. */
 #include <asm/io.h>		/* for inb(), outb(), etc. */
+#include <asm/uaccess.h>
 
 #define	_GNUC_
 #include <linux/sdla_fr.h>	/* frame relay firmware API definitions */
@@ -67,6 +111,9 @@
 	unsigned char state	PACKED;
 } dlci_status_t;
 
+static char TracingEnabled;
+/* variable for checking interrupts within the ISR routine */
+static int int_occur = 0;
 /****** Function Prototypes *************************************************/
 
 /* WAN link driver entry points. These are called by the WAN router module. */
@@ -75,14 +122,16 @@
 	wanif_conf_t* conf);
 static int del_if (wan_device_t* wandev, struct device* dev);
 
+/* WANPIPE-specific entry points */
+static int wpf_exec (struct sdla* card, void* u_cmd, void* u_data);
+
 /* Network device interface */
 static int if_init   (struct device* dev);
 static int if_open   (struct device* dev);
 static int if_close  (struct device* dev);
 static int if_header (struct sk_buff* skb, struct device* dev,
 	unsigned short type, void* daddr, void* saddr, unsigned len);
-static int if_rebuild_hdr (void* hdr, struct device* dev, unsigned long raddr,
-	struct sk_buff* skb);
+static int if_rebuild_hdr (struct sk_buff* skb);
 static int if_send (struct sk_buff* skb, struct device* dev);
 static struct enet_statistics* if_stats (struct device* dev);
 
@@ -103,6 +152,8 @@
 static int fr_set_intr_mode (sdla_t* card, unsigned mode, unsigned mtu);
 static int fr_comm_enable (sdla_t* card);
 static int fr_comm_disable (sdla_t* card);
+static int fr_get_err_stats (sdla_t* card);
+static int fr_get_stats (sdla_t* card);
 static int fr_add_dlci (sdla_t* card, int dlci, int num);
 static int fr_activate_dlci (sdla_t* card, int dlci, int num);
 static int fr_issue_isf (sdla_t* card, int isf);
@@ -120,7 +171,6 @@
 static struct device* find_channel (sdla_t* card, unsigned dlci);
 static int is_tx_ready (sdla_t* card);
 static unsigned int dec_to_uint (unsigned char* str, int len);
-static unsigned int hex_to_uint (unsigned char* str, int len);
 
 /****** Public Functions ****************************************************/
 
@@ -198,7 +248,7 @@
 	u.cfg.n392	= 3;
 	u.cfg.n393	= 4;
 	u.cfg.kbps	= conf->bps / 1000;
-	u.cfg.cir_fwd	= max(min(u.cfg.kbps, 512), 1);
+	u.cfg.cir_fwd	= 16;
 	u.cfg.cir_bwd = u.cfg.bc_fwd = u.cfg.bc_bwd = u.cfg.cir_fwd;
 	u.cfg.options	= 0x0081;	/* direct Rx, no CIR check */
 	switch (conf->u.fr.signalling)
@@ -214,7 +264,7 @@
 	{
 		u.cfg.station = 1;	/* switch emulation mode */
 		card->u.f.node_dlci = conf->u.fr.dlci ? conf->u.fr.dlci : 16;
-		card->u.f.dlci_num  = max(min(conf->u.fr.dlci_num, 1), 100);
+		card->u.f.dlci_num  = min(max(conf->u.fr.dlci_num, 1), 100);
 	}
 	if (conf->clocking == WANOPT_INTERNAL)
 		u.cfg.port |= 0x0001
@@ -270,11 +320,14 @@
 	card->wandev.clocking	= conf->clocking;
 	card->wandev.station	= conf->station;
 	card->poll		= &wpf_poll;
+	card->exec		= &wpf_exec;
 	card->wandev.update	= &update;
 	card->wandev.new_if	= &new_if;
 	card->wandev.del_if	= &del_if;
 	card->wandev.state	= WAN_DISCONNECTED;
-	return 0;
+        card->wandev.udp_port 	= conf->udp_port;       
+        TracingEnabled          = '0';
+        return 0;
 }
 
 /******* WAN Device Driver Entry Points *************************************/
@@ -284,9 +337,22 @@
  */
 static int update (wan_device_t* wandev)
 {
-/*
-	sdla_t* card = wandev->private;
-*/
+	sdla_t* card;
+
+	/* sanity checks */
+	if ((wandev == NULL) || (wandev->private == NULL))
+		return -EFAULT
+	;
+	if (wandev->state == WAN_UNCONFIGURED)
+		return -ENODEV
+	;
+	if (test_and_set_bit(0, (void*)&wandev->critical))
+		return -EAGAIN
+	;
+	card = wandev->private;
+	fr_get_err_stats(card);
+	fr_get_stats(card);
+	wandev->critical = 0;
 	return 0;
 }
 
@@ -377,6 +443,43 @@
 	return 0;
 }
 
+/****** WANPIPE-specific entry points ***************************************/
+
+/*============================================================================
+ * Execute adapter interface command.
+ */
+static int wpf_exec (struct sdla* card, void* u_cmd, void* u_data)
+{
+	fr_mbox_t* mbox = card->mbox;
+	int retry = MAX_CMD_RETRY;
+	int err, len;
+	fr_cmd_t cmd;
+
+	if(copy_from_user((void*)&cmd, u_cmd, sizeof(cmd)))
+		return -EFAULT;
+	/* execute command */
+	do
+	{
+		memcpy(&mbox->cmd, &cmd, sizeof(cmd));
+		if (cmd.length)
+			if(copy_from_user((void*)&mbox->data, u_data, cmd.length))
+				return -EFAULT;
+		if (sdla_exec(mbox))
+			err = mbox->cmd.result;
+		else
+			return -EIO;
+	}
+	while (err && retry-- && fr_event(card, err, mbox));
+
+	/* return result */
+	if(copy_to_user(u_cmd, (void*)&mbox->cmd, sizeof(fr_cmd_t)))
+		return -EFAULT;
+	len = mbox->cmd.length;
+	if (len && u_data && copy_to_user(u_data, (void*)&mbox->data, len))
+		return -EFAULT;
+	return 0;
+}
+
 /****** Network Device Interface ********************************************/
 
 /*============================================================================
@@ -416,6 +519,9 @@
 	dev->mem_start	= wandev->maddr;
 	dev->mem_end	= wandev->maddr + wandev->msize - 1;
 
+        /* Set transmit buffer queue length */
+        dev->tx_queue_len = 30;
+   
 	/* Initialize socket buffers */
 	for (i = 0; i < DEV_NUMBUFFS; ++i)
 		skb_queue_head_init(&dev->buffs[i])
@@ -451,12 +557,14 @@
 			err = -EIO;
 			goto done;
 		}
+		wanpipe_set_state(card, WAN_CONNECTED);
+
 		if (card->wandev.station == WANOPT_CPE)
 		{
 			/* CPE: issue full status enquiry */
 			fr_issue_isf(card, FR_ISF_FSE);
 		}
-		else	/* Switch: activate DLCI(s) */
+		else	/* FR switch: activate DLCI(s) */
 		{
 			fr_add_dlci(card,
 				card->u.f.node_dlci, card->u.f.dlci_num)
@@ -465,7 +573,6 @@
 				card->u.f.node_dlci, card->u.f.dlci_num)
 			;
 		}
-		wanpipe_set_state(card, WAN_CONNECTED);
 	}
 	dev->mtu = min(dev->mtu, card->wandev.mtu - FR_HEADER_LEN);
 	dev->interrupt = 0;
@@ -538,14 +645,13 @@
  * Return:	1	physical address resolved.
  *		0	physical address not resolved
  */
-static int if_rebuild_hdr (void* hdr, struct device* dev, unsigned long raddr,
-			   struct sk_buff* skb)
+static int if_rebuild_hdr (struct sk_buff* skb)
 {
-	fr_channel_t* chan = dev->priv;
+	fr_channel_t* chan = skb->dev->priv;
 	sdla_t* card = chan->card;
 
 	printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n",
-		card->devname, dev->name)
+		card->devname, skb->dev->name)
 	;
 	return 1;
 }
@@ -570,10 +676,11 @@
  */
 static int if_send (struct sk_buff* skb, struct device* dev)
 {
-	fr_channel_t* chan = dev->priv;
-	sdla_t* card = chan->card;
-	int retry = 0;
-
+	fr_channel_t *chan = dev->priv;
+	sdla_t *card = chan->card;
+	int retry=0, err;
+	struct device *dev2;
+	
 	if (test_and_set_bit(0, (void*)&card->wandev.critical))
 	{
 #ifdef _DEBUG_
@@ -581,7 +688,8 @@
 			card->devname)
 		;
 #endif
-		return 1;
+		dev_kfree_skb(skb, FREE_WRITE);
+		return 0;
 	}
 
 	if (test_and_set_bit(0, (void*)&dev->tbusy))
@@ -592,23 +700,55 @@
 		;
 #endif
 		++chan->ifstats.collisions;
+		++card->wandev.stats.collisions;
+
 		retry = 1;
+		if(card->wandev.tx_int_enabled)
+		{
+			for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) 
+			{
+		      		dev2->tbusy = 1;
+		   	}
+		}
+	}
+	else if (card->wandev.state != WAN_CONNECTED)
+	{
+		++chan->ifstats.tx_dropped;
+		++card->wandev.stats.tx_dropped;
+	}
+	else if (chan->state != WAN_CONNECTED)
+	{
+		update_chan_state(dev);
+		++chan->ifstats.tx_dropped;
+		++card->wandev.stats.tx_dropped;
+	}
+	else if (!is_tx_ready(card)) 
+	{
+		retry = 1;
+		if(card->wandev.tx_int_enabled)
+		{
+	   		for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave)
+ 			{
+	      			dev2->tbusy = 1;
+	   		}
+		}
 	}
-	else if ((card->wandev.state != WAN_CONNECTED) ||
-	    (chan->state != WAN_CONNECTED))
-		++chan->ifstats.tx_dropped
-	;
-	else if (!is_tx_ready(card))
-		retry = 1
-	;
 	else
 	{
- 		int err = (card->hw.fwid == SFID_FR508) ?
+ 		err = (card->hw.fwid == SFID_FR508) ?
 			fr508_send(card, chan->dlci, 0, skb->len, skb->data) :
 			fr502_send(card, chan->dlci, 0, skb->len, skb->data)
 		;
-		if (err) ++chan->ifstats.tx_errors;
-		else ++chan->ifstats.tx_packets;
+		if (err)
+		{
+			++chan->ifstats.tx_errors;
+			++card->wandev.stats.tx_errors;
+		}
+		else
+		{
+			++chan->ifstats.tx_packets;
+			++card->wandev.stats.tx_packets;
+		}
 	}
 	if (!retry)
 	{
@@ -619,6 +759,7 @@
 	return retry;
 }
 
+
 /*============================================================================
  * Get ethernet-style interface statistics.
  * Return a pointer to struct enet_statistics.
@@ -663,7 +804,14 @@
 {
 	fr508_flags_t* flags = card->flags;
 	fr_buf_ctl_t* bctl;
-
+	
+	if(int_occur){
+#ifdef _DEBUG_
+		printk(KERN_INFO "%s:Interrupt Occurred within an ISR\n",card->devname);
+#endif
+		return;
+	}
+	int_occur=1;
 	switch (flags->iflag)
 	{
 	case 0x01:	/* receive interrupt */
@@ -681,6 +829,7 @@
 	default:
 		spur_intr(card);
 	}
+	int_occur = 0;
 	flags->iflag = 0;
 }
 
@@ -690,13 +839,14 @@
 static void fr502_rx_intr (sdla_t* card)
 {
 	fr_mbox_t* mbox = card->rxmb;
-	struct sk_buff* skb;
-	struct device* dev;
-	fr_channel_t* chan;
+	struct sk_buff *skb;
+	struct device *dev;
+	fr_channel_t *chan;
 	unsigned dlci, len;
 	void* buf;
-
+   
 	sdla_mapmem(&card->hw, FR502_RX_VECTOR);
+
 	dlci = mbox->cmd.dlci;
 	len  = mbox->cmd.length;
 
@@ -741,13 +891,14 @@
 		/* can't decapsulate packet */
 		dev_kfree_skb(skb, FREE_READ);
 		++chan->ifstats.rx_errors;
+		++card->wandev.stats.rx_errors;
 	}
 	else
 	{
 		netif_rx(skb);
 		++chan->ifstats.rx_packets;
+		++card->wandev.stats.rx_packets;
 	}
-
 rx_done:
 	sdla_mapmem(&card->hw, FR_MB_VECTOR);
 }
@@ -763,7 +914,7 @@
 	fr_channel_t* chan;
 	unsigned dlci, len, offs;
 	void* buf;
-
+   
 	if (frbuf->flag != 0x01)
 	{
 		printk(KERN_INFO "%s: corrupted Rx buffer @ 0x%X!\n",
@@ -804,9 +955,9 @@
 	}
 
 	/* Copy data to the socket buffer */
-	if ((offs + len) > card->u.f.rx_top)
+	if ((offs + len) > card->u.f.rx_top + 1)
 	{
-		unsigned tmp = card->u.f.rx_top - offs;
+		unsigned tmp = card->u.f.rx_top - offs + 1;
 
 		buf = skb_put(skb, tmp);
 		sdla_peek(&card->hw, offs, buf, tmp);
@@ -814,8 +965,7 @@
 		len -= tmp;
 	}
 	buf = skb_put(skb, len);
-	sdla_peek(&card->hw, offs, buf, len);
-
+	sdla_peek(&card->hw, offs, buf, len);   
 	/* Decapsulate packet and pass it up the protocol stack */
 	skb->dev = dev;
 	buf = skb_pull(skb, 1);	/* remove hardware header */
@@ -824,13 +974,14 @@
 		/* can't decapsulate packet */
 		dev_kfree_skb(skb, FREE_READ);
 		++chan->ifstats.rx_errors;
+		++card->wandev.stats.rx_errors;
 	}
 	else
 	{
 		netif_rx(skb);
 		++chan->ifstats.rx_packets;
+		++card->wandev.stats.rx_packets;
 	}
-
 rx_done:
 	/* Release buffer element and calculate a pointer to the next one */
 	frbuf->flag = 0;
@@ -848,7 +999,17 @@
  */
 static void tx_intr (sdla_t* card)
 {
+   struct device* dev = card->wandev.dev;
+
+   for (; dev; dev = dev->slave) {
+      if( !dev || !dev->start ) continue;
+      dev->tbusy = 0;
+      dev_tint(dev);
+   }
+   card->wandev.tx_int_enabled = 0;	
+/*
 	printk(KERN_INFO "%s: transmit interrupt!\n", card->devname);
+*/
 }
 
 /*============================================================================
@@ -877,8 +1038,14 @@
  */
 static void wpf_poll (sdla_t* card)
 {
-	fr502_flags_t* flags = card->flags;
+	static unsigned long last_poll;
+	fr502_flags_t* flags;
+
+	if ((jiffies - last_poll) < HZ)
+		return
+	;
 
+	flags = card->flags;
 	if (flags->event)
 	{
 		fr_mbox_t* mbox = card->mbox;
@@ -889,6 +1056,7 @@
 		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
 		if (err) fr_event(card, err, mbox);
 	}
+	last_poll = jiffies;
 }
 
 /****** Frame Relay Firmware-Specific Functions *****************************/
@@ -1025,6 +1193,65 @@
 }
 
 /*============================================================================
+ * Get communications error statistics. 
+ */
+static int fr_get_err_stats (sdla_t* card)
+{
+	fr_mbox_t* mbox = card->mbox;
+	int retry = MAX_CMD_RETRY;
+	int err;
+
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+		mbox->cmd.command = FR_READ_ERROR_STATS;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	}
+	while (err && retry-- && fr_event(card, err, mbox));
+
+	if (!err)
+	{
+		fr_comm_stat_t* stats = (void*)mbox->data;
+
+		card->wandev.stats.rx_over_errors    = stats->rx_overruns;
+		card->wandev.stats.rx_crc_errors     = stats->rx_bad_crc;
+		card->wandev.stats.rx_missed_errors  = stats->rx_aborts;
+		card->wandev.stats.rx_length_errors  = stats->rx_too_long;
+		card->wandev.stats.tx_aborted_errors = stats->tx_aborts;
+	}
+	return err;
+}
+
+/*============================================================================
+ * Get statistics. 
+ */
+static int fr_get_stats (sdla_t* card)
+{
+	fr_mbox_t* mbox = card->mbox;
+	int retry = MAX_CMD_RETRY;
+	int err;
+
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(fr_cmd_t));
+		mbox->cmd.command = FR_READ_STATISTICS;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	}
+	while (err && retry-- && fr_event(card, err, mbox));
+
+	if (!err)
+	{
+		fr_link_stat_t* stats = (void*)mbox->data;
+
+		card->wandev.stats.rx_frame_errors = stats->rx_bad_format;
+		card->wandev.stats.rx_dropped =
+			stats->rx_dropped + stats->rx_dropped2
+		;
+	}
+	return err;
+}
+
+/*============================================================================
  * Add DLCI(s) (Access Node only!). 
  */
 static int fr_add_dlci (sdla_t* card, int dlci, int num)
@@ -1363,6 +1590,7 @@
 
 		if (sb & 0x02) return 1;
 		flags->imask |= 0x02;
+		card->wandev.tx_int_enabled = 1; 
 	}
 	else
 	{
@@ -1386,29 +1614,6 @@
 	for (val = 0; len && is_digit(*str); ++str, --len)
 		val = (val * 10) + (*str - (unsigned)'0')
 	;
-	return val;
-}
-
-/*============================================================================
- * Convert hex string to unsigned integer.
- * If len != 0 then only 'len' characters of the string are conferted.
- */
-static unsigned int hex_to_uint (unsigned char* str, int len)
-{
-	unsigned val, ch;
-
-	if (!len) len = strlen(str);
-	for (val = 0; len; ++str, --len)
-	{
-		ch = *str;
-		if (is_digit(ch))
-			val = (val << 4) + (ch - (unsigned)'0')
-		;
-		else if (is_hex_digit(ch))
-			val = (val << 4) + ((ch & 0xDF) - (unsigned)'A' + 10)
-		;
-		else break;
-	}
 	return val;
 }
 
diff -u --recursive --new-file v2.1.44/linux/drivers/net/sdla_ppp.c linux/drivers/net/sdla_ppp.c
--- v2.1.44/linux/drivers/net/sdla_ppp.c	Tue May 13 22:41:11 1997
+++ linux/drivers/net/sdla_ppp.c	Wed Jul 16 19:22:51 1997
@@ -10,6 +10,25 @@
 *		as published by the Free Software Foundation; either version
 *		2 of the License, or (at your option) any later version.
 * ============================================================================
+* Jun 29, 1997  Alan Cox	o Dumped the idiot UDP management system.
+*
+* May 22, 1997	Jaspreet Singh	o Added change in the PPP_SET_CONFIG command for
+*				508 card to reflect changes in the new 
+*				ppp508.sfm for supporting:continous transmission
+*				of Configure-Request packets without receiving a
+*				reply 				
+*				OR-ed 0x300 to conf_flags 
+*			        o Changed connect_tmout from 900 to 0
+* May 21, 1997	Jaspreet Singh  o Fixed UDP Management for multiple boards
+* Apr 25, 1997  Farhan Thawar    o added UDP Management stuff
+* Mar 11, 1997  Farhan Thawar   Version 3.1.1
+*                                o fixed (+1) bug in rx_intr()
+*                                o changed if_send() to return 0 if
+*                                  wandev.critical() is true
+*                                o free socket buffer in if_send() if
+*                                  returning 0 
+* Jan 15, 1997	Gene Kozin	Version 3.1.0
+*				 o implemented exec() entry point
 * Jan 06, 1997	Gene Kozin	Initial version.
 *****************************************************************************/
 
@@ -22,11 +41,12 @@
 #include <linux/errno.h>	/* return codes */
 #include <linux/string.h>	/* inline memset(), etc. */
 #include <linux/malloc.h>	/* kmalloc(), kfree() */
-#include <linux/router.h>	/* WAN router definitions */
+#include <linux/wanrouter.h>	/* WAN router definitions */
 #include <linux/wanpipe.h>	/* WANPIPE common user API definitions */
 #include <linux/if_arp.h>	/* ARPHRD_* defines */
 #include <linux/init.h>		/* __initfunc et al. */
 #include <asm/byteorder.h>	/* htons(), etc. */
+#include <asm/uaccess.h>
 
 #define	_GNUC_
 #include <linux/sdla_ppp.h>		/* PPP firmware API definitions */
@@ -57,14 +77,16 @@
 	wanif_conf_t* conf);
 static int del_if (wan_device_t* wandev, struct device* dev);
 
+/* WANPIPE-specific entry points */
+static int wpp_exec (struct sdla* card, void* u_cmd, void* u_data);
+
 /* Network device interface */
 static int if_init   (struct device* dev);
 static int if_open   (struct device* dev);
 static int if_close  (struct device* dev);
 static int if_header (struct sk_buff* skb, struct device* dev,
 	unsigned short type, void* daddr, void* saddr, unsigned len);
-static int if_rebuild_hdr (void* hdr, struct device* dev, unsigned long raddr,
-	struct sk_buff* skb);
+static int if_rebuild_hdr (struct sk_buff* skb);
 static int if_send (struct sk_buff* skb, struct device* dev);
 static struct enet_statistics* if_stats (struct device* dev);
 
@@ -74,6 +96,7 @@
 static int ppp_set_intr_mode (sdla_t* card, unsigned mode);
 static int ppp_comm_enable (sdla_t* card);
 static int ppp_comm_disable (sdla_t* card);
+static int ppp_get_err_stats (sdla_t* card);
 static int ppp_send (sdla_t* card, void* data, unsigned len, unsigned proto);
 static int ppp_error (sdla_t *card, int err, ppp_mbox_t* mb);
 
@@ -94,6 +117,7 @@
 static void show_disc_cause (sdla_t* card, unsigned cause);
 static unsigned char bps_to_speed_code (unsigned long bps);
 
+static char TracingEnabled;
 /****** Public Functions ****************************************************/
 
 /*============================================================================
@@ -163,10 +187,13 @@
 	card->wandev.station	= conf->station;
 	card->isr		= &wpp_isr;
 	card->poll		= &wpp_poll;
+	card->exec		= &wpp_exec;
 	card->wandev.update	= &update;
 	card->wandev.new_if	= &new_if;
 	card->wandev.del_if	= &del_if;
 	card->wandev.state	= WAN_DISCONNECTED;
+        card->wandev.udp_port   = conf->udp_port;
+        TracingEnabled          = '0';
 	return 0;
 }
 
@@ -177,9 +204,22 @@
  */
 static int update (wan_device_t* wandev)
 {
-/*
-	sdla_t* card = wandev->private;
-*/
+	sdla_t* card;
+
+	/* sanity checks */
+	if ((wandev == NULL) || (wandev->private == NULL))
+		return -EFAULT
+	;
+	if (wandev->state == WAN_UNCONFIGURED)
+		return -ENODEV
+	;
+	if (test_and_set_bit(0, (void*)&wandev->critical))
+		return -EAGAIN
+	;
+	card = wandev->private;
+
+	ppp_get_err_stats(card);
+	wandev->critical = 0;
 	return 0;
 }
 
@@ -228,6 +268,38 @@
 	return 0;
 }
 
+/****** WANPIPE-specific entry points ***************************************/
+
+/*============================================================================
+ * Execute adapter interface command.
+ */
+static int wpp_exec (struct sdla* card, void* u_cmd, void* u_data)
+{
+	ppp_mbox_t* mbox = card->mbox;
+	int len;
+
+	if(copy_from_user((void*)&mbox->cmd, u_cmd, sizeof(ppp_cmd_t)))
+		return -EFAULT;
+	len = mbox->cmd.length;
+	if (len)
+	{
+		if(copy_from_user((void*)&mbox->data, u_data, len))
+			return -EFAULT;
+	}
+
+	/* execute command */
+	if (!sdla_exec(mbox))
+		return -EIO;
+
+	/* return result */
+	if(copy_to_user(u_cmd, (void*)&mbox->cmd, sizeof(ppp_cmd_t)))
+		return -EFAULT;
+	len = mbox->cmd.length;
+	if (len && u_data && copy_to_user(u_data, (void*)&mbox->data, len))
+			return -EFAULT;
+	return 0;
+}
+
 /****** Network Device Interface ********************************************/
 
 /*============================================================================
@@ -264,6 +336,9 @@
 	dev->mem_start		= wandev->maddr;
 	dev->mem_end		= wandev->maddr + wandev->msize - 1;
 
+        /* Set transmit buffer queue length */
+        dev->tx_queue_len = 30;
+   
 	/* Initialize socket buffers */
 	for (i = 0; i < DEV_NUMBUFFS; ++i)
 		skb_queue_head_init(&dev->buffs[i])
@@ -408,13 +483,12 @@
  * Return:	1	physical address resolved.
  *		0	physical address not resolved
  */
-static int if_rebuild_hdr (void* hdr, struct device* dev, unsigned long raddr,
-			   struct sk_buff* skb)
+static int if_rebuild_hdr (struct sk_buff* skb)
 {
-	sdla_t* card = dev->priv;
+	sdla_t* card = skb->dev->priv;
 
 	printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n",
-		card->devname, dev->name)
+		card->devname, skb->dev->name)
 	;
 	return 1;
 }
@@ -460,8 +534,7 @@
 #endif
 		++card->wandev.stats.collisions;
 		retry = 1;
-	}
-	else if (card->wandev.state != WAN_CONNECTED)
+	} else if (card->wandev.state != WAN_CONNECTED)
 		++card->wandev.stats.tx_dropped
 	;
 	else if (!skb->protocol)
@@ -489,6 +562,7 @@
  * Get ethernet-style interface statistics.
  * Return a pointer to struct enet_statistics.
  */
+
 static struct enet_statistics* if_stats (struct device* dev)
 {
 	sdla_t* card = dev->priv;
@@ -599,6 +673,31 @@
 }
 
 /*============================================================================
+ * Get communications error statistics.
+ */
+static int ppp_get_err_stats (sdla_t* card)
+{
+	ppp_mbox_t* mb = card->mbox;
+	int err;
+
+	memset(&mb->cmd, 0, sizeof(ppp_cmd_t));
+	mb->cmd.command = PPP_READ_ERROR_STATS;
+	err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
+	if (err == CMD_OK)
+	{
+		ppp_err_stats_t* stats = (void*)mb->data;
+
+		card->wandev.stats.rx_over_errors    = stats->rx_overrun;
+		card->wandev.stats.rx_crc_errors     = stats->rx_bad_crc;
+		card->wandev.stats.rx_missed_errors  = stats->rx_abort;
+		card->wandev.stats.rx_length_errors  = stats->rx_lost;
+		card->wandev.stats.tx_aborted_errors = stats->tx_abort;
+	}
+	else ppp_error(card, err, mb);
+	return err;
+}
+
+/*============================================================================
  * Send packet.
  *	Return:	0 - o.k.
  *		1 - no transmit buffers available
@@ -701,7 +800,7 @@
 	struct sk_buff* skb;
 	unsigned len;
 	void* buf;
-
+   
 	if (rxbuf->flag != 0x01)
 	{
 		printk(KERN_INFO "%s: corrupted Rx buffer @ 0x%X!\n",
@@ -738,9 +837,9 @@
 	{
 		unsigned addr = rxbuf->buf.ptr;
 
-		if ((addr + len) > card->u.p.rx_top)
+		if ((addr + len) > card->u.p.rx_top + 1)
 		{
-			unsigned tmp = card->u.p.rx_top - addr;
+			unsigned tmp = card->u.p.rx_top - addr + 1;
 
 			buf = skb_put(skb, tmp);
 			sdla_peek(&card->hw, addr, buf, tmp);
@@ -751,8 +850,8 @@
 		sdla_peek(&card->hw, addr, buf, len);
 	}
 
-	/* Decapsulate packet and pass it up the protocol stack */
-	switch (rxbuf->proto)
+	/* Decapsulate packet */
+        switch (rxbuf->proto)
 	{
 	case 0x00:
 		skb->protocol = htons(ETH_P_IP);
@@ -762,10 +861,11 @@
 		skb->protocol = htons(ETH_P_IPX);
 		break;
 	}
+
+	/* Pass it up the protocol stack */
 	skb->dev = dev;
 	netif_rx(skb);
 	++card->wandev.stats.rx_packets;
-
 rx_done:
 	/* Release buffer element and calculate a pointer to the next one */
 	rxbuf->flag = (card->hw.fwid == SFID_PPP502) ? 0xFF : 0x00;
@@ -891,13 +991,14 @@
 	cfg.auth_wait_tmr	= 300;
 	cfg.mdm_fail_tmr	= 5;
 	cfg.dtr_drop_tmr	= 1;
-	cfg.connect_tmout	= 900;
+	cfg.connect_tmout	= 0;	/* changed it from 900 */
 	cfg.conf_retry		= 10;
 	cfg.term_retry		= 2;
 	cfg.fail_retry		= 5;
 	cfg.auth_retry		= 10;
 	cfg.ip_options		= 0x80;
 	cfg.ipx_options		= 0xA0;
+        cfg.conf_flags         |= 0x0E;
 /*
 	cfg.ip_local		= dev->pa_addr;
 	cfg.ip_remote		= dev->pa_dstaddr;
@@ -921,6 +1022,7 @@
 	if (card->wandev.interface == WANOPT_RS232)
 		cfg.conf_flags |= 0x0020;
 	;
+        cfg.conf_flags 	|= 0x300; /*send Configure-Request packets forever*/
 	cfg.txbuf_percent	= 60;	/* % of Tx bufs */
 	cfg.mtu_local		= card->wandev.mtu;
 	cfg.mtu_remote		= card->wandev.mtu;
@@ -929,7 +1031,7 @@
 	cfg.auth_wait_tmr	= 300;
 	cfg.mdm_fail_tmr	= 5;
 	cfg.dtr_drop_tmr	= 1;
-	cfg.connect_tmout	= 900;
+	cfg.connect_tmout	= 0; 	/* changed it from 900 */
 	cfg.conf_retry		= 10;
 	cfg.term_retry		= 2;
 	cfg.fail_retry		= 5;
diff -u --recursive --new-file v2.1.44/linux/drivers/net/sdla_x25.c linux/drivers/net/sdla_x25.c
--- v2.1.44/linux/drivers/net/sdla_x25.c	Tue May 13 22:41:11 1997
+++ linux/drivers/net/sdla_x25.c	Wed Jul 16 19:22:51 1997
@@ -10,6 +10,17 @@
 *		as published by the Free Software Foundation; either version
 *		2 of the License, or (at your option) any later version.
 * ============================================================================
+* Mar 11, 1997  Farhan Thawar   Version 3.1.1
+*                                o added support for V35
+*                                o changed if_send() to return 0 if
+*                                  wandev.critical() is true
+*                                o free socket buffer in if_send() if
+*                                  returning 0
+*                                o added support for single '@' address to
+*                                  accept all incoming calls
+*                                o fixed bug in set_chan_state() to disconnect
+* Jan 15, 1997	Gene Kozin	Version 3.1.0
+*				 o implemented exec() entry point
 * Jan 07, 1997	Gene Kozin	Initial version.
 *****************************************************************************/
 
@@ -22,10 +33,11 @@
 #include <linux/errno.h>	/* return codes */
 #include <linux/string.h>	/* inline memset(), etc. */
 #include <linux/malloc.h>	/* kmalloc(), kfree() */
-#include <linux/router.h>	/* WAN router definitions */
+#include <linux/wanrouter.h>	/* WAN router definitions */
 #include <linux/wanpipe.h>	/* WANPIPE common user API definitions */
 #include <linux/init.h>		/* __initfunc et al. */
 #include <asm/byteorder.h>	/* htons(), etc. */
+#include <asm/uaccess.h>	/* copy_from_user, etc */
 
 #define	_GNUC_
 #include <linux/sdla_x25.h>	/* X.25 firmware API definitions */
@@ -90,14 +102,16 @@
 	wanif_conf_t* conf);
 static int del_if (wan_device_t* wandev, struct device* dev);
 
+/* WANPIPE-specific entry points */
+static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data);
+
 /* Network device interface */
 static int if_init   (struct device* dev);
 static int if_open   (struct device* dev);
 static int if_close  (struct device* dev);
 static int if_header (struct sk_buff* skb, struct device* dev,
 	unsigned short type, void* daddr, void* saddr, unsigned len);
-static int if_rebuild_hdr (void* hdr, struct device* dev, unsigned long raddr,
-	struct sk_buff* skb);
+static int if_rebuild_hdr (struct sk_buff* skb);
 static int if_send (struct sk_buff* skb, struct device* dev);
 static struct enet_statistics* if_stats (struct device* dev);
 
@@ -118,6 +132,8 @@
 /* X.25 firmware interface functions */
 static int x25_get_version (sdla_t* card, char* str);
 static int x25_configure (sdla_t* card, TX25Config* conf);
+static int x25_get_err_stats (sdla_t* card);
+static int x25_get_stats (sdla_t* card);
 static int x25_set_intr_mode (sdla_t* card, int mode);
 static int x25_close_hdlc (sdla_t* card);
 static int x25_open_hdlc (sdla_t* card);
@@ -235,7 +251,9 @@
 	{
 		u.cfg.station = 0;		/* DCE mode */
 	}
-
+        if (conf->interface != WANOPT_RS232 ) {
+	        u.cfg.hdlcOptions |= 0x80;      /* V35 mode */
+	} 
 	/* adjust MTU */
 	if (!conf->mtu || (conf->mtu >= 1024))
 		card->wandev.mtu = 1024
@@ -299,6 +317,7 @@
 	card->wandev.station	= conf->station;
 	card->isr		= &wpx_isr;
 	card->poll		= &wpx_poll;
+	card->exec		= &wpx_exec;
 	card->wandev.update	= &update;
 	card->wandev.new_if	= &new_if;
 	card->wandev.del_if	= &del_if;
@@ -313,9 +332,23 @@
  */
 static int update (wan_device_t* wandev)
 {
-/*
-	sdla_t* card = wandev->private;
-*/
+	sdla_t* card;
+
+	/* sanity checks */
+	if ((wandev == NULL) || (wandev->private == NULL))
+		return -EFAULT
+	;
+	if (wandev->state == WAN_UNCONFIGURED)
+		return -ENODEV
+	;
+	if (test_and_set_bit(0, (void*)&wandev->critical))
+		return -EAGAIN
+	;
+	card = wandev->private;
+
+	x25_get_err_stats(card);
+	x25_get_stats(card);
+	wandev->critical = 0;
 	return 0;
 }
 
@@ -412,6 +445,45 @@
 	return 0;
 }
 
+/****** WANPIPE-specific entry points ***************************************/
+
+/*============================================================================
+ * Execute adapter interface command.
+ */
+static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data)
+{
+	TX25Mbox* mbox = card->mbox;
+	int retry = MAX_CMD_RETRY;
+	int err, len;
+	TX25Cmd cmd;
+
+	if(copy_from_user((void*)&cmd, u_cmd, sizeof(cmd)))
+		return -EFAULT;
+
+	/* execute command */
+	do
+	{
+		memcpy(&mbox->cmd, &cmd, sizeof(cmd));
+		if (cmd.length)
+			if(copy_from_user((void*)&mbox->data, u_data, cmd.length))
+				return -EFAULT;
+		if (sdla_exec(mbox))
+			err = mbox->cmd.result;
+		else
+			return -EIO;
+	}
+	while (err && retry-- && x25_error(card, err, cmd.command, cmd.lcn));
+
+	/* return result */
+	if(copy_to_user(u_cmd, (void*)&mbox->cmd, sizeof(TX25Cmd)))
+		return -EFAULT;
+	len = mbox->cmd.length;
+	if (len && u_data)
+		if(copy_to_user(u_data, (void*)&mbox->data, len))
+			return -EFAULT;
+	return 0;
+}
+
 /****** Network Device Interface ********************************************/
 
 /*============================================================================
@@ -555,14 +627,13 @@
  * Return:	1	physical address resolved.
  *		0	physical address not resolved
  */
-static int if_rebuild_hdr (void* hdr, struct device* dev, unsigned long raddr,
-			   struct sk_buff* skb)
+static int if_rebuild_hdr (struct sk_buff* skb)
 {
-	x25_channel_t* chan = dev->priv;
+	x25_channel_t* chan = skb->dev->priv;
 	sdla_t* card = chan->card;
 
 	printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n",
-		card->devname, dev->name)
+		card->devname, skb->dev->name)
 	;
 	return 1;
 }
@@ -588,7 +659,7 @@
 {
 	x25_channel_t* chan = dev->priv;
 	sdla_t* card = chan->card;
-	int retry = 0, queued = 0;
+	int queued = 0;
 
 	if (test_and_set_bit(0, (void*)&card->wandev.critical))
 	{
@@ -597,7 +668,8 @@
 			card->devname)
 		;
 #endif
-		return 1;
+		dev_kfree_skb(skb, FREE_WRITE);
+		return 0;
 	}
 
 	if (test_and_set_bit(0, (void*)&dev->tbusy))
@@ -608,7 +680,10 @@
 		;
 #endif
 		++chan->ifstats.collisions;
-		retry = 1;
+		++card->wandev.stats.collisions;
+	        dev_kfree_skb(skb, FREE_WRITE);
+	        card->wandev.critical = 0;
+	        return 0;
 	}
 	else if (chan->protocol && (chan->protocol != skb->protocol))
 	{
@@ -646,13 +721,13 @@
 		++chan->ifstats.tx_dropped;
 	}
 
-	if (!retry && !queued)
+	if (!queued)
 	{
 		dev_kfree_skb(skb, FREE_WRITE);
 		dev->tbusy = 0;
 	}
 	card->wandev.critical = 0;
-	return retry;
+	return 0;
 }
 
 /*============================================================================
@@ -996,6 +1071,62 @@
 }
 
 /*============================================================================
+ * Get communications error statistics.
+ */
+static int x25_get_err_stats (sdla_t* card)
+{
+	TX25Mbox* mbox = card->mbox;
+  	int retry = MAX_CMD_RETRY;
+	int err;
+
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+		mbox->cmd.command = X25_HDLC_READ_COMM_ERR;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	} while (err && retry-- &&
+		 x25_error(card, err, X25_HDLC_READ_COMM_ERR, 0))
+	;
+	if (!err)
+	{
+		THdlcCommErr* stats = (void*)mbox->data;
+
+		card->wandev.stats.rx_over_errors    = stats->rxOverrun;
+		card->wandev.stats.rx_crc_errors     = stats->rxBadCrc;
+		card->wandev.stats.rx_missed_errors  = stats->rxAborted;
+		card->wandev.stats.tx_aborted_errors = stats->txAborted;
+	}
+	return err;
+}
+
+/*============================================================================
+ * Get protocol statistics.
+ */
+static int x25_get_stats (sdla_t* card)
+{
+	TX25Mbox* mbox = card->mbox;
+  	int retry = MAX_CMD_RETRY;
+	int err;
+
+	do
+	{
+		memset(&mbox->cmd, 0, sizeof(TX25Cmd));
+		mbox->cmd.command = X25_READ_STATISTICS;
+		err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
+	} while (err && retry-- &&
+		 x25_error(card, err, X25_READ_STATISTICS, 0))
+	;
+	if (!err)
+	{
+		TX25Stats* stats = (void*)mbox->data;
+
+		card->wandev.stats.rx_packets = stats->rxData;
+		card->wandev.stats.tx_packets = stats->rxData;
+	}
+	return err;
+}
+
+/*============================================================================
  * Close HDLC link.
  */
 static int x25_close_hdlc (sdla_t* card)
@@ -1478,6 +1609,10 @@
 		if (strcmp(info->src, chan->addr) == 0)
 			break
 		;
+	        // If just an '@' is specified, accept all incomming calls
+	        if (strcmp(chan->addr, "") == 0)
+	                break
+	        ;
 	}
 
 	if (dev == NULL)
@@ -1755,9 +1890,10 @@
 			printk (KERN_INFO "%s: interface %s disconnected!\n",
 				card->devname, dev->name)
 			;
-			if (chan->svc)
-				*(unsigned short*)dev->dev_addr = 0
-			;
+			if (chan->svc) {
+				*(unsigned short*)dev->dev_addr = 0;
+		                chan->lcn = 0;
+			}
 			break;
 		}
 		chan->state = state;
diff -u --recursive --new-file v2.1.44/linux/drivers/net/sdlamain.c linux/drivers/net/sdlamain.c
--- v2.1.44/linux/drivers/net/sdlamain.c	Tue May 13 22:41:11 1997
+++ linux/drivers/net/sdlamain.c	Wed Jul 16 19:22:51 1997
@@ -26,9 +26,10 @@
 #include <linux/module.h>	/* support for loadable modules */
 #include <linux/ioport.h>	/* request_region(), release_region() */
 #include <linux/tqueue.h>	/* for kernel task queues */
-#include <linux/router.h>	/* WAN router definitions */
+#include <linux/wanrouter.h>	/* WAN router definitions */
 #include <linux/wanpipe.h>	/* WANPIPE common user API definitions */
-#include <asm/segment.h>	/* kernel <-> user copy */
+#include <asm/uaccess.h>	/* kernel <-> user copy */
+
 
 /****** Defines & Macros ****************************************************/
 
@@ -404,20 +405,13 @@
 	unsigned long oldvec;	/* DPM window vector */
 	int err = 0;
 
-	if ((u_dump == NULL) ||
-	    verify_area(VERIFY_READ, u_dump, sizeof(sdla_dump_t)))
-		return -EFAULT
-	;
-	memcpy_fromfs((void*)&dump, (void*)u_dump, sizeof(sdla_dump_t));
+	if(copy_from_user((void*)&dump, (void*)u_dump, sizeof(sdla_dump_t)))
+		return -EFAULT;
+		
 	if ((dump.magic != WANPIPE_MAGIC) ||
 	    (dump.offset + dump.length > card->hw.memory))
-		return -EINVAL
-	;
-	if ((dump.ptr == NULL) ||
-	    verify_area(VERIFY_WRITE, dump.ptr, dump.length))
-		return -EFAULT
-	;
-
+		return -EINVAL;
+		
 	winsize = card->hw.dpmsize;
         cli();				/* >>> critical section start <<< */
 	oldvec = card->hw.vector;
@@ -433,9 +427,12 @@
 			err = -EIO;
 			break;
 		}
-		memcpy_tofs((void*)(dump.ptr),
-			(void*)(card->hw.dpmbase + pos), len)
-		;
+		/* FIXME::: COPY TO KERNEL BUFFER FIRST ?? */
+		sti();	/* Not ideal but tough we have to do this */
+		if(copy_to_user((void*)(dump.ptr),
+			(void*)(card->hw.dpmbase + pos), len))	
+			return -EFAULT;
+		cli();
 		dump.length     -= len;
 		dump.offset     += len;
 		(char*)dump.ptr += len;
@@ -456,16 +453,12 @@
 	sdla_exec_t exec;
 
 	if (card->exec == NULL)
-		return -ENODEV
-	;
-	if ((u_exec == NULL) ||
-	    verify_area(VERIFY_READ, u_exec, sizeof(sdla_exec_t)))
-		return -EFAULT
-	;
-	memcpy_fromfs((void*)&exec, (void*)u_exec, sizeof(sdla_exec_t));
+		return -ENODEV;
+		
+	if(copy_from_user((void*)&exec, (void*)u_exec, sizeof(sdla_exec_t)))
+		return -EFAULT;
 	if ((exec.magic != WANPIPE_MAGIC) || (exec.cmd == NULL))
-		return -EINVAL
-	;
+		return -EINVAL;
 	return card->exec(card, exec.cmd, exec.data);
 }
 
diff -u --recursive --new-file v2.1.44/linux/drivers/net/shaper.c linux/drivers/net/shaper.c
--- v2.1.44/linux/drivers/net/shaper.c	Wed Apr 23 19:01:20 1997
+++ linux/drivers/net/shaper.c	Wed Jul 16 19:22:51 1997
@@ -70,11 +70,11 @@
 #include <linux/if_arp.h>
 #include <linux/init.h>
 #include <net/dst.h>
-#include "shaper.h"
+#include <linux/if_shaper.h>
 
 int sh_debug;		/* Debug flag */
 
-#define SHAPER_BANNER	"CymruNet Traffic Shaper BETA 0.03 for Linux 2.1\n"
+#define SHAPER_BANNER	"CymruNet Traffic Shaper BETA 0.04 for Linux 2.1\n"
 
 /*
  *	Locking
@@ -426,17 +426,26 @@
 	unsigned short type, void *daddr, void *saddr, unsigned len)
 {
 	struct shaper *sh=dev->priv;
+	int v;
 	if(sh_debug)
 		printk("Shaper header\n");
-	return sh->hard_header(skb,sh->dev,type,daddr,saddr,len);
+	skb->dev=sh->dev;
+	v=sh->hard_header(skb,sh->dev,type,daddr,saddr,len);
+	skb->dev=dev;
+	return v;
 }
 
 static int shaper_rebuild_header(struct sk_buff *skb)
 {
 	struct shaper *sh=skb->dev->priv;
+	struct device *dev=skb->dev;
+	int v;
 	if(sh_debug)
 		printk("Shaper rebuild header\n");
-	return sh->rebuild_header(skb);
+	skb->dev=sh->dev;
+	v=sh->rebuild_header(skb);
+	skb->dev=dev;
+	return v;
 }
 
 static int shaper_cache(struct dst_entry *dst, struct neighbour *neigh, struct hh_cache *hh)
@@ -483,6 +492,7 @@
 	else
 		shdev->rebuild_header	= NULL;
 	
+#if 0
 	if(dev->hard_header_cache)
 	{
 		sh->hard_header_cache	= dev->hard_header_cache;
@@ -500,6 +510,10 @@
 	}
 	else
 		shdev->header_cache_update= NULL;
+#else
+	shdev->header_cache_update = NULL;
+	shdev->hard_header_cache = NULL;
+#endif		
 	
 	shdev->hard_header_len=dev->hard_header_len;
 	shdev->type=dev->type;
diff -u --recursive --new-file v2.1.44/linux/drivers/net/shaper.h linux/drivers/net/shaper.h
--- v2.1.44/linux/drivers/net/shaper.h	Mon Apr 14 16:28:12 1997
+++ linux/drivers/net/shaper.h	Wed Dec 31 16:00:00 1969
@@ -1,61 +0,0 @@
-#ifndef __LINUX_SHAPER_H
-#define __LINUX_SHAPER_H
-
-#ifdef __KERNEL__
-
-#define SHAPER_QLEN	10
-/*
- *	This is a bit speed dependant (read it shouldnt be a constant!)
- *
- *	5 is about right for 28.8 upwards. Below that double for every
- *	halving of speed or so. - ie about 20 for 9600 baud.
- */
-#define SHAPER_LATENCY	(5*HZ)
-#define SHAPER_MAXSLIP	2
-#define SHAPER_BURST	(HZ/50)		/* Good for >128K then */
-
-struct shaper
-{
-	struct sk_buff_head sendq;
-	__u32 bytespertick;
-	__u32 shapelatency;
-	__u32 shapeclock;
-	__u32 recovery;		/* Time we can next clock a packet out on
-				   an empty queue */
-	char locked;
-	struct device *dev;
-	int  (*hard_start_xmit) (struct sk_buff *skb,
-		struct device *dev);
-	int  (*hard_header) (struct sk_buff *skb,
-		struct device *dev,
-		unsigned short type,
-		void *daddr,
-		void *saddr,
-		unsigned len);
-	int  (*rebuild_header)(struct sk_buff *skb);
-	int (*hard_header_cache)(struct dst_entry *dst, struct neighbour *neigh,
-		struct hh_cache *hh);
-	void (*header_cache_update)(struct hh_cache *hh, struct device *dev, unsigned char *  haddr);
-	struct net_device_stats* (*get_stats)(struct device *dev);
-	struct wait_queue *wait_queue;
-	struct timer_list timer;
-};
-
-#endif
-
-#define SHAPER_SET_DEV		0x0001
-#define SHAPER_SET_SPEED	0x0002
-
-struct shaperconf
-{
-	__u16	ss_cmd;
-	union
-	{
-		char 	ssu_name[14];
-		__u32	ssu_speed;
-	} ss_u;
-#define ss_speed ss_u.ssu_speed
-#define ss_name ss_u.ssu_name
-};
-
-#endif
diff -u --recursive --new-file v2.1.44/linux/drivers/net/strip.c linux/drivers/net/strip.c
--- v2.1.44/linux/drivers/net/strip.c	Tue May 13 22:41:11 1997
+++ linux/drivers/net/strip.c	Wed Jul 16 19:22:51 1997
@@ -14,53 +14,62 @@
  *		for kernel-based devices like TTY.  It interfaces between a
  *		raw TTY, and the kernel's INET protocol layers (via DDI).
  *
- * Version:	@(#)strip.c	0.9.8	June 1996
+ * Version:	@(#)strip.c	1.2	February 1997
  *
  * Author:	Stuart Cheshire <cheshire@cs.stanford.edu>
  *
- * Fixes:	v0.9 12th Feb 1996.
+ * Fixes:	v0.9 12th Feb 1996 (SC)
  *		New byte stuffing (2+6 run-length encoding)
  *		New watchdog timer task
  *		New Protocol key (SIP0)
  *		
- *		v0.9.1 3rd March 1996
+ *		v0.9.1 3rd March 1996 (SC)
  *		Changed to dynamic device allocation -- no more compile
  *		time (or boot time) limit on the number of STRIP devices.
  *		
- *		v0.9.2 13th March 1996
+ *		v0.9.2 13th March 1996 (SC)
  *		Uses arp cache lookups (but doesn't send arp packets yet)
  *		
- *		v0.9.3 17th April 1996
+ *		v0.9.3 17th April 1996 (SC)
  *		Fixed bug where STR_ERROR flag was getting set unneccessarily
+ *		(causing otherwise good packets to be unneccessarily dropped)
  *		
- *		v0.9.4 27th April 1996
+ *		v0.9.4 27th April 1996 (SC)
  *		First attempt at using "&COMMAND" Starmode AT commands
  *		
- *		v0.9.5 29th May 1996
+ *		v0.9.5 29th May 1996 (SC)
  *		First attempt at sending (unicast) ARP packets
  *		
- *		v0.9.6 5th June 1996
- *		Elliot put "message level" tags in every "printk" statement
+ *		v0.9.6 5th June 1996 (Elliot)
+ *		Put "message level" tags in every "printk" statement
  *		
- *		v0.9.7 13th June 1996
- *		Added support for the /proc fs (laik)
+ *		v0.9.7 13th June 1996 (laik)
+ *		Added support for the /proc fs
  *
- *              v0.9.8 July 1996
- *              Added packet logging (Mema)
- */
-
-/*
- * Undefine this symbol if you don't have PROC_NET_STRIP_STATUS
- * defined in include/linux/proc_fs.h
+ *              v0.9.8 July 1996 (Mema)
+ *              Added packet logging
+ *
+ *              v1.0 November 1996 (SC)
+ *              Fixed (severe) memory leaks in the /proc fs code
+ *              Fixed race conditions in the logging code
+ *
+ *              v1.1 January 1997 (SC)
+ *              Deleted packet logging (use tcpdump instead)
+ *              Added support for Metricom Firmware v204 features
+ *              (like message checksums)
+ *
+ *              v1.2 January 1997 (SC)
+ *              Put portables list back in
  */
 
-#define DO_PROC_NET_STRIP_STATUS 1
-
-/*
- * Define this symbol if you want to enable STRIP packet tracing.
- */
+#ifdef MODULE
+static const char StripVersion[] = "1.2-STUART.CHESHIRE-MODULAR";
+#else
+static const char StripVersion[] = "1.2-STUART.CHESHIRE";
+#endif
 
-#define DO_PROC_NET_STRIP_TRACE 0
+#define TICKLE_TIMERS 0
+#define EXT_COUNTERS 1
 
 
 /************************************************************************/
@@ -146,13 +155,19 @@
     __u8 c[24];
 } MetricomAddressString;
 
+/* Encapsulation can expand packet of size x to 65/64x + 1
+ * Sent packet looks like "<CR>*<address>*<key><encaps payload><CR>"
+ *                           1 1   1-18  1  4         ?         1
+ * eg.                     <CR>*0000-1234*SIP0<encaps payload><CR>
+ * We allow 31 bytes for the stars, the key, the address and the <CR>s
+ */
+#define STRIP_ENCAP_SIZE(X) (32 + (X)*65L/64L)
+
 /*
- * Note: A Metricom packet looks like this: *<address>*<key><payload><CR>
- * eg. *0000-1234*SIP0<payload><CR>
- * A STRIP_Header is never really sent over the radio, but making a dummy header
- * for internal use within the kernel that looks like an Ethernet header makes
- * certain other software happier. For example, tcpdump already understands
- * Ethernet headers.
+ * A STRIP_Header is never really sent over the radio, but making a dummy
+ * header for internal use within the kernel that looks like an Ethernet
+ * header makes certain other software happier. For example, tcpdump
+ * already understands Ethernet headers.
  */
 
 typedef struct
@@ -162,83 +177,20 @@
     unsigned short  protocol;		/* The protocol type, using Ethernet codes */
 } STRIP_Header;
 
-typedef struct GeographicLocation
-{
-    char s[18];
-} GeographicLocation;
-
-typedef enum {
-    NodeValid = 0x1,
-    NodeHasWAN = 0x2,
-    NodeIsRouter = 0x4
-} NodeType;
-
-typedef struct MetricomNode
-{
-    NodeType type;                  /* Some flags about the type of node */
-    GeographicLocation gl;     /* The location of the node. */
-    MetricomAddress addr;      /* The metricom address of this node */
-    int poll_latency;          /* The latency to poll that node ? */
-    int rssi;                  /* The Receiver Signal Strength Indicator */
-    struct MetricomNode *next; /* The next node */
-} MetricomNode;
-
-enum { FALSE = 0, TRUE = 1 };
-
-/*
- * Holds the packet signature for an IP packet.
- */
 typedef struct
 {
-    IPaddr src;
-    /* Data is stored in the following field in network byte order. */
-    __u16 id;
-} IPSignature;
+    char c[60];
+} MetricomNode;
 
-/*
- * Holds the packet signature for an ARP packet.
- */
+#define NODE_TABLE_SIZE 32
 typedef struct
 {
-    IPaddr src;
-    /* Data is stored in the following field in network byte order. */
-    __u16 op;
-} ARPSignature;
-
-/*
- * Holds the signature of a packet.
- */
-typedef union
-{
-    IPSignature ip_sig;
-    ARPSignature arp_sig;
-    __u8 print_sig[6];
-} PacketSignature;
-
-typedef enum {
-    EntrySend = 0,
-    EntryReceive = 1
-} LogEntry;
-
-/* Structure for Packet Logging */
-typedef struct stripLog
-{
-    LogEntry entry_type;
-    u_long seqNum;
-    int packet_type;
-    PacketSignature sig;
-    MetricomAddress src;
-    MetricomAddress dest;
-    struct timeval timeStamp;
-    u_long rawSize;
-    u_long stripSize;
-    u_long slipSize;
-    u_long valid;
-} StripLog;
+    struct timeval timestamp;
+    int            num_nodes;
+    MetricomNode   node[NODE_TABLE_SIZE];
+} MetricomNodeTable;
 
-#define ENTRY_TYPE_TO_STRING(X) ((X) ? "r" : "s")
-
-#define BOOLEAN_TO_STRING(X) ((X) ? "true" : "false")
+enum { FALSE = 0, TRUE = 1 };
 
 /*
  * Holds the radio's firmware version.
@@ -246,7 +198,7 @@
 typedef struct
 {
     char c[50];
-} MetricomFirmwareVersion;
+} FirmwareVersion;
 
 /*
  * Holds the radio's serial number.
@@ -254,7 +206,7 @@
 typedef struct
 {
     char c[18];
-} MetricomSerialNumber;
+} SerialNumber;
 
 /*
  * Holds the radio's battery voltage.
@@ -262,7 +214,19 @@
 typedef struct
 {
     char c[11];
-} MetricomBatteryVoltage;
+} BatteryVoltage;
+
+typedef struct
+{
+    char c[8];
+} char8;
+
+enum
+{
+    NoStructure = 0,		/* Really old firmware */
+    StructuredMessages = 1,	/* Parsable AT response msgs */
+    ChecksummedMessages = 2	/* Parsable AT response msgs with checksums */
+} FirmwareLevel;
 
 struct strip
 {
@@ -292,6 +256,25 @@
     unsigned long      tx_dropped;		/* When MTU change		*/
     unsigned long      rx_over_errors;		/* Frame bigger then STRIP buf. */
 
+    unsigned long      pps_timer;		/* Timer to determine pps	*/
+    unsigned long      rx_pps_count;		/* Counter to determine pps	*/
+    unsigned long      tx_pps_count;		/* Counter to determine pps	*/
+    unsigned long      sx_pps_count;		/* Counter to determine pps	*/
+    unsigned long      rx_average_pps;		/* rx packets per second * 8	*/
+    unsigned long      tx_average_pps;		/* tx packets per second * 8	*/
+    unsigned long      sx_average_pps;		/* sent packets per second * 8	*/
+
+#ifdef EXT_COUNTERS
+    unsigned long      rx_bytes;                /* total received bytes */
+    unsigned long      tx_bytes;                /* total received bytes */
+    unsigned long      rx_rbytes;               /* bytes thru radio i/f */
+    unsigned long      tx_rbytes;               /* bytes thru radio i/f */
+    unsigned long      rx_sbytes;               /* tot bytes thru serial i/f */
+    unsigned long      tx_sbytes;               /* tot bytes thru serial i/f */
+    unsigned long      rx_ebytes;               /* tot stat/err bytes */
+    unsigned long      tx_ebytes;               /* tot stat/err bytes */
+#endif
+
     /*
      * Internal variables.
      */
@@ -300,52 +283,142 @@
     struct strip     **referrer;		/* The pointer that points to us*/
     int                discard;			/* Set if serial error		*/
     int                working;			/* Is radio working correctly?	*/
-    int                structured_messages;	/* Parsable AT response msgs?	*/
+    int                firmware_level;		/* Message structuring level	*/
+    int                next_command;		/* Next periodic command	*/
     int                mtu;			/* Our mtu (to spot changes!)	*/
     long               watchdog_doprobe;	/* Next time to test the radio	*/
     long               watchdog_doreset;	/* Time to do next reset	*/
     long               gratuitous_arp;		/* Time to send next ARP refresh*/
     long               arp_interval;		/* Next ARP interval		*/
     struct timer_list  idle_timer;		/* For periodic wakeup calls	*/
-    MetricomNode      *neighbor_list;		/* The list of neighbor nodes   */
-    int                neighbor_list_locked;    /* Indicates the list is locked */
-    MetricomFirmwareVersion firmware_version;	/* The radio's firmware version */
-    MetricomSerialNumber serial_number;		/* The radio's serial number    */
-    MetricomBatteryVoltage battery_voltage;     /* The radio's battery voltage  */
+    MetricomAddress    true_dev_addr;		/* True address of radio	*/
+    int                manual_dev_addr;		/* Hack: See note below         */
+
+    FirmwareVersion    firmware_version;	/* The radio's firmware version */
+    SerialNumber       serial_number;		/* The radio's serial number    */
+    BatteryVoltage     battery_voltage;		/* The radio's battery voltage  */
 
     /*
      * Other useful structures.
      */
 
     struct tty_struct *tty;			/* ptr to TTY structure		*/
-    char               if_name[8];		/* Dynamically generated name	*/
+    char8              if_name;			/* Dynamically generated name	*/
     struct device      dev;			/* Our device structure		*/
 
     /*
-     * Packet Logging Structures.
+     * Neighbour radio records
      */
 
-    u_long             num_sent;
-    u_long             num_received;
-
-    int next_entry;                            	/* The index of the oldest packet; */
-                                                /* Also the next to be logged. */
-    StripLog packetLog[610];
+    MetricomNodeTable  portables;
+    MetricomNodeTable  poletops;
 };
 
+/*
+ * Note: manual_dev_addr hack
+ * 
+ * It is not possible to change the hardware address of a Metricom radio,
+ * or to send packets with a user-specified hardware source address, thus
+ * trying to manually set a hardware source address is a questionable
+ * thing to do.  However, if the user *does* manually set the hardware
+ * source address of a STRIP interface, then the kernel will believe it,
+ * and use it in certain places. For example, the hardware address listed
+ * by ifconfig will be the manual address, not the true one.
+ * (Both addresses are listed in /proc/net/strip.)
+ * Also, ARP packets will be sent out giving the user-specified address as
+ * the source address, not the real address. This is dangerous, because
+ * it means you won't receive any replies -- the ARP replies will go to
+ * the specified address, which will be some other radio. The case where
+ * this is useful is when that other radio is also connected to the same
+ * machine. This allows you to connect a pair of radios to one machine,
+ * and to use one exclusively for inbound traffic, and the other
+ * exclusively for outbound traffic. Pretty neat, huh?
+ * 
+ * Here's the full procedure to set this up:
+ * 
+ * 1. "slattach" two interfaces, e.g. st0 for outgoing packets,
+ *    and st1 for incoming packets
+ * 
+ * 2. "ifconfig" st0 (outbound radio) to have the hardware address
+ *    which is the real hardware address of st1 (inbound radio).
+ *    Now when it sends out packets, it will masquerade as st1, and
+ *    replies will be sent to that radio, which is exactly what we want.
+ * 
+ * 3. Set the route table entry ("route add default ..." or
+ *    "route add -net ...", as appropriate) to send packets via the st0
+ *    interface (outbound radio). Do not add any route which sends packets
+ *    out via the st1 interface -- that radio is for inbound traffic only.
+ * 
+ * 4. "ifconfig" st1 (inbound radio) to have hardware address zero.
+ *    This tells the STRIP driver to "shut down" that interface and not
+ *    send any packets through it. In particular, it stops sending the
+ *    periodic gratuitous ARP packets that a STRIP interface normally sends.
+ *    Also, when packets arrive on that interface, it will search the
+ *    interface list to see if there is another interface who's manual
+ *    hardware address matches its own real address (i.e. st0 in this
+ *    example) and if so it will transfer ownership of the skbuff to
+ *    that interface, so that it looks to the kernel as if the packet
+ *    arrived on that interface. This is necessary because when the
+ *    kernel sends an ARP packet on st0, it expects to get a reply on
+ *    st0, and if it sees the reply come from st1 then it will ignore
+ *    it (to be accurate, it puts the entry in the ARP table, but
+ *    labelled in such a way that st0 can't use it).
+ * 
+ * Thanks to Petros Maniatis for coming up with the idea of splitting
+ * inbound and outbound traffic between two interfaces, which turned
+ * out to be really easy to implement, even if it is a bit of a hack.
+ * 
+ * Having set a manual address on an interface, you can restore it
+ * to automatic operation (where the address is automatically kept
+ * consistent with the real address of the radio) by setting a manual
+ * address of all ones, e.g. "ifconfig st0 hw strip FFFFFFFFFFFF"
+ * This 'turns off' manual override mode for the device address.
+ * 
+ * Note: The IEEE 802 headers reported in tcpdump will show the *real*
+ * radio addresses the packets were sent and received from, so that you
+ * can see what is really going on with packets, and which interfaces
+ * they are really going through.
+ */
+
 
 /************************************************************************/
 /* Constants								*/
 
-#ifdef MODULE
-static const char StripVersion[] = "0.9.8-STUART.CHESHIRE-MODULAR";
-#else
-static const char StripVersion[] = "0.9.8-STUART.CHESHIRE";
-#endif
-
-static const char TickleString1[] = "***&COMMAND*ATS305?\r";
-static const char TickleString2[] = "***&COMMAND*ATS305?\r\r"
-       "*&COMMAND*ATS300?\r\r*&COMMAND*ATS325?\r\r*&COMMAND*AT~I2 nn\r\r";
+/*
+ * CommandString1 works on all radios
+ * Other CommandStrings are only used with firmware that provides structured responses.
+ * 
+ * ats319=1 Enables Info message for node additions and deletions
+ * ats319=2 Enables Info message for a new best node
+ * ats319=4 Enables checksums
+ * ats319=8 Enables ACK messages
+ */
+
+static const int MaxCommandStringLength = 32;
+static const int CompatibilityCommand = 1;
+
+static const char CommandString0[] = "*&COMMAND*ATS319=7";	/* Turn on checksums & info messages */
+static const char CommandString1[] = "*&COMMAND*ATS305?";	/* Query radio name */
+static const char CommandString2[] = "*&COMMAND*ATS325?";	/* Query battery voltage */
+static const char CommandString3[] = "*&COMMAND*ATS300?";	/* Query version information */
+static const char CommandString4[] = "*&COMMAND*ATS311?";	/* Query poletop list */
+static const char CommandString5[] = "*&COMMAND*AT~LA";		/* Query portables list */
+typedef struct { const char *string; long length; } StringDescriptor;
+
+static const StringDescriptor CommandString[] =
+    {
+    { CommandString0, sizeof(CommandString0)-1 },
+    { CommandString1, sizeof(CommandString1)-1 },
+    { CommandString2, sizeof(CommandString2)-1 },
+    { CommandString3, sizeof(CommandString3)-1 },
+    { CommandString4, sizeof(CommandString4)-1 },
+    { CommandString5, sizeof(CommandString5)-1 }
+    };
+
+#define GOT_ALL_RADIO_INFO(S)      \
+    ((S)->firmware_version.c[0] && \
+     (S)->battery_voltage.c[0]  && \
+     memcmp(&(S)->true_dev_addr, zero_address.c, sizeof(zero_address)))
 
 static const char            hextable[16]      = "0123456789ABCDEF";
 
@@ -354,26 +427,27 @@
 
 static const MetricomKey     SIP0Key           = { { "SIP0" } };
 static const MetricomKey     ARP0Key           = { { "ARP0" } };
-static const MetricomKey     ERR_Key           = { { "ERR_" } };
 static const MetricomKey     ATR_Key           = { { "ATR " } };
+static const MetricomKey     ACK_Key           = { { "ACK_" } };
+static const MetricomKey     INF_Key           = { { "INF_" } };
+static const MetricomKey     ERR_Key           = { { "ERR_" } };
 
 static const long            MaxARPInterval    = 60 * HZ;          /* One minute */
 
 /*
- * Maximum Starmode packet length (including starmode address) is 1183 bytes.
- * Allowing 32 bytes for header, and 65/64 expansion for STRIP encoding,
- * that translates to a maximum payload MTU of 1132.
- */
-static const unsigned short  MAX_STRIP_MTU          = 1132;
-static const unsigned short  DEFAULT_STRIP_MTU      = 1024;
+ * Maximum Starmode packet length is 1183 bytes. Allowing 4 bytes for
+ * protocol key, 4 bytes for checksum, one byte for CR, and 65/64 expansion
+ * for STRIP encoding, that translates to a maximum payload MTU of 1155.
+ * Note: A standard NFS 1K data packet is a total of 0x480 (1152) bytes
+ * long, including IP header, UDP header, and NFS header. Setting the STRIP
+ * MTU to 1152 allows us to send default sized NFS packets without fragmentation.
+ */
+static const unsigned short  MAX_SEND_MTU          = 1152;
+static const unsigned short  MAX_RECV_MTU          = 1500; /* Hoping for Ethernet sized packets in the future! */
+static const unsigned short  DEFAULT_STRIP_MTU      = 1152;
 static const int             STRIP_MAGIC            = 0x5303;
 static const long            LongTime               = 0x7FFFFFFF;
 
-static const int             STRIP_NODE_LEN         = 64;
-static const char            STRIP_PORTABLE_CHAR    = 'P';
-static const char            STRIP_ROUTER_CHAR      = 'r';
-static const int             STRIP_PROC_BUFFER_SIZE = 4096;
-static const int             STRIP_LOG_INT_SIZE     = 10;
 
 /************************************************************************/
 /* Global variables							*/
@@ -384,10 +458,18 @@
 /************************************************************************/
 /* Macros								*/
 
+/* Returns TRUE if text T begins with prefix P */
+#define has_prefix(T,P) (!strncmp((T), (P), sizeof(P)-1))
+
+/* Returns TRUE if text T of length L is equal to string S */
+#define text_equal(T,L,S) (((L) == sizeof(S)-1) && !strncmp((T), (S), sizeof(S)-1))
+
 #define READHEX(X) ((X)>='0' && (X)<='9' ? (X)-'0' :      \
                     (X)>='a' && (X)<='f' ? (X)-'a'+10 :   \
                     (X)>='A' && (X)<='F' ? (X)-'A'+10 : 0 )
 
+#define READHEX16(X) ((__u16)(READHEX(X)))
+
 #define READDEC(X) ((X)>='0' && (X)<='9' ? (X)-'0' : 0)
 
 #define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
@@ -395,17 +477,6 @@
 #define ELEMENTS_OF(X) (sizeof(X) / sizeof((X)[0]))
 #define ARRAY_END(X) (&((X)[ELEMENTS_OF(X)]))
 
-/* Encapsulation can expand packet of size x to 65/64x + 1              */
-/* Sent packet looks like "*<address>*<key><encaps payload><CR>"        */
-/*                         1   1-18  1  4         ?         1           */
-/* We allow 31 bytes for the stars, the key, the address and the <CR>   */
-#define STRIP_ENCAP_SIZE(X) (32 + (X)*65L/64L)
-
-#define IS_RADIO_ADDRESS(p) (                                                   \
-    isdigit((p)[0]) && isdigit((p)[1]) && isdigit((p)[2]) && isdigit((p)[3]) && \
-    (p)[4] == '-' &&                                                            \
-    isdigit((p)[5]) && isdigit((p)[6]) && isdigit((p)[7]) && isdigit((p)[8])    )
-
 #define JIFFIE_TO_SEC(X) ((X) / HZ)
 
 
@@ -605,7 +676,15 @@
                 }
                 /* else, we only have one so far, so switch to Stuff_Diff code */
                 code = Stuff_Diff;
-                /* and fall through to Stuff_Diff case below */
+                /* and fall through to Stuff_Diff case below
+                 * Note cunning cleverness here: case Stuff_Diff compares 
+                 * the current character with the previous two to see if it
+                 * has a run of three the same. Won't this be an error if
+                 * there aren't two previous characters stored to compare with?
+                 * No. Because we know the current character is *not* the same
+                 * as the previous one, the first test below will necessarily
+                 * fail and the send half of the "if" won't be executed.
+                 */
 
             /* Stuff_Diff: We have at least two *different* bytes encoded */
             case Stuff_Diff:
@@ -639,10 +718,10 @@
                 src++;    /* Consume the byte */
                 break;
         }
-    if (count == Stuff_MaxCount)
-    {
-        StuffData_FinishBlock(code + count);
-    }
+        if (count == Stuff_MaxCount)
+        {
+            StuffData_FinishBlock(code + count);
+        }
     }
     if (code == Stuff_NoCode)
     {
@@ -758,14 +837,21 @@
  * Convert a string to a Metricom Address.
  */
 
-static void string_to_radio_address(MetricomAddress *addr, __u8 *p)
+#define IS_RADIO_ADDRESS(p) (                                                 \
+  isdigit((p)[0]) && isdigit((p)[1]) && isdigit((p)[2]) && isdigit((p)[3]) && \
+  (p)[4] == '-' &&                                                            \
+  isdigit((p)[5]) && isdigit((p)[6]) && isdigit((p)[7]) && isdigit((p)[8])    )
+
+static int string_to_radio_address(MetricomAddress *addr, __u8 *p)
 {
+    if (!IS_RADIO_ADDRESS(p)) return(1);
     addr->c[0] = 0;
     addr->c[1] = 0;
     addr->c[2] = READHEX(p[0]) << 4 | READHEX(p[1]);
     addr->c[3] = READHEX(p[2]) << 4 | READHEX(p[3]);
     addr->c[4] = READHEX(p[5]) << 4 | READHEX(p[6]);
     addr->c[5] = READHEX(p[7]) << 4 | READHEX(p[8]);
+    return(0);
 }
 
 /*
@@ -780,19 +866,18 @@
 
 /*
  * Note: Must make sure sx_size is big enough to receive a stuffed
- * MAX_STRIP_MTU packet. Additionally, we also want to ensure that it's
+ * MAX_RECV_MTU packet. Additionally, we also want to ensure that it's
  * big enough to receive a large radio neighbour list (currently 4K).
  */
 
 static int allocate_buffers(struct strip *strip_info)
 {
     struct device *dev = &strip_info->dev;
-    int stuffedlen = STRIP_ENCAP_SIZE(dev->mtu);
-    int sx_size    = MAX(stuffedlen, 4096);
-    int tx_size    = stuffedlen + sizeof(TickleString2);
-    __u8 *r = kmalloc(MAX_STRIP_MTU, GFP_ATOMIC);
-    __u8 *s = kmalloc(sx_size,       GFP_ATOMIC);
-    __u8 *t = kmalloc(tx_size,       GFP_ATOMIC);
+    int sx_size    = MAX(STRIP_ENCAP_SIZE(MAX_RECV_MTU), 4096);
+    int tx_size    = STRIP_ENCAP_SIZE(dev->mtu) + MaxCommandStringLength;
+    __u8 *r = kmalloc(MAX_RECV_MTU, GFP_ATOMIC);
+    __u8 *s = kmalloc(sx_size,      GFP_ATOMIC);
+    __u8 *t = kmalloc(tx_size,      GFP_ATOMIC);
     if (r && s && t)
     {
         strip_info->rx_buff = r;
@@ -824,10 +909,10 @@
     unsigned char *otbuff = strip_info->tx_buff;
     InterruptStatus intstat;
 
-    if (dev->mtu > MAX_STRIP_MTU)
+    if (dev->mtu > MAX_SEND_MTU)
     {
         printk(KERN_ERR "%s: MTU exceeds maximum allowable (%d), MTU change cancelled.\n",
-            strip_info->dev.name, MAX_STRIP_MTU);
+            strip_info->dev.name, MAX_SEND_MTU);
         dev->mtu = old_mtu;
         return;
     }
@@ -856,9 +941,8 @@
             memcpy(strip_info->sx_buff, osbuff, strip_info->sx_count);
         else
         {
-            strip_info->sx_count = 0;
+            strip_info->discard = strip_info->sx_count;
             strip_info->rx_over_errors++;
-            strip_info->discard = 1;
         }
     }
 
@@ -889,7 +973,7 @@
     /*
      * Set the time to go off in one second.
      */
-    strip_info->idle_timer.expires  = jiffies + HZ;
+    strip_info->idle_timer.expires  = jiffies + 1*HZ;
     add_timer(&strip_info->idle_timer);
     if (!test_and_clear_bit(0, (void *)&strip_info->dev.tbusy))
         printk(KERN_ERR "%s: trying to unlock already unlocked device!\n",
@@ -900,8 +984,6 @@
 /************************************************************************/
 /* Callback routines for exporting information through /proc		*/
 
-#if DO_PROC_NET_STRIP_STATUS | DO_PROC_NET_STRIP_TRACE
-
 /*
  * This function updates the total amount of data printed so far. It then
  * determines if the amount of data printed into a buffer  has reached the
@@ -912,29 +994,29 @@
  */
 static int 
 shift_buffer(char *buffer, int requested_offset, int requested_len,
-	     int *total, int *slop, char **buf)
+             int *total, int *slop, char **buf)
 {
     int printed;
 
     /* printk(KERN_DEBUG "shift: buffer: %d o: %d l: %d t: %d buf: %d\n",
-	   (int) buffer, requested_offset, requested_len, *total,
-	   (int) *buf); */
+           (int) buffer, requested_offset, requested_len, *total,
+           (int) *buf); */
     printed = *buf - buffer;
     if (*total + printed <= requested_offset) {
-	*total += printed;
-	*buf = buffer;
+        *total += printed;
+        *buf = buffer;
     }
     else {
-	if (*total < requested_offset) {
-	    *slop = requested_offset - *total;
-	}
-	*total = requested_offset + printed - *slop;
+        if (*total < requested_offset) {
+            *slop = requested_offset - *total;
+        }
+        *total = requested_offset + printed - *slop;
     }
     if (*total > requested_offset + requested_len) {
-	return 1;
+        return 1;
     }
     else {
-	return 0;
+        return 0;
     }
 }
 
@@ -945,12 +1027,12 @@
  */
 static int
 calc_start_len(char *buffer, char **start, int requested_offset,
-	       int requested_len, int total, char *buf)
+               int requested_len, int total, char *buf)
 {
     int return_len, buffer_len;
 
     buffer_len = buf - buffer;
-    if (buffer_len >= STRIP_PROC_BUFFER_SIZE - 1) {
+    if (buffer_len >= 4095) {
  	printk(KERN_ERR "STRIP: exceeded /proc buffer size\n");
     }
 
@@ -960,20 +1042,16 @@
      */
     return_len = total - requested_offset;
     if (return_len < 0) {
-	return_len = 0;
+        return_len = 0;
     }
     *start = buf - return_len;
     if (return_len > requested_len) {
-	return_len = requested_len;
+        return_len = requested_len;
     }
     /* printk(KERN_DEBUG "return_len: %d\n", return_len); */
     return return_len;
 }
 
-#endif DO_PROC_NET_STRIP_STATUS | DO_PROC_NET_STRIP_TRACE
-
-#if DO_PROC_NET_STRIP_STATUS
-
 /*
  * If the time is in the near future, time_delta prints the number of
  * seconds to go into the buffer and returns the address of the buffer.
@@ -991,537 +1069,171 @@
     return(buffer);
 }
 
-/*
- * This function prints radio status information into the specified
- * buffer.
- */
-static int
-sprintf_status_info(char *buffer, struct strip *strip_info)
+static int sprintf_neighbours(char *buffer, MetricomNodeTable *table, char *title)
 {
-    char temp_buffer[32];
-    MetricomAddressString addr_string;
-    char *buf;
-
-    buf = buffer;
-    buf += sprintf(buf, "Interface name\t\t%s\n", strip_info->if_name);
-    buf += sprintf(buf, " Radio working:\t\t%s\n",
-		   strip_info->working &&
-                   (long)jiffies - strip_info->watchdog_doreset < 0 ? "Yes" : "No");
-    (void) radio_address_to_string((MetricomAddress *)
-				   &strip_info->dev.dev_addr,
-				   &addr_string);
-    buf += sprintf(buf, " Device address:\t%s\n", addr_string.c);
-    buf += sprintf(buf, " Firmware version:\t%s\n",
-		   !strip_info->working             ? "Unknown" :
-		   !strip_info->structured_messages ? "Should be upgraded" :
-		   strip_info->firmware_version.c);
-    buf += sprintf(buf, " Serial number:\t\t%s\n", strip_info->serial_number.c);
-    buf += sprintf(buf, " Battery voltage:\t%s\n", strip_info->battery_voltage.c);
-    buf += sprintf(buf, " Transmit queue (bytes):%d\n", strip_info->tx_left);
-    buf += sprintf(buf, " Next watchdog probe:\t%s\n",
-		   time_delta(temp_buffer, strip_info->watchdog_doprobe));
-    buf += sprintf(buf, " Next watchdog reset:\t%s\n",
-		   time_delta(temp_buffer, strip_info->watchdog_doreset));
-    buf += sprintf(buf, " Next gratuitous ARP:\t%s\n",
-		   time_delta(temp_buffer, strip_info->gratuitous_arp));
-    buf += sprintf(buf, " Next ARP interval:\t%ld seconds\n",
-		   JIFFIE_TO_SEC(strip_info->arp_interval));
-    return buf - buffer;
-}
-
-static int
-sprintf_portables(char *buffer, struct strip *strip_info)
-{
-
-    MetricomAddressString addr_string;
-    MetricomNode          *node;
-    char *buf;
-
-    buf = buffer;
-    buf += sprintf(buf, " portables: name\t\tpoll_latency\tsignal strength\n");
-    for (node = strip_info->neighbor_list; node != NULL;
-	 node = node->next) {
-	if (!(node->type & NodeValid)) {
-	    break;
-	}
-	if (node->type & NodeHasWAN) {
-	    continue;
-	}
-	(void) radio_address_to_string(&node->addr, &addr_string);
-	buf += sprintf(buf, "  %s\t\t\t\t%d\t\t%d\n",
-		       addr_string.c, node->poll_latency, node->rssi);
-    }
-    return buf - buffer;
-}
-
-static int
-sprintf_poletops(char *buffer, struct strip *strip_info)
-{
-    MetricomNode    *node;
-    char *buf;
-
-    buf = buffer;
-    buf += sprintf(buf, " poletops: GPS\t\t\tpoll_latency\tsignal strength\n");
-    for (node = strip_info->neighbor_list;
-	 node != NULL; node = node->next) {
-	if (!(node->type & NodeValid)) {
-	    break;
-	}
-	if (!(node->type & NodeHasWAN)) {
-	    continue;
-	}
-	buf += sprintf(buf, "  %s\t\t\t%d\t\t%d\n",
-		       node->gl.s, node->poll_latency, node->rssi);
-    }
-    return buf - buffer;
+    /* We wrap this in a do/while loop, so if the table changes */
+    /* while we're reading it, we just go around and try again. */
+    struct timeval t;
+    char *ptr;
+    do
+        {
+        int i;
+        t = table->timestamp;
+        ptr = buffer;
+        if (table->num_nodes) ptr += sprintf(ptr, "\n %s\n", title);
+        for (i=0; i<table->num_nodes; i++)
+            {
+            InterruptStatus intstat = DisableInterrupts();
+            MetricomNode node = table->node[i];
+            RestoreInterrupts(intstat);
+            ptr += sprintf(ptr, "  %s\n", node.c);
+            }
+        } while (table->timestamp.tv_sec != t.tv_sec || table->timestamp.tv_usec != t.tv_usec);
+    return ptr - buffer;
 }
 
 /*
- * This function is exports status information from the STRIP driver through
- * the /proc file system. /proc filesystem should be fixed:
- *    1) slow (sprintfs here, a memory copy in the proc that calls this one)
- *    2) length of buffer not passed
- *    3) dummy isn't client data set when the callback was registered
- *    4) poorly documented (this function is called until the requested amount
- *       of data is returned, buffer is only 4K long, dummy is the permissions
- *       of the file (?), the proc_dir_entry passed to proc_net_register must
- *       be kmalloc-ed)
- */
-
-static int
-strip_get_status_info(char *buffer, char **start, off_t requested_offset,
-		      int requested_len, int dummy)
-{
-    char            *buf;
-    int             total = 0, slop = 0, len_exceeded;
-    InterruptStatus i_status;
-    struct strip    *strip_info;
-
-    buf = buffer;
-    buf += sprintf(buf, "strip_version: %s\n", StripVersion);
-
-    i_status = DisableInterrupts();
-    strip_info = struct_strip_list;
-    RestoreInterrupts(i_status);
-
-    while (strip_info != NULL) {
-	i_status = DisableInterrupts();
-	buf += sprintf_status_info(buf, strip_info);
-	RestoreInterrupts(i_status);
-	len_exceeded = shift_buffer(buffer, requested_offset, requested_len,
-				    &total, &slop, &buf);
-	if (len_exceeded) {
-	    goto done;
-	}
-	strip_info->neighbor_list_locked = TRUE;
-	buf += sprintf_portables(buf, strip_info);
-	strip_info->neighbor_list_locked = FALSE;
-	len_exceeded = shift_buffer(buffer, requested_offset, requested_len,
-				    &total, &slop, &buf);
-	if (len_exceeded) {
-	    goto done;
-	}
-	strip_info->neighbor_list_locked = TRUE;
-	buf += sprintf_poletops(buf, strip_info);
-	strip_info->neighbor_list_locked = FALSE;
-	len_exceeded = shift_buffer(buffer, requested_offset, requested_len,
-				    &total, &slop, &buf);
-	if (len_exceeded) {
-	    goto done;
-	}
-	strip_info = strip_info->next;
-    }
-done:
-    return calc_start_len(buffer, start, requested_offset, requested_len,
-				total, buf);
-}
-
-#endif DO_PROC_NET_STRIP_STATUS
-
-#if DO_PROC_NET_STRIP_TRACE
-
-/*
- * Convert an Ethernet protocol to a string
- * Returns the number of characters printed.
+ * This function prints radio status information into the specified buffer.
+ * I think the buffer size is 4K, so this routine should never print more
+ * than 4K of data into it. With the maximum of 32 portables and 32 poletops
+ * reported, the routine outputs 3107 bytes into the buffer.
  */
-
-static int protocol_to_string(int protocol, __u8 *p)
-{
-    int printed;
-
-    switch (protocol) {
-    case ETH_P_IP:
-	printed = sprintf(p, "IP");
-	break;
-    case ETH_P_ARP:
-	printed = sprintf(p, "ARP");
-	break;
-    default: 
-	printed = sprintf(p, "%d", protocol);
-    }
-    return printed;
-}
-
 static int
-sprintf_log_entry(char *buffer, struct strip *strip_info, int packet_index)
+sprintf_status_info(char *buffer, struct strip *strip_info)
 {
-    StripLog *entry;
+    char temp[32];
+    char *p = buffer;
     MetricomAddressString addr_string;
-    __u8     sig_buf[24], *s;
-    char     *buf, proto_buf[10];
-
-    entry = &strip_info->packetLog[packet_index];
-    if (!entry->valid) {
-	return 0;
-    }
-    buf = buffer;
-    buf += sprintf(buf, "%-4s %s   %7lu ", strip_info->if_name,
-		   ENTRY_TYPE_TO_STRING(entry->entry_type), entry->seqNum);
-    (void) protocol_to_string(entry->packet_type, proto_buf);
-    buf += sprintf(buf, "%-4s", proto_buf);
-    s = entry->sig.print_sig;
-    sprintf(sig_buf, "%d.%d.%d.%d.%d.%d", s[0], s[1], s[2], s[3], s[4], s[5]);
-    buf += sprintf(buf, "%-24s", sig_buf);
-    (void) radio_address_to_string((MetricomAddress *) &entry->src,
-				   &addr_string);
-    buf += sprintf(buf, "%-10s", addr_string.c);
-    (void) radio_address_to_string((MetricomAddress *) &entry->dest,
-				   &addr_string);
-    buf += sprintf(buf, "%-10s", addr_string.c);
-    buf += sprintf(buf, "%8d %6d %5lu %6lu %5lu\n", entry->timeStamp.tv_sec,
-		   entry->timeStamp.tv_usec, entry->rawSize,
-		   entry->stripSize, entry->slipSize);
-    return buf - buffer;
-}
 
-/*
- * This function exports trace information from the STRIP driver through the
- * /proc file system.
- */
+    /* First, we must copy all of our data to a safe place, */
+    /* in case a serial interrupt comes in and changes it.  */
+    InterruptStatus intstat = DisableInterrupts();
+    int                tx_left             = strip_info->tx_left;
+    unsigned long      rx_average_pps      = strip_info->rx_average_pps;
+    unsigned long      tx_average_pps      = strip_info->tx_average_pps;
+    unsigned long      sx_average_pps      = strip_info->sx_average_pps;
+    int                working             = strip_info->working;
+    int                firmware_level      = strip_info->firmware_level;
+    long               watchdog_doprobe    = strip_info->watchdog_doprobe;
+    long               watchdog_doreset    = strip_info->watchdog_doreset;
+    long               gratuitous_arp      = strip_info->gratuitous_arp;
+    long               arp_interval        = strip_info->arp_interval;
+    FirmwareVersion    firmware_version    = strip_info->firmware_version;
+    SerialNumber       serial_number       = strip_info->serial_number;
+    BatteryVoltage     battery_voltage     = strip_info->battery_voltage;
+    char8              if_name             = strip_info->if_name;
+    MetricomAddress    true_dev_addr       = strip_info->true_dev_addr;
+    MetricomAddress    dev_dev_addr        = *(MetricomAddress*)strip_info->dev.dev_addr;
+    int                manual_dev_addr     = strip_info->manual_dev_addr;
+#ifdef EXT_COUNTERS
+    unsigned long      rx_bytes            = strip_info->rx_bytes;
+    unsigned long      tx_bytes            = strip_info->tx_bytes;
+    unsigned long      rx_rbytes           = strip_info->rx_rbytes;
+    unsigned long      tx_rbytes           = strip_info->tx_rbytes;
+    unsigned long      rx_sbytes           = strip_info->rx_sbytes;
+    unsigned long      tx_sbytes           = strip_info->tx_sbytes;
+    unsigned long      rx_ebytes           = strip_info->rx_ebytes;
+    unsigned long      tx_ebytes           = strip_info->tx_ebytes;
+#endif
+    RestoreInterrupts(intstat);
 
-static int
-strip_get_trace_info(char *buffer, char **start, off_t requested_offset,
-		     int requested_len, int dummy)
-{
-    char            *buf;
-    int             len_exceeded, total = 0, slop = 0, packet_index, oldest;
-    InterruptStatus i_status;
-    struct strip    *strip_info;
-
-    buf = buffer;
-    buf += sprintf(buf, "if   s/r seqnum  t   signature               ");
-    buf += sprintf(buf,
-		   "src       dest      sec      usec   raw   strip  slip\n");
-
-    i_status = DisableInterrupts();
-    strip_info = struct_strip_list;
-    oldest = strip_info->next_entry;
-    RestoreInterrupts(i_status);
-
-    /*
-     * If we disable interrupts for this entire loop,
-     * characters from the serial port could be lost,
-     * so we only disable interrupts when accessing
-     * a log entry. If more than STRIP_LOG_INT_SIZE
-     * packets are logged before the first entry is
-     * printed, then some of the entries could be
-     * printed out of order.
-     */
-    while (strip_info != NULL) {
-	for (packet_index = oldest + STRIP_LOG_INT_SIZE;
-	     packet_index != oldest;
-	     packet_index = (packet_index + 1) %
-		 ELEMENTS_OF(strip_info->packetLog)) {
-	    i_status = DisableInterrupts();
-	    buf += sprintf_log_entry(buf, strip_info, packet_index);
-	    RestoreInterrupts(i_status);
-	    len_exceeded = shift_buffer(buffer, requested_offset,
-					requested_len, &total, &slop, &buf);
-	    if (len_exceeded) {
-		goto done;
-	    }
-	}
-	strip_info = strip_info->next;
-    }
-done:
-    return calc_start_len(buffer, start, requested_offset, requested_len,
-			  total, buf);
-}
+    p += sprintf(p, "\nInterface name\t\t%s\n", if_name.c);
+    p += sprintf(p, " Radio working:\t\t%s\n", working ? "Yes" : "No");
+    radio_address_to_string(&true_dev_addr, &addr_string);
+    p += sprintf(p, " Radio address:\t\t%s\n", addr_string.c);
+    if (manual_dev_addr)
+    {
+        radio_address_to_string(&dev_dev_addr, &addr_string);
+        p += sprintf(p, " Device address:\t%s\n", addr_string.c);
+    }
+    p += sprintf(p, " Firmware version:\t%s", !working        ? "Unknown" :
+                                              !firmware_level ? "Should be upgraded" :
+                                              firmware_version.c);
+    if (firmware_level >= ChecksummedMessages) p += sprintf(p, " (Checksums Enabled)");
+    p += sprintf(p, "\n");
+    p += sprintf(p, " Serial number:\t\t%s\n", serial_number.c);
+    p += sprintf(p, " Battery voltage:\t%s\n", battery_voltage.c);
+    p += sprintf(p, " Transmit queue (bytes):%d\n", tx_left);
+    p += sprintf(p, " Receive packet rate:   %ld packets per second\n", rx_average_pps / 8);
+    p += sprintf(p, " Transmit packet rate:  %ld packets per second\n", tx_average_pps / 8);
+    p += sprintf(p, " Sent packet rate:      %ld packets per second\n", sx_average_pps / 8);
+    p += sprintf(p, " Next watchdog probe:\t%s\n", time_delta(temp, watchdog_doprobe));
+    p += sprintf(p, " Next watchdog reset:\t%s\n", time_delta(temp, watchdog_doreset));
+    p += sprintf(p, " Next gratuitous ARP:\t");
 
-static int slip_len(unsigned char *data, int len)
-{
-    static const unsigned char SLIP_END=0300;	/* indicates end of SLIP frame	*/
-    static const unsigned char SLIP_ESC=0333;	/* indicates SLIP byte stuffing	*/
-    int count = len;
-    while (--len >= 0)
+    if (!memcmp(strip_info->dev.dev_addr, zero_address.c, sizeof(zero_address)))
+        p += sprintf(p, "Disabled\n");
+    else
     {
-	if (*data == SLIP_END || *data == SLIP_ESC) count++;
-	data++;
+        p += sprintf(p, "%s\n", time_delta(temp, gratuitous_arp));
+        p += sprintf(p, " Next ARP interval:\t%ld seconds\n", JIFFIE_TO_SEC(arp_interval));
     }
-    return(count);
-}
-
-/* Copied from kernel/sched.c */
-static void jiffiestotimeval(unsigned long jiffies, struct timeval *value)
-{
-    value->tv_usec = (jiffies % HZ) * (1000000.0 / HZ);
-    value->tv_sec = jiffies / HZ;
-    return;
-}
 
-/*
- * This function logs a packet.
- * A pointer to the packet itself is passed so that some of the data can be
- * used to compute a signature. The pointer should point the the
- * part of the packet following the STRIP_header.
- */
-
-static void packet_log(struct strip *strip_info, __u8 *packet,
-		       LogEntry entry_type, STRIP_Header *hdr, 
-		       int raw_size, int strip_size, int slip_size)
-{
-    StripLog *entry;
-    struct iphdr *iphdr;
-    struct arphdr *arphdr;
-
-    entry = &strip_info->packetLog[strip_info->next_entry];
-    if (entry_type == EntrySend) {
-	entry->seqNum = strip_info->num_sent++;
-    }
-    else {
-	entry->seqNum = strip_info->num_received++;
-    }
-    entry->entry_type = entry_type;
-    entry->packet_type = ntohs(hdr->protocol);
-    switch (entry->packet_type) {
-    case ETH_P_IP:
-	/*
-	 * The signature for IP is the sender's ip address and
-	 * the identification field.
-	 */
-	iphdr = (struct iphdr *) packet;
-	entry->sig.ip_sig.id = iphdr->id;
-	entry->sig.ip_sig.src.l = iphdr->saddr;
-	break;
-    case ETH_P_ARP:
-	/*
-	 * The signature for ARP is the sender's ip address and
-	 * the operation.
-	 */
-	arphdr = (struct arphdr *) packet;
-	entry->sig.arp_sig.op = arphdr->ar_op;
-        memcpy(&entry->sig.arp_sig.src.l, packet + 8 + arphdr->ar_hln,
-	       sizeof(entry->sig.arp_sig.src.l));
-        entry->sig.arp_sig.src.l = entry->sig.arp_sig.src.l;
-	break;
-    default:
-	printk(KERN_DEBUG "STRIP: packet_log: unknown packet type: %d\n",
-	       entry->packet_type);
-	break;
-    }
-    memcpy(&entry->src, &hdr->src_addr, sizeof(MetricomAddress));
-    memcpy(&entry->dest, &hdr->dst_addr, sizeof(MetricomAddress));
-
-    jiffiestotimeval(jiffies, &(entry->timeStamp));
-    entry->rawSize = raw_size;
-    entry->stripSize = strip_size;
-    entry->slipSize = slip_size;
-    entry->valid = 1;
+    if (working)
+        {
+#ifdef EXT_COUNTERS
+          p += sprintf(p, "\n");
+          p += sprintf(p, " Total bytes:         \trx:\t%lu\ttx:\t%lu\n", rx_bytes, tx_bytes);
+          p += sprintf(p, "  thru radio:         \trx:\t%lu\ttx:\t%lu\n", rx_rbytes, tx_rbytes);
+          p += sprintf(p, "  thru serial port:   \trx:\t%lu\ttx:\t%lu\n", rx_sbytes, tx_sbytes);
+          p += sprintf(p, " Total stat/err bytes:\trx:\t%lu\ttx:\t%lu\n", rx_ebytes, tx_ebytes);
+#endif
+        p += sprintf_neighbours(p, &strip_info->poletops, "Poletops:");
+        p += sprintf_neighbours(p, &strip_info->portables, "Portables:");
+        }
 
-    strip_info->next_entry = (strip_info->next_entry + 1) %
-	ELEMENTS_OF(strip_info->packetLog);
+    return p - buffer;
 }
 
-#endif DO_PROC_NET_STRIP_TRACE
-
 /*
- * This function parses the response to the ATS300? command,
- * extracting the radio version and serial number.
+ * This function is exports status information from the STRIP driver through
+ * the /proc file system.
  */
-static void get_radio_version(struct strip *strip_info, __u8 *ptr, __u8 *end)
-{
-    __u8 *p, *value_begin, *value_end;
-    int len;
-    
-    /* Determine the beginning of the second line of the payload */
-    p = ptr;
-    while (p < end && *p != 10) p++;
-    if (p >= end) return;
-    p++;
-    value_begin = p;
-    
-    /* Determine the end of line */
-    while (p < end && *p != 10) p++;
-    if (p >= end) return;
-    value_end = p;
-    p++;
-     
-    len = value_end - value_begin;
-    len = MIN(len, sizeof(MetricomFirmwareVersion) - 1);
-    sprintf(strip_info->firmware_version.c, "%.*s", len, value_begin);
-    
-    /* Look for the first colon */
-    while (p < end && *p != ':') p++;
-    if (p >= end) return;
-    /* Skip over the space */
-    p += 2;
-    len = sizeof(MetricomSerialNumber) - 1;
-    if (p + len <= end) {
-	sprintf(strip_info->serial_number.c, "%.*s", len, p);
-    }
-    else {
-     	printk(KERN_ERR "STRIP: radio serial number shorter (%d) than expected (%d)\n",
-     	       end - p, len);
-    }
-}
 
-/*
- * This function parses the response to the ATS325? command,
- * extracting the radio battery voltage.
- */
-static void get_radio_voltage(struct strip *strip_info, __u8 *ptr, __u8 *end)
+static int get_status_info(char *buffer, char **start, off_t req_offset, int req_len, int dummy)
 {
-    int len;
+    int           total = 0, slop = 0;
+    struct strip *strip_info = struct_strip_list;
+    char         *buf = buffer;
 
-    len = sizeof(MetricomBatteryVoltage) - 1;
-    if (ptr + len <= end) {
-	sprintf(strip_info->battery_voltage.c, "%.*s", len, ptr);
-    }
-    else {
- 	printk(KERN_ERR "STRIP: radio voltage string shorter (%d) than expected (%d)\n",
- 	       end - ptr, len);
-    }
+    buf += sprintf(buf, "strip_version: %s\n", StripVersion);
+    if (shift_buffer(buffer, req_offset, req_len, &total, &slop, &buf)) goto exit;
+
+    while (strip_info != NULL)
+        {
+        buf += sprintf_status_info(buf, strip_info);
+        if (shift_buffer(buffer, req_offset, req_len, &total, &slop, &buf)) break;
+        strip_info = strip_info->next;
+        }
+    exit:
+    return(calc_start_len(buffer, start, req_offset, req_len, total, buf));
 }
 
-/*
- * This function parses the response to the AT~I2 command,
- * which gives the names of the radio's nearest neighbors.
- * It relies on the format of the response.
- */
-static void get_radio_neighbors(struct strip *strip_info, __u8 *ptr, __u8 *end)
+static const char proc_strip_status_name[] = "strip";
+static struct proc_dir_entry proc_strip_get_status_info =
 {
-    __u8 *p, *line_begin;
-    int num_nodes_reported, num_nodes_counted;
-    MetricomNode *node, *last;
-
-    /* Check if someone is reading the list */
-    if (strip_info->neighbor_list_locked) {
-	return;
-    }
-
-    /* Determine the number of Nodes */
-    p = ptr;
-    num_nodes_reported = simple_strtoul(p, NULL, 10);
-    /* printk(KERN_DEBUG "num_nodes: %d\n", num_nodes_reported); */
-
-    /* Determine the beginning of the next line */
-    while (p < end && *p != 10) p++;
-    if (p >= end) return;
-    p++;
-
-    /*
-     * The node list should never be empty because we allocate one empty
-     * node when the strip_info is allocated. The nodes which were allocated
-     * when the number of neighbors was high but are no longer needed because
-     * there aren't as many neighbors any more are marked invalid. Invalid nodes
-     * are kept at the end of the list.
-     */
-    node = strip_info->neighbor_list;
-    last = node;
-    if (node == NULL) {
-	DumpData("Neighbor list is NULL:", strip_info, p, end);
-	return;
-    }	
-    line_begin = p;
-    num_nodes_counted = 0;
-    while (line_begin < end) {
- 	/* Check to see if the format is what we expect. */
- 	if ((line_begin + STRIP_NODE_LEN) > end) {
- 	    printk(KERN_ERR "STRIP: radio neighbor node string shorter (%d) than expected (%d)\n",
- 	       end - line_begin, STRIP_NODE_LEN);
-	    break;
- 	}
-
-	/* Get a node */
-	if (node == NULL) {
-	    node = kmalloc(sizeof(MetricomNode), GFP_ATOMIC);
-	    node->next = NULL;
-	}
-	node->type = NodeValid;
-
-	/* Fill the node in */
-
-	/* Determine if it has a GPS location and fill it in if it does. */
-	p = line_begin;
-	/* printk(KERN_DEBUG "node: %64s\n", p); */
-	if (p[0] != STRIP_PORTABLE_CHAR) {
-	    node->type |= NodeHasWAN;
-	    sprintf(node->gl.s, "%.*s", (int) sizeof(GeographicLocation) - 1, p);
-	}
-	
-	/* Determine if it is a router */
-	p = line_begin + 18;
-	if (p[0] == STRIP_ROUTER_CHAR) {
-	    node->type |= NodeIsRouter;
-	}
-
-	/* Could be a radio address or some weird poletop address. */
-	p = line_begin + 20;
-	/* printk(KERN_DEBUG "before addr: %6s\n", p); */
-	string_to_radio_address(&node->addr, p);
-	/* radio_address_to_string(&node->addr, addr_string);
-	printk(KERN_DEBUG "after addr: %s\n", addr_string);  */
-	
-	if (IS_RADIO_ADDRESS(p)) {
-	    string_to_radio_address(&node->addr, p);
-	}
-	else {
-	    memset(&node->addr, 0, sizeof(MetricomAddress));
-	}
-	
-	/* Get the poll latency. %$#!@ simple_strtoul can't skip white space */
-	p = line_begin + 41;
-	while (isspace(*p) && (p < end)) {
-	    p++;
-	}
-	node->poll_latency = simple_strtoul(p, NULL, 10);
-	
-	/* Get the signal strength. simple_strtoul doesn't do minus signs */
-	p = line_begin + 60;
-	node->rssi = -simple_strtoul(p, NULL, 10);
-	
-	if (last != node) {
-	    last->next = node;
-	    last = node;
-	}
-	node = node->next;
-	line_begin += STRIP_NODE_LEN;
-	num_nodes_counted++;
-    }
-
-    /* invalidate all remaining nodes */
-    for (;node != NULL; node = node->next) {
-	node->type &= ~NodeValid;
-    }
-
-    /*
-     * If the number of nodes reported is different
-     * from the number counted, might need to up the number
-     * requested.
-     */
-    if (num_nodes_reported != num_nodes_counted) {
-	printk(KERN_DEBUG "nodes reported: %d \tnodes counted: %d\n",
-	       num_nodes_reported, num_nodes_counted);
-    }	
-}
+    PROC_NET_STRIP_STATUS,		/* unsigned short low_ino */
+    sizeof(proc_strip_status_name)-1,	/* unsigned short namelen */
+    proc_strip_status_name,		/* const char *name */
+    S_IFREG | S_IRUGO,			/* mode_t mode */
+    1,					/* nlink_t nlink */
+    0, 0, 0,				/* uid_t uid, gid_t gid, unsigned long size */
+    &proc_net_inode_operations,		/* struct inode_operations * ops */
+    &get_status_info,			/* int (*get_info)(...) */
+    NULL,				/* void (*fill_inode)(struct inode *); */
+    NULL, NULL, NULL,			/* struct proc_dir_entry *next, *parent, *subdir; */
+    NULL				/* void *data; */
+};
 
 
 /************************************************************************/
 /* Sending routines							*/
 
+#define InitString "ate0q1dt**starmode"
+
 static void ResetRadio(struct strip *strip_info)
-{	
-    static const char InitString[] = "\rat\r\rate0q1dt**starmode\r\r**";
+{
+    static const char s[] = "\r" InitString "\r**";
 
     /* If the radio isn't working anymore, we should clear the old status information. */
     if (strip_info->working)
@@ -1530,14 +1242,32 @@
         strip_info->firmware_version.c[0] = '\0';
         strip_info->serial_number.c[0] = '\0';
         strip_info->battery_voltage.c[0] = '\0';
+        strip_info->portables.num_nodes = 0;
+        do_gettimeofday(&strip_info->portables.timestamp);
+        strip_info->poletops.num_nodes = 0;
+        do_gettimeofday(&strip_info->poletops.timestamp);
     }
+
+    strip_info->pps_timer      = jiffies;
+    strip_info->rx_pps_count   = 0;
+    strip_info->tx_pps_count   = 0;
+    strip_info->sx_pps_count   = 0;
+    strip_info->rx_average_pps = 0;
+    strip_info->tx_average_pps = 0;
+    strip_info->sx_average_pps = 0;
+
     /* Mark radio address as unknown */
-    *(MetricomAddress*)&strip_info->dev.dev_addr = zero_address;
+    *(MetricomAddress*)&strip_info->true_dev_addr = zero_address;
+    if (!strip_info->manual_dev_addr) *(MetricomAddress*)strip_info->dev.dev_addr = zero_address;
     strip_info->working = FALSE;
-    strip_info->structured_messages = FALSE;
+    strip_info->firmware_level = NoStructure;
+    strip_info->next_command   = CompatibilityCommand;
     strip_info->watchdog_doprobe = jiffies + 10 * HZ;
     strip_info->watchdog_doreset = jiffies + 1 * HZ;
-    strip_info->tty->driver.write(strip_info->tty, 0, (char *)InitString, sizeof(InitString)-1);
+    strip_info->tty->driver.write(strip_info->tty, 0, (char *)s, sizeof(s)-1);
+#ifdef EXT_COUNTERS
+    strip_info->tx_ebytes += sizeof(s) - 1;
+#endif
 }
 
 /*
@@ -1573,6 +1303,9 @@
         int num_written = tty->driver.write(tty, 0, strip_info->tx_head, strip_info->tx_left);
         strip_info->tx_left -= num_written;
         strip_info->tx_head += num_written;
+#ifdef EXT_COUNTERS
+        strip_info->tx_sbytes += num_written;
+#endif
         RestoreInterrupts(intstat);
     }
     else            /* Else start transmission of another packet */
@@ -1583,12 +1316,21 @@
     }
 }
 
-static unsigned char *strip_make_packet(unsigned char *ptr, struct strip *strip_info, struct sk_buff *skb)
+static __u8 *add_checksum(__u8 *buffer, __u8 *end)
 {
-#if DO_PROC_NET_STRIP_TRACE
-    unsigned char *start_ptr;
-#endif DO_PROC_NET_STRIP_TRACE
+    __u16 sum = 0;
+    __u8 *p = buffer;
+    while (p < end) sum += *p++;
+    end[3] = hextable[sum & 0xF]; sum >>= 4;
+    end[2] = hextable[sum & 0xF]; sum >>= 4;
+    end[1] = hextable[sum & 0xF]; sum >>= 4;
+    end[0] = hextable[sum & 0xF];
+    return(end+4);
+}
 
+static unsigned char *strip_make_packet(unsigned char *buffer, struct strip *strip_info, struct sk_buff *skb)
+{
+    __u8           *ptr = buffer;
     __u8           *stuffstate = NULL;
     STRIP_Header   *header     = (STRIP_Header *)skb->data;
     MetricomAddress haddr      = header->dst_addr;
@@ -1603,7 +1345,6 @@
     {
         printk(KERN_ERR "%s: strip_make_packet: Unknown packet type 0x%04X\n",
             strip_info->dev.name, ntohs(header->protocol));
-        strip_info->tx_dropped++;
         return(NULL);
     }
 
@@ -1611,7 +1352,6 @@
     {
         printk(KERN_ERR "%s: Dropping oversized transmit packet: %d bytes\n",
             strip_info->dev.name, len);
-        strip_info->tx_dropped++;
         return(NULL);
     }
 
@@ -1629,6 +1369,12 @@
 	    }
     }
 
+    /*
+     * If we're sending to ourselves, discard the packet.
+     * (Metricom radios choke if they try to send a packet to their own address.)
+     */
+    if (!memcmp(haddr.c, strip_info->true_dev_addr.c, sizeof(haddr)))
+    	return(NULL);
     *ptr++ = '*';
     *ptr++ = hextable[haddr.c[2] >> 4];
     *ptr++ = hextable[haddr.c[2] & 0xF];
@@ -1645,17 +1391,9 @@
     *ptr++ = key.c[2];
     *ptr++ = key.c[3];
 
-#if DO_PROC_NET_STRIP_TRACE
-    start_ptr = ptr;
-#endif DO_PROC_NET_STRIP_TRACE
-
     ptr = StuffData(skb->data + sizeof(STRIP_Header), len, ptr, &stuffstate);
 
-#if DO_PROC_NET_STRIP_TRACE
-    packet_log(strip_info, skb->data + sizeof(STRIP_Header), EntrySend,
-	       header, len, ptr-start_ptr,
-	       slip_len(skb->data + sizeof(STRIP_Header), len)); 
-#endif DO_PROC_NET_STRIP_TRACE
+    if (strip_info->firmware_level >= ChecksummedMessages) ptr = add_checksum(buffer+1, ptr);
 
     *ptr++ = 0x0D;
     return(ptr);
@@ -1664,57 +1402,108 @@
 static void strip_send(struct strip *strip_info, struct sk_buff *skb)
 {
     unsigned char *ptr = strip_info->tx_buff;
+    int doreset = (long)jiffies - strip_info->watchdog_doreset >= 0;
+    int doprobe = (long)jiffies - strip_info->watchdog_doprobe >= 0 && !doreset;
 
-    /* If we have a packet, encapsulate it and put it in the buffer */
+    /*
+     * 1. If we have a packet, encapsulate it and put it in the buffer
+     */
     if (skb)
     {
-        ptr = strip_make_packet(ptr, strip_info, skb);
-        /* If error, unlock and return */
-        if (!ptr) { strip_unlock(strip_info); return; }
-        strip_info->tx_packets++;        /* Count another successful packet */
-        /*DumpData("Sending:", strip_info, strip_info->tx_buff, ptr);*/
-        /*HexDump("Sending", strip_info, strip_info->tx_buff, ptr);*/
-    }
-
-    /* Set up the strip_info ready to send the data */
-    strip_info->tx_head =       strip_info->tx_buff;
-    strip_info->tx_left = ptr - strip_info->tx_buff;
-    strip_info->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
-
-    /* If watchdog has expired, reset the radio */
-    if ((long)jiffies - strip_info->watchdog_doreset >= 0)
-    {
-        ResetRadio(strip_info);
-        return;
-        /* Note: if there's a packet to send, strip_write_some_more
-                 will do it after the reset has finished */
+        char *newptr = strip_make_packet(ptr, strip_info, skb);
+        strip_info->tx_pps_count++;
+        if (!newptr) strip_info->tx_dropped++;
+        else
+        {
+            ptr = newptr;
+            strip_info->sx_pps_count++;
+            strip_info->tx_packets++;        /* Count another successful packet */
+#ifdef EXT_COUNTERS
+            strip_info->tx_bytes += skb->len;
+            strip_info->tx_rbytes += ptr - strip_info->tx_buff;
+#endif
+            /*DumpData("Sending:", strip_info, strip_info->tx_buff, ptr);*/
+            /*HexDump("Sending", strip_info, strip_info->tx_buff, ptr);*/
+        }
     }
 
-    /* No reset.
-     * If it is time for another tickle, tack it on the end of the packet
+    /*
+     * 2. If it is time for another tickle, tack it on, after the packet
      */
-    if ((long)jiffies - strip_info->watchdog_doprobe >= 0)
+    if (doprobe)
     {
-        /* Send tickle to make radio protest */
-        /*printk(KERN_INFO "%s: Routine radio test.\n", strip_info->dev.name);*/
-        const char *TickleString = TickleString1;
-        int length = sizeof(TickleString1)-1;
-        if (strip_info->structured_messages)
+        StringDescriptor ts = CommandString[strip_info->next_command];
+#if TICKLE_TIMERS
         {
-            TickleString = TickleString2;
-            length = sizeof(TickleString2)-1;
+        struct timeval tv;
+        do_gettimeofday(&tv);
+        printk(KERN_INFO "**** Sending tickle string %d      at %02d.%06d\n",
+            strip_info->next_command, tv.tv_sec % 100, tv.tv_usec);
         }
-        memcpy(ptr, TickleString, length);
-        strip_info->tx_left += length;
+#endif
+        if (ptr == strip_info->tx_buff) *ptr++ = 0x0D;
+
+        *ptr++ = '*'; /* First send "**" to provoke an error message */
+        *ptr++ = '*';
+
+        /* Then add the command */
+        memcpy(ptr, ts.string, ts.length);
+
+        /* Add a checksum ? */
+        if (strip_info->firmware_level < ChecksummedMessages) ptr += ts.length;
+        else ptr = add_checksum(ptr, ptr + ts.length);
+
+        *ptr++ = 0x0D; /* Terminate the command with a <CR> */
+
+        /* Cycle to next periodic command? */
+        if (strip_info->firmware_level >= StructuredMessages)
+                if (++strip_info->next_command >= ELEMENTS_OF(CommandString))
+                        strip_info->next_command = 0;
+#ifdef EXT_COUNTERS
+        strip_info->tx_ebytes += ts.length;
+#endif
         strip_info->watchdog_doprobe = jiffies + 10 * HZ;
         strip_info->watchdog_doreset = jiffies + 1 * HZ;
+        /*printk(KERN_INFO "%s: Routine radio test.\n", strip_info->dev.name);*/
     }
 
     /*
-     * If it is time for a periodic ARP, queue one up to be sent
+     * 3. Set up the strip_info ready to send the data (if any).
+     */
+    strip_info->tx_head = strip_info->tx_buff;
+    strip_info->tx_left = ptr - strip_info->tx_buff;
+    strip_info->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
+
+    /*
+     * 4. Debugging check to make sure we're not overflowing the buffer.
+     */
+    if (strip_info->tx_size - strip_info->tx_left < 20)
+        printk(KERN_ERR "%s: Sending%5d bytes;%5d bytes free.\n", strip_info->dev.name,
+            strip_info->tx_left, strip_info->tx_size - strip_info->tx_left);
+
+    /*
+     * 5. If watchdog has expired, reset the radio. Note: if there's data waiting in
+     * the buffer, strip_write_some_more will send it after the reset has finished
+     */
+    if (doreset) { ResetRadio(strip_info); return; }
+
+    /*
+     * 6. If it is time for a periodic ARP, queue one up to be sent.
+     * We only do this if:
+     *  1. The radio is working
+     *  2. It's time to send another periodic ARP
+     *  3. We really know what our address is (and it is not manually set to zero)
+     *  4. We have a designated broadcast address configured
+     * If we queue up an ARP packet when we don't have a designated broadcast
+     * address configured, then the packet will just have to be discarded in
+     * strip_make_packet. This is not fatal, but it causes misleading information
+     * to be displayed in tcpdump. tcpdump will report that periodic APRs are
+     * being sent, when in fact they are not, because they are all being dropped
+     * in the strip_make_packet routine.
      */
     if (strip_info->working && (long)jiffies - strip_info->gratuitous_arp >= 0 &&
-        memcmp(strip_info->dev.dev_addr, zero_address.c, sizeof(zero_address)))
+        memcmp(strip_info->dev.dev_addr, zero_address.c, sizeof(zero_address)) &&
+        *strip_info->dev.broadcast!=0xFF)
     {
         /*printk(KERN_INFO "%s: Sending gratuitous ARP with interval %ld\n",
             strip_info->dev.name, strip_info->arp_interval / HZ);*/
@@ -1722,16 +1511,18 @@
         strip_info->arp_interval *= 2;
         if (strip_info->arp_interval > MaxARPInterval)
             strip_info->arp_interval = MaxARPInterval;
-        arp_send(ARPOP_REPLY, ETH_P_ARP, strip_info->dev.pa_addr,
-                        &strip_info->dev, strip_info->dev.pa_addr,
-                        NULL, strip_info->dev.dev_addr, NULL);
+        arp_send(ARPOP_REPLY, ETH_P_ARP,
+            strip_info->dev.pa_addr,	/* Target address of ARP packet is our address */
+            &strip_info->dev,		/* Device to send packet on */
+            strip_info->dev.pa_addr,	/* Source IP address this ARP packet comes from */
+            NULL,			/* Destination HW address is NULL (broadcast it) */
+            strip_info->dev.dev_addr,	/* Source HW address is our HW address */
+            strip_info->dev.dev_addr);	/* Target HW address is our HW address (redundant) */
     }
 
-    if (strip_info->tx_size - strip_info->tx_left < 20)
-        printk(KERN_ERR "%s: Sending%5d bytes;%5d bytes free.\n", strip_info->dev.name,
-            strip_info->tx_left, strip_info->tx_size - strip_info->tx_left);
-
-    /* All ready. Start the transmission */
+    /*
+     * 7. All ready. Start the transmission
+     */
     strip_write_some_more(strip_info->tty);
 }
 
@@ -1752,6 +1543,33 @@
     if (strip_info->mtu != strip_info->dev.mtu)
         strip_changedmtu(strip_info);
 
+    if (jiffies - strip_info->pps_timer > HZ)
+    {
+        unsigned long t = jiffies - strip_info->pps_timer;
+        unsigned long rx_pps_count = (strip_info->rx_pps_count * HZ * 8 + t/2) / t;
+        unsigned long tx_pps_count = (strip_info->tx_pps_count * HZ * 8 + t/2) / t;
+        unsigned long sx_pps_count = (strip_info->sx_pps_count * HZ * 8 + t/2) / t;
+
+        strip_info->pps_timer = jiffies;
+        strip_info->rx_pps_count = 0;
+        strip_info->tx_pps_count = 0;
+        strip_info->sx_pps_count = 0;
+
+        strip_info->rx_average_pps = (strip_info->rx_average_pps + rx_pps_count + 1) / 2;
+        strip_info->tx_average_pps = (strip_info->tx_average_pps + tx_pps_count + 1) / 2;
+        strip_info->sx_average_pps = (strip_info->sx_average_pps + sx_pps_count + 1) / 2;
+
+        if (rx_pps_count / 8 >= 10)
+            printk(KERN_INFO "%s: WARNING: Receiving %ld packets per second.\n",
+                strip_info->dev.name, rx_pps_count / 8);
+        if (tx_pps_count / 8 >= 10)
+            printk(KERN_INFO "%s: WARNING: Tx        %ld packets per second.\n",
+                strip_info->dev.name, tx_pps_count / 8);
+        if (sx_pps_count / 8 >= 10)
+            printk(KERN_INFO "%s: WARNING: Sending   %ld packets per second.\n",
+                strip_info->dev.name, sx_pps_count / 8);
+    }
+
     strip_send(strip_info, skb);
 
     if (skb) dev_kfree_skb(skb, FREE_WRITE);
@@ -1759,6 +1577,17 @@
 }
 
 /*
+ * IdleTask periodically calls strip_xmit, so even when we have no IP packets
+ * to send for an extended period of time, the watchdog processing still gets
+ * done to ensure that the radio stays in Starmode
+ */
+
+static void strip_IdleTask(unsigned long parameter)
+{
+    strip_xmit(NULL, (struct device *)parameter);
+}
+
+/*
  * Create the MAC header for an arbitrary protocol layer
  *
  * saddr!=NULL        means use this specific address (n/a for Metricom)
@@ -1772,19 +1601,20 @@
 static int strip_header(struct sk_buff *skb, struct device *dev,
         unsigned short type, void *daddr, void *saddr, unsigned len)
 {
+    struct strip *strip_info = (struct strip *)(dev->priv);
     STRIP_Header *header = (STRIP_Header *)skb_push(skb, sizeof(STRIP_Header));
 
     /*printk(KERN_INFO "%s: strip_header 0x%04X %s\n", dev->name, type,
         type == ETH_P_IP ? "IP" : type == ETH_P_ARP ? "ARP" : "");*/
 
-    memcpy(header->src_addr.c, dev->dev_addr, dev->addr_len);
+    header->src_addr = strip_info->true_dev_addr;
     header->protocol = htons(type);
 
     /*HexDump("strip_header", (struct strip *)(dev->priv), skb->data, skb->data + skb->len);*/
 
     if (!daddr) return(-dev->hard_header_len);
 
-    memcpy(header->dst_addr.c, daddr, dev->addr_len);
+    header->dst_addr = *(MetricomAddress*)daddr;
     return(dev->hard_header_len);
 }
 
@@ -1811,43 +1641,130 @@
 #endif
 }
 
+
+/************************************************************************/
+/* Receiving routines							*/
+
+static int strip_receive_room(struct tty_struct *tty)
+{
+    return 0x10000;  /* We can handle an infinite amount of data. :-) */
+}
+
 /*
- * IdleTask periodically calls strip_xmit, so even when we have no IP packets
- * to send for an extended period of time, the watchdog processing still gets
- * done to ensure that the radio stays in Starmode
+ * This function parses the response to the ATS300? command,
+ * extracting the radio version and serial number.
  */
-
-static void strip_IdleTask(unsigned long parameter)
+static void get_radio_version(struct strip *strip_info, __u8 *ptr, __u8 *end)
 {
-    strip_xmit(NULL, (struct device *)parameter);
+    __u8 *p, *value_begin, *value_end;
+    int len;
+    
+    /* Determine the beginning of the second line of the payload */
+    p = ptr;
+    while (p < end && *p != 10) p++;
+    if (p >= end) return;
+    p++;
+    value_begin = p;
+    
+    /* Determine the end of line */
+    while (p < end && *p != 10) p++;
+    if (p >= end) return;
+    value_end = p;
+    p++;
+     
+    len = value_end - value_begin;
+    len = MIN(len, sizeof(FirmwareVersion) - 1);
+    if (strip_info->firmware_version.c[0] == 0)
+        printk(KERN_INFO "%s: Radio Firmware: %.*s\n",
+            strip_info->dev.name, len, value_begin);
+    sprintf(strip_info->firmware_version.c, "%.*s", len, value_begin);
+    
+    /* Look for the first colon */
+    while (p < end && *p != ':') p++;
+    if (p >= end) return;
+    /* Skip over the space */
+    p += 2;
+    len = sizeof(SerialNumber) - 1;
+    if (p + len <= end) {
+        sprintf(strip_info->serial_number.c, "%.*s", len, p);
+    }
+    else {
+     	printk(KERN_DEBUG "STRIP: radio serial number shorter (%d) than expected (%d)\n",
+     	       end - p, len);
+    }
 }
 
+/*
+ * This function parses the response to the ATS325? command,
+ * extracting the radio battery voltage.
+ */
+static void get_radio_voltage(struct strip *strip_info, __u8 *ptr, __u8 *end)
+{
+    int len;
 
-/************************************************************************/
-/* Receiving routines							*/
+    len = sizeof(BatteryVoltage) - 1;
+    if (ptr + len <= end) {
+        sprintf(strip_info->battery_voltage.c, "%.*s", len, ptr);
+    }
+    else {
+ 	printk(KERN_DEBUG "STRIP: radio voltage string shorter (%d) than expected (%d)\n",
+ 	       end - ptr, len);
+    }
+}
 
-static int strip_receive_room(struct tty_struct *tty)
+/*
+ * This function parses the responses to the AT~LA and ATS311 commands,
+ * which list the radio's neighbours.
+ */
+static void get_radio_neighbours(MetricomNodeTable *table, __u8 *ptr, __u8 *end)
 {
-    return 0x10000;  /* We can handle an infinite amount of data. :-) */
+    table->num_nodes = 0;
+    while (ptr < end && table->num_nodes < NODE_TABLE_SIZE)
+        {
+        MetricomNode *node = &table->node[table->num_nodes++];
+        char *dst = node->c, *limit = dst + sizeof(*node) - 1;
+        while (ptr < end && *ptr <= 32) ptr++;
+        while (ptr < end && dst < limit && *ptr != 10) *dst++ = *ptr++;
+        *dst++ = 0;
+        while (ptr < end && ptr[-1] != 10) ptr++;
+        }
+    do_gettimeofday(&table->timestamp);
 }
 
-static void get_radio_address(struct strip *strip_info, __u8 *p)
+static int get_radio_address(struct strip *strip_info, __u8 *p)
 {
     MetricomAddress addr;
 
-    string_to_radio_address(&addr, p);
+    if (string_to_radio_address(&addr, p)) return(1);
 
     /* See if our radio address has changed */
-    if (memcmp(strip_info->dev.dev_addr, addr.c, sizeof(addr)))
+    if (memcmp(strip_info->true_dev_addr.c, addr.c, sizeof(addr)))
     {
         MetricomAddressString addr_string;
         radio_address_to_string(&addr, &addr_string);
-        printk(KERN_INFO "%s: My radio address = %s\n", strip_info->dev.name, addr_string.c);
-        memcpy(strip_info->dev.dev_addr, addr.c, sizeof(addr));
+        printk(KERN_INFO "%s: Radio address = %s\n", strip_info->dev.name, addr_string.c);
+        strip_info->true_dev_addr = addr;
+        if (!strip_info->manual_dev_addr) *(MetricomAddress*)strip_info->dev.dev_addr = addr;
         /* Give the radio a few seconds to get its head straight, then send an arp */
-        strip_info->gratuitous_arp = jiffies + 6 * HZ;
+        strip_info->gratuitous_arp = jiffies + 15 * HZ;
         strip_info->arp_interval = 1 * HZ;
     }
+    return(0);
+}
+
+static int verify_checksum(struct strip *strip_info)
+{
+    __u8 *p = strip_info->sx_buff;
+    __u8 *end = strip_info->sx_buff + strip_info->sx_count - 4;
+    u_short sum = (READHEX16(end[0]) << 12) | (READHEX16(end[1]) << 8) |
+                  (READHEX16(end[2]) <<  4) | (READHEX16(end[3]));
+    while (p < end) sum -= *p++;
+    if (sum == 0 && strip_info->firmware_level == StructuredMessages)
+    {
+        strip_info->firmware_level = ChecksummedMessages;
+        printk(KERN_INFO "%s: Radio provides message checksums\n", strip_info->dev.name);
+    }
+    return(sum == 0);
 }
 
 static void RecvErr(char *msg, struct strip *strip_info)
@@ -1860,114 +1777,156 @@
 
 static void RecvErr_Message(struct strip *strip_info, __u8 *sendername, const __u8 *msg)
 {
-    static const char ERR_001[] = "001"; /* Not in StarMode! */
-    static const char ERR_002[] = "002"; /* Remap handle */
-    static const char ERR_003[] = "003"; /* Can't resolve name */
-    static const char ERR_004[] = "004"; /* Name too small or missing */
-    static const char ERR_005[] = "005"; /* Bad count specification */
-    static const char ERR_006[] = "006"; /* Header too big */
-    static const char ERR_007[] = "007"; /* Body too big */
-    static const char ERR_008[] = "008"; /* Bad character in name */
-    static const char ERR_009[] = "009"; /* No count or line terminator */
-
-    if (!strncmp(msg, ERR_001, sizeof(ERR_001)-1))
+    if (has_prefix(msg, "001")) /* Not in StarMode! */
     {
         RecvErr("Error Msg:", strip_info);
         printk(KERN_INFO "%s: Radio %s is not in StarMode\n",
             strip_info->dev.name, sendername);
     }
-    else if (!strncmp(msg, ERR_002, sizeof(ERR_002)-1))
+
+    else if (has_prefix(msg, "002")) /* Remap handle */
     {
-        RecvErr("Error Msg:", strip_info);
-#ifdef notyet        /*Kernel doesn't have scanf!*/
-        int handle;
-        __u8 newname[64];
-        sscanf(msg, "ERR_002 Remap handle &%d to name %s", &handle, newname);
-        printk(KERN_INFO "%s: Radio name %s is handle %d\n",
-            strip_info->dev.name, newname, handle);
-#endif
+	/* We ignore "Remap handle" messages for now */
     }
-    else if (!strncmp(msg, ERR_003, sizeof(ERR_003)-1))
+
+    else if (has_prefix(msg, "003")) /* Can't resolve name */
     {
         RecvErr("Error Msg:", strip_info);
         printk(KERN_INFO "%s: Destination radio name is unknown\n",
             strip_info->dev.name);
     }
-    else if (!strncmp(msg, ERR_004, sizeof(ERR_004)-1))
+
+    else if (has_prefix(msg, "004")) /* Name too small or missing */
     {
         strip_info->watchdog_doreset = jiffies + LongTime;
+#if TICKLE_TIMERS
+        {
+        struct timeval tv;
+        do_gettimeofday(&tv);
+        printk(KERN_INFO "**** Got ERR_004 response         at %02d.%06d\n",
+            tv.tv_sec % 100, tv.tv_usec);
+        }
+#endif
         if (!strip_info->working)
         {
             strip_info->working = TRUE;
-            printk(KERN_INFO "%s: Radio now in starmode\n",
-                strip_info->dev.name);
+            printk(KERN_INFO "%s: Radio now in starmode\n", strip_info->dev.name);
             /*
              * If the radio has just entered a working state, we should do our first
              * probe ASAP, so that we find out our radio address etc. without delay.
              */
             strip_info->watchdog_doprobe = jiffies;
         }
-        if (!strip_info->structured_messages && sendername)
+        if (strip_info->firmware_level == NoStructure && sendername)
         {
-            strip_info->structured_messages = TRUE;
-            printk(KERN_INFO "%s: Radio provides structured messages\n",
-                strip_info->dev.name);
+            strip_info->firmware_level = StructuredMessages;
+            strip_info->next_command   = 0; /* Try to enable checksums ASAP */
+            printk(KERN_INFO "%s: Radio provides structured messages\n", strip_info->dev.name);
+        }
+        if (strip_info->firmware_level >= StructuredMessages)
+        {
+            verify_checksum(strip_info);
+            /*
+             * If the radio has structured messages but we don't yet have all our information about it, we should do
+             * probes without delay, until we have gathered all the information
+             */
+            if (!GOT_ALL_RADIO_INFO(strip_info)) strip_info->watchdog_doprobe = jiffies;
         }
     }
-    else if (!strncmp(msg, ERR_005, sizeof(ERR_005)-1))
+
+    else if (has_prefix(msg, "005")) /* Bad count specification */
         RecvErr("Error Msg:", strip_info);
-    else if (!strncmp(msg, ERR_006, sizeof(ERR_006)-1))
+
+    else if (has_prefix(msg, "006")) /* Header too big */
         RecvErr("Error Msg:", strip_info);
-    else if (!strncmp(msg, ERR_007, sizeof(ERR_007)-1))
+
+    else if (has_prefix(msg, "007")) /* Body too big */
     {
-        /*
-         * Note: This error knocks the radio back into
-         * command mode.
-         */
         RecvErr("Error Msg:", strip_info);
-        printk(KERN_ERR "%s: Error! Packet size too big for radio.",
+        printk(KERN_ERR "%s: Error! Packet size too big for radio.\n",
             strip_info->dev.name);
-        strip_info->watchdog_doreset = jiffies;        /* Do reset ASAP */
     }
-    else if (!strncmp(msg, ERR_008, sizeof(ERR_008)-1))
+
+    else if (has_prefix(msg, "008")) /* Bad character in name */
     {
         RecvErr("Error Msg:", strip_info);
         printk(KERN_ERR "%s: Radio name contains illegal character\n",
             strip_info->dev.name);
     }
-    else if (!strncmp(msg, ERR_009, sizeof(ERR_009)-1))
+
+    else if (has_prefix(msg, "009")) /* No count or line terminator */
         RecvErr("Error Msg:", strip_info);
+
+    else if (has_prefix(msg, "010")) /* Invalid checksum */
+        RecvErr("Error Msg:", strip_info);
+
+    else if (has_prefix(msg, "011")) /* Checksum didn't match */
+        RecvErr("Error Msg:", strip_info);
+
+    else if (has_prefix(msg, "012")) /* Failed to transmit packet */
+        RecvErr("Error Msg:", strip_info);
+
     else
         RecvErr("Error Msg:", strip_info);
 }
 
 static void process_AT_response(struct strip *strip_info, __u8 *ptr, __u8 *end)
 {
-    static const char ATS305[] = "ATS305?";
-    static const char ATS300[] = "ATS300?";
-    static const char ATS325[] = "ATS325?";
-    static const char ATI2[] = "AT~I2 nn";
-
-    /* Skip to the first newline character */
     __u8 *p = ptr;
-    while (p < end && *p != 10) p++;
-    if (p >= end) return;
-    p++;
+    while (p < end && p[-1] != 10) p++; /* Skip past first newline character */
+    /* Now ptr points to the AT command, and p points to the text of the response. */
 
-    if (!strncmp(ptr, ATS305, sizeof(ATS305)-1))
+#if TICKLE_TIMERS
     {
-        if (IS_RADIO_ADDRESS(p)) get_radio_address(strip_info, p);
-    }
-    else if (!strncmp(ptr, ATS300, sizeof(ATS300)-1)) {
-        get_radio_version(strip_info, p, end);
-    }
-    else if (!strncmp(ptr, ATS325, sizeof(ATS325)-1)) {
-        get_radio_voltage(strip_info, p, end);
+    struct timeval tv;
+    do_gettimeofday(&tv);
+    printk(KERN_INFO "**** Got AT response %.7s      at %02d.%06d\n",
+        ptr, tv.tv_sec % 100, tv.tv_usec);
     }
-    else if (!strncmp(ptr, ATI2, sizeof(ATI2)-1)) {
-        get_radio_neighbors(strip_info, p, end);
+#endif
+
+    if      (has_prefix(ptr, "ATS300?" )) get_radio_version(strip_info, p, end);
+    else if (has_prefix(ptr, "ATS305?" )) get_radio_address(strip_info, p);
+    else if (has_prefix(ptr, "ATS311?" )) get_radio_neighbours(&strip_info->poletops, p, end);
+    else if (has_prefix(ptr, "ATS319=7")) verify_checksum(strip_info);
+    else if (has_prefix(ptr, "ATS325?" )) get_radio_voltage(strip_info, p, end);
+    else if (has_prefix(ptr, "AT~LA"   )) get_radio_neighbours(&strip_info->portables, p, end);
+    else                                              RecvErr("Unknown AT Response:", strip_info);
+}
+
+static void process_ACK(struct strip *strip_info, __u8 *ptr, __u8 *end)
+{
+    /* Currently we don't do anything with ACKs from the radio */
+}
+
+static void process_Info(struct strip *strip_info, __u8 *ptr, __u8 *end)
+{
+    if (ptr+16 > end) RecvErr("Bad Info Msg:", strip_info);
+}
+
+static struct device *get_strip_dev(struct strip *strip_info)
+{
+    /* If our hardware address is *manually set* to zero, and we know our */
+    /* real radio hardware address, try to find another strip device that has been */
+    /* manually set to that address that we can 'transfer ownership' of this packet to  */
+    if (strip_info->manual_dev_addr &&
+        !memcmp(strip_info->dev.dev_addr, zero_address.c, sizeof(zero_address)) &&
+        memcmp(&strip_info->true_dev_addr, zero_address.c, sizeof(zero_address)))
+    {
+        struct device *dev = dev_base;
+        while (dev)
+        {
+            if (dev->type == strip_info->dev.type &&
+                !memcmp(dev->dev_addr, &strip_info->true_dev_addr, sizeof(MetricomAddress)))
+            {
+                printk(KERN_INFO "%s: Transferred packet ownership to %s.\n",
+                    strip_info->dev.name, dev->name);
+                return(dev);
+            }
+            dev = dev->next;
+        }
     }
-    else RecvErr("Unknown AT Response:", strip_info);
+    return(&strip_info->dev);
 }
 
 /*
@@ -1979,14 +1938,14 @@
     struct sk_buff *skb = dev_alloc_skb(sizeof(STRIP_Header) + packetlen);
     if (!skb)
     {
-        printk(KERN_INFO "%s: memory squeeze, dropping packet.\n", strip_info->dev.name);
+        printk(KERN_ERR "%s: memory squeeze, dropping packet.\n", strip_info->dev.name);
         strip_info->rx_dropped++;
     }
     else
     {
         memcpy(skb_put(skb, sizeof(STRIP_Header)), header, sizeof(STRIP_Header));
         memcpy(skb_put(skb, packetlen), strip_info->rx_buff, packetlen);
-        skb->dev      = &strip_info->dev;
+        skb->dev      = get_strip_dev(strip_info);
         skb->protocol = header->protocol;
         skb->mac.raw  = skb->data;
 
@@ -1997,6 +1956,10 @@
 
         /* Finally, hand the packet up to the next layer (e.g. IP or ARP, etc.) */
         strip_info->rx_packets++;
+        strip_info->rx_pps_count++;
+#ifdef EXT_COUNTERS
+        strip_info->rx_bytes += packetlen;
+#endif
         netif_rx(skb);
     }
 }
@@ -2005,10 +1968,6 @@
 {
     __u16 packetlen;
 
-#if DO_PROC_NET_STRIP_TRACE
-    __u8 *start_ptr = ptr;
-#endif DO_PROC_NET_STRIP_TRACE
-
     /* Decode start of the IP packet header */
     ptr = UnStuffData(ptr, end, strip_info->rx_buff, 4);
     if (!ptr)
@@ -2019,9 +1978,9 @@
 
     packetlen = ((__u16)strip_info->rx_buff[2] << 8) | strip_info->rx_buff[3];
 
-    if (packetlen > MAX_STRIP_MTU)
+    if (packetlen > MAX_RECV_MTU)
     {
-        printk(KERN_ERR "%s: Dropping oversized receive packet: %d bytes\n",
+        printk(KERN_INFO "%s: Dropping oversized received IP packet: %d bytes\n",
             strip_info->dev.name, packetlen);
         strip_info->rx_dropped++;
         return;
@@ -2045,11 +2004,6 @@
 
     header->protocol = htons(ETH_P_IP);
 
-#if DO_PROC_NET_STRIP_TRACE
-    packet_log(strip_info, strip_info->rx_buff, EntryReceive, header,
-	       packetlen, end-start_ptr, slip_len(strip_info->rx_buff, packetlen)); 
-#endif DO_PROC_NET_STRIP_TRACE
-
     deliver_packet(strip_info, header, packetlen);
 }
 
@@ -2058,10 +2012,6 @@
     __u16 packetlen;
     struct arphdr *arphdr = (struct arphdr *)strip_info->rx_buff;
 
-#if DO_PROC_NET_STRIP_TRACE
-    __u8 *start_ptr = ptr;
-#endif DO_PROC_NET_STRIP_TRACE
-
     /* Decode start of the ARP packet */
     ptr = UnStuffData(ptr, end, strip_info->rx_buff, 8);
     if (!ptr)
@@ -2072,9 +2022,9 @@
 
     packetlen = 8 + (arphdr->ar_hln + arphdr->ar_pln) * 2;
 
-    if (packetlen > MAX_STRIP_MTU)
+    if (packetlen > MAX_RECV_MTU)
     {
-        printk(KERN_ERR "%s: Dropping oversized receive packet: %d bytes\n",
+        printk(KERN_INFO "%s: Dropping oversized received ARP packet: %d bytes\n",
             strip_info->dev.name, packetlen);
         strip_info->rx_dropped++;
         return;
@@ -2100,15 +2050,47 @@
 
     header->protocol = htons(ETH_P_ARP);
 
-#if DO_PROC_NET_STRIP_TRACE
-    packet_log(strip_info, strip_info->rx_buff, EntryReceive, header,
-	       packetlen, end-start_ptr, slip_len(strip_info->rx_buff, packetlen)); 
-#endif DO_PROC_NET_STRIP_TRACE
-
     deliver_packet(strip_info, header, packetlen);
 }
 
-static void process_packet(struct strip *strip_info)
+/*
+ * process_text_message processes a <CR>-terminated block of data received
+ * from the radio that doesn't begin with a '*' character. All normal
+ * Starmode communication messages with the radio begin with a '*',
+ * so any text that does not indicates a serial port error, a radio that
+ * is in Hayes command mode instead of Starmode, or a radio with really
+ * old firmware that doesn't frame its Starmode responses properly.
+ */
+static void process_text_message(struct strip *strip_info)
+{
+    __u8 *msg = strip_info->sx_buff;
+    int len   = strip_info->sx_count;
+
+    /* Check for anything that looks like it might be our radio name */
+    /* (This is here for backwards compatibility with old firmware)  */
+    if (len == 9 && get_radio_address(strip_info, msg) == 0) return;
+
+    if (text_equal(msg, len, "OK"      )) return; /* Ignore 'OK' responses from prior commands */
+    if (text_equal(msg, len, "ERROR"   )) return; /* Ignore 'ERROR' messages */
+    if (text_equal(msg, len, InitString)) return; /* Ignore character echo back from the radio */
+
+    /* Catch other error messages */
+    /* (This is here for backwards compatibility with old firmware) */
+    if (has_prefix(msg, "ERR_")) { RecvErr_Message(strip_info, NULL, &msg[4]); return; }
+    
+    RecvErr("No initial *", strip_info);
+}
+
+/*
+ * process_message processes a <CR>-terminated block of data received
+ * from the radio. If the radio is not in Starmode or has old firmware,
+ * it may be a line of text in response to an AT command. Ideally, with
+ * a current radio that's properly in Starmode, all data received should
+ * be properly framed and checksummed radio message blocks, containing
+ * either a starmode packet, or a other communication from the radio
+ * firmware, like "INF_" Info messages and &COMMAND responses.
+ */
+static void process_message(struct strip *strip_info)
 {
     STRIP_Header header = { zero_address, zero_address, 0 };
     __u8 *ptr = strip_info->sx_buff;
@@ -2116,29 +2098,11 @@
     __u8 sendername[32], *sptr = sendername;
     MetricomKey key;
 
-    /* Ignore 'OK' responses from prior commands */
-    if (strip_info->sx_count == 2 && ptr[0] == 'O' && ptr[1] == 'K') return;
-
-    /* Check for anything that looks like it might be our radio name: dddd-dddd */
-    /* (This is here for backwards compatibility with old firmware)             */
-    if (strip_info->sx_count == 9 && IS_RADIO_ADDRESS(ptr))
-    {
-        get_radio_address(strip_info, ptr);
-        return;
-    }
-
     /*HexDump("Receiving", strip_info, ptr, end);*/
 
     /* Check for start of address marker, and then skip over it */
-    if (*ptr != '*')
-    {
-        /* Catch other error messages */
-        if (ptr[0] == 'E' && ptr[1] == 'R' && ptr[2] == 'R' && ptr[3] == '_')
-            RecvErr_Message(strip_info, NULL, &ptr[4]);
-        else RecvErr("No initial *", strip_info);
-        return;
-    }
-    ptr++; /* Skip the initial '*' */
+    if (*ptr == '*') ptr++;
+    else { process_text_message(strip_info); return; }
 
     /* Copy out the return address */
     while (ptr < end && *ptr != '*' && sptr < ARRAY_END(sendername)-1) *sptr++ = *ptr++;
@@ -2156,16 +2120,39 @@
     /* (This is here for backwards compatibility with old firmware) */
     if (!strcmp(sendername, "&COMMAND"))
     {
-        strip_info->structured_messages = FALSE;
+        strip_info->firmware_level = NoStructure;
+        strip_info->next_command   = CompatibilityCommand;
         return;
     }
 
-    if (ptr+4 >= end)
+    if (ptr+4 > end)
     {
         RecvErr("No proto key", strip_info);
         return;
     }
 
+    /* Get the protocol key out of the buffer */
+    key.c[0] = *ptr++;
+    key.c[1] = *ptr++;
+    key.c[2] = *ptr++;
+    key.c[3] = *ptr++;
+
+    /* If we're using checksums, verify the checksum at the end of the packet */
+    if (strip_info->firmware_level >= ChecksummedMessages)
+    {
+        end -= 4;	/* Chop the last four bytes off the packet (they're the checksum) */
+        if (ptr > end)
+        {
+            RecvErr("Missing Checksum", strip_info);
+            return;
+        }
+        if (!verify_checksum(strip_info))
+        {
+            RecvErr("Bad Checksum", strip_info);
+            return;
+        }
+    }
+
     /*printk(KERN_INFO "%s: Got packet from \"%s\".\n", strip_info->dev.name, sendername);*/
 
     /*
@@ -2173,38 +2160,45 @@
      * We assume that the destination address was our address (the radio does not
      * tell us this). If the radio supplies a source address, then we use it.
      */
-    memcpy(&header.dst_addr, strip_info->dev.dev_addr, sizeof(MetricomAddress));
-    if (IS_RADIO_ADDRESS(sendername)) string_to_radio_address(&header.src_addr, sendername);
+    header.dst_addr = strip_info->true_dev_addr;
+    string_to_radio_address(&header.src_addr, sendername);
 
-    /* Get the protocol key out of the buffer */
-    key.c[0] = *ptr++;
-    key.c[1] = *ptr++;
-    key.c[2] = *ptr++;
-    key.c[3] = *ptr++;
-
-    if      (key.l == SIP0Key.l) process_IP_packet(strip_info, &header, ptr, end);
-    else if (key.l == ARP0Key.l) process_ARP_packet(strip_info, &header, ptr, end);
+#ifdef EXT_COUNTERS
+    if      (key.l == SIP0Key.l) {
+      strip_info->rx_rbytes += (end - ptr);
+      process_IP_packet(strip_info, &header, ptr, end);
+    } else if (key.l == ARP0Key.l) {
+      strip_info->rx_rbytes += (end - ptr);
+      process_ARP_packet(strip_info, &header, ptr, end);
+    } else if (key.l == ATR_Key.l) {
+      strip_info->rx_ebytes += (end - ptr);
+      process_AT_response(strip_info, ptr, end);
+    } else if (key.l == ACK_Key.l) {
+      strip_info->rx_ebytes += (end - ptr);
+      process_ACK(strip_info, ptr, end);
+    } else if (key.l == INF_Key.l) {
+      strip_info->rx_ebytes += (end - ptr);
+      process_Info(strip_info, ptr, end);
+    } else if (key.l == ERR_Key.l) {
+      strip_info->rx_ebytes += (end - ptr);
+      RecvErr_Message(strip_info, sendername, ptr);
+    } else RecvErr("Unrecognized protocol key", strip_info);
+#else
+    if      (key.l == SIP0Key.l) process_IP_packet  (strip_info, &header, ptr, end);
+    else if (key.l == ARP0Key.l) process_ARP_packet (strip_info, &header, ptr, end);
     else if (key.l == ATR_Key.l) process_AT_response(strip_info, ptr, end);
-    else if (key.l == ERR_Key.l) RecvErr_Message(strip_info, sendername, ptr);
-    else /* RecvErr("Unrecognized protocol key", strip_info); */
-
-    /* Note, this "else" block is temporary, until Metricom fix their */
-    /* packet corruption bug */
-    {
-        RecvErr("Unrecognized protocol key (retrying)", strip_info);
-        ptr -= 3; /* Back up and try again */
-        key.c[0] = *ptr++;
-        key.c[1] = *ptr++;
-        key.c[2] = *ptr++;
-        key.c[3] = *ptr++;
-        if      (key.l == SIP0Key.l) process_IP_packet(strip_info, &header, ptr, end);
-        else if (key.l == ARP0Key.l) process_ARP_packet(strip_info, &header, ptr, end);
-        else if (key.l == ATR_Key.l) process_AT_response(strip_info, ptr, end);
-        else if (key.l == ERR_Key.l) RecvErr_Message(strip_info, sendername, ptr);
-        else RecvErr("Unrecognized protocol key", strip_info);
-    }
+    else if (key.l == ACK_Key.l) process_ACK        (strip_info, ptr, end);
+    else if (key.l == INF_Key.l) process_Info       (strip_info, ptr, end);
+    else if (key.l == ERR_Key.l) RecvErr_Message    (strip_info, sendername, ptr);
+    else                         RecvErr("Unrecognized protocol key", strip_info);
+#endif
 }
 
+#define TTYERROR(X) ((X) == TTY_BREAK   ? "Break"            : \
+                     (X) == TTY_FRAME   ? "Framing Error"    : \
+                     (X) == TTY_PARITY  ? "Parity Error"     : \
+                     (X) == TTY_OVERRUN ? "Hardware Overrun" : "Unknown Error")
+
 /*
  * Handle the 'receiver data ready' interrupt.
  * This function is called by the 'tty_io' module in the kernel when
@@ -2229,17 +2223,23 @@
     {
     struct timeval tv;
     do_gettimeofday(&tv);
-    printk(KERN_INFO "**** strip_receive_buf: %3d bytes at %d.%06d\n",
+    printk(KERN_INFO "**** strip_receive_buf: %3d bytes at %02d.%06d\n",
         count, tv.tv_sec % 100, tv.tv_usec);
     }
 #endif
 
+#ifdef EXT_COUNTERS
+    strip_info->rx_sbytes += count;
+#endif
+
     /* Read the characters out of the buffer */
     while (cp < end)
     {
+        if (fp && *fp) printk(KERN_INFO "%s: %s on serial port\n", strip_info->dev.name, TTYERROR(*fp));
         if (fp && *fp++ && !strip_info->discard) /* If there's a serial error, record it */
         {
-            strip_info->discard = 1;
+            /* If we have some characters in the buffer, discard them */
+            strip_info->discard = strip_info->sx_count;
             strip_info->rx_errors++;
         }
 
@@ -2249,21 +2249,23 @@
             if (*cp == 0x0D)                /* If end of packet, decide what to do with it */
             {
                 if (strip_info->sx_count > 3000)
-                    printk(KERN_INFO "Cut a %d byte packet (%d bytes remaining)%s\n",
-                        strip_info->sx_count, end-cp-1,
+                    printk(KERN_INFO "%s: Cut a %d byte packet (%d bytes remaining)%s\n",
+                        strip_info->dev.name, strip_info->sx_count, end-cp-1,
                         strip_info->discard ? " (discarded)" : "");
                 if (strip_info->sx_count > strip_info->sx_size)
                 {
-                    strip_info->discard = 1;
                     strip_info->rx_over_errors++;
                     printk(KERN_INFO "%s: sx_buff overflow (%d bytes total)\n",
                            strip_info->dev.name, strip_info->sx_count);
                 }
-                if (!strip_info->discard) process_packet(strip_info);
+                else if (strip_info->discard)
+                    printk(KERN_INFO "%s: Discarding bad packet (%d/%d)\n",
+                        strip_info->dev.name, strip_info->discard, strip_info->sx_count);
+                else process_message(strip_info);
                 strip_info->discard = 0;
                 strip_info->sx_count = 0;
             }
-            else if (!strip_info->discard) /* If we're not discarding, store the character */
+            else
             {
                 /* Make sure we have space in the buffer */
                 if (strip_info->sx_count < strip_info->sx_size)
@@ -2279,9 +2281,28 @@
 /************************************************************************/
 /* General control routines						*/
 
-static int strip_set_dev_mac_address(struct device *dev, void *addr)
+static int set_mac_address(struct strip *strip_info, MetricomAddress *addr)
 {
-    return -1;        /* You cannot override a Metricom radio's address */
+    /*
+     * We're using a manually specified address if the address is set
+     * to anything other than all ones. Setting the address to all ones
+     * disables manual mode and goes back to automatic address determination
+     * (tracking the true address that the radio has).
+     */
+    strip_info->manual_dev_addr = memcmp(addr->c, broadcast_address.c, sizeof(broadcast_address));
+    if (strip_info->manual_dev_addr)
+         *(MetricomAddress*)strip_info->dev.dev_addr = *addr;
+    else *(MetricomAddress*)strip_info->dev.dev_addr = strip_info->true_dev_addr;
+    return 0;
+}
+
+static int dev_set_mac_address(struct device *dev, void *addr)
+{
+    struct strip *strip_info = (struct strip *)(dev->priv);
+    struct sockaddr *sa = addr;
+    printk(KERN_INFO "%s: strip_set_dev_mac_address called\n", dev->name);
+    set_mac_address(strip_info, (MetricomAddress *)sa->sa_data);
+    return 0;
 }
 
 static struct net_device_stats *strip_get_stats(struct device *dev)
@@ -2341,7 +2362,8 @@
 
     strip_info->discard  = 0;
     strip_info->working  = FALSE;
-    strip_info->structured_messages = FALSE;
+    strip_info->firmware_level = NoStructure;
+    strip_info->next_command   = CompatibilityCommand;
     strip_info->sx_count = 0;
     strip_info->tx_left  = 0;
 
@@ -2442,7 +2464,7 @@
     dev->rebuild_header     = strip_rebuild_header;
     /*  dev->type_trans            unused */
     /*  dev->set_multicast_list   unused */
-    dev->set_mac_address    = strip_set_dev_mac_address;
+    dev->set_mac_address    = dev_set_mac_address;
     /*  dev->do_ioctl             unused */
     /*  dev->set_config           unused */
     dev->get_stats          = strip_get_stats;
@@ -2455,19 +2477,10 @@
 
 static void strip_free(struct strip *strip_info)
 {
-    MetricomNode *node, *free;
-
     *(strip_info->referrer) = strip_info->next;
     if (strip_info->next)
         strip_info->next->referrer = strip_info->referrer;
     strip_info->magic = 0;
-
-    for (node = strip_info->neighbor_list; node != NULL; )
-    {
-        free = node;
-        node = node->next;
-        kfree(free);
-    }
     kfree(strip_info);
 }
 
@@ -2522,13 +2535,9 @@
     strip_info->idle_timer.data     = (long)&strip_info->dev;
     strip_info->idle_timer.function = strip_IdleTask;
 
-    strip_info->neighbor_list = kmalloc(sizeof(MetricomNode), GFP_KERNEL);
-    strip_info->neighbor_list->type = 0;
-    strip_info->neighbor_list->next = NULL;
-
     /* Note: strip_info->if_name is currently 8 characters long */
-    sprintf(strip_info->if_name, "st%d", channel_id);
-    strip_info->dev.name         = strip_info->if_name;
+    sprintf(strip_info->if_name.c, "st%d", channel_id);
+    strip_info->dev.name         = strip_info->if_name.c;
     strip_info->dev.base_addr    = channel_id;
     strip_info->dev.priv         = (void*)strip_info;
     strip_info->dev.next         = NULL;
@@ -2598,6 +2607,9 @@
 #ifdef MODULE
     MOD_INC_USE_COUNT;
 #endif
+
+    printk(KERN_INFO "STRIP: device \"%s\" activated\n", strip_info->if_name.c);
+
     /*
      * Done.  We have linked the TTY line to a channel.
      */
@@ -2627,6 +2639,7 @@
 
     tty->disc_data = 0;
     strip_info->tty = NULL;
+    printk(KERN_INFO "STRIP: device \"%s\" closed down\n", strip_info->if_name.c);
     strip_free(strip_info);
     tty->disc_data = NULL;
 #ifdef MODULE
@@ -2657,12 +2670,17 @@
             err = verify_area(VERIFY_WRITE, (void*)arg, 16);
             if (err)
                 return -err;
-            copy_to_user((void*)arg, strip_info->dev.name,
-                strlen(strip_info->dev.name) + 1);
-            return 0;
+            return copy_to_user((void*)arg, strip_info->dev.name,
+                strlen(strip_info->dev.name) + 1)?-EFAULT:0;
 
         case SIOCSIFHWADDR:
-            return -EINVAL;
+            {
+            MetricomAddress addr;
+            printk(KERN_INFO "%s: SIOCSIFHWADDR\n", strip_info->dev.name);
+            if(copy_from_user(&addr, (void*)arg, sizeof(MetricomAddress)))
+            	return -EFAULT;
+            return(set_mac_address(strip_info, &addr));
+            }
 
         /*
          * Allow stty to read, but not set, the serial port
@@ -2683,32 +2701,6 @@
 /* Initialization							*/
 
 /*
- *      Registers with the /proc file system to create different /proc/net files.
- */
-
-static int strip_proc_net_register(unsigned short type, char *file_name,
-                                   int (*get_info)(char *, char **, off_t, int, int))
-{
-    struct proc_dir_entry *strip_entry;
-
-    strip_entry = kmalloc(sizeof(struct proc_dir_entry), GFP_ATOMIC);
-
-    memset(strip_entry, 0, sizeof(struct proc_dir_entry));
-    strip_entry->low_ino = type;
-    strip_entry->namelen = strlen(file_name);
-    strip_entry->name = file_name;
-    strip_entry->mode = S_IFREG | S_IRUGO;
-    strip_entry->nlink = 1;
-    strip_entry->uid = 0;
-    strip_entry->gid = 0;
-    strip_entry->size = 0;
-    strip_entry->ops = &proc_net_inode_operations;
-    strip_entry->get_info = get_info;
-
-    return proc_net_register(strip_entry);
-}
-
-/*
  * Initialize the STRIP driver.
  * This routine is called at boot time, to bootstrap the multi-channel
  * STRIP driver
@@ -2722,7 +2714,7 @@
     static struct tty_ldisc strip_ldisc;
     int status;
 
-    printk("STRIP: version %s (unlimited channels)\n", StripVersion);
+    printk(KERN_INFO "STRIP: Version %s (unlimited channels)\n", StripVersion);
 
     /*
      * Fill in our line protocol discipline, and register it
@@ -2747,24 +2739,12 @@
     }
 
     /*
-     * Register the status and trace files with /proc
+     * Register the status file with /proc
      */
-
-#if DO_PROC_NET_STRIP_STATUS
-    if (strip_proc_net_register(PROC_NET_STRIP_STATUS, "strip_status",
-                                               &strip_get_status_info) != 0)
+    if (proc_net_register(&proc_strip_get_status_info) != 0)
     {
-        printk(KERN_ERR "strip: status strip_proc_net_register() failed.\n");
+        printk(KERN_ERR "strip: status proc_net_register() failed.\n");
     }
-#endif
-
-#if DO_PROC_NET_STRIP_TRACE
-    if (strip_proc_net_register(PROC_NET_STRIP_TRACE, "strip_trace",
-                    &strip_get_trace_info) != 0)
-    {
-        printk(KERN_ERR "strip: trace strip_proc_net_register() failed.\n");
-    }
-#endif
 
 #ifdef MODULE
      return status;
@@ -2794,16 +2774,12 @@
     while (struct_strip_list)
         strip_free(struct_strip_list);
 
-    /* Unregister with the /proc/net files here. */
-
-#if DO_PROC_NET_STRIP_TRACE
-    proc_net_unregister(PROC_NET_STRIP_TRACE);
-#endif
-#if DO_PROC_NET_STRIP_STATUS
+    /* Unregister with the /proc/net file here. */
     proc_net_unregister(PROC_NET_STRIP_STATUS);
-#endif
 
     if ((i = tty_register_ldisc(N_STRIP, NULL)))
         printk(KERN_ERR "STRIP: can't unregister line discipline (err = %d)\n", i);
+
+    printk(KERN_INFO "STRIP: Module Unloaded\n");
 }
 #endif /* MODULE */
diff -u --recursive --new-file v2.1.44/linux/drivers/net/sunhme.c linux/drivers/net/sunhme.c
--- v2.1.44/linux/drivers/net/sunhme.c	Thu May 15 16:48:03 1997
+++ linux/drivers/net/sunhme.c	Wed Jul 16 19:22:51 1997
@@ -946,7 +946,8 @@
 		/* Because we reserve afterwards. */
 		skb_put(skb, (ETH_FRAME_LEN + RX_OFFSET));
 
-		hb->happy_meal_rxd[i].rx_addr = (unsigned int) skb->data;
+		hb->happy_meal_rxd[i].rx_addr =
+			(u32) ((unsigned long)skb->data);
 		skb_reserve(skb, RX_OFFSET);
 		hb->happy_meal_rxd[i].rx_flags =
 			(RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16));
@@ -1615,7 +1616,8 @@
 			/* Return it to the Happy meal. */
 	drop_it:
 			hp->net_stats.rx_dropped++;
-			this->rx_addr = (unsigned int) hp->rx_skbs[elem]->data;
+			this->rx_addr =
+				(u32) ((unsigned long)hp->rx_skbs[elem]->data);
 			this->rx_flags =
 				(RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16));
 			goto next;
@@ -1634,7 +1636,8 @@
 			hp->rx_skbs[elem] = new_skb;
 			new_skb->dev = dev;
 			skb_put(new_skb, (ETH_FRAME_LEN + RX_OFFSET));
-			rxbase[elem].rx_addr = (unsigned int) new_skb->data;
+			rxbase[elem].rx_addr =
+				(u32) ((unsigned long)new_skb->data);
 			skb_reserve(new_skb, RX_OFFSET);
 			rxbase[elem].rx_flags =
 				(RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16));
@@ -1655,7 +1658,8 @@
 			memcpy(copy_skb->data, skb->data, len);
 
 			/* Reuse original ring buffer. */
-			rxbase[elem].rx_addr = (unsigned int) skb->data;
+			rxbase[elem].rx_addr =
+				(u32) ((unsigned long)skb->data);
 			rxbase[elem].rx_flags =
 				(RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16));
 
@@ -1913,7 +1917,8 @@
 
 	SXD(("SX<l[%d]e[%d]>", len, entry));
 	hp->tx_skbs[entry] = skb;
-	hp->happy_block->happy_meal_txd[entry].tx_addr = (unsigned int) skb->data;
+	hp->happy_block->happy_meal_txd[entry].tx_addr =
+		(u32) ((unsigned long)skb->data);
 	hp->happy_block->happy_meal_txd[entry].tx_flags =
 		(TXFLAG_OWN | TXFLAG_SOP | TXFLAG_EOP | (len & TXFLAG_SIZE));
 	hp->tx_new = NEXT_TX(entry);
@@ -2087,6 +2092,8 @@
 	printk("\n");
 
 	hp = (struct happy_meal *) dev->priv;
+	memset(hp, 0, sizeof(*hp));
+
 	hp->happy_sbus_dev = sdev;
 
 	if(sdev->num_registers != 5) {
diff -u --recursive --new-file v2.1.44/linux/drivers/net/sunqe.c linux/drivers/net/sunqe.c
--- v2.1.44/linux/drivers/net/sunqe.c	Tue May 13 22:41:12 1997
+++ linux/drivers/net/sunqe.c	Wed Jul 16 19:22:51 1997
@@ -152,8 +152,8 @@
 		skb_put(skb, ETH_FRAME_LEN);
 		skb_reserve(skb, 34);
 
-		/* FIX FOR ULTRA */
-		qb->qe_rxd[i].rx_addr = (unsigned int) skb->data;
+		qb->qe_rxd[i].rx_addr =
+			(unsigned int) ((unsigned long)skb->data);
 		qb->qe_rxd[i].rx_flags =
 			(RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH));
 	}
@@ -491,7 +491,8 @@
 	drop_it:
 			/* Return it to the QE. */
 			qep->net_stats.rx_dropped++;
-			this->rx_addr = (unsigned int) qep->rx_skbs[elem]->data;
+			this->rx_addr =
+				(unsigned int) ((unsigned long)qep->rx_skbs[elem]->data);
 			this->rx_flags =
 				(RXD_OWN | (RX_BUF_ALLOC_SIZE & RXD_LENGTH));
 			goto next;
@@ -512,8 +513,8 @@
 			skb_put(new_skb, ETH_FRAME_LEN);
 			skb_reserve(new_skb, 34);
 
-			/* FIX FOR ULTRA */
-			rxbase[elem].rx_addr = (unsigned int) new_skb->data;
+			rxbase[elem].rx_addr =
+				(unsigned int) ((unsigned long)new_skb->data);
 			rxbase[elem].rx_flags =
 				(RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH));
 
@@ -533,7 +534,8 @@
 			eth_copy_and_sum(copy_skb, (unsigned char *)skb->data, len, 0);
 
 			/* Reuse original ring buffer. */
-			rxbase[elem].rx_addr = (unsigned int) skb->data;
+			rxbase[elem].rx_addr =
+				(unsigned int) ((unsigned long)skb->data);
 			rxbase[elem].rx_flags =
 				(RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH));
 
diff -u --recursive --new-file v2.1.44/linux/drivers/net/tlan.c linux/drivers/net/tlan.c
--- v2.1.44/linux/drivers/net/tlan.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/tlan.c	Wed Jul 16 19:22:51 1997
@@ -0,0 +1,2309 @@
+/********************************************************************
+ *
+ *  Linux ThunderLAN Driver
+ *
+ *  tlan.c
+ *  by James Banks, james.banks@caldera.com
+ *
+ *  (C) 1997 Caldera, Inc.
+ *
+ *  This software may be used and distributed according to the terms
+ *  of the GNU Public License, incorporated herein by reference.
+ *
+ ** This file is best viewed/edited with tabstop=4 and colums>=132.
+ *
+ ** Useful (if not required) reading:
+ *
+ *		Texas Instruments, ThunderLAN Programmer's Guide,
+ *			TI Literature Number SPWU013A
+ *			available in PDF format from www.ti.com
+ *		National Semiconductor, DP83840A Data Sheet
+ *			available in PDF format from www.national.com
+ *		Microchip Technology, 24C01A/02A/04A Data Sheet
+ *			available in PDF format from www.microchip.com
+ *
+ ********************************************************************/
+
+
+#include <linux/module.h>
+
+
+#include "tlan.h"
+
+
+#include <linux/bios32.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/etherdevice.h>
+
+
+
+
+#ifdef MODULE
+	static	struct device	*TLanDevices = NULL;
+	static	int				TLanDevicesInstalled = 0;
+#endif
+	static  int				debug = 0;
+	static	u8				*TLanPadBuffer;
+	static	char			TLanSignature[] = "TLAN";
+	static	int				TLanVersionMajor = 0;
+	static	int				TLanVersionMinor = 27;
+
+	static	TLanPciId TLanDeviceList[] = {
+		{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETELLIGENT_10,  "Compaq Netelligent 10" },
+		{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETELLIGENT_10_100, "Compaq Netelligent 10/100" }, 
+		{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETFLEX_3_INTEGRATED, "Compaq Integrated NetFlex-3" }, 
+		{ 0, 0, NULL } /* End of List */
+	};
+
+
+	static int  TLan_MiiReadReg(u16, u16, u16, u16 *);
+	static void TLan_MiiSendData( u16, u32, unsigned );
+	static void TLan_MiiSync(u16);
+	static void TLan_MiiWriteReg(u16, u16, u16, u16);
+
+
+
+/*****************************************************************************
+******************************************************************************
+
+	ThunderLAN Driver MII Routines
+
+	These routines are based on the information in Chap. 2 of the
+	"ThunderLAN Programmer's Guide", pp. 15-24.
+
+******************************************************************************
+*****************************************************************************/
+
+
+	/*************************************************************************
+	 *	TLan_MiiReadReg
+	 *
+	 *	Returns:	0 if ack received ok, 1 otherwise.
+	 *	Parms:		base_port	The base IO port of the adapter in question.
+	 *				dev			The address of the PHY to be queried.
+	 *				reg			The register whose contents are to be
+	 *							retreived.
+	 *				val			A pointer to a variable to store the retrieved
+	 *							value.
+	 *
+	 *	This function uses the TLAN's MII bus to retreive the contents of a
+	 *	given register on a PHY.  It sends the appropriate info and then
+	 *	reads the 16-bit register value from the MII bus via the TLAN SIO
+	 *	register.
+	 *
+	 ************************************************************************/
+
+		int TLan_MiiReadReg(u16 base_port, u16 dev, u16 reg, u16 *val)
+		{
+			u8	nack;
+			u16 sio, tmp;
+			u32 i;
+			int	err;
+
+			err = FALSE;
+			outw(TLAN_NET_SIO, base_port + TLAN_DIO_ADR);
+			sio = base_port + TLAN_DIO_DATA + TLAN_NET_SIO;
+
+			cli();
+
+			TLan_MiiSync(base_port);
+
+			TLan_ClearBit(TLAN_NET_SIO_MINTEN, sio);		/* Disable PHY ints */
+
+			TLan_MiiSendData( base_port, 0x1, 2 );			/* Start ( 01b ) */
+			TLan_MiiSendData( base_port, 0x2, 2 );			/* Read  ( 10b ) */
+			TLan_MiiSendData( base_port, dev, 5 );			/* Device #      */
+			TLan_MiiSendData( base_port, reg, 5 );			/* Register #    */
+
+
+			TLan_ClearBit(TLAN_NET_SIO_MTXEN, sio);			/* Change direction */
+
+			TLan_ClearBit(TLAN_NET_SIO_MCLK, sio);			/* Clock through Idle bit */
+			TLan_SetBit(TLAN_NET_SIO_MCLK, sio);
+			TLan_ClearBit(TLAN_NET_SIO_MCLK, sio);			/* Use this to wait 300ns */
+
+			nack = TLan_GetBit(TLAN_NET_SIO_MDATA, sio);	/* Check for ACK */
+			TLan_SetBit(TLAN_NET_SIO_MCLK, sio);			/* Finish ACK clock cycle */
+			if (nack) {										/* No ACK, so fake it */
+				for (i = 0; i < 16; i++) {
+					TLan_ClearBit(TLAN_NET_SIO_MCLK, sio);
+					TLan_SetBit(TLAN_NET_SIO_MCLK, sio);
+				}
+				tmp = 0xffff;
+				err = TRUE;
+			} else {										/* ACKed, so read data */
+				for (tmp = 0, i = 0x8000; i; i >>= 1) {
+					TLan_ClearBit(TLAN_NET_SIO_MCLK, sio);
+					if (TLan_GetBit(TLAN_NET_SIO_MDATA, sio))
+						tmp |= i;
+					TLan_SetBit(TLAN_NET_SIO_MCLK, sio);
+				}
+			}
+
+
+			TLan_ClearBit(TLAN_NET_SIO_MCLK, sio);			/* Idle cycle */
+			TLan_SetBit(TLAN_NET_SIO_MCLK, sio);
+
+			TLan_SetBit(TLAN_NET_SIO_MINTEN, sio);			/* Enable PHY ints */
+
+			*val = tmp;
+
+			sti();
+
+			return err;
+
+		} /* TLan_MiiReadReg */
+
+
+
+
+	/*************************************************************************
+	 *	TLan_MiiSendData
+	 *
+	 *	Returns:	Nothing
+	 *	Parms:		base_port	The base IO port of the adapter in question.
+	 *				dev			The address of the PHY to be queried.
+	 *				data		The value to be placed on the MII bus.
+	 *				num_bits	The number of bits in data that are to be
+	 *							placed on the MII bus.
+	 *
+	 *	This function sends on sequence of bits on the MII configuration
+	 *	bus.
+	 *
+	 ************************************************************************/
+
+	 	void TLan_MiiSendData( u16 base_port, u32 data, unsigned num_bits )
+		{
+			u16 sio;
+			u32 i;
+
+			if ( num_bits == 0 )
+				return;
+
+			outw( TLAN_NET_SIO, base_port + TLAN_DIO_ADR );
+			sio = base_port + TLAN_DIO_DATA + TLAN_NET_SIO;
+			TLan_SetBit( TLAN_NET_SIO_MTXEN, sio );
+
+			for ( i = ( 0x1 << ( num_bits - 1 ) ); i; i >>= 1 ) {
+				TLan_ClearBit( TLAN_NET_SIO_MCLK, sio );
+				TLan_GetBit( TLAN_NET_SIO_MCLK, sio );
+				if ( data & i )
+					TLan_SetBit( TLAN_NET_SIO_MDATA, sio );
+				else
+					TLan_ClearBit( TLAN_NET_SIO_MDATA, sio );
+				TLan_SetBit( TLAN_NET_SIO_MCLK, sio );
+				TLan_GetBit( TLAN_NET_SIO_MCLK, sio );
+			}
+
+		} /* TLan_MiiSendData */
+
+
+
+
+	/*************************************************************************
+	 *	TLan_MiiSync
+	 *
+	 *	Returns:	Nothing
+	 *	Parms:		base_port	The base IO port of the adapter in question.
+	 *
+	 *	This functions syncs all PHYs in terms of the MII configuration bus.
+	 *
+	 ************************************************************************/
+
+	 	void TLan_MiiSync( u16 base_port )
+		{
+			int i;
+			u16 sio;
+
+			outw( TLAN_NET_SIO, base_port + TLAN_DIO_ADR );
+			sio = base_port + TLAN_DIO_DATA + TLAN_NET_SIO;
+
+			TLan_ClearBit( TLAN_NET_SIO_MTXEN, sio );
+			for ( i = 0; i < 32; i++ ) {
+				TLan_ClearBit( TLAN_NET_SIO_MCLK, sio );
+				TLan_SetBit( TLAN_NET_SIO_MCLK, sio );
+			}
+
+		} /* TLan_MiiSync */
+
+
+
+
+	/*************************************************************************
+	 *	TLan_MiiWriteReg
+	 *
+	 *	Returns:	Nothing
+	 *	Parms:		base_port	The base IO port of the adapter in question.
+	 *				dev			The address of the PHY to be written to.
+	 *				reg			The register whose contents are to be
+	 *							written.
+	 *				val			The value to be written to the register.
+	 *
+	 *	This function uses the TLAN's MII bus to write the contents of a
+	 *	given register on a PHY.  It sends the appropriate info and then
+	 *	writes the 16-bit register value from the MII configuration bus
+	 *	via the TLAN SIO register.
+	 *
+	 ************************************************************************/
+
+		void TLan_MiiWriteReg(u16 base_port, u16 dev, u16 reg, u16 val)
+		{
+			u16 sio;
+
+			outw(TLAN_NET_SIO, base_port + TLAN_DIO_ADR);
+			sio = base_port + TLAN_DIO_DATA + TLAN_NET_SIO;
+
+			cli();
+
+			TLan_MiiSync( base_port );
+
+			TLan_ClearBit( TLAN_NET_SIO_MINTEN, sio );
+
+			TLan_MiiSendData( base_port, 0x1, 2 );			/* Start ( 01b ) */
+			TLan_MiiSendData( base_port, 0x1, 2 );			/* Write ( 01b ) */
+			TLan_MiiSendData( base_port, dev, 5 );			/* Device #      */
+			TLan_MiiSendData( base_port, reg, 5 );			/* Register #    */
+
+			TLan_MiiSendData( base_port, 0x2, 2 );			/* Send ACK */
+			TLan_MiiSendData( base_port, val, 16 );			/* Send Data */
+
+			TLan_ClearBit( TLAN_NET_SIO_MCLK, sio );		/* Idle cycle */
+			TLan_SetBit( TLAN_NET_SIO_MCLK, sio );
+
+			TLan_SetBit( TLAN_NET_SIO_MINTEN, sio );
+
+			sti();
+
+		} /* TLan_MiiWriteReg */
+
+
+
+
+/*****************************************************************************
+******************************************************************************
+
+	ThunderLAN Driver PHY Layer Routines
+
+	The TLAN chip can drive any number of PHYs (physical devices).  Rather
+	than having lots of 'if' or '#ifdef' statements, I have created a
+	second driver layer for the PHYs.  Each PHY can be identified from its
+	id in registers 2 and 3, and can be given a Check and Service routine
+	that will be called when the adapter is reset and when the adapter
+	receives a Network Status interrupt, respectively.
+	
+******************************************************************************
+*****************************************************************************/
+
+	static int	TLan_PhyNop( struct device * );
+	static void	TLan_PhyPrint( struct device * );
+	static void	TLan_PhySelect( struct device * );
+	static int	TLan_PhyInternalCheck( struct device * );
+	static int	TLan_PhyInternalService( struct device * );
+	static int	TLan_PhyDp83840aCheck( struct device * );
+
+
+
+
+	static TLanPhyIdEntry	TLanPhyIdTable[] = {
+		{ 0x4000, 0x5014, &TLan_PhyInternalCheck, &TLan_PhyInternalService, TLAN_PHY_ACTIVITY },
+		{ 0x4000, 0x5015, &TLan_PhyInternalCheck, &TLan_PhyInternalService, TLAN_PHY_ACTIVITY },
+		{ 0x2000, 0x5C01, &TLan_PhyDp83840aCheck, &TLan_PhyNop, TLAN_PHY_ACTIVITY | TLAN_PHY_AUTONEG },
+		{ 0x0000, 0x0000, NULL, NULL, 0 }
+	};
+
+
+
+
+    /*************************************************************************
+     *  TLan_PhyPrint
+	 *
+	 *	Returns:	Nothing
+	 *	Parms:		dev		A pointer to the device structure of the adapter
+	 *						which the desired PHY is located.
+	 *				
+	 *	This function prints the registers a PHY.
+     *
+     ************************************************************************/
+
+        void TLan_PhyPrint( struct device *dev )
+        {
+            TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
+            u16 i, data0, data1, data2, data3, phy;
+            u32 io;
+
+            phy = priv->phyAddr;
+            io = dev->base_addr;
+
+            if ( ( phy > 0 ) || ( phy <= TLAN_PHY_MAX_ADDR ) ) {
+                printk( "TLAN:   Device %s, PHY 0x%02x.\n", dev->name, phy );
+                printk( "TLAN:      Off.  +0     +1     +2     +3 \n" );
+                for ( i = 0; i < 0x20; i+= 4 ) {
+                    TLan_MiiReadReg( io, phy, i, &data0 );
+                    TLan_MiiReadReg( io, phy, i + 1, &data1 );
+                    TLan_MiiReadReg( io, phy, i + 2, &data2 );
+                    TLan_MiiReadReg( io, phy, i + 3, &data3 );
+                    printk( "TLAN:      0x%02x  0x%04hx 0x%04hx 0x%04hx 0x%04hx\n", i, data0, data1, data2, data3 );
+                }
+            } else {
+                printk( "TLAN:   Device %s, PHY 0x%02x (Invalid).\n", dev->name, phy );
+            }
+
+        } /* TLan_PhyPrint */
+
+
+
+
+    /*************************************************************************
+     *  TLan_PhySelect
+	 *
+	 *	Returns:	Nothing
+	 *	Parms:		dev		A pointer to the device structure of the adapter
+	 *						for which the PHY needs determined.
+     *
+	 *	This function decides which PHY amoung those attached to the TLAN chip
+	 *	is to be used.  The TLAN chip can be attached to multiple PHYs, and
+	 *	the driver needs to decide which one to talk to.  Currently this
+	 *	routine picks the PHY with the lowest address as the internal PHY
+	 *	address is 0x1F, the highest possible.  This strategy assumes that
+	 *	there can be only one other PHY, and, if it exists, it is the one to
+	 *	be used.  If token ring PHYs are ever supported, this routine will
+	 *	become a little more interesting...
+	 *
+     ************************************************************************/
+
+		void TLan_PhySelect( struct device *dev )
+		{
+			int				err;
+			int 			phy;
+			int				entry;
+			u16				id_hi;
+			u16				id_lo;
+			TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
+			u16				val;
+
+			priv->phyCheck = &TLan_PhyNop;		// Make absolutely sure these aren't NULL
+			priv->phyService = &TLan_PhyNop;
+
+			for ( phy = 0; phy <= TLAN_PHY_MAX_ADDR; phy++ ) {
+				err = TLan_MiiReadReg( dev->base_addr, phy, 0, &val );
+				if ( ! err ) {
+					TLan_MiiReadReg( dev->base_addr, phy, MII_GEN_ID_HI, &id_hi );
+					TLan_MiiReadReg( dev->base_addr, phy, MII_GEN_ID_LO, &id_lo );
+					entry = 0;
+					while ( ( TLanPhyIdTable[entry].idHi != 0 ) && ( TLanPhyIdTable[entry].idLo != 0 ) ) {
+						if ( ( TLanPhyIdTable[entry].idHi == id_hi ) && ( TLanPhyIdTable[entry].idLo == id_lo ) ) {
+							priv->phyAddr = phy;
+							priv->phyEntry = entry;
+							priv->phyCheck = TLanPhyIdTable[entry].check;
+							priv->phyService = TLanPhyIdTable[entry].service;
+							priv->phyFlags = TLanPhyIdTable[entry].flags;
+							break;
+						}
+						entry++;
+					}
+					break;
+				}
+			}
+
+		} /* TLan_PhySelect */
+
+
+
+
+    /*************************************************************************
+     *  TLan_PhyNop
+     *
+	 *	Returns:	Nothing
+	 *	Parms:		dev		A pointer to a device structure.
+	 *
+	 *	This function does nothing and is meant as a stand-in for when
+	 *	a Check or Service function would be meaningless.
+	 *
+     ************************************************************************/
+
+		int TLan_PhyNop( struct device *dev )
+		{
+			dev = NULL;
+			return 0;
+
+		} /* TLan_PhyNop */
+
+
+
+
+    /*************************************************************************
+     *  TLan_PhyInternalCheck
+     *
+	 *	Returns:	Nothing
+	 *	Parms:		dev		A pointer to a device structure of the adapter
+	 *						holding the PHY to be checked.
+	 *
+	 *	This function resets the internal PHY on a TLAN chip.  See Chap. 7,
+	 *	"Physical Interface (PHY)" of "ThunderLAN Programmer's Guide"
+     *
+     ************************************************************************/
+
+		int TLan_PhyInternalCheck( struct device *dev )
+		{
+			u16				gen_ctl;
+			int				i;
+			u32				io;
+			u16				phy;
+			TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
+			u16				value;
+
+			io = dev->base_addr;
+			phy = priv->phyAddr;
+
+			TLan_MiiReadReg( io, phy, MII_GEN_CTL, &gen_ctl );
+			if ( gen_ctl & MII_GC_PDOWN ) {
+				TLan_MiiSync( io );
+            	TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_PDOWN | MII_GC_LOOPBK | MII_GC_ISOLATE );
+            	TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_LOOPBK );
+				for ( i = 0; i < 500000; i++ )
+					SLOW_DOWN_IO;
+            	TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_RESET | MII_GC_LOOPBK );
+            	TLan_MiiSync( io );
+			}
+
+            TLan_MiiReadReg( io, phy, MII_GEN_CTL, &value );
+           	while ( value & MII_GC_RESET )
+               	TLan_MiiReadReg( io, phy, MII_GEN_CTL, &value );
+
+            // TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_LOOPBK | MII_GC_DUPLEX );
+            // TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_DUPLEX );
+            TLan_MiiWriteReg( io, phy, MII_GEN_CTL, 0 );
+
+				for ( i = 0; i < 500000; i++ )
+					SLOW_DOWN_IO;
+
+			// Read Possible Latched Link Status
+            TLan_MiiReadReg( io, phy, MII_GEN_STS, &value ); 
+			// Read Real Link Status
+            TLan_MiiReadReg( io, phy, MII_GEN_STS, &value ); 
+			if ( value & MII_GS_LINK ) {
+				priv->phyOnline = 1;
+				TLan_DioWrite8( io, TLAN_LED_REG, TLAN_LED_LINK );
+			} else {
+				priv->phyOnline = 0;
+				TLan_DioWrite8( io, TLAN_LED_REG, 0 );
+			}
+
+			// Enable Interrupts
+            TLan_MiiReadReg( io, phy, TLAN_TLPHY_CTL, &value );
+            value |= TLAN_TC_INTEN;
+            TLan_MiiWriteReg( io, phy, TLAN_TLPHY_CTL, value );
+			
+			return 0;
+
+		} /* TLanPhyInternalCheck */
+
+
+
+
+    /*************************************************************************
+     *  TLan_PhyInternalService
+     *
+	 *	Returns:	Nothing
+	 *	Parms:		dev		A pointer to a device structure of the adapter
+	 *						holding the PHY to be serviced.
+	 *
+	 *	This function services an interrupt generated by the internal PHY.
+	 *	It can turn on/off the link LED.  See Chap. 7,
+	 *	"Physical Interface (PHY)" of "ThunderLAN Programmer's Guide".
+     *
+     ************************************************************************/
+
+		int TLan_PhyInternalService( struct device *dev )
+		{
+			u16				tlphy_sts;
+			u16				gen_sts;
+			u16				an_exp;
+			u32				io;
+			u16				phy;
+			TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
+
+			io = dev->base_addr;
+			phy = priv->phyAddr;
+
+			TLan_MiiReadReg( io, phy, TLAN_TLPHY_STS, &tlphy_sts );
+           	TLan_MiiReadReg( io, phy, MII_GEN_STS, &gen_sts ); 
+           	TLan_MiiReadReg( io, phy, MII_AN_EXP, &an_exp ); 
+			if ( gen_sts & MII_GS_LINK ) {
+				priv->phyOnline = 1;
+				TLan_DioWrite8( io, TLAN_LED_REG, TLAN_LED_LINK );
+			} else {
+				priv->phyOnline = 0;
+				TLan_DioWrite8( io, TLAN_LED_REG, 0 );
+			}
+
+			return 0;
+
+		} /* TLan_PhyInternalService */
+
+
+
+
+    /*************************************************************************
+     *  TLan_PhyDp83840aCheck
+     *
+	 *	Returns:	Nothing
+	 *	Parms:		dev		A pointer to a device structure of the adapter
+	 *						holding the PHY to be reset.
+	 *
+	 *	This function resets a National Semiconductor DP83840A 10/100 Mb/s
+	 *	PHY device.  See National Semiconductor's data sheet for more info.
+	 *	This PHY is used on Compaq Netelligent 10/100 cards.
+     *
+     ************************************************************************/
+
+		static int	TLan_PhyDp83840aCheck( struct device *dev )
+		{
+			u16				gen_ctl;
+			int				i;
+			u32				io;
+			u16				phy;
+			TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
+			u16				value;
+
+			io = dev->base_addr;
+			phy = priv->phyAddr;
+
+			TLan_MiiReadReg( io, phy, MII_GEN_CTL, &gen_ctl );
+			if ( gen_ctl & MII_GC_PDOWN ) {
+				TLan_MiiSync( io );
+            	TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_PDOWN | MII_GC_LOOPBK | MII_GC_ISOLATE );
+            	TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_LOOPBK );
+				for ( i = 0; i < 500000; i++ )
+					SLOW_DOWN_IO;
+            	TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_RESET | MII_GC_LOOPBK );
+            	TLan_MiiSync( io );
+			}
+
+            TLan_MiiReadReg( io, phy, MII_GEN_CTL, &value );
+           	while ( value & MII_GC_RESET )
+               	TLan_MiiReadReg( io, phy, MII_GEN_CTL, &value );
+
+            // TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_LOOPBK | MII_GC_DUPLEX );
+            // TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_DUPLEX );
+            TLan_MiiWriteReg( io, phy, MII_GEN_CTL, 0 );
+            TLan_MiiWriteReg( io, phy, MII_GEN_CTL, 0x1000 );
+			TLan_MiiWriteReg( io, phy, MII_GEN_CTL, 0x1200 );
+
+				for ( i = 0; i < 50000; i++ )
+					SLOW_DOWN_IO;
+
+/*
+			// Read Possible Latched Link Status
+            TLan_MiiReadReg( io, phy, MII_GEN_STS, &value ); 
+			// Read Real Link Status
+            TLan_MiiReadReg( io, phy, MII_GEN_STS, &value ); 
+			if ( value & MII_GS_LINK ) {
+				priv->phyOnline = 1;
+				TLan_DioWrite8( io, TLAN_LED_REG, TLAN_LED_LINK );
+			} else {
+				priv->phyOnline = 0;
+				TLan_DioWrite8( io, TLAN_LED_REG, 0 );
+			}
+
+			// Enable Interrupts
+            TLan_MiiReadReg( io, phy, TLAN_TLPHY_CTL, &value );
+            value |= TLAN_TC_INTEN;
+            TLan_MiiWriteReg( io, phy, TLAN_TLPHY_CTL, value );
+*/
+			priv->phyOnline = 1;
+			
+			return 0;
+
+		} /* TLan_PhyDp83840aCheck */
+
+
+
+
+/*****************************************************************************
+******************************************************************************
+
+	ThunderLAN Driver Adapter Related Routines
+
+******************************************************************************
+*****************************************************************************/
+
+
+
+	static void TLan_ResetLists( struct device * );
+	static void	TLan_PrintDio( u16 );
+	static void TLan_PrintList( TLanList *, char *, int );
+	static void	TLan_ReadAndClearStats( struct device *, int );
+	static int	TLan_Reset( struct device * );
+	static void TLan_SetMac( struct device *, int areg, char *mac );
+
+
+
+
+	/*************************************************************************
+	 *	TLan_ResetLists
+	 *  
+	 *  Returns:	Nothing
+	 *	Parms:		dev		The device structure with the list stuctures to
+	 *						be reset.
+	 *
+	 *	This routine sets the variables associated with managing the TLAN
+	 *	lists to their initial values.
+	 *
+	 ************************************************************************/
+
+		void TLan_ResetLists( struct device *dev )
+		{
+			int             i;
+			TLanList        *list;
+			TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
+
+			priv->txHead = 0;
+			priv->txTail = 0;
+			for ( i = 0; i < TLAN_NUM_TX_LISTS; i++ ) {
+				list = priv->txList + i;
+				list->cStat = TLAN_CSTAT_UNUSED;
+				list->buffer[0].address = virt_to_bus( priv->txBuffer + ( i * TLAN_MAX_FRAME_SIZE ) );
+				list->buffer[2].count = 0;
+				list->buffer[2].address = 0;
+			}
+
+			priv->rxHead = 0;
+			priv->rxTail = TLAN_NUM_RX_LISTS - 1;
+			for ( i = 0; i < TLAN_NUM_RX_LISTS; i++ ) {
+				list = priv->rxList + i;
+				list->cStat = TLAN_CSTAT_READY;
+				list->frameSize = TLAN_MAX_FRAME_SIZE;
+				list->buffer[0].count = TLAN_MAX_FRAME_SIZE | TLAN_LAST_BUFFER;
+				list->buffer[0].address = virt_to_bus( priv->rxBuffer + ( i * TLAN_MAX_FRAME_SIZE ) );
+				list->buffer[1].count = 0;
+				list->buffer[1].address = 0;
+				if ( i < TLAN_NUM_RX_LISTS - 1 )
+					list->forward = virt_to_bus( list + 1 );
+				else
+					list->forward = 0;
+			}
+
+		} /* TLan_ResetLists */
+
+
+
+
+	/*************************************************************************
+	 *	TLan_PrintDio
+	 *  
+	 *  Returns:	Nothing
+	 *	Parms:		io_base		Base IO port of the device of which to print
+	 *							DIO registers.
+	 *
+	 *	This function prints out all the the internal (DIO) registers of a
+	 *	TLAN chip.
+	 *
+	 ************************************************************************/
+
+		void TLan_PrintDio( u16 io_base )
+		{
+			u32 data0, data1;
+			int	i;
+
+			printk( "TLAN:   Contents of internal registers for io base 0x%04hx.\n", io_base );
+			printk( "TLAN:      Off.  +0         +4\n" );
+			for ( i = 0; i < 0x4C; i+= 8 ) {
+				data0 = TLan_DioRead32( io_base, i );
+				data1 = TLan_DioRead32( io_base, i + 0x4 );
+				printk( "TLAN:      0x%02x  0x%08x 0x%08x\n", i, data0, data1 );
+			}
+
+		} /* TLan_PrintDio */
+
+
+
+
+	/*************************************************************************
+	 *	TLan_PrintList
+	 *  
+	 *  Returns:	Nothing
+	 *	Parms:		list	A pointer to the TLanList structure to be printed.
+	 *				type	A string to designate type of list, "Rx" or "Tx".
+	 *				num		The index of the list.
+	 *
+	 *	This function prints out the contents of the list pointed to by the
+	 *	list parameter.
+	 *
+	 ************************************************************************/
+
+		void TLan_PrintList( TLanList *list, char *type, int num)
+		{
+			int i;
+
+			printk( "TLAN:   %s List %d at 0x%08x\n", type, num, (u32) list );
+			printk( "TLAN:      Forward    = 0x%08x\n",  list->forward );
+			printk( "TLAN:      CSTAT      = 0x%04hx\n", list->cStat );
+			printk( "TLAN:      Frame Size = 0x%04hx\n", list->frameSize );
+			for ( i = 0; i < 10; i++ ) {
+				printk( "TLAN:      Buffer[%d].count, addr = 0x%08x, 0x%08x\n", i, list->buffer[i].count, list->buffer[i].address );
+			}
+
+		} /* TLan_PrintList */
+
+
+
+
+	/*************************************************************************
+	 *	TLan_ReadAndClearStats
+	 *
+	 *	Returns:	Nothing
+	 *	Parms:		dev		Pointer to device structure of adapter to which
+	 *						to read stats.
+	 *				record	Flag indicating whether to add 
+	 *
+	 *	This functions reads all the internal status registers of the TLAN
+	 *	chip, which clears them as a side effect.  It then either adds the
+	 *	values to the device's status struct, or discards them, depending
+	 *	on whether record is TLAN_RECORD (!=0)  or TLAN_IGNORE (==0).
+	 *
+	 ************************************************************************/
+
+		void TLan_ReadAndClearStats( struct device *dev, int record )
+		{
+			TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
+			u32				tx_good, tx_under;
+			u32				rx_good, rx_over;
+			u32				def_tx, crc, code;
+			u32				multi_col, single_col;
+			u32				excess_col, late_col, loss;
+
+			outw( TLAN_GOOD_TX_FRMS, dev->base_addr + TLAN_DIO_ADR );
+			tx_good  = inb( dev->base_addr + TLAN_DIO_DATA );
+			tx_good += inb( dev->base_addr + TLAN_DIO_DATA + 1 ) << 8;
+			tx_good += inb( dev->base_addr + TLAN_DIO_DATA + 2 ) << 16;
+			tx_under = inb( dev->base_addr + TLAN_DIO_DATA + 3 );
+
+			outw( TLAN_GOOD_RX_FRMS, dev->base_addr + TLAN_DIO_ADR );
+			rx_good  = inb( dev->base_addr + TLAN_DIO_DATA );
+			rx_good += inb( dev->base_addr + TLAN_DIO_DATA + 1 ) << 8;
+			rx_good += inb( dev->base_addr + TLAN_DIO_DATA + 2 ) << 16;
+			rx_over  = inb( dev->base_addr + TLAN_DIO_DATA + 3 );
+			
+			outw( TLAN_DEFERRED_TX, dev->base_addr + TLAN_DIO_ADR );
+			def_tx  = inb( dev->base_addr + TLAN_DIO_DATA );
+			def_tx += inb( dev->base_addr + TLAN_DIO_DATA + 1 ) << 8;
+			crc     = inb( dev->base_addr + TLAN_DIO_DATA + 2 );
+			code    = inb( dev->base_addr + TLAN_DIO_DATA + 3 );
+			
+			outw( TLAN_MULTICOL_FRMS, dev->base_addr + TLAN_DIO_ADR );
+			multi_col   = inb( dev->base_addr + TLAN_DIO_DATA );
+			multi_col  += inb( dev->base_addr + TLAN_DIO_DATA + 1 ) << 8;
+			single_col  = inb( dev->base_addr + TLAN_DIO_DATA + 2 );
+			single_col += inb( dev->base_addr + TLAN_DIO_DATA + 3 ) << 8;
+
+			outw( TLAN_EXCESSCOL_FRMS, dev->base_addr + TLAN_DIO_ADR );
+			excess_col = inb( dev->base_addr + TLAN_DIO_DATA );
+			late_col   = inb( dev->base_addr + TLAN_DIO_DATA + 1 );
+			loss       = inb( dev->base_addr + TLAN_DIO_DATA + 2 );
+
+			if ( record ) {
+				priv->stats.rx_packets += rx_good;
+				priv->stats.rx_errors  += rx_over + crc + code;
+				priv->stats.tx_packets += tx_good;
+				priv->stats.tx_errors  += tx_under + loss;
+				priv->stats.collisions += multi_col + single_col + excess_col + late_col;
+
+				priv->stats.rx_over_errors    += rx_over;
+				priv->stats.rx_crc_errors     += crc;
+				priv->stats.rx_frame_errors   += code;
+
+				priv->stats.tx_aborted_errors += tx_under;
+				priv->stats.tx_carrier_errors += loss;
+			}
+			
+		} /* TLan_ReadAndClearStats */
+
+
+
+
+	/*************************************************************************
+	 *	TLan_Reset
+	 *
+	 *	Returns:	0
+	 *	Parms:		dev		Pointer to device structure of adapter to be
+	 *						reset.
+	 *
+	 *	This function resets the adapter and it's physical device.  See
+	 *	Chap. 3, pp. 9-10 of the "ThunderLAN Programmer's Guide" for details.
+	 *	The routine tries to implement what is detailed there, though
+	 *	adjustments have been made.
+	 *
+	 ************************************************************************/
+
+		int TLan_Reset( struct device *dev )
+		{
+			TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
+			int i;
+			u32	data;
+			u8	data8;
+
+		//	1.  Assume Stat registers have been dealt with.
+		//	2.  Assert reset bit.
+			data = inl(dev->base_addr + TLAN_HOST_CMD);
+			data |= TLAN_HC_AD_RST;
+			outl(data, dev->base_addr + TLAN_HOST_CMD);
+		//	3.  Turn off interrupts.
+			data = inl(dev->base_addr + TLAN_HOST_CMD);
+			data |= TLAN_HC_INT_OFF;
+			outl(data, dev->base_addr + TLAN_HOST_CMD);
+		//	4.	Setup AREGs and HASHs.
+		 	for ( i = TLAN_AREG_0; i <= TLAN_HASH_2; i += 4 )
+				TLan_DioWrite32( dev->base_addr, (u16) i, 0 );
+		//	5.	Setup NetConfig register.
+			outw(TLAN_NET_CONFIG, dev->base_addr + TLAN_DIO_ADR);
+			outw(TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN | TLAN_NET_CFG_PHY_EN, dev->base_addr + TLAN_DIO_DATA);
+		//	6.	Setup BSIZE register.
+		//		Accept defaults, 0x22, for now.
+		//	7.	Setup TX commit in Acommit.
+		//		Allow it to manage itself.
+		//	8.	Load Ld_Tmr in HOST_CMD.
+		//		I don't know what this value should be.  I'll try 3.
+		 	outl( TLAN_HC_LD_TMR | 0x0, dev->base_addr + TLAN_HOST_CMD );
+		//	9.	Load Ld_Thr in HOST_CMD.
+		//		Try 1 for now.
+		 	outl( TLAN_HC_LD_THR | 0x1, dev->base_addr + TLAN_HOST_CMD );
+		//	10. Unreset the MII by setting NMRST (in NetSio) to 1.
+			outw( TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR );
+			TLan_SetBit( TLAN_NET_SIO_NMRST, dev->base_addr + TLAN_DIO_DATA + TLAN_NET_SIO );
+		//	10a. Other.
+		//	12. Setup the NetMask register.
+		TLan_DioWrite8( dev->base_addr, TLAN_INT_DIS, TLAN_ID_TX_EOC | TLAN_ID_RX_EOC );
+		//TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, TLAN_NET_CMD_NRESET | TLAN_NET_CMD_NWRAP | TLAN_NET_CMD_DUPLEX | TLAN_NET_CMD_CAF );
+		TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, TLAN_NET_CMD_NRESET | TLAN_NET_CMD_NWRAP );
+		//	11. Initialize PHYs.
+		TLan_PhySelect( dev );
+		(*priv->phyCheck)( dev ); 
+		if ( debug >= 1 )
+			TLan_PhyPrint( dev );
+
+		//data8 = TLAN_NET_MASK_MASK4 | TLAN_NET_MASK_MASK5 | TLAN_NET_MASK_MASK6 | TLAN_NET_MASK_MASK7; 
+		data8 = TLAN_NET_MASK_MASK4 | TLAN_NET_MASK_MASK5 | TLAN_NET_MASK_MASK7; 
+		TLan_DioWrite8( dev->base_addr, TLAN_NET_MASK, data8 );
+		TLan_DioWrite16( dev->base_addr, TLAN_MAX_RX, 1550 );
+		 /*
+		  *	13. Turn on interrupts to host.
+		  *		I don't want any interrupts, yet.
+		  */
+			/*
+			data = inl(base_port + TLAN_HOST_CMD);
+			data |= TLAN_HC_INT_ON;
+			outl(data, base_port + TLAN_HOST_CMD);
+			*/
+
+			return 0;
+
+		} /* TLan_Reset */
+
+
+
+
+	/*************************************************************************
+	 *	TLan_SetMac
+	 *
+	 *	Returns:	Nothing
+	 *	Parms:		dev		Pointer to device structure of adapter on which to
+	 *						change the AREG.
+	 *				areg	The AREG to set the address in (0 - 3).
+	 *				mac		A pointer to an array of chars.  Each element
+	 *						stores one byte of the address.  IE, it isn't
+	 *						in ascii.
+	 *
+	 *	This function transfers a MAC address to one of the TLAN AREGs
+	 *	(address registers).  The TLAN chip locks the register on writing to
+	 *	offset 0 and unlocks the register after writing to offset 5.  If NULL
+	 *	is passed in mac, then the AREG is filled with 0's.
+	 *
+	 ************************************************************************/
+
+		void TLan_SetMac( struct device *dev, int areg, char *mac )
+		{
+			int i;
+			
+			areg *= 6;
+
+			if ( mac != NULL ) {
+				for ( i = 0; i < 6; i++ )
+					TLan_DioWrite8( dev->base_addr, TLAN_AREG_0 + areg + i, mac[i] );
+			} else {
+				for ( i = 0; i < 6; i++ )
+					TLan_DioWrite8( dev->base_addr, TLAN_AREG_0 + areg + i, 0 );
+			}
+
+		} /* TLan_SetMac */
+
+
+
+
+/*****************************************************************************
+******************************************************************************
+
+	ThunderLAN Driver Eeprom routines
+
+	The Compaq Netelligent 10 and 10/100 cards use a Microchip 24C02A EEPROM.
+	These functions are based on information in Microchip's data sheet.  I
+	don't know how well this functions will work with other EEPROMs.
+
+******************************************************************************
+*****************************************************************************/
+
+		static void TLan_EeSendStart( u16 );
+		static int	TLan_EeSendByte( u16, u8, int );
+		static void TLan_EeReceiveByte( u16, u8 *, int );
+		static int	TLan_EeReadByte( u16, u8, u8 * );
+
+
+
+
+	/*************************************************************************
+	 *	TLan_EeSendStart
+	 *
+	 *	Returns:	Nothing
+	 *	Parms:		io_base		The IO port base address for the TLAN device
+	 *							with the EEPROM to use.
+	 *
+	 *	This function sends a start cycle to an EEPROM attached to a TLAN
+	 *	chip.
+	 *
+	 ************************************************************************/
+
+		void TLan_EeSendStart( u16 io_base )
+		{
+			u16 sio;
+
+			outw( TLAN_NET_SIO, io_base + TLAN_DIO_ADR );
+			sio = io_base + TLAN_DIO_DATA + TLAN_NET_SIO;
+
+			TLan_SetBit( TLAN_NET_SIO_ECLOK, sio );
+			TLan_SetBit( TLAN_NET_SIO_EDATA, sio );
+			TLan_SetBit( TLAN_NET_SIO_ETXEN, sio );
+			//
+			// FIXME: Do I really need these SLOW_DOWN_IOs?
+			//
+			SLOW_DOWN_IO;
+			TLan_ClearBit( TLAN_NET_SIO_EDATA, sio );
+			SLOW_DOWN_IO;
+			TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio );
+			SLOW_DOWN_IO;
+
+		} /* TLan_EeSendStart */
+
+
+
+
+	/*************************************************************************
+	 *	TLan_EeSendByte
+	 *
+	 *	Returns:	If the correct ack was received, 0, otherwise 1
+	 *	Parms:		io_base		The IO port base address for the TLAN device
+	 *							with the EEPROM to use.
+	 *				data		The 8 bits of information to send to the
+	 *							EEPROM.
+	 *				stop		If TLAN_EEPROM_STOP is passed, a stop cycle is
+	 *							sent after the byte is sent after the ack is
+	 *							read.
+	 *
+	 *	This function sends a byte on the serial EEPROM line, driving the
+	 *	clock to send each bit. The function then reverses transmission
+	 *	direction and reads an acknowledge bit.
+	 *
+	 ************************************************************************/
+
+		int	TLan_EeSendByte( u16 io_base, u8 data, int stop )
+		{
+			int err;
+			u8  place;
+			u16 sio;
+
+			outw( TLAN_NET_SIO, io_base + TLAN_DIO_ADR );
+			sio = io_base + TLAN_DIO_DATA + TLAN_NET_SIO;
+
+			// Assume clock is low, tx is enabled;
+			for ( place = 0x80; place; place >>= 1 ) {
+				if ( place & data )
+					TLan_SetBit( TLAN_NET_SIO_EDATA, sio );
+				else
+					TLan_ClearBit( TLAN_NET_SIO_EDATA, sio );
+				TLan_SetBit( TLAN_NET_SIO_ECLOK, sio );
+				TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio );
+			}
+			TLan_ClearBit( TLAN_NET_SIO_ETXEN, sio );
+			TLan_SetBit( TLAN_NET_SIO_ECLOK, sio );
+			err = TLan_GetBit( TLAN_NET_SIO_EDATA, sio );
+			TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio );
+			TLan_SetBit( TLAN_NET_SIO_ETXEN, sio );
+
+			if ( ( ! err ) && stop ) {
+				TLan_ClearBit( TLAN_NET_SIO_EDATA, sio );	// STOP, raise data while clock is high
+				TLan_SetBit( TLAN_NET_SIO_ECLOK, sio );
+				TLan_SetBit( TLAN_NET_SIO_EDATA, sio );
+			}
+
+			return ( err );
+
+		} /* TLan_EeSendByte */
+
+
+
+
+	/*************************************************************************
+	 *	TLan_EeReceiveByte
+	 *
+	 *	Returns:	Nothing
+	 *	Parms:		io_base		The IO port base address for the TLAN device
+	 *							with the EEPROM to use.
+	 *				data		An address to a char to hold the data sent
+	 *							from the EEPROM.
+	 *				stop		If TLAN_EEPROM_STOP is passed, a stop cycle is
+	 *							sent after the byte is received, and no ack is
+	 *							sent.
+	 *
+	 *	This function receives 8 bits of data from the EEPROM over the serial
+	 *	link.  It then sends and ack bit, or no ack and a stop bit.  This
+	 *	function is used to retrieve data after the address of a byte in the
+	 *	EEPROM has been sent.
+	 *
+	 ************************************************************************/
+
+		void TLan_EeReceiveByte( u16 io_base, u8 *data, int stop )
+		{
+			u8  place;
+			u16 sio;
+
+			outw( TLAN_NET_SIO, io_base + TLAN_DIO_ADR );
+			sio = io_base + TLAN_DIO_DATA + TLAN_NET_SIO;
+			*data = 0;
+
+			// Assume clock is low, tx is enabled;
+			TLan_ClearBit( TLAN_NET_SIO_ETXEN, sio );
+			for ( place = 0x80; place; place >>= 1 ) {
+				TLan_SetBit( TLAN_NET_SIO_ECLOK, sio );
+				if ( TLan_GetBit( TLAN_NET_SIO_EDATA, sio ) )
+					*data |= place;
+				TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio );
+			}
+
+			TLan_SetBit( TLAN_NET_SIO_ETXEN, sio );
+			if ( ! stop ) {
+				TLan_ClearBit( TLAN_NET_SIO_EDATA, sio );	// Ack = 0
+				TLan_SetBit( TLAN_NET_SIO_ECLOK, sio );
+				TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio );
+			} else {
+				TLan_SetBit( TLAN_NET_SIO_EDATA, sio );		// No ack = 1 (?)
+				TLan_SetBit( TLAN_NET_SIO_ECLOK, sio );
+				TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio );
+				TLan_ClearBit( TLAN_NET_SIO_EDATA, sio );	// STOP, raise data while clock is high
+				TLan_SetBit( TLAN_NET_SIO_ECLOK, sio );
+				TLan_SetBit( TLAN_NET_SIO_EDATA, sio );
+			}
+
+		} /* TLan_EeReceiveByte */
+
+
+
+
+	/*************************************************************************
+	 *	TLan_EeReadByte
+	 *
+	 *	Returns:	No error = 0, else, the stage at which the error occured.
+	 *	Parms:		io_base		The IO port base address for the TLAN device
+	 *							with the EEPROM to use.
+	 *				ee_addr		The address of the byte in the EEPROM whose
+	 *							contents are to be retrieved.
+	 *				data		An address to a char to hold the data obtained
+	 *							from the EEPROM.
+	 *
+	 *	This function reads a byte of information from an byte cell in the
+	 *	EEPROM.
+	 *
+	 ************************************************************************/
+
+		int TLan_EeReadByte( u16 io_base, u8 ee_addr, u8 *data )
+		{
+			int err;
+
+			cli();
+
+			TLan_EeSendStart( io_base );
+			err = TLan_EeSendByte( io_base, 0xA0, TLAN_EEPROM_ACK );
+			if (err)
+				return 1;
+			err = TLan_EeSendByte( io_base, ee_addr, TLAN_EEPROM_ACK );
+			if (err)
+				return 2;
+			TLan_EeSendStart( io_base );
+			err = TLan_EeSendByte( io_base, 0xA1, TLAN_EEPROM_ACK );
+			if (err)
+				return 3;
+			TLan_EeReceiveByte( io_base, data, TLAN_EEPROM_STOP );
+
+			sti();
+
+			return 0;
+
+		} /* TLan_EeReadByte */
+
+
+
+
+/*****************************************************************************
+******************************************************************************
+
+        ThunderLAN Driver Interrupt Vectors and Table
+
+		Please see Chap. 4, "Interrupt Handling" of the
+		"ThunderLAN Programmer's Guide" for more informations on handling
+		interrupts generated by TLAN based adapters.  
+
+******************************************************************************
+*****************************************************************************/
+
+	static u32 TLan_HandleInvalid( struct device *, u16 );
+	static u32 TLan_HandleTxEOF( struct device *, u16 );
+	static u32 TLan_HandleStatOverflow( struct device *, u16 );
+	static u32 TLan_HandleRxEOF( struct device *, u16 );
+	static u32 TLan_HandleDummy( struct device *, u16 );
+	static u32 TLan_HandleTxEOC( struct device *, u16 );
+	static u32 TLan_HandleStatusCheck( struct device *, u16 );
+	static u32 TLan_HandleRxEOC( struct device *, u16 );
+
+
+
+
+	typedef u32 (TLanIntVectorFunc)( struct device *, u16 );
+	
+
+
+
+	/*************************************************************************
+	 *	TLan_HandleInvalid
+	 *
+	 *	Returns:	0
+	 *	Parms:		dev			Device assigned the IRQ that was raised.
+	 *				host_int	The contents of the HOST_INT port.
+	 *
+	 *	This function handles invalid interrupts.  This should never happen
+	 *	unless some other adapter is trying to use the IRQ line assigned to
+	 *	the device.
+	 *
+	 ************************************************************************/
+
+		u32 TLan_HandleInvalid( struct device *dev, u16 host_int )
+		{
+			host_int = 0;
+			// printk( "TLAN:  Invalid interrupt on %s.\n", dev->name );
+			return 0;
+
+		} /* TLan_HandleInvalid */
+
+
+	/*************************************************************************
+	 *	TLan_HandleTxEOF
+	 *
+	 *	Returns:	1
+	 *	Parms:		dev			Device assigned the IRQ that was raised.
+	 *				host_int	The contents of the HOST_INT port.
+	 *
+	 *	This function handles Tx EOF interrupts which are raised by the
+	 *	adapter when it has completed sending the contents of a buffer.  If
+	 *	detemines which list/buffer was completed and resets it.  If the
+	 *	buffer was the last in the channel (EOC), then the function checks
+	 *	to see if another buffer is ready to send, and if so, sends a Tx Go
+	 *	command.  Finally, the driver activates/continues the activity LED.
+	 *
+	 ************************************************************************/
+
+		u32 TLan_HandleTxEOF( struct device *dev, u16 host_int )
+		{
+			TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
+			int				eoc = 0;
+			TLanList		*head_list;
+			u32				ack = 1;
+
+			// printk( "TLAN:  Handling Tx EOF\n" );
+			host_int = 0;
+			head_list = priv->txList + priv->txHead;
+			if ( head_list->cStat & TLAN_CSTAT_EOC )
+				eoc = 1;
+			if ( ! head_list->cStat & TLAN_CSTAT_FRM_CMP ) {
+				printk( "TLAN:  Received interrupt for uncompleted TX frame.\n" );
+			}
+			// printk( "Ack %d CSTAT=%hx\n", priv->txHead, head_list->cStat );
+			head_list->cStat = TLAN_CSTAT_UNUSED;
+			dev->tbusy = 0;
+			priv->txHead++;
+			if ( priv->txHead >= TLAN_NUM_TX_LISTS )
+				priv->txHead = 0;
+			if ( eoc ) {
+				// printk( "TLAN:  Handling Tx EOC\n" );
+				head_list = priv->txList + priv->txHead;
+				if ( ( head_list->cStat & TLAN_CSTAT_READY ) == TLAN_CSTAT_READY ) {
+					outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM );
+					ack |= TLAN_HC_GO;
+				} else {
+					priv->txInProgress = 0;
+				}
+			}
+			TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT );
+			if ( priv->phyFlags & TLAN_PHY_ACTIVITY ) {
+				if ( priv->timerSetAt == 0 ) {
+					// printk("TxEOF Starting timer...\n");
+					priv->timerSetAt = jiffies;
+					priv->timer.expires = jiffies + TLAN_TIMER_ACT_DELAY;
+					priv->timerType = TLAN_TIMER_ACT;
+					add_timer( &priv->timer );
+				} else if ( priv->timerType == TLAN_TIMER_ACT ) {
+					priv->timerSetAt = jiffies;
+					// printk("TxEOF continuing timer...\n");
+				}
+			}
+
+			return ack;
+
+		} /* TLan_HandleTxEOF */
+
+
+
+
+	/*************************************************************************
+	 *	TLan_HandleStatOverflow
+	 *
+	 *	Returns:	1
+	 *	Parms:		dev			Device assigned the IRQ that was raised.
+	 *				host_int	The contents of the HOST_INT port.
+	 *
+	 *	This function handles the Statistics Overflow interrupt which means
+	 *	that one or more of the TLAN statistics registers has reached 1/2
+	 *	capacity and needs to be read.
+	 *
+	 ************************************************************************/
+
+		u32 TLan_HandleStatOverflow( struct device *dev, u16 host_int )
+		{
+			host_int = 0;
+			TLan_ReadAndClearStats( dev, TLAN_RECORD );
+
+			return 1;
+
+		} /* TLan_HandleStatOverflow */
+
+
+
+
+	/*************************************************************************
+	 *	TLan_HandleRxEOF
+	 *
+	 *	Returns:	1
+	 *	Parms:		dev			Device assigned the IRQ that was raised.
+	 *				host_int	The contents of the HOST_INT port.
+	 *
+	 *	This function handles the Rx EOF interrupt which indicates a frame
+	 *	has been received by the adapter from the net and the frame has been
+	 *	transferred to memory.  The function determines the bounce buffer
+	 *	the frame has been loaded into, creates a new sk_buff big enough to
+	 *	hold the frame, and sends it to protocol stack.  It then resets the
+	 *	used buffer and appends it to the end of the list.  If the frame was
+	 *	the last in the Rx channel (EOC), the function restarts the receive
+	 *	channel by sending an Rx Go command to the adapter.  Then it activates/
+	 *	continues the the activity LED.
+	 *
+	 ************************************************************************/
+
+		u32 TLan_HandleRxEOF( struct device *dev, u16 host_int )
+		{
+			u32				ack = 1;
+			int				eoc = 0;
+			u8				*head_buffer;
+			TLanList		*head_list;
+			TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
+			struct sk_buff	*skb;
+			TLanList		*tail_list;
+			void			*t;
+
+			// printk( "TLAN:  Handling Rx EOF Head=%d Tail=%d\n", priv->rxHead, priv->rxTail );
+			host_int = 0;
+			head_list = priv->rxList + priv->rxHead;
+			tail_list = priv->rxList + priv->rxTail;
+			if ( head_list->cStat & TLAN_CSTAT_EOC )
+				eoc = 1;
+			if ( ! head_list->cStat & TLAN_CSTAT_FRM_CMP ) {
+				printk( "TLAN:  Received interrupt for uncompleted RX frame.\n" );
+			} else {
+				skb = dev_alloc_skb( head_list->frameSize + 7 );
+				if ( skb == NULL ) { 
+					printk( "TLAN:  Couldn't allocate memory for received data.\n" );
+				} else {
+					head_buffer = priv->rxBuffer + ( priv->rxHead * TLAN_MAX_FRAME_SIZE );
+					skb->dev = dev;
+					skb_reserve( skb, 2 );
+					t = (void *) skb_put( skb, head_list->frameSize );
+					// printk( " %hd %p %p\n", head_list->frameSize, skb->data, t );
+					memcpy( t, head_buffer, head_list->frameSize );
+					skb->protocol = eth_type_trans( skb, dev );
+					netif_rx( skb );
+				}
+			}
+			head_list->forward = 0;
+			head_list->frameSize = TLAN_MAX_FRAME_SIZE;
+			head_list->buffer[0].count = TLAN_MAX_FRAME_SIZE | TLAN_LAST_BUFFER;
+			tail_list->forward = virt_to_bus( head_list );
+			priv->rxHead++;
+			if ( priv->rxHead >= TLAN_NUM_RX_LISTS )
+				priv->rxHead = 0;
+			priv->rxTail++;
+			if ( priv->rxTail >= TLAN_NUM_RX_LISTS )
+				priv->rxTail = 0;
+			if ( eoc ) { 
+				// printk( "TLAN:  Handling Rx EOC Head=%d Tail=%d\n", priv->rxHead, priv->rxTail );
+				head_list = priv->rxList + priv->rxHead;
+				outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM );
+				ack |= TLAN_HC_GO | TLAN_HC_RT;
+				priv->rxEocCount++;
+			}
+			TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT );
+			if ( priv->phyFlags & TLAN_PHY_ACTIVITY ) {
+				if ( priv->timerSetAt == 0 )  {
+					// printk("RxEOF Starting timer...\n");
+					priv->timerSetAt = jiffies;
+					priv->timer.expires = jiffies + TLAN_TIMER_ACT_DELAY;
+					priv->timerType = TLAN_TIMER_ACT;
+					add_timer( &priv->timer );
+				} else if ( priv->timerType == TLAN_TIMER_ACT ) {
+					// printk("RxEOF tarting continuing timer...\n");
+					priv->timerSetAt = jiffies;
+				}
+			}
+			dev->last_rx = jiffies;
+
+			return ack;
+
+		} /* TLan_HandleRxEOF */
+
+
+
+
+	/*************************************************************************
+	 *	TLan_HandleDummy
+	 *
+	 *	Returns:	1
+	 *	Parms:		dev			Device assigned the IRQ that was raised.
+	 *				host_int	The contents of the HOST_INT port.
+	 *
+	 *	This function handles the Dummy interrupt, which is raised whenever
+	 *	a test interrupt is generated by setting the Req_Int bit of HOST_CMD
+	 *	to 1.
+	 *
+	 ************************************************************************/
+
+		u32 TLan_HandleDummy( struct device *dev, u16 host_int )
+		{
+			host_int = 0;
+			printk( "TLAN:  Dummy interrupt on %s.\n", dev->name );
+			return 1;
+
+		} /* TLan_HandleDummy */
+
+
+
+
+	/*************************************************************************
+	 *	TLan_HandleTxEOC
+	 *
+	 *	Returns:	1
+	 *	Parms:		dev			Device assigned the IRQ that was raised.
+	 *				host_int	The contents of the HOST_INT port.
+	 *
+	 *	This driver is structured to determine EOC occurances by reading the
+	 *	CSTAT member of the list structure.  Tx EOC interrupts are disabled
+	 *	via the DIO INTDIS register.
+	 *
+	 ************************************************************************/
+
+		u32 TLan_HandleTxEOC( struct device *dev, u16 host_int )
+		{
+			host_int = 0;
+			printk( "TLAN:  Tx EOC interrupt on %s.\n", dev->name );
+			return 1;
+
+		} /* TLan_HandleTxEOC */
+
+
+
+
+	/*************************************************************************
+	 *	TLan_HandleStatusCheck
+	 *
+	 *	Returns:	0 if Adapter check, 1 if Network Status check.
+	 *	Parms:		dev			Device assigned the IRQ that was raised.
+	 *				host_int	The contents of the HOST_INT port.
+	 *
+	 *	This function handles Adapter Check/Network Status interrupts
+	 *	generated by the adapter.  It checks the vector in the HOST_INT
+	 *	register to determine if it is an Adapter Check interrupt.  If so,
+	 *	it resets the adapter.  Otherwise it clears the status registers
+	 *	and services the PHY.
+	 *
+	 ************************************************************************/
+
+		u32 TLan_HandleStatusCheck( struct device *dev, u16 host_int )
+		{	
+			u32				ack;
+			u32				error;
+			u8				net_sts;
+			TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
+			
+			ack = 1;
+			if ( host_int & TLAN_HI_IV_MASK ) {
+				error = inl( dev->base_addr + TLAN_CH_PARM );
+				printk( "TLAN:   Adaptor Check on device %s err = 0x%x\n", dev->name, error );
+				TLan_ReadAndClearStats( dev, TLAN_RECORD );
+				outl( TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD );
+				TLan_ResetLists( dev );
+				TLan_Reset( dev );
+				dev->tbusy = 0;
+				TLan_SetMac( dev, 0, dev->dev_addr );
+				if ( priv->timerType == 0 ) {
+					if ( priv->phyFlags & TLAN_PHY_AUTONEG ) {
+						priv->timer.expires = jiffies + TLAN_TIMER_LINK_DELAY;
+						priv->timerSetAt = jiffies;
+						priv->timerType = TLAN_TIMER_LINK;
+						add_timer( &priv->timer );
+					} else {
+						//printk( " RX GO---->\n" );
+						outl( virt_to_bus( priv->rxList ), dev->base_addr + TLAN_CH_PARM );
+						outl( TLAN_HC_GO | TLAN_HC_RT, dev->base_addr + TLAN_HOST_CMD );
+					}
+				}
+				ack = 0;
+			} else {
+				net_sts = TLan_DioRead8( dev->base_addr, TLAN_NET_STS );
+				if ( net_sts )
+					TLan_DioWrite8( dev->base_addr, TLAN_NET_STS, net_sts );
+				if ( net_sts & TLAN_NET_STS_MIRQ )
+					(*priv->phyService)( dev );
+					
+				TLAN_DBG( 1, "TLAN: Status Check! %s Net_Sts=%x\n", dev->name, (unsigned) net_sts );
+			}
+
+			return ack;
+
+		} /* TLan_HandleStatusCheck */
+
+
+
+
+	/*************************************************************************
+	 *	TLan_HandleRxEOC
+	 *
+	 *	Returns:	1
+	 *	Parms:		dev			Device assigned the IRQ that was raised.
+	 *				host_int	The contents of the HOST_INT port.
+	 *
+	 *	This driver is structured to determine EOC occurances by reading the
+	 *	CSTAT member of the list structure.  Rx EOC interrupts are disabled
+	 *	via the DIO INTDIS register.
+	 *
+	 ************************************************************************/
+
+		u32 TLan_HandleRxEOC( struct device *dev, u16 host_int )
+		{
+			host_int = 0;
+			printk( "TLAN:  Rx EOC interrupt on %s.\n", dev->name );
+			return 1;
+
+		} /* TLan_HandleRxEOC */
+
+
+
+	static TLanIntVectorFunc *TLanIntVector[TLAN_INT_NUMBER_OF_INTS] = {
+		TLan_HandleInvalid,
+		TLan_HandleTxEOF,
+		TLan_HandleStatOverflow,
+		TLan_HandleRxEOF,
+		TLan_HandleDummy,
+		TLan_HandleTxEOC,
+		TLan_HandleStatusCheck,
+		TLan_HandleRxEOC
+	};
+
+
+
+
+/*****************************************************************************
+******************************************************************************
+
+	ThunderLAN Driver Timer Function
+
+******************************************************************************
+*****************************************************************************/
+
+	static void	TLan_Timer( unsigned long );
+
+
+
+
+	/*************************************************************************
+	 *	TLan_Timer
+	 *
+	 *	Returns:	Nothing
+	 *	Parms:		data	A value given to add timer when add_timer was
+	 *						called.
+	 *
+	 *	This function handles timed functionality for the TLAN driver.  The
+	 *	two current timer uses are for delaying for autonegotionation and
+	 *	driving the ACT LED.
+	 *	-	Autonegotiation requires being allowed about 2 1/2 seconds before
+	 *		attempting to transmit a packet.  It would be a very bad thing
+	 *		to hang the kernel this long, so the driver doesn't allow
+	 *		transmission 'til after this time, for certain PHYs.  It would
+	 *		be much nicer if all PHYs were interrupt-capable like the
+	 *		internal PHY.
+	 *	-	The ACT LED, which shows adapter activity, is driven by the driver,
+	 *		and so must be left on for a short period to power up the LED so
+	 *		it can be seen.  This delay can be changed by changing the
+	 *		TLAN_TIMER_ACT_DELAY in tlan.h, if desired.  10 jiffies produces a 
+	 *		slightly sluggish response.
+	 *
+	 ************************************************************************/
+
+		void TLan_Timer( unsigned long data )
+		{
+			struct device	*dev = (struct device *) data;
+			u16				gen_sts;
+			TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
+
+			// printk( "TLAN:  %s Entered Timer, type = %d\n", dev->name, priv->timerType );
+
+			switch ( priv->timerType ) {
+				case TLAN_TIMER_LINK:
+					TLan_MiiReadReg( dev->base_addr, priv->phyAddr, MII_GEN_STS, &gen_sts );
+					if ( gen_sts & MII_GS_LINK ) {
+						priv->phyOnline = 1;
+						outl( virt_to_bus( priv->rxList ), dev->base_addr + TLAN_CH_PARM );
+						outl( TLAN_HC_GO | TLAN_HC_RT, dev->base_addr + TLAN_HOST_CMD );
+						priv->timerSetAt = 0;
+						priv->timerType = 0;
+					} else {
+						priv->timer.expires = jiffies + ( TLAN_TIMER_LINK_DELAY * 2 );
+						add_timer( &priv->timer );
+					}
+					break;
+				case TLAN_TIMER_ACT:
+					if ( jiffies - priv->timerSetAt >= TLAN_TIMER_ACT_DELAY ) {
+						TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK );
+						priv->timerSetAt = 0;
+						priv->timerType = 0;
+					} else {
+						priv->timer.expires = priv->timerSetAt + TLAN_TIMER_ACT_DELAY;
+						add_timer( &priv->timer );
+					}
+					break;
+				default:
+					break;
+			}
+
+		} /* TLan_Timer */
+
+
+
+
+/*****************************************************************************
+******************************************************************************
+
+	ThunderLAN Driver Primary Functions
+
+	These functions are more or less common to all Linux network drivers.
+
+******************************************************************************
+*****************************************************************************/
+
+	static	int		TLan_PciProbe( u8 *, u8 *, u8 *, u8 *, u32 *, u32 * );
+	static	int		TLan_Init( struct device * );
+	static	int		TLan_Open(struct device *dev);
+	static	int		TLan_StartTx(struct sk_buff *, struct device *);
+	static	void	TLan_HandleInterrupt(int, void *, struct pt_regs *);
+	static	int		TLan_Close(struct device *);
+	static	struct enet_statistics *TLan_GetStats( struct device * );
+	static	void	TLan_SetMulticastList( struct device * );
+
+
+#ifdef MODULE
+
+	/*************************************************************************
+	 *	init_module
+	 *
+	 *	Returns:	0 if module installed ok, non-zero if not.
+	 *	Parms:		None
+	 *
+	 *	This function begins the setup of the driver creating a pad buffer,
+	 *	finding all TLAN devices (matching TLanDeviceList entries), and
+	 *	creating and initializing a device structure for each adapter.
+	 *
+	 ************************************************************************/
+
+		extern int init_module(void)
+		{
+    		int				failed, found;
+			size_t			dev_size;
+			struct device	*dev;
+			TLanPrivateInfo	*priv;
+			u8				bus, dfn, irq, rev;
+			u32				io_base, dl_ix;
+
+			printk("TLAN driver, v%d.%d, (C) 1997 Caldera, Inc.\n",
+				   TLanVersionMajor,
+				   TLanVersionMinor
+				  );
+
+			TLanPadBuffer = (u8 *) kmalloc( TLAN_MIN_FRAME_SIZE, GFP_KERNEL | GFP_DMA );
+			if ( TLanPadBuffer == NULL ) {
+				printk( "TLAN:  Could not allocate memory for pad buffer.\n" );
+				return -ENOMEM;
+			}
+			memset( TLanPadBuffer, 0, TLAN_MIN_FRAME_SIZE );
+
+			dev_size = sizeof(struct device) + sizeof(TLanPrivateInfo);
+			while ( ( found = TLan_PciProbe( &bus, &dfn, &irq, &rev, &io_base, &dl_ix ) ) ) {
+				dev = (struct device *) kmalloc( dev_size, GFP_KERNEL );
+				if ( dev == NULL ) {
+					printk( "TLAN:  Could not allocate memory for device.\n" );
+					continue;
+				}
+				memset( dev, 0, dev_size );
+
+				dev->priv = priv = ( (void *) dev ) + sizeof(struct device);
+				dev->name = priv->devName;
+				strcpy( priv->devName, "    " );
+				dev->base_addr = io_base;
+				dev->irq = irq;
+				dev->init = TLan_Init;
+
+				priv->pciBus = bus;
+				priv->pciDeviceFn = dfn;
+				priv->pciRevision = rev;
+				priv->pciEntry = dl_ix;
+
+				ether_setup( dev );
+
+				failed = register_netdev( dev );
+
+				if ( failed ) {
+					printk( "TLAN:  Could not register network device.  Freeing struct.\n" );
+					kfree( dev );
+				} else {
+					priv->nextDevice = TLanDevices;
+					TLanDevices = dev;
+					TLanDevicesInstalled++;
+					printk("TLAN:  %s irq=%2d io=%04x, %s\n", dev->name, (int) irq, io_base, TLanDeviceList[dl_ix].deviceName );
+				}
+			}
+			
+			// printk( "TLAN:  Found %d device(s).\n", TLanDevicesInstalled );
+
+    		return ( ( TLanDevicesInstalled >= 0 ) ? 0 : -ENODEV );
+
+		} /* init_module */
+
+
+
+
+	/*************************************************************************
+	 *	cleanup_module
+	 *
+	 *	Returns:	Nothing
+	 *	Parms:		None
+	 *
+	 *	Goes through the TLanDevices list and frees the device structs and
+	 *	memory associated with each device (lists and buffers).  It also
+	 *	ureserves the IO port regions associated with this device.
+	 *
+	 ************************************************************************/
+
+		extern void cleanup_module(void)
+		{
+			struct device	*dev;
+			TLanPrivateInfo	*priv;
+
+			while (TLanDevicesInstalled) {
+				dev = TLanDevices;
+				priv = (TLanPrivateInfo *) dev->priv;
+				if ( priv->dmaStorage )
+					kfree( priv->dmaStorage );
+				release_region( dev->base_addr, 0x10 );
+				unregister_netdev( dev );
+				TLanDevices = priv->nextDevice;
+				kfree( dev );
+				TLanDevicesInstalled--;
+			}
+			kfree( TLanPadBuffer );
+
+		} /* cleanup_module */
+
+
+#else /* MODULE */
+
+
+
+
+	/*************************************************************************
+	 *	tlan_probe
+	 *
+	 *	Returns:	0 on success, error code on error
+	 *	Parms:		dev		device struct to use if adapter is found.
+	 *
+	 *	The name is lower case to fit in with all the rest of the
+	 *	netcard_probe names.  This function looks for a/another TLan based
+	 *	adapter, setting it up with the provided device struct if one is
+	 *	found.
+	 *
+	 ************************************************************************/
+	 
+		extern int tlan_probe( struct device *dev )
+		{
+			static int		pad_allocated = 0;
+    		int				found;
+			TLanPrivateInfo	*priv;
+			u8				bus, dfn, irq, rev;
+			u32				io_base, dl_ix;
+
+			found = TLan_PciProbe( &bus, &dfn, &irq, &rev, &io_base, &dl_ix );
+			TLAN_DBG( 1, "TLAN:  Probing...\n" );
+			if ( found ) {
+				dev->priv = kmalloc( sizeof(TLanPrivateInfo), GFP_KERNEL );
+				if ( dev->priv == NULL ) {
+					printk( "TLAN:  Could not allocate memory for device.\n" );
+				}
+				memset( dev->priv, 0, sizeof(TLanPrivateInfo) );
+				priv = (TLanPrivateInfo *) dev->priv;
+
+				dev->name = priv->devName;
+				strcpy( priv->devName, "    " );
+
+				dev = init_etherdev( dev, sizeof(TLanPrivateInfo) );
+
+				dev->base_addr = io_base;
+				dev->irq = irq;
+
+				priv->pciBus = bus;
+				priv->pciDeviceFn = dfn;
+				priv->pciRevision = rev;
+				priv->pciEntry = dl_ix;
+
+				if ( ! pad_allocated ) {
+					TLanPadBuffer = (u8 *) kmalloc( TLAN_MIN_FRAME_SIZE, GFP_KERNEL | GFP_DMA );
+					if ( TLanPadBuffer == NULL ) {
+						printk( "TLAN:  Could not allocate memory for pad buffer.\n" );
+					} else {
+						pad_allocated = 1;
+						memset( TLanPadBuffer, 0, TLAN_MIN_FRAME_SIZE );
+					}
+				}
+				printk("TLAN %d.%d:  %s irq=%2d io=%04x, %s\n", TLanVersionMajor, 
+																TLanVersionMinor,
+																dev->name, 
+																(int) irq, 
+																io_base, 
+																TLanDeviceList[dl_ix].deviceName );
+				TLan_Init( dev );
+			}
+			
+    		return ( ( found ) ? 0 : -ENODEV );
+
+		} /* tlan_probe */
+
+
+#endif /* MODULE */
+
+
+
+
+	/*************************************************************************
+	 *	TLan_PciProbe
+	 *
+	 *	Returns:	1 if another TLAN card was found, 0 if not.
+	 *	Parms:		pci_bus		The PCI bus the card was found on.
+	 *				pci_dfn		The PCI whatever the card was found at.
+	 *				pci_irq		The IRQ of the found adapter.
+	 *				pci_rev		The revision of the adapter.
+	 *				pci_io_base	The first IO port used by the adapter.
+	 *				dl_ix		The index in the device list of the adapter.
+	 *
+	 *	This function searches for an adapter with PCI vendor and device
+	 *	IDs matching those in the TLanDeviceList.  The function 'remembers'
+	 *	the last device it found, and so finds a new device (if anymore are
+	 *	to be found) each time the function is called.  It then looks up
+	 *	pertinent PCI info and returns it to the caller.
+	 *
+	 ************************************************************************/
+
+		int TLan_PciProbe( u8 *pci_bus, u8 *pci_dfn, u8 *pci_irq, u8 *pci_rev, u32 *pci_io_base, u32 *dl_ix )
+		{
+			static int dl_index = 0;
+			static int pci_index = 0;
+
+			int not_found;
+			u8	pci_latency;
+			u16 pci_command;
+
+
+			if ( ! pcibios_present() ) {
+				printk( "TLAN:   PCI Bios not present.\n" );
+				return 0;
+			}
+
+			for (; TLanDeviceList[dl_index].vendorId != 0; dl_index++) {
+				not_found = pcibios_find_device( TLanDeviceList[dl_index].vendorId,
+												 TLanDeviceList[dl_index].deviceId,
+												 pci_index,
+												 pci_bus,
+												 pci_dfn
+											   );
+				if ( ! not_found ) {
+					TLAN_DBG( 1, "TLAN:   found: Vendor Id = 0x%hx, Device Id = 0x%hx\n",
+							TLanDeviceList[dl_index].vendorId,
+							TLanDeviceList[dl_index].deviceId
+						  );
+
+					pcibios_read_config_byte ( *pci_bus,  *pci_dfn, PCI_REVISION_ID,	pci_rev);
+					pcibios_read_config_byte ( *pci_bus,  *pci_dfn, PCI_INTERRUPT_LINE,	pci_irq);
+					pcibios_read_config_word ( *pci_bus,  *pci_dfn, PCI_COMMAND,		&pci_command);
+					pcibios_read_config_dword( *pci_bus,  *pci_dfn, PCI_BASE_ADDRESS_0,	pci_io_base);
+					pcibios_read_config_byte ( *pci_bus,  *pci_dfn, PCI_LATENCY_TIMER,	&pci_latency);
+
+					if (pci_latency < 0x10) {
+						pcibios_write_config_byte( *pci_bus, *pci_dfn, PCI_LATENCY_TIMER, 0xff);
+						TLAN_DBG( 1, "TLAN:      Setting latency timer to max.\n");
+					}
+
+					if ((pci_command & PCI_COMMAND_IO) && (*pci_io_base & 0x3)) {
+						*pci_io_base &= PCI_BASE_ADDRESS_IO_MASK;
+						TLAN_DBG( 1, "TLAN:      IO mapping is available at %x.\n", *pci_io_base);
+					} else {
+						*pci_io_base = 0;
+						printk("TLAN:      IO mapping not available, ignoring device.\n");
+					}
+
+					if (pci_command & PCI_COMMAND_MASTER) {
+						TLAN_DBG( 1, "TLAN:      Bus mastering is active.\n");
+					}
+
+					pci_index++;
+
+					if ( *pci_io_base ) {
+						*dl_ix = dl_index;
+						return 1;
+					}
+
+				} else {
+					pci_index = 0;
+				}
+			}
+
+			return 0;
+
+		} /* TLan_PciProbe */
+
+
+
+
+	/*************************************************************************
+	 *	TLan_Init
+	 *
+	 *	Returns:	0 on success, error code otherwise.
+	 *	Parms:		dev		The structure of the device to be init'ed.
+	 *
+	 *	This function completes the initialization of the device structure
+	 *	and driver.  It reserves the IO addresses, allocates memory for the
+	 *	lists and bounce buffers, retrieves the MAC address from the eeprom
+	 *	and assignes the device's methods.
+	 *	
+	 ************************************************************************/
+
+		int TLan_Init( struct device *dev )
+		{
+			int				dma_size;
+			int				err;
+			int				i;
+			TLanPrivateInfo	*priv;
+
+			priv = (TLanPrivateInfo *) dev->priv;
+
+			err = check_region( dev->base_addr, 0x10 );
+			if ( err ) {
+				printk( "TLAN:  %s: Io port region 0x%lx size 0x%x in use.\n", dev->name, dev->base_addr, 0x10 );
+				return -EIO;
+			}
+			request_region( dev->base_addr, 0x10, TLanSignature );
+
+			dma_size = ( TLAN_NUM_RX_LISTS + TLAN_NUM_TX_LISTS ) * ( sizeof(TLanList) + TLAN_MAX_FRAME_SIZE );
+			priv->dmaStorage = kmalloc( dma_size, GFP_KERNEL | GFP_DMA );
+			if ( priv->dmaStorage == NULL ) {
+				printk( "TLAN:  Could not allocate lists and buffers for %s.\n", dev->name );
+				return -ENOMEM;
+			}
+			memset( priv->dmaStorage, 0, dma_size );
+			priv->rxList = (TLanList *) ( ( ( (u32) priv->dmaStorage ) + 7 ) & 0xFFFFFFF8 );
+			priv->txList = priv->rxList + TLAN_NUM_RX_LISTS;
+			priv->rxBuffer = (u8 *) ( priv->txList + TLAN_NUM_TX_LISTS );
+			priv->txBuffer = priv->rxBuffer + ( TLAN_NUM_RX_LISTS * TLAN_MAX_FRAME_SIZE );
+
+			err = 0;
+			for ( i = 0;  i < 6 ; i++ )
+				err |= TLan_EeReadByte( dev->base_addr, (u8) 0x83 + i, (u8 *) &dev->dev_addr[i] );
+			if ( err )
+				printk( "TLAN:  %s: Error reading MAC Address from eeprom: %d\n", dev->name, err );
+			dev->addr_len = 6;
+
+			dev->open = &TLan_Open;
+			dev->hard_start_xmit = &TLan_StartTx;
+			dev->stop = &TLan_Close;
+			dev->get_stats = &TLan_GetStats;
+			dev->set_multicast_list = &TLan_SetMulticastList;
+
+			return 0;
+
+		} /* TLan_Init */
+
+
+
+
+	/*************************************************************************
+	 *	TLan_Open
+	 *
+	 *	Returns:	0 on success, error code otherwise.
+	 *	Parms:		dev		Structure of device to be opened.
+	 *
+	 *	This routine puts the driver and TLAN adapter in a state where it is
+	 *	ready to send and receive packets.  It allocates the IRQ, resets and
+	 *	brings the adapter out of reset, and allows interrupts.  It also
+	 *	delays the startup for autonegotiation or sends a Rx GO command to
+	 *	the adapter, as appropriate.
+	 *
+	 ************************************************************************/
+
+		int TLan_Open( struct device *dev )
+		{
+			int				err;
+			TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
+
+			err = request_irq( dev->irq, TLan_HandleInterrupt, SA_SHIRQ, TLanSignature, dev );
+			if ( err ) {
+				printk( "TLAN:  %s: IRQ %d already in use.\n", dev->name, dev->irq );
+				return -EAGAIN;
+			}
+
+			MOD_INC_USE_COUNT;
+
+			dev->tbusy = 0;
+			dev->interrupt = 0;
+			dev->start = 1;
+
+			/* NOTE: It might not be necessary to read the stats before a
+					 reset if you don't care what the values are.
+			*/
+			TLan_ResetLists( dev );
+			TLan_ReadAndClearStats( dev, TLAN_IGNORE );
+			TLan_Reset( dev );
+			TLan_SetMac( dev, 0, dev->dev_addr );
+			outb( ( TLAN_HC_INT_ON >> 8 ), dev->base_addr + TLAN_HOST_CMD + 1 );
+			if ( debug >= 1 )
+				outb( ( TLAN_HC_REQ_INT >> 8 ), dev->base_addr + TLAN_HOST_CMD + 1 );
+
+			init_timer( &priv->timer );
+			priv->timer.data = (unsigned long) dev;
+			priv->timer.function = &TLan_Timer;
+			if ( priv->phyFlags & TLAN_PHY_AUTONEG ) {
+				priv->timer.expires = jiffies + TLAN_TIMER_LINK_DELAY;
+				priv->timerSetAt = jiffies;
+				priv->timerType = TLAN_TIMER_LINK;
+				add_timer( &priv->timer );
+			} else {
+				TLAN_DBG( 1, "TLAN:  RX GO\n" );
+				outl( virt_to_bus( priv->rxList ), dev->base_addr + TLAN_CH_PARM );
+				outl( TLAN_HC_GO | TLAN_HC_RT, dev->base_addr + TLAN_HOST_CMD );
+			}
+
+			TLAN_DBG( 1, "TLAN:  Device %s opened.\n", dev->name );
+
+			return 0;
+
+		} /* TLan_Open */
+
+
+
+
+	/*************************************************************************
+	 *	TLan_StartTx
+	 *  
+	 *  Returns:	0 on success, non-zero on failure.
+	 *	Parms:		skb		A pointer to the sk_buff containing the frame to
+	 *						be sent.
+	 *				dev		The device to send the data on.
+	 *
+	 *	This function adds a frame to the Tx list to be sent ASAP.  First it
+	 *	verifies that the adapter is ready and there is room in the queue.
+	 *	Then it sets up the next available list, copies the frame to the
+	 *	corresponding buffer.  If the adapter Tx channel is idle, it gives
+	 *	adapter a Tx Go command on the list, otherwise it sets the forward
+	 *	address of the previous list to point to this one.  Then it frees
+	 *	the sk_buff.
+	 *
+	 ************************************************************************/
+
+		int TLan_StartTx( struct sk_buff *skb, struct device *dev )
+		{
+			TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
+			TLanList		*tail_list;
+			u8				*tail_buffer;
+			int				pad;
+
+			// printk( "Entering StartTx\n" );
+			if ( ! priv->phyOnline ) {
+				dev_kfree_skb( skb, FREE_WRITE );
+				return 0;
+			}
+
+			tail_list = priv->txList + priv->txTail;
+			if ( tail_list->cStat != TLAN_CSTAT_UNUSED ) {
+				// printk( "TLAN:  %s TX is busy, Head=%d Tail=%d\n", dev->name, priv->txHead, priv->txTail );
+				dev->tbusy = 1;
+				// printk( "TLAN:   Tx is busy.\n");
+				priv->txBusyCount++;
+				return 1;
+			}
+			tail_list->forward = 0;
+			tail_buffer = priv->txBuffer + ( priv->txTail * TLAN_MAX_FRAME_SIZE );
+			memcpy( tail_buffer, skb->data, skb->len );
+			pad = TLAN_MIN_FRAME_SIZE - skb->len;
+			if ( pad > 0 ) {
+				tail_list->frameSize = (u16) skb->len + pad;
+				tail_list->buffer[0].count = (u32) skb->len;
+				tail_list->buffer[1].count = TLAN_LAST_BUFFER | (u32) pad;
+				tail_list->buffer[1].address = virt_to_bus( TLanPadBuffer );
+			} else {
+				tail_list->frameSize = (u16) skb->len;
+				tail_list->buffer[0].count = TLAN_LAST_BUFFER | (u32) skb->len;
+				tail_list->buffer[1].count = 0;
+				tail_list->buffer[1].address = 0;
+			}
+			// are we transferring?
+			cli();
+			tail_list->cStat = TLAN_CSTAT_READY;
+			if ( ! priv->txInProgress ) {
+				priv->txInProgress = 1;
+				outw( 0x4, dev->base_addr + TLAN_HOST_INT );
+				// printk("TLAN: Sending GO for 0%d\n", priv->txTail );
+				outl( virt_to_bus( tail_list ), dev->base_addr + TLAN_CH_PARM );
+				outl( TLAN_HC_GO | TLAN_HC_ACK, dev->base_addr + TLAN_HOST_CMD );
+			} else {
+				// printk("TLAN: Adding 0%d\n", priv->txTail );
+				// Assign previous list to point to this one.  If previous has
+				// already been read, the EOC check in the TX EOF interrupt handler
+				// will start another transfer.
+				if ( priv->txTail == 0 )
+					( priv->txList + ( TLAN_NUM_TX_LISTS - 1 ) )->forward = virt_to_bus( tail_list );
+				else
+					( priv->txList + ( priv->txTail - 1 ) )->forward = virt_to_bus( tail_list );
+			}
+			sti();
+			priv->txTail++;
+			if ( priv->txTail >= TLAN_NUM_TX_LISTS )
+				priv->txTail = 0;
+
+			dev_kfree_skb( skb, FREE_WRITE );
+				
+			dev->trans_start = jiffies;
+			// printk( "Leaving StartTx\n" );
+			return 0;
+
+		} /* TLan_StartTx */
+
+
+
+
+	/*************************************************************************
+	 *	TLan_HandleInterrupt
+	 *  
+	 *  Returns:	Nothing
+	 *	Parms:		irq		The line on which the interrupt occurred.
+	 *				dev_id	A pointer to the device assigned to this irq line.
+	 *				regs	???
+	 *
+	 *	This function handles an interrupt generated by its assigned TLAN
+	 *	adapter.  The function deactivates interrupts on its adapter, records
+	 *	the type of interrupt, executes the appropriate subhandler, and
+	 *	acknowdges the interrupt to the adapter (thus re-enabling adapter
+	 *	interrupts.
+	 *
+	 ************************************************************************/
+
+		void TLan_HandleInterrupt(int irq, void *dev_id, struct pt_regs *regs)
+		{
+			u32				ack;
+			struct device	*dev;
+			u32				host_cmd;
+			u16				host_int;
+			int				type;
+
+			dev = (struct device *) dev_id;
+
+			if ( dev->interrupt )
+				TLAN_DBG( 1, "TLAN:   Re-entering interrupt handler for %s: %d.\n" , dev->name, dev->interrupt );
+			dev->interrupt++;
+
+			cli();
+
+			host_int = inw( dev->base_addr + TLAN_HOST_INT );
+			outw( host_int, dev->base_addr + TLAN_HOST_INT ); // Deactivate Ints
+
+			type = ( host_int & TLAN_HI_IT_MASK ) >> 2;
+
+			ack = TLanIntVector[type]( dev, host_int );
+
+			sti();
+
+			if ( ack ) {
+				host_cmd = TLAN_HC_ACK | ack | ( type << 18 );
+				outl( host_cmd, dev->base_addr + TLAN_HOST_CMD );
+			}
+
+			dev->interrupt--;
+
+		} /* TLan_HandleInterrupts */
+
+
+
+
+	/*************************************************************************
+	 *	TLan_Close
+	 *  
+	 *  Returns:	An error code.
+	 *	Parms:		dev		The device structure of the device to close.
+	 *
+	 *	This function shuts down the adapter.  It records any stats, puts
+	 *  the adapter into reset state, deactivates its time as needed, and
+	 *	frees the irq it is using.
+	 *
+	 ************************************************************************/
+
+		int TLan_Close(struct device *dev)
+		{
+			TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
+
+			dev->start = 0;
+			dev->tbusy = 1;
+
+			TLan_ReadAndClearStats( dev, TLAN_RECORD );
+			outl( TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD );
+			if ( priv->timerSetAt != 0 )
+				del_timer( &priv->timer );
+			free_irq( dev->irq, dev );
+			TLAN_DBG( 1, "TLAN:   Device %s closed.\n", dev->name );
+
+			MOD_DEC_USE_COUNT;
+
+			return 0;
+
+		} /* TLan_Close */
+
+
+
+
+	/*************************************************************************
+	 *	TLan_GetStats
+	 *  
+	 *  Returns:	A pointer to the device's statistics structure.
+	 *	Parms:		dev		The device structure to return the stats for.
+	 *
+	 *	This function updates the devices statistics by reading the TLAN
+	 *	chip's onboard registers.  Then it returns the address of the
+	 *	statistics structure.
+	 *
+	 ************************************************************************/
+
+		struct enet_statistics *TLan_GetStats( struct device *dev )
+		{
+			TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
+			int i;
+
+			/* Should only read stats if open ? */
+			TLan_ReadAndClearStats( dev, TLAN_RECORD );
+			printk( "TLAN:  %s Rx EOC Count: %d\n", dev->name, priv->rxEocCount );
+			printk( "TLAN:  %s Tx Busy Count: %d\n", dev->name, priv->txBusyCount );
+			// printk( "TLAN:   Got stats for %s.\n", dev->name );
+			TLan_PrintDio( dev->base_addr );
+			TLan_PhyPrint( dev );
+			for ( i = 0; i < TLAN_NUM_RX_LISTS; i++ )
+				TLan_PrintList( priv->rxList + i, "RX", i );
+			for ( i = 0; i < TLAN_NUM_TX_LISTS; i++ )
+				TLan_PrintList( priv->txList + i, "TX", i );
+			
+			return ( &( (TLanPrivateInfo *) dev->priv )->stats );
+
+		} /* TLan_GetStats */
+
+
+
+
+	/*************************************************************************
+	 *	TLan_SetMulticastList
+	 *  
+	 *  Returns:	Nothing
+	 *	Parms:		dev		The device structure to set the multicast list for.
+	 *
+	 *	This function sets the TLAN adaptor to various receive modes.  If the
+	 *	IFF_PROMISC flag is set, promiscuous mode is acitviated.  Otherwise,
+	 *	promiscuous mode is turned off.  If the IFF_ALLMULTI flag is set, then
+	 *	the hash table is set to receive all group addresses.  Otherwise, the
+	 *	first three multicast addresses are stored in AREG_1-3, and the rest
+	 *  are selected via the hash table, as necessary.
+	 *
+	 ************************************************************************/
+
+		void TLan_SetMulticastList( struct device *dev )
+		{	
+			struct dev_mc_list	*dmi = dev->mc_list;
+			u32					hash1 = 0;
+			u32					hash2 = 0;
+			int					i;
+			u32					offset;
+			u8					tmp;
+
+			if ( dev->flags & IFF_PROMISC ) {
+				tmp = TLan_DioRead8( dev->base_addr, TLAN_NET_CMD );
+				TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, tmp | TLAN_NET_CMD_CAF );
+			} else {
+				tmp = TLan_DioRead8( dev->base_addr, TLAN_NET_CMD );
+				TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, tmp & ~TLAN_NET_CMD_CAF );
+				if ( dev->flags & IFF_ALLMULTI ) {
+					for ( i = 0; i < 3; i++ ) 
+						TLan_SetMac( dev, i + 1, NULL );
+					TLan_DioWrite32( dev->base_addr, TLAN_HASH_1, 0xFFFFFFFF );
+					TLan_DioWrite32( dev->base_addr, TLAN_HASH_2, 0xFFFFFFFF );
+				} else {
+					for ( i = 0; i < dev->mc_count; i++ ) {
+						if ( i < 3 ) {
+							TLan_SetMac( dev, i + 1, (char *) &dmi->dmi_addr );
+						} else {
+							offset = TLan_HashFunc( (u8 *) &dmi->dmi_addr );
+							if ( offset < 32 ) 
+								hash1 |= ( 1 << offset );
+							else
+								hash2 |= ( 1 << ( offset - 32 ) );
+						}
+						dmi = dmi->next;
+					}
+					for ( ; i < 3; i++ ) 
+						TLan_SetMac( dev, i + 1, NULL );
+					TLan_DioWrite32( dev->base_addr, TLAN_HASH_1, hash1 );
+					TLan_DioWrite32( dev->base_addr, TLAN_HASH_2, hash2 );
+				}
+			}
+
+		} /* TLan_SetRxMode */
diff -u --recursive --new-file v2.1.44/linux/drivers/net/tlan.h linux/drivers/net/tlan.h
--- v2.1.44/linux/drivers/net/tlan.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/tlan.h	Wed Jul 16 19:22:51 1997
@@ -0,0 +1,485 @@
+/********************************************************************
+ *
+ *  Linux ThunderLAN Driver
+ *
+ *  tlan.h
+ *  by James Banks, james.banks@caldera.com
+ *
+ *  (C) 1997 Caldera, Inc.
+ *
+ *  This software may be used and distributed according to the terms
+ *  of the GNU Public License, incorporated herein by reference.
+ *
+ ** This file is best viewed/edited with tabstop=4, colums>=132
+ *
+ ********************************************************************/
+
+#include <asm/io.h>
+#include <asm/types.h>
+#include <linux/netdevice.h>
+
+
+
+	/*****************************************************************
+	 * TLan Definitions
+	 *
+	 ****************************************************************/
+
+	 	#define FALSE				0
+		#define TRUE				1
+
+		#define TLAN_MIN_FRAME_SIZE	64
+		#define TLAN_MAX_FRAME_SIZE	1600
+
+		#define TLAN_NUM_RX_LISTS 4
+		#define TLAN_NUM_TX_LISTS 8
+
+		#define TLAN_IGNORE	0
+		#define TLAN_RECORD	1
+
+		#define TLAN_DBG(lvl, format, args...)	if ( debug >= lvl ) printk( format, ##args );
+
+
+
+
+	/*****************************************************************
+	 * Device Identification Definitions
+	 *
+	 ****************************************************************/
+		
+		/* NOTE: These should be moved to pci.h someday */
+		#define PCI_DEVICE_ID_NETELLIGENT_10 0xAE34
+		#define PCI_DEVICE_ID_NETELLIGENT_10_100 0xAE32
+		#define PCI_DEVICE_ID_NETFLEX_3_INTEGRATED 0xAE35
+
+
+		typedef struct tlan_pci_id {
+			u16	vendorId;
+			u16	deviceId;
+			char *deviceName;
+		} TLanPciId;
+
+
+
+
+	/*****************************************************************
+	 * Rx/Tx List Definitions
+	 *
+	 ****************************************************************/
+
+		#define TLAN_BUFFERS_PER_LIST	10
+		#define TLAN_LAST_BUFFER	0x80000000
+		#define TLAN_CSTAT_UNUSED	0x8000
+		#define TLAN_CSTAT_FRM_CMP	0x4000
+		#define TLAN_CSTAT_READY	0x3000
+		#define TLAN_CSTAT_EOC		0x0800
+		#define TLAN_CSTAT_RX_ERROR	0x0400
+		#define TLAN_CSTAT_PASS_CRC	0x0200
+		#define TLAN_CSTAT_DP_PR	0x0100
+
+
+		typedef struct tlan_buffer_ref_tag {
+			u32		count;
+			u32		address;
+		} TLanBufferRef;
+
+
+		typedef struct tlan_list_tag {
+			u32						forward;
+			u16						cStat;
+			u16						frameSize;
+			TLanBufferRef			buffer[TLAN_BUFFERS_PER_LIST];
+		} TLanList;
+
+
+		typedef u8 TLanBuffer[TLAN_MAX_FRAME_SIZE];
+
+
+
+
+	/*****************************************************************
+	 * PHY definitions
+	 *
+	 ****************************************************************/
+
+		#define TLAN_PHY_MAX_ADDR   0x1F
+		#define TLAN_PHY_INTERNAL	0x1F
+
+		#define TLAN_PHY_ACTIVITY	0x00000001
+		#define TLAN_PHY_AUTONEG	0x00000002
+
+
+    	typedef int (TLanPhyFunc)( struct device * );
+
+
+    	typedef struct tlan_phy_id_entry_tag {
+        	u16         idHi;
+        	u16         idLo;
+        	TLanPhyFunc *check;
+        	TLanPhyFunc *service;
+			u32			flags;
+    	} TLanPhyIdEntry;
+
+
+
+
+	/*****************************************************************
+	 * TLAN Private Information Structure
+	 *
+	 ****************************************************************/
+
+		typedef struct tlan_private_tag {
+			struct device           *nextDevice;
+			void					*dmaStorage;
+			u8						*padBuffer;
+			TLanList                *rxList;
+			u8						*rxBuffer;
+			u32                     rxHead;
+			u32                     rxTail;
+			u32			rxEocCount;
+			TLanList                *txList;
+			u8						*txBuffer;
+			u32                     txHead;
+			u32                     txInProgress;
+			u32                     txTail;
+			u32			txBusyCount;
+			u32                     phyAddr;
+			u32                     phyEntry;
+			u32                     phyOnline;
+			u32                     phyFlags;
+			TLanPhyFunc             *phyCheck;
+			TLanPhyFunc             *phyService;
+			u32						timerSetAt;
+			u32						timerType;
+			struct timer_list		timer;
+			struct enet_statistics  stats;
+			u32                     pciEntry;
+			u8                      pciRevision;
+			u8                      pciBus;
+			u8                      pciDeviceFn;
+			char                    devName[8];
+		} TLanPrivateInfo;
+
+
+
+
+	/*****************************************************************
+	 * TLan Driver Timer Definitions
+	 *
+	 ****************************************************************/
+
+	 	#define TLAN_TIMER_LINK			1
+		#define TLAN_TIMER_ACT			2
+
+		#define TLAN_TIMER_LINK_DELAY	230
+		#define TLAN_TIMER_ACT_DELAY	10
+
+
+
+
+	/*****************************************************************
+	 * TLan Driver Eeprom Definitions
+	 *
+	 ****************************************************************/
+
+		#define TLAN_EEPROM_ACK		0
+		#define TLAN_EEPROM_STOP	1
+
+
+
+
+	/*****************************************************************
+	 * Host Register Offsets and Contents
+	 *
+	 ****************************************************************/
+
+		#define TLAN_HOST_CMD		0x00
+		#define 	TLAN_HC_GO		0x80000000
+		#define		TLAN_HC_STOP	0x40000000
+		#define		TLAN_HC_ACK		0x20000000
+		#define		TLAN_HC_CS_MASK 0x1FE00000
+		#define		TLAN_HC_EOC		0x00100000
+		#define		TLAN_HC_RT		0x00080000
+		#define		TLAN_HC_NES		0x00040000
+		#define		TLAN_HC_AD_RST	0x00008000
+		#define		TLAN_HC_LD_TMR	0x00004000
+		#define		TLAN_HC_LD_THR	0x00002000
+		#define		TLAN_HC_REQ_INT	0x00001000
+		#define		TLAN_HC_INT_OFF	0x00000800
+		#define		TLAN_HC_INT_ON	0x00000400
+		#define		TLAN_HC_AC_MASK	0x000000FF
+		#define TLAN_CH_PARM		0x04
+		#define TLAN_DIO_ADR		0x08
+		#define		TLAN_DA_ADR_INC	0x8000
+		#define		TLAN_DA_RAM_ADR	0x4000
+		#define TLAN_HOST_INT		0x0A
+		#define		TLAN_HI_IV_MASK	0x1FE0
+		#define		TLAN_HI_IT_MASK	0x001C
+		#define TLAN_DIO_DATA		0x0C
+
+
+/* ThunderLAN Internal Register DIO Offsets */
+
+#define TLAN_NET_CMD			0x00
+#define		TLAN_NET_CMD_NRESET	0x80
+#define		TLAN_NET_CMD_NWRAP	0x40
+#define		TLAN_NET_CMD_CSF	0x20
+#define		TLAN_NET_CMD_CAF	0x10
+#define		TLAN_NET_CMD_NOBRX	0x08
+#define		TLAN_NET_CMD_DUPLEX	0x04
+#define		TLAN_NET_CMD_TRFRAM	0x02
+#define		TLAN_NET_CMD_TXPACE	0x01
+#define TLAN_NET_SIO			0x01
+#define 	TLAN_NET_SIO_MINTEN	0x80
+#define		TLAN_NET_SIO_ECLOK	0x40
+#define		TLAN_NET_SIO_ETXEN	0x20
+#define		TLAN_NET_SIO_EDATA	0x10
+#define		TLAN_NET_SIO_NMRST	0x08
+#define		TLAN_NET_SIO_MCLK	0x04
+#define		TLAN_NET_SIO_MTXEN	0x02
+#define		TLAN_NET_SIO_MDATA	0x01
+#define TLAN_NET_STS			0x02
+#define		TLAN_NET_STS_MIRQ	0x80
+#define		TLAN_NET_STS_HBEAT	0x40
+#define		TLAN_NET_STS_TXSTOP	0x20
+#define		TLAN_NET_STS_RXSTOP 0x10
+#define		TLAN_NET_STS_RSRVD	0x0F
+#define TLAN_NET_MASK			0x03
+#define		TLAN_NET_MASK_MASK7	0x80
+#define		TLAN_NET_MASK_MASK6	0x40
+#define		TLAN_NET_MASK_MASK5	0x20
+#define		TLAN_NET_MASK_MASK4	0x10
+#define		TLAN_NET_MASK_RSRVD	0x0F
+#define TLAN_NET_CONFIG			0x04
+#define 	TLAN_NET_CFG_RCLK	0x8000
+#define		TLAN_NET_CFG_TCLK	0x4000
+#define		TLAN_NET_CFG_BIT	0x2000
+#define		TLAN_NET_CFG_RXCRC	0x1000
+#define		TLAN_NET_CFG_PEF	0x0800
+#define		TLAN_NET_CFG_1FRAG	0x0400
+#define		TLAN_NET_CFG_1CHAN	0x0200
+#define		TLAN_NET_CFG_MTEST	0x0100
+#define		TLAN_NET_CFG_PHY_EN	0x0080
+#define		TLAN_NET_CFG_MSMASK	0x007F
+#define TLAN_MAN_TEST		0x06
+#define TLAN_DEF_VENDOR_ID	0x08
+#define TLAN_DEF_DEVICE_ID	0x0A
+#define TLAN_DEF_REVISION	0x0C
+#define TLAN_DEF_SUBCLASS	0x0D
+#define TLAN_DEF_MIN_LAT	0x0E
+#define TLAN_DEF_MAX_LAT	0x0F
+#define TLAN_AREG_0			0x10
+#define TLAN_AREG_1			0x16
+#define TLAN_AREG_2			0x1C
+#define TLAN_AREG_3			0x22
+#define TLAN_HASH_1			0x28
+#define TLAN_HASH_2			0x2C
+#define TLAN_GOOD_TX_FRMS	0x30
+#define TLAN_TX_UNDERUNS	0x33
+#define TLAN_GOOD_RX_FRMS	0x34
+#define TLAN_RX_OVERRUNS	0x37
+#define TLAN_DEFERRED_TX	0x38
+#define TLAN_CRC_ERRORS		0x3A
+#define TLAN_CODE_ERRORS	0x3B
+#define TLAN_MULTICOL_FRMS	0x3C
+#define TLAN_SINGLECOL_FRMS	0x3E
+#define TLAN_EXCESSCOL_FRMS	0x40
+#define TLAN_LATE_COLS		0x41
+#define TLAN_CARRIER_LOSS	0x42
+#define TLAN_ACOMMIT		0x43
+#define TLAN_LED_REG		0x44
+#define		TLAN_LED_ACT	0x10
+#define		TLAN_LED_LINK	0x01
+#define TLAN_BSIZE_REG		0x45
+#define TLAN_MAX_RX			0x46
+#define TLAN_INT_DIS			0x48
+#define		TLAN_ID_TX_EOC		0x04
+#define		TLAN_ID_RX_EOF		0x02
+#define		TLAN_ID_RX_EOC		0x01
+
+
+
+/* ThunderLAN Interrupt Codes */
+
+#define TLAN_INT_NUMBER_OF_INTS	8
+
+#define TLAN_INT_NONE			0x0000
+#define TLAN_INT_TX_EOF			0x0001
+#define TLAN_INT_STAT_OVERFLOW	0x0002
+#define TLAN_INT_RX_EOF			0x0003
+#define TLAN_INT_DUMMY			0x0004
+#define TLAN_INT_TX_EOC			0x0005
+#define TLAN_INT_STATUS_CHECK	0x0006
+#define TLAN_INT_RX_EOC			0x0007
+
+
+
+/* ThunderLAN MII Registers */
+
+/* Generic MII/PHY Registers */
+
+#define MII_GEN_CTL				0x00
+#define 	MII_GC_RESET		0x8000
+#define		MII_GC_LOOPBK		0x4000
+#define		MII_GC_SPEEDSEL		0x2000
+#define		MII_GC_AUTOENB		0x1000
+#define		MII_GC_PDOWN		0x0800
+#define		MII_GC_ISOLATE		0x0400
+#define		MII_GC_AUTORSRT		0x0200
+#define		MII_GC_DUPLEX		0x0100
+#define		MII_GC_COLTEST		0x0080
+#define		MII_GC_RESERVED		0x007F
+#define MII_GEN_STS				0x01
+#define		MII_GS_100BT4		0x8000
+#define		MII_GS_100BTXFD		0x4000
+#define		MII_GS_100BTXHD		0x2000
+#define		MII_GS_10BTFD		0x1000
+#define		MII_GS_10BTHD		0x0800
+#define		MII_GS_RESERVED		0x07C0
+#define		MII_GS_AUTOCMPLT	0x0020
+#define		MII_GS_RFLT			0x0010
+#define		MII_GS_AUTONEG		0x0008
+#define		MII_GS_LINK			0x0004
+#define		MII_GS_JABBER		0x0002
+#define		MII_GS_EXTCAP		0x0001
+#define MII_GEN_ID_HI			0x02
+#define MII_GEN_ID_LO			0x03
+#define 	MII_GIL_OUI			0xFC00
+#define 	MII_GIL_MODEL		0x03F0
+#define 	MII_GIL_REVISION	0x000F
+#define MII_AN_ADV				0x04
+#define MII_AN_LPA				0x05
+#define MII_AN_EXP				0x06
+
+/* ThunderLAN Specific MII/PHY Registers */
+
+#define TLAN_TLPHY_ID			0x10
+#define TLAN_TLPHY_CTL			0x11
+#define 	TLAN_TC_IGLINK		0x8000
+#define		TLAN_TC_SWAPOL		0x4000
+#define		TLAN_TC_AUISEL		0x2000
+#define		TLAN_TC_SQEEN		0x1000
+#define		TLAN_TC_MTEST		0x0800
+#define		TLAN_TC_RESERVED	0x07F8
+#define		TLAN_TC_NFEW		0x0004
+#define		TLAN_TC_INTEN		0x0002
+#define		TLAN_TC_TINT		0x0001
+#define TLAN_TLPHY_STS			0x12
+#define		TLAN_TS_MINT		0x8000
+#define		TLAN_TS_PHOK		0x4000
+#define		TLAN_TS_POLOK		0x2000
+#define		TLAN_TS_TPENERGY	0x1000
+#define		TLAN_TS_RESERVED	0x0FFF
+
+
+
+/* Routines to access internal registers. */
+
+inline u8 TLan_DioRead8(u16 base_addr, u16 internal_addr)
+{
+	outw(internal_addr, base_addr + TLAN_DIO_ADR);
+	return (inb((base_addr + TLAN_DIO_DATA) + (internal_addr & 0x3)));
+	
+} /* TLan_DioRead8 */
+
+
+
+
+inline u16 TLan_DioRead16(u16 base_addr, u16 internal_addr)
+{
+	outw(internal_addr, base_addr + TLAN_DIO_ADR);
+	return (inw((base_addr + TLAN_DIO_DATA) + (internal_addr & 0x2)));
+
+} /* TLan_DioRead16 */
+
+
+
+
+inline u32 TLan_DioRead32(u16 base_addr, u16 internal_addr)
+{
+	outw(internal_addr, base_addr + TLAN_DIO_ADR);
+	return (inl(base_addr + TLAN_DIO_DATA));
+
+} /* TLan_DioRead32 */
+
+
+
+
+inline void TLan_DioWrite8(u16 base_addr, u16 internal_addr, u8 data)
+{
+	outw(internal_addr, base_addr + TLAN_DIO_ADR);
+	outb(data, base_addr + TLAN_DIO_DATA + (internal_addr & 0x3));
+
+}
+
+
+
+
+inline void TLan_DioWrite16(u16 base_addr, u16 internal_addr, u16 data)
+{
+	outw(internal_addr, base_addr + TLAN_DIO_ADR);
+	outw(data, base_addr + TLAN_DIO_DATA + (internal_addr & 0x2));
+
+}
+
+
+
+
+inline void TLan_DioWrite32(u16 base_addr, u16 internal_addr, u32 data)
+{
+	outw(internal_addr, base_addr + TLAN_DIO_ADR);
+	outl(data, base_addr + TLAN_DIO_DATA + (internal_addr & 0x2));
+
+}
+
+
+
+
+inline void TLan_ClearBit(u8 bit, u16 port)
+{
+	outb_p(inb_p(port) & ~bit, port);
+}
+
+
+
+
+inline int TLan_GetBit(u8 bit, u16 port)
+{
+	return ((int) (inb_p(port) & bit));
+}
+
+
+
+
+inline void TLan_SetBit(u8 bit, u16 port)
+{
+	outb_p(inb_p(port) | bit, port);
+}
+
+
+inline	u32	xor( u32 a, u32 b )
+{
+	return ( ( a && ! b ) || ( ! a && b ) );
+}
+#define XOR8( a, b, c, d, e, f, g, h )	xor( a, xor( b, xor( c, xor( d, xor( e, xor( f, xor( g, h ) ) ) ) ) ) )
+#define DA( a, bit )					( ( (u8) a[bit/8] ) & ( (u8) ( 1 << bit%8 ) ) )
+
+inline u32 TLan_HashFunc( u8 *a )
+{
+	u32	hash;
+
+	hash  = XOR8( DA(a,0), DA(a, 6), DA(a,12), DA(a,18), DA(a,24), DA(a,30), DA(a,36), DA(a,42) );
+	hash |= XOR8( DA(a,1), DA(a, 7), DA(a,13), DA(a,19), DA(a,25), DA(a,31), DA(a,37), DA(a,43) ) << 1;
+	hash |= XOR8( DA(a,2), DA(a, 8), DA(a,14), DA(a,20), DA(a,26), DA(a,32), DA(a,38), DA(a,44) ) << 2;
+	hash |= XOR8( DA(a,3), DA(a, 9), DA(a,15), DA(a,21), DA(a,27), DA(a,33), DA(a,39), DA(a,45) ) << 3;
+	hash |= XOR8( DA(a,4), DA(a,10), DA(a,16), DA(a,22), DA(a,28), DA(a,34), DA(a,40), DA(a,46) ) << 4;
+	hash |= XOR8( DA(a,5), DA(a,11), DA(a,17), DA(a,23), DA(a,29), DA(a,35), DA(a,41), DA(a,47) ) << 5;
+
+	return hash;
+
+} 
+
+
+
+
+#endif
diff -u --recursive --new-file v2.1.44/linux/drivers/net/tulip.c linux/drivers/net/tulip.c
--- v2.1.44/linux/drivers/net/tulip.c	Tue May 13 22:41:12 1997
+++ linux/drivers/net/tulip.c	Wed Jul 16 19:22:51 1997
@@ -1078,6 +1078,7 @@
 			skb->protocol = eth_type_trans(skb,dev);
 			netif_rx(skb);
 			lp->stats.rx_packets++;
+			lp->stats.rx_bytes+=skb->len;
 		}
 
 		lp->rx_ring[entry].status = TRING_OWN;
diff -u --recursive --new-file v2.1.44/linux/drivers/sbus/char/bwtwo.c linux/drivers/sbus/char/bwtwo.c
--- v2.1.44/linux/drivers/sbus/char/bwtwo.c	Thu Jun 26 12:33:39 1997
+++ linux/drivers/sbus/char/bwtwo.c	Wed Jul 16 20:37:21 1997
@@ -1,4 +1,4 @@
-/* $Id: bwtwo.c,v 1.17 1997/06/06 10:56:28 jj Exp $
+/* $Id: bwtwo.c,v 1.18 1997/07/17 02:21:43 davem Exp $
  * bwtwo.c: bwtwo console driver
  *
  * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -92,9 +92,10 @@
 	map_offset = get_phys ((unsigned long) fb->base);
 	r = io_remap_page_range (vma->vm_start, map_offset, map_size,
 				 vma->vm_page_prot, fb->space);
-	if (r) return -EAGAIN;
-	vma->vm_inode = inode;
-	atomic_inc(&inode->i_count);
+	if (r)
+		return -EAGAIN;
+
+	vma->vm_dentry = dget(file->f_dentry);
 	return 0;
 }
 
diff -u --recursive --new-file v2.1.44/linux/drivers/sbus/char/cgfourteen.c linux/drivers/sbus/char/cgfourteen.c
--- v2.1.44/linux/drivers/sbus/char/cgfourteen.c	Thu Jun 26 12:33:39 1997
+++ linux/drivers/sbus/char/cgfourteen.c	Wed Jul 16 20:37:21 1997
@@ -1,4 +1,4 @@
-/* $Id: cgfourteen.c,v 1.23 1997/06/06 10:56:29 jj Exp $
+/* $Id: cgfourteen.c,v 1.24 1997/07/17 02:21:44 davem Exp $
  * cgfourteen.c: Sun SparcStation console support.
  *
  * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -269,11 +269,12 @@
 					 map_offset,
 					 map_size, vma->vm_page_prot,
 					 fb->space);
-		if (r) return -EAGAIN;
+		if (r)
+			return -EAGAIN;
 		page += map_size;
 	}
-        vma->vm_inode = inode;
-        atomic_inc(&inode->i_count);
+
+	vma->vm_dentry = dget(file->f_dentry);
         return 0;
 }
 
diff -u --recursive --new-file v2.1.44/linux/drivers/sbus/char/cgsix.c linux/drivers/sbus/char/cgsix.c
--- v2.1.44/linux/drivers/sbus/char/cgsix.c	Mon Jul  7 08:18:55 1997
+++ linux/drivers/sbus/char/cgsix.c	Wed Jul 16 20:37:21 1997
@@ -1,4 +1,4 @@
-/* $Id: cgsix.c,v 1.33 1997/07/01 09:12:05 jj Exp $
+/* $Id: cgsix.c,v 1.35 1997/07/17 02:21:45 davem Exp $
  * cgsix.c: cgsix frame buffer driver
  *
  * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -321,11 +321,12 @@
 					 map_offset,
 					 map_size, vma->vm_page_prot,
 					 fb->space);
-		if (r) return -EAGAIN;
+		if (r)
+			return -EAGAIN;
 		page += map_size;
 	}
-        vma->vm_inode = inode;
-        atomic_inc(&inode->i_count);
+
+	vma->vm_dentry = dget(file->f_dentry);
         return 0;
 }
 
@@ -512,6 +513,10 @@
 	cg6info->bt->control = 0x73 << 24;
 	cg6info->bt->addr = 0x07 << 24;
 	cg6info->bt->control = 0x00 << 24;
+
+#ifdef __sparc_v9__	
+	printk("VA %016lx ", fb->base);
+#endif
 
 	printk("TEC Rev %x ",
 		(cg6info->thc->thc_misc >> CG6_THC_MISC_REV_SHIFT) &
diff -u --recursive --new-file v2.1.44/linux/drivers/sbus/char/cgthree.c linux/drivers/sbus/char/cgthree.c
--- v2.1.44/linux/drivers/sbus/char/cgthree.c	Thu Jun 26 12:33:39 1997
+++ linux/drivers/sbus/char/cgthree.c	Wed Jul 16 20:37:21 1997
@@ -1,4 +1,4 @@
-/* $Id: cgthree.c,v 1.22 1997/06/06 10:56:30 jj Exp $
+/* $Id: cgthree.c,v 1.23 1997/07/17 02:21:46 davem Exp $
  * cgtree.c: cg3 frame buffer driver
  *
  * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -128,11 +128,12 @@
 					 map_offset,
 					 map_size, vma->vm_page_prot,
 					 fb->space);
-		if (r) return -EAGAIN;
+		if (r)
+			return -EAGAIN;
 		page += map_size;
 	}
-        vma->vm_inode = inode;
-        atomic_inc(&inode->i_count);
+
+	vma->vm_dentry = dget(file->f_dentry);
         return 0;
 }
 
diff -u --recursive --new-file v2.1.44/linux/drivers/sbus/char/creator.c linux/drivers/sbus/char/creator.c
--- v2.1.44/linux/drivers/sbus/char/creator.c	Mon Jun 16 16:35:56 1997
+++ linux/drivers/sbus/char/creator.c	Wed Jul 16 20:37:21 1997
@@ -1,13 +1,13 @@
-/*
- * creator.c: Linux/Sun Ultra Creator console support.
- *
- * Copyright (C) 1997 MIguel de Icaza (miguel@nuclecu.unam.mx)
+/* $Id: creator.c,v 1.7 1997/07/17 02:21:47 davem Exp $
+ * creator.c: Creator/Creator3D frame buffer driver
  *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 #include <linux/kd.h>
 #include <linux/tty.h>
 #include <linux/malloc.h>
 #include <linux/proc_fs.h>
+#include <linux/config.h>
 
 #include <asm/sbus.h>
 #include <asm/io.h>
@@ -20,31 +20,575 @@
 #include <linux/selection.h>
 #include <linux/console_struct.h>
 #include "fb.h"
+#include "cg_common.h"
+
+#define	FFB_SFB8R_VOFF		0x00000000
+#define	FFB_SFB8G_VOFF		0x00400000
+#define	FFB_SFB8B_VOFF		0x00800000
+#define	FFB_SFB8X_VOFF		0x00c00000
+#define	FFB_SFB32_VOFF		0x01000000
+#define	FFB_SFB64_VOFF		0x02000000
+#define	FFB_FBC_REGS_VOFF	0x04000000
+#define	FFB_BM_FBC_REGS_VOFF	0x04002000
+#define	FFB_DFB8R_VOFF		0x04004000
+#define	FFB_DFB8G_VOFF		0x04404000
+#define	FFB_DFB8B_VOFF		0x04804000
+#define	FFB_DFB8X_VOFF		0x04c04000
+#define	FFB_DFB24_VOFF		0x05004000
+#define	FFB_DFB32_VOFF		0x06004000
+#define	FFB_DFB422A_VOFF	0x07004000	/* DFB 422 mode write to A */
+#define	FFB_DFB422AD_VOFF	0x07804000	/* DFB 422 mode with line doubling */
+#define	FFB_DFB24B_VOFF		0x08004000	/* DFB 24bit mode write to B */
+#define	FFB_DFB422B_VOFF	0x09004000	/* DFB 422 mode write to B */
+#define	FFB_DFB422BD_VOFF	0x09804000	/* DFB 422 mode with line doubling */
+#define	FFB_SFB16Z_VOFF		0x0a004000	/* 16bit mode Z planes */
+#define	FFB_SFB8Z_VOFF		0x0a404000	/* 8bit mode Z planes */
+#define	FFB_SFB422_VOFF		0x0ac04000	/* SFB 422 mode write to A/B */
+#define	FFB_SFB422D_VOFF	0x0b404000	/* SFB 422 mode with line doubling */
+#define	FFB_FBC_KREGS_VOFF	0x0bc04000
+#define	FFB_DAC_VOFF		0x0bc06000
+#define	FFB_PROM_VOFF		0x0bc08000
+#define	FFB_EXP_VOFF		0x0bc18000
+
+#define	FFB_SFB8R_POFF		0x04000000
+#define	FFB_SFB8G_POFF		0x04400000
+#define	FFB_SFB8B_POFF		0x04800000
+#define	FFB_SFB8X_POFF		0x04c00000
+#define	FFB_SFB32_POFF		0x05000000
+#define	FFB_SFB64_POFF		0x06000000
+#define	FFB_FBC_REGS_POFF	0x00600000
+#define	FFB_BM_FBC_REGS_POFF	0x00600000
+#define	FFB_DFB8R_POFF		0x01000000
+#define	FFB_DFB8G_POFF		0x01400000
+#define	FFB_DFB8B_POFF		0x01800000
+#define	FFB_DFB8X_POFF		0x01c00000
+#define	FFB_DFB24_POFF		0x02000000
+#define	FFB_DFB32_POFF		0x03000000
+#define	FFB_FBC_KREGS_POFF	0x00610000
+#define	FFB_DAC_POFF		0x00400000
+#define	FFB_PROM_POFF		0x00000000
+#define	FFB_EXP_POFF		0x00200000
+
+#define FFB_Y_BYTE_ADDR_SHIFT          11
+#define FFB_Y_ADDR_SHIFT               13
+
+#define FFB_PPC_ACE_DISABLE             1
+#define FFB_PPC_ACE_AUX_ADD             3
+#define FFB_PPC_ACE_SHIFT              18
+#define FFB_PPC_DCE_DISABLE             2
+#define FFB_PPC_DCE_SHIFT              16
+#define FFB_PPC_ABE_DISABLE             2
+#define FFB_PPC_ABE_SHIFT              14
+#define FFB_PPC_VCE_DISABLE             1
+#define FFB_PPC_VCE_2D                  2
+#define FFB_PPC_VCE_SHIFT              12
+#define FFB_PPC_APE_DISABLE             2
+#define FFB_PPC_APE_SHIFT              10
+#define FFB_PPC_CS_VARIABLE             2
+#define FFB_PPC_CS_SHIFT                0
+
+#define FFB_FBC_WB_A                    1
+#define FFB_FBC_WB_SHIFT               29
+#define FFB_FBC_PGE_MASK                3
+#define FFB_FBC_BE_SHIFT                4
+#define FFB_FBC_GE_SHIFT                2
+#define FFB_FBC_RE_SHIFT                0
+
+#define FFB_ROP_NEW                  0x83
+#define FFB_ROP_RGB_SHIFT               0
+
+#define FFB_UCSR_FIFO_MASK     0x00000fff
+#define FFB_UCSR_RP_BUSY       0x02000000
+
+struct ffb_fbc {
+	u8		xxx1[0x200];
+	volatile u32	ppc;
+	u8		xxx2[0x50];
+	volatile u32	fbc;
+	volatile u32	rop;
+	u8		xxx3[0x34];
+	volatile u32	pmask;
+	u8		xxx4[12];
+	volatile u32	clip0min;
+	volatile u32	clip0max;
+	volatile u32	clip1min;
+	volatile u32	clip1max;
+	volatile u32	clip2min;
+	volatile u32	clip2max;
+	volatile u32	clip3min;
+	volatile u32	clip3max;
+	u8		xxx5[0x3c];
+	volatile u32	unk1;
+	u8		xxx6[0x500];
+	volatile u32	unk2;
+	u8		xxx7[0xfc];
+	volatile u32	ucsr;
+};
+
+struct ffb_dac {
+	volatile u32	type;
+	volatile u32	value;
+	volatile u32	type2;
+	volatile u32	value2;
+};
+
+static void
+ffb_restore_palette (fbinfo_t *fbinfo)
+{
+}
+
+static void ffb_blitc(unsigned short, int, int);
+static void ffb_setw(int, int, unsigned short, int);
+static void ffb_cpyw(int, int, unsigned short *, int);
+static void ffb_fill(int, int, int *);
+
+static struct {
+	unsigned long voff;
+	unsigned long poff;
+	unsigned long size;
+} ffbmmap [] = {
+	{ FFB_SFB8R_VOFF,		FFB_SFB8R_POFF,		0x0400000 },
+	{ FFB_SFB8G_VOFF,		FFB_SFB8G_POFF,		0x0400000 },
+	{ FFB_SFB8B_VOFF,		FFB_SFB8B_POFF,		0x0400000 },
+	{ FFB_SFB8X_VOFF,		FFB_SFB8X_POFF,		0x0400000 },
+	{ FFB_SFB32_VOFF,		FFB_SFB32_POFF,		0x1000000 },
+	{ FFB_SFB64_VOFF,		FFB_SFB64_POFF,		0x2000000 },
+	{ FFB_FBC_REGS_VOFF,		FFB_FBC_REGS_POFF,	0x0002000 },
+	{ FFB_BM_FBC_REGS_VOFF,		FFB_BM_FBC_REGS_POFF,	0x0002000 },
+	{ FFB_DFB8R_VOFF,		FFB_DFB8R_POFF,		0x0400000 },
+	{ FFB_DFB8G_VOFF,		FFB_DFB8G_POFF,		0x0400000 },
+	{ FFB_DFB8B_VOFF,		FFB_DFB8B_POFF,		0x0400000 },
+	{ FFB_DFB8X_VOFF,		FFB_DFB8X_POFF,		0x0400000 },
+	{ FFB_DFB24_VOFF,		FFB_DFB24_POFF,		0x1000000 },
+	{ FFB_DFB32_VOFF,		FFB_DFB32_POFF,		0x1000000 },
+	{ FFB_FBC_KREGS_VOFF,		FFB_FBC_KREGS_POFF,	0x0002000 },
+	{ FFB_DAC_VOFF,			FFB_DAC_POFF,		0x0002000 },
+	{ FFB_PROM_VOFF,		FFB_PROM_POFF,		0x0010000 },
+	{ FFB_EXP_VOFF,			FFB_EXP_POFF,		0x0002000 }
+};
+
+/* Ugh: X wants to mmap a bunch of cute stuff at the same time :-( */
+/* So, we just mmap the things that are being asked for */
+static int
+ffb_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma,
+	  long base, fbinfo_t *fb)
+{
+	uint size, page, r, map_size;
+	unsigned long map_offset = 0;
+	int i;
+
+	size = vma->vm_end - vma->vm_start;
+        if (vma->vm_offset & ~PAGE_MASK)
+                return -ENXIO;
+
+	/* Try to align RAM */
+#define ALIGNMENT 0x400000
+	map_offset = vma->vm_offset + size;
+	if (vma->vm_offset < FFB_FBC_REGS_VOFF) {
+		struct vm_area_struct *vmm = find_vma(current->mm, vma->vm_start);
+		int alignment = ALIGNMENT - ((vma->vm_start - vma->vm_offset) & (ALIGNMENT - 1));
+
+		if (alignment == ALIGNMENT) alignment = 0;
+		if (alignment && (!vmm || vmm->vm_start >= vma->vm_end + alignment)) {
+			vma->vm_start += alignment;
+			vma->vm_end += alignment;
+		}
+	}
+#undef ALIGNMENT
+
+	/* To stop the swapper from even considering these pages */
+	vma->vm_flags |= FB_MMAP_VM_FLAGS;
+	
+	/* Each page, see which map applies */
+	for (page = 0; page < size; ){
+		map_size = 0;
+		for (i = 0; i < sizeof (ffbmmap) / sizeof (ffbmmap[0]); i++)
+			if (ffbmmap[i].voff == vma->vm_offset+page) {
+				map_size = ffbmmap[i].size;
+				map_offset = fb->info.ffb.physbase + ffbmmap[i].poff;
+			}
+
+		if (!map_size){
+			page += PAGE_SIZE;
+			continue;
+		}
+		if (page + map_size > size)
+			map_size = size - page;
+		r = io_remap_page_range (vma->vm_start+page,
+					 map_offset,
+					 map_size, vma->vm_page_prot, 0);
+		if (r)
+			return -EAGAIN;
+		page += map_size;
+	}
+
+	vma->vm_dentry = dget(file->f_dentry);
+        return 0;
+}
+
+/* XXX write body of these two... */
+static inline int
+ffb_wid_get (fbinfo_t *fb, struct fb_wid_list *wl)
+{
+	struct fb_wid_item *wi;
+	struct fb_wid_list wlt;
+	struct fb_wid_item wit[30];
+	char *km = NULL;
+	int i, j;
+	u32 l;
+	int err;
+	
+#ifdef CONFIG_SPARC32_COMPAT
+	if (current->tss.flags & SPARC_FLAG_32BIT) {
+		if (copy_from_user (&wlt, wl, 2 * sizeof (__u32)) ||
+		    __get_user ((long)wlt.wl_list, (((__u32 *)wl)+2)))
+			return -EFAULT;
+	} else
+#endif
+	if (copy_from_user (&wlt, wl, sizeof (wlt)))
+		return -EFAULT;
+	if (wlt.wl_count <= 30) {
+		if (copy_from_user (wit, wlt.wl_list, wlt.wl_count * sizeof(*wi)))
+			return -EFAULT;
+		wi = wit;
+	} else if (wlt.wl_count > 120)
+		return -EINVAL;
+	else {
+		wi = (struct fb_wid_item *) km = kmalloc (wlt.wl_count * sizeof (*wi), GFP_KERNEL);
+		if (!wi) return -ENOMEM;
+		if (copy_from_user (wi, wlt.wl_list, wlt.wl_count * sizeof(*wi))) {
+			kfree (wi);
+			return -EFAULT;
+		}
+	}
+	for (i = 0; i < wlt.wl_count; i++, wi++) {
+		switch (wi->wi_type) {
+		case FB_WID_DBL_8: j = (wi->wi_index & 0xf) + 0x40; break;
+		case FB_WID_DBL_24: j = wi->wi_index & 0x3f; break;
+		default: return -EINVAL;
+		}
+		wi->wi_attrs = 0xffff;
+		for (j = 0; j < 32; j++)
+			wi->wi_values [j] = 0;
+	}
+	err = 0;
+	if (copy_to_user (wlt.wl_list, km ? km : (char *)wit, wlt.wl_count * sizeof (*wi)))
+		err = -EFAULT;
+	if (km)
+		kfree (km);
+	return err;
+}
+
+static inline int
+ffb_wid_put (fbinfo_t *fb, struct fb_wid_list *wl)
+{
+	struct fb_wid_item *wi;
+	struct fb_wid_list wlt;
+	struct fb_wid_item wit[30];
+	char *km = NULL;
+	int i, j;
+	u32 l;
+	
+#ifdef CONFIG_SPARC32_COMPAT
+	if (current->tss.flags & SPARC_FLAG_32BIT) {
+		if (copy_from_user (&wlt, wl, 2 * sizeof (__u32)) ||
+		    __get_user ((long)wlt.wl_list, (((__u32 *)wl)+2)))
+			return -EFAULT;
+	} else
+#endif
+	if (copy_from_user (&wlt, wl, sizeof (wlt)))
+		return -EFAULT;
+	if (wlt.wl_count <= 30) {
+		if (copy_from_user (wit, wlt.wl_list, wlt.wl_count * sizeof(*wi)))
+			return -EFAULT;
+		wi = wit;
+	} else if (wlt.wl_count > 120)
+		return -EINVAL;
+	else {
+		wi = (struct fb_wid_item *) km = kmalloc (wlt.wl_count * sizeof (*wi), GFP_KERNEL);
+		if (!wi) return -ENOMEM;
+		if (copy_from_user (wi, wlt.wl_list, wlt.wl_count * sizeof(*wi))) {
+			kfree (wi);
+			return -EFAULT;
+		}
+	}
+	for (i = 0; i < wlt.wl_count; i++, wi++) {
+		switch (wi->wi_type) {
+		case FB_WID_DBL_8: j = (wi->wi_index & 0xf) + 0x40; break;
+		case FB_WID_DBL_24: j = wi->wi_index & 0x3f; break;
+		default: return -EINVAL;
+		}
+		/* x =	wi->wi_values [j] */;
+	}
+	if (km)
+		kfree (km);
+	return 0;
+}
+
+static inline void 
+ffb_curs_enable (fbinfo_t *fb, int enable)
+{
+	struct ffb_dac *dac = fb->info.ffb.dac;
+	
+	dac->type2 = 0x100;
+	if (fb->info.ffb.dac_rev <= 2)
+		dac->value2 = enable ? 3 : 0;
+	else
+		dac->value2 = enable ? 0 : 3;
+}
+
+static void
+ffb_setcursormap (fbinfo_t *fb, unsigned char *red,
+				 unsigned char *green,
+				 unsigned char *blue)
+{
+	struct ffb_dac *dac = fb->info.ffb.dac;
+	
+	ffb_curs_enable (fb, 0);
+	dac->type2 = 0x102;
+	dac->value2 = (red[0] | (green[0]<<8) | (blue[0]<<16));
+	dac->value2 = (red[1] | (green[1]<<8) | (blue[1]<<16));
+}
+
+/* Set cursor shape */
+static void
+ffb_setcurshape (fbinfo_t *fb)
+{
+	struct ffb_dac *dac = fb->info.ffb.dac;
+	int i, j;
+
+	ffb_curs_enable (fb, 0);
+	for (j = 0; j < 2; j++) {
+		dac->type2 = j ? 0 : 0x80;
+		for (i = 0; i < 0x40; i++) {
+			if (fb->cursor.size.fbx <= 32) {
+				dac->value2 = fb->cursor.bits [j][i];
+				dac->value2 = 0;
+			} else {
+				dac->value2 = fb->cursor.bits [j][2*i];
+				dac->value2 = fb->cursor.bits [j][2*i+1];
+			}
+		}
+	}	
+}
+
+/* Load cursor information */
+static void
+ffb_setcursor (fbinfo_t *fb)
+{
+	struct ffb_dac *dac = fb->info.ffb.dac;
+	struct cg_cursor *c = &fb->cursor;
+
+	dac->type2 = 0x104;
+/* Should this be just 0x7ff?? Should I do some margin handling and setcurshape
+   in that case? */
+	dac->value2 = (((c->cpos.fbx - c->chot.fbx) & 0xffff) << 16)
+	              |((c->cpos.fby - c->chot.fby) & 0xffff);
+	ffb_curs_enable (fb, fb->cursor.enable);
+}
+
+static void
+ffb_blank (fbinfo_t *fb)
+{
+/* XXX Write this */
+}
+
+static void
+ffb_unblank (fbinfo_t *fb)
+{
+/* XXX Write this */
+}
+
+static int ffb_clutstore (fbinfo_t *fb, int offset, int count)
+{
+	int i;
+	u32 *clut = fb->info.ffb.clut + offset;
+	struct ffb_dac *dac = fb->info.ffb.dac;
+	
+	dac->type = 0x2000 | offset;
+	for (i = 0; i < count; i++)
+		dac->value = *clut++;	/* Feed the colors in :)) */
+	return 0;
+}
+
+static int ffb_clutpost (fbinfo_t *fb, struct fb_clut *fc)
+{
+	int i;
+	u32 *clut;
+	struct fb_clut fct;
+	u8 red[256], green[256], blue[256];
+
+#ifdef CONFIG_SPARC32_COMPAT
+	if (current->tss.flags & SPARC_FLAG_32BIT) {
+		if (copy_from_user (&fct, fc, 3 * sizeof (__u32)) ||
+		    __get_user ((long)fct.red, &(((struct fb_clut32 *)fc)->red)) ||
+		    __get_user ((long)fct.green, &(((struct fb_clut32 *)fc)->green)) ||
+		    __get_user ((long)fct.blue, &(((struct fb_clut32 *)fc)->blue)))
+			return -EFAULT;
+	} else
+#endif
+	if (copy_from_user (&fct, fc, sizeof (struct fb_clut)))
+		return -EFAULT;
+	i = fct.offset + fct.count;
+	if (fct.clutid || i <= 0 || i > 256) return -EINVAL;
+	if (copy_from_user (red, fct.red, fct.count) ||
+	    copy_from_user (green, fct.green, fct.count) ||
+	    copy_from_user (blue, fct.blue, fct.count))
+		return -EFAULT;
+	clut = fb->info.ffb.clut + fct.offset;
+	for (i = 0; i < fct.count; i++)
+		*clut++ = ((red[i])|(green[i]<<8)|(blue[i]<<16));
+	return ffb_clutstore (fb, fct.offset, fct.count);
+}
+
+static int ffb_clutread (fbinfo_t *fb, struct fb_clut *fc)
+{
+/* XXX write this */
+	return 0;
+}
+
+static void
+ffb_loadcmap (fbinfo_t *fb, int index, int count)
+{
+	u32 *clut = fb->info.ffb.clut + index;
+	int i, j = count;
+	
+	for (i = index; j--; i++)
+		*clut++ = ((fb->color_map CM(i,0))) |
+			  ((fb->color_map CM(i,1)) << 8) |
+			  ((fb->color_map CM(i,2)) << 16);
+	ffb_clutstore (fb, index, count);
+}
+
+/* Handle ffb-specific ioctls */
+static int
+ffb_ioctl (struct inode *inode, struct file *file, unsigned cmd, unsigned long arg, fbinfo_t *fb)
+{
+	int i;
+	
+	switch (cmd) {
+	case FBIO_WID_GET:
+		return ffb_wid_get (fb, (struct fb_wid_list *)arg);
+	case FBIO_WID_PUT:
+		return ffb_wid_put (fb, (struct fb_wid_list *)arg);
+	case FFB_CLUTPOST:
+		return ffb_clutpost (fb, (struct fb_clut *)arg);
+	case FFB_CLUTREAD:
+		return ffb_clutread (fb, (struct fb_clut *)arg);
+		
+	default:
+		return -ENOSYS;
+	}
+}
 
-__initfunc(void creator_setup (fbinfo_t *fb, int slot, int con_node, unsigned long creator, int creator_io))
+void
+ffb_reset (fbinfo_t *fb)
 {
-        uint bases [2];
-        unsigned long *p;
+	struct ffb_info *ffb = &(fb->info.ffb);
+	int fifo;
 
-        if (!creator) {
-                prom_getproperty (con_node, "address", (char *) &bases[0], 4);
-                prom_printf ("Bases: %x %x\n", bases [0], bases [1]);
-                p = (unsigned long *) creator = bases[0];
-                fb->base = creator;
-                fb->base = 0xff168000;
-        }
-
-        fb->type.fb_cmsize = 256;
-        fb->mmap =  0;
-        fb->loadcmap = 0;
-        fb->setcursor = 0;
-        fb->setcursormap = 0;
-        fb->setcurshape = 0;
-        fb->ioctl = 0;
-        fb->switch_from_graph = 0;
-        fb->postsetup = sun_cg_postsetup;
-        fb->reset = 0;
-        fb->blank = 0;
-        fb->unblank = 0;
-        fb->type.fb_depth = 8;
+	if (fb->setcursor)
+		sun_hw_hide_cursor ();
+	
+	while ((fifo = (ffb->fbc->ucsr & FFB_UCSR_FIFO_MASK)) < 8);
+ 	ffb->fbc->ppc = (FFB_PPC_ACE_DISABLE << FFB_PPC_ACE_SHIFT) |
+			(FFB_PPC_DCE_DISABLE << FFB_PPC_DCE_SHIFT) |
+			(FFB_PPC_ABE_DISABLE << FFB_PPC_ABE_SHIFT) |
+			(FFB_PPC_VCE_DISABLE << FFB_PPC_VCE_SHIFT) |
+			(FFB_PPC_APE_DISABLE << FFB_PPC_APE_SHIFT) |
+			(FFB_PPC_CS_VARIABLE << FFB_PPC_CS_SHIFT);
+	ffb->fbc->fbc = (FFB_FBC_WB_A        << FFB_FBC_WB_SHIFT) |
+			(FFB_FBC_PGE_MASK    << FFB_FBC_BE_SHIFT) |
+			(FFB_FBC_PGE_MASK    << FFB_FBC_GE_SHIFT) |
+			(FFB_FBC_PGE_MASK    << FFB_FBC_RE_SHIFT);
+	ffb->fbc->rop = (FFB_ROP_NEW         << FFB_ROP_RGB_SHIFT);
+	ffb->fbc->pmask = 0x00ffffff;
+	while (ffb->fbc->ucsr & FFB_UCSR_RP_BUSY);
+}
+
+__initfunc(static unsigned long ffb_postsetup (fbinfo_t *fb, unsigned long memory_start))
+{
+	fb->info.ffb.clut = (u32 *)(memory_start);
+        fb->color_map = (u8 *)(memory_start+256*4+256);
+        return memory_start + 256*4 + 256*3;
+}
+
+__initfunc(void creator_setup (fbinfo_t *fb, int slot, int ffb_node, unsigned long ffb, int ffb_io))
+{
+	struct ffb_info *ffbinfo;
+	struct linux_prom64_registers regs[2*PROMREG_MAX];
+	
+	if (prom_getproperty(ffb_node, "reg", (void *) regs, sizeof(regs)) <= 0)
+		return;
+	ffb = regs[0].phys_addr;
+	printk ("creator%d at 0x%016lx ", slot, ffb);
+	
+	fb->base = ffb;	/* ??? */
+	
+	/* Fill in parameters we left out */
+	fb->type.fb_cmsize = 256;
+	fb->mmap = ffb_mmap;
+	fb->loadcmap = ffb_loadcmap;
+	fb->reset = ffb_reset;
+	fb->blank = ffb_blank;
+	fb->unblank = ffb_unblank;
+	fb->setcursor = ffb_setcursor;
+	fb->setcursormap = ffb_setcursormap;
+	fb->setcurshape = ffb_setcurshape;
+	fb->postsetup = ffb_postsetup;
+	fb->blitc = ffb_blitc;
+	fb->setw = ffb_setw;
+	fb->cpyw = ffb_cpyw;
+	fb->fill = ffb_fill;
+	fb->ioctl = ffb_ioctl;
+	fb->cursor.hwsize.fbx = 64;
+	fb->cursor.hwsize.fby = 64;
+	
+	ffbinfo = (struct ffb_info *) &fb->info.ffb;
+	
+	ffbinfo->physbase = ffb;
+
+	ffbinfo->fbc = (struct ffb_fbc *)(ffb + FFB_FBC_REGS_POFF);
+	ffbinfo->dac = (struct ffb_dac *)(ffb + FFB_DAC_POFF);
+	
+	ffbinfo->dac->type = 0x8000;
+	ffbinfo->dac_rev = (ffbinfo->dac->value >> 0x1c);
+	
+	if (slot == sun_prom_console_id)
+		fb_restore_palette = ffb_restore_palette;
+
+	/* Initialize Brooktree DAC */
+
+	printk("DAC %d\n", ffbinfo->dac_rev);
+		
+	if (slot && sun_prom_console_id == slot)
+		return;
+
+	/* Reset the ffb */
+	ffb_reset(fb);
+	
+	if (!slot) {
+		/* Enable Video */
+		ffb_unblank(fb);
+	} else {
+		ffb_blank(fb);
+	}
+}
+
+extern unsigned char vga_font[];
+
+static void ffb_blitc(unsigned short charattr, int xoff, int yoff)
+{
+}
+
+static void ffb_setw(int xoff, int yoff, unsigned short c, int count)
+{
+}
+
+static void ffb_cpyw(int xoff, int yoff, unsigned short *p, int count)
+{
+}
+
+static void ffb_fill(int attrib, int count, int *boxes)
+{
 }
diff -u --recursive --new-file v2.1.44/linux/drivers/sbus/char/fb.h linux/drivers/sbus/char/fb.h
--- v2.1.44/linux/drivers/sbus/char/fb.h	Thu Jun 26 12:33:39 1997
+++ linux/drivers/sbus/char/fb.h	Wed Jul 16 19:22:51 1997
@@ -1,4 +1,4 @@
-/* $Id: fb.h,v 1.27 1997/06/06 10:56:28 jj Exp $
+/* $Id: fb.h,v 1.29 1997/07/15 09:48:48 jj Exp $
  * fb.h: contains the definitions of the structures that various sun
  *       frame buffer can use to do console driver stuff.
  *
@@ -33,7 +33,7 @@
         struct  fbcurpos chot;	/* hot-spot */
         struct  fbcurpos size;	/* size of mask & image fields */
         struct	fbcurpos hwsize; /* hw max size */
-        int     bits[2][32];	/* space for mask & image bits */
+        int     bits[2][128];	/* space for mask & image bits */
 	char    color [6];	/* cursor colors */
 };
 
@@ -57,6 +57,14 @@
 	int lowdepth;
 };
 
+struct ffb_info {
+	unsigned long physbase;
+	struct ffb_fbc *fbc;
+	struct ffb_dac *dac;
+	int dac_rev;
+	u32	*clut;
+};
+
 struct leo_info {
 	struct leo_cursor *cursor;
 	struct leo_lc_ss0_krn *lc_ss0_krn;
@@ -113,6 +121,7 @@
 		struct cg14_info  cg14;
 		struct tcx_info   tcx;
 		struct leo_info	  leo;
+		struct ffb_info   ffb;
 	} info;		        /* per frame information */
 	int    space;           /* I/O space this card resides in */
 	int    blanked;		/* true if video blanked */
diff -u --recursive --new-file v2.1.44/linux/drivers/sbus/char/leo.c linux/drivers/sbus/char/leo.c
--- v2.1.44/linux/drivers/sbus/char/leo.c	Thu Jun 26 12:33:39 1997
+++ linux/drivers/sbus/char/leo.c	Wed Jul 16 20:37:21 1997
@@ -1,7 +1,7 @@
-/* $Id: leo.c,v 1.19 1997/06/06 10:56:30 jj Exp $
+/* $Id: leo.c,v 1.21 1997/07/17 02:21:48 davem Exp $
  * leo.c: SUNW,leo 24/8bit frame buffer driver
  *
- * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  * Copyright (C) 1997 Michal Rehacek (Michal.Rehacek@st.mff.cuni.cz)
  */
  
@@ -218,11 +218,12 @@
 					 map_offset,
 					 map_size, vma->vm_page_prot,
 					 fb->space);
-		if (r) return -EAGAIN;
+		if (r)
+			return -EAGAIN;
 		page += map_size;
 	}
-        vma->vm_inode = inode;
-        atomic_inc(&inode->i_count);
+
+	vma->vm_dentry = dget(file->f_dentry);
         return 0;
 }
 
@@ -376,7 +377,7 @@
 	return 0;
 }
 
-static int leo_clutpost (fbinfo_t *fb, struct leo_clut *lc)
+static int leo_clutpost (fbinfo_t *fb, struct fb_clut *lc)
 {
 	int xlate = 0, i;
 	u32 *clut;
@@ -398,7 +399,7 @@
 	return leo_clutstore (fb, lc->clutid);
 }
 
-static int leo_clutread (fbinfo_t *fb, struct leo_clut *lc)
+static int leo_clutread (fbinfo_t *fb, struct fb_clut *lc)
 {
 	int i;
 	u32 u;
@@ -463,29 +464,29 @@
 		if (i) return i;
 		return leo_wid_put (fb, (struct fb_wid_list *)arg);
 	case LEO_CLUTPOST:
-		i = verify_area (VERIFY_READ, (void *)arg, sizeof (struct leo_clut));
+		i = verify_area (VERIFY_READ, (void *)arg, sizeof (struct fb_clut));
 		if (i) return i;
-		i = ((struct leo_clut *)arg)->offset + ((struct leo_clut *)arg)->count;
+		i = ((struct fb_clut *)arg)->offset + ((struct fb_clut *)arg)->count;
 		if (i <= 0 || i > 256) return -EINVAL;
-		i = verify_area (VERIFY_READ, ((struct leo_clut *)arg)->red, ((struct leo_clut *)arg)->count);
+		i = verify_area (VERIFY_READ, ((struct fb_clut *)arg)->red, ((struct fb_clut *)arg)->count);
 		if (i) return i;
-		i = verify_area (VERIFY_READ, ((struct leo_clut *)arg)->green, ((struct leo_clut *)arg)->count);
+		i = verify_area (VERIFY_READ, ((struct fb_clut *)arg)->green, ((struct fb_clut *)arg)->count);
 		if (i) return i;
-		i = verify_area (VERIFY_READ, ((struct leo_clut *)arg)->blue, ((struct leo_clut *)arg)->count);
+		i = verify_area (VERIFY_READ, ((struct fb_clut *)arg)->blue, ((struct fb_clut *)arg)->count);
 		if (i) return i;
-		return leo_clutpost (fb, (struct leo_clut *)arg);
+		return leo_clutpost (fb, (struct fb_clut *)arg);
 	case LEO_CLUTREAD:
-		i = verify_area (VERIFY_READ, (void *)arg, sizeof (struct leo_clut));
+		i = verify_area (VERIFY_READ, (void *)arg, sizeof (struct fb_clut));
 		if (i) return i;
-		i = ((struct leo_clut *)arg)->offset + ((struct leo_clut *)arg)->count;
+		i = ((struct fb_clut *)arg)->offset + ((struct fb_clut *)arg)->count;
 		if (i <= 0 || i > 256) return -EINVAL;
-		i = verify_area (VERIFY_WRITE, ((struct leo_clut *)arg)->red, ((struct leo_clut *)arg)->count);
+		i = verify_area (VERIFY_WRITE, ((struct fb_clut *)arg)->red, ((struct fb_clut *)arg)->count);
 		if (i) return i;
-		i = verify_area (VERIFY_WRITE, ((struct leo_clut *)arg)->green, ((struct leo_clut *)arg)->count);
+		i = verify_area (VERIFY_WRITE, ((struct fb_clut *)arg)->green, ((struct fb_clut *)arg)->count);
 		if (i) return i;
-		i = verify_area (VERIFY_WRITE, ((struct leo_clut *)arg)->blue, ((struct leo_clut *)arg)->count);
+		i = verify_area (VERIFY_WRITE, ((struct fb_clut *)arg)->blue, ((struct fb_clut *)arg)->count);
 		if (i) return i;
-		return leo_clutread (fb, (struct leo_clut *)arg);
+		return leo_clutread (fb, (struct fb_clut *)arg);
 		
 	default:
 		return -ENOSYS;
diff -u --recursive --new-file v2.1.44/linux/drivers/sbus/char/suncons.c linux/drivers/sbus/char/suncons.c
--- v2.1.44/linux/drivers/sbus/char/suncons.c	Thu Jun 26 12:33:39 1997
+++ linux/drivers/sbus/char/suncons.c	Wed Jul 16 19:22:51 1997
@@ -1,4 +1,4 @@
-/* $Id: suncons.c,v 1.64 1997/06/06 10:56:25 jj Exp $
+/* $Id: suncons.c,v 1.66 1997/07/15 09:48:47 jj Exp $
  *
  * suncons.c: Sun SparcStation console support.
  *
@@ -828,10 +828,14 @@
 {
 	int root, n;
 
+#ifdef __sparc_v9__
 	root = prom_getchild (prom_root_node);
 	if ((n = prom_searchsiblings (root, "SUNW,ffb")) == 0)
 		return 0;
 	return n;
+#else
+	return 0;
+#endif
 }
 
 __initfunc(static void
@@ -1108,7 +1112,6 @@
 		if (!card_found)
 		    card_found = cg14 = cg14_present ();
 		if (!card_found){
-			prom_printf ("Searching for a creator\n");
 			card_found = creator = creator_present ();
 		}
 		if (!card_found){
@@ -1172,7 +1175,7 @@
 		if (creator){
 			sparc_framebuffer_setup (!sbdprom, creator, FBTYPE_CREATOR,
 						 0, 0, 0, prom_console_node == creator,
-						 prom_getchild (prom_root_node));
+						 prom_root_node);
 		}
 		break;
 	default:
@@ -1654,11 +1657,10 @@
 			return -EINVAL;
 		if ((uint) f.size.fby > fb->cursor.hwsize.fby)
 			return -EINVAL;
-		bytes = (f.size.fby * 32)/8;
-		i = verify_area (VERIFY_READ, f.image, bytes);
-		if (i) return i;
-		i = verify_area (VERIFY_READ, f.mask, bytes);
-		if (i) return i;
+		if (f.size.fbx > 32)
+			bytes = f.size.fby << 3;
+		else
+			bytes = f.size.fby << 2;
 	}
 	if (op & FB_CUR_SETCMAP){
 		if (f.cmap.index || f.cmap.count != 2)
@@ -1668,15 +1670,6 @@
 		    copy_from_user (blue, f.cmap.blue, 2))
 			return -EFAULT;
 	}
-	if (op & (FB_CUR_SETCUR | FB_CUR_SETPOS | FB_CUR_SETHOT)){
-		if (op & FB_CUR_SETCUR)
-			fb->cursor.enable = f.enable;
-		if (op & FB_CUR_SETPOS)
-			fb->cursor.cpos = f.pos;
-		if (op & FB_CUR_SETHOT)
-			fb->cursor.chot = f.hot;
-		(*fb->setcursor) (fb);
-	}
 	if (op & FB_CUR_SETCMAP)
 		(*fb->setcursormap) (fb, red, green, blue);
 	if (op & FB_CUR_SETSHAPE){
@@ -1687,14 +1680,30 @@
 		if (copy_from_user (fb->cursor.bits [0], f.mask, bytes) ||
 		    copy_from_user (fb->cursor.bits [1], f.image, bytes))
 			return -EFAULT;
-		u = ~0;
-		if (f.size.fbx < fb->cursor.hwsize.fbx)
-			u = ~(u  >> f.size.fbx);
-		for (i = fb->cursor.size.fby - 1; i >= 0; i--) {
-			fb->cursor.bits [0][i] &= u;
-			fb->cursor.bits [1][i] &= fb->cursor.bits [0][i];
+		if (f.size.fbx <= 32) {
+			u = ~(0xffffffff >> f.size.fbx);
+			for (i = fb->cursor.size.fby - 1; i >= 0; i--) {
+				fb->cursor.bits [0][i] &= u;
+				fb->cursor.bits [1][i] &= fb->cursor.bits [0][i];
+			}
+		} else {
+			u = ~(0xffffffff >> (f.size.fbx - 32));
+			for (i = fb->cursor.size.fby - 1; i >= 0; i--) {
+				fb->cursor.bits [0][2*i+1] &= u;
+				fb->cursor.bits [1][2*i] &= fb->cursor.bits [0][2*i];
+				fb->cursor.bits [1][2*i+1] &= fb->cursor.bits [0][2*i+1];
+			}
 		}
 		(*fb->setcurshape) (fb);
+	}
+	if (op & (FB_CUR_SETCUR | FB_CUR_SETPOS | FB_CUR_SETHOT)){
+		if (op & FB_CUR_SETCUR)
+			fb->cursor.enable = f.enable;
+		if (op & FB_CUR_SETPOS)
+			fb->cursor.cpos = f.pos;
+		if (op & FB_CUR_SETHOT)
+			fb->cursor.chot = f.hot;
+		(*fb->setcursor) (fb);
 	}
 	return 0;
 }
diff -u --recursive --new-file v2.1.44/linux/drivers/sbus/char/sunfb.c linux/drivers/sbus/char/sunfb.c
--- v2.1.44/linux/drivers/sbus/char/sunfb.c	Mon Jul  7 08:18:55 1997
+++ linux/drivers/sbus/char/sunfb.c	Wed Jul 16 20:37:21 1997
@@ -1,4 +1,4 @@
-/* $Id: sunfb.c,v 1.25 1997/07/01 09:12:06 jj Exp $
+/* $Id: sunfb.c,v 1.26 1997/07/17 02:21:48 davem Exp $
  * sunfb.c: Sun generic frame buffer support.
  *
  * Copyright (C) 1995, 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -275,7 +275,8 @@
 		int v;
 		
 		v = (*fb->mmap)(inode, file, vma, fb->base, fb);
-		if (v) return v;
+		if (v)
+			return v;
 		vma->vm_flags |= VM_IO;
 		if (!fb->mmaped) {
 			fb->mmaped = 1;
diff -u --recursive --new-file v2.1.44/linux/drivers/sbus/char/sunserial.h linux/drivers/sbus/char/sunserial.h
--- v2.1.44/linux/drivers/sbus/char/sunserial.h	Mon Apr 14 16:28:14 1997
+++ linux/drivers/sbus/char/sunserial.h	Wed Jul 16 19:22:51 1997
@@ -1,4 +1,4 @@
-/* $Id: sunserial.h,v 1.9 1997/04/12 23:33:12 ecd Exp $
+/* $Id: sunserial.h,v 1.11 1997/07/08 10:17:23 davem Exp $
  * serial.h: Definitions for the Sparc Zilog serial driver.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v2.1.44/linux/drivers/sbus/char/tcx.c linux/drivers/sbus/char/tcx.c
--- v2.1.44/linux/drivers/sbus/char/tcx.c	Thu Jun 26 12:33:39 1997
+++ linux/drivers/sbus/char/tcx.c	Wed Jul 16 20:37:21 1997
@@ -1,4 +1,4 @@
-/* $Id: tcx.c,v 1.16 1997/06/06 10:56:31 jj Exp $
+/* $Id: tcx.c,v 1.17 1997/07/17 02:21:50 davem Exp $
  * tcx.c: SUNW,tcx 24/8bit frame buffer driver
  *
  * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -169,11 +169,12 @@
 					 map_offset,
 					 map_size, vma->vm_page_prot,
 					 fb->space);
-		if (r) return -EAGAIN;
+		if (r)
+			return -EAGAIN;
 		page += map_size;
 	}
-        vma->vm_inode = inode;
-        atomic_inc(&inode->i_count);
+
+	vma->vm_dentry = dget(file->f_dentry);
         return 0;
 }
 
diff -u --recursive --new-file v2.1.44/linux/drivers/sbus/char/vfc_dev.c linux/drivers/sbus/char/vfc_dev.c
--- v2.1.44/linux/drivers/sbus/char/vfc_dev.c	Mon Jun 16 16:35:56 1997
+++ linux/drivers/sbus/char/vfc_dev.c	Wed Jul 16 19:22:51 1997
@@ -577,11 +577,12 @@
 	if(vma->vm_offset & ~PAGE_MASK) return -ENXIO;
 	vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO | VM_MAYREAD | VM_MAYWRITE | VM_MAYSHARE;
 	map_offset=(unsigned int)dev->phys_regs;
-	ret=io_remap_page_range(vma->vm_start,map_offset,map_size, 
-				vma->vm_page_prot, dev->which_io);
-	if(ret) return -EAGAIN;
-	vma->vm_inode=inode;
-	atomic_inc(&inode->i_count);
+	ret = io_remap_page_range(vma->vm_start,map_offset,map_size, 
+				  vma->vm_page_prot, dev->which_io);
+	if(ret)
+		return -EAGAIN;
+
+	vma->vm_dentry = dget(file->f_dentry);
 	return 0;
 }
 
diff -u --recursive --new-file v2.1.44/linux/drivers/sbus/char/weitek.c linux/drivers/sbus/char/weitek.c
--- v2.1.44/linux/drivers/sbus/char/weitek.c	Thu Jun 26 12:33:39 1997
+++ linux/drivers/sbus/char/weitek.c	Wed Jul 16 20:37:21 1997
@@ -1,4 +1,4 @@
-/* $Id: weitek.c,v 1.13 1997/06/06 10:56:31 jj Exp $
+/* $Id: weitek.c,v 1.14 1997/07/17 02:21:53 davem Exp $
  * weitek.c: Tadpole P9100/P9000 console driver
  *
  * Copyright (C) 1996 David Redman (djhr@tadpole.co.uk)
@@ -79,11 +79,12 @@
 					 map_offset,
 					 map_size, vma->vm_page_prot,
 					 fb->space);
-		if (r) return -EAGAIN;
+		if (r)
+			return -EAGAIN;
 		page += map_size;
 	}
-	vma->vm_inode = inode;
-	atomic_inc(&inode->i_count);
+
+	vma->vm_dentry = dget(file->f_dentry);
 	return 0;
 }
 #endif
diff -u --recursive --new-file v2.1.44/linux/drivers/scsi/BusLogic.h linux/drivers/scsi/BusLogic.h
--- v2.1.44/linux/drivers/scsi/BusLogic.h	Mon Jul  7 16:02:51 1997
+++ linux/drivers/scsi/BusLogic.h	Wed Jul 16 20:17:12 1997
@@ -29,6 +29,7 @@
 
 #include <linux/config.h>
 
+
 /*
   Define types for some of the structures that interface with the rest
   of the Linux Kernel and SCSI Subsystem.
diff -u --recursive --new-file v2.1.44/linux/drivers/scsi/advansys.h linux/drivers/scsi/advansys.h
--- v2.1.44/linux/drivers/scsi/advansys.h	Mon Jul  7 16:02:51 1997
+++ linux/drivers/scsi/advansys.h	Wed Jul 16 20:37:21 1997
@@ -1,4 +1,4 @@
-/* $Id: advansys.h,v 1997/05/28 00:23:06 bobf Exp bobf $ */
+/* $Id: advansys.h,v 1.6 1997/05/30 19:25:12 davem Exp $ */
 
 /*
  * advansys.h - Linux Host Driver for AdvanSys SCSI Adapters
diff -u --recursive --new-file v2.1.44/linux/drivers/scsi/qlogicpti.c linux/drivers/scsi/qlogicpti.c
--- v2.1.44/linux/drivers/scsi/qlogicpti.c	Thu May 29 21:53:08 1997
+++ linux/drivers/scsi/qlogicpti.c	Wed Jul 16 19:22:51 1997
@@ -653,7 +653,7 @@
 			}
 
 			qpti_host->base = (unsigned char *)qregs;
-			qpti_host->io_port = (unsigned int) qregs;
+			qpti_host->io_port = (unsigned int) ((unsigned long)qregs);
 			qpti_host->n_io_port = (unsigned char)
 				qpti->qdev->reg_addrs[0].reg_size;
 
@@ -805,7 +805,7 @@
 	memset(cmd, 0, sizeof(struct Command_Entry));
 	cmd->hdr.entry_cnt = 1;
 	cmd->hdr.entry_type = ENTRY_COMMAND;
-	cmd->handle = (u_int) Cmnd;          /* magic mushroom */
+	cmd->handle = (u_int) ((unsigned long)Cmnd);          /* magic mushroom */
 	cmd->target_id = Cmnd->target;
 	cmd->target_lun = Cmnd->lun;
 	cmd->cdb_length = Cmnd->cmd_len;
@@ -890,7 +890,7 @@
 							  Cmnd->request_bufflen,
 							  qpti->qdev->my_bus));
 
-		cmd->dataseg[0].d_base = (u_int) Cmnd->SCp.ptr;
+		cmd->dataseg[0].d_base = (u_int) ((unsigned long)Cmnd->SCp.ptr);
 		cmd->dataseg[0].d_count = Cmnd->request_bufflen;
 		cmd->segment_cnt = 1;
 	}
@@ -1062,7 +1062,7 @@
 			while(out_ptr != in_ptr) {
 				sts = (struct Status_Entry *) &qpti->res_cpu[out_ptr];
 				out_ptr = NEXT_RES_PTR(out_ptr);
-				Cmnd = (Scsi_Cmnd *) sts->handle; /* but_to_virt?!?! */
+				Cmnd = (Scsi_Cmnd *) ((unsigned long)sts->handle);
 				if(sts->completion_status == CS_RESET_OCCURRED ||
 				   sts->completion_status == CS_ABORTED ||
 				   (sts->status_flags & STF_BUS_RESET))
@@ -1111,8 +1111,8 @@
 	qlogicpti_disable_irqs(qpti->qregs);
 	param[0] = MBOX_ABORT;
 	param[1] = (((u_short) Cmnd->target) << 8) | Cmnd->lun;
-	param[2] = ((unsigned int)Cmnd) >> 16;
-	param[3] = ((unsigned int)Cmnd) & 0xffff;
+	param[2] = ((unsigned int)((unsigned long)Cmnd)) >> 16;
+	param[3] = ((unsigned int)((unsigned long)Cmnd)) & 0xffff;
 	if(qlogicpti_mbox_command(qpti, param, 0) ||
 	   (param[0] != MBOX_COMMAND_COMPLETE)) {
 		printk(KERN_EMERG "qlogicpti : scsi abort failure: %x\n", param[0]);
diff -u --recursive --new-file v2.1.44/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v2.1.44/linux/drivers/scsi/scsi.c	Wed Apr 23 19:01:22 1997
+++ linux/drivers/scsi/scsi.c	Wed Jul 16 19:22:51 1997
@@ -12,6 +12,7 @@
  *      Rik Faith <faith@cs.unc.edu>
  *      Tommy Thorn <tthorn>
  *      Thomas Wuensche <tw@fgb1.fgb.mw.tu-muenchen.de>
+ *      Andrea Arcangeli <arcangeli@mbox.queen.it>
  *
  *  Modified by Eric Youngdale eric@aib.com to
  *  add scatter-gather, multiple outstanding request, and other
@@ -3508,6 +3509,7 @@
 
 void cleanup_module( void)
 {
+    timer_active &= ~(1 << SCSI_TIMER);
 #if CONFIG_PROC_FS
     proc_scsi_unregister(0, PROC_SCSI_SCSI);
 
diff -u --recursive --new-file v2.1.44/linux/drivers/scsi/sg.c linux/drivers/scsi/sg.c
--- v2.1.44/linux/drivers/scsi/sg.c	Fri Apr  4 08:52:23 1997
+++ linux/drivers/scsi/sg.c	Mon Jul 14 11:33:25 1997
@@ -488,7 +488,7 @@
 
 static unsigned int sg_poll(struct file *file, poll_table * wait)
 {
-        int dev = MINOR(file->f_inode->i_rdev);
+        int dev = MINOR(file->f_dentry->d_inode->i_rdev);
         struct scsi_generic *device = &scsi_generics[dev];
         unsigned int mask = 0;
 
diff -u --recursive --new-file v2.1.44/linux/drivers/scsi/tmscsim.c linux/drivers/scsi/tmscsim.c
--- v2.1.44/linux/drivers/scsi/tmscsim.c	Tue May 13 22:41:13 1997
+++ linux/drivers/scsi/tmscsim.c	Thu Jul 10 07:55:30 1997
@@ -50,13 +50,8 @@
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/config.h>
-
-#include <linux/version.h>
-#if LINUX_VERSION_CODE < 66354 /* 1.3.50 */
-#include "../block/blk.h"
-#else
+#include <linux/init.h>
 #include <linux/blk.h>
-#endif
 
 #include "scsi.h"
 #include "hosts.h"
@@ -69,13 +64,10 @@
 
 #define PCI_DEVICE_ID_AMD53C974 	PCI_DEVICE_ID_AMD_SCSI
 
-
-#ifndef  VERSION_ELF_1_2_13
 struct proc_dir_entry	proc_scsi_tmscsim ={
        PROC_SCSI_DC390T, 7 ,"tmscsim",
        S_IFDIR | S_IRUGO | S_IXUGO, 2
        };
-#endif
 
 static USHORT DC390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB );
 static void DC390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
@@ -675,11 +667,7 @@
  * Description:
  *   Return the disk geometry for the given SCSI device.
  ***********************************************************************/
-#ifdef	VERSION_ELF_1_2_13
-int DC390_bios_param(Disk *disk, int devno, int geom[])
-#else
 int DC390_bios_param(Disk *disk, kdev_t devno, int geom[])
-#endif
 {
     int heads, sectors, cylinders;
     PACB pACB;
@@ -1046,14 +1034,10 @@
  ***********************************************************************/
 void DC390_initSRB( PSRB psrb )
 {
-#ifndef VERSION_ELF_1_2_13
 #ifdef DC390_DEBUG0
    printk("DC390 init: %08lx %08lx,",(ULONG)psrb,(ULONG)virt_to_bus(psrb));
 #endif
 	psrb->PhysSRB = virt_to_bus( psrb );
-#else
-	psrb->PhysSRB = (ULONG) psrb;
-#endif
 }
 
 
@@ -1084,7 +1068,7 @@
  * Inputs : psh - pointer to this host adapter's structure
  *
  ***********************************************************************/
-void DC390_initACB( PSH psh, ULONG io_port, UCHAR Irq, USHORT index )
+__initfunc(void DC390_initACB( PSH psh, ULONG io_port, UCHAR Irq, USHORT index ))
 {
     PACB    pACB;
     USHORT  i;
@@ -1098,7 +1082,6 @@
 
     pACB = (PACB) psh->hostdata;
 
-#ifndef VERSION_ELF_1_2_13
     psh->max_id = 8;
 #ifdef	CONFIG_SCSI_MULTI_LUN
     if( eepromBuf[index][EE_MODE2] & LUN_CHECK )
@@ -1106,7 +1089,6 @@
     else
 #endif
 	psh->max_lun = 1;
-#endif
 
     pACB->max_id = 7;
     if( pACB->max_id == eepromBuf[index][EE_ADAPT_SCSI_ID] )
@@ -1155,7 +1137,7 @@
  * Inputs : psh - pointer to this host adapter's structure
  *
  ***********************************************************************/
-int DC390_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, USHORT index )
+__initfunc(int DC390_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, USHORT index))
 {
     USHORT ioport;
     UCHAR  bval;
@@ -1179,11 +1161,7 @@
 
     if( !used_irq )
     {
-#ifdef	VERSION_ELF_1_2_13
-	if( request_irq(Irq, DC390_Interrupt, SA_INTERRUPT, "tmscsim"))
-#else
 	if( request_irq(Irq, DC390_Interrupt, SA_INTERRUPT, "tmscsim", NULL))
-#endif
 	{
 	    printk("DC390: register IRQ error!\n");
 	    return( -1 );
@@ -1533,8 +1511,8 @@
  *	field of the pACB structure MUST have been set.
  ***********************************************************************/
 
-static int
-DC390_init (PSHT psht, ULONG io_port, UCHAR Irq, USHORT index, USHORT MechNum)
+__initfunc(static int
+DC390_init (PSHT psht, ULONG io_port, UCHAR Irq, USHORT index, USHORT MechNum))
 {
     PSH   psh;
     PACB  pACB;
@@ -1614,8 +1592,8 @@
  *
  ***********************************************************************/
 
-int
-DC390_detect(Scsi_Host_Template *psht)
+__initfunc(int
+DC390_detect(Scsi_Host_Template *psht))
 {
 #ifdef FOR_PCI_OK
     UCHAR   pci_bus, pci_device_fn;
@@ -1626,19 +1604,13 @@
 
     UCHAR   irq;
     UCHAR   istatus;
-#ifndef VERSION_ELF_1_2_13
     UINT    io_port;
-#else
-    ULONG   io_port;
-#endif
     USHORT  adaptCnt = 0;	/* Number of boards detected */
     USHORT  pci_index = 0;	/* Device index to PCI BIOS calls */
     USHORT  MechNum, BusDevFunNum;
     ULONG   wlval;
 
-#ifndef VERSION_ELF_1_2_13
     psht->proc_dir = &proc_scsi_tmscsim;
-#endif
 
     InitialTime = 1;
     pSHT_start = psht;
@@ -1726,8 +1698,6 @@
 }
 
 
-#ifndef VERSION_ELF_1_2_13
-
 /********************************************************************
  * Function: tmscsim_set_info()
  *
@@ -1848,7 +1818,6 @@
   else
     return length;
 }
-#endif /* VERSION_ELF_1_2_13 */
 
 
 #ifdef MODULE
@@ -1909,11 +1878,7 @@
 #ifdef DC390_DEBUG0
 	    printk("DC390: Free IRQ %i.",host->irq);
 #endif
-#ifndef VERSION_ELF_1_2_13
 	    free_irq(host->irq,NULL);
-#else
-	    free_irq(host->irq);
-#endif
 	 }
     }
 
diff -u --recursive --new-file v2.1.44/linux/drivers/scsi/wd33c93.c linux/drivers/scsi/wd33c93.c
--- v2.1.44/linux/drivers/scsi/wd33c93.c	Wed Apr 23 19:01:22 1997
+++ linux/drivers/scsi/wd33c93.c	Wed Jul 16 19:22:51 1997
@@ -87,8 +87,9 @@
 #include "hosts.h"
 
 
-#define WD33C93_VERSION    "1.24"
-#define WD33C93_DATE       "29/Jan/1997"
+#define WD33C93_VERSION    "1.25"
+#define WD33C93_DATE       "09/Jul/1997"
+/* NOTE: 1.25 for m68k is related to in2000-1.31 for x86 */
 
 /*
  * Note - the following defines have been moved to 'wd33c93.h':
@@ -107,11 +108,14 @@
 
 
 /*
- * setup_strings is an array of strings that define some of the operating
- * parameters and settings for this driver. It is used unless an amiboot
- * or insmod command line has been specified, in which case those settings
- * are combined with the ones here. The driver recognizes the following
- * keywords (lower case required) and arguments:
+ * 'setup_strings' is a single string used to pass operating parameters and
+ * settings from the kernel/module command-line to the driver. 'setup_args[]'
+ * is an array of strings that define the compile-time default values for
+ * these settings. If Linux boots with an amiboot or insmod command-line,
+ * those settings are combined with 'setup_args[]'. Note that amiboot
+ * command-lines are prefixed with "wd33c93=" while insmod uses a
+ * "setup_strings=" prefix. The driver recognizes the following keywords
+ * (lower case required) and arguments:
  *
  * -  nosync:bitmask -bitmask is a byte where the 1st 7 bits correspond with
  *                    the 7 possible SCSI devices. Set a bit to negotiate for
@@ -139,13 +143,11 @@
  *    _must_ be a colon between a keyword and its numeric argument, with no
  *    spaces.
  * -  Keywords are separated by commas, no spaces, in the standard kernel
- *    command-line manner, except in the case of 'setup_strings[]' (see
- *    below), which is simply a C array of pointers to char. Each element
- *    in the array is a string comprising one keyword & argument.
+ *    command-line manner.
  * -  A keyword in the 'nth' comma-separated command-line member will overwrite
- *    the 'nth' element of setup_strings[]. A blank command-line member (in
+ *    the 'nth' element of setup_args[]. A blank command-line member (in
  *    other words, a comma with no preceding keyword) will _not_ overwrite
- *    the corresponding setup_strings[] element.
+ *    the corresponding setup_args[] element.
  * -  If a keyword is used more than once, the first one applies to the first
  *    SCSI host found, the second to the second card, etc, unless the 'next'
  *    keyword is used to change the order.
@@ -158,8 +160,16 @@
  * -  wd33c93=debug:0x1c
  */
 
-static char *setup_strings[] =
-      {"","","","","","","","","","","",""};
+/* Normally, no defaults are specified */
+static char *setup_args[] =
+      {"","","","","","","","",""};
+
+/* filled in by 'insmod' */
+static char *setup_strings = 0;
+
+#ifdef MODULE_PARM
+MODULE_PARM(setup_strings, "s");
+#endif
 
 
 
@@ -337,9 +347,24 @@
       cmd->SCp.this_residual = cmd->request_bufflen;
       }
 
-/* Preset the command status to GOOD, since that's the normal case */
+/* WD docs state that at the conclusion of a "LEVEL2" command, the
+ * status byte can be retrieved from the LUN register. Apparently,
+ * this is the case only for *uninterrupted* LEVEL2 commands! If
+ * there are any unexpected phases entered, even if they are 100%
+ * legal (different devices may choose to do things differently),
+ * the LEVEL2 command sequence is exited. This often occurs prior
+ * to receiving the status byte, in which case the driver does a
+ * status phase interrupt and gets the status byte on its own.
+ * While such a command can then be "resumed" (ie restarted to
+ * finish up as a LEVEL2 command), the LUN register will NOT be
+ * a valid status byte at the command's conclusion, and we must
+ * use the byte obtained during the earlier interrupt. Here, we
+ * preset SCp.Status to an illegal value (0xff) so that when
+ * this command finally completes, we can tell where the actual
+ * status byte is stored.
+ */
 
-   cmd->SCp.Status = GOOD;
+   cmd->SCp.Status = ILLEGAL_STATUS_BYTE;
 
    /*
     * Add the cmd to the end of 'input_Q'. Note that REQUEST SENSE
@@ -701,7 +726,8 @@
       write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_DMA);
       write_wd33c93_count(regp,cmd->SCp.this_residual);
 
-      if ((hostdata->level2 >= L2_DATA) || (cmd->SCp.phase == 0)) {
+      if ((hostdata->level2 >= L2_DATA) ||
+          (hostdata->level2 == L2_BASIC && cmd->SCp.phase == 0)) {
          write_wd33c93(regp, WD_COMMAND_PHASE, 0x45);
          write_wd33c93_cmd(regp, WD_CMD_SEL_ATN_XFER);
          hostdata->state = S_RUNNING_LEVEL2;
@@ -786,17 +812,17 @@
          hostdata->state = S_UNCONNECTED;
          cmd->scsi_done(cmd);
 
-	 /* From esp.c:
-	  * There is a window of time within the scsi_done() path
-	  * of execution where interrupts are turned back on full
-	  * blast and left that way.  During that time we could
-	  * reconnect to a disconnected command, then we'd bomb
-	  * out below.  We could also end up executing two commands
-	  * at _once_.  ...just so you know why the restore_flags()
-	  * is here...
-	  */
+    /* From esp.c:
+     * There is a window of time within the scsi_done() path
+     * of execution where interrupts are turned back on full
+     * blast and left that way.  During that time we could
+     * reconnect to a disconnected command, then we'd bomb
+     * out below.  We could also end up executing two commands
+     * at _once_.  ...just so you know why the restore_flags()
+     * is here...
+     */
 
-	 restore_flags(flags);
+    restore_flags(flags);
 
 /* We are not connected to a target - check to see if there
  * are commands waiting to be executed.
@@ -887,9 +913,10 @@
       case CSR_XFER_DONE|PHS_STATUS:
       case CSR_UNEXP    |PHS_STATUS:
       case CSR_SRV_REQ  |PHS_STATUS:
-DB(DB_INTR,printk("STATUS"))
+DB(DB_INTR,printk("STATUS="))
 
          cmd->SCp.Status = read_1_byte(regp);
+DB(DB_INTR,printk("%02x",cmd->SCp.Status))
          if (hostdata->level2 >= L2_BASIC) {
             sr = read_wd33c93(regp, WD_SCSI_STATUS);  /* clear interrupt */
             hostdata->state = S_RUNNING_LEVEL2;
@@ -897,7 +924,6 @@
             write_wd33c93_cmd(regp, WD_CMD_SEL_ATN_XFER);
             }
          else {
-DB(DB_INTR,printk("=%02x",cmd->SCp.Status))
             hostdata->state = S_CONNECTED;
             }
          break;
@@ -1067,21 +1093,22 @@
 DB(DB_INTR,printk("SX-DONE-%ld",cmd->pid))
             cmd->SCp.Message = COMMAND_COMPLETE;
             lun = read_wd33c93(regp, WD_TARGET_LUN);
-            if (cmd->SCp.Status == GOOD)
-               cmd->SCp.Status = lun;
+DB(DB_INTR,printk(":%d.%d",cmd->SCp.Status,lun))
             hostdata->connected = NULL;
-            if (cmd->cmnd[0] != REQUEST_SENSE)
-               cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
-            else if (cmd->SCp.Status != GOOD)
-               cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
             hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
             hostdata->state = S_UNCONNECTED;
+            if (cmd->SCp.Status == ILLEGAL_STATUS_BYTE)
+               cmd->SCp.Status = lun;
+            if (cmd->cmnd[0] == REQUEST_SENSE && cmd->SCp.Status != GOOD)
+               cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
+            else
+               cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
             cmd->scsi_done(cmd);
 
 /* We are no longer  connected to a target - check to see if
  * there are commands waiting to be executed.
  */
-	    restore_flags(flags);
+       restore_flags(flags);
             wd33c93_execute(instance);
             }
          else {
@@ -1154,17 +1181,17 @@
          hostdata->connected = NULL;
          hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
          hostdata->state = S_UNCONNECTED;
-         if (cmd->cmnd[0] != REQUEST_SENSE)
-            cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
-         else if (cmd->SCp.Status != GOOD)
+         if (cmd->cmnd[0] == REQUEST_SENSE && cmd->SCp.Status != GOOD)
             cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
+         else
+            cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
          cmd->scsi_done(cmd);
 
 /* We are no longer connected to a target - check to see if
  * there are commands waiting to be executed.
  */
-	 /* look above for comments on scsi_done() */
-	 restore_flags(flags);
+    /* look above for comments on scsi_done() */
+    restore_flags(flags);
          wd33c93_execute(instance);
          break;
 
@@ -1186,12 +1213,13 @@
                hostdata->connected = NULL;
                hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
                hostdata->state = S_UNCONNECTED;
-               if (cmd->cmnd[0] != REQUEST_SENSE)
-                  cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
-               else if (cmd->SCp.Status != GOOD)
+DB(DB_INTR,printk(":%d",cmd->SCp.Status))
+               if (cmd->cmnd[0] == REQUEST_SENSE && cmd->SCp.Status != GOOD)
                   cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
+               else
+                  cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
                cmd->scsi_done(cmd);
-	       restore_flags(flags);
+          restore_flags(flags);
                break;
             case S_PRE_TMP_DISC:
             case S_RUNNING_LEVEL2:
@@ -1433,7 +1461,7 @@
          cmd->result = DID_ABORT << 16;
          printk("scsi%d: Abort - removing command %ld from input_Q. ",
            instance->host_no, cmd->pid);
-	 enable_irq(cmd->host->irq);
+    enable_irq(cmd->host->irq);
          cmd->scsi_done(cmd);
          return SCSI_ABORT_SUCCESS;
          }
@@ -1523,7 +1551,7 @@
          printk("scsi%d: Abort - command %ld found on disconnected_Q - ",
                  instance->host_no, cmd->pid);
          printk("returning ABORT_SNOOZE. ");
-	 enable_irq(cmd->host->irq);
+    enable_irq(cmd->host->irq);
          return SCSI_ABORT_SNOOZE;
          }
       tmp = (Scsi_Cmnd *)tmp->host_scribble;
@@ -1551,10 +1579,11 @@
 
 
 #define MAX_WD33C93_HOSTS 4
-#define MAX_SETUP_STRINGS (sizeof(setup_strings) / sizeof(char *))
+#define MAX_SETUP_ARGS (sizeof(setup_args) / sizeof(char *))
 #define SETUP_BUFFER_SIZE 200
 static char setup_buffer[SETUP_BUFFER_SIZE];
-static char setup_used[MAX_SETUP_STRINGS];
+static char setup_used[MAX_SETUP_ARGS];
+static int done_setup = 0;
 
 void wd33c93_setup (char *str, int *ints)
 {
@@ -1583,45 +1612,46 @@
    setup_buffer[SETUP_BUFFER_SIZE - 1] = '\0';
    p1 = setup_buffer;
    i = 0;
-   while (*p1 && (i < MAX_SETUP_STRINGS)) {
+   while (*p1 && (i < MAX_SETUP_ARGS)) {
       p2 = strchr(p1, ',');
       if (p2) {
          *p2 = '\0';
          if (p1 != p2)
-            setup_strings[i] = p1;
+            setup_args[i] = p1;
          p1 = p2 + 1;
          i++;
          }
       else {
-         setup_strings[i] = p1;
+         setup_args[i] = p1;
          break;
          }
       }
-   for (i=0; i<MAX_SETUP_STRINGS; i++)
+   for (i=0; i<MAX_SETUP_ARGS; i++)
       setup_used[i] = 0;
+   done_setup = 1;
 }
 
 
-/* check_setup_strings() returns index if key found, 0 if not
+/* check_setup_args() returns index if key found, 0 if not
  */
 
-static int check_setup_strings(char *key, int *flags, int *val, char *buf)
+static int check_setup_args(char *key, int *flags, int *val, char *buf)
 {
 int x;
 char *cp;
 
-   for  (x=0; x<MAX_SETUP_STRINGS; x++) {
+   for  (x=0; x<MAX_SETUP_ARGS; x++) {
       if (setup_used[x])
          continue;
-      if (!strncmp(setup_strings[x], key, strlen(key)))
+      if (!strncmp(setup_args[x], key, strlen(key)))
          break;
-      if (!strncmp(setup_strings[x], "next", strlen("next")))
+      if (!strncmp(setup_args[x], "next", strlen("next")))
          return 0;
       }
-   if (x == MAX_SETUP_STRINGS)
+   if (x == MAX_SETUP_ARGS)
       return 0;
    setup_used[x] = 1;
-   cp = setup_strings[x] + strlen(key);
+   cp = setup_args[x] + strlen(key);
    *val = -1;
    if (*cp != ':')
       return ++x;
@@ -1643,6 +1673,9 @@
 int val;
 char buf[32];
 
+   if (!done_setup && setup_strings)
+      wd33c93_setup(setup_strings,0);
+
    hostdata = (struct WD33C93_hostdata *)instance->hostdata;
 
    hostdata->regp = regs;
@@ -1688,26 +1721,29 @@
 #endif
 
 
-   if (check_setup_strings("nosync",&flags,&val,buf))
+   if (check_setup_args("nosync",&flags,&val,buf))
       hostdata->no_sync = val;
 
-   if (check_setup_strings("nodma",&flags,&val,buf))
+   if (check_setup_args("nodma",&flags,&val,buf))
       hostdata->no_dma = (val == -1) ? 1 : val;
 
-   if (check_setup_strings("period",&flags,&val,buf))
+   if (check_setup_args("period",&flags,&val,buf))
       hostdata->default_sx_per = sx_table[round_period((unsigned int)val)].period_ns;
 
-   if (check_setup_strings("disconnect",&flags,&val,buf)) {
+   if (check_setup_args("disconnect",&flags,&val,buf)) {
       if ((val >= DIS_NEVER) && (val <= DIS_ALWAYS))
          hostdata->disconnect = val;
       else
          hostdata->disconnect = DIS_ADAPTIVE;
       }
 
-   if (check_setup_strings("debug",&flags,&val,buf))
+   if (check_setup_args("level2",&flags,&val,buf))
+      hostdata->level2 = val;
+
+   if (check_setup_args("debug",&flags,&val,buf))
       hostdata->args = val & DB_MASK;
 
-   if (check_setup_strings("clock",&flags,&val,buf)) {
+   if (check_setup_args("clock",&flags,&val,buf)) {
       if (val>7 && val<11)
          val = WD33C93_FS_8_10;
       else if (val>11 && val<16)
@@ -1719,13 +1755,13 @@
       hostdata->clock_freq = val;
       }
 
-   if ((i = check_setup_strings("next",&flags,&val,buf))) {
+   if ((i = check_setup_args("next",&flags,&val,buf))) {
       while (i)
          setup_used[--i] = 1;
       }
 
 #ifdef PROC_INTERFACE
-   if (check_setup_strings("proc",&flags,&val,buf))
+   if (check_setup_args("proc",&flags,&val,buf))
       hostdata->proc = val;
 #endif
 
@@ -1744,9 +1780,9 @@
 #else
    printk(" debugging=OFF\n");
 #endif
-   printk("           setup_strings=");
-   for (i=0; i<MAX_SETUP_STRINGS; i++)
-      printk("%s,",setup_strings[i]);
+   printk("           setup_args=");
+   for (i=0; i<MAX_SETUP_ARGS; i++)
+      printk("%s,",setup_args[i]);
    printk("\n");
    printk("           Version %s - %s, Compiled %s at %s\n",
                WD33C93_VERSION,WD33C93_DATE,__DATE__,__TIME__);
@@ -1822,6 +1858,10 @@
          bp += 6;
          hd->no_dma = simple_strtoul(bp,NULL,0);
          }
+      else if (!strncmp(bp,"level2:",7)) {
+         bp += 7;
+         hd->level2 = simple_strtoul(bp,NULL,0);
+         }
       return len;
       }
 
@@ -1838,32 +1878,32 @@
       sprintf(tbuf,"\nclock_freq=%02x no_sync=%02x no_dma=%d",
             hd->clock_freq,hd->no_sync,hd->no_dma);
       strcat(bp,tbuf);
-      strcat(bp,"\nsync_xfer[] =");
-      for (x=0; x<8; x++) {
-         sprintf(tbuf," %02x",hd->sync_xfer[x]);
+      strcat(bp,"\nsync_xfer[] =       ");
+      for (x=0; x<7; x++) {
+         sprintf(tbuf,"\t%02x",hd->sync_xfer[x]);
          strcat(bp,tbuf);
          }
-      strcat(bp,"\nsync_stat[] =");
-      for (x=0; x<8; x++) {
-         sprintf(tbuf," %02x",hd->sync_stat[x]);
+      strcat(bp,"\nsync_stat[] =       ");
+      for (x=0; x<7; x++) {
+         sprintf(tbuf,"\t%02x",hd->sync_stat[x]);
          strcat(bp,tbuf);
          }
       }
 #ifdef PROC_STATISTICS
    if (hd->proc & PR_STATISTICS) {
       strcat(bp,"\ncommands issued:    ");
-      for (x=0; x<8; x++) {
-         sprintf(tbuf," %ld",hd->cmd_cnt[x]);
+      for (x=0; x<7; x++) {
+         sprintf(tbuf,"\t%ld",hd->cmd_cnt[x]);
          strcat(bp,tbuf);
          }
       strcat(bp,"\ndisconnects allowed:");
-      for (x=0; x<8; x++) {
-         sprintf(tbuf," %ld",hd->disc_allowed_cnt[x]);
+      for (x=0; x<7; x++) {
+         sprintf(tbuf,"\t%ld",hd->disc_allowed_cnt[x]);
          strcat(bp,tbuf);
          }
       strcat(bp,"\ndisconnects done:   ");
-      for (x=0; x<8; x++) {
-         sprintf(tbuf," %ld",hd->disc_done_cnt[x]);
+      for (x=0; x<7; x++) {
+         sprintf(tbuf,"\t%ld",hd->disc_done_cnt[x]);
          strcat(bp,tbuf);
          }
       sprintf(tbuf,"\ninterrupts: %ld, DATA_PHASE ints: %ld DMA, %ld PIO",
diff -u --recursive --new-file v2.1.44/linux/drivers/scsi/wd33c93.h linux/drivers/scsi/wd33c93.h
--- v2.1.44/linux/drivers/scsi/wd33c93.h	Wed Apr 23 19:01:22 1997
+++ linux/drivers/scsi/wd33c93.h	Wed Jul 16 19:22:51 1997
@@ -2,7 +2,7 @@
  *    wd33c93.h -  Linux device driver definitions for the
  *                 Commodore Amiga A2091/590 SCSI controller card
  *
- *    IMPORTANT: This file is for version 1.24 - 29/Jan/1997
+ *    IMPORTANT: This file is for version 1.25 - 09/Jul/1997
  *
  * Copyright (c) 1996 John Shifflett, GeoLog Consulting
  *    john@geolog.com
@@ -198,6 +198,8 @@
 typedef void (*dma_stop_t) (struct Scsi_Host *instance, Scsi_Cmnd *SCpnt,
              int status);
 
+
+#define ILLEGAL_STATUS_BYTE   0xff
 
 #define DEFAULT_SX_PER   376     /* (ns) fairly safe */
 #define DEFAULT_SX_OFF   0       /* aka async */
diff -u --recursive --new-file v2.1.44/linux/drivers/sound/Config.in linux/drivers/sound/Config.in
--- v2.1.44/linux/drivers/sound/Config.in	Wed May 28 10:51:32 1997
+++ linux/drivers/sound/Config.in	Wed Jul 16 19:22:51 1997
@@ -1,15 +1,277 @@
-#
-# Sound driver configuration
-#
-#--------
-# There is another confic script which is compatible with rest of
-# the kernel. It can be activated by running 'make mkscript' in this
-# directory. Please note that this is an _experimental_ feature which
-# doesn't work with all cards (PSS, SM Wave, AudioTriX Pro, Maui).
-#--------
-#
-$MAKE -C drivers/sound config || exit 1
+bool 'ProAudioSpectrum 16 support' CONFIG_PAS
+bool '100%% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support' CONFIG_SB
+bool 'Generic OPL2/OPL3 FM synthesizer support' CONFIG_ADLIB
+bool 'Gravis Ultrasound support' CONFIG_GUS
+bool 'MPU-401 support (NOT for SB16)' CONFIG_MPU401
+bool 'PSS (ECHO-ADI2111) support' CONFIG_PSS
+bool '16 bit sampling option of GUS (_NOT_ GUS MAX)' CONFIG_GUS16
+bool 'GUS MAX support' CONFIG_GUSMAX
+bool 'Microsoft Sound System support' CONFIG_MSS
+bool 'Ensoniq SoundScape support' CONFIG_SSCAPE
+bool 'MediaTrix AudioTrix Pro support' CONFIG_TRIX
+bool 'Support for MAD16 and/or Mozart based cards' CONFIG_MAD16
+bool 'Support for Crystal CS4232 based (PnP) cards' CONFIG_CS4232
+bool 'Support for Turtle Beach Wave Front (Maui, Tropez) synthesizers' CONFIG_MAUI
+bool 'FM synthesizer (YM3812/OPL-3) support' CONFIG_YM3812
+
+if [ "$CONFIG_AEDSP16" = "y" ]; then
+hex 'I/O base for Audio Excel DSP 16 220 or 240' AEDSP16_BASE 220
+fi
+
+if [ "$CONFIG_SB" = "y" ]; then
+hex 'I/O base for SB Check from manual of the card' SBC_BASE 220
+fi
+
+if [ "$CONFIG_SB" = "y" ]; then
+int 'Sound Blaster IRQ Check from manual of the card' SBC_IRQ 7
+fi
+
+if [ "$CONFIG_SB" = "y" ]; then
+int 'Sound Blaster DMA 0, 1 or 3' SBC_DMA 1
+fi
+
+if [ "$CONFIG_SB" = "y" ]; then
+int 'Sound Blaster 16 bit DMA (SB16, Jazz16, SMW) 5, 6 or 7 (use 1 for 8 bit cards)' SB_DMA2 5
+fi
+
+if [ "$CONFIG_SB" = "y" ]; then
+hex 'MPU401 I/O base of SB16, Jazz16 and ES1688 Check from manual of the card' SB_MPU_BASE 330
+fi
+
+
+if [ "$CONFIG_SB" = "y" ]; then
+comment 'MPU401 IRQ is only required with Jazz16, SM Wave and ESS1688.'
+fi
+
+
+if [ "$CONFIG_SB" = "y" ]; then
+comment 'Enter -1 to the following question if you have something else such as SB16/32.'
+fi
+
+if [ "$CONFIG_SB" = "y" ]; then
+int 'SB MPU401 IRQ (Jazz16, SM Wave and ES1688) Check from manual of the card' SB_MPU_IRQ -1
+fi
+
+if [ "$CONFIG_PAS" = "y" ]; then
+int 'PAS16 IRQ 3, 4, 5, 7, 9, 10, 11, 12, 14 or 15' PAS_IRQ 10
+fi
+
+if [ "$CONFIG_PAS" = "y" ]; then
+int 'PAS16 DMA 0, 1, 3, 5, 6 or 7' PAS_DMA 3
+fi
+
+if [ "$CONFIG_GUS" = "y" ]; then
+hex 'I/O base for GUS 210, 220, 230, 240, 250 or 260' GUS_BASE 220
+fi
+
+if [ "$CONFIG_GUS" = "y" ]; then
+int 'GUS IRQ 3, 5, 7, 9, 11, 12 or 15' GUS_IRQ 15
+fi
+
+if [ "$CONFIG_GUS" = "y" ]; then
+int 'GUS DMA 1, 3, 5, 6 or 7' GUS_DMA 6
+fi
+
+if [ "$CONFIG_GUS" = "y" ]; then
+int 'Second DMA channel for GUS 1, 3, 5, 6 or 7' GUS_DMA2 -1
+fi
+
+if [ "$CONFIG_GUS16" = "y" ]; then
+hex 'I/O base for the 16 bit daughtercard of GUS 530, 604, E80 or F40' GUS16_BASE 530
+fi
+
+if [ "$CONFIG_GUS16" = "y" ]; then
+int 'GUS 16 bit daughtercard IRQ 3, 4, 5, 7, or 9' GUS16_IRQ 7
+fi
+
+if [ "$CONFIG_GUS16" = "y" ]; then
+int 'GUS DMA 0, 1 or 3' GUS16_DMA 3
+fi
+
+if [ "$CONFIG_MPU401" = "y" ]; then
+hex 'I/O base for MPU401 Check from manual of the card' MPU_BASE 330
+fi
+
+if [ "$CONFIG_MPU401" = "y" ]; then
+int 'MPU401 IRQ Check from manual of the card' MPU_IRQ 9
+fi
+
+
+if [ "$CONFIG_MAUI" = "y" ]; then
+comment 'ERROR! You have to use old sound configuration method with Maui.'
+fi
+
+if [ "$CONFIG_MAUI" = "y" ]; then
+hex 'I/O base for Maui 210, 230, 260, 290, 300, 320, 338 or 330' MAUI_BASE 330
+fi
+
+if [ "$CONFIG_MAUI" = "y" ]; then
+int 'Maui IRQ 5, 9, 12 or 15' MAUI_IRQ 9
+fi
+
+if [ "$CONFIG_UART6850" = "y" ]; then
+hex 'I/O base for UART 6850 MIDI port (Unknown)' U6850_BASE 0
+fi
+
+if [ "$CONFIG_UART6850" = "y" ]; then
+int 'UART6850 IRQ (Unknown)' U6850_IRQ -1
+fi
+
+
+if [ "$CONFIG_PSS" = "y" ]; then
+comment 'ERROR! You have to use old sound configuration method with PSS cards.'
+fi
+
+if [ "$CONFIG_PSS" = "y" ]; then
+hex 'PSS I/O base 220 or 240' PSS_BASE 220
+fi
+
+if [ "$CONFIG_PSS" = "y" ]; then
+hex 'PSS audio I/O base 530, 604, E80 or F40' PSS_MSS_BASE 530
+fi
+
+if [ "$CONFIG_PSS" = "y" ]; then
+int 'PSS audio IRQ 7, 9, 10 or 11' PSS_MSS_IRQ 11
+fi
 
+if [ "$CONFIG_PSS" = "y" ]; then
+int 'PSS audio DMA 0, 1 or 3' PSS_MSS_DMA 3
+fi
+
+if [ "$CONFIG_PSS" = "y" ]; then
+hex 'PSS MIDI I/O base ' PSS_MPU_BASE 330
+fi
+
+if [ "$CONFIG_PSS" = "y" ]; then
+int 'PSS MIDI IRQ 3, 4, 5, 7 or 9' PSS_MPU_IRQ 9
+fi
+
+if [ "$CONFIG_MSS" = "y" ]; then
+hex 'MSS/WSS I/O base 530, 604, E80 or F40' MSS_BASE 530
+fi
+
+if [ "$CONFIG_MSS" = "y" ]; then
+int 'MSS/WSS IRQ 7, 9, 10 or 11' MSS_IRQ 11
+fi
+
+if [ "$CONFIG_MSS" = "y" ]; then
+int 'MSS/WSS DMA 0, 1 or 3' MSS_DMA 3
+fi
+
+if [ "$CONFIG_MSS" = "y" ]; then
+int 'MSS/WSS second DMA (if possible) 0, 1 or 3' MSS_DMA2 -1
+fi
+
+if [ "$CONFIG_SSCAPE" = "y" ]; then
+hex 'SoundScape MIDI I/O base 320, 330, 340 or 350' SSCAPE_BASE 330
+fi
+
+if [ "$CONFIG_SSCAPE" = "y" ]; then
+int 'SoundScape MIDI IRQ ' SSCAPE_IRQ 9
+fi
+
+if [ "$CONFIG_SSCAPE" = "y" ]; then
+int 'SoundScape initialization DMA 0, 1 or 3' SSCAPE_DMA 3
+fi
+
+if [ "$CONFIG_SSCAPE" = "y" ]; then
+hex 'SoundScape audio I/O base 534, 608, E84 or F44' SSCAPE_MSS_BASE 534
+fi
+
+if [ "$CONFIG_SSCAPE" = "y" ]; then
+int 'SoundScape audio IRQ 7, 9, 10 or 11' SSCAPE_MSS_IRQ 11
+fi
+
+
+if [ "$CONFIG_TRIX" = "y" ]; then
+comment 'ERROR! You have to use old sound configuration method with AudioTrix.'
+fi
+
+if [ "$CONFIG_TRIX" = "y" ]; then
+hex 'AudioTrix audio I/O base 530, 604, E80 or F40' TRIX_BASE 530
+fi
+
+if [ "$CONFIG_TRIX" = "y" ]; then
+int 'AudioTrix audio IRQ 7, 9, 10 or 11' TRIX_IRQ 11
+fi
+
+if [ "$CONFIG_TRIX" = "y" ]; then
+int 'AudioTrix audio DMA 0, 1 or 3' TRIX_DMA 0
+fi
+
+if [ "$CONFIG_TRIX" = "y" ]; then
+int 'AudioTrix second (duplex) DMA 0, 1 or 3' TRIX_DMA2 3
+fi
+
+if [ "$CONFIG_TRIX" = "y" ]; then
+hex 'AudioTrix MIDI I/O base 330, 370, 3B0 or 3F0' TRIX_MPU_BASE 330
+fi
+
+if [ "$CONFIG_TRIX" = "y" ]; then
+int 'AudioTrix MIDI IRQ 3, 4, 5, 7 or 9' TRIX_MPU_IRQ 9
+fi
+
+if [ "$CONFIG_TRIX" = "y" ]; then
+hex 'AudioTrix SB I/O base 220, 210, 230, 240, 250, 260 or 270' TRIX_SB_BASE 220
+fi
+
+if [ "$CONFIG_TRIX" = "y" ]; then
+int 'AudioTrix SB IRQ 3, 4, 5 or 7' TRIX_SB_IRQ 7
+fi
+
+if [ "$CONFIG_TRIX" = "y" ]; then
+int 'AudioTrix SB DMA 1 or 3' TRIX_SB_DMA 1
+fi
+
+if [ "$CONFIG_CS4232" = "y" ]; then
+hex 'CS4232 audio I/O base 530, 604, E80 or F40' CS4232_BASE 530
+fi
+
+if [ "$CONFIG_CS4232" = "y" ]; then
+int 'CS4232 audio IRQ 5, 7, 9, 11, 12 or 15' CS4232_IRQ 11
+fi
+
+if [ "$CONFIG_CS4232" = "y" ]; then
+int 'CS4232 audio DMA 0, 1 or 3' CS4232_DMA 0
+fi
+
+if [ "$CONFIG_CS4232" = "y" ]; then
+int 'CS4232 second (duplex) DMA 0, 1 or 3' CS4232_DMA2 3
+fi
+
+if [ "$CONFIG_CS4232" = "y" ]; then
+hex 'CS4232 MIDI I/O base 330, 370, 3B0 or 3F0' CS4232_MPU_BASE 330
+fi
+
+if [ "$CONFIG_CS4232" = "y" ]; then
+int 'CS4232 MIDI IRQ 5, 7, 9, 11, 12 or 15' CS4232_MPU_IRQ 9
+fi
+
+if [ "$CONFIG_MAD16" = "y" ]; then
+hex 'MAD16 audio I/O base 530, 604, E80 or F40' MAD16_BASE 530
+fi
+
+if [ "$CONFIG_MAD16" = "y" ]; then
+int 'MAD16 audio IRQ 7, 9, 10 or 11' MAD16_IRQ 11
+fi
+
+if [ "$CONFIG_MAD16" = "y" ]; then
+int 'MAD16 audio DMA 0, 1 or 3' MAD16_DMA 3
+fi
+
+if [ "$CONFIG_MAD16" = "y" ]; then
+int 'MAD16 second (duplex) DMA 0, 1 or 3' MAD16_DMA2 0
+fi
+
+if [ "$CONFIG_MAD16" = "y" ]; then
+hex 'MAD16 MIDI I/O base 300, 310, 320 or 330 (0 disables)' MAD16_MPU_BASE 330
+fi
+
+if [ "$CONFIG_MAD16" = "y" ]; then
+int 'MAD16 MIDI IRQ 5, 7, 9 or 10' MAD16_MPU_IRQ 9
+fi
+#
+$MAKE -C drivers/sound kernelconfig || exit 1
 bool 'Additional low level drivers' CONFIG_LOWLEVEL_SOUND
 
 if [ "$CONFIG_LOWLEVEL_SOUND" = "y" ]; then
diff -u --recursive --new-file v2.1.44/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c
--- v2.1.44/linux/drivers/sound/soundcard.c	Mon Jun 16 16:35:56 1997
+++ linux/drivers/sound/soundcard.c	Mon Jul 14 10:37:05 1997
@@ -246,7 +246,7 @@
   struct inode   *inode;
   int             ret = 0;
 
-  inode = file->f_inode;
+  inode = file->f_dentry->d_inode;
 
   if (sound_select (inode, file, SEL_IN, wait))
     ret |= POLLIN;
@@ -326,8 +326,7 @@
 			vma->vm_page_prot))
     return -EAGAIN;
 
-  vma->vm_inode = inode;
-  atomic_inc(&inode->i_count);
+  vma->vm_dentry = dget(file->f_dentry);
 
   dmap->mapping_flags |= DMA_MAP_MAPPED;
 
diff -u --recursive --new-file v2.1.44/linux/fs/Config.in linux/fs/Config.in
--- v2.1.44/linux/fs/Config.in	Mon Jun 16 16:35:56 1997
+++ linux/fs/Config.in	Thu Jul 10 16:10:15 1997
@@ -5,26 +5,6 @@
 comment 'Filesystems'
 
 bool	 'Quota support' CONFIG_QUOTA
-bool     'Preload dcache entries in readdir() [ALPHA, currently dangerous!]' CONFIG_DCACHE_PRELOAD
-bool     'Include support for omirr online mirror' CONFIG_OMIRR
-bool     'Translate filename suffixes' CONFIG_TRANS_NAMES
-if [ "$CONFIG_TRANS_NAMES" = "y" ]; then
-  bool '  Restrict translation to specific gid' CONFIG_TRANS_RESTRICT
-  if [ "$CONFIG_TRANS_RESTRICT" = "y" ]; then
-    int '    Enter gid to compile in' CONFIG_TRANS_GID 4
-  fi
-  bool '  Translate nodename' CONFIG_TR_NODENAME
-  bool '  Translate compiled-in kernelname' CONFIG_TR_KERNNAME
-  if [ "$CONFIG_TR_KERNNAME" = "y" ]; then
-    string '    Enter kernelname string to compile in' CONFIG_KERNNAME banana
-  fi
-  bool '  Translate compiled-in kerneltype' CONFIG_TR_KERNTYPE
-  if [ "$CONFIG_TR_KERNTYPE" = "y" ]; then
-    string '    Enter kerneltype string to compile in' CONFIG_KERNTYPE default
-  fi
-  bool '  Translate machine type' CONFIG_TR_MACHINE
-  bool '  Translate sysname' CONFIG_TR_SYSNAME
-fi
 
 tristate 'Minix fs support' CONFIG_MINIX_FS
 tristate 'Second extended fs support' CONFIG_EXT2_FS
diff -u --recursive --new-file v2.1.44/linux/fs/affs/Changes linux/fs/affs/Changes
--- v2.1.44/linux/fs/affs/Changes	Tue May 13 22:41:13 1997
+++ linux/fs/affs/Changes	Wed Jul 16 19:22:51 1997
@@ -13,11 +13,25 @@
   reads basically work (but all files are of size 0).
   Alas, I've got no alpha to debug. :-(
 - If an affs mounted filesystem is exported via
-  nfs, it cannot be written to. No networking to
-  test that, either. :-(
+  nfs, it cannot be written to. 
+  As soon as I have my network up and running, I'll
+  try to fix this.
+- The partition checker (drivers/block/genhd.c)
+  doesn't work with devices which have 256 byte
+  blocks (some very old SCSI drives). 
 
 Please direct bug reports to: hjw@zvw.de
 
+Version 3.5
+-----------
+
+- Extension block caches are now allocated on
+  demand instead of when a file is opened, as
+  files can be read and written without opening
+  them (e. g. the loopback device does this).
+
+- Removed an unused function.
+
 Version 3.4
 -----------
 
@@ -80,7 +94,7 @@
   interface in Linux 1.3.
 - Write support.
 - Support for hard and symbolic links.
-- Lots of things I remeber even less ...
+- Lots of things I remember even less ...
 
 Version 2.0
 -----------
diff -u --recursive --new-file v2.1.44/linux/fs/affs/amigaffs.c linux/fs/affs/amigaffs.c
--- v2.1.44/linux/fs/affs/amigaffs.c	Tue May 13 22:41:13 1997
+++ linux/fs/affs/amigaffs.c	Wed Jul 16 19:22:51 1997
@@ -26,27 +26,6 @@
  *
  */
 
-/* Find the next used hash entry at or after *HASH_POS in a directory's hash
-   table.  *HASH_POS is assigned that entry's number.  DIR_DATA points to
-   the directory header block in memory.  If there are no more entries,
-   0 is returned.  Otherwise, the key number in the next used hash slot
-   is returned. */
-
-static int
-affs_find_next_hash_entry(int hsize, void *dir_data, int *hash_pos)
-{
-	struct dir_front *dir_front = dir_data;
-	int i;
-
-	for (i = *hash_pos; i < hsize; i++)
-		if (dir_front->hashtable[i] != 0)
-			break;
-	if (i >= hsize)
-		return 0;
-	*hash_pos = i;
-	return htonl(dir_front->hashtable[i]);
-}
-
 /* Set *NAME to point to the file name in a file header block in memory
    pointed to by FH_DATA.  The length of the name is returned. */
 
diff -u --recursive --new-file v2.1.44/linux/fs/affs/file.c linux/fs/affs/file.c
--- v2.1.44/linux/fs/affs/file.c	Mon Jun 16 16:35:56 1997
+++ linux/fs/affs/file.c	Wed Jul 16 19:22:51 1997
@@ -43,8 +43,8 @@
 			    unsigned long count);
 static long affs_file_write_ofs(struct inode *inode, struct file *filp, const char *buf,
 				unsigned long count);
-static int affs_open_file(struct inode *inode, struct file *filp);
 static int affs_release_file(struct inode *inode, struct file *filp);
+static int alloc_ext_cache(struct inode *inode);
 
 static struct file_operations affs_file_operations = {
 	NULL,			/* lseek - default */
@@ -54,7 +54,7 @@
 	NULL,			/* poll - default */
 	NULL,			/* ioctl - default */
 	generic_file_mmap,	/* mmap */
-	affs_open_file,		/* special open is needed */
+	NULL,			/* no special open */
 	affs_release_file,	/* release */
 	file_fsync		/* brute force, but works */
 };
@@ -87,7 +87,7 @@
 	NULL,			/* poll - default */
 	NULL,			/* ioctl - default */
 	NULL,			/* mmap */
-	affs_open_file,		/* special open is needed */
+	NULL,			/* no special open */
 	affs_release_file,	/* release */
 	file_fsync		/* brute force, but works */
 };
@@ -248,9 +248,9 @@
 		return 0;
 	}
 	if (!inode->u.affs_i.i_ec) {
-		affs_error(inode->i_sb,"bmap","No extension cache for open file (inode=%lu)",
-			inode->i_ino);
-		return 0;
+		if (alloc_ext_cache(inode)) {
+			return 0;
+		}
 	}
 
 	/* Try to find the requested key in the cache.
@@ -582,6 +582,12 @@
 		iput(inode);
 		return -EINVAL;
 	}
+	if (!inode->u.affs_i.i_ec) {
+		if (alloc_ext_cache(inode)) {
+			iput(inode);
+			return -ENOMEM;
+		}
+	}
 	if (filp->f_flags & O_APPEND) {
 		pos = inode->i_size;
 	} else
@@ -861,40 +867,6 @@
 }
 
 static int
-affs_open_file(struct inode *inode, struct file *filp)
-{
-	int	 error;
-	u32	 key;
-	int	 i;
-
-	pr_debug("AFFS: open_file(ino=%lu)\n",inode->i_ino);
-
-	error = 0;
-	inode->u.affs_i.i_cache_users++;
-	lock_super(inode->i_sb);
-	if (!inode->u.affs_i.i_ec) {
-		inode->u.affs_i.i_ec = (struct ext_cache *)get_free_page(GFP_KERNEL);
-		if (!inode->u.affs_i.i_ec) {
-			affs_error(inode->i_sb,"open_file","Cache allocation failed");
-			error = ENOMEM;
-		} else {
-			/* We only have to initialize non-zero values.
-			 * get_free_page() zeroed the page already.
-			 */
-			key = inode->u.affs_i.i_original ? inode->u.affs_i.i_original : inode->i_ino;
-			inode->u.affs_i.i_ec->ec[0] = key;
-			for (i = 0; i < 4; i++) {
-				inode->u.affs_i.i_ec->kc[i].kc_this_key = key;
-				inode->u.affs_i.i_ec->kc[i].kc_last     = -1;
-			}
-		}
-	}
-	unlock_super(inode->i_sb);
-
-	return error;
-}
-
-static int
 affs_release_file(struct inode *inode, struct file *filp)
 {
 	struct affs_zone	*zone;
@@ -916,13 +888,35 @@
 			unlock_super(inode->i_sb);
 		}
 	}
+	return 0;
+}
+
+static int
+alloc_ext_cache(struct inode *inode)
+{
+	s32	 key;
+	int	 i;
+
 	lock_super(inode->i_sb);
-	if (--inode->u.affs_i.i_cache_users == 0) {
+	if (!inode->u.affs_i.i_ec) {
+		inode->u.affs_i.i_ec = (struct ext_cache *)get_free_page(GFP_KERNEL);
 		if (inode->u.affs_i.i_ec) {
-			free_page((unsigned long)inode->u.affs_i.i_ec);
-			inode->u.affs_i.i_ec = NULL;
+			/* We only have to initialize non-zero values.
+			 * get_free_page() zeroed the page already.
+			 */
+			key = inode->u.affs_i.i_original ? inode->u.affs_i.i_original : inode->i_ino;
+			inode->u.affs_i.i_ec->ec[0] = key;
+			for (i = 0; i < 4; i++) {
+				inode->u.affs_i.i_ec->kc[i].kc_this_key = key;
+				inode->u.affs_i.i_ec->kc[i].kc_last     = -1;
+			}
 		}
 	}
 	unlock_super(inode->i_sb);
+
+	if (!inode->u.affs_i.i_ec) {
+		affs_error(inode->i_sb,"alloc_ext_cache","Cache allocation failed");
+		return -ENOMEM;
+	}
 	return 0;
 }
diff -u --recursive --new-file v2.1.44/linux/fs/affs/inode.c linux/fs/affs/inode.c
--- v2.1.44/linux/fs/affs/inode.c	Mon Jun 16 16:35:56 1997
+++ linux/fs/affs/inode.c	Wed Jul 16 19:22:51 1997
@@ -691,7 +691,6 @@
 	inode->u.affs_i.i_pa_next      = 0;
 	inode->u.affs_i.i_pa_last      = 0;
 	inode->u.affs_i.i_ec           = NULL;
-	inode->u.affs_i.i_cache_users  = 0;
 	inode->u.affs_i.i_lastblock    = -1;
 	inode->i_nlink                 = 1;
 	inode->i_mode                  = 0;
@@ -870,6 +869,12 @@
 affs_put_inode(struct inode *inode)
 {
 	pr_debug("AFFS: put_inode(ino=%lu, nlink=%u)\n",inode->i_ino,inode->i_nlink);
+	lock_super(inode->i_sb);
+	if (inode->u.affs_i.i_ec) {
+		free_page((unsigned long)inode->u.affs_i.i_ec);
+		inode->u.affs_i.i_ec = NULL;
+	}
+	unlock_super(inode->i_sb);
 	if (inode->i_nlink) {
 		return;
 	}
@@ -899,7 +904,7 @@
 		return NULL;
 	}
 
-	atomic_set(&inode->i_count, 1);
+	inode->i_count   = 1;
 	inode->i_nlink   = 1;
 	inode->i_dev     = sb->s_dev;
 	inode->i_uid     = current->fsuid;
@@ -921,7 +926,6 @@
 	inode->u.affs_i.i_pa_next      = 0;
 	inode->u.affs_i.i_pa_last      = 0;
 	inode->u.affs_i.i_ec           = NULL;
-	inode->u.affs_i.i_cache_users  = 0;
 	inode->u.affs_i.i_lastblock    = -1;
 
 	insert_inode_hash(inode);
diff -u --recursive --new-file v2.1.44/linux/fs/affs/namei.c linux/fs/affs/namei.c
--- v2.1.44/linux/fs/affs/namei.c	Thu Jul  3 17:30:26 1997
+++ linux/fs/affs/namei.c	Wed Jul 16 19:22:51 1997
@@ -343,7 +343,7 @@
 		retval = -ENOTEMPTY;
 		goto rmdir_done;
 	}
-	if (atomic_read(&inode->i_count) > 1) {
+	if (inode->i_count > 1) {
 		retval = -EBUSY;
 		goto rmdir_done;
 	}
@@ -512,7 +512,7 @@
     int ino;
     int result;
 
-    atomic_inc(&new_inode->i_count);
+    new_inode->i_count++;
     result = 0;
     for (;;) {
         if (new_inode == old_inode) {
@@ -566,12 +566,12 @@
 	old_bh = affs_find_entry(old_dir,old_name,old_len,&old_ino);
 	if (!old_bh)
 		goto end_rename;
-	old_inode = __iget(old_dir->i_sb,old_ino);
+	old_inode = iget(old_dir->i_sb,old_ino);
 	if (!old_inode)
 		goto end_rename;
 	new_bh = affs_find_entry(new_dir,new_name,new_len,&new_ino);
 	if (new_bh) {
-		new_inode = __iget(new_dir->i_sb,new_ino);
+		new_inode = iget(new_dir->i_sb,new_ino);
 		if (!new_inode) {		/* What does this mean? */
 			affs_brelse(new_bh);
 			new_bh = NULL;
@@ -592,7 +592,7 @@
 		if (!empty_dir(new_bh,AFFS_I2HSIZE(new_inode)))
 			goto end_rename;
 		retval = -EBUSY;
-		if (atomic_read(&new_inode->i_count) > 1)
+		if (new_inode->i_count > 1)
 			goto end_rename;
 	}
 	if (S_ISDIR(old_inode->i_mode)) {
diff -u --recursive --new-file v2.1.44/linux/fs/attr.c linux/fs/attr.c
--- v2.1.44/linux/fs/attr.c	Mon Jun 16 16:35:56 1997
+++ linux/fs/attr.c	Tue Jul  8 14:36:15 1997
@@ -74,7 +74,7 @@
 			if (!fsuser() && !in_group_p(inode->i_gid))
 				inode->i_mode &= ~S_ISGID;
 		}
-		inode->i_dirt = 1;
+		mark_inode_dirty(inode);
 	}
 }
 
diff -u --recursive --new-file v2.1.44/linux/fs/autofs/dir.c linux/fs/autofs/dir.c
--- v2.1.44/linux/fs/autofs/dir.c	Mon Jul  7 12:45:24 1997
+++ linux/fs/autofs/dir.c	Wed Jul 16 15:10:58 1997
@@ -37,9 +37,10 @@
 /*
  * No entries except for "." and "..", both of which are handled by the VFS layer
  */
-static int autofs_dir_lookup(struct inode *dir, struct qstr *str, struct inode **result)
+static int autofs_dir_lookup(struct inode *dir, struct dentry * dentry)
 {
-	return -ENOENT;		/* No other entries */
+	d_add(dentry, NULL);
+	return 0;
 }
 
 static struct file_operations autofs_dir_operations = {
diff -u --recursive --new-file v2.1.44/linux/fs/autofs/inode.c linux/fs/autofs/inode.c
--- v2.1.44/linux/fs/autofs/inode.c	Mon Jul  7 11:10:13 1997
+++ linux/fs/autofs/inode.c	Wed Jul 16 13:01:34 1997
@@ -19,11 +19,17 @@
 #define __NO_VERSION__
 #include <linux/module.h>
 
+/*
+ * Dummy functions - do we ever actually want to do
+ * something here?
+ */
 static void autofs_put_inode(struct inode *inode)
 {
-        if (inode->i_nlink)
-                return;
-        inode->i_size = 0;
+}
+
+static void autofs_delete_inode(struct inode *inode)
+{
+	inode->i_size = 0;
 }
 
 static void autofs_put_super(struct super_block *sb)
@@ -35,16 +41,16 @@
 	if ( !sbi->catatonic )
 		autofs_catatonic_mode(sbi); /* Free wait queues, close pipe */
 
-        lock_super(sb);
+	lock_super(sb);
 	autofs_hash_nuke(&sbi->dirhash);
 	for ( n = 0 ; n < AUTOFS_MAX_SYMLINKS ; n++ ) {
 		if ( test_bit(n, sbi->symlink_bitmap) )
 			kfree(sbi->symlink[n].data);
 	}
 
-        sb->s_dev = 0;
+	sb->s_dev = 0;
 	kfree(sb->u.generic_sbp);
-        unlock_super(sb);
+	unlock_super(sb);
 
 	DPRINTK(("autofs: shutting down\n"));
 	
@@ -53,95 +59,96 @@
 #endif
 }
 
-static void autofs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz);
+static int autofs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz);
 static void autofs_read_inode(struct inode *inode);
 static void autofs_write_inode(struct inode *inode);
 
 static struct super_operations autofs_sops = {
-        autofs_read_inode,
-        NULL,
-        autofs_write_inode,
-        autofs_put_inode,
-        autofs_put_super,
-        NULL,
-        autofs_statfs,
-        NULL
+	autofs_read_inode,
+	autofs_write_inode,
+	autofs_put_inode,
+	autofs_delete_inode,
+	NULL,			/* notify_change */
+	autofs_put_super,
+	NULL,			/* write_super */
+	autofs_statfs,
+	NULL
 };
 
 static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid, pid_t *pgrp, int *minproto, int *maxproto)
 {
-        char *this_char, *value;
-        
-        *uid = current->uid;
-        *gid = current->gid;
+	char *this_char, *value;
+	
+	*uid = current->uid;
+	*gid = current->gid;
 	*pgrp = current->pgrp;
 
 	*minproto = *maxproto = AUTOFS_PROTO_VERSION;
 
-        *pipefd = -1;
+	*pipefd = -1;
 
-        if ( !options ) return 1;
-        for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) {
-                if ((value = strchr(this_char,'=')) != NULL)
-                        *value++ = 0;
-                if (!strcmp(this_char,"fd")) {
-                        if (!value || !*value)
-                                return 1;
-                        *pipefd = simple_strtoul(value,&value,0);
-                        if (*value)
-                                return 1;
-                }
-                else if (!strcmp(this_char,"uid")) {
-                        if (!value || !*value)
-                                return 1;
-                        *uid = simple_strtoul(value,&value,0);
-                        if (*value)
-                                return 1;
-                }
-                else if (!strcmp(this_char,"gid")) {
-                        if (!value || !*value)
-                                return 1;
-                        *gid = simple_strtoul(value,&value,0);
-                        if (*value)
-                                return 1;
-                }
-                else if (!strcmp(this_char,"pgrp")) {
-                        if (!value || !*value)
-                                return 1;
-                        *pgrp = simple_strtoul(value,&value,0);
-                        if (*value)
-                                return 1;
-                }
-                else if (!strcmp(this_char,"minproto")) {
-                        if (!value || !*value)
-                                return 1;
-                        *minproto = simple_strtoul(value,&value,0);
-                        if (*value)
-                                return 1;
-                }
-                else if (!strcmp(this_char,"maxproto")) {
-                        if (!value || !*value)
-                                return 1;
-                        *maxproto = simple_strtoul(value,&value,0);
-                        if (*value)
-                                return 1;
-                }
-                else break;
-        }
-        return (*pipefd < 0);
+	if ( !options ) return 1;
+	for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) {
+		if ((value = strchr(this_char,'=')) != NULL)
+			*value++ = 0;
+		if (!strcmp(this_char,"fd")) {
+			if (!value || !*value)
+				return 1;
+			*pipefd = simple_strtoul(value,&value,0);
+			if (*value)
+				return 1;
+		}
+		else if (!strcmp(this_char,"uid")) {
+			if (!value || !*value)
+				return 1;
+			*uid = simple_strtoul(value,&value,0);
+			if (*value)
+				return 1;
+		}
+		else if (!strcmp(this_char,"gid")) {
+			if (!value || !*value)
+				return 1;
+			*gid = simple_strtoul(value,&value,0);
+			if (*value)
+				return 1;
+		}
+		else if (!strcmp(this_char,"pgrp")) {
+			if (!value || !*value)
+				return 1;
+			*pgrp = simple_strtoul(value,&value,0);
+			if (*value)
+				return 1;
+		}
+		else if (!strcmp(this_char,"minproto")) {
+			if (!value || !*value)
+				return 1;
+			*minproto = simple_strtoul(value,&value,0);
+			if (*value)
+				return 1;
+		}
+		else if (!strcmp(this_char,"maxproto")) {
+			if (!value || !*value)
+				return 1;
+			*maxproto = simple_strtoul(value,&value,0);
+			if (*value)
+				return 1;
+		}
+		else break;
+	}
+	return (*pipefd < 0);
 }
 
 struct super_block *autofs_read_super(struct super_block *s, void *data,
-                                      int silent)
+				      int silent)
 {
-        int pipefd;
+	int pipefd;
 	struct autofs_sb_info *sbi;
 	int minproto, maxproto;
 
 	MOD_INC_USE_COUNT;
 
-        lock_super(s);
-        sbi = (struct autofs_sb_info *) kmalloc(sizeof(struct autofs_sb_info), GFP_KERNEL);
+	lock_super(s);
+	sbi = (struct autofs_sb_info *) kmalloc(sizeof(struct autofs_sb_info), GFP_KERNEL);
 	if ( !sbi ) {
 		s->s_dev = 0;
 		MOD_DEC_USE_COUNT;
@@ -158,31 +165,31 @@
 	sbi->queues = NULL;
 	memset(sbi->symlink_bitmap, 0, sizeof(u32)*AUTOFS_SYMLINK_BITMAP_LEN);
 	sbi->next_dir_ino = AUTOFS_FIRST_DIR_INO;
-        s->s_blocksize = 1024;
-        s->s_blocksize_bits = 10;
-        s->s_magic = AUTOFS_SUPER_MAGIC;
-        s->s_op = &autofs_sops;
-        unlock_super(s);
-        s->s_root = d_alloc_root(iget(s, AUTOFS_ROOT_INO), NULL);
-        if (!s->s_root) {
-                s->s_dev = 0;
+	s->s_blocksize = 1024;
+	s->s_blocksize_bits = 10;
+	s->s_magic = AUTOFS_SUPER_MAGIC;
+	s->s_op = &autofs_sops;
+	unlock_super(s);
+	s->s_root = d_alloc_root(iget(s, AUTOFS_ROOT_INO), NULL);
+	if (!s->s_root) {
+		s->s_dev = 0;
 		kfree(sbi);
-                printk("autofs: get root inode failed\n");
+		printk("autofs: get root inode failed\n");
 		MOD_DEC_USE_COUNT;
-                return NULL;
-        }
+		return NULL;
+	}
 
-        if ( parse_options(data,&pipefd,&s->s_root->d_inode->i_uid,&s->s_root->d_inode->i_gid,&sbi->oz_pgrp,&minproto,&maxproto) ) {
-        	d_delete(s->s_root);
-                s->s_dev = 0;
+	if ( parse_options(data,&pipefd,&s->s_root->d_inode->i_uid,&s->s_root->d_inode->i_gid,&sbi->oz_pgrp,&minproto,&maxproto) ) {
+		dput(s->s_root);
+		s->s_dev = 0;
 		kfree(sbi);
-                printk("autofs: called with bogus options\n");
+		printk("autofs: called with bogus options\n");
 		MOD_DEC_USE_COUNT;
-                return NULL;
-        }
+		return NULL;
+	}
 
 	if ( minproto > AUTOFS_PROTO_VERSION || maxproto < AUTOFS_PROTO_VERSION ) {
-		d_delete(s->s_root);
+		dput(s->s_root);
 		s->s_dev = 0;
 		kfree(sbi);
 		printk("autofs: kernel does not match daemon version\n");
@@ -194,60 +201,60 @@
 	sbi->pipe = fget(pipefd);
 	if ( !sbi->pipe || !sbi->pipe->f_op || !sbi->pipe->f_op->write ) {
 		if ( sbi->pipe ) {
-			fput(sbi->pipe, sbi->pipe->f_inode);
+			fput(sbi->pipe);
 			printk("autofs: pipe file descriptor does not contain proper ops\n");
 		} else {
 			printk("autofs: could not open pipe file descriptor\n");
 		}
-		d_delete(s->s_root);
+		dput(s->s_root);
 		s->s_dev = 0;
 		kfree(sbi);
 		MOD_DEC_USE_COUNT;
 		return NULL;
 	}
-        return s;
+	return s;
 }
 
-static void autofs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+static int autofs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
 {
-        struct statfs tmp;
+	struct statfs tmp;
 
-        tmp.f_type = AUTOFS_SUPER_MAGIC;
-        tmp.f_bsize = 1024;
-        tmp.f_blocks = 0;
-        tmp.f_bfree = 0;
-        tmp.f_bavail = 0;
-        tmp.f_files = 0;
-        tmp.f_ffree = 0;
-        tmp.f_namelen = NAME_MAX;
-        copy_to_user(buf, &tmp, bufsiz);
+	tmp.f_type = AUTOFS_SUPER_MAGIC;
+	tmp.f_bsize = 1024;
+	tmp.f_blocks = 0;
+	tmp.f_bfree = 0;
+	tmp.f_bavail = 0;
+	tmp.f_files = 0;
+	tmp.f_ffree = 0;
+	tmp.f_namelen = NAME_MAX;
+	return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
 }
 
 static void autofs_read_inode(struct inode *inode)
 {
-        ino_t ino = inode->i_ino;
+	ino_t ino = inode->i_ino;
 	unsigned int n;
-        struct autofs_sb_info *sbi =
+	struct autofs_sb_info *sbi =
 		(struct autofs_sb_info *) inode->i_sb->u.generic_sbp;
 
-        inode->i_op = NULL;
-        inode->i_mode = 0;
-        inode->i_nlink = 2;
-        inode->i_size = 0;
-        inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
-        inode->i_blocks = 0;
-        inode->i_blksize = 1024;
-
-        if ( ino == AUTOFS_ROOT_INO ) {
-                inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR;
-                inode->i_op = &autofs_root_inode_operations;
+	inode->i_op = NULL;
+	inode->i_mode = 0;
+	inode->i_nlink = 2;
+	inode->i_size = 0;
+	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+	inode->i_blocks = 0;
+	inode->i_blksize = 1024;
+
+	if ( ino == AUTOFS_ROOT_INO ) {
+		inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR;
+		inode->i_op = &autofs_root_inode_operations;
 		inode->i_uid = inode->i_gid = 0; /* Changed in read_super */
-                return;
-        } 
+		return;
+	} 
+	
+	inode->i_uid = inode->i_sb->s_root->d_inode->i_uid;
+	inode->i_gid = inode->i_sb->s_root->d_inode->i_gid;
 	
-        inode->i_uid = inode->i_sb->s_root->d_inode->i_uid;
-        inode->i_gid = inode->i_sb->s_root->d_inode->i_gid;
-        
 	if ( ino >= AUTOFS_FIRST_SYMLINK && ino < AUTOFS_FIRST_DIR_INO ) {
 		/* Symlink inode - should be in symlink list */
 		struct autofs_symlink *sl;
@@ -274,5 +281,4 @@
 
 static void autofs_write_inode(struct inode *inode)
 {
-        inode->i_dirt = 0;
 }
diff -u --recursive --new-file v2.1.44/linux/fs/autofs/root.c linux/fs/autofs/root.c
--- v2.1.44/linux/fs/autofs/root.c	Mon Jul  7 13:55:00 1997
+++ linux/fs/autofs/root.c	Wed Jul 16 15:28:09 1997
@@ -16,7 +16,7 @@
 #include "autofs_i.h"
 
 static int autofs_root_readdir(struct inode *,struct file *,void *,filldir_t);
-static int autofs_root_lookup(struct inode *,struct qstr *,struct inode **);
+static int autofs_root_lookup(struct inode *,struct dentry *);
 static int autofs_root_symlink(struct inode *,struct dentry *,const char *);
 static int autofs_root_unlink(struct inode *,struct dentry *);
 static int autofs_root_rmdir(struct inode *,struct dentry *);
@@ -93,63 +93,105 @@
 	return 0;
 }
 
-static int autofs_root_lookup(struct inode *dir, struct qstr *str, struct inode **result)
+static int try_to_fill_dentry(struct dentry * dentry, struct super_block * sb, struct autofs_sb_info *sbi)
 {
-	struct autofs_sb_info *sbi;
+	struct inode * inode;
 	struct autofs_dir_ent *ent;
+	
+	while (!(ent = autofs_hash_lookup(&sbi->dirhash, &dentry->d_name))) {
+		int status = autofs_wait(sbi, &dentry->d_name);
+
+		/* Turn this into a real negative dentry? */
+		if (status == -ENOENT) {
+			dentry->d_flags = 0;
+			return 0;
+		}
+		if (status)
+			return status;
+	}
+
+	if (!dentry->d_inode) {
+		inode = iget(sb, ent->ino);
+		if (!inode)
+			return -EACCES;
+
+		dentry->d_inode = inode;
+	}
+
+	if (S_ISDIR(dentry->d_inode->i_mode)) {
+		while (dentry == dentry->d_mounts)
+			schedule();
+	}
+	dentry->d_flags = 0;
+	return 0;
+}
+
+
+/*
+ * Revalidate is called on every cache lookup.  Some of those
+ * cache lookups may actually happen while the dentry is not
+ * yet completely filled in, and revalidate has to delay such
+ * lookups..
+ */
+static struct dentry * autofs_revalidate(struct dentry * dentry)
+{
+	struct autofs_sb_info *sbi;
+	struct inode * dir = dentry->d_parent->d_inode;
+
+	sbi = (struct autofs_sb_info *) dir->i_sb->u.generic_sbp;
+
+	/* Incomplete dentry? */
+	if (dentry->d_flags) {
+		if (autofs_oz_mode(sbi))
+			return dentry;
+
+		try_to_fill_dentry(dentry, dir->i_sb, sbi);
+		return dentry;
+	}
+
+	/* Negative dentry.. Should we time these out? */
+	if (!dentry->d_inode)
+		return dentry;
+
+	/* We should update the usage stuff here.. */
+	return dentry;
+}
+
+static int autofs_root_lookup(struct inode *dir, struct dentry * dentry)
+{
+	struct autofs_sb_info *sbi;
 	struct inode *res;
-	int status, oz_mode;
+	int oz_mode;
 
 	DPRINTK(("autofs_root_lookup: name = "));
-	autofs_say(str->name,str->len);
+	autofs_say(dentry->d_name.name,dentry->d_name.len);
 
-	*result = NULL;
-	if (!dir)
-		return -ENOENT;
 	if (!S_ISDIR(dir->i_mode))
 		return -ENOTDIR;
 
-	*result = res = NULL;
+	res = NULL;
 	sbi = (struct autofs_sb_info *) dir->i_sb->u.generic_sbp;
 
 	oz_mode = autofs_oz_mode(sbi);
 	DPRINTK(("autofs_lookup: pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d\n", current->pid, current->pgrp, sbi->catatonic, oz_mode));
 
-	do {
-		while ( !(ent = autofs_hash_lookup(&sbi->dirhash,str)) ) {
-			DPRINTK(("lookup failed, pid = %u, pgrp = %u\n", current->pid, current->pgrp));
-			
-			if ( oz_mode )
-				return -ENOENT;
-			up(&dir->i_sem);
-			status = autofs_wait(sbi,str);
-			down(&dir->i_sem);
-			DPRINTK(("autofs_wait returned %d\n", status));
-			if ( status )
-				return status;
-		}
-
-		DPRINTK(("lookup successful, inode = %08x\n", (unsigned int)ent->ino));
-
-		if (!(res = iget(dir->i_sb,ent->ino))) {
-			printk("autofs: iget returned null!\n");
-			return -EACCES;
-		}
-		
-		if ( !oz_mode && S_ISDIR(res->i_mode) && res->i_sb == dir->i_sb ) {
-			/* Not a mount point yet, call 1-800-DAEMON */
-			DPRINTK(("autofs: waiting on non-mountpoint dir, inode = %lu, pid = %u, pgrp = %u\n", res->i_ino, current->pid, current->pgrp));
-			res = NULL;
-			up(&dir->i_sem);
-			status = autofs_wait(sbi,str);
-			down(&dir->i_sem);
-			if ( status )
-				return status;
-		}
-	} while(!res);
-	autofs_update_usage(&sbi->dirhash,ent);
-	
-	*result = res;
+	/*
+	 * Mark the dentry incomplete, but add it. This is needed so
+	 * that the VFS layer knows about the dentry, and we can count
+	 * on catching any lookups through the revalidate.
+	 *
+	 * Let all the hard work be done by the revalidate function that
+	 * needs to be able to do this anyway..
+	 *
+	 * We need to do this before we release the directory semaphore.
+	 */
+	dentry->d_revalidate = autofs_revalidate;
+	dentry->d_flags = 1;
+	d_add(dentry, NULL);
+
+	up(&dir->i_sem);
+	autofs_revalidate(dentry);
+	down(&dir->i_sem);
 	return 0;
 }
 
@@ -163,7 +205,7 @@
 	struct autofs_symlink *sl;
 
 	DPRINTK(("autofs_root_symlink: %s <- ", symname));
-	autofs_say(name,len);
+	autofs_say(dentry->d_name.name,dentry->d_name.len);
 
 	if ( !autofs_oz_mode(sbi) )
 		return -EPERM;
@@ -207,11 +249,22 @@
 	memcpy(ent->name, dentry->d_name.name,ent->len = dentry->d_name.len);
 
 	autofs_hash_insert(dh,ent);
-	d_instantiate(dentry, iget(dir->i_sb,ent->ino), 0);
+	d_instantiate(dentry, iget(dir->i_sb,ent->ino));
 
 	return 0;
 }
 
+/*
+ * NOTE!
+ *
+ * Normal filesystems would do a "d_delete()" to tell the VFS dcache
+ * that the file no longer exists. However, doing that means that the
+ * VFS layer can turn the dentry into a negative dentry, which we
+ * obviously do not want (we're dropping the entry not because it
+ * doesn't exist, but because it has timed out).
+ *
+ * Also see autofs_root_rmdir()..
+ */
 static int autofs_root_unlink(struct inode *dir, struct dentry *dentry)
 {
 	struct autofs_sb_info *sbi = (struct autofs_sb_info *) dir->i_sb->u.generic_sbp;
@@ -233,7 +286,7 @@
 	autofs_hash_delete(ent);
 	clear_bit(n,sbi->symlink_bitmap);
 	kfree(sbi->symlink[n].data);
-	d_delete(dentry);
+	d_drop(dentry);
 	
 	return 0;
 }
@@ -256,7 +309,7 @@
 
 	autofs_hash_delete(ent);
 	dir->i_nlink--;
-	d_delete(dentry);
+	d_drop(dentry);
 
 	return 0;
 }
@@ -294,7 +347,7 @@
 	ent->ino = sbi->next_dir_ino++;
 	autofs_hash_insert(dh,ent);
 	dir->i_nlink++;
-	d_instantiate(dentry, iget(dir->i_sb,ent->ino), D_DIR);
+	d_instantiate(dentry, iget(dir->i_sb,ent->ino));
 
 	return 0;
 }
diff -u --recursive --new-file v2.1.44/linux/fs/autofs/waitq.c linux/fs/autofs/waitq.c
--- v2.1.44/linux/fs/autofs/waitq.c	Mon Jul  7 12:57:29 1997
+++ linux/fs/autofs/waitq.c	Mon Jul 14 10:22:52 1997
@@ -37,7 +37,7 @@
 		wake_up(&wq->queue);
 		wq = nwq;
 	}
-	fput(sbi->pipe, sbi->pipe->f_inode);	/* Close the pipe */
+	fput(sbi->pipe);	/* Close the pipe */
 }
 
 static int autofs_write(struct file *file, const void *addr, int bytes)
@@ -55,7 +55,7 @@
 
 	old_signal = current->signal;
 
-	while ( bytes && (written = file->f_op->write(file->f_inode,file,data,bytes)) > 0 ) {
+	while ( bytes && (written = file->f_op->write(file->f_dentry->d_inode,file,data,bytes)) > 0 ) {
 		data += written;
 		bytes -= written;
 	}
diff -u --recursive --new-file v2.1.44/linux/fs/binfmt_aout.c linux/fs/binfmt_aout.c
--- v2.1.44/linux/fs/binfmt_aout.c	Mon Jun 16 16:35:57 1997
+++ linux/fs/binfmt_aout.c	Sun Jul 13 21:20:10 1997
@@ -79,6 +79,7 @@
 static inline int
 do_aout_core_dump(long signr, struct pt_regs * regs)
 {
+	struct dentry * dentry = NULL;
 	struct inode * inode = NULL;
 	struct file file;
 	unsigned short fs;
@@ -114,10 +115,12 @@
 #else
 	corefile[4] = '\0';
 #endif
-	if (open_namei(corefile,O_CREAT | 2 | O_TRUNC,0600,&inode,NULL)) {
-		inode = NULL;
+	dentry = open_namei(corefile,O_CREAT | 2 | O_TRUNC, 0600);
+	if (IS_ERR(dentry)) {
+		dentry = NULL;
 		goto end_coredump;
 	}
+	inode = dentry->d_inode;
 	if (!S_ISREG(inode->i_mode))
 		goto end_coredump;
 	if (!inode->i_op || !inode->i_op->default_file_ops)
@@ -127,7 +130,7 @@
 	file.f_mode = 3;
 	file.f_flags = 0;
 	file.f_count = 1;
-	file.f_inode = inode;
+	file.f_dentry = dentry;
 	file.f_pos = 0;
 	file.f_reada = 0;
 	file.f_op = inode->i_op->default_file_ops;
@@ -214,7 +217,6 @@
 /* Finally dump the task struct.  Not be used by gdb, but could be useful */
 	set_fs(KERNEL_DS);
 	DUMP_WRITE(current,sizeof(*current));
-	inode->i_status |= ST_MODIFIED;
 close_coredump:
 	if (file.f_op->release)
 		file.f_op->release(inode,&file);
@@ -222,7 +224,7 @@
 	put_write_access(inode);
 end_coredump:
 	set_fs(fs);
-	iput(inode);
+	dput(dentry);
 	return has_dumped;
 }
 
@@ -318,7 +320,7 @@
 	if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC &&
 	     N_MAGIC(ex) != QMAGIC && N_MAGIC(ex) != NMAGIC) ||
 	    N_TRSIZE(ex) || N_DRSIZE(ex) ||
-	    bprm->inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
+	    bprm->dentry->d_inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
 		return -ENOEXEC;
 	}
 
@@ -332,7 +334,7 @@
 	}
 
 	if (N_MAGIC(ex) == ZMAGIC && ex.a_text &&
-	    (fd_offset < bprm->inode->i_sb->s_blocksize)) {
+	    (fd_offset < bprm->dentry->d_inode->i_sb->s_blocksize)) {
 		printk(KERN_NOTICE "N_TXTOFF < BLOCK_SIZE. Please convert binary.\n");
 		return -ENOEXEC;
 	}
@@ -372,12 +374,12 @@
 		error = do_mmap(NULL, N_TXTADDR(ex), ex.a_text,
 				PROT_READ|PROT_WRITE|PROT_EXEC,
 				MAP_FIXED|MAP_PRIVATE, 0);
-		read_exec(bprm->inode, fd_offset, (char *) N_TXTADDR(ex),
+		read_exec(bprm->dentry, fd_offset, (char *) N_TXTADDR(ex),
 			  ex.a_text, 0);
 		error = do_mmap(NULL, N_DATADDR(ex), ex.a_data,
 				PROT_READ|PROT_WRITE|PROT_EXEC,
 				MAP_FIXED|MAP_PRIVATE, 0);
-		read_exec(bprm->inode, fd_offset + ex.a_text, (char *) N_DATADDR(ex),
+		read_exec(bprm->dentry, fd_offset + ex.a_text, (char *) N_DATADDR(ex),
 			  ex.a_data, 0);
 		goto beyond_if;
 	}
@@ -389,20 +391,20 @@
 			ex.a_text+ex.a_data + PAGE_SIZE - 1,
 			PROT_READ|PROT_WRITE|PROT_EXEC,
 			MAP_FIXED|MAP_PRIVATE, 0);
-		read_exec(bprm->inode, fd_offset, (char *) N_TXTADDR(ex),
+		read_exec(bprm->dentry, fd_offset, (char *) N_TXTADDR(ex),
 			  ex.a_text+ex.a_data, 0);
 #else
 		do_mmap(NULL, 0, ex.a_text+ex.a_data,
 			PROT_READ|PROT_WRITE|PROT_EXEC,
 			MAP_FIXED|MAP_PRIVATE, 0);
-		read_exec(bprm->inode, 32, (char *) 0, ex.a_text+ex.a_data, 0);
+		read_exec(bprm->dentry, 32, (char *) 0, ex.a_text+ex.a_data, 0);
 #endif
 	} else {
 		if ((ex.a_text & 0xfff || ex.a_data & 0xfff) &&
 		    (N_MAGIC(ex) != NMAGIC))
 			printk(KERN_NOTICE "executable not page aligned\n");
 
-		fd = open_inode(bprm->inode, O_RDONLY);
+		fd = open_dentry(bprm->dentry, O_RDONLY);
 
 		if (fd < 0)
 			return fd;
@@ -412,7 +414,7 @@
 			do_mmap(NULL, 0, ex.a_text+ex.a_data,
 				PROT_READ|PROT_WRITE|PROT_EXEC,
 				MAP_FIXED|MAP_PRIVATE, 0);
-			read_exec(bprm->inode, fd_offset,
+			read_exec(bprm->dentry, fd_offset,
 				  (char *) N_TXTADDR(ex), ex.a_text+ex.a_data, 0);
 			goto beyond_if;
 		}
@@ -482,17 +484,20 @@
 {
         struct file * file;
 	struct exec ex;
-	struct  inode * inode;
+	struct dentry * dentry;
+	struct inode * inode;
 	unsigned int len;
 	unsigned int bss;
 	unsigned int start_addr;
 	unsigned long error;
 
 	file = current->files->fd[fd];
-	inode = file->f_inode;
 
 	if (!file || !file->f_op)
 		return -EACCES;
+
+	dentry = file->f_dentry;
+	inode = dentry->d_inode;
 
 	/* Seek into the file */
 	if (file->f_op->llseek) {
diff -u --recursive --new-file v2.1.44/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- v2.1.44/linux/fs/binfmt_elf.c	Mon Jul  7 08:18:55 1997
+++ linux/fs/binfmt_elf.c	Mon Jul 14 11:42:23 1997
@@ -186,7 +186,7 @@
    an ELF header */
 
 static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
-				     struct inode * interpreter_inode,
+				     struct dentry * interpreter_dentry,
 				     unsigned long *interp_load_addr)
 {
 	struct file * file;
@@ -208,8 +208,8 @@
 	if ((interp_elf_ex->e_type != ET_EXEC &&
 	    interp_elf_ex->e_type != ET_DYN) ||
 	   !elf_check_arch(interp_elf_ex->e_machine) ||
-	   (!interpreter_inode->i_op ||
-	    !interpreter_inode->i_op->default_file_ops->mmap)){
+	   (!interpreter_dentry->d_inode->i_op ||
+	    !interpreter_dentry->d_inode->i_op->default_file_ops->mmap)){
 		return ~0UL;
 	}
 
@@ -236,7 +236,7 @@
 	    return ~0UL;
 	  }
 
-	retval = read_exec(interpreter_inode, interp_elf_ex->e_phoff,
+	retval = read_exec(interpreter_dentry, interp_elf_ex->e_phoff,
 			   (char *) elf_phdata,
 			   sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, 1);
 
@@ -245,7 +245,7 @@
 		return retval;
  	}
 
-	elf_exec_fileno = open_inode(interpreter_inode, O_RDONLY);
+	elf_exec_fileno = open_dentry(interpreter_dentry, O_RDONLY);
 	if (elf_exec_fileno < 0) {
 	  kfree(elf_phdata);
 	  return ~0UL;
@@ -333,7 +333,7 @@
 }
 
 static unsigned long load_aout_interp(struct exec * interp_ex,
-			     struct inode * interpreter_inode)
+			     struct dentry * interpreter_dentry)
 {
   int retval;
   unsigned long elf_entry;
@@ -348,13 +348,13 @@
     do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data,
 	    PROT_READ|PROT_WRITE|PROT_EXEC,
 	    MAP_FIXED|MAP_PRIVATE, 0);
-    retval = read_exec(interpreter_inode, 32, (char *) 0,
+    retval = read_exec(interpreter_dentry, 32, (char *) 0,
 		       interp_ex->a_text+interp_ex->a_data, 0);
   } else if (N_MAGIC(*interp_ex) == ZMAGIC || N_MAGIC(*interp_ex) == QMAGIC) {
     do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data,
 	    PROT_READ|PROT_WRITE|PROT_EXEC,
 	    MAP_FIXED|MAP_PRIVATE, 0);
-    retval = read_exec(interpreter_inode,
+    retval = read_exec(interpreter_dentry,
 		       N_TXTOFF(*interp_ex) ,
 		       (char *) N_TXTADDR(*interp_ex),
 		       interp_ex->a_text+interp_ex->a_data, 0);
@@ -389,7 +389,7 @@
 	struct elfhdr interp_elf_ex;
 	struct file * file;
   	struct exec interp_ex;
-	struct inode *interpreter_inode;
+	struct dentry *interpreter_dentry;
 	unsigned long load_addr;
 	int load_addr_set = 0;
 	unsigned int interpreter_type = INTERPRETER_NONE;
@@ -423,8 +423,8 @@
 	if ((elf_ex.e_type != ET_EXEC &&
 	    elf_ex.e_type != ET_DYN) ||
 	   (! elf_check_arch(elf_ex.e_machine)) ||
-	   (!bprm->inode->i_op || !bprm->inode->i_op->default_file_ops ||
-	    !bprm->inode->i_op->default_file_ops->mmap)){
+	   (!bprm->dentry->d_inode->i_op || !bprm->dentry->d_inode->i_op->default_file_ops ||
+	    !bprm->dentry->d_inode->i_op->default_file_ops->mmap)){
 		return -ENOEXEC;
 	}
 
@@ -436,7 +436,7 @@
 		return -ENOMEM;
 	}
 
-	retval = read_exec(bprm->inode, elf_ex.e_phoff, (char *) elf_phdata,
+	retval = read_exec(bprm->dentry, elf_ex.e_phoff, (char *) elf_phdata,
 			   elf_ex.e_phentsize * elf_ex.e_phnum, 1);
 	if (retval < 0) {
 		kfree (elf_phdata);
@@ -448,7 +448,7 @@
 	elf_bss = 0;
 	elf_brk = 0;
 
-	elf_exec_fileno = open_inode(bprm->inode, O_RDONLY);
+	elf_exec_fileno = open_dentry(bprm->dentry, O_RDONLY);
 
 	if (elf_exec_fileno < 0) {
 		kfree (elf_phdata);
@@ -486,7 +486,7 @@
 				return -ENOMEM;
 			}
 
-			retval = read_exec(bprm->inode,elf_ppnt->p_offset,
+			retval = read_exec(bprm->dentry,elf_ppnt->p_offset,
 					   elf_interpreter,
 					   elf_ppnt->p_filesz, 1);
 			/* If the program interpreter is one of these two,
@@ -501,13 +501,14 @@
 			if (retval >= 0) {
 				old_fs = get_fs(); /* This could probably be optimized */
 				set_fs(get_ds());
-				retval = open_namei(elf_interpreter, 0, 0,
-						    &interpreter_inode, NULL);
+				interpreter_dentry = open_namei(elf_interpreter, 0, 0);
 				set_fs(old_fs);
+				if (IS_ERR(interpreter_dentry))
+					retval = PTR_ERR(interpreter_dentry);
 			}
 
 			if (retval >= 0)
-				retval = read_exec(interpreter_inode,0,bprm->buf,128, 1);
+				retval = read_exec(interpreter_dentry,0,bprm->buf,128, 1);
 
 			if (retval >= 0) {
 				interp_ex = *((struct exec *) bprm->buf);		/* exec-header */
@@ -643,13 +644,13 @@
 	if (elf_interpreter) {
 		if (interpreter_type & 1)
 			elf_entry = load_aout_interp(&interp_ex,
-						     interpreter_inode);
+						     interpreter_dentry);
 		else if (interpreter_type & 2)
 			elf_entry = load_elf_interp(&interp_elf_ex,
-						    interpreter_inode,
+						    interpreter_dentry,
 						    &interp_load_addr);
 
-		iput(interpreter_inode);
+		dput(interpreter_dentry);
 		kfree(elf_interpreter);
 
 		if (elf_entry == ~0UL) {
@@ -677,8 +678,7 @@
 		__MOD_INC_USE_COUNT(current->binfmt->module);
 
 #ifndef VM_STACK_FLAGS
-	current->executable = bprm->inode;
-	atomic_inc(&bprm->inode->i_count);
+	current->executable = dget(bprm->dentry);
 #endif
 #ifdef LOW_ELF_STACK
 	current->start_stack = bprm->p = elf_stack - 4;
@@ -763,7 +763,8 @@
 	struct file * file;
 	struct elfhdr elf_ex;
 	struct elf_phdr *elf_phdata  =  NULL;
-	struct  inode * inode;
+	struct dentry * dentry;
+	struct inode * inode;
 	unsigned long len;
 	int elf_bss;
 	int retval;
@@ -773,7 +774,8 @@
 
 	len = 0;
 	file = current->files->fd[fd];
-	inode = file->f_inode;
+	dentry = file->f_dentry;
+	inode = dentry->d_inode;
 	elf_bss = 0;
 
 	if (!file || !file->f_op)
@@ -812,7 +814,7 @@
 	if (elf_phdata == NULL)
 		return -ENOMEM;
 
-	retval = read_exec(inode, elf_ex.e_phoff, (char *) elf_phdata,
+	retval = read_exec(dentry, elf_ex.e_phoff, (char *) elf_phdata,
 			   sizeof(struct elf_phdr) * elf_ex.e_phnum, 1);
 
 	j = 0;
@@ -884,14 +886,13 @@
  */
 static int dump_write(struct file *file, const void *addr, int nr)
 {
-	file->f_inode->i_status |= ST_MODIFIED;
-	return file->f_op->write(file->f_inode, file, addr, nr) == nr;
+	return file->f_op->write(file->f_dentry->d_inode, file, addr, nr) == nr;
 }
 
 static int dump_seek(struct file *file, off_t off)
 {
 	if (file->f_op->llseek) {
-		if (file->f_op->llseek(file->f_inode, file, off, 0) != off)
+		if (file->f_op->llseek(file->f_dentry->d_inode, file, off, 0) != off)
 			return 0;
 	} else
 		file->f_pos = off;
@@ -1006,6 +1007,7 @@
 {
 	int has_dumped = 0;
 	struct file file;
+	struct dentry *dentry;
 	struct inode *inode;
 	unsigned short fs;
 	char corefile[6+sizeof(current->comm)];
@@ -1079,10 +1081,12 @@
 #else
 	corefile[4] = '\0';
 #endif
-	if (open_namei(corefile,O_CREAT | 2 | O_TRUNC,0600,&inode,NULL)) {
-		inode = NULL;
+	dentry = open_namei(corefile, O_CREAT | 2 | O_TRUNC, 0600);
+	if (IS_ERR(dentry)) {
+		dentry = NULL;
 		goto end_coredump;
 	}
+	inode = dentry->d_inode;
 	if (!S_ISREG(inode->i_mode))
 		goto end_coredump;
 	if (!inode->i_op || !inode->i_op->default_file_ops)
@@ -1090,7 +1094,7 @@
 	file.f_mode = 3;
 	file.f_flags = 0;
 	file.f_count = 1;
-	file.f_inode = inode;
+	file.f_dentry = dentry;
 	file.f_pos = 0;
 	file.f_reada = 0;
 	file.f_op = inode->i_op->default_file_ops;
@@ -1287,7 +1291,7 @@
 
  end_coredump:
 	set_fs(fs);
-	iput(inode);
+	dput(dentry);
 #ifndef CONFIG_BINFMT_ELF
 	MOD_DEC_USE_COUNT;
 #endif
diff -u --recursive --new-file v2.1.44/linux/fs/binfmt_em86.c linux/fs/binfmt_em86.c
--- v2.1.44/linux/fs/binfmt_em86.c	Wed Apr 23 19:01:22 1997
+++ linux/fs/binfmt_em86.c	Sun Jul 13 21:20:10 1997
@@ -23,6 +23,7 @@
 static int do_load_em86(struct linux_binprm *bprm,struct pt_regs *regs)
 {
 	char *interp, *i_name, *i_arg;
+	struct dentry * dentry;
 	int retval;
 	struct elfhdr	elf_ex;
 
@@ -39,14 +40,14 @@
         if ((elf_ex.e_type != ET_EXEC &&
             elf_ex.e_type != ET_DYN) ||
            (!((elf_ex.e_machine == EM_386) || (elf_ex.e_machine == EM_486))) ||
-           (!bprm->inode->i_op || !bprm->inode->i_op->default_file_ops ||
-            !bprm->inode->i_op->default_file_ops->mmap)){
+           (!bprm->dentry->d_inode->i_op || !bprm->dentry->d_inode->i_op->default_file_ops ||
+            !bprm->dentry->d_inode->i_op->default_file_ops->mmap)){
                 return -ENOEXEC;
         }
 
 	bprm->sh_bang++;	/* Well, the bang-shell is implicit... */
-	iput(bprm->inode);
-	bprm->dont_iput = 1;
+	dput(bprm->dentry);
+	bprm->dentry = NULL;
 
 	/* Unlike in the script case, we don't have to do any hairy
 	 * parsing to find our interpreter... it's hardcoded!
@@ -79,14 +80,17 @@
 	 * Note that we use open_namei() as the name is now in kernel
 	 * space, and we don't need to copy it.
 	 */
-	retval = open_namei(interp, 0, 0, &bprm->inode, NULL);
-	if (retval)
-		return retval;
-	bprm->dont_iput=0;
-	retval=prepare_binprm(bprm);
-	if(retval<0)
+	dentry = open_namei(interp, 0, 0);
+	if (IS_ERR(dentry))
+		return PTR_ERR(dentry);
+
+	bprm->dentry = dentry;
+
+	retval = prepare_binprm(bprm);
+	if (retval < 0)
 		return retval;
-	return search_binary_handler(bprm,regs);
+
+	return search_binary_handler(bprm, regs);
 }
 
 static int load_em86(struct linux_binprm *bprm,struct pt_regs *regs)
diff -u --recursive --new-file v2.1.44/linux/fs/binfmt_java.c linux/fs/binfmt_java.c
--- v2.1.44/linux/fs/binfmt_java.c	Wed Apr 23 19:01:22 1997
+++ linux/fs/binfmt_java.c	Mon Jul 14 10:28:48 1997
@@ -28,7 +28,9 @@
 	char *i_name;
 	int len;
 	int retval;
+	struct dentry * dentry;
 	unsigned char *ucp = (unsigned char *) bprm->buf;
+
 	if ((ucp[0] != 0xca) || (ucp[1] != 0xfe) || (ucp[2] != 0xba) || (ucp[3] != 0xbe)) 
 		return -ENOEXEC;
 
@@ -42,8 +44,8 @@
 
 	bprm->java = 1;
 
-	iput(bprm->inode);
-	bprm->dont_iput=1;
+	dput(bprm->dentry);
+	bprm->dentry = NULL;
 
 	/*
 	 * Set args: [0] the name of the java interpreter
@@ -75,15 +77,17 @@
 	if (!bprm->p) 
 		return -E2BIG;
 	/*
-	 * OK, now restart the process with the interpreter's inode.
+	 * OK, now restart the process with the interpreter's dentry.
 	 */
 	bprm->filename = binfmt_java_interpreter;
-	retval = open_namei(binfmt_java_interpreter, 0, 0, &bprm->inode, NULL);
-	if (retval)
+	dentry = open_namei(binfmt_java_interpreter, 0, 0);
+	retval = PTR_ERR(dentry);
+	if (IS_ERR(dentry))
 		return retval;
-	bprm->dont_iput=0;
-	retval=prepare_binprm(bprm);
-	if(retval<0)
+
+	bprm->dentry = dentry;
+	retval = prepare_binprm(bprm);
+	if (retval < 0)
 		return retval;
 
 	return search_binary_handler(bprm,regs);
@@ -92,12 +96,14 @@
 static int do_load_applet(struct linux_binprm *bprm,struct pt_regs *regs)
 {
 	char *i_name;
+	struct dentry * dentry;
 	int retval;
+
 	if (strncmp (bprm->buf, "<!--applet", 10))
 		return -ENOEXEC;
 
-	iput(bprm->inode);
-	bprm->dont_iput=1;
+	dput(bprm->dentry);
+	bprm->dentry = NULL;
 
 	/*
 	 * Set args: [0] the name of the appletviewer
@@ -118,15 +124,17 @@
 	if (!bprm->p) 
 		return -E2BIG;
 	/*
-	 * OK, now restart the process with the interpreter's inode.
+	 * OK, now restart the process with the interpreter's dentry.
 	 */
 	bprm->filename = binfmt_java_appletviewer;
-	retval = open_namei(binfmt_java_appletviewer, 0, 0, &bprm->inode, NULL);
-	if (retval)
+	dentry = open_namei(binfmt_java_appletviewer, 0, 0);
+	retval = PTR_ERR(dentry);
+	if (IS_ERR(dentry))
 		return retval;
-	bprm->dont_iput=0;
-	retval=prepare_binprm(bprm);
-	if(retval<0)
+
+	bprm->dentry = dentry;
+	retval = prepare_binprm(bprm);
+	if (retval < 0)
 		return retval;
 
 	return search_binary_handler(bprm,regs);
diff -u --recursive --new-file v2.1.44/linux/fs/binfmt_misc.c linux/fs/binfmt_misc.c
--- v2.1.44/linux/fs/binfmt_misc.c	Tue Jul  1 08:55:56 1997
+++ linux/fs/binfmt_misc.c	Wed Jul 16 07:47:32 1997
@@ -50,7 +50,7 @@
 
 #define ENTRY_ENABLED 1		/* the old binfmt_entry.enabled */
 #define	ENTRY_MAGIC 8		/* not filename detection */
-#define ENTRY_STRIP_EXT 32	/* strip of last filename extension */
+#define ENTRY_STRIP_EXT 32	/* strip off last filename extension */
 
 static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs);
 static void entry_proc_cleanup(struct binfmt_entry *e);
@@ -157,10 +157,12 @@
 static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
 {
 	struct binfmt_entry *fmt;
+	struct dentry * dentry;
 	char iname[128];
 	char *iname_addr = iname, *p;
 	int retval, fmt_flags = 0;
 
+	MOD_INC_USE_COUNT;
 	if (!enabled) {
 		retval = -ENOEXEC;
 		goto _ret;
@@ -179,8 +181,8 @@
 		goto _ret;
 	}
 
-	iput(bprm->inode);
-	bprm->dont_iput = 1;
+	dput(bprm->dentry);
+	bprm->dentry = NULL;
 
 	/* Build args for interpreter */
 	if ((fmt_flags & ENTRY_STRIP_EXT) &&
@@ -197,13 +199,17 @@
 	}
 	bprm->filename = iname;	/* for binfmt_script */
 
-	if ((retval = open_namei(iname, 0, 0, &bprm->inode, NULL)))
+	dentry = open_namei(iname, 0, 0);
+	retval = PTR_ERR(dentry);
+	if (IS_ERR(dentry))
 		goto _ret;
-	bprm->dont_iput = 0;
+	bprm->dentry = dentry;
 
-	if ((retval = prepare_binprm(bprm)) >= 0)
+	retval = prepare_binprm(bprm);
+	if (retval >= 0)
 		retval = search_binary_handler(bprm, regs);
 _ret:
+	MOD_DEC_USE_COUNT;
 	return retval;
 }
 
@@ -262,13 +268,18 @@
 	struct binfmt_entry *e;
 	int memsize, cnt = count - 1, err = 0;
 
+	MOD_INC_USE_COUNT;
 	/* some sanity checks */
-	if ((count < 11) || (count > 256))
-		return -EINVAL;
+	if ((count < 11) || (count > 256)) {
+		err = -EINVAL;
+		goto _err;
+	}
 
 	memsize = sizeof(struct binfmt_entry) + count;
-	if (!(e = (struct binfmt_entry *) kmalloc(memsize, GFP_USER)))
-		return -ENOMEM;
+	if (!(e = (struct binfmt_entry *) kmalloc(memsize, GFP_USER))) {
+		err = -ENOMEM;
+		goto _err;
+	}
 
 	sp = buffer + 1;
 	del = buffer[0];
@@ -305,7 +316,8 @@
 	    !(e->proc_name) || !(e->interpreter) ||
 	    entry_proc_setup(e)) {
 		kfree(e);
-		return -EINVAL;
+		err = -EINVAL;
+		goto _err;
 	}
 
 	write_lock(&entries_lock);
@@ -313,7 +325,10 @@
 	entries = e;
 	write_unlock(&entries_lock);
 
-	return count;
+	err = count;
+_err:
+	MOD_DEC_USE_COUNT;
+	return err;
 }
 
 /*
@@ -328,6 +343,7 @@
 	char *dp;
 	int elen, i;
 
+	MOD_INC_USE_COUNT;
 #ifndef VERBOSE_STATUS
 	if (data) {
 		read_lock(&entries_lock);
@@ -387,6 +403,7 @@
 	*eof = (elen <= count) ? 1 : 0;
 	*start = page + off;
 
+	MOD_DEC_USE_COUNT;
 	return elen;
 }
 
@@ -400,6 +417,7 @@
 	struct binfmt_entry *e;
 	int res = count;
 
+	MOD_INC_USE_COUNT;
 	if (((buffer[0] == '1') || (buffer[0] == '0')) &&
 	    ((count == 1) || ((count == 2) && (buffer[1] == '\n')))) {
 		if (data) {
@@ -419,6 +437,7 @@
 	} else {
 		res = -EINVAL;
 	}
+	MOD_DEC_USE_COUNT;
 	return res;
 }
 
diff -u --recursive --new-file v2.1.44/linux/fs/binfmt_script.c linux/fs/binfmt_script.c
--- v2.1.44/linux/fs/binfmt_script.c	Wed Apr 23 19:01:22 1997
+++ linux/fs/binfmt_script.c	Sun Jul 13 21:20:10 1997
@@ -15,8 +15,10 @@
 static int do_load_script(struct linux_binprm *bprm,struct pt_regs *regs)
 {
 	char *cp, *i_name, *i_name_start, *i_arg;
+	struct dentry * dentry;
 	char interp[128];
 	int retval;
+
 	if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!') || (bprm->sh_bang)) 
 		return -ENOEXEC;
 	/*
@@ -25,8 +27,8 @@
 	 */
 
 	bprm->sh_bang++;
-	iput(bprm->inode);
-	bprm->dont_iput=1;
+	dput(bprm->dentry);
+	bprm->dentry = NULL;
 
 	bprm->buf[127] = '\0';
 	if ((cp = strchr(bprm->buf, '\n')) == NULL)
@@ -75,14 +77,15 @@
 	if (!bprm->p) 
 		return -E2BIG;
 	/*
-	 * OK, now restart the process with the interpreter's inode.
+	 * OK, now restart the process with the interpreter's dentry.
 	 */
-	retval = open_namei(interp, 0, 0, &bprm->inode, NULL);
-	if (retval)
-		return retval;
-	bprm->dont_iput=0;
-	retval=prepare_binprm(bprm);
-	if(retval<0)
+	dentry = open_namei(interp, 0, 0);
+	if (IS_ERR(dentry))
+		return PTR_ERR(dentry);
+
+	bprm->dentry = dentry;
+	retval = prepare_binprm(bprm);
+	if (retval < 0)
 		return retval;
 	return search_binary_handler(bprm,regs);
 }
diff -u --recursive --new-file v2.1.44/linux/fs/buffer.c linux/fs/buffer.c
--- v2.1.44/linux/fs/buffer.c	Tue Jul  1 20:21:42 1997
+++ linux/fs/buffer.c	Sun Jul 13 21:20:10 1997
@@ -289,16 +289,35 @@
 asmlinkage int sys_fsync(unsigned int fd)
 {
 	struct file * file;
+	struct dentry * dentry;
 	struct inode * inode;
-	int err = 0;
+	int err;
 
 	lock_kernel();
-	if (fd>=NR_OPEN || !(file=current->files->fd[fd]) || !(inode=file->f_inode))
-		err = -EBADF;
-	else if (!file->f_op || !file->f_op->fsync)
-		err = -EINVAL;
-	else if (file->f_op->fsync(inode,file))
-		err = -EIO;
+	err = -EBADF;
+
+	if (fd >= NR_OPEN)
+		goto out;
+
+	file = current->files->fd[fd];
+	if (!file)
+		goto out;
+
+	dentry = file->f_dentry;
+	if (!dentry)
+		goto out;
+
+	inode = dentry->d_inode;
+	if (!inode)
+		goto out;
+
+	err = -EINVAL;
+	if (!file->f_op || !file->f_op->fsync)
+		goto out;
+
+	err = file->f_op->fsync(inode,file);
+
+out:
 	unlock_kernel();
 	return err;
 }
@@ -306,20 +325,35 @@
 asmlinkage int sys_fdatasync(unsigned int fd)
 {
 	struct file * file;
+	struct dentry * dentry;
 	struct inode * inode;
-	int err = -EBADF;
+	int err;
 
 	lock_kernel();
-	if (fd>=NR_OPEN || !(file=current->files->fd[fd]) || !(inode=file->f_inode))
+	err = -EBADF;
+
+	if (fd >= NR_OPEN)
+		goto out;
+
+	file = current->files->fd[fd];
+	if (!file)
+		goto out;
+
+	dentry = file->f_dentry;
+	if (!dentry)
+		goto out;
+
+	inode = dentry->d_inode;
+	if (!inode)
 		goto out;
+
 	err = -EINVAL;
 	if (!file->f_op || !file->f_op->fsync)
 		goto out;
+
 	/* this needs further work, at the moment it is identical to fsync() */
-	if (file->f_op->fsync(inode,file))
-		err = -EIO;
-	else
-		err = 0;
+	err = file->f_op->fsync(inode,file);
+
 out:
 	unlock_kernel();
 	return err;
diff -u --recursive --new-file v2.1.44/linux/fs/dcache.c linux/fs/dcache.c
--- v2.1.44/linux/fs/dcache.c	Mon Jul  7 14:50:18 1997
+++ linux/fs/dcache.c	Tue Jul 15 17:46:30 1997
@@ -16,25 +16,8 @@
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/fs.h>
-#include <linux/dalloc.h>
-#include <linux/dlists.h>
 #include <linux/malloc.h>
 
-/* this should be removed after the beta phase */
-/*#define DEBUG*/
-/*#undef DEBUG*/
-/*#define DEBUG_DDIR_COUNT*/
-
-void printpath(struct dentry * entry);
-
-DEF_INSERT(alias,struct dentry,d_next,d_prev)
-DEF_REMOVE(alias,struct dentry,d_next,d_prev)
-
-DEF_INSERT(hash,struct dentry,d_hash_next,d_hash_prev)
-DEF_REMOVE(hash,struct dentry,d_hash_next,d_hash_prev)
-
-struct dentry * the_root = NULL;
-
 /*
  * This is the single most critical data structure when it comes
  * to the dcache: the hashtable for lookups. Somebody should try
@@ -46,286 +29,255 @@
 #define D_HASHBITS     10
 #define D_HASHSIZE     (1UL << D_HASHBITS)
 #define D_HASHMASK     (D_HASHSIZE-1)
-struct dentry * dentry_hashtable[D_HASHSIZE];
-
-static inline unsigned long dentry_hash(struct dentry *dir, int name_hash)
-{
-	unsigned long hash = name_hash + (unsigned long) dir;
-	hash = hash ^ (hash >> D_HASHBITS) ^ (hash >> D_HASHBITS*2);
-	return hash & D_HASHMASK;
-}
-
-unsigned long name_cache_init(unsigned long mem_start, unsigned long mem_end)
-{
-	return mem_start;
-}
-
-#ifdef DEBUG
-/* throw this away after the beta phase */
-/*************************************************************************/
-extern void xcheck(char * txt, struct inode * p);
-
-static int x_alloc = 0;
-static int x_freed = 0;
-static int x_free = 0;
 
-static void * tst[20000];
-static int cnt = 0;
+static struct list_head dentry_hashtable[D_HASHSIZE];
+static LIST_HEAD(dentry_unused);
 
-static void ins(void* ptr)
+void d_free(struct dentry *dentry)
 {
-	extern int inodes_stat;
-	tst[cnt++] = ptr;
-        if(cnt % 1000 == 0)
-		printk("------%d allocated: %d: %d %d %d\n", inodes_stat, cnt,
-		       x_alloc, x_freed, x_free);
-	if (cnt>=20000) panic("stop");
+	kfree(dentry->d_name.name);
+	kfree(dentry);
 }
 
-#if 0
-static inline int search(void* ptr)
+/*
+ * dput()
+ *
+ * This is complicated by the fact that we do not want to put
+ * dentries that are no longer on any hash chain on the unused
+ * list: we'd much rather just get rid of them immediately.
+ *
+ * However, that implies that we have to traverse the dentry
+ * tree upwards to the parents which might _also_ now be
+ * scheduled for deletion (it may have been only waiting for
+ * its last child to go away).
+ *
+ * This tail recursion is done by hand as we don't want to depend
+ * on the compiler to always get this right (gcc generally doesn't).
+ * Real recursion would eat up our stack space.
+ */
+void dput(struct dentry *dentry)
 {
-	int i;
-	for(i = cnt-1; i>=0; i--)
-		if (tst[i] == ptr)
-			return i;
-	return -1;
-}
-
-#define TST(n,x) if(search(x)<0) printk("%s bad ptr %p line %d\n", n, x, __LINE__)
-#else
-#define TST(n,x) /*nothing*/
-#endif
-
-void LOG(char * txt, struct dentry * entry)
-{
-	static int count = 0;
-	if (entry) {
-		TST(txt,entry);
-	}
-	if (count) {
-		count--;
-		printk("%s: entry=%p\n", txt, entry);
+	if (dentry) {
+		int count;
+repeat:
+		count = dentry->d_count-1;
+		if (count < 0) {
+			printk("Negative d_count (%d) for %s/%s\n",
+				count,
+				dentry->d_parent->d_name.name,
+				dentry->d_name.name);
+			*(int *)0 = 0;
+		}
+		dentry->d_count = count;
+		if (!count) {
+			list_del(&dentry->d_lru);
+			if (list_empty(&dentry->d_hash)) {
+				struct inode *inode = dentry->d_inode;
+				struct dentry * parent;
+				if (inode) {
+					list_del(&dentry->d_alias);
+					iput(inode);
+				}
+				parent = dentry->d_parent;
+				d_free(dentry);
+				if (dentry == parent)
+					return;
+				dentry = parent;
+				goto repeat;
+			}
+			list_add(&dentry->d_lru, &dentry_unused);
+		}
 	}
 }
 
-#ifdef DEBUG_DDIR_COUNT
-void recursive_test(struct dentry * entry)
-{
-}
-#else
-#define recursive_test(e) /*nothing*/
-#endif
-#else
-#define TST(n,x) /*nothing*/
-#define LOG(n,x) /*nothing*/
-#define xcheck(t,i) /*nothing*/
-#define recursive_test(e) /*nothing*/
-/*****************************************************************************/
-#endif
-
-void printpath(struct dentry * entry)
-{
-	if (!IS_ROOT(entry))
-		printpath(entry->d_parent);
-	printk("/%s", entry->d_name.name);
-}
-
-void d_free(struct dentry *dentry)
+/*
+ * Shrink the dcache. This is done when we need
+ * more memory, or simply when we need to unmount
+ * something (at which point we need to unuse
+ * all dentries).
+ */
+void shrink_dcache(void)
 {
-	if (dentry) {
-		kfree(dentry->d_name.name);
-		kfree(dentry);
+	for (;;) {
+		struct dentry *dentry;
+		struct list_head *tmp = dentry_unused.prev;
+
+		if (tmp == &dentry_unused)
+			break;
+		list_del(tmp);
+		INIT_LIST_HEAD(tmp);
+		dentry = list_entry(tmp, struct dentry, d_lru);
+		if (!dentry->d_count) {
+			struct dentry * parent;
+
+			list_del(&dentry->d_hash);
+			if (dentry->d_inode) {
+				struct inode * inode = dentry->d_inode;
+
+				list_del(&dentry->d_alias);
+				dentry->d_inode = NULL;
+				iput(inode);
+			}
+			parent = dentry->d_parent;
+			d_free(dentry);
+			dput(parent);
+		}
 	}
 }
 
 #define NAME_ALLOC_LEN(len)	((len+16) & ~15)
 
-struct dentry * d_alloc(struct dentry * parent, struct qstr *name, int isdir)
+struct dentry * d_alloc(struct dentry * parent, const struct qstr *name)
 {
-	char *str;
-	struct dentry *res;
+	char * str;
+	struct dentry *dentry;
 
-	res = kmalloc(sizeof(struct dentry), GFP_KERNEL);
-	if (!res)
+	dentry = kmalloc(sizeof(struct dentry), GFP_KERNEL);
+	if (!dentry)
 		return NULL;
 
 	str = kmalloc(NAME_ALLOC_LEN(name->len), GFP_KERNEL);
 	if (!str) {
-		kfree(res);
+		kfree(dentry);
 		return NULL;
 	}
-	
+
 	memcpy(str, name->name, name->len);
 	str[name->len] = 0;
 
-	memset(res, 0, sizeof(struct dentry));
-
-	res->d_parent = parent;
-	res->d_mounts = res;
-	res->d_covers = res;
-	res->d_flag = isdir ? D_DIR : 0;
-
-	res->d_name.name = str;
-	res->d_name.len = name->len;
-	res->d_name.hash = name->hash;
-
-#ifdef DEBUG
-	x_alloc++;
-#endif
-	return res;
+	dentry->d_count = 0;
+	dentry->d_flags = 0;
+	dentry->d_inode = NULL;
+	dentry->d_parent = parent;
+	dentry->d_mounts = dentry;
+	dentry->d_covers = dentry;
+	INIT_LIST_HEAD(&dentry->d_hash);
+	INIT_LIST_HEAD(&dentry->d_alias);
+	INIT_LIST_HEAD(&dentry->d_lru);
+
+	dentry->d_name.name = str;
+	dentry->d_name.len = name->len;
+	dentry->d_name.hash = name->hash;
+	dentry->d_revalidate = NULL;
+	return dentry;
 }
 
-extern blocking struct dentry * d_alloc_root(struct inode * root_inode, struct dentry *old_root)
+/*
+ * Fill in inode information in the entry.
+ *
+ * This turns negative dentries into productive full members
+ * of society.
+ *
+ * NOTE! This assumes that the inode count has been incremented
+ * (or otherwise set) by the caller to indicate that it is now
+ * in use by the dcache..
+ */
+void d_instantiate(struct dentry *entry, struct inode * inode)
 {
-	struct dentry *res;
-	struct qstr name = { "/", 1, 0 };	/* dummy qstr */
+	if (inode)
+		list_add(&entry->d_alias, &inode->i_dentry);
 
-	if (!root_inode)
-		return NULL;
-	res = d_alloc(NULL, &name, 1);
-	LOG("d_alloc_root", res);
-	res->d_parent = res;
-	d_instantiate(res, root_inode, D_DIR);
-	return res;
+	entry->d_inode = inode;
 }
 
-static inline struct dentry ** d_base_qstr(struct dentry * parent, struct qstr * s)
+struct dentry * d_alloc_root(struct inode * root_inode, struct dentry *old_root)
 {
-	return dentry_hashtable + dentry_hash(parent, s->hash);
-}
+	struct dentry *res = NULL;
 
-static inline struct dentry ** d_base_entry(struct dentry * pdir, struct dentry * entry)
-{
-	return d_base_qstr(pdir, &entry->d_name);
+	if (root_inode) {
+		res = d_alloc(NULL, &(const struct qstr) { "/", 1, 0 });
+		res->d_parent = res;
+		res->d_count = 1;
+		d_instantiate(res, root_inode);
+	}
+	return res;
 }
 
-
-static /*inline*/ blocking void _d_remove_from_parent(struct dentry * entry,
-						      struct dentry * parent)
+static inline struct list_head * d_hash(struct dentry * parent, unsigned long hash)
 {
-	if (entry->d_flag & D_HASHED) {
-		struct dentry ** base = d_base_entry(parent, entry);
-
-		remove_hash(base, entry);
-		entry->d_flag &= ~D_HASHED;
-	}
+	hash += (unsigned long) parent;
+	hash = hash ^ (hash >> D_HASHBITS) ^ (hash >> D_HASHBITS*2);
+	return dentry_hashtable + (hash & D_HASHMASK);
 }
 
-static inline struct dentry * __dlookup(struct dentry * base, struct dentry * parent, struct qstr * name)
+static inline struct dentry * __dlookup(struct list_head *head, struct dentry * parent, struct qstr * name)
 {
-	if (base) {
-		struct dentry * tmp = base;
-		int len = name->len;
-		int hash = name->hash;
-		const unsigned char *str = name->name;
-
-		do {
-			if (tmp->d_name.hash == hash		&&
-			    tmp->d_name.len == len		&&
-			    tmp->d_parent == parent		&&
-			   !(tmp->d_flag & D_DUPLICATE)		&&
-			   !memcmp(tmp->d_name.name, str, len))
-				return tmp;
-			tmp = tmp->d_hash_next;
-		} while(tmp != base);
+	struct list_head *tmp = head->next;
+	int len = name->len;
+	int hash = name->hash;
+	const unsigned char *str = name->name;
+
+	while (tmp != head) {
+		struct dentry * dentry = list_entry(tmp, struct dentry, d_hash);
+
+		tmp = tmp->next;
+		if (dentry->d_name.hash != hash)
+			continue;
+		if (dentry->d_name.len != len)
+			continue;
+		if (dentry->d_parent != parent)
+			continue;
+		if (memcmp(dentry->d_name.name, str, len))
+			continue;
+		return dentry;
 	}
 	return NULL;
 }
 
 struct dentry * d_lookup(struct dentry * dir, struct qstr * name)
 {
-	struct dentry ** base = d_base_qstr(dir, name);
-
-	return __dlookup(*base, dir, name);
+	return __dlookup(d_hash(dir, name->hash), dir, name);
 }
 
-static /*inline*/ blocking void _d_insert_to_parent(struct dentry * entry,
-						    struct dentry * parent,
-						    struct inode * inode,
-						    int flags)
+static inline void d_insert_to_parent(struct dentry * entry, struct dentry * parent)
 {
-	struct dentry ** base;
-
-	base = d_base_qstr(parent, &entry->d_name);
-	if (entry->d_flag & D_HASHED) {
-		printk("VFS: dcache entry is already hashed\n");
-		return;
-	}
-	insert_hash(base, entry);
-	entry->d_flag |= D_HASHED;
+	list_add(&entry->d_hash, d_hash(dget(parent), entry->d_name.hash));
 }
 
-/*
- * Fill in inode information in the entry.
- *
- * This turns negative dentries into productive full members
- * of society.
- *
- * NOTE! This assumes that the inode count has been incremented
- * (or otherwise set) by the caller to indicate that it is now
- * in use by the dcache..
- */
-void d_instantiate(struct dentry *entry, struct inode * inode, int flags)
+static inline void d_remove_from_parent(struct dentry * dentry, struct dentry * parent)
 {
-	entry->d_flag = (entry->d_flag & ~D_NEGATIVE) | flags;
-
-	if (inode && !(flags & D_NEGATIVE)) {
-		if (entry->d_flag & D_DIR) {
-			if (inode->i_dentry) {
-				printk("VFS: creating dcache directory alias\n");
-				return;
-			}
-		}
-		insert_alias(&inode->i_dentry, entry);
-	}
-
-	entry->d_inode = inode;
+	list_del(&dentry->d_hash);
+	dput(parent);
 }
 
+
 /*
- * Remove the inode from the dentry.. This removes
- * it from the parent hashes but otherwise leaves it
- * around - it may be a "zombie", part of a path
- * that is still in use...
+ * When a file is deleted, we have two options:
+ * - turn this dentry into a negative dentry
+ * - unhash this dentry and free it.
  *
- * "The Night of the Living Dead IV - the Dentry"
+ * Usually, we want to just turn this into
+ * a negative dentry, but if anybody else is
+ * currently using the dentry or the inode
+ * we can't do that and we fall back on removing
+ * it from the hash queues and waiting for
+ * it to be deleted later when it has no users
  */
 void d_delete(struct dentry * dentry)
 {
-	struct inode * inode = dentry->d_inode;
+	/*
+	 * Are we the only user?
+	 */
+	if (dentry->d_count == 1) {
+		struct inode * inode = dentry->d_inode;
 
-	_d_remove_from_parent(dentry, dentry->d_parent);
-	if (inode) {
-		remove_alias(&inode->i_dentry, dentry);
 		dentry->d_inode = NULL;
+		list_del(&dentry->d_alias);
 		iput(inode);
+		return;
 	}
+
+	/*
+	 * If not, just drop the dentry and let dput
+	 * pick up the tab..
+	 */
+	d_drop(dentry);
 }
 
-blocking void d_add(struct dentry * entry, struct inode * inode, int flags)
+void d_add(struct dentry * entry, struct inode * inode)
 {
-	struct dentry * parent = entry->d_parent;
-
-#ifdef DEBUG
-	if (inode)
-		xcheck("d_add", inode);
-	if (IS_ROOT(entry)) {
-		printk("VFS: d_add for root dentry ");
-		printpath(entry);
-		printk(" -> ");
-		printk("\n");
-		return;
-	}
-	if (!parent)
-		panic("d_add with parent==NULL");
-	LOG("d_add", entry);
-#endif
-        if(entry->d_flag & D_HASHED)
-		printk("VFS: d_add of already added dcache entry\n");
-
-	_d_insert_to_parent(entry, parent, inode, flags);
-	d_instantiate(entry, inode, flags);
+	d_insert_to_parent(entry, entry->d_parent);
+	d_instantiate(entry, inode);
 }
 
 static inline void alloc_new_name(struct dentry * entry, struct qstr *newname)
@@ -347,47 +299,18 @@
 	entry->d_name.hash = hash;
 }
 
-static inline void d_remove_old_parent(struct dentry * entry)
+void d_move(struct dentry * dentry, struct dentry * newdir, struct qstr * newname)
 {
-	struct dentry * parent;
-	struct inode * inode;
-
-	parent = entry->d_parent;
-	inode = entry->d_inode;
-	_d_remove_from_parent(entry, parent);
-}
-
-static inline void d_add_new_parent(struct dentry * entry, struct dentry * parent)
-{
-	struct inode * inode;
-
-	entry->d_parent = parent;
-	inode = entry->d_inode;
-
-	_d_insert_to_parent(entry, parent, inode, entry->d_flag);
-}
-
-
-blocking void d_move(struct dentry * entry, struct dentry * newdir, struct qstr * newname)
-{
-	struct inode * inode;
-	int flags;
-
-	if (!entry)
+	if (!dentry)
 		return;
-	inode = entry->d_inode;
-	flags = entry->d_flag;
-	if (!inode) {
-		printk("VFS: moving negative dcache entry\n");
-	}
 
-	if (flags & D_ZOMBIE) {
-		printk("VFS: moving zombie entry\n");
-	}
+	if (!dentry->d_inode)
+		printk("VFS: moving negative dcache entry\n");
 
-	d_remove_old_parent(entry);
-	alloc_new_name(entry, newname);
-	d_add_new_parent(entry, newdir);
+	d_remove_from_parent(dentry, dentry->d_parent);
+	alloc_new_name(dentry, newname);
+	dentry->d_parent = newdir;
+	d_insert_to_parent(dentry, newdir);
 }
 
 int d_path(struct dentry * entry, struct dentry * chroot, char * buf)
@@ -406,4 +329,17 @@
 		memcpy(buf, entry->d_name.name, entry->d_name.len);
 		return len + entry->d_name.len;
 	}
+}
+
+void dcache_init(void)
+{
+	int i;
+	struct list_head *d = dentry_hashtable;
+
+	i = D_HASHSIZE;
+	do {
+		INIT_LIST_HEAD(d);
+		d++;
+		i--;
+	} while (i);
 }
diff -u --recursive --new-file v2.1.44/linux/fs/devices.c linux/fs/devices.c
--- v2.1.44/linux/fs/devices.c	Mon Jun 16 16:35:57 1997
+++ linux/fs/devices.c	Mon Jul 14 23:08:29 1997
@@ -209,9 +209,7 @@
 
 	printk(KERN_DEBUG "VFS: Disk change detected on device %s\n",
 		kdevname(dev));
-	for (i=0 ; i<NR_SUPER ; i++)
-		if (super_blocks[i].s_dev == dev)
-			put_super(super_blocks[i].s_dev);
+
 	invalidate_inodes(dev);
 	invalidate_buffers(dev);
 
diff -u --recursive --new-file v2.1.44/linux/fs/dquot.c linux/fs/dquot.c
--- v2.1.44/linux/fs/dquot.c	Tue Jul  1 13:47:22 1997
+++ linux/fs/dquot.c	Sun Jul 13 21:20:10 1997
@@ -227,7 +227,7 @@
 	lock_dquot(dquot);
 	down(&dquot->dq_mnt->mnt_sem);
 	if (filp->f_op->llseek) {
-		if (filp->f_op->llseek(filp->f_inode, filp,
+		if (filp->f_op->llseek(filp->f_dentry->d_inode, filp,
 		    dqoff(dquot->dq_id), 0) != dqoff(dquot->dq_id)) {
 			up(&dquot->dq_mnt->mnt_sem);
 			unlock_dquot(dquot);
@@ -238,10 +238,9 @@
 	fs = get_fs();
 	set_fs(KERNEL_DS);
 
-	if (filp->f_op->write(filp->f_inode, filp,
+	if (filp->f_op->write(filp->f_dentry->d_inode, filp,
 	   (char *)&dquot->dq_dqb, sizeof(struct dqblk)) == sizeof(struct dqblk))
 		dquot->dq_flags &= ~DQ_MOD;
-	/* inode->i_status |= ST_MODIFIED is willingly *not* done here */
 
 	up(&dquot->dq_mnt->mnt_sem);
 	set_fs(fs);
@@ -260,7 +259,7 @@
 	lock_dquot(dquot);
 	down(&dquot->dq_mnt->mnt_sem);
 	if (filp->f_op->llseek) {
-		if (filp->f_op->llseek(filp->f_inode, filp,
+		if (filp->f_op->llseek(filp->f_dentry->d_inode, filp,
 		    dqoff(dquot->dq_id), 0) != dqoff(dquot->dq_id)) {
 			up(&dquot->dq_mnt->mnt_sem);
 			unlock_dquot(dquot);
@@ -270,7 +269,7 @@
 		filp->f_pos = dqoff(dquot->dq_id);
 	fs = get_fs();
 	set_fs(KERNEL_DS);
-	filp->f_op->read(filp->f_inode, filp, (char *)&dquot->dq_dqb, sizeof(struct dqblk));
+	filp->f_op->read(filp->f_dentry->d_inode, filp, (char *)&dquot->dq_dqb, sizeof(struct dqblk));
 	up(&dquot->dq_mnt->mnt_sem);
 	set_fs(fs);
 	if (dquot->dq_bhardlimit == 0 && dquot->dq_bsoftlimit == 0 &&
@@ -947,39 +946,53 @@
 
 int quota_on(kdev_t dev, short type, char *path)
 {
-	struct file *filp = (struct file *)NULL;
+	struct file *filp = NULL;
+	struct dentry *dentry;
 	struct vfsmount *vfsmnt;
 	struct inode *inode;
 	struct dquot *dquot;
 	char *tmp;
 	int error;
 
-	if ((vfsmnt = lookup_vfsmnt(dev)) == (struct vfsmount *)NULL)
-		return(-ENODEV);
-	if (vfsmnt->mnt_quotas[type] != (struct file *)NULL)
-		return(-EBUSY);
-	if ((error = getname(path, &tmp)) != 0)
-		return(error);
-	error = open_namei(tmp, O_RDWR, 0600, &inode, 0);
+	vfsmnt = lookup_vfsmnt(dev);
+	if (vfsmnt == NULL)
+		return -ENODEV;
+
+	if (vfsmnt->mnt_quotas[type] != NULL)
+		return -EBUSY;
+
+	tmp = getname(path);
+	error = PTR_ERR(tmp);
+	if (IS_ERR(tmp))
+		return error;
+
+	dentry = open_namei(tmp, O_RDWR, 0600);
 	putname(tmp);
-	if (error)
-		return(error);
+
+	error = PTR_ERR(dentry);
+	if (IS_ERR(dentry))
+		return error;
+	inode = dentry->d_inode;
+
 	if (!S_ISREG(inode->i_mode)) {
-		iput(inode);
-		return(-EACCES);
+		dput(dentry);
+		return -EACCES;
 	}
-	if ((filp = get_empty_filp()) != (struct file *)NULL) {
+
+	filp = get_empty_filp();
+	if (filp != NULL) {
 		filp->f_mode = (O_RDWR + 1) & O_ACCMODE;
 		filp->f_flags = O_RDWR;
-		filp->f_inode = inode;
+		filp->f_dentry = dentry;
 		filp->f_pos = 0;
 		filp->f_reada = 0;
 		filp->f_op = inode->i_op->default_file_ops;
 		if (filp->f_op->read || filp->f_op->write) {
-			if ((error = get_write_access(inode)) == 0) {
+			error = get_write_access(inode);
+			if (!error) {
 				if (filp->f_op && filp->f_op->open)
 					error = filp->f_op->open(inode, filp);
-				if (error == 0) {
+				if (!error) {
 					vfsmnt->mnt_quotas[type] = filp;
 					dquot = dqget(dev, 0, type);
 					vfsmnt->mnt_iexp[type] = (dquot) ? dquot->dq_itime : MAX_IQ_TIME;
@@ -987,7 +1000,7 @@
 					dqput(dquot);
 					vfsmnt->mnt_sb->dq_op = &dquot_operations;
 					add_dquot_ref(dev, type);
-					return(0);
+					return 0;
 				}
 				put_write_access(inode);
 			}
@@ -996,8 +1009,8 @@
 		put_filp(filp);
 	} else
 		error = -EMFILE;
-	iput(inode);
-	return(error);
+	dput(dentry);
+	return error;
 }
 
 /*
@@ -1009,7 +1022,6 @@
 asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr)
 {
 	int cmds = 0, type = 0, flags = 0;
-	struct inode *ino;
 	kdev_t dev;
 	int ret = -EINVAL;
 
@@ -1035,19 +1047,22 @@
 	}
 
 	ret = -EINVAL;
-	if (special == (char *)NULL && (cmds == Q_SYNC || cmds == Q_GETSTATS))
-		dev = 0;
-	else {
-		int error = namei(special, &ino);
-		if(error)
+	dev = 0;
+	if (special != NULL || (cmds != Q_SYNC && cmds != Q_GETSTATS)) {
+		mode_t mode;
+		struct dentry * dentry;
+
+		dentry = namei(special);
+		if (IS_ERR(dentry))
 			goto out;
-		dev = ino->i_rdev;
+
+		dev = dentry->d_inode->i_rdev;
+		mode = dentry->d_inode->i_mode;
+		dput(dentry);
+
 		ret = -ENOTBLK;
-		if (!S_ISBLK(ino->i_mode)) {
-			iput(ino);
+		if (!S_ISBLK(mode))
 			goto out;
-		}
-		iput(ino);
 	}
 
 	ret = -EINVAL;
diff -u --recursive --new-file v2.1.44/linux/fs/exec.c linux/fs/exec.c
--- v2.1.44/linux/fs/exec.c	Mon Jun 16 16:35:57 1997
+++ linux/fs/exec.c	Wed Jul 16 19:22:51 1997
@@ -84,6 +84,10 @@
 	init_aout_binfmt();
 #endif
 
+#ifdef CONFIG_BINFMT_AOUT32
+	init_aout32_binfmt();
+#endif
+
 #ifdef CONFIG_BINFMT_JAVA
 	init_java_binfmt();
 #endif
@@ -130,22 +134,24 @@
 }
 #endif	/* CONFIG_MODULES */
 
-int open_inode(struct inode * inode, int mode)
+int open_dentry(struct dentry * dentry, int mode)
 {
 	int fd;
+	struct inode * inode = dentry->d_inode;
 
 	if (!inode->i_op || !inode->i_op->default_file_ops)
 		return -EINVAL;
 	fd = get_unused_fd();
 	if (fd >= 0) {
 		struct file * f = get_empty_filp();
+
 		if (!f) {
 			put_unused_fd(fd);
 			return -ENFILE;
 		}
 		f->f_flags = mode;
 		f->f_mode = (mode+1) & O_ACCMODE;
-		f->f_inode = inode;
+		f->f_dentry = dentry;
 		f->f_pos = 0;
 		f->f_reada = 0;
 		f->f_op = inode->i_op->default_file_ops;
@@ -158,7 +164,7 @@
 			}
 		}
 		current->files->fd[fd] = f;
-		atomic_inc(&inode->i_count);
+		dget(dentry);
 	}
 	return fd;
 }
@@ -182,7 +188,7 @@
 		goto out;
 	file = current->files->fd[fd];
 	retval = -ENOEXEC;
-	if (file && file->f_inode && file->f_op && file->f_op->read) {
+	if (file && file->f_dentry && file->f_op && file->f_op->read) {
 		for (fmt = formats ; fmt ; fmt = fmt->next) {
 			int (*fn)(int) = fmt->load_shlib;
 			if (!fn)
@@ -316,7 +322,7 @@
 		mpnt->vm_flags = VM_STACK_FLAGS;
 		mpnt->vm_ops = NULL;
 		mpnt->vm_offset = 0;
-		mpnt->vm_inode = NULL;
+		mpnt->vm_dentry = NULL;
 		mpnt->vm_pte = 0;
 		insert_vm_struct(current->mm, mpnt);
 		current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
@@ -337,10 +343,11 @@
  * that aren't on a block boundary, and for files on filesystems
  * without bmap support.
  */
-int read_exec(struct inode *inode, unsigned long offset,
+int read_exec(struct dentry *dentry, unsigned long offset,
 	char * addr, unsigned long count, int to_kmem)
 {
 	struct file file;
+	struct inode * inode = dentry->d_inode;
 	int result = -ENOEXEC;
 
 	if (!inode->i_op || !inode->i_op->default_file_ops)
@@ -348,7 +355,7 @@
 	file.f_mode = 1;
 	file.f_flags = 0;
 	file.f_count = 1;
-	file.f_inode = inode;
+	file.f_dentry = dentry;
 	file.f_pos = 0;
 	file.f_reada = 0;
 	file.f_op = inode->i_op->default_file_ops;
@@ -477,7 +484,7 @@
 	flush_thread();
 
 	if (bprm->e_uid != current->euid || bprm->e_gid != current->egid || 
-	    permission(bprm->inode,MAY_READ))
+	    permission(bprm->dentry->d_inode,MAY_READ))
 		current->dumpable = 0;
 
 	flush_old_signals(current->sig);
@@ -492,20 +499,21 @@
 {
 	int mode;
 	int retval,id_change;
+	struct inode * inode = bprm->dentry->d_inode;
 
-	mode = bprm->inode->i_mode;
+	mode = inode->i_mode;
 	if (!S_ISREG(mode))			/* must be regular file */
 		return -EACCES;
 	if (!(mode & 0111))			/* with at least _one_ execute bit set */
 		return -EACCES;
-	if (IS_NOEXEC(bprm->inode))		/* FS mustn't be mounted noexec */
+	if (IS_NOEXEC(inode))			/* FS mustn't be mounted noexec */
 		return -EACCES;
-	if (!bprm->inode->i_sb)
+	if (!inode->i_sb)
 		return -EACCES;
-	if ((retval = permission(bprm->inode, MAY_EXEC)) != 0)
+	if ((retval = permission(inode, MAY_EXEC)) != 0)
 		return retval;
 	/* better not execute files which are being written to */
-	if (bprm->inode->i_writecount > 0)
+	if (inode->i_writecount > 0)
 		return -ETXTBSY;
 
 	bprm->e_uid = current->euid;
@@ -514,7 +522,7 @@
 
 	/* Set-uid? */
 	if (mode & S_ISUID) {
-		bprm->e_uid = bprm->inode->i_uid;
+		bprm->e_uid = inode->i_uid;
 		if (bprm->e_uid != current->euid)
 			id_change = 1;
 	}
@@ -526,7 +534,7 @@
 	 * executable.
 	 */
 	if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
-		bprm->e_gid = bprm->inode->i_gid;
+		bprm->e_gid = inode->i_gid;
 		if (!in_group_p(bprm->e_gid))
 			id_change = 1;
 	}
@@ -535,7 +543,7 @@
 		/* We can't suid-execute if we're sharing parts of the executable */
 		/* or if we're being traced (or if suid execs are not allowed)    */
 		/* (current->mm->count > 1 is ok, as we'll get a new mm anyway)   */
-		if (IS_NOSUID(bprm->inode)
+		if (IS_NOSUID(inode)
 		    || (current->flags & PF_PTRACED)
 		    || (current->fs->count > 1)
 		    || (atomic_read(&current->sig->count) > 1)
@@ -546,7 +554,7 @@
 	}
 
 	memset(bprm->buf,0,sizeof(bprm->buf));
-	return read_exec(bprm->inode,0,bprm->buf,128,1);
+	return read_exec(bprm->dentry,0,bprm->buf,128,1);
 }
 
 void remove_arg_zero(struct linux_binprm *bprm)
@@ -581,16 +589,19 @@
 		(eh->fh.f_flags & 0x3000) == 0x3000)
 	    {
 		char * dynloader[] = { "/sbin/loader" };
-		iput(bprm->inode);
-		bprm->dont_iput = 1;
+		struct dentry * dentry;
+
+		dput(bprm->dentry);
+		bprm->dentry = NULL;
 		remove_arg_zero(bprm);
 		bprm->p = copy_strings(1, dynloader, bprm->page, bprm->p, 2);
 		bprm->argc++;
 		bprm->loader = bprm->p;
-		retval = open_namei(dynloader[0], 0, 0, &bprm->inode, NULL);
-		if (retval)
+		dentry = open_namei(dynloader[0], 0, 0);
+		retval = PTR_ERR(dentry);
+		if (IS_ERR(dentry))
 			return retval;
-		bprm->dont_iput = 0;
+		bprm->dentry = dentry;
 		retval = prepare_binprm(bprm);
 		if (retval<0)
 			return retval;
@@ -606,15 +617,15 @@
 				continue;
 			retval = fn(bprm, regs);
 			if (retval >= 0) {
-				if(!bprm->dont_iput)
-					iput(bprm->inode);
-				bprm->dont_iput=1;
+				if (bprm->dentry)
+					dput(bprm->dentry);
+				bprm->dentry = NULL;
 				current->did_exec = 1;
 				return retval;
 			}
 			if (retval != -ENOEXEC)
 				break;
-			if (bprm->dont_iput) /* We don't have the inode anymore*/
+			if (!bprm->dentry) /* We don't have the dentry anymore */
 				return retval;
 		}
 		if (retval != -ENOEXEC) {
@@ -643,29 +654,38 @@
 int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs)
 {
 	struct linux_binprm bprm;
+	struct dentry * dentry;
 	int retval;
 	int i;
 
 	bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
 	for (i=0 ; i<MAX_ARG_PAGES ; i++)	/* clear page-table */
 		bprm.page[i] = 0;
-	retval = open_namei(filename, 0, 0, &bprm.inode, NULL);
-	if (retval)
+
+	dentry = open_namei(filename, 0, 0);
+	retval = PTR_ERR(dentry);
+	if (IS_ERR(dentry))
 		return retval;
+
+	bprm.dentry = dentry;
 	bprm.filename = filename;
 	bprm.sh_bang = 0;
 	bprm.java = 0;
 	bprm.loader = 0;
 	bprm.exec = 0;
-	bprm.dont_iput = 0;
-	if ((bprm.argc = count(argv)) < 0)
+	if ((bprm.argc = count(argv)) < 0) {
+		dput(dentry);
 		return bprm.argc;
-	if ((bprm.envc = count(envp)) < 0)
+	}
+
+	if ((bprm.envc = count(envp)) < 0) {
+		dput(dentry);
 		return bprm.envc;
+	}
 
 	retval = prepare_binprm(&bprm);
 	
-	if(retval>=0) {
+	if (retval >= 0) {
 		bprm.p = copy_strings(1, &bprm.filename, bprm.page, bprm.p, 2);
 		bprm.exec = bprm.p;
 		bprm.p = copy_strings(bprm.envc,envp,bprm.page,bprm.p,0);
@@ -674,16 +694,18 @@
 			retval = -E2BIG;
 	}
 
-	if(retval>=0)
+	if (retval >= 0)
 		retval = search_binary_handler(&bprm,regs);
-	if(retval>=0)
+	if (retval >= 0)
 		/* execve success */
 		return retval;
 
 	/* Something went wrong, return the inode and free the argument pages*/
-	if(!bprm.dont_iput)
-		iput(bprm.inode);
+	if (bprm.dentry)
+		dput(bprm.dentry);
+
 	for (i=0 ; i<MAX_ARG_PAGES ; i++)
 		free_page(bprm.page[i]);
-	return(retval);
+
+	return retval;
 }
diff -u --recursive --new-file v2.1.44/linux/fs/ext2/dir.c linux/fs/ext2/dir.c
--- v2.1.44/linux/fs/ext2/dir.c	Sat Jul  5 20:53:22 1997
+++ linux/fs/ext2/dir.c	Tue Jul  8 16:05:38 1997
@@ -212,9 +212,6 @@
 		offset = 0;
 		brelse (bh);
 	}
-	if (DO_UPDATE_ATIME(inode)) {
-		inode->i_atime = CURRENT_TIME;
-		inode->i_dirt = 1;
-	}
+	UPDATE_ATIME(inode);
 	return 0;
 }
diff -u --recursive --new-file v2.1.44/linux/fs/ext2/file.c linux/fs/ext2/file.c
--- v2.1.44/linux/fs/ext2/file.c	Sat Jul  5 20:53:22 1997
+++ linux/fs/ext2/file.c	Tue Jul  8 16:06:07 1997
@@ -122,7 +122,7 @@
 	mode &= inode->i_mode;
 	if (mode && !suser()) {
 		inode->i_mode &= ~mode;
-		inode->i_dirt = 1;
+		mark_inode_dirty(inode);
 	}
 }
 
@@ -251,7 +251,7 @@
 		inode->u.ext2_i.i_osync--;
 	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
 	filp->f_pos = pos;
-	inode->i_dirt = 1;
+	mark_inode_dirty(inode);
 	return written;
 }
 
diff -u --recursive --new-file v2.1.44/linux/fs/ext2/ialloc.c linux/fs/ext2/ialloc.c
--- v2.1.44/linux/fs/ext2/ialloc.c	Mon Jun 16 16:35:57 1997
+++ linux/fs/ext2/ialloc.c	Wed Jul 16 11:25:42 1997
@@ -171,9 +171,8 @@
 		printk ("ext2_free_inode: inode has no device\n");
 		return;
 	}
-	if (atomic_read(&inode->i_count) > 1) {
-		printk ("ext2_free_inode: inode has count=%d\n",
-			atomic_read(&inode->i_count));
+	if (inode->i_count > 1) {
+		printk ("ext2_free_inode: inode has count=%d\n", inode->i_count);
 		return;
 	}
 	if (inode->i_nlink) {
@@ -216,7 +215,6 @@
 		es->s_free_inodes_count =
 			cpu_to_le32(le32_to_cpu(es->s_free_inodes_count) + 1);
 		mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
-		inode->i_dirt = 0;
 	}
 	mark_buffer_dirty(bh, 1);
 	if (sb->s_flags & MS_SYNCHRONOUS) {
@@ -240,7 +238,7 @@
 			       int mode)
 {
 	inode->u.ext2_i.i_version++;
-	inode->i_dirt = 1;
+	mark_inode_dirty(inode);
 
 	return;
 }
@@ -404,7 +402,6 @@
 	sb->s_dirt = 1;
 	inode->i_mode = mode;
 	inode->i_sb = sb;
-	atomic_set(&inode->i_count, 1);
 	inode->i_nlink = 1;
 	inode->i_dev = sb->s_dev;
 	inode->i_uid = current->fsuid;
@@ -416,7 +413,7 @@
 			mode |= S_ISGID;
 	} else
 		inode->i_gid = current->fsgid;
-	inode->i_dirt = 1;
+	mark_inode_dirty(inode);
 	inode->i_ino = j;
 	inode->i_blksize = PAGE_SIZE;	/* This is the optimal IO size (for stat), not the fs block size */
 	inode->i_blocks = 0;
diff -u --recursive --new-file v2.1.44/linux/fs/ext2/inode.c linux/fs/ext2/inode.c
--- v2.1.44/linux/fs/ext2/inode.c	Tue May 13 22:41:14 1997
+++ linux/fs/ext2/inode.c	Wed Jul 16 10:26:21 1997
@@ -31,14 +31,24 @@
 
 static int ext2_update_inode(struct inode * inode, int do_sync);
 
+/*
+ * Called at each iput()
+ */
 void ext2_put_inode (struct inode * inode)
 {
 	ext2_discard_prealloc (inode);
-	if (inode->i_nlink || inode->i_ino == EXT2_ACL_IDX_INO ||
+}
+
+/*
+ * Called at the last iput() if i_nlink is zero.
+ */
+void ext2_delete_inode (struct inode * inode)
+{
+	if (inode->i_ino == EXT2_ACL_IDX_INO ||
 	    inode->i_ino == EXT2_ACL_DATA_INO)
 		return;
 	inode->u.ext2_i.i_dtime	= CURRENT_TIME;
-	inode->i_dirt = 1;
+	mark_inode_dirty(inode);
 	ext2_update_inode(inode, IS_SYNC(inode));
 	inode->i_size = 0;
 	if (inode->i_blocks)
@@ -248,7 +258,7 @@
 	if (IS_SYNC(inode) || inode->u.ext2_i.i_osync)
 		ext2_sync_inode (inode);
 	else
-		inode->i_dirt = 1;
+		mark_inode_dirty(inode);
 	return result;
 }
 
@@ -322,7 +332,7 @@
 	}
 	inode->i_ctime = CURRENT_TIME;
 	inode->i_blocks += blocks;
-	inode->i_dirt = 1;
+	mark_inode_dirty(inode);
 	inode->u.ext2_i.i_next_alloc_block = new_block;
 	inode->u.ext2_i.i_next_alloc_goal = tmp;
 	brelse (bh);
@@ -591,7 +601,6 @@
 	else for (block = 0; block < EXT2_N_BLOCKS; block++)
 		raw_inode->i_block[block] = cpu_to_le32(inode->u.ext2_i.i_data[block]);
 	mark_buffer_dirty(bh, 1);
-	inode->i_dirt = 0;
 	if (do_sync) {
 		ll_rw_block (WRITE, 1, &bh);
 		wait_on_buffer (bh);
@@ -671,7 +680,7 @@
 		inode->i_flags &= ~S_IMMUTABLE;
 		inode->u.ext2_i.i_flags &= ~EXT2_IMMUTABLE_FL;
 	}
-	inode->i_dirt = 1;
+	mark_inode_dirty(inode);
 
 	return 0;
 }
diff -u --recursive --new-file v2.1.44/linux/fs/ext2/ioctl.c linux/fs/ext2/ioctl.c
--- v2.1.44/linux/fs/ext2/ioctl.c	Tue May 13 22:41:14 1997
+++ linux/fs/ext2/ioctl.c	Tue Jul  8 16:07:59 1997
@@ -62,7 +62,7 @@
 		else
 			inode->i_flags &= ~MS_NOATIME;
 		inode->i_ctime = CURRENT_TIME;
-		inode->i_dirt = 1;
+		mark_inode_dirty(inode);
 		return 0;
 	case EXT2_IOC_GETVERSION:
 		return put_user(inode->u.ext2_i.i_version, (int *) arg);
@@ -74,7 +74,7 @@
 		if (get_user(inode->u.ext2_i.i_version, (int *) arg))
 			return -EFAULT;	
 		inode->i_ctime = CURRENT_TIME;
-		inode->i_dirt = 1;
+		mark_inode_dirty(inode);
 		return 0;
 	default:
 		return -ENOTTY;
diff -u --recursive --new-file v2.1.44/linux/fs/ext2/namei.c linux/fs/ext2/namei.c
--- v2.1.44/linux/fs/ext2/namei.c	Mon Jul  7 11:29:42 1997
+++ linux/fs/ext2/namei.c	Wed Jul 16 15:25:25 1997
@@ -155,31 +155,26 @@
 	return NULL;
 }
 
-int ext2_lookup(struct inode * dir, struct qstr *name, struct inode ** result)
+int ext2_lookup(struct inode * dir, struct dentry *dentry)
 {
-	unsigned long ino;
+	struct inode * inode;
 	struct ext2_dir_entry * de;
 	struct buffer_head * bh;
 
-	*result = NULL;
-	if (!dir)
-		return -ENOENT;
-
-	if (!S_ISDIR(dir->i_mode))
-		return -ENOTDIR;
-
-	if (name->len > EXT2_NAME_LEN)
+	if (dentry->d_name.len > EXT2_NAME_LEN)
 		return -ENAMETOOLONG;
 
-	ino = dir->i_version;
-	if (!(bh = ext2_find_entry (dir, name->name, name->len, &de)))
-		return -ENOENT;
-
-	ino = le32_to_cpu(de->inode);
-	brelse (bh);
-	if (!(*result = iget (dir->i_sb, ino)))
-		return -EACCES;
+	bh = ext2_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
+	inode = NULL;
+	if (bh) {
+		unsigned long ino = le32_to_cpu(de->inode);
+		brelse (bh);
+		inode = iget(dir->i_sb, ino);
 
+		if (!inode)
+			return -EACCES;
+	}
+	d_add(dentry, inode);
 	return 0;
 }
 
@@ -252,7 +247,7 @@
 				de->inode = le32_to_cpu(0);
 				de->rec_len = le16_to_cpu(sb->s_blocksize);
 				dir->i_size = offset + sb->s_blocksize;
-				dir->i_dirt = 1;
+				mark_inode_dirty(dir);
 			} else {
 
 				ext2_debug ("skipping to next block\n");
@@ -297,7 +292,7 @@
 			 * and/or different from the directory change time.
 			 */
 			dir->i_mtime = dir->i_ctime = CURRENT_TIME;
-			dir->i_dirt = 1;
+			mark_inode_dirty(dir);
 			dir->i_version = ++event;
 			mark_buffer_dirty(bh, 1);
 			*res_dir = de;
@@ -346,10 +341,10 @@
 /*
  * By the time this is called, we already have created
  * the directory cache entry for the new file, but it
- * is so far marked "D_NEGATIVE".
+ * is so far negative - it has no inode.
  *
- * If the create succeeds, remove the D_NEGATIVE flag,
- * and fill in the inode information with d_instantiate().
+ * If the create succeeds, we fill in the inode information
+ * with d_instantiate(). 
  */
 int ext2_create (struct inode * dir, struct dentry * dentry, int mode)
 {
@@ -366,11 +361,11 @@
 
 	inode->i_op = &ext2_file_inode_operations;
 	inode->i_mode = mode;
-	inode->i_dirt = 1;
+	mark_inode_dirty(inode);
 	bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
 	if (!bh) {
 		inode->i_nlink--;
-		inode->i_dirt = 1;
+		mark_inode_dirty(inode);
 		iput (inode);
 		return err;
 	}
@@ -382,7 +377,7 @@
 		wait_on_buffer (bh);
 	}
 	brelse (bh);
-	d_instantiate(dentry, inode, 0);
+	d_instantiate(dentry, inode);
 	return 0;
 }
 
@@ -423,11 +418,11 @@
 		init_fifo(inode);
 	if (S_ISBLK(mode) || S_ISCHR(mode))
 		inode->i_rdev = to_kdev_t(rdev);
-	inode->i_dirt = 1;
+	mark_inode_dirty(inode);
 	bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
 	if (!bh) {
 		inode->i_nlink--;
-		inode->i_dirt = 1;
+		mark_inode_dirty(inode);
 		iput(inode);
 		return err;
 	}
@@ -439,7 +434,7 @@
 		wait_on_buffer (bh);
 	}
 	brelse(bh);
-	d_instantiate(dentry, inode, 0);
+	d_instantiate(dentry, inode);
 	return 0;
 }
 
@@ -465,7 +460,7 @@
 	dir_block = ext2_bread (inode, 0, 1, &err);
 	if (!dir_block) {
 		inode->i_nlink--;
-		inode->i_dirt = 1;
+		mark_inode_dirty(inode);
 		iput (inode);
 		return err;
 	}
@@ -486,11 +481,11 @@
 	inode->i_mode = S_IFDIR | (mode & (S_IRWXUGO|S_ISVTX) & ~current->fs->umask);
 	if (dir->i_mode & S_ISGID)
 		inode->i_mode |= S_ISGID;
-	inode->i_dirt = 1;
+	mark_inode_dirty(inode);
 	bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
 	if (!bh) {
 		inode->i_nlink = 0;
-		inode->i_dirt = 1;
+		mark_inode_dirty(inode);
 		iput (inode);
 		return err;
 	}
@@ -502,8 +497,8 @@
 		wait_on_buffer (bh);
 	}
 	dir->i_nlink++;
-	dir->i_dirt = 1;
-	d_instantiate(dentry, inode, D_DIR);
+	mark_inode_dirty(dir);
+	d_instantiate(dentry, inode);
 	brelse (bh);
 	return 0;
 }
@@ -613,7 +608,7 @@
 	else if (le32_to_cpu(de->inode) != inode->i_ino)
 		retval = -ENOENT;
 	else {
-		if (atomic_read(&inode->i_count) > 1) {
+		if (inode->i_count > 1) {
 		/*
 		 * Are we deleting the last instance of a busy directory?
 		 * Better clean up if so.
@@ -640,10 +635,10 @@
 			      inode->i_nlink);
 	inode->i_version = ++event;
 	inode->i_nlink = 0;
-	inode->i_dirt = 1;
+	mark_inode_dirty(inode);
 	dir->i_nlink--;
 	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
-	dir->i_dirt = 1;
+	mark_inode_dirty(dir);
 	d_delete(dentry);
 
 end_rmdir:
@@ -701,9 +696,9 @@
 		wait_on_buffer (bh);
 	}
 	dir->i_ctime = dir->i_mtime = CURRENT_TIME;
-	dir->i_dirt = 1;
+	mark_inode_dirty(dir);
 	inode->i_nlink--;
-	inode->i_dirt = 1;
+	mark_inode_dirty(inode);
 	inode->i_ctime = dir->i_ctime;
 	retval = 0;
 	d_delete(dentry);	/* This also frees the inode */
@@ -738,7 +733,7 @@
 		name_block = ext2_bread (inode, 0, 1, &err);
 		if (!name_block) {
 			inode->i_nlink--;
-			inode->i_dirt = 1;
+			mark_inode_dirty(inode);
 			iput (inode);
 			return err;
 		}
@@ -758,12 +753,12 @@
 		brelse (name_block);
 	}
 	inode->i_size = i;
-	inode->i_dirt = 1;
+	mark_inode_dirty(inode);
 
 	bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
 	if (!bh) {
 		inode->i_nlink--;
-		inode->i_dirt = 1;
+		mark_inode_dirty(inode);
 		iput (inode);
 		return err;
 	}
@@ -775,7 +770,7 @@
 		wait_on_buffer (bh);
 	}
 	brelse (bh);
-	d_instantiate(dentry, inode, 0);
+	d_instantiate(dentry, inode);
 	return 0;
 }
 
@@ -808,33 +803,31 @@
 	brelse (bh);
 	inode->i_nlink++;
 	inode->i_ctime = CURRENT_TIME;
-	inode->i_dirt = 1;
-	atomic_inc(&inode->i_count);
-	d_instantiate(dentry, inode, 0);
+	mark_inode_dirty(inode);
+	inode->i_count++;
+	d_instantiate(dentry, inode);
 	return 0;
 }
 
-static int subdir (struct inode * new_inode, struct inode * old_inode)
+/*
+ * Trivially implemented using the dcache structure
+ */
+static int subdir (struct dentry * new_dentry, struct dentry * old_dentry)
 {
-	int ino;
 	int result;
 
-	atomic_inc(&new_inode->i_count);
 	result = 0;
 	for (;;) {
-		if (new_inode == old_inode) {
-			result = 1;
-			break;
-		}
-		if (new_inode->i_dev != old_inode->i_dev)
-			break;
-		ino = new_inode->i_ino;
-		if (ext2_lookup (new_inode, &(struct qstr) { "..", 2, 0 }, &new_inode))
-			break;
-		if (new_inode->i_ino == ino)
-			break;
+		if (new_dentry != old_dentry) {
+			struct dentry * parent = new_dentry->d_parent;
+			if (parent == new_dentry)
+				break;
+			new_dentry = parent;
+			continue;
+		}
+		result = 1;
+		break;
 	}
-	iput (new_inode);
 	return result;
 }
 
@@ -842,10 +835,6 @@
 	((struct ext2_dir_entry *) ((char *) buffer + \
 	le16_to_cpu(((struct ext2_dir_entry *) buffer)->rec_len)))->inode
 
-#define PARENT_NAME(buffer) \
-	((struct ext2_dir_entry *) ((char *) buffer + \
-	le16_to_cpu(((struct ext2_dir_entry *) buffer)->rec_len)))->name
-
 /*
  * rename uses retrying to avoid race-conditions: at least they should be
  * minimal.
@@ -906,13 +895,13 @@
 		if (!S_ISDIR(old_inode->i_mode))
 			goto end_rename;
 		retval = -EINVAL;
-		if (subdir (new_dir, old_inode))
+		if (subdir(new_dentry, old_dentry))
 			goto end_rename;
 		retval = -ENOTEMPTY;
 		if (!empty_dir (new_inode))
 			goto end_rename;
 		retval = -EBUSY;
-		if (atomic_read(&new_inode->i_count) > 1)
+		if (new_inode->i_count > 1)
 			goto end_rename;
 	}
 	retval = -EPERM;
@@ -925,7 +914,7 @@
 		if (new_inode && !S_ISDIR(new_inode->i_mode))
 			goto end_rename;
 		retval = -EINVAL;
-		if (subdir (new_dir, old_inode))
+		if (subdir(new_dentry, old_dentry))
 			goto end_rename;
 		dir_bh = ext2_bread (old_inode, 0, 0, &retval);
 		if (!dir_bh)
@@ -953,21 +942,21 @@
 	if (new_inode) {
 		new_inode->i_nlink--;
 		new_inode->i_ctime = CURRENT_TIME;
-		new_inode->i_dirt = 1;
+		mark_inode_dirty(new_inode);
 	}
 	old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
-	old_dir->i_dirt = 1;
+	mark_inode_dirty(old_dir);
 	if (dir_bh) {
 		PARENT_INO(dir_bh->b_data) = le32_to_cpu(new_dir->i_ino);
 		mark_buffer_dirty(dir_bh, 1);
 		old_dir->i_nlink--;
-		old_dir->i_dirt = 1;
+		mark_inode_dirty(old_dir);
 		if (new_inode) {
 			new_inode->i_nlink--;
-			new_inode->i_dirt = 1;
+			mark_inode_dirty(new_inode);
 		} else {
 			new_dir->i_nlink++;
-			new_dir->i_dirt = 1;
+			mark_inode_dirty(new_dir);
 		}
 	}
 	mark_buffer_dirty(old_bh,  1);
diff -u --recursive --new-file v2.1.44/linux/fs/ext2/super.c linux/fs/ext2/super.c
--- v2.1.44/linux/fs/ext2/super.c	Tue Jul  1 16:42:12 1997
+++ linux/fs/ext2/super.c	Wed Jul 16 10:26:21 1997
@@ -133,9 +133,10 @@
 
 static struct super_operations ext2_sops = {
 	ext2_read_inode,
-	NULL,
 	ext2_write_inode,
 	ext2_put_inode,
+	ext2_delete_inode,
+	NULL,
 	ext2_put_super,
 	ext2_write_super,
 	ext2_statfs,
@@ -762,7 +763,7 @@
 
 #endif
 
-void ext2_statfs (struct super_block * sb, struct statfs * buf, int bufsiz)
+int ext2_statfs (struct super_block * sb, struct statfs * buf, int bufsiz)
 {
 	unsigned long overhead;
 	unsigned long overhead_per_group;
@@ -793,5 +794,5 @@
 	tmp.f_files = le32_to_cpu(sb->u.ext2_sb.s_es->s_inodes_count);
 	tmp.f_ffree = ext2_count_free_inodes (sb);
 	tmp.f_namelen = EXT2_NAME_LEN;
-	copy_to_user(buf, &tmp, bufsiz);
+	return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
 }
diff -u --recursive --new-file v2.1.44/linux/fs/ext2/symlink.c linux/fs/ext2/symlink.c
--- v2.1.44/linux/fs/ext2/symlink.c	Sun Jul  6 21:31:52 1997
+++ linux/fs/ext2/symlink.c	Tue Jul  8 16:10:44 1997
@@ -65,10 +65,7 @@
 		}
 		link = bh->b_data;
 	}
-	if (!IS_RDONLY(inode)) {
-		inode->i_atime = CURRENT_TIME;
-		inode->i_dirt = 1;
-	}
+	UPDATE_ATIME(inode);
 	base = lookup_dentry(link, base, 1);
 	if (bh)
 		brelse(bh);
@@ -101,10 +98,7 @@
 		i++;
 	if (copy_to_user(buffer, link, i))
 		i = -EFAULT;
- 	if (DO_UPDATE_ATIME(inode)) {
-		inode->i_atime = CURRENT_TIME;
-		inode->i_dirt = 1;
-	}
+ 	UPDATE_ATIME(inode);
 	if (bh)
 		brelse (bh);
 	return i;
diff -u --recursive --new-file v2.1.44/linux/fs/ext2/truncate.c linux/fs/ext2/truncate.c
--- v2.1.44/linux/fs/ext2/truncate.c	Thu Nov 14 00:27:38 1996
+++ linux/fs/ext2/truncate.c	Fri Jul 11 21:56:02 1997
@@ -91,7 +91,7 @@
 		}
 		*p = 0;
 		inode->i_blocks -= blocks;
-		inode->i_dirt = 1;
+		mark_inode_dirty(inode);
 		bforget(bh);
 		if (free_count == 0) {
 			block_to_free = tmp;
@@ -110,7 +110,8 @@
 	return retry;
 }
 
-static int trunc_indirect (struct inode * inode, int offset, u32 * p)
+static int trunc_indirect (struct inode * inode, int offset, u32 * p,
+			   int in_inode)
 {
 	int i, tmp;
 	struct buffer_head * bh;
@@ -124,103 +125,16 @@
 #define INDIRECT_BLOCK ((int)DIRECT_BLOCK - offset)
 	int indirect_block = INDIRECT_BLOCK;
 
-	tmp = *p;
+	tmp = in_inode ? *p : le32_to_cpu(*p);
 	if (!tmp)
 		return 0;
 	ind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize);
-	if (tmp != *p) {
-		brelse (ind_bh);
-		return 1;
-	}
-	if (!ind_bh) {
-		*p = 0;
-		return 0;
-	}
-repeat:
-	for (i = indirect_block ; i < addr_per_block ; i++) {
-		if (i < 0)
-			i = 0;
-		if (i < indirect_block)
-			goto repeat;
-		ind = i + (u32 *) ind_bh->b_data;
-		tmp = le32_to_cpu(*ind);
-		if (!tmp)
-			continue;
-		bh = get_hash_table (inode->i_dev, tmp,
-				     inode->i_sb->s_blocksize);
-		if (i < indirect_block) {
-			brelse (bh);
-			goto repeat;
-		}
-		if ((bh && bh->b_count != 1) || tmp != le32_to_cpu(*ind)) {
-			retry = 1;
-			brelse (bh);
-			continue;
-		}
-		*ind = cpu_to_le32(0);
-		mark_buffer_dirty(ind_bh, 1);
-		bforget(bh);
-		if (free_count == 0) {
-			block_to_free = tmp;
-			free_count++;
-		} else if (free_count > 0 && block_to_free == tmp - free_count)
-			free_count++;
-		else {
-			ext2_free_blocks (inode, block_to_free, free_count);
-			block_to_free = tmp;
-			free_count = 1;
-		}
-/*		ext2_free_blocks (inode, tmp, 1); */
-		inode->i_blocks -= blocks;
-		inode->i_dirt = 1;
-	}
-	if (free_count > 0)
-		ext2_free_blocks (inode, block_to_free, free_count);
-	ind = (u32 *) ind_bh->b_data;
-	for (i = 0; i < addr_per_block; i++)
-		if (le32_to_cpu(*(ind++)))
-			break;
-	if (i >= addr_per_block)
-		if (ind_bh->b_count != 1)
-			retry = 1;
-		else {
-			tmp = *p;
-			*p = 0;
-			inode->i_blocks -= blocks;
-			inode->i_dirt = 1;
-			ext2_free_blocks (inode, tmp, 1);
-		}
-	if (IS_SYNC(inode) && buffer_dirty(ind_bh)) {
-		ll_rw_block (WRITE, 1, &ind_bh);
-		wait_on_buffer (ind_bh);
-	}
-	brelse (ind_bh);
-	return retry;
-}
-
-static int trunc_indirect_swab32 (struct inode * inode, int offset, u32 * p)
-{
-	int i, tmp;
-	struct buffer_head * bh;
-	struct buffer_head * ind_bh;
-	u32 * ind;
-	unsigned long block_to_free = 0;
-	unsigned long free_count = 0;
-	int retry = 0;
-	int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
-	int blocks = inode->i_sb->s_blocksize / 512;
-	int indirect_block = INDIRECT_BLOCK;
-
-	tmp = le32_to_cpu(*p);
-	if (!tmp)
-		return 0;
-	ind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize);
-	if (tmp != le32_to_cpu(*p)) {
+	if (tmp != (in_inode ? *p : le32_to_cpu(*p))) {
 		brelse (ind_bh);
 		return 1;
 	}
 	if (!ind_bh) {
-		*p = cpu_to_le32(0);
+		*p = in_inode ? 0 : cpu_to_le32(0);
 		return 0;
 	}
 repeat:
@@ -259,7 +173,7 @@
 		}
 /*		ext2_free_blocks (inode, tmp, 1); */
 		inode->i_blocks -= blocks;
-		inode->i_dirt = 1;
+		mark_inode_dirty(inode);
 	}
 	if (free_count > 0)
 		ext2_free_blocks (inode, block_to_free, free_count);
@@ -271,13 +185,15 @@
 		if (ind_bh->b_count != 1)
 			retry = 1;
 		else {
-			tmp = le32_to_cpu(*p);
-			*p = cpu_to_le32(0);
+			tmp = in_inode ? *p : le32_to_cpu(*p);
+			*p = in_inode ? 0 : cpu_to_le32(0);
 			inode->i_blocks -= blocks;
-			inode->i_dirt = 1;
+			mark_inode_dirty(inode);
 			ext2_free_blocks (inode, tmp, 1);
+			bforget(ind_bh);
+			ind_bh = NULL;
 		}
-	if (IS_SYNC(inode) && buffer_dirty(ind_bh)) {
+	if (IS_SYNC(inode) && ind_bh && buffer_dirty(ind_bh)) {
 		ll_rw_block (WRITE, 1, &ind_bh);
 		wait_on_buffer (ind_bh);
 	}
@@ -286,7 +202,7 @@
 }
 
 static int trunc_dindirect (struct inode * inode, int offset,
-			    u32 * p)
+			    u32 * p, int in_inode)
 {
 	int i, tmp;
 	struct buffer_head * dind_bh;
@@ -297,75 +213,16 @@
 #define DINDIRECT_BLOCK (((int)DIRECT_BLOCK - offset) / addr_per_block)
 	int dindirect_block = DINDIRECT_BLOCK;
 
-	tmp = *p;
-	if (!tmp)
-		return 0;
-	dind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize);
-	if (tmp != *p) {
-		brelse (dind_bh);
-		return 1;
-	}
-	if (!dind_bh) {
-		*p = 0;
-		return 0;
-	}
-repeat:
-	for (i = dindirect_block ; i < addr_per_block ; i++) {
-		if (i < 0)
-			i = 0;
-		if (i < dindirect_block)
-			goto repeat;
-		dind = i + (u32 *) dind_bh->b_data;
-		tmp = le32_to_cpu(*dind);
-		if (!tmp)
-			continue;
-		retry |= trunc_indirect_swab32 (inode, offset + (i * addr_per_block),
-						dind);
-		mark_buffer_dirty(dind_bh, 1);
-	}
-	dind = (u32 *) dind_bh->b_data;
-	for (i = 0; i < addr_per_block; i++)
-		if (le32_to_cpu(*(dind++)))
-			break;
-	if (i >= addr_per_block)
-		if (dind_bh->b_count != 1)
-			retry = 1;
-		else {
-			tmp = *p;
-			*p = 0;
-			inode->i_blocks -= blocks;
-			inode->i_dirt = 1;
-			ext2_free_blocks (inode, tmp, 1);
-		}
-	if (IS_SYNC(inode) && buffer_dirty(dind_bh)) {
-		ll_rw_block (WRITE, 1, &dind_bh);
-		wait_on_buffer (dind_bh);
-	}
-	brelse (dind_bh);
-	return retry;
-}
-
-static int trunc_dindirect_swab32 (struct inode * inode, int offset,
-				   u32 * p)
-{
-	int i, tmp;
-	struct buffer_head * dind_bh;
-	u32 * dind;
-	int retry = 0;
-	int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
-	int blocks = inode->i_sb->s_blocksize / 512;
-	int dindirect_block = DINDIRECT_BLOCK;
-
-	tmp = le32_to_cpu(*p);
+	tmp = in_inode ? *p : le32_to_cpu(*p);
 	if (!tmp)
 		return 0;
 	dind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize);
-	if (tmp != le32_to_cpu(*p)) {
+	if (tmp != (in_inode ? *p : le32_to_cpu(*p))) {
 		brelse (dind_bh);
 		return 1;
 	}
 	if (!dind_bh) {
-		*p = cpu_to_le32(0);
+		*p = in_inode ? 0 : cpu_to_le32(0);
 		return 0;
 	}
 repeat:
@@ -378,8 +235,8 @@
 		tmp = le32_to_cpu(*dind);
 		if (!tmp)
 			continue;
-		retry |= trunc_indirect_swab32 (inode, offset + (i * addr_per_block),
-						dind);
+		retry |= trunc_indirect(inode, offset + (i * addr_per_block),
+					dind, 0);
 		mark_buffer_dirty(dind_bh, 1);
 	}
 	dind = (u32 *) dind_bh->b_data;
@@ -390,13 +247,15 @@
 		if (dind_bh->b_count != 1)
 			retry = 1;
 		else {
-			tmp = le32_to_cpu(*p);
-			*p = cpu_to_le32(0);
+			tmp = in_inode ? *p : le32_to_cpu(*p);
+			*p = in_inode ? 0 : cpu_to_le32(0);
 			inode->i_blocks -= blocks;
-			inode->i_dirt = 1;
+			mark_inode_dirty(inode);
 			ext2_free_blocks (inode, tmp, 1);
+			bforget(dind_bh);
+			dind_bh = 0;
 		}
-	if (IS_SYNC(inode) && buffer_dirty(dind_bh)) {
+	if (IS_SYNC(inode) && dind_bh && buffer_dirty(dind_bh)) {
 		ll_rw_block (WRITE, 1, &dind_bh);
 		wait_on_buffer (dind_bh);
 	}
@@ -436,9 +295,9 @@
 		if (i < tindirect_block)
 			goto repeat;
 		tind = i + (u32 *) tind_bh->b_data;
-		retry |= trunc_dindirect_swab32(inode, EXT2_NDIR_BLOCKS +
+		retry |= trunc_dindirect(inode, EXT2_NDIR_BLOCKS +
 			 addr_per_block + (i + 1) * addr_per_block * addr_per_block,
-			 tind);
+			 tind, 0);
 		mark_buffer_dirty(tind_bh, 1);
 	}
 	tind = (u32 *) tind_bh->b_data;
@@ -452,10 +311,12 @@
 			tmp = *p;
 			*p = 0;
 			inode->i_blocks -= blocks;
-			inode->i_dirt = 1;
+			mark_inode_dirty(inode);
 			ext2_free_blocks (inode, tmp, 1);
+			bforget(tind_bh);
+			tind_bh = 0;
 		}
-	if (IS_SYNC(inode) && buffer_dirty(tind_bh)) {
+	if (IS_SYNC(inode) && tind_bh && buffer_dirty(tind_bh)) {
 		ll_rw_block (WRITE, 1, &tind_bh);
 		wait_on_buffer (tind_bh);
 	}
@@ -479,14 +340,14 @@
 	while (1) {
 		retry = trunc_direct(inode);
 		retry |= trunc_indirect (inode, EXT2_IND_BLOCK,
-			(u32 *) &inode->u.ext2_i.i_data[EXT2_IND_BLOCK]);
+			(u32 *) &inode->u.ext2_i.i_data[EXT2_IND_BLOCK], 1);
 		retry |= trunc_dindirect (inode, EXT2_IND_BLOCK +
 			EXT2_ADDR_PER_BLOCK(inode->i_sb),
-			(u32 *) &inode->u.ext2_i.i_data[EXT2_DIND_BLOCK]);
+			(u32 *) &inode->u.ext2_i.i_data[EXT2_DIND_BLOCK], 1);
 		retry |= trunc_tindirect (inode);
 		if (!retry)
 			break;
-		if (IS_SYNC(inode) && inode->i_dirt)
+		if (IS_SYNC(inode) && test_bit(I_DIRTY, &inode->i_state))
 			ext2_sync_inode (inode);
 		current->counter = 0;
 		schedule ();
@@ -510,5 +371,5 @@
 		}
 	}
 	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-	inode->i_dirt = 1;
+	mark_inode_dirty(inode);
 }
diff -u --recursive --new-file v2.1.44/linux/fs/fat/cache.c linux/fs/fat/cache.c
--- v2.1.44/linux/fs/fat/cache.c	Sat Dec 21 04:24:02 1996
+++ linux/fs/fat/cache.c	Wed Jul 16 08:05:24 1997
@@ -280,7 +280,7 @@
 		    12 ? EOF_FAT12 : EOF_FAT16);
 	else {
 		MSDOS_I(inode)->i_start = 0;
-		inode->i_dirt = 1;
+		mark_inode_dirty(inode);
 	}
 	lock_fat(inode->i_sb);
 	while (nr != -1) {
diff -u --recursive --new-file v2.1.44/linux/fs/fat/file.c linux/fs/fat/file.c
--- v2.1.44/linux/fs/fat/file.c	Mon Jun 16 16:35:57 1997
+++ linux/fs/fat/file.c	Wed Jul 16 08:13:34 1997
@@ -52,6 +52,7 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
+	NULL,			/* follow_link */
 	generic_readpage,	/* readpage */
 	NULL,			/* writepage */
 	fat_bmap,		/* bmap */
@@ -99,6 +100,7 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
+	NULL,			/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
@@ -355,7 +357,7 @@
 		filp->f_pos += written;
 		if (filp->f_pos > inode->i_size) {
 			inode->i_size = filp->f_pos;
-			inode->i_dirt = 1;
+			mark_inode_dirty(inode);
 		}
 		fat_set_uptodate(sb, bh, 1);
 		fat_mark_buffer_dirty(sb, bh, 0);
@@ -365,7 +367,7 @@
 		return error;
 	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 	MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
-	inode->i_dirt = 1;
+	mark_inode_dirty(inode);
 	return buf-start;
 }
 
@@ -379,5 +381,5 @@
 	cluster = SECTOR_SIZE*MSDOS_SB(inode->i_sb)->cluster_size;
 	(void) fat_free(inode,(inode->i_size+(cluster-1))/cluster);
 	MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
-	inode->i_dirt = 1;
+	mark_inode_dirty(inode);
 }
diff -u --recursive --new-file v2.1.44/linux/fs/fat/inode.c linux/fs/fat/inode.c
--- v2.1.44/linux/fs/fat/inode.c	Mon Apr  7 11:35:30 1997
+++ linux/fs/fat/inode.c	Wed Jul 16 08:18:24 1997
@@ -196,6 +196,7 @@
 	int debug,error,fat;
 	int blksize = 512;
 	struct fat_mount_options opts;
+	struct inode *root_inode;
 
 	MOD_INC_USE_COUNT;
 	if (hardsect_size[MAJOR(sb->s_dev)] != NULL){
@@ -329,7 +330,10 @@
 	MSDOS_SB(sb)->fat_lock = 0;
 	MSDOS_SB(sb)->prev_free = 0;
 	memcpy(&(MSDOS_SB(sb)->options), &opts, sizeof(struct fat_mount_options));
-	if (!(sb->s_mounted = iget(sb,MSDOS_ROOT_INO))) {
+
+	root_inode = iget(sb,MSDOS_ROOT_INO);
+	sb->s_root = d_alloc_root(root_inode, NULL);
+	if (!sb->s_root) {
 		sb->s_dev = 0;
 		printk("get root inode failed\n");
 		MOD_DEC_USE_COUNT;
@@ -339,7 +343,7 @@
 }
 
 
-void fat_statfs(struct super_block *sb,struct statfs *buf, int bufsiz)
+int fat_statfs(struct super_block *sb,struct statfs *buf, int bufsiz)
 {
 	int free,nr;
 	struct statfs tmp;
@@ -362,7 +366,7 @@
 	tmp.f_files = 0;
 	tmp.f_ffree = 0;
 	tmp.f_namelen = 12;
-	copy_to_user(buf, &tmp, bufsiz);
+	return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
 }
 
 
@@ -514,10 +518,9 @@
 		linked->i_blocks = inode->i_blocks;
 		linked->i_atime = inode->i_atime;
 		MSDOS_I(linked)->i_attrs = MSDOS_I(inode)->i_attrs;
-		linked->i_dirt = 1;
+		mark_inode_dirty(linked);
 	}
 
-	inode->i_dirt = 0;
 	if (inode->i_ino == MSDOS_ROOT_INO || !inode->i_nlink) return;
 	if (!(bh = fat_bread(sb, inode->i_ino >> MSDOS_DPB_BITS))) {
 		printk("dev = %s, ino = %ld\n",
diff -u --recursive --new-file v2.1.44/linux/fs/fat/misc.c linux/fs/fat/misc.c
--- v2.1.44/linux/fs/fat/misc.c	Thu Jul  3 13:18:33 1997
+++ linux/fs/fat/misc.c	Wed Jul 16 08:15:05 1997
@@ -40,9 +40,7 @@
 
 	not_ro = !(s->s_flags & MS_RDONLY);
 	if (not_ro) s->s_flags |= MS_RDONLY;
-	printk("Filesystem panic (dev %s, ", kdevname(s->s_dev));
-	printk("mounted on %s:%ld)\n  %s\n", /* note: kdevname returns & static char[] */
-	       kdevname(s->s_covered->i_dev), s->s_covered->i_ino, msg);
+	printk("Filesystem panic (dev %s).", kdevname(s->s_dev));
 	if (not_ro)
 		printk("  File system has been set read-only\n");
 }
@@ -180,7 +178,7 @@
 	if (last) fat_access(sb,last,nr);
 	else {
 		MSDOS_I(inode)->i_start = nr;
-		inode->i_dirt = 1;
+		mark_inode_dirty(inode);
 	}
 #ifdef DEBUG
 if (last) printk("next set to %d\n",fat_access(sb,last,-1));
@@ -217,7 +215,7 @@
 #ifdef DEBUG
 printk("size is %d now (%x)\n",inode->i_size,inode);
 #endif
-		inode->i_dirt = 1;
+		mark_inode_dirty(inode);
 	}
 	return 0;
 }
diff -u --recursive --new-file v2.1.44/linux/fs/fat/mmap.c linux/fs/fat/mmap.c
--- v2.1.44/linux/fs/fat/mmap.c	Mon Jun 16 16:35:57 1997
+++ linux/fs/fat/mmap.c	Wed Jul 16 19:22:51 1997
@@ -29,7 +29,7 @@
 	unsigned long address,
 	int error_code)
 {
-	struct inode * inode = area->vm_inode;
+	struct inode * inode = area->vm_dentry->d_inode;
 	unsigned long page;
 	unsigned int clear;
 	int pos;
@@ -101,11 +101,10 @@
 		return -EACCES;
 	if (!IS_RDONLY(inode)) {
 		inode->i_atime = CURRENT_TIME;
-		inode->i_dirt = 1;
+		mark_inode_dirty(inode);
 	}
 
-	vma->vm_inode = inode;
-	atomic_inc(&inode->i_count);
+	vma->vm_dentry = dget(file->f_dentry);
 	vma->vm_ops = &fat_file_mmap;
 	return 0;
 }
diff -u --recursive --new-file v2.1.44/linux/fs/fcntl.c linux/fs/fcntl.c
--- v2.1.44/linux/fs/fcntl.c	Tue May 13 22:41:14 1997
+++ linux/fs/fcntl.c	Sun Jul 13 21:20:10 1997
@@ -67,6 +67,34 @@
 	return ret;
 }
 
+#define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | FASYNC)
+
+static int setfl(struct file * filp, unsigned long arg)
+{
+	struct inode * inode = filp->f_dentry->d_inode;
+
+	/*
+	 * In the case of an append-only file, O_APPEND
+	 * cannot be cleared
+	 */
+	if (!(arg & O_APPEND) && IS_APPEND(inode))
+		return -EPERM;
+
+	/* Did FASYNC state change? */
+	if ((arg ^ filp->f_flags) & FASYNC) {
+		if (filp->f_op->fasync)
+			filp->f_op->fasync(inode, filp, (arg & FASYNC) != 0);
+	}
+
+	/* required for strict SunOS emulation */
+	if (O_NONBLOCK != O_NDELAY)
+	       if (arg & O_NDELAY)
+		   arg |= O_NONBLOCK;
+
+	filp->f_flags = (arg & SETFL_MASK) | (filp->f_flags & ~SETFL_MASK);
+	return 0;
+}
+
 asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
 {	
 	struct file * filp;
@@ -95,28 +123,7 @@
 			err = filp->f_flags;
 			break;
 		case F_SETFL:
-			/*
-			 * In the case of an append-only file, O_APPEND
-			 * cannot be cleared
-			 */
-			err = -EPERM;
-			if (IS_APPEND(filp->f_inode) && !(arg & O_APPEND))
-				break;
-			err = 0;
-			if ((arg & FASYNC) && !(filp->f_flags & FASYNC) &&
-			    filp->f_op->fasync)
-				filp->f_op->fasync(filp->f_inode, filp, 1);
-			if (!(arg & FASYNC) && (filp->f_flags & FASYNC) &&
-			    filp->f_op->fasync)
-				filp->f_op->fasync(filp->f_inode, filp, 0);
-			/* required for strict SunOS emulation */
-			if (O_NONBLOCK != O_NDELAY)
-			       if (arg & O_NDELAY)
-				   arg |= O_NONBLOCK;
-			filp->f_flags &= ~(O_APPEND | O_NONBLOCK | 
-					   O_NDELAY | FASYNC);
-			filp->f_flags |= arg & (O_APPEND | O_NONBLOCK |
-						O_NDELAY | FASYNC);
+			err = setfl(filp, arg);
 			break;
 		case F_GETLK:
 			err = fcntl_getlk(fd, (struct flock *) arg);
@@ -186,12 +193,12 @@
 		fasync_ok:
 			err = 0;
 			filp->f_owner = arg;
-			if (S_ISSOCK (filp->f_inode->i_mode))
+			if (S_ISSOCK (filp->f_dentry->d_inode->i_mode))
 				err = sock_fcntl (filp, F_SETOWN, arg);
 			break;
 		default:
 			/* sockets need a few special fcntls. */
-			if (S_ISSOCK (filp->f_inode->i_mode))
+			if (S_ISSOCK (filp->f_dentry->d_inode->i_mode))
 				err = sock_fcntl (filp, cmd, arg);
 			else
 				err = -EINVAL;
diff -u --recursive --new-file v2.1.44/linux/fs/fifo.c linux/fs/fifo.c
--- v2.1.44/linux/fs/fifo.c	Mon Jun 16 16:35:57 1997
+++ linux/fs/fifo.c	Wed Jul 16 10:26:21 1997
@@ -153,7 +153,6 @@
 void init_fifo(struct inode * inode)
 {
 	inode->i_op = &fifo_inode_operations;
-	inode->i_pipe = 1;
 	PIPE_LOCK(*inode) = 0;
 	PIPE_BASE(*inode) = NULL;
 	PIPE_START(*inode) = PIPE_LEN(*inode) = 0;
diff -u --recursive --new-file v2.1.44/linux/fs/file_table.c linux/fs/file_table.c
--- v2.1.44/linux/fs/file_table.c	Thu May 15 16:48:04 1997
+++ linux/fs/file_table.c	Sun Jul 13 21:20:10 1997
@@ -109,11 +109,15 @@
 	struct file *filp;
 
 	for (filp = inuse_filps; filp; filp = filp->f_next) {
-		if (!filp->f_inode || filp->f_inode->i_dev != dev)
+		struct inode * inode;
+		if (!filp->f_dentry)
 			continue;
-		if (filp->f_mode & FMODE_WRITE && filp->f_inode->i_sb->dq_op) {
-			filp->f_inode->i_sb->dq_op->initialize(filp->f_inode, type);
-			filp->f_inode->i_flags |= S_WRITE;
+		inode = filp->f_dentry->d_inode;
+		if (!inode || inode->i_dev != dev)
+			continue;
+		if (filp->f_mode & FMODE_WRITE && inode->i_sb->dq_op) {
+			inode->i_sb->dq_op->initialize(inode, type);
+			inode->i_flags |= S_WRITE;
 		}
 	}
 }
@@ -123,11 +127,15 @@
 	struct file *filp;
 
 	for (filp = inuse_filps; filp; filp = filp->f_next) {
-		if (!filp->f_inode || filp->f_inode->i_dev != dev)
+		struct inode * inode;
+		if (!filp->f_dentry)
+			continue;
+		inode = filp->f_dentry->d_inode;
+		if (!inode || inode->i_dev != dev)
 			continue;
-		if (IS_WRITABLE(filp->f_inode)) {
-			filp->f_inode->i_dquot[type] = NODQUOT;
-			filp->f_inode->i_flags &= ~S_WRITE;
+		if (IS_WRITABLE(inode)) {
+			inode->i_dquot[type] = NODQUOT;
+			inode->i_flags &= ~S_WRITE;
 		}
 	}
 }
diff -u --recursive --new-file v2.1.44/linux/fs/filesystems.c linux/fs/filesystems.c
--- v2.1.44/linux/fs/filesystems.c	Mon Jun 16 16:35:57 1997
+++ linux/fs/filesystems.c	Thu Jul 10 16:09:03 1997
@@ -8,7 +8,6 @@
 
 #include <linux/config.h>
 #include <linux/fs.h>
-#include <linux/nametrans.h>
 
 #include <linux/minix_fs.h>
 #include <linux/ext2_fs.h>
@@ -44,10 +43,6 @@
 	device_setup();
 
 	binfmt_setup();
-
-#ifdef CONFIG_TRANS_NAMES
-	init_nametrans();
-#endif
 
 #ifdef CONFIG_EXT2_FS
 	init_ext2_fs();
diff -u --recursive --new-file v2.1.44/linux/fs/inode.c linux/fs/inode.c
--- v2.1.44/linux/fs/inode.c	Mon Jul  7 16:28:05 1997
+++ linux/fs/inode.c	Wed Jul 16 16:56:52 1997
@@ -1,623 +1,457 @@
 /*
- * fs/inode.c
+ * linux/fs/inode.c
  *
- * Complete reimplementation
- * (C) 1997 Thomas Schoebel-Theuer
+ * (C) 1997 Linus Torvalds
  */
 
-/* Everything here is intended to be MP-safe. However, other parts
- * of the kernel are not yet MP-safe, in particular the inode->i_count++
- * that are spread over everywhere. These should be replaced by
- * iinc() as soon as possible. Since I have no MP machine, I could
- * not test it.
- */
-#include <linux/config.h>
-#include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/string.h>
 #include <linux/mm.h>
-#include <linux/kernel.h>
-#include <linux/dlists.h>
-#include <linux/dalloc.h>
-#include <linux/omirr.h>
-
-/* #define DEBUG */
-
-#define HASH_SIZE 1024 /* must be a power of 2 */
-#define NR_LEVELS 4
-
-#define ST_AGED      1
-#define ST_HASHED    2
-#define ST_EMPTY     4
-#define ST_TO_READ   8
-#define ST_TO_WRITE 16
-#define ST_TO_PUT   32
-#define ST_TO_DROP  64
-#define ST_IO       (ST_TO_READ|ST_TO_WRITE|ST_TO_PUT|ST_TO_DROP)
-#define ST_WAITING 128
-#define ST_FREEING 256
-#define ST_IBASKET 512
-
-/* The idea is to keep empty inodes in a separate list, so no search
- * is required as long as empty inodes exit.
- * All reusable inodes occurring in the hash table with i_count==0
- * are also registered in the ringlist aged_i[level], but in LRU order.
- * Used inodes with i_count>0 are kept solely in the hashtable and in
- * all_i, but in no other list.
- * The level is used for multilevel aging to avoid thrashing; each
- * time i_count decreases to 0, the inode is inserted into the next level
- * ringlist. Cache reusage is simply by taking the _last_ element from the
- * lowest-level ringlist that contains inodes.
- * In contrast to the old code, there isn't any O(n) search overhead now
- * in iget/iput (if you make HASH_SIZE large enough).
- */
-static struct inode * hashtable[HASH_SIZE];/* linked with i_hash_{next,prev} */
-static struct inode * all_i = NULL;        /* linked with i_{next,prev} */
-static struct inode * empty_i = NULL;      /* linked with i_{next,prev} */
-static struct inode * aged_i[NR_LEVELS+1]; /* linked with i_lru_{next,prev} */
-static int aged_reused[NR_LEVELS+1];       /* # removals from aged_i[level] */
-static int age_table[NR_LEVELS+1] = { /* You may tune this. */
-	1, 4, 10, 100, 1000
-}; /* after which # of uses to increase to the next level */
 
-/* This is for kernel/sysctl.c */
+/*
+ * New inode.c implementation.
+ *
+ * This implementation has the basic premise of trying
+ * to be extremely low-overhead and SMP-safe, yet be
+ * simple enough to be "obviously correct".
+ *
+ * Famous last words.
+ */
+
+/*
+ * Inode lookup is no longer as critical as it used to be:
+ * most of the lookups are going to be through the dcache.
+ */
+#define HASH_BITS	8
+#define HASH_SIZE	(1UL << HASH_BITS)
+#define HASH_MASK	(HASH_SIZE-1)
+
+/*
+ * Each inode can be on two separate lists. One is
+ * the hash list of the inode, used for lookups. The
+ * other linked list is the "type" list:
+ *  "in_use" - valid inode, hashed
+ *  "dirty" - valid inode, hashed, dirty.
+ *  "unused" - ready to be re-used. Not hashed.
+ *
+ * The two first versions also have a dirty list, allowing
+ * for low-overhead inode sync() operations.
+ */
+
+static LIST_HEAD(inode_in_use);
+static LIST_HEAD(inode_dirty);
+static LIST_HEAD(inode_unused);
+static struct list_head inode_hashtable[HASH_SIZE];
+
+/*
+ * A simple spinlock to protect the list manipulations
+ */
+spinlock_t inode_lock = SPIN_LOCK_UNLOCKED;
 
-/* Just aligning plain ints and arrays thereof doesn't work reliably.. */
+/*
+ * Statistics gathering.. Not actually done yet.
+ */
 struct {
 	int nr_inodes;
 	int nr_free_inodes;
-	int aged_count[NR_LEVELS+1];        /* # in each level */
+	int dummy[10];
 } inodes_stat;
 
 int max_inodes = NR_INODE;
-unsigned long last_inode = 0;
 
-void inode_init(void)
-{
-	memset(hashtable, 0, sizeof(hashtable));
-	memset(aged_i, 0, sizeof(aged_i));
-	memset(aged_reused, 0, sizeof(aged_reused));
-	memset(&inodes_stat, 0, sizeof(inodes_stat));
-}
-
-/* Intended for short locks of the above global data structures.
- * Could be replaced with spinlocks completely, since there is
- * no blocking during manipulation of the static data; however the
- * lock in invalidate_inodes() may last relatively long.
- */
-#ifdef __SMP__
-struct semaphore vfs_sem = MUTEX;
-#endif
-
-DEF_INSERT(all,struct inode,i_next,i_prev)
-DEF_REMOVE(all,struct inode,i_next,i_prev)
-	
-DEF_INSERT(lru,struct inode,i_lru_next,i_lru_prev)
-DEF_REMOVE(lru,struct inode,i_lru_next,i_lru_prev)
-
-DEF_INSERT(hash,struct inode,i_hash_next,i_hash_prev)
-DEF_REMOVE(hash,struct inode,i_hash_next,i_hash_prev)
-
-DEF_INSERT(ibasket,struct inode,i_basket_next,i_basket_prev)
-DEF_REMOVE(ibasket,struct inode,i_basket_next,i_basket_prev)
-
-#ifdef DEBUG
-extern void printpath(struct dentry * entry);
-struct inode * xtst[15000];
-int xcnt = 0;
-
-void xcheck(char * txt, struct inode * p)
+void __mark_inode_dirty(struct inode *inode)
 {
-	int i;
-	for(i=xcnt-1; i>=0; i--)
-		if (xtst[i] == p)
-			return;
-	printk("Bogus inode %p in %s\n", p, txt);
-}
-#else
-#define xcheck(t,p) /*nothing*/
-#endif
-
-static inline struct inode * grow_inodes(void)
-{
-	struct inode * res;
-	struct inode * inode = res = (struct inode*)__get_free_page(GFP_KERNEL);
-	int size = PAGE_SIZE;
-	if (!inode)
-		return NULL;
-	
-	size -= sizeof(struct inode);
-	inode++;
-	inodes_stat.nr_inodes++;
-#ifdef DEBUG
-xtst[xcnt++]=res;
-#endif
-	while(size >= sizeof(struct inode)) {
-#ifdef DEBUG
-xtst[xcnt++]=inode;
-#endif
-		inodes_stat.nr_inodes++;
-		inodes_stat.nr_free_inodes++;
-		insert_all(&empty_i, inode);
-		inode->i_status = ST_EMPTY;
-		inode++;
-		size -= sizeof(struct inode);
-	}
-	return res;
+	spin_lock(&inode_lock);
+	list_del(&inode->i_list);
+	list_add(&inode->i_list, &inode_dirty);
+	spin_unlock(&inode_lock);
 }
 
-static inline int hash(dev_t i_dev, unsigned long i_ino)
+static inline void unlock_inode(struct inode *inode)
 {
-	return ((int)i_ino ^ ((int)i_dev << 6)) & (HASH_SIZE-1);
+	clear_bit(I_LOCK, &inode->i_state);
+	wake_up(&inode->i_wait);
 }
 
-static inline blocking void wait_io(struct inode * inode, unsigned short flags)
+static void __wait_on_inode(struct inode * inode)
 {
-	while(inode->i_status & flags) {
-		struct wait_queue wait = {current, NULL};
-		inode->i_status |= ST_WAITING;
-		vfs_unlock();
-		add_wait_queue(&inode->i_wait, &wait);
-		sleep_on(&inode->i_wait);
-		remove_wait_queue(&inode->i_wait, &wait);
-		vfs_lock();
-	}
-}
+	struct wait_queue wait = { current, NULL };
 
-static inline blocking void set_io(struct inode * inode,
-				   unsigned short waitflags,
-				   unsigned short setflags)
-{
-	wait_io(inode, waitflags);
-	inode->i_status |= setflags;
-	vfs_unlock();
-}
-
-static inline blocking int release_io(struct inode * inode, unsigned short flags)
-{
-	int res = 0; 
-	vfs_lock();
-	inode->i_status &= ~flags;
-	if (inode->i_status & ST_WAITING) {
-		inode->i_status &= ~ST_WAITING;
-		vfs_unlock();
-		wake_up(&inode->i_wait);
-		res = 1;
+	add_wait_queue(&inode->i_wait, &wait);
+repeat:
+	current->state = TASK_UNINTERRUPTIBLE;
+	if (test_bit(I_LOCK, &inode->i_state)) {
+		schedule();
+		goto repeat;
 	}
-	return res;
+	remove_wait_queue(&inode->i_wait, &wait);
+	current->state = TASK_RUNNING;
 }
 
-static inline blocking void _io(void (*op)(struct inode*), struct inode * inode,
-				unsigned short waitflags, unsigned short setflags)
+static inline void wait_on_inode(struct inode *inode)
 {
-	/* Do nothing if the same op is already in progress. */
-	if (op && !(inode->i_status & setflags)) {
-		set_io(inode, waitflags, setflags);
-		op(inode);
-		if (release_io(inode, setflags)) {
-			/* Somebody grabbed my inode from under me. */
-#ifdef DEBUG
-			printk("_io grab!\n");
-#endif
-                        vfs_lock();
-		}
-	}
+	if (test_bit(I_LOCK, &inode->i_state))
+		__wait_on_inode(inode);
 }
 
-blocking void _clear_inode(struct inode * inode, int external, int verbose)
+/*
+ * These are initializations that only need to be done
+ * once, because the fields are idempotent across use
+ * of the inode..
+ */
+static inline void init_once(struct inode * inode)
 {
-xcheck("_clear_inode",inode);
-	if (inode->i_status & ST_IBASKET) {
-		struct super_block * sb = inode->i_sb;
-		remove_ibasket(&sb->s_ibasket, inode);
-		sb->s_ibasket_count--;
-		inode->i_status &= ~ST_IBASKET;
-#if 0
-printpath(inode->i_dentry);
-printk(" put_inode\n");
-#endif
-		_io(sb->s_op->put_inode, inode, ST_TO_PUT|ST_TO_WRITE, ST_TO_PUT);
-		if (inode->i_status & ST_EMPTY)
-			return;
-	}
-	if (inode->i_status & ST_HASHED)
-		remove_hash(&hashtable[hash(inode->i_dev, inode->i_ino)], inode);
-	if (inode->i_status & ST_AGED) {
-		/* "cannot happen" when called from an fs because at least
-		 * the caller must use it. Can happen when called from
-		 * invalidate_inodes(). */
-		if (verbose)
-			printk("VFS: clearing aged inode\n");
-		if (atomic_read(&inode->i_count))
-			printk("VFS: aged inode is in use\n");
-		remove_lru(&aged_i[inode->i_level], inode);
-		inodes_stat.aged_count[inode->i_level]--;
-	}
-	if (!external && inode->i_status & ST_IO) {
-		printk("VFS: clearing inode during IO operation\n");
-	}
-	if (!(inode->i_status & ST_EMPTY)) {
-		remove_all(&all_i, inode);
-		inode->i_status = ST_EMPTY;
-		if (inode->i_pages) {
-			vfs_unlock(); /* may block, can that be revised? */
-			truncate_inode_pages(inode, 0);
-			vfs_lock();
-		}
-		insert_all(&empty_i, inode);
-		inodes_stat.nr_free_inodes++;
-	} else if(external)
-		printk("VFS: empty inode is unnecessarily cleared multiple "
-		       "times by an fs\n");
-        else
-		printk("VFS: clearing empty inode\n");
-	inode->i_status = ST_EMPTY;
-	/* The inode is not really cleared any more here, but only once
-	 * when taken from empty_i. This saves instructions and processor
-	 * cache pollution.
-	 */
+	memset(inode, 0, sizeof(*inode));
+	init_waitqueue(&inode->i_wait);
+	INIT_LIST_HEAD(&inode->i_dentry);
+	INIT_LIST_HEAD(&inode->i_hash);
+	sema_init(&inode->i_sem, 1);
 }
 
-void insert_inode_hash(struct inode * inode)
-{
-xcheck("insert_inode_hash",inode);
-	vfs_lock();
-	if (!(inode->i_status & ST_HASHED)) {
-		insert_hash(&hashtable[hash(inode->i_dev, inode->i_ino)], inode);
-		inode->i_status |= ST_HASHED;
-	} else
-		printk("VFS: trying to hash an inode again\n");
-	vfs_unlock();
-}
 
-blocking struct inode * _get_empty_inode(void)
+/*
+ * Look out! This returns with the inode lock held if
+ * it got an inode..
+ */
+static struct inode * grow_inodes(void)
 {
-	struct inode * inode;
-	int retry = 0;
+	struct inode * inode = (struct inode *)__get_free_page(GFP_KERNEL);
 
-retry:
-	inode = empty_i;
 	if (inode) {
-		remove_all(&empty_i, inode);
-		inodes_stat.nr_free_inodes--;
-	} else if(inodes_stat.nr_inodes < max_inodes || retry > 2) {
-		inode = grow_inodes();
-	}
-	if (!inode) {
-		int level;
-		int usable = 0;
-		for(level = 0; level <= NR_LEVELS; level++)
-			if (aged_i[level]) {
-				inode = aged_i[level]->i_lru_prev;
-				/* Here is the picking strategy, tune this */
-				if (aged_reused[level] < (usable++ ?
-							 inodes_stat.aged_count[level] :
-							 2))
-					break;
-				aged_reused[level] = 0;
-			}
-		if (inode) {
-			if (!(inode->i_status & ST_AGED))
-				printk("VFS: inode aging inconsistency\n");
-			if (atomic_read(&inode->i_count))
-				printk("VFS: i_count of aged inode is not zero\n");
-			if (inode->i_dirt)
-				printk("VFS: Hey, somebody made my aged inode dirty\n");
-			_clear_inode(inode, 0, 0);
-			goto retry;
-		}
-	}
-	if (!inode) {
-		vfs_unlock();
-		schedule();
-		if (retry > 10)
-			panic("VFS: cannot repair inode shortage");
-		if (retry > 2)
-			printk("VFS: no free inodes\n");
-		retry++;
-		vfs_lock();
-		goto retry;
+		int size;
+		struct inode * tmp;
+
+		spin_lock(&inode_lock);
+		size = PAGE_SIZE - 2*sizeof(struct inode);
+		tmp = inode;
+		do {
+			tmp++;
+			init_once(tmp);
+			list_add(&tmp->i_list, &inode_unused);
+			size -= sizeof(struct inode);
+		} while (size >= 0);
+		init_once(inode);
 	}
-xcheck("get_empty_inode",inode);
-	memset(inode, 0, sizeof(struct inode));
-	atomic_set(&inode->i_count, 1);
-	inode->i_nlink = 1;
-	sema_init(&inode->i_sem, 1);
-	inode->i_ino = ++last_inode;
-	inode->i_version = ++event;
-	insert_all(&all_i, inode);
 	return inode;
 }
 
-static inline blocking struct inode * _get_empty_inode_hashed(dev_t i_dev,
-							      unsigned long i_ino)
+static inline void write_inode(struct inode *inode)
 {
-	struct inode ** base = &hashtable[hash(i_dev, i_ino)];
-	struct inode * inode = *base;
-	if (inode) do {
-		if (inode->i_ino == i_ino && inode->i_dev == i_dev) {
-			atomic_inc(&inode->i_count);
-			printk("VFS: inode %lx is already in use\n", i_ino);
-			return inode;
-		}
-		inode = inode->i_hash_next;
-	} while(inode != *base);
-	inode = _get_empty_inode();
-	inode->i_dev = i_dev;
-	inode->i_ino = i_ino;
-	insert_hash(base, inode);
-	inode->i_status |= ST_HASHED;
-	return inode;
+	if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->write_inode)
+		inode->i_sb->s_op->write_inode(inode);
 }
 
-blocking struct inode * get_empty_inode_hashed(dev_t i_dev, unsigned long i_ino)
+static inline void sync_list(struct list_head *head, struct list_head *clean)
 {
-	struct inode * inode;
+	struct list_head * tmp;
+
+	while ((tmp = head->prev) != head) {
+		struct inode *inode = list_entry(tmp, struct inode, i_list);
+		list_del(tmp);
+
+		/*
+		 * If the inode is locked, it's already being written out.
+		 * We have to wait for it, though.
+		 */
+		if (test_bit(I_LOCK, &inode->i_state)) {
+			list_add(tmp, head);
+			spin_unlock(&inode_lock);
+			__wait_on_inode(inode);
+		} else {
+			list_add(tmp, clean);
+			clear_bit(I_DIRTY, &inode->i_state);
+			set_bit(I_LOCK, &inode->i_state);
+			spin_unlock(&inode_lock);
+			write_inode(inode);
+			unlock_inode(inode);
+		}
+		spin_lock(&inode_lock);
+	}	
+}
 
-	vfs_lock();
-	inode = _get_empty_inode_hashed(i_dev, i_ino);
-	vfs_unlock();
-	return inode;
+/*
+ * "sync_inodes()" goes through the dirty list 
+ * and writes them out and puts them back on
+ * the normal list.
+ */
+void sync_inodes(kdev_t dev)
+{
+	spin_lock(&inode_lock);
+	sync_list(&inode_dirty, &inode_in_use);
+	spin_unlock(&inode_lock);
 }
 
-void _get_inode(struct inode * inode)
+/*
+ * This is called by the filesystem to tell us
+ * that the inode is no longer useful. We just
+ * terminate it with extreme predjudice.
+ */
+void clear_inode(struct inode *inode)
 {
-	if (inode->i_status & ST_IBASKET) {
-		inode->i_status &= ~ST_IBASKET;
-		remove_ibasket(&inode->i_sb->s_ibasket, inode);
-		inode->i_sb->s_ibasket_count--;
-	}
-	if (inode->i_status & ST_AGED) {
-		inode->i_status &= ~ST_AGED;
-		remove_lru(&aged_i[inode->i_level], inode);
-		inodes_stat.aged_count[inode->i_level]--;
-		aged_reused[inode->i_level]++;
-		if (S_ISDIR(inode->i_mode))
-			/* make dirs less thrashable */
-			inode->i_level = NR_LEVELS-1;
-		else if(inode->i_nlink > 1)
-			/* keep hardlinks totally separate */
-			inode->i_level = NR_LEVELS;
-		else if(++inode->i_reuse_count >= age_table[inode->i_level]
-			&& inode->i_level < NR_LEVELS-1)
-			inode->i_level++;
-		if (atomic_read(&inode->i_count) != 1)
-			printk("VFS: inode count was not zero (%d after ++)\n", atomic_read(&inode->i_count));
-	} else if(inode->i_status & ST_EMPTY)
-		printk("VFS: invalid reuse of empty inode\n");
+	truncate_inode_pages(inode, 0);
+	wait_on_inode(inode);
+	if (IS_WRITABLE(inode) && inode->i_sb && inode->i_sb->dq_op)
+		inode->i_sb->dq_op->drop(inode);
+
+	inode->i_state = 0;
 }
 
-blocking struct inode * iget(struct super_block * sb, unsigned long i_ino)
+#define CAN_UNUSE(inode) \
+	(((inode)->i_count == 0) && \
+	 ((inode)->i_nrpages == 0) && \
+	 (!(inode)->i_state))
+
+static void invalidate_list(struct list_head *head, kdev_t dev)
 {
-	struct inode ** base;
-	struct inode * inode;
-	dev_t i_dev;
-	
-	if (!sb)
-		panic("VFS: iget with sb == NULL");
-	i_dev = sb->s_dev;
-	if (!i_dev)
-		panic("VFS: sb->s_dev is NULL\n");
-	base = &hashtable[hash(i_dev, i_ino)];
-	vfs_lock();
-	inode = *base;
-	if (inode) do {
-		if (inode->i_ino == i_ino && inode->i_dev == i_dev) {
-			atomic_inc(&inode->i_count);
-			_get_inode(inode);
-
-			 /* Allow concurrent writes/puts. This is in particular
-			  * useful e.g. when syncing large chunks.
-			  * I hope the i_dirty flag is everywhere set as soon
-			  * as _any_ modifcation is made and _before_
-			  * giving up control, so no harm should occur if data
-			  * is modified during writes, because it will be
-			  * rewritten again (does a short inconsistency on the
-			  * disk harm?)
-			  */
-			wait_io(inode, ST_TO_READ);
-			vfs_unlock();
-			goto done;
-		}
-		inode = inode->i_hash_next;
-	} while(inode != *base);
-	inode = _get_empty_inode_hashed(i_dev, i_ino);
-	inode->i_sb = sb;
-	inode->i_flags = sb->s_flags;
-	if (sb->s_op && sb->s_op->read_inode) {
-		set_io(inode, 0, ST_TO_READ); /* do not wait at all */
-		sb->s_op->read_inode(inode);
-		if (release_io(inode, ST_TO_READ))
-			goto done;
+	struct list_head *next;
+
+	next = head->next;
+	for (;;) {
+		struct list_head * tmp = next;
+		struct inode * inode;
+
+		next = next->next;
+		if (tmp == head)
+			break;
+		inode = list_entry(tmp, struct inode, i_list);
+		if (inode->i_dev != dev)
+			continue;		
+		if (!CAN_UNUSE(inode))
+			continue;
+		list_del(&inode->i_hash);
+		INIT_LIST_HEAD(&inode->i_hash);
+		list_del(&inode->i_list);
+		list_add(&inode->i_list, &inode_unused);
 	}
-	vfs_unlock();
-done:
-	return inode;
 }
 
-blocking void __iput(struct inode * inode)
+void invalidate_inodes(kdev_t dev)
 {
-	struct super_block * sb;
-xcheck("_iput",inode);
-
-	if (atomic_read(&inode->i_count) < 0)
-		printk("VFS: i_count is negative\n");
+	spin_lock(&inode_lock);
+	invalidate_list(&inode_in_use, dev);
+	invalidate_list(&inode_dirty, dev);
+	spin_unlock(&inode_lock);
+}
 
-	if (atomic_read(&inode->i_count) || (inode->i_status & ST_FREEING))
-		return;
+/*
+ * This is called with the inode lock held. It just looks at the last
+ * inode on the in-use list, and if the inode is trivially freeable
+ * we just move it to the unused list.
+ *
+ * Otherwise we just move the inode to be the first inode and expect to
+ * get back to the problem later..
+ */
+static void try_to_free_inodes(void)
+{
+	struct list_head * tmp;
+	struct list_head *head = &inode_in_use;
 
-	inode->i_status |= ST_FREEING;
-	if (inode->i_pipe) {
-		free_page((unsigned long)PIPE_BASE(*inode));
-		PIPE_BASE(*inode)= NULL;
-	}
-	if ((sb = inode->i_sb)) {
-		if (sb->s_op) {
-			if (inode->i_nlink <= 0 &&
-			    !(inode->i_status & (ST_EMPTY|ST_IBASKET))) {
-				_clear_inode(inode, 0, 1);
-				goto done;
-			}
-			if (inode->i_dirt) {
-				inode->i_dirt = 0;
-				_io(sb->s_op->write_inode, inode,
-				    ST_TO_PUT|ST_TO_WRITE, ST_TO_WRITE);
-				if (atomic_read(&inode->i_count))
-					goto done;
-			}
-		}
-		if (IS_WRITABLE(inode) && sb->dq_op) {
-			/* can operate in parallel to other ops ? */
-			_io(sb->dq_op->drop, inode, 0, ST_TO_DROP);
-			if (atomic_read(&inode->i_count))
-				goto done;
+	tmp = head->prev;
+	if (tmp != head) {
+		struct inode * inode;
+
+		list_del(tmp);
+		inode = list_entry(tmp, struct inode, i_list);
+		if (CAN_UNUSE(inode)) {
+			list_del(&inode->i_hash);
+			INIT_LIST_HEAD(&inode->i_hash);
+			head = &inode_unused;
 		}
+		list_add(tmp, head);
 	}
-	if (inode->i_mmap)
-		printk("VFS: inode has mappings\n");
-	if (inode->i_status & ST_AGED) {
-		printk("VFS: reaging inode\n");
-#if defined(DEBUG)
-printpath(inode->i_dentry);
-printk("\n");
-#endif
-		goto done;
-	}
-	if (!(inode->i_status & (ST_HASHED|ST_EMPTY))) {
-		_clear_inode(inode, 0, 1);
-		goto done;
-	}
-	if (inode->i_status & ST_EMPTY) {
-		printk("VFS: aging an empty inode\n");
-		goto done;
+}
+		
+
+static struct inode * find_inode(struct super_block * sb, unsigned long ino, struct list_head *head)
+{
+	struct list_head *tmp;
+	struct inode * inode;
+
+	tmp = head;
+	for (;;) {
+		tmp = tmp->next;
+		inode = NULL;
+		if (tmp == head)
+			break;
+		inode = list_entry(tmp, struct inode, i_hash);
+		if (inode->i_sb != sb)
+			continue;
+		if (inode->i_ino != ino)
+			continue;
+		inode->i_count++;
+		break;
 	}
-	insert_lru(&aged_i[inode->i_level], inode);
-	inodes_stat.aged_count[inode->i_level]++;
-	inode->i_status |= ST_AGED;
-done:
-	inode->i_status &= ~ST_FREEING;
+	return inode;
 }
 
-blocking void _iput(struct inode * inode)
+/*
+ * This just initializes the inode fields
+ * to known values before returning the inode..
+ *
+ * i_sb, i_ino, i_count, i_state and the lists have
+ * been initialized elsewhere..
+ */
+void clean_inode(struct inode *inode)
 {
-	vfs_lock();
-	__iput(inode);
-	vfs_unlock();
+	memset(&inode->u, 0, sizeof(inode->u));
+	inode->i_sock = 0;
+	inode->i_op = NULL;
+	inode->i_nlink = 0;
+	inode->i_writecount = 0;
+	inode->i_size = 0;
+	memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
+	sema_init(&inode->i_sem, 1);
 }
 
-blocking void sync_inodes(kdev_t dev)
+/*
+ * This gets called with I_LOCK held: it needs
+ * to read the inode and then unlock it
+ */
+static inline void read_inode(struct inode *inode, struct super_block *sb)
 {
-	struct inode * inode;
-	vfs_lock();
-	inode = all_i;
-	if (inode) do {
-xcheck("sync_inodes",inode);
-		if (inode->i_dirt && (inode->i_dev == dev || !dev)) {
-			if (inode->i_sb && inode->i_sb->s_op &&
-			   !(inode->i_status & ST_FREEING)) {
-				inode->i_dirt = 0; 
-				_io(inode->i_sb->s_op->write_inode, inode,
-				    ST_IO, ST_TO_WRITE);
-			}
-		}
-		inode = inode->i_next;
-	} while(inode != all_i);
-	vfs_unlock();
+	sb->s_op->read_inode(inode);
+	unlock_inode(inode);
 }
 
-blocking int _check_inodes(kdev_t dev, int complain)
+struct inode * get_empty_inode(void)
 {
+	static unsigned long last_ino = 0;
 	struct inode * inode;
-	int bad = 0;
+	struct list_head * tmp;
 
-	vfs_lock();
-startover:
-	inode = all_i;
-	if (inode) do {
-		struct inode * next;
-xcheck("_check_inodes",inode);
-		next = inode->i_next;
-		if (inode->i_dev == dev) {
-			if (inode->i_dirt || atomic_read(&inode->i_count)) {
-				bad++;
-			} else {
-				_clear_inode(inode, 0, 0);
-
-				/* _clear_inode() may recursively clear other
-				 * inodes, probably also the next one.
-				 */
-				if (next->i_status & ST_EMPTY)
-					goto startover;
-			}
-		}
-		inode = next;
-	} while(inode != all_i);
-	vfs_unlock();
-	if (complain && bad)
-		printk("VFS: %d inode(s) busy on removed device `%s'\n",
-		       bad, kdevname(dev));
-	return (bad == 0);
+	spin_lock(&inode_lock);
+	try_to_free_inodes();
+	tmp = inode_unused.next;
+	if (tmp != &inode_unused) {
+		list_del(tmp);
+		inode = list_entry(tmp, struct inode, i_list);
+add_new_inode:
+		inode->i_sb = NULL;
+		inode->i_ino = ++last_ino;
+		inode->i_count = 1;
+		list_add(&inode->i_list, &inode_in_use);
+		inode->i_state = 0;
+		spin_unlock(&inode_lock);
+		clean_inode(inode);
+		return inode;
+	}
+
+	/*
+	 * Warning: if this succeeded, we will now
+	 * return with the inode lock.
+	 */
+	spin_unlock(&inode_lock);
+	inode = grow_inodes();
+	if (inode)
+		goto add_new_inode;
+
+	return inode;
 }
 
-/*inline*/ void invalidate_inodes(kdev_t dev)
+/*
+ * This is called with the inode lock held.. Be careful.
+ */
+static struct inode * get_new_inode(struct super_block *sb, unsigned long ino, struct list_head *head)
 {
-	/* Requires two passes, because of the new dcache holding
-	 * directories with i_count > 1.
+	struct inode * inode;
+	struct list_head * tmp = inode_unused.next;
+
+	if (tmp != &inode_unused) {
+		list_del(tmp);
+		inode = list_entry(tmp, struct inode, i_list);
+add_new_inode:
+		list_add(&inode->i_list, &inode_in_use);
+		list_add(&inode->i_hash, head);
+		inode->i_sb = sb;
+		inode->i_dev = sb->s_dev;
+		inode->i_ino = ino;
+		inode->i_flags = sb->s_flags;
+		inode->i_count = 1;
+		inode->i_state = 1 << I_LOCK;
+		spin_unlock(&inode_lock);
+		clean_inode(inode);
+		read_inode(inode, sb);
+		return inode;
+	}
+
+	/*
+	 * Uhhuh.. We need to expand.  Unlock for the allocation,
+	 * but note that "grow_inodes()" will return with the
+	 * lock held again if the allocation succeeded.
 	 */
-	(void)_check_inodes(dev, 0);
-	(void)_check_inodes(dev, 1);
+	spin_unlock(&inode_lock);
+	inode = grow_inodes();
+	if (inode) {
+		/* We released the lock, so.. */
+		struct inode * old = find_inode(sb, ino, head);
+		if (!old)
+			goto add_new_inode;
+		list_add(&inode->i_list, &inode_unused);
+		spin_unlock(&inode_lock);
+		wait_on_inode(old);
+		return old;
+	}
+	return inode;
 }
 
-/*inline*/ int fs_may_mount(kdev_t dev)
+static inline unsigned long hash(struct super_block *sb, unsigned long i_ino)
 {
-	return _check_inodes(dev, 0);
+	unsigned long tmp = i_ino | (unsigned long) sb;
+	tmp = tmp + (tmp >> HASH_BITS) + (tmp >> HASH_BITS*2);
+	return tmp & HASH_MASK;
 }
 
-int fs_may_remount_ro(kdev_t dev)
+struct inode *iget(struct super_block *sb, unsigned long ino)
 {
-	(void)dev;
-	return 1; /* not checked any more */
+	struct list_head * head = inode_hashtable + hash(sb,ino);
+	struct inode * inode;
+
+	spin_lock(&inode_lock);
+	inode = find_inode(sb, ino, head);
+	if (!inode) {
+		try_to_free_inodes();
+		return get_new_inode(sb, ino, head);
+	}
+	spin_unlock(&inode_lock);
+	wait_on_inode(inode);
+	return inode;
 }
 
-int fs_may_umount(kdev_t dev, struct dentry * root)
+void insert_inode_hash(struct inode *inode)
 {
-	struct inode * inode;
-	vfs_lock();
-	inode = all_i;
-	if (inode) do {
-		if (inode->i_dev == dev && atomic_read(&inode->i_count))
-			if (inode != root->d_inode) {
-				vfs_unlock();
-				return 0;
-			}
-		inode = inode->i_next;
-	} while(inode != all_i);
-	vfs_unlock();
-	return 1;
+	struct list_head *head = inode_hashtable + hash(inode->i_sb, inode->i_ino);
+	list_add(&inode->i_hash, head);
 }
 
-extern struct inode_operations pipe_inode_operations;
-
-blocking struct inode * get_pipe_inode(void)
+void iput(struct inode *inode)
 {
-	struct inode * inode = get_empty_inode();
+	if (inode) {
+		struct super_operations *op = NULL;
 
-	PIPE_BASE(*inode) = (char*)__get_free_page(GFP_USER);
-	if (!(PIPE_BASE(*inode))) {
-		iput(inode);
-		return NULL;
+		if (inode->i_sb && inode->i_sb->s_op)
+			op = inode->i_sb->s_op;
+		if (op && op->put_inode)
+			op->put_inode(inode);
+
+		spin_lock(&inode_lock);
+		if (!--inode->i_count) {
+			if (!inode->i_nlink) {
+				list_del(&inode->i_hash);
+				INIT_LIST_HEAD(&inode->i_hash);
+				if (op && op->delete_inode) {
+					void (*delete)(struct inode *) = op->delete_inode;
+					spin_unlock(&inode_lock);
+					delete(inode);
+					spin_lock(&inode_lock);
+				}
+			}
+			if (list_empty(&inode->i_hash)) {
+				list_del(&inode->i_list);
+				list_add(&inode->i_list, &inode_unused);
+			}
+		}
+		spin_unlock(&inode_lock);
 	}
-	inode->i_blksize = PAGE_SIZE;
-	inode->i_pipe = 1;
-	inode->i_mode = S_IFIFO | S_IRUSR | S_IWUSR;
-	atomic_inc(&inode->i_count);
-	inode->i_uid = current->fsuid;
-	inode->i_gid = current->fsgid;
-	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-	inode->i_op = &pipe_inode_operations;
-	PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 1;
-
-	return inode;
 }
 
 int bmap(struct inode * inode, int block)
@@ -625,4 +459,40 @@
 	if (inode->i_op && inode->i_op->bmap)
 		return inode->i_op->bmap(inode, block);
 	return 0;
+}
+
+/*
+ * Initialize the hash tables
+ */
+void inode_init(void)
+{
+	int i;
+	struct list_head *head = inode_hashtable;
+
+	i = HASH_SIZE;
+	do {
+		INIT_LIST_HEAD(head);
+		head++;
+		i--;
+	} while (i);
+}
+
+/*
+ * FIXME! These need to go through the in-use inodes to
+ * check whether we can mount/umount/remount.
+ */
+int fs_may_mount(kdev_t dev)
+{
+	return 1;
+}
+
+int fs_may_umount(struct super_block *sb, struct dentry * root)
+{
+	shrink_dcache();
+	return root->d_count == 1;
+}
+
+int fs_may_remount_ro(struct super_block *sb)
+{
+	return 1;
 }
diff -u --recursive --new-file v2.1.44/linux/fs/ioctl.c linux/fs/ioctl.c
--- v2.1.44/linux/fs/ioctl.c	Sun Jan 26 02:07:44 1997
+++ linux/fs/ioctl.c	Sun Jul 13 21:20:10 1997
@@ -20,28 +20,27 @@
 {
 	int error;
 	int block;
+	struct inode * inode = filp->f_dentry->d_inode;
 
 	switch (cmd) {
 		case FIBMAP:
-			if (filp->f_inode->i_op == NULL)
+			if (inode->i_op == NULL)
 				return -EBADF;
-		    	if (filp->f_inode->i_op->bmap == NULL)
+		    	if (inode->i_op->bmap == NULL)
 				return -EINVAL;
 			if ((error = get_user(block, (int *) arg)) != 0)
 				return error;
-			block = filp->f_inode->i_op->bmap(filp->f_inode,block);
+			block = inode->i_op->bmap(inode,block);
 			return put_user(block, (int *) arg);
 		case FIGETBSZ:
-			if (filp->f_inode->i_sb == NULL)
+			if (inode->i_sb == NULL)
 				return -EBADF;
-			return put_user(filp->f_inode->i_sb->s_blocksize,
-					(int *) arg);
+			return put_user(inode->i_sb->s_blocksize, (int *) arg);
 		case FIONREAD:
-			return put_user(filp->f_inode->i_size - filp->f_pos,
-					(int *) arg);
+			return put_user(inode->i_size - filp->f_pos, (int *) arg);
 	}
 	if (filp->f_op && filp->f_op->ioctl)
-		return filp->f_op->ioctl(filp->f_inode, filp, cmd, arg);
+		return filp->f_op->ioctl(inode, filp, cmd, arg);
 	return -ENOTTY;
 }
 
@@ -91,10 +90,10 @@
 			break;
 
 		default:
-			if (filp->f_inode && S_ISREG(filp->f_inode->i_mode))
+			if (filp->f_dentry && filp->f_dentry->d_inode && S_ISREG(filp->f_dentry->d_inode->i_mode))
 				error = file_ioctl(filp, cmd, arg);
 			else if (filp->f_op && filp->f_op->ioctl)
-				error = filp->f_op->ioctl(filp->f_inode, filp, cmd, arg);
+				error = filp->f_op->ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
 			else
 				error = -ENOTTY;
 	}
diff -u --recursive --new-file v2.1.44/linux/fs/isofs/dir.c linux/fs/isofs/dir.c
--- v2.1.44/linux/fs/isofs/dir.c	Mon Jun 16 16:35:57 1997
+++ linux/fs/isofs/dir.c	Wed Jul 16 10:26:21 1997
@@ -54,6 +54,7 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
+	NULL,			/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	isofs_bmap,		/* bmap */
@@ -61,20 +62,6 @@
 	NULL			/* permission */
 };
 
-static int parent_inode_number(struct inode * inode, struct iso_directory_record * de)
-{
-	int inode_number = inode->i_ino;
-
-	if ((inode->i_sb->u.isofs_sb.s_firstdatazone) != inode->i_ino)
-		inode_number = inode->u.isofs_i.i_backlink;
-
-	if (inode_number != -1)
-		return inode_number;
-
-	/* This should never happen, but who knows.  Try to be forgiving */
-	return isofs_lookup_grandparent(inode, find_rock_ridge_relocation(de, inode));
-}
-
 static int isofs_name_translate(char * old, int len, char * new)
 {
 	int i, c;
@@ -196,9 +183,7 @@
 
 		/* Handle the case of the '..' directory */
 		if (de->name_len[0] == 1 && de->name[0] == 1) {
-			inode_number = parent_inode_number(inode, de);
-			if (inode_number == -1)
-				break;
+			inode_number = filp->f_dentry->d_parent->d_inode->i_ino;
 			if (filldir(dirent, "..", 2, filp->f_pos, inode_number) < 0)
 				break;
 			filp->f_pos += de_len;
diff -u --recursive --new-file v2.1.44/linux/fs/isofs/file.c linux/fs/isofs/file.c
--- v2.1.44/linux/fs/isofs/file.c	Mon Jun 16 16:35:57 1997
+++ linux/fs/isofs/file.c	Tue Jul  8 19:36:45 1997
@@ -47,6 +47,7 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
+	NULL,			/* follow_link */
 	generic_readpage,	/* readpage */
 	NULL,			/* writepage */
 	isofs_bmap,		/* bmap */
diff -u --recursive --new-file v2.1.44/linux/fs/isofs/inode.c linux/fs/isofs/inode.c
--- v2.1.44/linux/fs/isofs/inode.c	Mon Jun 16 16:35:57 1997
+++ linux/fs/isofs/inode.c	Wed Jul 16 11:38:13 1997
@@ -54,9 +54,10 @@
 
 static struct super_operations isofs_sops = {
 	isofs_read_inode,
-	NULL,			/* notify_change */
 	NULL,			/* write_inode */
 	NULL,			/* put_inode */
+	NULL,			/* delete_inode */
+	NULL,			/* notify_change */
 	isofs_put_super,
 	NULL,			/* write_super */
 	isofs_statfs,
@@ -481,12 +482,12 @@
 	s->u.isofs_sb.s_mode = opt.mode & 0777;
 	s->s_blocksize = opt.blocksize;
 	s->s_blocksize_bits = blocksize_bits;
-	s->s_mounted = iget(s, (isonum_733(rootp->extent) +
+	s->s_root = d_alloc_root(iget(s, (isonum_733(rootp->extent) +
 			    isonum_711(rootp->ext_attr_length))
-				<< s -> u.isofs_sb.s_log_zone_size);
+				<< s -> u.isofs_sb.s_log_zone_size), NULL);
 	unlock_super(s);
 
-	if (!(s->s_mounted)) {
+	if (!(s->s_root)) {
 		s->s_dev = 0;
 		printk("get root inode failed\n");
 		MOD_DEC_USE_COUNT;
@@ -504,7 +505,7 @@
 	return NULL;
 }
 
-void isofs_statfs (struct super_block *sb, struct statfs *buf, int bufsiz)
+int isofs_statfs (struct super_block *sb, struct statfs *buf, int bufsiz)
 {
 	struct statfs tmp;
 
@@ -517,7 +518,7 @@
 	tmp.f_files = sb->u.isofs_sb.s_ninodes;
 	tmp.f_ffree = 0;
 	tmp.f_namelen = NAME_MAX;
-	copy_to_user(buf, &tmp, bufsiz);
+	return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
 }
 
 int isofs_bmap(struct inode * inode,int block)
@@ -663,7 +664,6 @@
 					   isonum_711 (raw_inode->ext_attr_length))
 	  << inode -> i_sb -> u.isofs_sb.s_log_zone_size;
 
-	inode->u.isofs_i.i_backlink = 0xffffffff; /* Will be used for previous directory */
 	switch (inode->i_sb->u.isofs_sb.s_conversion){
 	case 'a':
 	  inode->u.isofs_i.i_file_format = ISOFS_FILE_UNKNOWN; /* File type */
@@ -735,7 +735,6 @@
 	/* With a data error we return this information */
 	inode->i_mtime = inode->i_atime = inode->i_ctime = 0;
 	inode->u.isofs_i.i_first_extent = 0;
-	inode->u.isofs_i.i_backlink = 0xffffffff;
 	inode->i_size = 0;
 	inode->i_nlink = 1;
 	inode->i_uid = inode->i_gid = 0;
diff -u --recursive --new-file v2.1.44/linux/fs/isofs/namei.c linux/fs/isofs/namei.c
--- v2.1.44/linux/fs/isofs/namei.c	Mon Jun 16 16:35:57 1997
+++ linux/fs/isofs/namei.c	Wed Jul 16 14:18:57 1997
@@ -59,14 +59,13 @@
  * entry - you'll have to do that yourself if you want to.
  */
 static struct buffer_head * isofs_find_entry(struct inode * dir,
-	const char * name, int namelen, unsigned long * ino, unsigned long * ino_back)
+	const char * name, int namelen, unsigned long * ino)
 {
 	unsigned long bufsize = ISOFS_BUFFER_SIZE(dir);
 	unsigned char bufbits = ISOFS_BUFFER_BITS(dir);
 	unsigned int block, i, f_pos, offset, inode_number;
 	struct buffer_head * bh;
 	unsigned int old_offset;
-	unsigned int backlink;
 	int dlen, rrflag, match;
 	char * dpnt;
 	struct iso_directory_record * de;
@@ -86,7 +85,6 @@
   
 	while (f_pos < dir->i_size) {
 		de = (struct iso_directory_record *) (bh->b_data + offset);
-		backlink = dir->i_ino;
 		inode_number = (block << bufbits) + (offset & (bufsize - 1));
 
 		/* If byte is zero, this is the end of file, or time to move to
@@ -120,28 +118,6 @@
 	 		return 0;
 		}
 		
-		/* Handle the '.' case */
-		
-		if (de->name[0]==0 && de->name_len[0]==1) {
-			inode_number = dir->i_ino;
-			backlink = 0;
-		}
-		
-		/* Handle the '..' case */
-
-		if (de->name[0]==1 && de->name_len[0]==1) {
-#if 0
-			printk("Doing .. (%d %d)",
-			       dir->i_sb->s_firstdatazone,
-			       dir->i_ino);
-#endif
-			if((dir->i_sb->u.isofs_sb.s_firstdatazone) != dir->i_ino)
- 				inode_number = dir->u.isofs_i.i_backlink;
-			else
-				inode_number = dir->i_ino;
-			backlink = 0;
-		}
-    
 		dlen = de->name_len[0];
 		dpnt = de->name;
 		/* Now convert the filename in the buffer to lower case */
@@ -183,16 +159,8 @@
 				inode_number = 
 					isofs_lookup_grandparent(dir,
 					   find_rock_ridge_relocation(de,dir));
-				if(inode_number == -1){
-					/* Should never happen */
-					printk("Backlink not properly set %x %lx.\n",
-					       isonum_733(de->extent),
-					       dir->i_ino);
-					goto out;
-				}
 			}
 			*ino = inode_number;
-			*ino_back = backlink;
 			return bh;
 		}
 	}
@@ -201,62 +169,48 @@
 	return NULL;
 }
 
-int isofs_lookup(struct inode * dir,const char * name, int len,
-	struct inode ** result)
+int isofs_lookup(struct inode * dir, struct dentry * dentry)
 {
-	unsigned long ino, ino_back;
+	unsigned long ino;
 	struct buffer_head * bh;
 	char *lcname;
+	struct inode *inode;
 
 #ifdef DEBUG
-	printk("lookup: %x %d\n",dir->i_ino, len);
+	printk("lookup: %x %d\n",dir->i_ino, dentry->d_name.len);
 #endif
-	*result = NULL;
 	if (!dir)
 		return -ENOENT;
 
-	if (!S_ISDIR(dir->i_mode)) {
-		iput(dir);
+	if (!S_ISDIR(dir->i_mode))
 		return -ENOENT;
-	}
 
 	/* If mounted with check=relaxed (and most likely norock),
 	 * then first convert this name to lower case.
 	 */
 	if (dir->i_sb->u.isofs_sb.s_name_check == 'r' &&
-	    (lcname = kmalloc(len, GFP_KERNEL)) != NULL) {
+	    (lcname = kmalloc(dentry->d_name.len, GFP_KERNEL)) != NULL) {
 		int i;
 		char c;
 
-		for (i=0; i<len; i++) {
-			c = name[i];
+		for (i=0; i<dentry->d_name.len; i++) {
+			c = dentry->d_name.name[i];
 			if (c >= 'A' && c <= 'Z') c |= 0x20;
 			lcname[i] = c;
 		}
-		bh = isofs_find_entry(dir,lcname,len, &ino, &ino_back);
+		bh = isofs_find_entry(dir, lcname, dentry->d_name.len, &ino);
 		kfree(lcname);
 	} else
-		bh = isofs_find_entry(dir,name,len, &ino, &ino_back);
+		bh = isofs_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &ino);
 
-	if (!bh) {
-		iput(dir);
-		return -ENOENT;
-	}
-	brelse(bh);
-
-	if (!(*result = iget(dir->i_sb,ino))) {
-		iput(dir);
-		return -EACCES;
+	inode = NULL;
+	if (bh) {
+		brelse(bh);
+
+		inode = iget(dir->i_sb,ino);
+		if (!inode)
+			return -EACCES;
 	}
-
-	/* We need this backlink for the ".." entry unless the name that we
-	 * are looking up traversed a mount point (in which case the inode
-	 * may not even be on an iso9660 filesystem, and writing to
-	 * u.isofs_i would only cause memory corruption).
-	 */
-	if (ino_back && !(*result)->i_pipe && (*result)->i_sb == dir->i_sb)
-		(*result)->u.isofs_i.i_backlink = ino_back; 
-	
-	iput(dir);
+	d_add(dentry, inode);
 	return 0;
 }
diff -u --recursive --new-file v2.1.44/linux/fs/lockd/clntlock.c linux/fs/lockd/clntlock.c
--- v2.1.44/linux/fs/lockd/clntlock.c	Mon Apr  7 11:35:30 1997
+++ linux/fs/lockd/clntlock.c	Sun Jul 13 21:20:10 1997
@@ -172,7 +172,7 @@
 	/* First, reclaim all locks that have been granted previously. */
 	do {
 		for (fl = file_lock_table; fl; fl = fl->fl_next) {
-			inode = fl->fl_file->f_inode;
+			inode = fl->fl_file->f_dentry->d_inode;
 			if (inode->i_sb->s_magic == NFS_SUPER_MAGIC
 			 && nlm_cmp_addr(NFS_ADDR(inode), &host->h_addr)
 			 && fl->fl_u.nfs_fl.state != host->h_state
diff -u --recursive --new-file v2.1.44/linux/fs/lockd/clntproc.c linux/fs/lockd/clntproc.c
--- v2.1.44/linux/fs/lockd/clntproc.c	Sun Apr 13 10:18:22 1997
+++ linux/fs/lockd/clntproc.c	Sun Jul 13 21:20:10 1997
@@ -42,7 +42,7 @@
 	memset(argp, 0, sizeof(*argp));
 	argp->cookie  = nlm_cookie++;
 	argp->state   = nsm_local_state;
-	lock->fh      = *NFS_FH(fl->fl_file->f_inode);
+	lock->fh      = *NFS_FH(fl->fl_file->f_dentry->d_inode);
 	lock->caller  = system_utsname.nodename;
 	lock->oh.data = req->a_owner;
 	lock->oh.len  = sprintf(req->a_owner, "%d@%s",
diff -u --recursive --new-file v2.1.44/linux/fs/lockd/svclock.c linux/fs/lockd/svclock.c
--- v2.1.44/linux/fs/lockd/svclock.c	Mon Apr  7 11:35:30 1997
+++ linux/fs/lockd/svclock.c	Sun Jul 13 21:20:10 1997
@@ -274,8 +274,8 @@
 	int			error;
 
 	dprintk("lockd: nlmsvc_lock(%04x/%ld, ty=%d, pi=%d, %ld-%ld, bl=%d)\n",
-				file->f_file.f_inode->i_dev,
-				file->f_file.f_inode->i_ino,
+				file->f_file.f_dentry->d_inode->i_dev,
+				file->f_file.f_dentry->d_inode->i_ino,
 				lock->fl.fl_type, lock->fl.fl_pid,
 				lock->fl.fl_start,
 				lock->fl.fl_end,
@@ -344,8 +344,8 @@
 	struct file_lock	*fl;
 
 	dprintk("lockd: nlmsvc_testlock(%04x/%ld, ty=%d, %ld-%ld)\n",
-				file->f_file.f_inode->i_dev,
-				file->f_file.f_inode->i_ino,
+				file->f_file.f_dentry->d_inode->i_dev,
+				file->f_file.f_dentry->d_inode->i_ino,
 				lock->fl.fl_type,
 				lock->fl.fl_start,
 				lock->fl.fl_end);
@@ -375,8 +375,8 @@
 	int	error;
 
 	dprintk("lockd: nlmsvc_unlock(%04x/%ld, pi=%d, %ld-%ld)\n",
-				file->f_file.f_inode->i_dev,
-				file->f_file.f_inode->i_ino,
+				file->f_file.f_dentry->d_inode->i_dev,
+				file->f_file.f_dentry->d_inode->i_ino,
 				lock->fl.fl_pid,
 				lock->fl.fl_start,
 				lock->fl.fl_end);
@@ -403,8 +403,8 @@
 	struct nlm_block	*block;
 
 	dprintk("lockd: nlmsvc_cancel(%04x/%ld, pi=%d, %ld-%ld)\n",
-				file->f_file.f_inode->i_dev,
-				file->f_file.f_inode->i_ino,
+				file->f_file.f_dentry->d_inode->i_dev,
+				file->f_file.f_dentry->d_inode->i_ino,
 				lock->fl.fl_pid,
 				lock->fl.fl_start,
 				lock->fl.fl_end);
diff -u --recursive --new-file v2.1.44/linux/fs/locks.c linux/fs/locks.c
--- v2.1.44/linux/fs/locks.c	Sat May 24 09:10:24 1997
+++ linux/fs/locks.c	Sun Jul 13 21:20:10 1997
@@ -297,25 +297,34 @@
 {
 	struct flock flock;
 	struct file *filp;
+	struct dentry *dentry;
+	struct inode *inode;
 	struct file_lock *fl,file_lock;
 	int error;
 
 	if ((fd >= NR_OPEN) || !(filp = current->files->fd[fd]))
-		return (-EBADF);
+		return -EBADF;
 	if (copy_from_user(&flock, l, sizeof(flock)))
-		return (-EFAULT);
+		return -EFAULT;
 
 	if ((flock.l_type != F_RDLCK) && (flock.l_type != F_WRLCK))
-		return (-EINVAL);
+		return -EINVAL;
 
-	if (!filp->f_inode || !posix_make_lock(filp, &file_lock, &flock))
-		return (-EINVAL);
+	dentry = filp->f_dentry;
+	if (!dentry)
+		return -EINVAL;
+
+	inode = dentry->d_inode;
+	if (!inode)
+		return -EINVAL;
+
+	if (!posix_make_lock(filp, &file_lock, &flock))
+		return -EINVAL;
 
 	if (filp->f_op->lock) {
-		error = filp->f_op->lock(filp->f_inode, filp,
-					 F_GETLK, &file_lock);
+		error = filp->f_op->lock(inode, filp, F_GETLK, &file_lock);
 		if (error < 0)
-			return (error);
+			return error;
 		fl = &file_lock;
 	} else {
 		fl = posix_test_lock(filp, &file_lock);
@@ -344,6 +353,7 @@
 	struct file *filp;
 	struct file_lock file_lock;
 	struct flock flock;
+	struct dentry * dentry;
 	struct inode *inode;
 	int error;
 
@@ -351,10 +361,13 @@
 	 */
 
 	if ((fd >= NR_OPEN) || !(filp = current->files->fd[fd]))
-		return (-EBADF);
-	
-	if (!(inode = filp->f_inode))
-		return (-EINVAL);
+		return -EBADF;
+
+	if (!(dentry = filp->f_dentry))
+		return -EINVAL;
+
+	if (!(inode = dentry->d_inode))
+		return -EINVAL;
 	
 	/* Don't allow mandatory locks on files that may be memory mapped
 	 * and shared.
@@ -407,7 +420,7 @@
 	}
 
 	if (filp->f_op->lock != NULL) {
-		error = filp->f_op->lock(filp->f_inode, filp, cmd, &file_lock);
+		error = filp->f_op->lock(inode, filp, cmd, &file_lock);
 		if (error < 0)
 			return (error);
 	}
@@ -421,12 +434,14 @@
 {
 	struct file_lock file_lock, *fl;
 	struct file_lock **before;
+	struct inode * inode;
 
 	/* For POSIX locks we free all locks on this file for the given task.
 	 * For FLOCK we only free locks on this *open* file if it is the last
 	 * close on that file.
 	 */
-	before = &filp->f_inode->i_flock;
+	inode = filp->f_dentry->d_inode;
+	before = &inode->i_flock;
 
 	while ((fl = *before) != NULL) {
 		if (((fl->fl_flags & FL_POSIX) && (fl->fl_owner == task)) ||
@@ -436,10 +451,9 @@
 			locks_delete_lock(before, 0);
 			if (filp->f_op->lock) {
 				file_lock.fl_type = F_UNLCK;
-				filp->f_op->lock(filp->f_inode, filp,
-						 F_SETLK, &file_lock);
+				filp->f_op->lock(inode, filp, F_SETLK, &file_lock);
 				/* List may have changed: */
-				before = &filp->f_inode->i_flock;
+				before = &inode->i_flock;
 			}
 		} else {
 			before = &fl->fl_next;
@@ -454,7 +468,7 @@
 {
 	struct file_lock *cfl;
 
-	for (cfl = filp->f_inode->i_flock; cfl; cfl = cfl->fl_next) {
+	for (cfl = filp->f_dentry->d_inode->i_flock; cfl; cfl = cfl->fl_next) {
 		if (!(cfl->fl_flags & FL_POSIX))
 			continue;
 		if (posix_locks_conflict(cfl, fl))
@@ -585,7 +599,7 @@
 		start = filp->f_pos;
 		break;
 	case 2: /*SEEK_END*/
-		start = filp->f_inode->i_size;
+		start = filp->f_dentry->d_inode->i_size;
 		break;
 	default:
 		return (0);
@@ -612,7 +626,7 @@
 {
 	memset(fl, 0, sizeof(*fl));
 
-	if (!filp->f_inode)	/* just in case */
+	if (!filp->f_dentry)	/* just in case */
 		return (0);
 
 	switch (cmd & ~LOCK_NB) {
@@ -750,9 +764,10 @@
 	struct file_lock *fl;
 	struct file_lock *new_fl;
 	struct file_lock **before;
+	struct inode * inode = filp->f_dentry->d_inode;
 	int change = 0;
 
-	before = &filp->f_inode->i_flock;
+	before = &inode->i_flock;
 	while (((fl = *before) != NULL) && (fl->fl_flags & FL_FLOCK)) {
 		if (caller->fl_file == fl->fl_file) {
 			if (caller->fl_type == fl->fl_type)
@@ -772,7 +787,7 @@
 	if ((new_fl = locks_alloc_lock(caller)) == NULL)
 		return (-ENOLCK);
 repeat:
-	for (fl = filp->f_inode->i_flock; (fl != NULL) && (fl->fl_flags & FL_FLOCK);
+	for (fl = inode->i_flock; (fl != NULL) && (fl->fl_flags & FL_FLOCK);
 	     fl = fl->fl_next) {
 		if (!flock_locks_conflict(new_fl, fl))
 			continue;
@@ -801,7 +816,7 @@
 		}
 		goto repeat;
 	}
-	locks_insert_lock(&filp->f_inode->i_flock, new_fl);
+	locks_insert_lock(&inode->i_flock, new_fl);
 	return (0);
 }
 
@@ -825,11 +840,12 @@
 	struct file_lock *left = NULL;
 	struct file_lock *right = NULL;
 	struct file_lock **before;
+	struct inode * inode = filp->f_dentry->d_inode;
 	int added = 0;
 
 	if (caller->fl_type != F_UNLCK) {
   repeat:
-		for (fl = filp->f_inode->i_flock; fl != NULL; fl = fl->fl_next) {
+		for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
 			if (!(fl->fl_flags & FL_POSIX))
 				continue;
 			if (!posix_locks_conflict(caller, fl))
@@ -852,7 +868,7 @@
 	/* Find the first old lock with the same owner as the new lock.
 	 */
 	
-	before = &filp->f_inode->i_flock;
+	before = &inode->i_flock;
 
 	/* First skip locks owned by other processes.
 	 */
@@ -1054,7 +1070,7 @@
 	char *p = temp;
 	struct inode *inode;
 
-	inode = fl->fl_file->f_inode;
+	inode = fl->fl_file->f_dentry->d_inode;
 
 	p += sprintf(p, "%d:%s ", id, pfx);
 	if (fl->fl_flags & FL_POSIX) {
diff -u --recursive --new-file v2.1.44/linux/fs/minix/bitmap.c linux/fs/minix/bitmap.c
--- v2.1.44/linux/fs/minix/bitmap.c	Mon Jun 16 16:35:57 1997
+++ linux/fs/minix/bitmap.c	Wed Jul 16 19:22:51 1997
@@ -191,8 +191,8 @@
 		printk("free_inode: inode has no device\n");
 		return;
 	}
-	if (atomic_read(&inode->i_count) != 1) {
-		printk("free_inode: inode has count=%d\n",atomic_read(&inode->i_count));
+	if (inode->i_count != 1) {
+		printk("free_inode: inode has count=%d\n",inode->i_count);
 		return;
 	}
 	if (inode->i_nlink) {
@@ -251,12 +251,12 @@
 		iput(inode);
 		return NULL;
 	}
-	atomic_set(&inode->i_count, 1);
+	inode->i_count = 1;
 	inode->i_nlink = 1;
 	inode->i_dev = sb->s_dev;
 	inode->i_uid = current->fsuid;
 	inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
-	inode->i_dirt = 1;
+	mark_inode_dirty(inode);
 	inode->i_ino = j;
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
 	inode->i_op = NULL;
diff -u --recursive --new-file v2.1.44/linux/fs/minix/dir.c linux/fs/minix/dir.c
--- v2.1.44/linux/fs/minix/dir.c	Mon Jun 16 16:35:57 1997
+++ linux/fs/minix/dir.c	Tue Jul  8 19:36:45 1997
@@ -50,6 +50,7 @@
 	minix_mknod,		/* mknod */
 	minix_rename,		/* rename */
 	NULL,			/* readlink */
+	NULL,			/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
diff -u --recursive --new-file v2.1.44/linux/fs/minix/file.c linux/fs/minix/file.c
--- v2.1.44/linux/fs/minix/file.c	Mon Jun 16 16:35:57 1997
+++ linux/fs/minix/file.c	Wed Jul 16 08:05:24 1997
@@ -58,6 +58,7 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
+	NULL,			/* follow_link */
 	generic_readpage,	/* readpage */
 	NULL,			/* writepage */
 	minix_bmap,		/* bmap */
@@ -120,6 +121,6 @@
 		inode->i_size = pos;
 	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 	filp->f_pos = pos;
-	inode->i_dirt = 1;
+	mark_inode_dirty(inode);
 	return written;
 }
diff -u --recursive --new-file v2.1.44/linux/fs/minix/inode.c linux/fs/minix/inode.c
--- v2.1.44/linux/fs/minix/inode.c	Mon Jun 16 16:35:57 1997
+++ linux/fs/minix/inode.c	Wed Jul 16 08:07:44 1997
@@ -125,15 +125,13 @@
  * it really _is_ a minix filesystem, and to check the size
  * of the directory entry.
  */
-static const char * minix_checkroot(struct super_block *s)
+static const char * minix_checkroot(struct super_block *s, struct inode *dir)
 {
-	struct inode * dir;
 	struct buffer_head *bh;
 	struct minix_dir_entry *de;
 	const char * errmsg;
 	int dirsize;
 
-	dir = s->s_mounted;
 	if (!S_ISDIR(dir->i_mode))
 		return "root directory is not a directory";
 
@@ -172,7 +170,8 @@
 	int i, block;
 	kdev_t dev = s->s_dev;
 	const char * errmsg;
-
+	struct inode *root_inode;
+	
 	if (32 != sizeof (struct minix_inode))
 		panic("bad V1 i-node size");
 	if (64 != sizeof(struct minix2_inode))
@@ -272,8 +271,9 @@
 	/* set up enough so that it can read an inode */
 	s->s_dev = dev;
 	s->s_op = &minix_sops;
-	s->s_mounted = iget(s,MINIX_ROOT_INO);
-	if (!s->s_mounted) {
+	root_inode = iget(s,MINIX_ROOT_INO);
+	s->s_root = d_alloc_root(root_inode, NULL);
+	if (!s->s_root) {
 		s->s_dev = 0;
 		brelse(bh);
 		if (!silent)
@@ -282,11 +282,11 @@
 		return NULL;
 	}
 
-	errmsg = minix_checkroot(s);
+	errmsg = minix_checkroot(s, root_inode);
 	if (errmsg) {
 		if (!silent)
 			printk("MINIX-fs: %s\n", errmsg);
-		iput (s->s_mounted);
+		d_delete(s->s_root); /* XXX Is this enough? */
 		s->s_dev = 0;
 		brelse (bh);
 		MOD_DEC_USE_COUNT;
@@ -307,7 +307,7 @@
 	return s;
 }
 
-void minix_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+int minix_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
 {
 	struct statfs tmp;
 
@@ -319,7 +319,7 @@
 	tmp.f_files = sb->u.minix_sb.s_ninodes;
 	tmp.f_ffree = minix_count_free_inodes(sb);
 	tmp.f_namelen = sb->u.minix_sb.s_namelen;
-	copy_to_user(buf, &tmp, bufsiz);
+	return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
 }
 
 /*
@@ -472,7 +472,7 @@
 	}
 	*p = tmp;
 	inode->i_ctime = CURRENT_TIME;
-	inode->i_dirt = 1;
+	mark_inode_dirty(inode);
 	return result;
 }
 
@@ -585,7 +585,7 @@
 	}
 	*p = tmp;
 	inode->i_ctime = CURRENT_TIME;
-	inode->i_dirt = 1;
+	mark_inode_dirty(inode);
 	return result;
 }
 
@@ -833,14 +833,12 @@
 		printk("Bad inode number on dev %s"
 		       ": %d is out of range\n",
 			kdevname(inode->i_dev), ino);
-		inode->i_dirt = 0;
 		return 0;
 	}
 	block = 2 + inode->i_sb->u.minix_sb.s_imap_blocks + inode->i_sb->u.minix_sb.s_zmap_blocks +
 		(ino-1)/MINIX_INODES_PER_BLOCK;
 	if (!(bh=bread(inode->i_dev, block, BLOCK_SIZE))) {
 		printk("unable to read i-node block\n");
-		inode->i_dirt = 0;
 		return 0;
 	}
 	raw_inode = ((struct minix_inode *)bh->b_data) +
@@ -855,7 +853,6 @@
 		raw_inode->i_zone[0] = kdev_t_to_nr(inode->i_rdev);
 	else for (block = 0; block < 9; block++)
 		raw_inode->i_zone[block] = inode->u.minix_i.u.i1_data[block];
-	inode->i_dirt=0;
 	mark_buffer_dirty(bh, 1);
 	return bh;
 }
@@ -874,14 +871,12 @@
 		printk("Bad inode number on dev %s"
 		       ": %d is out of range\n",
 			kdevname(inode->i_dev), ino);
-		inode->i_dirt = 0;
 		return 0;
 	}
 	block = 2 + inode->i_sb->u.minix_sb.s_imap_blocks + inode->i_sb->u.minix_sb.s_zmap_blocks +
 		(ino-1)/MINIX2_INODES_PER_BLOCK;
 	if (!(bh=bread(inode->i_dev, block, BLOCK_SIZE))) {
 		printk("unable to read i-node block\n");
-		inode->i_dirt = 0;
 		return 0;
 	}
 	raw_inode = ((struct minix2_inode *)bh->b_data) +
@@ -898,7 +893,6 @@
 		raw_inode->i_zone[0] = kdev_t_to_nr(inode->i_rdev);
 	else for (block = 0; block < 10; block++)
 		raw_inode->i_zone[block] = inode->u.minix_i.u.i2_data[block];
-	inode->i_dirt=0;
 	mark_buffer_dirty(bh, 1);
 	return bh;
 }
diff -u --recursive --new-file v2.1.44/linux/fs/minix/namei.c linux/fs/minix/namei.c
--- v2.1.44/linux/fs/minix/namei.c	Thu Jul  3 17:30:52 1997
+++ linux/fs/minix/namei.c	Wed Jul 16 19:22:51 1997
@@ -104,7 +104,7 @@
 	return NULL;
 }
 
-int minix_lookup(struct inode * dir,const char * name, int len,
+int minix_lookup(struct inode * dir, struct qstr *name,
 	struct inode ** result)
 {
 	int ino;
@@ -114,21 +114,14 @@
 	*result = NULL;
 	if (!dir)
 		return -ENOENT;
-	if (!S_ISDIR(dir->i_mode)) {
-		iput(dir);
+	if (!S_ISDIR(dir->i_mode))
 		return -ENOENT;
-	}
-	if (!(bh = minix_find_entry(dir,name,len,&de))) {
-		iput(dir);
+	if (!(bh = minix_find_entry(dir, name->name, name->len, &de)))
 		return -ENOENT;
-	}
 	ino = de->inode;
 	brelse(bh);
-	if (!(*result = iget(dir->i_sb,ino))) {
-		iput(dir);
+	if (!(*result = iget(dir->i_sb,ino)))
 		return -EACCES;
-	}
-	iput(dir);
 	return 0;
 }
 
@@ -180,7 +173,7 @@
 		if (block*bh->b_size + offset > dir->i_size) {
 			de->inode = 0;
 			dir->i_size = block*bh->b_size + offset;
-			dir->i_dirt = 1;
+			mark_inode_dirty(dir);
 		}
 		if (de->inode) {
 			if (namecompare(namelen, info->s_namelen, name, de->name)) {
@@ -189,7 +182,7 @@
 			}
 		} else {
 			dir->i_mtime = dir->i_ctime = CURRENT_TIME;
-			dir->i_dirt = 1;
+			mark_inode_dirty(dir);
 			for (i = 0; i < info->s_namelen ; i++)
 				de->name[i] = (i < namelen) ? name[i] : 0;
 			dir->i_version = ++event;
@@ -208,42 +201,37 @@
 	return 0;
 }
 
-int minix_create(struct inode * dir,const char * name, int len, int mode,
-	struct inode ** result)
+int minix_create(struct inode * dir, struct dentry *dentry, int mode)
 {
 	int error;
 	struct inode * inode;
 	struct buffer_head * bh;
 	struct minix_dir_entry * de;
 
-	*result = NULL;
 	if (!dir)
 		return -ENOENT;
 	inode = minix_new_inode(dir);
-	if (!inode) {
-		iput(dir);
+	if (!inode)
 		return -ENOSPC;
-	}
 	inode->i_op = &minix_file_inode_operations;
 	inode->i_mode = mode;
-	inode->i_dirt = 1;
-	error = minix_add_entry(dir,name,len, &bh ,&de);
+	mark_inode_dirty(inode);
+	error = minix_add_entry(dir, dentry->d_name.name,
+				dentry->d_name.len, &bh ,&de);
 	if (error) {
 		inode->i_nlink--;
-		inode->i_dirt = 1;
+		mark_inode_dirty(inode);
 		iput(inode);
-		iput(dir);
 		return error;
 	}
 	de->inode = inode->i_ino;
 	mark_buffer_dirty(bh, 1);
 	brelse(bh);
-	iput(dir);
-	*result = inode;
+	d_instantiate(dentry, inode);
 	return 0;
 }
 
-int minix_mknod(struct inode * dir, const char * name, int len, int mode, int rdev)
+int minix_mknod(struct inode * dir, struct dentry *dentry, int mode, int rdev)
 {
 	int error;
 	struct inode * inode;
@@ -252,17 +240,15 @@
 
 	if (!dir)
 		return -ENOENT;
-	bh = minix_find_entry(dir,name,len,&de);
+	bh = minix_find_entry(dir, dentry->d_name.name,
+			      dentry->d_name.len, &de);
 	if (bh) {
 		brelse(bh);
-		iput(dir);
 		return -EEXIST;
 	}
 	inode = minix_new_inode(dir);
-	if (!inode) {
-		iput(dir);
+	if (!inode)
 		return -ENOSPC;
-	}
 	inode->i_uid = current->fsuid;
 	inode->i_mode = mode;
 	inode->i_op = NULL;
@@ -283,24 +269,22 @@
 		init_fifo(inode);
 	if (S_ISBLK(mode) || S_ISCHR(mode))
 		inode->i_rdev = to_kdev_t(rdev);
-	inode->i_dirt = 1;
-	error = minix_add_entry(dir, name, len, &bh, &de);
+	mark_inode_dirty(inode);
+	error = minix_add_entry(dir, dentry->d_name.name, dentry->d_name.len, &bh, &de);
 	if (error) {
 		inode->i_nlink--;
-		inode->i_dirt = 1;
+		mark_inode_dirty(inode);
 		iput(inode);
-		iput(dir);
 		return error;
 	}
 	de->inode = inode->i_ino;
 	mark_buffer_dirty(bh, 1);
 	brelse(bh);
-	iput(dir);
-	iput(inode);
+	d_instantiate(dentry, inode);
 	return 0;
 }
 
-int minix_mkdir(struct inode * dir, const char * name, int len, int mode)
+int minix_mkdir(struct inode * dir, struct dentry *dentry, int mode)
 {
 	int error;
 	struct inode * inode;
@@ -308,33 +292,26 @@
 	struct minix_dir_entry * de;
 	struct minix_sb_info * info;
 
-	if (!dir || !dir->i_sb) {
-		iput(dir);
+	if (!dir || !dir->i_sb)
 		return -EINVAL;
-	}
 	info = &dir->i_sb->u.minix_sb;
-	bh = minix_find_entry(dir,name,len,&de);
+	bh = minix_find_entry(dir, dentry->d_name.name,
+			      dentry->d_name.len, &de);
 	if (bh) {
 		brelse(bh);
-		iput(dir);
 		return -EEXIST;
 	}
-	if (dir->i_nlink >= MINIX_LINK_MAX) {
-		iput(dir);
+	if (dir->i_nlink >= MINIX_LINK_MAX)
 		return -EMLINK;
-	}
 	inode = minix_new_inode(dir);
-	if (!inode) {
-		iput(dir);
+	if (!inode)
 		return -ENOSPC;
-	}
 	inode->i_op = &minix_dir_inode_operations;
 	inode->i_size = 2 * info->s_dirsize;
 	dir_block = minix_bread(inode,0,1);
 	if (!dir_block) {
-		iput(dir);
 		inode->i_nlink--;
-		inode->i_dirt = 1;
+		mark_inode_dirty(inode);
 		iput(inode);
 		return -ENOSPC;
 	}
@@ -350,10 +327,10 @@
 	inode->i_mode = S_IFDIR | (mode & 0777 & ~current->fs->umask);
 	if (dir->i_mode & S_ISGID)
 		inode->i_mode |= S_ISGID;
-	inode->i_dirt = 1;
-	error = minix_add_entry(dir, name, len, &bh, &de);
+	mark_inode_dirty(inode);
+	error = minix_add_entry(dir, dentry->d_name.name,
+				dentry->d_name.len, &bh, &de);
 	if (error) {
-		iput(dir);
 		inode->i_nlink=0;
 		iput(inode);
 		return error;
@@ -361,10 +338,9 @@
 	de->inode = inode->i_ino;
 	mark_buffer_dirty(bh, 1);
 	dir->i_nlink++;
-	dir->i_dirt = 1;
-	iput(dir);
-	iput(inode);
+	mark_inode_dirty(dir);
 	brelse(bh);
+	d_instantiate(dentry, inode);
 	return 0;
 }
 
@@ -427,7 +403,7 @@
 	return 1;
 }
 
-int minix_rmdir(struct inode * dir, const char * name, int len)
+int minix_rmdir(struct inode * dir, struct dentry *dentry)
 {
 	int retval;
 	struct inode * inode;
@@ -435,13 +411,14 @@
 	struct minix_dir_entry * de;
 
 	inode = NULL;
-	bh = minix_find_entry(dir,name,len,&de);
+	bh = minix_find_entry(dir, dentry->d_name.name,
+			      dentry->d_name.len, &de);
 	retval = -ENOENT;
 	if (!bh)
 		goto end_rmdir;
 	retval = -EPERM;
-	if (!(inode = iget(dir->i_sb, de->inode)))
-		goto end_rmdir;
+	inode = dentry->d_inode;
+
         if ((dir->i_mode & S_ISVTX) && !fsuser() &&
             current->fsuid != inode->i_uid &&
             current->fsuid != dir->i_uid)
@@ -462,7 +439,7 @@
 		retval = -ENOENT;
 		goto end_rmdir;
 	}
-	if (atomic_read(&inode->i_count) > 1) {
+	if (inode->i_count > 1) {
 		retval = -EBUSY;
 		goto end_rmdir;
 	}
@@ -472,19 +449,18 @@
 	dir->i_version = ++event;
 	mark_buffer_dirty(bh, 1);
 	inode->i_nlink=0;
-	inode->i_dirt=1;
+	mark_inode_dirty(inode);
 	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 	dir->i_nlink--;
-	dir->i_dirt=1;
+	mark_inode_dirty(dir);
+	d_delete(dentry);
 	retval = 0;
 end_rmdir:
-	iput(dir);
-	iput(inode);
 	brelse(bh);
 	return retval;
 }
 
-int minix_unlink(struct inode * dir, const char * name, int len)
+int minix_unlink(struct inode * dir, struct dentry *dentry)
 {
 	int retval;
 	struct inode * inode;
@@ -494,16 +470,16 @@
 repeat:
 	retval = -ENOENT;
 	inode = NULL;
-	bh = minix_find_entry(dir,name,len,&de);
+	bh = minix_find_entry(dir, dentry->d_name.name,
+			      dentry->d_name.len, &de);
 	if (!bh)
 		goto end_unlink;
-	if (!(inode = iget(dir->i_sb, de->inode)))
-		goto end_unlink;
+	inode = dentry->d_inode;
+
 	retval = -EPERM;
 	if (S_ISDIR(inode->i_mode))
 		goto end_unlink;
 	if (de->inode != inode->i_ino) {
-		iput(inode);
 		brelse(bh);
 		current->counter = 0;
 		schedule();
@@ -527,19 +503,19 @@
 	dir->i_version = ++event;
 	mark_buffer_dirty(bh, 1);
 	dir->i_ctime = dir->i_mtime = CURRENT_TIME;
-	dir->i_dirt = 1;
+	mark_inode_dirty(dir);
 	inode->i_nlink--;
 	inode->i_ctime = dir->i_ctime;
-	inode->i_dirt = 1;
+	mark_inode_dirty(inode);
+	d_delete(dentry);	/* This also frees the inode */
 	retval = 0;
 end_unlink:
 	brelse(bh);
-	iput(inode);
-	iput(dir);
 	return retval;
 }
 
-int minix_symlink(struct inode * dir, const char * name, int len, const char * symname)
+int minix_symlink(struct inode * dir, struct dentry *dentry,
+		  const char * symname)
 {
 	struct minix_dir_entry * de;
 	struct inode * inode = NULL;
@@ -547,17 +523,15 @@
 	int i;
 	char c;
 
-	if (!(inode = minix_new_inode(dir))) {
-		iput(dir);
+	if (!(inode = minix_new_inode(dir)))
 		return -ENOSPC;
-	}
+
 	inode->i_mode = S_IFLNK | 0777;
 	inode->i_op = &minix_symlink_inode_operations;
 	name_block = minix_bread(inode,0,1);
 	if (!name_block) {
-		iput(dir);
 		inode->i_nlink--;
-		inode->i_dirt = 1;
+	        mark_inode_dirty(inode);
 		iput(inode);
 		return -ENOSPC;
 	}
@@ -568,69 +542,63 @@
 	mark_buffer_dirty(name_block, 1);
 	brelse(name_block);
 	inode->i_size = i;
-	inode->i_dirt = 1;
-	bh = minix_find_entry(dir,name,len,&de);
+	mark_inode_dirty(inode);
+	bh = minix_find_entry(dir, dentry->d_name.name,
+			      dentry->d_name.len, &de);
 	if (bh) {
 		inode->i_nlink--;
-		inode->i_dirt = 1;
+		mark_inode_dirty(inode);
 		iput(inode);
 		brelse(bh);
-		iput(dir);
 		return -EEXIST;
 	}
-	i = minix_add_entry(dir, name, len, &bh, &de);
+	i = minix_add_entry(dir, dentry->d_name.name,
+			    dentry->d_name.len, &bh, &de);
 	if (i) {
 		inode->i_nlink--;
-		inode->i_dirt = 1;
+		mark_inode_dirty(inode);
 		iput(inode);
-		iput(dir);
 		return i;
 	}
 	de->inode = inode->i_ino;
 	mark_buffer_dirty(bh, 1);
 	brelse(bh);
-	iput(dir);
-	iput(inode);
+	d_instantiate(dentry, inode);
 	return 0;
 }
 
-int minix_link(struct inode * oldinode, struct inode * dir, const char * name, int len)
+int minix_link(struct inode * inode, struct inode * dir,
+	       struct dentry *dentry)
 {
 	int error;
 	struct minix_dir_entry * de;
 	struct buffer_head * bh;
 
-	if (S_ISDIR(oldinode->i_mode)) {
-		iput(oldinode);
-		iput(dir);
+	if (S_ISDIR(inode->i_mode))
 		return -EPERM;
-	}
-	if (oldinode->i_nlink >= MINIX_LINK_MAX) {
-		iput(oldinode);
-		iput(dir);
+
+	if (inode->i_nlink >= MINIX_LINK_MAX)
 		return -EMLINK;
-	}
-	bh = minix_find_entry(dir,name,len,&de);
+
+	bh = minix_find_entry(dir, dentry->d_name.name,
+			      dentry->d_name.len, &de);
 	if (bh) {
 		brelse(bh);
-		iput(dir);
-		iput(oldinode);
 		return -EEXIST;
 	}
-	error = minix_add_entry(dir, name, len, &bh, &de);
+	error = minix_add_entry(dir, dentry->d_name.name,
+				dentry->d_name.len, &bh, &de);
 	if (error) {
-		iput(dir);
-		iput(oldinode);
+		brelse(bh);
 		return error;
 	}
-	de->inode = oldinode->i_ino;
+	de->inode = inode->i_ino;
 	mark_buffer_dirty(bh, 1);
 	brelse(bh);
-	iput(dir);
-	oldinode->i_nlink++;
-	oldinode->i_ctime = CURRENT_TIME;
-	oldinode->i_dirt = 1;
-	iput(oldinode);
+	inode->i_nlink++;
+	inode->i_ctime = CURRENT_TIME;
+	mark_inode_dirty(inode);
+	d_instantiate(dentry, inode);
 	return 0;
 }
 
@@ -639,7 +607,7 @@
 	int ino;
 	int result;
 
-	atomic_inc(&new_inode->i_count);
+	new_inode->i_count++;
 	result = 0;
 	for (;;) {
 		if (new_inode == old_inode) {
@@ -649,7 +617,9 @@
 		if (new_inode->i_dev != old_inode->i_dev)
 			break;
 		ino = new_inode->i_ino;
-		if (minix_lookup(new_inode,"..",2,&new_inode))
+		if (minix_lookup(new_inode,
+				 &(struct qstr) { "..", 2, 0 },
+				 &new_inode))
 			break;
 		if (new_inode->i_ino == ino)
 			break;
@@ -671,8 +641,8 @@
  * Anybody can rename anything with this: the permission checks are left to the
  * higher-level routines.
  */
-static int do_minix_rename(struct inode * old_dir, const char * old_name, int old_len,
-			   struct inode * new_dir, const char * new_name, int new_len)
+static int do_minix_rename(struct inode * old_dir, struct dentry *old_dentry,
+			   struct inode * new_dir, struct dentry *new_dentry)
 {
 	struct inode * old_inode, * new_inode;
 	struct buffer_head * old_bh, * new_bh, * dir_bh;
@@ -686,28 +656,26 @@
 	brelse(old_bh);
 	brelse(new_bh);
 	brelse(dir_bh);
-	iput(old_inode);
-	iput(new_inode);
 	current->counter = 0;
 	schedule();
 start_up:
 	old_inode = new_inode = NULL;
 	old_bh = new_bh = dir_bh = NULL;
-	old_bh = minix_find_entry(old_dir,old_name,old_len,&old_de);
+	old_bh = minix_find_entry(old_dir, old_dentry->d_name.name,
+				  old_dentry->d_name.len, &old_de);
 	retval = -ENOENT;
 	if (!old_bh)
 		goto end_rename;
-	old_inode = __iget(old_dir->i_sb, old_de->inode);
-	if (!old_inode)
-		goto end_rename;
+	old_inode = old_dentry->d_inode;
 	retval = -EPERM;
 	if ((old_dir->i_mode & S_ISVTX) && 
 	    current->fsuid != old_inode->i_uid &&
 	    current->fsuid != old_dir->i_uid && !fsuser())
 		goto end_rename;
-	new_bh = minix_find_entry(new_dir,new_name,new_len,&new_de);
+	new_inode = new_dentry->d_inode;
+	new_bh = minix_find_entry(new_dir, new_dentry->d_name.name,
+				  new_dentry->d_name.len, &new_de);
 	if (new_bh) {
-		new_inode = __iget(new_dir->i_sb, new_de->inode);
 		if (!new_inode) {
 			brelse(new_bh);
 			new_bh = NULL;
@@ -728,7 +696,7 @@
 		if (!empty_dir(new_inode))
 			goto end_rename;
 		retval = -EBUSY;
-		if (atomic_read(&new_inode->i_count) > 1)
+		if (new_inode->i_count > 1)
 			goto end_rename;
 	}
 	retval = -EPERM;
@@ -754,7 +722,10 @@
 			goto end_rename;
 	}
 	if (!new_bh) {
-		retval = minix_add_entry(new_dir,new_name,new_len,&new_bh,&new_de);
+		retval = minix_add_entry(new_dir,
+					 new_dentry->d_name.name,
+					 new_dentry->d_name.len,
+					 &new_bh, &new_de);
 		if (retval)
 			goto end_rename;
 	}
@@ -769,15 +740,15 @@
 	old_de->inode = 0;
 	new_de->inode = old_inode->i_ino;
 	old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
-	old_dir->i_dirt = 1;
+	mark_inode_dirty(old_dir);
 	old_dir->i_version = ++event;
 	new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME;
-	new_dir->i_dirt = 1;
+	mark_inode_dirty(new_dir);
 	new_dir->i_version = ++event;
 	if (new_inode) {
 		new_inode->i_nlink--;
 		new_inode->i_ctime = CURRENT_TIME;
-		new_inode->i_dirt = 1;
+		mark_inode_dirty(new_inode);
 	}
 	mark_buffer_dirty(old_bh, 1);
 	mark_buffer_dirty(new_bh, 1);
@@ -785,24 +756,23 @@
 		PARENT_INO(dir_bh->b_data) = new_dir->i_ino;
 		mark_buffer_dirty(dir_bh, 1);
 		old_dir->i_nlink--;
-		old_dir->i_dirt = 1;
+		mark_inode_dirty(old_dir);
 		if (new_inode) {
 			new_inode->i_nlink--;
-			new_inode->i_dirt = 1;
+			mark_inode_dirty(new_inode);
 		} else {
 			new_dir->i_nlink++;
-			new_dir->i_dirt = 1;
+			mark_inode_dirty(new_dir);
 		}
 	}
+	/* Update the dcache */
+	d_move(old_dentry, new_dentry->d_parent, &new_dentry->d_name);
+	d_delete(new_dentry);
 	retval = 0;
 end_rename:
 	brelse(dir_bh);
 	brelse(old_bh);
 	brelse(new_bh);
-	iput(old_inode);
-	iput(new_inode);
-	iput(old_dir);
-	iput(new_dir);
 	return retval;
 }
 
@@ -815,8 +785,8 @@
  * the same device that races occur: many renames can happen at once, as long
  * as they are on different partitions.
  */
-int minix_rename(struct inode * old_dir, const char * old_name, int old_len,
-		 struct inode * new_dir, const char * new_name, int new_len)
+int minix_rename(struct inode * old_dir, struct dentry *old_dentry,
+		 struct inode * new_dir, struct dentry *new_dentry)
 {
 	static struct wait_queue * wait = NULL;
 	static int lock = 0;
@@ -825,8 +795,8 @@
 	while (lock)
 		sleep_on(&wait);
 	lock = 1;
-	result = do_minix_rename(old_dir, old_name, old_len,
-				 new_dir, new_name, new_len);
+	result = do_minix_rename(old_dir, old_dentry,
+				 new_dir, new_dentry);
 	lock = 0;
 	wake_up(&wait);
 	return result;
diff -u --recursive --new-file v2.1.44/linux/fs/minix/symlink.c linux/fs/minix/symlink.c
--- v2.1.44/linux/fs/minix/symlink.c	Mon Jun 16 16:35:57 1997
+++ linux/fs/minix/symlink.c	Wed Jul 16 08:12:37 1997
@@ -15,6 +15,7 @@
 #include <asm/uaccess.h>
 
 static int minix_readlink(struct inode *, char *, int);
+static struct dentry *minix_follow_link(struct inode *, struct dentry *);
 
 /*
  * symlinks can't do much...
@@ -31,6 +32,7 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	minix_readlink,		/* readlink */
+	minix_follow_link,	/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
@@ -38,6 +40,21 @@
 	NULL			/* permission */
 };
 
+static struct dentry * minix_follow_link(struct inode * inode, struct dentry * base)
+{
+	struct buffer_head * bh;
+
+	bh = minix_bread(inode, 0, 0);
+	if (!bh) {
+		dput(base);
+		return ERR_PTR(-EIO);
+	}
+	UPDATE_ATIME(inode);
+	base = lookup_dentry(bh->b_data, base, 1);
+	brelse(bh);
+	return base;
+}
+
 static int minix_readlink(struct inode * inode, char * buffer, int buflen)
 {
 	struct buffer_head * bh;
@@ -47,7 +64,6 @@
 	if (buflen > 1023)
 		buflen = 1023;
 	bh = minix_bread(inode, 0, 0);
-	iput(inode);
 	if (!bh)
 		return 0;
 	i = 0;
diff -u --recursive --new-file v2.1.44/linux/fs/minix/truncate.c linux/fs/minix/truncate.c
--- v2.1.44/linux/fs/minix/truncate.c	Mon Apr 22 01:47:49 1996
+++ linux/fs/minix/truncate.c	Wed Jul 16 08:05:24 1997
@@ -58,7 +58,7 @@
 			continue;
 		}
 		*p = 0;
-		inode->i_dirt = 1;
+		mark_inode_dirty(inode);
 		if (bh) {
 			mark_buffer_clean(bh);
 			brelse(bh);
@@ -167,7 +167,7 @@
 		else {
 			tmp = *p;
 			*p = 0;
-			inode->i_dirt = 1;
+			mark_inode_dirty(inode);
 			minix_free_block(inode->i_sb,tmp);
 		}
 	brelse(dind_bh);
@@ -191,7 +191,7 @@
 		schedule();
 	}
 	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-	inode->i_dirt = 1;
+	mark_inode_dirty(inode);
 }
 
 /*
@@ -220,7 +220,7 @@
 			continue;
 		}
 		*p = 0;
-		inode->i_dirt = 1;
+		mark_inode_dirty(inode);
 		if (bh) {
 			mark_buffer_clean(bh);
 			brelse(bh);
@@ -329,7 +329,7 @@
 		else {
 			tmp = *p;
 			*p = 0;
-			inode->i_dirt = 1;
+			mark_inode_dirty(inode);
 			minix_free_block(inode->i_sb,tmp);
 		}
 	brelse(dind_bh);
@@ -374,7 +374,7 @@
                 else {
                         tmp = *p;
                         *p = 0;
-                        inode->i_dirt = 1;
+                        mark_inode_dirty(inode);
                         minix_free_block(inode->i_sb,tmp);
 		}
         brelse(tind_bh);
@@ -402,7 +402,7 @@
 		schedule();
 	}
 	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-	inode->i_dirt = 1;
+	mark_inode_dirty(inode);
 }
 
 /*
diff -u --recursive --new-file v2.1.44/linux/fs/msdos/namei.c linux/fs/msdos/namei.c
--- v2.1.44/linux/fs/msdos/namei.c	Mon Jun 16 16:35:57 1997
+++ linux/fs/msdos/namei.c	Wed Jul 16 19:22:51 1997
@@ -280,7 +280,7 @@
 	 * XXX all times should be set by caller upon successful completion.
 	 */
 	dir->i_ctime = dir->i_mtime = CURRENT_TIME;
-	dir->i_dirt = 1;
+	mark_inode_dirty(dir);
 	memcpy(de->name,name,MSDOS_NAME);
 	memset(de->unused, 0, sizeof(de->unused));
 	de->attr = is_dir ? ATTR_DIR : ATTR_ARCH;
@@ -295,7 +295,7 @@
 	if (!*result) return -EIO;
 	(*result)->i_mtime = (*result)->i_atime = (*result)->i_ctime =
 	    CURRENT_TIME;
-	(*result)->i_dirt = 1;
+	mark_inode_dirty(*result);
 	return 0;
 }
 
@@ -369,7 +369,7 @@
 	struct buffer_head *bh;
 	struct msdos_dir_entry *de;
 
-	if (atomic_read(&dir->i_count) > 1)
+	if (dir->i_count > 1)
 		return -EBUSY;
 	if (MSDOS_I(dir)->i_start) { /* may be zero in mkdir */
 		pos = 0;
@@ -415,7 +415,8 @@
 	inode->i_nlink = 0;
 	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 	dir->i_nlink--;
-	inode->i_dirt = dir->i_dirt = 1;
+	mark_inode_dirty(inode);
+	mark_inode_dirty(dir);
 	de->name[0] = DELETED_FLAG;
 	fat_mark_buffer_dirty(sb, bh, 1);
 	res = 0;
@@ -465,7 +466,7 @@
 	dot->i_size = inode->i_size; /* doesn't grow in the 2nd create_entry */
 	MSDOS_I(dot)->i_start = MSDOS_I(inode)->i_start;
 	dot->i_nlink = inode->i_nlink;
-	dot->i_dirt = 1;
+	mark_inode_dirty(dot);
 	iput(dot);
 	if ((res = msdos_create_entry(inode,MSDOS_DOTDOT,2,1,0,&dot)) < 0)
 		goto mkdir_error;
@@ -473,7 +474,7 @@
 	dot->i_size = dir->i_size;
 	MSDOS_I(dot)->i_start = MSDOS_I(dir)->i_start;
 	dot->i_nlink = dir->i_nlink;
-	dot->i_dirt = 1;
+	mark_inode_dirty(dot);
 	MSDOS_I(inode)->i_busy = 0;
 	iput(dot);
 	iput(inode);
@@ -519,7 +520,8 @@
 	inode->i_nlink = 0;
 	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 	MSDOS_I(inode)->i_busy = 1;
-	inode->i_dirt = dir->i_dirt = 1;
+	mark_inode_dirty(inode);
+	mark_inode_dirty(dir);
 	de->name[0] = DELETED_FLAG;
 	fat_mark_buffer_dirty(sb, bh, 1);
 unlink_done:
@@ -580,11 +582,11 @@
 		}
 		if (S_ISDIR(new_inode->i_mode)) {
 			new_dir->i_nlink--;
-			new_dir->i_dirt = 1;
+			mark_inode_dirty(new_dir);
 		}
 		new_inode->i_nlink = 0;
 		MSDOS_I(new_inode)->i_busy = 1;
-		new_inode->i_dirt = 1;
+		mark_inode_dirty(new_inode);
 		new_de->name[0] = DELETED_FLAG;
 		fat_mark_buffer_dirty(sb, new_bh, 1);
 		iput(new_inode);
@@ -675,7 +677,7 @@
 		}
 		new_inode->i_nlink = 0;
 		MSDOS_I(new_inode)->i_busy = 1;
-		new_inode->i_dirt = 1;
+		mark_inode_dirty(new_inode);
 		new_de->name[0] = DELETED_FLAG;
 		fat_mark_buffer_dirty(sb, new_bh, 1);
 	}
@@ -696,14 +698,14 @@
 	}
 	if (exists && S_ISDIR(new_inode->i_mode)) {
 		new_dir->i_nlink--;
-		new_dir->i_dirt = 1;
+		mark_inode_dirty(new_dir);
 	}
 	msdos_read_inode(free_inode);
 	MSDOS_I(old_inode)->i_busy = 1;
 	MSDOS_I(old_inode)->i_linked = free_inode;
 	MSDOS_I(free_inode)->i_oldlink = old_inode;
 	fat_cache_inval_inode(old_inode);
-	old_inode->i_dirt = 1;
+	mark_inode_dirty(old_inode);
 	old_de->name[0] = DELETED_FLAG;
 	fat_mark_buffer_dirty(sb, old_bh, 1);
 	fat_mark_buffer_dirty(sb, free_bh, 1);
@@ -711,7 +713,7 @@
 		MSDOS_I(new_inode)->i_depend = free_inode;
 		MSDOS_I(free_inode)->i_old = new_inode;
 		/* Two references now exist to free_inode so increase count */
-		atomic_inc(&free_inode->i_count);
+		free_inode->i_count++;
 		/* free_inode is put after putting new_inode and old_inode */
 		iput(new_inode);
 		fat_brelse(sb, new_bh);
@@ -726,7 +728,7 @@
 		}
 		dotdot_de->start = MSDOS_I(dotdot_inode)->i_start =
 		    MSDOS_I(new_dir)->i_start;
-		dotdot_inode->i_dirt = 1;
+		mark_inode_dirty(dotdot_inode);
 		fat_mark_buffer_dirty(sb, dotdot_bh, 1);
 		old_dir->i_nlink--;
 		new_dir->i_nlink++;
@@ -793,6 +795,7 @@
 	NULL,			/* mknod */
 	msdos_rename,		/* rename */
 	NULL,			/* readlink */
+	NULL,			/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	fat_bmap,		/* bmap */
diff -u --recursive --new-file v2.1.44/linux/fs/namei.c linux/fs/namei.c
--- v2.1.44/linux/fs/namei.c	Mon Jul  7 14:48:23 1997
+++ linux/fs/namei.c	Wed Jul 16 15:25:14 1997
@@ -19,10 +19,7 @@
 #include <linux/fcntl.h>
 #include <linux/stat.h>
 #include <linux/mm.h>
-#include <linux/dalloc.h>
-#include <linux/nametrans.h>
 #include <linux/proc_fs.h>
-#include <linux/omirr.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 
@@ -161,20 +158,22 @@
 	return retval;
 }
 
-int getname(const char * filename, char **result)
+char * getname(const char * filename)
 {
-	char *tmp;
-	int retval;
+	char *tmp, *result;
 
+	result = ERR_PTR(-ENOMEM);
 	tmp = get_page();
-	if (!tmp)
-		return -ENOMEM;
-	retval = do_getname(filename, tmp);
-	if (retval < 0)
-		putname(tmp);
-	else
-		*result = tmp;
-	return retval;
+	if (tmp)  {
+		int retval = do_getname(filename, tmp);
+
+		result = tmp;
+		if (retval < 0) {
+			putname(tmp);
+			result = ERR_PTR(retval);
+		}
+	}
+	return result;
 }
 
 /*
@@ -236,60 +235,60 @@
  * We get the directory semaphore, and after getting that we also
  * make sure that nobody added the entry to the dcache in the meantime..
  */
-static struct dentry * real_lookup(struct dentry * dentry, struct qstr * name)
+static struct dentry * real_lookup(struct dentry * parent, struct qstr * name)
 {
-	struct inode *dir = dentry->d_inode;
-	struct dentry *result;
-	struct inode *inode;
-	int error = -ENOTDIR;
-
-	down(&dir->i_sem);
-
-	error = -ENOTDIR;
-	if (dir->i_op && dir->i_op->lookup)
-		error = dir->i_op->lookup(dir, name, &inode);
-	result = ERR_PTR(error);
-
-	if (!error || error == -ENOENT) {
-		struct dentry *new;
-		int isdir = 0, flags = D_NOCHECKDUP;
-
-		if (error) {
-			flags = D_NEGATIVE;
-			inode = NULL;
-		} else if (S_ISDIR(inode->i_mode)) {
-			isdir = 1;
-			flags = D_DIR|D_NOCHECKDUP;
-		}
-		new = d_alloc(dentry, name, isdir);
+	struct dentry * result;
+	struct inode *dir = parent->d_inode;
 
-		/*
-		 * Ok, now we can't sleep any more. Double-check that
-		 * nobody else added this in the meantime..
-		 */
-		result = d_lookup(dentry, name);
-		if (result) {
-			d_free(new);
-		} else {
-			d_add(new, inode, flags);
-			result = new;
+	result = ERR_PTR(-ENOTDIR);
+	if (dir->i_op && dir->i_op->lookup) {
+		down(&dir->i_sem);
+		result = d_lookup(parent, name);
+		if (!result) {
+			int error;
+			result = d_alloc(parent, name);
+			error = dir->i_op->lookup(dir, result);
+			if (error) {
+				d_free(result);
+				result = ERR_PTR(error);
+			}
 		}
+		up(&dir->i_sem);
 	}
 	up(&dir->i_sem);
 	return result;
 }
 
 /* Internal lookup() using the new generic dcache. */
-static inline struct dentry * cached_lookup(struct dentry * dentry, struct qstr * name)
+static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name)
 {
-	return d_lookup(dentry, name);
+	struct dentry * dentry = d_lookup(parent, name);
+
+	if (dentry) {
+		if (dentry->d_revalidate) {
+			/* spin_unlock(&dentry_lock); */
+			dentry = dentry->d_revalidate(dentry);
+			/* spin_lock(&dentry_lock); */
+		}
+
+		/*
+		 * The parent d_count _should_ be at least 2: one for the
+		 * dentry we found, and one for the fact that we are using
+		 * it.
+		 */
+		if (parent->d_count <= 1) {
+			printk("lookup of %s success in %s, but parent count is %d\n",
+				dentry->d_name.name, parent->d_name.name, parent->d_count);
+		}
+	}
+	return dentry;
 }
 
 /*
  * "." and ".." are special - ".." especially so because it has to be able
  * to know about the current root directory and parent relationships
  */
-static struct dentry * reserved_lookup(struct dentry * dir, struct qstr * name)
+static struct dentry * reserved_lookup(struct dentry * parent, struct qstr * name)
 {
 	struct dentry *result = NULL;
 	if (name->name[0] == '.') {
@@ -300,33 +299,16 @@
 			if (name->name[1] != '.')
 				break;
 
-			if (dir != current->fs->root) {
-				dir = dir->d_covers->d_parent;
-			}
+			if (parent != current->fs->root)
+				parent = parent->d_covers->d_parent;
 			/* fallthrough */
 		case 1:
-			result = dget(dir);
-			break;
+			result = parent;
 		}
 	}
 	return result;
 }
 
-static inline int is_reserved(struct dentry *dentry)
-{
-	if (dentry->d_name.name[0] == '.') {
-		switch (dentry->d_name.len) {
-		case 2:
-			if (dentry->d_name.name[1] != '.')
-				break;
-			/* fallthrough */
-		case 1:
-			return 1;
-		}
-	}
-	return 0;
-}
-
 /* In difference to the former version, lookup() no longer eats the dir. */
 static struct dentry * lookup(struct dentry * dir, struct qstr * name)
 {
@@ -337,23 +319,23 @@
 	err = permission(dir->d_inode, MAY_EXEC);
 	result = ERR_PTR(err);
  	if (err)
-		goto done;
+		goto done_error;
 
 	result = reserved_lookup(dir, name);
 	if (result)
-		goto done;
+		goto done_noerror;
 
 	result = cached_lookup(dir, name);
 	if (result)
-		goto done;
+		goto done_noerror;
 
 	result = real_lookup(dir, name);
-	if (!result)
-		result = ERR_PTR(-ENOTDIR);
-done:
-	if (!IS_ERR(result))
-		result = dget(result->d_mounts);
 
+	if (!IS_ERR(result)) {
+done_noerror:
+		result = dget(result->d_mounts);
+	}
+done_error:
 	return result;
 }
 
@@ -364,7 +346,7 @@
 {
 	struct inode * inode = dentry->d_inode;
 
-	if (inode->i_op && inode->i_op->follow_link) {
+	if (inode && inode->i_op && inode->i_op->follow_link) {
 		struct dentry *result;
 
 		/* This eats the base */
@@ -397,7 +379,7 @@
 		base = dget(current->fs->pwd);
 	}
 
-	if (*name == '\0')
+	if (!*name)
 		return base;
 
 	/* At this point we know we have a real path component. */
@@ -405,37 +387,45 @@
 		int len;
 		unsigned long hash;
 		struct qstr this;
-		char c, trailing;
+		char c, follow;
 
+		dentry = ERR_PTR(-ENOENT);
+		if (!base->d_inode)
+			break;
 		this.name = name;
 		hash = init_name_hash();
-		for (len = 0; (c = *name++) && (c != '/') ; len++)
+		len = 0;
+		c = *name;
+		do {
+			len++; name++;
 			hash = partial_name_hash(c, hash);
+			c = *name;
+		} while (c && (c != '/'));
 
 		this.len = len;
 		this.hash = end_name_hash(hash);
 
 		/* remove trailing slashes? */
-		trailing = c;
+		follow = follow_link;
 		if (c) {
-			while ((c = *name) == '/')
-				name++;
+			follow |= c;
+			do {
+				c = *++name;
+			} while (c == '/');
 		}
 
 		dentry = lookup(base, &this);
 		if (IS_ERR(dentry))
 			break;
-		if (dentry->d_flag & D_NEGATIVE)
-			break;
 
-		/* Last component? */
-		if (!c) {
-			if (!trailing && !follow_link)
-				break;
-			return do_follow_link(base, dentry);
-		}
+		if (!follow)
+			break;
 
 		base = do_follow_link(base, dentry);
+		if (c)
+			continue;
+
+		return base;
 	}
 	dput(base);
 	return dentry;
@@ -451,47 +441,35 @@
  * namei exists in two versions: namei/lnamei. The only difference is
  * that namei follows links, while lnamei does not.
  */
-int __namei(const char *pathname, struct inode **res_inode, int follow_link)
+struct dentry * __namei(const char *pathname, int follow_link)
 {
-	int error;
-	char * name;
-
-	error = getname(pathname, &name);
-	if (!error) {
-		struct dentry * dentry;
+	char *name;
+	struct dentry *dentry;
 
+	name = getname(pathname);
+	dentry = (struct dentry *) name;
+	if (!IS_ERR(name)) {
 		dentry = lookup_dentry(name, NULL, follow_link);
 		putname(name);
-		error = PTR_ERR(dentry);
 		if (!IS_ERR(dentry)) {
-			error = -ENOENT;
-			if (dentry) {
-				if (!(dentry->d_flag & D_NEGATIVE)) {
-					struct inode *inode = dentry->d_inode;
-					atomic_inc(&inode->i_count);
-					*res_inode = inode;
-					error = 0;
-				}
+			if (!dentry->d_inode) {
 				dput(dentry);
+				dentry = ERR_PTR(-ENOENT);
 			}
 		}
 	}
-	return error;
+	return dentry;
 }
 
 static inline struct inode *get_parent(struct dentry *dentry)
 {
-	struct inode *dir = dentry->d_parent->d_inode;
-
-	atomic_inc(&dir->i_count);
-	return dir;
+	return dentry->d_parent->d_inode;
 }
 
 static inline struct inode *lock_parent(struct dentry *dentry)
 {
 	struct inode *dir = dentry->d_parent->d_inode;
 
-	atomic_inc(&dir->i_count);
 	down(&dir->i_sem);
 	return dir;
 }
@@ -509,20 +487,20 @@
  * which is a lot more logical, and also allows the "no perm" needed
  * for symlinks (where the permissions are checked later).
  */
-int open_namei(const char * pathname, int flag, int mode,
-               struct inode ** res_inode, struct dentry * base)
+struct dentry * open_namei(const char * pathname, int flag, int mode)
 {
-	int error;
+	int acc_mode, error;
 	struct inode *inode;
 	struct dentry *dentry;
 
 	mode &= S_IALLUGO & ~current->fs->umask;
 	mode |= S_IFREG;
 
-	dentry = lookup_dentry(pathname, base, 1);
+	dentry = lookup_dentry(pathname, NULL, 1);
 	if (IS_ERR(dentry))
-		return PTR_ERR(dentry);
+		return dentry;
 
+	acc_mode = ACC_MODE(flag);
 	if (flag & O_CREAT) {
 		struct inode *dir;
 
@@ -531,7 +509,7 @@
 		 * The existence test must be done _after_ getting the directory
 		 * semaphore - the dentry might otherwise change.
 		 */
-		if (!(dentry->d_flag & D_NEGATIVE)) {
+		if (dentry->d_inode) {
 			error = 0;
 			if (flag & O_EXCL)
 				error = -EEXIST;
@@ -543,23 +521,24 @@
 			if (dir->i_sb && dir->i_sb->dq_op)
 				dir->i_sb->dq_op->initialize(dir, -1);
 			error = dir->i_op->create(dir, dentry, mode);
+			/* Don't check for write permission */
+			acc_mode = 0;
 		}
 		up(&dir->i_sem);
-		iput(dir);
 		if (error)
 			goto exit;
 	}
 
 	error = -ENOENT;
-	if (dentry->d_flag & D_NEGATIVE)
+	inode = dentry->d_inode;
+	if (!inode)
 		goto exit;
 
-	inode = dentry->d_inode;
 	error = -EISDIR;
-	if (S_ISDIR(inode->i_mode) && (flag & 2))
+	if (S_ISDIR(inode->i_mode) && (flag & FMODE_WRITE))
 		goto exit;
 
-	error = permission(inode,ACC_MODE(flag));
+	error = permission(inode,acc_mode);
 	if (error)
 		goto exit;
 
@@ -611,56 +590,54 @@
 			if (inode->i_sb && inode->i_sb->dq_op)
 				inode->i_sb->dq_op->initialize(inode, -1);
 
-	*res_inode = inode;
-	atomic_inc(&inode->i_count);
-	error = 0;
+	return dentry;
 
 exit:
 	dput(dentry);
-	return error;
+	return ERR_PTR(error);
 }
 
-int do_mknod(const char * filename, int mode, dev_t dev)
+struct dentry * do_mknod(const char * filename, int mode, dev_t dev)
 {
 	int error;
 	struct inode *dir;
-	struct dentry *dentry;
+	struct dentry *dentry, *retval;
 
 	mode &= ~current->fs->umask;
 	dentry = lookup_dentry(filename, NULL, 1);
-
-	error = PTR_ERR(dentry);
 	if (IS_ERR(dentry))
-		goto exit;
+		return dentry;
 
 	dir = lock_parent(dentry);
 
-	error = -EEXIST;
-	if (!(dentry->d_flag & D_NEGATIVE))
+	retval = ERR_PTR(-EEXIST);
+	if (dentry->d_inode)
 		goto exit_lock;
 
-	error = -EROFS;
+	retval = ERR_PTR(-EROFS);
 	if (IS_RDONLY(dir))
 		goto exit_lock;
 
 	error = permission(dir,MAY_WRITE | MAY_EXEC);
+	retval = ERR_PTR(error);
 	if (error)
 		goto exit_lock;
 
-	error = -EPERM;
+	retval = ERR_PTR(-EPERM);
 	if (!dir->i_op || !dir->i_op->mknod)
 		goto exit_lock;
 
 	if (dir->i_sb && dir->i_sb->dq_op)
 		dir->i_sb->dq_op->initialize(dir, -1);
 	error = dir->i_op->mknod(dir, dentry, mode, dev);
+	retval = ERR_PTR(error);
+	if (!error)
+		retval = dget(dentry);
 
 exit_lock:
 	up(&dir->i_sem);
-	iput(dir);
 	dput(dentry);
-exit:
-	return error;
+	return retval;
 }
 
 asmlinkage int sys_mknod(const char * filename, int mode, dev_t dev)
@@ -682,10 +659,16 @@
 	default:
 		goto out;
 	}
-	error = getname(filename,&tmp);
-	if (!error) {
-		error = do_mknod(tmp,mode,dev);
+	tmp = getname(filename);
+	error = PTR_ERR(tmp);
+	if (!IS_ERR(tmp)) {
+		struct dentry * dentry = do_mknod(tmp,mode,dev);
 		putname(tmp);
+		error = PTR_ERR(dentry);
+		if (!IS_ERR(dentry)) {
+			dput(dentry);
+			error = 0;
+		}
 	}
 out:
 	unlock_kernel();
@@ -710,7 +693,7 @@
 	dir = lock_parent(dentry);
 
 	error = -EEXIST;
-	if (!(dentry->d_flag & D_NEGATIVE))
+	if (dentry->d_inode)
 		goto exit_lock;
 
 	error = -EROFS;
@@ -732,7 +715,6 @@
 
 exit_lock:
 	up(&dir->i_sem);
-	iput(dir);
 	dput(dentry);
 exit:
 	return error;
@@ -744,8 +726,9 @@
 	char * tmp;
 
 	lock_kernel();
-	error = getname(pathname,&tmp);
-	if (!error) {
+	tmp = getname(pathname);
+	error = PTR_ERR(tmp);
+	if (!IS_ERR(tmp)) {
 		error = do_mkdir(tmp,mode);
 		putname(tmp);
 	}
@@ -766,7 +749,7 @@
 
 	dir = lock_parent(dentry);
 	error = -ENOENT;
-	if (dentry->d_flag & D_NEGATIVE)
+	if (!dentry->d_inode)
 		goto exit_lock;
 
 	error = -EROFS;
@@ -800,7 +783,6 @@
 
 exit_lock:
         up(&dir->i_sem);
-        iput(dir);
 	dput(dentry);
 exit:
 	return error;
@@ -812,8 +794,9 @@
 	char * tmp;
 
 	lock_kernel();
-	error = getname(pathname,&tmp);
-	if (!error) {
+	tmp = getname(pathname);
+	error = PTR_ERR(tmp);
+	if (!IS_ERR(tmp)) {
 		error = do_rmdir(tmp);
 		putname(tmp);
 	}
@@ -860,7 +843,6 @@
 
 exit_lock:
         up(&dir->i_sem);
-        iput(dir);
 	dput(dentry);
 exit:
 	return error;
@@ -872,8 +854,9 @@
 	char * tmp;
 
 	lock_kernel();
-	error = getname(pathname,&tmp);
-	if (!error) {
+	tmp = getname(pathname);
+	error = PTR_ERR(tmp);
+	if (!IS_ERR(tmp)) {
 		error = do_unlink(tmp);
 		putname(tmp);
 	}
@@ -894,7 +877,7 @@
 		goto exit;
 
 	error = -EEXIST;
-	if (!(dentry->d_flag & D_NEGATIVE))
+	if (dentry->d_inode)
 		goto exit;
 
 	dir = lock_parent(dentry);
@@ -917,7 +900,6 @@
 
 exit_lock:
 	up(&dir->i_sem);
-	iput(dir);
 	dput(dentry);
 exit:
 	return error;
@@ -926,13 +908,16 @@
 asmlinkage int sys_symlink(const char * oldname, const char * newname)
 {
 	int error;
-	char * from, * to;
+	char * from;
 
 	lock_kernel();
-	error = getname(oldname,&from);
-	if (!error) {
-		error = getname(newname,&to);
-		if (!error) {
+	from = getname(oldname);
+	error = PTR_ERR(from);
+	if (!IS_ERR(from)) {
+		char * to;
+		to = getname(newname);
+		error = PTR_ERR(to);
+		if (!IS_ERR(to)) {
 			error = do_symlink(from,to);
 			putname(to);
 		}
@@ -961,18 +946,18 @@
 	dir = lock_parent(new_dentry);
 
 	error = -ENOENT;
-	if (old_dentry->d_flag & D_NEGATIVE)
+	inode = old_dentry->d_inode;
+	if (!inode)
 		goto exit_lock;
 
 	error = -EEXIST;
-	if (!(new_dentry->d_flag & D_NEGATIVE))
+	if (new_dentry->d_inode)
 		goto exit_lock;
 
 	error = -EROFS;
 	if (IS_RDONLY(dir))
 		goto exit_lock;
 
-	inode = old_dentry->d_inode;
 	error = -EXDEV;
 	if (dir->i_dev != inode->i_dev)
 		goto exit_lock;
@@ -998,7 +983,6 @@
 
 exit_lock:
 	up(&dir->i_sem);
-	iput(dir);
 	dput(new_dentry);
 exit_old:
 	dput(old_dentry);
@@ -1009,13 +993,16 @@
 asmlinkage int sys_link(const char * oldname, const char * newname)
 {
 	int error;
-	char * from, * to;
+	char * from;
 
 	lock_kernel();
-	error = getname(oldname,&from);
-	if (!error) {
-		error = getname(newname,&to);
-		if (!error) {
+	from = getname(oldname);
+	error = PTR_ERR(from);
+	if (!IS_ERR(from)) {
+		char * to;
+		to = getname(newname);
+		error = PTR_ERR(to);
+		if (!IS_ERR(to)) {
 			error = do_link(from,to);
 			putname(to);
 		}
@@ -1043,6 +1030,21 @@
 	}
 }
 
+static inline int is_reserved(struct dentry *dentry)
+{
+	if (dentry->d_name.name[0] == '.') {
+		switch (dentry->d_name.len) {
+		case 2:
+			if (dentry->d_name.name[1] != '.')
+				break;
+			/* fallthrough */
+		case 1:
+			return 1;
+		}
+	}
+	return 0;
+}
+
 static inline int do_rename(const char * oldname, const char * newname)
 {
 	int error;
@@ -1067,7 +1069,7 @@
 	double_down(&new_dir->i_sem, &old_dir->i_sem);
 
 	error = -ENOENT;
-	if (old_dentry->d_flag & D_NEGATIVE)
+	if (!old_dentry->d_inode)
 		goto exit_lock;
 
 	error = permission(old_dir,MAY_WRITE | MAY_EXEC);
@@ -1112,8 +1114,6 @@
 exit_lock:
 	up(&new_dir->i_sem);
 	up(&old_dir->i_sem);
-	iput(old_dir);
-	iput(new_dir);
 	dput(new_dentry);
 exit_old:
 	dput(old_dentry);
@@ -1124,13 +1124,16 @@
 asmlinkage int sys_rename(const char * oldname, const char * newname)
 {
 	int error;
-	char * from, * to;
+	char * from;
 
 	lock_kernel();
-	error = getname(oldname,&from);
-	if (!error) {
-		error = getname(newname,&to);
-		if (!error) {
+	from = getname(oldname);
+	error = PTR_ERR(from);
+	if (!IS_ERR(from)) {
+		char * to;
+		to = getname(newname);
+		error = PTR_ERR(to);
+		if (!IS_ERR(to)) {
 			error = do_rename(from,to);
 			putname(to);
 		}
diff -u --recursive --new-file v2.1.44/linux/fs/ncpfs/mmap.c linux/fs/ncpfs/mmap.c
--- v2.1.44/linux/fs/ncpfs/mmap.c	Mon Jun 16 16:35:58 1997
+++ linux/fs/ncpfs/mmap.c	Wed Jul 16 19:22:51 1997
@@ -132,8 +132,8 @@
 		inode->i_atime = CURRENT_TIME;
 		inode->i_dirt = 1;
 	}
-	vma->vm_inode = inode;
-	atomic_inc(&inode->i_count);
+
+	vma->vm_dentry = dget(file->f_dentry);
 	vma->vm_ops = &ncp_file_mmap;
 	return 0;
 }
diff -u --recursive --new-file v2.1.44/linux/fs/nfs/dir.c linux/fs/nfs/dir.c
--- v2.1.44/linux/fs/nfs/dir.c	Mon Jul  7 11:28:16 1997
+++ linux/fs/nfs/dir.c	Wed Jul 16 14:25:52 1997
@@ -42,7 +42,7 @@
 static int nfs_dir_open(struct inode * inode, struct file * file);
 static long nfs_dir_read(struct inode *, struct file *, char *, unsigned long);
 static int nfs_readdir(struct inode *, struct file *, void *, filldir_t);
-static int nfs_lookup(struct inode *, struct qstr *, struct inode **);
+static int nfs_lookup(struct inode *, struct dentry *);
 static int nfs_create(struct inode *, struct dentry *, int);
 static int nfs_mkdir(struct inode *, struct dentry *, int);
 static int nfs_rmdir(struct inode *, struct dentry *);
@@ -328,19 +328,17 @@
 }
  
 
-static int nfs_lookup(struct inode *dir, struct qstr * __name,
-		      struct inode **result)
+static int nfs_lookup(struct inode *dir, struct dentry * dentry)
 {
+	struct inode *inode;
 	struct nfs_fh fhandle;
 	struct nfs_fattr fattr;
-	int len = __name->len;
-	char name[len > NFS_MAXNAMLEN? 1 : len+1];
+	int len = dentry->d_name.len;
 	int error;
 
 	dfprintk(VFS, "NFS: lookup(%x/%ld, %.*s)\n",
-				dir->i_dev, dir->i_ino, len, __name->name);
+				dir->i_dev, dir->i_ino, len, dentry->d_name.name);
 
-	*result = NULL;
 	if (!dir || !S_ISDIR(dir->i_mode)) {
 		printk("nfs_lookup: inode is NULL or not a directory\n");
 		return -ENOENT;
@@ -349,17 +347,18 @@
 	if (len > NFS_MAXNAMLEN)
 		return -ENAMETOOLONG;
 
-	memcpy(name,__name->name,len);
-	name[len] = '\0';
+	error = nfs_proc_lookup(NFS_SERVER(dir), NFS_FH(dir), dentry->d_name.name, &fhandle, &fattr);
 
-	error = nfs_proc_lookup(NFS_SERVER(dir), NFS_FH(dir),
-		name, &fhandle, &fattr);
-	if (error)
+	inode = NULL;
+	if (!error) {
+		error = -ENOENT;
+		inode = nfs_fhget(dir->i_sb, &fhandle, &fattr);
+		if (!inode)
+			return -EACCES;
+	} else if (error != -ENOENT)
 		return error;
 
-	if (!(*result = nfs_fhget(dir->i_sb, &fhandle, &fattr)))
-		return -EACCES;
-
+	d_add(dentry, inode);
 	return 0;
 }
 
@@ -395,7 +394,7 @@
 	if (!inode)
 		return -EACCES;
 
-	d_instantiate(dentry, inode, 0);
+	d_instantiate(dentry, inode);
 	return 0;
 }
 
@@ -434,7 +433,7 @@
 	if (!inode)
 		return -EACCES;
 
-	d_instantiate(dentry, inode, 0);
+	d_instantiate(dentry, inode);
 	return 0;
 }
 
@@ -471,7 +470,7 @@
 	if (!inode)
 		return -EACCES;
 
-	d_instantiate(dentry, inode, D_DIR);
+	d_instantiate(dentry, inode);
 	return 0;
 }
 
@@ -561,7 +560,7 @@
 	if (!inode)
 		return -EACCES;
 
-	d_instantiate(dentry, inode, 0);
+	d_instantiate(dentry, inode);
 	return 0;
 }
 
@@ -587,8 +586,8 @@
 	if (error)
 		return error;
 
-	atomic_inc(&inode->i_count);
-	d_instantiate(dentry, inode, 0);
+	inode->i_count++;
+	d_instantiate(dentry, inode);
 	return 0;
 }
 
@@ -647,8 +646,7 @@
 	int was_empty;
 
 	dfprintk(VFS, "NFS: refresh_inode(%x/%ld ct=%d)\n",
-		 inode->i_dev, inode->i_ino,
-		 atomic_read(&inode->i_count));
+		 inode->i_dev, inode->i_ino, inode->i_count);
 
 	if (!inode || !fattr) {
 		printk("nfs_refresh_inode: inode or fattr is NULL\n");
diff -u --recursive --new-file v2.1.44/linux/fs/nfs/file.c linux/fs/nfs/file.c
--- v2.1.44/linux/fs/nfs/file.c	Mon Jul  7 10:53:54 1997
+++ linux/fs/nfs/file.c	Wed Jul 16 11:41:19 1997
@@ -143,7 +143,7 @@
 	int	result;
 
 	dfprintk(VFS, "nfs: write(%x/%ld (%d), %lu@%lu)\n",
-			inode->i_dev, inode->i_ino, atomic_read(&inode->i_count),
+			inode->i_dev, inode->i_ino, inode->i_count,
 			count, (unsigned long) file->f_pos);
 
 	if (!inode) {
@@ -180,11 +180,11 @@
 	int	status;
 
 	dprintk("NFS: nfs_lock(f=%4x/%ld, t=%x, fl=%x, r=%ld:%ld)\n",
-			filp->f_inode->i_dev, filp->f_inode->i_ino,
+			filp->f_dentry->d_inode->i_dev, filp->f_dentry->d_inode->i_ino,
 			fl->fl_type, fl->fl_flags,
 			fl->fl_start, fl->fl_end);
 
-	if (!(inode = filp->f_inode))
+	if (!(inode = filp->f_dentry->d_inode))
 		return -EINVAL;
 
 	/* No mandatory locks over NFS */
diff -u --recursive --new-file v2.1.44/linux/fs/nfs/inode.c linux/fs/nfs/inode.c
--- v2.1.44/linux/fs/nfs/inode.c	Mon Jul  7 13:06:09 1997
+++ linux/fs/nfs/inode.c	Wed Jul 16 11:40:59 1997
@@ -36,15 +36,17 @@
 
 static int nfs_notify_change(struct inode *, struct iattr *);
 static void nfs_put_inode(struct inode *);
+static void nfs_delete_inode(struct inode *);
 static void nfs_put_super(struct super_block *);
 static void nfs_read_inode(struct inode *);
-static void nfs_statfs(struct super_block *, struct statfs *, int bufsiz);
+static int nfs_statfs(struct super_block *, struct statfs *, int bufsiz);
 
 static struct super_operations nfs_sops = { 
 	nfs_read_inode,		/* read inode */
-	nfs_notify_change,	/* notify change */
 	NULL,			/* write inode */
 	nfs_put_inode,		/* put inode */
+	nfs_delete_inode,	/* delete inode */
+	nfs_notify_change,	/* notify change */
 	nfs_put_super,		/* put superblock */
 	NULL,			/* write superblock */
 	nfs_statfs,		/* stat filesystem */
@@ -73,9 +75,16 @@
 nfs_put_inode(struct inode * inode)
 {
 	dprintk("NFS: put_inode(%x/%ld)\n", inode->i_dev, inode->i_ino);
+}
 
-	if (inode->i_pipe)
-		clear_inode(inode);
+/*
+ * This should do any silly-rename cleanups once we
+ * get silly-renaming working again..
+ */
+static void
+nfs_delete_inode(struct inode * inode)
+{
+	dprintk("NFS: delete_inode(%x/%ld)\n", inode->i_dev, inode->i_ino);
 }
 
 void
@@ -249,7 +258,7 @@
 	return NULL;
 }
 
-static void
+static int
 nfs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
 {
 	int error;
@@ -270,7 +279,7 @@
 	tmp.f_files = 0;
 	tmp.f_ffree = 0;
 	tmp.f_namelen = NAME_MAX;
-	copy_to_user(buf, &tmp, bufsiz);
+	return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
 }
 
 /*
@@ -316,7 +325,7 @@
 	}
 	dprintk("NFS: fhget(%x/%ld ct=%d)\n",
 		inode->i_dev, inode->i_ino,
-		atomic_read(&inode->i_count));
+		inode->i_count);
 
 	return inode;
 }
@@ -363,7 +372,6 @@
 		nfs_truncate_dirty_pages(inode, sattr.size);
 		nfs_refresh_inode(inode, &fattr);
 	}
-	inode->i_dirt = 0;
 	return error;
 }
 
diff -u --recursive --new-file v2.1.44/linux/fs/nfs/nfsroot.c linux/fs/nfs/nfsroot.c
--- v2.1.44/linux/fs/nfs/nfsroot.c	Mon Jun 16 16:35:58 1997
+++ linux/fs/nfs/nfsroot.c	Wed Jul 16 20:37:21 1997
@@ -1,5 +1,5 @@
 /*
- *  $Id: nfsroot.c,v 1.37 1997/06/04 08:28:10 davem Exp $
+ *  $Id: nfsroot.c,v 1.38 1997/07/17 03:21:06 davem Exp $
  *
  *  Copyright (C) 1995, 1996  Gero Kuhlmann <gero@gkminix.han.de>
  *
@@ -78,7 +78,6 @@
 
 #include <asm/param.h>
 #include <linux/utsname.h>
-#include <linux/nametrans.h>
 #include <linux/in.h>
 #include <linux/if.h>
 #include <linux/inet.h>
@@ -833,9 +832,6 @@
 			root_bootp_string(nfs_path, ext+1, *ext, NFS_MAXPATHLEN);
 			break;
 	}
-#ifdef CONFIG_TRANS_NAMES
-	translations_dirty = 1;
-#endif
 }
 
 
@@ -1258,9 +1254,6 @@
 	system_utsname.domainname[0] = '\0';
 	user_dev_name[0] = '\0';
 	bootp_flag = rarp_flag = 1;
-#ifdef CONFIG_TRANS_NAMES
-	translations_dirty = 1;
-#endif
 
 	/* The following is just a shortcut for automatic IP configuration */
 	if (!strcmp(addrs, "bootp")) {
@@ -1306,9 +1299,6 @@
 				}
 				strncpy(system_utsname.nodename, ip, __NEW_UTS_LEN);
 				system_utsname.nodename[__NEW_UTS_LEN] = '\0';
-#ifdef CONFIG_TRANS_NAMES
-				translations_dirty = 1;
-#endif
 				break;
 			case 5:
 				strncpy(user_dev_name, ip, IFNAMSIZ);
@@ -1342,9 +1332,6 @@
 	if (!system_utsname.nodename[0]) {
 		strncpy(system_utsname.nodename, in_ntoa(myaddr), __NEW_UTS_LEN);
 		system_utsname.nodename[__NEW_UTS_LEN] = '\0';
-#ifdef CONFIG_TRANS_NAMES
-		translations_dirty = 1;
-#endif
 	}
 
 	/* Set the correct netmask */
diff -u --recursive --new-file v2.1.44/linux/fs/nfs/read.c linux/fs/nfs/read.c
--- v2.1.44/linux/fs/nfs/read.c	Mon Jun 16 16:35:58 1997
+++ linux/fs/nfs/read.c	Wed Jul 16 12:54:02 1997
@@ -150,7 +150,6 @@
 		fail++;
 		dprintk("NFS: %d successful reads, %d failures\n", succ, fail);
 	}
-	iput(req->ra_inode);
 	clear_bit(PG_locked, &page->flags);
 	wake_up(&page->wait);
 
@@ -188,7 +187,6 @@
 				nfs_readpage_result, req);
 
 	if (result >= 0) {
-		atomic_inc(&inode->i_count);
 		atomic_inc(&page->count);
 		return 0;
 	}
diff -u --recursive --new-file v2.1.44/linux/fs/nfs/write.c linux/fs/nfs/write.c
--- v2.1.44/linux/fs/nfs/write.c	Mon Jun 16 16:35:58 1997
+++ linux/fs/nfs/write.c	Wed Jul 16 12:53:49 1997
@@ -338,7 +338,7 @@
 	wreq->wb_page   = page;
 	wreq->wb_offset = offset;
 	wreq->wb_bytes  = bytes;
-	atomic_inc(&inode->i_count);
+
 	atomic_inc(&page->count);
 
 	append_write_request(&NFS_WRITEBACK(inode), wreq);
@@ -695,7 +695,6 @@
 
 	status = req->wb_task.tk_status;
 	remove_write_request(&nfs_failed_requests, req);
-	iput(req->wb_inode);
 	kfree(req);
 	return status;
 }
@@ -788,7 +787,6 @@
 			dprintk("NFS: %4d saving write failure code\n",
 						task->tk_pid);
 			append_write_request(&nfs_failed_requests, req);
-			atomic_inc(&inode->i_count);
 		}
 		clear_bit(PG_uptodate, &page->flags);
 	} else if (!WB_CANCELLED(req)) {
@@ -818,6 +816,5 @@
 		kfree(req);
 
 	free_page(page_address(page));
-	iput(inode);
 	nr_write_requests--;
 }
diff -u --recursive --new-file v2.1.44/linux/fs/nfsd/export.c linux/fs/nfsd/export.c
--- v2.1.44/linux/fs/nfsd/export.c	Mon Jun 16 16:35:58 1997
+++ linux/fs/nfsd/export.c	Wed Jul 16 19:22:51 1997
@@ -331,7 +331,7 @@
 
 	if (!(exp = exp_get(clp, dev, ino)))
 		return -EPERM;
-	atomic_inc(&exp->ex_inode->i_count);
+	exp->ex_inode->i_count++;
 	fh_compose(&fh, exp, exp->ex_inode);
 	memcpy(f, &fh.fh_handle, sizeof(struct knfs_fh));
 	fh_put(&fh);
diff -u --recursive --new-file v2.1.44/linux/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c
--- v2.1.44/linux/fs/nfsd/vfs.c	Mon Jun 16 16:35:58 1997
+++ linux/fs/nfsd/vfs.c	Wed Jul 16 19:22:51 1997
@@ -120,13 +120,13 @@
 	dotdot = (len == 2 && name[0] == '.' && name[1] == '.');
 	if (dotdot) {
 		if (dirp == current->fs->root) {
-			atomic_inc(&dirp->i_count);
+			dirp->i_count++;
 			*resfh = *fhp;
 			return 0;
 		}
 
 		if (dirp->i_dev == exp->ex_dev && dirp->i_ino == exp->ex_ino) {
-			atomic_inc(&dirp->i_count);
+			dirp->i_count++;
 			*resfh = *fhp;
 			return 0;
 		}
@@ -144,12 +144,12 @@
  	if (perm != 0)
 		return perm;
 	if (!len) {
-		atomic_inc(&dirp->i_count);
+		dirp->i_count++;
 		*resfh = *fhp;
 		return 0;
 	}
 
-	atomic_inc(&dirp->i_count);		/* lookup eats the dirp inode */
+	dirp->i_count++;		/* lookup eats the dirp inode */
 	err = dirp->i_op->lookup(dirp, name, len, &inode);
 
 	if (err)
@@ -162,7 +162,7 @@
 	if (!dotdot && (sb = inode->i_sb) && (inode == sb->s_mounted)) {
 		iput(inode);
 		inode = sb->s_covered;
-		atomic_inc(&inode->i_count);
+		inode->i_count++;
 	}
 
 	fh_compose(resfh, exp, inode);
@@ -291,7 +291,7 @@
 		}
 	}
 
-	atomic_inc(&inode->i_count);
+	inode->i_count++;
 	return 0;
 }
 
@@ -304,7 +304,7 @@
 	struct inode	*inode;
 
 	inode = filp->f_inode;
-	if (!atomic_read(&inode->i_count))
+	if (!inode->i_count)
 		printk(KERN_WARNING "nfsd: inode count == 0!\n");
 	if (filp->f_op && filp->f_op->release)
 		filp->f_op->release(inode, filp);
@@ -533,7 +533,7 @@
 
 	fh_lock(fhp);			/* lock directory */
 	dirp = fhp->fh_inode;
-	atomic_inc(&dirp->i_count);	/* dirop eats the inode */
+	dirp->i_count++;	/* dirop eats the inode */
 
 	switch (type) {
 	case S_IFREG:
@@ -568,7 +568,7 @@
 	 * If the VFS call doesn't return the inode, look it up now.
 	 */
 	if (inode == NULL) {
-		atomic_inc(&dirp->i_count);
+		dirp->i_count++;
 		err = dirp->i_op->lookup(dirp, fname, flen, &inode);
 		if (err < 0)
 			return -nfserrno(err);	/* Huh?! */
@@ -643,7 +643,7 @@
 	if (!inode->i_op || !inode->i_op->readlink)
 		return nfserr_io;
 
-	atomic_inc(&inode->i_count);
+	inode->i_count++;
 	oldfs = get_fs(); set_fs(KERNEL_DS);
 	err = inode->i_op->readlink(inode, buf, *lenp);
 	set_fs(oldfs);
@@ -680,7 +680,7 @@
 		return nfserr_perm;
 
 	fh_lock(fhp);			/* lock inode */
-	atomic_inc(&dirp->i_count);
+	dirp->i_count++;
 	err = dirp->i_op->symlink(dirp, fname, flen, path);
 	fh_unlock(fhp);			/* unlock inode */
 
@@ -693,7 +693,7 @@
 	/*
 	 * Okay, now look up the inode of the new symlink.
 	 */
-	atomic_inc(&dirp->i_count);	/* lookup eats the dirp inode */
+	dirp->i_count++;	/* lookup eats the dirp inode */
 	err = dirp->i_op->lookup(dirp, fname, flen, &inode);
 	if (err)
 		return nfserrno(-err);
@@ -730,7 +730,7 @@
 		return nfserr_perm;
 
 	fh_lock(ffhp);			/* lock directory inode */
-	atomic_inc(&dirp->i_count);
+	dirp->i_count++;
 	err = dirp->i_op->link(dest, dirp, fname, len);
 	fh_unlock(ffhp);		/* unlock inode */
 
@@ -770,8 +770,8 @@
 		return nfserr_perm;
 
 	fh_lock(tfhp);			/* lock destination directory */
-	atomic_inc(&tdir->i_count);
-	atomic_inc(&fdir->i_count);
+	tdir->i_count++;
+	fdir->i_count++;
 	err = fdir->i_op->rename(fdir, fname, flen, tdir, tname, tlen);
 	fh_unlock(tfhp);		/* unlock inode */
 
@@ -805,12 +805,12 @@
 	if (type == S_IFDIR) {
 		if (!dirp->i_op || !dirp->i_op->rmdir)
 			return nfserr_notdir;
-		atomic_inc(&dirp->i_count);
+		dirp->i_count++;
 		err = dirp->i_op->rmdir(dirp, fname, flen);
 	} else {	/* other than S_IFDIR */
 		if (!dirp->i_op || !dirp->i_op->unlink)
 			return nfserr_perm;
-		atomic_inc(&dirp->i_count);
+		dirp->i_count++;
 		err = dirp->i_op->unlink(dirp, fname, flen);
 	}
 
diff -u --recursive --new-file v2.1.44/linux/fs/open.c linux/fs/open.c
--- v2.1.44/linux/fs/open.c	Sun Jul  6 20:13:54 1997
+++ linux/fs/open.c	Wed Jul 16 17:05:45 1997
@@ -4,7 +4,6 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  */
 
-#include <linux/config.h>
 #include <linux/vfs.h>
 #include <linux/types.h>
 #include <linux/utime.h>
@@ -21,32 +20,27 @@
 #include <linux/file.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
-#include <linux/omirr.h>
 
 #include <asm/uaccess.h>
 #include <asm/bitops.h>
 
 asmlinkage int sys_statfs(const char * path, struct statfs * buf)
 {
-	struct inode * inode;
+	struct dentry * dentry;
 	int error;
 
 	lock_kernel();
-	error = verify_area(VERIFY_WRITE, buf, sizeof(struct statfs));
-	if (error)
-		goto out;
-	error = namei(path, &inode);
-	if (error)
-		goto out;
-	error = -ENOSYS;
-	if (!inode->i_sb->s_op->statfs) {
-		iput(inode);
-		goto out;
+	dentry = namei(path);
+	error = PTR_ERR(dentry);
+	if (!IS_ERR(dentry)) {
+		struct inode * inode = dentry->d_inode;
+
+		error = -ENOSYS;
+		if (inode->i_sb->s_op->statfs)
+			error = inode->i_sb->s_op->statfs(inode->i_sb, buf, sizeof(struct statfs));
+
+		dput(dentry);
 	}
-	inode->i_sb->s_op->statfs(inode->i_sb, buf, sizeof(struct statfs));
-	iput(inode);
-	error = 0;
-out:
 	unlock_kernel();
 	return error;
 }
@@ -54,6 +48,7 @@
 asmlinkage int sys_fstatfs(unsigned int fd, struct statfs * buf)
 {
 	struct inode * inode;
+	struct dentry * dentry;
 	struct file * file;
 	int error;
 
@@ -63,7 +58,9 @@
 		goto out;
 	if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
 		error = -EBADF;
-	else if (!(inode = file->f_inode))
+	else if (!(dentry = file->f_dentry))
+		error = -ENOENT;
+	else if (!(inode = dentry->d_inode))
 		error = -ENOENT;
 	else if (!inode->i_sb)
 		error = -ENODEV;
@@ -90,7 +87,6 @@
 		vmtruncate(inode, length);
 		if (inode->i_op && inode->i_op->truncate)
 			inode->i_op->truncate(inode);
-		inode->i_status |= ST_MODIFIED;
 	}
 	up(&inode->i_sem);
 	return error;
@@ -98,33 +94,37 @@
 
 asmlinkage int sys_truncate(const char * path, unsigned long length)
 {
+	struct dentry * dentry;
 	struct inode * inode;
 	int error;
 
 	lock_kernel();
-	error = namei(path, &inode);
-	if (error)
+	dentry = namei(path);
+
+	error = PTR_ERR(dentry);
+	if (IS_ERR(dentry))
 		goto out;
+	inode = dentry->d_inode;
 
 	error = -EACCES;
 	if (S_ISDIR(inode->i_mode))
-		goto iput_and_out;
+		goto dput_and_out;
 
 	error = permission(inode,MAY_WRITE);
 	if (error)
-		goto iput_and_out;
+		goto dput_and_out;
 
 	error = -EROFS;
 	if (IS_RDONLY(inode))
-		goto iput_and_out;
+		goto dput_and_out;
 
 	error = -EPERM;
 	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
-		goto iput_and_out;
+		goto dput_and_out;
 
 	error = get_write_access(inode);
 	if (error)
-		goto iput_and_out;
+		goto dput_and_out;
 
 	error = locks_verify_area(FLOCK_VERIFY_WRITE, inode, NULL,
 				  length < inode->i_size ? length : inode->i_size,
@@ -135,8 +135,8 @@
 		error = do_truncate(inode, length);
 	}
 	put_write_access(inode);
-iput_and_out:
-	iput(inode);
+dput_and_out:
+	dput(dentry);
 out:
 	unlock_kernel();
 	return error;
@@ -145,13 +145,16 @@
 asmlinkage int sys_ftruncate(unsigned int fd, unsigned long length)
 {
 	struct inode * inode;
+	struct dentry *dentry;
 	struct file * file;
 	int error;
 
 	lock_kernel();
 	if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
 		error = -EBADF;
-	else if (!(inode = file->f_inode))
+	else if (!(dentry = file->f_dentry))
+		error = -ENOENT;
+	else if (!(inode = dentry->d_inode))
 		error = -ENOENT;
 	else if (S_ISDIR(inode->i_mode) || !(file->f_mode & FMODE_WRITE))
 		error = -EACCES;
@@ -184,17 +187,21 @@
 asmlinkage int sys_utime(char * filename, struct utimbuf * times)
 {
 	int error;
+	struct dentry * dentry;
 	struct inode * inode;
 	struct iattr newattrs;
 
 	lock_kernel();
-	/* Hmm, should I always follow symlinks or not ? */
-	error = namei(filename, &inode);
-	if (error)
+	dentry = namei(filename);
+
+	error = PTR_ERR(dentry);
+	if (IS_ERR(dentry))
 		goto out;
+	inode = dentry->d_inode;
+
 	error = -EROFS;
 	if (IS_RDONLY(inode))
-		goto iput_and_out;
+		goto dput_and_out;
 
 	/* Don't worry, the checks are done in inode_change_ok() */
 	newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
@@ -203,22 +210,17 @@
 		if (!error) 
 			error = get_user(newattrs.ia_mtime, &times->modtime);
 		if (error)
-			goto iput_and_out;
+			goto dput_and_out;
 
 		newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
 	} else {
 		if (current->fsuid != inode->i_uid &&
 		    (error = permission(inode,MAY_WRITE)) != 0)
-			goto iput_and_out;
+			goto dput_and_out;
 	}
 	error = notify_change(inode, &newattrs);
-#ifdef CONFIG_OMIRR
-	if(!error)
-		omirr_printall(inode, " U %ld %ld %ld ", CURRENT_TIME,
-				newattrs.ia_atime, newattrs.ia_mtime);
-#endif
-iput_and_out:
-	iput(inode);
+dput_and_out:
+	dput(dentry);
 out:
 	unlock_kernel();
 	return error;
@@ -233,38 +235,39 @@
 asmlinkage int sys_utimes(char * filename, struct timeval * utimes)
 {
 	int error;
+	struct dentry * dentry;
 	struct inode * inode;
 	struct iattr newattrs;
 
 	lock_kernel();
-	error = namei(filename, &inode);
-	if (error)
+	dentry = namei(filename);
+
+	error = PTR_ERR(dentry);
+	if (IS_ERR(dentry))
 		goto out;
+	inode = dentry->d_inode;
+
 	error = -EROFS;
 	if (IS_RDONLY(inode))
-		goto iput_and_out;
+		goto dput_and_out;
+
 	/* Don't worry, the checks are done in inode_change_ok() */
 	newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
 	if (utimes) {
 		struct timeval times[2];
 		error = -EFAULT;
 		if (copy_from_user(&times, utimes, sizeof(times)))
-			goto iput_and_out;
+			goto dput_and_out;
 		newattrs.ia_atime = times[0].tv_sec;
 		newattrs.ia_mtime = times[1].tv_sec;
 		newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
 	} else {
 		if ((error = permission(inode,MAY_WRITE)) != 0)
-			goto iput_and_out;
+			goto dput_and_out;
 	}
 	error = notify_change(inode, &newattrs);
-#ifdef CONFIG_OMIRR
-	if(!error)
-		omirr_printall(inode, " U %ld %ld %ld ", CURRENT_TIME,
-				newattrs.ia_atime, newattrs.ia_mtime);
-#endif
-iput_and_out:
-	iput(inode);
+dput_and_out:
+	dput(dentry);
 out:
 	unlock_kernel();
 	return error;
@@ -276,7 +279,7 @@
  */
 asmlinkage int sys_access(const char * filename, int mode)
 {
-	struct inode * inode;
+	struct dentry * dentry;
 	int old_fsuid, old_fsgid;
 	int res = -EINVAL;
 
@@ -287,11 +290,14 @@
 	old_fsgid = current->fsgid;
 	current->fsuid = current->uid;
 	current->fsgid = current->gid;
-	res = namei(filename, &inode);
-	if (!res) {
-		res = permission(inode, mode);
-		iput(inode);
+
+	dentry = namei(filename);
+	res = PTR_ERR(dentry);
+	if (!IS_ERR(dentry)) {
+		res = permission(dentry->d_inode, mode);
+		dput(dentry);
 	}
+
 	current->fsuid = old_fsuid;
 	current->fsgid = old_fsgid;
 out:
@@ -307,17 +313,14 @@
 
 	lock_kernel();
 	
-	dentry = lookup_dentry(filename, NULL, 1);
+	dentry = namei(filename);
 	error = PTR_ERR(dentry);
 	if (IS_ERR(dentry))
 		goto out;
 
-	error = -ENOENT;
-	if (dentry->d_flag & D_NEGATIVE)
-		goto dput_and_out;
+	inode = dentry->d_inode;
 
 	error = -ENOTDIR;
-	inode = dentry->d_inode;
 	if (!S_ISDIR(inode->i_mode))
 		goto dput_and_out;
 
@@ -340,8 +343,8 @@
 asmlinkage int sys_fchdir(unsigned int fd)
 {
 	struct file *file;
+	struct dentry *dentry;
 	struct inode *inode;
-	struct dentry *dentry, *tmp;
 	int error;
 
 	lock_kernel();
@@ -351,7 +354,9 @@
 		goto out;
 
 	error = -ENOENT;
-	if (!(inode = file->f_inode))
+	if (!(dentry = file->f_dentry))
+		goto out;
+	if (!(inode = dentry->d_inode))
 		goto out;
 
 	error = -ENOTDIR;
@@ -362,10 +367,13 @@
 	if (error)
 		goto out;
 
-	dentry = dget(inode->i_dentry);
-	tmp = current->fs->pwd;
-	current->fs->pwd = dentry;
-	dput(tmp);
+	{
+		struct dentry *tmp;
+	
+		tmp = current->fs->pwd;
+		current->fs->pwd = dget(dentry);
+		dput(tmp);
+	}
 out:
 	unlock_kernel();
 	return error;
@@ -379,17 +387,14 @@
 
 	lock_kernel();
 	
-	dentry = lookup_dentry(filename, NULL, 1);
+	dentry = namei(filename);
 	error = PTR_ERR(dentry);
 	if (IS_ERR(dentry))
 		goto out;
 
-	error = -ENOENT;
-	if (dentry->d_flag & D_NEGATIVE)
-		goto dput_and_out;
+	inode = dentry->d_inode;
 
 	error = -ENOTDIR;
-	inode = dentry->d_inode;
 	if (!S_ISDIR(inode->i_mode))
 		goto dput_and_out;
 
@@ -405,6 +410,7 @@
 	tmp = current->fs->root;
 	current->fs->root = dentry;
 	dentry = tmp;
+	error = 0;
 
 dput_and_out:
 	dput(dentry);
@@ -416,6 +422,7 @@
 asmlinkage int sys_fchmod(unsigned int fd, mode_t mode)
 {
 	struct inode * inode;
+	struct dentry * dentry;
 	struct file * file;
 	struct iattr newattrs;
 	int err = -EBADF;
@@ -424,7 +431,9 @@
 	if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
 		goto out;
 	err = -ENOENT;
-	if (!(inode = file->f_inode))
+	if (!(dentry = file->f_dentry))
+		goto out;
+	if (!(inode = dentry->d_inode))
 		goto out;
 	err = -EROFS;
 	if (IS_RDONLY(inode))
@@ -436,12 +445,7 @@
 		mode = inode->i_mode;
 	newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
 	newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
-	inode->i_dirt = 1;
 	err = notify_change(inode, &newattrs);
-#ifdef CONFIG_OMIRR
-	if(!err)
-		omirr_printall(inode, " M %ld %ld ", CURRENT_TIME, newattrs.ia_mode);
-#endif
 out:
 	unlock_kernel();
 	return err;
@@ -449,36 +453,35 @@
 
 asmlinkage int sys_chmod(const char * filename, mode_t mode)
 {
+	struct dentry * dentry;
 	struct inode * inode;
 	int error;
 	struct iattr newattrs;
 
 	lock_kernel();
-	/* I'm not sure whether to use NAM_FOLLOW_TRAILSLASH instead,
-	 * because permissions on symlinks now can never be changed,
-	 * but on the other hand they are never needed.
-	 */
-	error = namei(filename, &inode);
-	if (error)
+	dentry = namei(filename);
+
+	error = PTR_ERR(dentry);
+	if (IS_ERR(dentry))
 		goto out;
+	inode = dentry->d_inode;
+
 	error = -EROFS;
 	if (IS_RDONLY(inode))
-		goto iput_and_out;
+		goto dput_and_out;
+
 	error = -EPERM;
 	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
-		goto iput_and_out;
+		goto dput_and_out;
+
 	if (mode == (mode_t) -1)
 		mode = inode->i_mode;
 	newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
 	newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
-	inode->i_dirt = 1;
 	error = notify_change(inode, &newattrs);
-#ifdef CONFIG_OMIRR
-	if(!error)
-		omirr_printall(inode, " M %ld %ld ", CURRENT_TIME, newattrs.ia_mode);
-#endif
-iput_and_out:
-	iput(inode);
+
+dput_and_out:
+	dput(dentry);
 out:
 	unlock_kernel();
 	return error;
@@ -487,6 +490,7 @@
 asmlinkage int sys_fchown(unsigned int fd, uid_t user, gid_t group)
 {
 	struct inode * inode;
+	struct dentry * dentry;
 	struct file * file;
 	struct iattr newattrs;
 	int error = -EBADF;
@@ -495,7 +499,9 @@
 	if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
 		goto out;
 	error = -ENOENT;
-	if (!(inode = file->f_inode))
+	if (!(dentry = file->f_dentry))
+		goto out;
+	if (!(inode = dentry->d_inode))
 		goto out;
 	error = -EROFS;
 	if (IS_RDONLY(inode))
@@ -528,7 +534,6 @@
 		newattrs.ia_mode &= ~S_ISGID;
 		newattrs.ia_valid |= ATTR_MODE;
 	}
-	inode->i_dirt = 1;
 	if (inode->i_sb && inode->i_sb->dq_op) {
 		inode->i_sb->dq_op->initialize(inode, -1);
 		error = -EDQUOT;
@@ -539,11 +544,6 @@
 			inode->i_sb->dq_op->transfer(inode, &newattrs, 1);
 	} else
 		error = notify_change(inode, &newattrs);
-#ifdef CONFIG_OMIRR
-	if(!error)
-		omirr_printall(inode, " O %d %d ", CURRENT_TIME,
-				newattrs.ia_uid, newattrs.ia_gid);
-#endif
 out:
 	unlock_kernel();
 	return error;
@@ -551,20 +551,27 @@
 
 asmlinkage int sys_chown(const char * filename, uid_t user, gid_t group)
 {
+	struct dentry * dentry;
 	struct inode * inode;
 	int error;
 	struct iattr newattrs;
 
 	lock_kernel();
-	error = namei(filename, &inode);
-	if (error)
+	dentry = namei(filename);
+
+	error = PTR_ERR(dentry);
+	if (IS_ERR(dentry))
 		goto out;
+	inode = dentry->d_inode;
+
 	error = -EROFS;
 	if (IS_RDONLY(inode))
-		goto iput_and_out;
+		goto dput_and_out;
+
 	error = -EPERM;
 	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
-		goto iput_and_out;
+		goto dput_and_out;
+
 	if (user == (uid_t) -1)
 		user = inode->i_uid;
 	if (group == (gid_t) -1)
@@ -590,24 +597,18 @@
 		newattrs.ia_mode &= ~S_ISGID;
 		newattrs.ia_valid |= ATTR_MODE;
 	}
-	inode->i_dirt = 1;
 	if (inode->i_sb->dq_op) {
 		inode->i_sb->dq_op->initialize(inode, -1);
 		error = -EDQUOT;
 		if (inode->i_sb->dq_op->transfer(inode, &newattrs, 0))
-			goto iput_and_out;
+			goto dput_and_out;
 		error = notify_change(inode, &newattrs);
 		if (error)
 			inode->i_sb->dq_op->transfer(inode, &newattrs, 1);
 	} else
 		error = notify_change(inode, &newattrs);
-#ifdef CONFIG_OMIRR
-	if(!error)
-		omirr_printall(inode, " O %d %d ", CURRENT_TIME,
-				newattrs.ia_uid, newattrs.ia_gid);
-#endif
-iput_and_out:
-	iput(inode);
+dput_and_out:
+	dput(dentry);
 out:
 	unlock_kernel();
 	return(error);
@@ -630,6 +631,7 @@
 static int do_open(const char * filename,int flags,int mode, int fd)
 {
 	struct inode * inode;
+	struct dentry * dentry;
 	struct file * f;
 	int flag,error;
 
@@ -642,16 +644,18 @@
 		flag++;
 	if (flag & O_TRUNC)
 		flag |= 2;
-	error = open_namei(filename,flag,mode,&inode,NULL);
-	if (error)
+	dentry = open_namei(filename,flag,mode);
+	error = PTR_ERR(dentry);
+	if (IS_ERR(dentry))
 		goto cleanup_file;
+	inode = dentry->d_inode;
 	if (f->f_mode & FMODE_WRITE) {
 		error = get_write_access(inode);
 		if (error)
-			goto cleanup_inode;
+			goto cleanup_dentry;
 	}
 
-	f->f_inode = inode;
+	f->f_dentry = dentry;
 	f->f_pos = 0;
 	f->f_reada = 0;
 	f->f_op = NULL;
@@ -670,8 +674,8 @@
 cleanup_all:
 	if (f->f_mode & FMODE_WRITE)
 		put_write_access(inode);
-cleanup_inode:
-	iput(inode);
+cleanup_dentry:
+	dput(dentry);
 cleanup_file:
 	put_filp(f);
 	return error;
@@ -705,14 +709,15 @@
 	int fd, error;
 
 	lock_kernel();
-	fd = get_unused_fd();
-	if (fd < 0) {
-		error = fd;
+	error = get_unused_fd();
+	if (error < 0)
 		goto out;
-	}
-	error = getname(filename, &tmp);
-	if (!error) {
-		error = do_open(tmp,flags,mode, fd);
+
+	fd = error;
+	tmp = getname(filename);
+	error = PTR_ERR(tmp);
+	if (!IS_ERR(tmp)) {
+		error = do_open(tmp,flags,mode,fd);
 		putname(tmp);
 		if (!error) {
 			error = fd;
@@ -743,31 +748,35 @@
 
 #endif
 
-int __fput(struct file *filp, struct inode *inode)
+int __fput(struct file *filp)
 {
 	int	error = 0;
+	struct dentry * dentry = filp->f_dentry;
+	struct inode * inode = dentry->d_inode;
 
 	if (filp->f_op && filp->f_op->release)
 		error = filp->f_op->release(inode,filp);
-	filp->f_inode = NULL;
+	filp->f_dentry = NULL;
 	if (filp->f_mode & FMODE_WRITE)
 		put_write_access(inode);
-	iput(inode);
+	dput(dentry);
 	return error;
 }
 
 int close_fp(struct file *filp)
 {
+	struct dentry *dentry;
 	struct inode *inode;
 
 	if (filp->f_count == 0) {
 		printk("VFS: Close: file count is 0\n");
 		return 0;
 	}
-	inode = filp->f_inode;
+	dentry = filp->f_dentry;
+	inode = dentry->d_inode;
 	if (inode)
 		locks_remove_locks(current, filp);
-	return fput(filp, inode);
+	return fput(filp);
 }
 
 asmlinkage int sys_close(unsigned int fd)
diff -u --recursive --new-file v2.1.44/linux/fs/pipe.c linux/fs/pipe.c
--- v2.1.44/linux/fs/pipe.c	Mon Jun 16 16:35:58 1997
+++ linux/fs/pipe.c	Wed Jul 16 20:03:40 1997
@@ -75,10 +75,7 @@
 	PIPE_LOCK(*inode)--;
 	wake_up_interruptible(&PIPE_WAIT(*inode));
 	if (read) {
-		if (DO_UPDATE_ATIME(inode)) {
-			inode->i_atime = CURRENT_TIME;
-			inode->i_dirt = 1;
-		}
+		UPDATE_ATIME(inode);
 		return read;
 	}
 	if (PIPE_WRITERS(*inode))
@@ -132,7 +129,7 @@
 		free = 1;
 	}
 	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
-	inode->i_dirt = 1;
+	mark_inode_dirty(inode);
 	return written;
 }
 
@@ -168,7 +165,7 @@
 static unsigned int pipe_poll(struct file * filp, poll_table * wait)
 {
 	unsigned int mask;
-	struct inode * inode = filp->f_inode;
+	struct inode * inode = filp->f_dentry->d_inode;
 
 	poll_wait(&PIPE_WAIT(*inode), wait);
 	mask = POLLIN | POLLRDNORM;
@@ -189,7 +186,7 @@
 static unsigned int fifo_poll(struct file * filp, poll_table * wait)
 {
 	unsigned int mask;
-	struct inode * inode = filp->f_inode;
+	struct inode * inode = filp->f_dentry->d_inode;
 
 	poll_wait(&PIPE_WAIT(*inode), wait);
 	mask = POLLIN | POLLRDNORM;
@@ -221,7 +218,7 @@
 
 static unsigned int connect_poll(struct file * filp, poll_table * wait)
 {
-	struct inode * inode = filp->f_inode;
+	struct inode * inode = filp->f_dentry->d_inode;
 
 	poll_wait(&PIPE_WAIT(*inode), wait);
 	if (!PIPE_EMPTY(*inode)) {
@@ -233,18 +230,26 @@
 	return POLLOUT | POLLWRNORM;
 }
 
-static int pipe_read_release(struct inode * inode, struct file * filp)
+static int pipe_release(struct inode * inode)
 {
-	PIPE_READERS(*inode)--;
+	if (!PIPE_READERS(*inode) && !PIPE_WRITERS(*inode)) {
+		free_page((unsigned long) PIPE_BASE(*inode));
+		PIPE_BASE(*inode) = NULL;
+	}
 	wake_up_interruptible(&PIPE_WAIT(*inode));
 	return 0;
 }
 
+static int pipe_read_release(struct inode * inode, struct file * filp)
+{
+	PIPE_READERS(*inode)--;
+	return pipe_release(inode);
+}
+
 static int pipe_write_release(struct inode * inode, struct file * filp)
 {
 	PIPE_WRITERS(*inode)--;
-	wake_up_interruptible(&PIPE_WAIT(*inode));
-	return 0;
+	return pipe_release(inode);
 }
 
 static int pipe_rdwr_release(struct inode * inode, struct file * filp)
@@ -253,8 +258,7 @@
 		PIPE_READERS(*inode)--;
 	if (filp->f_mode & FMODE_WRITE)
 		PIPE_WRITERS(*inode)--;
-	wake_up_interruptible(&PIPE_WAIT(*inode));
-	return 0;
+	return pipe_release(inode);
 }
 
 static int pipe_read_open(struct inode * inode, struct file * filp)
@@ -373,6 +377,43 @@
 	NULL
 };
 
+static struct inode * get_pipe_inode(void)
+{
+	extern struct inode_operations pipe_inode_operations;
+	struct inode *inode = get_empty_inode();
+
+	if (inode) {
+		unsigned long page = __get_free_page(GFP_USER);
+
+		if (!page) {
+			iput(inode);
+			inode = NULL;
+		} else {
+			PIPE_BASE(*inode) = (char *) page;
+			inode->i_op = &pipe_inode_operations;
+			inode->i_count = 1;
+			PIPE_WAIT(*inode) = NULL;
+			PIPE_START(*inode) = PIPE_LEN(*inode) = 0;
+			PIPE_RD_OPENERS(*inode) = PIPE_WR_OPENERS(*inode) = 0;
+			PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 1;
+			PIPE_LOCK(*inode) = 0;
+			/*
+			 * Mark the inode dirty from the very beginning,
+			 * that way it will never be moved to the dirty
+			 * list because "make_inode_dirty()" will think
+			 * that it already _is_ on the dirty list.
+			 */
+			inode->i_state = 1 << I_DIRTY;
+			inode->i_mode |= S_IFIFO | S_IRUSR | S_IWUSR;
+			inode->i_uid = current->fsuid;
+			inode->i_gid = current->fsgid;
+			inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+			inode->i_blksize = PAGE_SIZE;
+		}
+	}
+	return inode;
+}
+
 struct inode_operations pipe_inode_operations = {
 	&rdwr_pipe_fops,
 	NULL,			/* create */
@@ -422,12 +463,14 @@
 		goto close_f12_inode_i;
 	j = error;
 
-	f1->f_inode = f2->f_inode = inode;
+	f1->f_dentry = f2->f_dentry = dget(d_alloc_root(inode, NULL));
+
 	/* read file */
 	f1->f_pos = f2->f_pos = 0;
 	f1->f_flags = O_RDONLY;
 	f1->f_op = &read_pipe_fops;
 	f1->f_mode = 1;
+
 	/* write file */
 	f2->f_flags = O_WRONLY;
 	f2->f_op = &write_pipe_fops;
@@ -441,7 +484,6 @@
 close_f12_inode_i:
 	put_unused_fd(i);
 close_f12_inode:
-	atomic_dec(&inode->i_count);
 	iput(inode);
 close_f12:
 	put_filp(f2);
diff -u --recursive --new-file v2.1.44/linux/fs/proc/Makefile linux/fs/proc/Makefile
--- v2.1.44/linux/fs/proc/Makefile	Mon Jun 16 16:35:58 1997
+++ linux/fs/proc/Makefile	Wed Jul 16 15:35:49 1997
@@ -8,7 +8,7 @@
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
 O_TARGET := proc.o
-O_OBJS   := inode.o root.o base.o generic.o mem.o link.o arbitrary.o fd.o array.o \
+O_OBJS   := inode.o root.o base.o generic.o mem.o link.o fd.o array.o \
 		kmsg.o scsi.o proc_tty.o
 ifdef CONFIG_OMIRR
 O_OBJS   := $(O_OBJS) omirr.o
diff -u --recursive --new-file v2.1.44/linux/fs/proc/arbitrary.c linux/fs/proc/arbitrary.c
--- v2.1.44/linux/fs/proc/arbitrary.c	Sat Jul  5 20:53:22 1997
+++ linux/fs/proc/arbitrary.c	Wed Dec 31 16:00:00 1969
@@ -1,57 +0,0 @@
-/*
- * $Id: arbitrary.c,v 1.2 1997/06/05 01:27:47 davem Exp $
- *
- * linux/fs/proc/arbitrary.c - lookup() for arbitrary inodes.
- * Copyright (C) 1997, Thomas Schoebel-Theuer,
- * <schoebel@informatik.uni-stuttgart.de>.
- */
-
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/kdev_t.h>
-#include <linux/fs.h>
-
-/* Format of dev/inode pairs that can be used as file names:
- * [<dev_number_in_hex]:<inode_number_in_decimal>
- * (the same format that is already in use in /proc/<pid>/exe,
- * /proc/<pid>/cwd and /proc/<pid>/root).
- */
-/* Note that readdir does not supply such names, so they must be used
- * either "blind" or must be queried another way, for example
- * as result of a virtual symlink (see linux/proc/link.c).
- */
-int proc_arbitrary_lookup(struct inode * dir, const char * name,
-			  int len, struct inode ** result)
-{
-	int dev, ino;
-	char * ptr = (char*)name;
-	kdev_t kdev;
-	int i;
-	int error = -EINVAL;
-	
-	if(*ptr++ != '[')
-		goto done;
-	dev = simple_strtoul(ptr, &ptr, 16);
-	if(*ptr++ != ']')
-		goto done;
-	if(*ptr++ != ':')
-		goto done;
-	ino = simple_strtoul(ptr, &ptr, 0);
-	if((long)ptr - (long)name != len)
-		goto done;
-
-	error = -ENOENT;
-	kdev = to_kdev_t(dev);
-	if(!kdev)
-		goto done;
-	for(i = 0; i < NR_SUPER; i++)
-		if(super_blocks[i].s_dev == kdev)
-			break;
-	if(i < NR_SUPER) {
-		*result = iget(&super_blocks[i], ino);
-		if(*result)
-			error = 0;
-	}
-done:
-	return error;
-}
diff -u --recursive --new-file v2.1.44/linux/fs/proc/array.c linux/fs/proc/array.c
--- v2.1.44/linux/fs/proc/array.c	Sat Jul  5 20:53:22 1997
+++ linux/fs/proc/array.c	Sun Jul 13 21:20:10 1997
@@ -591,7 +591,7 @@
 
 		for (vma = mm->mmap; vma; vma = vma->vm_next) {
 			unsigned long len = (vma->vm_end - vma->vm_start) >> 10;
-			if (!vma->vm_inode) {
+			if (!vma->vm_dentry) {
 				data += len;
 				if (vma->vm_flags & VM_GROWSDOWN)
 					stack += len;
@@ -949,12 +949,11 @@
 		*cp++ = flags & VM_MAYSHARE ? 's' : 'p';
 		*cp++ = 0;
 
-		if (map->vm_inode != NULL) {
-			dev = map->vm_inode->i_dev;
-			ino = map->vm_inode->i_ino;
-		} else {
-			dev = 0;
-			ino = 0;
+		dev = 0;
+		ino = 0;
+		if (map->vm_dentry != NULL) {
+			dev = map->vm_dentry->d_inode->i_dev;
+			ino = map->vm_dentry->d_inode->i_ino;
 		}
 
 		len = sprintf(line,
diff -u --recursive --new-file v2.1.44/linux/fs/proc/fd.c linux/fs/proc/fd.c
--- v2.1.44/linux/fs/proc/fd.c	Mon Jul  7 12:43:07 1997
+++ linux/fs/proc/fd.c	Wed Jul 16 15:45:03 1997
@@ -14,7 +14,7 @@
 #include <linux/stat.h>
 
 static int proc_readfd(struct inode *, struct file *, void *, filldir_t);
-static int proc_lookupfd(struct inode *,struct qstr *,struct inode **);
+static int proc_lookupfd(struct inode *, struct dentry *);
 
 static struct file_operations proc_fd_operations = {
 	NULL,			/* lseek - default */
@@ -52,15 +52,24 @@
 	NULL			/* permission */
 };
 
-static int proc_lookupfd(struct inode * dir, struct qstr *str, struct inode ** result)
+/*
+ * NOTE! Normally we'd indicate that a file does not
+ * exist by creating a negative dentry and returning
+ * a successful return code. However, for this case
+ * we do not want to create negative dentries, because
+ * the state of the world can change behind our backs.
+ *
+ * Thus just return -ENOENT instead.
+ */
+static int proc_lookupfd(struct inode * dir, struct dentry * dentry)
 {
 	unsigned int ino, pid, fd, c;
 	struct task_struct * p;
 	struct super_block * sb;
+	struct inode *inode;
 	const char *name;
 	int len;
 
-	*result = NULL;
 	ino = dir->i_ino;
 	pid = ino >> 16;
 	ino &= 0x0000ffff;
@@ -71,8 +80,8 @@
 		return -ENOENT;
 
 	fd = 0;
-	len = str->len;
-	name = str->name;
+	len = dentry->d_name.len;
+	name = dentry->d_name.name;
 	while (len-- > 0) {
 		c = *name - '0';
 		name++;
@@ -100,13 +109,16 @@
  	if (fd >= NR_OPEN	||
 	    !p->files		||
 	    !p->files->fd[fd]	||
-	    !p->files->fd[fd]->f_inode)
+	    !p->files->fd[fd]->f_dentry)
 		return -ENOENT;
 
 	ino = (pid << 16) + (PROC_PID_FD_DIR << 8) + fd;
 
-	if (!(*result = proc_get_inode(sb, ino, NULL)))
+	inode = proc_get_inode(sb, ino, NULL);
+	if (!inode)
 		return -ENOENT;
+
+	d_add(dentry, inode);
 	return 0;
 }
 
@@ -144,7 +156,7 @@
 	for (fd -= 2 ; fd < NR_OPEN; fd++, filp->f_pos++) {
 		if (!p->files)
 			break;
-		if (!p->files->fd[fd] || !p->files->fd[fd]->f_inode)
+		if (!p->files->fd[fd] || !p->files->fd[fd]->f_dentry)
 			continue;
 
 		j = NUMBUF;
diff -u --recursive --new-file v2.1.44/linux/fs/proc/inode.c linux/fs/proc/inode.c
--- v2.1.44/linux/fs/proc/inode.c	Sun Jul  6 20:13:54 1997
+++ linux/fs/proc/inode.c	Wed Jul 16 11:36:44 1997
@@ -25,8 +25,14 @@
 	    && proc_openprom_use)
 		(*proc_openprom_use)(inode, 0);
 #endif	
-	if (inode->i_nlink)
-		return;
+}
+
+/*
+ * Does this ever happen?
+ */
+static void proc_delete_inode(struct inode *inode)
+{
+	printk("proc_delete_inode()?\n");
 	inode->i_size = 0;
 }
 
@@ -39,9 +45,10 @@
 
 static struct super_operations proc_sops = { 
 	proc_read_inode,
-	NULL,
 	proc_write_inode,
 	proc_put_inode,
+	proc_delete_inode,
+	NULL,
 	proc_put_super,
 	NULL,
 	proc_statfs,
@@ -141,7 +148,7 @@
 	return s;
 }
 
-void proc_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+int proc_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
 {
 	struct statfs tmp;
 
@@ -153,7 +160,7 @@
 	tmp.f_files = 0;
 	tmp.f_ffree = 0;
 	tmp.f_namelen = NAME_MAX;
-	copy_to_user(buf, &tmp, bufsiz);
+	return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
 }
 
 void proc_read_inode(struct inode * inode)
@@ -201,5 +208,4 @@
 
 void proc_write_inode(struct inode * inode)
 {
-	inode->i_dirt=0;
 }
diff -u --recursive --new-file v2.1.44/linux/fs/proc/link.c linux/fs/proc/link.c
--- v2.1.44/linux/fs/proc/link.c	Sat Jul  5 20:53:22 1997
+++ linux/fs/proc/link.c	Sun Jul 13 21:20:10 1997
@@ -14,7 +14,6 @@
 #include <linux/mm.h>
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
-#include <linux/dalloc.h>
 
 static int proc_readlink(struct inode *, char *, int);
 static struct dentry * proc_follow_link(struct inode *, struct dentry *);
@@ -105,7 +104,7 @@
 			vma = p->mm->mmap;
 			while (vma) {
 				if (vma->vm_flags & VM_EXECUTABLE)
-					return dget(vma->vm_inode->i_dentry);
+					return dget(vma->vm_dentry);
 
 				vma = vma->vm_next;
 			}
@@ -121,9 +120,9 @@
 					break;
 				if (!p->files->fd[ino])
 					break;
-				if (!p->files->fd[ino]->f_inode)
+				if (!p->files->fd[ino]->f_dentry)
 					break;
-				result = dget(p->files->fd[ino]->f_inode->i_dentry);
+				result = dget(p->files->fd[ino]->f_dentry);
 				break;
 			}
 	}
diff -u --recursive --new-file v2.1.44/linux/fs/proc/omirr.c linux/fs/proc/omirr.c
--- v2.1.44/linux/fs/proc/omirr.c	Sat Jul  5 20:53:22 1997
+++ linux/fs/proc/omirr.c	Thu Jul 10 14:53:00 1997
@@ -7,7 +7,6 @@
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/fs.h>
-#include <linux/dalloc.h>
 #include <linux/omirr.h>
 #include <asm/uaccess.h>
 
diff -u --recursive --new-file v2.1.44/linux/fs/proc/openpromfs.c linux/fs/proc/openpromfs.c
--- v2.1.44/linux/fs/proc/openpromfs.c	Sat Jul  5 20:53:22 1997
+++ linux/fs/proc/openpromfs.c	Wed Jul 16 20:37:21 1997
@@ -1,7 +1,7 @@
-/* $Id: openpromfs.c,v 1.15 1997/06/05 01:28:11 davem Exp $
+/* $Id: openpromfs.c,v 1.18 1997/07/17 02:24:01 davem Exp $
  * openpromfs.c: /proc/openprom handling routines
  *
- * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
 #include <linux/module.h>
@@ -68,7 +68,7 @@
 	
 	if (count < 0 || !inode->u.generic_ip)
 		return -EINVAL;
-	sprintf (buffer, "%8.8x\n", (u32)(inode->u.generic_ip));
+	sprintf (buffer, "%8.8x\n", (u32)(long)(inode->u.generic_ip));
 	if (file->f_pos >= 9)
 		return 0;
 	if (count > 9 - file->f_pos)
@@ -86,27 +86,28 @@
 	char *p;
 	u32 *q;
 	openprom_property *op;
+	char buffer[64];
 	
 	if (filp->f_pos >= 0xffffff)
 		return -EINVAL;
 	if (!filp->private_data) {
-		node = nodes[(u16)((uint)inode->u.generic_ip)].node;
-		i = ((u32)inode->u.generic_ip) >> 16;
-		if ((u16)((uint)inode->u.generic_ip) == aliases) {
+		node = nodes[(u16)((long)inode->u.generic_ip)].node;
+		i = ((u32)(long)inode->u.generic_ip) >> 16;
+		if ((u16)((long)inode->u.generic_ip) == aliases) {
 			if (i >= aliases_nodes)
 				p = 0;
 			else
 				p = alias_names [i];
 		} else
-			for (p = prom_firstprop (node);
+			for (p = prom_firstprop (node, buffer);
 			     i && p && *p;
-			     p = prom_nextprop (node, p), i--)
+			     p = prom_nextprop (node, p, buffer), i--)
 				/* nothing */ ;
 		if (!p || !*p)
 			return -EIO;
 		i = prom_getproplen (node, p);
 		if (i < 0) {
-			if ((u16)((uint)inode->u.generic_ip) == aliases)
+			if ((u16)((long)inode->u.generic_ip) == aliases)
 				i = 0;
 			else
 				return -EIO;
@@ -155,7 +156,7 @@
 	if (count > i - k) count = i - k;
 	if (op->flag & OPP_STRING) {
 		if (!k) {
-			*buf = '\'';
+			__put_user('\'', buf);
 			k++;
 			count--;
 		}
@@ -170,9 +171,9 @@
 			k += j;
 		}
 		if (count)
-			buf [k++ - filp->f_pos] = '\'';
+			__put_user('\'', &buf [k++ - filp->f_pos]);
 		if (count > 1)
-			buf [k++ - filp->f_pos] = '\n';
+			__put_user('\n', &buf [k++ - filp->f_pos]);
 	} else if (op->flag & OPP_BINARY) {
 		char buffer[10];
 		u32 *first, *last;
@@ -186,26 +187,26 @@
 
 		if (first == last) {
 			sprintf (buffer, "%08x.", *first);
-			memcpy (buf, buffer + first_off, last_cnt - first_off);
+			copy_to_user (buf, buffer + first_off, last_cnt - first_off);
 			buf += last_cnt - first_off;
 		} else {		
 			for (q = first; q <= last; q++) {
 				sprintf (buffer, "%08x.", *q);
 				if (q == first) {
-					memcpy (buf, buffer + first_off,
-						9 - first_off);
+					copy_to_user (buf, buffer + first_off,
+						      9 - first_off);
 					buf += 9 - first_off;
 				} else if (q == last) {
-					memcpy (buf, buffer, last_cnt);
+					copy_to_user (buf, buffer, last_cnt);
 					buf += last_cnt;
 				} else {
-					memcpy (buf, buffer, 9);
+					copy_to_user (buf, buffer, 9);
 					buf += 9;
 				}
 			}
 		}
 		if (last == (u32 *)(op->value + op->len - 4) && last_cnt == 9)
-			*(buf - 1) = '\n';
+			__put_user('\n', (buf - 1));
 		k += count;
 	}
 	count = k - filp->f_pos;
@@ -242,8 +243,10 @@
 		for (i = 0; i < count; i++, j++) {
 			if (j == 9) j = 0;
 			if (!j) {
-				if (buf [i] != '.') {
-					if (buf [i] != '\n') {
+				char ctmp;
+				__get_user(ctmp, &buf[i]);
+				if (ctmp != '.') {
+					if (ctmp != '\n') {
 						if (op->flag & OPP_BINARY)
 							return -EINVAL;
 						else
@@ -255,10 +258,12 @@
 					}
 				}
 			} else {
-				if (buf [i] < '0' || 
-				    (buf [i] > '9' && buf [i] < 'A') ||
-				    (buf [i] > 'F' && buf [i] < 'a') ||
-				    buf [i] > 'f') {
+				char ctmp;
+				__get_user(ctmp, &buf[i]);
+				if (ctmp < '0' || 
+				    (ctmp > '9' && ctmp < 'A') ||
+				    (ctmp > 'F' && ctmp < 'a') ||
+				    ctmp > 'f') {
 					if (op->flag & OPP_BINARY)
 						return -EINVAL;
 					else
@@ -292,8 +297,8 @@
 		last_cnt = (k + count) % 9;
 		if (first + 1 == last) {
 			memset (tmp, '0', 8);
-			memcpy (tmp + first_off, buf, (count + first_off > 8) ?
-						      8 - first_off : count);
+			copy_from_user (tmp + first_off, buf,
+					(count + first_off > 8) ? 8 - first_off : count);
 			mask = 0xffffffff;
 			mask2 = 0xffffffff;
 			for (j = 0; j < first_off; j++)
@@ -312,8 +317,8 @@
 				if (q == first) {
 					if (first_off < 8) {
 						memset (tmp, '0', 8);
-						memcpy (tmp + first_off, buf,
-							8 - first_off);
+						copy_from_user (tmp + first_off, buf,
+								8 - first_off);
 						mask = 0xffffffff;
 						for (j = 0; j < first_off; j++)
 							mask >>= 1;
@@ -324,7 +329,7 @@
 				} else if ((q == last - 1) && last_cnt
 					   && (last_cnt < 8)) {
 					memset (tmp, '0', 8);
-					memcpy (tmp, buf, last_cnt);
+					copy_from_user (tmp, buf, last_cnt);
 					mask = 0xffffffff;
 					for (j = 0; j < 8 - last_cnt; j++)
 						mask <<= 1;
@@ -332,7 +337,10 @@
 					*q |= simple_strtoul (tmp, 0, 16);
 					buf += last_cnt;
 				} else {
-					*q = simple_strtoul (buf, 0, 16);
+					char tchars[17]; /* XXX yuck... */
+
+					copy_from_user(tchars, buf, 16);
+					*q = simple_strtoul (tchars, 0, 16);
 					buf += 9;
 				}
 			}
@@ -347,12 +355,15 @@
 write_try_string:
 	if (!(op->flag & OPP_BINARY)) {
 		if (!(op->flag & (OPP_QUOTED | OPP_NOTQUOTED))) {
+			char ctmp;
+
 			/* No way, if somebody starts writing from the middle, 
 			 * we don't know whether he uses quotes around or not 
 			 */
 			if (k > 0)
 				return -EINVAL;
-			if (*buf == '\'') {
+			__get_user(ctmp, buf);
+			if (ctmp == '\'') {
 				op->flag |= OPP_QUOTED;
 				buf++;
 				count--;
@@ -383,7 +394,7 @@
 			kfree (b);
 		}
 		p = op->value + filp->f_pos - ((op->flag & OPP_QUOTED) ? 1 : 0);
-		memcpy (p, buf, count);
+		copy_from_user (p, buf, count);
 		op->flag |= OPP_DIRTY;
 		for (i = 0; i < count; i++, p++)
 			if (*p == '\n') {
@@ -414,8 +425,8 @@
 	
 	if (!op)
 		return 0;
-	node = nodes[(u16)((uint)inode->u.generic_ip)].node;
-	if ((u16)((uint)inode->u.generic_ip) == aliases) {
+	node = nodes[(u16)((long)inode->u.generic_ip)].node;
+	if ((u16)((long)inode->u.generic_ip) == aliases) {
 		if ((op->flag & OPP_DIRTY) && (op->flag & OPP_STRING)) {
 			char *p = op->name;
 			int i = (op->value - op->name) - strlen (op->name) - 1;
@@ -607,6 +618,7 @@
 	int i;
 	struct inode *inode;
 	struct openpromfs_dev *d = NULL;
+	char buffer2[64];
 	
 	*result = NULL;
 	if (!dir || !S_ISDIR(dir->i_mode)) {
@@ -662,9 +674,9 @@
 	if (!ino) {
 		int j = NODEP2INO(NODE(dir->i_ino).first_prop);
 		if (dirnode != aliases) {
-			for (p = prom_firstprop (n);
+			for (p = prom_firstprop (n, buffer2);
 			     p && *p;
-			     p = prom_nextprop (n, p)) {
+			     p = prom_nextprop (n, p, buffer2)) {
 				j++;
 				if ((len == strlen (p))
 				    && !strncmp (p, name, len)) {
@@ -723,7 +735,7 @@
 		inode->i_mode = S_IFREG | S_IRUGO;
 		inode->i_op = &openpromfs_nodenum_inode_ops;
 		inode->i_nlink = 1;
-		inode->u.generic_ip = (void *)(n);
+		inode->u.generic_ip = (void *)(long)(n);
 		break;
 	case OPFSL_PROPERTY:
 		if ((dirnode == options) && (len == 17)
@@ -740,7 +752,7 @@
 		inode->i_nlink = 1;
 		if (inode->i_size < 0)
 			inode->i_size = 0;
-		inode->u.generic_ip = (void *)(((u16)dirnode) | 
+		inode->u.generic_ip = (void *)(long)(((u16)dirnode) | 
 			(((u16)(ino - NODEP2INO(NODE(dir->i_ino).first_prop) - 1)) << 16));
 		break;
 	case OPFSL_DEVICE:
@@ -764,6 +776,7 @@
 	u16 node;
 	char *p;
 	struct openpromfs_dev *d;
+	char buffer2[64];
 	
 	if (!inode || !S_ISDIR (inode->i_mode)) return -ENOTDIR;
 	ino = inode->i_ino;
@@ -816,9 +829,9 @@
 				}
 			}
 		} else {
-			for (p = prom_firstprop (n);
+			for (p = prom_firstprop (n, buffer2);
 			     p && *p;
-			     p = prom_nextprop (n, p)) {
+			     p = prom_nextprop (n, p, buffer2)) {
 				j++;
 				if (i) i--;
 				else {
@@ -880,7 +893,7 @@
 	inode->i_op = &openpromfs_prop_inode_ops;
 	inode->i_nlink = 1;
 	if (inode->i_size < 0) inode->i_size = 0;
-	inode->u.generic_ip = (void *)(((u16)aliases) | 
+	inode->u.generic_ip = (void *)(long)(((u16)aliases) | 
 			(((u16)(aliases_nodes - 1)) << 16));
 	*result = inode;
 	return 0;
@@ -943,6 +956,7 @@
 {
 	char *p;
 	u16 n = last_node++, i;
+	char buffer[64];
 
 	if (check_space (n) < 0)
 		return 0xffff;
@@ -964,15 +978,15 @@
 		}
 	}
 	if (n != aliases)
-		for (p = prom_firstprop (node);
+		for (p = prom_firstprop (node, buffer);
 		     p && p != (char *)-1 && *p;
-		     p = prom_nextprop (node, p))
+		     p = prom_nextprop (node, p, buffer))
 			first_prop++;
 	else {
 		char *q;
-		for (p = prom_firstprop (node);
+		for (p = prom_firstprop (node, buffer);
 		     p && p != (char *)-1 && *p;
-		     p = prom_nextprop (node, p)) {
+		     p = prom_nextprop (node, p, buffer)) {
 			if (aliases_nodes == ALIASES_NNODES)
 				break;
 			for (i = 0; i < aliases_nodes; i++)
@@ -1015,7 +1029,7 @@
 	static int usec = 0;
 
 	if (inc) {
-		if (atomic_read(&inode->i_count) == 1)
+		if (inode->i_count == 1)
 			usec++;
 		else if (root_fresh && inode->i_ino == PROC_OPENPROM_FIRST) {
 			root_fresh = 0;
@@ -1028,10 +1042,10 @@
 			usec--;
 	}
 	printk ("openpromfs_use: %d %d %d %d\n",
-		inode->i_ino, inc, usec, atomic_read(&inode->i_count));
+		inode->i_ino, inc, usec, inode->i_count);
 #else
 	if (inc) {
-		if (atomic_read(&inode->i_count) == 1)
+		if (inode->i_count == 1)
 			MOD_INC_USE_COUNT;
 		else if (root_fresh && inode->i_ino == PROC_OPENPROM_FIRST) {
 			root_fresh = 0;
@@ -1062,8 +1076,10 @@
 int init_module (void)
 #endif
 {
+#ifndef __sparc_v9__
 	if (!romvec->pv_romvers)
 		return RET(ENODEV);
+#endif
 	nodes = (openpromfs_node *)__get_free_pages(GFP_KERNEL, 0, 0);
 	if (!nodes) {
 		printk (KERN_WARNING "/proc/openprom: can't get free page\n");
diff -u --recursive --new-file v2.1.44/linux/fs/proc/root.c linux/fs/proc/root.c
--- v2.1.44/linux/fs/proc/root.c	Mon Jul  7 13:11:02 1997
+++ linux/fs/proc/root.c	Wed Jul 16 16:08:02 1997
@@ -24,7 +24,7 @@
 #define FIRST_PROCESS_ENTRY 256
 
 static int proc_root_readdir(struct inode *, struct file *, void *, filldir_t);
-static int proc_root_lookup(struct inode *,struct qstr *,struct inode **);
+static int proc_root_lookup(struct inode *,struct dentry *);
 
 static unsigned char proc_alloc_map[PROC_NDYNAMIC / 8] = {0};
 
@@ -227,7 +227,6 @@
 	    proc_openprom_deflookup)
 		return proc_openprom_inode_operations.lookup 
 				(dir, str, result);
-	iput(dir);
 	return -ENOENT;
 }
 #endif
@@ -622,45 +621,50 @@
 	proc_tty_init();
 }
 
-
-int proc_lookup(struct inode * dir, struct qstr * str, struct inode ** result)
+/*
+ * Don't create negative dentries here, return -ENOENT by hand
+ * instead.
+ */
+int proc_lookup(struct inode * dir, struct dentry *dentry)
 {
+	struct inode *inode;
 	struct proc_dir_entry * de;
 
-	*result = NULL;
 	if (!dir || !S_ISDIR(dir->i_mode))
 		return -ENOTDIR;
 
 	de = (struct proc_dir_entry *) dir->u.generic_ip;
-	if (!de)
-		return -EINVAL;
-
-	*result = NULL;
-	for (de = de->subdir; de ; de = de->next) {
-		if (!de || !de->low_ino)
-			continue;
-		if (de->namelen != str->len)
-			continue;
-		if (!memcmp(str->name, de->name, str->len)) {
-			int ino = de->low_ino | (dir->i_ino & ~(0xffff));
-			if (!(*result = proc_get_inode(dir->i_sb, ino, de)))
-				return -EINVAL;
-			return 0;
+	inode = NULL;
+	if (de) {
+		for (de = de->subdir; de ; de = de->next) {
+			if (!de || !de->low_ino)
+				continue;
+			if (de->namelen != dentry->d_name.len)
+				continue;
+			if (!memcmp(dentry->d_name.name, de->name, de->namelen)) {
+				int ino = de->low_ino | (dir->i_ino & ~(0xffff));
+				inode = proc_get_inode(dir->i_sb, ino, de);
+				if (!inode)
+					return -EINVAL;
+				break;
+			}
 		}
 	}
-	return -ENOENT;
+	if (!inode)
+		return -ENOENT;
+
+	d_add(dentry, inode);
+	return 0;
 }
 
-static int proc_root_lookup(struct inode * dir,struct qstr *str, struct inode ** result)
+static int proc_root_lookup(struct inode * dir, struct dentry * dentry)
 {
 	unsigned int pid, c;
-	int ino, retval;
 	struct task_struct *p;
 	const char *name;
+	struct inode *inode;
 	int len;
 
-	atomic_inc(&dir->i_count);
-
 	if (dir->i_ino == PROC_ROOT_INO) { /* check for safety... */
 		dir->i_nlink = proc_root.nlink;
 
@@ -672,13 +676,12 @@
 		read_unlock(&tasklist_lock);
 	}
 
-	retval = proc_lookup(dir, str, result);
-	if (retval != -ENOENT)
-		return retval;
+	if (!proc_lookup(dir, dentry))
+		return 0;
 	
 	pid = 0;
-	name = str->name;
-	len = str->len;
+	name = dentry->d_name.name;
+	len = dentry->d_name.len;
 	while (len-- > 0) {
 		c = *name - '0';
 		name++;
@@ -694,12 +697,14 @@
 		}
 	}
 	p = find_task_by_pid(pid);
-	if (!pid || !p)
-		return -ENOENT;
-
-	ino = (pid << 16) + PROC_PID_INO;
-	if (!(*result = proc_get_inode(dir->i_sb, ino, &proc_pid)))
-		return -EINVAL;
+	inode = NULL;
+	if (pid && p) {
+		unsigned long ino = (pid << 16) + PROC_PID_INO;
+		inode = proc_get_inode(dir->i_sb, ino, &proc_pid);
+		if (!inode)
+			return -EINVAL;
+	}
+	d_add(dentry, inode);
 	return 0;
 }
 
diff -u --recursive --new-file v2.1.44/linux/fs/read_write.c linux/fs/read_write.c
--- v2.1.44/linux/fs/read_write.c	Mon Jun 16 16:35:59 1997
+++ linux/fs/read_write.c	Sun Jul 13 21:20:10 1997
@@ -60,13 +60,15 @@
 {
 	long retval;
 	struct file * file;
+	struct dentry * dentry;
 	struct inode * inode;
 
 	lock_kernel();
 	retval = -EBADF;
 	if (fd >= NR_OPEN ||
 	    !(file = current->files->fd[fd]) ||
-	    !(inode = file->f_inode))
+	    !(dentry = file->f_dentry) ||
+	    !(inode = dentry->d_inode))
 		goto bad;
 	retval = -EINVAL;
 	if (origin > 2)
@@ -83,6 +85,7 @@
 {
 	long retval;
 	struct file * file;
+	struct dentry * dentry;
 	struct inode * inode;
 	long long offset;
 
@@ -90,7 +93,8 @@
 	retval = -EBADF;
 	if (fd >= NR_OPEN ||
 	    !(file = current->files->fd[fd]) ||
-	    !(inode = file->f_inode))
+	    !(dentry = file->f_dentry) ||
+	    !(inode = dentry->d_inode))
 		goto bad;
 	retval = -EINVAL;
 	if (origin > 2)
@@ -115,6 +119,7 @@
 {
 	int error;
 	struct file * file;
+	struct dentry * dentry;
 	struct inode * inode;
 	long (*read)(struct inode *, struct file *, char *, unsigned long);
 
@@ -123,7 +128,10 @@
 	file = fget(fd);
 	if (!file)
 		goto bad_file;
-	inode = file->f_inode;
+	dentry = file->f_dentry;
+	if (!dentry)
+		goto bad_file;
+	inode = dentry->d_inode;
 	if (!inode)
 		goto out;
 	error = -EBADF;
@@ -137,7 +145,7 @@
 		goto out;
 	error = read(inode,file,buf,count);
 out:
-	fput(file, inode);
+	fput(file);
 bad_file:
 	unlock_kernel();
 	return error;
@@ -147,6 +155,7 @@
 {
 	int error;
 	struct file * file;
+	struct dentry * dentry;
 	struct inode * inode;
 	long (*write)(struct inode *, struct file *, const char *, unsigned long);
 
@@ -155,7 +164,10 @@
 	file = fget(fd);
 	if (!file)
 		goto bad_file;
-	inode = file->f_inode;
+	dentry = file->f_dentry;
+	if (!dentry)
+		goto out;
+	inode = dentry->d_inode;
 	if (!inode)
 		goto out;
 	if (!(file->f_mode & 2))
@@ -168,10 +180,9 @@
 		goto out;
 	down(&inode->i_sem);
 	error = write(inode,file,buf,count);
-	inode->i_status |= ST_MODIFIED;
 	up(&inode->i_sem);
 out:
-	fput(file, inode);
+	fput(file);
 bad_file:
 	unlock_kernel();
 	return error;
@@ -264,8 +275,6 @@
 		if (nr != len)
 			break;
 	}
-	if(fn == (IO_fn_t) file->f_op->write)
-		inode->i_status |= ST_MODIFIED;
 	if (iov != iovstack)
 		kfree(iov);
 	return retval;
@@ -274,14 +283,30 @@
 asmlinkage long sys_readv(unsigned long fd, const struct iovec * vector, unsigned long count)
 {
 	struct file * file;
+	struct dentry * dentry;
 	struct inode * inode;
-	long err = -EBADF;
+	long err;
 
 	lock_kernel();
-	if (fd >= NR_OPEN || !(file = current->files->fd[fd]) || !(inode=file->f_inode))
+	err = -EBADF;
+	if (fd >= NR_OPEN)
+		goto out;
+
+	file = current->files->fd[fd];
+	if (!file)
 		goto out;
+
 	if (!(file->f_mode & 1))
 		goto out;
+
+	dentry = file->f_dentry;
+	if (!dentry)
+		goto out;
+
+	inode = dentry->d_inode;
+	if (!inode)
+		goto out;
+
 	err = do_readv_writev(VERIFY_WRITE, inode, file, vector, count);
 out:
 	unlock_kernel();
@@ -290,15 +315,32 @@
 
 asmlinkage long sys_writev(unsigned long fd, const struct iovec * vector, unsigned long count)
 {
-	int error = -EBADF;
+	long error;
 	struct file * file;
+	struct dentry * dentry;
 	struct inode * inode;
 
 	lock_kernel();
-	if (fd >= NR_OPEN || !(file = current->files->fd[fd]) || !(inode=file->f_inode))
+	error = -EBADF;
+
+	if (fd >= NR_OPEN)
+		goto out;
+
+	file = current->files->fd[fd];
+	if (!file)
 		goto out;
+
 	if (!(file->f_mode & 2))
 		goto out;
+
+	dentry = file->f_dentry;
+	if (!dentry)
+		goto out;
+
+	inode = dentry->d_inode;
+	if (!inode)
+		goto out;
+
 	down(&inode->i_sem);
 	error = do_readv_writev(VERIFY_READ, inode, file, vector, count);
 	up(&inode->i_sem);
diff -u --recursive --new-file v2.1.44/linux/fs/readdir.c linux/fs/readdir.c
--- v2.1.44/linux/fs/readdir.c	Sun Jul  6 20:13:54 1997
+++ linux/fs/readdir.c	Sun Jul 13 21:20:10 1997
@@ -57,22 +57,37 @@
 
 asmlinkage int old_readdir(unsigned int fd, void * dirent, unsigned int count)
 {
-	int error = -EBADF;
+	int error;
 	struct file * file;
+	struct dentry * dentry;
+	struct inode * inode;
 	struct readdir_callback buf;
 
 	lock_kernel();
-	if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+	error = -EBADF;
+	if (fd >= NR_OPEN)
 		goto out;
-	error = -ENOTDIR;
-	if (!file->f_op || !file->f_op->readdir)
+
+	file = current->files->fd[fd];
+	if (!file)
 		goto out;
-	error = verify_area(VERIFY_WRITE, dirent, sizeof(struct old_linux_dirent));
-	if (error)
+
+	dentry = file->f_dentry;
+	if (!dentry)
+		goto out;
+
+	inode = dentry->d_inode;
+	if (!inode)
 		goto out;
+
 	buf.count = 0;
 	buf.dirent = dirent;
-	error = file->f_op->readdir(file->f_inode, file, &buf, fillonedir);
+
+	error = -ENOTDIR;
+	if (!file->f_op || !file->f_op->readdir)
+		goto out;
+
+	error = file->f_op->readdir(inode, file, &buf, fillonedir);
 	if (error < 0)
 		goto out;
 	error = buf.count;
@@ -126,30 +141,44 @@
 asmlinkage int sys_getdents(unsigned int fd, void * dirent, unsigned int count)
 {
 	struct file * file;
+	struct dentry * dentry;
+	struct inode * inode;
 	struct linux_dirent * lastdirent;
 	struct getdents_callback buf;
-	int error = -EBADF;
+	int error;
 
 	lock_kernel();
-	if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+	error = -EBADF;
+	if (fd >= NR_OPEN)
 		goto out;
-	error = -ENOTDIR;
-	if (!file->f_op || !file->f_op->readdir)
+
+	file = current->files->fd[fd];
+	if (!file)
 		goto out;
-	error = verify_area(VERIFY_WRITE, dirent, count);
-	if (error)
+
+	dentry = file->f_dentry;
+	if (!dentry)
+		goto out;
+
+	inode = dentry->d_inode;
+	if (!inode)
 		goto out;
+
 	buf.current_dir = (struct linux_dirent *) dirent;
 	buf.previous = NULL;
 	buf.count = count;
 	buf.error = 0;
-	error = file->f_op->readdir(file->f_inode, file, &buf, filldir);
+
+	error = -ENOTDIR;
+	if (!file->f_op || !file->f_op->readdir)
+		goto out;
+
+	error = file->f_op->readdir(inode, file, &buf, filldir);
 	if (error < 0)
 		goto out;
 	lastdirent = buf.previous;
-	if (!lastdirent) {
-		error = buf.error;
-	} else {
+	error = buf.error;
+	if (lastdirent) {
 		put_user(file->f_pos, &lastdirent->d_off);
 		error = count - buf.count;
 	}
diff -u --recursive --new-file v2.1.44/linux/fs/smbfs/mmap.c linux/fs/smbfs/mmap.c
--- v2.1.44/linux/fs/smbfs/mmap.c	Mon Jun 16 16:35:59 1997
+++ linux/fs/smbfs/mmap.c	Wed Jul 16 19:22:51 1997
@@ -119,8 +119,8 @@
 		inode->i_atime = CURRENT_TIME;
 		inode->i_dirt = 1;
 	}
-	vma->vm_inode = inode;
-	atomic_inc(&inode->i_count);
+
+	vma->vm_dentry = dget(file->f_dentry);
 	vma->vm_ops = &smb_file_mmap;
 	return 0;
 }
diff -u --recursive --new-file v2.1.44/linux/fs/stat.c linux/fs/stat.c
--- v2.1.44/linux/fs/stat.c	Sun Jul  6 21:31:52 1997
+++ linux/fs/stat.c	Wed Jul 16 10:26:21 1997
@@ -48,8 +48,6 @@
 	tmp.st_gid = inode->i_gid;
 	tmp.st_rdev = kdev_t_to_nr(inode->i_rdev);
 	tmp.st_size = inode->i_size;
-	if (inode->i_pipe)
-		tmp.st_size = PIPE_SIZE(*inode);
 	tmp.st_atime = inode->i_atime;
 	tmp.st_mtime = inode->i_mtime;
 	tmp.st_ctime = inode->i_ctime;
@@ -72,8 +70,6 @@
 	tmp.st_gid = inode->i_gid;
 	tmp.st_rdev = kdev_t_to_nr(inode->i_rdev);
 	tmp.st_size = inode->i_size;
-	if (inode->i_pipe)
-		tmp.st_size = PIPE_SIZE(*inode);
 	tmp.st_atime = inode->i_atime;
 	tmp.st_mtime = inode->i_mtime;
 	tmp.st_ctime = inode->i_ctime;
@@ -116,6 +112,7 @@
 	return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
 }
 
+
 #if !defined(__alpha__) && !defined(__sparc__)
 /*
  * For backward compatibility?  Maybe this should be moved
@@ -123,17 +120,21 @@
  */
 asmlinkage int sys_stat(char * filename, struct __old_kernel_stat * statbuf)
 {
-	struct inode * inode;
+	struct dentry * dentry;
 	int error;
 
 	lock_kernel();
-	error = namei(filename, &inode);
-	if (error)
-		goto out;
-	if ((error = do_revalidate(inode)) == 0)
-		error = cp_old_stat(inode,statbuf);
-	iput(inode);
-out:
+	dentry = namei(filename);
+
+	error = PTR_ERR(dentry);
+	if (!IS_ERR(dentry)) {
+		struct inode * inode = dentry->d_inode;
+		error = do_revalidate(inode);
+		if (!error)
+			error = cp_old_stat(inode, statbuf);
+
+		dput(dentry);
+	}
 	unlock_kernel();
 	return error;
 }
@@ -141,17 +142,21 @@
 
 asmlinkage int sys_newstat(char * filename, struct stat * statbuf)
 {
-	struct inode * inode;
+	struct dentry * dentry;
 	int error;
 
 	lock_kernel();
-	error = namei(filename, &inode);
-	if (error)
-		goto out;
-	if ((error = do_revalidate(inode)) == 0)
-		error = cp_new_stat(inode,statbuf);
-	iput(inode);
-out:
+	dentry = namei(filename);
+
+	error = PTR_ERR(dentry);
+	if (!IS_ERR(dentry)) {
+		struct inode * inode = dentry->d_inode;
+		error = do_revalidate(inode);
+		if (!error)
+			error = cp_new_stat(inode,statbuf);
+
+		dput(dentry);
+	}
 	unlock_kernel();
 	return error;
 }
@@ -164,17 +169,21 @@
  */
 asmlinkage int sys_lstat(char * filename, struct __old_kernel_stat * statbuf)
 {
-	struct inode * inode;
+	struct dentry * dentry;
 	int error;
 
 	lock_kernel();
-	error = lnamei(filename, &inode);
-	if (error)
-		goto out;
-	if ((error = do_revalidate(inode)) == 0)
-		error = cp_old_stat(inode,statbuf);
-	iput(inode);
-out:
+	dentry = lnamei(filename);
+
+	error = PTR_ERR(dentry);
+	if (!IS_ERR(dentry)) {
+		struct inode * inode = dentry->d_inode;
+		error = do_revalidate(inode);
+		if (!error)
+			error = cp_old_stat(inode, statbuf);
+
+		dput(dentry);
+	}
 	unlock_kernel();
 	return error;
 }
@@ -183,17 +192,21 @@
 
 asmlinkage int sys_newlstat(char * filename, struct stat * statbuf)
 {
-	struct inode * inode;
+	struct dentry * dentry;
 	int error;
 
 	lock_kernel();
-	error = lnamei(filename, &inode);
-	if (error)
-		goto out;
-	if ((error = do_revalidate(inode)) == 0)
-		error = cp_new_stat(inode,statbuf);
-	iput(inode);
-out:
+	dentry = lnamei(filename);
+
+	error = PTR_ERR(dentry);
+	if (!IS_ERR(dentry)) {
+		struct inode * inode = dentry->d_inode;
+		error = do_revalidate(inode);
+		if (!error)
+			error = cp_new_stat(inode,statbuf);
+
+		dput(dentry);
+	}
 	unlock_kernel();
 	return error;
 }
@@ -207,17 +220,19 @@
 asmlinkage int sys_fstat(unsigned int fd, struct __old_kernel_stat * statbuf)
 {
 	struct file * f;
-	struct inode * inode;
-	int ret = -EBADF;
+	int err = -EBADF;
 
 	lock_kernel();
-	if (fd >= NR_OPEN || !(f=current->files->fd[fd]) || !(inode=f->f_inode))
-		goto out;
-	if ((ret = do_revalidate(inode)) == 0)
-		ret = cp_old_stat(inode,statbuf);
-out:
+	if (fd < NR_OPEN && (f = current->files->fd[fd]) != NULL) {
+		struct dentry * dentry = f->f_dentry;
+		struct inode * inode = dentry->d_inode;
+
+		err = do_revalidate(inode);
+		if (!err)
+			err = cp_old_stat(inode,statbuf);
+	}
 	unlock_kernel();
-	return ret;
+	return err;
 }
 
 #endif
@@ -225,44 +240,43 @@
 asmlinkage int sys_newfstat(unsigned int fd, struct stat * statbuf)
 {
 	struct file * f;
-	struct inode * inode;
 	int err = -EBADF;
 
 	lock_kernel();
-	if (fd >= NR_OPEN || !(f=current->files->fd[fd]) || !(inode=f->f_inode))
-		goto out;
-	if ((err = do_revalidate(inode)) == 0)
-		err = cp_new_stat(inode,statbuf);
-out:
+	if (fd < NR_OPEN && (f = current->files->fd[fd]) != NULL) {
+		struct dentry * dentry = f->f_dentry;
+		struct inode * inode = dentry->d_inode;
+
+		err = do_revalidate(inode);
+		if (!err)
+			err = cp_new_stat(inode,statbuf);
+	}
 	unlock_kernel();
 	return err;
 }
 
 asmlinkage int sys_readlink(const char * path, char * buf, int bufsiz)
 {
-	struct inode * inode;
+	struct dentry * dentry;
 	int error;
 
 	if (bufsiz <= 0)
 		return -EINVAL;
 
 	lock_kernel();
-	error = lnamei(path, &inode);
-	if (error)
-		goto out;
-	error = -EINVAL;
-	if (!inode->i_op || !inode->i_op->readlink ||
-	    !S_ISLNK(inode->i_mode) || (error = do_revalidate(inode)) < 0) {
-		iput(inode);
-		goto out;
-	}
-	if (!IS_RDONLY(inode)) {
-		inode->i_atime = CURRENT_TIME;
-		inode->i_dirt = 1;
-	}
-	error = inode->i_op->readlink(inode,buf,bufsiz);
-	iput(inode);
-out:
+	dentry = lnamei(path);
+
+	error = PTR_ERR(dentry);
+	if (!IS_ERR(dentry)) {
+		struct inode * inode = dentry->d_inode;
+
+		error = -EINVAL;
+		if (inode->i_op && inode->i_op->readlink && !(error = do_revalidate(inode))) {
+			UPDATE_ATIME(inode);
+			error = inode->i_op->readlink(inode,buf,bufsiz);
+		}
+		dput(dentry);
+	}
 	unlock_kernel();
 	return error;
 }
diff -u --recursive --new-file v2.1.44/linux/fs/super.c linux/fs/super.c
--- v2.1.44/linux/fs/super.c	Sun Jul  6 20:13:54 1997
+++ linux/fs/super.c	Wed Jul 16 16:53:10 1997
@@ -33,7 +33,6 @@
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/fd.h>
-#include <linux/dalloc.h>
 #include <linux/init.h>
 
 #include <asm/system.h>
@@ -102,13 +101,13 @@
 
 	lptr->mnt_dev = dev;
 	sema_init(&lptr->mnt_sem, 1);
-	if (dev_name && !getname(dev_name, &tmp)) {
+	if (dev_name && !IS_ERR(tmp = getname(dev_name))) {
 		if ((lptr->mnt_devname =
 		    (char *) kmalloc(strlen(tmp)+1, GFP_KERNEL)) != (char *)NULL)
 			strcpy(lptr->mnt_devname, tmp);
 		putname(tmp);
 	}
-	if (dir_name && !getname(dir_name, &tmp)) {
+	if (dir_name && !IS_ERR(tmp = getname(dir_name))) {
 		if ((lptr->mnt_dirname =
 		    (char *) kmalloc(strlen(tmp)+1, GFP_KERNEL)) != (char *)NULL)
 			strcpy(lptr->mnt_dirname, tmp);
@@ -198,9 +197,11 @@
 	char * name;
 	int err, index;
 
-	err = getname(__name, &name);
-	if (err)
+	name = getname(__name);
+	err = PTR_ERR(name);
+	if (IS_ERR(name))
 		return err;
+
 	index = 0;
 	for (tmp = file_systems ; tmp ; tmp = tmp->next) {
 		if (strcmp(tmp->name, name) == 0) {
@@ -454,26 +455,6 @@
 	return NULL;
 }
 
-void put_super(kdev_t dev)
-{
-	struct super_block * sb;
-
-	if (dev == ROOT_DEV) {
-		printk("VFS: Root device %s: prepare for armageddon\n",
-		       kdevname(dev));
-		return;
-	}
-	if (!(sb = get_super(dev)))
-		return;
-	if (sb->s_root != sb->s_root->d_mounts) {
-		printk("VFS: Mounted device %s - tssk, tssk\n",
-		       kdevname(dev));
-		return;
-	}
-	if (sb->s_op && sb->s_op->put_super)
-		sb->s_op->put_super(sb);
-}
-
 asmlinkage int sys_ustat(dev_t dev, struct ustat * ubuf)
 {
         struct super_block *s;
@@ -573,14 +554,12 @@
 {
 	struct dentry * covers = dentry->d_covers;
 
-	if (covers == dentry) {
-		printk("VFS: unmount - covers == dentry?\n");
-		return;
+	if (covers != dentry) {
+		covers->d_mounts = covers;
+		dentry->d_covers = dentry;
+		dput(covers);
+		dput(dentry);
 	}
-	covers->d_mounts = covers;
-	dentry->d_covers = dentry;
-	dput(covers);
-	dput(dentry);
 }
 
 static void d_mount(struct dentry *covers, struct dentry *dentry)
@@ -598,13 +577,18 @@
 	struct super_block * sb;
 	int retval;
 	
+	sb = get_super(dev);
+	if (!sb)
+		return -ENOENT;
+
+	if (!sb->s_root)
+		return -ENOENT;
+
 	if (dev==ROOT_DEV && !unmount_root) {
 		/*
 		 * Special case for "unmounting" root. We just try to remount
 		 * it readonly, and sync() the device.
 		 */
-		if (!(sb=get_super(dev)))
-			return -ENOENT;
 		if (!(sb->s_flags & MS_RDONLY)) {
 			/*
 			 * Make sure all quotas are turned off on this device we need to mount
@@ -620,9 +604,6 @@
 		}
 		return 0;
 	}
-	sb=get_super(dev);
-	if (!sb)
-		return -ENOENT;
 
 	/*
 	 * Before checking if the filesystem is still busy make sure the kernel
@@ -630,23 +611,44 @@
 	 * too bad there are no quotas running anymore. Turn them on again by hand.
 	 */
 	quota_off(dev, -1);
-	if (!fs_may_umount(dev, sb->s_root))
+	if (!fs_may_umount(sb, sb->s_root))
 		return -EBUSY;
 
-	/* Clear up the dcache tree. This should be cleaner.. */
-	if (sb->s_root) {
-		d_umount(sb->s_root);
-		d_delete(sb->s_root);
-	}
-
+	/* clean up dcache .. */
+	d_umount(sb->s_root);
 	sb->s_root = NULL;
-	if (sb->s_op && sb->s_op->write_super && sb->s_dirt)
-		sb->s_op->write_super(sb);
-	put_super(dev);
+
+	if (sb->s_op) {
+		if (sb->s_op->write_super && sb->s_dirt)
+			sb->s_op->write_super(sb);
+		if (sb->s_op->put_super)
+			sb->s_op->put_super(sb);
+	}
 	remove_vfsmnt(dev);
 	return 0;
 }
 
+static int umount_dev(kdev_t dev)
+{
+	int retval;
+	struct inode * inode = get_empty_inode();
+
+	inode->i_rdev = dev;
+	if (MAJOR(dev) >= MAX_BLKDEV)
+		return -ENXIO;
+
+	retval = do_umount(dev,0);
+	if (!retval) {
+		fsync_dev(dev);
+		if (dev != ROOT_DEV) {
+			blkdev_release(inode);
+			put_unnamed_dev(dev);
+		}
+	}
+	iput(inode);
+	return retval;
+}
+
 /*
  * Now umount can handle mount points as well as block devices.
  * This is important for filesystems which use unnamed block devices.
@@ -660,50 +662,36 @@
 
 asmlinkage int sys_umount(char * name)
 {
-	struct inode * inode;
-	kdev_t dev;
-	struct inode * dummy_inode = NULL;
-	int retval = -EPERM;
+	struct dentry * dentry;
+	int retval;
 
-	lock_kernel();
 	if (!suser())
-		goto out;
-	retval = namei(name, &inode);
-	if (S_ISBLK(inode->i_mode)) {
-		dev = inode->i_rdev;
-		retval = -EACCES;
-		if (IS_NODEV(inode)) {
-			iput(inode);
-			goto out;
-		}
-	} else {
-		retval = -EINVAL;
-		if (!inode->i_sb || inode != inode->i_sb->s_root->d_inode) {
-			iput(inode);
-			goto out;
-		}
-		dev = inode->i_sb->s_dev;
-		iput(inode);
-		inode = dummy_inode = get_empty_inode();
-		inode->i_rdev = dev;
-	}
-	retval = -ENXIO;
-	if (MAJOR(dev) >= MAX_BLKDEV) {
-		iput(inode);
-		goto out;
-	}
-	retval = do_umount(dev,0);
-	if (!retval) {
-		fsync_dev(dev);
-		if (dev != ROOT_DEV) {
-			blkdev_release (inode);
-			put_unnamed_dev(dev);
+		return -EPERM;
+
+	lock_kernel();
+	dentry = namei(name);
+	retval = PTR_ERR(dentry);
+	if (!IS_ERR(dentry)) {
+		struct inode * inode = dentry->d_inode;
+		kdev_t dev = inode->i_rdev;
+
+		retval = 0;		
+		if (S_ISBLK(inode->i_mode)) {
+			if (IS_NODEV(inode))
+				retval = -EACCES;
+		} else {
+			struct super_block *sb = inode->i_sb;
+			retval = -EINVAL;
+			if (sb && inode == sb->s_root->d_inode) {
+				dev = sb->s_dev;
+				retval = 0;
+			}
 		}
+		dput(dentry);
+
+		if (!retval)
+			retval = umount_dev(dev);
 	}
-	iput(inode);
-	if (!retval)
-		fsync_dev(dev);
-out:
 	unlock_kernel();
 	return retval;
 }
@@ -740,16 +728,11 @@
 		return -EACCES;
 		/*flags |= MS_RDONLY;*/
 
-	dir_d = lookup_dentry(dir_name, NULL, 1);
+	dir_d = namei(dir_name);
 	error = PTR_ERR(dir_d);
 	if (IS_ERR(dir_d))
 		return error;
 
-	if (dir_d->d_flag & D_NEGATIVE) {
-		dput(dir_d);
-		return -ENOENT;
-	}
-
 	if (dir_d->d_covers != dir_d) {
 		dput(dir_d);
 		return -EBUSY;
@@ -797,7 +780,7 @@
 		/*flags |= MS_RDONLY;*/
 	/* If we are remounting RDONLY, make sure there are no rw files open */
 	if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY))
-		if (!fs_may_remount_ro(sb->s_dev))
+		if (!fs_may_remount_ro(sb))
 			return -EBUSY;
 	sb->s_flags = (flags & ~MS_RDONLY) | (sb->s_flags & MS_RDONLY);
 	if (sb->s_op && sb->s_op->remount_fs) {
@@ -815,18 +798,19 @@
 
 static int do_remount(const char *dir,int flags,char *data)
 {
-	struct inode *dir_i;
+	struct dentry *dentry;
 	int retval;
 
-	retval = namei(dir, &dir_i);
-	if (retval)
-		return retval;
-	if (dir_i != dir_i->i_sb->s_root->d_inode) {
-		iput(dir_i);
-		return -EINVAL;
+	dentry = namei(dir);
+	retval = PTR_ERR(dentry);
+	if (!IS_ERR(dentry)) {
+		struct super_block * sb = dentry->d_inode->i_sb;
+
+		retval = -EINVAL;
+		if (dentry == sb->s_root)
+			retval = do_remount_sb(sb, flags, data);
+		dput(dentry);
 	}
-	retval = do_remount_sb(dir_i->i_sb, flags, data);
-	iput(dir_i);
 	return retval;
 }
 
@@ -877,7 +861,8 @@
 	unsigned long new_flags, void * data)
 {
 	struct file_system_type * fstype;
-	struct inode * inode;
+	struct dentry * dentry = NULL;
+	struct inode * inode = NULL;
 	struct file_operations * fops;
 	kdev_t dev;
 	int retval = -EPERM;
@@ -909,58 +894,54 @@
 		goto out;
 	t = fstype->name;
 	fops = NULL;
-	if ((fstype->fs_flags & FS_REQUIRES_DEV)) {
-		retval = namei(dev_name, &inode);
-		if (retval)
+	if (fstype->fs_flags & FS_REQUIRES_DEV) {
+		dentry = namei(dev_name);
+		retval = PTR_ERR(dentry);
+		if (IS_ERR(dentry))
 			goto out;
+
+		inode = dentry->d_inode;
 		retval = -ENOTBLK;
-		if (!S_ISBLK(inode->i_mode)) {
-			iput(inode);
-			goto out;
-		}
+		if (!S_ISBLK(inode->i_mode))
+			goto dput_and_out;
+
 		retval = -EACCES;
-		if (IS_NODEV(inode)) {
-			iput(inode);
-			goto out;
-		}
+		if (IS_NODEV(inode))
+			goto dput_and_out;
+
 		dev = inode->i_rdev;
 		retval = -ENXIO;
-		if (MAJOR(dev) >= MAX_BLKDEV) {
-			iput(inode);
-			goto out;
-		}
+		if (MAJOR(dev) >= MAX_BLKDEV)
+			goto dput_and_out;
+
 		fops = get_blkfops(MAJOR(dev));
 		retval = -ENOTBLK;
-		if (!fops) {
-			iput(inode);
-			goto out;
-		}
+		if (!fops)
+			goto dput_and_out;
+
 		if (fops->open) {
 			struct file dummy;	/* allows read-write or read-only flag */
 			memset(&dummy, 0, sizeof(dummy));
-			dummy.f_inode = inode;
+			dummy.f_dentry = dentry;
 			dummy.f_mode = (new_flags & MS_RDONLY) ? 1 : 3;
 			retval = fops->open(inode, &dummy);
-			if (retval) {
-				iput(inode);
-				goto out;
-			}
+			if (retval)
+				goto dput_and_out;
 		}
 
 	} else {
 		retval = -EMFILE;
 		if (!(dev = get_unnamed_dev()))
 			goto out;
-		inode = NULL;
 	}
+
 	page = 0;
 	if ((new_flags & MS_MGC_MSK) == MS_MGC_VAL) {
 		flags = new_flags & ~MS_MGC_MSK;
 		retval = copy_mount_options(data, &page);
 		if (retval < 0) {
 			put_unnamed_dev(dev);
-			iput(inode);
-			goto out;
+			goto dput_and_out;
 		}
 	}
 	retval = do_mount(dev,dev_name,dir_name,t,flags,(void *) page);
@@ -969,7 +950,8 @@
 		fops->release(inode, NULL);
 		put_unnamed_dev(dev);
 	}
-	iput(inode);
+dput_and_out:
+	dput(dentry);
 out:
 	unlock_kernel();
 	return retval;
@@ -1036,7 +1018,7 @@
 	memset(&filp, 0, sizeof(filp));
 	d_inode = get_empty_inode();
 	d_inode->i_rdev = ROOT_DEV;
-	filp.f_inode = d_inode;
+	filp.f_dentry = NULL;
 	if ( root_mountflags & MS_RDONLY)
 		filp.f_mode = 1; /* read only */
 	else
@@ -1094,8 +1076,7 @@
 {
 	kdev_t old_root_dev;
 	struct vfsmount *vfsmnt;
-	struct inode *old_root,*old_pwd,*inode;
-	unsigned long old_fs;
+	struct dentry *old_root,*old_pwd,*dir_d = NULL;
 	int error;
 
 	old_root = current->fs->root;
@@ -1107,24 +1088,29 @@
 	}
 	ROOT_DEV = new_root_dev;
 	do_mount_root();
-	old_fs = get_fs();
-	set_fs(get_ds());
-        error = namei(put_old, &inode);
-	if (error) inode = NULL;
-	set_fs(old_fs);
-	if (!error && (atomic_read(&inode->i_count) != 1 || inode->i_mount))
+	dir_d = lookup_dentry(put_old, NULL, 1);
+	if (IS_ERR(dir_d)) {
+		error = PTR_ERR(dir_d);
+	} else if (!dir_d->d_inode) {
+		dput(dir_d);
+		error = -ENOENT;
+	} else {
+		error = 0;
+	}
+	if (!error && dir_d->d_covers != dir_d) {
+		dput(dir_d);
 		error = -EBUSY;
-	if (!error && !S_ISDIR(inode->i_mode))
+	}
+	if (!error && !S_ISDIR(dir_d->d_inode->i_mode)) {
+		dput(dir_d);
 		error = -ENOTDIR;
-	iput(old_root); /* current->fs->root */
-	iput(old_pwd); /* current->fs->pwd */
+	}
+	dput(old_root);
+	dput(old_pwd);
 	if (error) {
 		int umount_error;
 
-		if (inode) iput(inode);
 		printk(KERN_NOTICE "Trying to unmount old root ... ");
-		old_root->i_mount = old_root;
-			/* does this belong into do_mount_root ? */
 		umount_error = do_umount(old_root_dev,1);
 		if (umount_error) printk(KERN_ERR "error %d\n",umount_error);
 		else {
@@ -1133,16 +1119,16 @@
 		}
 		return umount_error ? error : 0;
 	}
-	iput(old_root); /* sb->s_covered */
 	remove_vfsmnt(old_root_dev);
 	vfsmnt = add_vfsmnt(old_root_dev,"/dev/root.old",put_old);
 	if (!vfsmnt) printk(KERN_CRIT "Trouble: add_vfsmnt failed\n");
 	else {
-		vfsmnt->mnt_sb = old_root->i_sb;
-		vfsmnt->mnt_sb->s_covered = inode;
+		vfsmnt->mnt_sb = old_root->d_inode->i_sb;
+		d_mount(dir_d,vfsmnt->mnt_sb->s_root);
 		vfsmnt->mnt_flags = vfsmnt->mnt_sb->s_flags;
 	}
-	inode->i_mount = old_root;
+	d_umount(old_root);
+	d_mount(dir_d,old_root);
 	return 0;
 }
 
diff -u --recursive --new-file v2.1.44/linux/fs/sysv/dir.c linux/fs/sysv/dir.c
--- v2.1.44/linux/fs/sysv/dir.c	Mon Jun 16 16:35:59 1997
+++ linux/fs/sysv/dir.c	Wed Jul 16 08:31:41 1997
@@ -57,6 +57,7 @@
 	sysv_mknod,		/* mknod */
 	sysv_rename,		/* rename */
 	NULL,			/* readlink */
+	NULL,			/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
diff -u --recursive --new-file v2.1.44/linux/fs/sysv/file.c linux/fs/sysv/file.c
--- v2.1.44/linux/fs/sysv/file.c	Mon Jun 16 16:35:59 1997
+++ linux/fs/sysv/file.c	Wed Jul 16 08:28:13 1997
@@ -64,6 +64,7 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
+	NULL,			/* follow_link */
 	generic_readpage,	/* readpage */
 	NULL,			/* writepage */
 	sysv_bmap,		/* bmap */
@@ -194,7 +195,7 @@
 	filp->f_reada = 1;
 	if (!IS_RDONLY(inode)) {
 		inode->i_atime = CURRENT_TIME;
-		inode->i_dirt = 1;
+		mark_inode_dirty(inode);
 	}
 	return read;
 }
@@ -255,7 +256,7 @@
 		pos += c;
 		if (pos > inode->i_size) {
 			inode->i_size = pos;
-			inode->i_dirt = 1;
+			mark_inode_dirty(inode);
 		}
 		written += c;
 		buf += c;
@@ -265,6 +266,6 @@
 	}
 	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 	filp->f_pos = pos;
-	inode->i_dirt = 1;
+	mark_inode_dirty(inode);
 	return written;
 }
diff -u --recursive --new-file v2.1.44/linux/fs/sysv/ialloc.c linux/fs/sysv/ialloc.c
--- v2.1.44/linux/fs/sysv/ialloc.c	Mon Jun 16 16:35:59 1997
+++ linux/fs/sysv/ialloc.c	Wed Jul 16 19:22:51 1997
@@ -62,9 +62,8 @@
 		printk("sysv_free_inode: inode has no device\n");
 		return;
 	}
-	if (atomic_read(&inode->i_count) != 1) {
-		printk("sysv_free_inode: inode has count=%d\n",
-		       atomic_read(&inode->i_count));
+	if (inode->i_count != 1) {
+		printk("sysv_free_inode: inode has count=%d\n", inode->i_count);
 		return;
 	}
 	if (inode->i_nlink) {
@@ -150,12 +149,12 @@
 	mark_buffer_dirty(sb->sv_bh1, 1); /* super-block has been modified */
 	if (sb->sv_bh1 != sb->sv_bh2) mark_buffer_dirty(sb->sv_bh2, 1);
 	sb->s_dirt = 1; /* and needs time stamp */
-	atomic_set(&inode->i_count, 1);
+	inode->i_count = 1;
 	inode->i_nlink = 1;
 	inode->i_dev = sb->s_dev;
 	inode->i_uid = current->fsuid;
 	inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
-	inode->i_dirt = 1;
+	mark_inode_dirty(inode);
 	inode->i_ino = ino;
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
 	inode->i_op = NULL;
@@ -166,7 +165,7 @@
 	inode->i_size = 0;		/* ditto */
 	sysv_write_inode(inode);	/* ensure inode not allocated again */
 					/* FIXME: caller may call this too. */
-	inode->i_dirt = 1;		/* cleared by sysv_write_inode() */
+	mark_inode_dirty(inode);	/* cleared by sysv_write_inode() */
 	/* That's it. */
 	(*sb->sv_sb_total_free_inodes)--;
 	mark_buffer_dirty(sb->sv_bh2, 1); /* super-block has been modified again */
diff -u --recursive --new-file v2.1.44/linux/fs/sysv/inode.c linux/fs/sysv/inode.c
--- v2.1.44/linux/fs/sysv/inode.c	Mon Jun 16 16:35:59 1997
+++ linux/fs/sysv/inode.c	Wed Jul 16 08:27:34 1997
@@ -344,6 +344,7 @@
 	struct buffer_head *bh;
 	const char *found;
 	kdev_t dev = sb->s_dev;
+	struct inode *root_inode;
 
 	if (1024 != sizeof (struct xenix_super_block))
 		panic("Xenix FS: bad super-block size");
@@ -483,9 +484,10 @@
 	/* set up enough so that it can read an inode */
 	sb->s_dev = dev;
 	sb->s_op = &sysv_sops;
-	sb->s_mounted = iget(sb,SYSV_ROOT_INO);
+	root_inode = iget(sb,SYSV_ROOT_INO);
+	sb->s_root = d_alloc_root(root_inode, NULL);
 	unlock_super(sb);
-	if (!sb->s_mounted) {
+	if (!sb->s_root) {
 		printk("SysV FS: get root inode failed\n");
 		sysv_put_super(sb);
 		return NULL;
@@ -534,7 +536,7 @@
 	MOD_DEC_USE_COUNT;
 }
 
-void sysv_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+int sysv_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
 {
 	struct statfs tmp;
 
@@ -547,7 +549,7 @@
 	tmp.f_ffree = sysv_count_free_inodes(sb);	/* free file nodes in fs */
 	tmp.f_namelen = SYSV_NAMELEN;
 	/* Don't know what value to put in tmp.f_fsid */ /* file system id */
-	copy_to_user(buf, &tmp, bufsiz);
+	return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
 }
 
 
@@ -667,7 +669,7 @@
 	}
 	*p = tmp;
 	inode->i_ctime = CURRENT_TIME;
-	inode->i_dirt = 1;
+	mark_inode_dirty(inode);
 	return result;
 }
 
@@ -900,13 +902,11 @@
 		printk("Bad inode number on dev %s"
 		       ": %d is out of range\n",
 		       kdevname(inode->i_dev), ino);
-		inode->i_dirt = 0;
 		return 0;
 	}
 	block = sb->sv_firstinodezone + ((ino-1) >> sb->sv_inodes_per_block_bits);
 	if (!(bh = sv_bread(sb,inode->i_dev,block))) {
 		printk("unable to read i-node block\n");
-		inode->i_dirt = 0;
 		return 0;
 	}
 	raw_inode = (struct sysv_inode *) bh->b_data + ((ino-1) & sb->sv_inodes_per_block_1);
@@ -937,7 +937,6 @@
 	else
 		for (block = 0; block < 10+1+1+1; block++)
 			write3byte(&raw_inode->i_a.i_addb[3*block],inode->u.sysv_i.i_data[block]);
-	inode->i_dirt=0;
 	mark_buffer_dirty(bh, 1);
 	return bh;
 }
diff -u --recursive --new-file v2.1.44/linux/fs/sysv/namei.c linux/fs/sysv/namei.c
--- v2.1.44/linux/fs/sysv/namei.c	Mon Jun 16 16:35:59 1997
+++ linux/fs/sysv/namei.c	Wed Jul 16 19:22:51 1997
@@ -175,7 +175,7 @@
 		if (pos > dir->i_size) {
 			de->inode = 0;
 			dir->i_size = pos;
-			dir->i_dirt = 1;
+			mark_inode_dirty(dir);
 		}
 		if (de->inode) {
 			if (namecompare(namelen, SYSV_NAMELEN, name, de->name)) {
@@ -184,7 +184,7 @@
 			}
 		} else {
 			dir->i_mtime = dir->i_ctime = CURRENT_TIME;
-			dir->i_dirt = 1;
+			mark_inode_dirty(dir);
 			for (i = 0; i < SYSV_NAMELEN ; i++)
 				de->name[i] = (i < namelen) ? name[i] : 0;
 			mark_buffer_dirty(bh, 1);
@@ -219,11 +219,11 @@
 	}
 	inode->i_op = &sysv_file_inode_operations;
 	inode->i_mode = mode;
-	inode->i_dirt = 1;
+	mark_inode_dirty(inode);
 	error = sysv_add_entry(dir,name,len, &bh ,&de);
 	if (error) {
 		inode->i_nlink--;
-		inode->i_dirt = 1;
+		mark_inode_dirty(inode);
 		iput(inode);
 		iput(dir);
 		return error;
@@ -276,11 +276,11 @@
 		init_fifo(inode);
 	if (S_ISBLK(mode) || S_ISCHR(mode))
 		inode->i_rdev = to_kdev_t(rdev);
-	inode->i_dirt = 1;
+	mark_inode_dirty(inode);
 	error = sysv_add_entry(dir, name, len, &bh, &de);
 	if (error) {
 		inode->i_nlink--;
-		inode->i_dirt = 1;
+		mark_inode_dirty(inode);
 		iput(inode);
 		iput(dir);
 		return error;
@@ -325,7 +325,7 @@
 	if (!dir_block) {
 		iput(dir);
 		inode->i_nlink--;
-		inode->i_dirt = 1;
+		mark_inode_dirty(inode);
 		iput(inode);
 		return -ENOSPC;
 	}
@@ -341,7 +341,7 @@
 	inode->i_mode = S_IFDIR | (mode & 0777 & ~current->fs->umask);
 	if (dir->i_mode & S_ISGID)
 		inode->i_mode |= S_ISGID;
-	inode->i_dirt = 1;
+	mark_inode_dirty(inode);
 	error = sysv_add_entry(dir, name, len, &bh, &de);
 	if (error) {
 		iput(dir);
@@ -352,7 +352,7 @@
 	de->inode = inode->i_ino;
 	mark_buffer_dirty(bh, 1);
 	dir->i_nlink++;
-	dir->i_dirt = 1;
+	mark_inode_dirty(dir);
 	iput(dir);
 	iput(inode);
 	brelse(bh);
@@ -454,7 +454,7 @@
 		retval = -ENOENT;
 		goto end_rmdir;
 	}
-	if (atomic_read(&inode->i_count) > 1) {
+	if (inode->i_count > 1) {
 		retval = -EBUSY;
 		goto end_rmdir;
 	}
@@ -463,10 +463,10 @@
 	de->inode = 0;
 	mark_buffer_dirty(bh, 1);
 	inode->i_nlink=0;
-	inode->i_dirt=1;
+	mark_inode_dirty(inode);
 	dir->i_nlink--;
 	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
-	dir->i_dirt=1;
+	mark_inode_dirty(dir);
 	retval = 0;
 end_rmdir:
 	iput(dir);
@@ -517,10 +517,10 @@
 	de->inode = 0;
 	mark_buffer_dirty(bh, 1);
 	dir->i_ctime = dir->i_mtime = CURRENT_TIME;
-	dir->i_dirt = 1;
+	mark_inode_dirty(dir);
 	inode->i_nlink--;
 	inode->i_ctime = dir->i_ctime;
-	inode->i_dirt = 1;
+	mark_inode_dirty(inode);
 	retval = 0;
 end_unlink:
 	brelse(bh);
@@ -550,7 +550,7 @@
 	if (!name_block) {
 		iput(dir);
 		inode->i_nlink--;
-		inode->i_dirt = 1;
+		mark_inode_dirty(inode);
 		iput(inode);
 		return -ENOSPC;
 	}
@@ -563,11 +563,11 @@
 	mark_buffer_dirty(name_block, 1);
 	brelse(name_block);
 	inode->i_size = i;
-	inode->i_dirt = 1;
+	mark_inode_dirty(inode);
 	bh = sysv_find_entry(dir,name,len,&de);
 	if (bh) {
 		inode->i_nlink--;
-		inode->i_dirt = 1;
+		mark_inode_dirty(inode);
 		iput(inode);
 		brelse(bh);
 		iput(dir);
@@ -576,7 +576,7 @@
 	i = sysv_add_entry(dir, name, len, &bh, &de);
 	if (i) {
 		inode->i_nlink--;
-		inode->i_dirt = 1;
+		mark_inode_dirty(inode);
 		iput(inode);
 		iput(dir);
 		return i;
@@ -624,7 +624,7 @@
 	iput(dir);
 	oldinode->i_nlink++;
 	oldinode->i_ctime = CURRENT_TIME;
-	oldinode->i_dirt = 1;
+	mark_inode_dirty(oldinode);
 	iput(oldinode);
 	return 0;
 }
@@ -635,7 +635,7 @@
 	int ino;
 	int result;
 
-	atomic_inc(&new_inode->i_count);
+	new_inode->i_count++;
 	result = 0;
 	for (;;) {
 		if (new_inode == old_inode) {
@@ -667,8 +667,8 @@
  * Anybody can rename anything with this: the permission checks are left to the
  * higher-level routines.
  */
-static int do_sysv_rename(struct inode * old_dir, const char * old_name, int old_len,
-			  struct inode * new_dir, const char * new_name, int new_len)
+static int do_sysv_rename(struct inode * old_dir, struct dentry * old_dentry,
+			  struct inode * new_dir, struct dentry * new_dentry)
 {
 	struct inode * old_inode, * new_inode;
 	struct buffer_head * old_bh, * new_bh, * dir_bh;
@@ -687,21 +687,21 @@
 start_up:
 	old_inode = new_inode = NULL;
 	old_bh = new_bh = dir_bh = NULL;
-	old_bh = sysv_find_entry(old_dir,old_name,old_len,&old_de);
+	old_bh = sysv_find_entry(old_dir,old_dentry->d_name.name,
+				old_dentry->d_name.len,&old_de);
 	retval = -ENOENT;
 	if (!old_bh)
 		goto end_rename;
-	old_inode = __iget(old_dir->i_sb, old_de->inode, 0); /* don't cross mnt-points */
-	if (!old_inode)
-		goto end_rename;
+	old_inode = old_dentry->d_inode;/* don't cross mnt-points */
 	retval = -EPERM;
 	if ((old_dir->i_mode & S_ISVTX) && 
 	    current->fsuid != old_inode->i_uid &&
 	    current->fsuid != old_dir->i_uid && !fsuser())
 		goto end_rename;
-	new_bh = sysv_find_entry(new_dir,new_name,new_len,&new_de);
+	new_inode = new_dentry->d_inode;
+	new_bh = sysv_find_entry(new_dir,new_dentry->d_name.name,
+				new_dentry->d_name.len,&new_de);
 	if (new_bh) {
-		new_inode = __iget(new_dir->i_sb, new_de->inode, 0);
 		if (!new_inode) {
 			brelse(new_bh);
 			new_bh = NULL;
@@ -722,7 +722,7 @@
 		if (!empty_dir(new_inode))
 			goto end_rename;
 		retval = -EBUSY;
-		if (atomic_read(&new_inode->i_count) > 1)
+		if (new_inode->i_count > 1)
 			goto end_rename;
 	}
 	retval = -EPERM;
@@ -748,7 +748,8 @@
 			goto end_rename;
 	}
 	if (!new_bh) {
-		retval = sysv_add_entry(new_dir,new_name,new_len,&new_bh,&new_de);
+		retval = sysv_add_entry(new_dir,new_dentry->d_name.name,
+					new_dentry->d_name.len,&new_bh,&new_de);
 		if (retval)
 			goto end_rename;
 	}
@@ -763,13 +764,13 @@
 	old_de->inode = 0;
 	new_de->inode = old_inode->i_ino;
 	old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
-	old_dir->i_dirt = 1;
+	mark_inode_dirty(old_dir);
 	new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME;
-	new_dir->i_dirt = 1;
+	mark_inode_dirty(new_dir);
 	if (new_inode) {
 		new_inode->i_nlink--;
 		new_inode->i_ctime = CURRENT_TIME;
-		new_inode->i_dirt = 1;
+		mark_inode_dirty(new_inode);
 	}
 	mark_buffer_dirty(old_bh, 1);
 	mark_buffer_dirty(new_bh, 1);
@@ -777,13 +778,13 @@
 		PARENT_INO(dir_bh->b_data) = new_dir->i_ino;
 		mark_buffer_dirty(dir_bh, 1);
 		old_dir->i_nlink--;
-		old_dir->i_dirt = 1;
+		mark_inode_dirty(old_dir);
 		if (new_inode) {
 			new_inode->i_nlink--;
-			new_inode->i_dirt = 1;
+			mark_inode_dirty(new_inode);
 		} else {
 			new_dir->i_nlink++;
-			new_dir->i_dirt = 1;
+			mark_inode_dirty(new_dir);
 		}
 	}
 	retval = 0;
@@ -807,8 +808,8 @@
  * the same device that races occur: many renames can happen at once, as long
  * as they are on different partitions.
  */
-int sysv_rename(struct inode * old_dir, const char * old_name, int old_len,
-		struct inode * new_dir, const char * new_name, int new_len)
+int sysv_rename(struct inode * old_dir, struct dentry * old_dentry,
+		struct inode * new_dir, struct dentry * new_dentry)
 {
 	static struct wait_queue * wait = NULL;
 	static int lock = 0;
@@ -817,8 +818,8 @@
 	while (lock)
 		sleep_on(&wait);
 	lock = 1;
-	result = do_sysv_rename(old_dir, old_name, old_len,
-				new_dir, new_name, new_len);
+	result = do_sysv_rename(old_dir, old_dentry,
+				new_dir, new_dentry);
 	lock = 0;
 	wake_up(&wait);
 	return result;
diff -u --recursive --new-file v2.1.44/linux/fs/sysv/symlink.c linux/fs/sysv/symlink.c
--- v2.1.44/linux/fs/sysv/symlink.c	Mon Jun 16 16:35:59 1997
+++ linux/fs/sysv/symlink.c	Wed Jul 16 08:31:02 1997
@@ -21,6 +21,7 @@
 #include <asm/uaccess.h>
 
 static int sysv_readlink(struct inode *, char *, int);
+static struct dentry *sysv_follow_link(struct inode *, struct dentry *);
 
 /*
  * symlinks can't do much...
@@ -37,6 +38,7 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	sysv_readlink,		/* readlink */
+	sysv_follow_link,	/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
@@ -44,6 +46,21 @@
 	NULL			/* permission */
 };
 
+static struct dentry *sysv_follow_link(struct inode * inode, struct dentry * base)
+{
+	struct buffer_head * bh;
+
+	bh = sysv_file_bread(inode, 0, 0);
+	if (!bh) {
+		dput(base);
+		return ERR_PTR(-EIO);
+	}
+	UPDATE_ATIME(inode);
+	base = lookup_dentry(bh->b_data, base, 1);
+	brelse(bh);
+	return base;
+}
+
 static int sysv_readlink(struct inode * inode, char * buffer, int buflen)
 {
 	struct buffer_head * bh;
@@ -54,7 +71,6 @@
 	if (buflen > inode->i_sb->sv_block_size_1)
 		buflen = inode->i_sb->sv_block_size_1;
 	bh = sysv_file_bread(inode, 0, 0);
-	iput(inode);
 	if (!bh)
 		return 0;
 	bh_data = bh->b_data;
diff -u --recursive --new-file v2.1.44/linux/fs/sysv/truncate.c linux/fs/sysv/truncate.c
--- v2.1.44/linux/fs/sysv/truncate.c	Sun Nov 26 09:23:10 1995
+++ linux/fs/sysv/truncate.c	Wed Jul 16 08:05:24 1997
@@ -64,7 +64,7 @@
 			continue;
 		}
 		*p = 0;
-		inode->i_dirt = 1;
+		mark_inode_dirty(inode);
 		brelse(bh);
 		sysv_free_block(sb,block);
 	}
@@ -257,12 +257,14 @@
 static int trunc_all(struct inode * inode)
 {
 	struct super_block * sb;
+	char * res;
 
 	sb = inode->i_sb;
+	res = (char *)test_bit(I_DIRTY,&inode->i_state);
 	return trunc_direct(inode)
-	     | trunc_indirect(inode,sb->sv_ind0_size,&inode->u.sysv_i.i_data[10],0,&inode->i_dirt)
-	     | trunc_dindirect(inode,sb->sv_ind1_size,&inode->u.sysv_i.i_data[11],0,&inode->i_dirt)
-	     | trunc_tindirect(inode,sb->sv_ind2_size,&inode->u.sysv_i.i_data[12],0,&inode->i_dirt);
+	     | trunc_indirect(inode,sb->sv_ind0_size,&inode->u.sysv_i.i_data[10],0,res)
+	     | trunc_dindirect(inode,sb->sv_ind1_size,&inode->u.sysv_i.i_data[11],0,res)
+	     | trunc_tindirect(inode,sb->sv_ind2_size,&inode->u.sysv_i.i_data[12],0,res);
 }
 
 
@@ -285,5 +287,5 @@
 		schedule();
 	}
 	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-	inode->i_dirt = 1;
+	mark_inode_dirty(inode);
 }
diff -u --recursive --new-file v2.1.44/linux/fs/ufs/ufs_file.c linux/fs/ufs/ufs_file.c
--- v2.1.44/linux/fs/ufs/ufs_file.c	Mon Jun 16 16:35:59 1997
+++ linux/fs/ufs/ufs_file.c	Wed Jul 16 20:37:21 1997
@@ -6,7 +6,7 @@
  * Laboratory for Computer Science Research Computing Facility
  * Rutgers, The State University of New Jersey
  *
- * $Id: ufs_file.c,v 1.8 1997/06/05 01:29:09 davem Exp $
+ * $Id: ufs_file.c,v 1.9 1997/07/17 02:24:13 davem Exp $
  *
  */
 
@@ -41,6 +41,7 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
+	NULL,			/* follow_link */
 	generic_readpage,	/* readpage */
 	NULL,			/* writepage */
 	ufs_bmap,		/* bmap */
diff -u --recursive --new-file v2.1.44/linux/fs/ufs/ufs_inode.c linux/fs/ufs/ufs_inode.c
--- v2.1.44/linux/fs/ufs/ufs_inode.c	Mon Jun 16 16:35:59 1997
+++ linux/fs/ufs/ufs_inode.c	Wed Jul 16 20:37:21 1997
@@ -6,7 +6,7 @@
  * Laboratory for Computer Science Research Computing Facility
  * Rutgers, The State University of New Jersey
  *
- * $Id: ufs_inode.c,v 1.8 1997/06/04 08:28:28 davem Exp $
+ * $Id: ufs_inode.c,v 1.9 1997/07/17 02:24:14 davem Exp $
  *
  */
 
@@ -19,8 +19,7 @@
 	printk("ino %lu  mode 0%6.6o  lk %d  uid %d  gid %d"
 	       "  sz %lu  blks %lu  cnt %u\n",
 	       inode->i_ino, inode->i_mode, inode->i_nlink, inode->i_uid,
-	       inode->i_gid, inode->i_size, inode->i_blocks,
-	       atomic_read(&inode->i_count));
+	       inode->i_gid, inode->i_size, inode->i_blocks, inode->i_count);
 	printk("  db <0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x"
 	       " 0x%x 0x%x 0x%x 0x%x>\n",
 		inode->u.ufs_i.i_data[0], inode->u.ufs_i.i_data[1],
diff -u --recursive --new-file v2.1.44/linux/fs/ufs/ufs_namei.c linux/fs/ufs/ufs_namei.c
--- v2.1.44/linux/fs/ufs/ufs_namei.c	Sat Nov 30 02:26:15 1996
+++ linux/fs/ufs/ufs_namei.c	Wed Jul 16 20:37:21 1997
@@ -6,7 +6,7 @@
  * Laboratory for Computer Science Research Computing Facility
  * Rutgers, The State University of New Jersey
  *
- * $Id: ufs_namei.c,v 1.7 1996/06/01 14:56:49 ecd Exp $
+ * $Id: ufs_namei.c,v 1.8 1997/07/17 02:24:14 davem Exp $
  *
  */
 
@@ -35,12 +35,14 @@
 }
 
 /* XXX - this is a mess, especially for endianity */
-int ufs_lookup (struct inode * dir, const char * name, int len,
+int ufs_lookup (struct inode * dir, struct qstr *qname,
 	        struct inode ** result)
 {
 	unsigned long int lfragno, fragno;
 	struct buffer_head * bh;
 	struct ufs_direct * d;
+	const char *name = qname->name;
+	int len = qname->len;
 
 	if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG)
 		printk("Passed name: %s\nPassed length: %d\n", name, len);
diff -u --recursive --new-file v2.1.44/linux/fs/ufs/ufs_super.c linux/fs/ufs/ufs_super.c
--- v2.1.44/linux/fs/ufs/ufs_super.c	Mon Jun 16 16:35:59 1997
+++ linux/fs/ufs/ufs_super.c	Wed Jul 16 20:37:21 1997
@@ -8,7 +8,7 @@
  *
  * Copyright (C) 1996  Eddie C. Dost  (ecd@skynet.be)
  *
- * $Id: ufs_super.c,v 1.24 1997/06/04 08:28:29 davem Exp $
+ * $Id: ufs_super.c,v 1.25 1997/07/17 02:24:15 davem Exp $
  *
  */
 
@@ -254,7 +254,7 @@
 	sb->u.ufs_sb.s_lmask = ~((ufs_swab32(usb->fs_fmask) - ufs_swab32(usb->fs_bmask))
 					>> ufs_swab32(usb->fs_fshift));
 	sb->u.ufs_sb.s_fsfrag = ufs_swab32(usb->fs_frag); /* XXX - rename this later */
-	sb->s_mounted = iget(sb, UFS_ROOTINO);
+	sb->s_root = d_alloc_root(iget(sb, UFS_ROOTINO), NULL);
 
 #ifdef DEBUG_UFS_SUPER
 	printk("ufs_read_super: inopb %u\n", sb->u.ufs_sb.s_inopb);
diff -u --recursive --new-file v2.1.44/linux/fs/vfat/namei.c linux/fs/vfat/namei.c
--- v2.1.44/linux/fs/vfat/namei.c	Mon Jun 16 16:35:59 1997
+++ linux/fs/vfat/namei.c	Wed Jul 16 19:22:51 1997
@@ -877,7 +877,7 @@
 
 		PRINTK(("vfat_find: create file 4\n"));
 		dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME;
-		dir->i_dirt = 1;
+		mark_inode_dirty(dir);
 
 		PRINTK(("vfat_find: create file 5\n"));
 
@@ -1010,7 +1010,7 @@
 		return -EIO;
 	(*result)->i_mtime = (*result)->i_atime = (*result)->i_ctime =
 	    CURRENT_TIME;
-	(*result)->i_dirt = 1;
+	mark_inode_dirty(*result);
 	(*result)->i_version = ++event;
 	dir->i_version = event;
 
@@ -1046,7 +1046,7 @@
 	 * XXX all times should be set by caller upon successful completion.
 	 */
 	dir->i_atime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
-	dir->i_dirt = 1;
+	mark_inode_dirty(dir);
 	memcpy(de->name,name,MSDOS_NAME);
 	memset(de->unused, 0, sizeof(de->unused));
 	de->lcase = 0;
@@ -1062,7 +1062,7 @@
 		vfat_read_inode(dot);
 	if (!dot) return -EIO;
 	dot->i_mtime = dot->i_atime = CURRENT_TIME;
-	dot->i_dirt = 1;
+	mark_inode_dirty(dot);
 	if (isdot) {
 		dot->i_size = dir->i_size;
 		MSDOS_I(dot)->i_start = MSDOS_I(dir)->i_start;
@@ -1125,7 +1125,7 @@
 	struct buffer_head *bh;
 	struct msdos_dir_entry *de;
 
-	if (atomic_read(&dir->i_count) > 1)
+	if (dir->i_count > 1)
 		return -EBUSY;
 	if (MSDOS_I(dir)->i_start) { /* may be zero in mkdir */
 		pos = 0;
@@ -1173,7 +1173,8 @@
 	inode->i_mtime = dir->i_mtime = CURRENT_TIME;
 	inode->i_atime = dir->i_atime = CURRENT_TIME;
 	dir->i_nlink--;
-	inode->i_dirt = dir->i_dirt = 1;
+	mark_inode_dirty(dir);
+	mark_inode_dirty(inode);
 	de->name[0] = DELETED_FLAG;
 	fat_mark_buffer_dirty(sb, bh, 1);
 	iput(inode);
@@ -1196,7 +1197,8 @@
 	inode->i_atime = dir->i_atime = CURRENT_TIME;
 	dir->i_version = ++event;
 	MSDOS_I(inode)->i_busy = 1;
-	inode->i_dirt = dir->i_dirt = 1;
+	mark_inode_dirty(dir);
+	mark_inode_dirty(inode);
 	de->name[0] = DELETED_FLAG;
 	fat_mark_buffer_dirty(sb, bh, 1);
 
@@ -1478,7 +1480,7 @@
 	MSDOS_I(new_inode)->i_oldlink = old_inode;
 	fat_cache_inval_inode(old_inode);
 	PRINTK(("vfat_rename 15: old_slots=%d\n",old_slots));
-	old_inode->i_dirt = 1;
+	mark_inode_dirty(old_inode);
 	old_dir->i_version = ++event;
 
 	/* remove the old entry */
@@ -1511,7 +1513,7 @@
 		}
 		dotdot_de->start = MSDOS_I(dotdot_inode)->i_start =
 		    MSDOS_I(new_dir)->i_start;
-		dotdot_inode->i_dirt = 1;
+		mark_inode_dirty(dotdot_inode);
 		fat_mark_buffer_dirty(sb, dotdot_bh, 1);
 		old_dir->i_nlink--;
 		new_dir->i_nlink++;
diff -u --recursive --new-file v2.1.44/linux/include/asm-mips/namei.h linux/include/asm-mips/namei.h
--- v2.1.44/linux/include/asm-mips/namei.h	Thu Jun 26 12:33:40 1997
+++ linux/include/asm-mips/namei.h	Wed Jul 16 19:22:51 1997
@@ -13,6 +13,8 @@
 /* Only one at this time. */
 #define IRIX32_EMUL "usr/gnemul/irix/"
 
+#if 0 /* XXX FIXME */
+
 extern int __namei(int, const char *, struct inode *, char *, struct inode **,
 		   struct inode **, struct qstr *, struct dentry **, int *);
 
@@ -43,6 +45,8 @@
 
 	return 0;
 }
+
+#endif /* XXX FIXME */
 
 #else /* !defined(CONFIG_BINFMT_IRIX) */
 
diff -u --recursive --new-file v2.1.44/linux/include/asm-mips/socket.h linux/include/asm-mips/socket.h
--- v2.1.44/linux/include/asm-mips/socket.h	Thu Jun 26 12:33:40 1997
+++ linux/include/asm-mips/socket.h	Wed Jul 16 19:22:51 1997
@@ -1,7 +1,6 @@
 #ifndef __ASM_MIPS_SOCKET_H
 #define __ASM_MIPS_SOCKET_H
 
-#include <linux/types.h>
 #include <asm/sockios.h>
 
 /*
diff -u --recursive --new-file v2.1.44/linux/include/asm-sparc/namei.h linux/include/asm-sparc/namei.h
--- v2.1.44/linux/include/asm-sparc/namei.h	Mon Jun 16 16:36:00 1997
+++ linux/include/asm-sparc/namei.h	Wed Jul 16 20:37:22 1997
@@ -1,4 +1,4 @@
-/* $Id: namei.h,v 1.5 1997/06/07 08:32:54 ecd Exp $
+/* $Id: namei.h,v 1.6 1997/07/17 02:24:25 davem Exp $
  * linux/include/asm-sparc/namei.h
  *
  * Routines to handle famous /usr/gnemul/s*.
@@ -11,6 +11,8 @@
 #define SPARC_BSD_EMUL "usr/gnemul/sunos/"
 #define SPARC_SOL_EMUL "usr/gnemul/solaris/"
 
+#if 0 /* XXX FIXME */
+
 extern int __namei(int, const char *, struct inode *, char *, struct inode **,
 		   struct inode **, struct qstr *, struct dentry **, int *);
 
@@ -43,5 +45,7 @@
 
 	return 0;
 }
+
+#endif /* XXX FIXME */
 
 #endif /* __SPARC_NAMEI_H */
diff -u --recursive --new-file v2.1.44/linux/include/asm-sparc64/bitops.h linux/include/asm-sparc64/bitops.h
--- v2.1.44/linux/include/asm-sparc64/bitops.h	Mon Jul  7 08:18:55 1997
+++ linux/include/asm-sparc64/bitops.h	Wed Jul 16 19:22:51 1997
@@ -1,4 +1,4 @@
-/* $Id: bitops.h,v 1.18 1997/06/30 12:36:18 davem Exp $
+/* $Id: bitops.h,v 1.19 1997/07/08 10:17:37 davem Exp $
  * bitops.h: Bit string operations on the V9.
  *
  * Copyright 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -23,21 +23,21 @@
 {
 	unsigned long oldbit;
 	unsigned long temp0, temp1;
-	unsigned int * m = ((unsigned int *) addr) + (nr >> 5);
+	unsigned long * m = ((unsigned long *) addr) + (nr >> 6);
 
 	__asm__ __volatile__("
-	lduw		[%4], %0
+	ldx		[%4], %0
 1:
 	andcc		%0, %3, %2
-	bne,pn		%%icc, 2f
+	bne,pn		%%xcc, 2f
 	 xor		%0, %3, %1
-	cas 		[%4], %0, %1
+	casx 		[%4], %0, %1
 	cmp		%0, %1
-	bne,a,pn	%%icc, 1b
-	 lduw		[%4], %0
+	bne,a,pn	%%xcc, 1b
+	 ldx		[%4], %0
 2:
 "	: "=&r" (temp0), "=&r" (temp1), "=&r" (oldbit)
-	: "HIr" (1UL << (nr & 31)), "r" (m)
+	: "HIr" (1UL << (nr & 63)), "r" (m)
 	: "cc");
 	return oldbit != 0;
 }
@@ -51,21 +51,21 @@
 {
 	unsigned long oldbit;
 	unsigned long temp0, temp1;
-	unsigned int * m = ((unsigned int *) addr) + (nr >> 5);
+	unsigned long * m = ((unsigned long *) addr) + (nr >> 6);
 
 	__asm__ __volatile__("
-	lduw		[%4], %0
+	ldx		[%4], %0
 1:
 	andcc		%0, %3, %2
-	be,pn		%%icc, 2f
+	be,pn		%%xcc, 2f
 	 xor		%0, %3, %1
-	cas 		[%4], %0, %1
+	casx 		[%4], %0, %1
 	cmp		%0, %1
-	bne,a,pn	%%icc, 1b
-	 lduw		[%4], %0
+	bne,a,pn	%%xcc, 1b
+	 ldx		[%4], %0
 2:
 "	: "=&r" (temp0), "=&r" (temp1), "=&r" (oldbit)
-	: "HIr" (1UL << (nr & 31)), "r" (m)
+	: "HIr" (1UL << (nr & 63)), "r" (m)
 	: "cc");
 	return oldbit != 0;
 }
@@ -79,19 +79,19 @@
 {
 	unsigned long oldbit;
 	unsigned long temp0, temp1;
-	unsigned int * m = ((unsigned int *) addr) + (nr >> 5);
+	unsigned long * m = ((unsigned long *) addr) + (nr >> 6);
 
 	__asm__ __volatile__("
-	lduw		[%4], %0
+	ldx		[%4], %0
 1:
 	and		%0, %3, %2
 	xor		%0, %3, %1
-	cas 		[%4], %0, %1
+	casx 		[%4], %0, %1
 	cmp		%0, %1
-	bne,a,pn	%%icc, 1b
-	 lduw		[%4], %0
+	bne,a,pn	%%xcc, 1b
+	 ldx		[%4], %0
 "	: "=&r" (temp0), "=&r" (temp1), "=&r" (oldbit)
-	: "HIr" (1UL << (nr & 31)), "r" (m)
+	: "HIr" (1UL << (nr & 63)), "r" (m)
 	: "cc");
 	return oldbit != 0;
 }
@@ -103,7 +103,7 @@
 
 extern __inline__ unsigned long test_bit(int nr, __const__ void *addr)
 {
-	return 1UL & (((__const__ int *) addr)[nr >> 5] >> (nr & 31));
+	return 1UL & (((__const__ long *) addr)[nr >> 6] >> (nr & 63));
 }
 
 /* The easy/cheese version for now. */
diff -u --recursive --new-file v2.1.44/linux/include/asm-sparc64/fbio.h linux/include/asm-sparc64/fbio.h
--- v2.1.44/linux/include/asm-sparc64/fbio.h	Thu Jun 26 12:33:40 1997
+++ linux/include/asm-sparc64/fbio.h	Wed Jul 16 19:22:51 1997
@@ -138,7 +138,6 @@
 	__u32	wi_attrs;
 	__u32	wi_values[32];
 };
-/* XXX 32-bit binary compatability item... -DaveM */
 struct fb_wid_list {
 	__u32	wl_flags;
 	__u32	wl_count;
@@ -150,6 +149,21 @@
 #define FBIO_WID_PUT	_IOW('F', 32, struct fb_wid_list)
 #define FBIO_WID_GET	_IOWR('F', 33, struct fb_wid_list)
 
+/* Creator ioctls */
+#define FFB_IOCTL	('F'<<8)
+#define FFB_SYS_INFO		(FFB_IOCTL|80)
+#define FFB_CLUTREAD		(FFB_IOCTL|81)
+#define FFB_CLUTPOST		(FFB_IOCTL|82)
+#define FFB_SETDIAGMODE		(FFB_IOCTL|83)
+#define FFB_GETMONITORID	(FFB_IOCTL|84)
+#define FFB_GETVIDEOMODE	(FFB_IOCTL|85)
+#define FFB_SETVIDEOMODE	(FFB_IOCTL|86)
+#define FFB_SETSERVER		(FFB_IOCTL|87)
+#define FFB_SETOVCTL		(FFB_IOCTL|88)
+#define FFB_GETOVCTL		(FFB_IOCTL|89)
+#define FFB_GETSAXNUM		(FFB_IOCTL|90)
+#define FFB_FBDEBUG		(FFB_IOCTL|91)
+
 /* Cg14 ioctls */
 #define MDI_IOCTL          ('M'<<8)
 #define MDI_RESET          (MDI_IOCTL|1)
@@ -174,16 +188,15 @@
  */
 #define MDI_CLEAR_XLUT       (MDI_IOCTL|9)
 
-/* leo ioctls */
-struct leo_clut_alloc {
+/* leo & ffb ioctls */
+struct fb_clut_alloc {
 	__u32	clutid;	/* Set on return */
  	__u32	flag;
  	__u32	index;
 };
 
-/* XXX 32-bit binary compatability item... -DaveM */
-struct leo_clut {
-#define LEO_CLUT_WAIT	0x00000001	/* Not yet implemented */
+struct fb_clut {
+#define FB_CLUT_WAIT	0x00000001	/* Not yet implemented */
  	__u32	flag;
  	__u32	clutid;
  	__u32	offset;
@@ -192,10 +205,21 @@
  	char *	green;
  	char *	blue;
 };
-#define LEO_CLUTALLOC	_IOWR('L', 53, struct leo_clut_alloc)
-#define LEO_CLUTFREE	_IOW('L', 54, struct leo_clut_alloc)
-#define LEO_CLUTREAD	_IOW('L', 55, struct leo_clut)
-#define LEO_CLUTPOST	_IOW('L', 56, struct leo_clut)
+
+struct fb_clut32 {
+ 	__u32	flag;
+ 	__u32	clutid;
+ 	__u32	offset;
+ 	__u32	count;
+ 	__u32	red;
+ 	__u32	green;
+ 	__u32	blue;
+};
+
+#define LEO_CLUTALLOC	_IOWR('L', 53, struct fb_clut_alloc)
+#define LEO_CLUTFREE	_IOW('L', 54, struct fb_clut_alloc)
+#define LEO_CLUTREAD	_IOW('L', 55, struct fb_clut)
+#define LEO_CLUTPOST	_IOW('L', 56, struct fb_clut)
 #define LEO_SETGAMMA	_IOW('L', 68, int) /* Not yet implemented */
 #define LEO_GETGAMMA	_IOR('L', 69, int) /* Not yet implemented */
 
diff -u --recursive --new-file v2.1.44/linux/include/asm-sparc64/floppy.h linux/include/asm-sparc64/floppy.h
--- v2.1.44/linux/include/asm-sparc64/floppy.h	Thu Mar 27 14:40:09 1997
+++ linux/include/asm-sparc64/floppy.h	Wed Jul 16 19:22:51 1997
@@ -1,4 +1,4 @@
-/* $Id: floppy.h,v 1.2 1997/03/14 21:05:25 jj Exp $
+/* $Id: floppy.h,v 1.3 1997/07/11 03:03:22 davem Exp $
  * asm-sparc64/floppy.h: Sparc specific parts of the Floppy driver.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -315,7 +315,7 @@
         /* printk("DOR @0x%p\n", &sun_fdc->dor_82077); */ /* P3 */
 
 	/* Success... */
-	return (int) sun_fdc;
+	return (int) ((unsigned long)sun_fdc);
 }
 
 static int sparc_eject(void)
diff -u --recursive --new-file v2.1.44/linux/include/asm-sparc64/hardirq.h linux/include/asm-sparc64/hardirq.h
--- v2.1.44/linux/include/asm-sparc64/hardirq.h	Thu May 29 21:53:09 1997
+++ linux/include/asm-sparc64/hardirq.h	Wed Jul 16 19:22:51 1997
@@ -13,8 +13,8 @@
 
 #ifndef __SMP__
 
-#define hardirq_trylock(cpu)	(++local_irq_count[cpu], (cpu)==0)
-#define hardirq_endlock(cpu)	(--local_irq_count[cpu])
+#define hardirq_trylock(cpu)	(local_irq_count[cpu] == 0)
+#define hardirq_endlock(cpu)	do { } while(0)
 
 #define hardirq_enter(cpu)	(local_irq_count[cpu]++)
 #define hardirq_exit(cpu)	(local_irq_count[cpu]--)
diff -u --recursive --new-file v2.1.44/linux/include/asm-sparc64/head.h linux/include/asm-sparc64/head.h
--- v2.1.44/linux/include/asm-sparc64/head.h	Mon Jul  7 08:18:55 1997
+++ linux/include/asm-sparc64/head.h	Wed Jul 16 19:22:51 1997
@@ -1,4 +1,4 @@
-/* $Id: head.h,v 1.26 1997/07/07 03:05:23 davem Exp $ */
+/* $Id: head.h,v 1.27 1997/07/13 17:30:43 davem Exp $ */
 #ifndef _SPARC64_HEAD_H
 #define _SPARC64_HEAD_H
 
@@ -115,7 +115,7 @@
 /* On UP this is ok, and worth the effort, for SMP we need
  * a different mechanism and thus cannot do it all in trap table. -DaveM
  */
-#if 0 /* ndef __SMP__ */
+#ifndef __SMP__
 #define TRAP_IVEC				\
 	ldxa	[%g2] ASI_UDB_INTR_R, %g3;	\
 	and	%g3, 0x7ff, %g3;		\
diff -u --recursive --new-file v2.1.44/linux/include/asm-sparc64/mmu_context.h linux/include/asm-sparc64/mmu_context.h
--- v2.1.44/linux/include/asm-sparc64/mmu_context.h	Mon Jul  7 08:18:55 1997
+++ linux/include/asm-sparc64/mmu_context.h	Wed Jul 16 19:22:51 1997
@@ -1,4 +1,4 @@
-/* $Id: mmu_context.h,v 1.16 1997/07/05 09:54:46 davem Exp $ */
+/* $Id: mmu_context.h,v 1.17 1997/07/13 19:13:39 davem Exp $ */
 #ifndef __SPARC64_MMU_CONTEXT_H
 #define __SPARC64_MMU_CONTEXT_H
 
@@ -11,11 +11,6 @@
 
 #ifndef __ASSEMBLY__
 
-/* Initialize the context related info for a new mm_struct
- * instance.
- */
-#define init_new_context(mm)	((mm)->context = NO_CONTEXT)
-
 #define destroy_context(mm)	do { } while(0)
 
 extern unsigned long tlb_context_cache;
@@ -25,6 +20,11 @@
 #define CTX_FIRST_VERSION	((1UL << CTX_VERSION_SHIFT) + 1UL)
 
 extern void get_new_mmu_context(struct mm_struct *mm, unsigned long ctx);
+
+/* Initialize the context related info for a new mm_struct
+ * instance.
+ */
+#define init_new_context(mm)	get_new_mmu_context((mm), tlb_context_cache)
 
 extern __inline__ void get_mmu_context(struct task_struct *tsk)
 {
diff -u --recursive --new-file v2.1.44/linux/include/asm-sparc64/namei.h linux/include/asm-sparc64/namei.h
--- v2.1.44/linux/include/asm-sparc64/namei.h	Mon Jun 16 16:36:00 1997
+++ linux/include/asm-sparc64/namei.h	Wed Jul 16 20:37:22 1997
@@ -1,4 +1,4 @@
-/* $Id: namei.h,v 1.4 1997/06/07 08:32:56 ecd Exp $
+/* $Id: namei.h,v 1.5 1997/07/17 02:24:28 davem Exp $
  * linux/include/asm-sparc64/namei.h
  *
  * Routines to handle famous /usr/gnemul/s*.
@@ -11,6 +11,7 @@
 #define SPARC_BSD_EMUL "usr/gnemul/sunos/"
 #define SPARC_SOL_EMUL "usr/gnemul/solaris/"
 
+#if 0 /* XXX FIXME */
 extern int __namei(int, const char *, struct inode *, char *, struct inode **,
 		   struct inode **, struct qstr *, struct dentry **, int *);
 
@@ -43,5 +44,7 @@
 
 	return 0;
 }
+
+#endif /* XXX FIXME */
 
 #endif /* __SPARC64_NAMEI_H */
diff -u --recursive --new-file v2.1.44/linux/include/asm-sparc64/softirq.h linux/include/asm-sparc64/softirq.h
--- v2.1.44/linux/include/asm-sparc64/softirq.h	Thu May 29 21:53:09 1997
+++ linux/include/asm-sparc64/softirq.h	Wed Jul 16 19:22:51 1997
@@ -43,10 +43,12 @@
 do {	int ent = nr;		\
 	bh_mask &= ~(1 << ent);	\
 	bh_mask_count[ent]++;	\
+	barrier();		\
 } while(0)
 
 #define enable_bh(nr)			\
 do {	int ent = nr;			\
+	barrier();			\
 	if (!--bh_mask_count[ent])	\
 		bh_mask |= 1 << ent;	\
 } while(0)
diff -u --recursive --new-file v2.1.44/linux/include/asm-sparc64/spinlock.h linux/include/asm-sparc64/spinlock.h
--- v2.1.44/linux/include/asm-sparc64/spinlock.h	Thu May 29 21:53:10 1997
+++ linux/include/asm-sparc64/spinlock.h	Wed Jul 16 19:22:51 1997
@@ -53,6 +53,11 @@
 
 #else /* !(__SMP__) */
 
+/* All of these locking primitives are expected to work properly
+ * even in an RMO memory model, which currently is what the kernel
+ * runs in.
+ */
+
 typedef unsigned char spinlock_t;
 #define SPIN_LOCK_UNLOCKED	0
 #define spin_lock_init(lock)	(*(lock) = 0)
@@ -64,6 +69,7 @@
 1:	ldstub		[%0], %%g2
 	brnz,a,pn	%%g2, 2f
 	 ldub		[%0], %%g2
+	membar		#LoadLoad | #LoadStore
 	.text		2
 2:	brnz,a,pt	2b
 	 ldub		[%0], %%g2
@@ -77,7 +83,8 @@
 extern __inline__ int spin_trylock(spinlock_t *lock)
 {
 	unsigned int result;
-	__asm__ __volatile__("ldstub [%1], %0"
+	__asm__ __volatile__("ldstub [%1], %0\n\t"
+			     "membar #LoadLoad | #LoadStore"
 			     : "=r" (result)
 			     : "r" (lock)
 			     : "memory");
@@ -86,7 +93,11 @@
 
 extern __inline__ void spin_unlock(spinlock_t *lock)
 {
-	__asm__ __volatile__("stb %%g0, [%0]" : : "r" (lock) : "memory");
+	__asm__ __volatile__("membar	#StoreStore | #LoadStore\n\t"
+			     "stb	%%g0, [%0]"
+			     : /* No outputs */
+			     : "r" (lock)
+			     : "memory");
 }
 
 extern __inline__ void spin_lock_irq(spinlock_t *lock)
@@ -96,6 +107,7 @@
 	ldstub		[%0], %%g2
 	brnz,a,pn	%%g2, 2f
 	 ldub		[%0], %%g2
+	membar		#LoadLoad | #LoadStore
 	.text		2
 2:	brnz,a,pt	2b
 	 ldub		[%0], %%g2
@@ -109,6 +121,7 @@
 extern __inline__ void spin_unlock_irq(spinlock_t *lock)
 {
 	__asm__ __volatile__("
+	membar		#StoreStore | #LoadStore
 	stb		%%g0, [%0]
 	wrpr		%%g0, 0x0, %%pil
 "	: /* no outputs */
@@ -116,28 +129,30 @@
 	: "memory");
 }
 
-#define spin_lock_irqsave(lock, flags)			\
-do {	register spinlock_t *lp asm("g1");		\
-	lp = lock;					\
-	__asm__ __volatile__(				\
-	"	rdpr		%%pil, %0\n\t"		\
-	"	wrpr		%%g0, 15, %%pil\n\t"	\
-	"1:	ldstub		[%1], %%g2\n\t"		\
-	"	brnz,a,pnt	%%g2, 2f\n\t"		\
-	"	 ldub		[%1], %%g2\n\t"		\
-	"	.text		2\n\t"			\
-	"2:	brnz,a,pt	%%g2, 2b\n\t"		\
-	"	 ldub		[%1], %%g2\n\t"		\
-	"	b,a,pt		%%xcc, 1b\n\t"		\
-	"	.previous\n"				\
-	: "=r" (flags)					\
-	: "r" (lp)					\
-	: "g2", "memory");				\
+#define spin_lock_irqsave(lock, flags)				\
+do {	register spinlock_t *lp asm("g1");			\
+	lp = lock;						\
+	__asm__ __volatile__(					\
+	"	rdpr		%%pil, %0\n\t"			\
+	"	wrpr		%%g0, 15, %%pil\n\t"		\
+	"1:	ldstub		[%1], %%g2\n\t"			\
+	"	brnz,a,pnt	%%g2, 2f\n\t"			\
+	"	 ldub		[%1], %%g2\n\t"			\
+	"	membar		#LoadLoad | #LoadStore\n\t"	\
+	"	.text		2\n\t"				\
+	"2:	brnz,a,pt	%%g2, 2b\n\t"			\
+	"	 ldub		[%1], %%g2\n\t"			\
+	"	b,a,pt		%%xcc, 1b\n\t"			\
+	"	.previous\n"					\
+	: "=r" (flags)						\
+	: "r" (lp)						\
+	: "g2", "memory");					\
 } while(0)
 
 extern __inline__ void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags)
 {
 	__asm__ __volatile__("
+	membar		#StoreStore | #LoadStore
 	stb		%%g0, [%0]
 	wrpr		%1, 0x0, %%pil
 "	: /* no outputs */
@@ -161,6 +176,7 @@
 	cmp		%%g2, %%g3
 	bne,a,pn	%%xcc, 1b
 	 ldx		[%0],%%g2
+	membar		#LoadLoad | #LoadStore
 	.text		2
 2:	ldx		[%0], %%g2
 3:	brlz,pt		%%g2, 3b
@@ -169,12 +185,13 @@
 	.previous
 "	: /* no outputs */
 	: "r" (rw)
-	: "g2", "g3", "memory");
+	: "g2", "g3", "cc", "memory");
 }
 
 extern __inline__ void read_unlock(rwlock_t *rw)
 {
 	__asm__ __volatile__("
+	membar		#StoreStore | #LoadStore
 	ldx		[%0], %%g2
 1:
 	sub		%%g2, 1, %%g3
@@ -184,7 +201,7 @@
 	 ldx		[%0], %%g2
 "	: /* no outputs */
 	: "r" (rw)
-	: "g2", "g3", "memory");
+	: "g2", "g3", "cc", "memory");
 }
 
 extern __inline__ void write_lock(rwlock_t *rw)
@@ -203,6 +220,7 @@
 	andncc		%%g3, %%g5, %%g0
 	bne,a,pn	%%xcc, 3f
 	 ldx		[%0], %%g2
+	membar		#LoadLoad | #LoadStore
 	.text		2
 3:
 	andn		%%g2, %%g5, %%g3
@@ -210,6 +228,7 @@
 	cmp		%%g2, %%g3
 	bne,a,pn	%%xcc, 3b
 	 ldx		[%0], %%g2
+	membar		#LoadLoad | #LoadStore
 5:	ldx		[%0], %%g2
 6:	brlz,pt		%%g2, 6b
 	 ldx		[%0], %%g2
@@ -222,6 +241,7 @@
 extern __inline__ void write_unlock(rwlock_t *rw)
 {
 	__asm__ __volatile__("
+	membar		#StoreStore | #LoadStore
 	sethi		%%uhi(0x8000000000000000), %%g5
 	ldx		[%0], %%g2
 	sllx		%%g5, 32, %%g5
diff -u --recursive --new-file v2.1.44/linux/include/asm-sparc64/string.h linux/include/asm-sparc64/string.h
--- v2.1.44/linux/include/asm-sparc64/string.h	Mon Jul  7 08:18:56 1997
+++ linux/include/asm-sparc64/string.h	Wed Jul 16 19:22:51 1997
@@ -1,4 +1,4 @@
-/* $Id: string.h,v 1.6 1997/06/24 17:29:14 jj Exp $
+/* $Id: string.h,v 1.7 1997/07/13 18:23:44 davem Exp $
  * string.h: External definitions for optimized assembly string
  *           routines for the Linux Kernel.
  *
@@ -44,28 +44,16 @@
 	if(n) {
 		if(n <= 32) {
 			__builtin_memcpy(to, from, n);
-#if 0			
-		} else if (n < 384) {
-			__memcpy_16plus(to, from, n, ASI_BLK_P, ASI_BLK_P);
-		} else {
-			__memcpy_384plus(to, from, n, ASI_BLK_P, ASI_BLK_P);
-		}
-#else
 		} else {
 			__memcpy(to, from, n);
 		}
-#endif		
 	}
 	return to;
 }
 
 extern inline void *__nonconstant_memcpy(void *to, const void *from, __kernel_size_t n)
 {
-#if 0
-	__memcpy_entry(to, from, n, ASI_BLK_P, ASI_BLK_P);
-#else
 	__memcpy(to, from, n);
-#endif
 	return to;
 }
 
diff -u --recursive --new-file v2.1.44/linux/include/asm-sparc64/uaccess.h linux/include/asm-sparc64/uaccess.h
--- v2.1.44/linux/include/asm-sparc64/uaccess.h	Mon Jul  7 08:18:56 1997
+++ linux/include/asm-sparc64/uaccess.h	Wed Jul 16 19:22:51 1997
@@ -1,4 +1,4 @@
-/* $Id: uaccess.h,v 1.19 1997/06/30 10:31:46 jj Exp $ */
+/* $Id: uaccess.h,v 1.20 1997/07/13 18:23:45 davem Exp $ */
 #ifndef _ASM_UACCESS_H
 #define _ASM_UACCESS_H
 
@@ -255,47 +255,44 @@
 
 extern int __get_user_bad(void);
 
-extern __kernel_size_t __memcpy_short(void *to, const void *from, __kernel_size_t size, long asi_src, long asi_dst);
-extern __kernel_size_t __memcpy_entry(void *to, const void *from, __kernel_size_t size, long asi_src, long asi_dst);
-extern __kernel_size_t __memcpy_16plus(void *to, const void *from, __kernel_size_t size, long asi_src, long asi_dst);
-extern __kernel_size_t __memcpy_386plus(void *to, const void *from, __kernel_size_t size, long asi_src, long asi_dst);
+extern __kernel_size_t __memcpy_short(void *to, const void *from,
+				      __kernel_size_t size,
+				      long asi_src, long asi_dst);
+
+extern __kernel_size_t __memcpy_entry(void *to, const void *from,
+				      __kernel_size_t size,
+				      long asi_src, long asi_dst);
+
+extern __kernel_size_t __memcpy_16plus(void *to, const void *from,
+				       __kernel_size_t size,
+				       long asi_src, long asi_dst);
+
+extern __kernel_size_t __memcpy_386plus(void *to, const void *from,
+					__kernel_size_t size,
+					long asi_src, long asi_dst);
 
-#if 0
-extern __inline__ __kernel_size_t __copy_to_user(void *to, void *from, __kernel_size_t size)
-{
-	if (__builtin_constant_p(size)) {
-		if (!size) return 0;
-		if (size < 16)
-			return __memcpy_short(to,(const void *)from,size,ASI_BLK_P,ASI_BLK_S);
-		else if (size < 384)
-			return __memcpy_16plus(to,(const void *)from,size,ASI_BLK_P,ASI_BLK_S);
-		else
-			return __memcpy_386plus(to,(const void *)from,size,ASI_BLK_P,ASI_BLK_S);
-	} else {
-		if (!size) return 0;
-		return __memcpy_entry(to,(const void *)from,size,ASI_BLK_P,ASI_BLK_S);
-	}
-}
+extern __kernel_size_t __copy_from_user(void *to, const void *from,
+					__kernel_size_t size);
 
-extern __inline__ __kernel_size_t __copy_from_user(void *to, void *from, __kernel_size_t size)
-{
-	if (__builtin_constant_p(size)) {
-		if (!size) return 0;
-		if (size < 16)
-			return __memcpy_short(to,(const void *)from,size,ASI_BLK_S,ASI_BLK_P);
-		else if (size < 384)
-			return __memcpy_16plus(to,(const void *)from,size,ASI_BLK_S,ASI_BLK_P);
-		else
-			return __memcpy_386plus(to,(const void *)from,size,ASI_BLK_S,ASI_BLK_P);
-	} else {
-		if (!size) return 0;
-		return __memcpy_entry(to,(const void *)from,size,ASI_BLK_S,ASI_BLK_P);
-	}
-}
-#else
-extern __kernel_size_t __copy_from_user(void *to, const void *from, __kernel_size_t size);
-extern __kernel_size_t __copy_to_user(void *to, const void *from, __kernel_size_t size);
-#endif
+extern __kernel_size_t __copy_to_user(void *to, const void *from,
+				      __kernel_size_t size);
+
+extern __kernel_size_t __copy_in_user(void *to, const void *from,
+				      __kernel_size_t size);
+
+#define copy_from_user(to,from,n)		\
+	__copy_from_user((void *)(to),	\
+		    (void *)(from), (__kernel_size_t)(n))
+
+#define copy_from_user_ret(to,from,n,retval) ({ \
+if (copy_from_user(to,from,n)) \
+	return retval; \
+})
+
+#define __copy_from_user_ret(to,from,n,retval) ({ \
+if (__copy_from_user(to,from,n)) \
+	return retval; \
+})
 
 #define copy_to_user(to,from,n) \
 	__copy_to_user((void *)(to), \
@@ -311,17 +308,17 @@
 	return retval; \
 })
 
-#define copy_from_user(to,from,n)		\
-	__copy_from_user((void *)(to),	\
-		    (void *)(from), (__kernel_size_t)(n))
+#define copy_in_user(to,from,n) \
+	__copy_in_user((void *)(to), \
+	(void *) (from), (__kernel_size_t)(n))
 
-#define copy_from_user_ret(to,from,n,retval) ({ \
-if (copy_from_user(to,from,n)) \
+#define copy_in_user_ret(to,from,n,retval) ({ \
+if (copy_in_user(to,from,n)) \
 	return retval; \
 })
 
-#define __copy_from_user_ret(to,from,n,retval) ({ \
-if (__copy_from_user(to,from,n)) \
+#define __copy_in_user_ret(to,from,n,retval) ({ \
+if (__copy_in_user(to,from,n)) \
 	return retval; \
 })
 
diff -u --recursive --new-file v2.1.44/linux/include/linux/binfmts.h linux/include/linux/binfmts.h
--- v2.1.44/linux/include/linux/binfmts.h	Mon Jul  7 08:24:28 1997
+++ linux/include/linux/binfmts.h	Sun Jul 13 21:20:10 1997
@@ -19,12 +19,11 @@
 	unsigned long p;
 	int sh_bang;
 	int java;		/* Java binary, prevent recursive invocation */
-	struct inode * inode;
+	struct dentry * dentry;
 	int e_uid, e_gid;
 	int argc, envc;
 	char * filename;	/* Name of binary */
 	unsigned long loader, exec;
-	int dont_iput;		/* binfmt handler has put inode */
 };
 
 /*
@@ -42,10 +41,10 @@
 extern int register_binfmt(struct linux_binfmt *);
 extern int unregister_binfmt(struct linux_binfmt *);
 
-extern int read_exec(struct inode *inode, unsigned long offset,
+extern int read_exec(struct dentry *, unsigned long offset,
 	char * addr, unsigned long count, int to_kmem);
 
-extern int open_inode(struct inode * inode, int mode);
+extern int open_dentry(struct dentry *, int mode);
 
 extern int init_elf_binfmt(void);
 extern int init_elf32_binfmt(void);
diff -u --recursive --new-file v2.1.44/linux/include/linux/cyclades.h linux/include/linux/cyclades.h
--- v2.1.44/linux/include/linux/cyclades.h	Tue May 13 22:41:18 1997
+++ linux/include/linux/cyclades.h	Thu Jul 10 11:22:04 1997
@@ -1,4 +1,4 @@
-/* $Revision: 1.7 $$Date: 1997/03/26 10:30:00 $
+/* $Revision: 2.0 $$Date: 1997/06/30 10:30:00 $
  * linux/include/linux/cyclades.h
  *
  * This file is maintained by Marcio Saito <marcio@cyclades.com> and
@@ -6,6 +6,14 @@
  *
  * This file contains the general definitions for the cyclades.c driver
  *$Log: cyclades.h,v $
+ *Revision 2.0  1997/06/30 10:30:00  ivan
+ *added some new doorbell command constants related to IOCTLW and
+ *UART error signaling
+ *
+ *Revision 1.8  1997/06/03 15:30:00  ivan
+ *added constant ZFIRM_HLT
+ *added constant CyPCI_Ze_win ( = 2 * Cy_PCI_Zwin)
+ *
  *Revision 1.7  1997/03/26 10:30:00  daniel
  *new entries at the end of cyclades_port struct to reallocate
  *variables illegally allocated within card memory.
@@ -86,6 +94,8 @@
  */
 
 #define	DP_WINDOW_SIZE		(0x00080000)	/* window size 512 Kb */
+#define	ZE_DP_WINDOW_SIZE	(0x00100000)	/* window size 1 Mb (Ze and
+						  8Zo V.2 */
 #define	CTRL_WINDOW_SIZE	(0x00000100)	/* runtime regs 256 bytes */
 
 /*
@@ -183,6 +193,7 @@
 
 #define ID_ADDRESS	0x00000180L	/* signature/pointer address */
 #define	ZFIRM_ID	0x5557465AL	/* ZFIRM/U signature */
+#define	ZFIRM_HLT	0x59505B5CL	/* ZFIRM needs external power supply */
 struct	FIRM_ID {
 	uclong	signature;		/* ZFIRM/U signature */
 	uclong	zfwctrl_addr;		/* pointer to ZFW_CTRL structure */
@@ -238,7 +249,10 @@
 #define	C_IN_RXBRK	0x00001000	/* Break received */
 #define	C_IN_PR_ERROR	0x00002000	/* parity error */
 #define	C_IN_FR_ERROR	0x00004000	/* frame error */
-
+#define C_IN_OVR_ERROR  0x00008000      /* overrun error */
+#define C_IN_RXOFL	0x00010000      /* RX buffer overflow */
+#define C_IN_IOCTLW	0x00020000      /* I/O control w/ wait */
+ 
 /* flow control */
 
 #define	C_FL_OXX	0x00000001	/* output Xon/Xoff flow control */
@@ -294,6 +308,8 @@
 #define	C_CM_RXBRK	0x84		/* Break received */
 #define	C_CM_PR_ERROR	0x85		/* Parity error */
 #define	C_CM_FR_ERROR	0x86		/* Frame error */
+#define C_CM_OVR_ERROR  0x87            /* Overrun error */
+#define C_CM_RXOFL	0x88            /* RX buffer overflow */
 #define	C_CM_CMDERROR	0x90		/* command error */
 #define	C_CM_FATAL	0x91		/* fatal error */
 #define	C_CM_HW_RESET	0x92		/* reset board */
@@ -468,9 +484,10 @@
 
 #define CyMaxChipsPerCard 8
 
-#define CyPCI_Ywin 0x4000
-#define CyPCI_Zctl 0x100
-#define CyPCI_Zwin 0x80000
+#define CyPCI_Ywin 	0x4000
+#define CyPCI_Zctl 	0x100
+#define CyPCI_Zwin 	0x80000
+#define CyPCI_Ze_win 	(2 * CyPCI_Zwin)
 
 /**** CD1400 registers ****/
 
diff -u --recursive --new-file v2.1.44/linux/include/linux/dalloc.h linux/include/linux/dalloc.h
--- v2.1.44/linux/include/linux/dalloc.h	Mon Jul  7 14:57:40 1997
+++ linux/include/linux/dalloc.h	Wed Dec 31 16:00:00 1969
@@ -1,145 +0,0 @@
-#ifndef DALLOC_H
-#define DALLOC_H
-/*
- * $Id: dalloc.h,v 1.3 1997/06/13 04:39:34 davem Exp $
- *
- * include/linux/dalloc.h - alloc routines for dcache
- * alloc / free space for pathname strings
- * Copyright (C) 1997, Thomas Schoebel-Theuer,
- * <schoebel@informatik.uni-stuttgart.de>.
- */
-
-#define D_MAXLEN 1024
-
-/* public flags for d_add() */
-#define D_NORMAL	  0
-#define D_BASKET	  1 /* put into basket (deleted/unref'd files) */
-#define D_DUPLICATE	  2 /* allow duplicate entries */
-#define D_NOCHECKDUP	  4 /* no not check for duplicates */
-#define D_NEGATIVE	  8 /* negative entry */
-#define D_PRELOADED	 16
-#define D_DIR		 32 /* directory entry - look out for allocation issues */
-#define D_HASHED	 64
-#define D_ZOMBIE	128
-#define D_INC_DDIR	512
-
-/* public flags for d_del() */
-#define D_REMOVE         0
-#define D_NO_CLEAR_INODE 1
-
-#define IS_ROOT(x) ((x) == (x)->d_parent)
-
-/* "quick string" -- I introduced this to shorten the parameter list
- * of many routines. Think of it as a (str,stlen,hash) pair.
- * Storing the len instead of doing strlen() very often is performance
- * critical.
- */
-struct qstr {
-	const unsigned char * name;
-	int len, hash;
-};
-
-/* Name hashing routines. Initial hash value */
-#define init_name_hash()		0
-
-/* partial hash update function. Assume roughly 4 bits per character */
-static inline unsigned long partial_name_hash(unsigned char c, unsigned long prevhash)
-{
-	prevhash = (prevhash << 4) | (prevhash >> (8*sizeof(unsigned long)-4));
-	return prevhash ^ c;
-}
-
-/* Finally: cut down the number of bits to a int value (and try to avoid losing bits) */
-static inline unsigned long end_name_hash(unsigned long hash)
-{
-	if (sizeof(hash) > sizeof(unsigned int))
-		hash += hash >> 4*sizeof(hash);
-	return (unsigned int) hash;
-}
-
-struct dentry {
-	unsigned int d_flag;
-	unsigned int d_count;
-	struct inode  * d_inode;	/* Where the name belongs to */
-	struct dentry * d_parent;	/* parent directory */
-	struct dentry * d_mounts;	/* mount information */
-	struct dentry * d_covers;
-	struct dentry * d_next;		/* hardlink aliasname / empty list */
-	struct dentry * d_prev;		/* hardlink aliasname */
-	struct dentry * d_hash_next;
-	struct dentry * d_hash_prev;
-	struct dentry * d_basket_next;
-	struct dentry * d_basket_prev;
-	struct qstr d_name;
-};
-
-extern struct dentry * the_root;
-
-/*
- * These are the low-level FS interfaces to the dcache..
- */
-extern void d_instantiate(struct dentry *, struct inode *, int);
-extern void d_delete(struct dentry *);
-
-
-/* Note that all these routines must be called with vfs_lock() held */
-
-/* get inode, if necessary retrieve it with iget() */
-extern blocking struct inode * d_inode(struct dentry ** changing_entry);
-
-/* allocate/de-allocate */
-extern void d_free(struct dentry *);
-extern struct dentry * d_alloc(struct dentry * parent, struct qstr *name, int isdir);
-
-/* only used at mount-time */
-extern blocking
-struct dentry * d_alloc_root(struct inode * root_inode, struct dentry * old_root);
-
-/*
- * This adds the entry to the hash queues and initializes "d_inode".
- * The entry was actually filled in earlier during "d_alloc()"
- */
-extern blocking
-void d_add(struct dentry * entry, struct inode * inode, int flags);
-
-/* combination of d_alloc() and d_add(), less lookup overhead */
-extern blocking 
-struct dentry * d_entry(struct dentry * parent, struct qstr * name, struct inode * inode);
-extern blocking
-void d_entry_preliminary(struct dentry * parent, struct qstr * name, unsigned long ino);
-
-/* recursive d_del() all successors */
-extern blocking
-void d_del(struct dentry * entry, int flags);
-
-/* used for rename() and baskets */
-extern blocking 
-void d_move(struct dentry * entry, struct dentry * newparent, struct qstr * newname);
-
-/* appendix may either be NULL or be used for transname suffixes */
-extern struct dentry * d_lookup(struct dentry * dir, struct qstr * name);
-
-/* write full pathname into buffer and return length */
-extern int d_path(struct dentry * entry, struct dentry * chroot, char * buf);
-
-extern struct dentry * d_basket(struct dentry * dir_entry);
-
-extern int d_isbasket(struct dentry * entry);
-
-/*
- * Whee..
- */
-static inline void dput(struct dentry *dentry)
-{
-	if (dentry)
-		dentry->d_count--;
-}
-
-static inline struct dentry * dget(struct dentry *dentry)
-{
-	if (dentry)
-		dentry->d_count++;
-	return dentry;
-}
-
-#endif
diff -u --recursive --new-file v2.1.44/linux/include/linux/dcache.h linux/include/linux/dcache.h
--- v2.1.44/linux/include/linux/dcache.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/dcache.h	Wed Jul 16 07:50:16 1997
@@ -0,0 +1,122 @@
+#ifndef __LINUX_DCACHE_H
+#define __LINUX_DCACHE_H
+
+/*
+ * linux/include/linux/dcache.h
+ *
+ * Directory cache data structures
+ */
+
+#define D_MAXLEN 1024
+
+#define IS_ROOT(x) ((x) == (x)->d_parent)
+
+/*
+ * "quick string" -- eases parameter passing, but more importantly
+ * saves "metadata" about the string (ie length and the hash).
+ */
+struct qstr {
+	const unsigned char * name;
+	unsigned int len, hash;
+};
+
+/* Name hashing routines. Initial hash value */
+#define init_name_hash()		0
+
+/* partial hash update function. Assume roughly 4 bits per character */
+static inline unsigned long partial_name_hash(unsigned char c, unsigned long prevhash)
+{
+	prevhash = (prevhash << 4) | (prevhash >> (8*sizeof(unsigned long)-4));
+	return prevhash ^ c;
+}
+
+/* Finally: cut down the number of bits to a int value (and try to avoid losing bits) */
+static inline unsigned long end_name_hash(unsigned long hash)
+{
+	if (sizeof(hash) > sizeof(unsigned int))
+		hash += hash >> 4*sizeof(hash);
+	return (unsigned int) hash;
+}
+
+struct dentry {
+	int d_count;
+	unsigned int d_flags;
+	struct inode  * d_inode;	/* Where the name belongs to - NULL is negative */
+	struct dentry * d_parent;	/* parent directory */
+	struct dentry * d_mounts;	/* mount information */
+	struct dentry * d_covers;
+	struct list_head d_hash;	/* lookup hash list */
+	struct list_head d_alias;	/* inode alias list */
+	struct list_head d_lru;		/* d_count = 0 LRU list */
+	struct qstr d_name;
+	struct dentry * (*d_revalidate)(struct dentry *);
+};
+
+/*
+ * d_drop() unhashes the entry from the parent
+ * dentry hashes, so that it won't be found through
+ * a VFS lookup any more. Note that this is different
+ * from deleting the dentry - d_delete will try to
+ * mark the dentry negative if possible, giving a
+ * successful _negative_ lookup, while d_drop will
+ * just make the cache lookup fail.
+ *
+ * d_drop() is used mainly for stuff that wants
+ * to invalidate a dentry for some reason (NFS
+ * timeouts or autofs deletes).
+ */
+static inline void d_drop(struct dentry * dentry)
+{
+	list_del(&dentry->d_hash);
+	INIT_LIST_HEAD(&dentry->d_hash);
+}
+
+/*
+ * These are the low-level FS interfaces to the dcache..
+ */
+extern void d_instantiate(struct dentry *, struct inode *);
+extern void d_delete(struct dentry *);
+
+
+/* allocate/de-allocate */
+extern void d_free(struct dentry *);
+extern struct dentry * d_alloc(struct dentry * parent, const struct qstr *name);
+extern void shrink_dcache(void);
+
+/* only used at mount-time */
+extern struct dentry * d_alloc_root(struct inode * root_inode, struct dentry * old_root);
+
+/*
+ * This adds the entry to the hash queues and initializes "d_inode".
+ * The entry was actually filled in earlier during "d_alloc()"
+ */
+extern void d_add(struct dentry * entry, struct inode * inode);
+
+/* used for rename() and baskets */
+extern void d_move(struct dentry * entry, struct dentry * newparent, struct qstr * newname);
+
+/* appendix may either be NULL or be used for transname suffixes */
+extern struct dentry * d_lookup(struct dentry * dir, struct qstr * name);
+
+/* write full pathname into buffer and return length */
+extern int d_path(struct dentry * entry, struct dentry * chroot, char * buf);
+
+/* Allocation counts.. */
+static inline struct dentry * dget(struct dentry *dentry)
+{
+	if (dentry)
+		dentry->d_count++;
+	return dentry;
+}
+
+extern void dput(struct dentry *);
+
+/*
+ * This is ugly. The inode:dentry relationship is a 1:n
+ * relationship, so we have to return one (random) dentry
+ * from the alias list. We select the first one..
+ */
+#define i_dentry(inode) \
+	list_entry((inode)->i_dentry.next, struct dentry, d_alias)
+
+#endif	/* __LINUX_DCACHE_H */
diff -u --recursive --new-file v2.1.44/linux/include/linux/ext2_fs.h linux/include/linux/ext2_fs.h
--- v2.1.44/linux/include/linux/ext2_fs.h	Mon Jul  7 11:28:47 1997
+++ linux/include/linux/ext2_fs.h	Wed Jul 16 14:01:06 1997
@@ -483,6 +483,7 @@
 extern void ext2_read_inode (struct inode *);
 extern void ext2_write_inode (struct inode *);
 extern void ext2_put_inode (struct inode *);
+extern void ext2_delete_inode (struct inode *);
 extern int ext2_sync_inode (struct inode *);
 extern void ext2_discard_prealloc (struct inode *);
 
@@ -492,7 +493,7 @@
 
 /* namei.c */
 extern void ext2_release (struct inode *, struct file *);
-extern int ext2_lookup (struct inode *,struct qstr *, struct inode **);
+extern int ext2_lookup (struct inode *, struct dentry *);
 extern int ext2_create (struct inode *,struct dentry *,int);
 extern int ext2_mkdir (struct inode *,struct dentry *,int);
 extern int ext2_rmdir (struct inode *,struct dentry *);
@@ -515,7 +516,7 @@
 extern int ext2_remount (struct super_block *, int *, char *);
 extern struct super_block * ext2_read_super (struct super_block *,void *,int);
 extern int init_ext2_fs(void);
-extern void ext2_statfs (struct super_block *, struct statfs *, int);
+extern int ext2_statfs (struct super_block *, struct statfs *, int);
 
 /* truncate.c */
 extern void ext2_truncate (struct inode *);
diff -u --recursive --new-file v2.1.44/linux/include/linux/file.h linux/include/linux/file.h
--- v2.1.44/linux/include/linux/file.h	Tue May 13 22:41:18 1997
+++ linux/include/linux/file.h	Sun Jul 13 21:20:10 1997
@@ -12,7 +12,7 @@
 	return file;
 }
 
-extern int __fput(struct file *, struct inode *);
+extern int __fput(struct file *);
 extern void insert_file_free(struct file *file);
 
 /* It does not matter which list it is on. */
@@ -23,13 +23,13 @@
 	*file->f_pprev = file->f_next;
 }
 
-extern inline int fput(struct file *file, struct inode *inode)
+extern inline int fput(struct file *file)
 {
 	int count = file->f_count-1;
 	int error = 0;
 
 	if (!count) {
-		error = __fput(file, inode);
+		error = __fput(file);
 		file->f_count = 0;
 		remove_filp(file);
 		insert_file_free(file);
diff -u --recursive --new-file v2.1.44/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.1.44/linux/include/linux/fs.h	Mon Jul  7 16:02:01 1997
+++ linux/include/linux/fs.h	Wed Jul 16 20:16:33 1997
@@ -15,16 +15,13 @@
 #include <linux/net.h>
 #include <linux/kdev_t.h>
 #include <linux/ioctl.h>
+#include <linux/list.h>
+#include <linux/dcache.h>
 
 #include <asm/atomic.h>
 #include <asm/bitops.h>
 
-/* Prefixes for routines (having no effect), but indicate what
- * the routine may do. This can greatly ease reasoning about routines...
- */
-#define blocking /*routine may schedule()*/
 
-#include <linux/dalloc.h>
 
 /*
  * It's silly to have NR_OPEN bigger than NR_FILE, but I'll fix
@@ -78,9 +75,6 @@
 			   */
 #define FS_IBASKET      8 /* FS does callback to free_ibasket() if space gets low. */
 
-/* public flags for i_status */
-#define ST_MODIFIED 1024
-
 /*
  * These are the fs-independent mount-flags: up to 16 flags are supported
  */
@@ -126,7 +120,12 @@
 #define IS_APPEND(inode) ((inode)->i_flags & S_APPEND)
 #define IS_IMMUTABLE(inode) ((inode)->i_flags & S_IMMUTABLE)
 #define IS_NOATIME(inode) ((inode)->i_flags & MS_NOATIME)
-#define DO_UPDATE_ATIME(inode) (!IS_NOATIME(inode) && !IS_RDONLY(inode))
+
+#define UPDATE_ATIME(inode) \
+	if (!IS_NOATIME(inode) && !IS_RDONLY(inode)) { \
+		inode->i_atime = CURRENT_TIME; \
+		mark_inode_dirty(inode); \
+	}
 
 /* the read-only stuff doesn't really belong here, but any other place is
    probably as bad and I don't want to create yet another include file. */
@@ -152,7 +151,7 @@
 extern void buffer_init(void);
 extern void inode_init(void);
 extern void file_table_init(void);
-extern unsigned long name_cache_init(unsigned long start, unsigned long end);
+extern void dcache_init(void);
 
 typedef char buffer_block[BLOCK_SIZE];
 
@@ -300,14 +299,12 @@
 #include <linux/quota.h>
 
 struct inode {
-	struct inode 		*i_hash_next;
-	struct inode		*i_hash_prev;
-	struct inode		*i_next;
-	struct inode		*i_prev;
+	struct list_head	i_hash;
+	struct list_head	i_list;
 
 	unsigned long		i_ino;
 	kdev_t			i_dev;
-	atomic_t		i_count;
+	unsigned short		i_count;
 	umode_t			i_mode;
 	nlink_t			i_nlink;
 	uid_t			i_uid;
@@ -330,25 +327,14 @@
 	struct page		*i_pages;
 	struct dquot		*i_dquot[MAXQUOTAS];
 
-	struct inode		*i_lru_next;
-	struct inode		*i_lru_prev;
-
-	struct inode		*i_basket_next;
-	struct inode		*i_basket_prev;
-	struct dentry		*i_dentry;
+	struct list_head	i_dentry;
 
-	unsigned short		i_status;
-	unsigned short		i_reuse_count;
+	unsigned long		i_state;
 
 	unsigned int		i_flags;
-	unsigned char		i_lock;
-	unsigned char		i_dirt;
 	unsigned char		i_pipe;
 	unsigned char		i_sock;
 
-	unsigned char		i_level;
-	unsigned short		i_fill;
-
 	int			i_writecount;
 	unsigned int		i_attr_flags;
 	union {
@@ -369,9 +355,21 @@
 	} u;
 };
 
+/* Inode state bits.. */
+#define I_DIRTY		0
+#define I_LOCK		1
+#define I_FREEING	2
+
+extern void __mark_inode_dirty(struct inode *);
+static inline void mark_inode_dirty(struct inode *inode)
+{
+	if (!test_and_set_bit(I_DIRTY, &inode->i_state))
+		__mark_inode_dirty(inode);
+}
+
 struct file {
 	struct file		*f_next, **f_pprev;
-	struct inode		*f_inode;
+	struct dentry		*f_dentry;
 	struct file_operations	*f_op;
 	mode_t			f_mode;
 	loff_t			f_pos;
@@ -545,7 +543,7 @@
 struct inode_operations {
 	struct file_operations * default_file_ops;
 	int (*create) (struct inode *,struct dentry *,int);
-	int (*lookup) (struct inode *,struct qstr *name,struct inode **);
+	int (*lookup) (struct inode *,struct dentry *);
 	int (*link) (struct inode *,struct inode *,struct dentry *);
 	int (*unlink) (struct inode *,struct dentry *);
 	int (*symlink) (struct inode *,struct dentry *,const char *);
@@ -568,12 +566,13 @@
 
 struct super_operations {
 	void (*read_inode) (struct inode *);
-	int (*notify_change) (struct inode *, struct iattr *);
 	void (*write_inode) (struct inode *);
 	void (*put_inode) (struct inode *);
+	void (*delete_inode) (struct inode *);
+	int (*notify_change) (struct inode *, struct iattr *);
 	void (*put_super) (struct super_block *);
 	void (*write_super) (struct super_block *);
-	void (*statfs) (struct super_block *, struct statfs *, int);
+	int (*statfs) (struct super_block *, struct statfs *, int);
 	int (*remount_fs) (struct super_block *, int *, char *);
 };
 
@@ -602,7 +601,7 @@
 
 extern void kill_fasync(struct fasync_struct *fa, int sig);
 
-extern int getname(const char * filename, char **result);
+extern char * getname(const char * filename);
 extern void putname(char * name);
 extern int do_truncate(struct inode *, unsigned long);
 extern int register_blkdev(unsigned int, const char *, struct file_operations *);
@@ -632,8 +631,8 @@
 extern struct file_system_type *get_fs_type(const char *name);
 
 extern int fs_may_mount(kdev_t dev);
-extern int fs_may_umount(kdev_t dev, struct dentry * root);
-extern int fs_may_remount_ro(kdev_t dev);
+extern int fs_may_umount(struct super_block *, struct dentry * root);
+extern int fs_may_remount_ro(struct super_block *);
 
 extern struct file *inuse_filps;
 extern struct super_block super_blocks[NR_SUPER];
@@ -684,9 +683,8 @@
 extern int permission(struct inode * inode,int mask);
 extern int get_write_access(struct inode *inode);
 extern void put_write_access(struct inode *inode);
-extern int open_namei(const char * pathname, int flag, int mode,
-	struct inode ** res_inode, struct dentry * base);
-extern int do_mknod(const char * filename, int mode, dev_t dev);
+extern struct dentry * open_namei(const char * pathname, int flag, int mode);
+extern struct dentry * do_mknod(const char * filename, int mode, dev_t dev);
 extern int do_pipe(int *);
 
 /*
@@ -702,10 +700,10 @@
 #define IS_ERR(ptr)	((unsigned long)(ptr) > (unsigned long)(-1000))
 
 extern struct dentry * lookup_dentry(const char *, struct dentry *, int);
-extern int __namei(const char *, struct inode **, int);
+extern struct dentry * __namei(const char *, int);
 
-#define namei(pathname, inode_p)	__namei(pathname, inode_p, 1)
-#define lnamei(pathname, inode_p)	__namei(pathname, inode_p, 0)
+#define namei(pathname)		__namei(pathname, 1)
+#define lnamei(pathname)	__namei(pathname, 0)
 
 #include <asm/semaphore.h>
 
@@ -735,50 +733,19 @@
 
 /* Not to be used by ordinary vfs users */
 extern void _get_inode(struct inode * inode);
-extern blocking void __iput(struct inode * inode);
-
-extern blocking void _iput(struct inode * inode);
-extern inline blocking void iput(struct inode * inode)
-{
-	if (inode) {
-		extern void wake_up_interruptible(struct wait_queue **q);
+extern void iput(struct inode * inode);
 
-		if (inode->i_pipe)
-			wake_up_interruptible(&inode->u.pipe_i.wait);
-
-		/* It does not matter if somebody re-increments it in between,
-		 * only the _last_ user needs to call _iput().
-		 */
-		if (atomic_dec_and_test(&inode->i_count))
-			_iput(inode);
-	}
-}
+extern struct inode * iget(struct super_block * sb, unsigned long nr);
+extern void clear_inode(struct inode * inode);
+extern struct inode * get_empty_inode(void);
 
-extern blocking struct inode * iget(struct super_block * sb, unsigned long nr);
-extern blocking void _clear_inode(struct inode * inode, int external, int verbose);
-extern blocking inline void clear_inode(struct inode * inode)
-{
-	vfs_lock();
-	_clear_inode(inode, 1, 1);
-	vfs_unlock();
-}
-extern blocking struct inode * _get_empty_inode(void);
-extern inline blocking struct inode * get_empty_inode(void)
-{
-	struct inode * inode;
-	vfs_lock();
-	inode = _get_empty_inode();
-	vfs_unlock();
-	return inode;
-}
 /* Please prefer to use this function in future, instead of using
  * a get_empty_inode()/insert_inode_hash() combination.
  * It allows for better checking and less race conditions.
  */
-blocking struct inode * get_empty_inode_hashed(dev_t i_dev, unsigned long i_ino);
+extern struct inode * get_empty_inode_hashed(dev_t i_dev, unsigned long i_ino);
 
 extern void insert_inode_hash(struct inode *);
-extern blocking struct inode * get_pipe_inode(void);
 extern int get_unused_fd(void);
 extern void put_unused_fd(int);
 extern struct file * get_empty_filp(void);
diff -u --recursive --new-file v2.1.44/linux/include/linux/if_shaper.h linux/include/linux/if_shaper.h
--- v2.1.44/linux/include/linux/if_shaper.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/if_shaper.h	Wed Jul 16 19:22:51 1997
@@ -0,0 +1,61 @@
+#ifndef __LINUX_SHAPER_H
+#define __LINUX_SHAPER_H
+
+#ifdef __KERNEL__
+
+#define SHAPER_QLEN	10
+/*
+ *	This is a bit speed dependant (read it shouldnt be a constant!)
+ *
+ *	5 is about right for 28.8 upwards. Below that double for every
+ *	halving of speed or so. - ie about 20 for 9600 baud.
+ */
+#define SHAPER_LATENCY	(5*HZ)
+#define SHAPER_MAXSLIP	2
+#define SHAPER_BURST	(HZ/50)		/* Good for >128K then */
+
+struct shaper
+{
+	struct sk_buff_head sendq;
+	__u32 bytespertick;
+	__u32 shapelatency;
+	__u32 shapeclock;
+	__u32 recovery;		/* Time we can next clock a packet out on
+				   an empty queue */
+	char locked;
+	struct device *dev;
+	int  (*hard_start_xmit) (struct sk_buff *skb,
+		struct device *dev);
+	int  (*hard_header) (struct sk_buff *skb,
+		struct device *dev,
+		unsigned short type,
+		void *daddr,
+		void *saddr,
+		unsigned len);
+	int  (*rebuild_header)(struct sk_buff *skb);
+	int (*hard_header_cache)(struct dst_entry *dst, struct neighbour *neigh,
+		struct hh_cache *hh);
+	void (*header_cache_update)(struct hh_cache *hh, struct device *dev, unsigned char *  haddr);
+	struct net_device_stats* (*get_stats)(struct device *dev);
+	struct wait_queue *wait_queue;
+	struct timer_list timer;
+};
+
+#endif
+
+#define SHAPER_SET_DEV		0x0001
+#define SHAPER_SET_SPEED	0x0002
+
+struct shaperconf
+{
+	__u16	ss_cmd;
+	union
+	{
+		char 	ssu_name[14];
+		__u32	ssu_speed;
+	} ss_u;
+#define ss_speed ss_u.ssu_speed
+#define ss_name ss_u.ssu_name
+};
+
+#endif
diff -u --recursive --new-file v2.1.44/linux/include/linux/iso_fs.h linux/include/linux/iso_fs.h
--- v2.1.44/linux/include/linux/iso_fs.h	Thu Feb  6 02:57:47 1997
+++ linux/include/linux/iso_fs.h	Wed Jul 16 14:19:15 1997
@@ -152,8 +152,7 @@
 
 extern int isofs_open(struct inode * inode, struct file * filp);
 extern void isofs_release(struct inode * inode, struct file * filp);
-extern int isofs_lookup(struct inode * dir,const char * name, int len,
-			struct inode ** result);
+extern int isofs_lookup(struct inode * dir, struct dentry *);
 extern unsigned long isofs_count_free_inodes(struct super_block *sb);
 extern int isofs_new_block(int dev);
 extern int isofs_free_block(int dev, int block);
@@ -164,7 +163,7 @@
 extern int init_iso9660_fs(void);
 extern void isofs_read_inode(struct inode *);
 extern void isofs_put_inode(struct inode *);
-extern void isofs_statfs(struct super_block *, struct statfs *, int);
+extern int isofs_statfs(struct super_block *, struct statfs *, int);
 
 extern int isofs_lseek(struct inode *, struct file *, off_t, int);
 extern int isofs_read(struct inode *, struct file *, char *, int);
diff -u --recursive --new-file v2.1.44/linux/include/linux/iso_fs_i.h linux/include/linux/iso_fs_i.h
--- v2.1.44/linux/include/linux/iso_fs_i.h	Wed Dec  1 04:44:15 1993
+++ linux/include/linux/iso_fs_i.h	Wed Jul 16 10:26:21 1997
@@ -6,7 +6,6 @@
  */
 struct iso_inode_info {
 	unsigned int i_first_extent;
-	unsigned int i_backlink;
 	unsigned char i_file_format;
 };
 
diff -u --recursive --new-file v2.1.44/linux/include/linux/joystick.h linux/include/linux/joystick.h
--- v2.1.44/linux/include/linux/joystick.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/joystick.h	Wed Jul 16 19:22:51 1997
@@ -0,0 +1,61 @@
+#ifndef _LINUX_JOYSTICK_H
+#define _LINUX_JOYSTICK_H
+
+#define JS_RETURN sizeof(struct js_status)	/*number of bytes returned by js_read*/
+#define JS_TRUE 1
+#define JS_FALSE 0
+#define JS_PORT 0x201		/*io port for joystick operations*/
+#define JS_DEF_TIMEOUT 0x1300	/*default timeout value for js_read()*/
+#define JS_DEF_CORR	0	/*default correction factor*/
+#define JS_DEF_TIMELIMIT 10L	/*default data valid time =10 jiffies == 100ms*/
+#define JS_X_0	0x01		/*bit mask for x-axis js0*/
+#define JS_Y_0	0x02		/*bit mask for y-axis js0*/
+#define JS_X_1	0x04		/*bit mask for x-axis js1*/
+#define JS_Y_1	0x08		/*bit mask for y-axis js1*/
+#define JS_MAX 2		/*Max number of joysticks*/
+#define PIT_MODE 0x43		/*io port for timer 0*/
+#define PIT_COUNTER_0 0x40	/*io port for timer 0*/
+#define JSIOCSCAL 0x01		/*ioctl cmd to set joystick correction factor*/
+#define JSIOCGCAL 0x02		/*ioctl cmd to get joystick correction factor*/
+#define JSIOCSTIMEOUT 0x03	/*ioctl cmd to set maximum number of iterations
+				  to wait for a timeout*/
+#define JSIOCGTIMEOUT		0x04	/*as above, to get*/
+#define JSIOCSTIMELIMIT	0x05	/*set data retention time*/
+#define JSIOCGTIMELIMIT	0x06	/*get data retention time*/
+#define JSIOCGCONFIG		0x07	/*get the whole js_data[minor] struct*/
+#define JSIOCSCONFIG		0x08	/*set the whole js_data[minor] struct
+						  except js_busy!*/
+
+/*
+ *	This union is used for the ioctl to set the scaling factor and to 
+ *	return the current values for a joystick. 'buttons' is ignored on
+ *	the ioctl call
+ */
+
+struct js_status 
+{
+	int buttons;
+	int x;
+	int y;
+};
+
+/*
+ *	This struct is used for misc data about the joystick
+ */
+
+struct js_config 
+{
+	int js_timeout;		/*timeout*/
+	int busy;		/*joystick is in use*/
+	long js_expiretime;	/*Time when stick after which stick must be re-read*/
+	long js_timelimit;	/*Max time before data is invalid*/
+	struct js_status js_save;	/*last read data*/
+	struct js_status js_corr;	/*correction factor*/
+};
+
+#define LATCH (1193180L/HZ)	/*initial timer 0 value*/
+#define DELTA_TIME(X,Y) ((X)-(Y)+(((X)>=(Y))?0:LATCH))
+
+extern int joystick_init(void);
+
+#endif /* _LINUX_JOYSTICK_H */
diff -u --recursive --new-file v2.1.44/linux/include/linux/list.h linux/include/linux/list.h
--- v2.1.44/linux/include/linux/list.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/list.h	Sun Jul 13 21:20:10 1997
@@ -0,0 +1,63 @@
+#ifndef _LINUX_LIST_H
+#define _LINUX_LIST_H
+
+/*
+ * Simple doubly linked list implementation.
+ */
+struct list_head {
+	struct list_head *next, *prev;
+};
+
+#define LIST_HEAD(name) \
+	struct list_head name = { &name, &name }
+
+#define INIT_LIST_HEAD(ptr) do { \
+	(ptr)->next = (ptr); (ptr)->prev = (ptr); \
+} while (0)
+
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+	struct list_head *next = head->next;
+	next->prev = new;
+	new->next = next;
+	new->prev = head;
+	head->next = new;
+}
+
+static inline void list_del(struct list_head *entry)
+{
+	struct list_head *next, *prev;
+	next = entry->next;
+	prev = entry->prev;
+	next->prev = prev;
+	prev->next = next;
+}
+
+static inline int list_empty(struct list_head *head)
+{
+	return head->next == head;
+}
+
+/*
+ * Splice in "list" into "head"
+ */
+static inline void list_splice(struct list_head *list, struct list_head *head)
+{
+	struct list_head *first = list->next;
+
+	if (first != list) {
+		struct list_head *last = list->prev;
+		struct list_head *at = head->next;
+
+		first->prev = head;
+		head->next = first;
+
+		last->next = at;
+		at->prev = last;
+	}
+}
+
+#define list_entry(ptr, type, member) \
+	((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
+
+#endif
diff -u --recursive --new-file v2.1.44/linux/include/linux/lockd/lockd.h linux/include/linux/lockd/lockd.h
--- v2.1.44/linux/include/linux/lockd/lockd.h	Mon Jul  7 16:03:34 1997
+++ linux/include/linux/lockd/lockd.h	Wed Jul 16 20:17:48 1997
@@ -166,7 +166,7 @@
 extern __inline__ struct inode *
 nlmsvc_file_inode(struct nlm_file *file)
 {
-	return file->f_file.f_inode;
+	return file->f_file.f_dentry->d_inode;
 }
 
 /*
diff -u --recursive --new-file v2.1.44/linux/include/linux/minix_fs.h linux/include/linux/minix_fs.h
--- v2.1.44/linux/include/linux/minix_fs.h	Mon Jun 16 16:36:00 1997
+++ linux/include/linux/minix_fs.h	Wed Jul 16 08:08:05 1997
@@ -88,19 +88,18 @@
 
 #ifdef __KERNEL__
 
-extern int minix_lookup(struct inode * dir,const char * name, int len,
+extern int minix_lookup(struct inode * dir, struct qstr *name,
                         struct inode ** result);
-extern int minix_create(struct inode * dir,const char * name, int len, int mode,
-	struct inode ** result);
-extern int minix_mkdir(struct inode * dir, const char * name, int len, int mode);
-extern int minix_rmdir(struct inode * dir, const char * name, int len);
-extern int minix_unlink(struct inode * dir, const char * name, int len);
-extern int minix_symlink(struct inode * inode, const char * name, int len,
+extern int minix_create(struct inode * dir, struct dentry *dentry, int mode);
+extern int minix_mkdir(struct inode * dir, struct dentry *dentry, int mode);
+extern int minix_rmdir(struct inode * dir, struct dentry *dentry);
+extern int minix_unlink(struct inode * dir, struct dentry *dentry);
+extern int minix_symlink(struct inode * inode, struct dentry *dentry,
 	const char * symname);
-extern int minix_link(struct inode * oldinode, struct inode * dir, const char * name, int len);
-extern int minix_mknod(struct inode * dir, const char * name, int len, int mode, int rdev);
-extern int minix_rename(struct inode * old_dir, const char * old_name, int old_len,
-			struct inode * new_dir, const char * new_name, int new_len);
+extern int minix_link(struct inode * oldinode, struct inode * dir, struct dentry *dentry);
+extern int minix_mknod(struct inode * dir, struct dentry *dentry, int mode, int rdev);
+extern int minix_rename(struct inode * old_dir, struct dentry *old_dentry,
+			struct inode * new_dir, struct dentry *new_dentry);
 extern struct inode * minix_new_inode(const struct inode * dir);
 extern void minix_free_inode(struct inode * inode);
 extern unsigned long minix_count_free_inodes(struct super_block *sb);
@@ -122,7 +121,7 @@
 extern void minix_read_inode(struct inode *);
 extern void minix_write_inode(struct inode *);
 extern void minix_put_inode(struct inode *);
-extern void minix_statfs(struct super_block *, struct statfs *, int);
+extern int minix_statfs(struct super_block *, struct statfs *, int);
 extern int minix_sync_inode(struct inode *);
 extern int minix_sync_file(struct inode *, struct file *);
 
diff -u --recursive --new-file v2.1.44/linux/include/linux/miscdevice.h linux/include/linux/miscdevice.h
--- v2.1.44/linux/include/linux/miscdevice.h	Fri Dec 13 01:37:47 1996
+++ linux/include/linux/miscdevice.h	Wed Jul 16 19:22:51 1997
@@ -8,6 +8,7 @@
 #define AMIGAMOUSE_MINOR 4
 #define ATARIMOUSE_MINOR 5
 #define SUN_MOUSE_MINOR 6
+#define PC110PAD_MINOR 9
 #define RTC_MINOR 135
 #define SUN_OPENPROM_MINOR 139
 #define MISC_DYNAMIC_MINOR 255
diff -u --recursive --new-file v2.1.44/linux/include/linux/mm.h linux/include/linux/mm.h
--- v2.1.44/linux/include/linux/mm.h	Mon Jul  7 16:02:03 1997
+++ linux/include/linux/mm.h	Wed Jul 16 20:16:33 1997
@@ -48,7 +48,7 @@
 
 	struct vm_operations_struct * vm_ops;
 	unsigned long vm_offset;
-	struct inode * vm_inode;
+	struct dentry * vm_dentry;
 	unsigned long vm_pte;			/* shared mem */
 };
 
@@ -118,7 +118,7 @@
 	unsigned long offset;
 	struct page *next_hash;
 	atomic_t count;
-	unsigned flags;	/* atomic flags, some possibly updated asynchronously */
+	unsigned long flags;	/* atomic flags, some possibly updated asynchronously */
 	unsigned dirty:16,
 		 age:8;
 	struct wait_queue *wait;
diff -u --recursive --new-file v2.1.44/linux/include/linux/msdos_fs.h linux/include/linux/msdos_fs.h
--- v2.1.44/linux/include/linux/msdos_fs.h	Mon Jul  7 16:03:54 1997
+++ linux/include/linux/msdos_fs.h	Wed Jul 16 20:18:04 1997
@@ -215,7 +215,7 @@
 extern void fat_read_inode(struct inode *inode, struct inode_operations *dir_ops);
 extern struct super_block *fat_read_super(struct super_block *s, void *data, int silent);
 extern void msdos_put_super(struct super_block *sb);
-extern void fat_statfs(struct super_block *sb,struct statfs *buf, int);
+extern int fat_statfs(struct super_block *sb,struct statfs *buf, int);
 extern void fat_write_inode(struct inode *inode);
 
 /* dir.c */
diff -u --recursive --new-file v2.1.44/linux/include/linux/nametrans.h linux/include/linux/nametrans.h
--- v2.1.44/linux/include/linux/nametrans.h	Mon Jul  7 14:57:52 1997
+++ linux/include/linux/nametrans.h	Wed Dec 31 16:00:00 1969
@@ -1,69 +0,0 @@
-#ifndef NAMETRANS_H
-#define NAMETRANS_H
-/*
- * $Id: nametrans.h,v 1.1 1997/06/04 08:26:57 davem Exp $
- *
- * include/linux/nametrans.h - context-dependend filename suffixes.
- * Copyright (C) 1997, Thomas Schoebel-Theuer,
- * <schoebel@informatik.uni-stuttgart.de>.
- */
-
-#include <linux/dalloc.h>
-#include <linux/sysctl.h>
-
-#define MAX_DEFAULT_TRANSLEN 128
-
-/* only filenames matching the following length restrictions can be
- * translated. I introduced these restrictions because they *greatly*
- * simplify buffer management (no need to allocate kernel pages and free them).
- * The maximal total length of a context-dependend filename is the
- * sum of both constants. */
-#define MAX_TRANS_FILELEN 128 /* max len of a name that could be translated */
-#define MAX_TRANS_SUFFIX   64 /* max len of a #keyword=value# suffix */
-
-/* max number of translations */
-#define MAX_TRANSLATIONS 16
-
-struct translations {
-	int count;
-	struct qstr name[MAX_TRANSLATIONS];
-	struct qstr c_name[MAX_TRANSLATIONS];
-};
-
-/* global/default translations */
-extern char nametrans_txt[MAX_DEFAULT_TRANSLEN];
-
-/* Any changer of a built-in translation must set this flag */
-extern int translations_dirty;
-
-
-/* called once at boot time */
-extern void init_nametrans(void);
-
-/* set global translations */
-extern void nametrans_setup(char * line);
-
-/* return reusable global buffer. needed by VFS. */
-struct translations * get_translations(char * env);
-
-/* if the _first_ environment variable is "NAMETRANS", return
- * a pointer to the list of appendices.
- * You can set the first environment variable using
- * 'env - NAMETRANS=... "`env`" command ...'
- */
-extern char * env_transl(void);
-
-/* if name has the correct suffix "#keyword=correct_context#",
- * return position of the suffix, else 0.
- */
-extern char* testname(int restricted, char* name);
-
-/* for use in kernel/sysctrl.h */
-extern int nametrans_dostring(ctl_table * table, int write, struct file * filp,
-			      void * buffer, size_t * lenp);
-extern int nametrans_string(ctl_table * table, int * name, int nlen,
-			    void * oldval, size_t * oldlenp,
-			    void * newval, size_t newlen, void ** context);
-
-
-#endif
diff -u --recursive --new-file v2.1.44/linux/include/linux/nfsd/nfsfh.h linux/include/linux/nfsd/nfsfh.h
--- v2.1.44/linux/include/linux/nfsd/nfsfh.h	Mon Jul  7 16:03:34 1997
+++ linux/include/linux/nfsd/nfsfh.h	Wed Jul 16 20:17:48 1997
@@ -57,7 +57,7 @@
 typedef struct svc_fh {
 	struct knfs_fh		fh_handle;	/* FH data */
 	struct svc_export *	fh_export;	/* export pointer */
-	struct inode *		fh_inode;	/* inode */
+	struct dentry *		fh_dentry;	/* file */
 	size_t			fh_pre_size;	/* size before operation */
 	time_t			fh_pre_mtime;	/* mtime before oper */
 	time_t			fh_pre_ctime;	/* ctime before oper */
@@ -98,7 +98,7 @@
 static inline void
 fh_lock(struct svc_fh *fhp)
 {
-	struct inode	*inode = fhp->fh_inode;
+	struct inode	*inode = fhp->fh_dentry->d_inode;
 
 	/*
 	dfprintk(FILEOP, "nfsd: fh_lock(%x/%ld) locked = %d\n",
@@ -118,7 +118,7 @@
 static inline void
 fh_unlock(struct svc_fh *fhp)
 {
-	struct inode	*inode = fhp->fh_inode;
+	struct inode	*inode = fhp->fh_dentry->d_inode;
 
 	if (fhp->fh_locked) {
 		if (!fhp->fh_post_version)
@@ -135,9 +135,9 @@
 static inline void
 fh_put(struct svc_fh *fhp)
 {
-	if (fhp->fh_inode) {
+	if (fhp->fh_dentry) {
 		fh_unlock(fhp);
-		iput(fhp->fh_inode);
+		dput(fhp->fh_dentry);
 	}
 }
 #else
@@ -146,19 +146,19 @@
 static inline void
 __fh_put(struct svc_fh *fhp, char *file, int line)
 {
-	struct inode	*inode;
+	struct dentry	*dentry;
 
-	if (!(inode = fhp->fh_inode))
+	if (!(dentry = fhp->fh_dentry))
 		return;
 
-	if (!atomic_read(&inode->i_count)) {
-		printk("nfsd: trying to free free inode in %s:%d\n"
-		       "      dev %04x ino %ld, mode %07o\n",
-		       file, line, inode->i_dev,
-		       inode->i_ino, inode->i_mode);
+	if (!dentry->d_count) {
+		printk("nfsd: trying to free free dentry in %s:%d\n"
+		       "      file %s/%s\n",
+		       file, line,
+		       dentry->d_parent->d_name.name, dentry->d_name.name);
 	} else {
 		fh_unlock(fhp);
-		iput(inode);
+		dput(dentry);
 	}
 }
 #endif
diff -u --recursive --new-file v2.1.44/linux/include/linux/omirr.h linux/include/linux/omirr.h
--- v2.1.44/linux/include/linux/omirr.h	Mon Jul  7 16:03:45 1997
+++ linux/include/linux/omirr.h	Wed Dec 31 16:00:00 1969
@@ -1,17 +0,0 @@
-/*
- * fs/proc/omirr.c  -  online mirror support
- *
- * (C) 1997 Thomas Schoebel-Theuer
- */
-
-#ifndef OMIRR_H
-#define OMIRR_H
-#include <linux/fs.h>
-#include <linux/dalloc.h>
-
-extern int omirr_print(struct dentry * ent1, struct dentry * ent2, 
-		       struct qstr * suffix, const char * fmt, ...);
-
-extern int omirr_printall(struct inode * inode, const char * fmt, ...);
-
-#endif
diff -u --recursive --new-file v2.1.44/linux/include/linux/pipe_fs_i.h linux/include/linux/pipe_fs_i.h
--- v2.1.44/linux/include/linux/pipe_fs_i.h	Tue Mar 12 06:08:22 1996
+++ linux/include/linux/pipe_fs_i.h	Wed Jul 16 10:26:21 1997
@@ -5,7 +5,6 @@
 	struct wait_queue * wait;
 	char * base;
 	unsigned int start;
-	unsigned int len;
 	unsigned int lock;
 	unsigned int rd_openers;
 	unsigned int wr_openers;
@@ -16,7 +15,7 @@
 #define PIPE_WAIT(inode)	((inode).u.pipe_i.wait)
 #define PIPE_BASE(inode)	((inode).u.pipe_i.base)
 #define PIPE_START(inode)	((inode).u.pipe_i.start)
-#define PIPE_LEN(inode)		((inode).u.pipe_i.len)
+#define PIPE_LEN(inode)		((inode).i_size)
 #define PIPE_RD_OPENERS(inode)	((inode).u.pipe_i.rd_openers)
 #define PIPE_WR_OPENERS(inode)	((inode).u.pipe_i.wr_openers)
 #define PIPE_READERS(inode)	((inode).u.pipe_i.readers)
diff -u --recursive --new-file v2.1.44/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- v2.1.44/linux/include/linux/proc_fs.h	Mon Jul  7 16:02:05 1997
+++ linux/include/linux/proc_fs.h	Wed Jul 16 20:16:34 1997
@@ -309,7 +309,7 @@
 extern struct super_block *proc_read_super(struct super_block *,void *,int);
 extern int init_proc_fs(void);
 extern struct inode * proc_get_inode(struct super_block *, int, struct proc_dir_entry *);
-extern void proc_statfs(struct super_block *, struct statfs *, int);
+extern int proc_statfs(struct super_block *, struct statfs *, int);
 extern void proc_read_inode(struct inode *);
 extern void proc_write_inode(struct inode *);
 
@@ -323,7 +323,7 @@
  * of the /proc/<pid> subdirectories.
  */
 extern int proc_readdir(struct inode *, struct file *, void *, filldir_t);
-extern int proc_lookup(struct inode *, struct qstr *, struct inode **);
+extern int proc_lookup(struct inode *, struct dentry *);
 
 struct openpromfs_dev {
  	struct openpromfs_dev *next;
diff -u --recursive --new-file v2.1.44/linux/include/linux/sdla_fr.h linux/include/linux/sdla_fr.h
--- v2.1.44/linux/include/linux/sdla_fr.h	Sun Feb  2 05:18:47 1997
+++ linux/include/linux/sdla_fr.h	Wed Jul 16 19:22:51 1997
@@ -281,7 +281,7 @@
 } fr_dlc_conf_t;
 
 /*----------------------------------------------------------------------------
- * S502 Interrupt mode control block.
+ * S502 interrupt mode control block.
  *	This structure is passed to the FR_SET_INTR_FLAGS and returned by the
  *	FR_READ_INTR_FLAGS commands.
  */
@@ -292,7 +292,7 @@
 } fr502_intr_ctl_t;
 
 /*----------------------------------------------------------------------------
- * S508 Interrupt mode control block.
+ * S508 interrupt mode control block.
  *	This structure is passed to the FR_SET_INTR_FLAGS and returned by the
  *	FR_READ_INTR_FLAGS commands.
  */
@@ -306,10 +306,10 @@
 } fr508_intr_ctl_t;
 
 /*----------------------------------------------------------------------------
- * Channel Status.
+ * Channel status.
  *	This structure is returned by the FR_READ_STATUS command.
  */
-typedef struct	frDLCStatus
+typedef struct	fr_dlc_Status
 {
 	unsigned char status		PACKED;	/* 00h: link/DLCI status */
 	struct
@@ -317,7 +317,7 @@
 		unsigned short dlci	PACKED;	/* 01h: DLCI number */
 		unsigned char status	PACKED;	/* 03h: DLCI status */
 	} circuit[1]			PACKED;
-} frDLCStatus_t;
+} fr_dlc_status_t;
 
 /* 'status' defines */
 #define	FR_LINK_INOPER	0x00		/* for global status (DLCI == 0) */
@@ -333,7 +333,7 @@
  *	This structure is returned by the FR_READ_STATISTICS command when
  *	dcli == 0.
  */
-typedef struct	frLinkStat
+typedef struct	fr_link_stat
 {
 	unsigned short rx_too_long	PACKED;	/* 00h:  */
 	unsigned short rx_dropped	PACKED;	/* 02h:  */
@@ -363,14 +363,14 @@
 	unsigned short current_T392	PACKED;	/* 32h:  */
 	unsigned short current_N392	PACKED;	/* 34h:  */
 	unsigned short current_N393	PACKED;	/* 36h:  */
-} frLinkStat_t;
+} fr_link_stat_t;
 
 /*----------------------------------------------------------------------------
- * DLCI Statistics.
+ * DLCI statistics.
  *	This structure is returned by the FR_READ_STATISTICS command when
  *	dlci != 0.
  */
-typedef struct	frDLCIStat
+typedef struct	fr_dlci_stat
 {
 	unsigned long tx_frames		PACKED;	/* 00h:  */
 	unsigned long tx_bytes		PACKED;	/* 04h:  */
@@ -384,13 +384,13 @@
 	unsigned long tx_calc_timer	PACKED;	/* 24h:  */
 	unsigned long rx_throughput	PACKED;	/* 28h:  */
 	unsigned long rx_calc_timer	PACKED;	/* 2Ch:  */
-} frDLCIStat_t;
+} fr_dlci_stat_t;
 
 /*----------------------------------------------------------------------------
- * Communications Error Statistics.
+ * Communications error statistics.
  *	This structure is returned by the FR_READ_ERROR_STATS command.
  */
-typedef struct	frCommStat
+typedef struct	fr_comm_stat
 {
 	unsigned char rx_overruns	PACKED;	/* 00h:  */
 	unsigned char rx_bad_crc	PACKED;	/* 01h:  */
@@ -401,7 +401,7 @@
 	unsigned char tx_missed_undr	PACKED;	/* 06h:  */
 	unsigned char dcd_dropped	PACKED;	/* 07h:  */
 	unsigned char cts_dropped	PACKED;	/* 08h:  */
-} frCommStat_t;
+} fr_comm_stat_t;
 
 /*----------------------------------------------------------------------------
  * Defines for the FR_ISSUE_IS_FRAME command.
diff -u --recursive --new-file v2.1.44/linux/include/linux/sdla_x25.h linux/include/linux/sdla_x25.h
--- v2.1.44/linux/include/linux/sdla_x25.h	Sun Feb  2 05:18:47 1997
+++ linux/include/linux/sdla_x25.h	Wed Jul 16 19:22:51 1997
@@ -480,7 +480,7 @@
 	unsigned short rxRR		PACKED;	/* 3Ah: RR */
 	unsigned short txRNR		PACKED;	/* 3Ch: RNR */
 	unsigned short rxRNR		PACKED;	/* 3Eh: RNR */
-} X25Stats;
+} TX25Stats;
 
 /*----------------------------------------------------------------------------
  * X25_READ_HISTORY_TABLE Command.
diff -u --recursive --new-file v2.1.44/linux/include/linux/simp.h linux/include/linux/simp.h
--- v2.1.44/linux/include/linux/simp.h	Mon Jul  7 08:26:24 1997
+++ linux/include/linux/simp.h	Wed Jul 16 19:22:51 1997
@@ -24,7 +24,7 @@
  * Note for big-sized objects in the range of whole pages, use
  * the fast Linux page allocator instead, directly.
  */
-extern struct simp * simp_create(char * name, long size, long clearable_offset,
+extern struct simp * simp_create(char * name, long size,
 				 structor first_ctor, 
 				 structor again_ctor, 
 				 structor dtor);
diff -u --recursive --new-file v2.1.44/linux/include/linux/slab.h linux/include/linux/slab.h
--- v2.1.44/linux/include/linux/slab.h	Mon Jul  7 16:02:03 1997
+++ linux/include/linux/slab.h	Wed Jul 16 20:16:33 1997
@@ -57,7 +57,7 @@
 
 extern void *kmalloc(size_t, int);
 extern void kfree(const void *);
-extern void kfree_s(void *, size_t);
+extern void kfree_s(const void *, size_t);
 
 extern int kmem_cache_reap(int, int, int);
 extern int get_slabinfo(char *);
diff -u --recursive --new-file v2.1.44/linux/include/linux/swap.h linux/include/linux/swap.h
--- v2.1.44/linux/include/linux/swap.h	Mon Jun 16 16:36:00 1997
+++ linux/include/linux/swap.h	Sun Jul 13 21:20:10 1997
@@ -19,8 +19,7 @@
 struct swap_info_struct {
 	unsigned int flags;
 	kdev_t swap_device;
-	char *swap_filename;
-	struct inode * swap_file;
+	struct dentry * swap_file;
 	unsigned char * swap_map;
 	unsigned char * swap_lockmap;
 	unsigned int lowest_bit;
diff -u --recursive --new-file v2.1.44/linux/include/linux/sysv_fs.h linux/include/linux/sysv_fs.h
--- v2.1.44/linux/include/linux/sysv_fs.h	Mon Jul  7 16:03:54 1997
+++ linux/include/linux/sysv_fs.h	Wed Jul 16 20:18:04 1997
@@ -372,8 +372,8 @@
 	const char * symname);
 extern int sysv_link(struct inode * oldinode, struct inode * dir, const char * name, int len);
 extern int sysv_mknod(struct inode * dir, const char * name, int len, int mode, int rdev);
-extern int sysv_rename(struct inode * old_dir, const char * old_name, int old_len,
-		       struct inode * new_dir, const char * new_name, int new_len);
+extern int sysv_rename(struct inode * old_dir, struct dentry * old_dentry,
+		       struct inode * new_dir, struct dentry * new_dentry);
 extern struct inode * sysv_new_inode(const struct inode * dir);
 extern void sysv_free_inode(struct inode * inode);
 extern unsigned long sysv_count_free_inodes(struct super_block *sb);
@@ -396,7 +396,7 @@
 extern int sysv_notify_change(struct inode *, struct iattr *);
 extern void sysv_write_inode(struct inode *);
 extern void sysv_put_inode(struct inode *);
-extern void sysv_statfs(struct super_block *, struct statfs *, int);
+extern int sysv_statfs(struct super_block *, struct statfs *, int);
 extern int sysv_sync_inode(struct inode *);
 extern int sysv_sync_file(struct inode *, struct file *);
 extern int sysv_mmap(struct inode *, struct file *, struct vm_area_struct *);
diff -u --recursive --new-file v2.1.44/linux/include/linux/tqueue.h linux/include/linux/tqueue.h
--- v2.1.44/linux/include/linux/tqueue.h	Tue May 13 22:41:19 1997
+++ linux/include/linux/tqueue.h	Wed Jul 16 19:22:51 1997
@@ -42,7 +42,7 @@
 
 struct tq_struct {
 	struct tq_struct *next;		/* linked list of active bh's */
-	int sync;			/* must be initialized to zero */
+	unsigned long sync;		/* must be initialized to zero */
 	void (*routine)(void *);	/* function to call */
 	void *data;			/* argument to function */
 };
diff -u --recursive --new-file v2.1.44/linux/include/linux/ufs_fs.h linux/include/linux/ufs_fs.h
--- v2.1.44/linux/include/linux/ufs_fs.h	Mon Jun 30 15:23:11 1997
+++ linux/include/linux/ufs_fs.h	Wed Jul 16 20:37:22 1997
@@ -6,7 +6,7 @@
  * Laboratory for Computer Science Research Computing Facility
  * Rutgers, The State University of New Jersey
  *
- * $Id: ufs_fs.h,v 1.7 1996/08/13 19:27:59 ecd Exp $
+ * $Id: ufs_fs.h,v 1.8 1997/07/17 02:17:54 davem Exp $
  *
  */
 
@@ -225,7 +225,7 @@
 extern void ufs_print_inode (struct inode *);
 
 /* ufs_namei.c */
-extern int ufs_lookup (struct inode *, const char *, int, struct inode **);
+extern int ufs_lookup (struct inode *, struct qstr *, struct inode **);
 
 /* ufs_super.c */
 extern void ufs_warning (struct super_block *, const char *, const char *, ...)
diff -u --recursive --new-file v2.1.44/linux/include/linux/vmalloc.h linux/include/linux/vmalloc.h
--- v2.1.44/linux/include/linux/vmalloc.h	Mon Jul  7 16:02:03 1997
+++ linux/include/linux/vmalloc.h	Wed Jul 16 20:16:33 1997
@@ -17,6 +17,8 @@
 void vfree(void * addr);
 void * vmalloc(unsigned long size);
 int vread(char *buf, char *addr, int count);
+void vmfree_area_pages(unsigned long address, unsigned long size);
+int vmalloc_area_pages(unsigned long address, unsigned long size);
 
 extern inline void set_pgdir(unsigned long address, pgd_t entry)
 {
@@ -34,3 +36,4 @@
 }
 
 #endif
+
diff -u --recursive --new-file v2.1.44/linux/include/linux/wanpipe.h linux/include/linux/wanpipe.h
--- v2.1.44/linux/include/linux/wanpipe.h	Sun Feb  2 05:18:47 1997
+++ linux/include/linux/wanpipe.h	Wed Jul 16 19:22:51 1997
@@ -11,6 +11,8 @@
 *		as published by the Free Software Foundation; either version
 *		2 of the License, or (at your option) any later version.
 * ============================================================================
+* Jan 15, 1997	Gene Kozin	Version 3.1.0
+*				 o added UDP management stuff
 * Jan 02, 1997	Gene Kozin	Version 3.0.0
 *****************************************************************************/
 #ifndef	_WANPIPE_H
@@ -19,6 +21,11 @@
 #include <linux/wanrouter.h>
 
 /* Defines */
+
+#ifndef	PACKED
+#define	PACKED	__attribute__((packed))
+#endif
+
 #define	WANPIPE_MAGIC	0x414C4453L	/* signatire: 'SDLA' reversed */
 
 /* IOCTL numbers (up to 16) */
@@ -44,6 +51,22 @@
 	void* data;		/* -> data buffer */
 } sdla_exec_t;
 
+/* UDP management stuff */
+
+typedef struct wum_header
+{
+	unsigned char signature[8];	/* 00h: signature */
+	unsigned char type;		/* 08h: request/reply */
+	unsigned char command;		/* 09h: commnand */
+	unsigned char reserved[6];	/* 0Ah: reserved */
+} wum_header_t;
+
+#define	WUM_SIGNATURE_L	0x50495046
+#define	WUM_SIGNATURE_H	0x444E3845
+
+#define	WUM_KILL	0x50
+#define	WUM_EXEC	0x51
+
 #ifdef	__KERNEL__
 /****** Kernel Interface ****************************************************/
 
@@ -77,6 +100,7 @@
 	wan_device_t wandev;		/* WAN device data space */
 	unsigned open_cnt;		/* number of open interfaces */
 	unsigned long state_tick;	/* link state timestamp */
+/*	unsigned tx_int_enabled; */	/* tranmit interrupt enabled or not */
 	char in_isr;			/* interrupt-in-service flag */
 	void* mbox;			/* -> mailbox */
 	void* rxmb;			/* -> receive mailbox */
diff -u --recursive --new-file v2.1.44/linux/include/linux/wanrouter.h linux/include/linux/wanrouter.h
--- v2.1.44/linux/include/linux/wanrouter.h	Mon Jul  7 16:04:48 1997
+++ linux/include/linux/wanrouter.h	Wed Jul 16 20:18:45 1997
@@ -1,5 +1,5 @@
 /*****************************************************************************
-* wanrouter.h	Definitions for the WAN Multiprotocol Router Module.
+* router.h	Definitions for the WAN Multiprotocol Router Module.
 *		This module provides API and common services for WAN Link
 *		Drivers and is completely hardware-independent.
 *
@@ -12,6 +12,10 @@
 *		as published by the Free Software Foundation; either version
 *		2 of the License, or (at your option) any later version.
 * ============================================================================
+* May 29, 1997 	Jaspreet Singh	Added 'tx_int_enabled' tp 'wan_device_t'
+* May 21, 1997	Jaspreet Singh	Added 'udp_port' to 'wan_device_t'
+* Apr 25, 1997  Farhan Thawar   Added 'udp_port' to 'wandev_conf_t'
+* Jan 16, 1997	Gene Kozin	router_devlist made public
 * Jan 02, 1997	Gene Kozin	Initial version (based on wanpipe.h).
 *****************************************************************************/
 #ifndef	_ROUTER_H
@@ -128,7 +132,8 @@
 	int dma;		/* DMA request level */
 	unsigned bps;		/* data transfer rate */
 	unsigned mtu;		/* maximum transmit unit size */
-	char interface;		/* RS-232/V.35, etc. */
+        unsigned udp_port;      /* UDP port for management */
+        char interface;		/* RS-232/V.35, etc. */
 	char clocking;		/* external/internal */
 	char line_coding;	/* NRZ/NRZI/FM0/FM1, etc. */
 	char station;		/* DTE/DCE, primary/secondary, etc. */
@@ -283,6 +288,8 @@
 	int dma;			/* DMA request level */
 	unsigned bps;			/* data transfer rate */
 	unsigned mtu;			/* max physical transmit unit size */
+	unsigned udp_port;              /* UDP port for management */
+        unsigned tx_int_enabled; 	/* Transmit Interrupt enabled or not */
 	char interface;			/* RS-232/V.35, etc. */
 	char clocking;			/* external/internal */
 	char line_coding;		/* NRZ/NRZI/FM0/FM1, etc. */
@@ -311,22 +318,24 @@
 	struct proc_dir_entry dent;	/* proc filesystem entry */
 } wan_device_t;
 
-/* Init Point */
-extern void wanrouter_init(void);
-
 /* Public functions available for device drivers */
-extern int register_wan_device (wan_device_t* wandev);
-extern int unregister_wan_device (char* name);
-unsigned short wanrouter_type_trans (struct sk_buff* skb, struct device* dev);
-int wanrouter_encapsulate (struct sk_buff* skb, struct device* dev);
+extern int register_wandev (wan_device_t* wandev);
+extern int unregister_wandev (char* name);
+unsigned short wan_type_trans (struct sk_buff* skb, struct device* dev);
+int wan_encapsulate (struct sk_buff* skb, struct device* dev);
 
 /* Proc interface functions. These must not be called by the drivers! */
 extern int wanrouter_proc_init (void);
 extern void wanrouter_proc_cleanup (void);
 extern int wanrouter_proc_add (wan_device_t* wandev);
 extern int wanrouter_proc_delete (wan_device_t* wandev);
-extern int wanrouter_ioctl(struct inode* inode, struct file* file,
-	unsigned int cmd, unsigned long arg);
+extern int wanrouter_ioctl(
+	struct inode* inode, struct file* file,
+	unsigned int cmd, unsigned long arg)
+;
+
+/* Public Data */
+extern wan_device_t* router_devlist;	/* list of registered devices */
 
 #endif	/* __KERNEL__ */
 #endif	/* _ROUTER_H */
diff -u --recursive --new-file v2.1.44/linux/include/linux/wrapper.h linux/include/linux/wrapper.h
--- v2.1.44/linux/include/linux/wrapper.h	Mon Jun 16 16:36:00 1997
+++ linux/include/linux/wrapper.h	Wed Jul 16 19:22:51 1997
@@ -20,9 +20,9 @@
 #define module_unregister_blkdev unregister_blkdev
 
 #define inode_get_rdev(i) i->i_rdev
-#define inode_get_count(i) atomic_read(&((i)->i_count))
-#define inode_inc_count(i) atomic_inc(&((i)->i_count))
-#define inode_dec_count(i) atomic_dec(&((i)->i_count))
+#define inode_get_count(i) i->i_count
+#define inode_inc_count(i) i->i_count++
+#define inode_dec_count(i) i->i_count--
 
 #define file_get_flags(f) f->f_flags
 
diff -u --recursive --new-file v2.1.44/linux/init/main.c linux/init/main.c
--- v2.1.44/linux/init/main.c	Mon Jun 16 16:36:01 1997
+++ linux/init/main.c	Wed Jul 16 19:22:51 1997
@@ -32,7 +32,6 @@
 #include <linux/slab.h>
 #include <linux/major.h>
 #include <linux/blk.h>
-#include <linux/nametrans.h>
 #include <linux/init.h>
 #ifdef CONFIG_ROOT_NFS
 #include <linux/nfs_fs.h>
@@ -559,12 +558,6 @@
 		return 1;
 	}
 #endif
-#ifdef CONFIG_TRANS_NAMES
-	if(!strncmp(line,"nametrans=",10)) {
-		nametrans_setup(line+10);
-		return 1;
-	}
-#endif
 	while (bootsetups[i].str) {
 		int n = strlen(bootsetups[i].str);
 		if (!strncmp(line,bootsetups[i].str,n)) {
@@ -758,6 +751,12 @@
 		if (!strncmp(line,"init=",5)) {
 			line += 5;
 			execute_command = line;
+			/* In case LILO is going to boot us with default command line,
+			 * it prepends "auto" before the whole cmdline which makes
+			 * the shell think it should execute a script with such name.
+			 * So we ignore all arguments entered _before_ init=... [MJ]
+			 */
+			args = 0;
 			continue;
 		}
 		if (checksetup(line))
@@ -886,7 +885,6 @@
 	memory_start = kmem_cache_init(memory_start, memory_end);
 	sti();
 	calibrate_delay();
-	memory_start = name_cache_init(memory_start,memory_end);
 #ifdef CONFIG_BLK_DEV_INITRD
 	if (initrd_start && !initrd_below_start_ok && initrd_start < memory_start) {
 		printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - "
@@ -901,6 +899,7 @@
 #endif
 	uidcache_init();
 	filescache_init();
+	dcache_init();
 	vma_init();
 	buffer_init();
 	inode_init();
diff -u --recursive --new-file v2.1.44/linux/ipc/shm.c linux/ipc/shm.c
--- v2.1.44/linux/ipc/shm.c	Tue May 13 22:41:19 1997
+++ linux/ipc/shm.c	Sun Jul 13 21:20:11 1997
@@ -555,7 +555,7 @@
 	shmd->vm_flags = VM_SHM | VM_MAYSHARE | VM_SHARED
 			 | VM_MAYREAD | VM_MAYEXEC | VM_READ | VM_EXEC
 			 | ((shmflg & SHM_RDONLY) ? 0 : VM_MAYWRITE | VM_WRITE);
-	shmd->vm_inode = NULL;
+	shmd->vm_dentry = NULL;
 	shmd->vm_offset = 0;
 	shmd->vm_ops = &shm_vm_ops;
 
diff -u --recursive --new-file v2.1.44/linux/kernel/exit.c linux/kernel/exit.c
--- v2.1.44/linux/kernel/exit.c	Tue Jul  1 14:19:02 1997
+++ linux/kernel/exit.c	Sat Jul 12 12:33:28 1997
@@ -368,8 +368,11 @@
 			break;
 		while (set) {
 			if (set & 1) {
-				close_fp(files->fd[i]);
-				files->fd[i] = NULL;
+				struct file * file = files->fd[i];
+				if (file) {
+					files->fd[i] = NULL;
+					close_fp(file);
+				}
 			}
 			i++;
 			set >>= 1;
diff -u --recursive --new-file v2.1.44/linux/kernel/fork.c linux/kernel/fork.c
--- v2.1.44/linux/kernel/fork.c	Sat Jul  5 20:53:22 1997
+++ linux/kernel/fork.c	Sun Jul 13 21:20:11 1997
@@ -211,7 +211,7 @@
 	flush_cache_mm(current->mm);
 	pprev = &mm->mmap;
 	for (mpnt = current->mm->mmap ; mpnt ; mpnt = mpnt->vm_next) {
-		struct inode *inode;
+		struct dentry *dentry;
 
 		tmp = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
 		if (!tmp) {
@@ -223,11 +223,11 @@
 		tmp->vm_flags &= ~VM_LOCKED;
 		tmp->vm_mm = mm;
 		tmp->vm_next = NULL;
-		inode = tmp->vm_inode;
-		if (inode) {
-			atomic_inc(&inode->i_count);
+		dentry = tmp->vm_dentry;
+		if (dentry) {
+			dentry->d_count++;
 			if (tmp->vm_flags & VM_DENYWRITE)
-				inode->i_writecount--;
+				dentry->d_inode->i_writecount--;
       
 			/* insert tmp into the share list, just after mpnt */
 			if((tmp->vm_next_share = mpnt->vm_next_share) != NULL)
diff -u --recursive --new-file v2.1.44/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.1.44/linux/kernel/ksyms.c	Sun Jul  6 20:13:54 1997
+++ linux/kernel/ksyms.c	Wed Jul 16 07:48:28 1997
@@ -142,12 +142,14 @@
 EXPORT_SYMBOL(putname);
 EXPORT_SYMBOL(__fput);
 EXPORT_SYMBOL(iget);
-EXPORT_SYMBOL(_iput);
+EXPORT_SYMBOL(iput);
 EXPORT_SYMBOL(__namei);
 EXPORT_SYMBOL(lookup_dentry);
 EXPORT_SYMBOL(open_namei);
 EXPORT_SYMBOL(sys_close);
 EXPORT_SYMBOL(close_fp);
+EXPORT_SYMBOL(d_alloc_root);
+EXPORT_SYMBOL(d_delete);
 EXPORT_SYMBOL(insert_file_free);
 EXPORT_SYMBOL(check_disk_change);
 EXPORT_SYMBOL(invalidate_buffers);
@@ -178,6 +180,7 @@
 EXPORT_SYMBOL(posix_test_lock);
 EXPORT_SYMBOL(posix_block_lock);
 EXPORT_SYMBOL(posix_unblock_lock);
+EXPORT_SYMBOL(dput);
 
 #if !defined(CONFIG_NFSD) && defined(CONFIG_NFSD_MODULE)
 EXPORT_SYMBOL(do_nfsservctl);
@@ -330,7 +333,7 @@
 EXPORT_SYMBOL(copy_strings);
 EXPORT_SYMBOL(do_execve);
 EXPORT_SYMBOL(flush_old_exec);
-EXPORT_SYMBOL(open_inode);
+EXPORT_SYMBOL(open_dentry);
 EXPORT_SYMBOL(read_exec);
 
 /* Miscellaneous access points */
@@ -342,7 +345,7 @@
 EXPORT_SYMBOL(sys_tz);
 EXPORT_SYMBOL(__wait_on_super);
 EXPORT_SYMBOL(file_fsync);
-EXPORT_SYMBOL(_clear_inode);
+EXPORT_SYMBOL(clear_inode);
 EXPORT_SYMBOL(refile_buffer);
 EXPORT_SYMBOL(nr_async_pages);
 EXPORT_SYMBOL(___strtok);
@@ -353,7 +356,7 @@
 EXPORT_SYMBOL(blkdev_inode_operations);
 EXPORT_SYMBOL(read_ahead);
 EXPORT_SYMBOL(get_hash_table);
-EXPORT_SYMBOL(_get_empty_inode);
+EXPORT_SYMBOL(get_empty_inode);
 EXPORT_SYMBOL(insert_inode_hash);
 EXPORT_SYMBOL(event);
 EXPORT_SYMBOL(__down);
diff -u --recursive --new-file v2.1.44/linux/kernel/sys.c linux/kernel/sys.c
--- v2.1.44/linux/kernel/sys.c	Thu Jun 26 12:33:40 1997
+++ linux/kernel/sys.c	Sun Jul 13 21:20:11 1997
@@ -21,7 +21,6 @@
 #include <linux/fcntl.h>
 #include <linux/acct.h>
 #include <linux/tty.h>
-#include <linux/nametrans.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/notifier.h>
@@ -397,10 +396,8 @@
       fs = get_fs();
       set_fs(KERNEL_DS);
 
-      acct_file.f_op->write(acct_file.f_inode, &acct_file,
+      acct_file.f_op->write(acct_file.f_dentry->d_inode, &acct_file,
                              (char *)&ac, sizeof(struct acct));
-      /* inode->i_status |= ST_MODIFIED is willingly *not* done here */
-
       set_fs(fs);
    }
    return 0;
@@ -408,8 +405,6 @@
 
 asmlinkage int sys_acct(const char *name)
 {
-	struct inode *inode = (struct inode *)0;
-	char *tmp;
 	int error = -EPERM;
 
 	lock_kernel();
@@ -419,10 +414,10 @@
 	if (name == (char *)0) {
 		if (acct_active) {
 			if (acct_file.f_op->release)
-				acct_file.f_op->release(acct_file.f_inode, &acct_file);
+				acct_file.f_op->release(acct_file.f_dentry->d_inode, &acct_file);
 
-			if (acct_file.f_inode != (struct inode *) 0)
-				iput(acct_file.f_inode);
+			if (acct_file.f_dentry != NULL)
+				dput(acct_file.f_dentry);
 
 			acct_active = 0;
 		}
@@ -430,40 +425,51 @@
 	} else {
 		error = -EBUSY;
 		if (!acct_active) {
-			if ((error = getname(name, &tmp)) != 0)
+			struct dentry *dentry;
+			struct inode *inode;
+			char *tmp;
+
+			tmp = getname(name);
+			error = PTR_ERR(tmp);
+			if (IS_ERR(tmp))
 				goto out;
 
-			error = open_namei(tmp, O_RDWR, 0600, &inode, 0);
+			dentry = open_namei(tmp, O_RDWR, 0600);
 			putname(tmp);
-			if (error)
+
+			error = PTR_ERR(dentry);
+			if (IS_ERR(dentry))
 				goto out;
+			inode = dentry->d_inode;
 
 			error = -EACCES;
 			if (!S_ISREG(inode->i_mode)) {
-				iput(inode);
+				dput(dentry);
 				goto out;
 			}
 
 			error = -EIO;
 			if (!inode->i_op || !inode->i_op->default_file_ops || 
 			    !inode->i_op->default_file_ops->write) {
-				iput(inode);
+				dput(dentry);
 				goto out;
 			}
 
 			acct_file.f_mode = 3;
 			acct_file.f_flags = 0;
 			acct_file.f_count = 1;
-			acct_file.f_inode = inode;
+			acct_file.f_dentry = dentry;
 			acct_file.f_pos = inode->i_size;
 			acct_file.f_reada = 0;
 			acct_file.f_op = inode->i_op->default_file_ops;
 
-			if(acct_file.f_op->open)
-				if(acct_file.f_op->open(acct_file.f_inode, &acct_file)) {
-					iput(inode);
+			if(acct_file.f_op->open) {
+				error = acct_file.f_op->open(inode, &acct_file);
+				if (error) {
+					dput(dentry);
 					goto out;
 				}
+			}
 
 			acct_active = 1;
 			error = 0;
diff -u --recursive --new-file v2.1.44/linux/kernel/sysctl.c linux/kernel/sysctl.c
--- v2.1.44/linux/kernel/sysctl.c	Mon Jul  7 13:11:09 1997
+++ linux/kernel/sysctl.c	Wed Jul 16 19:22:51 1997
@@ -16,7 +16,6 @@
 #include <linux/mm.h>
 #include <linux/sysctl.h>
 #include <linux/swapctl.h>
-#include <linux/nametrans.h>
 #include <linux/proc_fs.h>
 #include <linux/malloc.h>
 #include <linux/stat.h>
@@ -172,10 +171,6 @@
 	{KERN_JAVA_APPLETVIEWER, "java-appletviewer", binfmt_java_appletviewer,
 	 64, 0644, NULL, &proc_dostring, &sysctl_string },
 #endif
-#ifdef CONFIG_TRANS_NAMES
-	{KERN_NAMETRANS, "nametrans", nametrans_txt, MAX_DEFAULT_TRANSLEN,
-	 0644, NULL, &nametrans_dostring, &nametrans_string},
-#endif
 #ifdef __sparc__
 	{KERN_SPARC_REBOOT, "reboot-cmd", reboot_command,
 	 256, 0644, NULL, &proc_dostring, &sysctl_string },
@@ -823,6 +818,12 @@
 
 #else /* CONFIG_PROC_FS */
 
+int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
+			  void *buffer, size_t *lenp)
+{
+  return -ENOSYS; 
+}
+
 int proc_dostring(ctl_table *table, int write, struct file *filp,
 		  void *buffer, size_t *lenp)
 {
@@ -841,6 +842,12 @@
 	return -ENOSYS;
 }
 
+int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
+		    void *buffer, size_t *lenp)
+{
+	return -ENOSYS;
+}
+
 #endif /* CONFIG_PROC_FS */
 
 
@@ -1036,6 +1043,12 @@
 }
 
 int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
+		    void *buffer, size_t *lenp)
+{
+	return -ENOSYS;
+}
+
+int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
 		    void *buffer, size_t *lenp)
 {
 	return -ENOSYS;
diff -u --recursive --new-file v2.1.44/linux/mm/Makefile linux/mm/Makefile
--- v2.1.44/linux/mm/Makefile	Mon Jul  7 10:02:52 1997
+++ linux/mm/Makefile	Wed Jul 16 19:22:51 1997
@@ -9,7 +9,7 @@
 
 O_TARGET := mm.o
 O_OBJS	 := memory.o mmap.o filemap.o mprotect.o mlock.o mremap.o \
-	    vmalloc.o slab.o \
+	    vmalloc.o slab.o simp.o\
 	    swap.o vmscan.o page_io.o page_alloc.o swap_state.o swapfile.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.44/linux/mm/filemap.c linux/mm/filemap.c
--- v2.1.44/linux/mm/filemap.c	Mon Jun 16 16:36:01 1997
+++ linux/mm/filemap.c	Sun Jul 13 21:20:11 1997
@@ -753,10 +753,7 @@
 	filp->f_reada = 1;
 	if (page_cache)
 		free_page(page_cache);
-	if (DO_UPDATE_ATIME(inode)) {
-		inode->i_atime = CURRENT_TIME;
-		inode->i_dirt = 1;
-	}
+	UPDATE_ATIME(inode)
 	if (!read)
 		read = error;
 	return read;
@@ -775,7 +772,7 @@
 {
 	unsigned long offset;
 	struct page * page, **hash;
-	struct inode * inode = area->vm_inode;
+	struct inode * inode = area->vm_dentry->d_inode;
 	unsigned long old_page, new_page;
 
 	new_page = 0;
@@ -919,7 +916,6 @@
 	retval = -EIO;
 	if (size == file->f_op->write(inode, file, (const char *) page, size))
 		retval = 0;
-	/* inode->i_status |= ST_MODIFIED is willingly *not* done here */
 	set_fs(old_fs);
 	return retval;
 }
@@ -930,6 +926,7 @@
 {
 	int result;
 	struct file file;
+	struct dentry * dentry;
 	struct inode * inode;
 	struct buffer_head * bh;
 
@@ -944,14 +941,15 @@
 		return 0;
 	}
 
-	inode = vma->vm_inode;
+	dentry = vma->vm_dentry;
+	inode = dentry->d_inode;
 	file.f_op = inode->i_op->default_file_ops;
 	if (!file.f_op->write)
 		return -EIO;
 	file.f_mode = 3;
 	file.f_flags = 0;
 	file.f_count = 1;
-	file.f_inode = inode;
+	file.f_dentry = dentry;
 	file.f_pos = offset;
 	file.f_reada = 0;
 
@@ -1189,12 +1187,8 @@
 		return -EACCES;
 	if (!inode->i_op || !inode->i_op->readpage)
 		return -ENOEXEC;
-	if (DO_UPDATE_ATIME(inode)) {
-		inode->i_atime = CURRENT_TIME;
-		inode->i_dirt = 1;
-	}
-	vma->vm_inode = inode;
-	atomic_inc(&inode->i_count);
+	UPDATE_ATIME(inode);
+	vma->vm_dentry = dget(file->f_dentry);
 	vma->vm_ops = ops;
 	return 0;
 }
@@ -1207,7 +1201,7 @@
 static int msync_interval(struct vm_area_struct * vma,
 	unsigned long start, unsigned long end, int flags)
 {
-	if (!vma->vm_inode)
+	if (!vma->vm_dentry)
 		return 0;
 	if (vma->vm_ops->sync) {
 		int error;
@@ -1215,7 +1209,7 @@
 		if (error)
 			return error;
 		if (flags & MS_SYNC)
-			return file_fsync(vma->vm_inode, NULL);
+			return file_fsync(vma->vm_dentry->d_inode, NULL);
 		return 0;
 	}
 	return 0;
diff -u --recursive --new-file v2.1.44/linux/mm/mlock.c linux/mm/mlock.c
--- v2.1.44/linux/mm/mlock.c	Mon Jun 16 16:36:01 1997
+++ linux/mm/mlock.c	Sun Jul 13 21:20:11 1997
@@ -38,8 +38,7 @@
 	n->vm_end = end;
 	vma->vm_offset += vma->vm_start - n->vm_start;
 	n->vm_flags = newflags;
-	if (n->vm_inode)
-		atomic_inc(&n->vm_inode->i_count);
+	n->vm_dentry = dget(vma->vm_dentry);
 	if (n->vm_ops && n->vm_ops->open)
 		n->vm_ops->open(n);
 	insert_vm_struct(current->mm, n);
@@ -59,8 +58,7 @@
 	n->vm_start = start;
 	n->vm_offset += n->vm_start - vma->vm_start;
 	n->vm_flags = newflags;
-	if (n->vm_inode)
-		atomic_inc(&n->vm_inode->i_count);
+	n->vm_dentry = dget(vma->vm_dentry);
 	if (n->vm_ops && n->vm_ops->open)
 		n->vm_ops->open(n);
 	insert_vm_struct(current->mm, n);
@@ -89,8 +87,9 @@
 	vma->vm_offset += vma->vm_start - left->vm_start;
 	right->vm_offset += right->vm_start - left->vm_start;
 	vma->vm_flags = newflags;
-	if (vma->vm_inode)
-		atomic_add(2, &vma->vm_inode->i_count);
+	if (vma->vm_dentry)
+		vma->vm_dentry->d_count += 2;
+
 	if (vma->vm_ops && vma->vm_ops->open) {
 		vma->vm_ops->open(left);
 		vma->vm_ops->open(right);
diff -u --recursive --new-file v2.1.44/linux/mm/mmap.c linux/mm/mmap.c
--- v2.1.44/linux/mm/mmap.c	Mon Jul  7 08:24:28 1997
+++ linux/mm/mmap.c	Sun Jul 13 21:20:11 1997
@@ -74,11 +74,11 @@
 /* Remove one vm structure from the inode's i_mmap ring. */
 static inline void remove_shared_vm_struct(struct vm_area_struct *vma)
 {
-	struct inode * inode = vma->vm_inode;
+	struct dentry * dentry = vma->vm_dentry;
 
-	if (inode) {
+	if (dentry) {
 		if (vma->vm_flags & VM_DENYWRITE)
-			inode->i_writecount++;
+			dentry->d_inode->i_writecount++;
 		if(vma->vm_next_share)
 			vma->vm_next_share->vm_pprev_share = vma->vm_pprev_share;
 		*vma->vm_pprev_share = vma->vm_next_share;
@@ -194,7 +194,7 @@
 				return -EACCES;
 
 			/* make sure there are no mandatory locks on the file. */
-			if (locks_verify_locked(file->f_inode))
+			if (locks_verify_locked(file->f_dentry->d_inode))
 				return -EAGAIN;
 			/* fall through */
 		case MAP_PRIVATE:
@@ -259,7 +259,7 @@
 	vma->vm_page_prot = protection_map[vma->vm_flags & 0x0f];
 	vma->vm_ops = NULL;
 	vma->vm_offset = off;
-	vma->vm_inode = NULL;
+	vma->vm_dentry = NULL;
 	vma->vm_pte = 0;
 
 	do_munmap(addr, len);	/* Clear old maps */
@@ -283,7 +283,7 @@
 	if (file) {
 		int error = 0;
 		if (vma->vm_flags & VM_DENYWRITE) {
-			if (file->f_inode->i_writecount > 0)
+			if (file->f_dentry->d_inode->i_writecount > 0)
 				error = -ETXTBSY;
 			else {
 	        		/* f_op->mmap might possibly sleep
@@ -291,16 +291,16 @@
 				 * might). In any case, this takes care of any
 				 * race that this might cause.
 				 */
-				file->f_inode->i_writecount--;
+				file->f_dentry->d_inode->i_writecount--;
 				correct_wcount = 1;
 			}
 		}
 		if (!error)
-			error = file->f_op->mmap(file->f_inode, file, vma);
+			error = file->f_op->mmap(file->f_dentry->d_inode, file, vma);
 	
 		if (error) {
 			if (correct_wcount)
-				file->f_inode->i_writecount++;
+				file->f_dentry->d_inode->i_writecount++;
 			kmem_cache_free(vm_area_cachep, vma);
 			return error;
 		}
@@ -309,7 +309,7 @@
 	flags = vma->vm_flags;
 	insert_vm_struct(mm, vma);
 	if (correct_wcount)
-		file->f_inode->i_writecount++;
+		file->f_dentry->d_inode->i_writecount++;
 	merge_segments(mm, vma->vm_start, vma->vm_end);
 	
 	addr = vma->vm_start;
@@ -389,8 +389,8 @@
 	if (addr == area->vm_start && end == area->vm_end) {
 		if (area->vm_ops && area->vm_ops->close)
 			area->vm_ops->close(area);
-		if (area->vm_inode)
-			iput(area->vm_inode);
+		if (area->vm_dentry)
+			dput(area->vm_dentry);
 		return;
 	}
 
@@ -407,11 +407,14 @@
 
 		if (!mpnt)
 			return;
-		*mpnt = *area;
-		mpnt->vm_offset += (end - area->vm_start);
+		mpnt->vm_mm = area->vm_mm;
 		mpnt->vm_start = end;
-		if (mpnt->vm_inode)
-			atomic_inc(&mpnt->vm_inode->i_count);
+		mpnt->vm_end = area->vm_end;
+		mpnt->vm_page_prot = area->vm_page_prot;
+		mpnt->vm_flags = area->vm_flags;
+		mpnt->vm_ops = area->vm_ops;
+		mpnt->vm_offset += (end - area->vm_start);
+		mpnt->vm_dentry = dget(area->vm_dentry);
 		if (mpnt->vm_ops && mpnt->vm_ops->open)
 			mpnt->vm_ops->open(mpnt);
 		area->vm_end = addr;	/* Truncate area */
@@ -544,8 +547,8 @@
 		}
 		remove_shared_vm_struct(mpnt);
 		zap_page_range(mm, start, size);
-		if (mpnt->vm_inode)
-			iput(mpnt->vm_inode);
+		if (mpnt->vm_dentry)
+			dput(mpnt->vm_dentry);
 		kmem_cache_free(vm_area_cachep, mpnt);
 		mpnt = next;
 	}
@@ -557,7 +560,7 @@
 void insert_vm_struct(struct mm_struct *mm, struct vm_area_struct *vmp)
 {
 	struct vm_area_struct **pprev = &mm->mmap;
-	struct inode * inode;
+	struct dentry * dentry;
 
 	/* Find where to link it in. */
 	while(*pprev && (*pprev)->vm_start <= vmp->vm_start)
@@ -569,8 +572,9 @@
 	*pprev = vmp;
 	vmp->vm_pprev = pprev;
 
-	inode = vmp->vm_inode;
-	if (inode) {
+	dentry = vmp->vm_dentry;
+	if (dentry) {
+		struct inode * inode = dentry->d_inode;
 		if (vmp->vm_flags & VM_DENYWRITE)
 			inode->i_writecount--;
       
@@ -617,16 +621,19 @@
 	for ( ; mpnt && prev->vm_start < end_addr ; prev = mpnt, mpnt = next) {
 		next = mpnt->vm_next;
 
-		/* To share, we must have the same inode, operations.. */
-		if ((mpnt->vm_inode != prev->vm_inode)	||
+		/* To share, we must have the same dentry, operations.. */
+		if ((mpnt->vm_dentry != prev->vm_dentry)||
 		    (mpnt->vm_pte != prev->vm_pte)	||
 		    (mpnt->vm_ops != prev->vm_ops)	||
 		    (mpnt->vm_flags != prev->vm_flags)	||
 		    (prev->vm_end != mpnt->vm_start))
 			continue;
 
-		/* and if we have an inode, the offsets must be contiguous.. */
-		if ((mpnt->vm_inode != NULL) || (mpnt->vm_flags & VM_SHM)) {
+		/*
+		 * If we have a dentry or it's a shared memory area
+		 * the offsets must be contiguous..
+		 */
+		if ((mpnt->vm_dentry != NULL) || (mpnt->vm_flags & VM_SHM)) {
 			unsigned long off = prev->vm_offset+prev->vm_end-prev->vm_start;
 			if (off != mpnt->vm_offset)
 				continue;
@@ -647,8 +654,8 @@
 			mpnt->vm_ops->close(mpnt);
 		}
 		remove_shared_vm_struct(mpnt);
-		if (mpnt->vm_inode)
-			atomic_dec(&mpnt->vm_inode->i_count);
+		if (mpnt->vm_dentry)
+			dput(mpnt->vm_dentry);
 		kmem_cache_free(vm_area_cachep, mpnt);
 		mpnt = prev;
 	}
diff -u --recursive --new-file v2.1.44/linux/mm/mprotect.c linux/mm/mprotect.c
--- v2.1.44/linux/mm/mprotect.c	Mon Jun 16 16:36:01 1997
+++ linux/mm/mprotect.c	Sun Jul 13 21:20:11 1997
@@ -110,8 +110,7 @@
 	vma->vm_offset += vma->vm_start - n->vm_start;
 	n->vm_flags = newflags;
 	n->vm_page_prot = prot;
-	if (n->vm_inode)
-		atomic_inc(&n->vm_inode->i_count);
+	n->vm_dentry = dget(n->vm_dentry);
 	if (n->vm_ops && n->vm_ops->open)
 		n->vm_ops->open(n);
 	insert_vm_struct(current->mm, n);
@@ -133,8 +132,7 @@
 	n->vm_offset += n->vm_start - vma->vm_start;
 	n->vm_flags = newflags;
 	n->vm_page_prot = prot;
-	if (n->vm_inode)
-		atomic_inc(&n->vm_inode->i_count);
+	n->vm_dentry = dget(n->vm_dentry);
 	if (n->vm_ops && n->vm_ops->open)
 		n->vm_ops->open(n);
 	insert_vm_struct(current->mm, n);
@@ -165,8 +163,8 @@
 	right->vm_offset += right->vm_start - left->vm_start;
 	vma->vm_flags = newflags;
 	vma->vm_page_prot = prot;
-	if (vma->vm_inode)
-		atomic_add(2, &vma->vm_inode->i_count);
+	if (vma->vm_dentry)
+		vma->vm_dentry->d_count += 2;
 	if (vma->vm_ops && vma->vm_ops->open) {
 		vma->vm_ops->open(left);
 		vma->vm_ops->open(right);
diff -u --recursive --new-file v2.1.44/linux/mm/mremap.c linux/mm/mremap.c
--- v2.1.44/linux/mm/mremap.c	Mon Jun 16 16:36:01 1997
+++ linux/mm/mremap.c	Sun Jul 13 21:20:11 1997
@@ -140,8 +140,7 @@
 			new_vma->vm_start = new_addr;
 			new_vma->vm_end = new_addr+new_len;
 			new_vma->vm_offset = vma->vm_offset + (addr - vma->vm_start);
-			if (new_vma->vm_inode)
-				atomic_inc(&new_vma->vm_inode->i_count);
+			new_vma->vm_dentry = dget(vma->vm_dentry);
 			if (new_vma->vm_ops && new_vma->vm_ops->open)
 				new_vma->vm_ops->open(new_vma);
 			insert_vm_struct(current->mm, new_vma);
diff -u --recursive --new-file v2.1.44/linux/mm/page_io.c linux/mm/page_io.c
--- v2.1.44/linux/mm/page_io.c	Mon Jun 16 16:36:01 1997
+++ linux/mm/page_io.c	Sun Jul 13 21:20:11 1997
@@ -98,7 +98,7 @@
 			return;
 		wait_on_page(page);
 	} else if (p->swap_file) {
-		struct inode *swapf = p->swap_file;
+		struct inode *swapf = p->swap_file->d_inode;
 		unsigned int zones[PAGE_SIZE/512];
 		int i;
 		if (swapf->i_op->bmap == NULL
diff -u --recursive --new-file v2.1.44/linux/mm/simp.c linux/mm/simp.c
--- v2.1.44/linux/mm/simp.c	Wed Dec 31 16:00:00 1969
+++ linux/mm/simp.c	Wed Jul 16 19:22:51 1997
@@ -0,0 +1,434 @@
+#define NULL 0
+/*
+ * mm/simp.c  -- simple allocator for cached objects
+ *
+ * (C) 1997 Thomas Schoebel-Theuer
+ */
+
+#include <linux/simp.h>
+#include <linux/smp.h>
+#include <linux/mm.h>
+#include <asm/spinlock.h>
+
+/* The next two defines can be independently enabled for debugging */
+/*#define DEBUG*/
+/*#define DEAD_BEEF*/
+
+#ifdef DEAD_BEEF
+#define DEBUG_BEEF 1
+#else
+#define DEBUG_BEEF 0
+#endif
+
+#ifdef __SMP__
+#define NR_PROCESSORS  NR_CPUS
+#define GLOBAL_SIZE CHUNK_SIZE
+#else
+#define NR_PROCESSORS  1
+#define GLOBAL_SIZE PAGE_SIZE
+#endif
+
+#define POSTBUFFER_SIZE 63
+#define ORDER 2
+#define CHUNK_SIZE (PAGE_SIZE*(1<<ORDER))
+#define CHUNK_BASE(ptr) (struct header*)(((unsigned long)(ptr)) & ~(CHUNK_SIZE-1))
+#define CHUNK_END(hdr) (void**)((char*)(hdr) + CHUNK_SIZE)
+
+#define COLOR_INCREMENT (8*sizeof(void*)) /* should be 1 cache line */
+#define ALIGN_CACHE(adr) ((((((unsigned long)adr) - 1) / COLOR_INCREMENT) + 1) * COLOR_INCREMENT)
+#define HEADER_SIZE ALIGN_CACHE(sizeof(struct header))
+#define ELEM_SIZE ALIGN_CACHE(sizeof(struct elem))
+#define FILL_TYPE(name,wrongsize) char name[ALIGN_CACHE(wrongsize)-(wrongsize)]
+
+#define MAX_SIMPS ((GLOBAL_SIZE / sizeof(struct simp)) - 1)
+
+struct header { /* this is at the beginning of each memory region */
+	/* 1st cache line */
+	void ** index;
+	void ** fresh;
+	struct simp * father;
+	void ** emptypos;
+	struct header * next;
+	structor again_ctor;
+	structor first_ctor;
+	void * fill[1];
+#ifdef DEBUG
+	/* 2nd cache line */
+	char magic[32];
+#endif
+};
+
+struct per_processor {
+	void ** buffer_pos;
+	void * postbuffer[POSTBUFFER_SIZE];
+};
+
+struct simp {
+	/* 1st cache lines */
+	struct per_processor private[NR_PROCESSORS];
+	/* next cache line */
+	struct header * usable_list;
+	spinlock_t lock;
+	char fill[sizeof(void*) - sizeof(spinlock_t)];
+	long real_size;
+	long max_elems;
+	structor again_ctor;
+	structor first_ctor;
+	structor dtor;
+	long fill2;
+	/* next cache line */
+	long create_offset;
+	long color;
+	long max_color;
+	long size;
+	long fill3[4];
+	/* next cache line */
+	char name[32];
+};
+
+struct global_data {
+	/* 1st cache line */
+	long changed_flag;
+	long nr_simps;
+	spinlock_t lock;
+	char fill[(6+8)*sizeof(void*)+sizeof(void*)-sizeof(spinlock_t)];
+	/* rest */
+	struct simp simps[MAX_SIMPS];
+};
+
+static struct global_data * global = NULL;
+
+#ifdef DEBUG
+static char global_magic[32] = "SIMP header SdC581oi9rY20051962\n";
+#endif
+
+struct simp * simp_create(char * name, long size,
+			  structor first_ctor, 
+			  structor again_ctor, 
+			  structor dtor)
+{
+	struct simp * simp;
+	long fraction;
+	long real_size;
+	int cpu;
+
+	if(!global) {
+#ifdef __SMP__
+		global = (struct global_data*)__get_free_pages(GFP_KERNEL, ORDER, 0);
+		memset(global, 0, CHUNK_SIZE);
+#else
+		global = (struct global_data*)get_free_page(GFP_KERNEL);
+#endif
+		spin_lock_init(&global->lock);
+	}
+
+	spin_lock(&global->lock);
+	simp = &global->simps[global->nr_simps++];
+	spin_unlock(&global->lock);
+
+	if(global->nr_simps >= MAX_SIMPS) {
+		printk("SIMP: too many simps allocated\n");
+		return NULL;
+	}
+	memset(simp, 0, sizeof(struct simp));
+	spin_lock_init(&simp->lock);
+	strncpy(simp->name, name, 15);
+	simp->size = size;
+	simp->real_size = real_size = ALIGN_CACHE(size);
+	/* allow aggregation of very small objects in 2-power fractions of
+	 * cachelines */
+	fraction = COLOR_INCREMENT / 2;
+	while(size <= fraction && fraction >= sizeof(void*)) {
+		simp->real_size = fraction;
+		fraction >>= 1;
+	}
+	simp->first_ctor = first_ctor;
+	simp->again_ctor = again_ctor;
+	simp->dtor = dtor;
+	
+	real_size += sizeof(void*);
+	simp->max_elems = (CHUNK_SIZE - HEADER_SIZE) / real_size;
+	simp->max_color = (CHUNK_SIZE - HEADER_SIZE) % real_size;
+	for(cpu = 0; cpu < NR_PROCESSORS; cpu++) {
+		struct per_processor * private = &simp->private[cpu];
+		private->buffer_pos = private->postbuffer;
+	}
+	return simp;
+}
+
+/* Do *not* inline this, it clobbers too many registers... */
+static void alloc_header(struct simp * simp)
+{
+	struct header * hdr;
+	char * ptr;
+	void ** index;
+	long count;
+
+	spin_unlock(&simp->lock);
+	for(;;) {
+		hdr = (struct header*)__get_free_pages(GFP_KERNEL, ORDER, 0);
+		if(hdr)
+			break;
+		if(!simp_garbage())
+			return;
+	}
+#ifdef DEBUG
+	if(CHUNK_BASE(hdr) != hdr)
+		panic("simp: bad kernel page alignment");
+#endif
+
+	memset(hdr, 0, HEADER_SIZE);
+#ifdef DEBUG
+	memcpy(hdr->magic, global_magic, sizeof(global_magic));
+#endif
+	hdr->father = simp;
+	hdr->again_ctor = simp->again_ctor;
+	hdr->first_ctor = simp->first_ctor;
+	
+	/* note: races on simp->color don't produce any error :-) */
+	ptr = ((char*)hdr) + HEADER_SIZE + simp->color;
+	index = CHUNK_END(hdr);
+	for(count = 0; count < simp->max_elems; count++) {
+		*--index = ptr;
+		ptr += simp->real_size;
+		/* note: constructors are not called here in bunch but
+		 * instead at each single simp_alloc(), in order
+		 * to maximize chances that the cache will be
+		 * polluted after a simp_alloc() anyway,
+		 * and not here. */
+	}
+	hdr->index = hdr->fresh = hdr->emptypos = index;
+
+	spin_lock(&simp->lock);
+	simp->color += COLOR_INCREMENT;
+	if(simp->color >= simp->max_color)
+		simp->color = 0;
+	hdr->next = simp->usable_list;
+	simp->usable_list = hdr;
+}
+
+
+/* current x86 memcpy() is horribly moving around registers for nothing,
+ * is doing unnecessary work if the size is dividable by a power-of-two,
+ * and it clobbers way too many registers.
+ * This results in nearly any other register being transfered to stack.
+ * Fixing this would be a major win for the whole kernel!
+ */
+static void ** bunch_alloc(struct simp * simp, void ** buffer)
+{
+	struct header * hdr;
+	void ** index;
+	void ** to;
+	void ** end;
+	structor todo;
+	long length;
+
+	spin_lock(&simp->lock);
+	hdr = simp->usable_list;
+	if(!hdr) {
+		alloc_header(simp);
+		hdr = simp->usable_list;
+		if(!hdr) {
+			spin_unlock(&simp->lock);
+			*buffer = NULL;
+			return buffer+1;
+		}
+	}
+	
+	index = hdr->index;
+	end = hdr->fresh;
+	todo = hdr->again_ctor;
+	if(index == end) {
+		end = CHUNK_END(hdr);
+		todo = hdr->first_ctor;
+	}
+	to = index + POSTBUFFER_SIZE/2;
+	if(to >= end) {
+		to = end;
+		if(to == CHUNK_END(hdr)) {
+			simp->usable_list = hdr->next;
+			hdr->next = NULL;
+		}
+	}
+	if(to > hdr->fresh)
+		hdr->fresh = to;
+	hdr->index = to;
+	length = ((unsigned long)to) - (unsigned long)index;
+	to = buffer + (length/sizeof(void**));
+
+	memcpy(buffer, index, length);
+
+	spin_unlock(&simp->lock);
+
+	if(todo) {
+		do {
+			todo(*buffer++);
+		} while(buffer < to);
+	}
+	return to;
+}
+
+void * simp_alloc(struct simp * simp)
+{
+#ifdef __SMP__
+	const long cpu = smp_processor_id();
+	struct per_processor * priv = &simp->private[cpu];
+#else
+#define priv (&simp->private[0]) /*fool gcc to use no extra register*/
+#endif
+	void ** buffer_pos = priv->buffer_pos;
+	void * res;
+
+	if(buffer_pos == priv->postbuffer) {
+		buffer_pos = bunch_alloc(simp, buffer_pos);
+	}
+	buffer_pos--;
+	res = *buffer_pos;
+	priv->buffer_pos = buffer_pos;
+	return res;
+}
+
+#ifdef DEBUG
+long check_header(struct header * hdr, void * ptr)
+{
+	void ** test;
+
+	if(!hdr) {
+		printk("SIMP: simp_free() with NULL pointer\n");
+		return 1;
+	}
+	if(strncmp(hdr->magic, global_magic, 32)) {
+		printk("SIMP: simpe_free() with bad ptr %p, or header corruption\n", ptr);
+		return 1;
+	}
+	/* This is brute force, but I don't want to pay for any
+	 * overhead if debugging is not enabled, in particular
+	 * no space overhead for keeping hashtables etc. */
+	test = hdr->index;
+	while(test < CHUNK_END(hdr)) {
+		if(*test++ == ptr) {
+			printk("SIMP: trying to simp_free(%p) again\n", ptr);
+			return 1;
+		}
+	}
+	return 0;
+}
+#endif
+
+static void ** bunch_free(struct simp * simp, void ** buffer)
+{
+	void ** stop;
+
+	stop = buffer - POSTBUFFER_SIZE/3;
+
+	spin_lock(&simp->lock);
+	while(buffer > stop) {
+		void * elem = buffer[-1];
+		struct header * hdr = CHUNK_BASE(elem);
+		void ** index = hdr->index;
+		index--;
+		hdr->index = index;
+		*index = elem;
+		if(!hdr->next) {
+			hdr->next = simp->usable_list;
+			simp->usable_list = hdr;
+		}
+
+		buffer -= 2;
+		elem = *buffer;
+		hdr = CHUNK_BASE(elem);
+		index = hdr->index;
+		index--;
+		hdr->index = index;
+		*index = elem;
+		if(!hdr->next) {
+			hdr->next = simp->usable_list;
+			simp->usable_list = hdr;
+		}
+	}
+	spin_unlock(&simp->lock);
+	global->changed_flag = 1;
+	return buffer;
+}
+
+void simp_free(void * objp)
+{
+	struct header * hdr;
+	void ** buffer_pos;
+	struct per_processor * private;
+#ifdef __SMP__
+	const long cpu = smp_processor_id();
+#else
+	const long cpu = 0;
+#endif
+
+	hdr = CHUNK_BASE(objp);
+#ifdef DEBUG
+	if(check_header(hdr, objp))
+		return;
+#endif
+
+	private = &hdr->father->private[cpu];
+	buffer_pos = private->buffer_pos;
+	if(buffer_pos >= private->postbuffer+POSTBUFFER_SIZE) {
+		buffer_pos = bunch_free(hdr->father, buffer_pos);
+	}
+
+	*buffer_pos++ = objp;
+	private->buffer_pos = buffer_pos;
+
+#ifdef DEAD_BEEF
+	{
+		unsigned int * ptr = (unsigned int*)objp;
+		int count = (hdr->father->real_size - ELEM_SIZE) / sizeof(unsigned int);
+		while(count--)
+			*ptr++ = 0xdeadbeef;
+	}
+#endif
+}
+
+long simp_garbage(void)
+{
+	int i;
+	int res;
+
+	if(!global->changed_flag)
+		return 0; /* shortcut */
+	/* Note: costs do not matter here. Any heavy thrashing of
+	 * simp chunks that could be caused by pools stealing each
+	 * other's memory has to be considered a BUG :-)
+	 * Simply avoid memory shortages by conservative allocating
+	 * policies.
+	 */
+	global->changed_flag = 0;
+	res = 0;
+	for(i = 0; i < global->nr_simps; i++) {
+		struct simp * simp = &global->simps[i];
+		struct header ** base = &simp->usable_list;
+		struct header * del;
+
+		spin_lock(&simp->lock);
+		del = *base;
+		while(del) {
+			if(del->index == del->emptypos) {
+				if(simp->dtor) {
+					void ** ptr = del->index;
+					while(ptr < CHUNK_END(del)) {
+						simp->dtor(*ptr++);
+					}
+				}
+				*base = del->next;
+#ifdef DEBUG
+				memset(del, 0, CHUNK_SIZE);
+#endif
+				free_pages((unsigned long)del, ORDER);
+				res++;
+			} else
+				base = &del->next;
+			del = *base;
+		}
+		spin_unlock(&simp->lock);
+	}
+	return res;
+}
+
diff -u --recursive --new-file v2.1.44/linux/mm/slab.c linux/mm/slab.c
--- v2.1.44/linux/mm/slab.c	Mon Jul  7 08:26:24 1997
+++ linux/mm/slab.c	Thu Jul 10 17:15:31 1997
@@ -1275,7 +1275,7 @@
 }
 
 static void
-kmem_report_free_err(const char *str, void *objp, kmem_cache_t * cachep)
+kmem_report_free_err(const char *str, const void *objp, kmem_cache_t * cachep)
 {
 	if (cachep)
 		SLAB_STATS_INC_ERR(cachep);
@@ -1456,7 +1456,7 @@
  * it should be in this state _before_ it is released.
  */
 static inline void
-__kmem_cache_free(kmem_cache_t *cachep, void *objp)
+__kmem_cache_free(kmem_cache_t *cachep, const void *objp)
 {
 	kmem_slab_t	*slabp;
 	kmem_bufctl_t	*bufp;
@@ -1653,7 +1653,7 @@
 }
 
 void
-kfree_s(void *objp, size_t size)
+kfree_s(const void *objp, size_t size)
 {
 	struct page *page;
 	int	nr;
diff -u --recursive --new-file v2.1.44/linux/mm/swapfile.c linux/mm/swapfile.c
--- v2.1.44/linux/mm/swapfile.c	Sun Jul  6 20:13:54 1997
+++ linux/mm/swapfile.c	Sun Jul 13 21:20:11 1997
@@ -326,7 +326,7 @@
 asmlinkage int sys_swapoff(const char * specialfile)
 {
 	struct swap_info_struct * p = NULL;
-	struct inode * inode;
+	struct dentry * dentry;
 	struct file filp;
 	int i, type, prev;
 	int err = -EPERM;
@@ -334,19 +334,22 @@
 	lock_kernel();
 	if (!suser())
 		goto out;
-	err = namei(specialfile, &inode);
-	if (err)
+
+	dentry = namei(specialfile);
+	err = PTR_ERR(dentry);
+	if (IS_ERR(dentry))
 		goto out;
+
 	prev = -1;
 	for (type = swap_list.head; type >= 0; type = swap_info[type].next) {
 		p = swap_info + type;
 		if ((p->flags & SWP_WRITEOK) == SWP_WRITEOK) {
 			if (p->swap_file) {
-				if (p->swap_file == inode)
+				if (p->swap_file == dentry)
 				  break;
 			} else {
-				if (S_ISBLK(inode->i_mode)
-				    && (p->swap_device == inode->i_rdev))
+				if (S_ISBLK(dentry->d_inode->i_mode)
+				    && (p->swap_device == dentry->d_inode->i_rdev))
 				  break;
 			}
 		}
@@ -354,7 +357,7 @@
 	}
 	err = -EINVAL;
 	if (type < 0){
-		iput(inode);
+		dput(dentry);
 		goto out;
 	}
 	if (prev < 0) {
@@ -369,7 +372,7 @@
 	p->flags = SWP_USED;
 	err = try_to_unuse(type);
 	if (err) {
-		iput(inode);
+		dput(dentry);
 		/* re-insert swap space back into swap_list */
 		for (prev = -1, i = swap_list.head; i >= 0; prev = i, i = swap_info[i].next)
 			if (p->prio >= swap_info[i].prio)
@@ -384,21 +387,19 @@
 	}
 	if(p->swap_device){
 		memset(&filp, 0, sizeof(filp));		
-		filp.f_inode = inode;
+		filp.f_dentry = dentry;
 		filp.f_mode = 3; /* read write */
 		/* open it again to get fops */
-		if( !blkdev_open(inode, &filp) &&
+		if( !blkdev_open(dentry->d_inode, &filp) &&
 		   filp.f_op && filp.f_op->release){
-			filp.f_op->release(inode,&filp);
-			filp.f_op->release(inode,&filp);
+			filp.f_op->release(dentry->d_inode,&filp);
+			filp.f_op->release(dentry->d_inode,&filp);
 		}
 	}
-	iput(inode);
+	dput(dentry);
 
 	nr_swap_pages -= p->pages;
-	iput(p->swap_file);
-	if (p->swap_filename)
-		kfree(p->swap_filename);
+	dput(p->swap_file);
 	p->swap_file = NULL;
 	p->swap_device = 0;
 	vfree(p->swap_map);
@@ -420,10 +421,8 @@
 	len += sprintf(buf, "Filename\t\t\tType\t\tSize\tUsed\tPriority\n");
 	for (i = 0 ; i < nr_swapfiles ; i++, ptr++)
 		if (ptr->flags & SWP_USED) {
-			if (ptr->swap_filename)
-				len += sprintf(buf + len, "%-31s ", ptr->swap_filename);
-			else
-				len += sprintf(buf + len, "(null)\t\t\t");
+			len += sprintf(buf + len, "%-31s ", ptr->swap_file->d_name.name);
+
 			if (ptr->swap_file)
 				len += sprintf(buf + len, "file\t\t");
 			else
@@ -451,11 +450,10 @@
 asmlinkage int sys_swapon(const char * specialfile, int swap_flags)
 {
 	struct swap_info_struct * p;
-	struct inode * swap_inode;
+	struct dentry * swap_dentry;
 	unsigned int type;
 	int i, j, prev;
 	int error = -EPERM;
-	char *tmp;
 	struct file filp;
 	static int least_priority = 0;
 
@@ -472,7 +470,6 @@
 	if (type >= nr_swapfiles)
 		nr_swapfiles = type+1;
 	p->flags = SWP_USED;
-	p->swap_filename = NULL;
 	p->swap_file = NULL;
 	p->swap_device = 0;
 	p->swap_map = NULL;
@@ -488,22 +485,22 @@
 	} else {
 		p->prio = --least_priority;
 	}
-	error = namei(specialfile, &swap_inode);
-	if (error)
+	swap_dentry = namei(specialfile);
+	error = PTR_ERR(swap_dentry);
+	if (IS_ERR(swap_dentry))
 		goto bad_swap_2;
-	p->swap_file = swap_inode;
+
+	p->swap_file = swap_dentry;
 	error = -EINVAL;
 
-	if (S_ISBLK(swap_inode->i_mode)) {
-		p->swap_device = swap_inode->i_rdev;
+	if (S_ISBLK(swap_dentry->d_inode->i_mode)) {
+		p->swap_device = swap_dentry->d_inode->i_rdev;
 		set_blocksize(p->swap_device, PAGE_SIZE);
 		
-		filp.f_inode = swap_inode;
+		filp.f_dentry = swap_dentry;
 		filp.f_mode = 3; /* read write */
-		error = blkdev_open(swap_inode, &filp);
-		p->swap_file = NULL;
-		iput(swap_inode);
-		if(error)
+		error = blkdev_open(swap_dentry->d_inode, &filp);
+		if (error)
 			goto bad_swap_2;
 		error = -ENODEV;
 		if (!p->swap_device ||
@@ -517,7 +514,7 @@
 			if (p->swap_device == swap_info[i].swap_device)
 				goto bad_swap;
 		}
-	} else if (!S_ISREG(swap_inode->i_mode))
+	} else if (!S_ISREG(swap_dentry->d_inode->i_mode))
 		goto bad_swap;
 	p->swap_lockmap = (unsigned char *) get_free_page(GFP_USER);
 	if (!p->swap_lockmap) {
@@ -577,12 +574,6 @@
 		prev = i;
 	}
 	p->next = i;
-	if (!getname(specialfile, &tmp)) {
-		if ((p->swap_filename =
-		    (char *) kmalloc(strlen(tmp)+1, GFP_KERNEL)) != (char *)NULL)
-			strcpy(p->swap_filename, tmp);
-		putname(tmp);
-	}
 	if (prev < 0) {
 		swap_list.head = swap_list.next = p - swap_info;
 	} else {
@@ -592,11 +583,11 @@
 	goto out;
 bad_swap:
 	if(filp.f_op && filp.f_op->release)
-		filp.f_op->release(filp.f_inode,&filp);
+		filp.f_op->release(filp.f_dentry->d_inode,&filp);
 bad_swap_2:
 	free_page((long) p->swap_lockmap);
 	vfree(p->swap_map);
-	iput(p->swap_file);
+	dput(p->swap_file);
 	p->swap_device = 0;
 	p->swap_file = NULL;
 	p->swap_map = NULL;
diff -u --recursive --new-file v2.1.44/linux/mm/vmscan.c linux/mm/vmscan.c
--- v2.1.44/linux/mm/vmscan.c	Mon Jun 16 16:36:01 1997
+++ linux/mm/vmscan.c	Mon Jul 14 01:12:49 1997
@@ -362,13 +362,22 @@
 				return 1;
 			state = 1;
 		case 1:
-			if (kmem_cache_reap(i, dma, wait))
-				return 1;
+			shrink_dcache();
 			state = 2;
 		case 2:
-			if (shm_swap(i, dma))
+			/*
+			 * We shouldn't have a priority here:
+			 * If we're low on memory we should
+			 * unconditionally throw away _all_
+			 * kmalloc caches!
+			 */
+			if (kmem_cache_reap(0, dma, wait))
 				return 1;
 			state = 3;
+		case 3:
+			if (shm_swap(i, dma))
+				return 1;
+			state = 4;
 		default:
 			if (swap_out(i, dma, wait))
 				return 1;
diff -u --recursive --new-file v2.1.44/linux/net/Config.in linux/net/Config.in
--- v2.1.44/linux/net/Config.in	Mon Jun 16 16:36:01 1997
+++ linux/net/Config.in	Wed Jul 16 19:22:51 1997
@@ -53,6 +53,6 @@
 #  if [ "$CONFIG_LLC" = "y" ]; then
 #   bool 'Netbeui (EXPERIMENTAL)' CONFIG_NETBEUI
 #  fi
-  tristate 'WAN router' CONFIG_WAN_ROUTER
+  bool 'WAN router' CONFIG_WAN_ROUTER
 fi
 endmenu
diff -u --recursive --new-file v2.1.44/linux/net/Makefile linux/net/Makefile
--- v2.1.44/linux/net/Makefile	Mon Jul  7 13:04:57 1997
+++ linux/net/Makefile	Wed Jul 16 19:22:51 1997
@@ -113,6 +113,9 @@
   endif
 endif
 
+# We must attach netsyms.o to socket.o, as otherwise there is nothing
+# to pull the object file from the archive.
+
 SOCK         := socket.o
 ifeq ($(CONFIG_NET),y)
 ifeq ($(CONFIG_MODULES),y)
diff -u --recursive --new-file v2.1.44/linux/net/appletalk/ddp.c linux/net/appletalk/ddp.c
--- v2.1.44/linux/net/appletalk/ddp.c	Thu Jun 26 12:33:40 1997
+++ linux/net/appletalk/ddp.c	Wed Jul 16 19:22:51 1997
@@ -1832,7 +1832,7 @@
 	{
 		if((!(rt->flags&RTF_GATEWAY))&&(!(dev->flags&IFF_LOOPBACK)))
 		{
-			struct sk_buff *skb2=skb_clone(skb, GFP_KERNEL);
+			struct sk_buff *skb2=skb_copy(skb, GFP_KERNEL);
 			if(skb2)
 			{
 				loopback=1;
diff -u --recursive --new-file v2.1.44/linux/net/appletalk/sysctl_net_atalk.c linux/net/appletalk/sysctl_net_atalk.c
--- v2.1.44/linux/net/appletalk/sysctl_net_atalk.c	Mon Jun 16 16:36:01 1997
+++ linux/net/appletalk/sysctl_net_atalk.c	Wed Jul 16 19:22:51 1997
@@ -14,7 +14,7 @@
 extern int sysctl_aarp_retransmit_limit;
 extern int sysctl_aarp_resolve_time;
 
-
+#ifdef CONFIG_SYSCTL
 static ctl_table atalk_table[] = {
 	{NET_ATALK_AARP_EXPIRY_TIME, "aarp-expiry-time",
 	 &sysctl_aarp_expiry_time, sizeof(int), 0644, NULL, &proc_dointvec_jiffies},
@@ -39,16 +39,25 @@
 
 static struct ctl_table_header *atalk_table_header;
 
-inline void atalk_register_sysctl(void)
+void atalk_register_sysctl(void)
 {
 	atalk_table_header = register_sysctl_table(atalk_root_table, 1);
 }
 
-inline void atalk_unregister_sysctl(void)
+void atalk_unregister_sysctl(void)
 {
 	unregister_sysctl_table(atalk_table_header);
 }
 
+#else
+void atalk_register_sysctl(void)
+{
+}
+
+void atalk_unregister_sysctl(void)
+{
+}
+#endif
 
 
 
diff -u --recursive --new-file v2.1.44/linux/net/core/scm.c linux/net/core/scm.c
--- v2.1.44/linux/net/core/scm.c	Thu May 15 16:48:05 1997
+++ linux/net/core/scm.c	Sun Jul 13 21:20:11 1997
@@ -172,9 +172,9 @@
 				if (acc_fd < 0 || acc_fd >= NR_OPEN ||
 				    (file=current->files->fd[acc_fd])==NULL)
 					return -EBADF;
-				if (!file->f_inode || !file->f_inode->i_sock)
+				if (!file->f_dentry->d_inode || !file->f_dentry->d_inode->i_sock)
 					return -ENOTSOCK;
-				p->sock = &file->f_inode->u.socket_i;
+				p->sock = &file->f_dentry->d_inode->u.socket_i;
 				if (p->sock->state != SS_UNCONNECTED) 
 					return -EINVAL;
 			}
diff -u --recursive --new-file v2.1.44/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- v2.1.44/linux/net/ipv4/tcp_input.c	Thu Jun 26 12:33:41 1997
+++ linux/net/ipv4/tcp_input.c	Wed Jul 16 19:22:51 1997
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_input.c,v 1.53 1997/06/06 20:38:00 freitag Exp $
+ * Version:	$Id: tcp_input.c,v 1.54 1997/07/10 11:19:39 freitag Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -56,14 +56,19 @@
 static void tcp_cong_avoid_vegas(struct sock *sk, u32 seq, u32 ack,
 				 u32 seq_rtt);
 
+#ifdef CONFIG_SYSCTL
+#define SYNC_INIT 0 /* let the user enable it */
+#else
+#define SYNC_INIT 1
+#endif
+
 int sysctl_tcp_cong_avoidance;
 int sysctl_tcp_hoe_retransmits;
 int sysctl_tcp_sack;
 int sysctl_tcp_tsack;
 int sysctl_tcp_timestamps;
 int sysctl_tcp_window_scaling;
-int sysctl_tcp_syncookies; 
-int sysctl_tcp_always_syncookie;
+int sysctl_tcp_syncookies = SYNC_INIT; 
 int sysctl_tcp_max_delay_acks = MAX_DELAY_ACK;
 int sysctl_tcp_stdurg;
 
diff -u --recursive --new-file v2.1.44/linux/net/netlink.c linux/net/netlink.c
--- v2.1.44/linux/net/netlink.c	Tue May 13 22:41:24 1997
+++ linux/net/netlink.c	Sun Jul 13 21:20:11 1997
@@ -68,7 +68,7 @@
 static unsigned int netlink_poll(struct file *file, poll_table * wait)
 {
 	unsigned int mask;
-	unsigned int minor = MINOR(file->f_inode->i_rdev);
+	unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
 
 	poll_wait(&read_space_wait[minor], wait);
 	mask = POLLOUT | POLLWRNORM;
diff -u --recursive --new-file v2.1.44/linux/net/socket.c linux/net/socket.c
--- v2.1.44/linux/net/socket.c	Mon Jul  7 10:11:49 1997
+++ linux/net/socket.c	Wed Jul 16 19:22:51 1997
@@ -67,7 +67,6 @@
 #include <linux/socket.h>
 #include <linux/fcntl.h>
 #include <linux/file.h>
-#include <linux/dalloc.h>
 #include <linux/net.h>
 #include <linux/interrupt.h>
 #include <linux/netdevice.h>
@@ -150,7 +149,11 @@
 #define MAX_SOCK_ADDR	128		/* 108 for Unix domain - 
 					   16 for IP, 16 for IPX,
 					   24 for IPv6,
-					   about 80 for AX.25 */
+					   about 80 for AX.25 
+					   must be at least one bigger than
+					   the AF_UNIX size (see net/unix/af_unix.c
+					   :unix_mkname()).  
+					 */
  
 int move_addr_to_kernel(void *uaddr, int ulen, void *kaddr)
 {
@@ -207,13 +210,24 @@
 			return -ENFILE;
 		}
 
+		file->f_dentry = d_alloc_root(inode, NULL);
+		if (!file->f_dentry) {
+			put_filp(file);
+			put_unused_fd(fd);
+			return -ENOMEM;
+		}
+
+		/*
+		 * The socket maintains a reference to the inode, so we
+		 * have to increment the count.
+		 */
+		inode->i_count++;
+
 		current->files->fd[fd] = file;
 		file->f_op = &socket_file_ops;
 		file->f_mode = 3;
 		file->f_flags = O_RDWR;
-		file->f_inode = inode;
-		if (inode) 
-			atomic_inc(&inode->i_count);
+		file->f_dentry = d_alloc_root(inode, NULL);
 		file->f_pos = 0;
 	}
 	return fd;
@@ -239,11 +253,11 @@
 		return NULL;
 	}
 
-	inode = file->f_inode;
+	inode = file->f_dentry->d_inode;
 	if (!inode || !inode->i_sock || !socki_lookup(inode))
 	{
 		*err = -ENOTSOCK;
-		fput(file,inode);
+		fput(file);
 		return NULL;
 	}
 
@@ -252,7 +266,7 @@
 
 extern __inline__ void sockfd_put(struct socket *sock)
 {
-	fput(sock->file,sock->inode);
+	fput(sock->file);
 }
 
 /*
@@ -461,7 +475,7 @@
 {
 	struct socket *sock;
 
-	sock = socki_lookup(file->f_inode);
+	sock = socki_lookup(file->f_dentry->d_inode);
 
 	/*
 	 *	We can't return errors to poll, so it's either yes or no. 
@@ -1293,7 +1307,7 @@
 {
 	struct socket *sock;
 
-	sock = socki_lookup (filp->f_inode);
+	sock = socki_lookup (filp->f_dentry->d_inode);
 	if (sock && sock->ops && sock->ops->fcntl)
 		return sock->ops->fcntl(sock, cmd, arg);
 	return(-EINVAL);
diff -u --recursive --new-file v2.1.44/linux/net/unix/af_unix.c linux/net/unix/af_unix.c
--- v2.1.44/linux/net/unix/af_unix.c	Mon Jul  7 08:20:00 1997
+++ linux/net/unix/af_unix.c	Wed Jul 16 19:22:51 1997
@@ -162,8 +162,16 @@
 		return -EINVAL;
 	if (sunaddr->sun_path[0])
 	{
-		if (len >= sizeof(*sunaddr))
-			len = sizeof(*sunaddr)-1;
+		/*
+		 *	This may look like an off by one error but it is
+		 *	a bit more subtle. 108 is the longest valid AF_UNIX
+		 *	path for a binding. sun_path[108] doesnt as such
+		 *	exist. However in kernel space we are guaranteed that
+		 *	it is a valid memory location in our kernel
+		 *	address buffer.
+		 */
+		if (len > sizeof(*sunaddr))
+			len = sizeof(*sunaddr);
 		((char *)sunaddr)[len]=0;
 		len = strlen(sunaddr->sun_path)+1+sizeof(short);
 		return len;
@@ -450,24 +458,18 @@
 static unix_socket *unix_find_other(struct sockaddr_un *sunname, int len,
 				    int type, unsigned hash, int *error)
 {
-	unsigned long old_fs;
-	int err;
-	struct inode *inode;
 	unix_socket *u;
 	
 	if (sunname->sun_path[0])
 	{
-		old_fs=get_fs();
-		set_fs(get_ds());
-		err = open_namei(sunname->sun_path, 2, S_IFSOCK, &inode, NULL);
-		set_fs(old_fs);
-		if(err<0)
-		{
-			*error=err;
+		struct dentry *dentry;
+		dentry = open_namei(sunname->sun_path, 2, S_IFSOCK);
+		if (IS_ERR(dentry)) {
+			*error = PTR_ERR(dentry);
 			return NULL;
 		}
-		u=unix_find_socket_byinode(inode);
-		iput(inode);
+		u=unix_find_socket_byinode(dentry->d_inode);
+		dput(dentry);
 		if (u && u->type != type)
 		{
 			*error=-EPROTOTYPE;
@@ -491,8 +493,8 @@
 {
 	struct sock *sk = sock->sk;
 	struct sockaddr_un *sunaddr=(struct sockaddr_un *)uaddr;
-	struct inode * inode;
-	int old_fs;
+	struct dentry * dentry;
+	struct inode * inode = NULL;
 	int err;
 	unsigned hash;
 	struct unix_address *addr;
@@ -545,15 +547,16 @@
 	addr->hash = UNIX_HASH_SIZE;
 	sk->protinfo.af_unix.addr = addr;
 	
-	old_fs=get_fs();
-	set_fs(get_ds());
 
-	err=do_mknod(sunaddr->sun_path, S_IFSOCK|S_IRWXUGO, 0);
-	if (!err)
-		err=open_namei(sunaddr->sun_path, 2, S_IFSOCK, &inode, NULL);
-	
-	set_fs(old_fs);
-	
+	dentry = do_mknod(sunaddr->sun_path, S_IFSOCK|S_IRWXUGO, 0);
+	err = PTR_ERR(dentry);
+	if (!IS_ERR(dentry)) {
+		inode = dentry->d_inode;
+		inode->i_count++;	/* HATEFUL - we should use the dentry */
+		dput(dentry);
+		err = 0;
+	}
+
 	if(err<0)
 	{
 		unix_release_addr(addr);
@@ -799,7 +802,7 @@
 	}
 	if (sk->protinfo.af_unix.inode)
 	{
-		atomic_inc(&sk->protinfo.af_unix.inode->i_count);
+		sk->protinfo.af_unix.inode->i_count++;	/* Should use dentry */
 		newsk->protinfo.af_unix.inode=sk->protinfo.af_unix.inode;
 	}
 		
diff -u --recursive --new-file v2.1.44/linux/net/unix/garbage.c linux/net/unix/garbage.c
--- v2.1.44/linux/net/unix/garbage.c	Thu Dec 12 06:54:26 1996
+++ linux/net/unix/garbage.c	Sun Jul 13 21:20:11 1997
@@ -68,7 +68,7 @@
 extern inline unix_socket *unix_get_socket(struct file *filp)
 {
 	unix_socket * u_sock = NULL;
-	struct inode *inode = filp->f_inode;
+	struct inode *inode = filp->f_dentry->d_inode;
 
 	/*
 	 *	Socket ?
diff -u --recursive --new-file v2.1.44/linux/net/wanrouter/patchlevel linux/net/wanrouter/patchlevel
--- v2.1.44/linux/net/wanrouter/patchlevel	Sun Feb  2 05:18:52 1997
+++ linux/net/wanrouter/patchlevel	Wed Jul 16 19:22:51 1997
@@ -1 +1,2 @@
-1.0.0
+1.0.3-modified
+
diff -u --recursive --new-file v2.1.44/linux/net/wanrouter/wanmain.c linux/net/wanrouter/wanmain.c
--- v2.1.44/linux/net/wanrouter/wanmain.c	Tue May 13 22:41:25 1997
+++ linux/net/wanrouter/wanmain.c	Wed Jul 16 19:22:51 1997
@@ -11,15 +11,17 @@
 *
 * Author:	Gene Kozin	<genek@compuserve.com>
 *
-* Copyright:	(c) 1995-1996 Sangoma Technologies Inc.
+* Copyright:	(c) 1995-1997 Sangoma Technologies Inc.
 *
 *		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.
 * ============================================================================
-* Dec 27, 1996	Gene Kozin	Initial version (based on Sangoma's WANPIPE)
+* Jun 27, 1997  Alan Cox	realigned with vendor code
+* Jan 16, 1997	Gene Kozin	router_devlist made public
 * Jan 31, 1997  Alan Cox	Hacked it about a bit for 2.1
+* Dec 27, 1996	Gene Kozin	Initial version (based on Sangoma's WANPIPE)
 *****************************************************************************/
 
 #include <linux/stddef.h>	/* offsetof(), etc. */
@@ -78,9 +80,9 @@
  */
 
 static char fullname[]		= "WAN Router";
-static char copyright[]		= "(c) 1995-1996 Sangoma Technologies Inc.";
+static char copyright[]		= "(c) 1995-1997 Sangoma Technologies Inc.";
 static char modname[]		= ROUTER_NAME;	/* short module name */
-static wan_device_t* devlist	= NULL;	/* list of registered devices */
+wan_device_t * router_devlist	= NULL;	/* list of registered devices */
 static int devcnt		= 0;
 
 /*
@@ -199,8 +201,8 @@
 	 
 	wandev->ndev = 0;
 	wandev->dev  = NULL;
-	wandev->next = devlist;
-	devlist = wandev;
+	wandev->next = router_devlist;
+	router_devlist = wandev;
 	++devcnt;
         MOD_INC_USE_COUNT;	/* prevent module from unloading */
 	return 0;
@@ -225,7 +227,7 @@
 	if (name == NULL)
 		return -EINVAL;
 
-	for (wandev = devlist, prev = NULL;
+	for (wandev = router_devlist, prev = NULL;
 		wandev && strcmp(wandev->name, name);
 		prev = wandev, wandev = wandev->next)
 		;
@@ -246,7 +248,7 @@
 	if (prev)
 		prev->next = wandev->next;
 	else
-		devlist = wandev->next;
+		router_devlist = wandev->next;
 	--devcnt;
 	wanrouter_proc_delete(wandev);
         MOD_DEC_USE_COUNT;
@@ -613,7 +615,7 @@
 {
 	wan_device_t* wandev;
 
-	for (wandev = devlist;wandev && strcmp(wandev->name, name);
+	for (wandev = router_devlist;wandev && strcmp(wandev->name, name);
 		wandev = wandev->next);
 	return wandev;
 }
diff -u --recursive --new-file v2.1.44/linux/net/wanrouter/wanproc.c linux/net/wanrouter/wanproc.c
--- v2.1.44/linux/net/wanrouter/wanproc.c	Mon Jun 16 16:36:02 1997
+++ linux/net/wanrouter/wanproc.c	Wed Jul 16 19:22:51 1997
@@ -1,20 +1,22 @@
 /*****************************************************************************
-* wanproc.c	WAN Multiprotocol Router Module. proc filesystem interface.
+* wanproc.c	WAN Router Module. /proc filesystem interface.
 *
 *		This module is completely hardware-independent and provides
 *		access to the router using Linux /proc filesystem.
 *
 * Author:	Gene Kozin	<genek@compuserve.com>
 *
-* Copyright:	(c) 1995-1996 Sangoma Technologies Inc.
+* Copyright:	(c) 1995-1997 Sangoma Technologies Inc.
 *
 *		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.
 * ============================================================================
-* Dec 13, 1996	Gene Kozin	Initial version (based on Sangoma's WANPIPE)
+* Jun 29, 1997	Alan Cox	Merged with 1.0.3 vendor code
+* Jan 29, 1997	Gene Kozin	v1.0.1. Implemented /proc read routines
 * Jan 30, 1997	Alan Cox	Hacked around for 2.1
+* Dec 13, 1996	Gene Kozin	Initial version (based on Sangoma's WANPIPE)
 *****************************************************************************/
 
 #include <linux/stddef.h>	/* offsetof(), etc. */
@@ -39,7 +41,7 @@
 #define max(a,b) (((a)>(b))?(a):(b))
 #endif
 
-#define	ROUTER_PAGE_SZ	4000	/* buffer size for printing proc info */
+#define	PROC_BUFSZ	4000	/* buffer size for printing proc info */
 
 /****** Data Types **********************************************************/
 
@@ -60,7 +62,6 @@
 
 /* Methods for preparing data for reading proc entries */
 
-static int about_get_info(char* buf, char** start, off_t offs, int len, int dummy);
 static int config_get_info(char* buf, char** start, off_t offs, int len, int dummy);
 static int status_get_info(char* buf, char** start, off_t offs, int len, int dummy);
 static int wandev_get_info(char* buf, char** start, off_t offs, int len, int dummy);
@@ -76,7 +77,6 @@
  */
 
 static char name_root[]	= ROUTER_NAME;
-static char name_info[]	= "about";
 static char name_conf[]	= "config";
 static char name_stat[]	= "status";
 
@@ -84,9 +84,8 @@
  *	Structures for interfacing with the /proc filesystem.
  *	Router creates its own directory /proc/net/router with the folowing
  *	entries:
- *	About		general information (version, copyright, etc.)
- *	Conf		device configuration
- *	Stat		global device statistics
+ *	config		device configuration
+ *	status		global device statistics
  *	<device>	entry for each WAN device
  */
 
@@ -194,29 +193,6 @@
 };
 
 /*
- *	/proc/net/router/about 
- */
- 
-static struct proc_dir_entry proc_router_info =
-{
-	0,			/* .low_ino */
-	sizeof(name_info) - 1,	/* .namelen */
-	name_info,		/* .name */
-	0444 | S_IFREG,		/* .mode */
-	1,			/* .nlink */
-	0,			/* .uid */
-	0,			/* .gid */
-	0,			/* .size */
-	&router_inode,		/* .ops */
-	&about_get_info,	/* .get_info */
-	NULL,			/* .fill_node */
-	NULL,			/* .next */
-	NULL,			/* .parent */
-	NULL,			/* .subdir */
-	NULL,			/* .data */
-};
-
-/*
  *	/proc/net/router/config 
  */
  
@@ -262,6 +238,16 @@
 	NULL,			/* .data */
 };
 
+/* Strings */
+static char conf_hdr[] =
+	"Device name    | port |IRQ|DMA|mem.addr|mem.size|"
+	"option1|option2|option3|option4\n";
+	
+static char stat_hdr[] =
+	"Device name    |station|interface|clocking|baud rate| MTU |ndev"
+	"|link state\n";
+
+
 /*
  *	Interface functions
  */
@@ -272,11 +258,10 @@
 
 __initfunc(int wanrouter_proc_init (void))
 {
-	int err = proc_register(&proc_net, &proc_router);
+	int err = proc_register(proc_net, &proc_router);
 
 	if (!err)
 	{
-		proc_register(&proc_router, &proc_router_info);
 		proc_register(&proc_router, &proc_router_conf);
 		proc_register(&proc_router, &proc_router_stat);
 	}
@@ -289,10 +274,9 @@
 
 void wanrouter_proc_cleanup (void)
 {
-	proc_unregister(&proc_router, proc_router_info.low_ino);
 	proc_unregister(&proc_router, proc_router_conf.low_ino);
 	proc_unregister(&proc_router, proc_router_stat.low_ino);
-	proc_unregister(&proc_net, proc_router.low_ino);
+	proc_unregister(proc_net, proc_router.low_ino);
 }
 
 /*
@@ -367,7 +351,7 @@
 	if ((dent == NULL) || (dent->get_info == NULL))
 		return 0;
 		
-	page = kmalloc(ROUTER_PAGE_SZ, GFP_KERNEL);
+	page = kmalloc(PROC_BUFSZ, GFP_KERNEL);
 	if (page == NULL)
 		return -ENOBUFS;
 		
@@ -387,49 +371,86 @@
 }
 
 /*
- *	Prepare data for reading 'About' entry.
- *	Return length of data.
- */
-
-static int about_get_info(char* buf, char** start, off_t offs, int len, 
-				int dummy)
-{
-	int cnt = 0;
-
-	cnt += sprintf(&buf[cnt], "%12s : %u.%u\n",
-		"version", ROUTER_VERSION, ROUTER_RELEASE);
-	return cnt;
-}
-
-/*
  *	Prepare data for reading 'Config' entry.
  *	Return length of data.
- *	NOT YET IMPLEMENTED
  */
 
 static int config_get_info(char* buf, char** start, off_t offs, int len, 
 	int dummy)
 {
-	int cnt = 0;
+	int cnt = sizeof(conf_hdr) - 1;
+	wan_device_t* wandev;
+	strcpy(buf, conf_hdr);
+	for (wandev = router_devlist;
+	     wandev && (cnt < (PROC_BUFSZ - 80));
+	     wandev = wandev->next)
+	{
+		if (wandev->state) cnt += sprintf(&buf[cnt],
+			"%-15s|0x%-4X|%3u|%3u|0x%-6lX|0x%-6X|%7u|%7u|%7u|%7u\n",
+			wandev->name,
+			wandev->ioport,
+			wandev->irq,
+			wandev->dma,
+			wandev->maddr,
+			wandev->msize,
+			wandev->hw_opt[0],
+			wandev->hw_opt[1],
+			wandev->hw_opt[2],
+			wandev->hw_opt[3]);
+	}
 
-	cnt += sprintf(&buf[cnt], "%12s : %u.%u\n",
-		"version", ROUTER_VERSION, ROUTER_RELEASE);
 	return cnt;
 }
 
 /*
  *	Prepare data for reading 'Status' entry.
  *	Return length of data.
- *	NOT YET IMPLEMENTED
  */
 
 static int status_get_info(char* buf, char** start, off_t offs, int len, 
 			int dummy)
 {
-	int cnt = 0;
-
-	cnt += sprintf(&buf[cnt], "%12s : %u.%u\n",
-		"version", ROUTER_VERSION, ROUTER_RELEASE);
+	int cnt = sizeof(stat_hdr) - 1;
+	wan_device_t* wandev;
+	strcpy(buf, stat_hdr);
+	for (wandev = router_devlist;
+	     wandev && (cnt < (PROC_BUFSZ - 80));
+	     wandev = wandev->next)
+	{
+		if (!wandev->state) continue;
+		cnt += sprintf(&buf[cnt],
+			"%-15s|%-7s|%-9s|%-8s|%9u|%5u|%3u |",
+			wandev->name,
+			wandev->station ? " DCE" : " DTE",
+			wandev->interface ? " V.35" : " RS-232",
+			wandev->clocking ? "internal" : "external",
+			wandev->bps,
+			wandev->mtu,
+			wandev->ndev)
+		;
+		switch (wandev->state)
+		{
+		case WAN_UNCONFIGURED:
+			cnt += sprintf(&buf[cnt], "%-12s\n", "unconfigured");
+			break;
+
+		case WAN_DISCONNECTED:
+			cnt += sprintf(&buf[cnt], "%-12s\n", "disconnected");
+			break;
+
+		case WAN_CONNECTING:
+			cnt += sprintf(&buf[cnt], "%-12s\n", "connecting");
+			break;
+
+		case WAN_CONNECTED:
+			cnt += sprintf(&buf[cnt], "%-12s\n", "connected");
+			break;
+
+		default:
+			cnt += sprintf(&buf[cnt], "%-12s\n", "invalid");
+			break;
+		}
+	}
 	return cnt;
 }
 
@@ -449,7 +470,52 @@
 
 	if ((wandev == NULL) || (wandev->magic != ROUTER_MAGIC))
 		return 0;
-	cnt += sprintf(&buf[cnt], "%12s : %s\n", "name", wandev->name);
+	if (!wandev->state)
+		return sprintf(&buf[cnt], "device is not configured!\n")
+	;
+
+	/* Update device statistics */
+	if (wandev->update) wandev->update(wandev);
+
+	cnt += sprintf(&buf[cnt], "%30s: %12lu\n",
+		"total frames received", wandev->stats.rx_packets)
+	;
+	cnt += sprintf(&buf[cnt], "%30s: %12lu\n",
+		"receiver overrun errors", wandev->stats.rx_over_errors)
+	;
+	cnt += sprintf(&buf[cnt], "%30s: %12lu\n",
+		"CRC errors", wandev->stats.rx_crc_errors)
+	;
+	cnt += sprintf(&buf[cnt], "%30s: %12lu\n",
+		"frame length errors", wandev->stats.rx_length_errors)
+	;
+	cnt += sprintf(&buf[cnt], "%30s: %12lu\n",
+		"frame format errors", wandev->stats.rx_frame_errors)
+	;
+	cnt += sprintf(&buf[cnt], "%30s: %12lu\n",
+		"aborted frames received", wandev->stats.rx_missed_errors)
+	;
+	cnt += sprintf(&buf[cnt], "%30s: %12lu\n",
+		"reveived frames dropped", wandev->stats.rx_dropped)
+	;
+	cnt += sprintf(&buf[cnt], "%30s: %12lu\n",
+		"other receive errors", wandev->stats.rx_errors)
+	;
+	cnt += sprintf(&buf[cnt], "\n%30s: %12lu\n",
+		"total frames transmitted", wandev->stats.tx_packets)
+	;
+	cnt += sprintf(&buf[cnt], "%30s: %12lu\n",
+		"aborted frames transmitted", wandev->stats.tx_aborted_errors)
+	;
+	cnt += sprintf(&buf[cnt], "%30s: %12lu\n",
+		"transmit frames dropped", wandev->stats.tx_dropped)
+	;
+	cnt += sprintf(&buf[cnt], "%30s: %12lu\n",
+		"transmit collisions", wandev->stats.collisions)
+	;
+	cnt += sprintf(&buf[cnt], "%30s: %12lu\n",
+		"other transmit errors", wandev->stats.tx_errors)
+	;
 	return cnt;
 }
 
